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