2 * Copyright notice from original mutt:
3 * Copyright (C) 1999-2000 Thomas Roessler <roessler@does-not-exist.org>
5 * This file is part of mutt-ng, see http://www.muttng.org/.
6 * It's licensed under the GNU General Public License,
7 * please see the file GPL in the top level source directory.
11 * Mixmaster support for Mutt
19 #include "recvattach.h"
20 #include "mutt_curses.h"
21 #include "mutt_menu.h"
35 #include <sys/types.h>
39 #define SW (option(OPTMBOXPANE)?SidebarWidth:0)
47 static REMAILER **mix_type2_list (size_t * l);
48 static REMAILER *mix_new_remailer (void);
49 static const char *mix_format_caps (REMAILER * r);
50 static int mix_chain_add (MIXCHAIN * chain, const char *s,
51 REMAILER ** type2_list);
52 static int mix_get_caps (const char *capstr);
53 static void mix_add_entry (REMAILER ***, REMAILER *, size_t *, size_t *);
54 static void mix_entry (char *b, size_t blen, MUTTMENU * menu, int num);
55 static void mix_free_remailer (REMAILER ** r);
56 static void mix_free_type2_list (REMAILER *** ttlp);
57 static void mix_redraw_ce (REMAILER ** type2_list, struct coord *coords,
58 MIXCHAIN * chain, int i, short selected);
59 static void mix_redraw_chain (REMAILER ** type2_list, struct coord *coords,
60 MIXCHAIN * chain, int cur);
61 static void mix_redraw_head (MIXCHAIN *);
62 static void mix_screen_coordinates (REMAILER ** type2_list, struct coord **,
65 static int mix_get_caps (const char *capstr)
72 caps |= MIX_CAP_COMPRESS;
76 caps |= MIX_CAP_MIDDLEMAN;
83 caps |= MIX_CAP_NEWSMAIL;
87 caps |= MIX_CAP_NEWSPOST;
101 static void mix_add_entry (REMAILER *** type2_list, REMAILER * entry,
102 size_t * slots, size_t * used)
104 if (*used == *slots) {
106 mem_realloc (type2_list, sizeof (REMAILER *) * (*slots));
109 (*type2_list)[(*used)++] = entry;
114 static REMAILER *mix_new_remailer (void)
116 return mem_calloc (1, sizeof (REMAILER));
119 static void mix_free_remailer (REMAILER ** r)
121 mem_free (&(*r)->shortname);
122 mem_free (&(*r)->addr);
123 mem_free (&(*r)->ver);
128 /* parse the type2.list as given by mixmaster -T */
130 static REMAILER **mix_type2_list (size_t * l)
136 char cmd[HUGE_STRING + _POSIX_PATH_MAX];
137 char line[HUGE_STRING];
140 REMAILER **type2_list = NULL, *p;
141 size_t slots = 0, used = 0;
146 if ((devnull = open ("/dev/null", O_RDWR)) == -1)
149 snprintf (cmd, sizeof (cmd), "%s -T", Mixmaster);
152 mutt_create_filter_fd (cmd, NULL, &fp, NULL, devnull, -1,
158 /* first, generate the "random" remailer */
160 p = mix_new_remailer ();
161 p->shortname = str_dup ("<random>");
162 mix_add_entry (&type2_list, p, &slots, &used);
164 while (fgets (line, sizeof (line), fp)) {
165 p = mix_new_remailer ();
167 if (!(t = strtok (line, " \t\n")))
170 p->shortname = str_dup (t);
172 if (!(t = strtok (NULL, " \t\n")))
175 p->addr = str_dup (t);
177 if (!(t = strtok (NULL, " \t\n")))
180 if (!(t = strtok (NULL, " \t\n")))
183 p->ver = str_dup (t);
185 if (!(t = strtok (NULL, " \t\n")))
188 p->caps = mix_get_caps (t);
190 mix_add_entry (&type2_list, p, &slots, &used);
194 mix_free_remailer (&p);
199 mix_add_entry (&type2_list, NULL, &slots, &used);
200 mutt_wait_filter (mm_pid);
207 static void mix_free_type2_list (REMAILER *** ttlp)
210 REMAILER **type2_list = *ttlp;
212 for (i = 0; type2_list[i]; i++)
213 mix_free_remailer (&type2_list[i]);
215 mem_free (type2_list);
219 #define MIX_HOFFSET 2
220 #define MIX_VOFFSET (LINES - 6)
221 #define MIX_MAXROW (LINES - 3)
224 static void mix_screen_coordinates (REMAILER ** type2_list,
225 struct coord **coordsp,
226 MIXCHAIN * chain, int i)
229 struct coord *coords;
234 mem_realloc (coordsp, sizeof (struct coord) * chain->cl);
240 coords[i - 1].c + str_len (type2_list[chain->ch[i - 1]]->shortname) + 2;
249 for (; i < chain->cl; i++) {
251 c += str_len (type2_list[chain->ch[i]]->shortname) + 2;
254 oc = c = MIX_HOFFSET;
265 static void mix_redraw_ce (REMAILER ** type2_list,
266 struct coord *coords,
267 MIXCHAIN * chain, int i, short selected)
269 if (!coords || !chain)
272 if (coords[i].r < MIX_MAXROW) {
275 SETCOLOR (MT_COLOR_INDICATOR);
277 SETCOLOR (MT_COLOR_NORMAL);
279 mvaddstr (coords[i].r, coords[i].c, type2_list[chain->ch[i]]->shortname);
280 SETCOLOR (MT_COLOR_NORMAL);
282 if (i + 1 < chain->cl)
287 static void mix_redraw_chain (REMAILER ** type2_list,
288 struct coord *coords, MIXCHAIN * chain, int cur)
292 SETCOLOR (MT_COLOR_NORMAL);
293 BKGDSET (MT_COLOR_NORMAL);
295 for (i = MIX_VOFFSET; i < MIX_MAXROW; i++) {
300 for (i = 0; i < chain->cl; i++)
301 mix_redraw_ce (type2_list, coords, chain, i, i == cur);
304 static void mix_redraw_head (MIXCHAIN * chain)
306 SETCOLOR (MT_COLOR_STATUS);
307 mvprintw (MIX_VOFFSET - 1, 0, "-- Remailer chain [Length: %d]",
308 chain ? chain->cl : 0);
310 BKGDSET (MT_COLOR_STATUS);
313 BKGDSET (MT_COLOR_NORMAL);
314 SETCOLOR (MT_COLOR_NORMAL);
317 static const char *mix_format_caps (REMAILER * r)
319 static char capbuff[10];
322 if (r->caps & MIX_CAP_COMPRESS)
327 if (r->caps & MIX_CAP_MIDDLEMAN)
332 if (r->caps & MIX_CAP_NEWSPOST) {
341 if (r->caps & MIX_CAP_NEWSMAIL) {
356 * Format an entry for the remailer menu.
365 static const char *mix_entry_fmt (char *dest,
370 const char *ifstring,
371 const char *elsestring,
372 unsigned long data, format_flag flags)
375 REMAILER *remailer = (REMAILER *) data;
376 int optional = (flags & M_FORMAT_OPTIONAL);
381 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
382 snprintf (dest, destlen, fmt, remailer->num);
387 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
388 snprintf (dest, destlen, fmt, mix_format_caps (remailer));
393 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
394 snprintf (dest, destlen, fmt, NONULL (remailer->shortname));
396 else if (!remailer->shortname)
401 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
402 snprintf (dest, destlen, fmt, NONULL (remailer->addr));
404 else if (!remailer->addr)
413 mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
414 else if (flags & M_FORMAT_OPTIONAL)
415 mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
421 static void mix_entry (char *b, size_t blen, MUTTMENU * menu, int num)
423 REMAILER **type2_list = (REMAILER **) menu->data;
424 int w=(COLS-SW)>blen?blen:(COLS-SW);
426 mutt_FormatString (b, w, NONULL (MixEntryFormat), mix_entry_fmt,
427 (unsigned long) type2_list[num], M_FORMAT_ARROWCURSOR);
430 static int mix_chain_add (MIXCHAIN * chain, const char *s,
431 REMAILER ** type2_list)
435 if (chain->cl >= MAXMIXES)
438 if (!str_cmp (s, "0") || !ascii_strcasecmp (s, "<random>")) {
439 chain->ch[chain->cl++] = 0;
443 for (i = 0; type2_list[i]; i++) {
444 if (!ascii_strcasecmp (s, type2_list[i]->shortname)) {
445 chain->ch[chain->cl++] = i;
450 /* replace unknown remailers by <random> */
453 chain->ch[chain->cl++] = 0;
458 static struct mapping_t RemailerHelp[] = {
459 {N_("Append"), OP_MIX_APPEND},
460 {N_("Insert"), OP_MIX_INSERT},
461 {N_("Delete"), OP_MIX_DELETE},
462 {N_("Abort"), OP_EXIT},
463 {N_("OK"), OP_MIX_USE},
468 void mix_make_chain (LIST ** chainp, int *redraw)
472 int c_cur = 0, c_old = 0;
476 REMAILER **type2_list = NULL;
479 struct coord *coords = NULL;
482 char helpstr[SHORT_STRING];
489 if (!(type2_list = mix_type2_list (&ttll))) {
490 mutt_error _("Can't get mixmaster's type2.list!");
495 *redraw = REDRAW_FULL;
497 chain = mem_calloc (sizeof (MIXCHAIN), 1);
498 for (p = *chainp; p; p = p->next)
499 mix_chain_add (chain, (char *) p->data, type2_list);
501 mutt_free_list (chainp);
504 for (i = 0; i < chain->cl; i++) {
505 if (chain->ch[i] >= ttll)
509 mix_screen_coordinates (type2_list, &coords, chain, 0);
511 menu = mutt_new_menu ();
512 menu->menu = MENU_MIX;
514 menu->make_entry = mix_entry;
516 menu->title = _("Select a remailer chain.");
517 menu->data = type2_list;
519 mutt_compile_help (helpstr, sizeof (helpstr), MENU_MIX, RemailerHelp);
521 m_len = menu->pagelen = MIX_VOFFSET - menu->offset - 1;
524 if (menu->pagelen != m_len) {
525 menu->pagelen = m_len;
526 menu->redraw = REDRAW_FULL;
530 mix_redraw_head (chain);
531 mix_redraw_chain (type2_list, coords, chain, c_cur);
534 else if (c_cur != c_old) {
535 mix_redraw_ce (type2_list, coords, chain, c_old, 0);
536 mix_redraw_ce (type2_list, coords, chain, c_cur, 1);
541 switch ((op = mutt_menuLoop (menu))) {
544 menu_redraw_status (menu);
545 mix_redraw_head (chain);
546 mix_screen_coordinates (type2_list, &coords, chain, 0);
547 mix_redraw_chain (type2_list, coords, chain, c_cur);
548 menu->pagelen = m_len = MIX_VOFFSET - menu->offset - 1;
563 chain->ch[0] = menu->current;
564 mix_screen_coordinates (type2_list, &coords, chain, c_cur);
568 if (chain->cl && chain->ch[chain->cl - 1] &&
569 (type2_list[chain->ch[chain->cl - 1]]->caps & MIX_CAP_MIDDLEMAN))
572 ("Error: %s can't be used as the final remailer of a chain."),
573 type2_list[chain->ch[chain->cl - 1]]->shortname);
581 case OP_GENERIC_SELECT_ENTRY:
584 if (chain->cl < MAXMIXES && c_cur < chain->cl)
590 if (chain->cl < MAXMIXES) {
592 for (i = chain->cl - 1; i > c_cur; i--)
593 chain->ch[i] = chain->ch[i - 1];
595 chain->ch[c_cur] = menu->current;
596 mix_screen_coordinates (type2_list, &coords, chain, c_cur);
600 mutt_error (_("Mixmaster chains are limited to %d elements."),
611 for (i = c_cur; i < chain->cl; i++)
612 chain->ch[i] = chain->ch[i + 1];
614 if (c_cur == chain->cl && c_cur)
617 mix_screen_coordinates (type2_list, &coords, chain, c_cur);
621 mutt_error _("The remailer chain is already empty.");
626 case OP_MIX_CHAIN_PREV:
631 mutt_error _("You already have the first chain element selected.");
636 case OP_MIX_CHAIN_NEXT:
638 if (chain->cl && c_cur < chain->cl - 1)
641 mutt_error _("You already have the last chain element selected.");
648 mutt_menuDestroy (&menu);
650 /* construct the remailer list */
653 for (i = 0; i < chain->cl; i++) {
654 if ((j = chain->ch[i]))
655 t = type2_list[j]->shortname;
659 *chainp = mutt_add_list (*chainp, t);
663 mix_free_type2_list (&type2_list);
668 /* some safety checks before piping the message to mixmaster */
670 int mix_check_message (HEADER * msg)
673 short need_hostname = 0;
676 if (msg->env->cc || msg->env->bcc) {
677 mutt_error _("Mixmaster doesn't accept Cc or Bcc headers.");
682 /* When using mixmaster, we MUST qualify any addresses since
683 * the message will be delivered through remote systems.
685 * use_domain won't be respected at this point, hidden_host will.
688 for (p = msg->env->to; p; p = p->next) {
689 if (!p->group && strchr (p->mailbox, '@') == NULL) {
697 if (!(fqdn = mutt_fqdn (1))) {
700 ("Please set the hostname variable to a proper value when using mixmaster!");
704 /* Cc and Bcc are empty at this point. */
705 rfc822_qualify (msg->env->to, fqdn);
706 rfc822_qualify (msg->env->reply_to, fqdn);
707 rfc822_qualify (msg->env->mail_followup_to, fqdn);
713 int mix_send_message (LIST * chain, const char *tempfile)
715 char cmd[HUGE_STRING];
716 char tmp[HUGE_STRING];
717 char cd_quoted[STRING];
720 snprintf (cmd, sizeof (cmd), "cat %s | %s -m ", tempfile, Mixmaster);
722 for (i = 0; chain; chain = chain->next, i = 1) {
723 strfcpy (tmp, cmd, sizeof (tmp));
724 mutt_quote_filename (cd_quoted, sizeof (cd_quoted), (char *) chain->data);
725 snprintf (cmd, sizeof (cmd), "%s%s%s", tmp, i ? "," : " -l ", cd_quoted);
728 if (!option (OPTNOCURSES))
731 if ((i = mutt_system (cmd))) {
732 fprintf (stderr, _("Error sending message, child exited %d.\n"), i);
733 if (!option (OPTNOCURSES)) {
734 mutt_any_key_to_continue (NULL);
735 mutt_error _("Error sending message.");