~ubuntu-branches/ubuntu/jaunty/edbrowse/jaunty-security

« back to all changes in this revision

Viewing changes to src/sendmail.c

  • Committer: Bazaar Package Importer
  • Author(s): Kapil Hari Paranjape
  • Date: 2008-04-09 18:55:23 UTC
  • mfrom: (1.1.4 upstream) (3.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080409185523-dqokcloumyn1ibn4
Tags: 3.3.4-1
* New upstream version (3.3.4).
 - Convert between iso8859-1 and utf-8 on the fly.
 - Support reading of pdf using pdftohtml.
 - French translation of html documentation.
 - Old html documentation renamed to usersguide.
 - Additional documentation on philosophy.
* debian/control:
 - Changed homepage to sourcefource site.
 - Moved homepage from description to its own field.
 - Added "poppler-utils | xpdf-utils" to Recommends.
 - Added "www-browser", "mail-reader" and "editor" to Provides. 
 - Removed "XS-" from Vcs-Svn tag.
 - Standards-Version: 3.7.3
* debian/docs: Added new documentation files
  from "doc/" subdirectory.
* debian/watch: Updated to use sourceforge site.
* debian/edbrowse.doc-base:
  - Changed name of upstream provided html documentation from
    "ebdoc.html" to "usersguide.html".
  - Changed section from "net" to "Network/Web Browsing".
* debian/install: Compiled binary is now in "src/".

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* sendmail.c
 
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.
 
6
 */
 
7
 
 
8
#include "eb.h"
 
9
 
 
10
#include <time.h>
 
11
 
 
12
#define MAXRECAT 100            /* max number of recipients or attachments */
 
13
 
 
14
char serverLine[MAXTTYLINE];
 
15
static char spareLine[MAXTTYLINE];
 
16
int mssock;                     /* mail server socket */
 
17
static bool doSignature;
 
18
static char subjectLine[200];
 
19
 
 
20
static struct ALIAS {
 
21
    char name[16];
 
22
    char email[64];
 
23
} *addressList;
 
24
static int nads;                /* number of addresses */
 
25
static time_t adbooktime;
 
26
 
 
27
/* read and/or refresh the address book */
 
28
bool
 
29
loadAddressBook(void)
 
30
{
 
31
    char *buf, *bufend, *v, *last, *s, *t;
 
32
    bool cmt = false;
 
33
    char state = 0, c;
 
34
    int j, buflen, ln = 1;
 
35
    time_t mtime;
 
36
 
 
37
    if(!addressFile ||
 
38
       (mtime = fileTimeByName(addressFile)) == -1 || mtime <= adbooktime)
 
39
        return true;
 
40
 
 
41
    debugPrint(3, "loading address book");
 
42
    nzFree(addressList);
 
43
    addressList = 0;
 
44
    nads = 0;
 
45
    if(!fileIntoMemory(addressFile, &buf, &buflen))
 
46
        return false;
 
47
    bufend = buf + buflen;
 
48
 
 
49
    for(s = t = last = buf; s < bufend; ++s) {
 
50
        c = *s;
 
51
        if(cmt) {
 
52
            if(c != '\n')
 
53
                continue;
 
54
            cmt = false;
 
55
        }
 
56
        if(c == ':') {          /* delimiter */
 
57
            if(state == 0) {
 
58
                setError(MSG_ABNoAlias, ln);
 
59
              freefail:
 
60
                nzFree(buf);
 
61
                return false;
 
62
            }
 
63
            while(t[-1] == ' ' || t[-1] == '\t')
 
64
                --t;
 
65
            if(state == 1) {
 
66
                *t++ = c;
 
67
                state = 2;
 
68
                continue;
 
69
            }
 
70
            c = '#';            /* extra fields are ignored */
 
71
        }                       /* : */
 
72
        if(c == '#') {
 
73
            cmt = true;
 
74
            continue;
 
75
        }
 
76
        if(c == '\n') {
 
77
            ++ln;
 
78
            if(state == 0)
 
79
                continue;
 
80
            if(state == 1) {
 
81
                setError(MSG_ABNoColon, ln - 1);
 
82
                goto freefail;
 
83
            }
 
84
            if(state == 3) {
 
85
                ++nads;
 
86
                while(isspaceByte(t[-1]))
 
87
                    --t;
 
88
                *t = 0;
 
89
                v = strchr(last, ':');
 
90
                if(v - last >= 16) {
 
91
                    setError(MSG_ABAliasLong, ln - 1);
 
92
                    goto freefail;
 
93
                }
 
94
                ++v;
 
95
                if(t - v >= 64) {
 
96
                    setError(MSG_ABMailLong, ln - 1);
 
97
                    goto freefail;
 
98
                }
 
99
                if(!strchr(v, '@')) {
 
100
                    setError(MSG_ABNoAt, ln - 1);
 
101
                    goto freefail;
 
102
                }
 
103
                if(strpbrk(v, " \t")) {
 
104
                    setError(MSG_ABMailSpaces, ln - 1);
 
105
                    goto freefail;
 
106
                }
 
107
 
 
108
                while(last < t) {
 
109
                    if(!isprintByte(*last)) {
 
110
                        setError(MSG_AbMailUnprintable, ln - 1);
 
111
                        goto freefail;
 
112
                    }
 
113
                    ++last;
 
114
                }
 
115
                *t++ = c;
 
116
            } else
 
117
                t = last;       /* back it up */
 
118
            last = t;
 
119
            state = 0;
 
120
            continue;
 
121
        }
 
122
        /* nl */
 
123
        if((c == ' ' || c == '\t') && (state == 0 || state == 2))
 
124
            continue;
 
125
        if(state == 0)
 
126
            state = 1;
 
127
        if(state == 2)
 
128
            state = 3;
 
129
        *t++ = c;
 
130
    }
 
131
 
 
132
    *t = 0;
 
133
    if(state) {
 
134
        setError(MSG_ABUnterminated);
 
135
        goto freefail;
 
136
    }
 
137
 
 
138
    if(nads) {
 
139
        addressList = allocMem(nads * sizeof (struct ALIAS));
 
140
        j = 0;
 
141
        for(s = buf; *s; s = t + 1, ++j) {
 
142
            t = strchr(s, ':');
 
143
            memcpy(addressList[j].name, s, t - s);
 
144
            addressList[j].name[t - s] = 0;
 
145
            s = t + 1;
 
146
            t = strchr(s, '\n');
 
147
            memcpy(addressList[j].email, s, t - s);
 
148
            addressList[j].email[t - s] = 0;
 
149
        }
 
150
    }
 
151
    /* aliases are present */
 
152
    nzFree(buf);
 
153
    adbooktime = mtime;
 
154
    return true;
 
155
}                               /* loadAddressBook */
 
156
 
 
157
const char *
 
158
reverseAlias(const char *reply)
 
159
{
 
160
    int i;
 
161
    for(i = 0; i < nads; ++i)
 
162
        if(stringEqual(reply, addressList[i].email)) {
 
163
            const char *a = addressList[i].name;
 
164
            if(*a == '!')
 
165
                break;
 
166
            return a;
 
167
        }
 
168
    return 0;                   /* not found */
 
169
}                               /* reverseAlias */
 
170
 
 
171
 
 
172
/*********************************************************************
 
173
Put and get lines from the mail server.
 
174
Print the lines if the debug level calls for it.
 
175
*********************************************************************/
 
176
 
 
177
bool
 
178
serverPutLine(const char *buf, bool secure)
 
179
{
 
180
    int n, len = strlen(buf);
 
181
    char c;
 
182
    if(debugLevel >= 4) {
 
183
        printf("> ");
 
184
        for(n = 0; n < len; ++n) {
 
185
            c = buf[n];
 
186
            if(c != '\r')
 
187
                putchar(c);
 
188
        }
 
189
    }
 
190
    if(secure)
 
191
        n = ssl_write(buf, len);
 
192
    else
 
193
        n = tcp_write(mssock, buf, len);
 
194
    if(n < len) {
 
195
        setError(MSG_MailWrite);
 
196
        return false;
 
197
    }
 
198
    return true;
 
199
}                               /* serverPutLine */
 
200
 
 
201
bool
 
202
serverGetLine(bool secure)
 
203
{
 
204
    int n, len, slen;
 
205
    char c;
 
206
    char *s;
 
207
    slen = strlen(spareLine);
 
208
    strcpy(serverLine, spareLine);
 
209
    s = strchr(serverLine, '\n');
 
210
    if(!s) {
 
211
        if(secure)
 
212
            len = ssl_read(serverLine + slen, sizeof (serverLine) - 1 - slen);
 
213
        else
 
214
            len =
 
215
               tcp_read(mssock, serverLine + slen,
 
216
               sizeof (serverLine) - 1 - slen);
 
217
        if(len <= 0) {
 
218
            setError(MSG_MailRead);
 
219
            return false;
 
220
        }
 
221
        slen += len;
 
222
        serverLine[slen] = 0;
 
223
    }
 
224
    s = strchr(serverLine, '\n');
 
225
    if(!s) {
 
226
        setError(MSG_MailResponseLong);
 
227
        return false;
 
228
    }
 
229
    strcpy(spareLine, s + 1);
 
230
    *s = 0;
 
231
    if(s > serverLine && s[-1] == '\r')
 
232
        *--s = 0;
 
233
    debugPrint(4, "< %s", serverLine);
 
234
    return true;
 
235
}                               /* serverGetLine */
 
236
 
 
237
static bool
 
238
serverPutGet(const char *line, bool secure)
 
239
{
 
240
    if(!serverPutLine(line, secure))
 
241
        return false;
 
242
    if(!serverGetLine(secure))
 
243
        return false;
 
244
}                               /* serverPutGet */
 
245
 
 
246
void
 
247
serverClose(bool secure)
 
248
{
 
249
    serverPutLine("quit\r\n", secure);
 
250
    endhostent();
 
251
    sleep(2);
 
252
    if(secure)
 
253
        ssl_done();
 
254
    close(mssock);
 
255
}                               /* serverClose */
 
256
 
 
257
/* Connect to the mail server */
 
258
bool
 
259
mailConnect(const char *host, int port, bool secure)
 
260
{
 
261
    IP32bit ip = tcp_name_ip(host);
 
262
    if(ip == NULL_IP) {
 
263
        setError((intFlag ? MSG_Interrupted : MSG_MailLocate), host);
 
264
        return false;
 
265
    }
 
266
    debugPrint(4, "%s -> %s", host, tcp_ip_dots(ip));
 
267
    mssock = tcp_connect(ip, port, mailTimeout);
 
268
    if(mssock < 0) {
 
269
        setError(intFlag ? MSG_Interrupted : MSG_MailConnect);
 
270
        return false;
 
271
    }
 
272
    debugPrint(4, "connected to port %d", port);
 
273
    spareLine[0] = 0;
 
274
    if(secure) {
 
275
        int n = ssl_newbind(mssock);
 
276
        if(n < 0) {
 
277
            if(n == -999)
 
278
                setError(MSG_NoCertify, host);
 
279
            else
 
280
                setError(MSG_WebConnectSecure, host, n);
 
281
            return false;
 
282
        }
 
283
        debugPrint(4, "secure connection established");
 
284
    }
 
285
    return true;
 
286
}                               /* mailConnect */
 
287
 
 
288
static char base64_chars[] =
 
289
   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
290
char *
 
291
base64Encode(const char *inbuf, int inlen, bool lines)
 
292
{
 
293
    char *out, *outstr;
 
294
    uchar *in = (uchar *) inbuf;
 
295
    int colno;
 
296
    int outlen = ((inlen / 3) + 1) * 4;
 
297
    ++outlen;                   /* zero on the end */
 
298
    if(lines)
 
299
        outlen += (inlen / 54) + 1;
 
300
    outstr = out = allocMem(outlen);
 
301
    colno = 0;
 
302
    while(inlen >= 3) {
 
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)];
 
307
        inlen -= 3;
 
308
        in += 3;
 
309
        if(!lines)
 
310
            continue;
 
311
        colno += 4;
 
312
        if(colno < 72)
 
313
            continue;
 
314
        *out++ = '\n';
 
315
        colno = 0;
 
316
    }
 
317
    if(inlen == 1) {
 
318
        *out++ = base64_chars[(int)(*in >> 2)];
 
319
        *out++ = base64_chars[(int)(*in << 4 & 63)];
 
320
        *out++ = '=';
 
321
        *out++ = '=';
 
322
        colno += 4;
 
323
    }
 
324
    if(inlen == 2) {
 
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)];
 
328
        *out++ = '=';
 
329
        colno += 4;
 
330
    }
 
331
/* finish the last line */
 
332
    if(lines && colno)
 
333
        *out++ = '\n';
 
334
    *out = 0;
 
335
    return outstr;
 
336
}                               /* base64Encode */
 
337
 
 
338
char *
 
339
qpEncode(const char *line)
 
340
{
 
341
    char *newbuf;
 
342
    int l;
 
343
    const char *s;
 
344
    char c;
 
345
 
 
346
    newbuf = initString(&l);
 
347
    for(s = line; (c = *s); ++s) {
 
348
        if(c < '\n' && c != '\t' || c == '=') {
 
349
            char expand[4];
 
350
            sprintf(expand, "=%02X", (uchar) c);
 
351
            stringAndString(&newbuf, &l, expand);
 
352
        } else {
 
353
            stringAndChar(&newbuf, &l, c);
 
354
        }
 
355
    }
 
356
 
 
357
    return newbuf;
 
358
}                               /* qpEncode */
 
359
 
 
360
/* Return 0 if there was no need to encode */
 
361
static char *
 
362
isoEncode(char *start, char *end)
 
363
{
 
364
    int nacount = 0, count = 0, len;
 
365
    char *s, *t;
 
366
    char c, code;
 
367
 
 
368
    for(s = start; s < end; ++s) {
 
369
        c = *s;
 
370
        if(c == 0)
 
371
            *s = ' ';
 
372
        if(isspaceByte(c))
 
373
            *s = ' ';
 
374
    }
 
375
 
 
376
    for(s = start; s < end; ++s) {
 
377
        c = *s;
 
378
        ++count;
 
379
        if(!isprintByte(c) && c != ' ')
 
380
            ++nacount;
 
381
    }
 
382
 
 
383
    if(!nacount)
 
384
        return 0;
 
385
 
 
386
    if(nacount * 4 >= count && count > 8) {
 
387
        code = 'B';
 
388
        s = base64Encode(start, end - start, false);
 
389
        goto package;
 
390
    }
 
391
 
 
392
    code = 'Q';
 
393
    s = qpEncode(start);
 
394
 
 
395
  package:
 
396
    len = strlen(s);
 
397
    t = allocMem(len + 20);
 
398
    sprintf(t, "=?ISO-8859-1?%c?%s?=", code, s);
 
399
    nzFree(s);
 
400
    return t;
 
401
}                               /* isoEncode */
 
402
 
 
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. */
 
410
bool
 
411
encodeAttachment(const char *file, int ismail, bool webform,
 
412
   const char **type_p, const char **enc_p, char **data_p)
 
413
{
 
414
    char *buf;
 
415
    char c;
 
416
    bool longline;
 
417
    char *s, *t, *v;
 
418
    char *ct, *ce;              /* content type, content encoding */
 
419
    int buflen, i, cx;
 
420
    int nacount, nullcount, nlcount;
 
421
 
 
422
    if(ismail < 0) {
 
423
        buf = cloneString(file);
 
424
        buflen = strlen(buf);
 
425
        ismail = -ismail;
 
426
        file = EMPTYSTRING;
 
427
    } else {
 
428
 
 
429
        if(!ismc && (cx = stringIsNum(file)) >= 0) {
 
430
            static char newfilename[16];
 
431
            if(!unfoldBuffer(cx, false, &buf, &buflen))
 
432
                return false;
 
433
            if(!buflen) {
 
434
                if(webform) {
 
435
                  empty:
 
436
                    buf = EMPTYSTRING;
 
437
                    ct = "text/plain";
 
438
                    ce = "7bit";
 
439
                    goto success;
 
440
                }
 
441
                setError(MSG_BufferXEmpty, cx);
 
442
                goto freefail;
 
443
            }
 
444
            sprintf(newfilename, "<buffer %d>", cx);
 
445
            file = newfilename;
 
446
            if(sessionList[cx].lw->fileName)
 
447
                file = sessionList[cx].lw->fileName;
 
448
        } else {
 
449
            if(!fileIntoMemory(file, &buf, &buflen))
 
450
                return false;
 
451
            if(!buflen) {
 
452
                if(webform)
 
453
                    goto empty;
 
454
                setError(MSG_FileXEmpty, file);
 
455
                goto freefail;
 
456
            }
 
457
        }
 
458
    }                           /* ismail negative or normal */
 
459
 
 
460
    if(ismail) {
 
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 */
 
466
        s = buf;
 
467
        i = ismail;
 
468
        while(--i) {
 
469
            while(*s != '\n')
 
470
                ++s;
 
471
            ++s;
 
472
        }
 
473
        while(*s == ' ' || *s == '\t')
 
474
            ++s;
 
475
        if(!memEqualCI(s, "subject:", 8)) {
 
476
            setError(MSG_SubjectStart);
 
477
            goto freefail;
 
478
        }
 
479
        s += 8;
 
480
        while(*s == ' ' || *s == '\t')
 
481
            ++s;
 
482
        t = s;
 
483
        while(*s != '\n')
 
484
            ++s;
 
485
        v = s;
 
486
        while(s > t && isspaceByte(s[-1]))
 
487
            --s;
 
488
        if(s == t) {
 
489
            setError(MSG_SubjectEmpty);
 
490
            goto freefail;
 
491
        }
 
492
        if(s - t >= sizeof (subjectLine)) {
 
493
            setError(MSG_SubjectLong, sizeof (subjectLine) - 1);
 
494
            goto freefail;
 
495
        }
 
496
        memcpy(subjectLine, t, s - t);
 
497
        subjectLine[s - t] = 0;
 
498
        t = subjectLine + (s - t);
 
499
        s = isoEncode(subjectLine, t);
 
500
        if(s) {
 
501
            if(strlen(s) >= sizeof (subjectLine)) {
 
502
                setError(MSG_SubjectLong, sizeof (subjectLine) - 1);
 
503
                goto freefail;
 
504
            }
 
505
            strcpy(subjectLine, s);
 
506
            nzFree(s);
 
507
        }
 
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')
 
512
                break;
 
513
        buflen -= (v - buf);
 
514
        if(buflen)
 
515
            memcpy(buf, v, buflen);
 
516
        buf[buflen] = 0;
 
517
 
 
518
        if(doSignature) {       /* Append .signature file. */
 
519
            c = fileTypeByName(sigFile, false);
 
520
            if(c != 0) {
 
521
                int fd, n;
 
522
                if(c != 'f') {
 
523
                    setError(MSG_SigRegular);
 
524
                    goto freefail;
 
525
                }
 
526
                n = fileSizeByName(sigFile);
 
527
                if(n > 0) {
 
528
                    buf = reallocMem(buf, buflen + n + 1);
 
529
                    fd = open(sigFile, O_RDONLY);
 
530
                    if(fd < 0) {
 
531
                        setError(MSG_SigAccess);
 
532
                        goto freefail;
 
533
                    }
 
534
                    read(fd, buf + buflen, n);
 
535
                    close(fd);
 
536
                    buflen += n;
 
537
                    buf[buflen] = 0;
 
538
                }
 
539
            }
 
540
        }                       /* .signature */
 
541
    }
 
542
 
 
543
    /* primary email message */
 
544
    /* Infer content type from the filename */
 
545
    ct = 0;
 
546
    s = strrchr(file, '.');
 
547
    if(s && s[1]) {
 
548
        ++s;
 
549
        if(stringEqualCI(s, "ps"))
 
550
            ct = "application/PostScript";
 
551
        if(stringEqualCI(s, "jpeg"))
 
552
            ct = "image/jpeg";
 
553
        if(stringEqualCI(s, "gif"))
 
554
            ct = "image/gif";
 
555
        if(stringEqualCI(s, "wav"))
 
556
            ct = "audio/basic";
 
557
        if(stringEqualCI(s, "mpeg"))
 
558
            ct = "video/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"))
 
565
            ct = "text/html";
 
566
    }
 
567
 
 
568
/* Count the nonascii characters */
 
569
    nacount = nullcount = nlcount = 0;
 
570
    longline = false;
 
571
    s = 0;
 
572
    for(i = 0; i < buflen; ++i) {
 
573
        c = buf[i];
 
574
        if(c == '\0')
 
575
            ++nullcount;
 
576
        if(c < 0)
 
577
            ++nacount;
 
578
        if(c != '\n')
 
579
            continue;
 
580
        ++nlcount;
 
581
        t = buf + i;
 
582
        if(s && t - s > 120)
 
583
            longline = true;
 
584
        if(!s && i > 120)
 
585
            longline = true;
 
586
        s = t;
 
587
    }
 
588
    t = buf + i;
 
589
    if(s && t - s > 120)
 
590
        longline = true;
 
591
    if(!s && i > 120)
 
592
        longline = true;
 
593
    debugPrint(6, "attaching %s length %d nonascii %d nulls %d longline %d",
 
594
       file, buflen, nacount, nullcount, longline);
 
595
    nacount += nullcount;
 
596
 
 
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. */
 
600
 
 
601
    if(buflen > 20 && nacount * 5 > buflen ||
 
602
       webform && (nacount * 20 > buflen || nullcount || longline)) {
 
603
        if(ismail) {
 
604
            setError(MSG_MailBinary, file);
 
605
            goto freefail;
 
606
        }
 
607
 
 
608
        s = base64Encode(buf, buflen, true);
 
609
        nzFree(buf);
 
610
        buf = s;
 
611
        if(!ct)
 
612
            ct = "application/octet-stream";    /* default type */
 
613
        ce = "base64";
 
614
        goto success;
 
615
    }
 
616
 
 
617
    if(!ct)
 
618
        ct = "text/plain";
 
619
 
 
620
/* Switch to unix newlines - we'll switch back to dos later. */
 
621
    v = buf + buflen;
 
622
    for(s = t = buf; s < v; ++s) {
 
623
        c = *s;
 
624
        if(c == '\r' && s < v - 1 && s[1] == '\n')
 
625
            continue;
 
626
        *t++ = c;
 
627
    }
 
628
    buflen = t - buf;
 
629
 
 
630
/* Do we need to use quoted-printable? */
 
631
/* Perhaps this hshould read (nacount > 0) */
 
632
    if(nacount * 20 > buflen || nullcount || longline) {
 
633
        char *newbuf;
 
634
        int l, colno = 0, space = 0;
 
635
 
 
636
        newbuf = initString(&l);
 
637
        v = buf + buflen;
 
638
        for(s = buf; s < v; ++s) {
 
639
            c = *s;
 
640
/* do we have to =expand this character? */
 
641
            if(c < '\n' && c != '\t' ||
 
642
               c == '=' ||
 
643
               c == '\xff' ||
 
644
               (c == ' ' || c == '\t') && s < v - 1 && s[1] == '\n') {
 
645
                char expand[4];
 
646
                sprintf(expand, "=%02X", (uchar) c);
 
647
                stringAndString(&newbuf, &l, expand);
 
648
                colno += 3;
 
649
            } else {
 
650
                stringAndChar(&newbuf, &l, c);
 
651
                ++colno;
 
652
            }
 
653
            if(c == '\n') {
 
654
                colno = space = 0;
 
655
                continue;
 
656
            }
 
657
            if(c == ' ' || c == '\t')
 
658
                space = l;
 
659
            if(colno < 72)
 
660
                continue;
 
661
            if(s == v - 1)
 
662
                continue;
 
663
/* If newline's coming up anyways, don't force another one. */
 
664
            if(s[1] == '\n')
 
665
                continue;
 
666
            i = l;
 
667
            if(!space || space == i) {
 
668
                stringAndString(&newbuf, &l, "=\n");
 
669
                colno = space = 0;
 
670
                continue;
 
671
            }
 
672
            colno = i - space;
 
673
            stringAndString(&newbuf, &l, "**"); /* make room */
 
674
            while(i > space) {
 
675
                newbuf[i + 1] = newbuf[i - 1];
 
676
                --i;
 
677
            }
 
678
            newbuf[space] = '=';
 
679
            newbuf[space + 1] = '\n';
 
680
            space = 0;
 
681
        }                       /* loop over characters */
 
682
 
 
683
        nzFree(buf);
 
684
        buf = newbuf;
 
685
        ce = "quoted-printable";
 
686
        goto success;
 
687
    }
 
688
    /* quoted printable */
 
689
    buf[buflen] = 0;
 
690
    ce = (nacount ? "8bit" : "7bit");
 
691
 
 
692
  success:
 
693
    debugPrint(6, "encoded %s %s length %d", ct, ce, strlen(buf));
 
694
    *enc_p = ce;
 
695
    *type_p = ct;
 
696
    *data_p = buf;
 
697
    return true;
 
698
 
 
699
  freefail:
 
700
    nzFree(buf);
 
701
    return false;
 
702
}                               /* encodeAttachment */
 
703
 
 
704
static char *
 
705
mailTimeString(void)
 
706
{
 
707
    static char buf[48];
 
708
    struct tm *cur_tm;
 
709
    long now;
 
710
    time(&now);
 
711
    cur_tm = localtime(&now);
 
712
    strftime(buf, sizeof (buf), "%a, %d %b %Y %H:%M:%S %z", cur_tm);
 
713
    return buf;
 
714
}                               /* mailTimeString */
 
715
 
 
716
static char *
 
717
messageTimeID(void)
 
718
{
 
719
    static char buf[48];
 
720
    struct tm *cur_tm;
 
721
    long now;
 
722
    time(&now);
 
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);
 
727
    return buf;
 
728
}                               /* messageTimeID */
 
729
 
 
730
static void
 
731
appendAttachment(const char *s, char **out, int *l)
 
732
{
 
733
    const char *t;
 
734
    int n;
 
735
    while(*s) {                 /* another line */
 
736
        t = strchr(s, '\n');
 
737
        if(!t)
 
738
            t = s + strlen(s);
 
739
        n = t - s;
 
740
        if(t[-1] == '\r')
 
741
            --n;
 
742
        if(n)
 
743
            memcpy(serverLine, s, n);
 
744
        serverLine[n] = 0;
 
745
        if(n == 1 && serverLine[0] == '.')      /* can't allow this */
 
746
            strcpy(serverLine, " .");
 
747
        strcat(serverLine, eol);
 
748
        stringAndString(out, l, serverLine);
 
749
        if(*t)
 
750
            ++t;
 
751
        s = t;
 
752
    }
 
753
/* Small bug here - an attachment that is not base64 encoded,
 
754
 * and had no newline at the end, now has one. */
 
755
}                               /* appendAttachment */
 
756
 
 
757
char *
 
758
makeBoundary(void)
 
759
{
 
760
    static char boundary[60];
 
761
    sprintf(boundary, "nextpart-eb-%06d", rand() % 1000000);
 
762
    return boundary;
 
763
}                               /* makeBoundary */
 
764
 
 
765
/* Send mail to the smtp server. */
 
766
bool
 
767
sendMail(int account, const char **recipients, const char *body,
 
768
   int subjat, const char **attachments, const char *refline,
 
769
   int nalt, bool dosig)
 
770
{
 
771
    char *from, *fromiso, *reply, *login, *smlogin, *pass;
 
772
    const struct MACCOUNT *a, *ao, *localMail;
 
773
    const char *s, *boundary;
 
774
    char reccc[MAXRECAT];
 
775
    char *t;
 
776
    int nat, cx, i, j;
 
777
    char *out = 0;
 
778
    bool mustmime = false;
 
779
    bool firstrec;
 
780
    const char *ct, *ce;
 
781
    char *encoded = 0;
 
782
 
 
783
    if(!validAccount(account))
 
784
        return false;
 
785
    localMail = accounts + localAccount - 1;
 
786
 
 
787
    a = accounts + account - 1;
 
788
    from = a->from;
 
789
    reply = a->reply;
 
790
    ao = a->outssl ? a : localMail;
 
791
    login = ao->login;
 
792
    smlogin = strchr(login, '\\');
 
793
    if(smlogin)
 
794
        ++smlogin;
 
795
    else
 
796
        smlogin = login;
 
797
    pass = ao->password;
 
798
    doSignature = dosig;
 
799
 
 
800
    nat = 0;                    /* number of attachments */
 
801
    if(attachments) {
 
802
        while(attachments[nat])
 
803
            ++nat;
 
804
    }
 
805
    if(nat)
 
806
        mustmime = true;
 
807
    if(nalt && nalt < nat) {
 
808
        setError(MSG_AttAlternate);
 
809
        return false;
 
810
    }
 
811
 
 
812
    if(!loadAddressBook())
 
813
        return false;
 
814
 
 
815
/* set copy flags */
 
816
    for(j = 0; s = recipients[j]; ++j) {
 
817
        char cc = 0;
 
818
        if(*s == '^' || *s == '?')
 
819
            cc = *s++;
 
820
        if(j == MAXRECAT) {
 
821
            setError(MSG_RecipMany, MAXRECAT);
 
822
            return false;
 
823
        }
 
824
        recipients[j] = s;
 
825
        reccc[j] = cc;
 
826
    }
 
827
 
 
828
/* Look up aliases in the address book */
 
829
    for(j = 0; s = recipients[j]; ++j) {
 
830
        if(strchr(s, '@'))
 
831
            continue;
 
832
        t = 0;
 
833
        for(i = 0; i < nads; ++i) {
 
834
            const char *a = addressList[i].name;
 
835
            if(*a == '-' || *a == '!')
 
836
                ++a;
 
837
            if(!stringEqual(s, a))
 
838
                continue;
 
839
            t = addressList[i].email;
 
840
            debugPrint(3, " %s becomes %s", s, t);
 
841
            break;
 
842
        }
 
843
        if(t) {
 
844
            recipients[j] = t;
 
845
            continue;
 
846
        }
 
847
        if(!addressFile) {
 
848
            setError(MSG_ABMissing);
 
849
            return false;
 
850
        }
 
851
        setError(MSG_ABNoAlias2, s);
 
852
        return false;
 
853
    }                           /* recipients */
 
854
 
 
855
    if(!j) {
 
856
        setError(MSG_RecipNone);
 
857
        return false;
 
858
    }
 
859
 
 
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))
 
864
                return false;
 
865
            if(!sessionList[cx].lw->dol) {
 
866
                setError(MSG_AttSessionEmpty, cx);
 
867
                return false;
 
868
            }
 
869
        } else {
 
870
            char ftype = fileTypeByName(s, false);
 
871
            if(!ftype) {
 
872
                setError(MSG_AttAccess, s);
 
873
                return false;
 
874
            }
 
875
            if(ftype != 'f') {
 
876
                setError(MSG_AttRegular, s);
 
877
                return false;
 
878
            }
 
879
            if(!fileSizeByName(s)) {
 
880
                setError(MSG_AttEmpty2, s);
 
881
                return false;
 
882
            }
 
883
        }
 
884
    }                           /* loop over attachments */
 
885
 
 
886
    if(!encodeAttachment(body, subjat, false, &ct, &ce, &encoded))
 
887
        return false;
 
888
    if(ce[0] == 'q')
 
889
        mustmime = true;
 
890
 
 
891
    boundary = makeBoundary();
 
892
 
 
893
    if(!mailConnect(ao->outurl, ao->outport, ao->outssl)) {
 
894
        nzFree(encoded);
 
895
        return false;
 
896
    }
 
897
    if(!serverGetLine(ao->outssl))
 
898
        goto mailfail;
 
899
    while(memEqualCI(serverLine, "220-", 4)) {
 
900
        if(!serverGetLine(ao->outssl))
 
901
            goto mailfail;
 
902
    }
 
903
    if(!memEqualCI(serverLine, "220 ", 4)) {
 
904
        setError(MSG_MailBadPrompt, serverLine);
 
905
        goto mailfail;
 
906
    }
 
907
 
 
908
    sprintf(serverLine, "%s %s%s", (a->outssl ? "ehlo" : "Helo"), smlogin, eol);
 
909
    if(!serverPutLine(serverLine, ao->outssl))
 
910
        goto mailfail;
 
911
  get250:
 
912
    if(!serverGetLine(ao->outssl))
 
913
        goto mailfail;
 
914
    if(!memEqualCI(serverLine, "250", 3) ||
 
915
       serverLine[3] != ' ' && serverLine[3] != '-') {
 
916
        setError(MSG_MailWhat, login);
 
917
        goto mailfail;
 
918
    }
 
919
    if(serverLine[3] == '-')
 
920
        goto get250;
 
921
 
 
922
    if(ao->outssl) {
 
923
        char *b;
 
924
/* login authentication is the only thing I support right now. */
 
925
        if(!serverPutGet("auth login\r\n", true))
 
926
            goto mailfail;
 
927
        if(!memEqualCI(serverLine, "334 ", 4)) {
 
928
            setError(MSG_AuthLoginOnly);
 
929
            goto mailfail;
 
930
        }
 
931
        b = base64Encode(login, strlen(login), false);
 
932
        sprintf(serverLine, "%s%s", b, eol);
 
933
        nzFree(b);
 
934
        if(!serverPutGet(serverLine, true))
 
935
            goto mailfail;
 
936
        if(!memEqualCI(serverLine, "334 ", 4)) {
 
937
            setError(MSG_AuthLoginOnly);
 
938
            goto mailfail;
 
939
        }
 
940
        b = base64Encode(pass, strlen(pass), false);
 
941
        sprintf(serverLine, "%s%s", b, eol);
 
942
        nzFree(b);
 
943
        if(!serverPutGet(serverLine, true))
 
944
            goto mailfail;
 
945
        if(!memEqualCI(serverLine, "235 ", 4)) {
 
946
            setError(MSG_SmtpNotComplete, serverLine);
 
947
            goto mailfail;
 
948
        }
 
949
    }
 
950
 
 
951
    sprintf(serverLine, "mail from: <%s>%s", reply, eol);
 
952
    if(!serverPutGet(serverLine, ao->outssl))
 
953
        goto mailfail;
 
954
    if(!memEqualCI(serverLine, "250 ", 4)) {
 
955
        setError(MSG_MailReject, reply);
 
956
        goto mailfail;
 
957
    }
 
958
 
 
959
    for(j = 0; s = recipients[j]; ++j) {
 
960
        sprintf(serverLine, "rcpt to: <%s>%s", s, eol);
 
961
        if(!serverPutGet(serverLine, ao->outssl))
 
962
            goto mailfail;
 
963
        if(!memEqualCI(serverLine, "250 ", 4)) {
 
964
            setError(MSG_MailReject, s);
 
965
            goto mailfail;
 
966
        }
 
967
    }
 
968
 
 
969
    if(!serverPutGet("data\r\n", ao->outssl))
 
970
        goto mailfail;
 
971
    if(!memEqualCI(serverLine, "354 ", 4)) {
 
972
        setError(MSG_MailNotReady, serverLine);
 
973
        goto mailfail;
 
974
    }
 
975
 
 
976
/* Build the outgoing mail, and send it in one go, as one string. */
 
977
    out = initString(&j);
 
978
 
 
979
    firstrec = true;
 
980
    for(i = 0; s = recipients[i]; ++i) {
 
981
        if(reccc[i])
 
982
            continue;
 
983
        stringAndString(&out, &j, firstrec ? "To:" : ",\r\n  ");
 
984
        stringAndString(&out, &j, s);
 
985
        firstrec = false;
 
986
    }
 
987
    if(!firstrec)
 
988
        stringAndString(&out, &j, eol);
 
989
 
 
990
    firstrec = true;
 
991
    for(i = 0; s = recipients[i]; ++i) {
 
992
        if(reccc[i] != '^')
 
993
            continue;
 
994
        stringAndString(&out, &j, firstrec ? "CC:" : ",\r\n  ");
 
995
        stringAndString(&out, &j, s);
 
996
        firstrec = false;
 
997
    }
 
998
    if(!firstrec)
 
999
        stringAndString(&out, &j, eol);
 
1000
 
 
1001
    firstrec = true;
 
1002
    for(i = 0; s = recipients[i]; ++i) {
 
1003
        if(reccc[i] != '?')
 
1004
            continue;
 
1005
        stringAndString(&out, &j, firstrec ? "BCC:" : ",\r\n  ");
 
1006
        stringAndString(&out, &j, s);
 
1007
        firstrec = false;
 
1008
    }
 
1009
    if(!firstrec)
 
1010
        stringAndString(&out, &j, eol);
 
1011
 
 
1012
    fromiso = isoEncode(from, from + strlen(from));
 
1013
    if(!fromiso)
 
1014
        fromiso = 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);
 
1019
    if(fromiso != from)
 
1020
        nzFree(fromiso);
 
1021
    if(refline) {
 
1022
        s = refline + strlen(refline);
 
1023
        if(s > refline && s[-1] == '\n')
 
1024
            --s;
 
1025
        stringAndBytes(&out, &j, refline, s - refline);
 
1026
        stringAndString(&out, &j, eol);
 
1027
    }
 
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);
 
1035
 
 
1036
    if(!mustmime) {
 
1037
/* no mime components required, we can just send the mail. */
 
1038
        sprintf(serverLine,
 
1039
           "Content-type: %s%sContent-Transfer-Encoding: %s%s%s", ct, eol, ce,
 
1040
           eol, eol);
 
1041
        stringAndString(&out, &j, serverLine);
 
1042
    } else {
 
1043
        sprintf(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);
 
1051
        sprintf(serverLine,
 
1052
           "%sContent-type: %s%sContent-Transfer-Encoding: %s%s%s", eol, ct,
 
1053
           eol, ce, eol, eol);
 
1054
        stringAndString(&out, &j, serverLine);
 
1055
    }
 
1056
 
 
1057
/* Now send the body, line by line. */
 
1058
    appendAttachment(encoded, &out, &j);
 
1059
    nzFree(encoded);
 
1060
    encoded = 0;
 
1061
 
 
1062
    if(mustmime) {
 
1063
        for(i = 0; s = attachments[i]; ++i) {
 
1064
            if(!encodeAttachment(s, 0, false, &ct, &ce, &encoded))
 
1065
                return false;
 
1066
            sprintf(serverLine, "%s--%s%sContent-Type: %s", eol, boundary, eol,
 
1067
               ct);
 
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);
 
1074
            }
 
1075
            sprintf(serverLine, "%sContent-Transfer-Encoding: %s%s%s", eol, ce,
 
1076
               eol, eol);
 
1077
            stringAndString(&out, &j, serverLine);
 
1078
            appendAttachment(encoded, &out, &j);
 
1079
            nzFree(encoded);
 
1080
            encoded = 0;
 
1081
        }                       /* loop over attachments */
 
1082
 
 
1083
/* The last boundary */
 
1084
        sprintf(serverLine, "%s--%s--%s", eol, boundary, eol);
 
1085
        stringAndString(&out, &j, serverLine);
 
1086
    }
 
1087
 
 
1088
    /* mime format */
 
1089
    /* A dot alone ends the transmission */
 
1090
    stringAndString(&out, &j, ".\r\n");
 
1091
    if(!serverPutLine(out, ao->outssl))
 
1092
        goto mailfail;
 
1093
    nzFree(out);
 
1094
    out = 0;
 
1095
 
 
1096
    if(!serverGetLine(ao->outssl))
 
1097
        goto mailfail;
 
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);
 
1103
        goto mailfail;
 
1104
    }
 
1105
 
 
1106
    serverClose(ao->outssl);
 
1107
    return true;
 
1108
 
 
1109
  mailfail:
 
1110
    nzFree(encoded);
 
1111
    nzFree(out);
 
1112
    close(mssock);
 
1113
    return false;
 
1114
}                               /* sendMail */
 
1115
 
 
1116
bool
 
1117
validAccount(int n)
 
1118
{
 
1119
    if(!maxAccount) {
 
1120
        setError(MSG_MailAccountsNone);
 
1121
        return false;
 
1122
    }
 
1123
    if(n <= 0 || n > maxAccount) {
 
1124
        setError(MSG_MailAccountBad, n, maxAccount);
 
1125
        return false;
 
1126
    }
 
1127
    return true;
 
1128
}                               /* validAccount */
 
1129
 
 
1130
bool
 
1131
sendMailCurrent(int sm_account, bool dosig)
 
1132
{
 
1133
    const char *reclist[MAXRECAT + 1];
 
1134
    char *recmem;
 
1135
    const char *atlist[MAXRECAT + 1];
 
1136
    char *atmem;
 
1137
    char *s, *t;
 
1138
    char cxbuf[4];
 
1139
    int lr, la, ln;
 
1140
    char *refline = 0;
 
1141
    int nrec = 0, nat = 0, nalt = 0;
 
1142
    int account = localAccount;
 
1143
    int j;
 
1144
    bool rc = false;
 
1145
    bool subj = false;
 
1146
 
 
1147
    if(cw->browseMode) {
 
1148
        setError(MSG_MailBrowse);
 
1149
        return false;
 
1150
    }
 
1151
    if(cw->sqlMode) {
 
1152
        setError(MSG_MailDB);
 
1153
        return false;
 
1154
    }
 
1155
    if(cw->dirMode) {
 
1156
        setError(MSG_MailDir);
 
1157
        return false;
 
1158
    }
 
1159
    if(cw->binMode) {
 
1160
        setError(MSG_MailBinary2);
 
1161
        return false;
 
1162
    }
 
1163
    if(!cw->dol) {
 
1164
        setError(MSG_MailEmpty);
 
1165
        return false;
 
1166
    }
 
1167
 
 
1168
    if(!validAccount(account))
 
1169
        return false;
 
1170
 
 
1171
    recmem = initString(&lr);
 
1172
    atmem = initString(&la);
 
1173
 
 
1174
/* Gather recipients and attachments, until we reach subject: */
 
1175
    for(ln = 1; ln <= cw->dol; ++ln) {
 
1176
        char *line = (char *)fetchLine(ln, -1);
 
1177
 
 
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)) {
 
1184
            char cc = 0;
 
1185
            if(toupper(line[0]) == 'C')
 
1186
                cc = '^';
 
1187
            if(toupper(line[0]) == 'B')
 
1188
                cc = '?';
 
1189
            if(toupper(line[0]) == 'R')
 
1190
                line += 9;
 
1191
            else
 
1192
                line = strchr(line, ':') + 1;
 
1193
            while(*line == ' ' || *line == '\t')
 
1194
                ++line;
 
1195
            if(*line == '\n') {
 
1196
                setError(MSG_RecipNone2, ln);
 
1197
                goto done;
 
1198
            }
 
1199
            if(nrec == MAXRECAT) {
 
1200
                setError(MSG_RecipMany, MAXRECAT);
 
1201
                goto done;
 
1202
            }
 
1203
            ++nrec;
 
1204
            for(t = line; *t != '\n'; ++t) ;
 
1205
            if(cc) {
 
1206
                if(!lr) {
 
1207
                    setError(MSG_MailFirstCC);
 
1208
                    goto done;
 
1209
                }
 
1210
                stringAndChar(&recmem, &lr, cc);
 
1211
            }
 
1212
            stringAndBytes(&recmem, &lr, line, t + 1 - line);
 
1213
            continue;
 
1214
        }
 
1215
 
 
1216
        if(memEqualCI(line, "attach:", 7) || memEqualCI(line, "alt:", 4)) {
 
1217
            if(toupper(line[1]) == 'T')
 
1218
                line += 7;
 
1219
            else
 
1220
                line += 4, ++nalt;
 
1221
            while(*line == ' ' || *line == '\t')
 
1222
                ++line;
 
1223
            if(*line == '\n') {
 
1224
                setError(MSG_AttLineX, ln);
 
1225
                goto done;
 
1226
            }
 
1227
            if(nat == MAXRECAT) {
 
1228
                setError(MSG_RecipMany, MAXRECAT);
 
1229
                goto done;
 
1230
            }
 
1231
            ++nat;
 
1232
            for(t = line; *t != '\n'; ++t) ;
 
1233
            stringAndBytes(&atmem, &la, line, t + 1 - line);
 
1234
            continue;
 
1235
        }
 
1236
 
 
1237
        if(memEqualCI(line, "account:", 8)) {
 
1238
            line += 8;
 
1239
            while(*line == ' ' || *line == '\t')
 
1240
                ++line;
 
1241
            if(!isdigitByte(*line) ||
 
1242
               (account = strtol(line, &line, 10)) == 0 ||
 
1243
               account > maxAccount || *line != '\n') {
 
1244
                setError(MSG_MailAccountBadLineX, ln);
 
1245
                goto done;
 
1246
            }
 
1247
            continue;
 
1248
        }
 
1249
 
 
1250
        if(memEqualCI(line, "references:", 11)) {
 
1251
            if(!refline)
 
1252
                refline = line;
 
1253
            continue;
 
1254
        }
 
1255
 
 
1256
        if(memEqualCI(line, "subject:", 8)) {
 
1257
            while(*line == ' ' || *line == '\t')
 
1258
                ++line;
 
1259
            if(*line == '\n') {
 
1260
                setError(MSG_SubjectEmpty2);
 
1261
                goto done;
 
1262
            }
 
1263
            subj = true;
 
1264
        }
 
1265
 
 
1266
        break;
 
1267
    }                           /* loop over lines */
 
1268
 
 
1269
    if(sm_account)
 
1270
        account = sm_account;
 
1271
    if(!subj) {
 
1272
        setError(((ln > cw->dol) + MSG_MailFirstLine), ln);
 
1273
        goto done;
 
1274
    }
 
1275
 
 
1276
    if(nrec == 0) {
 
1277
        setError(MSG_RecipNone3);
 
1278
        goto done;
 
1279
    }
 
1280
 
 
1281
    for(s = recmem, j = 0; *s; s = t + 1, ++j) {
 
1282
        t = strchr(s, '\n');
 
1283
        *t = 0;
 
1284
        reclist[j] = s;
 
1285
    }
 
1286
    reclist[j] = 0;
 
1287
    for(s = atmem, j = 0; *s; s = t + 1, ++j) {
 
1288
        t = strchr(s, '\n');
 
1289
        *t = 0;
 
1290
        atlist[j] = s;
 
1291
    }
 
1292
    atlist[j] = 0;
 
1293
 
 
1294
    sprintf(cxbuf, "%d", context);
 
1295
    rc = sendMail(account, reclist, cxbuf, ln, atlist, refline, nalt, dosig);
 
1296
 
 
1297
  done:
 
1298
    nzFree(recmem);
 
1299
    nzFree(atmem);
 
1300
    if(!rc && intFlag)
 
1301
        setError(MSG_Interrupted);
 
1302
    if(rc)
 
1303
        i_puts(MSG_OK);
 
1304
    return rc;
 
1305
}                               /* sendMailCurrent */