7976e2588e92dca0567231cf3998759bf6f1827f max Thu May 7 03:27:42 2015 -0700 implementing the external tools "send to" menu, refs #15113 diff --git src/hg/hgTracks/extTools.c src/hg/hgTracks/extTools.c new file mode 100644 index 0000000..ab95586 --- /dev/null +++ src/hg/hgTracks/extTools.c @@ -0,0 +1,192 @@ +// Code to parse list of external tools and redirect to it via a hidden form */ +// +// The link from hgTracks has the form ?hgt.redirectTool= +// Note that you can add the parameter &debug=1 to the URL to see and modify the hidden form +// cgi-bin/extTools.ra defines the parameters and labels of the tools + +/* Copyright (C) 2014 The Regents of the University of California + * See README in this or parent directory for licensing information. */ + +#include "common.h" +#include "dystring.h" +#include "hCommon.h" +#include "htmshell.h" +#include "hash.h" +#include "web.h" +#include "ra.h" +#include "hgTracks.h" +#include "extTools.h" +#include "hgFind.h" +#include "obscure.h" + +static char *getRequiredRaSetting(struct hash *hash, char *name, struct lineFile *lf) +/* Grab a group setting out of the ra hash. errAbort if not found. */ +{ +char *str; +if ((str = hashFindVal(hash, name)) == NULL) + errAbort("missing required setting '%s' on line %d in file %s\n", + name, lf->lineIx, lf->fileName); +return str; +} + +struct extTool *readExtToolRa(char *raFileName) +/* parse the extTools.ra file. Inspired by trackHub.c:readGroupRa() */ +{ +struct lineFile *lf = udcWrapShortLineFile(raFileName, NULL, 1*1024*1024); +struct extTool *list = NULL; +//struct hash *ra; +struct slPair *raList; +while ((raList = raNextStanzAsPairs(lf)) != NULL) + { + struct extTool *et; + AllocVar(et); + + struct slPair *paramList = NULL; + + struct hash *raHash; + raHash = hashNew(0); + + // the "param" field is there more than once, so cannot use a hash for it + struct slPair *raPair; + for (raPair = raList; raPair != NULL; raPair = raPair->next) + { + if (sameWord(raPair->name, "param")) + { + // split the val into parameter name and value + char *paramArr[2]; + int fCount = chopByWhite(raPair->val, paramArr, 2); + // hacky way to allow spaces in parameter names and values + char *name = replaceChars(paramArr[0], "%20", " "); + char *val; + if (fCount==2) + val = cloneString(paramArr[1]); + else + val = cloneString(""); + val = replaceChars(val, "%20", " "); + slPairAdd(¶mList, name, val); + } + else + // add all other name/val pairs to the hash + hashAdd(raHash, raPair->name, cloneString(raPair->val)); + } + + // pull out the normal fields from the hash + et->tool = cloneString(getRequiredRaSetting(raHash, "tool", lf)); + et->shortLabel = cloneString(getRequiredRaSetting(raHash, "shortLabel", lf)); + char *maxSize = hashFindVal(raHash, "maxSize"); + if (maxSize!=NULL) + et->maxSize = sqlUnsignedOrError(maxSize, "Error: maxSize %s for tool %s is not a number", \ + maxSize, et->tool); + et->longLabel = cloneString(getRequiredRaSetting(raHash, "longLabel", lf)); + et->url = cloneString(getRequiredRaSetting(raHash, "url", lf)); + et->dbs = NULL; + if (hashFindVal(raHash, "dbs")) + et->dbs = commaSepToSlNames(hashFindVal(raHash, "dbs")); + + slReverse(¶mList); + et->params = paramList; + + slAddHead(&list, et); + freeHashAndVals(&raHash); + slPairFree(&raList); + } + +if (list) + slReverse(&list); +lineFileClose(&lf); +return list; +} + +void extToolRedirect(struct cart *cart, char *tool) +/* redirect to an external tool, sending the data specified in the ext tools config file */ +{ +bool debug = cgiVarExists("debug"); + +struct extTool *extTools = readExtToolRa("extTools.ra"); +struct extTool *et; +for (et = extTools; et != NULL; et = et->next) + if (sameWord(et->tool, tool)) + break; +if (et==NULL) + errAbort("No configuration found for tool %s", tool); + +// construct an invisible CGI form with the given parameters +printf("\n"); + +if (debug) + printf("Target URL: %s

", et->url); + +printf("

\n", et->url); + +struct slPair *slp; +char *db = cartString(cart, "db"); +char *pos = cartString(cart, "position"); + +char *chromName; +int winStart, winEnd; +findGenomePos(db, pos, &chromName, &winStart, &winEnd, cart); +int len = winEnd-winStart; + +if (et->maxSize!=0 && len > et->maxSize) + { + printf("Sorry, this tool accepts only a sequence with less than %d base pairs

\n" + "Try to zoom in some more.

\n", et->maxSize); + return; + } + +boolean submitDone = FALSE; +for (slp=et->params; slp!=NULL; slp=slp->next) + { + char* val = slp->val; + if (sameWord(val, "$db")) + val = db; + if (sameWord(val, "$position")) + val = pos; + if (stringIn("$halfLen", val)) + { + char buf[64]; + safef(buf, sizeof(buf), "%d", len/2); + val = replaceChars(val, "$halfLen", buf); + } + if (sameWord(val, "$seq")) + { + static struct dnaSeq *seq = NULL; + seq = hDnaFromSeq(db, chromName, winStart, winEnd, dnaLower); + val = seq->dna; + } + // any remaining $-expression might be one of the general ones + if (stringIn("$", val)) + val = replaceInUrl(val, "", cart, db, chromName, winStart, winEnd, NULL, TRUE); + + // output + if (debug) + { + printf("%s: ", slp->name); + printf("

", slp->name, val); + } + else + { + // parameter named submit is a special case + if (sameWord(slp->name, "submit")) + { + submitDone = TRUE; + printf("\n", val); + } + else + printf("", slp->name, val); + } + } + +// a hidden submit button, see +// http://stackoverflow.com/questions/477691/submitting-a-form-by-pressing-enter-without-a-submit-button +if (debug) + printf("\n"); +else if (!submitDone) + printf("\n"); +printf("

\n"); +// a little javascript that clicks the submit button +if (!debug) + printf("\n"); +printf("\n"); +}