]>
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 | |
13 | deliver_local(struct qitem *it, const char **errmsg) | |
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 | ||
32 | /* mailx removes users mailspool file if empty, so open with O_CREAT */ | |
5445c73b | 33 | mbox = open_locked(fn, O_WRONLY|O_APPEND|O_NONBLOCK|O_CREAT, 0660); |
fd1de51a | 34 | if (mbox < 0) { |
4d5af2b0 | 35 | syslog(LOG_NOTICE, "local delivery deferred: can not open `%s': %m", fn); |
fd1de51a SS |
36 | return (1); |
37 | } | |
5a96b98a SS |
38 | mboxlen = lseek(mbox, 0, SEEK_END); |
39 | ||
40 | /* New mails start with \nFrom ...., unless we're at the beginning of the mbox */ | |
41 | if (mboxlen == 0) | |
42 | newline = ""; | |
43 | ||
44 | /* If we're bouncing a message, claim it comes from MAILER-DAEMON */ | |
45 | sender = it->sender; | |
46 | if (strcmp(sender, "") == 0) | |
47 | sender = "MAILER-DAEMON"; | |
fd1de51a | 48 | |
6ddd63e1 | 49 | if (fseek(it->mailf, 0, SEEK_SET) != 0) { |
4d5af2b0 | 50 | syslog(LOG_NOTICE, "local delivery deferred: can not seek: %m"); |
fd1de51a SS |
51 | return (1); |
52 | } | |
53 | ||
5a96b98a | 54 | error = snprintf(line, sizeof(line), "%sFrom %s\t%s", newline, sender, ctime(&now)); |
fd1de51a | 55 | if (error < 0 || (size_t)error >= sizeof(line)) { |
4d5af2b0 | 56 | syslog(LOG_NOTICE, "local delivery deferred: can not write header: %m"); |
fd1de51a SS |
57 | return (1); |
58 | } | |
59 | if (write(mbox, line, error) != error) | |
60 | goto wrerror; | |
61 | ||
62 | while (!feof(it->mailf)) { | |
63 | if (fgets(line, sizeof(line), it->mailf) == NULL) | |
64 | break; | |
65 | linelen = strlen(line); | |
66 | if (linelen == 0 || line[linelen - 1] != '\n') { | |
4d5af2b0 | 67 | syslog(LOG_CRIT, "local delivery failed: corrupted queue file"); |
fd1de51a SS |
68 | *errmsg = "corrupted queue file"; |
69 | error = -1; | |
70 | goto chop; | |
71 | } | |
72 | ||
5a96b98a | 73 | if (hadnl && strncmp(line, "From ", 5) == 0) { |
fd1de51a SS |
74 | const char *gt = ">"; |
75 | ||
76 | if (write(mbox, gt, 1) != 1) | |
77 | goto wrerror; | |
5a96b98a SS |
78 | hadnl = 0; |
79 | } else if (strcmp(line, "\n") == 0) { | |
80 | hadnl = 1; | |
81 | } else { | |
82 | hadnl = 0; | |
fd1de51a SS |
83 | } |
84 | if ((size_t)write(mbox, line, linelen) != linelen) | |
85 | goto wrerror; | |
86 | } | |
fd1de51a SS |
87 | close(mbox); |
88 | return (0); | |
89 | ||
90 | wrerror: | |
4d5af2b0 | 91 | syslog(LOG_ERR, "local delivery failed: write error: %m"); |
fd1de51a SS |
92 | error = 1; |
93 | chop: | |
94 | if (ftruncate(mbox, mboxlen) != 0) | |
4d5af2b0 | 95 | syslog(LOG_WARNING, "error recovering mbox `%s': %m", fn); |
fd1de51a SS |
96 | close(mbox); |
97 | return (error); | |
98 | } |