Logo Search packages:      
Sourcecode: af version File versions  Download package

composition.c

/* Composition.c - Composition handling routines for af.
   Copyright (C) 2002, 2003 Malc Arnold.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston,
   MA 02111-1307  USA */


#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include "af.h"
#include "sendmail.h"
#include "keyseq.h"
#include "functions.h"
#include "variable.h"
#include "io.h"
#include "mime.h"
#include "version.h"
#include STRING_HDR

/****************************************************************************/
/* RCS info */

#ifndef lint
static char *RcsId = "$Id: composition.c,v 1.3 2003/11/27 01:45:57 malc Exp $";
#endif /* ! lint */

/****************************************************************************/
/* Global function declarations */

extern char *xmalloc(), *xstrdup(), *vstrcat(), *tempnam();
extern char *ttyname(), *strerror(), *strdate(), *strudate();
extern char *c_contype(), *set_param(), *encode_header_line();
extern char *decode_header(), *get_addr(), *utos(), *get_home();
extern char *get_vtext(), *get_header();
extern int isatty(), unlink(), strcasecmp(), get_vval(), edit_file();
extern int write_text(), match_contype(), check_dest_headers();
extern int is_header(), is_fromline(), is_blank(), mmdf_form();
extern int compose_mail(), add_user_header(), set_up_headers();
extern int set_up_copying(), set_up_sigfile();
extern void free(), cmsg(), emsg(), emsgl(), typeout(), set_header();
extern void init_composition_headers(), init_body_part_headers();
extern void sign_composition(), check_mime_headers(), reset_headers();
extern void autofold_headers(), delete_headers(), copy_message_text();
extern void free_text(), free_headers(), free_messages();
extern MESSAGE *composition_message(), *read_message();
extern MESSAGE *update_message_from_text();
extern HEADER *find_dest_header();
extern TEXTLINE *append_text(), *insert_text();
extern TEXTLINE *delete_text(), *replace_text();
extern TEXTLINE *encode_text_list(), *decode_text_list();
extern DATEZONE *date_now();

/* Local function declarations */

int read_composition(), write_composition();
int save_composition(), update_composition();
void free_composition();
static int reset_stdin(), write_headers();
static void update_composition_body(), update_composition_header_text();
static void delete_header_text(), add_from_line_to_text();
static void add_header_line_to_text(), add_blank_line_to_text();
static void save_unsent_composition(), encode_composition();
static COMPOSITION *make_composition();
static TEXTLINE *copy_from_lines();

/****************************************************************************/
/* Import the system error number */

extern int errno;

/****************************************************************************/
/* Import the user quit flag from commands.c */

extern int user_quit;

/****************************************************************************/
COMPOSITION *init_composition(to, cc, bcc, subject, contype,
                        filnam, orig_msg, mail_flags)
char *to, *cc, *bcc, *subject, *contype, *filnam;
MESSAGE *orig_msg;
int mail_flags;
{
      /* Create and initialise a new composition */

      char *prefix, *preface, *headers_to_copy;
      int quote_8bit;
      COMPOSITION *comp;

      /* First of all we make a new composition */

      comp = make_composition(mail_flags, filnam);

      /* Set up the header definitions for the composition */

      init_composition_headers(comp, to, cc, bcc, subject,
                         contype, filnam, orig_msg);

      /* If we have a file to read then we'd better read it now */

      if ((filnam != NULL || !isatty(fileno(stdin)))
          && (!read_composition(comp, filnam, (filnam == NULL)
                          ? get_vval(V_EDIT_IHDRS) : V_FALSE)
            || !isatty(fileno(stdin)) && !reset_stdin())) {
            /* Failed to read the file or reset stdin */

            free_composition(comp);
            return(NULL);
      }

      /* End any typeout caused by reading from stdin */

      typeout(NULL);

      /* Set up the headers, copying flag and signature file */

      if (!set_up_headers(comp) || !set_up_copying(comp, orig_msg)
          || !set_up_sigfile(comp)) {
            /* Error in the headers or user quit */

            free_composition(comp);
            return(NULL);
      }

      /* If we are copying text then do so */

      if (orig_msg != NULL && comp->copy) {
            /* Determine the parameters for the copy */

            preface = (comp->bounce || comp->editing)
                  ? NULL : get_vtext(V_PREFACE);
            prefix = (comp->bounce || comp->editing)
                  ? NULL : get_vtext(V_COPY_PFX);
            headers_to_copy = (comp->bounce || comp->editing)
                  ? NULL : get_vtext(V_TOCOPY);
            quote_8bit = (!comp->bounce && !comp->editing
                        && orig_msg->charset != NULL
                        && strcasecmp(orig_msg->charset, US_ASCII)
                        && strcasecmp(orig_msg->charset,
                                  get_vtext(V_CHARSET)));

            /* Copy the text of the message and update it */

            copy_message_text(comp->message, orig_msg, preface,
                          prefix, headers_to_copy, TRUE,
                          !comp->bounce && !comp->editing,
                          quote_8bit, comp->editing,
                          FALSE, FOLD_WIDTH);

            /* And update the composition */

            (void) update_composition(comp, NULL, FALSE);
      }

      /* That's the composition initialised */

      return(comp);
}
/****************************************************************************/
COMPOSITION *init_body_part_composition(contype, filnam, silent, attachment)
char *contype, *filnam;
int silent, attachment;
{
      /* Create and initialise a new composition for a body part */

      COMPOSITION *comp;

      /* First of all we make a new composition */

      comp = make_composition(SM_BODY_PART, filnam);

      /* Set up the header definitions for the composition */

      init_body_part_headers(comp, contype, filnam, attachment);

      /* If we have a file to read then we'd better read it now */

      if (filnam != NULL && !read_composition(comp, filnam, FALSE)) {
            /* Failed to read the file */

            free_composition(comp);
            return(NULL);
      }

      /* Set up the headers */

      if (!silent && !set_up_headers(comp)) {
            /* Error in the headers or user quit */

            free_composition(comp);
            return(NULL);
      }

      /* And update the composition */

      (void) update_composition(comp, NULL, FALSE);

      /* That's the composition initialised */

      return(comp);
}
/****************************************************************************/
void free_composition(comp)
COMPOSITION *comp;
{
      /* Free up the space used by a composition */

      if (comp != NULL) {
            /* Free the composition message and headers */

            free_messages(comp->message);
            free_headers(comp->headers);

            /* Now free the signature file */

            if (comp->sigfile != NULL) {
                  free(comp->sigfile);
            }

            /* And the encoding used */

            if (comp->encoded != NULL) {
                  free(comp->encoded);
            }

            /* And the composition itself */

            free(comp);
      }

      /* That's done */

      return;
}
/****************************************************************************/
int read_composition(comp, filnam, headers)
COMPOSITION *comp;
char *filnam;
int headers;
{
      /*
       * Read the composition (with or without headers) from a
       * file, or from stdin if filnam is NULL.  Returns TRUE
       * unless some system error prevents reading of the file,
       * or a failure occurs in silent mail.
       */

      int status;
      FILE *fp;
      MESSAGE *message = NULL;

      /* Open the file to read */

      if ((fp = (filnam != NULL) ? fopen(filnam, "r") : stdin) == NULL) {
            emsgl("Can't open ", filnam, ": ", strerror(errno), NULL);
            return(FALSE);
      }

      /* Read the message from the file, possibly copying headers */

      message = read_message(fp, (headers) ? NULL : message,
                         TRUE, comp->editing, FALSE);

      /* Update the composition from the message text */

      status = update_composition(comp, message, headers);

      /* And close the file */

      if (filnam != NULL) {
            (void) fclose(fp);
      }

      /* End any typeout unless reading from stdin */

      if (filnam != NULL) {
            typeout(NULL);
      }

      /* Now handle the case of errors in silent mail */

      if (!status && comp->silent) {
            emsg("Bad headers in outgoing mail");
            save_unsent_composition(comp);
            return(FALSE);
      }

      /* Return success */

      return(TRUE);
}
/****************************************************************************/
int save_composition(comp, filnam, fmt)
COMPOSITION *comp;
char *filnam;
unsigned fmt;
{
      /*
       * Save a composition, with or without headers, and with the
       * body possibly decoded, to a file
       */

      int status;
      FILE *fp;

      /* Force the correct timestamps in the message if required */
          
      if (fmt & CS_MBOX) {
            update_composition_header_text(comp);
      }

      /* Open the file for appending */

      if ((fp = fopen(filnam, "a")) == NULL) {
            emsgl("Can't open ", filnam, ": ", strerror(errno), NULL);
            return(FALSE);
      }

      /* Write the composition to the file */

      status = write_composition(comp, fp, filnam, fmt);

      /* Close the file and return status */

      (void) fclose(fp);
      return(status);
}
/****************************************************************************/
int write_composition(comp, fp, filnam, fmt)
COMPOSITION *comp;
FILE *fp;
char *filnam;
unsigned fmt;
{
      /* Write the composition to a file as required */

      int wfmt, status;

      /* What format will be be writing the message in? */

      wfmt = (fmt & CS_MBOX)
            ? (filnam != NULL && mmdf_form(filnam))
            ? WF_MBOX | WF_MMDF : WF_MBOX
            : (fmt & CS_EDIT) ? WF_BODY | WF_DECODE | WF_NOBLANK
            : WF_BODY | WF_NOBLANK;

      /* Write the headers and then body of the composition */

      if ((status = write_headers(comp, fp, fmt))
          || (status = write_text(fp, comp->message, wfmt, NULL))) {
            /* Error writing the file */

            emsgl("Error writing ", (filnam != NULL)
                  ? filnam : "composition", ": ", strerror(status), NULL);
            return(FALSE);
      }

      /* Success */

      return(TRUE);
}
/****************************************************************************/
int edit_composition(comp, headers, body)
COMPOSITION *comp;
int headers, body;
{
      /*
       * Edit the text of a composition and update the values.
       * Returns TRUE unless a serious system problem prevented
       * the edit.
       */

      char *tfile;
      unsigned fmt;
      TEXTLINE *fromlines;

      /* If the composition is multipart than use compose mode */

      if (body && (comp->multipart || comp->message->multipart
                 || !comp->message->textual)) {
            return(compose_mail(comp));
      }

      /* Preserve the from lines if required */

      fromlines = (comp->editing) ? copy_from_lines(comp->message) : NULL;

      /* Get the name of a temporary file to use */

      if ((tfile = tempnam(TFILEDIR, TFILEPFX)) == NULL) {
            /* Can't get a temporary file, should "never happen" */

            emsgl("Can't create temporary file: ", strerror(errno), NULL);
            return(FALSE);
      }

      /* Do we want to add the signature now? */

      if (body && comp->sigfile != NULL && get_vval(V_EDIT_ISIG)) {
            sign_composition(comp);
      }

      /* Write the decoded composition to the temp file */

      fmt = (headers != V_TRUE) ? CS_BODY | CS_EDIT : CS_EDIT;
      if (!save_composition(comp, tfile, fmt)) {
            /* Couldn't write the temp file */

            return(FALSE);
      }

      /* Now edit the temporary file */
      
      if (edit_file(tfile) < 0) {
            (void) unlink(tfile);
            free(tfile);
            return(FALSE);
      }

      /* Read back the composition from the file */

      if (!read_composition(comp, tfile, headers)) {
            (void) unlink(tfile);
            free(tfile);
            return(TRUE);
      }

      /* Replace from lines if required */

      if (fromlines != NULL) {
            fromlines = replace_text(fromlines, NULL,
                               comp->message->text);
            comp->message->text = fromlines;
      }

      /* Do we want to add the signature now? */

      if (body && comp->sigfile != NULL) {
            sign_composition(comp);
      }

      /* Check for bogus text after a header-only edit */

      if (!body && comp->body != NULL) {
            /* Report the error */

            typeout("Extraneous text after message headers discarded\n");

            /* And delete the bogus text */

            replace_text(comp->message->text, comp->body, NULL);
      }

      /* End any typeout of error messsages */

      typeout(NULL);

      /* Clean up and return success */

      (void) unlink(tfile);
      free(tfile);
      return(TRUE);
}
/****************************************************************************/
int update_composition(comp, message, headers)
COMPOSITION *comp;
MESSAGE *message;
int headers;
{
      /*
       * Update the composition's header details so that they
       * reflect the details given in the updated message.
       */

      char *orig_dest_hdr = NULL, *orig_dest = NULL;
      int status, resent;
      HEADER *hdr;
      TEXTLINE *t;

      /* First, update the composition's message if required */

      if (message != NULL) {
            /* Update the composition from the message */

            free_messages(comp->message);
            comp->message = message;
            comp->encoded = (comp->message->encoding != NULL)
                  ? xstrdup(comp->message->encoding) : NULL;
      }

      /* Make sure the message is set */

      message = comp->message;

      /* Default the message body pointer */

      comp->body = comp->message->text;

      /* So far everything's OK */

      status = TRUE;

      /* Do we want to translate headers in the edit file? */

      if (headers != V_FALSE
          || !comp->updated && (comp->bounce || comp->editing)) {
            /* Check if the message is Resent- */

            resent = (get_header(comp, RESENT_FROM) != NULL ||
                    get_header(comp, RESENT_SENDER) != NULL);

            /* Get the original destination header */

            hdr = find_dest_header(comp, resent);

            /* Copy the original header and destination */

            orig_dest_hdr = (hdr != NULL) ? xstrdup(hdr->name) : NULL;
            orig_dest = (hdr != NULL && hdr->text != NULL)
                  ? xstrdup(hdr->text) : NULL;

            /* Clear the headers' found flags before we start */

            reset_headers(comp);

            /* Skip over from lines in the message text */

            t = message->text;
            while (t != NULL && is_fromline(t->line)) {
                  t = t->next;
            }

            /* Loop until all the headers have been processed */

            while (t != NULL && is_header(t->line)) {
                  /* Add the header with checking */

                  status = (add_user_header(comp, t->line, headers)
                          && status);

                  /* And move on to the next header */

                  t = t->next;
            }

            /* Clear any headers that the user deleted */

            if (headers == V_TRUE) {
                  delete_headers(comp);
            }

            /* Now check if we have destinations specified */

            if (orig_dest != NULL && !check_dest_headers(comp, resent)) {
                  /* Let the user know we have a problem? */

                  if (!comp->silent) {
                        typeout("No destinations specified: ");
                        typeout("restoring original ");
                        typeout(orig_dest_hdr);
                        typeout(" header\n");
                  }

                  /* Restore the old destination headers */

                  set_header(comp, orig_dest_hdr, orig_dest);
            }

            /* Free the original destination */

            if (orig_dest != NULL) {
                  free(orig_dest);
            }
            if (orig_dest_hdr != NULL) {
                  free(orig_dest_hdr);
            }

            /* Canonicalise and fold the the headers */

            autofold_headers(comp);
      }

      /* Update the composition's body pointer */

      update_composition_body(comp);

      /* Check the composition's MIME headers */

      check_mime_headers(comp, headers && !comp->silent);

      /* Now update the composition's header text and message flags */

      update_composition_header_text(comp);
      comp->message = update_message_from_text(comp->message);

      /* Update the composition's multipart flag */

      comp->multipart = comp->message->multipart;

      /* Now encode the composition's body text if required */

      encode_composition(comp);

      /* Note that we've updated the composition and return status */

      comp->updated = TRUE;
      return(status);
}
/****************************************************************************/
static COMPOSITION *make_composition(mail_flags, filnam)
int mail_flags;
char *filnam;
{
      /* Create a new composition and set its flags */

      COMPOSITION *comp;

      /* Allocate the composition */

      comp = (COMPOSITION *) xmalloc(sizeof(COMPOSITION));

      /* And initialise the contents */

      comp->message = composition_message();
      comp->headers = NULL;
      comp->body = NULL;
      comp->sigfile = NULL;
      comp->encoded = NULL;
      comp->updated = FALSE;

      /* Now set the flags for the message */

      comp->body_part = ((mail_flags & SM_BODY_PART) != 0);
      comp->multipart = ((mail_flags & SM_MPART) != 0);
      comp->mime = ((mail_flags & SM_MIME) != 0);
      comp->reply = ((mail_flags & SM_REPLY) != 0);
      comp->forward = ((mail_flags & SM_FORWARD) != 0);
      comp->bounce = ((mail_flags & SM_BOUNCE) != 0);
      comp->file = (filnam != NULL);
      comp->attachments = ((mail_flags & SM_ATTACH) != 0);
      comp->silent = ((mail_flags & SM_SILENT) != 0);
      comp->editing = ((mail_flags & SM_EDIT) != 0);
      comp->copy = FALSE;

      /* And return the composition */

      return(comp);
}
/****************************************************************************/
static int reset_stdin()
{
      /* Reset stdin to the terminal */

      char *term;

      /* Get the name of the terminal from stdout */

      term = ttyname(fileno(stdout));

      /* Reopen stdin to the terminal */

      if (freopen(term, "r", stdin) == NULL) {
            emsgl("Can't open ", term, ": ", strerror(errno), NULL);
            return(FALSE);
      }

      /* All went ok */

      return(TRUE);
}
/****************************************************************************/
static int write_headers(comp, fp, fmt)
COMPOSITION *comp;
FILE *fp;
int fmt;
{
      /* Write the headers of the composition to fp */

      char *text;
      HEADER *hdr;

      /* Do we need to write headers at all? */

      if ((fmt & CS_MBOX) || (fmt & CS_BODY)) {
            return(0);
      }

      /* Loop over the headers */

      for (hdr = comp->headers; hdr != NULL; hdr = hdr->next) {
            /* Do we need to write this header? */

            if (!(fmt & CS_EDIT) && (hdr->text != NULL)
                || (fmt & CS_EDIT) && hdr->edit && hdr->show) {
#ifdef NO_MTA_CC
                  /* Handle the Bcc header when sending */

                  if (!(fmt & CS_EDIT)
                      && (!strcasecmp(hdr->name, BCC)
                        || !strcasecmp(hdr->name, RESENT_BCC))) {
                        /* Might want an empty Bcc: header */

                        if (get_header(comp, TO) == NULL
                            && get_header(comp, RESENT_TO) == NULL
                            && get_header(comp, CC) == NULL
                            && get_header(comp, RESENT_CC) == NULL
                            && (fputs(hdr->name, fp) == EOF
                              || putc('\n', fp) == EOF)) {
                              /* Error writing the header */

                              return(errno);
                        }

                        /* Skip the rest of the header text */

                        continue;
                  }
#endif /* NO_MTA_CC */
                  /* Use the saved or current version of the header */

                  text = (!(fmt & CS_EDIT) || hdr->saved == NULL)
                        ? hdr->text : hdr->saved;

                  /* Decode the header text if required */

                  text = (!(fmt & CS_EDIT) || text == NULL) ? text :
                        decode_header(hdr->name, text, WR_FOLD);

                  /* Put the header name and text */

                  if (fputs(hdr->name, fp) == EOF
                      || putc(' ', fp) == EOF) {
                        return(errno);
                  }
                  if (text != NULL && fputs(text, fp) == EOF
                      || putc('\n', fp) == EOF) {
                        return(errno);
                  }
            }
      }

      /* Output a blank line following the headers */

      if (putc('\n', fp) == EOF) {
            return(errno);
      }

      /* And return success */

      return(0);
}
/****************************************************************************/
static void update_composition_body(comp)
COMPOSITION *comp;
{
      /* Update the body pointer in the composition */

      TEXTLINE *t; 

      /* Skip fromlines in the composition */

      t = comp->message->text;
      while (t != NULL && is_fromline(t->line)) {
            t = t->next;
      }

      /* Skip header lines in the composition */

      while (t != NULL && is_header(t->line)) {
            t = t->next;
      }

      /* Now skip blank lines in the composition */

      while (t != NULL && is_blank(t->line)) {
            t = t->next;
      }

      /* Update the composition's body pointer and return */

      comp->body = t;
      return;
}
/****************************************************************************/
static void update_composition_header_text(comp)
COMPOSITION *comp;
{
      /* Update the composition's header text */

      HEADER *hdr;

#ifndef NO_MTA_DATE
      int resent;
#endif /* ! NO_MTA_DATE */

      /* Delete the message's headers from the text */

      delete_header_text(comp->message, comp->editing);

      /* Add a blank line after the headers */

      add_blank_line_to_text(comp->message, comp->body);

#ifndef NO_MTA_DATE
      /* Check if the message is Resent- */

      resent = (get_header(comp, RESENT_FROM) != NULL
              || get_header(comp, RESENT_SENDER) != NULL);
      date_header = (resent) ? RESENT_DATE : DATE;
#endif /* ! NO_MTA_DATE */

      /* Now add a fromline to the message if required */

      if (!comp->body_part && !comp->editing) {
            add_from_line_to_text(comp->message);
      }

      /* Now add each header to the message text */

      for (hdr = comp->headers; hdr != NULL; hdr = hdr->next) {
            /* Do we need to send this header? */

            if (hdr->text != NULL) {
                  /* Use the saved or current version of the header */

                  add_header_line_to_text(comp->message,
                                    hdr->name, hdr->text);

#ifndef NO_MTA_DATE
            } else if (resent && !strcmp(hdr->name, RESENT_DATE)
                     || !resent && !strcmp(hdr->name, DATE)) {
                  /* We'll need a date header in the message text */

                  add_header_line_to_text(comp->message,
                                    (resent) ? RESENT_DATE : DATE,
                                    strdate(date_now(), TRUE));
#endif /* ! NO_MTA_DATE */

#ifdef MTA_CONTENT_LENGTH
            } else if (!strcmp(hdr->name, CONTENT_LENGTH)) {
                  /* Write an accurate Content-Length header */

                  add_header_line_to_text(comp->message, CONTENT_LENGTH,
                                    utos(text_chars(comp->body)));
#endif /* MTA_CONTENT_LENGTH */
            }
      }

      return;
}
/****************************************************************************/
static void delete_header_text(message, keep_fromlines)
MESSAGE *message;
int keep_fromlines;
{
      /*
       * Delete any lines containing fromlines or headers from the
       * message's text.  Used when composing to make the message
       * text match the canonicalised and checked headers.
       */

      TEXTLINE *t, *next;

      /* Delete the fromlines from the message if required */

      t = message->text;
      while (t != NULL && is_fromline(t->line)) {
            /* Delete the line from the text if required */

            if (!keep_fromlines) {
                  message->text = delete_text(message->text, t);
                  t = message->text;
            } else {
                  t = t->next;
            }
      }

      /* Delete the header lines from the message */

      while (t != NULL && is_header(t->line)) {
            /* Delete the line from the text */

            next = t->next;
            message->text = delete_text(message->text, t);
            t = next;
      }

      /* Delete the blank lines from the message */

      while (t != NULL && is_blank(t->line)) {
            /* Delete the line from the text */

            next = t->next;
            message->text = delete_text(message->text, t);
            t = next;
      }

      return;
}
/****************************************************************************/
static void add_from_line_to_text(message)
MESSAGE *message;
{
      /* Insert a valid from line into the message */

      char *line;
      TEXTLINE *t;

      /* Build the from line */

      line = vstrcat(MFROM, get_addr(), " ",
                   strudate(date_now()), "\n", NULL);

      /* Skip any existing from lines */

      t = message->text;
      while (t != NULL && is_fromline(t->line)) {
            t = t->next;
      }

      /* And insert the from line into the text */

      message->text = insert_text(message->text, t, line);
      return;
}
/****************************************************************************/
static void add_header_line_to_text(message, name, text)
MESSAGE *message;
{
      /* Insert a header line into the message */

      char *line, *eline;
      TEXTLINE *t;

      /* Build the header line */

      line = vstrcat(name, text, "\n", NULL);
      eline = xstrdup(encode_header_line(line, WR_FOLD));
      free(line);

      /* Skip any existing from lines */

      t = message->text;
      while (t != NULL && is_fromline(t->line)) {
            t = t->next;
      }

      /* Skip any existing header lines */

      while (t != NULL && is_header(t->line)) {
            t = t->next;
      }

      /* And insert the header line into the text */

      message->text = insert_text(message->text, t, eline);
      return;
}
/****************************************************************************/
static void add_blank_line_to_text(message, body)
MESSAGE *message;
TEXTLINE *body;
{
      /* Insert a blank line into the message before the body */

      message->text = insert_text(message->text, body, xstrdup("\n"));
      return;
}
/****************************************************************************/
static TEXTLINE *copy_from_lines(message)
MESSAGE *message;
{
      /* Return a copy of the message's from lines */

      TEXTLINE *t, *fromlines = NULL;

      /* Loop over the message's from lines */

      for (t = message->text; t != NULL && is_fromline(t->line);
           t = t->next) {
            /* Add this fromline to the list */

            fromlines = append_text(fromlines, xstrdup(t->line));
      }

      /* Return the from lines */

      return(fromlines);
}
/****************************************************************************/
static void encode_composition(comp)
COMPOSITION *comp;
{
      /* Encode the body of a composition according to the headers */

      TEXTLINE *decoded_text, *encoded_text;

      /* Check the composition isn't already correctly encoded */

      if (comp->encoded != NULL
          && !strcmp(comp->encoded, comp->message->encoding)) {
            /* Nothing to do here */

            return;
      }

      /* Decode the message body if required */

      decoded_text = decode_text_list(comp->body, comp->encoded,
                              comp->message->textual);

      /* Encode the text of the composition's body */

      encoded_text = encode_text_list(decoded_text, comp->message->encoding,
                              comp->message->textual);
      free_text(decoded_text);

      /* And replace it in the list */

      comp->message->text = replace_text(comp->message->text,
                                 comp->body, encoded_text);
      comp->body = encoded_text;

#ifdef MTA_CONTENT_LENGTH
      /* Update the message's Content-Length */

      comp->message->length = text_chars(comp->body);
      update_composition_header_text(comp);
#endif /* MTA_CONTENT_LENGTH */


      /* Update how the composition has been encoded and return */

      if (comp->encoded != NULL) {
            free(comp->encoded);
      }
      comp->encoded = (comp->message->encoding != NULL)
            ? xstrdup(comp->message->encoding) : NULL;
      return;
}
/****************************************************************************/
static void save_unsent_composition(comp)
COMPOSITION *comp;
{
      /* Append the composition to DEADFILE after an error */

      char *dfile;

      /* Form the dead file name */

      dfile = vstrcat(get_home(NULL), "/", DEADFILE, NULL);

      /* Now write the message to the file */

      if (save_composition(comp, dfile, CS_MBOX)) {
            /* Report the success */

            cmsg(" (Mail stored in ");
            cmsg(DEADFILE);
            cmsg(")");
      }

      /* Clean up and return */

      free(dfile);
      return;
}
/****************************************************************************/

Generated by  Doxygen 1.6.0   Back to index