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
- branch=trunk inherited from [a28c83647d]
- closed added by [3eda2d41db] on 2009-01-29 23:05:42
- sym-trunk inherited from [a28c83647d]
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 ID</th> - @ <th> Capabilities </th> - @ <th>Contact 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 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> </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> +