/* pcmail.c copyright (C) 1987 Stuart Lynne Copying and use of this program are controlled by the terms of the Free Software Foundations GNU Emacs General Public License. version 0.1 March 31/1987 pcmail pcmail address1 address2 ... < the.message description An 822 compatible (hopefully) mail delivery system for pc's. Designed for delivering mail on a pc based system. It will put local mail (ie, not @ or ! in address) into files in the default mail directory. If remote it will put into an outgoing mailbag in the default mail directory. Performs a simple bundling of mail messages into one file with arguments prepended as To: arg header lines. And adds a Message-Lines: header which gives the number of lines in the content part of the message (after the first blank line). pcmail john jack jill@xyz.uucp < afile To: john To: jack To: jill@xyz.uucp X-Message-Lines: ????? Content-Length: ????? ... ... ... Content-Length: is used without X- prepended to be compatible with AT&T Mail bundles. This is not 822 compatible per se, but is allowed. It also adds the from From and Date lines. Subject: lines may be inserted by placing them at the beginning of the message. A Unix version should lock the /usr/mail/mailbag file. Another program called rpcmail will unbundle the files created by pcmail and deliver each message to the local rmail. So conceptually (pcmail ..... < ...; pcmail .... < ...) | sz -> rz | rpcmail would deliver remote messages intact. environment variables The following evironment variables are used: MAILBOX current user's mailbox, "stuart" NAME current user's name, "Stuart Lynne" DOMAIN domain of this machine, "slynne.mac.van-bc.can" MAILDIR where is mail kept, "mpw:mail" compiling Compiled by itself it will operate as a standalone program. If the compiler option: -DNOMAIN is used, it will compile as a routine: pcmail (argc, argv) char **argv; int argc; and can be used internally in other programs. Customization PCMAIL mailbag for remote mail FAKEUUX emulate uux, make appropriate files in SPOOLDIR RMAIL rmail DEBUG1 first level Debug trace */ /* #ifdef NOMAIN #include "dcp.h" #else */ #include #include "host.h" /* #endif */ FILE *FOPEN(); #define FORWARD "Forward to" #define SBUFSIZ 124 FILE *mailfile; FILE *tempfile; char buf[BUFSIZ]; char miscbuff[100]; long int lines = 0; long int bytes = 0; long int sequence = 0; long tloc; char chartime[26]; /* current time in characters */ char *thetime; char tfilename[100]; char mfilename[100]; char mailsent[100]; int local = TRUE; char remotes[BUFSIZ]; char uucp[] = "uucp"; char *fgets(); int fputs(); #ifdef NOMAIN #ifdef RMAIL #define main rmail #else #define main lmail #endif #define exit return extern int debuglevel; #else int debuglevel; #endif #ifndef RMAIL char Subject[132] = ""; #endif char *mcurdir; char s_mcurdir[128]; /* current directory path (save malloc call) */ char * getcwd(); int chdir(); main(argc, argv) char *argv[]; { long int position; register int header = 1; register int amount; register int argcount; register char **argvec; int remote; int s1, s2; #ifndef NOMAIN /* get environment var's */ HOSTINIT; loadenv(); if (argc <= 1) { fprintf( stderr, "pcmail usage: pcmail addresses < message\n" ); exit(1); } debuglevel = 1; #endif #ifdef RMAIL local = FALSE; #else local = TRUE; #endif if ( debuglevel > 5 ) { fprintf( stderr, "pcmail: argc %d ", argc ); argcount = argc; argvec = argv; while (argcount--) { fprintf( stderr, " \"%s\"", *argvec++ ); } fprintf( stderr, "\n" ); tloc = time( (long *)NULL ); thetime = ctime(&tloc); fprintf( stderr, "thetime: %s\n",thetime ); } mcurdir = getcwd( s_mcurdir, 0 ); chdir( spooldir ); /* get sequence number */ mkfilename( tfilename, confdir, SFILENAME ); if ( debuglevel > 4 ) fprintf( stderr, "pcmail: opening %s\n", tfilename ); /* */ tempfile = FOPEN( tfilename, "r", 't' ); if (tempfile != (FILE *)NULL) { fscanf( tempfile, "%ld", &sequence ); fclose( tempfile ); } else fprintf( stderr, "pcmail: can't find %s file, creating\n", tfilename ); /* update sequence number */ if ( debuglevel > 5 ) fprintf( stderr, "pcmail: new sequence # %ld\n", sequence ); tempfile = FOPEN( tfilename, "w", 't' ); if (tempfile != (FILE *)NULL) { fprintf( tempfile, "%ld\n", sequence+1 ); fclose( tempfile ); } /* open a temporary file */ /* sprintf( tfilename, TFILENAME, sequence ); */ sprintf( miscbuff, TFILENAME, sequence ); mkfilename( tfilename, tempdir, miscbuff ); if ( debuglevel > 5 ) fprintf( stderr, "pcmail: opening %s\n", tfilename ); tempfile = FOPEN( tfilename, "w", 'b' ); if (tempfile == (FILE *)NULL) { fprintf( stderr, "pcmail: can't open %s\n", tfilename ); exit(1); } /* copy stdin to tempfile, counting content lines and bytes */ header = 1; while (fgets( buf, 512, stdin ) != (char *)NULL) { if (header != 0) { if (strlen( buf ) == 1) { header = 0; fprintf( tempfile, "\n" ); continue; } else if (strchr( buf, ':' ) == NULL) { header = 0; fprintf( tempfile, "\n" ); } } if (header == 0) { lines++; bytes += strlen( buf ); } fputs( buf, tempfile ); } #ifndef RMAIL /* copy stdin to tempfile, counting content lines and bytes */ /* get sequence number */ mkfilename( mfilename, home, SIGFILE ); if (debuglevel > 4) fprintf( stderr, "pcmail: opening sigfile %s\n", mfilename ); mailfile = FOPEN( mfilename, "r", 't' ); if (mailfile != (FILE *)NULL) { fputs( "\n--\n", tempfile ); while (fgets( buf, 512, mailfile ) != (char *)NULL) { lines++; bytes += strlen( buf ); fputs( buf, tempfile ); } fclose( mailfile ); } #endif fclose( tempfile ); if ( debuglevel > 4 ) { fprintf( stderr, "pcmail: stdin copied to tmp %ld %ld\n", bytes, lines ); fprintf( stderr, "pcmail: args %d\n", argc ); } /* loop on args, copying to appropriate postbox, do remote only once remote checking is done empirically, could be better */ remotes[0] = '\0'; #ifndef RMAIL if ( strcmp( argv[1], "-s" ) == SAME ) { argv++;argv++; argc--;argc--; if ( argc == 0 ) return( -1 ); strcpy( Subject, *argv ); } #endif argcount = argc; argvec = argv; while (--argcount > 0) { argvec++; if ( debuglevel > 5 ) fprintf( stderr, "pcmail: arg# %d\ %s\n", argcount, *argvec ); if ( (strchr( *argvec, '!' ) != SAME) || (strchr( *argvec, '@' ) != SAME) || (strchr( *argvec, '%' ) != SAME) ) { if ( debuglevel > 5 ) fprintf( stderr, "pcmail: send to remote\n" ); s1 = strlen( remotes ); s2 = strlen( *argvec ); /* can we cram one more address on line */ if ( s1 > 0 && (s1 + s2 + 1) > 128 ) { /* dump it then, to bad */ sendone( argc, argv, remotes, TRUE ); remotes[0] = '\0'; } /* add *arvgvec to list of remotes */ strcat( remotes, " " ); strcat( remotes, *argvec ); } else { if ( debuglevel > 5 ) fprintf( stderr, "pcmail: calling sendone %s\n", *argvec ); sendone( argc, argv, *argvec, FALSE ); } } /* dump remotes if necessary */ if ( strlen( remotes ) > 0 ) sendone( argc, argv, remotes, TRUE ); #ifndef RMAIL mkfilename( mailsent, home, COPYFILE ); if ( debuglevel > 4 ) fprintf( stderr, "pcmail: copfile = %s\n", mailsent ); sendone( argc, argv, mailsent, FALSE ); #endif unlink( tfilename ); chdir( mcurdir ); exit(0); } char fpat1[] = "%c.%.7s%04ld"; char fpat2[] = "S %s %s %s - %s 0666 %s"; /* sendone copies file plus headers to appropriate postbox NB. we do headers here to allow flexibility later, for example in being able to do bcc, per host service processing etc. */ sendone( argc, argv, address, remote ) char **argv; int argc; char *address; { register char *cp; char icfilename[32]; /* local C. copy file */ char ixfilename[32]; /* local X. xqt file */ char idfilename[32]; /* local D. data file */ char rxfilename[32]; /* remote X. xqt file */ char rdfilename[32]; /* remote D. data file */ char tmfilename[32]; /* temporary storage */ if ( remote ) { /* sprintf all required file names */ sprintf( tmfilename, fpat1, 'C', mailserv, sequence ); importpath( icfilename, tmfilename ); sprintf( tmfilename, fpat1, 'D', mailserv, sequence ); importpath( idfilename, tmfilename ); sprintf( tmfilename, fpat1, 'D', nodename, sequence ); importpath( ixfilename, tmfilename ); sprintf( rdfilename, fpat1, 'D', nodename, sequence ); sprintf( rxfilename, fpat1, 'X', nodename, sequence ); } else { /* postbox file name */ if ( index( address, SEPCHAR ) == (char *)NULL ) mkfilename( idfilename, maildir, address ); else strcpy( idfilename, address ); } if ( debuglevel > 5 ) fprintf( stderr, "pcmail: sendone: %s\n", idfilename ); if ( remote == FALSE ) { if ( debuglevel > 5 ) fprintf( stderr, "pcmail: sendone: check for remote\n" ); /* check for forwarding */ if ( (mailfile = FOPEN( idfilename, "r", 'b' )) != (FILE *)NULL ) { cp = fgets( buf, BUFSIZ, mailfile ); fclose( mailfile ); if (cp != (char *)NULL) if (strncmp( buf, FORWARD, 10 ) == 0) { strcpy( buf, buf+11 ); return( sendone( argc, argv, buf, FALSE ) ); } } } /* open mailfile */ if ( (mailfile = FOPEN( idfilename, "a", 'b' )) == (FILE *)NULL ) { fprintf( stdout, "pcmail: cannot append to %s\n", idfilename ); return( 0 ); } if ( debuglevel > 5 ) fprintf( stderr, "pcmail: append to mailfile\n" ); tloc = time( (long *)NULL ); thetime = ctime(&tloc); (void)strcpy(chartime, thetime); /* make our own copy */ thetime = chartime; /* and work with our own copy */ thetime[strlen(thetime)-1] = '\0'; #ifdef RMAIL fprintf( mailfile, "From uucp %s", thetime ); fputc( '\012', mailfile ); fprintf( mailfile, "Received: by %s (pcmail) %s", domain, thetime ); fputc( '\012', mailfile ); #else RMAIL fprintf( mailfile, "From %s %s", mailbox, thetime ); if ( remote ) fprintf( mailfile, " remote from %s", nodename ); fputc( '\012', mailfile ); fprintf( mailfile, "Received: by %s (pcmail) %s", domain, thetime ); fputc( '\012', mailfile ); fprintf( mailfile, "Date: %s", thetime ); fputc( '\012', mailfile ); /* add Date:, From: and Message-ID: headers */ fprintf( mailfile, "From: %s <%s@%s>", name, mailbox, domain ); fputc( '\012', mailfile ); fprintf( mailfile, "Message-ID: <%ld@%s>", sequence, domain ); fputc( '\012', mailfile ); /* add To: headers */ while (--argc > 0) { fprintf( mailfile, "To: %s", *++argv ); fputc( '\012', mailfile ); } if ( strlen( Subject ) > 0 ) { fprintf( mailfile, "Subject: %s", Subject ); fputc( '\012', mailfile ); } #ifdef PCMAIL /* add Message-Lines: and Content-Length: headers */ fprintf( mailfile, "X-Message-Lines: %ld", lines ); fputc( '\012', mailfile ); fprintf( mailfile, "Content-Length: %ld", bytes ); fputc( '\012', mailfile ); #endif PCMAIL #endif RMAIL /* copy tempfile to postbox file */ if (debuglevel > 4) fprintf( stderr, "pcmail: copy tempfile %s to %s\n", tfilename, idfilename ); tempfile = FOPEN( tfilename, "r", 'b' ); if ( tempfile == (FILE *)NULL) { fprintf( stdout, "pcmail: can't re-open %s\n", tfilename ); return( 0 ); } while (fgets( buf, 512, tempfile ) != (char *)NULL) { if ( strncmp( buf, "From ", 5 ) == 0 ) fputc( '>', mailfile ); cp = &buf[ strlen(buf)-1 ]; if ( *cp == '\n' ) *cp = '\0'; fputs( buf, mailfile ); fputc( '\012', mailfile ); } /* close files */ fclose( mailfile ); fclose( tempfile ); /* all done unless going to remote via uucp */ /* must create the job control files */ if ( remote == TRUE ) { /* create remote X xqt file */ mailfile = FOPEN( ixfilename, "w", 'b' ); if (mailfile == (FILE *)NULL) { fprintf( stdout, "pcmail: cannot append to %s\n", ixfilename ); return( 0 ); } fprintf( mailfile, "U %s %s", uucp, nodename ); fputc( '\012', mailfile ); fprintf( mailfile, "F %s", rdfilename ); fputc( '\012', mailfile ); fprintf( mailfile, "I %s", rdfilename ); fputc( '\012', mailfile ); fprintf( mailfile, "C rmail %s", address ); fputc( '\012', mailfile ); fclose( mailfile ); /* create local C copy file */ mailfile = FOPEN( icfilename, "w", 't' ); if (mailfile == (FILE *)NULL) { fprintf( stdout, "pcmail: cannot append to %s\n", icfilename ); return( 0 ); } fprintf( mailfile, fpat2, idfilename, rdfilename, uucp, idfilename, uucp ); fputc( '\012', mailfile ); fprintf( mailfile, fpat2, ixfilename, rxfilename, uucp, ixfilename, uucp ); fputc( '\012', mailfile ); fclose( mailfile ); } /* if ( remote == TRUE ) */ return( 1 ); } #ifndef AMIGA #ifdef RMAIL rnews(argc, argv) int argc; char *argv[]; { struct tm *thetm; char filename[132]; char format[128]; FILE *f; char buf[BUFSIZ]; static int count = 0; tloc = time( (long *)NULL ); thetime = ctime(&tloc); tloc = time( (long *)NULL ); thetm = localtime( &tloc ); /* mkfilename( format, spooldir, NEWSDIR ); */ sprintf( filename, NEWSDIR, thetm->tm_year % 100, thetm->tm_mon, thetm->tm_mday, thetm->tm_hour, thetm->tm_min, thetm->tm_sec, count ); count++; if ( debuglevel > 5 ) fprintf( stderr, "rnews: %s\n", filename ); if ( (f = FOPEN( filename, "w", 't' )) == (FILE *)NULL ) { fprintf( stderr, "rnews: can't open %s %d\n", filename, errno ); return( -1 ); } while ( fgets( buf, BUFSIZ, stdin ) != (char *)NULL ) fputs( buf, f ); fclose( f ); } #endif RMAIL #endif AMIGA