Back to index

courier  0.68.2
outbox.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2002-2009 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 
00006 #if    HAVE_CONFIG_H
00007 #include      "config.h"
00008 #endif
00009 #include      <stdio.h>
00010 #include      <stdlib.h>
00011 #include      <string.h>
00012 #include      <errno.h>
00013 #include      <signal.h>
00014 #include      <ctype.h>
00015 #include      <fcntl.h>
00016 #if    HAVE_UNISTD_H
00017 #include      <unistd.h>
00018 #endif
00019 
00020 #include      "outbox.h"
00021 #include      "imapwrite.h"
00022 
00023 #include      <sys/types.h>
00024 #include      <sys/stat.h>
00025 #if HAVE_SYS_WAIT_H
00026 #include      <sys/wait.h>
00027 #endif
00028 #ifndef WEXITSTATUS
00029 #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
00030 #endif
00031 #ifndef WIFEXITED
00032 #define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
00033 #endif
00034 
00035 /*
00036 ** Is this the magic outbox?
00037 */
00038 
00039 int is_outbox(const char *mailbox)
00040 {
00041        const char *p=getenv("OUTBOX");
00042 
00043        if (strncmp(mailbox, "./", 2) == 0)
00044               mailbox += 2;
00045 
00046        if (p == NULL || *p == 0 || strcmp(p, mailbox))
00047               return (0);
00048 
00049        return (1);
00050 }
00051 
00052 const char *defaultSendFrom()
00053 {
00054        const char *from;
00055 
00056        from=getenv("AUTHADDR");
00057        if (!from || !*from)
00058               from=getenv("AUTHENTICATED");
00059        if (from && !*from)
00060               from=NULL;
00061 
00062        return from;
00063 }
00064 
00065 /*
00066 ** After a message is copied to a folder, mail it, if it's an OUTBOX.
00067 */
00068 
00069 static void errlogger(char *buffer)
00070 {
00071        fprintf(stderr, "ERR: error sending a message, user=%s: %s\n",
00072               getenv("AUTHENTICATED"), buffer);
00073 }
00074 
00075 int check_outbox(const char *message, const char *mailbox)
00076 {
00077        char *argv[10];
00078        const char *from;
00079 
00080        if (!is_outbox(mailbox))
00081               return (0);
00082 
00083        from=defaultSendFrom();
00084 
00085        argv[1]="-oi";
00086        argv[2]="-t";
00087        argv[3]=NULL;
00088        if (from)
00089        {
00090               argv[3]="-f";
00091               argv[4]=(char *)from;
00092               argv[5]=NULL;
00093        }
00094 
00095        return (imapd_sendmsg(message, argv, errlogger));
00096 }
00097 
00098 int imapd_sendmsg(const char *message, char **argv, void (*err_func)(char *))
00099 {
00100        char buffer[512];
00101        int i;
00102        int ch;
00103        const char *from=defaultSendFrom();
00104        const char *hdrfrom;
00105 
00106        const char *prog;
00107 
00108        int pipefd[2];
00109        FILE *pipefp, *pipesendmail;
00110        pid_t pid, pid2;
00111        int waitstat;
00112 
00113        signal(SIGCHLD, SIG_DFL);
00114        signal(SIGPIPE, SIG_DFL);
00115 
00116        if (pipe(pipefd) < 0)
00117               write_error_exit("pipe");
00118 
00119        prog=getenv("SENDMAIL");
00120        if (!prog  || !*prog)
00121               prog="sendmail";
00122 
00123 
00124        pid=fork();
00125 
00126        if (pid < 0)
00127               write_error_exit("fork");
00128 
00129        if (pid > 0)  /* Parent reads err message, checks exit status */
00130        {
00131               i=0;
00132               close(pipefd[1]);
00133               pipefp=fdopen(pipefd[0], "r");
00134               if (pipefp == NULL)
00135                      write_error_exit("fdopen");
00136               while ((ch=getc(pipefp)) != EOF)
00137               {
00138                      if ((unsigned char)ch < ' ')
00139                             ch='/';
00140                      if (i < sizeof(buffer)-1)
00141                             buffer[i++]=ch;
00142               }
00143               fclose(pipefp);
00144               close(pipefd[0]);
00145               buffer[i]=0;
00146 
00147               while ((pid2=wait(&waitstat)) != pid)
00148                      if (pid2 < 0 && errno == ECHILD)
00149                             break;
00150 
00151               if (pid2 < 0 || !WIFEXITED(waitstat) || WEXITSTATUS(waitstat))
00152               {
00153                      if (buffer[0] == '\0')
00154                      {
00155                             buffer[0]=0;
00156                             strncat(buffer, prog, 128);
00157 
00158 #ifdef WIFSIGNALED
00159 #ifdef WTERMSIG
00160                             if (WIFSIGNALED(waitstat))
00161                                    sprintf(buffer+strlen(buffer),
00162                                           " terminated with signal %d",
00163                                           (int)WTERMSIG(waitstat));
00164                             else
00165 #endif
00166 #endif
00167                                    strcat(buffer, " failed without logging an error.  This shouldn't happen.");
00168                      }
00169 
00170                      (*err_func)(buffer);
00171                      return (-1);
00172               }
00173               return (0);
00174        }
00175 
00176        close(pipefd[0]);
00177        close(1);
00178        close(2);
00179        if (dup(pipefd[1]) != 1 || dup(pipefd[1]) != 2)
00180        {
00181               perror("dup(pipefd) failed");
00182               exit(1);
00183        }
00184        close(pipefd[1]);
00185 
00186        pipefp=fopen(message, "r");
00187        if (pipefp == NULL)
00188        {
00189               perror(message);
00190               exit(1);
00191        }
00192 
00193        /* Child forks again, second child process runs sendmail */
00194 
00195        if (pipe(pipefd) < 0)
00196        {
00197               perror("pipe");
00198               exit(1);
00199        }
00200 
00201        pid=fork();
00202 
00203        if (pid < 0)
00204        {
00205               perror("fork");
00206               exit(1);
00207        }
00208 
00209        if (pid == 0)
00210        {
00211               fclose(pipefp);
00212               close(pipefd[1]);
00213               close(0);
00214               errno=EINVAL;
00215               if (dup(pipefd[0]) != 0)
00216               {
00217                      perror("dup");
00218                      exit(1);
00219               }
00220 
00221               argv[0]=(char *)prog;
00222 
00223               execvp(prog, argv);
00224               perror(prog);
00225               exit(1);
00226        }
00227 
00228        close(pipefd[0]);
00229 
00230        pipesendmail=fdopen(pipefd[1], "w");
00231        if (!pipesendmail)
00232        {
00233               perror("fdopen");
00234               kill(pid, SIGTERM);
00235               close(pipefd[1]);
00236               exit(1);
00237        }
00238 
00239        if ((hdrfrom=getenv("HEADERFROM")) != NULL && *hdrfrom && from)
00240               fprintf(pipesendmail, "%s: %s\n", hdrfrom, from);
00241        while ((ch=getc(pipefp)) != EOF)
00242               putc(ch, pipesendmail);
00243        fclose(pipefp);
00244        fclose(pipesendmail);
00245 
00246        while ((pid2=wait(&waitstat)) != pid)
00247               if (pid2 < 0 && errno == ECHILD)
00248                      break;
00249 
00250        if (pid2 < 0 || !WIFEXITED(waitstat) || WEXITSTATUS(waitstat))
00251        {
00252               fprintf(stderr, "Message send FAILED.\n");
00253               exit(1);
00254        }
00255        exit(0);
00256        return (0);
00257 }