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