Changes On Branch use-fossil_strcmp-everywhere
Not logged in

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#### Tcl shell for use in running the fossil testsuite.  If you do not
#    care about testing the end result, this can be blank.
#
TCLSH = tclsh

LIB =	@LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@
TCC +=	@EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H -Dstrcmp=fossil_strcmp
INSTALLDIR = $(DESTDIR)@prefix@/bin
USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@
FOSSIL_ENABLE_TCL = @FOSSIL_ENABLE_TCL@
FOSSIL_ENABLE_TCL_STUBS = @FOSSIL_ENABLE_TCL_STUBS@

include $(SRCDIR)/main.mk

distclean: clean
	rm -f autoconfig.h config.log Makefile






|









35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#### Tcl shell for use in running the fossil testsuite.  If you do not
#    care about testing the end result, this can be blank.
#
TCLSH = tclsh

LIB =	@LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@
TCC +=	@EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H
INSTALLDIR = $(DESTDIR)@prefix@/bin
USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@
FOSSIL_ENABLE_TCL = @FOSSIL_ENABLE_TCL@
FOSSIL_ENABLE_TCL_STUBS = @FOSSIL_ENABLE_TCL_STUBS@

include $(SRCDIR)/main.mk

distclean: clean
	rm -f autoconfig.h config.log Makefile

Changes to auto.def.

231
232
233
234
235
236
237

238
239
240
cc-check-function-in-lib iconv iconv

# Check for getpassphrase() for Solaris 10 where getpass() truncates to 10 chars
if {![cc-check-functions getpassphrase]} {
    # Haiku needs this
    cc-check-function-in-lib getpass bsd
}


make-template Makefile.in
make-config-header autoconfig.h -auto {USE_* FOSSIL_*}






>



231
232
233
234
235
236
237
238
239
240
241
cc-check-function-in-lib iconv iconv

# Check for getpassphrase() for Solaris 10 where getpass() truncates to 10 chars
if {![cc-check-functions getpassphrase]} {
    # Haiku needs this
    cc-check-function-in-lib getpass bsd
}
cc-check-function-in-lib dlopen dl

make-template Makefile.in
make-config-header autoconfig.h -auto {USE_* FOSSIL_*}

Changes to compat/zlib/configure.

812
813
814
815
816
817
818

/^sharedlibdir *=/s#=.*#=$sharedlibdir#
/^includedir *=/s#=.*#=$includedir#
/^mandir *=/s#=.*#=$mandir#
/^LDFLAGS *=/s#=.*#=$LDFLAGS#
" | sed -e "
s/\@VERSION\@/$VER/g;
" > zlib.pc







>
812
813
814
815
816
817
818
819
/^sharedlibdir *=/s#=.*#=$sharedlibdir#
/^includedir *=/s#=.*#=$includedir#
/^mandir *=/s#=.*#=$mandir#
/^LDFLAGS *=/s#=.*#=$LDFLAGS#
" | sed -e "
s/\@VERSION\@/$VER/g;
" > zlib.pc
#

Changes to src/blob.c.

1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117


1118
1119
1120
1121
1122
1123
1124

1125
1126
1127
1128
1129
1130
1131
    struct Blob temp;
    zUtf8 = blob_str(pBlob) + bomSize;
    blob_zero(&temp);
    blob_append(&temp, zUtf8, -1);
    blob_swap(pBlob, &temp);
    blob_reset(&temp);
#ifdef _WIN32
  }else if( starts_with_utf16le_bom(pBlob, &bomSize) ){
    /* Make sure the blob contains two terminating 0-bytes */
    blob_append(pBlob, "", 1);
    zUtf8 = blob_str(pBlob) + bomSize;
    zUtf8 = fossil_unicode_to_utf8(zUtf8);
    blob_zero(pBlob);
    blob_append(pBlob, zUtf8, -1);
    fossil_unicode_free(zUtf8);
  }else if( starts_with_utf16be_bom(pBlob, &bomSize) ){


    unsigned int i = blob_size(pBlob);
    zUtf8 = blob_buffer(pBlob);
    while( i > 0 ){
      /* swap bytes of unicode representation */
      char zTemp = zUtf8[--i];
      zUtf8[i] = zUtf8[i-1];
      zUtf8[--i] = zTemp;

    }
    /* Make sure the blob contains two terminating 0-bytes */
    blob_append(pBlob, "", 1);
    zUtf8 = blob_str(pBlob) + bomSize;
    zUtf8 = fossil_unicode_to_utf8(zUtf8);
    blob_zero(pBlob);
    blob_append(pBlob, zUtf8, -1);






|
<
<
|
<
<
<
<
<
>
>
|
<
|
|
|
|
|
>







1102
1103
1104
1105
1106
1107
1108
1109


1110





1111
1112
1113

1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
    struct Blob temp;
    zUtf8 = blob_str(pBlob) + bomSize;
    blob_zero(&temp);
    blob_append(&temp, zUtf8, -1);
    blob_swap(pBlob, &temp);
    blob_reset(&temp);
#ifdef _WIN32
  }else if( starts_with_utf16_bom(pBlob, &bomSize) ){


    zUtf8 = blob_buffer(pBlob);





    if (*((unsigned short *)zUtf8) == 0xfffe) {
      /* Found BOM, but with reversed bytes */
      unsigned int i = blob_size(pBlob);

      while( i > 0 ){
        /* swap bytes of unicode representation */
        char zTemp = zUtf8[--i];
        zUtf8[i] = zUtf8[i-1];
        zUtf8[--i] = zTemp;
      }
    }
    /* Make sure the blob contains two terminating 0-bytes */
    blob_append(pBlob, "", 1);
    zUtf8 = blob_str(pBlob) + bomSize;
    zUtf8 = fossil_unicode_to_utf8(zUtf8);
    blob_zero(pBlob);
    blob_append(pBlob, zUtf8, -1);

Changes to src/checkin.c.

614
615
616
617
618
619
620


621
622

623
624
625
626
627
628
629
630
631
632
633
634



635
636
637
638
639
640

641
642
643
644
645
646
647
....
1197
1198
1199
1200
1201
1202
1203
1204





1205
1206
1207
1208
1209
1210
1211
**
** The last element of aCommitFile[] is always 0 - indicating the end
** of the array.
**
** If there were no arguments passed to [commit], aCommitFile is not
** allocated and remains NULL. Other parts of the code interpret this
** to mean "all files".


*/
void select_commit_files(void){

  if( g.argc>2 ){
    int ii;
    Blob b;
    blob_zero(&b);
    g.aCommitFile = fossil_malloc(sizeof(int)*(g.argc-1));

    for(ii=2; ii<g.argc; ii++){
      int iId;
      file_tree_name(g.argv[ii], &b, 1);
      iId = db_int(-1, "SELECT id FROM vfile WHERE pathname=%Q", blob_str(&b));
      if( iId<0 ){
        fossil_fatal("fossil knows nothing about: %s", g.argv[ii]);



      }
      g.aCommitFile[ii-2] = iId;
      blob_reset(&b);
    }
    g.aCommitFile[ii-2] = 0;
  }

}

/*
** Make sure the current check-in with timestamp zDate is younger than its
** ancestor identified rid and zUuid.  Throw a fatal error if not.
*/
static void checkin_verify_younger(
................................................................................
  ** follows "commit", then only those files are committed.
  **
  ** After the following function call has returned, the Global.aCommitFile[]
  ** array is allocated to contain the "id" field from the vfile table
  ** for each file to be committed. Or, if aCommitFile is NULL, all files
  ** should be committed.
  */
  select_commit_files();





  isAMerge = db_exists("SELECT 1 FROM vmerge WHERE id=0");
  if( g.aCommitFile && isAMerge ){
    fossil_fatal("cannot do a partial commit of a merge");
  }

  /* Doing "fossil mv fileA fileB; fossil add fileA; fossil commit fileA"
  ** will generate a manifest that has two fileA entries, which is illegal.






>
>

|
>

|









|
>
>
>

<


|

>







 







|
>
>
>
>
>







614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641

642
643
644
645
646
647
648
649
650
651
652
653
....
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
**
** The last element of aCommitFile[] is always 0 - indicating the end
** of the array.
**
** If there were no arguments passed to [commit], aCommitFile is not
** allocated and remains NULL. Other parts of the code interpret this
** to mean "all files".
**
** Returns 1 if there was a warning, 0 otherwise.
*/
int select_commit_files(void){
  int result = 0;
  if( g.argc>2 ){
    int ii, jj=0;
    Blob b;
    blob_zero(&b);
    g.aCommitFile = fossil_malloc(sizeof(int)*(g.argc-1));

    for(ii=2; ii<g.argc; ii++){
      int iId;
      file_tree_name(g.argv[ii], &b, 1);
      iId = db_int(-1, "SELECT id FROM vfile WHERE pathname=%Q", blob_str(&b));
      if( iId<0 ){
        fossil_warning("fossil knows nothing about: %s", g.argv[ii]);
        result = 1;
      } else {
        g.aCommitFile[jj++] = iId;
      }

      blob_reset(&b);
    }
    g.aCommitFile[jj] = 0;
  }
  return result;
}

/*
** Make sure the current check-in with timestamp zDate is younger than its
** ancestor identified rid and zUuid.  Throw a fatal error if not.
*/
static void checkin_verify_younger(
................................................................................
  ** follows "commit", then only those files are committed.
  **
  ** After the following function call has returned, the Global.aCommitFile[]
  ** array is allocated to contain the "id" field from the vfile table
  ** for each file to be committed. Or, if aCommitFile is NULL, all files
  ** should be committed.
  */
  if ( select_commit_files() ){
    blob_zero(&ans);
    prompt_user("continue (y/N)? ", &ans);
    cReply = blob_str(&ans)[0];
    if( cReply!='y' && cReply!='Y' ) fossil_exit(1);;
  }
  isAMerge = db_exists("SELECT 1 FROM vmerge WHERE id=0");
  if( g.aCommitFile && isAMerge ){
    fossil_fatal("cannot do a partial commit of a merge");
  }

  /* Doing "fossil mv fileA fileB; fossil add fileA; fossil commit fileA"
  ** will generate a manifest that has two fileA entries, which is illegal.

Changes to src/cson_amalgamation.c.

4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
    }
    else if( buf->capacity >= n )
    {
        return 0;
    }
    else
    {
        unsigned char * x = (unsigned char *)realloc( buf->mem, n );
        if( ! x ) return cson_rc.AllocError;
        memset( x + buf->used, 0, n - buf->used );
        buf->mem = x;
        buf->capacity = n;
        ++buf->timesExpanded;
        return 0;
    }






|







4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
    }
    else if( buf->capacity >= n )
    {
        return 0;
    }
    else
    {
        unsigned char * x = (unsigned char *)cson_realloc( buf->mem, n, "cson_buffer::mem" );
        if( ! x ) return cson_rc.AllocError;
        memset( x + buf->used, 0, n - buf->used );
        buf->mem = x;
        buf->capacity = n;
        ++buf->timesExpanded;
        return 0;
    }

Changes to src/diff.c.

357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388

389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
/*
** This function returns non-zero if the blob starts with a UTF-16le or
** UTF-16be byte-order-mark (BOM).
*/
int starts_with_utf16_bom(const Blob *pContent, int *pnByte){
  const char *z = blob_buffer(pContent);
  int c1, c2;

  if( pnByte ) *pnByte = 2;
  if( blob_size(pContent)<2 ) return 0;
  c1 = z[0]; c2 = z[1];
  if( (c1==(char)0xff) && (c2==(char)0xfe) ){
    return 1;
  }else if( (c1==(char)0xfe) && (c2==(char)0xff) ){
    return 1;
  }
  return 0;
}

/*
** This function returns non-zero if the blob starts with a UTF-16le
** byte-order-mark (BOM).
*/
int starts_with_utf16le_bom(const Blob *pContent, int *pnByte){
  const char *z = blob_buffer(pContent);
  int c1, c2;

  if( pnByte ) *pnByte = 2;
  if( blob_size(pContent)<2 ) return 0;
  c1 = z[0]; c2 = z[1];
  if( (c1==(char)0xff) && (c2==(char)0xfe) ){

    return 1;
  }
  return 0;
}

/*
** This function returns non-zero if the blob starts with a UTF-16be
** byte-order-mark (BOM).
*/
int starts_with_utf16be_bom(const Blob *pContent, int *pnByte){
  const char *z = blob_buffer(pContent);
  int c1, c2;

  if( pnByte ) *pnByte = 2;
  if( blob_size(pContent)<2 ) return 0;
  c1 = z[0]; c2 = z[1];
  if( (c1==(char)0xfe) && (c2==(char)0xff) ){
    return 1;
  }
  return 0;
}

/*
** Return true if two DLine elements are identical.
*/






|


|
|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
>
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







357
358
359
360
361
362
363
364
365
366
367
368
369
















370


371
372

















373
374
375
376
377
378
379
/*
** This function returns non-zero if the blob starts with a UTF-16le or
** UTF-16be byte-order-mark (BOM).
*/
int starts_with_utf16_bom(const Blob *pContent, int *pnByte){
  const char *z = blob_buffer(pContent);
  int c1;

  if( pnByte ) *pnByte = 2;
  if( (blob_size(pContent)<2) || (blob_size(pContent)&1)) return 0;
  c1 = ((unsigned short *)z)[0];
  if( (c1==0xfeff) || (c1==0xfffe) ){
















    if( blob_size(pContent) < 4 ) return 1;


    c1 = ((unsigned short *)z)[1];
    if( c1 != 0 ) return 1;

















  }
  return 0;
}

/*
** Return true if two DLine elements are identical.
*/

Changes to src/http.c.

128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
...
229
230
231
232
233
234
235




236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
** in pRecv.  pRecv is assumed to be uninitialized when
** this routine is called - this routine will initialize it.
**
** The server address is contain in the "g" global structure.  The
** url_parse() routine should have been called prior to this routine
** in order to fill this structure appropriately.
*/
int http_exchange(Blob *pSend, Blob *pReply, int useLogin){
  Blob login;           /* The login card */
  Blob payload;         /* The complete payload including login card */
  Blob hdr;             /* The HTTP request header */
  int closeConnection;  /* True to close the connection when done */
  int iLength;          /* Length of the reply payload */
  int rc = 0;           /* Result code */
  int iHttpVersion;     /* Which version of HTTP protocol server uses */
................................................................................
      if( c=='c' || c=='C' ){
        closeConnection = 1;
      }else if( c=='k' || c=='K' ){
        closeConnection = 0;
      }
    }else if( rc==302 && fossil_strnicmp(zLine, "location:", 9)==0 ){
      int i, j;




      for(i=9; zLine[i] && zLine[i]==' '; i++){}
      if( zLine[i]==0 ) fossil_fatal("malformed redirect: %s", zLine);
      j = strlen(zLine) - 1; 
      while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
         j -= 4;
         zLine[j] = 0;
      }
      fossil_print("redirect to %s\n", &zLine[i]);
      url_parse(&zLine[i]);
      transport_close();
      return http_exchange(pSend, pReply, useLogin);
    }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
      if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
        isCompressed = 0;
      }else if( fossil_strnicmp(&zLine[14], 
                          "application/x-fossil-uncompressed", -1)==0 ){
        isCompressed = 0;
      }else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){






|







 







>
>
>
>










|







128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
...
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
** in pRecv.  pRecv is assumed to be uninitialized when
** this routine is called - this routine will initialize it.
**
** The server address is contain in the "g" global structure.  The
** url_parse() routine should have been called prior to this routine
** in order to fill this structure appropriately.
*/
int http_exchange(Blob *pSend, Blob *pReply, int useLogin, int maxRedirect){
  Blob login;           /* The login card */
  Blob payload;         /* The complete payload including login card */
  Blob hdr;             /* The HTTP request header */
  int closeConnection;  /* True to close the connection when done */
  int iLength;          /* Length of the reply payload */
  int rc = 0;           /* Result code */
  int iHttpVersion;     /* Which version of HTTP protocol server uses */
................................................................................
      if( c=='c' || c=='C' ){
        closeConnection = 1;
      }else if( c=='k' || c=='K' ){
        closeConnection = 0;
      }
    }else if( rc==302 && fossil_strnicmp(zLine, "location:", 9)==0 ){
      int i, j;

      if ( --maxRedirect == 0){
        fossil_fatal("redirect limit exceeded");
      }
      for(i=9; zLine[i] && zLine[i]==' '; i++){}
      if( zLine[i]==0 ) fossil_fatal("malformed redirect: %s", zLine);
      j = strlen(zLine) - 1; 
      while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
         j -= 4;
         zLine[j] = 0;
      }
      fossil_print("redirect to %s\n", &zLine[i]);
      url_parse(&zLine[i]);
      transport_close();
      return http_exchange(pSend, pReply, useLogin, maxRedirect);
    }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
      if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
        isCompressed = 0;
      }else if( fossil_strnicmp(&zLine[14], 
                          "application/x-fossil-uncompressed", -1)==0 ){
        isCompressed = 0;
      }else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){

Changes to src/http_transport.c.

181
182
183
184
185
186
187

188
189
190
191
192
193
194
...
217
218
219
220
221
222
223

224
225
226

















227
228
229
230
231
232
233
234
235
























236
237
238
239
240
241
242
...
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
...
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
...
436
437
438
439
440
441
442
443



444
445
446
447
448
449
450
...
458
459
460
461
462
463
464

465
466
467
468
469
470
471
...
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
  if( g.urlIsSsh ){
    /* Only SSH requires a global initialization.  For SSH we need to create
    ** and run an SSH command to talk to the remote machine.
    */
    const char *zSsh;  /* The base SSH command */
    Blob zCmd;         /* The SSH command */
    char *zHost;       /* The host name to contact */


    zSsh = db_get("ssh-command", zDefaultSshCmd);
    blob_init(&zCmd, zSsh, -1);
    if( g.urlPort!=g.urlDfltPort ){
#ifdef __MINGW32__
      blob_appendf(&zCmd, " -P %d", g.urlPort);
#else
................................................................................
        blob_reset(&pw);
        fossil_print(" -pw ********");  /* Do not show the password text */
      }
#endif
    }else{
      zHost = mprintf("%s", g.urlName);
    }

    blob_append(&zCmd, " ", 1);
    shell_escape(&zCmd, zHost);
    fossil_print(" %s\n", zHost);  /* Show the conclusion of the SSH command */

















    free(zHost);
    popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid);
    if( sshPid==0 ){
      fossil_fatal("cannot start ssh tunnel using [%b]", &zCmd);
    }
    blob_reset(&zCmd);
    transport_ssh_startup();
  }
}

























/*
** Open a connection to the server.  The server is defined by the following
** global variables:
**
**   g.urlName        Name of the server.  Ex: www.fossil-scm.org
**   g.urlPort        TCP/IP port.  Ex: 80
................................................................................
  if( transport.isOpen==0 ){
    if( g.urlIsSsh ){
      Blob cmd;
      blob_zero(&cmd);
      shell_escape(&cmd, g.urlFossil);
      blob_append(&cmd, " test-http ", -1);
      shell_escape(&cmd, g.urlPath);
      /* printf("%s\n", blob_str(&cmd)); fflush(stdout); */
      fprintf(sshOut, "%s\n", blob_str(&cmd));
      fflush(sshOut);
      blob_reset(&cmd);
    }else if( g.urlIsHttps ){
      #ifdef FOSSIL_ENABLE_SSL
      rc = ssl_open();
      if( rc==0 ) transport.isOpen = 1;
      #else
      socket_set_errmsg("HTTPS: Fossil has been compiled without SSL support");
................................................................................
*/
static int transport_fetch(char *zBuf, int N){
  int got;
  if( sshIn ){
    int x;
    int wanted = N;
    got = 0;
    /* printf("want %d bytes...\n", wanted); fflush(stdout); */
    while( wanted>0 ){
      x = read(sshIn, &zBuf[got], wanted);
      if( x<=0 ) break;
      got += x;
      wanted -= x;
    }
  }else if( g.urlIsHttps ){
................................................................................
** Return the number of bytes actually received.
*/
int transport_receive(char *zBuf, int N){
  int onHand;       /* Bytes current held in the transport buffer */
  int nByte = 0;    /* Bytes of content received */

  onHand = transport.nUsed - transport.iCursor;
  /* printf("request %d with %d on hand\n", N, onHand); fflush(stdout); */



  if( onHand>0 ){
    int toMove = onHand;
    if( toMove>N ) toMove = N;
    /* printf("bytes on hand: %d of %d\n", toMove, N); fflush(stdout); */
    memcpy(zBuf, &transport.pBuf[transport.iCursor], toMove);
    transport.iCursor += toMove;
    if( transport.iCursor>=transport.nUsed ){
................................................................................
  if( N>0 ){
    int got = transport_fetch(zBuf, N);
    if( got>0 ){
      nByte += got;
      transport.nRcvd += got;
    }
  }

  return nByte;
}

/*
** Load up to N new bytes of content into the transport.pBuf buffer.
** The buffer itself might be moved.  And the transport.iCursor value
** might be reset to 0.
................................................................................
        transport.pBuf[i] = 0;
        i--;
      }
      break;
    }
    i++;
  }
   /* printf("Got line: [%s]\n", &transport.pBuf[iStart]); */
  return &transport.pBuf[iStart];
}

void transport_global_shutdown(void){
  if( g.urlIsSsh && sshPid ){
    /*printf("Closing SSH tunnel: ");*/
    fflush(stdout);






>







 







>


<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>









>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|
|
|







 







<







 







|
>
>
>







 







>







 







|







181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
...
218
219
220
221
222
223
224
225
226
227

228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
...
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
...
443
444
445
446
447
448
449

450
451
452
453
454
455
456
...
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
...
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
...
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
  if( g.urlIsSsh ){
    /* Only SSH requires a global initialization.  For SSH we need to create
    ** and run an SSH command to talk to the remote machine.
    */
    const char *zSsh;  /* The base SSH command */
    Blob zCmd;         /* The SSH command */
    char *zHost;       /* The host name to contact */
    int n;             /* Size of prefix string */

    zSsh = db_get("ssh-command", zDefaultSshCmd);
    blob_init(&zCmd, zSsh, -1);
    if( g.urlPort!=g.urlDfltPort ){
#ifdef __MINGW32__
      blob_appendf(&zCmd, " -P %d", g.urlPort);
#else
................................................................................
        blob_reset(&pw);
        fossil_print(" -pw ********");  /* Do not show the password text */
      }
#endif
    }else{
      zHost = mprintf("%s", g.urlName);
    }
    n = blob_size(&zCmd);
    blob_append(&zCmd, " ", 1);
    shell_escape(&zCmd, zHost);

    if( g.urlShell ){
      blob_appendf(&zCmd, " %s", g.urlShell);
    }else{
#if defined(FOSSIL_ENABLE_SSH_FAR_SIDE)
      /* The following works.  But only if the fossil on the remote side
      ** is recent enough to support the test-ssh-far-side command.  That
      ** command was added on 2013-02-06.  We will leave this turned off
      ** until most fossil servers have upgraded to that version or a later
      ** version.  The sync will still work as long as the shell on the far
      ** side is bash and not tcsh.  And if the default far side shell is
      ** tcsh, then the shell=/bin/bash query parameter can be used as a
      ** work-around.  Enable this code after about a year...
      */
      blob_appendf(&zCmd, " exec %s test-ssh-far-side", g.urlFossil);
#endif
    }
    fossil_print("%s\n", blob_str(&zCmd)+n);  /* Show tail of SSH command */
    free(zHost);
    popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid);
    if( sshPid==0 ){
      fossil_fatal("cannot start ssh tunnel using [%b]", &zCmd);
    }
    blob_reset(&zCmd);
    transport_ssh_startup();
  }
}

/*
** COMMAND: test-ssh-far-side
**
** Read lines of input text, one by one, and evaluate each line using
** system().  The ssh: sync protocol uses this on the far side of the
** SSH link.
*/
void test_ssh_far_side_cmd(void){
  int i = 0;
  int got;
  char zLine[5000];
  while( i<sizeof(zLine) ){
    got = read(0, zLine+i, 1);
    if( got==0 ) return;
    if( zLine[i]=='\n' ){
      zLine[i] = 0;
      system(zLine);
      i = 0;
    }else{
      i++;
    }
  }
}

/*
** Open a connection to the server.  The server is defined by the following
** global variables:
**
**   g.urlName        Name of the server.  Ex: www.fossil-scm.org
**   g.urlPort        TCP/IP port.  Ex: 80
................................................................................
  if( transport.isOpen==0 ){
    if( g.urlIsSsh ){
      Blob cmd;
      blob_zero(&cmd);
      shell_escape(&cmd, g.urlFossil);
      blob_append(&cmd, " test-http ", -1);
      shell_escape(&cmd, g.urlPath);
      fprintf(sshOut, "%s || true\n", blob_str(&cmd));
      fflush(sshOut);
      if( g.fSshTrace ) printf("Sent: [%s]\n", blob_str(&cmd));
      blob_reset(&cmd);
    }else if( g.urlIsHttps ){
      #ifdef FOSSIL_ENABLE_SSL
      rc = ssl_open();
      if( rc==0 ) transport.isOpen = 1;
      #else
      socket_set_errmsg("HTTPS: Fossil has been compiled without SSL support");
................................................................................
*/
static int transport_fetch(char *zBuf, int N){
  int got;
  if( sshIn ){
    int x;
    int wanted = N;
    got = 0;

    while( wanted>0 ){
      x = read(sshIn, &zBuf[got], wanted);
      if( x<=0 ) break;
      got += x;
      wanted -= x;
    }
  }else if( g.urlIsHttps ){
................................................................................
** Return the number of bytes actually received.
*/
int transport_receive(char *zBuf, int N){
  int onHand;       /* Bytes current held in the transport buffer */
  int nByte = 0;    /* Bytes of content received */

  onHand = transport.nUsed - transport.iCursor;
  if( g.fSshTrace){
    printf("Reading %d bytes with %d on hand...  ", N, onHand);
    fflush(stdout);
  }
  if( onHand>0 ){
    int toMove = onHand;
    if( toMove>N ) toMove = N;
    /* printf("bytes on hand: %d of %d\n", toMove, N); fflush(stdout); */
    memcpy(zBuf, &transport.pBuf[transport.iCursor], toMove);
    transport.iCursor += toMove;
    if( transport.iCursor>=transport.nUsed ){
................................................................................
  if( N>0 ){
    int got = transport_fetch(zBuf, N);
    if( got>0 ){
      nByte += got;
      transport.nRcvd += got;
    }
  }
  if( g.fSshTrace ) printf("Got %d bytes\n", nByte);
  return nByte;
}

/*
** Load up to N new bytes of content into the transport.pBuf buffer.
** The buffer itself might be moved.  And the transport.iCursor value
** might be reset to 0.
................................................................................
        transport.pBuf[i] = 0;
        i--;
      }
      break;
    }
    i++;
  }
  if( g.fSshTrace ) printf("Got line: [%s]\n", &transport.pBuf[iStart]);
  return &transport.pBuf[iStart];
}

void transport_global_shutdown(void){
  if( g.urlIsSsh && sshPid ){
    /*printf("Closing SSH tunnel: ");*/
    fflush(stdout);

Changes to src/json_detail.h.

197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
  char const * mtime;
  char const * payload;
  char const * requestId;
  char const * resultCode;
  char const * resultText;
  char const * timestamp;
} FossilJsonKeys_;
const FossilJsonKeys_ FossilJsonKeys;

/*
** A page/command dispatch helper for fossil_json_f() implementations.
** pages must be an array of JsonPageDef commands which we can
** dispatch. The final item in the array MUST have a NULL name
** element.
**






|







197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
  char const * mtime;
  char const * payload;
  char const * requestId;
  char const * resultCode;
  char const * resultText;
  char const * timestamp;
} FossilJsonKeys_;
extern const FossilJsonKeys_ FossilJsonKeys;

/*
** A page/command dispatch helper for fossil_json_f() implementations.
** pages must be an array of JsonPageDef commands which we can
** dispatch. The final item in the array MUST have a NULL name
** element.
**

Changes to src/main.c.

133
134
135
136
137
138
139

140
141
142
143
144
145
146
...
168
169
170
171
172
173
174
175

176
177
178
179
180
181
182
....
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123




1124
1125
1126
1127
1128
1129
1130
1131
1132
1133


1134
1135
1136
1137
1138
1139
1140
1141
....
1271
1272
1273
1274
1275
1276
1277

1278
1279
1280
1281
1282
1283
1284
....
1347
1348
1349
1350
1351
1352
1353




1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366


1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
....
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
....
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768


1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
....
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
....
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
  int fHttpTrace;         /* Trace outbound HTTP requests */
  int fSystemTrace;       /* Trace calls to fossil_system(), --systemtrace */
  int fSshTrace;          /* Trace the SSH setup traffic */
  int fNoSync;            /* Do not do an autosync ever.  --nosync */
  char *zPath;            /* Name of webpage being served */
  char *zExtra;           /* Extra path information past the webpage name */
  char *zBaseURL;         /* Full text of the URL being served */

  char *zTop;             /* Parent directory of zPath */
  const char *zContentType;  /* The content type of the input HTTP request */
  int iErrPriority;       /* Priority of current error message */
  char *zErrMsg;          /* Text of an error message */
  int sslNotAvailable;    /* SSL is not available.  Do not redirect to https: */
  Blob cgiIn;             /* Input to an xfer www method */
  int cgiOutput;          /* Write error and status messages to CGI */
................................................................................
  int urlPort;            /* TCP port number for http: or https: */
  int urlDfltPort;        /* The default port for the given protocol */
  char *urlPath;          /* Pathname for http: */
  char *urlUser;          /* User id for http: */
  char *urlPasswd;        /* Password for http: */
  char *urlCanonical;     /* Canonical representation of the URL */
  char *urlProxyAuth;     /* Proxy-Authorizer: string */
  char *urlFossil;        /* The path of the ?fossil=path suffix on ssh: */

  int dontKeepUrl;        /* Do not persist the URL */

  const char *zLogin;     /* Login name.  "" if not logged in. */
  const char *zSSLIdentity;  /* Value of --ssl-identity option, filename of SSL client identity */
  int useLocalauth;       /* No login required if from 127.0.0.1 */
  int noPswd;             /* Logged in without password (on 127.0.0.1) */
  int userUid;            /* Integer user id */
................................................................................

/*
** Set the g.zBaseURL value to the full URL for the toplevel of
** the fossil tree.  Set g.zTop to g.zBaseURL without the
** leading "http://" and the host and port.
**
** The g.zBaseURL is normally set based on HTTP_HOST and SCRIPT_NAME
** environment variables.  However, if zAltBase is not NULL then it
** is the argument to the --baseurl option command-line option and
** g.zBaseURL and g.zTop is set from that instead.




*/
static void set_base_url(const char *zAltBase){
  int i;
  const char *zHost;
  const char *zMode;
  const char *zCur;

  if( g.zBaseURL!=0 ) return;
  if( zAltBase ){
    int i, n, c;


    g.zTop = g.zBaseURL = mprintf("%s", zAltBase);
    if( memcmp(g.zTop, "http://", 7)!=0 && memcmp(g.zTop,"https://",8)!=0 ){
      fossil_fatal("argument to --baseurl should be 'http://host/path'"
                   " or 'https://host/path'");
    }
    for(i=n=0; (c = g.zTop[i])!=0; i++){
      if( c=='/' ){
        n++;
................................................................................
  ** repository based on the first element of PATH_INFO and open it.
  */
  zPathInfo = PD("PATH_INFO","");
  if( !g.repositoryOpen ){
    char *zRepo, *zToFree;
    const char *zOldScript = PD("SCRIPT_NAME", "");
    char *zNewScript;

    int j, k;
    i64 szFile;

    i = zPathInfo[0]!=0;
    while( 1 ){
      while( zPathInfo[i] && zPathInfo[i]!='/' ){ i++; }
      zRepo = zToFree = mprintf("%s%.*s.fossil",g.zRepositoryName,i,zPathInfo);
................................................................................
          cgi_set_status(404, "not found");
          cgi_reply();
        }
        return;
      }
      break;
    }




    zNewScript = mprintf("%s%.*s", zOldScript, i, zPathInfo);
    cgi_replace_parameter("PATH_INFO", &zPathInfo[i+1]);
    zPathInfo += i;
    cgi_replace_parameter("SCRIPT_NAME", zNewScript);
    db_open_repository(zRepo);
    if( g.fHttpTrace ){
      fprintf(stderr,
          "# repository: [%s]\n"
          "# new PATH_INFO = [%s]\n"
          "# new SCRIPT_NAME = [%s]\n",
          zRepo, zPathInfo, zNewScript);
    }
  }



  /* Find the page that the user has requested, construct and deliver that
  ** page.
  */
  if( g.zContentType && memcmp(g.zContentType, "application/x-fossil", 20)==0 ){
    zPathInfo = "/xfer";
  }
  set_base_url(0);
  if( zPathInfo==0 || zPathInfo[0]==0
      || (zPathInfo[0]=='/' && zPathInfo[1]==0) ){
#ifdef FOSSIL_ENABLE_JSON
    if(g.json.isJsonMode){
      json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,1);
      fossil_exit(0);
    }
................................................................................
**
** See also: cgi, server, winsrv
*/
void cmd_http(void){
  const char *zIpAddr;
  const char *zNotFound;
  const char *zHost;
  const char *zAltBase;
  const char *zFileGlob;

  /* The winhttp module passes the --files option as --files-urlenc with
  ** the argument being URL encoded, to avoid wildcard expansion in the 
  ** shell.  This option is for internal use and is undocumented.
  */
  zFileGlob = find_option("files-urlenc",0,1);
................................................................................
    zFileGlob = z;
  }else{
    zFileGlob = find_option("files",0,1);
  }
  zNotFound = find_option("notfound", 0, 1);
  g.useLocalauth = find_option("localauth", 0, 0)!=0;
  g.sslNotAvailable = find_option("nossl", 0, 0)!=0;
  zAltBase = find_option("baseurl", 0, 1);
  if( zAltBase ) set_base_url(zAltBase);
  if( find_option("https",0,0)!=0 ) cgi_replace_parameter("HTTPS","on");
  zHost = find_option("host", 0, 1);
  if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost);
  g.cgiOutput = 1;


  if( g.argc!=2 && g.argc!=3 && g.argc!=6 ){
    fossil_fatal("no repository specified");
  }
  g.fullHttpReply = 1;
  if( g.argc==6 ){
    g.httpIn = fossil_fopen(g.argv[3], "rb");
    g.httpOut = fossil_fopen(g.argv[4], "wb");
    zIpAddr = g.argv[5];
  }else{
    g.httpIn = stdin;
    g.httpOut = stdout;
    zIpAddr = 0;
  }
  find_server_repository(0);
  g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
  cgi_handle_http_request(zIpAddr);
  process_one_web_page(zNotFound, glob_create(zFileGlob));
}
................................................................................
  int iPort, mxPort;        /* Range of TCP ports allowed */
  const char *zPort;        /* Value of the --port option */
  const char *zBrowser;     /* Name of web browser program */
  char *zBrowserCmd = 0;    /* Command to launch the web browser */
  int isUiCmd;              /* True if command is "ui", not "server' */
  const char *zNotFound;    /* The --notfound option or NULL */
  int flags = 0;            /* Server flags */
  const char *zAltBase;     /* Argument to the --baseurl option */
  const char *zFileGlob;    /* Static content must match this */

#if defined(_WIN32)
  const char *zStopperFile;    /* Name of file used to terminate server */
  zStopperFile = find_option("stopper", 0, 1);
#endif

................................................................................
  g.thTrace = find_option("th-trace", 0, 0)!=0;
  g.useLocalauth = find_option("localauth", 0, 0)!=0;
  if( g.thTrace ){
    blob_zero(&g.thLog);
  }
  zPort = find_option("port", "P", 1);
  zNotFound = find_option("notfound", 0, 1);
  zAltBase = find_option("baseurl", 0, 1);
  if( zAltBase ){
    set_base_url(zAltBase);
  }
  if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?");
  isUiCmd = g.argv[1][0]=='u';
  if( isUiCmd ){
    flags |= HTTP_SERVER_LOCALHOST;
    g.useLocalauth = 1;
  }
  find_server_repository(isUiCmd && zNotFound==0);






>







 







|
>







 







|


>
>
>
>

|





|
|

>
>
|







 







>







 







>
>
>
>













>
>







<







 







<







 







|
|




>
>









<
<







 







<







 







|
<
|
<







133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
...
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
....
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
....
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
....
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388

1389
1390
1391
1392
1393
1394
1395
....
1752
1753
1754
1755
1756
1757
1758

1759
1760
1761
1762
1763
1764
1765
....
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792


1793
1794
1795
1796
1797
1798
1799
....
1899
1900
1901
1902
1903
1904
1905

1906
1907
1908
1909
1910
1911
1912
....
1914
1915
1916
1917
1918
1919
1920
1921

1922

1923
1924
1925
1926
1927
1928
1929
  int fHttpTrace;         /* Trace outbound HTTP requests */
  int fSystemTrace;       /* Trace calls to fossil_system(), --systemtrace */
  int fSshTrace;          /* Trace the SSH setup traffic */
  int fNoSync;            /* Do not do an autosync ever.  --nosync */
  char *zPath;            /* Name of webpage being served */
  char *zExtra;           /* Extra path information past the webpage name */
  char *zBaseURL;         /* Full text of the URL being served */
  const char *zAltBase;   /* Alternative URL root.  --baseurl */
  char *zTop;             /* Parent directory of zPath */
  const char *zContentType;  /* The content type of the input HTTP request */
  int iErrPriority;       /* Priority of current error message */
  char *zErrMsg;          /* Text of an error message */
  int sslNotAvailable;    /* SSL is not available.  Do not redirect to https: */
  Blob cgiIn;             /* Input to an xfer www method */
  int cgiOutput;          /* Write error and status messages to CGI */
................................................................................
  int urlPort;            /* TCP port number for http: or https: */
  int urlDfltPort;        /* The default port for the given protocol */
  char *urlPath;          /* Pathname for http: */
  char *urlUser;          /* User id for http: */
  char *urlPasswd;        /* Password for http: */
  char *urlCanonical;     /* Canonical representation of the URL */
  char *urlProxyAuth;     /* Proxy-Authorizer: string */
  char *urlFossil;        /* The fossil query parameter on ssh: */
  char *urlShell;         /* The shell query parameter on ssh: */
  int dontKeepUrl;        /* Do not persist the URL */

  const char *zLogin;     /* Login name.  "" if not logged in. */
  const char *zSSLIdentity;  /* Value of --ssl-identity option, filename of SSL client identity */
  int useLocalauth;       /* No login required if from 127.0.0.1 */
  int noPswd;             /* Logged in without password (on 127.0.0.1) */
  int userUid;            /* Integer user id */
................................................................................

/*
** Set the g.zBaseURL value to the full URL for the toplevel of
** the fossil tree.  Set g.zTop to g.zBaseURL without the
** leading "http://" and the host and port.
**
** The g.zBaseURL is normally set based on HTTP_HOST and SCRIPT_NAME
** environment variables.  However, if g.zAltBase is not NULL then it
** is the argument to the --baseurl option command-line option and
** g.zBaseURL and g.zTop is set from that instead.
**
** If g.zAltBase is set, then zRepoName may be a repository name (with a
** leading slash ** but without the .fossil) with is concatenated to the
** root.
*/
static void set_base_url(const char* zRepoName){
  int i;
  const char *zHost;
  const char *zMode;
  const char *zCur;

  fossil_free(g.zBaseURL);
  if( g.zAltBase ){
    int i, n, c;
    if (!zRepoName) zRepoName = "";
    if (zRepoName[0] == '/') zRepoName++;
    g.zTop = g.zBaseURL = mprintf("%s%s", g.zAltBase, zRepoName);
    if( memcmp(g.zTop, "http://", 7)!=0 && memcmp(g.zTop,"https://",8)!=0 ){
      fossil_fatal("argument to --baseurl should be 'http://host/path'"
                   " or 'https://host/path'");
    }
    for(i=n=0; (c = g.zTop[i])!=0; i++){
      if( c=='/' ){
        n++;
................................................................................
  ** repository based on the first element of PATH_INFO and open it.
  */
  zPathInfo = PD("PATH_INFO","");
  if( !g.repositoryOpen ){
    char *zRepo, *zToFree;
    const char *zOldScript = PD("SCRIPT_NAME", "");
    char *zNewScript;
    char *zRepoName;
    int j, k;
    i64 szFile;

    i = zPathInfo[0]!=0;
    while( 1 ){
      while( zPathInfo[i] && zPathInfo[i]!='/' ){ i++; }
      zRepo = zToFree = mprintf("%s%.*s.fossil",g.zRepositoryName,i,zPathInfo);
................................................................................
          cgi_set_status(404, "not found");
          cgi_reply();
        }
        return;
      }
      break;
    }
    /* Rebuild the base URL to add the repository name to the end. */
    zRepoName = mprintf("%.*s", i, zPathInfo);
    set_base_url(zRepoName);
    fossil_free(zRepoName);
    zNewScript = mprintf("%s%.*s", zOldScript, i, zPathInfo);
    cgi_replace_parameter("PATH_INFO", &zPathInfo[i+1]);
    zPathInfo += i;
    cgi_replace_parameter("SCRIPT_NAME", zNewScript);
    db_open_repository(zRepo);
    if( g.fHttpTrace ){
      fprintf(stderr,
          "# repository: [%s]\n"
          "# new PATH_INFO = [%s]\n"
          "# new SCRIPT_NAME = [%s]\n",
          zRepo, zPathInfo, zNewScript);
    }
  }
  else
    set_base_url(0);

  /* Find the page that the user has requested, construct and deliver that
  ** page.
  */
  if( g.zContentType && memcmp(g.zContentType, "application/x-fossil", 20)==0 ){
    zPathInfo = "/xfer";
  }

  if( zPathInfo==0 || zPathInfo[0]==0
      || (zPathInfo[0]=='/' && zPathInfo[1]==0) ){
#ifdef FOSSIL_ENABLE_JSON
    if(g.json.isJsonMode){
      json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,1);
      fossil_exit(0);
    }
................................................................................
**
** See also: cgi, server, winsrv
*/
void cmd_http(void){
  const char *zIpAddr;
  const char *zNotFound;
  const char *zHost;

  const char *zFileGlob;

  /* The winhttp module passes the --files option as --files-urlenc with
  ** the argument being URL encoded, to avoid wildcard expansion in the 
  ** shell.  This option is for internal use and is undocumented.
  */
  zFileGlob = find_option("files-urlenc",0,1);
................................................................................
    zFileGlob = z;
  }else{
    zFileGlob = find_option("files",0,1);
  }
  zNotFound = find_option("notfound", 0, 1);
  g.useLocalauth = find_option("localauth", 0, 0)!=0;
  g.sslNotAvailable = find_option("nossl", 0, 0)!=0;
  g.zAltBase = find_option("baseurl", 0, 1);
  set_base_url(0);
  if( find_option("https",0,0)!=0 ) cgi_replace_parameter("HTTPS","on");
  zHost = find_option("host", 0, 1);
  if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost);
  g.cgiOutput = 1;
  g.httpIn = stdin;
  g.httpOut = stdout;
  if( g.argc!=2 && g.argc!=3 && g.argc!=6 ){
    fossil_fatal("no repository specified");
  }
  g.fullHttpReply = 1;
  if( g.argc==6 ){
    g.httpIn = fossil_fopen(g.argv[3], "rb");
    g.httpOut = fossil_fopen(g.argv[4], "wb");
    zIpAddr = g.argv[5];
  }else{


    zIpAddr = 0;
  }
  find_server_repository(0);
  g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
  cgi_handle_http_request(zIpAddr);
  process_one_web_page(zNotFound, glob_create(zFileGlob));
}
................................................................................
  int iPort, mxPort;        /* Range of TCP ports allowed */
  const char *zPort;        /* Value of the --port option */
  const char *zBrowser;     /* Name of web browser program */
  char *zBrowserCmd = 0;    /* Command to launch the web browser */
  int isUiCmd;              /* True if command is "ui", not "server' */
  const char *zNotFound;    /* The --notfound option or NULL */
  int flags = 0;            /* Server flags */

  const char *zFileGlob;    /* Static content must match this */

#if defined(_WIN32)
  const char *zStopperFile;    /* Name of file used to terminate server */
  zStopperFile = find_option("stopper", 0, 1);
#endif

................................................................................
  g.thTrace = find_option("th-trace", 0, 0)!=0;
  g.useLocalauth = find_option("localauth", 0, 0)!=0;
  if( g.thTrace ){
    blob_zero(&g.thLog);
  }
  zPort = find_option("port", "P", 1);
  zNotFound = find_option("notfound", 0, 1);
  g.zAltBase = find_option("baseurl", 0, 1);

  set_base_url(0);

  if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?");
  isUiCmd = g.argv[1][0]=='u';
  if( isUiCmd ){
    flags |= HTTP_SERVER_LOCALHOST;
    g.useLocalauth = 1;
  }
  find_server_repository(isUiCmd && zNotFound==0);

Changes to src/rss.c.

20
21
22
23
24
25
26













27

28
29
30
31
32
33




34

35
36
37
38
39
40
41
..
60
61
62
63
64
65
66

67
68
69
70
71
72
73
..
74
75
76
77
78
79
80




































81
82
83
84
85
86
87
#include "config.h"
#include <time.h>
#include "rss.h"
#include <assert.h>

/*
** WEBPAGE: timeline.rss













*/

void page_timeline_rss(void){
  Stmt q;
  int nLine=0;
  char *zPubDate, *zProjectName, *zProjectDescr, *zFreeProjectName=0;
  Blob bSQL;
  const char *zType = PD("y","all"); /* Type of events.  All if NULL */




  int nLimit = atoi(PD("n","20"));

  const char zSQL1[] =
    @ SELECT
    @   blob.rid,
    @   uuid,
    @   event.mtime,
    @   coalesce(ecomment,comment),
    @   coalesce(euser,user),
................................................................................
    blob_appendf(&bSQL, " AND event.type=%Q", zType);
  }else{
    if( !g.perm.Read ){
      if( g.perm.RdTkt && g.perm.RdWiki ){
        blob_append(&bSQL, " AND event.type!='ci'", -1);
      }else if( g.perm.RdTkt ){
        blob_append(&bSQL, " AND event.type=='t'", -1);

      }else{
        blob_append(&bSQL, " AND event.type=='w'", -1);
      }
    }else if( !g.perm.RdWiki ){
      if( g.perm.RdTkt ){
        blob_append(&bSQL, " AND event.type!='w'", -1);
      }else{
................................................................................
        blob_append(&bSQL, " AND event.type=='ci'", -1);
      }
    }else if( !g.perm.RdTkt ){
      assert( !g.perm.RdTkt &&& g.perm.Read && g.perm.RdWiki );
      blob_append(&bSQL, " AND event.type!='t'", -1);
    }
  }





































  blob_append( &bSQL, " ORDER BY event.mtime DESC", -1 );

  cgi_set_content_type("application/rss+xml");

  zProjectName = db_get("project-name", 0);
  if( zProjectName==0 ){






>
>
>
>
>
>
>
>
>
>
>
>
>

>






>
>
>
>

>







 







>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
..
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
..
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include "config.h"
#include <time.h>
#include "rss.h"
#include <assert.h>

/*
** WEBPAGE: timeline.rss
** URL:  /timeline.rss/y=TYPE&n=LIMIT&tkt=UUID&tag=TAG&wiki=NAME&name=FILENAME
**
** Produce an RSS feed of the timeline.
**
** TYPE may be: all, ci (show checkins only), t (show tickets only),
** w (show wiki only). LIMIT is the number of items to show.
**
** tkt=UUID filters for only those events for the specified ticket. tag=TAG
** filters for a tag, and wiki=NAME for a wiki page. Only one may be used.
**
** In addition, name=FILENAME filters for a specific file. This may be
** combined with one of the other filters (useful for looking at a specific
** branch).
*/

void page_timeline_rss(void){
  Stmt q;
  int nLine=0;
  char *zPubDate, *zProjectName, *zProjectDescr, *zFreeProjectName=0;
  Blob bSQL;
  const char *zType = PD("y","all"); /* Type of events.  All if NULL */
  const char *zTicketUuid = PD("tkt",NULL);
  const char *zTag = PD("tag",NULL);
  const char *zFilename = PD("name",NULL);
  const char *zWiki = PD("wiki",NULL);
  int nLimit = atoi(PD("n","20"));
  int nTagId;
  const char zSQL1[] =
    @ SELECT
    @   blob.rid,
    @   uuid,
    @   event.mtime,
    @   coalesce(ecomment,comment),
    @   coalesce(euser,user),
................................................................................
    blob_appendf(&bSQL, " AND event.type=%Q", zType);
  }else{
    if( !g.perm.Read ){
      if( g.perm.RdTkt && g.perm.RdWiki ){
        blob_append(&bSQL, " AND event.type!='ci'", -1);
      }else if( g.perm.RdTkt ){
        blob_append(&bSQL, " AND event.type=='t'", -1);
        
      }else{
        blob_append(&bSQL, " AND event.type=='w'", -1);
      }
    }else if( !g.perm.RdWiki ){
      if( g.perm.RdTkt ){
        blob_append(&bSQL, " AND event.type!='w'", -1);
      }else{
................................................................................
        blob_append(&bSQL, " AND event.type=='ci'", -1);
      }
    }else if( !g.perm.RdTkt ){
      assert( !g.perm.RdTkt &&& g.perm.Read && g.perm.RdWiki );
      blob_append(&bSQL, " AND event.type!='t'", -1);
    }
  }

  if( zTicketUuid ){
    nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",
      zTicketUuid);
    if ( nTagId==0 ){
      nTagId = -1;
    }
  }else if( zTag ){
    nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'sym-%q*'",
      zTag);
    if ( nTagId==0 ){
      nTagId = -1;
    }
  }else if( zWiki ){
    nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'wiki-%q*'",
      zWiki);
    if ( nTagId==0 ){
      nTagId = -1;
    }
  }else{
    nTagId = 0;
  }

  if( nTagId==-1 ){
    blob_appendf(&bSQL, " AND 0");
  }else if( nTagId!=0 ){
    blob_appendf(&bSQL, " AND (EXISTS(SELECT 1 FROM tagxref"
      " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid))", nTagId);
  }

  if( zFilename ){
    blob_appendf(&bSQL,
      " AND (SELECT mlink.fnid FROM mlink WHERE event.objid=mlink.mid) IN (SELECT fnid FROM filename WHERE name=%Q %s)",
        zFilename, filename_collation()
    );
  }

  blob_append( &bSQL, " ORDER BY event.mtime DESC", -1 );

  cgi_set_content_type("application/rss+xml");

  zProjectName = db_get("project-name", 0);
  if( zProjectName==0 ){

Changes to src/url.c.

61
62
63
64
65
66
67

68
69
70
71
72
73
74
75
76
77
78
79

80
81
82
83
84
85
86
...
142
143
144
145
146
147
148
149







150
151
152
153
154
155
156
  if( strncmp(zUrl, "http://", 7)==0
   || strncmp(zUrl, "https://", 8)==0
   || strncmp(zUrl, "ssh://", 6)==0
  ){
    int iStart;
    char *zLogin;
    char *zExe;


    g.urlIsFile = 0;
    if( zUrl[4]=='s' ){
      g.urlIsHttps = 1;
      g.urlProtocol = "https";
      g.urlDfltPort = 443;
      iStart = 8;
    }else if( zUrl[0]=='s' ){
      g.urlIsSsh = 1;
      g.urlProtocol = "ssh";
      g.urlDfltPort = 22;
      g.urlFossil = "fossil";

      iStart = 6;
    }else{
      g.urlIsHttps = 0;
      g.urlProtocol = "http";
      g.urlDfltPort = 80;
      iStart = 7;
    }
................................................................................
      if( g.urlPath[i] ){
        g.urlPath[i] = 0;
        i++;
      }
      if( fossil_strcmp(zName,"fossil")==0 ){
        g.urlFossil = zValue;
        dehttpize(g.urlFossil);
        zExe = mprintf("?fossil=%T", g.urlFossil);







      }
    }

    dehttpize(g.urlPath);
    if( g.urlDfltPort==g.urlPort ){
      g.urlCanonical = mprintf(
        "%s://%s%T%T%s", 






>












>







 







|
>
>
>
>
>
>
>







61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
...
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
  if( strncmp(zUrl, "http://", 7)==0
   || strncmp(zUrl, "https://", 8)==0
   || strncmp(zUrl, "ssh://", 6)==0
  ){
    int iStart;
    char *zLogin;
    char *zExe;
    char cQuerySep = '?';

    g.urlIsFile = 0;
    if( zUrl[4]=='s' ){
      g.urlIsHttps = 1;
      g.urlProtocol = "https";
      g.urlDfltPort = 443;
      iStart = 8;
    }else if( zUrl[0]=='s' ){
      g.urlIsSsh = 1;
      g.urlProtocol = "ssh";
      g.urlDfltPort = 22;
      g.urlFossil = "fossil";
      g.urlShell = 0;
      iStart = 6;
    }else{
      g.urlIsHttps = 0;
      g.urlProtocol = "http";
      g.urlDfltPort = 80;
      iStart = 7;
    }
................................................................................
      if( g.urlPath[i] ){
        g.urlPath[i] = 0;
        i++;
      }
      if( fossil_strcmp(zName,"fossil")==0 ){
        g.urlFossil = zValue;
        dehttpize(g.urlFossil);
        zExe = mprintf("%cfossil=%T", cQuerySep, g.urlFossil);
        cQuerySep = '&';
      }
      if( fossil_strcmp(zName,"shell")==0 ){
        g.urlShell = zValue;
        dehttpize(g.urlShell);
        zExe = mprintf("%cshell=%T", cQuerySep, g.urlFossil);
        cQuerySep = '&';
      }
    }

    dehttpize(g.urlPath);
    if( g.urlDfltPort==g.urlPort ){
      g.urlCanonical = mprintf(
        "%s://%s%T%T%s", 

Changes to src/wikiformat.c.

822
823
824
825
826
827
828
829

830
831
832
833
834
835
836
....
1169
1170
1171
1172
1173
1174
1175

1176
1177
1178
1179
1180
1181
1182
    blob_appendf(pOut, "</%s>", aMarkup[p->iCode].zName);
  }else{
    blob_appendf(pOut, "<%s", aMarkup[p->iCode].zName);
    for(i=0; i<p->nAttr; i++){
      blob_appendf(pOut, " %s", aAttribute[p->aAttr[i].iACode].zName);
      if( p->aAttr[i].zValue ){
        const char *zVal = p->aAttr[i].zValue;
        if( p->aAttr[i].iACode==ATTR_SRC && zVal[0]=='/' ){

          blob_appendf(pOut, "=\"%s%s\"", g.zTop, zVal);
        }else{
          blob_appendf(pOut, "=\"%s\"", zVal);
        }
      }
    }
    if (p->iType & MUTYPE_SINGLE){
................................................................................
  const char *z;

  assert( nClose>=20 );
  if( strncmp(zTarget, "http:", 5)==0
   || strncmp(zTarget, "https:", 6)==0
   || strncmp(zTarget, "ftp:", 4)==0
   || strncmp(zTarget, "mailto:", 7)==0

  ){
    blob_appendf(p->pOut, "<a href=\"%s\">", zTarget);
  }else if( zTarget[0]=='/' ){
    blob_appendf(p->pOut, "<a href=\"%s%h\">", g.zTop, zTarget);
  }else if( zTarget[0]=='.'
         && (zTarget[1]=='/' || (zTarget[1]=='.' && zTarget[2]=='/'))
         && (p->state & WIKI_LINKSONLY)==0 ){






|
>







 







>







822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
....
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
    blob_appendf(pOut, "</%s>", aMarkup[p->iCode].zName);
  }else{
    blob_appendf(pOut, "<%s", aMarkup[p->iCode].zName);
    for(i=0; i<p->nAttr; i++){
      blob_appendf(pOut, " %s", aAttribute[p->aAttr[i].iACode].zName);
      if( p->aAttr[i].zValue ){
        const char *zVal = p->aAttr[i].zValue;
        if( p->aAttr[i].iACode==ATTR_SRC && zVal[0]=='/'
            && (zVal[0]==0 || zVal[1]!='/') ){
          blob_appendf(pOut, "=\"%s%s\"", g.zTop, zVal);
        }else{
          blob_appendf(pOut, "=\"%s\"", zVal);
        }
      }
    }
    if (p->iType & MUTYPE_SINGLE){
................................................................................
  const char *z;

  assert( nClose>=20 );
  if( strncmp(zTarget, "http:", 5)==0
   || strncmp(zTarget, "https:", 6)==0
   || strncmp(zTarget, "ftp:", 4)==0
   || strncmp(zTarget, "mailto:", 7)==0
   || strncmp(zTarget, "//", 2)==0
  ){
    blob_appendf(p->pOut, "<a href=\"%s\">", zTarget);
  }else if( zTarget[0]=='/' ){
    blob_appendf(p->pOut, "<a href=\"%s%h\">", g.zTop, zTarget);
  }else if( zTarget[0]=='.'
         && (zTarget[1]=='/' || (zTarget[1]=='.' && zTarget[2]=='/'))
         && (p->state & WIKI_LINKSONLY)==0 ){

Changes to src/xfer.c.

18
19
20
21
22
23
24






25
26
27
28
29
30
31
....
1478
1479
1480
1481
1482
1483
1484
1485

1486
1487
1488
1489
1490
1491
1492
** This file contains code to implement the file transfer protocol.
*/
#include "config.h"
#include "xfer.h"

#include <time.h>







/*
** This structure holds information about the current state of either
** a client or a server that is participating in xfer.
*/
typedef struct Xfer Xfer;
struct Xfer {
  Blob *pIn;          /* Input text from the other side */
................................................................................
    xfer.nDeltaSent = 0;
    xfer.nGimmeSent = 0;
    xfer.nIGotSent = 0;
    if( syncFlags & SYNC_VERBOSE ){
      fossil_print("waiting for server...");
    }
    fflush(stdout);
    if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0) ){

      nErr++;
      break;
    }
    lastPctDone = -1;
    blob_reset(&send);
    rArrivalTime = db_double(0.0, "SELECT julianday('now')");







>
>
>
>
>
>







 







|
>







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
....
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
** This file contains code to implement the file transfer protocol.
*/
#include "config.h"
#include "xfer.h"

#include <time.h>

/*
** Maximum number of HTTP redirects that any http_exchange() call will
** follow before throwing a fatal error. Most browsers use a limit of 20.
*/
#define MAX_REDIRECTS 20

/*
** This structure holds information about the current state of either
** a client or a server that is participating in xfer.
*/
typedef struct Xfer Xfer;
struct Xfer {
  Blob *pIn;          /* Input text from the other side */
................................................................................
    xfer.nDeltaSent = 0;
    xfer.nGimmeSent = 0;
    xfer.nIGotSent = 0;
    if( syncFlags & SYNC_VERBOSE ){
      fossil_print("waiting for server...");
    }
    fflush(stdout);
    if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0,
        MAX_REDIRECTS) ){
      nErr++;
      break;
    }
    lastPctDone = -1;
    blob_reset(&send);
    rArrivalTime = db_double(0.0, "SELECT julianday('now')");

Changes to www/build.wiki.

52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
..
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
These link will build a ZIP archive or a gzip-compressed tarball of the 
complete source code and download it to your browser.
</ol>

<h2>2.0 Compiling</h2>

<ol>
<li value="6">
<p>Unpack the ZIP or tarball you downloaded then
<b>cd</b> into the directory created.</p></li>

<li><i>(Optional, unix only)</i>
Run <b>./configure</b> to construct a makefile.

<ol type="a">
................................................................................
"<b>nmake /f Makefile.msc</b>".
</ol>
</ol>

<h2>3.0 Installing</h2>

<ol>
<li value="9">
<p>The finished binary is named "fossil" (or "fossil.exe" on windows).  
Put this binary in a 
directory that is somewhere on your PATH environment variable.
It does not matter where.</p>

<li>
<p><b>(Optional:)</b>






|







 







|







52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
..
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
These link will build a ZIP archive or a gzip-compressed tarball of the 
complete source code and download it to your browser.
</ol>

<h2>2.0 Compiling</h2>

<ol>
<li value="5">
<p>Unpack the ZIP or tarball you downloaded then
<b>cd</b> into the directory created.</p></li>

<li><i>(Optional, unix only)</i>
Run <b>./configure</b> to construct a makefile.

<ol type="a">
................................................................................
"<b>nmake /f Makefile.msc</b>".
</ol>
</ol>

<h2>3.0 Installing</h2>

<ol>
<li value="8">
<p>The finished binary is named "fossil" (or "fossil.exe" on windows).  
Put this binary in a 
directory that is somewhere on your PATH environment variable.
It does not matter where.</p>

<li>
<p><b>(Optional:)</b>