NeoMutt  2021-10-29-225-gb9986f
Teaching an old dog new tricks
DOXYGEN
mutt_attach.h File Reference

Handling of email attachments. More...

#include <stdbool.h>
#include <stdio.h>
+ Include dependency graph for mutt_attach.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Enumerations

enum  ViewAttachMode { MUTT_VA_REGULAR = 1 , MUTT_VA_MAILCAP , MUTT_VA_AS_TEXT , MUTT_VA_PAGER }
 Options for mutt_view_attachment() More...
 
enum  SaveAttach { MUTT_SAVE_NO_FLAGS = 0 , MUTT_SAVE_APPEND , MUTT_SAVE_OVERWRITE }
 Options for saving attachments. More...
 

Functions

int mutt_attach_display_loop (struct ConfigSubset *sub, struct Menu *menu, int op, struct Email *e, struct AttachCtx *actx, bool recv)
 Event loop for the Attachment menu. More...
 
void mutt_save_attachment_list (struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, struct Email *e, struct Menu *menu)
 Save a list of attachments. More...
 
void mutt_pipe_attachment_list (struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, bool filter)
 Pipe a list of attachments to a command. More...
 
void mutt_print_attachment_list (struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top)
 Print a list of Attachments. More...
 
int mutt_view_attachment (FILE *fp, struct Body *a, enum ViewAttachMode mode, struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
 View an attachment. More...
 
void mutt_check_lookup_list (struct Body *b, char *type, size_t len)
 Update the mime type. More...
 
int mutt_compose_attachment (struct Body *a)
 Create an attachment. More...
 
int mutt_decode_save_attachment (FILE *fp, struct Body *m, const char *path, int displaying, enum SaveAttach opt)
 Decode, then save an attachment. More...
 
int mutt_edit_attachment (struct Body *a)
 Edit an attachment. More...
 
int mutt_get_tmp_attachment (struct Body *a)
 Get a temporary copy of an attachment. More...
 
int mutt_pipe_attachment (FILE *fp, struct Body *b, const char *path, char *outfile)
 Pipe an attachment to a command. More...
 
int mutt_print_attachment (FILE *fp, struct Body *a)
 Print out an attachment. More...
 
int mutt_save_attachment (FILE *fp, struct Body *m, const char *path, enum SaveAttach opt, struct Email *e)
 Save an attachment. More...
 
void mutt_add_temp_attachment (const char *filename)
 Add file to list of temporary attachments. More...
 
void mutt_unlink_temp_attachments (void)
 Delete all temporary attachments. More...
 

Detailed Description

Handling of email attachments.

Authors
  • Michael R. Elkins

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

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file mutt_attach.h.

Enumeration Type Documentation

◆ ViewAttachMode

Options for mutt_view_attachment()

Enumerator
MUTT_VA_REGULAR 

View using default method.

MUTT_VA_MAILCAP 

Force viewing using mailcap entry.

MUTT_VA_AS_TEXT 

Force viewing as text.

MUTT_VA_PAGER 

View attachment in pager using copiousoutput mailcap.

Definition at line 41 of file mutt_attach.h.

42 {
43  MUTT_VA_REGULAR = 1,
47 };
@ MUTT_VA_MAILCAP
Force viewing using mailcap entry.
Definition: mutt_attach.h:44
@ MUTT_VA_REGULAR
View using default method.
Definition: mutt_attach.h:43
@ MUTT_VA_PAGER
View attachment in pager using copiousoutput mailcap.
Definition: mutt_attach.h:46
@ MUTT_VA_AS_TEXT
Force viewing as text.
Definition: mutt_attach.h:45

◆ SaveAttach

enum SaveAttach

Options for saving attachments.

See also
mutt_save_attachment(), mutt_decode_save_attachment(), save_attachment_open(), mutt_check_overwrite()
Enumerator
MUTT_SAVE_NO_FLAGS 

No flags set.

MUTT_SAVE_APPEND 

Append to existing file.

MUTT_SAVE_OVERWRITE 

Overwrite existing file.

Definition at line 55 of file mutt_attach.h.

56 {
57  MUTT_SAVE_NO_FLAGS = 0,
60 };
@ MUTT_SAVE_APPEND
Append to existing file.
Definition: mutt_attach.h:58
@ MUTT_SAVE_OVERWRITE
Overwrite existing file.
Definition: mutt_attach.h:59
@ MUTT_SAVE_NO_FLAGS
No flags set.
Definition: mutt_attach.h:57

Function Documentation

◆ mutt_attach_display_loop()

int mutt_attach_display_loop ( struct ConfigSubset sub,
struct Menu menu,
int  op,
struct Email e,
struct AttachCtx actx,
bool  recv 
)

Event loop for the Attachment menu.

Parameters
subConfig Subset
menuMenu listing Attachments
opOperation, e.g. OP_VIEW_ATTACH
eEmail
actxAttachment context
recvtrue if these are received attachments (rather than in compose)
Return values
numOperation performed

Definition at line 941 of file recvattach.c.

943 {
944  do
945  {
946  switch (op)
947  {
948  case OP_DISPLAY_HEADERS:
949  bool_str_toggle(NeoMutt->sub, "weed", NULL);
950  /* fallthrough */
951 
952  case OP_VIEW_ATTACH:
953  {
954  struct AttachPtr *cur_att = current_attachment(actx, menu);
955  if (!cur_att->fp)
956  {
957  if (cur_att->body->type == TYPE_MULTIPART)
958  {
959  struct Body *b = cur_att->body->parts;
960  while (b->parts)
961  b = b->parts;
962  cur_att = b->aptr;
963  }
964  }
965  op = mutt_view_attachment(cur_att->fp, cur_att->body, MUTT_VA_REGULAR,
966  e, actx, menu->win);
967  break;
968  }
969 
970  case OP_NEXT_ENTRY:
971  case OP_MAIN_NEXT_UNDELETED: /* hack */
972  {
973  const int index = menu_get_index(menu) + 1;
974  if (index < menu->max)
975  {
976  menu_set_index(menu, index);
977  op = OP_VIEW_ATTACH;
978  }
979  else
980  op = OP_NULL;
981  break;
982  }
983 
984  case OP_PREV_ENTRY:
985  case OP_MAIN_PREV_UNDELETED: /* hack */
986  {
987  const int index = menu_get_index(menu) - 1;
988  if (index >= 0)
989  {
990  menu_set_index(menu, index);
991  op = OP_VIEW_ATTACH;
992  }
993  else
994  op = OP_NULL;
995  break;
996  }
997 
998  case OP_EDIT_TYPE:
999  {
1000  struct AttachPtr *cur_att = current_attachment(actx, menu);
1001  /* when we edit the content-type, we should redisplay the attachment
1002  * immediately */
1003  mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1004  if (recv)
1005  recvattach_edit_content_type(actx, menu, e);
1006  else
1007  mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1008 
1010  op = OP_VIEW_ATTACH;
1011  break;
1012  }
1013  /* functions which are passed through from the pager */
1014  case OP_CHECK_TRADITIONAL:
1016  {
1017  op = OP_NULL;
1018  break;
1019  }
1020  /* fallthrough */
1021  case OP_ATTACH_COLLAPSE:
1022  if (recv)
1023  return op;
1024  /* fallthrough */
1025  default:
1026  op = OP_NULL;
1027  }
1028  } while (op != OP_NULL);
1029 
1030  return op;
1031 }
int bool_str_toggle(struct ConfigSubset *sub, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition: bool.c:214
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition: commands.c:1109
#define MENU_REDRAW_INDEX
Redraw the index.
Definition: lib.h:52
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition: menu.c:648
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:624
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:638
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
int mutt_view_attachment(FILE *fp, struct Body *a, enum ViewAttachMode mode, struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
View an attachment.
Definition: mutt_attach.c:416
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition: lib.h:89
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
#define WithCrypto
Definition: lib.h:113
struct AttachPtr * current_attachment(struct AttachCtx *actx, struct Menu *menu)
Get the current attachment.
Definition: recvattach.c:67
void recvattach_edit_content_type(struct AttachCtx *actx, struct Menu *menu, struct Email *e)
Edit the content type of an attachment.
Definition: recvattach.c:910
An email to which things will be attached.
Definition: attach.h:35
struct Body * body
Attachment.
Definition: attach.h:36
FILE * fp
Used in the recvattach menu.
Definition: attach.h:37
The body of an email.
Definition: body.h:35
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:71
struct AttachPtr * aptr
Menu information, used in recvattach.c.
Definition: body.h:73
unsigned int type
content-type primary type, ContentType
Definition: body.h:39
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
struct MuttWindow * win
Window holding the Menu.
Definition: lib.h:76
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_save_attachment_list()

void mutt_save_attachment_list ( struct AttachCtx actx,
FILE *  fp,
bool  tag,
struct Body top,
struct Email e,
struct Menu menu 
)

Save a list of attachments.

Parameters
actxAttachment context
fpFile handle for the attachment (OPTIONAL)
tagIf true, only save the tagged attachments
topFirst Attachment
eEmail
menuMenu listing attachments

Definition at line 412 of file recvattach.c.

414 {
415  char *directory = NULL;
416  int rc = 1;
417  int last = menu_get_index(menu);
418  FILE *fp_out = NULL;
419  int saved_attachments = 0;
420 
421  struct Buffer *buf = mutt_buffer_pool_get();
422  struct Buffer *tfile = mutt_buffer_pool_get();
423 
424  const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
425  const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
426  const bool c_attach_save_without_prompting =
427  cs_subset_bool(NeoMutt->sub, "attach_save_without_prompting");
428 
429  for (int i = 0; !tag || (i < actx->idxlen); i++)
430  {
431  if (tag)
432  {
433  fp = actx->idx[i]->fp;
434  top = actx->idx[i]->body;
435  }
436  if (!tag || top->tagged)
437  {
438  if (!c_attach_split)
439  {
440  if (mutt_buffer_is_empty(buf))
441  {
442  enum SaveAttach opt = MUTT_SAVE_NO_FLAGS;
443 
445  prepend_savedir(buf);
446 
447  if ((mutt_buffer_get_field(_("Save to file: "), buf, MUTT_COMP_FILE | MUTT_COMP_CLEAR,
448  false, NULL, NULL, NULL) != 0) ||
450  {
451  goto cleanup;
452  }
454  if (mutt_check_overwrite(top->filename, mutt_buffer_string(buf), tfile, &opt, NULL))
455  goto cleanup;
456  rc = save_attachment_flowed_helper(fp, top, mutt_buffer_string(tfile), opt, e);
457  if ((rc == 0) && c_attach_sep && (fp_out = fopen(mutt_buffer_string(tfile), "a")))
458  {
459  fprintf(fp_out, "%s", c_attach_sep);
460  mutt_file_fclose(&fp_out);
461  }
462  }
463  else
464  {
466  MUTT_SAVE_APPEND, e);
467  if ((rc == 0) && c_attach_sep && (fp_out = fopen(mutt_buffer_string(tfile), "a")))
468  {
469  fprintf(fp_out, "%s", c_attach_sep);
470  mutt_file_fclose(&fp_out);
471  }
472  }
473  }
474  else
475  {
476  if (tag && menu && top->aptr)
477  {
478  menu_set_index(menu, top->aptr->num);
480 
481  menu_redraw(menu);
482  }
483  if (c_attach_save_without_prompting)
484  {
485  // Save each file, with no prompting, using the configured 'AttachSaveDir'
486  rc = save_without_prompting(fp, top, e);
487  if (rc == 0)
488  saved_attachments++;
489  }
490  else
491  {
492  // Save each file, prompting the user for the location each time.
493  if (query_save_attachment(fp, top, e, &directory) == -1)
494  break;
495  }
496  }
497  }
498  if (!tag)
499  break;
500  }
501 
502  FREE(&directory);
503 
504  if (tag && menu)
505  {
506  menu_set_index(menu, last);
508  }
509 
510  if (rc == 0)
511  {
512  if (!c_attach_split)
513  saved_attachments = 1;
514 
515  if (!c_attach_split || c_attach_save_without_prompting)
516  {
517  mutt_message(ngettext("Attachment saved", "%d attachments saved", saved_attachments),
518  saved_attachments);
519  }
520  }
521 
522 cleanup:
524  mutt_buffer_pool_release(&tfile);
525 }
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
int mutt_buffer_get_field(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, struct Mailbox *m, char ***files, int *numfiles)
Ask the user for a string.
Definition: curs_lib.c:267
int menu_redraw(struct Menu *menu)
Redraw the parts of the screen that have been flagged to be redrawn.
Definition: draw.c:519
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
#define mutt_message(...)
Definition: logging.h:86
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
#define FREE(x)
Definition: memory.h:40
#define MENU_REDRAW_MOTION
Redraw after moving the menu list.
Definition: lib.h:53
#define _(a)
Definition: message.h:28
const char * mutt_path_basename(const char *f)
Find the last component for a pathname.
Definition: path.c:329
#define MUTT_COMP_FILE
File completion (in browser)
Definition: mutt.h:55
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:62
SaveAttach
Options for saving attachments.
Definition: mutt_attach.h:56
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:322
int mutt_check_overwrite(const char *attname, const char *path, struct Buffer *fname, enum SaveAttach *opt, char **directory)
Ask the user if overwriting is necessary.
Definition: muttlib.c:625
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
static int save_attachment_flowed_helper(FILE *fp, struct Body *b, const char *path, enum SaveAttach flags, struct Email *e)
Helper for unstuffing attachments.
Definition: recvattach.c:216
static void prepend_savedir(struct Buffer *buf)
Add $attach_save_dir to the beginning of a path.
Definition: recvattach.c:157
static int save_without_prompting(FILE *fp, struct Body *body, struct Email *e)
Save the attachment, without prompting each time.
Definition: recvattach.c:362
static int query_save_attachment(FILE *fp, struct Body *body, struct Email *e, char **directory)
Ask the user if we should save the attachment.
Definition: recvattach.c:263
#define NONULL(x)
Definition: string2.h:37
struct AttachPtr ** idx
Array of attachments.
Definition: attach.h:54
short idxlen
Number of attachmentes.
Definition: attach.h:55
int num
Attachment index number.
Definition: attach.h:41
bool tagged
This attachment is tagged.
Definition: body.h:89
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:57
String manipulation buffer.
Definition: buffer.h:34
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_pipe_attachment_list()

void mutt_pipe_attachment_list ( struct AttachCtx actx,
FILE *  fp,
bool  tag,
struct Body top,
bool  filter 
)

Pipe a list of attachments to a command.

Parameters
actxAttachment context
fpFile handle to the attachment (OPTIONAL)
tagIf true, only save the tagged attachments
topFirst Attachment
filterIs this command a filter?

Definition at line 705 of file recvattach.c.

707 {
708  struct State state = { 0 };
709  struct Buffer *buf = NULL;
710 
711  if (fp)
712  filter = false; /* sanity check: we can't filter in the recv case yet */
713 
714  buf = mutt_buffer_pool_get();
715  /* perform charset conversion on text attachments when piping */
716  state.flags = MUTT_CHARCONV;
717 
718  if (mutt_buffer_get_field((filter ? _("Filter through: ") : _("Pipe to: ")), buf,
719  MUTT_COMP_FILE_SIMPLE, false, NULL, NULL, NULL) != 0)
720  {
721  goto cleanup;
722  }
723 
724  if (mutt_buffer_len(buf) == 0)
725  goto cleanup;
726 
728 
729  const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
730  if (!filter && !c_attach_split)
731  {
732  mutt_endwin();
733  pid_t pid = filter_create(mutt_buffer_string(buf), &state.fp_out, NULL, NULL);
734  pipe_attachment_list(mutt_buffer_string(buf), actx, fp, tag, top, filter, &state);
735  mutt_file_fclose(&state.fp_out);
736  const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
737  if ((filter_wait(pid) != 0) || c_wait_key)
739  }
740  else
741  pipe_attachment_list(mutt_buffer_string(buf), actx, fp, tag, top, filter, &state);
742 
743 cleanup:
745 }
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:356
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:427
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:394
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
#define MUTT_COMP_FILE_SIMPLE
File completion (no browser)
Definition: mutt.h:57
static void pipe_attachment_list(const char *command, struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, bool filter, struct State *state)
Pipe a list of attachments to a command.
Definition: recvattach.c:673
Keep track when processing files.
Definition: state.h:45
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
FILE * fp_out
File to write to.
Definition: state.h:47
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_print_attachment_list()

void mutt_print_attachment_list ( struct AttachCtx actx,
FILE *  fp,
bool  tag,
struct Body top 
)

Print a list of Attachments.

Parameters
actxAttachment context
fpFile handle to the attachment (OPTIONAL)
tagApply to all tagged Attachments
topFirst Attachment

Definition at line 864 of file recvattach.c.

865 {
866  char prompt[128];
867  struct State state = { 0 };
868  int tagmsgcount = 0;
869 
870  if (tag)
871  for (int i = 0; i < actx->idxlen; i++)
872  if (actx->idx[i]->body->tagged)
873  tagmsgcount++;
874 
875  snprintf(prompt, sizeof(prompt),
876  tag ? ngettext("Print tagged attachment?", "Print %d tagged attachments?", tagmsgcount) :
877  _("Print attachment?"),
878  tagmsgcount);
879  const enum QuadOption c_print = cs_subset_quad(NeoMutt->sub, "print");
880  if (query_quadoption(c_print, prompt) != MUTT_YES)
881  return;
882 
883  const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
884  if (c_attach_split)
885  {
886  print_attachment_list(actx, fp, tag, top, &state);
887  }
888  else
889  {
890  if (!can_print(actx, top, tag))
891  return;
892  mutt_endwin();
893  const char *const c_print_command =
894  cs_subset_string(NeoMutt->sub, "print_command");
895  pid_t pid = filter_create(NONULL(c_print_command), &state.fp_out, NULL, NULL);
896  print_attachment_list(actx, fp, tag, top, &state);
897  mutt_file_fclose(&state.fp_out);
898  const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
899  if ((filter_wait(pid) != 0) || c_wait_key)
901  }
902 }
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:218
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: question.c:349
static void print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, struct State *state)
Print a list of Attachments.
Definition: recvattach.c:794
static bool can_print(struct AttachCtx *actx, struct Body *top, bool tag)
Do we know how to print this attachment type?
Definition: recvattach.c:754
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_view_attachment()

int mutt_view_attachment ( FILE *  fp,
struct Body a,
enum ViewAttachMode  mode,
struct Email e,
struct AttachCtx actx,
struct MuttWindow win 
)

View an attachment.

Parameters
fpSource file stream. Can be NULL
aThe message body containing the attachment
modeHow the attachment should be viewed, see ViewAttachMode
eCurrent Email. Can be NULL
actxAttachment context
winWindow
Return values
0The viewer is run and exited successfully
-1Error
numReturn value of mutt_do_pager() when it is used

Display a message attachment using the viewer program configured in mailcap. If there is no mailcap entry for a file type, view the image as text. Viewer processes are opened and waited on synchronously so viewing an attachment this way will block the main neomutt process until the viewer process exits.

Definition at line 416 of file mutt_attach.c.

418 {
419  bool use_mailcap = false;
420  bool use_pipe = false;
421  bool use_pager = true;
422  char type[256];
423  char desc[256];
424  char *fname = NULL;
425  struct MailcapEntry *entry = NULL;
426  int rc = -1;
427  bool has_tempfile = false;
428  bool unlink_pagerfile = false;
429 
430  bool is_message = mutt_is_message_type(a->type, a->subtype);
431  if ((WithCrypto != 0) && is_message && a->email &&
433  {
434  return rc;
435  }
436 
437  struct Buffer *tmpfile = mutt_buffer_pool_get();
438  struct Buffer *pagerfile = mutt_buffer_pool_get();
439  struct Buffer *cmd = mutt_buffer_pool_get();
440 
441  use_mailcap = ((mode == MUTT_VA_MAILCAP) ||
442  ((mode == MUTT_VA_REGULAR) && mutt_needs_mailcap(a)) ||
443  (mode == MUTT_VA_PAGER));
444  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
445 
446  char columns[16];
447  snprintf(columns, sizeof(columns), "%d", win->state.cols);
448  mutt_envlist_set("COLUMNS", columns, true);
449 
450  if (use_mailcap)
451  {
452  entry = mailcap_entry_new();
453  enum MailcapLookup mailcap_opt =
455  if (!mailcap_lookup(a, type, sizeof(type), entry, mailcap_opt))
456  {
457  if ((mode == MUTT_VA_REGULAR) || (mode == MUTT_VA_PAGER))
458  {
459  /* fallback to view as text */
460  mailcap_entry_free(&entry);
461  mutt_error(_("No matching mailcap entry found. Viewing as text."));
462  mode = MUTT_VA_AS_TEXT;
463  use_mailcap = false;
464  }
465  else
466  goto return_error;
467  }
468  }
469 
470  if (use_mailcap)
471  {
472  if (!entry->command)
473  {
474  mutt_error(_("MIME type not defined. Can't view attachment."));
475  goto return_error;
476  }
477  mutt_buffer_strcpy(cmd, entry->command);
478 
479  fname = mutt_str_dup(a->filename);
480  /* In send mode(!fp), we allow slashes because those are part of
481  * the tmpfile. The path will be removed in expand_filename */
482  mutt_file_sanitize_filename(fname, fp ? true : false);
483  mailcap_expand_filename(entry->nametemplate, fname, tmpfile);
484  FREE(&fname);
485 
486  if (mutt_save_attachment(fp, a, mutt_buffer_string(tmpfile), 0, NULL) == -1)
487  goto return_error;
488  has_tempfile = true;
489 
491 
492  use_pipe = mailcap_expand_command(a, mutt_buffer_string(tmpfile), type, cmd);
493  use_pager = entry->copiousoutput;
494  }
495 
496  if (use_pager)
497  {
498  if (fp && !use_mailcap && a->filename)
499  {
500  /* recv case */
501  mutt_buffer_strcpy(pagerfile, a->filename);
502  mutt_adv_mktemp(pagerfile);
503  }
504  else
505  mutt_buffer_mktemp(pagerfile);
506  }
507 
508  if (use_mailcap)
509  {
510  pid_t pid = 0;
511  int fd_temp = -1, fd_pager = -1;
512 
513  if (!use_pager)
514  mutt_endwin();
515 
516  const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
517  if (use_pager || use_pipe)
518  {
519  if (use_pager && ((fd_pager = mutt_file_open(mutt_buffer_string(pagerfile),
520  O_CREAT | O_EXCL | O_WRONLY)) == -1))
521  {
522  mutt_perror("open");
523  goto return_error;
524  }
525  unlink_pagerfile = true;
526 
527  if (use_pipe && ((fd_temp = open(mutt_buffer_string(tmpfile), 0)) == -1))
528  {
529  if (fd_pager != -1)
530  close(fd_pager);
531  mutt_perror("open");
532  goto return_error;
533  }
534  unlink_pagerfile = true;
535 
536  pid = filter_create_fd(mutt_buffer_string(cmd), NULL, NULL, NULL,
537  use_pipe ? fd_temp : -1, use_pager ? fd_pager : -1, -1);
538 
539  if (pid == -1)
540  {
541  if (fd_pager != -1)
542  close(fd_pager);
543 
544  if (fd_temp != -1)
545  close(fd_temp);
546 
547  mutt_error(_("Can't create filter"));
548  goto return_error;
549  }
550 
551  if (use_pager)
552  {
553  if (a->description)
554  {
555  snprintf(desc, sizeof(desc), _("---Command: %-20.20s Description: %s"),
557  }
558  else
559  {
560  snprintf(desc, sizeof(desc), _("---Command: %-30.30s Attachment: %s"),
561  mutt_buffer_string(cmd), type);
562  }
563  filter_wait(pid);
564  }
565  else
566  {
567  if (wait_interactive_filter(pid) || (entry->needsterminal && c_wait_key))
569  }
570 
571  if (fd_temp != -1)
572  close(fd_temp);
573  if (fd_pager != -1)
574  close(fd_pager);
575  }
576  else
577  {
578  /* interactive cmd */
579  int rv = mutt_system(mutt_buffer_string(cmd));
580  if (rv == -1)
581  mutt_debug(LL_DEBUG1, "Error running \"%s\"\n", cmd->data);
582 
583  if ((rv != 0) || (entry->needsterminal && c_wait_key))
585  }
586  }
587  else
588  {
589  /* Don't use mailcap; the attachment is viewed in the pager */
590 
591  if (mode == MUTT_VA_AS_TEXT)
592  {
593  /* just let me see the raw data */
594  if (fp)
595  {
596  /* Viewing from a received message.
597  *
598  * Don't use mutt_save_attachment() because we want to perform charset
599  * conversion since this will be displayed by the internal pager. */
600  struct State decode_state = { 0 };
601 
602  decode_state.fp_out = mutt_file_fopen(mutt_buffer_string(pagerfile), "w");
603  if (!decode_state.fp_out)
604  {
605  mutt_debug(LL_DEBUG1, "mutt_file_fopen(%s) errno=%d %s\n",
606  mutt_buffer_string(pagerfile), errno, strerror(errno));
607  mutt_perror(mutt_buffer_string(pagerfile));
608  goto return_error;
609  }
610  decode_state.fp_in = fp;
611  decode_state.flags = MUTT_CHARCONV;
612  mutt_decode_attachment(a, &decode_state);
613  if (mutt_file_fclose(&decode_state.fp_out) == EOF)
614  {
615  mutt_debug(LL_DEBUG1, "fclose(%s) errno=%d %s\n",
616  mutt_buffer_string(pagerfile), errno, strerror(errno));
617  }
618  }
619  else
620  {
621  /* in compose mode, just copy the file. we can't use
622  * mutt_decode_attachment() since it assumes the content-encoding has
623  * already been applied */
624  if (mutt_save_attachment(fp, a, mutt_buffer_string(pagerfile), MUTT_SAVE_NO_FLAGS, NULL))
625  goto return_error;
626  unlink_pagerfile = true;
627  }
629  }
630  else
631  {
632  /* Use built-in handler */
633  OptViewAttach = true; /* disable the "use 'v' to view this part"
634  * message in case of error */
635  if (mutt_decode_save_attachment(fp, a, mutt_buffer_string(pagerfile),
637  {
638  OptViewAttach = false;
639  goto return_error;
640  }
641  unlink_pagerfile = true;
642  OptViewAttach = false;
643  }
644 
645  if (a->description)
646  mutt_str_copy(desc, a->description, sizeof(desc));
647  else if (a->filename)
648  snprintf(desc, sizeof(desc), _("---Attachment: %s: %s"), a->filename, type);
649  else
650  snprintf(desc, sizeof(desc), _("---Attachment: %s"), type);
651  }
652 
653  /* We only reach this point if there have been no errors */
654 
655  if (use_pager)
656  {
657  struct PagerData pdata = { 0 };
658  struct PagerView pview = { &pdata };
659 
660  pdata.actx = actx;
661  pdata.body = a;
662  pdata.fname = mutt_buffer_string(pagerfile);
663  pdata.fp = fp;
664 
665  pview.banner = desc;
666  pview.flags = MUTT_PAGER_ATTACHMENT |
667  (is_message ? MUTT_PAGER_MESSAGE : MUTT_PAGER_NO_FLAGS) |
668  ((use_mailcap && entry->xneomuttnowrap) ? MUTT_PAGER_NOWRAP :
670  pview.mode = PAGER_MODE_ATTACH;
671 
672  rc = mutt_do_pager(&pview, e);
673 
674  mutt_buffer_reset(pagerfile);
675  unlink_pagerfile = false;
676  }
677  else
678  rc = 0;
679 
680 return_error:
681 
682  if (!entry || !entry->xneomuttkeep)
683  {
684  if ((fp && !mutt_buffer_is_empty(tmpfile)) || has_tempfile)
685  {
686  /* add temporary file to TempAttachmentsList to be deleted on timeout hook */
688  }
689  }
690 
691  mailcap_entry_free(&entry);
692 
693  if (unlink_pagerfile)
695 
696  mutt_buffer_pool_release(&tmpfile);
697  mutt_buffer_pool_release(&pagerfile);
699  mutt_envlist_unset("COLUMNS");
700 
701  return rc;
702 }
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:135
int mutt_do_pager(struct PagerView *pview, struct Email *e)
Display some page-able text to the user (help or attachment)
Definition: do_pager.c:120
bool mutt_envlist_unset(const char *name)
Unset an environment variable.
Definition: envlist.c:132
bool mutt_envlist_set(const char *name, const char *value, bool overwrite)
Set an environment variable.
Definition: envlist.c:85
int mutt_file_open(const char *path, uint32_t flags)
Open a file.
Definition: file.c:524
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition: file.c:622
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:593
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:195
pid_t filter_create_fd(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, int fdin, int fdout, int fderr)
Run a command on a pipe (optionally connect stdin/stdout)
Definition: filter.c:61
#define mutt_error(...)
Definition: logging.h:87
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
#define mutt_perror(...)
Definition: logging.h:88
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email's attachment.
Definition: handler.c:1864
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
struct MailcapEntry * mailcap_entry_new(void)
Allocate memory for a new rfc1524 entry.
Definition: mailcap.c:437
bool mailcap_lookup(struct Body *a, char *type, size_t typelen, struct MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: mailcap.c:475
void mailcap_entry_free(struct MailcapEntry **ptr)
Deallocate an struct MailcapEntry.
Definition: mailcap.c:446
int mailcap_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: mailcap.c:67
void mailcap_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: mailcap.c:545
MailcapLookup
Mailcap actions.
Definition: mailcap.h:55
@ MUTT_MC_AUTOVIEW
Mailcap autoview field.
Definition: mailcap.h:60
@ MUTT_MC_NO_FLAGS
No flags set.
Definition: mailcap.h:56
#define TYPE(body)
Definition: mime.h:89
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:181
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:560
int mutt_decode_save_attachment(FILE *fp, struct Body *m, const char *path, int displaying, enum SaveAttach opt)
Decode, then save an attachment.
Definition: mutt_attach.c:1014
static int wait_interactive_filter(pid_t pid)
Wait after an interactive filter.
Definition: mutt_attach.c:383
void mutt_add_temp_attachment(const char *filename)
Add file to list of temporary attachments.
Definition: mutt_attach.c:1278
int mutt_save_attachment(FILE *fp, struct Body *m, const char *path, enum SaveAttach opt, struct Email *e)
Save an attachment.
Definition: mutt_attach.c:880
bool mutt_needs_mailcap(struct Body *m)
Does this type need a mailcap entry do display.
Definition: muttlib.c:406
void mutt_adv_mktemp(struct Buffer *buf)
Create a temporary file.
Definition: muttlib.c:83
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:74
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:75
bool OptViewAttach
(pseudo) signals that we are viewing attachments
Definition: options.h:60
#define MUTT_PAGER_NO_FLAGS
No flags are set.
Definition: lib.h:59
#define MUTT_PAGER_NOWRAP
Format for term width, ignore $wrap.
Definition: lib.h:72
@ PAGER_MODE_ATTACH
Pager is invoked via 2nd path. A user-selected attachment (mime part or a nested email) will be shown...
Definition: lib.h:137
#define MUTT_PAGER_MESSAGE
Definition: lib.h:75
#define MUTT_PAGER_ATTACHMENT
Attachments may exist.
Definition: lib.h:71
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1435
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
void mutt_rfc3676_space_unstuff_attachment(struct Body *b, const char *filename)
Unstuff attachments.
Definition: rfc3676.c:515
struct Email * email
header information for message/rfc822
Definition: body.h:72
char * description
content-description
Definition: body.h:54
char * subtype
content-type subtype
Definition: body.h:59
char * data
Pointer to data.
Definition: buffer.h:35
A mailcap entry.
Definition: mailcap.h:36
bool needsterminal
endwin() and system
Definition: mailcap.h:45
char * nametemplate
Definition: mailcap.h:43
char * command
Definition: mailcap.h:37
bool copiousoutput
needs pager, basically
Definition: mailcap.h:46
bool xneomuttkeep
do not remove the file on command exit
Definition: mailcap.h:47
bool xneomuttnowrap
do not wrap the output in the pager
Definition: mailcap.h:48
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
Data to be displayed by PagerView.
Definition: lib.h:149
const char * fname
Name of the file to read.
Definition: lib.h:153
FILE * fp
Source stream.
Definition: lib.h:151
struct Body * body
Current attachment.
Definition: lib.h:150
struct AttachCtx * actx
Attachment information.
Definition: lib.h:152
Paged view into some data.
Definition: lib.h:160
struct PagerData * pdata
Data that pager displays. NOTNULL.
Definition: lib.h:161
enum PagerMode mode
Pager mode.
Definition: lib.h:162
PagerFlags flags
Additional settings to tweak pager's function.
Definition: lib.h:163
const char * banner
Title to display in status bar.
Definition: lib.h:164
FILE * fp_in
File to read from.
Definition: state.h:46
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:60
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_check_lookup_list()

void mutt_check_lookup_list ( struct Body b,
char *  type,
size_t  len 
)

Update the mime type.

Parameters
bMessage attachment body
typeBuffer with mime type of attachment in "type/subtype" format
lenBuffer length

Definition at line 336 of file mutt_attach.c.

337 {
338  struct ListNode *np = NULL;
339  STAILQ_FOREACH(np, &MimeLookupList, entries)
340  {
341  const int i = mutt_str_len(np->data) - 1;
342  if (((i > 0) && (np->data[i - 1] == '/') && (np->data[i] == '*') &&
343  mutt_istrn_equal(type, np->data, i)) ||
344  mutt_istr_equal(type, np->data))
345  {
346  struct Body tmp = { 0 };
347  enum ContentType n;
348  if ((n = mutt_lookup_mime_type(&tmp, b->filename)) != TYPE_OTHER ||
349  (n = mutt_lookup_mime_type(&tmp, b->description)) != TYPE_OTHER)
350  {
351  snprintf(type, len, "%s/%s",
352  (n == TYPE_AUDIO) ? "audio" :
353  (n == TYPE_APPLICATION) ? "application" :
354  (n == TYPE_IMAGE) ? "image" :
355  (n == TYPE_MESSAGE) ? "message" :
356  (n == TYPE_MODEL) ? "model" :
357  (n == TYPE_MULTIPART) ? "multipart" :
358  (n == TYPE_TEXT) ? "text" :
359  (n == TYPE_VIDEO) ? "video" :
360  "other",
361  tmp.subtype);
362  mutt_debug(LL_DEBUG1, "\"%s\" -> %s\n", b->filename, type);
363  }
364  FREE(&tmp.subtype);
365  FREE(&tmp.xtype);
366  }
367  }
368 }
ContentType
Content-Type.
Definition: mime.h:30
@ TYPE_AUDIO
Type: 'audio/*'.
Definition: mime.h:32
@ TYPE_IMAGE
Type: 'image/*'.
Definition: mime.h:34
@ TYPE_OTHER
Unknown Content-Type.
Definition: mime.h:31
@ TYPE_MESSAGE
Type: 'message/*'.
Definition: mime.h:35
@ TYPE_MODEL
Type: 'model/*'.
Definition: mime.h:36
@ TYPE_APPLICATION
Type: 'application/*'.
Definition: mime.h:33
@ TYPE_TEXT
Type: 'text/*'.
Definition: mime.h:38
@ TYPE_VIDEO
Type: 'video/*'.
Definition: mime.h:39
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:727
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:475
bool mutt_istrn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings ignoring case (to a maximum), safely.
Definition: string.c:432
struct ListHead MimeLookupList
List of mime types that that shouldn't use the mailcap entry.
Definition: mutt_globals.h:65
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
enum ContentType mutt_lookup_mime_type(struct Body *att, const char *path)
Find the MIME type for an attachment.
Definition: sendlib.c:564
char * xtype
content-type if x-unknown
Definition: body.h:60
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_compose_attachment()

int mutt_compose_attachment ( struct Body a)

Create an attachment.

Parameters
aBody of email
Return values
1Require full screen redraw
0Otherwise

Definition at line 114 of file mutt_attach.c.

115 {
116  char type[256];
117  struct MailcapEntry *entry = mailcap_entry_new();
118  bool unlink_newfile = false;
119  int rc = 0;
120  struct Buffer *cmd = mutt_buffer_pool_get();
121  struct Buffer *newfile = mutt_buffer_pool_get();
122  struct Buffer *tmpfile = mutt_buffer_pool_get();
123 
124  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
125  if (mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_COMPOSE))
126  {
127  if (entry->composecommand || entry->composetypecommand)
128  {
129  if (entry->composetypecommand)
131  else
132  mutt_buffer_strcpy(cmd, entry->composecommand);
133 
134  mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
135  mutt_debug(LL_DEBUG1, "oldfile: %s newfile: %s\n", a->filename,
136  mutt_buffer_string(newfile));
137  if (mutt_file_symlink(a->filename, mutt_buffer_string(newfile)) == -1)
138  {
139  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
140  goto bailout;
141  mutt_buffer_strcpy(newfile, a->filename);
142  }
143  else
144  unlink_newfile = true;
145 
146  if (mailcap_expand_command(a, mutt_buffer_string(newfile), type, cmd))
147  {
148  /* For now, editing requires a file, no piping */
149  mutt_error(_("Mailcap compose entry requires %%s"));
150  }
151  else
152  {
153  int r;
154 
155  mutt_endwin();
157  if (r == -1)
158  mutt_error(_("Error running \"%s\""), mutt_buffer_string(cmd));
159 
160  if ((r != -1) && entry->composetypecommand)
161  {
162  struct Body *b = NULL;
163 
164  FILE *fp = mutt_file_fopen(a->filename, "r");
165  if (!fp)
166  {
167  mutt_perror(_("Failure to open file to parse headers"));
168  goto bailout;
169  }
170 
171  b = mutt_read_mime_header(fp, 0);
172  if (b)
173  {
174  if (!TAILQ_EMPTY(&b->parameter))
175  {
177  a->parameter = b->parameter;
178  TAILQ_INIT(&b->parameter);
179  }
180  if (b->description)
181  {
182  FREE(&a->description);
183  a->description = b->description;
184  b->description = NULL;
185  }
186  if (b->form_name)
187  {
188  FREE(&a->form_name);
189  a->form_name = b->form_name;
190  b->form_name = NULL;
191  }
192 
193  /* Remove headers by copying out data to another file, then
194  * copying the file back */
195  const LOFF_T offset = b->offset;
196  mutt_body_free(&b);
197  if (!mutt_file_seek(fp, offset, SEEK_SET))
198  {
199  goto bailout;
200  }
201 
202  mutt_buffer_mktemp(tmpfile);
203  FILE *fp_tmp = mutt_file_fopen(mutt_buffer_string(tmpfile), "w");
204  if (!fp_tmp)
205  {
206  mutt_perror(_("Failure to open file to strip headers"));
207  mutt_file_fclose(&fp);
208  goto bailout;
209  }
210  mutt_file_copy_stream(fp, fp_tmp);
211  mutt_file_fclose(&fp);
212  mutt_file_fclose(&fp_tmp);
214  if (mutt_file_rename(mutt_buffer_string(tmpfile), a->filename) != 0)
215  {
216  mutt_perror(_("Failure to rename file"));
217  goto bailout;
218  }
219  }
220  }
221  }
222  }
223  }
224  else
225  {
226  mutt_message(_("No mailcap compose entry for %s, creating empty file"), type);
227  rc = 1;
228  goto bailout;
229  }
230 
231  rc = 1;
232 
233 bailout:
234 
235  if (unlink_newfile)
236  unlink(mutt_buffer_string(newfile));
237 
239  mutt_buffer_pool_release(&newfile);
240  mutt_buffer_pool_release(&tmpfile);
241 
242  mailcap_entry_free(&entry);
243  return rc;
244 }
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:271
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:665
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition: file.c:1378
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:299
@ MUTT_MC_COMPOSE
Mailcap compose field.
Definition: mailcap.h:58
void mutt_param_free(struct ParameterList *pl)
Free a ParameterList.
Definition: parameter.c:61
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1328
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:182
#define TAILQ_INIT(head)
Definition: queue.h:765
#define TAILQ_EMPTY(head)
Definition: queue.h:721
LOFF_T offset
offset where the actual data begins
Definition: body.h:51
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:66
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:61
char * form_name
Content-Disposition form-data name param.
Definition: body.h:58
char * composecommand
Definition: mailcap.h:39
char * composetypecommand
Definition: mailcap.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_decode_save_attachment()

int mutt_decode_save_attachment ( FILE *  fp,
struct Body m,
const char *  path,
int  displaying,
enum SaveAttach  opt 
)

Decode, then save an attachment.

Parameters
fpFile to read from (OPTIONAL)
mAttachment
pathPath to save the Attachment to
displayingFlags, e.g. MUTT_DISPLAY
optSave option, see SaveAttach
Return values
0Success
-1Error

Definition at line 1014 of file mutt_attach.c.

1016 {
1017  struct State s = { 0 };
1018  unsigned int saved_encoding = 0;
1019  struct Body *saved_parts = NULL;
1020  struct Email *e_saved = NULL;
1021  int rc = 0;
1022 
1023  s.flags = displaying;
1024 
1025  if (opt == MUTT_SAVE_APPEND)
1026  s.fp_out = fopen(path, "a");
1027  else if (opt == MUTT_SAVE_OVERWRITE)
1028  s.fp_out = fopen(path, "w");
1029  else
1030  s.fp_out = mutt_file_fopen(path, "w");
1031 
1032  if (!s.fp_out)
1033  {
1034  mutt_perror("fopen");
1035  return -1;
1036  }
1037 
1038  if (!fp)
1039  {
1040  /* When called from the compose menu, the attachment isn't parsed,
1041  * so we need to do it here. */
1042  s.fp_in = fopen(m->filename, "r");
1043  if (!s.fp_in)
1044  {
1045  mutt_perror("fopen");
1047  return -1;
1048  }
1049 
1050  struct stat st = { 0 };
1051  if (fstat(fileno(s.fp_in), &st) == -1)
1052  {
1053  mutt_perror("stat");
1054  mutt_file_fclose(&s.fp_in);
1056  return -1;
1057  }
1058 
1059  saved_encoding = m->encoding;
1060  if (!is_multipart(m))
1061  m->encoding = ENC_8BIT;
1062 
1063  m->length = st.st_size;
1064  m->offset = 0;
1065  saved_parts = m->parts;
1066  e_saved = m->email;
1067  mutt_parse_part(s.fp_in, m);
1068 
1069  if (m->noconv || is_multipart(m))
1070  s.flags |= MUTT_CHARCONV;
1071  }
1072  else
1073  {
1074  s.fp_in = fp;
1075  s.flags |= MUTT_CHARCONV;
1076  }
1077 
1078  mutt_body_handler(m, &s);
1079 
1080  if (mutt_file_fsync_close(&s.fp_out) != 0)
1081  {
1082  mutt_perror("fclose");
1083  rc = -1;
1084  }
1085  if (!fp)
1086  {
1087  m->length = 0;
1088  m->encoding = saved_encoding;
1089  if (saved_parts)
1090  {
1091  email_free(&m->email);
1092  m->parts = saved_parts;
1093  m->email = e_saved;
1094  }
1095  mutt_file_fclose(&s.fp_in);
1096  }
1097 
1098  return rc;
1099 }
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:169
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1607
@ ENC_8BIT
8-bit text
Definition: mime.h:50
#define is_multipart(body)
Definition: mime.h:82
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1730
bool noconv
Don't do character set conversion.
Definition: body.h:45
LOFF_T length
length (in bytes) of attachment
Definition: body.h:52
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:40
The envelope/body of an email.
Definition: email.h:37
char * path
Path of Email (for local Mailboxes)
Definition: email.h:68
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_edit_attachment()

int mutt_edit_attachment ( struct Body a)

Edit an attachment.

Parameters
aEmail containing attachment
Return values
1Editor found
0Editor not found

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.

Returning 0 is useful to tell the calling menu to redraw

Definition at line 259 of file mutt_attach.c.

260 {
261  char type[256];
262  struct MailcapEntry *entry = mailcap_entry_new();
263  bool unlink_newfile = false;
264  int rc = 0;
265  struct Buffer *cmd = mutt_buffer_pool_get();
266  struct Buffer *newfile = mutt_buffer_pool_get();
267 
268  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
269  if (mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_EDIT))
270  {
271  if (entry->editcommand)
272  {
273  mutt_buffer_strcpy(cmd, entry->editcommand);
274  mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
275  mutt_debug(LL_DEBUG1, "oldfile: %s newfile: %s\n", a->filename,
276  mutt_buffer_string(newfile));
277  if (mutt_file_symlink(a->filename, mutt_buffer_string(newfile)) == -1)
278  {
279  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
280  goto bailout;
281  mutt_buffer_strcpy(newfile, a->filename);
282  }
283  else
284  unlink_newfile = true;
285 
286  if (mailcap_expand_command(a, mutt_buffer_string(newfile), type, cmd))
287  {
288  /* For now, editing requires a file, no piping */
289  mutt_error(_("Mailcap Edit entry requires %%s"));
290  goto bailout;
291  }
292  else
293  {
294  mutt_endwin();
295  if (mutt_system(mutt_buffer_string(cmd)) == -1)
296  {
297  mutt_error(_("Error running \"%s\""), mutt_buffer_string(cmd));
298  goto bailout;
299  }
300  }
301  }
302  }
303  else if (a->type == TYPE_TEXT)
304  {
305  /* On text, default to editor */
306  const char *const c_editor = cs_subset_string(NeoMutt->sub, "editor");
307  mutt_edit_file(NONULL(c_editor), a->filename);
308  }
309  else
310  {
311  mutt_error(_("No mailcap edit entry for %s"), type);
312  rc = 0;
313  goto bailout;
314  }
315 
316  rc = 1;
317 
318 bailout:
319 
320  if (unlink_newfile)
321  unlink(mutt_buffer_string(newfile));
322 
324  mutt_buffer_pool_release(&newfile);
325 
326  mailcap_entry_free(&entry);
327  return rc;
328 }
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition: curs_lib.c:352
@ MUTT_MC_EDIT
Mailcap edit field.
Definition: mailcap.h:57
char * editcommand
Definition: mailcap.h:41
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_get_tmp_attachment()

int mutt_get_tmp_attachment ( struct Body a)

Get a temporary copy of an attachment.

Parameters
aAttachment to copy
Return values
0Success
-1Error

Definition at line 68 of file mutt_attach.c.

69 {
70  char type[256];
71 
72  if (a->unlink)
73  return 0;
74 
75  struct Buffer *tmpfile = mutt_buffer_pool_get();
76  struct MailcapEntry *entry = mailcap_entry_new();
77  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
78  mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_NO_FLAGS);
79  mailcap_expand_filename(entry->nametemplate, a->filename, tmpfile);
80 
81  mailcap_entry_free(&entry);
82 
83  FILE *fp_in = NULL, *fp_out = NULL;
84  if ((fp_in = fopen(a->filename, "r")) &&
85  (fp_out = mutt_file_fopen(mutt_buffer_string(tmpfile), "w")))
86  {
87  mutt_file_copy_stream(fp_in, fp_out);
89  a->unlink = true;
90 
91  struct stat st = { 0 };
92  if ((fstat(fileno(fp_in), &st) == 0) && (a->stamp >= st.st_mtime))
93  {
95  }
96  }
97  else
98  mutt_perror(fp_in ? mutt_buffer_string(tmpfile) : a->filename);
99 
100  mutt_file_fclose(&fp_in);
101  mutt_file_fclose(&fp_out);
102 
103  mutt_buffer_pool_release(&tmpfile);
104 
105  return a->unlink ? 0 : -1;
106 }
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:257
void mutt_stamp_attachment(struct Body *a)
Timestamp an Attachment.
Definition: sendlib.c:895
time_t stamp
Time stamp of last encoding update.
Definition: body.h:75
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_pipe_attachment()

int mutt_pipe_attachment ( FILE *  fp,
struct Body b,
const char *  path,
char *  outfile 
)

Pipe an attachment to a command.

Parameters
fpFile to pipe into the command
bAttachment
pathPath to command
outfileFile to save output to
Return values
1Success
0Error

Definition at line 713 of file mutt_attach.c.

714 {
715  pid_t pid = 0;
716  int out = -1, rc = 0;
717  bool is_flowed = false;
718  bool unlink_unstuff = false;
719  FILE *fp_filter = NULL, *fp_unstuff = NULL, *fp_in = NULL;
720  struct Buffer *unstuff_tempfile = NULL;
721 
722  if (outfile && *outfile)
723  {
724  out = mutt_file_open(outfile, O_CREAT | O_EXCL | O_WRONLY);
725  if (out < 0)
726  {
727  mutt_perror("open");
728  return 0;
729  }
730  }
731 
733  {
734  is_flowed = true;
735  unstuff_tempfile = mutt_buffer_pool_get();
736  mutt_buffer_mktemp(unstuff_tempfile);
737  }
738 
739  mutt_endwin();
740 
741  if (outfile && *outfile)
742  pid = filter_create_fd(path, &fp_filter, NULL, NULL, -1, out, -1);
743  else
744  pid = filter_create(path, &fp_filter, NULL, NULL);
745  if (pid < 0)
746  {
747  mutt_perror(_("Can't create filter"));
748  goto bail;
749  }
750 
751  /* recv case */
752  if (fp)
753  {
754  struct State s = { 0 };
755 
756  /* perform charset conversion on text attachments when piping */
757  s.flags = MUTT_CHARCONV;
758 
759  if (is_flowed)
760  {
761  fp_unstuff = mutt_file_fopen(mutt_buffer_string(unstuff_tempfile), "w");
762  if (fp_unstuff == NULL)
763  {
764  mutt_perror("mutt_file_fopen");
765  goto bail;
766  }
767  unlink_unstuff = true;
768 
769  s.fp_in = fp;
770  s.fp_out = fp_unstuff;
771  mutt_decode_attachment(b, &s);
772  mutt_file_fclose(&fp_unstuff);
773 
775 
776  fp_unstuff = mutt_file_fopen(mutt_buffer_string(unstuff_tempfile), "r");
777  if (fp_unstuff == NULL)
778  {
779  mutt_perror("mutt_file_fopen");
780  goto bail;
781  }
782  mutt_file_copy_stream(fp_unstuff, fp_filter);
783  mutt_file_fclose(&fp_unstuff);
784  }
785  else
786  {
787  s.fp_in = fp;
788  s.fp_out = fp_filter;
789  mutt_decode_attachment(b, &s);
790  }
791  }
792 
793  /* send case */
794  else
795  {
796  const char *infile = NULL;
797 
798  if (is_flowed)
799  {
800  if (mutt_save_attachment(fp, b, mutt_buffer_string(unstuff_tempfile),
801  MUTT_SAVE_NO_FLAGS, NULL) == -1)
802  {
803  goto bail;
804  }
805  unlink_unstuff = true;
807  infile = mutt_buffer_string(unstuff_tempfile);
808  }
809  else
810  infile = b->filename;
811 
812  fp_in = fopen(infile, "r");
813  if (!fp_in)
814  {
815  mutt_perror("fopen");
816  goto bail;
817  }
818 
819  mutt_file_copy_stream(fp_in, fp_filter);
821  }
822 
823  mutt_file_fclose(&fp_filter);
824  rc = 1;
825 
826 bail:
827  if (outfile && *outfile)
828  {
829  close(out);
830  if (rc == 0)
831  unlink(outfile);
832  else if (is_flowed)
834  }
835 
836  mutt_file_fclose(&fp_unstuff);
837  mutt_file_fclose(&fp_filter);
839 
840  if (unlink_unstuff)
841  mutt_file_unlink(mutt_buffer_string(unstuff_tempfile));
842  mutt_buffer_pool_release(&unstuff_tempfile);
843 
844  /* check for error exit from child process */
845  if ((pid > 0) && (filter_wait(pid) != 0))
846  rc = 0;
847 
848  const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
849  if ((rc == 0) || c_wait_key)
851  return rc;
852 }
void mutt_rfc3676_space_stuff_attachment(struct Body *b, const char *filename)
Stuff attachments.
Definition: rfc3676.c:536
bool mutt_rfc3676_is_format_flowed(struct Body *b)
Is the Email "format-flowed"?
Definition: rfc3676.c:391
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_print_attachment()

int mutt_print_attachment ( FILE *  fp,
struct Body a 
)

Print out an attachment.

Parameters
fpFile to write to
aAttachment
Return values
1Success
0Error

Ok, the difference between send and receive: recv: Body->filename is a suggested name, and Mailbox|Email points to the attachment in mailbox which is encoded send: Body->filename points to the un-encoded file which contains the attachment

Definition at line 1114 of file mutt_attach.c.

1115 {
1116  char type[256];
1117  pid_t pid;
1118  FILE *fp_in = NULL, *fp_out = NULL;
1119  bool unlink_newfile = false;
1120  struct Buffer *newfile = mutt_buffer_pool_get();
1121  struct Buffer *cmd = mutt_buffer_pool_get();
1122 
1123  int rc = 0;
1124 
1125  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
1126 
1127  if (mailcap_lookup(a, type, sizeof(type), NULL, MUTT_MC_PRINT))
1128  {
1129  mutt_debug(LL_DEBUG2, "Using mailcap\n");
1130 
1131  struct MailcapEntry *entry = mailcap_entry_new();
1132  mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_PRINT);
1133 
1134  char *sanitized_fname = mutt_str_dup(a->filename);
1135  /* In send mode (!fp), we allow slashes because those are part of
1136  * the tempfile. The path will be removed in expand_filename */
1137  mutt_file_sanitize_filename(sanitized_fname, fp ? true : false);
1138  mailcap_expand_filename(entry->nametemplate, sanitized_fname, newfile);
1139  FREE(&sanitized_fname);
1140 
1141  if (mutt_save_attachment(fp, a, mutt_buffer_string(newfile),
1142  MUTT_SAVE_NO_FLAGS, NULL) == -1)
1143  {
1144  goto mailcap_cleanup;
1145  }
1146  unlink_newfile = 1;
1147 
1149 
1150  mutt_buffer_strcpy(cmd, entry->printcommand);
1151 
1152  bool piped = mailcap_expand_command(a, mutt_buffer_string(newfile), type, cmd);
1153 
1154  mutt_endwin();
1155 
1156  const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
1157  /* interactive program */
1158  if (piped)
1159  {
1160  fp_in = fopen(mutt_buffer_string(newfile), "r");
1161  if (!fp_in)
1162  {
1163  mutt_perror("fopen");
1164  mailcap_entry_free(&entry);
1165  goto mailcap_cleanup;
1166  }
1167 
1168  pid = filter_create(mutt_buffer_string(cmd), &fp_out, NULL, NULL);
1169  if (pid < 0)
1170  {
1171  mutt_perror(_("Can't create filter"));
1172  mailcap_entry_free(&entry);
1173  mutt_file_fclose(&fp_in);
1174  goto mailcap_cleanup;
1175  }
1176  mutt_file_copy_stream(fp_in, fp_out);
1177  mutt_file_fclose(&fp_out);
1178  mutt_file_fclose(&fp_in);
1179  if (filter_wait(pid) || c_wait_key)
1181  }
1182  else
1183  {
1184  int rc2 = mutt_system(mutt_buffer_string(cmd));
1185  if (rc2 == -1)
1186  mutt_debug(LL_DEBUG1, "Error running \"%s\"\n", cmd->data);
1187 
1188  if ((rc2 != 0) || c_wait_key)
1190  }
1191 
1192  rc = 1;
1193 
1194  mailcap_cleanup:
1195  if (unlink_newfile)
1197 
1198  mailcap_entry_free(&entry);
1199  goto out;
1200  }
1201 
1202  const char *const c_print_command =
1203  cs_subset_string(NeoMutt->sub, "print_command");
1204  if (mutt_istr_equal("text/plain", type) ||
1205  mutt_istr_equal("application/postscript", type))
1206  {
1207  rc = (mutt_pipe_attachment(fp, a, NONULL(c_print_command), NULL));
1208  goto out;
1209  }
1210  else if (mutt_can_decode(a))
1211  {
1212  /* decode and print */
1213 
1214  fp_in = NULL;
1215  fp_out = NULL;
1216 
1217  mutt_buffer_mktemp(newfile);
1218  if (mutt_decode_save_attachment(fp, a, mutt_buffer_string(newfile),
1220  {
1221  unlink_newfile = true;
1222  mutt_debug(LL_DEBUG2, "successfully decoded %s type attachment to %s\n",
1223  type, mutt_buffer_string(newfile));
1224 
1225  fp_in = fopen(mutt_buffer_string(newfile), "r");
1226  if (!fp_in)
1227  {
1228  mutt_perror("fopen");
1229  goto decode_cleanup;
1230  }
1231 
1232  mutt_debug(LL_DEBUG2, "successfully opened %s read-only\n",
1233  mutt_buffer_string(newfile));
1234 
1235  mutt_endwin();
1236  pid = filter_create(NONULL(c_print_command), &fp_out, NULL, NULL);
1237  if (pid < 0)
1238  {
1239  mutt_perror(_("Can't create filter"));
1240  goto decode_cleanup;
1241  }
1242 
1243  mutt_debug(LL_DEBUG2, "Filter created\n");
1244 
1245  mutt_file_copy_stream(fp_in, fp_out);
1246 
1247  mutt_file_fclose(&fp_out);
1248  mutt_file_fclose(&fp_in);
1249 
1250  const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
1251  if ((filter_wait(pid) != 0) || c_wait_key)
1253  rc = 1;
1254  }
1255  decode_cleanup:
1256  mutt_file_fclose(&fp_in);
1257  mutt_file_fclose(&fp_out);
1258  if (unlink_newfile)
1260  }
1261  else
1262  {
1263  mutt_error(_("I don't know how to print that"));
1264  rc = 0;
1265  }
1266 
1267 out:
1268  mutt_buffer_pool_release(&newfile);
1270 
1271  return rc;
1272 }
bool mutt_can_decode(struct Body *a)
Will decoding the attachment produce any output.
Definition: handler.c:1824
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
@ MUTT_MC_PRINT
Mailcap print field.
Definition: mailcap.h:59
#define MUTT_PRINTING
Are we printing? - MUTT_DISPLAY "light".
Definition: state.h:37
int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, char *outfile)
Pipe an attachment to a command.
Definition: mutt_attach.c:713
char * printcommand
Definition: mailcap.h:42
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_save_attachment()

int mutt_save_attachment ( FILE *  fp,
struct Body m,
const char *  path,
enum SaveAttach  opt,
struct Email e 
)

Save an attachment.

Parameters
fpSource file stream. Can be NULL
mEmail Body
pathWhere to save the attachment
optSave option, see SaveAttach
eCurrent Email. Can be NULL
Return values
0Success
-1Error

Definition at line 880 of file mutt_attach.c.

882 {
883  if (!m)
884  return -1;
885 
886  if (fp)
887  {
888  /* recv mode */
889 
890  if (e && m->email && (m->encoding != ENC_BASE64) &&
892  {
893  /* message type attachments are written to mail folders. */
894 
895  char buf[8192];
896  struct Message *msg = NULL;
897  CopyHeaderFlags chflags = CH_NO_FLAGS;
898  int rc = -1;
899 
900  struct Email *e_new = m->email;
901  e_new->msgno = e->msgno; /* required for MH/maildir */
902  e_new->read = true;
903 
904  if (!mutt_file_seek(fp, m->offset, SEEK_SET))
905  return -1;
906  if (!fgets(buf, sizeof(buf), fp))
907  return -1;
908  struct Mailbox *m_att = mx_path_resolve(path);
909  if (!mx_mbox_open(m_att, MUTT_APPEND | MUTT_QUIET))
910  {
911  mailbox_free(&m_att);
912  return -1;
913  }
914  msg = mx_msg_open_new(m_att, e_new,
915  is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
916  if (!msg)
917  {
918  mx_mbox_close(m_att);
919  return -1;
920  }
921  if ((m_att->type == MUTT_MBOX) || (m_att->type == MUTT_MMDF))
922  chflags = CH_FROM | CH_UPDATE_LEN;
923  chflags |= ((m_att->type == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
924  if ((mutt_copy_message_fp(msg->fp, fp, e_new, MUTT_CM_NO_FLAGS, chflags, 0) == 0) &&
925  (mx_msg_commit(m_att, msg) == 0))
926  {
927  rc = 0;
928  }
929  else
930  {
931  rc = -1;
932  }
933 
934  mx_msg_close(m_att, &msg);
935  mx_mbox_close(m_att);
936  return rc;
937  }
938  else
939  {
940  /* In recv mode, extract from folder and decode */
941 
942  struct State s = { 0 };
943 
944  s.fp_out = save_attachment_open(path, opt);
945  if (!s.fp_out)
946  {
947  mutt_perror("fopen");
948  return -1;
949  }
950  if (!mutt_file_seek((s.fp_in = fp), m->offset, SEEK_SET))
951  {
953  return -1;
954  }
955  mutt_decode_attachment(m, &s);
956 
957  if (mutt_file_fsync_close(&s.fp_out) != 0)
958  {
959  mutt_perror("fclose");
960  return -1;
961  }
962  }
963  }
964  else
965  {
966  if (!m->filename)
967  return -1;
968 
969  /* In send mode, just copy file */
970 
971  FILE *fp_old = fopen(m->filename, "r");
972  if (!fp_old)
973  {
974  mutt_perror("fopen");
975  return -1;
976  }
977 
978  FILE *fp_new = save_attachment_open(path, opt);
979  if (!fp_new)
980  {
981  mutt_perror("fopen");
982  mutt_file_fclose(&fp_old);
983  return -1;
984  }
985 
986  if (mutt_file_copy_stream(fp_old, fp_new) == -1)
987  {
988  mutt_error(_("Write fault"));
989  mutt_file_fclose(&fp_old);
990  mutt_file_fclose(&fp_new);
991  return -1;
992  }
993  mutt_file_fclose(&fp_old);
994  if (mutt_file_fsync_close(&fp_new) != 0)
995  {
996  mutt_error(_("Write fault"));
997  return -1;
998  }
999  }
1000 
1001  return 0;
1002 }
int mutt_copy_message_fp(FILE *fp_out, FILE *fp_in, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Make a copy of a message from a FILE pointer.
Definition: copy.c:651
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:52
#define CH_NOSTATUS
Suppress the status and x-status fields.
Definition: copy.h:58
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:56
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:50
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:62
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:35
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:51
bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
Is a string a 'From' header line?
Definition: from.c:48
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:87
@ MUTT_MMDF
'mmdf' Mailbox type
Definition: mailbox.h:49
@ MUTT_MBOX
'mbox' Mailbox type
Definition: mailbox.h:48
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition: mailbox.h:51
@ ENC_BASE64
Base-64 encoded text.
Definition: mime.h:52
@ ENC_QUOTED_PRINTABLE
Quoted-printable text.
Definition: mime.h:51
static FILE * save_attachment_open(const char *path, enum SaveAttach opt)
Open a file to write an attachment to.
Definition: mutt_attach.c:860
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1192
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:304
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1677
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1171
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1060
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:616
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:42
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:41
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mxapi.h:62
#define MUTT_QUIET
Do not print any messages.
Definition: mxapi.h:64
bool read
Email is read.
Definition: email.h:48
int msgno
Number displayed to the user.
Definition: email.h:111
A mailbox.
Definition: mailbox.h:82
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
A local copy of an email.
Definition: mxapi.h:42
FILE * fp
pointer to the message data
Definition: mxapi.h:43
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_add_temp_attachment()

void mutt_add_temp_attachment ( const char *  filename)

Add file to list of temporary attachments.

Parameters
filenamefilename with full path

Definition at line 1278 of file mutt_attach.c.

1279 {
1281 }
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
struct ListHead TempAttachmentsList
List of temporary files for displaying attachments.
Definition: mutt_globals.h:67
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_unlink_temp_attachments()

void mutt_unlink_temp_attachments ( void  )

Delete all temporary attachments.

Definition at line 1286 of file mutt_attach.c.

1287 {
1288  struct ListNode *np = NULL;
1289 
1290  STAILQ_FOREACH(np, &TempAttachmentsList, entries)
1291  {
1292  (void) mutt_file_chmod_add(np->data, S_IWUSR);
1293  mutt_file_unlink(np->data);
1294  }
1295 
1297 }
int mutt_file_chmod_add(const char *path, mode_t mode)
Add permissions to a file.
Definition: file.c:1098
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
+ Here is the call graph for this function:
+ Here is the caller graph for this function: