198c9b8daecc44fbda6a6494c566c723920f030a lrnassar Wed Mar 11 18:25:21 2026 -0700 Fixing a few hundred clear typos with the help of Claude. Some are less important in code comments, but majority of them are in user-facing places. I manually approved 60%+ of the changes and didn't see any that were an incorrect suggestion, at worst it was potentially uncessesary, like a code comment having cant instead of can't. No RM. diff --git src/hg/hgUserSuggestion/hgUserSuggestion.c src/hg/hgUserSuggestion/hgUserSuggestion.c index 2c4fa5cd3d7..89735098a7b 100644 --- src/hg/hgUserSuggestion/hgUserSuggestion.c +++ src/hg/hgUserSuggestion/hgUserSuggestion.c @@ -1,687 +1,687 @@ /* hgUserSuggestion - CGI-script to collect user's suggestion. */ /* Copyright (C) 2013 The Regents of the University of California * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */ #include "common.h" #include "errAbort.h" #include "hCommon.h" #include "jksql.h" #include "portable.h" #include "cheapcgi.h" #include "htmshell.h" #include "hdb.h" #include "hui.h" #include "cart.h" #include "hPrint.h" #include "dbDb.h" #include "web.h" #include "hash.h" #include "hgConfig.h" #include "hgUserSuggestion.h" #include "mailViaPipe.h" #include "htmlPage.h" #include "net.h" #include "jsonParse.h" /* ---- Global variables. ---- */ struct cart *cart; /* The user's ui state. */ struct hash *oldVars = NULL; /* ---- Global helper functions ---- */ void checkHgConfForSuggestion() /* Abort if hg.conf has not been set up to accept suggestion */ { if (isEmpty(cfgOption(CFG_SUGGEST_MAILTOADDR)) || isEmpty(cfgOption(CFG_SUGGEST_MAILFROMADDR)) || isEmpty(cfgOption(CFG_FILTERKEYWORD)) || isEmpty(cfgOption(CFG_SUGGEST_MAIL_SIGNATURE)) || isEmpty(cfgOption(CFG_SUGGEST_MAIL_RETURN_ADDR)) || isEmpty(cfgOption(CFG_SUGGEST_BROWSER_NAME))) errAbort("This Genome Browser has not been configured to accept suggestions yet. Please contact the browser administrator for more information."); } char *mailToAddr() /* Return the address to send suggestion to */ { return cloneString(cfgOption(CFG_SUGGEST_MAILTOADDR)); } char *mailFromAddr() /* Return the bogus sender address to help filter out spam */ { return cloneString(cfgOption(CFG_SUGGEST_MAILFROMADDR)); } char *filterKeyword() /* Return the keyword used to filter out spam */ { return cloneString(cfgOption(CFG_FILTERKEYWORD)); } char *mailSignature() /* Return the signature to be used by outbound mail. */ { return cloneString(cfgOption(CFG_SUGGEST_MAIL_SIGNATURE)); } char *mailReturnAddr() /* Return the return addr. to be used by outbound mail. */ { return cloneString(cfgOption(CFG_SUGGEST_MAIL_RETURN_ADDR)); } char *browserName() /* Return the browser name like 'UCSC Genome Browser' */ { return cloneString(cfgOption(CFG_SUGGEST_BROWSER_NAME)); } static char *now() /* Return a mysql-formatted time like "2008-05-19 15:33:34". */ { char nowBuf[512]; time_t curtime; curtime = time (NULL); struct tm *theTime = localtime(&curtime); strftime(nowBuf, sizeof nowBuf, "%Y-%m-%d %H:%M:%S", theTime); return cloneString(nowBuf); } int spc_email_isvalid(const char *address) { /* Check the format of an email address syntactically. Return 1 if * valid, else 0 */ /* Code copied from the book: "Secure Programming Cookbook for C and C++" By: John Viega; Matt Messier Publisher: O'Reilly Media, Inc. Pub. Date: July 14, 2003 Print ISBN-13: 978-0-596-00394-4 */ int count = 0; const char *c, *domain; static char *rfc822_specials = "()<>@,;:\\\"[]"; /* first we validate the name portion (name@domain) */ for (c = address; *c; c++) { if (*c == '\"' && (c == address || *(c - 1) == '.' || *(c - 1) == '\"')) { while (*++c) { if (*c == '\"') break; if (*c == '\\' && (*++c == ' ')) continue; if (*c <= ' ' || *c >= 127) return 0; } if (!*c++) return 0; if (*c == '@') break; if (*c != '.') return 0; continue; } if (*c == '@') break; if (*c <= ' ' || *c >= 127) return 0; if (strchr(rfc822_specials, *c)) return 0; } if (c == address || *(c - 1) == '.') return 0; /* next we validate the domain portion (name@domain) */ if (!*(domain = ++c)) return 0; do { if (*c == '.') { if (c == domain || *(c - 1) == '.') return 0; count++; } if (*c <= ' ' || *c >= 127) return 0; if (strchr(rfc822_specials, *c)) return 0; } while (*++c); return (count >= 1); } boolean validateCategory(char *category) /* Validate the Category from the request */ { const char *cat[5] = {"Tracks", "Genome Assemblies", "Browser Tools", "Command-line Utilities", "Others"}; int i; for(i=0;i<5;i++) { if (strcmp(cat[i], category)==0) return TRUE; } return FALSE; } /* javascript functions */ void printMainForm() /* Create the main suggestion form */ { hPrintf( "
\n\n"); jsOnEventById("click","sendButton","submitform();"); } void printValidateScript() /* javascript to validate form inputs */ { jsInline( " function validateMainForm(theform)\n" " {\n" " var x=theform.suggestName.value;\n" " if (x==null || x==\"\")\n" " {\n" " alert(\"Name field must be filled out\");\n" " theform.suggestName.focus() ;\n" " return false;\n" " }\n" " var y=theform.suggestEmail.value;\n" " if (y==null || y==\"\")\n" " {\n" " alert(\"Email field must be filled out\");\n" " theform.suggestEmail.focus() ;\n" " return false;\n" " }\n" " if (!validateMailAddr(theform.suggestEmail.value))\n" " {\n" " alert(\"Not a valid e-mail address\");\n" " theform.suggestEmail.focus() ;\n" " return false;\n" " }\n" " var str1 = theform.suggestEmail.value;\n" " var str2 = theform.suggestCfmEmail.value;\n" " if (str2==null || str2==\"\")\n" " {\n" " alert(\"Please re-enter your email address.\");\n" " theform.suggestCfmEmail.focus();\n" " return false;\n" " }\n" " if (str1 != str2)\n" " {\n" " alert(\"Email addresses do not match, please re-enter.\");\n" " theform.suggestCfmEmail.focus();\n" " return false;\n" " }\n" " var y=theform.suggestSummary.value;\n" " if (y==null || y==\"\")\n" " {\n" " alert(\"Summary field must be filled out\");\n" " theform.suggestSummary.focus() ;\n" " return false;\n" " } \n" " return true; \n" " }" " function validateMailAddr(x)\n" " {\n" " var atpos=x.indexOf(\"@\");\n" " var dotpos=x.lastIndexOf(\".\");\n" " if (atpos<1 || dotpos"
"You may follow up on the status of your request at any time by "
"contacting us and quoting your reference number:
%s
"
"A copy of this information has also been sent to you at %s.
Click here if you wish to make additional suggestions.
"); hPrintf( ""
"Your suggestion summary:
"
"%s
"
"Your suggestion details:
"
"
%s" "", summary, details); if (captchaScore > -1.0) hPrintf("
(google captcha score: %g)
\n", captchaScore); } void printInvalidForm(double captchaScore, boolean robot) /* display invalid form page */ { if (captchaScore > -1.0) { if (robot) { char *sName=cartUsualString(cart,"suggestName","no name entered"); char *sEmail=cartUsualString(cart,"suggestEmail","no email entered"); char *sCategory=cartUsualString(cart,"suggestCategory","no category entered"); char *sSummary=cartUsualString(cart,"suggestSummary","no summary entered"); char *sDetails=cartUsualString(cart,"suggestDetails","no details entered"); hPrintf( "" "Congratulations, your google captcha score (%g) appears to qualify " "you as a robot. If this is in error, please email our support email:" " I am *not* a ROBOT !" "
", captchaScore, mailToAddr(), captchaScore, sName, sEmail, sCategory, sSummary, sDetails ); } else { hPrintf( "" "The form is invalid. Please correct it and " "submit again. (score: %g)
", captchaScore ); } } else hPrintf( "" "The form is invalid. Please correct it and " "submit again.
" ); jsOnEventById("click", "goBack", "history.go(-1)"); } void printInvalidCategory(char *invalidCategory) /* display invalid category page */ { hPrintf( "" "The category \"%s\" is invalid. Please correct it and " "submit again.
", invalidCategory); jsOnEventById("click", "goBack", "history.go(-1)"); } void printInvalidEmailAddr(char *invalidEmailAddr) /* display suggestion confirm page */ { hPrintf( "" "The email address \"%s\" is invalid. Please correct it and " "submit again.
", invalidEmailAddr); jsOnEventById("click", "goBack", "history.go(-1)"); } void sendSuggestionBack(char *sName, char *sEmail, char *sCategory, char *sSummary, char *sDetails, char *suggestID) /* send back the suggestion */ { /* parameters from hg.conf */ char *mailTo = mailToAddr(); char *mailFrom=mailFromAddr(); char *filter=filterKeyword(); char subject[512]; char msg[4608]; /* need to make larger */ safef(msg, sizeof(msg), "SuggestionID:: %s\nUserName:: %s\nUserEmail:: %s\nCategory:: %s\nSummary:: %s\n\n\nDetails::\n%s", suggestID, sName, sEmail, sCategory, sSummary, sDetails); safef(subject, sizeof(subject),"%s %s", filter, suggestID); // ignore returned result mailViaPipe(mailTo, subject, msg, mailFrom); } void sendConfirmMail(char *emailAddr, char *suggestID, char *summary, char *details) /* send user suggestion confirm mail */ { char subject[512]; char msg[4608]; char *remoteAddr=getenv("REMOTE_ADDR"); char brwName[512]; char returnAddr[512]; char signature[512]; char userEmailAddr[512]; safecpy(brwName,sizeof(brwName), browserName()); safecpy(returnAddr,sizeof(returnAddr), mailReturnAddr()); safecpy(signature,sizeof(signature), mailSignature()); safecpy(userEmailAddr, sizeof(userEmailAddr),emailAddr); safef(subject, sizeof(subject),"Thank you for your suggestion to the %s", brwName); safef(msg, sizeof(msg), " Someone (probably you, from IP address %s) submitted a suggestion to the %s regarding \"%s\".\n\n The suggestion has been assigned a reference number of \"%s\". If you wish to follow up on the progress of this suggestion with browser staff, you may contact us at %s. Please include the reference number of your suggestion in the email.\n\nThank you for your input,\n%s\n\nYour suggestion summary:\n%s\n\nYour suggestion details:\n%s", remoteAddr, brwName, summary, suggestID, returnAddr, signature, summary, details); // ignore returned result mailViaPipe(userEmailAddr, subject, msg, returnAddr); } void askForSuggest(char *organism, char *db) /* Put up the suggestion form. */ { printMainForm(); printValidateScript(); if (isNotEmpty(cfgOption(CFG_SUGGEST_SITE_KEY))) { printSubmitFormScript(); } else { printCheckCaptchaScript(); printSubmitFormScript(); } //cartSaveSession(cart); } static void recordError(double score, char *msg, char *urlResult) /* record captcha errors in apache error_log */ { if (urlResult) { stripChar(urlResult, '\n'); stripChar(urlResult, ' '); fprintf(stderr, "reCAPTCHA score: %g, '%s' '%s'\n", score, msg, urlResult); } else fprintf(stderr, "reCAPTCHA score: %g, '%s'\n", score, msg); } void submitSuggestion() /* send the suggestion to ,.. */ { /* parameters from hg.conf */ /* values from cart */ char *sName=cartUsualString(cart,"suggestName",""); boolean captchaRobot = FALSE; // OK when not configured double captchaScore = -1.0; if (isNotEmpty(cfgOption(CFG_SUGGEST_SECRET_KEY))) { captchaRobot = TRUE; // assume robot until proven human captchaScore = -0.9; // and allow score to show up in printout char *threshHoldString = cfgOptionDefault(CFG_SUGGEST_HUMAN_THRESHOLD, "-0.1"); double threshHoldScore = sqlDouble(threshHoldString); char *reCaptcha = cartUsualString(cart,"reCaptchaToken", NULL); if (reCaptcha) { char siteverify[4096]; safef(siteverify, sizeof(siteverify), "https://www.google.com/recaptcha/api/siteverify?secret=%s&response=%s", cfgOption(CFG_SUGGEST_SECRET_KEY), reCaptcha); struct htmlPage *verify = htmlPageGet(siteverify); /* successful return: { "success": true, "challenge_ts": "2023-06-09T23:47:35Z", "hostname": "genome-test.gi.ucsc.edu", "score": 0.9, "action": "userSuggest"} error return: { "success": false, "error-codes": [ "timeout-or-duplicate" ]}' */ if (verify) { struct lm *lm = lmInit(1<<16); struct jsonElement *jsonObj = jsonParseLm(verify->htmlText, lm); if (jsonObj) { struct jsonElement *score = jsonFindNamedField(jsonObj, NULL, "score"); struct jsonElement *success = jsonFindNamedField(jsonObj, NULL, "success"); if (success) { if (success->val.jeBoolean) { if (score) { captchaScore = score->val.jeDouble; if (score->val.jeDouble > threshHoldScore) { captchaRobot = FALSE; recordError(captchaScore, "captcha approved", verify->htmlText); } else recordError(captchaScore, "score < threshold", verify->htmlText); } else recordError(captchaScore, "score not found in JSON", verify->htmlText); } // if (success->val.jeBoolean) else recordError(captchaScore, "success FALSE", verify->htmlText); } // if (success) else recordError(captchaScore, "success status not found in JSON", verify->htmlText); } // if (jsonObj) else recordError(captchaScore, "JSON object not found in siteverify return", verify->htmlText); } // if (verify) else recordError(captchaScore, "siteverify URL access failed", NULL); } // if (reCaptcha) else recordError(captchaScore, "reCaptchaToken not found in form", NULL); } // if (isNotEmpty(cfgOption(CFG_SUGGEST_SECRET_KEY))) char *sEmail=cartUsualString(cart,"suggestEmail",""); char *sCategory=cartUsualString(cart,"suggestCategory",""); char *sSummary=cartUsualString(cart,"suggestSummary",""); char *sDetails=cartUsualString(cart,"suggestDetails",""); char *sWebsite=cartUsualString(cart,"suggestWebsite",""); char suggestID[512]; safef(suggestID, sizeof(suggestID),"%s %s", sEmail, now()); /* reject if the hidden field is not blank */ if (isNotEmpty(sWebsite) || captchaRobot) { printInvalidForm(captchaScore, captchaRobot); cartSetString(cart, "suggestWebsite", ""); return; } /* reject suggestion if category is invalid */ if (!validateCategory(sCategory)) { printInvalidCategory(sCategory); return; } /* Send back suggestion only with valid user email address */ if (spc_email_isvalid(sEmail) != 0) { /* send back the suggestion */ sendSuggestionBack(sName, sEmail, sCategory, sSummary, sDetails, suggestID); /* send confirmation mail to user */ sendConfirmMail(sEmail,suggestID, sSummary, sDetails); /* display confirmation page */ printSuggestionConfirmed(sSummary, suggestID, sEmail, mailReturnAddr(), sDetails, captchaScore); } else { /* save all field value in cart */ printInvalidEmailAddr(sEmail); } cartRemove(cart, "do.suggestSendMail"); } void doMiddle(struct cart *theCart) /* Write header and body of html page. */ { char *db, *organism; cart = theCart; getDbAndGenome(cart, &db, &organism, oldVars); cartWebStart(theCart, db, "UCSC Genome Browser: Suggestion Box"); checkHgConfForSuggestion(); if (cartVarExists(cart, "do.suggestSendMail")) { submitSuggestion(); cartRemove(cart, "do.suggestSendMail"); return; } askForSuggest(organism,db); if (isNotEmpty(cfgOption(CFG_SUGGEST_SITE_KEY))) { printReCaptchaV3(); - hPrintf("this site protected by reCAPTCHA and the Google privacy policy and terms of service apply
This site is protected by reCAPTCHA and the Google privacy policy and terms of service apply