Back to index

courier  0.68.2
autoresponse.c
Go to the documentation of this file.
00001 /*
00002 */
00003 
00004 /*
00005 ** Copyright 2001-2011 Double Precision, Inc.  See COPYING for
00006 ** distribution information.
00007 */
00008 
00009 #include      "config.h"
00010 #include      "autoresponse.h"
00011 #include      "maildir/autoresponse.h"
00012 #include      "mailfilter.h"
00013 #include      "unicode/unicode.h"
00014 #include      "sqwebmail.h"
00015 #include      "htmllibdir.h"
00016 #include      "maildir.h"
00017 #include      "maildir/maildirmisc.h"
00018 #include      "maildir/maildirfilter.h"
00019 #include      "rfc2045/rfc2045.h"
00020 #include      "newmsg.h"
00021 #include      "cgi/cgi.h"
00022 #include      "numlib/numlib.h"
00023 #include      <string.h>
00024 #include      <stdlib.h>
00025 #include      <stdio.h>
00026 #include      <signal.h>
00027 #include      <ctype.h>
00028 #include      <errno.h>
00029 #if HAVE_SYS_WAIT_H
00030 #include      <sys/wait.h>
00031 #endif
00032 #ifndef WEXITSTATUS
00033 #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
00034 #endif
00035 #ifndef WIFEXITED
00036 #define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
00037 #endif
00038 
00039 extern const char *sqwebmail_content_charset;
00040 extern void output_attrencoded(const char *);
00041 extern const char *calc_mime_type(const char *filename);
00042 
00043 extern void charset_warning(const char *);
00044 
00045 static void save_autoresponse(const char *p, size_t l, void *vp)
00046 {
00047        FILE *fp=*(FILE **)vp;
00048 
00049        if (fp)
00050               if (fwrite(p, l, 1, fp) != 1)
00051                      ; /* ignore */
00052 }
00053 
00054 static int read_headers(FILE *);
00055 
00056 static int show_autoresponse_trampoline(const char *ptr, size_t cnt, void *arg)
00057 {
00058        show_textarea((struct show_textarea_info *)arg, ptr, cnt);
00059        return 0;
00060 }
00061 
00062 void autoresponse()
00063 {
00064 const char    *autoresp_title1=getarg("TITLE1");
00065 const char    *autoresp_title2=getarg("TITLE2");
00066 const char    *autoresp_text1=getarg("TEXT1");
00067 const char    *autoresp_text2=getarg("TEXT2");
00068 
00069        if ( *cgi("do.newautoresp"))
00070        {
00071               const char *name=cgi("newname");
00072               char *p;
00073               FILE *fp;
00074 
00075               p=folder_toutf7(name);
00076 
00077               if (!p || maildir_autoresponse_validate(NULL, p))
00078               {
00079                      free(p);
00080                      printf("%s", getarg("BADNAME"));
00081                      return;
00082               }
00083 
00084               if ((fp=maildir_autoresponse_open(NULL, p)) != NULL)
00085               {
00086                      free(p);
00087                      fclose(fp);
00088                      printf("%s", getarg("EEXIST"));
00089                      return;
00090               }
00091 
00092               printf("%s%s%s\n", autoresp_title1, name, autoresp_title2);
00093               printf("<input type=\"hidden\" name=\"autoresponse\" value=\"");
00094               output_attrencoded(p);
00095               printf("\" />\n");
00096               free(p);
00097 
00098               printf("%s%s\n", autoresp_text1, autoresp_text2);
00099               printf("%s<input type=\"file\" size=\"20\" name=\"uploadfile\" /><br />",
00100                      getarg("UPLOAD"));
00101               printf("<input type=\"submit\" name=\"do.autorespcreate\""
00102                      " value=\"%s\" />", getarg("SAVE"));
00103               return;
00104        }
00105 
00106        if ( *cgi("do.autorespedit"))
00107        {
00108               const char *autorespname=cgi("autoresponse_choose");
00109               FILE *fp;
00110               char *s=folder_fromutf7(autorespname);
00111               const char *pp;
00112 
00113               if (!s)
00114               {
00115                      printf(getarg("ERROR"), strerror(errno));
00116                      return;
00117               }
00118 
00119               pp=cgi("replytext");
00120 
00121               if ((fp=maildir_autoresponse_open(NULL, autorespname)) == NULL
00122                   && !*pp)
00123               {
00124                      free(s);
00125                      return;
00126               }
00127 
00128               printf("%s%s%s\n", autoresp_title1, s, autoresp_title2);
00129 
00130               if (fp && read_headers(fp))
00131               {
00132                      fclose(fp);
00133                      free(s);
00134                      return;
00135               }
00136 
00137               printf("<input type=\"hidden\" name=\"autoresponse\" value=\"");
00138               output_attrencoded(autorespname);
00139               printf("\" />\n");
00140               free(s);
00141 
00142               printf("%s", autoresp_text1);
00143 
00144               if (pp && *pp)
00145                      output_attrencoded(pp);
00146               else
00147               {
00148                      struct show_textarea_info info;
00149                      libmail_u_convert_handle_t h;
00150 
00151                      show_textarea_init(&info, 0);
00152 
00153                      h=libmail_u_convert_init("utf-8",
00154                                            sqwebmail_content_charset,
00155                                            show_autoresponse_trampoline,
00156                                            &info);
00157 
00158                      if (h)
00159                      {
00160                             size_t i;
00161                             char buf[BUFSIZ];
00162 
00163                             while ((i=fread(buf, 1, sizeof(buf), fp)) > 0)
00164                             {
00165                                    libmail_u_convert(h, buf, i);
00166                             }
00167                             libmail_u_convert_deinit(h, NULL);
00168                      }
00169               }
00170 
00171               if (fp)
00172                      fclose(fp);
00173               printf("%s\n", autoresp_text2);
00174               printf("%s<input type=\"file\" size=\"20\" name=\"uploadfile\" /><br />",
00175                      getarg("UPLOAD"));
00176               printf("<input type=\"submit\" name=\"do.autorespcreate\""
00177                      " value=\"%s\" />", getarg("SAVE"));
00178               return;
00179        }
00180 }
00181 
00182 /*
00183 ** Read the MIME headers in the autoresponse file, to make sure that we
00184 ** can show it.
00185 */
00186 
00187 static int read_headers(FILE *fp)
00188 {
00189        struct rfc2045 *rfc2045p=rfc2045_alloc();
00190        static const char mv[]="Mime-Version: 1.0\n";
00191        char buf[BUFSIZ];
00192        char *s;
00193        const char *content_type, *content_transfer_encoding, *charset;
00194 
00195        rfc2045_parse(rfc2045p, mv, sizeof(mv)-1);
00196 
00197        while ((s=fgets(buf, sizeof(buf), fp)) != NULL)
00198        {
00199               rfc2045_parse(rfc2045p, s, strlen(s));
00200               if (strcmp(s, "\n") == 0 || strcmp(s, "\r\n") == 0)
00201                      break;
00202        }
00203        rfc2045_parse_partial(rfc2045p);
00204 
00205        rfc2045_mimeinfo(rfc2045p, &content_type,
00206                       &content_transfer_encoding,
00207                       &charset);
00208 
00209        if (strcmp(content_type, "text/plain") ||
00210            !rfc2045_isflowed(rfc2045p))
00211        {
00212               printf(getarg("ATT"), content_type);
00213               rfc2045_free(rfc2045p);
00214               return (-1);
00215        }
00216 
00217        rfc2045_free(rfc2045p);
00218        return (0);
00219 }
00220 
00221 static FILE *upload_attachment(const char *);
00222 
00223 void autoresponsedelete()
00224 {
00225        if ( *cgi("do.autorespcreate"))
00226        {
00227               const char *autorespname=cgi("autoresponse");
00228               const char *autoresptxt=cgi("text");
00229               FILE *fp;
00230               size_t l;
00231 
00232               if ((fp=upload_attachment(autorespname)) == NULL)
00233               {
00234                      struct wrap_info uw;
00235 
00236                      if ((fp=maildir_autoresponse_create(NULL,
00237                                                      autorespname))
00238                          == NULL)
00239                      {
00240                             printf(getarg("SAVEFAILED"), strerror(errno));
00241                             return;
00242                      }
00243 
00244                      l=strlen(autoresptxt);
00245                      while (l && (autoresptxt[l-1] == '\r' ||
00246                                  autoresptxt[l-1] == '\n'))
00247                             --l;
00248 
00249                      fprintf(fp, "Content-Type: text/plain");
00250                      fprintf(fp, "; format=flowed; delsp=yes"
00251                             "; charset=\"utf-8\"\n");
00252                      fprintf(fp, "Content-Transfer-Encoding: 8bit\n\n");
00253 
00254                      wrap_text_init(&uw, "utf-8", save_autoresponse, &fp);
00255                      wrap_text(&uw, autoresptxt, l);
00256               }
00257 
00258               if (fflush(fp) || ferror(fp))
00259               {
00260                      fclose(fp);
00261                      printf(getarg("SAVEFAILED"), strerror(errno));
00262                      return;
00263               }
00264               if (maildir_autoresponse_create_finish(NULL, autorespname, fp))
00265               {
00266                      if (errno == ENOSPC)
00267                      {
00268                             cgi_put("do.autorespedit", "1");
00269                             cgi_put("autoresponse_choose", autorespname);
00270                             cgi_put("replytext", cgi("text"));
00271                             printf(getarg("QUOTA"), strerror(errno));
00272                      }
00273                      else
00274                             printf(getarg("SAVEFAILED"), strerror(errno));
00275               }
00276               return;
00277        }
00278 
00279        if ( *cgi("do.autorespdelete"))
00280        {
00281               const char *autorespname=cgi("autoresponse_choose");
00282 
00283               if (mailfilter_autoreplyused(autorespname))
00284               {
00285                      char *s=folder_fromutf7(autorespname);
00286                      printf(getarg("INUSE"), s ? s:"");
00287                      if (s)
00288                             free(s);
00289               }
00290               else
00291                      maildir_autoresponse_delete(NULL, autorespname);
00292               return;
00293        }
00294 }
00295 
00296 struct upload_attach_info {
00297        FILE *fp;
00298        const char *filename;
00299        const char *name;
00300        const char *autorespname;
00301 } ;
00302 
00303 static int start_upload(const char *, const char *, void *);
00304 static int upload(const char *, size_t, void *);
00305 static void end_upload(void *);
00306 
00307 static FILE *upload_attachment(const char *autorespname)
00308 {
00309        struct upload_attach_info uai;
00310 
00311        uai.fp=NULL;
00312        uai.autorespname=autorespname;
00313 
00314        if (cgi_getfiles( &start_upload, &upload, &end_upload, 1, &uai ))
00315        {
00316               if (uai.fp)
00317                      fclose(uai.fp);
00318 
00319               return (NULL);
00320        }
00321 
00322        return (uai.fp);
00323 }
00324 
00325 static int start_upload(const char *name, const char *filename, void *vp)
00326 {
00327        struct upload_attach_info *uai=(struct upload_attach_info *)vp;
00328        const char *p;
00329 
00330        p=strrchr(filename, '/');
00331        if (p) filename=p+1;
00332 
00333        p=strrchr(filename, '\\');
00334        if (p) filename=p+1;
00335 
00336        if (*filename)
00337        {
00338               uai->filename=filename;
00339        }
00340        else
00341        {
00342               p=strrchr(name, '/');
00343               if (p) name=p+1;
00344 
00345               p=strrchr(name, '\\');
00346               if (p) name=p+1;
00347               uai->filename=p;
00348        }
00349 
00350        uai->fp=tmpfile();
00351        if (!uai->fp)
00352               enomem();
00353        return (0);
00354 }
00355 
00356 static int upload(const char *c, size_t n, void *vp)
00357 {
00358        struct upload_attach_info *uai=(struct upload_attach_info *)vp;
00359 
00360        if (fwrite(c, n, 1, uai->fp) != 1)
00361        {
00362               fclose(uai->fp);
00363               enomem();
00364        }
00365        return (0);
00366 }
00367 
00368 static int upload_messagerfc822(FILE *, FILE *);
00369 
00370 static void end_upload(void *vp)
00371 {
00372        struct upload_attach_info *uai=(struct upload_attach_info *)vp;
00373        const char *mimetype;
00374        char *argvec[10];
00375        int n;
00376        pid_t pid1, pid2;
00377        int waitstat;
00378        FILE *afp;
00379 
00380        if (fflush(uai->fp) || ferror(uai->fp)
00381            || fseek(uai->fp, 0L, SEEK_SET) < 0)
00382        {
00383               fclose(uai->fp);
00384               enomem();
00385        }
00386 
00387        mimetype=calc_mime_type(uai->filename);
00388 
00389        if (strcasecmp(mimetype, "message/rfc822") == 0)
00390        {
00391               /* Magic */
00392 
00393               afp=maildir_autoresponse_create(NULL, uai->autorespname);
00394               if (!afp)
00395               {
00396                      fclose(uai->fp);
00397                      enomem();
00398               }
00399 
00400               if (upload_messagerfc822(uai->fp, afp) ||
00401                   fflush(afp) || ferror(afp))
00402               {
00403                      fclose(uai->fp);
00404                      fclose(afp);
00405                      enomem();
00406               }
00407               fclose(uai->fp);
00408               uai->fp=afp;
00409               return;
00410        }
00411        argvec[0]="makemime";
00412        argvec[1]="-c";
00413        argvec[2]=(char *)mimetype;
00414 
00415        n=3;
00416        if (strncasecmp(argvec[2], "text/", 5) == 0 ||
00417            strcasecmp(argvec[2], "auto") == 0)
00418        {
00419               argvec[3]="-C";
00420               argvec[4]=(char *)sqwebmail_content_charset;
00421               n=5;
00422        }
00423 
00424        argvec[n++]="-";
00425        argvec[n]=0;
00426 
00427        afp=maildir_autoresponse_create(NULL, uai->autorespname);
00428        if (!afp)
00429        {
00430               fclose(uai->fp);
00431               enomem();
00432        }
00433 
00434        signal(SIGCHLD, SIG_DFL);
00435        pid1=fork();
00436 
00437        if (pid1 < 0)
00438        {
00439               fclose(afp);
00440               fclose(uai->fp);
00441               enomem();
00442        }
00443 
00444        if (pid1 == 0)
00445        {
00446               dup2(fileno(uai->fp), 0);
00447               dup2(fileno(afp), 1);
00448               fclose(uai->fp);
00449               fclose(afp);
00450               execv(MAKEMIME, argvec);
00451               fprintf(stderr,
00452                      "CRIT: exec %s: %s\n", MAKEMIME, strerror(errno));
00453               exit(1);
00454        }
00455 
00456        for (;;)
00457        {
00458               pid2=wait(&waitstat);
00459 
00460               if (pid2 == pid1)
00461               {
00462                      waitstat= WIFEXITED(waitstat) ? WEXITSTATUS(waitstat)
00463                             : 1;
00464                      break;
00465               }
00466 
00467               if (pid2 == -1)
00468               {
00469                      waitstat=1;
00470                      break;
00471               }
00472        }
00473 
00474        if (waitstat)
00475        {
00476               fclose(afp);
00477               fclose(uai->fp);
00478               enomem();
00479        }
00480 
00481        fclose(uai->fp);
00482        uai->fp=afp;
00483 }
00484 
00485 /*
00486 ** If we get something that's MIMEed as message/rfc822, read it, strip its
00487 ** headers except for the MIME content- headers, then save what's left as
00488 ** our autoreply.  This allows for a convenient way to upload
00489 ** multipart/alternative content.
00490 */
00491 
00492 static int upload_messagerfc822(FILE *i, FILE *o)
00493 {
00494        char buf[BUFSIZ];
00495        int skip_hdr;
00496        int c;
00497        const char *pp;
00498 
00499        skip_hdr=0;
00500 
00501        for (;;)
00502        {
00503               if (fgets(buf, sizeof(buf), i) == NULL)
00504               {
00505                      fprintf(o, "\n");
00506                      return (0);
00507               }
00508 
00509               if (strcmp(buf, "\n") == 0 || strcmp(buf, "\r\n") == 0)
00510               {
00511                      fprintf(o, "\n");
00512                      break;
00513               }
00514 
00515               if (!isspace((int)(unsigned char)*buf))
00516                      skip_hdr=strncasecmp(buf, "content-", 8) != 0;
00517 
00518               if (skip_hdr)
00519                      continue;
00520 
00521               for (pp=buf; *pp; pp++)
00522                      if (*pp != '\r')
00523                             if (putc((int)(unsigned char)*pp, o)
00524                                 == EOF)
00525                                    return (-1);
00526        }
00527 
00528        while ((c=getc(i)) != EOF)
00529               if (c != '\r')
00530                      if (putc(c, o) == EOF)
00531                             return (-1);
00532        return (0);
00533 }
00534 
00535 
00536 
00537 static int comp_autorespname(const void *a, const void *b)
00538 {
00539        const char *ca=*(const char **)a;
00540        const char *cb=*(const char **)b;
00541 
00542        char *sa=folder_fromutf7(ca);
00543        char *sb=folder_fromutf7(cb);
00544 
00545        int i=sa && sb ? strcoll(sa, sb):0;
00546 
00547        free(sa);
00548        free(sb);
00549        return (i);
00550 }
00551 
00552 void autoresponselist()
00553 {
00554        char **list=maildir_autoresponse_list(NULL); /* I'm sorry... */
00555        size_t i;
00556 
00557        if (!list)
00558        {
00559               printf(getarg("ERROR"), strerror(errno));
00560               return;
00561        }
00562 
00563        for (i=0; list[i]; i++)
00564               ;
00565 
00566        qsort(list, i, sizeof(list[0]), &comp_autorespname);
00567 
00568        for (i=0; list[i]; i++)
00569        {
00570               char *s;
00571 
00572               printf("<option value=\"");
00573               output_attrencoded(list[i]);
00574               printf("\">");
00575 
00576               s=folder_fromutf7(list[i]);
00577               output_attrencoded(s);
00578               printf("</option>");
00579               free(s);
00580        }
00581 
00582        maildir_autoresponse_list_free(list);
00583 }
00584 
00585 void autoresponsepick()
00586 {
00587        char **list=maildir_autoresponse_list(NULL);
00588        size_t i;
00589        const char *choice=cgi("autoresponse_choose");
00590 
00591        if (!list)
00592        {
00593               printf(getarg("ERROR"), strerror(errno));
00594               return;
00595        }
00596 
00597        for (i=0; list[i]; i++)
00598               ;
00599 
00600        qsort(list, i, sizeof(list[0]), &comp_autorespname);
00601 
00602        for (i=0; list[i]; i++)
00603        {
00604               char *s;
00605 
00606               printf("<option%s value=\"",
00607                      strcmp(choice, list[i]) ? "":" selected='selected'");
00608               output_attrencoded(list[i]);
00609               printf("\">");
00610 
00611               s=folder_fromutf7(list[i]);
00612               output_attrencoded(s);
00613               printf("</option>");
00614               free(s);
00615        }
00616 
00617        maildir_autoresponse_list_free(list);
00618 }