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