]> diplodocus.org Git - nmh/blob - uip/dropsbr.c
Makefile.am: Add test/inc/test-eom-align to XFAIL_TESTS.
[nmh] / uip / dropsbr.c
1 /* dropsbr.c -- create/read/manipulate mail drops
2 *
3 * This code is Copyright (c) 2002, by the authors of nmh. See the
4 * COPYRIGHT file in the root directory of the nmh distribution for
5 * complete copyright information.
6 */
7
8 #include <h/nmh.h>
9 #include <h/utils.h>
10
11 #include <h/mh.h>
12 #include <h/dropsbr.h>
13 #include <h/mts.h>
14 #include <h/tws.h>
15 #include "../sbr/lock_file.h"
16 #include "../sbr/m_mktemp.h"
17
18 #ifdef NTOHLSWAP
19 # include <netinet/in.h>
20 #else
21 # undef ntohl
22 # define ntohl(n) (n)
23 #endif
24
25 #include <fcntl.h>
26
27 /*
28 * static prototypes
29 */
30 static int mbx_chk_mbox (int);
31 static int mbx_chk_mmdf (int);
32
33
34 /*
35 * Main entry point to open/create and lock
36 * a file or maildrop.
37 */
38
39 int
40 mbx_open (char *file, int mbx_style, uid_t uid, gid_t gid, mode_t mode)
41 {
42 int j, count, fd = NOTOK;
43 struct stat st;
44
45 j = 0;
46
47 /* attempt to open and lock file */
48 for (count = 4; count > 0; count--) {
49 int failed_to_lock = 0;
50
51 if ((fd = lkopenspool (file, O_RDWR | O_CREAT | O_NONBLOCK,
52 mode, &failed_to_lock)) != NOTOK)
53 break;
54
55 if (!failed_to_lock)
56 return NOTOK;
57
58 j = errno;
59 sleep (5);
60 }
61
62 errno = j;
63
64 /*
65 * Return if we still failed after 4 attempts,
66 * or we just want to skip the sanity checks.
67 */
68 if (fd == NOTOK || mbx_style == OTHER_FORMAT)
69 return fd;
70
71 /*
72 * Do sanity checks on maildrop.
73 */
74 if (fstat (fd, &st) == NOTOK) {
75 /*
76 * The stat failed. So we make sure file
77 * has right ownership/modes
78 */
79 if (chown (file, uid, gid) < 0) {
80 advise (file, "chown");
81 }
82 if (chmod (file, mode) < 0) {
83 advise (file, "chmod");
84 }
85 } else if (st.st_size > 0) {
86 int status;
87
88 /* check the maildrop */
89 switch (mbx_style) {
90 case MMDF_FORMAT:
91 default:
92 status = mbx_chk_mmdf (fd);
93 break;
94
95 case MBOX_FORMAT:
96 status = mbx_chk_mbox (fd);
97 break;
98 }
99
100 /* if error, attempt to close it */
101 if (status == NOTOK) {
102 close (fd);
103 return NOTOK;
104 }
105 }
106
107 return fd;
108 }
109
110
111 /*
112 * Check/prepare MBOX style maildrop for appending.
113 */
114
115 static int
116 mbx_chk_mbox (int fd)
117 {
118 /* just seek to the end */
119 if (lseek(fd, 0, SEEK_END) == (off_t) NOTOK)
120 return NOTOK;
121
122 return OK;
123 }
124
125
126 /*
127 * Check/prepare MMDF style maildrop for appending.
128 */
129
130 static int
131 mbx_chk_mmdf (int fd)
132 {
133 ssize_t count;
134 char ldelim[BUFSIZ];
135
136 count = strlen (mmdlm2);
137
138 if (lseek (fd, -count, SEEK_END) == (off_t) NOTOK)
139 return NOTOK;
140 if (read (fd, ldelim, count) != count)
141 return NOTOK;
142
143 ldelim[count] = 0;
144
145 if (strcmp (ldelim, mmdlm2)
146 && write (fd, "\n", 1) != 1
147 && write (fd, mmdlm2, count) != count)
148 return NOTOK;
149
150 return OK;
151 }
152
153
154 /*
155 * Append message to end of file or maildrop.
156 */
157
158 int
159 mbx_copy (char *mailbox, int mbx_style, int md, int fd,
160 char *text)
161 {
162 int i, j, size;
163 char *cp, buffer[BUFSIZ + 1]; /* Space for NUL. */
164 FILE *fp;
165
166 size = 0;
167
168 switch (mbx_style) {
169 case MMDF_FORMAT:
170 default:
171 j = strlen (mmdlm1);
172 if (write (md, mmdlm1, j) != j)
173 return NOTOK;
174
175 if (text) {
176 i = strlen (text);
177 if (write (md, text, i) != i)
178 return NOTOK;
179 for (cp = text; *cp++; size++)
180 if (*cp == '\n')
181 size++;
182 }
183
184 while ((i = read (fd, buffer, sizeof buffer - 1)) > 0) {
185 buffer[i] = '\0'; /* Terminate for stringdex(). */
186
187 for ( ; (j = stringdex (mmdlm1, buffer)) >= 0; buffer[j]++)
188 continue;
189 for ( ; (j = stringdex (mmdlm2, buffer)) >= 0; buffer[j]++)
190 continue;
191 if (write (md, buffer, i) != i)
192 return NOTOK;
193 }
194
195 j = strlen (mmdlm2);
196 if (write (md, mmdlm2, j) != j)
197 return NOTOK;
198
199 return (i != NOTOK ? OK : NOTOK);
200
201 case MBOX_FORMAT:
202 if ((j = dup (fd)) == NOTOK)
203 return NOTOK;
204 if ((fp = fdopen (j, "r")) == NULL) {
205 close (j);
206 return NOTOK;
207 }
208
209 /* If text is given, we add it to top of message */
210 if (text) {
211 i = strlen (text);
212 if (write (md, text, i) != i)
213 return NOTOK;
214 for (cp = text; *cp++; size++)
215 if (*cp == '\n')
216 size++;
217 }
218
219 for (j = 0; fgets (buffer, sizeof(buffer), fp) != NULL; j++) {
220
221 /*
222 * Check the first line, and make some changes.
223 */
224 if (j == 0 && !text) {
225 /*
226 * Change the "Return-Path:" field (if in first line)
227 * back to "From ".
228 */
229 if (has_prefix(buffer, "Return-Path:")) {
230 char tmpbuffer[sizeof buffer];
231 char *tp, *ep, *fp;
232
233 strncpy(tmpbuffer, buffer, sizeof(tmpbuffer));
234 ep = tmpbuffer + 13;
235 if (!(fp = strchr(ep + 1, ' ')))
236 fp = strchr(ep + 1, '\n');
237 tp = dctime(dlocaltimenow());
238 snprintf (buffer, sizeof(buffer), "From %.*s %s",
239 (int)(fp - ep), ep, tp);
240 } else if (has_prefix(buffer, "X-Envelope-From:")) {
241 /*
242 * Change the "X-Envelope-From:" field
243 * (if first line) back to "From ".
244 */
245 char tmpbuffer[sizeof buffer];
246 char *ep;
247
248 strncpy(tmpbuffer, buffer, sizeof(tmpbuffer));
249 ep = tmpbuffer + 17;
250 snprintf (buffer, sizeof(buffer), "From %s", ep);
251 } else if (!has_prefix(buffer, "From ")) {
252 /*
253 * If there is already a "From " line,
254 * then leave it alone. Else we add one.
255 */
256 char tmpbuffer[sizeof buffer];
257 char *tp, *ep;
258
259 strncpy(tmpbuffer, buffer, sizeof(tmpbuffer));
260 ep = "nobody@nowhere";
261 tp = dctime(dlocaltimenow());
262 snprintf (buffer, sizeof(buffer), "From %s %s%s", ep, tp, tmpbuffer);
263 }
264 }
265
266 /*
267 * If this is not first line, and begins with
268 * "From ", then prepend line with ">".
269 */
270 if (j != 0 && has_prefix(buffer, "From ")) {
271 if (write (md, ">", 1) < 0) {
272 advise (mailbox, "write");
273 }
274 size++;
275 }
276 i = strlen (buffer);
277 if (write (md, buffer, i) != i) {
278 fclose (fp);
279 return NOTOK;
280 }
281 }
282 if (write (md, "\n", 1) != 1) {
283 fclose (fp);
284 return NOTOK;
285 }
286
287 fclose (fp);
288 lseek(fd, 0, SEEK_END);
289
290 return OK;
291 }
292 }
293
294
295 /*
296 * Close and unlock file/maildrop.
297 */
298
299 int
300 mbx_close (char *mailbox, int md)
301 {
302 if (lkclosespool (md, mailbox) == 0)
303 return OK;
304 return NOTOK;
305 }