Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch dg-misc Excluding Merge-Ins
This is equivalent to a diff from 7ac0fd9d11 to e4a698bdd2
2013-02-12
| ||
16:47 | Merge from trunk. Leaf check-in: e4a698bdd2 user: dg tags: use-fossil_strcmp-everywhere, dg-misc | |
11:53 | Replaced a call to realloc() with cson_realloc() (which, in turn, uses the fossil realloc). check-in: a1d2cd84b8 user: stephan tags: trunk | |
2013-02-06
| ||
17:37 | Allow filtering by filename, tag or wiki page as well as by ticket UUID. Better handling of invalid values (they now generate empty RSS feeds rather than appending the HTML footer...). check-in: d244452bda user: dg tags: use-fossil_strcmp-everywhere, dg-misc | |
2013-01-30
| ||
13:10 | Make sure that "fossil_strcmp" is used everywhere in stead of "strcmp": The "strcmp" function from the C library is not usable in all situations, e.g. with --static on Linux Do an #undef in printf.c, preventing that the fossil_strcmp function is optimized for non-null arguments. check-in: afffe48643 user: jan.nijtmans tags: trunk | |
12:37 | Create new branch named "dg-misc" check-in: 168b42eee1 user: dg tags: use-fossil_strcmp-everywhere, dg-misc | |
10:03 | Make sure that "fossil_strcmp" is used everywhere in stead of "strcmp": The "strcmp" function from the C library is not usable in all situations, e.g. with --static on Linux Closed-Leaf check-in: 7ac0fd9d11 user: jan.nijtmans tags: use-fossil_strcmp-everywhere | |
2013-01-29
| ||
09:15 | Rename "unicode-glob" setting to "encoding-glob". Mention the existance of the *-glob settings in the "fossil commit" warnings. Alphabetize the settings list. check-in: 7d237c49f3 user: jan.nijtmans tags: trunk | |
Changes to Makefile.in.
35 35 36 36 #### Tcl shell for use in running the fossil testsuite. If you do not 37 37 # care about testing the end result, this can be blank. 38 38 # 39 39 TCLSH = tclsh 40 40 41 41 LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@ 42 -TCC += @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H -Dstrcmp=fossil_strcmp 42 +TCC += @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H 43 43 INSTALLDIR = $(DESTDIR)@prefix@/bin 44 44 USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@ 45 45 FOSSIL_ENABLE_TCL = @FOSSIL_ENABLE_TCL@ 46 46 FOSSIL_ENABLE_TCL_STUBS = @FOSSIL_ENABLE_TCL_STUBS@ 47 47 48 48 include $(SRCDIR)/main.mk 49 49 50 50 distclean: clean 51 51 rm -f autoconfig.h config.log Makefile
Changes to auto.def.
231 231 cc-check-function-in-lib iconv iconv 232 232 233 233 # Check for getpassphrase() for Solaris 10 where getpass() truncates to 10 chars 234 234 if {![cc-check-functions getpassphrase]} { 235 235 # Haiku needs this 236 236 cc-check-function-in-lib getpass bsd 237 237 } 238 +cc-check-function-in-lib dlopen dl 238 239 239 240 make-template Makefile.in 240 241 make-config-header autoconfig.h -auto {USE_* FOSSIL_*}
Changes to compat/zlib/configure.
812 812 /^sharedlibdir *=/s#=.*#=$sharedlibdir# 813 813 /^includedir *=/s#=.*#=$includedir# 814 814 /^mandir *=/s#=.*#=$mandir# 815 815 /^LDFLAGS *=/s#=.*#=$LDFLAGS# 816 816 " | sed -e " 817 817 s/\@VERSION\@/$VER/g; 818 818 " > zlib.pc 819 +#
Changes to src/blob.c.
1102 1102 struct Blob temp; 1103 1103 zUtf8 = blob_str(pBlob) + bomSize; 1104 1104 blob_zero(&temp); 1105 1105 blob_append(&temp, zUtf8, -1); 1106 1106 blob_swap(pBlob, &temp); 1107 1107 blob_reset(&temp); 1108 1108 #ifdef _WIN32 1109 - }else if( starts_with_utf16le_bom(pBlob, &bomSize) ){ 1110 - /* Make sure the blob contains two terminating 0-bytes */ 1111 - blob_append(pBlob, "", 1); 1112 - zUtf8 = blob_str(pBlob) + bomSize; 1113 - zUtf8 = fossil_unicode_to_utf8(zUtf8); 1114 - blob_zero(pBlob); 1115 - blob_append(pBlob, zUtf8, -1); 1116 - fossil_unicode_free(zUtf8); 1117 - }else if( starts_with_utf16be_bom(pBlob, &bomSize) ){ 1118 - unsigned int i = blob_size(pBlob); 1109 + }else if( starts_with_utf16_bom(pBlob, &bomSize) ){ 1119 1110 zUtf8 = blob_buffer(pBlob); 1120 - while( i > 0 ){ 1121 - /* swap bytes of unicode representation */ 1122 - char zTemp = zUtf8[--i]; 1123 - zUtf8[i] = zUtf8[i-1]; 1124 - zUtf8[--i] = zTemp; 1111 + if (*((unsigned short *)zUtf8) == 0xfffe) { 1112 + /* Found BOM, but with reversed bytes */ 1113 + unsigned int i = blob_size(pBlob); 1114 + while( i > 0 ){ 1115 + /* swap bytes of unicode representation */ 1116 + char zTemp = zUtf8[--i]; 1117 + zUtf8[i] = zUtf8[i-1]; 1118 + zUtf8[--i] = zTemp; 1119 + } 1125 1120 } 1126 1121 /* Make sure the blob contains two terminating 0-bytes */ 1127 1122 blob_append(pBlob, "", 1); 1128 1123 zUtf8 = blob_str(pBlob) + bomSize; 1129 1124 zUtf8 = fossil_unicode_to_utf8(zUtf8); 1130 1125 blob_zero(pBlob); 1131 1126 blob_append(pBlob, zUtf8, -1);
Changes to src/checkin.c.
614 614 ** 615 615 ** The last element of aCommitFile[] is always 0 - indicating the end 616 616 ** of the array. 617 617 ** 618 618 ** If there were no arguments passed to [commit], aCommitFile is not 619 619 ** allocated and remains NULL. Other parts of the code interpret this 620 620 ** to mean "all files". 621 +** 622 +** Returns 1 if there was a warning, 0 otherwise. 621 623 */ 622 -void select_commit_files(void){ 624 +int select_commit_files(void){ 625 + int result = 0; 623 626 if( g.argc>2 ){ 624 - int ii; 627 + int ii, jj=0; 625 628 Blob b; 626 629 blob_zero(&b); 627 630 g.aCommitFile = fossil_malloc(sizeof(int)*(g.argc-1)); 628 631 629 632 for(ii=2; ii<g.argc; ii++){ 630 633 int iId; 631 634 file_tree_name(g.argv[ii], &b, 1); 632 635 iId = db_int(-1, "SELECT id FROM vfile WHERE pathname=%Q", blob_str(&b)); 633 636 if( iId<0 ){ 634 - fossil_fatal("fossil knows nothing about: %s", g.argv[ii]); 637 + fossil_warning("fossil knows nothing about: %s", g.argv[ii]); 638 + result = 1; 639 + } else { 640 + g.aCommitFile[jj++] = iId; 635 641 } 636 - g.aCommitFile[ii-2] = iId; 637 642 blob_reset(&b); 638 643 } 639 - g.aCommitFile[ii-2] = 0; 644 + g.aCommitFile[jj] = 0; 640 645 } 646 + return result; 641 647 } 642 648 643 649 /* 644 650 ** Make sure the current check-in with timestamp zDate is younger than its 645 651 ** ancestor identified rid and zUuid. Throw a fatal error if not. 646 652 */ 647 653 static void checkin_verify_younger( ................................................................................ 1197 1203 ** follows "commit", then only those files are committed. 1198 1204 ** 1199 1205 ** After the following function call has returned, the Global.aCommitFile[] 1200 1206 ** array is allocated to contain the "id" field from the vfile table 1201 1207 ** for each file to be committed. Or, if aCommitFile is NULL, all files 1202 1208 ** should be committed. 1203 1209 */ 1204 - select_commit_files(); 1210 + if ( select_commit_files() ){ 1211 + blob_zero(&ans); 1212 + prompt_user("continue (y/N)? ", &ans); 1213 + cReply = blob_str(&ans)[0]; 1214 + if( cReply!='y' && cReply!='Y' ) fossil_exit(1);; 1215 + } 1205 1216 isAMerge = db_exists("SELECT 1 FROM vmerge WHERE id=0"); 1206 1217 if( g.aCommitFile && isAMerge ){ 1207 1218 fossil_fatal("cannot do a partial commit of a merge"); 1208 1219 } 1209 1220 1210 1221 /* Doing "fossil mv fileA fileB; fossil add fileA; fossil commit fileA" 1211 1222 ** will generate a manifest that has two fileA entries, which is illegal.
Changes to src/cson_amalgamation.c.
4347 4347 } 4348 4348 else if( buf->capacity >= n ) 4349 4349 { 4350 4350 return 0; 4351 4351 } 4352 4352 else 4353 4353 { 4354 - unsigned char * x = (unsigned char *)realloc( buf->mem, n ); 4354 + unsigned char * x = (unsigned char *)cson_realloc( buf->mem, n, "cson_buffer::mem" ); 4355 4355 if( ! x ) return cson_rc.AllocError; 4356 4356 memset( x + buf->used, 0, n - buf->used ); 4357 4357 buf->mem = x; 4358 4358 buf->capacity = n; 4359 4359 ++buf->timesExpanded; 4360 4360 return 0; 4361 4361 }
Changes to src/diff.c.
357 357 358 358 /* 359 359 ** This function returns non-zero if the blob starts with a UTF-16le or 360 360 ** UTF-16be byte-order-mark (BOM). 361 361 */ 362 362 int starts_with_utf16_bom(const Blob *pContent, int *pnByte){ 363 363 const char *z = blob_buffer(pContent); 364 - int c1, c2; 364 + int c1; 365 365 366 366 if( pnByte ) *pnByte = 2; 367 - if( blob_size(pContent)<2 ) return 0; 368 - c1 = z[0]; c2 = z[1]; 369 - if( (c1==(char)0xff) && (c2==(char)0xfe) ){ 370 - return 1; 371 - }else if( (c1==(char)0xfe) && (c2==(char)0xff) ){ 372 - return 1; 373 - } 374 - return 0; 375 -} 376 - 377 -/* 378 -** This function returns non-zero if the blob starts with a UTF-16le 379 -** byte-order-mark (BOM). 380 -*/ 381 -int starts_with_utf16le_bom(const Blob *pContent, int *pnByte){ 382 - const char *z = blob_buffer(pContent); 383 - int c1, c2; 384 - 385 - if( pnByte ) *pnByte = 2; 386 - if( blob_size(pContent)<2 ) return 0; 387 - c1 = z[0]; c2 = z[1]; 388 - if( (c1==(char)0xff) && (c2==(char)0xfe) ){ 389 - return 1; 390 - } 391 - return 0; 392 -} 393 - 394 -/* 395 -** This function returns non-zero if the blob starts with a UTF-16be 396 -** byte-order-mark (BOM). 397 -*/ 398 -int starts_with_utf16be_bom(const Blob *pContent, int *pnByte){ 399 - const char *z = blob_buffer(pContent); 400 - int c1, c2; 401 - 402 - if( pnByte ) *pnByte = 2; 403 - if( blob_size(pContent)<2 ) return 0; 404 - c1 = z[0]; c2 = z[1]; 405 - if( (c1==(char)0xfe) && (c2==(char)0xff) ){ 406 - return 1; 367 + if( (blob_size(pContent)<2) || (blob_size(pContent)&1)) return 0; 368 + c1 = ((unsigned short *)z)[0]; 369 + if( (c1==0xfeff) || (c1==0xfffe) ){ 370 + if( blob_size(pContent) < 4 ) return 1; 371 + c1 = ((unsigned short *)z)[1]; 372 + if( c1 != 0 ) return 1; 407 373 } 408 374 return 0; 409 375 } 410 376 411 377 /* 412 378 ** Return true if two DLine elements are identical. 413 379 */
Changes to src/http.c.
128 128 ** in pRecv. pRecv is assumed to be uninitialized when 129 129 ** this routine is called - this routine will initialize it. 130 130 ** 131 131 ** The server address is contain in the "g" global structure. The 132 132 ** url_parse() routine should have been called prior to this routine 133 133 ** in order to fill this structure appropriately. 134 134 */ 135 -int http_exchange(Blob *pSend, Blob *pReply, int useLogin){ 135 +int http_exchange(Blob *pSend, Blob *pReply, int useLogin, int maxRedirect){ 136 136 Blob login; /* The login card */ 137 137 Blob payload; /* The complete payload including login card */ 138 138 Blob hdr; /* The HTTP request header */ 139 139 int closeConnection; /* True to close the connection when done */ 140 140 int iLength; /* Length of the reply payload */ 141 141 int rc = 0; /* Result code */ 142 142 int iHttpVersion; /* Which version of HTTP protocol server uses */ ................................................................................ 229 229 if( c=='c' || c=='C' ){ 230 230 closeConnection = 1; 231 231 }else if( c=='k' || c=='K' ){ 232 232 closeConnection = 0; 233 233 } 234 234 }else if( rc==302 && fossil_strnicmp(zLine, "location:", 9)==0 ){ 235 235 int i, j; 236 + 237 + if ( --maxRedirect == 0){ 238 + fossil_fatal("redirect limit exceeded"); 239 + } 236 240 for(i=9; zLine[i] && zLine[i]==' '; i++){} 237 241 if( zLine[i]==0 ) fossil_fatal("malformed redirect: %s", zLine); 238 242 j = strlen(zLine) - 1; 239 243 while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){ 240 244 j -= 4; 241 245 zLine[j] = 0; 242 246 } 243 247 fossil_print("redirect to %s\n", &zLine[i]); 244 248 url_parse(&zLine[i]); 245 249 transport_close(); 246 - return http_exchange(pSend, pReply, useLogin); 250 + return http_exchange(pSend, pReply, useLogin, maxRedirect); 247 251 }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){ 248 252 if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){ 249 253 isCompressed = 0; 250 254 }else if( fossil_strnicmp(&zLine[14], 251 255 "application/x-fossil-uncompressed", -1)==0 ){ 252 256 isCompressed = 0; 253 257 }else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){
Changes to src/http_transport.c.
181 181 if( g.urlIsSsh ){ 182 182 /* Only SSH requires a global initialization. For SSH we need to create 183 183 ** and run an SSH command to talk to the remote machine. 184 184 */ 185 185 const char *zSsh; /* The base SSH command */ 186 186 Blob zCmd; /* The SSH command */ 187 187 char *zHost; /* The host name to contact */ 188 + int n; /* Size of prefix string */ 188 189 189 190 zSsh = db_get("ssh-command", zDefaultSshCmd); 190 191 blob_init(&zCmd, zSsh, -1); 191 192 if( g.urlPort!=g.urlDfltPort ){ 192 193 #ifdef __MINGW32__ 193 194 blob_appendf(&zCmd, " -P %d", g.urlPort); 194 195 #else ................................................................................ 217 218 blob_reset(&pw); 218 219 fossil_print(" -pw ********"); /* Do not show the password text */ 219 220 } 220 221 #endif 221 222 }else{ 222 223 zHost = mprintf("%s", g.urlName); 223 224 } 225 + n = blob_size(&zCmd); 224 226 blob_append(&zCmd, " ", 1); 225 227 shell_escape(&zCmd, zHost); 226 - fossil_print(" %s\n", zHost); /* Show the conclusion of the SSH command */ 228 + if( g.urlShell ){ 229 + blob_appendf(&zCmd, " %s", g.urlShell); 230 + }else{ 231 +#if defined(FOSSIL_ENABLE_SSH_FAR_SIDE) 232 + /* The following works. But only if the fossil on the remote side 233 + ** is recent enough to support the test-ssh-far-side command. That 234 + ** command was added on 2013-02-06. We will leave this turned off 235 + ** until most fossil servers have upgraded to that version or a later 236 + ** version. The sync will still work as long as the shell on the far 237 + ** side is bash and not tcsh. And if the default far side shell is 238 + ** tcsh, then the shell=/bin/bash query parameter can be used as a 239 + ** work-around. Enable this code after about a year... 240 + */ 241 + blob_appendf(&zCmd, " exec %s test-ssh-far-side", g.urlFossil); 242 +#endif 243 + } 244 + fossil_print("%s\n", blob_str(&zCmd)+n); /* Show tail of SSH command */ 227 245 free(zHost); 228 246 popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid); 229 247 if( sshPid==0 ){ 230 248 fossil_fatal("cannot start ssh tunnel using [%b]", &zCmd); 231 249 } 232 250 blob_reset(&zCmd); 233 251 transport_ssh_startup(); 234 252 } 235 253 } 254 + 255 +/* 256 +** COMMAND: test-ssh-far-side 257 +** 258 +** Read lines of input text, one by one, and evaluate each line using 259 +** system(). The ssh: sync protocol uses this on the far side of the 260 +** SSH link. 261 +*/ 262 +void test_ssh_far_side_cmd(void){ 263 + int i = 0; 264 + int got; 265 + char zLine[5000]; 266 + while( i<sizeof(zLine) ){ 267 + got = read(0, zLine+i, 1); 268 + if( got==0 ) return; 269 + if( zLine[i]=='\n' ){ 270 + zLine[i] = 0; 271 + system(zLine); 272 + i = 0; 273 + }else{ 274 + i++; 275 + } 276 + } 277 +} 236 278 237 279 /* 238 280 ** Open a connection to the server. The server is defined by the following 239 281 ** global variables: 240 282 ** 241 283 ** g.urlName Name of the server. Ex: www.fossil-scm.org 242 284 ** g.urlPort TCP/IP port. Ex: 80 ................................................................................ 249 291 if( transport.isOpen==0 ){ 250 292 if( g.urlIsSsh ){ 251 293 Blob cmd; 252 294 blob_zero(&cmd); 253 295 shell_escape(&cmd, g.urlFossil); 254 296 blob_append(&cmd, " test-http ", -1); 255 297 shell_escape(&cmd, g.urlPath); 256 - /* printf("%s\n", blob_str(&cmd)); fflush(stdout); */ 257 - fprintf(sshOut, "%s\n", blob_str(&cmd)); 298 + fprintf(sshOut, "%s || true\n", blob_str(&cmd)); 258 299 fflush(sshOut); 300 + if( g.fSshTrace ) printf("Sent: [%s]\n", blob_str(&cmd)); 259 301 blob_reset(&cmd); 260 302 }else if( g.urlIsHttps ){ 261 303 #ifdef FOSSIL_ENABLE_SSL 262 304 rc = ssl_open(); 263 305 if( rc==0 ) transport.isOpen = 1; 264 306 #else 265 307 socket_set_errmsg("HTTPS: Fossil has been compiled without SSL support"); ................................................................................ 401 443 */ 402 444 static int transport_fetch(char *zBuf, int N){ 403 445 int got; 404 446 if( sshIn ){ 405 447 int x; 406 448 int wanted = N; 407 449 got = 0; 408 - /* printf("want %d bytes...\n", wanted); fflush(stdout); */ 409 450 while( wanted>0 ){ 410 451 x = read(sshIn, &zBuf[got], wanted); 411 452 if( x<=0 ) break; 412 453 got += x; 413 454 wanted -= x; 414 455 } 415 456 }else if( g.urlIsHttps ){ ................................................................................ 436 477 ** Return the number of bytes actually received. 437 478 */ 438 479 int transport_receive(char *zBuf, int N){ 439 480 int onHand; /* Bytes current held in the transport buffer */ 440 481 int nByte = 0; /* Bytes of content received */ 441 482 442 483 onHand = transport.nUsed - transport.iCursor; 443 - /* printf("request %d with %d on hand\n", N, onHand); fflush(stdout); */ 484 + if( g.fSshTrace){ 485 + printf("Reading %d bytes with %d on hand... ", N, onHand); 486 + fflush(stdout); 487 + } 444 488 if( onHand>0 ){ 445 489 int toMove = onHand; 446 490 if( toMove>N ) toMove = N; 447 491 /* printf("bytes on hand: %d of %d\n", toMove, N); fflush(stdout); */ 448 492 memcpy(zBuf, &transport.pBuf[transport.iCursor], toMove); 449 493 transport.iCursor += toMove; 450 494 if( transport.iCursor>=transport.nUsed ){ ................................................................................ 458 502 if( N>0 ){ 459 503 int got = transport_fetch(zBuf, N); 460 504 if( got>0 ){ 461 505 nByte += got; 462 506 transport.nRcvd += got; 463 507 } 464 508 } 509 + if( g.fSshTrace ) printf("Got %d bytes\n", nByte); 465 510 return nByte; 466 511 } 467 512 468 513 /* 469 514 ** Load up to N new bytes of content into the transport.pBuf buffer. 470 515 ** The buffer itself might be moved. And the transport.iCursor value 471 516 ** might be reset to 0. ................................................................................ 530 575 transport.pBuf[i] = 0; 531 576 i--; 532 577 } 533 578 break; 534 579 } 535 580 i++; 536 581 } 537 - /* printf("Got line: [%s]\n", &transport.pBuf[iStart]); */ 582 + if( g.fSshTrace ) printf("Got line: [%s]\n", &transport.pBuf[iStart]); 538 583 return &transport.pBuf[iStart]; 539 584 } 540 585 541 586 void transport_global_shutdown(void){ 542 587 if( g.urlIsSsh && sshPid ){ 543 588 /*printf("Closing SSH tunnel: ");*/ 544 589 fflush(stdout);
Changes to src/json_detail.h.
197 197 char const * mtime; 198 198 char const * payload; 199 199 char const * requestId; 200 200 char const * resultCode; 201 201 char const * resultText; 202 202 char const * timestamp; 203 203 } FossilJsonKeys_; 204 -const FossilJsonKeys_ FossilJsonKeys; 204 +extern const FossilJsonKeys_ FossilJsonKeys; 205 205 206 206 /* 207 207 ** A page/command dispatch helper for fossil_json_f() implementations. 208 208 ** pages must be an array of JsonPageDef commands which we can 209 209 ** dispatch. The final item in the array MUST have a NULL name 210 210 ** element. 211 211 **
Changes to src/main.c.
133 133 int fHttpTrace; /* Trace outbound HTTP requests */ 134 134 int fSystemTrace; /* Trace calls to fossil_system(), --systemtrace */ 135 135 int fSshTrace; /* Trace the SSH setup traffic */ 136 136 int fNoSync; /* Do not do an autosync ever. --nosync */ 137 137 char *zPath; /* Name of webpage being served */ 138 138 char *zExtra; /* Extra path information past the webpage name */ 139 139 char *zBaseURL; /* Full text of the URL being served */ 140 + const char *zAltBase; /* Alternative URL root. --baseurl */ 140 141 char *zTop; /* Parent directory of zPath */ 141 142 const char *zContentType; /* The content type of the input HTTP request */ 142 143 int iErrPriority; /* Priority of current error message */ 143 144 char *zErrMsg; /* Text of an error message */ 144 145 int sslNotAvailable; /* SSL is not available. Do not redirect to https: */ 145 146 Blob cgiIn; /* Input to an xfer www method */ 146 147 int cgiOutput; /* Write error and status messages to CGI */ ................................................................................ 168 169 int urlPort; /* TCP port number for http: or https: */ 169 170 int urlDfltPort; /* The default port for the given protocol */ 170 171 char *urlPath; /* Pathname for http: */ 171 172 char *urlUser; /* User id for http: */ 172 173 char *urlPasswd; /* Password for http: */ 173 174 char *urlCanonical; /* Canonical representation of the URL */ 174 175 char *urlProxyAuth; /* Proxy-Authorizer: string */ 175 - char *urlFossil; /* The path of the ?fossil=path suffix on ssh: */ 176 + char *urlFossil; /* The fossil query parameter on ssh: */ 177 + char *urlShell; /* The shell query parameter on ssh: */ 176 178 int dontKeepUrl; /* Do not persist the URL */ 177 179 178 180 const char *zLogin; /* Login name. "" if not logged in. */ 179 181 const char *zSSLIdentity; /* Value of --ssl-identity option, filename of SSL client identity */ 180 182 int useLocalauth; /* No login required if from 127.0.0.1 */ 181 183 int noPswd; /* Logged in without password (on 127.0.0.1) */ 182 184 int userUid; /* Integer user id */ ................................................................................ 1114 1116 1115 1117 /* 1116 1118 ** Set the g.zBaseURL value to the full URL for the toplevel of 1117 1119 ** the fossil tree. Set g.zTop to g.zBaseURL without the 1118 1120 ** leading "http://" and the host and port. 1119 1121 ** 1120 1122 ** The g.zBaseURL is normally set based on HTTP_HOST and SCRIPT_NAME 1121 -** environment variables. However, if zAltBase is not NULL then it 1123 +** environment variables. However, if g.zAltBase is not NULL then it 1122 1124 ** is the argument to the --baseurl option command-line option and 1123 1125 ** g.zBaseURL and g.zTop is set from that instead. 1126 +** 1127 +** If g.zAltBase is set, then zRepoName may be a repository name (with a 1128 +** leading slash ** but without the .fossil) with is concatenated to the 1129 +** root. 1124 1130 */ 1125 -static void set_base_url(const char *zAltBase){ 1131 +static void set_base_url(const char* zRepoName){ 1126 1132 int i; 1127 1133 const char *zHost; 1128 1134 const char *zMode; 1129 1135 const char *zCur; 1130 1136 1131 - if( g.zBaseURL!=0 ) return; 1132 - if( zAltBase ){ 1137 + fossil_free(g.zBaseURL); 1138 + if( g.zAltBase ){ 1133 1139 int i, n, c; 1134 - g.zTop = g.zBaseURL = mprintf("%s", zAltBase); 1140 + if (!zRepoName) zRepoName = ""; 1141 + if (zRepoName[0] == '/') zRepoName++; 1142 + g.zTop = g.zBaseURL = mprintf("%s%s", g.zAltBase, zRepoName); 1135 1143 if( memcmp(g.zTop, "http://", 7)!=0 && memcmp(g.zTop,"https://",8)!=0 ){ 1136 1144 fossil_fatal("argument to --baseurl should be 'http://host/path'" 1137 1145 " or 'https://host/path'"); 1138 1146 } 1139 1147 for(i=n=0; (c = g.zTop[i])!=0; i++){ 1140 1148 if( c=='/' ){ 1141 1149 n++; ................................................................................ 1271 1279 ** repository based on the first element of PATH_INFO and open it. 1272 1280 */ 1273 1281 zPathInfo = PD("PATH_INFO",""); 1274 1282 if( !g.repositoryOpen ){ 1275 1283 char *zRepo, *zToFree; 1276 1284 const char *zOldScript = PD("SCRIPT_NAME", ""); 1277 1285 char *zNewScript; 1286 + char *zRepoName; 1278 1287 int j, k; 1279 1288 i64 szFile; 1280 1289 1281 1290 i = zPathInfo[0]!=0; 1282 1291 while( 1 ){ 1283 1292 while( zPathInfo[i] && zPathInfo[i]!='/' ){ i++; } 1284 1293 zRepo = zToFree = mprintf("%s%.*s.fossil",g.zRepositoryName,i,zPathInfo); ................................................................................ 1347 1356 cgi_set_status(404, "not found"); 1348 1357 cgi_reply(); 1349 1358 } 1350 1359 return; 1351 1360 } 1352 1361 break; 1353 1362 } 1363 + /* Rebuild the base URL to add the repository name to the end. */ 1364 + zRepoName = mprintf("%.*s", i, zPathInfo); 1365 + set_base_url(zRepoName); 1366 + fossil_free(zRepoName); 1354 1367 zNewScript = mprintf("%s%.*s", zOldScript, i, zPathInfo); 1355 1368 cgi_replace_parameter("PATH_INFO", &zPathInfo[i+1]); 1356 1369 zPathInfo += i; 1357 1370 cgi_replace_parameter("SCRIPT_NAME", zNewScript); 1358 1371 db_open_repository(zRepo); 1359 1372 if( g.fHttpTrace ){ 1360 1373 fprintf(stderr, 1361 1374 "# repository: [%s]\n" 1362 1375 "# new PATH_INFO = [%s]\n" 1363 1376 "# new SCRIPT_NAME = [%s]\n", 1364 1377 zRepo, zPathInfo, zNewScript); 1365 1378 } 1366 1379 } 1380 + else 1381 + set_base_url(0); 1367 1382 1368 1383 /* Find the page that the user has requested, construct and deliver that 1369 1384 ** page. 1370 1385 */ 1371 1386 if( g.zContentType && memcmp(g.zContentType, "application/x-fossil", 20)==0 ){ 1372 1387 zPathInfo = "/xfer"; 1373 1388 } 1374 - set_base_url(0); 1375 1389 if( zPathInfo==0 || zPathInfo[0]==0 1376 1390 || (zPathInfo[0]=='/' && zPathInfo[1]==0) ){ 1377 1391 #ifdef FOSSIL_ENABLE_JSON 1378 1392 if(g.json.isJsonMode){ 1379 1393 json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,1); 1380 1394 fossil_exit(0); 1381 1395 } ................................................................................ 1738 1752 ** 1739 1753 ** See also: cgi, server, winsrv 1740 1754 */ 1741 1755 void cmd_http(void){ 1742 1756 const char *zIpAddr; 1743 1757 const char *zNotFound; 1744 1758 const char *zHost; 1745 - const char *zAltBase; 1746 1759 const char *zFileGlob; 1747 1760 1748 1761 /* The winhttp module passes the --files option as --files-urlenc with 1749 1762 ** the argument being URL encoded, to avoid wildcard expansion in the 1750 1763 ** shell. This option is for internal use and is undocumented. 1751 1764 */ 1752 1765 zFileGlob = find_option("files-urlenc",0,1); ................................................................................ 1756 1769 zFileGlob = z; 1757 1770 }else{ 1758 1771 zFileGlob = find_option("files",0,1); 1759 1772 } 1760 1773 zNotFound = find_option("notfound", 0, 1); 1761 1774 g.useLocalauth = find_option("localauth", 0, 0)!=0; 1762 1775 g.sslNotAvailable = find_option("nossl", 0, 0)!=0; 1763 - zAltBase = find_option("baseurl", 0, 1); 1764 - if( zAltBase ) set_base_url(zAltBase); 1776 + g.zAltBase = find_option("baseurl", 0, 1); 1777 + set_base_url(0); 1765 1778 if( find_option("https",0,0)!=0 ) cgi_replace_parameter("HTTPS","on"); 1766 1779 zHost = find_option("host", 0, 1); 1767 1780 if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost); 1768 1781 g.cgiOutput = 1; 1782 + g.httpIn = stdin; 1783 + g.httpOut = stdout; 1769 1784 if( g.argc!=2 && g.argc!=3 && g.argc!=6 ){ 1770 1785 fossil_fatal("no repository specified"); 1771 1786 } 1772 1787 g.fullHttpReply = 1; 1773 1788 if( g.argc==6 ){ 1774 1789 g.httpIn = fossil_fopen(g.argv[3], "rb"); 1775 1790 g.httpOut = fossil_fopen(g.argv[4], "wb"); 1776 1791 zIpAddr = g.argv[5]; 1777 1792 }else{ 1778 - g.httpIn = stdin; 1779 - g.httpOut = stdout; 1780 1793 zIpAddr = 0; 1781 1794 } 1782 1795 find_server_repository(0); 1783 1796 g.zRepositoryName = enter_chroot_jail(g.zRepositoryName); 1784 1797 cgi_handle_http_request(zIpAddr); 1785 1798 process_one_web_page(zNotFound, glob_create(zFileGlob)); 1786 1799 } ................................................................................ 1886 1899 int iPort, mxPort; /* Range of TCP ports allowed */ 1887 1900 const char *zPort; /* Value of the --port option */ 1888 1901 const char *zBrowser; /* Name of web browser program */ 1889 1902 char *zBrowserCmd = 0; /* Command to launch the web browser */ 1890 1903 int isUiCmd; /* True if command is "ui", not "server' */ 1891 1904 const char *zNotFound; /* The --notfound option or NULL */ 1892 1905 int flags = 0; /* Server flags */ 1893 - const char *zAltBase; /* Argument to the --baseurl option */ 1894 1906 const char *zFileGlob; /* Static content must match this */ 1895 1907 1896 1908 #if defined(_WIN32) 1897 1909 const char *zStopperFile; /* Name of file used to terminate server */ 1898 1910 zStopperFile = find_option("stopper", 0, 1); 1899 1911 #endif 1900 1912 ................................................................................ 1902 1914 g.thTrace = find_option("th-trace", 0, 0)!=0; 1903 1915 g.useLocalauth = find_option("localauth", 0, 0)!=0; 1904 1916 if( g.thTrace ){ 1905 1917 blob_zero(&g.thLog); 1906 1918 } 1907 1919 zPort = find_option("port", "P", 1); 1908 1920 zNotFound = find_option("notfound", 0, 1); 1909 - zAltBase = find_option("baseurl", 0, 1); 1910 - if( zAltBase ){ 1911 - set_base_url(zAltBase); 1912 - } 1921 + g.zAltBase = find_option("baseurl", 0, 1); 1922 + set_base_url(0); 1913 1923 if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?"); 1914 1924 isUiCmd = g.argv[1][0]=='u'; 1915 1925 if( isUiCmd ){ 1916 1926 flags |= HTTP_SERVER_LOCALHOST; 1917 1927 g.useLocalauth = 1; 1918 1928 } 1919 1929 find_server_repository(isUiCmd && zNotFound==0);
Changes to src/rss.c.
20 20 #include "config.h" 21 21 #include <time.h> 22 22 #include "rss.h" 23 23 #include <assert.h> 24 24 25 25 /* 26 26 ** WEBPAGE: timeline.rss 27 +** URL: /timeline.rss/y=TYPE&n=LIMIT&tkt=UUID&tag=TAG&wiki=NAME&name=FILENAME 28 +** 29 +** Produce an RSS feed of the timeline. 30 +** 31 +** TYPE may be: all, ci (show checkins only), t (show tickets only), 32 +** w (show wiki only). LIMIT is the number of items to show. 33 +** 34 +** tkt=UUID filters for only those events for the specified ticket. tag=TAG 35 +** filters for a tag, and wiki=NAME for a wiki page. Only one may be used. 36 +** 37 +** In addition, name=FILENAME filters for a specific file. This may be 38 +** combined with one of the other filters (useful for looking at a specific 39 +** branch). 27 40 */ 41 + 28 42 void page_timeline_rss(void){ 29 43 Stmt q; 30 44 int nLine=0; 31 45 char *zPubDate, *zProjectName, *zProjectDescr, *zFreeProjectName=0; 32 46 Blob bSQL; 33 47 const char *zType = PD("y","all"); /* Type of events. All if NULL */ 48 + const char *zTicketUuid = PD("tkt",NULL); 49 + const char *zTag = PD("tag",NULL); 50 + const char *zFilename = PD("name",NULL); 51 + const char *zWiki = PD("wiki",NULL); 34 52 int nLimit = atoi(PD("n","20")); 53 + int nTagId; 35 54 const char zSQL1[] = 36 55 @ SELECT 37 56 @ blob.rid, 38 57 @ uuid, 39 58 @ event.mtime, 40 59 @ coalesce(ecomment,comment), 41 60 @ coalesce(euser,user), ................................................................................ 60 79 blob_appendf(&bSQL, " AND event.type=%Q", zType); 61 80 }else{ 62 81 if( !g.perm.Read ){ 63 82 if( g.perm.RdTkt && g.perm.RdWiki ){ 64 83 blob_append(&bSQL, " AND event.type!='ci'", -1); 65 84 }else if( g.perm.RdTkt ){ 66 85 blob_append(&bSQL, " AND event.type=='t'", -1); 86 + 67 87 }else{ 68 88 blob_append(&bSQL, " AND event.type=='w'", -1); 69 89 } 70 90 }else if( !g.perm.RdWiki ){ 71 91 if( g.perm.RdTkt ){ 72 92 blob_append(&bSQL, " AND event.type!='w'", -1); 73 93 }else{ ................................................................................ 74 94 blob_append(&bSQL, " AND event.type=='ci'", -1); 75 95 } 76 96 }else if( !g.perm.RdTkt ){ 77 97 assert( !g.perm.RdTkt &&& g.perm.Read && g.perm.RdWiki ); 78 98 blob_append(&bSQL, " AND event.type!='t'", -1); 79 99 } 80 100 } 101 + 102 + if( zTicketUuid ){ 103 + nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'", 104 + zTicketUuid); 105 + if ( nTagId==0 ){ 106 + nTagId = -1; 107 + } 108 + }else if( zTag ){ 109 + nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'sym-%q*'", 110 + zTag); 111 + if ( nTagId==0 ){ 112 + nTagId = -1; 113 + } 114 + }else if( zWiki ){ 115 + nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'wiki-%q*'", 116 + zWiki); 117 + if ( nTagId==0 ){ 118 + nTagId = -1; 119 + } 120 + }else{ 121 + nTagId = 0; 122 + } 123 + 124 + if( nTagId==-1 ){ 125 + blob_appendf(&bSQL, " AND 0"); 126 + }else if( nTagId!=0 ){ 127 + blob_appendf(&bSQL, " AND (EXISTS(SELECT 1 FROM tagxref" 128 + " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid))", nTagId); 129 + } 130 + 131 + if( zFilename ){ 132 + blob_appendf(&bSQL, 133 + " AND (SELECT mlink.fnid FROM mlink WHERE event.objid=mlink.mid) IN (SELECT fnid FROM filename WHERE name=%Q %s)", 134 + zFilename, filename_collation() 135 + ); 136 + } 81 137 82 138 blob_append( &bSQL, " ORDER BY event.mtime DESC", -1 ); 83 139 84 140 cgi_set_content_type("application/rss+xml"); 85 141 86 142 zProjectName = db_get("project-name", 0); 87 143 if( zProjectName==0 ){
Changes to src/url.c.
61 61 if( strncmp(zUrl, "http://", 7)==0 62 62 || strncmp(zUrl, "https://", 8)==0 63 63 || strncmp(zUrl, "ssh://", 6)==0 64 64 ){ 65 65 int iStart; 66 66 char *zLogin; 67 67 char *zExe; 68 + char cQuerySep = '?'; 68 69 69 70 g.urlIsFile = 0; 70 71 if( zUrl[4]=='s' ){ 71 72 g.urlIsHttps = 1; 72 73 g.urlProtocol = "https"; 73 74 g.urlDfltPort = 443; 74 75 iStart = 8; 75 76 }else if( zUrl[0]=='s' ){ 76 77 g.urlIsSsh = 1; 77 78 g.urlProtocol = "ssh"; 78 79 g.urlDfltPort = 22; 79 80 g.urlFossil = "fossil"; 81 + g.urlShell = 0; 80 82 iStart = 6; 81 83 }else{ 82 84 g.urlIsHttps = 0; 83 85 g.urlProtocol = "http"; 84 86 g.urlDfltPort = 80; 85 87 iStart = 7; 86 88 } ................................................................................ 142 144 if( g.urlPath[i] ){ 143 145 g.urlPath[i] = 0; 144 146 i++; 145 147 } 146 148 if( fossil_strcmp(zName,"fossil")==0 ){ 147 149 g.urlFossil = zValue; 148 150 dehttpize(g.urlFossil); 149 - zExe = mprintf("?fossil=%T", g.urlFossil); 151 + zExe = mprintf("%cfossil=%T", cQuerySep, g.urlFossil); 152 + cQuerySep = '&'; 153 + } 154 + if( fossil_strcmp(zName,"shell")==0 ){ 155 + g.urlShell = zValue; 156 + dehttpize(g.urlShell); 157 + zExe = mprintf("%cshell=%T", cQuerySep, g.urlFossil); 158 + cQuerySep = '&'; 150 159 } 151 160 } 152 161 153 162 dehttpize(g.urlPath); 154 163 if( g.urlDfltPort==g.urlPort ){ 155 164 g.urlCanonical = mprintf( 156 165 "%s://%s%T%T%s",
Changes to src/wikiformat.c.
822 822 blob_appendf(pOut, "</%s>", aMarkup[p->iCode].zName); 823 823 }else{ 824 824 blob_appendf(pOut, "<%s", aMarkup[p->iCode].zName); 825 825 for(i=0; i<p->nAttr; i++){ 826 826 blob_appendf(pOut, " %s", aAttribute[p->aAttr[i].iACode].zName); 827 827 if( p->aAttr[i].zValue ){ 828 828 const char *zVal = p->aAttr[i].zValue; 829 - if( p->aAttr[i].iACode==ATTR_SRC && zVal[0]=='/' ){ 829 + if( p->aAttr[i].iACode==ATTR_SRC && zVal[0]=='/' 830 + && (zVal[0]==0 || zVal[1]!='/') ){ 830 831 blob_appendf(pOut, "=\"%s%s\"", g.zTop, zVal); 831 832 }else{ 832 833 blob_appendf(pOut, "=\"%s\"", zVal); 833 834 } 834 835 } 835 836 } 836 837 if (p->iType & MUTYPE_SINGLE){ ................................................................................ 1169 1170 const char *z; 1170 1171 1171 1172 assert( nClose>=20 ); 1172 1173 if( strncmp(zTarget, "http:", 5)==0 1173 1174 || strncmp(zTarget, "https:", 6)==0 1174 1175 || strncmp(zTarget, "ftp:", 4)==0 1175 1176 || strncmp(zTarget, "mailto:", 7)==0 1177 + || strncmp(zTarget, "//", 2)==0 1176 1178 ){ 1177 1179 blob_appendf(p->pOut, "<a href=\"%s\">", zTarget); 1178 1180 }else if( zTarget[0]=='/' ){ 1179 1181 blob_appendf(p->pOut, "<a href=\"%s%h\">", g.zTop, zTarget); 1180 1182 }else if( zTarget[0]=='.' 1181 1183 && (zTarget[1]=='/' || (zTarget[1]=='.' && zTarget[2]=='/')) 1182 1184 && (p->state & WIKI_LINKSONLY)==0 ){
Changes to src/xfer.c.
18 18 ** This file contains code to implement the file transfer protocol. 19 19 */ 20 20 #include "config.h" 21 21 #include "xfer.h" 22 22 23 23 #include <time.h> 24 24 25 +/* 26 +** Maximum number of HTTP redirects that any http_exchange() call will 27 +** follow before throwing a fatal error. Most browsers use a limit of 20. 28 +*/ 29 +#define MAX_REDIRECTS 20 30 + 25 31 /* 26 32 ** This structure holds information about the current state of either 27 33 ** a client or a server that is participating in xfer. 28 34 */ 29 35 typedef struct Xfer Xfer; 30 36 struct Xfer { 31 37 Blob *pIn; /* Input text from the other side */ ................................................................................ 1478 1484 xfer.nDeltaSent = 0; 1479 1485 xfer.nGimmeSent = 0; 1480 1486 xfer.nIGotSent = 0; 1481 1487 if( syncFlags & SYNC_VERBOSE ){ 1482 1488 fossil_print("waiting for server..."); 1483 1489 } 1484 1490 fflush(stdout); 1485 - if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0) ){ 1491 + if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0, 1492 + MAX_REDIRECTS) ){ 1486 1493 nErr++; 1487 1494 break; 1488 1495 } 1489 1496 lastPctDone = -1; 1490 1497 blob_reset(&send); 1491 1498 rArrivalTime = db_double(0.0, "SELECT julianday('now')"); 1492 1499
Changes to www/build.wiki.
52 52 These link will build a ZIP archive or a gzip-compressed tarball of the 53 53 complete source code and download it to your browser. 54 54 </ol> 55 55 56 56 <h2>2.0 Compiling</h2> 57 57 58 58 <ol> 59 -<li value="6"> 59 +<li value="5"> 60 60 <p>Unpack the ZIP or tarball you downloaded then 61 61 <b>cd</b> into the directory created.</p></li> 62 62 63 63 <li><i>(Optional, unix only)</i> 64 64 Run <b>./configure</b> to construct a makefile. 65 65 66 66 <ol type="a"> ................................................................................ 99 99 "<b>nmake /f Makefile.msc</b>". 100 100 </ol> 101 101 </ol> 102 102 103 103 <h2>3.0 Installing</h2> 104 104 105 105 <ol> 106 -<li value="9"> 106 +<li value="8"> 107 107 <p>The finished binary is named "fossil" (or "fossil.exe" on windows). 108 108 Put this binary in a 109 109 directory that is somewhere on your PATH environment variable. 110 110 It does not matter where.</p> 111 111 112 112 <li> 113 113 <p><b>(Optional:)</b>