]> diplodocus.org Git - nmh/blob - uip/viamail.c
Apply David Levine's fix from whomfile() to sendfile() as well.
[nmh] / uip / viamail.c
1
2 /*
3 * viamail.c -- send multiple files in a MIME message
4 *
5 * This code is Copyright (c) 2002, by the authors of nmh. See the
6 * COPYRIGHT file in the root directory of the nmh distribution for
7 * complete copyright information.
8 */
9
10 #include <h/mh.h>
11 #include <fcntl.h>
12 #include <h/signals.h>
13 #include <h/md5.h>
14 #include <errno.h>
15 #include <signal.h>
16 #include <h/mts.h>
17 #include <h/tws.h>
18 #include <h/mime.h>
19 #include <h/mhparse.h>
20
21 #define VIAMAIL_SWITCHES \
22 X("to mailpath", 0, TOSW) \
23 X("from mailpath", 0, FROMSW) \
24 X("subject subject", 0, SUBJECTSW) \
25 X("parameters arguments", 0, PARAMSW) \
26 X("description text", 0, DESCRIPTSW) \
27 X("comment text", 0, COMMENTSW) \
28 X("delay seconds", 0, DELAYSW) \
29 X("verbose", 0, VERBSW) \
30 X("noverbose", 0, NVERBSW) \
31 X("version", 0, VERSIONSW) \
32 X("help", 0, HELPSW) \
33 X("debug", -5, DEBUGSW) \
34
35 #define X(sw, minchars, id) id,
36 DEFINE_SWITCH_ENUM(VIAMAIL);
37 #undef X
38
39 #define X(sw, minchars, id) { sw, minchars, id },
40 DEFINE_SWITCH_ARRAY(VIAMAIL, switches);
41 #undef X
42
43 extern int debugsw;
44 extern int splitsw;
45 extern int verbsw;
46
47 /*
48 * static prototypes
49 */
50 static int via_mail (char *, char *, char *, char *, char *, int, char *);
51
52
53 int
54 main (int argc, char **argv)
55 {
56 int delay = 0;
57 char *f1 = NULL, *f2 = NULL, *f3 = NULL;
58 char *f4 = NULL, *f5 = NULL, *f7 = NULL;
59 static char postpath[PATH_MAX];
60 char *cp, buf[BUFSIZ];
61 char **argp, **arguments;
62
63 #ifdef LOCALE
64 setlocale(LC_ALL, "");
65 #endif
66 invo_name = r1bindex (argv[0], '/');
67
68 /* foil search of user profile/context */
69 if (context_foil (NULL) == -1)
70 done (1);
71
72 arguments = getarguments (invo_name, argc, argv, 0);
73 argp = arguments;
74
75 while ((cp = *argp++)) {
76 if (*cp == '-') {
77 switch (smatch (++cp, switches)) {
78 case AMBIGSW:
79 ambigsw (cp, switches);
80 done (1);
81 case UNKWNSW:
82 adios (NULL, "-%s unknown", cp);
83
84 case HELPSW:
85 snprintf (buf, sizeof(buf), "%s [switches]", invo_name);
86 print_help (buf, switches, 1);
87 done (0);
88 case VERSIONSW:
89 print_version(invo_name);
90 done (0);
91
92 case TOSW:
93 if (!(f1 = *argp++))
94 adios (NULL, "missing argument to %s", argp[-2]);
95 continue;
96 case SUBJECTSW:
97 if (!(f2 = *argp++))
98 adios (NULL, "missing argument to %s", argp[-2]);
99 continue;
100 case PARAMSW:
101 if (!(f3 = *argp++))
102 adios (NULL, "missing argument to %s", argp[-2]);
103 continue;
104 case DESCRIPTSW:
105 if (!(f4 = *argp++))
106 adios (NULL, "missing argument to %s", argp[-2]);
107 continue;
108 case COMMENTSW:
109 if (!(f5 = *argp++))
110 adios (NULL, "missing argument to %s", argp[-2]);
111 continue;
112 case DELAYSW:
113 if (!(cp = *argp++) || *cp == '-')
114 adios (NULL, "missing argument to %s", argp[-2]);
115
116 /*
117 * If there is an error, just reset the delay parameter
118 * to -1. We will set a default delay later.
119 */
120 if (sscanf (cp, "%d", &delay) != 1)
121 delay = -1;
122 continue;
123 case FROMSW:
124 if (!(f7 = *argp++))
125 adios (NULL, "missing argument to %s", argp[-2]);
126 continue;
127
128 case VERBSW:
129 verbsw = 1;
130 continue;
131 case NVERBSW:
132 verbsw = 0;
133 continue;
134
135 case DEBUGSW:
136 debugsw = 1;
137 continue;
138 }
139 }
140 }
141
142 if (!f1)
143 adios (NULL, "missing -viamail \"mailpath\" switch");
144
145 /* viamail doesn't read the context and postproc isn't always what
146 we want, such as when running make distcheck. If we have the
147 absolute path, set postproc to point to post in the same
148 directory as this executable.
149 This could be generalized to handle relative paths (by
150 converting to absolute), to find the full path from PATH given
151 just the basename, and to squash out ../ but it's only needed
152 here. viamail is typically called from sendfiles, which
153 provides the absolute path.
154 */
155 if (argv[0] && argv[0][0] == '/' &&
156 strlen(argv[0]) - 3 < sizeof postpath) {
157 strncpy (postpath, argv[0], sizeof postpath - 1);
158 postpath[sizeof postpath - 1] = '\0';
159 if ((cp = strrchr (postpath, '/'))) {
160 struct stat st;
161
162 *(cp + 1) = '\0';
163 /* strlen ("post") <= sizeof postpath - (cp - postpath) - 2
164 but use strncat just in case the code above changes. */
165 strncat (postpath, "post", sizeof postpath - (cp - postpath) - 2);
166
167 if (stat (postpath, &st) == OK) {
168 postproc = postpath;
169 }
170 }
171 }
172
173 via_mail (f1, f2, f3, f4, f5, delay, f7);
174 return 0; /* dead code to satisfy the compiler */
175 }
176
177
178 /*
179 * VIAMAIL
180 */
181
182 static int
183 via_mail (char *mailsw, char *subjsw, char *parmsw, char *descsw,
184 char *cmntsw, int delay, char *fromsw)
185 {
186 int status, vecp;
187 char tmpfil[BUFSIZ], *program;
188 char **vec;
189 struct stat st;
190 FILE *fp;
191 char *tfile = NULL;
192
193 umask (~m_gmprot ());
194
195 tfile = m_mktemp2(NULL, invo_name, NULL, &fp);
196 if (tfile == NULL) adios("viamail", "unable to create temporary file");
197 chmod(tfile, 0600);
198 strncpy (tmpfil, tfile, sizeof(tmpfil));
199
200 if (!strchr(mailsw, '@'))
201 mailsw = concat (mailsw, "@", LocalName (0), NULL);
202 fprintf (fp, "To: %s\n", mailsw);
203
204 if (subjsw)
205 fprintf (fp, "Subject: %s\n", subjsw);
206
207 if (fromsw) {
208 if (!strchr(fromsw, '@'))
209 fromsw = concat (fromsw, "@", LocalName (0), NULL);
210 fprintf (fp, "From: %s\n", fromsw);
211 }
212
213 fprintf (fp, "%s: %s\n", VRSN_FIELD, VRSN_VALUE);
214 fprintf (fp, "%s: application/octet-stream", TYPE_FIELD);
215
216 if (parmsw)
217 fprintf (fp, "; %s", parmsw);
218
219 if (cmntsw)
220 fprintf (fp, "\n\t(%s)", cmntsw);
221
222 if (descsw)
223 fprintf (fp, "\n%s: %s", DESCR_FIELD, descsw);
224
225 fprintf (fp, "\n%s: %s\n\n", ENCODING_FIELD, "base64");
226
227 if (fflush (fp))
228 adios (tmpfil, "error writing to");
229
230 writeBase64aux (stdin, fp);
231 if (fflush (fp))
232 adios (tmpfil, "error writing to");
233
234 if (fstat (fileno (fp), &st) == NOTOK)
235 adios ("failed", "fstat of %s", tmpfil);
236
237 if (delay < 0)
238 splitsw = 10;
239 else
240 splitsw = delay;
241
242 status = 0;
243
244 vec = argsplit(postproc, &program, &vecp);
245 if (verbsw)
246 vec[vecp++] = "-verbose";
247
248 switch (sendsbr (vec, vecp, program, tmpfil, &st, 0, (char *)0, 0)) {
249 case DONE:
250 case NOTOK:
251 status++;
252 break;
253 case OK:
254 break;
255 }
256
257 fclose (fp);
258 if (unlink (tmpfil) == -1)
259 advise (NULL, "unable to remove temp file %s", tmpfil);
260 done (status);
261 return 1;
262 }