1
2 static char rcsid[] = "@(#)$Id: elm.c,v 1.9 1996/08/08 19:49:23 wfp5p Exp $";
3
4 /*******************************************************************************
5 * The Elm Mail System - $Revision: 1.9 $ $State: Exp $
6 *
7 * This file and all associated files and documentation:
8 * Copyright (c) 1988-1995 USENET Community Trust
9 * Copyright (c) 1986,1987 Dave Taylor
10 *******************************************************************************
11 * Bug reports, patches, comments, suggestions should be sent to:
12 *
13 * Bill Pemberton, Elm Coordinator
14 * flash@virginia.edu
15 *
16 *******************************************************************************
17 * $Log: elm.c,v $
18 * Revision 1.9 1996/08/08 19:49:23 wfp5p
19 * Alpha 11
20 *
21 * Revision 1.8 1996/05/09 15:51:18 wfp5p
22 * Alpha 10
23 *
24 * Revision 1.7 1996/03/14 17:27:59 wfp5p
25 * Alpha 9
26 *
27 * Revision 1.6 1996/03/13 14:37:59 wfp5p
28 * Alpha 9 before Chip's big changes
29 *
30 * Revision 1.5 1995/09/29 17:42:05 wfp5p
31 * Alpha 8 (Chip's big changes)
32 *
33 * Revision 1.4 1995/09/11 15:19:05 wfp5p
34 * Alpha 7
35 *
36 * Revision 1.3 1995/05/10 13:34:48 wfp5p
37 * Added mailing list stuff by Paul Close <pdc@sgi.com>
38 *
39 * Revision 1.2 1995/04/20 21:01:46 wfp5p
40 * Added the showreply feature and emacs key bindings.
41 *
42 * Revision 1.1.1.1 1995/04/19 20:38:35 wfp5p
43 * Initial import of elm 2.4 PL0 as base for elm 2.5.
44 *
45 ******************************************************************************/
46
47 /* Main program of the ELM mail system!
48 */
49
50 #define INTERN
51 #include "elm_defs.h"
52 #include <setjmp.h> /* so that "GetKey_jmpbuf" gets defined */
53 #include "elm_globals.h"
54 #include "s_elm.h"
55
56 #ifdef I_TIME
57 # include <time.h>
58 #endif
59 #ifdef I_SYSTIME
60 # include <sys/time.h>
61 #endif
62 #ifdef BSD
63 # include <sys/timeb.h>
64 #endif
65
66 long bytes();
67 char *format_long(), *parse_arguments();
68 static void debug_message(void);
69
main(argc,argv)70 main(argc, argv)
71 int argc;
72 char *argv[];
73 {
74 int ch;
75 char address[SLEN], to_whom[SLEN], *req_mfile;
76 int i,j; /** Random counting variables (etc) **/
77 int pageon, /** for when we receive new mail... **/
78 last_in_folder; /** for when we receive new mail too... **/
79 long num; /** another variable for fun.. **/
80 int err;
81
82 initialize_common();
83 req_mfile = parse_arguments(argc, argv, to_whom);
84 initialize(req_mfile);
85
86 if (OPMODE_IS_SENDMODE(opmode)) {
87 if (OPMODE_IS_INTERACTIVE(opmode)) {
88 sprintf(address, catgets(elm_msg_cat, ElmSet, ElmSendOnlyMode,
89 "Send only mode [ELM %s]"), version_buff);
90 CenterLine(1, address);
91 }
92
93 if (to_whom && *to_whom)
94 dprint(3, (debugfile, "Mail-only: mailing to\n-> \"%s\"\n",
95 format_long(to_whom, 3)));
96 else
97 dprint(3, (debugfile, "Mail-only; no recipient specified\n"));
98
99 (void) send_message(to_whom, (char *)NULL, batch_subject,
100 SM_ORIGINAL);
101 leave(LEAVE_NORMAL);
102 }
103
104 headers_per_page = LINES - (mini_menu ? 13 : 8);
105 if (headers_per_page < 1)
106 headers_per_page = 1;
107
108 /* read in the folder */
109 newmbox(req_mfile, FALSE);
110
111 redraw = 1;
112
113 while (1) {
114
115 if (redraw)
116 showscreen();
117 redraw = 0;
118 nufoot = 0;
119 nucurr = 0;
120
121 if (curr_folder.fp)
122 fflush (curr_folder.fp);
123
124 if ((num = bytes(curr_folder.filename)) != curr_folder.size) {
125 dprint(2, (debugfile, "Just received %d bytes more mail (elm)\n",
126 num - curr_folder.size));
127 error(catgets(elm_msg_cat, ElmSet, ElmNewMailHangOn,
128 "New mail has arrived! Hang on..."));
129 last_in_folder = curr_folder.num_mssgs;
130 pageon = header_page;
131 newmbox(curr_folder.filename, TRUE); /* last won't be touched! */
132 clear_error();
133 header_page = pageon;
134
135 if (selected) /* update count of selected messages */
136 selected += curr_folder.num_mssgs - last_in_folder;
137
138 if (on_page(curr_folder.curr_mssg)) /* do we REALLY have to rewrite? */
139 showscreen();
140 else {
141 update_title();
142 ClearLine(LINES-1); /* remove reading message... */
143 if ((curr_folder.num_mssgs - last_in_folder) == 1)
144 error(catgets(elm_msg_cat, ElmSet, ElmNewMessageRecv,
145 "1 new message received."));
146 else
147 error1(catgets(elm_msg_cat, ElmSet, ElmNewMessageRecvPlural,
148 "%d new messages received."),
149 curr_folder.num_mssgs - last_in_folder);
150 }
151 }
152
153 prompt(nls_Prompt);
154
155 CleartoEOLN();
156 ch = GetKey(timeout);
157 CleartoEOS();
158 if (clear_error())
159 MoveCursor(LINES-3, strlen(nls_Prompt));
160
161 #ifdef DEBUG
162 dprint(4, (debugfile, "\nCommand: %c [%d]\n\n", ch, ch));
163 #endif
164
165 switch (ch) {
166
167 case KEY_TIMEOUT:
168 break;
169
170 case KEY_REDRAW:
171 ++redraw;
172 break;
173
174 case '?' : if (help(FALSE))
175 redraw++;
176 else
177 nufoot++;
178 break;
179
180 case '$' : PutLine0(-1, -1, catgets(elm_msg_cat,
181 ElmSet, ElmResyncFolder,
182 "Resynchronize folder"));
183 redraw += resync();
184 nucurr = get_page(curr_folder.curr_mssg);
185 break;
186
187 case '|' : WriteChar('|');
188 if (curr_folder.num_mssgs < 1) {
189 error(catgets(elm_msg_cat, ElmSet, ElmNoMailToPipe,
190 "No mail to pipe!"));
191 FlushInput();
192 } else {
193 redraw += do_pipe();
194 }
195 break;
196
197 #ifdef ALLOW_SUBSHELL
198 case '!' : WriteChar('!');
199 redraw += subshell();
200 break;
201 #endif
202
203 case '&' : TreatAsSpooled = !TreatAsSpooled;
204 if (TreatAsSpooled) {
205 error(catgets(elm_msg_cat, ElmSet, ElmMagicOn,
206 "[Magic On]"));
207 } else {
208 error(catgets(elm_msg_cat, ElmSet, ElmMagicOff,
209 "[Magic Off]"));
210 }
211 break;
212
213
214 case '%' : if (curr_folder.curr_mssg > 0) {
215 get_return(address, curr_folder.curr_mssg-1);
216 clear_error();
217 PutLine1(LINES,(COLS-strlen(address))/2,
218 "%.78s", address);
219 } else {
220 error(catgets(elm_msg_cat, ElmSet, ElmNoMailReturnAddress,
221 "No mail to get return address of!"));
222 }
223 break;
224
225 case '<' : /* scan current message for calendar information */
226 #ifdef ENABLE_CALENDAR
227 if (curr_folder.num_mssgs < 1) {
228 error(catgets(elm_msg_cat, ElmSet, ElmNoMailToScan,
229 "No mail to scan!"));
230 }
231 else {
232 PutLine0(-1, -1, catgets(elm_msg_cat,
233 ElmSet, ElmScanForCalendar,
234 "Scan message for calendar entries..."));
235 scan_calendar();
236 }
237 #else
238 error(catgets(elm_msg_cat,
239 ElmSet, ElmSorryNoCalendar,
240 "Sorry. Calendar function disabled."));
241 #endif
242 break;
243
244 case 'a' : alias();
245 redraw++;
246 break;
247
248 case 'b' : PutLine0(-1, -1, catgets(elm_msg_cat,
249 ElmSet, ElmBounceMessage,
250 "Bounce message"));
251 if (curr_folder.num_mssgs < 1) {
252 error(catgets(elm_msg_cat,
253 ElmSet, ElmNoMailToBounce,
254 "No mail to bounce!"));
255 FlushInput();
256 }
257 else
258 nufoot = remail();
259 break;
260
261 case 'c' : define_softkeys(SOFTKEYS_CHANGE);
262 redraw += change_file(catgets(elm_msg_cat, ElmSet,
263 ElmChangeFolder,
264 "Change folder"));
265 define_softkeys(SOFTKEYS_MAIN);
266 break;
267
268 #ifdef ALLOW_MAILBOX_EDITING
269 case 'e' : PutLine0(-1, -1, catgets(elm_msg_cat,
270 ElmSet, ElmEditFolder,
271 "Edit folder"));
272 if (curr_folder.curr_mssg > 0) {
273 edit_mailbox();
274 }
275 else {
276 error(catgets(elm_msg_cat, ElmSet, ElmFolderIsEmpty,
277 "Folder is empty!"));
278 }
279 break;
280 #else
281 case 'e' : error(catgets(elm_msg_cat, ElmSet, ElmNoFolderEdit,
282 "Folder editing isn't configured in this version of ELM."));
283 break;
284 #endif
285
286 case 'f' : PutLine0(-1, -1, catgets(elm_msg_cat,
287 ElmSet, ElmForward,
288 "Forward"));
289 if (curr_folder.curr_mssg > 0) {
290 if(forward())
291 redraw++;
292 else
293 nufoot++;
294 } else {
295 error(catgets(elm_msg_cat, ElmSet, ElmNoMailToForward,
296 "No mail to forward!"));
297 FlushInput();
298 }
299 break;
300
301 case 'g' : PutLine0(-1, -1, catgets(elm_msg_cat,
302 ElmSet, ElmGroupReply,
303 "Group reply"));
304 if (curr_folder.curr_mssg > 0) {
305 if (curr_folder.headers[curr_folder.curr_mssg-1]->status & FORM_LETTER) {
306 error(catgets(elm_msg_cat, ElmSet, ElmCantGroupReplyForm,
307 "Can't group reply to a Form!!"));
308 FlushInput();
309 }
310 else {
311 redraw += reply_to_everyone();
312 }
313 }
314 else {
315 error(catgets(elm_msg_cat, ElmSet, ElmNoMailToReply,
316 "No mail to reply to!"));
317 FlushInput();
318 }
319 break;
320
321 case 'h' : if (filter)
322 PutLine0(-1, -1, catgets(elm_msg_cat,
323 ElmSet, ElmMessageWithHeaders,
324 "Message with headers..."));
325 else
326 PutLine0(-1, -1, catgets(elm_msg_cat,
327 ElmSet, ElmDisplayMessage,
328 "Display message"));
329 if(curr_folder.curr_mssg > 0) {
330 j = filter;
331 filter = FALSE;
332 i = show_msg(curr_folder.curr_mssg);
333 ResizeScreen();
334 while (i)
335 i = process_showmsg_cmd(i);
336 filter = j;
337 redraw++;
338 (void)get_page(curr_folder.curr_mssg);
339 } else
340 error(catgets(elm_msg_cat, ElmSet, ElmNoMailToRead,
341 "No mail to read!"));
342 break;
343
344 case 'M' : if (show_mlists)
345 {
346 char buffer[SLEN];
347
348 strcpy(buffer, catgets(elm_msg_cat, ElmSet,
349 ElmMlistOff,
350 "[Mlists Off]"));
351
352 PutLine0(LINES,(COLS-10)/2,buffer);
353 show_mlists = 0;
354 }
355 else
356 {
357 char buffer[SLEN];
358
359 strcpy(buffer, catgets(elm_msg_cat, ElmSet,
360 ElmMlistOn,
361 "[Mlists On]"));
362
363 PutLine0(LINES,(COLS-10)/2,buffer);
364
365 show_mlists = 1;
366 }
367 last_header_page = -1; /* force a redraw */
368 show_headers();
369 break;
370
371 case 'm' : PutLine0(-1, -1, catgets(elm_msg_cat,
372 ElmSet, ElmMail,
373 "Mail"));
374 redraw += send_message((char *)NULL,
375 (char *)NULL, (char *)NULL, SM_ORIGINAL);
376 break;
377
378 case ' ' :
379 case ctrl('J'):
380 case ctrl('M'): PutLine0(-1, -1, catgets(elm_msg_cat,
381 ElmSet, ElmDisplayMessage,
382 "Display message"));
383 if(curr_folder.curr_mssg > 0 ) {
384 define_softkeys(SOFTKEYS_READ);
385 i = show_msg(curr_folder.curr_mssg);
386 ResizeScreen();
387 while (i)
388 i = process_showmsg_cmd(i);
389 define_softkeys(SOFTKEYS_MAIN);
390 redraw++;
391 (void)get_page(curr_folder.curr_mssg);
392 } else
393 error(catgets(elm_msg_cat, ElmSet, ElmNoMailToRead,
394 "No mail to read!"));
395 break;
396
397 case 'n' : PutLine0(-1, -1, catgets(elm_msg_cat,
398 ElmSet, ElmNextMessage,
399 "Next Message"));
400 if(curr_folder.curr_mssg > 0 ) {
401 define_softkeys(SOFTKEYS_READ);
402 i = show_msg(curr_folder.curr_mssg);
403 ResizeScreen();
404 while (i)
405 i = process_showmsg_cmd(i);
406 define_softkeys(SOFTKEYS_MAIN);
407 redraw++;
408 if (++curr_folder.curr_mssg > curr_folder.num_mssgs)
409 curr_folder.curr_mssg = curr_folder.num_mssgs;
410 (void)get_page(curr_folder.curr_mssg);
411 } else
412 error(catgets(elm_msg_cat, ElmSet, ElmNoMailToRead,
413 "No mail to read!"));
414 break;
415
416 case 'o' : PutLine0(-1, -1, catgets(elm_msg_cat,
417 ElmSet, ElmOptions,
418 "Options"));
419 if((i=options()) > 0)
420 get_page(curr_folder.curr_mssg);
421 redraw++; /* always fix da screen... */
422 break;
423
424 case 'p' : PutLine0(-1, -1, catgets(elm_msg_cat,
425 ElmSet, ElmPrintMail,
426 "Print mail"));
427 if (curr_folder.num_mssgs < 1) {
428 error(catgets(elm_msg_cat, ElmSet, ElmNoMailToPrint,
429 "No mail to print!"));
430 } else if (print_msg(TRUE) != 0)
431 redraw++;
432 break;
433
434 case 'q' : PutLine0(-1, -1, catgets(elm_msg_cat,
435 ElmSet, ElmQuit,
436 "Quit"));
437 quit(TRUE);
438 break;
439
440 case 'Q' : PutLine0(-1, -1, catgets(elm_msg_cat,
441 ElmSet, ElmQuickQuit,
442 "Quick quit"));
443 quit(FALSE);
444 break;
445
446 case 'r' : PutLine0(-1, -1, catgets(elm_msg_cat,
447 ElmSet, ElmReplyToMessage,
448 "Reply to message"));
449 if (curr_folder.curr_mssg > 0)
450 redraw += reply();
451 else {
452 error(catgets(elm_msg_cat, ElmSet, ElmNoMailToReplyTo,
453 "No mail to reply to!"));
454 FlushInput();
455 }
456 break;
457
458 case '>' : /** backwards compatibility **/
459
460 case 'C' :
461 case 's' : if (curr_folder.num_mssgs < 1) {
462 if (ch != 'C')
463 error(catgets(elm_msg_cat, ElmSet, ElmNoMailToSave,
464 "No mail to save!"));
465 else
466 error(catgets(elm_msg_cat, ElmSet, ElmNoMailToCopy,
467 "No mail to copy!"));
468 FlushInput();
469 }
470 else {
471 if (save(&redraw, FALSE, (ch != 'C'))
472 && resolve_mode && ch != 'C') {
473 if((i=next_message(curr_folder.curr_mssg-1, TRUE)) != -1) {
474 curr_folder.curr_mssg = i+1;
475 nucurr = get_page(curr_folder.curr_mssg);
476 }
477 }
478 }
479 ClearLine(LINES-2);
480 break;
481
482 #ifdef ALLOW_STATUS_CHANGING
483 case 'S' : PutLine0(-1, -1, "Status");
484 /* catgets(elm_msg_cat, ElmSet, ElmOptions, */
485 if((i=ch_status()) > 0)
486 get_page(curr_folder.curr_mssg);
487 redraw++; /* always fix da screen... */
488 break;
489 #else
490 case 'S' : error(catgets(elm_msg_cat, ElmSet, ElmNoStatusChange,
491 "Status changing isn't configured in this version of ELM."));
492 break;
493 #endif
494
495 case 'X' : PutLine0(-1, -1, catgets(elm_msg_cat,
496 ElmSet, ElmQuickExit,
497 "Quick Exit"));
498 quit_abandon(FALSE);
499
500 case ctrl('Q') :
501 case 'x' : PutLine0(-1, -1, catgets(elm_msg_cat,
502 ElmSet, ElmExit,
503 "Exit"));
504 quit_abandon(TRUE);
505 break;
506
507 case '@':
508 case '#':
509 for (;;) {
510 error(
511 "Debug: display p)age, current m)essage, t)erminal, or q)uit to return.");
512 if ((i = ReadCh()) == 'q')
513 break;
514 switch (i) {
515 case 'p': debug_page(); break;
516 case 'm': debug_message(); break;
517 case 't': debug_terminal(); break;
518 default: Beep();
519 }
520 }
521 clear_error();
522 redraw++;
523 break;
524
525 /* None of the menu specific commands were chosen, therefore
526 * it must be a "motion" command (or an error). */
527 default : motion(ch);
528
529 }
530
531 if (redraw) {
532 showscreen();
533 redraw = 0;
534 nucurr = 0;
535 nufoot = 0;
536 }
537
538 check_range();
539
540 if (nucurr == NEW_PAGE)
541 show_headers();
542 else if (nucurr == SAME_PAGE)
543 show_current();
544 else if (nufoot) {
545 if (mini_menu) {
546 MoveCursor(LINES-7, 0);
547 CleartoEOS();
548 show_menu();
549 }
550 else {
551 MoveCursor(LINES-4, 0);
552 CleartoEOS();
553 }
554 show_last_error(); /* for those operations that have to
555 * clear the footer except for a message.
556 */
557 }
558
559 } /* the BIG while loop! */
560 }
561
debug_page()562 debug_page()
563 {
564 int i, first, last, line;
565 char buffer[SLEN];
566
567 first = header_page * headers_per_page; /* starting header */
568 if ((last = first + (headers_per_page-1)) >= curr_folder.num_mssgs)
569 last = curr_folder.num_mssgs-1;
570
571 ClearScreen();
572 PutLine1(0, 0, "Current mail file = %s",
573 curr_folder.filename);
574 PutLine2(1, 0, "Current message number = %-8d %d message(s) total",
575 curr_folder.curr_mssg, curr_folder.num_mssgs);
576 PutLine2(2, 0, "Header_page = %-8d %d page(s) total",
577 header_page+1, (int) (curr_folder.num_mssgs / headers_per_page) + 1);
578 sprintf(buffer, "%3s %-16s %-34s %5s %8s %8s",
579 "Num", "From", "Subject", "Lines", "Offset", "ContLen");
580 PutLine0(4, 0, buffer);
581
582 line = 5;
583 for (i = first ; i <= last ; ++i) {
584 sprintf(buffer,
585 "%3d %-16.16s %-35.35s %4d %8d %8d",
586 i+1,
587 curr_folder.headers[i]->from,
588 curr_folder.headers[i]->subject,
589 curr_folder.headers[i]->lines,
590 curr_folder.headers[i]->offset,
591 curr_folder.headers[i]->content_length);
592 PutLine0(++line, 0, buffer);
593 }
594
595 }
596
597 static void
debug_message()598 debug_message()
599 {
600 /**** Spit out the current message record. Include EVERYTHING
601 in the record structure. **/
602
603 struct header_rec *hdr;
604 char buffer[SLEN];
605 time_t tval;
606 int row, i;
607
608 #define ShowStr(row, name, str) PutLine2((row), 0, \
609 (strlen(str) > 62 ? "%-16s|%.60s..." : "%-16s|%s|"), (name), (str))
610 #define ShowNum(row, name, num) PutLine2((row), 0, \
611 "%-16s%ld", (name), (long)(num))
612
613 ClearScreen();
614 PutLine1(0, 24,
615 "--- Debug Display - Message %d Header_Rec ---",
616 curr_folder.curr_mssg);
617
618 PutLine0(2, 24, "status:");
619 PutLine0(2, 32, "A C D E F M D N N O P T U V");
620 PutLine0(3, 32, "c o e x o i e p e l r a r i");
621 PutLine0(4, 32, "t n l p r m c l w d i g g s");
622 PutLine0(5, 32, "n f d d m e o a v d n i");
623
624 if (curr_folder.num_mssgs == 0) {
625 CenterLine(8, catgets(elm_msg_cat, ElmSet, ElmNoMailToCheck,
626 "No mail to check."));
627 return;
628 }
629 hdr = curr_folder.headers[curr_folder.curr_mssg-1];
630
631 ShowNum(2, "index_number:", hdr->index_number);
632 ShowNum(3, "offset:", hdr->offset);
633 ShowNum(4, "lines:", hdr->lines);
634 ShowNum(5, "content_length:", hdr->content_length);
635 ShowNum(6, "cc_index:", hdr->cc_index);
636 ShowStr(7, "mailx_status:", hdr->mailx_status);
637
638 #define SHOW_STATUS(hdr, FLAG) (!!((hdr)->status & (FLAG)))
639 sprintf(buffer, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d",
640 SHOW_STATUS(hdr, ACTION),
641 SHOW_STATUS(hdr, CONFIDENTIAL),
642 SHOW_STATUS(hdr, DELETED),
643 SHOW_STATUS(hdr, EXPIRED),
644 SHOW_STATUS(hdr, FORM_LETTER),
645 SHOW_STATUS(hdr, MIME_MESSAGE),
646 SHOW_STATUS(hdr, MIME_NEEDDECOD),
647 SHOW_STATUS(hdr, MIME_NOTPLAIN),
648 SHOW_STATUS(hdr, NEW),
649 SHOW_STATUS(hdr, UNREAD),
650 SHOW_STATUS(hdr, PRIVATE),
651 SHOW_STATUS(hdr, TAGGED),
652 SHOW_STATUS(hdr, URGENT),
653 SHOW_STATUS(hdr, VISIBLE));
654 PutLine0(7, 32, buffer);
655 row = 8;
656
657 trim_trailing_spaces(strcpy(buffer, ctime(&hdr->received_time)));
658 ShowStr(++row, "received_time:", buffer);
659 tval = hdr->time_sent + hdr->tz_offset;
660 trim_trailing_spaces(strcpy(buffer, ctime(&tval)));
661 ShowStr(++row, "time_sent:", buffer);
662 ShowStr(++row, "time_zone:", hdr->time_zone);
663 ShowNum(++row, "tz_offset:", hdr->tz_offset);
664 ShowStr(++row, "from:", hdr->from);
665 ShowStr(++row, "to:", hdr->to);
666 ShowStr(++row, "subject:", hdr->subject);
667 ShowStr(++row, "messageid:", hdr->messageid);
668 ShowStr(++row, "allfrom:", hdr->allfrom);
669 ShowStr(++row, "allto:", hdr->allto);
670
671 ShowNum(++row, "ml_cc_index:", hdr->ml_cc_index);
672 ShowStr(++row, "ml_to:", "");
673 WriteChar('\b'); /* erase closing "|" added above */
674 for (i = 0; i < hdr->ml_to.len; i++) {
675 if (i > 0)
676 PutLine0(-1, -1, ", ");
677 PutLine0(-1, -1, hdr->ml_to.str[i]);
678 }
679 WriteChar('|');
680 }
681
check_range()682 check_range()
683 {
684 int count, curr, i;
685
686 if (inalias) {
687 count = num_aliases;
688 curr = curr_alias;
689 } else {
690 count = curr_folder.num_mssgs;
691 curr = curr_folder.curr_mssg;
692 }
693
694 i = compute_visible(curr);
695
696 if ((curr < 1) || (selected && i < 1)) {
697 if (count > 0) {
698 /* We are out of range! Get to first message! */
699 if (selected)
700 curr = compute_visible(1);
701 else
702 curr = 1;
703 }
704 else
705 curr = 0;
706 }
707 else if ((curr > count) || (selected && i > selected)) {
708 if (count > 0) {
709 /* We are out of range! Get to last (visible) message! */
710 if (selected)
711 curr = visible_to_index(selected)+1;
712 else
713 curr = count;
714 }
715 else
716 curr = 0;
717 }
718
719
720 if (inalias)
721 curr_alias = curr;
722 else
723 curr_folder.curr_mssg = curr;
724
725 }
726
727 static char *no_mail = NULL;
728 static char *no_aliases = NULL;
729
730 #define ifmain(a,b) (inalias ? (b) : (a))
731
motion(ch)732 motion(ch)
733 int ch;
734 {
735 /* Consolidated the standard menu navigation and delete/tag
736 * commands to a function. */
737
738 int key_offset; /** Position offset within keyboard string **/
739 int i;
740 int count, curr;
741
742 if (inalias) {
743 count = num_aliases;
744 curr = curr_alias;
745 } else {
746 count = curr_folder.num_mssgs;
747 curr = curr_folder.curr_mssg;
748 }
749
750 if (no_mail == NULL) {
751 no_mail = catgets(elm_msg_cat, ElmSet, ElmNoMailInFolder,
752 "No mail in folder!");
753 no_aliases = catgets(elm_msg_cat, ElmSet, ElmNoAliases,
754 "No aliases!");
755 }
756
757 switch (ch) {
758
759 case '/' : /* scan mbox or aliases for string */
760 if (count < 1) {
761 error1(catgets(elm_msg_cat, ElmSet,
762 ElmNoItemToScan, "No %s to scan!"), nls_items);
763 FlushInput();
764 }
765 else if (pattern_match()) {
766 if (inalias)
767 curr = curr_alias;
768 else
769 curr = curr_folder.curr_mssg;
770 nucurr = get_page(curr);
771 }
772 break;
773
774 case KEY_NPAGE:
775 case KEY_RIGHT:
776 case ctrl('V'):
777 case '+' : /* move to next page if we're not on the last */
778 if((selected &&
779 ((header_page+1)*headers_per_page < selected))
780 ||(!selected &&
781 ((header_page+1)*headers_per_page<count))){
782
783 header_page++;
784 nucurr = NEW_PAGE;
785
786 if(move_when_paged) {
787 /* move to first message of new page */
788 if(selected)
789 curr = visible_to_index(
790 header_page * headers_per_page + 1) + 1;
791 else
792 curr = header_page * headers_per_page + 1;
793 }
794 } else
795 error(catgets(elm_msg_cat, ElmSet, ElmAlreadyOnLastPage,
796 "Already on last page."));
797 break;
798
799 case KEY_PPAGE:
800 case KEY_LEFT:
801 case '-' : /* move to prev page if we're not on the first */
802 if(header_page > 0) {
803 header_page--;
804 nucurr = NEW_PAGE;
805
806 if(move_when_paged) {
807 /* move to first message of new page */
808 if(selected)
809 curr = visible_to_index(
810 header_page * headers_per_page + 1) + 1;
811 else
812 curr = header_page * headers_per_page + 1;
813 }
814 } else
815 error(catgets(elm_msg_cat, ElmSet, ElmAlreadyOnFirstPage,
816 "Already on first page."));
817 break;
818
819 case KEY_HOME:
820 case '=' : if (selected)
821 curr = visible_to_index(1)+1;
822 else
823 curr = 1;
824 nucurr = get_page(curr);
825 break;
826
827 case KEY_END:
828 case '*' : if (selected)
829 curr = (visible_to_index(selected)+1);
830 else
831 curr = count;
832 nucurr = get_page(curr);
833 break;
834
835 /* case EOF : leave(0);
836 break; */
837
838 case ctrl('D') :
839 case '^' :
840 case 'd' : if (count < 1) {
841 error1(catgets(elm_msg_cat, ElmSet, ElmNoItemToDelete,
842 "No %s to delete!"), nls_item);
843 /* fflush(stdin);*/
844 }
845 else {
846 if(ch == ctrl('D')) {
847
848 /* if current item did not become deleted,
849 * don't to move to the next undeleted item */
850 if(!meta_match(MATCH_DELETE))
851 break;
852
853 } else
854 delete_msg((ch == 'd'), TRUE);
855
856 if (resolve_mode) /* move after mail resolved */
857 if((i=next_message(curr-1, TRUE)) != -1) {
858 curr = i+1;
859 nucurr = get_page(curr);
860 }
861 }
862 break;
863
864 case 'H' : { /* move to first line of page */
865 int first_on_page;
866
867 if (selected)
868 first_on_page = visible_to_index(
869 header_page * headers_per_page + 1) + 1;
870 else
871 first_on_page = header_page*headers_per_page + 1;
872
873 /* don't bother to redraw if you don't move */
874 if (curr != first_on_page) {
875 curr = first_on_page;
876 nucurr = SAME_PAGE;
877 }
878
879 break;
880 }
881
882 case ctrl('N'):
883 case 'J' : if(curr > 0) {
884 if((i=next_message(curr-1, FALSE)) != -1) {
885 curr = i+1;
886 nucurr = get_page(curr);
887 } else
888 error1(catgets(elm_msg_cat, ElmSet, ElmNoMoreItemBelow,
889 "No more %s below."), nls_items);
890 } else error(ifmain(no_mail, no_aliases));
891 break;
892
893 next_undel_msg:
894 case KEY_DOWN:
895 case 'j' : if(curr > 0) {
896 if((i=next_message(curr-1, TRUE)) != -1) {
897 curr = i+1;
898 nucurr = get_page(curr);
899 } else
900 error1(catgets(elm_msg_cat, ElmSet, ElmNoItemUndeletedBelow,
901 "No more undeleted %s below."), nls_items);
902 } else error(ifmain(no_mail, no_aliases));
903 break;
904
905 case ctrl('P'):
906 case 'K' : if(curr > 0) {
907 if((i=prev_message(curr-1, FALSE)) != -1) {
908 curr = i+1;
909 nucurr = get_page(curr);
910 } else
911 error1(catgets(elm_msg_cat, ElmSet, ElmNoMoreItemAbove,
912 "No more %s above."), nls_items);
913 } else error(ifmain(no_mail, no_aliases));
914 break;
915
916 case KEY_UP:
917 case 'k' : if(curr > 0) {
918 if((i=prev_message(curr-1, TRUE)) != -1) {
919 curr = i+1;
920 nucurr = get_page(curr);
921 } else
922 error1(catgets(elm_msg_cat, ElmSet, ElmNoMoreUndeletedAbove,
923 "No more undeleted %s above."), nls_items);
924 } else error(ifmain(no_mail, no_aliases));
925 break;
926
927 case 'L' : { /* move to last line of page */
928 int last_on_page, last_of_all, last_line;
929
930 if (selected) {
931 last_on_page = visible_to_index(
932 (header_page + 1) * headers_per_page) + 1;
933 last_of_all = (visible_to_index(selected) + 1);
934 } else {
935 last_on_page = (header_page+1) * headers_per_page;
936 last_of_all = count;
937 }
938
939 if (last_on_page < last_of_all)
940 last_line = last_on_page;
941 else
942 last_line = last_of_all;
943
944 /* don't bother to redraw if you don't move */
945 if (curr != last_line) {
946 curr = last_line;
947 nucurr = SAME_PAGE;
948 }
949
950 break;
951 }
952
953 case 'l' : PutLine1(LINES-3, strlen(nls_Prompt),
954 catgets(elm_msg_cat, ElmSet, ElmLimitDisplayBy,
955 "Limit displayed %s by..."), nls_items);
956 clear_error();
957 if (limit() != 0) {
958 curr = curr_folder.curr_mssg;
959 nucurr = get_page(curr);
960 redraw++;
961 } else {
962 nufoot++;
963 }
964 break;
965
966 case ctrl('T') :
967 case 'T' :
968 case 't' : if (count < 1) {
969 error1(catgets(elm_msg_cat, ElmSet, ElmNoItemToTag,
970 "No %s to tag!"), nls_items);
971 }
972 else if (ch == 't')
973 tag_message(TRUE);
974 else if (ch == 'T') {
975 tag_message(TRUE);
976 goto next_undel_msg;
977 }
978 else
979 (void) meta_match(MATCH_TAG);
980 break;
981
982 case 'u' : if (count < 1) {
983 error1(catgets(elm_msg_cat, ElmSet, ElmNoItemToMarkUndeleted,
984 "No %s to mark as undeleted!"), nls_items);
985 }
986 else
987 {
988
989 /* Overload u to have it mark unread a read
990 * message which is not deleted.
991 */
992
993 if ( (!inalias) && (isoff(curr_folder.headers[curr_folder.curr_mssg-1]->status, DELETED)))
994 {
995 setit(curr_folder.headers[curr_folder.curr_mssg-1]->status, UNREAD);
996 curr_folder.headers[curr_folder.curr_mssg-1]->status_chgd = TRUE;
997 show_msg_status(curr_folder.curr_mssg-1);
998 }
999 else
1000 undelete_msg(TRUE);
1001 if (resolve_mode) /* move after mail resolved */
1002 if((i=next_message(curr-1, FALSE)) != -1) {
1003 curr = i+1;
1004 nucurr = get_page(curr);
1005 }
1006 /*************************************************************************
1007 ** What we've done here is to special case the "U)ndelete" command to
1008 ** ignore whether the next message is marked for deletion or not. The
1009 ** reason is obvious upon usage - it's a real pain to undelete a series
1010 ** of messages without this quirk. Thanks to Jim Davis @ HPLabs for
1011 ** suggesting this more intuitive behaviour.
1012 **
1013 ** The old way, for those people that might want to see what the previous
1014 ** behaviour was to call next_message with TRUE, not FALSE.
1015 **************************************************************************/
1016 }
1017 break;
1018
1019 case ctrl('U') : if (count < 1) {
1020 error1(catgets(elm_msg_cat, ElmSet, ElmNoItemToUndelete,
1021 "No %s to undelete!"), nls_items);
1022 }
1023 else
1024 (void) meta_match(MATCH_UNDELETE);
1025 break;
1026
1027 case ctrl('L') : redraw++; break;
1028
1029 default : if (ch > '0' && ch <= '9') {
1030 PutLine1(LINES-3, strlen(nls_Prompt),
1031 catgets(elm_msg_cat, ElmSet, ElmNewCurrentItem,
1032 "New Current %s"), nls_Item);
1033 UnreadCh(ch);
1034 i = enter_number(LINES-3, curr, nls_item);
1035
1036 if( i > count)
1037 error1(catgets(elm_msg_cat, ElmSet, ElmNotThatMany,
1038 "Not that many %s."), nls_items);
1039 else if(selected
1040 && isoff(ifmain(curr_folder.headers[i-1]->status,
1041 aliases[i-1]->status), VISIBLE))
1042 error1(catgets(elm_msg_cat, ElmSet, ElmNotInLimitedDisplay,
1043 "%s not in limited display."), nls_Item);
1044 else {
1045 curr = i;
1046 nucurr = get_page(curr);
1047 }
1048 }
1049 else {
1050 error(catgets(elm_msg_cat, ElmSet, ElmUnknownCommand,
1051 "Unknown command. Use '?' for help."));
1052 FlushInput();
1053 }
1054 }
1055
1056 if (inalias)
1057 curr_alias = curr;
1058 else
1059 curr_folder.curr_mssg = curr;
1060 }
1061