summaryrefslogtreecommitdiffstats
path: root/remailer.c
diff options
context:
space:
mode:
authorThomas Roessler <roessler@does-not-exist.org>1999-01-13 01:53:03 +0000
committerThomas Roessler <roessler@does-not-exist.org>1999-01-13 01:53:03 +0000
commit822535edf4b160d9f023fd2026c824ef061f4ea5 (patch)
treed2bc1f73f47c95b140c4c0ea0be42b70f26880fe /remailer.c
parenta983c11963da7df7c9e4a99e54084a2cf4a1b176 (diff)
A first take at adding a mixmaster front-end to mutt. Don't worry,
it's optional. ;-)
Diffstat (limited to 'remailer.c')
-rw-r--r--remailer.c683
1 files changed, 683 insertions, 0 deletions
diff --git a/remailer.c b/remailer.c
new file mode 100644
index 00000000..f216b9ae
--- /dev/null
+++ b/remailer.c
@@ -0,0 +1,683 @@
+/*
+ * Copyright (C) 1999 Thomas Roessler <roessler@guug.de>
+ *
+ * This program is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
+ * 02139, USA.
+ */
+
+/*
+ * Mixmaster support for Mutt
+ */
+
+#include "mutt.h"
+#include "mutt_curses.h"
+#include "mutt_menu.h"
+#include "mapping.h"
+
+#include "remailer.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <fcntl.h>
+
+#ifdef MIXMASTER
+
+struct coord
+{
+ short r, c;
+};
+
+static REMAILER **mix_type2_list (size_t *l);
+static REMAILER *mix_new_remailer (void);
+static const char *mix_format_caps (REMAILER *r);
+static int mix_get_caps (const char *capstr);
+static void mix_add_entry (REMAILER ***, REMAILER *, size_t *, size_t *);
+static int mix_chain_add (MIXCHAIN *chain, const char *s, REMAILER **type2_list);
+static void mix_entry (char *b, size_t blen, MUTTMENU *menu, int num);
+static void mix_free_remailer (REMAILER **r);
+static void mix_free_type2_list (REMAILER ***ttlp);
+static void mix_redraw_ce (REMAILER **type2_list, struct coord *coords, MIXCHAIN *chain, int i, short selected);
+static void mix_redraw_chain (REMAILER **type2_list, struct coord *coords, MIXCHAIN *chain, int cur);
+static void mix_redraw_head (MIXCHAIN *);
+static void mix_screen_coordinates (REMAILER **type2_list, struct coord **, MIXCHAIN *, int);
+
+static int mix_get_caps (const char *capstr)
+{
+ int caps = 0;
+
+ while (*capstr)
+ {
+ switch (*capstr)
+ {
+ case 'C':
+ caps |= MIX_CAP_COMPRESS;
+ break;
+
+ case 'M':
+ caps |= MIX_CAP_MIDDLEMAN;
+ break;
+
+ case 'N':
+ {
+ switch (*++capstr)
+ {
+ case 'm':
+ caps |= MIX_CAP_NEWSMAIL;
+ break;
+
+ case 'p':
+ caps |= MIX_CAP_NEWSPOST;
+ break;
+
+ }
+ }
+ }
+
+ if (*capstr) capstr++;
+ }
+
+ return caps;
+}
+
+static void mix_add_entry (REMAILER ***type2_list, REMAILER *entry,
+ size_t *slots, size_t *used)
+{
+ if (*used == *slots)
+ {
+ *slots += 5;
+ safe_realloc ((void **) type2_list, sizeof (REMAILER *) * (*slots));
+ }
+
+ (*type2_list)[(*used)++] = entry;
+}
+
+static REMAILER *mix_new_remailer (void)
+{
+ return safe_calloc (1, sizeof (REMAILER));
+}
+
+static void mix_free_remailer (REMAILER **r)
+{
+ safe_free ((void **) &(*r)->shortname);
+ safe_free ((void **) &(*r)->addr);
+ safe_free ((void **) &(*r)->ver);
+
+ safe_free ((void **) r);
+}
+
+/* parse the type2.list as given by mixmaster -T */
+
+static REMAILER **mix_type2_list (size_t *l)
+{
+ FILE *fp;
+ pid_t mm_pid;
+ int devnull;
+
+ char cmd[HUGE_STRING + _POSIX_PATH_MAX];
+ char line[HUGE_STRING];
+ char *t;
+
+ REMAILER **type2_list = NULL, *p;
+ size_t slots = 0, used = 0;
+
+ if (!l)
+ return NULL;
+
+ if ((devnull = open ("/dev/null", O_RDWR)) == -1)
+ return NULL;
+
+ snprintf (cmd, sizeof (cmd), "%s -T", Mixmaster);
+
+ if ((mm_pid = mutt_create_filter_fd (cmd, NULL, &fp, NULL, devnull, -1, devnull)) == -1)
+ {
+ close (devnull);
+ return NULL;
+ }
+
+ /* first, generate the "random" remailer */
+
+ p = mix_new_remailer ();
+ p->shortname = safe_strdup ("<random>");
+ mix_add_entry (&type2_list, p, &slots, &used);
+
+ while (fgets (line, sizeof (line), fp))
+ {
+ p = mix_new_remailer ();
+
+ if (!(t = strtok (line, " \t\n")))
+ goto problem;
+
+ p->shortname = safe_strdup (t);
+
+ if (!(t = strtok (NULL, " \t\n")))
+ goto problem;
+
+ p->addr = safe_strdup (t);
+
+ if (!(t = strtok (NULL, " \t\n")))
+ goto problem;
+
+ if (!(t = strtok (NULL, " \t\n")))
+ goto problem;
+
+ p->ver = safe_strdup (t);
+
+ if (!(t = strtok (NULL, " \t\n")))
+ goto problem;
+
+ p->caps = mix_get_caps (t);
+
+ mix_add_entry (&type2_list, p, &slots, &used);
+ continue;
+
+ problem:
+ mix_free_remailer (&p);
+ }
+
+ *l = used;
+
+ mix_add_entry (&type2_list, NULL, &slots, &used);
+ mutt_wait_filter (mm_pid);
+
+ close (devnull);
+
+ return type2_list;
+}
+
+static void mix_free_type2_list (REMAILER ***ttlp)
+{
+ int i;
+ REMAILER **type2_list = *ttlp;
+
+ for (i = 0; type2_list[i]; i++)
+ mix_free_remailer (&type2_list[i]);
+
+ safe_free ((void **) type2_list);
+}
+
+
+#define MIX_HOFFSET 2
+#define MIX_VOFFSET (LINES - 6)
+#define MIX_MAXROW (LINES - 3)
+
+
+static void mix_screen_coordinates (REMAILER **type2_list,
+ struct coord **coordsp,
+ MIXCHAIN *chain,
+ int i)
+{
+ short c, r, oc;
+ struct coord *coords;
+
+ if (!chain->cl)
+ return;
+
+ safe_realloc ((void **) coordsp, sizeof (struct coord) * chain->cl);
+
+ coords = *coordsp;
+
+ if (i)
+ {
+ c = coords[i-1].c + strlen (type2_list[chain->ch[i-1]]->shortname) + 2;
+ r = coords[i-1].r;
+ }
+ else
+ {
+ r = MIX_VOFFSET;
+ c = MIX_HOFFSET;
+ }
+
+
+ for (; i < chain->cl; i++)
+ {
+ oc = c;
+ c += strlen (type2_list[chain->ch[i]]->shortname) + 2;
+
+ if (c >= COLS)
+ {
+ oc = c = MIX_HOFFSET;
+ r++;
+ }
+
+ coords[i].c = oc;
+ coords[i].r = r;
+
+ }
+
+}
+
+static void mix_redraw_ce (REMAILER **type2_list,
+ struct coord *coords,
+ MIXCHAIN *chain,
+ int i,
+ short selected)
+{
+ if (!coords || !chain)
+ return;
+
+ if (coords[i].r < MIX_MAXROW)
+ {
+
+ if (selected)
+ SETCOLOR (MT_COLOR_INDICATOR);
+ else
+ SETCOLOR (MT_COLOR_NORMAL);
+
+ mvaddstr (coords[i].r, coords[i].c, type2_list[chain->ch[i]]->shortname);
+ SETCOLOR (MT_COLOR_NORMAL);
+
+ if (i + 1 < chain->cl)
+ addstr (", ");
+ }
+}
+
+static void mix_redraw_chain (REMAILER **type2_list,
+ struct coord *coords,
+ MIXCHAIN *chain,
+ int cur)
+{
+ int i;
+
+ SETCOLOR (MT_COLOR_NORMAL);
+ BKGDSET (MT_COLOR_NORMAL);
+
+ for (i = MIX_VOFFSET; i < MIX_MAXROW; i++)
+ {
+ move (i, 0);
+ clrtoeol ();
+ }
+
+ for (i = 0; i < chain->cl; i++)
+ mix_redraw_ce (type2_list, coords, chain, i, i == cur);
+}
+
+static void mix_redraw_head (MIXCHAIN *chain)
+{
+ SETCOLOR (MT_COLOR_STATUS);
+ mvprintw (MIX_VOFFSET - 1, 0, "-- Remailer chain [Length: %d]", chain ? chain->cl : 0);
+
+ BKGDSET (MT_COLOR_STATUS);
+ clrtoeol ();
+
+ BKGDSET (MT_COLOR_NORMAL);
+ SETCOLOR (MT_COLOR_NORMAL);
+}
+
+static const char *mix_format_caps (REMAILER *r)
+{
+ static char capbuff[10];
+ char *t = capbuff;
+
+ if (r->caps & MIX_CAP_COMPRESS)
+ *t++ = 'C';
+ else
+ *t++ = ' ';
+
+ if (r->caps & MIX_CAP_MIDDLEMAN)
+ *t++ = 'M';
+ else
+ *t++ = ' ';
+
+ if (r->caps & MIX_CAP_NEWSPOST)
+ {
+ *t++ = 'N';
+ *t++ = 'p';
+ }
+ else
+ {
+ *t++ = ' ';
+ *t++ = ' ';
+ }
+
+ if (r->caps & MIX_CAP_NEWSMAIL)
+ {
+ *t++ = 'N';
+ *t++ = 'm';
+ }
+ else
+ {
+ *t++ = ' ';
+ *t++ = ' ';
+ }
+
+ *t = '\0';
+
+ return capbuff;
+}
+
+
+static void mix_entry (char *b, size_t blen, MUTTMENU *menu, int num)
+{
+ REMAILER **type2_list = (REMAILER **) menu->data;
+ snprintf (b, blen, "%4d %s %-16s %s",
+ num + 1, mix_format_caps (type2_list[num]),
+ NONULL (type2_list[num]->shortname),
+ NONULL (type2_list[num]->addr));
+}
+
+static int mix_chain_add (MIXCHAIN *chain, const char *s,
+ REMAILER **type2_list)
+{
+ int i;
+
+ if (chain->cl >= MAXMIXES)
+ return -1;
+
+ if (!mutt_strcmp (s, "0") || !mutt_strcasecmp (s, "<random>"))
+ {
+ chain->ch[chain->cl++] = 0;
+ return 0;
+ }
+
+ for (i = 0; type2_list[i]; i++)
+ {
+ if (!mutt_strcasecmp (s, type2_list[i]->shortname))
+ {
+ chain->ch[chain->cl++] = i;
+ return 0;
+ }
+ }
+
+ /* replace unknown remailers by <random> */
+
+ if (!type2_list[i])
+ chain->ch[chain->cl++] = 0;
+
+ return 0;
+}
+
+static struct mapping_t RemailerHelp[] =
+{
+ { N_("Append"), OP_MIX_APPEND },
+ { N_("Insert"), OP_MIX_INSERT },
+ { N_("Delete"), OP_MIX_DELETE },
+ { N_("Abort"), OP_EXIT },
+ { N_("OK"), OP_MIX_USE },
+ { NULL }
+};
+
+
+void mix_make_chain (LIST **chainp, int *redraw)
+{
+ LIST *p;
+ MIXCHAIN *chain;
+ int c_cur = 0, c_old = 0;
+ int m_len;
+ short c_redraw = 1;
+
+ REMAILER **type2_list = NULL;
+ size_t ttll = 0;
+
+ struct coord *coords = NULL;
+
+ MUTTMENU *menu;
+ char helpstr[SHORT_STRING];
+ short loop = 1;
+ int op;
+
+ int i, j;
+ char *t;
+
+ if (!(type2_list = mix_type2_list (&ttll)))
+ {
+ mutt_error _("Can't get mixmaster's type2.list!");
+ return;
+ }
+
+ *redraw = REDRAW_FULL;
+
+ chain = safe_calloc (sizeof (MIXCHAIN), 1);
+ for (p = *chainp; p; p = p->next)
+ mix_chain_add (chain, (char *) p->data, type2_list);
+
+ mutt_free_list (chainp);
+
+ /* safety check */
+ for (i = 0; i < chain->cl; i++)
+ {
+ if (chain->ch[i] >= ttll)
+ chain->ch[i] = 0;
+ }
+
+ mix_screen_coordinates (type2_list, &coords, chain, 0);
+
+ menu = mutt_new_menu ();
+ menu->menu = MENU_MIX;
+ menu->max = ttll;
+ menu->make_entry = mix_entry;
+ menu->tag = NULL;
+ menu->title = _("Select a remailer chain.");
+ menu->data = type2_list;
+ menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_MIX, RemailerHelp);
+
+ m_len = menu->pagelen = MIX_VOFFSET - menu->offset - 1;
+
+ while (loop)
+ {
+ if (menu->pagelen != m_len)
+ {
+ menu->pagelen = m_len;
+ menu->redraw = REDRAW_FULL;
+ }
+
+ if (c_redraw)
+ {
+ mix_redraw_head (chain);
+ mix_redraw_chain (type2_list, coords, chain, c_cur);
+ c_redraw = 0;
+ }
+ else if (c_cur != c_old)
+ {
+ mix_redraw_ce (type2_list, coords, chain, c_old, 0);
+ mix_redraw_ce (type2_list, coords, chain, c_cur, 1);
+ }
+
+ c_old = c_cur;
+
+ switch ((op = mutt_menuLoop (menu)))
+ {
+ case OP_REDRAW:
+ {
+ menu_redraw_status (menu);
+ mix_redraw_head (chain);
+ mix_screen_coordinates (type2_list, &coords, chain, 0);
+ mix_redraw_chain (type2_list, coords, chain, c_cur);
+ menu->pagelen = m_len = MIX_VOFFSET - menu->offset - 1;
+ break;
+ }
+
+ case OP_EXIT:
+ {
+ chain->cl = 0;
+ loop = 0;
+ break;
+ }
+
+ case OP_MIX_USE:
+ {
+ if (chain->cl && chain->ch[chain->cl - 1] &&
+ (type2_list[chain->ch[chain->cl-1]]->caps & MIX_CAP_MIDDLEMAN))
+ {
+ char buff[SHORT_STRING];
+
+ snprintf (buff, sizeof (buff), _("Error: %s can't be used as the final remailer of a chain."),
+ type2_list[chain->ch[chain->cl - 1]]->shortname);
+ mutt_error (buff);
+ }
+ else
+ {
+ loop = 0;
+ }
+ break;
+ }
+
+ case OP_GENERIC_SELECT_ENTRY:
+ case OP_MIX_APPEND:
+ {
+ if (chain->cl < MAXMIXES)
+ {
+ c_cur = chain->cl++;
+ chain->ch[c_cur] = menu->current;
+ mix_screen_coordinates (type2_list, &coords, chain, c_cur);
+ c_redraw = 1;
+ }
+ else
+ {
+ char buff[SHORT_STRING];
+ snprintf (buff, sizeof (buff), _("Mixmaster chains are limited to %d elements."),
+ MAXMIXES);
+ mutt_error (buff);
+ }
+ break;
+ }
+
+ case OP_MIX_INSERT:
+ {
+ if (chain->cl < MAXMIXES)
+ {
+ chain->cl++;
+ for (i = chain->cl - 1; i > c_cur; i--)
+ chain->ch[i] = chain->ch[i-1];
+
+ chain->ch[c_cur] = menu->current;
+ mix_screen_coordinates (type2_list, &coords, chain, c_cur);
+ c_redraw = 1;
+ }
+ else
+ {
+ char buff[SHORT_STRING];
+ snprintf (buff, sizeof (buff), _("Mixmaster chains are limited to %d elements."),
+ MAXMIXES);
+ mutt_error (buff);
+ }
+
+ break;
+ }
+
+ case OP_MIX_DELETE:
+ {
+ if (chain->cl)
+ {
+ chain->cl--;
+
+ for (i = c_cur; i < chain->cl; i++)
+ chain->ch[i] = chain->ch[i+1];
+
+ if (c_cur == chain->cl && c_cur)
+ c_cur--;
+
+ mix_screen_coordinates (type2_list, &coords, chain, c_cur);
+ c_redraw = 1;
+ }
+ else
+ {
+ mutt_error _("The remailer chain is already empty.");
+ }
+ break;
+ }
+
+ case OP_MIX_CHAIN_PREV:
+ {
+ if (c_cur)
+ c_cur--;
+ else
+ mutt_error _("You already have the first chain element selected.");
+
+ break;
+ }
+
+ case OP_MIX_CHAIN_NEXT:
+ {
+ if (chain->cl && c_cur < chain->cl - 1)
+ c_cur++;
+ else
+ mutt_error _("You already have the last chain element selected.");
+
+ break;
+ }
+ }
+ }
+
+ mutt_menuDestroy (&menu);
+
+ /* construct the remailer list */
+
+ if (chain->cl)
+ {
+ for (i = 0; i < chain->cl; i++)
+ {
+ if ((j = chain->ch[i]))
+ t = type2_list[j]->shortname;
+ else
+ t = "0";
+
+ *chainp = mutt_add_list (*chainp, t);
+ }
+ }
+
+ mix_free_type2_list (&type2_list);
+ safe_free ((void **) &coords);
+ safe_free ((void **) &chain);
+}
+
+int mix_check_message (HEADER *msg)
+{
+ if (msg->env->cc || msg->env->bcc)
+ {
+ mutt_error _("Mixmaster doesn't accept Cc or Bcc headers.");
+ return -1;
+ }
+
+ return 0;
+}
+
+int mix_send_message (LIST *chain, const char *tempfile)
+{
+ char cmd[HUGE_STRING];
+ char tmp[HUGE_STRING];
+ int i;
+
+ snprintf (cmd, sizeof (cmd), "cat %s | %s -m -l", tempfile, Mixmaster);
+ for (; chain; chain = chain->next)
+ {
+ strfcpy (tmp, cmd, sizeof (tmp));
+ snprintf (cmd, sizeof (cmd), "%s %s", tmp, (char *) chain->data);
+ }
+
+ if (!option (OPTNOCURSES))
+ endwin ();
+
+ if ((i = mutt_system (cmd)))
+ {
+ fprintf (stderr, _("Error sending message, child exited %d.\n"), i);
+ if (!option (OPTNOCURSES))
+ {
+ mutt_any_key_to_continue (NULL);
+ mutt_error _("Error sending message.");
+ }
+ }
+
+ unlink (tempfile);
+ return i;
+}
+
+
+#endif