send.c 37.1 KB
Newer Older
Thomas Roessler's avatar
Thomas Roessler committed
1
/*
2
 * Copyright (C) 1996-2000 Michael R. Elkins <me@cs.hmc.edu>
Thomas Roessler's avatar
Thomas Roessler committed
3 4 5 6 7 8 9 10 11 12 13 14 15
 * 
 *     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 of the License, 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
16
 *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
Thomas Roessler's avatar
Thomas Roessler committed
17 18 19 20
 */ 

#include "mutt.h"
#include "mutt_curses.h"
21
#include "rfc2047.h"
Thomas Roessler's avatar
Thomas Roessler committed
22 23 24 25 26 27 28 29 30 31 32 33 34 35
#include "keymap.h"
#include "mime.h"
#include "mailbox.h"
#include "copy.h"
#include "mx.h"

#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <dirent.h>
36 37 38
#include <time.h>
#include <sys/types.h>
#include <utime.h>
Thomas Roessler's avatar
Thomas Roessler committed
39

40
#ifdef HAVE_PGP
Thomas Roessler's avatar
Thomas Roessler committed
41 42 43
#include "pgp.h"
#endif

44 45 46
#ifdef MIXMASTER
#include "remailer.h"
#endif
Thomas Roessler's avatar
Thomas Roessler committed
47 48


Thomas Roessler's avatar
Thomas Roessler committed
49
static void append_signature (FILE *f)
Thomas Roessler's avatar
Thomas Roessler committed
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
{
  FILE *tmpfp;
  pid_t thepid;

  if (Signature && (tmpfp = mutt_open_read (Signature, &thepid)))
  {
    if (option (OPTSIGDASHES))
      fputs ("\n-- \n", f);
    mutt_copy_stream (tmpfp, f);
    fclose (tmpfp);
    if (thepid != -1)
      mutt_wait_filter (thepid);
  }
}

/* compare two e-mail addresses and return 1 if they are equivalent */
static int mutt_addrcmp (ADDRESS *a, ADDRESS *b)
{
  if (!a->mailbox || !b->mailbox)
    return 0;
70
  if (mutt_strcasecmp (a->mailbox, b->mailbox))
Thomas Roessler's avatar
Thomas Roessler committed
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
    return 0;
  return 1;
}

/* search an e-mail address in a list */
static int mutt_addrsrc (ADDRESS *a, ADDRESS *lst)
{
  for (; lst; lst = lst->next)
  {
    if (mutt_addrcmp (a, lst))
      return (1);
  }
  return (0);
}

/* removes addresses from "b" which are contained in "a" */
static ADDRESS *mutt_remove_xrefs (ADDRESS *a, ADDRESS *b)
{
  ADDRESS *top, *p, *prev = NULL;

  top = b;
  while (b)
  {
    for (p = a; p; p = p->next)
    {
      if (mutt_addrcmp (p, b))
	break;
    }
    if (p)
    {
      if (prev)
      {
	prev->next = b->next;
	b->next = NULL;
	rfc822_free_address (&b);
	b = prev;
      }
      else
      {
	top = top->next;
	b->next = NULL;
	rfc822_free_address (&b);
	b = top;
      }
    }
    else
    {
      prev = b;
      b = b->next;
    }
  }
  return top;
}

/* remove any address which matches the current user.  if `leave_only' is
 * nonzero, don't remove the user's address if it is the only one in the list
 */
static ADDRESS *remove_user (ADDRESS *a, int leave_only)
{
  ADDRESS *top = NULL, *last = NULL;

  while (a)
  {
    if (!mutt_addr_is_user (a))
    {
      if (top)
      {
        last->next = a;
        last = last->next;
      }
      else
        last = top = a;
      a = a->next;
      last->next = NULL;
    }
    else
    {
      ADDRESS *tmp = a;
      
      a = a->next;
      if (!leave_only || a || last)
      {
	tmp->next = NULL;
	rfc822_free_address (&tmp);
      }
      else
	last = top = tmp;
    }
  }
  return top;
}

static ADDRESS *find_mailing_lists (ADDRESS *t, ADDRESS *c)
{
  ADDRESS *top = NULL, *ptr = NULL;

  for (; t || c; t = c, c = NULL)
  {
    for (; t; t = t->next)
    {
      if (mutt_is_mail_list (t))
      {
	if (top)
	{
	  ptr->next = rfc822_cpy_adr_real (t);
	  ptr = ptr->next;
	}
	else
	  ptr = top = rfc822_cpy_adr_real (t);
      }
    }
  }
  return top;
}

static int edit_address (ADDRESS **a, /* const */ char *field)
{
  char buf[HUGE_STRING];

  buf[0] = 0;
  rfc822_write_address (buf, sizeof (buf), *a);
  if (mutt_get_field (field, buf, sizeof (buf), M_ALIAS) != 0)
    return (-1);
  rfc822_free_address (a);
  *a = mutt_expand_aliases (mutt_parse_adrlist (NULL, buf));
  return 0;
}

static int edit_envelope (ENVELOPE *en)
{
  char buf[HUGE_STRING];
  LIST *uh = UserHeader;

  if (edit_address (&en->to, "To: ") == -1 || en->to == NULL)
    return (-1);
  if (option (OPTASKCC) && edit_address (&en->cc, "Cc: ") == -1)
    return (-1);
  if (option (OPTASKBCC) && edit_address (&en->bcc, "Bcc: ") == -1)
    return (-1);

  if (en->subject)
  {
    if (option (OPTFASTREPLY))
      return (0);
    else
      strfcpy (buf, en->subject, sizeof (buf));
  }
  else
  {
    char *p;

    buf[0] = 0;
    for (; uh; uh = uh->next)
    {
225
      if (mutt_strncasecmp ("subject:", uh->data, 8) == 0)
Thomas Roessler's avatar
Thomas Roessler committed
226 227 228 229 230 231 232 233 234
      {
	p = uh->data + 8;
	SKIPWS (p);
	strncpy (buf, p, sizeof (buf));
      }
    }
  }
  
  if (mutt_get_field ("Subject: ", buf, sizeof (buf), 0) != 0 ||
235
      (!buf[0] && query_quadoption (OPT_SUBJECT, _("No subject, abort?")) != 0))
Thomas Roessler's avatar
Thomas Roessler committed
236
  {
237
    mutt_message _("No subject, aborting.");
Thomas Roessler's avatar
Thomas Roessler committed
238 239
    return (-1);
  }
240
  mutt_str_replace (&en->subject, buf);
Thomas Roessler's avatar
Thomas Roessler committed
241 242 243 244 245 246 247 248 249 250

  return 0;
}

static void process_user_recips (ENVELOPE *env)
{
  LIST *uh = UserHeader;

  for (; uh; uh = uh->next)
  {
251
    if (mutt_strncasecmp ("to:", uh->data, 3) == 0)
Thomas Roessler's avatar
Thomas Roessler committed
252
      env->to = rfc822_parse_adrlist (env->to, uh->data + 3);
253
    else if (mutt_strncasecmp ("cc:", uh->data, 3) == 0)
Thomas Roessler's avatar
Thomas Roessler committed
254
      env->cc = rfc822_parse_adrlist (env->cc, uh->data + 3);
255
    else if (mutt_strncasecmp ("bcc:", uh->data, 4) == 0)
Thomas Roessler's avatar
Thomas Roessler committed
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
      env->bcc = rfc822_parse_adrlist (env->bcc, uh->data + 4);
  }
}

static void process_user_header (ENVELOPE *env)
{
  LIST *uh = UserHeader;
  LIST *last = env->userhdrs;

  if (last)
    while (last->next)
      last = last->next;

  for (; uh; uh = uh->next)
  {
271 272 273 274 275 276 277
    if (mutt_strncasecmp ("from:", uh->data, 5) == 0)
    {
      /* User has specified a default From: address.  Remove default address */
      rfc822_free_address (&env->from);
      env->from = rfc822_parse_adrlist (env->from, uh->data + 5);
    }
    else if (mutt_strncasecmp ("reply-to:", uh->data, 9) == 0)
Thomas Roessler's avatar
Thomas Roessler committed
278 279 280 281
    {
      rfc822_free_address (&env->reply_to);
      env->reply_to = rfc822_parse_adrlist (env->reply_to, uh->data + 9);
    }
282 283 284
    else if (mutt_strncasecmp ("to:", uh->data, 3) != 0 &&
	     mutt_strncasecmp ("cc:", uh->data, 3) != 0 &&
	     mutt_strncasecmp ("bcc:", uh->data, 4) != 0 &&
285
	     mutt_strncasecmp ("subject:", uh->data, 8) != 0)
Thomas Roessler's avatar
Thomas Roessler committed
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
    {
      if (last)
      {
	last->next = mutt_new_list ();
	last = last->next;
      }
      else
	last = env->userhdrs = mutt_new_list ();
      last->data = safe_strdup (uh->data);
    }
  }
}

LIST *mutt_copy_list (LIST *p)
{
  LIST *t, *r=NULL, *l=NULL;

  for (; p; p = p->next)
  {
    t = (LIST *) safe_malloc (sizeof (LIST));
    t->data = safe_strdup (p->data);
    t->next = NULL;
    if (l)
    {
      r->next = t;
      r = r->next;
    }
    else
      l = r = t;
  }
  return (l);
}

319
void mutt_forward_intro (FILE *fp, HEADER *cur)
Thomas Roessler's avatar
Thomas Roessler committed
320 321
{
  char buffer[STRING];
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
  
  fputs ("----- Forwarded message from ", fp);
  buffer[0] = 0;
  rfc822_write_address (buffer, sizeof (buffer), cur->env->from);
  fputs (buffer, fp);
  fputs (" -----\n\n", fp);
}

void mutt_forward_trailer (FILE *fp)
{
  fputs ("\n----- End forwarded message -----\n", fp);
}


static int include_forward (CONTEXT *ctx, HEADER *cur, FILE *out)
{
Thomas Roessler's avatar
Thomas Roessler committed
338
  int chflags = CH_DECODE, cmflags = 0;
339
  
340 341
  mutt_parse_mime_message (ctx, cur);
  mutt_message_hook (ctx, cur, M_MESSAGEHOOK);
Thomas Roessler's avatar
Thomas Roessler committed
342

343
#ifdef HAVE_PGP
Thomas Roessler's avatar
Thomas Roessler committed
344
  if ((cur->pgp & PGPENCRYPT) && option (OPTFORWDECODE))
Thomas Roessler's avatar
Thomas Roessler committed
345
  {
Thomas Roessler's avatar
Thomas Roessler committed
346 347
    /* make sure we have the user's passphrase before proceeding... */
    pgp_valid_passphrase ();
Thomas Roessler's avatar
Thomas Roessler committed
348
  }
349
#endif /* HAVE_PGP */
Thomas Roessler's avatar
Thomas Roessler committed
350

351
  mutt_forward_intro (out, cur);
Thomas Roessler's avatar
Thomas Roessler committed
352 353 354

  if (option (OPTFORWDECODE))
  {
355
    cmflags |= M_CM_DECODE | M_CM_CHARCONV;
356
    if (option (OPTWEED))
357
    {
358
      chflags |= CH_WEED | CH_REORDER;
359 360
      cmflags |= M_CM_WEED;
    }
Thomas Roessler's avatar
Thomas Roessler committed
361 362 363
  }
  if (option (OPTFORWQUOTE))
    cmflags |= M_CM_PREFIX;
364

Thomas Roessler's avatar
Thomas Roessler committed
365
  mutt_copy_message (out, ctx, cur, cmflags, chflags);
366
  mutt_forward_trailer (out);
Thomas Roessler's avatar
Thomas Roessler committed
367 368 369
  return 0;
}

370 371 372 373 374 375 376 377 378 379 380 381
void mutt_make_attribution (CONTEXT *ctx, HEADER *cur, FILE *out)
{
  char buffer[STRING];
  if (Attribution)
  {
    mutt_make_string (buffer, sizeof (buffer), Attribution, ctx, cur);
    fputs (buffer, out);
    fputc ('\n', out);
  }
}

void mutt_make_post_indent (CONTEXT *ctx, HEADER *cur, FILE *out)
Thomas Roessler's avatar
Thomas Roessler committed
382 383
{
  char buffer[STRING];
384 385 386 387 388 389 390 391 392 393
  if (PostIndentString)
  {
    mutt_make_string (buffer, sizeof (buffer), PostIndentString, ctx, cur);
    fputs (buffer, out);
    fputc ('\n', out);
  }
}

static int include_reply (CONTEXT *ctx, HEADER *cur, FILE *out)
{
394 395
  int cmflags = M_CM_PREFIX | M_CM_DECODE | M_CM_CHARCONV;
  int chflags = CH_DECODE;
Thomas Roessler's avatar
Thomas Roessler committed
396

397
#ifdef HAVE_PGP
Thomas Roessler's avatar
Thomas Roessler committed
398 399 400 401 402 403 404 405
  if (cur->pgp)
  {
    if (cur->pgp & PGPENCRYPT)
    {
      /* make sure we have the user's passphrase before proceeding... */
      pgp_valid_passphrase ();
    }
  }
406
#endif /* HAVE_PGP */
Thomas Roessler's avatar
Thomas Roessler committed
407

408 409
  mutt_parse_mime_message (ctx, cur);
  mutt_message_hook (ctx, cur, M_MESSAGEHOOK);
410
  
411 412
  mutt_make_attribution (ctx, cur, out);
  
Thomas Roessler's avatar
Thomas Roessler committed
413
  if (!option (OPTHEADER))
414 415 416 417 418 419 420 421
    cmflags |= M_CM_NOHEADER;
  if (option (OPTWEED))
  {
    chflags |= CH_WEED;
    cmflags |= M_CM_WEED;
  }

  mutt_copy_message (out, ctx, cur, cmflags, chflags);
422

423 424
  mutt_make_post_indent (ctx, cur, out);
  
Thomas Roessler's avatar
Thomas Roessler committed
425 426 427
  return 0;
}

428
static int default_to (ADDRESS **to, ENVELOPE *env, int flags)
Thomas Roessler's avatar
Thomas Roessler committed
429 430 431
{
  char prompt[STRING];

432
  if (flags && env->mail_followup_to)
Thomas Roessler's avatar
Thomas Roessler committed
433
  {
434 435
    snprintf (prompt, sizeof (prompt), _("Follow-up to %s%s?"),
	      env->mail_followup_to->mailbox,
436
	      env->mail_followup_to->next ? ",..." : "");
437

438
    switch (query_quadoption (OPT_MFUPTO, prompt))
439
    {
440
    case M_YES:
441 442
      rfc822_append (to, env->mail_followup_to);
      return 0;
443 444 445

    case -1:
      return -1; /* abort */
446
    }
Thomas Roessler's avatar
Thomas Roessler committed
447 448
  }

449 450 451 452 453 454
  /* Exit now if we're setting up the default Cc list for list-reply
   * (only set if Mail-Followup-To is present and honoured).
   */
  if (flags & SENDLISTREPLY)
    return 0;

455
  if (!option(OPTREPLYSELF) && mutt_addr_is_user (env->from))
Thomas Roessler's avatar
Thomas Roessler committed
456 457 458 459 460 461
  {
    /* mail is from the user, assume replying to recipients */
    rfc822_append (to, env->to);
  }
  else if (env->reply_to)
  {
462
    if ((mutt_addrcmp (env->from, env->reply_to) && !env->reply_to->next) || 
463
	(option (OPTIGNORELISTREPLYTO) &&
Thomas Roessler's avatar
Thomas Roessler committed
464 465
	mutt_is_mail_list (env->reply_to) &&
	(mutt_addrsrc (env->reply_to, env->to) ||
466
	mutt_addrsrc (env->reply_to, env->cc))))
Thomas Roessler's avatar
Thomas Roessler committed
467 468 469
    {
      /* If the Reply-To: address is a mailing list, assume that it was
       * put there by the mailing list, and use the From: address
470 471 472 473 474
       * 
       * We also take the from header if our correspondant has a reply-to
       * header which is identical to the electronic mail address given
       * in his From header.
       * 
Thomas Roessler's avatar
Thomas Roessler committed
475 476 477
       */
      rfc822_append (to, env->from);
    }
478 479
    else if (!(mutt_addrcmp (env->from, env->reply_to) && 
	       !env->reply_to->next) &&
Thomas Roessler's avatar
Thomas Roessler committed
480 481 482 483 484 485 486
	     quadoption (OPT_REPLYTO) != M_YES)
    {
      /* There are quite a few mailing lists which set the Reply-To:
       * header field to the list address, which makes it quite impossible
       * to send a message to only the sender of the message.  This
       * provides a way to do that.
       */
487 488 489
      snprintf (prompt, sizeof (prompt), _("Reply to %s%s?"),
		env->reply_to->mailbox, 
		env->reply_to->next?",...":"");
490 491 492
      switch (query_quadoption (OPT_REPLYTO, prompt))
      {
      case M_YES:
Thomas Roessler's avatar
Thomas Roessler committed
493
	rfc822_append (to, env->reply_to);
494 495 496
	break;

      case M_NO:
Thomas Roessler's avatar
Thomas Roessler committed
497
	rfc822_append (to, env->from);
498 499 500
	break;

      default:
Thomas Roessler's avatar
Thomas Roessler committed
501
	return (-1); /* abort */
502
      }
Thomas Roessler's avatar
Thomas Roessler committed
503 504 505 506 507 508 509 510 511 512
    }
    else
      rfc822_append (to, env->reply_to);
  }
  else
    rfc822_append (to, env->from);

  return (0);
}

513
int mutt_fetch_recips (ENVELOPE *out, ENVELOPE *in, int flags)
Thomas Roessler's avatar
Thomas Roessler committed
514 515 516 517 518 519 520
{
  ADDRESS *tmp;
  if (flags & SENDLISTREPLY)
  {
    tmp = find_mailing_lists (in->to, in->cc);
    rfc822_append (&out->to, tmp);
    rfc822_free_address (&tmp);
521 522 523 524

    if (in->mail_followup_to &&
        default_to (&out->cc, in, flags & SENDLISTREPLY) == -1)
      return (-1); /* abort */
Thomas Roessler's avatar
Thomas Roessler committed
525 526 527 528 529 530 531 532
  }
  else
  {
    if (default_to (&out->to, in, flags & SENDGROUPREPLY) == -1)
      return (-1); /* abort */

    if ((flags & SENDGROUPREPLY) && !in->mail_followup_to)
    {
533 534
      /* if(!mutt_addr_is_user(in->to)) */
      rfc822_append (&out->cc, in->to);
Thomas Roessler's avatar
Thomas Roessler committed
535 536 537 538 539 540
      rfc822_append (&out->cc, in->cc);
    }
  }
  return 0;
}

541
LIST *mutt_make_references(ENVELOPE *e)
Thomas Roessler's avatar
Thomas Roessler committed
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
{
  LIST *t, *l;
  
  l = mutt_copy_list(e->references);
  
  if(e->message_id)
  {
    t = mutt_new_list();
    t->data = safe_strdup(e->message_id);
    t->next = l;
    l = t;
  }
  
  return l;
}

558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616
void mutt_fix_reply_recipients (ENVELOPE *env)
{
  if (! option (OPTMETOO))
  {
    /* the order is important here.  do the CC: first so that if the
     * the user is the only recipient, it ends up on the TO: field
     */
    env->cc = remove_user (env->cc, (env->to == NULL));
    env->to = remove_user (env->to, (env->cc == NULL));
  }
  
  /* the CC field can get cluttered, especially with lists */
  env->to = mutt_remove_duplicates (env->to);
  env->cc = mutt_remove_duplicates (env->cc);
  env->cc = mutt_remove_xrefs (env->to, env->cc);
}

void mutt_make_forward_subject (ENVELOPE *env, CONTEXT *ctx, HEADER *cur)
{
  char buffer[STRING];

  /* set the default subject for the message. */
  mutt_make_string (buffer, sizeof (buffer), NONULL(ForwFmt), ctx, cur);
  env->subject = safe_strdup (buffer);
}

void mutt_make_misc_reply_headers (ENVELOPE *env, CONTEXT *ctx,
				    HEADER *cur, ENVELOPE *curenv)
{
  LIST *tmp;
  char buffer[STRING];

  if (curenv->real_subj)
  {
    env->subject = safe_malloc (mutt_strlen (curenv->real_subj) + 5);
    sprintf (env->subject, "Re: %s", curenv->real_subj);
  }
  else
    env->subject = safe_strdup ("Re: your mail");
  
  /* add the In-Reply-To field */
  if (InReplyTo)
  {
    strfcpy (buffer, "In-Reply-To: ", sizeof (buffer));
    mutt_make_string (buffer + 13, sizeof (buffer) - 13, InReplyTo, ctx, cur);
    tmp = env->userhdrs;
    while (tmp && tmp->next)
      tmp = tmp->next;
    if (tmp)
    {
      tmp->next = mutt_new_list ();
      tmp = tmp->next;
    }
    else
      tmp = env->userhdrs = mutt_new_list ();
    tmp->data = safe_strdup (buffer);
  }
}

Thomas Roessler's avatar
Thomas Roessler committed
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
static int
envelope_defaults (ENVELOPE *env, CONTEXT *ctx, HEADER *cur, int flags)
{
  ENVELOPE *curenv = NULL;
  int i = 0, tag = 0;

  if (!cur)
  {
    tag = 1;
    for (i = 0; i < ctx->vcount; i++)
      if (ctx->hdrs[ctx->v2r[i]]->tagged)
      {
	cur = ctx->hdrs[ctx->v2r[i]];
	curenv = cur->env;
	break;
      }

    if (!cur)
    {
      /* This could happen if the user tagged some messages and then did
       * a limit such that none of the tagged message are visible.
       */
639
      mutt_error _("No tagged messages are visible!");
Thomas Roessler's avatar
Thomas Roessler committed
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
      return (-1);
    }
  }
  else
    curenv = cur->env;

  if (flags & SENDREPLY)
  {
    if (tag)
    {
      HEADER *h;

      for (i = 0; i < ctx->vcount; i++)
      {
	h = ctx->hdrs[ctx->v2r[i]];
655
	if (h->tagged && mutt_fetch_recips (env, h->env, flags) == -1)
Thomas Roessler's avatar
Thomas Roessler committed
656 657 658
	  return -1;
      }
    }
659
    else if (mutt_fetch_recips (env, curenv, flags) == -1)
Thomas Roessler's avatar
Thomas Roessler committed
660 661 662 663
      return -1;

    if ((flags & SENDLISTREPLY) && !env->to)
    {
664
      mutt_error _("No mailing lists found!");
Thomas Roessler's avatar
Thomas Roessler committed
665 666 667
      return (-1);
    }

668 669 670
    mutt_fix_reply_recipients (env);
    mutt_make_misc_reply_headers (env, ctx, cur, curenv);
    
Thomas Roessler's avatar
Thomas Roessler committed
671
    if(tag)
Thomas Roessler's avatar
Thomas Roessler committed
672
    {
Thomas Roessler's avatar
Thomas Roessler committed
673 674
      HEADER *h;
      LIST **p;
Thomas Roessler's avatar
Thomas Roessler committed
675

Thomas Roessler's avatar
Thomas Roessler committed
676 677
      env->references = NULL;
      p = &env->references;
678

Thomas Roessler's avatar
Thomas Roessler committed
679 680 681 682 683
      for(i = 0; i < ctx->vcount; i++)
      {
	while(*p) p = &(*p)->next;
	h = ctx->hdrs[ctx->v2r[i]];
	if(h->tagged)
684
	  *p = mutt_make_references(h->env);
Thomas Roessler's avatar
Thomas Roessler committed
685
      }
Thomas Roessler's avatar
Thomas Roessler committed
686
    }
Thomas Roessler's avatar
Thomas Roessler committed
687
    else
688
      env->references = mutt_make_references(curenv);
Thomas Roessler's avatar
Thomas Roessler committed
689

Thomas Roessler's avatar
Thomas Roessler committed
690 691
  }
  else if (flags & SENDFORWARD)
692
    mutt_make_forward_subject (env, ctx, cur);
Thomas Roessler's avatar
Thomas Roessler committed
693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709

  return (0);
}

static int
generate_body (FILE *tempfp,	/* stream for outgoing message */
	       HEADER *msg,	/* header for outgoing message */
	       int flags,	/* compose mode */
	       CONTEXT *ctx,	/* current mailbox */
	       HEADER *cur)	/* current message */
{
  int i;
  HEADER *h;
  BODY *tmp;

  if (flags & SENDREPLY)
  {
710
    if ((i = query_quadoption (OPT_INCLUDE, _("Include message in reply?"))) == -1)
Thomas Roessler's avatar
Thomas Roessler committed
711 712 713 714
      return (-1);

    if (i == M_YES)
    {
715
      mutt_message _("Including quoted message...");
Thomas Roessler's avatar
Thomas Roessler committed
716 717 718 719 720 721 722 723 724
      if (!cur)
      {
	for (i = 0; i < ctx->vcount; i++)
	{
	  h = ctx->hdrs[ctx->v2r[i]];
	  if (h->tagged)
	  {
	    if (include_reply (ctx, h, tempfp) == -1)
	    {
725
	      mutt_error _("Could not include all requested messages!");
Thomas Roessler's avatar
Thomas Roessler committed
726 727 728 729 730 731 732 733
	      return (-1);
	    }
	    fputc ('\n', tempfp);
	  }
	}
      }
      else
	include_reply (ctx, cur, tempfp);
734

Thomas Roessler's avatar
Thomas Roessler committed
735 736 737 738
    }
  }
  else if (flags & SENDFORWARD)
  {
739
    if ((i = query_quadoption (OPT_MIMEFWD, _("Forward MIME encapsulated?"))) == M_YES)
Thomas Roessler's avatar
Thomas Roessler committed
740 741 742
    {
      BODY *last = msg->content;

743 744
      mutt_message _("Preparing forwarded message...");
      
Thomas Roessler's avatar
Thomas Roessler committed
745 746 747 748 749
      while (last && last->next)
	last = last->next;

      if (cur)
      {
Thomas Roessler's avatar
Thomas Roessler committed
750
	tmp = mutt_make_message_attach (ctx, cur, 0);
Thomas Roessler's avatar
Thomas Roessler committed
751 752 753 754 755 756 757 758 759 760 761
	if (last)
	  last->next = tmp;
	else
	  msg->content = tmp;
      }
      else
      {
	for (i = 0; i < ctx->vcount; i++)
	{
	  if (ctx->hdrs[ctx->v2r[i]]->tagged)
	  {
Thomas Roessler's avatar
Thomas Roessler committed
762
	    tmp = mutt_make_message_attach (ctx, ctx->hdrs[ctx->v2r[i]], 0);
Thomas Roessler's avatar
Thomas Roessler committed
763 764 765 766 767 768 769 770 771 772 773
	    if (last)
	    {
	      last->next = tmp;
	      last = tmp;
	    }
	    else
	      last = msg->content = tmp;
	  }
	}
      }
    }
774
    else if (i != -1)
Thomas Roessler's avatar
Thomas Roessler committed
775 776 777 778 779 780 781 782
    {
      if (cur)
	include_forward (ctx, cur, tempfp);
      else
	for (i=0; i < ctx->vcount; i++)
	  if (ctx->hdrs[ctx->v2r[i]]->tagged)
	    include_forward (ctx, ctx->hdrs[ctx->v2r[i]], tempfp);
    }
783 784
    else if (i == -1)
      return -1;
Thomas Roessler's avatar
Thomas Roessler committed
785 786 787 788
  }



789
#ifdef HAVE_PGP
Thomas Roessler's avatar
Thomas Roessler committed
790 791 792 793 794 795 796 797 798 799 800
  else if (flags & SENDKEY) 
  {
    BODY *tmp;
    if ((tmp = pgp_make_key_attachment (NULL)) == NULL)
      return -1;

    tmp->next = msg->content;
    msg->content = tmp;
  }
#endif

801
  mutt_clear_error ();
Thomas Roessler's avatar
Thomas Roessler committed
802 803 804 805

  return (0);
}

806
void mutt_set_followup_to (ENVELOPE *e)
Thomas Roessler's avatar
Thomas Roessler committed
807 808
{
  ADDRESS *t = NULL;
809
  ADDRESS *from;
Thomas Roessler's avatar
Thomas Roessler committed
810

811 812
  /* 
   * Only generate the Mail-Followup-To if the user has requested it, and
813 814
   * it hasn't already been set
   */
815

Thomas Roessler's avatar
Thomas Roessler committed
816 817
  if (option (OPTFOLLOWUPTO) && !e->mail_followup_to)
  {
818
    if (mutt_is_list_cc (0, e->to, e->cc))
Thomas Roessler's avatar
Thomas Roessler committed
819
    {
820 821 822
      /* 
       * this message goes to known mailing lists, so create a proper
       * mail-followup-to header
Thomas Roessler's avatar
Thomas Roessler committed
823
       */
824

Thomas Roessler's avatar
Thomas Roessler committed
825 826 827
      t = rfc822_append (&e->mail_followup_to, e->to);
      rfc822_append (&t, e->cc);
    }
828 829 830 831 832 833 834 835 836 837 838

    /* remove ourselves from the mail-followup-to header */
    e->mail_followup_to = remove_user (e->mail_followup_to, 0);

    /*
     * If we are not subscribed to any of the lists in question,
     * re-add ourselves to the mail-followup-to header.  The 
     * mail-followup-to header generated is a no-op with group-reply,
     * but makes sure list-reply has the desired effect.
     */

839
    if (e->mail_followup_to && !mutt_is_list_recipient (0, e->to, e->cc))
840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858
    {
      if (e->from)
	from = rfc822_cpy_adr (e->from);
      else
	from = mutt_default_from ();
      
      if (from)
      {
	/* Normally, this loop will not even be entered. */
	for (t = from; t && t->next; t = t->next)
	  ;
	
	t->next = e->mail_followup_to; 	/* t cannot be NULL at this point. */
	e->mail_followup_to = from;
      }
    }
    
    e->mail_followup_to = mutt_remove_duplicates (e->mail_followup_to);
    
Thomas Roessler's avatar
Thomas Roessler committed
859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887
  }
}


/* look through the recipients of the message we are replying to, and if
   we find an address that matches $alternates, we use that as the default
   from field */
static ADDRESS *set_reverse_name (ENVELOPE *env)
{
  ADDRESS *tmp;

  for (tmp = env->to; tmp; tmp = tmp->next)
  {
    if (mutt_addr_is_user (tmp))
      break;
  }
  if (!tmp)
  {
    for (tmp = env->cc; tmp; tmp = tmp->next)
    {
      if (mutt_addr_is_user (tmp))
	break;
    }
  }
  if (!tmp && mutt_addr_is_user (env->from))
    tmp = env->from;
  if (tmp)
  {
    tmp = rfc822_cpy_adr_real (tmp);
888
    if (!option (OPTREVREAL))
889
      FREE (&tmp->personal);
Thomas Roessler's avatar
Thomas Roessler committed
890 891 892 893 894 895
    if (!tmp->personal)
      tmp->personal = safe_strdup (Realname);
  }
  return (tmp);
}

896
ADDRESS *mutt_default_from (void)
Thomas Roessler's avatar
Thomas Roessler committed
897
{
898
  ADDRESS *adr;
Thomas Roessler's avatar
Thomas Roessler committed
899
  const char *fqdn = mutt_fqdn(1);
Thomas Roessler's avatar
Thomas Roessler committed
900

901 902 903 904 905 906 907 908
  /* 
   * Note: We let $from override $realname here.  Is this the right
   * thing to do? 
   */

  if (From)
    adr = rfc822_cpy_adr_real (From);
  else if (option (OPTUSEDOMAIN))
Thomas Roessler's avatar
Thomas Roessler committed
909
  {
910
    adr = rfc822_new_address ();
911
    adr->mailbox = safe_malloc (mutt_strlen (Username) + mutt_strlen (fqdn) + 2);
Thomas Roessler's avatar
Thomas Roessler committed
912
    sprintf (adr->mailbox, "%s@%s", NONULL(Username), NONULL(fqdn));
Thomas Roessler's avatar
Thomas Roessler committed
913 914
  }
  else
915 916
  {
    adr = rfc822_new_address ();
Thomas Roessler's avatar
Thomas Roessler committed
917
    adr->mailbox = safe_strdup (NONULL(Username));
918 919
  }
  
Thomas Roessler's avatar
Thomas Roessler committed
920 921 922
  return (adr);
}

923 924 925 926 927
static int send_message (HEADER *msg)
{  
  char tempfile[_POSIX_PATH_MAX];
  FILE *tempfp;
  int i;
928
  
929 930 931 932 933
  /* Write out the message in MIME form. */
  mutt_mktemp (tempfile);
  if ((tempfp = safe_fopen (tempfile, "w")) == NULL)
    return (-1);

934 935 936 937 938 939 940
#ifdef MIXMASTER
  mutt_write_rfc822_header (tempfp, msg->env, msg->content, 0, msg->chain ? 1 : 0);
#endif
#ifndef MIXMASTER
  mutt_write_rfc822_header (tempfp, msg->env, msg->content, 0, 0);
#endif
  
941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956
  fputc ('\n', tempfp); /* tie off the header. */

  if ((mutt_write_mime_body (msg->content, tempfp) == -1))
  {
    fclose(tempfp);
    unlink (tempfile);
    return (-1);
  }
  
  if (fclose (tempfp) != 0)
  {
    mutt_perror (tempfile);
    unlink (tempfile);
    return (-1);
  }

957 958 959 960 961
#ifdef MIXMASTER
  if (msg->chain)
    return mix_send_message (msg->chain, tempfile);
#endif

962 963
  i = mutt_invoke_sendmail (msg->env->from, msg->env->to, msg->env->cc, 
			    msg->env->bcc, tempfile, (msg->content->encoding == ENC8BIT));
964
  return (i);
965 966 967
}

/* rfc2047 encode the content-descriptions */
968
static void encode_descriptions (BODY *b, short recurse)
969 970 971 972 973 974 975
{
  BODY *t;

  for (t = b; t; t = t->next)
  {
    if (t->description)
    {
976
      rfc2047_encode_string (&t->description);
977
    }
978 979 980 981 982 983 984 985 986 987 988 989 990 991
    if (recurse && t->parts)
      encode_descriptions (t->parts, recurse);
  }
}

/* rfc2047 decode them in case of an error */
static void decode_descriptions (BODY *b)
{
  BODY *t;
  
  for (t = b; t; t = t->next)
  {
    if (t->description)
    {
992
      rfc2047_decode (&t->description);
993
    }
994
    if (t->parts)
995
      decode_descriptions (t->parts);
996 997 998
  }
}

999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
int mutt_resend_message (FILE *fp, CONTEXT *ctx, HEADER *cur)
{
  HEADER *msg = mutt_new_header ();
  
  if (mutt_prepare_template (fp, ctx, msg, cur, 1) < 0)
    return -1;
  
  return ci_send_message (SENDRESEND, msg, NULL, ctx, cur);
}

int
Thomas Roessler's avatar
Thomas Roessler committed
1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020
ci_send_message (int flags,		/* send mode */
		 HEADER *msg,		/* template to use for new message */
		 char *tempfile,	/* file specified by -i or -H */
		 CONTEXT *ctx,		/* current mailbox */
		 HEADER *cur)		/* current message */
{
  char buffer[LONG_STRING];
  char fcc[_POSIX_PATH_MAX] = ""; /* where to copy this message */
  FILE *tempfp = NULL;
  BODY *pbody;
  int i, killfrom = 0;
1021

1022
#ifdef HAVE_PGP
1023
  BODY *save_content = NULL;
1024
  BODY *clear_content = NULL;
1025
  char *pgpkeylist = NULL;
Thomas Roessler's avatar
Thomas Roessler committed
1026 1027 1028
  /* save current value of "pgp_sign_as" */
  char *signas = NULL;
  char *signmic = NULL;
1029 1030
#endif

1031 1032
  int rv = -1;
  
1033 1034
  if (!flags && !msg && quadoption (OPT_RECALL) != M_NO &&
      mutt_num_postponed (1))
1035 1036 1037 1038
  {
    /* If the user is composing a new message, check to see if there
     * are any postponed messages first.
     */
1039
    if ((i = query_quadoption (OPT_RECALL, _("Recall postponed message?"))) == -1)
1040
      return rv;
1041

1042 1043 1044 1045 1046
    if(i == M_YES)
      flags |= SENDPOSTPONED;
  }
  
  
1047
#ifdef HAVE_PGP
1048
  if (flags & SENDPOSTPONED)
Thomas Roessler's avatar
Thomas Roessler committed
1049 1050 1051 1052
  {
    signas = safe_strdup(PgpSignAs);
    signmic = safe_strdup(PgpSignMicalg);
  }
1053
#endif /* HAVE_PGP */
Thomas Roessler's avatar
Thomas Roessler committed
1054 1055 1056

  if (msg)
  {
Thomas Roessler's avatar
Thomas Roessler committed
1057
    mutt_expand_aliases_env (msg->env);
Thomas Roessler's avatar
Thomas Roessler committed
1058 1059 1060 1061 1062
  }
  else
  {
    msg = mutt_new_header ();

1063
    if (flags == SENDPOSTPONED)
Thomas Roessler's avatar
Thomas Roessler committed
1064
    {
1065
      if ((flags = mutt_get_postponed (ctx, msg, &cur, fcc, sizeof (fcc))) < 0)
Thomas Roessler's avatar
Thomas Roessler committed
1066 1067 1068
	goto cleanup;
    }

1069
    if (flags & (SENDPOSTPONED|SENDRESEND))
Thomas Roessler's avatar
Thomas Roessler committed
1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081
    {
      if ((tempfp = safe_fopen (msg->content->filename, "a+")) == NULL)
      {
	mutt_perror (msg->content->filename);
	goto cleanup;
      }
    }

    if (!msg->env)
      msg->env = mutt_new_envelope ();
  }

1082
  if (! (flags & (SENDKEY | SENDPOSTPONED | SENDRESEND)))
Thomas Roessler's avatar
Thomas Roessler committed
1083 1084 1085 1086 1087 1088 1089 1090 1091
  {
    pbody = mutt_new_body ();
    pbody->next = msg->content; /* don't kill command-line attachments */
    msg->content = pbody;
    
    msg->content->type = TYPETEXT;
    msg->content->subtype = safe_strdup ("plain");
    msg->content->unlink = 1;
    msg->content->use_disp = 0;
1092
    msg->content->disposition = DISPINLINE;
Thomas Roessler's avatar
Thomas Roessler committed
1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
    
    if (!tempfile)
    {
      mutt_mktemp (buffer);
      tempfp = safe_fopen (buffer, "w+");
      msg->content->filename = safe_strdup (buffer);
    }
    else
    {
      tempfp = safe_fopen (tempfile, "a+");
      msg->content->filename = safe_strdup (tempfile);
    }

    if (!tempfp)
    {
Thomas Roessler's avatar
Thomas Roessler committed
1108 1109
      dprint(1,(debugfile, "newsend_message: can't create tempfile %s (errno=%d)\n", msg->content->filename, errno));
      mutt_perror (msg->content->filename);
Thomas Roessler's avatar
Thomas Roessler committed
1110 1111 1112 1113 1114
      goto cleanup;
    }
  }

  /* this is handled here so that the user can match ~f in send-hook */
1115
  if (cur && option (OPTREVNAME) && !(flags & (SENDPOSTPONED|SENDRESEND)))
Thomas Roessler's avatar
Thomas Roessler committed
1116 1117
  {
    /* we shouldn't have to worry about freeing `msg->env->from' before
1118 1119 1120
     * setting it here since this code will only execute when doing some
     * sort of reply.  the pointer will only be set when using the -H command
     * line option */
Thomas Roessler's avatar
Thomas Roessler committed
1121 1122 1123
    msg->env->from = set_reverse_name (cur->env);
  }

1124
  if (!msg->env->from && option (OPTUSEFROM) && !(flags & (SENDPOSTPONED|SENDRESEND)))
Thomas Roessler's avatar
Thomas Roessler committed
1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135
    msg->env->from = mutt_default_from ();

  if (flags & SENDBATCH) 
  {
    mutt_copy_stream (stdin, tempfp);
    if (option (OPTHDRS))
    {
      process_user_recips (msg->env);
      process_user_header (msg->env);
    }
  }
1136
  else if (! (flags & (SENDPOSTPONED|SENDRESEND)))
Thomas Roessler's avatar
Thomas Roessler committed
1137
  {
1138
    if ((flags & (SENDREPLY | SENDFORWARD)) && ctx &&
Thomas Roessler's avatar
Thomas Roessler committed
1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153
	envelope_defaults (msg->env, ctx, cur, flags) == -1)
      goto cleanup;

    if (option (OPTHDRS))
      process_user_recips (msg->env);

    if (! (flags & SENDMAILX) &&
	! (option (OPTAUTOEDIT) && option (OPTEDITHDRS)) &&
	! ((flags & SENDREPLY) && option (OPTFASTREPLY)))
    {
      if (edit_envelope (msg->env) == -1)
	goto cleanup;
    }

    /* the from address must be set here regardless of whether or not
1154 1155 1156 1157
     * $use_from is set so that the `~P' (from you) operator in send-hook
     * patterns will work.  if $use_from is unset, the from address is killed
     * after send-hooks are evaulated */

Thomas Roessler's avatar
Thomas Roessler committed
1158 1159 1160 1161 1162 1163 1164
    if (!msg->env->from)
    {
      msg->env->from = mutt_default_from ();
      killfrom = 1;
    }

    /* change settings based upon recipients */
1165
    
1166
    mutt_message_hook (NULL, msg, M_SENDHOOK);
Thomas Roessler's avatar
Thomas Roessler committed
1167 1168 1169 1170 1171 1172 1173

    if (killfrom)
    {
      rfc822_free_address (&msg->env->from);
      killfrom = 0;
    }

1174
    if (option (OPTHDRS))
Thomas Roessler's avatar
Thomas Roessler committed
1175 1176 1177
      process_user_header (msg->env);


1178 1179
    if (option (OPTSIGONTOP) && (! (flags & (SENDMAILX | SENDKEY)) && Editor && mutt_strcmp (Editor, "builtin") != 0))
      append_signature (tempfp);
1180 1181 1182 1183 1184 1185

    /* include replies/forwarded messages, unless we are given a template */
    if (!tempfile && (ctx || !(flags & (SENDREPLY|SENDFORWARD)))
	&& generate_body (tempfp, msg, flags, ctx, cur) == -1)
      goto cleanup;

1186
    if (!option (OPTSIGONTOP) && (! (flags & (SENDMAILX | SENDKEY)) && Editor && mutt_strcmp (Editor, "builtin") != 0))
1187 1188 1189 1190 1191 1192 1193
      append_signature (tempfp);

    /* 
     * this wants to be done _after_ generate_body, so message-hooks
     * can take effect.
     */

1194
#ifdef HAVE_PGP
Thomas Roessler's avatar
Thomas Roessler committed
1195 1196 1197 1198 1199 1200 1201 1202 1203 1204
    if (! (flags & SENDMAILX))
    {
      if (option (OPTPGPAUTOSIGN))
	msg->pgp |= PGPSIGN;
      if (option (OPTPGPAUTOENCRYPT))
	msg->pgp |= PGPENCRYPT;
      if (option (OPTPGPREPLYENCRYPT) && cur && cur->pgp & PGPENCRYPT)
	msg->pgp |= PGPENCRYPT;
      if (option (OPTPGPREPLYSIGN) && cur && cur->pgp & PGPSIGN)
	msg->pgp |= PGPSIGN;
1205 1206
      if (option (OPTPGPREPLYSIGNENCRYPTED) && cur && cur->pgp & PGPENCRYPT)
	msg->pgp |= PGPSIGN;
Thomas Roessler's avatar
Thomas Roessler committed
1207
    }
1208
#endif /* HAVE_PGP */
Thomas Roessler's avatar
Thomas Roessler committed
1209 1210 1211 1212 1213 1214



  }
  /* wait until now to set the real name portion of our return address so
     that $realname can be set in a send-hook */
1215
  if (msg->env->from && !msg->env->from->personal && !(flags & (SENDRESEND|SENDPOSTPONED)))
Thomas Roessler's avatar
Thomas Roessler committed
1216 1217 1218 1219
    msg->env->from->personal = safe_strdup (Realname);



1220
#ifdef HAVE_PGP
Thomas Roessler's avatar
Thomas Roessler committed
1221
  
1222
  if (! (flags & SENDKEY) && tempfp)
Thomas Roessler's avatar
Thomas Roessler committed
1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233
  {

#endif
    


    fclose (tempfp);
    tempfp = NULL;
    


1234
#ifdef HAVE_PGP
Thomas Roessler's avatar
Thomas Roessler committed
1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250
    
  }

#endif



  if (flags & SENDMAILX)
  {
    if (mutt_builtin_editor (msg->content->filename, msg, cur) == -1)
      goto cleanup;
  }
  else if (! (flags & SENDBATCH))
  {
    struct stat st;
    time_t mtime;
1251
    struct utimbuf utim;
Thomas Roessler's avatar
Thomas Roessler committed
1252 1253 1254

    stat (msg->content->filename, &st);
    mtime = st.st_mtime;
1255 1256 1257 1258 1259 1260 1261 1262 1263 1264
    if (mtime == time (NULL))
    {
      /* Decrease the file's modification time by 1 second so we are sure
       * to find out if the `editor' program changes it in less than 1 second.
       */
      mtime -= 1;
      utim.actime = mtime;
      utim.modtime = mtime;
      utime (msg->content->filename, &utim);
    }
Thomas Roessler's avatar
Thomas Roessler committed
1265

1266
    mutt_update_encoding (msg->content);
Thomas Roessler's avatar
Thomas Roessler committed
1267 1268 1269 1270 1271

    /* If the this isn't a text message, look for a mailcap edit command */
    if(! (flags & SENDKEY))
    {
      if (mutt_needs_mailcap (msg->content))
Thomas Roessler's avatar
Thomas Roessler committed
1272
	mutt_edit_attachment (msg->content);
1273
      else if (!Editor || mutt_strcmp ("builtin", Editor) == 0)
Thomas Roessler's avatar
Thomas Roessler committed
1274 1275 1276 1277 1278 1279 1280
	mutt_builtin_editor (msg->content->filename, msg, cur);
      else if (option (OPTEDITHDRS))
	mutt_edit_headers (Editor, msg->content->filename, msg, fcc, sizeof (fcc));
      else
	mutt_edit_file (Editor, msg->content->filename);
    }

1281
    if (! (flags & (SENDPOSTPONED | SENDFORWARD | SENDKEY | SENDRESEND)))
Thomas Roessler's avatar
Thomas Roessler committed
1282 1283 1284 1285 1286
    {
      if (stat (msg->content->filename, &st) == 0)
      {
	/* if the file was not modified, bail out now */
	if (mtime == st.st_mtime &&
1287
	    query_quadoption (OPT_ABORT, _("Abort unmodified message?")) == M_YES)
Thomas Roessler's avatar
Thomas Roessler committed
1288
	{
1289
	  mutt_message _("Aborted unmodified message.");
Thomas Roessler's avatar
Thomas Roessler committed
1290 1291 1292 1293 1294 1295 1296 1297 1298
	  goto cleanup;
	}
      }
      else
	mutt_perror (msg->content->filename);
    }
  }

  /* specify a default fcc.  if we are in batchmode, only save a copy of
1299 1300
   * the message if the value of $copy is yes or ask-yes */

1301
  if (!fcc[0] && !(flags & (SENDRESEND|SENDPOSTPONED)) && (!(flags & SENDBATCH) || (quadoption (OPT_COPY) & 0x1)))
Thomas Roessler's avatar
Thomas Roessler committed
1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317
  {
    /* set the default FCC */
    if (!msg->env->from)
    {
      msg->env->from = mutt_default_from ();
      killfrom = 1; /* no need to check $use_from because if the user specified
		       a from address it would have already been set by now */
    }
    mutt_select_fcc (fcc, sizeof (fcc), msg);
    if (killfrom)
    {
      rfc822_free_address (&msg->env->from);
      killfrom = 0;
    }
  }

1318
  
1319
  mutt_update_encoding (msg->content);
Thomas Roessler's avatar
Thomas Roessler committed
1320 1321 1322 1323 1324

  if (! (flags & (SENDMAILX | SENDBATCH)))
  {
main_loop:

1325
    mutt_pretty_mailbox (fcc);
1326 1327
    i = mutt_compose_menu (msg, fcc, sizeof (fcc), cur);
    if (i == -1)
Thomas Roessler's avatar
Thomas Roessler committed
1328 1329
    {
      /* abort */
1330
      mutt_message _("Mail not sent.");
Thomas Roessler's avatar
Thomas Roessler committed
1331 1332 1333 1334 1335 1336 1337
      goto cleanup;
    }
    else if (i == 1)
    {
      /* postpone the message until later. */
      if (msg->content->next)
	msg->content = mutt_make_multipart (msg->content);
1338 1339 1340 1341 1342 1343 1344

      /*
       * make sure the message is written to the right part of a maildir 
       * postponed folder.
       */
      msg->read = 0; msg->old = 0;

1345 1346 1347
      encode_descriptions (msg->content, 1);
      mutt_prepare_envelope (msg->env, 0);

1348
      if (!Postponed || mutt_write_fcc (NONULL (Postponed), msg, (cur && (flags & SENDREPLY)) ? cur->env->message_id : NULL, 1, fcc) < 0)
Thomas Roessler's avatar
Thomas Roessler committed
1349
      {
1350
	msg->content = mutt_remove_multipart (msg->content);
1351 1352
	decode_descriptions (msg->content);
	mutt_unprepare_envelope (msg->env);
Thomas Roessler's avatar
Thomas Roessler committed
1353 1354
	goto main_loop;
      }
1355
      mutt_update_num_postponed ();
1356
      mutt_message _("Message postponed.");
Thomas Roessler's avatar
Thomas Roessler committed
1357 1358 1359 1360 1361 1362 1363 1364
      goto cleanup;
    }
  }

  if (!msg->env->to && !msg->env->cc && !msg->env->bcc)
  {
    if (! (flags & SENDBATCH))
    {
1365
      mutt_error _("No recipients are specified!");
Thomas Roessler's avatar
Thomas Roessler committed
1366 1367 1368 1369
      goto main_loop;
    }
    else
    {
1370
      puts _("No recipients were specified.");
Thomas Roessler's avatar
Thomas Roessler committed
1371 1372 1373 1374 1375
      goto cleanup;
    }
  }

  if (!msg->env->subject && ! (flags & SENDBATCH) &&
1376
      (i = query_quadoption (OPT_SUBJECT, _("No subject, abort sending?"))) != M_NO)
Thomas Roessler's avatar
Thomas Roessler committed
1377 1378 1379
  {
    /* if the abort is automatic, print an error message */
    if (quadoption (OPT_SUBJECT) == M_YES)
1380
      mutt_error _("No subject specified.");
Thomas Roessler's avatar
Thomas Roessler committed
1381 1382 1383 1384 1385 1386
    goto main_loop;
  }

  if (msg->content->next)
    msg->content = mutt_make_multipart (msg->content);

1387 1388
  /* 
   * Ok, we need to do it this way instead of handling all fcc stuff in
1389 1390 1391
   * one place in order to avoid going to main_loop with encoded "env"
   * in case of error.  Ugh.
   */
1392

1393 1394
  encode_descriptions (msg->content, 1);
  
1395
#ifdef HAVE_PGP
Thomas Roessler's avatar
Thomas Roessler committed
1396 1397
  if (msg->pgp)
  {
1398
    /* save the decrypted attachments */
1399
    clear_content = msg->content;
1400

Thomas Roessler's avatar
Thomas Roessler committed
1401 1402
    if ((pgp_get_keys (msg, &pgpkeylist) == -1) ||
	(pgp_protect (msg, pgpkeylist) == -1))
Thomas Roessler's avatar
Thomas Roessler committed
1403
    {
1404 1405
      msg->content = mutt_remove_multipart (msg->content);
      
1406 1407
      if (pgpkeylist)
	FREE (&pgpkeylist);
1408 1409
      
      decode_descriptions (msg->content);
Thomas Roessler's avatar
Thomas Roessler committed
1410 1411
      goto main_loop;
    }
1412
    encode_descriptions (msg->content, 0);
Thomas Roessler's avatar
Thomas Roessler committed
1413 1414
  }

1415 1416 1417 1418 1419 1420 1421 1422
  /* 
   * at this point, msg->content is one of the following three things:
   * - multipart/signed.  In this case, clear_content is a child.
   * - multipart/encrypted.  In this case, clear_content exists
   *   independently
   * - application/pgp.  In this case, clear_content exists independently.
   * - something else.  In this case, it's the same as clear_content.
   */
1423

1424
#endif /* HAVE_PGP */
1425

1426
  if (!option (OPTNOCURSES) && !(flags & SENDMAILX))
1427
    mutt_message _("Sending message...");
Thomas Roessler's avatar
Thomas Roessler committed
1428

1429
  mutt_prepare_envelope (msg->env, 1);
Thomas Roessler's avatar
Thomas Roessler committed
1430

1431
  /* save a copy of the message, if necessary. */
1432

Thomas Roessler's avatar
Thomas Roessler committed
1433
  mutt_expand_path (fcc, sizeof (fcc));
1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449

  
  /* Don't save a copy when we are in batch-mode, and the FCC
   * folder is on an IMAP server: This would involve possibly lots
   * of user interaction, which is not available in batch mode. 
   * 
   * Note: A patch to fix the problems with the use of IMAP servers
   * from non-curses mode is available from Brendan Cully.  However, 
   * I'd like to think a bit more about this before including it.
   */

#ifdef USE_IMAP
  if ((flags & SENDBATCH) && fcc[0] && mx_is_imap (fcc))
    fcc[0] = '\0';
#endif

1450
  if (*fcc && mutt_strcmp ("/dev/null", fcc) != 0)
1451 1452
  {
    BODY *tmpbody = msg->content;
1453
#ifdef HAVE_PGP
1454 1455
    BODY *save_sig = NULL;
    BODY *save_parts = NULL;
1456
#endif /* HAVE_PGP */
Thomas Roessler's avatar
Thomas Roessler committed
1457

1458
#ifdef HAVE_PGP
1459 1460 1461 1462
    if (msg->pgp && option (OPTFCCCLEAR))
      msg->content = clear_content;
#endif

1463 1464 1465
    /* check to see if the user wants copies of all attachments */
    if (!option (OPTFCCATTACH) && msg->content->type == TYPEMULTIPART)
    {
1466
#ifdef HAVE_PGP
1467 1468
      if (mutt_strcmp (msg->content->subtype, "encrypted") == 0 ||
	  mutt_strcmp (msg->content->subtype, "signed") == 0)
1469
      {
1470
	if (clear_content->type == TYPEMULTIPART)
1471
	{
1472 1473 1474 1475
	  if (!(msg->pgp & PGPENCRYPT) && (msg->pgp & PGPSIGN))
	  {
	    /* save initial signature and attachments */
	    save_sig = msg->content->parts->next;
1476
	    save_parts = clear_content->parts->next;
1477 1478 1479
	  }

	  /* this means writing only the main part */
1480
	  msg->content = clear_content->parts;
1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491

	  if (pgp_protect (msg, pgpkeylist) == -1)
	  {
	    /* we can't do much about it at this point, so
	     * fallback to saving the whole thing to fcc
	     */
	    msg->content = tmpbody;
	    save_sig = NULL;
	    goto full_fcc;
	  }

1492
	  save_content = msg->content;
1493 1494 1495
	}
      }
      else
1496
#endif /* HAVE_PGP */
1497 1498
	msg->content = msg->content->parts;
    }
Thomas Roessler's avatar
Thomas Roessler committed
1499

1500
#ifdef HAVE_PGP
1501
full_fcc:
1502
#endif /* HAVE_PGP */
1503
    if (msg->content)
1504
      mutt_write_fcc (fcc, msg, NULL, 0, NULL);
1505

1506
    msg->content = tmpbody;
1507

1508
#ifdef HAVE_PGP
1509 1510 1511 1512 1513 1514
    if (save_sig)
    {
      /* cleanup the second signature structures */
      mutt_free_body (&save_content->parts->next);
      save_content->parts = NULL;
      mutt_free_body (&save_content);
1515

1516 1517 1518 1519
      /* restore old signature and attachments */
      msg->content->parts->next = save_sig;
      msg->content->parts->parts->next = save_parts;
    }
1520 1521 1522 1523 1524 1525
    else if (save_content)
    {
      /* destroy the new encrypted body. */
      mutt_free_body (&save_content);
    }
      
1526
#endif /* HAVE_PGP */
Thomas Roessler's avatar
Thomas Roessler committed
1527 1528 1529
  }


1530
  if ((i = send_message (msg)) == -1)
Thomas Roessler's avatar
Thomas Roessler committed
1531
  {
1532 1533
    if (!(flags & SENDBATCH))
    {
1534
#ifdef HAVE_PGP
1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546
      if ((msg->pgp & PGPENCRYPT) || 
	  ((msg->pgp & PGPSIGN) && msg->content->type == TYPEAPPLICATION))
      {
	mutt_free_body (&msg->content); /* destroy PGP data */
	msg->content = clear_content;	/* restore clear text. */
      }
      else if ((msg->pgp & PGPSIGN) && msg->content->type == TYPEMULTIPART)
      {
	mutt_free_body (&msg->content->parts->next);		/* destroy sig */
	msg->content = mutt_remove_multipart (msg->content);	/* remove multipart */
      }
#endif
1547
      msg->content = mutt_remove_multipart (msg->content);
1548 1549
      decode_descriptions (msg->content);
      mutt_unprepare_envelope (msg->env);
1550 1551 1552 1553 1554 1555 1556
      goto main_loop;
    }
    else
    {
      puts _("Could not send the message.");
      goto cleanup;
    }
Thomas Roessler's avatar
Thomas Roessler committed
1557
  }
1558 1559
  else if (!option (OPTNOCURSES) && ! (flags & SENDMAILX))
    mutt_message (i == 0 ? _("Mail sent.") : _("Sending in background."));
Thomas Roessler's avatar
Thomas Roessler committed
1560

1561
#ifdef HAVE_PGP
1562 1563 1564 1565 1566 1567
  if (msg->pgp & PGPENCRYPT)
  {
    /* cleanup structures from the first encryption */
    mutt_free_body (&clear_content);
    FREE (&pgpkeylist);
  }
1568
#endif /* HAVE_PGP */
1569

Thomas Roessler's avatar
Thomas Roessler committed
1570 1571
  if (flags & SENDREPLY)
  {
1572
    if (cur && ctx)
Thomas Roessler's avatar
Thomas Roessler committed
1573 1574 1575 1576 1577 1578 1579 1580 1581
      mutt_set_flag (ctx, cur, M_REPLIED, 1);
    else if (!(flags & SENDPOSTPONED) && ctx && ctx->tagged)
    {
      for (i = 0; i < ctx->vcount; i++)
	if (ctx->hdrs[ctx->v2r[i]]->tagged)
	  mutt_set_flag (ctx, ctx->hdrs[ctx->v2r[i]], M_REPLIED, 1);
    }
  }

1582 1583 1584

  rv = 0;
  
Thomas Roessler's avatar
Thomas Roessler committed
1585 1586 1587 1588
cleanup:



1589
#ifdef HAVE_PGP
1590
  if (flags & SENDPOSTPONED)
Thomas Roessler's avatar
Thomas Roessler committed
1591
  {
1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603
    
    if(signas)
    {
      safe_free((void **) &PgpSignAs);
      PgpSignAs = signas;
    }
    
    if(signmic)
    {
      safe_free((void **) &PgpSignMicalg);
      PgpSignMicalg = signmic;
    }
Thomas Roessler's avatar
Thomas Roessler committed
1604