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