distout and ready_msg return NOTOK on error
[mmh] / uip / distsbr.c
1 /*
2 ** distsbr.c -- routines to do additional "dist-style" processing
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/mh.h>
10 #include <fcntl.h>
11 #include <h/utils.h>
12
13 static int  hdrfd = NOTOK;
14 static int  txtfd = NOTOK;
15
16 /*
17 ** static prototypes
18 */
19 static int ready_msg(char *);
20
21 int
22 distout(char *drft, char *msgnam, char *backup)
23 {
24         int state;
25         register unsigned char *dp;
26         register char *resent;
27         char name[NAMESZ], buffer[BUFSIZ];
28         register FILE *ifp, *ofp;
29
30         strcpy(backup, m_mktemp(toabsdir(invo_name), NULL, NULL));
31         if (rename(drft, backup) == NOTOK) {
32                 advise(backup, "unable to rename %s to",drft);
33                 return NOTOK;
34         }
35         if (!(ifp = fopen(backup, "r"))) {
36                 advise(backup, "unable to read");
37                 return NOTOK;
38         }
39
40         if (!(ofp = fopen(drft, "w"))) {
41                 advise(drft, "unable to create temporary file");
42                 return NOTOK;
43         }
44         chmod(drft, m_gmprot());
45
46         if (ready_msg(msgnam) != OK) {
47                 return NOTOK;
48         }
49         lseek(hdrfd, (off_t) 0, SEEK_SET); /* msgnam not accurate */
50         cpydata(hdrfd, fileno(ofp), msgnam, drft);
51
52         state = FLD;
53         resent = NULL;
54         while (1) {
55                 switch (state = m_getfld(state, name, buffer, sizeof buffer,
56                                 ifp)) {
57                 case FLD:
58                 case FLDPLUS:
59                 case FLDEOF:
60                         if (!uprf(name, "resent")) {
61                                 advise(NULL, "Please re-edit draft to remove the ``%s'' header.", name);
62                                 goto leave_bad;
63                         }
64                         if (state == FLD) {
65                                 resent = add(":", add(name, resent));
66                         }
67                         resent = add(buffer, resent);
68                         fprintf(ofp, "%s: %s", name, buffer);
69                         while (state == FLDPLUS) {
70                                 state = m_getfld(state, name, buffer,
71                                                 sizeof buffer, ifp);
72                                 resent = add(buffer, resent);
73                                 fputs(buffer, ofp);
74                         }
75                         if (state == FLDEOF) {
76                                 goto process;
77                         }
78                         break;
79
80                 case BODY:
81                 case BODYEOF:
82                         for (dp = buffer; *dp; dp++) {
83                                 if (!isspace(*dp)) {
84                                         advise(NULL, "Please re-edit draft to consist of headers only.");
85                                         goto leave_bad;
86                                 }
87                         }
88
89                 case FILEEOF:
90                         goto process;
91
92                 case LENERR:
93                 case FMTERR:
94                         advise(NULL, "Please re-edit draft and fix that header.");
95 leave_bad: ;
96                         fclose(ifp);
97                         fclose(ofp);
98                         unlink(drft);
99                         if (rename(backup, drft) == NOTOK) {
100                                 advise(drft, "unable to rename %s to", backup);
101                         }
102                         return NOTOK;
103
104                 default:
105                         advise(NULL, "getfld() returned %d", state);
106                         return NOTOK;
107                 }
108         }
109
110 process: ;
111         fclose(ifp);
112         fflush(ofp);
113
114         if (!resent) {
115                 advise(NULL, "Please re-edit draft to include a ``Resent-To:'' header.");
116                 fclose(ofp);
117                 unlink(drft);
118                 if (rename(backup, drft) == NOTOK) {
119                         advise(drft, "unable to rename %s to", backup);
120                 }
121                 return NOTOK;
122         }
123         free(resent);
124
125         if (txtfd != NOTOK) {
126                 lseek(txtfd, (off_t) 0, SEEK_SET);  /* msgnam not accurate */
127                 cpydata(txtfd, fileno(ofp), msgnam, drft);
128         }
129
130         fclose(ofp);
131
132         return OK;
133 }
134
135
136 static int
137 ready_msg(char *msgnam)
138 {
139         int state, out;
140         char name[NAMESZ], buffer[BUFSIZ], tmpfil[BUFSIZ];
141         register FILE *ifp, *ofp;
142         char *cp = NULL;
143
144         if (hdrfd != NOTOK) {
145                 close(hdrfd);
146                 hdrfd = NOTOK;
147         }
148         if (txtfd != NOTOK) {
149                 close(txtfd);
150                 txtfd = NOTOK;
151         }
152         if (!(ifp = fopen(msgnam, "r"))) {
153                 advise(msgnam, "unable to open message");
154                 return NOTOK;
155         }
156
157         cp = m_mktemp2(NULL, "dist", &hdrfd, NULL);
158         if (!cp) {
159                 advise("distsbr", "unable to create temporary file");
160                 return NOTOK;
161         }
162         fchmod(hdrfd, 0600);
163         strncpy(tmpfil, cp, sizeof(tmpfil));
164         if ((out = dup(hdrfd)) == NOTOK || !(ofp = fdopen(out, "w"))) {
165                 advise(NULL, "no file descriptors -- you lose big");
166                 return NOTOK;
167         }
168         unlink(tmpfil);
169
170         state = FLD;
171         while (1) {
172                 state = m_getfld(state, name, buffer, sizeof buffer, ifp);
173                 switch (state) {
174                 case FLD:
175                 case FLDPLUS:
176                 case FLDEOF:
177                         if (uprf(name, "resent")) {
178                                 fprintf(ofp, "Prev-");
179                         }
180                         fprintf(ofp, "%s: %s", name, buffer);
181                         while (state == FLDPLUS) {
182                                 state = m_getfld(state, name, buffer,
183                                                 sizeof buffer, ifp);
184                                 fputs(buffer, ofp);
185                         }
186                         if (state == FLDEOF) {
187                                 goto process;
188                         }
189                         break;
190
191                 case BODY:
192                 case BODYEOF:
193                         fclose(ofp);
194
195                         cp = m_mktemp2(NULL, "dist", &txtfd, NULL);
196                         if (!cp) {
197                                 advise("distsbr", "unable to create temp file");
198                                 return NOTOK;
199                         }
200                         fchmod(txtfd, 0600);
201                         strncpy(tmpfil, cp, sizeof(tmpfil));
202                         if ((out = dup(txtfd)) == NOTOK ||
203                                         !(ofp = fdopen(out, "w"))) {
204                                 advise(NULL, "no file descriptors -- you lose");
205                                 return NOTOK;
206                         }
207                         unlink(tmpfil);
208                         fprintf(ofp, "\n%s", buffer);
209                         while (state == BODY) {
210                                 state = m_getfld(state, name, buffer,
211                                                 sizeof buffer, ifp);
212                                 fputs(buffer, ofp);
213                         }
214                 case FILEEOF:
215                         goto process;
216
217                 case LENERR:
218                 case FMTERR:
219                         advise(NULL, "format error in message %s", msgnam);
220                         return NOTOK;
221
222                 default:
223                         advise(NULL, "getfld() returned %d", state);
224                         return NOTOK;
225                 }
226         }
227 process: ;
228         fclose(ifp);
229         fclose(ofp);
230         return OK;
231 }