Fossil

Check-in [06afb702]
Login

Check-in [06afb702]

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

Overview
Comment:Match the COMMAND and WEBPAGE names with _cmd and _page functions; forumpost/045bffda68
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | api-cleanup
Files: files | file ages | folders
SHA3-256: 06afb7022f6f4553d118aa121c69de556f81a0c2e07dca5d1b9b9770fea13cd4
User & Date: ashepilko 2020-04-05 23:45:50
Context
2020-04-11
22:35
Merged from trunk ... (Closed-Leaf check-in: 2f24675a user: ashepilko tags: api-cleanup)
2020-04-05
23:45
Match the COMMAND and WEBPAGE names with _cmd and _page functions; forumpost/045bffda68 ... (check-in: 06afb702 user: ashepilko tags: api-cleanup)
19:44
Fixes to search. (1) Keep forum search up-to-date. (2) Do not add items to search if they are pending moderation. ... (check-in: 5e28febf user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/add.c.
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/*
** COMMAND: test-reserved-names
**
** Usage: %fossil test-reserved-names [-omitrepo]
**
** Show all reserved filenames for the current check-out.
*/
void test_reserved_names(void){
  int i;
  const char *z;
  int omitRepo = find_option("omitrepo",0,0)!=0;

  /* We should be done with options.. */
  verify_all_options();








|







148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/*
** COMMAND: test-reserved-names
**
** Usage: %fossil test-reserved-names [-omitrepo]
**
** Show all reserved filenames for the current check-out.
*/
void test_reserved_names_cmd(void){
  int i;
  const char *z;
  int omitRepo = find_option("omitrepo",0,0)!=0;

  /* We should be done with options.. */
  verify_all_options();

Changes to src/alerts.c.
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
**
** Logic for email notification, also known as "alerts".
**
** Are you looking for the code that reads and writes the internet
** email protocol?  That is not here.  See the "smtp.c" file instead.
** Yes, the choice of source code filenames is not the greatest, but
** it is not so bad that changing them seems justified.
*/ 
#include "config.h"
#include "alerts.h"
#include <assert.h>
#include <time.h>

/*
** Maximum size of the subscriberCode blob, in bytes







|







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
**
** Logic for email notification, also known as "alerts".
**
** Are you looking for the code that reads and writes the internet
** email protocol?  That is not here.  See the "smtp.c" file instead.
** Yes, the choice of source code filenames is not the greatest, but
** it is not so bad that changing them seems justified.
*/
#include "config.h"
#include "alerts.h"
#include <assert.h>
#include <time.h>

/*
** Maximum size of the subscriberCode blob, in bytes
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211

/*
** WEBPAGE: setup_notification
**
** Administrative page for configuring and controlling email notification.
** Normally accessible via the /Admin/Notification menu.
*/
void setup_notification(void){
  static const char *const azSendMethods[] = {
    "off",   "Disabled",
    "pipe",  "Pipe to a command",
    "db",    "Store in a database",
    "dir",   "Store in a directory",
    "relay", "SMTP relay"
  };







|







197
198
199
200
201
202
203
204
205
206
207
208
209
210
211

/*
** WEBPAGE: setup_notification
**
** Administrative page for configuring and controlling email notification.
** Normally accessible via the /Admin/Notification menu.
*/
void setup_notification_page(void){
  static const char *const azSendMethods[] = {
    "off",   "Disabled",
    "pipe",  "Pipe to a command",
    "db",    "Store in a database",
    "dir",   "Store in a directory",
    "relay", "SMTP relay"
  };
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
**
** Usage: %fossil test-mailbox-hashname HUMAN-NAME ...
**
** Return the mailbox hash name corresponding to each human-readable
** name on the command line.  This is a test interface for the
** alert_mailbox_name() function.
*/
void alert_test_mailbox_hashname(void){
  int i;
  for(i=2; i<g.argc; i++){
    fossil_print("%30s: %s\n", g.argv[i], alert_mailbox_name(g.argv[i]));
  }
}

/*







|







744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
**
** Usage: %fossil test-mailbox-hashname HUMAN-NAME ...
**
** Return the mailbox hash name corresponding to each human-readable
** name on the command line.  This is a test interface for the
** alert_mailbox_name() function.
*/
void test_mailbox_hashname_cmd(void){
  int i;
  for(i=2; i<g.argc; i++){
    fossil_print("%30s: %s\n", g.argv[i], alert_mailbox_name(g.argv[i]));
  }
}

/*
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
**                              --body FILENAME
**                              --smtp-trace
**                              --stdout
**                              --subject|-S SUBJECT
**
**    unsubscribe EMAIL       Remove a single subscriber with the given EMAIL.
*/
void alert_cmd(void){
  const char *zCmd;
  int nCmd;
  db_find_and_open_repository(0, 0);
  alert_schema(0);
  zCmd = g.argc>=3 ? g.argv[2] : "x";
  nCmd = (int)strlen(zCmd);
  if( strncmp(zCmd, "pending", nCmd)==0 ){







|







1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
**                              --body FILENAME
**                              --smtp-trace
**                              --stdout
**                              --subject|-S SUBJECT
**
**    unsubscribe EMAIL       Remove a single subscriber with the given EMAIL.
*/
void alerts_cmd(void){
  const char *zCmd;
  int nCmd;
  db_find_and_open_repository(0, 0);
  alert_schema(0);
  zCmd = g.argc>=3 ? g.argv[2] : "x";
  nCmd = (int)strlen(zCmd);
  if( strncmp(zCmd, "pending", nCmd)==0 ){
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
** WEBPAGE: alerts
**
** Edit email alert and notification settings.
**
** The subscriber is identified in either of two ways:
**
**    (1)  The name= query parameter contains the subscriberCode.
**         
**    (2)  The user is logged into an account other than "nobody" or
**         "anonymous".  In that case the notification settings
**         associated with that account can be edited without needing
**         to know the subscriber code.
*/
void alert_page(void){
  const char *zName = P("name");
  Stmt q;
  int sa, sc, sf, st, sw, sx;
  int sdigest = 0, sdonotcall = 0, sverified = 0;
  int isLogin;         /* Logged in as an individual */
  const char *ssub = 0;
  const char *semail = 0;







|





|







1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
** WEBPAGE: alerts
**
** Edit email alert and notification settings.
**
** The subscriber is identified in either of two ways:
**
**    (1)  The name= query parameter contains the subscriberCode.
**
**    (2)  The user is logged into an account other than "nobody" or
**         "anonymous".  In that case the notification settings
**         associated with that account can be edited without needing
**         to know the subscriber code.
*/
void alerts_page(void){
  const char *zName = P("name");
  Stmt q;
  int sa, sc, sf, st, sw, sx;
  int sdigest = 0, sdonotcall = 0, sverified = 0;
  int isLogin;         /* Logged in as an individual */
  const char *ssub = 0;
  const char *semail = 0;
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
**
** This page, accessible to administrators only,
** shows a list of subscriber email addresses.
** Clicking on an email takes one to the /alerts page
** for that email where the delivery settings can be
** modified.
*/
void subscriber_list_page(void){
  Blob sql;
  Stmt q;
  sqlite3_int64 iNow;
  int nTotal;
  int nPending;
  int nDel = 0;
  if( alert_webpages_disabled() ) return;







|







1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
**
** This page, accessible to administrators only,
** shows a list of subscriber email addresses.
** Clicking on an email takes one to the /alerts page
** for that email where the delivery settings can be
** modified.
*/
void subscribers_page(void){
  Blob sql;
  Stmt q;
  sqlite3_int64 iNow;
  int nTotal;
  int nPending;
  int nDel = 0;
  if( alert_webpages_disabled() ) return;
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
*/
void alert_footer(Blob *pOut){
  blob_appendf(pOut, "\n-- \nTo unsubscribe: %s/unsubscribe\n",
     db_get("email-url","http://localhost:8080"));
}

/*
** COMMAND:  test-alert
**
** Usage: %fossil test-alert EVENTID ...
**
** Generate the text of an email alert for all of the EVENTIDs
** listed on the command-line.  Or if no events are listed on the
** command line, generate text for all events named in the
** pending_alert table.







|







2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
*/
void alert_footer(Blob *pOut){
  blob_appendf(pOut, "\n-- \nTo unsubscribe: %s/unsubscribe\n",
     db_get("email-url","http://localhost:8080"));
}

/*
** COMMAND: test-alert
**
** Usage: %fossil test-alert EVENTID ...
**
** Generate the text of an email alert for all of the EVENTIDs
** listed on the command-line.  Or if no events are listed on the
** command line, generate text for all events named in the
** pending_alert table.
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
  alert_footer(&out);
  fossil_print("%s", blob_str(&out));
  blob_reset(&out);
  db_end_transaction(0);
}

/*
** COMMAND:  test-add-alerts
**
** Usage: %fossil test-add-alerts [OPTIONS] EVENTID ...
**
** Add one or more events to the pending_alert queue.  Use this
** command during testing to force email notifications for specific
** events.
**







|







2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
  alert_footer(&out);
  fossil_print("%s", blob_str(&out));
  blob_reset(&out);
  db_end_transaction(0);
}

/*
** COMMAND: test-add-alerts
**
** Usage: %fossil test-add-alerts [OPTIONS] EVENTID ...
**
** Add one or more events to the pending_alert queue.  Use this
** command during testing to force email notifications for specific
** events.
**
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
**
**    --debug             Like --backoffice, but add the SENDALERT_STDOUT
**                        so that emails are printed to standard output
**                        rather than being sent.
**
**    --digest            Process emails using SENDALERT_DIGEST
*/
void test_add_alert_cmd(void){
  int i;
  int doAuto = find_option("backoffice",0,0)!=0;
  unsigned mFlags = 0;
  if( find_option("debug",0,0)!=0 ){
    doAuto = 1;
    mFlags = SENDALERT_STDOUT;
  }







|







2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
**
**    --debug             Like --backoffice, but add the SENDALERT_STDOUT
**                        so that emails are printed to standard output
**                        rather than being sent.
**
**    --digest            Process emails using SENDALERT_DIGEST
*/
void test_add_alerts_cmd(void){
  int i;
  int doAuto = find_option("backoffice",0,0)!=0;
  unsigned mFlags = 0;
  if( find_option("debug",0,0)!=0 ){
    doAuto = 1;
    mFlags = SENDALERT_STDOUT;
  }
Changes to src/allrepo.c.
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
  db_open_config(1, 0);
  blob_zero(&extra);
  zCmd = g.argv[2];
  if( !login_is_nobody() ) blob_appendf(&extra, " -U %s", g.zLogin);
  if( strncmp(zCmd, "ui", n)==0 || strncmp(zCmd, "server", n)==0 ){
    g.argv[1] = g.argv[2];
    g.argv[2] = "/";
    cmd_webserver();
    return;
  }
  if( strncmp(zCmd, "list", n)==0 || strncmp(zCmd,"ls",n)==0 ){
    zCmd = "list";
    useCheckouts = find_option("ckout","c",0)!=0;
  }else if( strncmp(zCmd, "clean", n)==0 ){
    zCmd = "clean --chdir";







|







194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
  db_open_config(1, 0);
  blob_zero(&extra);
  zCmd = g.argv[2];
  if( !login_is_nobody() ) blob_appendf(&extra, " -U %s", g.zLogin);
  if( strncmp(zCmd, "ui", n)==0 || strncmp(zCmd, "server", n)==0 ){
    g.argv[1] = g.argv[2];
    g.argv[2] = "/";
    webserver_cmd();
    return;
  }
  if( strncmp(zCmd, "list", n)==0 || strncmp(zCmd,"ls",n)==0 ){
    zCmd = "list";
    useCheckouts = find_option("ckout","c",0)!=0;
  }else if( strncmp(zCmd, "clean", n)==0 ){
    zCmd = "clean --chdir";
Changes to src/attach.c.
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  db_finalize(&q);
  @ </ol>
  style_footer();
  return;
}

/*
** WEBPAGE: attachdownload
** WEBPAGE: attachimage
** WEBPAGE: attachview
**
** Download or display an attachment.
** Query parameters:
**
**    tkt=TICKETUUID
**    page=WIKIPAGE
**    technote=TECHNOTEUUID







|
|
|







145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  db_finalize(&q);
  @ </ol>
  style_footer();
  return;
}

/*
** WEBPAGE: attachview
** WEBPAGE: attachdownload
** WEBPAGE: attachimage
**
** Download or display an attachment.
** Query parameters:
**
**    tkt=TICKETUUID
**    page=WIKIPAGE
**    technote=TECHNOTEUUID
Changes to src/backoffice.c.
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
**
** Usage: %fossil [--sleep N] PROCESS-ID ...
**
** Show the current process id, and also tell whether or not all other
** processes IDs on the command line are running or not.  If the --sleep N
** option is provide, then sleep for N seconds before exiting.
*/
void test_process_id_command(void){
  const char *zSleep = find_option("sleep",0,1);
  int i;
  verify_all_options();
  fossil_print("ProcessID for this process: %lld\n", backofficeProcessId());
  if( zSleep ) sqlite3_sleep(1000*atoi(zSleep));
  for(i=2; i<g.argc; i++){
    sqlite3_uint64 x = (sqlite3_uint64)atoi(g.argv[i]);







|







314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
**
** Usage: %fossil [--sleep N] PROCESS-ID ...
**
** Show the current process id, and also tell whether or not all other
** processes IDs on the command line are running or not.  If the --sleep N
** option is provide, then sleep for N seconds before exiting.
*/
void test_process_id_cmd(void){
  const char *zSleep = find_option("sleep",0,1);
  int i;
  verify_all_options();
  fossil_print("ProcessID for this process: %lld\n", backofficeProcessId());
  if( zSleep ) sqlite3_sleep(1000*atoi(zSleep));
  for(i=2; i<g.argc; i++){
    sqlite3_uint64 x = (sqlite3_uint64)atoi(g.argv[i]);
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
** COMMAND: test-backoffice-lease
**
** Usage: %fossil test-backoffice-lease
**
** Print out information about the backoffice "lease" entry in the
** config table that controls whether or not backoffice should run.
*/
void test_backoffice_lease(void){
  sqlite3_int64 tmNow = time(0);
  Lease x;
  const char *zLease;
  db_find_and_open_repository(0,0);
  verify_all_options();
  zLease = db_get("backoffice","");
  fossil_print("now:        %lld\n", tmNow);







|







336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
** COMMAND: test-backoffice-lease
**
** Usage: %fossil test-backoffice-lease
**
** Print out information about the backoffice "lease" entry in the
** config table that controls whether or not backoffice should run.
*/
void test_backoffice_lease_cmd(void){
  sqlite3_int64 tmNow = time(0);
  Lease x;
  const char *zLease;
  db_find_and_open_repository(0,0);
  verify_all_options();
  zLease = db_get("backoffice","");
  fossil_print("now:        %lld\n", tmNow);
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
**
**    --poll N                Repeat backoffice calls for repositories that
**                            change in appoximately N-second intervals.
**                            N less than 1 turns polling off (the default).
**
**    --trace                 Enable debugging output on stderr
*/
void backoffice_command(void){
  int nPoll;
  const char *zPoll;
  int bDebug = 0;
  unsigned int nCmd = 0;
  if( find_option("trace",0,0)!=0 ) g.fAnyTrace = 1;
  if( find_option("nodelay",0,0)!=0 ) backofficeNoDelay = 1;
  zPoll = find_option("poll",0,1);







|







565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
**
**    --poll N                Repeat backoffice calls for repositories that
**                            change in appoximately N-second intervals.
**                            N less than 1 turns polling off (the default).
**
**    --trace                 Enable debugging output on stderr
*/
void backoffice_cmd(void){
  int nPoll;
  const char *zPoll;
  int bDebug = 0;
  unsigned int nCmd = 0;
  if( find_option("trace",0,0)!=0 ) g.fAnyTrace = 1;
  if( find_option("nodelay",0,0)!=0 ) backofficeNoDelay = 1;
  zPoll = find_option("poll",0,1);
Changes to src/bisect.c.
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
    newArgv[0] = g.argv[0];
    newArgv[1] = "ui";
    newArgv[2] = "--page";
    newArgv[3] = "timeline?bisect";
    newArgv[4] = 0;
    g.argv = newArgv;
    g.argc = 4;
    cmd_webserver();
  }else if( strncmp(zCmd, "vlist", n)==0
         || strncmp(zCmd, "ls", n)==0
         || strncmp(zCmd, "status", n)==0
  ){
    int fAll = find_option("all", "a", 0)!=0;
    bisect_list(!fAll);
  }else if( !foundCmd ){







|







508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
    newArgv[0] = g.argv[0];
    newArgv[1] = "ui";
    newArgv[2] = "--page";
    newArgv[3] = "timeline?bisect";
    newArgv[4] = 0;
    g.argv = newArgv;
    g.argc = 4;
    webserver_cmd();
  }else if( strncmp(zCmd, "vlist", n)==0
         || strncmp(zCmd, "ls", n)==0
         || strncmp(zCmd, "status", n)==0
  ){
    int fAll = find_option("all", "a", 0)!=0;
    bisect_list(!fAll);
  }else if( !foundCmd ){
Changes to src/blob.c.
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142

/*
** COMMAND: test-isspace
**
** Verify that the fossil_isspace() routine is working correctly by
** testing it on all possible inputs.
*/
void isspace_cmd(void){
  int i;
  for(i=0; i<=255; i++){
    if( i==' ' || i=='\n' || i=='\t' || i=='\v'
        || i=='\f' || i=='\r' ){
      assert( fossil_isspace((char)i) );
    }else{
      assert( !fossil_isspace((char)i) );







|







128
129
130
131
132
133
134
135
136
137
138
139
140
141
142

/*
** COMMAND: test-isspace
**
** Verify that the fossil_isspace() routine is working correctly by
** testing it on all possible inputs.
*/
void test_isspace_cmd(void){
  int i;
  for(i=0; i<=255; i++){
    if( i==' ' || i=='\n' || i=='\t' || i=='\v'
        || i=='\f' || i=='\r' ){
      assert( fossil_isspace((char)i) );
    }else{
      assert( !fossil_isspace((char)i) );
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
**
** Usage: %fossil test-compress INPUTFILE OUTPUTFILE
**
** Run compression on INPUTFILE and write the result into OUTPUTFILE.
**
** This is used to test and debug the blob_compress() routine.
*/
void compress_cmd(void){
  Blob f;
  if( g.argc!=4 ) usage("INPUTFILE OUTPUTFILE");
  blob_read_from_file(&f, g.argv[2], ExtFILE);
  blob_compress(&f, &f);
  blob_write_to_file(&f, g.argv[3]);
}








|







1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
**
** Usage: %fossil test-compress INPUTFILE OUTPUTFILE
**
** Run compression on INPUTFILE and write the result into OUTPUTFILE.
**
** This is used to test and debug the blob_compress() routine.
*/
void test_compress_cmd(void){
  Blob f;
  if( g.argc!=4 ) usage("INPUTFILE OUTPUTFILE");
  blob_read_from_file(&f, g.argv[2], ExtFILE);
  blob_compress(&f, &f);
  blob_write_to_file(&f, g.argv[3]);
}

1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
** Usage: %fossil test-compress-2 IN1 IN2 OUT
**
** Read files IN1 and IN2, concatenate the content, compress the
** content, then write results into OUT.
**
** This is used to test and debug the blob_compress2() routine.
*/
void compress2_cmd(void){
  Blob f1, f2;
  if( g.argc!=5 ) usage("INPUTFILE1 INPUTFILE2 OUTPUTFILE");
  blob_read_from_file(&f1, g.argv[2], ExtFILE);
  blob_read_from_file(&f2, g.argv[3], ExtFILE);
  blob_compress2(&f1, &f2, &f1);
  blob_write_to_file(&f1, g.argv[4]);
}







|







1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
** Usage: %fossil test-compress-2 IN1 IN2 OUT
**
** Read files IN1 and IN2, concatenate the content, compress the
** content, then write results into OUT.
**
** This is used to test and debug the blob_compress2() routine.
*/
void test_compress2_cmd(void){
  Blob f1, f2;
  if( g.argc!=5 ) usage("INPUTFILE1 INPUTFILE2 OUTPUTFILE");
  blob_read_from_file(&f1, g.argv[2], ExtFILE);
  blob_read_from_file(&f2, g.argv[3], ExtFILE);
  blob_compress2(&f1, &f2, &f1);
  blob_write_to_file(&f1, g.argv[4]);
}
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
**
** Usage: %fossil test-uncompress IN OUT
**
** Read the content of file IN, uncompress that content, and write the
** result into OUT.  This command is intended for testing of the
** blob_compress() function.
*/
void uncompress_cmd(void){
  Blob f;
  if( g.argc!=4 ) usage("INPUTFILE OUTPUTFILE");
  blob_read_from_file(&f, g.argv[2], ExtFILE);
  blob_uncompress(&f, &f);
  blob_write_to_file(&f, g.argv[3]);
}

/*
** COMMAND: test-cycle-compress
**
** Compress and uncompress each file named on the command line.
** Verify that the original content is recovered.
*/
void test_cycle_compress(void){
  int i;
  Blob b1, b2, b3;
  for(i=2; i<g.argc; i++){
    blob_read_from_file(&b1, g.argv[i], ExtFILE);
    blob_compress(&b1, &b2);
    blob_uncompress(&b2, &b3);
    if( blob_compare(&b1, &b3) ){







|













|







1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
**
** Usage: %fossil test-uncompress IN OUT
**
** Read the content of file IN, uncompress that content, and write the
** result into OUT.  This command is intended for testing of the
** blob_compress() function.
*/
void test_uncompress_cmd(void){
  Blob f;
  if( g.argc!=4 ) usage("INPUTFILE OUTPUTFILE");
  blob_read_from_file(&f, g.argv[2], ExtFILE);
  blob_uncompress(&f, &f);
  blob_write_to_file(&f, g.argv[3]);
}

/*
** COMMAND: test-cycle-compress
**
** Compress and uncompress each file named on the command line.
** Verify that the original content is recovered.
*/
void test_cycle_compress_cmd(void){
  int i;
  Blob b1, b2, b3;
  for(i=2; i<g.argc; i++){
    blob_read_from_file(&b1, g.argv[i], ExtFILE);
    blob_compress(&b1, &b2);
    blob_uncompress(&b2, &b3);
    if( blob_compare(&b1, &b3) ){
Changes to src/browse.c.
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
**
**    name=PATH        Directory to display.  Optional.  Top-level if missing
**    ci=LABEL         Show only files in this check-in.  Optional.
**    type=TYPE        TYPE=flat: use this display
**                     TYPE=tree: use the /tree display instead
**    noreadme         Do not attempt to display the README file.
*/
void page_dir(void){
  char *zD = fossil_strdup(P("name"));
  int nD = zD ? strlen(zD)+1 : 0;
  int mxLen;
  char *zPrefix;
  Stmt q;
  const char *zCI = P("ci");
  int rid = 0;
  char *zUuid = 0;
  Blob dirname;
  Manifest *pM = 0;
  const char *zSubdirLink;
  int linkTrunk = 1;
  int linkTip = 1;
  HQuery sURI;

  if( strcmp(PD("type","flat"),"tree")==0 ){ page_tree(); return; }
  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
  style_header("File List");
  style_adunit_config(ADUNIT_RIGHT_OK);
  sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
                          pathelementFunc, 0, 0);







|















|







116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
**
**    name=PATH        Directory to display.  Optional.  Top-level if missing
**    ci=LABEL         Show only files in this check-in.  Optional.
**    type=TYPE        TYPE=flat: use this display
**                     TYPE=tree: use the /tree display instead
**    noreadme         Do not attempt to display the README file.
*/
void dir_page(void){
  char *zD = fossil_strdup(P("name"));
  int nD = zD ? strlen(zD)+1 : 0;
  int mxLen;
  char *zPrefix;
  Stmt q;
  const char *zCI = P("ci");
  int rid = 0;
  char *zUuid = 0;
  Blob dirname;
  Manifest *pM = 0;
  const char *zSubdirLink;
  int linkTrunk = 1;
  int linkTip = 1;
  HQuery sURI;

  if( strcmp(PD("type","flat"),"tree")==0 ){ tree_page(); return; }
  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
  style_header("File List");
  style_adunit_config(ADUNIT_RIGHT_OK);
  sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
                          pathelementFunc, 0, 0);
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
**    name=PATH        Directory to display.  Optional
**    ci=LABEL         Show only files in this check-in.  Optional.
**    re=REGEXP        Show only files matching REGEXP.  Optional.
**    expand           Begin with the tree fully expanded.
**    nofiles          Show directories (folders) only.  Omit files.
**    mtime            Order directory elements by decreasing mtime
*/
void page_tree(void){
  char *zD = fossil_strdup(P("name"));
  int nD = zD ? strlen(zD)+1 : 0;
  const char *zCI = P("ci");
  int rid = 0;
  char *zUuid = 0;
  Blob dirname;
  Manifest *pM = 0;







|







585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
**    name=PATH        Directory to display.  Optional
**    ci=LABEL         Show only files in this check-in.  Optional.
**    re=REGEXP        Show only files matching REGEXP.  Optional.
**    expand           Begin with the tree fully expanded.
**    nofiles          Show directories (folders) only.  Omit files.
**    mtime            Order directory elements by decreasing mtime
*/
void tree_page(void){
  char *zD = fossil_strdup(P("name"));
  int nD = zD ? strlen(zD)+1 : 0;
  const char *zCI = P("ci");
  int rid = 0;
  char *zUuid = 0;
  Blob dirname;
  Manifest *pM = 0;
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
  FileTree sTree;          /* The complete tree of files */
  HQuery sURI;             /* Hyperlink */
  int startExpanded;       /* True to start out with the tree expanded */
  int showDirOnly;         /* Show directories only.  Omit files */
  int nDir = 0;            /* Number of directories. Used for ID attributes */
  char *zProjectName = db_get("project-name", 0);

  if( strcmp(PD("type","flat"),"flat")==0 ){ page_dir(); return; }
  memset(&sTree, 0, sizeof(sTree));
  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
  sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
                          pathelementFunc, 0, 0);
  url_initialize(&sURI, "tree");







|







611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
  FileTree sTree;          /* The complete tree of files */
  HQuery sURI;             /* Hyperlink */
  int startExpanded;       /* True to start out with the tree expanded */
  int showDirOnly;         /* Show directories only.  Omit files */
  int nDir = 0;            /* Number of directories. Used for ID attributes */
  char *zProjectName = db_get("project-name", 0);

  if( strcmp(PD("type","flat"),"flat")==0 ){ dir_page(); return; }
  memset(&sTree, 0, sizeof(sTree));
  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
  sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
                          pathelementFunc, 0, 0);
  url_initialize(&sURI, "tree");
Changes to src/builtin.c.
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
}

/*
** COMMAND: test-builtin-list
**
** List the names and sizes of all built-in resources.
*/
void test_builtin_list(void){
  int i;
  for(i=0; i<count(aBuiltinFiles); i++){
    fossil_print("%-30s %6d\n", aBuiltinFiles[i].zName,aBuiltinFiles[i].nByte);
  }
}

/*
** WEBPAGE: test-builtin-files
**
** Show all built-in text files.
*/
void test_builtin_list_page(void){
  int i;
  style_header("Built-in Text Files");
  @ <ul>
  for(i=0; i<count(aBuiltinFiles); i++){
    const char *z = aBuiltinFiles[i].zName;
    @ <li>%z(href("%R/builtin?name=%T&id=%S",z,MANIFEST_UUID))%h(z)</a>
  }
  @ </ul>
  style_footer();
}

/*
** COMMAND: test-builtin-get
**
** Usage: %fossil test-builtin-get NAME ?OUTPUT-FILE?
*/
void test_builtin_get(void){
  const unsigned char *pData;
  int nByte;
  Blob x;
  if( g.argc!=3 && g.argc!=4 ){
    usage("NAME ?OUTPUT-FILE?");
  }
  pData = builtin_file(g.argv[2], &nByte);







|











|
















|







56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
}

/*
** COMMAND: test-builtin-list
**
** List the names and sizes of all built-in resources.
*/
void test_builtin_list_cmd(void){
  int i;
  for(i=0; i<count(aBuiltinFiles); i++){
    fossil_print("%-30s %6d\n", aBuiltinFiles[i].zName,aBuiltinFiles[i].nByte);
  }
}

/*
** WEBPAGE: test-builtin-files
**
** Show all built-in text files.
*/
void test_builtin_files_page(void){
  int i;
  style_header("Built-in Text Files");
  @ <ul>
  for(i=0; i<count(aBuiltinFiles); i++){
    const char *z = aBuiltinFiles[i].zName;
    @ <li>%z(href("%R/builtin?name=%T&id=%S",z,MANIFEST_UUID))%h(z)</a>
  }
  @ </ul>
  style_footer();
}

/*
** COMMAND: test-builtin-get
**
** Usage: %fossil test-builtin-get NAME ?OUTPUT-FILE?
*/
void test_builtin_get_cmd(void){
  const unsigned char *pData;
  int nByte;
  Blob x;
  if( g.argc!=3 && g.argc!=4 ){
    usage("NAME ?OUTPUT-FILE?");
  }
  pData = builtin_file(g.argv[2], &nByte);
Changes to src/cache.c.
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
}

/*
** WEBPAGE: cachestat
**
** Show information about the webpage cache.  Requires Setup privilege.
*/
void cache_page(void){
  sqlite3 *db;
  sqlite3_stmt *pStmt;
  char zBuf[100];

  login_check_credentials();
  if( !g.perm.Setup ){ login_needed(0); return; }
  style_header("Web Cache Status");







|







344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
}

/*
** WEBPAGE: cachestat
**
** Show information about the webpage cache.  Requires Setup privilege.
*/
void cachestat_page(void){
  sqlite3 *db;
  sqlite3_stmt *pStmt;
  char zBuf[100];

  login_check_credentials();
  if( !g.perm.Setup ){ login_needed(0); return; }
  style_header("Web Cache Status");
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
**
** Usage:  /cacheget?key=KEY
**
** Download a single entry for the cache, identified by KEY.
** This page is normally a hyperlink from the /cachestat page.
** Requires Admin privilege.
*/
void cache_getpage(void){
  const char *zKey;
  Blob content;

  login_check_credentials();
  if( !g.perm.Setup ){ login_needed(0); return; }
  zKey = PD("key","");
  blob_zero(&content);







|







394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
**
** Usage:  /cacheget?key=KEY
**
** Download a single entry for the cache, identified by KEY.
** This page is normally a hyperlink from the /cachestat page.
** Requires Admin privilege.
*/
void cacheget_page(void){
  const char *zKey;
  Blob content;

  login_check_credentials();
  if( !g.perm.Setup ){ login_needed(0); return; }
  zKey = PD("key","");
  blob_zero(&content);
Changes to src/captcha.c.
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
#endif /* CAPTCHA==3 */

/*
** COMMAND: test-captcha
**
** Render an ASCII-art captcha for numbers given on the command line.
*/
void test_captcha(void){
  int i;
  unsigned int v;
  char *z;

  for(i=2; i<g.argc; i++){
    char zHex[30];
    v = (unsigned int)atoi(g.argv[i]);







|







415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
#endif /* CAPTCHA==3 */

/*
** COMMAND: test-captcha
**
** Render an ASCII-art captcha for numbers given on the command line.
*/
void test_captcha_cmd(void){
  int i;
  unsigned int v;
  char *z;

  for(i=2; i<g.argc; i++){
    char zHex[30];
    v = (unsigned int)atoi(g.argv[i]);
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588

/*
** WEBPAGE: test-captcha
** Test the captcha-generator by rendering the value of the name= query
** parameter using ascii-art.  If name= is omitted, show a random 16-digit
** hexadecimal number.
*/
void captcha_test(void){
  const char *zPw = P("name");
  if( zPw==0 || zPw[0]==0 ){
    u64 x;
    sqlite3_randomness(sizeof(x), &x);
    zPw = mprintf("%016llx", x);
  }
  style_header("Captcha Test");







|







574
575
576
577
578
579
580
581
582
583
584
585
586
587
588

/*
** WEBPAGE: test-captcha
** Test the captcha-generator by rendering the value of the name= query
** parameter using ascii-art.  If name= is omitted, show a random 16-digit
** hexadecimal number.
*/
void test_captcha_page(void){
  const char *zPw = P("name");
  if( zPw==0 || zPw[0]==0 ){
    u64 x;
    sqlite3_randomness(sizeof(x), &x);
    zPw = mprintf("%016llx", x);
  }
  style_header("Captcha Test");
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
      pOut->aData[42] = (char)((len>>16)&0xff);
      pOut->aData[43] = (char)((len>>24)&0xff);
    }
  }
}

/*
** WEBPAGE: /captcha-audio
**
** Return a WAV file that pronounces the digits of the captcha that
** is determined by the seed given in the name= query parameter.
*/
void captcha_wav_page(void){
  const char *zSeed = P("name");
  const char *zDecode = captcha_decode((unsigned int)atoi(zSeed));
  Blob audio;
  captcha_wav(zDecode, &audio);
  cgi_set_content_type("audio/wav");
  cgi_set_content(&audio);
}

/*
** WEBPAGE: /test-captcha-audio
**
** Return a WAV file that pronounces the hex digits of the name=
** query parameter.
*/
void captcha_test_wav_page(void){
  const char *zSeed = P("name");
  Blob audio;
  captcha_wav(zSeed, &audio);
  cgi_set_content_type("audio/wav");
  cgi_set_content(&audio);
}







|




|









|




|






673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
      pOut->aData[42] = (char)((len>>16)&0xff);
      pOut->aData[43] = (char)((len>>24)&0xff);
    }
  }
}

/*
** WEBPAGE: captcha-audio
**
** Return a WAV file that pronounces the digits of the captcha that
** is determined by the seed given in the name= query parameter.
*/
void captcha_audio_page(void){
  const char *zSeed = P("name");
  const char *zDecode = captcha_decode((unsigned int)atoi(zSeed));
  Blob audio;
  captcha_wav(zDecode, &audio);
  cgi_set_content_type("audio/wav");
  cgi_set_content(&audio);
}

/*
** WEBPAGE: test-captcha-audio
**
** Return a WAV file that pronounces the hex digits of the name=
** query parameter.
*/
void test_captcha_audio_page(void){
  const char *zSeed = P("name");
  Blob audio;
  captcha_wav(zSeed, &audio);
  cgi_set_content_type("audio/wav");
  cgi_set_content(&audio);
}
Changes to src/checkin.c.
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
  int relPathOption = find_option("rel-paths", 0, 0)!=0;
  if( absPathOption ){ relativePaths = 0; }
  if( relPathOption ){ relativePaths = 1; }
  return relativePaths;
}

/*
** COMMAND: changes
** COMMAND: status
**
** Usage: %fossil changes|status ?OPTIONS? ?PATHS ...?
**
** Report the change status of files in the current checkout.  If one or
** more PATHS are specified, only changes among the named files and
** directories are reported.  Directories are searched recursively.
**







|
|







347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
  int relPathOption = find_option("rel-paths", 0, 0)!=0;
  if( absPathOption ){ relativePaths = 0; }
  if( relPathOption ){ relativePaths = 1; }
  return relativePaths;
}

/*
** COMMAND: status
** COMMAND: changes
**
** Usage: %fossil changes|status ?OPTIONS? ?PATHS ...?
**
** Report the change status of files in the current checkout.  If one or
** more PATHS are specified, only changes among the named files and
** directories are reported.  Directories are searched recursively.
**
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
** COMMAND: test-date-format
**
** Usage: %fossil test-date-format DATE-STRING...
**
** Convert the DATE-STRING into the standard format used in artifacts
** and display the result.
*/
void test_date_format(void){
  int i;
  db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
  for(i=2; i<g.argc; i++){
    fossil_print("%s -> %s\n", g.argv[i], date_in_standard_format(g.argv[i]));
  }
}








|







1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
** COMMAND: test-date-format
**
** Usage: %fossil test-date-format DATE-STRING...
**
** Convert the DATE-STRING into the standard format used in artifacts
** and display the result.
*/
void test_date_format_cmd(void){
  int i;
  db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
  for(i=2; i<g.argc; i++){
    fossil_print("%s -> %s\n", g.argv[i], date_in_standard_format(g.argv[i]));
  }
}

1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
**
** Options:
**    --no-settings     Do not consider any glob settings.
**    -v|--verbose      Show per-file results for all pre-commit checks.
**
** See also: commit, extras
*/
void test_commit_warning(void){
  int rc = 0;
  int noSettings;
  int verboseFlag;
  Stmt q;
  noSettings = find_option("no-settings",0,0)!=0;
  verboseFlag = find_option("verbose","v",0)!=0;
  verify_all_options();







|







1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
**
** Options:
**    --no-settings     Do not consider any glob settings.
**    -v|--verbose      Show per-file results for all pre-commit checks.
**
** See also: commit, extras
*/
void test_commit_warning_cmd(void){
  int rc = 0;
  int noSettings;
  int verboseFlag;
  Stmt q;
  noSettings = find_option("no-settings",0,0)!=0;
  verboseFlag = find_option("verbose","v",0)!=0;
  verify_all_options();
Changes to src/comformat.c.
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
**   --origbreak      Attempt to break when the original comment text
**                    is detected.
**   --indent         Number of spaces to indent (default (-1) is to
**                    auto-detect).  Zero means no indent.
**   -W|--width <num> Width of lines (default (-1) is to auto-detect).
**                    Zero means no limit.
*/
void test_comment_format(void){
  const char *zWidth;
  const char *zIndent;
  const char *zPrefix;
  char *zText;
  char *zOrigText;
  int indent, width;
  int fromFile = find_option("file", 0, 0)!=0;







|







566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
**   --origbreak      Attempt to break when the original comment text
**                    is detected.
**   --indent         Number of spaces to indent (default (-1) is to
**                    auto-detect).  Zero means no indent.
**   -W|--width <num> Width of lines (default (-1) is to auto-detect).
**                    Zero means no limit.
*/
void test_comment_format_cmd(void){
  const char *zWidth;
  const char *zIndent;
  const char *zPrefix;
  char *zText;
  char *zOrigText;
  int indent, width;
  int fromFile = find_option("file", 0, 0)!=0;
Changes to src/content.c.
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
** successfully reconstructed using "fossil rebuild".
**
** Options:
**
**    --parse            Parse all manifests, wikis, tickets, events, and
**                       so forth, reporting any errors found.
*/
void test_integrity(void){
  Stmt q;
  Blob content;
  int n1 = 0;
  int n2 = 0;
  int nErr = 0;
  int total;
  int nCA = 0;







|







934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
** successfully reconstructed using "fossil rebuild".
**
** Options:
**
**    --parse            Parse all manifests, wikis, tickets, events, and
**                       so forth, reporting any errors found.
*/
void test_integrity_cmd(void){
  Stmt q;
  Blob content;
  int n1 = 0;
  int n2 = 0;
  int nErr = 0;
  int total;
  int nCA = 0;
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
}

/*
** COMMAND: test-orphans
**
** Search the repository for orphaned artifacts.
*/
void test_orphans(void){
  Stmt q;
  int cnt = 0;

  db_find_and_open_repository(0, 0);
  db_multi_exec(
    "CREATE TEMP TABLE used(id INTEGER PRIMARY KEY ON CONFLICT IGNORE);"
    "INSERT INTO used SELECT mid FROM mlink;"  /* Manifests */







|







1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
}

/*
** COMMAND: test-orphans
**
** Search the repository for orphaned artifacts.
*/
void test_orphans_cmd(void){
  Stmt q;
  int cnt = 0;

  db_find_and_open_repository(0, 0);
  db_multi_exec(
    "CREATE TEMP TABLE used(id INTEGER PRIMARY KEY ON CONFLICT IGNORE);"
    "INSERT INTO used SELECT mid FROM mlink;"  /* Manifests */
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
** that are missing or shunned.
**
** Options:
**
**    --notshunned          Do not report shunned artifacts
**    --quiet               Only show output if there are errors
*/
void test_missing(void){
  Stmt q;
  Blob content;
  int nErr = 0;
  int nArtifact = 0;
  int i;
  Manifest *p;
  unsigned flags = 0;







|







1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
** that are missing or shunned.
**
** Options:
**
**    --notshunned          Do not report shunned artifacts
**    --quiet               Only show output if there are errors
*/
void test_missing_cmd(void){
  Stmt q;
  Blob content;
  int nErr = 0;
  int nArtifact = 0;
  int i;
  Manifest *p;
  unsigned flags = 0;
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
**
** WARNING: You must run "fossil rebuild" after this command to rebuild
** the metadata.
**
** Note that the arguments are the integer raw RID values from the BLOB table,
** not artifact hashes or labels.
*/
void test_content_erase(void){
  int i;
  Blob x;
  char c;
  Stmt q;
  prompt_user("This command erases information from the repository and\n"
              "might irrecoverably damage the repository.  Make sure you\n"
              "have a backup copy!\n"







|







1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
**
** WARNING: You must run "fossil rebuild" after this command to rebuild
** the metadata.
**
** Note that the arguments are the integer raw RID values from the BLOB table,
** not artifact hashes or labels.
*/
void test_content_erase_cmd(void){
  int i;
  Blob x;
  char c;
  Stmt q;
  prompt_user("This command erases information from the repository and\n"
              "might irrecoverably damage the repository.  Make sure you\n"
              "have a backup copy!\n"
Changes to src/cookies.c.
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
  assert( zPName!=0 );
  cookie_parse();
  for(i=0; i<cookies.nParam && strcmp(zPName,cookies.aParam[i].zPName); i++){}
  return i<cookies.nParam ? cookies.aParam[i].zPValue : zDefault;
}

/*
** WEBPAGE:  cookies
**
** Show the current display settings contained in the
** "fossil_display_settings" cookie.
*/
void cookie_page(void){
  int i;
  if( PB("clear") ){
    cgi_set_cookie(DISPLAY_SETTINGS_COOKIE, "", 0, 1);
    cgi_replace_parameter(DISPLAY_SETTINGS_COOKIE, "");
  }
  cookie_parse();
  style_header("User Preference Cookie Values");







|




|







199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
  assert( zPName!=0 );
  cookie_parse();
  for(i=0; i<cookies.nParam && strcmp(zPName,cookies.aParam[i].zPName); i++){}
  return i<cookies.nParam ? cookies.aParam[i].zPValue : zDefault;
}

/*
** WEBPAGE: cookies
**
** Show the current display settings contained in the
** "fossil_display_settings" cookie.
*/
void cookies_page(void){
  int i;
  if( PB("clear") ){
    cgi_set_cookie(DISPLAY_SETTINGS_COOKIE, "", 0, 1);
    cgi_replace_parameter(DISPLAY_SETTINGS_COOKIE, "");
  }
  cookie_parse();
  style_header("User Preference Cookie Values");
Changes to src/db.c.
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617

/*
** COMMAND: test-db-exec-error
**
** Invoke the db_exec() interface with an erroneous SQL statement
** in order to verify the error handling logic.
*/
void db_test_db_exec_cmd(void){
  Stmt err;
  db_find_and_open_repository(0,0);
  db_prepare(&err, "INSERT INTO repository.config(name) VALUES(NULL);");
  db_exec(&err);
}

/*







|







603
604
605
606
607
608
609
610
611
612
613
614
615
616
617

/*
** COMMAND: test-db-exec-error
**
** Invoke the db_exec() interface with an erroneous SQL statement
** in order to verify the error handling logic.
*/
void test_db_exec_error_cmd(void){
  Stmt err;
  db_find_and_open_repository(0,0);
  db_prepare(&err, "INSERT INTO repository.config(name) VALUES(NULL);");
  db_exec(&err);
}

/*
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
**
** Usage: %fossil test-move-repository PATHNAME
**
** Change the location of the repository database on a local check-out.
** Use this command to avoid having to close and reopen a checkout
** when relocating the repository database.
*/
void move_repo_cmd(void){
  Blob repo;
  char *zRepo;
  if( g.argc!=3 ){
    usage("PATHNAME");
  }
  file_canonical_name(g.argv[2], &repo, 0);
  zRepo = blob_str(&repo);







|







1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
**
** Usage: %fossil test-move-repository PATHNAME
**
** Change the location of the repository database on a local check-out.
** Use this command to avoid having to close and reopen a checkout
** when relocating the repository database.
*/
void test_move_repo_cmd(void){
  Blob repo;
  char *zRepo;
  if( g.argc!=3 ){
    usage("PATHNAME");
  }
  file_canonical_name(g.argv[2], &repo, 0);
  zRepo = blob_str(&repo);
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
**   --force-missing   Force opening a repository with missing content
**   --setmtime        Set timestamps of all files to match their SCM-side
**                     times (the timestamp of the last checkin which modified
**                     them).
**
** See also: close
*/
void cmd_open(void){
  int emptyFlag;
  int keepFlag;
  int forceMissingFlag;
  int allowNested;
  int allowSymlinks;
  int setmtimeFlag;              /* --setmtime.  Set mtimes on files */
  static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0, 0 };







|







2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
**   --force-missing   Force opening a repository with missing content
**   --setmtime        Set timestamps of all files to match their SCM-side
**                     times (the timestamp of the last checkin which modified
**                     them).
**
** See also: close
*/
void open_cmd(void){
  int emptyFlag;
  int keepFlag;
  int forceMissingFlag;
  int allowNested;
  int allowSymlinks;
  int setmtimeFlag;              /* --setmtime.  Set mtimes on files */
  static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0, 0 };
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
**   --global   set or unset the given property globally instead of
**              setting or unsetting it for the open repository only.
**
**   --exact    only consider exact name matches.
**
** See also: configuration
*/
void setting_cmd(void){
  int i;
  int globalFlag = find_option("global","g",0)!=0;
  int exactFlag = find_option("exact",0,0)!=0;
  int unsetFlag = g.argv[1][0]=='u';
  int nSetting;
  const Setting *aSetting = setting_info(&nSetting);
  find_repository_option();







|







3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
**   --global   set or unset the given property globally instead of
**              setting or unsetting it for the open repository only.
**
**   --exact    only consider exact name matches.
**
** See also: configuration
*/
void settings_cmd(void){
  int i;
  int globalFlag = find_option("global","g",0)!=0;
  int exactFlag = find_option("exact",0,0)!=0;
  int unsetFlag = g.argv[1][0]=='u';
  int nSetting;
  const Setting *aSetting = setting_info(&nSetting);
  find_repository_option();
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
**
** The purpose of this command is for testing the WITHOUT ROWID capabilities
** of SQLite.  There is no big advantage to using WITHOUT ROWID in Fossil.
**
** Options:
**    --dryrun | -n         No changes.  Just print what would happen.
*/
void test_without_rowid(void){
  int i, j;
  Stmt q;
  Blob allSql;
  int dryRun = find_option("dry-run", "n", 0)!=0;
  for(i=2; i<g.argc; i++){
    db_open_or_attach(g.argv[i], "main");
    blob_init(&allSql, "BEGIN;\n", -1);







|







3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
**
** The purpose of this command is for testing the WITHOUT ROWID capabilities
** of SQLite.  There is no big advantage to using WITHOUT ROWID in Fossil.
**
** Options:
**    --dryrun | -n         No changes.  Just print what would happen.
*/
void test_without_rowid_cmd(void){
  int i, j;
  Stmt q;
  Blob allSql;
  int dryRun = find_option("dry-run", "n", 0)!=0;
  for(i=2; i<g.argc; i++){
    db_open_or_attach(g.argv[i], "main");
    blob_init(&allSql, "BEGIN;\n", -1);
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
** COMMAND: test-database-names
**
** Print the names of the various database files:
** (1) The main repository database
** (2) The local checkout database
** (3) The global configuration database
*/
void test_database_name_cmd(void){
  db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
  fossil_print("Repository database: %s\n", g.zRepositoryName);
  fossil_print("Local database:      %s\n", g.zLocalDbName);
  fossil_print("Config database:     %s\n", g.zConfigDbName);
}

/*







|







3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
** COMMAND: test-database-names
**
** Print the names of the various database files:
** (1) The main repository database
** (2) The local checkout database
** (3) The global configuration database
*/
void test_database_names_cmd(void){
  db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
  fossil_print("Repository database: %s\n", g.zRepositoryName);
  fossil_print("Local database:      %s\n", g.zLocalDbName);
  fossil_print("Config database:     %s\n", g.zConfigDbName);
}

/*
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
** Usage: %fossil test-fingerprint ?RCVID?
**
** Display the repository fingerprint using the supplied RCVID or
** using the latest RCVID if not is given on the command line.
** Show both the legacy and the newer version of the fingerprint,
** and the currently stored fingerprint if there is one.
*/
void test_fingerprint(void){
  int rcvid = 0;
  db_find_and_open_repository(OPEN_ANY_SCHEMA,0);
  if( g.argc==3 ){
    rcvid = atoi(g.argv[2]);
  }else if( g.argc!=2 ){
    fossil_fatal("wrong number of arguments");
  } 







|







4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
** Usage: %fossil test-fingerprint ?RCVID?
**
** Display the repository fingerprint using the supplied RCVID or
** using the latest RCVID if not is given on the command line.
** Show both the legacy and the newer version of the fingerprint,
** and the currently stored fingerprint if there is one.
*/
void test_fingerprint_cmd(void){
  int rcvid = 0;
  db_find_and_open_repository(OPEN_ANY_SCHEMA,0);
  if( g.argc==3 ){
    rcvid = atoi(g.argv[2]);
  }else if( g.argc!=2 ){
    fossil_fatal("wrong number of arguments");
  } 
Changes to src/deltacmd.c.
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
** COMMAND: test-delta-create
**
** Usage: %fossil test-delta-create FILE1 FILE2 DELTA
**
** Create and output a delta that carries FILE1 into FILE2.
** Store the result in DELTA.
*/
void delta_create_cmd(void){
  Blob orig, target, delta;
  if( g.argc!=5 ){
    usage("ORIGIN TARGET DELTA");
  }
  if( blob_read_from_file(&orig, g.argv[2], ExtFILE)<0 ){
    fossil_fatal("cannot read %s", g.argv[2]);
  }







|







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
** COMMAND: test-delta-create
**
** Usage: %fossil test-delta-create FILE1 FILE2 DELTA
**
** Create and output a delta that carries FILE1 into FILE2.
** Store the result in DELTA.
*/
void test_delta_create_cmd(void){
  Blob orig, target, delta;
  if( g.argc!=5 ){
    usage("ORIGIN TARGET DELTA");
  }
  if( blob_read_from_file(&orig, g.argv[2], ExtFILE)<0 ){
    fossil_fatal("cannot read %s", g.argv[2]);
  }
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
** COMMAND: test-delta-analyze
**
** Usage: %fossil test-delta-analyze FILE1 FILE2
**
** Create and a delta that carries FILE1 into FILE2.  Print the
** number bytes copied and the number of bytes inserted.
*/
void delta_analyze_cmd(void){
  Blob orig, target, delta;
  int nCopy = 0;
  int nInsert = 0;
  int sz1, sz2, sz3;
  if( g.argc!=4 ){
    usage("ORIGIN TARGET");
  }







|







74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
** COMMAND: test-delta-analyze
**
** Usage: %fossil test-delta-analyze FILE1 FILE2
**
** Create and a delta that carries FILE1 into FILE2.  Print the
** number bytes copied and the number of bytes inserted.
*/
void test_delta_analyze_cmd(void){
  Blob orig, target, delta;
  int nCopy = 0;
  int nInsert = 0;
  int sz1, sz2, sz3;
  if( g.argc!=4 ){
    usage("ORIGIN TARGET");
  }
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/*
** COMMAND: test-delta-apply
**
** Usage: %fossil test-delta-apply FILE1 DELTA
**
** Apply DELTA to FILE1 and output the result.
*/
void delta_apply_cmd(void){
  Blob orig, target, delta;
  if( g.argc!=5 ){
    usage("ORIGIN DELTA TARGET");
  }
  if( blob_read_from_file(&orig, g.argv[2], ExtFILE)<0 ){
    fossil_fatal("cannot read %s", g.argv[2]);
  }







|







145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/*
** COMMAND: test-delta-apply
**
** Usage: %fossil test-delta-apply FILE1 DELTA
**
** Apply DELTA to FILE1 and output the result.
*/
void test_delta_apply_cmd(void){
  Blob orig, target, delta;
  if( g.argc!=5 ){
    usage("ORIGIN DELTA TARGET");
  }
  if( blob_read_from_file(&orig, g.argv[2], ExtFILE)<0 ){
    fossil_fatal("cannot read %s", g.argv[2]);
  }
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
**
** Usage: %fossil test-delta FILE1 FILE2
**
** Read two files named on the command-line.  Create and apply deltas
** going in both directions.  Verify that the original files are
** correctly recovered.
*/
void cmd_test_delta(void){
  Blob f1, f2;     /* Original file content */
  Blob d12, d21;   /* Deltas from f1->f2 and f2->f1 */
  Blob a1, a2;     /* Recovered file content */
  if( g.argc!=4 ) usage("FILE1 FILE2");
  blob_read_from_file(&f1, g.argv[2], ExtFILE);
  blob_read_from_file(&f2, g.argv[3], ExtFILE);
  blob_delta_create(&f1, &f2, &d12);







|







175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
**
** Usage: %fossil test-delta FILE1 FILE2
**
** Read two files named on the command-line.  Create and apply deltas
** going in both directions.  Verify that the original files are
** correctly recovered.
*/
void test_delta_cmd(void){
  Blob f1, f2;     /* Original file content */
  Blob d12, d21;   /* Deltas from f1->f2 and f2->f1 */
  Blob a1, a2;     /* Recovered file content */
  if( g.argc!=4 ) usage("FILE1 FILE2");
  blob_read_from_file(&f1, g.argv[2], ExtFILE);
  blob_read_from_file(&f2, g.argv[3], ExtFILE);
  blob_delta_create(&f1, &f2, &d12);
Changes to src/diff.c.
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
**    log=BOOLEAN         Show a log of versions analyzed
**    origin=ID           The origin checkin.  If unspecified, the root
**                           check-in over the entire repository is used.
**                           Specify "origin=trunk" or similar for a reverse
**                           annotation
**    w=BOOLEAN           Ignore whitespace
*/
void annotation_page(void){
  int i;
  const char *zLimit;    /* Depth limit */
  u64 annFlags = DIFF_STRIP_EOLCR;
  int showLog;           /* True to display the log */
  int fileVers;          /* Show file version instead of check-in versions */
  int ignoreWs;          /* Ignore whitespace */
  const char *zFilename; /* Name of file to annotate */







|







2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
**    log=BOOLEAN         Show a log of versions analyzed
**    origin=ID           The origin checkin.  If unspecified, the root
**                           check-in over the entire repository is used.
**                           Specify "origin=trunk" or similar for a reverse
**                           annotation
**    w=BOOLEAN           Ignore whitespace
*/
void annotate_page(void){
  int i;
  const char *zLimit;    /* Depth limit */
  u64 annFlags = DIFF_STRIP_EOLCR;
  int showLog;           /* True to display the log */
  int fileVers;          /* Show file version instead of check-in versions */
  int ignoreWs;          /* Ignore whitespace */
  const char *zFilename; /* Name of file to annotate */
Changes to src/dispatch.c.
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
}

/*
** COMMAND: test-list-webpage
**
** List all web pages.
*/
void cmd_test_webpage_list(void){
  int i, nCmd;
  const char *aCmd[MX_COMMAND];
  for(i=nCmd=0; i<MX_COMMAND; i++){
    if(CMDFLAG_WEBPAGE & aCommand[i].eCmdFlags){
      aCmd[nCmd++] = aCommand[i].zName;
    }
  }







|







496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
}

/*
** COMMAND: test-list-webpage
**
** List all web pages.
*/
void test_list_webpage_cmd(void){
  int i, nCmd;
  const char *aCmd[MX_COMMAND];
  for(i=nCmd=0; i<MX_COMMAND; i++){
    if(CMDFLAG_WEBPAGE & aCommand[i].eCmdFlags){
      aCmd[nCmd++] = aCommand[i].zName;
    }
  }
Changes to src/doc.c.
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
**
** Return the deduced mimetype for each file listed.
**
** If Fossil is compiled with -DFOSSIL_DEBUG then the "mimetype-test"
** filename is special and verifies the integrity of the mimetype table.
** It should return "ok".
*/
void mimetype_test_cmd(void){
  int i;
  mimetype_verify();
  db_find_and_open_repository(0, 0);
  for(i=2; i<g.argc; i++){
    fossil_print("%-20s -> %s\n", g.argv[i], mimetype_from_name(g.argv[i]));
  }
}







|







457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
**
** Return the deduced mimetype for each file listed.
**
** If Fossil is compiled with -DFOSSIL_DEBUG then the "mimetype-test"
** filename is special and verifies the integrity of the mimetype table.
** It should return "ok".
*/
void test_mimetype_cmd(void){
  int i;
  mimetype_verify();
  db_find_and_open_repository(0, 0);
  for(i=2; i<g.argc; i++){
    fossil_print("%-20s -> %s\n", g.argv[i], mimetype_from_name(g.argv[i]));
  }
}
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
    cgi_set_content_type(zMime);
    cgi_set_content(pBody);
  }
}


/*
** WEBPAGE: uv
** WEBPAGE: doc
** URL: /uv/FILE
** URL: /doc/CHECKIN/FILE
**
** CHECKIN can be either tag or hash prefix or timestamp identifying a
** particular check, or the name of a branch (meaning the most recent
** check-in on that branch) or one of various magic words:
**







|
|







802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
    cgi_set_content_type(zMime);
    cgi_set_content(pBody);
  }
}


/*
** WEBPAGE: doc
** WEBPAGE: uv
** URL: /uv/FILE
** URL: /doc/CHECKIN/FILE
**
** CHECKIN can be either tag or hash prefix or timestamp identifying a
** particular check, or the name of a branch (meaning the most recent
** check-in on that branch) or one of various magic words:
**
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
** If no pattern is specified (by the s= query parameter) then the user
** is prompted to enter a search string.
**
** Query parameters:
**
**     s=PATTERN             Search for PATTERN
*/
void doc_search_page(void){
  login_check_credentials();
  style_header("Document Search");
  search_screen(SRCH_DOC, 0);
  style_footer();
}







|





1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
** If no pattern is specified (by the s= query parameter) then the user
** is prompted to enter a search string.
**
** Query parameters:
**
**     s=PATTERN             Search for PATTERN
*/
void docsrch_page(void){
  login_check_credentials();
  style_header("Document Search");
  search_screen(SRCH_DOC, 0);
  style_footer();
}
Changes to src/export.c.
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849

/*
** COMMAND: test-topological-sort
**
** Invoke the topological_sort_checkins() interface for testing
** purposes.
*/
void test_topological_sort(void){
  int n;
  db_find_and_open_repository(0, 0);
  n = topological_sort_checkins(1);
  fossil_print("%d reorderings required\n", n);
}

/***************************************************************************







|







835
836
837
838
839
840
841
842
843
844
845
846
847
848
849

/*
** COMMAND: test-topological-sort
**
** Invoke the topological_sort_checkins() interface for testing
** purposes.
*/
void test_topological_sort_cmd(void){
  int n;
  db_find_and_open_repository(0, 0);
  n = topological_sort_checkins(1);
  fossil_print("%d reorderings required\n", n);
}

/***************************************************************************
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
**
**       TBD...   
**
**   fossil git status
**
**       Show the status of the current Git mirror, if there is one.
*/
void gitmirror_command(void){
  char *zCmd;
  int nCmd;
  if( g.argc<3 ){
    usage("export ARGS...");
  }
  zCmd =  g.argv[2];
  nCmd = (int)strlen(zCmd);







|







1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
**
**       TBD...   
**
**   fossil git status
**
**       Show the status of the current Git mirror, if there is one.
*/
void gitmirror_cmd(void){
  char *zCmd;
  int nCmd;
  if( g.argc<3 ){
    usage("export ARGS...");
  }
  zCmd =  g.argv[2];
  nCmd = (int)strlen(zCmd);
Changes to src/extcgi.c.
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
}

/*
** WEBPAGE: extfilelist
**
** List all files in the extension CGI document root and its subfolders.
*/
void ext_filelist_page(void){
  Stmt q;
  login_check_credentials();
  if( !g.perm.Admin ){
    login_needed(0);
    return;
  }
  ext_files();







|







381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
}

/*
** WEBPAGE: extfilelist
**
** List all files in the extension CGI document root and its subfolders.
*/
void extfilelist_page(void){
  Stmt q;
  login_check_credentials();
  if( !g.perm.Admin ){
    login_needed(0);
    return;
  }
  ext_files();
Changes to src/file.c.
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
**
** Usage: %fossil test-file-copy SOURCE DESTINATION
**
** Make a copy of the file at SOURCE into a new name DESTINATION.  Any
** directories in the path leading up to DESTINATION that do not already
** exist are created automatically.
*/
void test_file_copy(void){
  if( g.argc!=4 ){
    fossil_fatal("Usage: %s test-file-copy SOURCE DESTINATION", g.argv[0]);
  }
  file_copy(g.argv[2], g.argv[3]);
}

/*







|







509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
**
** Usage: %fossil test-file-copy SOURCE DESTINATION
**
** Make a copy of the file at SOURCE into a new name DESTINATION.  Any
** directories in the path leading up to DESTINATION that do not already
** exist are created automatically.
*/
void test_file_copy_cmd(void){
  if( g.argc!=4 ){
    fossil_fatal("Usage: %s test-file-copy SOURCE DESTINATION", g.argv[0]);
  }
  file_copy(g.argv[2], g.argv[3]);
}

/*
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
/*
** COMMAND: test-set-mtime
**
** Usage: %fossil test-set-mtime FILENAME DATE/TIME
**
** Sets the mtime of the named file to the date/time shown.
*/
void test_set_mtime(void){
  const char *zFile;
  char *zDate;
  i64 iMTime;
  if( g.argc!=4 ){
    usage("FILENAME DATE/TIME");
  }
  db_open_or_attach(":memory:", "mem");







|







576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
/*
** COMMAND: test-set-mtime
**
** Usage: %fossil test-set-mtime FILENAME DATE/TIME
**
** Sets the mtime of the named file to the date/time shown.
*/
void test_set_mtime_cmd(void){
  const char *zFile;
  char *zDate;
  i64 iMTime;
  if( g.argc!=4 ){
    usage("FILENAME DATE/TIME");
  }
  db_open_or_attach(":memory:", "mem");
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
** COMMAND: test-is-normal-dir
**
** Usage: %fossil test-is-normal-dir NAME...
**
** Returns non-zero if the specified names represent real directories, i.e.
** not junctions, symbolic links, etc.
*/
void test_is_normal_dir(void){
  int i;
  for(i=2; i<g.argc; i++){
    wchar_t *zMbcs = fossil_utf8_to_path(g.argv[i], 1);
    fossil_print("ATTRS \"%s\" -> %lx\n", g.argv[i], GetFileAttributesW(zMbcs));
    fossil_print("ISDIR \"%s\" -> %d\n", g.argv[i], file_is_normal_dir(zMbcs));
    fossil_path_free(zMbcs);
  }







|







732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
** COMMAND: test-is-normal-dir
**
** Usage: %fossil test-is-normal-dir NAME...
**
** Returns non-zero if the specified names represent real directories, i.e.
** not junctions, symbolic links, etc.
*/
void test_is_normal_dir_cmd(void){
  int i;
  for(i=2; i<g.argc; i++){
    wchar_t *zMbcs = fossil_utf8_to_path(g.argv[i], 1);
    fossil_print("ATTRS \"%s\" -> %lx\n", g.argv[i], GetFileAttributesW(zMbcs));
    fossil_print("ISDIR \"%s\" -> %d\n", g.argv[i], file_is_normal_dir(zMbcs));
    fossil_path_free(zMbcs);
  }
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
/*
** COMMAND: test-simplify-name
**
** Usage: %fossil test-simplify-name FILENAME...
**
** Print the simplified versions of each FILENAME.
*/
void cmd_test_simplify_name(void){
  int i;
  char *z;
  for(i=2; i<g.argc; i++){
    z = mprintf("%s", g.argv[i]);
    fossil_print("[%s] -> ", z);
    file_simplify_name(z, -1, 0);
    fossil_print("[%s]\n", z);







|







994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
/*
** COMMAND: test-simplify-name
**
** Usage: %fossil test-simplify-name FILENAME...
**
** Print the simplified versions of each FILENAME.
*/
void test_simplify_name_cmd(void){
  int i;
  char *z;
  for(i=2; i<g.argc; i++){
    z = mprintf("%s", g.argv[i]);
    fossil_print("[%s] -> ", z);
    file_simplify_name(z, -1, 0);
    fossil_print("[%s]\n", z);
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
** Options:
**
**     --allow-symlinks BOOLEAN     Temporarily turn allow-symlinks on/off
**     --open-config                Open the configuration database first.
**     --slash                      Trailing slashes, if any, are retained.
**     --reset                      Reset cached stat() info for each file.
*/
void cmd_test_file_environment(void){
  int i;
  int slashFlag = find_option("slash",0,0)!=0;
  int resetFlag = find_option("reset",0,0)!=0;
  const char *zAllow = find_option("allow-symlinks",0,1);
  if( find_option("open-config", 0, 0)!=0 ){
    Th_OpenConfig(1);
  }







|







1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
** Options:
**
**     --allow-symlinks BOOLEAN     Temporarily turn allow-symlinks on/off
**     --open-config                Open the configuration database first.
**     --slash                      Trailing slashes, if any, are retained.
**     --reset                      Reset cached stat() info for each file.
*/
void test_file_environment_cmd(void){
  int i;
  int slashFlag = find_option("slash",0,0)!=0;
  int resetFlag = find_option("reset",0,0)!=0;
  const char *zAllow = find_option("allow-symlinks",0,1);
  if( find_option("open-config", 0, 0)!=0 ){
    Th_OpenConfig(1);
  }
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
** COMMAND: test-canonical-name
**
** Usage: %fossil test-canonical-name FILENAME...
**
** Test the operation of the canonical name generator.
** Also test Fossil's ability to measure attributes of a file.
*/
void cmd_test_canonical_name(void){
  int i;
  Blob x;
  int slashFlag = find_option("slash",0,0)!=0;
  blob_zero(&x);
  for(i=2; i<g.argc; i++){
    char zBuf[100];
    const char *zName = g.argv[i];







|







1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
** COMMAND: test-canonical-name
**
** Usage: %fossil test-canonical-name FILENAME...
**
** Test the operation of the canonical name generator.
** Also test Fossil's ability to measure attributes of a file.
*/
void test_canonical_name_cmd(void){
  int i;
  Blob x;
  int slashFlag = find_option("slash",0,0)!=0;
  blob_zero(&x);
  for(i=2; i<g.argc; i++){
    char zBuf[100];
    const char *zName = g.argv[i];
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
}

/*
** COMMAND: test-relative-name
**
** Test the operation of the relative name generator.
*/
void cmd_test_relative_name(void){
  int i;
  Blob x;
  int slashFlag = find_option("slash",0,0)!=0;
  blob_zero(&x);
  for(i=2; i<g.argc; i++){
    file_relative_name(g.argv[i], &x, slashFlag);
    fossil_print("%s\n", blob_buffer(&x));







|







1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
}

/*
** COMMAND: test-relative-name
**
** Test the operation of the relative name generator.
*/
void test_relative_name_cmd(void){
  int i;
  Blob x;
  int slashFlag = find_option("slash",0,0)!=0;
  blob_zero(&x);
  for(i=2; i<g.argc; i++){
    file_relative_name(g.argv[i], &x, slashFlag);
    fossil_print("%s\n", blob_buffer(&x));
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
** Test the operation of the tree name generator.
**
** Options:
**   --absolute           Return an absolute path instead of a relative one.
**   --case-sensitive B   Enable or disable case-sensitive filenames.  B is
**                        a boolean: "yes", "no", "true", "false", etc.
*/
void cmd_test_tree_name(void){
  int i;
  Blob x;
  int absoluteFlag = find_option("absolute",0,0)!=0;
  db_find_and_open_repository(0,0);
  blob_zero(&x);
  for(i=2; i<g.argc; i++){
    if( file_tree_name(g.argv[i], &x, absoluteFlag, 1) ){







|







1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
** Test the operation of the tree name generator.
**
** Options:
**   --absolute           Return an absolute path instead of a relative one.
**   --case-sensitive B   Enable or disable case-sensitive filenames.  B is
**                        a boolean: "yes", "no", "true", "false", etc.
*/
void test_tree_name_cmd(void){
  int i;
  Blob x;
  int absoluteFlag = find_option("absolute",0,0)!=0;
  db_find_and_open_repository(0,0);
  blob_zero(&x);
  for(i=2; i<g.argc; i++){
    if( file_tree_name(g.argv[i], &x, absoluteFlag, 1) ){
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
** COMMAND: test-tempname
** Usage:  fossil test-name [--time SUFFIX] [--tag NAME] BASENAME ...
**
** Generate temporary filenames derived from BASENAME.  Use the --time
** option to generate temp names based on the time of day.  If --tag NAME
** is specified, try to use NAME as the differentiator in the temp file.
*/
void file_test_tempname(void){
  int i;
  const char *zSuffix = find_option("time",0,1);
  Blob x = BLOB_INITIALIZER;
  char *z;
  const char *zTag = find_option("tag",0,1);
  verify_all_options();
  for(i=2; i<g.argc; i++){







|







1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
** COMMAND: test-tempname
** Usage:  fossil test-name [--time SUFFIX] [--tag NAME] BASENAME ...
**
** Generate temporary filenames derived from BASENAME.  Use the --time
** option to generate temp names based on the time of day.  If --tag NAME
** is specified, try to use NAME as the differentiator in the temp file.
*/
void test_tempname_cmd(void){
  int i;
  const char *zSuffix = find_option("time",0,1);
  Blob x = BLOB_INITIALIZER;
  char *z;
  const char *zTag = find_option("tag",0,1);
  verify_all_options();
  for(i=2; i<g.argc; i++){
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905

/*
** COMMAND: test-valid-for-windows
** Usage:  fossil test-valid-for-windows FILENAME ....
**
** Show which filenames are not valid for Windows
*/
void file_test_valid_for_windows(void){
  int i;
  for(i=2; i<g.argc; i++){
    fossil_print("%s %s\n", file_is_win_reserved(g.argv[i]), g.argv[i]);
  }
}

/*







|







1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905

/*
** COMMAND: test-valid-for-windows
** Usage:  fossil test-valid-for-windows FILENAME ....
**
** Show which filenames are not valid for Windows
*/
void test_valid_for_windows_cmd(void){
  int i;
  for(i=2; i<g.argc; i++){
    fossil_print("%s %s\n", file_is_win_reserved(g.argv[i]), g.argv[i]);
  }
}

/*
Changes to src/forum.c.
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
** Usage: %fossil test-forumthread [THREADID]
**
** Display a summary of all messages on a thread THREADID.  If the
** THREADID argument is omitted, then show a list of all threads.
**
** This command is intended for testing an analysis only.
*/
void forumthread_cmd(void){
  int fpid;
  int froot;
  const char *zName;
  ForumThread *pThread;
  ForumEntry *p;

  db_find_and_open_repository(0,0);







|







251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
** Usage: %fossil test-forumthread [THREADID]
**
** Display a summary of all messages on a thread THREADID.  If the
** THREADID argument is omitted, then show a list of all threads.
**
** This command is intended for testing an analysis only.
*/
void test_forumthread_cmd(void){
  int fpid;
  int froot;
  const char *zName;
  ForumThread *pThread;
  ForumEntry *p;

  db_find_and_open_repository(0,0);
Changes to src/fuzz.c.
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
**
** Run a fuzz test using INPUTFILE as the test data.  TYPE can be one of:
**
**     wiki                  Fuzz the Fossil-wiki translator
**     markdown              Fuzz the markdown translator
**     artifact              Fuzz the artifact parser
*/
void fuzz_command(void){
  Blob in;
  int i;
  fuzzer_options();
  verify_all_options();
  for(i=2; i<g.argc; i++){
    blob_read_from_file(&in, g.argv[i], ExtFILE);
    LLVMFuzzerTestOneInput((const uint8_t*)in.aData, (size_t)in.nUsed);







|







123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
**
** Run a fuzz test using INPUTFILE as the test data.  TYPE can be one of:
**
**     wiki                  Fuzz the Fossil-wiki translator
**     markdown              Fuzz the markdown translator
**     artifact              Fuzz the artifact parser
*/
void test_fuzz_cmd(void){
  Blob in;
  int i;
  fuzzer_options();
  verify_all_options();
  for(i=2; i<g.argc; i++){
    blob_read_from_file(&in, g.argv[i], ExtFILE);
    LLVMFuzzerTestOneInput((const uint8_t*)in.aData, (size_t)in.nUsed);
Changes to src/glob.c.
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
** quoted glob patterns.  Show which of the STRINGs that follow match
** the PATTERN.
**
** If PATTERN begins with "@" the rest of the pattern is understood
** to be a setting name (such as binary-glob, crln-glob, or encoding-glob)
** and the value of that setting is used as the actually glob pattern.
*/
void glob_test_cmd(void){
  Glob *pGlob;
  int i;
  char *zPattern;
  if( g.argc<4 ) usage("PATTERN STRING ...");
  zPattern = g.argv[2];
  if( zPattern[0]=='@' ){
    db_find_and_open_repository(OPEN_ANY_SCHEMA,0);







|







175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
** quoted glob patterns.  Show which of the STRINGs that follow match
** the PATTERN.
**
** If PATTERN begins with "@" the rest of the pattern is understood
** to be a setting name (such as binary-glob, crln-glob, or encoding-glob)
** and the value of that setting is used as the actually glob pattern.
*/
void test_glob_cmd(void){
  Glob *pGlob;
  int i;
  char *zPattern;
  if( g.argc<4 ) usage("PATTERN STRING ...");
  zPattern = g.argv[2];
  if( zPattern[0]=='@' ){
    db_find_and_open_repository(OPEN_ANY_SCHEMA,0);
Changes to src/hname.c.
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
**                     allowed during a clone.
**
** The default hash policy for existing repositories is "auto", which will
** immediately promote to "sha3" if the repository contains one or more
** artifacts with SHA3 names.  The default hash policy for new repositories
** is "shun-sha1".
*/
void hash_policy_command(void){
  int i;
  db_find_and_open_repository(0, 0);
  if( g.argc!=2 && g.argc!=3 ) usage("?NEW-POLICY?");
  if( g.argc==2 ){
    fossil_print("%s\n", azPolicy[g.eHashPolicy]);
    return;
  }







|







254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
**                     allowed during a clone.
**
** The default hash policy for existing repositories is "auto", which will
** immediately promote to "sha3" if the repository contains one or more
** artifacts with SHA3 names.  The default hash policy for new repositories
** is "shun-sha1".
*/
void hash_policy_cmd(void){
  int i;
  db_find_and_open_repository(0, 0);
  if( g.argc!=2 && g.argc!=3 ) usage("?NEW-POLICY?");
  if( g.argc==2 ){
    fossil_print("%s\n", azPolicy[g.eHashPolicy]);
    return;
  }
Changes to src/http.c.
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
** Options:
**
**     --compress                 Use ZLIB compression on the payload
**     --mimetype TYPE            Mimetype of the payload
**     --out FILE                 Store the reply in FILE
**     -v                         Verbose output
*/
void test_httpmsg_command(void){
  const char *zMimetype;
  const char *zInFile;
  const char *zOutFile;
  Blob in, out;
  unsigned int mHttpFlags = HTTP_GENERIC|HTTP_NOCOMPRESS;

  zMimetype = find_option("mimetype",0,1);







|







482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
** Options:
**
**     --compress                 Use ZLIB compression on the payload
**     --mimetype TYPE            Mimetype of the payload
**     --out FILE                 Store the reply in FILE
**     -v                         Verbose output
*/
void test_httpmsg_cmd(void){
  const char *zMimetype;
  const char *zInFile;
  const char *zOutFile;
  Blob in, out;
  unsigned int mHttpFlags = HTTP_GENERIC|HTTP_NOCOMPRESS;

  zMimetype = find_option("mimetype",0,1);
Changes to src/info.c.
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
/*
** WEBPAGE: test-backlinks
**
** Show a timeline of all check-ins and other events that have entries
** in the backlink table.  This is used for testing the rendering
** of the "References" section of the /info page.
*/
void backlink_timeline_page(void){
  Blob sql;
  Stmt q;

  login_check_credentials();
  if( !g.perm.Read || !g.perm.RdTkt || !g.perm.RdWiki ){
    login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki);
    return;







|







338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
/*
** WEBPAGE: test-backlinks
**
** Show a timeline of all check-ins and other events that have entries
** in the backlink table.  This is used for testing the rendering
** of the "References" section of the /info page.
*/
void test_backlinks_page(void){
  Blob sql;
  Stmt q;

  login_check_credentials();
  if( !g.perm.Read || !g.perm.RdTkt || !g.perm.RdWiki ){
    login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki);
    return;
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
  www_print_timeline(&q, TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL,
                     0, 0, 0, rid, 0, 0);
  db_finalize(&q);
  style_footer();
}

/*
** WEBPAGE: vinfo
** WEBPAGE: ci
** URL:  /ci/ARTIFACTID
**  OR:  /ci?name=ARTIFACTID
**
** Display information about a particular check-in.  The exact
** same information is shown on the /info page if the name query
** parameter to /info describes a check-in.
**







|
|







637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
  www_print_timeline(&q, TIMELINE_DISJOINT|TIMELINE_GRAPH|TIMELINE_NOSCROLL,
                     0, 0, 0, rid, 0, 0);
  db_finalize(&q);
  style_footer();
}

/*
** WEBPAGE: ci
** WEBPAGE: vinfo
** URL:  /ci/ARTIFACTID
**  OR:  /ci?name=ARTIFACTID
**
** Display information about a particular check-in.  The exact
** same information is shown on the /info page if the name query
** parameter to /info describes a check-in.
**
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
**      dc=N             Show N lines of context around each diff
**      patch            Use the patch diff format
**      regex=REGEX      Only show differences that match REGEX
**      sbs=BOOLEAN      Turn side-by-side diffs on and off (default: on)
**      verbose=BOOLEAN  Show more detail when describing artifacts
**      w=BOOLEAN        Ignore whitespace
*/
void diff_page(void){
  int v1, v2;
  int isPatch = P("patch")!=0;
  int diffType;          /* 0: none, 1: unified,  2: side-by-side */
  char *zV1;
  char *zV2;
  const char *zRe;
  ReCompiled *pRe = 0;







|







1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
**      dc=N             Show N lines of context around each diff
**      patch            Use the patch diff format
**      regex=REGEX      Only show differences that match REGEX
**      sbs=BOOLEAN      Turn side-by-side diffs on and off (default: on)
**      verbose=BOOLEAN  Show more detail when describing artifacts
**      w=BOOLEAN        Ignore whitespace
*/
void fdiff_page(void){
  int v1, v2;
  int isPatch = P("patch")!=0;
  int diffType;          /* 0: none, 1: unified,  2: side-by-side */
  char *zV1;
  char *zV2;
  const char *zRe;
  ReCompiled *pRe = 0;
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
  if( rid==0 ){
    url_add_parameter(&url, "name", zName);
    if( isFile ){
      /* Do a top-level directory listing in /file mode if no argument
      ** specified */
      if( zName==0 || zName[0]==0 ){
        if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
        page_tree();
        return;
      }
      /* Look for a single file with the given name */
      rid = db_int(0,
         "SELECT fid FROM filename, mlink, event"
         " WHERE name=%Q"
         "   AND mlink.fnid=filename.fnid"







|







2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
  if( rid==0 ){
    url_add_parameter(&url, "name", zName);
    if( isFile ){
      /* Do a top-level directory listing in /file mode if no argument
      ** specified */
      if( zName==0 || zName[0]==0 ){
        if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
        tree_page();
        return;
      }
      /* Look for a single file with the given name */
      rid = db_int(0,
         "SELECT fid FROM filename, mlink, event"
         " WHERE name=%Q"
         "   AND mlink.fnid=filename.fnid"
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
        if( nName && zName[nName-1]=='/' ) nName--;
        if( db_exists(
           "SELECT 1 FROM filename"
           " WHERE name GLOB '%.*q/*' AND substr(name,1,%d)=='%.*q/';",
           nName, zName, nName+1, nName, zName
        ) ){
          if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
          page_tree();
          return;
        }
      }
      /* If no file or directory called NAME: issue an error */
      if( rid==0 ){
        style_header("No such file");
        @ File '%h(zName)' does not exist in this repository.







|







2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
        if( nName && zName[nName-1]=='/' ) nName--;
        if( db_exists(
           "SELECT 1 FROM filename"
           " WHERE name GLOB '%.*q/*' AND substr(name,1,%d)=='%.*q/';",
           nName, zName, nName+1, nName, zName
        ) ){
          if( P("ci")==0 ) cgi_set_query_parameter("ci","tip");
          tree_page();
          return;
        }
      }
      /* If no file or directory called NAME: issue an error */
      if( rid==0 ){
        style_header("No such file");
        @ File '%h(zName)' does not exist in this repository.
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
**
** DATETIME may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in
** year-month-day form, it may be truncated, the "T" may be replaced by
** a space, and it may also name a timezone offset from UTC as "-HH:MM"
** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z"
** means UTC.
*/
void ci_amend_cmd(void){
  int rid;
  const char *zComment;         /* Current comment on the check-in */
  const char *zNewComment;      /* Revised check-in comment */
  const char *zComFile;         /* Filename from which to read comment */
  const char *zUser;            /* Current user for the check-in */
  const char *zNewUser;         /* Revised user */
  const char *zDate;            /* Current date of the check-in */







|







3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
**
** DATETIME may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in
** year-month-day form, it may be truncated, the "T" may be replaced by
** a space, and it may also name a timezone offset from UTC as "-HH:MM"
** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z"
** means UTC.
*/
void amend_cmd(void){
  int rid;
  const char *zComment;         /* Current comment on the check-in */
  const char *zNewComment;      /* Revised check-in comment */
  const char *zComFile;         /* Filename from which to read comment */
  const char *zUser;            /* Current user for the check-in */
  const char *zNewUser;         /* Revised user */
  const char *zDate;            /* Current date of the check-in */
Changes to src/json.c.
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
** For notes regarding the public JSON interface, please see:
**
** https://docs.google.com/document/d/1fXViveNhDbiXgCuE7QDXQOKeFzf2qNUkBEgiUvoqFN4/view
**
**
** Notes for hackers...
**
** Here's how command/page dispatching works: json_page_top() (in HTTP mode) or
** json_cmd_top() (in CLI mode) catch the "json" path/command. Those functions then
** dispatch to a JSON-mode-specific command/page handler with the type fossil_json_f().
** See the API docs for that typedef (below) for the semantics of the callbacks.
**
**
*/
#include "VERSION.h"
#include "config.h"







|
|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
** For notes regarding the public JSON interface, please see:
**
** https://docs.google.com/document/d/1fXViveNhDbiXgCuE7QDXQOKeFzf2qNUkBEgiUvoqFN4/view
**
**
** Notes for hackers...
**
** Here's how command/page dispatching works: json_page() (in HTTP mode) or
** json_cmd() (in CLI mode) catch the "json" path/command. Those functions then
** dispatch to a JSON-mode-specific command/page handler with the type fossil_json_f().
** See the API docs for that typedef (below) for the semantics of the callbacks.
**
**
*/
#include "VERSION.h"
#include "config.h"
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
    ? cson_object_get(g.json.reqPayload.o,pKey)
    : NULL;
}

/*
** Initializes some JSON bits which need to be initialized relatively
** early on. It should only be called from cgi_init() or
** json_cmd_top() (early on in those functions).
**
** Initializes g.json.gc and g.json.param. This code does not (and
** must not) rely on any of the fossil environment having been set
** up. e.g. it must not use cgi_parameter() and friends because this
** must be called before those data are initialized.
*/
void json_main_bootstrap(){







|







709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
    ? cson_object_get(g.json.reqPayload.o,pKey)
    : NULL;
}

/*
** Initializes some JSON bits which need to be initialized relatively
** early on. It should only be called from cgi_init() or
** json_cmd() (early on in those functions).
**
** Initializes g.json.gc and g.json.param. This code does not (and
** must not) rely on any of the fossil environment having been set
** up. e.g. it must not use cgi_parameter() and friends because this
** must be called before those data are initialized.
*/
void json_main_bootstrap(){
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
  }
  return a ? cson_array_value(a) : NULL;
}


/*
** Performs some common initialization of JSON-related state.  Must be
** called by the json_page_top() and json_cmd_top() dispatching
** functions to set up the JSON stat used by the dispatched functions.
**
** Implicitly sets up the login information state in CGI mode, but
** does not perform any permissions checking. It _might_ (haven't
** tested this) die with an error if an auth cookie is malformed.
**
** This must be called by the top-level JSON command dispatching code







|







917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
  }
  return a ? cson_array_value(a) : NULL;
}


/*
** Performs some common initialization of JSON-related state.  Must be
** called by the json_page() and json_cmd() dispatching
** functions to set up the JSON stat used by the dispatched functions.
**
** Implicitly sets up the login information state in CGI mode, but
** does not perform any permissions checking. It _might_ (haven't
** tested this) die with an error if an auth cookie is malformed.
**
** This must be called by the top-level JSON command dispatching code
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
{"whoami",json_page_whoami,0},
{"wiki",json_page_wiki,0},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};

/*
** Internal helper for json_cmd_top() and json_page_top().
**
** Searches JsonPageDefs for a command with the given name. If found,
** it is used to generate and output a JSON response. If not found, it
** generates a JSON-style error response. Returns 0 on success, non-0
** on error. On error it will set g.json's error state.
*/
static int json_dispatch_root_command( char const * zCommand ){







|







2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
{"whoami",json_page_whoami,0},
{"wiki",json_page_wiki,0},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};

/*
** Internal helper for json_cmd() and json_page().
**
** Searches JsonPageDefs for a command with the given name. If found,
** it is used to generate and output a JSON response. If not found, it
** generates a JSON-style error response. Returns 0 on success, non-0
** on error. On error it will set g.json's error state.
*/
static int json_dispatch_root_command( char const * zCommand ){
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
#ifdef FOSSIL_ENABLE_JSON
/* dupe ifdef needed for mkindex */
/*
** WEBPAGE: json
**
** Pages under /json/... must be entered into JsonPageDefs.
** This function dispatches them, and is the HTTP equivalent of
** json_cmd_top().
*/
void json_page_top(void){
  char const * zCommand;
  assert(g.json.gc.a && "json_main_bootstrap() was not called!");
  json_mode_bootstrap();
  zCommand = json_command_arg(1);
  if(!zCommand || !*zCommand){
    json_dispatch_missing_args_err( JsonPageDefs,
                                    "No command (sub-path) specified."
                                    " Try one of: ");
    return;
  }
  json_dispatch_root_command( zCommand );
}
#endif /* FOSSIL_ENABLE_JSON for mkindex */

#ifdef FOSSIL_ENABLE_JSON
/* dupe ifdef needed for mkindex */
/*
** This function dispatches json commands and is the CLI equivalent of
** json_page_top().
**
** COMMAND: json
**
** Usage: %fossil json SUBCOMMAND ?OPTIONS?
**
** 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







|

|


















|







2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
#ifdef FOSSIL_ENABLE_JSON
/* dupe ifdef needed for mkindex */
/*
** WEBPAGE: json
**
** Pages under /json/... must be entered into JsonPageDefs.
** This function dispatches them, and is the HTTP equivalent of
** json_cmd().
*/
void json_page(void){
  char const * zCommand;
  assert(g.json.gc.a && "json_main_bootstrap() was not called!");
  json_mode_bootstrap();
  zCommand = json_command_arg(1);
  if(!zCommand || !*zCommand){
    json_dispatch_missing_args_err( JsonPageDefs,
                                    "No command (sub-path) specified."
                                    " Try one of: ");
    return;
  }
  json_dispatch_root_command( zCommand );
}
#endif /* FOSSIL_ENABLE_JSON for mkindex */

#ifdef FOSSIL_ENABLE_JSON
/* dupe ifdef needed for mkindex */
/*
** This function dispatches json commands and is the CLI equivalent of
** json_page().
**
** COMMAND: json
**
** Usage: %fossil json SUBCOMMAND ?OPTIONS?
**
** 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
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
**   whoami
**   wiki
**
** Run '%fossil json' without any subcommand to see the full list (but be
** aware that some listed might not yet be fully implemented).
**
*/
void json_cmd_top(void){
  char const * cmd = NULL;
  int rc = 0;
  memset( &g.perm, 0xff, sizeof(g.perm) )
    /* In CLI mode fossil does not use permissions
       and they all default to false. We enable them
       here because (A) fossil doesn't use them in local
       mode but (B) having them set gives us one less







|







2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
**   whoami
**   wiki
**
** Run '%fossil json' without any subcommand to see the full list (but be
** aware that some listed might not yet be fully implemented).
**
*/
void json_cmd(void){
  char const * cmd = NULL;
  int rc = 0;
  memset( &g.perm, 0xff, sizeof(g.perm) )
    /* In CLI mode fossil does not use permissions
       and they all default to false. We enable them
       here because (A) fossil doesn't use them in local
       mode but (B) having them set gives us one less
Changes to src/leaf.c.
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
** COMMAND: test-leaf-ambiguity
**
** Usage: %fossil NAME ...
**
** Resolve each name on the command line and call leaf_ambiguity_warning()
** for each resulting RID.
*/
void leaf_ambiguity_warning_test(void){
  int i;
  int rid;
  int rc;
  db_find_and_open_repository(0,0);
  verify_all_options();
  for(i=2; i<g.argc; i++){
    char *zUuid;







|







249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
** COMMAND: test-leaf-ambiguity
**
** Usage: %fossil NAME ...
**
** Resolve each name on the command line and call leaf_ambiguity_warning()
** for each resulting RID.
*/
void test_leaf_ambiguity_cmd(void){
  int i;
  int rid;
  int rc;
  db_find_and_open_repository(0,0);
  verify_all_options();
  for(i=2; i<g.argc; i++){
    char *zUuid;
Changes to src/loadctrl.c.
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/*
** COMMAND: test-loadavg
**
** %fossil test-loadavg
**
** Print the load average on the host machine.
*/
void loadavg_test_cmd(void){
  fossil_print("load-average: %f\n", load_average());
}

/*
** Abort the current operation of the load average of the host computer
** is too high.
*/







|







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/*
** COMMAND: test-loadavg
**
** %fossil test-loadavg
**
** Print the load average on the host machine.
*/
void test_loadavg_cmd(void){
  fossil_print("load-average: %f\n", load_average());
}

/*
** Abort the current operation of the load average of the host computer
** is too high.
*/
Changes to src/login.c.
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
/*
** COMMAND: test-ishuman
**
** Read lines of text from standard input.  Interpret each line of text
** as a User-Agent string from an HTTP header.  Label each line as HUMAN
** or ROBOT.
*/
void test_ishuman(void){
  char zLine[3000];
  while( fgets(zLine, sizeof(zLine), stdin) ){
    fossil_print("%s %s", isHuman(zLine) ? "HUMAN" : "ROBOT", zLine);
  }
}

/*







|







419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
/*
** COMMAND: test-ishuman
**
** Read lines of text from standard input.  Interpret each line of text
** as a User-Agent string from an HTTP header.  Label each line as HUMAN
** or ROBOT.
*/
void test_ishuman_cmd(void){
  char zLine[3000];
  while( fgets(zLine, sizeof(zLine), stdin) ){
    fossil_print("%s %s", isHuman(zLine) ? "HUMAN" : "ROBOT", zLine);
  }
}

/*
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
** A login-group is a set of repositories that share user credentials.
** If a user is logged into one member of the group, then that user can
** access any other group member as long as they have an entry in the
** USER table of that member.  If a user changes their password using
** web interface, their password is also automatically changed in every
** other member of the login group.
*/
void login_group_command(void){
  const char *zLGName;
  const char *zCmd;
  int nCmd;
  Stmt q;
  db_find_and_open_repository(0,0);
  if( g.argc>2 ){
    zCmd = g.argv[2];







|







1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
** A login-group is a set of repositories that share user credentials.
** If a user is logged into one member of the group, then that user can
** access any other group member as long as they have an entry in the
** USER table of that member.  If a user changes their password using
** web interface, their password is also automatically changed in every
** other member of the login group.
*/
void login_group_cmd(void){
  const char *zLGName;
  const char *zCmd;
  int nCmd;
  Stmt q;
  db_find_and_open_repository(0,0);
  if( g.argc>2 ){
    zCmd = g.argv[2];
Changes to src/lookslike.c.
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
**                     performance measurement. Default = 1;
**    --utf8           Ignoring BOM and file size, force UTF-8 checking
**    --utf16          Ignoring BOM and file size, force UTF-16 checking
**
** FILENAME is the name of a file to check for textual content in the UTF-8
** and/or UTF-16 encodings.
*/
void looks_like_utf_test_cmd(void){
  Blob blob;         /* the contents of the specified file */
  int fUtf8 = 0;     /* return value of starts_with_utf8_bom() */
  int fUtf16 = 0;    /* return value of starts_with_utf16_bom() */
  int fUnicode = 0;  /* return value of could_be_utf16() */
  int lookFlags = 0; /* output flags from looks_like_utf8/utf16() */
  int bRevUtf16 = 0; /* non-zero -> UTF-16 byte order reversed */
  int fForceUtf8 = find_option("utf8",0,0)!=0;







|







406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
**                     performance measurement. Default = 1;
**    --utf8           Ignoring BOM and file size, force UTF-8 checking
**    --utf16          Ignoring BOM and file size, force UTF-16 checking
**
** FILENAME is the name of a file to check for textual content in the UTF-8
** and/or UTF-16 encodings.
*/
void test_looks_like_utf_cmd(void){
  Blob blob;         /* the contents of the specified file */
  int fUtf8 = 0;     /* return value of starts_with_utf8_bom() */
  int fUtf16 = 0;    /* return value of starts_with_utf16_bom() */
  int fUnicode = 0;  /* return value of could_be_utf16() */
  int lookFlags = 0; /* output flags from looks_like_utf8/utf16() */
  int bRevUtf16 = 0; /* non-zero -> UTF-16 byte order reversed */
  int fForceUtf8 = find_option("utf8",0,0)!=0;
Changes to src/main.c.
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
**
** Show the version information for Fossil.
**
** Query parameters:
**
**    verbose       Show details
*/
void test_version_page(void){
  Blob versionInfo;
  int verboseFlag;

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  verboseFlag = PD("verbose", 0) != 0;
  style_header("Version Information");







|







1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
**
** Show the version information for Fossil.
**
** Query parameters:
**
**    verbose       Show details
*/
void version_page(void){
  Blob versionInfo;
  int verboseFlag;

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  verboseFlag = PD("verbose", 0) != 0;
  style_header("Version Information");
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
        }
        if( !g.fNoThHook && (rc==TH_OK || rc==TH_CONTINUE) ){
          Th_WebpageNotify(g.zPath, 0);
        }
      }
#endif
    }
  }else if( pCmd->xFunc!=page_xfer && db_schema_is_outofdate() ){
#ifdef FOSSIL_ENABLE_JSON
    if(g.json.isJsonMode){
      json_err(FSL_JSON_E_DB_NEEDS_REBUILD,NULL,0);
    }else
#endif
    {
      @ <h1>Server Configuration Error</h1>







|







1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
        }
        if( !g.fNoThHook && (rc==TH_OK || rc==TH_CONTINUE) ){
          Th_WebpageNotify(g.zPath, 0);
        }
      }
#endif
    }
  }else if( pCmd->xFunc!=xfer_page && db_schema_is_outofdate() ){
#ifdef FOSSIL_ENABLE_JSON
    if(g.json.isJsonMode){
      json_err(FSL_JSON_E_DB_NEEDS_REBUILD,NULL,0);
    }else
#endif
    {
      @ <h1>Server Configuration Error</h1>
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
**                             an unconditional redirect to URL is taken.
**
** Most CGI files contain only a "repository:" line.  It is uncommon to
** use any other option.
**
** See also: http, server, winsrv
*/
void cmd_cgi(void){
  const char *zFile;
  const char *zNotFound = 0;
  char **azRedirect = 0;             /* List of repositories to redirect to */
  int nRedirect = 0;                 /* Number of entries in azRedirect */
  Glob *pFileGlob = 0;               /* Pattern for files */
  int allowRepoList = 0;             /* Allow lists of repository files */
  Blob config, line, key, value, value2;







|







2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
**                             an unconditional redirect to URL is taken.
**
** Most CGI files contain only a "repository:" line.  It is uncommon to
** use any other option.
**
** See also: http, server, winsrv
*/
void cgi_cmd(void){
  const char *zFile;
  const char *zNotFound = 0;
  char **azRedirect = 0;             /* List of repositories to redirect to */
  int nRedirect = 0;                 /* Number of entries in azRedirect */
  Glob *pFileGlob = 0;               /* Pattern for files */
  int allowRepoList = 0;             /* Allow lists of repository files */
  Blob config, line, key, value, value2;
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
**   --skin LABEL     Use override skin LABEL
**   --th-trace       trace TH1 execution (for debugging purposes)
**   --usepidkey      Use saved encryption key from parent process.  This is
**                    only necessary when using SEE on Windows.
**
** See also: cgi, server, winsrv
*/
void cmd_http(void){
  const char *zIpAddr = 0;
  const char *zNotFound;
  const char *zHost;
  const char *zAltBase;
  const char *zFileGlob;
  const char *zInFile;
  const char *zOutFile;







|







2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
**   --skin LABEL     Use override skin LABEL
**   --th-trace       trace TH1 execution (for debugging purposes)
**   --usepidkey      Use saved encryption key from parent process.  This is
**                    only necessary when using SEE on Windows.
**
** See also: cgi, server, winsrv
*/
void http_cmd(void){
  const char *zIpAddr = 0;
  const char *zNotFound;
  const char *zHost;
  const char *zAltBase;
  const char *zFileGlob;
  const char *zInFile;
  const char *zOutFile;
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
**
** Works like the http command but gives setup permission to all users.
**
** Options:
**   --th-trace          trace TH1 execution (for debugging purposes)
**
*/
void cmd_test_http(void){
  const char *zIpAddr;    /* IP address of remote client */

  Th_InitTraceLog();
  login_set_capabilities("sx", 0);
  g.useLocalauth = 1;
  g.httpIn = stdin;
  g.httpOut = stdout;







|







2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
**
** Works like the http command but gives setup permission to all users.
**
** Options:
**   --th-trace          trace TH1 execution (for debugging purposes)
**
*/
void test_http_cmd(void){
  const char *zIpAddr;    /* IP address of remote client */

  Th_InitTraceLog();
  login_set_capabilities("sx", 0);
  g.useLocalauth = 1;
  g.httpIn = stdin;
  g.httpOut = stdout;
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
**   --scgi              Accept SCGI rather than HTTP
**   --skin LABEL        Use override skin LABEL
**   --usepidkey         Use saved encryption key from parent process.  This is
**                       only necessary when using SEE on Windows.
**
** See also: cgi, http, winsrv
*/
void cmd_webserver(void){
  int iPort, mxPort;        /* Range of TCP ports allowed */
  const char *zPort;        /* Value of the --port option */
  const char *zBrowser;     /* Name of web browser program */
  char *zBrowserCmd = 0;    /* Command to launch the web browser */
  int isUiCmd;              /* True if command is "ui", not "server' */
  const char *zNotFound;    /* The --notfound option or NULL */
  int flags = 0;            /* Server flags */







|







2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
**   --scgi              Accept SCGI rather than HTTP
**   --skin LABEL        Use override skin LABEL
**   --usepidkey         Use saved encryption key from parent process.  This is
**                       only necessary when using SEE on Windows.
**
** See also: cgi, http, winsrv
*/
void webserver_cmd(void){
  int iPort, mxPort;        /* Range of TCP ports allowed */
  const char *zPort;        /* Value of the --port option */
  const char *zBrowser;     /* Name of web browser program */
  char *zBrowserCmd = 0;    /* Command to launch the web browser */
  int isUiCmd;              /* True if command is "ui", not "server' */
  const char *zNotFound;    /* The --notfound option or NULL */
  int flags = 0;            /* Server flags */
Changes to src/manifest.c.
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
** COMMAND: test-parse-manifest
**
** Usage: %fossil test-parse-manifest FILENAME ?N?
**
** Parse the manifest(s) given on the command-line and report any
** errors.  If the N argument is given, run the parsing N times.
*/
void manifest_test_parse_cmd(void){
  Manifest *p;
  Blob b;
  int i;
  int n = 1;
  db_find_and_open_repository(0,0);
  verify_all_options();
  if( g.argc!=3 && g.argc!=4 ){







|







1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
** COMMAND: test-parse-manifest
**
** Usage: %fossil test-parse-manifest FILENAME ?N?
**
** Parse the manifest(s) given on the command-line and report any
** errors.  If the N argument is given, run the parsing N times.
*/
void test_parse_manifest_cmd(void){
  Manifest *p;
  Blob b;
  int i;
  int n = 1;
  db_find_and_open_repository(0,0);
  verify_all_options();
  if( g.argc!=3 && g.argc!=4 ){
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
** Parse all entries in the BLOB table that are believed to be non-data
** artifacts and report any errors.  Run this test command on historical
** repositories after making any changes to the manifest_parse()
** implementation to confirm that the changes did not break anything.
**
** If the --limit N argument is given, parse no more than N blobs
*/
void manifest_test_parse_all_blobs_cmd(void){
  Manifest *p;
  Blob err;
  Stmt q;
  int nTest = 0;
  int nErr = 0;
  int N = 1000000000;
  const char *z;







|







1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
** Parse all entries in the BLOB table that are believed to be non-data
** artifacts and report any errors.  Run this test command on historical
** repositories after making any changes to the manifest_parse()
** implementation to confirm that the changes did not break anything.
**
** If the --limit N argument is given, parse no more than N blobs
*/
void test_parse_all_blobs_cmd(void){
  Manifest *p;
  Blob err;
  Stmt q;
  int nTest = 0;
  int nErr = 0;
  int N = 1000000000;
  const char *z;
Changes to src/md5.c.
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
** COMMAND: md5sum*
**
** Usage: %fossil md5sum FILES....
**
** Compute an MD5 checksum of all files named on the command-line.
** If a file is named "-" then content is read from standard input.
*/
void md5sum_test(void){
  int i;
  Blob in;
  Blob cksum;

  for(i=2; i<g.argc; i++){
    blob_init(&cksum, "********** not found ***********", -1);
    if( g.argv[i][0]=='-' && g.argv[i][1]==0 ){







|







440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
** COMMAND: md5sum*
**
** Usage: %fossil md5sum FILES....
**
** Compute an MD5 checksum of all files named on the command-line.
** If a file is named "-" then content is read from standard input.
*/
void md5sum_cmd(void){
  int i;
  Blob in;
  Blob cksum;

  for(i=2; i<g.argc; i++){
    blob_init(&cksum, "********** not found ***********", -1);
    if( g.argv[i][0]=='-' && g.argv[i][1]==0 ){
Changes to src/name.c.
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
** COMMAND: test-name-to-id
**
** Usage:  %fossil test-name-to-id [--count N] NAME
**
** Convert a NAME to a full artifact ID.  Repeat the conversion N
** times (for timing purposes) if the --count option is given.
*/
void test_name_to_id(void){
  int i;
  int n = 0;
  Blob name;
  db_must_be_within_tree();
  for(i=2; i<g.argc; i++){
    if( strcmp(g.argv[i],"--count")==0 && i+1<g.argc ){
      i++;







|







528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
** COMMAND: test-name-to-id
**
** Usage:  %fossil test-name-to-id [--count N] NAME
**
** Convert a NAME to a full artifact ID.  Repeat the conversion N
** times (for timing purposes) if the --count option is given.
*/
void test_name_to_id_cmd(void){
  int i;
  int n = 0;
  Blob name;
  db_must_be_within_tree();
  for(i=2; i<g.argc; i++){
    if( strcmp(g.argv[i],"--count")==0 && i+1<g.argc ){
      i++;
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
/*
** COMMAND: test-unclustered
**
** Usage: %fossil test-unclustered
**
** Show all artifacts in the unclustered table
*/
void test_unclusterd_cmd(void){
  db_find_and_open_repository(0,0);
  describe_artifacts_to_stdout("IN unclustered", 0);
}

/*
** COMMAND: test-phantoms
**
** Usage: %fossil test-phantoms
**
** Show all phantom artifacts
*/
void test_phatoms_cmd(void){
  db_find_and_open_repository(0,0);
  describe_artifacts_to_stdout("IN (SELECT rid FROM blob WHERE size<0)", 0);
}

/* Maximum number of collision examples to remember */
#define MAX_COLLIDE 25








|











|







1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
/*
** COMMAND: test-unclustered
**
** Usage: %fossil test-unclustered
**
** Show all artifacts in the unclustered table
*/
void test_unclustered_cmd(void){
  db_find_and_open_repository(0,0);
  describe_artifacts_to_stdout("IN unclustered", 0);
}

/*
** COMMAND: test-phantoms
**
** Usage: %fossil test-phantoms
**
** Show all phantom artifacts
*/
void test_phantoms_cmd(void){
  db_find_and_open_repository(0,0);
  describe_artifacts_to_stdout("IN (SELECT rid FROM blob WHERE size<0)", 0);
}

/* Maximum number of collision examples to remember */
#define MAX_COLLIDE 25

1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
}

/*
** WEBPAGE: hash-collisions
**
** Show the number of hash collisions for hash prefixes of various lengths.
*/
void hash_collisions_webpage(void){
  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  style_header("Hash Prefix Collisions");
  style_submenu_element("Activity Reports", "reports");
  style_submenu_element("Stats", "stat");
  @ <h1>Hash Prefix Collisions on Check-ins</h1>
  collision_report("SELECT (SELECT uuid FROM blob WHERE rid=objid)"
                   "  FROM event WHERE event.type='ci'"
                   " ORDER BY 1");
  @ <h1>Hash Prefix Collisions on All Artifacts</h1>
  collision_report("SELECT uuid FROM blob ORDER BY 1");
  style_footer();
}







|













1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
}

/*
** WEBPAGE: hash-collisions
**
** Show the number of hash collisions for hash prefixes of various lengths.
*/
void hash_collisions_page(void){
  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  style_header("Hash Prefix Collisions");
  style_submenu_element("Activity Reports", "reports");
  style_submenu_element("Stats", "stat");
  @ <h1>Hash Prefix Collisions on Check-ins</h1>
  collision_report("SELECT (SELECT uuid FROM blob WHERE rid=objid)"
                   "  FROM event WHERE event.type='ci'"
                   " ORDER BY 1");
  @ <h1>Hash Prefix Collisions on All Artifacts</h1>
  collision_report("SELECT uuid FROM blob ORDER BY 1");
  style_footer();
}
Changes to src/path.c.
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
** COMMAND: test-shortest-path
**
** Usage: %fossil test-shortest-path ?--no-merge? VERSION1 VERSION2
**
** Report the shortest path between two check-ins.  If the --no-merge flag
** is used, follow only direct parent-child paths and omit merge links.
*/
void shortest_path_test_cmd(void){
  int iFrom;
  int iTo;
  PathNode *p;
  int n;
  int directOnly;
  int oneWay;








|







241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
** COMMAND: test-shortest-path
**
** Usage: %fossil test-shortest-path ?--no-merge? VERSION1 VERSION2
**
** Report the shortest path between two check-ins.  If the --no-merge flag
** is used, follow only direct parent-child paths and omit merge links.
*/
void test_shortest_path_cmd(void){
  int iFrom;
  int iTo;
  PathNode *p;
  int n;
  int directOnly;
  int oneWay;

347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
** COMMAND: test-ancestor-path
**
** Usage: %fossil test-ancestor-path VERSION1 VERSION2
**
** Report the path from VERSION1 to VERSION2 through their most recent
** common ancestor.
*/
void ancestor_path_test_cmd(void){
  int iFrom;
  int iTo;
  int iPivot;
  PathNode *p;
  int n;

  db_find_and_open_repository(0,0);







|







347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
** COMMAND: test-ancestor-path
**
** Usage: %fossil test-ancestor-path VERSION1 VERSION2
**
** Report the path from VERSION1 to VERSION2 through their most recent
** common ancestor.
*/
void test_ancestor_path_cmd(void){
  int iFrom;
  int iTo;
  int iPivot;
  PathNode *p;
  int n;

  db_find_and_open_repository(0,0);
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
/*
** COMMAND: test-name-changes
**
** Usage: %fossil test-name-changes [--debug] VERSION1 VERSION2
**
** Show all filename changes that occur going from VERSION1 to VERSION2
*/
void test_name_change(void){
  int iFrom;
  int iTo;
  int *aChng;
  int nChng;
  int i;
  const char *zDebug = 0;
  int revOk = 0;







|







519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
/*
** COMMAND: test-name-changes
**
** Usage: %fossil test-name-changes [--debug] VERSION1 VERSION2
**
** Show all filename changes that occur going from VERSION1 to VERSION2
*/
void test_name_changes_cmd(void){
  int iFrom;
  int iTo;
  int *aChng;
  int nChng;
  int i;
  const char *zDebug = 0;
  int revOk = 0;
Changes to src/piechart.c.
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
}

/*
** WEBPAGE: test-piechart
**
** Generate a pie-chart based on data input from a form.
*/
void piechart_test_page(void){
  const char *zData;
  Stmt ins;
  int n = 0;
  int width;
  int height;
  int i, j;








|







263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
}

/*
** WEBPAGE: test-piechart
**
** Generate a pie-chart based on data input from a form.
*/
void test_piechart_page(void){
  const char *zData;
  Stmt ins;
  int n = 0;
  int width;
  int height;
  int i, j;

Changes to src/pivot.c.
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
** Usage: %fossil test-find-pivot ?options? PRIMARY SECONDARY ...
**
** Test the pivot_find() procedure.
**
** Options:
**    --ignore-merges       Ignore merges for discovering name pivots
*/
void test_find_pivot(void){
  int i, rid;
  int ignoreMerges = find_option("ignore-merges",0,0)!=0;
  int showDetails = find_option("details",0,0)!=0;
  if( g.argc<4 ){
    usage("?options? PRIMARY SECONDARY ...");
  }
  db_must_be_within_tree();







|







159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
** Usage: %fossil test-find-pivot ?options? PRIMARY SECONDARY ...
**
** Test the pivot_find() procedure.
**
** Options:
**    --ignore-merges       Ignore merges for discovering name pivots
*/
void test_find_pivot_cmd(void){
  int i, rid;
  int ignoreMerges = find_option("ignore-merges",0,0)!=0;
  int showDetails = find_option("details",0,0)!=0;
  if( g.argc<4 ){
    usage("?options? PRIMARY SECONDARY ...");
  }
  db_must_be_within_tree();
Changes to src/rebuild.c.
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
  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
** ability of fossil to accept records in any order and still
** construct a sane repository.







|







356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
  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_cmd' ('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
** ability of fossil to accept records in any order and still
** construct a sane repository.
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
**   --randomize       Scan artifacts in a random order
**   --stats           Show artifact statistics after rebuilding
**   --vacuum          Run VACUUM on the database after rebuilding
**   --wal             Set Write-Ahead-Log journalling mode on the database
**
** See also: deconstruct, reconstruct
*/
void rebuild_database(void){
  int forceFlag;
  int randomizeFlag;
  int errCnt = 0;
  int omitVerify;
  int doClustering;
  const char *zPagesize;
  int newPagesize = 0;







|







602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
**   --randomize       Scan artifacts in a random order
**   --stats           Show artifact statistics after rebuilding
**   --vacuum          Run VACUUM on the database after rebuilding
**   --wal             Set Write-Ahead-Log journalling mode on the database
**
** See also: deconstruct, reconstruct
*/
void rebuild_database_cmd(void){
  int forceFlag;
  int randomizeFlag;
  int errCnt = 0;
  int omitVerify;
  int doClustering;
  const char *zPagesize;
  int newPagesize = 0;
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785

/*
** COMMAND: test-create-clusters
**
** Create clusters for all unclustered artifacts if the number of unclustered
** artifacts exceeds the current clustering threshold.
*/
void test_createcluster_cmd(void){
  if( g.argc==3 ){
    db_open_repository(g.argv[2]);
  }else{
    db_find_and_open_repository(0, 0);
    if( g.argc!=2 ){
      usage("?REPOSITORY-FILENAME?");
    }







|







771
772
773
774
775
776
777
778
779
780
781
782
783
784
785

/*
** COMMAND: test-create-clusters
**
** Create clusters for all unclustered artifacts if the number of unclustered
** artifacts exceeds the current clustering threshold.
*/
void test_create_clusters_cmd(void){
  if( g.argc==3 ){
    db_open_repository(g.argv[2]);
  }else{
    db_find_and_open_repository(0, 0);
    if( g.argc!=2 ){
      usage("?REPOSITORY-FILENAME?");
    }
Changes to src/regexp.c.
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
** Run a regular expression match over the named disk files, or against
** standard input if no disk files are named on the command-line.
**
** Options:
**
**   -i|--ignore-case    Ignore case
*/
void re_test_grep(void){
  ReCompiled *pRe;
  const char *zErr;
  int ignoreCase = find_option("ignore-case","i",0)!=0;
  if( g.argc<3 ){
    usage("REGEXP [FILE...]");
  }
  zErr = re_compile(&pRe, g.argv[2], ignoreCase);







|







762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
** Run a regular expression match over the named disk files, or against
** standard input if no disk files are named on the command-line.
**
** Options:
**
**   -i|--ignore-case    Ignore case
*/
void test_grep_cmd(void){
  ReCompiled *pRe;
  const char *zErr;
  int ignoreCase = find_option("ignore-case","i",0)!=0;
  if( g.argc<3 ){
    usage("REGEXP [FILE...]");
  }
  zErr = re_compile(&pRe, g.argv[2], ignoreCase);
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
**     --once                     Stop searching after the first match
**     -s|--no-messages           Suppress error messages about nonexistant
**                                or unreadable files
**     -v|--invert-match          Invert the sense of matching.  Show only
**                                files that have no matches. Implies -l
**     --verbose                  Show each file as it is analyzed
*/
void re_grep_cmd(void){
  u32 flags = 0;
  int bVerbose = 0;
  ReCompiled *pRe;
  const char *zErr;
  int ignoreCase = 0;
  Blob fullName;
  int ii;







|







815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
**     --once                     Stop searching after the first match
**     -s|--no-messages           Suppress error messages about nonexistant
**                                or unreadable files
**     -v|--invert-match          Invert the sense of matching.  Show only
**                                files that have no matches. Implies -l
**     --verbose                  Show each file as it is analyzed
*/
void grep_cmd(void){
  u32 flags = 0;
  int bVerbose = 0;
  ReCompiled *pRe;
  const char *zErr;
  int ignoreCase = 0;
  Blob fullName;
  int ii;
Changes to src/repolist.c.
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
** COMMAND: test-list-page
**
** Usage: %fossil test-list-page DIRECTORY
**
** Show all repositories underneath DIRECTORY.  Or if DIRECTORY is "/"
** show all repositories in the ~/.fossil file.
*/
void test_list_page(void){
  if( g.argc<3 ){
    g.zRepositoryName = "/";
  }else{
    g.zRepositoryName = g.argv[2];
  }
  g.httpOut = stdout;
  repo_list_page();







|







274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
** COMMAND: test-list-page
**
** Usage: %fossil test-list-page DIRECTORY
**
** Show all repositories underneath DIRECTORY.  Or if DIRECTORY is "/"
** show all repositories in the ~/.fossil file.
*/
void test_list_page_cmd(void){
  if( g.argc<3 ){
    g.zRepositoryName = "/";
  }else{
    g.zRepositoryName = g.argv[2];
  }
  g.httpOut = stdout;
  repo_list_page();
Changes to src/report.c.
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#endif

/*
** WEBPAGE: reportlist
**
** Main menu for Tickets.
*/
void view_list(void){
  const char *zScript;
  Blob ril;   /* Report Item List */
  Stmt q;
  int rn = 0;
  int cnt = 0;

  login_check_credentials();







|







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#endif

/*
** WEBPAGE: reportlist
**
** Main menu for Tickets.
*/
void reportlist_page(void){
  const char *zScript;
  Blob ril;   /* Report Item List */
  Stmt q;
  int rn = 0;
  int cnt = 0;

  login_check_credentials();
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
/*
** WEBPAGE: rptsql
** URL: /rptsql?rn=N
**
** Display the SQL query used to generate a ticket report.  The rn=N
** query parameter identifies the specific report number to be displayed.
*/
void view_see_sql(void){
  int rn;
  const char *zTitle;
  const char *zSQL;
  const char *zOwner;
  const char *zClrKey;
  Stmt q;








|







297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
/*
** WEBPAGE: rptsql
** URL: /rptsql?rn=N
**
** Display the SQL query used to generate a ticket report.  The rn=N
** query parameter identifies the specific report number to be displayed.
*/
void rptsql_page(void){
  int rn;
  const char *zTitle;
  const char *zSQL;
  const char *zOwner;
  const char *zClrKey;
  Stmt q;

355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
**
**     rn=N           Ticket report number. (required)
**     t=TITLE        Title of the report format
**     w=USER         Owner of the report format
**     s=SQL          SQL text used to implement the report
**     k=KEY          Color key
*/
void view_edit(void){
  int rn;
  const char *zTitle;
  const char *z;
  const char *zOwner;
  const char *zClrKey;
  char *zSQL;
  char *zErr = 0;







|







355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
**
**     rn=N           Ticket report number. (required)
**     t=TITLE        Title of the report format
**     w=USER         Owner of the report format
**     s=SQL          SQL text used to implement the report
**     k=KEY          Color key
*/
void rptedit_page(void){
  int rn;
  const char *zTitle;
  const char *z;
  const char *zOwner;
  const char *zClrKey;
  char *zSQL;
  char *zErr = 0;
Changes to src/rss.c.
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
** filters for a tag, and wiki=NAME for a wiki page. Only one may be used.
**
** In addition, name=FILENAME filters for a specific file. This may be
** combined with one of the other filters (useful for looking at a specific
** branch).
*/

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







|







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
** filters for a tag, and wiki=NAME for a wiki page. Only one may be used.
**
** In addition, name=FILENAME filters for a specific file. This may be
** combined with one of the other filters (useful for looking at a specific
** branch).
*/

void timeline_rss_page(void){
  Stmt q;
  int nLine=0;
  char *zPubDate, *zProjectName, *zProjectDescr, *zFreeProjectName=0;
  Blob bSQL;
  const char *zType = PD("y","all"); /* Type of events.  All if NULL */
  const char *zTicketUuid = PD("tkt",NULL);
  const char *zTag = PD("tag",NULL);
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
**   filters for a specific file. This may be combined with one of the other
**   filters (useful for looking at a specific branch).
**
** -url STRING
**   Sets the RSS feed's root URL to the given string. The default is
** "URL-PLACEHOLDER" (without quotes).
*/
void cmd_timeline_rss(void){
  Stmt q;
  int nLine=0;
  char *zPubDate, *zProjectName, *zProjectDescr, *zFreeProjectName=0;
  Blob bSQL;
  const char *zType = find_option("type","y",1); /* Type of events.  All if NULL */
  const char *zTicketUuid = find_option("tkt",NULL,1);
  const char *zTag = find_option("tag",NULL,1);







|







248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
**   filters for a specific file. This may be combined with one of the other
**   filters (useful for looking at a specific branch).
**
** -url STRING
**   Sets the RSS feed's root URL to the given string. The default is
** "URL-PLACEHOLDER" (without quotes).
*/
void timeline_rss_cmd(void){
  Stmt q;
  int nLine=0;
  char *zPubDate, *zProjectName, *zProjectDescr, *zFreeProjectName=0;
  Blob bSQL;
  const char *zType = find_option("type","y",1); /* Type of events.  All if NULL */
  const char *zTicketUuid = find_option("tkt",NULL,1);
  const char *zTag = find_option("tag",NULL,1);
Changes to src/search.c.
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
** Usage: fossil test-search-stext TYPE RID NAME
**
** Compute the search text for document TYPE-RID whose name is NAME.
** The TYPE is one of "c", "d", "t", "w", or "e".  The RID is the document
** ID.  The NAME is used to figure out a mimetype to use for formatting
** the raw document text.
*/
void test_search_stext(void){
  Blob out;
  db_find_and_open_repository(0,0);
  if( g.argc!=5 ) usage("TYPE RID NAME");
  search_stext(g.argv[2][0], atoi(g.argv[3]), g.argv[4], &out);
  fossil_print("%s\n",blob_str(&out));
  blob_reset(&out);
}

/*
** COMMAND: test-convert-stext
**
** Usage: fossil test-convert-stext FILE MIMETYPE
**
** Read the content of FILE and convert it to stext according to MIMETYPE.
** Send the result to standard output.
*/
void test_convert_stext(void){
  Blob in, out;
  db_find_and_open_repository(0,0);
  if( g.argc!=4 ) usage("FILENAME MIMETYPE");
  blob_read_from_file(&in, g.argv[2], ExtFILE);
  blob_init(&out, 0, 0);
  get_stext_by_mimetype(&in, g.argv[3], &out);
  fossil_print("%s\n",blob_str(&out));







|
















|







1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
** Usage: fossil test-search-stext TYPE RID NAME
**
** Compute the search text for document TYPE-RID whose name is NAME.
** The TYPE is one of "c", "d", "t", "w", or "e".  The RID is the document
** ID.  The NAME is used to figure out a mimetype to use for formatting
** the raw document text.
*/
void test_search_stext_cmd(void){
  Blob out;
  db_find_and_open_repository(0,0);
  if( g.argc!=5 ) usage("TYPE RID NAME");
  search_stext(g.argv[2][0], atoi(g.argv[3]), g.argv[4], &out);
  fossil_print("%s\n",blob_str(&out));
  blob_reset(&out);
}

/*
** COMMAND: test-convert-stext
**
** Usage: fossil test-convert-stext FILE MIMETYPE
**
** Read the content of FILE and convert it to stext according to MIMETYPE.
** Send the result to standard output.
*/
void test_convert_stext_cmd(void){
  Blob in, out;
  db_find_and_open_repository(0,0);
  if( g.argc!=4 ) usage("FILENAME MIMETYPE");
  blob_read_from_file(&in, g.argv[2], ExtFILE);
  blob_init(&out, 0, 0);
  get_stext_by_mimetype(&in, g.argv[3], &out);
  fossil_print("%s\n",blob_str(&out));
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
}

/*
** WEBPAGE: test-ftsdocs
**
** Show a table of all documents currently in the search index.
*/
void search_data_page(void){
  Stmt q;
  const char *zId = P("id");
  const char *zType = P("y");
  const char *zIdxed = P("ixed");
  int id;
  int cnt1 = 0, cnt2 = 0, cnt3 = 0;
  login_check_credentials();







|







1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
}

/*
** WEBPAGE: test-ftsdocs
**
** Show a table of all documents currently in the search index.
*/
void test_ftsdocs_page(void){
  Stmt q;
  const char *zId = P("id");
  const char *zType = P("y");
  const char *zIdxed = P("ixed");
  int id;
  int cnt1 = 0, cnt2 = 0, cnt3 = 0;
  login_check_credentials();
Changes to src/setup.c.
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323


/*
** WEBPAGE: setup_access
**
** The access-control settings page.  Requires Setup privileges.
*/
void setup_access(void){
  static const char *const azRedirectOpts[] = {
    "0", "Off",
    "1", "Login Page Only",
    "2", "All Pages"
  };
  login_check_credentials();
  if( !g.perm.Setup ){







|







309
310
311
312
313
314
315
316
317
318
319
320
321
322
323


/*
** WEBPAGE: setup_access
**
** The access-control settings page.  Requires Setup privileges.
*/
void setup_access_page(void){
  static const char *const azRedirectOpts[] = {
    "0", "Off",
    "1", "Login Page Only",
    "2", "All Pages"
  };
  login_check_credentials();
  if( !g.perm.Setup ){
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554

/*
** WEBPAGE: setup_login_group
**
** Change how the current repository participates in a login
** group.
*/
void setup_login_group(void){
  const char *zGroup;
  char *zErrMsg = 0;
  Blob fullName;
  char *zSelfRepo;
  const char *zRepo = PD("repo", "");
  const char *zLogin = PD("login", "");
  const char *zPw = PD("pw", "");







|







540
541
542
543
544
545
546
547
548
549
550
551
552
553
554

/*
** WEBPAGE: setup_login_group
**
** Change how the current repository participates in a login
** group.
*/
void setup_login_group_page(void){
  const char *zGroup;
  char *zErrMsg = 0;
  Blob fullName;
  char *zSelfRepo;
  const char *zRepo = PD("repo", "");
  const char *zLogin = PD("login", "");
  const char *zPw = PD("pw", "");
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677

/*
** WEBPAGE: setup_timeline
**
** Edit administrative settings controlling the display of
** timelines.
*/
void setup_timeline(void){
  double tmDiff;
  char zTmDiff[20];
  static const char *const azTimeFormats[] = {
      "0", "HH:MM",
      "1", "HH:MM:SS",
      "2", "YYYY-MM-DD HH:MM",
      "3", "YYMMDD HH:MM",







|







663
664
665
666
667
668
669
670
671
672
673
674
675
676
677

/*
** WEBPAGE: setup_timeline
**
** Edit administrative settings controlling the display of
** timelines.
*/
void setup_timeline_page(void){
  double tmDiff;
  char zTmDiff[20];
  static const char *const azTimeFormats[] = {
      "0", "HH:MM",
      "1", "HH:MM:SS",
      "2", "YYYY-MM-DD HH:MM",
      "3", "YYMMDD HH:MM",
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816

/*
** WEBPAGE: setup_settings
**
** Change or view miscellaneous settings.  Part of the
** /setup pages requiring Setup privileges.
*/
void setup_settings(void){
  int nSetting;
  int i;
  Setting const *pSet;
  const Setting *aSetting = setting_info(&nSetting);

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







|







802
803
804
805
806
807
808
809
810
811
812
813
814
815
816

/*
** WEBPAGE: setup_settings
**
** Change or view miscellaneous settings.  Part of the
** /setup pages requiring Setup privileges.
*/
void setup_settings_page(void){
  int nSetting;
  int i;
  Setting const *pSet;
  const Setting *aSetting = setting_info(&nSetting);

  login_check_credentials();
  if( !g.perm.Setup ){
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
}

/*
** WEBPAGE: setup_config
**
** The "Admin/Configuration" page.  Requires Setup privilege.
*/
void setup_config(void){
  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed(0);
    return;
  }

  style_header("WWW Configuration");







|







889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
}

/*
** WEBPAGE: setup_config
**
** The "Admin/Configuration" page.  Requires Setup privilege.
*/
void setup_config_page(void){
  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed(0);
    return;
  }

  style_header("WWW Configuration");
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
}

/*
** WEBPAGE: setup_wiki
**
** The "Admin/Wiki" page.  Requires Setup privilege.
*/
void setup_wiki(void){
  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed(0);
    return;
  }

  style_header("Wiki Configuration");







|







985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
}

/*
** WEBPAGE: setup_wiki
**
** The "Admin/Wiki" page.  Requires Setup privilege.
*/
void setup_wiki_page(void){
  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed(0);
    return;
  }

  style_header("Wiki Configuration");
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
}

/*
** WEBPAGE: setup_modreq
**
** Admin page for setting up moderation of tickets and wiki.
*/
void setup_modreq(void){
  login_check_credentials();
  if( !g.perm.Admin ){
    login_needed(0);
    return;
  }

  style_header("Moderator For Wiki And Tickets");







|







1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
}

/*
** WEBPAGE: setup_modreq
**
** Admin page for setting up moderation of tickets and wiki.
*/
void setup_modreq_page(void){
  login_check_credentials();
  if( !g.perm.Admin ){
    login_needed(0);
    return;
  }

  style_header("Moderator For Wiki And Tickets");
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107

/*
** WEBPAGE: setup_adunit
**
** Administrative page for configuring and controlling ad units
** and how they are displayed.
*/
void setup_adunit(void){
  login_check_credentials();
  if( !g.perm.Admin ){
    login_needed(0);
    return;
  }
  db_begin_transaction();
  if( P("clear")!=0 && cgi_csrf_safe(1) ){







|







1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107

/*
** WEBPAGE: setup_adunit
**
** Administrative page for configuring and controlling ad units
** and how they are displayed.
*/
void setup_adunit_page(void){
  login_check_credentials();
  if( !g.perm.Admin ){
    login_needed(0);
    return;
  }
  db_begin_transaction();
  if( P("clear")!=0 && cgi_csrf_safe(1) ){
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
}

/*
** WEBPAGE: setup_logo
**
** Administrative page for changing the logo image.
*/
void setup_logo(void){
  const char *zLogoMtime = db_get_mtime("logo-image", 0, 0);
  const char *zLogoMime = db_get("logo-mimetype","image/gif");
  const char *aLogoImg = P("logoim");
  int szLogoImg = atoi(PD("logoim:bytes","0"));
  const char *zBgMtime = db_get_mtime("background-image", 0, 0);
  const char *zBgMime = db_get("background-mimetype","image/gif");
  const char *aBgImg = P("bgim");







|







1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
}

/*
** WEBPAGE: setup_logo
**
** Administrative page for changing the logo image.
*/
void setup_logo_page(void){
  const char *zLogoMtime = db_get_mtime("logo-image", 0, 0);
  const char *zLogoMime = db_get("logo-mimetype","image/gif");
  const char *aLogoImg = P("logoim");
  int szLogoImg = atoi(PD("logoim:bytes","0"));
  const char *zBgMtime = db_get_mtime("background-image", 0, 0);
  const char *zBgMime = db_get("background-mimetype","image/gif");
  const char *aBgImg = P("bgim");
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342

/*
** WEBPAGE: admin_sql
**
** Run raw SQL commands against the database file using the web interface.
** Requires Setup privileges.
*/
void sql_page(void){
  const char *zQ;
  int go = P("go")!=0;
  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed(0);
    return;
  }







|







1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342

/*
** WEBPAGE: admin_sql
**
** Run raw SQL commands against the database file using the web interface.
** Requires Setup privileges.
*/
void admin_sql_page(void){
  const char *zQ;
  int go = P("go")!=0;
  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed(0);
    return;
  }
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
/*
** WEBPAGE: admin_th1
**
** Run raw TH1 commands using the web interface.  If Tcl integration was
** enabled at compile-time and the "tcl" setting is enabled, Tcl commands
** may be run as well.  Requires Admin privilege.
*/
void th1_page(void){
  const char *zQ = P("q");
  int go = P("go")!=0;
  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed(0);
    return;
  }







|







1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
/*
** WEBPAGE: admin_th1
**
** Run raw TH1 commands using the web interface.  If Tcl integration was
** enabled at compile-time and the "tcl" setting is enabled, Tcl commands
** may be run as well.  Requires Admin privilege.
*/
void admin_th1_page(void){
  const char *zQ = P("q");
  int go = P("go")!=0;
  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed(0);
    return;
  }
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
/*
** WEBPAGE: admin_log
**
** Shows the contents of the admin_log table, which is only created if
** the admin-log setting is enabled. Requires Admin or Setup ('a' or
** 's') permissions.
*/
void page_admin_log(){
  Stmt stLog;
  int limit;                 /* How many entries to show */
  int ofst;                  /* Offset to the first entry */
  int fLogEnabled;
  int counter = 0;
  login_check_credentials();
  if( !g.perm.Admin ){







|







1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
/*
** WEBPAGE: admin_log
**
** Shows the contents of the admin_log table, which is only created if
** the admin-log setting is enabled. Requires Admin or Setup ('a' or
** 's') permissions.
*/
void admin_log_page(){
  Stmt stLog;
  int limit;                 /* How many entries to show */
  int ofst;                  /* Offset to the first entry */
  int fLogEnabled;
  int counter = 0;
  login_check_credentials();
  if( !g.perm.Admin ){
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
}

/*
** WEBPAGE: srchsetup
**
** Configure the search engine.  Requires Admin privilege.
*/
void page_srchsetup(){
  login_check_credentials();
  if( !g.perm.Admin ){
    login_needed(0);
    return;
  }
  style_header("Search Configuration");
  @ <form action="%s(g.zTop)/srchsetup" method="post"><div>







|







1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
}

/*
** WEBPAGE: srchsetup
**
** Configure the search engine.  Requires Admin privilege.
*/
void srchsetup_page(){
  login_check_credentials();
  if( !g.perm.Admin ){
    login_needed(0);
    return;
  }
  style_header("Search Configuration");
  @ <form action="%s(g.zTop)/srchsetup" method="post"><div>
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
}

/*
** WEBPAGE: waliassetup
**
** Configure the URL aliases
*/
void page_waliassetup(){
  Stmt q;
  int cnt = 0;
  Blob namelist;
  login_check_credentials();
  if( !g.perm.Admin ){
    login_needed(0);
    return;







|







1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
}

/*
** WEBPAGE: waliassetup
**
** Configure the URL aliases
*/
void waliassetup_page(){
  Stmt q;
  int cnt = 0;
  Blob namelist;
  login_check_credentials();
  if( !g.perm.Admin ){
    login_needed(0);
    return;
Changes to src/setupuser.c.
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
** Show a list of users.  Clicking on any user jumps to the edit
** screen for that user.  Requires Admin privileges.
**
** Query parameters:
**
**   with=CAP         Only show users that have one or more capabilities in CAP.
*/
void setup_ulist(void){
  Stmt s;
  double rNow;
  const char *zWith = P("with");
  int bUnusedOnly = P("unused")!=0;

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







|







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
** Show a list of users.  Clicking on any user jumps to the edit
** screen for that user.  Requires Admin privileges.
**
** Query parameters:
**
**   with=CAP         Only show users that have one or more capabilities in CAP.
*/
void setup_ulist_page(void){
  Stmt s;
  double rNow;
  const char *zWith = P("with");
  int bUnusedOnly = P("unused")!=0;

  login_check_credentials();
  if( !g.perm.Admin ){
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/*
** WEBPAGE: setup_ulist_notes
**
** A documentation page showing notes about user configuration.  This
** information used to be a side-bar on the user list page, but has been
** factored out for improved presentation.
*/
void setup_ulist_notes(void){
  style_header("User Configuration Notes");
  @ <h1>User Configuration Notes:</h1>
  @ <ol>
  @ <li><p>
  @ Every user, logged in or not, inherits the privileges of
  @ <span class="usertype">nobody</span>.
  @ </p></li>







|







188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/*
** WEBPAGE: setup_ulist_notes
**
** A documentation page showing notes about user configuration.  This
** information used to be a side-bar on the user list page, but has been
** factored out for improved presentation.
*/
void setup_ulist_notes_page(void){
  style_header("User Configuration Notes");
  @ <h1>User Configuration Notes:</h1>
  @ <ol>
  @ <li><p>
  @ Every user, logged in or not, inherits the privileges of
  @ <span class="usertype">nobody</span>.
  @ </p></li>
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247

/*
** WEBPAGE: setup_ucap_list
**
** A documentation page showing the meaning of the various user capabilities
** code letters.
*/
void setup_ucap_list(void){
  style_header("User Capability Codes");
  @ <h1>All capabilities</h1>
  capabilities_table(CAPCLASS_ALL);
  @ <h1>Capabilities associated with checked-in content</h1>
  capabilities_table(CAPCLASS_CODE);
  @ <h1>Capabilities associated with data transfer and sync</h1>
  capabilities_table(CAPCLASS_DATA);







|







233
234
235
236
237
238
239
240
241
242
243
244
245
246
247

/*
** WEBPAGE: setup_ucap_list
**
** A documentation page showing the meaning of the various user capabilities
** code letters.
*/
void setup_ucap_list_page(void){
  style_header("User Capability Codes");
  @ <h1>All capabilities</h1>
  capabilities_table(CAPCLASS_ALL);
  @ <h1>Capabilities associated with checked-in content</h1>
  capabilities_table(CAPCLASS_CODE);
  @ <h1>Capabilities associated with data transfer and sync</h1>
  capabilities_table(CAPCLASS_DATA);
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288

/*
** WEBPAGE: setup_uedit
**
** Edit information about a user or create a new user.
** Requires Admin privileges.
*/
void user_edit(void){
  const char *zId, *zLogin, *zInfo, *zCap, *zPw;
  const char *zGroup;
  const char *zOldLogin;
  int uid, i;
  char *zDeleteVerify = 0;   /* Delete user verification text */
  int higherUser = 0;  /* True if user being edited is SETUP and the */
                       /* user doing the editing is ADMIN.  Disallow editing */







|







274
275
276
277
278
279
280
281
282
283
284
285
286
287
288

/*
** WEBPAGE: setup_uedit
**
** Edit information about a user or create a new user.
** Requires Admin privileges.
*/
void setup_uedit_page(void){
  const char *zId, *zLogin, *zInfo, *zCap, *zPw;
  const char *zGroup;
  const char *zOldLogin;
  int uid, i;
  char *zDeleteVerify = 0;   /* Delete user verification text */
  int higherUser = 0;  /* True if user being edited is SETUP and the */
                       /* user doing the editing is ADMIN.  Disallow editing */
Changes to src/sha1.c.
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
** Options:
**
**    -h, --dereference     If FILE is a symbolic link, compute the hash
**                          on the object that the link points to.  Normally,
**                          the hash is over the name of the object that
**                          the link points to.
*/
void sha1sum_test(void){
  int i;
  Blob in;
  Blob cksum;
  int eFType = SymFILE;
  if( find_option("dereference","h",0)!=0 ){
    eFType = ExtFILE;
  }







|







506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
** Options:
**
**    -h, --dereference     If FILE is a symbolic link, compute the hash
**                          on the object that the link points to.  Normally,
**                          the hash is over the name of the object that
**                          the link points to.
*/
void sha1sum_cmd(void){
  int i;
  Blob in;
  Blob cksum;
  int eFType = SymFILE;
  if( find_option("dereference","h",0)!=0 ){
    eFType = ExtFILE;
  }
Changes to src/sha3.c.
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
**    --384               Compute a SHA3-384 hash
**    --512               Compute a SHA3-512 hash
**    --size N            An N-bit hash.  N must be a multiple of 32 between
**                        128 and 512.
**    -h, --dereference   If FILE is a symbolic link, compute the hash on
**                        the object pointed to, not on the link itself.
*/
void sha3sum_test(void){
  int i;
  Blob in;
  Blob cksum;
  int iSize = 256;
  int eFType = SymFILE;

  if( find_option("dereference","h",0) ) eFType = ExtFILE;







|







636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
**    --384               Compute a SHA3-384 hash
**    --512               Compute a SHA3-512 hash
**    --size N            An N-bit hash.  N must be a multiple of 32 between
**                        128 and 512.
**    -h, --dereference   If FILE is a symbolic link, compute the hash on
**                        the object pointed to, not on the link itself.
*/
void sha3sum_cmd(void){
  int i;
  Blob in;
  Blob cksum;
  int iSize = 256;
  int eFType = SymFILE;

  if( find_option("dereference","h",0) ) eFType = ExtFILE;
Changes to src/skins.c.
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
}

/*
** WEBPAGE: setup_skin_admin
**
** Administrative actions on skins.  For administrators only.
*/
void setup_skin_admin(void){
  const char *z;
  char *zName;
  char *zErr = 0;
  const char *zCurrent = 0;  /* Current skin */
  int i;                     /* Loop counter */
  Stmt q;
  int seenCurrent = 0;







|







446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
}

/*
** WEBPAGE: setup_skin_admin
**
** Administrative actions on skins.  For administrators only.
*/
void setup_skin_admin_page(void){
  const char *z;
  char *zName;
  char *zErr = 0;
  const char *zCurrent = 0;  /* Current skin */
  int i;                     /* Loop counter */
  Stmt q;
  int seenCurrent = 0;
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
**
** Edit aspects of a skin determined by the w= query parameter.
** Requires Admin or Setup privileges.
**
**    w=NUM     -- 0=CSS, 1=footer, 2=header, 3=details, 4=js
**    sk=NUM    -- the draft skin number
*/
void setup_skinedit(void){
  static const struct sSkinAddr {
    const char *zFile;
    const char *zTitle;
    const char *zSubmenu;
  } aSkinAttr[] = {
    /* 0 */ { "css",     "CSS",             "CSS",     },
    /* 1 */ { "footer",  "Page Footer",     "Footer",  },







|







696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
**
** Edit aspects of a skin determined by the w= query parameter.
** Requires Admin or Setup privileges.
**
**    w=NUM     -- 0=CSS, 1=footer, 2=header, 3=details, 4=js
**    sk=NUM    -- the draft skin number
*/
void setup_skinedit_page(void){
  static const struct sSkinAddr {
    const char *zFile;
    const char *zTitle;
    const char *zSubmenu;
  } aSkinAttr[] = {
    /* 0 */ { "css",     "CSS",             "CSS",     },
    /* 1 */ { "footer",  "Page Footer",     "Footer",  },
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
}

/*
** WEBPAGE: setup_skin
**
** Generate a page showing the steps needed to customize a skin.
*/
void setup_skin(void){
  int i;          /* Loop counter */
  int iSkin;      /* Which draft skin is being edited */
  int isSetup;    /* True for an administrator */
  int isEditor;   /* Others authorized to make edits */
  char *zAllowedEditors;   /* Who may edit the draft skin */
  char *zBase;             /* Base URL for draft under test */
  static const char *const azTestPages[] = {







|







872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
}

/*
** WEBPAGE: setup_skin
**
** Generate a page showing the steps needed to customize a skin.
*/
void setup_skin_page(void){
  int i;          /* Loop counter */
  int iSkin;      /* Which draft skin is being edited */
  int isSetup;    /* True for an administrator */
  int isEditor;   /* Others authorized to make edits */
  char *zAllowedEditors;   /* Who may edit the draft skin */
  char *zBase;             /* Base URL for draft under test */
  static const char *const azTestPages[] = {
Changes to src/smtp.c.
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
** COMMAND: test-find-mx
**
** Usage: %fossil test-find-mx DOMAIN ...
**
** Do a DNS MX lookup to find the hostname for sending email for
** DOMAIN.
*/
void test_find_mx(void){
  int i;
  if( g.argc<=2 ){
    usage("DOMAIN ...");
  }
  for(i=2; i<g.argc; i++){
    char *z = smtp_mx_host(g.argv[i]);
    fossil_print("%s: %s\n", g.argv[i], z);







|







131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
** COMMAND: test-find-mx
**
** Usage: %fossil test-find-mx DOMAIN ...
**
** Do a DNS MX lookup to find the hostname for sending email for
** DOMAIN.
*/
void test_find_mx_cmd(void){
  int i;
  if( g.argc<=2 ){
    usage("DOMAIN ...");
  }
  for(i=2; i<g.argc; i++){
    char *z = smtp_mx_host(g.argv[i]);
    fossil_print("%s: %s\n", g.argv[i], z);
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
** on the console.  Use ME as the domain name of the sender.
**
** Options:
**
**    --direct              Use DOMAIN directly without going through MX
**    --port N              Talk on TCP port N
*/
void test_smtp_probe(void){
  SmtpSession *p;
  const char *zDomain;
  const char *zSelf;
  const char *zPort;
  int iPort = 25;
  u32 smtpFlags = SMTP_TRACE_STDOUT|SMTP_PORT;








|







425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
** on the console.  Use ME as the domain name of the sender.
**
** Options:
**
**    --direct              Use DOMAIN directly without going through MX
**    --port N              Talk on TCP port N
*/
void test_smtp_probe_cmd(void){
  SmtpSession *p;
  const char *zDomain;
  const char *zSelf;
  const char *zPort;
  int iPort = 25;
  u32 smtpFlags = SMTP_TRACE_STDOUT|SMTP_PORT;

505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
**
** Usage: %fossil test-smtp-senddata FILE
**
** Read content from FILE, then send it to stdout encoded as if sent
** to the DATA portion of an SMTP session.  This command is used to
** test the encoding logic.
*/
void test_smtp_senddata(void){
  Blob f;
  if( g.argc!=3 ) usage("FILE");
  blob_read_from_file(&f, g.argv[2], ExtFILE);
  smtp_send_email_body(blob_str(&f), smtp_test_sender, 0);
  blob_reset(&f);
}








|







505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
**
** Usage: %fossil test-smtp-senddata FILE
**
** Read content from FILE, then send it to stdout encoded as if sent
** to the DATA portion of an SMTP session.  This command is used to
** test the encoding logic.
*/
void test_smtp_senddata_cmd(void){
  Blob f;
  if( g.argc!=3 ) usage("FILE");
  blob_read_from_file(&f, g.argv[2], ExtFILE);
  smtp_send_email_body(blob_str(&f), smtp_test_sender, 0);
  blob_reset(&f);
}

600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
** Options:
**
**      --direct              Go directly to the TO domain.  Bypass MX lookup
**      --relayhost R         Use R as relay host directly for delivery.
**      --port N              Use TCP port N instead of 25
**      --trace               Show the SMTP conversation on the console
*/
void test_smtp_send(void){
  SmtpSession *p;
  const char *zFrom;
  int nTo;
  const char *zToDomain;
  const char *zFromDomain;
  const char *zRelay;
  const char **azTo;







|







600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
** Options:
**
**      --direct              Go directly to the TO domain.  Bypass MX lookup
**      --relayhost R         Use R as relay host directly for delivery.
**      --port N              Use TCP port N instead of 25
**      --trace               Show the SMTP conversation on the console
*/
void test_smtp_send_cmd(void){
  SmtpSession *p;
  const char *zFrom;
  int nTo;
  const char *zToDomain;
  const char *zFromDomain;
  const char *zRelay;
  const char **azTo;
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
/*
** WEBPAGE: setup_smtp
**
** Administrative page for configuring and controlling inbound email and
** output email queuing.  This page is available to administrators
** only via the /Admin/EmailServer menu.
*/
void setup_smtp(void){
  Stmt q;
  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed(0);
    return;
  }
  db_begin_transaction();







|







759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
/*
** WEBPAGE: setup_smtp
**
** Administrative page for configuring and controlling inbound email and
** output email queuing.  This page is available to administrators
** only via the /Admin/EmailServer menu.
*/
void setup_smtp_page(void){
  Stmt q;
  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed(0);
    return;
  }
  db_begin_transaction();
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
**    eaddr=ADDR          ADDR is the email address as edited.
**
**    oaddr=ADDR          The original email address prior to editing.
**                        Omit to add a new address.
**
**    epolicy=TXT         The routing policy.
*/
void setup_smtp_route(void){
  char *zEAddr = PT("eaddr");         /* new email address */
  char *zEPolicy = PT("epolicy");     /* new routing policy */
  char *zOAddr = PT("oaddr");         /* original email address */
  char *zErr = 0;
  int iErr = 0;
  login_check_credentials();
  if( !g.perm.Setup ){







|







820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
**    eaddr=ADDR          ADDR is the email address as edited.
**
**    oaddr=ADDR          The original email address prior to editing.
**                        Omit to add a new address.
**
**    epolicy=TXT         The routing policy.
*/
void setup_smtp_route_page(void){
  char *zEAddr = PT("eaddr");         /* new email address */
  char *zEPolicy = PT("epolicy");     /* new routing policy */
  char *zOAddr = PT("oaddr");         /* original email address */
  char *zErr = 0;
  int iErr = 0;
  login_check_credentials();
  if( !g.perm.Setup ){
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
**
** Verify that the emailblob.enref field is correct.  Report any errors.
** Use the --repair command to fix up the enref field.  The --full option
** gives a full report showing the enref value on all entries in the
** emailblob table.  If the --clean flags is used together with --repair,
** then emailblob table entires with enref==0 are removed.
*/
void test_refcheck_emailblob(void){
  int doRepair;
  int fullReport;
  int doClean;
  Blob sql;
  Stmt q;
  int nErr = 0;
  db_find_and_open_repository(0, 0);







|







1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
**
** Verify that the emailblob.enref field is correct.  Report any errors.
** Use the --repair command to fix up the enref field.  The --full option
** gives a full report showing the enref value on all entries in the
** emailblob table.  If the --clean flags is used together with --repair,
** then emailblob table entires with enref==0 are removed.
*/
void test_emailblob_refcheck_cmd(void){
  int doRepair;
  int fullReport;
  int doClean;
  Blob sql;
  Stmt q;
  int nErr = 0;
  db_find_and_open_repository(0, 0);
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
**      --trace           Print a transcript of the conversation on stderr
**                        for debugging and analysis
**
**      --ipaddr ADDR     The SMTP connection originates at ADDR.  Or if ADDR
**                        is the name of an environment variable, the address
**                        is taken from that environment variable.
*/
void smtp_server(void){
  char *zDbName;
  const char *zDomain;
  SmtpServer x;
  char z[5000];

  smtp_server_init(&x);
  zDomain = find_option("domain",0,1);







|







1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
**      --trace           Print a transcript of the conversation on stderr
**                        for debugging and analysis
**
**      --ipaddr ADDR     The SMTP connection originates at ADDR.  Or if ADDR
**                        is the name of an environment variable, the address
**                        is taken from that environment variable.
*/
void smtp_server_cmd(void){
  char *zDbName;
  const char *zDomain;
  SmtpServer x;
  char z[5000];

  smtp_server_init(&x);
  zDomain = find_option("domain",0,1);
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
** off of the wire.
**
**   --logdir  DIR        Each pop3d session creates a new logfile
**                        in the directory DIR and records a transcript
**                        of the session there.  The logfile is opened
**                        before entering the chroot jail.
*/
void pop3d_command(void){
  char *zDbName;
  char *zA1, *zA2, *zCmd, *z;
  int inAuth = 1;
  int i;
  FILE *pLog = 0;
  const char *zDir;
  Stmt q;







|







1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
** off of the wire.
**
**   --logdir  DIR        Each pop3d session creates a new logfile
**                        in the directory DIR and records a transcript
**                        of the session there.  The logfile is opened
**                        before entering the chroot jail.
*/
void pop3d_cmd(void){
  char *zDbName;
  char *zA1, *zA2, *zCmd, *z;
  int inAuth = 1;
  int i;
  FILE *pLog = 0;
  const char *zDir;
  Stmt q;
Changes to src/sqlcmd.c.
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
**
**    REGEXP                    The REGEXP operator works, unlike in
**                              standard SQLite.
**
**    symbolic_name_to_rid(X)   Return the BLOB.RID corresponding to symbolic
**                              name X.
*/
void cmd_sqlite3(void){
  int noRepository;
  char *zConfigDb;
  extern int sqlite3_shell(int, char**);
#ifdef FOSSIL_ENABLE_TH1_HOOKS
  g.fNoThHook = 1;
#endif
  noRepository = find_option("no-repository", 0, 0)!=0;







|







313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
**
**    REGEXP                    The REGEXP operator works, unlike in
**                              standard SQLite.
**
**    symbolic_name_to_rid(X)   Return the BLOB.RID corresponding to symbolic
**                              name X.
*/
void sqlite3_cmd(void){
  int noRepository;
  char *zConfigDb;
  extern int sqlite3_shell(int, char**);
#ifdef FOSSIL_ENABLE_TH1_HOOKS
  g.fNoThHook = 1;
#endif
  noRepository = find_option("no-repository", 0, 0)!=0;
Changes to src/statrep.c.
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
** The view-specific query parameters include:
**
** view=byweek:
**
**   y=YYYY            The year to report (default is the server's
**                     current year).
*/
void stats_report_page(){
  const char *zView = P("view");     /* Which view/report to show. */
  int eType = RPT_NONE;              /* Numeric code for view/report to show */
  int i;                             /* Loop counter */
  const char *zUserName;             /* Name of user */
  const char *azView[16];            /* Drop-down menu of view types */
  static const struct {
    const char *zName;  /* Name of view= screen type */







|







733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
** The view-specific query parameters include:
**
** view=byweek:
**
**   y=YYYY            The year to report (default is the server's
**                     current year).
*/
void reports_page(){
  const char *zView = P("view");     /* Which view/report to show. */
  int eType = RPT_NONE;              /* Numeric code for view/report to show */
  int i;                             /* Loop counter */
  const char *zUserName;             /* Name of user */
  const char *azView[16];            /* Drop-down menu of view types */
  static const struct {
    const char *zName;  /* Name of view= screen type */
Changes to src/style.c.
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
/*
** COMMAND: test-contains-selector
**
** Usage: %fossil test-contains-selector FILENAME SELECTOR
**
** Determine if the CSS stylesheet FILENAME contains SELECTOR.
*/
void contains_selector_cmd(void){
  int found;
  char *zSelector;
  Blob css;
  if( g.argc!=4 ) usage("FILENAME SELECTOR");
  blob_read_from_file(&css, g.argv[2], ExtFILE);
  zSelector = g.argv[3];
  found = containsSelector(blob_str(&css), zSelector);
  fossil_print("%s %s\n", zSelector, found ? "found" : "not found");
  blob_reset(&css);
}

/*
** WEBPAGE: script.js
**
** Return the "Javascript" content for the current skin (if there is any)
*/
void page_script_js(void){
  const char *zScript = skin_get("js");
  if( P("test") ){
    /* Render the script as plain-text for testing purposes, if the "test"
    ** query parameter is present */
    cgi_set_content_type("text/plain");
  }else{
    /* Default behavior is to return javascript */
    cgi_set_content_type("application/javascript");
  }
  style_init_th1_vars(0);
  Th_Render(zScript?zScript:"");
}


/*
** WEBPAGE: style.css
**
** Return the style sheet.
*/
void page_style_css(void){
  Blob css;
  int i;
  int isInit = 0;

  cgi_set_content_type("text/css");
  blob_init(&css,skin_get("css"),-1);








|
















|



















|







1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
/*
** COMMAND: test-contains-selector
**
** Usage: %fossil test-contains-selector FILENAME SELECTOR
**
** Determine if the CSS stylesheet FILENAME contains SELECTOR.
*/
void test_contains_selector_cmd(void){
  int found;
  char *zSelector;
  Blob css;
  if( g.argc!=4 ) usage("FILENAME SELECTOR");
  blob_read_from_file(&css, g.argv[2], ExtFILE);
  zSelector = g.argv[3];
  found = containsSelector(blob_str(&css), zSelector);
  fossil_print("%s %s\n", zSelector, found ? "found" : "not found");
  blob_reset(&css);
}

/*
** WEBPAGE: script.js
**
** Return the "Javascript" content for the current skin (if there is any)
*/
void script_js_page(void){
  const char *zScript = skin_get("js");
  if( P("test") ){
    /* Render the script as plain-text for testing purposes, if the "test"
    ** query parameter is present */
    cgi_set_content_type("text/plain");
  }else{
    /* Default behavior is to return javascript */
    cgi_set_content_type("application/javascript");
  }
  style_init_th1_vars(0);
  Th_Render(zScript?zScript:"");
}


/*
** WEBPAGE: style.css
**
** Return the style sheet.
*/
void style_css_page(void){
  Blob css;
  int i;
  int isInit = 0;

  cgi_set_content_type("text/css");
  blob_init(&css,skin_get("css"),-1);

1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
**
** Return the built-in text given by FILENAME.  This is used internally 
** by many Fossil web pages to load built-in javascript files.
**
** If the id= query parameter is present, then Fossil assumes that the
** result is immutable and sets a very large cache retention time (1 year).
*/
void page_builtin_text(void){
  Blob out;
  const char *zName = P("name");
  const char *zTxt = 0;
  const char *zId = P("id");
  int nId;
  if( zName ) zTxt = builtin_text(zName);
  if( zTxt==0 ){







|







1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
**
** Return the built-in text given by FILENAME.  This is used internally 
** by many Fossil web pages to load built-in javascript files.
**
** If the id= query parameter is present, then Fossil assumes that the
** result is immutable and sets a very large cache retention time (1 year).
*/
void builtin_page(void){
  Blob out;
  const char *zName = P("name");
  const char *zTxt = 0;
  const char *zId = P("id");
  int nId;
  if( zName ) zTxt = builtin_text(zName);
  if( zTxt==0 ){
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182

/*
** WEBPAGE: test_env
**
** Display CGI-variables and other aspects of the run-time
** environment, for debugging and trouble-shooting purposes.
*/
void page_test_env(void){
  webpage_error("");
}

/*
** WEBPAGE: honeypot
** This page is a honeypot for spiders and bots.
*/







|







1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182

/*
** WEBPAGE: test_env
**
** Display CGI-variables and other aspects of the run-time
** environment, for debugging and trouble-shooting purposes.
*/
void test_env_page(void){
  webpage_error("");
}

/*
** WEBPAGE: honeypot
** This page is a honeypot for spiders and bots.
*/
Changes to src/tag.c.
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
** Usage: %fossil test-tag (+|*|-)TAGNAME ARTIFACT-ID ?VALUE?
**
** Add a tag or anti-tag to the rebuildable tables of the local repository.
** No tag artifact is created so the new tag is erased the next
** time the repository is rebuilt.  This routine is for testing
** use only.
*/
void testtag_cmd(void){
  const char *zTag;
  const char *zValue;
  int rid;
  int tagtype;
  db_must_be_within_tree();
  if( g.argc!=4 && g.argc!=5 ){
    usage("TAGNAME ARTIFACT-ID ?VALUE?");







|







248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
** Usage: %fossil test-tag (+|*|-)TAGNAME ARTIFACT-ID ?VALUE?
**
** Add a tag or anti-tag to the rebuildable tables of the local repository.
** No tag artifact is created so the new tag is erased the next
** time the repository is rebuilt.  This routine is for testing
** use only.
*/
void test_tag_cmd(void){
  const char *zTag;
  const char *zValue;
  int rid;
  int tagtype;
  db_must_be_within_tree();
  if( g.argc!=4 && g.argc!=5 ){
    usage("TAGNAME ARTIFACT-ID ?VALUE?");
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
  }
  @ </ul>
  db_finalize(&q);
  style_footer();
}

/*
** WEBPAGE: /tagtimeline
**
** Render a timeline with all check-ins that contain non-propagating
** symbolic tags.
**
** Query parameters:
**
**     ng            No graph







|







726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
  }
  @ </ul>
  db_finalize(&q);
  style_footer();
}

/*
** WEBPAGE: tagtimeline
**
** Render a timeline with all check-ins that contain non-propagating
** symbolic tags.
**
** Query parameters:
**
**     ng            No graph
Changes to src/th_main.c.
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
**     --cgi                Include a CGI response header in the output
**     --http               Include an HTTP response header in the output
**     --open-config        Open the configuration database
**     --set-anon-caps      Set anonymous login capabilities
**     --set-user-caps      Set user login capabilities
**     --th-trace           Trace TH1 execution (for debugging purposes)
*/
void test_th_render(void){
  int forceCgi, fullHttpReply;
  Blob in;
  Th_InitTraceLog();
  forceCgi = find_option("cgi", 0, 0)!=0;
  fullHttpReply = find_option("http", 0, 0)!=0;
  if( fullHttpReply ) forceCgi = 1;
  if( forceCgi ) Th_ForceCgi(fullHttpReply);







|







2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
**     --cgi                Include a CGI response header in the output
**     --http               Include an HTTP response header in the output
**     --open-config        Open the configuration database
**     --set-anon-caps      Set anonymous login capabilities
**     --set-user-caps      Set user login capabilities
**     --th-trace           Trace TH1 execution (for debugging purposes)
*/
void test_th_render_cmd(void){
  int forceCgi, fullHttpReply;
  Blob in;
  Th_InitTraceLog();
  forceCgi = find_option("cgi", 0, 0)!=0;
  fullHttpReply = find_option("http", 0, 0)!=0;
  if( fullHttpReply ) forceCgi = 1;
  if( forceCgi ) Th_ForceCgi(fullHttpReply);
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
**     --cgi                Include a CGI response header in the output
**     --http               Include an HTTP response header in the output
**     --open-config        Open the configuration database
**     --set-anon-caps      Set anonymous login capabilities
**     --set-user-caps      Set user login capabilities
**     --th-trace           Trace TH1 execution (for debugging purposes)
*/
void test_th_eval(void){
  int rc;
  const char *zRc;
  int forceCgi, fullHttpReply;
  Th_InitTraceLog();
  forceCgi = find_option("cgi", 0, 0)!=0;
  fullHttpReply = find_option("http", 0, 0)!=0;
  if( fullHttpReply ) forceCgi = 1;







|







2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
**     --cgi                Include a CGI response header in the output
**     --http               Include an HTTP response header in the output
**     --open-config        Open the configuration database
**     --set-anon-caps      Set anonymous login capabilities
**     --set-user-caps      Set user login capabilities
**     --th-trace           Trace TH1 execution (for debugging purposes)
*/
void test_th_eval_cmd(void){
  int rc;
  const char *zRc;
  int forceCgi, fullHttpReply;
  Th_InitTraceLog();
  forceCgi = find_option("cgi", 0, 0)!=0;
  fullHttpReply = find_option("http", 0, 0)!=0;
  if( fullHttpReply ) forceCgi = 1;
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
**     --cgi                Include a CGI response header in the output
**     --http               Include an HTTP response header in the output
**     --open-config        Open the configuration database
**     --set-anon-caps      Set anonymous login capabilities
**     --set-user-caps      Set user login capabilities
**     --th-trace           Trace TH1 execution (for debugging purposes)
*/
void test_th_source(void){
  int rc;
  const char *zRc;
  int forceCgi, fullHttpReply;
  Blob in;
  Th_InitTraceLog();
  forceCgi = find_option("cgi", 0, 0)!=0;
  fullHttpReply = find_option("http", 0, 0)!=0;







|







2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
**     --cgi                Include a CGI response header in the output
**     --http               Include an HTTP response header in the output
**     --open-config        Open the configuration database
**     --set-anon-caps      Set anonymous login capabilities
**     --set-user-caps      Set user login capabilities
**     --th-trace           Trace TH1 execution (for debugging purposes)
*/
void test_th_source_cmd(void){
  int rc;
  const char *zRc;
  int forceCgi, fullHttpReply;
  Blob in;
  Th_InitTraceLog();
  forceCgi = find_option("cgi", 0, 0)!=0;
  fullHttpReply = find_option("http", 0, 0)!=0;
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
**
** Options:
**
**     --cgi                Include a CGI response header in the output
**     --http               Include an HTTP response header in the output
**     --th-trace           Trace TH1 execution (for debugging purposes)
*/
void test_th_hook(void){
  int rc = TH_OK;
  int nResult = 0;
  char *zResult = 0;
  int forceCgi, fullHttpReply;
  Th_InitTraceLog();
  forceCgi = find_option("cgi", 0, 0)!=0;
  fullHttpReply = find_option("http", 0, 0)!=0;







|







2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
**
** Options:
**
**     --cgi                Include a CGI response header in the output
**     --http               Include an HTTP response header in the output
**     --th-trace           Trace TH1 execution (for debugging purposes)
*/
void test_th_hook_cmd(void){
  int rc = TH_OK;
  int nResult = 0;
  char *zResult = 0;
  int forceCgi, fullHttpReply;
  Th_InitTraceLog();
  forceCgi = find_option("cgi", 0, 0)!=0;
  fullHttpReply = find_option("http", 0, 0)!=0;
Changes to src/timeline.c.
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
** COMMAND: test-hash-color
**
** Usage: %fossil test-hash-color TAG ...
**
** Print out the color names associated with each tag.  Used for
** testing the hash_color() function.
*/
void test_hash_color(void){
  int i;
  for(i=2; i<g.argc; i++){
    fossil_print("%20s: %s\n", g.argv[i], hash_color(g.argv[i]));
  }
}

/*
** WEBPAGE: hash-color-test
**
** Print out the color names associated with each tag.  Used for
** testing the hash_color() function.
*/
void test_hash_color_page(void){
  const char *zBr;
  char zNm[10];
  int i, cnt;
  login_check_credentials();

  style_header("Hash Color Test");
  for(i=cnt=0; i<10; i++){







|












|







166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
** COMMAND: test-hash-color
**
** Usage: %fossil test-hash-color TAG ...
**
** Print out the color names associated with each tag.  Used for
** testing the hash_color() function.
*/
void test_hash_color_cmd(void){
  int i;
  for(i=2; i<g.argc; i++){
    fossil_print("%20s: %s\n", g.argv[i], hash_color(g.argv[i]));
  }
}

/*
** WEBPAGE: hash-color-test
**
** Print out the color names associated with each tag.  Used for
** testing the hash_color() function.
*/
void hash_color_test_page(void){
  const char *zBr;
  char zNm[10];
  int i, cnt;
  login_check_credentials();

  style_header("Hash Color Test");
  for(i=cnt=0; i<10; i++){
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
** appear, then u=, y=, a=, and b= are ignored.
**
** If both a= and b= appear then both upper and lower bounds are honored.
**
** CHECKIN or TIMEORTAG can be a check-in hash prefix, or a tag, or the
** name of a branch.
*/
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 */
  int nEntry;                        /* Max number of entries on timeline */
  int p_rid = name_to_typed_rid(P("p"),"ci");  /* artifact p and its parents */
  int d_rid = name_to_typed_rid(P("d"),"ci");  /* artifact d and descendants */
  int f_rid = name_to_typed_rid(P("f"),"ci");  /* artifact f and close family */







|







1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
** appear, then u=, y=, a=, and b= are ignored.
**
** If both a= and b= appear then both upper and lower bounds are honored.
**
** CHECKIN or TIMEORTAG can be a check-in hash prefix, or a tag, or the
** name of a branch.
*/
void timeline_page(void){
  Stmt q;                            /* Query used to generate the timeline */
  Blob sql;                          /* text of SQL used to generate timeline */
  Blob desc;                         /* Description of the timeline */
  int nEntry;                        /* Max number of entries on timeline */
  int p_rid = name_to_typed_rid(P("p"),"ci");  /* artifact p and its parents */
  int d_rid = name_to_typed_rid(P("d"),"ci");  /* artifact d and descendants */
  int f_rid = name_to_typed_rid(P("f"),"ci");  /* artifact f and close family */
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
**
** Usage: %fossil test-timewarp-list ?-v|---verbose?
**
** Display all instances of child check-ins that appear earlier in time
** than their parent.  If the -v|--verbose option is provided, both the
** parent and child check-ins and their times are shown.
*/
void test_timewarp_cmd(void){
  Stmt q;
  int verboseFlag;

  db_find_and_open_repository(0, 0);
  verboseFlag = find_option("verbose", "v", 0)!=0;
  if( !verboseFlag ){
    verboseFlag = find_option("detail", 0, 0)!=0; /* deprecated */







|







3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
**
** Usage: %fossil test-timewarp-list ?-v|---verbose?
**
** Display all instances of child check-ins that appear earlier in time
** than their parent.  If the -v|--verbose option is provided, both the
** parent and child check-ins and their times are shown.
*/
void test_timewarp_list_cmd(void){
  Stmt q;
  int verboseFlag;

  db_find_and_open_repository(0, 0);
  verboseFlag = find_option("verbose", "v", 0)!=0;
  if( !verboseFlag ){
    verboseFlag = find_option("detail", 0, 0)!=0; /* deprecated */
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
** WEBPAGE: timewarps
**
** Show all check-ins that are "timewarps".  A timewarp is a
** check-in that occurs before its parent, according to the
** timestamp information on the check-in.  This can only actually
** happen, of course, if a users system clock is set incorrectly.
*/
void test_timewarp_page(void){
  Stmt q;
  int cnt = 0;

  login_check_credentials();
  if( !g.perm.Read || !g.perm.Hyperlink ){
    login_needed(g.anon.Read && g.anon.Hyperlink);
    return;







|







3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
** WEBPAGE: timewarps
**
** Show all check-ins that are "timewarps".  A timewarp is a
** check-in that occurs before its parent, according to the
** timestamp information on the check-in.  This can only actually
** happen, of course, if a users system clock is set incorrectly.
*/
void timewarps_page(void){
  Stmt q;
  int cnt = 0;

  login_check_credentials();
  if( !g.perm.Read || !g.perm.Hyperlink ){
    login_needed(g.anon.Read && g.anon.Hyperlink);
    return;
Changes to src/tkt.c.
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
** COMMAND: test-ticket-rebuild
**
** Usage: %fossil test-ticket-rebuild TICKETID|all
**
** Rebuild the TICKET and TICKETCHNG tables for the given ticket ID
** or for ALL.
*/
void test_ticket_rebuild(void){
  db_find_and_open_repository(0, 0);
  if( g.argc!=3 ) usage("TICKETID|all");
  if( fossil_strcmp(g.argv[2], "all")==0 ){
    ticket_rebuild();
  }else{
    const char *zUuid;
    zUuid = db_text(0, "SELECT substr(tagname,5) FROM tag"







|







407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
** COMMAND: test-ticket-rebuild
**
** Usage: %fossil test-ticket-rebuild TICKETID|all
**
** Rebuild the TICKET and TICKETCHNG tables for the given ticket ID
** or for ALL.
*/
void test_ticket_rebuild_cmd(void){
  db_find_and_open_repository(0, 0);
  if( g.argc!=3 ) usage("TICKETID|all");
  if( fossil_strcmp(g.argv[2], "all")==0 ){
    ticket_rebuild();
  }else{
    const char *zUuid;
    zUuid = db_text(0, "SELECT substr(tagname,5) FROM tag"
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
/*
** WEBPAGE: ticket
**
** This is intended to be the primary "Ticket" page.  Render as
** either ticket-search (if search is enabled) or as the
** /reportlist page (if ticket search is disabled).
*/
void tkt_home_page(void){
  login_check_credentials();
  if( search_restrict(SRCH_TKT)!=0 ){
    tkt_srchpage();
  }else{
    view_list();
  }
}

/*
** WEBPAGE: tktsrch
** Usage:  /tktsrch?s=PATTERN
**
** Full-text search of all current tickets
*/
void tkt_srchpage(void){
  login_check_credentials();
  style_header("Ticket Search");
  ticket_standard_submenu(T_ALL_BUT(T_SRCH));
  search_screen(SRCH_TKT, 0);
  style_footer();
}







|


|

|









|






1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
/*
** WEBPAGE: ticket
**
** This is intended to be the primary "Ticket" page.  Render as
** either ticket-search (if search is enabled) or as the
** /reportlist page (if ticket search is disabled).
*/
void ticket_page(void){
  login_check_credentials();
  if( search_restrict(SRCH_TKT)!=0 ){
    tktsrch_page();
  }else{
    reportlist_page();
  }
}

/*
** WEBPAGE: tktsrch
** Usage:  /tktsrch?s=PATTERN
**
** Full-text search of all current tickets
*/
void tktsrch_page(void){
  login_check_credentials();
  style_header("Ticket Search");
  ticket_standard_submenu(T_ALL_BUT(T_SRCH));
  search_screen(SRCH_TKT, 0);
  style_footer();
}
Changes to src/tktsetup.c.
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
}

/*
** WEBPAGE: tktsetup_reportlist
** Administrative page used to view or edit the TH1 script that
** defines the "report list" page.
*/
void tktsetup_reportlist(void){
  static const char zDesc[] =
  @ Enter HTML with embedded TH1 script that will render the "report list" page
  ;
  tktsetup_generic(
    "HTML For Report List",
    "ticket-reportlist",
    zDefaultReportList,







|







772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
}

/*
** WEBPAGE: tktsetup_reportlist
** Administrative page used to view or edit the TH1 script that
** defines the "report list" page.
*/
void tktsetup_reportlist_page(void){
  static const char zDesc[] =
  @ Enter HTML with embedded TH1 script that will render the "report list" page
  ;
  tktsetup_generic(
    "HTML For Report List",
    "ticket-reportlist",
    zDefaultReportList,
Changes to src/url.c.
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
** COMMAND: test-urlparser
**
** Usage: %fossil test-urlparser URL ?options?
**
**    --remember      Store results in last-sync-url
**    --prompt-pw     Prompt for password if missing
*/
void cmd_test_urlparser(void){
  int i;
  unsigned fg = 0;
  url_proxy_options();
  if( find_option("remember",0,0) ){
    db_must_be_within_tree();
    fg |= URL_REMEMBER;
  }







|







320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
** COMMAND: test-urlparser
**
** Usage: %fossil test-urlparser URL ?options?
**
**    --remember      Store results in last-sync-url
**    --prompt-pw     Prompt for password if missing
*/
void test_urlparser_cmd(void){
  int i;
  unsigned fg = 0;
  url_proxy_options();
  if( find_option("remember",0,0) ){
    db_must_be_within_tree();
    fg |= URL_REMEMBER;
  }
Changes to src/user.c.
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
**
** Usage: %fossil test-hash-passwords REPOSITORY
**
** Convert all local password storage to use a SHA1 hash of the password
** rather than cleartext.  Passwords that are already stored as the SHA1
** has are unchanged.
*/
void user_hash_passwords_cmd(void){
  if( g.argc!=3 ) usage("REPOSITORY");
  db_open_repository(g.argv[2]);
  sqlite3_create_function(g.db, "shared_secret", 2, SQLITE_UTF8, 0,
                          sha1_shared_secret_sql_function, 0, 0);
  db_multi_exec(
    "UPDATE user SET pw=shared_secret(pw,login), mtime=now()"
    " WHERE length(pw)>0 AND length(pw)!=40"







|







566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
**
** Usage: %fossil test-hash-passwords REPOSITORY
**
** Convert all local password storage to use a SHA1 hash of the password
** rather than cleartext.  Passwords that are already stored as the SHA1
** has are unchanged.
*/
void test_hash_passwords_cmd(void){
  if( g.argc!=3 ) usage("REPOSITORY");
  db_open_repository(g.argv[2]);
  sqlite3_create_function(g.db, "shared_secret", 2, SQLITE_UTF8, 0,
                          sha1_shared_secret_sql_function, 0, 0);
  db_multi_exec(
    "UPDATE user SET pw=shared_secret(pw,login), mtime=now()"
    " WHERE length(pw)>0 AND length(pw)!=40"
Changes to src/util.c.
564
565
566
567
568
569
570
571
572
573
574
575
576
577
**
** Usage: %fossil test-random-password ?N?
**
** Generate a random password string of approximately N characters in length.
** If N is omitted, use 10.  Values of N less than 8 are changed to 8
** and greater than 55 and changed to 55.
*/
void test_random_password(void){
  int N = 10;
  if( g.argc>=3 ){
    N = atoi(g.argv[2]);
  }
  fossil_print("%s\n", fossil_random_password(N));
}







|






564
565
566
567
568
569
570
571
572
573
574
575
576
577
**
** Usage: %fossil test-random-password ?N?
**
** Generate a random password string of approximately N characters in length.
** If N is omitted, use 10.  Values of N less than 8 are changed to 8
** and greater than 55 and changed to 55.
*/
void test_random_password_cmd(void){
  int N = 10;
  if( g.argc>=3 ){
    N = atoi(g.argv[2]);
  }
  fossil_print("%s\n", fossil_random_password(N));
}
Changes to src/verify.c.
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
}

/*
** COMMAND: test-verify-all
**
** Verify all records in the repository.
*/
void verify_all_cmd(void){
  Stmt q;
  int cnt = 0;
  db_must_be_within_tree();
  db_prepare(&q, "SELECT rid FROM blob");
  while( db_step(&q)==SQLITE_ROW ){
    int rid = db_column_int(&q, 0);
    verify_before_commit(rid);







|







109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
}

/*
** COMMAND: test-verify-all
**
** Verify all records in the repository.
*/
void test_verify_all_cmd(void){
  Stmt q;
  int cnt = 0;
  db_must_be_within_tree();
  db_prepare(&q, "SELECT rid FROM blob");
  while( db_step(&q)==SQLITE_ROW ){
    int rid = db_column_int(&q, 0);
    verify_before_commit(rid);
Changes to src/webmail.c.
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
** COMMAND: test-decode-email
**
** Usage: %fossil test-decode-email FILE
**
** Read an rfc-2822 formatted email out of FILE, then write a decoding
** to stdout.  Use for testing and validating the email decoder.
*/
void test_email_decode_cmd(void){
  Blob email;
  EmailToc *p;
  int i;
  verify_all_options();
  if( g.argc!=3 ) usage("FILE");
  blob_read_from_file(&email, g.argv[2], ExtFILE);
  p = emailtoc_from_email(&email);







|







304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
** COMMAND: test-decode-email
**
** Usage: %fossil test-decode-email FILE
**
** Read an rfc-2822 formatted email out of FILE, then write a decoding
** to stdout.  Use for testing and validating the email decoder.
*/
void test_decode_email_cmd(void){
  Blob email;
  EmailToc *p;
  int i;
  verify_all_options();
  if( g.argc!=3 ) usage("FILE");
  blob_read_from_file(&email, g.argv[2], ExtFILE);
  p = emailtoc_from_email(&email);
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
     "3", "Sent",
     "4", "Everything",
  };
  style_submenu_multichoice("d", sizeof(az)/(2*sizeof(az[0])), az, 0);
}

/*
** WEBPAGE:  webmail
**
** This page can be used to read content from the EMAILBOX table
** that contains email received by the "fossil smtpd" command.
**
** Query parameters:
**
**     id=N                 Show a single email entry emailbox.ebid==N







|







572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
     "3", "Sent",
     "4", "Everything",
  };
  style_submenu_multichoice("d", sizeof(az)/(2*sizeof(az[0])), az, 0);
}

/*
** WEBPAGE: webmail
**
** This page can be used to read content from the EMAILBOX table
** that contains email received by the "fossil smtpd" command.
**
** Query parameters:
**
**     id=N                 Show a single email entry emailbox.ebid==N
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
  @ }
  @ </script>
  style_footer();
  db_end_transaction(0);
}

/*
** WEBPAGE:  emailblob
**
** This page, accessible only to administrators, allows easy viewing of
** the emailblob table - the table that contains the text of email messages
** both inbound and outbound, and transcripts of SMTP sessions.
**
**    id=N          Show the text of emailblob with emailid==N
**
*/
void webmail_emailblob_page(void){
  int id = atoi(PD("id","0"));
  Stmt q;
  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed(0);
    return;
  }







|








|







760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
  @ }
  @ </script>
  style_footer();
  db_end_transaction(0);
}

/*
** WEBPAGE: emailblob
**
** This page, accessible only to administrators, allows easy viewing of
** the emailblob table - the table that contains the text of email messages
** both inbound and outbound, and transcripts of SMTP sessions.
**
**    id=N          Show the text of emailblob with emailid==N
**
*/
void emailblob_page(void){
  int id = atoi(PD("id","0"));
  Stmt q;
  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed(0);
    return;
  }
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
    db_finalize(&q);
    style_table_sorter();
  }
  style_footer();
}

/*
** WEBPAGE:  emailoutq
**
** This page, accessible only to administrators, allows easy viewing of
** the emailoutq table - the table that contains the email messages
** that are queued for transmission via SMTP.
*/
void webmail_emailoutq_page(void){
  Stmt q;
  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed(0);
    return;
  }
  add_content_sql_commands(g.db);







|





|







856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
    db_finalize(&q);
    style_table_sorter();
  }
  style_footer();
}

/*
** WEBPAGE: emailoutq
**
** This page, accessible only to administrators, allows easy viewing of
** the emailoutq table - the table that contains the email messages
** that are queued for transmission via SMTP.
*/
void emailoutq_page(void){
  Stmt q;
  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed(0);
    return;
  }
  add_content_sql_commands(g.db);
Changes to src/wiki.c.
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
}

/*
** WEBPAGE: md_rules
**
** Show a summary of the Markdown wiki formatting rules.
*/
void markdown_rules_page(void){
  Blob x;
  int fTxt = P("txt")!=0;
  style_header("Markdown Formatting Rules");
  if( fTxt ){
    style_submenu_element("Formatted", "%R/md_rules");
  }else{
    style_submenu_element("Plain-Text", "%R/md_rules?txt=1");







|







207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
}

/*
** WEBPAGE: md_rules
**
** Show a summary of the Markdown wiki formatting rules.
*/
void md_rules_page(void){
  Blob x;
  int fTxt = P("txt")!=0;
  style_header("Markdown Formatting Rules");
  if( fTxt ){
    style_submenu_element("Formatted", "%R/md_rules");
  }else{
    style_submenu_element("Plain-Text", "%R/md_rules?txt=1");
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
  }
}

/*
** WEBPAGE: wikihelp
** A generic landing page for wiki.
*/
void wiki_helppage(void){
  login_check_credentials();
  if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
  style_header("Wiki Help");
  wiki_standard_submenu(W_ALL_BUT(W_HELP));
  @ <h2>Wiki Links</h2>
  @ <ul>
  @ <li> %z(href("%R/timeline?y=w"))Recent changes</a> to wiki pages.</li>







|







316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
  }
}

/*
** WEBPAGE: wikihelp
** A generic landing page for wiki.
*/
void wikihelp_page(void){
  login_check_credentials();
  if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
  style_header("Wiki Help");
  wiki_standard_submenu(W_ALL_BUT(W_HELP));
  @ <h2>Wiki Links</h2>
  @ <ul>
  @ <li> %z(href("%R/timeline?y=w"))Recent changes</a> to wiki pages.</li>
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368

/*
** WEBPAGE: wikisrch
** Usage:  /wikisrch?s=PATTERN
**
** Full-text search of all current wiki text
*/
void wiki_srchpage(void){
  login_check_credentials();
  style_header("Wiki Search");
  wiki_standard_submenu(W_HELP|W_LIST|W_SANDBOX);
  search_screen(SRCH_WIKI, 0);
  style_footer();
}








|







354
355
356
357
358
359
360
361
362
363
364
365
366
367
368

/*
** WEBPAGE: wikisrch
** Usage:  /wikisrch?s=PATTERN
**
** Full-text search of all current wiki text
*/
void wikisrch_page(void){
  login_check_credentials();
  style_header("Wiki Search");
  wiki_standard_submenu(W_HELP|W_LIST|W_SANDBOX);
  search_screen(SRCH_WIKI, 0);
  style_footer();
}

476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
  int noSubmenu = P("nsm")!=0;

  login_check_credentials();
  if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
  zPageName = P("name");
  if( zPageName==0 ){
    if( search_restrict(SRCH_WIKI)!=0 ){
      wiki_srchpage();
    }else{
      wiki_helppage();
    }
    return;
  }
  if( check_name(zPageName) ) return;
  isSandbox = is_sandbox(zPageName);
  if( isSandbox ){
    submenuFlags &= ~W_SANDBOX;







|

|







476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
  int noSubmenu = P("nsm")!=0;

  login_check_credentials();
  if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
  zPageName = P("name");
  if( zPageName==0 ){
    if( search_restrict(SRCH_WIKI)!=0 ){
      wikisrch_page();
    }else{
      wikihelp_page();
    }
    return;
  }
  if( check_name(zPageName) ) return;
  isSandbox = is_sandbox(zPageName);
  if( isSandbox ){
    submenuFlags &= ~W_SANDBOX;
Changes to src/wikiformat.c.
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
**    --buttons        Set the WIKI_BUTTONS flag
**    --htmlonly       Set the WIKI_HTMLONLY flag
**    --linksonly      Set the WIKI_LINKSONLY flag
**    --nobadlinks     Set the WIKI_NOBADLINKS flag
**    --inline         Set the WIKI_INLINE flag
**    --noblock        Set the WIKI_NOBLOCK flag
*/
void test_wiki_render(void){
  Blob in, out;
  int flags = 0;
  if( find_option("buttons",0,0)!=0 ) flags |= WIKI_BUTTONS;
  if( find_option("htmlonly",0,0)!=0 ) flags |= WIKI_HTMLONLY;
  if( find_option("linksonly",0,0)!=0 ) flags |= WIKI_LINKSONLY;
  if( find_option("nobadlinks",0,0)!=0 ) flags |= WIKI_NOBADLINKS;
  if( find_option("inline",0,0)!=0 ) flags |= WIKI_INLINE;







|







1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
**    --buttons        Set the WIKI_BUTTONS flag
**    --htmlonly       Set the WIKI_HTMLONLY flag
**    --linksonly      Set the WIKI_LINKSONLY flag
**    --nobadlinks     Set the WIKI_NOBADLINKS flag
**    --inline         Set the WIKI_INLINE flag
**    --noblock        Set the WIKI_NOBLOCK flag
*/
void test_wiki_render_cmd(void){
  Blob in, out;
  int flags = 0;
  if( find_option("buttons",0,0)!=0 ) flags |= WIKI_BUTTONS;
  if( find_option("htmlonly",0,0)!=0 ) flags |= WIKI_HTMLONLY;
  if( find_option("linksonly",0,0)!=0 ) flags |= WIKI_LINKSONLY;
  if( find_option("nobadlinks",0,0)!=0 ) flags |= WIKI_NOBADLINKS;
  if( find_option("inline",0,0)!=0 ) flags |= WIKI_INLINE;
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
/*
** COMMAND: test-markdown-render
**
** Usage: %fossil test-markdown-render FILE
**
** Render markdown in FILE as HTML on stdout.
*/
void test_markdown_render(void){
  Blob in, out;
  db_find_and_open_repository(OPEN_OK_NOT_FOUND|OPEN_SUBSTITUTE,0);
  verify_all_options();
  if( g.argc!=3 ) usage("FILE");
  blob_zero(&out);
  blob_read_from_file(&in, g.argv[2], ExtFILE);
  markdown_to_html(&in, 0, &out);







|







1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
/*
** COMMAND: test-markdown-render
**
** Usage: %fossil test-markdown-render FILE
**
** Render markdown in FILE as HTML on stdout.
*/
void test_markdown_render_cmd(void){
  Blob in, out;
  db_find_and_open_repository(OPEN_OK_NOT_FOUND|OPEN_SUBSTITUTE,0);
  verify_all_options();
  if( g.argc!=3 ) usage("FILE");
  blob_zero(&out);
  blob_read_from_file(&in, g.argv[2], ExtFILE);
  markdown_to_html(&in, 0, &out);
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151

/*
** COMMAND: test-html-tokenize
**
** Tokenize an HTML file.  Return the offset and length and text of
** each token - one token per line.  Omit white-space tokens.
*/
void test_html_tokenize(void){
  Blob in;
  char *z;
  int i;
  int iOfst, n;

  for(i=2; i<g.argc; i++){
    blob_read_from_file(&in, g.argv[i], ExtFILE);







|







2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151

/*
** COMMAND: test-html-tokenize
**
** Tokenize an HTML file.  Return the offset and length and text of
** each token - one token per line.  Omit white-space tokens.
*/
void test_html_tokenize_cmd(void){
  Blob in;
  char *z;
  int i;
  int iOfst, n;

  for(i=2; i<g.argc; i++){
    blob_read_from_file(&in, g.argv[i], ExtFILE);
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286

/*
** COMMAND: test-html-tidy
**
** Run the htmlTidy() routine on the content of all files named on
** the command-line and write the results to standard output.
*/
void test_html_tidy(void){
  Blob in, out;
  int i;

  for(i=2; i<g.argc; i++){
    blob_read_from_file(&in, g.argv[i], ExtFILE);
    blob_zero(&out);
    htmlTidy(blob_str(&in), &out);







|







2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286

/*
** COMMAND: test-html-tidy
**
** Run the htmlTidy() routine on the content of all files named on
** the command-line and write the results to standard output.
*/
void test_html_tidy_cmd(void){
  Blob in, out;
  int i;

  for(i=2; i<g.argc; i++){
    blob_read_from_file(&in, g.argv[i], ExtFILE);
    blob_zero(&out);
    htmlTidy(blob_str(&in), &out);
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
** Read all files named on the command-line.  Convert the file
** content from HTML to text and write the results on standard
** output.
**
** This command is intended as a test and debug interface for
** the html_to_plaintext() routine.
*/
void test_html_to_text(void){
  Blob in, out;
  int i;

  for(i=2; i<g.argc; i++){
    blob_read_from_file(&in, g.argv[i], ExtFILE);
    blob_zero(&out);
    html_to_plaintext(blob_str(&in), &out);
    blob_reset(&in);
    fossil_puts(blob_str(&out), 0);
    blob_reset(&out);
  }
}







|












2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
** Read all files named on the command-line.  Convert the file
** content from HTML to text and write the results on standard
** output.
**
** This command is intended as a test and debug interface for
** the html_to_plaintext() routine.
*/
void test_html_to_text_cmd(void){
  Blob in, out;
  int i;

  for(i=2; i<g.argc; i++){
    blob_read_from_file(&in, g.argv[i], ExtFILE);
    blob_zero(&out);
    html_to_plaintext(blob_str(&in), &out);
    blob_reset(&in);
    fossil_puts(blob_str(&out), 0);
    blob_reset(&out);
  }
}
Changes to src/winhttp.c.
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
**         Stop the service.
**
**
** NOTE: This command is available on Windows operating systems only and
**       requires administrative rights on the machine executed.
**
*/
void cmd_win32_service(void){
  int n;
  const char *zMethod;
  const char *zSvcName = "Fossil-DSCM";    /* Default service name */

  if( g.argc<3 ){
    usage("create|delete|show|start|stop ...");
  }







|







1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
**         Stop the service.
**
**
** NOTE: This command is available on Windows operating systems only and
**       requires administrative rights on the machine executed.
**
*/
void win32_service_cmd(void){
  int n;
  const char *zMethod;
  const char *zSvcName = "Fossil-DSCM";    /* Default service name */

  if( g.argc<3 ){
    usage("create|delete|show|start|stop ...");
  }
Changes to src/xfer.c.
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
**
** WEBPAGE: xfer  raw-content
**
** This is the transfer handler on the server side.  The transfer
** message has been uncompressed and placed in the g.cgiIn blob.
** Process this message and form an appropriate reply.
*/
void page_xfer(void){
  int isPull = 0;
  int isPush = 0;
  int nErr = 0;
  Xfer xfer;
  int deltaFlag = 0;
  int isClone = 0;
  int nGimme = 0;







|







1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
**
** WEBPAGE: xfer  raw-content
**
** This is the transfer handler on the server side.  The transfer
** message has been uncompressed and placed in the g.cgiIn blob.
** Process this message and form an appropriate reply.
*/
void xfer_page(void){
  int isPull = 0;
  int isPush = 0;
  int nErr = 0;
  Xfer xfer;
  int deltaFlag = 0;
  int isClone = 0;
  int nGimme = 0;
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
** message will appear on standard output.  Capture this message
** into a file named (for example) out.txt.  Then run the
** server in gdb:
**
**     gdb fossil
**     r test-xfer out.txt
*/
void cmd_test_xfer(void){
  db_find_and_open_repository(0,0);
  if( g.argc!=2 && g.argc!=3 ){
    usage("?MESSAGEFILE?");
  }
  blob_zero(&g.cgiIn);
  blob_read_from_file(&g.cgiIn, g.argc==2 ? "-" : g.argv[2], ExtFILE);
  disableLogin = 1;
  page_xfer();
  fossil_print("%s\n", cgi_extract_content());
}

/*
** Format strings for progress reporting.
*/
static const char zLabelFormat[] = "%-10s %10s %10s %10s %10s\n";







|







|







1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
** message will appear on standard output.  Capture this message
** into a file named (for example) out.txt.  Then run the
** server in gdb:
**
**     gdb fossil
**     r test-xfer out.txt
*/
void test_xfer_cmd(void){
  db_find_and_open_repository(0,0);
  if( g.argc!=2 && g.argc!=3 ){
    usage("?MESSAGEFILE?");
  }
  blob_zero(&g.cgiIn);
  blob_read_from_file(&g.cgiIn, g.argc==2 ? "-" : g.argv[2], ExtFILE);
  disableLogin = 1;
  xfer_page();
  fossil_print("%s\n", cgi_extract_content());
}

/*
** Format strings for progress reporting.
*/
static const char zLabelFormat[] = "%-10s %10s %10s %10s %10s\n";
Changes to src/zip.c.
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585

/*
** COMMAND: test-filezip
**
** Generate a ZIP archive specified by the first argument that
** contains files given in the second and subsequent arguments.
*/
void filezip_cmd(void){
  int i;
  Blob zip;
  Blob file;
  int eFType = SymFILE;
  Archive sArchive;
  memset(&sArchive, 0, sizeof(Archive));
  sArchive.eType = ARCHIVE_ZIP;







|







571
572
573
574
575
576
577
578
579
580
581
582
583
584
585

/*
** COMMAND: test-filezip
**
** Generate a ZIP archive specified by the first argument that
** contains files given in the second and subsequent arguments.
*/
void test_filezip_cmd(void){
  int i;
  Blob zip;
  Blob file;
  int eFType = SymFILE;
  Archive sArchive;
  memset(&sArchive, 0, sizeof(Archive));
  sArchive.eType = ARCHIVE_ZIP;
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
**                       list of GLOB patterns in PATTERN, as with ex=
**
**   ex=PATTERN          Omit any file that match PATTERN.  PATTERN is a
**                       comma-separated list of GLOB patterns, where each
**                       pattern can optionally be quoted using ".." or '..'.
**                       Any file matching both ex= and in= is excluded.
*/
void baseline_zip_page(void){
  int rid;
  const char *z;
  char *zName, *zRid, *zKey;
  int nName, nRid;
  const char *zInclude;         /* The in= query parameter */
  const char *zExclude;         /* The ex= query parameter */
  Blob cacheKey;                /* The key to cache */







|







865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
**                       list of GLOB patterns in PATTERN, as with ex=
**
**   ex=PATTERN          Omit any file that match PATTERN.  PATTERN is a
**                       comma-separated list of GLOB patterns, where each
**                       pattern can optionally be quoted using ".." or '..'.
**                       Any file matching both ex= and in= is excluded.
*/
void zip_page(void){
  int rid;
  const char *z;
  char *zName, *zRid, *zKey;
  int nName, nRid;
  const char *zInclude;         /* The in= query parameter */
  const char *zExclude;         /* The ex= query parameter */
  Blob cacheKey;                /* The key to cache */