Back to index

courier  0.68.2
newmsg_create.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 1998 - 2009 Double Precision, Inc.  See COPYING for
00003 ** distribution information.
00004 */
00005 
00006 
00007 /*
00008 */
00009 #include      "config.h"
00010 #include      "cgi/cgi.h"
00011 #include      "sqconfig.h"
00012 #include      "sqwebmail.h"
00013 #include      "auth.h"
00014 #include      "maildir.h"
00015 #include      "newmsg.h"
00016 #include      "folder.h"
00017 #include      "filter.h"
00018 #include      "pref.h"
00019 #include      "gpg.h"
00020 #include      "addressbook.h"
00021 #include      "maildir/maildirmisc.h"
00022 #include      "rfc822/rfc822.h"
00023 #include      "rfc2045/rfc2045.h"
00024 #include      "rfc822/rfc2047.h"
00025 #include      "rfc822/encode.h"
00026 #include      "rfc822/rfc822hdr.h"
00027 #include      "msg2html.h"
00028 #include      "gpglib/gpglib.h"
00029 #include      "http11/http11.h"
00030 #include      "htmllibdir.h"
00031 #include      "unicode/unicode.h"
00032 #include      "courierauth.h"
00033 
00034 #include      <stdlib.h>
00035 #if HAVE_UNISTD_H
00036 #include      <unistd.h>
00037 #endif
00038 #include      <ctype.h>
00039 #include      <fcntl.h>
00040 
00041 #define HASTEXTPLAIN(q) (rfc2045_searchcontenttype((q), "text/plain") != NULL)
00042 /* Also in attachments.c */
00043 
00044 extern const char *rfc822_mkdt(time_t);
00045 
00046 extern const char *sqwebmail_content_charset;
00047 extern const char *sqwebmail_content_language;
00048 
00049 int newdraftfd;
00050 extern const char *sqwebmail_mailboxid;
00051 
00052 const char mimemsg[]="This is a MIME-formatted message.  If you see this text it means that your\nmail software cannot handle MIME-formatted messages.\n\n";
00053 
00054 char *newmsg_createdraft_do(const char *, const char *, int);
00055 
00056 /* Save message in a draft file */
00057 
00058 char *newmsg_createdraft(const char *curdraft)
00059 {
00060        if (curdraft && *curdraft)
00061        {
00062        char   *base=maildir_basename(curdraft);
00063        char   *filename=maildir_find(INBOX "." DRAFTS, base);
00064 
00065               if (filename)
00066               {
00067               char   *p=newmsg_createdraft_do(filename, cgi("message"), 0);
00068 
00069                      free(filename);
00070                      free(base);
00071                      return (p);
00072               }
00073               free(base);
00074        }
00075        return (newmsg_createdraft_do(0, cgi("message"), 0));
00076 }
00077 
00078 static void create_draftheader_do(const char *hdrname, const char *p,
00079        int isrfc822addr);
00080 
00081 static void create_draftheader(const char *hdrname, const char *p,
00082                             const char *q, int isrfc822addr)
00083 {
00084        if (q && *q)  /* Add from address book */
00085        {
00086        char   *nick=cgi_multiple("nick", ",");
00087        char   *s;
00088 
00089               if (nick)
00090               {
00091                      s=malloc(strlen(p)+strlen(nick)+2);
00092 
00093                      if (s)
00094                      {
00095                             strcpy(s, p);
00096                             if (*s && *nick)     strcat(s, ",");
00097                             strcat(s, nick);
00098                             create_draftheader_do(hdrname, s, isrfc822addr);
00099                             free(s);
00100                             free(nick);
00101                             return;
00102                      }
00103                      free(nick);
00104               }
00105 
00106        }
00107        create_draftheader_do(hdrname, p, isrfc822addr);
00108 }
00109 
00110 #define       ISLWS(c)      ((c)=='\t' || (c)=='\r' || (c)=='\n' || (c)==' ')
00111 
00112 static void header_wrap(const char *name, const char *hdr,
00113                      char *outbuf, size_t *outcnt)
00114 {
00115 char   *pfix;
00116 size_t offset=strlen(name);
00117 
00118        *outcnt=0;
00119        pfix="";
00120 
00121        while (*hdr)
00122        {
00123        size_t i;
00124        size_t spc;
00125 
00126               for (spc=0, i=0; hdr[i]; i++)
00127               {
00128                      if (i + offset >= 75 && spc)
00129                      {
00130                              i = spc;
00131                             offset = 0;
00132                             break;
00133                      }
00134 
00135                      if (ISLWS(hdr[i]))
00136                      {
00137                             spc = i;
00138                             while (ISLWS(hdr[i+1]))
00139                                    ++i;
00140                      }
00141               }
00142 
00143               if (outbuf)
00144               {
00145                      strcpy(outbuf, pfix);
00146                      outbuf += strlen(pfix);
00147               }
00148               *outcnt += strlen(pfix);
00149 
00150               if (outbuf)
00151               {
00152               size_t j;
00153                      for (j=0; j < i; j++)
00154                      {
00155                             if (ISLWS(hdr[j]))
00156                             {
00157                                    *(outbuf++) = ' ';
00158                                    while (ISLWS(hdr[j+1]))
00159                                           ++j;
00160                             }
00161                             else
00162                                    *(outbuf++) = hdr[j];
00163                      }
00164               }
00165               *outcnt += i;
00166               pfix="\n  ";
00167               hdr += i;
00168               while (ISLWS(*hdr))
00169                      ++hdr;
00170        }
00171        if (outbuf)
00172               *outbuf=0;
00173        ++*outcnt;
00174 }
00175                      
00176 static void create_draftheader_do(const char *hdrname, const char *p,
00177        int isrfc822addr)
00178 {
00179 char   *s, *t;
00180 size_t l;
00181 
00182        if (!*p)      return;
00183 
00184        if (!isrfc822addr)
00185        {
00186               s=rfc2047_encode_str(p, sqwebmail_content_charset,
00187                                  rfc2047_qp_allow_any);
00188        }
00189        else
00190        {
00191               s=rfc2047_encode_header_tobuf("to", p,
00192                                          sqwebmail_content_charset);
00193        }
00194 
00195        header_wrap(hdrname, s, NULL, &l);
00196        if (l)
00197        {
00198               if (!(t=malloc(l))) enomem();
00199               header_wrap(hdrname, s, t, &l);
00200               if (*t)
00201               {
00202                      free(s);
00203                      s = t;
00204               }
00205               else
00206                      free(t);
00207        }
00208 
00209        if (!s)
00210        {
00211               close(newdraftfd);
00212               enomem();
00213        }
00214        maildir_writemsgstr(newdraftfd, hdrname);
00215        maildir_writemsgstr(newdraftfd, s);
00216        maildir_writemsgstr(newdraftfd, "\n");
00217        free(s);
00218 }
00219 
00220 void newmsg_create_multipart(int newdraftfd, const char *charset,
00221                      const char *multipart_boundary)
00222 {
00223        maildir_writemsgstr(newdraftfd,
00224               "Mime-version: 1.0\n"
00225               "Content-Type: multipart/mixed; boundary=\"");
00226        maildir_writemsgstr(newdraftfd, multipart_boundary);
00227        maildir_writemsgstr(newdraftfd, "\"; charset=\"");
00228        maildir_writemsgstr(newdraftfd, charset);
00229        maildir_writemsgstr(newdraftfd, 
00230                                    "\"\n\n");
00231 
00232        maildir_writemsgstr(newdraftfd, mimemsg);
00233 }
00234 
00235 
00236 static char   *newmsg_multipart_boundary(FILE *, const char *);
00237 static void newmsg_copy_attachments(struct rfc2045 *, FILE *, const char *);
00238 
00239 void newmsg_copy_nonmime_headers(FILE *fp)
00240 {
00241 char   *header, *value;
00242 char   *q;
00243 
00244        while ((header=maildir_readheader(fp, &value, 1)) != NULL)
00245        {
00246               if (strcmp(header, "mime-version") == 0 ||
00247                      strncmp(header, "content-", 8) == 0)      continue;
00248 
00249               /* Fluff - capitalize header names */
00250 
00251               for (q=header; *q; q++)
00252               {
00253                      for (*q=toupper(*q); *q; q++)
00254                             if (*q == '-')       break;
00255                      if (!*q)
00256                             break;
00257               }
00258 
00259               maildir_writemsgstr(newdraftfd, header);
00260               maildir_writemsgstr(newdraftfd, ": ");
00261               maildir_writemsgstr(newdraftfd, value);
00262               maildir_writemsgstr(newdraftfd, "\n");
00263        }
00264 }
00265 
00266 void newmsg_copy_content_headers(FILE *fp)
00267 {
00268 char   *header, *value;
00269 char   *q;
00270 
00271        while ((header=maildir_readheader(fp, &value, 1)) != NULL)
00272        {
00273               if (strncmp(header, "content-", 8)) continue;
00274 
00275               for (q=header; *q; q++)
00276               {
00277                      for (*q=toupper(*q); *q; q++)
00278                             if (*q == '-')       break;
00279                      if (!*q)
00280                             break;
00281               }
00282 
00283               maildir_writemsgstr(newdraftfd, header);
00284               maildir_writemsgstr(newdraftfd, ": ");
00285               maildir_writemsgstr(newdraftfd, value);
00286               maildir_writemsgstr(newdraftfd, "\n");
00287        }
00288 }
00289 
00290 void wrap_text_init(struct wrap_info *uw,
00291                   const char *output_chset,
00292                   void (*output_func)(const char *p, size_t l, void *arg),
00293                   void *arg)
00294 {
00295        memset(uw, 0, sizeof(*uw));
00296        uw->output_func=output_func;
00297        uw->output_chset=output_chset;
00298        uw->arg=arg;
00299 }
00300 
00301 static void do_save_u_line(struct wrap_info *uw,
00302                         const unicode_char *uc,
00303                         size_t ucsize,
00304                         int flowed)
00305 {
00306        char *cbuf;
00307        size_t csize;
00308 
00309        libmail_u_convert_handle_t h=
00310               libmail_u_convert_fromu_init(uw->output_chset,
00311                                         &cbuf,
00312                                         &csize,
00313                                         0);
00314 
00315        if (h)
00316        {
00317               if (ucsize)
00318               {
00319                      if (uc[0] == ' ')
00320                             libmail_u_convert_uc(h, uc, 1);
00321                      /* Space stuff */
00322 
00323                      libmail_u_convert_uc(h, uc, ucsize);
00324               }
00325               if (flowed)
00326               {
00327                      unicode_char spc=' ';
00328                      libmail_u_convert_uc(h, &spc, 1);
00329               }
00330 
00331               {
00332                      unicode_char nl='\n';
00333                      libmail_u_convert_uc(h, &nl, 1);
00334               }
00335 
00336               if (libmail_u_convert_deinit(h, NULL))
00337                      cbuf=NULL;
00338        }
00339        else
00340               cbuf=NULL;
00341 
00342        if (cbuf)
00343        {
00344               (*uw->output_func)(cbuf, csize, uw->arg);
00345               free(cbuf);
00346        }
00347 }
00348 
00349 static void flush_line(struct wrap_info *uw, int flowed)
00350 {
00351        do_save_u_line(uw, uw->uc + uw->line_start,
00352                      uw->word_start - uw->line_start, flowed);
00353 
00354        uw->line_start=uw->word_start;
00355        uw->line_width=0;
00356 }
00357 
00358 static void add_word(struct wrap_info *uw)
00359 {
00360        if (uw->line_start < uw->word_start &&
00361            uw->line_width + uw->word_width > MYLINESIZE)
00362               flush_line(uw, 1);
00363 
00364        uw->line_width += uw->word_width;
00365 
00366        uw->word_start=uw->cur_index;
00367        uw->word_width=0;
00368 }
00369 
00370 static int do_save_u_process_lb(int type, void *arg)
00371 {
00372        struct wrap_info *uw=(struct wrap_info *)arg;
00373 
00374        if (uw->cur_index >= uw->ucsize)
00375               enomem();
00376 
00377        if (type != UNICODE_LB_NONE)
00378        {
00379               add_word(uw);
00380               if (type == UNICODE_LB_MANDATORY)
00381                      flush_line(uw, 0);
00382        }
00383 
00384 
00385        if (uw->word_width >= MYLINESIZE &&
00386            uw->cur_index > 0 &&
00387            unicode_grapheme_break(uw->uc[uw->cur_index-1],
00388                                uw->uc[uw->cur_index]))
00389               add_word(uw);
00390 
00391        uw->word_width += unicode_wcwidth(uw->uc[uw->cur_index]);
00392        ++uw->cur_index;
00393        return 0;
00394 }
00395 
00396 static void do_wrap_u_line(struct wrap_info *uw,
00397                         const unicode_char *uc,
00398                         size_t ucsize)
00399 {
00400        unicode_lb_info_t lb;
00401 
00402        while (ucsize && uc[ucsize-1] == ' ')
00403               --ucsize;
00404 
00405        uw->uc=uc;
00406        uw->ucsize=ucsize;
00407        uw->cur_index=0;
00408        uw->word_start=0;
00409        uw->word_width=0;
00410 
00411        uw->line_start=0;
00412        uw->line_width=0;
00413        if ((lb=unicode_lb_init(do_save_u_process_lb, uw)) != NULL)
00414        {
00415               unicode_lb_set_opts(lb,
00416                                 UNICODE_LB_OPT_PRBREAK
00417                                 | UNICODE_LB_OPT_SYBREAK);
00418               unicode_lb_next_cnt(lb, uc, ucsize);
00419               unicode_lb_end(lb);
00420               add_word(uw);
00421               flush_line(uw, 0);
00422        }
00423 }
00424 
00425 static void save_textplain(const char *p, size_t l, void *dummy)
00426 {
00427        maildir_writemsg(newdraftfd, p, l);
00428 }
00429 
00430 void wrap_text(struct wrap_info *uw,
00431               const char *newmsg,
00432               size_t newmsg_size)
00433 {
00434        size_t i=0, j;
00435 
00436        while (i < newmsg_size)
00437        {
00438               unicode_char *uc;
00439               size_t ucsize;
00440               libmail_u_convert_handle_t h;
00441 
00442               j=i;
00443 
00444               while (i<newmsg_size && newmsg[i] != '\n')
00445                      ++i;
00446 
00447               h=libmail_u_convert_tou_init(sqwebmail_content_charset,
00448                                         &uc, &ucsize, 0);
00449 
00450               if (h)
00451               {
00452                      libmail_u_convert(h, newmsg+j, i-j);
00453 
00454                      if (libmail_u_convert_deinit(h, NULL))
00455                             uc=NULL;
00456               }
00457               else
00458               {
00459                      uc=NULL;
00460               }
00461 
00462               if (uc)
00463               {
00464                      size_t i, j;
00465 
00466                      /* Get rid of any CRs that sneak in */
00467 
00468                      for (i=j=0; i<ucsize; ++i)
00469                      {
00470                             if (uc[i] == '\r')
00471                                    continue;
00472 
00473                             uc[j]=uc[i];
00474                             ++j;
00475                      }
00476 
00477                      if (j && *uc == '>')
00478                             do_save_u_line(uw, uc, j, 0);
00479                      else
00480                             do_wrap_u_line(uw, uc, j);
00481 
00482                      free(uc);
00483               }
00484 
00485               if (i < newmsg_size)
00486                      ++i;
00487        }
00488 }
00489 
00490 static void convert_text2html(const char *p, size_t l, void *arg)
00491 {
00492        struct msg2html_textplain_info *info=
00493               (struct msg2html_textplain_info *)arg;
00494 
00495        msg2html_textplain(info, p, l);
00496 }
00497 
00498 static char *mkurl(const char *url, void *dummy)
00499 {
00500        char *buf=malloc(strlen(url)*2+100);
00501 
00502        if (!buf)
00503               return NULL;
00504 
00505        /* msg2html guarantees that the characters in url are "safe" */
00506 
00507        sprintf(buf, "<a href=\"%s\">%s</a>", url, url);
00508        return buf;
00509 }
00510 
00511 char *newmsg_createdraft_do(const char *curdraft, const char *newmsg,
00512        int keepheader)
00513 {
00514 char   *draftfilename;
00515 FILE   *fp=0;
00516 char   *multipart_boundary;
00517 const char *content_type;
00518 const char *content_transfer_encoding;
00519 const char *charset;
00520 unsigned long prev_size=0;
00521 off_t  transferencodingpos;
00522 off_t  transferencoding2pos;
00523 int is_newevent=strcmp(cgi("form"), "newevent") == 0;
00524 struct rfc2045       *rfcp;
00525 int has_attachments=0;
00526 size_t newmsg_size;
00527 char *sig, *footer;
00528 
00529 /*
00530 ** Trim extra newlines.
00531 */
00532        newmsg_size=strlen(newmsg);
00533 
00534        while (newmsg_size && newmsg[newmsg_size-1] == '\n')
00535               --newmsg_size;
00536 
00537 /* We're on the 'new event' screen */
00538 
00539        if (curdraft) /* Reuse a draft filename */
00540               newdraftfd=maildir_recreatemsg(INBOX "." DRAFTS, curdraft, &draftfilename);
00541        else
00542               newdraftfd=maildir_createmsg(INBOX "." DRAFTS, 0, &draftfilename);
00543        if (newdraftfd < 0)  enomem();
00544 
00545        pref_wikifmt=0;
00546        if (strcmp(cgi("textformat"), "wiki") == 0)
00547               pref_wikifmt=1;
00548        pref_update();
00549 
00550        fp=NULL;
00551        if (curdraft)
00552        {
00553        int    x=maildir_safeopen(curdraft, O_RDONLY, 0);
00554 
00555               if (x >= 0)
00556                      if ((fp=fdopen(x, "r")) == 0)
00557                             close(x);
00558        }
00559 
00560        if (fp)
00561        {
00562        char   *header, *value;
00563        struct stat   stat_buf;
00564 
00565               if (fstat(fileno(fp), &stat_buf))
00566               {
00567                      fclose(fp);
00568                      enomem();
00569               }
00570               prev_size=stat_buf.st_size;
00571 
00572               while ((header=maildir_readheader(fp, &value, 1)) != NULL)
00573               {
00574                      if (keepheader == NEWMSG_SQISPELL)
00575                      {
00576                             if (strcasecmp(header, "mime-version") == 0 ||
00577                                 strncasecmp(header, "content-", 8) == 0)
00578                                    continue;
00579                      }
00580                      else if (keepheader == NEWMSG_PCP)
00581                      {
00582                             if (strcasecmp(header, "mime-version") == 0 ||
00583                                 strncasecmp(header, "content-", 8) == 0 ||
00584                                 strcasecmp(header, "date") == 0 ||
00585                                 strcasecmp(header, "from") == 0 ||
00586                                 strcasecmp(header, "subject") == 0)
00587                                    continue;
00588                      }
00589                      else
00590                      {
00591                             if (strcmp(header, "in-reply-to") &&
00592                                    strcmp(header, "references") &&
00593                                    strncmp(header, "x-", 2))   continue;
00594                             /* Do not discard these headers */
00595                      }
00596 
00597                      if (strcasecmp(header, "x-sqwebmail-wikifmt") == 0)
00598                             continue;
00599 
00600                      maildir_writemsgstr(newdraftfd, header);
00601                      maildir_writemsgstr(newdraftfd, ": ");
00602                      maildir_writemsgstr(newdraftfd, value);
00603                      maildir_writemsgstr(newdraftfd, "\n");
00604               }
00605        }
00606        else if (is_newevent)
00607               maildir_writemsgstr(newdraftfd, "X-Event: 1\n");
00608 
00609        if (!keepheader
00610            || keepheader == NEWMSG_PCP)
00611        /* Coming back from msg edit, set headers */
00612        {
00613        const  char *p=cgi("headerfrom");
00614 
00615               if (!*p)      p=pref_from;
00616               if (!p || !*p || auth_getoptionenvint("wbnochangingfrom"))
00617                      p=login_fromhdr();
00618 
00619               create_draftheader("From: ", p, 0, 1);
00620 
00621               if (!pref_from || strcmp(p, pref_from))
00622                      pref_setfrom(p);
00623 
00624 /* sam ????
00625        create_draftheader("In-Reply-To: ", cgi("headerin-reply-to"));
00626 */
00627               if (!is_newevent)
00628               {
00629 #if 0
00630                      {
00631                             FILE *fp;
00632                             fp=fopen("/tmp/pid", "w");
00633                             fprintf(fp, "%d", getpid());
00634                             fclose(fp);
00635                             sleep(10);
00636                      }
00637 #endif
00638 
00639                      create_draftheader("To: ", cgi("headerto"),
00640                                       cgi("addressbook_to"), 1);
00641                      create_draftheader("Cc: ", cgi("headercc"),
00642                                       cgi("addressbook_cc"), 1);
00643                      create_draftheader("Bcc: ", cgi("headerbcc"),
00644                                       cgi("addressbook_bcc"), 1);
00645                      create_draftheader("Reply-To: ", cgi("headerreply-to"), 0, 1);
00646               }
00647        }
00648 
00649        if (pref_wikifmt)
00650               create_draftheader("x-sqwebmail-wikifmt: ", "1", 0, 0);
00651 
00652        if (!keepheader || keepheader == NEWMSG_PCP)
00653        {
00654        time_t t;
00655 
00656               create_draftheader("Subject: ", cgi("headersubject"), 0, 0);
00657 
00658               time(&t);
00659               create_draftheader("Date: ", rfc822_mkdate(t), 0, 0);
00660        }
00661 
00662        /* If the message has attachments, calculate multipart boundary */
00663 
00664        rfcp=NULL;
00665 
00666        if (fp)
00667        {
00668               rfcp=rfc2045_fromfp(fp);
00669               if (!rfcp)
00670               {
00671                      close(newdraftfd);
00672                      fclose(fp);
00673                      enomem();
00674               }
00675        }
00676 
00677        multipart_boundary=newmsg_multipart_boundary(fp, newmsg);
00678 
00679        if (rfcp && rfcp->firstpart &&
00680            strcmp((rfc2045_mimeinfo(rfcp, &content_type,
00681                            &content_transfer_encoding, &charset),
00682                   content_type), "multipart/mixed") == 0)
00683        {
00684               has_attachments=1;
00685               newmsg_create_multipart(newdraftfd,
00686                      sqwebmail_content_charset, multipart_boundary);
00687 
00688               maildir_writemsgstr(newdraftfd, "--");
00689               maildir_writemsgstr(newdraftfd, multipart_boundary);
00690               maildir_writemsgstr(newdraftfd,"\n");
00691        }
00692        else
00693        {
00694               maildir_writemsgstr(newdraftfd, "Mime-Version: 1.0\n");
00695        }
00696 
00697        if (pref_wikifmt)
00698        {
00699               ++multipart_boundary[strlen(multipart_boundary)-1];
00700 
00701               maildir_writemsgstr(newdraftfd,
00702                                 "Content-Type: multipart/alternative;"
00703                                 " boundary=\"");
00704               maildir_writemsgstr(newdraftfd, multipart_boundary);
00705               maildir_writemsgstr(newdraftfd, "\"\n"
00706                                 "\n"
00707                                 "\n"
00708                                 "--");
00709               maildir_writemsgstr(newdraftfd, multipart_boundary);
00710               maildir_writemsgstr(newdraftfd, "\n");
00711        }
00712 
00713        maildir_writemsgstr(newdraftfd,
00714                          "Content-Type: text/plain; format=flowed; delsp=yes;"
00715                          " charset=\"");
00716        maildir_writemsgstr(newdraftfd, sqwebmail_content_charset);
00717        maildir_writemsgstr(newdraftfd, "\"\n");
00718 
00719        maildir_writemsgstr(newdraftfd, "Content-Transfer-Encoding: ");
00720        transferencoding2pos=transferencodingpos=writebufpos;
00721        maildir_writemsgstr(newdraftfd, "7bit\n\n");
00722 
00723        /*     maildir_writemsgstr(newdraftfd, "\n"); */
00724 
00725        sig=pref_getsig();
00726        footer=pref_getfile(http11_open_langfile(get_templatedir(),
00727                                            sqwebmail_content_language,
00728                                            "footer"));
00729 
00730        while (newmsg_size &&
00731               (newmsg[newmsg_size-1] == '\r' ||
00732               newmsg[newmsg_size-1] == '\n'))
00733               --newmsg_size;
00734 
00735        {
00736               struct wrap_info uw;
00737 
00738               wrap_text_init(&uw, sqwebmail_content_charset,
00739                             save_textplain, NULL);
00740 
00741               wrap_text(&uw, newmsg, newmsg_size);
00742 
00743               if ((sig && *sig) || (footer && *footer))
00744               {
00745                      static const unicode_char sig_line[]={'-', '-', ' '};
00746 
00747                      do_save_u_line(&uw, sig_line, 0, 0);
00748                      do_save_u_line(&uw, sig_line, 3, 0);
00749               }
00750 
00751               if (sig && *sig)
00752                      wrap_text(&uw, sig, strlen(sig));
00753 
00754               if (footer && *footer)
00755               {
00756                      do_save_u_line(&uw, NULL, 0, 0);
00757                      maildir_writemsg(newdraftfd, footer, strlen(footer));
00758               }
00759 
00760        }
00761 
00762        if (pref_wikifmt)
00763        {
00764               struct msg2html_textplain_info *info;
00765 
00766               maildir_writemsgstr(newdraftfd, "\n"
00767                                 "--");
00768               maildir_writemsgstr(newdraftfd, multipart_boundary);
00769               maildir_writemsgstr(newdraftfd, "\n"
00770                                 "Content-Type: text/html; charset=\"");
00771               maildir_writemsgstr(newdraftfd, sqwebmail_content_charset);
00772               maildir_writemsgstr(newdraftfd, "\"\n"
00773                                 "Content-Transfer-Encoding: ");
00774               transferencoding2pos=writebufpos;
00775               maildir_writemsgstr(newdraftfd, "7bit\n\n");
00776 
00777               info=msg2html_textplain_start(sqwebmail_content_charset,
00778                                          sqwebmail_content_charset,
00779                                          1,
00780                                          1,
00781                                          0,
00782                                          mkurl, NULL,
00783                                          NULL,
00784                                          NULL,
00785                                          1,
00786                                          save_textplain,
00787                                          NULL);
00788 
00789               if (info)
00790               {
00791                      struct wrap_info uw;
00792 
00793                      wrap_text_init(&uw, sqwebmail_content_charset,
00794                                    convert_text2html, info);
00795 
00796                      wrap_text(&uw, newmsg, newmsg_size);
00797                      msg2html_textplain_end(info);
00798               }
00799 
00800               if ((sig && *sig) || (footer && *footer))
00801                      save_textplain("<hr />\n", 7, NULL);
00802 
00803               if (sig && *sig)
00804               {
00805 
00806                      info=msg2html_textplain_start(sqwebmail_content_charset,
00807                                                 sqwebmail_content_charset,
00808                                                 1,
00809                                                 1,
00810                                                 0,
00811                                                 mkurl, NULL,
00812                                                 NULL,
00813                                                 NULL,
00814                                                 1,
00815                                                 save_textplain,
00816                                                 NULL);
00817 
00818                      if (info)
00819                      {
00820                             struct wrap_info uw;
00821 
00822                             wrap_text_init(&uw, sqwebmail_content_charset,
00823                                           convert_text2html, info);
00824 
00825                             wrap_text(&uw, sig, strlen(sig));
00826                             msg2html_textplain_end(info);
00827                      }
00828               }
00829 
00830               if (footer && *footer)
00831               {
00832                      save_textplain("<br />\n", 7, NULL);
00833 
00834                      info=msg2html_textplain_start(sqwebmail_content_charset,
00835                                                 sqwebmail_content_charset,
00836                                                 1,
00837                                                 1,
00838                                                 0,
00839                                                 mkurl, NULL,
00840                                                 NULL,
00841                                                 NULL,
00842                                                 1,
00843                                                 save_textplain,
00844                                                 NULL);
00845 
00846                      if (info)
00847                      {
00848                             msg2html_textplain(info, footer,
00849                                              strlen(footer));
00850                             msg2html_textplain_end(info);
00851                      }
00852               }
00853 
00854               maildir_writemsgstr(newdraftfd, "\n"
00855                                 "--");
00856               maildir_writemsgstr(newdraftfd, multipart_boundary);
00857               maildir_writemsgstr(newdraftfd, "--\n");
00858               --multipart_boundary[strlen(multipart_boundary)-1];
00859 
00860        }
00861 
00862        if (sig)
00863               free(sig);
00864 
00865        if (footer)
00866               free(footer);
00867 
00868        if ( multipart_boundary && rfcp && has_attachments)
00869        {
00870               newmsg_copy_attachments(rfcp, fp, multipart_boundary);
00871               maildir_writemsgstr(newdraftfd, "\n--");
00872               maildir_writemsgstr(newdraftfd, multipart_boundary);
00873               maildir_writemsgstr(newdraftfd, "--\n");
00874               free(multipart_boundary);
00875        }
00876        if (fp)       fclose(fp);
00877        if (rfcp)
00878               rfc2045_free(rfcp);
00879 
00880        if ( maildir_writemsg_flush(newdraftfd) == 0 && writebuf8bit)
00881        {
00882               if (lseek(newdraftfd, transferencodingpos, SEEK_SET) < 0 ||
00883                      write(newdraftfd, "8", 1) != 1 ||
00884                   lseek(newdraftfd, transferencoding2pos, SEEK_SET) < 0 ||
00885                      write(newdraftfd, "8", 1) != 1)
00886               {
00887                      close(newdraftfd);
00888                      enomem();
00889               }
00890        }
00891 
00892        if ( maildir_closemsg(newdraftfd, INBOX "." DRAFTS, draftfilename, -1, prev_size))
00893               cgi_put("error", "quota");
00894 
00895        return(draftfilename);
00896 }
00897 
00898 static void sentmsg_copy(FILE *f, struct rfc2045 *p)
00899 {
00900        off_t start_pos, end_pos, start_body;
00901        char buf[BUFSIZ];
00902        int n;
00903        off_t   dummy;
00904 
00905         rfc2045_mimepos(p, &start_pos, &end_pos, &start_body, &dummy, &dummy);
00906         if (fseek(f, start_pos, SEEK_SET) == -1)
00907         {
00908                 fclose(f);
00909                 close(newdraftfd);
00910                 enomem();
00911         }
00912 
00913         while (start_pos < end_pos)
00914         {
00915         int     cnt=sizeof(buf);
00916 
00917                 if (cnt > end_pos - start_pos)
00918                         cnt=end_pos - start_pos;
00919 
00920                 if ((n=fread(buf, 1, cnt, f)) <= 0)
00921                 {
00922                         fclose(f);      
00923                         close(newdraftfd);
00924                         enomem();
00925                 }
00926 
00927                 maildir_writemsg(newdraftfd, buf, n);
00928                 start_pos += n;
00929         }
00930 }
00931 
00932 
00933 /* Create message in the sent folder */
00934 
00935 static void header_uc(char *h)
00936 {
00937        while (*h)
00938        {
00939               *h=toupper( (int)(unsigned char) *h);
00940               while (*h)
00941               {
00942                      if (*h++ == '-')     break;
00943               }
00944        }
00945 }
00946 
00947 struct lookup_buffers {
00948        struct lookup_buffers *next;
00949        char *buf;
00950        char *buf2;
00951        } ;
00952 
00953 static int lookup_addressbook_do(const char *header, const char *value,
00954        struct lookup_buffers **lookup_buffer_list)
00955 {
00956        struct rfc822t *t;
00957        struct rfc822a *a;
00958        int    i;
00959        char   *newbuf;
00960        struct lookup_buffers *ptr;
00961        int    expanded=0;
00962 
00963        t=rfc822t_alloc_new(value, NULL, NULL);
00964        if (!t)       enomem();
00965        a=rfc822a_alloc(t);
00966        if (!a)
00967        {
00968               rfc822t_free(t);
00969               enomem();
00970        }
00971 
00972        for (i=0; i<a->naddrs; i++)
00973        {
00974               char   *p;
00975               char   *s;
00976               const  char *q;
00977               struct lookup_buffers *r;
00978 
00979               if (a->addrs[i].tokens == 0)
00980                      continue;
00981               if (a->addrs[i].name)
00982                      continue;     /* Can't be a nickname */
00983 
00984               p=rfc822_getaddr(a, i);
00985               if (!p)
00986               {
00987                      rfc822a_free(a);
00988                      rfc822t_free(t);
00989                      free(p);
00990                      return (-1);
00991               }
00992 
00993               for (ptr= *lookup_buffer_list; ptr; ptr=ptr->next)
00994                      if (strcmp(ptr->buf2, p) == 0)
00995                             break;
00996 
00997               if (ptr)      /* Address book loop */
00998               {
00999               int    j;
01000 
01001                      for (j=i+1; j<a->naddrs; j++)
01002                             a->addrs[j-1]=a->addrs[j];
01003                      --a->naddrs;
01004                      --i;
01005                      free(p);
01006                      continue;
01007               }
01008 
01009               s=rfc822_display_addr_str_tobuf(p, "utf-8");
01010 
01011               if (s == NULL || (q=ab_find(s)) == 0)
01012               {
01013                      if (s)
01014                             free(s);
01015                      free(p);
01016                      continue;
01017               }
01018               free(s);
01019 
01020               r=malloc(sizeof(struct lookup_buffers));
01021               if (r) r->buf=r->buf2=0;
01022 
01023               if (!r || !(r->buf=strdup(q)) || !(r->buf2=strdup(p)))
01024               {
01025                      free(p);
01026                      if (r && r->buf)     free(r->buf);
01027                      if (r) free(r);
01028                      rfc822a_free(a);
01029                      rfc822t_free(t);
01030                      return (-1);
01031               }
01032               free(p);
01033               r->next= *lookup_buffer_list;
01034               *lookup_buffer_list=r;
01035               a->addrs[i].tokens->next=0;
01036               a->addrs[i].tokens->token=0;
01037               a->addrs[i].tokens->ptr=r->buf;
01038               a->addrs[i].tokens->len=strlen(r->buf);
01039               expanded=1;
01040        }
01041 
01042        newbuf=rfc822_getaddrs_wrap(a, 70);
01043        rfc822a_free(a);
01044        rfc822t_free(t);
01045        if (!newbuf)  return (-1);
01046 
01047        if (expanded) /* Look through the address book again */
01048        {
01049        int    rc=lookup_addressbook_do(header, newbuf, lookup_buffer_list);
01050 
01051               free(newbuf);
01052               return (rc);
01053        }
01054 
01055        create_draftheader_do(header, newbuf, 1);
01056        free(newbuf);
01057        return (0);
01058 }
01059 
01060 static void lookup_addressbook(const char *header, const char *value)
01061 {
01062        struct lookup_buffers *lookup_buffer_list=0;
01063        int    rc;
01064        char *header_cpy;
01065        char *value_cpy;
01066        /*
01067        ** header & value may be pointing to buffer allocated by
01068        ** maildir_readheader.
01069        ** lookup_addressbook_do may call it again.
01070        */
01071 
01072        header_cpy=strdup(header);
01073        if (!header_cpy)
01074               enomem();
01075 
01076        value_cpy=strdup(value);
01077        if (!value_cpy)
01078        {
01079               free(header_cpy);
01080               enomem();
01081        }
01082 
01083        rc=lookup_addressbook_do(header_cpy, value_cpy, &lookup_buffer_list);
01084        free(header_cpy);
01085 
01086        while (lookup_buffer_list)
01087        {
01088        struct lookup_buffers *p=lookup_buffer_list;
01089 
01090               lookup_buffer_list=p->next;
01091               free(p->buf);
01092               free(p->buf2);
01093               free(p);
01094        }
01095        if (rc)       enomem();
01096 }
01097 
01098 char *newmsg_createsentmsg(const char *draftname, int *isgpgerr)
01099 {
01100 char   *filename=maildir_find(INBOX "." DRAFTS, draftname);
01101 FILE   *fp;
01102 char   *sentname;
01103 char   *header, *value;
01104 struct rfc2045 *rfcp;
01105 int    x;
01106 
01107        *isgpgerr=0;
01108  
01109        if (!filename)       return (0);
01110 
01111        fp=0;
01112 
01113        x=maildir_safeopen(filename, O_RDONLY, 0);
01114        if (x >= 0)
01115               if ((fp=fdopen(x, "r")) == 0)
01116                      close(x);
01117 
01118        if (fp == 0)
01119        {
01120               free(filename);
01121               enomem();
01122        }
01123 
01124        rfcp=rfc2045_fromfp(fp);
01125        if (!rfcp || fseek(fp, 0L, SEEK_SET) < 0)
01126        {
01127               fclose(fp);
01128               close(newdraftfd);
01129               enomem();
01130        }
01131 
01132        newdraftfd=maildir_createmsg(INBOX "." SENT, 0, &sentname);
01133        if (newdraftfd < 0)
01134        {
01135               rfc2045_free(rfcp);
01136               free(filename);
01137               fclose(fp);
01138               enomem();
01139        }
01140        /* First, copy all headers except X- headers */
01141 
01142        while ((header=maildir_readheader(fp, &value, 1)) != 0)
01143        {
01144               if (strncmp(header, "x-", 2) == 0) continue;
01145               header_uc(header);
01146               if (rfc822hdr_namecmp(header, "To") == 0)
01147               {
01148                      lookup_addressbook("To: ", value);
01149                      continue;
01150               }
01151 
01152               if (rfc822hdr_namecmp(header, "Cc") == 0)
01153               {
01154                      lookup_addressbook("Cc: ", value);
01155                      continue;
01156               }
01157 
01158               if (rfc822hdr_namecmp(header, "Bcc") == 0)
01159               {
01160                      lookup_addressbook("Bcc: ", value);
01161                      continue;
01162               }
01163 
01164               maildir_writemsgstr(newdraftfd, header);
01165               maildir_writemsgstr(newdraftfd, ": ");
01166               maildir_writemsgstr(newdraftfd, value);
01167               maildir_writemsgstr(newdraftfd, "\n");
01168        }
01169        if (auth_getoptionenvint("wbusexsender"))
01170        {
01171               maildir_writemsgstr(newdraftfd, "X-Sender: ");
01172               maildir_writemsgstr(newdraftfd, login_returnaddr());
01173               maildir_writemsgstr(newdraftfd, "\n");
01174        }
01175 
01176        maildir_writemsgstr(newdraftfd, "\n");
01177 
01178        {
01179               off_t start_pos, end_pos, start_body;
01180               char buf[BUFSIZ];
01181               int n;
01182               off_t   dummy;
01183               
01184               rfc2045_mimepos(rfcp, &start_pos, &end_pos, &start_body,
01185                             &dummy, &dummy);
01186 
01187               if (fseek(fp, start_body, SEEK_SET) == -1)
01188               {
01189                      fclose(fp);
01190                      close(newdraftfd);
01191                      enomem();
01192               }
01193 
01194               while (start_body < end_pos)
01195               {
01196                      int     cnt=sizeof(buf);
01197 
01198                      if (cnt > end_pos - start_pos)
01199                             cnt=end_pos - start_pos;
01200 
01201                      if ((n=fread(buf, 1, cnt, fp)) <= 0)
01202                      {
01203                             fclose(fp);      
01204                             close(newdraftfd);
01205                             enomem();
01206                      }
01207 
01208                      maildir_writemsg(newdraftfd, buf, n);
01209                      start_body += n;
01210               }
01211        }
01212 
01213 
01214        if ( maildir_writemsg_flush(newdraftfd))
01215        {
01216               free(sentname);
01217               return (0);
01218        }
01219 
01220 #if 0
01221        if (writebuf8bit)
01222        {
01223               if (lseek(newdraftfd, transferencodingpos, SEEK_SET) < 0 ||
01224                      write(newdraftfd, "8", 1) != 1)
01225               {
01226                      free(sentname);
01227                      return (0);
01228               }
01229        }
01230 #endif
01231 
01232        if ( maildir_writemsg_flush(newdraftfd))
01233        {
01234               maildir_closemsg(newdraftfd, INBOX "." SENT, sentname, 0, 0);
01235               free(sentname);
01236               return (0);
01237        }
01238 
01239        if (libmail_gpg_has_gpg(GPGDIR) == 0)
01240        {
01241               char dosign= *cgi("sign");
01242               char doencrypt= *cgi("encrypt");
01243               const char *signkey= cgi("signkey");
01244               char *encryptkeys=cgi_multiple("encryptkey", " ");
01245 
01246               if (!encryptkeys)
01247                      enomem();
01248 
01249               if (gpgbadarg(encryptkeys) || !*encryptkeys)
01250               {
01251                      free(encryptkeys);
01252                      encryptkeys=0;
01253               }
01254 
01255               if (gpgbadarg(signkey) || !*signkey)
01256               {
01257                      signkey=0;
01258               }
01259 
01260               if (!encryptkeys)
01261                      doencrypt=0;
01262 
01263               if (!signkey)
01264                      dosign=0;
01265 
01266               if (lseek(newdraftfd, 0L, SEEK_SET) < 0)
01267               {
01268                      maildir_closemsg(newdraftfd, INBOX "." SENT,
01269                                     sentname, 0, 0);
01270                      free(sentname);
01271                      return (0);
01272               }
01273 
01274               if (!dosign)
01275                      signkey=0;
01276               if (!doencrypt)
01277                      encryptkeys=0;
01278 
01279               if (dosign || doencrypt)
01280               {
01281                      /*
01282                      ** What we do is create another draft, then substitute
01283                      ** it for newdraftfd/sentname.  Sneaky.
01284                      */
01285 
01286                      char *newnewsentname;
01287                      int newnewdraftfd=maildir_createmsg(INBOX "." SENT, 0,
01288                                                      &newnewsentname);
01289 
01290                      if (newnewdraftfd < 0)
01291                      {
01292                             maildir_closemsg(newdraftfd, INBOX "." SENT,
01293                                            sentname, 0, 0);
01294                             free(sentname);
01295                             free(encryptkeys);
01296                             return (0);
01297                      }
01298 
01299                      if (gpgdomsg(newdraftfd, newnewdraftfd,
01300                                  signkey, encryptkeys))
01301                      {
01302                             maildir_closemsg(newnewdraftfd, INBOX "." SENT,
01303                                            newnewsentname, 0, 0);
01304                             free(newnewsentname);
01305                             maildir_closemsg(newdraftfd, INBOX "." SENT,
01306                                            sentname, 0, 0);
01307                             free(sentname);
01308                             free(encryptkeys);
01309                             *isgpgerr=1;
01310                             return (0);
01311                      }
01312 
01313                      maildir_closemsg(newdraftfd, INBOX "." SENT, sentname, 0, 0);
01314                      free(sentname);
01315                      sentname=newnewsentname;
01316                      newdraftfd=newnewdraftfd;
01317 
01318               }
01319               free(encryptkeys);
01320        }
01321 
01322        if ( maildir_closemsg(newdraftfd, INBOX "." SENT, sentname, 1, 0))
01323        {
01324               free(sentname);
01325               return (0);
01326        }
01327        return (sentname);
01328 }
01329 
01330 /* ---------------------------------------------------------------------- */
01331 
01332 /* Create a potential multipart boundary separator tag */
01333 
01334 char *multipart_boundary_create()
01335 {
01336 char   pidbuf[MAXLONGSIZE];
01337 char   timebuf[MAXLONGSIZE];
01338 time_t t;
01339 char   cntbuf[MAXLONGSIZE];
01340 static unsigned long cnt=0;
01341 char   *p;
01342 
01343        sprintf(pidbuf, "%lu", (unsigned long)getpid());
01344        time(&t);
01345        sprintf(timebuf, "%lu", (unsigned long)t);
01346        sprintf(cntbuf, "%lu", cnt++);
01347        p=malloc(strlen(pidbuf)+strlen(timebuf) +strlen(cntbuf)+20);
01348        sprintf(p, "=_%s_%s_%s_000", cntbuf, pidbuf, timebuf);
01349        return (p);
01350 }
01351 
01352 /* Search for the boundary tag in a string buffer - this is the new message
01353 ** we're creating.  We should really look for the tag at the beginning of the
01354 ** line, however, the text is not yet linewrapped, besides, why make your
01355 ** life hard?
01356 */
01357 
01358 int multipart_boundary_checks(const char *boundary, const char *msg)
01359 {
01360 size_t boundarylen=strlen(boundary);
01361 
01362        while (*msg)
01363        {
01364               if (msg[0] == '-' && msg[1] == '-' && msg[2] != '-' &&
01365                      strncasecmp(msg+2, boundary, boundarylen) == 0)
01366                             return (-1);
01367               ++msg;
01368        }
01369        return (0);
01370 }
01371 
01372 /* Again, just look for it at the beginning of the line -- why make your
01373 ** life hard? */
01374 
01375 int multipart_boundary_checkf(const char *boundary, FILE *f)
01376 {
01377 size_t boundarylen=strlen(boundary);
01378 const char *line;
01379 
01380        if (fseek(f, 0L, SEEK_SET) == -1)
01381        {
01382               fclose(f);
01383               close(newdraftfd);
01384               enomem();
01385        }
01386 
01387        while ((line=maildir_readline(f)) != 0)
01388               if (line[0] == '-' && line[1] == '-' &&
01389                      strncasecmp(line+2, boundary, boundarylen) == 0)
01390                             return (-1);
01391        return (0);
01392 }
01393 
01394 /* ---------------------------------------------------------------------- */
01395 
01396 /* Copy existing attachments into the new draft message */
01397 
01398 /* multipart_boundary - determine if current draft has attachments */
01399 
01400 static char   *newmsg_multipart_boundary(FILE *f, const char *msg)
01401 {
01402        char   *p=0;
01403 
01404        do
01405        {
01406               if (p) free(p);
01407               p=multipart_boundary_create();
01408        } while (multipart_boundary_checks(p, msg)
01409                || (f && multipart_boundary_checkf(p, f)));
01410        return (p);
01411 }
01412 
01413 static void   newmsg_copy_attachments(struct rfc2045 *rfcp,
01414                                    FILE *f, const char *boundary)
01415 {
01416 struct rfc2045 *p;
01417 int    foundtextplain=0;
01418 
01419        for (p=rfcp->firstpart; p; p=p->next)
01420        {
01421               if (p->isdummy)      continue;
01422               if (!foundtextplain && HASTEXTPLAIN(p))
01423               {      /* Previous version of this message */
01424 
01425                      foundtextplain=1;
01426                      continue;
01427               }
01428               maildir_writemsgstr(newdraftfd, "\n--");
01429               maildir_writemsgstr(newdraftfd, boundary);
01430               maildir_writemsgstr(newdraftfd, "\n");
01431               sentmsg_copy(f, p);  /* Reuse some code */
01432        }
01433 }