示例#1
0
/* return 0 on success, -1 on failure */
int mutt_sync_compressed (CONTEXT * ctx)
{
    char *cmd;
    int rc = 0;
    FILE *fp;
    COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compressinfo;

    if (!ctx->quiet)
        mutt_message (_("Compressing %s..."), ctx->realpath);

    cmd = get_compression_cmd (ci->close, ctx);
    if (cmd == NULL)
        return (-1);

    if ((fp = fopen (ctx->realpath, "a")) == NULL) {
        mutt_perror (ctx->realpath);
        mem_free (&cmd);
        return (-1);
    }
    mutt_block_signals ();
    if (mbox_lock_compressed (ctx, fp, 1, 1) == -1) {
        fclose (fp);
        mutt_unblock_signals ();
        mutt_error _("Unable to lock mailbox!");

        store_size (ctx);

        mem_free (&cmd);
        return (-1);
    }

    debug_print (2, ("CompressCommand: '%s'\n", cmd));

    endwin ();
    fflush (stdout);
    sprintf (echo_cmd, _("echo Compressing %s..."), ctx->realpath);
    mutt_system (echo_cmd);
    if (mutt_system (cmd)) {
        mutt_any_key_to_continue (NULL);
        mutt_error (_
                    ("%s: Error compressing mailbox! Original mailbox deleted, uncompressed one kept!\n"),
                    ctx->path);
        rc = -1;
    }

    mbox_unlock_compressed (ctx, fp);
    mutt_unblock_signals ();
    fclose (fp);

    mem_free (&cmd);

    store_size (ctx);

    return (rc);
}
示例#2
0
文件: curs_lib.c 项目: darnir/neomutt
/**
 * mutt_do_pager - Display some page-able text to the user
 * @param banner   Message for status bar
 * @param tempfile File to display
 * @param do_color Flags, see #PagerFlags
 * @param info     Info about current mailbox (OPTIONAL)
 * @retval  0 Success
 * @retval -1 Error
 */
int mutt_do_pager(const char *banner, const char *tempfile, PagerFlags do_color,
                  struct Pager *info)
{
  int rc;

  if (!C_Pager || (mutt_str_strcmp(C_Pager, "builtin") == 0))
    rc = mutt_pager(banner, tempfile, do_color, info);
  else
  {
    char cmd[256];

    mutt_endwin();
    mutt_file_expand_fmt_quote(cmd, sizeof(cmd), C_Pager, tempfile);
    if (mutt_system(cmd) == -1)
    {
      mutt_error(_("Error running \"%s\""), cmd);
      rc = -1;
    }
    else
      rc = 0;
    mutt_file_unlink(tempfile);
  }

  return rc;
}
示例#3
0
文件: remailer.c 项目: aschrab/mutt
int mix_send_message (LIST *chain, const char *tempfile)
{
  char cmd[HUGE_STRING];
  char tmp[HUGE_STRING];
  char cd_quoted[STRING];
  int i;

  snprintf (cmd, sizeof (cmd), "cat %s | %s -m ", tempfile, Mixmaster);
  
  for (i = 0; chain; chain = chain->next, i = 1)
  {
    strfcpy (tmp, cmd, sizeof (tmp));
    mutt_quote_filename (cd_quoted, sizeof (cd_quoted), (char *) chain->data);
    snprintf (cmd, sizeof (cmd), "%s%s%s", tmp, i ? "," : " -l ", cd_quoted);
  }

  if (!option (OPTNOCURSES))
    mutt_endwin (NULL);
  
  if ((i = mutt_system (cmd)))
  {
    fprintf (stderr, _("Error sending message, child exited %d.\n"), i);
    if (!option (OPTNOCURSES))
    {
      mutt_any_key_to_continue (NULL);
      mutt_error _("Error sending message.");
    }
  }

  unlink (tempfile);
  return i;
}
int mutt_do_pager (const char *banner,
		   const char *tempfile,
		   int do_color,
		   pager_t *info)
{
  int rc;
  
  if (!Pager || mutt_strcmp (Pager, "builtin") == 0)
    rc = mutt_pager (banner, tempfile, do_color, info);
  else
  {
    char cmd[STRING];
    
    endwin ();
    mutt_expand_file_fmt (cmd, sizeof(cmd), Pager, tempfile);
    if (mutt_system (cmd) == -1)
    {
      mutt_error (_("Error running \"%s\"!"), cmd);
      rc = -1;
    }
    else
      rc = 0;
    mutt_unlink (tempfile);
  }

  return rc;
}
示例#5
0
文件: compress.c 项目: darnir/neomutt
/**
 * execute_command - Run a system command
 * @param m        Mailbox to work with
 * @param command  Command string to execute
 * @param progress Message to show the user
 * @retval 1 Success
 * @retval 0 Failure
 *
 * Run the supplied command, taking care of all the NeoMutt requirements,
 * such as locking files and blocking signals.
 */
static int execute_command(struct Mailbox *m, const char *command, const char *progress)
{
  int rc = 1;
  char sys_cmd[STR_COMMAND];

  if (!m || !command || !progress)
    return 0;

  if (!m->quiet)
  {
    mutt_message(progress, m->realpath);
  }

  mutt_sig_block();
  endwin();
  fflush(stdout);

  expand_command_str(m, command, sys_cmd, sizeof(sys_cmd));

  if (mutt_system(sys_cmd) != 0)
  {
    rc = 0;
    mutt_any_key_to_continue(NULL);
    mutt_error(_("Error running \"%s\""), sys_cmd);
  }

  mutt_sig_unblock();

  return rc;
}
void mutt_edit_file (const char *editor, const char *data)
{
  char cmd[LONG_STRING];
  
  endwin ();
  mutt_expand_file_fmt (cmd, sizeof (cmd), editor, data);
  if (mutt_system (cmd) == -1)
    mutt_error (_("Error running \"%s\"!"), cmd);
  keypad (stdscr, TRUE);
  clearok (stdscr, TRUE);
}
示例#7
0
void pgp_invoke_import (const char *fname)
{
  char _fname[_POSIX_PATH_MAX + SHORT_STRING];
  char cmd[HUGE_STRING];
  struct pgp_command_context cctx;

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

  mutt_quote_filename (_fname, sizeof (_fname), fname);
  cctx.fname = _fname;

  mutt_pgp_command (cmd, sizeof (cmd), &cctx, PgpImportCommand);
  mutt_system (cmd);
}
示例#8
0
文件: curs_lib.c 项目: darnir/neomutt
/**
 * mutt_edit_file - Let the user edit a file
 * @param editor User's editor config
 * @param file   File to edit
 */
void mutt_edit_file(const char *editor, const char *file)
{
  char cmd[STR_COMMAND];

  mutt_endwin();
  mutt_file_expand_fmt_quote(cmd, sizeof(cmd), editor, file);
  if (mutt_system(cmd) != 0)
  {
    mutt_error(_("Error running \"%s\""), cmd);
  }
  /* the terminal may have been resized while the editor owned it */
  mutt_resize_screen();
  keypad(stdscr, true);
  clearok(stdscr, true);
}
示例#9
0
/* invoke a command in a subshell */
void mutt_shell_escape (void)
{
        char buf[LONG_STRING];

        buf[0] = 0;
        if (mutt_get_field (_("Shell command: "), buf, sizeof (buf), M_CMD) == 0) {
                if (!buf[0] && Shell)
                        strfcpy (buf, Shell, sizeof (buf));
                if(buf[0]) {
                        CLEARLINE (LINES-1);
                        mutt_endwin (NULL);
                        fflush (stdout);
                        if (mutt_system (buf) != 0 || option (OPTWAITKEY))
                                mutt_any_key_to_continue (NULL);
                }
        }
}
示例#10
0
文件: socket.c 项目: darnir/neomutt
/**
 * socket_preconnect - Execute a command before opening a socket
 * @retval 0  Success
 * @retval >0 An errno, e.g. EPERM
 */
static int socket_preconnect(void)
{
  if (!C_Preconnect)
    return 0;

  mutt_debug(LL_DEBUG2, "Executing preconnect: %s\n", C_Preconnect);
  const int rc = mutt_system(C_Preconnect);
  mutt_debug(LL_DEBUG2, "Preconnect result: %d\n", rc);
  if (rc != 0)
  {
    const int save_errno = errno;
    mutt_perror(_("Preconnect command failed"));

    return save_errno;
  }

  return 0;
}
示例#11
0
void pgp_invoke_getkeys (ADDRESS * addr)
{
  char buff[LONG_STRING];
  char tmp[LONG_STRING];
  char cmd[HUGE_STRING];
  int devnull;

  char *personal;

  struct pgp_command_context cctx;

  if (!PgpGetkeysCommand)
    return;

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

  personal = addr->personal;
  addr->personal = NULL;

  *tmp = '\0';
  mutt_addrlist_to_local (addr);
  rfc822_write_address_single (tmp, sizeof (tmp), addr, 0);
  mutt_quote_filename (buff, sizeof (buff), tmp);

  addr->personal = personal;

  cctx.ids = buff;

  mutt_pgp_command (cmd, sizeof (cmd), &cctx, PgpGetkeysCommand);

  devnull = open ("/dev/null", O_RDWR);

  if (!isendwin ())
    mutt_message _("Fetching PGP key...");

  mutt_system (cmd);

  if (!isendwin ())
    mutt_clear_error ();

  close (devnull);
}
示例#12
0
static int socket_preconnect (void)
{
        int rc;
        int save_errno;

        if (mutt_strlen (Preconnect)) {
                dprint (2, (debugfile, "Executing preconnect: %s\n", Preconnect));
                rc = mutt_system (Preconnect);
                dprint (2, (debugfile, "Preconnect result: %d\n", rc));
                if (rc) {
                        save_errno = errno;
                        mutt_perror (_("Preconnect command failed."));
                        mutt_sleep (1);

                        return save_errno;
                }
        }

        return 0;
}
示例#13
0
int mutt_open_read_compressed (CONTEXT * ctx)
{
    char *cmd;
    FILE *fp;
    int rc;

    COMPRESS_INFO *ci = set_compress_info (ctx);

    if (!ci->open) {
        ctx->magic = 0;
        mem_free (ctx->compressinfo);
        return (-1);
    }
    if (!ci->close || access (ctx->path, W_OK) != 0)
        ctx->readonly = 1;

    set_path (ctx);
    store_size (ctx);

    if (!ctx->quiet)
        mutt_message (_("Decompressing %s..."), ctx->realpath);

    cmd = get_compression_cmd (ci->open, ctx);
    if (cmd == NULL)
        return (-1);
    debug_print (2, ("DecompressCmd: '%s'\n", cmd));

    if ((fp = fopen (ctx->realpath, "r")) == NULL) {
        mutt_perror (ctx->realpath);
        mem_free (&cmd);
        return (-1);
    }
    mutt_block_signals ();
    if (mbox_lock_compressed (ctx, fp, 0, 1) == -1) {
        fclose (fp);
        mutt_unblock_signals ();
        mutt_error _("Unable to lock mailbox!");

        mem_free (&cmd);
        return (-1);
    }

    endwin ();
    fflush (stdout);
    sprintf (echo_cmd, _("echo Decompressing %s..."), ctx->realpath);
    mutt_system (echo_cmd);
    rc = mutt_system (cmd);
    mbox_unlock_compressed (ctx, fp);
    mutt_unblock_signals ();
    fclose (fp);

    if (rc) {
        mutt_any_key_to_continue (NULL);
        ctx->magic = 0;
        mem_free (ctx->compressinfo);
        mutt_error (_("Error executing: %s : unable to open the mailbox!\n"),
                    cmd);
    }
    mem_free (&cmd);
    if (rc)
        return (-1);

    if (mutt_check_mailbox_compressed (ctx))
        return (-1);

    ctx->magic = mx_get_magic (ctx->path);

    return (0);
}
示例#14
0
static int rfc1524_mailcap_parse (BODY *a,
				  char *filename,
				  char *type, 
				  rfc1524_entry *entry,
				  int opt)
{
  FILE *fp;
  char *buf = NULL;
  size_t buflen;
  char *ch;
  char *field;
  int found = FALSE;
  int copiousoutput;
  int composecommand;
  int editcommand;
  int printcommand;
  int btlen;
  int line = 0;

  /* rfc1524 mailcap file is of the format:
   * base/type; command; extradefs
   * type can be * for matching all
   * base with no /type is an implicit wild
   * command contains a %s for the filename to pass, default to pipe on stdin
   * extradefs are of the form:
   *  def1="definition"; def2="define \;";
   * line wraps with a \ at the end of the line
   * # for comments
   */

  /* find length of basetype */
  if ((ch = strchr (type, '/')) == NULL)
    return FALSE;
  btlen = ch - type;

  if ((fp = fopen (filename, "r")) != NULL)
  {
    while (!found && (buf = mutt_read_line (buf, &buflen, fp, &line, M_CONT)) != NULL)
    {
      /* ignore comments */
      if (*buf == '#')
	continue;
      dprint (2, (debugfile, "mailcap entry: %s\n", buf));

      /* check type */
      ch = get_field (buf);
      if (ascii_strcasecmp (buf, type) &&
	  (ascii_strncasecmp (buf, type, btlen) ||
	   (buf[btlen] != 0 &&			/* implicit wild */
	    mutt_strcmp (buf + btlen, "/*"))))	/* wildsubtype */
	continue;

      /* next field is the viewcommand */
      field = ch;
      ch = get_field (ch);
      if (entry)
	entry->command = safe_strdup (field);

      /* parse the optional fields */
      found = TRUE;
      copiousoutput = FALSE;
      composecommand = FALSE;
      editcommand = FALSE;
      printcommand = FALSE;

      while (ch)
      {
	field = ch;
	ch = get_field (ch);
	dprint (2, (debugfile, "field: %s\n", field));

	if (!ascii_strcasecmp (field, "needsterminal"))
	{
	  if (entry)
	    entry->needsterminal = TRUE;
	}
	else if (!ascii_strcasecmp (field, "copiousoutput"))
	{
	  copiousoutput = TRUE;
	  if (entry)
	    entry->copiousoutput = TRUE;
	}
	else if (!ascii_strncasecmp (field, "composetyped", 12))
	{
	  /* this compare most occur before compose to match correctly */
	  if (get_field_text (field + 12, entry ? &entry->composetypecommand : NULL,
			      type, filename, line))
	    composecommand = TRUE;
	}
	else if (!ascii_strncasecmp (field, "compose", 7))
	{
	  if (get_field_text (field + 7, entry ? &entry->composecommand : NULL,
			      type, filename, line))
	    composecommand = TRUE;
	}
	else if (!ascii_strncasecmp (field, "print", 5))
	{
	  if (get_field_text (field + 5, entry ? &entry->printcommand : NULL,
			      type, filename, line))
	    printcommand = TRUE;
	}
	else if (!ascii_strncasecmp (field, "edit", 4))
	{
	  if (get_field_text (field + 4, entry ? &entry->editcommand : NULL,
			      type, filename, line))
	    editcommand = TRUE;
	}
	else if (!ascii_strncasecmp (field, "nametemplate", 12))
	{
	  get_field_text (field + 12, entry ? &entry->nametemplate : NULL,
			  type, filename, line);
	}
	else if (!ascii_strncasecmp (field, "x-convert", 9))
	{
	  get_field_text (field + 9, entry ? &entry->convert : NULL,
			  type, filename, line);
	}
	else if (!ascii_strncasecmp (field, "test", 4))
	{
	  /* 
	   * This routine executes the given test command to determine
	   * if this is the right entry.
	   */
	  char *test_command = NULL;
	  size_t len;

	  if (get_field_text (field + 4, &test_command, type, filename, line)
	      && test_command)
	  {
	    len = mutt_strlen (test_command) + STRING;
	    safe_realloc (&test_command, len);
	    rfc1524_expand_command (a, a->filename, type, test_command, len);
	    if (mutt_system (test_command))
	    {
	      /* a non-zero exit code means test failed */
	      found = FALSE;
	    }
	    FREE (&test_command);
	  }
	}
      } /* while (ch) */

      if (opt == M_AUTOVIEW)
      {
	if (!copiousoutput)
	  found = FALSE;
      }
      else if (opt == M_COMPOSE)
      {
	if (!composecommand)
	  found = FALSE;
      }
      else if (opt == M_EDIT)
      {
	if (!editcommand)
	  found = FALSE;
      }
      else if (opt == M_PRINT)
      {
	if (!printcommand)
	  found = FALSE;
      }
      
      if (!found)
      {
	/* reset */
	if (entry)
	{
	  FREE (&entry->command);
	  FREE (&entry->composecommand);
	  FREE (&entry->composetypecommand);
	  FREE (&entry->editcommand);
	  FREE (&entry->printcommand);
	  FREE (&entry->nametemplate);
	  FREE (&entry->convert);
	  entry->needsterminal = 0;
	  entry->copiousoutput = 0;
	}
      }
    } /* while (!found && (buf = mutt_read_line ())) */
    safe_fclose (&fp);
  } /* if ((fp = fopen ())) */
  FREE (&buf);
  return found;
}
示例#15
0
int mutt_print_attachment (FILE *fp, BODY *a)
{
  char newfile[_POSIX_PATH_MAX] = "";
  char type[STRING];
  pid_t thepid;
  FILE *ifp, *fpout;
  short unlink_newfile = 0;
  
  snprintf (type, sizeof (type), "%s/%s", TYPE (a), a->subtype);

  if (rfc1524_mailcap_lookup (a, type, NULL, M_PRINT)) 
  {
    char command[_POSIX_PATH_MAX+STRING];
    rfc1524_entry *entry;
    int piped = FALSE;

    dprint (2, (debugfile, "Using mailcap...\n"));
    
    entry = rfc1524_new_entry ();
    rfc1524_mailcap_lookup (a, type, entry, M_PRINT);
    if (rfc1524_expand_filename (entry->nametemplate, a->filename,
						  newfile, sizeof (newfile)))
    {
      if (!fp)
      {
	if (safe_symlink(a->filename, newfile) == -1)
	{
	  if (mutt_yesorno (_("Can't match nametemplate, continue?"), M_YES) != M_YES)
	  {
	    rfc1524_free_entry (&entry);
	    return 0;
	  }
	  strfcpy (newfile, a->filename, sizeof (newfile));
	}
	else
	  unlink_newfile = 1;
      }
    }

    /* in recv mode, save file to newfile first */
    if (fp)
      mutt_save_attachment (fp, a, newfile, 0, NULL);

    strfcpy (command, entry->printcommand, sizeof (command));
    piped = rfc1524_expand_command (a, newfile, type, command, sizeof (command));

    mutt_endwin (NULL);

    /* interactive program */
    if (piped)
    {
      if ((ifp = fopen (newfile, "r")) == NULL)
      {
	mutt_perror ("fopen");
	rfc1524_free_entry (&entry);
	return (0);
      }

      if ((thepid = mutt_create_filter (command, &fpout, NULL, NULL)) < 0)
      {
	mutt_perror _("Can't create filter");
	rfc1524_free_entry (&entry);
	safe_fclose (&ifp);
	return 0;
      }
      mutt_copy_stream (ifp, fpout);
      safe_fclose (&fpout);
      safe_fclose (&ifp);
      if (mutt_wait_filter (thepid) || option (OPTWAITKEY))
	mutt_any_key_to_continue (NULL);
    }
    else
    {
      if (mutt_system (command) || option (OPTWAITKEY))
	mutt_any_key_to_continue (NULL);
    }

    if (fp)
      mutt_unlink (newfile);
    else if (unlink_newfile)
      unlink(newfile);

    rfc1524_free_entry (&entry);
    return (1);
  }

  if (!ascii_strcasecmp ("text/plain", type) ||
      !ascii_strcasecmp ("application/postscript", type))
  {
    return (mutt_pipe_attachment (fp, a, NONULL(PrintCmd), NULL));
  }
  else if (mutt_can_decode (a))
  {
    /* decode and print */

    int rc = 0;
    
    ifp = NULL;
    fpout = NULL;
    
    mutt_mktemp (newfile, sizeof (newfile));
    if (mutt_decode_save_attachment (fp, a, newfile, M_PRINTING, 0) == 0)
    {
      
      dprint (2, (debugfile, "successfully decoded %s type attachment to %s\n",
		  type, newfile));
      
      if ((ifp = fopen (newfile, "r")) == NULL)
      {
	mutt_perror ("fopen");
	goto bail0;
      }

      dprint (2, (debugfile, "successfully opened %s read-only\n", newfile));
      
      mutt_endwin (NULL);
      if ((thepid = mutt_create_filter (NONULL(PrintCmd), &fpout, NULL, NULL)) < 0)
      {
	mutt_perror _("Can't create filter");
	goto bail0;
      }

      dprint (2, (debugfile, "Filter created.\n"));
      
      mutt_copy_stream (ifp, fpout);

      safe_fclose (&fpout);
      safe_fclose (&ifp);

      if (mutt_wait_filter (thepid) != 0 || option (OPTWAITKEY))
	mutt_any_key_to_continue (NULL);
      rc = 1;
    }
  bail0:
    safe_fclose (&ifp);
    safe_fclose (&fpout);
    mutt_unlink (newfile);
    return rc;
  }
  else
  {
    mutt_error _("I don't know how to print that!");
    return 0;
  }
}
示例#16
0
/* return 1 if require full screen redraw, 0 otherwise */
int mutt_compose_attachment (BODY *a)
{
  char type[STRING];
  char command[STRING];
  char newfile[_POSIX_PATH_MAX] = "";
  rfc1524_entry *entry = rfc1524_new_entry ();
  short unlink_newfile = 0;
  int rc = 0;
  
  snprintf (type, sizeof (type), "%s/%s", TYPE (a), a->subtype);
  if (rfc1524_mailcap_lookup (a, type, entry, M_COMPOSE))
  {
    if (entry->composecommand || entry->composetypecommand)
    {

      if (entry->composetypecommand)
	strfcpy (command, entry->composetypecommand, sizeof (command));
      else 
	strfcpy (command, entry->composecommand, sizeof (command));
      if (rfc1524_expand_filename (entry->nametemplate,
				      a->filename, newfile, sizeof (newfile)))
      {
	dprint(1, (debugfile, "oldfile: %s\t newfile: %s\n",
				  a->filename, newfile));
	if (safe_symlink (a->filename, newfile) == -1)
	{
	  if (mutt_yesorno (_("Can't match nametemplate, continue?"), M_YES) != M_YES)
	    goto bailout;
	}
	else
	  unlink_newfile = 1;
      }
      else
	strfcpy(newfile, a->filename, sizeof(newfile));
      
      if (rfc1524_expand_command (a, newfile, type,
				      command, sizeof (command)))
      {
	/* For now, editing requires a file, no piping */
	mutt_error _("Mailcap compose entry requires %%s");
      }
      else
      {
	int r;

	mutt_endwin (NULL);
	if ((r = mutt_system (command)) == -1)
	  mutt_error (_("Error running \"%s\"!"), command);
	
	if (r != -1 && entry->composetypecommand)
	{
	  BODY *b;
	  FILE *fp, *tfp;
	  char tempfile[_POSIX_PATH_MAX];

	  if ((fp = safe_fopen (a->filename, "r")) == NULL)
	  {
	    mutt_perror _("Failure to open file to parse headers.");
	    goto bailout;
	  }

	  b = mutt_read_mime_header (fp, 0);
	  if (b)
	  {
	    if (b->parameter)
	    {
	      mutt_free_parameter (&a->parameter);
	      a->parameter = b->parameter;
	      b->parameter = NULL;
	    }
	    if (b->description) {
	      FREE (&a->description);
	      a->description = b->description;
	      b->description = NULL;
	    }
	    if (b->form_name)
	    {
	      FREE (&a->form_name);
	      a->form_name = b->form_name;
	      b->form_name = NULL;
	    }

	    /* Remove headers by copying out data to another file, then 
	     * copying the file back */
	    fseeko (fp, b->offset, 0);
	    mutt_mktemp (tempfile, sizeof (tempfile));
	    if ((tfp = safe_fopen (tempfile, "w")) == NULL)
	    {
	      mutt_perror _("Failure to open file to strip headers.");
	      goto bailout;
	    }
	    mutt_copy_stream (fp, tfp);
	    safe_fclose (&fp);
	    safe_fclose (&tfp);
	    mutt_unlink (a->filename);  
	    if (mutt_rename_file (tempfile, a->filename) != 0) 
	    {
	      mutt_perror _("Failure to rename file.");
	      goto bailout;
	    }

	    mutt_free_body (&b);
	  }
	}
      }
    }
  }
  else
  {
    rfc1524_free_entry (&entry);
    mutt_message (_("No mailcap compose entry for %s, creating empty file."),
		   type);
    return 1;
  }

  rc = 1;
  
  bailout:
  
  if(unlink_newfile)
    unlink(newfile);

  rfc1524_free_entry (&entry);
  return rc;
}
示例#17
0
/* returns -1 on error, 0 or the return code from mutt_do_pager() on success */
int mutt_view_attachment (FILE *fp, BODY *a, int flag, HEADER *hdr,
			  ATTACHPTR **idx, short idxlen)
{
  char tempfile[_POSIX_PATH_MAX] = "";
  char pagerfile[_POSIX_PATH_MAX] = "";
  int is_message;
  int use_mailcap;
  int use_pipe = 0;
  int use_pager = 1;
  char type[STRING];
  char command[HUGE_STRING];
  char descrip[STRING];
  char *fname;
  rfc1524_entry *entry = NULL;
  int rc = -1;
  int unlink_tempfile = 0;
  
  is_message = mutt_is_message_type(a->type, a->subtype);
  if (WithCrypto && is_message && a->hdr && (a->hdr->security & ENCRYPT) &&
      !crypt_valid_passphrase(a->hdr->security))
    return (rc);
  use_mailcap = (flag == M_MAILCAP ||
		(flag == M_REGULAR && mutt_needs_mailcap (a)));
  snprintf (type, sizeof (type), "%s/%s", TYPE (a), a->subtype);
  
  if (use_mailcap)
  {
    entry = rfc1524_new_entry (); 
    if (!rfc1524_mailcap_lookup (a, type, entry, 0))
    {
      if (flag == M_REGULAR)
      {
	/* fallback to view as text */
	rfc1524_free_entry (&entry);
	mutt_error _("No matching mailcap entry found.  Viewing as text.");
	flag = M_AS_TEXT;
	use_mailcap = 0;
      }
      else
	goto return_error;
    }
  }
  
  if (use_mailcap)
  {
    if (!entry->command)
    {
      mutt_error _("MIME type not defined.  Cannot view attachment.");
      goto return_error;
    }
    strfcpy (command, entry->command, sizeof (command));
    
    if (fp)
    {
      fname = safe_strdup (a->filename);
      mutt_sanitize_filename (fname, 1);
    }
    else
      fname = a->filename;

    if (rfc1524_expand_filename (entry->nametemplate, fname,
				 tempfile, sizeof (tempfile)))
    {
      if (fp == NULL && mutt_strcmp(tempfile, a->filename))
      {
	/* send case: the file is already there */
	if (safe_symlink (a->filename, tempfile) == -1)
	{
	  if (mutt_yesorno (_("Can't match nametemplate, continue?"), M_YES) == M_YES)
	    strfcpy (tempfile, a->filename, sizeof (tempfile));
	  else
	    goto return_error;
	}
	else
	  unlink_tempfile = 1;
      }
    }
    else if (fp == NULL) /* send case */
      strfcpy (tempfile, a->filename, sizeof (tempfile));
    
    if (fp)
    {
      /* recv case: we need to save the attachment to a file */
      FREE (&fname);
      if (mutt_save_attachment (fp, a, tempfile, 0, NULL) == -1)
	goto return_error;
    }

    use_pipe = rfc1524_expand_command (a, tempfile, type,
				       command, sizeof (command));
    use_pager = entry->copiousoutput;
  }
  
  if (use_pager)
  {
    if (fp && !use_mailcap && a->filename)
    {
      /* recv case */
      strfcpy (pagerfile, a->filename, sizeof (pagerfile));
      mutt_adv_mktemp (pagerfile, sizeof(pagerfile));
    }
    else
      mutt_mktemp (pagerfile, sizeof (pagerfile));
  }
    
  if (use_mailcap)
  {
    pid_t thepid = 0;
    int tempfd = -1, pagerfd = -1;
    
    if (!use_pager)
      mutt_endwin (NULL);

    if (use_pager || use_pipe)
    {
      if (use_pager && ((pagerfd = safe_open (pagerfile, O_CREAT | O_EXCL | O_WRONLY)) == -1))
      {
	mutt_perror ("open");
	goto return_error;
      }
      if (use_pipe && ((tempfd = open (tempfile, 0)) == -1))
      {
	if(pagerfd != -1)
	  close(pagerfd);
	mutt_perror ("open");
	goto return_error;
      }

      if ((thepid = mutt_create_filter_fd (command, NULL, NULL, NULL,
					   use_pipe ? tempfd : -1, use_pager ? pagerfd : -1, -1)) == -1)
      {
	if(pagerfd != -1)
	  close(pagerfd);
	
	if(tempfd != -1)
	  close(tempfd);

	mutt_error _("Cannot create filter");
	goto return_error;
      }

      if (use_pager)
      {
	if (a->description)
	  snprintf (descrip, sizeof (descrip),
		    _("---Command: %-20.20s Description: %s"),
		    command, a->description);
	else
	  snprintf (descrip, sizeof (descrip),
		    _("---Command: %-30.30s Attachment: %s"), command, type);
      }

      if ((mutt_wait_filter (thepid) || (entry->needsterminal &&
	  option (OPTWAITKEY))) && !use_pager)
	mutt_any_key_to_continue (NULL);

      if (tempfd != -1)
	close (tempfd);
      if (pagerfd != -1)
	close (pagerfd);
    }
    else
    {
      /* interactive command */
      if (mutt_system (command) ||
	  (entry->needsterminal && option (OPTWAITKEY)))
	mutt_any_key_to_continue (NULL);
    }
  }
  else
  {
    /* Don't use mailcap; the attachment is viewed in the pager */

    if (flag == M_AS_TEXT)
    {
      /* just let me see the raw data */
      if (mutt_save_attachment (fp, a, pagerfile, 0, NULL))
	goto return_error;
    }
    else
    {
      /* Use built-in handler */
      set_option (OPTVIEWATTACH); /* disable the "use 'v' to view this part"
				   * message in case of error */
      if (mutt_decode_save_attachment (fp, a, pagerfile, M_DISPLAY, 0))
      {
	unset_option (OPTVIEWATTACH);
	goto return_error;
      }
      unset_option (OPTVIEWATTACH);
    }
    
    if (a->description)
      strfcpy (descrip, a->description, sizeof (descrip));
    else if (a->filename)
      snprintf (descrip, sizeof (descrip), _("---Attachment: %s: %s"),
	  a->filename, type);
    else
      snprintf (descrip, sizeof (descrip), _("---Attachment: %s"), type);
  }
  
  /* We only reach this point if there have been no errors */

  if (use_pager)
  {
    pager_t info;
    
    memset (&info, 0, sizeof (info));
    info.fp = fp;
    info.bdy = a;
    info.ctx = Context;
    info.idx = idx;
    info.idxlen = idxlen;
    info.hdr = hdr;

    rc = mutt_do_pager (descrip, pagerfile,
			M_PAGER_ATTACHMENT | (is_message ? M_PAGER_MESSAGE : 0), &info);
    *pagerfile = '\0';
  }
  else
    rc = 0;

  return_error:
  
  if (entry)
    rfc1524_free_entry (&entry);
  if (fp && tempfile[0])
    mutt_unlink (tempfile);
  else if (unlink_tempfile)
    unlink(tempfile);

  if (pagerfile[0])
    mutt_unlink (pagerfile);

  return rc;
}
示例#18
0
/* 
 * Currently, this only works for send mode, as it assumes that the 
 * BODY->filename actually contains the information.  I'm not sure
 * we want to deal with editing attachments we've already received,
 * so this should be ok.
 *
 * Returns 1 if editor found, 0 if not (useful to tell calling menu to
 * redraw)
 */
int mutt_edit_attachment (BODY *a)
{
  char type[STRING];
  char command[STRING];
  char newfile[_POSIX_PATH_MAX] = "";
  rfc1524_entry *entry = rfc1524_new_entry ();
  short unlink_newfile = 0;
  int rc = 0;
  
  snprintf (type, sizeof (type), "%s/%s", TYPE (a), a->subtype);
  if (rfc1524_mailcap_lookup (a, type, entry, M_EDIT))
  {
    if (entry->editcommand)
    {

      strfcpy (command, entry->editcommand, sizeof (command));
      if (rfc1524_expand_filename (entry->nametemplate,
				      a->filename, newfile, sizeof (newfile)))
      {
	dprint(1, (debugfile, "oldfile: %s\t newfile: %s\n",
				  a->filename, newfile));
	if (safe_symlink (a->filename, newfile) == -1)
	{
	  if (mutt_yesorno (_("Can't match nametemplate, continue?"), M_YES) != M_YES)
	    goto bailout;
	}
	else
	  unlink_newfile = 1;
      }
      else
	strfcpy(newfile, a->filename, sizeof(newfile));

      if (rfc1524_expand_command (a, newfile, type,
				      command, sizeof (command)))
      {
	/* For now, editing requires a file, no piping */
	mutt_error _("Mailcap Edit entry requires %%s");
        goto bailout;
      }
      else
      {
	mutt_endwin (NULL);
	if (mutt_system (command) == -1)
        {
	  mutt_error (_("Error running \"%s\"!"), command);
          goto bailout;
        }
      }
    }
  }
  else if (a->type == TYPETEXT)
  {
    /* On text, default to editor */
    mutt_edit_file (NONULL (Editor), a->filename);
  }
  else
  {
    rfc1524_free_entry (&entry);
    mutt_error (_("No mailcap edit entry for %s"),type);
    return 0;
  }

  rc = 1;
  
  bailout:
  
  if(unlink_newfile)
    unlink(newfile);
  
  rfc1524_free_entry (&entry);
  return rc;
}
示例#19
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;
}
示例#20
0
int mutt_slow_close_compressed (CONTEXT * ctx)
{
    FILE *fp;
    const char *append;
    char *cmd;
    COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compressinfo;

    debug_print (2, ("called on '%s'\n", ctx->path));

    if (!(ctx->append && ((append = get_append_command (ctx->realpath, ctx))
                          || (append = ci->close)))) {
        /* if we can not or should not append,
                                         * we only have to remove the compressed info, because sync was already
                                         * called
                                         */
        mutt_fast_close_compressed (ctx);
        return (0);
    }

    if (ctx->fp)
        fclose (ctx->fp);
    ctx->fp = NULL;

    if (!ctx->quiet) {
        if (append == ci->close)
            mutt_message (_("Compressing %s..."), ctx->realpath);
        else
            mutt_message (_("Compressed-appending to %s..."), ctx->realpath);
    }

    cmd = get_compression_cmd (append, ctx);
    if (cmd == NULL)
        return (-1);

    if ((fp = fopen (ctx->realpath, "a")) == NULL) {
        mutt_perror (ctx->realpath);
        mem_free (&cmd);
        return (-1);
    }
    mutt_block_signals ();
    if (mbox_lock_compressed (ctx, fp, 1, 1) == -1) {
        fclose (fp);
        mutt_unblock_signals ();
        mutt_error _("Unable to lock mailbox!");

        mem_free (&cmd);
        return (-1);
    }

    debug_print (2, ("CompressCmd: '%s'\n", cmd));

    endwin ();
    fflush (stdout);

    if (append == ci->close)
        sprintf (echo_cmd, _("echo Compressing %s..."), ctx->realpath);
    else
        sprintf (echo_cmd, _("echo Compressed-appending to %s..."),
                 ctx->realpath);
    mutt_system (echo_cmd);

    if (mutt_system (cmd)) {
        mutt_any_key_to_continue (NULL);
        mutt_error (_
                    (" %s: Error compressing mailbox!  Uncompressed one kept!\n"),
                    ctx->path);
        mem_free (&cmd);
        mbox_unlock_compressed (ctx, fp);
        mutt_unblock_signals ();
        fclose (fp);
        return (-1);
    }

    mbox_unlock_compressed (ctx, fp);
    mutt_unblock_signals ();
    fclose (fp);
    remove_file (ctx);
    restore_path (ctx);
    mem_free (&cmd);
    mem_free (&ctx->compressinfo);

    return (0);
}
示例#21
0
/* return values:
 *
 * 1	message should be postponed
 * 0	normal exit
 * -1	abort message
 */
int mutt_compose_menu (HEADER *msg,   /* structure for new message */
                       char *fcc,     /* where to save a copy of the message */
                       size_t fcclen,
                       HEADER *cur,   /* current message */
                       int flags)
{
  char helpstr[LONG_STRING];
  char buf[LONG_STRING];
  char fname[_POSIX_PATH_MAX];
  MUTTMENU *menu;
  ATTACHPTR **idx = NULL;
  short idxlen = 0;
  short idxmax = 0;
  int i, close = 0;
  int r = -1;		/* return value */
  int op = 0;
  int loop = 1;
  int fccSet = 0;	/* has the user edited the Fcc: field ? */
  CONTEXT *ctx = NULL, *this = NULL;
  /* Sort, SortAux could be changed in mutt_index_menu() */
  int oldSort, oldSortAux;
  struct stat st;

  mutt_attach_init (msg->content);
  idx = mutt_gen_attach_list (msg->content, -1, idx, &idxlen, &idxmax, 0, 1);

  menu = mutt_new_menu (MENU_COMPOSE);
  menu->offset = HDR_ATTACH;
  menu->max = idxlen;
  menu->make_entry = snd_entry;
  menu->tag = mutt_tag_attach;
  menu->data = idx;
  menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_COMPOSE, ComposeHelp);
  
  while (loop)
  {
    switch (op = mutt_menuLoop (menu))
    {
      case OP_REDRAW:
	draw_envelope (msg, fcc);
	menu->offset = HDR_ATTACH;
	menu->pagelen = LINES - HDR_ATTACH - 2;
	break;
      case OP_COMPOSE_EDIT_FROM:
	menu->redraw = edit_address_list (HDR_FROM, &msg->env->from);
        mutt_message_hook (NULL, msg, M_SEND2HOOK);
	break;
      case OP_COMPOSE_EDIT_TO:
	menu->redraw = edit_address_list (HDR_TO, &msg->env->to);
	if (option (OPTCRYPTOPPORTUNISTICENCRYPT))
	{
	  crypt_opportunistic_encrypt (msg);
	  redraw_crypt_lines (msg);
	}
        mutt_message_hook (NULL, msg, M_SEND2HOOK);
        break;
      case OP_COMPOSE_EDIT_BCC:
	menu->redraw = edit_address_list (HDR_BCC, &msg->env->bcc);
	if (option (OPTCRYPTOPPORTUNISTICENCRYPT))
	{
	  crypt_opportunistic_encrypt (msg);
	  redraw_crypt_lines (msg);
	}
        mutt_message_hook (NULL, msg, M_SEND2HOOK);
	break;
      case OP_COMPOSE_EDIT_CC:
	menu->redraw = edit_address_list (HDR_CC, &msg->env->cc);
	if (option (OPTCRYPTOPPORTUNISTICENCRYPT))
	{
	  crypt_opportunistic_encrypt (msg);
	  redraw_crypt_lines (msg);
	}
        mutt_message_hook (NULL, msg, M_SEND2HOOK);	
        break;
      case OP_COMPOSE_EDIT_SUBJECT:
	if (msg->env->subject)
	  strfcpy (buf, msg->env->subject, sizeof (buf));
	else
	  buf[0] = 0;
	if (mutt_get_field ("Subject: ", buf, sizeof (buf), 0) == 0)
	{
	  mutt_str_replace (&msg->env->subject, buf);
	  move (HDR_SUBJECT, HDR_XOFFSET);
	  if (msg->env->subject)
	    mutt_paddstr (W, msg->env->subject);
	  else
	    clrtoeol();
	}
        mutt_message_hook (NULL, msg, M_SEND2HOOK);
        break;
      case OP_COMPOSE_EDIT_REPLY_TO:
	menu->redraw = edit_address_list (HDR_REPLYTO, &msg->env->reply_to);
        mutt_message_hook (NULL, msg, M_SEND2HOOK);
	break;
      case OP_COMPOSE_EDIT_FCC:
	strfcpy (buf, fcc, sizeof (buf));
	if (mutt_get_field ("Fcc: ", buf, sizeof (buf), M_FILE | M_CLEAR) == 0)
	{
	  strfcpy (fcc, buf, fcclen);
	  mutt_pretty_mailbox (fcc, fcclen);
	  move (HDR_FCC, HDR_XOFFSET);
	  mutt_paddstr (W, fcc);
	  fccSet = 1;
	}
	MAYBE_REDRAW (menu->redraw);
        mutt_message_hook (NULL, msg, M_SEND2HOOK);
        break;
      case OP_COMPOSE_EDIT_MESSAGE:
	if (Editor && (mutt_strcmp ("builtin", Editor) != 0) && !option (OPTEDITHDRS))
	{
	  mutt_edit_file (Editor, msg->content->filename);
	  mutt_update_encoding (msg->content);
	  menu->redraw = REDRAW_FULL;
	  mutt_message_hook (NULL, msg, M_SEND2HOOK);
	  break;
	}
	/* fall through */
      case OP_COMPOSE_EDIT_HEADERS:
	if (mutt_strcmp ("builtin", Editor) != 0 &&
	    (op == OP_COMPOSE_EDIT_HEADERS ||
	    (op == OP_COMPOSE_EDIT_MESSAGE && option (OPTEDITHDRS))))
	{
	  char *tag = NULL, *err = NULL;
	  mutt_env_to_local (msg->env);
	  mutt_edit_headers (NONULL (Editor), msg->content->filename, msg,
			     fcc, fcclen);
	  if (mutt_env_to_intl (msg->env, &tag, &err))
	  {
	    mutt_error (_("Bad IDN in \"%s\": '%s'"), tag, err);
	    FREE (&err);
	  }
	  if (option (OPTCRYPTOPPORTUNISTICENCRYPT))
	    crypt_opportunistic_encrypt (msg);
	}
	else
	{
	  /* this is grouped with OP_COMPOSE_EDIT_HEADERS because the
	     attachment list could change if the user invokes ~v to edit
	     the message with headers, in which we need to execute the
	     code below to regenerate the index array */
	  mutt_builtin_editor (msg->content->filename, msg, cur);
	}
	mutt_update_encoding (msg->content);

	/* attachments may have been added */
	if (idxlen && idx[idxlen - 1]->content->next)
	{
	  for (i = 0; i < idxlen; i++)
          {
            FREE (&idx[i]->tree);
	    FREE (&idx[i]);
          }
	  idxlen = 0;
	  idx = mutt_gen_attach_list (msg->content, -1, idx, &idxlen, &idxmax, 0, 1);
	  menu->data = idx;
	  menu->max = idxlen;
	}

        menu->redraw = REDRAW_FULL;
        mutt_message_hook (NULL, msg, M_SEND2HOOK);
	break;



      case OP_COMPOSE_ATTACH_KEY:
        if (!(WithCrypto & APPLICATION_PGP))
          break;       
	if (idxlen == idxmax)
        {
	  safe_realloc (&idx, sizeof (ATTACHPTR *) * (idxmax += 5));
	  menu->data = idx;
	}
	
	idx[idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR));
	if ((idx[idxlen]->content = crypt_pgp_make_key_attachment(NULL)) != NULL)
	{
	  update_idx (menu, idx, idxlen++);
	  menu->redraw |= REDRAW_INDEX;
	}
	else
	  FREE (&idx[idxlen]);

	menu->redraw |= REDRAW_STATUS;

	if (option(OPTNEEDREDRAW))
	{
	  menu->redraw = REDRAW_FULL;
	  unset_option(OPTNEEDREDRAW);
	}
	
        mutt_message_hook (NULL, msg, M_SEND2HOOK);
        break;


      case OP_COMPOSE_ATTACH_FILE:
	{
	  char *prompt, **files;
	  int error, numfiles;

	  fname[0] = 0;
	  prompt = _("Attach file");
	  numfiles = 0;
	  files = NULL;

	  if (_mutt_enter_fname (prompt, fname, sizeof (fname), &menu->redraw, 0, 1, &files, &numfiles) == -1 ||
	      *fname == '\0')
	    break;

	  if (idxlen + numfiles >= idxmax)
	  {
	    safe_realloc (&idx, sizeof (ATTACHPTR *) * (idxmax += 5 + numfiles));
	    menu->data = idx;
	  }

	  error = 0;
	  if (numfiles > 1)
	    mutt_message _("Attaching selected files...");
	  for (i = 0; i < numfiles; i++)
	  {
	    char *att = files[i];
	    idx[idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR));
            idx[idxlen]->unowned = 1;
	    idx[idxlen]->content = mutt_make_file_attach (att);
	    if (idx[idxlen]->content != NULL)
	      update_idx (menu, idx, idxlen++);
	    else
	    {
	      error = 1;
	      mutt_error (_("Unable to attach %s!"), att);
	      FREE (&idx[idxlen]);
	    }
	  }
	  
	  FREE (&files);
	  if (!error) mutt_clear_error ();

	  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
	}
        mutt_message_hook (NULL, msg, M_SEND2HOOK);
        break;

      case OP_COMPOSE_ATTACH_MESSAGE:
	{
	  char *prompt;
	  HEADER *h;

	  fname[0] = 0;
	  prompt = _("Open mailbox to attach message from");

	  if (Context)
	  {
	    strfcpy (fname, NONULL (Context->path), sizeof (fname));
	    mutt_pretty_mailbox (fname, sizeof (fname));
	  }

	  if (mutt_enter_fname (prompt, fname, sizeof (fname), &menu->redraw, 1) == -1 || !fname[0])
	    break;

	  mutt_expand_path (fname, sizeof (fname));
#ifdef USE_IMAP
          if (!mx_is_imap (fname))
#endif
#ifdef USE_POP
          if (!mx_is_pop (fname))
#endif
	  /* check to make sure the file exists and is readable */
	  if (access (fname, R_OK) == -1)
	  {
	    mutt_perror (fname);
	    break;
	  }

	  menu->redraw = REDRAW_FULL;

	  ctx = mx_open_mailbox (fname, M_READONLY, NULL);
	  if (ctx == NULL)
	  {
	    mutt_error (_("Unable to open mailbox %s"), fname);
	    break;
	  }

	  if (!ctx->msgcount)
	  {
	    mx_close_mailbox (ctx, NULL);
	    FREE (&ctx);
	    mutt_error _("No messages in that folder.");
	    break;
	  }

	  this = Context; /* remember current folder and sort methods*/
	  oldSort = Sort; oldSortAux = SortAux;
	  
	  Context = ctx;
	  set_option(OPTATTACHMSG);
	  mutt_message _("Tag the messages you want to attach!");
	  close = mutt_index_menu ();
	  unset_option(OPTATTACHMSG);

	  if (!Context)
	  {
	    /* go back to the folder we started from */
	    Context = this;
	    /* Restore old $sort and $sort_aux */
	    Sort = oldSort;
	    SortAux = oldSortAux;
	    menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
	    break;
	  }

	  if (idxlen + Context->tagged >= idxmax)
	  {
	    safe_realloc (&idx, sizeof (ATTACHPTR *) * (idxmax += 5 + Context->tagged));
	    menu->data = idx;
	  }

	  for (i = 0; i < Context->msgcount; i++)
	  {
	    h = Context->hdrs[i];
	    if (h->tagged)
	    {
	      idx[idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR));
	      idx[idxlen]->content = mutt_make_message_attach (Context, h, 1);
	      if (idx[idxlen]->content != NULL)
		update_idx (menu, idx, idxlen++);
	      else
	      {
		mutt_error _("Unable to attach!");
		FREE (&idx[idxlen]);
	      }
	    }
	  }
	  menu->redraw |= REDRAW_FULL;

	  if (close == OP_QUIT) 
	    mx_close_mailbox (Context, NULL);
	  else
	    mx_fastclose_mailbox (Context);
	  FREE (&Context);

	  /* go back to the folder we started from */
	  Context = this;
	  /* Restore old $sort and $sort_aux */
	  Sort = oldSort;
	  SortAux = oldSortAux;
	}
        mutt_message_hook (NULL, msg, M_SEND2HOOK);
        break;

      case OP_DELETE:
	CHECK_COUNT;
        if (idx[menu->current]->unowned)
          idx[menu->current]->content->unlink = 0;
	if (delete_attachment (menu, &idxlen, menu->current) == -1)
	  break;
	mutt_update_tree (idx, idxlen);
	if (idxlen)
	{
	  if (menu->current > idxlen - 1)
	    menu->current = idxlen - 1;
	}
	else
	  menu->current = 0;

	if (menu->current == 0)
	  msg->content = idx[0]->content;

        menu->redraw |= REDRAW_STATUS;
        mutt_message_hook (NULL, msg, M_SEND2HOOK);
        break;

#define CURRENT idx[menu->current]->content
      
      case OP_COMPOSE_TOGGLE_RECODE:
      {      
        CHECK_COUNT;
        if (!mutt_is_text_part (CURRENT))
        {
	  mutt_error (_("Recoding only affects text attachments."));
	  break;
	}
        CURRENT->noconv = !CURRENT->noconv;
        if (CURRENT->noconv)
	  mutt_message (_("The current attachment won't be converted."));
        else
	  mutt_message (_("The current attachment will be converted."));
	menu->redraw = REDRAW_CURRENT;
        mutt_message_hook (NULL, msg, M_SEND2HOOK);
        break;
      }
#undef CURRENT

      case OP_COMPOSE_EDIT_DESCRIPTION:
	CHECK_COUNT;
	strfcpy (buf,
		 idx[menu->current]->content->description ?
		 idx[menu->current]->content->description : "",
		 sizeof (buf));
	/* header names should not be translated */
	if (mutt_get_field ("Description: ", buf, sizeof (buf), 0) == 0)
	{
	  mutt_str_replace (&idx[menu->current]->content->description, buf);
	  menu->redraw = REDRAW_CURRENT;
	}
        mutt_message_hook (NULL, msg, M_SEND2HOOK);
        break;

      case OP_COMPOSE_UPDATE_ENCODING:
        CHECK_COUNT;
        if (menu->tagprefix)
        {
	  BODY *top;
	  for (top = msg->content; top; top = top->next)
	  {
	    if (top->tagged)
	      mutt_update_encoding (top);
	  }
	  menu->redraw = REDRAW_FULL;
	}
        else
        {
          mutt_update_encoding(idx[menu->current]->content);
	  menu->redraw = REDRAW_CURRENT | REDRAW_STATUS;
	}
        mutt_message_hook (NULL, msg, M_SEND2HOOK);
        break;
      
      case OP_COMPOSE_TOGGLE_DISPOSITION:
	/* toggle the content-disposition between inline/attachment */
	idx[menu->current]->content->disposition = (idx[menu->current]->content->disposition == DISPINLINE) ? DISPATTACH : DISPINLINE;
	menu->redraw = REDRAW_CURRENT;
	break;

      case OP_EDIT_TYPE:
	CHECK_COUNT;
        {
	  mutt_edit_content_type (NULL, idx[menu->current]->content, NULL);

	  /* this may have been a change to text/something */
	  mutt_update_encoding (idx[menu->current]->content);

	  menu->redraw = REDRAW_CURRENT;
	}
        mutt_message_hook (NULL, msg, M_SEND2HOOK);
        break;

      case OP_COMPOSE_EDIT_ENCODING:
	CHECK_COUNT;
	strfcpy (buf, ENCODING (idx[menu->current]->content->encoding),
							      sizeof (buf));
	if (mutt_get_field ("Content-Transfer-Encoding: ", buf,
					    sizeof (buf), 0) == 0 && buf[0])
	{
	  if ((i = mutt_check_encoding (buf)) != ENCOTHER && i != ENCUUENCODED)
	  {
	    idx[menu->current]->content->encoding = i;
	    menu->redraw = REDRAW_CURRENT | REDRAW_STATUS;
	    mutt_clear_error();
	  }
	  else
	    mutt_error _("Invalid encoding.");
	}
        mutt_message_hook (NULL, msg, M_SEND2HOOK);
        break;

      case OP_COMPOSE_SEND_MESSAGE:

        /* Note: We don't invoke send2-hook here, since we want to leave
	 * users an opportunity to change settings from the ":" prompt.
	 */
      
        if(check_attachments(idx, idxlen) != 0)
        {
	  menu->redraw = REDRAW_FULL;
	  break;
	}

      
#ifdef MIXMASTER
        if (msg->chain && mix_check_message (msg) != 0)
	  break;
#endif
      
	if (!fccSet && *fcc)
	{
	  if ((i = query_quadoption (OPT_COPY,
				_("Save a copy of this message?"))) == -1)
	    break;
	  else if (i == M_NO)
	    *fcc = 0;
	}

	loop = 0;
	r = 0;
	break;

      case OP_COMPOSE_EDIT_FILE:
	CHECK_COUNT;
	mutt_edit_file (NONULL(Editor), idx[menu->current]->content->filename);
	mutt_update_encoding (idx[menu->current]->content);
	menu->redraw = REDRAW_CURRENT | REDRAW_STATUS;
        mutt_message_hook (NULL, msg, M_SEND2HOOK);
	break;

      case OP_COMPOSE_TOGGLE_UNLINK:
	CHECK_COUNT;
	idx[menu->current]->content->unlink = !idx[menu->current]->content->unlink;

#if 0
        /* OPTRESOLVE is otherwise ignored on this menu.
	 * Where's the bug?
	 */

        if (option (OPTRESOLVE) && menu->current + 1 < menu->max)
	  menu->current++;
# endif
	menu->redraw = REDRAW_INDEX;
        /* No send2hook since this doesn't change the message. */
	break;

      case OP_COMPOSE_GET_ATTACHMENT:
        CHECK_COUNT;
        if(menu->tagprefix)
        {
	  BODY *top;
	  for(top = msg->content; top; top = top->next)
	  {
	    if(top->tagged)
	      mutt_get_tmp_attachment(top);
	  }
	  menu->redraw = REDRAW_FULL;
	}
        else if (mutt_get_tmp_attachment(idx[menu->current]->content) == 0)
	  menu->redraw = REDRAW_CURRENT;

        /* No send2hook since this doesn't change the message. */
        break;
      
      case OP_COMPOSE_RENAME_FILE:
	CHECK_COUNT;
	strfcpy (fname, idx[menu->current]->content->filename, sizeof (fname));
	mutt_pretty_mailbox (fname, sizeof (fname));
	if (mutt_get_field (_("Rename to: "), fname, sizeof (fname), M_FILE)
							== 0 && fname[0])
	{
	  if (stat(idx[menu->current]->content->filename, &st) == -1)
	  {
            /* L10N:
               "stat" is a system call. Do "man 2 stat" for more information. */
	    mutt_error (_("Can't stat %s: %s"), fname, strerror (errno));
	    break;
	  }

	  mutt_expand_path (fname, sizeof (fname));
	  if(mutt_rename_file (idx[menu->current]->content->filename, fname))
	    break;
	  
	  mutt_str_replace (&idx[menu->current]->content->filename, fname);
	  menu->redraw = REDRAW_CURRENT;

	  if(idx[menu->current]->content->stamp >= st.st_mtime)
	    mutt_stamp_attachment(idx[menu->current]->content);
	  
	}
        mutt_message_hook (NULL, msg, M_SEND2HOOK);
        break;

      case OP_COMPOSE_NEW_MIME:
	{
	  char type[STRING];
	  char *p;
	  int itype;
	  FILE *fp;

	  CLEARLINE (LINES-1);
	  fname[0] = 0;
	  if (mutt_get_field (_("New file: "), fname, sizeof (fname), M_FILE)
	      != 0 || !fname[0])
	    continue;
	  mutt_expand_path (fname, sizeof (fname));

	  /* Call to lookup_mime_type () ?  maybe later */
	  type[0] = 0;
	  if (mutt_get_field ("Content-Type: ", type, sizeof (type), 0) != 0 
	      || !type[0])
	    continue;

	  if (!(p = strchr (type, '/')))
	  {
	    mutt_error _("Content-Type is of the form base/sub");
	    continue;
	  }
	  *p++ = 0;
	  if ((itype = mutt_check_mime_type (type)) == TYPEOTHER)
	  {
	    mutt_error (_("Unknown Content-Type %s"), type);
	    continue;
	  }
	  if (idxlen == idxmax)
	  {
	    safe_realloc (&idx, sizeof (ATTACHPTR *) * (idxmax += 5));
	    menu->data = idx;
	  }

	  idx[idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR));
	  /* Touch the file */
	  if (!(fp = safe_fopen (fname, "w")))
	  {
	    mutt_error (_("Can't create file %s"), fname);
	    FREE (&idx[idxlen]);
	    continue;
	  }
	  safe_fclose (&fp);

	  if ((idx[idxlen]->content = mutt_make_file_attach (fname)) == NULL)
	  {
	    mutt_error _("What we have here is a failure to make an attachment");
	    continue;
	  }
	  update_idx (menu, idx, idxlen++);

	  idx[menu->current]->content->type = itype;
	  mutt_str_replace (&idx[menu->current]->content->subtype, p);
	  idx[menu->current]->content->unlink = 1;
	  menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;

	  if (mutt_compose_attachment (idx[menu->current]->content))
	  {
	    mutt_update_encoding (idx[menu->current]->content);
	    menu->redraw = REDRAW_FULL;
	  }
	}
        mutt_message_hook (NULL, msg, M_SEND2HOOK);    
        break;

      case OP_COMPOSE_EDIT_MIME:
	CHECK_COUNT;
	if (mutt_edit_attachment (idx[menu->current]->content))
	{
	  mutt_update_encoding (idx[menu->current]->content);
	  menu->redraw = REDRAW_FULL;
	}
        mutt_message_hook (NULL, msg, M_SEND2HOOK);
        break;

      case OP_VIEW_ATTACH:
      case OP_DISPLAY_HEADERS:
	CHECK_COUNT;
	mutt_attach_display_loop (menu, op, NULL, NULL, NULL, &idx, &idxlen, NULL, 0);
	menu->redraw = REDRAW_FULL;
        /* no send2hook, since this doesn't modify the message */
	break;

      case OP_SAVE:
	CHECK_COUNT;
	mutt_save_attachment_list (NULL, menu->tagprefix, menu->tagprefix ?  msg->content : idx[menu->current]->content, NULL, menu);
	MAYBE_REDRAW (menu->redraw);
        /* no send2hook, since this doesn't modify the message */
	break;

      case OP_PRINT:
	CHECK_COUNT;
	mutt_print_attachment_list (NULL, menu->tagprefix, menu->tagprefix ? msg->content : idx[menu->current]->content);
        /* no send2hook, since this doesn't modify the message */
	break;

      case OP_PIPE:
      case OP_FILTER:
        CHECK_COUNT;
	mutt_pipe_attachment_list (NULL, menu->tagprefix, menu->tagprefix ? msg->content : idx[menu->current]->content, op == OP_FILTER);
	if (op == OP_FILTER) /* cte might have changed */
	  menu->redraw = menu->tagprefix ? REDRAW_FULL : REDRAW_CURRENT;
        menu->redraw |= REDRAW_STATUS;
        mutt_message_hook (NULL, msg, M_SEND2HOOK);
	break;

      case OP_EXIT:
	if ((i = query_quadoption (OPT_POSTPONE, _("Postpone this message?"))) == M_NO)
	{
          for (i = 0; i < idxlen; i++)
            if (idx[i]->unowned)
              idx[i]->content->unlink = 0;

          if (!(flags & M_COMPOSE_NOFREEHEADER))
          {
            while (idxlen-- > 0)
            {
              /* avoid freeing other attachments */
              idx[idxlen]->content->next = NULL;
              idx[idxlen]->content->parts = NULL;
              mutt_free_body (&idx[idxlen]->content);
              FREE (&idx[idxlen]->tree);
              FREE (&idx[idxlen]);
            }
            FREE (&idx);
            idxlen = 0;
            idxmax = 0;
          }
	  r = -1;
	  loop = 0;
	  break;
	}
	else if (i == -1)
	  break; /* abort */

	/* fall through to postpone! */

      case OP_COMPOSE_POSTPONE_MESSAGE:

        if(check_attachments(idx, idxlen) != 0)
        {
	  menu->redraw = REDRAW_FULL;
	  break;
	}
      
	loop = 0;
	r = 1;
	break;

      case OP_COMPOSE_ISPELL:
	endwin ();
	snprintf (buf, sizeof (buf), "%s -x %s", NONULL(Ispell), msg->content->filename);
	if (mutt_system (buf) == -1)
	  mutt_error (_("Error running \"%s\"!"), buf);
	else
        {
	  mutt_update_encoding (msg->content);
	  menu->redraw |= REDRAW_STATUS;
	}
	break;

      case OP_COMPOSE_WRITE_MESSAGE:

       fname[0] = '\0';
       if (Context)
       {
	 strfcpy (fname, NONULL (Context->path), sizeof (fname));
	 mutt_pretty_mailbox (fname, sizeof (fname));
       }
       if (idxlen)
         msg->content = idx[0]->content;
       if (mutt_enter_fname (_("Write message to mailbox"), fname, sizeof (fname),
                             &menu->redraw, 1) != -1 && fname[0])
       {
         mutt_message (_("Writing message to %s ..."), fname);
         mutt_expand_path (fname, sizeof (fname));

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

         if (mutt_write_fcc (fname, msg, NULL, 0, NULL) < 0)
           msg->content = mutt_remove_multipart (msg->content);
         else
           mutt_message _("Message written.");
       }
       break;



      case OP_COMPOSE_PGP_MENU:
        if (!(WithCrypto & APPLICATION_PGP))
          break;
	if ((WithCrypto & APPLICATION_SMIME)
            && (msg->security & APPLICATION_SMIME))
	{
          if (msg->security & (ENCRYPT | SIGN))
          {
            if (mutt_yesorno (_("S/MIME already selected. Clear & continue ? "),
                              M_YES) != M_YES)
            {
              mutt_clear_error ();
              break;
            }
            msg->security &= ~(ENCRYPT | SIGN);
          }
	  msg->security &= ~APPLICATION_SMIME;
	  msg->security |= APPLICATION_PGP;
          crypt_opportunistic_encrypt (msg);
          redraw_crypt_lines (msg);
	}
	msg->security = crypt_pgp_send_menu (msg, &menu->redraw);
	redraw_crypt_lines (msg);
        mutt_message_hook (NULL, msg, M_SEND2HOOK);
        break;


      case OP_FORGET_PASSPHRASE:
	crypt_forget_passphrase ();
	break;


      case OP_COMPOSE_SMIME_MENU:
        if (!(WithCrypto & APPLICATION_SMIME))
          break;

	if ((WithCrypto & APPLICATION_PGP)
            && (msg->security & APPLICATION_PGP))
	{
          if (msg->security & (ENCRYPT | SIGN))
          {
            if (mutt_yesorno (_("PGP already selected. Clear & continue ? "),
                                M_YES) != M_YES)
            {
              mutt_clear_error ();
              break;
            }
            msg->security &= ~(ENCRYPT | SIGN);
          }
	  msg->security &= ~APPLICATION_PGP;
	  msg->security |= APPLICATION_SMIME;
          crypt_opportunistic_encrypt (msg);
          redraw_crypt_lines (msg);
	}
	msg->security = crypt_smime_send_menu(msg, &menu->redraw);
	redraw_crypt_lines (msg);
        mutt_message_hook (NULL, msg, M_SEND2HOOK);
        break;


#ifdef MIXMASTER
      case OP_COMPOSE_MIX:
      
      	mix_make_chain (&msg->chain, &menu->redraw);
        mutt_message_hook (NULL, msg, M_SEND2HOOK);
        break;
#endif

    }

    /* Draw formatted compose status line */
    if (menu->redraw & REDRAW_STATUS) 
    {
	compose_status_line (buf, sizeof (buf), 0, menu, NONULL(ComposeFormat));
	move(option (OPTSTATUSONTOP) ? 0 : LINES-2, 0);
	SETCOLOR (MT_COLOR_STATUS);
	mutt_paddstr (COLS, buf);
	NORMAL_COLOR;
	menu->redraw &= ~REDRAW_STATUS;
    }
  }

  mutt_menuDestroy (&menu);

  if (idxlen)
  {
    msg->content = idx[0]->content;
    for (i = 0; i < idxlen; i++)
    {
      idx[i]->content->aptr = NULL;
      FREE (&idx[i]->tree);
      FREE (&idx[i]);
    }
  }
  else
    msg->content = NULL;

  FREE (&idx);

  return (r);
}