Rearranged whitespace (and comments) in all the code!
[mmh] / uip / send.c
1 /*
2  * send.c -- send a composed message
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 <errno.h>
12 #include <signal.h>
13
14
15 static struct swit switches[] = {
16 #define ALIASW  0
17         { "alias aliasfile", 0 },
18 #define DEBUGSW  1
19         { "debug", -5 },
20 #define DRAFTSW  2
21         { "draft", 0 },
22 #define DFOLDSW  3
23         { "draftfolder +folder", 6 },
24 #define DMSGSW  4
25         { "draftmessage msg", 6 },
26 #define NDFLDSW  5
27         { "nodraftfolder", 0 },
28 #define FILTSW  6
29         { "filter filterfile", 0 },
30 #define NFILTSW  7
31         { "nofilter", 0 },
32 #define FRMTSW  8
33         { "format", 0 },
34 #define NFRMTSW  9
35         { "noformat", 0 },
36 #define FORWSW  10
37         { "forward", 0 },
38 #define NFORWSW  11
39         { "noforward", 0 },
40 #define MIMESW  12
41         { "mime", 0 },
42 #define NMIMESW  13
43         { "nomime", 0 },
44 #define MSGDSW  14
45         { "msgid", 0 },
46 #define NMSGDSW  15
47         { "nomsgid", 0 },
48 #define PUSHSW  16
49         { "push", 0 },
50 #define NPUSHSW  17
51         { "nopush", 0 },
52 #define SPLITSW  18
53         { "split seconds", 0 },
54 #define UNIQSW  19
55         { "unique", -6 },
56 #define NUNIQSW  20
57         { "nounique", -8 },
58 #define VERBSW  21
59         { "verbose", 0 },
60 #define NVERBSW  22
61         { "noverbose", 0 },
62 #define WATCSW  23
63         { "watch", 0 },
64 #define NWATCSW  24
65         { "nowatch", 0 },
66 #define WIDTHSW  25
67         { "width columns", 0 },
68 #define VERSIONSW  26
69         { "version", 0 },
70 #define HELPSW  27
71         { "help", 0 },
72 #define BITSTUFFSW  28
73         { "dashstuffing", -12 },
74 #define NBITSTUFFSW  29
75         { "nodashstuffing", -14 },
76 #define MAILSW  30
77         { "mail", -4 },
78 #define SAMLSW  31
79         { "saml", -4 },
80 #define SENDSW  32
81         { "send", -4 },
82 #define SOMLSW  33
83         { "soml", -4 },
84 #define CLIESW  34
85         { "client host", -6 },
86 #define SERVSW  35
87         { "server host", 6 },
88 #define SNOOPSW  36
89         { "snoop", 5 },
90 #define ATTACHSW  40
91         { "attach", 6 },
92 #define ATTACHFORMATSW  41
93         { "attachformat", 7 },
94 #define PORTSW  42
95         { "port server-port-name/number" , 4 },
96         { NULL, 0 }
97 };
98
99 static struct swit anyl[] = {
100 #define NOSW  0
101         { "no", 0 },
102 #define YESW  1
103         { "yes", 0 },
104 #define LISTDSW  2
105         { "list", 0 },
106         { NULL, 0 }
107 };
108
109 extern int debugsw;  /* from sendsbr.c */
110 extern int forwsw;
111 extern int inplace;
112 extern int pushsw;
113 extern int splitsw;
114 extern int unique;
115 extern int verbsw;
116
117 extern char *altmsg;  /*  .. */
118 extern char *annotext;
119 extern char *distfile;
120
121
122 int
123 main (int argc, char **argv)
124 {
125         int msgp = 0, distsw = 0, vecp = 1;
126         int isdf = 0, mime = 0;
127         int msgnum, status;
128         char *cp, *dfolder = NULL, *maildir = NULL;
129         char buf[BUFSIZ], **ap, **argp, **arguments;
130         char *msgs[MAXARGS], *vec[MAXARGS];
131         struct msgs *mp;
132         struct stat st;
133         char *attach = (char *)0;  /* header field name for attachments */
134         int attachformat = 0; /* mhbuild format specifier for attachments */
135 #ifdef UCI
136         FILE *fp;
137 #endif /* UCI */
138
139 #ifdef LOCALE
140         setlocale(LC_ALL, "");
141 #endif
142         invo_name = r1bindex (argv[0], '/');
143
144         /* read user profile/context */
145         context_read();
146
147         arguments = getarguments (invo_name, argc, argv, 1);
148         argp = arguments;
149
150         vec[vecp++] = "-library";
151         vec[vecp++] = getcpy (m_maildir (""));
152
153         while ((cp = *argp++)) {
154                 if (*cp == '-') {
155                         switch (smatch (++cp, switches)) {
156                                 case AMBIGSW:
157                                         ambigsw (cp, switches);
158                                         done (1);
159                                 case UNKWNSW:
160                                         adios (NULL, "-%s unknown\n", cp);
161
162                                 case HELPSW:
163                                         snprintf (buf, sizeof(buf), "%s [file] [switches]", invo_name);
164                                         print_help (buf, switches, 1);
165                                         done (1);
166                                 case VERSIONSW:
167                                         print_version(invo_name);
168                                         done (1);
169
170                                 case DRAFTSW:
171                                         msgs[msgp++] = draft;
172                                         continue;
173
174                                 case DFOLDSW:
175                                         if (dfolder)
176                                                 adios (NULL, "only one draft folder at a time!");
177                                         if (!(cp = *argp++) || *cp == '-')
178                                                 adios (NULL, "missing argument to %s", argp[-2]);
179                                         dfolder = path (*cp == '+' || *cp == '@' ? cp + 1 : cp,
180                                                         *cp != '@' ? TFOLDER : TSUBCWF);
181                                         continue;
182                                 case DMSGSW:
183                                         if (!(cp = *argp++) || *cp == '-')
184                                                 adios (NULL, "missing argument to %s", argp[-2]);
185                                         msgs[msgp++] = cp;
186                                         continue;
187                                 case NDFLDSW:
188                                         dfolder = NULL;
189                                         isdf = NOTOK;
190                                         continue;
191
192                                 case PUSHSW:
193                                         pushsw++;
194                                         continue;
195                                 case NPUSHSW:
196                                         pushsw = 0;
197                                         continue;
198
199                                 case SPLITSW:
200                                         if (!(cp = *argp++) || sscanf (cp, "%d", &splitsw) != 1)
201                                                 adios (NULL, "missing argument to %s", argp[-2]);
202                                         continue;
203
204                                 case UNIQSW:
205                                         unique++;
206                                         continue;
207                                 case NUNIQSW:
208                                         unique = 0;
209                                         continue;
210
211                                 case FORWSW:
212                                         forwsw++;
213                                         continue;
214                                 case NFORWSW:
215                                         forwsw = 0;
216                                         continue;
217
218                                 case VERBSW:
219                                         verbsw++;
220                                         vec[vecp++] = --cp;
221                                         continue;
222                                 case NVERBSW:
223                                         verbsw = 0;
224                                         vec[vecp++] = --cp;
225                                         continue;
226
227                                 case MIMESW:
228                                         mime++;
229                                         vec[vecp++] = --cp;
230                                         continue;
231                                 case NMIMESW:
232                                         mime = 0;
233                                         vec[vecp++] = --cp;
234                                         continue;
235
236                                 case DEBUGSW:
237                                         debugsw++;  /* fall */
238                                 case NFILTSW:
239                                 case FRMTSW:
240                                 case NFRMTSW:
241                                 case BITSTUFFSW:
242                                 case NBITSTUFFSW:
243                                 case MSGDSW:
244                                 case NMSGDSW:
245                                 case WATCSW:
246                                 case NWATCSW:
247                                 case MAILSW:
248                                 case SAMLSW:
249                                 case SENDSW:
250                                 case SOMLSW:
251                                 case SNOOPSW:
252                                         vec[vecp++] = --cp;
253                                         continue;
254
255                                 case ALIASW:
256                                 case FILTSW:
257                                 case WIDTHSW:
258                                 case CLIESW:
259                                 case SERVSW:
260                                 case PORTSW:
261                                         vec[vecp++] = --cp;
262                                         if (!(cp = *argp++) || *cp == '-')
263                                                 adios (NULL, "missing argument to %s", argp[-2]);
264                                         vec[vecp++] = cp;
265                                         continue;
266
267                                 case ATTACHSW:
268                                         if (!(attach = *argp++) || *attach == '-')
269                                                 adios (NULL, "missing argument to %s", argp[-2]);
270                                         continue;
271
272                                 case ATTACHFORMATSW:
273                                         if (! *argp || **argp == '-')
274                                                 adios (NULL, "missing argument to %s", argp[-1]);
275                                         else {
276                                                 attachformat = atoi (*argp);
277                                                 if (attachformat < 0 ||
278                                                         attachformat > ATTACHFORMATS - 1) {
279                                                         advise (NULL, "unsupported attachformat %d",
280                                                                         attachformat);
281                                                         continue;
282                                                 }
283                                         }
284                                         ++argp;
285                                         continue;
286                         }
287                 } else {
288                         msgs[msgp++] = cp;
289                 }
290         }
291
292         /*
293          * check for "Aliasfile:" profile entry
294          */
295         if ((cp = context_find ("Aliasfile"))) {
296                 char *dp = NULL;
297
298                 for (ap = brkstring(dp = getcpy(cp), " ", "\n"); ap && *ap; ap++) {
299                         vec[vecp++] = "-alias";
300                         vec[vecp++] = *ap;
301                 }
302         }
303
304         if (dfolder == NULL) {
305                 if (msgp == 0) {
306 #ifdef WHATNOW
307                         if ((cp = getenv ("mhdraft")) && *cp) {
308                                 msgs[msgp++] = cp;
309                                 goto go_to_it;
310                         }
311 #endif /* WHATNOW */
312                         msgs[msgp++] = getcpy (m_draft (NULL, NULL, 1, &isdf));
313                         if (stat (msgs[0], &st) == NOTOK)
314                                 adios (msgs[0], "unable to stat draft file");
315                         cp = concat ("Use \"", msgs[0], "\"? ", NULL);
316                         for (status = LISTDSW; status != YESW;) {
317                                 if (!(argp = getans (cp, anyl)))
318                                         done (1);
319                                 switch (status = smatch (*argp, anyl)) {
320                                         case NOSW:
321                                                 done (0);
322                                         case YESW:
323                                                 break;
324                                         case LISTDSW:
325                                                 showfile (++argp, msgs[0]);
326                                                 break;
327                                         default:
328                                                 advise (NULL, "say what?");
329                                                 break;
330                                 }
331                         }
332                 } else {
333                         for (msgnum = 0; msgnum < msgp; msgnum++)
334                                 msgs[msgnum] = getcpy (m_maildir (msgs[msgnum]));
335                 }
336         } else {
337                 if (!context_find ("path"))
338                         free (path ("./", TFOLDER));
339
340                 if (!msgp)
341                         msgs[msgp++] = "cur";
342                 maildir = m_maildir (dfolder);
343
344                 if (chdir (maildir) == NOTOK)
345                         adios (maildir, "unable to change directory to");
346
347                 /* read folder and create message structure */
348                 if (!(mp = folder_read (dfolder)))
349                         adios (NULL, "unable to read folder %s", dfolder);
350
351                 /* check for empty folder */
352                 if (mp->nummsg == 0)
353                         adios (NULL, "no messages in %s", dfolder);
354
355                 /* parse all the message ranges/sequences and set SELECTED */
356                 for (msgnum = 0; msgnum < msgp; msgnum++)
357                         if (!m_convert (mp, msgs[msgnum]))
358                                 done (1);
359                 seq_setprev (mp);  /* set the previous-sequence */
360
361                 for (msgp = 0, msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
362                         if (is_selected (mp, msgnum)) {
363                                 msgs[msgp++] = getcpy (m_name (msgnum));
364                                 unset_exists (mp, msgnum);
365                         }
366                 }
367
368                 mp->msgflags |= SEQMOD;
369                 seq_save (mp);
370         }
371
372 #ifdef WHATNOW
373 go_to_it:
374 #endif /* WHATNOW */
375
376         if ((cp = getenv ("SIGNATURE")) == NULL || *cp == 0)
377                 if ((cp = context_find ("signature")) && *cp)
378                         m_putenv ("SIGNATURE", cp);
379 #ifdef UCI
380                 else {
381                         snprintf (buf, sizeof(buf), "%s/.signature", mypath);
382                         if ((fp = fopen (buf, "r")) != NULL
383                                 && fgets (buf, sizeof buf, fp) != NULL) {
384                                         fclose (fp);
385                                         if (cp = strchr (buf, '\n'))
386                                                 *cp = 0;
387                                         m_putenv ("SIGNATURE", buf);
388                         }
389                 }
390 #endif /* UCI */
391
392         for (msgnum = 0; msgnum < msgp; msgnum++)
393                 if (stat (msgs[msgnum], &st) == NOTOK)
394                         adios (msgs[msgnum], "unable to stat draft file");
395
396         if ((annotext = getenv ("mhannotate")) == NULL || *annotext == 0)
397                 annotext = NULL;
398         if (annotext && ((cp = getenv ("mhinplace")) != NULL && *cp != 0))
399                 inplace = atoi (cp);
400         if ((altmsg = getenv ("mhaltmsg")) == NULL || *altmsg == 0)
401                 altmsg = NULL;  /* used by dist interface - see below */
402
403         if ((cp = getenv ("mhdist"))
404                         && *cp
405                         && (distsw = atoi (cp))
406                         && altmsg) {
407                 vec[vecp++] = "-dist";
408                 distfile = getcpy (m_mktemp2 (altmsg, invo_name, NULL, NULL));
409                 if (link (altmsg, distfile) == NOTOK) {
410                         if (errno != EXDEV
411 #ifdef EISREMOTE
412                                         && errno != EISREMOTE
413 #endif /* EISREMOTE */
414                                 )
415                                 adios (distfile, "unable to link %s to", altmsg);
416                         free (distfile);
417                         distfile = getcpy (m_mktemp2(NULL, invo_name, NULL, NULL));
418                         {
419                                 int in, out;
420                                 struct stat st;
421
422                                 if ((in = open (altmsg, O_RDONLY)) == NOTOK)
423                                         adios (altmsg, "unable to open");
424                                 fstat(in, &st);
425                                 if ((out = creat (distfile, (int) st.st_mode & 0777)) == NOTOK)
426                                         adios (distfile, "unable to write");
427                                 cpydata (in, out, altmsg, distfile);
428                                 close (in);
429                                 close (out);
430                         }
431                 }
432         } else {
433                 distfile = NULL;
434         }
435
436         if (altmsg == NULL || stat (altmsg, &st) == NOTOK) {
437                 st.st_mtime = 0;
438                 st.st_dev = 0;
439                 st.st_ino = 0;
440         }
441         if (pushsw)
442                 push ();
443
444         status = 0;
445         vec[0] = r1bindex (postproc, '/');
446         closefds (3);
447
448         for (msgnum = 0; msgnum < msgp; msgnum++) {
449                 switch (sendsbr (vec, vecp, msgs[msgnum], &st, 1, attach,
450                                                  attachformat)) {
451                         case DONE:
452                                 done (++status);
453                         case NOTOK:
454                                 status++;  /* fall */
455                         case OK:
456                                 break;
457                 }
458         }
459
460         context_save ();  /* save the context file */
461         done (status);
462         return 1;
463 }