lib/cheapcgi.c

Go to the documentation of this file.
00001 /* Routines for getting variables passed in from web page
00002  * forms via CGI. 
00003  *
00004  * This file is copyright 2002 Jim Kent, but license is hereby
00005  * granted for all use - public, private or commercial. */
00006 
00007 #include "common.h"
00008 #include "hash.h"
00009 #include "cheapcgi.h"
00010 #include "portable.h"
00011 #include "linefile.h"
00012 #include "errabort.h"
00013 #include "mime.h"
00014 
00015 static char const rcsid[] = "$Id: cheapcgi.c,v 1.85 2006/12/19 18:49:52 kent Exp $";
00016 
00017 /* These three variables hold the parsed version of cgi variables. */
00018 static char *inputString = NULL;
00019 static unsigned long inputSize;
00020 static struct hash *inputHash = NULL;
00021 static struct cgiVar *inputList = NULL;
00022 
00023 static boolean haveCookiesHash = FALSE;
00024 static struct hash *cookieHash = NULL;
00025 static struct cgiVar *cookieList = NULL;
00026 
00027 /* should cheapcgi use temp files to store uploaded files */
00028 static boolean doUseTempFile = FALSE;
00029 
00030 void dumpCookieList()
00031 /* Print out the cookie list. */
00032 {
00033 struct cgiVar *v;
00034 for (v=cookieList; v != NULL; v = v->next)
00035     printf("%s=%s (%d)\n", v->name, v->val, v->saved);
00036 }
00037 
00038 void useTempFile() 
00039 /* tell cheapcgi to use temp files */
00040 {
00041 doUseTempFile = TRUE;
00042 }
00043 
00044 boolean cgiIsOnWeb()
00045 /* Return TRUE if looks like we're being run as a CGI. */
00046 {
00047 return getenv("REQUEST_METHOD") != NULL;
00048 }
00049 
00050 char *cgiScriptName()
00051 /* Return name of script so libs can do context-sensitive stuff. */
00052 {
00053 return getenv("SCRIPT_NAME");
00054 }
00055 
00056 char *cgiServerName()
00057 /* Return name of server */
00058 {
00059 return getenv("SERVER_NAME");
00060 }
00061 
00062 char *_cgiRawInput()
00063 /* For debugging get the unprocessed input. */
00064 {
00065 return inputString;
00066 }
00067 
00068 static void getQueryInput()
00069 /* Get query string from environment if they've used GET method. */
00070 {
00071 inputString = getenv("QUERY_STRING");
00072 if (inputString == NULL)
00073     errAbort("No QUERY_STRING in environment.");
00074 inputString = cloneString(inputString);
00075 }
00076 
00077 static void getPostInput()
00078 /* Get input from file if they've used POST method. */
00079 {
00080 char *s;
00081 long i;
00082 int r;
00083 
00084 s = getenv("CONTENT_LENGTH");
00085 if (s == NULL)
00086     errAbort("No CONTENT_LENGTH in environment.");
00087 if (sscanf(s, "%lu", &inputSize) != 1)
00088     errAbort("CONTENT_LENGTH isn't a number.");
00089 s = getenv("CONTENT_TYPE");
00090 if (s != NULL && startsWith("multipart/form-data", s))
00091     {
00092     /* use MIME parse on input stream instead, can handle large uploads */
00093     inputString = "";  // must not be NULL so it knows it was set
00094     return;  
00095     }
00096 inputString = needMem((size_t)inputSize+1);
00097 for (i=0; i<inputSize; ++i)
00098     {
00099     r = getc(stdin);
00100     if (r == EOF)
00101         errAbort("Short POST input.");
00102     inputString[i] = r;
00103     }
00104 inputString[inputSize] = 0;
00105 }
00106 
00107 #define memmem(hay, haySize, needle, needleSize) \
00108     memMatch(needle, needleSize, hay, haySize)
00109 
00110 static void cgiParseMultipart(struct hash **retHash, struct cgiVar **retList)
00111 /* process a multipart form */
00112 {
00113 char h[1024];  /* hold mime header line */
00114 char *s = NULL, *ct = NULL;
00115 struct dyString *dy = newDyString(256);
00116 struct mimeBuf *mb = NULL;
00117 struct mimePart *mp = NULL;
00118 char **env = NULL;
00119 struct hash *hash = newHash(6);
00120 struct cgiVar *list = NULL, *el;
00121 extern char **environ;
00122 
00123 
00124 //debug
00125 //fprintf(stderr,"GALT: top of cgiParseMultipart()\n");
00126 //fflush(stderr);
00127 
00128 /* find the CONTENT_ environment strings, use to make Alternate Header string for MIME */
00129 for(env=environ; *env; env++)
00130     if (startsWith("CONTENT_",*env))
00131         {
00132         //debug
00133         //fprintf(stderr,"%s\n",*env);  //debug
00134         safef(h,sizeof(h),"%s",*env);
00135         s = strchr(h,'_');    /* change env syntax to MIME style header, from _= to -: */
00136         if (!s)
00137             errAbort("expecting '_' parsing env var %s for MIME alt header", *env);
00138         *s = '-';
00139         s = strchr(h,'=');
00140         if (!s)
00141             errAbort("expecting '=' parsing env var %s for MIME alt header", *env);
00142         *s = ':';
00143         dyStringPrintf(dy,"%s\r\n",h);
00144         }
00145 dyStringAppend(dy,"\r\n");  /* blank line at end means end of headers */
00146 
00147 //debug
00148 //fprintf(stderr,"Alternate Header Text:\n%s",dy->string);
00149 //fflush(stderr);
00150 mb = initMimeBuf(STDIN_FILENO);
00151 //debug
00152 //fprintf(stderr,"got past initMimeBuf(STDIN_FILENO)\n");
00153 //fflush(stderr);
00154 mp = parseMultiParts(mb, cloneString(dy->string)); /* The Alternate Header will get freed */
00155 freeDyString(&dy);
00156 if(!mp->multi) /* expecting multipart child parts */
00157     errAbort("Malformatted multipart-form.");
00158 
00159 //debug
00160 //fprintf(stderr,"GALT: Wow got past parse of MIME!\n");
00161 //fflush(stderr);
00162 
00163 ct = hashFindVal(mp->hdr,"content-type");
00164 //debug
00165 //fprintf(stderr,"GALT: main content-type: %s\n",ct);
00166 //fflush(stderr);
00167 if (!startsWith("multipart/form-data",ct))
00168     errAbort("main content-type expected starts with [multipart/form-data], found [%s]",ct);
00169 
00170 for(mp=mp->multi;mp;mp=mp->next)
00171     {
00172     char *cd = NULL, *cdMain = NULL, *cdName = NULL, *cdFileName = NULL, *ct = NULL;
00173     cd = hashFindVal(mp->hdr,"content-disposition");
00174     ct = hashFindVal(mp->hdr,"content-type");
00175     //debug
00176     //fprintf(stderr,"GALT: content-disposition: %s\n",cd);
00177     //fprintf(stderr,"GALT: content-type: %s\n",ct);
00178     //fflush(stderr);
00179     cdMain=getMimeHeaderMainVal(cd);
00180     cdName=getMimeHeaderFieldVal(cd,"name");
00181     cdFileName=getMimeHeaderFieldVal(cd,"filename");
00182     //debug
00183     //fprintf(stderr,"GALT: main:[%s], name:[%s], filename:[%s]\n",cdMain,cdName,cdFileName);
00184     //fflush(stderr);
00185     if (!sameString(cdMain,"form-data"))
00186         errAbort("main content-type expected [form-data], found [%s]",cdMain);
00187 
00188     //debug
00189     //fprintf(stderr,"GALT: mp->size[%llu], mp->binary=[%d], mp->fileName=[%s], mp=>data:[%s]\n",
00190         //(unsigned long long) mp->size, mp->binary, mp->fileName, 
00191         //mp->binary && mp->data ? "<binary data not safe to print>" : mp->data);
00192     //fflush(stderr);
00193     
00194     /* filename if there is one */
00195     if(cdFileName) 
00196         {
00197         char varNameFilename[256];
00198         safef(varNameFilename, sizeof(varNameFilename), "%s__filename", cdName);
00199         AllocVar(el);
00200         el->val = cloneString(cdFileName);
00201         slAddHead(&list, el);
00202         hashAddSaveName(hash, varNameFilename, el, &el->name);
00203         }
00204         
00205     if (mp->data) 
00206         {
00207         if (mp->binary)
00208             {
00209             char varNameBinary[256];
00210             char addrSizeBuf[40];
00211             safef(varNameBinary,sizeof(varNameBinary),"%s__binary",cdName);
00212             safef(addrSizeBuf,sizeof(addrSizeBuf),"%lu %llu", 
00213                 (unsigned long)mp->data,
00214                 (unsigned long long)mp->size);
00215             AllocVar(el);
00216             el->val = cloneString(addrSizeBuf);
00217             slAddHead(&list, el);
00218             hashAddSaveName(hash, varNameBinary, el, &el->name);
00219             }
00220         else  /* normal variable, not too big, does not contain zeros */
00221             {
00222             AllocVar(el);
00223             el->val = mp->data;
00224             slAddHead(&list, el);
00225             hashAddSaveName(hash, cdName, el, &el->name);
00226             }
00227         }           
00228     else if (mp->fileName)
00229         {
00230         char varNameData[256];
00231         safef(varNameData, sizeof(varNameData), "%s__data", cdName);
00232         AllocVar(el);
00233         el->val = mp->fileName; 
00234         slAddHead(&list, el);
00235         hashAddSaveName(hash, varNameData, el, &el->name);
00236         //debug
00237         //fprintf(stderr,"GALT special: saved varNameData:[%s], mp=>fileName:[%s]\n",el->name,el->val);
00238         //fflush(stderr);
00239         }
00240     else if (mp->multi)
00241         {
00242         warn("unexpected nested MIME structures");
00243         }
00244     else
00245         {
00246         errAbort("mp-> type not data,fileName, or multi - unexpected MIME structure");
00247         }
00248     
00249     freez(&cdMain);
00250     freez(&cdName);
00251     freez(&cdFileName);
00252     }
00253 
00254 slReverse(&list);
00255 *retList = list;
00256 *retHash = hash;
00257 }
00258 
00259 
00260 
00261 
00262 static void parseCookies(struct hash **retHash, struct cgiVar **retList)
00263 /* parses any cookies and puts them into the given hash and list */
00264 {
00265 char* str;
00266 char *namePt, *dataPt, *nextNamePt;
00267 struct hash *hash;
00268 struct cgiVar *list = NULL, *el;
00269 
00270 /* don't build the hash table again */
00271 if(haveCookiesHash == TRUE)
00272         return;
00273 
00274 str = cloneString(getenv("HTTP_COOKIE"));
00275 if(str == NULL) /* don't have a cookie */
00276         return;
00277 
00278 hash = newHash(6);
00279 
00280 namePt = str;
00281 while (namePt != NULL)
00282     {
00283     dataPt = strchr(namePt, '=');
00284     if (dataPt == NULL)
00285         errAbort("Mangled Cookie input string %s", namePt);
00286     *dataPt++ = 0;
00287     nextNamePt = strchr(dataPt, ';');
00288     if (nextNamePt != NULL)
00289         {
00290          *nextNamePt++ = 0;
00291          nextNamePt++;
00292         }
00293     cgiDecode(dataPt,dataPt,strlen(dataPt));
00294     AllocVar(el);
00295     el->val = dataPt;
00296     slAddHead(&list, el);
00297     hashAddSaveName(hash, namePt, el, &el->name);
00298     namePt = nextNamePt;
00299     }
00300 
00301 haveCookiesHash = TRUE;
00302 
00303 slReverse(&list);
00304 *retList = list;
00305 *retHash = hash;
00306 }
00307 
00308 char *findCookieData(char *varName)
00309 /* Get the string associated with varName from the cookie string. */
00310 {
00311 struct cgiVar *var;
00312 
00313 /* make sure that the cookie hash table has been created */
00314 parseCookies(&cookieHash, &cookieList);
00315 if (cookieHash == NULL)
00316     return NULL;
00317 if ((var = hashFindVal(cookieHash, varName)) == NULL)
00318     return NULL;
00319 return var->val;
00320 }
00321 
00322 static char *cgiInputSource(char *s)
00323 /* For NULL sources make a guess as to real source. */
00324 {
00325 char *qs;
00326 if (s != NULL)
00327     return s;
00328 qs = getenv("QUERY_STRING");
00329 if (qs == NULL)
00330     return "POST";
00331 if (qs[0] == 0)
00332     {
00333     char *cl = getenv("CONTENT_LENGTH");
00334     if (cl != NULL && atoi(cl) > 0)
00335         return "POST";
00336     }
00337 return "QUERY";
00338 }
00339 
00340 static void _cgiFindInput(char *method)
00341 /* Get raw CGI input into inputString.  Method can be "POST", "QUERY", "GET" or NULL
00342  * for unknown. */
00343 {
00344 if (inputString == NULL)
00345     {
00346     method = cgiInputSource(method);
00347     if (sameWord(method, "POST"))
00348         getPostInput();
00349     else if (sameWord(method, "QUERY") || sameWord(method, "GET"))
00350         getQueryInput();
00351     else
00352         errAbort("Unknown form method");
00353     }
00354 }
00355 
00356 static void cgiParseInputAbort(char *input, struct hash **retHash, 
00357         struct cgiVar **retList)
00358 /* Parse cgi-style input into a hash table and list.  This will alter
00359  * the input data.  The hash table will contain references back 
00360  * into input, so please don't free input until you're done with 
00361  * the hash. Prints message aborts if there's an error.*/
00362 {
00363 char *namePt, *dataPt, *nextNamePt;
00364 struct hash *hash = newHash(6);
00365 struct cgiVar *list = NULL, *el;
00366 
00367 namePt = input;
00368 while (namePt != NULL && namePt[0] != 0)
00369     {
00370     dataPt = strchr(namePt, '=');
00371     if (dataPt == NULL)
00372         {
00373         errAbort("Mangled CGI input string %s", namePt);
00374         }
00375     *dataPt++ = 0;
00376     nextNamePt = strchr(dataPt, '&');
00377     if (nextNamePt == NULL)
00378         nextNamePt = strchr(dataPt, ';');       /* Accomodate DAS. */
00379     if (nextNamePt != NULL)
00380          *nextNamePt++ = 0;
00381     cgiDecode(namePt,namePt,strlen(namePt));    /* for unusual ct names */
00382     cgiDecode(dataPt,dataPt,strlen(dataPt));
00383     AllocVar(el);
00384     el->val = dataPt;
00385     slAddHead(&list, el);
00386     hashAddSaveName(hash, namePt, el, &el->name);
00387     namePt = nextNamePt;
00388     }
00389 slReverse(&list);
00390 *retList = list;
00391 *retHash = hash;
00392 }
00393 
00394 static jmp_buf cgiParseRecover;
00395 
00396 static void cgiParseAbort()
00397 /* Abort cgi parsing. */
00398 {
00399 longjmp(cgiParseRecover, -1);
00400 }
00401 
00402 boolean cgiParseInput(char *input, struct hash **retHash, 
00403         struct cgiVar **retList)
00404 /* Parse cgi-style input into a hash table and list.  This will alter
00405  * the input data.  The hash table will contain references back 
00406  * into input, so please don't free input until you're done with 
00407  * the hash. Prints message and returns FALSE if there's an error.*/
00408 {
00409 boolean ok = TRUE;
00410 int status = setjmp(cgiParseRecover);
00411 if (status == 0)    /* Always true except after long jump. */
00412     {
00413     pushAbortHandler(cgiParseAbort);
00414     cgiParseInputAbort(input, retHash, retList);
00415     }
00416 else    /* They long jumped here because of an error. */
00417     {
00418     ok = FALSE;
00419     }
00420 popAbortHandler();
00421 return ok;
00422 }
00423 
00424 static void initCgiInput() 
00425 /* Initialize CGI input stuff.  After this CGI vars are
00426  * stored in an internal hash/list regardless of how they
00427  * were passed to the program. */
00428 {
00429 char* s;
00430 
00431 if (inputString != NULL)
00432     return;
00433 _cgiFindInput(NULL);
00434 
00435 /* check to see if the input is a multipart form */
00436 s = getenv("CONTENT_TYPE");
00437 if (s != NULL && startsWith("multipart/form-data", s))
00438     {
00439     cgiParseMultipart(&inputHash, &inputList);
00440     }       
00441 else
00442     {
00443     cgiParseInputAbort(inputString, &inputHash, &inputList);
00444     }
00445 
00446 /* now parse the cookies */
00447 parseCookies(&cookieHash, &cookieList);
00448 
00449 /* Set enviroment variables CGIs to enable sql tracing and/or profiling */
00450 s = cgiOptionalString("JKSQL_TRACE");
00451 if (s != NULL)
00452     envUpdate("JKSQL_TRACE", s);
00453 s = cgiOptionalString("JKSQL_PROF");
00454 if (s != NULL)
00455     envUpdate("JKSQL_PROF", s);
00456     
00457 }
00458 
00459 struct cgiVar *cgiVarList() 
00460 /* return the list of cgiVar's */
00461 {
00462 initCgiInput();
00463 return inputList;
00464 }
00465 
00466 static char *findVarData(char *varName)
00467 /* Get the string associated with varName from the query string. */
00468 {
00469 struct cgiVar *var;
00470 
00471 initCgiInput();
00472 if ((var = hashFindVal(inputHash, varName)) == NULL)
00473     return NULL;
00474 return var->val;
00475 }
00476 
00477 void cgiBadVar(char *varName)
00478 /* Complain about a variable that's not there. */
00479 {
00480 if (varName == NULL) varName = "";
00481 errAbort("Sorry, didn't find input variable %s\n"
00482         "Probably the web page didn't mean to call this program.", 
00483         varName);
00484 }
00485 
00486 static char *mustFindVarData(char *varName)
00487 /* Find variable and associated data or die trying. */
00488 {
00489 char *res = findVarData(varName);
00490 if (res == NULL)
00491     cgiBadVar(varName);
00492 return res;
00493 }
00494 
00495 void cgiDecode(char *in, char *out, int inLength)
00496 /* Decode from cgi pluses-for-spaces format to normal. 
00497  * Out will be a little shorter than in typically, and
00498  * can be the same buffer. */
00499 {
00500 char c;
00501 int i;
00502 for (i=0; i<inLength;++i)
00503     {
00504     c = *in++;
00505     if (c == '+') 
00506         *out++ = ' ';
00507     else if (c == '%')
00508         {
00509         int code;
00510         if (sscanf(in, "%2x", &code) != 1) 
00511             code = '?';
00512         in += 2;
00513         i += 2;
00514         *out++ = code;
00515         }
00516     else
00517         *out++ = c;
00518     }
00519 *out++ = 0;
00520 }
00521 
00522 char *cgiEncode(char *inString)
00523 /* Return a cgi-encoded version of inString. 
00524  * Alphanumerics kept as is, space translated to plus,
00525  * and all other characters translated to %hexVal. */
00526 {
00527 char c;
00528 int outSize = 0;
00529 char *outString, *out, *in;
00530 
00531 if (inString == NULL)
00532     return(cloneString(""));
00533 
00534 /* Count up how long it will be */
00535 in = inString;
00536 while ((c = *in++) != 0)
00537     {
00538     if (isalnum(c) || c == ' ' || c == '.' || c == '_')
00539         outSize += 1;
00540     else
00541         outSize += 3;
00542     }
00543 outString = needMem(outSize+1);
00544 
00545 /* Encode string */
00546 in = inString;
00547 out = outString;
00548 while ((c = *in++) != 0)
00549     {
00550     if (isalnum(c) || c == '.' || c == '_')
00551         *out++ = c;
00552     else if (c == ' ')
00553         *out++ = '+';
00554     else
00555         {
00556         unsigned char uc = c;
00557         char buf[4];
00558         *out++ = '%';
00559         safef(buf, sizeof(buf), "%02X", uc);
00560         *out++ = buf[0];
00561         *out++ = buf[1];
00562         }
00563     }
00564 *out++ = 0;
00565 return outString;
00566 }
00567 
00568 char *cgiEncodeFull(char *inString)
00569 /* Return a cgi-encoded version of inString (no + for space!). 
00570  * Alphanumerics/./_ kept as is and all other characters translated to 
00571  * %hexVal. */
00572 {
00573 char c;
00574 int outSize = 0;
00575 char *outString, *out, *in;
00576 
00577 if (inString == NULL)
00578     return(cloneString(""));
00579 
00580 /* Count up how long it will be */
00581 in = inString;
00582 while ((c = *in++) != 0)
00583     {
00584     if (isalnum(c) || c == '.' || c == '_')
00585         outSize += 1;
00586     else
00587         outSize += 3;
00588     }
00589 outString = needMem(outSize+1);
00590 
00591 /* Encode string */
00592 in = inString;
00593 out = outString;
00594 while ((c = *in++) != 0)
00595     {
00596     if (isalnum(c) || c == '.' || c == '_')
00597         *out++ = c;
00598     else
00599         {
00600         unsigned char uc = c;
00601         char buf[4];
00602         *out++ = '%';
00603         safef(buf, sizeof(buf), "%02X", uc);
00604         *out++ = buf[0];
00605         *out++ = buf[1];
00606         }
00607     }
00608 *out++ = 0;
00609 return outString;
00610 }
00611 
00612 char *cgiOptionalString(char *varName)
00613 /* Return value of string if it exists in cgi environment, else NULL */
00614 {
00615 return findVarData(varName);
00616 }
00617 
00618 
00619 char *cgiString(char *varName)
00620 /* Return string value of cgi variable. */
00621 {
00622 return mustFindVarData(varName);
00623 }
00624 
00625 char *cgiUsualString(char *varName, char *usual)
00626 /* Return value of string if it exists in cgi environment.  
00627  * Otherwise return 'usual' */
00628 {
00629 char *pt;
00630 pt = findVarData(varName);
00631 if (pt == NULL)
00632     pt = usual;
00633 return pt;
00634 }
00635 
00636 struct slName *cgiStringList(char *varName)
00637 /* Find list of cgi variables with given name.  This
00638  * may be empty.  Free result with slFreeList(). */
00639 {
00640 struct hashEl *hel;
00641 struct slName *stringList = NULL, *string;
00642 
00643 initCgiInput();
00644 for (hel = hashLookup(inputHash, varName); hel != NULL; hel = hel->next)
00645     {
00646     if (sameString(hel->name, varName))
00647         {
00648         struct cgiVar *var = hel->val;
00649         string = newSlName(var->val);
00650         slAddHead(&stringList, string);
00651         }
00652     }
00653 return stringList;
00654 }
00655 
00656 
00657 int cgiInt(char *varName)
00658 /* Return int value of cgi variable. */
00659 {
00660 char *data;
00661 char c;
00662 
00663 data = mustFindVarData(varName);
00664 data = skipLeadingSpaces(data);
00665 c = data[0];
00666 if (!(isdigit(c) || (c == '-' && isdigit(data[1]))))
00667      errAbort("Expecting number in %s, got \"%s\"\n", varName, data);
00668 return atoi(data);
00669 }
00670 
00671 int cgiIntExp(char *varName)
00672 /* Evaluate an integer expression in varName and
00673  * return value. */
00674 {
00675 return intExp(cgiString(varName));
00676 }
00677 
00678 int cgiOptionalInt(char *varName, int defaultVal)
00679 /* This returns integer value of varName if it exists in cgi environment
00680  * and it's not just the empty string otherwise it returns defaultVal. */
00681 {
00682 char *s = cgiOptionalString(varName);
00683 s = skipLeadingSpaces(s);
00684 if (isEmpty(s))
00685     return defaultVal;
00686 return cgiInt(varName);
00687 }
00688 
00689 double cgiDouble(char *varName)
00690 /* Returns double value. */
00691 {
00692 char *data;
00693 double x;
00694 
00695 data = mustFindVarData(varName);
00696 if (sscanf(data, "%lf", &x)<1) 
00697      errAbort("Expecting real number in %s, got \"%s\"\n", varName, data);
00698 return x;
00699 }
00700 
00701 double cgiOptionalDouble(char *varName, double defaultVal)
00702 /* Returns double value. */
00703 {
00704 if (!cgiVarExists(varName))
00705     return defaultVal;
00706 return cgiDouble(varName);
00707 }
00708 
00709 boolean cgiVarExists(char *varName)
00710 /* Returns TRUE if the variable was passed in. */
00711 {
00712 initCgiInput();
00713 return hashLookup(inputHash, varName) != NULL;
00714 }
00715 
00716 boolean cgiBoolean(char *varName)
00717 {
00718 return cgiVarExists(varName);
00719 }
00720 
00721 int cgiOneChoice(char *varName, struct cgiChoice *choices, int choiceSize)
00722 /* Returns value associated with string variable in choice table. */
00723 {
00724 char *key = cgiString(varName);
00725 int i;
00726 int val = -1;
00727 
00728 for (i=0; i<choiceSize; ++i)
00729     {
00730     if (sameWord(choices[i].name, key))
00731         {
00732         val =  choices[i].value;
00733         return val;
00734         }
00735     }
00736 errAbort("Unknown key %s for variable %s\n", key, varName);
00737 return val;
00738 }
00739 
00740 void cgiMakeSubmitButton()
00741 /* Make 'submit' type button. */
00742 {
00743 cgiMakeButton("Submit", "Submit");
00744 }
00745 
00746 void cgiMakeResetButton()
00747 /* Make 'reset' type button. */
00748 {
00749 printf("<INPUT TYPE=RESET NAME=\"Reset\" VALUE=\" Reset \">");
00750 }
00751 
00752 void cgiMakeClearButton(char *form, char *field)
00753 /* Make button to clear a text field. */
00754 {
00755 char javascript[1024];
00756 
00757 safef(javascript, sizeof(javascript), 
00758     "document.%s.%s.value = ''; document.%s.submit();", form, field, form);
00759 cgiMakeOnClickButton(javascript, " Clear  ");
00760 }
00761 
00762 void cgiMakeButtonWithMsg(char *name, char *value, char *msg)
00763 /* Make 'submit' type button. Display msg on mouseover, if present*/
00764 {
00765 printf("<INPUT TYPE=SUBMIT NAME=\"%s\" VALUE=\"%s\" %s%s%s>", 
00766         name, value, 
00767         (msg ? " TITLE=\"" : ""), (msg ? msg : ""), (msg ? "\"" : "" ));
00768 }
00769 
00770 void cgiMakeButton(char *name, char *value)
00771 /* Make 'submit' type button */
00772 {
00773 cgiMakeButtonWithMsg(name, value, NULL);
00774 }
00775 
00776 void cgiMakeOnClickButton(char *command, char *value)
00777 /* Make 'push' type button with client side onClick (java)script. */
00778 {
00779 printf("<INPUT TYPE=\"button\" VALUE=\"%s\" onClick=\"%s\">", value, command);
00780 }
00781 
00782 void cgiMakeOptionalButton(char *name, char *value, boolean disabled)
00783 /* Make 'submit' type button that can be disabled. */
00784 {
00785 printf("<INPUT TYPE=SUBMIT NAME=\"%s\" VALUE=\"%s\"", name, value);
00786 if (disabled)
00787     printf(" DISABLED");
00788 printf(">"); 
00789 }
00790 
00791 void cgiMakeFileEntry(char *name)
00792 /* Make file entry box/browser */
00793 {
00794     printf("<INPUT TYPE=FILE NAME=\"%s\">", name);
00795 }
00796 
00797 void cgiSimpleTableStart()
00798 /* start HTML table  -- no customization. Leaves room
00799  * for a fancier implementation */
00800 {
00801 printf("<TABLE>\n");
00802 }
00803 
00804 void cgiTableEnd()
00805 /* end HTML table */
00806 {
00807 printf("</TABLE>\n");
00808 }
00809 
00810 void cgiSimpleTableRowStart()
00811 /* Start table row */
00812 {
00813 printf("<TR>\n");
00814 }
00815 
00816 void cgiTableRowEnd()
00817 /* End table row */
00818 {
00819 printf("</TR>\n");
00820 }
00821 
00822 void cgiSimpleTableFieldStart()
00823 /* Start table field */
00824 {
00825 printf("<TD>");
00826 }
00827 
00828 void cgiTableFieldEnd()
00829 /* End table field */
00830 {
00831 printf("</TD>\n");
00832 }
00833 
00834 void cgiTableField(char *text)
00835 /* Make table field entry */
00836 {
00837 printf("<TD> %s </TD>\n", text);
00838 }
00839 
00840 void cgiTableFieldWithMsg(char *text, char *msg)
00841 /* Make table field entry with mouseover */
00842 {
00843 printf("<TD %s%s%s> %s </TD>\n", 
00844         (msg ? " TITLE=\"" : ""), (msg ? msg : ""), (msg ? "\"" : "" ),
00845         text);
00846 }
00847 
00848 void cgiParagraph(char *text)
00849 /* Make text paragraph */
00850 {
00851 printf("<P> %s\n", text);
00852 }
00853 
00854 void cgiMakeRadioButton(char *name, char *value, boolean checked)
00855 /* Make radio type button.  A group of radio buttons should have the
00856  * same name but different values.   The default selection should be
00857  * sent with checked on. */
00858 {
00859 printf("<INPUT TYPE=RADIO NAME=\"%s\" VALUE=\"%s\" %s>", name, value,
00860    (checked ? "CHECKED" : ""));
00861 }
00862 
00863 void cgiMakeOnClickRadioButton(char *name, char *value, boolean checked,
00864                                         char *command)
00865 /* Make radio type button with onClick command.
00866  *  A group of radio buttons should have the
00867  * same name but different values.   The default selection should be
00868  * sent with checked on. */
00869 {
00870 printf("<INPUT TYPE=RADIO NAME=\"%s\" VALUE=\"%s\" %s %s>",
00871         name, value, command, (checked ? "CHECKED" : ""));
00872 }
00873 
00874 char *cgiBooleanShadowPrefix()
00875 /* Prefix for shadow variable set with boolean variables. */
00876 {
00877 return "boolshad.";
00878 }
00879 
00880 boolean cgiBooleanDefined(char *name)
00881 /* Return TRUE if boolean variable is defined (by
00882  * checking for shadow. */
00883 {
00884 char buf[256];
00885 safef(buf, sizeof(buf), "%s%s", cgiBooleanShadowPrefix(), name);
00886 return cgiVarExists(buf);
00887 }
00888 
00889 void cgiMakeCheckBoxWithMsg(char *name, boolean checked, char *msg)
00890 /* Make check box. Also make a shadow hidden variable so we
00891  * can distinguish between variable not present and
00892  * variable set to false. Use msg as mousever if present */
00893 {
00894 char buf[256];
00895 
00896 printf("<INPUT TYPE=CHECKBOX NAME=\"%s\" VALUE=on %s%s%s %s>", name,
00897     (msg ? " TITLE=\"" : ""), (msg ? msg : ""), (msg ? "\"" : "" ), 
00898     (checked ? " CHECKED" : ""));
00899 safef(buf, sizeof(buf), "%s%s", cgiBooleanShadowPrefix(), name);
00900 cgiMakeHiddenVar(buf, "1");
00901 }
00902 
00903 void cgiMakeCheckBox(char *name, boolean checked)
00904 /* Make check box. */
00905 {
00906 cgiMakeCheckBoxWithMsg(name, checked, NULL);
00907 }
00908 
00909 void cgiMakeHiddenBoolean(char *name, boolean on)
00910 /* Make hidden boolean variable. Also make a shadow hidden variable so we
00911  * can distinguish between variable not present and
00912  * variable set to false. */
00913 {
00914 char buf[256];
00915 cgiMakeHiddenVar(name, on ? "on" : "off");
00916 safef(buf, sizeof(buf), "%s%s", cgiBooleanShadowPrefix(), name);
00917 cgiMakeHiddenVar(buf, "1");
00918 }
00919 
00920 void cgiMakeTextArea(char *varName, char *initialVal, int rowCount, int columnCount)
00921 /* Make a text area with area rowCount X columnCount and with text: intialVal */
00922 {
00923 cgiMakeTextAreaDisableable(varName, initialVal, rowCount, columnCount, FALSE);
00924 }
00925 
00926 void cgiMakeTextAreaDisableable(char *varName, char *initialVal, int rowCount, int columnCount, boolean disabled)
00927 /* Make a text area that can be disabled. The rea has rowCount X 
00928  * columnCount and with text: intialVal */
00929 {
00930 printf("<TEXTAREA NAME=\"%s\" ROWS=%d COLS=%d %s>%s</TEXTAREA>", varName,
00931        rowCount, columnCount, disabled ? "DISABLED" : "",
00932        (initialVal != NULL ? initialVal : ""));
00933 }
00934 
00935 void cgiMakeTextVar(char *varName, char *initialVal, int charSize)
00936 /* Make a text control filled with initial value.  If charSize
00937  * is zero it's calculated from initialVal size. */
00938 {
00939 if (initialVal == NULL)
00940     initialVal = "";
00941 if (charSize == 0) charSize = strlen(initialVal);
00942 if (charSize == 0) charSize = 8;
00943 
00944 printf("<INPUT TYPE=TEXT NAME=\"%s\" SIZE=%d VALUE=\"%s\">", varName, 
00945         charSize, initialVal);
00946 }
00947 
00948 void cgiMakeIntVar(char *varName, int initialVal, int maxDigits)
00949 /* Make a text control filled with initial value.  */
00950 {
00951 if (maxDigits == 0) maxDigits = 4;
00952 
00953 printf("<INPUT TYPE=TEXT NAME=\"%s\" SIZE=%d VALUE=%d>", varName, 
00954         maxDigits, initialVal);
00955 }
00956 
00957 void cgiMakeDoubleVar(char *varName, double initialVal, int maxDigits)
00958 /* Make a text control filled with initial floating-point value.  */
00959 {
00960 if (maxDigits == 0) maxDigits = 4;
00961 
00962 printf("<INPUT TYPE=TEXT NAME=\"%s\" SIZE=%d VALUE=%g>", varName, 
00963         maxDigits, initialVal);
00964 }
00965 
00966 
00967 
00968 void cgiMakeDropList(char *name, char *menu[], int menuSize, char *checked)
00969 /* Make a drop-down list with names. 
00970  * uses style "normalText" */
00971 {
00972     cgiMakeDropListClass(name, menu, menuSize, checked, "normalText");
00973 }
00974 
00975 /* Make a drop-down list with names. */
00976 void cgiMakeDropListClass(char *name, char *menu[], 
00977         int menuSize, char *checked, char *class)
00978 /* Make a drop-down list with names. */
00979 {
00980 int i;
00981 char *selString;
00982 if (checked == NULL) checked = menu[0];
00983 printf("<SELECT NAME=\"%s\" class=%s>\n", name, class);
00984 for (i=0; i<menuSize; ++i)
00985     {
00986     if (sameWord(menu[i], checked))
00987         selString = " SELECTED";
00988     else
00989         selString = "";
00990     printf("<OPTION%s>%s</OPTION>\n", selString, menu[i]);
00991     }
00992 printf("</SELECT>\n");
00993 }
00994 
00995 void cgiMakeMultList(char *name, char *menu[], int menuSize, char *checked, int length)
00996 /* Make a list of names with window height equalt to length,
00997  * which can have multiple selections. Same as drop-down list 
00998  * except "multiple" is added to select tag. */
00999 {
01000 int i;
01001 char *selString;
01002 if (checked == NULL) checked = menu[0];
01003 printf("<SELECT MULTIPLE SIZE=%d ALIGN=CENTER NAME=\"%s\">\n", length, name);
01004 for (i=0; i<menuSize; ++i)
01005     {
01006     if (sameWord(menu[i], checked))
01007         selString = " SELECTED";
01008     else
01009         selString = "";
01010     printf("<OPTION%s>%s</OPTION>\n", selString, menu[i]);
01011     }
01012 printf("</SELECT>\n");
01013 }
01014 
01015 void cgiMakeDropListFull(char *name, char *menu[], char *values[], 
01016                          int menuSize, char *checked, char *extraAttribs)
01017 /* Make a drop-down list with names and values. */
01018 {
01019 int i;
01020 char *selString;
01021 if (checked == NULL) checked = menu[0];
01022 
01023 if (NULL != extraAttribs)
01024     {
01025     printf("<SELECT NAME=\"%s\" %s>\n", name, extraAttribs);
01026     }
01027 else
01028     {
01029     printf("<SELECT NAME=\"%s\">\n", name);
01030     }
01031 
01032 for (i=0; i<menuSize; ++i)
01033     {
01034     if (sameWord(values[i], checked))
01035         selString = " SELECTED";
01036     else
01037         selString = "";
01038     printf("<OPTION%s VALUE=\"%s\">%s</OPTION>\n", selString, values[i], menu[i]);
01039     }
01040 printf("</SELECT>\n");
01041 }
01042 
01043 void cgiMakeDropListWithVals(char *name, char *menu[], char *values[], 
01044                          int menuSize, char *checked)
01045 /* Make a drop-down list with names and values. In this case checked
01046  * corresponds to a value, not a menu. */
01047 {
01048 int i;
01049 char *selString;
01050 if (checked == NULL) checked = values[0];
01051 
01052 printf("<SELECT NAME=\"%s\">\n", name);
01053 for (i=0; i<menuSize; ++i)
01054     {
01055     if (sameWord(values[i], checked))
01056         selString = " SELECTED";
01057     else
01058         selString = "";
01059     printf("<OPTION%s VALUE=\"%s\">%s</OPTION>\n", selString, values[i], menu[i]);
01060     }
01061 printf("</SELECT>\n");
01062 }
01063 
01064 void cgiMakeHiddenVar(char *varName, char *string)
01065 /* Store string in hidden input for next time around. */
01066 {
01067 printf("<INPUT TYPE=HIDDEN NAME=\"%s\" VALUE=\"%s\">", varName, string);
01068 }
01069 
01070 void cgiContinueHiddenVar(char *varName)
01071 /* Write CGI var back to hidden input for next time around. */
01072 {
01073 if (cgiVarExists(varName))
01074     cgiMakeHiddenVar(varName, cgiString(varName));
01075 }
01076 
01077 void cgiVarExclude(char *varName)
01078 /* If varName exists, remove it. */
01079 {
01080 if (cgiVarExists(varName))
01081     {
01082     struct cgiVar *cv = hashRemove(inputHash, varName);
01083     slRemoveEl(&inputList, cv);
01084     }
01085 }
01086 
01087 void cgiVarExcludeExcept(char **varNames)
01088 /* Exclude all variables except for those in NULL
01089  * terminated array varNames.  varNames may be NULL
01090  * in which case nothing is excluded. */
01091 {
01092 struct hashEl *list, *el;
01093 struct hash *exclude = newHash(8);
01094 char *s;
01095 
01096 /* Build up hash of things to exclude */
01097 if (varNames != NULL)
01098    {
01099    while ((s = *varNames++) != NULL)
01100        hashAdd(exclude, s, NULL);
01101    }
01102 
01103 /* Step through variable list and remove them if not
01104  * excluded. */
01105 initCgiInput();
01106 list = hashElListHash(inputHash);
01107 for (el = list; el != NULL; el = el->next)
01108     {
01109     if (!hashLookup(exclude, el->name))
01110         cgiVarExclude(el->name);
01111     }
01112 hashElFreeList(&list);
01113 freeHash(&exclude);
01114 }
01115 
01116 void cgiVarSet(char *varName, char *val)
01117 /* Set a cgi variable to a particular value. */
01118 {
01119 struct cgiVar *var;
01120 initCgiInput();
01121 AllocVar(var);
01122 var->val = cloneString(val);
01123 hashAddSaveName(inputHash, varName, var, &var->name);
01124 }
01125 
01126 struct dyString *cgiUrlString()
01127 /* Get URL-formatted that expresses current CGI variable state. */
01128 {
01129 struct dyString *dy = newDyString(0);
01130 struct cgiVar *cv;
01131 char *e;
01132 
01133 
01134 for (cv = inputList; cv != NULL; cv = cv->next)
01135     {
01136     if (cv != inputList)
01137        dyStringAppend(dy, "&");
01138     e = cgiEncode(cv->val);
01139     dyStringPrintf(dy, "%s=", cv->name);
01140     dyStringAppend(dy, e);
01141     freez(&e);
01142     }
01143 return dy;
01144 }
01145 
01146 void cgiContinueAllVars()
01147 /* Write back all CGI vars as hidden input for next time around. */
01148 {
01149 struct cgiVar *cv;
01150 for (cv = inputList; cv != NULL; cv = cv->next)
01151     cgiMakeHiddenVar(cv->name, cv->val);
01152 }
01153 
01154 
01155 boolean cgiFromCommandLine(int *pArgc, char *argv[], boolean preferWeb)
01156 /* Use the command line to set up things as if we were a CGI program. 
01157  * User types in command line (assuming your program called cgiScript) 
01158  * like:
01159  *        cgiScript nonCgiArg1 var1=value1 var2=value2 var3=value3 nonCgiArg2
01160  * or like
01161  *        cgiScript nonCgiArg1 var1=value1&var2=value2&var3=value3 nonCgiArg2
01162  * or even like
01163  *        cgiScript nonCgiArg1 -x -y=bogus z=really
01164  * (The non-cgi arguments can occur anywhere.  The cgi arguments (all containing
01165  * the character '=' or starting with '-') are erased from argc/argv.  Normally 
01166  * you call this cgiSpoof(&argc, argv);
01167  */
01168 {
01169 int argc = *pArgc;
01170 int i;
01171 int argcLeft = argc;
01172 char *name;
01173 static char queryString[4096];
01174 char *q = queryString;
01175 boolean needAnd = TRUE;
01176 boolean gotAny = FALSE;
01177 boolean startDash;
01178 boolean gotEq;
01179 static char hostLine[512];
01180 
01181 if (preferWeb && cgiIsOnWeb())
01182     return TRUE;        /* No spoofing required! */
01183 q += safef(q, queryString + sizeof(queryString) - q,
01184            "%s", "QUERY_STRING=cgiSpoof=on");
01185 for (i=0; i<argcLeft; )
01186     {
01187     name = argv[i];
01188     if ((startDash = (name[0] == '-')))
01189        ++name;
01190     gotEq = (strchr(name, '=') != NULL);
01191     if (gotEq || startDash)
01192         {
01193         if (needAnd)
01194             *q++ = '&';
01195         q += safef(q, queryString + sizeof(queryString) - q, "%s", name);
01196         if (!gotEq || strchr(name, '&') == NULL)
01197             needAnd = TRUE;
01198         if (!gotEq)
01199             q += safef(q, queryString + sizeof(queryString) - q, "=on");
01200         memcpy(&argv[i], &argv[i+1], sizeof(argv[i]) * (argcLeft-i-1));
01201         argcLeft -= 1;
01202         gotAny = TRUE;
01203         }
01204     else
01205         i++;
01206     }
01207 if (gotAny)
01208     {
01209     *pArgc = argcLeft;
01210     }
01211 putenv("REQUEST_METHOD=GET");
01212 putenv(queryString);
01213 safef(hostLine, sizeof(hostLine), "SERVER_NAME=%s", getenv("HOST"));
01214 putenv(hostLine);
01215 initCgiInput();
01216 return gotAny;
01217 }
01218 
01219 boolean cgiSpoof(int *pArgc, char *argv[])
01220 /* If run from web line set up input
01221  * variables from web line, otherwise
01222  * set up from command line. */
01223 {
01224 return cgiFromCommandLine(pArgc, argv, TRUE);
01225 }
01226 
01227 boolean cgiFromFile(char *fileName)
01228 /* Set up a cgi environment using parameters stored in a file.
01229  * Takes file with arguments in the form:
01230  *       argument1=someVal
01231  *       # This is a comment
01232  *       argument2=someOtherVal
01233  *       ...
01234  * and puts them into the cgi environment so that the usual
01235  * cgiGetVar() commands can be used. Useful when a program 
01236  * has a lot of possible parameters.
01237  */
01238 {
01239 char **argv = NULL;
01240 int argc = 0; 
01241 int maxArgc = 10;
01242 int i;
01243 struct lineFile *lf = lineFileOpen(fileName, TRUE);
01244 char *line;
01245 boolean spoof= FALSE;
01246 AllocArray(argv, maxArgc);
01247 /* Remember that first arg is program name.
01248    Put filename there instead. */
01249 argc = 1; 
01250 argv[0] = cloneString(fileName);
01251 for(;;)
01252     {
01253     /* If we are at the end we're done. */
01254     if(!lineFileNext(lf, &line, NULL))
01255         break;
01256     /* If it is a comment or blank line skip it. */
01257     if (line[0] == '#' || sameString(line, ""))
01258         continue;
01259     /* If our argv array is full expand it. */
01260     if((argc+1) >= maxArgc)
01261         {
01262         ExpandArray(argv, maxArgc, 2*maxArgc);
01263         maxArgc *= 2;
01264         }
01265     /* Fill in another argument to our psuedo arguments. */
01266     argv[argc++] = cloneString(line);
01267     }
01268 spoof = cgiSpoof(&argc, argv);
01269 /* Cleanup. */
01270 lineFileClose(&lf);
01271 for(i=0; i<argc; i++)
01272     freez(&argv[i]);
01273 freez(&argv);
01274 return spoof;
01275 }

Generated on Tue Dec 25 18:39:30 2007 for blat by  doxygen 1.5.2