File Annotation
Not logged in
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Copyright (c) 2006 D. Richard Hipp
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This program is free software; you can redistribute it and/or
dbda8d6ce9 2007-07-21       drh: ** modify it under the terms of the GNU General Public
dbda8d6ce9 2007-07-21       drh: ** License version 2 as published by the Free Software Foundation.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This program is distributed in the hope that it will be useful,
dbda8d6ce9 2007-07-21       drh: ** but WITHOUT ANY WARRANTY; without even the implied warranty of
dbda8d6ce9 2007-07-21       drh: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
dbda8d6ce9 2007-07-21       drh: ** General Public License for more details.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** You should have received a copy of the GNU General Public
dbda8d6ce9 2007-07-21       drh: ** License along with this library; if not, write to the
dbda8d6ce9 2007-07-21       drh: ** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
dbda8d6ce9 2007-07-21       drh: ** Boston, MA  02111-1307, USA.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Author contact information:
dbda8d6ce9 2007-07-21       drh: **   drh@hwaci.com
dbda8d6ce9 2007-07-21       drh: **   http://www.hwaci.com/drh/
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: *******************************************************************************
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This module codes the main() procedure that runs first when the
dbda8d6ce9 2007-07-21       drh: ** program is invoked.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #include "config.h"
dbda8d6ce9 2007-07-21       drh: #include "main.h"
dbda8d6ce9 2007-07-21       drh: #include <string.h>
dbda8d6ce9 2007-07-21       drh: #include <time.h>
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: #if INTERFACE
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Number of elements in an array
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #define count(X)  (sizeof(X)/sizeof(X[0]))
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Size of a UUID in characters
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #define UUID_SIZE 40
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
55342eb9fb 2008-05-17       drh: ** Maximum number of auxiliary parameters on reports
55342eb9fb 2008-05-17       drh: */
55342eb9fb 2008-05-17       drh: #define MX_AUX  5
55342eb9fb 2008-05-17       drh: 
55342eb9fb 2008-05-17       drh: /*
dbda8d6ce9 2007-07-21       drh: ** All global variables are in this structure.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: struct Global {
dbda8d6ce9 2007-07-21       drh:   int argc; char **argv;  /* Command-line arguments to the program */
dbda8d6ce9 2007-07-21       drh:   int isConst;            /* True if the output is unchanging */
dbda8d6ce9 2007-07-21       drh:   sqlite3 *db;            /* The connection to the databases */
dbda8d6ce9 2007-07-21       drh:   int configOpen;         /* True if the config database is open */
dbda8d6ce9 2007-07-21       drh:   long long int now;      /* Seconds since 1970 */
dbda8d6ce9 2007-07-21       drh:   int repositoryOpen;     /* True if the main repository database is open */
dbda8d6ce9 2007-07-21       drh:   char *zRepositoryName;  /* Name of the repository database */
dbda8d6ce9 2007-07-21       drh:   int localOpen;          /* True if the local database is open */
dbda8d6ce9 2007-07-21       drh:   char *zLocalRoot;       /* The directory holding the  local database */
dbda8d6ce9 2007-07-21       drh:   int minPrefix;          /* Number of digits needed for a distinct UUID */
dbda8d6ce9 2007-07-21       drh:   int fSqlTrace;          /* True if -sqltrace flag is present */
dbda8d6ce9 2007-07-21       drh:   int fSqlPrint;          /* True if -sqlprint flag is present */
dbda8d6ce9 2007-07-21       drh:   int fHttpTrace;         /* Trace outbound HTTP requests */
9ba6e4287b 2008-05-10       drh:   int fNoSync;            /* Do not do an autosync even.  --nosync */
dbda8d6ce9 2007-07-21       drh:   char *zPath;            /* Name of webpage being served */
dbda8d6ce9 2007-07-21       drh:   char *zExtra;           /* Extra path information past the webpage name */
dbda8d6ce9 2007-07-21       drh:   char *zBaseURL;         /* Full text of the URL being served */
50a58adb76 2007-10-10       drh:   char *zTop;             /* Parent directory of zPath */
dbda8d6ce9 2007-07-21       drh:   const char *zContentType;  /* The content type of the input HTTP request */
dbda8d6ce9 2007-07-21       drh:   int iErrPriority;       /* Priority of current error message */
dbda8d6ce9 2007-07-21       drh:   char *zErrMsg;          /* Text of an error message */
dbda8d6ce9 2007-07-21       drh:   Blob cgiIn;             /* Input to an xfer www method */
dbda8d6ce9 2007-07-21       drh:   int cgiPanic;           /* Write error messages to CGI */
dcc48662f8 2008-06-08       drh:   int fullHttpReply;      /* True for full HTTP reply.  False for CGI reply */
fde1d82372 2008-02-13       drh:   Th_Interp *interp;      /* The TH1 interpreter */
e2e016c31f 2008-05-17       drh:   FILE *httpIn;           /* Accept HTTP input from here */
e2e016c31f 2008-05-17       drh:   FILE *httpOut;          /* Send HTTP output here */
243e02bfbd 2008-05-18       drh:   int xlinkClusterOnly;   /* Set when cloning.  Only process clusters */
0b36f02f15 2008-11-01       drh:   int fTimeFormat;        /* 1 for UTC.  2 for localtime.  0 not yet selected */
e2e016c31f 2008-05-17       drh: 
e2e016c31f 2008-05-17       drh:   int *aCommitFile;       /* Array of files to be committed */
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   int urlIsFile;          /* True if a "file:" url */
dbda8d6ce9 2007-07-21       drh:   char *urlName;          /* Hostname for http: or filename for file: */
1dbf332352 2008-05-05       drh:   char *urlHostname;      /* The HOST: parameter on http headers */
dbda8d6ce9 2007-07-21       drh:   int urlPort;            /* TCP port number for http: */
dbda8d6ce9 2007-07-21       drh:   char *urlPath;          /* Pathname for http: */
e621b6dbe3 2007-07-30       drh:   char *urlUser;          /* User id for http: */
e621b6dbe3 2007-07-30       drh:   char *urlPasswd;        /* Password for http: */
dbda8d6ce9 2007-07-21       drh:   char *urlCanonical;     /* Canonical representation of the URL */
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   const char *zLogin;     /* Login name.  "" if not logged in. */
dbda8d6ce9 2007-07-21       drh:   int noPswd;             /* Logged in without password (on 127.0.0.1) */
dbda8d6ce9 2007-07-21       drh:   int userUid;            /* Integer user id */
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /* Information used to populate the RCVFROM table */
dbda8d6ce9 2007-07-21       drh:   int rcvid;              /* The rcvid.  0 if not yet defined. */
dbda8d6ce9 2007-07-21       drh:   char *zIpAddr;          /* The remote IP address */
dbda8d6ce9 2007-07-21       drh:   char *zNonce;           /* The nonce used for login */
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /* permissions used by the server */
22c1ac41d4 2007-08-23       drh:   int okSetup;            /* s: use Setup screens on web interface */
22c1ac41d4 2007-08-23       drh:   int okAdmin;            /* a: administrative permission */
22c1ac41d4 2007-08-23       drh:   int okDelete;           /* d: delete wiki or tickets */
22c1ac41d4 2007-08-23       drh:   int okPassword;         /* p: change password */
22c1ac41d4 2007-08-23       drh:   int okQuery;            /* q: create new reports */
22c1ac41d4 2007-08-23       drh:   int okWrite;            /* i: xfer inbound. checkin */
22c1ac41d4 2007-08-23       drh:   int okRead;             /* o: xfer outbound. checkout */
22c1ac41d4 2007-08-23       drh:   int okHistory;          /* h: access historical information. */
22c1ac41d4 2007-08-23       drh:   int okClone;            /* g: clone */
22c1ac41d4 2007-08-23       drh:   int okRdWiki;           /* j: view wiki via web */
22c1ac41d4 2007-08-23       drh:   int okNewWiki;          /* f: create new wiki via web */
22c1ac41d4 2007-08-23       drh:   int okApndWiki;         /* m: append to wiki via web */
22c1ac41d4 2007-08-23       drh:   int okWrWiki;           /* k: edit wiki via web */
22c1ac41d4 2007-08-23       drh:   int okRdTkt;            /* r: view tickets via web */
22c1ac41d4 2007-08-23       drh:   int okNewTkt;           /* n: create new tickets */
22c1ac41d4 2007-08-23       drh:   int okApndTkt;          /* c: append to tickets via the web */
22c1ac41d4 2007-08-23       drh:   int okWrTkt;            /* w: make changes to tickets via web */
49380d500a 2008-05-28       drh:   int okTktFmt;           /* t: create new ticket report formats */
21326fb6f7 2008-07-19       drh:   int okRdAddr;           /* e: read email addresses or other private data */
fa6e993017 2008-08-12       cle:   int okZip;              /* z: download zipped artifact via /zip URL */
fa6e993017 2008-08-12       cle: 
0be54823ba 2008-10-18       drh:   /* For defense against Cross-site Request Forgery attacks */
0be54823ba 2008-10-18       drh:   char zCsrfToken[12];    /* Value of the anti-CSRF token */
0be54823ba 2008-10-18       drh:   int okCsrf;             /* Anti-CSRF token is present and valid */
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   FILE *fDebug;           /* Write debug information here, if the file exists */
f55c6a1b62 2008-10-24       drh:   int thTrace;            /* True to enable TH1 debugging output */
f55c6a1b62 2008-10-24       drh:   Blob thLog;             /* Text of the TH1 debugging output */
55342eb9fb 2008-05-17       drh: 
55342eb9fb 2008-05-17       drh:   /* Storage for the aux() and/or option() SQL function arguments */
55342eb9fb 2008-05-17       drh:   int nAux;                    /* Number of distinct aux() or option() values */
55342eb9fb 2008-05-17       drh:   const char *azAuxName[MX_AUX]; /* Name of each aux() or option() value */
55342eb9fb 2008-05-17       drh:   char *azAuxParam[MX_AUX];      /* Param of each aux() or option() value */
55342eb9fb 2008-05-17       drh:   const char *azAuxVal[MX_AUX];  /* Value of each aux() or option() value */
55342eb9fb 2008-05-17       drh:   const char **azAuxOpt[MX_AUX]; /* Options of each option() value */
55342eb9fb 2008-05-17       drh:   int anAuxCols[MX_AUX];         /* Number of columns for option() values */
dbda8d6ce9 2007-07-21       drh: };
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Macro for debugging:
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #define CGIDEBUG(X)  if( g.fDebug ) cgi_debug X
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: #endif
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: Global g;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** The table of web pages supported by this application is generated
dbda8d6ce9 2007-07-21       drh: ** automatically by the "mkindex" program and written into a file
dbda8d6ce9 2007-07-21       drh: ** named "page_index.h".  We include that file here to get access
dbda8d6ce9 2007-07-21       drh: ** to the table.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #include "page_index.h"
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Search for a function whose name matches zName.  Write a pointer to
dbda8d6ce9 2007-07-21       drh: ** that function into *pxFunc and return 0.  If no match is found,
dbda8d6ce9 2007-07-21       drh: ** return 1.  If the command is ambiguous return 2;
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** The NameMap structure and the tables we are searching against are
dbda8d6ce9 2007-07-21       drh: ** defined in the page_index.h header file which is automatically
dbda8d6ce9 2007-07-21       drh: ** generated by mkindex.c program.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int name_search(
dbda8d6ce9 2007-07-21       drh:   const char *zName,       /* The name we are looking for */
dbda8d6ce9 2007-07-21       drh:   const NameMap *aMap,     /* Search in this array */
dbda8d6ce9 2007-07-21       drh:   int nMap,                /* Number of slots in aMap[] */
c9fdb846fb 2007-08-18       drh:   int *pIndex              /* OUT: The index in aMap[] of the match */
dbda8d6ce9 2007-07-21       drh: ){
dbda8d6ce9 2007-07-21       drh:   int upr, lwr, cnt, m, i;
dbda8d6ce9 2007-07-21       drh:   int n = strlen(zName);
dbda8d6ce9 2007-07-21       drh:   lwr = 0;
dbda8d6ce9 2007-07-21       drh:   upr = nMap-1;
dbda8d6ce9 2007-07-21       drh:   while( lwr<=upr ){
dbda8d6ce9 2007-07-21       drh:     int mid, c;
dbda8d6ce9 2007-07-21       drh:     mid = (upr+lwr)/2;
dbda8d6ce9 2007-07-21       drh:     c = strcmp(zName, aMap[mid].zName);
dbda8d6ce9 2007-07-21       drh:     if( c==0 ){
c9fdb846fb 2007-08-18       drh:       *pIndex = mid;
dbda8d6ce9 2007-07-21       drh:       return 0;
dbda8d6ce9 2007-07-21       drh:     }else if( c<0 ){
dbda8d6ce9 2007-07-21       drh:       upr = mid - 1;
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       lwr = mid + 1;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   for(m=cnt=0, i=upr-2; i<=upr+3 && i<nMap; i++){
dbda8d6ce9 2007-07-21       drh:     if( i<0 ) continue;
dbda8d6ce9 2007-07-21       drh:     if( strncmp(zName, aMap[i].zName, n)==0 ){
dbda8d6ce9 2007-07-21       drh:       m = i;
dbda8d6ce9 2007-07-21       drh:       cnt++;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( cnt==1 ){
c9fdb846fb 2007-08-18       drh:     *pIndex = m;
dbda8d6ce9 2007-07-21       drh:     return 0;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   return 1+(cnt>1);
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** This procedure runs first.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: int main(int argc, char **argv){
dbda8d6ce9 2007-07-21       drh:   const char *zCmdName;
c9fdb846fb 2007-08-18       drh:   int idx;
dbda8d6ce9 2007-07-21       drh:   int rc;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   g.now = time(0);
dbda8d6ce9 2007-07-21       drh:   g.argc = argc;
dbda8d6ce9 2007-07-21       drh:   g.argv = argv;
dbda8d6ce9 2007-07-21       drh:   if( getenv("GATEWAY_INTERFACE")!=0 ){
dbda8d6ce9 2007-07-21       drh:     zCmdName = "cgi";
dbda8d6ce9 2007-07-21       drh:   }else if( argc<2 ){
dbda8d6ce9 2007-07-21       drh:     fprintf(stderr, "Usage: %s COMMAND ...\n", argv[0]);
dbda8d6ce9 2007-07-21       drh:     exit(1);
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
dbda8d6ce9 2007-07-21       drh:     g.fSqlPrint = find_option("sqlprint", 0, 0)!=0;
dbda8d6ce9 2007-07-21       drh:     g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
dbda8d6ce9 2007-07-21       drh:     g.zLogin = find_option("user", "U", 1);
dbda8d6ce9 2007-07-21       drh:     zCmdName = argv[1];
dbda8d6ce9 2007-07-21       drh:   }
c9fdb846fb 2007-08-18       drh:   rc = name_search(zCmdName, aCommand, count(aCommand), &idx);
dbda8d6ce9 2007-07-21       drh:   if( rc==1 ){
dbda8d6ce9 2007-07-21       drh:     fprintf(stderr,"%s: unknown command: %s\n"
0cd202a86e 2007-08-23       drh:                    "%s: use \"help\" for more information\n",
dbda8d6ce9 2007-07-21       drh:                    argv[0], zCmdName, argv[0]);
dbda8d6ce9 2007-07-21       drh:     return 1;
dbda8d6ce9 2007-07-21       drh:   }else if( rc==2 ){
dbda8d6ce9 2007-07-21       drh:     fprintf(stderr,"%s: ambiguous command prefix: %s\n"
0cd202a86e 2007-08-23       drh:                    "%s: use \"help\" for more information\n",
dbda8d6ce9 2007-07-21       drh:                    argv[0], zCmdName, argv[0]);
dbda8d6ce9 2007-07-21       drh:     return 1;
dbda8d6ce9 2007-07-21       drh:   }
c9fdb846fb 2007-08-18       drh:   aCommand[idx].xFunc();
dbda8d6ce9 2007-07-21       drh:   return 0;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Print an error message, rollback all databases, and quit.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void fossil_panic(const char *zFormat, ...){
dbda8d6ce9 2007-07-21       drh:   char *z;
dbda8d6ce9 2007-07-21       drh:   va_list ap;
dbfe682b92 2008-05-22       drh:   static int once = 1;
dbda8d6ce9 2007-07-21       drh:   va_start(ap, zFormat);
dbda8d6ce9 2007-07-21       drh:   z = vmprintf(zFormat, ap);
dbda8d6ce9 2007-07-21       drh:   va_end(ap);
dbfe682b92 2008-05-22       drh:   if( g.cgiPanic && once ){
dbfe682b92 2008-05-22       drh:     once = 0;
dbfe682b92 2008-05-22       drh:     cgi_printf("<p><font color=\"red\">%h</font></p>", z);
dbda8d6ce9 2007-07-21       drh:     cgi_reply();
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     fprintf(stderr, "%s: %s\n", g.argv[0], z);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   db_force_rollback();
dbda8d6ce9 2007-07-21       drh:   exit(1);
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: void fossil_fatal(const char *zFormat, ...){
dbda8d6ce9 2007-07-21       drh:   char *z;
dbda8d6ce9 2007-07-21       drh:   va_list ap;
dbda8d6ce9 2007-07-21       drh:   va_start(ap, zFormat);
dbda8d6ce9 2007-07-21       drh:   z = vmprintf(zFormat, ap);
dbda8d6ce9 2007-07-21       drh:   va_end(ap);
dbda8d6ce9 2007-07-21       drh:   if( g.cgiPanic ){
dbda8d6ce9 2007-07-21       drh:     g.cgiPanic = 0;
396cc2a4eb 2007-07-30       drh:     cgi_printf("<p><font color=\"red\">%h</font></p>", z);
dbda8d6ce9 2007-07-21       drh:     cgi_reply();
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     fprintf(stderr, "%s: %s\n", g.argv[0], z);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   db_force_rollback();
dbda8d6ce9 2007-07-21       drh:   exit(1);
844718abbf 2008-05-13       drh: }
844718abbf 2008-05-13       drh: void fossil_warning(const char *zFormat, ...){
844718abbf 2008-05-13       drh:   char *z;
844718abbf 2008-05-13       drh:   va_list ap;
844718abbf 2008-05-13       drh:   va_start(ap, zFormat);
844718abbf 2008-05-13       drh:   z = vmprintf(zFormat, ap);
844718abbf 2008-05-13       drh:   va_end(ap);
844718abbf 2008-05-13       drh:   if( g.cgiPanic ){
844718abbf 2008-05-13       drh:     cgi_printf("<p><font color=\"red\">%h</font></p>", z);
844718abbf 2008-05-13       drh:   }else{
844718abbf 2008-05-13       drh:     fprintf(stderr, "%s: %s\n", g.argv[0], z);
844718abbf 2008-05-13       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Print a usage comment and quit
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void usage(const char *zFormat){
dbda8d6ce9 2007-07-21       drh:   fprintf(stderr, "Usage: %s %s %s\n", g.argv[0], g.argv[1], zFormat);
dbda8d6ce9 2007-07-21       drh:   exit(1);
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Remove n elements from g.argv beginning with the i-th element.
dbda8d6ce9 2007-07-21       drh: */
da4f0c2638 2008-02-01       aku: void remove_from_argv(int i, int n){
dbda8d6ce9 2007-07-21       drh:   int j;
dbda8d6ce9 2007-07-21       drh:   for(j=i+n; j<g.argc; i++, j++){
dbda8d6ce9 2007-07-21       drh:     g.argv[i] = g.argv[j];
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   g.argc = i;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Look for a command-line option.  If present, return a pointer.
dbda8d6ce9 2007-07-21       drh: ** Return NULL if missing.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** hasArg==0 means the option is a flag.  It is either present or not.
dbda8d6ce9 2007-07-21       drh: ** hasArg==1 means the option has an argument.  Return a pointer to the
dbda8d6ce9 2007-07-21       drh: ** argument.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: const char *find_option(const char *zLong, const char *zShort, int hasArg){
dbda8d6ce9 2007-07-21       drh:   int i;
be758137b0 2008-05-25       drh:   int nLong;
dbda8d6ce9 2007-07-21       drh:   const char *zReturn = 0;
dbda8d6ce9 2007-07-21       drh:   assert( hasArg==0 || hasArg==1 );
be758137b0 2008-05-25       drh:   nLong = strlen(zLong);
dbda8d6ce9 2007-07-21       drh:   for(i=2; i<g.argc; i++){
dbda8d6ce9 2007-07-21       drh:     char *z = g.argv[i];
dbda8d6ce9 2007-07-21       drh:     if( z[0]!='-' ) continue;
dbda8d6ce9 2007-07-21       drh:     z++;
dbda8d6ce9 2007-07-21       drh:     if( z[0]=='-' ){
dbda8d6ce9 2007-07-21       drh:       if( z[1]==0 ){
dbda8d6ce9 2007-07-21       drh:         remove_from_argv(i, 1);
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       z++;
dbda8d6ce9 2007-07-21       drh:     }
be758137b0 2008-05-25       drh:     if( strncmp(z,zLong,nLong)==0 ){
be758137b0 2008-05-25       drh:       if( hasArg && z[nLong]=='=' ){
be758137b0 2008-05-25       drh:         zReturn = &z[nLong+1];
be758137b0 2008-05-25       drh:         remove_from_argv(i, 1);
be758137b0 2008-05-25       drh:         break;
be758137b0 2008-05-25       drh:       }else if( z[nLong]==0 ){
be758137b0 2008-05-25       drh:         zReturn = g.argv[i+hasArg];
be758137b0 2008-05-25       drh:         remove_from_argv(i, 1+hasArg);
be758137b0 2008-05-25       drh:         break;
be758137b0 2008-05-25       drh:       }
be758137b0 2008-05-25       drh:     }else if( zShort!=0 && strcmp(z,zShort)==0 ){
dbda8d6ce9 2007-07-21       drh:       zReturn = g.argv[i+hasArg];
dbda8d6ce9 2007-07-21       drh:       remove_from_argv(i, 1+hasArg);
dbda8d6ce9 2007-07-21       drh:       break;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   return zReturn;
6aff11f03f 2007-08-03       drh: }
6aff11f03f 2007-08-03       drh: 
6aff11f03f 2007-08-03       drh: /*
da4f0c2638 2008-02-01       aku: ** Verify that there are no unprocessed command-line options.  If
6aff11f03f 2007-08-03       drh: ** Any remaining command-line argument begins with "-" print
6aff11f03f 2007-08-03       drh: ** an error message and quit.
6aff11f03f 2007-08-03       drh: */
6aff11f03f 2007-08-03       drh: void verify_all_options(void){
6aff11f03f 2007-08-03       drh:   int i;
6aff11f03f 2007-08-03       drh:   for(i=1; i<g.argc; i++){
6aff11f03f 2007-08-03       drh:     if( g.argv[i][0]=='-' ){
6aff11f03f 2007-08-03       drh:       fossil_fatal("unrecognized command-line option: %s", g.argv[i]);
6aff11f03f 2007-08-03       drh:     }
6aff11f03f 2007-08-03       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Print a list of words in multiple columns.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void multi_column_list(const char **azWord, int nWord){
dbda8d6ce9 2007-07-21       drh:   int i, j, len;
dbda8d6ce9 2007-07-21       drh:   int mxLen = 0;
dbda8d6ce9 2007-07-21       drh:   int nCol;
dbda8d6ce9 2007-07-21       drh:   int nRow;
dbda8d6ce9 2007-07-21       drh:   for(i=0; i<nWord; i++){
dbda8d6ce9 2007-07-21       drh:     len = strlen(azWord[i]);
dbda8d6ce9 2007-07-21       drh:     if( len>mxLen ) mxLen = len;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   nCol = 80/(mxLen+2);
dbda8d6ce9 2007-07-21       drh:   if( nCol==0 ) nCol = 1;
dbda8d6ce9 2007-07-21       drh:   nRow = (nWord + nCol - 1)/nCol;
dbda8d6ce9 2007-07-21       drh:   for(i=0; i<nRow; i++){
dbda8d6ce9 2007-07-21       drh:     const char *zSpacer = "";
dbda8d6ce9 2007-07-21       drh:     for(j=i; j<nWord; j+=nRow){
dbda8d6ce9 2007-07-21       drh:       printf("%s%-*s", zSpacer, mxLen, azWord[j]);
dbda8d6ce9 2007-07-21       drh:       zSpacer = "  ";
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     printf("\n");
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
b2e55c0d4d 2007-09-01       drh: ** COM MAND: commands
c9fdb846fb 2007-08-18       drh: **
c9fdb846fb 2007-08-18       drh: ** Usage: %fossil commands
c9fdb846fb 2007-08-18       drh: ** List all supported commands.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void cmd_cmd_list(void){
dbda8d6ce9 2007-07-21       drh:   int i, nCmd;
dbda8d6ce9 2007-07-21       drh:   const char *aCmd[count(aCommand)];
dbda8d6ce9 2007-07-21       drh:   for(i=nCmd=0; i<count(aCommand); i++){
dbda8d6ce9 2007-07-21       drh:     if( strncmp(aCommand[i].zName,"test",4)==0 ) continue;
c9fdb846fb 2007-08-18       drh:     /* if( strcmp(aCommand[i].zName, g.argv[1])==0 ) continue; */
dbda8d6ce9 2007-07-21       drh:     aCmd[nCmd++] = aCommand[i].zName;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   multi_column_list(aCmd, nCmd);
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** COMMAND: test-commands
dbda8d6ce9 2007-07-21       drh: **
c9fdb846fb 2007-08-18       drh: ** Usage: %fossil test-commands
6b85fd173e 2008-05-10       drh: **
c9fdb846fb 2007-08-18       drh: ** List all commands used for testing and debugging.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void cmd_test_cmd_list(void){
dbda8d6ce9 2007-07-21       drh:   int i, nCmd;
dbda8d6ce9 2007-07-21       drh:   const char *aCmd[count(aCommand)];
dbda8d6ce9 2007-07-21       drh:   for(i=nCmd=0; i<count(aCommand); i++){
dbda8d6ce9 2007-07-21       drh:     if( strncmp(aCommand[i].zName,"test",4)!=0 ) continue;
c9fdb846fb 2007-08-18       drh:     /* if( strcmp(aCommand[i].zName, g.argv[1])==0 ) continue; */
dbda8d6ce9 2007-07-21       drh:     aCmd[nCmd++] = aCommand[i].zName;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   multi_column_list(aCmd, nCmd);
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
a1f727be9d 2008-10-18       drh: ** COMMAND: version
a1f727be9d 2008-10-18       drh: **
a1f727be9d 2008-10-18       drh: ** Usage:  %fossil version
a1f727be9d 2008-10-18       drh: **
a1f727be9d 2008-10-18       drh: ** Print the source code version number for the fossil executable.
a1f727be9d 2008-10-18       drh: */
a1f727be9d 2008-10-18       drh: void version_cmd(void){
d5cd3251fa 2008-10-31       drh:   printf("This is fossil version " MANIFEST_VERSION " " MANIFEST_DATE " UTC\n");
a1f727be9d 2008-10-18       drh: }
a1f727be9d 2008-10-18       drh: 
a1f727be9d 2008-10-18       drh: 
a1f727be9d 2008-10-18       drh: /*
c9fdb846fb 2007-08-18       drh: ** COMMAND: help
c9fdb846fb 2007-08-18       drh: **
c9fdb846fb 2007-08-18       drh: ** Usage: %fossil help COMMAND
6b85fd173e 2008-05-10       drh: **
c9fdb846fb 2007-08-18       drh: ** Display information on how to use COMMAND
c9fdb846fb 2007-08-18       drh: */
c9fdb846fb 2007-08-18       drh: void help_cmd(void){
c9fdb846fb 2007-08-18       drh:   int rc, idx;
c9fdb846fb 2007-08-18       drh:   const char *z;
c9fdb846fb 2007-08-18       drh:   if( g.argc!=3 ){
6607844a01 2007-08-18       drh:     printf("Usage: %s help COMMAND.\nAvailable COMMANDs:\n", g.argv[0]);
c9fdb846fb 2007-08-18       drh:     cmd_cmd_list();
a1f727be9d 2008-10-18       drh:     version_cmd();
c9fdb846fb 2007-08-18       drh:     return;
c9fdb846fb 2007-08-18       drh:   }
c9fdb846fb 2007-08-18       drh:   rc = name_search(g.argv[2], aCommand, count(aCommand), &idx);
c9fdb846fb 2007-08-18       drh:   if( rc==1 ){
c9fdb846fb 2007-08-18       drh:     fossil_fatal("unknown command: %s", g.argv[2]);
c9fdb846fb 2007-08-18       drh:   }else if( rc==2 ){
c9fdb846fb 2007-08-18       drh:     fossil_fatal("ambiguous command prefix: %s", g.argv[2]);
c9fdb846fb 2007-08-18       drh:   }
c9fdb846fb 2007-08-18       drh:   z = aCmdHelp[idx];
c9fdb846fb 2007-08-18       drh:   if( z==0 ){
c9fdb846fb 2007-08-18       drh:     fossil_fatal("no help available for the %s command",
c9fdb846fb 2007-08-18       drh:        aCommand[idx].zName);
c9fdb846fb 2007-08-18       drh:   }
c9fdb846fb 2007-08-18       drh:   while( *z ){
c9fdb846fb 2007-08-18       drh:     if( *z=='%' && strncmp(z, "%fossil", 7)==0 ){
c9fdb846fb 2007-08-18       drh:       printf("%s", g.argv[0]);
c9fdb846fb 2007-08-18       drh:       z += 7;
c9fdb846fb 2007-08-18       drh:     }else{
c9fdb846fb 2007-08-18       drh:       putchar(*z);
c9fdb846fb 2007-08-18       drh:       z++;
c9fdb846fb 2007-08-18       drh:     }
c9fdb846fb 2007-08-18       drh:   }
c9fdb846fb 2007-08-18       drh:   putchar('\n');
c9fdb846fb 2007-08-18       drh: }
c9fdb846fb 2007-08-18       drh: 
c9fdb846fb 2007-08-18       drh: /*
50a58adb76 2007-10-10       drh: ** Set the g.zBaseURL value to the full URL for the toplevel of
50a58adb76 2007-10-10       drh: ** the fossil tree.  Set g.zHomeURL to g.zBaseURL without the
50a58adb76 2007-10-10       drh: ** leading "http://" and the host and port.
dbda8d6ce9 2007-07-21       drh: */
50a58adb76 2007-10-10       drh: void set_base_url(void){
dbda8d6ce9 2007-07-21       drh:   int i;
dbda8d6ce9 2007-07-21       drh:   const char *zHost = PD("HTTP_HOST","");
dbda8d6ce9 2007-07-21       drh:   const char *zMode = PD("HTTPS","off");
c23469468b 2008-05-13       drh:   const char *zCur = PD("SCRIPT_NAME","/");
c23469468b 2008-05-13       drh: 
c23469468b 2008-05-13       drh:   i = strlen(zCur);
c23469468b 2008-05-13       drh:   while( i>0 && zCur[i-1]=='/' ) i--;
50a58adb76 2007-10-10       drh:   if( strcmp(zMode,"on")==0 ){
50a58adb76 2007-10-10       drh:     g.zBaseURL = mprintf("https://%s%.*s", zHost, i, zCur);
1ce716b2ec 2007-10-11       drh:     g.zTop = &g.zBaseURL[8+strlen(zHost)];
50a58adb76 2007-10-10       drh:   }else{
50a58adb76 2007-10-10       drh:     g.zBaseURL = mprintf("http://%s%.*s", zHost, i, zCur);
1ce716b2ec 2007-10-11       drh:     g.zTop = &g.zBaseURL[7+strlen(zHost)];
1ce716b2ec 2007-10-11       drh:   }
1ce716b2ec 2007-10-11       drh: }
dbda8d6ce9 2007-07-21       drh: 
1ce716b2ec 2007-10-11       drh: /*
68c24b1857 2008-05-16       drh: ** Send an HTTP redirect back to the designated Index Page.
68c24b1857 2008-05-16       drh: */
68c24b1857 2008-05-16       drh: void fossil_redirect_home(void){
68c24b1857 2008-05-16       drh:   cgi_redirectf("%s%s", g.zBaseURL, db_get("index-page", "/index"));
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Preconditions:
dbda8d6ce9 2007-07-21       drh: **
677aa71bca 2007-10-12       drh: **    * Environment variables are set up according to the CGI standard.
dbda8d6ce9 2007-07-21       drh: **    * The respository database has been located and opened.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Process the webpage specified by the PATH_INFO or REQUEST_URI
dbda8d6ce9 2007-07-21       drh: ** environment variable.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void process_one_web_page(void){
dbda8d6ce9 2007-07-21       drh:   const char *zPathInfo;
da4f0c2638 2008-02-01       aku:   char *zPath = NULL;
c9fdb846fb 2007-08-18       drh:   int idx;
c7c81df138 2008-05-16       drh:   int i;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /* Find the page that the user has requested, construct and deliver that
dbda8d6ce9 2007-07-21       drh:   ** page.
dbda8d6ce9 2007-07-21       drh:   */
c7c81df138 2008-05-16       drh:   set_base_url();
dbda8d6ce9 2007-07-21       drh:   zPathInfo = P("PATH_INFO");
c7c81df138 2008-05-16       drh:   if( zPathInfo==0 || zPathInfo[0]==0
c7c81df138 2008-05-16       drh:       || (zPathInfo[0]=='/' && zPathInfo[1]==0) ){
68c24b1857 2008-05-16       drh:     fossil_redirect_home();
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     zPath = mprintf("%s", zPathInfo);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /* Remove the leading "/" at the beginning of the path.
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh:   g.zPath = &zPath[1];
dbda8d6ce9 2007-07-21       drh:   for(i=1; zPath[i] && zPath[i]!='/'; i++){}
dbda8d6ce9 2007-07-21       drh:   if( zPath[i]=='/' ){
dbda8d6ce9 2007-07-21       drh:     zPath[i] = 0;
dbda8d6ce9 2007-07-21       drh:     g.zExtra = &zPath[i+1];
9f89a8e68e 2007-10-10       drh:   }else{
9f89a8e68e 2007-10-10       drh:     g.zExtra = 0;
9f89a8e68e 2007-10-10       drh:   }
9f89a8e68e 2007-10-10       drh:   if( g.zExtra ){
dbda8d6ce9 2007-07-21       drh:     /* CGI parameters get this treatment elsewhere, but places like getfile
dbda8d6ce9 2007-07-21       drh:     ** will use g.zExtra directly.
dbda8d6ce9 2007-07-21       drh:     */
dbda8d6ce9 2007-07-21       drh:     dehttpize(g.zExtra);
677aa71bca 2007-10-12       drh:     cgi_set_parameter_nocopy("name", g.zExtra);
9f89a8e68e 2007-10-10       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /* Prevent robots from indexing this site.
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh:   if( strcmp(g.zPath, "robots.txt")==0 ){
dbda8d6ce9 2007-07-21       drh:     cgi_set_content_type("text/plain");
dbda8d6ce9 2007-07-21       drh:     @ User-agent: *
dbda8d6ce9 2007-07-21       drh:     @ Disallow: /
dbda8d6ce9 2007-07-21       drh:     cgi_reply();
dbda8d6ce9 2007-07-21       drh:     exit(0);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /* Locate the method specified by the path and execute the function
dbda8d6ce9 2007-07-21       drh:   ** that implements that method.
dbda8d6ce9 2007-07-21       drh:   */
c9fdb846fb 2007-08-18       drh:   if( name_search(g.zPath, aWebpage, count(aWebpage), &idx) &&
c9fdb846fb 2007-08-18       drh:       name_search("not_found", aWebpage, count(aWebpage), &idx) ){
dbda8d6ce9 2007-07-21       drh:     cgi_set_status(404,"Not Found");
dbda8d6ce9 2007-07-21       drh:     @ <h1>Not Found</h1>
dbda8d6ce9 2007-07-21       drh:     @ <p>Page not found: %h(g.zPath)</p>
dbda8d6ce9 2007-07-21       drh:   }else{
c9fdb846fb 2007-08-18       drh:     aWebpage[idx].xFunc();
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /* Return the result.
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh:   cgi_reply();
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** COMMAND: cgi
dbda8d6ce9 2007-07-21       drh: **
6607844a01 2007-08-18       drh: ** Usage: %fossil ?cgi? SCRIPT
6607844a01 2007-08-18       drh: **
6607844a01 2007-08-18       drh: ** The SCRIPT argument is the name of a file that is the CGI script
6607844a01 2007-08-18       drh: ** that is being run.  The command name, "cgi", may be omitted if
6607844a01 2007-08-18       drh: ** the GATEWAY_INTERFACE environment variable is set to "CGI" (which
6607844a01 2007-08-18       drh: ** should always be the case for CGI scripts run by a webserver.)  The
6607844a01 2007-08-18       drh: ** SCRIPT file should look something like this:
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **      #!/usr/bin/fossil
dbda8d6ce9 2007-07-21       drh: **      repository: /home/somebody/project.db
dbda8d6ce9 2007-07-21       drh: **
6607844a01 2007-08-18       drh: ** The second line defines the name of the repository.  After locating
6607844a01 2007-08-18       drh: ** the repository, fossil will generate a webpage on stdout based on
6607844a01 2007-08-18       drh: ** the values of standard CGI environment variables.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void cmd_cgi(void){
dbda8d6ce9 2007-07-21       drh:   const char *zFile;
dbda8d6ce9 2007-07-21       drh:   Blob config, line, key, value;
dbda8d6ce9 2007-07-21       drh:   if( g.argc==3 && strcmp(g.argv[1],"cgi")==0 ){
dbda8d6ce9 2007-07-21       drh:     zFile = g.argv[2];
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     zFile = g.argv[1];
dbda8d6ce9 2007-07-21       drh:   }
b4f9d90ca3 2008-05-22       drh:   g.httpOut = stdout;
b4f9d90ca3 2008-05-22       drh:   g.httpIn = stdin;
396cc2a4eb 2007-07-30       drh:   g.cgiPanic = 1;
dbda8d6ce9 2007-07-21       drh:   blob_read_from_file(&config, zFile);
dbda8d6ce9 2007-07-21       drh:   while( blob_line(&config, &line) ){
dbda8d6ce9 2007-07-21       drh:     if( !blob_token(&line, &key) ) continue;
dbda8d6ce9 2007-07-21       drh:     if( blob_buffer(&key)[0]=='#' ) continue;
dbda8d6ce9 2007-07-21       drh:     if( blob_eq(&key, "debug:") && blob_token(&line, &value) ){
dbda8d6ce9 2007-07-21       drh:       g.fDebug = fopen(blob_str(&value), "a");
dbda8d6ce9 2007-07-21       drh:       blob_reset(&value);
dbda8d6ce9 2007-07-21       drh:       continue;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( blob_eq(&key, "HOME:") && blob_token(&line, &value) ){
dbda8d6ce9 2007-07-21       drh:       cgi_setenv("HOME", blob_str(&value));
dbda8d6ce9 2007-07-21       drh:       blob_reset(&value);
dbda8d6ce9 2007-07-21       drh:       continue;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( blob_eq(&key, "repository:") && blob_token(&line, &value) ){
dbda8d6ce9 2007-07-21       drh:       db_open_repository(blob_str(&value));
dbda8d6ce9 2007-07-21       drh:       blob_reset(&value);
dbda8d6ce9 2007-07-21       drh:       blob_reset(&config);
dbda8d6ce9 2007-07-21       drh:       break;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( g.db==0 ){
dbda8d6ce9 2007-07-21       drh:     cgi_panic("Unable to find or open the project repository");
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   cgi_init();
dbda8d6ce9 2007-07-21       drh:   process_one_web_page();
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
e2e016c31f 2008-05-17       drh: ** undocumented format:
e2e016c31f 2008-05-17       drh: **
e2e016c31f 2008-05-17       drh: **        fossil http REPOSITORY INFILE OUTFILE IPADDR
e2e016c31f 2008-05-17       drh: **
e2e016c31f 2008-05-17       drh: ** The argv==6 form is used by the win32 server only.
e2e016c31f 2008-05-17       drh: **
dbda8d6ce9 2007-07-21       drh: ** COMMAND: http
dbda8d6ce9 2007-07-21       drh: **
6607844a01 2007-08-18       drh: ** Usage: %fossil http REPOSITORY
dbda8d6ce9 2007-07-21       drh: **
6607844a01 2007-08-18       drh: ** Handle a single HTTP request appearing on stdin.  The resulting webpage
6607844a01 2007-08-18       drh: ** is delivered on stdout.  This method is used to launch an HTTP request
6607844a01 2007-08-18       drh: ** handler from inetd, for example.  The argument is the name of the
6607844a01 2007-08-18       drh: ** repository.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void cmd_http(void){
dcc48662f8 2008-06-08       drh:   const char *zIpAddr;
e2e016c31f 2008-05-17       drh:   if( g.argc!=2 && g.argc!=3 && g.argc!=6 ){
dbda8d6ce9 2007-07-21       drh:     cgi_panic("no repository specified");
dbda8d6ce9 2007-07-21       drh:   }
f5e8b1d736 2007-08-04       drh:   g.cgiPanic = 1;
dcc48662f8 2008-06-08       drh:   g.fullHttpReply = 1;
dcc48662f8 2008-06-08       drh:   if( g.argc==6 ){
dcc48662f8 2008-06-08       drh:     g.httpIn = fopen(g.argv[3], "rb");
dcc48662f8 2008-06-08       drh:     g.httpOut = fopen(g.argv[4], "wb");
dcc48662f8 2008-06-08       drh:     zIpAddr = g.argv[5];
dcc48662f8 2008-06-08       drh:   }else{
dcc48662f8 2008-06-08       drh:     g.httpIn = stdin;
dcc48662f8 2008-06-08       drh:     g.httpOut = stdout;
dcc48662f8 2008-06-08       drh:     zIpAddr = 0;
dcc48662f8 2008-06-08       drh:   }
e2e016c31f 2008-05-17       drh:   if( g.argc>=3 ){
dbda8d6ce9 2007-07-21       drh:     db_open_repository(g.argv[2]);
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     db_must_be_within_tree();
dbda8d6ce9 2007-07-21       drh:   }
e2e016c31f 2008-05-17       drh:   cgi_handle_http_request(zIpAddr);
dbda8d6ce9 2007-07-21       drh:   process_one_web_page();
f5e8b1d736 2007-08-04       drh: }
f5e8b1d736 2007-08-04       drh: 
f5e8b1d736 2007-08-04       drh: /*
1e9c0e287e 2007-10-03       drh: ** COMMAND: test-http
1e9c0e287e 2007-10-03       drh: ** Works like the http command but gives setup permission to all users.
1e9c0e287e 2007-10-03       drh: */
1e9c0e287e 2007-10-03       drh: void cmd_test_http(void){
1e9c0e287e 2007-10-03       drh:   login_set_capabilities("s");
1e9c0e287e 2007-10-03       drh:   cmd_http();
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** COMMAND: server
dfb68976be 2008-05-17       drh: ** COMMAND: ui
6607844a01 2007-08-18       drh: **
6607844a01 2007-08-18       drh: ** Usage: %fossil server ?-P|--port TCPPORT? ?REPOSITORY?
dfb68976be 2008-05-17       drh: **    Or: %fossil ui ?-P|--port TCPPORT? ?REPOSITORY?
dbda8d6ce9 2007-07-21       drh: **
6607844a01 2007-08-18       drh: ** Open a socket and begin listening and responding to HTTP requests on
6607844a01 2007-08-18       drh: ** TCP port 8080, or on any other TCP port defined by the -P or
6607844a01 2007-08-18       drh: ** --port option.  The optional argument is the name of the repository.
6607844a01 2007-08-18       drh: ** The repository argument may be omitted if the working directory is
6607844a01 2007-08-18       drh: ** within an open checkout.
dbda8d6ce9 2007-07-21       drh: **
dfb68976be 2008-05-17       drh: ** The "ui" command automatically starts a web browser after initializing
dfb68976be 2008-05-17       drh: ** the web server.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void cmd_webserver(void){
dbda8d6ce9 2007-07-21       drh:   int iPort;
dbda8d6ce9 2007-07-21       drh:   const char *zPort;
dfb68976be 2008-05-17       drh:   char *zBrowser;
dfb68976be 2008-05-17       drh:   char *zBrowserCmd = 0;
dbda8d6ce9 2007-07-21       drh: 
31e94c0a04 2008-10-25       drh:   g.thTrace = find_option("th-trace", 0, 0)!=0;
f55c6a1b62 2008-10-24       drh:   if( g.thTrace ){
f55c6a1b62 2008-10-24       drh:     blob_zero(&g.thLog);
f5e8b1d736 2007-08-04       drh:   }
dbda8d6ce9 2007-07-21       drh:   zPort = find_option("port", "P", 1);
f5e8b1d736 2007-08-04       drh:   if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?");
f5e8b1d736 2007-08-04       drh:   if( g.argc==2 ){
f5e8b1d736 2007-08-04       drh:     db_must_be_within_tree();
dcc48662f8 2008-06-08       drh:   }else{
dcc48662f8 2008-06-08       drh:     db_open_repository(g.argv[2]);
dcc48662f8 2008-06-08       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( zPort ){
dbda8d6ce9 2007-07-21       drh:     iPort = atoi(zPort);
dbda8d6ce9 2007-07-21       drh:   }else{
02f09cdd6c 2008-11-09       drh:     iPort = db_get_int("http-port", 8080);
e2e016c31f 2008-05-17       drh:   }
e2e016c31f 2008-05-17       drh: #ifndef __MINGW32__
e2e016c31f 2008-05-17       drh:   /* Unix implementation */
dfb68976be 2008-05-17       drh:   if( g.argv[1][0]=='u' ){
dfb68976be 2008-05-17       drh: #if !defined(__DARWIN__) && !defined(__APPLE__)
dfb68976be 2008-05-17       drh:     zBrowser = db_get("web-browser", "firefox");
dfb68976be 2008-05-17       drh: #else
dfb68976be 2008-05-17       drh:     zBrowser = db_get("web-browser", "open");
dfb68976be 2008-05-17       drh: #endif
dfb68976be 2008-05-17       drh:     zBrowserCmd = mprintf("%s http://localhost:%d/ &", zBrowser, iPort);
dfb68976be 2008-05-17       drh:   }
3f5ef308fe 2008-10-27       drh:   db_close();
dfb68976be 2008-05-17       drh:   if( cgi_http_server(iPort, zBrowserCmd) ){
e2e016c31f 2008-05-17       drh:     fossil_fatal("unable to listen on TCP socket %d", iPort);
dbda8d6ce9 2007-07-21       drh:   }
e2e016c31f 2008-05-17       drh:   g.httpIn = stdin;
e2e016c31f 2008-05-17       drh:   g.httpOut = stdout;
dbda8d6ce9 2007-07-21       drh:   if( g.fHttpTrace ){
dbda8d6ce9 2007-07-21       drh:     fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
dbda8d6ce9 2007-07-21       drh:   }
f5e8b1d736 2007-08-04       drh:   g.cgiPanic = 1;
dbda8d6ce9 2007-07-21       drh:   if( g.argc==2 ){
dbda8d6ce9 2007-07-21       drh:     db_must_be_within_tree();
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     db_open_repository(g.argv[2]);
dbda8d6ce9 2007-07-21       drh:   }
e2e016c31f 2008-05-17       drh:   cgi_handle_http_request(0);
dbda8d6ce9 2007-07-21       drh:   process_one_web_page();
e2e016c31f 2008-05-17       drh: #else
e2e016c31f 2008-05-17       drh:   /* Win32 implementation */
dfb68976be 2008-05-17       drh:   if( g.argv[1][0]=='u' ){
dfb68976be 2008-05-17       drh:     zBrowser = db_get("web-browser", "start");
dfb68976be 2008-05-17       drh:     zBrowserCmd = mprintf("%s http://127.0.0.1:%d/", zBrowser, iPort);
dfb68976be 2008-05-17       drh:   }
3f5ef308fe 2008-10-27       drh:   db_close();
dfb68976be 2008-05-17       drh:   win32_http_server(iPort, zBrowserCmd);
e2e016c31f 2008-05-17       drh: #endif
dbda8d6ce9 2007-07-21       drh: }