tmenu.c - mixmaster - mixmaster 3.0 patched for libressl
HTML git clone git://parazyd.org/mixmaster.git
DIR Log
DIR Files
DIR Refs
DIR README
---
tmenu.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 */