1 | |
---|
2 | /* |
---|
3 | * sendsbr.c -- routines to help WhatNow/Send along |
---|
4 | * |
---|
5 | * $Id: sendsbr.c,v 1.1.1.1 1999-02-07 18:14:17 danw Exp $ |
---|
6 | */ |
---|
7 | |
---|
8 | #include <h/mh.h> |
---|
9 | #include <h/signals.h> |
---|
10 | #include <setjmp.h> |
---|
11 | #include <signal.h> |
---|
12 | #include <fcntl.h> |
---|
13 | #include <h/mime.h> |
---|
14 | |
---|
15 | int debugsw = 0; /* global */ |
---|
16 | int forwsw = 1; |
---|
17 | int inplace = 1; |
---|
18 | int pushsw = 0; |
---|
19 | int splitsw = -1; |
---|
20 | int unique = 0; |
---|
21 | int verbsw = 0; |
---|
22 | |
---|
23 | char *altmsg = NULL; /* .. */ |
---|
24 | char *annotext = NULL; |
---|
25 | char *distfile = NULL; |
---|
26 | |
---|
27 | static int armed = 0; |
---|
28 | static jmp_buf env; |
---|
29 | |
---|
30 | /* |
---|
31 | * external prototypes |
---|
32 | */ |
---|
33 | int sendsbr (char **, int, char *, struct stat *, int); |
---|
34 | void done (int); |
---|
35 | char *getusername (void); |
---|
36 | |
---|
37 | /* |
---|
38 | * static prototypes |
---|
39 | */ |
---|
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 *); |
---|
46 | |
---|
47 | |
---|
48 | /* |
---|
49 | * Entry point into (back-end) routines to send message. |
---|
50 | */ |
---|
51 | |
---|
52 | int |
---|
53 | sendsbr (char **vec, int vecp, char *drft, struct stat *st, int rename_drft) |
---|
54 | { |
---|
55 | int status; |
---|
56 | char buffer[BUFSIZ], file[BUFSIZ]; |
---|
57 | struct stat sts; |
---|
58 | |
---|
59 | armed++; |
---|
60 | switch (setjmp (env)) { |
---|
61 | case OK: |
---|
62 | /* |
---|
63 | * If given -push and -unique (which is undocumented), then |
---|
64 | * rename the draft file. I'm not quite sure why. |
---|
65 | */ |
---|
66 | if (pushsw && unique) { |
---|
67 | if (rename (drft, strncpy (file, m_scratch (drft, invo_name), sizeof(file))) |
---|
68 | == NOTOK) |
---|
69 | adios (file, "unable to rename %s to", drft); |
---|
70 | drft = file; |
---|
71 | } |
---|
72 | |
---|
73 | /* |
---|
74 | * Check if we need to split the message into |
---|
75 | * multiple messages of type "message/partial". |
---|
76 | */ |
---|
77 | if (splitsw >= 0 && !distfile && stat (drft, &sts) != NOTOK |
---|
78 | && sts.st_size >= CPERMSG) { |
---|
79 | status = splitmsg (vec, vecp, drft, st, splitsw) ? NOTOK : OK; |
---|
80 | } else { |
---|
81 | status = sendaux (vec, vecp, drft, st) ? NOTOK : OK; |
---|
82 | } |
---|
83 | |
---|
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); |
---|
88 | break; |
---|
89 | |
---|
90 | default: |
---|
91 | status = DONE; |
---|
92 | break; |
---|
93 | } |
---|
94 | |
---|
95 | armed = 0; |
---|
96 | if (distfile) |
---|
97 | unlink (distfile); |
---|
98 | |
---|
99 | return status; |
---|
100 | } |
---|
101 | |
---|
102 | |
---|
103 | /* |
---|
104 | * Split large message into several messages of |
---|
105 | * type "message/partial" and send them. |
---|
106 | */ |
---|
107 | |
---|
108 | static int |
---|
109 | splitmsg (char **vec, int vecp, char *drft, struct stat *st, int delay) |
---|
110 | { |
---|
111 | int compnum, nparts, partno, state, status; |
---|
112 | long pos, start; |
---|
113 | time_t clock; |
---|
114 | char *cp, *dp, buffer[BUFSIZ], msgid[BUFSIZ]; |
---|
115 | char subject[BUFSIZ]; |
---|
116 | char name[NAMESZ], partnum[BUFSIZ]; |
---|
117 | FILE *in; |
---|
118 | |
---|
119 | if ((in = fopen (drft, "r")) == NULL) |
---|
120 | adios (drft, "unable to open for reading"); |
---|
121 | |
---|
122 | cp = dp = NULL; |
---|
123 | start = 0L; |
---|
124 | |
---|
125 | /* |
---|
126 | * Scan through the message and examine the various header fields, |
---|
127 | * as well as locate the beginning of the message body. |
---|
128 | */ |
---|
129 | for (compnum = 1, state = FLD;;) { |
---|
130 | switch (state = m_getfld (state, name, buffer, sizeof(buffer), in)) { |
---|
131 | case FLD: |
---|
132 | case FLDPLUS: |
---|
133 | case FLDEOF: |
---|
134 | compnum++; |
---|
135 | |
---|
136 | /* |
---|
137 | * This header field is discarded. |
---|
138 | */ |
---|
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")) { |
---|
146 | /* |
---|
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. |
---|
153 | */ |
---|
154 | if (!strcasecmp (name, "Subject")) { |
---|
155 | size_t sublen; |
---|
156 | |
---|
157 | strncpy (subject, buffer, BUFSIZ); |
---|
158 | sublen = strlen (subject); |
---|
159 | if (sublen > 0 && subject[sublen - 1] == '\n') |
---|
160 | subject[sublen - 1] = '\0'; |
---|
161 | } |
---|
162 | |
---|
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); |
---|
167 | } |
---|
168 | } else { |
---|
169 | /* |
---|
170 | * These header fields are copied to the header of |
---|
171 | * each message/partial in the collection. |
---|
172 | */ |
---|
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); |
---|
177 | } |
---|
178 | } |
---|
179 | |
---|
180 | if (state != FLDEOF) { |
---|
181 | start = ftell (in) + 1; |
---|
182 | continue; |
---|
183 | } |
---|
184 | /* else fall... */ |
---|
185 | |
---|
186 | case BODY: |
---|
187 | case BODYEOF: |
---|
188 | case FILEEOF: |
---|
189 | break; |
---|
190 | |
---|
191 | case LENERR: |
---|
192 | case FMTERR: |
---|
193 | adios (NULL, "message format error in component #%d", compnum); |
---|
194 | |
---|
195 | default: |
---|
196 | adios (NULL, "getfld () returned %d", state); |
---|
197 | } |
---|
198 | |
---|
199 | break; |
---|
200 | } |
---|
201 | if (cp == NULL) |
---|
202 | adios (NULL, "headers missing from draft"); |
---|
203 | |
---|
204 | nparts = 1; |
---|
205 | pos = start; |
---|
206 | while (fgets (buffer, sizeof(buffer) - 1, in)) { |
---|
207 | long len; |
---|
208 | |
---|
209 | if ((pos += (len = strlen (buffer))) > CPERMSG) { |
---|
210 | nparts++; |
---|
211 | pos = len; |
---|
212 | } |
---|
213 | } |
---|
214 | |
---|
215 | /* Only one part, nothing to split */ |
---|
216 | if (nparts == 1) { |
---|
217 | free (cp); |
---|
218 | if (dp) |
---|
219 | free (dp); |
---|
220 | |
---|
221 | fclose (in); |
---|
222 | return sendaux (vec, vecp, drft, st); |
---|
223 | } |
---|
224 | |
---|
225 | if (!pushsw) { |
---|
226 | printf ("Sending as %d Partial Messages\n", nparts); |
---|
227 | fflush (stdout); |
---|
228 | } |
---|
229 | status = OK; |
---|
230 | |
---|
231 | vec[vecp++] = "-partno"; |
---|
232 | vec[vecp++] = partnum; |
---|
233 | if (delay == 0) |
---|
234 | vec[vecp++] = "-queued"; |
---|
235 | |
---|
236 | time (&clock); |
---|
237 | snprintf (msgid, sizeof(msgid), "<%d.%ld@%s>", |
---|
238 | (int) getpid(), (long) clock, LocalName()); |
---|
239 | |
---|
240 | fseek (in, start, SEEK_SET); |
---|
241 | for (partno = 1; partno <= nparts; partno++) { |
---|
242 | char tmpdrf[BUFSIZ]; |
---|
243 | FILE *out; |
---|
244 | |
---|
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); |
---|
249 | |
---|
250 | /* |
---|
251 | * Output the header fields |
---|
252 | */ |
---|
253 | fputs (cp, out); |
---|
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); |
---|
259 | |
---|
260 | /* |
---|
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. |
---|
264 | */ |
---|
265 | if (partno == 1) { |
---|
266 | if (dp) |
---|
267 | fputs (dp, out); |
---|
268 | fprintf (out, "Message-ID: %s\n", msgid); |
---|
269 | fprintf (out, "\n"); |
---|
270 | } |
---|
271 | |
---|
272 | pos = 0; |
---|
273 | for (;;) { |
---|
274 | long len; |
---|
275 | |
---|
276 | if (!fgets (buffer, sizeof(buffer) - 1, in)) { |
---|
277 | if (partno == nparts) |
---|
278 | break; |
---|
279 | adios (NULL, "premature eof"); |
---|
280 | } |
---|
281 | |
---|
282 | if ((pos += (len = strlen (buffer))) > CPERMSG) { |
---|
283 | fseek (in, -len, SEEK_CUR); |
---|
284 | break; |
---|
285 | } |
---|
286 | |
---|
287 | fputs (buffer, out); |
---|
288 | } |
---|
289 | |
---|
290 | if (fflush (out)) |
---|
291 | adios (tmpdrf, "error writing to"); |
---|
292 | |
---|
293 | fclose (out); |
---|
294 | |
---|
295 | if (!pushsw && verbsw) { |
---|
296 | printf ("\n"); |
---|
297 | fflush (stdout); |
---|
298 | } |
---|
299 | |
---|
300 | /* Pause here, if a delay is specified */ |
---|
301 | if (delay > 0 && 1 < partno && partno <= nparts) { |
---|
302 | if (!pushsw) { |
---|
303 | printf ("pausing %d seconds before sending part %d...\n", |
---|
304 | delay, partno); |
---|
305 | fflush (stdout); |
---|
306 | } |
---|
307 | sleep ((unsigned int) delay); |
---|
308 | } |
---|
309 | |
---|
310 | snprintf (partnum, sizeof(partnum), "%d", partno); |
---|
311 | status = sendaux (vec, vecp, tmpdrf, st); |
---|
312 | unlink (tmpdrf); |
---|
313 | if (status != OK) |
---|
314 | break; |
---|
315 | |
---|
316 | /* |
---|
317 | * This is so sendaux will only annotate |
---|
318 | * the altmsg the first time it is called. |
---|
319 | */ |
---|
320 | annotext = NULL; |
---|
321 | } |
---|
322 | |
---|
323 | free (cp); |
---|
324 | if (dp) |
---|
325 | free (dp); |
---|
326 | |
---|
327 | fclose (in); /* close the draft */ |
---|
328 | return status; |
---|
329 | } |
---|
330 | |
---|
331 | |
---|
332 | /* |
---|
333 | * Annotate original message, and |
---|
334 | * call `postproc' to send message. |
---|
335 | */ |
---|
336 | |
---|
337 | static int |
---|
338 | sendaux (char **vec, int vecp, char *drft, struct stat *st) |
---|
339 | { |
---|
340 | pid_t child_id; |
---|
341 | int i, status, fd, fd2; |
---|
342 | char backup[BUFSIZ], buf[BUFSIZ]; |
---|
343 | |
---|
344 | fd = pushsw ? tmp_fd () : NOTOK; |
---|
345 | fd2 = NOTOK; |
---|
346 | |
---|
347 | vec[vecp++] = drft; |
---|
348 | if (annotext) { |
---|
349 | if ((fd2 = tmp_fd ()) != NOTOK) { |
---|
350 | vec[vecp++] = "-idanno"; |
---|
351 | snprintf (buf, sizeof(buf), "%d", fd2); |
---|
352 | vec[vecp++] = buf; |
---|
353 | } else { |
---|
354 | admonish (NULL, "unable to create file for annotation list"); |
---|
355 | } |
---|
356 | } |
---|
357 | if (distfile && distout (drft, distfile, backup) == NOTOK) |
---|
358 | done (1); |
---|
359 | vec[vecp] = NULL; |
---|
360 | |
---|
361 | for (i = 0; (child_id = vfork()) == NOTOK && i < 5; i++) |
---|
362 | sleep (5); |
---|
363 | |
---|
364 | switch (child_id) { |
---|
365 | case -1: |
---|
366 | /* oops -- fork error */ |
---|
367 | adios ("fork", "unable to"); |
---|
368 | break; /* NOT REACHED */ |
---|
369 | |
---|
370 | case 0: |
---|
371 | /* |
---|
372 | * child process -- send it |
---|
373 | * |
---|
374 | * If fd is ok, then we are pushing and fd points to temp |
---|
375 | * file, so capture anything on stdout and stderr there. |
---|
376 | */ |
---|
377 | if (fd != NOTOK) { |
---|
378 | dup2 (fd, fileno (stdout)); |
---|
379 | dup2 (fd, fileno (stderr)); |
---|
380 | close (fd); |
---|
381 | } |
---|
382 | execvp (postproc, vec); |
---|
383 | fprintf (stderr, "unable to exec "); |
---|
384 | perror (postproc); |
---|
385 | _exit (-1); |
---|
386 | break; /* NOT REACHED */ |
---|
387 | |
---|
388 | default: |
---|
389 | /* |
---|
390 | * parent process -- wait for it |
---|
391 | */ |
---|
392 | if ((status = pidwait(child_id, NOTOK)) == OK) { |
---|
393 | if (annotext && fd2 != NOTOK) |
---|
394 | anno (fd2, st); |
---|
395 | } else { |
---|
396 | /* |
---|
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. |
---|
400 | */ |
---|
401 | if (fd != NOTOK) { |
---|
402 | alert (drft, fd); |
---|
403 | close (fd); |
---|
404 | } else { |
---|
405 | advise (NULL, "message not delivered to anyone"); |
---|
406 | } |
---|
407 | if (annotext && fd2 != NOTOK) |
---|
408 | close (fd2); |
---|
409 | if (distfile) { |
---|
410 | unlink (drft); |
---|
411 | if (rename (backup, drft) == NOTOK) |
---|
412 | advise (drft, "unable to rename %s to", backup); |
---|
413 | } |
---|
414 | } |
---|
415 | break; |
---|
416 | } |
---|
417 | |
---|
418 | return status; |
---|
419 | } |
---|
420 | |
---|
421 | |
---|
422 | /* |
---|
423 | * Mail error notification (and possibly a copy of the |
---|
424 | * message) back to the user, using the mailproc |
---|
425 | */ |
---|
426 | |
---|
427 | static void |
---|
428 | alert (char *file, int out) |
---|
429 | { |
---|
430 | pid_t child_id; |
---|
431 | int i, in; |
---|
432 | char buf[BUFSIZ]; |
---|
433 | |
---|
434 | for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++) |
---|
435 | sleep (5); |
---|
436 | |
---|
437 | switch (child_id) { |
---|
438 | case NOTOK: |
---|
439 | /* oops -- fork error */ |
---|
440 | advise ("fork", "unable to"); |
---|
441 | |
---|
442 | case OK: |
---|
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); |
---|
448 | if (forwsw) { |
---|
449 | if ((in = open (file, O_RDONLY)) == NOTOK) { |
---|
450 | admonish (file, "unable to re-open"); |
---|
451 | } else { |
---|
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"); |
---|
458 | close (in); |
---|
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); |
---|
463 | } |
---|
464 | } |
---|
465 | lseek (out, (off_t) 0, SEEK_SET); |
---|
466 | dup2 (out, fileno (stdin)); |
---|
467 | close (out); |
---|
468 | /* create subject for error notification */ |
---|
469 | snprintf (buf, sizeof(buf), "send failed on %s", |
---|
470 | forwsw ? "enclosed draft" : file); |
---|
471 | |
---|
472 | execlp (mailproc, r1bindex (mailproc, '/'), getusername (), |
---|
473 | "-subject", buf, NULL); |
---|
474 | fprintf (stderr, "unable to exec "); |
---|
475 | perror (mailproc); |
---|
476 | _exit (-1); |
---|
477 | |
---|
478 | default: /* no waiting... */ |
---|
479 | break; |
---|
480 | } |
---|
481 | } |
---|
482 | |
---|
483 | |
---|
484 | static int |
---|
485 | tmp_fd (void) |
---|
486 | { |
---|
487 | int fd; |
---|
488 | char tmpfil[BUFSIZ]; |
---|
489 | |
---|
490 | strncpy (tmpfil, m_tmpfil (invo_name), sizeof(tmpfil)); |
---|
491 | if ((fd = open (tmpfil, O_RDWR | O_CREAT | O_TRUNC, 0600)) == NOTOK) |
---|
492 | return NOTOK; |
---|
493 | if (debugsw) |
---|
494 | advise (NULL, "temporary file %s selected", tmpfil); |
---|
495 | else |
---|
496 | if (unlink (tmpfil) == NOTOK) |
---|
497 | advise (tmpfil, "unable to remove"); |
---|
498 | |
---|
499 | return fd; |
---|
500 | } |
---|
501 | |
---|
502 | |
---|
503 | static void |
---|
504 | anno (int fd, struct stat *st) |
---|
505 | { |
---|
506 | pid_t child_id; |
---|
507 | sigset_t set, oset; |
---|
508 | static char *cwd = NULL; |
---|
509 | struct stat st2; |
---|
510 | |
---|
511 | if (altmsg && |
---|
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)) { |
---|
516 | if (debugsw) |
---|
517 | admonish (NULL, "$mhaltmsg mismatch"); |
---|
518 | return; |
---|
519 | } |
---|
520 | |
---|
521 | child_id = debugsw ? NOTOK : fork (); |
---|
522 | switch (child_id) { |
---|
523 | case NOTOK: /* oops */ |
---|
524 | if (!debugsw) |
---|
525 | advise (NULL, |
---|
526 | "unable to fork, so doing annotations by hand..."); |
---|
527 | if (cwd == NULL) |
---|
528 | cwd = getcpy (pwd ()); |
---|
529 | |
---|
530 | case OK: |
---|
531 | /* block a few signals */ |
---|
532 | sigemptyset (&set); |
---|
533 | sigaddset (&set, SIGHUP); |
---|
534 | sigaddset (&set, SIGINT); |
---|
535 | sigaddset (&set, SIGQUIT); |
---|
536 | sigaddset (&set, SIGTERM); |
---|
537 | SIGPROCMASK (SIG_BLOCK, &set, &oset); |
---|
538 | |
---|
539 | annoaux (fd); |
---|
540 | if (child_id == OK) |
---|
541 | _exit (0); |
---|
542 | |
---|
543 | /* reset the signal mask */ |
---|
544 | SIGPROCMASK (SIG_SETMASK, &oset, &set); |
---|
545 | |
---|
546 | chdir (cwd); |
---|
547 | break; |
---|
548 | |
---|
549 | default: /* no waiting... */ |
---|
550 | close (fd); |
---|
551 | break; |
---|
552 | } |
---|
553 | } |
---|
554 | |
---|
555 | |
---|
556 | static void |
---|
557 | annoaux (int fd) |
---|
558 | { |
---|
559 | int fd2, fd3, msgnum; |
---|
560 | char *cp, *folder, *maildir; |
---|
561 | char buffer[BUFSIZ], **ap; |
---|
562 | FILE *fp; |
---|
563 | struct msgs *mp; |
---|
564 | |
---|
565 | if ((folder = getenv ("mhfolder")) == NULL || *folder == 0) { |
---|
566 | if (debugsw) |
---|
567 | admonish (NULL, "$mhfolder not set"); |
---|
568 | return; |
---|
569 | } |
---|
570 | maildir = m_maildir (folder); |
---|
571 | if (chdir (maildir) == NOTOK) { |
---|
572 | if (debugsw) |
---|
573 | admonish (maildir, "unable to change directory to"); |
---|
574 | return; |
---|
575 | } |
---|
576 | if (!(mp = folder_read (folder))) { |
---|
577 | if (debugsw) |
---|
578 | admonish (NULL, "unable to read folder %s"); |
---|
579 | return; |
---|
580 | } |
---|
581 | |
---|
582 | /* check for empty folder */ |
---|
583 | if (mp->nummsg == 0) { |
---|
584 | if (debugsw) |
---|
585 | admonish (NULL, "no messages in %s", folder); |
---|
586 | goto oops; |
---|
587 | } |
---|
588 | |
---|
589 | if ((cp = getenv ("mhmessages")) == NULL || *cp == 0) { |
---|
590 | if (debugsw) |
---|
591 | admonish (NULL, "$mhmessages not set"); |
---|
592 | goto oops; |
---|
593 | } |
---|
594 | if (!debugsw /* MOBY HACK... */ |
---|
595 | && pushsw |
---|
596 | && (fd3 = open ("/dev/null", O_RDWR)) != NOTOK |
---|
597 | && (fd2 = dup (fileno (stderr))) != NOTOK) { |
---|
598 | dup2 (fd3, fileno (stderr)); |
---|
599 | close (fd3); |
---|
600 | } |
---|
601 | else |
---|
602 | fd2 = NOTOK; |
---|
603 | for (ap = brkstring (cp = getcpy (cp), " ", NULL); *ap; ap++) |
---|
604 | m_convert (mp, *ap); |
---|
605 | free (cp); |
---|
606 | if (fd2 != NOTOK) |
---|
607 | dup2 (fd2, fileno (stderr)); |
---|
608 | if (mp->numsel == 0) { |
---|
609 | if (debugsw) |
---|
610 | admonish (NULL, "no messages to annotate"); |
---|
611 | goto oops; |
---|
612 | } |
---|
613 | |
---|
614 | lseek (fd, (off_t) 0, SEEK_SET); |
---|
615 | if ((fp = fdopen (fd, "r")) == NULL) { |
---|
616 | if (debugsw) |
---|
617 | admonish (NULL, "unable to fdopen annotation list"); |
---|
618 | goto oops; |
---|
619 | } |
---|
620 | cp = NULL; |
---|
621 | while (fgets (buffer, sizeof(buffer), fp) != NULL) |
---|
622 | cp = add (buffer, cp); |
---|
623 | fclose (fp); |
---|
624 | |
---|
625 | if (debugsw) |
---|
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)) { |
---|
630 | if (debugsw) |
---|
631 | advise (NULL, "annotate message %d", msgnum); |
---|
632 | annotate (m_name (msgnum), annotext, cp, inplace, 1); |
---|
633 | } |
---|
634 | } |
---|
635 | |
---|
636 | free (cp); |
---|
637 | |
---|
638 | oops: |
---|
639 | folder_free (mp); /* free folder/message structure */ |
---|
640 | } |
---|
641 | |
---|
642 | |
---|
643 | void |
---|
644 | done (int status) |
---|
645 | { |
---|
646 | if (armed) |
---|
647 | longjmp (env, status ? status : NOTOK); |
---|
648 | |
---|
649 | exit (status); |
---|
650 | } |
---|