00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 #define cgicTempDir "/tmp"
00010 
00011 #if CGICDEBUG
00012 #define CGICDEBUGSTART \
00013   { \
00014     FILE *dout; \
00015     dout = fopen("/home/boutell/public_html/debug", "a"); \
00016   
00017 #define CGICDEBUGEND \
00018     fclose(dout); \
00019   }
00020 #else 
00021 #define CGICDEBUGSTART
00022 #define CGICDEBUGEND
00023 #endif 
00024 
00025 #include <stdio.h>
00026 #include <string.h>
00027 #include <ctype.h>
00028 #include <stdlib.h>
00029 #include <time.h>
00030 #include <sys/types.h>
00031 #include <sys/stat.h>
00032 
00033 #ifdef WIN32
00034 #include <io.h>
00035 
00036 
00037 #include <fcntl.h>
00038 
00039 #else
00040 #include <unistd.h>
00041 #endif 
00042 #include "cgic.h"
00043 
00044 #define cgiStrEq(a, b) (!strcmp((a), (b)))
00045 
00046 char *cgiServerSoftware;
00047 char *cgiServerName;
00048 char *cgiGatewayInterface;
00049 char *cgiServerProtocol;
00050 char *cgiServerPort;
00051 char *cgiRequestMethod;
00052 char *cgiPathInfo;
00053 char *cgiPathTranslated;
00054 char *cgiScriptName;
00055 char *cgiQueryString;
00056 char *cgiRemoteHost;
00057 char *cgiRemoteAddr;
00058 char *cgiAuthType;
00059 char *cgiRemoteUser;
00060 char *cgiRemoteIdent;
00061 char cgiContentTypeData[1024];
00062 char *cgiContentType = cgiContentTypeData;
00063 char *cgiMultipartBoundary;
00064 char *cgiCookie;
00065 int cgiContentLength;
00066 char *cgiAccept;
00067 char *cgiUserAgent;
00068 char *cgiReferrer;
00069 
00070 FILE *cgiIn;
00071 FILE *cgiOut;
00072 
00073 
00074 static int cgiRestored = 0;
00075 
00076 static void cgiGetenv(char **s, char *var);
00077 
00078 typedef enum {
00079   cgiParseSuccess,
00080   cgiParseMemory,
00081   cgiParseIO
00082 } cgiParseResultType;
00083 
00084 
00085 
00086 
00087 
00088 
00089 
00090 
00091 
00092 typedef struct cgiFormEntryStruct {
00093         char *attr;
00094   
00095 
00096  
00097   char *value;
00098   
00099 
00100   
00101 
00102   int valueLength;
00103   char *fileName; 
00104   char *contentType;
00105   
00106   char *tfileName;
00107         struct cgiFormEntryStruct *next;
00108 } cgiFormEntry;
00109 
00110 
00111 static cgiFormEntry *cgiFormEntryFirst;
00112 
00113 static cgiParseResultType cgiParseGetFormInput();
00114 static cgiParseResultType cgiParsePostFormInput();
00115 static cgiParseResultType cgiParsePostMultipartInput();
00116 static cgiParseResultType cgiParseFormInput(char *data, int length);
00117 static void cgiSetupConstants();
00118 static void cgiFreeResources();
00119 static int cgiStrEqNc(char *s1, char *s2);
00120 static int cgiStrBeginsNc(char *s1, char *s2);
00121 
00122 int main(int argc, char *argv[]) {
00123   int result;
00124   char *cgiContentLengthString;
00125   char *e;
00126   cgiSetupConstants();
00127   cgiGetenv(&cgiServerSoftware, "SERVER_SOFTWARE");
00128   cgiGetenv(&cgiServerName, "SERVER_NAME");
00129   cgiGetenv(&cgiGatewayInterface, "GATEWAY_INTERFACE");
00130   cgiGetenv(&cgiServerProtocol, "SERVER_PROTOCOL");
00131   cgiGetenv(&cgiServerPort, "SERVER_PORT");
00132   cgiGetenv(&cgiRequestMethod, "REQUEST_METHOD");
00133   cgiGetenv(&cgiPathInfo, "PATH_INFO");
00134   cgiGetenv(&cgiPathTranslated, "PATH_TRANSLATED");
00135   cgiGetenv(&cgiScriptName, "SCRIPT_NAME");
00136   cgiGetenv(&cgiQueryString, "QUERY_STRING");
00137   cgiGetenv(&cgiRemoteHost, "REMOTE_HOST");
00138   cgiGetenv(&cgiRemoteAddr, "REMOTE_ADDR");
00139   cgiGetenv(&cgiAuthType, "AUTH_TYPE");
00140   cgiGetenv(&cgiRemoteUser, "REMOTE_USER");
00141   cgiGetenv(&cgiRemoteIdent, "REMOTE_IDENT");
00142   
00143 
00144   e = getenv("CONTENT_TYPE");
00145   if (e) {
00146     if (strlen(e) < sizeof(cgiContentTypeData)) {
00147       strcpy(cgiContentType, e);
00148     } else {
00149       
00150 
00151       strncpy(cgiContentType, e, sizeof(cgiContentTypeData));
00152       cgiContentType[sizeof(cgiContentTypeData) - 1] = '\0';
00153     }
00154   } else {
00155     cgiContentType[0] = '\0';
00156   }
00157   
00158   cgiMultipartBoundary = "";
00159   
00160 
00161 
00162 
00163   if (strchr(cgiContentType, ';')) {
00164     char *sat = strchr(cgiContentType, ';');
00165     while (sat) {
00166       *sat = '\0';
00167       sat++;
00168       while (isspace(*sat)) {
00169         sat++;
00170       } 
00171       if (cgiStrBeginsNc(sat, "boundary=")) {
00172         char *s;
00173         cgiMultipartBoundary = sat + strlen("boundary=");
00174         s = cgiMultipartBoundary;
00175         while ((*s) && (!isspace(*s))) {
00176           s++;
00177         }
00178         *s = '\0';
00179         break;
00180       } else {
00181         sat = strchr(sat, ';');
00182       }   
00183     }
00184   }
00185   cgiGetenv(&cgiContentLengthString, "CONTENT_LENGTH");
00186   cgiContentLength = atoi(cgiContentLengthString);  
00187   cgiGetenv(&cgiAccept, "HTTP_ACCEPT");
00188   cgiGetenv(&cgiUserAgent, "HTTP_USER_AGENT");
00189   cgiGetenv(&cgiReferrer, "HTTP_REFERER");
00190   cgiGetenv(&cgiCookie, "HTTP_COOKIE");
00191 #ifdef CGICDEBUG
00192   CGICDEBUGSTART
00193   fprintf(dout, "%d\n", cgiContentLength);
00194   fprintf(dout, "%s\n", cgiRequestMethod);
00195   fprintf(dout, "%s\n", cgiContentType);
00196   CGICDEBUGEND  
00197 #endif 
00198 #ifdef WIN32
00199   
00200   
00201   _setmode( _fileno( stdin ), _O_BINARY );
00202   _setmode( _fileno( stdout ), _O_BINARY );
00203 #endif 
00204   cgiFormEntryFirst = 0;
00205   cgiIn = stdin;
00206   cgiOut = stdout;
00207   cgiRestored = 0;
00208 
00209 
00210   
00211 
00212 
00213   if (argc) {
00214     if (argv[0]) {
00215       cgiRestored = 0;
00216     }
00217   } 
00218 
00219 
00220   if (cgiStrEqNc(cgiRequestMethod, "post")) {
00221 #ifdef CGICDEBUG
00222     CGICDEBUGSTART
00223     fprintf(dout, "POST recognized\n");
00224     CGICDEBUGEND
00225 #endif 
00226     if (cgiStrEqNc(cgiContentType, "application/x-www-form-urlencoded")) {  
00227 #ifdef CGICDEBUG
00228       CGICDEBUGSTART
00229       fprintf(dout, "Calling PostFormInput\n");
00230       CGICDEBUGEND  
00231 #endif 
00232       if (cgiParsePostFormInput() != cgiParseSuccess) {
00233 #ifdef CGICDEBUG
00234         CGICDEBUGSTART
00235         fprintf(dout, "PostFormInput failed\n");
00236         CGICDEBUGEND  
00237 #endif 
00238         cgiFreeResources();
00239         return -1;
00240       } 
00241 #ifdef CGICDEBUG
00242       CGICDEBUGSTART
00243       fprintf(dout, "PostFormInput succeeded\n");
00244       CGICDEBUGEND  
00245 #endif 
00246     } else if (cgiStrEqNc(cgiContentType, "multipart/form-data")) {
00247 #ifdef CGICDEBUG
00248       CGICDEBUGSTART
00249       fprintf(dout, "Calling PostMultipartInput\n");
00250       CGICDEBUGEND  
00251 #endif 
00252       if (cgiParsePostMultipartInput() != cgiParseSuccess) {
00253 #ifdef CGICDEBUG
00254         CGICDEBUGSTART
00255         fprintf(dout, "PostMultipartInput failed\n");
00256         CGICDEBUGEND  
00257 #endif 
00258         cgiFreeResources();
00259         return -1;
00260       } 
00261 #ifdef CGICDEBUG
00262       CGICDEBUGSTART
00263       fprintf(dout, "PostMultipartInput succeeded\n");
00264       CGICDEBUGEND  
00265 #endif 
00266     }
00267   } else if (cgiStrEqNc(cgiRequestMethod, "get")) { 
00268     
00269 
00270     cgiContentLength = strlen(cgiQueryString);
00271     if (cgiParseGetFormInput() != cgiParseSuccess) {
00272 #ifdef CGICDEBUG
00273       CGICDEBUGSTART
00274       fprintf(dout, "GetFormInput failed\n");
00275       CGICDEBUGEND  
00276 #endif 
00277       cgiFreeResources();
00278       return -1;
00279     } else {  
00280 #ifdef CGICDEBUG
00281       CGICDEBUGSTART
00282       fprintf(dout, "GetFormInput succeeded\n");
00283       CGICDEBUGEND  
00284 #endif 
00285     }
00286   }
00287   result = cgiMain();
00288   cgiFreeResources();
00289   return result;
00290 }
00291 
00292 static void cgiGetenv(char **s, char *var){
00293   *s = getenv(var);
00294   if (!(*s)) {
00295     *s = "";
00296   }
00297 }
00298 
00299 static cgiParseResultType cgiParsePostFormInput() {
00300   char *input;
00301   cgiParseResultType result;
00302   if (!cgiContentLength) {
00303     return cgiParseSuccess;
00304   }
00305   input = (char *) malloc(cgiContentLength);
00306   if (!input) {
00307     return cgiParseMemory;  
00308   }
00309   if (((int) fread(input, 1, cgiContentLength, cgiIn)) 
00310     != cgiContentLength) 
00311   {
00312     return cgiParseIO;
00313   } 
00314   result = cgiParseFormInput(input, cgiContentLength);
00315   free(input);
00316   return result;
00317 }
00318 
00319 
00320 
00321 
00322 
00323 typedef struct {
00324   
00325   char putback[1024]; 
00326   
00327 
00328 
00329   int readPos;
00330   
00331 
00332 
00333 
00334 
00335   int writePos;
00336   
00337 
00338   int offset;
00339 } mpStream, *mpStreamPtr;
00340 
00341 int mpRead(mpStreamPtr mpp, char *buffer, int len)
00342 {
00343   int ilen = len;
00344   int got = 0;
00345   while (len) {
00346     if (mpp->readPos != mpp->writePos) {
00347       *buffer++ = mpp->putback[mpp->readPos++];
00348       mpp->readPos %= sizeof(mpp->putback);
00349       got++;
00350       len--;
00351     } else {
00352       break;
00353     } 
00354   }
00355   
00356 
00357   if (len > (cgiContentLength - mpp->offset)) {
00358     len = cgiContentLength - mpp->offset;
00359   }
00360   if (len) {
00361     int fgot = fread(buffer, 1, len, cgiIn);
00362     if (fgot >= 0) {
00363       mpp->offset += (got + fgot);
00364       return got + fgot;
00365     } else if (got > 0) {
00366       mpp->offset += got;
00367       return got;
00368     } else {
00369       
00370       return fgot;
00371     }
00372   } else if (got) {
00373     return got;
00374   } else if (ilen) {  
00375     return EOF;
00376   } else {
00377     
00378     return 0;
00379   }
00380 }
00381 
00382 void mpPutBack(mpStreamPtr mpp, char *data, int len)
00383 {
00384   mpp->offset -= len;
00385   while (len) {
00386     mpp->putback[mpp->writePos++] = *data++;
00387     mpp->writePos %= sizeof(mpp->putback);
00388     len--;
00389   }
00390 }
00391 
00392 
00393 
00394 
00395 
00396 
00397 
00398 
00399 
00400 
00401 
00402 
00403 
00404 
00405 
00406 static cgiParseResultType afterNextBoundary(mpStreamPtr mpp,
00407   FILE *outf,
00408   char **outP,
00409   int *bodyLengthP,
00410   int first
00411   );
00412 
00413 static int readHeaderLine(
00414   mpStreamPtr mpp,  
00415   char *attr,
00416   int attrSpace,
00417   char *value,
00418   int valueSpace);
00419 
00420 static void decomposeValue(char *value,
00421   char *mvalue, int mvalueSpace,
00422   char **argNames,
00423   char **argValues,
00424   int argValueSpace);
00425 
00426 
00427 
00428 
00429 
00430 
00431   
00432 static cgiParseResultType getTempFileName(char *tfileName);
00433 
00434 static cgiParseResultType cgiParsePostMultipartInput() {
00435   cgiParseResultType result;
00436   cgiFormEntry *n = 0, *l = 0;
00437   int got;
00438   FILE *outf = 0;
00439   char *out = 0;
00440   char tfileName[1024];
00441   mpStream mp;
00442   mpStreamPtr mpp = ∓
00443   memset(&mp, 0, sizeof(mp));
00444   if (!cgiContentLength) {
00445     return cgiParseSuccess;
00446   }
00447   
00448   result = afterNextBoundary(mpp, 0, 0, 0, 1);
00449   if (result == cgiParseIO) { 
00450     
00451     return cgiParseSuccess;
00452   } else if (result != cgiParseSuccess) {
00453     return result;
00454   }
00455   while (1) {
00456     char d[1024];
00457     char fvalue[1024];
00458     char fname[1024];
00459     int bodyLength = 0;
00460     char ffileName[1024];
00461     char fcontentType[1024];
00462     char attr[1024];
00463     char value[1024];
00464     fvalue[0] = 0;
00465     fname[0] = 0;
00466     ffileName[0] = 0;
00467     fcontentType[0] = 0;
00468     out = 0;
00469     outf = 0;
00470     
00471     got = mpRead(mpp, d, 2);
00472     if (got < 2) {
00473       
00474       break;
00475     }
00476     if ((d[0] == '-') && (d[1] == '-')) {
00477       
00478       break;
00479     }
00480     mpPutBack(mpp, d, 2);
00481     
00482     while (readHeaderLine(
00483         mpp, attr, sizeof(attr), value, sizeof(value))) 
00484     {
00485       char *argNames[3];
00486       char *argValues[2];
00487       
00488 
00489       if (cgiStrEqNc(attr, "Content-Disposition")) {
00490         argNames[0] = "name";
00491         argNames[1] = "filename";
00492         argNames[2] = 0;
00493         argValues[0] = fname;
00494         argValues[1] = ffileName;
00495         decomposeValue(value, 
00496           fvalue, sizeof(fvalue),
00497           argNames,
00498           argValues,
00499           1024);  
00500       } else if (cgiStrEqNc(attr, "Content-Type")) {
00501         argNames[0] = 0;
00502         decomposeValue(value, 
00503           fcontentType, sizeof(fcontentType),
00504           argNames,
00505           0,
00506           0);
00507       }
00508     }
00509     if (!cgiStrEqNc(fvalue, "form-data")) {
00510        
00511       continue;
00512     }
00513     
00514 
00515 
00516 
00517 
00518 
00519     if (strlen(ffileName)) {
00520       if (getTempFileName(tfileName) != cgiParseSuccess) {
00521         return cgiParseIO;
00522       } 
00523       outf = fopen(tfileName, "w+b");
00524     } else {
00525       outf = 0;
00526       tfileName[0] = '\0';
00527     } 
00528     result = afterNextBoundary(mpp, outf, &out, &bodyLength, 0);
00529     if (result != cgiParseSuccess) {
00530       
00531       if (outf) {
00532         fclose(outf);
00533         unlink(tfileName);
00534       }
00535       if (out) {
00536         free(out);
00537       }
00538       return result;
00539     }
00540     
00541     n = (cgiFormEntry *) malloc(sizeof(cgiFormEntry));  
00542     if (!n) {
00543       goto outOfMemory;
00544     }
00545     memset(n, 0, sizeof(cgiFormEntry));
00546     
00547 
00548     n->attr = (char *) malloc(strlen(fname) + 1);
00549     if (!n->attr) {
00550       goto outOfMemory;
00551     }
00552     strcpy(n->attr, fname);
00553     if (out) {
00554       n->value = out;
00555       out = 0;
00556     } else if (outf) {
00557       n->value = (char *) malloc(1);
00558       if (!n->value) {
00559         goto outOfMemory;
00560       }
00561       n->value[0] = '\0';
00562       fclose(outf);
00563     }
00564     n->valueLength = bodyLength;
00565     n->next = 0;
00566     if (!l) {
00567       cgiFormEntryFirst = n;
00568     } else {
00569       l->next = n;
00570     }
00571     n->fileName = (char *) malloc(strlen(ffileName) + 1);
00572     if (!n->fileName) {
00573       goto outOfMemory;
00574     }
00575     strcpy(n->fileName, ffileName);
00576     n->contentType = (char *) malloc(strlen(fcontentType) + 1);
00577     if (!n->contentType) {
00578       goto outOfMemory;
00579     }
00580     strcpy(n->contentType, fcontentType);
00581     n->tfileName = (char *) malloc(strlen(tfileName) + 1);
00582     if (!n->tfileName) {
00583       goto outOfMemory;
00584     }
00585     strcpy(n->tfileName, tfileName);
00586 
00587     l = n;      
00588   } 
00589   return cgiParseSuccess;
00590 outOfMemory:
00591   if (n) {
00592     if (n->attr) {
00593       free(n->attr);
00594     }
00595     if (n->value) {
00596       free(n->value);
00597     }
00598     if (n->fileName) {
00599       free(n->fileName);
00600     }
00601     if (n->tfileName) {
00602       free(n->tfileName);
00603     }
00604     if (n->contentType) {
00605       free(n->contentType);
00606     }
00607     free(n);
00608   }
00609   if (out) {
00610     free(out);
00611   }
00612   if (outf) {
00613     fclose(outf);
00614     unlink(tfileName);
00615   }
00616   return cgiParseMemory;
00617 }
00618 
00619 static cgiParseResultType getTempFileName(char *tfileName)
00620 {
00621 #ifndef WIN32
00622   
00623 
00624 
00625 
00626 
00627 
00628 
00629 
00630   int outfd; 
00631   strcpy(tfileName, cgicTempDir "/cgicXXXXXX");
00632   outfd = mkstemp(tfileName);
00633   if (outfd == -1) {
00634     return cgiParseIO;
00635   }
00636   close(outfd);
00637   
00638   if (chmod(tfileName, 0600) != 0) {
00639     unlink(tfileName);
00640     return cgiParseIO;
00641   }
00642 #else
00643   
00644   if (!tmpnam(tfileName)) {
00645     return cgiParseIO;
00646   }
00647 #endif
00648   return cgiParseSuccess;
00649 }
00650 
00651 
00652 #define APPEND(string, char) \
00653   { \
00654     if ((string##Len + 1) < string##Space) { \
00655       string[string##Len++] = (char); \
00656     } \
00657   }
00658 
00659 #define RAPPEND(string, ch) \
00660   { \
00661     if ((string##Len + 1) == string##Space)  { \
00662       char *sold = string; \
00663       string##Space *= 2; \
00664       string = (char *) realloc(string, string##Space); \
00665       if (!string) { \
00666         string = sold; \
00667         goto outOfMemory; \
00668       } \
00669     } \
00670     string[string##Len++] = (ch); \
00671   }
00672     
00673 #define BAPPEND(ch) \
00674   { \
00675     if (outf) { \
00676       putc(ch, outf); \
00677       outLen++; \
00678     } else if (out) { \
00679       RAPPEND(out, ch); \
00680     } \
00681   }
00682 
00683 cgiParseResultType afterNextBoundary(mpStreamPtr mpp, FILE *outf, char **outP,
00684   int *bodyLengthP, int first)
00685 {
00686   int outLen = 0;
00687   int outSpace = 256;
00688   char *out = 0;
00689   cgiParseResultType result;
00690   int boffset;
00691   int got;
00692   char d[2];  
00693   
00694 
00695 
00696 
00697   char workingBoundaryData[1024];
00698   char *workingBoundary = workingBoundaryData;
00699   int workingBoundaryLength;
00700   if ((!outf) && (outP)) {
00701     out = (char *) malloc(outSpace);
00702     if (!out) {
00703       goto outOfMemory;
00704     }
00705   }
00706   boffset = 0;
00707   sprintf(workingBoundaryData, "\r\n--%s", cgiMultipartBoundary);
00708   if (first) {
00709     workingBoundary = workingBoundaryData + 2;
00710   }
00711   workingBoundaryLength = strlen(workingBoundary);
00712   while (1) {
00713     got = mpRead(mpp, d, 1);
00714     if (got != 1) {
00715       
00716       result = cgiParseIO;
00717       goto error;
00718     }
00719     if (d[0] == workingBoundary[boffset]) {
00720       
00721 
00722 
00723       boffset++;
00724       if (boffset == workingBoundaryLength) {
00725         break;
00726       } 
00727     } else if (boffset > 0) {
00728       
00729 
00730 
00731 
00732 
00733 
00734 
00735       BAPPEND(workingBoundary[0]);
00736       mpPutBack(mpp, 
00737         workingBoundary + 1, boffset - 1);
00738       mpPutBack(mpp, d, 1);
00739       boffset = 0;
00740     } else {    
00741       
00742 
00743       BAPPEND(d[0]);
00744     } 
00745   }
00746   
00747 
00748   got = mpRead(mpp, d, 2);
00749   if (got != 2) {
00750     result = cgiParseIO;
00751     goto error;
00752   } 
00753   if ((d[0] == '\r') && (d[1] == '\n')) {
00754     
00755   } else if (d[0] == '-') {
00756     
00757 
00758     mpPutBack(mpp, d, 2);
00759   } 
00760   if (out && outSpace) {
00761     char *oout = out;
00762     out[outLen] = '\0';
00763     out = (char *) realloc(out, outLen + 1);
00764     if (!out) {
00765       
00766 
00767 
00768       out = oout;
00769     }
00770     *outP = out;
00771   }
00772   if (bodyLengthP) {
00773     *bodyLengthP = outLen;
00774   }
00775   return cgiParseSuccess;
00776 outOfMemory:
00777   result = cgiParseMemory;
00778   if (outP) {
00779     if (out) {
00780       free(out);
00781     }
00782     *outP = '\0'; 
00783   }
00784 error:
00785   if (bodyLengthP) {
00786     *bodyLengthP = 0;
00787   }
00788   if (out) {
00789     free(out);
00790   }
00791   if (outP) {
00792     *outP = 0;  
00793   }
00794   return result;
00795 }
00796 
00797 static void decomposeValue(char *value,
00798   char *mvalue, int mvalueSpace,
00799   char **argNames,
00800   char **argValues,
00801   int argValueSpace)
00802 {
00803   char argName[1024];
00804   int argNameSpace = sizeof(argName);
00805   int argNameLen = 0;
00806   int mvalueLen = 0;
00807   char *argValue;
00808   int argNum = 0;
00809   while (argNames[argNum]) {
00810     if (argValueSpace) {
00811       argValues[argNum][0] = '\0';
00812     }
00813     argNum++;
00814   }
00815   while (isspace(*value)) {
00816     value++;
00817   }
00818   
00819   if (*value == '\"') {
00820     value++;
00821     while ((*value) && (*value != '\"')) {
00822       APPEND(mvalue, *value);
00823       value++;
00824     }
00825     while ((*value) && (*value != ';')) {
00826       value++;
00827     }
00828   } else {
00829     
00830     while ((*value) && (*value != ';')) {
00831       APPEND(mvalue, *value);
00832       value++;
00833     } 
00834   } 
00835   if (mvalueSpace) {
00836     mvalue[mvalueLen] = '\0';
00837   }
00838   while (*value == ';') {
00839     int argNum;
00840     int argValueLen = 0;
00841     
00842     value++;
00843     
00844     while ((*value) && (isspace(*value))) { 
00845       value++;
00846     }
00847     
00848     argNameLen = 0;
00849     while ((*value) && (isalnum(*value))) {
00850       APPEND(argName, *value);
00851       value++;
00852     }
00853     if (argNameSpace) {
00854       argName[argNameLen] = '\0';
00855     }
00856     while ((*value) && isspace(*value)) {
00857       value++;
00858     }
00859     if (*value != '=') {
00860       
00861       return; 
00862     }
00863     value++;
00864     while ((*value) && isspace(*value)) {
00865       value++;
00866     }
00867     
00868     argNum = 0;
00869     argValue = 0;
00870     while (argNames[argNum]) {
00871       if (cgiStrEqNc(argName, argNames[argNum])) {
00872         argValue = argValues[argNum];
00873         break;
00874       }
00875       argNum++;
00876     }   
00877     
00878     if (*value == '\"') {
00879       value++;
00880       while ((*value) && (*value != '\"')) {
00881         if (argValue) {
00882           APPEND(argValue, *value);
00883         }
00884         value++;
00885       }
00886       while ((*value) && (*value != ';')) {
00887         value++;
00888       }
00889     } else {
00890       
00891       while ((*value) && (*value != ';')) {
00892         if (argNames[argNum]) {
00893           APPEND(argValue, *value);
00894         }
00895         value++;
00896       } 
00897     } 
00898     if (argValueSpace) {
00899       argValue[argValueLen] = '\0';
00900     }
00901   }   
00902 }
00903 
00904 static int readHeaderLine(
00905   mpStreamPtr mpp,
00906   char *attr,
00907   int attrSpace,
00908   char *value,
00909   int valueSpace)
00910 { 
00911   int attrLen = 0;
00912   int valueLen = 0;
00913   int valueFound = 0;
00914   while (1) {
00915     char d[1];
00916     int got = mpRead(mpp, d, 1);
00917     if (got != 1) { 
00918       return 0;
00919     }
00920     if (d[0] == '\r') {
00921       got = mpRead(mpp, d, 1);
00922       if (got == 1) { 
00923         if (d[0] == '\n') {
00924           
00925         } else {
00926           mpPutBack(mpp, d, 1);
00927         }
00928       }
00929       break;
00930     } else if (d[0] == '\n') {
00931       break;
00932     } else if ((d[0] == ':') && attrLen) {
00933       valueFound = 1;
00934       while (mpRead(mpp, d, 1) == 1) {
00935         if (!isspace(d[0])) {
00936           mpPutBack(mpp, d, 1);
00937           break;
00938         } 
00939       }
00940     } else if (!valueFound) {
00941       if (!isspace(*d)) {
00942         if (attrLen < (attrSpace - 1)) {
00943           attr[attrLen++] = *d;
00944         }
00945       }   
00946     } else if (valueFound) {  
00947       if (valueLen < (valueSpace - 1)) {
00948         value[valueLen++] = *d;
00949       }
00950     }
00951   }
00952   if (attrSpace) {
00953     attr[attrLen] = '\0';
00954   }
00955   if (valueSpace) {
00956     value[valueLen] = '\0';
00957   }
00958   if (attrLen && valueLen) {
00959     return 1;
00960   } else {
00961     return 0;
00962   }
00963 }
00964 
00965 static cgiParseResultType cgiParseGetFormInput() {
00966   return cgiParseFormInput(cgiQueryString, cgiContentLength);
00967 }
00968 
00969 typedef enum {
00970   cgiEscapeRest,
00971   cgiEscapeFirst,
00972   cgiEscapeSecond
00973 } cgiEscapeState;
00974 
00975 typedef enum {
00976   cgiUnescapeSuccess,
00977   cgiUnescapeMemory
00978 } cgiUnescapeResultType;
00979 
00980 static cgiUnescapeResultType cgiUnescapeChars(char **sp, char *cp, int len);
00981 
00982 static cgiParseResultType cgiParseFormInput(char *data, int length) {
00983   
00984   int pos = 0;
00985   cgiFormEntry *n;
00986   cgiFormEntry *l = 0;
00987   while (pos != length) {
00988     int foundEq = 0;
00989     int foundAmp = 0;
00990     int start = pos;
00991     int len = 0;
00992     char *attr;
00993     char *value;
00994     while (pos != length) {
00995       if (data[pos] == '=') {
00996         foundEq = 1;
00997         pos++;
00998         break;
00999       }
01000       pos++;
01001       len++;
01002     }
01003     if (!foundEq) {
01004       break;
01005     }
01006     if (cgiUnescapeChars(&attr, data+start, len)
01007       != cgiUnescapeSuccess) {
01008       return cgiParseMemory;
01009     } 
01010     start = pos;
01011     len = 0;
01012     while (pos != length) {
01013       if (data[pos] == '&') {
01014         foundAmp = 1;
01015         pos++;
01016         break;
01017       }
01018       pos++;
01019       len++;
01020     }
01021     
01022 
01023     if (cgiUnescapeChars(&value, data+start, len)
01024       != cgiUnescapeSuccess) {
01025       free(attr);
01026       return cgiParseMemory;
01027     } 
01028     
01029     n = (cgiFormEntry *) malloc(sizeof(cgiFormEntry));  
01030     if (!n) {
01031       free(attr);
01032       free(value);
01033       return cgiParseMemory;
01034     }
01035     n->attr = attr;
01036     n->value = value;
01037     n->valueLength = strlen(n->value);
01038     n->fileName = (char *) malloc(1);
01039     if (!n->fileName) {
01040       free(attr);
01041       free(value);
01042       free(n);
01043       return cgiParseMemory;
01044     } 
01045     n->fileName[0] = '\0';
01046     n->contentType = (char *) malloc(1);
01047     if (!n->contentType) {
01048       free(attr);
01049       free(value);
01050       free(n->fileName);
01051       free(n);
01052       return cgiParseMemory;
01053     } 
01054     n->contentType[0] = '\0';
01055     n->tfileName = (char *) malloc(1);
01056     if (!n->tfileName) {
01057       free(attr);
01058       free(value);
01059       free(n->fileName);
01060       free(n->contentType);
01061       free(n);
01062       return cgiParseMemory;
01063     } 
01064     n->tfileName[0] = '\0';
01065     n->next = 0;
01066     if (!l) {
01067       cgiFormEntryFirst = n;
01068     } else {
01069       l->next = n;
01070     }
01071     l = n;
01072     if (!foundAmp) {
01073       break;
01074     }     
01075   }
01076   return cgiParseSuccess;
01077 }
01078 
01079 static int cgiHexValue[256];
01080 
01081 cgiUnescapeResultType cgiUnescapeChars(char **sp, char *cp, int len) {
01082   char *s;
01083   cgiEscapeState escapeState = cgiEscapeRest;
01084   int escapedValue = 0;
01085   int srcPos = 0;
01086   int dstPos = 0;
01087   s = (char *) malloc(len + 1);
01088   if (!s) {
01089     return cgiUnescapeMemory;
01090   }
01091   while (srcPos < len) {
01092     int ch = cp[srcPos];
01093     switch (escapeState) {
01094       case cgiEscapeRest:
01095       if (ch == '%') {
01096         escapeState = cgiEscapeFirst;
01097       } else if (ch == '+') {
01098         s[dstPos++] = ' ';
01099       } else {
01100         s[dstPos++] = ch; 
01101       }
01102       break;
01103       case cgiEscapeFirst:
01104       escapedValue = cgiHexValue[ch] << 4;  
01105       escapeState = cgiEscapeSecond;
01106       break;
01107       case cgiEscapeSecond:
01108       escapedValue += cgiHexValue[ch];
01109       s[dstPos++] = escapedValue;
01110       escapeState = cgiEscapeRest;
01111       break;
01112     }
01113     srcPos++;
01114   }
01115   s[dstPos] = '\0';
01116   *sp = s;
01117   return cgiUnescapeSuccess;
01118 }   
01119   
01120 static void cgiSetupConstants() {
01121   int i;
01122   for (i=0; (i < 256); i++) {
01123     cgiHexValue[i] = 0;
01124   }
01125   cgiHexValue['0'] = 0; 
01126   cgiHexValue['1'] = 1; 
01127   cgiHexValue['2'] = 2; 
01128   cgiHexValue['3'] = 3; 
01129   cgiHexValue['4'] = 4; 
01130   cgiHexValue['5'] = 5; 
01131   cgiHexValue['6'] = 6; 
01132   cgiHexValue['7'] = 7; 
01133   cgiHexValue['8'] = 8; 
01134   cgiHexValue['9'] = 9;
01135   cgiHexValue['A'] = 10;
01136   cgiHexValue['B'] = 11;
01137   cgiHexValue['C'] = 12;
01138   cgiHexValue['D'] = 13;
01139   cgiHexValue['E'] = 14;
01140   cgiHexValue['F'] = 15;
01141   cgiHexValue['a'] = 10;
01142   cgiHexValue['b'] = 11;
01143   cgiHexValue['c'] = 12;
01144   cgiHexValue['d'] = 13;
01145   cgiHexValue['e'] = 14;
01146   cgiHexValue['f'] = 15;
01147 }
01148 
01149 static void cgiFreeResources() {
01150   cgiFormEntry *c = cgiFormEntryFirst;
01151   cgiFormEntry *n;
01152   while (c) {
01153     n = c->next;
01154     free(c->attr);
01155     free(c->value);
01156     free(c->fileName);
01157     free(c->contentType);
01158     if (strlen(c->tfileName)) {
01159       unlink(c->tfileName);
01160     }
01161     free(c->tfileName);
01162     free(c);
01163     c = n;
01164   }
01165   
01166 
01167   if (cgiRestored) {
01168     free(cgiServerSoftware);
01169     free(cgiServerName);
01170     free(cgiGatewayInterface);
01171     free(cgiServerProtocol);
01172     free(cgiServerPort);
01173     free(cgiRequestMethod);
01174     free(cgiPathInfo);
01175     free(cgiPathTranslated);
01176     free(cgiScriptName);
01177     free(cgiQueryString);
01178     free(cgiRemoteHost);
01179     free(cgiRemoteAddr);
01180     free(cgiAuthType);
01181     free(cgiRemoteUser);
01182     free(cgiRemoteIdent);
01183     free(cgiContentType);
01184     free(cgiAccept);
01185     free(cgiUserAgent);
01186     free(cgiReferrer);
01187   }
01188   
01189 
01190   cgiFormEntryFirst = 0;
01191   cgiRestored = 0;
01192 }
01193 
01194 static cgiFormResultType cgiFormEntryString(
01195   cgiFormEntry *e, char *result, int max, int newlines);
01196 
01197 static cgiFormEntry *cgiFormEntryFindFirst(char *name);
01198 static cgiFormEntry *cgiFormEntryFindNext();
01199 
01200 cgiFormResultType cgiFormString(
01201         char *name, char *result, int max) {
01202   cgiFormEntry *e;
01203   e = cgiFormEntryFindFirst(name);
01204   if (!e) {
01205     strcpy(result, "");
01206     return cgiFormNotFound;
01207   }
01208   return cgiFormEntryString(e, result, max, 1);
01209 }
01210 
01211 cgiFormResultType cgiFormFileName(
01212   char *name, char *result, int resultSpace)
01213 {
01214   cgiFormEntry *e;
01215   int resultLen = 0;
01216   char *s;
01217   e = cgiFormEntryFindFirst(name);
01218   if (!e) {
01219     strcpy(result, "");
01220     return cgiFormNotFound;
01221   }
01222   s = e->fileName;
01223   while (*s) {
01224     APPEND(result, *s);
01225     s++;
01226   } 
01227   if (resultSpace) {
01228     result[resultLen] = '\0';
01229   }
01230   if (!strlen(e->fileName)) {
01231     return cgiFormNoFileName;
01232   } else if (((int) strlen(e->fileName)) > (resultSpace - 1)) {
01233     return cgiFormTruncated;
01234   } else {
01235     return cgiFormSuccess;
01236   }
01237 }
01238 
01239 cgiFormResultType cgiFormFileContentType(
01240   char *name, char *result, int resultSpace)
01241 {
01242   cgiFormEntry *e;
01243   int resultLen = 0;
01244   char *s;
01245   e = cgiFormEntryFindFirst(name);
01246   if (!e) {
01247     if (resultSpace) {
01248       result[0] = '\0';
01249     } 
01250     return cgiFormNotFound;
01251   }
01252   s = e->contentType;
01253   while (*s) {
01254     APPEND(result, *s);
01255     s++;
01256   } 
01257   if (resultSpace) {
01258     result[resultLen] = '\0';
01259   }
01260   if (!strlen(e->contentType)) {
01261     return cgiFormNoContentType;
01262   } else if (((int) strlen(e->contentType)) > (resultSpace - 1)) {
01263     return cgiFormTruncated;
01264   } else {
01265     return cgiFormSuccess;
01266   }
01267 }
01268 
01269 cgiFormResultType cgiFormFileSize(
01270   char *name, int *sizeP)
01271 {
01272   cgiFormEntry *e;
01273   e = cgiFormEntryFindFirst(name);
01274   if (!e) {
01275     if (sizeP) {
01276       *sizeP = 0;
01277     }
01278     return cgiFormNotFound;
01279   } else if (!strlen(e->tfileName)) {
01280     if (sizeP) {
01281       *sizeP = 0;
01282     }
01283     return cgiFormNotAFile;
01284   } else {
01285     if (sizeP) {
01286       *sizeP = e->valueLength;
01287     }
01288     return cgiFormSuccess;
01289   }
01290 }
01291 
01292 typedef struct cgiFileStruct {
01293   FILE *in;
01294 } cgiFile;
01295 
01296 cgiFormResultType cgiFormFileOpen(
01297   char *name, cgiFilePtr *cfpp)
01298 {
01299   cgiFormEntry *e;
01300   cgiFilePtr cfp;
01301   e = cgiFormEntryFindFirst(name);
01302   if (!e) {
01303     *cfpp = 0;
01304     return cgiFormNotFound;
01305   }
01306   if (!strlen(e->tfileName)) {
01307     *cfpp = 0;
01308     return cgiFormNotAFile;
01309   }
01310   cfp = (cgiFilePtr) malloc(sizeof(cgiFile));
01311   if (!cfp) {
01312     *cfpp = 0;
01313     return cgiFormMemory;
01314   }
01315   cfp->in = fopen(e->tfileName, "rb");
01316   if (!cfp->in) {
01317     free(cfp);
01318     return cgiFormIO;
01319   }
01320   *cfpp = cfp;
01321   return cgiFormSuccess;
01322 }
01323 
01324 cgiFormResultType cgiFormFileRead(
01325   cgiFilePtr cfp, char *buffer, 
01326   int bufferSize, int *gotP)
01327 {
01328   int got = 0;
01329   if (!cfp) {
01330     return cgiFormOpenFailed;
01331   }
01332   got = fread(buffer, 1, bufferSize, cfp->in);
01333   if (got <= 0) {
01334     return cgiFormEOF;
01335   }
01336   *gotP = got;
01337   return cgiFormSuccess;
01338 }
01339 
01340 cgiFormResultType cgiFormFileClose(cgiFilePtr cfp)
01341 {
01342   if (!cfp) {
01343     return cgiFormOpenFailed;
01344   }
01345   fclose(cfp->in);
01346   free(cfp);
01347   return cgiFormSuccess;
01348 }
01349 
01350 cgiFormResultType cgiFormStringNoNewlines(
01351         char *name, char *result, int max) {
01352   cgiFormEntry *e;
01353   e = cgiFormEntryFindFirst(name);
01354   if (!e) {
01355     strcpy(result, "");
01356     return cgiFormNotFound;
01357   }
01358   return cgiFormEntryString(e, result, max, 0);
01359 }
01360 
01361 cgiFormResultType cgiFormStringMultiple(
01362         char *name, char ***result) {
01363   char **stringArray;
01364   cgiFormEntry *e;
01365   int i;
01366   int total = 0;
01367   
01368 
01369 
01370   e = cgiFormEntryFindFirst(name);
01371   if (e != 0) {
01372     do {
01373       total++;
01374     } while ((e = cgiFormEntryFindNext()) != 0); 
01375   }
01376   stringArray = (char **) malloc(sizeof(char *) * (total + 1));
01377   if (!stringArray) {
01378     *result = 0;
01379     return cgiFormMemory;
01380   }
01381   
01382   for (i=0; (i <= total); i++) {
01383     stringArray[i] = 0;
01384   }
01385   
01386   e = cgiFormEntryFindFirst(name);
01387 #ifdef CGICDEBUG
01388   CGICDEBUGSTART
01389   fprintf(dout, "StringMultiple Beginning\n");
01390   CGICDEBUGEND
01391 #endif 
01392   if (e) {
01393     i = 0;
01394     do {
01395       int max = (int) (strlen(e->value) + 1);
01396       stringArray[i] = (char *) malloc(max);
01397       if (stringArray[i] == 0) {
01398         
01399         cgiStringArrayFree(stringArray);
01400         *result = 0;
01401         return cgiFormMemory;
01402       } 
01403       strcpy(stringArray[i], e->value);
01404       cgiFormEntryString(e, stringArray[i], max, 1);
01405       i++;
01406     } while ((e = cgiFormEntryFindNext()) != 0); 
01407     *result = stringArray;
01408 #ifdef CGICDEBUG
01409     CGICDEBUGSTART
01410     fprintf(dout, "StringMultiple Succeeding\n");
01411     CGICDEBUGEND
01412 #endif 
01413     return cgiFormSuccess;
01414   } else {
01415     *result = stringArray;
01416 #ifdef CGICDEBUG
01417     CGICDEBUGSTART
01418     fprintf(dout, "StringMultiple found nothing\n");
01419     CGICDEBUGEND
01420 #endif 
01421     return cgiFormNotFound;
01422   } 
01423 }
01424 
01425 cgiFormResultType cgiFormStringSpaceNeeded(
01426         char *name, int *result) {
01427   cgiFormEntry *e;
01428   e = cgiFormEntryFindFirst(name);
01429   if (!e) {
01430     *result = 1;
01431     return cgiFormNotFound; 
01432   }
01433   *result = ((int) strlen(e->value)) + 1;
01434   return cgiFormSuccess;
01435 }
01436 
01437 static cgiFormResultType cgiFormEntryString(
01438   cgiFormEntry *e, char *result, int max, int newlines) {
01439   char *dp, *sp;
01440   int truncated = 0;
01441   int len = 0;
01442   int avail = max-1;
01443   int crCount = 0;
01444   int lfCount = 0;  
01445   dp = result;
01446   sp = e->value;  
01447   while (1) {
01448     int ch;
01449     
01450 
01451 
01452 
01453 
01454     ch = *sp;
01455     
01456 
01457 
01458 
01459 
01460 
01461     if ((ch == 13) || (ch == 10)) {
01462       if (ch == 13) {
01463         crCount++;
01464       } else {
01465         lfCount++;
01466       } 
01467     } else {
01468       if (crCount || lfCount) {
01469         int lfsAdd = crCount;
01470         if (lfCount > crCount) {
01471           lfsAdd = lfCount;
01472         }
01473         
01474         if (!newlines) {
01475           lfsAdd = 0;
01476         }
01477         while (lfsAdd) {
01478           if (len >= avail) {
01479             truncated = 1;
01480             break;
01481           }
01482           *dp = 10;
01483           dp++;
01484           lfsAdd--;
01485           len++;    
01486         }
01487         crCount = 0;
01488         lfCount = 0;
01489       }
01490       if (ch == '\0') {
01491         
01492         break;        
01493       } 
01494       
01495 
01496 
01497       if (len >= avail) {
01498         truncated = 1;
01499         break;
01500       }
01501       *dp = ch;
01502       dp++;
01503       len++;
01504     }
01505     sp++; 
01506   } 
01507   *dp = '\0';
01508   if (truncated) {
01509     return cgiFormTruncated;
01510   } else if (!len) {
01511     return cgiFormEmpty;
01512   } else {
01513     return cgiFormSuccess;
01514   }
01515 }
01516 
01517 static int cgiFirstNonspaceChar(char *s);
01518 
01519 cgiFormResultType cgiFormInteger(
01520         char *name, int *result, int defaultV) {
01521   cgiFormEntry *e;
01522   int ch;
01523   e = cgiFormEntryFindFirst(name);
01524   if (!e) {
01525     *result = defaultV;
01526     return cgiFormNotFound; 
01527   } 
01528   if (!strlen(e->value)) {
01529     *result = defaultV;
01530     return cgiFormEmpty;
01531   }
01532   ch = cgiFirstNonspaceChar(e->value);
01533   if (!(isdigit(ch)) && (ch != '-') && (ch != '+')) {
01534     *result = defaultV;
01535     return cgiFormBadType;
01536   } else {
01537     *result = atoi(e->value);
01538     return cgiFormSuccess;
01539   }
01540 }
01541 
01542 cgiFormResultType cgiFormIntegerBounded(
01543         char *name, int *result, int min, int max, int defaultV) {
01544   cgiFormResultType error = cgiFormInteger(name, result, defaultV);
01545   if (error != cgiFormSuccess) {
01546     return error;
01547   }
01548   if (*result < min) {
01549     *result = min;
01550     return cgiFormConstrained;
01551   } 
01552   if (*result > max) {
01553     *result = max;
01554     return cgiFormConstrained;
01555   } 
01556   return cgiFormSuccess;
01557 }
01558 
01559 cgiFormResultType cgiFormDouble(
01560         char *name, double *result, double defaultV) {
01561   cgiFormEntry *e;
01562   int ch;
01563   e = cgiFormEntryFindFirst(name);
01564   if (!e) {
01565     *result = defaultV;
01566     return cgiFormNotFound; 
01567   } 
01568   if (!strlen(e->value)) {
01569     *result = defaultV;
01570     return cgiFormEmpty;
01571   } 
01572   ch = cgiFirstNonspaceChar(e->value);
01573   if (!(isdigit(ch)) && (ch != '.') && (ch != '-') && (ch != '+')) {
01574     *result = defaultV;
01575     return cgiFormBadType;
01576   } else {
01577     *result = atof(e->value);
01578     return cgiFormSuccess;
01579   }
01580 }
01581 
01582 cgiFormResultType cgiFormDoubleBounded(
01583         char *name, double *result, double min, double max, double defaultV) {
01584   cgiFormResultType error = cgiFormDouble(name, result, defaultV);
01585   if (error != cgiFormSuccess) {
01586     return error;
01587   }
01588   if (*result < min) {
01589     *result = min;
01590     return cgiFormConstrained;
01591   } 
01592   if (*result > max) {
01593     *result = max;
01594     return cgiFormConstrained;
01595   } 
01596   return cgiFormSuccess;
01597 }
01598 
01599 cgiFormResultType cgiFormSelectSingle(
01600   char *name, char **choicesText, int choicesTotal, 
01601   int *result, int defaultV) 
01602 {
01603   cgiFormEntry *e;
01604   int i;
01605   e = cgiFormEntryFindFirst(name);
01606 #ifdef CGICDEBUG
01607   CGICDEBUGSTART
01608   fprintf(dout, "%d\n", (int) e);
01609   CGICDEBUGEND
01610 #endif 
01611   if (!e) {
01612     *result = defaultV;
01613     return cgiFormNotFound;
01614   }
01615   for (i=0; (i < choicesTotal); i++) {
01616 #ifdef CGICDEBUG
01617     CGICDEBUGSTART
01618     fprintf(dout, "%s %s\n", choicesText[i], e->value);
01619     CGICDEBUGEND
01620 #endif 
01621     if (cgiStrEq(choicesText[i], e->value)) {
01622 #ifdef CGICDEBUG
01623       CGICDEBUGSTART
01624       fprintf(dout, "MATCH\n");
01625       CGICDEBUGEND
01626 #endif 
01627       *result = i;
01628       return cgiFormSuccess;
01629     }
01630   }
01631   *result = defaultV;
01632   return cgiFormNoSuchChoice;
01633 }
01634 
01635 cgiFormResultType cgiFormSelectMultiple(
01636   char *name, char **choicesText, int choicesTotal, 
01637   int *result, int *invalid) 
01638 {
01639   cgiFormEntry *e;
01640   int i;
01641   int hits = 0;
01642   int invalidE = 0;
01643   for (i=0; (i < choicesTotal); i++) {
01644     result[i] = 0;
01645   }
01646   e = cgiFormEntryFindFirst(name);
01647   if (!e) {
01648     *invalid = invalidE;
01649     return cgiFormNotFound;
01650   }
01651   do {
01652     int hit = 0;
01653     for (i=0; (i < choicesTotal); i++) {
01654       if (cgiStrEq(choicesText[i], e->value)) {
01655         result[i] = 1;
01656         hits++;
01657         hit = 1;
01658         break;
01659       }
01660     }
01661     if (!(hit)) {
01662       invalidE++;
01663     }
01664   } while ((e = cgiFormEntryFindNext()) != 0);
01665 
01666   *invalid = invalidE;
01667 
01668   if (hits) {
01669     return cgiFormSuccess;
01670   } else {
01671     return cgiFormNotFound;
01672   }
01673 }
01674 
01675 cgiFormResultType cgiFormCheckboxSingle(
01676   char *name)
01677 {
01678   cgiFormEntry *e;
01679   e = cgiFormEntryFindFirst(name);
01680   if (!e) {
01681     return cgiFormNotFound;
01682   }
01683   return cgiFormSuccess;
01684 }
01685 
01686 extern cgiFormResultType cgiFormCheckboxMultiple(
01687   char *name, char **valuesText, int valuesTotal, 
01688   int *result, int *invalid)
01689 {
01690   
01691   return cgiFormSelectMultiple(name, valuesText, 
01692     valuesTotal, result, invalid);
01693 }
01694 
01695 cgiFormResultType cgiFormRadio(
01696   char *name, 
01697   char **valuesText, int valuesTotal, int *result, int defaultV)
01698 {
01699   
01700   return cgiFormSelectSingle(name, valuesText, valuesTotal, 
01701     result, defaultV);
01702 }
01703 
01704 cgiFormResultType cgiCookieString(
01705   char *name,
01706   char *value,
01707   int space)
01708 {
01709   char *p = cgiCookie;
01710   while (*p) {
01711     char *n = name;
01712     
01713 
01714 
01715 
01716 
01717 
01718     while (*p == *n) {
01719       if ((p == '\0') && (n == '\0')) {
01720         
01721         return cgiFormNotFound;
01722       }
01723       p++;
01724       n++;
01725     }
01726     if ((!*n) && (*p == '=')) {
01727       p++;
01728       while ((*p != ';') && (*p != '\0') &&
01729         (space > 1)) 
01730       {
01731         *value = *p;
01732         value++;
01733         p++;
01734         space--;
01735       }
01736       if (space > 0) {
01737         *value = '\0';
01738       }
01739       
01740 
01741       if (!(((*p) == ';') || ((*p) == '\0')))
01742       {
01743         return cgiFormTruncated;
01744       } else {  
01745         return cgiFormSuccess;
01746       }
01747     } else {
01748        
01749       while (*p) {
01750         if (*p == ';') {
01751           break;
01752         }
01753         p++;
01754       }
01755       if (!*p) {
01756         
01757         if (space) {
01758           *value = '\0';
01759         }
01760         return cgiFormNotFound;
01761       }
01762       p++;  
01763       
01764       while ((*p) && isspace(*p)) {
01765         p++;
01766       } 
01767     }
01768   }
01769   
01770 
01771   if (space) {
01772     *value = '\0';
01773   }
01774   return cgiFormNotFound;
01775 }
01776 
01777 cgiFormResultType cgiCookieInteger(
01778   char *name,
01779   int *result,
01780   int defaultV)
01781 {
01782   char buffer[256];
01783   cgiFormResultType r = 
01784     cgiCookieString(name, buffer, sizeof(buffer));
01785   if (r != cgiFormSuccess) {
01786     *result = defaultV;
01787   } else {
01788     *result = atoi(buffer);
01789   }
01790   return r;
01791 }
01792 
01793 void cgiHeaderCookieSetInteger(char *name, int value, int secondsToLive,
01794   char *path, char *domain)
01795 {
01796   char svalue[256];
01797   sprintf(svalue, "%d", value);
01798   cgiHeaderCookieSetString(name, svalue, secondsToLive, path, domain);
01799 }
01800 
01801 char *days[] = {
01802   "Sun",
01803   "Mon",
01804   "Tue",
01805   "Wed",
01806   "Thu",
01807   "Fri",
01808   "Sat"
01809 };
01810 
01811 char *months[] = {
01812   "Jan",
01813   "Feb",
01814   "Mar",
01815   "Apr",
01816   "May",
01817   "Jun",
01818   "Jul",
01819   "Aug",
01820   "Sep",
01821   "Oct",
01822   "Nov",
01823   "Dec"
01824 };
01825 
01826 void cgiHeaderCookieSetString(char *name, char *value, int secondsToLive,
01827   char *path, char *domain)
01828 {
01829   
01830 
01831 
01832 
01833 
01834 
01835 
01836 
01837 
01838 
01839   time_t now;
01840   time_t then;
01841   struct tm *gt;
01842   time(&now);
01843   then = now + secondsToLive;
01844   gt = gmtime(&then);
01845   fprintf(cgiOut, 
01846     "Set-Cookie: %s=%s; domain=%s; expires=%s, %02d-%s-%04d %02d:%02d:%02d GMT; path=%s\r\n",
01847     name, value, domain, 
01848     days[gt->tm_wday],
01849     gt->tm_mday,
01850     months[gt->tm_mon],
01851     gt->tm_year + 1900,   
01852     gt->tm_hour,
01853     gt->tm_min,
01854     gt->tm_sec,
01855     path);
01856 }
01857 
01858 void cgiHeaderLocation(char *redirectUrl) {
01859   fprintf(cgiOut, "Location: %s\r\n\r\n", redirectUrl);
01860 }
01861 
01862 void cgiHeaderStatus(int status, char *statusMessage) {
01863   fprintf(cgiOut, "Status: %d %s\r\n\r\n", status, statusMessage);
01864 }
01865 
01866 void cgiHeaderContentType(char *mimeType) {
01867   fprintf(cgiOut, "Content-type: %s\r\n\r\n", mimeType);
01868 }
01869 
01870 static int cgiWriteString(FILE *out, char *s);
01871 
01872 static int cgiWriteInt(FILE *out, int i);
01873 
01874 #define CGIC_VERSION "2.0"
01875 
01876 cgiEnvironmentResultType cgiWriteEnvironment(char *filename) {
01877   FILE *out;
01878   cgiFormEntry *e;
01879   
01880   out = fopen(filename, "wb");
01881   if (!out) {
01882     
01883     return cgiEnvironmentIO;
01884   }
01885   if (!cgiWriteString(out, "CGIC2.0")) {
01886     goto error;
01887   }
01888   if (!cgiWriteString(out, cgiServerSoftware)) {
01889     goto error;
01890   }
01891   if (!cgiWriteString(out, cgiServerName)) {
01892     goto error;
01893   }
01894   if (!cgiWriteString(out, cgiGatewayInterface)) {
01895     goto error;
01896   }
01897   if (!cgiWriteString(out, cgiServerProtocol)) {
01898     goto error;
01899   }
01900   if (!cgiWriteString(out, cgiServerPort)) {
01901     goto error;
01902   }
01903   if (!cgiWriteString(out, cgiRequestMethod)) {
01904     goto error;
01905   }
01906   if (!cgiWriteString(out, cgiPathInfo)) {
01907     goto error;
01908   }
01909   if (!cgiWriteString(out, cgiPathTranslated)) {
01910     goto error;
01911   }
01912   if (!cgiWriteString(out, cgiScriptName)) {
01913     goto error;
01914   }
01915   if (!cgiWriteString(out, cgiQueryString)) {
01916     goto error;
01917   }
01918   if (!cgiWriteString(out, cgiRemoteHost)) {
01919     goto error;
01920   }
01921   if (!cgiWriteString(out, cgiRemoteAddr)) {
01922     goto error;
01923   }
01924   if (!cgiWriteString(out, cgiAuthType)) {
01925     goto error;
01926   }
01927   if (!cgiWriteString(out, cgiRemoteUser)) {
01928     goto error;
01929   }
01930   if (!cgiWriteString(out, cgiRemoteIdent)) {
01931     goto error;
01932   }
01933   if (!cgiWriteString(out, cgiContentType)) {
01934     goto error;
01935   }
01936   if (!cgiWriteString(out, cgiAccept)) {
01937     goto error;
01938   }
01939   if (!cgiWriteString(out, cgiUserAgent)) {
01940     goto error;
01941   }
01942   if (!cgiWriteString(out, cgiReferrer)) {
01943     goto error;
01944   }
01945   if (!cgiWriteString(out, cgiCookie)) {
01946     goto error;
01947   }
01948   if (!cgiWriteInt(out, cgiContentLength)) {
01949     goto error;
01950   }
01951   e = cgiFormEntryFirst;
01952   while (e) {
01953     cgiFilePtr fp;
01954     if (!cgiWriteString(out, e->attr)) {
01955       goto error;
01956     }
01957     if (!cgiWriteString(out, e->value)) {
01958       goto error;
01959     }
01960     
01961     if (!cgiWriteString(out, e->fileName)) {
01962       goto error;
01963     }
01964     if (!cgiWriteString(out, e->contentType)) {
01965       goto error;
01966     }
01967     if (!cgiWriteInt(out, e->valueLength)) {
01968       goto error;
01969     }
01970     if (cgiFormFileOpen(e->attr, &fp) == cgiFormSuccess) {
01971       char buffer[1024];
01972       int got;
01973       if (!cgiWriteInt(out, 1)) {
01974         cgiFormFileClose(fp);
01975         goto error;
01976       }
01977       while (cgiFormFileRead(fp, buffer, 
01978         sizeof(buffer), &got) == cgiFormSuccess)
01979       {
01980         if (((int) fwrite(buffer, 1, got, out)) != got) {
01981           cgiFormFileClose(fp);
01982           goto error;
01983         }
01984       }
01985       if (cgiFormFileClose(fp) != cgiFormSuccess) {
01986         goto error;
01987       }
01988     } else {
01989       if (!cgiWriteInt(out, 0)) {
01990         goto error;
01991       }
01992     }
01993     e = e->next;
01994   }
01995   fclose(out);
01996   return cgiEnvironmentSuccess;
01997 error:
01998   fclose(out);
01999   
02000 
02001 
02002   unlink(filename);
02003   return cgiEnvironmentIO;
02004 }
02005 
02006 static int cgiWriteString(FILE *out, char *s) {
02007   int len = (int) strlen(s);
02008   cgiWriteInt(out, len);
02009   if (((int) fwrite(s, 1, len, out)) != len) {
02010     return 0;
02011   }
02012   return 1;
02013 }
02014 
02015 static int cgiWriteInt(FILE *out, int i) {
02016   if (!fwrite(&i, sizeof(int), 1, out)) {
02017     return 0;
02018   }
02019   return 1;
02020 }
02021 
02022 static int cgiReadString(FILE *out, char **s);
02023 
02024 static int cgiReadInt(FILE *out, int *i);
02025 
02026 cgiEnvironmentResultType cgiReadEnvironment(char *filename) {
02027   FILE *in;
02028   cgiFormEntry *e = 0, *p;
02029   char *version;
02030   
02031   cgiEnvironmentResultType result = cgiEnvironmentIO;
02032   
02033   cgiFreeResources();
02034   
02035   in = fopen(filename, "rb");
02036   if (!in) {
02037     
02038     return cgiEnvironmentIO;
02039   }
02040   if (!cgiReadString(in, &version)) {
02041     goto error;
02042   }
02043   if (strcmp(version, "CGIC" CGIC_VERSION)) {
02044     
02045     free(version);
02046     return cgiEnvironmentWrongVersion;
02047   } 
02048   
02049   free(version);
02050   if (!cgiReadString(in, &cgiServerSoftware)) {
02051     goto error;
02052   }
02053   if (!cgiReadString(in, &cgiServerName)) {
02054     goto error;
02055   }
02056   if (!cgiReadString(in, &cgiGatewayInterface)) {
02057     goto error;
02058   }
02059   if (!cgiReadString(in, &cgiServerProtocol)) {
02060     goto error;
02061   }
02062   if (!cgiReadString(in, &cgiServerPort)) {
02063     goto error;
02064   }
02065   if (!cgiReadString(in, &cgiRequestMethod)) {
02066     goto error;
02067   }
02068   if (!cgiReadString(in, &cgiPathInfo)) {
02069     goto error;
02070   }
02071   if (!cgiReadString(in, &cgiPathTranslated)) {
02072     goto error;
02073   }
02074   if (!cgiReadString(in, &cgiScriptName)) {
02075     goto error;
02076   }
02077   if (!cgiReadString(in, &cgiQueryString)) {
02078     goto error;
02079   }
02080   if (!cgiReadString(in, &cgiRemoteHost)) {
02081     goto error;
02082   }
02083   if (!cgiReadString(in, &cgiRemoteAddr)) {
02084     goto error;
02085   }
02086   if (!cgiReadString(in, &cgiAuthType)) {
02087     goto error;
02088   }
02089   if (!cgiReadString(in, &cgiRemoteUser)) {
02090     goto error;
02091   }
02092   if (!cgiReadString(in, &cgiRemoteIdent)) {
02093     goto error;
02094   }
02095   if (!cgiReadString(in, &cgiContentType)) {
02096     goto error;
02097   }
02098   if (!cgiReadString(in, &cgiAccept)) {
02099     goto error;
02100   }
02101   if (!cgiReadString(in, &cgiUserAgent)) {
02102     goto error;
02103   }
02104   if (!cgiReadString(in, &cgiReferrer)) {
02105     goto error;
02106   }
02107   
02108   if (!cgiReadString(in, &cgiCookie)) {
02109     goto error;
02110   }
02111   if (!cgiReadInt(in, &cgiContentLength)) {
02112     goto error;
02113   }
02114   p = 0;
02115   while (1) {
02116     int fileFlag;
02117     e = (cgiFormEntry *) calloc(1, sizeof(cgiFormEntry));
02118     if (!e) {
02119       cgiFreeResources();
02120       fclose(in);
02121       return cgiEnvironmentMemory;
02122     }
02123     memset(e, 0, sizeof(cgiFormEntry));
02124     if (!cgiReadString(in, &e->attr)) {
02125       
02126       
02127       free(e);
02128       break;
02129     }
02130     if (!cgiReadString(in, &e->value)) {
02131       goto outOfMemory;
02132     }
02133     if (!cgiReadString(in, &e->fileName)) {
02134       goto outOfMemory;
02135     }
02136     if (!cgiReadString(in, &e->contentType)) {
02137       goto outOfMemory;
02138     }
02139     if (!cgiReadInt(in, &e->valueLength)) {
02140       goto outOfMemory;
02141     }
02142     if (!cgiReadInt(in, &fileFlag)) {
02143       goto outOfMemory;
02144     }
02145     if (fileFlag) {
02146       char buffer[1024];
02147       FILE *out;
02148       char tfileName[1024];
02149       int got;
02150       int len = e->valueLength;
02151       if (getTempFileName(tfileName)
02152         != cgiParseSuccess)
02153       {
02154         result = cgiEnvironmentIO;
02155         goto error;
02156       }
02157       out = fopen(tfileName, "w+b");
02158       if (!out) {
02159         result = cgiEnvironmentIO;
02160         goto error;
02161       }
02162       while (len > 0) {   
02163         
02164 
02165 
02166         int tryr = len;
02167         if (tryr > ((int) sizeof(buffer))) {
02168           tryr = sizeof(buffer);
02169         }
02170         got = fread(buffer, 1, tryr, in);
02171         if (got <= 0) {
02172           result = cgiEnvironmentIO;
02173           fclose(out);
02174           unlink(tfileName);
02175           goto error;
02176         }
02177         if (((int) fwrite(buffer, 1, got, out)) != got) {
02178           result = cgiEnvironmentIO;
02179           fclose(out);
02180           unlink(tfileName);
02181           goto error;
02182         }
02183         len -= got;
02184       }
02185       fclose(out);
02186       e->tfileName = (char *) malloc((int) strlen(tfileName) + 1);
02187       if (!e->tfileName) {
02188         result = cgiEnvironmentMemory;
02189         unlink(tfileName);
02190         goto error;
02191       }
02192       strcpy(e->tfileName, tfileName);
02193     } else {
02194       e->tfileName = (char *) malloc(1);
02195       if (!e->tfileName) {
02196         result = cgiEnvironmentMemory;
02197         goto error;
02198       }
02199     } 
02200     e->next = 0;
02201     if (p) {
02202       p->next = e;
02203     } else {
02204       cgiFormEntryFirst = e;
02205     } 
02206     p = e;
02207   }
02208   fclose(in);
02209   cgiRestored = 1;
02210   return cgiEnvironmentSuccess;
02211 outOfMemory:
02212   result = cgiEnvironmentMemory;
02213 error:
02214   cgiFreeResources();
02215   fclose(in);
02216   if (e) {
02217     if (e->attr) {
02218       free(e->attr);
02219     }
02220     if (e->value) {
02221       free(e->value);
02222     }
02223     if (e->fileName) {
02224       free(e->fileName);
02225     }
02226     if (e->contentType) {
02227       free(e->contentType);
02228     }
02229     if (e->tfileName) {
02230       free(e->tfileName);
02231     }
02232     free(e);
02233   }
02234   return result;
02235 }
02236 
02237 static int cgiReadString(FILE *in, char **s) {
02238   int len;
02239    
02240   if (!cgiReadInt(in, &len)) {
02241     return 0;
02242   }
02243   *s = (char *) malloc(len + 1);
02244   if (!(*s)) {
02245     return 0;
02246   } 
02247   if (((int) fread(*s, 1, len, in)) != len) {
02248     return 0;
02249   }
02250   (*s)[len] = '\0';
02251   return 1;
02252 }
02253 
02254 static int cgiReadInt(FILE *out, int *i) {
02255   if (!fread(i, sizeof(int), 1, out)) {
02256     return 0;
02257   }
02258   return 1;
02259 }
02260 
02261 static int cgiStrEqNc(char *s1, char *s2) {
02262   while(1) {
02263     if (!(*s1)) {
02264       if (!(*s2)) {
02265         return 1;
02266       } else {
02267         return 0;
02268       }
02269     } else if (!(*s2)) {
02270       return 0;
02271     }
02272     if (isalpha(*s1)) {
02273       if (tolower(*s1) != tolower(*s2)) {
02274         return 0;
02275       }
02276     } else if ((*s1) != (*s2)) {
02277       return 0;
02278     }
02279     s1++;
02280     s2++;
02281   }
02282 }
02283 
02284 static int cgiStrBeginsNc(char *s1, char *s2) {
02285   while(1) {
02286     if (!(*s2)) {
02287       return 1;
02288     } else if (!(*s1)) {
02289       return 0;
02290     }
02291     if (isalpha(*s1)) {
02292       if (tolower(*s1) != tolower(*s2)) {
02293         return 0;
02294       }
02295     } else if ((*s1) != (*s2)) {
02296       return 0;
02297     }
02298     s1++;
02299     s2++;
02300   }
02301 }
02302 
02303 static char *cgiFindTarget = 0;
02304 static cgiFormEntry *cgiFindPos = 0;
02305 
02306 static cgiFormEntry *cgiFormEntryFindFirst(char *name) {
02307   cgiFindTarget = name;
02308   cgiFindPos = cgiFormEntryFirst;
02309   return cgiFormEntryFindNext();
02310 }
02311 
02312 static cgiFormEntry *cgiFormEntryFindNext() {
02313   while (cgiFindPos) {
02314     cgiFormEntry *c = cgiFindPos;
02315     cgiFindPos = c->next;
02316     if (!strcmp(c -> attr, cgiFindTarget)) {
02317       return c;
02318     }
02319   }
02320   return 0;
02321 }
02322 
02323 static int cgiFirstNonspaceChar(char *s) {
02324   int len = strspn(s, " \n\r\t");
02325   return s[len];
02326 }
02327 
02328 void cgiStringArrayFree(char **stringArray) {
02329   char *p;
02330   char **arrayItself = stringArray;
02331   p = *stringArray;
02332   while (p) {
02333     free(p);
02334     stringArray++;
02335     p = *stringArray;
02336   }
02337   
02338   free(arrayItself);
02339 } 
02340 
02341 cgiFormResultType cgiCookies(char ***result) {
02342   char **stringArray;
02343   int i;
02344   int total = 0;
02345   char *p;
02346   char *n;
02347   p = cgiCookie;
02348   while (*p) {
02349     if (*p == '=') {
02350       total++;
02351     }
02352     p++;
02353   }
02354   stringArray = (char **) malloc(sizeof(char *) * (total + 1));
02355   if (!stringArray) {
02356     *result = 0;
02357     return cgiFormMemory;
02358   }
02359   
02360   for (i=0; (i <= total); i++) {
02361     stringArray[i] = 0;
02362   }
02363   i = 0;
02364   p = cgiCookie;
02365   while (*p) {
02366     while (*p && isspace(*p)) {
02367       p++;
02368     }
02369     n = p;
02370     while (*p && (*p != '=')) {
02371       p++;
02372     }
02373     if (p != n) {
02374       stringArray[i] = (char *) malloc((p - n) + 1);
02375       if (!stringArray[i]) {
02376         cgiStringArrayFree(stringArray);
02377         *result = 0;
02378         return cgiFormMemory;
02379       } 
02380       memcpy(stringArray[i], n, p - n);
02381       stringArray[i][p - n] = '\0';
02382       i++;
02383     }
02384     while (*p && (*p != ';')) {
02385       p++;  
02386     }
02387     if (!*p) {
02388       break;
02389     }
02390     if (*p == ';') {
02391       p++;
02392     }
02393   }
02394   *result = stringArray;
02395   return cgiFormSuccess;
02396 }
02397 
02398 cgiFormResultType cgiFormEntries(char ***result) {
02399   char **stringArray;
02400   cgiFormEntry *e, *pe;
02401   int i;
02402   int total = 0;
02403   e = cgiFormEntryFirst;
02404   while (e) {
02405     
02406 
02407     pe = cgiFormEntryFirst;
02408     while (pe != e) {
02409       if (!strcmp(e->attr, pe->attr)) {
02410         goto skipSecondValue;
02411       }
02412       pe = pe->next;          
02413     }
02414     total++;
02415 skipSecondValue:
02416     e = e->next;
02417   }
02418   stringArray = (char **) malloc(sizeof(char *) * (total + 1));
02419   if (!stringArray) {
02420     *result = 0;
02421     return cgiFormMemory;
02422   }
02423   
02424   for (i=0; (i <= total); i++) {
02425     stringArray[i] = 0;
02426   }
02427   
02428   e = cgiFormEntryFirst;
02429   i = 0;
02430   while (e) {
02431     int space;
02432     
02433 
02434     pe = cgiFormEntryFirst;
02435     while (pe != e) {
02436       if (!strcmp(e->attr, pe->attr)) {
02437         goto skipSecondValue2;
02438       }
02439       pe = pe->next;          
02440     }   
02441     space = (int) strlen(e->attr) + 1;
02442     stringArray[i] = (char *) malloc(space);
02443     if (stringArray[i] == 0) {
02444       
02445       cgiStringArrayFree(stringArray);
02446       *result = 0;
02447       return cgiFormMemory;
02448     } 
02449     strcpy(stringArray[i], e->attr);
02450     i++;
02451 skipSecondValue2:
02452     e = e->next;
02453   }
02454   *result = stringArray;
02455   return cgiFormSuccess;
02456 }
02457 
02458 #define TRYPUTC(ch) \
02459   { \
02460     if (putc((ch), cgiOut) == EOF) { \
02461       return cgiFormIO; \
02462     } \
02463   } 
02464 
02465 cgiFormResultType cgiHtmlEscapeData(char *data, int len)
02466 {
02467   while (len--) {
02468     if (*data == '<') {
02469       TRYPUTC('&');
02470       TRYPUTC('l');
02471       TRYPUTC('t');
02472       TRYPUTC(';');
02473     } else if (*data == '&') {
02474       TRYPUTC('&');
02475       TRYPUTC('a');
02476       TRYPUTC('m');
02477       TRYPUTC('p');
02478       TRYPUTC(';');
02479     } else if (*data == '>') {
02480       TRYPUTC('&');
02481       TRYPUTC('g');
02482       TRYPUTC('t');
02483       TRYPUTC(';');
02484     } else {
02485       TRYPUTC(*data);
02486     }
02487     data++;
02488   }
02489   return cgiFormSuccess;
02490 }
02491 
02492 cgiFormResultType cgiHtmlEscape(char *s)
02493 {
02494   return cgiHtmlEscapeData(s, (int) strlen(s));
02495 }
02496 
02497 
02498 
02499 
02500 
02501 
02502 
02503 cgiFormResultType cgiValueEscapeData(char *data, int len)
02504 {
02505   while (len--) {
02506     if (*data == '\"') {
02507       TRYPUTC('&');
02508       TRYPUTC('#');
02509       TRYPUTC('3');
02510       TRYPUTC('4');
02511       TRYPUTC(';');
02512     } else {
02513       TRYPUTC(*data);
02514     }
02515     data++;
02516   }
02517   return cgiFormSuccess;
02518 }
02519 
02520 cgiFormResultType cgiValueEscape(char *s)
02521 {
02522   return cgiValueEscapeData(s, (int) strlen(s));
02523 }
02524 
02525