DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download
Index: ┃ T m

⟦f3feaab8a⟧ TextFile

    Length: 19017 (0x4a49)
    Types: TextFile
    Names: »mailmsg2.c«

Derivation

└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
    └─ ⟦this⟧ »EUUGD11/euug-87hel/sec1/elm/src/mailmsg2.c« 

TextFile

/** 			mailmsg2.c			**/

/** Interface to allow mail to be sent to users.  Part of ELM  **/

/** (C) Copyright 1986, Dave Taylor 			       **/

#include "headers.h"
#include <errno.h>

extern int errno;

char *error_name(), *error_description(), *strip_parens();
char *strcat(), *strcpy();
char *format_long(), *strip_commas(), *tail_of_string(); 

unsigned long sleep();

#ifdef SITE_HIDING 
 char *get_ctime_date();
#endif
FILE *write_header_info();

extern char subject[SLEN], action[SLEN], reply_to[SLEN], expires[SLEN], 
	    priority [SLEN], to[VERY_LONG_STRING], cc[VERY_LONG_STRING],
            in_reply_to[SLEN], expanded_to[VERY_LONG_STRING], 
	    expanded_cc[VERY_LONG_STRING], user_defined_header[SLEN];
#ifdef ALLOW_BCC
extern char bcc[VERY_LONG_STRING], expanded_bcc[VERY_LONG_STRING];
#endif

int gotten_key = 0;

char *bounce_off_remote();

mail(copy_msg, edit_message, batch, form)
int  copy_msg, edit_message, batch, form;
{
	/** Given the addresses and various other miscellany (specifically, 
	    'copy-msg' indicates whether a copy of the current message should 
	    be included, 'edit_message' indicates whether the message should 
	    be edited and 'batch' indicates that the message should be read 
	    from stdin) this routine will invoke an editor for the user and 
	    then actually mail off the message. 'form' can be YES, NO, or
	    MAYBE.  YES=add "Content-Type: mailform" header, MAYBE=add the
	    M)ake form option to last question, and NO=don't worry about it!
	    Also, if 'copy_msg' = FORM, then grab the form temp file and use
	    that...
	**/

	FILE *reply, *real_reply; /* second is post-input buffer */
	char filename[SLEN], filename2[SLEN], fname[SLEN],
             very_long_buffer[VERY_LONG_STRING];
	char ch;
	register int retransmit = FALSE; 
	int      already_has_text = FALSE;		/* we need an ADDRESS */

	static int cancelled_msg = 0;

	dprint2(4,"\nMailing to '%s'(with%s editing)\n",
		  expanded_to, edit_message? "" : "out");
	
	/** first generate the temporary filename **/

	sprintf(filename,"%s%d",temp_file, getpid());

	/** if possible, let's try to recall the last message? **/

	if (! batch && copy_msg != FORM && user_level != 0)
	  retransmit = recall_last_msg(filename, copy_msg, &cancelled_msg, 
		       &already_has_text);

	/** if we're not retransmitting, create the file.. **/

	if (! retransmit)
	  if ((reply = fopen(filename,"w")) == NULL) {
	    dprint2(1,
               "Attempt to write to temp file %s failed with error %s (mail)\n",
		 filename, error_name(errno));
	    error2("Could not create file %s (%s)",filename,
		 error_name(errno));
	    return(1);
	  }

	if (batch) {
	  Raw(OFF);
	  if (isatty(fileno(stdin))) {
	    fclose(reply);	/* let edit-the-message open it! */
	    printf("To: %s\nSubject: %s\n", expanded_to, subject);
	    strcpy(editor, "none");	/* force inline editor */
	    if (no_editor_edit_the_message(filename)) {
	      return(0);	/* confused?  edit_the_msg returns 1 if bad */
	    }
	    if (verify_transmission(filename, &form) == 'f')
	      return(0);
	  }
	  else {
	    while (gets(very_long_buffer) != NULL) 
	      fprintf(reply, "%s\n", very_long_buffer);
	  }
	}

	if (copy_msg == FORM) {
	  sprintf(fname, "%s%d", temp_form_file, getpid());
	  fclose(reply);	/* we can't retransmit a form! */
	  if (access(fname,ACCESS_EXISTS) != 0) {
	    error("couldn't find forms file!");
	    return(0);
	  }
	  unlink(filename);
	  dprint2(4, "-- linking existing file %s to file %s --\n",
		  fname, filename);
	  link(fname, filename);
	  unlink(fname);
	}
	else if (copy_msg && ! retransmit)    /* if retransmit we have it! */
	  if (edit_message) {
	    copy_message(prefixchars, reply, noheader, FALSE);
	    already_has_text = TRUE;	/* we just added it, right? */
	  }
	  else
	    copy_message("", reply, noheader, FALSE);

	if (!batch && ! retransmit && signature && copy_msg != FORM) {
	  fprintf(reply, "\n--\n");	/* News 2.11 compatibility? */
	  if (chloc(expanded_to, '!') == -1 && chloc(expanded_to, '@') == -1) {
	    if (strlen(local_signature) > 0) {
	      if (local_signature[0] != '/')
	        sprintf(filename2, "%s/%s", home, local_signature);
	      else	
 	        strcpy(filename2, local_signature);
	      (void) append(reply, filename2);
	      already_has_text = TRUE;	/* added signature... */
	    }
	  }
	  else {
	    if (remote_signature[0] != '/')
	      sprintf(filename2, "%s/%s", home, remote_signature);
	    else	
 	      strcpy(filename2, remote_signature);
	    (void) append(reply, filename2);
	    already_has_text = TRUE;	/* added signature... */
	  }
	}

	if (! retransmit && copy_msg != FORM)
	  (void) fclose(reply);	/* on replies, it won't be open! */

	/** Edit the message **/

	if (edit_message)
	  create_readmsg_file();	/* for "readmsg" routine */

	ch = edit_message? 'e' : ' ';	/* drop through if needed... */

	if (! batch) {
	  do {
	    switch (ch) {
	      case 'e': if (edit_the_message(filename, already_has_text)) {
			  cancelled_msg = TRUE;
			  return(1);
			}
			break;
	      case 'h': edit_headers();					break;
	      default : /* do nothing */ ;
	    }

	    /** ask that silly question again... **/
  
	    if ((ch = verify_transmission(filename, &form)) == 'f') {
	      cancelled_msg = TRUE;
	      return(1);
	    }
	  } while (ch != 's');

	  if (form == YES) 
	    if (format_form(filename) < 1) {
	      cancelled_msg = TRUE;
	      return(1);
	    }

	  if ((reply = fopen(filename,"r")) == NULL) {
	      dprint2(1,
	    "Attempt to open file %s for reading failed with error %s (mail)\n",
                filename, error_name(errno));
	      error1("Could not open reply file (%s)", error_name(errno));
	      return(1);
	  }
	}
	else if ((reply = fopen(filename,"r")) == NULL) {
	  dprint2(1,
	    "Attempt to open file %s for reading failed with error %s (mail)\n",
             filename, error_name(errno));
	  error1("Could not open reply file (%s)", error_name(errno));
	  return(1);
	}

	cancelled_msg = FALSE;	/* it ain't cancelled, is it? */

	/** ask about bounceback if the user wants us to.... **/

	if (uucp_hops(to) > bounceback && bounceback > 0 && copy_msg != FORM) 
	  if (verify_bounceback() == TRUE) {
	    if (strlen(cc) > 0) strcat(expanded_cc, ", ");
	    strcat(expanded_cc, bounce_off_remote(to));
	  }

	/** grab a copy if the user so desires... **/

	if (auto_cc && !batch) 
	  save_copy(subject, expanded_to, expanded_cc, filename, to);

	/** write all header information into real_reply **/

	sprintf(filename2,"%s%d",temp_file, getpid()+1);
	
	/** try to write headers to new temp file **/

	dprint2(6, "Composition file='%s' and mail buffer='%s'\n", 
		    filename, filename2);

	if ((real_reply=write_header_info(filename2, expanded_to, expanded_cc,
#ifdef ALLOW_BCC
				 	  expanded_bcc,
#endif
			                  form == YES)) == NULL) {

	  /** IT FAILED!!  MEIN GOTT!  Use a dumb mailer instead! **/

	  dprint1(3,"** write_header failed: %s\n", error_name(errno));

	  if (cc[0] != '\0')  		/* copies! */
	    sprintf(expanded_to,"%s %s", expanded_to, expanded_cc);

	  sprintf(very_long_buffer, "( (%s -s \"%s\" %s ; %s %s) & ) < %s",
                  mailx, subject, strip_parens(strip_commas(expanded_to)), 
		  remove, filename, filename);

	  error1("Message sent using dumb mailer - %s", mailx);
	  sleep(2);	/* ensure time to see this prompt! */

	}
	else {
	  copy_message_across(reply, real_reply);

	  fclose(real_reply);

	  if (cc[0] != '\0')  				         /* copies! */
	    sprintf(expanded_to,"%s %s", expanded_to, expanded_cc);

#ifdef ALLOW_BCC
	  if (bcc[0] != '\0') {
	    strcat(expanded_to, " ");
	    strcat(expanded_to, expanded_bcc);
	  }
#endif

	  if (access(sendmail, EXECUTE_ACCESS) == 0 
#ifdef SITE_HIDING
	      && ! is_a_hidden_user(username))
#else
	     )
#endif
	    sprintf(very_long_buffer,"( (%s %s %s ; %s %s) & ) < %s",
                  sendmail, smflags, strip_parens(strip_commas(expanded_to)), 
		  remove, filename2, filename2);
	  else 				   /* oh well, use default mailer... */
            sprintf(very_long_buffer,"( (%s %s ; %s %s) & ) < %s", 
                  mailer, strip_parens(strip_commas(expanded_to)), 
		  remove, filename2, filename2);
	}
	
	fclose(reply);

	if (mail_only) {
	  printf("sending mail...");
	  fflush(stdout);
	}
	else {	
	  PutLine0(LINES,0,"sending mail...");
	  CleartoEOLN();
	}

	system_call(very_long_buffer, SH);

	if (mail_only) 
	  printf("\rmail sent!      \n\r");
	else 
	  set_error("Mail sent!");

	return(TRUE);
}

mail_form(address, subj)
char *address, *subj;
{
	/** copy the appropriate variables to the shared space... */

	strcpy(subject, subj);
	strcpy(to, address);
	strcpy(expanded_to, address);

	return(mail(FORM, NO, NO, NO));
}

int
recall_last_msg(filename, copy_msg, cancelled_msg, already_has_text)
char *filename;
int  copy_msg, *cancelled_msg, *already_has_text;
{
	/** If filename exists and we've recently cancelled a message,
	    the ask if the user wants to use that message instead!  This
	    routine returns TRUE if the user wants to retransmit the last
	    message, FALSE otherwise...
	**/

	register int retransmit = FALSE;

	if (access(filename, EDIT_ACCESS) == 0 && *cancelled_msg) {
	  Raw(ON);
	  CleartoEOLN();
	  if (copy_msg)
	    PutLine1(LINES-1,0,"Recall last kept message instead? (y/n) y%c",
		     BACKSPACE);
	  else
	    PutLine1(LINES-1,0,"Recall last kept message? (y/n) y%c", 
		     BACKSPACE);
	  fflush(stdout);
	  if (tolower(ReadCh()) != 'n') {
	    Write_to_screen("Yes",0);	
            retransmit++;
	    *already_has_text = TRUE;
	  }
	  else 
	    Write_to_screen("No",0);	

	  fflush(stdout);

	  *cancelled_msg = 0;
	}

	return(retransmit);
}

int
verify_transmission(filename, form_letter)
char *filename;
int  *form_letter;
{
	/** Ensure the user wants to send this.  This routine returns
	    the character entered.  Modified compliments of Steve Wolf 
	    to add the'dead.letter' feature.
	    Also added form letter support... 
	**/

	FILE *deadfd, *messagefd;
	char ch, buffer[LONG_SLEN], fname[SLEN];

	if (mail_only) {
	  if (isatty(fileno(stdin))) {
	    printf("\n\rAre you sure you want to send this? (y/n) ");
	    CleartoEOLN();
	    printf("y%c", BACKSPACE);
	    fflush(stdin);				/* wait for answer! */
	    fflush(stdout);
	    if (tolower(ReadCh()) == 'n') { 			/* >SIGH< */
	      printf("No\n\r\n\r");
	      /** try to save it as a dead letter file **/
	      
	      sprintf(fname, "%s/%s", home, dead_letter);

	      if ((deadfd = fopen(fname,"a")) == NULL) {
		dprint2(1,
		   "\nAttempt to append to deadletter file '%s' failed: %s\n\r",
		    fname, error_name(errno));
	        printf("Message not saved, Sorry.\n\r\n\r");
		return('f');
	      }
	      else if ((messagefd = fopen(filename, "r")) == NULL) {
		dprint2(1,"\nAttempt to read reply file '%s' failed: %s\n\r",
			filename, error_name(errno));
	        printf("Message not saved, Sorry.\n\r\n\r");
		return('f');
	      }
	
	      /* if we get here we're okay for everything, right? */

	      while (fgets(buffer, LONG_SLEN, messagefd) != NULL)
		fputs(buffer, deadfd);

	      fclose(messagefd);
	      fclose(deadfd);

	      printf("Message saved in file \"$HOME/%s\"\n\r\n\r", dead_letter);

	      return('f');	/* forget it! */
	    }
	    else
	      printf("Yes\n\r\n\r");
	    return('s');       /* send this baby! */
	  }
	  else
	    return('s');	/*    ditto       */
	}
	else if (check_first) {    /* used to check strlen(infile) > 0 too? */
reprompt:
	  MoveCursor(LINES,0);
	  CleartoEOLN();
	  ClearLine(LINES-1);

	  if (user_level == 0)
	    PutLine1(LINES-1,0, "Are you sure you want to send this? (y/n) y%c",
			   BACKSPACE);
	  else if (*form_letter == PREFORMATTED) 
	    PutLine1(LINES-1, 0, 
                 "Choose: edit H)eaders, S)end, or F)orget : s%c",
	         BACKSPACE);
	  else if (*form_letter == YES) 
	    PutLine1(LINES-1, 0, 
                 "Choose: E)dit form, edit H)eaders, S)end, or F)orget : s%c",
	         BACKSPACE);
	  else if (*form_letter == MAYBE) 
	    PutLine1(LINES-1, 0, 
        "Choose: E)dit msg, edit H)eaders, M)ake form, S)end, or F)orget : s%c",
	     BACKSPACE);
	  else
	    PutLine1(LINES-1, 0, 
	     "Please choose: E)dit msg, edit H)eaders, S)end, or F)orget : s%c",
	     BACKSPACE);

	  fflush(stdin);	/* wait for answer! */
	  fflush(stdout);
	  Raw(ON);	/* double check... testing only... */
	  ch = tolower(ReadCh());

	  if (user_level == 0) {
	    if (ch == 'n') {
	      set_error("message cancelled");
	      return('f');
	    }
	    else
	      return('s');
	  }

	  /* otherwise someone who knows what's happenin' so...  */

	  switch (ch) {
	     case 'f': Write_to_screen("Forget",0);
	               set_error(
          "Message kept - Can be restored at next F)orward, M)ail or R)eply ");
		       break;

	     case '\n' :
	     case '\r' :
	     case 's'  : Write_to_screen("Send",0);
			 ch = 's';		/* make sure! */
			 break;

	     case 'm'  : if (*form_letter == MAYBE) {
			   *form_letter = YES;
		           switch (check_form_file(filename)) {
			     case -1 : return('f');
			     case 0  : *form_letter = MAYBE;  /* check later!*/
				       error("No fields in form!");
				       return('e');
			     default : goto reprompt;
	                   }
			 }
			 else {
	                    Write_to_screen("%c??", 1, 07);	/* BEEP */
			    sleep(1);
		            goto reprompt;		/* yech */
	                 }
	     case 'e'  :  if (*form_letter != PREFORMATTED) {
			    Write_to_screen("Edit",0);
	 	            if (*form_letter == YES) 
			      *form_letter = MAYBE;
	                  }
			  else {
	                    Write_to_screen("%c??", 1, 07);	/* BEEP */
			    sleep(1);
		            goto reprompt;		/* yech */
	                 }
			 break;
	     case 'h'  : Write_to_screen("Headers",0);
			 break;

	     default   : Write_to_screen("%c??", 1, 07);	/* BEEP */
			 sleep(1);
		         goto reprompt;		/* yech */
	   }

	   return(ch);
	}
	else return('s');
}

FILE *
#ifdef ALLOW_BCC
 write_header_info(filename, long_to, long_cc, long_bcc, form)
 char *filename, *long_to, *long_cc, *long_bcc;
#else
 write_header_info(filename, long_to, long_cc, form)
 char *filename, *long_to, *long_cc;
#endif
int   form;
{
	/** Try to open filedesc as the specified filename.  If we can,
	    then write all the headers into the file.  The routine returns
	    'filedesc' if it succeeded, NULL otherwise.  Added the ability
	    to have backquoted stuff in the users .elmheaders file!
	**/

	static FILE *filedesc;		/* our friendly file descriptor  */

#ifdef SITE_HIDING
	char  buffer[SLEN];
	int   is_hidden_user;		/* someone we should know about?  */
#endif

	char  *get_arpa_date();

	if ((filedesc = fopen(filename, "w")) == NULL) {
	  dprint1(1,
	    "Attempt to open file %s for writing failed! (write_header_info)\n",
	     filename);
	  dprint2(1,"** %s - %s **\n\n", error_name(errno),
		 error_description(errno));
	  error2("Error %s encountered trying to write to %s", 
		error_name(errno), filename);
	  sleep(2);
	  return(NULL);		/* couldn't open it!! */
	}

#ifdef SITE_HIDING
	if ((is_hidden_user = is_a_hidden_user(username))) {
	  /** this is the interesting part of this trick... **/
	  sprintf(buffer, "From %s!%s %s\n",  HIDDEN_SITE_NAME,
		  username, get_ctime_date());
	  fprintf(filedesc, "%s", buffer);
	  dprint1(1,"\nadded: %s", buffer);
	  /** so is this perverted or what? **/
	}
#endif

	fprintf(filedesc, "To: %s\n", format_long(long_to, strlen("To:")));

	fprintf(filedesc,"Date: %s\n", get_arpa_date());

#ifndef DONT_ADD_FROM
# ifdef SITE_HIDING
	if (is_hidden_user)
	  fprintf(filedesc,"From: %s <%s!%s!%s>\n", full_username,
		  hostname, HIDDEN_SITE_NAME, username);
	else
# endif
# ifdef  INTERNET_ADDRESS_FORMAT
#  ifdef  USE_DOMAIN
	fprintf(filedesc,"From: %s <%s@%s%s>\n", full_username, 
		username, hostname, DOMAIN);
#  else
	fprintf(filedesc,"From: %s <%s@%s>\n", full_username,
		username, hostname);
#  endif
# else
	fprintf(filedesc,"From: %s <%s!%s>\n", full_username,
		hostname, username);
# endif
#endif

	fprintf(filedesc, "Subject: %s\n", subject);

	if (cc[0] != '\0')
	  fprintf(filedesc, "Cc: %s\n", format_long(long_cc, strlen("Cc: ")));

#ifdef ALLOW_BCC
	if (bcc[0] != '\0')
	 fprintf(filedesc, "Bcc: %s\n", format_long(long_bcc, strlen("Bcc: ")));
#endif

	if (strlen(action) > 0)
	    fprintf(filedesc, "Action: %s\n", action);
	
	if (strlen(priority) > 0)
	    fprintf(filedesc, "Priority: %s\n", priority);
	
	if (strlen(expires) > 0)
	    fprintf(filedesc, "Expiration-Date: %s\n", expires);
	
	if (strlen(reply_to) > 0)
	    fprintf(filedesc, "Reply-To: %s\n", reply_to);

	if (strlen(in_reply_to) > 0)
	    fprintf(filedesc, "In-Reply-To: %s\n", in_reply_to);

	if (strlen(user_defined_header) > 0)
	    fprintf(filedesc, "%s\n", user_defined_header);

	add_mailheaders(filedesc);

	if (form)
	  fprintf(filedesc, "Content-Type: mailform\n");

	fprintf(filedesc, "X-Mailer: Elm [version %s]\n\n", VERSION);

	return((FILE *) filedesc);
}

copy_message_across(source, dest)
FILE *source, *dest;
{
	/** copy the message in the file pointed to by source to the
	    file pointed to by dest.  **/

	int  crypted = FALSE;			/* are we encrypting?  */
	int  encoded_lines = 0;			/* # lines encoded     */
	char buffer[LONG_SLEN];			/* file reading buffer */

	while (fgets(buffer, LONG_SLEN, source) != NULL) {
	  if (buffer[0] == '[') {
	    if (strncmp(buffer, START_ENCODE, strlen(START_ENCODE))==0)
	      crypted = TRUE;
	     else if (strncmp(buffer, END_ENCODE, strlen(END_ENCODE))==0)
	      crypted = FALSE;
	     else if (strncmp(buffer, DONT_SAVE, strlen(DONT_SAVE)) == 0)
	      continue;	/* next line? */
	    }
	    else if (crypted) {
	      if (! gotten_key++)
	        getkey(ON);
	      else if (! encoded_lines++)
	        get_key_no_prompt();		/* reinitialize.. */
	     
	      encode(buffer);
	    }
	    fputs(buffer, dest);
	  }
}

int
verify_bounceback()
{
	/** Ensure the user wants to have a bounceback copy too.  (This is
	    only called on messages that are greater than the specified 
	    threshold hops and NEVER for non-uucp addresses.... Returns
	    TRUE iff the user wants to bounce a copy back.... 
	 **/

	if (mail_only) {
	  printf("Would you like a copy \"bounced\" off the remote? (y/n) ");
	  CleartoEOLN();
	  printf("n%c", BACKSPACE);
	  fflush(stdin);				/* wait for answer! */
	  fflush(stdout);
	  if (tolower(ReadCh()) != 'y') {
	    printf("No\n\r");
	    return(FALSE);
	  }
	  else
	    printf("Yes - Bounceback included\n\r");
	}
	else {
	  MoveCursor(LINES,0);
	  CleartoEOLN();
	  PutLine1(LINES,0, 
		"\"Bounce\" a copy off the remote machine? (y/n) y%c",
		BACKSPACE);
	  fflush(stdin);	/* wait for answer! */
	  fflush(stdout);
	  if (tolower(ReadCh()) != 'y') { 
	    Write_to_screen("No", 0);
	    fflush(stdout);
	    return(FALSE);
	  }
	  Write_to_screen("Yes!", 0);
	  fflush(stdout);
	}

	return(TRUE);
}