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