Fossil

Check-in [45065c5c]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix typos.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | spelling
Files: files | file ages | folders
SHA1: 45065c5c282cda9916c4c224f4e962a1fc791252
User & Date: dmitry 2012-11-04 12:59:14
Context
2012-11-04
17:41
Merge the "spelling" branch into trunk, fixing a huge number of typos, mostly in comments, but occasionally in error messages or help screens. check-in: db0c5127 user: drh tags: trunk
12:59
Fix typos. Closed-Leaf check-in: 45065c5c user: dmitry tags: spelling
11:58
Improvements to the fix for [0ff64b0a5fc88e7e]: (1) Better error message and (2) allow the partial commit of the renamed file as long as its destination files is also part of the partial commit. check-in: c0fe455c user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/add.c.

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
...
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
...
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
     ".fos",
     ".fos-journal",
     ".fos-wal",
     ".fos-shm",
  };

  /* Names of auxiliary files generated by SQLite when the "manifest"
  ** properity is enabled
  */
  static const char *const azManifest[] = {
     "manifest",
     "manifest.uuid",
  };

  /* Cached setting "manifest" */
................................................................................
  vid = db_lget_int("checkout",0);
  if( vid==0 ){
    fossil_panic("no checkout to add to");
  }
  db_begin_transaction();

  /* step 1:  
  ** Populate the temp table "sfile" with the names of all unmanged
  ** files currently in the check-out, except for files that match the
  ** --ignore or ignore-glob patterns and dot-files.  Then add all of
  ** the files in the sfile temp table to the set of managed files.
  */
  db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
  n = strlen(g.zLocalRoot);
  blob_init(&path, g.zLocalRoot, n-1);
................................................................................
        db_multi_exec("UPDATE vfile SET deleted=1 WHERE pathname=%Q", zFile);
      }
      fossil_print("DELETED  %s\n", zFile);
      nDelete++;
    }
  }
  db_finalize(&q);
  /* show cmmand summary */
  fossil_print("added %d files, deleted %d files\n", nAdd, nDelete);

  db_end_transaction(isTest);
}


/*







|







 







|







 







|







51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
...
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
...
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
     ".fos",
     ".fos-journal",
     ".fos-wal",
     ".fos-shm",
  };

  /* Names of auxiliary files generated by SQLite when the "manifest"
  ** property is enabled
  */
  static const char *const azManifest[] = {
     "manifest",
     "manifest.uuid",
  };

  /* Cached setting "manifest" */
................................................................................
  vid = db_lget_int("checkout",0);
  if( vid==0 ){
    fossil_panic("no checkout to add to");
  }
  db_begin_transaction();

  /* step 1:  
  ** Populate the temp table "sfile" with the names of all unmanaged
  ** files currently in the check-out, except for files that match the
  ** --ignore or ignore-glob patterns and dot-files.  Then add all of
  ** the files in the sfile temp table to the set of managed files.
  */
  db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
  n = strlen(g.zLocalRoot);
  blob_init(&path, g.zLocalRoot, n-1);
................................................................................
        db_multi_exec("UPDATE vfile SET deleted=1 WHERE pathname=%Q", zFile);
      }
      fossil_print("DELETED  %s\n", zFile);
      nDelete++;
    }
  }
  db_finalize(&q);
  /* show command summary */
  fossil_print("added %d files, deleted %d files\n", nAdd, nDelete);

  db_end_transaction(isTest);
}


/*

Changes to src/blob.c.

669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
  }
}
void blob_vappendf(Blob *pBlob, const char *zFormat, va_list ap){
  if( pBlob ) vxprintf(pBlob, zFormat, ap);
}

/*
** Initalize a blob to the data on an input channel.  Return
** the number of bytes read into the blob.  Any prior content
** of the blob is discarded, not freed.
*/
int blob_read_from_channel(Blob *pBlob, FILE *in, int nToRead){
  size_t n;
  blob_zero(pBlob);
  if( nToRead<0 ){







|







669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
  }
}
void blob_vappendf(Blob *pBlob, const char *zFormat, va_list ap){
  if( pBlob ) vxprintf(pBlob, zFormat, ap);
}

/*
** Initialize a blob to the data on an input channel.  Return
** the number of bytes read into the blob.  Any prior content
** of the blob is discarded, not freed.
*/
int blob_read_from_channel(Blob *pBlob, FILE *in, int nToRead){
  size_t n;
  blob_zero(pBlob);
  if( nToRead<0 ){

Changes to src/browse.c.

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
** This file contains code to implement the file browser web interface.
*/
#include "config.h"
#include "browse.h"
#include <assert.h>

/*
** This is the implemention of the "pathelement(X,N)" SQL function.
**
** If X is a unix-like pathname (with "/" separators) and N is an
** integer, then skip the initial N characters of X and return the
** name of the path component that begins on the N+1th character
** (numbered from 0).  If the path component is a directory (if
** it is followed by other path components) then prepend "/".
**







|







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
** This file contains code to implement the file browser web interface.
*/
#include "config.h"
#include "browse.h"
#include <assert.h>

/*
** This is the implementation of the "pathelement(X,N)" SQL function.
**
** If X is a unix-like pathname (with "/" separators) and N is an
** integer, then skip the initial N characters of X and return the
** name of the path component that begins on the N+1th character
** (numbered from 0).  If the path component is a directory (if
** it is followed by other path components) then prepend "/".
**

Changes to src/captcha.c.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains code to a simple text-based CAPTCHA.  Though eaily
** defeated by a sophisticated attacker, this CAPTCHA does at least make
** scripting attacks more difficult.
*/
#include <assert.h>
#include "config.h"
#include "captcha.h"








|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains code to a simple text-based CAPTCHA.  Though easily
** defeated by a sophisticated attacker, this CAPTCHA does at least make
** scripting attacks more difficult.
*/
#include <assert.h>
#include "config.h"
#include "captcha.h"

Changes to src/cgi.c.

963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
  for(i=0; zOut[i]; i++){}
  while( i>0 && fossil_isspace(zOut[i-1]) ) zOut[--i] = 0;
  return zOut;
}

/*
** Return the name of the i-th CGI parameter.  Return NULL if there
** are fewer than i registered CGI parmaeters.
*/
const char *cgi_parameter_name(int i){
  if( i>=0 && i<nUsedQP ){
    return aParamQP[i].zName;
  }else{
    return 0;
  }







|







963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
  for(i=0; zOut[i]; i++){}
  while( i>0 && fossil_isspace(zOut[i-1]) ) zOut[--i] = 0;
  return zOut;
}

/*
** Return the name of the i-th CGI parameter.  Return NULL if there
** are fewer than i registered CGI parameters.
*/
const char *cgi_parameter_name(int i){
  if( i>=0 && i<nUsedQP ){
    return aParamQP[i].zName;
  }else{
    return 0;
  }

Changes to src/checkin.c.

715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
....
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
  Blob *pComment,             /* Check-in comment text */
  int vid,                    /* blob-id of the parent manifest */
  int verifyDate,             /* Verify that child is younger */
  Blob *pCksum,               /* Repository checksum.  May be 0 */
  const char *zDateOvrd,      /* Date override.  If 0 then use 'now' */
  const char *zUserOvrd,      /* User override.  If 0 then use g.zLogin */
  const char *zBranch,        /* Branch name.  May be 0 */
  const char *zColor,         /* One-time gackground color.  May be 0 */
  const char *zBrClr,         /* Persistent branch color.  May be 0 */
  const char **azTag,         /* Tags to apply to this check-in */
  int *pnFBcard               /* Number of generated B- and F-cards */
){
  char *zDate;                /* Date of the check-in */
  char *zParentUuid;          /* UUID of parent check-in */
  Blob filename;              /* A single filename */
................................................................................
    db_multi_exec("REPLACE INTO vvar VALUES('ci-comment',%B)", &comment);
    db_end_transaction(0);
    db_begin_transaction();
  }

  /* Step 1: Insert records for all modified files into the blob
  ** table. If there were arguments passed to this command, only
  ** the identified fils are inserted (if they have been modified).
  */
  db_prepare(&q,
    "SELECT id, %Q || pathname, mrid, %s, chnged, %s FROM vfile "
    "WHERE chnged==1 AND NOT deleted AND is_selected(id)",
    g.zLocalRoot, glob_expr("pathname", db_get("crnl-glob","")),
    glob_expr("pathname", db_get("binary-glob",""))
  );







|







 







|







715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
....
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
  Blob *pComment,             /* Check-in comment text */
  int vid,                    /* blob-id of the parent manifest */
  int verifyDate,             /* Verify that child is younger */
  Blob *pCksum,               /* Repository checksum.  May be 0 */
  const char *zDateOvrd,      /* Date override.  If 0 then use 'now' */
  const char *zUserOvrd,      /* User override.  If 0 then use g.zLogin */
  const char *zBranch,        /* Branch name.  May be 0 */
  const char *zColor,         /* One-time background color.  May be 0 */
  const char *zBrClr,         /* Persistent branch color.  May be 0 */
  const char **azTag,         /* Tags to apply to this check-in */
  int *pnFBcard               /* Number of generated B- and F-cards */
){
  char *zDate;                /* Date of the check-in */
  char *zParentUuid;          /* UUID of parent check-in */
  Blob filename;              /* A single filename */
................................................................................
    db_multi_exec("REPLACE INTO vvar VALUES('ci-comment',%B)", &comment);
    db_end_transaction(0);
    db_begin_transaction();
  }

  /* Step 1: Insert records for all modified files into the blob
  ** table. If there were arguments passed to this command, only
  ** the identified files are inserted (if they have been modified).
  */
  db_prepare(&q,
    "SELECT id, %Q || pathname, mrid, %s, chnged, %s FROM vfile "
    "WHERE chnged==1 AND NOT deleted AND is_selected(id)",
    g.zLocalRoot, glob_expr("pathname", db_get("crnl-glob","")),
    glob_expr("pathname", db_get("binary-glob",""))
  );

Changes to src/clone.c.

68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/*
** Delete all private content from a repository.
*/
void delete_private_content(void){
  fix_private_blob_dependencies(1);
  db_multi_exec(
    "DELETE FROM blob WHERE rid IN private;"
    "DELETE FROM delta wHERE rid IN private;"
    "DELETE FROM private;"
    "DROP TABLE IF EXISTS modreq;"
  );
}


/*







|







68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/*
** Delete all private content from a repository.
*/
void delete_private_content(void){
  fix_private_blob_dependencies(1);
  db_multi_exec(
    "DELETE FROM blob WHERE rid IN private;"
    "DELETE FROM delta WHERE rid IN private;"
    "DELETE FROM private;"
    "DROP TABLE IF EXISTS modreq;"
  );
}


/*

Changes to src/configure.c.

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
..
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
...
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
...
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
...
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
...
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains code used to manage repository configurations.
**
** By "responsitory configure" we mean the local state of a repository
** distinct from the versioned files.
*/
#include "config.h"
#include "configure.h"
#include <assert.h>

#if INTERFACE
................................................................................
  const char *zName;   /* Name of the configuration set */
  int groupMask;       /* Mask for that configuration set */
  const char *zHelp;   /* What it does */
} aGroupName[] = {
  { "/email",        CONFIGSET_ADDR,  "Concealed email addresses in tickets" },
  { "/project",      CONFIGSET_PROJ,  "Project name and description"         },
  { "/skin",         CONFIGSET_SKIN | CONFIGSET_CSS,
                                      "Web interface apparance settings"     },
  { "/css",          CONFIGSET_CSS,   "Style sheet"                          },
  { "/shun",         CONFIGSET_SHUN,  "List of shunned artifacts"            },
  { "/ticket",       CONFIGSET_TKT,   "Ticket setup",                        },
  { "/user",         CONFIGSET_USER,  "Users and privilege settings"         },
  { "/xfer",         CONFIGSET_XFER,  "Transfer setup",                      },
  { "/all",          CONFIGSET_ALL,   "All of the above"                     },
};
................................................................................
  }
  return 0;
}

/*
** Return a pointer to a string that contains the RHS of an IN operator
** that will select CONFIG table names that are part of the configuration
** that matchines iMatch.
*/
const char *configure_inop_rhs(int iMask){
  Blob x;
  int i;
  const char *zSep = "";

  blob_zero(&x);
................................................................................
){
  int m = sqlite3_value_int(argv[0]);
  configHasBeenReset |= m;
}

/*
** Create the temporary _xfer_reportfmt and _xfer_user tables that are
** necessary in order to evalute the SQL text generated by the
** configure_render_special_name() routine.
**
** If replaceFlag is true, then the setup is such that the content in
** the SQL text will completely replace the current repository configuration.
** If replaceFlag is false, then the SQL text will be merged with the
** existing configuration.  When merging, existing values take priority
** over SQL text values.
................................................................................
**    /user       $MTIME $LOGIN pw $VALUE cap $VALUE info $VALUE photo $VALUE
**    /shun       $MTIME $UUID scom $VALUE
**    /reportfmt  $MTIME $TITLE owner $VALUE cols $VALUE sqlcode $VALUE
**    /concealed  $MTIME $HASH content $VALUE
**
** OLD FORMAT:
**
** The old format is retained for backwards compatiblity, but is deprecated.
** The cutover from old format to new was on 2011-04-25.  After sufficient
** time has passed, support for the old format will be removed.
**
** zName is either the NAME of an element of the CONFIG table, or else
** one of the special names "@shun", "@reportfmt", "@user", or "@concealed".
** If zName is a CONFIG table name, then CONTENT replaces (overwrites) the
** element in the CONFIG table.  For one of the @-labels, CONTENT is raw
................................................................................
** Usage: %fossil configuration METHOD ... ?OPTIONS?
**
** Where METHOD is one of: export import merge pull push reset.  All methods
** accept the -R or --repository option to specific a repository.
**
**    %fossil configuration export AREA FILENAME
**
**         Write to FILENAME exported configuraton information for AREA.
**         AREA can be one of:  all email project shun skin ticket user
**
**    %fossil configuration import FILENAME
**
**         Read a configuration from FILENAME, overwriting the current
**         configuration.
**







|







 







|







 







|







 







|







 







|







 







|







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
..
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
...
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
...
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
...
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
...
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains code used to manage repository configurations.
**
** By "repository configure" we mean the local state of a repository
** distinct from the versioned files.
*/
#include "config.h"
#include "configure.h"
#include <assert.h>

#if INTERFACE
................................................................................
  const char *zName;   /* Name of the configuration set */
  int groupMask;       /* Mask for that configuration set */
  const char *zHelp;   /* What it does */
} aGroupName[] = {
  { "/email",        CONFIGSET_ADDR,  "Concealed email addresses in tickets" },
  { "/project",      CONFIGSET_PROJ,  "Project name and description"         },
  { "/skin",         CONFIGSET_SKIN | CONFIGSET_CSS,
                                      "Web interface appearance settings"    },
  { "/css",          CONFIGSET_CSS,   "Style sheet"                          },
  { "/shun",         CONFIGSET_SHUN,  "List of shunned artifacts"            },
  { "/ticket",       CONFIGSET_TKT,   "Ticket setup",                        },
  { "/user",         CONFIGSET_USER,  "Users and privilege settings"         },
  { "/xfer",         CONFIGSET_XFER,  "Transfer setup",                      },
  { "/all",          CONFIGSET_ALL,   "All of the above"                     },
};
................................................................................
  }
  return 0;
}

/*
** Return a pointer to a string that contains the RHS of an IN operator
** that will select CONFIG table names that are part of the configuration
** that matches iMatch.
*/
const char *configure_inop_rhs(int iMask){
  Blob x;
  int i;
  const char *zSep = "";

  blob_zero(&x);
................................................................................
){
  int m = sqlite3_value_int(argv[0]);
  configHasBeenReset |= m;
}

/*
** Create the temporary _xfer_reportfmt and _xfer_user tables that are
** necessary in order to evaluate the SQL text generated by the
** configure_render_special_name() routine.
**
** If replaceFlag is true, then the setup is such that the content in
** the SQL text will completely replace the current repository configuration.
** If replaceFlag is false, then the SQL text will be merged with the
** existing configuration.  When merging, existing values take priority
** over SQL text values.
................................................................................
**    /user       $MTIME $LOGIN pw $VALUE cap $VALUE info $VALUE photo $VALUE
**    /shun       $MTIME $UUID scom $VALUE
**    /reportfmt  $MTIME $TITLE owner $VALUE cols $VALUE sqlcode $VALUE
**    /concealed  $MTIME $HASH content $VALUE
**
** OLD FORMAT:
**
** The old format is retained for backwards compatibility, but is deprecated.
** The cutover from old format to new was on 2011-04-25.  After sufficient
** time has passed, support for the old format will be removed.
**
** zName is either the NAME of an element of the CONFIG table, or else
** one of the special names "@shun", "@reportfmt", "@user", or "@concealed".
** If zName is a CONFIG table name, then CONTENT replaces (overwrites) the
** element in the CONFIG table.  For one of the @-labels, CONTENT is raw
................................................................................
** Usage: %fossil configuration METHOD ... ?OPTIONS?
**
** Where METHOD is one of: export import merge pull push reset.  All methods
** accept the -R or --repository option to specific a repository.
**
**    %fossil configuration export AREA FILENAME
**
**         Write to FILENAME exported configuration information for AREA.
**         AREA can be one of:  all email project shun skin ticket user
**
**    %fossil configuration import FILENAME
**
**         Read a configuration from FILENAME, overwriting the current
**         configuration.
**

Changes to src/content.c.

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
..
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
...
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
** Procedures store and retrieve records from the repository
*/
#include "config.h"
#include "content.h"
#include <assert.h>

/*
** The artifact retrival cache
*/
static struct {
  i64 szTotal;         /* Total size of all entries in the cache */
  int n;               /* Current number of eache entries */
  int nAlloc;          /* Number of slots allocated in a[] */
  int nextAge;         /* Age counter for implementing LRU */
  int skipCnt;         /* Used to limit entries expelled from cache */
  struct cacheLine {   /* One instance of this for each cache entry */
    int rid;                  /* Artifact id */
    int age;                  /* Age.  Newer is larger */
    Blob content;             /* Content of the artifact */
................................................................................
  /*
  ** The missing artifact cache.
  **
  ** Artifacts whose record ID are in missingCache cannot be retrieved
  ** either because they are phantoms or because they are a delta that
  ** depends on a phantom.  Artifacts whose content we are certain is
  ** available are in availableCache.  If an artifact is in neither cache
  ** then its current availablity is unknown.
  */
  Bag missing;         /* Cache of artifacts that are incomplete */
  Bag available;       /* Cache of artifacts that are complete */
} contentCache;

/*
** Remove the oldest element from the content cache
................................................................................
** and zUuid is zero then the correct zUuid is computed from pBlob.
**
** If the record already exists but is a phantom, the pBlob content
** is inserted and the phatom becomes a real record.
**
** The original content of pBlob is not disturbed.  The caller continues
** to be responsible for pBlob.  This routine does *not* take over
** responsiblity for freeing pBlob.
*/
int content_put_ex(
  Blob *pBlob,              /* Content to add to the repository */
  const char *zUuid,        /* SHA1 hash of reconstructed pBlob */
  int srcId,                /* pBlob is a delta from this entry */
  int nBlob,                /* pBlob is compressed. Original size is this */
  int isPrivate             /* The content should be marked private */







|



|







 







|







 







|







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
..
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
...
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
** Procedures store and retrieve records from the repository
*/
#include "config.h"
#include "content.h"
#include <assert.h>

/*
** The artifact retrieval cache
*/
static struct {
  i64 szTotal;         /* Total size of all entries in the cache */
  int n;               /* Current number of cache entries */
  int nAlloc;          /* Number of slots allocated in a[] */
  int nextAge;         /* Age counter for implementing LRU */
  int skipCnt;         /* Used to limit entries expelled from cache */
  struct cacheLine {   /* One instance of this for each cache entry */
    int rid;                  /* Artifact id */
    int age;                  /* Age.  Newer is larger */
    Blob content;             /* Content of the artifact */
................................................................................
  /*
  ** The missing artifact cache.
  **
  ** Artifacts whose record ID are in missingCache cannot be retrieved
  ** either because they are phantoms or because they are a delta that
  ** depends on a phantom.  Artifacts whose content we are certain is
  ** available are in availableCache.  If an artifact is in neither cache
  ** then its current availability is unknown.
  */
  Bag missing;         /* Cache of artifacts that are incomplete */
  Bag available;       /* Cache of artifacts that are complete */
} contentCache;

/*
** Remove the oldest element from the content cache
................................................................................
** and zUuid is zero then the correct zUuid is computed from pBlob.
**
** If the record already exists but is a phantom, the pBlob content
** is inserted and the phatom becomes a real record.
**
** The original content of pBlob is not disturbed.  The caller continues
** to be responsible for pBlob.  This routine does *not* take over
** responsibility for freeing pBlob.
*/
int content_put_ex(
  Blob *pBlob,              /* Content to add to the repository */
  const char *zUuid,        /* SHA1 hash of reconstructed pBlob */
  int srcId,                /* pBlob is a delta from this entry */
  int nBlob,                /* pBlob is compressed. Original size is this */
  int isPrivate             /* The content should be marked private */

Changes to src/db.c.

211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
...
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
...
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
....
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
....
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
....
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
  }
}

/*
** Install a commit hook.  Hooks are installed in sequence order.
** It is an error to install the same commit hook more than once.
**
** Each commit hook is called (in order of accending sequence) at
** each commit operation.  If any commit hook returns non-zero,
** the subsequence commit hooks are omitted and the transaction
** rolls back rather than commit.  It is the responsibility of the
** hooks themselves to issue any error messages.
*/
void db_commit_hook(int (*x)(void), int sequence){
  int i;
................................................................................
}
int db_bind_blob(Stmt *pStmt, const char *zParamName, Blob *pBlob){
  return sqlite3_bind_blob(pStmt->pStmt, paramIdx(pStmt, zParamName),
                          blob_buffer(pBlob), blob_size(pBlob), SQLITE_STATIC);
}

/* bind_str() treats a Blob object like a TEXT string and binds it
** to the SQL variable.  Constrast this to bind_blob() which treats
** the Blob object like an SQL BLOB.
*/
int db_bind_str(Stmt *pStmt, const char *zParamName, Blob *pBlob){
  return sqlite3_bind_text(pStmt->pStmt, paramIdx(pStmt, zParamName),
                          blob_buffer(pBlob), blob_size(pBlob), SQLITE_STATIC);
}

................................................................................
}
void db_column_blob(Stmt *pStmt, int N, Blob *pBlob){
  blob_append(pBlob, sqlite3_column_blob(pStmt->pStmt, N),
              sqlite3_column_bytes(pStmt->pStmt, N));
}

/*
** Initialize a blob to an ephermeral copy of the content of a
** column in the current row.  The data in the blob will become
** invalid when the statement is stepped or reset.
*/
void db_ephemeral_blob(Stmt *pStmt, int N, Blob *pBlob){
  blob_init(pBlob, sqlite3_column_blob(pStmt->pStmt, N),
              sqlite3_column_bytes(pStmt->pStmt, N));
}
................................................................................
){
  if( g.zLogin!=0 ){
    sqlite3_result_text(context, g.zLogin, -1, SQLITE_STATIC);
  }
}

/*
** Implement the cgi() SQL function.  cgi() takes a an argument which is
** a name of CGI query parameter. The value of that parameter is returned,
** if available. optional second argument will be returned if the first
** doesn't exist as a CGI parameter.
*/
static void db_sql_cgi(sqlite3_context *context, int argc, sqlite3_value **argv){
  const char* zP;
  if( argc!=1 && argc!=2 ) return;
  zP = P((const char*)sqlite3_value_text(argv[0]));
  if( zP ){
................................................................................
**                     Ex: kdiff3 "%baseline" "%original" "%merge" -o "%output"
**                     Ex: xxdiff "%original" "%baseline" "%merge" -M "%output"
**                     Ex: meld "%baseline" "%original" "%merge" "%output"
**
**    http-port        The TCP/IP port number to use by the "server"
**                     and "ui" commands.  Default: 8080
**
**    https-login      Send login creditials using HTTPS instead of HTTP
**                     even if the login page request came via HTTP.
**
**    ignore-glob      The VALUE is a comma or newline-separated list of GLOB
**     (versionable)   patterns specifying files that the "extra" command will
**                     ignore.  Example:  *.o,*.obj,*.exe
**
**    localauth        If enabled, require that HTTP connections from
................................................................................
    }
  }else{
    usage("?PROPERTY? ?VALUE?");
  }
}

/*
** The input in a a timespan measured in days.  Return a string which
** describes that timespan in units of seconds, minutes, hours, days,
** or years, depending on its duration.
*/
char *db_timespan_name(double rSpan){
  if( rSpan<0 ) rSpan = -rSpan;
  rSpan *= 24.0*3600.0;  /* Convert units to seconds */
  if( rSpan<120.0 ){







|







 







|







 







|







 







|

|







 







|







 







|







211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
...
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
...
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
....
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
....
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
....
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
  }
}

/*
** Install a commit hook.  Hooks are installed in sequence order.
** It is an error to install the same commit hook more than once.
**
** Each commit hook is called (in order of ascending sequence) at
** each commit operation.  If any commit hook returns non-zero,
** the subsequence commit hooks are omitted and the transaction
** rolls back rather than commit.  It is the responsibility of the
** hooks themselves to issue any error messages.
*/
void db_commit_hook(int (*x)(void), int sequence){
  int i;
................................................................................
}
int db_bind_blob(Stmt *pStmt, const char *zParamName, Blob *pBlob){
  return sqlite3_bind_blob(pStmt->pStmt, paramIdx(pStmt, zParamName),
                          blob_buffer(pBlob), blob_size(pBlob), SQLITE_STATIC);
}

/* bind_str() treats a Blob object like a TEXT string and binds it
** to the SQL variable.  Contrast this to bind_blob() which treats
** the Blob object like an SQL BLOB.
*/
int db_bind_str(Stmt *pStmt, const char *zParamName, Blob *pBlob){
  return sqlite3_bind_text(pStmt->pStmt, paramIdx(pStmt, zParamName),
                          blob_buffer(pBlob), blob_size(pBlob), SQLITE_STATIC);
}

................................................................................
}
void db_column_blob(Stmt *pStmt, int N, Blob *pBlob){
  blob_append(pBlob, sqlite3_column_blob(pStmt->pStmt, N),
              sqlite3_column_bytes(pStmt->pStmt, N));
}

/*
** Initialize a blob to an ephemeral copy of the content of a
** column in the current row.  The data in the blob will become
** invalid when the statement is stepped or reset.
*/
void db_ephemeral_blob(Stmt *pStmt, int N, Blob *pBlob){
  blob_init(pBlob, sqlite3_column_blob(pStmt->pStmt, N),
              sqlite3_column_bytes(pStmt->pStmt, N));
}
................................................................................
){
  if( g.zLogin!=0 ){
    sqlite3_result_text(context, g.zLogin, -1, SQLITE_STATIC);
  }
}

/*
** Implement the cgi() SQL function.  cgi() takes an argument which is
** a name of CGI query parameter. The value of that parameter is returned,
** if available. Optional second argument will be returned if the first
** doesn't exist as a CGI parameter.
*/
static void db_sql_cgi(sqlite3_context *context, int argc, sqlite3_value **argv){
  const char* zP;
  if( argc!=1 && argc!=2 ) return;
  zP = P((const char*)sqlite3_value_text(argv[0]));
  if( zP ){
................................................................................
**                     Ex: kdiff3 "%baseline" "%original" "%merge" -o "%output"
**                     Ex: xxdiff "%original" "%baseline" "%merge" -M "%output"
**                     Ex: meld "%baseline" "%original" "%merge" "%output"
**
**    http-port        The TCP/IP port number to use by the "server"
**                     and "ui" commands.  Default: 8080
**
**    https-login      Send login credentials using HTTPS instead of HTTP
**                     even if the login page request came via HTTP.
**
**    ignore-glob      The VALUE is a comma or newline-separated list of GLOB
**     (versionable)   patterns specifying files that the "extra" command will
**                     ignore.  Example:  *.o,*.obj,*.exe
**
**    localauth        If enabled, require that HTTP connections from
................................................................................
    }
  }else{
    usage("?PROPERTY? ?VALUE?");
  }
}

/*
** The input in a timespan measured in days.  Return a string which
** describes that timespan in units of seconds, minutes, hours, days,
** or years, depending on its duration.
*/
char *db_timespan_name(double rSpan){
  if( rSpan<0 ) rSpan = -rSpan;
  rSpan *= 24.0*3600.0;  /* Convert units to seconds */
  if( rSpan<120.0 ){

Changes to src/delta.c.

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
**   http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This module implements the delta compress algorithm.
**
** Though developed specifically for fossil, the code in this file
** is generally appliable and is thus easily separated from the
** fossil source code base.  Nothing in this file depends on anything
** else in fossil.
*/
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>







|







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
**   http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This module implements the delta compress algorithm.
**
** Though developed specifically for fossil, the code in this file
** is generally applicable and is thus easily separated from the
** fossil source code base.  Nothing in this file depends on anything
** else in fossil.
*/
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>

Changes to src/descendants.c.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
..
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains code used to find decendants of a version
** or leaves of a version tree.
*/
#include "config.h"
#include "descendants.h"
#include <assert.h>


/*
** Create a temporary table named "leaves" if it does not
** already exist.  Load this table with the RID of all
** check-ins that are leaves which are decended from
** check-in iBase.
**
** A "leaf" is a check-in that has no children in the same branch.
** There is a separate permanent table LEAF that contains all leaves
** in the tree.  This routine is used to compute a subset of that
** table consisting of leaves that are descended from a single checkin.
**
................................................................................
    /* Initialize the bags. */
    bag_init(&seen);
    bag_init(&pending);
    bag_insert(&pending, iBase);

    /* This query returns all non-branch-merge children of check-in :rid.
    **
    ** If a a child is a merge of a fork within the same branch, it is 
    ** returned.  Only merge children in different branches are excluded.
    */
    db_prepare(&q1,
      "SELECT cid FROM plink"
      " WHERE pid=:rid"
      "   AND (isprim"
      "        OR coalesce((SELECT value FROM tagxref"







|










|







 







|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
..
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains code used to find descendants of a version
** or leaves of a version tree.
*/
#include "config.h"
#include "descendants.h"
#include <assert.h>


/*
** Create a temporary table named "leaves" if it does not
** already exist.  Load this table with the RID of all
** check-ins that are leaves which are descended from
** check-in iBase.
**
** A "leaf" is a check-in that has no children in the same branch.
** There is a separate permanent table LEAF that contains all leaves
** in the tree.  This routine is used to compute a subset of that
** table consisting of leaves that are descended from a single checkin.
**
................................................................................
    /* Initialize the bags. */
    bag_init(&seen);
    bag_init(&pending);
    bag_insert(&pending, iBase);

    /* This query returns all non-branch-merge children of check-in :rid.
    **
    ** If a child is a merge of a fork within the same branch, it is 
    ** returned.  Only merge children in different branches are excluded.
    */
    db_prepare(&q1,
      "SELECT cid FROM plink"
      " WHERE pid=:rid"
      "   AND (isprim"
      "        OR coalesce((SELECT value FROM tagxref"

Changes to src/diff.c.

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
....
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
#include "config.h"
#include "diff.h"
#include <assert.h>


#if INTERFACE
/*
** Allowed flag parameters to the text_diff() and html_sbsdiff() funtions:
*/
#define DIFF_CONTEXT_MASK ((u64)0x0000ffff) /* Lines of context. Default if 0 */
#define DIFF_WIDTH_MASK   ((u64)0x00ff0000) /* side-by-side column width */
#define DIFF_IGNORE_EOLWS ((u64)0x01000000) /* Ignore end-of-line whitespace */
#define DIFF_SIDEBYSIDE   ((u64)0x02000000) /* Generate a side-by-side diff */
#define DIFF_NEWFILE      ((u64)0x04000000) /* Missing shown as empty files */
#define DIFF_BRIEF        ((u64)0x08000000) /* Show filenames only */
................................................................................
*/
void annotate_cmd(void){
  int fnid;         /* Filename ID */
  int fid;          /* File instance ID */
  int mid;          /* Manifest where file was checked in */
  int cid;          /* Checkout ID */
  Blob treename;    /* FILENAME translated to canonical form */
  char *zFilename;  /* Cannonical filename */
  Annotator ann;    /* The annotation of the file */
  int i;            /* Loop counter */
  const char *zLimit; /* The value to the --limit option */
  int iLimit;       /* How far back in time to look */
  int showLog;      /* True to show the log */
  int fileVers;     /* Show file version instead of check-in versions */
  int annFlags = 0; /* Flags to control annotation properties */







|







 







|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
....
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
#include "config.h"
#include "diff.h"
#include <assert.h>


#if INTERFACE
/*
** Allowed flag parameters to the text_diff() and html_sbsdiff() functions:
*/
#define DIFF_CONTEXT_MASK ((u64)0x0000ffff) /* Lines of context. Default if 0 */
#define DIFF_WIDTH_MASK   ((u64)0x00ff0000) /* side-by-side column width */
#define DIFF_IGNORE_EOLWS ((u64)0x01000000) /* Ignore end-of-line whitespace */
#define DIFF_SIDEBYSIDE   ((u64)0x02000000) /* Generate a side-by-side diff */
#define DIFF_NEWFILE      ((u64)0x04000000) /* Missing shown as empty files */
#define DIFF_BRIEF        ((u64)0x08000000) /* Show filenames only */
................................................................................
*/
void annotate_cmd(void){
  int fnid;         /* Filename ID */
  int fid;          /* File instance ID */
  int mid;          /* Manifest where file was checked in */
  int cid;          /* Checkout ID */
  Blob treename;    /* FILENAME translated to canonical form */
  char *zFilename;  /* Canonical filename */
  Annotator ann;    /* The annotation of the file */
  int i;            /* Loop counter */
  const char *zLimit; /* The value to the --limit option */
  int iLimit;       /* How far back in time to look */
  int showLog;      /* True to show the log */
  int fileVers;     /* Show file version instead of check-in versions */
  int annFlags = 0; /* Flags to control annotation properties */

Changes to src/encode.c.

132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
  zOut[i] = 0;
  return zOut;
}

/*
** Convert the input string into a form that is suitable for use as
** a token in the HTTP protocol.  Spaces are encoded as '+' and special
** characters are encoded as "%HH" where HH is a two-digit hexidecimal
** representation of the character.  The "/" character is encoded
** as "%2F".
*/
char *httpize(const char *z, int n){
  return EncodeHttp(z, n, 1);
}








|







132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
  zOut[i] = 0;
  return zOut;
}

/*
** Convert the input string into a form that is suitable for use as
** a token in the HTTP protocol.  Spaces are encoded as '+' and special
** characters are encoded as "%HH" where HH is a two-digit hexadecimal
** representation of the character.  The "/" character is encoded
** as "%2F".
*/
char *httpize(const char *z, int n){
  return EncodeHttp(z, n, 1);
}

Changes to src/glob.c.

214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
    }
  }
  return *z==0;
}

/*
** Return true (non-zero) if zString matches any of the patterns in
** the Glob.  The value returned is actually a 1-basd index of the pattern
** that matched.  Return 0 if none of the patterns match zString.
**
** A NULL glob matches nothing.
*/
int glob_match(Glob *pGlob, const char *zString){
  int i;
  if( pGlob==0 ) return 0;







|







214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
    }
  }
  return *z==0;
}

/*
** Return true (non-zero) if zString matches any of the patterns in
** the Glob.  The value returned is actually a 1-based index of the pattern
** that matched.  Return 0 if none of the patterns match zString.
**
** A NULL glob matches nothing.
*/
int glob_match(Glob *pGlob, const char *zString){
  int i;
  if( pGlob==0 ) return 0;

Changes to src/http_socket.c.

124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#endif
    iSocket = -1;
  }
}

/*
** Open a socket connection.  The identify of the server is determined
** by global varibles that are set using url_parse():
**
**    g.urlName       Name of the server.  Ex: www.fossil-scm.org
**    g.urlPort       TCP/IP port to use.  Ex: 80
**
** Return the number of errors.
*/
int socket_open(void){







|







124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#endif
    iSocket = -1;
  }
}

/*
** Open a socket connection.  The identify of the server is determined
** by global variables that are set using url_parse():
**
**    g.urlName       Name of the server.  Ex: www.fossil-scm.org
**    g.urlPort       TCP/IP port to use.  Ex: 80
**
** Return the number of errors.
*/
int socket_open(void){

Changes to src/http_ssl.c.

180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
    (void)BIO_reset(iBio);
    BIO_free_all(iBio);
  }
}

/*
** Open an SSL connection.  The identify of the server is determined
** by global varibles that are set using url_parse():
**
**    g.urlName       Name of the server.  Ex: www.fossil-scm.org
**    g.urlPort       TCP/IP port to use.  Ex: 80
**
** Return the number of errors.
*/
int ssl_open(void){







|







180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
    (void)BIO_reset(iBio);
    BIO_free_all(iBio);
  }
}

/*
** Open an SSL connection.  The identify of the server is determined
** by global variables that are set using url_parse():
**
**    g.urlName       Name of the server.  Ex: www.fossil-scm.org
**    g.urlPort       TCP/IP port to use.  Ex: 80
**
** Return the number of errors.
*/
int ssl_open(void){

Changes to src/http_transport.c.

290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
      n -= sent;
    }
  }
}

/*
** This routine is called when the outbound message is complete and
** it is time to being recieving a reply.
*/
void transport_flip(void){
  if( g.urlIsSsh ){
    fprintf(sshOut, "\n\n");
  }else if( g.urlIsFile ){
    char *zCmd;
    fclose(transport.pFile);







|







290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
      n -= sent;
    }
  }
}

/*
** This routine is called when the outbound message is complete and
** it is time to being receiving a reply.
*/
void transport_flip(void){
  if( g.urlIsSsh ){
    fprintf(sshOut, "\n\n");
  }else if( g.urlIsFile ){
    char *zCmd;
    fclose(transport.pFile);

Changes to src/json.c.

320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
...
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
....
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
....
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
....
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
....
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
....
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
  static char buf[BufSize] = {'F','O','S','S','I','L','-',0};
  assert((code >= 1000) && (code <= 9999) && "Invalid Fossil/JSON code.");
  sprintf(buf+7,"%04d", code);
  return buf;
}

/*
** Adds v to the API-internal cleanup mechanism. key is ingored
** (legacy) but might be re-introduced and "should" be a unique
** (app-wide) value.  Failure to insert an item may be caused by any
** of the following:
**
** - Allocation error.
** - g.json.gc.a is NULL
** - key is NULL or empty.
................................................................................
     them in.
  */
  v = cson_value_new_array();
  g.json.gc.v = v;
  g.json.gc.a = cson_value_get_array(v);
  cson_value_add_reference(v)
    /* Needed to allow us to include this value in other JSON
       containers without transfering ownership to those containers.
       All other persistent g.json.XXX.v values get appended to
       g.json.gc.a, and therefore already have a live reference
       for this purpose.
    */
    ;

  /*
................................................................................
** on error.
**
** If payload is not NULL and resultCode is 0 then it is set as the
** "payload" property of the returned object.  If resultCode is 0 then
** it defaults to g.json.resultCode. If resultCode is (or defaults to)
** non-zero and payload is not NULL then this function calls
** cson_value_free(payload) and does not insert the payload into the
** response. In either case, onwership of payload is transfered to (or
** shared with, if the caller holds a reference) this function.
**
** pMsg is an optional message string property (resultText) of the
** response. If resultCode is non-0 and pMsg is NULL then
** json_err_cstr() is used to get the error string. The caller may
** provide his own or may use an empty string to suppress the
** resultText property.
................................................................................
      tmp = g.json.cmd.v;
      SET("$commandPath");
    }
    if(g.json.param.v){
      tmp = g.json.param.v;
      SET("$params");
    }
    if(0){/*Only for debuggering, add some info to the response.*/
      tmp = cson_value_new_integer( g.json.cmd.offset );
      cson_object_set( o, "cmd.offset", tmp );
      cson_object_set( o, "isCGI", cson_value_new_bool( g.isHTTP ) );
    }
  }

  if(HAS_TIMER){
................................................................................
    /* This is, philosophically speaking, not quite the right place
       for ending the timer, but this is the one function which all of
       the JSON exit paths use (and they call it after processing,
       just before they end).
    */
    double span;
    span = END_TIMER;
    /* i'm actually seeing sub-ms runtimes in some tests, but a time of
       0 is "just wrong", so we'll bump that up to 1ms.
    */
    cson_object_set(o,"procTimeMs", cson_value_new_integer((cson_int_t)((span>1.0)?span:1)));
  }
  if(g.json.warnings){
    tmp = cson_array_value(g.json.warnings);
    SET("warnings");
................................................................................
    ++g.json.dispatchDepth;
    return (*def->func)();
  }
}


/*
** Impl of /json/rebuild. Requires admin previleges.
*/
static cson_value * json_page_rebuild(){
  if( !g.perm.Admin ){
    json_set_err(FSL_JSON_E_DENIED,"Requires 'a' privileges.");
    return NULL;
  }else{
  /* Reminder: the db_xxx() ops "should" fail via the fossil core
................................................................................
**
** In CLI mode, the -R REPO common option is supported. Due to limitations
** in the argument dispatching code, any -FLAGS must come after the final
** sub- (or subsub-) command.
**
** The commands include:
**
**   anonymousPassord
**   artifact
**   branch
**   cap
**   config
**   diff
**   dir
**   g







|







 







|







 







|







 







|







 







|







 







|







 







|







320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
...
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
....
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
....
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
....
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
....
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
....
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
  static char buf[BufSize] = {'F','O','S','S','I','L','-',0};
  assert((code >= 1000) && (code <= 9999) && "Invalid Fossil/JSON code.");
  sprintf(buf+7,"%04d", code);
  return buf;
}

/*
** Adds v to the API-internal cleanup mechanism. key is ignored
** (legacy) but might be re-introduced and "should" be a unique
** (app-wide) value.  Failure to insert an item may be caused by any
** of the following:
**
** - Allocation error.
** - g.json.gc.a is NULL
** - key is NULL or empty.
................................................................................
     them in.
  */
  v = cson_value_new_array();
  g.json.gc.v = v;
  g.json.gc.a = cson_value_get_array(v);
  cson_value_add_reference(v)
    /* Needed to allow us to include this value in other JSON
       containers without transferring ownership to those containers.
       All other persistent g.json.XXX.v values get appended to
       g.json.gc.a, and therefore already have a live reference
       for this purpose.
    */
    ;

  /*
................................................................................
** on error.
**
** If payload is not NULL and resultCode is 0 then it is set as the
** "payload" property of the returned object.  If resultCode is 0 then
** it defaults to g.json.resultCode. If resultCode is (or defaults to)
** non-zero and payload is not NULL then this function calls
** cson_value_free(payload) and does not insert the payload into the
** response. In either case, ownership of payload is transfered to (or
** shared with, if the caller holds a reference) this function.
**
** pMsg is an optional message string property (resultText) of the
** response. If resultCode is non-0 and pMsg is NULL then
** json_err_cstr() is used to get the error string. The caller may
** provide his own or may use an empty string to suppress the
** resultText property.
................................................................................
      tmp = g.json.cmd.v;
      SET("$commandPath");
    }
    if(g.json.param.v){
      tmp = g.json.param.v;
      SET("$params");
    }
    if(0){/*Only for debugging, add some info to the response.*/
      tmp = cson_value_new_integer( g.json.cmd.offset );
      cson_object_set( o, "cmd.offset", tmp );
      cson_object_set( o, "isCGI", cson_value_new_bool( g.isHTTP ) );
    }
  }

  if(HAS_TIMER){
................................................................................
    /* This is, philosophically speaking, not quite the right place
       for ending the timer, but this is the one function which all of
       the JSON exit paths use (and they call it after processing,
       just before they end).
    */
    double span;
    span = END_TIMER;
    /* I'm actually seeing sub-ms runtimes in some tests, but a time of
       0 is "just wrong", so we'll bump that up to 1ms.
    */
    cson_object_set(o,"procTimeMs", cson_value_new_integer((cson_int_t)((span>1.0)?span:1)));
  }
  if(g.json.warnings){
    tmp = cson_array_value(g.json.warnings);
    SET("warnings");
................................................................................
    ++g.json.dispatchDepth;
    return (*def->func)();
  }
}


/*
** Impl of /json/rebuild. Requires admin privileges.
*/
static cson_value * json_page_rebuild(){
  if( !g.perm.Admin ){
    json_set_err(FSL_JSON_E_DENIED,"Requires 'a' privileges.");
    return NULL;
  }else{
  /* Reminder: the db_xxx() ops "should" fail via the fossil core
................................................................................
**
** In CLI mode, the -R REPO common option is supported. Due to limitations
** in the argument dispatching code, any -FLAGS must come after the final
** sub- (or subsub-) command.
**
** The commands include:
**
**   anonymousPassword
**   artifact
**   branch
**   cap
**   config
**   diff
**   dir
**   g

Changes to src/json_detail.h.

115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
...
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
...
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
...
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
** responsible for handling one JSON request/command and/or
** dispatching to sub-commands.
**
** By the time the callback is called, json_page_top() (HTTP mode) or
** json_cmd_top() (CLI mode) will have set up the JSON-related
** environment. Implementations may generate a "result payload" of any
** JSON type by returning its value from this function (ownership is
** tranferred to the caller). On error they should set
** g.json.resultCode to one of the FossilJsonCodes values and return
** either their payload object or NULL. Note that NULL is a legal
** success value - it simply means the response will contain no
** payload. If g.json.resultCode is non-zero when this function
** returns then the top-level dispatcher will destroy any payload
** returned by this function and will output a JSON error response
** instead.
................................................................................
** All of the setup/response code is handled by the top dispatcher
** functions and the callbacks concern themselves only with:
**
** a) Permissions checking (inspecting g.perm).
** b) generating a response payload (if applicable)
** c) Setting g.json's error state (if applicable). See json_set_err().
**
** It is imperitive that NO callback functions EVER output ANYTHING to
** stdout, as that will effectively corrupt any JSON output, and
** almost certainly will corrupt any HTTP response headers. Output
** sent to stderr ends up in my apache log, so that might be useful
** for debuggering in some cases, but no such code should be left
** enabled for non-debuggering builds.
*/
typedef cson_value * (*fossil_json_f)();

/*
** Holds name-to-function mappings for JSON page/command dispatching.
**
** Internally we model page dispatching lists as arrays of these
................................................................................
  fossil_json_f func;
  /*
  ** Which mode(s) of execution does func() support:
  **
  ** <0 = CLI only, >0 = HTTP only, 0==both
  **
  ** Now that we can simulate POST in CLI mode, the distinction
  ** between them has disappeared in most (or all) cases, so 0 is the
  ** the standard value.
  **
  ** 201207: this is not needed any more. We can get rid of it. Or
  ** keep it around in case it becomes useful again at some point.
  */
  char runMode;
} JsonPageDef;
................................................................................
/*
** 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.
**
** This function takes the command specified in
** json_comand_arg(1+g.json.dispatchDepth) and searches pages for a
** matching name. If found then that page's func() is called to fetch
** the payload, which is returned to the caller.
**
** On error, g.json.resultCode is set to one of the FossilJsonCodes
** values and NULL is returned. If non-NULL is returned, ownership is
** transfered to the caller (but the g.json error state might still be
** set in that case, so the caller must check that or pass it on up
................................................................................
**
** a) Not running in JSON mode (via json command or /json path).
**
** b) We are running in JSON CLI mode, but no POST data has been fed
** in.
**
** Whether or not we need to take args from CLI or POST data makes a
** difference in argument/parameter handling in many JSON rountines,
** and thus this distinction.
*/
char fossil_has_json();

enum json_get_changed_files_flags {
    json_get_changed_files_ELIDE_PARENT = 1 << 0
};

#endif/*FOSSIL_JSON_DETAIL_H_INCLUDED*/
#endif /* FOSSIL_ENABLE_JSON */







|







 







|



|
|







 







|







 







|







 







|










115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
...
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
...
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
...
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
** responsible for handling one JSON request/command and/or
** dispatching to sub-commands.
**
** By the time the callback is called, json_page_top() (HTTP mode) or
** json_cmd_top() (CLI mode) will have set up the JSON-related
** environment. Implementations may generate a "result payload" of any
** JSON type by returning its value from this function (ownership is
** transferred to the caller). On error they should set
** g.json.resultCode to one of the FossilJsonCodes values and return
** either their payload object or NULL. Note that NULL is a legal
** success value - it simply means the response will contain no
** payload. If g.json.resultCode is non-zero when this function
** returns then the top-level dispatcher will destroy any payload
** returned by this function and will output a JSON error response
** instead.
................................................................................
** All of the setup/response code is handled by the top dispatcher
** functions and the callbacks concern themselves only with:
**
** a) Permissions checking (inspecting g.perm).
** b) generating a response payload (if applicable)
** c) Setting g.json's error state (if applicable). See json_set_err().
**
** It is imperative that NO callback functions EVER output ANYTHING to
** stdout, as that will effectively corrupt any JSON output, and
** almost certainly will corrupt any HTTP response headers. Output
** sent to stderr ends up in my apache log, so that might be useful
** for debugging in some cases, but no such code should be left
** enabled for non-debugging builds.
*/
typedef cson_value * (*fossil_json_f)();

/*
** Holds name-to-function mappings for JSON page/command dispatching.
**
** Internally we model page dispatching lists as arrays of these
................................................................................
  fossil_json_f func;
  /*
  ** Which mode(s) of execution does func() support:
  **
  ** <0 = CLI only, >0 = HTTP only, 0==both
  **
  ** Now that we can simulate POST in CLI mode, the distinction
  ** between them has disappeared in most (or all) cases, so 0 is
  ** the standard value.
  **
  ** 201207: this is not needed any more. We can get rid of it. Or
  ** keep it around in case it becomes useful again at some point.
  */
  char runMode;
} JsonPageDef;
................................................................................
/*
** 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.
**
** This function takes the command specified in
** json_command_arg(1+g.json.dispatchDepth) and searches pages for a
** matching name. If found then that page's func() is called to fetch
** the payload, which is returned to the caller.
**
** On error, g.json.resultCode is set to one of the FossilJsonCodes
** values and NULL is returned. If non-NULL is returned, ownership is
** transfered to the caller (but the g.json error state might still be
** set in that case, so the caller must check that or pass it on up
................................................................................
**
** a) Not running in JSON mode (via json command or /json path).
**
** b) We are running in JSON CLI mode, but no POST data has been fed
** in.
**
** Whether or not we need to take args from CLI or POST data makes a
** difference in argument/parameter handling in many JSON routines,
** and thus this distinction.
*/
char fossil_has_json();

enum json_get_changed_files_flags {
    json_get_changed_files_ELIDE_PARENT = 1 << 0
};

#endif/*FOSSIL_JSON_DETAIL_H_INCLUDED*/
#endif /* FOSSIL_ENABLE_JSON */

Changes to src/json_login.c.

167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
...
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
       the expiry time is assigned. (Remember that JSON doesn't do
       unsigned int.)

       For non-anonymous users we could also simply query the
       user.cexpire db field after calling login_set_user_cookie(),
       but for anonymous we need to get the time when the cookie is
       set because anon does not get a db entry like normal users
       do. Anonyous cookies currently have a hard-coded lifetime in
       login_set_anon_cookie() (currently 6 hours), which we "should
       arguably" change to use the time configured for non-anonymous
       users (see login_set_user_cookie() for details).
    */
    return payload;
  }
}
................................................................................
** Impl of /json/logout.
**
*/
cson_value * json_page_logout(){
  cson_value const *token = g.json.authToken;
    /* Remember that json_mode_bootstrap() replaces the login cookie
       with the JSON auth token if the request contains it. If the
       reqest is missing the auth token then this will fetch fossil's
       original cookie. Either way, it's what we want :).

       We require the auth token to avoid someone maliciously
       trying to log someone else out (not 100% sure if that
       would be possible, given fossil's hardened cookie, but
       i'll assume it would be for the time being).
    */
    ;
  if(!token){
    g.json.resultCode = FSL_JSON_E_MISSING_AUTH;
  }else{
    login_clear_login_data();
    g.json.authToken = NULL /* memory is owned elsewhere.*/;







|







 







|





|







167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
...
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
       the expiry time is assigned. (Remember that JSON doesn't do
       unsigned int.)

       For non-anonymous users we could also simply query the
       user.cexpire db field after calling login_set_user_cookie(),
       but for anonymous we need to get the time when the cookie is
       set because anon does not get a db entry like normal users
       do. Anonymous cookies currently have a hard-coded lifetime in
       login_set_anon_cookie() (currently 6 hours), which we "should
       arguably" change to use the time configured for non-anonymous
       users (see login_set_user_cookie() for details).
    */
    return payload;
  }
}
................................................................................
** Impl of /json/logout.
**
*/
cson_value * json_page_logout(){
  cson_value const *token = g.json.authToken;
    /* Remember that json_mode_bootstrap() replaces the login cookie
       with the JSON auth token if the request contains it. If the
       request is missing the auth token then this will fetch fossil's
       original cookie. Either way, it's what we want :).

       We require the auth token to avoid someone maliciously
       trying to log someone else out (not 100% sure if that
       would be possible, given fossil's hardened cookie, but
       I'll assume it would be for the time being).
    */
    ;
  if(!token){
    g.json.resultCode = FSL_JSON_E_MISSING_AUTH;
  }else{
    login_clear_login_data();
    g.json.authToken = NULL /* memory is owned elsewhere.*/;

Changes to src/json_tag.c.

283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
      "   coalesce(ecomment,comment) AS comment,"
      "   coalesce(euser,user) AS user,"
      "   CASE event.type"
      "     WHEN 'ci' THEN 'checkin'"
      "     WHEN 'w' THEN 'wiki'"
      "     WHEN 'e' THEN 'event'"
      "     WHEN 't' THEN 'ticket'"
      "     ELSE 'WTF?'"
      "   END"
      "   AS eventType"
      " FROM event, blob"
      " WHERE blob.rid=event.objid"
      ;
    /* FIXME: re-add tags. */
    db_prepare(&q,







|







283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
      "   coalesce(ecomment,comment) AS comment,"
      "   coalesce(euser,user) AS user,"
      "   CASE event.type"
      "     WHEN 'ci' THEN 'checkin'"
      "     WHEN 'w' THEN 'wiki'"
      "     WHEN 'e' THEN 'event'"
      "     WHEN 't' THEN 'ticket'"
      "     ELSE 'unknown'"
      "   END"
      "   AS eventType"
      " FROM event, blob"
      " WHERE blob.rid=event.objid"
      ;
    /* FIXME: re-add tags. */
    db_prepare(&q,

Changes to src/json_timeline.c.

627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
    int const rid = db_column_int(&q,0);
    Manifest * pMan = NULL;
    cson_value * rowV;
    cson_object * row;
    /*printf("rid=%d\n",rid);*/
    pMan = manifest_get(rid, CFTYPE_TICKET);
    if(!pMan){
      /* this might be an attachment? i'm seeing this with
         rid 15380, uuid [1292fef05f2472108].

         /json/artifact/1292fef05f2472108 returns not-found,
         probably because we haven't added artifact/ticket
         yet(?).
      */
      continue;







|







627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
    int const rid = db_column_int(&q,0);
    Manifest * pMan = NULL;
    cson_value * rowV;
    cson_object * row;
    /*printf("rid=%d\n",rid);*/
    pMan = manifest_get(rid, CFTYPE_TICKET);
    if(!pMan){
      /* this might be an attachment? I'm seeing this with
         rid 15380, uuid [1292fef05f2472108].

         /json/artifact/1292fef05f2472108 returns not-found,
         probably because we haven't added artifact/ticket
         yet(?).
      */
      continue;

Changes to src/json_wiki.c.

208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
                                                     char contentFormat ){
  if(!zSymname || !*zSymname){
    return json_get_wiki_page_by_name(zPageName, contentFormat);
  }else{
    int rid = symbolic_name_to_rid( zSymname ? zSymname : zPageName, "w" );
    if(rid<0){
      json_set_err(FSL_JSON_E_AMBIGUOUS_UUID,
                   "UUID [%s] is ambiguious.", zSymname);
      return NULL;
    }else if(rid==0){
      json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND,
                   "UUID [%s] does not resolve to a wiki page.", zSymname);
      return NULL;
    }else{
      return json_get_wiki_page_by_rid(rid, contentFormat);







|







208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
                                                     char contentFormat ){
  if(!zSymname || !*zSymname){
    return json_get_wiki_page_by_name(zPageName, contentFormat);
  }else{
    int rid = symbolic_name_to_rid( zSymname ? zSymname : zPageName, "w" );
    if(rid<0){
      json_set_err(FSL_JSON_E_AMBIGUOUS_UUID,
                   "UUID [%s] is ambiguous.", zSymname);
      return NULL;
    }else if(rid==0){
      json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND,
                   "UUID [%s] does not resolve to a wiki page.", zSymname);
      return NULL;
    }else{
      return json_get_wiki_page_by_rid(rid, contentFormat);

Changes to src/login.c.

352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
...
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
...
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
....
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
....
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
                   login_cookie_path(), -86400);
    db_multi_exec("UPDATE user SET cookie=NULL, ipaddr=NULL, "
                  "  cexpire=0 WHERE uid=%d"
                  "  AND login NOT IN ('anonymous','nobody',"
                  "  'developer','reader')", g.userUid);
    cgi_replace_parameter(cookie, NULL)
      /* At the time of this writing, cgi_replace_parameter() was
      ** "NULL-value-safe", and i'm hoping the NULL doesn't cause any
      ** downstream problems here. We could alternately use "" here.
      */
      ;
  }
}

/*
................................................................................
void login_page(void){
  const char *zUsername, *zPasswd;
  const char *zNew1, *zNew2;
  const char *zAnonPw = 0;
  const char *zGoto = P("g");
  int anonFlag;
  char *zErrMsg = "";
  int uid;                     /* User id loged in user */
  char *zSha1Pw;
  const char *zIpAddr;         /* IP address of requestor */

  login_check_credentials();
  sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0,
		  constant_time_cmp_function, 0, 0);
  zUsername = P("u");
................................................................................
    "   AND constant_time_cmp(cookie,%Q)=0",
    zLogin, zRemoteAddr, zCookie
  );
  return uid;
}

/*
** This routine examines the login cookie to see if it exists and and
** is valid.  If the login cookie checks out, it then sets global
** variables appropriately.  Global variables set include g.userUid
** and g.zLogin and the g.perm family of permission booleans.
**
** If the 
*/
void login_check_credentials(void){
................................................................................
*/
void login_insert_csrf_secret(void){
  @ <input type="hidden" name="csrf" value="%s(g.zCsrfToken)" />
}

/*
** Before using the results of a form, first call this routine to verify
** that ths Anti-CSRF token is present and is valid.  If the Anti-CSRF token
** is missing or is incorrect, that indicates a cross-site scripting attach
** so emits an error message and abort.
*/
void login_verify_csrf_secret(void){
  if( g.okCsrf ) return;
  if( fossil_strcmp(P("csrf"), g.zCsrfToken)==0 ){
    g.okCsrf = 1;
................................................................................
    "   AND name <> 'peer-repo-%q'"
    " ORDER BY +value",
    zSelfCode
  );
  while( db_step(&q)==SQLITE_ROW ){
    const char *zRepoName = db_column_text(&q, 1);
    if( file_size(zRepoName)<0 ){
      /* Silently remove non-existant repositories from the login group. */
      const char *zLabel = db_column_text(&q, 0);
      db_multi_exec(
         "DELETE FROM config WHERE name GLOB 'peer-*-%q'",
         &zLabel[10]
      );
      continue;
    }







|







 







|







 







|







 







|







 







|







352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
...
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
...
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
....
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
....
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
                   login_cookie_path(), -86400);
    db_multi_exec("UPDATE user SET cookie=NULL, ipaddr=NULL, "
                  "  cexpire=0 WHERE uid=%d"
                  "  AND login NOT IN ('anonymous','nobody',"
                  "  'developer','reader')", g.userUid);
    cgi_replace_parameter(cookie, NULL)
      /* At the time of this writing, cgi_replace_parameter() was
      ** "NULL-value-safe", and I'm hoping the NULL doesn't cause any
      ** downstream problems here. We could alternately use "" here.
      */
      ;
  }
}

/*
................................................................................
void login_page(void){
  const char *zUsername, *zPasswd;
  const char *zNew1, *zNew2;
  const char *zAnonPw = 0;
  const char *zGoto = P("g");
  int anonFlag;
  char *zErrMsg = "";
  int uid;                     /* User id logged in user */
  char *zSha1Pw;
  const char *zIpAddr;         /* IP address of requestor */

  login_check_credentials();
  sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0,
		  constant_time_cmp_function, 0, 0);
  zUsername = P("u");
................................................................................
    "   AND constant_time_cmp(cookie,%Q)=0",
    zLogin, zRemoteAddr, zCookie
  );
  return uid;
}

/*
** This routine examines the login cookie to see if it exists and
** is valid.  If the login cookie checks out, it then sets global
** variables appropriately.  Global variables set include g.userUid
** and g.zLogin and the g.perm family of permission booleans.
**
** If the 
*/
void login_check_credentials(void){
................................................................................
*/
void login_insert_csrf_secret(void){
  @ <input type="hidden" name="csrf" value="%s(g.zCsrfToken)" />
}

/*
** Before using the results of a form, first call this routine to verify
** that this Anti-CSRF token is present and is valid.  If the Anti-CSRF token
** is missing or is incorrect, that indicates a cross-site scripting attach
** so emits an error message and abort.
*/
void login_verify_csrf_secret(void){
  if( g.okCsrf ) return;
  if( fossil_strcmp(P("csrf"), g.zCsrfToken)==0 ){
    g.okCsrf = 1;
................................................................................
    "   AND name <> 'peer-repo-%q'"
    " ORDER BY +value",
    zSelfCode
  );
  while( db_step(&q)==SQLITE_ROW ){
    const char *zRepoName = db_column_text(&q, 1);
    if( file_size(zRepoName)<0 ){
      /* Silently remove non-existent repositories from the login group. */
      const char *zLabel = db_column_text(&q, 0);
      db_multi_exec(
         "DELETE FROM config WHERE name GLOB 'peer-*-%q'",
         &zLabel[10]
      );
      continue;
    }

Changes to src/main.c.

148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
....
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
....
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
....
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
  FILE *httpIn;           /* Accept HTTP input from here */
  FILE *httpOut;          /* Send HTTP output here */
  int xlinkClusterOnly;   /* Set when cloning.  Only process clusters */
  int fTimeFormat;        /* 1 for UTC.  2 for localtime.  0 not yet selected */
  int *aCommitFile;       /* Array of files to be committed */
  int markPrivate;        /* All new artifacts are private if true */
  int clockSkewSeen;      /* True if clocks on client and server out of sync */
  char isHTTP;            /* True if erver/CGI modes, else assume CLI. */
  char javascriptHyperlink; /* If true, set href= using script, not HTML */

  int urlIsFile;          /* True if a "file:" url */
  int urlIsHttps;         /* True if a "https:" url */
  int urlIsSsh;           /* True if an "ssh:" url */
  char *urlName;          /* Hostname for http: or filename for file: */
  char *urlHostname;      /* The HOST: parameter on http headers */
................................................................................
    ** will use g.zExtra directly.
    ** Reminder: the login mechanism uses 'name' differently, and may
    ** eventually have a problem/collision with this.
    **
    ** Disabled by stephan when running in JSON mode because this
    ** particular parameter name is very common and i have had no end
    ** of grief with this handling. The JSON API never relies on the
    ** handling below, and by disabling it in JSON mode i can remove
    ** lots of special-case handling in several JSON handlers.
    */
#ifdef FOSSIL_ENABLE_JSON
    if(!g.json.isJsonMode){
#endif
      dehttpize(g.zExtra);
      cgi_set_parameter_nocopy("name", g.zExtra);
................................................................................
** inserted.  Paint an error page if no match is found.
**
** If there is a line of the form:
**
**    redirect: * URL
**
** Then a redirect is made to URL if no match is found.  Otherwise a
** very primative error message is returned.
*/
void redirect_web_page(int nRedirect, char **azRedirect){
  int i;                             /* Loop counter */
  const char *zNotFound = 0;         /* Not found URL */
  const char *zName = P("name");
  set_base_url(0);
  if( zName==0 ){
................................................................................
** within an open checkout.
**
** The "ui" command automatically starts a web browser after initializing
** the web server.  The "ui" command also binds to 127.0.0.1 and so will
** only process HTTP traffic from the local machine.
**
** In the "server" command, the REPOSITORY can be a directory (aka folder)
** that contains one or more rspositories with names ending in ".fossil".
** In that case, the first element of the URL is used to select among the
** various repositories.
**
** By default, the "ui" command provides full administrative access without
** having to log in.  This can be disabled by setting turning off the
** "localauth" setting.  Automatic login for the "server" command is available
** if the --localauth option is present and the "localauth" setting is off







|







 







|







 







|







 







|







148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
....
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
....
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
....
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
  FILE *httpIn;           /* Accept HTTP input from here */
  FILE *httpOut;          /* Send HTTP output here */
  int xlinkClusterOnly;   /* Set when cloning.  Only process clusters */
  int fTimeFormat;        /* 1 for UTC.  2 for localtime.  0 not yet selected */
  int *aCommitFile;       /* Array of files to be committed */
  int markPrivate;        /* All new artifacts are private if true */
  int clockSkewSeen;      /* True if clocks on client and server out of sync */
  char isHTTP;            /* True if server/CGI modes, else assume CLI. */
  char javascriptHyperlink; /* If true, set href= using script, not HTML */

  int urlIsFile;          /* True if a "file:" url */
  int urlIsHttps;         /* True if a "https:" url */
  int urlIsSsh;           /* True if an "ssh:" url */
  char *urlName;          /* Hostname for http: or filename for file: */
  char *urlHostname;      /* The HOST: parameter on http headers */
................................................................................
    ** will use g.zExtra directly.
    ** Reminder: the login mechanism uses 'name' differently, and may
    ** eventually have a problem/collision with this.
    **
    ** Disabled by stephan when running in JSON mode because this
    ** particular parameter name is very common and i have had no end
    ** of grief with this handling. The JSON API never relies on the
    ** handling below, and by disabling it in JSON mode I can remove
    ** lots of special-case handling in several JSON handlers.
    */
#ifdef FOSSIL_ENABLE_JSON
    if(!g.json.isJsonMode){
#endif
      dehttpize(g.zExtra);
      cgi_set_parameter_nocopy("name", g.zExtra);
................................................................................
** inserted.  Paint an error page if no match is found.
**
** If there is a line of the form:
**
**    redirect: * URL
**
** Then a redirect is made to URL if no match is found.  Otherwise a
** very primitive error message is returned.
*/
void redirect_web_page(int nRedirect, char **azRedirect){
  int i;                             /* Loop counter */
  const char *zNotFound = 0;         /* Not found URL */
  const char *zName = P("name");
  set_base_url(0);
  if( zName==0 ){
................................................................................
** within an open checkout.
**
** The "ui" command automatically starts a web browser after initializing
** the web server.  The "ui" command also binds to 127.0.0.1 and so will
** only process HTTP traffic from the local machine.
**
** In the "server" command, the REPOSITORY can be a directory (aka folder)
** that contains one or more repositories with names ending in ".fossil".
** In that case, the first element of the URL is used to select among the
** various repositories.
**
** By default, the "ui" command provides full administrative access without
** having to log in.  This can be disabled by setting turning off the
** "localauth" setting.  Automatic login for the "server" command is available
** if the --localauth option is present and the "localauth" setting is off

Changes to src/makeheaders.c.

745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
....
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
....
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
....
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
....
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
#define TT_Comment         4   /* Either C or C++ style comment */
#define TT_Number          5   /* Any numeric constant */
#define TT_String          6   /* String or character constants. ".." or '.' */
#define TT_Braces          7   /* All text between { and a matching } */
#define TT_EOF             8   /* End of file */
#define TT_Error           9   /* An error condition */
#define TT_BlockComment    10  /* A C-Style comment at the left margin that
                                * spans multple lines */
#define TT_Other           0   /* None of the above */

/*
** Get a single low-level token from the input file.  Update the
** file pointer so that it points to the first character beyond the
** token.
**
................................................................................

  /*
  ** At this point, we know we have a type declaration that is bounded
  ** by pList and pEnd and has the name pName.
  */

  /*
  ** If the braces are followed immedately by a semicolon, then we are
  ** dealing a type declaration only.  There is not variable definition
  ** following the type declaration.  So reset...
  */
  if( pEnd->pNext==0 || pEnd->pNext->zText[0]==';' ){
    *pReset = ';';
    need_to_collapse = 0;
  }else{
................................................................................
** definition or a function prototype.  Return TRUE if we are dealing
** with a variable defintion and FALSE for a prototype.
**
** pEnd is the token that ends the object.  It can be either a ';' or
** a '='.  If it is '=', then assume we have a variable definition.
**
** If pEnd is ';', then the determination is more difficult.  We have
** to search for an occurance of an ID followed immediately by '('.
** If found, we have a prototype.  Otherwise we are dealing with a
** variable definition.
*/
static int isVariableDef(Token *pFirst, Token *pEnd){
  if( pEnd && pEnd->zText[0]=='=' && 
    (pEnd->pPrev->nText!=8 || strncmp(pEnd->pPrev->zText,"operator",8)!=0)
  ){
................................................................................
      DeclSetProperty(p,DP_Forward|DP_Declared|DP_Flag);
    }else{
      DeclClearProperty(p,DP_Flag);
    }
  }

  /*
  ** Call ScanText() recusively (this routine is called from ScanText())
  ** to include declarations required to come before these declarations.
  */
  for(p=pDecl; p; p=p->pSameName){
    if( DeclHasProperty(p,DP_Flag) ){
      if( p->zDecl[0]=='#' ){
        ScanText(&p->zDecl[1],pState);
      }else{
................................................................................
    }
  }
  /* printf("END SCANTEXT\n"); */
}

/*
** Provide a full declaration to any object which so far has had only
** a foward declaration.
*/
static void CompleteForwardDeclarations(GenState *pState){
  Decl *pDecl;
  int progress;

  do{
    progress = 0;







|







 







|







 







|







 







|







 







|







745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
....
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
....
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
....
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
....
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
#define TT_Comment         4   /* Either C or C++ style comment */
#define TT_Number          5   /* Any numeric constant */
#define TT_String          6   /* String or character constants. ".." or '.' */
#define TT_Braces          7   /* All text between { and a matching } */
#define TT_EOF             8   /* End of file */
#define TT_Error           9   /* An error condition */
#define TT_BlockComment    10  /* A C-Style comment at the left margin that
                                * spans multiple lines */
#define TT_Other           0   /* None of the above */

/*
** Get a single low-level token from the input file.  Update the
** file pointer so that it points to the first character beyond the
** token.
**
................................................................................

  /*
  ** At this point, we know we have a type declaration that is bounded
  ** by pList and pEnd and has the name pName.
  */

  /*
  ** If the braces are followed immediately by a semicolon, then we are
  ** dealing a type declaration only.  There is not variable definition
  ** following the type declaration.  So reset...
  */
  if( pEnd->pNext==0 || pEnd->pNext->zText[0]==';' ){
    *pReset = ';';
    need_to_collapse = 0;
  }else{
................................................................................
** definition or a function prototype.  Return TRUE if we are dealing
** with a variable defintion and FALSE for a prototype.
**
** pEnd is the token that ends the object.  It can be either a ';' or
** a '='.  If it is '=', then assume we have a variable definition.
**
** If pEnd is ';', then the determination is more difficult.  We have
** to search for an occurrence of an ID followed immediately by '('.
** If found, we have a prototype.  Otherwise we are dealing with a
** variable definition.
*/
static int isVariableDef(Token *pFirst, Token *pEnd){
  if( pEnd && pEnd->zText[0]=='=' && 
    (pEnd->pPrev->nText!=8 || strncmp(pEnd->pPrev->zText,"operator",8)!=0)
  ){
................................................................................
      DeclSetProperty(p,DP_Forward|DP_Declared|DP_Flag);
    }else{
      DeclClearProperty(p,DP_Flag);
    }
  }

  /*
  ** Call ScanText() recursively (this routine is called from ScanText())
  ** to include declarations required to come before these declarations.
  */
  for(p=pDecl; p; p=p->pSameName){
    if( DeclHasProperty(p,DP_Flag) ){
      if( p->zDecl[0]=='#' ){
        ScanText(&p->zDecl[1],pState);
      }else{
................................................................................
    }
  }
  /* printf("END SCANTEXT\n"); */
}

/*
** Provide a full declaration to any object which so far has had only
** a forward declaration.
*/
static void CompleteForwardDeclarations(GenState *pState){
  Decl *pDecl;
  int progress;

  do{
    progress = 0;

Changes to src/manifest.c.

448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
....
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
....
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
....
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
        p->zAttachTarget = zTarget;
        break;
      }

      /*
      **    B <uuid>
      **
      ** A B-line gives the UUID for the baselinen of a delta-manifest.
      */
      case 'B': {
        if( p->zBaseline ) SYNTAX("more than one B-card");
        p->zBaseline = next_token(&x, &sz);
        if( p->zBaseline==0 ) SYNTAX("missing UUID on B-card");
        if( sz!=UUID_SIZE || !validate16(p->zBaseline, UUID_SIZE) ){
          SYNTAX("invalid UUID on B-card");
................................................................................
/*
** Add a single entry to the mlink table.  Also add the filename to
** the filename table if it is not there already.
*/
static void add_one_mlink(
  int mid,                  /* The record ID of the manifest */
  const char *zFromUuid,    /* UUID for the mlink.pid. "" to add file */
  const char *zToUuid,      /* UUID for the mlink.fid. "" to delele */
  const char *zFilename,    /* Filename */
  const char *zPrior,       /* Previous filename. NULL if unchanged */
  int isPublic,             /* True if mid is not a private manifest */
  int mperm                 /* 1: exec, 2: symlink */
){
  int fnid, pfnid, pid, fid;
  static Stmt s1;
................................................................................
    manifest_destroy(*ppOther);
    return;
  }
  isPublic = !content_is_private(cid);

  /* Try to make the parent manifest a delta from the child, if that
  ** is an appropriate thing to do.  For a new baseline, make the 
  ** previoius baseline a delta from the current baseline.
  */
  if( (pParent->zBaseline==0)==(pChild->zBaseline==0) ){
    content_deltify(pid, cid, 0); 
  }else if( pChild->zBaseline==0 && pParent->zBaseline!=0 ){
    content_deltify(pParent->pBaseline->rid, cid, 0);
  }

................................................................................
      if( p->aTag[i].zUuid ){
        tid = uuid_to_rid(p->aTag[i].zUuid, 1);
      }else{
        tid = rid;
      }
      if( tid ){
        switch( p->aTag[i].zName[0] ){
          case '-':  type = 0;  break;  /* Cancel prior occurances */
          case '+':  type = 1;  break;  /* Apply to target only */
          case '*':  type = 2;  break;  /* Propagate to descendants */
          default:
            fossil_fatal("unknown tag type in manifest: %s", p->aTag);
            return 0;
        }
        tag_insert(&p->aTag[i].zName[1], type, p->aTag[i].zValue, 







|







 







|







 







|







 







|







448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
....
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
....
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
....
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
        p->zAttachTarget = zTarget;
        break;
      }

      /*
      **    B <uuid>
      **
      ** A B-line gives the UUID for the baseline of a delta-manifest.
      */
      case 'B': {
        if( p->zBaseline ) SYNTAX("more than one B-card");
        p->zBaseline = next_token(&x, &sz);
        if( p->zBaseline==0 ) SYNTAX("missing UUID on B-card");
        if( sz!=UUID_SIZE || !validate16(p->zBaseline, UUID_SIZE) ){
          SYNTAX("invalid UUID on B-card");
................................................................................
/*
** Add a single entry to the mlink table.  Also add the filename to
** the filename table if it is not there already.
*/
static void add_one_mlink(
  int mid,                  /* The record ID of the manifest */
  const char *zFromUuid,    /* UUID for the mlink.pid. "" to add file */
  const char *zToUuid,      /* UUID for the mlink.fid. "" to delete */
  const char *zFilename,    /* Filename */
  const char *zPrior,       /* Previous filename. NULL if unchanged */
  int isPublic,             /* True if mid is not a private manifest */
  int mperm                 /* 1: exec, 2: symlink */
){
  int fnid, pfnid, pid, fid;
  static Stmt s1;
................................................................................
    manifest_destroy(*ppOther);
    return;
  }
  isPublic = !content_is_private(cid);

  /* Try to make the parent manifest a delta from the child, if that
  ** is an appropriate thing to do.  For a new baseline, make the 
  ** previous baseline a delta from the current baseline.
  */
  if( (pParent->zBaseline==0)==(pChild->zBaseline==0) ){
    content_deltify(pid, cid, 0); 
  }else if( pChild->zBaseline==0 && pParent->zBaseline!=0 ){
    content_deltify(pParent->pBaseline->rid, cid, 0);
  }

................................................................................
      if( p->aTag[i].zUuid ){
        tid = uuid_to_rid(p->aTag[i].zUuid, 1);
      }else{
        tid = rid;
      }
      if( tid ){
        switch( p->aTag[i].zName[0] ){
          case '-':  type = 0;  break;  /* Cancel prior occurrences */
          case '+':  type = 1;  break;  /* Apply to target only */
          case '*':  type = 2;  break;  /* Propagate to descendants */
          default:
            fossil_fatal("unknown tag type in manifest: %s", p->aTag);
            return 0;
        }
        tag_insert(&p->aTag[i].zName[1], type, p->aTag[i].zValue, 

Changes to src/md5.c.

364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
  }
  return zOut;
}


/*
** Compute the MD5 checksum of a file on disk.  Store the resulting
** checksum in the blob pCksum.  pCksum is assumed to be ininitialized.
**
** Return the number of errors.
*/
int md5sum_file(const char *zFilename, Blob *pCksum){
  FILE *in;
  MD5Context ctx;
  unsigned char zResult[16];







|







364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
  }
  return zOut;
}


/*
** Compute the MD5 checksum of a file on disk.  Store the resulting
** checksum in the blob pCksum.  pCksum is assumed to be initialized.
**
** Return the number of errors.
*/
int md5sum_file(const char *zFilename, Blob *pCksum){
  FILE *in;
  MD5Context ctx;
  unsigned char zResult[16];

Changes to src/merge3.c.

81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
** The aC[] array contains triples of integers.  Within each triple, the
** elements are:
**
**   (0)  The number of lines to copy
**   (1)  The number of lines to delete
**   (2)  The number of liens to insert
**
** Suppose we want to advance over sz lines of the originl file.  This routine
** returns true if that advance would land us on a copy operation.  It
** returns false if the advance would end on a delete.
*/
static int ends_at_CPY(int *aC, int sz){
  while( sz>0 && (aC[0]>0 || aC[1]>0 || aC[2]>0) ){
    if( aC[0]>=sz ) return 1;
    sz -= aC[0];







|







81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
** The aC[] array contains triples of integers.  Within each triple, the
** elements are:
**
**   (0)  The number of lines to copy
**   (1)  The number of lines to delete
**   (2)  The number of liens to insert
**
** Suppose we want to advance over sz lines of the original file.  This routine
** returns true if that advance would land us on a copy operation.  It
** returns false if the advance would end on a delete.
*/
static int ends_at_CPY(int *aC, int sz){
  while( sz>0 && (aC[0]>0 || aC[1]>0 || aC[2]>0) ){
    if( aC[0]>=sz ) return 1;
    sz -= aC[0];

Changes to src/mkindex.c.

44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
**
** Comment text following COMMAND: through the end of the comment is
** understood to be help text for the command specified.  This help
** text is accumulated and a table containing the text for each command
** is generated.  That table is used implement the "fossil help" command
** and the "/help" HTTP method.
**
** Multiple occurrances of WEBPAGE: or COMMAND: (but not both) can appear
** before each function name.  In this way, webpages and commands can
** have aliases.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>







|







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
**
** Comment text following COMMAND: through the end of the comment is
** understood to be help text for the command specified.  This help
** text is accumulated and a table containing the text for each command
** is generated.  That table is used implement the "fossil help" command
** and the "/help" HTTP method.
**
** Multiple occurrences of WEBPAGE: or COMMAND: (but not both) can appear
** before each function name.  In this way, webpages and commands can
** have aliases.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>

Changes to src/name.c.

60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
...
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
** The following additional forms are available in local checkouts:
**
**   *  "current"
**   *  "prev" or "previous"
**   *  "next"
**
** Return the RID of the matching artifact.  Or return 0 if the name does not
** match any known object.  Or return -1 if the name is ambiguious.
**
** The zType parameter specifies the type of artifact: ci, t, w, e, g. 
** If zType is NULL or "" or "*" then any type of artifact will serve.
** zType is "ci" in most use cases since we are usually searching for
** a check-in.
*/
int symbolic_name_to_rid(const char *zTag, const char *zType){
................................................................................
  return name_to_typed_rid(zName, "*");
}

/*
** WEBPAGE: ambiguous
** URL: /ambiguous?name=UUID&src=WEBPAGE
** 
** The UUID given by the name paramager is ambiguous.  Display a page
** that shows all possible choices and let the user select between them.
*/
void ambiguous_page(void){
  Stmt q;
  const char *zName = P("name");  
  const char *zSrc = P("src");
  char *z;







|







 







|







60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
...
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
** The following additional forms are available in local checkouts:
**
**   *  "current"
**   *  "prev" or "previous"
**   *  "next"
**
** Return the RID of the matching artifact.  Or return 0 if the name does not
** match any known object.  Or return -1 if the name is ambiguous.
**
** The zType parameter specifies the type of artifact: ci, t, w, e, g. 
** If zType is NULL or "" or "*" then any type of artifact will serve.
** zType is "ci" in most use cases since we are usually searching for
** a check-in.
*/
int symbolic_name_to_rid(const char *zTag, const char *zType){
................................................................................
  return name_to_typed_rid(zName, "*");
}

/*
** WEBPAGE: ambiguous
** URL: /ambiguous?name=UUID&src=WEBPAGE
** 
** The UUID given by the name parameter is ambiguous.  Display a page
** that shows all possible choices and let the user select between them.
*/
void ambiguous_page(void){
  Stmt q;
  const char *zName = P("name");  
  const char *zSrc = P("src");
  char *z;

Changes to src/printf.c.

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

/*
** Conversion types fall into various categories as defined by the
** following enumeration.
*/
#define etRADIX       1 /* Integer types.  %d, %x, %o, and so forth */
#define etFLOAT       2 /* Floating point.  %f */
#define etEXP         3 /* Exponentional notation. %e and %E */
#define etGENERIC     4 /* Floating or exponential, depending on exponent. %g */
#define etSIZE        5 /* Return number of characters processed so far. %n */
#define etSTRING      6 /* Strings. %s */
#define etDYNSTRING   7 /* Dynamically allocated strings. %z */
#define etPERCENT     8 /* Percent symbol. %% */
#define etCHARX       9 /* Characters. %c */
#define etERROR      10 /* Used to indicate no such conversion type */







|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

/*
** Conversion types fall into various categories as defined by the
** following enumeration.
*/
#define etRADIX       1 /* Integer types.  %d, %x, %o, and so forth */
#define etFLOAT       2 /* Floating point.  %f */
#define etEXP         3 /* Exponential notation. %e and %E */
#define etGENERIC     4 /* Floating or exponential, depending on exponent. %g */
#define etSIZE        5 /* Return number of characters processed so far. %n */
#define etSTRING      6 /* Strings. %s */
#define etDYNSTRING   7 /* Dynamically allocated strings. %z */
#define etPERCENT     8 /* Percent symbol. %% */
#define etCHARX       9 /* Characters. %c */
#define etERROR      10 /* Used to indicate no such conversion type */

Changes to src/rebuild.c.

203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
...
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
...
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
...
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
** rid with content pBase and all of its descendants.  This
** routine clears the content buffer before returning.
**
** If the zFNameFormat variable is set, then this routine is
** called to run "fossil deconstruct" instead of the usual
** "fossil rebuild".  In that case, instead of rebuilding the
** cross-referencing information, write the file content out
** to the approriate directory.
**
** In both cases, this routine automatically recurses to process
** other artifacts that are deltas off of the current artifact.
** This is the most efficient way to extract all of the original
** artifact content from the Fossil repository.
*/
static void rebuild_step(int rid, int size, Blob *pBase){
................................................................................
  zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
  if( zUuid==0 ) return;
  tag_add_artifact("sym-", "trunk", zUuid, 0, 2, 0, 0);
  tag_add_artifact("", "branch", zUuid, "trunk", 2, 0, 0);
}

/*
** Core function to rebuild the infomration in the derived tables of a
** fossil repository from the blobs. This function is shared between
** 'rebuild_database' ('rebuild') and 'reconstruct_cmd'
** ('reconstruct'), both of which have to regenerate this information
** from scratch.
**
** If the randomize parameter is true, then the BLOBs are deliberately
** extracted in a random order.  This feature is used to test the
................................................................................
  zPrefixOpt=find_option("prefixlength","L",1);
  if( !zPrefixOpt ){
    prefixLength = 2;
  }else{
    if( zPrefixOpt[0]>='0' && zPrefixOpt[0]<='9' && !zPrefixOpt[1] ){
      prefixLength = (int)(*zPrefixOpt-'0');
    }else{
      fossil_fatal("N(%s) is not a a valid prefix length!",zPrefixOpt);
    }
  }
  /* open repository and open query for all artifacts */
  db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
  privateFlag = find_option("private",0,0)!=0;
  verify_all_options();
  /* check number of arguments */
................................................................................
  }
#ifndef _WIN32
  if( file_access(zDestDir, W_OK) ){
    fossil_fatal("DESTINATION(%s) is not writeable!",zDestDir);
  }
#else
  /* write access on windows is not checked, errors will be
  ** dected on blob_write_to_file
  */
#endif
  if( prefixLength ){
    zFNameFormat = mprintf("%s/%%.%ds/%%s",zDestDir,prefixLength);
  }else{
    zFNameFormat = mprintf("%s/%%s",zDestDir);
  }







|







 







|







 







|







 







|







203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
...
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
...
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
...
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
** rid with content pBase and all of its descendants.  This
** routine clears the content buffer before returning.
**
** If the zFNameFormat variable is set, then this routine is
** called to run "fossil deconstruct" instead of the usual
** "fossil rebuild".  In that case, instead of rebuilding the
** cross-referencing information, write the file content out
** to the appropriate directory.
**
** In both cases, this routine automatically recurses to process
** other artifacts that are deltas off of the current artifact.
** This is the most efficient way to extract all of the original
** artifact content from the Fossil repository.
*/
static void rebuild_step(int rid, int size, Blob *pBase){
................................................................................
  zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
  if( zUuid==0 ) return;
  tag_add_artifact("sym-", "trunk", zUuid, 0, 2, 0, 0);
  tag_add_artifact("", "branch", zUuid, "trunk", 2, 0, 0);
}

/*
** Core function to rebuild the information in the derived tables of a
** fossil repository from the blobs. This function is shared between
** 'rebuild_database' ('rebuild') and 'reconstruct_cmd'
** ('reconstruct'), both of which have to regenerate this information
** from scratch.
**
** If the randomize parameter is true, then the BLOBs are deliberately
** extracted in a random order.  This feature is used to test the
................................................................................
  zPrefixOpt=find_option("prefixlength","L",1);
  if( !zPrefixOpt ){
    prefixLength = 2;
  }else{
    if( zPrefixOpt[0]>='0' && zPrefixOpt[0]<='9' && !zPrefixOpt[1] ){
      prefixLength = (int)(*zPrefixOpt-'0');
    }else{
      fossil_fatal("N(%s) is not a valid prefix length!",zPrefixOpt);
    }
  }
  /* open repository and open query for all artifacts */
  db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
  privateFlag = find_option("private",0,0)!=0;
  verify_all_options();
  /* check number of arguments */
................................................................................
  }
#ifndef _WIN32
  if( file_access(zDestDir, W_OK) ){
    fossil_fatal("DESTINATION(%s) is not writeable!",zDestDir);
  }
#else
  /* write access on windows is not checked, errors will be
  ** detected on blob_write_to_file
  */
#endif
  if( prefixLength ){
    zFNameFormat = mprintf("%s/%%.%ds/%%s",zDestDir,prefixLength);
  }else{
    zFNameFormat = mprintf("%s/%%s",zDestDir);
  }

Changes to src/report.c.

116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
....
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
    return mprintf("%d", atoi(zOrig));
  }
  return "";
}

/*
** Remove blank lines from the beginning of a string and
** all whitespace from the end. Removes whitespace preceeding a NL,
** which also converts any CRNL sequence into a single NL.
*/
char *remove_blank_lines(const char *zOrig){
  int i, j, n;
  char *z;
  for(i=j=0; fossil_isspace(zOrig[i]); i++){ if( zOrig[i]=='\n' ) j = i+1; }
  n = strlen(&zOrig[j]);
................................................................................
    fossil_print("%s", i<nArg-1 ? (zSep?zSep:"\t") : "\n");
  }
  return 0;
}

/*
** Generate a report.  The rn query parameter is the report number.
** The output is written to stdout as flat file. The zFilter paramater
** is a full WHERE-condition.
*/
void rptshow( 
    const char *zRep,
    const char *zSepIn,
    const char *zFilter,
    tTktShowEncoding enc







|







 







|







116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
....
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
    return mprintf("%d", atoi(zOrig));
  }
  return "";
}

/*
** Remove blank lines from the beginning of a string and
** all whitespace from the end. Removes whitespace preceding a NL,
** which also converts any CRNL sequence into a single NL.
*/
char *remove_blank_lines(const char *zOrig){
  int i, j, n;
  char *z;
  for(i=j=0; fossil_isspace(zOrig[i]); i++){ if( zOrig[i]=='\n' ) j = i+1; }
  n = strlen(&zOrig[j]);
................................................................................
    fossil_print("%s", i<nArg-1 ? (zSep?zSep:"\t") : "\n");
  }
  return 0;
}

/*
** Generate a report.  The rn query parameter is the report number.
** The output is written to stdout as flat file. The zFilter parameter
** is a full WHERE-condition.
*/
void rptshow( 
    const char *zRep,
    const char *zSepIn,
    const char *zFilter,
    tTktShowEncoding enc

Changes to src/search.c.

91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
};

/*
** Compare a search pattern against an input string and return a score.
**
** Scoring:
**   *  All terms must match at least once or the score is zero
**   *  10 bonus points if the first occurrance is an exact match
**   *  1 additional point for each subsequent match of the same word
**   *  Extra points of two consecutive words of the pattern are consecutive
**      in the document
*/
int search_score(Search *p, const char *zDoc){
  int iPrev = 999;
  int score = 10;







|







91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
};

/*
** Compare a search pattern against an input string and return a score.
**
** Scoring:
**   *  All terms must match at least once or the score is zero
**   *  10 bonus points if the first occurrence is an exact match
**   *  1 additional point for each subsequent match of the same word
**   *  Extra points of two consecutive words of the pattern are consecutive
**      in the document
*/
int search_score(Search *p, const char *zDoc){
  int iPrev = 999;
  int score = 10;

Changes to src/setup.c.

307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
  int uid, i;
  int higherUser = 0;  /* True if user being edited is SETUP and the */
                       /* user doing the editing is ADMIN.  Disallow editing */
  char *inherit[128];
  int a[128];
  char *oa[128];

  /* Must have ADMIN privleges to access this page
  */
  login_check_credentials();
  if( !g.perm.Admin ){ login_needed(); return; }

  /* Check to see if an ADMIN user is trying to edit a SETUP account.
  ** Don't allow that.
  */







|







307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
  int uid, i;
  int higherUser = 0;  /* True if user being edited is SETUP and the */
                       /* user doing the editing is ADMIN.  Disallow editing */
  char *inherit[128];
  int a[128];
  char *oa[128];

  /* Must have ADMIN privileges to access this page
  */
  login_check_credentials();
  if( !g.perm.Admin ){ login_needed(); return; }

  /* Check to see if an ADMIN user is trying to edit a SETUP account.
  ** Don't allow that.
  */

Changes to src/sha1.c.

269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
  }
  return zOut;
}


/*
** Compute the SHA1 checksum of a file on disk.  Store the resulting
** checksum in the blob pCksum.  pCksum is assumed to be ininitialized.
**
** Return the number of errors.
*/
int sha1sum_file(const char *zFilename, Blob *pCksum){
  FILE *in;
  SHA1Context ctx;
  unsigned char zResult[20];







|







269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
  }
  return zOut;
}


/*
** Compute the SHA1 checksum of a file on disk.  Store the resulting
** checksum in the blob pCksum.  pCksum is assumed to be initialized.
**
** Return the number of errors.
*/
int sha1sum_file(const char *zFilename, Blob *pCksum){
  FILE *in;
  SHA1Context ctx;
  unsigned char zResult[20];

Changes to src/shell.c.

302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
....
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
  }
  return *z==0;
}

/*
** A global char* and an SQL function to access its current value 
** from within an SQL statement. This program used to use the 
** sqlite_exec_printf() API to substitue a string into an SQL statement.
** The correct way to do this with sqlite3 is to use the bind API, but
** since the shell is built around the callback paradigm it would be a lot
** of work. Instead just use this hack, which is quite harmless.
*/
static const char *zShellStatic = 0;
static void shellstaticFunc(
  sqlite3_context *context,
................................................................................
      if( !pStmt ){
        /* this happens for a comment or white-space */
        zSql = zLeftover;
        while( IsSpace(zSql[0]) ) zSql++;
        continue;
      }

      /* save off the prepared statment handle and reset row count */
      if( pArg ){
        pArg->pStmt = pStmt;
        pArg->cnt = 0;
      }

      /* echo the sql statement if echo on */
      if( pArg && pArg->echoOn ){







|







 







|







302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
....
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
  }
  return *z==0;
}

/*
** A global char* and an SQL function to access its current value 
** from within an SQL statement. This program used to use the 
** sqlite_exec_printf() API to substitute a string into an SQL statement.
** The correct way to do this with sqlite3 is to use the bind API, but
** since the shell is built around the callback paradigm it would be a lot
** of work. Instead just use this hack, which is quite harmless.
*/
static const char *zShellStatic = 0;
static void shellstaticFunc(
  sqlite3_context *context,
................................................................................
      if( !pStmt ){
        /* this happens for a comment or white-space */
        zSql = zLeftover;
        while( IsSpace(zSql[0]) ) zSql++;
        continue;
      }

      /* save off the prepared statement handle and reset row count */
      if( pArg ){
        pArg->pStmt = pStmt;
        pArg->cnt = 0;
      }

      /* echo the sql statement if echo on */
      if( pArg && pArg->echoOn ){

Changes to src/sqlcmd.c.

101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
    sqlite3_result_blob(context, pOut, nOut, sqlite3_free);
  }else{
    sqlite3_result_error(context, "input is not zlib compressed", -1);
  }
}

/*
** This is the "automatic extensionn" initializer that runs right after
** the connection to the repository database is opened.  Set up the
** database connection to be more useful to the human operator.
*/
static int sqlcmd_autoinit(
  sqlite3 *db,
  const char **pzErrMsg,
  const void *notUsed







|







101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
    sqlite3_result_blob(context, pOut, nOut, sqlite3_free);
  }else{
    sqlite3_result_error(context, "input is not zlib compressed", -1);
  }
}

/*
** This is the "automatic extension" initializer that runs right after
** the connection to the repository database is opened.  Set up the
** database connection to be more useful to the human operator.
*/
static int sqlcmd_autoinit(
  sqlite3 *db,
  const char **pzErrMsg,
  const void *notUsed

Changes to src/style.c.

698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
...
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
...
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
    @   color: red;
  },
  { "span.note",
    "format for leading text for notes",
    @   font-weight: bold;
  },
  { "span.textareaLabel",
    "format for textare labels",
    @   font-weight: bold;
  },
  { "table.usetupLayoutTable",
    "format for the user setup layout table",
    @   outline-style: none;
    @   padding: 0;
    @   margin: 25px;
................................................................................
    "selected lines of text within a linenumbered artifact display",
    @   font-weight: bold;
    @   color: blue;
    @   background-color: #d5d5ff;
    @   border: 1px blue solid;
  },
  { "p.missingPriv",
    "format for missing priviliges note on user setup page",
    @  color: blue;
  },
  { "span.wikiruleHead",
    "format for leading text in wikirules definitions",
    @   font-weight: bold;
  },
  { "td.tktDspLabel",
................................................................................
    @   color: #0000ff;
  },
  { "span.diffln",
    "line numbers in a diff",
    @   color: #a0a0a0;
  },
  { "span.modpending",
    "Moderation Pending message on timelin",
    @   color: #b03800;
    @   font-style: italic;
  },
  { 0,
    0,
    0
  }







|







 







|







 







|







698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
...
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
...
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
    @   color: red;
  },
  { "span.note",
    "format for leading text for notes",
    @   font-weight: bold;
  },
  { "span.textareaLabel",
    "format for textarea labels",
    @   font-weight: bold;
  },
  { "table.usetupLayoutTable",
    "format for the user setup layout table",
    @   outline-style: none;
    @   padding: 0;
    @   margin: 25px;
................................................................................
    "selected lines of text within a linenumbered artifact display",
    @   font-weight: bold;
    @   color: blue;
    @   background-color: #d5d5ff;
    @   border: 1px blue solid;
  },
  { "p.missingPriv",
    "format for missing privileges note on user setup page",
    @  color: blue;
  },
  { "span.wikiruleHead",
    "format for leading text in wikirules definitions",
    @   font-weight: bold;
  },
  { "td.tktDspLabel",
................................................................................
    @   color: #0000ff;
  },
  { "span.diffln",
    "line numbers in a diff",
    @   color: #a0a0a0;
  },
  { "span.modpending",
    "Moderation Pending message on timeline",
    @   color: #b03800;
    @   font-style: italic;
  },
  { 0,
    0,
    0
  }

Changes to src/tag.c.

339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
** Run various subcommands to control tags and properties
**
**     %fossil tag add ?--raw? ?--propagate? TAGNAME CHECK-IN ?VALUE?
**
**         Add a new tag or property to CHECK-IN. The tag will
**         be usable instead of a CHECK-IN in commands such as
**         update and merge.  If the --propagate flag is present,
**         the tag value propages to all descendants of CHECK-IN
**
**     %fossil tag cancel ?--raw? TAGNAME CHECK-IN
**
**         Remove the tag TAGNAME from CHECK-IN, and also remove
**         the propagation of the tag to any descendants.
**
**     %fossil tag find ?--raw? ?--type TYPE? TAGNAME







|







339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
** Run various subcommands to control tags and properties
**
**     %fossil tag add ?--raw? ?--propagate? TAGNAME CHECK-IN ?VALUE?
**
**         Add a new tag or property to CHECK-IN. The tag will
**         be usable instead of a CHECK-IN in commands such as
**         update and merge.  If the --propagate flag is present,
**         the tag value propagates to all descendants of CHECK-IN
**
**     %fossil tag cancel ?--raw? TAGNAME CHECK-IN
**
**         Remove the tag TAGNAME from CHECK-IN, and also remove
**         the propagation of the tag to any descendants.
**
**     %fossil tag find ?--raw? ?--type TYPE? TAGNAME

Changes to src/th.c.

75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
...
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
...
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
....
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
** is stored in Th_Variable.nRef.
**
** For scalar variables, Th_Variable.zData is never 0. Th_Variable.nData
** stores the number of bytes in the value pointed to by zData.
**
** For an array variable, Th_Variable.zData is 0 and pHash points to
** a hash table mapping between array key name (a th1 string) and
** a the pointer to the Th_Variable structure holding the scalar
** value.
*/
struct Th_Variable {
  int nRef;                   /* Number of references to this structure */
  int nData;                  /* Number of bytes at Th_Variable.zData */
  char *zData;               /* Data for scalar variables */
  Th_Hash *pHash;             /* Data for array variables */
................................................................................
    case 'f': case 'F': return 15;
  }
  return -1;
}

/*
** Argument pEntry points to an entry in a stack frame hash table
** (Th_Frame.paVar). Decrement the refrerence count of the Th_Variable
** structure that the entry points to. Free the Th_Variable if its
** reference count reaches 0.
**
** Argument pContext is a pointer to the interpreter structure.
*/
static void thFreeVariable(Th_HashEntry *pEntry, void *pContext){
  Th_Variable *pValue = (Th_Variable *)pEntry->pData;
................................................................................
      /* Call the command procedure. */
      if( rc==TH_OK ){
        Th_Command *p = (Th_Command *)(pEntry->pData);
        const char **azArg = (const char **)argv;
        rc = p->xProc(interp, p->pContext, argc, azArg, argl);
      }
  
      /* If an error occured, add this command to the stack trace report. */
      if( rc==TH_ERROR ){
        char *zRes;
        int nRes;
        char *zStack = 0;
        int nStack = 0;
  
        zRes = Th_TakeResult(interp, &nRes);
................................................................................
** arrayok is true an array name is Ok.
*/
static Th_Variable *thFindValue(
  Th_Interp *interp,
  const char *zVar,     /* Pointer to variable name */
  int nVar,              /* Number of bytes at nVar */
  int create,            /* If true, create the variable if not found */
  int arrayok            /* If true, an array is Ok. Othewise array==error */
){
  const char *zOuter;
  int nOuter;
  const char *zInner;
  int nInner;
  int isGlobal;








|







 







|







 







|







 







|







75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
...
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
...
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
....
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
** is stored in Th_Variable.nRef.
**
** For scalar variables, Th_Variable.zData is never 0. Th_Variable.nData
** stores the number of bytes in the value pointed to by zData.
**
** For an array variable, Th_Variable.zData is 0 and pHash points to
** a hash table mapping between array key name (a th1 string) and
** a pointer to the Th_Variable structure holding the scalar
** value.
*/
struct Th_Variable {
  int nRef;                   /* Number of references to this structure */
  int nData;                  /* Number of bytes at Th_Variable.zData */
  char *zData;               /* Data for scalar variables */
  Th_Hash *pHash;             /* Data for array variables */
................................................................................
    case 'f': case 'F': return 15;
  }
  return -1;
}

/*
** Argument pEntry points to an entry in a stack frame hash table
** (Th_Frame.paVar). Decrement the reference count of the Th_Variable
** structure that the entry points to. Free the Th_Variable if its
** reference count reaches 0.
**
** Argument pContext is a pointer to the interpreter structure.
*/
static void thFreeVariable(Th_HashEntry *pEntry, void *pContext){
  Th_Variable *pValue = (Th_Variable *)pEntry->pData;
................................................................................
      /* Call the command procedure. */
      if( rc==TH_OK ){
        Th_Command *p = (Th_Command *)(pEntry->pData);
        const char **azArg = (const char **)argv;
        rc = p->xProc(interp, p->pContext, argc, azArg, argl);
      }
  
      /* If an error occurred, add this command to the stack trace report. */
      if( rc==TH_ERROR ){
        char *zRes;
        int nRes;
        char *zStack = 0;
        int nStack = 0;
  
        zRes = Th_TakeResult(interp, &nRes);
................................................................................
** arrayok is true an array name is Ok.
*/
static Th_Variable *thFindValue(
  Th_Interp *interp,
  const char *zVar,     /* Pointer to variable name */
  int nVar,              /* Number of bytes at nVar */
  int create,            /* If true, create the variable if not found */
  int arrayok            /* If true, an array is Ok. Otherwise array==error */
){
  const char *zOuter;
  int nOuter;
  const char *zInner;
  int nInner;
  int isGlobal;

Changes to src/th_main.c.

484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
  return TH_OK;
}

/*
** TH1 command:     stime
**
** Return the number of microseconds of CPU time consumed by the current
** process in systsem space.
*/
static int stimeCmd(
  Th_Interp *interp,
  void *p, 
  int argc, 
  const char **argv, 
  int *argl







|







484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
  return TH_OK;
}

/*
** TH1 command:     stime
**
** Return the number of microseconds of CPU time consumed by the current
** process in system space.
*/
static int stimeCmd(
  Th_Interp *interp,
  void *p, 
  int argc, 
  const char **argv, 
  int *argl

Changes to src/timeline.c.

880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
...
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
....
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
**
**    a=TIMEORTAG    after this event
**    b=TIMEORTAG    before this event
**    c=TIMEORTAG    "circa" this event
**    n=COUNT        max number of events in output
**    p=UUID         artifact and up to COUNT parents and ancestors
**    d=UUID         artifact and up to COUNT descendants
**    dp=UUUID       The same as d=UUID&p=UUID
**    t=TAGID        show only check-ins with the given tagid
**    r=TAGID        show check-ins related to tagid
**    u=USER         only if belonging to this user
**    y=TYPE         'ci', 'w', 't', 'e'
**    s=TEXT         string search (comment and brief)
**    ng             Suppress the graph if present
**    nd             Suppress "divider" lines
................................................................................
**    brbg           Background color from branch name
**    ubg            Background color from user
**
** p= and d= can appear individually or together.  If either p= or d=
** appear, then u=, y=, a=, and b= are ignored.
**
** If a= and b= appear, only a= is used.  If neither appear, the most
** recent events are choosen.
**
** If n= is missing, the default count is 20.
*/
void page_timeline(void){
  Stmt q;                            /* Query used to generate the timeline */
  Blob sql;                          /* text of SQL used to generate timeline */
  Blob desc;                         /* Description of the timeline */
................................................................................
      blob_appendf(&sql,
        "AND (EXISTS(SELECT 1 FROM tagxref"
                    " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)", tagid);

      if( zBrName ){
        url_add_parameter(&url, "r", zBrName);
        /* The next two blob_appendf() calls add SQL that causes checkins that
        ** are not part of the branch which are parents or childen of the branch
        ** to be included in the report.  This related check-ins are useful
        ** in helping to visualize what has happened on a quiescent branch 
        ** that is infrequently merged with a much more activate branch.
        */
        blob_appendf(&sql,
          " OR EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=cid"
                     " WHERE tagid=%d AND tagtype>0 AND pid=blob.rid)",
           tagid
        );
        if( P("mionly")==0 ){







|







 







|







 







|
|
|
|







880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
...
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
....
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
**
**    a=TIMEORTAG    after this event
**    b=TIMEORTAG    before this event
**    c=TIMEORTAG    "circa" this event
**    n=COUNT        max number of events in output
**    p=UUID         artifact and up to COUNT parents and ancestors
**    d=UUID         artifact and up to COUNT descendants
**    dp=UUID        The same as d=UUID&p=UUID
**    t=TAGID        show only check-ins with the given tagid
**    r=TAGID        show check-ins related to tagid
**    u=USER         only if belonging to this user
**    y=TYPE         'ci', 'w', 't', 'e'
**    s=TEXT         string search (comment and brief)
**    ng             Suppress the graph if present
**    nd             Suppress "divider" lines
................................................................................
**    brbg           Background color from branch name
**    ubg            Background color from user
**
** p= and d= can appear individually or together.  If either p= or d=
** appear, then u=, y=, a=, and b= are ignored.
**
** If a= and b= appear, only a= is used.  If neither appear, the most
** recent events are chosen.
**
** If n= is missing, the default count is 20.
*/
void page_timeline(void){
  Stmt q;                            /* Query used to generate the timeline */
  Blob sql;                          /* text of SQL used to generate timeline */
  Blob desc;                         /* Description of the timeline */
................................................................................
      blob_appendf(&sql,
        "AND (EXISTS(SELECT 1 FROM tagxref"
                    " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)", tagid);

      if( zBrName ){
        url_add_parameter(&url, "r", zBrName);
        /* The next two blob_appendf() calls add SQL that causes checkins that
        ** are not part of the branch which are parents or children of the
        ** branch to be included in the report.  This related check-ins are
        ** useful in helping to visualize what has happened on a quiescent
        ** branch that is infrequently merged with a much more activate branch.
        */
        blob_appendf(&sql,
          " OR EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=cid"
                     " WHERE tagid=%d AND tagtype>0 AND pid=blob.rid)",
           tagid
        );
        if( P("mionly")==0 ){

Changes to src/tkt.c.

89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
...
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
**
** Only load those fields which do not already exist as
** variables.
**
** Fields of the TICKET table that begin with "private_" are
** expanded using the db_reveal() function.  If g.perm.RdAddr is
** true, then the db_reveal() function will decode the content
** using the CONCEALED table so that the content legable.
** Otherwise, db_reveal() is a no-op and the content remains
** obscured.
*/
static void initializeVariablesFromDb(void){
  const char *zName;
  Stmt q;
  int i, n, size, j;
................................................................................
}


/*
** WEBPAGE: tktnew
** WEBPAGE: debug_tktnew
**
** Enter a new ticket.  the tktnew_template script in the ticket
** configuration is used.  The /tktnew page is the official ticket
** entry page.  The /debug_tktnew page is used for debugging the
** tktnew_template in the ticket configuration.  /debug_tktnew works
** just like /tktnew except that it does not really save the new ticket
** when you press submit - it just prints the ticket artifact at the
** top of the screen.
*/







|







 







|







89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
...
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
**
** Only load those fields which do not already exist as
** variables.
**
** Fields of the TICKET table that begin with "private_" are
** expanded using the db_reveal() function.  If g.perm.RdAddr is
** true, then the db_reveal() function will decode the content
** using the CONCEALED table so that the content legible.
** Otherwise, db_reveal() is a no-op and the content remains
** obscured.
*/
static void initializeVariablesFromDb(void){
  const char *zName;
  Stmt q;
  int i, n, size, j;
................................................................................
}


/*
** WEBPAGE: tktnew
** WEBPAGE: debug_tktnew
**
** Enter a new ticket.  The tktnew_template script in the ticket
** configuration is used.  The /tktnew page is the official ticket
** entry page.  The /debug_tktnew page is used for debugging the
** tktnew_template in the ticket configuration.  /debug_tktnew works
** just like /tktnew except that it does not really save the new ticket
** when you press submit - it just prints the ticket artifact at the
** top of the screen.
*/

Changes to src/tktsetup.c.

94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
** Common implementation for the ticket setup editor pages.
*/
static void tktsetup_generic(
  const char *zTitle,           /* Page title */
  const char *zDbField,         /* Configuration field being edited */
  const char *zDfltValue,       /* Default text value */
  const char *zDesc,            /* Description of this field */
  char *(*xText)(const char*),  /* Validitity test or NULL */
  void (*xRebuild)(void),       /* Run after successulf update */
  int height                    /* Height of the edit box */
){
  const char *z;
  int isSubmit;
  
  login_check_credentials();
  if( !g.perm.Setup ){







|
|







94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
** Common implementation for the ticket setup editor pages.
*/
static void tktsetup_generic(
  const char *zTitle,           /* Page title */
  const char *zDbField,         /* Configuration field being edited */
  const char *zDfltValue,       /* Default text value */
  const char *zDesc,            /* Description of this field */
  char *(*xText)(const char*),  /* Validity test or NULL */
  void (*xRebuild)(void),       /* Run after successful update */
  int height                    /* Height of the edit box */
){
  const char *z;
  int isSubmit;
  
  login_check_credentials();
  if( !g.perm.Setup ){

Changes to src/update.c.

104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
...
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
  int debugFlag;        /* --debug option */
  int setmtimeFlag;     /* --setmtime.  Set mtimes on files */
  int nChng;            /* Number of file renames */
  int *aChng;           /* Array of file renames */
  int i;                /* Loop counter */
  int nConflict = 0;    /* Number of merge conflicts */
  int nOverwrite = 0;   /* Number of unmanaged files overwritten */
  int nUpdate = 0;      /* Number of chagnes of any kind */
  Stmt mtimeXfer;       /* Statment to transfer mtimes */

  if( !internalUpdate ){
    undo_capture_command_line();
    url_proxy_options();
  }
  latestFlag = find_option("latest",0, 0)!=0;
  nochangeFlag = find_option("nochange","n",0)!=0;
................................................................................
      }else if( !is_a_version(tid) ){
        fossil_fatal("no such version: %s", g.argv[2]);
      }
    }
  }
  
  /* If no VERSION is specified on the command-line, then look for a
  ** descendent of the current version.  If there are multiple descendents,
  ** look for one from the same branch as the current version.  If there
  ** are still multiple descendents, show them all and refuse to update
  ** until the user selects one.
  */
  if( tid==0 ){
    int closeCode = 1;
    compute_leaves(vid, closeCode);
    if( !db_exists("SELECT 1 FROM leaves") ){
      closeCode = 0;







|
|







 







|

|







104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
...
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
  int debugFlag;        /* --debug option */
  int setmtimeFlag;     /* --setmtime.  Set mtimes on files */
  int nChng;            /* Number of file renames */
  int *aChng;           /* Array of file renames */
  int i;                /* Loop counter */
  int nConflict = 0;    /* Number of merge conflicts */
  int nOverwrite = 0;   /* Number of unmanaged files overwritten */
  int nUpdate = 0;      /* Number of changes of any kind */
  Stmt mtimeXfer;       /* Statement to transfer mtimes */

  if( !internalUpdate ){
    undo_capture_command_line();
    url_proxy_options();
  }
  latestFlag = find_option("latest",0, 0)!=0;
  nochangeFlag = find_option("nochange","n",0)!=0;
................................................................................
      }else if( !is_a_version(tid) ){
        fossil_fatal("no such version: %s", g.argv[2]);
      }
    }
  }
  
  /* If no VERSION is specified on the command-line, then look for a
  ** descendent of the current version.  If there are multiple descendants,
  ** look for one from the same branch as the current version.  If there
  ** are still multiple descendants, show them all and refuse to update
  ** until the user selects one.
  */
  if( tid==0 ){
    int closeCode = 1;
    compute_leaves(vid, closeCode);
    if( !db_exists("SELECT 1 FROM leaves") ){
      closeCode = 0;

Changes to src/verify.c.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains code used to help verify the integrity of the
** the repository.
**
** This file primarily implements the verify_before_commit() interface.
** Any function can call verify_before_commit() with a record id (RID)
** as an argument.  Then before the next change to the database commits,
** this routine will reach in and check that the record can be extracted
** correctly from the BLOB table.







|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains code used to help verify the integrity of
** the repository.
**
** This file primarily implements the verify_before_commit() interface.
** Any function can call verify_before_commit() with a record id (RID)
** as an argument.  Then before the next change to the database commits,
** this routine will reach in and check that the record can be extracted
** correctly from the BLOB table.

Changes to src/wiki.c.

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
...
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894

/*
** Return true if the input string is a well-formed wiki page name.
**
** Well-formed wiki page names do not begin or end with whitespace,
** and do not contain tabs or other control characters and do not
** contain more than a single space character in a row.  Well-formed
** names must be between 3 and 100 chracters in length, inclusive.
*/
int wiki_name_is_wellformed(const unsigned char *z){
  int i;
  if( z[0]<=0x20 ){
    return 0;
  }
  for(i=1; z[i]; i++){
................................................................................
**
**        Create a new wiki page with initial content taken from
**        FILE or from standard input.
**
**     %fossil wiki list
**
**        Lists all wiki entries, one per line, ordered
**        case-insentively by name.
**
*/
void wiki_cmd(void){
  int n;
  db_find_and_open_repository(0, 0);
  if( g.argc<3 ){
    goto wiki_cmd_usage;







|







 







|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
...
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894

/*
** Return true if the input string is a well-formed wiki page name.
**
** Well-formed wiki page names do not begin or end with whitespace,
** and do not contain tabs or other control characters and do not
** contain more than a single space character in a row.  Well-formed
** names must be between 3 and 100 characters in length, inclusive.
*/
int wiki_name_is_wellformed(const unsigned char *z){
  int i;
  if( z[0]<=0x20 ){
    return 0;
  }
  for(i=1; z[i]; i++){
................................................................................
**
**        Create a new wiki page with initial content taken from
**        FILE or from standard input.
**
**     %fossil wiki list
**
**        Lists all wiki entries, one per line, ordered
**        case-insensitively by name.
**
*/
void wiki_cmd(void){
  int n;
  db_find_and_open_repository(0, 0);
  if( g.argc<3 ){
    goto wiki_cmd_usage;

Changes to src/wikiformat.c.

1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
....
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
  }
  db_reset(&q);
  return rc;
}

/*
** Resolve a hyperlink.  The zTarget argument is the content of the [...]
** in the wiki.  Append to the output string whatever text is approprate
** for opening the hyperlink.  Write into zClose[0...nClose-1] text that will
** close the markup.
**
** Actually, this routine might or might not append the hyperlink, depending
** on current rendering rules: specifically does the current user have
** "History" permission.
**
................................................................................
**
**    [#fragment]
**
**    [2010-02-27 07:13]
*/
static void openHyperlink(
  Renderer *p,            /* Rendering context */
  const char *zTarget,    /* Hyperlink traget; text within [...] */
  char *zClose,           /* Write hyperlink closing text here */
  int nClose,             /* Bytes available in zClose[] */
  const char *zOrig       /* Complete document text */
){
  const char *zTerm = "</a>";
  assert( nClose>=20 );








|







 







|







1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
....
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
  }
  db_reset(&q);
  return rc;
}

/*
** Resolve a hyperlink.  The zTarget argument is the content of the [...]
** in the wiki.  Append to the output string whatever text is appropriate
** for opening the hyperlink.  Write into zClose[0...nClose-1] text that will
** close the markup.
**
** Actually, this routine might or might not append the hyperlink, depending
** on current rendering rules: specifically does the current user have
** "History" permission.
**
................................................................................
**
**    [#fragment]
**
**    [2010-02-27 07:13]
*/
static void openHyperlink(
  Renderer *p,            /* Rendering context */
  const char *zTarget,    /* Hyperlink target; text within [...] */
  char *zClose,           /* Write hyperlink closing text here */
  int nClose,             /* Bytes available in zClose[] */
  const char *zOrig       /* Complete document text */
){
  const char *zTerm = "</a>";
  assert( nClose>=20 );

Changes to src/winhttp.c.

269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
*/
static char *win32_get_last_errmsg(void){
  DWORD nMsg;
  DWORD nErr = GetLastError();
  LPWSTR tmp = NULL;
  char *zMsg = NULL;

  /* Try first to get the error text in english. */
  nMsg = FormatMessageW(
           FORMAT_MESSAGE_ALLOCATE_BUFFER |
           FORMAT_MESSAGE_FROM_SYSTEM     |
           FORMAT_MESSAGE_IGNORE_INSERTS,
           NULL,
           nErr,
           MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),







|







269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
*/
static char *win32_get_last_errmsg(void){
  DWORD nMsg;
  DWORD nErr = GetLastError();
  LPWSTR tmp = NULL;
  char *zMsg = NULL;

  /* Try first to get the error text in English. */
  nMsg = FormatMessageW(
           FORMAT_MESSAGE_ALLOCATE_BUFFER |
           FORMAT_MESSAGE_FROM_SYSTEM     |
           FORMAT_MESSAGE_IGNORE_INSERTS,
           NULL,
           nErr,
           MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),

Changes to src/xfer.c.

546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
**
**        login LOGIN NONCE SIGNATURE
**
** The NONCE is the SHA1 hash of the remainder of the input.  
** SIGNATURE is the SHA1 checksum of the NONCE concatenated 
** with the users password.
**
** The parameters to this routine are ephermeral blobs holding the
** LOGIN, NONCE and SIGNATURE.
**
** This routine attempts to locate the user and verify the signature.
** If everything checks out, the USER.CAP column for the USER table
** is consulted to set privileges in the global g variable.
**
** If anything fails to check out, no changes are made to privileges.







|







546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
**
**        login LOGIN NONCE SIGNATURE
**
** The NONCE is the SHA1 hash of the remainder of the input.  
** SIGNATURE is the SHA1 checksum of the NONCE concatenated 
** with the users password.
**
** The parameters to this routine are ephemeral blobs holding the
** LOGIN, NONCE and SIGNATURE.
**
** This routine attempts to locate the user and verify the signature.
** If everything checks out, the USER.CAP column for the USER table
** is consulted to set privileges in the global g variable.
**
** If anything fails to check out, no changes are made to privileges.

Changes to src/xfersetup.c.

46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
** Common implementation for the transfer setup editor pages.
*/
static void xfersetup_generic(
  const char *zTitle,           /* Page title */
  const char *zDbField,         /* Configuration field being edited */
  const char *zDfltValue,       /* Default text value */
  const char *zDesc,            /* Description of this field */
  char *(*xText)(const char*),  /* Validitity test or NULL */
  void (*xRebuild)(void),       /* Run after successulf update */
  int height                    /* Height of the edit box */
){
  const char *z;
  int isSubmit;

  login_check_credentials();
  if( !g.perm.Setup ){







|
|







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
** Common implementation for the transfer setup editor pages.
*/
static void xfersetup_generic(
  const char *zTitle,           /* Page title */
  const char *zDbField,         /* Configuration field being edited */
  const char *zDfltValue,       /* Default text value */
  const char *zDesc,            /* Description of this field */
  char *(*xText)(const char*),  /* Validity test or NULL */
  void (*xRebuild)(void),       /* Run after successful update */
  int height                    /* Height of the edit box */
){
  const char *z;
  int isSubmit;

  login_check_credentials();
  if( !g.perm.Setup ){