home *** CD-ROM | disk | FTP | other *** search
- /*--------------------------------------------------------------------*/
- /* d e l i v e r . c */
- /* */
- /* UUPC/extended mail delivery subroutines */
- /*--------------------------------------------------------------------*/
-
- /*--------------------------------------------------------------------*/
- /* Embedded Japanese support provided by Kenji Rikitake */
- /* 28-AUG-1991 */
- /* */
- /* On Japanese support: */
- /* */
- /* Japanese MS-DOS uses a 2byte Kanji (Japanese ideogram) code */
- /* called "Shift-JIS". This cannot be delivered via SMTP since */
- /* Shift-JIS maps its first byte from 0x80-0x9f and 0xe0-0xfc. */
- /* JUNET requests all hosts to send Kanji in a 7bit subset of */
- /* ISO2022. This is commonly called "JIS 7bit". */
- /* */
- /* To provide Japanese functionality, you need to convert all */
- /* remote delivery messages to JIS 7bit, and all local delivery */
- /* messages to Shift-JIS. */
- /*--------------------------------------------------------------------*/
-
- /*--------------------------------------------------------------------*/
- /* Use a complex beep upon mail delivery if way to control the */
- /* speaker is available; if using MS C 6.0 under DOS, we can't */
- /* so don't try */
- /*--------------------------------------------------------------------*/
-
- #ifdef __TURBOC__
- #define SMARTBEEP
- #endif
-
- #ifdef FAMILYAPI
- #define SMARTBEEP
- #endif
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <io.h>
- #include <ctype.h>
- #include <sys/types.h>
- #include <string.h>
- #include <process.h>
-
- #ifdef __TURBOC__
- #include <dos.h>
- #endif
-
- #ifdef FAMILYAPI
- #include <os2.h>
- #endif
-
- #include "lib.h"
- #include "address.h"
- #include "deliver.h"
- #include "expath.h"
- #include "getseq.h"
- #include "kanjicnv.h"
- #include "hlib.h"
- #include "hostable.h"
- #include "import.h"
- #include "pushpop.h"
- #include "security.h"
- #include "usertabl.h"
-
- #ifdef SMARTBEEP
- #include "ssleep.h"
- #endif
-
- /*--------------------------------------------------------------------*/
- /* Define current file name for panic() and printerr() */
- /*--------------------------------------------------------------------*/
-
- currentfile();
-
- /*--------------------------------------------------------------------*/
- /* Internal prototypes */
- /*--------------------------------------------------------------------*/
-
- static size_t DeliverLocal( const char *input, /* Input file name */
- char *user, /* Target address */
- boolean validate); /* Validate/forward
- local mail */
-
- static void trumpet( const char *tune);
-
- static size_t DeliverRemote( const char *input, /* Input file name */
- const char *address, /* Target address */
- const char *path);
-
- static size_t DeliverGateway( const char *input,
- const char *user,
- const char *node,
- const struct HostTable *hostp);
-
- static int CopyData( const boolean remotedelivery,
- const char *input,
- FILE *mbox);
-
- /*--------------------------------------------------------------------*/
- /* Global (set by rmail.c) for number of hops this mail has seen */
- /*--------------------------------------------------------------------*/
-
- INTEGER hops = 0;
-
- boolean remoteMail = FALSE;
-
- char *ruser = NULL;
- char *rnode = NULL;
-
- /*--------------------------------------------------------------------*/
- /* D e l i v e r */
- /* */
- /* Deliver mail to one user */
- /*--------------------------------------------------------------------*/
-
- size_t Deliver( const char *input, /* Input file name */
- char *address, /* Target address */
- boolean validate) /* Validate/forward
- local mail */
- {
- char node[MAXADDR];
- char path[MAXADDR];
- char user[MAXADDR];
- char *token;
- struct HostTable *hostp;
-
- if (ruser == NULL)
- {
- sprintf(path,"%s!%s", fromnode, fromuser);
- user_at_node(path, path, node, user);
- ruser = strdup( user );
- rnode = strdup( node );
- }
-
- user_at_node(address, path, node, user);
-
- /*--------------------------------------------------------------------*/
- /* Handle local delivery */
- /*--------------------------------------------------------------------*/
-
- if (equal(path, nodename)) /* Local node? */
- {
- if (equal(nodename, node)) /* Really the local node? */
- return DeliverLocal( input, user, validate ); /* Yes! */
- else {
- printmsg(0,"Mail for \"%s\" via \"%s\" has no \
- delivery route, delivering to postmaster %s",
- address, path , postmaster);
- return Deliver( input, postmaster, TRUE);
- } /* else */
- } /* if */
-
- /*--------------------------------------------------------------------*/
- /* Do we need loop protection? */
- /*--------------------------------------------------------------------*/
-
- if (hops > maxhops)
- {
- printmsg(0,
- "Mail for \"%s\" via \"%s\" has exceeded hop \
- limit of %d, delivering to postmaster %s",
- address, path , maxhops, postmaster);
- return Deliver( input, postmaster, TRUE);
- }
-
- /*--------------------------------------------------------------------*/
- /* Deliver to a gateway if needed */
- /*--------------------------------------------------------------------*/
-
- hostp = checkname( path );
- if ( (hostp != BADHOST) && (hostp->hstatus == gatewayed))
- return DeliverGateway( input, user, node, hostp );
-
- /*--------------------------------------------------------------------*/
- /* Deliver mail to a system directory connected to us */
- /*--------------------------------------------------------------------*/
-
- if (equal(path,node)) /* Directly connected system? */
- return DeliverRemote( input, user, path); /* Yes */
-
- /*--------------------------------------------------------------------*/
- /* Default delivery; strip any this node and the directly */
- /* connected system from the address, then deliver to the next */
- /* hop on the route */
- /*--------------------------------------------------------------------*/
-
- strcpy(node,address);
- token = strtok(node,"!"); /* Get first host in path */
- if (equal( HostAlias(token), nodename)) /* Local system? */
- {
- token = strtok(NULL,""); /* Yes --> Get rest of addr */
- strcpy(address, token); /* Use it for address */
- token = strtok(token,"!"); /* Get next host in path */
- } /* if */
-
- if (equal( HostAlias(token), path )) /* Next system? */
- {
- token = strtok(NULL,""); /* Yes --> Get rest of addr */
- strcpy(address, token); /* Use it for address */
- } /* if */
-
- if (!strpbrk(address,"!@")) /* Any host delimiters? */
- { /* No --> Check for % routing */
- token = strrchr(address,'%'); /* Get last percent sign */
- if (token != NULL)
- *token = '@'; /* Make it an RFC-822 address */
- else
- printmsg(0,"Deliver: Cannot find node in \"%s\"",
- address); /* That's odd, it should not */
- /* be a local address! */
- } /* if */
-
- return DeliverRemote( input, address, path );
-
- } /* Deliver */
-
- /*--------------------------------------------------------------------*/
- /* D e l i v e r L o c a l */
- /* */
- /* Handle local delivery, including optional forwarding */
- /*--------------------------------------------------------------------*/
-
- static size_t DeliverLocal( const char *input,
- /* Input file name */
- char *user, /* Target address */
- boolean validate) /* TRUE = validate,
- forward user's mail */
- {
- char mboxname[FILENAME_MAX];
- FILE *mbox;
- char buf[BUFSIZ];
- char command[BUFSIZ];
- struct UserTable *userp;
- int delivered = 0;
- boolean announce = FALSE;
-
- /*--------------------------------------------------------------------*/
- /* If the parameter is the postmaster, use the configuration */
- /* defined value for the postmaster */
- /*--------------------------------------------------------------------*/
-
- if (equali(user, POSTMASTER))
- user = postmaster;
-
- /*--------------------------------------------------------------------*/
- /* Validate user id and check for forwarding */
- /*--------------------------------------------------------------------*/
-
- if (validate)
- {
- validate = strcmp( postmaster , user);
- /* Don't loop delivering to postmast*/
- userp = checkuser(user); /* Locate user id in host table */
- if ( userp == BADUSER ) /* Invalid user id? */
- { /* Yes --> Dump in trash bin */
- printmsg(0,
- "\"%s\" is an invalid user, delivering to %s",
- user, postmaster);
- return DeliverLocal( input, postmaster, validate);
- } /* if */
-
-
- /*--------------------------------------------------------------------*/
- /* The user id validated; handle the mail */
- /*--------------------------------------------------------------------*/
-
- mkfilename(mboxname, userp->homedir, DOTFORWARD);
- mbox = FOPEN(mboxname, "r", TEXT);
-
- if (mbox == NULL ) /* The .forward file exists? */
- announce = TRUE; /* No --> Fall through */
- else {
- while( fgets( buf , BUFSIZ , mbox) != NULL )
- {
- char c = *buf;
- if ( buf[ strlen(buf) - 1 ]== '\n')
- buf[ strlen(buf) - 1 ] = '\0';
- printmsg(8,"Forwarding to \"%s\"", buf);
- if ( isalpha( c ) && (buf[1] == ':')) /* Drive name? */
- c = ':'; /* Yes --> special case */
-
- switch(*buf)
- {
- case '\0':
- break; /* Empty line, ignore */
-
- case '|': /* Pipe mail into a command */
- {
- long here = ftell(mbox);
- fclose(mbox);
- sprintf(command , "%s < %s", &buf[1], input);
- printmsg(1,"Executing \"%s\" in %s",
- command, userp->homedir);
- PushDir( userp->homedir );
- system(command); /* FIX THIS */
- PopDir();
- delivered += 1;
- mbox = FOPEN(mboxname, "r", TEXT);
- fseek( mbox, here, SEEK_SET);
- break;
- } /* case */
-
- case '\\': /* Deliver without forwarding */
- delivered += Deliver( input, &buf[1], FALSE );
- announce = TRUE;
- break;
-
- case '/': /* Save in absolute path name */
- case ':':
- case '~':
- if (expand_path(buf, NULL, userp->homedir,
- E_mailext) == NULL )
- {
- printmsg(0,
- "Invalid path in filename, delivering to %s",
- user, postmaster);
- return DeliverLocal( input, postmaster, validate );
- }
- else
- delivered += DeliverLocal( input, buf, FALSE );
- announce = TRUE;
- break;
-
- default: /* Deliver normally */
- delivered += Deliver( input, buf, validate );
- } /* switch */
- } /* while */
-
- fclose(mbox);
-
- if (announce) /* Did we deliver mail locally? */
- trumpet( userp->beep); /* Yes --> Inform the user */
- return delivered;
-
- } /* if */
-
- } /* if (validate) */
-
- /*--------------------------------------------------------------------*/
- /* The user is valid (or not validated) and not forwarded */
- /*--------------------------------------------------------------------*/
-
- if ((*user == '/') || (isalpha( *user ) && user[1] == ':'))
- /* Absolute path from recursive call? */
- strcpy(mboxname, user); /* Yes --> Use it as-is */
- else
- mkmailbox(mboxname, user);
- /* No --> Build normal name */
-
- printmsg(1,"Delivering mail from %s%s%s to %s",
- ruser,
- remoteMail ? "@" : "",
- remoteMail ? rnode : "",
- user );
-
- if ( announce )
- trumpet( userp->beep); /* Local delivery, inform the user */
-
- mbox = FOPEN( mboxname , "a", TEXT );
- if (mbox == NULL )
- {
- printerr(mboxname);
- printmsg(0,"Cannot open mailbox \"%s\" for output",
- mboxname);
- }
-
- if (!isatty(fileno(mbox)))
- fputs(MESSAGESEP,mbox); /* Write separator line */
-
- return CopyData( FALSE, input , mbox );
-
- } /* DeliverLocal */
-
- /*--------------------------------------------------------------------*/
- /* t r u m p e t */
- /* */
- /* Trumpet the arrival of remote mail to a local user */
- /*--------------------------------------------------------------------*/
-
- static void trumpet( const char *tune)
- {
- #ifdef SMARTBEEP
- char buf[BUFSIZ];
- char *token = buf;
- size_t tone, duration;
- #endif
-
- if ((tune == NULL) || !remoteMail) /* Should we announce? */
- return; /* No --> Return quietly (literally) */
-
- /*--------------------------------------------------------------------*/
- /* We are to announce the arrival of the mail */
- /*--------------------------------------------------------------------*/
-
- #ifdef SMARTBEEP
- strcpy(buf,tune); /* Save the data */
-
- while( (token = strtok( token, ",")) != NULL)
- {
- tone = (size_t) atoi(token);
- token = strtok( NULL, ",");
- duration = (token == NULL) ? 500 : (size_t) atoi(token);
- #ifdef __TURBOC__
- if (tone == 0)
- nosound();
- else
- sound( tone );
- ddelay( duration );
- #else
- if (tone == 0)
- ddelay(duration);
- else
- DosBeep( tone, duration );
- #endif /* SMARTBEEP */
- token = NULL; /* Look at next part of string */
- } /* while */
-
- #ifdef __TURBOC__
- nosound();
- #endif
- #else
-
- /*--------------------------------------------------------------------*/
- /* We cannot play the requested tune; just beep at the user */
- /*--------------------------------------------------------------------*/
-
- fputc('\a', stdout);
- #endif /* SMARTBEEP */
-
- } /* trumpet */
-
- /*--------------------------------------------------------------------*/
- /* D e l i v e r G a t e w a y */
- /* */
- /* Deliver mail via a gateway program */
- /*--------------------------------------------------------------------*/
-
- static size_t DeliverGateway( const char *input,
- const char *user,
- const char *node,
- const struct HostTable *hostp)
- {
- char command[BUFSIZ];
-
- /*--------------------------------------------------------------------*/
- /* Format the command and tell the user what we're going to do */
- /*--------------------------------------------------------------------*/
-
- sprintf(command , "%s %s %s %s < %s",
- hostp->via, /* Program to perform forward */
- hostp->hostname, /* Nominal host routing via */
- node , /* Final destination system */
- user, /* user on "node" for delivery*/
- input); /* The data to forward */
-
- printmsg(1,
- "Gatewaying mail from %s@%s to %s@%s via %s using \"%s\"",
- ruser, rnode, user, node, hostp->hostname, hostp->via);
- printmsg(3,"DeliverGateway: %s",command);
-
- /*--------------------------------------------------------------------*/
- /* Run the command and return caller with count of mail delivered */
- /*--------------------------------------------------------------------*/
-
- system(command);
- return 1;
-
- } /* DeliveryGateway */
-
- /*--------------------------------------------------------------------*/
- /* D e l i v e r R e m o t e */
- /* */
- /* Queue mail for delivery on another system via UUCP */
- /*--------------------------------------------------------------------*/
-
- static size_t DeliverRemote( const char *input, /* Input file name */
- const char *address, /* Target address */
- const char *path)
- {
- static char *spool_fmt = SPOOLFMT; /* spool file name */
- static char *dataf_fmt = DATAFFMT;
- static char *send_cmd = "S %s %s %s - %s 0666\n";
- static long seqno = 0;
- static char *SavePath = NULL;
- FILE *stream; /* For writing out data */
- static char everyone[500]; /* 512, with room for "rmail " */
-
- char msfile[FILENAME_MAX]; /* MS-DOS format name of files */
- char msname[22]; /* MS-DOS format w/o path name */
-
- char tmfile[15]; /* Call file, UNIX format name */
- static char ixfile[15]; /* eXecute file for remote system,
- UNIX format name for local system */
- static char idfile[15]; /* Data file, UNIX format name */
- static char rdfile[15]; /* Data file name on remote system,
- UNIX format */
- static char rxfile[15]; /* Remote system UNIX name of eXecute
- file */
-
- printmsg(1,"Spooling mail from %s%s%s to %s via %s",
- ruser,
- remoteMail ? "@" : "",
- remoteMail ? rnode : "",
- address ,
- path);
-
- /*--------------------------------------------------------------------*/
- /* Create the UNIX format of the file names we need */
- /*--------------------------------------------------------------------*/
-
- if ((seqno == 0) ||
- (SavePath == NULL) ||
- !equal(SavePath, path) ||
- ((int) (strlen(everyone) + strlen(address) + 2) > (int) sizeof everyone))
- {
- char *seq;
- seqno = getseq();
- seq = JobNumber( seqno );
- if (SavePath != NULL )
- {
- free(SavePath);
- SavePath = NULL;
- } /* if */
- sprintf(tmfile, spool_fmt, 'C', path, 'A' , seq);
- sprintf(idfile, dataf_fmt, 'D', nodename , seq, 'd');
- sprintf(rdfile, dataf_fmt, 'D', nodename , seq, 'r');
- sprintf(ixfile, dataf_fmt, 'D', nodename , seq, 'e');
- sprintf(rxfile, dataf_fmt, 'X', nodename , seq, 'r');
- strcpy(everyone,address);
- } /* if */
- else {
- strcat(everyone," ");
- strcat(everyone,address);
- } /* else */
-
- /*--------------------------------------------------------------------*/
- /* create remote X (xqt) file */
- /*--------------------------------------------------------------------*/
-
- importpath( msname, ixfile, path);
- mkfilename( msfile, spooldir, msname);
-
- stream = FOPEN(msfile, "w", BINARY);
- if ( stream == NULL )
- {
- printerr(msfile);
- printmsg(0, "DeliverRemote: cannot open X file %s", msfile);
- return 0;
- } /* if */
-
-
- fprintf(stream, "R %s %s\nU %s %s\nF %s\nI %s\nC rmail %s\n",
- ruser, rnode,
- (equal(HostAlias( nodename ) , fromnode ) ||
- equal(HostAlias( domain ) , fromnode )) ?
- fromuser : "uucp" , nodename,
- rdfile, rdfile, everyone);
- fclose(stream);
-
- if (SavePath != NULL)
- return 1;
-
- /*--------------------------------------------------------------------*/
- /* Create the data file with the mail to send to the remote system */
- /*--------------------------------------------------------------------*/
-
- importpath(msname, idfile, path);
- mkfilename( msfile, spooldir, msname);
-
- stream = FOPEN(msfile, "w", BINARY);
- if (stream == NULL )
- {
- printerr(msfile);
- printmsg(0,
- "DeliverRemote: Cannot open spool file \"%s\" for output",
- msfile);
- return 0;
- }
-
- if (!CopyData( TRUE, input , stream ))
- {
- remove( msfile );
- return 0;
- }
-
- /*--------------------------------------------------------------------*/
- /* create local C (call) file */
- /*--------------------------------------------------------------------*/
-
- importpath( msname, tmfile, path);
- mkfilename( msfile, spooldir, msname);
-
- stream = FOPEN(msfile, "w", TEXT);
- if (stream == NULL)
- {
- printerr( msname );
- printmsg(0, "DeliverRemote: cannot open C file %s", msfile);
- return 0;
- }
-
- fprintf(stream, send_cmd, idfile, rdfile,
- (equal(HostAlias( nodename ) , fromnode ) ||
- equal(HostAlias( domain ) , fromnode )) ?
- fromuser : "uucp" ,
- idfile);
- fprintf(stream, send_cmd, ixfile, rxfile,
- (equal(HostAlias( nodename ) , fromnode ) ||
- equal(HostAlias( domain ) , fromnode )) ?
- fromuser : "uucp" ,
- ixfile);
- fclose(stream);
-
- if (bflag[F_MULTI]) /* Deliver to multiple users at once? */
- SavePath = strdup(path); /* Yes --> Save routing info */
-
- return 1;
- } /* DeliverRemote */
-
- /*--------------------------------------------------------------------*/
- /* C o p y D a t a */
- /* */
- /* Copy data into its final resting spot */
- /*--------------------------------------------------------------------*/
-
- static int CopyData( const boolean remotedelivery,
- const char *input,
- FILE *dataout)
- {
- FILE *datain = FOPEN(input, "r", TEXT);
- char buf[BUFSIZ];
- int column = 0;
- boolean success = TRUE;
-
- int (*put_string) (char *, FILE *) = (int (*)(char *, FILE *)) fputs;
- /* Assume no Kanji translation needed */
-
- /*--------------------------------------------------------------------*/
- /* Verify the input opened */
- /*--------------------------------------------------------------------*/
-
- if (datain == NULL)
- {
- printerr(input);
- printmsg(0,"Unable to open input file \"%s\"", input);
- fclose(dataout);
- return 0;
- } /* datain */
-
- /*--------------------------------------------------------------------*/
- /* When we do the From line, we also determine if we must */
- /* translate the data. Note that the default is initialized to */
- /* fputs() above. */
- /* */
- /* If Kanji is not enabled, don't translate it */
- /* */
- /* If local mail queued for local delivery, the data is already */
- /* in Shift JIS, so don't translate it. */
- /* */
- /* If remote mail is queued for remote delivery, the data is */
- /* already in JIS 7bit, so don't translate it. */
- /* */
- /* If delivering remote mail locally, translate to Shift JIS */
- /* */
- /* If delivering local mail remotely, translate to JIS 7 bit */
- /*--------------------------------------------------------------------*/
-
- /*--------------------------------------------------------------------*/
- /* Generate a FROM line */
- /*--------------------------------------------------------------------*/
-
- switch( (int) remoteMail * 2 + (int) remotedelivery )
- {
- case 3: /* Remote sender, remote delivery */
- strcpy( buf, fromuser );
- strtok( buf, "!"); /* Get first host in list */
- if ( !equal(HostAlias( buf ), fromnode ))
- /* Host already in list? */
- { /* No --> Insert it */
- fprintf(dataout, "From %s!%s %s remote from %s\n",
- fromnode,
- fromuser,
- now,
- nodename);
- break;
- }
-
- /*--------------------------------------------------------------------*/
- /* If the name to add and the first name in the path are the */
- /* same, fall through to case 2, which doesn't add the same */
- /* name on twice */
- /* */
- /* Note: For the Kanji translation we re-check the */
- /* remoteDelivery flag since we do the fall through from above. */
- /*--------------------------------------------------------------------*/
-
- case 2: /* Remote sender, local delivery */
- if ( bflag[ F_KANJI ] && !remotedelivery )
- /* Kanji from remote node? */
- put_string = (int (*)(char *, FILE *)) fputs_shiftjis;
- /* Yes --> Translate it */
-
- fprintf(dataout, "From %s %s remote from %s\n",
- fromuser,
- now,
- fromnode);
- break;
-
- case 1: /* Local sender, remote delivery */
- if ( bflag[F_KANJI]) /* Translation enabled? */
- put_string = (int (*)(char *, FILE *)) fputs_jis7bit;
- /* Translate into 7 bit Kanji */
-
- column = strlen(domain) - 5;
- if ((column > 0) && equali(&domain[column],".UUCP"))
- /* UUCP domain? */
- fprintf(dataout, "From %s %s remote from %s\n",
- fromuser, /* Yes --> Use simple address */
- now,
- nodename);
- else /* No --> Use domain address */
- fprintf(dataout, "From %s!%s %s remote from %s\n",
- domain,
- fromuser,
- now,
- nodename);
- break;
-
- case 0: /* Local sender, local delivery */
- fprintf(dataout, "From %s %s\n",
- fromuser,
- now);
- break;
-
- } /* switch */
-
- /*--------------------------------------------------------------------*/
- /* Loop to copy the data */
- /*--------------------------------------------------------------------*/
-
- while (fgets(buf, BUFSIZ, datain) != NULL)
- {
- if ((*put_string)(buf, dataout) == EOF) /* I/O error? */
- {
- printerr("output");
- printmsg(0,"I/O error on \"%s\"", "output");
- fclose(dataout);
- return 0;
- } /* if */
- } /* while */
-
- /*--------------------------------------------------------------------*/
- /* Close up shop and return */
- /*--------------------------------------------------------------------*/
-
- if (ferror(datain)) /* Clean end of file on input? */
- {
- printerr(input);
- clearerr(datain);
- success = FALSE;
- }
-
- fclose(datain);
- fclose(dataout);
- return success;
- } /* CopyData */
-