2
* Send mail using the smtp protocol.
3
* Send the contents of a file, or the current edbrowse buffer.
4
* Copyright (c) Karl Dahlke, 2008
5
* This file is part of the edbrowse project, released under GPL.
12
#define MAXRECAT 100 /* max number of recipients or attachments */
14
char serverLine[MAXTTYLINE];
15
static char spareLine[MAXTTYLINE];
16
int mssock; /* mail server socket */
17
static bool doSignature;
18
static char subjectLine[200];
24
static int nads; /* number of addresses */
25
static time_t adbooktime;
27
/* read and/or refresh the address book */
31
char *buf, *bufend, *v, *last, *s, *t;
34
int j, buflen, ln = 1;
38
(mtime = fileTimeByName(addressFile)) == -1 || mtime <= adbooktime)
41
debugPrint(3, "loading address book");
45
if(!fileIntoMemory(addressFile, &buf, &buflen))
47
bufend = buf + buflen;
49
for(s = t = last = buf; s < bufend; ++s) {
56
if(c == ':') { /* delimiter */
58
setError(MSG_ABNoAlias, ln);
63
while(t[-1] == ' ' || t[-1] == '\t')
70
c = '#'; /* extra fields are ignored */
81
setError(MSG_ABNoColon, ln - 1);
86
while(isspaceByte(t[-1]))
89
v = strchr(last, ':');
91
setError(MSG_ABAliasLong, ln - 1);
96
setError(MSG_ABMailLong, ln - 1);
100
setError(MSG_ABNoAt, ln - 1);
103
if(strpbrk(v, " \t")) {
104
setError(MSG_ABMailSpaces, ln - 1);
109
if(!isprintByte(*last)) {
110
setError(MSG_AbMailUnprintable, ln - 1);
117
t = last; /* back it up */
123
if((c == ' ' || c == '\t') && (state == 0 || state == 2))
134
setError(MSG_ABUnterminated);
139
addressList = allocMem(nads * sizeof (struct ALIAS));
141
for(s = buf; *s; s = t + 1, ++j) {
143
memcpy(addressList[j].name, s, t - s);
144
addressList[j].name[t - s] = 0;
147
memcpy(addressList[j].email, s, t - s);
148
addressList[j].email[t - s] = 0;
151
/* aliases are present */
155
} /* loadAddressBook */
158
reverseAlias(const char *reply)
161
for(i = 0; i < nads; ++i)
162
if(stringEqual(reply, addressList[i].email)) {
163
const char *a = addressList[i].name;
168
return 0; /* not found */
172
/*********************************************************************
173
Put and get lines from the mail server.
174
Print the lines if the debug level calls for it.
175
*********************************************************************/
178
serverPutLine(const char *buf, bool secure)
180
int n, len = strlen(buf);
182
if(debugLevel >= 4) {
184
for(n = 0; n < len; ++n) {
191
n = ssl_write(buf, len);
193
n = tcp_write(mssock, buf, len);
195
setError(MSG_MailWrite);
199
} /* serverPutLine */
202
serverGetLine(bool secure)
207
slen = strlen(spareLine);
208
strcpy(serverLine, spareLine);
209
s = strchr(serverLine, '\n');
212
len = ssl_read(serverLine + slen, sizeof (serverLine) - 1 - slen);
215
tcp_read(mssock, serverLine + slen,
216
sizeof (serverLine) - 1 - slen);
218
setError(MSG_MailRead);
222
serverLine[slen] = 0;
224
s = strchr(serverLine, '\n');
226
setError(MSG_MailResponseLong);
229
strcpy(spareLine, s + 1);
231
if(s > serverLine && s[-1] == '\r')
233
debugPrint(4, "< %s", serverLine);
235
} /* serverGetLine */
238
serverPutGet(const char *line, bool secure)
240
if(!serverPutLine(line, secure))
242
if(!serverGetLine(secure))
247
serverClose(bool secure)
249
serverPutLine("quit\r\n", secure);
257
/* Connect to the mail server */
259
mailConnect(const char *host, int port, bool secure)
261
IP32bit ip = tcp_name_ip(host);
263
setError((intFlag ? MSG_Interrupted : MSG_MailLocate), host);
266
debugPrint(4, "%s -> %s", host, tcp_ip_dots(ip));
267
mssock = tcp_connect(ip, port, mailTimeout);
269
setError(intFlag ? MSG_Interrupted : MSG_MailConnect);
272
debugPrint(4, "connected to port %d", port);
275
int n = ssl_newbind(mssock);
278
setError(MSG_NoCertify, host);
280
setError(MSG_WebConnectSecure, host, n);
283
debugPrint(4, "secure connection established");
288
static char base64_chars[] =
289
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
291
base64Encode(const char *inbuf, int inlen, bool lines)
294
uchar *in = (uchar *) inbuf;
296
int outlen = ((inlen / 3) + 1) * 4;
297
++outlen; /* zero on the end */
299
outlen += (inlen / 54) + 1;
300
outstr = out = allocMem(outlen);
303
*out++ = base64_chars[(int)(*in >> 2)];
304
*out++ = base64_chars[(int)((*in << 4 | *(in + 1) >> 4) & 63)];
305
*out++ = base64_chars[(int)((*(in + 1) << 2 | *(in + 2) >> 6) & 63)];
306
*out++ = base64_chars[(int)(*(in + 2) & 63)];
318
*out++ = base64_chars[(int)(*in >> 2)];
319
*out++ = base64_chars[(int)(*in << 4 & 63)];
325
*out++ = base64_chars[(int)(*in >> 2)];
326
*out++ = base64_chars[(int)((*in << 4 | *(in + 1) >> 4) & 63)];
327
*out++ = base64_chars[(int)((*(in + 1) << 2) & 63)];
331
/* finish the last line */
339
qpEncode(const char *line)
346
newbuf = initString(&l);
347
for(s = line; (c = *s); ++s) {
348
if(c < '\n' && c != '\t' || c == '=') {
350
sprintf(expand, "=%02X", (uchar) c);
351
stringAndString(&newbuf, &l, expand);
353
stringAndChar(&newbuf, &l, c);
360
/* Return 0 if there was no need to encode */
362
isoEncode(char *start, char *end)
364
int nacount = 0, count = 0, len;
368
for(s = start; s < end; ++s) {
376
for(s = start; s < end; ++s) {
379
if(!isprintByte(c) && c != ' ')
386
if(nacount * 4 >= count && count > 8) {
388
s = base64Encode(start, end - start, false);
397
t = allocMem(len + 20);
398
sprintf(t, "=?ISO-8859-1?%c?%s?=", code, s);
403
/* Read a file into memory, mime encode it,
404
* and return the type of encoding and the encoded data.
405
* Last three parameters are result parameters.
406
* If ismail is nonzero, the file is the mail, not an attachment.
407
* In fact ismail indicates the line that holds the subject.
408
* If ismail is negative, then -ismail indicates the subject line,
409
* and the string file is not the filename, but rather, the mail to send. */
411
encodeAttachment(const char *file, int ismail, bool webform,
412
const char **type_p, const char **enc_p, char **data_p)
418
char *ct, *ce; /* content type, content encoding */
420
int nacount, nullcount, nlcount;
423
buf = cloneString(file);
424
buflen = strlen(buf);
429
if(!ismc && (cx = stringIsNum(file)) >= 0) {
430
static char newfilename[16];
431
if(!unfoldBuffer(cx, false, &buf, &buflen))
441
setError(MSG_BufferXEmpty, cx);
444
sprintf(newfilename, "<buffer %d>", cx);
446
if(sessionList[cx].lw->fileName)
447
file = sessionList[cx].lw->fileName;
449
if(!fileIntoMemory(file, &buf, &buflen))
454
setError(MSG_FileXEmpty, file);
458
} /* ismail negative or normal */
461
/* Put newline at the end. Yes, the buffer is allocated
462
* with space for newline and null. */
463
if(buf[buflen - 1] != '\n')
464
buf[buflen++] = '\n';
465
/* check for subject: line */
473
while(*s == ' ' || *s == '\t')
475
if(!memEqualCI(s, "subject:", 8)) {
476
setError(MSG_SubjectStart);
480
while(*s == ' ' || *s == '\t')
486
while(s > t && isspaceByte(s[-1]))
489
setError(MSG_SubjectEmpty);
492
if(s - t >= sizeof (subjectLine)) {
493
setError(MSG_SubjectLong, sizeof (subjectLine) - 1);
496
memcpy(subjectLine, t, s - t);
497
subjectLine[s - t] = 0;
498
t = subjectLine + (s - t);
499
s = isoEncode(subjectLine, t);
501
if(strlen(s) >= sizeof (subjectLine)) {
502
setError(MSG_SubjectLong, sizeof (subjectLine) - 1);
505
strcpy(subjectLine, s);
508
debugPrint(6, "subject = %s", subjectLine);
509
/* Blank lines after subject are optional, and ignored. */
510
for(t = buf + buflen; v < t; ++v)
511
if(*v != '\r' && *v != '\n')
515
memcpy(buf, v, buflen);
518
if(doSignature) { /* Append .signature file. */
519
c = fileTypeByName(sigFile, false);
523
setError(MSG_SigRegular);
526
n = fileSizeByName(sigFile);
528
buf = reallocMem(buf, buflen + n + 1);
529
fd = open(sigFile, O_RDONLY);
531
setError(MSG_SigAccess);
534
read(fd, buf + buflen, n);
543
/* primary email message */
544
/* Infer content type from the filename */
546
s = strrchr(file, '.');
549
if(stringEqualCI(s, "ps"))
550
ct = "application/PostScript";
551
if(stringEqualCI(s, "jpeg"))
553
if(stringEqualCI(s, "gif"))
555
if(stringEqualCI(s, "wav"))
557
if(stringEqualCI(s, "mpeg"))
559
if(stringEqualCI(s, "rtf"))
560
ct = "text/richtext";
561
if(stringEqualCI(s, "htm") ||
562
stringEqualCI(s, "html") ||
563
stringEqualCI(s, "shtm") ||
564
stringEqualCI(s, "shtml") || stringEqualCI(s, "asp"))
568
/* Count the nonascii characters */
569
nacount = nullcount = nlcount = 0;
572
for(i = 0; i < buflen; ++i) {
593
debugPrint(6, "attaching %s length %d nonascii %d nulls %d longline %d",
594
file, buflen, nacount, nullcount, longline);
595
nacount += nullcount;
597
/* Criteria for base64 encode.
598
* But, some web servers won't take qp encode, so if this is a web form,
599
* and we would normally qp encode, do base 64. */
601
if(buflen > 20 && nacount * 5 > buflen ||
602
webform && (nacount * 20 > buflen || nullcount || longline)) {
604
setError(MSG_MailBinary, file);
608
s = base64Encode(buf, buflen, true);
612
ct = "application/octet-stream"; /* default type */
620
/* Switch to unix newlines - we'll switch back to dos later. */
622
for(s = t = buf; s < v; ++s) {
624
if(c == '\r' && s < v - 1 && s[1] == '\n')
630
/* Do we need to use quoted-printable? */
631
/* Perhaps this hshould read (nacount > 0) */
632
if(nacount * 20 > buflen || nullcount || longline) {
634
int l, colno = 0, space = 0;
636
newbuf = initString(&l);
638
for(s = buf; s < v; ++s) {
640
/* do we have to =expand this character? */
641
if(c < '\n' && c != '\t' ||
644
(c == ' ' || c == '\t') && s < v - 1 && s[1] == '\n') {
646
sprintf(expand, "=%02X", (uchar) c);
647
stringAndString(&newbuf, &l, expand);
650
stringAndChar(&newbuf, &l, c);
657
if(c == ' ' || c == '\t')
663
/* If newline's coming up anyways, don't force another one. */
667
if(!space || space == i) {
668
stringAndString(&newbuf, &l, "=\n");
673
stringAndString(&newbuf, &l, "**"); /* make room */
675
newbuf[i + 1] = newbuf[i - 1];
679
newbuf[space + 1] = '\n';
681
} /* loop over characters */
685
ce = "quoted-printable";
688
/* quoted printable */
690
ce = (nacount ? "8bit" : "7bit");
693
debugPrint(6, "encoded %s %s length %d", ct, ce, strlen(buf));
702
} /* encodeAttachment */
711
cur_tm = localtime(&now);
712
strftime(buf, sizeof (buf), "%a, %d %b %Y %H:%M:%S %z", cur_tm);
714
} /* mailTimeString */
723
cur_tm = localtime(&now);
724
sprintf(buf, "%04d%02d%02d%02d%02d%02d",
725
cur_tm->tm_year + 1900, cur_tm->tm_mon, cur_tm->tm_mday,
726
cur_tm->tm_hour, cur_tm->tm_min, cur_tm->tm_sec);
728
} /* messageTimeID */
731
appendAttachment(const char *s, char **out, int *l)
735
while(*s) { /* another line */
743
memcpy(serverLine, s, n);
745
if(n == 1 && serverLine[0] == '.') /* can't allow this */
746
strcpy(serverLine, " .");
747
strcat(serverLine, eol);
748
stringAndString(out, l, serverLine);
753
/* Small bug here - an attachment that is not base64 encoded,
754
* and had no newline at the end, now has one. */
755
} /* appendAttachment */
760
static char boundary[60];
761
sprintf(boundary, "nextpart-eb-%06d", rand() % 1000000);
765
/* Send mail to the smtp server. */
767
sendMail(int account, const char **recipients, const char *body,
768
int subjat, const char **attachments, const char *refline,
769
int nalt, bool dosig)
771
char *from, *fromiso, *reply, *login, *smlogin, *pass;
772
const struct MACCOUNT *a, *ao, *localMail;
773
const char *s, *boundary;
774
char reccc[MAXRECAT];
778
bool mustmime = false;
783
if(!validAccount(account))
785
localMail = accounts + localAccount - 1;
787
a = accounts + account - 1;
790
ao = a->outssl ? a : localMail;
792
smlogin = strchr(login, '\\');
800
nat = 0; /* number of attachments */
802
while(attachments[nat])
807
if(nalt && nalt < nat) {
808
setError(MSG_AttAlternate);
812
if(!loadAddressBook())
816
for(j = 0; s = recipients[j]; ++j) {
818
if(*s == '^' || *s == '?')
821
setError(MSG_RecipMany, MAXRECAT);
828
/* Look up aliases in the address book */
829
for(j = 0; s = recipients[j]; ++j) {
833
for(i = 0; i < nads; ++i) {
834
const char *a = addressList[i].name;
835
if(*a == '-' || *a == '!')
837
if(!stringEqual(s, a))
839
t = addressList[i].email;
840
debugPrint(3, " %s becomes %s", s, t);
848
setError(MSG_ABMissing);
851
setError(MSG_ABNoAlias2, s);
856
setError(MSG_RecipNone);
860
/* verify attachments are readable */
861
for(j = 0; s = attachments[j]; ++j) {
862
if(!ismc && (cx = stringIsNum(s)) >= 0) {
863
if(!cxCompare(cx) || !cxActive(cx))
865
if(!sessionList[cx].lw->dol) {
866
setError(MSG_AttSessionEmpty, cx);
870
char ftype = fileTypeByName(s, false);
872
setError(MSG_AttAccess, s);
876
setError(MSG_AttRegular, s);
879
if(!fileSizeByName(s)) {
880
setError(MSG_AttEmpty2, s);
884
} /* loop over attachments */
886
if(!encodeAttachment(body, subjat, false, &ct, &ce, &encoded))
891
boundary = makeBoundary();
893
if(!mailConnect(ao->outurl, ao->outport, ao->outssl)) {
897
if(!serverGetLine(ao->outssl))
899
while(memEqualCI(serverLine, "220-", 4)) {
900
if(!serverGetLine(ao->outssl))
903
if(!memEqualCI(serverLine, "220 ", 4)) {
904
setError(MSG_MailBadPrompt, serverLine);
908
sprintf(serverLine, "%s %s%s", (a->outssl ? "ehlo" : "Helo"), smlogin, eol);
909
if(!serverPutLine(serverLine, ao->outssl))
912
if(!serverGetLine(ao->outssl))
914
if(!memEqualCI(serverLine, "250", 3) ||
915
serverLine[3] != ' ' && serverLine[3] != '-') {
916
setError(MSG_MailWhat, login);
919
if(serverLine[3] == '-')
924
/* login authentication is the only thing I support right now. */
925
if(!serverPutGet("auth login\r\n", true))
927
if(!memEqualCI(serverLine, "334 ", 4)) {
928
setError(MSG_AuthLoginOnly);
931
b = base64Encode(login, strlen(login), false);
932
sprintf(serverLine, "%s%s", b, eol);
934
if(!serverPutGet(serverLine, true))
936
if(!memEqualCI(serverLine, "334 ", 4)) {
937
setError(MSG_AuthLoginOnly);
940
b = base64Encode(pass, strlen(pass), false);
941
sprintf(serverLine, "%s%s", b, eol);
943
if(!serverPutGet(serverLine, true))
945
if(!memEqualCI(serverLine, "235 ", 4)) {
946
setError(MSG_SmtpNotComplete, serverLine);
951
sprintf(serverLine, "mail from: <%s>%s", reply, eol);
952
if(!serverPutGet(serverLine, ao->outssl))
954
if(!memEqualCI(serverLine, "250 ", 4)) {
955
setError(MSG_MailReject, reply);
959
for(j = 0; s = recipients[j]; ++j) {
960
sprintf(serverLine, "rcpt to: <%s>%s", s, eol);
961
if(!serverPutGet(serverLine, ao->outssl))
963
if(!memEqualCI(serverLine, "250 ", 4)) {
964
setError(MSG_MailReject, s);
969
if(!serverPutGet("data\r\n", ao->outssl))
971
if(!memEqualCI(serverLine, "354 ", 4)) {
972
setError(MSG_MailNotReady, serverLine);
976
/* Build the outgoing mail, and send it in one go, as one string. */
977
out = initString(&j);
980
for(i = 0; s = recipients[i]; ++i) {
983
stringAndString(&out, &j, firstrec ? "To:" : ",\r\n ");
984
stringAndString(&out, &j, s);
988
stringAndString(&out, &j, eol);
991
for(i = 0; s = recipients[i]; ++i) {
994
stringAndString(&out, &j, firstrec ? "CC:" : ",\r\n ");
995
stringAndString(&out, &j, s);
999
stringAndString(&out, &j, eol);
1002
for(i = 0; s = recipients[i]; ++i) {
1005
stringAndString(&out, &j, firstrec ? "BCC:" : ",\r\n ");
1006
stringAndString(&out, &j, s);
1010
stringAndString(&out, &j, eol);
1012
fromiso = isoEncode(from, from + strlen(from));
1015
sprintf(serverLine, "From: %s <%s>%s", fromiso, reply, eol);
1016
stringAndString(&out, &j, serverLine);
1017
sprintf(serverLine, "Reply-to: %s <%s>%s", fromiso, reply, eol);
1018
stringAndString(&out, &j, serverLine);
1022
s = refline + strlen(refline);
1023
if(s > refline && s[-1] == '\n')
1025
stringAndBytes(&out, &j, refline, s - refline);
1026
stringAndString(&out, &j, eol);
1028
sprintf(serverLine, "User-Agent: %s%s", currentAgent, eol);
1029
stringAndString(&out, &j, serverLine);
1030
sprintf(serverLine, "Subject: %s%s", subjectLine, eol);
1031
stringAndString(&out, &j, serverLine);
1032
sprintf(serverLine, "Date: %s%sMessage-ID: <%s.%s>%sMime-Version: 1.0%s",
1033
mailTimeString(), eol, messageTimeID(), reply, eol, eol);
1034
stringAndString(&out, &j, serverLine);
1037
/* no mime components required, we can just send the mail. */
1039
"Content-type: %s%sContent-Transfer-Encoding: %s%s%s", ct, eol, ce,
1041
stringAndString(&out, &j, serverLine);
1044
"Content-Type: multipart/%s; boundary=%s%sContent-Transfer-Encoding: 7bit%s%s",
1045
nalt ? "alternative" : "mixed", boundary, eol, eol, eol);
1046
stringAndString(&out, &j, serverLine);
1047
stringAndString(&out, &j,
1048
"This message is in MIME format. Since your mail reader does not understand\r\n\
1049
this format, some or all of this message may not be legible.\r\n\r\n--");
1050
stringAndString(&out, &j, boundary);
1052
"%sContent-type: %s%sContent-Transfer-Encoding: %s%s%s", eol, ct,
1054
stringAndString(&out, &j, serverLine);
1057
/* Now send the body, line by line. */
1058
appendAttachment(encoded, &out, &j);
1063
for(i = 0; s = attachments[i]; ++i) {
1064
if(!encodeAttachment(s, 0, false, &ct, &ce, &encoded))
1066
sprintf(serverLine, "%s--%s%sContent-Type: %s", eol, boundary, eol,
1068
stringAndString(&out, &j, serverLine);
1069
/* If the filename has a quote in it, forget it. */
1070
/* Also, suppress filename if this is an alternate presentation. */
1071
if(!nalt && !strchr(s, '"') && (ismc || stringIsNum(s) < 0)) {
1072
sprintf(serverLine, "; name=\"%s\"", s);
1073
stringAndString(&out, &j, serverLine);
1075
sprintf(serverLine, "%sContent-Transfer-Encoding: %s%s%s", eol, ce,
1077
stringAndString(&out, &j, serverLine);
1078
appendAttachment(encoded, &out, &j);
1081
} /* loop over attachments */
1083
/* The last boundary */
1084
sprintf(serverLine, "%s--%s--%s", eol, boundary, eol);
1085
stringAndString(&out, &j, serverLine);
1089
/* A dot alone ends the transmission */
1090
stringAndString(&out, &j, ".\r\n");
1091
if(!serverPutLine(out, ao->outssl))
1096
if(!serverGetLine(ao->outssl))
1098
if(!memEqualCI(serverLine, "250 ", 4) &&
1099
/* do these next two lines make any sense? */
1100
!strstrCI(serverLine, "message accepted") &&
1101
!strstrCI(serverLine, "message received")) {
1102
setError(MSG_MailNotSent, serverLine);
1106
serverClose(ao->outssl);
1120
setError(MSG_MailAccountsNone);
1123
if(n <= 0 || n > maxAccount) {
1124
setError(MSG_MailAccountBad, n, maxAccount);
1128
} /* validAccount */
1131
sendMailCurrent(int sm_account, bool dosig)
1133
const char *reclist[MAXRECAT + 1];
1135
const char *atlist[MAXRECAT + 1];
1141
int nrec = 0, nat = 0, nalt = 0;
1142
int account = localAccount;
1147
if(cw->browseMode) {
1148
setError(MSG_MailBrowse);
1152
setError(MSG_MailDB);
1156
setError(MSG_MailDir);
1160
setError(MSG_MailBinary2);
1164
setError(MSG_MailEmpty);
1168
if(!validAccount(account))
1171
recmem = initString(&lr);
1172
atmem = initString(&la);
1174
/* Gather recipients and attachments, until we reach subject: */
1175
for(ln = 1; ln <= cw->dol; ++ln) {
1176
char *line = (char *)fetchLine(ln, -1);
1178
if(memEqualCI(line, "to:", 3) ||
1179
memEqualCI(line, "mailto:", 7) ||
1180
memEqualCI(line, "cc:", 3) ||
1181
memEqualCI(line, "bcc:", 4) ||
1182
memEqualCI(line, "reply to:", 9) ||
1183
memEqualCI(line, "reply to ", 9)) {
1185
if(toupper(line[0]) == 'C')
1187
if(toupper(line[0]) == 'B')
1189
if(toupper(line[0]) == 'R')
1192
line = strchr(line, ':') + 1;
1193
while(*line == ' ' || *line == '\t')
1196
setError(MSG_RecipNone2, ln);
1199
if(nrec == MAXRECAT) {
1200
setError(MSG_RecipMany, MAXRECAT);
1204
for(t = line; *t != '\n'; ++t) ;
1207
setError(MSG_MailFirstCC);
1210
stringAndChar(&recmem, &lr, cc);
1212
stringAndBytes(&recmem, &lr, line, t + 1 - line);
1216
if(memEqualCI(line, "attach:", 7) || memEqualCI(line, "alt:", 4)) {
1217
if(toupper(line[1]) == 'T')
1221
while(*line == ' ' || *line == '\t')
1224
setError(MSG_AttLineX, ln);
1227
if(nat == MAXRECAT) {
1228
setError(MSG_RecipMany, MAXRECAT);
1232
for(t = line; *t != '\n'; ++t) ;
1233
stringAndBytes(&atmem, &la, line, t + 1 - line);
1237
if(memEqualCI(line, "account:", 8)) {
1239
while(*line == ' ' || *line == '\t')
1241
if(!isdigitByte(*line) ||
1242
(account = strtol(line, &line, 10)) == 0 ||
1243
account > maxAccount || *line != '\n') {
1244
setError(MSG_MailAccountBadLineX, ln);
1250
if(memEqualCI(line, "references:", 11)) {
1256
if(memEqualCI(line, "subject:", 8)) {
1257
while(*line == ' ' || *line == '\t')
1260
setError(MSG_SubjectEmpty2);
1267
} /* loop over lines */
1270
account = sm_account;
1272
setError(((ln > cw->dol) + MSG_MailFirstLine), ln);
1277
setError(MSG_RecipNone3);
1281
for(s = recmem, j = 0; *s; s = t + 1, ++j) {
1282
t = strchr(s, '\n');
1287
for(s = atmem, j = 0; *s; s = t + 1, ++j) {
1288
t = strchr(s, '\n');
1294
sprintf(cxbuf, "%d", context);
1295
rc = sendMail(account, reclist, cxbuf, ln, atlist, refline, nalt, dosig);
1301
setError(MSG_Interrupted);
1305
} /* sendMailCurrent */