Skip to content
Newer
Older
100644 786 lines (631 sloc) 15.7 KB
14c2920 Imported Upstream version 1.5.18
Antonio Radici authored
1 /*
19304f7 Imported Upstream version 1.5.19
Antonio Radici authored
2 * Copyright (C) 1999-2001 Thomas Roessler <roessler@does-not-exist.org>
14c2920 Imported Upstream version 1.5.18
Antonio Radici authored
3 *
4 * This program is free software; you can redistribute it
5 * and/or modify it under the terms of the GNU General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later
8 * version.
9 *
10 * This program is distributed in the hope that it will be
11 * useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more
14 * details.
15 *
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, write to the Free
18 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22 /*
23 * Mixmaster support for Mutt
24 */
25
26 #if HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include "mutt.h"
31 #include "mutt_curses.h"
32 #include "mutt_menu.h"
33 #include "mutt_regex.h"
34 #include "mapping.h"
35
36 #include "remailer.h"
37
38 #include <stdio.h>
39 #include <string.h>
40 #include <stdlib.h>
41
42 #include <sys/types.h>
43 #include <sys/file.h>
44 #include <fcntl.h>
45
46 #ifdef MIXMASTER
47
48 struct coord
49 {
50 short r, c;
51 };
52
53 static REMAILER **mix_type2_list (size_t *l);
54 static REMAILER *mix_new_remailer (void);
55 static const char *mix_format_caps (REMAILER *r);
56 static int mix_chain_add (MIXCHAIN *chain, const char *s, REMAILER **type2_list);
57 static int mix_get_caps (const char *capstr);
58 static void mix_add_entry (REMAILER ***, REMAILER *, size_t *, size_t *);
59 static void mix_entry (char *b, size_t blen, MUTTMENU *menu, int num);
60 static void mix_free_remailer (REMAILER **r);
61 static void mix_free_type2_list (REMAILER ***ttlp);
62 static void mix_redraw_ce (REMAILER **type2_list, struct coord *coords, MIXCHAIN *chain, int i, short selected);
63 static void mix_redraw_chain (REMAILER **type2_list, struct coord *coords, MIXCHAIN *chain, int cur);
64 static void mix_redraw_head (MIXCHAIN *);
65 static void mix_screen_coordinates (REMAILER **type2_list, struct coord **, MIXCHAIN *, int);
66
67 static int mix_get_caps (const char *capstr)
68 {
69 int caps = 0;
70
71 while (*capstr)
72 {
73 switch (*capstr)
74 {
75 case 'C':
76 caps |= MIX_CAP_COMPRESS;
77 break;
78
79 case 'M':
80 caps |= MIX_CAP_MIDDLEMAN;
81 break;
82
83 case 'N':
84 {
85 switch (*++capstr)
86 {
87 case 'm':
88 caps |= MIX_CAP_NEWSMAIL;
89 break;
90
91 case 'p':
92 caps |= MIX_CAP_NEWSPOST;
93 break;
94
95 }
96 }
97 }
98
99 if (*capstr) capstr++;
100 }
101
102 return caps;
103 }
104
105 static void mix_add_entry (REMAILER ***type2_list, REMAILER *entry,
106 size_t *slots, size_t *used)
107 {
108 if (*used == *slots)
109 {
110 *slots += 5;
111 safe_realloc (type2_list, sizeof (REMAILER *) * (*slots));
112 }
113
114 (*type2_list)[(*used)++] = entry;
115 if (entry) entry->num = *used;
116 }
117
118 static REMAILER *mix_new_remailer (void)
119 {
120 return safe_calloc (1, sizeof (REMAILER));
121 }
122
123 static void mix_free_remailer (REMAILER **r)
124 {
125 FREE (&(*r)->shortname);
126 FREE (&(*r)->addr);
127 FREE (&(*r)->ver);
128
129 FREE (r); /* __FREE_CHECKED__ */
130 }
131
132 /* parse the type2.list as given by mixmaster -T */
133
134 static REMAILER **mix_type2_list (size_t *l)
135 {
136 FILE *fp;
137 pid_t mm_pid;
138 int devnull;
139
140 char cmd[HUGE_STRING + _POSIX_PATH_MAX];
141 char line[HUGE_STRING];
142 char *t;
143
144 REMAILER **type2_list = NULL, *p;
145 size_t slots = 0, used = 0;
146
147 if (!l)
148 return NULL;
149
150 if ((devnull = open ("/dev/null", O_RDWR)) == -1)
151 return NULL;
152
153 snprintf (cmd, sizeof (cmd), "%s -T", Mixmaster);
154
155 if ((mm_pid = mutt_create_filter_fd (cmd, NULL, &fp, NULL, devnull, -1, devnull)) == -1)
156 {
157 close (devnull);
158 return NULL;
159 }
160
161 /* first, generate the "random" remailer */
162
163 p = mix_new_remailer ();
164 p->shortname = safe_strdup ("<random>");
165 mix_add_entry (&type2_list, p, &slots, &used);
166
167 while (fgets (line, sizeof (line), fp))
168 {
169 p = mix_new_remailer ();
170
171 if (!(t = strtok (line, " \t\n")))
172 goto problem;
173
174 p->shortname = safe_strdup (t);
175
176 if (!(t = strtok (NULL, " \t\n")))
177 goto problem;
178
179 p->addr = safe_strdup (t);
180
181 if (!(t = strtok (NULL, " \t\n")))
182 goto problem;
183
184 if (!(t = strtok (NULL, " \t\n")))
185 goto problem;
186
187 p->ver = safe_strdup (t);
188
189 if (!(t = strtok (NULL, " \t\n")))
190 goto problem;
191
192 p->caps = mix_get_caps (t);
193
194 mix_add_entry (&type2_list, p, &slots, &used);
195 continue;
196
197 problem:
198 mix_free_remailer (&p);
199 }
200
201 *l = used;
202
203 mix_add_entry (&type2_list, NULL, &slots, &used);
204 mutt_wait_filter (mm_pid);
205
206 close (devnull);
207
208 return type2_list;
209 }
210
211 static void mix_free_type2_list (REMAILER ***ttlp)
212 {
213 int i;
214 REMAILER **type2_list = *ttlp;
215
216 for (i = 0; type2_list[i]; i++)
217 mix_free_remailer (&type2_list[i]);
218
219 FREE (type2_list); /* __FREE_CHECKED__ */
220 }
221
222
223 #define MIX_HOFFSET 2
224 #define MIX_VOFFSET (LINES - 6)
225 #define MIX_MAXROW (LINES - 3)
226
227
228 static void mix_screen_coordinates (REMAILER **type2_list,
229 struct coord **coordsp,
230 MIXCHAIN *chain,
231 int i)
232 {
233 short c, r, oc;
234 struct coord *coords;
235
236 if (!chain->cl)
237 return;
238
239 safe_realloc (coordsp, sizeof (struct coord) * chain->cl);
240
241 coords = *coordsp;
242
243 if (i)
244 {
245 c = coords[i-1].c + strlen (type2_list[chain->ch[i-1]]->shortname) + 2;
246 r = coords[i-1].r;
247 }
248 else
249 {
250 r = MIX_VOFFSET;
251 c = MIX_HOFFSET;
252 }
253
254
255 for (; i < chain->cl; i++)
256 {
257 oc = c;
258 c += strlen (type2_list[chain->ch[i]]->shortname) + 2;
259
260 if (c >= COLS)
261 {
262 oc = c = MIX_HOFFSET;
263 r++;
264 }
265
266 coords[i].c = oc;
267 coords[i].r = r;
268
269 }
270
271 }
272
273 static void mix_redraw_ce (REMAILER **type2_list,
274 struct coord *coords,
275 MIXCHAIN *chain,
276 int i,
277 short selected)
278 {
279 if (!coords || !chain)
280 return;
281
282 if (coords[i].r < MIX_MAXROW)
283 {
284
285 if (selected)
286 SETCOLOR (MT_COLOR_INDICATOR);
287 else
288 SETCOLOR (MT_COLOR_NORMAL);
289
290 mvaddstr (coords[i].r, coords[i].c, type2_list[chain->ch[i]]->shortname);
291 SETCOLOR (MT_COLOR_NORMAL);
292
293 if (i + 1 < chain->cl)
294 addstr (", ");
295 }
296 }
297
298 static void mix_redraw_chain (REMAILER **type2_list,
299 struct coord *coords,
300 MIXCHAIN *chain,
301 int cur)
302 {
303 int i;
304
305 SETCOLOR (MT_COLOR_NORMAL);
306 BKGDSET (MT_COLOR_NORMAL);
307
308 for (i = MIX_VOFFSET; i < MIX_MAXROW; i++)
309 {
310 move (i, 0);
311 clrtoeol ();
312 }
313
314 for (i = 0; i < chain->cl; i++)
315 mix_redraw_ce (type2_list, coords, chain, i, i == cur);
316 }
317
318 static void mix_redraw_head (MIXCHAIN *chain)
319 {
320 SETCOLOR (MT_COLOR_STATUS);
321 mvprintw (MIX_VOFFSET - 1, 0, "-- Remailer chain [Length: %d]", chain ? chain->cl : 0);
322
323 BKGDSET (MT_COLOR_STATUS);
324 clrtoeol ();
325
326 BKGDSET (MT_COLOR_NORMAL);
327 SETCOLOR (MT_COLOR_NORMAL);
328 }
329
330 static const char *mix_format_caps (REMAILER *r)
331 {
332 static char capbuff[10];
333 char *t = capbuff;
334
335 if (r->caps & MIX_CAP_COMPRESS)
336 *t++ = 'C';
337 else
338 *t++ = ' ';
339
340 if (r->caps & MIX_CAP_MIDDLEMAN)
341 *t++ = 'M';
342 else
343 *t++ = ' ';
344
345 if (r->caps & MIX_CAP_NEWSPOST)
346 {
347 *t++ = 'N';
348 *t++ = 'p';
349 }
350 else
351 {
352 *t++ = ' ';
353 *t++ = ' ';
354 }
355
356 if (r->caps & MIX_CAP_NEWSMAIL)
357 {
358 *t++ = 'N';
359 *t++ = 'm';
360 }
361 else
362 {
363 *t++ = ' ';
364 *t++ = ' ';
365 }
366
367 *t = '\0';
368
369 return capbuff;
370 }
371
372 /*
373 * Format an entry for the remailer menu.
374 *
375 * %n number
376 * %c capabilities
377 * %s short name
378 * %a address
379 *
380 */
381
382 static const char *mix_entry_fmt (char *dest,
383 size_t destlen,
384 size_t col,
385 char op,
386 const char *src,
387 const char *prefix,
388 const char *ifstring,
389 const char *elsestring,
390 unsigned long data,
391 format_flag flags)
392 {
393 char fmt[16];
394 REMAILER *remailer = (REMAILER *) data;
395 int optional = (flags & M_FORMAT_OPTIONAL);
396
397 switch (op)
398 {
399 case 'n':
400 if (!optional)
401 {
402 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
403 snprintf (dest, destlen, fmt, remailer->num);
404 }
405 break;
406 case 'c':
407 if (!optional)
408 {
409 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
410 snprintf (dest, destlen, fmt, mix_format_caps(remailer));
411 }
412 break;
413 case 's':
414 if (!optional)
415 {
416 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
417 snprintf (dest, destlen, fmt, NONULL(remailer->shortname));
418 }
419 else if (!remailer->shortname)
420 optional = 0;
421 break;
422 case 'a':
423 if (!optional)
424 {
425 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
426 snprintf (dest, destlen, fmt, NONULL(remailer->addr));
427 }
428 else if (!remailer->addr)
429 optional = 0;
430 break;
431
432 default:
433 *dest = '\0';
434 }
435
436 if (optional)
437 mutt_FormatString (dest, destlen, col, ifstring, mutt_attach_fmt, data, 0);
438 else if (flags & M_FORMAT_OPTIONAL)
439 mutt_FormatString (dest, destlen, col, elsestring, mutt_attach_fmt, data, 0);
440 return (src);
441 }
442
443
444
445 static void mix_entry (char *b, size_t blen, MUTTMENU *menu, int num)
446 {
447 REMAILER **type2_list = (REMAILER **) menu->data;
448 mutt_FormatString (b, blen, 0, NONULL (MixEntryFormat), mix_entry_fmt,
449 (unsigned long) type2_list[num], M_FORMAT_ARROWCURSOR);
450 }
451
452 static int mix_chain_add (MIXCHAIN *chain, const char *s,
453 REMAILER **type2_list)
454 {
455 int i;
456
457 if (chain->cl >= MAXMIXES)
458 return -1;
459
460 if (!mutt_strcmp (s, "0") || !ascii_strcasecmp (s, "<random>"))
461 {
462 chain->ch[chain->cl++] = 0;
463 return 0;
464 }
465
466 for (i = 0; type2_list[i]; i++)
467 {
468 if (!ascii_strcasecmp (s, type2_list[i]->shortname))
469 {
470 chain->ch[chain->cl++] = i;
471 return 0;
472 }
473 }
474
475 /* replace unknown remailers by <random> */
476
477 if (!type2_list[i])
478 chain->ch[chain->cl++] = 0;
479
480 return 0;
481 }
482
483 static struct mapping_t RemailerHelp[] =
484 {
485 { N_("Append"), OP_MIX_APPEND },
486 { N_("Insert"), OP_MIX_INSERT },
487 { N_("Delete"), OP_MIX_DELETE },
488 { N_("Abort"), OP_EXIT },
489 { N_("OK"), OP_MIX_USE },
647ac54 Imported Upstream version 1.5.20
Antonio Radici authored
490 { NULL, 0 }
14c2920 Imported Upstream version 1.5.18
Antonio Radici authored
491 };
492
493
494 void mix_make_chain (LIST **chainp, int *redraw)
495 {
496 LIST *p;
497 MIXCHAIN *chain;
498 int c_cur = 0, c_old = 0;
499 int m_len;
500 short c_redraw = 1;
501
502 REMAILER **type2_list = NULL;
503 size_t ttll = 0;
504
505 struct coord *coords = NULL;
506
507 MUTTMENU *menu;
508 char helpstr[LONG_STRING];
509 short loop = 1;
510 int op;
511
512 int i, j;
513 char *t;
514
515 if (!(type2_list = mix_type2_list (&ttll)))
516 {
517 mutt_error _("Can't get mixmaster's type2.list!");
518 return;
519 }
520
521 *redraw = REDRAW_FULL;
522
523 chain = safe_calloc (sizeof (MIXCHAIN), 1);
524 for (p = *chainp; p; p = p->next)
525 mix_chain_add (chain, (char *) p->data, type2_list);
526
527 mutt_free_list (chainp);
528
529 /* safety check */
530 for (i = 0; i < chain->cl; i++)
531 {
532 if (chain->ch[i] >= ttll)
533 chain->ch[i] = 0;
534 }
535
536 mix_screen_coordinates (type2_list, &coords, chain, 0);
537
19304f7 Imported Upstream version 1.5.19
Antonio Radici authored
538 menu = mutt_new_menu (MENU_MIX);
14c2920 Imported Upstream version 1.5.18
Antonio Radici authored
539 menu->max = ttll;
540 menu->make_entry = mix_entry;
541 menu->tag = NULL;
542 menu->title = _("Select a remailer chain.");
543 menu->data = type2_list;
544 menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_MIX, RemailerHelp);
545
546 m_len = menu->pagelen = MIX_VOFFSET - menu->offset - 1;
547
548 while (loop)
549 {
550 if (menu->pagelen != m_len)
551 {
552 menu->pagelen = m_len;
553 menu->redraw = REDRAW_FULL;
554 }
555
556 if (c_redraw)
557 {
558 mix_redraw_head (chain);
559 mix_redraw_chain (type2_list, coords, chain, c_cur);
560 c_redraw = 0;
561 }
562 else if (c_cur != c_old)
563 {
564 mix_redraw_ce (type2_list, coords, chain, c_old, 0);
565 mix_redraw_ce (type2_list, coords, chain, c_cur, 1);
566 }
567
568 c_old = c_cur;
569
570 switch ((op = mutt_menuLoop (menu)))
571 {
572 case OP_REDRAW:
573 {
574 menu_redraw_status (menu);
575 mix_redraw_head (chain);
576 mix_screen_coordinates (type2_list, &coords, chain, 0);
577 mix_redraw_chain (type2_list, coords, chain, c_cur);
578 menu->pagelen = m_len = MIX_VOFFSET - menu->offset - 1;
579 break;
580 }
581
582 case OP_EXIT:
583 {
584 chain->cl = 0;
585 loop = 0;
586 break;
587 }
588
589 case OP_MIX_USE:
590 {
591 if (!chain->cl)
592 {
593 chain->cl++;
594 chain->ch[0] = menu->current;
595 mix_screen_coordinates (type2_list, &coords, chain, c_cur);
596 c_redraw = 1;
597 }
598
599 if (chain->cl && chain->ch[chain->cl - 1] &&
600 (type2_list[chain->ch[chain->cl-1]]->caps & MIX_CAP_MIDDLEMAN))
601 {
602 mutt_error ( _("Error: %s can't be used as the final remailer of a chain."),
603 type2_list[chain->ch[chain->cl - 1]]->shortname);
604 }
605 else
606 {
607 loop = 0;
608 }
609 break;
610 }
611
612 case OP_GENERIC_SELECT_ENTRY:
613 case OP_MIX_APPEND:
614 {
615 if (chain->cl < MAXMIXES && c_cur < chain->cl)
616 c_cur++;
617 }
618 /* fallthrough */
619 case OP_MIX_INSERT:
620 {
621 if (chain->cl < MAXMIXES)
622 {
623 chain->cl++;
624 for (i = chain->cl - 1; i > c_cur; i--)
625 chain->ch[i] = chain->ch[i-1];
626
627 chain->ch[c_cur] = menu->current;
628 mix_screen_coordinates (type2_list, &coords, chain, c_cur);
629 c_redraw = 1;
630 }
631 else
632 mutt_error ( _("Mixmaster chains are limited to %d elements."),
633 MAXMIXES);
634
635 break;
636 }
637
638 case OP_MIX_DELETE:
639 {
640 if (chain->cl)
641 {
642 chain->cl--;
643
644 for (i = c_cur; i < chain->cl; i++)
645 chain->ch[i] = chain->ch[i+1];
646
647 if (c_cur == chain->cl && c_cur)
648 c_cur--;
649
650 mix_screen_coordinates (type2_list, &coords, chain, c_cur);
651 c_redraw = 1;
652 }
653 else
654 {
655 mutt_error _("The remailer chain is already empty.");
656 }
657 break;
658 }
659
660 case OP_MIX_CHAIN_PREV:
661 {
662 if (c_cur)
663 c_cur--;
664 else
665 mutt_error _("You already have the first chain element selected.");
666
667 break;
668 }
669
670 case OP_MIX_CHAIN_NEXT:
671 {
672 if (chain->cl && c_cur < chain->cl - 1)
673 c_cur++;
674 else
675 mutt_error _("You already have the last chain element selected.");
676
677 break;
678 }
679 }
680 }
681
682 mutt_menuDestroy (&menu);
683
684 /* construct the remailer list */
685
686 if (chain->cl)
687 {
688 for (i = 0; i < chain->cl; i++)
689 {
690 if ((j = chain->ch[i]))
691 t = type2_list[j]->shortname;
692 else
693 t = "*";
694
695 *chainp = mutt_add_list (*chainp, t);
696 }
697 }
698
699 mix_free_type2_list (&type2_list);
700 FREE (&coords);
701 FREE (&chain);
702 }
703
704 /* some safety checks before piping the message to mixmaster */
705
706 int mix_check_message (HEADER *msg)
707 {
708 const char *fqdn;
709 short need_hostname = 0;
710 ADDRESS *p;
711
712 if (msg->env->cc || msg->env->bcc)
713 {
714 mutt_error _("Mixmaster doesn't accept Cc or Bcc headers.");
715 return -1;
716 }
717
718 /* When using mixmaster, we MUST qualify any addresses since
719 * the message will be delivered through remote systems.
720 *
721 * use_domain won't be respected at this point, hidden_host will.
722 */
723
724 for (p = msg->env->to; p; p = p->next)
725 {
726 if (!p->group && strchr (p->mailbox, '@') == NULL)
727 {
728 need_hostname = 1;
729 break;
730 }
731 }
732
733 if (need_hostname)
734 {
735
736 if (!(fqdn = mutt_fqdn (1)))
737 {
738 mutt_error _("Please set the hostname variable to a proper value when using mixmaster!");
739 return (-1);
740 }
741
742 /* Cc and Bcc are empty at this point. */
743 rfc822_qualify (msg->env->to, fqdn);
744 rfc822_qualify (msg->env->reply_to, fqdn);
745 rfc822_qualify (msg->env->mail_followup_to, fqdn);
746 }
747
748 return 0;
749 }
750
751 int mix_send_message (LIST *chain, const char *tempfile)
752 {
753 char cmd[HUGE_STRING];
754 char tmp[HUGE_STRING];
755 char cd_quoted[STRING];
756 int i;
757
758 snprintf (cmd, sizeof (cmd), "cat %s | %s -m ", tempfile, Mixmaster);
759
760 for (i = 0; chain; chain = chain->next, i = 1)
761 {
762 strfcpy (tmp, cmd, sizeof (tmp));
763 mutt_quote_filename (cd_quoted, sizeof (cd_quoted), (char *) chain->data);
764 snprintf (cmd, sizeof (cmd), "%s%s%s", tmp, i ? "," : " -l ", cd_quoted);
765 }
766
767 if (!option (OPTNOCURSES))
768 mutt_endwin (NULL);
769
770 if ((i = mutt_system (cmd)))
771 {
772 fprintf (stderr, _("Error sending message, child exited %d.\n"), i);
773 if (!option (OPTNOCURSES))
774 {
775 mutt_any_key_to_continue (NULL);
776 mutt_error _("Error sending message.");
777 }
778 }
779
780 unlink (tempfile);
781 return i;
782 }
783
784
785 #endif
Something went wrong with that request. Please try again.