void mutt_free_body (BODY **p)
{
  BODY *a = *p, *b;

  while (a)
  {
    b = a;
    a = a->next; 

    if (b->parameter)
      mutt_free_parameter (&b->parameter);
    if (b->unlink && b->filename)
      unlink (b->filename);
    safe_free ((void **) &b->filename);
    safe_free ((void **) &b->content);
    safe_free ((void **) &b->xtype);
    safe_free ((void **) &b->subtype);
    safe_free ((void **) &b->description);
    safe_free ((void **) &b->form_name);

    if (b->hdr)
    {
      /* Don't free twice (b->hdr->content = b->parts) */
      b->hdr->content = NULL;
      mutt_free_header(&b->hdr);
    }

    if (b->parts)
      mutt_free_body (&b->parts);

    safe_free ((void **) &b);
  }

  *p = 0;
}
Example #2
0
HEADER *
mutt_hcache_restore(const unsigned char *d, HEADER ** oh)
{
  int off = 0;
  HEADER *h = mutt_new_header();
  int convert = !Charset_is_utf8;

  /* skip validate */
  off += sizeof (validate);

  /* skip crc */
  off += sizeof (unsigned int);

  memcpy(h, d + off, sizeof (HEADER));
  off += sizeof (HEADER);

  h->env = mutt_new_envelope();
  restore_envelope(h->env, d, &off, convert);

  h->content = mutt_new_body();
  restore_body(h->content, d, &off, convert);

  restore_char(&h->maildir_flags, d, &off, convert);

  /* this is needed for maildir style mailboxes */
  if (oh)
  {
    h->old = (*oh)->old;
    h->path = safe_strdup((*oh)->path);
    mutt_free_header(oh);
  }

  return h;
}
Example #3
0
File: mh.c Project: hww3/pexts
static void maildir_free_entry(struct maildir **md)
{
  if(!md || !*md)
    return;

  safe_free((void **) &(*md)->canon_fname);
  if((*md)->h)
    mutt_free_header(&(*md)->h);

  safe_free((void **) md);
}
Example #4
0
void mutt_free_body (BODY ** p)
{
  BODY *a = *p, *b;

  while (a) {
    b = a;
    a = a->next;

    if (b->parameter)
      mutt_free_parameter (&b->parameter);
    if (b->unlink && b->filename) {
      debug_print (1, ("unlinking %s.\n", b->filename));
      unlink (b->filename);
    }
    else if (b->filename)
      debug_print (1, ("not unlinking %s.\n", b->filename));

    mem_free (&b->filename);
    mem_free (&b->content);
    mem_free (&b->xtype);
    mem_free (&b->subtype);
    mem_free (&b->description);
    mem_free (&b->form_name);

    if (b->hdr) {
      /* Don't free twice (b->hdr->content = b->parts) */
      b->hdr->content = NULL;
      mutt_free_header (&b->hdr);
    }

    if (b->parts)
      mutt_free_body (&b->parts);

    mem_free (&b);
  }

  *p = 0;
}
Example #5
0
File: mh.c Project: 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;
}
Example #6
0
static void append_message(CONTEXT *ctx,
                           notmuch_query_t *q,
                           notmuch_message_t *msg,
                           int dedup)
{
    char *newpath = NULL;
    const char *path;
    HEADER *h = NULL;

    /* deduplicate */
    if (dedup && get_mutt_header(ctx, msg)) {
        get_ctxdata(ctx)->ignmsgcount++;
        nm_progress_update(ctx, q);
        dprint(2, (debugfile, "nm: ignore id=%s, already in the context\n",
                   notmuch_message_get_message_id(msg)));
        return;
    }

    path = get_message_last_filename(msg);
    if (!path)
        return;

    dprint(2, (debugfile, "nm: appending message, i=%d, id=%s, path=%s\n",
               ctx->msgcount,
               notmuch_message_get_message_id(msg),
               path));

    if (ctx->msgcount >= ctx->hdrmax) {
        dprint(2, (debugfile, "nm: allocate mx memory\n"));
        mx_alloc_memory(ctx);
    }
    if (access(path, F_OK) == 0)
        h = maildir_parse_message(M_MAILDIR, path, 0, NULL);
    else {
        /* maybe moved try find it... */
        char *folder = get_folder_from_path(path);

        if (folder) {
            FILE *f = maildir_open_find_message(folder, path, &newpath);
            if (f) {
                h = maildir_parse_stream(M_MAILDIR, f, newpath, 0, NULL);
                fclose(f);

                dprint(1, (debugfile, "nm: not up-to-date: %s -> %s\n",
                           path, newpath));
            }
        }
        FREE(&folder);
    }

    if (!h) {
        dprint(1, (debugfile, "nm: failed to parse message: %s\n", path));
        goto done;
    }
    if (init_header(h, newpath ? newpath : path, msg) != 0) {
        mutt_free_header(&h);
        dprint(1, (debugfile, "nm: failed to append header!\n"));
        goto done;
    }

    h->active = 1;
    h->index = ctx->msgcount;
    ctx->size += h->content->length
                 + h->content->offset
                 - h->content->hdr_offset;
    ctx->hdrs[ctx->msgcount] = h;
    ctx->msgcount++;

    if (newpath) {
        /* remember that file has been moved -- nm_sync() will update the DB */
        struct nm_hdrdata *hd = (struct nm_hdrdata *) h->data;

        if (hd) {
            dprint(1, (debugfile, "nm: remember obsolete path: %s\n", path));
            hd->oldpath = safe_strdup(path);
        }
    }
    nm_progress_update(ctx, q);
done:
    FREE(&newpath);
}
Example #7
0
/* returns 0 on success, -1 on error */
int mutt_decode_save_attachment (FILE *fp, BODY *m, char *path,
				 int displaying, int flags)
{
  STATE s;
  unsigned int saved_encoding = 0;
  BODY *saved_parts = NULL;
  HEADER *saved_hdr = NULL;

  memset (&s, 0, sizeof (s));
  s.flags = displaying;

  if (flags == M_SAVE_APPEND)
    s.fpout = fopen (path, "a");
  else if (flags == M_SAVE_OVERWRITE)
    s.fpout = fopen (path, "w");	/* __FOPEN_CHECKED__ */
  else
    s.fpout = safe_fopen (path, "w");

  if (s.fpout == NULL)
  {
    mutt_perror ("fopen");
    return (-1);
  }

  if (fp == NULL)
  {
    /* When called from the compose menu, the attachment isn't parsed,
     * so we need to do it here. */
    struct stat st;

    if (stat (m->filename, &st) == -1)
    {
      mutt_perror ("stat");
      safe_fclose (&s.fpout);
      return (-1);
    }

    if ((s.fpin = fopen (m->filename, "r")) == NULL)
    {
      mutt_perror ("fopen");
      return (-1);
    }

    saved_encoding = m->encoding;
    if (!is_multipart (m))
      m->encoding = ENC8BIT;
    
    m->length = st.st_size;
    m->offset = 0;
    saved_parts = m->parts;
    saved_hdr = m->hdr;
    mutt_parse_part (s.fpin, m);

    if (m->noconv || is_multipart (m))
      s.flags |= M_CHARCONV;
  }
  else
  {
    s.fpin = fp;
    s.flags |= M_CHARCONV;
  }

  mutt_body_handler (m, &s);

  safe_fclose (&s.fpout);
  if (fp == NULL)
  {
    m->length = 0;
    m->encoding = saved_encoding;
    if (saved_parts)
    {
      mutt_free_header (&m->hdr);
      m->parts = saved_parts;
      m->hdr = saved_hdr;
    }
    safe_fclose (&s.fpin);
  }

  return (0);
}
char *_mutt_expand_path (char *s, size_t slen, int rx)
{
  char p[_POSIX_PATH_MAX] = "";
  char q[_POSIX_PATH_MAX] = "";
  char tmp[_POSIX_PATH_MAX];
  char *t;

  char *tail = ""; 

  int recurse = 0;
  
  do 
  {
    recurse = 0;

    switch (*s)
    {
      case '~':
      {
	if (*(s + 1) == '/' || *(s + 1) == 0)
	{
	  strfcpy (p, NONULL(Homedir), sizeof (p));
	  tail = s + 1;
	}
	else
	{
	  struct passwd *pw;
	  if ((t = strchr (s + 1, '/'))) 
	    *t = 0;

	  if ((pw = getpwnam (s + 1)))
	  {
	    strfcpy (p, pw->pw_dir, sizeof (p));
	    if (t)
	    {
	      *t = '/';
	      tail = t;
	    }
	    else
	      tail = "";
	  }
	  else
	  {
	    /* user not found! */
	    if (t)
	      *t = '/';
	    *p = '\0';
	    tail = s;
	  }
	}
      }
      break;
      
      case '=':
      case '+':    
      {
#ifdef USE_IMAP
	/* special case: folder = {host}: don't append slash */
	if (mx_is_imap (NONULL (Maildir)) && Maildir[strlen (Maildir) - 1] == '}')
	  strfcpy (p, NONULL (Maildir), sizeof (p));
	else
#endif
	  snprintf (p, sizeof (p), "%s/", NONULL (Maildir));
	
	tail = s + 1;
      }
      break;
      
      /* elm compatibility, @ expands alias to user name */
    
      case '@':
      {
	HEADER *h;
	ADDRESS *alias;
	
	if ((alias = mutt_lookup_alias (s + 1)))
	{
	  h = mutt_new_header();
	  h->env = mutt_new_envelope();
	  h->env->from = h->env->to = alias;
	  mutt_default_save (p, sizeof (p), h);
	  h->env->from = h->env->to = NULL;
	  mutt_free_header (&h);
	  /* Avoid infinite recursion if the resulting folder starts with '@' */
	  if (*p != '@')
	    recurse = 1;
	  
	  tail = "";
	}
      }
      break;
      
      case '>':
      {
	strfcpy (p, NONULL(Inbox), sizeof (p));
	tail = s + 1;
      }
      break;
      
      case '<':
      {
	strfcpy (p, NONULL(Outbox), sizeof (p));
	tail = s + 1;
      }
      break;
      
      case '!':
      {
	if (*(s+1) == '!')
	{
	  strfcpy (p, NONULL(LastFolder), sizeof (p));
	  tail = s + 2;
	}
	else 
	{
	  strfcpy (p, NONULL(Spoolfile), sizeof (p));
	  tail = s + 1;
	}
      }
      break;
      
      case '-':
      {
	strfcpy (p, NONULL(LastFolder), sizeof (p));
	tail = s + 1;
      }
      break;
      
      default:
      {
	*p = '\0';
	tail = s;
      }
    }

    if (rx && *p && !recurse)
    {
      mutt_rx_sanitize_string (q, sizeof (q), p);
      snprintf (tmp, sizeof (tmp), "%s%s", q, tail);
    }
    else
      snprintf (tmp, sizeof (tmp), "%s%s", p, tail);
    
    strfcpy (s, tmp, slen);
  }
  while (recurse);

  return (s);
}
Example #9
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;
}
Example #10
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;
}
Example #11
0
File: recvcmd.c Project: 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);
}
Example #12
0
File: recvcmd.c Project: 0xAX/muttx
static void attach_forward_msgs (FILE * fp, struct header *hdr,
				 ATTACHPTR ** idx, short idxlen, struct body * cur)
{
	struct header *curhdr = NULL;
	struct header *tmphdr;
	short i;
	int rc;

	struct body **last;
	char tmpbody[_POSIX_PATH_MAX];
	FILE *tmpfp = NULL;

	int cmflags = 0;
	int chflags = CH_XMIT;

	if (cur)
		curhdr = cur->hdr;
	else
	{
		for (i = 0; i < idxlen; i++)
			if (idx[i]->content->tagged)
			{
				curhdr = idx[i]->content->hdr;
				break;
			}
	}

	tmphdr = mutt_new_header ();
	tmphdr->env = mutt_new_envelope ();
	mutt_make_forward_subject (tmphdr->env, Context, curhdr);


	tmpbody[0] = '\0';

	if ((rc = query_quadoption (OPT_MIMEFWD,
				    ("Forward MIME encapsulated?"))) == M_NO)
	{

		/* no MIME encapsulation */

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

		if (bit_val(options, OPTFORWQUOTE))
		{
			chflags |= CH_PREFIX;
			cmflags |= M_CM_PREFIX;
		}

		if (bit_val(options, OPTFORWDECODE))
		{
			cmflags |= M_CM_DECODE | M_CM_CHARCONV;
			if (bit_val(options, OPTWEED))
			{
				chflags |= CH_WEED | CH_REORDER;
				cmflags |= M_CM_WEED;
			}
		}


		if (cur)
		{
			/* mutt_message_hook (cur->hdr, M_MESSAGEHOOK); */
			mutt_forward_intro (tmpfp, cur->hdr);
			_mutt_copy_message (tmpfp, fp, cur->hdr, cur->hdr->content, cmflags, chflags);
			mutt_forward_trailer (tmpfp);
		}
		else
		{
			for (i = 0; i < idxlen; i++)
			{
				if (idx[i]->content->tagged)
				{
					/* mutt_message_hook (idx[i]->content->hdr, M_MESSAGEHOOK); */
					mutt_forward_intro (tmpfp, idx[i]->content->hdr);
					_mutt_copy_message (tmpfp, fp, idx[i]->content->hdr,
							    idx[i]->content->hdr->content, cmflags, chflags);
					mutt_forward_trailer (tmpfp);
				}
			}
		}
		safe_fclose (&tmpfp);
	}
	else if (rc == M_YES)	/* do MIME encapsulation - we don't need to do much here */
	{
		last = &tmphdr->content;
		if (cur)
			mutt_copy_body (fp, last, cur);
		else
		{
			for (i = 0; i < idxlen; i++)
				if (idx[i]->content->tagged)
				{
					mutt_copy_body (fp, last, idx[i]->content);
					last = &((*last)->next);
				}
		}
	}
	else
		mutt_free_header (&tmphdr);

	ci_send_message (0, tmphdr, *tmpbody ? tmpbody : NULL,
			 NULL, curhdr);

}
Example #13
0
File: recvcmd.c Project: 0xAX/muttx
static void attach_forward_bodies (FILE * fp, struct header * hdr,
				   ATTACHPTR ** idx, short idxlen,
				   struct body * cur,
				   short nattach)
{
	short i;
	short mime_fwd_all = 0;
	short mime_fwd_any = 1;
	struct header *parent = NULL;
	struct header *tmphdr = NULL;
	struct body **last;
	char tmpbody[_POSIX_PATH_MAX];
	FILE *tmpfp = NULL;

	char prefix[STRING];

	int rc = 0;

	STATE st;

	/*
	 * First, find the parent message.
	 * Note: This could be made an option by just
	 * putting the following lines into an if block.
	 */


	parent = find_parent (idx, idxlen, cur, nattach);

	if (parent == NULL)
		parent = hdr;


	tmphdr = mutt_new_header ();
	tmphdr->env = mutt_new_envelope ();
	mutt_make_forward_subject (tmphdr->env, Context, parent);

	mutt_mktemp (tmpbody, sizeof (tmpbody));
	if ((tmpfp = safe_fopen (tmpbody, "w")) == NULL)
	{
		mutt_error (("Can't open temporary file %s."), tmpbody);
		return;
	}

	mutt_forward_intro (tmpfp, parent);

	/* prepare the prefix here since we'll need it later. */

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

	include_header (bit_val(options, OPTFORWQUOTE), fp, parent,
			tmpfp, prefix);


	/*
	 * Now, we have prepared the first part of the message body: The
	 * original message's header.
	 *
	 * The next part is more interesting: either include the message bodies,
	 * or attach them.
	 */

	if ((!cur || mutt_can_decode (cur)) &&
	    (rc = query_quadoption (OPT_MIMEFWD,
				    ("Forward as attachments?"))) == M_YES)
		mime_fwd_all = 1;
	else if (rc == -1)
		goto bail;

	/*
	 * shortcut MIMEFWDREST when there is only one attachment.  Is
	 * this intuitive?
	 */

	if (!mime_fwd_all && !cur && (nattach > 1)
	    && !check_can_decode (idx, idxlen, cur))
	{
		if ((rc = query_quadoption (OPT_MIMEFWDREST,
					    ("Can't decode all tagged attachments.  MIME-forward the others?"))) == -1)
			goto bail;
		else if (rc == M_NO)
			mime_fwd_any = 0;
	}

	/* initialize a state structure */

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

	if (bit_val(options, OPTFORWQUOTE))
		st.prefix = prefix;
	st.flags = M_CHARCONV;
	if (bit_val(options, OPTWEED))
		st.flags |= M_WEED;
	st.fpin = fp;
	st.fpout = tmpfp;

	/* where do we append new MIME parts? */
	last = &tmphdr->content;

	if (cur)
	{
		/* single body case */

		if (!mime_fwd_all && mutt_can_decode (cur))
		{
			mutt_body_handler (cur, &st);
			state_putc ('\n', &st);
		}
		else
		{
			if (mutt_copy_body (fp, last, cur) == -1)
				goto bail;
			last = &((*last)->next);
		}
	}
	else
	{
		/* multiple body case */

		if (!mime_fwd_all)
		{
			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);
				}
			}
		}

		if (mime_fwd_any &&
		    copy_problematic_attachments (fp, last, idx, idxlen, mime_fwd_all) == NULL)
			goto bail;
	}

	mutt_forward_trailer (tmpfp);

	safe_fclose (&tmpfp);
	tmpfp = NULL;

	/* now that we have the template, send it. */
	ci_send_message (0, tmphdr, tmpbody, NULL, parent);
	return;

bail:

	if (tmpfp)
	{
		safe_fclose (&tmpfp);
		mutt_unlink (tmpbody);
	}

	mutt_free_header (&tmphdr);
}
Example #14
0
/*
 * Read headers
 * returns:
 *  0 on success
 * -1 - connection lost,
 * -2 - invalid command or execution error,
 * -3 - error writing to tempfile
 */
static int pop_fetch_headers(CONTEXT *ctx)
{
    int i, ret, old_count, new_count, deleted;
    unsigned short hcached = 0, bcached;
    POP_DATA *pop_data = (POP_DATA *)ctx->data;
    progress_t progress;

    time(&pop_data->check_time);
    pop_data->clear_cache = 0;

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

    old_count = ctx->msgcount;
    ret = pop_fetch_data(pop_data, "UIDL\r\n", NULL, fetch_uidl, ctx);
    new_count = ctx->msgcount;
    ctx->msgcount = old_count;

    if (pop_data->cmd_uidl == 2) {
        if (ret == 0) {
            pop_data->cmd_uidl = 1;

            dprint(1, "pop_fetch_headers: set UIDL capability\n");
        }

        if ((ret == -2)
            && (pop_data->cmd_uidl == 2)) {
            pop_data->cmd_uidl = 0;

            dprint(1, "pop_fetch_headers: unset UIDL capability\n");
            snprintf(pop_data->err_msg, sizeof(pop_data->err_msg),
                     _("Command UIDL is not supported by server."));
        }
    }

    if (!ctx->quiet)
        mutt_progress_init(&progress, _("Fetching message headers..."),
                           M_PROGRESS_MSG, ReadInc, new_count - old_count);

    if (ret == 0) {
        for (i = 0, deleted = 0; i < old_count; i++) {
            if (ctx->hdrs[i]->refno == -1) {
                ctx->hdrs[i]->deleted = 1;
                deleted++;
            }
        }

        if (deleted > 0) {
            mutt_error(_(
                           "%d messages have been lost. Try reopening the mailbox."),
                       deleted);
            mutt_sleep(2);
        }

        for (i = old_count; i < new_count; i++) {
            if (!ctx->quiet)
                mutt_progress_update(&progress, i + 1 - old_count, -1);
            if ((ret = pop_read_header(pop_data, ctx->hdrs[i])) < 0)
                break;
            /*
             * faked support for flags works like this:
             * - if 'hcached' is 1, we have the message in our hcache:
             *        - if we also have a body: read
             *        - if we don't have a body: old
             *          (if $mark_old is set which is maybe wrong as
             *          $mark_old should be considered for syncing the
             *          folder and not when opening it XXX)
             * - if 'hcached' is 0, we don't have the message in our hcache:
             *        - if we also have a body: read
             *        - if we don't have a body: new
             */
            bcached =
                mutt_bcache_exists(pop_data->bcache, ctx->hdrs[i]->data) == 0;
            ctx->hdrs[i]->old = 0;
            ctx->hdrs[i]->read = 0;

            if (hcached) {
                if (bcached)
                    ctx->hdrs[i]->read = 1;
                else if (option(OPTMARKOLD))
                    ctx->hdrs[i]->old = 1;
            } else {
                if (bcached)
                    ctx->hdrs[i]->read = 1;
            }

            ctx->msgcount++;
        }

        if (i > old_count)
            mx_update_context(ctx, i - old_count);
    }

    if (ret < 0) {
        for (i = ctx->msgcount; i < new_count; i++)
            mutt_free_header(&ctx->hdrs[i]);
        return ret;
    }

    /* after putting the result into our structures,
     * clean up cache, i.e. wipe messages deleted outside
     * the availability of our cache
     */
    if (option(OPTMESSAGECACHECLEAN))
        mutt_bcache_list(pop_data->bcache, msg_cache_check, (void *)ctx);

    mutt_clear_error();
    return new_count - old_count;
}
Example #15
0
/*
 * Read headers
 * returns:
 *  0 on success
 * -1 - conection lost,
 * -2 - invalid command or execution error,
 * -3 - error writing to tempfile
 */
static int pop_fetch_headers (CONTEXT *ctx)
{
  int i, ret, old_count, new_count, deleted;
  unsigned short hcached = 0, bcached;
  POP_DATA *pop_data = (POP_DATA *)ctx->data;
  progress_t progress;

#ifdef USE_HCACHE
  header_cache_t *hc = NULL;
  void *data;

  hc = pop_hcache_open (pop_data, ctx->path);
#endif

  time (&pop_data->check_time);
  pop_data->clear_cache = 0;

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

  old_count = ctx->msgcount;
  ret = pop_fetch_data (pop_data, "UIDL\r\n", NULL, fetch_uidl, ctx);
  new_count = ctx->msgcount;
  ctx->msgcount = old_count;

  if (pop_data->cmd_uidl == 2)
  {
    if (ret == 0)
    {
      pop_data->cmd_uidl = 1;

      dprint (1, (debugfile, "pop_fetch_headers: set UIDL capability\n"));
    }

    if (ret == -2 && pop_data->cmd_uidl == 2)
    {
      pop_data->cmd_uidl = 0;

      dprint (1, (debugfile, "pop_fetch_headers: unset UIDL capability\n"));
      snprintf (pop_data->err_msg, sizeof (pop_data->err_msg),
	      _("Command UIDL is not supported by server."));
    }
  }

  if (!ctx->quiet)
    mutt_progress_init (&progress, _("Fetching message headers..."),
                        M_PROGRESS_MSG, ReadInc, new_count - old_count);

  if (ret == 0)
  {
    for (i = 0, deleted = 0; i < old_count; i++)
    {
      if (ctx->hdrs[i]->refno == -1)
      {
	ctx->hdrs[i]->deleted = 1;
	deleted++;
      }
    }
    if (deleted > 0)
    {
      mutt_error (_("%d messages have been lost. Try reopening the mailbox."),
		  deleted);
      mutt_sleep (2);
    }

    for (i = old_count; i < new_count; i++)
    {
      if (!ctx->quiet)
	mutt_progress_update (&progress, i + 1 - old_count, -1);
#if USE_HCACHE
      if ((data = mutt_hcache_fetch (hc, ctx->hdrs[i]->data, strlen)))
      {
	char *uidl = safe_strdup (ctx->hdrs[i]->data);
	int refno = ctx->hdrs[i]->refno;
	int index = ctx->hdrs[i]->index;
	/*
	 * - POP dynamically numbers headers and relies on h->refno
	 *   to map messages; so restore header and overwrite restored
	 *   refno with current refno, same for index
	 * - h->data needs to a separate pointer as it's driver-specific
	 *   data freed separately elsewhere
	 *   (the old h->data should point inside a malloc'd block from
	 *   hcache so there shouldn't be a memleak here)
	 */
	HEADER *h = mutt_hcache_restore ((unsigned char *) data, NULL);
	mutt_free_header (&ctx->hdrs[i]);
	ctx->hdrs[i] = h;
	ctx->hdrs[i]->refno = refno;
	ctx->hdrs[i]->index = index;
	ctx->hdrs[i]->data = uidl;
	ret = 0;
	hcached = 1;
      }
      else
#endif
      if ((ret = pop_read_header (pop_data, ctx->hdrs[i])) < 0)
	break;
#if USE_HCACHE
      else
      {
	mutt_hcache_store (hc, ctx->hdrs[i]->data, ctx->hdrs[i], 0, strlen, M_GENERATE_UIDVALIDITY);
      }

      FREE(&data);
#endif

      /*
       * faked support for flags works like this:
       * - if 'hcached' is 1, we have the message in our hcache:
       *        - if we also have a body: read
       *        - if we don't have a body: old
       *          (if $mark_old is set which is maybe wrong as
       *          $mark_old should be considered for syncing the
       *          folder and not when opening it XXX)
       * - if 'hcached' is 0, we don't have the message in our hcache:
       *        - if we also have a body: read
       *        - if we don't have a body: new
       */
      bcached = mutt_bcache_exists (pop_data->bcache, ctx->hdrs[i]->data) == 0;
      ctx->hdrs[i]->old = 0;
      ctx->hdrs[i]->read = 0;
      if (hcached)
      {
        if (bcached)
          ctx->hdrs[i]->read = 1;
        else if (option (OPTMARKOLD))
          ctx->hdrs[i]->old = 1;
      }
      else
      {
        if (bcached)
          ctx->hdrs[i]->read = 1;
      }

      ctx->msgcount++;
    }

    if (i > old_count)
      mx_update_context (ctx, i - old_count);
  }

#if USE_HCACHE
    mutt_hcache_close (hc);
#endif

  if (ret < 0)
  {
    for (i = ctx->msgcount; i < new_count; i++)
      mutt_free_header (&ctx->hdrs[i]);
    return ret;
  }

  /* after putting the result into our structures,
   * clean up cache, i.e. wipe messages deleted outside
   * the availability of our cache
   */
  if (option (OPTMESSAGECACHECLEAN))
    mutt_bcache_list (pop_data->bcache, msg_cache_check, (void*)ctx);

  mutt_clear_error ();
  return (new_count - old_count);
}