]>
diplodocus.org Git - nmh/blob - uip/sendsbr.c
3 * sendsbr.c -- routines to help WhatNow/Send along
15 int debugsw
= 0; /* global */
23 char *altmsg
= NULL
; /* .. */
24 char *annotext
= NULL
;
25 char *distfile
= NULL
;
33 int sendsbr (char **, int, char *, struct stat
*, int);
35 char *getusername (void);
40 static void alert (char *, int);
41 static int tmp_fd (void);
42 static void anno (int, struct stat
*);
43 static void annoaux (int);
44 static int splitmsg (char **, int, char *, struct stat
*, int);
45 static int sendaux (char **, int, char *, struct stat
*);
49 * Entry point into (back-end) routines to send message.
53 sendsbr (char **vec
, int vecp
, char *drft
, struct stat
*st
, int rename_drft
)
56 char buffer
[BUFSIZ
], file
[BUFSIZ
];
60 switch (setjmp (env
)) {
63 * If given -push and -unique (which is undocumented), then
64 * rename the draft file. I'm not quite sure why.
66 if (pushsw
&& unique
) {
67 if (rename (drft
, strncpy (file
, m_scratch (drft
, invo_name
), sizeof(file
)))
69 adios (file
, "unable to rename %s to", drft
);
74 * Check if we need to split the message into
75 * multiple messages of type "message/partial".
77 if (splitsw
>= 0 && !distfile
&& stat (drft
, &sts
) != NOTOK
78 && sts
.st_size
>= CPERMSG
) {
79 status
= splitmsg (vec
, vecp
, drft
, st
, splitsw
) ? NOTOK
: OK
;
81 status
= sendaux (vec
, vecp
, drft
, st
) ? NOTOK
: OK
;
84 /* rename the original draft */
85 if (rename_drft
&& status
== OK
&&
86 rename (drft
, strncpy (buffer
, m_backup (drft
), sizeof(buffer
))) == NOTOK
)
87 advise (buffer
, "unable to rename %s to", drft
);
104 * Split large message into several messages of
105 * type "message/partial" and send them.
109 splitmsg (char **vec
, int vecp
, char *drft
, struct stat
*st
, int delay
)
111 int compnum
, nparts
, partno
, state
, status
;
114 char *cp
, *dp
, buffer
[BUFSIZ
], msgid
[BUFSIZ
];
115 char subject
[BUFSIZ
];
116 char name
[NAMESZ
], partnum
[BUFSIZ
];
119 if ((in
= fopen (drft
, "r")) == NULL
)
120 adios (drft
, "unable to open for reading");
126 * Scan through the message and examine the various header fields,
127 * as well as locate the beginning of the message body.
129 for (compnum
= 1, state
= FLD
;;) {
130 switch (state
= m_getfld (state
, name
, buffer
, sizeof(buffer
), in
)) {
137 * This header field is discarded.
139 if (!strcasecmp (name
, "Message-ID")) {
140 while (state
== FLDPLUS
)
141 state
= m_getfld (state
, name
, buffer
, sizeof(buffer
), in
);
142 } else if (uprf (name
, XXX_FIELD_PRF
)
143 || !strcasecmp (name
, VRSN_FIELD
)
144 || !strcasecmp (name
, "Subject")
145 || !strcasecmp (name
, "Encrypted")) {
147 * These header fields are copied to the enclosed
148 * header of the first message in the collection
149 * of message/partials. For the "Subject" header
150 * field, we also record it, so that a modified
151 * version of it, can be copied to the header
152 * of each messsage/partial in the collection.
154 if (!strcasecmp (name
, "Subject")) {
157 strncpy (subject
, buffer
, BUFSIZ
);
158 sublen
= strlen (subject
);
159 if (sublen
> 0 && subject
[sublen
- 1] == '\n')
160 subject
[sublen
- 1] = '\0';
163 dp
= add (concat (name
, ":", buffer
, NULL
), dp
);
164 while (state
== FLDPLUS
) {
165 state
= m_getfld (state
, name
, buffer
, sizeof(buffer
), in
);
166 dp
= add (buffer
, dp
);
170 * These header fields are copied to the header of
171 * each message/partial in the collection.
173 cp
= add (concat (name
, ":", buffer
, NULL
), cp
);
174 while (state
== FLDPLUS
) {
175 state
= m_getfld (state
, name
, buffer
, sizeof(buffer
), in
);
176 cp
= add (buffer
, cp
);
180 if (state
!= FLDEOF
) {
181 start
= ftell (in
) + 1;
193 adios (NULL
, "message format error in component #%d", compnum
);
196 adios (NULL
, "getfld () returned %d", state
);
202 adios (NULL
, "headers missing from draft");
206 while (fgets (buffer
, sizeof(buffer
) - 1, in
)) {
209 if ((pos
+= (len
= strlen (buffer
))) > CPERMSG
) {
215 /* Only one part, nothing to split */
222 return sendaux (vec
, vecp
, drft
, st
);
226 printf ("Sending as %d Partial Messages\n", nparts
);
231 vec
[vecp
++] = "-partno";
232 vec
[vecp
++] = partnum
;
234 vec
[vecp
++] = "-queued";
237 snprintf (msgid
, sizeof(msgid
), "<%d.%ld@%s>",
238 (int) getpid(), (long) clock
, LocalName());
240 fseek (in
, start
, SEEK_SET
);
241 for (partno
= 1; partno
<= nparts
; partno
++) {
245 strncpy (tmpdrf
, m_scratch (drft
, invo_name
), sizeof(tmpdrf
));
246 if ((out
= fopen (tmpdrf
, "w")) == NULL
)
247 adios (tmpdrf
, "unable to open for writing");
248 chmod (tmpdrf
, 0600);
251 * Output the header fields
254 fprintf (out
, "Subject: %s (part %d of %d)\n", subject
, partno
, nparts
);
255 fprintf (out
, "%s: %s\n", VRSN_FIELD
, VRSN_VALUE
);
256 fprintf (out
, "%s: message/partial; id=\"%s\";\n", TYPE_FIELD
, msgid
);
257 fprintf (out
, "\tnumber=%d; total=%d\n", partno
, nparts
);
258 fprintf (out
, "%s: part %d of %d\n\n", DESCR_FIELD
, partno
, nparts
);
261 * If this is the first in the collection, output the
262 * header fields we are encapsulating at the beginning
263 * of the body of the first message.
268 fprintf (out
, "Message-ID: %s\n", msgid
);
276 if (!fgets (buffer
, sizeof(buffer
) - 1, in
)) {
277 if (partno
== nparts
)
279 adios (NULL
, "premature eof");
282 if ((pos
+= (len
= strlen (buffer
))) > CPERMSG
) {
283 fseek (in
, -len
, SEEK_CUR
);
291 adios (tmpdrf
, "error writing to");
295 if (!pushsw
&& verbsw
) {
300 /* Pause here, if a delay is specified */
301 if (delay
> 0 && 1 < partno
&& partno
<= nparts
) {
303 printf ("pausing %d seconds before sending part %d...\n",
307 sleep ((unsigned int) delay
);
310 snprintf (partnum
, sizeof(partnum
), "%d", partno
);
311 status
= sendaux (vec
, vecp
, tmpdrf
, st
);
317 * This is so sendaux will only annotate
318 * the altmsg the first time it is called.
327 fclose (in
); /* close the draft */
333 * Annotate original message, and
334 * call `postproc' to send message.
338 sendaux (char **vec
, int vecp
, char *drft
, struct stat
*st
)
341 int i
, status
, fd
, fd2
;
342 char backup
[BUFSIZ
], buf
[BUFSIZ
];
344 fd
= pushsw
? tmp_fd () : NOTOK
;
349 if ((fd2
= tmp_fd ()) != NOTOK
) {
350 vec
[vecp
++] = "-idanno";
351 snprintf (buf
, sizeof(buf
), "%d", fd2
);
354 admonish (NULL
, "unable to create file for annotation list");
357 if (distfile
&& distout (drft
, distfile
, backup
) == NOTOK
)
361 for (i
= 0; (child_id
= vfork()) == NOTOK
&& i
< 5; i
++)
366 /* oops -- fork error */
367 adios ("fork", "unable to");
368 break; /* NOT REACHED */
372 * child process -- send it
374 * If fd is ok, then we are pushing and fd points to temp
375 * file, so capture anything on stdout and stderr there.
378 dup2 (fd
, fileno (stdout
));
379 dup2 (fd
, fileno (stderr
));
382 execvp (postproc
, vec
);
383 fprintf (stderr
, "unable to exec ");
386 break; /* NOT REACHED */
390 * parent process -- wait for it
392 if ((status
= pidwait(child_id
, NOTOK
)) == OK
) {
393 if (annotext
&& fd2
!= NOTOK
)
397 * If postproc failed, and we have good fd (which means
398 * we pushed), then mail error message (and possibly the
399 * draft) back to the user.
405 advise (NULL
, "message not delivered to anyone");
407 if (annotext
&& fd2
!= NOTOK
)
411 if (rename (backup
, drft
) == NOTOK
)
412 advise (drft
, "unable to rename %s to", backup
);
423 * Mail error notification (and possibly a copy of the
424 * message) back to the user, using the mailproc
428 alert (char *file
, int out
)
434 for (i
= 0; (child_id
= fork()) == NOTOK
&& i
< 5; i
++)
439 /* oops -- fork error */
440 advise ("fork", "unable to");
443 /* child process -- send it */
444 SIGNAL (SIGHUP
, SIG_IGN
);
445 SIGNAL (SIGINT
, SIG_IGN
);
446 SIGNAL (SIGQUIT
, SIG_IGN
);
447 SIGNAL (SIGTERM
, SIG_IGN
);
449 if ((in
= open (file
, O_RDONLY
)) == NOTOK
) {
450 admonish (file
, "unable to re-open");
452 lseek (out
, (off_t
) 0, SEEK_END
);
453 strncpy (buf
, "\nMessage not delivered to anyone.\n", sizeof(buf
));
454 write (out
, buf
, strlen (buf
));
455 strncpy (buf
, "\n------- Unsent Draft\n\n", sizeof(buf
));
456 write (out
, buf
, strlen (buf
));
457 cpydgst (in
, out
, file
, "temporary file");
459 strncpy (buf
, "\n------- End of Unsent Draft\n", sizeof(buf
));
460 write (out
, buf
, strlen (buf
));
461 if (rename (file
, strncpy (buf
, m_backup (file
), sizeof(buf
))) == NOTOK
)
462 admonish (buf
, "unable to rename %s to", file
);
465 lseek (out
, (off_t
) 0, SEEK_SET
);
466 dup2 (out
, fileno (stdin
));
468 /* create subject for error notification */
469 snprintf (buf
, sizeof(buf
), "send failed on %s",
470 forwsw
? "enclosed draft" : file
);
472 execlp (mailproc
, r1bindex (mailproc
, '/'), getusername (),
473 "-subject", buf
, NULL
);
474 fprintf (stderr
, "unable to exec ");
478 default: /* no waiting... */
490 strncpy (tmpfil
, m_tmpfil (invo_name
), sizeof(tmpfil
));
491 if ((fd
= open (tmpfil
, O_RDWR
| O_CREAT
| O_TRUNC
, 0600)) == NOTOK
)
494 advise (NULL
, "temporary file %s selected", tmpfil
);
496 if (unlink (tmpfil
) == NOTOK
)
497 advise (tmpfil
, "unable to remove");
504 anno (int fd
, struct stat
*st
)
508 static char *cwd
= NULL
;
512 (stat (altmsg
, &st2
) == NOTOK
513 || st
->st_mtime
!= st2
.st_mtime
514 || st
->st_dev
!= st2
.st_dev
515 || st
->st_ino
!= st2
.st_ino
)) {
517 admonish (NULL
, "$mhaltmsg mismatch");
521 child_id
= debugsw
? NOTOK
: fork ();
523 case NOTOK
: /* oops */
526 "unable to fork, so doing annotations by hand...");
528 cwd
= getcpy (pwd ());
531 /* block a few signals */
533 sigaddset (&set
, SIGHUP
);
534 sigaddset (&set
, SIGINT
);
535 sigaddset (&set
, SIGQUIT
);
536 sigaddset (&set
, SIGTERM
);
537 SIGPROCMASK (SIG_BLOCK
, &set
, &oset
);
543 /* reset the signal mask */
544 SIGPROCMASK (SIG_SETMASK
, &oset
, &set
);
549 default: /* no waiting... */
559 int fd2
, fd3
, msgnum
;
560 char *cp
, *folder
, *maildir
;
561 char buffer
[BUFSIZ
], **ap
;
565 if ((folder
= getenv ("mhfolder")) == NULL
|| *folder
== 0) {
567 admonish (NULL
, "$mhfolder not set");
570 maildir
= m_maildir (folder
);
571 if (chdir (maildir
) == NOTOK
) {
573 admonish (maildir
, "unable to change directory to");
576 if (!(mp
= folder_read (folder
))) {
578 admonish (NULL
, "unable to read folder %s");
582 /* check for empty folder */
583 if (mp
->nummsg
== 0) {
585 admonish (NULL
, "no messages in %s", folder
);
589 if ((cp
= getenv ("mhmessages")) == NULL
|| *cp
== 0) {
591 admonish (NULL
, "$mhmessages not set");
594 if (!debugsw
/* MOBY HACK... */
596 && (fd3
= open ("/dev/null", O_RDWR
)) != NOTOK
597 && (fd2
= dup (fileno (stderr
))) != NOTOK
) {
598 dup2 (fd3
, fileno (stderr
));
603 for (ap
= brkstring (cp
= getcpy (cp
), " ", NULL
); *ap
; ap
++)
607 dup2 (fd2
, fileno (stderr
));
608 if (mp
->numsel
== 0) {
610 admonish (NULL
, "no messages to annotate");
614 lseek (fd
, (off_t
) 0, SEEK_SET
);
615 if ((fp
= fdopen (fd
, "r")) == NULL
) {
617 admonish (NULL
, "unable to fdopen annotation list");
621 while (fgets (buffer
, sizeof(buffer
), fp
) != NULL
)
622 cp
= add (buffer
, cp
);
626 advise (NULL
, "annotate%s with %s: \"%s\"",
627 inplace
? " inplace" : "", annotext
, cp
);
628 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++) {
629 if (is_selected(mp
, msgnum
)) {
631 advise (NULL
, "annotate message %d", msgnum
);
632 annotate (m_name (msgnum
), annotext
, cp
, inplace
, 1);
639 folder_free (mp
); /* free folder/message structure */
647 longjmp (env
, status
? status
: NOTOK
);