Back to index

courier  0.68.2
Classes | Defines | Functions
rfc2045reply.c File Reference
#include "rfc2045_config.h"
#include "rfc2045.h"
#include "rfc2045src.h"
#include "rfc3676parser.h"
#include "rfc822/rfc2047.h"
#include "rfc2045charset.h"
#include "rfc822/rfc822.h"
#include "unicode/unicode.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

Go to the source code of this file.

Classes

struct  replyinfostruct

Defines

#define CBSTR(s)   s, strlen(s), callback_arg
#define BLOWUP

Functions

void rfc2045_enomem ()
static int mkreply (struct rfc2045_mkreplyinfo *)
static int mkforward (struct rfc2045_mkreplyinfo *)
static void mksalutation_datefmt (const char *fmt_start, const char *fmt_end, const char *date, void(*callback_func)(const char *, size_t, void *), void *callback_arg)
static void mksalutation_cb (const char *salutation_template, const char *newsgroup, const char *message_id, const char *newsgroups, const char *sender_addr, const char *sender_name, const char *date, const char *subject, void(*callback_func)(const char *, size_t, void *), void *callback_arg)
static void mksal_count (const char *str, size_t cnt, void *arg)
static void mksal_save (const char *str, size_t cnt, void *arg)
static char * mksalutation (const char *salutation_template, const char *newsgroup, const char *message_id, const char *newsgroups, const char *sender_addr, const char *sender_name, const char *date, const char *subject, const char *charset)
int rfc2045_makereply (struct rfc2045_mkreplyinfo *ri)
static int quotereply (const char *p, size_t l, void *voidptr)
static int output_reply (const char *ptr, size_t cnt, void *arg)
static int reply_begin (size_t quote_level, void *arg)
static int reply_contents (const unicode_char *txt, size_t txt_size, void *arg)
static int reply_end (void *arg)
static int reply_wrap (void *arg)
static void reformat (struct rfc2045_mkreplyinfo *ri, struct rfc2045 *rfc, size_t adjustLevel)
static void replybody (struct rfc2045_mkreplyinfo *ri, struct rfc2045 *rfc)
static void writes (struct rfc2045_mkreplyinfo *ri, const char *c)
static void forwardbody (struct rfc2045_mkreplyinfo *ri, long nbytes)
static int writereferences (struct rfc2045_mkreplyinfo *ri, const char *oldref, const char *oldmsgid)
static char * mlcheck (struct rfc2045_mkreplyinfo *ri, const char *)
static int replydsn (struct rfc2045_mkreplyinfo *)
static int replyfeedback (struct rfc2045_mkreplyinfo *)
static void dsn_arrival_date (struct rfc2045_mkreplyinfo *ri)
static char * do_checkmailinglists (struct rfc822a *a, struct rfc2045_mkreplyinfo *, char *)

Class Documentation

struct replyinfostruct

Definition at line 234 of file rfc2045reply.c.

Collaboration diagram for replyinfostruct:
Class Members
int isflowed
rfc3676_parser_t parser
size_t quote_level
size_t quote_level_adjust
struct rfc2045_mkreplyinfo * ri
int start_line
size_t trailing_spaces
libmail_u_convert_handle_t u_handle

Define Documentation

#define BLOWUP
Value:
{ \
              if (whowrote) free(whowrote); \
              if (subject) free(subject); \
              if (oldmsgid) free(oldmsgid); \
              if (oldreferences)   free(oldreferences); \
              if (oldtocc) free(oldtocc); \
              if (oldtolist) free(oldtolist); \
              if (oldfrom) free(oldfrom); \
              if (oldreplyto)      free(oldreplyto); \
              if (oldenvelope) free(oldenvelope); \
              if (newsgroup) free(newsgroup); \
              if (newsgroups) free(newsgroups); \
              if (date) free(date); \
              rfc2045header_end(hi); \
              return (-1); \
       }
#define CBSTR (   s)    s, strlen(s), callback_arg

Function Documentation

static char * do_checkmailinglists ( struct rfc822a a,
struct rfc2045_mkreplyinfo ri,
char *  mlbuffer 
) [static]

Definition at line 1634 of file rfc2045reply.c.

{
       int i;

       for (i=0; i<a->naddrs; i++)
       {
              char *p=rfc822_getaddr(a, i);
              char *q;

              if (!p)
                     return (NULL);

              strcpy(mlbuffer, ri->mailinglists ? ri->mailinglists:"");

              for (q=mlbuffer; (q=strtok(q, "\n \t")) != NULL; q=NULL)
              {
                     if (strcasecmp(p, q) == 0)
                            break;
              }

              free(p);
              if (q == NULL)
              {
                     rfc822_deladdr(a, i);
                     --i;
              }
       }

       if (a->naddrs == 0)
              return (strdup(""));
       return (rfc822_getaddrs(a));
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void dsn_arrival_date ( struct rfc2045_mkreplyinfo ri) [static]

Definition at line 1521 of file rfc2045reply.c.

{
       writes(ri, "Arrival-Date: ");

       time_t now;

       time(&now);

       writes(ri, rfc822_mkdate(now));
       writes(ri, "\n");
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void forwardbody ( struct rfc2045_mkreplyinfo ri,
long  nbytes 
) [static]

Definition at line 467 of file rfc2045reply.c.

{
       char   buf[BUFSIZ];
       ssize_t i;

       while ((i=nbytes > sizeof(buf) ? sizeof(buf):nbytes) > 0 &&
              (i=SRC_READ(ri->src, buf, i)) > 0)
       {
              nbytes -= i;
              (*ri->write_func)(buf, i, ri->voidarg);
       }
}

Here is the caller graph for this function:

static int mkforward ( struct rfc2045_mkreplyinfo ri) [static]

Definition at line 483 of file rfc2045reply.c.

{
       off_t  start_pos, end_pos, start_body;
       off_t  dummy;

       char   *header, *value;
       char   *subject=0;

       char   *boundary=0;

       struct rfc2045headerinfo *hi;

       struct rfc2045 *textplain_content;
       struct rfc2045 *first_attachment;
       int attachment_is_message_rfc822;

       /*
       ** Use the original message's subject to set the subject of the
       ** forward message.
       */

       hi=rfc2045header_start(ri->src, ri->rfc2045partp);

       if (!hi)
              return (-1);

       for (;;)
       {
              if (rfc2045header_get(hi, &header, &value, 0))
              {
                     rfc2045header_end(hi);
                     return (-1);
              }

              if (!header)
                     break;
              if (strcmp(header, "subject") == 0)
              {
                     if (subject)  free(subject);

                     subject=strdup(value);
                     if (!subject)
                     {
                            rfc2045header_end(hi);
                            return (-1);
                     }
              }
       }

       rfc2045header_end(hi);

       writes(ri, "Subject: ");

       if (ri->subject)
       {
              /*
              ** ... unless the caller overrides it.
              */

              writes(ri, ri->subject);
       }
       else if (subject)
       {
              char   *s=rfc822_coresubj_keepblobs(subject);

              if (!s)
                     return (-1);

              writes(ri, s);
              free(s);
              writes(ri, " (fwd)");
       }
       writes(ri, "\nMime-Version: 1.0\n");

       /*
       ** To assemble a forward template, two things are needed:
       **
       ** 1. The original message, as text/plain.
       **
       ** 2. Any attachments in the original message.
       **    A. The attachments get either copied to the forward message, or
       **    B. The original message is attached as a single message/rfc822
       **       entity.
       **
       ** 2b is always produced by "forwardatt". If a suitable text/plain
       ** part of the original message could not be found, 2b is also
       ** produced even by "forward".
       */

       textplain_content=NULL;

       attachment_is_message_rfc822=0;
       first_attachment=NULL;

       {
              const char *content_type, *dummy;

              struct rfc2045 *top_part=ri->rfc2045partp;

              rfc2045_mimeinfo(top_part,
                             &content_type, &dummy, &dummy);

              if (strcmp(content_type, "multipart/signed") == 0)
              {
                     struct rfc2045 *p=top_part->firstpart;

                     if (p && p->isdummy)
                            p=p->next;

                     if (p)
                     {
                            top_part=p;
                            rfc2045_mimeinfo(top_part,
                                           &content_type, &dummy, &dummy);
                     }
              }
              else if (strcmp(content_type, "multipart/x-mimegpg") == 0)
              {
                     struct rfc2045 *p=top_part->firstpart;

                     if (p && p->isdummy)
                            p=p->next;

                     if (p)
                     {
                            const char *part_ct;

                            rfc2045_mimeinfo(p,
                                           &part_ct, &dummy, &dummy);

                            if (strcmp(part_ct, "text/x-gpg-output") == 0
                                && p->next)
                            {
                                   top_part=p->next;
                                   rfc2045_mimeinfo(top_part,
                                                  &content_type,
                                                  &dummy, &dummy);
                            }
                     }
              }

              if (strcmp(content_type, "text/plain") == 0)
              {
                     textplain_content=top_part;
              }
              else if (strcmp(content_type, "multipart/alternative") == 0)
              {
                     textplain_content=
                            rfc2045_searchcontenttype(top_part,
                                                   "text/plain");
              }
              else if (strcmp(content_type, "multipart/mixed") == 0)
              {
                     struct rfc2045 *p=top_part->firstpart;

                     if (p->isdummy)
                            p=p->next;

                     textplain_content=
                            rfc2045_searchcontenttype(p, "text/plain");

                     /*
                     ** If the first part contained a suitable text/plain,
                     ** any remaining MIME parts become attachments that
                     ** get copied to the forward message.
                     */
                     if (textplain_content)
                            first_attachment=p->next;
              }

              if (strcmp(ri->replymode, "forwardatt") == 0 ||
                  textplain_content == NULL)
              {
                     /*
                     ** Copy the entire message as the sole message/rfc822
                     ** attachment in the forward message.
                     */
                     textplain_content=NULL;
                     first_attachment=top_part;
                     attachment_is_message_rfc822=1;
              }
       }

       boundary=strdup(rfc2045_mk_boundary(ri->rfc2045partp, ri->src));
       if (!boundary)
       {
              if (subject)  free(subject);
              return (-1);
       }

       if (first_attachment)
       {
              writes(ri, "Content-Type: multipart/mixed; boundary=\"");
              writes(ri, boundary);
              writes(ri, "\"\n\n");
              writes(ri, RFC2045MIMEMSG);
              writes(ri, "\n--");
              writes(ri, boundary);
              writes(ri, "\n");
       }

       if (ri->content_set_charset)
       {
              (*ri->content_set_charset)(ri->voidarg);
       }
       else
       {
              writes(ri, "Content-Type: text/plain; format=flowed; delsp=yes; charset=\"");
              writes(ri, ri->charset);
              writes(ri, "\"\n");
       }

       writes(ri, "Content-Transfer-Encoding: 8bit\n\n");
       if (ri->content_specify)
              (*ri->content_specify)(ri->voidarg);

       writes(ri, "\n");
       if (ri->writesig_func)
              (*ri->writesig_func)(ri->voidarg);
       writes(ri, "\n");

       if (ri->forwardsep)
       {
              writes(ri, ri->forwardsep);
              writes(ri, "\n");
       }

       if (textplain_content)
       {
              /* Copy original headers. */
              
              hi=rfc2045header_start(ri->src, ri->rfc2045partp);
              for (;;)
              {
                     if (rfc2045header_get(hi, &header, &value,
                                         RFC2045H_NOLC|RFC2045H_KEEPNL))
                     {
                            rfc2045header_end(hi);
                            break;
                     }
                     if (!header)
                            break;
                     if (strcasecmp(header, "subject") == 0 ||
                         strcasecmp(header, "from") == 0 ||
                         strcasecmp(header, "to") == 0 ||
                         strcasecmp(header, "cc") == 0 ||
                         strcasecmp(header, "date") == 0 ||
                         strcasecmp(header, "message-id") == 0 ||
                         strcasecmp(header, "resent-from") == 0 ||
                         strcasecmp(header, "resent-to") == 0 ||
                         strcasecmp(header, "resent-cc") == 0 ||
                         strcasecmp(header, "resent-date") == 0 ||
                         strcasecmp(header, "resent-message-id") == 0)
                     {
                            if (subject) free(subject);

                            subject=rfc822_display_hdrvalue_tobuf(header,
                                                              value,
                                                              ri->charset,
                                                              NULL,
                                                              NULL);

                            if (subject)
                            {
                                   (*ri->write_func)(header,
                                                   strlen(header),
                                                   ri->voidarg);
                                   (*ri->write_func)(": ", 2, ri->voidarg);
                                   (*ri->write_func)(subject,
                                                   strlen(subject),
                                                   ri->voidarg);
                                   (*ri->write_func)("\n", 1, ri->voidarg);
                            }
                     }
              }
              rfc2045header_end(hi);
              (*ri->write_func)("\n", 1, ri->voidarg);

              reformat(ri, textplain_content, 0);
       }

       if (first_attachment)
       {
              /*
              ** There are attachments to copy
              */

              if (attachment_is_message_rfc822)
              {
                     /* Copy everything as a message/rfc822 */

                     writes(ri, "\n--");
                     writes(ri, boundary);
                     writes(ri, "\nContent-Type: message/rfc822\n");

                     if (ri->forwarddescr)
                     {
                            char *p=rfc2047_encode_str(ri->forwarddescr,
                                                    ri->charset ?
                                                    ri->charset
                                                    : "iso-8859-1",
                                                    rfc2047_qp_allow_any
                                                    );

                            writes(ri, "Content-Description: ");
                            writes(ri, p ? p:"");
                            free(p);
                            writes(ri, "\n");
                     }

                     writes(ri, "\n");

                     rfc2045_mimepos(first_attachment, &start_pos, &end_pos,
                                   &start_body,
                                   &dummy, &dummy);
                     
                     if (SRC_SEEK(ri->src, start_pos) == (off_t)-1)
                     {
                            if (subject) free(subject);
                            free(boundary);
                            return -1;
                     }
                     forwardbody(ri, end_pos - start_pos);
              }
              else
              {
                     /* Copy over individual attachments, one by one */

                     for (; first_attachment;
                          first_attachment=first_attachment->next)
                     {
                            writes(ri, "\n--");
                            writes(ri, boundary);
                            writes(ri, "\n");

                            rfc2045_mimepos(first_attachment, &start_pos,
                                          &end_pos,
                                          &start_body,
                                          &dummy, &dummy);
                     
                            if (SRC_SEEK(ri->src, start_pos) == (off_t)-1)
                            {
                                   if (subject) free(subject);
                                   free(boundary);
                                   return -1;
                            }

                            forwardbody(ri, end_pos - start_pos);
                     }
              }

              writes(ri, "\n--");
              writes(ri, boundary);
              writes(ri, "--\n");
       }

       if (subject) free(subject);
       free(boundary);
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int mkreply ( struct rfc2045_mkreplyinfo ri) [static]

Definition at line 912 of file rfc2045reply.c.

{
       char   *oldtocc, *oldfrom, *oldreplyto, *oldtolist;
       char   *subject;
       char   *oldmsgid;
       char   *oldreferences;
       char   *oldenvelope;
       char   *header, *value;
       char   *date;
       char   *newsgroup;
       char   *newsgroups;

       char   *whowrote;
       off_t  start_pos, end_pos, start_body, dummy;
       int errflag=0;
       char   *boundary;
       char   *dsn_report_type;
       int    (*dsn_report_gen)(struct rfc2045_mkreplyinfo *);

       struct rfc2045headerinfo *hi;

       oldtocc=0;
       oldtolist=0;
       oldfrom=0;
       oldreplyto=0;
       subject=0;
       oldmsgid=0;
       oldreferences=0;
       oldenvelope=0;
       whowrote=0;
       newsgroup=0;
       newsgroups=0;
       date=0;

       rfc2045_mimepos(ri->rfc2045partp, &start_pos, &end_pos, &start_body,
              &dummy, &dummy);

       hi=rfc2045header_start(ri->src, ri->rfc2045partp);

       if (!hi)
              return (-1);

#define BLOWUP { \
              if (whowrote) free(whowrote); \
              if (subject) free(subject); \
              if (oldmsgid) free(oldmsgid); \
              if (oldreferences)   free(oldreferences); \
              if (oldtocc) free(oldtocc); \
              if (oldtolist) free(oldtolist); \
              if (oldfrom) free(oldfrom); \
              if (oldreplyto)      free(oldreplyto); \
              if (oldenvelope) free(oldenvelope); \
              if (newsgroup) free(newsgroup); \
              if (newsgroups) free(newsgroups); \
              if (date) free(date); \
              rfc2045header_end(hi); \
              return (-1); \
       }

       for (;;)
       {
              if (rfc2045header_get(hi, &header, &value, 0))
              {
                     BLOWUP;
                     return (-1);
              }

              if (!header)
                     break;

              if (strcmp(header, "subject") == 0)
              {
                     if (subject)  free(subject);

                     subject=strdup(value);
                     if (!subject)
                            BLOWUP;
              }
              else if (strcmp(header, "reply-to") == 0)
              {
                     if (oldreplyto)      free(oldreplyto);
                     oldreplyto=strdup(value);
                     if (!oldreplyto)
                            BLOWUP;
              }
              else if (strcmp(header, "from") == 0)
              {
                     if (oldfrom)  free(oldfrom);
                     oldfrom=strdup(value);
                     if (!oldfrom)
                            BLOWUP;
              }
              else if (strcmp(header, "message-id") == 0)
              {
                     if (oldmsgid) free(oldmsgid);
                     oldmsgid=strdup(value);
                     if (!oldmsgid)
                            BLOWUP;
              }
              else if (strcmp(header, "references") == 0)
              {
                     if (oldreferences)   free(oldreferences);
                     oldreferences=strdup(value);
                     if (!oldreferences)
                            BLOWUP;
              }
              else if ((strcmp(header, "return-path") == 0 ||
                       strcmp(header, "errors-to") == 0) &&
                      ri->replytoenvelope)
              {
                     if (oldenvelope)     free(oldenvelope);
                     oldenvelope=strdup(value);
                     if (!oldenvelope)
                            BLOWUP;
              }
              else if (strcmp(header, "newsgroups") == 0)
              {
                     if (newsgroups)      free(newsgroups);
                     newsgroups=strdup(value);
                     if (!newsgroups)
                            BLOWUP;
              }
              else if (strcmp(header, "x-newsgroup") == 0)
              {
                     if (newsgroup)       free(newsgroup);
                     newsgroup=strdup(value);
                     if (!newsgroup)
                            BLOWUP;
              }
              else if (strcmp(header, "date") == 0)
              {
                     if (date)     free(date);
                     date=strdup(value);
                     if (!date)
                            BLOWUP;
              }
              else if ((strcmp(ri->replymode, "replyall") == 0
                       || strcmp(ri->replymode, "replylist") == 0) &&
                      (
                       strcmp(header, "to") == 0 ||
                       strcmp(header, "cc") == 0
                       )
                      )
              {
                     char   *newh=malloc( (oldtocc ?
                                          strlen(oldtocc):0)
                                         + strlen(value)+2);
                     char   *p;

                            if (!newh)
                                   BLOWUP;

                            *newh=0;
                            if (oldtocc)
                                   strcat(strcpy(newh, oldtocc),
                                                        ",");
                            strcat(newh, value);
                            if (oldtocc)  free(oldtocc);
                            oldtocc=newh;

                            p=mlcheck(ri, value);
                            if (!p || (newh=malloc((oldtolist ?
                                                 strlen(oldtolist):0)
                                      + strlen(p)+2)) == NULL)
                            {
                                   if (p)
                                          free(p);
                                   BLOWUP;
                            }

                            if (*p)
                            {
                                   *newh=0;
                                   if (oldtolist)
                                          strcat(strcpy(newh, oldtolist),
                                                 ",");
                                   strcat(newh, p);
                                   if (oldtolist)
                                          free(oldtolist);
                                   oldtolist=newh;
                            }
                            free(p);
              }
       }

       rfc2045header_end(hi);

       /* Write:  "%s writes:" */

       {
              struct rfc822t *rfcp=rfc822t_alloc_new(oldfrom ? oldfrom:"",
                                                 NULL, NULL);
              struct rfc822a *rfcpa;
              char   *sender_name=NULL;
              char   *sender_addr=NULL;
              int    n;

              if (!rfcp)
                     BLOWUP;

              rfcpa=rfc822a_alloc(rfcp);
              if (!rfcpa)
              {
                     rfc822t_free(rfcp);
                     BLOWUP;
              }

              for (n=0; n<rfcpa->naddrs; ++n)
              {
                     if (rfcpa->addrs[n].tokens == NULL)
                            continue;

                     sender_name=rfc822_display_name_tobuf(rfcpa, n,
                                                       ri->charset);
                     sender_addr=rfc822_display_addr_tobuf(rfcpa, n,
                                                       ri->charset);
                     break;
              }

              rfc822a_free(rfcpa);
              rfc822t_free(rfcp);

              whowrote=mksalutation(ri->replysalut,
                                  newsgroup ? newsgroup:"",
                                  oldmsgid ? oldmsgid:"",
                                  newsgroups ? newsgroups:"",

                                  sender_addr ? sender_addr:"(no address given)",
                                  sender_name ? sender_name:sender_addr,
                                  date,
                                  subject,
                                  ri->charset);

              if (sender_name)
                     free(sender_name);
              if (sender_addr)
                     free(sender_addr);

              if (!whowrote)
              {
                     BLOWUP;
              }
       }

       if (newsgroups)
              free(newsgroups);
       if (newsgroup)
              free(newsgroup);
       if (date)
              free(date);
       if (oldreplyto)
       {
              if (oldfrom)  free(oldfrom);
              oldfrom=oldreplyto;
              oldreplyto=0;
       }

       if (oldenvelope)
       {
              if (oldfrom)  free(oldfrom);
              oldfrom=oldenvelope;
              oldenvelope=0;
       }

       /*
       ** Replytolist: if we found mailing list addresses, drop
       ** oldtocc, we'll use oldtolist.
       ** Otherwise, drop oldtolist.
       */

       if (strcmp(ri->replymode, "replylist") == 0)
       {
              if (oldtolist)
              {
                     if (oldtocc)
                     {
                            free(oldtocc);
                            oldtocc=0;
                     }

                     if (oldfrom)
                     {
                            free(oldfrom);
                            oldfrom=0;
                     }
              }
       }
       else
       {
              if (oldtolist)
              {
                     free(oldtolist);
                     oldtolist=NULL;
              }
       }

       /* Remove duplicate entries from new Cc header */

       if (oldtocc)
       {
              struct rfc822t       *rfccc, *rfcto;
              struct rfc822a       *arfccc, *arfcto;
              int    i, j;
              char   *new_addresses;

              rfccc=rfc822t_alloc_new(oldtocc, NULL, NULL);
              rfcto= oldfrom ? rfc822t_alloc_new(oldfrom, NULL,
                                             NULL):NULL;
              arfccc=rfccc ? rfc822a_alloc(rfccc):NULL;
              arfcto=rfcto ? rfc822a_alloc(rfcto):NULL;

              for (i=0; arfccc && i <arfccc->naddrs; i++)
              {
                     char   *addr=rfc822_getaddr(arfccc, i);

                     if (!addr)    continue;

                            /* Remove address from Cc if it is my address */

                     if ( (ri->myaddr_func)(addr, ri->voidarg))
                     {
                            rfc822_deladdr(arfccc, i); --i;
                            free(addr);
                            continue;
                     }

                            /* Remove address from Cc if it appears in To: */

                     for (j=0; arfcto && j < arfcto->naddrs; j++)
                     {
                            char *addr2=rfc822_getaddr(arfcto, j);

                            if (!addr2)   continue;
                            if (strcmp(addr, addr2) == 0)
                            {
                                   free(addr2);
                                   break;
                            }
                            free(addr2);
                     }
                     if (arfcto && j < arfcto->naddrs)
                     {
                            rfc822_deladdr(arfccc, i); --i;
                            free(addr);
                            continue;
                     }

                            /* Remove outright duplicates in Cc */

                     for (j=i+1; j<arfccc->naddrs; j++)
                     {
                            char *addr2=rfc822_getaddr(arfccc, j);

                            if (!addr2)   continue;
                            if (strcmp(addr, addr2) == 0)
                            {
                                   rfc822_deladdr(arfccc, j);
                                   --j;
                            }
                            free(addr2);
                     }
                     free(addr);
              }
              new_addresses=rfc822_getaddrs(arfccc);
              free(oldtocc);
              oldtocc=new_addresses;
              if (arfccc)   rfc822a_free(arfccc);
              if (arfcto)   rfc822a_free(arfcto);
              rfc822t_free(rfccc);
              if (rfcto) rfc822t_free(rfcto);
       }

       if (strcmp(ri->replymode, "feedback") == 0)
       {
              if (oldtolist)
              {
                     free(oldtolist);
                     oldtolist=NULL;
              }

              if (oldfrom)
              {
                     free(oldfrom);
                     oldfrom=NULL;
              }

              if (oldtocc)
              {
                     free(oldtocc);
                     oldtocc=NULL;
              }
       }

       if (oldtolist)
       {
              writes(ri, "To: ");
              writes(ri, oldtolist);
              writes(ri, "\n");
              free(oldtolist);
       }

       if (oldfrom)
       {
              writes(ri, "To: ");
              writes(ri, oldfrom);
              writes(ri, "\n");
              free(oldfrom);
       }

       if (oldtocc)
       {
              writes(ri, "Cc: ");
              writes(ri, oldtocc);
              writes(ri, "\n");
              free(oldtocc);
       }

       if (oldmsgid || oldreferences)
       {
              writes(ri, "References: ");
              if (writereferences(ri, oldreferences, oldmsgid))
                     errflag= -1;
              if (oldreferences)   free(oldreferences);
       }
       if (oldmsgid)
       {
              writes(ri, "In-Reply-To: ");
              writes(ri, oldmsgid);
              writes(ri, "\n");
              free(oldmsgid);
       }
       writes(ri,"Subject: ");

       if (ri->subject)
       {
              writes(ri, ri->subject);
       }
       else if (subject)
       {
              if (strcmp(ri->replymode, "feedback") == 0 ||
                  strcmp(ri->replymode, "replyfeedback") == 0)
              {
                     writes(ri, subject);
              }
              else
              {
                     char   *s=rfc822_coresubj_keepblobs(subject);

                     writes(ri, "Re: ");
                     writes(ri, s ? s:"");
                     if (s) free(s);
              }
              free(subject);
       }

       writes(ri, "\nMime-Version: 1.0\n");

       boundary=NULL;
       dsn_report_type=NULL;

       if (strcmp(ri->replymode, "replydsn") == 0 && ri->dsnfrom)
       {
              dsn_report_type="delivery-status";
              dsn_report_gen=&replydsn;
       }
       else if (strcmp(ri->replymode, "replyfeedback") == 0 ||
               strcmp(ri->replymode, "feedback") == 0)
       {
              dsn_report_type="feedback-report";
              dsn_report_gen=&replyfeedback;
       }

       if (dsn_report_type)
       {
              boundary=rfc2045_mk_boundary(ri->rfc2045partp, ri->src);
              if (!boundary)
                     return (-1);

              writes(ri, "Content-Type: multipart/report;"
                     " report-type=");

              writes(ri, dsn_report_type);
              writes(ri, ";\n    boundary=\"");

              writes(ri, boundary);

              writes(ri,"\"\n"
                     "\n"
                     RFC2045MIMEMSG
                     "\n"
                     "--");
              writes(ri, boundary);
              writes(ri, "\n");
       }

       if (ri->content_set_charset)
       {
              (*ri->content_set_charset)(ri->voidarg);
       }
       else
       {
              writes(ri, "Content-Type: text/plain; format=flowed; delsp=yes; charset=\"");
              writes(ri, ri->charset);
              writes(ri, "\"\n");
       }
       writes(ri, "Content-Transfer-Encoding: 8bit\n\n");

       if (!ri->donotquote)
       {
              if (whowrote)
              {
                     writes(ri, whowrote);
                     free(whowrote);
                     writes(ri, "\n\n");
              }
              if (SRC_SEEK(ri->src, start_body) == (off_t)-1)
                     return (-1);

              replybody(ri, ri->rfc2045partp);
              writes(ri, "\n");    /* First blank line in the reply */
       }

       if (ri->content_specify)
              (*ri->content_specify)(ri->voidarg);

       writes(ri, "\n");
       if (ri->writesig_func)
              (*ri->writesig_func)(ri->voidarg);
       writes(ri, "\n");

       if (boundary)
       {
              /* replydsn or replyfeedback */

              char   *header, *value;
              struct rfc2045headerinfo *hi;

              writes(ri, "\n--");
              writes(ri, boundary);
              writes(ri, "\nContent-Type: message/");

              writes(ri, dsn_report_type);
              writes(ri, "\n"
                     "Content-Transfer-Encoding: 7bit\n\n");

              if (errflag == 0)
                     errflag=(*dsn_report_gen)(ri);

              writes(ri, "\n--");
              writes(ri, boundary);

              if (ri->fullmsg)
              {
                     off_t cnt=end_pos - start_pos;
                     char buf[BUFSIZ];

                     writes(ri, "\nContent-Type: message/rfc822\n"
                            "Content-Disposition: attachment\n\n");

                     if (errflag == 0)
                            errflag=SRC_SEEK(ri->src, start_pos);

                     while (errflag == 0 && cnt > 0)
                     {
                            int n=cnt > sizeof(BUFSIZ) ? BUFSIZ:(int)cnt;

                            n=SRC_READ(ri->src, buf, n);

                            if (n <= 0)
                            {
                                   errflag= -1;
                                   break;
                            }
                            (*ri->write_func)(buf, n, ri->voidarg);
                            cnt -= n;
                     }
              }
              else
              {
                     writes(ri, "\nContent-Type: text/rfc822-headers; charset=\"iso-8859-1\"\n"
                            "Content-Disposition: attachment\n"
                            "Content-Transfer-Encoding: 8bit\n\n"
                            );

                     hi=rfc2045header_start(ri->src, ri->rfc2045partp);

                     while (hi)
                     {
                            if (rfc2045header_get(hi, &header, &value,
                                                RFC2045H_NOLC) || !header)
                            {
                                   rfc2045header_end(hi);
                                   break;
                            }

                            writes(ri, header);
                            writes(ri, ": ");
                            writes(ri, value);
                            writes(ri, "\n");
                     }
              }
              writes(ri, "\n--");
              writes(ri, boundary);
              writes(ri, "--\n");
              free(boundary);
       }
       return (errflag);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void mksal_count ( const char *  str,
size_t  cnt,
void *  arg 
) [static]

Definition at line 153 of file rfc2045reply.c.

{
       *(size_t *)arg += cnt;
}

Here is the caller graph for this function:

static void mksal_save ( const char *  str,
size_t  cnt,
void *  arg 
) [static]

Definition at line 160 of file rfc2045reply.c.

{
       if (cnt)
              memcpy(*(char **)arg, str, cnt);

       *(char **)arg += cnt;
}

Here is the caller graph for this function:

static char* mksalutation ( const char *  salutation_template,
const char *  newsgroup,
const char *  message_id,
const char *  newsgroups,
const char *  sender_addr,
const char *  sender_name,
const char *  date,
const char *  subject,
const char *  charset 
) [static]

Definition at line 170 of file rfc2045reply.c.

{
       size_t cnt;
       char *p, *q;

       char *subj_decoded=rfc822_display_hdrvalue_tobuf("subject", subject,
                                                  charset, NULL, NULL);

       if (!subj_decoded)
              return NULL;

       cnt=1;

       mksalutation_cb(salutation_template,
                     newsgroup,
                     message_id,
                     newsgroups,
                     sender_addr,
                     sender_name,
                     date,
                     subj_decoded,
                     mksal_count, &cnt);

       p=q=malloc(cnt);

       if (!p)
       {
              free(subj_decoded);
              return NULL;
       }

       mksalutation_cb(salutation_template,
                     newsgroup,
                     message_id,
                     newsgroups,
                     sender_addr,
                     sender_name,
                     date,
                     subj_decoded,
                     mksal_save, &q);
       *q=0;

       free(subj_decoded);
       return p;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void mksalutation_cb ( const char *  salutation_template,
const char *  newsgroup,
const char *  message_id,
const char *  newsgroups,
const char *  sender_addr,
const char *  sender_name,
const char *  date,
const char *  subject,
void(*)(const char *, size_t, void *)  callback_func,
void *  callback_arg 
) [static]

Definition at line 70 of file rfc2045reply.c.

{
       const char *p;

       for (p=salutation_template; *p; p++)
       {
              const char *fmt_start=0, *fmt_end=0;

              if (*p != '%' || p[1] == '\0')
              {
                     (*callback_func)( p, 1, callback_arg );
                     continue;
              }

              ++p;

              if (*p == '{')
              {
                     fmt_start= ++p;

                     while (*p)
                     {
                            if (*p == '}')
                            {
                                   fmt_end=p;
                                   ++p;
                                   break;
                            }
                     }

                     if (!fmt_end)
                            continue;
              }

#define CBSTR(s) s, strlen(s), callback_arg

              switch (*p)   {
              case 'n':
                     (*callback_func)("\n", 1, callback_arg );
                     continue;
              case 'C':
                     (*callback_func)(CBSTR(newsgroup));
                     break;
              case 'i':
                     (*callback_func)(CBSTR(message_id));
                     break;
              case 'N':
                     (*callback_func)(CBSTR(newsgroups));
                     break;
              case 'f':
                     (*callback_func)(CBSTR(sender_addr));
                     break;
              case 'F':
                     (*callback_func)(CBSTR(sender_name));
                     break;
              case 'd':
                     mksalutation_datefmt(fmt_start,
                                        fmt_end,
                                        date,
                                        callback_func, callback_arg);
                     break;
              case 's':
                     (*callback_func)(CBSTR(subject));
                     break;
              default:
                     (*callback_func)(p, 1, callback_arg);
                     break;
              }
#undef CBSTR

       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void mksalutation_datefmt ( const char *  fmt_start,
const char *  fmt_end,
const char *  date,
void(*)(const char *, size_t, void *)  callback_func,
void *  callback_arg 
) [static]

Definition at line 26 of file rfc2045reply.c.

{
       time_t t;

       if (!fmt_start)
       {
              fmt_start="%a, %d %b %Y %H:%M:%S %z";
              fmt_end=fmt_start + strlen(fmt_start);
       }

       if ((t=rfc822_parsedt(date)))
       {
              struct tm tmbuf;

              if (localtime_r(&t, &tmbuf))
              {
                     char *fmtstr=malloc(fmt_end-fmt_start + 1);

                     if (fmtstr)
                     {
                            char fmtbuf[1024];

                            memcpy(fmtstr, fmt_start, fmt_end - fmt_start);
                            fmtstr[fmt_end-fmt_start]=0;

                            fmtbuf[strftime(fmtbuf,
                                          sizeof(fmtbuf)-1,
                                          fmtstr, &tmbuf)]=0;

                            free(fmtstr);
                            (*callback_func)(fmtbuf, strlen(fmtbuf),
                                           callback_arg);
                            return;
                     }
              }
       }
       (*callback_func)(date, strlen(date), callback_arg);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static char * mlcheck ( struct rfc2045_mkreplyinfo ri,
const char *  hdr 
) [static]

Definition at line 1599 of file rfc2045reply.c.

{
       struct rfc822t *t;
       struct rfc822a *a;

       char *mlcopy;
       char *p;

       t=rfc822t_alloc_new(hdr, NULL, NULL);

       if (!t)
              return (0);

       a=rfc822a_alloc(t);

       if (!a)
       {
              rfc822t_free(t);
              return (0);
       }

       mlcopy=strdup(ri->mailinglists ? ri->mailinglists:"");
       if (!mlcopy)
              p=0;
       else
       {
              p=do_checkmailinglists(a, ri, mlcopy);
              free(mlcopy);
       }

       rfc822a_free(a);
       rfc822t_free(t);
       return (p);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int output_reply ( const char *  ptr,
size_t  cnt,
void *  arg 
) [static]

Definition at line 263 of file rfc2045reply.c.

{
       struct replyinfostruct *s=(struct replyinfostruct *)arg;

       (*s->ri->write_func)(ptr, cnt, s->ri->voidarg);
       return 0;
}

Here is the caller graph for this function:

static int quotereply ( const char *  p,
size_t  l,
void *  voidptr 
) [static]

Definition at line 252 of file rfc2045reply.c.

{
       struct replyinfostruct *ris=(struct replyinfostruct *)voidptr;

       return rfc3676parser(ris->parser, p, l);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void reformat ( struct rfc2045_mkreplyinfo ri,
struct rfc2045 rfc,
size_t  adjustLevel 
) [static]

Definition at line 418 of file rfc2045reply.c.

{
       struct replyinfostruct ris;

       struct rfc3676_parser_info info;
       int conv_err;

       ris.ri=ri;
       ris.quote_level_adjust=adjustLevel;

       memset(&info, 0, sizeof(info));

       info.charset=ri->charset;
       ris.isflowed=info.isflowed=rfc2045_isflowed(rfc);
       info.isdelsp=rfc2045_isdelsp(rfc);

       info.line_begin=reply_begin;
       info.line_contents=reply_contents;
       info.line_flowed_notify=reply_wrap;
       info.line_end=reply_end;
       info.arg=&ris;

       if ((ris.parser=rfc3676parser_init(&info)) != NULL)
       {
              rfc2045_decodetextmimesection(ri->src, rfc,
                                         ri->charset,
                                         &conv_err,
                                         quotereply,
                                         &ris);
              rfc3676parser_deinit(ris.parser, NULL);
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int reply_begin ( size_t  quote_level,
void *  arg 
) [static]

Definition at line 274 of file rfc2045reply.c.

{
       struct replyinfostruct *s=(struct replyinfostruct *)arg;
       unicode_char quoteChar='>';

       /*
       ** Save quote level, begin conversion from unicode to the native
       ** charset.
       */
       s->quote_level=quote_level+s->quote_level_adjust;

       s->u_handle=libmail_u_convert_init(libmail_u_ucs4_native,
                                      s->ri->charset,
                                      output_reply,
                                      s);

       /*
       ** Emit quoting indentation, if any.
       */
       s->start_line=1;
       s->trailing_spaces=0;

       if (s->u_handle)
       {
              size_t i;

              for (i=0; i<s->quote_level; i++)
              {
                     libmail_u_convert_uc(s->u_handle, &quoteChar, 1);
              }
       }
       return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int reply_contents ( const unicode_char txt,
size_t  txt_size,
void *  arg 
) [static]

Definition at line 313 of file rfc2045reply.c.

{
       unicode_char spaceChar=' ';
       size_t nonspc_cnt;

       struct replyinfostruct *s=(struct replyinfostruct *)arg;

       if (!s->u_handle || txt_size == 0)
              return 0;

       /*
       ** Space-stuff the initial character.
       */

       if (s->start_line)
       {
              if (!s->isflowed)
              {
                     /*
                     ** If the original content is not flowed, the rfc3676
                     ** parser does not parse the number of > quote
                     ** characters and does not set the quote level.
                     */

                     if ((s->quote_level > 0 && *txt != '>') || *txt == ' ')
                            libmail_u_convert_uc(s->u_handle,
                                               &spaceChar, 1);

              }
              else
              {
                     if (s->quote_level > 0 || *txt == ' ' || *txt == '>')
                            libmail_u_convert_uc(s->u_handle,
                                               &spaceChar, 1);
              }
              s->start_line=0;
       }

       /*
       ** Trim any trailing spaces from the RFC 3676 parsed content.
       */

       for (nonspc_cnt=txt_size; nonspc_cnt > 0; --nonspc_cnt)
              if (txt[nonspc_cnt-1] != ' ')
                     break;

       /*
       ** If the contents are not totally whitespace, it's ok now to emit
       ** any accumulated whitespace from previous content.
       */

       if (nonspc_cnt)
       {
              while (s->trailing_spaces)
              {
                     libmail_u_convert_uc(s->u_handle, &spaceChar, 1);
                     --s->trailing_spaces;
              }

              libmail_u_convert_uc(s->u_handle, txt, nonspc_cnt);
       }

       s->trailing_spaces += txt_size - nonspc_cnt;
       return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int reply_end ( void *  arg) [static]

Definition at line 381 of file rfc2045reply.c.

{
       unicode_char newLine='\n';
       struct replyinfostruct *s=(struct replyinfostruct *)arg;

       libmail_u_convert_uc(s->u_handle, &newLine, 1);

       libmail_u_convert_deinit(s->u_handle, NULL);
       return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int reply_wrap ( void *  arg) [static]

Definition at line 395 of file rfc2045reply.c.

{
       unicode_char spaceChar=' ';
       struct replyinfostruct *s=(struct replyinfostruct *)arg;

       /*
       ** It's safe to preserve trailing spaces on flowed lines.
       */

       while (s->trailing_spaces)
       {
              libmail_u_convert_uc(s->u_handle, &spaceChar, 1);
              --s->trailing_spaces;
       }

       libmail_u_convert_uc(s->u_handle, &spaceChar, 1);
       reply_end(s);
       reply_begin(s->quote_level-s->quote_level_adjust, s);
       /* Undo the adjustment in reply_begin() */

       return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void replybody ( struct rfc2045_mkreplyinfo ri,
struct rfc2045 rfc 
) [static]

Definition at line 452 of file rfc2045reply.c.

{
       rfc=rfc2045_searchcontenttype(rfc, "text/plain");

       if (!rfc)
              return;

       reformat(ri, rfc, 1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int replydsn ( struct rfc2045_mkreplyinfo ri) [static]

Definition at line 1533 of file rfc2045reply.c.

{
       dsn_arrival_date(ri);

       writes (ri, "\n"
              "Final-Recipient: rfc822; ");

       writes(ri, ri->dsnfrom);

       writes(ri, "\n"
              "Action: delivered\n"
              "Status: 2.0.0\n");
       return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int replyfeedback ( struct rfc2045_mkreplyinfo ri) [static]

Definition at line 1548 of file rfc2045reply.c.

{
       size_t i;

       dsn_arrival_date(ri);
       writes(ri, "User-Agent: librfc2045 "
              RFC2045PKG "/" RFC2045VER
              "\n"
              "Version: 1\n");

       for (i=0; ri->feedbackheaders &&
                   ri->feedbackheaders[i] && ri->feedbackheaders[i+1];
            i += 2)
       {
              char *p=strdup(ri->feedbackheaders[i]), *q;
              char lastch;

              if (!p)
                     return -1;

              lastch='-';
              for (q=p; *q; q++)
              {
                     if (*q >= 'A' && *q <= 'Z')
                            *q += 'a'-'A';

                     if (lastch == '-' && *q >= 'a' && *q <= 'z')
                            *q += 'A' - 'a';
                     lastch=*q;
              }

              writes(ri, p);
              free(p);
              writes(ri, ": ");
              writes(ri, ri->feedbackheaders[i+1]);
              writes(ri, "\n");
       }

       return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rfc2045_enomem ( )

Definition at line 44 of file pcp.c.

{
       fprintf(stderr, "Out of memory.\n");
       exit(1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int rfc2045_makereply ( struct rfc2045_mkreplyinfo ri)

Definition at line 225 of file rfc2045reply.c.

{
       if (strcmp(ri->replymode, "forward") == 0
           || strcmp(ri->replymode, "forwardatt") == 0)
              return (mkforward(ri));

       return (mkreply(ri));
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int writereferences ( struct rfc2045_mkreplyinfo ri,
const char *  oldref,
const char *  oldmsgid 
) [static]

Definition at line 845 of file rfc2045reply.c.

{
char   *buf=malloc((oldref ? strlen(oldref):0)
              + (oldmsgid ? strlen(oldmsgid):0)+2);
char   *p, *q;
struct rfc822t *tp;
struct rfc822a *ap;
int    i;

       if (!buf)
              return (-1);

       /* Create new references header */
       *buf=0;
       if (oldref)   strcat(buf, oldref);
       if (oldref && oldmsgid)     strcat(buf, " ");
       if (oldmsgid) strcat(buf, oldmsgid);

       /* Do wrapping the RIGHT way, by
       ** RFC822 parsing the References: header
       */

       if ((tp=rfc822t_alloc_new(buf, NULL, NULL)) == 0 ||
              (ap=rfc822a_alloc(tp)) == 0)
       {
              free(buf);
              if (tp)
                     rfc822t_free(tp);
              return (-1);
       }

       /* Keep only the last 20 message IDs */

       i=0;
       if (ap->naddrs > 20) i=ap->naddrs-20;
       p="";
       while (i < ap->naddrs)
       {
              q=rfc822_gettok(ap->addrs[i].tokens);
              if (!q)
              {
                     rfc822a_free(ap);
                     rfc822t_free(tp);
                     free(buf);
                     return (-1);
              }

              writes(ri, p);
              writes(ri, "<");
              writes(ri, q);
              writes(ri, ">\n");
              p="            ";
              free(q);
              i++;
       }
       rfc822a_free(ap);
       rfc822t_free(tp);
       free(buf);
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void writes ( struct rfc2045_mkreplyinfo ri,
const char *  c 
) [static]

Definition at line 462 of file rfc2045reply.c.

{
       (*ri->write_func)(c, strlen(c), ri->voidarg);
}