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