home *** CD-ROM | disk | FTP | other *** search
- /*--------------------------------------------------------------------*/
- /* m a i l . c */
- /* */
- /* Mailer User-Agent (UA) */
- /*--------------------------------------------------------------------*/
-
- /*--------------------------------------------------------------------*/
- /* Changes Copyright (c) 1989-1993 by Kendra Electronic */
- /* Wonderworks. */
- /* */
- /* All rights reserved except those explicitly granted by */
- /* the UUPC/extended license agreement. */
- /*--------------------------------------------------------------------*/
-
- /*--------------------------------------------------------------------*/
- /* RCS Information */
- /*--------------------------------------------------------------------*/
-
- /*
- * $Id: mail.c 1.8 1993/09/23 03:26:51 ahd Exp $
- *
- * Revision history:
- * $Log: mail.c $
- * Revision 1.8 1993/09/23 03:26:51 ahd
- * Use current version variables for Visual C++ under Windows NT
- *
- * Revision 1.7 1993/09/20 04:39:51 ahd
- * OS/2 2.x support
- *
- * Revision 1.6 1993/07/31 16:26:01 ahd
- * Changes in support of Robert Denny's Windows support
- *
- * Revision 1.5 1993/07/24 03:40:55 ahd
- * Change description of "-" command, previous command.
- *
- * version 1.0 Stuart Lynne
- * version 1.5 Samuel Lam <skl@van-bc.UUCP> August/87
- *
- * version 1.6 Drew Derbyshire May/89
- * Support for single user aliases, -u option for reading
- * alternate mailboxes, parsing addresses via external routine,
- * parsing Resent- fields, suppressing Received: fields,
- * automatic positioning to next message. ahd
- * 23 Sep 89 Version 1.07a
- * Support lists in aliases ahd
- *
- * 29 Sep 89 Version 1.07b
- * Add prompting for subject in outgoing mail. ahd
- * 01 Oct 89 Add additional function prototypes to catch bad calls ahd
- * 02 Oct 89 Alter large strings/structures to use malloc()/free() ahd
- * 12 Oct 89 Version 1.07d
- * Correct free() of line in Send_Mail
- * 12 Dec 89 Version 1.07g
- * Various spelling corrections
- * 18 Mar 90 Version 1.07i
- * Add ~user support for save/write command
- * Add ignore list for user
- * Shorten lines printed by aborting from a print command ahd
- * 30 Apr 90 Add autoedit support for sending mail ahd
- * 2 May 90 Add support for options= flags ahd
- * 3 May 90 Split selected subroutines into maillib.c ahd
- * 4 May 90 Add 'save' option. ahd
- * 8 May 90 Add 'pager' option ahd
- * 10 May 90 Add 'purge' option ahd
- * 13 May 90 Alter logging so that no numbers are printed on console ahd
- * Additions for unofficial version 1.07k, Philip David Meese June 1990
- * 16 June 90
- * -added mail command: Copy current (without delete) pdm
- * -altered calls to Collect_Mail to support mail subcmds pdm
- * -added handling of '+' to indicate "relative to home
- * directory" for BSD like mail users. pdm
- * 12 Feb 91 rewrite parser a for more BSD like syntax
- */
-
- static const char rcsid[] =
- "$Id: mail.c 1.8 1993/09/23 03:26:51 ahd Exp $";
-
- /*--------------------------------------------------------------------*/
- /* System include files */
- /*--------------------------------------------------------------------*/
-
- #include <ctype.h>
- #include <stdio.h>
- #include <io.h>
- #include <stdlib.h>
- #include <string.h>
- #include <limits.h>
- #include <time.h>
- #include <dos.h>
- #include <direct.h>
-
- #ifdef _Windows
- #include <windows.h>
- #include <alloc.h>
- #endif
-
- /*--------------------------------------------------------------------*/
- /* UUPC/extended include files */
- /*--------------------------------------------------------------------*/
-
- #include "lib.h"
- #include "address.h"
- #include "alias.h" /* ahd */
- #include "dater.h"
- #include "expath.h"
- #include "getopt.h"
- #include "hlib.h"
- #include "mail.h"
- #include "mailblib.h"
- #include "maillib.h" /* ahd */
- #include "mailsend.h"
- #include "mlib.h"
- #include "pushpop.h"
- #include "stater.h"
- #include "timestmp.h"
-
- #if defined(_Windows)
- #include "winutil.h"
- #endif
-
- /*--------------------------------------------------------------------*/
- /* Global variables */
- /*--------------------------------------------------------------------*/
-
- #ifdef _Windows
- unsigned _stklen = 10 * 1024;
- unsigned _heaplen = 30 * 1024;
- #endif
-
- currentfile();
-
- static char *tmailbox;
- static char mfilename[FILENAME_MAX];
- int letternum = 0;
-
- static boolean useto = FALSE;
-
- FILE *fmailbox;
-
- #define MAXLETTERS 100
-
- static int maxletters = MAXLETTERS;
-
- struct ldesc *letters;
-
- /*--------------------------------------------------------------------*/
- /* Local procedure names */
- /*--------------------------------------------------------------------*/
-
- static void Cleanup(void);
-
- static void Interactive_Mail( const boolean PrintOnly,
- const boolean postoffice );
-
- static void IncludeNew( const char *target, const char *user);
-
- static void PrintSubject(int msgnum, int letternum);
-
- static void UpdateMailbox(int letternum, boolean postoffice);
-
- static int CreateBox(FILE *rmailbox,
- FILE *fmailbox,
- const char *tmailbox);
-
- static void usage( void );
-
- /*--------------------------------------------------------------------*/
- /* Global variables */
- /*--------------------------------------------------------------------*/
-
- static char *replytolist[] = { "Resent-Reply-To:",
- "Resent-From:",
- "Reply-To:",
- "From:",
- NULL };
-
- static char *fromlist[] = { "Resent-From:",
- "From:",
- NULL};
-
- static char *tolist[] = { "Resent-To:",
- "To:",
- NULL};
-
- static char *subjectlist[] = { "Resent-Subject:",
- "Subject:",
- NULL };
-
- static char *datelist[] = { "Resent-Date:",
- "Date:" ,
- NULL} ;
-
-
- /*--------------------------------------------------------------------*/
- /* Information on existing mailbox */
- /*--------------------------------------------------------------------*/
-
- static long mboxsize = 0;
- static time_t mboxage = 0;
-
- /*--------------------------------------------------------------------*/
- /* Command parsing table */
- /*--------------------------------------------------------------------*/
-
- #define NUMERIC_CMD "9999"
- #define EMPTY_CMD ""
-
- static struct CommandTable {
- char *sym;
- ACTION verb;
- unsigned int bits;
- char *help;
- } table[] = {
- { EMPTY_CMD, M_EMPTY, NODISPLAY | NO_OPERANDS | AUTOPRINT ,
- NULL},
- { "!", M_SYSTEM, STRING_OP,
- "Execute DOS command"},
- { "+", M_DOWN, KEWSHORT_OP | AUTOPRINT,
- "Alias for next"},
- { "-", M_UP, KEWSHORT_OP | AUTOPRINT,
- "Alias for previous"},
- { "?", M_FASTHELP, NO_OPERANDS,
- "Print this help"},
- { "alias", M_ALIAS, TOKEN_OP,
- "Print user alias"},
- { "copy", M_COPY, LETTER_OP | FILE_OP ,
- "Copy item to file"},
- { "delete", M_DELETE, LETTER_OP | POSITION | AUTOPRINT ,
- "Delete mail item"},
- { "debug", M_DEBUG, KEWSHORT_OP,
- "Enable debug output"},
- { "dquit", M_DELETEQ, LETTER_OP ,
- "Delete then quit"},
- { "exit", M_EXIT, NO_OPERANDS,
- "Exit without updating mailbox"},
- { "forward", M_FORWARD, LETTER_OP | USER_OP,
- "Resend item to others"},
- { "go", M_GOTO, LETTER_OP | AUTOPRINT ,
- "Go to item"},
- { "Headers", M_HEADERS, LETTER_OP | POSITION ,
- "Print specified item summary"},
- { "headers", M_HEADERS, NO_OPERANDS,
- "Print all item summaries"},
- { "help", M_HELP, NO_OPERANDS,
- "Print long help text"},
- { "mail", M_MAIL, USER_OP,
- "Compose and send mail"},
- { "next", M_DOWN, KEWSHORT_OP | AUTOPRINT ,
- "Move to next item"},
- {"print", M_EXTPRINT, LETTER_OP | POSITION ,
- "Print item (condensed)"},
- {"Print", M_INTPRINT, LETTER_OP | POSITION ,
- "Print item (condensed)"},
- {"previous", M_UP, KEWSHORT_OP | AUTOPRINT ,
- "Move to previous item"},
- {"quit", M_QUIT, NO_OPERANDS,
- "Update mailbox, exit"},
- {"reply", M_REPLY, LETTER_OP | POSITION ,
- "Reply to sender of item"},
- {"save", M_SAVE, LETTER_OP | FILE_OP | POSITION | AUTOPRINT ,
- "Copy item, delete"},
- {"set", M_SET, STRING_OP,
- "Print/set boolean options"},
- {"status", M_STATUS, NO_OPERANDS,
- "Report version/status info"},
- {"type", M_EXTTYPE, LETTER_OP | POSITION,
- "Print item with all headers"},
- {"Type", M_INTTYPE, LETTER_OP | POSITION,
- "Print item with all headers"},
- {"undelete", M_UNDELETE, LETTER_OP | POSITION | AUTOPRINT ,
- "Rescue item after save/delete"},
- {"write", M_WRITE, LETTER_OP | FILE_OP | POSITION | AUTOPRINT ,
- "Copy item w/o header, delete"},
- {"xit", M_EXIT, NO_OPERANDS,
- "alias for exit"},
- { NUMERIC_CMD, M_GOTO, NODISPLAY | KEWSHORT_OP | AUTOPRINT ,
- NULL} ,
- { NULL, M_INVALID, NODISPLAY | STRING_OP,
- NULL }
- } ;
-
- /*--------------------------------------------------------------------*/
- /* m a i n */
- /* */
- /* Main program */
- /*--------------------------------------------------------------------*/
-
- void main(int argc, char **argv)
- {
-
- boolean PrintOnly = FALSE;
- boolean postoffice = TRUE;
- boolean readmail = FALSE;
- boolean sendmail = FALSE;
- int option;
- char *subject = NULL;
-
- #if defined(__CORE__)
- copywrong = strdup(copyright);
- checkref(copywrong);
- #endif
-
- banner( argv );
-
- if (!configure( B_MUA ))
- exit(1); /* system configuration failed */
-
- if (!InitRouter())
- exit(1); /* system configuration failed */
-
- tmailbox = mktempname(NULL, "TMP");
- PushDir(".");
-
- /*--------------------------------------------------------------------*/
- /* get mailbox file name */
- /*--------------------------------------------------------------------*/
-
- strcpy( mfilename, E_mailbox );
- if ( strchr( mfilename ,'.' ) == NULL )
- mfilename[8] = '\0'; /* Prevent OS/2 filename length
- overrun */
-
- if ( bflag[ F_MULTITASK ] )
- {
- if (expand_path( mfilename, E_homedir, E_homedir, E_mailext ) == NULL )
- panic();
- }
- else
- mkmailbox(mfilename, E_mailbox );
-
- /*--------------------------------------------------------------------*/
- /* parse arguments */
- /*--------------------------------------------------------------------*/
-
- while ((option = getopt(argc, argv, "f:ps:tu:x:")) != EOF)
- {
- char oname[FILENAME_MAX];
-
- switch (option)
- {
- case 'f':
- readmail = TRUE;
- strcpy( mfilename, optarg );
- if (expand_path( mfilename, NULL, E_homedir, E_mailext ) == NULL )
- usage();
-
- /*--------------------------------------------------------------------*/
- /* This next one is a little tricky ... If we log outgoing */
- /* mail, we copy the name of the outgoing mail file into a */
- /* temporary buffer, and expand the name of the file to include */
- /* the path name. If this name is the same as the current */
- /* file, flip-flip the useto flag which says use the To: */
- /* related fields when scanning headers, not the From: related */
- /* fields. */
- /*--------------------------------------------------------------------*/
-
- if (( E_filesent != NULL ) &&
- (expand_path( strcpy( oname, E_filesent) ,
- E_homedir, E_homedir , E_mailext ) != NULL ) &&
- equali( oname , mfilename ))
- /* Our outgoing filename? */
- useto = ! useto; /* Yes --> Automatically switch */
- postoffice = FALSE;
- break;
-
- case 'p':
- readmail = TRUE;
- PrintOnly = TRUE;
- break;
-
- case 'u': /* Read alternate mailbox? */
- readmail = TRUE;
- mkmailbox(mfilename, optarg);
- postoffice = FALSE;
- break;
-
- case 'x':
- debuglevel = atoi(optarg);
- break;
-
- case 's':
- sendmail = TRUE;
- subject = optarg;
- break;
-
- case 't':
- readmail = TRUE;
- useto = ! useto;
- break;
-
- case '?':
- usage();
-
- } /* switch */
-
- } /* while */
-
- /*--------------------------------------------------------------------*/
- /* Check for conflicts */
- /*--------------------------------------------------------------------*/
-
- sendmail |= (optind != argc);
-
- if ( sendmail && readmail )
- {
- puts("Conflicting options specified");
- usage();
- }
-
- if ((optind == argc) && sendmail)
- {
- puts("Missing addresses for sending mail");
- usage();
- }
-
- /*--------------------------------------------------------------------*/
- /* We have the options, now decide how to process them */
- /*--------------------------------------------------------------------*/
-
- if (sendmail)
- {
- argc -= optind;
-
- if ( subject != NULL )
- {
-
- argv = &argv[optind-2];
- argv[0] = "-s";
- argv[1] = subject;
-
- Collect_Mail(stdin, argc+2 , argv , -1, FALSE);
- } /* if ( subject != NULL ) */
- else {
- Collect_Mail(stdin, argc, &argv[optind], -1, FALSE);
-
- #ifdef _Windows
- atexit ( CloseEasyWin );
- #endif
- }
-
- } /* if (sendmail) */
- else {
- if ( postoffice && bflag[ F_MULTITASK ] )
- IncludeNew( mfilename, E_mailbox);
- Interactive_Mail( PrintOnly , postoffice );
- }
-
- Cleanup();
- PopDir();
- exit(0);
-
- } /*main*/
-
- /*--------------------------------------------------------------------*/
- /* C l e a n u p */
- /* */
- /* Remove temporary files when exiting */
- /*--------------------------------------------------------------------*/
-
- void Cleanup()
- {
-
- printmsg(2,"Deleting temporary mailbox %s", tmailbox);
-
- if ( fmailbox != NULL )
- {
- fclose(fmailbox);
- fmailbox = NULL;
- }
-
- unlink(tmailbox);
-
- } /*Cleanup*/
-
-
- /*--------------------------------------------------------------------*/
- /* I n t e r a c t i v e _ M a i l */
- /* */
- /* main procedure for reading mail */
- /*--------------------------------------------------------------------*/
-
- static void Interactive_Mail( const boolean PrintOnly,
- const boolean postoffice )
- {
- char resp[LSIZE];
- int current = 0; /* ahd */
- boolean done = FALSE; /* ahd */
- boolean modified;
- FILE *rmailbox;
-
- /*--------------------------------------------------------------------*/
- /* Open real and temporary mailbox files */
- /*--------------------------------------------------------------------*/
-
- if ((rmailbox = FOPEN(mfilename, "r",TEXT_MODE)) == nil(FILE)) {
- printf("No mail in %s\n", mfilename);
- return;
- }
-
- mboxage = stater( mfilename, &mboxsize );
- /* Remember mailbox information */
-
- if ((fmailbox = FOPEN(tmailbox, "w", BINARY_MODE)) == nil(FILE)) {
- printerr(tmailbox);
- return;
- }
-
- letters = calloc(maxletters,sizeof(letters[0]));
- checkref(letters);
-
- /*--------------------------------------------------------------------*/
- /* Copy real mailbox to temporary one */
- /*--------------------------------------------------------------------*/
-
- setvbuf(rmailbox, NULL, _IOFBF, 8192);
- setvbuf(fmailbox, NULL, _IOFBF, 8192);
-
- letternum = CreateBox(rmailbox, fmailbox, tmailbox);
-
- fclose(rmailbox);
- fclose(fmailbox);
-
- rmailbox = fmailbox = NULL;
-
- if (letternum < 1) /* Did we find any mail in the box? */
- { /* No --> Return to caller */
- if (letternum == 0)
- printf("No mail in %s\n", mfilename);
- return;
- }
-
- /*--------------------------------------------------------------------*/
- /* Shrink mailbox status array to what we actually need */
- /*--------------------------------------------------------------------*/
-
- letters = realloc( letters, (letternum + 1) * sizeof(letters[0]));
- checkref(letters);
-
- fmailbox = FOPEN(tmailbox, "r", BINARY_MODE);
-
- if (fmailbox == NULL)
- {
- printerr(tmailbox);
- panic();
- } /* if */
- setvbuf(fmailbox, NULL, _IOFBF, 8192);
-
- modified = postoffice && (!PrintOnly);
-
- if (PrintOnly) {
- int j = 0;
- while (j < letternum)
- {
- Pager(j, TRUE, noreceived, !j );
- j++ ;
- }
- return;
- }
-
- PrintSubject(-1,letternum); /* print all subjects */
-
- /*--------------------------------------------------------------------*/
- /* Determine first letter in to prompt at */
- /*--------------------------------------------------------------------*/
-
- if (letternum == 0)
- current = -1;
- else
- current = 0;
-
- /*--------------------------------------------------------------------*/
- /* Begin main command loop for reading the mail */
- /*--------------------------------------------------------------------*/
-
- if (!bflag[F_EXPERT])
- printf("Enter \"?\" for short help or \"help\" for long help.\n");
-
- #ifdef _Windows
- atexit ( CloseEasyWin );
- #endif
-
- while( ! done )
- {
- char *command, *operand;
- int integer;
- boolean first_pass = TRUE;
- int previous = current;
- struct CommandTable *cmd_ptr = table;
- boolean success = TRUE;
- boolean crlf = FALSE; /* crlf after delete command? */
-
- printf("%d%s",current + 1,
- (letters[current].status == M_DELETED) ? "*" : " ");
- if (!Console_fgets(resp, LSIZE, "? ")) /* End of file? */
- {
- done = TRUE;
- continue; /* Yes --> Exit loop */
- }
- PageReset();
-
- /*--------------------------------------------------------------------*/
- /* Locate command to execute */
- /*--------------------------------------------------------------------*/
-
- integer = strlen( resp );
- if (integer && ( resp[ integer - 1 ] == '\n'))
- resp[ integer - 1 ] = '\0'; /* Trim newline, if any */
-
- operand = command = strtok( resp, WHITESPACE );
- if ( command == NULL )
- command = EMPTY_CMD;
- else if (Numeric(command))
- command = NUMERIC_CMD;
-
- while( cmd_ptr->sym != NULL)
- {
- if (equaln(command, cmd_ptr->sym, strlen(command)))
- break; /* Exit if we have a hit */
- cmd_ptr++; /* Examine next command */
- } /* while */
-
- /*--------------------------------------------------------------------*/
- /* Get rest of command line, and trim leading spaces from it */
- /*--------------------------------------------------------------------*/
-
- if (!equal(command, NUMERIC_CMD) && (operand != NULL))
- {
- operand = strtok( NULL , "");
- /* Save rest of string for later */
- if ( operand != NULL )
- {
- while( isspace( *operand ))
- operand++ ;
-
- if (*operand == '\0')
- operand = NULL ;
- } /* if */
- }
-
- /*--------------------------------------------------------------------*/
- /* Parse items to be selected from mailbox for command */
- /*--------------------------------------------------------------------*/
-
- if (cmd_ptr->bits & (LETTER_OP) )
- success = SelectItems( &operand, current, cmd_ptr->bits);
-
- /*--------------------------------------------------------------------*/
- /* Process the operands in the list */
- /*--------------------------------------------------------------------*/
-
- while( success &&
- Get_Operand( &integer, &operand, cmd_ptr->bits, first_pass) )
- {
- switch( cmd_ptr->verb )
- {
- case M_ALIAS:
- ShowAlias( operand );
- break;
-
- case M_COPY:
- success = SaveItem( integer,
- FALSE, /* Do not delete */
- seperators, /* Do save headers */
- (operand == NULL) ? "PRN" : operand ,
- cmd_ptr->verb );
- break;
-
- case M_DEBUG:
- debuglevel = integer;
- printmsg(0,"Debug set to %d",debuglevel);
- break;
-
- case M_DELETEQ:
- done = TRUE;
- case M_DELETE:
- if (letters[integer].status < M_DELETED)
- {
- letters[integer].status = M_DELETED;
- if ( ! crlf )
- printf("Deleting item(s) %d",integer + 1 );
- else
- printf(" %d",integer + 1 );
- crlf = modified = TRUE;
- }
- break;
-
- case M_DOWN:
- current = Position( 0 , integer , current );
- break;
-
- case M_EMPTY:
- if ( bflag[F_DOSKEY] && !bflag[F_EXPERT] )
- {
- printf("DOSKEY active, empty line ignored\n");
- PrintSubject( current , letternum );
- success = FALSE;
- }
- else if (letters[current].status == M_UNREAD)
- success = Pager( current , TRUE, noreceived, first_pass);
- else
- current = Position( 0 , 1 , current );
- break;
-
- case M_EXIT:
- modified = FALSE;
- done = TRUE;
- break;
-
- case M_EXTPRINT:
- success = Pager( integer , TRUE, noreceived, first_pass);
- break;
-
- case M_EXTTYPE:
- success = Pager( integer , TRUE, noseperator, first_pass);
- break;
-
- case M_FASTHELP:
- {
- size_t subscript = 0;
- #ifndef _Windows
- size_t column = 0;
- #endif
- fputs("Valid commands are:\n",stdout);
- while( table[subscript].sym != NULL)
- {
- if ( !(table[subscript].bits & NODISPLAY ))
- {
- #ifdef _Windows
- fputc( '\n' , stdout );
- #else
- fputc( ( column++ % 2 ) ? ' ' : '\n' , stdout );
- #endif
- printf("%-9s%-30s",table[subscript].sym,
- table[subscript].help );
- } /* if */
- subscript ++;
- } /* while */
- fputs("\n\nEnter \"help\" for additional information.\n",
- stdout);
- break;
- } /* case */
-
- case M_FORWARD:
- success = ForwardItem( integer, operand);
- break;
-
- case M_GOTO:
- current = Position( integer, 0, current );
- break;
-
- case M_HEADERS:
- PrintSubject( (cmd_ptr->bits & NO_OPERANDS) ?
- -1 : integer, letternum );
- break;
-
- case M_HELP:
- {
- char filename[FILENAME_MAX];
- mkfilename(filename, E_confdir, "mail.hlp");
- Sub_Pager(filename, TRUE );
- break;
- }
-
- case M_INTPRINT:
- success = Pager( integer , FALSE, noreceived, first_pass);
- break;
-
- case M_INTTYPE:
- success = Pager( integer , FALSE, noseperator, first_pass);
- break;
-
- case M_INVALID:
- printf("Invalid command \"%s\". Enter \"?\" for help.\n",
- command);
- break;
-
- case M_MAIL:
- success = DeliverMail( operand , current);
- break;
-
- case M_NOOP:
- break;
-
- case M_REPLY:
- success = Reply( integer );
- break;
-
- case M_QUIT:
- done = TRUE;
- break;
-
- case M_SAVE:
- success = SaveItem( integer,
- TRUE, /* Do delete */
- seperators, /* Do save headers */
- operand ,
- cmd_ptr->verb );
- modified = TRUE;
- break;
-
- case M_SET:
- if (operand == NULL)
- sayoptions( configFlags);
- else
- options(operand, USER_CONFIG, configFlags, bflag);
- break;
-
- case M_SYSTEM:
- subshell( operand );
- break;
-
- case M_UNDELETE:
- letters[integer].status = M_UNREAD;
- break;
-
- case M_UP:
- current = Position( 0 , - integer , current );
- break;
-
- case M_STATUS:
- printf("%s:\t%s created %s %s running under %s %d.%02d\n",
- compilep, compilev, compiled, compilet,
-
- #ifdef WIN32
- "Windows NT",
- _winmajor,
- _winminor);
- #elif defined(__OS2__)
- "OS/2(R)" ,
- (int) _osmajor / 10,
- _osminor);
- #elif defined(__TURBOC__)
- "DOS",
- _osmajor,
- _osminor);
- #else
- (_osmode == DOS_MODE) ? "DOS" : "OS/2(R)" ,
- (_osmode == DOS_MODE) ? _osmajor : ((int) _osmajor / 10 ),
- _osminor);
- #endif
- #ifdef _Windows
- printf("Windows version: %s\t", compilew );
- #endif
- printf("Magic Word:\t%s\n","flarp");
- printf("Return address:\t\"%s\" <%s@%s>\n"
- "Domain name:\t%s\tNodename:\t%s\n",
- E_name, E_mailbox, E_fdomain, E_domain, E_nodename );
- printf("Current File:\t%s\tNumber of items: %d\n"
- "File size:\t%ld bytes\tLast updated:\t%s",
- mfilename, letternum + 1 , mboxsize ,
- ctime( & mboxage ) );
- break;
-
- case M_WRITE:
- success = SaveItem( integer,
- TRUE, /* Do delete */
- noheader, /* Do not save headers */
- operand,
- cmd_ptr->verb );
- modified = TRUE;
- } /* switch */
- first_pass = FALSE;
- } /* while */
-
- success = ! first_pass; /* If first_pass not run, then
- Get_Operand failed */
-
- if ( crlf )
- putchar('\n');
-
- if ( success && !done )
- {
- if (cmd_ptr->bits & POSITION)
- current = Position( 0 , 0 , integer );
-
- if ( current != previous )
- {
- if ( (cmd_ptr->bits & AUTOPRINT ) &&
- bflag[F_AUTOPRINT] &&
- (letters[current].status != M_DELETED) )
- Pager( current , TRUE, noreceived, TRUE);
- else
- PrintSubject( current , letternum );
- } /* if */
- } /* if */
- } /* while */
-
- /*--------------------------------------------------------------------*/
- /* End main command loop */
- /*--------------------------------------------------------------------*/
-
- if (modified)
- UpdateMailbox(letternum, postoffice);
-
- free(letters);
-
- } /*Interactive_Mail*/
-
- /*--------------------------------------------------------------------*/
- /* I n c l u d e N e w */
- /* */
- /* Includes mail from the system box into the user's local */
- /* mailbox */
- /*--------------------------------------------------------------------*/
-
- static void IncludeNew( const char *target, const char *user)
- {
- long age, size;
- FILE *stream_in;
- FILE *stream_out;
- int bytes;
-
- char sysbox[FILENAME_MAX];
- char buf[BUFSIZ];
-
- mkmailbox(sysbox, user);
-
- /*--------------------------------------------------------------------*/
- /* Return semi-quietly if we can't open the system mailbox */
- /*--------------------------------------------------------------------*/
-
- stream_in = FOPEN( sysbox, "r", BINARY_MODE);
- if ( stream_in == NULL )
- {
- if ( debuglevel > 1 )
- printerr( sysbox );
- return;
- }
-
- /*--------------------------------------------------------------------*/
- /* Determine if we have new mail, returning quietly if not */
- /*--------------------------------------------------------------------*/
-
- age = stater( sysbox , &size );
-
- if ( age == -1)
- panic();
-
- printmsg( 1, "Including mail from %s through %s",
- sysbox,
- ctime(&age));
-
- /*--------------------------------------------------------------------*/
- /* Now open up the output file */
- /*--------------------------------------------------------------------*/
-
- stream_out = FOPEN( target, "a+", BINARY_MODE);
-
- if ( stream_out == NULL )
- {
- printerr( target );
- panic();
- }
-
- /*--------------------------------------------------------------------*/
- /* Loop to read the data */
- /*--------------------------------------------------------------------*/
-
- while ((bytes = fread(buf,sizeof(char), sizeof buf, stream_in)) > 0)
- {
- if ((int) fwrite(buf, sizeof(char), bytes, stream_out) != bytes)
- {
- printmsg(0, "Error including new mail into %s", target );
- printerr( target );
- fclose( stream_in );
- fclose( stream_out );
- panic();
- }
- } /* while */
-
- /*--------------------------------------------------------------------*/
- /* Clean up and return to caller */
- /*--------------------------------------------------------------------*/
-
- if ( ferror( stream_in ))
- {
- printerr( sysbox );
- panic();
- }
-
- fclose( stream_in );
- fclose( stream_out );
-
- filebkup( sysbox );
- unlink(sysbox);
-
- } /* IncludeNew */
-
- /*--------------------------------------------------------------------*/
- /* C r e a t e B o x */
- /* */
- /* Creates the temporary mailbox and related tables */
- /*--------------------------------------------------------------------*/
-
- int CreateBox(FILE *rmailbox, FILE *fmailbox , const char *tmailbox)
- {
-
- /*--------------------------------------------------------------------*/
- /* Copy real mailbox file to temporary mailbox file */
- /*--------------------------------------------------------------------*/
-
- int letternum = 0;
- boolean inheader = FALSE;
- long position;
- char line[LSIZE];
- char **list;
- size_t replyprior = 0;
- size_t dateprior = 0;
- size_t subjectprior = 0;
- size_t fromprior = 0;
-
- struct ldesc *letter = NULL;
-
- while ((fgets(line, LSIZE, rmailbox) != nil(char)) ){
-
- if (inheader)
- {
- if (*line == '\n')
- inheader = FALSE;
- } /* inheader */
- else { /* Determine if starting new message */
- if (equal(line,MESSAGESEP) ||
- (bflag[F_FROMSEP] && equaln(line, "From ", 5)))
- {
- while (equal(line,MESSAGESEP))
- if (fgets(line, LSIZE, rmailbox) == NULL)
- {
- printerr(mfilename);
- panic();
- } /* if */
-
- /*--------------------------------------------------------------------*/
- /* Make the mailbox bigger if we need to */
- /*--------------------------------------------------------------------*/
-
- position = ftell(fmailbox);
- if ( (letternum+1) == maxletters )
- {
- maxletters = max((int) ((maxletters * mboxsize) / position),
- (letternum * 11) / 10 );
- printmsg(2,"Reallocating mailbox array from %d to %d entries",
- letternum+1, maxletters );
- letters = realloc( letters, maxletters * sizeof(letters[0]));
- checkref( letters );
- }
-
- /*--------------------------------------------------------------------*/
- /* Initialize this entry in th mailbox array */
- /*--------------------------------------------------------------------*/
-
- letter = &letters[letternum++];
-
- fromprior = subjectprior = replyprior = dateprior = INT_MAX;
- letter->from = letter->subject = letter->date =
- letter->replyto = MISSING;
- letter->adr = position;
- letter->status = M_UNREAD;
- letter->lines = 0L;
- inheader = TRUE;
- printf("Reading message %d (%d%% done)\r",letternum,
- (int) (position * 100 / mboxsize));
- }
- else
- {
- if(letter == NULL) /* Did we find first letter? */
- { /* No --> Abort with message */
- fprintf(stderr,"%s %s\n\a",
- "This mailbox is not in UUPC/extended format!",
- bflag[F_FROMSEP] ?
- "Messages must be seperated by From lines!" :
- "(Try \"options=fromsep\" in your configuration file)");
- panic();
- } /* if */
-
- letter->lines++;
- } /* else */
- } /* else */
-
- if (inheader)
- {
- size_t priority = 0;
-
- /*--------------------------------------------------------------------*/
- /* Search for the best Date: related field */
- /*--------------------------------------------------------------------*/
-
- while ( (dateprior > priority) && (datelist[priority] != NULL ))
- {
- if (equalni(line, datelist[priority],
- strlen(datelist[priority]) ) )
- {
- letter->date = ftell(fmailbox);
- dateprior = priority;
- }
- priority++;
- }
-
- /*--------------------------------------------------------------------*/
- /* Search for the best Subject: related field */
- /*--------------------------------------------------------------------*/
-
- priority = 0;
- while ( (subjectprior > priority) &&
- (subjectlist[priority] != NULL ))
- {
- if (equalni(line, subjectlist[priority],
- strlen(subjectlist[priority]) ) )
- {
- letter->subject = ftell(fmailbox);
- subjectprior = priority;
- }
- priority++;
- }
-
- /*--------------------------------------------------------------------*/
- /* Search for the best From: header related field */
- /*--------------------------------------------------------------------*/
-
- list = (useto) ? tolist : fromlist;
- priority = 0;
- while ( (fromprior > priority) && (list[priority] != NULL ))
- {
- if (equalni(line, list[priority],
- strlen(list[priority]) ) )
- {
- letter->from = ftell(fmailbox);
- fromprior = priority;
- }
- priority++;
- } /* while */
-
- /*--------------------------------------------------------------------*/
- /* Search for the best Reply-To related field */
- /*--------------------------------------------------------------------*/
-
- priority = 0;
- while ( (replyprior > priority) &&
- (replytolist[priority] != NULL ))
- {
- if (equalni(line, replytolist[priority],
- strlen(replytolist[priority]) ) )
- {
- letter->replyto = ftell(fmailbox);
- replyprior = priority;
- } /* if */
- priority++;
- } /* while */
- } /* inheader */
-
- if (fputs(line, fmailbox) == EOF )
- {
- printerr(tmailbox);
- panic();
- } /* if */
-
-
- } /* while */
-
- letters[letternum].adr = ftell(fmailbox);
- letters[letternum].status = M_DELETED;
-
-
- fclose(rmailbox);
- fclose(fmailbox);
-
- return letternum;
-
- } /* CreateBox */
-
- /*--------------------------------------------------------------------*/
- /* P r i n t S u j e c t */
- /* */
- /* Print the subject line of one or all messages in the mailbox */
- /*--------------------------------------------------------------------*/
-
- void PrintSubject(int msgnum,int letternum)
- {
- struct ldesc *ld;
- char from[LSIZE];
- char subject[LSIZE];
- char date[LSIZE];
- char line[LSIZE];
-
- int k, mink, maxk;
-
- if (msgnum == -1)
- { /* print all of them? */
- sprintf(line," %d messages in file %s.\n",letternum,mfilename);
- PageLine(line);
- mink = 0;
- maxk = letternum - 1;
- } else
- mink = maxk = msgnum;
-
- for (k = mink ; k <= maxk ; k++) {
-
- ld = &letters[k];
- if ((ld->status == M_DELETED) && (msgnum == -1))
- continue;
-
- ReturnAddress(from,ld); /* Get return address for letter */
-
- /* Date: Wed May 13 23:59:53 1987 */
- *date = '\0'; /* default date to null */
- if (RetrieveLine(ld->date, date, LSIZE)) {
- sscanf(date, "%*s %*s %s %s", line, subject);
- sprintf(date, "%s %s", line, subject);
- }
-
- strcpy(subject, "--- no subject ---");
- if (RetrieveLine(ld->subject, line, LSIZE)) {
- register char *sp;
- sp = line;
- while (!isspace(*sp))
- sp++;
- while (isspace(*sp))
- sp++;
- strcpy(subject, sp);
- }
-
- /* make sure the fields aren't too long */
-
- from[25] = '\0';
- date[6] = '\0';
- subject[30] = '\0';
-
- sprintf(line, "%3d%c %6s %-25s %-30s (%5ld)\n", k + 1,
- ((ld->status == M_DELETED) ? '*' : ' '),
- date, from, subject, ld->lines);
-
- if (PageLine(line))
- break;
-
- }
-
- } /*PrintSubject*/
-
-
- /*--------------------------------------------------------------------*/
- /* U p d a t e M a i l b o x */
- /* */
- /* Update the permanent mailbox for the user */
- /*--------------------------------------------------------------------*/
-
- void UpdateMailbox(int letternum, boolean postoffice)
- {
- int current;
- boolean changed = FALSE;
- boolean problem = FALSE;
- FILE *fmailbag;
- FILE *mbox = NULL;
- char *mboxname = NULL;
- long newsize;
- time_t newage;
- size_t msave = 0;
- size_t psave = 0;
-
- /*--------------------------------------------------------------------*/
- /* Auto save into user's home directory mailbox if we were */
- /* reading the system mailbox and the user specified the */
- /* 'save' option. */
- /*--------------------------------------------------------------------*/
-
- postoffice = postoffice && bflag[F_SAVE];
-
- /*--------------------------------------------------------------------*/
- /* Determine if anything was actually changed in the mailbox */
- /*--------------------------------------------------------------------*/
-
- for (current = 0;
- (current < letternum) && (! changed);
- current++)
- {
- if (letters[current].status == M_DELETED)
- changed = TRUE;
-
- if (postoffice && (letters[current].status != M_UNREAD))
- changed = TRUE;
- }
-
- if (!changed)
- return;
-
- /*--------------------------------------------------------------------*/
- /* Determine if the mailbox has changed since we built our */
- /* temporary file */
- /*--------------------------------------------------------------------*/
-
- newage = stater( mfilename , &newsize );
-
- if ( mboxsize != newsize )
- {
- printf("%s size has changed from %ld to %ld bytes\n",
- mfilename, mboxsize, newsize );
- problem = TRUE;
- }
-
- if ( mboxage != newage )
- {
- char mboxbuf[DATEBUF];
- char newbuf[DATEBUF];
- printf("%s date stamp has changed from %s to %s\n",
- mfilename, dater(mboxage, mboxbuf), dater(newage, newbuf) );
- problem = TRUE;
- }
-
- while ( problem )
- {
- int c;
-
- printf("WARNING! File %s has changed, data may be lost if updated!\n",
- mfilename);
- fputs("Update anyway? ",stdout);
-
- c = Get_One();
-
- switch (tolower( c ))
- {
- case 'y':
- puts("Yes");
- problem = FALSE;
- break;
-
- case 'n':
- printf("No\nUpdate aborted, %s left unchanged.\n",
- mfilename);
- return;
-
- default:
- printf("%c - Invalid Response\n",c);
- break;
- } /* switch */
- } /* while ( problem ) */
-
- /*--------------------------------------------------------------------*/
- /* Allocate auto save related variables */
- /*--------------------------------------------------------------------*/
-
- if (postoffice)
- {
- mboxname = malloc(FILENAME_MAX);
- checkref(mboxname);
- strcpy( mboxname, "mbox" );
- expand_path( mboxname, E_homedir, E_homedir, E_mailext );
- } /* if (postoffice) */
-
- /*--------------------------------------------------------------------*/
- /* Create a backup file if needed */
- /*--------------------------------------------------------------------*/
-
- if ( bflag[F_BACKUP] )
- filebkup( mfilename );
-
- /*--------------------------------------------------------------------*/
- /* Begin re-writing the mailbox */
- /*--------------------------------------------------------------------*/
-
- if ((fmailbag = FOPEN(mfilename, "w",TEXT_MODE)) == nil(FILE))
- {
- printf("UpdateMailbox: can't rewrite %s.\n", mfilename);
- Cleanup();
- } /* if */
-
- setvbuf(fmailbag, NULL, _IOFBF, 8192);
-
- /*--------------------------------------------------------------------*/
- /* We got the files open, now actually loop through copying */
- /* data from our temporary mailbox back into the permenent one, */
- /* or in the user's mbox if he read the message and the post */
- /* office is open. */
- /*--------------------------------------------------------------------*/
-
- printf("Cleaning up ", current+ 1);
-
- for (current = 0; current < letternum; current++)
- {
- if (letters[current].status == M_DELETED)
- {
- /* No operation */
- fputc('.', stdout);
- }
- else if (postoffice && (letters[current].status != M_UNREAD))
- {
-
- if ( mbox == NULL ) /* Mailbox already open? */
- { /* No --> Do so now */
- mbox = FOPEN(mboxname, "a",TEXT_MODE);
- if (mbox == NULL) /* Open fail? */
- { /* Yes --> Disable postoffice autosave*/
- printf("\nUpdateMailbox: can't append to %s.\n", mboxname);
- postoffice = FALSE;
- current--; /* Process this entry again */
- } /* if */
- else
- setvbuf(mbox, NULL, _IOFBF, 8192);
- } /* if ( mbox == NULL ) */
-
- if ( mbox != NULL )
- {
- fputc('+', stdout);
- CopyMsg(current, mbox, seperators, FALSE);
- msave++;
- } /* mbox */
- }
- else {
- fputc('*', stdout);
- CopyMsg(current, fmailbag, seperators, FALSE);
- psave ++;
- } /* else */
-
- } /* for */
- fputs(" done!\n", stdout);
-
- /*--------------------------------------------------------------------*/
- /* Close the post office. We close the 'mbox' in the user's */
- /* home directory, report if any data was saved in it, and */
- /* then free the storage associated with the postoffice processing.*/
- /*--------------------------------------------------------------------*/
-
- if ( postoffice )
- {
-
- if (msave > 0) /* Did we write data into mailbox? */
- { /* Yes --> Report it */
- fclose(mbox);
- printf("%d letter%s saved in %s%s",
- msave,
- (msave > 1) ? "s" : "" ,
- mboxname,
- (psave > 0) ? ", " : ".\n");
- }
-
- free(mboxname);
- } /* if (postoffice) */
-
- /*--------------------------------------------------------------------*/
- /* Now, clean up after the input mailbox. We close it, and */
- /* report when anything was saved into it. If nothing was */
- /* saved, we delete the file if the 'purge' option is active. */
- /*--------------------------------------------------------------------*/
-
- fclose(fmailbag);
-
- if (psave > 0)
- printf("%d letter%s held in %s.\n",
- psave ,
- (psave > 1) ? "s" : "" , mfilename);
- else if (bflag[F_PURGE] )
- {
- remove(mfilename);
- printf("Empty mail box %s has been deleted.\n", mfilename);
- }
-
- } /* UpdateMailbox */
-
- /*--------------------------------------------------------------------*/
- /* U s a g e */
- /* */
- /* Report command line syntax */
- /*--------------------------------------------------------------------*/
-
- static void usage( void )
- {
- puts("\nUsage:\tmail [-s subject] recipient ... "
- "[-c recipient ...] [-b receipient ...]\n"
- "\tmail [-f mailbox] [-u user] [-t] [-p] [-x debug]");
- exit(1);
- }
-