]>
Commit | Line | Data |
---|---|---|
fd1de51a SS |
1 | #include <err.h> |
2 | #include <errno.h> | |
3 | #include <fcntl.h> | |
4 | #include <paths.h> | |
5 | #include <stdint.h> | |
6 | #include <stdio.h> | |
7 | #include <syslog.h> | |
8 | #include <unistd.h> | |
9 | ||
10 | #include "dma.h" | |
11 | ||
12 | int | |
249ee966 | 13 | deliver_local(struct qitem *it) |
fd1de51a SS |
14 | { |
15 | char fn[PATH_MAX+1]; | |
16 | char line[1000]; | |
5a96b98a SS |
17 | const char *sender; |
18 | const char *newline = "\n"; | |
fd1de51a SS |
19 | size_t linelen; |
20 | int mbox; | |
21 | int error; | |
5a96b98a | 22 | int hadnl = 0; |
fd1de51a SS |
23 | off_t mboxlen; |
24 | time_t now = time(NULL); | |
25 | ||
26 | error = snprintf(fn, sizeof(fn), "%s/%s", _PATH_MAILDIR, it->addr); | |
27 | if (error < 0 || (size_t)error >= sizeof(fn)) { | |
4d5af2b0 | 28 | syslog(LOG_NOTICE, "local delivery deferred: %m"); |
fd1de51a SS |
29 | return (1); |
30 | } | |
31 | ||
f54b5114 SS |
32 | /* wait for a maximum of 100s to get the lock to the file */ |
33 | do_timeout(100, 0); | |
34 | ||
fd1de51a | 35 | /* mailx removes users mailspool file if empty, so open with O_CREAT */ |
f54b5114 | 36 | mbox = open_locked(fn, O_WRONLY|O_APPEND|O_CREAT, 0660); |
fd1de51a | 37 | if (mbox < 0) { |
f54b5114 SS |
38 | int e = errno; |
39 | ||
40 | do_timeout(0, 0); | |
41 | if (e == EINTR) | |
42 | syslog(LOG_NOTICE, "local delivery deferred: can not lock `%s'", fn); | |
43 | else | |
44 | syslog(LOG_NOTICE, "local delivery deferred: can not open `%s': %m", fn); | |
fd1de51a SS |
45 | return (1); |
46 | } | |
f54b5114 SS |
47 | do_timeout(0, 0); |
48 | ||
5a96b98a SS |
49 | mboxlen = lseek(mbox, 0, SEEK_END); |
50 | ||
51 | /* New mails start with \nFrom ...., unless we're at the beginning of the mbox */ | |
52 | if (mboxlen == 0) | |
53 | newline = ""; | |
54 | ||
55 | /* If we're bouncing a message, claim it comes from MAILER-DAEMON */ | |
56 | sender = it->sender; | |
57 | if (strcmp(sender, "") == 0) | |
58 | sender = "MAILER-DAEMON"; | |
fd1de51a | 59 | |
6ddd63e1 | 60 | if (fseek(it->mailf, 0, SEEK_SET) != 0) { |
4d5af2b0 | 61 | syslog(LOG_NOTICE, "local delivery deferred: can not seek: %m"); |
f54b5114 | 62 | goto out; |
fd1de51a SS |
63 | } |
64 | ||
5a96b98a | 65 | error = snprintf(line, sizeof(line), "%sFrom %s\t%s", newline, sender, ctime(&now)); |
fd1de51a | 66 | if (error < 0 || (size_t)error >= sizeof(line)) { |
4d5af2b0 | 67 | syslog(LOG_NOTICE, "local delivery deferred: can not write header: %m"); |
f54b5114 | 68 | goto out; |
fd1de51a SS |
69 | } |
70 | if (write(mbox, line, error) != error) | |
71 | goto wrerror; | |
72 | ||
73 | while (!feof(it->mailf)) { | |
74 | if (fgets(line, sizeof(line), it->mailf) == NULL) | |
75 | break; | |
76 | linelen = strlen(line); | |
77 | if (linelen == 0 || line[linelen - 1] != '\n') { | |
4d5af2b0 | 78 | syslog(LOG_CRIT, "local delivery failed: corrupted queue file"); |
249ee966 | 79 | snprintf(errmsg, sizeof(errmsg), "corrupted queue file"); |
fd1de51a SS |
80 | error = -1; |
81 | goto chop; | |
82 | } | |
83 | ||
5a96b98a | 84 | if (hadnl && strncmp(line, "From ", 5) == 0) { |
fd1de51a SS |
85 | const char *gt = ">"; |
86 | ||
87 | if (write(mbox, gt, 1) != 1) | |
88 | goto wrerror; | |
5a96b98a SS |
89 | hadnl = 0; |
90 | } else if (strcmp(line, "\n") == 0) { | |
91 | hadnl = 1; | |
92 | } else { | |
93 | hadnl = 0; | |
fd1de51a SS |
94 | } |
95 | if ((size_t)write(mbox, line, linelen) != linelen) | |
96 | goto wrerror; | |
97 | } | |
fd1de51a SS |
98 | close(mbox); |
99 | return (0); | |
100 | ||
101 | wrerror: | |
4d5af2b0 | 102 | syslog(LOG_ERR, "local delivery failed: write error: %m"); |
fd1de51a SS |
103 | error = 1; |
104 | chop: | |
105 | if (ftruncate(mbox, mboxlen) != 0) | |
4d5af2b0 | 106 | syslog(LOG_WARNING, "error recovering mbox `%s': %m", fn); |
f54b5114 | 107 | out: |
fd1de51a SS |
108 | close(mbox); |
109 | return (error); | |
110 | } |