Logo Search packages:      
Sourcecode: filter version File versions  Download package

actions.c

static char rcsid[] ="@(#)$Id: actions.c,v 5.8 1993/08/03 19:28:39 syd Exp $";

/*******************************************************************************
 *  The Elm Mail System  -  $Revision: 5.8 $   $State: Exp $
 *
 *                Copyright (c) 1988-1992 USENET Community Trust
 *                Copyright (c) 1986,1987 Dave Taylor
 *******************************************************************************
 * Bug reports, patches, comments, suggestions should be sent to:
 *
 *    Philip Brown    filter@bolthole.com
 *
 *******************************************************************************
 * $Log: actions.c,v $
 * Revision 5.8  1993/08/03  19:28:39  syd
 * Elm tries to replace the system toupper() and tolower() on current
 * BSD systems, which is unnecessary.  Even worse, the replacements
 * collide during linking with routines in isctype.o.  This patch adds
 * a Configure test to determine whether replacements are really needed
 * (BROKE_CTYPE definition).  The <ctype.h> header file is now included
 * globally through hdrs/defs.h and the BROKE_CTYPE patchup is handled
 * there.  Inclusion of <ctype.h> was removed from *all* the individual
 * files, and the toupper() and tolower() routines in lib/opt_utils.c
 * were dropped.
 * From: chip@chinacat.unicom.com (Chip Rosenthal)
 *
 * Revision 5.7  1993/08/03  19:07:58  syd
 * Removed bogus string lockfile.
 * From: Jan.Djarv@sa.erisoft.se (Jan Djarv)
 *
 * Revision 5.6  1993/04/21  01:25:45  syd
 * I'm using Elm 2.4.21 under Linux.  Linux has no Bourne shell.  Each
 * user installs her favorite shell as /bin/sh.  I use Bash 1.12.
 *
 * Elm invokes the mail transport (MTA) like so:
 *
 *    ( ( MTA destination; rm -f tempfile ) & ) < tempfile &
 *
 * This form of command doesn't work with my Bash, in which any command
 * which is backgrounded ("&") gets its stdin attached to /dev/null.
 *
 * The below patch arranges for Elm to call the MTA thusly:
 *
 *    ( MTA destination <tempfile; rm -f tempfile ) &
 * From: decwrl!uunet.UU.NET!fin!chip (Chip Salzenberg)
 *
 * Revision 5.5  1993/01/27  19:40:01  syd
 * I implemented a change to filter's default verbose message format
 * including %x %X style date and time along with username
 * From: mark@drd.com (Mark Lawrence)
 *
 * Revision 5.4  1993/01/20  03:37:16  syd
 * Nits and typos in the NLS messages and corresponding default messages.
 * From: dwolfe@pffft.sps.mot.com (Dave Wolfe)
 *
 * Revision 5.3  1992/12/24  19:22:05  syd
 * Quote from the filter of phrase to prevent RFC-822 parsing problems
 * From: Syd via request from Ian Stewartson <istewart@dlvax2.datlog.co.uk>
 *
 * Revision 5.2  1992/12/11  02:16:08  syd
 * remove unreachable return(0) at end of function
 * From: Syd
 *
 * Revision 5.1  1992/10/03  22:18:09  syd
 * Initial checkin as of 2.4 Release at PL0
 *
 *
 ******************************************************************************/


/** RESULT oriented routines *chuckle*.  These routines implement the
    actions that result from either a specified rule being true or from
    the default action being taken.
**/

#include <stdio.h>
#include <pwd.h>
#include <fcntl.h>

#include "defs.h"
#include "filter.h"
#include "utils.h"
#include "s_filter.h"
#include "version.h"
#include "lock.h"


FILE *emergency_local_delivery();
extern char *date_n_user();

/*
 * open pipe to mailer,and (re)send mail we received to given address.
 * ASSUME that global "tmpfilename" is set to name of tmpfile
 * that we have (FILE*)ftmp into.
 * Also assume that caller has done rewind(ftmp);
 *
 * return value suitable for passing to _exit()
 */
int pipe_to_mailer(ftmp, resendflag, address)
FILE *ftmp;
int resendflag;
char *address;
{
      FILE *pipefd;
      char buffer[VERY_LONG_STRING];
      int statusp,in_header = TRUE;

      if (strcmp(sendmail, mailer) == 0)
            sprintf(buffer, "%s %s %s", sendmail, smflags, address);
      else
            sprintf(buffer, "%s %s", mailer, address);


      if ((pipefd = popen(buffer, "w")) == NULL) {
            if (outfptr != NULL){
                  /* log failure */
                  fprintf(outfptr,
                         catgets(elm_msg_cat,
                               FilterSet,FilterPopenFailed,
                               "filter (%s): popen %s failed!\n"),
                         date_n_user(), buffer);
            }

            /* mail the "hard way" */
            sprintf(buffer, "(%s %s %s < %s ) &",
                    sendmail, smflags, address, tmpfilename);
            exit(system(buffer));

      }

      if(resendflag==1){
            /* Strip off any possible leading "From " fake header,
             * then just dump the whole thing to the sendmail pipe
             */
            if(fgets(buffer,SLEN,ftmp)==NULL){
                  return(pclose(pipefd));
            }
            /* We want to ignore first line,
             * but ONLY IF it is the special mbox-added
             *  non-header "From " line
             */
            if(!THE_SAME(buffer,"From ")){
                  fprintf(pipefd,"%s", buffer);
            }
            while (fgets(buffer, SLEN, ftmp) != NULL){
                  fprintf(pipefd,"%s", buffer);
            }
            fflush(pipefd);
            return(pclose(pipefd));
      }

      /* else */
      fprintf(pipefd, "Subject: \"%s\"\n", subject);
      fprintf(pipefd,
            catgets(elm_msg_cat,FilterSet,
                  FilterFromTheFilterOf,
                  "From: \"The Filter of %s@%s\" <%s>\n"), 
            username, hostname, username);
      fprintf(pipefd, "To: %s\n", address);
      fprintf(pipefd,
            catgets(elm_msg_cat,
                  FilterSet,FilterXFilteredBy,
                  "X-Filtered-By: %s\n\n"),
            versionstring);
                
      fprintf(pipefd,
            catgets(elm_msg_cat,
                  FilterSet,FilterBeginMesg,
                  "-- Begin filtered message --\n\n"));

                
      while (fgets(buffer, SLEN, ftmp) != NULL){
            if (already_been_forwarded && in_header)
                  in_header = (strlen(buffer) == 1? 0 : in_header);
            else {
                  /* note the indent! */
                  fprintf(pipefd," %s", buffer);
            }
      }

      fprintf(pipefd,
            catgets(elm_msg_cat,
                  FilterSet,FilterEndMesg,
                  "\n-- End of filtered message --\n"));

      fflush(pipefd);
      return(pclose(pipefd));

      
}

/* This is badly named, because it actually does what should be
 * save_to_mailbox(), as WELL as send email to external users.
 * (It checks and saves locally if local user, otherwise calls
 *  sendmail or whatever mailer was compiled in)
 *
 * fptr is assumed to be a FILE* to the original tmpfile that we dumped
 * stdin to. We dont open it, and we dont close it neither.
 */
mail_message(address, fptr,resendflag)
char *address;
FILE *fptr;
int resendflag; /* if 1, resend without any mangling */
{
      /* Called with an address to send mail to.   For various reasons
       * that are too disgusting to go into herein, we're going to actually
       * open the users mailbox and by hand add this message.  Yech.
       * EXCEPT if the user is somewhere else, then we'll try to use
       * sendmail.
       */

      FILE *mailfptr;
      int  line_count = 0, mailunit, pid, statusp;
      char buffer[VERY_LONG_STRING];

      rewind(fptr);

      if(show_only)
            return 0;


      if (strcmp(address, username) != 0) {     /* mailing to someone else */
          
          if (verbose && ! log_actions_only && outfptr != NULL)
            fprintf(outfptr,
                  catgets(elm_msg_cat,
                        FilterSet,FilterMailingMessage,
                        "filter (%s): Mailing to %s via %s\n"), 
                  date_n_user(), address, mailer);


          if (already_been_forwarded) {   /* potential looping! */
            if (contains(Hfrom, username)) {
            if (outfptr != NULL)
                fprintf(outfptr,
                    catgets(elm_msg_cat,FilterSet,FilterLoopDetected, 
      "filter (%s): Filter loop detected!  Message left in tempfile %s\n"), 
                  date_n_user(), tmpfilename );
              if (outfptr != NULL) fclose(outfptr);

            /* deliberately clean-exit here to ensure tempfile
             * not unlinked
             */
              exit(0);
            }
          }

          /*
           * we do a fork/exec here to prevent evil people
           * from abusing the setgid privileges of filter.
           */
          
          if ( (pid=fork()) > 0 ) /* we're the parent */
            {
                wait(&statusp);
                if (statusp!=0)
                  {
                      fprintf(outfptr,
                            catgets(elm_msg_cat,
                                  FilterSet,FilterBadWaitStat,
                "filter (%s): Command \"%s\" exited with value %d\n"),
                            date_n_user(),buffer,statusp);
                  }
            }
          else if (pid==0) /* we're the child */
            {
                /* use safe permissions */
                
                setuid(user_uid);
                setgid(user_gid);

                _exit(pipe_to_mailer(fptr,resendflag,address));

            }
          else /* fork failed */
            {
              if (outfptr != NULL)
                fprintf(outfptr,
                      catgets(elm_msg_cat,
                            FilterSet,FilterForkFailed,
                "filter (%s): fork of command \"%s\" failed\n"),
                      date_n_user(),buffer);
            }
          
          return 1;           /* YEAH!  Wot a slick program, eh? */
        
      } /* if (strcmp(address, username) != 0) */
        
      /** OTHERWISE it is to the current user... **/

        
      if (!lock()) {

          if (outfptr != NULL) {
            fprintf(outfptr, catgets(elm_msg_cat,FilterSet,
                             FilterCouldntCreateLockFile,
                 "filter (%s): Couldn't create lock file\n"),
                date_n_user());
            fprintf(outfptr, catgets(elm_msg_cat,FilterSet,
                             FilterCantOpenMailBox,
                 "filter (%s): Can't open mailbox %s!\n"),
                date_n_user(), user_mailbox);
          }
          if ((mailfptr = emergency_local_delivery()) == NULL)
            return(1);
      }
      else {
            if (verbose && ! log_actions_only && outfptr != NULL)
                  fprintf(outfptr,
                        catgets(elm_msg_cat,
                              FilterSet,FilterMailingMessage,
                              "filter (%s): local delivery to %s\n"),
                              date_n_user(), address);

            if ((mailunit = open(user_mailbox,
                      O_APPEND | O_WRONLY | O_CREAT, 0600)) >= 0)
                  mailfptr = fdopen(mailunit, "a");
            else if ((mailfptr = emergency_local_delivery()) == NULL)
                  return(1);
      }

      while (fgets(buffer, sizeof(buffer), fptr) != NULL) {
#ifdef ESCAPE_FROM_LINE
            line_count++;
            if (THE_SAME(buffer, "From ") && line_count > 1){
                  fprintf(mailfptr, ">");
            }
#endif
            fputs(buffer, mailfptr);
      }

      /* add a little mailbox message separator. */
      fputs("\n", mailfptr);

      fclose(mailfptr);
      unlock();         /* blamo or not?  Let it decide! */

      return 0;

}


/* save message to a folder, one way or another.
 * But we may need to do special things with GID before starting the actual
 * save, not to mention "~" expension.
 * We may even fork(). 
 *
 * tmpfptr must be a FILE* to the temp file we dumped stdin to at start
 * return 0 on okay, non-zero otherwise.
 * Note that the return MAYBE something meaningful, like EX_TEMPFAIL.
 * So caller should keep it as exit status.
 */
int save_message(foldername, tmpfptr)
char *foldername;
FILE *tmpfptr;
{
      /** Save the message in a folder.  Use full file buffering to
          make this work without contention problems **/

      int  gid, pid, statusp, ret;

      /* allow for ~ file names expansion in rules */
      (void) expand_filename(foldername);

      if (verbose && outfptr != NULL)
        fprintf(outfptr, catgets(elm_msg_cat,FilterSet,FilterSavedMessage,
                         "filter (%s): Saving message in folder %s\n"), 
              date_n_user(), foldername);

      if (show_only)
           return(0);

      gid=getgid();
      
      
      if (gid != user_gid) /* then fork */
      {
            
            if ((pid=fork()) > 0) /* we're the parent */
            {
                wait(&statusp);
                return(statusp);
                    
            }
            else if (pid == 0) /* we're the child */
            {
                /*
                 *  we want the file to have
                 *  the user's group id
                 */
                
                ret = setgid(user_gid);
                ret = save_to_folder(foldername,tmpfptr);
                
                _exit(ret);
                
            }
            else /* fork failed */
            {
                fprintf(outfptr,
                      catgets(elm_msg_cat,
                            FilterSet,FilterForkSaveFailed,
                "filter (%s): fork-and-save message failed\n\
\tsaving with current group ID\n"),
                      date_n_user());
                /*
                 * save with the current group id.
                 */
                ret = save_to_folder(foldername,tmpfptr);
                return(ret);
                
            }
      }
      else
      {
            /*
             *  ok to save with current group id.
             */
            ret = save_to_folder(foldername,tmpfptr);
            return(ret);
            
      }
      return(ret); /* not reached, just to make warnings go away*/
}

/* We are definately saving to a FILE now.
 * return 0 on okay, special-email-exit-status otherwise.
 *  (usually EX_TEMPFAIL)
 */
int save_to_folder(foldername,tmpfptr)
char *foldername;
FILE *tmpfptr;
{
      /*
       * this function does the actual work of saving the message
       * in the named folder.
       */
      
      FILE  *folderfptr;
      char  buffer[SLEN];
      int   fdunit, line_count=0;
      
      rewind(tmpfptr);
      fflush(tmpfptr);

      if(!lockfolder(foldername))
      {
            fprintf(outfptr, catgets(elm_msg_cat,FilterSet,
                  FilterCouldntCreateLockFile,
                  "filter (%s): Couldn't create lock file\n"),
                  date_n_user());
            fprintf(outfptr, catgets(elm_msg_cat,FilterSet,
                             FilterCantOpenMailBox,
                  "filter (%s): Can't open mailfolder %s!\n"),
                  date_n_user(), foldername);

            return(75); /* EX_TEMPFAIL */
          
      }
      if ((fdunit = open(foldername,
                   O_APPEND | O_WRONLY | O_CREAT, 0600)) < 0) {
          if (outfptr != NULL)
             fprintf(outfptr, 
                   catgets(elm_msg_cat,
                         FilterSet,FilterCantSaveMessageToFolder,
             "filter (%s): can't save message to requested folder %s!\n"),
                   date_n_user(), foldername);
          return(75); /* EX_TEMPFAIL */
      }
      folderfptr = fdopen(fdunit,"a");
      
      while (fgets(buffer, sizeof(buffer), tmpfptr) != NULL) {
#ifdef ESCAPE_FROM_LINE
            /* "From " used as beginning-of-msg marker, so escape it
             * if it is not actually the first line in the message
             */
            line_count++;
            if((line_count >1) && THE_SAME(buffer, "From ") ){
                  fprintf(folderfptr, ">"); 
            }
#endif
            fputs(buffer, folderfptr);
      }
      
      /*
       * Add two newlines, to ensure that other mailers (which, unlike
       * elm, may only look for \n\nFrom_ as the start-of-message
       * indicator).
       */
      
      fprintf(folderfptr, "\n\n");
      
      fclose(folderfptr);

      unlockfolder(foldername);
      
      return(0);
}

void execute(command, tmpfptr)
char *command;
FILE *tmpfptr;
{
      /** execute the indicated command, feeding as standard input the
          message we have.
      **/

      int pid, statusp;
      char buffer[SLEN];

      rewind(tmpfptr);
      fflush(tmpfptr);

      if (verbose && outfptr != NULL)
        fprintf(outfptr, catgets(elm_msg_cat,FilterSet,FilterExecutingCmd,
             "filter (%s): Executing %s\n"), date_n_user(), command);

      if(show_only){
            return;
      }

      sprintf(buffer, "%s",command);

      if ( (pid=fork()) > 0) /* we're the parent */
      {
            wait(&statusp);
            if (statusp!=0)
            {
              if (outfptr != NULL)
                  fprintf(outfptr,
                        catgets(elm_msg_cat,
                              FilterSet,FilterBadWaitStat,
                              "filter (%s): Command \"%s\" exited with value %d\n"),
                                    date_n_user(),command,statusp);
                  }
                  
            }
      else if (pid==0)/* we're the child */
      {
            int tmpfd;
            /*
             * reset uid/gid to user's uid and gid
             */
            setgid(user_gid);
            setuid(user_uid);

            tmpfd=fileno(tmpfptr);
            close(0);
            dup(tmpfd);

            exit(system(buffer));
      }
      else /* fork() failed */
      {
                  fprintf(outfptr,
                        catgets(elm_msg_cat,
                              FilterSet,FilterForkFailed,
                  "filter (%s): fork of command \"%s\" failed\n"),
                        date_n_user(),command);
      }
            

}

FILE *
emergency_local_delivery()
{
      /** This is called when we can't deliver the mail to the usual
          mailbox in the usual way ...
      **/

      FILE *fptr;
      char  mailbox[SLEN];
      int   mailunit;

      sprintf(mailbox, "%s/%s", home, EMERGENCY_MAILBOX);

      if ((mailunit = open(mailbox, O_APPEND | O_WRONLY | O_CREAT, 0600)) < 0) {
        if (outfptr != NULL)
          fprintf(outfptr, catgets(elm_msg_cat,FilterSet,FilterCantOpenEither,
                         "filter (%s): Can't open %s either!!\n"),
                date_n_user(), mailbox);

        sprintf(mailbox,"%s/%s", home, EMERG_MBOX); 

        if ((mailunit = open(mailbox, O_APPEND | O_WRONLY | O_CREAT, 0600)) < 0) {

          if (outfptr != NULL) {
              fprintf(outfptr, catgets(elm_msg_cat,FilterSet,
                               FilterCantOpenEither,
                         "filter (%s): Can't open %s either!!\n"),
                  date_n_user(), mailbox);
            fprintf(outfptr,catgets(elm_msg_cat,FilterSet,FilterCantOpenAny, 
                  "filter (%s): I can't open ANY mailboxes!  Augh!!\n"),
                   date_n_user());
           }
          
          /* DIE DIE DIE DIE!! */
           leave(catgets(elm_msg_cat,FilterSet,FilterCantOpenAnyLeave,
                     "Cannot open any mailbox"));
         }
         else
           if (outfptr != NULL)
             fprintf(outfptr,catgets(elm_msg_cat,FilterSet,
                             FilterUsingEmergMbox,
                  "filter (%s): Using %s as emergency mailbox\n"),
                   date_n_user(), mailbox);
        }
        else
          if (outfptr != NULL)
            fprintf(outfptr,catgets(elm_msg_cat,FilterSet,
                             FilterUsingEmergMbox,
                  "filter (%s): Using %s as emergency mailbox\n"), 
                  date_n_user(), mailbox);

      fptr = fdopen(mailunit, "a");
      return((FILE *) fptr);
}

Generated by  Doxygen 1.6.0   Back to index