Esempio n. 1
0
static HEADER *select_msg (void)
{
  MUTTMENU *menu;
  int i, done=0, r=-1;
  char helpstr[LONG_STRING];
  short orig_sort;

  menu = mutt_new_menu (MENU_POST);
  menu->make_entry = post_entry;
  menu->max = PostContext->msgcount;
  menu->title = _("Postponed Messages");
  menu->data = PostContext;
  menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_POST, PostponeHelp);

  /* The postponed mailbox is setup to have sorting disabled, but the global
   * Sort variable may indicate something different.   Sorting has to be
   * disabled while the postpone menu is being displayed. */
  orig_sort = Sort;
  Sort = SORT_ORDER;

  while (!done)
  {
    switch (i = mutt_menuLoop (menu))
    {
      case OP_DELETE:
      case OP_UNDELETE:
        /* should deleted draft messages be saved in the trash folder? */
	mutt_set_flag (PostContext, PostContext->hdrs[menu->current], MUTT_DELETE, (i == OP_DELETE) ? 1 : 0);
	PostCount = PostContext->msgcount - PostContext->deleted;
	if (option (OPTRESOLVE) && menu->current < menu->max - 1)
	{
	  menu->oldcurrent = menu->current;
	  menu->current++;
	  if (menu->current >= menu->top + menu->pagelen)
	  {
	    menu->top = menu->current;
	    menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
	  }
	  else
	    menu->redraw |= REDRAW_MOTION_RESYNCH;
	}
	else
	  menu->redraw = REDRAW_CURRENT;
	break;

      case OP_GENERIC_SELECT_ENTRY:
	r = menu->current;
	done = 1;
	break;

      case OP_EXIT:
	done = 1;
	break;
    }
  }

  Sort = orig_sort;
  mutt_menuDestroy (&menu);
  return (r > -1 ? PostContext->hdrs[r] : NULL);
}
Esempio n. 2
0
void f_reset_flag(INT32 args) {
	int idx;
	HEADER *header=0;
	int flag;
	
	get_all_args("reset_flag",args,"%i%i",&idx,&flag);
	
	header=THIS->ctx->hdrs[idx];
	mutt_set_flag(THIS->ctx, header, flag,0);
	pop_n_elems(args);
}
static HEADER *select_msg (void)
{
  MUTTMENU *menu;
  int i, done=0, r=-1;
  char helpstr[SHORT_STRING];

  menu = mutt_new_menu ();
  menu->make_entry = post_entry;
  menu->menu = MENU_POST;
  menu->max = PostContext->msgcount;
  menu->title = _("Postponed Messages");
  menu->data = PostContext;
  menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_POST, PostponeHelp);

  while (!done)
  {
    switch (i = mutt_menuLoop (menu))
    {
      case OP_DELETE:
      case OP_UNDELETE:
	mutt_set_flag (PostContext, PostContext->hdrs[menu->current], M_DELETE, (i == OP_DELETE) ? 1 : 0);
	PostCount = PostContext->msgcount - PostContext->deleted;
	if (option (OPTRESOLVE) && menu->current < menu->max - 1)
	{
	  menu->oldcurrent = menu->current;
	  menu->current++;
	  if (menu->current >= menu->top + menu->pagelen)
	  {
	    menu->top = menu->current;
	    menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
	  }
	  else
	    menu->redraw |= REDRAW_MOTION_RESYNCH;
	}
	else
	  menu->redraw = REDRAW_CURRENT;
	break;

      case OP_GENERIC_SELECT_ENTRY:
	r = menu->current;
	done = 1;
	break;

      case OP_EXIT:
	done = 1;
	break;
    }
  }

  mutt_menuDestroy (&menu);
  return (r > -1 ? PostContext->hdrs[r] : NULL);
}
Esempio n. 4
0
File: mh.c Progetto: hww3/pexts
int mh_check_mailbox(CONTEXT *ctx, int *index_hint)
{
  char buf[_POSIX_PATH_MAX], b1[LONG_STRING], b2[LONG_STRING];
  struct stat st, st_cur;
  short modified = 0, have_new = 0, occult = 0;
  struct maildir *md, *p;
  struct maildir **last;
  HASH *fnames;
  int i, j;
  
  if(!option (OPTCHECKNEW))
    return 0;
  
  if(ctx->magic == M_MH)
  {
    strfcpy(buf, ctx->path, sizeof(buf));
    if(stat(buf, &st) == -1)
      return -1;

    /* create .mh_sequences when there isn't one. */
    snprintf (buf, sizeof (buf), "%s/.mh_sequences", ctx->path);
    if (stat (buf, &st_cur) == -1)
    {
      if (errno == ENOENT)
      {
	char *tmp;
	FILE *fp = NULL;

	if (mh_mkstemp (ctx, &fp, &tmp) == 0)
	{
	  safe_fclose (&fp);
	  if (safe_rename (tmp, buf) == -1)
	    unlink (tmp);
	  safe_free ((void **) &tmp);
	}
	
	if (stat (buf, &st_cur) == -1)
	  modified = 1;
      }
      else
	modified = 1;
    }
  }
  else if(ctx->magic == M_MAILDIR)
  {
    snprintf(buf, sizeof(buf), "%s/new", ctx->path);
    if(stat(buf, &st) == -1)
      return -1;
    
    snprintf(buf, sizeof(buf), "%s/cur", ctx->path);
    if(stat(buf, &st_cur) == -1)			/* XXX - name is bad. */
      modified = 1;

  }
  
  if(!modified && ctx->magic == M_MAILDIR && st_cur.st_mtime > ctx->mtime_cur)
    modified = 1;
  
  if(!modified && ctx->magic == M_MH && (st.st_mtime > ctx->mtime || st_cur.st_mtime > ctx->mtime_cur))
    modified = 1;
  
  if(modified || (ctx->magic == M_MAILDIR && st.st_mtime > ctx->mtime))
    have_new = 1;
  
  if(!modified && !have_new)
    return 0;

  ctx->mtime_cur = st_cur.st_mtime;
  ctx->mtime = st.st_mtime;

#if 0
  if(Sort != SORT_ORDER)
  {
    short old_sort;
    
    old_sort = Sort;
    Sort = SORT_ORDER;
    mutt_sort_headers(ctx, 1);
    Sort = old_sort;
  }
#endif

  md = NULL;
  last = &md;

  if(ctx->magic == M_MAILDIR)
  {
    if(have_new)
      maildir_parse_dir(ctx, &last, "new", NULL);
    if(modified)
      maildir_parse_dir(ctx, &last, "cur", NULL);
  }
  else if(ctx->magic == M_MH)
  {
    struct mh_sequences mhs;
    memset (&mhs, 0, sizeof (mhs));
    maildir_parse_dir (ctx, &last, NULL, NULL);
    mh_read_sequences (&mhs, ctx->path);
    mh_update_maildir (md, &mhs);
    mhs_free_sequences (&mhs);
  }

  /* check for modifications and adjust flags */

  fnames = hash_create (1031);
  
  for(p = md; p; p = p->next)
  {
    if(ctx->magic == M_MAILDIR)
    {
      maildir_canon_filename(b2, p->h->path, sizeof(b2));
      p->canon_fname = safe_strdup(b2);
    }
    else
      p->canon_fname = safe_strdup(p->h->path);
    
    hash_insert(fnames, p->canon_fname, p, 0);
  }

  
  for(i = 0; i < ctx->msgcount; i++)
  {
    ctx->hdrs[i]->active = 0;

    if(ctx->magic == M_MAILDIR)
      maildir_canon_filename(b1, ctx->hdrs[i]->path, sizeof(b1));
    else
      strfcpy(b1, ctx->hdrs[i]->path, sizeof(b1));

    dprint(2, (debugfile, "%s:%d: mh_check_mailbox(): Looking for %s.\n", __FILE__, __LINE__, b1));
    
    if((p = hash_find(fnames, b1)) && p->h &&
       mbox_strict_cmp_headers(ctx->hdrs[i], p->h))
    {
      /* found the right message */

      dprint(2, (debugfile, "%s:%d: Found.  Flags before: %s%s%s%s%s\n", __FILE__, __LINE__,
		 ctx->hdrs[i]->flagged ? "f" : "",
		 ctx->hdrs[i]->deleted ? "D" : "",
		 ctx->hdrs[i]->replied ? "r" : "",
		 ctx->hdrs[i]->old     ? "O" : "",
		 ctx->hdrs[i]->read    ? "R" : ""));

      if(mutt_strcmp(ctx->hdrs[i]->path, p->h->path))
	mutt_str_replace (&ctx->hdrs[i]->path, p->h->path);

      if(modified)
      {
	if(!ctx->hdrs[i]->changed)
	{
	  mutt_set_flag (ctx, ctx->hdrs[i], M_FLAG, p->h->flagged);
	  mutt_set_flag (ctx, ctx->hdrs[i], M_REPLIED, p->h->replied);
	  mutt_set_flag (ctx, ctx->hdrs[i], M_READ, p->h->read);
	}

	mutt_set_flag(ctx, ctx->hdrs[i], M_OLD, p->h->old);
      }

      ctx->hdrs[i]->active = 1;

      dprint(2, (debugfile, "%s:%d:         Flags after: %s%s%s%s%s\n", __FILE__, __LINE__,
		 ctx->hdrs[i]->flagged ? "f" : "",
		 ctx->hdrs[i]->deleted ? "D" : "",
		 ctx->hdrs[i]->replied ? "r" : "",
		 ctx->hdrs[i]->old     ? "O" : "",
		 ctx->hdrs[i]->read    ? "R" : ""));

      mutt_free_header(&p->h);
    }
    else if (ctx->magic == M_MAILDIR && !modified && !strncmp("cur/", ctx->hdrs[i]->path, 4))
    {
      /* If the cur/ part wasn't externally modified for a maildir
       * type folder, assume the message is still active. Actually,
       * we simply don't know.
       */

      ctx->hdrs[i]->active = 1;
    }
    else if (modified || (ctx->magic == M_MAILDIR && !strncmp("new/", ctx->hdrs[i]->path, 4)))
    {
      
      /* Mailbox was modified, or a new message vanished. */

      /* Note: This code will _not_ apply for a new message which
       * is just moved to cur/, as this would modify cur's time
       * stamp and lead to modified == 1.  Thus, we'd have parsed
       * the complete folder above, and the message would have
       * been found in the look-up table.
       */
      
      dprint(2, (debugfile, "%s:%d: Not found.  Flags were: %s%s%s%s%s\n", __FILE__, __LINE__,
		 ctx->hdrs[i]->flagged ? "f" : "",
		 ctx->hdrs[i]->deleted ? "D" : "",
		 ctx->hdrs[i]->replied ? "r" : "",
		 ctx->hdrs[i]->old     ? "O" : "",
		 ctx->hdrs[i]->read    ? "R" : ""));
      
      occult = 1;

    }
  }

  /* destroy the file name hash */

  hash_destroy(&fnames, NULL);

  /* If we didn't just get new mail, update the tables. */
  
  if(modified || occult)
  {
    short old_sort;
    int old_count;

#ifndef LIBMUTT
    if (Sort != SORT_ORDER)
    {
      old_sort = Sort;
      Sort = SORT_ORDER;
      mutt_sort_headers (ctx, 1);
      Sort = old_sort;
    }
#endif
  
    old_count = ctx->msgcount;
    for (i = 0, j = 0; i < old_count; i++)
    {
      if (ctx->hdrs[i]->active && index_hint && *index_hint == i)
	*index_hint = j;

      if (ctx->hdrs[i]->active)
	ctx->hdrs[i]->index = j++;
    }
    mx_update_tables(ctx, 0);
  }

  /* Incorporate new messages */

  maildir_move_to_context(ctx, &md);

  return (modified || occult) ? M_REOPENED : have_new ? M_NEW_MAIL : 0;
}
Esempio n. 5
0
/* args:
 *      ctx	Context info, used when recalling a message to which
 *              we reply.
 *	hdr	envelope/attachment info for recalled message
 *	cur	if message was a reply, `cur' is set to the message which
 *		`hdr' is in reply to
 *	fcc	fcc for the recalled message
 *	fcclen	max length of fcc
 *
 * return vals:
 *	-1		error/no messages
 *	0		normal exit
 *	SENDREPLY	recalled message is a reply
 */
int mutt_get_postponed (CONTEXT *ctx, HEADER *hdr, HEADER **cur, char *fcc, size_t fcclen)
{
  HEADER *h;
  int code = SENDPOSTPONED;
  LIST *tmp;
  LIST *last = NULL;
  LIST *next;
  const char *p;
  int opt_delete;

  if (!Postponed)
    return (-1);

  if ((PostContext = mx_open_mailbox (Postponed, M_NOSORT, NULL)) == NULL)
  {
    PostCount = 0;
    mutt_error _("No postponed messages.");
    return (-1);
  }

  if (! PostContext->msgcount)
  {
    PostCount = 0;
    mx_close_mailbox (PostContext, NULL);
    FREE (&PostContext);
    mutt_error _("No postponed messages.");
    return (-1);
  }

  if (PostContext->msgcount == 1)
  {
    /* only one message, so just use that one. */
    h = PostContext->hdrs[0];
  }
  else if ((h = select_msg ()) == NULL)
  {
    mx_close_mailbox (PostContext, NULL);
    FREE (&PostContext);
    return (-1);
  }

  if (mutt_prepare_template (NULL, PostContext, hdr, h, 0) < 0)
  {
    mx_fastclose_mailbox (PostContext);
    FREE (&PostContext);
    return (-1);
  }

  /* finished with this message, so delete it. */
  mutt_set_flag (PostContext, h, M_DELETE, 1);

  /* update the count for the status display */
  PostCount = PostContext->msgcount - PostContext->deleted;

  /* avoid the "purge deleted messages" prompt */
  opt_delete = quadoption (OPT_DELETE);
  set_quadoption (OPT_DELETE, M_YES);
  mx_close_mailbox (PostContext, NULL);
  set_quadoption (OPT_DELETE, opt_delete);

  FREE (&PostContext);

  for (tmp = hdr->env->userhdrs; tmp; )
  {
    if (ascii_strncasecmp ("X-Mutt-References:", tmp->data, 18) == 0)
    {
      if (ctx)
      {
	/* if a mailbox is currently open, look to see if the orignal message
	   the user attempted to reply to is in this mailbox */
	p = skip_email_wsp(tmp->data + 18);
	if (!ctx->id_hash)
	  ctx->id_hash = mutt_make_id_hash (ctx);
	*cur = hash_find (ctx->id_hash, p);
      }

      /* Remove the X-Mutt-References: header field. */
      next = tmp->next;
      if (last)
	last->next = tmp->next;
      else
	hdr->env->userhdrs = tmp->next;
      tmp->next = NULL;
      mutt_free_list (&tmp);
      tmp = next;
      if (*cur)
	code |= SENDREPLY;
    }
    else if (ascii_strncasecmp ("X-Mutt-Fcc:", tmp->data, 11) == 0)
    {
      p = skip_email_wsp(tmp->data + 11);
      strfcpy (fcc, p, fcclen);
      mutt_pretty_mailbox (fcc, fcclen);

      /* remove the X-Mutt-Fcc: header field */
      next = tmp->next;
      if (last)
	last->next = tmp->next;
      else
	hdr->env->userhdrs = tmp->next;
      tmp->next = NULL;
      mutt_free_list (&tmp);
      tmp = next;
     /* note that x-mutt-fcc was present.  we do this because we want to add a
      * default fcc if the header was missing, but preserve the request of the
      * user to not make a copy if the header field is present, but empty.
      * see http://dev.mutt.org/trac/ticket/3653
      */
      code |= SENDPOSTPONEDFCC;
    }
    else if ((WithCrypto & APPLICATION_PGP)
             && (mutt_strncmp ("Pgp:", tmp->data, 4) == 0 /* this is generated
						       * by old mutt versions
						       */
                 || mutt_strncmp ("X-Mutt-PGP:", tmp->data, 11) == 0))
    {
      hdr->security = mutt_parse_crypt_hdr (strchr (tmp->data, ':') + 1, 1,
					    APPLICATION_PGP);
      hdr->security |= APPLICATION_PGP;

      /* remove the pgp field */
      next = tmp->next;
      if (last)
	last->next = tmp->next;
      else
	hdr->env->userhdrs = tmp->next;
      tmp->next = NULL;
      mutt_free_list (&tmp);
      tmp = next;
    }
    else if ((WithCrypto & APPLICATION_SMIME)
             && mutt_strncmp ("X-Mutt-SMIME:", tmp->data, 13) == 0)
    {
      hdr->security = mutt_parse_crypt_hdr (strchr (tmp->data, ':') + 1, 1,
					    APPLICATION_SMIME);
      hdr->security |= APPLICATION_SMIME;

      /* remove the smime field */
      next = tmp->next;
      if (last)
	last->next = tmp->next;
      else
	hdr->env->userhdrs = tmp->next;
      tmp->next = NULL;
      mutt_free_list (&tmp);
      tmp = next;
    }

#ifdef MIXMASTER
    else if (mutt_strncmp ("X-Mutt-Mix:", tmp->data, 11) == 0)
    {
      char *t;
      mutt_free_list (&hdr->chain);

      t = strtok (tmp->data + 11, " \t\n");
      while (t)
      {
	hdr->chain = mutt_add_list (hdr->chain, t);
	t = strtok (NULL, " \t\n");
      }

      next = tmp->next;
      if (last)
	last->next = tmp->next;
      else
	hdr->env->userhdrs = tmp->next;
      tmp->next = NULL;
      mutt_free_list (&tmp);
      tmp = next;
    }
#endif

    else
    {
      last = tmp;
      tmp = tmp->next;
    }
  }

  if (option (OPTCRYPTOPPORTUNISTICENCRYPT))
    crypt_opportunistic_encrypt (hdr);

  return (code);
}
Esempio n. 6
0
int imap_fetch_message (CONTEXT *ctx, MESSAGE *msg, int msgno)
{
  IMAP_DATA* idata;
  HEADER* h;
  ENVELOPE* newenv;
  char buf[LONG_STRING];
  char path[_POSIX_PATH_MAX];
  char *pc;
  long bytes;
  progress_t progressbar;
  int uid;
  int cacheno;
  IMAP_CACHE *cache;
  int read;
  int rc;
  /* Sam's weird courier server returns an OK response even when FETCH
   * fails. Thanks Sam. */
  short fetched = 0;

  idata = (IMAP_DATA*) ctx->data;
  h = ctx->hdrs[msgno];

  if ((msg->fp = msg_cache_get (idata, h)))
  {
    if (HEADER_DATA(h)->parsed)
      return 0;
    else
      goto parsemsg;
  }

  /* we still do some caching even if imap_cachedir is unset */
  /* see if we already have the message in our cache */
  cacheno = HEADER_DATA(h)->uid % IMAP_CACHE_LEN;
  cache = &idata->cache[cacheno];

  if (cache->path)
  {
    /* don't treat cache errors as fatal, just fall back. */
    if (cache->uid == HEADER_DATA(h)->uid &&
        (msg->fp = fopen (cache->path, "r")))
      return 0;
    else
    {
      unlink (cache->path);
      FREE (&cache->path);
    }
  }

  if (!isendwin())
    mutt_message _("Fetching message...");

  if (!(msg->fp = msg_cache_put (idata, h)))
  {
    cache->uid = HEADER_DATA(h)->uid;
    mutt_mktemp (path, sizeof (path));
    cache->path = safe_strdup (path);
    if (!(msg->fp = safe_fopen (path, "w+")))
    {
      FREE (&cache->path);
      return -1;
    }
  }

  /* mark this header as currently inactive so the command handler won't
   * also try to update it. HACK until all this code can be moved into the
   * command handler */
  h->active = 0;

  snprintf (buf, sizeof (buf), "UID FETCH %u %s", HEADER_DATA(h)->uid,
	    (mutt_bit_isset (idata->capabilities, IMAP4REV1) ?
	     (option (OPTIMAPPEEK) ? "BODY.PEEK[]" : "BODY[]") :
	     "RFC822"));

  imap_cmd_start (idata, buf);
  do
  {
    if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE)
      break;

    pc = idata->buf;
    pc = imap_next_word (pc);
    pc = imap_next_word (pc);

    if (!ascii_strncasecmp ("FETCH", pc, 5))
    {
      while (*pc)
      {
	pc = imap_next_word (pc);
	if (pc[0] == '(')
	  pc++;
	if (ascii_strncasecmp ("UID", pc, 3) == 0)
	{
	  pc = imap_next_word (pc);
	  uid = atoi (pc);
	  if (uid != HEADER_DATA(h)->uid)
	    mutt_error (_("The message index is incorrect. Try reopening the mailbox."));
	}
	else if ((ascii_strncasecmp ("RFC822", pc, 6) == 0) ||
		 (ascii_strncasecmp ("BODY[]", pc, 6) == 0))
	{
	  pc = imap_next_word (pc);
	  if (imap_get_literal_count(pc, &bytes) < 0)
	  {
	    imap_error ("imap_fetch_message()", buf);
	    goto bail;
	  }
	  mutt_progress_init (&progressbar, _("Fetching message..."),
			      MUTT_PROGRESS_SIZE, NetInc, bytes);
	  if (imap_read_literal (msg->fp, idata, bytes, &progressbar) < 0)
	    goto bail;
	  /* pick up trailing line */
	  if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE)
	    goto bail;
	  pc = idata->buf;

	  fetched = 1;
	}
	/* UW-IMAP will provide a FLAGS update here if the FETCH causes a
	 * change (eg from \Unseen to \Seen).
	 * Uncommitted changes in mutt take precedence. If we decide to
	 * incrementally update flags later, this won't stop us syncing */
	else if ((ascii_strncasecmp ("FLAGS", pc, 5) == 0) && !h->changed)
	{
	  if ((pc = imap_set_flags (idata, h, pc)) == NULL)
	    goto bail;
	}
      }
    }
  }
  while (rc == IMAP_CMD_CONTINUE);

  /* see comment before command start. */
  h->active = 1;

  fflush (msg->fp);
  if (ferror (msg->fp))
  {
    mutt_perror (cache->path);
    goto bail;
  }

  if (rc != IMAP_CMD_OK)
    goto bail;

  if (!fetched || !imap_code (idata->buf))
    goto bail;

  msg_cache_commit (idata, h);

  parsemsg:
  /* Update the header information.  Previously, we only downloaded a
   * portion of the headers, those required for the main display.
   */
  rewind (msg->fp);
  /* It may be that the Status header indicates a message is read, but the
   * IMAP server doesn't know the message has been \Seen. So we capture
   * the server's notion of 'read' and if it differs from the message info
   * picked up in mutt_read_rfc822_header, we mark the message (and context
   * changed). Another possibility: ignore Status on IMAP?*/
  read = h->read;
  newenv = mutt_read_rfc822_header (msg->fp, h, 0, 0);
  mutt_merge_envelopes(h->env, &newenv);

  /* see above. We want the new status in h->read, so we unset it manually
   * and let mutt_set_flag set it correctly, updating context. */
  if (read != h->read)
  {
    h->read = read;
    mutt_set_flag (ctx, h, MUTT_NEW, read);
  }

  h->lines = 0;
  fgets (buf, sizeof (buf), msg->fp);
  while (!feof (msg->fp))
  {
    h->lines++;
    fgets (buf, sizeof (buf), msg->fp);
  }

  h->content->length = ftell (msg->fp) - h->content->offset;

  /* This needs to be done in case this is a multipart message */
#if defined(HAVE_PGP) || defined(HAVE_SMIME)
  h->security = crypt_query (h->content);
#endif

  mutt_clear_error();
  rewind (msg->fp);
  HEADER_DATA(h)->parsed = 1;

  return 0;

bail:
  safe_fclose (&msg->fp);
  imap_cache_del (idata, h);
  if (cache->path)
  {
    unlink (cache->path);
    FREE (&cache->path);
  }

  return -1;
}
Esempio n. 7
0
/* args:
 *      ctx	Context info, used when recalling a message to which
 *              we reply.
 *	hdr	envelope/attachment info for recalled message
 *	cur	if message was a reply, `cur' is set to the message which
 *		`hdr' is in reply to
 *	fcc	fcc for the recalled message
 *	fcclen	max length of fcc
 *
 * return vals:
 *	-1		error/no messages
 *	0		normal exit
 *	SENDREPLY	recalled message is a reply
 */
int mutt_get_postponed (CONTEXT * ctx, HEADER * hdr, HEADER ** cur, char *fcc,
                        size_t fcclen)
{
  HEADER *h;
  int code = SENDPOSTPONED;
  LIST *tmp;
  LIST *last = NULL;
  LIST *next;
  char *p;
  int opt_delete;

  if (!Postponed)
    return (-1);

  if ((PostContext = mx_open_mailbox (Postponed, M_NOSORT, NULL)) == NULL) {
    PostCount = 0;
    mutt_error _("No postponed messages.");

    return (-1);
  }

  if (!PostContext->msgcount) {
    PostCount = 0;
    mx_close_mailbox (PostContext, NULL);
    mem_free (&PostContext);
    mutt_error _("No postponed messages.");

    return (-1);
  }

  if (PostContext->msgcount == 1) {
    /* only one message, so just use that one. */
    h = PostContext->hdrs[0];
  }
  else if ((h = select_msg ()) == NULL) {
    mx_close_mailbox (PostContext, NULL);
    mem_free (&PostContext);
    return (-1);
  }

  if (mutt_prepare_template (NULL, PostContext, hdr, h, 0) < 0) {
    mx_fastclose_mailbox (PostContext);
    mem_free (&PostContext);
    return (-1);
  }

  /* finished with this message, so delete it. */
  mutt_set_flag (PostContext, h, M_DELETE, 1);

  /* and consider it saved, so that it won't be moved to the trash folder */
  mutt_set_flag (PostContext, h, M_APPENDED, 1);

  /* update the count for the status display */
  PostCount = PostContext->msgcount - PostContext->deleted;

  /* avoid the "purge deleted messages" prompt */
  opt_delete = quadoption (OPT_DELETE);
  set_quadoption (OPT_DELETE, M_YES);
  mx_close_mailbox (PostContext, NULL);
  set_quadoption (OPT_DELETE, opt_delete);

  mem_free (&PostContext);

  for (tmp = hdr->env->userhdrs; tmp;) {
    if (ascii_strncasecmp ("X-Mutt-References:", tmp->data, 18) == 0) {
      if (ctx) {
        /* if a mailbox is currently open, look to see if the orignal message
           the user attempted to reply to is in this mailbox */
        p = tmp->data + 18;
        SKIPWS (p);
        if (!ctx->id_hash)
          ctx->id_hash = mutt_make_id_hash (ctx);
        *cur = hash_find (ctx->id_hash, p);
      }

      /* Remove the X-Mutt-References: header field. */
      next = tmp->next;
      if (last)
        last->next = tmp->next;
      else
        hdr->env->userhdrs = tmp->next;
      tmp->next = NULL;
      mutt_free_list (&tmp);
      tmp = next;
      if (*cur)
        code |= SENDREPLY;
    }
    else if (ascii_strncasecmp ("X-Mutt-Fcc:", tmp->data, 11) == 0) {
      p = tmp->data + 11;
      SKIPWS (p);
      strfcpy (fcc, p, fcclen);
      mutt_pretty_mailbox (fcc);

      /* remove the X-Mutt-Fcc: header field */
      next = tmp->next;
      if (last)
        last->next = tmp->next;
      else
        hdr->env->userhdrs = tmp->next;
      tmp->next = NULL;
      mutt_free_list (&tmp);
      tmp = next;
    }
    else if ((WithCrypto & APPLICATION_PGP)
             && (str_ncmp ("Pgp:", tmp->data, 4) == 0       /* this is generated
                                                                 * by old mutt versions
                                                                 */
                 || str_ncmp ("X-Mutt-PGP:", tmp->data, 11) == 0)) {
      hdr->security = mutt_parse_crypt_hdr (strchr (tmp->data, ':') + 1, 1);
      hdr->security |= APPLICATION_PGP;

      /* remove the pgp field */
      next = tmp->next;
      if (last)
        last->next = tmp->next;
      else
        hdr->env->userhdrs = tmp->next;
      tmp->next = NULL;
      mutt_free_list (&tmp);
      tmp = next;
    }
    else if ((WithCrypto & APPLICATION_SMIME)
             && str_ncmp ("X-Mutt-SMIME:", tmp->data, 13) == 0) {
      hdr->security = mutt_parse_crypt_hdr (strchr (tmp->data, ':') + 1, 1);
      hdr->security |= APPLICATION_SMIME;

      /* remove the smime field */
      next = tmp->next;
      if (last)
        last->next = tmp->next;
      else
        hdr->env->userhdrs = tmp->next;
      tmp->next = NULL;
      mutt_free_list (&tmp);
      tmp = next;
    }

#ifdef MIXMASTER
    else if (str_ncmp ("X-Mutt-Mix:", tmp->data, 11) == 0) {
      char *t;

      mutt_free_list (&hdr->chain);

      t = strtok (tmp->data + 11, " \t\n");
      while (t) {
        hdr->chain = mutt_add_list (hdr->chain, t);
        t = strtok (NULL, " \t\n");
      }

      next = tmp->next;
      if (last)
        last->next = tmp->next;
      else
        hdr->env->userhdrs = tmp->next;
      tmp->next = NULL;
      mutt_free_list (&tmp);
      tmp = next;
    }
#endif

    else {
      last = tmp;
      tmp = tmp->next;
    }
  }
  return (code);
}
Esempio n. 8
0
int
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;
  int fcc_error = 0;
  int free_clear_content = 0;

  BODY *save_content = NULL;
  BODY *clear_content = NULL;
  char *pgpkeylist = NULL;
  /* save current value of "pgp_sign_as" */
  char *signas = NULL;
  char *tag = NULL, *err = NULL;
  char *ctype;

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

    if(i == M_YES)
      flags |= SENDPOSTPONED;
  }
  
  
  if ((WithCrypto & APPLICATION_PGP) && (flags & SENDPOSTPONED))
    signas = safe_strdup(PgpSignAs);

  /* Delay expansion of aliases until absolutely necessary--shouldn't
   * be necessary unless we are prompting the user or about to execute a
   * send-hook.
   */

  if (!msg)
  {
    msg = mutt_new_header ();

    if (flags == SENDPOSTPONED)
    {
      if ((flags = mutt_get_postponed (ctx, msg, &cur, fcc, sizeof (fcc))) < 0)
	goto cleanup;
    }

    if (flags & (SENDPOSTPONED|SENDRESEND))
    {
      if ((tempfp = safe_fopen (msg->content->filename, "a+")) == NULL)
      {
	mutt_perror (msg->content->filename);
	goto cleanup;
      }
    }

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

  /* Parse and use an eventual list-post header */
  if ((flags & SENDLISTREPLY) 
      && cur && cur->env && cur->env->list_post) 
  {
    /* Use any list-post header as a template */
    url_parse_mailto (msg->env, NULL, cur->env->list_post);
    /* We don't let them set the sender's address. */
    rfc822_free_address (&msg->env->from);
  }
  
  if (! (flags & (SENDKEY | SENDPOSTPONED | SENDRESEND)))
  {
    pbody = mutt_new_body ();
    pbody->next = msg->content; /* don't kill command-line attachments */
    msg->content = pbody;

    if (!(ctype = safe_strdup (ContentType)))
      ctype = safe_strdup ("text/plain");
    mutt_parse_content_type (ctype, msg->content);
    FREE (&ctype);
    msg->content->unlink = 1;
    msg->content->use_disp = 0;
    msg->content->disposition = DISPINLINE;
    
    if (!tempfile)
    {
      mutt_mktemp (buffer, sizeof (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)
    {
      dprint(1,(debugfile, "newsend_message: can't create tempfile %s (errno=%d)\n", msg->content->filename, errno));
      mutt_perror (msg->content->filename);
      goto cleanup;
    }
  }

  /* this is handled here so that the user can match ~f in send-hook */
  if (cur && option (OPTREVNAME) && !(flags & (SENDPOSTPONED|SENDRESEND)))
  {
    /* we shouldn't have to worry about freeing `msg->env->from' before
     * 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.
     *
     * We shouldn't have to worry about alias expansion here since we are
     * either replying to a real or postponed message, therefore no aliases
     * should exist since the user has not had the opportunity to add
     * addresses to the list.  We just have to ensure the postponed messages
     * have their aliases expanded.
     */

    msg->env->from = set_reverse_name (cur->env);
  }

  if (! (flags & (SENDPOSTPONED|SENDRESEND)))
  {
    if ((flags & (SENDREPLY | SENDFORWARD)) && ctx &&
	envelope_defaults (msg->env, ctx, cur, flags) == -1)
      goto cleanup;

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

    /* Expand aliases and remove duplicates/crossrefs */
    mutt_expand_aliases_env (msg->env);
    
    if (flags & SENDREPLY)
      mutt_fix_reply_recipients (msg->env);

    if (! (flags & (SENDMAILX|SENDBATCH)) &&
	! (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
     * $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 */

    if (!msg->env->from)
    {
      msg->env->from = mutt_default_from ();
      killfrom = 1;
    }

    if ((flags & SENDREPLY) && cur)
    {
      /* change setting based upon message we are replying to */
      mutt_message_hook (ctx, cur, M_REPLYHOOK);

      /*
       * set the replied flag for the message we are generating so that the
       * user can use ~Q in a send-hook to know when reply-hook's are also
       * being used.
       */
      msg->replied = 1;
    }

    /* change settings based upon recipients */
    
    mutt_message_hook (NULL, msg, M_SENDHOOK);

    /*
     * Unset the replied flag from the message we are composing since it is
     * no longer required.  This is done here because the FCC'd copy of
     * this message was erroneously get the 'R'eplied flag when stored in
     * a maildir-style mailbox.
     */
    msg->replied = 0;

    if (! (flags & SENDKEY))
    {
      if (option (OPTTEXTFLOWED) && msg->content->type == TYPETEXT && !ascii_strcasecmp (msg->content->subtype, "plain"))
        mutt_set_parameter ("format", "flowed", &msg->content->parameter);
    }

    /* $use_from and/or $from might have changed in a send-hook */
    if (killfrom)
    {
      rfc822_free_address (&msg->env->from);
      if (option (OPTUSEFROM) && !(flags & (SENDPOSTPONED|SENDRESEND)))
	msg->env->from = mutt_default_from ();
      killfrom = 0;
    }

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

    if (flags & SENDBATCH)
       mutt_copy_stream (stdin, tempfp);

    if (option (OPTSIGONTOP) && ! (flags & (SENDMAILX|SENDKEY|SENDBATCH))
	&& Editor && mutt_strcmp (Editor, "builtin") != 0)
      append_signature (tempfp);

    /* 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;

    if (!option (OPTSIGONTOP) && ! (flags & (SENDMAILX|SENDKEY|SENDBATCH))
	&& Editor && mutt_strcmp (Editor, "builtin") != 0)
      append_signature (tempfp);
  }
  
  /* 
   * This hook is even called for postponed messages, and can, e.g., be
   * used for setting the editor, the sendmail path, or the
   * envelope sender.
   */
  mutt_message_hook (NULL, msg, M_SEND2HOOK);

  /* wait until now to set the real name portion of our return address so
     that $realname can be set in a send-hook */
  if (msg->env->from && !msg->env->from->personal
      && !(flags & (SENDRESEND|SENDPOSTPONED)))
    msg->env->from->personal = safe_strdup (Realname);

  if (!((WithCrypto & APPLICATION_PGP) && (flags & SENDKEY)))
    safe_fclose (&tempfp);

  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 = mutt_decrease_mtime (msg->content->filename, NULL);

    mutt_update_encoding (msg->content);

    /*
     * Select whether or not the user's editor should be called now.  We
     * don't want to do this when:
     * 1) we are sending a key/cert
     * 2) we are forwarding a message and the user doesn't want to edit it.
     *    This is controlled by the quadoption $forward_edit.  However, if
     *    both $edit_headers and $autoedit are set, we want to ignore the
     *    setting of $forward_edit because the user probably needs to add the
     *    recipients.
     */
    if (! (flags & SENDKEY) &&
	((flags & SENDFORWARD) == 0 ||
	 (option (OPTEDITHDRS) && option (OPTAUTOEDIT)) ||
	 query_quadoption (OPT_FORWEDIT, _("Edit forwarded message?")) == M_YES))
    {
      /* If the this isn't a text message, look for a mailcap edit command */
      if (mutt_needs_mailcap (msg->content))
      {
	if (!mutt_edit_attachment (msg->content))
          goto cleanup;
      }
      else if (!Editor || mutt_strcmp ("builtin", Editor) == 0)
	mutt_builtin_editor (msg->content->filename, msg, cur);
      else if (option (OPTEDITHDRS))
      {
	mutt_env_to_local (msg->env);
	mutt_edit_headers (Editor, msg->content->filename, msg, fcc, sizeof (fcc));
	mutt_env_to_idna (msg->env, NULL, NULL);
      }
      else
      {
	mutt_edit_file (Editor, msg->content->filename);
	if (stat (msg->content->filename, &st) == 0)
	{
	  if (mtime != st.st_mtime)
	    fix_end_of_file (msg->content->filename);
	}
	else
	  mutt_perror (msg->content->filename);
      }
      
      /* If using format=flowed, perform space stuffing.  Avoid stuffing when
       * recalling a postponed message where the stuffing was already
       * performed.  If it has already been performed, the format=flowed
       * parameter will be present.
       */
      if (option (OPTTEXTFLOWED) && msg->content->type == TYPETEXT && !ascii_strcasecmp("plain", msg->content->subtype))
      {
	char *p = mutt_get_parameter("format", msg->content->parameter);
	if (ascii_strcasecmp("flowed", NONULL(p)))
	  rfc3676_space_stuff (msg);
      }

      mutt_message_hook (NULL, msg, M_SEND2HOOK);
    }

    if (! (flags & (SENDPOSTPONED | SENDFORWARD | SENDKEY | SENDRESEND)))
    {
      if (stat (msg->content->filename, &st) == 0)
      {
	/* if the file was not modified, bail out now */
	if (mtime == st.st_mtime && !msg->content->next &&
	    query_quadoption (OPT_ABORT, _("Abort unmodified message?")) == M_YES)
	{
	  mutt_message _("Aborted unmodified message.");
	  goto cleanup;
	}
      }
      else
	mutt_perror (msg->content->filename);
    }
  }

  /* 
   * Set the message security unless:
   * 1) crypto support is not enabled (WithCrypto==0)
   * 2) pgp: header field was present during message editing with $edit_headers (msg->security != 0)
   * 3) we are resending a message
   * 4) we are recalling a postponed message (don't override the user's saved settings)
   * 5) we are in mailx mode
   * 6) we are in batch mode
   *
   * This is done after allowing the user to edit the message so that security
   * settings can be configured with send2-hook and $edit_headers.
   */
  if (WithCrypto && (msg->security == 0) && !(flags & (SENDBATCH | SENDMAILX | SENDPOSTPONED | SENDRESEND)))
  {
    if (option (OPTCRYPTAUTOSIGN))
      msg->security |= SIGN;
    if (option (OPTCRYPTAUTOENCRYPT))
      msg->security |= ENCRYPT;
    if (option (OPTCRYPTREPLYENCRYPT) && cur && (cur->security & ENCRYPT))
      msg->security |= ENCRYPT;
    if (option (OPTCRYPTREPLYSIGN) && cur && (cur->security & SIGN))
      msg->security |= SIGN;
    if (option (OPTCRYPTREPLYSIGNENCRYPTED) && cur && (cur->security & ENCRYPT))
      msg->security |= SIGN;
    if (WithCrypto & APPLICATION_PGP && (msg->security & (ENCRYPT | SIGN)))
    {
      if (option (OPTPGPAUTOINLINE))
	msg->security |= INLINE;
      if (option (OPTPGPREPLYINLINE) && cur && (cur->security & INLINE))
	msg->security |= INLINE;
    }

    if (msg->security)
    {
      /* 
       * When replying / forwarding, use the original message's
       * crypto system.  According to the documentation,
       * smime_is_default should be disregarded here.
       * 
       * Problem: At least with forwarding, this doesn't really
       * make much sense. Should we have an option to completely
       * disable individual mechanisms at run-time?
       */
      if (cur)
      {
	if ((WithCrypto & APPLICATION_PGP) && option (OPTCRYPTAUTOPGP) 
	    && (cur->security & APPLICATION_PGP))
	  msg->security |= APPLICATION_PGP;
	else if ((WithCrypto & APPLICATION_SMIME) && option (OPTCRYPTAUTOSMIME)
	    && (cur->security & APPLICATION_SMIME))
	  msg->security |= APPLICATION_SMIME;
      }

      /*
       * No crypto mechanism selected? Use availability + smime_is_default
       * for the decision. 
       */
      if (!(msg->security & (APPLICATION_SMIME | APPLICATION_PGP)))
      {
	if ((WithCrypto & APPLICATION_SMIME) && option (OPTCRYPTAUTOSMIME) 
	    && option (OPTSMIMEISDEFAULT))
	  msg->security |= APPLICATION_SMIME;
	else if ((WithCrypto & APPLICATION_PGP) && option (OPTCRYPTAUTOPGP))
	  msg->security |= APPLICATION_PGP;
	else if ((WithCrypto & APPLICATION_SMIME) && option (OPTCRYPTAUTOSMIME))
	  msg->security |= APPLICATION_SMIME;
      }
    }

    /* No permissible mechanisms found.  Don't sign or encrypt. */
    if (!(msg->security & (APPLICATION_SMIME|APPLICATION_PGP)))
      msg->security = 0;
  }

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

  if (!fcc[0] && !(flags & (SENDPOSTPONED)) && (!(flags & SENDBATCH) || (quadoption (OPT_COPY) & 0x1)))
  {
    /* 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;
    }
  }

  
  mutt_update_encoding (msg->content);

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

    fcc_error = 0; /* reset value since we may have failed before */
    mutt_pretty_mailbox (fcc, sizeof (fcc));
    i = mutt_compose_menu (msg, fcc, sizeof (fcc), cur);
    if (i == -1)
    {
      /* abort */
      mutt_message _("Mail not sent.");
      goto cleanup;
    }
    else if (i == 1)
    {
      /* postpone the message until later. */
      if (msg->content->next)
	msg->content = mutt_make_multipart (msg->content);

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

      encode_descriptions (msg->content, 1);
      mutt_prepare_envelope (msg->env, 0);
      mutt_env_to_idna (msg->env, NULL, NULL);	/* Handle bad IDNAs the next time. */

      if (!Postponed || mutt_write_fcc (NONULL (Postponed), msg, (cur && (flags & SENDREPLY)) ? cur->env->message_id : NULL, 1, fcc) < 0)
      {
	msg->content = mutt_remove_multipart (msg->content);
	decode_descriptions (msg->content);
	mutt_unprepare_envelope (msg->env);
	goto main_loop;
      }
      mutt_update_num_postponed ();
      mutt_message _("Message postponed.");
      goto cleanup;
    }
  }

  if (!has_recips (msg->env->to) && !has_recips (msg->env->cc) &&
      !has_recips (msg->env->bcc))
  {
    if (! (flags & SENDBATCH))
    {
      mutt_error _("No recipients are specified!");
      goto main_loop;
    }
    else
    {
      puts _("No recipients were specified.");
      goto cleanup;
    }
  }

  if (mutt_env_to_idna (msg->env, &tag, &err))
  {
    mutt_error (_("Bad IDN in \"%s\": '%s'"), tag, err);
    FREE (&err);
    if (!(flags & SENDBATCH))
      goto main_loop;
    else 
      goto cleanup;
  }
  
  if (!msg->env->subject && ! (flags & SENDBATCH) &&
      (i = query_quadoption (OPT_SUBJECT, _("No subject, abort sending?"))) != M_NO)
  {
    /* if the abort is automatic, print an error message */
    if (quadoption (OPT_SUBJECT) == M_YES)
      mutt_error _("No subject specified.");
    goto main_loop;
  }

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

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

  encode_descriptions (msg->content, 1);
  
  /*
   * Make sure that clear_content and free_clear_content are
   * properly initialized -- we may visit this particular place in
   * the code multiple times, including after a failed call to
   * mutt_protect().
   */
  
  clear_content = NULL;
  free_clear_content = 0;
  
  if (WithCrypto)
  {
    if (msg->security)  
    {
      /* save the decrypted attachments */
      clear_content = msg->content;
  
      if ((crypt_get_keys (msg, &pgpkeylist) == -1) ||
          mutt_protect (msg, pgpkeylist) == -1)
      {
        msg->content = mutt_remove_multipart (msg->content);
        
	FREE (&pgpkeylist);
        
        decode_descriptions (msg->content);
        goto main_loop;
      }
      encode_descriptions (msg->content, 0);
    }
  
    /* 
     * 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.
     */
  
    /* This is ugly -- lack of "reporting back" from mutt_protect(). */
    
    if (clear_content && (msg->content != clear_content)
        && (msg->content->parts != clear_content))
      free_clear_content = 1;
  }

  if (!option (OPTNOCURSES) && !(flags & SENDMAILX))
    mutt_message _("Sending message...");

  mutt_prepare_envelope (msg->env, 1);

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

  mutt_expand_path (fcc, sizeof (fcc));

  
  /* 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

  if (*fcc && mutt_strcmp ("/dev/null", fcc) != 0)
  {
    BODY *tmpbody = msg->content;
    BODY *save_sig = NULL;
    BODY *save_parts = NULL;

    if (WithCrypto && msg->security && option (OPTFCCCLEAR))
      msg->content = clear_content;

    /* check to see if the user wants copies of all attachments */
    if (query_quadoption (OPT_FCCATTACH, _("Save attachments in Fcc?")) != M_YES &&
	msg->content->type == TYPEMULTIPART)
    {
      if (WithCrypto
          && (mutt_strcmp (msg->content->subtype, "encrypted") == 0 ||
              mutt_strcmp (msg->content->subtype, "signed") == 0))
      {
	if (clear_content->type == TYPEMULTIPART)
	{
	  if(!(msg->security & ENCRYPT) && (msg->security & SIGN))
	  {
	    /* save initial signature and attachments */
	    save_sig = msg->content->parts->next;
	    save_parts = clear_content->parts->next;
	  }

	  /* this means writing only the main part */
	  msg->content = clear_content->parts;

	  if (mutt_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;
	  }

	  save_content = msg->content;
	}
      }
      else
	msg->content = msg->content->parts;
    }

full_fcc:
    if (msg->content)
    {
      /* update received time so that when storing to a mbox-style folder
       * the From_ line contains the current time instead of when the
       * message was first postponed.
       */
      msg->received = time (NULL);
      if (mutt_write_fcc (fcc, msg, NULL, 0, NULL) == -1)
      {
	/*
	 * Error writing FCC, we should abort sending.
	 */
	fcc_error = 1;
      }
    }

    msg->content = tmpbody;

    if (WithCrypto && save_sig)
    {
      /* cleanup the second signature structures */
      if (save_content->parts)
      {
	mutt_free_body (&save_content->parts->next);
	save_content->parts = NULL;
      }
      mutt_free_body (&save_content);

      /* restore old signature and attachments */
      msg->content->parts->next = save_sig;
      msg->content->parts->parts->next = save_parts;
    }
    else if (WithCrypto && save_content)
    {
      /* destroy the new encrypted body. */
      mutt_free_body (&save_content);
    }

  }


  /*
   * Don't attempt to send the message if the FCC failed.  Just pretend
   * the send failed as well so we give the user a chance to fix the
   * error.
   */
  if (fcc_error || (i = send_message (msg)) < 0)
  {
    if (!(flags & SENDBATCH))
    {
      if (!WithCrypto)
        ;
      else if ((msg->security & ENCRYPT) || 
               ((msg->security & SIGN)
                && msg->content->type == TYPEAPPLICATION))
      {
	mutt_free_body (&msg->content); /* destroy PGP data */
	msg->content = clear_content;	/* restore clear text. */
      }
      else if ((msg->security & SIGN) && msg->content->type == TYPEMULTIPART)
      {
	mutt_free_body (&msg->content->parts->next);	     /* destroy sig */
	msg->content = mutt_remove_multipart (msg->content); 
      }

      msg->content = mutt_remove_multipart (msg->content);
      decode_descriptions (msg->content);
      mutt_unprepare_envelope (msg->env);
      goto main_loop;
    }
    else
    {
      puts _("Could not send the message.");
      goto cleanup;
    }
  }
  else if (!option (OPTNOCURSES) && ! (flags & SENDMAILX))
    mutt_message (i == 0 ? _("Mail sent.") : _("Sending in background."));

  if (WithCrypto && (msg->security & ENCRYPT))
    FREE (&pgpkeylist);
  
  if (WithCrypto && free_clear_content)
    mutt_free_body (&clear_content);

  /* set 'replied' flag only if the user didn't change/remove
     In-Reply-To: and References: headers during edit */
  if (flags & SENDREPLY)
  {
    if (cur && ctx)
      mutt_set_flag (ctx, cur, M_REPLIED, is_reply (cur, msg));
    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,
			 is_reply (ctx->hdrs[ctx->v2r[i]], msg));
    }
  }


  rv = 0;
  
cleanup:

  if ((WithCrypto & APPLICATION_PGP) && (flags & SENDPOSTPONED))
  {
    if(signas)
    {
      FREE (&PgpSignAs);
      PgpSignAs = signas;
    }
  }
   
  safe_fclose (&tempfp);
  mutt_free_header (&msg);
  
  return rv;
}
Esempio n. 9
0
int mutt_display_message (HEADER *cur)
{
  char tempfile[_POSIX_PATH_MAX], buf[LONG_STRING];
  int rc = 0, builtin = 0;
  int cmflags = M_CM_DECODE | M_CM_DISPLAY | M_CM_CHARCONV;
  FILE *fpout = NULL;
  FILE *fpfilterout = NULL;
  pid_t filterpid = -1;
  int res;

  snprintf (buf, sizeof (buf), "%s/%s", TYPE (cur->content),
	    cur->content->subtype);

  mutt_parse_mime_message (Context, cur);
  mutt_message_hook (Context, cur, M_MESSAGEHOOK);

  /* see if crypto is needed for this message.  if so, we should exit curses */
  if (WithCrypto && cur->security)
  {
    if (cur->security & ENCRYPT)
    {
      if (cur->security & APPLICATION_SMIME)
	crypt_smime_getkeys (cur->env);
      if(!crypt_valid_passphrase(cur->security))
	return 0;

      cmflags |= M_CM_VERIFY;
    }
    else if (cur->security & SIGN)
    {
      /* find out whether or not the verify signature */
      if (query_quadoption (OPT_VERIFYSIG, _("Verify PGP signature?")) == M_YES)
      {
	cmflags |= M_CM_VERIFY;
      }
    }
  }
  
  if (cmflags & M_CM_VERIFY || cur->security & ENCRYPT)
  {
    if (cur->security & APPLICATION_PGP)
    {
      if (cur->env->from)
        crypt_pgp_invoke_getkeys (cur->env->from);
      
      crypt_invoke_message (APPLICATION_PGP);
    }

    if (cur->security & APPLICATION_SMIME)
      crypt_invoke_message (APPLICATION_SMIME);
  }


  mutt_mktemp (tempfile, sizeof (tempfile));
  if ((fpout = safe_fopen (tempfile, "w")) == NULL)
  {
    mutt_error _("Could not create temporary file!");
    return (0);
  }

  if (DisplayFilter && *DisplayFilter) 
  {
    fpfilterout = fpout;
    fpout = NULL;
    /* mutt_endwin (NULL); */
    filterpid = mutt_create_filter_fd (DisplayFilter, &fpout, NULL, NULL,
				       -1, fileno(fpfilterout), -1);
    if (filterpid < 0)
    {
      mutt_error (_("Cannot create display filter"));
      safe_fclose (&fpfilterout);
      unlink (tempfile);
      return 0;
    }
  }

  if (!Pager || mutt_strcmp (Pager, "builtin") == 0)
    builtin = 1;
  else
  {
    struct hdr_format_info hfi;
    hfi.ctx = Context;
    hfi.pager_progress = ExtPagerProgress;
    hfi.hdr = cur;
    mutt_make_string_info (buf, sizeof (buf), NONULL(PagerFmt), &hfi, M_FORMAT_MAKEPRINT);
    fputs (buf, fpout);
    fputs ("\n\n", fpout);
  }

  res = mutt_copy_message (fpout, Context, cur, cmflags,
       	(option (OPTWEED) ? (CH_WEED | CH_REORDER) : 0) | CH_DECODE | CH_FROM | CH_DISPLAY);
  if ((safe_fclose (&fpout) != 0 && errno != EPIPE) || res < 0)
  {
    mutt_error (_("Could not copy message"));
    if (fpfilterout != NULL)
    {
      mutt_wait_filter (filterpid);
      safe_fclose (&fpfilterout);
    }
    mutt_unlink (tempfile);
    return 0;
  }

  if (fpfilterout != NULL && mutt_wait_filter (filterpid) != 0)
    mutt_any_key_to_continue (NULL);

  safe_fclose (&fpfilterout);	/* XXX - check result? */

  
  if (WithCrypto)
  {
    /* update crypto information for this message */
    cur->security &= ~(GOODSIGN|BADSIGN);
    cur->security |= crypt_query (cur->content);
  
    /* Remove color cache for this message, in case there
       are color patterns for both ~g and ~V */
    cur->pair = 0;
  }

  if (builtin)
  {
    pager_t info;

    if (WithCrypto 
        && (cur->security & APPLICATION_SMIME) && (cmflags & M_CM_VERIFY))
    {
      if (cur->security & GOODSIGN)
      {
	if (!crypt_smime_verify_sender(cur))
	  mutt_message ( _("S/MIME signature successfully verified."));
	else
	  mutt_error ( _("S/MIME certificate owner does not match sender."));
      }
      else if (cur->security & PARTSIGN)
	mutt_message (_("Warning: Part of this message has not been signed."));
      else if (cur->security & SIGN || cur->security & BADSIGN)
	mutt_error ( _("S/MIME signature could NOT be verified."));
    }

    if (WithCrypto 
        && (cur->security & APPLICATION_PGP) && (cmflags & M_CM_VERIFY))
    {
      if (cur->security & GOODSIGN)
	mutt_message (_("PGP signature successfully verified."));
      else if (cur->security & PARTSIGN)
	mutt_message (_("Warning: Part of this message has not been signed."));
      else if (cur->security & SIGN)
	mutt_message (_("PGP signature could NOT be verified."));
    }

    /* Invoke the builtin pager */
    memset (&info, 0, sizeof (pager_t));
    info.hdr = cur;
    info.ctx = Context;
    rc = mutt_pager (NULL, tempfile, M_PAGER_MESSAGE, &info);
  }
  else
  {
    int r;

    mutt_endwin (NULL);
    snprintf (buf, sizeof (buf), "%s %s", NONULL(Pager), tempfile);
    if ((r = mutt_system (buf)) == -1)
      mutt_error (_("Error running \"%s\"!"), buf);
    unlink (tempfile);
    if (!option (OPTNOCURSES))
      keypad (stdscr, TRUE);
    if (r != -1)
      mutt_set_flag (Context, cur, M_READ, 1);
    if (r != -1 && option (OPTPROMPTAFTER))
    {
      mutt_unget_event (mutt_any_key_to_continue _("Command: "), 0);
      rc = km_dokey (MENU_PAGER);
    }
    else
      rc = 0;
  }

  return rc;
}
Esempio n. 10
0
File: mbox.c Progetto: kdave/neomutt
/**
 * reopen_mailbox - Close and reopen a mailbox
 * @param m          Mailbox
 * @param index_hint Current email
 * @retval >0 Success, e.g. #MUTT_REOPENED, #MUTT_NEW_MAIL
 * @retval -1 Error
 */
static int reopen_mailbox(struct Mailbox *m, int *index_hint)
{
  if (!m)
    return -1;

  struct MboxAccountData *adata = mbox_adata_get(m);
  if (!adata)
    return -1;

  bool (*cmp_headers)(const struct Email *, const struct Email *) = NULL;
  struct Email **old_hdrs = NULL;
  int old_msg_count;
  bool msg_mod = false;
  int rc = -1;

  /* silent operations */
  m->quiet = true;

  if (!m->quiet)
    mutt_message(_("Reopening mailbox..."));

  /* our heuristics require the old mailbox to be unsorted */
  if (C_Sort != SORT_ORDER)
  {
    short old_sort = C_Sort;
    C_Sort = SORT_ORDER;
    mutt_mailbox_changed(m, MBN_RESORT);
    C_Sort = old_sort;
  }

  old_hdrs = NULL;
  old_msg_count = 0;

  /* simulate a close */
  mutt_mailbox_changed(m, MBN_CLOSED);
  mutt_hash_free(&m->id_hash);
  mutt_hash_free(&m->subj_hash);
  mutt_hash_free(&m->label_hash);
  FREE(&m->v2r);
  if (m->readonly)
  {
    for (int i = 0; i < m->msg_count; i++)
      mutt_email_free(&(m->emails[i])); /* nothing to do! */
    FREE(&m->emails);
  }
  else
  {
    /* save the old headers */
    old_msg_count = m->msg_count;
    old_hdrs = m->emails;
    m->emails = NULL;
  }

  m->email_max = 0; /* force allocation of new headers */
  m->msg_count = 0;
  m->vcount = 0;
  m->msg_tagged = 0;
  m->msg_deleted = 0;
  m->msg_new = 0;
  m->msg_unread = 0;
  m->msg_flagged = 0;
  m->changed = false;
  m->id_hash = NULL;
  m->subj_hash = NULL;
  mutt_make_label_hash(m);

  switch (m->magic)
  {
    case MUTT_MBOX:
    case MUTT_MMDF:
      cmp_headers = mutt_email_cmp_strict;
      mutt_file_fclose(&adata->fp);
      adata->fp = mutt_file_fopen(m->path, "r");
      if (!adata->fp)
        rc = -1;
      else if (m->magic == MUTT_MBOX)
        rc = mbox_parse_mailbox(m);
      else
        rc = mmdf_parse_mailbox(m);
      break;

    default:
      rc = -1;
      break;
  }

  if (rc == -1)
  {
    /* free the old headers */
    for (int i = 0; i < old_msg_count; i++)
      mutt_email_free(&(old_hdrs[i]));
    FREE(&old_hdrs);

    m->quiet = false;
    return -1;
  }

  mutt_file_touch_atime(fileno(adata->fp));

  /* now try to recover the old flags */

  if (!m->readonly)
  {
    for (int i = 0; i < m->msg_count; i++)
    {
      bool found = false;

      /* some messages have been deleted, and new  messages have been
       * appended at the end; the heuristic is that old messages have then
       * "advanced" towards the beginning of the folder, so we begin the
       * search at index "i" */
      int j;
      for (j = i; j < old_msg_count; j++)
      {
        if (!old_hdrs[j])
          continue;
        if (cmp_headers(m->emails[i], old_hdrs[j]))
        {
          found = true;
          break;
        }
      }
      if (!found)
      {
        for (j = 0; (j < i) && (j < old_msg_count); j++)
        {
          if (!old_hdrs[j])
            continue;
          if (cmp_headers(m->emails[i], old_hdrs[j]))
          {
            found = true;
            break;
          }
        }
      }

      if (found)
      {
        /* this is best done here */
        if (index_hint && (*index_hint == j))
          *index_hint = i;

        if (old_hdrs[j]->changed)
        {
          /* Only update the flags if the old header was changed;
           * otherwise, the header may have been modified externally,
           * and we don't want to lose _those_ changes */
          mutt_set_flag(m, m->emails[i], MUTT_FLAG, old_hdrs[j]->flagged);
          mutt_set_flag(m, m->emails[i], MUTT_REPLIED, old_hdrs[j]->replied);
          mutt_set_flag(m, m->emails[i], MUTT_OLD, old_hdrs[j]->old);
          mutt_set_flag(m, m->emails[i], MUTT_READ, old_hdrs[j]->read);
        }
        mutt_set_flag(m, m->emails[i], MUTT_DELETE, old_hdrs[j]->deleted);
        mutt_set_flag(m, m->emails[i], MUTT_PURGE, old_hdrs[j]->purge);
        mutt_set_flag(m, m->emails[i], MUTT_TAG, old_hdrs[j]->tagged);

        /* we don't need this header any more */
        mutt_email_free(&(old_hdrs[j]));
      }
    }

    /* free the remaining old headers */
    for (int j = 0; j < old_msg_count; j++)
    {
      if (old_hdrs[j])
      {
        mutt_email_free(&(old_hdrs[j]));
        msg_mod = true;
      }
    }
    FREE(&old_hdrs);
  }

  m->quiet = false;

  return (m->changed || msg_mod) ? MUTT_REOPENED : MUTT_NEW_MAIL;
}
Esempio n. 11
0
int mutt_reopen_mailbox(CONTEXT *ctx, int *index_hint)
{
    int (*cmp_headers) (const HEADER *,
                        const HEADER *) = NULL;
    HEADER **old_hdrs;
    int old_msgcount;
    int msg_mod = 0;
    int index_hint_set;
    int i, j;
    int rc = -1;

    /* silent operations */
    ctx->quiet = 1;

    if (!ctx->quiet)
        mutt_message _("Reopening mailbox...");

    /* our heuristics require the old mailbox to be unsorted */
    if (Sort != SORT_ORDER) {
        short old_sort;

        old_sort = Sort;
        Sort = SORT_ORDER;
        mutt_sort_headers(ctx, 1);
        Sort = old_sort;
    }

    old_hdrs = NULL;
    old_msgcount = 0;

    /* simulate a close */
    if (ctx->id_hash)
        hash_destroy(&ctx->id_hash, NULL);

    if (ctx->subj_hash)
        hash_destroy(&ctx->subj_hash, NULL);
    mutt_clear_threads(ctx);
    safe_free(&ctx->v2r);

    if (ctx->readonly) {
        for (i = 0; i < ctx->msgcount; i++)
            mutt_free_header(&(ctx->hdrs[i]));  /* nothing to do! */
        safe_free(&ctx->hdrs);
    } else {
        /* save the old headers */
        old_msgcount = ctx->msgcount;
        old_hdrs = ctx->hdrs;
        ctx->hdrs = NULL;
    }

    ctx->hdrmax = 0; /* force allocation of new headers */
    ctx->msgcount = 0;
    ctx->vcount = 0;
    ctx->tagged = 0;
    ctx->deleted = 0;
    ctx->new_messages = 0;
    ctx->unread = 0;
    ctx->flagged = 0;
    ctx->changed = 0;
    ctx->id_hash = NULL;
    ctx->subj_hash = NULL;

    switch (ctx->magic) {
    case M_MBOX:
    case M_MMDF:
        cmp_headers = mbox_strict_cmp_headers;
        safe_fclose(&ctx->fp);

        if (!(ctx->fp = safe_fopen(ctx->path, "r")))
            rc = -1;
        else
            rc = ((ctx->magic == M_MBOX) ? mbox_parse_mailbox
                  : mmdf_parse_mailbox)(ctx);
        break;

    default:
        rc = -1;
        break;
    }

    if (rc == -1) {
        /* free the old headers */
        for (j = 0; j < old_msgcount; j++)
            mutt_free_header(&(old_hdrs[j]));
        safe_free(&old_hdrs);

        ctx->quiet = 0;
        return -1;
    }

    /* now try to recover the old flags */

    index_hint_set = (index_hint == NULL);

    if (!ctx->readonly) {
        for (i = 0; i < ctx->msgcount; i++) {
            int found = 0;

            /* some messages have been deleted, and new  messages have been
             * appended at the end; the heuristic is that old messages have then
             * "advanced" towards the beginning of the folder, so we begin the
             * search at index "i"
             */
            for (j = i; j < old_msgcount; j++) {
                if (old_hdrs[j] == NULL)
                    continue;

                if (cmp_headers(ctx->hdrs[i], old_hdrs[j])) {
                    found = 1;
                    break;
                }
            }

            if (!found) {
                for (j = 0; j < i
                     && j < old_msgcount; j++) {
                    if (old_hdrs[j] == NULL)
                        continue;

                    if (cmp_headers(ctx->hdrs[i], old_hdrs[j])) {
                        found = 1;
                        break;
                    }
                }
            }

            if (found) {
                /* this is best done here */
                if (!index_hint_set
                    && (*index_hint == j))
                    *index_hint = i;

                if (old_hdrs[j]->changed) {
                    /* Only update the flags if the old header was changed;
                     * otherwise, the header may have been modified externally,
                     * and we don't want to lose _those_ changes
                     */
                    mutt_set_flag(ctx, ctx->hdrs[i], M_FLAG, old_hdrs[j]->flagged);
                    mutt_set_flag(ctx, ctx->hdrs[i], M_REPLIED, old_hdrs[j]->replied);
                    mutt_set_flag(ctx, ctx->hdrs[i], M_OLD, old_hdrs[j]->old);
                    mutt_set_flag(ctx, ctx->hdrs[i], M_READ, old_hdrs[j]->read);
                }
                mutt_set_flag(ctx, ctx->hdrs[i], M_DELETE, old_hdrs[j]->deleted);
                mutt_set_flag(ctx, ctx->hdrs[i], M_TAG, old_hdrs[j]->tagged);

                /* we don't need this header any more */
                mutt_free_header(&(old_hdrs[j]));
            }
        }

        /* free the remaining old headers */
        for (j = 0; j < old_msgcount; j++) {
            if (old_hdrs[j]) {
                mutt_free_header(&(old_hdrs[j]));
                msg_mod = 1;
            }
        }
        safe_free(&old_hdrs);
    }

    ctx->quiet = 0;

    return (ctx->changed
            || msg_mod) ? M_REOPENED : M_NEW_MAIL;
}
/* args:
 *      ctx	Context info, used when recalling a message to which
 *              we reply.
 *	hdr	envelope/attachment info for recalled message
 *	cur	if message was a reply, `cur' is set to the message which
 *		`hdr' is in reply to
 *	fcc	fcc for the recalled message
 *	fcclen	max length of fcc
 *
 * return vals:
 *	-1		error/no messages
 *	0		normal exit
 *	SENDREPLY	recalled message is a reply
 */
int mutt_get_postponed (CONTEXT *ctx, HEADER *hdr, HEADER **cur, char *fcc, size_t fcclen)
{
  HEADER *h;
  int code = SENDPOSTPONED;
  LIST *tmp;
  LIST *last = NULL;
  LIST *next;
  char *p;
  int opt_delete;
#ifdef USE_IMAP
  char curpath[LONG_STRING];
  int need_reopen = 0;
#endif

  if (!Postponed)
    return (-1);

#ifdef USE_IMAP
  /* if we're in an IMAP folder and the postponed folder is also IMAP, we may
   * need to take steps to avoid opening an additional connection to the same
   * server. */
  if ((ctx && ctx->magic == M_IMAP) && mx_is_imap (Postponed))
  { 
    strfcpy (curpath, ctx->path, sizeof (curpath));
    if (imap_select_mailbox (ctx, Postponed) < 0)
      return -1;
    need_reopen = 1;
    PostContext = ctx;
  }
  else
#endif
  if ((PostContext = mx_open_mailbox (Postponed, M_NOSORT, NULL)) == NULL)
  {
    PostCount = 0;
    mutt_error _("No postponed messages.");
    return (-1);
  }
  
  if (! PostContext->msgcount)
  {
    PostCount = 0;
    mx_close_mailbox (PostContext, NULL);
#ifdef USE_IMAP
  if (need_reopen)
    ctx = mx_open_mailbox (curpath, 0, PostContext);
  else
#endif
    safe_free ((void **) &PostContext);
    mutt_error _("No postponed messages.");
    return (-1);
  }

  if (PostContext->msgcount == 1)
  {
    /* only one message, so just use that one. */
    h = PostContext->hdrs[0];
  }
  else if ((h = select_msg ()) == NULL)
  {
    mx_close_mailbox (PostContext, NULL);
#ifdef USE_IMAP
  if (need_reopen)
    ctx = mx_open_mailbox (curpath, 0, PostContext);
  else
#endif
    safe_free ((void **) &PostContext);
    return (-1);
  }

  if (mutt_prepare_template (NULL, PostContext, hdr, h, 0) < 0)
  {
    mx_fastclose_mailbox (PostContext);
#ifdef USE_IMAP
    if (need_reopen)
      ctx = mx_open_mailbox (curpath, 0, NULL);
    else
#endif
    safe_free ((void **) &PostContext);
    return (-1);
  }

  /* finished with this message, so delete it. */
  mutt_set_flag (PostContext, h, M_DELETE, 1);

  /* update the count for the status display */
  PostCount = PostContext->msgcount - PostContext->deleted;

  /* avoid the "purge deleted messages" prompt */
  opt_delete = quadoption (OPT_DELETE);
  set_quadoption (OPT_DELETE, M_YES);
  mx_close_mailbox (PostContext, NULL);
  set_quadoption (OPT_DELETE, opt_delete);

#ifdef USE_IMAP
  if (need_reopen)
    ctx = mx_open_mailbox (curpath, 0, PostContext);
  else
#endif
  safe_free ((void **) &PostContext);

  for (tmp = hdr->env->userhdrs; tmp; )
  {
    if (mutt_strncasecmp ("X-Mutt-References:", tmp->data, 18) == 0)
    {
      if (ctx)
      {
	/* if a mailbox is currently open, look to see if the orignal message
	   the user attempted to reply to is in this mailbox */
	p = tmp->data + 18;
	SKIPWS (p);
	*cur = hash_find (ctx->id_hash, p);
      }

      /* Remove the X-Mutt-References: header field. */
      next = tmp->next;
      if (last)
	last->next = tmp->next;
      else
	hdr->env->userhdrs = tmp->next;
      tmp->next = NULL;
      mutt_free_list (&tmp);
      tmp = next;
      if (*cur)
	code |= SENDREPLY;
    }
    else if (mutt_strncasecmp ("X-Mutt-Fcc:", tmp->data, 11) == 0)
    {
      p = tmp->data + 11;
      SKIPWS (p);
      strfcpy (fcc, p, fcclen);
      mutt_pretty_mailbox (fcc);

      /* remove the X-Mutt-Fcc: header field */
      next = tmp->next;
      if (last)
	last->next = tmp->next;
      else
	hdr->env->userhdrs = tmp->next;
      tmp->next = NULL;
      mutt_free_list (&tmp);
      tmp = next;
    }



#ifdef HAVE_PGP
    else if (mutt_strncmp ("Pgp:", tmp->data, 4) == 0 /* this is generated
						       * by old mutt versions
						       */
	     || mutt_strncmp ("X-Mutt-PGP:", tmp->data, 11) == 0)
    {
      hdr->pgp = mutt_parse_pgp_hdr (strchr (tmp->data, ':') + 1, 1);
       
      /* remove the pgp field */
      next = tmp->next;
      if (last)
	last->next = tmp->next;
      else
	hdr->env->userhdrs = tmp->next;
      tmp->next = NULL;
      mutt_free_list (&tmp);
      tmp = next;
    }
#endif /* HAVE_PGP */

#ifdef MIXMASTER
    else if (mutt_strncmp ("X-Mutt-Mix:", tmp->data, 11) == 0)
    {
      char *t;
      mutt_free_list (&hdr->chain);
      
      t = strtok (tmp->data + 11, " \t\n");
      while (t)
      {
	hdr->chain = mutt_add_list (hdr->chain, t);
	t = strtok (NULL, " \t\n");
      }
      
      next = tmp->next;
      if (last) 
	last->next = tmp->next;
      else
	hdr->env->userhdrs = tmp->next;
      tmp->next = NULL;
      mutt_free_list (&tmp);
      tmp = next;
    }
#endif

    else
    {
      last = tmp;
      tmp = tmp->next;
    }
  }
  return (code);
}
Esempio n. 13
0
File: recvcmd.c Progetto: 0xAX/muttx
void mutt_attach_reply (FILE * fp, struct header *hdr,
			ATTACHPTR ** idx, short idxlen, struct body * cur,
			int flags)
{
	short mime_reply_any = 0;

	short nattach = 0;
	struct header *parent = NULL;
	struct header *tmphdr = NULL;
	short i;

	STATE st;
	char tmpbody[_POSIX_PATH_MAX];
	FILE *tmpfp;

	char prefix[SHORT_STRING];
	int rc;

	if (check_all_msg (idx, idxlen, cur, 0) == -1)
	{
		nattach = count_tagged (idx, idxlen);
		if ((parent = find_parent (idx, idxlen, cur, nattach)) == NULL)
			parent = hdr;
	}

	if (nattach > 1 && !check_can_decode (idx, idxlen, cur))
	{
		if ((rc = query_quadoption (OPT_MIMEFWDREST,
					    ("Can't decode all tagged attachments.  MIME-encapsulate the others?"))) == -1)
			return;
		else if (rc == M_YES)
			mime_reply_any = 1;
	}
	else if (nattach == 1)
		mime_reply_any = 1;

	tmphdr = mutt_new_header ();
	tmphdr->env = mutt_new_envelope ();

	if (attach_reply_envelope_defaults (tmphdr->env, idx, idxlen,
					    parent ? parent : (cur ? cur->hdr : NULL), flags) == -1)
	{
		mutt_free_header (&tmphdr);
		return;
	}

	mutt_mktemp (tmpbody, sizeof (tmpbody));
	if ((tmpfp = safe_fopen (tmpbody, "w")) == NULL)
	{
		mutt_error (("Can't create %s."), tmpbody);
		mutt_free_header (&tmphdr);
		return;
	}

	if (!parent)
	{
		if (cur)
			attach_include_reply (fp, tmpfp, cur->hdr, flags);
		else
		{
			for (i = 0; i < idxlen; i++)
			{
				if (idx[i]->content->tagged)
					attach_include_reply (fp, tmpfp, idx[i]->content->hdr, flags);
			}
		}
	}
	else
	{
		mutt_make_attribution (Context, parent, tmpfp);

		memset (&st, 0, sizeof (STATE));
		st.fpin = fp;
		st.fpout = tmpfp;

		if (!bit_val(options, OPTTEXTFLOWED))
			_mutt_make_string (prefix, sizeof (prefix), NONULL (Prefix),
					   Context, parent, 0);
		else
			strfcpy (prefix, ">", sizeof (prefix));

		st.prefix = prefix;
		st.flags  = M_CHARCONV;

		if (bit_val(options, OPTWEED))
			st.flags |= M_WEED;

		if (bit_val(options, OPTHEADER))
			include_header (1, fp, parent, tmpfp, prefix);

		if (cur)
		{
			if (mutt_can_decode (cur))
			{
				mutt_body_handler (cur, &st);
				state_putc ('\n', &st);
			}
			else
				mutt_copy_body (fp, &tmphdr->content, cur);
		}
		else
		{
			for (i = 0; i < idxlen; i++)
			{
				if (idx[i]->content->tagged && mutt_can_decode (idx[i]->content))
				{
					mutt_body_handler (idx[i]->content, &st);
					state_putc ('\n', &st);
				}
			}
		}

		mutt_make_post_indent (Context, parent, tmpfp);

		if (mime_reply_any && !cur &&
		    copy_problematic_attachments (fp, &tmphdr->content, idx, idxlen, 0) == NULL)
		{
			mutt_free_header (&tmphdr);
			safe_fclose (&tmpfp);
			return;
		}
	}

	safe_fclose (&tmpfp);

	if (ci_send_message (flags, tmphdr, tmpbody, NULL,
			     parent ? parent : (cur ? cur->hdr : NULL)) == 0)
		mutt_set_flag (Context, hdr, M_REPLIED, 1);
}
Esempio n. 14
0
static int edit_one_message (CONTEXT *ctx, HEADER *cur)
{
  char tmp[_POSIX_PATH_MAX];
  char buff[STRING];
  int omagic;
  int oerrno;
  int rc;

  unsigned short o_read;
  unsigned short o_old;

  int of, cf;
  
  CONTEXT tmpctx;
  MESSAGE *msg;

  FILE *fp = NULL;

  struct stat sb;
  time_t mtime = 0;
  
  mutt_mktemp (tmp, sizeof (tmp));

  omagic = DefaultMagic;
  DefaultMagic = MUTT_MBOX;

  rc = (mx_open_mailbox (tmp, MUTT_NEWFOLDER, &tmpctx) == NULL) ? -1 : 0;

  DefaultMagic = omagic;

  if (rc == -1)
  {
    mutt_error (_("could not create temporary folder: %s"), strerror (errno));
    return -1;
  }

  rc = mutt_append_message (&tmpctx, ctx, cur, 0, CH_NOLEN |
	((ctx->magic == MUTT_MBOX || ctx->magic == MUTT_MMDF) ? 0 : CH_NOSTATUS));
  oerrno = errno;

  mx_close_mailbox (&tmpctx, NULL);

  if (rc == -1)
  {
    mutt_error (_("could not write temporary mail folder: %s"), strerror (oerrno));
    goto bail;
  }

  if ((rc = stat (tmp, &sb)) == -1)
  {
    mutt_error (_("Can't stat %s: %s"), tmp, strerror (errno));
    goto bail;
  }

  /*
   * 2002-09-05 [email protected]
   * The file the user is going to edit is not a real mbox, so we need to
   * truncate the last newline in the temp file, which is logically part of
   * the message separator, and not the body of the message.  If we fail to
   * remove it, the message will grow by one line each time the user edits
   * the message.
   */
  if (sb.st_size != 0 && truncate (tmp, sb.st_size - 1) == -1)
  {
    mutt_error (_("could not truncate temporary mail folder: %s"),
		strerror (errno));
    goto bail;
  }

  mtime = mutt_decrease_mtime (tmp, &sb);

  mutt_edit_file (NONULL(Editor), tmp);

  if ((rc = stat (tmp, &sb)) == -1)
  {
    mutt_error (_("Can't stat %s: %s"), tmp, strerror (errno));
    goto bail;
  }
  
  if (sb.st_size == 0)
  {
    mutt_message (_("Message file is empty!"));
    rc = 1;
    goto bail;
  }

  if (sb.st_mtime == mtime)
  {
    mutt_message (_("Message not modified!"));
    rc = 1;
    goto bail;
  }

  if ((fp = fopen (tmp, "r")) == NULL)
  {
    rc = -1;
    mutt_error (_("Can't open message file: %s"), strerror (errno));
    goto bail;
  }

  if (mx_open_mailbox (ctx->path, MUTT_APPEND, &tmpctx) == NULL)
  {
    rc = -1;
    /* L10N: %s is from strerror(errno) */
    mutt_error (_("Can't append to folder: %s"), strerror (errno));
    goto bail;
  }

  of = 0;
  cf = ((tmpctx.magic == MUTT_MBOX || tmpctx.magic == MUTT_MMDF) ? 0 : CH_NOSTATUS);
  
  if (fgets (buff, sizeof (buff), fp) && is_from (buff, NULL, 0, NULL))
  {
    if (tmpctx.magic == MUTT_MBOX || tmpctx.magic == MUTT_MMDF)
      cf = CH_FROM | CH_FORCE_FROM;
  }
  else
    of = MUTT_ADD_FROM;

  /* 
   * XXX - we have to play games with the message flags to avoid
   * problematic behavior with maildir folders.
   *
   */

  o_read = cur->read; o_old = cur->old;
  cur->read = cur->old = 0;
  msg = mx_open_new_message (&tmpctx, cur, of);
  cur->read = o_read; cur->old = o_old;

  if (msg == NULL)
  {
    mutt_error (_("Can't append to folder: %s"), strerror (errno));
    mx_close_mailbox (&tmpctx, NULL);
    goto bail;
  }

  if ((rc = mutt_copy_hdr (fp, msg->fp, 0, sb.st_size, CH_NOLEN | cf, NULL)) == 0)
  {
    fputc ('\n', msg->fp);
    rc = mutt_copy_stream (fp, msg->fp);
  }

  rc = mx_commit_message (msg, &tmpctx);
  mx_close_message (&tmpctx, &msg);
  
  mx_close_mailbox (&tmpctx, NULL);
  
  bail:
  if (fp) safe_fclose (&fp);

  if (rc >= 0)
    unlink (tmp);

  if (rc == 0)
  {
    mutt_set_flag (Context, cur, MUTT_DELETE, 1);
    mutt_set_flag (Context, cur, MUTT_PURGE, 1);
    mutt_set_flag (Context, cur, MUTT_READ, 1);

    if (option (OPTDELETEUNTAG))
      mutt_set_flag (Context, cur, MUTT_TAG, 0);
  }
  else if (rc == -1)
    mutt_message (_("Error. Preserving temporary file: %s"), tmp);

    
  return rc;
}