[mod.sources] v09i017: ELM Mail System, Part17/19

sources-request@mirror.UUCP (03/12/87)

Submitted by: Dave Taylor <hplabs!taylor>
Mod.sources: Volume 9, Issue 17
Archive-name: elm2/Part17

#! /bin/sh
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
# If this archive is complete, you will see the message:
#		"End of archive 17 (of 19)."
# Contents:  src/elm.c src/mailmsg2.c
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo shar: Extracting \"src/elm.c\" \(19751 characters\)
if test -f src/elm.c ; then 
  echo shar: Will not over-write existing file \"src/elm.c\"
else
sed "s/^X//" >src/elm.c <<'END_OF_src/elm.c'
X/**			elm.c			**/
X
X/* Main program of the ELM mail system! 
X
X   This file and all associated files and documentation:
X	(C) Copyright 1986 Dave Taylor
X*/
X
X#include "elm.h"
X
X#ifdef BSD
X# undef toupper
X# undef tolower
X#endif
X
Xlong bytes();
Xchar *format_long();
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	char ch, address[SLEN], to_whom[LONG_SLEN];
X	int  redraw, 		/** do we need to rewrite the entire screen? **/
X	     nuhead, 		/** or perhaps just the headers section...   **/
X	     nucurr, 		/** or just the current message pointer...   **/
X	     nufoot; 		/** clear lines 16 thru bottom and new menu  **/
X	int  i;      		/** Random counting variable (etc)           **/
X	int  pageon, 		/** for when we receive new mail...          **/
X	     last_in_mailbox;	/** for when we receive new mail too...      **/
X
X	parse_arguments(argc, argv, to_whom);
X
X	if (mail_only) {
X
X	   initialize(FALSE);
X
X	   Raw(ON);
X	   dprint1(3,"Mail-only: mailing to\n-> \"%s\"\n", 
X		   format_long(to_whom, 3));
X	   (void) send(to_whom, "", TRUE, NO); 
X	   leave(0);
X	}
X
X	initialize(TRUE);
X
X	ScreenSize(&LINES, &COLUMNS);
X
X	showscreen();
X
X	mailfile_size = bytes(infile);
X
X	Raw(ON);
X
X	while (1) {
X	  redraw = 0;
X	  nuhead = 0;
X	  nufoot = 0;
X	  nucurr = 0;
X	  if ((i = bytes(infile)) != mailfile_size) {
X	    dprint1(2,"Just received %d bytes more mail (elm)\n", 
X		    i - mailfile_size);
X	    error("New mail has arrived!   Hang on...");
X	    last_in_mailbox = message_count;
X	    pageon = header_page;
X	    newmbox(2, FALSE, TRUE);	/* last won't be touched! */
X	    clear_error();
X	    header_page = pageon;
X
X	    if (on_page(current))   /* do we REALLY have to rewrite? */
X	      showscreen();
X	    else {
X	      update_title();
X	      ClearLine(LINES-1);	     /* remove reading message... */
X	      error2("%d new message%s received", 
X		     message_count - last_in_mailbox,
X		     plural(message_count - last_in_mailbox));
X	    }
X	    mailfile_size = i;
X	    if (cursor_control)
X	      transmit_functions(ON);	/* insurance */
X	  }
X
X	  prompt("Command: ");
X
X	  CleartoEOLN();
X	  ch = tolower(GetPrompt()); 
X	  CleartoEOS();
X	  dprint1(4, "\nCommand: %c\n\n", ch);
X
X	  set_error("");	/* clear error buffer */
X
X	  MoveCursor(LINES-3,strlen("Command: "));
X
X	  switch (ch) {
X
X	    case '?' 	:  if (help())
X	  		     redraw++;
X			   else
X			     nufoot++;
X			   break;
X
X	    case '$'    : resync(); 					break;
X
X	    case ' '    : 
X	    case '+'	:  header_page++; nuhead++;	
X			   if (move_when_paged && header_page <=
X			      (message_count / headers_per_page)) {
X			     current = header_page*headers_per_page + 1;
X			     if (selected)
X			       current = visible_to_index(current)+1;
X	                   }
X			   break;
X
X	    case '-'    :  header_page--; nuhead++;	
X			   if (move_when_paged && header_page >= 0) {
X			     current = header_page*headers_per_page + 1;
X			     if (selected)
X			       current = visible_to_index(current)+1;
X			   }
X			   break;
X
X	    case '='    :  if (selected)
X			     current = visible_to_index(1)+1;
X	                   else
X			     current = 1;
X	                   if (get_page(current))
X			     nuhead++;	
X			   else
X			     nucurr++; 			break;
X
X	    case '*'    :  if (selected) 
X			     current = (visible_to_index(selected)+1);
X			   else
X			     current = message_count;	
X	                   if (get_page(current))
X			     nuhead++;	
X			   else
X			     nucurr++; 			break;
X
X	    case '|'    :  Writechar('|'); 
X	    		   softkeys_off();
X                           redraw = do_pipe();		
X	                   softkeys_on(); 		break;
X
X	    case '!'    :  Writechar('!'); 
X	    		   softkeys_off();
X                           redraw = subshell();		
X	                   softkeys_on(); 		break;
X
X	    case '%'    :  get_return(address);
X			   clear_error();
X			   PutLine1(LINES,(COLUMNS-strlen(address))/2,
X			            "%.78s", address);	
X		           break;
X
X	    case '/'    :  if (pattern_match()) {
X	                     if (get_page(current))
X			       nuhead++;
X	                     else
X	                       nucurr++;
X	                   }
X			   else 
X			      error("pattern not found!");
X			   break;
X
X	    case '<'    :  /* scan current message for calendar information */
X#ifdef ENABLE_CALENDAR
X			   PutLine0(LINES-3, strlen("Command: "), 	
X				   "Scan message for calendar entries...");
X			   scan_calendar();
X#else
X	 		   error("Sorry - calendar function disabled");
X#endif
X			   break;
X
X	    case 'a'    :  alias();     
X			   nufoot++; 	
X			   define_softkeys(MAIN); 	break;
X			
X	    case 'b'    :  PutLine0(LINES-3, strlen("Command: "), 
X		             "Bounce message");
X			   fflush(stdout);
X			   if (message_count < 1)
X	  		     error("No mail to bounce!");
X			   else 
X			     nufoot = remail();
X			   break;
X
X	    case 'c'    :  PutLine0(LINES-3, strlen("Command: "), 
X			      "Change mailbox");
X			   define_softkeys(CHANGE);
X			   if ((file_changed = leave_mbox(FALSE)) != -1) {
X	                     redraw = newmbox(0, TRUE, TRUE);
X	    		     dprint1(1, "** redraw returned as %d **\n",
X				     redraw);
X			     mailfile_size = bytes(infile);	
X	      	           }
X			   else {
X			     file_changed = 0;
X			     sort_mailbox(message_count, FALSE);
X			   }
X			   define_softkeys(MAIN);
X			   break;
X
X	    case '^'    :
X	    case 'd'    :  if (message_count < 1)
X			     error("No mail to delete!");
X			   else {
X 	                     delete_msg((ch == 'd'));			
X			     if (resolve_mode) 	/* move after mail resolved */
X			       if (current < message_count) {
X	                         current++;  		
X			         if (get_page(current))
X			           nuhead++;
X			         else
X			           nucurr++;
X			       }
X	                   }
X			   break;
X
X	    case ctrl('D') : if (message_count < 1)
X			       error("No mail to delete!");
X			     else 
X			       meta_match(DELETED);
X			     break;
X
X	    case 'e'    :  PutLine0(LINES-3,strlen("Command: "),"Edit mailbox");
X			   if (current > 0) {
X			     edit_mailbox();
X	    		     if (cursor_control)
X	                       transmit_functions(ON);	/* insurance */
X	   		   }
X			   else
X			     error("Mailbox is empty!");
X			   break;
X		
X	    case 'f'    :  PutLine0(LINES-3, strlen("Command: "), "Forward");
X			   define_softkeys(YESNO);
X			   if (current > 0)  
X	                     redraw = forward();   
X			   else 
X	                     error("No mail to forward!");
X			   define_softkeys(MAIN);
X			   break;
X
X	    case 'g'    :  PutLine0(LINES-3,strlen("Command: "), "Group reply");
X		           fflush(stdout);
X			   if (current > 0) {
X			     if (header_table[current-1].status & FORM_LETTER)
X			       error("Can't group reply to a Form!!");
X			     else {
X			       PutLine0(LINES-3,COLUMNS-40,
X                                       "building addresses...");
X			       define_softkeys(YESNO);
X	                       redraw = reply_to_everyone();	
X			       define_softkeys(MAIN);
X	                     }
X	                   }
X			   else 
X			     error("No mail to reply to!"); 
X			   break;
X
X	    case 'h'    :  if (filter)
X	                     PutLine0(LINES-3, strlen("Command: "), 
X				"Message with headers...");
X	                   else
X			     PutLine0(LINES-3, strlen("Command: "),"Read message");
X			   fflush(stdout);
X			   i = filter;
X			   filter = FALSE;
X			   redraw = show_msg(current);
X			   filter = i;
X			   break;
X
X	    case 'j'    :  if (selected) {
X			     if ((current = next_visible(current)) < 0)
X	                       current = visible_to_index(selected)+1;
X			   }
X			   else 
X	                     current++;  
X			   if (get_page(current))
X			     nuhead++;
X			   else
X			     nucurr++;			break;
X
X	    case 'k'    :  if (selected) 
X			     current = previous_visible(current);
X	     		   else
X	                     current--;  
X			   if (get_page(current))
X			     nuhead++;
X			   else
X			     nucurr++;			break;
X
X	    case 'l'    :  PutLine0(LINES-3, strlen("Command: "),
X			           "Limit displayed messages by...");
X			   if (limit() != 0) {
X	                     nuhead++;
X	   		     update_title();	/* poof! */
X			   }
X			   else
X	    		     nufoot++;
X			   break;
X
X	    case 'm'    :  PutLine0(LINES-3, strlen("Command: "), "Mail");
X			   redraw = send("", "", TRUE, allow_forms); 
X			   break;
X
X	    case ctrl('J'):
X	    case ctrl('M'):PutLine0(LINES-3, strlen("Command: "), "Read Message");	
X			   fflush(stdout);
X			   define_softkeys(READ);
X			   redraw = show_msg(current);
X			   break;
X
X	    case 'n'    :  PutLine0(LINES-3, strlen("Command: "), "Next Message");
X			   fflush(stdout);
X			   define_softkeys(READ);
X			   redraw = show_msg(current);
X			   current += redraw;		
X			   if (current > message_count)
X			     current = message_count;
X			   (void) get_page(current); /* rewrites ANYway */
X			   break;
X
X	    case 'o'    :  PutLine0(LINES-3, strlen("Command: "), "Options");
X			   options();
X			   redraw++;	/* always fix da screen... */
X			   break;
X
X	    case 'p'    :  PutLine0(LINES-3, strlen("Command: "), "Print mail");
X			   fflush(stdout);
X			   if (message_count < 1)
X			     error("No mail to print!");
X			   else
X			     printmsg();			
X			   break;
X
X	    case 'q'    :  PutLine0(LINES-3, strlen("Command: "), "Quit");
X
X			   if (mbox_specified == 0) lock(OUTGOING);
X
X			   if (mailfile_size != bytes(infile)) {
X			     error("New Mail!  Quit cancelled...");
X	  		     if (mbox_specified == 0) unlock();
X	                   }
X		           else
X			     quit();		
X
X			   break;
X
X	    case 'r'    :  PutLine0(LINES-3, strlen("Command: "), 
X			      "Reply to message");
X			   if (current > 0) 
X	                     redraw = reply();	
X			   else 
X			     error("No mail to reply to!"); 
X			   softkeys_on();
X			   break;
X
X	    case '>'    : /** backwards compatibility **/
X
X	    case 's'    :  if  (message_count < 1)
X			     error("No mail to save!");
X			   else {
X	                     PutLine0(LINES-3, strlen("Command: "),
X				      "Save Message");
X			     PutLine0(LINES-3,COLUMNS-40,
X				"(Use '?' to list your folders)");
X			     if (save(&redraw) && resolve_mode) {
X			       if (current < message_count) {
X			         current++;	/* move to next message */
X			         if (get_page(current))
X			           nuhead++;
X			         else
X			           nucurr++;		
X			       }
X			     }
X			   }
X			   ClearLine(LINES-2);		
X			   break;
X
X            case ctrl('T') :
X	    case 't'       :  if (message_count < 1)
X			        error("no mail to tag!");
X			      else if (ch == 't')
X			        tag_message(); 
X			      else
X			        meta_match(TAGGED);
X	                      break;
X
X	    case 'u'    :  if (message_count < 1)
X			     error("no mail to mark as undeleted!");
X			   else {
X	                     undelete_msg();		        
X			     if (resolve_mode) 	/* move after mail resolved */
X			       if (current < message_count) {
X	                         current++;  		
X			         if (get_page(current))
X			           nuhead++;
X			         else
X			           nucurr++;
X			       }
X			   }
X			   break;
X
X	    case ctrl('U') : if (message_count < 1)
X			       error("No mail to undelete!");
X			     else 
X			       meta_match(UNDELETE);
X			     break;
X
X	    case ctrl('Q') :
X	    case ctrl('?') : 
X	    case 'x'    :  PutLine0(LINES-3, strlen("Command: "), "Exit");  
X                           fflush(stdout);              leave();
X
X	    case ctrl('L') : redraw++;	break;
X	    
X	    case '@'    : debug_screen();  redraw++;	break;
X	
X	    case '#'    : debug_message(); redraw++;	break;
X
X	    case NO_OP_COMMAND : break;	/* noop for timeout loop */
X
X	    case ESCAPE : if (cursor_control) {
X			    ch = ReadCh(); 
X	                    if (ch == up[1]) {
X			      if (selected)
X			        current = previous_visible(current);
X			      else 
X			        current--;
X			      if (get_page(current))
X			        nuhead++;
X			      else
X			        nucurr++;			
X	                    }
X			    else if (ch == down[1]) {
X			      if (selected) {
X			        if ((current = next_visible(current)) < 0)
X	                          current = visible_to_index(selected)+1;
X			      }
X			      else 
X			        current++;
X			      if (get_page(current))
X			        nuhead++;
X			      else
X			        nucurr++;			
X			    }
X			    else if (hp_terminal) { 
X
X			     switch (ch) {
X			      case 'U' :	/* <NEXT> */
X	    			 header_page++; 
X				 nuhead++;
X			         if (move_when_paged && header_page 
X			             <= (message_count / headers_per_page)) {
X			           current = header_page*headers_per_page + 1;
X			           if (selected)
X			             current = visible_to_index(current)+1;
X			         }
X				 break;
X
X			      case 'V' :       /* <PREV> */
X	    			header_page--; 
X				nuhead++;
X			        if (move_when_paged && header_page >= 0) {
X			           current = header_page*headers_per_page + 1;
X			           if (selected)
X			             current = visible_to_index(current)+1;
X			         }
X				break;
X
X			      case 'h' : 	
X			      case 'H' : 	/* <HOME UP> */
X	    		        if (selected)
X			          current = visible_to_index(1)+1;
X	                        else
X			          current = 1;
X	                        if (get_page(current))
X			          nuhead++;
X	                        else
X	                          nucurr++;
X				break;
X
X			      case 'F' : 	/* <HOME DOWN> */
X	    		        if (selected)
X			          current = visible_to_index(selected)+1;
X	                        else
X			          current = message_count;
X	                        if (get_page(current))
X			          nuhead++;
X	                        else
X	                          nucurr++;
X			        break;
X
X			      /** let's continue, what the heck... **/
X
X			      case 'A' : 	/* <UP> */
X			      case 'D' : 	/* <BACKTAB> */
X			      case 'i' : 	/* <LEFT> */
X			         if (selected)
X			           current = previous_visible(current);
X			         else 
X			           current--;
X			         if (get_page(current))
X			           nuhead++;
X			         else
X			           nucurr++;			
X				 break;
X
X			      case 'B' : 	/* <UP> */
X			      case 'I' : 	/* <BACKTAB> */
X			      case 'C' : 	/* <LEFT> */
X			         if (selected) {
X			           if ((current = next_visible(current)) < 0)
X	                             current = visible_to_index(selected)+1;
X			         }
X			         else 
X			           current++;
X			         if (get_page(current))
X			           nuhead++;
X			         else
X			           nucurr++;			
X			         break;
X
X			      default: PutLine2(LINES-3, strlen("Command: "), 
X				          "%c%c", ESCAPE, ch);
X			     }
X			    }
X			    else /* false hit - output */
X			      PutLine2(LINES-3, strlen("Command: "), 
X				          "%c%c", ESCAPE, ch);
X			    break;
X			  }
X
X			  /* else fall into the default error message! */
X
X	    default	: if (ch > '0' && ch <= '9') {
X			    PutLine0(LINES-3, strlen("Command: "), 
X				    "New Current Message");
X			    current = read_number(ch);
X			    if (selected) {
X			      if ((current = visible_to_index(current)+1) >
X				  message_count)
X			        goto too_big;
X	                    }
X	                    if (get_page(current))
X			      nuhead++;
X	                    else
X	                      nucurr++;
X			  }
X			  else
X	 		    error("Unknown command: Use '?' for commands");
X	  }
X
X	  dprint5(4,"redraw=%s, current=%d, nuhead=%s, nufoot=%s, nucurr=%s\n",
X		  onoff(redraw), current, onoff(nuhead), onoff(nufoot),
X		  onoff(nucurr));
X
X	  if (redraw)
X	    showscreen();
X
X	  if (current < 1) {
X	    if (message_count > 0) {
X	      error("already at message #1!");
X	      if (selected)
X	        current = compute_visible(0);	/* get to #0 */
X	      else
X	        current = 1;
X	    }
X	    else if (current < 0) {
X	      error("No messages to read!");
X	      current = 0;
X	    }
X	  }
X	  else if (current > message_count) {
X	    if (message_count > 0) {
Xtoo_big:
X	      if (selected) {
X	        error2("only %d message%s selected!", selected, 
X			plural(selected));
X	        current = compute_visible(selected);
X	      }
X	      else {
X	        error2("only %d message%s!", message_count, 
X		       plural(message_count));
X	        current = message_count;
X	      }
X	    }
X	    else {
X	      error("No messages to read!");
X	      current = 0;
X	    }
X	  }
X	  else if (selected && (i=visible_to_index(selected)) > message_count) {
X	    error2("only %d message%s selected!", selected, plural(selected));
X	    current = i+1;	/* FIXED!  Phew! */
X	  }
X	    
X	  if (nuhead) 
X	    show_headers();
X	  else if (nucurr)
X	    show_current();
X	  else if (nufoot) {
X	    if (mini_menu) {
X	      MoveCursor(LINES-7, 0);  
X              CleartoEOS();
X	      show_menu();
X	    }
X	    else {
X	      MoveCursor(LINES-4, 0);
X	      CleartoEOS();
X	    }
X	  }
X
X	} /* the BIG while loop! */
X}
X
Xdebug_screen()
X{
X	/**** spit out all the current variable settings and the table
X	      entries for the current 'n' items displayed. ****/
X
X	register int i, j;
X	char     buffer[SLEN];
X
X	ClearScreen();
X	Raw(OFF);
X
X	PutLine2(0,0,"Current message number = %d\t\t%d message(s) total\n",
X	        current, message_count);
X	PutLine2(2,0,"Header_page = %d           \t\t%d possible page(s)\n",
X		header_page, (int) (message_count / headers_per_page) + 1);
X
X	PutLine1(4,0,"\nCurrent mailfile is %s.\n\n", infile);
X
X	i = header_page*headers_per_page;	/* starting header */
X
X	if ((j = i + (headers_per_page-1)) >= message_count) 
X	  j = message_count-1;
X
X	Write_to_screen(
X"Num      From                 	Subject                         Lines  Offset\n\n",0);
X
X	while (i <= j) {
X	   sprintf(buffer, 
X	   "%3d  %-16.16s  %-40.40s  %4d  %d\n",
X		    i+1,
X	            header_table[i].from, 
X	            header_table[i].subject,
X		    header_table[i].lines,
X		    header_table[i].offset);
X	    Write_to_screen(buffer, 0);
X	  i++;
X	}
X	
X	Raw(ON);
X
X	PutLine0(LINES,0,"Press any key to return: ");
X	(void) ReadCh();
X}
X
X
Xdebug_message()
X{
X	/**** Spit out the current message record.  Include EVERYTHING
X	      in the record structure. **/
X	
X	char buffer[SLEN];
X
X	ClearScreen();
X	Raw(OFF);
X
X	Write_to_screen("\t\t\t----- Message %d -----\n\n\n\n", 1,
X		current);
X
X	Write_to_screen("Lines : %-5d\t\t\t\tStatus: N  E  A  P  D  T  V\n", 1,
X		header_table[current-1].lines);
X	Write_to_screen("            \t\t\t\t        e  x  c  r  e  a  i\n", 0);
X	Write_to_screen("            \t\t\t\t        w  p  t  i  l  g  s\n", 0);
X
X	sprintf(buffer, 
X		"\nOffset: %ld\t\t\t\t          %d  %d  %d  %d  %d  %d  %d\n",
X		header_table[current-1].offset,
X		(header_table[current-1].status & NEW) != 0,
X		(header_table[current-1].status & EXPIRED) != 0,
X		(header_table[current-1].status & ACTION) != 0,
X		(header_table[current-1].status & PRIORITY) != 0,
X		(header_table[current-1].status & DELETED) != 0,
X	        (header_table[current-1].status & TAGGED) != 0,
X		(header_table[current-1].status & VISIBLE) != 0);
X	Write_to_screen(buffer, 0);
X
X	sprintf(buffer, "\nReceived on: %d/%d/%d at %d:%02d\n\n",
X	        header_table[current-1].received.month+1,
X	        header_table[current-1].received.day,
X	        header_table[current-1].received.year,
X	        header_table[current-1].received.hour,
X	        header_table[current-1].received.minute);
X	Write_to_screen(buffer, 0);
X
X	sprintf(buffer, "Message sent on: %s, %s %s, %s at %s\n\n",
X	        header_table[current-1].dayname,
X	        header_table[current-1].month,
X	        header_table[current-1].day,
X	        header_table[current-1].year,
X	        header_table[current-1].time);
X	Write_to_screen(buffer, 0);
X	
X	Write_to_screen("\nFrom: %s\n\nSubject: %s", 2,
X		header_table[current-1].from,
X	        header_table[current-1].subject);
X
X	Write_to_screen("\nTo: %s\n\nIndex = %d\n", 2,
X		header_table[current-1].to,
X		header_table[current-1].index_number);
X	
X	Raw(ON);
X
X	PutLine0(LINES,0,"Press any key to return: ");
X	(void) ReadCh();
X}
END_OF_src/elm.c
if test 19751 -ne `wc -c <src/elm.c`; then
    echo shar: \"src/elm.c\" unpacked with wrong size!?
fi
# end of overwriting check
fi
echo shar: Extracting \"src/mailmsg2.c\" \(19017 characters\)
if test -f src/mailmsg2.c ; then 
  echo shar: Will not over-write existing file \"src/mailmsg2.c\"
else
sed "s/^X//" >src/mailmsg2.c <<'END_OF_src/mailmsg2.c'
X/** 			mailmsg2.c			**/
X
X/** Interface to allow mail to be sent to users.  Part of ELM  **/
X
X/** (C) Copyright 1986, Dave Taylor 			       **/
X
X#include "headers.h"
X#include <errno.h>
X
Xextern int errno;
X
Xchar *error_name(), *error_description(), *strip_parens();
Xchar *strcat(), *strcpy();
Xchar *format_long(), *strip_commas(), *tail_of_string(); 
X
Xunsigned long sleep();
X
X#ifdef SITE_HIDING 
X char *get_ctime_date();
X#endif
XFILE *write_header_info();
X
Xextern char subject[SLEN], action[SLEN], reply_to[SLEN], expires[SLEN], 
X	    priority [SLEN], to[VERY_LONG_STRING], cc[VERY_LONG_STRING],
X            in_reply_to[SLEN], expanded_to[VERY_LONG_STRING], 
X	    expanded_cc[VERY_LONG_STRING], user_defined_header[SLEN];
X#ifdef ALLOW_BCC
Xextern char bcc[VERY_LONG_STRING], expanded_bcc[VERY_LONG_STRING];
X#endif
X
Xint gotten_key = 0;
X
Xchar *bounce_off_remote();
X
Xmail(copy_msg, edit_message, batch, form)
Xint  copy_msg, edit_message, batch, form;
X{
X	/** Given the addresses and various other miscellany (specifically, 
X	    'copy-msg' indicates whether a copy of the current message should 
X	    be included, 'edit_message' indicates whether the message should 
X	    be edited and 'batch' indicates that the message should be read 
X	    from stdin) this routine will invoke an editor for the user and 
X	    then actually mail off the message. 'form' can be YES, NO, or
X	    MAYBE.  YES=add "Content-Type: mailform" header, MAYBE=add the
X	    M)ake form option to last question, and NO=don't worry about it!
X	    Also, if 'copy_msg' = FORM, then grab the form temp file and use
X	    that...
X	**/
X
X	FILE *reply, *real_reply; /* second is post-input buffer */
X	char filename[SLEN], filename2[SLEN], fname[SLEN],
X             very_long_buffer[VERY_LONG_STRING];
X	char ch;
X	register int retransmit = FALSE; 
X	int      already_has_text = FALSE;		/* we need an ADDRESS */
X
X	static int cancelled_msg = 0;
X
X	dprint2(4,"\nMailing to '%s'(with%s editing)\n",
X		  expanded_to, edit_message? "" : "out");
X	
X	/** first generate the temporary filename **/
X
X	sprintf(filename,"%s%d",temp_file, getpid());
X
X	/** if possible, let's try to recall the last message? **/
X
X	if (! batch && copy_msg != FORM && user_level != 0)
X	  retransmit = recall_last_msg(filename, copy_msg, &cancelled_msg, 
X		       &already_has_text);
X
X	/** if we're not retransmitting, create the file.. **/
X
X	if (! retransmit)
X	  if ((reply = fopen(filename,"w")) == NULL) {
X	    dprint2(1,
X               "Attempt to write to temp file %s failed with error %s (mail)\n",
X		 filename, error_name(errno));
X	    error2("Could not create file %s (%s)",filename,
X		 error_name(errno));
X	    return(1);
X	  }
X
X	if (batch) {
X	  Raw(OFF);
X	  if (isatty(fileno(stdin))) {
X	    fclose(reply);	/* let edit-the-message open it! */
X	    printf("To: %s\nSubject: %s\n", expanded_to, subject);
X	    strcpy(editor, "none");	/* force inline editor */
X	    if (no_editor_edit_the_message(filename)) {
X	      return(0);	/* confused?  edit_the_msg returns 1 if bad */
X	    }
X	    if (verify_transmission(filename, &form) == 'f')
X	      return(0);
X	  }
X	  else {
X	    while (gets(very_long_buffer) != NULL) 
X	      fprintf(reply, "%s\n", very_long_buffer);
X	  }
X	}
X
X	if (copy_msg == FORM) {
X	  sprintf(fname, "%s%d", temp_form_file, getpid());
X	  fclose(reply);	/* we can't retransmit a form! */
X	  if (access(fname,ACCESS_EXISTS) != 0) {
X	    error("couldn't find forms file!");
X	    return(0);
X	  }
X	  unlink(filename);
X	  dprint2(4, "-- linking existing file %s to file %s --\n",
X		  fname, filename);
X	  link(fname, filename);
X	  unlink(fname);
X	}
X	else if (copy_msg && ! retransmit)    /* if retransmit we have it! */
X	  if (edit_message) {
X	    copy_message(prefixchars, reply, noheader, FALSE);
X	    already_has_text = TRUE;	/* we just added it, right? */
X	  }
X	  else
X	    copy_message("", reply, noheader, FALSE);
X
X	if (!batch && ! retransmit && signature && copy_msg != FORM) {
X	  fprintf(reply, "\n--\n");	/* News 2.11 compatibility? */
X	  if (chloc(expanded_to, '!') == -1 && chloc(expanded_to, '@') == -1) {
X	    if (strlen(local_signature) > 0) {
X	      if (local_signature[0] != '/')
X	        sprintf(filename2, "%s/%s", home, local_signature);
X	      else	
X 	        strcpy(filename2, local_signature);
X	      (void) append(reply, filename2);
X	      already_has_text = TRUE;	/* added signature... */
X	    }
X	  }
X	  else {
X	    if (remote_signature[0] != '/')
X	      sprintf(filename2, "%s/%s", home, remote_signature);
X	    else	
X 	      strcpy(filename2, remote_signature);
X	    (void) append(reply, filename2);
X	    already_has_text = TRUE;	/* added signature... */
X	  }
X	}
X
X	if (! retransmit && copy_msg != FORM)
X	  (void) fclose(reply);	/* on replies, it won't be open! */
X
X	/** Edit the message **/
X
X	if (edit_message)
X	  create_readmsg_file();	/* for "readmsg" routine */
X
X	ch = edit_message? 'e' : ' ';	/* drop through if needed... */
X
X	if (! batch) {
X	  do {
X	    switch (ch) {
X	      case 'e': if (edit_the_message(filename, already_has_text)) {
X			  cancelled_msg = TRUE;
X			  return(1);
X			}
X			break;
X	      case 'h': edit_headers();					break;
X	      default : /* do nothing */ ;
X	    }
X
X	    /** ask that silly question again... **/
X  
X	    if ((ch = verify_transmission(filename, &form)) == 'f') {
X	      cancelled_msg = TRUE;
X	      return(1);
X	    }
X	  } while (ch != 's');
X
X	  if (form == YES) 
X	    if (format_form(filename) < 1) {
X	      cancelled_msg = TRUE;
X	      return(1);
X	    }
X
X	  if ((reply = fopen(filename,"r")) == NULL) {
X	      dprint2(1,
X	    "Attempt to open file %s for reading failed with error %s (mail)\n",
X                filename, error_name(errno));
X	      error1("Could not open reply file (%s)", error_name(errno));
X	      return(1);
X	  }
X	}
X	else if ((reply = fopen(filename,"r")) == NULL) {
X	  dprint2(1,
X	    "Attempt to open file %s for reading failed with error %s (mail)\n",
X             filename, error_name(errno));
X	  error1("Could not open reply file (%s)", error_name(errno));
X	  return(1);
X	}
X
X	cancelled_msg = FALSE;	/* it ain't cancelled, is it? */
X
X	/** ask about bounceback if the user wants us to.... **/
X
X	if (uucp_hops(to) > bounceback && bounceback > 0 && copy_msg != FORM) 
X	  if (verify_bounceback() == TRUE) {
X	    if (strlen(cc) > 0) strcat(expanded_cc, ", ");
X	    strcat(expanded_cc, bounce_off_remote(to));
X	  }
X
X	/** grab a copy if the user so desires... **/
X
X	if (auto_cc && !batch) 
X	  save_copy(subject, expanded_to, expanded_cc, filename, to);
X
X	/** write all header information into real_reply **/
X
X	sprintf(filename2,"%s%d",temp_file, getpid()+1);
X	
X	/** try to write headers to new temp file **/
X
X	dprint2(6, "Composition file='%s' and mail buffer='%s'\n", 
X		    filename, filename2);
X
X	if ((real_reply=write_header_info(filename2, expanded_to, expanded_cc,
X#ifdef ALLOW_BCC
X				 	  expanded_bcc,
X#endif
X			                  form == YES)) == NULL) {
X
X	  /** IT FAILED!!  MEIN GOTT!  Use a dumb mailer instead! **/
X
X	  dprint1(3,"** write_header failed: %s\n", error_name(errno));
X
X	  if (cc[0] != '\0')  		/* copies! */
X	    sprintf(expanded_to,"%s %s", expanded_to, expanded_cc);
X
X	  sprintf(very_long_buffer, "( (%s -s \"%s\" %s ; %s %s) & ) < %s",
X                  mailx, subject, strip_parens(strip_commas(expanded_to)), 
X		  remove, filename, filename);
X
X	  error1("Message sent using dumb mailer - %s", mailx);
X	  sleep(2);	/* ensure time to see this prompt! */
X
X	}
X	else {
X	  copy_message_across(reply, real_reply);
X
X	  fclose(real_reply);
X
X	  if (cc[0] != '\0')  				         /* copies! */
X	    sprintf(expanded_to,"%s %s", expanded_to, expanded_cc);
X
X#ifdef ALLOW_BCC
X	  if (bcc[0] != '\0') {
X	    strcat(expanded_to, " ");
X	    strcat(expanded_to, expanded_bcc);
X	  }
X#endif
X
X	  if (access(sendmail, EXECUTE_ACCESS) == 0 
X#ifdef SITE_HIDING
X	      && ! is_a_hidden_user(username))
X#else
X	     )
X#endif
X	    sprintf(very_long_buffer,"( (%s %s %s ; %s %s) & ) < %s",
X                  sendmail, smflags, strip_parens(strip_commas(expanded_to)), 
X		  remove, filename2, filename2);
X	  else 				   /* oh well, use default mailer... */
X            sprintf(very_long_buffer,"( (%s %s ; %s %s) & ) < %s", 
X                  mailer, strip_parens(strip_commas(expanded_to)), 
X		  remove, filename2, filename2);
X	}
X	
X	fclose(reply);
X
X	if (mail_only) {
X	  printf("sending mail...");
X	  fflush(stdout);
X	}
X	else {	
X	  PutLine0(LINES,0,"sending mail...");
X	  CleartoEOLN();
X	}
X
X	system_call(very_long_buffer, SH);
X
X	if (mail_only) 
X	  printf("\rmail sent!      \n\r");
X	else 
X	  set_error("Mail sent!");
X
X	return(TRUE);
X}
X
Xmail_form(address, subj)
Xchar *address, *subj;
X{
X	/** copy the appropriate variables to the shared space... */
X
X	strcpy(subject, subj);
X	strcpy(to, address);
X	strcpy(expanded_to, address);
X
X	return(mail(FORM, NO, NO, NO));
X}
X
Xint
Xrecall_last_msg(filename, copy_msg, cancelled_msg, already_has_text)
Xchar *filename;
Xint  copy_msg, *cancelled_msg, *already_has_text;
X{
X	/** If filename exists and we've recently cancelled a message,
X	    the ask if the user wants to use that message instead!  This
X	    routine returns TRUE if the user wants to retransmit the last
X	    message, FALSE otherwise...
X	**/
X
X	register int retransmit = FALSE;
X
X	if (access(filename, EDIT_ACCESS) == 0 && *cancelled_msg) {
X	  Raw(ON);
X	  CleartoEOLN();
X	  if (copy_msg)
X	    PutLine1(LINES-1,0,"Recall last kept message instead? (y/n) y%c",
X		     BACKSPACE);
X	  else
X	    PutLine1(LINES-1,0,"Recall last kept message? (y/n) y%c", 
X		     BACKSPACE);
X	  fflush(stdout);
X	  if (tolower(ReadCh()) != 'n') {
X	    Write_to_screen("Yes",0);	
X            retransmit++;
X	    *already_has_text = TRUE;
X	  }
X	  else 
X	    Write_to_screen("No",0);	
X
X	  fflush(stdout);
X
X	  *cancelled_msg = 0;
X	}
X
X	return(retransmit);
X}
X
Xint
Xverify_transmission(filename, form_letter)
Xchar *filename;
Xint  *form_letter;
X{
X	/** Ensure the user wants to send this.  This routine returns
X	    the character entered.  Modified compliments of Steve Wolf 
X	    to add the'dead.letter' feature.
X	    Also added form letter support... 
X	**/
X
X	FILE *deadfd, *messagefd;
X	char ch, buffer[LONG_SLEN], fname[SLEN];
X
X	if (mail_only) {
X	  if (isatty(fileno(stdin))) {
X	    printf("\n\rAre you sure you want to send this? (y/n) ");
X	    CleartoEOLN();
X	    printf("y%c", BACKSPACE);
X	    fflush(stdin);				/* wait for answer! */
X	    fflush(stdout);
X	    if (tolower(ReadCh()) == 'n') { 			/* >SIGH< */
X	      printf("No\n\r\n\r");
X	      /** try to save it as a dead letter file **/
X	      
X	      sprintf(fname, "%s/%s", home, dead_letter);
X
X	      if ((deadfd = fopen(fname,"a")) == NULL) {
X		dprint2(1,
X		   "\nAttempt to append to deadletter file '%s' failed: %s\n\r",
X		    fname, error_name(errno));
X	        printf("Message not saved, Sorry.\n\r\n\r");
X		return('f');
X	      }
X	      else if ((messagefd = fopen(filename, "r")) == NULL) {
X		dprint2(1,"\nAttempt to read reply file '%s' failed: %s\n\r",
X			filename, error_name(errno));
X	        printf("Message not saved, Sorry.\n\r\n\r");
X		return('f');
X	      }
X	
X	      /* if we get here we're okay for everything, right? */
X
X	      while (fgets(buffer, LONG_SLEN, messagefd) != NULL)
X		fputs(buffer, deadfd);
X
X	      fclose(messagefd);
X	      fclose(deadfd);
X
X	      printf("Message saved in file \"$HOME/%s\"\n\r\n\r", dead_letter);
X
X	      return('f');	/* forget it! */
X	    }
X	    else
X	      printf("Yes\n\r\n\r");
X	    return('s');       /* send this baby! */
X	  }
X	  else
X	    return('s');	/*    ditto       */
X	}
X	else if (check_first) {    /* used to check strlen(infile) > 0 too? */
Xreprompt:
X	  MoveCursor(LINES,0);
X	  CleartoEOLN();
X	  ClearLine(LINES-1);
X
X	  if (user_level == 0)
X	    PutLine1(LINES-1,0, "Are you sure you want to send this? (y/n) y%c",
X			   BACKSPACE);
X	  else if (*form_letter == PREFORMATTED) 
X	    PutLine1(LINES-1, 0, 
X                 "Choose: edit H)eaders, S)end, or F)orget : s%c",
X	         BACKSPACE);
X	  else if (*form_letter == YES) 
X	    PutLine1(LINES-1, 0, 
X                 "Choose: E)dit form, edit H)eaders, S)end, or F)orget : s%c",
X	         BACKSPACE);
X	  else if (*form_letter == MAYBE) 
X	    PutLine1(LINES-1, 0, 
X        "Choose: E)dit msg, edit H)eaders, M)ake form, S)end, or F)orget : s%c",
X	     BACKSPACE);
X	  else
X	    PutLine1(LINES-1, 0, 
X	     "Please choose: E)dit msg, edit H)eaders, S)end, or F)orget : s%c",
X	     BACKSPACE);
X
X	  fflush(stdin);	/* wait for answer! */
X	  fflush(stdout);
X	  Raw(ON);	/* double check... testing only... */
X	  ch = tolower(ReadCh());
X
X	  if (user_level == 0) {
X	    if (ch == 'n') {
X	      set_error("message cancelled");
X	      return('f');
X	    }
X	    else
X	      return('s');
X	  }
X
X	  /* otherwise someone who knows what's happenin' so...  */
X
X	  switch (ch) {
X	     case 'f': Write_to_screen("Forget",0);
X	               set_error(
X          "Message kept - Can be restored at next F)orward, M)ail or R)eply ");
X		       break;
X
X	     case '\n' :
X	     case '\r' :
X	     case 's'  : Write_to_screen("Send",0);
X			 ch = 's';		/* make sure! */
X			 break;
X
X	     case 'm'  : if (*form_letter == MAYBE) {
X			   *form_letter = YES;
X		           switch (check_form_file(filename)) {
X			     case -1 : return('f');
X			     case 0  : *form_letter = MAYBE;  /* check later!*/
X				       error("No fields in form!");
X				       return('e');
X			     default : goto reprompt;
X	                   }
X			 }
X			 else {
X	                    Write_to_screen("%c??", 1, 07);	/* BEEP */
X			    sleep(1);
X		            goto reprompt;		/* yech */
X	                 }
X	     case 'e'  :  if (*form_letter != PREFORMATTED) {
X			    Write_to_screen("Edit",0);
X	 	            if (*form_letter == YES) 
X			      *form_letter = MAYBE;
X	                  }
X			  else {
X	                    Write_to_screen("%c??", 1, 07);	/* BEEP */
X			    sleep(1);
X		            goto reprompt;		/* yech */
X	                 }
X			 break;
X	     case 'h'  : Write_to_screen("Headers",0);
X			 break;
X
X	     default   : Write_to_screen("%c??", 1, 07);	/* BEEP */
X			 sleep(1);
X		         goto reprompt;		/* yech */
X	   }
X
X	   return(ch);
X	}
X	else return('s');
X}
X
XFILE *
X#ifdef ALLOW_BCC
X write_header_info(filename, long_to, long_cc, long_bcc, form)
X char *filename, *long_to, *long_cc, *long_bcc;
X#else
X write_header_info(filename, long_to, long_cc, form)
X char *filename, *long_to, *long_cc;
X#endif
Xint   form;
X{
X	/** Try to open filedesc as the specified filename.  If we can,
X	    then write all the headers into the file.  The routine returns
X	    'filedesc' if it succeeded, NULL otherwise.  Added the ability
X	    to have backquoted stuff in the users .elmheaders file!
X	**/
X
X	static FILE *filedesc;		/* our friendly file descriptor  */
X
X#ifdef SITE_HIDING
X	char  buffer[SLEN];
X	int   is_hidden_user;		/* someone we should know about?  */
X#endif
X
X	char  *get_arpa_date();
X
X	if ((filedesc = fopen(filename, "w")) == NULL) {
X	  dprint1(1,
X	    "Attempt to open file %s for writing failed! (write_header_info)\n",
X	     filename);
X	  dprint2(1,"** %s - %s **\n\n", error_name(errno),
X		 error_description(errno));
X	  error2("Error %s encountered trying to write to %s", 
X		error_name(errno), filename);
X	  sleep(2);
X	  return(NULL);		/* couldn't open it!! */
X	}
X
X#ifdef SITE_HIDING
X	if ((is_hidden_user = is_a_hidden_user(username))) {
X	  /** this is the interesting part of this trick... **/
X	  sprintf(buffer, "From %s!%s %s\n",  HIDDEN_SITE_NAME,
X		  username, get_ctime_date());
X	  fprintf(filedesc, "%s", buffer);
X	  dprint1(1,"\nadded: %s", buffer);
X	  /** so is this perverted or what? **/
X	}
X#endif
X
X	fprintf(filedesc, "To: %s\n", format_long(long_to, strlen("To:")));
X
X	fprintf(filedesc,"Date: %s\n", get_arpa_date());
X
X#ifndef DONT_ADD_FROM
X# ifdef SITE_HIDING
X	if (is_hidden_user)
X	  fprintf(filedesc,"From: %s <%s!%s!%s>\n", full_username,
X		  hostname, HIDDEN_SITE_NAME, username);
X	else
X# endif
X# ifdef  INTERNET_ADDRESS_FORMAT
X#  ifdef  USE_DOMAIN
X	fprintf(filedesc,"From: %s <%s@%s%s>\n", full_username, 
X		username, hostname, DOMAIN);
X#  else
X	fprintf(filedesc,"From: %s <%s@%s>\n", full_username,
X		username, hostname);
X#  endif
X# else
X	fprintf(filedesc,"From: %s <%s!%s>\n", full_username,
X		hostname, username);
X# endif
X#endif
X
X	fprintf(filedesc, "Subject: %s\n", subject);
X
X	if (cc[0] != '\0')
X	  fprintf(filedesc, "Cc: %s\n", format_long(long_cc, strlen("Cc: ")));
X
X#ifdef ALLOW_BCC
X	if (bcc[0] != '\0')
X	 fprintf(filedesc, "Bcc: %s\n", format_long(long_bcc, strlen("Bcc: ")));
X#endif
X
X	if (strlen(action) > 0)
X	    fprintf(filedesc, "Action: %s\n", action);
X	
X	if (strlen(priority) > 0)
X	    fprintf(filedesc, "Priority: %s\n", priority);
X	
X	if (strlen(expires) > 0)
X	    fprintf(filedesc, "Expiration-Date: %s\n", expires);
X	
X	if (strlen(reply_to) > 0)
X	    fprintf(filedesc, "Reply-To: %s\n", reply_to);
X
X	if (strlen(in_reply_to) > 0)
X	    fprintf(filedesc, "In-Reply-To: %s\n", in_reply_to);
X
X	if (strlen(user_defined_header) > 0)
X	    fprintf(filedesc, "%s\n", user_defined_header);
X
X	add_mailheaders(filedesc);
X
X	if (form)
X	  fprintf(filedesc, "Content-Type: mailform\n");
X
X	fprintf(filedesc, "X-Mailer: Elm [version %s]\n\n", VERSION);
X
X	return((FILE *) filedesc);
X}
X
Xcopy_message_across(source, dest)
XFILE *source, *dest;
X{
X	/** copy the message in the file pointed to by source to the
X	    file pointed to by dest.  **/
X
X	int  crypted = FALSE;			/* are we encrypting?  */
X	int  encoded_lines = 0;			/* # lines encoded     */
X	char buffer[LONG_SLEN];			/* file reading buffer */
X
X	while (fgets(buffer, LONG_SLEN, source) != NULL) {
X	  if (buffer[0] == '[') {
X	    if (strncmp(buffer, START_ENCODE, strlen(START_ENCODE))==0)
X	      crypted = TRUE;
X	     else if (strncmp(buffer, END_ENCODE, strlen(END_ENCODE))==0)
X	      crypted = FALSE;
X	     else if (strncmp(buffer, DONT_SAVE, strlen(DONT_SAVE)) == 0)
X	      continue;	/* next line? */
X	    }
X	    else if (crypted) {
X	      if (! gotten_key++)
X	        getkey(ON);
X	      else if (! encoded_lines++)
X	        get_key_no_prompt();		/* reinitialize.. */
X	     
X	      encode(buffer);
X	    }
X	    fputs(buffer, dest);
X	  }
X}
X
Xint
Xverify_bounceback()
X{
X	/** Ensure the user wants to have a bounceback copy too.  (This is
X	    only called on messages that are greater than the specified 
X	    threshold hops and NEVER for non-uucp addresses.... Returns
X	    TRUE iff the user wants to bounce a copy back.... 
X	 **/
X
X	if (mail_only) {
X	  printf("Would you like a copy \"bounced\" off the remote? (y/n) ");
X	  CleartoEOLN();
X	  printf("n%c", BACKSPACE);
X	  fflush(stdin);				/* wait for answer! */
X	  fflush(stdout);
X	  if (tolower(ReadCh()) != 'y') {
X	    printf("No\n\r");
X	    return(FALSE);
X	  }
X	  else
X	    printf("Yes - Bounceback included\n\r");
X	}
X	else {
X	  MoveCursor(LINES,0);
X	  CleartoEOLN();
X	  PutLine1(LINES,0, 
X		"\"Bounce\" a copy off the remote machine? (y/n) y%c",
X		BACKSPACE);
X	  fflush(stdin);	/* wait for answer! */
X	  fflush(stdout);
X	  if (tolower(ReadCh()) != 'y') { 
X	    Write_to_screen("No", 0);
X	    fflush(stdout);
X	    return(FALSE);
X	  }
X	  Write_to_screen("Yes!", 0);
X	  fflush(stdout);
X	}
X
X	return(TRUE);
X}
END_OF_src/mailmsg2.c
if test 19017 -ne `wc -c <src/mailmsg2.c`; then
    echo shar: \"src/mailmsg2.c\" unpacked with wrong size!?
fi
# end of overwriting check
fi
echo shar: End of archive 17 \(of 19\).
cp /dev/null ark17isdone
DONE=true
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
    if test ! -f ark${I}isdone ; then
	echo shar: You still need to run archive ${I}.
	DONE=false
    fi
done
if test "$DONE" = "true" ; then
	echo You have unpacked all 19 archives.
	echo "See the Instructions file"
	rm -f ark[1-9]isdone ark[1-9][0-9]isdone
fi
##  End of shell archive.
exit 0