Back to index

courier  0.68.2
rfc2045reply.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2000-2011 Double Precision, Inc.  See COPYING for
00003 ** distribution information.
00004 */
00005 
00006 #include "rfc2045_config.h"
00007 #include      "rfc2045.h"
00008 #include      "rfc2045src.h"
00009 #include      "rfc3676parser.h"
00010 #include      "rfc822/rfc2047.h"
00011 #include      "rfc2045charset.h"
00012 #include      "rfc822/rfc822.h"
00013 #include      "unicode/unicode.h"
00014 #include      <stdio.h>
00015 #include      <unistd.h>
00016 #include      <stdlib.h>
00017 #include      <string.h>
00018 #include      <ctype.h>
00019 
00020 
00021 extern void rfc2045_enomem();
00022 
00023 static int mkreply(struct rfc2045_mkreplyinfo *);
00024 static int mkforward(struct rfc2045_mkreplyinfo *);
00025 
00026 static void mksalutation_datefmt(const char *fmt_start,
00027                              const char *fmt_end,
00028                              const char *date,
00029                              void (*callback_func)(const char *,
00030                                                  size_t, void *),
00031                              void *callback_arg)
00032 {
00033        time_t t;
00034 
00035        if (!fmt_start)
00036        {
00037               fmt_start="%a, %d %b %Y %H:%M:%S %z";
00038               fmt_end=fmt_start + strlen(fmt_start);
00039        }
00040 
00041        if ((t=rfc822_parsedt(date)))
00042        {
00043               struct tm tmbuf;
00044 
00045               if (localtime_r(&t, &tmbuf))
00046               {
00047                      char *fmtstr=malloc(fmt_end-fmt_start + 1);
00048 
00049                      if (fmtstr)
00050                      {
00051                             char fmtbuf[1024];
00052 
00053                             memcpy(fmtstr, fmt_start, fmt_end - fmt_start);
00054                             fmtstr[fmt_end-fmt_start]=0;
00055 
00056                             fmtbuf[strftime(fmtbuf,
00057                                           sizeof(fmtbuf)-1,
00058                                           fmtstr, &tmbuf)]=0;
00059 
00060                             free(fmtstr);
00061                             (*callback_func)(fmtbuf, strlen(fmtbuf),
00062                                            callback_arg);
00063                             return;
00064                      }
00065               }
00066        }
00067        (*callback_func)(date, strlen(date), callback_arg);
00068 }
00069 
00070 static void mksalutation_cb(const char *salutation_template,
00071                          const char *newsgroup,
00072                          const char *message_id,
00073                          const char *newsgroups,
00074                          const char *sender_addr,
00075                          const char *sender_name,
00076                          const char *date,
00077                          const char *subject,
00078 
00079                          void (*callback_func)(const char *, size_t, void *),
00080                          void *callback_arg)
00081 {
00082        const char *p;
00083 
00084        for (p=salutation_template; *p; p++)
00085        {
00086               const char *fmt_start=0, *fmt_end=0;
00087 
00088               if (*p != '%' || p[1] == '\0')
00089               {
00090                      (*callback_func)( p, 1, callback_arg );
00091                      continue;
00092               }
00093 
00094               ++p;
00095 
00096               if (*p == '{')
00097               {
00098                      fmt_start= ++p;
00099 
00100                      while (*p)
00101                      {
00102                             if (*p == '}')
00103                             {
00104                                    fmt_end=p;
00105                                    ++p;
00106                                    break;
00107                             }
00108                      }
00109 
00110                      if (!fmt_end)
00111                             continue;
00112               }
00113 
00114 #define CBSTR(s) s, strlen(s), callback_arg
00115 
00116               switch (*p)   {
00117               case 'n':
00118                      (*callback_func)("\n", 1, callback_arg );
00119                      continue;
00120               case 'C':
00121                      (*callback_func)(CBSTR(newsgroup));
00122                      break;
00123               case 'i':
00124                      (*callback_func)(CBSTR(message_id));
00125                      break;
00126               case 'N':
00127                      (*callback_func)(CBSTR(newsgroups));
00128                      break;
00129               case 'f':
00130                      (*callback_func)(CBSTR(sender_addr));
00131                      break;
00132               case 'F':
00133                      (*callback_func)(CBSTR(sender_name));
00134                      break;
00135               case 'd':
00136                      mksalutation_datefmt(fmt_start,
00137                                         fmt_end,
00138                                         date,
00139                                         callback_func, callback_arg);
00140                      break;
00141               case 's':
00142                      (*callback_func)(CBSTR(subject));
00143                      break;
00144               default:
00145                      (*callback_func)(p, 1, callback_arg);
00146                      break;
00147               }
00148 #undef CBSTR
00149 
00150        }
00151 }
00152 
00153 static void mksal_count(const char *str,
00154                      size_t cnt,
00155                      void *arg)
00156 {
00157        *(size_t *)arg += cnt;
00158 }
00159 
00160 static void mksal_save(const char *str,
00161                      size_t cnt,
00162                      void *arg)
00163 {
00164        if (cnt)
00165               memcpy(*(char **)arg, str, cnt);
00166 
00167        *(char **)arg += cnt;
00168 }
00169 
00170 static char *mksalutation(const char *salutation_template,
00171                        const char *newsgroup,
00172                        const char *message_id,
00173                        const char *newsgroups,
00174                        const char *sender_addr,
00175                        const char *sender_name,
00176                        const char *date,
00177                        const char *subject,
00178                        const char *charset)
00179 {
00180        size_t cnt;
00181        char *p, *q;
00182 
00183        char *subj_decoded=rfc822_display_hdrvalue_tobuf("subject", subject,
00184                                                   charset, NULL, NULL);
00185 
00186        if (!subj_decoded)
00187               return NULL;
00188 
00189        cnt=1;
00190 
00191        mksalutation_cb(salutation_template,
00192                      newsgroup,
00193                      message_id,
00194                      newsgroups,
00195                      sender_addr,
00196                      sender_name,
00197                      date,
00198                      subj_decoded,
00199                      mksal_count, &cnt);
00200 
00201        p=q=malloc(cnt);
00202 
00203        if (!p)
00204        {
00205               free(subj_decoded);
00206               return NULL;
00207        }
00208 
00209        mksalutation_cb(salutation_template,
00210                      newsgroup,
00211                      message_id,
00212                      newsgroups,
00213                      sender_addr,
00214                      sender_name,
00215                      date,
00216                      subj_decoded,
00217                      mksal_save, &q);
00218        *q=0;
00219 
00220        free(subj_decoded);
00221        return p;
00222 }
00223 
00224 
00225 int rfc2045_makereply(struct rfc2045_mkreplyinfo *ri)
00226 {
00227        if (strcmp(ri->replymode, "forward") == 0
00228            || strcmp(ri->replymode, "forwardatt") == 0)
00229               return (mkforward(ri));
00230 
00231        return (mkreply(ri));
00232 }
00233 
00234 struct replyinfostruct {
00235 
00236        struct rfc2045_mkreplyinfo *ri;
00237        rfc3676_parser_t parser;
00238 
00239        size_t quote_level_adjust;
00240        size_t quote_level;
00241        int start_line;
00242        int isflowed;
00243        size_t trailing_spaces;
00244        libmail_u_convert_handle_t u_handle;
00245 
00246 };
00247 
00248 /*
00249 ** Pass original content to the RFC 3676 parser
00250 */
00251 
00252 static int quotereply(const char *p, size_t l, void *voidptr)
00253 {
00254        struct replyinfostruct *ris=(struct replyinfostruct *)voidptr;
00255 
00256        return rfc3676parser(ris->parser, p, l);
00257 }
00258 
00259 /*
00260 ** Push formatted reply downstream.
00261 */
00262 
00263 static int output_reply(const char *ptr, size_t cnt, void *arg)
00264 {
00265        struct replyinfostruct *s=(struct replyinfostruct *)arg;
00266 
00267        (*s->ri->write_func)(ptr, cnt, s->ri->voidarg);
00268        return 0;
00269 }
00270 
00271 /*
00272 ** RFC 3676 parser: Start of a new line in the reply.
00273 */
00274 static int reply_begin(size_t quote_level,
00275                      void *arg)
00276 {
00277        struct replyinfostruct *s=(struct replyinfostruct *)arg;
00278        unicode_char quoteChar='>';
00279 
00280        /*
00281        ** Save quote level, begin conversion from unicode to the native
00282        ** charset.
00283        */
00284        s->quote_level=quote_level+s->quote_level_adjust;
00285 
00286        s->u_handle=libmail_u_convert_init(libmail_u_ucs4_native,
00287                                       s->ri->charset,
00288                                       output_reply,
00289                                       s);
00290 
00291        /*
00292        ** Emit quoting indentation, if any.
00293        */
00294        s->start_line=1;
00295        s->trailing_spaces=0;
00296 
00297        if (s->u_handle)
00298        {
00299               size_t i;
00300 
00301               for (i=0; i<s->quote_level; i++)
00302               {
00303                      libmail_u_convert_uc(s->u_handle, &quoteChar, 1);
00304               }
00305        }
00306        return 0;
00307 }
00308 
00309 /*
00310 ** RFC 3676: (possibly partial) contents of a deflowed line, as unicode.
00311 */
00312 
00313 static int reply_contents(const unicode_char *txt,
00314                        size_t txt_size,
00315                        void *arg)
00316 {
00317        unicode_char spaceChar=' ';
00318        size_t nonspc_cnt;
00319 
00320        struct replyinfostruct *s=(struct replyinfostruct *)arg;
00321 
00322        if (!s->u_handle || txt_size == 0)
00323               return 0;
00324 
00325        /*
00326        ** Space-stuff the initial character.
00327        */
00328 
00329        if (s->start_line)
00330        {
00331               if (!s->isflowed)
00332               {
00333                      /*
00334                      ** If the original content is not flowed, the rfc3676
00335                      ** parser does not parse the number of > quote
00336                      ** characters and does not set the quote level.
00337                      */
00338 
00339                      if ((s->quote_level > 0 && *txt != '>') || *txt == ' ')
00340                             libmail_u_convert_uc(s->u_handle,
00341                                                &spaceChar, 1);
00342 
00343               }
00344               else
00345               {
00346                      if (s->quote_level > 0 || *txt == ' ' || *txt == '>')
00347                             libmail_u_convert_uc(s->u_handle,
00348                                                &spaceChar, 1);
00349               }
00350               s->start_line=0;
00351        }
00352 
00353        /*
00354        ** Trim any trailing spaces from the RFC 3676 parsed content.
00355        */
00356 
00357        for (nonspc_cnt=txt_size; nonspc_cnt > 0; --nonspc_cnt)
00358               if (txt[nonspc_cnt-1] != ' ')
00359                      break;
00360 
00361        /*
00362        ** If the contents are not totally whitespace, it's ok now to emit
00363        ** any accumulated whitespace from previous content.
00364        */
00365 
00366        if (nonspc_cnt)
00367        {
00368               while (s->trailing_spaces)
00369               {
00370                      libmail_u_convert_uc(s->u_handle, &spaceChar, 1);
00371                      --s->trailing_spaces;
00372               }
00373 
00374               libmail_u_convert_uc(s->u_handle, txt, nonspc_cnt);
00375        }
00376 
00377        s->trailing_spaces += txt_size - nonspc_cnt;
00378        return 0;
00379 }
00380 
00381 static int reply_end(void *arg)
00382 {
00383        unicode_char newLine='\n';
00384        struct replyinfostruct *s=(struct replyinfostruct *)arg;
00385 
00386        libmail_u_convert_uc(s->u_handle, &newLine, 1);
00387 
00388        libmail_u_convert_deinit(s->u_handle, NULL);
00389        return 0;
00390 }
00391 
00392 /*
00393 ** RFC 3676 parser: flowed line break. Replicate it.
00394 */
00395 static int reply_wrap(void *arg)
00396 {
00397        unicode_char spaceChar=' ';
00398        struct replyinfostruct *s=(struct replyinfostruct *)arg;
00399 
00400        /*
00401        ** It's safe to preserve trailing spaces on flowed lines.
00402        */
00403 
00404        while (s->trailing_spaces)
00405        {
00406               libmail_u_convert_uc(s->u_handle, &spaceChar, 1);
00407               --s->trailing_spaces;
00408        }
00409 
00410        libmail_u_convert_uc(s->u_handle, &spaceChar, 1);
00411        reply_end(s);
00412        reply_begin(s->quote_level-s->quote_level_adjust, s);
00413        /* Undo the adjustment in reply_begin() */
00414 
00415        return 0;
00416 }
00417 
00418 static void reformat(struct rfc2045_mkreplyinfo *ri, struct rfc2045 *rfc,
00419                    size_t adjustLevel)
00420 {
00421        struct replyinfostruct ris;
00422 
00423        struct rfc3676_parser_info info;
00424        int conv_err;
00425 
00426        ris.ri=ri;
00427        ris.quote_level_adjust=adjustLevel;
00428 
00429        memset(&info, 0, sizeof(info));
00430 
00431        info.charset=ri->charset;
00432        ris.isflowed=info.isflowed=rfc2045_isflowed(rfc);
00433        info.isdelsp=rfc2045_isdelsp(rfc);
00434 
00435        info.line_begin=reply_begin;
00436        info.line_contents=reply_contents;
00437        info.line_flowed_notify=reply_wrap;
00438        info.line_end=reply_end;
00439        info.arg=&ris;
00440 
00441        if ((ris.parser=rfc3676parser_init(&info)) != NULL)
00442        {
00443               rfc2045_decodetextmimesection(ri->src, rfc,
00444                                          ri->charset,
00445                                          &conv_err,
00446                                          quotereply,
00447                                          &ris);
00448               rfc3676parser_deinit(ris.parser, NULL);
00449        }
00450 }
00451 
00452 static void   replybody(struct rfc2045_mkreplyinfo *ri, struct rfc2045 *rfc)
00453 {
00454        rfc=rfc2045_searchcontenttype(rfc, "text/plain");
00455 
00456        if (!rfc)
00457               return;
00458 
00459        reformat(ri, rfc, 1);
00460 }
00461 
00462 static void writes(struct rfc2045_mkreplyinfo *ri, const char *c)
00463 {
00464        (*ri->write_func)(c, strlen(c), ri->voidarg);
00465 }
00466 
00467 static void forwardbody(struct rfc2045_mkreplyinfo *ri, long nbytes)
00468 {
00469        char   buf[BUFSIZ];
00470        ssize_t i;
00471 
00472        while ((i=nbytes > sizeof(buf) ? sizeof(buf):nbytes) > 0 &&
00473               (i=SRC_READ(ri->src, buf, i)) > 0)
00474        {
00475               nbytes -= i;
00476               (*ri->write_func)(buf, i, ri->voidarg);
00477        }
00478 }
00479 
00480 /*
00481 ** Format a forward
00482 */
00483 static int mkforward(struct rfc2045_mkreplyinfo *ri)
00484 {
00485        off_t  start_pos, end_pos, start_body;
00486        off_t  dummy;
00487 
00488        char   *header, *value;
00489        char   *subject=0;
00490 
00491        char   *boundary=0;
00492 
00493        struct rfc2045headerinfo *hi;
00494 
00495        struct rfc2045 *textplain_content;
00496        struct rfc2045 *first_attachment;
00497        int attachment_is_message_rfc822;
00498 
00499        /*
00500        ** Use the original message's subject to set the subject of the
00501        ** forward message.
00502        */
00503 
00504        hi=rfc2045header_start(ri->src, ri->rfc2045partp);
00505 
00506        if (!hi)
00507               return (-1);
00508 
00509        for (;;)
00510        {
00511               if (rfc2045header_get(hi, &header, &value, 0))
00512               {
00513                      rfc2045header_end(hi);
00514                      return (-1);
00515               }
00516 
00517               if (!header)
00518                      break;
00519               if (strcmp(header, "subject") == 0)
00520               {
00521                      if (subject)  free(subject);
00522 
00523                      subject=strdup(value);
00524                      if (!subject)
00525                      {
00526                             rfc2045header_end(hi);
00527                             return (-1);
00528                      }
00529               }
00530        }
00531 
00532        rfc2045header_end(hi);
00533 
00534        writes(ri, "Subject: ");
00535 
00536        if (ri->subject)
00537        {
00538               /*
00539               ** ... unless the caller overrides it.
00540               */
00541 
00542               writes(ri, ri->subject);
00543        }
00544        else if (subject)
00545        {
00546               char   *s=rfc822_coresubj_keepblobs(subject);
00547 
00548               if (!s)
00549                      return (-1);
00550 
00551               writes(ri, s);
00552               free(s);
00553               writes(ri, " (fwd)");
00554        }
00555        writes(ri, "\nMime-Version: 1.0\n");
00556 
00557        /*
00558        ** To assemble a forward template, two things are needed:
00559        **
00560        ** 1. The original message, as text/plain.
00561        **
00562        ** 2. Any attachments in the original message.
00563        **    A. The attachments get either copied to the forward message, or
00564        **    B. The original message is attached as a single message/rfc822
00565        **       entity.
00566        **
00567        ** 2b is always produced by "forwardatt". If a suitable text/plain
00568        ** part of the original message could not be found, 2b is also
00569        ** produced even by "forward".
00570        */
00571 
00572        textplain_content=NULL;
00573 
00574        attachment_is_message_rfc822=0;
00575        first_attachment=NULL;
00576 
00577        {
00578               const char *content_type, *dummy;
00579 
00580               struct rfc2045 *top_part=ri->rfc2045partp;
00581 
00582               rfc2045_mimeinfo(top_part,
00583                              &content_type, &dummy, &dummy);
00584 
00585               if (strcmp(content_type, "multipart/signed") == 0)
00586               {
00587                      struct rfc2045 *p=top_part->firstpart;
00588 
00589                      if (p && p->isdummy)
00590                             p=p->next;
00591 
00592                      if (p)
00593                      {
00594                             top_part=p;
00595                             rfc2045_mimeinfo(top_part,
00596                                            &content_type, &dummy, &dummy);
00597                      }
00598               }
00599               else if (strcmp(content_type, "multipart/x-mimegpg") == 0)
00600               {
00601                      struct rfc2045 *p=top_part->firstpart;
00602 
00603                      if (p && p->isdummy)
00604                             p=p->next;
00605 
00606                      if (p)
00607                      {
00608                             const char *part_ct;
00609 
00610                             rfc2045_mimeinfo(p,
00611                                            &part_ct, &dummy, &dummy);
00612 
00613                             if (strcmp(part_ct, "text/x-gpg-output") == 0
00614                                 && p->next)
00615                             {
00616                                    top_part=p->next;
00617                                    rfc2045_mimeinfo(top_part,
00618                                                   &content_type,
00619                                                   &dummy, &dummy);
00620                             }
00621                      }
00622               }
00623 
00624               if (strcmp(content_type, "text/plain") == 0)
00625               {
00626                      textplain_content=top_part;
00627               }
00628               else if (strcmp(content_type, "multipart/alternative") == 0)
00629               {
00630                      textplain_content=
00631                             rfc2045_searchcontenttype(top_part,
00632                                                    "text/plain");
00633               }
00634               else if (strcmp(content_type, "multipart/mixed") == 0)
00635               {
00636                      struct rfc2045 *p=top_part->firstpart;
00637 
00638                      if (p->isdummy)
00639                             p=p->next;
00640 
00641                      textplain_content=
00642                             rfc2045_searchcontenttype(p, "text/plain");
00643 
00644                      /*
00645                      ** If the first part contained a suitable text/plain,
00646                      ** any remaining MIME parts become attachments that
00647                      ** get copied to the forward message.
00648                      */
00649                      if (textplain_content)
00650                             first_attachment=p->next;
00651               }
00652 
00653               if (strcmp(ri->replymode, "forwardatt") == 0 ||
00654                   textplain_content == NULL)
00655               {
00656                      /*
00657                      ** Copy the entire message as the sole message/rfc822
00658                      ** attachment in the forward message.
00659                      */
00660                      textplain_content=NULL;
00661                      first_attachment=top_part;
00662                      attachment_is_message_rfc822=1;
00663               }
00664        }
00665 
00666        boundary=strdup(rfc2045_mk_boundary(ri->rfc2045partp, ri->src));
00667        if (!boundary)
00668        {
00669               if (subject)  free(subject);
00670               return (-1);
00671        }
00672 
00673        if (first_attachment)
00674        {
00675               writes(ri, "Content-Type: multipart/mixed; boundary=\"");
00676               writes(ri, boundary);
00677               writes(ri, "\"\n\n");
00678               writes(ri, RFC2045MIMEMSG);
00679               writes(ri, "\n--");
00680               writes(ri, boundary);
00681               writes(ri, "\n");
00682        }
00683 
00684        if (ri->content_set_charset)
00685        {
00686               (*ri->content_set_charset)(ri->voidarg);
00687        }
00688        else
00689        {
00690               writes(ri, "Content-Type: text/plain; format=flowed; delsp=yes; charset=\"");
00691               writes(ri, ri->charset);
00692               writes(ri, "\"\n");
00693        }
00694 
00695        writes(ri, "Content-Transfer-Encoding: 8bit\n\n");
00696        if (ri->content_specify)
00697               (*ri->content_specify)(ri->voidarg);
00698 
00699        writes(ri, "\n");
00700        if (ri->writesig_func)
00701               (*ri->writesig_func)(ri->voidarg);
00702        writes(ri, "\n");
00703 
00704        if (ri->forwardsep)
00705        {
00706               writes(ri, ri->forwardsep);
00707               writes(ri, "\n");
00708        }
00709 
00710        if (textplain_content)
00711        {
00712               /* Copy original headers. */
00713               
00714               hi=rfc2045header_start(ri->src, ri->rfc2045partp);
00715               for (;;)
00716               {
00717                      if (rfc2045header_get(hi, &header, &value,
00718                                          RFC2045H_NOLC|RFC2045H_KEEPNL))
00719                      {
00720                             rfc2045header_end(hi);
00721                             break;
00722                      }
00723                      if (!header)
00724                             break;
00725                      if (strcasecmp(header, "subject") == 0 ||
00726                          strcasecmp(header, "from") == 0 ||
00727                          strcasecmp(header, "to") == 0 ||
00728                          strcasecmp(header, "cc") == 0 ||
00729                          strcasecmp(header, "date") == 0 ||
00730                          strcasecmp(header, "message-id") == 0 ||
00731                          strcasecmp(header, "resent-from") == 0 ||
00732                          strcasecmp(header, "resent-to") == 0 ||
00733                          strcasecmp(header, "resent-cc") == 0 ||
00734                          strcasecmp(header, "resent-date") == 0 ||
00735                          strcasecmp(header, "resent-message-id") == 0)
00736                      {
00737                             if (subject) free(subject);
00738 
00739                             subject=rfc822_display_hdrvalue_tobuf(header,
00740                                                               value,
00741                                                               ri->charset,
00742                                                               NULL,
00743                                                               NULL);
00744 
00745                             if (subject)
00746                             {
00747                                    (*ri->write_func)(header,
00748                                                    strlen(header),
00749                                                    ri->voidarg);
00750                                    (*ri->write_func)(": ", 2, ri->voidarg);
00751                                    (*ri->write_func)(subject,
00752                                                    strlen(subject),
00753                                                    ri->voidarg);
00754                                    (*ri->write_func)("\n", 1, ri->voidarg);
00755                             }
00756                      }
00757               }
00758               rfc2045header_end(hi);
00759               (*ri->write_func)("\n", 1, ri->voidarg);
00760 
00761               reformat(ri, textplain_content, 0);
00762        }
00763 
00764        if (first_attachment)
00765        {
00766               /*
00767               ** There are attachments to copy
00768               */
00769 
00770               if (attachment_is_message_rfc822)
00771               {
00772                      /* Copy everything as a message/rfc822 */
00773 
00774                      writes(ri, "\n--");
00775                      writes(ri, boundary);
00776                      writes(ri, "\nContent-Type: message/rfc822\n");
00777 
00778                      if (ri->forwarddescr)
00779                      {
00780                             char *p=rfc2047_encode_str(ri->forwarddescr,
00781                                                     ri->charset ?
00782                                                     ri->charset
00783                                                     : "iso-8859-1",
00784                                                     rfc2047_qp_allow_any
00785                                                     );
00786 
00787                             writes(ri, "Content-Description: ");
00788                             writes(ri, p ? p:"");
00789                             free(p);
00790                             writes(ri, "\n");
00791                      }
00792 
00793                      writes(ri, "\n");
00794 
00795                      rfc2045_mimepos(first_attachment, &start_pos, &end_pos,
00796                                    &start_body,
00797                                    &dummy, &dummy);
00798                      
00799                      if (SRC_SEEK(ri->src, start_pos) == (off_t)-1)
00800                      {
00801                             if (subject) free(subject);
00802                             free(boundary);
00803                             return -1;
00804                      }
00805                      forwardbody(ri, end_pos - start_pos);
00806               }
00807               else
00808               {
00809                      /* Copy over individual attachments, one by one */
00810 
00811                      for (; first_attachment;
00812                           first_attachment=first_attachment->next)
00813                      {
00814                             writes(ri, "\n--");
00815                             writes(ri, boundary);
00816                             writes(ri, "\n");
00817 
00818                             rfc2045_mimepos(first_attachment, &start_pos,
00819                                           &end_pos,
00820                                           &start_body,
00821                                           &dummy, &dummy);
00822                      
00823                             if (SRC_SEEK(ri->src, start_pos) == (off_t)-1)
00824                             {
00825                                    if (subject) free(subject);
00826                                    free(boundary);
00827                                    return -1;
00828                             }
00829 
00830                             forwardbody(ri, end_pos - start_pos);
00831                      }
00832               }
00833 
00834               writes(ri, "\n--");
00835               writes(ri, boundary);
00836               writes(ri, "--\n");
00837        }
00838 
00839        if (subject) free(subject);
00840        free(boundary);
00841        return (0);
00842 }
00843 
00844 
00845 static int writereferences(struct rfc2045_mkreplyinfo *ri,
00846                          const char *oldref, const char *oldmsgid)
00847 {
00848 char   *buf=malloc((oldref ? strlen(oldref):0)
00849               + (oldmsgid ? strlen(oldmsgid):0)+2);
00850 char   *p, *q;
00851 struct rfc822t *tp;
00852 struct rfc822a *ap;
00853 int    i;
00854 
00855        if (!buf)
00856               return (-1);
00857 
00858        /* Create new references header */
00859        *buf=0;
00860        if (oldref)   strcat(buf, oldref);
00861        if (oldref && oldmsgid)     strcat(buf, " ");
00862        if (oldmsgid) strcat(buf, oldmsgid);
00863 
00864        /* Do wrapping the RIGHT way, by
00865        ** RFC822 parsing the References: header
00866        */
00867 
00868        if ((tp=rfc822t_alloc_new(buf, NULL, NULL)) == 0 ||
00869               (ap=rfc822a_alloc(tp)) == 0)
00870        {
00871               free(buf);
00872               if (tp)
00873                      rfc822t_free(tp);
00874               return (-1);
00875        }
00876 
00877        /* Keep only the last 20 message IDs */
00878 
00879        i=0;
00880        if (ap->naddrs > 20) i=ap->naddrs-20;
00881        p="";
00882        while (i < ap->naddrs)
00883        {
00884               q=rfc822_gettok(ap->addrs[i].tokens);
00885               if (!q)
00886               {
00887                      rfc822a_free(ap);
00888                      rfc822t_free(tp);
00889                      free(buf);
00890                      return (-1);
00891               }
00892 
00893               writes(ri, p);
00894               writes(ri, "<");
00895               writes(ri, q);
00896               writes(ri, ">\n");
00897               p="            ";
00898               free(q);
00899               i++;
00900        }
00901        rfc822a_free(ap);
00902        rfc822t_free(tp);
00903        free(buf);
00904        return (0);
00905 }
00906 
00907 static char *mlcheck(struct rfc2045_mkreplyinfo *ri, const char *);
00908 
00909 static int replydsn(struct rfc2045_mkreplyinfo *);
00910 static int replyfeedback(struct rfc2045_mkreplyinfo *);
00911 
00912 static int mkreply(struct rfc2045_mkreplyinfo *ri)
00913 {
00914        char   *oldtocc, *oldfrom, *oldreplyto, *oldtolist;
00915        char   *subject;
00916        char   *oldmsgid;
00917        char   *oldreferences;
00918        char   *oldenvelope;
00919        char   *header, *value;
00920        char   *date;
00921        char   *newsgroup;
00922        char   *newsgroups;
00923 
00924        char   *whowrote;
00925        off_t  start_pos, end_pos, start_body, dummy;
00926        int errflag=0;
00927        char   *boundary;
00928        char   *dsn_report_type;
00929        int    (*dsn_report_gen)(struct rfc2045_mkreplyinfo *);
00930 
00931        struct rfc2045headerinfo *hi;
00932 
00933        oldtocc=0;
00934        oldtolist=0;
00935        oldfrom=0;
00936        oldreplyto=0;
00937        subject=0;
00938        oldmsgid=0;
00939        oldreferences=0;
00940        oldenvelope=0;
00941        whowrote=0;
00942        newsgroup=0;
00943        newsgroups=0;
00944        date=0;
00945 
00946        rfc2045_mimepos(ri->rfc2045partp, &start_pos, &end_pos, &start_body,
00947               &dummy, &dummy);
00948 
00949        hi=rfc2045header_start(ri->src, ri->rfc2045partp);
00950 
00951        if (!hi)
00952               return (-1);
00953 
00954 #define BLOWUP { \
00955               if (whowrote) free(whowrote); \
00956               if (subject) free(subject); \
00957               if (oldmsgid) free(oldmsgid); \
00958               if (oldreferences)   free(oldreferences); \
00959               if (oldtocc) free(oldtocc); \
00960               if (oldtolist) free(oldtolist); \
00961               if (oldfrom) free(oldfrom); \
00962               if (oldreplyto)      free(oldreplyto); \
00963               if (oldenvelope) free(oldenvelope); \
00964               if (newsgroup) free(newsgroup); \
00965               if (newsgroups) free(newsgroups); \
00966               if (date) free(date); \
00967               rfc2045header_end(hi); \
00968               return (-1); \
00969        }
00970 
00971        for (;;)
00972        {
00973               if (rfc2045header_get(hi, &header, &value, 0))
00974               {
00975                      BLOWUP;
00976                      return (-1);
00977               }
00978 
00979               if (!header)
00980                      break;
00981 
00982               if (strcmp(header, "subject") == 0)
00983               {
00984                      if (subject)  free(subject);
00985 
00986                      subject=strdup(value);
00987                      if (!subject)
00988                             BLOWUP;
00989               }
00990               else if (strcmp(header, "reply-to") == 0)
00991               {
00992                      if (oldreplyto)      free(oldreplyto);
00993                      oldreplyto=strdup(value);
00994                      if (!oldreplyto)
00995                             BLOWUP;
00996               }
00997               else if (strcmp(header, "from") == 0)
00998               {
00999                      if (oldfrom)  free(oldfrom);
01000                      oldfrom=strdup(value);
01001                      if (!oldfrom)
01002                             BLOWUP;
01003               }
01004               else if (strcmp(header, "message-id") == 0)
01005               {
01006                      if (oldmsgid) free(oldmsgid);
01007                      oldmsgid=strdup(value);
01008                      if (!oldmsgid)
01009                             BLOWUP;
01010               }
01011               else if (strcmp(header, "references") == 0)
01012               {
01013                      if (oldreferences)   free(oldreferences);
01014                      oldreferences=strdup(value);
01015                      if (!oldreferences)
01016                             BLOWUP;
01017               }
01018               else if ((strcmp(header, "return-path") == 0 ||
01019                        strcmp(header, "errors-to") == 0) &&
01020                       ri->replytoenvelope)
01021               {
01022                      if (oldenvelope)     free(oldenvelope);
01023                      oldenvelope=strdup(value);
01024                      if (!oldenvelope)
01025                             BLOWUP;
01026               }
01027               else if (strcmp(header, "newsgroups") == 0)
01028               {
01029                      if (newsgroups)      free(newsgroups);
01030                      newsgroups=strdup(value);
01031                      if (!newsgroups)
01032                             BLOWUP;
01033               }
01034               else if (strcmp(header, "x-newsgroup") == 0)
01035               {
01036                      if (newsgroup)       free(newsgroup);
01037                      newsgroup=strdup(value);
01038                      if (!newsgroup)
01039                             BLOWUP;
01040               }
01041               else if (strcmp(header, "date") == 0)
01042               {
01043                      if (date)     free(date);
01044                      date=strdup(value);
01045                      if (!date)
01046                             BLOWUP;
01047               }
01048               else if ((strcmp(ri->replymode, "replyall") == 0
01049                        || strcmp(ri->replymode, "replylist") == 0) &&
01050                       (
01051                        strcmp(header, "to") == 0 ||
01052                        strcmp(header, "cc") == 0
01053                        )
01054                       )
01055               {
01056                      char   *newh=malloc( (oldtocc ?
01057                                           strlen(oldtocc):0)
01058                                          + strlen(value)+2);
01059                      char   *p;
01060 
01061                             if (!newh)
01062                                    BLOWUP;
01063 
01064                             *newh=0;
01065                             if (oldtocc)
01066                                    strcat(strcpy(newh, oldtocc),
01067                                                         ",");
01068                             strcat(newh, value);
01069                             if (oldtocc)  free(oldtocc);
01070                             oldtocc=newh;
01071 
01072                             p=mlcheck(ri, value);
01073                             if (!p || (newh=malloc((oldtolist ?
01074                                                  strlen(oldtolist):0)
01075                                       + strlen(p)+2)) == NULL)
01076                             {
01077                                    if (p)
01078                                           free(p);
01079                                    BLOWUP;
01080                             }
01081 
01082                             if (*p)
01083                             {
01084                                    *newh=0;
01085                                    if (oldtolist)
01086                                           strcat(strcpy(newh, oldtolist),
01087                                                  ",");
01088                                    strcat(newh, p);
01089                                    if (oldtolist)
01090                                           free(oldtolist);
01091                                    oldtolist=newh;
01092                             }
01093                             free(p);
01094               }
01095        }
01096 
01097        rfc2045header_end(hi);
01098 
01099        /* Write:  "%s writes:" */
01100 
01101        {
01102               struct rfc822t *rfcp=rfc822t_alloc_new(oldfrom ? oldfrom:"",
01103                                                  NULL, NULL);
01104               struct rfc822a *rfcpa;
01105               char   *sender_name=NULL;
01106               char   *sender_addr=NULL;
01107               int    n;
01108 
01109               if (!rfcp)
01110                      BLOWUP;
01111 
01112               rfcpa=rfc822a_alloc(rfcp);
01113               if (!rfcpa)
01114               {
01115                      rfc822t_free(rfcp);
01116                      BLOWUP;
01117               }
01118 
01119               for (n=0; n<rfcpa->naddrs; ++n)
01120               {
01121                      if (rfcpa->addrs[n].tokens == NULL)
01122                             continue;
01123 
01124                      sender_name=rfc822_display_name_tobuf(rfcpa, n,
01125                                                        ri->charset);
01126                      sender_addr=rfc822_display_addr_tobuf(rfcpa, n,
01127                                                        ri->charset);
01128                      break;
01129               }
01130 
01131               rfc822a_free(rfcpa);
01132               rfc822t_free(rfcp);
01133 
01134               whowrote=mksalutation(ri->replysalut,
01135                                   newsgroup ? newsgroup:"",
01136                                   oldmsgid ? oldmsgid:"",
01137                                   newsgroups ? newsgroups:"",
01138 
01139                                   sender_addr ? sender_addr:"(no address given)",
01140                                   sender_name ? sender_name:sender_addr,
01141                                   date,
01142                                   subject,
01143                                   ri->charset);
01144 
01145               if (sender_name)
01146                      free(sender_name);
01147               if (sender_addr)
01148                      free(sender_addr);
01149 
01150               if (!whowrote)
01151               {
01152                      BLOWUP;
01153               }
01154        }
01155 
01156        if (newsgroups)
01157               free(newsgroups);
01158        if (newsgroup)
01159               free(newsgroup);
01160        if (date)
01161               free(date);
01162        if (oldreplyto)
01163        {
01164               if (oldfrom)  free(oldfrom);
01165               oldfrom=oldreplyto;
01166               oldreplyto=0;
01167        }
01168 
01169        if (oldenvelope)
01170        {
01171               if (oldfrom)  free(oldfrom);
01172               oldfrom=oldenvelope;
01173               oldenvelope=0;
01174        }
01175 
01176        /*
01177        ** Replytolist: if we found mailing list addresses, drop
01178        ** oldtocc, we'll use oldtolist.
01179        ** Otherwise, drop oldtolist.
01180        */
01181 
01182        if (strcmp(ri->replymode, "replylist") == 0)
01183        {
01184               if (oldtolist)
01185               {
01186                      if (oldtocc)
01187                      {
01188                             free(oldtocc);
01189                             oldtocc=0;
01190                      }
01191 
01192                      if (oldfrom)
01193                      {
01194                             free(oldfrom);
01195                             oldfrom=0;
01196                      }
01197               }
01198        }
01199        else
01200        {
01201               if (oldtolist)
01202               {
01203                      free(oldtolist);
01204                      oldtolist=NULL;
01205               }
01206        }
01207 
01208        /* Remove duplicate entries from new Cc header */
01209 
01210        if (oldtocc)
01211        {
01212               struct rfc822t       *rfccc, *rfcto;
01213               struct rfc822a       *arfccc, *arfcto;
01214               int    i, j;
01215               char   *new_addresses;
01216 
01217               rfccc=rfc822t_alloc_new(oldtocc, NULL, NULL);
01218               rfcto= oldfrom ? rfc822t_alloc_new(oldfrom, NULL,
01219                                              NULL):NULL;
01220               arfccc=rfccc ? rfc822a_alloc(rfccc):NULL;
01221               arfcto=rfcto ? rfc822a_alloc(rfcto):NULL;
01222 
01223               for (i=0; arfccc && i <arfccc->naddrs; i++)
01224               {
01225                      char   *addr=rfc822_getaddr(arfccc, i);
01226 
01227                      if (!addr)    continue;
01228 
01229                             /* Remove address from Cc if it is my address */
01230 
01231                      if ( (ri->myaddr_func)(addr, ri->voidarg))
01232                      {
01233                             rfc822_deladdr(arfccc, i); --i;
01234                             free(addr);
01235                             continue;
01236                      }
01237 
01238                             /* Remove address from Cc if it appears in To: */
01239 
01240                      for (j=0; arfcto && j < arfcto->naddrs; j++)
01241                      {
01242                             char *addr2=rfc822_getaddr(arfcto, j);
01243 
01244                             if (!addr2)   continue;
01245                             if (strcmp(addr, addr2) == 0)
01246                             {
01247                                    free(addr2);
01248                                    break;
01249                             }
01250                             free(addr2);
01251                      }
01252                      if (arfcto && j < arfcto->naddrs)
01253                      {
01254                             rfc822_deladdr(arfccc, i); --i;
01255                             free(addr);
01256                             continue;
01257                      }
01258 
01259                             /* Remove outright duplicates in Cc */
01260 
01261                      for (j=i+1; j<arfccc->naddrs; j++)
01262                      {
01263                             char *addr2=rfc822_getaddr(arfccc, j);
01264 
01265                             if (!addr2)   continue;
01266                             if (strcmp(addr, addr2) == 0)
01267                             {
01268                                    rfc822_deladdr(arfccc, j);
01269                                    --j;
01270                             }
01271                             free(addr2);
01272                      }
01273                      free(addr);
01274               }
01275               new_addresses=rfc822_getaddrs(arfccc);
01276               free(oldtocc);
01277               oldtocc=new_addresses;
01278               if (arfccc)   rfc822a_free(arfccc);
01279               if (arfcto)   rfc822a_free(arfcto);
01280               rfc822t_free(rfccc);
01281               if (rfcto) rfc822t_free(rfcto);
01282        }
01283 
01284        if (strcmp(ri->replymode, "feedback") == 0)
01285        {
01286               if (oldtolist)
01287               {
01288                      free(oldtolist);
01289                      oldtolist=NULL;
01290               }
01291 
01292               if (oldfrom)
01293               {
01294                      free(oldfrom);
01295                      oldfrom=NULL;
01296               }
01297 
01298               if (oldtocc)
01299               {
01300                      free(oldtocc);
01301                      oldtocc=NULL;
01302               }
01303        }
01304 
01305        if (oldtolist)
01306        {
01307               writes(ri, "To: ");
01308               writes(ri, oldtolist);
01309               writes(ri, "\n");
01310               free(oldtolist);
01311        }
01312 
01313        if (oldfrom)
01314        {
01315               writes(ri, "To: ");
01316               writes(ri, oldfrom);
01317               writes(ri, "\n");
01318               free(oldfrom);
01319        }
01320 
01321        if (oldtocc)
01322        {
01323               writes(ri, "Cc: ");
01324               writes(ri, oldtocc);
01325               writes(ri, "\n");
01326               free(oldtocc);
01327        }
01328 
01329        if (oldmsgid || oldreferences)
01330        {
01331               writes(ri, "References: ");
01332               if (writereferences(ri, oldreferences, oldmsgid))
01333                      errflag= -1;
01334               if (oldreferences)   free(oldreferences);
01335        }
01336        if (oldmsgid)
01337        {
01338               writes(ri, "In-Reply-To: ");
01339               writes(ri, oldmsgid);
01340               writes(ri, "\n");
01341               free(oldmsgid);
01342        }
01343        writes(ri,"Subject: ");
01344 
01345        if (ri->subject)
01346        {
01347               writes(ri, ri->subject);
01348        }
01349        else if (subject)
01350        {
01351               if (strcmp(ri->replymode, "feedback") == 0 ||
01352                   strcmp(ri->replymode, "replyfeedback") == 0)
01353               {
01354                      writes(ri, subject);
01355               }
01356               else
01357               {
01358                      char   *s=rfc822_coresubj_keepblobs(subject);
01359 
01360                      writes(ri, "Re: ");
01361                      writes(ri, s ? s:"");
01362                      if (s) free(s);
01363               }
01364               free(subject);
01365        }
01366 
01367        writes(ri, "\nMime-Version: 1.0\n");
01368 
01369        boundary=NULL;
01370        dsn_report_type=NULL;
01371 
01372        if (strcmp(ri->replymode, "replydsn") == 0 && ri->dsnfrom)
01373        {
01374               dsn_report_type="delivery-status";
01375               dsn_report_gen=&replydsn;
01376        }
01377        else if (strcmp(ri->replymode, "replyfeedback") == 0 ||
01378                strcmp(ri->replymode, "feedback") == 0)
01379        {
01380               dsn_report_type="feedback-report";
01381               dsn_report_gen=&replyfeedback;
01382        }
01383 
01384        if (dsn_report_type)
01385        {
01386               boundary=rfc2045_mk_boundary(ri->rfc2045partp, ri->src);
01387               if (!boundary)
01388                      return (-1);
01389 
01390               writes(ri, "Content-Type: multipart/report;"
01391                      " report-type=");
01392 
01393               writes(ri, dsn_report_type);
01394               writes(ri, ";\n    boundary=\"");
01395 
01396               writes(ri, boundary);
01397 
01398               writes(ri,"\"\n"
01399                      "\n"
01400                      RFC2045MIMEMSG
01401                      "\n"
01402                      "--");
01403               writes(ri, boundary);
01404               writes(ri, "\n");
01405        }
01406 
01407        if (ri->content_set_charset)
01408        {
01409               (*ri->content_set_charset)(ri->voidarg);
01410        }
01411        else
01412        {
01413               writes(ri, "Content-Type: text/plain; format=flowed; delsp=yes; charset=\"");
01414               writes(ri, ri->charset);
01415               writes(ri, "\"\n");
01416        }
01417        writes(ri, "Content-Transfer-Encoding: 8bit\n\n");
01418 
01419        if (!ri->donotquote)
01420        {
01421               if (whowrote)
01422               {
01423                      writes(ri, whowrote);
01424                      free(whowrote);
01425                      writes(ri, "\n\n");
01426               }
01427               if (SRC_SEEK(ri->src, start_body) == (off_t)-1)
01428                      return (-1);
01429 
01430               replybody(ri, ri->rfc2045partp);
01431               writes(ri, "\n");    /* First blank line in the reply */
01432        }
01433 
01434        if (ri->content_specify)
01435               (*ri->content_specify)(ri->voidarg);
01436 
01437        writes(ri, "\n");
01438        if (ri->writesig_func)
01439               (*ri->writesig_func)(ri->voidarg);
01440        writes(ri, "\n");
01441 
01442        if (boundary)
01443        {
01444               /* replydsn or replyfeedback */
01445 
01446               char   *header, *value;
01447               struct rfc2045headerinfo *hi;
01448 
01449               writes(ri, "\n--");
01450               writes(ri, boundary);
01451               writes(ri, "\nContent-Type: message/");
01452 
01453               writes(ri, dsn_report_type);
01454               writes(ri, "\n"
01455                      "Content-Transfer-Encoding: 7bit\n\n");
01456 
01457               if (errflag == 0)
01458                      errflag=(*dsn_report_gen)(ri);
01459 
01460               writes(ri, "\n--");
01461               writes(ri, boundary);
01462 
01463               if (ri->fullmsg)
01464               {
01465                      off_t cnt=end_pos - start_pos;
01466                      char buf[BUFSIZ];
01467 
01468                      writes(ri, "\nContent-Type: message/rfc822\n"
01469                             "Content-Disposition: attachment\n\n");
01470 
01471                      if (errflag == 0)
01472                             errflag=SRC_SEEK(ri->src, start_pos);
01473 
01474                      while (errflag == 0 && cnt > 0)
01475                      {
01476                             int n=cnt > sizeof(BUFSIZ) ? BUFSIZ:(int)cnt;
01477 
01478                             n=SRC_READ(ri->src, buf, n);
01479 
01480                             if (n <= 0)
01481                             {
01482                                    errflag= -1;
01483                                    break;
01484                             }
01485                             (*ri->write_func)(buf, n, ri->voidarg);
01486                             cnt -= n;
01487                      }
01488               }
01489               else
01490               {
01491                      writes(ri, "\nContent-Type: text/rfc822-headers; charset=\"iso-8859-1\"\n"
01492                             "Content-Disposition: attachment\n"
01493                             "Content-Transfer-Encoding: 8bit\n\n"
01494                             );
01495 
01496                      hi=rfc2045header_start(ri->src, ri->rfc2045partp);
01497 
01498                      while (hi)
01499                      {
01500                             if (rfc2045header_get(hi, &header, &value,
01501                                                 RFC2045H_NOLC) || !header)
01502                             {
01503                                    rfc2045header_end(hi);
01504                                    break;
01505                             }
01506 
01507                             writes(ri, header);
01508                             writes(ri, ": ");
01509                             writes(ri, value);
01510                             writes(ri, "\n");
01511                      }
01512               }
01513               writes(ri, "\n--");
01514               writes(ri, boundary);
01515               writes(ri, "--\n");
01516               free(boundary);
01517        }
01518        return (errflag);
01519 }
01520 
01521 static void dsn_arrival_date(struct rfc2045_mkreplyinfo *ri)
01522 {
01523        writes(ri, "Arrival-Date: ");
01524 
01525        time_t now;
01526 
01527        time(&now);
01528 
01529        writes(ri, rfc822_mkdate(now));
01530        writes(ri, "\n");
01531 }
01532 
01533 static int replydsn(struct rfc2045_mkreplyinfo *ri)
01534 {
01535        dsn_arrival_date(ri);
01536 
01537        writes (ri, "\n"
01538               "Final-Recipient: rfc822; ");
01539 
01540        writes(ri, ri->dsnfrom);
01541 
01542        writes(ri, "\n"
01543               "Action: delivered\n"
01544               "Status: 2.0.0\n");
01545        return 0;
01546 }
01547 
01548 static int replyfeedback(struct rfc2045_mkreplyinfo *ri)
01549 {
01550        size_t i;
01551 
01552        dsn_arrival_date(ri);
01553        writes(ri, "User-Agent: librfc2045 "
01554               RFC2045PKG "/" RFC2045VER
01555               "\n"
01556               "Version: 1\n");
01557 
01558        for (i=0; ri->feedbackheaders &&
01559                    ri->feedbackheaders[i] && ri->feedbackheaders[i+1];
01560             i += 2)
01561        {
01562               char *p=strdup(ri->feedbackheaders[i]), *q;
01563               char lastch;
01564 
01565               if (!p)
01566                      return -1;
01567 
01568               lastch='-';
01569               for (q=p; *q; q++)
01570               {
01571                      if (*q >= 'A' && *q <= 'Z')
01572                             *q += 'a'-'A';
01573 
01574                      if (lastch == '-' && *q >= 'a' && *q <= 'z')
01575                             *q += 'A' - 'a';
01576                      lastch=*q;
01577               }
01578 
01579               writes(ri, p);
01580               free(p);
01581               writes(ri, ": ");
01582               writes(ri, ri->feedbackheaders[i+1]);
01583               writes(ri, "\n");
01584        }
01585 
01586        return 0;
01587 }
01588 
01589 
01590 /*
01591 ** Accept a list of recipients, and return a list that contains only those
01592 ** recipients that are defined as mailing lists.
01593 */
01594 
01595 static char *do_checkmailinglists(struct rfc822a *a,
01596                               struct rfc2045_mkreplyinfo *,
01597                               char *);
01598 
01599 static char *mlcheck(struct rfc2045_mkreplyinfo *ri, const char *hdr)
01600 {
01601        struct rfc822t *t;
01602        struct rfc822a *a;
01603 
01604        char *mlcopy;
01605        char *p;
01606 
01607        t=rfc822t_alloc_new(hdr, NULL, NULL);
01608 
01609        if (!t)
01610               return (0);
01611 
01612        a=rfc822a_alloc(t);
01613 
01614        if (!a)
01615        {
01616               rfc822t_free(t);
01617               return (0);
01618        }
01619 
01620        mlcopy=strdup(ri->mailinglists ? ri->mailinglists:"");
01621        if (!mlcopy)
01622               p=0;
01623        else
01624        {
01625               p=do_checkmailinglists(a, ri, mlcopy);
01626               free(mlcopy);
01627        }
01628 
01629        rfc822a_free(a);
01630        rfc822t_free(t);
01631        return (p);
01632 }
01633 
01634 static char *do_checkmailinglists(struct rfc822a *a,
01635                               struct rfc2045_mkreplyinfo *ri,
01636                               char *mlbuffer)
01637 {
01638        int i;
01639 
01640        for (i=0; i<a->naddrs; i++)
01641        {
01642               char *p=rfc822_getaddr(a, i);
01643               char *q;
01644 
01645               if (!p)
01646                      return (NULL);
01647 
01648               strcpy(mlbuffer, ri->mailinglists ? ri->mailinglists:"");
01649 
01650               for (q=mlbuffer; (q=strtok(q, "\n \t")) != NULL; q=NULL)
01651               {
01652                      if (strcasecmp(p, q) == 0)
01653                             break;
01654               }
01655 
01656               free(p);
01657               if (q == NULL)
01658               {
01659                      rfc822_deladdr(a, i);
01660                      --i;
01661               }
01662        }
01663 
01664        if (a->naddrs == 0)
01665               return (strdup(""));
01666        return (rfc822_getaddrs(a));
01667 }