Back to index

courier  0.68.2
attachments.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 1998 - 2011 Double Precision, Inc.  See COPYING for
00003 ** distribution information.
00004 */
00005 
00006 
00007 /*
00008 */
00009 #include      "config.h"
00010 #include      "sqwebmail.h"
00011 #include      "cgi/cgi.h"
00012 #include      "sqconfig.h"
00013 #include      "maildir.h"
00014 #include      "folder.h"
00015 #include      "pref.h"
00016 #include      "rfc822/rfc822.h"
00017 #include      "rfc822/rfc2047.h"
00018 #include      "rfc2045/rfc2045.h"
00019 #include      "token.h"
00020 #include      "newmsg.h"
00021 #include      "gpg.h"
00022 #include      "gpglib/gpglib.h"
00023 #include      "courierauth.h"
00024 #include      <stdio.h>
00025 #include      <stdlib.h>
00026 #include      <ctype.h>
00027 #include      <signal.h>
00028 #include      <errno.h>
00029 #include      <fcntl.h>
00030 #if    HAVE_UNISTD_H
00031 #include        <unistd.h>
00032 #endif
00033 #include      <sys/types.h>
00034 #include      <sys/stat.h>
00035 #if HAVE_SYS_WAIT_H
00036 #include      <sys/wait.h>
00037 #endif
00038 #ifndef WEXITSTATUS
00039 #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
00040 #endif
00041 #ifndef WIFEXITED
00042 #define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
00043 #endif
00044 
00045 #include      "maildir/maildirmisc.h"
00046 
00047 #include      "htmllibdir.h"
00048 #include      "unicode/unicode.h"
00049 
00050 extern char *newmsg_alladdrs(FILE *);
00051 extern void newmsg_copy_content_headers(FILE *fp);
00052 
00053 extern char *alloc_filename(const char *, const char *, const char *);
00054 extern const char *showsize(unsigned long);
00055 extern void output_attrencoded(const char *);
00056 extern int newdraftfd;
00057 extern void newmsg_hiddenheader(const char *, const char *);
00058 extern void output_scriptptrget();
00059 extern void output_urlencoded(const char *);
00060 extern void sendmsg_done();
00061 
00062 extern char *multipart_boundary_create();
00063 extern int multipart_boundary_checkf(const char *, FILE *);
00064 extern int ishttps();
00065 
00066 extern void newmsg_create_multipart(int, const char *, const char *);
00067 extern void newmsg_copy_nonmime_headers(FILE *);
00068 
00069 extern const char *sqwebmail_content_charset;
00070 extern const char *sqwebmail_content_language;
00071 
00072 static void attachment_showname(const char *);
00073 
00074 #define HASTEXTPLAIN(q) (rfc2045_searchcontenttype((q), "text/plain") != NULL)
00075 /* Also in newmsg_create.c */
00076 
00077 
00078 static off_t max_attach()
00079 {
00080        off_t n=0;
00081        const char *p=getenv("SQWEBMAIL_MAXMSGSIZE");
00082 
00083        if (p)
00084               n=atol(p);
00085 
00086        if (n < MAXMSGSIZE)
00087               n=MAXMSGSIZE;
00088        return n;
00089 }
00090 
00091 
00092 void attachments_head(const char *folder, const char *pos, const char *draft)
00093 {
00094 char *filename;
00095 FILE   *fp;
00096 struct rfc2045 *rfcp;
00097 int    cnt=0;
00098 struct rfc2045 *q;
00099 int    foundtextplain=0;
00100 const char    *noattach_lab=getarg("NOATTACH");
00101 const char    *quotaerr=getarg("QUOTAERR");
00102 const char    *limiterr=getarg("LIMITERR");
00103 off_t  dummy;
00104 int    fd2;
00105 
00106        CHECKFILENAME(draft);
00107        filename=maildir_find(INBOX "." DRAFTS, draft);
00108        if (!filename)       return;
00109 
00110        fd2=maildir_safeopen(filename, O_RDONLY, 0);
00111 
00112        fp=0;
00113        if (fd2 >= 0)
00114        {
00115               fp=fdopen(fd2, "r");
00116               if (fp == NULL)
00117                      close(fd2);
00118        }
00119 
00120        if (fp == NULL)
00121        {
00122               free(filename);
00123               return;
00124        }
00125 
00126        rfcp=rfc2045_fromfp(fp);
00127        fclose(fp);
00128        free(filename);
00129 
00130        if (strcmp(cgi("error"), "quota") == 0)
00131        {
00132               printf("%s", quotaerr);
00133        }
00134 
00135        if (strcmp(cgi("error"), "limits") == 0)
00136        {
00137               printf(limiterr, (unsigned long)(max_attach() / (1024 * 1024)));
00138        }
00139 
00140        if (strcmp(cgi("error"), "makemime") == 0)
00141        {
00142               printf(getarg("MAKEMIMEERR"), MAKEMIME);
00143        }
00144        newmsg_hiddenheader("pos", pos);
00145        newmsg_hiddenheader("draft", draft);
00146        tokennew();
00147        printf("<table width=\"100%%\" border=\"0\">");
00148 
00149        if (rfcp)
00150        {
00151               const char *content_type;
00152               const char *content_transfer_encoding;
00153               const char *charset;
00154 
00155               rfc2045_mimeinfo(rfcp, &content_type,
00156                      &content_transfer_encoding, &charset);
00157 
00158               if (content_type &&
00159                   strcmp(content_type, "multipart/alternative") == 0)
00160                      rfcp=NULL;
00161 
00162               /* No attachments here */
00163        }
00164 
00165        for (q=rfcp ? rfcp->firstpart:0; q; q=q->next)
00166        {
00167        const char *content_type;
00168        const char *content_transfer_encoding;
00169        const char *charset;
00170        const char *name;
00171        const char *cn;
00172        char *content_name;
00173 
00174        off_t start_pos, end_pos, start_body;
00175 
00176               if (q->isdummy)      continue;
00177 
00178               rfc2045_mimeinfo(q, &content_type,
00179                      &content_transfer_encoding, &charset);
00180               if (!foundtextplain && HASTEXTPLAIN(q))
00181               {
00182                      foundtextplain=1;
00183                      continue;
00184               }
00185               rfc2045_mimepos(q, &start_pos, &end_pos, &start_body,
00186                      &dummy, &dummy);
00187 
00188               ++cnt;
00189               printf("<tr><td align=\"left\"><input type=\"checkbox\" name=\"del%d\" id=\"del%d\" />&nbsp;",
00190                      cnt, cnt);
00191 
00192               if (rfc2231_udecodeType(q, "name", sqwebmail_content_charset,
00193                                    &content_name) < 0 ||
00194                   rfc2231_udecodeDisposition(q, "filename",
00195                                           sqwebmail_content_charset,
00196                                           &content_name) < 0)
00197                      content_name=NULL;
00198 
00199               if (!content_name &&
00200                   ((cn=rfc2045_getattr(q->content_type_attr, "name")) ||
00201                    (cn=rfc2045_getattr(q->content_disposition_attr,
00202                                     "filename"))))
00203               {
00204                      content_name =
00205                             rfc822_display_hdrvalue_tobuf("subject",
00206                                                        cn,
00207                                                        sqwebmail_content_charset,
00208                                                        NULL,
00209                                                        NULL);
00210               }
00211 
00212               if ((!content_name || !*content_name) &&
00213                   strcmp(content_type, "application/pgp-keys") == 0)
00214                      name=getarg("KEYDESCR");
00215               else
00216               {
00217                      name=content_name;
00218               }
00219 
00220               attachment_showname(name);
00221               if (content_name)
00222                      free(content_name);
00223               printf("</td><td align=\"left\">&nbsp;&nbsp;<label for=\"del%d\">", cnt);
00224               output_attrencoded( content_type );
00225               printf("</label></td><td align=\"right\">%s<br /></td></tr>",
00226                      showsize(end_pos - start_body));
00227        }
00228 
00229        if (cnt == 0)
00230               printf("<tr><td align=\"center\">%s<br /></td></tr>\n",
00231                      noattach_lab);
00232        printf("</table>\n");
00233 }
00234 
00235 void attachments_opts(const char *draft)
00236 {
00237        char *filename;
00238        FILE *fp;
00239 
00240        CHECKFILENAME(draft);
00241 
00242        filename=maildir_find(INBOX "." DRAFTS, draft);
00243        if (!filename)
00244               return;
00245        fp=fopen(filename, "r");
00246        free(filename);
00247        if (!fp)
00248               return;
00249 
00250        printf("<label><input type=\"checkbox\" name=\"fcc\"%s />%s</label><br />",
00251               pref_noarchive ? "":" checked=\"checked\"",
00252               getarg("PRESERVELAB"));
00253        if (auth_getoptionenvint("wbnodsn") == 0)
00254               printf("<label><input type=\"checkbox\" name=\"dsn\" />%s</label><br />",
00255                      getarg("DSN"));
00256 
00257        if (libmail_gpg_has_gpg(GPGDIR) == 0)
00258        {
00259               char *all_addr;
00260 
00261               printf("<label><input type=\"checkbox\" "
00262                      "name=\"sign\" />%s</label><select name=\"signkey\">",
00263                      getarg("SIGNLAB"));
00264               gpgselectkey();
00265               printf("</select><br />\n");
00266 
00267               all_addr=newmsg_alladdrs(fp);
00268 
00269               printf("<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">"
00270                      "<tr valign=\"middle\"><td><input type=\"checkbox\""
00271                      " name=\"encrypt\" id=\"encrypt\" /></td><td><label for=\"encrypt\">%s</label></td>"
00272                      "<td><select size=\"4\" multiple=\"multiple\" name=\"encryptkey\">",
00273                      getarg("ENCRYPTLAB"));
00274               gpgencryptkeys(all_addr);
00275               printf("</select></td></tr>\n");
00276 
00277               if (ishttps())
00278                      printf("<tr valign=\"middle\"><td>&nbsp;</td><td>%s</td><td><input type=\"password\" name=\"passphrase\" /></td></tr>\n",
00279                             getarg("PASSPHRASE"));
00280 
00281               printf("</table><br />\n");
00282               if (all_addr)
00283                      free(all_addr);
00284        }
00285        fclose(fp);
00286 }
00287 
00288 static void attachment_showname(const char *name)
00289 {
00290        if (!name || !*name) name="[attachment]"; /* Eh??? */
00291        output_attrencoded(name);
00292 }
00293 
00294 static void attachment_open(const char *draft,
00295        FILE **fp,
00296        int    *fd2,
00297        struct rfc2045 **rfcp)
00298 {
00299 char   *oldname=maildir_find(INBOX "." DRAFTS, draft);
00300 
00301        if (!oldname) enomem();
00302 
00303        *fd2=maildir_safeopen(oldname, O_RDONLY, 0);
00304 
00305        *fp=0;
00306        if (*fd2 >= 0)
00307        {
00308               *fp=fdopen(*fd2, "r");
00309               if (*fp == NULL)
00310                      close(*fd2);
00311        }
00312 
00313        if (*fp == NULL)     enomem();
00314        *rfcp=rfc2045_fromfp( *fp );
00315        if (!*rfcp)   enomem();
00316 }
00317 
00318 static int messagecopy(FILE *fp, off_t start, off_t end)
00319 {
00320 char   buf[512];
00321 int    n;
00322 
00323        if (fseek(fp, start, SEEK_SET) == -1)     return (-1);
00324        while (start < end)
00325        {
00326               n=sizeof(buf);
00327               if (n > end - start)
00328                      n=end - start;
00329               n=fread(buf, 1, n, fp);
00330               if (n <= 0)   enomem();
00331               maildir_writemsg(newdraftfd, buf, n);
00332               start += n;
00333        }
00334        return (0);
00335 }
00336 
00337 /* Return non-zero if user selected all attachments for deletion */
00338 
00339 static int deleting_all_attachments(struct rfc2045 *p)
00340 {
00341 struct rfc2045 *q;
00342 const char *content_type;
00343 const char *content_transfer_encoding;
00344 const char *charset;
00345 int    foundtextplain, cnt;
00346 char   buf[MAXLONGSIZE+4];
00347 
00348        foundtextplain=0;
00349        cnt=0;
00350        for (q=p->firstpart; q; q=q->next)
00351        {
00352               rfc2045_mimeinfo(q, &content_type,
00353                      &content_transfer_encoding, &charset);
00354               if (q->isdummy)      continue;
00355 
00356               if (!foundtextplain && HASTEXTPLAIN(q))
00357               {
00358                      foundtextplain=1;
00359                      continue;
00360               }
00361 
00362               sprintf(buf, "del%d", ++cnt);
00363               if (*cgi(buf) == '\0')      return (0);
00364        }
00365        return (1);
00366 }
00367 
00368 static int del_final_attachment(FILE *fp, struct rfc2045 *rfcp)
00369 {
00370 struct rfc2045 *q;
00371 const char *content_type;
00372 const char *content_transfer_encoding;
00373 const char *charset;
00374 off_t start_pos, end_pos, start_body;
00375 off_t dummy;
00376 
00377        for (q=rfcp->firstpart; q; q=q->next)
00378        {
00379               if (q->isdummy)      continue;
00380               rfc2045_mimeinfo(q, &content_type,
00381                      &content_transfer_encoding, &charset);
00382               if (HASTEXTPLAIN(q))
00383                      break;
00384        }
00385        if (!q)       return (-1);
00386 
00387        if (fseek(fp, 0L, SEEK_SET) == -1) return (-1);
00388        newmsg_copy_nonmime_headers(fp);
00389        maildir_writemsgstr(newdraftfd, "mime-version: 1.0\n");
00390 
00391        rfc2045_mimepos(q, &start_pos, &end_pos, &start_body, &dummy, &dummy);
00392        return (messagecopy(fp, start_pos, end_pos));
00393 }
00394 
00395 static int del_some_attachments(FILE *fp, struct rfc2045 *rfcp)
00396 {
00397 struct rfc2045 *q;
00398 const char *content_type;
00399 const char *content_transfer_encoding;
00400 const char *charset;
00401 int    foundtextplain;
00402 int    cnt;
00403 const char *boundary=rfc2045_boundary(rfcp);
00404 off_t  start_pos, end_pos, start_body;
00405 off_t  dummy;
00406 
00407        rfc2045_mimepos(rfcp, &start_pos, &end_pos, &start_body, &dummy,
00408               &dummy);
00409        if (messagecopy(fp, 0, start_body))       return (-1);
00410 
00411        foundtextplain=0;
00412        cnt=0;
00413        for (q=rfcp->firstpart; q; q=q->next)
00414        {
00415               rfc2045_mimeinfo(q, &content_type,
00416                      &content_transfer_encoding, &charset);
00417               if (q->isdummy)
00418                      ;
00419               else if (!foundtextplain && HASTEXTPLAIN(q))
00420                      foundtextplain=1;
00421               else
00422               {
00423               char   buf[MAXLONGSIZE+4];
00424 
00425                      sprintf(buf, "del%d", ++cnt);
00426                      if (*cgi(buf))       continue;     /* This one's gone */
00427               }
00428 
00429               if (!q->isdummy)
00430               {
00431                      maildir_writemsgstr(newdraftfd, "\n--");
00432                      maildir_writemsgstr(newdraftfd, boundary);
00433                      maildir_writemsgstr(newdraftfd, "\n");
00434               }
00435               rfc2045_mimepos(q, &start_pos, &end_pos, &start_body, &dummy,
00436                      &dummy);
00437               if (messagecopy(fp, start_pos, end_pos))
00438                      return (-1);
00439        }
00440        maildir_writemsgstr(newdraftfd, "\n--");
00441        maildir_writemsgstr(newdraftfd, boundary);
00442        maildir_writemsgstr(newdraftfd, "--\n");
00443        return (0);
00444 }
00445 
00446 void attach_delete(const char *draft)
00447 {
00448 FILE   *fp;
00449 int    fd2;
00450 struct rfc2045 *rfcp;
00451 char   *draftfilename;
00452 int    isok=1;
00453 struct stat   stat_buf;
00454 
00455        attachment_open(draft, &fp, &fd2, &rfcp);
00456        if (!rfcp->firstpart)
00457        {
00458               rfc2045_free(rfcp);
00459               fclose(fp);
00460               return;       /* No attachments to delete */
00461        }
00462 
00463        if (fstat(fileno(fp), &stat_buf))
00464        {
00465               fclose(fp);
00466               enomem();
00467        }
00468 
00469        newdraftfd=maildir_recreatemsg(INBOX "." DRAFTS, draft, &draftfilename);
00470        if (newdraftfd < 0)
00471        {
00472               fclose(fp);
00473               enomem();
00474        }
00475 
00476        if (deleting_all_attachments(rfcp))
00477        {
00478               /* Deleting all attachments */
00479 
00480               if (del_final_attachment(fp, rfcp))       isok=0;
00481        }
00482        else
00483        {
00484               if (del_some_attachments(fp, rfcp))       isok=0;
00485        }
00486        fclose(fp);
00487        rfc2045_free(rfcp);
00488 
00489        if ( maildir_closemsg(newdraftfd, INBOX "." DRAFTS, draftfilename, isok,
00490               stat_buf.st_size))
00491        {
00492               free(draftfilename);
00493               enomem();
00494        }
00495        free(draftfilename);
00496        maildir_remcache(INBOX "." DRAFTS);       /* Cache file invalid now */
00497 }
00498 
00499 /* ---------------------------------------------------------------------- */
00500 /* Upload an attachment */
00501 
00502 static int isbinary;
00503 static int attachfd;
00504 static const char *cgi_attachname, *cgi_attachfilename;
00505 
00506 static int upload_start(const char *name, const char *filename, void *dummy)
00507 {
00508 const  char *p;
00509 
00510        p=strrchr(filename, '/');
00511        if (p) filename=p+1;
00512 
00513        p=strrchr(filename, '\\');
00514        if (p) filename=p+1;
00515 
00516        cgi_attachname=name;
00517        cgi_attachfilename=filename;
00518        isbinary=0;
00519        return (0);
00520 }
00521 
00522 static int upload_file(const char *ptr, size_t cnt, void *voidptr)
00523 {
00524 size_t i;
00525 
00526        for (i=0; i<cnt; i++)
00527               if ( (ptr[i] < ' ' || ptr[i] >= 127) && ptr[i] != '\n' &&
00528                      ptr[i] != '\r')
00529                      isbinary=1;
00530        maildir_writemsg(attachfd, ptr, cnt);
00531        return (0);
00532 }
00533 
00534 static void upload_end(void *dummy)
00535 {
00536 }
00537 
00538 #if 0
00539 static void writebase64encode(const char *p, size_t n)
00540 {
00541        maildir_writemsg(newdraftfd, p, n);
00542 }
00543 #endif
00544 
00545 static const char *search_mime_type(const char *mimetype, const char *filename)
00546 {
00547 FILE   *fp;
00548 char   *p, *q;
00549 
00550        if (!filename || !(filename=strrchr(filename, '.')))    return (0);
00551        ++filename;
00552 
00553        if ((fp=fopen(mimetype, "r")) == NULL)    return(0);
00554        while ((p=maildir_readline(fp)) != NULL)
00555        {
00556               if ((q=strchr(p, '#')) != NULL)    *q='\0';
00557               if ((p=strtok(p, " \t")) == NULL)  continue;
00558               while ((q=strtok(NULL, " \t")) != NULL)
00559                      if (strcasecmp(q, filename) == 0)
00560                      {
00561                             fclose(fp);
00562                             return (p);
00563                      }
00564        }
00565        fclose(fp);
00566        return (NULL);
00567 }
00568 
00569 const char *calc_mime_type(const char *filename)
00570 {
00571 static const char mimetypes[]=MIMETYPES;
00572 const char    *p;
00573 char *q;
00574 const char *r;
00575 char *s;
00576 
00577        p=mimetypes;
00578        if (!p)       enomem();
00579        while (*p)
00580        {
00581               if (*p == ':')
00582               {
00583                      ++p;
00584                      continue;
00585               }
00586               q=strdup(p);
00587               if (!q)       enomem();
00588               if ((s=strchr(q, ':')) != NULL)    *s='\0';
00589               if ((r=search_mime_type(q, filename)) != 0)
00590               {
00591                      free(q);
00592                      return (r);
00593               }
00594               free(q);
00595               while (*p && *p != ':')
00596                      p++;
00597        }
00598        return ("auto");
00599 }
00600 
00601 static int getkey(const char *keyname, int issecret)
00602 {
00603        int rc;
00604 
00605        if (!*keyname)
00606               return (1);
00607        upload_start("", "", NULL);
00608 
00609        rc=gpgexportkey(keyname, issecret, &upload_file, NULL);
00610        upload_end(NULL);
00611        return (rc);
00612 }
00613 
00614 #if 0
00615 static void write_disposition_param(const char *label, const char *value)
00616 {
00617 char   *p, *q;
00618 const char *r;
00619 
00620         while (value && ((r=strchr(value, ':')) || (r=strchr(value, '/'))
00621                 || (r=strchr(value, '\\'))))
00622                 value=r+1;
00623 
00624        if (!value || !*value)      return;
00625        maildir_writemsgstr(newdraftfd, "; ");
00626        maildir_writemsgstr(newdraftfd, label);
00627        maildir_writemsgstr(newdraftfd, "=\"");
00628        p=strdup(value);
00629        if (!p)       enomem();
00630        while ((q=strchr(p, '\\')) || (q=strchr(p, '"')))
00631               *q='_';
00632        maildir_writemsgstr(newdraftfd, p);
00633        maildir_writemsgstr(newdraftfd, "\"");
00634        free(p);
00635 }
00636 #endif
00637 
00638 static int cnt_filename(const char *param,
00639                      const char *value,
00640                      void *void_arg)
00641 {
00642        *(int *)void_arg += strlen(param)+strlen(value)+5;
00643        return 0;
00644 }
00645 
00646 static int save_filename(const char *param,
00647                       const char *value,
00648                       void *void_arg)
00649 {
00650        strcat(strcat(strcat(strcat((char *)void_arg, ";\n  "), param),
00651                     "="), value);
00652        return 0;
00653 }
00654 
00655 int attach_upload(const char *draft,
00656                 const char *attpubkey,
00657                 const char *attprivkey)
00658 {
00659        char   *attachfilename;
00660        char   *draftfilename;
00661        FILE   *draftfp;
00662        char   *boundary;
00663        FILE   *tempfp;
00664        struct rfc2045 *rfcp, *q;
00665        const char *content_type;
00666        const char *content_transfer_encoding;
00667        const char *charset;
00668        off_t  start_pos, end_pos, start_body;
00669        int    n;
00670        char   buf[BUFSIZ];
00671        int    pipefd[2];
00672        struct stat   stat_buf, attach_stat_buf;
00673        off_t  dummy;
00674        int    fd2;
00675        char   *filenamemime;
00676        char *argvec[20];
00677        char   *filenamebuf;
00678        pid_t pid1, pid2;
00679        int waitstat;
00680 
00681        /* Open the file containing the draft message */
00682 
00683        draftfilename=maildir_find(INBOX "." DRAFTS, draft);
00684        if (!draftfilename)  return (0);
00685 
00686        fd2=maildir_safeopen(draftfilename, O_RDONLY, 0);
00687 
00688        draftfp=0;
00689        if (fd2 >= 0)
00690        {
00691               draftfp=fdopen(fd2, "r");
00692               if (draftfp == NULL)
00693                      close(fd2);
00694        }
00695 
00696        if (draftfp == 0)
00697               enomem();
00698 
00699        free(draftfilename);
00700        if (fstat(fileno(draftfp), &stat_buf))
00701        {
00702               fclose(draftfp);
00703               enomem();
00704        }
00705 
00706        /* Create a temporary file in tmp where we'll temporarily store the
00707        ** attachment
00708        */
00709 
00710        attachfd=maildir_createmsg(INBOX "." DRAFTS, "temp", &attachfilename);
00711        if (attachfd < 0)
00712        {
00713               fclose(draftfp);
00714               enomem();
00715        }
00716 
00717        if ((
00718             attpubkey ? getkey(attpubkey, 0):
00719             attprivkey ? getkey(attprivkey, 1):
00720             cgi_getfiles( &upload_start, &upload_file, &upload_end, 1, NULL))
00721               || maildir_writemsg_flush(attachfd))
00722        {
00723               maildir_closemsg(attachfd, INBOX "." DRAFTS, attachfilename, 0, 0);
00724               free(attachfilename);
00725               fclose(draftfp);
00726               close(attachfd);
00727               return (0);
00728        }
00729 
00730        if (fstat(attachfd, &attach_stat_buf) ||
00731            attach_stat_buf.st_size + stat_buf.st_size > max_attach())
00732        {
00733               maildir_closemsg(attachfd, INBOX "." DRAFTS, attachfilename, 0, 0);
00734               maildir_deletenewmsg(attachfd, INBOX "." DRAFTS, attachfilename);
00735               free(attachfilename);
00736               fclose(draftfp);
00737               close(attachfd);
00738               return (-2);
00739        }
00740               
00741 
00742        /* Calculate new MIME content boundary */
00743 
00744        boundary=0;
00745        tempfp=0;
00746 
00747        n=dup(attachfd);
00748 
00749        if (n < 0)
00750        {
00751               fclose(draftfp);
00752               enomem();
00753        }
00754        tempfp=fdopen(n, "r");
00755        if (tempfp == 0)
00756        {
00757               fclose(draftfp);
00758               enomem();
00759        }
00760 
00761        do
00762        {
00763               if (boundary) free(boundary);
00764               boundary=multipart_boundary_create();
00765        } while ( multipart_boundary_checkf(boundary, draftfp) ||
00766                 multipart_boundary_checkf(boundary, tempfp));
00767 
00768        if (tempfp)   fclose(tempfp);
00769 
00770        /* Parse existing draft for its MIME structure */
00771 
00772        rfcp=rfc2045_fromfp(draftfp);
00773 
00774        rfc2045_mimeinfo(rfcp, &content_type,
00775               &content_transfer_encoding, &charset);
00776 
00777        /* Create a new version of the draft message */
00778 
00779        newdraftfd=maildir_recreatemsg(INBOX "." DRAFTS, draft, &draftfilename);
00780        if (newdraftfd < 0)
00781        {
00782               maildir_closemsg(attachfd, INBOX "." DRAFTS, attachfilename, 0, 0);
00783               fclose(draftfp);
00784               close(attachfd);
00785               enomem();
00786        }
00787 
00788        if (fseek(draftfp, 0L, SEEK_SET) < 0)
00789        {
00790               maildir_closemsg(newdraftfd, INBOX "." DRAFTS, draftfilename, 0, 0);
00791               maildir_closemsg(attachfd, INBOX "." DRAFTS, attachfilename, 0, 0);
00792               fclose(draftfp);
00793               close(attachfd);
00794               enomem();
00795        }
00796 
00797        newmsg_copy_nonmime_headers(draftfp);
00798 
00799        /* Create a multipart message, 1st attachment is the existing
00800        ** contents.
00801        */
00802 
00803        newmsg_create_multipart(newdraftfd, charset, boundary);
00804        maildir_writemsgstr(newdraftfd, "--");
00805        maildir_writemsgstr(newdraftfd, boundary);
00806        maildir_writemsgstr(newdraftfd, "\n");
00807 
00808        if (rfcp == NULL || strcmp(content_type, "multipart/mixed"))
00809        {
00810               int rc;
00811 
00812               /*
00813               ** The current draft does not have attachments.  Take its
00814               ** sole contents, and write it as a text/plain attachment.
00815               */
00816 
00817               if (fseek(draftfp, 0L, SEEK_SET) < 0)
00818                      rc = -1;
00819               else
00820               {
00821                      newmsg_copy_content_headers(draftfp);
00822                      maildir_writemsgstr(newdraftfd, "\n");
00823                      rfc2045_mimepos(rfcp, &start_pos, &end_pos,
00824                                    &start_body,
00825                                    &dummy, &dummy);
00826                      rc=messagecopy(draftfp, start_body, end_pos);
00827               }
00828 
00829               if (rc)
00830               {
00831                      maildir_closemsg(newdraftfd, INBOX "." DRAFTS, draftfilename,
00832                             0, 0);
00833                      maildir_closemsg(attachfd, INBOX "." DRAFTS, attachfilename,
00834                             0, 0);
00835                      fclose(draftfp);
00836                      close(newdraftfd);
00837                      close(attachfd);
00838                      enomem();
00839               }
00840 
00841               maildir_writemsgstr(newdraftfd, "\n--");
00842               maildir_writemsgstr(newdraftfd, boundary);
00843               maildir_writemsgstr(newdraftfd, "\n");
00844        }
00845        else
00846        {
00847               /* If the current draft already has MIME attachments,
00848               ** just copy them over to the new draft message.
00849               */
00850 
00851               for (q=rfcp->firstpart; q; q=q->next)
00852               {
00853                      if (q->isdummy)      continue;
00854                      rfc2045_mimepos(q, &start_pos, &end_pos, &start_body,
00855                                    &dummy, &dummy);
00856                      if (messagecopy(draftfp, start_pos, end_pos))
00857                      {
00858                             maildir_closemsg(newdraftfd, INBOX "." DRAFTS,
00859                                    draftfilename, 0, 0);
00860                             maildir_closemsg(attachfd, INBOX "." DRAFTS,
00861                                    attachfilename, 0, 0);
00862                             fclose(draftfp);
00863                             close(newdraftfd);
00864                             close(attachfd);
00865                             enomem();
00866                      }
00867                      maildir_writemsgstr(newdraftfd, "\n--");
00868                      maildir_writemsgstr(newdraftfd, boundary);
00869                      maildir_writemsgstr(newdraftfd, "\n");
00870               }
00871        }
00872 
00873        {
00874               const char *cp=strrchr(cgi_attachfilename, '/');
00875               int len;
00876               static const char fnStr[]="filename";
00877 
00878               if (cp)
00879                      ++cp;
00880               else
00881                      cp=cgi_attachfilename;
00882 
00883               len=1;
00884               rfc2231_attrCreate(fnStr, cp,
00885                                sqwebmail_content_charset,
00886                                sqwebmail_content_language,
00887                                &cnt_filename, &len);
00888 
00889               filenamemime=malloc(len);
00890 
00891               if (filenamemime)
00892               {
00893                      *filenamemime=0;
00894                      rfc2231_attrCreate(fnStr, cp,
00895                                       sqwebmail_content_charset,
00896                                       sqwebmail_content_language,
00897                                       save_filename, filenamemime);
00898               }
00899        }
00900 
00901        argvec[0]="makemime";
00902        argvec[1]="-c";
00903 
00904        if (attpubkey || attprivkey)
00905        {
00906               argvec[2]="application/pgp-keys";
00907               argvec[3]="-N";
00908               argvec[4]="pgpkeys.txt";
00909               argvec[5]="-a";
00910               argvec[6]="Content-Disposition: attachment; filename=\"pgpkeys.txt\"";
00911               n=7;
00912               filenamebuf=0;
00913        }
00914        else
00915        {
00916               const char *pp;
00917 
00918               argvec[2]=(char *)calc_mime_type(cgi_attachfilename);
00919               argvec[3]="-N";
00920               argvec[4]=cgi_attachfilename ?
00921                      (char *)cgi_attachfilename:"filename.dat";
00922               n=5;
00923 
00924               pp=*cgi("attach_inline") ?
00925                      "Content-Disposition: inline":
00926                      "Content-Disposition: attachment";
00927 
00928               filenamebuf=malloc(strlen(pp)+strlen(filenamemime ?
00929                                                filenamemime:"") + 15);
00930 
00931               if (filenamebuf)
00932               {
00933                      strcpy(filenamebuf, pp);
00934                      strcat(filenamebuf, filenamemime ? filenamemime:"");
00935 
00936                      argvec[n++]="-a";
00937                      argvec[n++]=filenamebuf;
00938               }
00939        }
00940 
00941        argvec[n++]="-C";
00942        argvec[n++]=(char *)sqwebmail_content_charset;
00943 
00944        signal(SIGCHLD, SIG_DFL);
00945 
00946        argvec[n++]="-";
00947        argvec[n++]=0;
00948 
00949        if (pipe(pipefd) < 0)
00950        {
00951               if (filenamemime)
00952                      free(filenamemime);
00953               if (filenamebuf)
00954                      free(filenamebuf);
00955               maildir_closemsg(newdraftfd, INBOX "." DRAFTS, draftfilename, 0, 0);
00956               maildir_closemsg(attachfd, INBOX "." DRAFTS, attachfilename, 0, 0);
00957               fclose(draftfp);
00958               close(newdraftfd);
00959               close(attachfd);
00960               enomem();
00961        }
00962 
00963        if (lseek(attachfd, 0L, SEEK_SET) < 0 || (pid1=fork()) < 0)
00964        {
00965               close(pipefd[0]);
00966               close(pipefd[1]);
00967               if (filenamemime)
00968                      free(filenamemime);
00969               if (filenamebuf)
00970                      free(filenamebuf);
00971               maildir_closemsg(newdraftfd, INBOX "." DRAFTS, draftfilename, 0, 0);
00972               maildir_closemsg(attachfd, INBOX "." DRAFTS, attachfilename, 0, 0);
00973               fclose(draftfp);
00974               close(newdraftfd);
00975               close(attachfd);
00976               enomem();
00977               return (0);
00978        }
00979 
00980        if (pid1 == 0)
00981        {
00982               dup2(attachfd, 0);
00983               dup2(pipefd[1], 1);
00984               close(attachfd);
00985               close(newdraftfd);
00986               close(pipefd[0]);
00987               close(pipefd[1]);
00988               execv(MAKEMIME, argvec);
00989               fprintf(stderr,
00990                      "CRIT: exec %s: %s\n", MAKEMIME, strerror(errno));
00991               exit(1);
00992        }
00993 
00994        if (filenamemime)
00995               free(filenamemime);
00996        if (filenamebuf)
00997               free(filenamebuf);
00998 
00999        close (pipefd[1]);
01000 
01001 
01002        while ((n=read(pipefd[0], buf, sizeof(buf))) > 0)
01003        {
01004               maildir_writemsg(newdraftfd, buf, n);
01005        }
01006        close(pipefd[0]);
01007 
01008        for (;;)
01009        {
01010               pid2=wait(&waitstat);
01011 
01012               if (pid2 == pid1)
01013               {
01014                      waitstat= WIFEXITED(waitstat) ? WEXITSTATUS(waitstat)
01015                             : 1;
01016                      break;
01017               }
01018 
01019               if (pid2 == -1)
01020               {
01021                      waitstat=1;
01022                      break;
01023               }
01024        }
01025 
01026        if (waitstat > 0 || n < 0)
01027        {
01028               maildir_closemsg(newdraftfd, INBOX "." DRAFTS, draftfilename, 0, 0);
01029               maildir_closemsg(attachfd, INBOX "." DRAFTS, attachfilename, 0, 0);
01030               fclose(draftfp);
01031               close(newdraftfd);
01032               maildir_deletenewmsg(attachfd, INBOX "." DRAFTS, attachfilename);
01033               close(attachfd);
01034               return (-3);
01035        }
01036 
01037        maildir_writemsgstr(newdraftfd, "\n--");
01038        maildir_writemsgstr(newdraftfd, boundary);
01039        maildir_writemsgstr(newdraftfd, "--\n");
01040 
01041        /* Finish new draft message, let it replace the current one */
01042 
01043        if (maildir_closemsg(newdraftfd, INBOX "." DRAFTS, draftfilename, 1,
01044               stat_buf.st_size))
01045        {
01046               maildir_closemsg(attachfd, INBOX "." DRAFTS, attachfilename, 0, 0);
01047               free(draftfilename);
01048               maildir_deletenewmsg(attachfd, INBOX "." DRAFTS, attachfilename);
01049               free(attachfilename);
01050               rfc2045_free(rfcp);
01051               fclose(draftfp);
01052               close(attachfd);
01053               return (-1);
01054        }
01055        free(draftfilename);
01056 
01057        fclose(draftfp);
01058 
01059        /* Remove and delete temp attachment file */
01060 
01061        maildir_deletenewmsg(attachfd, INBOX "." DRAFTS, attachfilename);
01062        free(attachfilename);
01063        rfc2045_free(rfcp);
01064        return (0);
01065 }
01066 
01067 void doattach(const char *folder, const char *draft)
01068 {
01069 int    quotaflag=0;
01070 
01071        CHECKFILENAME(draft);
01072        if (*cgi("dodelete"))
01073        {
01074               if (!tokencheck())
01075               {
01076                      attach_delete(draft);
01077                      tokensave();
01078               }
01079        }
01080        else if (*cgi("upload"))
01081        {
01082               if (!tokencheck())
01083               {
01084                      quotaflag=attach_upload(draft, NULL, NULL);
01085                      tokensave();
01086               }
01087        }
01088        else if (*cgi("uppubkey") && libmail_gpg_has_gpg(GPGDIR) == 0)
01089        {
01090               if (!tokencheck())
01091               {
01092                      quotaflag=attach_upload(draft, cgi("pubkey"), NULL);
01093                      tokensave();
01094               }
01095        }
01096        else if (*cgi("upprivkey") && *cgi("really") &&
01097                libmail_gpg_has_gpg(GPGDIR) == 0)
01098        {
01099               if (!tokencheck())
01100               {
01101                      quotaflag=attach_upload(draft, NULL, cgi("privkey"));
01102                      tokensave();
01103               }
01104        }
01105        else if (*cgi("previewmsg"))
01106        {
01107               cgi_put("draft", draft);
01108               newmsg_do(folder);
01109               return;
01110        }
01111        else if (*cgi("sendmsg"))
01112        {
01113               cgi_put("draftmessage", draft);
01114               newmsg_do(folder);
01115               return;
01116        }
01117        else if (*cgi("savedraft"))
01118        {
01119               sendmsg_done();
01120               return;
01121        }
01122 
01123        if (quotaflag == -2)
01124         {
01125                 http_redirect_argss(
01126                   "&form=attachments&pos=%s&draft=%s&error=limits",
01127                   cgi("pos"), draft);
01128         }
01129        else if (quotaflag == -3)
01130        {
01131                 http_redirect_argss(
01132                   "&form=attachments&pos=%s&draft=%s&error=makemime",
01133                   cgi("pos"), draft);
01134        }
01135         else
01136         {
01137                 http_redirect_argss(
01138                   (quotaflag ? "&form=attachments&pos=%s&draft=%s&error=quota":
01139                   "&form=attachments&pos=%s&draft=%s"), cgi("pos"),
01140                   draft);
01141         }
01142 }