a53b9958fa734f73aeffb9ddfe2fbad1ca65f90c galt Mon Jan 30 16:18:41 2017 -0800 Check-in of CSP2 Content-Security-Policy work. All C-language CGIs should now support CSP2 in browser to stop major forms of XSS javascript injection. Javascript on pages is gathered together, and then emitted in a single script block at the end with a nonce that tells the browser, this is js that we generated instead of being injected by a hacker. Both inline script from script blocks and inline js event handlers had to be pulled out and separated. You will not see js sprinkled through-out the page now. Older browsers that support CSP1 or that do not understand CSP at all will still work, just without protection. External js libraries loaded at runtime need to be added to the CSP policy header in src/lib/htmshell.c. diff --git src/hg/hgc/wikiTrack.c src/hg/hgc/wikiTrack.c index fd632d8..1ac4bab 100644 --- src/hg/hgc/wikiTrack.c +++ src/hg/hgc/wikiTrack.c @@ -1,588 +1,588 @@ /* Handle details pages for wiggle tracks. */ /* Copyright (C) 2013 The Regents of the University of California * See README in this or parent directory for licensing information. */ #include "common.h" #include "cart.h" #include "hgc.h" #include "hCommon.h" #include "hgColors.h" #include "hgConfig.h" #include "obscure.h" #include "binRange.h" #include "web.h" #include "net.h" #include "grp.h" #include "hui.h" #include "htmlPage.h" #include "wikiLink.h" #include "wikiTrack.h" #define ITEM_SCORE_DEFAULT "1000" #define ADD_ITEM_COMMENT_DEFAULT "add comments" -static char *colorMenuJS = "onchange=\"updateColorSelectBox();\" style=\"width:8em;\""; - static void colorMenuOutput() /* the item color pull-down menu in the create item form */ { hPrintf("<INPUT NAME=\"colorPullDown\" VALUE=\"\" SIZE=1 STYLE=\"display:none;\" >\n"); -hPrintf("<SELECT NAME=\"%s\" style=\"width:8em; background-color:#000000;\" %s>\n", NEW_ITEM_COLOR, colorMenuJS); +hPrintf("<SELECT NAME=\"%s\" id='%s' style=\"width:8em; background-color:#000000;\">\n" + , NEW_ITEM_COLOR, NEW_ITEM_COLOR); +jsOnEventById("change", NEW_ITEM_COLOR, "updateColorSelectBox();"); hPrintf("<OPTION SELECTED VALUE = \"#000000\" style=\"background-color:#000000;\" >black</OPTION>\n"); hPrintf("<OPTION value = \"#0000ff\" style=\"background-color:#0000ff;\" >blue</OPTION>\n"); hPrintf("<OPTION VALUE = \"#9600c8\" style=\"background-color:#9600c8;\" >purple</OPTION>\n"); hPrintf("<OPTION VALUE = \"#ff0000\" style=\"background-color:#ff0000;\" >red</OPTION>\n"); hPrintf("<OPTION VALUE = \"#e67800\" style=\"background-color:#e67800;\" >orange</OPTION>\n"); hPrintf("<OPTION VALUE = \"#dcdc00\" style=\"background-color:#dcdc00;\" >yellow</OPTION>\n"); hPrintf("<OPTION VALUE = \"#00b400\" style=\"background-color:#00b400;\" >green</OPTION>\n"); hPrintf("<OPTION VALUE = \"#8c8c8c\" style=\"background-color:#8c8c8c;\" >gray</OPTION>\n"); hPrintf("</SELECT>\n"); } static char *encodedHgcReturnUrl(int id, char *table) /* Return a CGI-encoded hgc URL with hgsid and given id. Free when done. */ { char retBuf[1024]; int o = cartUsualInt(cart, "o", winStart); safef(retBuf, sizeof(retBuf), "http://%s/cgi-bin/hgc?%s&g=%s&c=%s&o=%d&l=%d&r=%d&db=%s&i=%d", cgiServerNamePort(), cartSidUrlString(cart), table, seqName, o, winStart, winEnd, database, id); return cgiEncode(retBuf); } static char *wikiTrackUserLoginUrl(int id, char *table) /* Return the URL for the wiki user login page. */ { char *retEnc = encodedHgcReturnUrl(id, table); char buf[2048]; if (! wikiLinkEnabled()) errAbort("wikiLinkUserLoginUrl called when wiki is not enabled (specified " "in hg.conf)."); safef(buf, sizeof(buf), "%s/index.php?title=Special:UserloginUCSC&returnto=%s", cfgOptionDefault(CFG_WIKI_URL, NULL), retEnc); freez(&retEnc); return(cloneString(buf)); } void offerLogin(int id, char *loginType, char *table) /* display login prompts to the wiki when user isn't already logged in */ { char *wikiHost = wikiLinkHost(); char *loginUrl = wikiTrackUserLoginUrl(id, table); printf("<P>Please login to %s the annotation track.</P>\n", loginType); printf("<P>The login page is handled by our " "<A HREF=\"http://%s/\" TARGET=_BLANK>wiki system</A>:\n", wikiHost); printf("<A HREF=\"%s\"><B>click here to login.</B></A><BR>\n", loginUrl); printf("The wiki also serves as a forum for users " "to share knowledge and ideas.\n</P>\n"); freeMem(loginUrl); freeMem(wikiHost); webIncludeHelpFile("wikiTrackAddCommentHelp", TRUE); webIncludeHelpFile("wikiTrack", TRUE); } static void startForm(char *name, char *actionType) { hPrintf("<FORM ID=\"%s\" NAME=\"%s\" ACTION=\"%s\">\n\n", name, name, hgcName()); cartSaveSession(cart); cgiMakeHiddenVar("g", actionType); cgiContinueHiddenVar("c"); cgiContinueHiddenVar("o"); hPrintf("\n"); cgiContinueHiddenVar("l"); cgiContinueHiddenVar("r"); hPrintf("\n"); } static struct bed *multipleItems(struct wikiTrack *item) { struct sqlResult *sr; char **row; struct sqlConnection *wikiConn = wikiConnect(); char query[1024]; struct bed *bedList = NULL; sqlSafef(query, ArraySize(query), "SELECT chrom,chromStart,chromEnd,id FROM %s " "WHERE descriptionKey='%s' ORDER BY chrom,chromStart;", WIKI_TRACK_TABLE, item->descriptionKey); sr = sqlGetResult(wikiConn, query); while ( (row = sqlNextRow(sr)) != NULL) { int elId = sqlUnsigned(row[3]); if (elId == item->id) continue; struct bed *bed; AllocVar(bed); bed->chrom = cloneString(row[0]); bed->chromStart = sqlUnsigned(row[1]); bed->chromEnd = sqlUnsigned(row[2]); bed->score = elId; slAddHead(&bedList,bed); } sqlFreeResult(&sr); slSort(&bedList, bedCmpExtendedChr); wikiDisconnect(&wikiConn); return bedList; } static void displayItem(struct wikiTrack *item, char *userName) /* given an already fetched item, get the item description from * the wiki. Put up edit form(s) if userName is not NULL */ { boolean geneAnnotation = FALSE; char *url = cfgOptionDefault(CFG_WIKI_URL, NULL); if (isNotEmpty(item->geneSymbol) && differentWord(item->geneSymbol,"0")) { hPrintf("<B>This is a UCSC gene annotation</B><BR>\n"); geneAnnotation = TRUE; } else hPrintf("<B>This is a genome location annotation, not a gene annotation.</B>\n"); printPosOnChrom(item->chrom, item->chromStart, item->chromEnd, item->strand, FALSE, item->name); if (geneAnnotation) { struct bed *itemList = multipleItems(item); if (slCount(itemList) > 0) { hPrintf(" This gene symbol <B>'%s'</B> is also found in the following " "locations:<BR>\n", item->name); struct bed *el; for (el = itemList; el; el = el->next) { printf(" <B>%s:</B> " "<A HREF=\"%s&db=%s&position=%s%%3A%d-%d\">", item->name, hgTracksPathAndSettings(), database, el->chrom, el->chromStart+1, el->chromEnd); printf("%s:%d-%d</A><BR>\n", el->chrom, el->chromStart+1, el->chromEnd); } } } hPrintf("<B>Created </B>%s<B> by: </B>", item->creationDate); hPrintf("<A HREF=\"%s/index.php/User:%s\" TARGET=_blank>%s</A><BR>\n", url, item->owner, item->owner); hPrintf("<B>Most recent quick update: </B>%s<BR>\n", item->lastModifiedDate); boolean editor = isWikiEditor(userName); if ((NULL != userName) && (editor || (sameWord(userName, item->owner) && !geneAnnotation))) { hPrintf("<em>(comments for deleted items remain in the wiki, with a " "note<BR> that the item has been deleted.)</em><BR>\n"); startForm("deleteForm", G_DELETE_WIKI_ITEM); char idString[128]; safef(idString, ArraySize(idString), "%d", item->id); cgiMakeHiddenVar("i", idString); hPrintf("\n"); webPrintLinkTableStart(); webPrintLinkCellStart(); if (editor && (differentWord(userName, item->owner) || geneAnnotation)) hPrintf("Editor '%s' has deletion rights ", userName); else hPrintf("Owner '%s' has deletion rights ", item->owner); webPrintLinkCellEnd(); webPrintLinkCellStart(); cgiMakeButton("submit", "DELETE"); webPrintLinkCellEnd(); webPrintLinkCellStart(); hPrintf(" (no questions asked)"); webPrintLinkCellEnd(); webPrintLinkTableEnd(); hPrintf("\n</FORM>\n"); } hPrintf("<B>View the wiki article " "<A HREF=\"%s/index.php/%s\" TARGET=_blank>%s:</A> to see " "existing comments.</B><BR>\n", url, item->descriptionKey, item->descriptionKey); if (NULL != userName) hPrintf("<B>Mark this wiki article as <em>" "<A HREF=\"%s/index.php/%s?action=watch\" TARGET=_blank>watched</A>" "</em> to receive email notices of any comment additions.</B><BR>\n", url, item->descriptionKey); hPrintf("<HR>\n"); if (NULL == userName) { if (! wikiTrackReadOnly() ) /* read-only option 2012-06-25 */ offerLogin(item->id, "add comments to items on", WIKI_TRACK_TABLE); } else if (emailVerified(TRUE)) /* do print message when not verified */ { startForm("addComments", G_ADD_WIKI_COMMENTS); char idString[128]; safef(idString, ArraySize(idString), "%d", item->id); cgiMakeHiddenVar("i", idString); hPrintf("\n"); webPrintLinkTableStart(); /* first row is a title line */ char label[256]; safef(label, ArraySize(label), "'%s' quick add comments to item '%s'\n", userName, item->name); webPrintWideLabelCell(label, 2); webPrintLinkTableNewRow(); /* second row is initial comment/description text entry */ webPrintWideCellStart(2, HG_COL_TABLE); cgiMakeTextArea(NEW_ITEM_COMMENT, ADD_ITEM_COMMENT_DEFAULT, 3, 70); webPrintLinkCellEnd(); webPrintLinkTableNewRow(); /*webPrintLinkCellStart(); more careful explicit alignment */ hPrintf("<TD BGCOLOR=\"#%s\" ALIGN=\"CENTER\" VALIGN=\"TOP\">", HG_COL_TABLE); cgiMakeButton("submit", "add comments"); hPrintf("\n</FORM>\n"); webPrintLinkCellEnd(); /*webPrintLinkCellStart(); doesn't valign center properly */ hPrintf("<TD BGCOLOR=\"#%s\" ALIGN=\"CENTER\" VALIGN=\"TOP\">", HG_COL_TABLE); hPrintf("\n<FORM ID=\"cancel\" NAME=\"cancel\" ACTION=\"%s\">", hgTracksName()); cgiMakeButton("cancel", "return to tracks display"); hPrintf("\n</FORM>\n"); webPrintLinkCellEnd(); webPrintLinkTableEnd(); hPrintf("For more extensive edits, please edit the "); hPrintf("wiki article <A HREF=\"%s/index.php/%s\" TARGET=_blank>%s</A> " "in the wiki editing system.<BR>", url, item->descriptionKey, item->descriptionKey); webIncludeHelpFile("wikiTrackAddCommentHelp", TRUE); webIncludeHelpFile("wikiTrack", TRUE); } } /* displayItem() */ void outputJavaScript() /* java script functions used in the create item form */ { hPrintf("<SCRIPT TYPE=\"text/javascript\">\n"); hPrintf("function updateColorSelectBox() {\n" " var form = document.getElementById(\"createItem\");\n" " document.createItem.colorPullDown.style.display='inline';\n" " document.createItem.colorPullDown.select();\n" " document.createItem.colorPullDown.style.display='none';\n" " form.%s.style.background = form.%s[form.%s.selectedIndex].value;\n" " form.%s.style.color = form.%s[form.%s.selectedIndex].value;\n" "}\n", NEW_ITEM_COLOR, NEW_ITEM_COLOR, NEW_ITEM_COLOR, NEW_ITEM_COLOR, NEW_ITEM_COLOR, NEW_ITEM_COLOR); hPrintf("</SCRIPT>\n"); } void doWikiTrack(char *wikiItemId, char *chrom, int winStart, int winEnd) /* handle item clicks on wikiTrack - may create new items */ { char *userName = NULL; if (wikiTrackEnabled(database, &userName) && sameWord("0", wikiItemId)) { cartWebStart(cart, database, "%s", "User Annotation Track: Create new item"); if (NULL == userName) { if (! wikiTrackReadOnly() ) /* read-only option 2012-06-25 */ { offerLogin(0, "add new items to", WIKI_TRACK_TABLE); //cartHtmlEnd(); } return; } if (emailVerified(TRUE)) /* do print message when not verified */ { outputJavaScript(); startForm("createItem", G_CREATE_WIKI_ITEM); webPrintLinkTableStart(); /* first row is a title line */ char label[256]; safef(label, ArraySize(label), "Create new item, owner: '%s'\n", userName); webPrintWideLabelCell(label, 2); webPrintLinkTableNewRow(); /* third row is position entry box */ webPrintWideCellStart(2, HG_COL_TABLE); puts("<B>position: </B>"); savePosInTextBox(seqName, winStart+1, winEnd); hPrintf(" (size: "); printLongWithCommas(stdout, (long long)(winEnd - winStart)); hPrintf(")"); webPrintLinkCellEnd(); webPrintLinkTableNewRow(); /* fourth row is strand selection radio box */ webPrintWideCellStart(2, HG_COL_TABLE); char *strand = cartUsualString(cart, NEW_ITEM_STRAND, "plus"); boolean plusStrand = sameWord("plus",strand) ? TRUE : FALSE; hPrintf("<B>strand: "); cgiMakeRadioButton(NEW_ITEM_STRAND, "plus", plusStrand); hPrintf(" + "); cgiMakeRadioButton(NEW_ITEM_STRAND, "minus", ! plusStrand); hPrintf(" -</B>"); webPrintLinkCellEnd(); webPrintLinkTableNewRow(); /* fifth row is item name text entry */ webPrintWideCellStart(2, HG_COL_TABLE); hPrintf("<B>item name: </B>"); cgiMakeTextVar("i", NEW_ITEM_NAME, 18); webPrintLinkCellEnd(); #ifdef NOT webPrintLinkTableNewRow(); /* sixth row is item score text entry */ webPrintWideCellStart(2, HG_COL_TABLE); hPrintf("<B>item score: </B>"); cgiMakeTextVar(NEW_ITEM_SCORE, ITEM_SCORE_DEFAULT, 4); hPrintf(" (range: 0 to %s)", ITEM_SCORE_DEFAULT); webPrintLinkCellEnd(); #endif webPrintLinkTableNewRow(); /* seventh row is item color pull-down menu */ webPrintWideCellStart(2, HG_COL_TABLE); hPrintf("<B>item color: </B>"); colorMenuOutput(); webPrintLinkCellEnd(); webPrintLinkTableNewRow(); /* seventh row is initial comment/description text entry */ webPrintWideCellStart(2, HG_COL_TABLE); hPrintf("<B>initial comments/description:</B><BR>"); cgiMakeTextArea(NEW_ITEM_COMMENT, NEW_ITEM_COMMENT_DEFAULT, 5, 70); webPrintLinkCellEnd(); webPrintLinkTableNewRow(); /* seventh row is the submit and cancel buttons */ /*webPrintLinkCellStart(); more careful explicit alignment */ hPrintf("<TD BGCOLOR=\"#%s\" ALIGN=\"CENTER\" VALIGN=\"TOP\">", HG_COL_TABLE); cgiMakeButton("submit", "create new item"); hPrintf("\n</FORM>\n"); webPrintLinkCellEnd(); /*webPrintLinkCellStart(); doesn't valign center properly */ hPrintf("<TD BGCOLOR=\"#%s\" ALIGN=\"CENTER\" VALIGN=\"TOP\">", HG_COL_TABLE); hPrintf("\n<FORM ID=\"cancel\" NAME=\"cancel\" ACTION=\"%s\">", hgTracksName()); cgiMakeButton("cancel", "cancel"); hPrintf("\n</FORM>\n"); webPrintLinkCellEnd(); webPrintLinkTableEnd(); hPrintf("This entry form starts the comments for this new item.<BR>\n" "Subsequent edits will be performed in the wiki editing system." "<BR>\n"); webIncludeHelpFile("wikiTrackCreateItemHelp", TRUE); webIncludeHelpFile("wikiTrack", TRUE); } } else { struct wikiTrack *item = findWikiItemId(wikiItemId); cartWebStart(cart, database, "%s (%s) %s", "User Annotation Track", item->name, wikiItemId); /* if we can get the hgc clicks to add item id to the incoming data, * then use that item Id here */ displayItem(item, userName); } } /* void doWikiTrack() */ static void updateLastModifiedDate(int id) /* set lastModifiedDate to now() */ { char query[512]; struct sqlConnection *wikiConn = wikiConnect(); sqlSafef(query, ArraySize(query), "UPDATE %s set lastModifiedDate=now() WHERE id='%d'", WIKI_TRACK_TABLE, id); sqlUpdate(wikiConn,query); wikiDisconnect(&wikiConn); } static void deleteItem(int id) /* delete the item with specified id */ { char query[512]; struct sqlConnection *wikiConn = wikiConnect(); sqlSafef(query, ArraySize(query), "DELETE FROM %s WHERE id='%d'", WIKI_TRACK_TABLE, id); sqlUpdate(wikiConn,query); wikiDisconnect(&wikiConn); } void doDeleteWikiItem(char *wikiItemId, char *chrom, int winStart, int winEnd) /* handle delete item clicks for wikiTrack */ { char *userName = NULL; struct wikiTrack *item = findWikiItemId(wikiItemId); cartWebStart(cart, database, "%s (%s)", "User Annotation Track, deleted item: ", item->name); if (NULL == wikiItemId) errAbort("delete wiki item: NULL wikiItemId"); if (! wikiTrackEnabled(database, &userName)) errAbort("delete wiki item: wiki track not enabled"); /* this may be a multiple loci gene symbol annotation */ struct bed *itemList = multipleItems(item); char comments[1024]; if (slCount(itemList) > 0) safef(comments,ArraySize(comments), "This item '''%s''' on assembly %s " "at %s:%d-%d (and %d other loci) has been deleted from the wiki track\n\n", item->name, item->db, item->chrom, item->chromStart, item->chromEnd, slCount(itemList)); else safef(comments,ArraySize(comments), "This item '''%s''' on assembly %s " "at %s:%d-%d has been deleted from the wiki track\n\n", item->name, item->db, item->chrom, item->chromStart, item->chromEnd); prefixComments(item, comments, userName, seqName, winStart, winEnd, database, NULL, "(deleted item)", NEW_ITEM_CATEGORY); deleteItem(sqlSigned(wikiItemId)); /* this may be a multiple loci gene symbol annotation */ if (slCount(itemList) > 0) { struct bed *el; for (el = itemList; el; el = el->next) deleteItem(el->score); } hPrintf("<BR>\n"); hPrintf("<FORM ID=\"delete\" NAME=\"delete\" ACTION=\"%s\">", hgTracksName()); cgiMakeButton("submit", "return to tracks display"); hPrintf("\n</FORM>\n"); hPrintf("<BR>\n"); webIncludeHelpFile("wikiTrack", TRUE); } void doAddWikiComments(char *wikiItemId, char *chrom, int winStart, int winEnd) /* handle add comment item clicks for wikiTrack */ { char *userName = NULL; struct wikiTrack *item = findWikiItemId(wikiItemId); cartWebStart(cart, database, "%s (%s)", "User Annotation Track", item->name); if (NULL == wikiItemId) errAbort("add wiki comments: NULL wikiItemId"); if (! wikiTrackEnabled(database, &userName)) errAbort("add wiki comments: wiki track not enabled"); if (NULL == userName) errAbort("add wiki comments: user not logged in ?"); addDescription(item, userName, seqName, winStart, winEnd, cart, database, NULL, NULL, NEW_ITEM_CATEGORY); updateLastModifiedDate(sqlSigned(wikiItemId)); displayItem(item, userName); } void doCreateWikiItem(char *itemName, char *chrom, int winStart, int winEnd) /* handle create item clicks for wikiTrack */ { int itemStart = 0; int itemEnd = 0; char *chrName = NULL; char *pos = NULL; char *strand = cartUsualString(cart, NEW_ITEM_STRAND, "plus"); char *class = cartUsualString(cart, NEW_ITEM_CLASS, ITEM_NOT_CLASSIFIED); boolean plusStrand = sameWord("plus",strand) ? TRUE : FALSE; char descriptionKey[256]; struct sqlConnection *wikiConn = wikiConnect(); char *userName = NULL; char *color = cartUsualString(cart, NEW_ITEM_COLOR, "#000000"); int score = 0; struct wikiTrack *newItem; if (! wikiTrackEnabled(database, &userName)) errAbort("create new wiki item: wiki track not enabled"); if (NULL == userName) errAbort("create new wiki item: user not logged in ?"); #ifdef NOT score = sqlSigned(cartUsualString(cart, NEW_ITEM_SCORE, ITEM_SCORE_DEFAULT)); #endif score = 0; pos = stripCommas(cartOptionalString(cart, "getDnaPos")); if (NULL == pos) errAbort("create new wiki item: called incorrectly, without getDnaPos"); hgParseChromRange(database, pos, &chrName, &itemStart, &itemEnd); if (NULL == chrName) webAbort("Wiki Annotation", "illegal chrom name entered: '%s'<BR>\n" "Note: chrom names are case sensitive.<BR>\n", pos); char *realChrName = hgOfficialChromName(database, chrName); if (NULL == realChrName) webAbort("Wiki Annotation", "illegal chrom name entered: '%s'<BR>\n" "Note: chrom names are case sensitive.<BR>\n", pos); if (itemStart > itemEnd) { int t = itemEnd; itemEnd = itemStart; itemStart = t; } safef(descriptionKey,ArraySize(descriptionKey), "GenomeAnnotation:%s-%d", database, 0); AllocVar(newItem); newItem->bin = binFromRange(itemStart, itemEnd); newItem->chrom = cloneString(realChrName); newItem->chromStart = itemStart; newItem->chromEnd = itemEnd; newItem->name = cloneString(itemName); newItem->score = score; safef(newItem->strand, sizeof(newItem->strand), "%s", plusStrand ? "+" : "-"); newItem->db = cloneString(database); newItem->owner = cloneString(userName); newItem->class = cloneString(class); newItem->color = cloneString(color); newItem->creationDate = cloneString("0"); newItem->lastModifiedDate = cloneString("0"); newItem->descriptionKey = cloneString(descriptionKey); newItem->id = 0; newItem->geneSymbol = cloneString("0"); wikiTrackSaveToDb(wikiConn, newItem, WIKI_TRACK_TABLE, 1024); int id = sqlLastAutoId(wikiConn); safef(descriptionKey,ArraySize(descriptionKey), "GenomeAnnotation:%s-%d", database, id); wikiTrackFree(&newItem); char newItemName[128]; char query[512]; if (sameWord(itemName,NEW_ITEM_NAME)) { safef(newItemName, ArraySize(newItemName), "%s-%d", database, id); sqlSafef(query, ArraySize(query), "UPDATE %s set creationDate=now(),lastModifiedDate=now(),descriptionKey='%s',name='%s-%d' WHERE id='%d'", WIKI_TRACK_TABLE, descriptionKey, database, id, id); } else { safef(newItemName, ArraySize(newItemName), "%s", itemName); sqlSafef(query, ArraySize(query), "UPDATE %s set creationDate=now(),lastModifiedDate=now(),descriptionKey='%s' WHERE id='%d'", WIKI_TRACK_TABLE, descriptionKey, id); } sqlUpdate(wikiConn,query); wikiDisconnect(&wikiConn); cartWebStart(cart, database, "%s %s", "User Annotation Track, created new item: ", newItemName); char wikiItemId[64]; safef(wikiItemId,ArraySize(wikiItemId),"%d", id); struct wikiTrack *item = findWikiItemId(wikiItemId); addDescription(item, userName, seqName, winStart, winEnd, cart, database, NULL, NULL, NEW_ITEM_CATEGORY); displayItem(item, userName); } /* void doCreateWikiItem() */