Back to index

courier  0.68.2
courierfax.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 
00010 #include      "courier.h"
00011 #include      "moduledel.h"
00012 #include      "comqueuename.h"
00013 #include      "comfax.h"
00014 #include      "rfc822/rfc822.h"
00015 #include      "waitlib/waitlib.h"
00016 #include      "unicode/unicode.h"
00017 #include      "numlib/numlib.h"
00018 #include      <stdlib.h>
00019 #include      <locale.h>
00020 #include      <langinfo.h>
00021 #include      <string.h>
00022 #include      <ctype.h>
00023 #include      <signal.h>
00024 #include      <errno.h>
00025 #if    HAVE_UNISTD_H
00026 #include      <unistd.h>
00027 #endif
00028 #if    HAVE_FCNTL_H
00029 #include      <fcntl.h>
00030 #endif
00031 #include      <pwd.h>
00032 #include      <sys/wait.h>
00033 #include      <sys/time.h>
00034 #include      "comctlfile.h"
00035 #include      "comqueuename.h"
00036 #include      "comstrtotime.h"
00037 #include      "comstrtimestamp.h"
00038 #include      "comverp.h"
00039 #include      <sys/stat.h>
00040 #include <sys/types.h>
00041 #if HAVE_SYS_WAIT_H
00042 #include <sys/wait.h>
00043 #endif
00044 #ifndef WEXITSTATUS
00045 #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
00046 #endif
00047 #ifndef WIFEXITED
00048 #define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
00049 #endif
00050 #include      "faxconvert.h"
00051 #include      "sendfax.h"
00052 #include      "faxtmpdir.h"
00053 
00054 
00055 static void fax(struct moduledel *);
00056 
00057 /*
00058 **  Kill the child process.
00059 */
00060 
00061 static RETSIGTYPE killit(int n)
00062 {
00063        module_signal(SIGKILL);
00064        exit(0);
00065 #if RETSIGTYPE != void
00066        return (0);
00067 #endif
00068 }
00069 
00070 /*
00071 ** Main loop.  Receive a message to deliver.  Fork off a child process.  Yawn.
00072 */
00073 
00074 int main(int argc, char **argv)
00075 {
00076        struct moduledel *p;
00077        int waitstat;
00078        const char *cp;
00079 
00080        clog_open_syslog("courierfax");
00081        if (chdir(getenv("COURIER_HOME")))
00082               clog_msg_errno();
00083 
00084        cp=getenv("MAXDELS");
00085        if (!cp || atoi(cp) != 1)
00086        {
00087               clog_msg_start_err();
00088               clog_msg_str("FATAL: courierfax module misconfiguration, MAXDELS must be 1");
00089               clog_msg_send();
00090               exit(0);
00091        }
00092 
00093        cp=getenv("MAXRCPT");
00094        if (!cp || atoi(cp) != 1)
00095        {
00096               clog_msg_start_err();
00097               clog_msg_str("FATAL: courierfax module misconfiguration, MAXRCPT must be 1");
00098               clog_msg_send();
00099               exit(0);
00100        }
00101 
00102        module_init(0);
00103        while ((p=module_getdel()) != NULL)
00104        {
00105               pid_t  pid;
00106               unsigned delid;
00107 
00108               delid=atol(p->delid);
00109 
00110               if ((pid=module_fork(delid, 0)) == -1)
00111               {
00112                      clog_msg_prerrno();
00113                      module_completed(delid, delid);
00114                      continue;
00115               }
00116 
00117               if (pid == 0)
00118               {
00119                      fax(p);
00120                      exit(0);
00121               }
00122        }
00123 
00124        module_signal(SIGTERM);
00125        signal(SIGCHLD, SIG_DFL);
00126        signal(SIGALRM, killit);
00127        alarm(5);
00128        wait(&waitstat);
00129        alarm(0);
00130        return (0);
00131 }
00132 
00133 /*
00134 **  All righty - pick up a message to deliver.
00135 */
00136 
00137 static RETSIGTYPE faxabort(int n)
00138 {
00139        signal(SIGTERM, SIG_IGN);
00140        kill(-getpid(), SIGTERM);
00141 #if RETSIGTYPE != void
00142        return (0);
00143 #endif
00144 }
00145 
00146 static int read_childerrmsg(pid_t child_proc,
00147                          int errfd,
00148                          int (*errhandler)(int, char *, void *),
00149                          void *errhandler_arg)
00150 {
00151        char errbuf[BUFSIZ];
00152        int errptr=0;
00153        int waitstat;
00154        pid_t p;
00155 
00156        for (;;)
00157        {
00158               int n, i;
00159 
00160               if (errptr >= BUFSIZ/4 * 3)
00161               {
00162                      /* Read errmsg too big, strip it */
00163 
00164                      i=BUFSIZ/2;
00165 
00166                      for (n=BUFSIZ/2; n<errptr; n++)
00167                             if (errbuf[n] == '\n')
00168                             {
00169                                    i= n+1;
00170                                    break;
00171                             }
00172 
00173                      strcpy(errbuf, "...\n");
00174                      n=4;
00175                      while (i < errptr)
00176                             errbuf[n++] = errbuf[i++];
00177                      errptr=n;
00178               }
00179 
00180               n=read(errfd, errbuf+errptr, BUFSIZ-1-errptr);
00181               if (n <= 0)
00182                      break;
00183               errptr += n;
00184        }
00185        errbuf[errptr]=0;
00186        close(errfd);
00187 
00188        while ((p=wait(&waitstat)) != child_proc)
00189        {
00190               if (p < 0 && errno != EINTR)
00191                      break;
00192        }
00193 
00194        if (p == child_proc && WIFEXITED(waitstat) &&
00195            WEXITSTATUS(waitstat) == 0)
00196               return (0);
00197 
00198        if (errptr == 0)
00199               strcpy(errbuf, "courierfax: child process crashed.");
00200 
00201        return (*errhandler)(p == child_proc && WIFEXITED(waitstat)
00202                           ? WEXITSTATUS(waitstat):1,
00203                           errbuf, errhandler_arg);
00204 }
00205 
00206 struct faxconv_err_args {
00207        struct ctlfile *ctf;
00208        unsigned nreceip;
00209 
00210        struct sort_file_list *file_list;
00211        int is_locked;
00212        int n_cover_pages;
00213 } ;
00214 
00215 
00216 static int faxconvert_cleanup(int dummy, char *errmsg, void *vp)
00217 {
00218        struct faxconv_err_args *args=(struct faxconv_err_args *)vp;
00219 
00220        ctlfile_append_reply(args->ctf, args->nreceip,
00221                           errmsg,
00222                           COMCTLFILE_DELFAIL_NOTRACK, 0);
00223        return (-1);
00224 }
00225 
00226 extern int faxconvert(const char *, int, int *);
00227 
00228 static int faxsend_cleanup(int, char *, void *);
00229 
00230 static void fax(struct moduledel *p)
00231 {
00232        struct ctlfile ctf;
00233        unsigned nreceipients=p->nreceipients;
00234        const char *host=p->host;
00235        const char *receipient;
00236        unsigned nrecipient=(unsigned)atol(p->receipients[0]);
00237        int pipefd[2];
00238        pid_t child_proc;
00239        int faxopts;
00240        int n_cover_pages;
00241        FILE *fp;
00242 
00243        struct faxconv_err_args err_args;
00244 
00245        struct sort_file_list *page_list, *pp;
00246 
00247 
00248 #if     HAVE_SETPGRP
00249 #if     SETPGRP_VOID
00250         setpgrp();
00251 #else
00252         setpgrp(0, 0);
00253 #endif
00254 #else
00255 #if     HAVE_SETPGID
00256         setpgid(0, 0);
00257 #endif
00258 #endif
00259 
00260        if (comgetfaxopts(host, &faxopts))
00261        {
00262               clog_msg_start_err();
00263               clog_msg_str("courierfax: FATAL: invalid host");
00264               clog_msg_send();
00265               exit(1);
00266        }
00267 
00268        putenv(faxopts & FAX_LOWRES ? "FAXRES=lo":"FAXRES=hi");
00269 
00270        if (nreceipients != 1)
00271        {
00272               clog_msg_start_err();
00273               clog_msg_str("courierfax: FATAL: # receipients must be 1");
00274               clog_msg_send();
00275               exit(1);
00276        }
00277 
00278        receipient=p->receipients[1];
00279        nrecipient=(unsigned)atol(p->receipients[0]);
00280 
00281        if (ctlfile_openi(p->inum, &ctf, 0))
00282               clog_msg_errno();
00283 
00284        /* Convert message to fax format, use a child process */
00285 
00286        signal(SIGTERM, faxabort);
00287 
00288        if (pipe(pipefd) < 0)
00289        {
00290               clog_msg_errno();
00291        }
00292 
00293        child_proc=fork();
00294        if (child_proc < 0)
00295        {
00296               clog_msg_errno();
00297               return;
00298        }
00299 
00300        if (child_proc == 0)
00301        {
00302               const char *fn;
00303 
00304               close(0);
00305               if (open("/dev/null", O_RDONLY) != 0)
00306                      clog_msg_errno();
00307 
00308               close(pipefd[0]);
00309               close(1);
00310               if (dup(pipefd[1]) != 1)
00311               {
00312                      perror("dup");
00313                      exit(1);
00314               }
00315               close(2);
00316               if (dup(pipefd[1]) != 2)
00317               {
00318                      fprintf(stderr, "ERROR: dup failed\n");
00319                      exit(1);
00320               }
00321               close(pipefd[1]);
00322 
00323               libmail_changeuidgid(MAILUID, MAILGID);
00324 
00325               fn=qmsgsdatname(p->inum);
00326 
00327               if (faxconvert(fn, faxopts, &n_cover_pages))
00328                      exit (1);
00329 
00330               if ((fp=fopen(FAXTMPDIR "/.ncoverpages", "w")) == NULL ||
00331                   fprintf(fp, "%d\n", n_cover_pages) < 0 ||
00332                   fflush(fp) < 0)
00333                      exit(1);
00334               fclose(fp);
00335               exit(0);
00336        }
00337 
00338        close(pipefd[1]);
00339 
00340        err_args.ctf= &ctf;
00341        err_args.nreceip=nrecipient;
00342 
00343        if (read_childerrmsg(child_proc, pipefd[0],
00344                           &faxconvert_cleanup, &err_args))
00345        {
00346               ctlfile_close(&ctf);
00347               return;
00348        }
00349 
00350        /* Hit it */
00351 
00352        if ((fp=fopen(FAXTMPDIR "/.ncoverpages", "r")) == NULL ||
00353            fscanf(fp, "%d", &n_cover_pages) != 1)
00354        {
00355               if (fp)
00356                      fclose(fp);
00357 
00358               ctlfile_append_reply(err_args.ctf,
00359                                  err_args.nreceip,
00360                                  "Internal error: cannot read number of cover pages",
00361                                  COMCTLFILE_DELFAIL, 0);
00362               ctlfile_close(&ctf);
00363               exit(0);
00364        }
00365 
00366        page_list=read_dir_sort_filenames(FAXTMPDIR, FAXTMPDIR "/");
00367 
00368        if (!page_list)
00369        {
00370               clog_msg_start_err();
00371               clog_msg_str("courierfax: INTERNAL ERROR - no pages to xmit.");
00372               clog_msg_send();
00373               exit(1);
00374        }
00375 
00376        /* Keep trying until the modem line is unlocked */
00377 
00378        do
00379        {
00380               if (pipe(pipefd) < 0)
00381               {
00382                      clog_msg_errno();
00383               }
00384 
00385               child_proc=fork();
00386               if (child_proc < 0)
00387               {
00388                      clog_msg_errno();
00389                      return;
00390               }
00391 
00392               if (child_proc == 0)
00393               {
00394                      unsigned page_cnt=0;
00395                      char **argvec;
00396 
00397                      close(pipefd[0]);
00398                      close(0);
00399                      if (open("/dev/null", O_RDONLY) != 0)
00400                      {
00401                             perror("/dev/null");
00402                             exit(1);
00403                      }
00404                      close(1);
00405                      if (dup(pipefd[1]) != 1)
00406                      {
00407                             perror("dup");
00408                             exit(1);
00409                      }
00410                      close(2);
00411                      if (dup(pipefd[1]) != 2)
00412                      {
00413                             fprintf(stderr, "ERROR: dup failed\n");
00414                             exit(1);
00415                      }
00416                      close(pipefd[1]);
00417 
00418                      for (pp=page_list; pp; pp=pp->next)
00419                             ++page_cnt;
00420 
00421 #if 0
00422                      while (page_list)
00423                      {
00424                             unlink(page_list->filename);
00425                             page_list=page_list->next;
00426                      }
00427 
00428                      exit(0);
00429 #endif
00430 
00431                      argvec=(char **)courier_malloc(sizeof(char *)*
00432                                                  (page_cnt+10));
00433 
00434                      argvec[0]=SENDFAX;
00435                      argvec[1]="-v";
00436                      argvec[2]="-r";
00437 
00438                      page_cnt=3;
00439 
00440                      if (faxopts & FAX_LOWRES)
00441                             argvec[page_cnt++]="-n";
00442 
00443                      argvec[page_cnt++]=(char *)receipient;
00444 
00445                      while (page_list)
00446                      {
00447                             argvec[page_cnt++]=page_list->filename;
00448                             page_list=page_list->next;
00449                      }
00450                      argvec[page_cnt]=0;
00451                      execv(SENDFAX, argvec);
00452                      perror(SENDFAX);
00453                      exit(1);
00454               }
00455               close(pipefd[1]);
00456 
00457               err_args.ctf= &ctf;
00458               err_args.nreceip=nrecipient;
00459               err_args.file_list=page_list;
00460               err_args.is_locked=0;
00461               err_args.n_cover_pages=n_cover_pages;
00462 
00463               if (read_childerrmsg(child_proc, pipefd[0],
00464                                  &faxsend_cleanup, &err_args) == 0)
00465               {
00466                      size_t npages=0;
00467                      char fmtbuf[NUMBUFSIZE];
00468                      char fmtbuf1[NUMBUFSIZE];
00469                      char fmtbuf2[NUMBUFSIZE+100];
00470 
00471                      for (pp=page_list; pp; pp=pp->next)
00472                             ++npages;
00473 
00474                      libmail_str_size_t(npages, fmtbuf);
00475                      libmail_str_size_t(n_cover_pages, fmtbuf1);
00476 
00477                      sprintf(fmtbuf2,
00478                             "%s pages - including %s cover page(s)"
00479                             " - sent by fax.", fmtbuf, fmtbuf1);
00480 
00481                      ctlfile_append_reply(&ctf, (unsigned)
00482                                         nrecipient,
00483                                         fmtbuf2,
00484                                         COMCTLFILE_DELSUCCESS, " l");
00485                      break;
00486               }
00487        } while (err_args.is_locked);
00488 
00489        ctlfile_close(&ctf);
00490        rmdir_contents(FAXTMPDIR);
00491 }
00492 
00493 static int faxsend_cleanup(int errcode, char *errmsg, void *vp)
00494 {
00495        struct faxconv_err_args *args=(struct faxconv_err_args *)vp;
00496        unsigned pages_sent=0;
00497        char *p, *q;
00498 
00499        int i;
00500        time_t now_time;
00501 
00502        unsigned coverpage_cnt=0;
00503        unsigned page_cnt=0;
00504 
00505        /* Check how many files sendfax renamed (were succesfully sent) */
00506 
00507        while (args->file_list)
00508        {
00509               if (access(args->file_list->filename, 0) == 0)
00510                      break;
00511 
00512               if (coverpage_cnt < args->n_cover_pages)
00513                      ++coverpage_cnt;
00514               else
00515                      ++pages_sent;
00516               args->file_list=args->file_list->next;
00517        }
00518 
00519        /* Strip out any blank lines in captured output from sendfax */
00520 
00521        for (p=q=errmsg; *p; p++)
00522        {
00523               if (*p == '\n' && (p[1] == '\n' || p[1] == 0))
00524                      continue;
00525 
00526               *q++=*p;
00527        }
00528        *q=0;
00529 
00530        /* Find the last message from sendfax */
00531 
00532        for (p=q=errmsg; *p; p++)
00533        {
00534               if (*p != '\n')
00535                      continue;
00536 
00537               *p=0;
00538 
00539               /* Dump sendfax's output to the log */
00540 
00541               if (*q)
00542               {
00543                      clog_msg_start_info();
00544                      clog_msg_str("courierfax: " SENDFAX ": ");
00545                      clog_msg_str(q);
00546                      clog_msg_send();
00547               }
00548               q=p+1;
00549        }
00550 
00551        if (*q)       /* Last line of the error message */
00552        {
00553               clog_msg_start_info();
00554               clog_msg_str("courierfax: " SENDFAX ": ");
00555               clog_msg_str(q);
00556               clog_msg_send();
00557        }
00558        else   /* Default message */
00559        {
00560               q=SENDFAX ": completed.";
00561        }
00562 
00563        /*
00564        ** Ugly hack: capture the following message from sendfax:
00565        **
00566        ** /usr/sbin/sendfax: cannot access fax device(s) (locked?)
00567        */
00568 
00569 #if 0
00570        lockflag=0;
00571        p=strchr(q, ':');
00572        if (p)
00573        {
00574               static const char msg1[]="cannot access fax device";
00575               static const char msg2[]="locked";
00576 
00577               ++p;
00578               while (*p && isspace((int)(unsigned char)*p))
00579                      p++;
00580 
00581               if (*p && strncasecmp(p, msg1, sizeof(msg1)-1) == 0)
00582               {
00583                      p += sizeof(msg1);
00584                      while (*p && !isspace((int)(unsigned char)*p))
00585                             ++p;
00586 
00587                      p=strchr(p, '(');
00588 
00589                      if (p && strncmp(p+1, msg2, sizeof(msg2)-1) == 0)
00590                      {
00591                             args->is_locked=1;
00592                             clog_msg_start_info();
00593                             clog_msg_str("courierfax: detected locked"
00594                                         " modem line, sleeping...");
00595                             clog_msg_send();
00596                             sleep(60);
00597                             return (-1);
00598                      }
00599               }
00600        }
00601 #else
00602 
00603        if (errcode == 2)
00604        {
00605               args->is_locked=1;
00606               clog_msg_start_info();
00607               clog_msg_str("courierfax: detected locked"
00608                           " modem line, sleeping...");
00609               clog_msg_send();
00610               sleep(60);
00611               return (-1);
00612        }
00613 #endif
00614 
00615        ctlfile_append_connectioninfo(args->ctf, args->nreceip,
00616                                   COMCTLFILE_DELINFO_REPLY, q);
00617 
00618        sprintf(errmsg, "%u cover pages, %u document pages sent.",
00619               coverpage_cnt, page_cnt);
00620 
00621        i=ctlfile_searchfirst(args->ctf, COMCTLFILE_FAXEXPIRES);
00622 
00623        time(&now_time);
00624        ctlfile_append_reply(args->ctf, args->nreceip,
00625                           errmsg,
00626                           (pages_sent == 0 &&
00627                            i >= 0 &&
00628                            errcode < 10 &&
00629                            now_time < strtotime(args->ctf->lines[i]+1)
00630                            ? COMCTLFILE_DELDEFERRED:
00631                            COMCTLFILE_DELFAIL_NOTRACK), 0);
00632        return (-1);
00633 }
00634