]> diplodocus.org Git - nmh/blob - docs/historical/mh-6.8.5/uip/sendsbr.c
sbr/mts.c: Delete mmdlm2; use same-valued mmdlm1 instead.
[nmh] / docs / historical / mh-6.8.5 / uip / sendsbr.c
1 /* sendsbr.c - routines to help WhatNow/Send along */
2 #ifndef lint
3 static char ident[] = "@(#)$Id: sendsbr.c,v 2.14 1993/08/25 17:28:05 jromine Exp $";
4 #endif /* lint */
5
6 #include "../h/mh.h"
7 #include <setjmp.h>
8 #include <stdio.h>
9 #include <signal.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12
13 static alert(), anno(), annoaux();
14 static int tmp_fd();
15 static int sendaux();
16 #ifdef MIME
17 static int sendaux2();
18 #endif
19
20 /* \f */
21
22 int debugsw = 0; /* global */
23 int forwsw = 1;
24 int inplace = 0;
25 int mime = 0;
26 int pushsw = 0;
27 int splitsw = -1;
28 int unique = 0;
29 int verbsw = 0;
30
31 char *altmsg = NULL; /* .. */
32 char *annotext = NULL;
33 char *distfile = NULL;
34
35
36 static int armed = 0;
37 static jmp_buf env;
38
39
40 char *getusr ();
41 off_t lseek ();
42 long time ();
43
44 /* \f */
45
46 int sendsbr (vec, vecp, drft, st)
47 char **vec,
48 *drft;
49 int vecp;
50 struct stat *st;
51 {
52 int status;
53
54 armed++;
55 switch (setjmp (env)) {
56 case OK:
57 status = sendaux (vec, vecp, drft, st) ? NOTOK : OK;
58 break;
59
60 default:
61 status = DONE;
62 break;
63 }
64 armed = 0;
65 if (distfile)
66 (void) unlink (distfile);
67
68 return status;
69 }
70
71 /* \f */
72
73 #ifdef MIME
74 #include "../h/mhn.h"
75
76 static int sendaux (vec, vecp, drft, st)
77 register char **vec,
78 *drft;
79 int vecp;
80 register struct stat *st;
81 {
82 int compnum,
83 nparts,
84 partno,
85 state,
86 status;
87 long clock,
88 pos,
89 start;
90 char *cp,
91 *dp,
92 buffer[BUFSIZ],
93 msgid[BUFSIZ],
94 name[NAMESZ],
95 partnum[BUFSIZ];
96 struct stat sts;
97 FILE *in;
98
99 if (splitsw < 0
100 || distfile
101 || stat (drft, &sts) == NOTOK
102 || sts.st_size < CPERMSG) {
103 one_shot: ;
104 splitsw = -1;
105 return sendaux2 (vec, vecp, drft, st);
106 }
107
108 if ((in = fopen (drft, "r")) == NULL)
109 adios (drft, "unable to open for reading");
110
111 cp = dp = NULL;
112 start = 0L;
113 for (compnum = 1, state = FLD;;) {
114 switch (state = m_getfld (state, name, buffer, sizeof buffer, in)) {
115 case FLD:
116 case FLDPLUS:
117 case FLDEOF:
118 compnum++;
119
120 if (uleq (name, VRSN_FIELD)
121 || uleq (name, "Encrypted")
122 || uleq (name, "Message-ID")) {
123 while (state == FLDPLUS)
124 state = m_getfld (state, name, buffer, sizeof buffer,
125 in);
126 }
127 else
128 if (uprf (name, XXX_FIELD_PRF)) {
129 dp = add (concat (name, ":", buffer, NULLCP), dp);
130 while (state == FLDPLUS) {
131 state = m_getfld (state, name, buffer,
132 sizeof buffer, in);
133 dp = add (buffer, dp);
134 }
135 }
136 else {
137 cp = add (concat (name, ":", buffer, NULLCP), cp);
138 while (state == FLDPLUS) {
139 state = m_getfld (state, name, buffer,
140 sizeof buffer, in);
141 cp = add (buffer, cp);
142 }
143 }
144 if (state != FLDEOF) {
145 start = ftell (in) + 1;
146 continue;
147 }
148 /* else fall... */
149 case BODY:
150 case BODYEOF:
151 case FILEEOF:
152 break;
153
154 case LENERR:
155 case FMTERR:
156 adios (NULLCP, "message format error in component #%d",
157 compnum);
158
159 default:
160 adios (NULLCP, "getfld () returned %d", state);
161 }
162
163 break;
164 }
165 if (cp == NULL)
166 adios (NULLCP, "headers missing from draft");
167
168 nparts = 1, pos = start;
169 while (fgets (buffer, sizeof buffer - 1, in)) {
170 register long len;
171
172 if ((pos += (len = strlen (buffer))) > CPERMSG)
173 nparts++, pos = len;
174 }
175 if (nparts == 1) {
176 free (cp);
177 if (dp)
178 free (dp);
179
180 (void) fclose (in);
181
182 goto one_shot;
183 }
184
185 if (!pushsw) {
186 printf ("Sending as %d Partial Messages\n", nparts);
187 (void) fflush (stdout);
188 }
189 status = OK;
190
191 vec[vecp++] = "-partno";
192 vec[vecp++] = partnum;
193 if (splitsw == 0)
194 vec[vecp++] = "-queued";
195
196 (void) time (&clock);
197 (void) sprintf (msgid, "<%d.%ld@%s>", getpid (), clock, LocalName ());
198
199 (void) fseek (in, start, 0);
200 for (partno = 1; partno <= nparts; partno++) {
201 char tmpdrf[BUFSIZ];
202 FILE *out;
203
204 (void) strcpy (tmpdrf, m_scratch (drft, invo_name));
205 if ((out = fopen (tmpdrf, "w")) == NULL)
206 adios (tmpdrf, "unable to open for writing");
207 (void) chmod (tmpdrf, 0600);
208
209 (void) fputs (cp, out);
210 fprintf (out, "%s: %s\n", VRSN_FIELD, VRSN_VALUE);
211 fprintf (out,
212 "%s: message/partial; id=\"%s\"; number=%d; total=%d\n",
213 TYPE_FIELD, msgid, partno, nparts);
214 fprintf (out, "%s: part %d of %d\n\n", DESCR_FIELD, partno,
215 nparts);
216
217 if (partno == 1) {
218 if (dp)
219 (void) fputs (dp, out);
220 fprintf (out, "Message-ID: %s\n", msgid);
221 fprintf (out, "\n");
222 }
223
224 pos = 0;
225 for (;;) {
226 register long len;
227
228 if (!fgets (buffer, sizeof buffer - 1, in)) {
229 if (partno == nparts)
230 break;
231 adios (NULLCP, "premature eof");
232 }
233
234 if ((pos += (len = strlen (buffer))) > CPERMSG) {
235 (void) fseek (in, -len, 1);
236 break;
237 }
238
239 (void) fputs (buffer, out);
240 }
241
242 if (fflush (out))
243 adios (tmpdrf, "error writing to");
244
245 (void) fclose (out);
246
247 if (!pushsw && verbsw) {
248 printf ("\n");
249 (void) fflush (stdout);
250 }
251 if (splitsw > 0 && 1 < partno && partno < nparts) {
252 if (!pushsw) {
253 printf ("pausing %d seconds before sending part %d...\n",
254 splitsw, partno);
255 (void) fflush (stdout);
256 }
257
258 sleep ((unsigned) splitsw);
259 }
260
261 (void) sprintf (partnum, "%d", partno);
262 status = sendaux2 (vec, vecp, tmpdrf, st);
263 (void) unlink (tmpdrf);
264 if (status != OK)
265 break;
266
267 annotext = NULL;
268 }
269
270 free (cp);
271 if (dp)
272 free (dp);
273
274 (void) fclose (in);
275
276 if (status == OK &&
277 rename (drft, strcpy (buffer, m_backup (drft))) == NOTOK)
278 advise (buffer, "unable to rename %s to", drft);
279
280 return status;
281 }
282 #endif
283
284 /* \f */
285
286 #ifndef MIME
287 static int sendaux (vec, vecp, drft, st)
288 #else /* MIME */
289 static int sendaux2 (vec, vecp, drft, st)
290 #endif /* MIME */
291 register char **vec,
292 *drft;
293 int vecp;
294 register struct stat *st;
295 {
296 int child_id,
297 i,
298 status,
299 fd,
300 fd2;
301 char backup[BUFSIZ],
302 buf[BUFSIZ],
303 file[BUFSIZ];
304
305 fd = pushsw ? tmp_fd () : NOTOK;
306 fd2 = NOTOK;
307
308 if (pushsw && unique) {
309 if (rename (drft, strcpy (file, m_scratch (drft, invo_name)))
310 == NOTOK)
311 adios (file, "unable to rename %s to", drft);
312 drft = file;
313 }
314 vec[vecp++] = drft;
315 if (annotext)
316 if ((fd2 = tmp_fd ()) != NOTOK) {
317 vec[vecp++] = "-idanno";
318 (void) sprintf (buf, "%d", fd2);
319 vec[vecp++] = buf;
320 }
321 else
322 admonish (NULLCP, "unable to create file for annotation list");
323 if (distfile && distout (drft, distfile, backup) == NOTOK)
324 done (1);
325 vec[vecp] = NULL;
326
327 for (i = 0; (child_id = vfork ()) == NOTOK && i < 5; i++)
328 sleep (5);
329 switch (child_id) {
330 case NOTOK: /* oops */
331 adios ("fork", "unable to");
332
333 case OK: /* send it */
334 if (fd != NOTOK) {
335 (void) dup2 (fd, fileno (stdout));
336 (void) dup2 (fd, fileno (stderr));
337 (void) close (fd);
338 }
339 execvp (postproc, vec);
340 fprintf (stderr, "unable to exec ");
341 perror (postproc);
342 _exit (-1);
343
344 default: /* wait for it */
345 if ((status = pidwait (child_id, NOTOK)) == 0) {
346 if (annotext && fd2 != NOTOK)
347 anno (fd2, st);
348 if (splitsw < 0
349 && rename (drft, strcpy (buf, m_backup (drft)))
350 == NOTOK)
351 advise (buf, "unable to rename %s to", drft);
352 }
353 else {
354 if (fd != NOTOK) {
355 alert (drft, fd);
356 (void) close (fd);
357 }
358 else
359 advise (NULLCP, "message not delivered to anyone");
360 if (annotext && fd2 != NOTOK)
361 (void) close (fd2);
362 if (distfile) {
363 (void) unlink (drft);
364 if (rename (backup, drft) == NOTOK)
365 advise (drft, "unable to rename %s to", backup);
366 }
367 }
368 break;
369 }
370
371 return status;
372 }
373
374 /* \f */
375
376 static alert (file, out)
377 register char *file;
378 int out;
379 {
380 int child_id,
381 i,
382 in;
383 char buf[BUFSIZ];
384
385 for (i = 0; (child_id = fork ()) == NOTOK && i < 5; i++)
386 sleep (5);
387 switch (child_id) {
388 case NOTOK: /* oops */
389 advise ("fork", "unable to");
390
391 case OK: /* send it */
392 (void) signal (SIGHUP, SIG_IGN);
393 (void) signal (SIGINT, SIG_IGN);
394 (void) signal (SIGQUIT, SIG_IGN);
395 (void) signal (SIGTERM, SIG_IGN);
396 if (forwsw)
397 if ((in = open (file, 0)) == NOTOK)
398 admonish (file, "unable to re-open");
399 else {
400 (void) lseek (out, (off_t)0, 2);
401 (void) strcpy (buf, "\nMessage not delivered to anyone.\n");
402 (void) write (out, buf, strlen (buf));
403 (void) strcpy (buf, "\n------- Unsent Draft\n\n");
404 (void) write (out, buf, strlen (buf));
405 cpydgst (in, out, file, "temporary file");
406 (void) close (in);
407 (void) strcpy (buf, "\n------- End of Unsent Draft\n");
408 (void) write (out, buf, strlen (buf));
409 if (rename (file, strcpy (buf, m_backup (file))) == NOTOK)
410 admonish (buf, "unable to rename %s to", file);
411 }
412 (void) lseek (out, (off_t)0, 0);
413 (void) dup2 (out, fileno (stdin));
414 (void) close (out);
415 (void) sprintf (buf, "send failed on %s",
416 forwsw ? "enclosed draft" : file);
417
418 execlp (mailproc, r1bindex (mailproc, '/'), getusr (),
419 "-subject", buf, NULLCP);
420 fprintf (stderr, "unable to exec ");
421 perror (mailproc);
422 _exit (-1);
423
424 default: /* no waiting... */
425 break;
426 }
427 }
428
429 /* \f */
430
431 static int tmp_fd () {
432 int fd;
433 char tmpfil[BUFSIZ];
434
435 (void) strcpy (tmpfil, m_tmpfil (invo_name));
436 if ((fd = creat (tmpfil, 0600)) == NOTOK)
437 return NOTOK;
438 (void) close (fd);
439
440 if ((fd = open (tmpfil, 2)) == NOTOK)
441 return NOTOK;
442 if (debugsw)
443 advise (NULLCP, "temporary file %s selected", tmpfil);
444 else
445 if (unlink (tmpfil) == NOTOK)
446 advise (tmpfil, "unable to remove");
447
448 return fd;
449 }
450
451 /* \f */
452
453 static anno (fd, st)
454 int fd;
455 register struct stat *st;
456 {
457 int child_id;
458 TYPESIG (*hstat) (), (*istat) (), (*qstat) (), (*tstat) ();
459 static char *cwd = NULL;
460 struct stat st2;
461
462 if (altmsg &&
463 (stat (altmsg, &st2) == NOTOK
464 || st -> st_mtime != st2.st_mtime
465 || st -> st_dev != st2.st_dev
466 || st -> st_ino != st2.st_ino)) {
467 if (debugsw)
468 admonish (NULLCP, "$mhaltmsg mismatch");
469 return;
470 }
471
472 child_id = debugsw ? NOTOK : fork ();
473 switch (child_id) {
474 case NOTOK: /* oops */
475 if (!debugsw)
476 advise (NULLCP,
477 "unable to fork, so doing annotations by hand...");
478 if (cwd == NULL)
479 cwd = getcpy (pwd ());
480
481 case OK:
482 hstat = signal (SIGHUP, SIG_IGN);
483 istat = signal (SIGINT, SIG_IGN);
484 qstat = signal (SIGQUIT, SIG_IGN);
485 tstat = signal (SIGTERM, SIG_IGN);
486
487 annoaux (fd);
488 if (child_id == OK)
489 _exit (0);
490
491 (void) signal (SIGHUP, hstat);
492 (void) signal (SIGINT, istat);
493 (void) signal (SIGQUIT, qstat);
494 (void) signal (SIGTERM, tstat);
495
496 (void) chdir (cwd);
497 break;
498
499 default: /* no waiting... */
500 (void) close (fd);
501 break;
502 }
503 }
504
505 /* \f */
506
507 static annoaux (fd)
508 int fd;
509 {
510 int fd2,
511 fd3,
512 msgnum;
513 char *cp,
514 *folder,
515 *maildir,
516 buffer[BUFSIZ],
517 **ap;
518 FILE *fp;
519 struct msgs *mp;
520
521 if ((folder = getenv ("mhfolder")) == NULL || *folder == 0) {
522 if (debugsw)
523 admonish (NULLCP, "$mhfolder not set");
524 return;
525 }
526 maildir = m_maildir (folder);
527 if (chdir (maildir) == NOTOK) {
528 if (debugsw)
529 admonish (maildir, "unable to change directory to");
530 return;
531 }
532 if (!(mp = m_gmsg (folder))) {
533 if (debugsw)
534 admonish (NULLCP, "unable to read folder %s");
535 return;
536 }
537 if (mp -> hghmsg == 0) {
538 if (debugsw)
539 admonish (NULLCP, "no messages in %s", folder);
540 goto oops;
541 }
542
543 if ((cp = getenv ("mhmessages")) == NULL || *cp == 0) {
544 if (debugsw)
545 admonish (NULLCP, "$mhmessages not set");
546 goto oops;
547 }
548 if (!debugsw /* MOBY HACK... */
549 && pushsw
550 && (fd3 = open ("/dev/null", 2)) != NOTOK
551 && (fd2 = dup (fileno (stderr))) != NOTOK) {
552 (void) dup2 (fd3, fileno (stderr));
553 (void) close (fd3);
554 }
555 else
556 fd2 = NOTOK;
557 for (ap = brkstring (cp = getcpy (cp), " ", NULLCP); *ap; ap++)
558 (void) m_convert (mp, *ap);
559 free (cp);
560 if (fd2 != NOTOK)
561 (void) dup2 (fd2, fileno (stderr));
562 if (mp -> numsel == 0) {
563 if (debugsw)
564 admonish (NULLCP, "no messages to annotate");
565 goto oops;
566 }
567
568 (void) lseek (fd, (off_t)0, 0);
569 if ((fp = fdopen (fd, "r")) == NULL) {
570 if (debugsw)
571 admonish (NULLCP, "unable to fdopen annotation list");
572 goto oops;
573 }
574 cp = NULL;
575 while (fgets (buffer, sizeof buffer, fp) != NULL)
576 cp = add (buffer, cp);
577 (void) fclose (fp);
578
579 if (debugsw)
580 advise (NULLCP, "annotate%s with %s: \"%s\"",
581 inplace ? " inplace" : "", annotext, cp);
582 for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
583 if (mp -> msgstats[msgnum] & SELECTED) {
584 if (debugsw)
585 advise (NULLCP, "annotate message %d", msgnum);
586 (void) annotate (m_name (msgnum), annotext, cp, inplace, 1);
587 }
588
589 free (cp);
590
591 oops: ;
592 m_fmsg (mp);
593 }
594
595 /* \f */
596
597 void done (status)
598 int status;
599 {
600 if (armed)
601 longjmp (env, status ? status : NOTOK);
602
603 exit (status);
604 }