Check-in [9b30224db7]
Not logged in
Overview

SHA1 Hash:9b30224db761b02ca4d7243fbadcc4e297ffc604
Date: 2007-08-25 04:02:27
User: aku
Comment:Merging formatting changes to timeline and concepts documentation
Timelines: ancestors | descendants | both | trunk
Other Links: files | ZIP archive | manifest

Tags And Properties
Changes
[hide diffs]

Added art/concept1.dia version [da39a3ee5e]


Added art/concept2.dia version [da39a3ee5e]


Modified src/main.c from [057090c5e8] to [da39a3ee5e].

@@ -1,639 +1,1 @@
-/*
-** Copyright (c) 2006 D. Richard Hipp
-**
-** This program is free software; you can redistribute it and/or
-** modify it under the terms of the GNU General Public
-** License version 2 as published by the Free Software Foundation.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-** General Public License for more details.
-**
-** You should have received a copy of the GNU General Public
-** License along with this library; if not, write to the
-** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-** Boston, MA  02111-1307, USA.
-**
-** Author contact information:
-**   drh@hwaci.com
-**   http://www.hwaci.com/drh/
-**
-*******************************************************************************
-**
-** This module codes the main() procedure that runs first when the
-** program is invoked.
-*/
-#include "config.h"
-#include "main.h"
-#include <string.h>
-#include <time.h>
-
-#if INTERFACE
-
-/*
-** Number of elements in an array
-*/
-#define count(X)  (sizeof(X)/sizeof(X[0]))
-
-/*
-** Size of a UUID in characters
-*/
-#define UUID_SIZE 40
-
-/*
-** All global variables are in this structure.
-*/
-struct Global {
-  int argc; char **argv;  /* Command-line arguments to the program */
-  int isConst;            /* True if the output is unchanging */
-  sqlite3 *db;            /* The connection to the databases */
-  int configOpen;         /* True if the config database is open */
-  long long int now;      /* Seconds since 1970 */
-  int repositoryOpen;     /* True if the main repository database is open */
-  char *zRepositoryName;  /* Name of the repository database */
-  int localOpen;          /* True if the local database is open */
-  char *zLocalRoot;       /* The directory holding the  local database */
-  int minPrefix;          /* Number of digits needed for a distinct UUID */
-  int fSqlTrace;          /* True if -sqltrace flag is present */
-  int fSqlPrint;          /* True if -sqlprint flag is present */
-  int fHttpTrace;         /* Trace outbound HTTP requests */
-  char *zPath;            /* Name of webpage being served */
-  char *zExtra;           /* Extra path information past the webpage name */
-  char *zBaseURL;         /* Full text of the URL being served */
-  const char *zContentType;  /* The content type of the input HTTP request */
-  int iErrPriority;       /* Priority of current error message */
-  char *zErrMsg;          /* Text of an error message */
-  Blob cgiIn;             /* Input to an xfer www method */
-  int cgiPanic;           /* Write error messages to CGI */
-
-  int *aCommitFile;
-
-  int urlIsFile;          /* True if a "file:" url */
-  char *urlName;          /* Hostname for http: or filename for file: */
-  int urlPort;            /* TCP port number for http: */
-  char *urlPath;          /* Pathname for http: */
-  char *urlUser;          /* User id for http: */
-  char *urlPasswd;        /* Password for http: */
-  char *urlCanonical;     /* Canonical representation of the URL */
-
-  const char *zLogin;     /* Login name.  "" if not logged in. */
-  int noPswd;             /* Logged in without password (on 127.0.0.1) */
-  int userUid;            /* Integer user id */
-
-  /* Information used to populate the RCVFROM table */
-  int rcvid;              /* The rcvid.  0 if not yet defined. */
-  char *zIpAddr;          /* The remote IP address */
-  char *zNonce;           /* The nonce used for login */
-
-  /* permissions used by the server */
-  int okSetup;            /* s: use Setup screens on web interface */
-  int okAdmin;            /* a: administrative permission */
-  int okDelete;           /* d: delete wiki or tickets */
-  int okPassword;         /* p: change password */
-  int okQuery;            /* q: create new reports */
-  int okWrite;            /* i: xfer inbound. checkin */
-  int okRead;             /* o: xfer outbound. checkout */
-  int okHistory;          /* h: access historical information. */
-  int okClone;            /* g: clone */
-  int okRdWiki;           /* j: view wiki via web */
-  int okNewWiki;          /* f: create new wiki via web */
-  int okApndWiki;         /* m: append to wiki via web */
-  int okWrWiki;           /* k: edit wiki via web */
-  int okRdTkt;            /* r: view tickets via web */
-  int okNewTkt;           /* n: create new tickets */
-  int okApndTkt;          /* c: append to tickets via the web */
-  int okWrTkt;            /* w: make changes to tickets via web */
-
-  FILE *fDebug;           /* Write debug information here, if the file exists */
-};
-
-/*
-** Macro for debugging:
-*/
-#define CGIDEBUG(X)  if( g.fDebug ) cgi_debug X
-
-#endif
-
-Global g;
-
-/*
-** The table of web pages supported by this application is generated
-** automatically by the "mkindex" program and written into a file
-** named "page_index.h".  We include that file here to get access
-** to the table.
-*/
-#include "page_index.h"
-
-/*
-** Search for a function whose name matches zName.  Write a pointer to
-** that function into *pxFunc and return 0.  If no match is found,
-** return 1.  If the command is ambiguous return 2;
-**
-** The NameMap structure and the tables we are searching against are
-** defined in the page_index.h header file which is automatically
-** generated by mkindex.c program.
-*/
-static int name_search(
-  const char *zName,       /* The name we are looking for */
-  const NameMap *aMap,     /* Search in this array */
-  int nMap,                /* Number of slots in aMap[] */
-  int *pIndex              /* OUT: The index in aMap[] of the match */
-){
-  int upr, lwr, cnt, m, i;
-  int n = strlen(zName);
-  lwr = 0;
-  upr = nMap-1;
-  while( lwr<=upr ){
-    int mid, c;
-    mid = (upr+lwr)/2;
-    c = strcmp(zName, aMap[mid].zName);
-    if( c==0 ){
-      *pIndex = mid;
-      return 0;
-    }else if( c<0 ){
-      upr = mid - 1;
-    }else{
-      lwr = mid + 1;
-    }
-  }
-  for(m=cnt=0, i=upr-2; i<=upr+3 && i<nMap; i++){
-    if( i<0 ) continue;
-    if( strncmp(zName, aMap[i].zName, n)==0 ){
-      m = i;
-      cnt++;
-    }
-  }
-  if( cnt==1 ){
-    *pIndex = m;
-    return 0;
-  }
-  return 1+(cnt>1);
-}
-
-
-/*
-** This procedure runs first.
-*/
-int main(int argc, char **argv){
-  const char *zCmdName;
-  int idx;
-  int rc;
-
-  g.now = time(0);
-  g.argc = argc;
-  g.argv = argv;
-  if( getenv("GATEWAY_INTERFACE")!=0 ){
-    zCmdName = "cgi";
-  }else if( argc<2 ){
-    fprintf(stderr, "Usage: %s COMMAND ...\n", argv[0]);
-    exit(1);
-  }else{
-    g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
-    g.fSqlPrint = find_option("sqlprint", 0, 0)!=0;
-    g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
-    g.zLogin = find_option("user", "U", 1);
-    zCmdName = argv[1];
-  }
-  rc = name_search(zCmdName, aCommand, count(aCommand), &idx);
-  if( rc==1 ){
-    fprintf(stderr,"%s: unknown command: %s\n"
-                   "%s: use \"commands\" or \"test-commands\" for help\n",
-                   argv[0], zCmdName, argv[0]);
-    return 1;
-  }else if( rc==2 ){
-    fprintf(stderr,"%s: ambiguous command prefix: %s\n"
-                   "%s: use \"commands\" or \"test-commands\" for help\n",
-                   argv[0], zCmdName, argv[0]);
-    return 1;
-  }
-  aCommand[idx].xFunc();
-  return 0;
-}
-
-/*
-** Print an error message, rollback all databases, and quit.
-*/
-void fossil_panic(const char *zFormat, ...){
-  char *z;
-  va_list ap;
-  va_start(ap, zFormat);
-  z = vmprintf(zFormat, ap);
-  va_end(ap);
-  if( g.cgiPanic ){
-    g.cgiPanic = 0;
-    cgi_printf("<p><font color=\"red\">%h</font></p>", z);
-    style_footer();
-    cgi_reply();
-  }else{
-    fprintf(stderr, "%s: %s\n", g.argv[0], z);
-  }
-  db_force_rollback();
-  exit(1);
-}
-void fossil_fatal(const char *zFormat, ...){
-  char *z;
-  va_list ap;
-  va_start(ap, zFormat);
-  z = vmprintf(zFormat, ap);
-  va_end(ap);
-  if( g.cgiPanic ){
-    g.cgiPanic = 0;
-    cgi_printf("<p><font color=\"red\">%h</font></p>", z);
-    style_footer();
-    cgi_reply();
-  }else{
-    fprintf(stderr, "%s: %s\n", g.argv[0], z);
-  }
-  db_force_rollback();
-  exit(1);
-}
-
-/*
-** Print a usage comment and quit
-*/
-void usage(const char *zFormat){
-  fprintf(stderr, "Usage: %s %s %s\n", g.argv[0], g.argv[1], zFormat);
-  exit(1);
-}
-
-/*
-** Remove n elements from g.argv beginning with the i-th element.
-*/
-static void remove_from_argv(int i, int n){
-  int j;
-  for(j=i+n; j<g.argc; i++, j++){
-    g.argv[i] = g.argv[j];
-  }
-  g.argc = i;
-}
-
-
-/*
-** Look for a command-line option.  If present, return a pointer.
-** Return NULL if missing.
-**
-** hasArg==0 means the option is a flag.  It is either present or not.
-** hasArg==1 means the option has an argument.  Return a pointer to the
-** argument.
-*/
-const char *find_option(const char *zLong, const char *zShort, int hasArg){
-  int i;
-  const char *zReturn = 0;
-  assert( hasArg==0 || hasArg==1 );
-  for(i=2; i<g.argc; i++){
-    char *z = g.argv[i];
-    if( z[0]!='-' ) continue;
-    z++;
-    if( z[0]=='-' ){
-      if( z[1]==0 ){
-        remove_from_argv(i, 1);
-        break;
-      }
-      z++;
-    }
-    if( strcmp(z,zLong)==0 || (zShort!=0 && strcmp(z,zShort)==0) ){
-      zReturn = g.argv[i+hasArg];
-      remove_from_argv(i, 1+hasArg);
-      break;
-    }
-  }
-  return zReturn;
-}
-
-/*
-** Verify that there are no processed command-line options.  If
-** Any remaining command-line argument begins with "-" print
-** an error message and quit.
-*/
-void verify_all_options(void){
-  int i;
-  for(i=1; i<g.argc; i++){
-    if( g.argv[i][0]=='-' ){
-      fossil_fatal("unrecognized command-line option: %s", g.argv[i]);
-    }
-  }
-}
-
-/*
-** Print a list of words in multiple columns.
-*/
-static void multi_column_list(const char **azWord, int nWord){
-  int i, j, len;
-  int mxLen = 0;
-  int nCol;
-  int nRow;
-  for(i=0; i<nWord; i++){
-    len = strlen(azWord[i]);
-    if( len>mxLen ) mxLen = len;
-  }
-  nCol = 80/(mxLen+2);
-  if( nCol==0 ) nCol = 1;
-  nRow = (nWord + nCol - 1)/nCol;
-  for(i=0; i<nRow; i++){
-    const char *zSpacer = "";
-    for(j=i; j<nWord; j+=nRow){
-      printf("%s%-*s", zSpacer, mxLen, azWord[j]);
-      zSpacer = "  ";
-    }
-    printf("\n");
-  }
-}
-
-/*
-** COMMAND: commands
-**
-** Usage: %fossil commands
-** List all supported commands.
-*/
-void cmd_cmd_list(void){
-  int i, nCmd;
-  const char *aCmd[count(aCommand)];
-  for(i=nCmd=0; i<count(aCommand); i++){
-    if( strncmp(aCommand[i].zName,"test",4)==0 ) continue;
-    /* if( strcmp(aCommand[i].zName, g.argv[1])==0 ) continue; */
-    aCmd[nCmd++] = aCommand[i].zName;
-  }
-  multi_column_list(aCmd, nCmd);
-}
-
-/*
-** COMMAND: test-commands
-**
-** Usage: %fossil test-commands
-** List all commands used for testing and debugging.
-*/
-void cmd_test_cmd_list(void){
-  int i, nCmd;
-  const char *aCmd[count(aCommand)];
-  for(i=nCmd=0; i<count(aCommand); i++){
-    if( strncmp(aCommand[i].zName,"test",4)!=0 ) continue;
-    /* if( strcmp(aCommand[i].zName, g.argv[1])==0 ) continue; */
-    aCmd[nCmd++] = aCommand[i].zName;
-  }
-  multi_column_list(aCmd, nCmd);
-}
-
-
-/*
-** COMMAND: help
-**
-** Usage: %fossil help COMMAND
-** Display information on how to use COMMAND
-*/
-void help_cmd(void){
-  int rc, idx;
-  const char *z;
-  if( g.argc!=3 ){
-    printf("Usage: %s help COMMAND.\nAvailable COMMANDs:\n", g.argv[0]);
-    cmd_cmd_list();
-    return;
-  }
-  rc = name_search(g.argv[2], aCommand, count(aCommand), &idx);
-  if( rc==1 ){
-    fossil_fatal("unknown command: %s", g.argv[2]);
-  }else if( rc==2 ){
-    fossil_fatal("ambiguous command prefix: %s", g.argv[2]);
-  }
-  z = aCmdHelp[idx];
-  if( z==0 ){
-    fossil_fatal("no help available for the %s command",
-       aCommand[idx].zName);
-  }
-  while( *z ){
-    if( *z=='%' && strncmp(z, "%fossil", 7)==0 ){
-      printf("%s", g.argv[0]);
-      z += 7;
-    }else{
-      putchar(*z);
-      z++;
-    }
-  }
-  putchar('\n');
-}
-
-/*
-** RSS feeds need to reference absolute URLs so we need to calculate
-** the base URL onto which we add components. This is basically
-** cgi_redirect() stripped down and always returning an absolute URL.
-*/
-static char *get_base_url(void){
-  int i;
-  const char *zHost = PD("HTTP_HOST","");
-  const char *zMode = PD("HTTPS","off");
-  const char *zCur = PD("REQUEST_URI","/");
-
-  for(i=0; zCur[i] && zCur[i]!='?' && zCur[i]!='#'; i++){}
-  if( g.zExtra ){
-    /* Skip to start of extra stuff, then pass over any /'s that might
-    ** have separated the document root from the extra stuff. This
-    ** ensures that the redirection actually redirects the root, not
-    ** something deep down at the bottom of a URL.
-    */
-    i -= strlen(g.zExtra);
-    while( i>0 && zCur[i-1]=='/' ){ i--; }
-  }
-  while( i>0 && zCur[i-1]!='/' ){ i--; }
-  while( i>0 && zCur[i-1]=='/' ){ i--; }
-
-  if( strcmp(zMode,"on")==0 ){
-    return mprintf("https://%s%.*s", zHost, i, zCur);
-  }
-  return mprintf("http://%s%.*s", zHost, i, zCur);
-}
-
-/*
-** Preconditions:
-**
-**    * Environment various are set up according to the CGI standard.
-**    * The respository database has been located and opened.
-**
-** Process the webpage specified by the PATH_INFO or REQUEST_URI
-** environment variable.
-*/
-static void process_one_web_page(void){
-  const char *zPathInfo;
-  char *zPath;
-  int idx;
-  int i, j;
-
-  /* Find the page that the user has requested, construct and deliver that
-  ** page.
-  */
-  zPathInfo = P("PATH_INFO");
-  if( zPathInfo==0 || zPathInfo[0]==0 ){
-    const char *zUri;
-    char *zBase;
-    zUri = PD("REQUEST_URI","/");
-    for(i=0; zUri[i] && zUri[i]!='?' && zUri[i]!='#'; i++){}
-    for(j=i; j>0 && zUri[j-1]!='/'; j--){}
-    zBase = mprintf("%.*s/index", i-j, &zUri[j]);
-    cgi_redirect(zBase);
-    cgi_reply();
-    return;
-  }else{
-    zPath = mprintf("%s", zPathInfo);
-  }
-
-  /* Remove the leading "/" at the beginning of the path.
-  */
-  g.zPath = &zPath[1];
-  for(i=1; zPath[i] && zPath[i]!='/'; i++){}
-  if( zPath[i]=='/' ){
-    zPath[i] = 0;
-    g.zExtra = &zPath[i+1];
-
-    /* CGI parameters get this treatment elsewhere, but places like getfile
-    ** will use g.zExtra directly.
-    */
-    dehttpize(g.zExtra);
-  }else{
-    g.zExtra = 0;
-  }
-  g.zBaseURL = get_base_url();
-
-  /* Prevent robots from indexing this site.
-  */
-  if( strcmp(g.zPath, "robots.txt")==0 ){
-    cgi_set_content_type("text/plain");
-    @ User-agent: *
-    @ Disallow: /
-    cgi_reply();
-    exit(0);
-  }
-
-  /* Locate the method specified by the path and execute the function
-  ** that implements that method.
-  */
-  if( name_search(g.zPath, aWebpage, count(aWebpage), &idx) &&
-      name_search("not_found", aWebpage, count(aWebpage), &idx) ){
-    cgi_set_status(404,"Not Found");
-    @ <h1>Not Found</h1>
-    @ <p>Page not found: %h(g.zPath)</p>
-  }else{
-    aWebpage[idx].xFunc();
-  }
-
-  /* Return the result.
-  */
-  cgi_reply();
-}
-
-/*
-** COMMAND: cgi
-**
-** Usage: %fossil ?cgi? SCRIPT
-**
-** The SCRIPT argument is the name of a file that is the CGI script
-** that is being run.  The command name, "cgi", may be omitted if
-** the GATEWAY_INTERFACE environment variable is set to "CGI" (which
-** should always be the case for CGI scripts run by a webserver.)  The
-** SCRIPT file should look something like this:
-**
-**      #!/usr/bin/fossil
-**      repository: /home/somebody/project.db
-**
-** The second line defines the name of the repository.  After locating
-** the repository, fossil will generate a webpage on stdout based on
-** the values of standard CGI environment variables.
-*/
-void cmd_cgi(void){
-  const char *zFile;
-  Blob config, line, key, value;
-  if( g.argc==3 && strcmp(g.argv[1],"cgi")==0 ){
-    zFile = g.argv[2];
-  }else{
-    zFile = g.argv[1];
-  }
-  g.cgiPanic = 1;
-  blob_read_from_file(&config, zFile);
-  while( blob_line(&config, &line) ){
-    if( !blob_token(&line, &key) ) continue;
-    if( blob_buffer(&key)[0]=='#' ) continue;
-    if( blob_eq(&key, "debug:") && blob_token(&line, &value) ){
-      g.fDebug = fopen(blob_str(&value), "a");
-      blob_reset(&value);
-      continue;
-    }
-    if( blob_eq(&key, "HOME:") && blob_token(&line, &value) ){
-      cgi_setenv("HOME", blob_str(&value));
-      blob_reset(&value);
-      continue;
-    }
-    if( blob_eq(&key, "repository:") && blob_token(&line, &value) ){
-      db_open_repository(blob_str(&value));
-      blob_reset(&value);
-      blob_reset(&config);
-      break;
-    }
-  }
-  if( g.db==0 ){
-    cgi_panic("Unable to find or open the project repository");
-  }
-  cgi_init();
-  process_one_web_page();
-}
-
-/*
-** COMMAND: http
-**
-** Usage: %fossil http REPOSITORY
-**
-** Handle a single HTTP request appearing on stdin.  The resulting webpage
-** is delivered on stdout.  This method is used to launch an HTTP request
-** handler from inetd, for example.  The argument is the name of the
-** repository.
-*/
-void cmd_http(void){
-  if( g.argc!=2 && g.argc!=3 ){
-    cgi_panic("no repository specified");
-  }
-  g.cgiPanic = 1;
-  if( g.argc==3 ){
-    db_open_repository(g.argv[2]);
-  }else{
-    db_must_be_within_tree();
-  }
-  cgi_handle_http_request();
-  process_one_web_page();
-}
-
-/*
-** COMMAND: server
-**
-** Usage: %fossil server ?-P|--port TCPPORT? ?REPOSITORY?
-**
-** Open a socket and begin listening and responding to HTTP requests on
-** TCP port 8080, or on any other TCP port defined by the -P or
-** --port option.  The optional argument is the name of the repository.
-** The repository argument may be omitted if the working directory is
-** within an open checkout.
-*/
-void cmd_webserver(void){
-  int iPort;
-  const char *zPort;
-
-  zPort = find_option("port", "P", 1);
-  if( zPort ){
-    iPort = atoi(zPort);
-  }else{
-    iPort = 8080;
-  }
-  if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?");
-  if( g.argc==2 ){
-    db_must_be_within_tree();
-    db_close();
-  }
-  cgi_http_server(iPort);
-  if( g.fHttpTrace ){
-    fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
-  }
-  g.cgiPanic = 1;
-  if( g.argc==2 ){
-    db_must_be_within_tree();
-  }else{
-    db_open_repository(g.argv[2]);
-  }
-  cgi_handle_http_request();
-  process_one_web_page();
-}
+

Modified src/setup.c from [d267e09065] to [da39a3ee5e].

@@ -1,547 +1,1 @@
-/*
-** Copyright (c) 2007 D. Richard Hipp
-**
-** This program is free software; you can redistribute it and/or
-** modify it under the terms of the GNU General Public
-** License as published by the Free Software Foundation; either
-** version 2 of the License, or (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-** General Public License for more details.
-**
-** You should have received a copy of the GNU General Public
-** License along with this library; if not, write to the
-** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-** Boston, MA  02111-1307, USA.
-**
-** Author contact information:
-**   drh@hwaci.com
-**   http://www.hwaci.com/drh/
-**
-*******************************************************************************
-**
-** Implementation of the Setup page
-*/
-#include <assert.h>
-#include "config.h"
-#include "setup.h"
-
-
-/*
-** Output a single entry for a menu generated using an HTML table.
-** If zLink is not NULL or an empty string, then it is the page that
-** the menu entry will hyperlink to.  If zLink is NULL or "", then
-** the menu entry has no hyperlink - it is disabled.
-*/
-static void menu_entry(
-  const char *zTitle,
-  const char *zLink,
-  const char *zDesc
-){
-  @ <dt>
-  if( zLink && zLink[0] ){
-    @ <a href="%s(zLink)">%h(zTitle)</a>
-  }else{
-    @ %h(zTitle)
-  }
-  @ </dt>
-  @ <dd>%h(zDesc)</dd>
-}
-
-/*
-** WEBPAGE: /setup
-*/
-void setup_page(void){
-  login_check_credentials();
-  if( !g.okSetup ){
-    login_needed();
-  }
-
-  style_header("Setup");
-  @ <dl id="setup">
-  menu_entry("Users", "setup_ulist",
-    "Grant privileges to individual users.");
-  menu_entry("Access", "setup_access",
-    "Control access settings.");
-  menu_entry("Configuration", "setup_config",
-    "Configure the WWW components of the repository");
-  @ </dl>
-
-  style_footer();
-}
-
-/*
-** WEBPAGE: setup_ulist
-**
-** Show a list of users.  Clicking on any user jumps to the edit
-** screen for that user.
-*/
-void setup_ulist(void){
-  Stmt s;
-
-  style_footer();
-  login_check_credentials();
-  if( !g.okSetup ){
-    login_needed();
-    return;
-  }
-
-  style_submenu_element("Add", "Add User", "setup_uedit");
-  style_header("User List");
-  @ <table align="left" hspace="10" border="1" cellpadding="10"><tr><td>
-  @ <table cellspacing=0 cellpadding=0 border=0>
-  @ <tr>
-  @   <th align="right">User&nbsp;ID</th>
-  @   <th>&nbsp;&nbsp;&nbsp;Capabilities&nbsp;&nbsp;&nbsp;</th>
-  @   <th>Contact&nbsp;Info</th>
-  @ </tr>
-  db_prepare(&s, "SELECT uid, login, cap, info FROM user ORDER BY login");
-  while( db_step(&s)==SQLITE_ROW ){
-    @ <tr>
-    @ <td align="right">
-    if( g.okAdmin ){
-      @ <a href="setup_uedit?id=%d(db_column_int(&s,0))">
-    }
-    @ <nobr>%h(db_column_text(&s,1))</nobr>
-    if( g.okAdmin ){
-      @ </a>
-    }
-    @ </td>
-    @ <td align="center">%s(db_column_text(&s,2))</td>
-    @ <td align="left">%s(db_column_text(&s,3))</td>
-    @ </tr>
-  }
-  @ </table></td></tr></table>
-  @ <p style="clear:both">
-  @ <b>Notes:</b>
-  @ <ol>
-  @ <li><p>The permission flags are as follows:</p>
-  @ <table>
-  @ <tr><td>s</td><td></td><td>Setup: Superuser can do anything</td></tr>
-  @ <tr><td>a</td><td width="10"></td>
-  @     <td>Admin: Create or delete users and ticket report formats</td></tr>
-  @ <tr><td>d</td><td></td>
-  @     <td>Delete: Erase anonymous wiki, tickets, and attachments</td></tr>
-  @ <tr><td>p</td><td></td><td>Password: Change password</td></tr>
-  @ <tr><td>q</td><td></td><td>Query: Create or edit report formats</td></tr>
-  @ <tr><td>i</td><td></td>
-  @     <td>Check-in: Add new code to the repository</td></tr>
-  @ <tr><td>o</td><td></td>
-  @     <td>Check-out: Read code out of the repository</td></tr>
-  @ <tr><td>h</td><td></td>
-  @     <td>History: Access older version of code, tickets, or wiki</td></tr>
-  @ <tr><td>g</td><td></td><td>Clone: Clone the repository</td></tr>
-  @ <tr><td>j</td><td></td><td>Read-Wiki: View wiki pages</td></tr>
-  @ <tr><td>f</td><td></td><td>New-Wiki: Create new wiki pages</td></tr>
-  @ <tr><td>m</td><td></td><td>Append-Wiki: Append to wiki pages</td></tr>
-  @ <tr><td>k</td><td></td><td>Write-Wiki: Modify wiki pages</td></tr>
-  @ <tr><td>r</td><td></td>
-  @      <td>Read-Tkt: View tickets and change histories</td></tr>
-  @ <tr><td>n</td><td></td><td>New-Tkt: Create new tickets</td></tr>
-  @ <tr><td>c</td><td></td><td>Append-Tkt: Append to tickets</td></tr>
-  @ <tr><td>w</td><td></td><td>Write-Tkt: Edit tickets</td></tr>
-  @ </table>
-  @ </p></li>
-  @
-  @ <li><p>
-  @ Every user, logged in or not, has the privileges of <b>nobody</b>.
-  @ Any human can login as <b>anonymous</b> since the password is
-  @ clearly displayed on the login page for them to type.  The purpose
-  @ of requiring anonymous to log in is to prevent access by spiders.
-  @ </p></li>
-  @
-  @ </ol>
-  style_footer();
-}
-
-/*
-** WEBPAGE: /setup_uedit
-*/
-void user_edit(void){
-  const char *zId, *zLogin, *zInfo, *zCap;
-  char *oaa, *oas, *oar, *oaw, *oan, *oai, *oaj, *oao, *oap ;
-  char *oak, *oad, *oaq, *oac, *oaf, *oam, *oah, *oag;
-  int doWrite;
-  int uid;
-  int higherUser = 0;  /* True if user being edited is SETUP and the */
-                       /* user doing the editing is ADMIN.  Disallow editing */
-
-  /* Must have ADMIN privleges to access this page
-  */
-  login_check_credentials();
-  if( !g.okAdmin ){ login_needed(); return; }
-
-  /* Check to see if an ADMIN user is trying to edit a SETUP account.
-  ** Don't allow that.
-  */
-  zId = PD("id", "0");
-  uid = atoi(zId);
-  if( zId && !g.okSetup && uid>0 ){
-    char *zOldCaps;
-    zOldCaps = db_text(0, "SELECT caps FROM user WHERE uid=%d",uid);
-    higherUser = zOldCaps && strchr(zOldCaps,'s');
-  }
-
-  if( P("can") ){
-    cgi_redirect("setup_ulist");
-    return;
-  }
-
-  /* If we have all the necessary information, write the new or
-  ** modified user record.  After writing the user record, redirect
-  ** to the page that displays a list of users.
-  */
-  doWrite = cgi_all("login","info","pw") && !higherUser;
-  if( doWrite ){
-    const char *zPw;
-    const char *zLogin;
-    char zCap[30];
-    int i = 0;
-    int aa = P("aa")!=0;
-    int ad = P("ad")!=0;
-    int ai = P("ai")!=0;
-    int aj = P("aj")!=0;
-    int ak = P("ak")!=0;
-    int an = P("an")!=0;
-    int ao = P("ao")!=0;
-    int ap = P("ap")!=0;
-    int aq = P("aq")!=0;
-    int ar = P("ar")!=0;
-    int as = g.okSetup && P("as")!=0;
-    int aw = P("aw")!=0;
-    int ac = P("ac")!=0;
-    int af = P("af")!=0;
-    int am = P("am")!=0;
-    int ah = P("ah")!=0;
-    int ag = P("ag")!=0;
-    if( aa ){ zCap[i++] = 'a'; }
-    if( ac ){ zCap[i++] = 'c'; }
-    if( ad ){ zCap[i++] = 'd'; }
-    if( af ){ zCap[i++] = 'f'; }
-    if( ah ){ zCap[i++] = 'h'; }
-    if( ag ){ zCap[i++] = 'g'; }
-    if( ai ){ zCap[i++] = 'i'; }
-    if( aj ){ zCap[i++] = 'j'; }
-    if( ak ){ zCap[i++] = 'k'; }
-    if( am ){ zCap[i++] = 'm'; }
-    if( an ){ zCap[i++] = 'n'; }
-    if( ao ){ zCap[i++] = 'o'; }
-    if( ap ){ zCap[i++] = 'p'; }
-    if( aq ){ zCap[i++] = 'q'; }
-    if( ar ){ zCap[i++] = 'r'; }
-    if( as ){ zCap[i++] = 's'; }
-    if( aw ){ zCap[i++] = 'w'; }
-
-    zCap[i] = 0;
-    zPw = P("pw");
-    if( zPw==0 || zPw[0]==0 ){
-      zPw = db_text(0, "SELECT pw FROM user WHERE uid=%d", uid);
-    }
-    zLogin = P("login");
-    if( uid>0 &&
-        db_exists("SELECT 1 FROM user WHERE login=%Q AND uid!=%d", zLogin, uid)
-    ){
-      style_header("User Creation Error");
-      @ <font color="red">Login "%h(zLogin)" is already used by a different
-      @ user.</font>
-      @
-      @ <p><a href="setup_uedit?id=%d(uid))>[Bummer]</a></p>
-      style_footer();
-      return;
-    }
-    db_multi_exec(
-       "REPLACE INTO user(uid,login,info,pw,cap) "
-       "VALUES(nullif(%d,0),%Q,%Q,%Q,'%s')",
-      uid, P("login"), P("info"), zPw, zCap
-    );
-    cgi_redirect("setup_ulist");
-    return;
-  }
-
-  /* Load the existing information about the user, if any
-  */
-  zLogin = "";
-  zInfo = "";
-  zCap = "";
-  oaa = oac = oad = oaf = oag = oah = oai = oaj = oak = oam =
-        oan = oao = oap = oaq = oar = oas = oaw = "";
-  if( uid ){
-    zLogin = db_text("", "SELECT login FROM user WHERE uid=%d", uid);
-    zInfo = db_text("", "SELECT info FROM user WHERE uid=%d", uid);
-    zCap = db_text("", "SELECT cap FROM user WHERE uid=%d", uid);
-    if( strchr(zCap, 'a') ) oaa = " checked";
-    if( strchr(zCap, 'c') ) oac = " checked";
-    if( strchr(zCap, 'd') ) oad = " checked";
-    if( strchr(zCap, 'f') ) oaf = " checked";
-    if( strchr(zCap, 'g') ) oag = " checked";
-    if( strchr(zCap, 'h') ) oah = " checked";
-    if( strchr(zCap, 'i') ) oai = " checked";
-    if( strchr(zCap, 'j') ) oaj = " checked";
-    if( strchr(zCap, 'k') ) oak = " checked";
-    if( strchr(zCap, 'm') ) oam = " checked";
-    if( strchr(zCap, 'n') ) oan = " checked";
-    if( strchr(zCap, 'o') ) oao = " checked";
-    if( strchr(zCap, 'p') ) oap = " checked";
-    if( strchr(zCap, 'q') ) oaq = " checked";
-    if( strchr(zCap, 'r') ) oar = " checked";
-    if( strchr(zCap, 's') ) oas = " checked";
-    if( strchr(zCap, 'w') ) oaw = " checked";
-  }
-
-  /* Begin generating the page
-  */
-  style_submenu_element("Cancel", "Cancel", "setup_ulist");
-  if( uid ){
-    style_header(mprintf("Edit User %h", zLogin));
-  }else{
-    style_header("Add A New User");
-  }
-  @ <table align="left" hspace="20" vspace="10"><tr><td>
-  @ <form action="%s(g.zPath)" method="POST">
-  @ <table>
-  @ <tr>
-  @   <td align="right"><nobr>User ID:</nobr></td>
-  if( uid ){
-    @   <td>%d(uid) <input type="hidden" name="id" value="%d(uid)"></td>
-  }else{
-    @   <td>(new user)<input type="hidden" name="id" value=0></td>
-  }
-  @ </tr>
-  @ <tr>
-  @   <td align="right"><nobr>Login:</nobr></td>
-  @   <td><input type="text" name="login" value="%h(zLogin)"></td>
-  @ </tr>
-  @ <tr>
-  @   <td align="right"><nobr>Contact&nbsp;Info:</nobr></td>
-  @   <td><input type="text" name="info" size=40 value="%h(zInfo)"></td>
-  @ </tr>
-  @ <tr>
-  @   <td align="right" valign="top">Capabilities:</td>
-  @   <td>
-  if( g.okSetup ){
-    @     <input type="checkbox" name="as"%s(oas)>Setup</input><br>
-  }
-  @     <input type="checkbox" name="aa"%s(oaa)>Admin</input><br>
-  @     <input type="checkbox" name="ad"%s(oad)>Delete</input><br>
-  @     <input type="checkbox" name="ap"%s(oap)>Password</input><br>
-  @     <input type="checkbox" name="aq"%s(oaq)>Query</input><br>
-  @     <input type="checkbox" name="ai"%s(oai)>Check-In</input><br>
-  @     <input type="checkbox" name="ao"%s(oao)>Check-Out</input><br>
-  @     <input type="checkbox" name="ah"%s(oah)>History</input><br>
-  @     <input type="checkbox" name="ag"%s(oag)>Clone</input><br>
-  @     <input type="checkbox" name="aj"%s(oaj)>Read Wiki</input><br>
-  @     <input type="checkbox" name="af"%s(oaf)>New Wiki</input><br>
-  @     <input type="checkbox" name="am"%s(oam)>Append Wiki</input><br>
-  @     <input type="checkbox" name="ak"%s(oak)>Write Wiki</input><br>
-  @     <input type="checkbox" name="ar"%s(oar)>Read Tkt</input><br>
-  @     <input type="checkbox" name="an"%s(oan)>New Tkt</input><br>
-  @     <input type="checkbox" name="ac"%s(oac)>Append Tkt</input><br>
-  @     <input type="checkbox" name="aw"%s(oaw)>Write Tkt</input>
-  @   </td>
-  @ </tr>
-  @ <tr>
-  @   <td align="right">Password:</td>
-  @   <td><input type="password" name="pw" value=""></td>
-  @ </tr>
-  if( !higherUser ){
-    @ <tr>
-    @   <td>&nbsp</td>
-    @   <td><input type="submit" name="submit" value="Apply Changes">
-    @ </tr>
-  }
-  @ </table></td></tr></table>
-  @ <p><b>Notes:</b></p>
-  @ <ol>
-  if( higherUser ){
-    @ <li><p>
-    @ User %h(zId) has Setup privileges and you only have Admin privileges
-    @ so you are not permitted to make changes to %h(zId).
-    @ </p></li>
-    @
-  }
-  @
-  @ <li><p>
-  @ The <b>Delete</b> privilege give the user the ability to erase
-  @ wiki, tickets, and atttachments that have been added by anonymous
-  @ users.  This capability is intended for deletion of spam.
-  @ </p></li>
-  @
-  @ <li><p>
-  @ The <b>Query</b> privilege allows the user to create or edit
-  @ report formats by specifying appropriate SQL.  Users can run
-  @ existing reports without the Query privilege.
-  @ </p></li>
-  @
-  @ <li><p>
-  @ An <b>Admin</b> user can add other users, create new ticket report
-  @ formats, and change system defaults.  But only the <b>Setup</b> user
-  @ is able to change the repository to
-  @ which this program is linked.
-  @ </p></li>
-  @
-  @ <li><p>
-  @ The <b>History</b> privilege allows a user to see a timeline
-  @ with hyperlinks to version information, to download ZIP archives
-  @ of individual versions.
-  @ </p></li>
-  @
-  @ <li><p>
-  @ No login is required for user "<b>nobody</b>".  The capabilities
-  @ of this user are available to anyone without supplying a username or
-  @ password.  To disable nobody access, make sure there is no user
-  @ with an ID of <b>nobody</b> or that the nobody user has no
-  @ capabilities enabled.  The password for nobody is ignore.  To
-  @ avoid problems with spiders overloading the server, it is suggested
-  @ that the 'h' (History) capability be turned off for user nobody.
-  @ </p></li>
-  @
-  @ <li><p>
-  @ Login is required for user "<b>anonymous</b>" but the password
-  @ is displayed on the login screen beside the password entry box
-  @ so anybody who can read should be able to login as anonymous.
-  @ On the other hand, spiders and web-crawlers will typically not
-  @ be able to login.  Set the capabilities of the anonymous user
-  @ to things that you want any human to be able to do, but no any
-  @ spider.
-  @ </p></li>
-  @ </form>
-  style_footer();
-}
-
-
-/*
-** Generate a checkbox for an attribute.
-*/
-static void onoff_attribute(
-  const char *zLabel,   /* The text label on the checkbox */
-  const char *zVar,     /* The corresponding row in the VAR table */
-  const char *zQParm,   /* The query parameter */
-  int dfltVal           /* Default value if VAR table entry does not exist */
-){
-  const char *zVal = db_get(zVar, 0);
-  const char *zQ = P(zQParm);
-  int iVal;
-  if( zVal ){
-    iVal = atoi(zVal);
-  }else{
-    iVal = dfltVal;
-  }
-  if( zQ==0 && P("submit") ){
-    zQ = "off";
-  }
-  if( zQ ){
-    int iQ = strcmp(zQ,"on")==0 || atoi(zQ);
-    if( iQ!=iVal ){
-      db_set(zVar, iQ ? "1" : "0");
-      iVal = iQ;
-    }
-  }
-  if( iVal ){
-    @ <input type="checkbox" name="%s(zQParm)" checked>%s(zLabel)</input>
-  }else{
-    @ <input type="checkbox" name="%s(zQParm)">%s(zLabel)</input>
-  }
-}
-
-/*
-** Generate an entry box for an attribute.
-*/
-static void entry_attribute(
-  const char *zLabel,   /* The text label on the entry box */
-  int width,            /* Width of the entry box */
-  const char *zVar,     /* The corresponding row in the VAR table */
-  const char *zQParm,   /* The query parameter */
-  const char *zDflt     /* Default value if VAR table entry does not exist */
-){
-  const char *zVal = db_get(zVar, zDflt);
-  const char *zQ = P(zQParm);
-  if( zQ && strcmp(zQ,zVal)!=0 ){
-    db_set(zVar, zQ);
-    zVal = zQ;
-  }
-  @ <input type="text" name="%s(zQParm)" value="%h(zVal)" size="%d(width)">
-  @ %s(zLabel)
-}
-
-
-
-/*
-** WEBPAGE: setup_access
-*/
-void setup_access(void){
-  login_check_credentials();
-  if( !g.okSetup ){
-    login_needed();
-  }
-
-  style_header("Access Control Settings");
-  db_begin_transaction();
-  @ <form action="%s(g.zBaseURL)/setup_access" method="POST">
-
-  @ <hr>
-  onoff_attribute("Require password for local access",
-     "authenticate-localhost", "localauth", 1);
-  @ <p>When enabled, the password sign-in is required for
-  @ web access coming from 127.0.0.1.  When disabled, web access
-  @ from 127.0.0.1 is allows without any login - the user id is selected
-  @ from the ~/.fossil database. Password login is always required
-  @ for incoming web connections on internet addresses other than
-  @ 127.0.0.1.</p></li>
-
-  @ <hr>
-  entry_attribute("Login expiration time", 6, "cookie-expire", "cex", "8766");
-  @ <p>The number of hours for which a login is valid.  This must be a
-  @ positive number.  The default is 8760 hours which is approximately equal
-  @ to a year.</p>
-
-  @ <hr>
-  onoff_attribute("Allow anonymous signup", "anon-signup", "asu", 0);
-  @ <p>Allow users to create their own accounts</p>
-
-  @ <hr>
-  @ <p><input type="submit"  name="submit" value="Apply Changes"></p>
-  @ </form>
-  db_end_transaction(0);
-  style_footer();
-}
-
-/*
-** WEBPAGE: setup_config
-*/
-void setup_config(void){
-  login_check_credentials();
-  if( !g.okSetup ){
-    login_needed();
-  }
-
-  style_header("WWW Configuration");
-  db_begin_transaction();
-  @ <form action="%s(g.zBaseURL)/setup_config" method="POST">
-
-  @ <hr>
-  entry_attribute("Home page", 60, "homepage", "hp", "");
-  @ <p>The name of a wiki file that is the homepage for the website.
-  @ The home page is the page that is displayed by the "Home" link
-  @ at the top of this screen.</p>
-
-  entry_attribute("Ticket subdirectory", 60, "ticket-subdir", "tsd", "");
-  @ <p>A subdirectory in the file hierarchy that contains all trouble
-  @ tickets.  Leave this blank to disable ticketing.  Tickets text
-  @ files within this subdirectory containing a particular format
-  @ (documented separately) and with the ".tkt" suffix.</p>
-
-  entry_attribute("Wiki subdirectory", 60, "wiki-subdir", "wsd", "");
-  @ <p>A subdirectory in the file hierarchy that contains wiki pages.
-  @ Leave this blank to disable wiki.  Wiki pages are
-  @ files within this subdirectory whose name is he wiki page title
-  @ and with the suffix ".wiki".</p>
-
-
-  @ <hr>
-  @ <p><input type="submit"  name="submit" value="Apply Changes"></p>
-  @ </form>
-  db_end_transaction(0);
-  style_footer();
-}
+

Modified src/timeline.c from [4792000fa7] to [da39a3ee5e].

@@ -1,229 +1,1 @@
-/*
-** Copyright (c) 2007 D. Richard Hipp
-**
-** This program is free software; you can redistribute it and/or
-** modify it under the terms of the GNU General Public
-** License version 2 as published by the Free Software Foundation.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-** General Public License for more details.
-**
-** You should have received a copy of the GNU General Public
-** License along with this library; if not, write to the
-** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-** Boston, MA  02111-1307, USA.
-**
-** Author contact information:
-**   drh@hwaci.com
-**   http://www.hwaci.com/drh/
-**
-*******************************************************************************
-**
-** This file contains code to implement the timeline web page
-**
-*/
-#include "config.h"
-#include "timeline.h"
-
-/*
-** Generate a hyperlink to a version.
-*/
-void hyperlink_to_uuid(const char *zUuid){
-  char zShortUuid[UUID_SIZE+1];
-  sprintf(zShortUuid, "%.10s", zUuid);
-  if( g.okHistory ){
-    @ <a href="%s(g.zBaseURL)/vinfo/%s(zUuid)">[%s(zShortUuid)]</a>
-  }else{
-    @ <b>[%s(zShortUuid)]</b>
-  }
-}
-
-/*
-** Generate a hyperlink to a diff between two versions.
-*/
-void hyperlink_to_diff(const char *zV1, const char *zV2){
-  if( g.okHistory ){
-    if( zV2==0 ){
-      @ <a href="%s(g.zBaseURL)/diff?v2=%s(zV1)">[diff]</a>
-    }else{
-      @ <a href="%s(g.zBaseURL)/diff?v1=%s(zV1)&v2=%s(zV2)">[diff]</a>
-    }
-  }
-}
-
-/*
-** Output a timeline in the web format given a query.  The query
-** should return 4 columns:
-**
-**    0.  UUID
-**    1.  Date/Time
-**    2.  Comment string
-**    3.  User
-*/
-void www_print_timeline(Stmt *pQuery, char *zLastDate){
-  char zPrevDate[20];
-  zPrevDate[0] = 0;
-  @ <table cellspacing=0 border=0 cellpadding=0>
-  while( db_step(pQuery)==SQLITE_ROW ){
-    const char *zDate = db_column_text(pQuery, 1);
-    if( memcmp(zDate, zPrevDate, 10) ){
-      sprintf(zPrevDate, "%.10s", zDate);
-      @ <tr><td colspan=3>
-      @ <table cellpadding=2 border=0>
-      @ <tr><td bgcolor="#a0b5f4" class="border1">
-      @ <table cellpadding=2 cellspacing=0 border=0><tr>
-      @ <td bgcolor="#d0d9f4" class="bkgnd1">%s(zPrevDate)</td>
-      @ </tr></table>
-      @ </td></tr></table>
-      @ </td></tr>
-    }
-    @ <tr><td valign="top">%s(&zDate[11])</td>
-    @ <td width="20"></td>
-    @ <td valign="top" align="left">
-    hyperlink_to_uuid(db_column_text(pQuery,0));
-    @ %h(db_column_text(pQuery,2)) (by %h(db_column_text(pQuery,3)))</td>
-    if( zLastDate ){
-      strcpy(zLastDate, zDate);
-    }
-  }
-  @ </table>
-}
-
-
-
-/*
-** WEBPAGE: timeline
-*/
-void page_timeline(void){
-  Stmt q;
-  char *zSQL;
-  char zDate[100];
-  const char *zStart = P("d");
-  int nEntry = atoi(PD("n","25"));
-
-  /* To view the timeline, must have permission to read project data.
-  */
-  login_check_credentials();
-  if( !g.okRead ){ login_needed(); return; }
-
-  style_header("Timeline");
-  if( !g.okHistory &&
-      db_exists("SELECT 1 FROM user"
-                " WHERE login='anonymous'"
-                "   AND cap LIKE '%%h%%'") ){
-    @ <p><b>Note:</b> You will be able to see much more timeline
-    @ information if <a href="%s(g.zBaseURL)/login">login</a>.</p>
-  }
-  zSQL = mprintf(
-    "SELECT uuid, datetime(event.mtime,'localtime'), comment, user"
-    "  FROM event, blob"
-    " WHERE event.type='ci' AND blob.rid=event.objid"
-  );
-  if( zStart ){
-    while( isspace(zStart[0]) ){ zStart++; }
-    if( zStart[0] ){
-      zSQL = mprintf("%z AND event.mtime<=julianday(%Q, 'localtime')",
-                      zSQL, zStart);
-    }
-  }
-  zSQL = mprintf("%z ORDER BY event.mtime DESC LIMIT %d", zSQL, nEntry);
-  db_prepare(&q, zSQL);
-  free(zSQL);
-  zDate[0] = 0;
-  www_print_timeline(&q, zDate);
-  db_finalize(&q);
-  if( zStart==0 ){
-    zStart = zDate;
-  }
-  @ <hr>
-  @ <form method="GET" action="%s(g.zBaseURL)/timeline">
-  @ Start Date:
-  @ <input type="text" size="30" value="%h(zStart)" name="d">
-  @ Number Of Entries:
-  @ <input type="text" size="4" value="%d(nEntry)" name="n">
-  @ <br><input type="submit" value="Submit">
-  @ </form>
-  @ <form method="GET" action="%s(g.zBaseURL)/timeline">
-  @ <input type="hidden" value="%h(zDate)" name="d">
-  @ <input type="hidden" value="%d(nEntry)" name="n">
-  @ <input type="submit" value="Next %d(nEntry) Rows">
-  @ </form>
-  style_footer();
-}
-
-/*
-** The input query q selects various records.  Print a human-readable
-** summary of those records.
-**
-** Limit the number of entries printed to nLine.
-*/
-void print_timeline(Stmt *q, int mxLine){
-  int nLine = 0;
-  char zPrevDate[20];
-  zPrevDate[0] = 0;
-
-  while( db_step(q)==SQLITE_ROW && nLine<=mxLine ){
-    const char *zId = db_column_text(q, 0);
-    const char *zDate = db_column_text(q, 1);
-    const char *zCom = db_column_text(q, 2);
-    char zUuid[UUID_SIZE+1];
-
-    sprintf(zUuid, "%.10s", zId);
-    if( memcmp(zDate, zPrevDate, 10) ){
-      printf("=== %.10s ===\n", zDate);
-      memcpy(zPrevDate, zDate, 10);
-      nLine++;
-    }
-    if( zCom==0 ) zCom = "";
-    printf("%.5s [%.10s] ", &zDate[11], zUuid);
-    nLine += comment_print(zCom, 19, 79);
-  }
-}
-
-
-/*
-** COMMAND: timeline
-**
-** Usage: %fossil timeline ?DATETIME? ?-n|--count N?
-**
-** Print a summary of activity going backwards in date and time
-** specified or from the current date and time if no arguments
-** are given.  Show as many as N (default 20) check-ins.
-**
-** The date and time should be in the ISO8601 format.  For
-** examples: "2007-08-18 07:21:21".  The time may be omitted.
-** Times are according to the local timezone.
-*/
-void timeline_cmd(void){
-  Stmt q;
-  int n;
-  char *zCount;
-  char *zDate;
-  db_find_and_open_repository();
-  zCount = find_option("n","count",1);
-  if( zCount ){
-    n = atoi(zCount);
-  }else{
-    n = 20;
-  }
-  if( g.argc!=2 && g.argc!=3 ){
-    usage("YYYY-MM-DDtHH:MM:SS");
-  }
-  if( g.argc==3 ){
-    zDate = g.argv[2];
-  }else{
-    zDate = "now";
-  }
-  db_prepare(&q,
-    "SELECT uuid, datetime(event.mtime,'localtime'),"
-    "       comment || ' (by ' || user || ')'"
-    "  FROM event, blob"
-    " WHERE event.type='ci' AND blob.rid=event.objid"
-    "   AND event.mtime<=(SELECT julianday(%Q,'utc'))"
-    " ORDER BY event.mtime DESC", zDate
-  );
-  print_timeline(&q, n);
-  db_finalize(&q);
-}
+

Added www/concept1.gif version [da39a3ee5e]


Added www/concept2.gif version [da39a3ee5e]


Added www/concepts.html version [da39a3ee5e]


Modified www/fileformat.html from [c1aa3452d9] to [da39a3ee5e].

@@ -1,179 +1,1 @@
-<html>
-<head>
-<title>Fossil File Format</title>
-</head>
-<body bgcolor="white">
-<h1 align="center">
-Fossil File Formats
-</h1>
-
-<p>
-The global state of a fossil repository is determined by an unordered
-set of files.  Some files used to represent wiki pages, trouble tickets,
-and the special "manifest" file has a specific and well-defined format.
-Other files are just the content of the files.  Files can be text or
-binary.
-</p>
-
-<p>
-Each file in the repository is named by its SHA1 hash.
-Some files have a particular format which qualifies them
-as "manifests".  A manifest assigns filenames to a subset
-of the files in the repository, in order to provide a
-snapshot of the state of the project at a point in time.
-Each manifest file corresponds to a version or baseline
-of the project.
-</p>
-
-<h2>1.0 The Manifest File</h2>
-
-<p>
-Any file in the repository that follows the syntactic rules
-of a manifest is a manifest.  Note that a manifest can
-be both a real manifest and also a content file, though this
-is rare.
-</p>
-
-<p>
-A manifest is a line-oriented text file.  Newline characters
-(ASCII 0x0a) separate lines.  Each line begins with a single
-character "line type".  Zero or more arguments may follow
-the line type.  All arguments are separated from each other
-and from the line-type character by a single space
-character.  There is no surplus white space between arguments
-and no leading or trailing whitespace except for the newline
-character that acts as the line separator.
-</p>
-
-<p>
-All lines of the manifest occur in strict sorted lexigraphical order.
-No line may be duplicated.
-The entire manifest file may be PGP clear-signed, but otherwise it
-may contain no additional text or data beyond what is described here.
-</p>
-
-<p>
-Allowed lines in the manifest are as follows:
-</p>
-
-<blockquote>
-<b>C</b> <i>checkin-comment</i><br>
-<b>D</b> <i>time-and-date-stamp</i><br>
-<b>F</b> <i>filename</i> <i>SHA1-hash</i><br>
-<b>P</b> <i>SHA1-hash</i>+<br>
-<b>R</b> <i>repository-checksum</i><br>
-<b>U</b> <i>user-login</i><br>
-<b>Z</b> <i>manifest-checksum</i>
-</blockquote>
-
-<p>
-A manifest must have exactly one C-line.  The sole argument to
-the C-line is a check-in comment that describes the baseline that
-the manifest defines.  The check-in comment is text.  The following
-escape sequences are applied to the text:
-A space (ASCII 0x20) is represented as "\s" (ASCII 0x5C, 0x73).  A
-newline (ASCII 0x0a) is "\n" (ASCII 0x6C, x6E).  A backslash
-(ASCII 0x5C) is represented as two backslashes "\\".  Apart from
-space and newline, no other whitespace characters are allowed in
-the check-in comment.  Nor are any unprintable characters allowed
-in the comment.
-</p>
-
-<p>
-A manifest must have exactly one D-line.  The sole argument to
-the D-line is a date-time stamp in the ISO8601 format.  The
-date and time should be in coordinated universal time (UTC).
-The format is:
-</p>
-
-<blockquote>
-<i>YYYY</i><b>-</b><i>MM</i><b>-</b><i>DD</i><b>T</b><i>HH</i><b>:</b><i>MM</i><b>:</b><i>SS</i>
-</blockquote>
-
-<p>
-A manifest has zero or more F-lines.  Each F-line defines a file
-(other than the manifest itself) which is part of the baseline that
-the manifest defines.  There are two arguments.  The first argment
-is the pathname of the file in the baseline relative to the root
-of the project file hierarchy.  No ".." or "." directories are allowed
-within the filename.  Space characters are escaped as in C-line
-comment text.  Backslash characters and newlines are not allowed
-within filenames.  The directory separator character is a forward
-slash (ASCII 0x2F).  The second argument to the F-line is the
-full 40-character hexadecimal SHA1 hash of the file content.
-Upper-case letters ABCDEF are used for the higher digits of the
-hexadecimal.
-</p>
-
-<p>
-A manifest has zero or one P-lines.  Most manifests have one P-line.
-The P-line has a varying number of arguments that
-defines other manifests from which the current manifest
-is derived.  Each argument is an 40-character lowercase
-hexadecimal SHA1 of the predecessor manifest.  All arguments
-to the P-line must be unique to that line.
-The first predecessor is the manifests direct ancestor.
-Other arguments define manifests with which the first was
-merged to yield the current manifest.  Most manifests have
-a P-line with a single argument.  The first manifest in the
-project has no ancestors and thus has no P-line.
-</p>
-
-<p>
-A manifest may optionally have a single R-line.  The R-line has
-a single argument which is the MD5 checksum of all files in
-the baseline except the manifest itself.  The checksum is expressed
-as 32-characters of lowercase hexadecimal.   The checksum is
-computed as follows:  For each file in the baseline (except for
-the manifest itself) in strict sorted lexigraphical order,
-take the pathname of the file relative to the root of the
-repository, append a single space (ASCII 0x20), the
-size of the file in ASCII decimal, a single newline
-character (ASCII 0x0A), and the complete text of the file.
-Compute the MD5 checksum of the the result.
-</p>
-
-<p>
-Each manifest has a single U-line.  The argument to the U-line is
-the login of the user who created the manifest.  The login name
-is encoded using the same character escapes as is used for the
-check-in comment argument to the C-line.
-</p>
-
-<p>
-A manifest has an option Z-line as its last line.  The argument
-to the Z-line is a 32-character lowercase hexadecimal MD5 hash
-of all prior lines of the manifest up to and including the newline
-character that immediately preceeds the "Z".  The Z-line is just
-a sanity check to prove that the manifest is well-formed and
-consistent.
-</p>
-
-<h2>2.0 Trouble Tickets</h2>
-
-<p>
-Each trouble ticket is a file in the repository and appears in
-a manifest for every baseline in which the ticket exists.
-Trouble tickets occur in a specific subdirectory of the file
-heirarchy.  The name of the subdirectory that contains tickets
-is part of the local state of each repository.  The filename
-of each trouble ticket has a ".tkt" suffix.  The trouble ticket
-has a particular file format defined below.
-</p>
-
-<i>To be continued...</i>
-
-<h2>3.0 Wiki Pages</h2>
-
-<p>
-Each wiki is a file in the repository and appears in
-a manifest for every baseline in which that wiki page exists.
-Wiki pages occur in a specific subdirectory of the file
-heirarchy.  The name of the subdirectory that contains wiki pages
-is part of the local state of each repository.  The filename
-of each wiki page has a ".wiki" suffix.  The base name of
-the file is the name of the wiki page.  The wiki pages
-have a particular file format defined below.
-</p>
-
-<i>To be continued...</i>
+

Modified www/index.html from [55770629c6] to [da39a3ee5e].

@@ -1,88 +1,1 @@
-<html>
-<head>
-<title>Fossil SCM Homepage</title>
-</head>
-<body bgcolor="white">
-<h1>Fossil - A Software Configuration Management System</h1>
-
-<p>
-This is a preliminary homepage for a new software configuration
-management system called "Fossil".
-The system is
-<a href="http://fossil-scm.hwaci.com/fossil/index">self-hosting</a>.
-You can download the lastest sources
-compile it your self using the instructions below.
-</p>
-
-<p>Design Goals For Fossil:</p>
-
-<ul>
-<li>Supports disconnected, distributed development (like
-<a href="http://kerneltrap.org/node/4982">git</a>,
-<a href="http://www.venge.net/monotone/">monotone</a>,
-<a href="http://www.selenic.com/mercurial/wiki/index.cgi">mercurial</a>, or
-<a href="http://www.bitkeeper.com/">bitkeeper</a>)
-or client/server operation (like
-<a href="http://www.nongnu.org/cvs/">CVS</a> or
-<a href="http://subversion.tigris.org/">subversion</a>)
-or both at the same time</li>
-<li>Integrated bug tracking and wiki, along the lines of
-<a href="http://www.cvstrac.org/">CVSTrac</a> and
-<a href="http://www.edgewall.com/trac/">Trac</a>.</li>
-<li>Built-in web interface that supports deep archaeological digs through
-historical source code.</li>
-<li>All network communication via
-<a href="http://en.wikipedia.org/wiki/HTTP">HTTP</a>
-(so that everything works from behind restrictive firewalls).</li>
-<li>Everything included in a single self-contained executable -
-    trivial to install</li>
-<li>Server runs as <a href="http://www.w3.org/CGI/">CGI</a>, using
-<a href="http://en.wikipedia.org/wiki/inetd">inetd</a> or
-<a href="http://www.xinetd.org/">xinetd</a> or using its own built-in,
-standalone web server.</li>
-<li>An entire project contained in single disk file (which also
-happens to be an <a href="http://www.sqlite.org/">SQLite</a> database.)</li>
-<li>Trivial to setup and administer</li>
-<li>Files and versions are identified by their
-<a href="http://en.wikipedia.org/wiki/SHA-1">SHA1</a> signature.</a>
-Any unique prefix is sufficient to identify a file
-or version - usually the first 4 or 5 characters suffice.</li>
-<li>The file format is trival and requires nothing more complex
-than a text editor and the "sha1sum" command-line utility to decode.</li>
-<li>Automatic <a href="selfcheck.html">self-check</a>
-on repository changes makes it exceedingly
-unlikely that data will ever be lost because of a software bug.</li>
-</ul>
-
-<p>Objectives Of Fossil:</p>
-
-<ul>
-<li>Fossil should be ridiculously easy to install and operate.</li>
-<li>With fossil, it should be possible (and easy) to set up a project
-on an inexpensive shared-hosting ISP
-(example: <a href="http://www.he.net/hosting.html">Hurricane Electric</a>)
-that provides nothing more than web space and CGI capability.</li>
-<li>Fossil should provide in-depth historical and status information about the
-project through a web interface</li>
-<li>The integration of <a href="http://wiki.org/wiki.cgi?WhatIsWiki">Wiki</a>
-and the ability to safely support anonymous check-in are features sometimes
-described as
-<a href="http://www.oreillynet.com/pub/a/oreilly/tim/news/2005/09/30/what-is-web-20.html">Web 2.0</a>.
-Fossil attempts to better capture "collective intelligence" and
-"the wisdom of crowds" by opening up write access to the masses.</li>
-</ul>
-
-<p>Other Links:</p>
-
-<ul>
-<li><a href="build.html">Building And Installing</a></li>
-<li><a href="quickstart.html">Quick Start</a> guide to using fossil
-<li><a href="pop.html">Principals Of Operation</a></li>
-<li>The <a href="selfcheck.html">automatic self-check</a> mechanism
-helps insure project integrity.</li>
-<li>The <a href="fileformat.html">file format</a> used by every content
-file stored in the repository.</li>
-</ul>
-
-</body>
-</html>
+

Modified www/quickstart.html from [f9a5dc6ef0] to [da39a3ee5e].

@@ -1,228 +1,1 @@
-<html>
-<title>Fossil - Quick Start</title>
-<body bgcolor="white">
-<h1 align="center">Fossil Quick Start</h1>
-
-<p>This is a guide to get you started using fossil quickly
-and painlessly.</p>
-
-<h2>Installing</h2><blockquote>
-
-    <p>Fossil is a single self-contained C program that you need to
-    <a href="build.html">install</a> before using.  Build the binary
-    and put it someplace on your PATH environment variable.</p>
-
-    </blockquote>
-    <h2>Cloning A Existing Repository</h2>
-    <blockquote>
-
-    <p>Use this command:</p>
-
-    <blockquote>
-    <b>fossil clone</b> <i>URL  repository-filename</i>
-    </blockquote>
-
-    <p>The <i>URL</i> above is the http URL for the fossil repository
-    you want to clone.  You can call the new repository anything you
-    want - there are no naming restrictions.  As an example, you can
-    clone the fossil repository this way:</p>
-
-    <blockquote>
-    <b>fossil clone http://fossil-scm.hwaci.com/fossil myclone.fsl</b>
-    </blockquote>
-
-</blockquote><h2>Starting A New Project</h2><blockquote>
-
-    <p>To start a new project with fossil, create a new empty repository
-    this way:</p>
-
-    <blockquote>
-    <b>fossil new </b><i> repository-filename</i>
-    </blockquote>
-
-</blockquote><h2>Configuring Your Local Repository</h2><blockquote>
-
-    <p>When you create a new repository, either by cloning an existing
-    project or create a new project of your own, you usually want to do some
-    local configuration.  This is accomplished using a webbrowser.  First
-    start a fossil webserver like this:</p>
-
-    <blockquote>
-    <b>fossil server </b><i> repository-filename</i>
-    </blockquote>
-
-    <p>This creates a mini-webserver listening on port 8080.  You can
-    specify a different port using the <b>-port</b> option on the command-line.
-    After the server is running, point your webbrowser at
-    http://localhost:8080/ and start configuring.</p>
-
-    <p>By default, fossil does not require a login for HTTP connections
-    coming in from the IP loopback address 127.0.0.1.  You can, and perhaps
-    should, change this after you create a few users.</p>
-
-    <p>When you are finished configuring, just press Control-C or use
-    the <b>kill</b> command to shut down the mini-server.</p>
-
-</blockquote><h2>Checking Out A Local Tree</h2><blockquote>
-
-    <p>To work on a project in fossil, you need to check out a local
-    copy of the source tree.  Create the directory you want to be
-    the root of your tree and cd into that directory.  Then
-    to this:</p>
-
-    <blockquote>
-    <b>fossil open </b><i> repository-filename</i>
-    </blockquote>
-
-    <p>This leaves you with the original (empty) version of the tree
-    checked out.  To get to the latest version, also do this:</p>
-
-    <blockquote>
-    <b>fossil update</b>
-    </blockquote>
-
-    <p>From anywhere underneath the root of your local tree, you
-    can type commands like the following to find out the status of
-    your local tree:</p>
-
-    <blockquote>
-    <b>fossil info</b><br>
-    <b>fossil status</b><br>
-    <b>fossil changes</b><br>
-    <b>fossil timeline</b><br>
-    <b>fossil leaves</b><br>
-    <b>fossil ls</b><br>
-    <b>fossil branches</b><br>
-    </blockquote>
-
-</blockquote><h2>Making Changes</h2><blockquote>
-
-    <p>To add new files to your project, or remove old files, use these
-    commands:</p>
-
-    <blockquote>
-    <b>fossil add</b> <i>file...</i><br>
-    <b>fossil rm</b> <i>file...</i>
-    </blockquote>
-
-    <p>You can also edit files freely.  Once you are ready to commit
-    your changes, type:</p>
-
-    <blockquote>
-    <b>fossil commit</b>
-    </blockquote>
-
-    <p>You will be prompted for check-in comments using whatever editor
-    is specified by your VISUAL or EDITOR environment variable.  If you
-    have GPG installed, you may be prompted for your GPG passphrase so
-    that the check-in can be signed with your GPG signature.  After
-    this your changes will be checked in.</p>
-
-</blockquote><h2>Sharing Changes</h2><blockquote>
-
-    <p>The changes you <b>commit</b> are only on your local repository.
-    To share those changes with other repositories, do:</p>
-
-    <blockquote>
-    <b>fossil push</b> <i>URL</i>
-    </blockquote>
-
-    <p>Where <i>URL</i> is the http: URL of the server repository you
-    want to share your changes with.  If you omit the <i>URL</i> argument,
-    fossil will use whatever server you most recently synced with.</p>
-
-    <p>The <b>push</b> command only sends your changes to others.  To
-    Receive changes from others, use <b>pull</b>.  Or go both ways at
-    once using <b>sync</b>:</p>
-
-    <blockquote>
-    <b>fossil pull</b> <i>URL</i><br>
-    <b>fossil sync</b> <i>URL</i>
-    </blockquote>
-
-    <p>When you pull in changes from others, they go into your repository,
-    not into your checked-out local tree.  To get the changes into your
-    local tree, use <b>update</b>:</p>
-
-    <blockquote>
-    <b>fossil update</b> <i>UUID</i>
-    </blockquote>
-
-    <p>The <i>UUID</i> is some unique abbreviation to the 40-character
-    version ID.  If you omit the <i>UUID</i> fossil moves you to the
-    leaf version of the branch your are currently on.  If your branch
-    has multiple leaves, you get an error - you'll have to specify the
-    leaf you want using a <i>UUID</i> argument.</p>
-
-</blockquote><h2>Branching And Merging</h2><blockquote>
-
-    <p>You can create branches by doing multiple commits off of the
-    same base version.  To merge to branches back together, first
-    <b>update</b> to the leaf of one branch.  Then do a <b>merge</b>
-    of the leaf of the other branch:</p>
-
-    <blockquote>
-    <b>fossil merge</b> <i>UUID</i>
-    </blockquote>
-
-    <p>Test to make sure your merge didn't mess up the code, then
-    <b>commit</b> and possibly also <b>push</b> your changes.   Remember
-    that nobody else can see your changes until you <b>commit</b> and
-    if other are using a different repository you will also need to
-    <b>push</b>.</p>
-
-</blockquote><h2>Setting Up A Server</h2><blockquote>
-
-    <p>The easiest way to set up a server is:</p>
-
-    <blockquote>
-    <b>fossil server</b> <i>repository-filename</i>
-    </blockquote>
-
-    <p>You can omit the <i>repository-filename</i> if you are within
-    a checked-out local tree.  This server uses port 8080 by default
-    but you can specify a different port using the <b>-port</b> command.</p>
-
-    <p>Command-line servers like this are useful when two people want
-    to share a repository on temporary or ad-hoc basis.  For a more
-    permanent installation, you should use either the CGI server or the
-    inetd server.  To use the CGI server, create a CGI script that
-    looks something like this:</p>
-
-    <blockquote><b>
-    #!/usr/local/bin/fossil<br>
-    repository: /home/proj1/repos1.fsl
-    </b></blockquote>
-
-    <p>Adjust the paths in this CGI script to match your installation.
-    Now point clients at the CGI script.  That's all there is to it!</p>
-
-    <p>You can also run fossil off of inetd or xinetd.  For an inetd
-    installation, make an entry in /etc/inetd.conf that looks something
-    like this:</p>
-
-    <blockquote><b>
-    80 stream tcp nowait.1000 root /usr/bin/fossil \<br>
-        /usr/bin/fossil http /home/proj1/repos1.fsl
-    </b></blockquote>
-
-    <p>Adjust the paths to suit your installation, of course.  Notice that
-    fossil runs as root.  This is not required - you can run it as an
-    unprivileged user.  But it is more secure to run fossil as root.
-    When you do run fossil as root, it automatically puts itself in a
-    chroot jail in the same directory as the repository, then drops
-    root privileges prior to reading any information from the request.</p>
-
-</blockquote><h2>More Hints</h2><blockquote>
-
-    <p>Try these commands:</p>
-
-    <blockquote><b>
-    fossil command<br>
-    fossil test-command
-    </b></blockquote>
-
-    <p>Explore and have fun!</p>
-
-
-</blockquote></body></html>
+