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