mixmaster

mixmaster 3.0 patched for libressl
git clone git://parazyd.org/mixmaster.git
Log | Files | Refs | README

menusend.c (12957B)


      1 /* Mixmaster version 3.0  --  (C) 1999 - 2006 Anonymizer Inc. and others.
      2 
      3    Mixmaster may be redistributed and modified under certain conditions.
      4    This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
      5    ANY KIND, either express or implied. See the file COPYRIGHT for
      6    details.
      7 
      8    Menu-based user interface -- send message
      9    $Id: menusend.c 934 2006-06-24 13:40:39Z rabbi $ */
     10 
     11 
     12 #include "menu.h"
     13 #include "mix3.h"
     14 #include <string.h>
     15 #include <ctype.h>
     16 #include <stdlib.h>
     17 #ifdef POSIX
     18 #include <unistd.h>
     19 #else /* end of POSIX */
     20 #include <io.h>
     21 #endif /* else if not POSIX */
     22 
     23 void send_message(int type, char *nym, BUFFER *in)
     24 {
     25   char dest[LINELEN] = "", subject[LINELEN] = "";
     26   char chain[CHAINMAX], thisnym[LINELEN], path[PATHMAX];
     27   BUFFER *chainlist, *msg, *txt, *tmp, *field, *content, *cc, *cite;
     28   int numcopies;
     29   int hdr = 0;			/* txt buffer contains header lines */
     30   FILE *f;
     31   int n, err;
     32 
     33 #ifdef USE_PGP
     34   int sign = 0, encrypt = 0, key = 0;
     35 
     36 #endif /* USE_PGP */
     37 #ifdef USE_NCURSES
     38   char reliability[9];
     39   int c;
     40   char line[LINELEN];
     41 
     42 #endif /* USE_NCURSES */
     43   msg = buf_new();
     44   tmp = buf_new();
     45   txt = buf_new();
     46   field = buf_new();
     47   content = buf_new();
     48   chainlist = buf_new();
     49   cc = buf_new();
     50   cite = buf_new();
     51   strncpy(chain, CHAIN, CHAINMAX);
     52   numcopies = NUMCOPIES;
     53 
     54   mix_status("");
     55   strncpy(thisnym, nym, sizeof(thisnym));
     56 
     57   if (in != NULL)
     58     buf_set(txt, in);
     59 
     60   if (bufileft(txt, "From "))
     61     buf_getline(txt, field);	/* ignore envelope From */
     62 
     63   if (type == 'p' || type == 'm') {
     64 #ifndef USE_NCURSES
     65     mix_status("Invalid option to -f");
     66     mix_exit();
     67     exit(1);
     68 #else /* end of not USE_NCURSES */
     69     clear();
     70     echo();
     71     if (in != NULL)
     72       mvprintw(1, 0, "%s forwarding message...", thisnym);
     73     if (type == 'p')
     74       mvprintw(3, 0, "Newsgroups: ");
     75     else
     76       mvprintw(3, 0, "Send message to: ");
     77     refresh();
     78     wgetnstr(stdscr, dest, LINELEN);
     79     if (dest[0] == '\0') {
     80       noecho();
     81       cl(3, 0);
     82       goto quit;
     83     }
     84     if (txt->length == 0) {
     85       mvprintw(4, 0, "Subject: ");
     86       refresh();
     87       wgetnstr(stdscr, subject, LINELEN);
     88     } else {
     89       strcpy(subject, "Forwarded message");
     90       while (buf_getheader(txt, field, content) == 0) {
     91 	if (bufieq(field, "subject")) {
     92 	  strncpy(subject, content->data, sizeof(subject));
     93 	  strcatn(subject, " (fwd)", sizeof(subject));
     94 	}
     95 	if (bufieq(field, "from") || bufieq(field, "subject") ||
     96 	    bufieq(field, "date"))
     97 	  buf_appendheader(tmp, field, content);
     98       }
     99       buf_nl(tmp);
    100       buf_rest(tmp, txt);
    101       buf_move(txt, tmp);
    102     }
    103     noecho();
    104 #endif /* else if USE_NCURSES */
    105   } else {
    106     strcpy(subject, "Re: your mail");
    107     while (buf_getheader(txt, field, content) == 0) {
    108       if (bufieq(field, "subject")) {
    109 	if (bufileft(content, "Re:"))
    110 	  subject[0] = '\0';
    111 	else
    112 	  strcpy(subject, "Re: ");
    113 	strcatn(subject, content->data, sizeof(subject));
    114       }
    115       if (bufieq(field, "from"))
    116 	buf_set(cite, content);
    117       if (type == 'p' || type == 'f') {
    118 	if (dest[0] == '\0' && bufieq(field, "newsgroups"))
    119 	  strncpy(dest, content->data, sizeof(dest));
    120 	if (bufieq(field, "followup-to") && !bufieq(content, "poster"))
    121 	  strncpy(dest, content->data, sizeof(dest));
    122 	if (bufieq(field, "message-id"))
    123 	  buf_appendf(tmp, "References: %b\n", content);
    124       } else {
    125 	if (dest[0] == '\0' && bufieq(field, "from"))
    126 	  strncpy(dest, content->data, sizeof(dest));
    127 	if (bufieq(field, "reply-to"))
    128 	  strncpy(dest, content->data, sizeof(dest));
    129 	if (type == 'g' && (bufieq(field, "to") || bufieq(field, "cc"))) {
    130 	  if (cc->length)
    131 	    buf_appends(cc, ", ");
    132 	  buf_cat(cc, content);
    133 	}
    134 	if (bufieq(field, "message-id"))
    135 	  buf_appendf(tmp, "In-Reply-To: %b\n", content);
    136       }
    137     }
    138     if (cc->length)
    139       buf_appendf(tmp, "Cc: %b\n", cc);
    140     if (tmp->length > 0)
    141       hdr = 1;
    142     if (hdr)
    143       buf_nl(tmp);
    144 
    145     if ((type == 'f' || type == 'g') && cite->length) {
    146       buf_appendf(tmp, "%b wrote:\n\n", cite);
    147     }
    148     if (type == 'r')
    149       buf_appends(tmp, "You wrote:\n\n");
    150 
    151     while (buf_getline(txt, content) != -1)
    152       buf_appendf(tmp, "> %b\n", content);
    153     buf_set(txt, tmp);
    154     if (dest[0] == '\0') {
    155 #ifdef USE_NCURSES
    156       beep();
    157       mix_status("No recipient address found.");
    158 #endif /* USE_NCURSES */
    159       goto quit;
    160     }
    161     goto edit;
    162   }
    163 
    164 #ifdef USE_NCURSES
    165 redraw:
    166   clear();
    167 
    168   for (;;) {
    169     standout();
    170     mvprintw(0, 0, "Mixmaster %s - ", VERSION);
    171     printw(type == 'p' || type == 'f' ? "posting to Usenet" : "sending mail");
    172     standend();
    173     mix_status(NULL);
    174     cl(2, 0);
    175 #ifdef NYMSUPPORT
    176     printw("n)ym: %s", thisnym);
    177 #endif /* NYMSUPPORT */
    178     if (!strleft(thisnym, NONANON)) {
    179       chain_reliability(chain, 0, reliability);   /* chaintype 0=mix */
    180       cl(4, 0);
    181       printw("c)hain: %-35s (reliability: %s)", chain, reliability);
    182       cl(5, 0);
    183       printw("r)edundancy: %3d copies ", numcopies);
    184     }
    185     cl(7, 0);
    186     printw("d)estination: %s", dest);
    187     cl(8, 0);
    188     printw("s)ubject: %s", subject);
    189 #ifdef USE_PGP
    190     if (type != 'p' && type != 'f') {
    191       cl(10, 0);
    192       printw("pgp encry)ption: ");
    193       if (encrypt)
    194 	printw("yes");
    195       else
    196 	printw("no");
    197     }
    198     if (!streq(thisnym, ANON)) {
    199       cl(11, 0);
    200       printw("p)gp signature: ");
    201       if (sign)
    202 	printw("yes");
    203       else
    204 	printw("no");
    205       cl(12, 0);
    206       if (key == 0)
    207 	printw("attach pgp k)ey: no");
    208     }
    209 #endif /* USE_PGP */
    210 
    211     if (txt->length == 0)
    212       mvprintw(LINES - 3, 18,
    213 	       "e)dit message           f)ile      q)uit w/o sending");
    214     else
    215       mvprintw(LINES - 3, 0,
    216 	       "m)ail message      e)dit message         f)ile          q)uit w/o sending");
    217     move(LINES - 1, COLS - 1);
    218     refresh();
    219     c = getch();
    220     if (c != ERR) {
    221       mix_status("");
    222       if (c == '\r' || c == '\n') {	/* default action is edit or mail */
    223 	if (txt->length == 0)
    224 	  c = 'e';
    225 	else
    226 	  c = 'm';
    227       }
    228       switch (c) {
    229 #ifdef NYMSUPPORT
    230       case 'n':
    231 	menu_nym(thisnym);
    232 	goto redraw;
    233 #endif /* NYMSUPPORT */
    234       case '\014':
    235 	goto redraw;
    236       case 'd':
    237 	echo();
    238 	cl(LINES - 3, 20);
    239 	cl(7, 14);
    240 	wgetnstr(stdscr, dest, LINELEN);
    241 	noecho();
    242 	break;
    243       case 's':
    244 	echo();
    245 	cl(LINES - 3, 20);
    246 	cl(8, 10);
    247 	wgetnstr(stdscr, subject, LINELEN);
    248 	noecho();
    249 	break;
    250       case 'c':
    251 	menu_chain(chain, 0, (type == 'p' || type == 'f')
    252 		   && streq(thisnym, ANON));
    253 	goto redraw;
    254       case 'r':
    255 	echo();
    256 	cl(LINES - 5, 20);
    257 	cl(5, 13);
    258 	wgetnstr(stdscr, line, LINELEN);
    259 	numcopies = strtol(line, NULL, 10);
    260 	if (numcopies < 1 || numcopies > 10)
    261 	  numcopies = 1;
    262 	noecho();
    263 	break;
    264       case 'f':
    265 	cl(LINES - 3, 0);
    266 	askfilename(path);
    267 	cl(LINES - 3, 0);
    268 	if (txt->length) {
    269 	  buf_sets(tmp, path);
    270 	  buf_clear(msg);
    271 	  if (!hdr)
    272 	    buf_nl(msg);
    273 	  buf_cat(msg, txt);
    274 	  if (attachfile(msg, tmp) == -1)
    275 	    beep();
    276 	  else {
    277 	    buf_move(txt, msg);
    278 	    hdr = 1;
    279 	  }
    280 	} else {
    281 	  if ((f = fopen(path, "r")) != NULL) {
    282 	    buf_clear(txt);
    283 	    buf_read(txt, f);
    284 	    fclose(f);
    285 	  } else
    286 	    beep();
    287 	}
    288 	break;
    289       case 'e':
    290 #endif /* USE_NCURSES */
    291 	{
    292 	  int linecount;
    293 
    294 	edit:
    295 	  linecount = 1;
    296 	  sprintf(path, "%s%cx%02x%02x%02x%02x.txt", POOLDIR, DIRSEP,
    297 		  rnd_byte(), rnd_byte(), rnd_byte(), rnd_byte());
    298 	  f = fopen(path, "w");
    299 	  if (f == NULL) {
    300 #ifdef USE_NCURSES
    301 	    beep();
    302 #endif /* USE_NCURSES */
    303 	  } else {
    304 	    if (type == 'f' || type == 'p')
    305 	      fprintf(f, "Newsgroups: %s\n", dest);
    306 	    if (type == 'r' || type == 'g' || type == 'm')
    307 	      fprintf(f, "To: %s\n", dest);
    308 	    fprintf(f, "Subject: %s\n", subject);
    309 	    linecount += 2;
    310 	    if (hdr)
    311 	      while (buf_getline(txt, NULL) == 0) linecount++;
    312 	    else
    313 	      fprintf(f, "\n");
    314 	    linecount++;
    315 	    if (txt->length == 0)
    316 	      fprintf(f, "\n");
    317 
    318 	    buf_write(txt, f);
    319 	    fclose(f);
    320 	  }
    321 
    322 	  menu_spawn_editor(path, linecount);
    323 
    324 	  f = fopen(path, "r");
    325 	  if (f == NULL) {
    326 #ifdef USE_NCURSES
    327 	    clear();
    328 	    beep();
    329 	    continue;
    330 #else /* end of USE_NCURSES */
    331 	    goto quit;
    332 #endif /* else if not USE_NCURSES */
    333 	  }
    334 	  buf_reset(txt);
    335 	  hdr = 0;
    336 
    337 	  buf_reset(tmp);
    338 	  buf_read(tmp, f);
    339 	  while (buf_getheader(tmp, field, content) == 0) {
    340 	    if (bufieq(field, "subject"))
    341 	      strncpy(subject, content->data,
    342 		      sizeof(subject));
    343 	    else if ((type == 'p' || type == 'f') &&
    344 		     bufieq(field, "newsgroups"))
    345 	      strncpy(dest, content->data, sizeof(dest));
    346 	    else if (bufieq(field, "to"))
    347 	      strncpy(dest, content->data, sizeof(dest));
    348 	    else {
    349 	      buf_appendheader(txt, field, content);
    350 	      hdr = 1;
    351 	    }
    352 	  }
    353 	  if (hdr)
    354 	    buf_nl(txt);
    355 	  buf_rest(txt, tmp);
    356 
    357 	  fclose(f);
    358 	  unlink(path);
    359 	  strcatn(path, "~", PATHMAX);
    360 	  unlink(path);
    361 #ifndef USE_NCURSES
    362 	  {
    363 	    char line[4];
    364 
    365 	    fprintf(stderr, "Send message [y/n]? ");
    366 	    scanf("%3s", line);
    367 	    if (!strleft(line, "y"))
    368 	      goto quit;
    369 	  }
    370 #else /* end of not USE_NCURSES */
    371 	  goto redraw;
    372 	}
    373 	break;
    374       case 'm':
    375 	if (txt->length == 0)
    376 	  beep();
    377 	else if (dest[0] == '\0') {
    378 	  mix_status("No destination given.");
    379 	  goto redraw;
    380 	} else {
    381 	  mix_status("Creating message...");
    382 #endif /* else if USE_NCURSES */
    383 	  buf_reset(msg);
    384 
    385 	  if (type == 'p' || type == 'f')
    386 	    buf_appends(msg, "Newsgroups: ");
    387 	  else
    388 	    buf_appends(msg, "To: ");
    389 	  buf_appends(msg, dest);
    390 	  buf_nl(msg);
    391 	  buf_appends(msg, "Subject: ");
    392 	  if (subject[0] == '\0')
    393 	    buf_appends(msg, "(no subject)");
    394 	  else
    395 	    buf_appends(msg, subject);
    396 	  buf_nl(msg);
    397 	  if (!hdr)
    398 	    buf_nl(msg);
    399 	  buf_cat(msg, txt);
    400 #ifdef USE_PGP
    401 	  {
    402 	    BUFFER *p;
    403 
    404 	    p = buf_new();
    405 	    if (streq(thisnym, ANON))
    406 	      sign = 0;
    407 	    if (sign || (key && !strileft(thisnym, NONANON)))
    408 	      user_pass(p);
    409 
    410 	    if (encrypt || sign) {
    411 	      if (pgp_mailenc((encrypt ? PGP_ENCRYPT : 0)
    412 			      | (sign ? PGP_SIGN : 0) | PGP_TEXT
    413 			      | (strleft(thisnym, NONANON) ? 0 : PGP_REMAIL),
    414 			      msg, strleft(thisnym, NONANON) ?
    415 			      ADDRESS : thisnym, p, PGPPUBRING,
    416 			      strleft(thisnym, NONANON) ?
    417 			      PGPSECRING : NYMSECRING) == -1) {
    418 		mix_genericerror();
    419 #ifdef USE_NCURSES
    420 		beep();
    421 		goto redraw;
    422 #endif /* USE_NCURSES */
    423 	      }
    424 	    }
    425 	    buf_free(p);
    426 	  }
    427 #endif /* USE_PGP */
    428 
    429 	  if (strleft(thisnym, NONANON)) {
    430 	    FILE *f = NULL;
    431 
    432 	    if (type == 'p' || type == 'f') {
    433 	      if (strchr(NEWS, '@')) {
    434 		/*  NOT_IMPLEMENTED; */
    435 	      } else
    436 		f = openpipe(NEWS);
    437 	    } else {
    438 	      if (NAME[0]) {
    439 		buf_sets(tmp, NAME);
    440 		buf_appends(tmp, " <");
    441 		buf_appends(tmp, ADDRESS);
    442 		buf_appends(tmp, ">");
    443 	      } else
    444 		buf_sets(tmp, ADDRESS);
    445 	      mail_encode(msg, 0);
    446 	      if (sendmail(msg, tmp->data, NULL) != 0) {
    447 #ifdef USE_NCURSES
    448 		clear();
    449 #endif /* USE_NCURSES */
    450 		mix_status("Error sending message.");
    451 #ifdef USE_NCURSES
    452 		goto redraw;
    453 #else /* end of USE_NCURSES */
    454 		goto quit;
    455 #endif /* else if not USE_NCURSES */
    456 	      }
    457 	    }
    458 #ifdef USE_NCURSES
    459 	    clear();
    460 #endif /* USE_NCURSES */
    461 	    mix_status("Message sent non-anonymously.");
    462 	    goto quit;
    463 	  } else {
    464 #ifdef USE_PGP
    465 #ifdef NYMSUPPORT
    466 	    if (!streq(thisnym, ANON)) {
    467 	      if (nym_encrypt(msg, thisnym, (type == 'p' || type == 'f') ?
    468 			      MSG_POST : MSG_MAIL) == 0)
    469 		type = 'm';
    470 	    }
    471 #endif /* NYMSUPPORT */
    472 #endif /* USE_PGP */
    473 	    err = mix_encrypt((type == 'p' || type == 'f') ?
    474 			      MSG_POST : MSG_MAIL,
    475 			      msg, chain, numcopies, chainlist);
    476 	    if (err == 0) {
    477 #ifdef USE_NCURSES
    478 	      clear();
    479 #endif /* USE_NCURSES */
    480 	      for (n = 0; buf_getline(chainlist, tmp) == 0; n++) ;
    481 	      if (n > 1)
    482 		mix_status("Done. (%d packets)", n);
    483 	      else
    484 		mix_status("Chain: %s", chainlist->data);
    485 	      goto quit;
    486 	    } else {
    487 #ifdef USE_NCURSES
    488 	      beep();
    489 #endif /* USE_NCURSES */
    490 	      if (chainlist->length)
    491 		mix_status("%s", chainlist->data);
    492 	      else
    493 		mix_genericerror();
    494 	    }
    495 	  }
    496 	}
    497 #ifdef USE_NCURSES
    498 	break;
    499       case 'q':
    500       case 'Q':
    501 	clear();
    502 	goto quit;
    503 #ifdef USE_PGP
    504       case 'p':
    505 	if (!streq(thisnym, ANON))
    506 	  sign = !sign;
    507 	break;
    508       case 'y':
    509 	encrypt = !encrypt;
    510 	break;
    511       case 'k':
    512 	if (!streq(thisnym, ANON)) {
    513 	  BUFFER *p, *keytxt, *uid;
    514 
    515 	  key = 1;
    516 	  p = buf_new();
    517 	  keytxt = buf_new();
    518 	  uid = buf_new();
    519 
    520 	  buf_appendf(uid, "<%s>", strleft(thisnym, NONANON) ? ADDRESS :
    521 		      thisnym);
    522 	  user_pass(p);
    523 	  pgp_pubkeycert(uid, strleft(thisnym, NONANON) ?
    524 			 PGPSECRING : NYMSECRING, p, keytxt, PGP_ARMOR_NYMKEY);
    525 
    526 	  buf_clear(msg);
    527 	  if (!hdr)
    528 	    buf_nl(msg);
    529 	  buf_cat(msg, txt);
    530 	  buf_sets(p, "application/pgp-keys");
    531 	  mime_attach(msg, keytxt, p);
    532 	  hdr = 1;
    533 	  buf_move(txt, msg);
    534 
    535 	  buf_free(p);
    536 	  buf_free(keytxt);
    537 	  buf_free(uid);
    538 	}
    539 	break;
    540 #endif /* USE_PGP */
    541       default:
    542 	beep();
    543       }
    544     }
    545   }
    546 #endif /* USE_NCURSES */
    547 quit:
    548   buf_free(cc);
    549   buf_free(cite);
    550   buf_free(msg);
    551   buf_free(txt);
    552   buf_free(field);
    553   buf_free(content);
    554   buf_free(chainlist);
    555   buf_free(tmp);
    556 }