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