Replaced mkinstalldirs with `mkdir -p'.
[mmh] / uip / dropsbr.c
1 /*
2 ** dropsbr.c -- create/read/manipulate mail drops
3 **
4 ** This code is Copyright (c) 2002, by the authors of nmh.  See the
5 ** COPYRIGHT file in the root directory of the nmh distribution for
6 ** complete copyright information.
7 */
8
9 #include <h/nmh.h>
10 #include <h/utils.h>
11
12 #include <h/mh.h>
13 #include <h/dropsbr.h>
14 #include <h/tws.h>
15
16 #ifdef HAVE_ERRNO_H
17 # include <errno.h>
18 #endif
19
20 #include <fcntl.h>
21
22
23 /*
24 ** Main entry point to open/create and lock
25 ** a file or maildrop.
26 */
27 int
28 mbx_open(char *file, uid_t uid, gid_t gid, mode_t mode)
29 {
30         int j, count, fd;
31         struct stat st;
32
33         j = 0;
34
35         /* attempt to open and lock file */
36         for (count = 4; count > 0; count--) {
37                 if ((fd = lkopen(file, O_RDWR | O_CREAT | O_NONBLOCK, mode))
38                                 == NOTOK) {
39                         switch (errno) {
40 #if defined(FCNTL_LOCKING) || defined(LOCKF_LOCKING)
41                         case EACCES:
42                         case EAGAIN:
43 #endif
44
45 #ifdef FLOCK_LOCKING
46                         case EWOULDBLOCK:
47 #endif
48                         case ETXTBSY:
49                                 j = errno;
50                                 sleep(5);
51                                 break;
52
53                         default:
54                                 /* just return error */
55                                 return NOTOK;
56                         }
57                 }
58
59                 /* good file descriptor */
60                 break;
61         }
62
63         errno = j;
64
65         /*
66         ** Return if we still failed after 4 attempts,
67         ** or we just want to skip the sanity checks.
68         */
69         if (fd == NOTOK)
70                 return fd;
71
72         /* Do sanity checks on maildrop. */
73         if (fstat(fd, &st) == NOTOK) {
74                 /*
75                 ** The stat failed.  So we make sure file
76                 ** has right ownership/modes
77                 */
78                 chown(file, uid, gid);
79                 chmod(file, mode);
80         } else if (st.st_size > (off_t) 0) {
81                 int status;
82
83                 /* Check/prepare MBOX style maildrop for appending. */
84                 if (lseek(fd, (off_t) 0, SEEK_END) == (off_t) NOTOK) {
85                         status = NOTOK;
86                 } else {
87                         status = OK;
88                 }
89
90                 /* if error, attempt to close it */
91                 if (status == NOTOK) {
92                         close(fd);
93                         return NOTOK;
94                 }
95         }
96
97         return fd;
98 }
99
100
101
102 /*
103 ** Append message to end of file or maildrop.
104 */
105 int
106 mbx_copy(char *mailbox, int md, int fd, int noisy)
107 {
108         int i, j;
109         off_t start, stop;
110         long pos;
111         char buffer[BUFSIZ];
112         FILE *fp;
113
114         pos = (long) lseek(md, (off_t) 0, SEEK_CUR);
115
116         if ((j = dup(fd)) == NOTOK)
117                 return NOTOK;
118         if ((fp = fdopen(j, "r")) == NULL) {
119                 close(j);
120                 return NOTOK;
121         }
122         start = lseek(md, (off_t) 0, SEEK_CUR);
123
124         for (j = 0; fgets(buffer, sizeof(buffer), fp) != NULL; j++) {
125                 /*
126                 ** Check the first line, and make some changes.
127                 */
128                 if (j == 0) {
129                         /*
130                         ** Change the "Return-Path:" field
131                         ** (if in first line) back to "From ".
132                         */
133                         if (strncmp(buffer, "Return-Path:", 12)==0) {
134                                 char tmpbuffer[BUFSIZ];
135                                 char *tp, *ep, *fp;
136
137                                 strncpy(tmpbuffer, buffer, sizeof(tmpbuffer));
138                                 ep = tmpbuffer + 13;
139                                 if (!(fp = strchr(ep + 1, ' ')))
140                                         fp = strchr(ep + 1, '\n');
141                                 tp = dctime(dlocaltimenow());
142                                         snprintf(buffer, sizeof(buffer),
143                                                         "From %.*s  %s",
144                                                         (int)(fp-ep), ep, tp);
145                         } else if (strncmp(buffer, "X-Envelope-From:",
146                                         16)==0) {
147                                 /*
148                                 ** Change the "X-Envelope-From:" field
149                                 ** (if first line) back to "From ".
150                                 */
151                                 char tmpbuffer[BUFSIZ];
152                                 char *ep;
153
154                                 strncpy(tmpbuffer, buffer, sizeof(tmpbuffer));
155                                 ep = tmpbuffer + 17;
156                                 snprintf(buffer, sizeof(buffer), "From %s",
157                                                 ep);
158                         } else if (strncmp(buffer, "From ", 5)!=0) {
159                                 /*
160                                 ** If there is already a "From " line,
161                                 ** then leave it alone.  Else we add one.
162                                 */
163                                 char tmpbuffer[BUFSIZ];
164                                 char *tp, *ep;
165
166                                 strncpy(tmpbuffer, buffer, sizeof(tmpbuffer));
167                                 ep = "nobody@nowhere";
168                                 tp = dctime(dlocaltimenow());
169                                 snprintf(buffer, sizeof(buffer),
170                                                 "From %s  %s%s", ep, tp,
171                                                 tmpbuffer);
172                         }
173                 }
174
175                 /*
176                 ** If this is not first line, and begins with "From ",
177                 ** then prepend line with ">".
178                 */
179                 if (j != 0 && strncmp(buffer, "From ", 5) == 0) {
180                         write(md, ">", 1);
181                 }
182                 i = strlen(buffer);
183                 if (write(md, buffer, i) != i) {
184                         fclose(fp);
185                         return NOTOK;
186                 }
187         }
188
189         if (write(md, "\n", 1) != 1) {
190                 fclose(fp);
191                 return NOTOK;
192         }
193         fclose(fp);
194         lseek(fd, (off_t) 0, SEEK_END);
195         stop = lseek(md, (off_t) 0, SEEK_CUR);
196
197         return OK;
198 }
199
200
201 /*
202 ** Close and unlock file/maildrop.
203 */
204 int
205 mbx_close(char *mailbox, int md)
206 {
207         if (lkclose(md, mailbox) == 0)
208                 return OK;
209         return NOTOK;
210 }