/* start a document.write */ void dwStart(void) { if (cw->dw) return; cw->dw = initString(&cw->dw_l); stringAndString(&cw->dw, &cw->dw_l, "<!DOCTYPE public><body>"); } /* dwStart */
char *tidyPreprocess(const char *h) { char *ns; /* the new string */ int l; char *inside, *expanded; const char *lg, *s = strstrCI(h, "<textarea"); /* most web pages don't have textareas */ if (!s) return NULL; ns = initString(&l); stringAndBytes(&ns, &l, h, s - h); h = s; while (true) { /* next textarea */ s = strstrCI(h, "<textarea"); if (!s) break; s = strchr(s, '>'); if (!s) break; ++s; stringAndBytes(&ns, &l, h, s - h); h = s; s = strstrCI(h, "</textarea"); if (!s) break; lg = strpbrk(h, "<>"); /* lg is at most s */ if (lg == s) continue; inside = pullString1(h, s); expanded = htmlEscapeTextarea(inside); stringAndString(&ns, &l, expanded); nzFree(inside); nzFree(expanded); h = s; } stringAndString(&ns, &l, h); return ns; } /* tidyPreprocess */
/* If debug is at least 5, show a simple acknowledgement or error * from the js process. */ static void ack5(void) { char *a; int a_l; char buf[32]; if (debugLevel < 5) return; a = initString(&a_l); stringAndChar(&a, &a_l, '<'); if (head.highstat) { sprintf(buf, " error %d|%d", head.highstat, head.lowstat); stringAndString(&a, &a_l, buf); } stringAndChar(&a, &a_l, ' '); if (propval) stringAndString(&a, &a_l, debugString(propval)); else if (head.cmd == EJ_CMD_HASPROP) stringAndNum(&a, &a_l, head.proptype); else stringAndString(&a, &a_l, "ok"); debugPrint(5, "%s", a); nzFree(a); } /* ack5 */
bool showTables(void) { char tabname[40]; char tabtype[40]; char tabowner[40]; SQLLEN tabnameOut, tabtypeOut, tabownerOut; char *buf; int buflen, cx; int truevalue = SQL_TRUE; /* SQLSetConnectAttr(hdbc, SQL_ATTR_METADATA_ID, &truevalue, SQL_IS_INTEGER); */ newStatement(); stmt_text = "get tables"; debugStatement(); rc = SQLTables(hstmt, NULL, SQL_NTS, NULL, SQL_NTS, NULL, SQL_NTS, NULL, SQL_NTS); if(rc) goto abort; SQLBindCol(hstmt, 2, SQL_CHAR, (SQLPOINTER) tabowner, sizeof (tabowner), &tabownerOut); SQLBindCol(hstmt, 3, SQL_CHAR, (SQLPOINTER) tabname, sizeof (tabname), &tabnameOut); SQLBindCol(hstmt, 4, SQL_CHAR, (SQLPOINTER) tabtype, sizeof (tabtype), &tabtypeOut); buf = initString(&buflen); while(SQLFetch(hstmt) == SQL_SUCCESS) { char tabline[140]; sprintf(tabline, "%s.%s|%s\n", tabowner, tabname, tabtype); stringAndString(&buf, &buflen, tabline); } cx = sideBuffer(0, buf, buflen, 0, false); nzFree(buf); i_printf(MSG_ShowTables, cx); SQLFreeHandle(SQL_HANDLE_STMT, hstmt); return true; abort: SQLFreeHandle(SQL_HANDLE_STMT, hstmt); return false; } /* showTables */
/* call javascript function with arguments, but all args must be objects */ static int run_function(jsobjtype obj, const char *name, int argc, const jsobjtype * argv) { int rc; propval = 0; /* should already be 0 */ if (!allowJS || !cw->winobj || !obj) return -1; debugPrint(5, "> call %s(%d)", name, argc); if (argc) { int i, l; char oval[20]; propval = initString(&l); for (i = 0; i < argc; ++i) { sprintf(oval, "%p|", argv[i]); stringAndString(&propval, &l, oval); } } head.cmd = EJ_CMD_CALL; head.n = strlen(name); head.obj = obj; head.proplength = 0; if (propval) head.proplength = strlen(propval); if (writeHeader()) return -1; if (writeToJS(name, head.n)) return -1; if (propval) { rc = writeToJS(propval, head.proplength); nzFree(propval); propval = 0; if (rc) return -1; } if (readMessage()) return -1; ack5(); return 0; } /* run_function */
static char *qpEncode(const char *line) { char *newbuf; int l; const char *s; char c; newbuf = initString(&l); for (s = line; (c = *s); ++s) { if (c < '\n' && c != '\t' || c == '=') { char expand[4]; sprintf(expand, "=%02X", (uchar) c); stringAndString(&newbuf, &l, expand); } else { stringAndChar(&newbuf, &l, c); } } return newbuf; } /* qpEncode */
static void appendAttachment(const char *s, char **out, int *l) { const char *t; int n; while (*s) { /* another line */ t = strchr(s, '\n'); if (!t) t = s + strlen(s); n = t - s; if (t[-1] == '\r') --n; if (n) memcpy(serverLine, s, n); serverLine[n] = 0; strcat(serverLine, eol); stringAndString(out, l, serverLine); if (*t) ++t; s = t; } /* Small bug here - an attachment that is not base64 encoded, * and had no newline at the end, now has one. */ } /* appendAttachment */
static bool sendMailSMTP(const struct MACCOUNT *account, const char *reply, const char **recipients, const char *message) { CURLcode res = CURLE_OK; bool smtp_success = false; char *smtp_url = buildSMTPURL(account); struct curl_slist *recipient_slist = buildRecipientSList(recipients); struct smtp_upload upload = { .data = message,.length = strlen(message),.pos = 0 }; CURL *handle = newSendmailHandle(account, smtp_url, reply, recipient_slist); if (!handle) goto smtp_cleanup; curl_easy_setopt(handle, CURLOPT_READFUNCTION, smtp_upload_callback); curl_easy_setopt(handle, CURLOPT_READDATA, &upload); curl_easy_setopt(handle, CURLOPT_UPLOAD, 1L); res = curl_easy_perform(handle); if (res == CURLE_OK) smtp_success = true; smtp_cleanup: if (res != CURLE_OK) ebcurl_setError(res, smtp_url); if (handle) curl_easy_cleanup(handle); curl_slist_free_all(recipient_slist); nzFree(smtp_url); return smtp_success; } /* sendMailSMTP */ /* Send mail to the smtp server. */ bool sendMail(int account, const char **recipients, const char *body, int subjat, const char **attachments, const char *refline, int nalt, bool dosig) { char *from, *fromiso, *reply, *login, *smlogin, *pass; const struct MACCOUNT *a, *ao, *localMail; const char *s, *boundary; char reccc[MAXRECAT]; char *t; int nat, cx, i, j; char *out = 0; bool sendmail_success = false; bool mustmime = false; bool firstgreet = true; bool firstrec; const char *ct, *ce; char *encoded = 0; if (!validAccount(account)) return false; mailAccount = account; localMail = accounts + localAccount - 1; a = accounts + account - 1; from = a->from; reply = a->reply; ao = a->outssl ? a : localMail; doSignature = dosig; nat = 0; /* number of attachments */ if (attachments) { while (attachments[nat]) ++nat; } if (nat) mustmime = true; if (nalt && nalt < nat) { setError(MSG_AttAlternate); return false; } if (!loadAddressBook()) return false; /* set copy flags */ for (j = 0; s = recipients[j]; ++j) { char cc = 0; if (*s == '^' || *s == '?') cc = *s++; if (j == MAXRECAT) { setError(MSG_RecipMany, MAXRECAT); return false; } recipients[j] = s; reccc[j] = cc; } /* Look up aliases in the address book */ for (j = 0; s = recipients[j]; ++j) { if (strchr(s, '@')) continue; t = 0; for (i = 0; i < nads; ++i) { const char *a = addressList[i].name; if (*a == '-' || *a == '!') ++a; if (!stringEqual(s, a)) continue; t = addressList[i].email; debugPrint(3, " %s becomes %s", s, t); break; } if (t) { recipients[j] = t; continue; } if (!addressFile) { setError(MSG_ABMissing); return false; } setError(MSG_ABNoAlias2, s); return false; } /* recipients */ if (!j) { setError(MSG_RecipNone); return false; } /* verify attachments are readable */ for (j = 0; s = attachments[j]; ++j) { if (!ismc && (cx = stringIsNum(s)) >= 0) { if (!cxCompare(cx) || !cxActive(cx)) return false; if (!sessionList[cx].lw->dol) { setError(MSG_AttSessionEmpty, cx); return false; } } else { char ftype = fileTypeByName(s, false); if (!ftype) { setError(MSG_AttAccess, s); return false; } if (ftype != 'f') { setError(MSG_AttRegular, s); return false; } if (!fileSizeByName(s)) { setError(MSG_AttEmpty2, s); return false; } } } /* loop over attachments */ if (!encodeAttachment(body, subjat, false, &ct, &ce, &encoded)) return false; if (ce[0] == 'q') mustmime = true; boundary = makeBoundary(); /* Build the outgoing mail, as one string. */ out = initString(&j); firstrec = true; for (i = 0; s = recipients[i]; ++i) { if (reccc[i]) continue; stringAndString(&out, &j, firstrec ? "To:" : ",\r\n "); stringAndString(&out, &j, s); firstrec = false; } if (!firstrec) stringAndString(&out, &j, eol); firstrec = true; for (i = 0; s = recipients[i]; ++i) { if (reccc[i] != '^') continue; stringAndString(&out, &j, firstrec ? "CC:" : ",\r\n "); stringAndString(&out, &j, s); firstrec = false; } if (!firstrec) stringAndString(&out, &j, eol); firstrec = true; for (i = 0; s = recipients[i]; ++i) { if (reccc[i] != '?') continue; stringAndString(&out, &j, firstrec ? "BCC:" : ",\r\n "); stringAndString(&out, &j, s); firstrec = false; } if (!firstrec) stringAndString(&out, &j, eol); fromiso = isoEncode(from, from + strlen(from)); if (!fromiso) fromiso = from; sprintf(serverLine, "From: %s <%s>%s", fromiso, reply, eol); stringAndString(&out, &j, serverLine); sprintf(serverLine, "Reply-to: %s <%s>%s", fromiso, reply, eol); stringAndString(&out, &j, serverLine); if (fromiso != from) nzFree(fromiso); if (refline) { s = strchr(refline, '\n'); if (!s) /* should never happen */ s = refline + strlen(refline); stringAndBytes(&out, &j, refline, s - refline); stringAndString(&out, &j, eol); } sprintf(serverLine, "User-Agent: %s%s", currentAgent, eol); stringAndString(&out, &j, serverLine); if (subjectLine[0]) { sprintf(serverLine, "Subject: %s%s", subjectLine, eol); stringAndString(&out, &j, serverLine); } sprintf(serverLine, "Date: %s%sMessage-ID: <%s.%s>%sMime-Version: 1.0%s", mailTimeString(), eol, messageTimeID(), reply, eol, eol); stringAndString(&out, &j, serverLine); if (!mustmime) { /* no mime components required, we can just send the mail. */ sprintf(serverLine, "Content-Type: %s%s%sContent-Transfer-Encoding: %s%s%s", ct, charsetString(ct, ce), eol, ce, eol, eol); stringAndString(&out, &j, serverLine); } else { sprintf(serverLine, "Content-Type: multipart/%s; boundary=%s%sContent-Transfer-Encoding: 7bit%s%s", nalt ? "alternative" : "mixed", boundary, eol, eol, eol); stringAndString(&out, &j, serverLine); stringAndString(&out, &j, "This message is in MIME format. Since your mail reader does not understand\r\n\ this format, some or all of this message may not be legible.\r\n\r\n--"); stringAndString(&out, &j, boundary); sprintf(serverLine, "%sContent-Type: %s%s%sContent-Transfer-Encoding: %s%s%s", eol, ct, charsetString(ct, ce), eol, ce, eol, eol); stringAndString(&out, &j, serverLine); } /* Now send the body, line by line. */ appendAttachment(encoded, &out, &j); nzFree(encoded); encoded = 0; if (mustmime) { for (i = 0; s = attachments[i]; ++i) { if (!encodeAttachment (s, 0, false, &ct, &ce, &encoded)) return false; sprintf(serverLine, "%s--%s%sContent-Type: %s%s", eol, boundary, eol, ct, charsetString(ct, ce)); stringAndString(&out, &j, serverLine); /* If the filename has a quote in it, forget it. */ /* Also, suppress filename if this is an alternate presentation. */ if (!nalt && !strchr(s, '"') && (ismc || stringIsNum(s) < 0)) { sprintf(serverLine, "; name=\"%s\"", s); stringAndString(&out, &j, serverLine); } sprintf(serverLine, "%sContent-Transfer-Encoding: %s%s%s", eol, ce, eol, eol); stringAndString(&out, &j, serverLine); appendAttachment(encoded, &out, &j); nzFree(encoded); encoded = 0; } /* loop over attachments */ /* The last boundary */ sprintf(serverLine, "%s--%s--%s", eol, boundary, eol); stringAndString(&out, &j, serverLine); } /* mime format */ sendmail_success = sendMailSMTP(ao, reply, recipients, out); nzFree(out); return sendmail_success; } /* sendMail */
/* Read a file into memory, mime encode it, * and return the type of encoding and the encoded data. * Last three parameters are result parameters. * If ismail is nonzero, the file is the mail, not an attachment. * In fact ismail indicates the line that holds the subject. * If ismail is negative, then -ismail indicates the subject line, * and the string file is not the filename, but rather, the mail to send. */ bool encodeAttachment(const char *file, int ismail, bool webform, const char **type_p, const char **enc_p, char **data_p) { char *buf; char c; bool longline; char *s, *t, *v; char *ct, *ce; /* content type, content encoding */ int buflen, i, cx; int nacount, nullcount, nlcount; if (ismail < 0) { buf = cloneString(file); buflen = strlen(buf); ismail = -ismail; file = EMPTYSTRING; } else { if (!ismc && (cx = stringIsNum(file)) >= 0) { static char newfilename[16]; if (!unfoldBuffer(cx, false, &buf, &buflen)) return false; if (!buflen) { if (webform) { empty: buf = EMPTYSTRING; ct = "text/plain"; ce = "7bit"; goto success; } setError(MSG_BufferXEmpty, cx); goto freefail; } sprintf(newfilename, "<buffer %d>", cx); file = newfilename; if (sessionList[cx].lw->fileName) file = sessionList[cx].lw->fileName; } else { if (!fileIntoMemory(file, &buf, &buflen)) return false; if (!buflen) { if (webform) goto empty; setError(MSG_FileXEmpty, file); goto freefail; } } } /* ismail negative or normal */ if (ismail) { /* Put newline at the end. Yes, the buffer is allocated * with space for newline and null. */ if (buf[buflen - 1] != '\n') buf[buflen++] = '\n'; /* check for subject: line */ s = buf; i = ismail; while (--i) { while (*s != '\n') ++s; ++s; } while (*s == ' ' || *s == '\t') ++s; if (!memEqualCI(s, "subject:", 8)) { setError(MSG_SubjectStart); goto freefail; } s += 8; while (*s == ' ' || *s == '\t') ++s; t = s; while (*s != '\n') ++s; v = s; while (s > t && isspaceByte(s[-1])) --s; if (s - t >= sizeof(subjectLine)) { setError(MSG_SubjectLong, sizeof(subjectLine) - 1); goto freefail; } if (s > t) memcpy(subjectLine, t, s - t); subjectLine[s - t] = 0; if (subjectLine[0]) { char *subjiso = isoEncode(subjectLine, subjectLine + strlen(subjectLine)); if (subjiso) { if (strlen(subjiso) >= sizeof(subjectLine)) { nzFree(subjiso); setError(MSG_SubjectLong, sizeof(subjectLine) - 1); goto freefail; } strcpy(subjectLine, subjiso); nzFree(subjiso); } } debugPrint(6, "subject = %s", subjectLine); /* Blank lines after subject are optional, and ignored. */ for (t = buf + buflen; v < t; ++v) if (*v != '\r' && *v != '\n') break; buflen -= (v - buf); if (buflen) memmove(buf, v, buflen); buf[buflen] = 0; if (doSignature) { /* Append .signature file. */ /* Try account specific .signature file, then fall back to .signature */ sprintf(sigFileEnd, "%d", mailAccount); c = fileTypeByName(sigFile, false); if (!c) { *sigFileEnd = 0; c = fileTypeByName(sigFile, false); } if (c != 0) { int fd, n; if (c != 'f') { setError(MSG_SigRegular); goto freefail; } n = fileSizeByName(sigFile); if (n > 0) { buf = reallocMem(buf, buflen + n + 1); fd = open(sigFile, O_RDONLY); if (fd < 0) { setError(MSG_SigAccess); goto freefail; } read(fd, buf + buflen, n); close(fd); buflen += n; buf[buflen] = 0; } } } /* .signature */ } /* Infer content type from the filename */ ct = 0; s = strrchr(file, '.'); if (s && s[1]) { ++s; if (stringEqualCI(s, "ps")) ct = "application/PostScript"; if (stringEqualCI(s, "jpeg")) ct = "image/jpeg"; if (stringEqualCI(s, "gif")) ct = "image/gif"; if (stringEqualCI(s, "wav")) ct = "audio/basic"; if (stringEqualCI(s, "mpeg")) ct = "video/mpeg"; if (stringEqualCI(s, "rtf")) ct = "text/richtext"; if (stringEqualCI(s, "htm") || stringEqualCI(s, "html") || stringEqualCI(s, "shtm") || stringEqualCI(s, "shtml") || stringEqualCI(s, "asp")) ct = "text/html"; } /* Count the nonascii characters */ nacount = nullcount = nlcount = 0; longline = false; s = 0; for (i = 0; i < buflen; ++i) { c = buf[i]; if (c == '\0') ++nullcount; if (c < 0) ++nacount; if (c != '\n') continue; ++nlcount; t = buf + i; if (s && t - s > 120) longline = true; if (!s && i > 120) longline = true; s = t; } t = buf + i; if (s && t - s > 120) longline = true; if (!s && i > 120) longline = true; debugPrint(6, "attaching %s length %d nonascii %d nulls %d longline %d", file, buflen, nacount, nullcount, longline); nacount += nullcount; /* Set the type of attachment */ if (buflen > 20 && nacount * 5 > buflen) { if (!ct) ct = "application/octet-stream"; /* default type for binary */ } if (!ct) ct = "text/plain"; /* Criteria for base64 encode. * files uploaded from a web form need not be encoded, unless they contain * nulls, which is a quirk of my slapped together software. */ if (!webform && (buflen > 20 && nacount * 5 > buflen) || webform && nullcount) { if (ismail) { setError(MSG_MailBinary, file); goto freefail; } s = base64Encode(buf, buflen, true); nzFree(buf); buf = s; ce = "base64"; goto success; } if (!webform) { /* Switch to unix newlines - we'll switch back to dos later. */ v = buf + buflen; for (s = t = buf; s < v; ++s) { c = *s; if (c == '\r' && s < v - 1 && s[1] == '\n') continue; *t++ = c; } buflen = t - buf; /* Do we need to use quoted-printable? */ /* Perhaps this hshould read (nacount > 0) */ if (nacount * 20 > buflen || nullcount || longline) { char *newbuf; int l, colno = 0, space = 0; newbuf = initString(&l); v = buf + buflen; for (s = buf; s < v; ++s) { c = *s; /* do we have to =expand this character? */ if (c < '\n' && c != '\t' || c == '=' || c == '\xff' || (c == ' ' || c == '\t') && s < v - 1 && s[1] == '\n') { char expand[4]; sprintf(expand, "=%02X", (uchar) c); stringAndString(&newbuf, &l, expand); colno += 3; } else { stringAndChar(&newbuf, &l, c); ++colno; } if (c == '\n') { colno = space = 0; continue; } if (c == ' ' || c == '\t') space = l; if (colno < 72) continue; if (s == v - 1) continue; /* If newline's coming up anyways, don't force another one. */ if (s[1] == '\n') continue; i = l; if (!space || space == i) { stringAndString(&newbuf, &l, "=\n"); colno = space = 0; continue; } colno = i - space; stringAndString(&newbuf, &l, "**"); /* make room */ while (i > space) { newbuf[i + 1] = newbuf[i - 1]; --i; } newbuf[space] = '='; newbuf[space + 1] = '\n'; space = 0; } /* loop over characters */ nzFree(buf); buf = newbuf; ce = "quoted-printable"; goto success; } } buf[buflen] = 0; ce = (nacount ? "8bit" : "7bit"); success: debugPrint(6, "encoded %s %s length %d", ct, ce, strlen(buf)); *enc_p = ce; *type_p = ct; *data_p = buf; return true; freefail: nzFree(buf); return false; } /* encodeAttachment */
static void processEffects(void) { char *s, *t, *v; char c; jsobjtype p; int n; struct inputChange *ic; if (!effects) return; s = effects; while (c = *s) { /* another effect */ s += 2; v = strstr(s, "`~@}"); /* end marker */ /* There should always be an end marker - * unless there is a spurious null in the string. */ if (!v) break; *v = 0; switch (c) { case 'w': /* document.write */ dwStart(); stringAndString(&cw->dw, &cw->dw_l, s); break; case 'n': /* new window */ /* url on one line, name of window on next line */ t = strchr(s, '\n'); *t = 0; javaOpensWindow(s, t + 1); break; case 'v': /* value = "foo" */ t = strchr(s, '='); *t++ = 0; sscanf(s, "%p", &p); prepareForField(t); javaSetsTagVar(p, t); break; case 't': /* js timer */ n = strtol(s, &t, 10); s = t + 1; t = strchr(s, '|'); *t++ = 0; v[-2] = 0; sscanf(t, "%p", &p); ic = allocMem(sizeof(struct inputChange) + strlen(s)); // Yeah I know, this isn't a pointer to htmlTag. ic->t = p; ic->tagno = n; ic->major = 't'; ic->minor = v[-1]; strcpy(ic->value, s); addToListBack(&inputChangesPending, ic); break; case 'c': /* cookie */ /* Javascript does some modest syntax checking on the cookie before * passing it back to us, so I'm just going to assume it works. */ receiveCookie(cw->fileName, s); break; case 'f': c = *s++; sscanf(s, "%p", &p); javaSubmitsForm(p, (c == 'r')); break; case 'i': c = *s++; /* h = inner html, t = inner text */ t = strchr(s, '|'); *t++ = 0; sscanf(s, "%p", &p); javaSetsInner(p, t, c); break; case 'l': c = *s; s += 2; sscanf(s, "%p", &p); s = strchr(s, ',') + 1; javaSetsLinkage(false, c, p, s); break; } /* switch */ /* skip past end marker + newline */ s = v + 5; } /* loop over effects */ free(effects); effects = 0; } /* processEffects */