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