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 }