diff options
author | Thomas Roessler <roessler@does-not-exist.org> | 1999-01-13 01:53:03 +0000 |
---|---|---|
committer | Thomas Roessler <roessler@does-not-exist.org> | 1999-01-13 01:53:03 +0000 |
commit | 822535edf4b160d9f023fd2026c824ef061f4ea5 (patch) | |
tree | d2bc1f73f47c95b140c4c0ea0be42b70f26880fe /remailer.c | |
parent | a983c11963da7df7c9e4a99e54084a2cf4a1b176 (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.c | 683 |
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 |