Fossil SCM
Merge updates from trunk.
Commit
9abccbaa50c81115e6e18019cfba7902e598b9c855924cbd2d8763eca50c06d0
Parent
74b7f07c4952903…
8 files changed
+78
-9
+2
-1
+39
-1
+16
-11
+9
-1
+1
-19
+5
+1
-1
+78
-9
| --- src/cgi.c | ||
| +++ src/cgi.c | ||
| @@ -350,11 +350,11 @@ | ||
| 350 | 350 | fwrite(blob_buffer(&cgiContent[i]), 1, size, g.httpOut); |
| 351 | 351 | } |
| 352 | 352 | } |
| 353 | 353 | } |
| 354 | 354 | fflush(g.httpOut); |
| 355 | - CGIDEBUG(("DONE\n")); | |
| 355 | + CGIDEBUG(("-------- END cgi ---------\n")); | |
| 356 | 356 | |
| 357 | 357 | /* After the webpage has been sent, do any useful background |
| 358 | 358 | ** processing. |
| 359 | 359 | */ |
| 360 | 360 | g.cgiOutput = 2; |
| @@ -1167,10 +1167,14 @@ | ||
| 1167 | 1167 | } |
| 1168 | 1168 | j++; |
| 1169 | 1169 | } |
| 1170 | 1170 | nUsedQP = j; |
| 1171 | 1171 | } |
| 1172 | + | |
| 1173 | + /* Invoking with a NULL zName is just a way to cause the parameters | |
| 1174 | + ** to be sorted. So go ahead and bail out in that case */ | |
| 1175 | + if( zName==0 || zName[0]==0 ) return 0; | |
| 1172 | 1176 | |
| 1173 | 1177 | /* Do a binary search for a matching query parameter */ |
| 1174 | 1178 | lo = 0; |
| 1175 | 1179 | hi = nUsedQP-1; |
| 1176 | 1180 | while( lo<=hi ){ |
| @@ -1189,11 +1193,11 @@ | ||
| 1189 | 1193 | /* If no match is found and the name begins with an upper-case |
| 1190 | 1194 | ** letter, then check to see if there is an environment variable |
| 1191 | 1195 | ** with the given name. Handle environment variables with empty values |
| 1192 | 1196 | ** the same as non-existent environment variables. |
| 1193 | 1197 | */ |
| 1194 | - if( zName && fossil_isupper(zName[0]) ){ | |
| 1198 | + if( fossil_isupper(zName[0]) ){ | |
| 1195 | 1199 | const char *zValue = fossil_getenv(zName); |
| 1196 | 1200 | if( zValue && zValue[0] ){ |
| 1197 | 1201 | cgi_set_parameter_nocopy(zName, zValue, 0); |
| 1198 | 1202 | CGIDEBUG(("env-match [%s] = [%s]\n", zName, zValue)); |
| 1199 | 1203 | return zValue; |
| @@ -1314,28 +1318,73 @@ | ||
| 1314 | 1318 | va_end(ap); |
| 1315 | 1319 | return 1; |
| 1316 | 1320 | } |
| 1317 | 1321 | |
| 1318 | 1322 | /* |
| 1319 | -** Print all query parameters on standard output. Format the | |
| 1320 | -** parameters as HTML. This is used for testing and debugging. | |
| 1323 | +** Load all relevant environment variables into the parameter buffer. | |
| 1324 | +** Invoke this routine prior to calling cgi_print_all() in order to see | |
| 1325 | +** the full CGI environment. This routine intended for debugging purposes | |
| 1326 | +** only. | |
| 1327 | +*/ | |
| 1328 | +void cgi_load_environment(void){ | |
| 1329 | + /* The following is a list of environment variables that Fossil considers | |
| 1330 | + ** to be "relevant". */ | |
| 1331 | + static const char *const azCgiVars[] = { | |
| 1332 | + "COMSPEC", "DOCUMENT_ROOT", "GATEWAY_INTERFACE", "SCGI", | |
| 1333 | + "HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET", "HTTP_ACCEPT_ENCODING", | |
| 1334 | + "HTTP_ACCEPT_LANGUAGE", "HTTP_AUTHENICATION", | |
| 1335 | + "HTTP_CONNECTION", "HTTP_HOST", | |
| 1336 | + "HTTP_IF_NONE_MATCH", "HTTP_IF_MODIFIED_SINCE", | |
| 1337 | + "HTTP_USER_AGENT", "HTTP_REFERER", "PATH_INFO", "PATH_TRANSLATED", | |
| 1338 | + "QUERY_STRING", "REMOTE_ADDR", "REMOTE_PORT", | |
| 1339 | + "REMOTE_USER", "REQUEST_METHOD", | |
| 1340 | + "REQUEST_URI", "SCRIPT_FILENAME", "SCRIPT_NAME", "SERVER_PROTOCOL", | |
| 1341 | + "HOME", "FOSSIL_HOME", "USERNAME", "USER", "FOSSIL_USER", | |
| 1342 | + "SQLITE_TMPDIR", "TMPDIR", | |
| 1343 | + "TEMP", "TMP", "FOSSIL_VFS", | |
| 1344 | + "FOSSIL_FORCE_TICKET_MODERATION", "FOSSIL_FORCE_WIKI_MODERATION", | |
| 1345 | + "FOSSIL_TCL_PATH", "TH1_DELETE_INTERP", "TH1_ENABLE_DOCS", | |
| 1346 | + "TH1_ENABLE_HOOKS", "TH1_ENABLE_TCL", "REMOTE_HOST", | |
| 1347 | + }; | |
| 1348 | + int i; | |
| 1349 | + for(i=0; i<count(azCgiVars); i++) (void)P(azCgiVars[i]); | |
| 1350 | +} | |
| 1351 | + | |
| 1352 | +/* | |
| 1353 | +** Print all query parameters on standard output. | |
| 1354 | +** This is used for testing and debugging. | |
| 1321 | 1355 | ** |
| 1322 | 1356 | ** Omit the values of the cookies unless showAll is true. |
| 1357 | +** | |
| 1358 | +** The eDest parameter determines where the output is shown: | |
| 1359 | +** | |
| 1360 | +** eDest==0: Rendering as HTML into the CGI reply | |
| 1361 | +** eDest==1: Written to stderr | |
| 1362 | +** eDest==2: Written to cgi_debug | |
| 1323 | 1363 | */ |
| 1324 | -void cgi_print_all(int showAll, int onConsole){ | |
| 1364 | +void cgi_print_all(int showAll, unsigned int eDest){ | |
| 1325 | 1365 | int i; |
| 1326 | 1366 | cgi_parameter("",""); /* Force the parameters into sorted order */ |
| 1327 | 1367 | for(i=0; i<nUsedQP; i++){ |
| 1328 | 1368 | const char *zName = aParamQP[i].zName; |
| 1329 | 1369 | if( !showAll ){ |
| 1330 | 1370 | if( fossil_stricmp("HTTP_COOKIE",zName)==0 ) continue; |
| 1331 | 1371 | if( fossil_strnicmp("fossil-",zName,7)==0 ) continue; |
| 1332 | 1372 | } |
| 1333 | - if( onConsole ){ | |
| 1334 | - fossil_trace("%s = %s\n", zName, aParamQP[i].zValue); | |
| 1335 | - }else{ | |
| 1336 | - cgi_printf("%h = %h <br />\n", zName, aParamQP[i].zValue); | |
| 1373 | + switch( eDest ){ | |
| 1374 | + case 0: { | |
| 1375 | + cgi_printf("%h = %h <br />\n", zName, aParamQP[i].zValue); | |
| 1376 | + break; | |
| 1377 | + } | |
| 1378 | + case 1: { | |
| 1379 | + fossil_trace("%s = %s\n", zName, aParamQP[i].zValue); | |
| 1380 | + break; | |
| 1381 | + } | |
| 1382 | + case 2: { | |
| 1383 | + cgi_debug("%s = %s\n", zName, aParamQP[i].zValue); | |
| 1384 | + break; | |
| 1385 | + } | |
| 1337 | 1386 | } |
| 1338 | 1387 | } |
| 1339 | 1388 | } |
| 1340 | 1389 | |
| 1341 | 1390 | /* |
| @@ -2076,10 +2125,30 @@ | ||
| 2076 | 2125 | return mprintf("%s, %d %s %02d %02d:%02d:%02d +0000", |
| 2077 | 2126 | azDays[pTm->tm_wday], pTm->tm_mday, azMonths[pTm->tm_mon], |
| 2078 | 2127 | pTm->tm_year+1900, pTm->tm_hour, pTm->tm_min, pTm->tm_sec); |
| 2079 | 2128 | } |
| 2080 | 2129 | } |
| 2130 | + | |
| 2131 | +/* | |
| 2132 | +** Returns an ISO8601-formatted time string suitable for debugging | |
| 2133 | +** purposes. | |
| 2134 | +** | |
| 2135 | +** The value returned is always a string obtained from mprintf() and must | |
| 2136 | +** be freed using fossil_free() to avoid a memory leak. | |
| 2137 | +*/ | |
| 2138 | +char *cgi_iso8601_datestamp(void){ | |
| 2139 | + struct tm *pTm; | |
| 2140 | + time_t now = time(0); | |
| 2141 | + pTm = gmtime(&now); | |
| 2142 | + if( pTm==0 ){ | |
| 2143 | + return mprintf(""); | |
| 2144 | + }else{ | |
| 2145 | + return mprintf("%04d-%02d-%02d %02d:%02d:%02d", | |
| 2146 | + pTm->tm_year+1900, pTm->tm_mon, pTm->tm_mday, | |
| 2147 | + pTm->tm_hour, pTm->tm_min, pTm->tm_sec); | |
| 2148 | + } | |
| 2149 | +} | |
| 2081 | 2150 | |
| 2082 | 2151 | /* |
| 2083 | 2152 | ** Parse an RFC822-formatted timestamp as we'd expect from HTTP and return |
| 2084 | 2153 | ** a Unix epoch time. <= zero is returned on failure. |
| 2085 | 2154 | ** |
| 2086 | 2155 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -350,11 +350,11 @@ | |
| 350 | fwrite(blob_buffer(&cgiContent[i]), 1, size, g.httpOut); |
| 351 | } |
| 352 | } |
| 353 | } |
| 354 | fflush(g.httpOut); |
| 355 | CGIDEBUG(("DONE\n")); |
| 356 | |
| 357 | /* After the webpage has been sent, do any useful background |
| 358 | ** processing. |
| 359 | */ |
| 360 | g.cgiOutput = 2; |
| @@ -1167,10 +1167,14 @@ | |
| 1167 | } |
| 1168 | j++; |
| 1169 | } |
| 1170 | nUsedQP = j; |
| 1171 | } |
| 1172 | |
| 1173 | /* Do a binary search for a matching query parameter */ |
| 1174 | lo = 0; |
| 1175 | hi = nUsedQP-1; |
| 1176 | while( lo<=hi ){ |
| @@ -1189,11 +1193,11 @@ | |
| 1189 | /* If no match is found and the name begins with an upper-case |
| 1190 | ** letter, then check to see if there is an environment variable |
| 1191 | ** with the given name. Handle environment variables with empty values |
| 1192 | ** the same as non-existent environment variables. |
| 1193 | */ |
| 1194 | if( zName && fossil_isupper(zName[0]) ){ |
| 1195 | const char *zValue = fossil_getenv(zName); |
| 1196 | if( zValue && zValue[0] ){ |
| 1197 | cgi_set_parameter_nocopy(zName, zValue, 0); |
| 1198 | CGIDEBUG(("env-match [%s] = [%s]\n", zName, zValue)); |
| 1199 | return zValue; |
| @@ -1314,28 +1318,73 @@ | |
| 1314 | va_end(ap); |
| 1315 | return 1; |
| 1316 | } |
| 1317 | |
| 1318 | /* |
| 1319 | ** Print all query parameters on standard output. Format the |
| 1320 | ** parameters as HTML. This is used for testing and debugging. |
| 1321 | ** |
| 1322 | ** Omit the values of the cookies unless showAll is true. |
| 1323 | */ |
| 1324 | void cgi_print_all(int showAll, int onConsole){ |
| 1325 | int i; |
| 1326 | cgi_parameter("",""); /* Force the parameters into sorted order */ |
| 1327 | for(i=0; i<nUsedQP; i++){ |
| 1328 | const char *zName = aParamQP[i].zName; |
| 1329 | if( !showAll ){ |
| 1330 | if( fossil_stricmp("HTTP_COOKIE",zName)==0 ) continue; |
| 1331 | if( fossil_strnicmp("fossil-",zName,7)==0 ) continue; |
| 1332 | } |
| 1333 | if( onConsole ){ |
| 1334 | fossil_trace("%s = %s\n", zName, aParamQP[i].zValue); |
| 1335 | }else{ |
| 1336 | cgi_printf("%h = %h <br />\n", zName, aParamQP[i].zValue); |
| 1337 | } |
| 1338 | } |
| 1339 | } |
| 1340 | |
| 1341 | /* |
| @@ -2076,10 +2125,30 @@ | |
| 2076 | return mprintf("%s, %d %s %02d %02d:%02d:%02d +0000", |
| 2077 | azDays[pTm->tm_wday], pTm->tm_mday, azMonths[pTm->tm_mon], |
| 2078 | pTm->tm_year+1900, pTm->tm_hour, pTm->tm_min, pTm->tm_sec); |
| 2079 | } |
| 2080 | } |
| 2081 | |
| 2082 | /* |
| 2083 | ** Parse an RFC822-formatted timestamp as we'd expect from HTTP and return |
| 2084 | ** a Unix epoch time. <= zero is returned on failure. |
| 2085 | ** |
| 2086 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -350,11 +350,11 @@ | |
| 350 | fwrite(blob_buffer(&cgiContent[i]), 1, size, g.httpOut); |
| 351 | } |
| 352 | } |
| 353 | } |
| 354 | fflush(g.httpOut); |
| 355 | CGIDEBUG(("-------- END cgi ---------\n")); |
| 356 | |
| 357 | /* After the webpage has been sent, do any useful background |
| 358 | ** processing. |
| 359 | */ |
| 360 | g.cgiOutput = 2; |
| @@ -1167,10 +1167,14 @@ | |
| 1167 | } |
| 1168 | j++; |
| 1169 | } |
| 1170 | nUsedQP = j; |
| 1171 | } |
| 1172 | |
| 1173 | /* Invoking with a NULL zName is just a way to cause the parameters |
| 1174 | ** to be sorted. So go ahead and bail out in that case */ |
| 1175 | if( zName==0 || zName[0]==0 ) return 0; |
| 1176 | |
| 1177 | /* Do a binary search for a matching query parameter */ |
| 1178 | lo = 0; |
| 1179 | hi = nUsedQP-1; |
| 1180 | while( lo<=hi ){ |
| @@ -1189,11 +1193,11 @@ | |
| 1193 | /* If no match is found and the name begins with an upper-case |
| 1194 | ** letter, then check to see if there is an environment variable |
| 1195 | ** with the given name. Handle environment variables with empty values |
| 1196 | ** the same as non-existent environment variables. |
| 1197 | */ |
| 1198 | if( fossil_isupper(zName[0]) ){ |
| 1199 | const char *zValue = fossil_getenv(zName); |
| 1200 | if( zValue && zValue[0] ){ |
| 1201 | cgi_set_parameter_nocopy(zName, zValue, 0); |
| 1202 | CGIDEBUG(("env-match [%s] = [%s]\n", zName, zValue)); |
| 1203 | return zValue; |
| @@ -1314,28 +1318,73 @@ | |
| 1318 | va_end(ap); |
| 1319 | return 1; |
| 1320 | } |
| 1321 | |
| 1322 | /* |
| 1323 | ** Load all relevant environment variables into the parameter buffer. |
| 1324 | ** Invoke this routine prior to calling cgi_print_all() in order to see |
| 1325 | ** the full CGI environment. This routine intended for debugging purposes |
| 1326 | ** only. |
| 1327 | */ |
| 1328 | void cgi_load_environment(void){ |
| 1329 | /* The following is a list of environment variables that Fossil considers |
| 1330 | ** to be "relevant". */ |
| 1331 | static const char *const azCgiVars[] = { |
| 1332 | "COMSPEC", "DOCUMENT_ROOT", "GATEWAY_INTERFACE", "SCGI", |
| 1333 | "HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET", "HTTP_ACCEPT_ENCODING", |
| 1334 | "HTTP_ACCEPT_LANGUAGE", "HTTP_AUTHENICATION", |
| 1335 | "HTTP_CONNECTION", "HTTP_HOST", |
| 1336 | "HTTP_IF_NONE_MATCH", "HTTP_IF_MODIFIED_SINCE", |
| 1337 | "HTTP_USER_AGENT", "HTTP_REFERER", "PATH_INFO", "PATH_TRANSLATED", |
| 1338 | "QUERY_STRING", "REMOTE_ADDR", "REMOTE_PORT", |
| 1339 | "REMOTE_USER", "REQUEST_METHOD", |
| 1340 | "REQUEST_URI", "SCRIPT_FILENAME", "SCRIPT_NAME", "SERVER_PROTOCOL", |
| 1341 | "HOME", "FOSSIL_HOME", "USERNAME", "USER", "FOSSIL_USER", |
| 1342 | "SQLITE_TMPDIR", "TMPDIR", |
| 1343 | "TEMP", "TMP", "FOSSIL_VFS", |
| 1344 | "FOSSIL_FORCE_TICKET_MODERATION", "FOSSIL_FORCE_WIKI_MODERATION", |
| 1345 | "FOSSIL_TCL_PATH", "TH1_DELETE_INTERP", "TH1_ENABLE_DOCS", |
| 1346 | "TH1_ENABLE_HOOKS", "TH1_ENABLE_TCL", "REMOTE_HOST", |
| 1347 | }; |
| 1348 | int i; |
| 1349 | for(i=0; i<count(azCgiVars); i++) (void)P(azCgiVars[i]); |
| 1350 | } |
| 1351 | |
| 1352 | /* |
| 1353 | ** Print all query parameters on standard output. |
| 1354 | ** This is used for testing and debugging. |
| 1355 | ** |
| 1356 | ** Omit the values of the cookies unless showAll is true. |
| 1357 | ** |
| 1358 | ** The eDest parameter determines where the output is shown: |
| 1359 | ** |
| 1360 | ** eDest==0: Rendering as HTML into the CGI reply |
| 1361 | ** eDest==1: Written to stderr |
| 1362 | ** eDest==2: Written to cgi_debug |
| 1363 | */ |
| 1364 | void cgi_print_all(int showAll, unsigned int eDest){ |
| 1365 | int i; |
| 1366 | cgi_parameter("",""); /* Force the parameters into sorted order */ |
| 1367 | for(i=0; i<nUsedQP; i++){ |
| 1368 | const char *zName = aParamQP[i].zName; |
| 1369 | if( !showAll ){ |
| 1370 | if( fossil_stricmp("HTTP_COOKIE",zName)==0 ) continue; |
| 1371 | if( fossil_strnicmp("fossil-",zName,7)==0 ) continue; |
| 1372 | } |
| 1373 | switch( eDest ){ |
| 1374 | case 0: { |
| 1375 | cgi_printf("%h = %h <br />\n", zName, aParamQP[i].zValue); |
| 1376 | break; |
| 1377 | } |
| 1378 | case 1: { |
| 1379 | fossil_trace("%s = %s\n", zName, aParamQP[i].zValue); |
| 1380 | break; |
| 1381 | } |
| 1382 | case 2: { |
| 1383 | cgi_debug("%s = %s\n", zName, aParamQP[i].zValue); |
| 1384 | break; |
| 1385 | } |
| 1386 | } |
| 1387 | } |
| 1388 | } |
| 1389 | |
| 1390 | /* |
| @@ -2076,10 +2125,30 @@ | |
| 2125 | return mprintf("%s, %d %s %02d %02d:%02d:%02d +0000", |
| 2126 | azDays[pTm->tm_wday], pTm->tm_mday, azMonths[pTm->tm_mon], |
| 2127 | pTm->tm_year+1900, pTm->tm_hour, pTm->tm_min, pTm->tm_sec); |
| 2128 | } |
| 2129 | } |
| 2130 | |
| 2131 | /* |
| 2132 | ** Returns an ISO8601-formatted time string suitable for debugging |
| 2133 | ** purposes. |
| 2134 | ** |
| 2135 | ** The value returned is always a string obtained from mprintf() and must |
| 2136 | ** be freed using fossil_free() to avoid a memory leak. |
| 2137 | */ |
| 2138 | char *cgi_iso8601_datestamp(void){ |
| 2139 | struct tm *pTm; |
| 2140 | time_t now = time(0); |
| 2141 | pTm = gmtime(&now); |
| 2142 | if( pTm==0 ){ |
| 2143 | return mprintf(""); |
| 2144 | }else{ |
| 2145 | return mprintf("%04d-%02d-%02d %02d:%02d:%02d", |
| 2146 | pTm->tm_year+1900, pTm->tm_mon, pTm->tm_mday, |
| 2147 | pTm->tm_hour, pTm->tm_min, pTm->tm_sec); |
| 2148 | } |
| 2149 | } |
| 2150 | |
| 2151 | /* |
| 2152 | ** Parse an RFC822-formatted timestamp as we'd expect from HTTP and return |
| 2153 | ** a Unix epoch time. <= zero is returned on failure. |
| 2154 | ** |
| 2155 |
+2
-1
| --- src/doc.c | ||
| +++ src/doc.c | ||
| @@ -39,11 +39,11 @@ | ||
| 39 | 39 | |
| 40 | 40 | /* A table of mimetypes based on file content prefixes |
| 41 | 41 | */ |
| 42 | 42 | static const struct { |
| 43 | 43 | const char *zPrefix; /* The file prefix */ |
| 44 | - int size; /* Length of the prefix */ | |
| 44 | + const int size; /* Length of the prefix */ | |
| 45 | 45 | const char *zMimetype; /* The corresponding mimetype */ |
| 46 | 46 | } aMime[] = { |
| 47 | 47 | { "GIF87a", 6, "image/gif" }, |
| 48 | 48 | { "GIF89a", 6, "image/gif" }, |
| 49 | 49 | { "\211PNG\r\n\032\n", 8, "image/png" }, |
| @@ -269,10 +269,11 @@ | ||
| 269 | 269 | { "viv", 3, "video/vnd.vivo" }, |
| 270 | 270 | { "vivo", 4, "video/vnd.vivo" }, |
| 271 | 271 | { "vrml", 4, "model/vrml" }, |
| 272 | 272 | { "wav", 3, "audio/x-wav" }, |
| 273 | 273 | { "wax", 3, "audio/x-ms-wax" }, |
| 274 | + { "webp", 4, "image/webp" }, | |
| 274 | 275 | { "wiki", 4, "text/x-fossil-wiki" }, |
| 275 | 276 | { "wma", 3, "audio/x-ms-wma" }, |
| 276 | 277 | { "wmv", 3, "video/x-ms-wmv" }, |
| 277 | 278 | { "wmx", 3, "video/x-ms-wmx" }, |
| 278 | 279 | { "wrl", 3, "model/vrml" }, |
| 279 | 280 |
| --- src/doc.c | |
| +++ src/doc.c | |
| @@ -39,11 +39,11 @@ | |
| 39 | |
| 40 | /* A table of mimetypes based on file content prefixes |
| 41 | */ |
| 42 | static const struct { |
| 43 | const char *zPrefix; /* The file prefix */ |
| 44 | int size; /* Length of the prefix */ |
| 45 | const char *zMimetype; /* The corresponding mimetype */ |
| 46 | } aMime[] = { |
| 47 | { "GIF87a", 6, "image/gif" }, |
| 48 | { "GIF89a", 6, "image/gif" }, |
| 49 | { "\211PNG\r\n\032\n", 8, "image/png" }, |
| @@ -269,10 +269,11 @@ | |
| 269 | { "viv", 3, "video/vnd.vivo" }, |
| 270 | { "vivo", 4, "video/vnd.vivo" }, |
| 271 | { "vrml", 4, "model/vrml" }, |
| 272 | { "wav", 3, "audio/x-wav" }, |
| 273 | { "wax", 3, "audio/x-ms-wax" }, |
| 274 | { "wiki", 4, "text/x-fossil-wiki" }, |
| 275 | { "wma", 3, "audio/x-ms-wma" }, |
| 276 | { "wmv", 3, "video/x-ms-wmv" }, |
| 277 | { "wmx", 3, "video/x-ms-wmx" }, |
| 278 | { "wrl", 3, "model/vrml" }, |
| 279 |
| --- src/doc.c | |
| +++ src/doc.c | |
| @@ -39,11 +39,11 @@ | |
| 39 | |
| 40 | /* A table of mimetypes based on file content prefixes |
| 41 | */ |
| 42 | static const struct { |
| 43 | const char *zPrefix; /* The file prefix */ |
| 44 | const int size; /* Length of the prefix */ |
| 45 | const char *zMimetype; /* The corresponding mimetype */ |
| 46 | } aMime[] = { |
| 47 | { "GIF87a", 6, "image/gif" }, |
| 48 | { "GIF89a", 6, "image/gif" }, |
| 49 | { "\211PNG\r\n\032\n", 8, "image/png" }, |
| @@ -269,10 +269,11 @@ | |
| 269 | { "viv", 3, "video/vnd.vivo" }, |
| 270 | { "vivo", 4, "video/vnd.vivo" }, |
| 271 | { "vrml", 4, "model/vrml" }, |
| 272 | { "wav", 3, "audio/x-wav" }, |
| 273 | { "wax", 3, "audio/x-ms-wax" }, |
| 274 | { "webp", 4, "image/webp" }, |
| 275 | { "wiki", 4, "text/x-fossil-wiki" }, |
| 276 | { "wma", 3, "audio/x-ms-wma" }, |
| 277 | { "wmv", 3, "video/x-ms-wmv" }, |
| 278 | { "wmx", 3, "video/x-ms-wmx" }, |
| 279 | { "wrl", 3, "model/vrml" }, |
| 280 |
+39
-1
| --- src/extcgi.c | ||
| +++ src/extcgi.c | ||
| @@ -98,10 +98,43 @@ | ||
| 98 | 98 | break; |
| 99 | 99 | } |
| 100 | 100 | } |
| 101 | 101 | return zFailReason; |
| 102 | 102 | } |
| 103 | + | |
| 104 | +/* | |
| 105 | +** The *pzPath input is a pathname obtained from mprintf(). | |
| 106 | +** | |
| 107 | +** If | |
| 108 | +** | |
| 109 | +** (1) zPathname is the name of a directory, and | |
| 110 | +** (2) the name ends with "/", and | |
| 111 | +** (3) the directory contains a file named index.html, index.wiki, | |
| 112 | +** or index.md (in that order) | |
| 113 | +** | |
| 114 | +** then replace the input with a revised name that includes the index.* | |
| 115 | +** file and return non-zero (true). If any condition is not met, return | |
| 116 | +** zero and leave the input pathname unchanged. | |
| 117 | +*/ | |
| 118 | +static int isDirWithIndexFile(char **pzPath){ | |
| 119 | + static const char *azIndexNames[] = { | |
| 120 | + "index.html", "index.wiki", "index.md" | |
| 121 | + }; | |
| 122 | + int i; | |
| 123 | + if( file_isdir(*pzPath, ExtFILE)!=1 ) return 0; | |
| 124 | + if( sqlite3_strglob("*/", *pzPath)!=0 ) return 0; | |
| 125 | + for(i=0; i<sizeof(azIndexNames)/sizeof(azIndexNames[0]); i++){ | |
| 126 | + char *zNew = mprintf("%s%s", *pzPath, azIndexNames[i]); | |
| 127 | + if( file_isfile(zNew, ExtFILE) ){ | |
| 128 | + fossil_free(*pzPath); | |
| 129 | + *pzPath = zNew; | |
| 130 | + return 1; | |
| 131 | + } | |
| 132 | + fossil_free(zNew); | |
| 133 | + } | |
| 134 | + return 0; | |
| 135 | +} | |
| 103 | 136 | |
| 104 | 137 | /* |
| 105 | 138 | ** WEBPAGE: ext raw-content |
| 106 | 139 | ** |
| 107 | 140 | ** Relay an HTTP request to secondary CGI after first checking the |
| @@ -120,10 +153,15 @@ | ||
| 120 | 153 | ** The path after the /ext is the path to the CGI script or static file |
| 121 | 154 | ** relative to DIR. For security, this path may not contain characters |
| 122 | 155 | ** other than ASCII letters or digits, ".", "-", "/", and "_". If the |
| 123 | 156 | ** "." or "-" characters are present in the path then they may not follow |
| 124 | 157 | ** a "/". |
| 158 | +** | |
| 159 | +** If the path after /ext ends with "/" and is the name of a directory then | |
| 160 | +** that directory is searched for files named "index.html", "index.wiki", | |
| 161 | +** and "index.md" (in that order) and if found, those filenames are | |
| 162 | +** appended to the path. | |
| 125 | 163 | */ |
| 126 | 164 | void ext_page(void){ |
| 127 | 165 | const char *zName = P("name"); /* Path information after /ext */ |
| 128 | 166 | char *zPath = 0; /* Complete path from extroot */ |
| 129 | 167 | int nRoot; /* Number of bytes in the extroot name */ |
| @@ -164,11 +202,11 @@ | ||
| 164 | 202 | zFailReason = "extroot is not a directory"; |
| 165 | 203 | goto ext_not_found; |
| 166 | 204 | } |
| 167 | 205 | zPath = mprintf("%s/%s", g.zExtRoot, zName); |
| 168 | 206 | nRoot = (int)strlen(g.zExtRoot); |
| 169 | - if( file_isfile(zPath, ExtFILE) ){ | |
| 207 | + if( file_isfile(zPath, ExtFILE) || isDirWithIndexFile(&zPath) ){ | |
| 170 | 208 | nScript = (int)strlen(zPath); |
| 171 | 209 | zScript = zPath; |
| 172 | 210 | }else{ |
| 173 | 211 | for(i=nRoot+1; zPath[i]; i++){ |
| 174 | 212 | char c = zPath[i]; |
| 175 | 213 |
| --- src/extcgi.c | |
| +++ src/extcgi.c | |
| @@ -98,10 +98,43 @@ | |
| 98 | break; |
| 99 | } |
| 100 | } |
| 101 | return zFailReason; |
| 102 | } |
| 103 | |
| 104 | /* |
| 105 | ** WEBPAGE: ext raw-content |
| 106 | ** |
| 107 | ** Relay an HTTP request to secondary CGI after first checking the |
| @@ -120,10 +153,15 @@ | |
| 120 | ** The path after the /ext is the path to the CGI script or static file |
| 121 | ** relative to DIR. For security, this path may not contain characters |
| 122 | ** other than ASCII letters or digits, ".", "-", "/", and "_". If the |
| 123 | ** "." or "-" characters are present in the path then they may not follow |
| 124 | ** a "/". |
| 125 | */ |
| 126 | void ext_page(void){ |
| 127 | const char *zName = P("name"); /* Path information after /ext */ |
| 128 | char *zPath = 0; /* Complete path from extroot */ |
| 129 | int nRoot; /* Number of bytes in the extroot name */ |
| @@ -164,11 +202,11 @@ | |
| 164 | zFailReason = "extroot is not a directory"; |
| 165 | goto ext_not_found; |
| 166 | } |
| 167 | zPath = mprintf("%s/%s", g.zExtRoot, zName); |
| 168 | nRoot = (int)strlen(g.zExtRoot); |
| 169 | if( file_isfile(zPath, ExtFILE) ){ |
| 170 | nScript = (int)strlen(zPath); |
| 171 | zScript = zPath; |
| 172 | }else{ |
| 173 | for(i=nRoot+1; zPath[i]; i++){ |
| 174 | char c = zPath[i]; |
| 175 |
| --- src/extcgi.c | |
| +++ src/extcgi.c | |
| @@ -98,10 +98,43 @@ | |
| 98 | break; |
| 99 | } |
| 100 | } |
| 101 | return zFailReason; |
| 102 | } |
| 103 | |
| 104 | /* |
| 105 | ** The *pzPath input is a pathname obtained from mprintf(). |
| 106 | ** |
| 107 | ** If |
| 108 | ** |
| 109 | ** (1) zPathname is the name of a directory, and |
| 110 | ** (2) the name ends with "/", and |
| 111 | ** (3) the directory contains a file named index.html, index.wiki, |
| 112 | ** or index.md (in that order) |
| 113 | ** |
| 114 | ** then replace the input with a revised name that includes the index.* |
| 115 | ** file and return non-zero (true). If any condition is not met, return |
| 116 | ** zero and leave the input pathname unchanged. |
| 117 | */ |
| 118 | static int isDirWithIndexFile(char **pzPath){ |
| 119 | static const char *azIndexNames[] = { |
| 120 | "index.html", "index.wiki", "index.md" |
| 121 | }; |
| 122 | int i; |
| 123 | if( file_isdir(*pzPath, ExtFILE)!=1 ) return 0; |
| 124 | if( sqlite3_strglob("*/", *pzPath)!=0 ) return 0; |
| 125 | for(i=0; i<sizeof(azIndexNames)/sizeof(azIndexNames[0]); i++){ |
| 126 | char *zNew = mprintf("%s%s", *pzPath, azIndexNames[i]); |
| 127 | if( file_isfile(zNew, ExtFILE) ){ |
| 128 | fossil_free(*pzPath); |
| 129 | *pzPath = zNew; |
| 130 | return 1; |
| 131 | } |
| 132 | fossil_free(zNew); |
| 133 | } |
| 134 | return 0; |
| 135 | } |
| 136 | |
| 137 | /* |
| 138 | ** WEBPAGE: ext raw-content |
| 139 | ** |
| 140 | ** Relay an HTTP request to secondary CGI after first checking the |
| @@ -120,10 +153,15 @@ | |
| 153 | ** The path after the /ext is the path to the CGI script or static file |
| 154 | ** relative to DIR. For security, this path may not contain characters |
| 155 | ** other than ASCII letters or digits, ".", "-", "/", and "_". If the |
| 156 | ** "." or "-" characters are present in the path then they may not follow |
| 157 | ** a "/". |
| 158 | ** |
| 159 | ** If the path after /ext ends with "/" and is the name of a directory then |
| 160 | ** that directory is searched for files named "index.html", "index.wiki", |
| 161 | ** and "index.md" (in that order) and if found, those filenames are |
| 162 | ** appended to the path. |
| 163 | */ |
| 164 | void ext_page(void){ |
| 165 | const char *zName = P("name"); /* Path information after /ext */ |
| 166 | char *zPath = 0; /* Complete path from extroot */ |
| 167 | int nRoot; /* Number of bytes in the extroot name */ |
| @@ -164,11 +202,11 @@ | |
| 202 | zFailReason = "extroot is not a directory"; |
| 203 | goto ext_not_found; |
| 204 | } |
| 205 | zPath = mprintf("%s/%s", g.zExtRoot, zName); |
| 206 | nRoot = (int)strlen(g.zExtRoot); |
| 207 | if( file_isfile(zPath, ExtFILE) || isDirWithIndexFile(&zPath) ){ |
| 208 | nScript = (int)strlen(zPath); |
| 209 | zScript = zPath; |
| 210 | }else{ |
| 211 | for(i=nRoot+1; zPath[i]; i++){ |
| 212 | char c = zPath[i]; |
| 213 |
+16
-11
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -2042,11 +2042,11 @@ | ||
| 2042 | 2042 | g.httpIn = stdin; |
| 2043 | 2043 | fossil_binary_mode(g.httpOut); |
| 2044 | 2044 | fossil_binary_mode(g.httpIn); |
| 2045 | 2045 | g.cgiOutput = 1; |
| 2046 | 2046 | fossil_set_timeout(FOSSIL_DEFAULT_TIMEOUT); |
| 2047 | - /* Read and parse the CGI control file. */ | |
| 2047 | + /* Find the name of the CGI control file */ | |
| 2048 | 2048 | if( g.argc==3 && fossil_strcmp(g.argv[1],"cgi")==0 ){ |
| 2049 | 2049 | zFile = g.argv[2]; |
| 2050 | 2050 | }else if( g.argc>=2 ){ |
| 2051 | 2051 | zFile = g.argv[1]; |
| 2052 | 2052 | }else{ |
| @@ -2147,20 +2147,10 @@ | ||
| 2147 | 2147 | fossil_setenv(blob_str(&value), blob_str(&value2)); |
| 2148 | 2148 | blob_reset(&value); |
| 2149 | 2149 | blob_reset(&value2); |
| 2150 | 2150 | continue; |
| 2151 | 2151 | } |
| 2152 | - if( blob_eq(&key, "debug:") && blob_token(&line, &value) ){ | |
| 2153 | - /* debug: FILENAME | |
| 2154 | - ** | |
| 2155 | - ** Causes output from cgi_debug() and CGIDEBUG(()) calls to go | |
| 2156 | - ** into FILENAME. | |
| 2157 | - */ | |
| 2158 | - g.fDebug = fossil_fopen(blob_str(&value), "ab"); | |
| 2159 | - blob_reset(&value); | |
| 2160 | - continue; | |
| 2161 | - } | |
| 2162 | 2152 | if( blob_eq(&key, "errorlog:") && blob_token(&line, &value) ){ |
| 2163 | 2153 | /* errorlog: FILENAME |
| 2164 | 2154 | ** |
| 2165 | 2155 | ** Causes messages from warnings, errors, and panics to be appended |
| 2166 | 2156 | ** to FILENAME. |
| @@ -2206,10 +2196,25 @@ | ||
| 2206 | 2196 | ** this directive is a silent no-op. |
| 2207 | 2197 | */ |
| 2208 | 2198 | skin_use_alternative(blob_str(&value)); |
| 2209 | 2199 | blob_reset(&value); |
| 2210 | 2200 | continue; |
| 2201 | + } | |
| 2202 | + if( blob_eq(&key, "cgi-debug:") && blob_token(&line, &value) ){ | |
| 2203 | + /* cgi-debug: FILENAME | |
| 2204 | + ** | |
| 2205 | + ** Causes output from cgi_debug() and CGIDEBUG(()) calls to go | |
| 2206 | + ** into FILENAME. Useful for debugging CGI configuration problems. | |
| 2207 | + */ | |
| 2208 | + char *zNow = cgi_iso8601_datestamp(); | |
| 2209 | + cgi_load_environment(); | |
| 2210 | + g.fDebug = fossil_fopen(blob_str(&value), "ab"); | |
| 2211 | + blob_reset(&value); | |
| 2212 | + cgi_debug("-------- BEGIN cgi at %s --------\n", zNow); | |
| 2213 | + fossil_free(zNow); | |
| 2214 | + cgi_print_all(1,2); | |
| 2215 | + continue; | |
| 2211 | 2216 | } |
| 2212 | 2217 | } |
| 2213 | 2218 | blob_reset(&config); |
| 2214 | 2219 | if( g.db==0 && g.zRepositoryName==0 && nRedirect==0 ){ |
| 2215 | 2220 | cgi_panic("Unable to find or open the project repository"); |
| 2216 | 2221 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -2042,11 +2042,11 @@ | |
| 2042 | g.httpIn = stdin; |
| 2043 | fossil_binary_mode(g.httpOut); |
| 2044 | fossil_binary_mode(g.httpIn); |
| 2045 | g.cgiOutput = 1; |
| 2046 | fossil_set_timeout(FOSSIL_DEFAULT_TIMEOUT); |
| 2047 | /* Read and parse the CGI control file. */ |
| 2048 | if( g.argc==3 && fossil_strcmp(g.argv[1],"cgi")==0 ){ |
| 2049 | zFile = g.argv[2]; |
| 2050 | }else if( g.argc>=2 ){ |
| 2051 | zFile = g.argv[1]; |
| 2052 | }else{ |
| @@ -2147,20 +2147,10 @@ | |
| 2147 | fossil_setenv(blob_str(&value), blob_str(&value2)); |
| 2148 | blob_reset(&value); |
| 2149 | blob_reset(&value2); |
| 2150 | continue; |
| 2151 | } |
| 2152 | if( blob_eq(&key, "debug:") && blob_token(&line, &value) ){ |
| 2153 | /* debug: FILENAME |
| 2154 | ** |
| 2155 | ** Causes output from cgi_debug() and CGIDEBUG(()) calls to go |
| 2156 | ** into FILENAME. |
| 2157 | */ |
| 2158 | g.fDebug = fossil_fopen(blob_str(&value), "ab"); |
| 2159 | blob_reset(&value); |
| 2160 | continue; |
| 2161 | } |
| 2162 | if( blob_eq(&key, "errorlog:") && blob_token(&line, &value) ){ |
| 2163 | /* errorlog: FILENAME |
| 2164 | ** |
| 2165 | ** Causes messages from warnings, errors, and panics to be appended |
| 2166 | ** to FILENAME. |
| @@ -2206,10 +2196,25 @@ | |
| 2206 | ** this directive is a silent no-op. |
| 2207 | */ |
| 2208 | skin_use_alternative(blob_str(&value)); |
| 2209 | blob_reset(&value); |
| 2210 | continue; |
| 2211 | } |
| 2212 | } |
| 2213 | blob_reset(&config); |
| 2214 | if( g.db==0 && g.zRepositoryName==0 && nRedirect==0 ){ |
| 2215 | cgi_panic("Unable to find or open the project repository"); |
| 2216 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -2042,11 +2042,11 @@ | |
| 2042 | g.httpIn = stdin; |
| 2043 | fossil_binary_mode(g.httpOut); |
| 2044 | fossil_binary_mode(g.httpIn); |
| 2045 | g.cgiOutput = 1; |
| 2046 | fossil_set_timeout(FOSSIL_DEFAULT_TIMEOUT); |
| 2047 | /* Find the name of the CGI control file */ |
| 2048 | if( g.argc==3 && fossil_strcmp(g.argv[1],"cgi")==0 ){ |
| 2049 | zFile = g.argv[2]; |
| 2050 | }else if( g.argc>=2 ){ |
| 2051 | zFile = g.argv[1]; |
| 2052 | }else{ |
| @@ -2147,20 +2147,10 @@ | |
| 2147 | fossil_setenv(blob_str(&value), blob_str(&value2)); |
| 2148 | blob_reset(&value); |
| 2149 | blob_reset(&value2); |
| 2150 | continue; |
| 2151 | } |
| 2152 | if( blob_eq(&key, "errorlog:") && blob_token(&line, &value) ){ |
| 2153 | /* errorlog: FILENAME |
| 2154 | ** |
| 2155 | ** Causes messages from warnings, errors, and panics to be appended |
| 2156 | ** to FILENAME. |
| @@ -2206,10 +2196,25 @@ | |
| 2196 | ** this directive is a silent no-op. |
| 2197 | */ |
| 2198 | skin_use_alternative(blob_str(&value)); |
| 2199 | blob_reset(&value); |
| 2200 | continue; |
| 2201 | } |
| 2202 | if( blob_eq(&key, "cgi-debug:") && blob_token(&line, &value) ){ |
| 2203 | /* cgi-debug: FILENAME |
| 2204 | ** |
| 2205 | ** Causes output from cgi_debug() and CGIDEBUG(()) calls to go |
| 2206 | ** into FILENAME. Useful for debugging CGI configuration problems. |
| 2207 | */ |
| 2208 | char *zNow = cgi_iso8601_datestamp(); |
| 2209 | cgi_load_environment(); |
| 2210 | g.fDebug = fossil_fopen(blob_str(&value), "ab"); |
| 2211 | blob_reset(&value); |
| 2212 | cgi_debug("-------- BEGIN cgi at %s --------\n", zNow); |
| 2213 | fossil_free(zNow); |
| 2214 | cgi_print_all(1,2); |
| 2215 | continue; |
| 2216 | } |
| 2217 | } |
| 2218 | blob_reset(&config); |
| 2219 | if( g.db==0 && g.zRepositoryName==0 && nRedirect==0 ){ |
| 2220 | cgi_panic("Unable to find or open the project repository"); |
| 2221 |
+9
-1
| --- src/smtp.c | ||
| +++ src/smtp.c | ||
| @@ -598,36 +598,44 @@ | ||
| 598 | 598 | ** to the list of users TO. FROM is the sender of the email. |
| 599 | 599 | ** |
| 600 | 600 | ** Options: |
| 601 | 601 | ** |
| 602 | 602 | ** --direct Go directly to the TO domain. Bypass MX lookup |
| 603 | +** --relayhost R Use R as relay host directly for delivery. | |
| 603 | 604 | ** --port N Use TCP port N instead of 25 |
| 604 | 605 | ** --trace Show the SMTP conversation on the console |
| 605 | 606 | */ |
| 606 | 607 | void test_smtp_send(void){ |
| 607 | 608 | SmtpSession *p; |
| 608 | 609 | const char *zFrom; |
| 609 | 610 | int nTo; |
| 610 | 611 | const char *zToDomain; |
| 611 | 612 | const char *zFromDomain; |
| 613 | + const char *zRelay; | |
| 612 | 614 | const char **azTo; |
| 613 | 615 | int smtpPort = 25; |
| 614 | 616 | const char *zPort; |
| 615 | 617 | Blob body; |
| 616 | 618 | u32 smtpFlags = SMTP_PORT; |
| 617 | 619 | if( find_option("trace",0,0)!=0 ) smtpFlags |= SMTP_TRACE_STDOUT; |
| 618 | 620 | if( find_option("direct",0,0)!=0 ) smtpFlags |= SMTP_DIRECT; |
| 619 | 621 | zPort = find_option("port",0,1); |
| 620 | 622 | if( zPort ) smtpPort = atoi(zPort); |
| 623 | + zRelay = find_option("relayhost",0,1); | |
| 621 | 624 | verify_all_options(); |
| 622 | 625 | if( g.argc<5 ) usage("EMAIL FROM TO ..."); |
| 623 | 626 | blob_read_from_file(&body, g.argv[2], ExtFILE); |
| 624 | 627 | zFrom = g.argv[3]; |
| 625 | 628 | nTo = g.argc-4; |
| 626 | 629 | azTo = (const char**)g.argv+4; |
| 627 | 630 | zFromDomain = domainOfAddr(zFrom); |
| 628 | - zToDomain = domainOfAddr(azTo[0]); | |
| 631 | + if( zRelay!=0 && zRelay[0]!= 0) { | |
| 632 | + smtpFlags |= SMTP_DIRECT; | |
| 633 | + zToDomain = zRelay; | |
| 634 | + }else{ | |
| 635 | + zToDomain = domainOfAddr(azTo[0]); | |
| 636 | + } | |
| 629 | 637 | p = smtp_session_new(zFromDomain, zToDomain, smtpFlags, smtpPort); |
| 630 | 638 | if( p->zErr ){ |
| 631 | 639 | fossil_fatal("%s", p->zErr); |
| 632 | 640 | } |
| 633 | 641 | fossil_print("Connection to \"%s\"\n", p->zHostname); |
| 634 | 642 |
| --- src/smtp.c | |
| +++ src/smtp.c | |
| @@ -598,36 +598,44 @@ | |
| 598 | ** to the list of users TO. FROM is the sender of the email. |
| 599 | ** |
| 600 | ** Options: |
| 601 | ** |
| 602 | ** --direct Go directly to the TO domain. Bypass MX lookup |
| 603 | ** --port N Use TCP port N instead of 25 |
| 604 | ** --trace Show the SMTP conversation on the console |
| 605 | */ |
| 606 | void test_smtp_send(void){ |
| 607 | SmtpSession *p; |
| 608 | const char *zFrom; |
| 609 | int nTo; |
| 610 | const char *zToDomain; |
| 611 | const char *zFromDomain; |
| 612 | const char **azTo; |
| 613 | int smtpPort = 25; |
| 614 | const char *zPort; |
| 615 | Blob body; |
| 616 | u32 smtpFlags = SMTP_PORT; |
| 617 | if( find_option("trace",0,0)!=0 ) smtpFlags |= SMTP_TRACE_STDOUT; |
| 618 | if( find_option("direct",0,0)!=0 ) smtpFlags |= SMTP_DIRECT; |
| 619 | zPort = find_option("port",0,1); |
| 620 | if( zPort ) smtpPort = atoi(zPort); |
| 621 | verify_all_options(); |
| 622 | if( g.argc<5 ) usage("EMAIL FROM TO ..."); |
| 623 | blob_read_from_file(&body, g.argv[2], ExtFILE); |
| 624 | zFrom = g.argv[3]; |
| 625 | nTo = g.argc-4; |
| 626 | azTo = (const char**)g.argv+4; |
| 627 | zFromDomain = domainOfAddr(zFrom); |
| 628 | zToDomain = domainOfAddr(azTo[0]); |
| 629 | p = smtp_session_new(zFromDomain, zToDomain, smtpFlags, smtpPort); |
| 630 | if( p->zErr ){ |
| 631 | fossil_fatal("%s", p->zErr); |
| 632 | } |
| 633 | fossil_print("Connection to \"%s\"\n", p->zHostname); |
| 634 |
| --- src/smtp.c | |
| +++ src/smtp.c | |
| @@ -598,36 +598,44 @@ | |
| 598 | ** to the list of users TO. FROM is the sender of the email. |
| 599 | ** |
| 600 | ** Options: |
| 601 | ** |
| 602 | ** --direct Go directly to the TO domain. Bypass MX lookup |
| 603 | ** --relayhost R Use R as relay host directly for delivery. |
| 604 | ** --port N Use TCP port N instead of 25 |
| 605 | ** --trace Show the SMTP conversation on the console |
| 606 | */ |
| 607 | void test_smtp_send(void){ |
| 608 | SmtpSession *p; |
| 609 | const char *zFrom; |
| 610 | int nTo; |
| 611 | const char *zToDomain; |
| 612 | const char *zFromDomain; |
| 613 | const char *zRelay; |
| 614 | const char **azTo; |
| 615 | int smtpPort = 25; |
| 616 | const char *zPort; |
| 617 | Blob body; |
| 618 | u32 smtpFlags = SMTP_PORT; |
| 619 | if( find_option("trace",0,0)!=0 ) smtpFlags |= SMTP_TRACE_STDOUT; |
| 620 | if( find_option("direct",0,0)!=0 ) smtpFlags |= SMTP_DIRECT; |
| 621 | zPort = find_option("port",0,1); |
| 622 | if( zPort ) smtpPort = atoi(zPort); |
| 623 | zRelay = find_option("relayhost",0,1); |
| 624 | verify_all_options(); |
| 625 | if( g.argc<5 ) usage("EMAIL FROM TO ..."); |
| 626 | blob_read_from_file(&body, g.argv[2], ExtFILE); |
| 627 | zFrom = g.argv[3]; |
| 628 | nTo = g.argc-4; |
| 629 | azTo = (const char**)g.argv+4; |
| 630 | zFromDomain = domainOfAddr(zFrom); |
| 631 | if( zRelay!=0 && zRelay[0]!= 0) { |
| 632 | smtpFlags |= SMTP_DIRECT; |
| 633 | zToDomain = zRelay; |
| 634 | }else{ |
| 635 | zToDomain = domainOfAddr(azTo[0]); |
| 636 | } |
| 637 | p = smtp_session_new(zFromDomain, zToDomain, smtpFlags, smtpPort); |
| 638 | if( p->zErr ){ |
| 639 | fossil_fatal("%s", p->zErr); |
| 640 | } |
| 641 | fossil_print("Connection to \"%s\"\n", p->zHostname); |
| 642 |
+1
-19
| --- src/style.c | ||
| +++ src/style.c | ||
| @@ -1139,38 +1139,20 @@ | ||
| 1139 | 1139 | ** the error message is shown. |
| 1140 | 1140 | ** |
| 1141 | 1141 | ** If zFormat is an empty string, then this is the /test_env page. |
| 1142 | 1142 | */ |
| 1143 | 1143 | void webpage_error(const char *zFormat, ...){ |
| 1144 | - int i; | |
| 1145 | 1144 | int showAll; |
| 1146 | 1145 | char *zErr = 0; |
| 1147 | 1146 | int isAuth = 0; |
| 1148 | 1147 | char zCap[100]; |
| 1149 | - static const char *const azCgiVars[] = { | |
| 1150 | - "COMSPEC", "DOCUMENT_ROOT", "GATEWAY_INTERFACE", "SCGI", | |
| 1151 | - "HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET", "HTTP_ACCEPT_ENCODING", | |
| 1152 | - "HTTP_ACCEPT_LANGUAGE", "HTTP_AUTHENICATION", | |
| 1153 | - "HTTP_CONNECTION", "HTTP_HOST", | |
| 1154 | - "HTTP_IF_NONE_MATCH", "HTTP_IF_MODIFIED_SINCE", | |
| 1155 | - "HTTP_USER_AGENT", "HTTP_REFERER", "PATH_INFO", "PATH_TRANSLATED", | |
| 1156 | - "QUERY_STRING", "REMOTE_ADDR", "REMOTE_PORT", | |
| 1157 | - "REMOTE_USER", "REQUEST_METHOD", | |
| 1158 | - "REQUEST_URI", "SCRIPT_FILENAME", "SCRIPT_NAME", "SERVER_PROTOCOL", | |
| 1159 | - "HOME", "FOSSIL_HOME", "USERNAME", "USER", "FOSSIL_USER", | |
| 1160 | - "SQLITE_TMPDIR", "TMPDIR", | |
| 1161 | - "TEMP", "TMP", "FOSSIL_VFS", | |
| 1162 | - "FOSSIL_FORCE_TICKET_MODERATION", "FOSSIL_FORCE_WIKI_MODERATION", | |
| 1163 | - "FOSSIL_TCL_PATH", "TH1_DELETE_INTERP", "TH1_ENABLE_DOCS", | |
| 1164 | - "TH1_ENABLE_HOOKS", "TH1_ENABLE_TCL", "REMOTE_HOST", | |
| 1165 | - }; | |
| 1166 | 1148 | |
| 1167 | 1149 | login_check_credentials(); |
| 1168 | 1150 | if( g.perm.Admin || g.perm.Setup || db_get_boolean("test_env_enable",0) ){ |
| 1169 | 1151 | isAuth = 1; |
| 1170 | 1152 | } |
| 1171 | - for(i=0; i<count(azCgiVars); i++) (void)P(azCgiVars[i]); | |
| 1153 | + cgi_load_environment(); | |
| 1172 | 1154 | if( zFormat[0] ){ |
| 1173 | 1155 | va_list ap; |
| 1174 | 1156 | va_start(ap, zFormat); |
| 1175 | 1157 | zErr = vmprintf(zFormat, ap); |
| 1176 | 1158 | va_end(ap); |
| 1177 | 1159 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -1139,38 +1139,20 @@ | |
| 1139 | ** the error message is shown. |
| 1140 | ** |
| 1141 | ** If zFormat is an empty string, then this is the /test_env page. |
| 1142 | */ |
| 1143 | void webpage_error(const char *zFormat, ...){ |
| 1144 | int i; |
| 1145 | int showAll; |
| 1146 | char *zErr = 0; |
| 1147 | int isAuth = 0; |
| 1148 | char zCap[100]; |
| 1149 | static const char *const azCgiVars[] = { |
| 1150 | "COMSPEC", "DOCUMENT_ROOT", "GATEWAY_INTERFACE", "SCGI", |
| 1151 | "HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET", "HTTP_ACCEPT_ENCODING", |
| 1152 | "HTTP_ACCEPT_LANGUAGE", "HTTP_AUTHENICATION", |
| 1153 | "HTTP_CONNECTION", "HTTP_HOST", |
| 1154 | "HTTP_IF_NONE_MATCH", "HTTP_IF_MODIFIED_SINCE", |
| 1155 | "HTTP_USER_AGENT", "HTTP_REFERER", "PATH_INFO", "PATH_TRANSLATED", |
| 1156 | "QUERY_STRING", "REMOTE_ADDR", "REMOTE_PORT", |
| 1157 | "REMOTE_USER", "REQUEST_METHOD", |
| 1158 | "REQUEST_URI", "SCRIPT_FILENAME", "SCRIPT_NAME", "SERVER_PROTOCOL", |
| 1159 | "HOME", "FOSSIL_HOME", "USERNAME", "USER", "FOSSIL_USER", |
| 1160 | "SQLITE_TMPDIR", "TMPDIR", |
| 1161 | "TEMP", "TMP", "FOSSIL_VFS", |
| 1162 | "FOSSIL_FORCE_TICKET_MODERATION", "FOSSIL_FORCE_WIKI_MODERATION", |
| 1163 | "FOSSIL_TCL_PATH", "TH1_DELETE_INTERP", "TH1_ENABLE_DOCS", |
| 1164 | "TH1_ENABLE_HOOKS", "TH1_ENABLE_TCL", "REMOTE_HOST", |
| 1165 | }; |
| 1166 | |
| 1167 | login_check_credentials(); |
| 1168 | if( g.perm.Admin || g.perm.Setup || db_get_boolean("test_env_enable",0) ){ |
| 1169 | isAuth = 1; |
| 1170 | } |
| 1171 | for(i=0; i<count(azCgiVars); i++) (void)P(azCgiVars[i]); |
| 1172 | if( zFormat[0] ){ |
| 1173 | va_list ap; |
| 1174 | va_start(ap, zFormat); |
| 1175 | zErr = vmprintf(zFormat, ap); |
| 1176 | va_end(ap); |
| 1177 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -1139,38 +1139,20 @@ | |
| 1139 | ** the error message is shown. |
| 1140 | ** |
| 1141 | ** If zFormat is an empty string, then this is the /test_env page. |
| 1142 | */ |
| 1143 | void webpage_error(const char *zFormat, ...){ |
| 1144 | int showAll; |
| 1145 | char *zErr = 0; |
| 1146 | int isAuth = 0; |
| 1147 | char zCap[100]; |
| 1148 | |
| 1149 | login_check_credentials(); |
| 1150 | if( g.perm.Admin || g.perm.Setup || db_get_boolean("test_env_enable",0) ){ |
| 1151 | isAuth = 1; |
| 1152 | } |
| 1153 | cgi_load_environment(); |
| 1154 | if( zFormat[0] ){ |
| 1155 | va_list ap; |
| 1156 | va_start(ap, zFormat); |
| 1157 | zErr = vmprintf(zFormat, ap); |
| 1158 | va_end(ap); |
| 1159 |
+5
| --- www/cgi.wiki | ||
| +++ www/cgi.wiki | ||
| @@ -136,5 +136,10 @@ | ||
| 136 | 136 | This parameter can be repeated as many times as necessary. |
| 137 | 137 | |
| 138 | 138 | <h2 id="HOME">HOME: <i>PATH</i></h2> |
| 139 | 139 | |
| 140 | 140 | This parameter is a short-hand for "<b>setenv HOME <i>PATH</i></b>". |
| 141 | + | |
| 142 | +<h2 id="cgi-debug">cgi-debug: <i>FILE</i></h2> | |
| 143 | + | |
| 144 | +Cause CGI-related debugging information to be appended in <i>FILE</i>. Use | |
| 145 | +this to help debug CGI problems. | |
| 141 | 146 |
| --- www/cgi.wiki | |
| +++ www/cgi.wiki | |
| @@ -136,5 +136,10 @@ | |
| 136 | This parameter can be repeated as many times as necessary. |
| 137 | |
| 138 | <h2 id="HOME">HOME: <i>PATH</i></h2> |
| 139 | |
| 140 | This parameter is a short-hand for "<b>setenv HOME <i>PATH</i></b>". |
| 141 |
| --- www/cgi.wiki | |
| +++ www/cgi.wiki | |
| @@ -136,5 +136,10 @@ | |
| 136 | This parameter can be repeated as many times as necessary. |
| 137 | |
| 138 | <h2 id="HOME">HOME: <i>PATH</i></h2> |
| 139 | |
| 140 | This parameter is a short-hand for "<b>setenv HOME <i>PATH</i></b>". |
| 141 | |
| 142 | <h2 id="cgi-debug">cgi-debug: <i>FILE</i></h2> |
| 143 | |
| 144 | Cause CGI-related debugging information to be appended in <i>FILE</i>. Use |
| 145 | this to help debug CGI problems. |
| 146 |
+1
-1
| --- www/serverext.wiki | ||
| +++ www/serverext.wiki | ||
| @@ -201,11 +201,11 @@ | ||
| 201 | 201 | |
| 202 | 202 | <blockquote><verbatim> |
| 203 | 203 | <script nonce='$FOSSIL_NONCE'>...</script> |
| 204 | 204 | </verbatim></blockquote> |
| 205 | 205 | |
| 206 | -Except, of course, the $FOSSIL_NONCE is replace by the value of the | |
| 206 | +Except, of course, the $FOSSIL_NONCE is replaced by the value of the | |
| 207 | 207 | FOSSIL_NONCE environment variable. |
| 208 | 208 | |
| 209 | 209 | If the HTTP request includes content (for example if this is a POST request) |
| 210 | 210 | then the CONTENT_LENGTH value will be positive and the data for the content |
| 211 | 211 | will be readable on standard input. |
| 212 | 212 |
| --- www/serverext.wiki | |
| +++ www/serverext.wiki | |
| @@ -201,11 +201,11 @@ | |
| 201 | |
| 202 | <blockquote><verbatim> |
| 203 | <script nonce='$FOSSIL_NONCE'>...</script> |
| 204 | </verbatim></blockquote> |
| 205 | |
| 206 | Except, of course, the $FOSSIL_NONCE is replace by the value of the |
| 207 | FOSSIL_NONCE environment variable. |
| 208 | |
| 209 | If the HTTP request includes content (for example if this is a POST request) |
| 210 | then the CONTENT_LENGTH value will be positive and the data for the content |
| 211 | will be readable on standard input. |
| 212 |
| --- www/serverext.wiki | |
| +++ www/serverext.wiki | |
| @@ -201,11 +201,11 @@ | |
| 201 | |
| 202 | <blockquote><verbatim> |
| 203 | <script nonce='$FOSSIL_NONCE'>...</script> |
| 204 | </verbatim></blockquote> |
| 205 | |
| 206 | Except, of course, the $FOSSIL_NONCE is replaced by the value of the |
| 207 | FOSSIL_NONCE environment variable. |
| 208 | |
| 209 | If the HTTP request includes content (for example if this is a POST request) |
| 210 | then the CONTENT_LENGTH value will be positive and the data for the content |
| 211 | will be readable on standard input. |
| 212 |