Changes On Branch ben-testing
Not logged in

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

Changes In Branch ben-testing Excluding Merge-Ins

This is equivalent to a diff from 073725ae0c to 47b5bf7d16

2011-08-14
23:14
Merge the ben-testing branch into trunk. check-in: 9a0c995826 user: drh tags: trunk
23:12
Fix the file_relative_name() function so that it works on windows. Closed-Leaf check-in: 47b5bf7d16 user: drh tags: ben-testing
17:54
Remove the seperate versionable version of db_get(), which now uses ctrlSettings to determine whether a setting is versionable or not. check-in: 3113f7b18f user: ben tags: ben-testing
07:21
Merge trunk into ben-testing, adjusting for versionable settings. check-in: 246ac307bb user: ben tags: ben-testing
2011-08-12
12:13
Fix harmless compiler warnings in tar.c. check-in: 073725ae0c user: drh tags: trunk
11:54
When forcing a rollback following an error, reset all SQL statement first so that the rollback can be successful. check-in: 9515143de5 user: drh tags: trunk

Changes to src/checkin.c.

    30     30   **
    31     31   ** If missingIsFatal is true, then any files that are missing or which
    32     32   ** are not true files results in a fatal error.
    33     33   */
    34     34   static void status_report(
    35     35     Blob *report,          /* Append the status report here */
    36     36     const char *zPrefix,   /* Prefix on each line of the report */
    37         -  int missingIsFatal     /* MISSING and NOT_A_FILE are fatal errors */
           37  +  int missingIsFatal,    /* MISSING and NOT_A_FILE are fatal errors */
           38  +  int cwdRelative        /* Report relative to the current working dir */ 
    38     39   ){
    39     40     Stmt q;
    40     41     int nPrefix = strlen(zPrefix);
    41     42     int nErr = 0;
           43  +  Blob rewrittenPathname;
    42     44     db_prepare(&q, 
    43     45       "SELECT pathname, deleted, chnged, rid, coalesce(origname!=pathname,0)"
    44     46       "  FROM vfile "
    45     47       " WHERE file_is_selected(id)"
    46     48       "   AND (chnged OR deleted OR rid=0 OR pathname!=origname) ORDER BY 1"
    47     49     );
           50  +  blob_zero(&rewrittenPathname);
    48     51     while( db_step(&q)==SQLITE_ROW ){
    49     52       const char *zPathname = db_column_text(&q,0);
           53  +    const char *zDisplayName = zPathname;
    50     54       int isDeleted = db_column_int(&q, 1);
    51     55       int isChnged = db_column_int(&q,2);
    52     56       int isNew = db_column_int(&q,3)==0;
    53     57       int isRenamed = db_column_int(&q,4);
    54     58       char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
           59  +    if( cwdRelative ){
           60  +      file_relative_name(zFullName, &rewrittenPathname);
           61  +      zDisplayName = blob_str(&rewrittenPathname);
           62  +      if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){
           63  +        zDisplayName += 2;  /* no unnecessary ./ prefix */
           64  +      }
           65  +    }
    55     66       blob_append(report, zPrefix, nPrefix);
    56     67       if( isDeleted ){
    57         -      blob_appendf(report, "DELETED    %s\n", zPathname);
           68  +      blob_appendf(report, "DELETED    %s\n", zDisplayName);
    58     69       }else if( !file_isfile(zFullName) ){
    59     70         if( file_access(zFullName, 0)==0 ){
    60         -        blob_appendf(report, "NOT_A_FILE %s\n", zPathname);
           71  +        blob_appendf(report, "NOT_A_FILE %s\n", zDisplayName);
    61     72           if( missingIsFatal ){
    62         -          fossil_warning("not a file: %s", zPathname);
           73  +          fossil_warning("not a file: %s", zDisplayName);
    63     74             nErr++;
    64     75           }
    65     76         }else{
    66         -        blob_appendf(report, "MISSING    %s\n", zPathname);
           77  +        blob_appendf(report, "MISSING    %s\n", zDisplayName);
    67     78           if( missingIsFatal ){
    68         -          fossil_warning("missing file: %s", zPathname);
           79  +          fossil_warning("missing file: %s", zDisplayName);
    69     80             nErr++;
    70     81           }
    71     82         }
    72     83       }else if( isNew ){
    73         -      blob_appendf(report, "ADDED      %s\n", zPathname);
           84  +      blob_appendf(report, "ADDED      %s\n", zDisplayName);
    74     85       }else if( isDeleted ){
    75         -      blob_appendf(report, "DELETED    %s\n", zPathname);
           86  +      blob_appendf(report, "DELETED    %s\n", zDisplayName);
    76     87       }else if( isChnged==2 ){
    77         -      blob_appendf(report, "UPDATED_BY_MERGE %s\n", zPathname);
           88  +      blob_appendf(report, "UPDATED_BY_MERGE %s\n", zDisplayName);
    78     89       }else if( isChnged==3 ){
    79         -      blob_appendf(report, "ADDED_BY_MERGE %s\n", zPathname);
           90  +      blob_appendf(report, "ADDED_BY_MERGE %s\n", zDisplayName);
    80     91       }else if( isChnged==1 ){
    81         -      blob_appendf(report, "EDITED     %s\n", zPathname);
           92  +      blob_appendf(report, "EDITED     %s\n", zDisplayName);
    82     93       }else if( isRenamed ){
    83         -      blob_appendf(report, "RENAMED    %s\n", zPathname);
           94  +      blob_appendf(report, "RENAMED    %s\n", zDisplayName);
    84     95       }
    85     96       free(zFullName);
    86     97     }
           98  +  blob_reset(&rewrittenPathname);
    87     99     db_finalize(&q);
    88    100     db_prepare(&q, "SELECT uuid FROM vmerge JOIN blob ON merge=rid"
    89    101                    " WHERE id=0");
    90    102     while( db_step(&q)==SQLITE_ROW ){
    91    103       blob_append(report, zPrefix, nPrefix);
    92    104       blob_appendf(report, "MERGED_WITH %s\n", db_column_text(&q, 0));
    93    105     }
    94    106     db_finalize(&q);
    95    107     if( nErr ){
    96    108       fossil_fatal("aborting due to prior errors");
    97    109     }
    98    110   }
          111  +
          112  +/*
          113  +** Use the "relative-paths" setting and the --abs-paths and
          114  +** --rel-paths command line options to determine whether the
          115  +** status report should be shown relative to the current
          116  +** working directory.
          117  +*/
          118  +static int determine_cwd_relative_option()
          119  +{
          120  +  int relativePaths = db_get_boolean("relative-paths", 1);
          121  +  int absPathOption = find_option("abs-paths", 0, 0)!=0;
          122  +  int relPathOption = find_option("rel-paths", 0, 0)!=0;
          123  +  if( absPathOption ){ relativePaths = 0; }
          124  +  if( relPathOption ){ relativePaths = 1; }
          125  +  return relativePaths;
          126  +}
    99    127   
   100    128   /*
   101    129   ** COMMAND: changes
   102    130   **
   103    131   ** Usage: %fossil changes
   104    132   **
   105    133   ** Report on the edit status of all files in the current checkout.
   106    134   ** See also the "status" and "extra" commands.
   107    135   **
          136  +** Pathnames are displayed according to the "relative-paths" setting,
          137  +** unless overridden by the --abs-paths or --rel-paths options.
          138  +**
   108    139   ** Options:
   109    140   **
   110    141   **    --sha1sum         Verify file status using SHA1 hashing rather
   111    142   **                      than relying on file mtimes.
          143  +**
          144  +**    --abs-paths       Display absolute pathnames.
          145  +**
          146  +**    --rel-paths       Display pathnames relative to the current working
          147  +**                      directory.
   112    148   */
   113    149   void changes_cmd(void){
   114    150     Blob report;
   115    151     int vid;
   116    152     int useSha1sum = find_option("sha1sum", 0, 0)!=0;
          153  +  int cwdRelative = 0;
   117    154     db_must_be_within_tree();
          155  +  cwdRelative = determine_cwd_relative_option();
   118    156     blob_zero(&report);
   119    157     vid = db_lget_int("checkout", 0);
   120    158     vfile_check_signature(vid, 0, useSha1sum);
   121         -  status_report(&report, "", 0);
          159  +  status_report(&report, "", 0, cwdRelative);
   122    160     blob_write_to_file(&report, "-");
   123    161   }
   124    162   
   125    163   /*
   126    164   ** COMMAND: status
   127    165   **
   128    166   ** Usage: %fossil status
   129    167   **
   130    168   ** Report on the status of the current checkout.
   131    169   **
          170  +** Pathnames are displayed according to the "relative-paths" setting,
          171  +** unless overridden by the --abs-paths or --rel-paths options.
          172  +**
   132    173   ** Options:
   133    174   **
   134    175   **    --sha1sum         Verify file status using SHA1 hashing rather
   135    176   **                      than relying on file mtimes.
          177  +**
          178  +**    --abs-paths       Display absolute pathnames.
          179  +**
          180  +**    --rel-paths       Display pathnames relative to the current working
          181  +**                      directory.
   136    182   */
   137    183   void status_cmd(void){
   138    184     int vid;
   139    185     db_must_be_within_tree();
   140    186          /* 012345678901234 */
   141    187     fossil_print("repository:   %s\n", db_lget("repository",""));
   142    188     fossil_print("local-root:   %s\n", g.zLocalRoot);
................................................................................
   210    256   **
   211    257   ** Files and subdirectories whose names begin with "." are normally
   212    258   ** ignored but can be included by adding the --dotfiles option.
   213    259   **
   214    260   ** The GLOBPATTERN is a comma-separated list of GLOB expressions for
   215    261   ** files that are ignored.  The GLOBPATTERN specified by the "ignore-glob"
   216    262   ** is used if the --ignore option is omitted.
          263  +**
          264  +** Pathnames are displayed according to the "relative-paths" setting,
          265  +** unless overridden by the --abs-paths or --rel-paths options.
          266  +**
          267  +** Options:
          268  +**
          269  +**    --dotfiles        Include files with names beginning with "."
          270  +**
          271  +**    --ignore GLOBPATTERN 
          272  +**                      Override the "ignore-glob" setting.
          273  +**
          274  +**    --abs-paths       Display absolute pathnames.
          275  +**
          276  +**    --rel-paths       Display pathnames relative to the current working
          277  +**                      directory.
   217    278   */
   218    279   void extra_cmd(void){
   219    280     Blob path;
   220    281     Blob repo;
   221    282     Stmt q;
   222    283     int n;
   223    284     const char *zIgnoreFlag = find_option("ignore",0,1);
   224    285     int allFlag = find_option("dotfiles",0,0)!=0;
          286  +  int cwdRelative = 0;
   225    287     int outputManifest;
   226    288     Glob *pIgnore;
          289  +  Blob rewrittenPathname;
          290  +  const char *zPathname, *zDisplayName;
   227    291   
   228    292     db_must_be_within_tree();
          293  +  cwdRelative = determine_cwd_relative_option();
   229    294     outputManifest = db_get_boolean("manifest",0);
   230    295     db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
   231    296     n = strlen(g.zLocalRoot);
   232    297     blob_init(&path, g.zLocalRoot, n-1);
   233    298     if( zIgnoreFlag==0 ){
   234    299       zIgnoreFlag = db_get("ignore-glob", 0);
   235    300     }
................................................................................
   241    306         " WHERE x NOT IN (%s)"
   242    307         " ORDER BY 1",
   243    308         fossil_all_reserved_names()
   244    309     );
   245    310     if( file_tree_name(g.zRepositoryName, &repo, 0) ){
   246    311       db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo);
   247    312     }
          313  +  blob_zero(&rewrittenPathname);
   248    314     while( db_step(&q)==SQLITE_ROW ){
   249         -    fossil_print("%s\n", db_column_text(&q, 0));
          315  +    zDisplayName = zPathname = db_column_text(&q, 0);
          316  +    if( cwdRelative ) {
          317  +      char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
          318  +      file_relative_name(zFullName, &rewrittenPathname);
          319  +      free(zFullName);
          320  +      zDisplayName = blob_str(&rewrittenPathname);
          321  +      if( zDisplayName[0]=='.' && zDisplayName[1]=='/' ){
          322  +        zDisplayName += 2;  /* no unnecessary ./ prefix */
          323  +      }
          324  +    }
          325  +    fossil_print("%s\n", zDisplayName);
   250    326     }
          327  +  blob_reset(&rewrittenPathname);
   251    328     db_finalize(&q);
   252    329   }
   253    330   
   254    331   /*
   255    332   ** COMMAND: clean
   256    333   ** Usage: %fossil clean ?--force? ?--dotfiles? ?--ignore GLOBPATTERN?
   257    334   **
................................................................................
   365    442     if( g.markPrivate ){
   366    443       blob_append(&text,
   367    444         "# PRIVATE BRANCH: This check-in will be private and will not sync to\n"
   368    445         "# repositories.\n"
   369    446         "#\n", -1
   370    447       );
   371    448     }
   372         -  status_report(&text, "# ", 1);
          449  +  status_report(&text, "# ", 1, 0);
   373    450     zEditor = db_get("editor", 0);
   374    451     if( zEditor==0 ){
   375    452       zEditor = getenv("VISUAL");
   376    453     }
   377    454     if( zEditor==0 ){
   378    455       zEditor = getenv("EDITOR");
   379    456     }

Changes to src/checkout.c.

   230    230     }
   231    231     db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid);
   232    232     if( !keepFlag ){
   233    233       vfile_to_disk(vid, 0, 1, promptFlag);
   234    234     }
   235    235     checkout_set_all_exe(vid);
   236    236     manifest_to_disk(vid);
          237  +  ensure_empty_dirs_created();
   237    238     db_lset_int("checkout", vid);
   238    239     undo_reset();
   239    240     db_multi_exec("DELETE FROM vmerge");
   240    241     if( !keepFlag && db_get_boolean("repo-cksum",1) ){
   241    242       vfile_aggregate_checksum_manifest(vid, &cksum1, &cksum1b);
   242    243       vfile_aggregate_checksum_disk(vid, &cksum2);
   243    244       if( blob_compare(&cksum1, &cksum2) ){

Changes to src/clone.c.

    35     35   ** admin user. This can be overridden using the -A|--admin-user
    36     36   ** parameter.
    37     37   **
    38     38   ** Options:
    39     39   **
    40     40   **    --admin-user|-A USERNAME    Make USERNAME the administrator
    41     41   **    --private                   Also clone private branches 
           42  +**    --ssl-identity=filename     Use the SSL identity if requested by the server
    42     43   **
    43     44   */
    44     45   void clone_cmd(void){
    45     46     char *zPassword;
    46     47     const char *zDefaultUser;   /* Optional name of the default user */
    47     48     const char *zPw;     /* The user clone password */
    48     49     int nErr = 0;
................................................................................
    92     93       db_begin_transaction();
    93     94       db_record_repository_filename(g.argv[3]);
    94     95       db_initial_setup(0, zDefaultUser, 0);
    95     96       user_select();
    96     97       db_set("content-schema", CONTENT_SCHEMA, 0);
    97     98       db_set("aux-schema", AUX_SCHEMA, 0);
    98     99       db_set("last-sync-url", g.argv[2], 0);
          100  +    if( g.zSSLIdentity!=0 ){
          101  +      /* If the --ssl-identity option was specified, store it as a setting */
          102  +      Blob fn;
          103  +      blob_zero(&fn);
          104  +      file_canonical_name(g.zSSLIdentity, &fn);
          105  +      db_set("ssl-identity", blob_str(&fn), 0);
          106  +      blob_reset(&fn);
          107  +    }
    99    108       db_multi_exec(
   100    109         "REPLACE INTO config(name,value,mtime)"
   101    110         " VALUES('server-code', lower(hex(randomblob(20))), now());"
   102    111       );
   103    112       url_enable_proxy(0);
   104    113       url_get_password_if_needed();
   105    114       g.xlinkClusterOnly = 1;

Changes to src/configure.c.

    79     79     { "logo-mimetype",          CONFIGSET_SKIN },
    80     80     { "logo-image",             CONFIGSET_SKIN },
    81     81     { "project-name",           CONFIGSET_PROJ },
    82     82     { "project-description",    CONFIGSET_PROJ },
    83     83     { "manifest",               CONFIGSET_PROJ },
    84     84     { "ignore-glob",            CONFIGSET_PROJ },
    85     85     { "crnl-glob",              CONFIGSET_PROJ },
           86  +  { "empty-dirs",             CONFIGSET_PROJ },
    86     87     { "index-page",             CONFIGSET_SKIN },
    87     88     { "timeline-block-markup",  CONFIGSET_SKIN },
    88     89     { "timeline-max-comment",   CONFIGSET_SKIN },
    89     90     { "ticket-table",           CONFIGSET_TKT  },
    90     91     { "ticket-common",          CONFIGSET_TKT  },
    91     92     { "ticket-newpage",         CONFIGSET_TKT  },
    92     93     { "ticket-viewpage",        CONFIGSET_TKT  },

Changes to src/db.c.

  1397   1397   void db_swap_connections(void){
  1398   1398     if( !g.useAttach ){
  1399   1399       sqlite3 *dbTemp = g.db;
  1400   1400       g.db = g.dbConfig;
  1401   1401       g.dbConfig = dbTemp;
  1402   1402     }
  1403   1403   }
         1404  +
         1405  +/*
         1406  +** Logic for reading potentially versioned settings from
         1407  +** .fossil-settings/<name> , and emits warnings if necessary.
         1408  +** Returns the non-versioned value without modification if there is no
         1409  +** versioned value.
         1410  +*/
         1411  +static char *db_get_do_versionable(const char *zName, char *zNonVersionedSetting){
         1412  +  /* Attempt to load the versioned setting from a checked out file */
         1413  +  char *zVersionedSetting = 0;
         1414  +  int noWarn = 0;
         1415  +
         1416  +  if( db_open_local() ){
         1417  +    Blob versionedPathname;
         1418  +    char *zVersionedPathname;
         1419  +    blob_zero(&versionedPathname);
         1420  +    blob_appendf(&versionedPathname, "%s/.fossil-settings/%s",
         1421  +                 g.zLocalRoot, zName);
         1422  +    zVersionedPathname = blob_str(&versionedPathname);
         1423  +    if( file_size(zVersionedPathname)>=0 ){
         1424  +      /* File exists, and contains the value for this setting. Load from
         1425  +      ** the file. */
         1426  +      Blob setting;
         1427  +      blob_zero(&setting);
         1428  +      if( blob_read_from_file(&setting, zVersionedPathname) >= 0 ){
         1429  +        blob_trim(&setting); /* Avoid non-obvious problems with line endings
         1430  +                             ** on boolean properties */
         1431  +        zVersionedSetting = strdup(blob_str(&setting));
         1432  +      }
         1433  +      blob_reset(&setting);
         1434  +      /* See if there's a no-warn flag */
         1435  +      blob_append(&versionedPathname, ".no-warn", -1);
         1436  +      if( file_size(blob_str(&versionedPathname))>=0 ){
         1437  +        noWarn = 1;
         1438  +      }
         1439  +    }
         1440  +    blob_reset(&versionedPathname);
         1441  +  }
         1442  +  /* Display a warning? */
         1443  +  if( zVersionedSetting!=0 && zNonVersionedSetting!=0
         1444  +   && zNonVersionedSetting[0]!='\0' && !noWarn
         1445  +  ){
         1446  +    /* There's a versioned setting, and a non-versioned setting. Tell
         1447  +    ** the user about the conflict */
         1448  +    fossil_warning(
         1449  +        "setting %s has both versioned and non-versioned values: using "
         1450  +        "versioned value from file .fossil-settings/%s (to silence this "
         1451  +        "warning, either create an empty file named "
         1452  +        ".fossil-settings/%s.no-warn or delete the non-versioned setting "
         1453  +        " with \"fossil unset %s\")", zName, zName, zName, zName
         1454  +    );
         1455  +  }
         1456  +  /* Prefer the versioned setting */
         1457  +  return ( zVersionedSetting!=0 ) ? zVersionedSetting : zNonVersionedSetting;
         1458  +}
         1459  +
  1404   1460   
  1405   1461   /*
  1406   1462   ** Get and set values from the CONFIG, GLOBAL_CONFIG and VVAR table in the
  1407   1463   ** repository and local databases.
  1408   1464   */
  1409   1465   char *db_get(const char *zName, char *zDefault){
  1410   1466     char *z = 0;
         1467  +  int i;
         1468  +  const struct stControlSettings *ctrlSetting = 0;
         1469  +  /* Is this a setting? */
         1470  +  for(i=0; ctrlSettings[i].name; i++){
         1471  +    if( strcmp(ctrlSettings[i].name, zName)==0 ){
         1472  +      ctrlSetting = &(ctrlSettings[i]);
         1473  +      break;
         1474  +    }
         1475  +  }
  1411   1476     if( g.repositoryOpen ){
  1412   1477       z = db_text(0, "SELECT value FROM config WHERE name=%Q", zName);
  1413   1478     }
  1414   1479     if( z==0 && g.configOpen ){
  1415   1480       db_swap_connections();
  1416   1481       z = db_text(0, "SELECT value FROM global_config WHERE name=%Q", zName);
  1417   1482       db_swap_connections();
         1483  +  }
         1484  +  if( ctrlSetting!=0 && ctrlSetting->versionable ){
         1485  +    /* This is a versionable setting, try and get the info from a checked out file */
         1486  +    z = db_get_do_versionable(zName, z);
  1418   1487     }
  1419   1488     if( z==0 ){
  1420   1489       z = zDefault;
  1421   1490     }
  1422   1491     return z;
  1423   1492   }
  1424   1493   void db_set(const char *zName, const char *zValue, int globalFlag){
................................................................................
  1601   1670       info_cmd();
  1602   1671     }
  1603   1672   }
  1604   1673   
  1605   1674   /*
  1606   1675   ** Print the value of a setting named zName
  1607   1676   */
  1608         -static void print_setting(const char *zName){
         1677  +static void print_setting(const struct stControlSettings *ctrlSetting, int localOpen){
  1609   1678     Stmt q;
  1610   1679     if( g.repositoryOpen ){
  1611   1680       db_prepare(&q,
  1612   1681          "SELECT '(local)', value FROM config WHERE name=%Q"
  1613   1682          " UNION ALL "
  1614   1683          "SELECT '(global)', value FROM global_config WHERE name=%Q",
  1615         -       zName, zName
         1684  +       ctrlSetting->name, ctrlSetting->name
  1616   1685       );
  1617   1686     }else{
  1618   1687       db_prepare(&q,
  1619   1688         "SELECT '(global)', value FROM global_config WHERE name=%Q",
  1620         -      zName
         1689  +      ctrlSetting->name
  1621   1690       );
  1622   1691     }
  1623   1692     if( db_step(&q)==SQLITE_ROW ){
  1624         -    fossil_print("%-20s %-8s %s\n", zName, db_column_text(&q, 0),
         1693  +    fossil_print("%-20s %-8s %s\n", ctrlSetting->name, db_column_text(&q, 0),
  1625   1694           db_column_text(&q, 1));
  1626   1695     }else{
  1627         -    fossil_print("%-20s\n", zName);
         1696  +    fossil_print("%-20s\n", ctrlSetting->name);
         1697  +  }
         1698  +  if( ctrlSetting->versionable && localOpen ){
         1699  +    /* Check to see if this is overridden by a versionable settings file */
         1700  +    Blob versionedPathname;
         1701  +    blob_zero(&versionedPathname);
         1702  +    blob_appendf(&versionedPathname, "%s/.fossil-settings/%s", g.zLocalRoot, ctrlSetting->name);
         1703  +    if( file_size(blob_str(&versionedPathname))>=0 ){
         1704  +      fossil_print("  (overridden by contents of file .fossil-settings/%s)\n", ctrlSetting->name);
         1705  +    }
  1628   1706     }
  1629   1707     db_finalize(&q);
  1630   1708   }
  1631   1709   
  1632   1710   
  1633   1711   /*
  1634   1712   ** define all settings, which can be controlled via the set/unset
................................................................................
  1640   1718   ** set-commands and displays the 'set'-help as info.
  1641   1719   */
  1642   1720   #if INTERFACE
  1643   1721   struct stControlSettings {
  1644   1722     char const *name;     /* Name of the setting */
  1645   1723     char const *var;      /* Internal variable name used by db_set() */
  1646   1724     int width;            /* Width of display.  0 for boolean values */
         1725  +  int versionable;      /* Is this setting versionable? */
  1647   1726     char const *def;      /* Default value */
  1648   1727   };
  1649   1728   #endif /* INTERFACE */
  1650   1729   struct stControlSettings const ctrlSettings[] = {
  1651         -  { "access-log",    0,                0, "off"                 },
  1652         -  { "auto-captcha",  "autocaptcha",    0, "on"                  },
  1653         -  { "auto-shun",     0,                0, "on"                  },
  1654         -  { "autosync",      0,                0, "on"                  },
  1655         -  { "binary-glob",   0,               32, ""                    },
  1656         -  { "case-sensitive",0,                0, "on"                  },
  1657         -  { "clearsign",     0,                0, "off"                 },
  1658         -  { "crnl-glob",     0,               16, ""                    },
  1659         -  { "default-perms", 0,               16, "u"                   },
  1660         -  { "diff-command",  0,               16, ""                    },
  1661         -  { "dont-push",     0,                0, "off"                 },
  1662         -  { "editor",        0,               16, ""                    },
  1663         -  { "gdiff-command", 0,               16, "gdiff"               },
  1664         -  { "gmerge-command",0,               40, ""                    },
  1665         -  { "https-login",   0,                0, "off"                 },
  1666         -  { "ignore-glob",   0,               40, ""                    },
  1667         -  { "http-port",     0,               16, "8080"                },
  1668         -  { "localauth",     0,                0, "off"                 },
  1669         -  { "main-branch",   0,               40, "trunk"               },
  1670         -  { "manifest",      0,                0, "off"                 },
  1671         -  { "max-upload",    0,               25, "250000"              },
  1672         -  { "mtime-changes", 0,                0, "on"                  },
  1673         -  { "pgp-command",   0,               32, "gpg --clearsign -o " },
  1674         -  { "proxy",         0,               32, "off"                 },
  1675         -  { "repo-cksum",    0,                0, "on"                  },
  1676         -  { "self-register", 0,                0, "off"                 },
  1677         -  { "ssh-command",   0,               32, ""                    },
  1678         -  { "web-browser",   0,               32, ""                    },
  1679         -  { "white-foreground", 0,             0, "off"                 },
  1680         -  { 0,0,0,0 }
         1730  +  { "access-log",    0,                0, 0, "off"                 },
         1731  +  { "auto-captcha",  "autocaptcha",    0, 0, "on"                  },
         1732  +  { "auto-shun",     0,                0, 0, "on"                  },
         1733  +  { "autosync",      0,                0, 0, "on"                  },
         1734  +  { "binary-glob",   0,               32, 1, ""                    },
         1735  +  { "clearsign",     0,                0, 0, "off"                 },
         1736  +  { "case-sensitive",0,                0, 0, "on"                  },
         1737  +  { "crnl-glob",     0,               16, 1, ""                    },
         1738  +  { "default-perms", 0,               16, 0, "u"                   },
         1739  +  { "diff-command",  0,               16, 0, ""                    },
         1740  +  { "dont-push",     0,                0, 0, "off"                 },
         1741  +  { "editor",        0,               16, 0, ""                    },
         1742  +  { "gdiff-command", 0,               16, 0, "gdiff"               },
         1743  +  { "gmerge-command",0,               40, 0, ""                    },
         1744  +  { "https-login",   0,                0, 0, "off"                 },
         1745  +  { "ignore-glob",   0,               40, 1, ""                    },
         1746  +  { "empty-dirs",    0,               40, 1, ""                    },
         1747  +  { "http-port",     0,               16, 0, "8080"                },
         1748  +  { "localauth",     0,                0, 0, "off"                 },
         1749  +  { "main-branch",   0,               40, 0, "trunk"               },
         1750  +  { "manifest",      0,                0, 1, "off"                 },
         1751  +  { "max-upload",    0,               25, 0, "250000"              },
         1752  +  { "mtime-changes", 0,                0, 0, "on"                  },
         1753  +  { "pgp-command",   0,               32, 0, "gpg --clearsign -o " },
         1754  +  { "proxy",         0,               32, 0, "off"                 },
         1755  +  { "relative-paths",0,                0, 0, "on"                  },
         1756  +  { "repo-cksum",    0,                0, 0, "on"                  },
         1757  +  { "self-register", 0,                0, 0, "off"                 },
         1758  +  { "ssl-ca-location",0,              40, 0, ""                    },
         1759  +  { "ssl-identity",  0,               40, 0, ""                    },
         1760  +  { "ssh-command",   0,               32, 0, ""                    },
         1761  +  { "web-browser",   0,               32, 0, ""                    },
         1762  +  { "white-foreground", 0,             0, 0, "off"                 },
         1763  +  { 0,0,0,0,0 }
  1681   1764   };
  1682   1765   
  1683   1766   /*
  1684   1767   ** COMMAND: settings
  1685   1768   ** COMMAND: unset
  1686   1769   **
  1687   1770   ** %fossil settings ?PROPERTY? ?VALUE? ?-global?
  1688   1771   ** %fossil unset PROPERTY ?-global?
  1689   1772   **
  1690   1773   ** The "settings" command with no arguments lists all properties and their
  1691   1774   ** values.  With just a property name it shows the value of that property.
  1692   1775   ** With a value argument it changes the property for the current repository.
         1776  +**
         1777  +** Settings marked as versionable are overridden by the contents of the
         1778  +** file named .fossil-settings/PROPERTY in the checked out files, if that
         1779  +** file exists.
  1693   1780   **
  1694   1781   ** The "unset" command clears a property setting.
  1695   1782   **
  1696   1783   **
  1697   1784   **    auto-captcha     If enabled, the Login page provides a button to
  1698   1785   **                     fill in the captcha password.  Default: on
  1699   1786   **
................................................................................
  1703   1790   **
  1704   1791   **    autosync         If enabled, automatically pull prior to commit
  1705   1792   **                     or update and automatically push after commit or
  1706   1793   **                     tag or branch creation.  If the value is "pullonly"
  1707   1794   **                     then only pull operations occur automatically.
  1708   1795   **                     Default: on
  1709   1796   **
  1710         -**    binary-glob      The VALUE is a comma-separated list of GLOB patterns
  1711         -**                     that should be treated as binary files for merging
  1712         -**                     purposes.  Example:   *.xml
         1797  +**    binary-glob      The VALUE is a comma or newline-separated list of
         1798  +**     (versionable)   GLOB patterns that should be treated as binary files
         1799  +**                     for merging purposes.  Example:   *.xml
  1713   1800   **
  1714   1801   **    case-sensitive   If TRUE, the files whose names differ only in case
  1715   1802   **                     care considered distinct.  If FALSE files whose names
  1716   1803   **                     differ only in case are the same file.  Defaults to
  1717   1804   **                     TRUE for unix and FALSE for windows and mac.
  1718   1805   **
  1719   1806   **    clearsign        When enabled, fossil will attempt to sign all commits
  1720   1807   **                     with gpg.  When disabled (the default), commits will
  1721   1808   **                     be unsigned.  Default: off
  1722   1809   **
  1723         -**    crnl-glob        A comma-separated list of GLOB patterns for text files
  1724         -**                     in which it is ok to have CR+NL line endings.
         1810  +**    crnl-glob        A comma or newline-separated list of GLOB patterns for
         1811  +**     (versionable)   text files in which it is ok to have CR+NL line endings.
  1725   1812   **                     Set to "*" to disable CR+NL checking.
  1726   1813   **
  1727   1814   **    default-perms    Permissions given automatically to new users.  For more
  1728   1815   **                     information on permissions see Users page in Server
  1729   1816   **                     Administration of the HTTP UI. Default: u.
  1730   1817   **
  1731   1818   **    diff-command     External command to run when performing a diff.
  1732   1819   **                     If undefined, the internal text diff will be used.
  1733   1820   **
  1734   1821   **    dont-push        Prevent this repository from pushing from client to
  1735   1822   **                     server.  Useful when setting up a private branch.
         1823  +**
         1824  +**    empty-dirs       A comma or newline-separated list of pathnames. On
         1825  +**     (versionable)   update and checkout commands, if no file or directory
         1826  +**                     exists with that name, an empty directory will be
         1827  +**                     created.
  1736   1828   **
  1737   1829   **    editor           Text editor command used for check-in comments.
  1738   1830   **
  1739   1831   **    gdiff-command    External command to run when performing a graphical
  1740   1832   **                     diff. If undefined, text diff will be used.
  1741   1833   **
  1742   1834   **    gmerge-command   A graphical merge conflict resolver command operating
................................................................................
  1747   1839   **
  1748   1840   **    http-port        The TCP/IP port number to use by the "server"
  1749   1841   **                     and "ui" commands.  Default: 8080
  1750   1842   **
  1751   1843   **    https-login      Send login creditials using HTTPS instead of HTTP
  1752   1844   **                     even if the login page request came via HTTP.
  1753   1845   **
  1754         -**    ignore-glob      The VALUE is a comma-separated list of GLOB patterns
  1755         -**                     specifying files that the "extra" command will ignore.
  1756         -**                     Example:  *.o,*.obj,*.exe
         1846  +**    ignore-glob      The VALUE is a comma or newline-separated list of GLOB
         1847  +**     (versionable)   patterns specifying files that the "extra" command will
         1848  +**                     ignore.  Example:  *.o,*.obj,*.exe
  1757   1849   **
  1758   1850   **    localauth        If enabled, require that HTTP connections from
  1759   1851   **                     127.0.0.1 be authenticated by password.  If
  1760   1852   **                     false, all HTTP requests from localhost have
  1761   1853   **                     unrestricted access to the repository.
  1762   1854   **
  1763   1855   **    main-branch      The primary branch for the project.  Default: trunk
  1764   1856   **
  1765   1857   **    manifest         If enabled, automatically create files "manifest" and
  1766         -**                     "manifest.uuid" in every checkout.  The SQLite and
         1858  +**     (versionable)   "manifest.uuid" in every checkout.  The SQLite and
  1767   1859   **                     Fossil repositories both require this.  Default: off.
  1768   1860   **
  1769   1861   **    max-upload       A limit on the size of uplink HTTP requests.  The
  1770   1862   **                     default is 250000 bytes.
  1771   1863   **
  1772   1864   **    mtime-changes    Use file modification times (mtimes) to detect when
  1773   1865   **                     files have been modified.  (Default "on".)
................................................................................
  1775   1867   **    pgp-command      Command used to clear-sign manifests at check-in.
  1776   1868   **                     The default is "gpg --clearsign -o ".
  1777   1869   **
  1778   1870   **    proxy            URL of the HTTP proxy.  If undefined or "off" then
  1779   1871   **                     the "http_proxy" environment variable is consulted.
  1780   1872   **                     If the http_proxy environment variable is undefined
  1781   1873   **                     then a direct HTTP connection is used.
         1874  +**
         1875  +**    relative-paths   When showing changes and extras, report paths relative
         1876  +**                     to the current working directory.  Default: "on"
  1782   1877   **
  1783   1878   **    repo-cksum       Compute checksums over all files in each checkout
  1784   1879   **                     as a double-check of correctness.  Defaults to "on".
  1785   1880   **                     Disable on large repositories for a performance
  1786   1881   **                     improvement.
  1787   1882   **
  1788   1883   **    self-register    Allow users to register themselves through the HTTP UI.
  1789   1884   **                     This is useful if you want to see other names than
  1790   1885   **                     "Anonymous" in e.g. ticketing system. On the other hand
  1791   1886   **                     users can not be deleted. Default: off.
         1887  +**
         1888  +**    ssl-ca-location  The full pathname to a file containing PEM encoded
         1889  +**                     CA root certificates, or a directory of certificates
         1890  +**                     with filenames formed from the certificate hashes as
         1891  +**                     required by OpenSSL.
         1892  +**                     If set, this will override the OS default list of
         1893  +**                     OpenSSL CAs. If unset, the default list will be used.
         1894  +**                     Some platforms may add additional certificates.
         1895  +**                     Check your platform behaviour is as required if the
         1896  +**                     exact contents of the CA root is critical for your
         1897  +**                     application.
         1898  +**
         1899  +**    ssl-identity     The full pathname to a file containing a certificate
         1900  +**                     and private key in PEM format. Create by concatenating
         1901  +**                     the certificate and private key files.
         1902  +**                     This identity will be presented to SSL servers to
         1903  +**                     authenticate this client, in addition to the normal
         1904  +**                     password authentication.
  1792   1905   **
  1793   1906   **    ssh-command      Command used to talk to a remote machine with
  1794   1907   **                     the "ssh://" protocol.
  1795   1908   **
  1796   1909   **    web-browser      A shell command used to launch your preferred
  1797   1910   **                     web browser when given a URL as an argument.
  1798   1911   **                     Defaults to "start" on windows, "open" on Mac,
................................................................................
  1809   1922     if( !g.repositoryOpen ){
  1810   1923       globalFlag = 1;
  1811   1924     }
  1812   1925     if( unsetFlag && g.argc!=3 ){
  1813   1926       usage("PROPERTY ?-global?");
  1814   1927     }
  1815   1928     if( g.argc==2 ){
         1929  +    int openLocal = db_open_local();
  1816   1930       for(i=0; ctrlSettings[i].name; i++){
  1817         -      print_setting(ctrlSettings[i].name);
         1931  +      print_setting(&ctrlSettings[i], openLocal);
  1818   1932       }
  1819   1933     }else if( g.argc==3 || g.argc==4 ){
  1820   1934       const char *zName = g.argv[2];
  1821   1935       int isManifest;
  1822   1936       int n = strlen(zName);
  1823   1937       for(i=0; ctrlSettings[i].name; i++){
  1824   1938         if( strncmp(ctrlSettings[i].name, zName, n)==0 ) break;
................................................................................
  1832   1946       }
  1833   1947       if( unsetFlag ){
  1834   1948         db_unset(ctrlSettings[i].name, globalFlag);
  1835   1949       }else if( g.argc==4 ){
  1836   1950         db_set(ctrlSettings[i].name, g.argv[3], globalFlag);
  1837   1951       }else{
  1838   1952         isManifest = 0;
  1839         -      print_setting(ctrlSettings[i].name);
         1953  +      print_setting(&ctrlSettings[i], db_open_local());
  1840   1954       }
  1841   1955       if( isManifest && g.localOpen ){
  1842   1956         manifest_to_disk(db_lget_int("checkout", 0));
  1843   1957       }
  1844   1958     }else{
  1845   1959       usage("?PROPERTY? ?VALUE?");
  1846   1960     }

Changes to src/file.c.

   497    497           if( z[i+2]=='/' || z[i+2]==0 ) return 0;
   498    498           if( z[i+2]=='.' && (z[i+3]=='/' || z[i+3]==0) ) return 0;
   499    499         }
   500    500       }
   501    501     }
   502    502     return 1;
   503    503   }
          504  +
          505  +/* 
          506  +** Return a pointer to the first character in a pathname past the
          507  +** drive letter.  This routine is a no-op on unix.
          508  +*/
          509  +char *file_without_drive_letter(char *zIn){
          510  +#ifdef _WIN32
          511  +  if( fossil_isalpha(zIn[0]) && zIn[1]==':' ) zIn += 2;
          512  +#endif
          513  +  return zIn;
          514  +}
   504    515   
   505    516   /*
   506    517   ** Compute a pathname for a file or directory that is relative
   507    518   ** to the current directory.
   508    519   */
   509    520   void file_relative_name(const char *zOrigName, Blob *pOut){
   510    521     char *zPath;
   511    522     blob_set(pOut, zOrigName);
   512    523     blob_resize(pOut, file_simplify_name(blob_buffer(pOut), blob_size(pOut))); 
   513         -  zPath = blob_buffer(pOut);
          524  +  zPath = file_without_drive_letter(blob_buffer(pOut));
   514    525     if( zPath[0]=='/' ){
   515    526       int i, j;
   516    527       Blob tmp;
   517         -    char zPwd[2000];
   518         -    file_getcwd(zPwd, sizeof(zPwd)-20);
   519         -    for(i=1; zPath[i] && zPwd[i]==zPath[i]; i++){}
          528  +    char *zPwd;
          529  +    char zBuf[2000];
          530  +    zPwd = zBuf;
          531  +    file_getcwd(zBuf, sizeof(zBuf)-20);
          532  +    zPwd = file_without_drive_letter(zBuf);
          533  +    i = 1;
          534  +#ifdef _WIN32
          535  +    while( zPath[i] && fossil_tolower(zPwd[i])==fossil_tolower(zPath[i]) ) i++;
          536  +#else
          537  +    while( zPath[i] && zPwd[i]==zPath[i] ) i++;
          538  +#endif
   520    539       if( zPath[i]==0 ){
   521    540         blob_reset(pOut);
   522    541         if( zPwd[i]==0 ){
   523    542           blob_append(pOut, ".", 1);
   524    543         }else{
   525    544           blob_append(pOut, "..", 2);
   526    545           for(j=i+1; zPwd[j]; j++){

Changes to src/glob.c.

   108    108     if( zPatternList==0 || zPatternList[0]==0 ) return 0;
   109    109     nList = strlen(zPatternList);
   110    110     p = fossil_malloc( sizeof(*p) + nList+1 );
   111    111     memset(p, 0, sizeof(*p));
   112    112     z = (char*)&p[1];
   113    113     memcpy(z, zPatternList, nList+1);
   114    114     while( z[0] ){
   115         -    while( z[0]==',' || z[0]==' ' ) z++;  /* Skip leading spaces */
          115  +    while( z[0]==',' || z[0]==' ' || z[0]=='\n' || z[0]=='\r' ) z++;  /* Skip leading spaces and newlines */
   116    116       if( z[0]=='\'' || z[0]=='"' ){
   117    117         delimiter = z[0];
   118    118         z++;
   119    119       }else{
   120    120         delimiter = ',';
   121    121       }
   122    122       if( z[0]==0 ) break;
   123    123       p->azPattern = fossil_realloc(p->azPattern, (p->nPattern+1)*sizeof(char*) );
   124    124       p->azPattern[p->nPattern++] = z;
   125         -    for(i=0; z[i] && z[i]!=delimiter; i++){}
          125  +    for(i=0; z[i] && z[i]!=delimiter && z[i]!='\n' && z[i]!='\r'; i++){}
   126    126       if( delimiter==',' ){
   127         -      /* Remove trailing spaces on a comma-delimited pattern */
   128         -      for(j=i; j>1 && z[j-1]==' '; j--){}
          127  +      /* Remove trailing spaces / newlines on a comma-delimited pattern */
          128  +      for(j=i; j>1 && (z[j-1]==' ' || z[j-1]=='\n' || z[j-1]=='\r'); j--){}
   129    129         if( j<i ) z[j] = 0;
   130    130       }
   131    131       if( z[i]==0 ) break;
   132    132       z[i] = 0;
   133    133       z += i+1;
   134    134     }
   135    135     return p;

Changes to src/http_ssl.c.

    76     76   
    77     77   /*
    78     78   ** Return the current SSL error message
    79     79   */
    80     80   const char *ssl_errmsg(void){
    81     81     return sslErrMsg;
    82     82   }
           83  +
           84  +/*
           85  +** When a server requests a client certificate that hasn't been provided,
           86  +** display a warning message explaining what to do next.
           87  +*/
           88  +static int ssl_client_cert_callback(SSL *ssl, X509 **x509, EVP_PKEY **pkey){
           89  +  fossil_warning("The remote server requested a client certificate for "
           90  +    "authentication. Specify the pathname to a file containing the PEM "
           91  +    "encoded certificate and private key with the --ssl-identity option "
           92  +    "or the ssl-identity setting.");
           93  +  return 0; /* no cert available */    
           94  +}
    83     95   
    84     96   /*
    85     97   ** Call this routine once before any other use of the SSL interface.
    86     98   ** This routine does initial configuration of the SSL module.
    87     99   */
    88    100   void ssl_global_init(void){
          101  +  const char *zCaSetting = 0, *zCaFile = 0, *zCaDirectory = 0;
          102  +  
    89    103     if( sslIsInit==0 ){
    90    104       SSL_library_init();
    91    105       SSL_load_error_strings();
    92    106       ERR_load_BIO_strings();
    93    107       OpenSSL_add_all_algorithms();    
    94    108       sslCtx = SSL_CTX_new(SSLv23_client_method());
    95         -    X509_STORE_set_default_paths(SSL_CTX_get_cert_store(sslCtx));
          109  +    
          110  +    /* Set up acceptable CA root certificates */
          111  +    zCaSetting = db_get("ssl-ca-location", 0);
          112  +    if( zCaSetting==0 || zCaSetting[0]=='\0' ){
          113  +      /* CA location not specified, use platform's default certificate store */
          114  +      X509_STORE_set_default_paths(SSL_CTX_get_cert_store(sslCtx));
          115  +    }else{
          116  +      /* User has specified a CA location, make sure it exists and use it */
          117  +      switch( file_isdir(zCaSetting) ){
          118  +        case 0: { /* doesn't exist */
          119  +          fossil_fatal("ssl-ca-location is set to '%s', "
          120  +              "but is not a file or directory", zCaSetting);
          121  +          break;
          122  +        }
          123  +        case 1: { /* directory */
          124  +          zCaDirectory = zCaSetting;
          125  +          break;
          126  +        }
          127  +        case 2: { /* file */
          128  +          zCaFile = zCaSetting;
          129  +          break;
          130  +        }
          131  +      }
          132  +      if( SSL_CTX_load_verify_locations(sslCtx, zCaFile, zCaDirectory)==0 ){
          133  +        fossil_fatal("Failed to use CA root certificates from "
          134  +          "ssl-ca-location '%s'", zCaSetting);
          135  +      }
          136  +    }
          137  +    
          138  +    /* Load client SSL identity, preferring the filename specified on the command line */
          139  +    const char *identityFile = ( g.zSSLIdentity!= 0) ? g.zSSLIdentity : db_get("ssl-identity", 0);
          140  +    if( identityFile!=0 && identityFile[0]!='\0' ){
          141  +      if( SSL_CTX_use_certificate_file(sslCtx, identityFile, SSL_FILETYPE_PEM)!= 1
          142  +          || SSL_CTX_use_PrivateKey_file(sslCtx, identityFile, SSL_FILETYPE_PEM)!=1 ){
          143  +        fossil_fatal("Could not load SSL identity from %s", identityFile);
          144  +      }
          145  +    }
          146  +    /* Register a callback to tell the user what to do when the server asks for a cert */
          147  +    SSL_CTX_set_client_cert_cb(sslCtx, ssl_client_cert_callback);
          148  +
    96    149       sslIsInit = 1;
    97    150     }
    98    151   }
    99    152   
   100    153   /*
   101    154   ** Call this routine to shutdown the SSL module prior to program exit.
   102    155   */
................................................................................
   202    255       BIO_get_mem_data(mem, &desc);
   203    256       
   204    257       if( hasSavedCertificate ){
   205    258         warning = "WARNING: Certificate doesn't match the "
   206    259                   "saved certificate for this host!";
   207    260       }
   208    261       prompt = mprintf("\nUnknown SSL certificate:\n\n%s\n\n%s\n"
          262  +                     "Either:\n"
          263  +                     " * verify the certificate is correct using the "
          264  +                     "SHA1 fingerprint above\n"
          265  +                     " * use the global ssl-ca-location setting to specify your CA root\n"
          266  +                     "   certificates list\n\n"
          267  +                     "If you are not expecting this message, answer no and "
          268  +                     "contact your server\nadministrator.\n\n"
   209    269                        "Accept certificate [a=always/y/N]? ", desc, warning);
   210    270       BIO_free(mem);
   211    271   
   212    272       prompt_user(prompt, &ans);
   213    273       free(prompt);
   214    274       if( blob_str(&ans)[0]!='y' && blob_str(&ans)[0]!='a' ) {
   215    275         X509_free(cert);

Changes to src/main.c.

   103    103     char *urlPasswd;        /* Password for http: */
   104    104     char *urlCanonical;     /* Canonical representation of the URL */
   105    105     char *urlProxyAuth;     /* Proxy-Authorizer: string */
   106    106     char *urlFossil;        /* The path of the ?fossil=path suffix on ssh: */
   107    107     int dontKeepUrl;        /* Do not persist the URL */
   108    108   
   109    109     const char *zLogin;     /* Login name.  "" if not logged in. */
          110  +  const char *zSSLIdentity;  /* Value of --ssl-identity option, filename of SSL client identity */
   110    111     int useLocalauth;       /* No login required if from 127.0.0.1 */
   111    112     int noPswd;             /* Logged in without password (on 127.0.0.1) */
   112    113     int userUid;            /* Integer user id */
   113    114   
   114    115     /* Information used to populate the RCVFROM table */
   115    116     int rcvid;              /* The rcvid.  0 if not yet defined. */
   116    117     char *zIpAddr;          /* The remote IP address */
................................................................................
   249    250       g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
   250    251       g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
   251    252       g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
   252    253       if( g.fSqlTrace ) g.fSqlStats = 1;
   253    254       g.fSqlPrint = find_option("sqlprint", 0, 0)!=0;
   254    255       g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
   255    256       g.zLogin = find_option("user", "U", 1);
          257  +    g.zSSLIdentity = find_option("ssl-identity", 0, 1);
   256    258       if( find_option("help",0,0)!=0 ){
   257    259         /* --help anywhere on the command line is translated into
   258    260         ** "fossil help argv[1] argv[2]..." */
   259    261         int i;
   260    262         char **zNewArgv = fossil_malloc( sizeof(char*)*(g.argc+2) );
   261    263         for(i=1; i<g.argc; i++) zNewArgv[i+1] = argv[i];
   262    264         zNewArgv[i+1] = 0;

Changes to src/setup.c.

  1060   1060     @ <table border="0"><tr><td valign="top">
  1061   1061     login_insert_csrf_secret();
  1062   1062     for(pSet=ctrlSettings; pSet->name!=0; pSet++){
  1063   1063       if( pSet->width==0 ){
  1064   1064         onoff_attribute(pSet->name, pSet->name,
  1065   1065                         pSet->var!=0 ? pSet->var : pSet->name,
  1066   1066                         is_truth(pSet->def));
  1067         -      @ <br />
         1067  +      if( pSet->versionable ){
         1068  +        @  (v)<br />
         1069  +      } else {
         1070  +        @ <br />
         1071  +      }
  1068   1072       }
  1069   1073     }
  1070   1074     @ </td><td style="width: 30;"></td><td valign="top">
  1071   1075     for(pSet=ctrlSettings; pSet->name!=0; pSet++){
  1072   1076       if( pSet->width!=0 ){
  1073   1077         entry_attribute(pSet->name, /*pSet->width*/ 40, pSet->name,
  1074   1078                         pSet->var!=0 ? pSet->var : pSet->name,
  1075   1079                         (char*)pSet->def);
  1076         -      @ <br />
         1080  +      if( pSet->versionable ){
         1081  +        @  (v)<br />
         1082  +      } else {
         1083  +        @ <br />
         1084  +      }
  1077   1085       }
  1078   1086     }
  1079   1087     @ </td></tr></table>
  1080   1088     @ <p><input type="submit"  name="submit" value="Apply Changes" /></p>
  1081   1089     @ </div></form>
         1090  +  @ <p>Settings marked with (v) are 'versionable' and will be overridden by the contents of files named <tt>.fossil-settings/PROPERTY</tt>.</p>
  1082   1091     @ <hr /><p>
  1083   1092     @ These settings work in the same way, as the <kbd>set</kbd> commandline:<br />
  1084   1093     @ </p><pre>%s(zHelp_setting_cmd)</pre>
  1085   1094     db_end_transaction(0);
  1086   1095     style_footer();
  1087   1096   }
  1088   1097   

Changes to src/update.c.

   113    113     if( vid==0 ){
   114    114       fossil_fatal("cannot find current version");
   115    115     }
   116    116     if( !nochangeFlag && db_exists("SELECT 1 FROM vmerge") ){
   117    117       fossil_fatal("cannot update an uncommitted merge");
   118    118     }
   119    119     if( !nochangeFlag && !internalUpdate ) autosync(AUTOSYNC_PULL);
          120  +  
          121  +  /* Create any empty directories now, as well as after the update, so changes in settings are reflected now */
          122  +  ensure_empty_dirs_created();
   120    123   
   121    124     if( internalUpdate ){
   122    125       tid = internalUpdate;
   123    126     }else if( g.argc>=3 ){
   124    127       if( fossil_strcmp(g.argv[2], "current")==0 ){
   125    128         /* If VERSION is "current", then use the same algorithm to find the
   126    129         ** target as if VERSION were omitted. */
................................................................................
   439    442     
   440    443     /*
   441    444     ** Clean up the mid and pid VFILE entries.  Then commit the changes.
   442    445     */
   443    446     if( nochangeFlag ){
   444    447       db_end_transaction(1);  /* With --nochange, rollback changes */
   445    448     }else{
          449  +    ensure_empty_dirs_created();
   446    450       if( g.argc<=3 ){
   447    451         /* All files updated.  Shift the current checkout to the target. */
   448    452         db_multi_exec("DELETE FROM vfile WHERE vid!=%d", tid);
   449    453         checkout_set_all_exe(tid);
   450    454         manifest_to_disk(tid);
   451    455         db_lset_int("checkout", tid);
   452    456       }else{
................................................................................
   454    458         ** checkout unchanged. */
   455    459         db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid);
   456    460       }
   457    461       if( !internalUpdate ) undo_finish();
   458    462       db_end_transaction(0);
   459    463     }
   460    464   }
          465  +
          466  +/*
          467  +** Make sure empty directories are created
          468  +*/
          469  +void ensure_empty_dirs_created(void){
          470  +  /* Make empty directories? */
          471  +  char *zEmptyDirs = db_get("empty-dirs", 0);
          472  +  if( zEmptyDirs!=0 ){
          473  +    char *bc;
          474  +    Blob dirName;
          475  +    Blob dirsList;
          476  +
          477  +    blob_zero(&dirsList);
          478  +    blob_init(&dirsList, zEmptyDirs, strlen(zEmptyDirs));
          479  +    /* Replace commas by spaces */
          480  +    bc = blob_str(&dirsList);
          481  +    while( (*bc)!='\0' ){
          482  +      if( (*bc)==',' ) { *bc = ' '; }
          483  +      ++bc;
          484  +    }
          485  +    /* Make directories */
          486  +    blob_zero(&dirName);
          487  +    while( blob_token(&dirsList, &dirName) ){
          488  +      const char *zDir = blob_str(&dirName);
          489  +      /* Make full pathname of the directory */
          490  +      Blob path;
          491  +      const char *zPath;
          492  +
          493  +      blob_zero(&path);
          494  +      blob_appendf(&path, "%s/%s", g.zLocalRoot, zDir);
          495  +      zPath = blob_str(&path);      
          496  +      /* Handle various cases of existence of the directory */
          497  +      switch( file_isdir(zPath) ){
          498  +        case 0: { /* doesn't exist */
          499  +          if( file_mkdir(zPath, 0)!=0 ) {
          500  +            fossil_warning("couldn't create directory %s as "
          501  +                           "required by empty-dirs setting", zDir);
          502  +          }          
          503  +          break;
          504  +        }
          505  +        case 1: { /* exists, and is a directory */
          506  +          /* do nothing - required directory exists already */
          507  +          break;
          508  +        }
          509  +        case 2: { /* exists, but isn't a directory */
          510  +          fossil_warning("file %s found, but a directory is required "
          511  +                         "by empty-dirs setting", zDir);          
          512  +        }
          513  +      }
          514  +      blob_reset(&path);
          515  +    }
          516  +  }
          517  +}
   461    518   
   462    519   
   463    520   /*
   464    521   ** Get the contents of a file within the checking "revision".  If
   465    522   ** revision==NULL then get the file content for the current checkout.
   466    523   */
   467    524   int historical_version_of_file(

Changes to www/changes.wiki.

     1      1   <title>Change Log</title>
     2      2   
     3      3   <h2>Changes For Version 1.19 (pending)</h2>
     4      4   
     5      5     *  Added a ./configure script based on autosetup.
     6      6     *  Added the "[/help/winsrv | fossil winsrv]" command
     7      7        for creating a Fossil service on windows systems.
            8  +  *  Added "versionable settings" where settings that affect
            9  +     the local tree can be stored in versioned files in the
           10  +     .fossil-settings directory.
           11  +  *  The status, changes and extras commands now show
           12  +     pathnames relative to the current working directory,
           13  +     unless overridden by command line options or the
           14  +     "relative-paths" setting.<br><b>WARNING:</b> This
           15  +     change will break scripts which rely on the current
           16  +     output when the current working directory is not the
           17  +     repository root.
           18  +  *  Added "empty-dirs" versionable setting.
           19  +  *  Added support for client-side SSL certificates with "ssl-identity"
           20  +     setting and --ssl-identity option.
           21  +  *  Added "ssl-ca-location" setting to specify trusted root
           22  +     SSL certificates.
     8     23   
     9     24   <h2>Changes For Version 1.18 (2011-07-14)</h2>
    10     25   
    11     26     *  Added this Change Log
    12     27     *  Added sequential version numbering
    13     28     *  Added a optional configure script - the Makefile still works for most
    14     29        systems.

Changes to www/index.wiki.

   125    125     *  A tutorial on [./branching.wiki | branching], what it means and how
   126    126        to do it using fossil.
   127    127     *  The [./selfcheck.wiki | automatic self-check] mechanism
   128    128        helps insure project integrity.
   129    129     *  Fossil contains a [./wikitheory.wiki | built-in wiki].
   130    130     *  An [./event.wiki | Event] is a special kind of wiki page associated
   131    131        with a point in time rather than a name.
          132  +  *  [./settings.wiki | Settings] control the behaviour of fossil.
          133  +  *  [./ssl.wiki | Use SSL] to encrypt communication with the server.
   132    134     *  There is a
   133    135       [http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users | mailing list] (with publicly readable
   134    136        [http://www.mail-archive.com/fossil-users@lists.fossil-scm.org | archives]
   135    137        available for discussing fossil issues.
   136    138     *  [./stats.wiki | Performance statistics] taken from real-world projects
   137    139        hosted on fossil.
   138    140     *  How to [./shunning.wiki | delete content] from a fossil repository.

Changes to www/mkindex.tcl.

     7      7   #
     8      8   
     9      9   set doclist {
    10     10     bugtheory.wiki {Bug Tracking In Fossil}
    11     11     branching.wiki {Branching, Forking, Merging, and Tagging}
    12     12     build.wiki {Building and Installing Fossil}
    13     13     checkin_names.wiki {Checkin And Version Names}
           14  +  changes.wiki {Fossil Changelog}
    14     15     copyright-release.html {Contributor License Agreement}
    15     16     concepts.wiki {Fossil Core Concepts}
    16     17     contribute.wiki {Contributing Code or Documentation To The Fossil Project}
    17     18     custom_ticket.wiki {Customizing The Ticket System}
    18     19     delta_encoder_algorithm.wiki {Fossil Delta Encoding Algorithm}
    19     20     delta_format.wiki {Fossil Delta Format}
    20     21     embeddeddoc.wiki {Embedded Project Documentation}
................................................................................
    33     34     quickstart.wiki {Fossil Quick Start Guide}
    34     35     quotes.wiki
    35     36         {Quotes: What People Are Saying About Fossil, Git, and DVCSes in General}
    36     37     ../test/release-checklist.wiki {Pre-Release Testing Checklist}
    37     38     selfcheck.wiki {Fossil Repository Integrity Self Checks}
    38     39     selfhost.wiki {Fossil Self Hosting Repositories}
    39     40     server.wiki {How To Configure A Fossil Server}
           41  +  settings.wiki {Fossil Settings}
    40     42     shunning.wiki {Shunning: Deleting Content From Fossil}
    41     43     stats.wiki {Performance Statistics}
    42     44     style.wiki {Source Code Style Guidelines}
           45  +  ssl.wiki {Using SSL with Fossil}
    43     46     sync.wiki {The Fossil Sync Protocol}
    44     47     tech_overview.wiki {A Technical Overview Of The Design And Implementation
    45     48                         Of Fossil}
    46     49     tech_overview.wiki {SQLite Databases Used By Fossil}
    47     50     theory1.wiki {Thoughts On The Design Of The Fossil DVCS}
    48     51     webui.wiki {The Fossil Web Interface}
    49     52     wikitheory.wiki {Wiki In Fossil}

Changes to www/permutedindex.wiki.

     9      9   <li><a href="faq.wiki">Asked Questions &#151; Frequently</a></li>
    10     10   <li><a href="password.wiki">Authentication &#151; Password Management And</a></li>
    11     11   <li><a href="private.wiki">Branches &#151; Creating, Syncing, and Deleting Private</a></li>
    12     12   <li><a href="branching.wiki">Branching, Forking, Merging, and Tagging</a></li>
    13     13   <li><a href="bugtheory.wiki">Bug Tracking In Fossil</a></li>
    14     14   <li><a href="makefile.wiki">Build Process &#151; The Fossil</a></li>
    15     15   <li><a href="build.wiki">Building and Installing Fossil</a></li>
           16  +<li><a href="changes.wiki">Changelog &#151; Fossil</a></li>
    16     17   <li><a href="checkin_names.wiki">Checkin And Version Names</a></li>
    17     18   <li><a href="../test/release-checklist.wiki">Checklist &#151; Pre-Release Testing</a></li>
    18     19   <li><a href="foss-cklist.wiki">Checklist For Successful Open-Source Projects</a></li>
    19     20   <li><a href="selfcheck.wiki">Checks &#151; Fossil Repository Integrity Self</a></li>
    20     21   <li><a href="contribute.wiki">Code or Documentation To The Fossil Project &#151; Contributing</a></li>
    21     22   <li><a href="style.wiki">Code Style Guidelines &#151; Source</a></li>
    22     23   <li><a href="concepts.wiki">Concepts &#151; Fossil Core</a></li>
................................................................................
    42     43   <li><a href="embeddeddoc.wiki">Embedded Project Documentation</a></li>
    43     44   <li><a href="delta_encoder_algorithm.wiki">Encoding Algorithm &#151; Fossil Delta</a></li>
    44     45   <li><a href="inout.wiki">Export To And From Git &#151; Import And</a></li>
    45     46   <li><a href="fileformat.wiki">File Format &#151; Fossil</a></li>
    46     47   <li><a href="branching.wiki">Forking, Merging, and Tagging &#151; Branching,</a></li>
    47     48   <li><a href="delta_format.wiki">Format &#151; Fossil Delta</a></li>
    48     49   <li><a href="fileformat.wiki">Format &#151; Fossil File</a></li>
           50  +<li><a href="changes.wiki">Fossil Changelog</a></li>
    49     51   <li><a href="concepts.wiki">Fossil Core Concepts</a></li>
    50     52   <li><a href="delta_encoder_algorithm.wiki">Fossil Delta Encoding Algorithm</a></li>
    51     53   <li><a href="delta_format.wiki">Fossil Delta Format</a></li>
    52     54   <li><a href="fileformat.wiki">Fossil File Format</a></li>
    53     55   <li><a href="quickstart.wiki">Fossil Quick Start Guide</a></li>
    54     56   <li><a href="selfcheck.wiki">Fossil Repository Integrity Self Checks</a></li>
    55     57   <li><a href="selfhost.wiki">Fossil Self Hosting Repositories</a></li>
           58  +<li><a href="settings.wiki">Fossil Settings</a></li>
    56     59   <li><a href="fossil-v-git.wiki">Fossil Versus Git</a></li>
    57     60   <li><a href="quotes.wiki">Fossil, Git, and DVCSes in General &#151; Quotes: What People Are Saying About</a></li>
    58     61   <li><a href="faq.wiki">Frequently Asked Questions</a></li>
    59     62   <li><a href="shunning.wiki">From Fossil &#151; Shunning: Deleting Content</a></li>
    60     63   <li><a href="inout.wiki">From Git &#151; Import And Export To And</a></li>
    61     64   <li><a href="quotes.wiki">General &#151; Quotes: What People Are Saying About Fossil, Git, and DVCSes in</a></li>
    62     65   <li><a href="fossil-v-git.wiki">Git &#151; Fossil Versus</a></li>
................................................................................
    97    100   <li><a href="quotes.wiki">Quotes: What People Are Saying About Fossil, Git, and DVCSes in General</a></li>
    98    101   <li><a href="selfhost.wiki">Repositories &#151; Fossil Self Hosting</a></li>
    99    102   <li><a href="selfcheck.wiki">Repository Integrity Self Checks &#151; Fossil</a></li>
   100    103   <li><a href="quotes.wiki">Saying About Fossil, Git, and DVCSes in General &#151; Quotes: What People Are</a></li>
   101    104   <li><a href="selfcheck.wiki">Self Checks &#151; Fossil Repository Integrity</a></li>
   102    105   <li><a href="selfhost.wiki">Self Hosting Repositories &#151; Fossil</a></li>
   103    106   <li><a href="server.wiki">Server &#151; How To Configure A Fossil</a></li>
          107  +<li><a href="settings.wiki">Settings &#151; Fossil</a></li>
   104    108   <li><a href="shunning.wiki">Shunning: Deleting Content From Fossil</a></li>
   105    109   <li><a href="style.wiki">Source Code Style Guidelines</a></li>
   106    110   <li><a href="tech_overview.wiki">SQLite Databases Used By Fossil</a></li>
          111  +<li><a href="ssl.wiki">SSL with Fossil &#151; Using</a></li>
   107    112   <li><a href="quickstart.wiki">Start Guide &#151; Fossil Quick</a></li>
   108    113   <li><a href="stats.wiki">Statistics &#151; Performance</a></li>
   109    114   <li><a href="style.wiki">Style Guidelines &#151; Source Code</a></li>
   110    115   <li><a href="foss-cklist.wiki">Successful Open-Source Projects &#151; Checklist For</a></li>
   111    116   <li><a href="sync.wiki">Sync Protocol &#151; The Fossil</a></li>
   112    117   <li><a href="private.wiki">Syncing, and Deleting Private Branches &#151; Creating,</a></li>
   113    118   <li><a href="custom_ticket.wiki">System &#151; Customizing The Ticket</a></li>
................................................................................
   116    121   <li><a href="../test/release-checklist.wiki">Testing Checklist &#151; Pre-Release</a></li>
   117    122   <li><a href="makefile.wiki">The Fossil Build Process</a></li>
   118    123   <li><a href="sync.wiki">The Fossil Sync Protocol</a></li>
   119    124   <li><a href="webui.wiki">The Fossil Web Interface</a></li>
   120    125   <li><a href="theory1.wiki">Thoughts On The Design Of The Fossil DVCS</a></li>
   121    126   <li><a href="custom_ticket.wiki">Ticket System &#151; Customizing The</a></li>
   122    127   <li><a href="bugtheory.wiki">Tracking In Fossil &#151; Bug</a></li>
          128  +<li><a href="ssl.wiki">Using SSL with Fossil</a></li>
   123    129   <li><a href="checkin_names.wiki">Version Names &#151; Checkin And</a></li>
   124    130   <li><a href="fossil-v-git.wiki">Versus Git &#151; Fossil</a></li>
   125    131   <li><a href="webui.wiki">Web Interface &#151; The Fossil</a></li>
   126    132   <li><a href="quotes.wiki">What People Are Saying About Fossil, Git, and DVCSes in General &#151; Quotes:</a></li>
   127    133   <li><a href="wikitheory.wiki">Wiki In Fossil</a></li>
          134  +<li><a href="ssl.wiki">with Fossil &#151; Using SSL</a></li>
   128    135   </ul>

Changes to www/server.wiki.

    95     95   </p>
    96     96   <p>
    97     97   If you are using "inetd" to serve your repository, then you simply need to add "/usr/bin/stunnel" (perhaps on a different path, depending on your setup) before the command line to launch Fossil.
    98     98   </p>
    99     99   <p>
   100    100   At this stage, the standalone server (e.g. "fossil server") does not support SSL.
   101    101   </p>
          102  +<p>
          103  +For more information, see <a href="./ssl.wiki">Using SSL with Fossil</a>.
          104  +</p>
   102    105   </blockquote>
   103    106   
   104    107   <h2>Various security concerns with hosted repositories</h2><blockquote>
   105    108   <p>
   106    109   There are two main concerns relating to usage of Fossil for sharing sensitive information (source or any other data):
   107    110   <ul>
   108    111   <li>Interception of the Fossil synchronization stream, thereby capturing data, and

Added www/settings.wiki.

            1  +<title>Fossil Settings</title>
            2  +
            3  +<h2>Using Fossil Settings</h2>
            4  +
            5  +Settings control the behaviour of fossil. They are set with the <tt>fossil settings</tt> command, or through the web interface in the Settings page in the Admin section.
            6  +
            7  +For a list of all settings, view the Settings page, or type <tt>fossil help settings</tt> from the command line.
            8  +
            9  +
           10  +<h3>Repository settings</h3>
           11  +
           12  +Settings are set on a per-repository basis. When you clone a repository, a subset of settings are copied to your local repository.
           13  +
           14  +If you make a change to a setting on your local repository, it is not synced back to the server when you <tt>push</tt> or <tt>sync</tt>. If you make a change on the server, you need to manually make the change on all repositories which are cloned from this repository.
           15  +
           16  +You can also set a setting globally on your local machine. The value will be used for all repositories cloned to your machine, unless overridden explicitly in a particular repository. Global settings can be set by using the <tt>-global</tt> option on the <tt>fossil settings</tt> command.
           17  +
           18  +
           19  +<h3>"Versionable" settings</h3>
           20  +
           21  +Most of the settings control the behaviour of fossil on your local machine, largely acting to reflect your preference on how you want to use Fossil, how you communicate with the server, or options for hosting a repository on the web. 
           22  +
           23  +However, for historical reasons, some settings affect how you work with versioned files. These are <tt>binary-glob</tt>, <tt>crnl-glob</tt>, <tt>ignore-glob</tt>, <tt>empty-dirs</tt> and <tt>manifest</tt>. The most important is <tt>ignore-glob</tt> which specifies which files should be ignored when looking for unmanaged files with the <tt>extras</tt> command.
           24  +
           25  +Because these options can change over time, and the inconvenience of replicating changes, these settings are "versionable". As well as being able to be set using the <tt>settings</tt> command or the web interface, you can created versioned files in the <tt>.fossil-settings</tt> directory named with the setting name. The contents of the file is the value of the setting, and these files are checked in, committed, merged, and so on, as with any other file.
           26  +
           27  +Where a setting is a list of values, such as <tt>ignore-glob</tt>, you can also a newline as a separator as well as a comma.
           28  +
           29  +For example, to set the list of ignored files, create a <tt>.fossil-settings/ignore-glob</tt> file where each line contains a glob for ignored files.
           30  +
           31  +If you set the value of a setting using the <tt>settings</tt> command as well as a versioned file, the versioned setting will take precedence. A warning will be displayed.

Added www/ssl.wiki.

            1  +<title>SSL and Fossil</title>
            2  +
            3  +<h2>Using SSL with Fossil</h2>
            4  +
            5  +If you are storing sensitive information in your repository, you should use SSL to encrypt all communications. This will protect the credentials used to access the server, as well preventing eavesdropping of the contents of your repository.
            6  +
            7  +To host a repository with SSL, you need to use an web server which supports SSL in front of the Fossil server. You can host it using the CGI option or by proxying Fossil's built in HTTP server.
            8  +
            9  +Your fossil client must be built with SSL support. The <tt>configure</tt> script will attempt to find OpenSSL on your system, but if necessary, you can specify the location with the <tt>--with-openssl</tt> option. Type <tt>./configure --help</tt> for details.
           10  +
           11  +Make sure the URL you clone from uses the <tt>https:</tt> scheme to ensure you're using SSL. If your server is configured to serve the repository from http as well as https, it's easy to accidentally use unencrypted HTTP if you forget the all important 's'.
           12  +
           13  +
           14  +<h2>Certificates</h2>
           15  +
           16  +To verify the identify of a server, SSL uses certificates. Fossil needs to know which certificates you trust.
           17  +
           18  +If you are using a self-signed certificate, you'll be asked if you want to accept the certificate the first time you communicate with the server. Verify the certificate fingerprint is correct, then answer "always" to remember your decision.
           19  +
           20  +If you are using a certificate signed by a certificate authority, you need to specify the certificates you trust with the <tt>ssl-ca-location</tt> setting. Set this globally with the <tt>-global</tt> option for convenience.
           21  +
           22  +This should be set to the location of a file containing all the PEM encoded certificates you trust. You can obtain a certificate using a web browser, for example, Firefox, or just refer to your system's trusted CA roots which are usually stored somewhere in <tt>/etc</tt>.
           23  +
           24  +
           25  +<h2>Client side certificates</h2>
           26  +
           27  +You can also use client side certificates to add an extra layer of authentication, over and above Fossil's built in user management. If you are particularly paranoid, you'll want to use this to remove the ability of anyone on the internet from making any request to Fossil. Without presenting a valid client side certificate, the web server won't invoke the fossil CGI handler.
           28  +
           29  +Configure your server to request a client side certificate, and set up a certificate authority to sign your client certificates. For each person who needs to access the repository, create a private key and certificate signed with that CA.
           30  +
           31  +The PEM encoded private key and certificate should be stored in a single file, simply by concatenating the key and certificate files. Specify the location of this file with the <tt>ssl-identity</tt> setting, or the <tt>--ssl-identity</tt> option to the <tt>clone</tt> command.
           32  +
           33  +If you've password protected the private key, the password will be requested every time you connect to the server. This password is not stored by fossil, as doing so would defeat the purpose of having a password.
           34  +
           35  +If you attempt to connect to a server which requests a client certificate, but don't provide one, fossil will show an error message which explains what to do to authenticate with the server.
           36  +