menu.c (22252B)
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 9 $Id: menu.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 #include <fcntl.h> 18 #ifdef POSIX 19 #include <unistd.h> 20 #else /* end of POSIX */ 21 #include <io.h> 22 #endif /* else if not POSIX */ 23 #include <assert.h> 24 25 void menu_folder(char command, char *foldername) 26 { 27 mix_init(NULL); 28 if (foldername) 29 menu_init(); 30 read_folder(command, foldername, ANON); 31 menu_exit(); 32 } 33 34 void read_folder(char command, char *foldername, char *nym) 35 { 36 #ifdef USE_NCURSES 37 char path[PATHMAX] = "stdin", path_with_tilde[PATHMAX], l[LINELEN]; 38 #else /* end of USE_NCURSES */ 39 char path[PATHMAX] = "stdin", l[LINELEN]; 40 #endif /* else if not USE_NCURSES */ 41 char *h; 42 FILE *f; 43 BUFFER *folder; 44 BUFFER *line, *field, *content, *name; 45 BUFFER *index; 46 BUFFER *mail, *log; 47 int mailfolder = -1; /* -1 = unknown, 0 = no mailfolder, 1 = mailfolder */ 48 int num = 0; 49 long from = -1, subject = -1; 50 int folder_has_changed; 51 #ifdef USE_NCURSES 52 BUFFER *deleted_message; 53 BUFFER *new_folder; 54 BUFFER *new_index; 55 long length; 56 char sub[LINELEN], str[LINELEN], search[LINELEN] = ""; 57 long p; 58 int display, range, selected, i, redraw, c, q; 59 60 #endif /* USE_NCURSES */ 61 int ispgp = 0, eof = 0; 62 folder_has_changed = 0; 63 64 line = buf_new(); 65 field = buf_new(); 66 content = buf_new(); 67 index = buf_new(); 68 mail = buf_new(); 69 name = buf_new(); 70 folder = buf_new(); 71 log = buf_new(); 72 73 if (foldername == NULL) 74 f = stdin; 75 else { 76 if (foldername[0] == '~' && (h = getenv("HOME")) != NULL) { 77 strncpy(path, h, PATHMAX); 78 strcatn(path, foldername + 1, PATHMAX); 79 } else 80 strncpy(path, foldername, PATHMAX); 81 f = fopen(path, "r"); 82 } 83 if (f == NULL) { 84 #ifdef USE_NCURSES 85 if (foldername) 86 beep(); 87 #endif /* USE_NCURSES */ 88 mix_status("Can't read %s.\n", path); 89 goto end; 90 } 91 for (;;) { 92 if (fgets(l, sizeof(l), f) == NULL) 93 eof = 1; 94 else if (mailfolder == -1) { 95 if (strleft(l, "From ")) 96 mailfolder = 1; 97 else if (strileft(l, "from:") || strileft(l, "path:") 98 || strileft(l, "xref:") || strileft(l, "return-path")) 99 mailfolder = 0; 100 else 101 break; 102 } 103 if (eof || (mailfolder && strleft(l, "From ")) || 104 (mailfolder == 0 && from != -1 && 105 (strileft(l, "path:") || 106 strileft(l, "xref:") || strileft(l,"return-path")))) { 107 if (num > 1) 108 mix_status("Reading message %d", num); 109 #ifdef USE_PGP 110 if (ispgp) 111 #ifdef NYMSUPPORT 112 switch (nym_decrypt(mail, NULL, log)) { 113 case 2: 114 from = -1, subject = -1; 115 while (buf_getline(mail, line) == 0) { 116 if (bufileft(line, "from:")) 117 from = folder->length + mail->ptr - line->length - 1; 118 if (bufileft(line, "subject:")) 119 subject = folder->length + mail->ptr - line->length - 1; 120 } 121 folder_has_changed = 1; 122 break; 123 case -1: 124 buf_clear(mail); 125 from = -1, subject = -1; 126 continue; 127 default: 128 ; 129 } 130 #else 131 if (!eof) { 132 buf_clear(mail); 133 from = -1, subject = -1; 134 continue; 135 } 136 #endif /* NYMSUPPORT */ 137 #endif /* USE_PGP */ 138 buf_cat(folder, mail); 139 buf_clear(mail); 140 ispgp = 0; 141 if (num > 0) { 142 buf_appendl(index, from); 143 buf_appendl(index, subject); 144 } 145 if (eof) 146 break; 147 148 buf_appendl(index, folder->length); 149 from = subject = -1; 150 num++; 151 } 152 if (from == -1 && strileft(l, "from:")) 153 from = folder->length + mail->length; 154 155 if (subject == -1 && strileft(l, "subject:")) 156 subject = folder->length + mail->length; 157 158 buf_appends(mail, l); 159 if (strleft(l, begin_pgp)) 160 ispgp = 1; 161 } 162 163 if (foldername) 164 fclose(f); 165 else { 166 dup2(open("/dev/tty", O_RDWR), fileno(stdin)); 167 menu_init(); 168 } 169 170 mix_status(""); 171 if (folder->length == 0) { 172 #ifdef USE_NCURSES 173 clear(); 174 beep(); 175 #endif /* USE_NCURSES */ 176 mix_status("%s is empty.\n", path); 177 goto end; 178 } 179 if (mailfolder == -1) { 180 #ifdef USE_NCURSES 181 clear(); 182 beep(); 183 #endif /* USE_NCURSES */ 184 mix_status("%s is not a mail folder.\n", path); 185 goto end; 186 } 187 #ifndef USE_NCURSES 188 if (command == 0) { 189 buf_write(folder, stdout); 190 goto end; 191 } 192 if (num > 1) { 193 mix_status("Folder contains several messages."); 194 goto end; 195 } 196 #endif /* not USE_NCURSES */ 197 198 if (num < 2) { 199 folder->ptr = 0; 200 mimedecode(folder); 201 202 if (command != 0) 203 send_message(command, nym, folder); 204 #ifdef USE_NCURSES 205 else 206 read_message(folder, nym); 207 208 clear(); 209 #endif /* USE_NCURSES */ 210 goto end; 211 } 212 #ifdef USE_NCURSES 213 display = selected = 0; 214 range = LINES - 3; 215 redraw = 2; 216 217 for (;;) { 218 if (selected < 0) 219 selected = 0; 220 if (selected >= num) 221 selected = num - 1; 222 223 if (selected < display) { 224 display = selected - range / 2; 225 redraw = 2; 226 } 227 if (selected >= display + range) { 228 display = selected - range / 2; 229 redraw = 2; 230 } 231 if (display >= num - 5) 232 display = num - 5; 233 if (display < 0) 234 display = 0; 235 236 if (redraw) { 237 if (redraw == 2) { 238 clear(); 239 standout(); 240 mvprintw(0, 0, "Mixmaster %s", VERSION); 241 printw(" %.20s reading %.50s", nym, path); 242 standend(); 243 } 244 for (i = display; i < display + range; i++) { 245 if (i < num) { 246 index->ptr = 12 * i; 247 p = buf_getl(index); 248 buf_clear(name); 249 folder->ptr = buf_getl(index); 250 if (folder->ptr < 0) 251 folder->ptr = 0; 252 else { 253 buf_getheader(folder, field, line); 254 if (line->length) { 255 decode_header(line); 256 rfc822_name(line, name); 257 } 258 } 259 if (i == selected) 260 standout(); 261 262 mvaddnstr(i - display + 2, 0, name->data, 18); 263 264 sub[0] = '\0'; 265 folder->ptr = buf_getl(index); 266 if (folder->ptr < 0) 267 folder->ptr = 0; 268 else { 269 buf_getheader(folder, field, content); 270 if (content->length) { 271 decode_header(content); 272 strncpy(sub, content->data, sizeof(sub)); 273 } 274 } 275 if (sub[0] == '\0') 276 strcpy(sub, "(no subject)"); 277 mvaddnstr(i - display + 2, 20, sub, COLS - 21); 278 279 if (i == selected) 280 standend(); 281 } 282 } 283 } 284 move(LINES - 1, COLS - 1); 285 refresh(); 286 redraw = 0; 287 288 c = getch(); 289 switch (c) { 290 case '\014': 291 display = selected - range / 2; 292 redraw = 2; 293 break; 294 case 'q': 295 clear(); 296 goto end; 297 case '/': 298 echo(); 299 cl(LINES - 1, 0); 300 printw("Search: "); 301 refresh(); 302 wgetnstr(stdscr, str, LINELEN); 303 if (str[0] != '\0') 304 strncpy(search, str, LINELEN); 305 noecho(); 306 for (i = (selected < num ? selected + 1 : 0); i < num; i++) { 307 index->ptr = 12 * i + 4; 308 folder->ptr = buf_getl(index); 309 if (folder->ptr < 0) 310 folder->ptr = 0; 311 else { 312 buf_getheader(folder, field, line); 313 if (line->length) { 314 decode_header(line); 315 if (bufifind(line, search)) 316 break; 317 } 318 } 319 folder->ptr = buf_getl(index); 320 if (folder->ptr < 0) 321 folder->ptr = 0; 322 else { 323 buf_getheader(folder, field, line); 324 if (line->length) { 325 decode_header(line); 326 if (bufifind(line, search)) 327 break; 328 } 329 } 330 } 331 if (i < num) 332 selected = i; 333 else 334 beep(); 335 redraw = 1; 336 break; 337 case '\r': /* read message */ 338 case '\n': 339 case 'r': /* reply to message */ 340 case 'g': 341 case 'f': 342 case 'm': 343 case 'p': 344 case 's': 345 index->ptr = 12 * selected; 346 p = buf_getl(index); 347 if (selected < num - 1) { 348 index->ptr = 12 * (selected + 1); 349 q = buf_getl(index) - p; 350 } else 351 q = folder->length - p; 352 buf_clear(mail); 353 buf_append(mail, folder->data + p, q); 354 mimedecode(mail); 355 if(c == 's') 356 savemsg(mail); 357 else{ 358 if (c == '\r' || c == '\n') 359 read_message(mail, nym); 360 else 361 send_message(c, nym, mail); 362 } 363 redraw = 2; 364 break; 365 case 'd': /* delete message */ 366 /* Remove message from folder */ 367 if(num > 0){ 368 index->ptr = 12 * selected; 369 p = buf_getl(index); 370 if (selected < num - 1) { 371 index->ptr = 12 * (selected + 1); 372 q = buf_getl(index) - p; 373 } else 374 q = folder->length - p; 375 deleted_message = buf_new(); 376 new_folder = buf_new(); 377 buf_cut_out(folder, deleted_message, new_folder, p, q); 378 buf_free(deleted_message); 379 buf_free(folder); 380 folder = new_folder; 381 /* Update index file */ 382 new_index = buf_new(); 383 index->ptr = 0; 384 if(selected > 0) 385 buf_get(index, new_index, 12 * selected); 386 index->ptr = 12 * (selected + 1); 387 while((from = buf_getl(index)) != -1){ 388 subject = buf_getl(index); 389 length = buf_getl(index); 390 buf_appendl(new_index, from - q); 391 buf_appendl(new_index, subject - q); 392 buf_appendl(new_index, length - q); 393 } 394 buf_free(index); 395 index = new_index; 396 /* Done */ 397 num--; 398 folder_has_changed = 1; 399 } 400 redraw = 2; 401 break; 402 case KEY_UP: 403 selected--; 404 redraw = 1; 405 break; 406 case KEY_DOWN: 407 case 'n': /* nym ???? */ 408 selected++; 409 redraw = 1; 410 break; 411 case KEY_PPAGE: 412 selected -= range; 413 redraw = 1; 414 break; 415 case KEY_NPAGE: 416 selected += range; 417 redraw = 1; 418 break; 419 default: 420 beep(); 421 } 422 } 423 #endif /* USE_NCURSES */ 424 425 end: 426 #ifdef USE_NCURSES 427 /* If folder has changed, ask user about saving new folder. */ 428 if (folder_has_changed && !streq(path, "stdin")) { 429 mvprintw(LINES - 2, 0, "Buffer has changed. Save [y/n]? "); 430 c = getch(); 431 cl(LINES - 2, 0); 432 if ((c == 'y') || (c == 'Y')){ 433 strncpy(path_with_tilde, path, PATHMAX-1); 434 strcat(path_with_tilde, "~"); 435 rename(path, path_with_tilde); /* Rename folder to folder~ */ 436 f = fopen(path, "w"); /* Write new folder */ 437 if (f == NULL) 438 mix_status("Can't write to %s.", path); 439 else{ 440 buf_write(folder, f); 441 mix_status("Wrote %s.", path); 442 fclose(f); 443 } 444 } 445 else{ 446 mix_status("%s was not saved.", path); 447 } 448 } 449 #endif /* USE_NCURSES */ 450 buf_free(folder); 451 buf_free(line); 452 buf_free(field); 453 buf_free(content); 454 buf_free(index); 455 buf_free(mail); 456 buf_free(name); 457 buf_free(log); 458 } 459 460 #ifdef USE_NCURSES 461 static int sortrel(const void *a, const void *b) 462 { 463 int na, ra, nb, rb; 464 465 na = *(int *) a; 466 nb = *(int *) b; 467 468 ra = *((int *) a + 1); 469 rb = *((int *) b + 1); 470 return rb - ra; 471 } 472 473 void menu_main(void) 474 { 475 int y, x; 476 int pool, n; 477 int c; 478 int space; 479 BUFFER *chainlist, *line; 480 char nym[LINELEN] = ANON; 481 482 chainlist = buf_new(); 483 line = buf_new(); 484 485 mix_init(NULL); 486 menu_init(); 487 488 menu_redraw: 489 clear(); 490 for (;;) { 491 standout(); 492 mvprintw(0, 0, "Mixmaster %s", VERSION); 493 #if 0 494 mvprintw(0, COLS - sizeof(COPYRIGHT), COPYRIGHT); 495 #endif 496 for (space = 0; space < (COLS - 10 - sizeof(VERSION)); space++) { 497 printw(" "); 498 }; 499 standend(); 500 mix_status(NULL); 501 502 #ifdef NYMSUPPORT 503 mvprintw(8, 4, "n)ym: %s", nym); 504 #endif /* NYMSUPPORT */ 505 y = 12, x = 25; 506 mvprintw(y++, x, "m)ail"); 507 mvprintw(y++, x, "p)ost to Usenet"); 508 mvprintw(y++, x, "r)ead mail (or news article)"); 509 mvprintw(y++, x, "d)ummy message"); 510 mvprintw(y++, x, "s)end messages from pool"); 511 mvprintw(y++, x, "e)dit configuration file"); 512 mvprintw(y++, x, "u)pdate stats"); 513 mvprintw(y++, x, "q)uit"); 514 515 pool = pool_read(NULL); 516 if (pool == 1) 517 mvprintw(4, 2, "%3d outgoing message in the pool. \n", pool); 518 else 519 mvprintw(4, 2, "%3d outgoing messages in the pool.\n", pool); 520 521 move(LINES - 1, COLS - 1); 522 refresh(); 523 c = getch(); 524 if (c != ERR) { 525 mix_status(""); 526 switch (c) { 527 case '\014': 528 mix_status(""); 529 goto menu_redraw; 530 #ifdef NYMSUPPORT 531 case 'n': 532 menu_nym(nym); 533 goto menu_redraw; 534 #endif /* NYMSUPPORT */ 535 case 'm': 536 case 'p': 537 send_message(c, nym, NULL); 538 break; 539 case 'd': 540 mix_status("Creating message..."); 541 if (mix_encrypt(MSG_NULL, NULL, NULL, 1, chainlist) != 0) { 542 if (chainlist->length > 0) 543 mix_status("%s", chainlist->data); 544 else 545 mix_genericerror(); 546 beep(); 547 } else { 548 for (n = 0; buf_getline(chainlist, line) == 0; n++) ; 549 if (n > 1) 550 mix_status("Done (%d packets).", n); 551 else 552 mix_status("Chain: %s", chainlist->data); 553 } 554 break; 555 case 's': 556 mix_status("Mailing messages..."); 557 mix_send(); 558 mix_status("Done."); 559 break; 560 case 'r': 561 { 562 char name[LINELEN]; 563 564 cl(LINES - 3, 0); 565 if (getenv("MAIL")) 566 printw("File name [%s]: ", getenv("MAIL")); 567 else 568 printw("File name: "); 569 echo(); 570 wgetnstr(stdscr, name, LINELEN); 571 noecho(); 572 cl(LINES - 3, 0); 573 if (name[0] == '\0') { 574 if (getenv("MAIL")) 575 read_folder(0, getenv("MAIL"), nym); 576 } else 577 read_folder(0, name, nym); 578 } 579 break; 580 case 'e': 581 do { 582 char path[PATHMAX]; 583 mixfile(path, MIXCONF); 584 menu_spawn_editor(path, 0); 585 mix_config(); 586 } while (0); 587 break; 588 case 'u': 589 update_stats(); 590 break; 591 case 'q': 592 case 'Q': 593 goto quit; 594 default: 595 beep(); 596 } 597 } 598 } 599 600 quit: 601 menu_exit(); 602 buf_free(chainlist); 603 buf_free(line); 604 } 605 606 void read_message(BUFFER *message, char *nym) 607 { 608 int l = 0; 609 int c; 610 int inhdr = 1, txtbegin; 611 BUFFER *field, *content, *line, *hdr; 612 char sub[LINELEN] = "mail"; 613 char thisnym[LINELEN] = ""; 614 615 field = buf_new(); 616 content = buf_new(); 617 line = buf_new(); 618 hdr = buf_new(); 619 620 if (thisnym[0] == '\0') 621 strncpy(thisnym, nym, LINELEN); 622 623 if (bufleft(message, "From nymserver ")) { 624 /* select nym if Nym: pseudo header is in the first line */ 625 buf_getline(message, line); 626 buf_getheader(message, field, content); 627 if (bufieq(field, "Nym")) 628 strncpy(thisnym, content->data, sizeof(thisnym)); 629 buf_rewind(message); 630 } 631 while (buf_getheader(message, field, content) == 0) { 632 if (bufieq(field, "received") || bufleft(field, "From ")) 633 continue; 634 if (bufieq(field, "subject")) 635 strncpy(sub, content->data, sizeof(sub)); 636 buf_appendheader(hdr, field, content); 637 } 638 if (strlen(sub) > COLS - strlen(VERSION) - strlen(thisnym) - 23) 639 sub[COLS - strlen(VERSION) - strlen(thisnym) - 24] = '\0'; 640 txtbegin = message->ptr; 641 642 loop: 643 clear(); 644 standout(); 645 mvprintw(0, 0, "Mixmaster %s", VERSION); 646 printw(" %.20s reading %.50s\n", thisnym, sub); 647 standend(); 648 mix_status(NULL); 649 650 while (l < LINES - 2) { 651 if (inhdr) { 652 if (buf_getline(hdr, line) == -1) 653 buf_clear(line), inhdr = 0; 654 } else { 655 if (buf_getline(message, line) == -1) { 656 standout(); 657 mvprintw(LINES - 1, 0, "Command"); 658 standend(); 659 refresh(); 660 for (;;) { 661 c = getch(); 662 switch (c) { 663 case 'm': 664 case 'p': 665 case 'r': 666 case 'g': 667 case 'f': 668 send_message(c, thisnym, message); 669 goto end; 670 case 'u': 671 inhdr = 0; 672 message->ptr = txtbegin; 673 l = 0; 674 goto loop; 675 case 'h': 676 inhdr = 1; 677 hdr->ptr = 0; 678 message->ptr = txtbegin; 679 l = 0; 680 goto loop; 681 case 's': 682 savemsg(message); 683 /* fallthru */ 684 case 'q': 685 case 'i': 686 case '\n': 687 case '\r': 688 goto end; 689 case '\014': 690 refresh(); 691 continue; 692 default: 693 beep(); 694 refresh(); 695 } 696 } 697 } 698 } 699 mvprintw(l + 1, 0, "%s\n", line->data); 700 l += (line->length - 1) / COLS + 1; 701 } 702 standout(); 703 mvprintw(LINES - 1, 0, "MORE"); 704 standend(); 705 refresh(); 706 for (;;) { 707 c = getch(); 708 switch (c) { 709 case 'm': 710 case 'p': 711 case 'r': 712 case 'g': 713 case 'f': 714 send_message(c, thisnym, message); 715 goto end; 716 case 'u': 717 inhdr = 0; 718 message->ptr = txtbegin; 719 l = 0; 720 goto loop; 721 case 'h': 722 inhdr = 1; /* show full header */ 723 hdr->ptr = 0; 724 message->ptr = txtbegin; 725 l = 0; 726 goto loop; 727 case 's': 728 savemsg(message); 729 /* fallthru */ 730 case 'q': 731 case 'i': 732 goto end; 733 case ' ': 734 case '\n': 735 case '\r': 736 l = 0; 737 goto loop; 738 case '\014': 739 refresh(); 740 continue; 741 default: 742 beep(); 743 refresh(); 744 } 745 } 746 end: 747 buf_free(field); 748 buf_free(content); 749 buf_free(line); 750 buf_free(hdr); 751 } 752 753 int menu_replychain(int *d, int *l, char *mdest, char *pdest, char *psub, 754 char *r) 755 { 756 int c; 757 char line[LINELEN]; 758 char reliability[9]; 759 760 redraw: 761 clear(); 762 standout(); 763 printw("Create a nym reply block:"); 764 standend(); 765 mix_status(NULL); 766 767 mvprintw(3, 0, "Type of reply block:\n"); 768 if (*d == MSG_MAIL) 769 standout(); 770 printw(" m)ail "); 771 if (*d == MSG_MAIL) 772 standend(); 773 774 if (*d == MSG_POST) 775 standout(); 776 printw(" Usenet message p)ool "); 777 if (*d == MSG_POST) 778 standend(); 779 780 if (*d == MSG_NULL) 781 standout(); 782 printw(" cover t)raffic "); 783 if (*d == MSG_NULL) 784 standend(); 785 786 if (*d != MSG_NULL) 787 mvprintw(6, 0, "d)estination: %s", *d == MSG_MAIL ? mdest : pdest); 788 if (psub && *d == MSG_POST) 789 mvprintw(7, 0, "s)ubject: %s", psub); 790 chain_reliability(r, 1, reliability); /* chaintype 1=ek */ 791 mvprintw(8, 0, "c)hain: %-39s (reliability: %s)", r, reliability); 792 mvprintw(10, 0, "l)atency: %d hours", *l); 793 move(LINES - 1, COLS - 1); 794 795 for (;;) { 796 refresh(); 797 c = getch(); 798 switch (c) { 799 case 'm': 800 *d = MSG_MAIL; 801 goto redraw; 802 case 'p': 803 *d = MSG_POST; 804 goto redraw; 805 case 't': 806 *d = MSG_NULL; 807 goto redraw; 808 case 'q': 809 return (-1); 810 case 'd': 811 cl(6, 0); 812 printw("d)estination: "); 813 echo(); 814 wgetnstr(stdscr, *d == MSG_MAIL ? mdest : pdest, LINELEN); 815 noecho(); 816 goto redraw; 817 case 'l': 818 cl(10, 0); 819 printw("l)atency: "); 820 echo(); 821 wgetnstr(stdscr, line, LINELEN); 822 *l = strtol(line, NULL, 10); 823 if (*l < 0) 824 *l = 0; 825 noecho(); 826 goto redraw; 827 case 'c': 828 menu_chain(r, 1, *d == MSG_POST); 829 goto redraw; 830 case '\014': 831 goto redraw; 832 case '\n': 833 case '\r': 834 return (0); 835 case 's': 836 if (*d == MSG_POST) { 837 cl(7, 0); 838 printw("s)ubject: "); 839 echo(); 840 wgetnstr(stdscr, psub, LINELEN); 841 noecho(); 842 goto redraw; 843 } 844 default: 845 beep(); 846 } 847 } 848 } 849 850 void menu_chain(char *chainstr, int chaintype, int post) 851 /* chaintype 0=mix 1=ek 2=newnym */ 852 { 853 REMAILER remailer[MAXREM]; 854 int badchains[MAXREM][MAXREM]; 855 int rlist[2 * MAXREM]; 856 char newchain[CHAINMAX]; 857 char info[LINELEN]; 858 int num = 0, i, middlemanlast=0, ok = 1; 859 int c, x, y; 860 int nymserv = 0; 861 int chain[20], chainlen = 0; 862 char reliability[9]; 863 864 if (chaintype == 2) 865 nymserv = 1, chaintype = 1; 866 assert(chaintype == 0 || chaintype == 1); 867 868 clear(); 869 standout(); 870 if (nymserv) 871 printw("Select nym server:\n\n"); 872 else 873 printw("Select remailer chain:\n\n"); 874 standend(); 875 876 if (chaintype == 1) 877 num = t1_rlist(remailer, badchains); 878 else 879 num = mix2_rlist(remailer, badchains); 880 881 if (num < 1) { 882 mix_status("Can't read remailer list."); 883 beep(); 884 return; 885 } 886 for (i = 0; i < num; i++) { 887 rlist[2 * i] = i + 1; 888 rlist[2 * i + 1] = remailer[i + 1].info[chaintype].reliability - 889 remailer[i + 1].info[chaintype].latency / 3600; 890 if (remailer[i + 1].info[chaintype].history[0] == '\0') 891 rlist[2 * i + 1] = -1; 892 if ((nymserv && !remailer[i + 1].flags.newnym) || 893 ((chaintype == 0 && !remailer[i + 1].flags.mix) || 894 (chaintype == 1 && !nymserv && (!remailer[i + 1].flags.ek 895 || !remailer[i + 1].flags.pgp)))) 896 rlist[2 * i] = 0, rlist[2 * i + 1] = -2; 897 } 898 qsort(rlist, num - 1, 2 * sizeof(int), sortrel); 899 900 for (i = 0; i < num; i++) 901 if (rlist[2 * i + 1] == -2) { 902 num = i; 903 break; 904 } 905 if (num < 1) { 906 mix_status("No remailers found!"); 907 return; 908 } 909 if (num > 2 * (LINES - 6)) 910 num = 2 * (LINES - 6); 911 if (num > 2 * 26) 912 num = 2 * 26; 913 914 for (i = 0; i < num && rlist[2 * i + 1] > -2; i++) { 915 y = i, x = 0; 916 if (y >= LINES - 6) 917 y -= LINES - 6, x += 40; 918 mvprintw(y + 2, x, "%c", i < 26 ? i + 'a' : i - 26 + 'A'); 919 mvprintw(y + 2, x + 2, "%s", remailer[rlist[2 * i]].name); 920 mvprintw(y + 2, x + 16, "%s", 921 remailer[rlist[2 * i]].info[chaintype].history); 922 sprintf(info, "%3.2f", 923 remailer[rlist[2 * i]].info[chaintype].reliability / 100.0); 924 mvprintw(y + 2, x + 29 + 6 - strlen(info), "%s%%", info); 925 } 926 y = num + 3; 927 if (y > LINES - 4) 928 y = LINES - 4; 929 mvprintw(y, 0, "* select at random"); 930 931 for (;;) { 932 newchain[0] = '\0'; 933 for (i = 0; i < chainlen; i++) { 934 if (i) 935 strcatn(newchain, ",", CHAINMAX); 936 if (chain[i]) 937 strcatn(newchain, remailer[chain[i]].name, CHAINMAX); 938 else 939 strcatn(newchain, "*", CHAINMAX); 940 } 941 if (chainlen > 0) { 942 ok = 1; 943 middlemanlast = remailer[chain[chainlen - 1]].flags.middle; 944 if (post && !remailer[chain[chainlen - 1]].flags.post && !(chain[chainlen - 1] == 0 /*randhop*/)) 945 ok = 0; 946 } else 947 ok = 1; 948 949 mvprintw(LINES - 4, 40, 950 middlemanlast ? 951 "MIDDLEMAN " : 952 (ok ? 953 " " : 954 "NO POSTING ")); 955 cl(LINES - 3, 0); 956 cl(LINES - 2, 0); 957 cl(LINES - 1, 0); 958 if(!nymserv){ 959 chain_reliability(newchain, chaintype, reliability); 960 mvprintw(LINES - 4, 58, "(reliability: %s)", reliability); 961 } 962 mvprintw(LINES - 3, 0, nymserv ? "Nym server: %s" : "Chain: %s", 963 newchain); 964 refresh(); 965 c = getch(); 966 if (c == '\n' || c == '\r') { 967 /* beep and sleep in case the user made a mistake */ 968 if (middlemanlast) { 969 beep(); 970 sleep(2); 971 } 972 if (ok || middlemanlast) 973 break; 974 else 975 beep(); 976 } else if (c == '*') { 977 if (chainlen > 19 || (nymserv && chainlen > 0)) 978 beep(); 979 else 980 chain[chainlen++] = 0; 981 } else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { 982 if (c >= 'a') 983 c -= 'a'; 984 else 985 c = c - 'A' + 26; 986 987 if (chainlen > 19 || (nymserv && chainlen > 0) || c >= num) 988 beep(); 989 else 990 chain[chainlen++] = rlist[2 * c]; 991 } else if (c == killchar()) 992 chainlen = 0; 993 else if ((c == KEY_BACKSPACE || c == KEY_LEFT || c == erasechar()) 994 && chainlen > 0) 995 --chainlen; 996 else 997 beep(); 998 } 999 if (chainlen) 1000 strncpy(chainstr, newchain, CHAINMAX); 1001 } 1002 1003 #endif /* USE_NCURSES */