NeoMutt  2025-01-09-41-g086358
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
mutt_attach.h File Reference

Handling of email attachments. More...

#include <stdbool.h>
#include <stdio.h>
#include "mutt/lib.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 }
 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.
 
void mutt_save_attachment_list (struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b, struct Email *e, struct Menu *menu)
 Save a list of attachments.
 
void mutt_pipe_attachment_list (struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b, bool filter)
 Pipe a list of attachments to a command.
 
void mutt_print_attachment_list (struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b)
 Print a list of Attachments.
 
int mutt_view_attachment (FILE *fp, struct Body *b, enum ViewAttachMode mode, struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
 View an attachment.
 
void mutt_check_lookup_list (struct Body *b, char *type, size_t len)
 Update the mime type.
 
int mutt_compose_attachment (struct Body *b)
 Create an attachment.
 
int mutt_decode_save_attachment (FILE *fp, struct Body *b, const char *path, StateFlags flags, enum SaveAttach opt)
 Decode, then save an attachment.
 
bool mutt_edit_attachment (struct Body *b)
 Edit an attachment.
 
int mutt_get_tmp_attachment (struct Body *b)
 Get a temporary copy of an attachment.
 
int mutt_pipe_attachment (FILE *fp, struct Body *b, const char *path, const char *outfile)
 Pipe an attachment to a command.
 
int mutt_print_attachment (FILE *fp, struct Body *b)
 Print out an attachment.
 
int mutt_save_attachment (FILE *fp, struct Body *b, const char *path, enum SaveAttach opt, struct Email *e)
 Save an attachment.
 
void mutt_add_temp_attachment (const char *filename)
 Add file to list of temporary attachments.
 
void mutt_temp_attachments_cleanup (void)
 Delete all temporary attachments.
 

Detailed Description

Handling of email attachments.

Authors
  • Richard Russon

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 42 of file mutt_attach.h.

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

◆ 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 

Overwrite existing file (the default)

MUTT_SAVE_APPEND 

Append to existing file.

Definition at line 56 of file mutt_attach.h.

57{
60};
@ MUTT_SAVE_APPEND
Append to existing file.
Definition: mutt_attach.h:59
@ MUTT_SAVE_NO_FLAGS
Overwrite existing file (the default)
Definition: mutt_attach.h:58

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_ATTACHMENT_VIEW
eEmail
actxAttachment context
recvtrue if these are received attachments (rather than in compose)
Return values
numOperation performed

Definition at line 961 of file recvattach.c.

963{
964 do
965 {
966 switch (op)
967 {
968 case OP_DISPLAY_HEADERS:
969 bool_str_toggle(NeoMutt->sub, "weed", NULL);
971
972 case OP_ATTACHMENT_VIEW:
973 {
974 struct AttachPtr *cur_att = current_attachment(actx, menu);
975 if (!cur_att->fp)
976 {
977 if (cur_att->body->type == TYPE_MULTIPART)
978 {
979 struct Body *b = cur_att->body->parts;
980 while (b->parts)
981 b = b->parts;
982 cur_att = b->aptr;
983 }
984 }
985 op = mutt_view_attachment(cur_att->fp, cur_att->body, MUTT_VA_REGULAR,
986 e, actx, menu->win);
987 break;
988 }
989
990 case OP_NEXT_ENTRY:
991 case OP_MAIN_NEXT_UNDELETED: /* hack */
992 {
993 const int index = menu_get_index(menu) + 1;
994 if (index < menu->max)
995 {
996 menu_set_index(menu, index);
997 op = OP_ATTACHMENT_VIEW;
998 }
999 else
1000 {
1001 op = OP_NULL;
1002 }
1003 break;
1004 }
1005
1006 case OP_PREV_ENTRY:
1007 case OP_MAIN_PREV_UNDELETED: /* hack */
1008 {
1009 const int index = menu_get_index(menu) - 1;
1010 if (index >= 0)
1011 {
1012 menu_set_index(menu, index);
1013 op = OP_ATTACHMENT_VIEW;
1014 }
1015 else
1016 {
1017 op = OP_NULL;
1018 }
1019 break;
1020 }
1021
1022 case OP_ATTACHMENT_EDIT_TYPE:
1023 {
1024 struct AttachPtr *cur_att = current_attachment(actx, menu);
1025 /* when we edit the content-type, we should redisplay the attachment
1026 * immediately */
1027 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1028 if (recv)
1029 recvattach_edit_content_type(actx, menu, e);
1030 else
1031 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1032
1034 op = OP_ATTACHMENT_VIEW;
1035 break;
1036 }
1037 /* functions which are passed through from the pager */
1038 case OP_PIPE:
1039 {
1040 struct AttachPtr *cur_att = current_attachment(actx, menu);
1041 mutt_pipe_attachment_list(actx, cur_att->fp, false, cur_att->body, false);
1042 op = OP_ATTACHMENT_VIEW;
1043 break;
1044 }
1045 case OP_ATTACHMENT_PRINT:
1046 {
1047 struct AttachPtr *cur_att = current_attachment(actx, menu);
1048 mutt_print_attachment_list(actx, cur_att->fp, false, cur_att->body);
1049 op = OP_ATTACHMENT_VIEW;
1050 break;
1051 }
1052 case OP_ATTACHMENT_SAVE:
1053 {
1054 struct AttachPtr *cur_att = current_attachment(actx, menu);
1055 mutt_save_attachment_list(actx, cur_att->fp, false, cur_att->body, e, NULL);
1056 op = OP_ATTACHMENT_VIEW;
1057 break;
1058 }
1059 case OP_CHECK_TRADITIONAL:
1061 {
1062 op = OP_NULL;
1063 break;
1064 }
1066
1067 case OP_ATTACHMENT_COLLAPSE:
1068 if (recv)
1069 return op;
1071
1072 default:
1073 op = OP_NULL;
1074 }
1075 } while (op != OP_NULL);
1076
1077 return op;
1078}
int bool_str_toggle(struct ConfigSubset *sub, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition: bool.c:224
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition: external.c:1070
#define MENU_REDRAW_INDEX
Redraw the index.
Definition: lib.h:56
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition: menu.c:184
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:160
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:174
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
#define FALLTHROUGH
Definition: lib.h:111
int mutt_view_attachment(FILE *fp, struct Body *b, enum ViewAttachMode mode, struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
View an attachment.
Definition: mutt_attach.c:419
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition: lib.h:98
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:96
#define WithCrypto
Definition: lib.h:122
void mutt_save_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b, struct Email *e, struct Menu *menu)
Save a list of attachments.
Definition: recvattach.c:432
struct AttachPtr * current_attachment(struct AttachCtx *actx, struct Menu *menu)
Get the current attachment.
Definition: recvattach.c:77
void mutt_pipe_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b, bool filter)
Pipe a list of attachments to a command.
Definition: recvattach.c:724
void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b)
Print a list of Attachments.
Definition: recvattach.c:887
void recvattach_edit_content_type(struct AttachCtx *actx, struct Menu *menu, struct Email *e)
Edit the content type of an attachment.
Definition: recvattach.c:931
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:36
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:73
struct AttachPtr * aptr
Menu information, used in recvattach.c.
Definition: body.h:75
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:43
struct MuttWindow * win
Window holding the Menu.
Definition: lib.h:86
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
+ 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 b,
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
bFirst Attachment
eEmail
menuMenu listing attachments

Definition at line 432 of file recvattach.c.

434{
435 char *directory = NULL;
436 int rc = 1;
437 int last = menu_get_index(menu);
438 FILE *fp_out = NULL;
439 int saved_attachments = 0;
440
441 struct Buffer *buf = buf_pool_get();
442 struct Buffer *tfile = buf_pool_get();
443
444 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
445 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
446 const bool c_attach_save_without_prompting = cs_subset_bool(NeoMutt->sub, "attach_save_without_prompting");
447
448 for (int i = 0; !tag || (i < actx->idxlen); i++)
449 {
450 if (tag)
451 {
452 fp = actx->idx[i]->fp;
453 b = actx->idx[i]->body;
454 }
455 if (!tag || b->tagged)
456 {
457 if (c_attach_split)
458 {
459 if (tag && menu && b->aptr)
460 {
461 menu_set_index(menu, b->aptr->num);
463
464 menu_redraw(menu);
465 }
466 if (c_attach_save_without_prompting)
467 {
468 // Save each file, with no prompting, using the configured 'AttachSaveDir'
469 rc = save_without_prompting(fp, b, e);
470 if (rc == 0)
471 saved_attachments++;
472 }
473 else
474 {
475 // Save each file, prompting the user for the location each time.
476 if (query_save_attachment(fp, b, e, &directory) == -1)
477 break;
478 }
479 }
480 else
481 {
483
484 if (buf_is_empty(buf))
485 {
487 prepend_savedir(buf);
488
489 struct FileCompletionData cdata = { false, NULL, NULL, NULL };
490 if ((mw_get_field(_("Save to file: "), buf, MUTT_COMP_CLEAR, HC_FILE,
491 &CompleteFileOps, &cdata) != 0) ||
492 buf_is_empty(buf))
493 {
494 goto cleanup;
495 }
496 buf_expand_path(buf);
497 if (mutt_check_overwrite(b->filename, buf_string(buf), tfile, &opt, NULL))
498 goto cleanup;
499 }
500 else
501 {
502 opt = MUTT_SAVE_APPEND;
503 }
504
505 rc = save_attachment_flowed_helper(fp, b, buf_string(tfile), opt, e);
506 if ((rc == 0) && c_attach_sep && (fp_out = mutt_file_fopen(buf_string(tfile), "a")))
507 {
508 fprintf(fp_out, "%s", c_attach_sep);
509 mutt_file_fclose(&fp_out);
510 }
511 }
512 }
513 if (!tag)
514 break;
515 }
516
517 FREE(&directory);
518
519 if (tag && menu)
520 {
521 menu_set_index(menu, last);
523 }
524
525 if (rc == 0)
526 {
527 if (!c_attach_split)
528 saved_attachments = 1;
529
530 if (!c_attach_split || c_attach_save_without_prompting)
531 {
532 mutt_message(ngettext("Attachment saved", "%d attachments saved", saved_attachments),
533 saved_attachments);
534 }
535 }
536
537cleanup:
538 buf_pool_release(&buf);
539 buf_pool_release(&tfile);
540}
const struct CompleteOps CompleteFileOps
Auto-Completion of Files.
Definition: complete.c:153
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:291
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:291
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:47
int menu_redraw(struct Menu *menu)
Redraw the parts of the screen that have been flagged to be redrawn.
Definition: draw.c:481
#define mutt_file_fclose(FP)
Definition: file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:138
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition: window.c:273
#define mutt_message(...)
Definition: logging2.h:91
@ HC_FILE
Files.
Definition: lib.h:56
#define FREE(x)
Definition: memory.h:55
#define MENU_REDRAW_MOTION
Redraw after moving the menu list.
Definition: lib.h:57
#define _(a)
Definition: message.h:28
const char * mutt_path_basename(const char *path)
Find the last component for a pathname.
Definition: path.c:282
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:57
SaveAttach
Options for saving attachments.
Definition: mutt_attach.h:57
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:315
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:541
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:96
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:232
static int save_without_prompting(FILE *fp, struct Body *b, struct Email *e)
Save the attachment, without prompting each time.
Definition: recvattach.c:382
static void prepend_savedir(struct Buffer *buf)
Add $attach_save_dir to the beginning of a path.
Definition: recvattach.c:173
static int query_save_attachment(FILE *fp, struct Body *b, struct Email *e, char **directory)
Ask the user if we should save the attachment.
Definition: recvattach.c:278
#define NONULL(x)
Definition: string2.h:37
struct AttachPtr ** idx
Array of attachments.
Definition: attach.h:67
short idxlen
Number of attachmentes.
Definition: attach.h:68
int num
Attachment index number.
Definition: attach.h:41
bool tagged
This attachment is tagged.
Definition: body.h:90
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:59
String manipulation buffer.
Definition: buffer.h:36
Input for the file completion function.
Definition: curs_lib.h:40
+ 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 b,
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
bFirst Attachment
filterIs this command a filter?

Definition at line 724 of file recvattach.c.

726{
727 struct State state = { 0 };
728 struct Buffer *buf = NULL;
729
730 if (fp)
731 filter = false; /* sanity check: we can't filter in the recv case yet */
732
733 buf = buf_pool_get();
734 /* perform charset conversion on text attachments when piping */
735 state.flags = STATE_CHARCONV;
736
737 if (mw_get_field((filter ? _("Filter through: ") : _("Pipe to: ")), buf,
739 {
740 goto cleanup;
741 }
742
743 if (buf_is_empty(buf))
744 goto cleanup;
745
746 buf_expand_path(buf);
747
748 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
749 if (!filter && !c_attach_split)
750 {
751 mutt_endwin();
752 pid_t pid = filter_create(buf_string(buf), &state.fp_out, NULL, NULL, EnvList);
753 pipe_attachment_list(buf_string(buf), actx, fp, tag, b, filter, &state);
754 mutt_file_fclose(&state.fp_out);
755 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
756 if ((filter_wait(pid) != 0) || c_wait_key)
758 }
759 else
760 {
761 pipe_attachment_list(buf_string(buf), actx, fp, tag, b, filter, &state);
762 }
763
764cleanup:
765 buf_pool_release(&buf);
766}
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:173
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:151
char ** EnvList
Private copy of the environment variables.
Definition: globals.c:75
@ HC_EXT_COMMAND
External commands.
Definition: lib.h:53
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:220
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, char **envlist)
Set up filter program.
Definition: filter.c:209
#define STATE_CHARCONV
Do character set conversions.
Definition: state.h:37
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:56
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:692
Keep track when processing files.
Definition: state.h:48
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition: state.h:52
FILE * fp_out
File to write to.
Definition: state.h:50
+ 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 b 
)

Print a list of Attachments.

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

Definition at line 887 of file recvattach.c.

888{
889 char prompt[128] = { 0 };
890 struct State state = { 0 };
891 int tagmsgcount = 0;
892
893 if (tag)
894 for (int i = 0; i < actx->idxlen; i++)
895 if (actx->idx[i]->body->tagged)
896 tagmsgcount++;
897
898 snprintf(prompt, sizeof(prompt),
899 tag ? ngettext("Print tagged attachment?", "Print %d tagged attachments?", tagmsgcount) :
900 _("Print attachment?"),
901 tagmsgcount);
902 if (query_quadoption(prompt, NeoMutt->sub, "print") != MUTT_YES)
903 return;
904
905 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
906 if (c_attach_split)
907 {
908 print_attachment_list(actx, fp, tag, b, &state);
909 }
910 else
911 {
912 if (!can_print(actx, b, tag))
913 return;
914 mutt_endwin();
915 const char *const c_print_command = cs_subset_string(NeoMutt->sub, "print_command");
916 pid_t pid = filter_create(NONULL(c_print_command), &state.fp_out, NULL, NULL, EnvList);
917 print_attachment_list(actx, fp, tag, b, &state);
918 mutt_file_fclose(&state.fp_out);
919 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
920 if ((filter_wait(pid) != 0) || c_wait_key)
922 }
923}
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
enum QuadOption query_quadoption(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition: question.c:379
static void print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b, struct State *state)
Print a list of Attachments.
Definition: recvattach.c:815
static bool can_print(struct AttachCtx *actx, struct Body *b, bool tag)
Do we know how to print this attachment type?
Definition: recvattach.c:775
+ 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 b,
enum ViewAttachMode  mode,
struct Email e,
struct AttachCtx actx,
struct MuttWindow win 
)

View an attachment.

Parameters
fpSource file stream. Can be NULL
bThe 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 419 of file mutt_attach.c.

421{
422 bool use_mailcap = false;
423 bool use_pipe = false;
424 bool use_pager = true;
425 char type[256] = { 0 };
426 char desc[512] = { 0 };
427 char *fname = NULL;
428 struct MailcapEntry *entry = NULL;
429 int rc = -1;
430 bool has_tempfile = false;
431 bool unlink_pagerfile = false;
432
433 bool is_message = mutt_is_message_type(b->type, b->subtype);
434 if ((WithCrypto != 0) && is_message && b->email &&
436 {
437 return rc;
438 }
439
440 struct Buffer *tempfile = buf_pool_get();
441 struct Buffer *pagerfile = buf_pool_get();
442 struct Buffer *cmd = buf_pool_get();
443
444 use_mailcap = ((mode == MUTT_VA_MAILCAP) ||
445 ((mode == MUTT_VA_REGULAR) && mutt_needs_mailcap(b)) ||
446 (mode == MUTT_VA_PAGER));
447 snprintf(type, sizeof(type), "%s/%s", TYPE(b), b->subtype);
448
449 char columns[16] = { 0 };
450 snprintf(columns, sizeof(columns), "%d", win->state.cols);
451 envlist_set(&EnvList, "COLUMNS", columns, true);
452
453 if (use_mailcap)
454 {
455 entry = mailcap_entry_new();
456 enum MailcapLookup mailcap_opt = (mode == MUTT_VA_PAGER) ? MUTT_MC_AUTOVIEW : MUTT_MC_NO_FLAGS;
457 if (!mailcap_lookup(b, type, sizeof(type), entry, mailcap_opt))
458 {
459 if ((mode == MUTT_VA_REGULAR) || (mode == MUTT_VA_PAGER))
460 {
461 /* fallback to view as text */
462 mailcap_entry_free(&entry);
463 mutt_error(_("No matching mailcap entry found. Viewing as text."));
464 mode = MUTT_VA_AS_TEXT;
465 use_mailcap = false;
466 }
467 else
468 {
469 goto return_error;
470 }
471 }
472 }
473
474 if (use_mailcap)
475 {
476 if (!entry->command)
477 {
478 mutt_error(_("MIME type not defined. Can't view attachment."));
479 goto return_error;
480 }
481 buf_strcpy(cmd, entry->command);
482
483 fname = mutt_str_dup(b->filename);
484 /* In send mode(!fp), we allow slashes because those are part of
485 * the tempfile. The path will be removed in expand_filename */
486 mutt_file_sanitize_filename(fname, fp ? true : false);
487 mailcap_expand_filename(entry->nametemplate, fname, tempfile);
488 FREE(&fname);
489
490 if (mutt_save_attachment(fp, b, buf_string(tempfile), 0, NULL) == -1)
491 goto return_error;
492 has_tempfile = true;
493
495
496 /* check for multipart/related and save attachments with b Content-ID */
497 if (mutt_str_equal(type, "text/html"))
498 {
499 struct Body *related_ancestor = NULL;
500 if (actx->body_idx && (WithCrypto != 0) && (e->security & SEC_ENCRYPT))
501 related_ancestor = attach_body_ancestor(actx->body_idx[0], b, "related");
502 else
503 related_ancestor = attach_body_ancestor(e->body, b, "related");
504 if (related_ancestor)
505 {
506 struct CidMapList cid_map_list = STAILQ_HEAD_INITIALIZER(cid_map_list);
507 mutt_debug(LL_DEBUG2, "viewing text/html attachment in multipart/related group\n");
508 /* save attachments and build cid_map_list Content-ID to filename mapping list */
509 cid_save_attachments(related_ancestor->parts, &cid_map_list);
510 /* replace Content-IDs with filenames */
511 cid_to_filename(tempfile, &cid_map_list);
512 /* empty Content-ID to filename mapping list */
513 cid_map_list_clear(&cid_map_list);
514 }
515 }
516
517 use_pipe = mailcap_expand_command(b, buf_string(tempfile), type, cmd);
518 use_pager = entry->copiousoutput;
519 }
520
521 if (use_pager)
522 {
523 if (fp && !use_mailcap && b->filename)
524 {
525 /* recv case */
526 buf_strcpy(pagerfile, b->filename);
527 mutt_adv_mktemp(pagerfile);
528 }
529 else
530 {
531 buf_mktemp(pagerfile);
532 }
533 }
534
535 if (use_mailcap)
536 {
537 pid_t pid = 0;
538 int fd_temp = -1, fd_pager = -1;
539
540 if (!use_pager)
541 mutt_endwin();
542
543 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
544 if (use_pager || use_pipe)
545 {
546 if (use_pager &&
547 ((fd_pager = mutt_file_open(buf_string(pagerfile),
548 O_CREAT | O_EXCL | O_WRONLY, 0600)) == -1))
549 {
550 mutt_perror("open");
551 goto return_error;
552 }
553 unlink_pagerfile = true;
554
555 if (use_pipe && ((fd_temp = open(buf_string(tempfile), 0)) == -1))
556 {
557 if (fd_pager != -1)
558 close(fd_pager);
559 mutt_perror("open");
560 goto return_error;
561 }
562 unlink_pagerfile = true;
563
564 pid = filter_create_fd(buf_string(cmd), NULL, NULL, NULL, use_pipe ? fd_temp : -1,
565 use_pager ? fd_pager : -1, -1, EnvList);
566
567 if (pid == -1)
568 {
569 if (fd_pager != -1)
570 close(fd_pager);
571
572 if (fd_temp != -1)
573 close(fd_temp);
574
575 mutt_error(_("Can't create filter"));
576 goto return_error;
577 }
578
579 if (use_pager)
580 {
581 if (b->description)
582 {
583 snprintf(desc, sizeof(desc), _("---Command: %-20.20s Description: %s"),
584 buf_string(cmd), b->description);
585 }
586 else
587 {
588 snprintf(desc, sizeof(desc), _("---Command: %-30.30s Attachment: %s"),
589 buf_string(cmd), type);
590 }
591 filter_wait(pid);
592 }
593 else
594 {
595 if (wait_interactive_filter(pid) || (entry->needsterminal && c_wait_key))
597 }
598
599 if (fd_temp != -1)
600 close(fd_temp);
601 if (fd_pager != -1)
602 close(fd_pager);
603 }
604 else
605 {
606 /* interactive cmd */
607 int rv = mutt_system(buf_string(cmd));
608 if (rv == -1)
609 mutt_debug(LL_DEBUG1, "Error running \"%s\"\n", cmd->data);
610
611 if ((rv != 0) || (entry->needsterminal && c_wait_key))
613 }
614 }
615 else
616 {
617 /* Don't use mailcap; the attachment is viewed in the pager */
618
619 if (mode == MUTT_VA_AS_TEXT)
620 {
621 /* just let me see the raw data */
622 if (fp)
623 {
624 /* Viewing from a received message.
625 *
626 * Don't use mutt_save_attachment() because we want to perform charset
627 * conversion since this will be displayed by the internal pager. */
628 struct State state = { 0 };
629
630 state.fp_out = mutt_file_fopen(buf_string(pagerfile), "w");
631 if (!state.fp_out)
632 {
633 mutt_debug(LL_DEBUG1, "mutt_file_fopen(%s) errno=%d %s\n",
634 buf_string(pagerfile), errno, strerror(errno));
635 mutt_perror("%s", buf_string(pagerfile));
636 goto return_error;
637 }
638 state.fp_in = fp;
639 state.flags = STATE_CHARCONV;
640 mutt_decode_attachment(b, &state);
641 mutt_file_fclose(&state.fp_out);
642 }
643 else
644 {
645 /* in compose mode, just copy the file. we can't use
646 * mutt_decode_attachment() since it assumes the content-encoding has
647 * already been applied */
648 if (mutt_save_attachment(fp, b, buf_string(pagerfile), MUTT_SAVE_NO_FLAGS, NULL))
649 goto return_error;
650 unlink_pagerfile = true;
651 }
653 }
654 else
655 {
657 const char *const c_pager = pager_get_pager(NeoMutt->sub);
658 if (!c_pager)
660
661 /* Use built-in handler */
663 {
664 goto return_error;
665 }
666 unlink_pagerfile = true;
667 }
668
669 if (b->description)
670 mutt_str_copy(desc, b->description, sizeof(desc));
671 else if (b->filename)
672 snprintf(desc, sizeof(desc), _("---Attachment: %s: %s"), b->filename, type);
673 else
674 snprintf(desc, sizeof(desc), _("---Attachment: %s"), type);
675 }
676
677 /* We only reach this point if there have been no errors */
678
679 if (use_pager)
680 {
681 struct PagerData pdata = { 0 };
682 struct PagerView pview = { &pdata };
683
684 pdata.actx = actx;
685 pdata.body = b;
686 pdata.fname = buf_string(pagerfile);
687 pdata.fp = fp;
688
689 pview.banner = desc;
691 (is_message ? MUTT_PAGER_MESSAGE : MUTT_PAGER_NO_FLAGS) |
692 ((use_mailcap && entry->xneomuttnowrap) ? MUTT_PAGER_NOWRAP :
694 pview.mode = PAGER_MODE_ATTACH;
695
696 rc = mutt_do_pager(&pview, e);
697
698 buf_reset(pagerfile);
699 unlink_pagerfile = false;
700 }
701 else
702 {
703 rc = 0;
704 }
705
706return_error:
707
708 if (!entry || !entry->xneomuttkeep)
709 {
710 if ((fp && !buf_is_empty(tempfile)) || has_tempfile)
711 {
712 /* add temporary file to TempAttachmentsList to be deleted on timeout hook */
714 }
715 }
716
717 mailcap_entry_free(&entry);
718
719 if (unlink_pagerfile)
720 mutt_file_unlink(buf_string(pagerfile));
721
722 buf_pool_release(&tempfile);
723 buf_pool_release(&pagerfile);
724 buf_pool_release(&cmd);
725 envlist_unset(&EnvList, "COLUMNS");
726
727 return rc;
728}
struct Body * attach_body_ancestor(struct Body *start, struct Body *body, const char *subtype)
Find the ancestor of a body with specified subtype.
Definition: lib.c:116
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:76
void cid_save_attachments(struct Body *body, struct CidMapList *cid_map_list)
Save all attachments in a "multipart/related" group with a Content-ID.
Definition: cid.c:151
void cid_to_filename(struct Buffer *filename, const struct CidMapList *cid_map_list)
Replace Content-IDs with filenames.
Definition: cid.c:170
void cid_map_list_clear(struct CidMapList *cid_map_list)
Empty a CidMapList.
Definition: cid.c:82
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:132
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:122
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1498
bool envlist_set(char ***envp, const char *name, const char *value, bool overwrite)
Set an environment variable.
Definition: envlist.c:88
bool envlist_unset(char ***envp, const char *name)
Unset an environment variable.
Definition: envlist.c:136
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition: file.c:589
int mutt_file_open(const char *path, uint32_t flags, mode_t mode)
Open a file.
Definition: file.c:515
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:159
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
#define mutt_perror(...)
Definition: logging2.h:93
void mutt_decode_attachment(const struct Body *b, struct State *state)
Decode an email's attachment.
Definition: handler.c:1906
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
void mailcap_entry_free(struct MailcapEntry **ptr)
Deallocate an struct MailcapEntry.
Definition: mailcap.c:454
struct MailcapEntry * mailcap_entry_new(void)
Allocate memory for a new rfc1524 entry.
Definition: mailcap.c:445
int mailcap_expand_command(struct Body *b, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: mailcap.c:69
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:552
bool mailcap_lookup(struct Body *b, char *type, size_t typelen, struct MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: mailcap.c:483
MailcapLookup
Mailcap actions.
Definition: mailcap.h:56
@ MUTT_MC_AUTOVIEW
Mailcap autoview field.
Definition: mailcap.h:61
@ MUTT_MC_NO_FLAGS
No flags set.
Definition: mailcap.h:57
#define TYPE(body)
Definition: mime.h:89
pid_t filter_create_fd(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, int fdin, int fdout, int fderr, char **envlist)
Run a command on a pipe (optionally connect stdin/stdout)
Definition: filter.c:62
#define STATE_PAGER
Output will be displayed in the Pager.
Definition: state.h:42
#define STATE_DISPLAY
Output is displayed to the user.
Definition: state.h:33
#define STATE_DISPLAY_ATTACH
We are displaying an attachment.
Definition: state.h:41
uint16_t StateFlags
Flags for State->flags, e.g. STATE_DISPLAY.
Definition: state.h:31
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
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:581
static int wait_interactive_filter(pid_t pid)
Wait after an interactive filter.
Definition: mutt_attach.c:390
int mutt_save_attachment(FILE *fp, struct Body *b, const char *path, enum SaveAttach opt, struct Email *e)
Save an attachment.
Definition: mutt_attach.c:905
int mutt_decode_save_attachment(FILE *fp, struct Body *b, const char *path, StateFlags flags, enum SaveAttach opt)
Decode, then save an attachment.
Definition: mutt_attach.c:1039
void mutt_add_temp_attachment(const char *filename)
Add file to list of temporary attachments.
Definition: mutt_attach.c:1297
bool mutt_needs_mailcap(struct Body *b)
Does this type need a mailcap entry do display.
Definition: muttlib.c:379
void mutt_adv_mktemp(struct Buffer *buf)
Create a temporary file.
Definition: muttlib.c:84
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:84
const char * pager_get_pager(struct ConfigSubset *sub)
Get the value of $pager.
Definition: config.c:111
#define MUTT_PAGER_NO_FLAGS
No flags are set.
Definition: lib.h:60
#define MUTT_PAGER_NOWRAP
Format for term width, ignore $wrap.
Definition: lib.h:71
@ 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:70
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:52
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
void mutt_rfc3676_space_unstuff_attachment(struct Body *b, const char *filename)
Unstuff attachments.
Definition: rfc3676.c:518
struct Body ** body_idx
Extra struct Body* used for decryption.
Definition: attach.h:78
struct Email * email
header information for message/rfc822
Definition: body.h:74
char * description
content-description
Definition: body.h:55
char * subtype
content-type subtype
Definition: body.h:61
char * data
Pointer to data.
Definition: buffer.h:37
struct Body * body
List of MIME parts.
Definition: email.h:69
A mailcap entry.
Definition: mailcap.h:37
bool needsterminal
endwin() and system
Definition: mailcap.h:46
char * nametemplate
Definition: mailcap.h:44
char * command
Definition: mailcap.h:38
bool copiousoutput
needs pager, basically
Definition: mailcap.h:47
bool xneomuttkeep
do not remove the file on command exit
Definition: mailcap.h:48
bool xneomuttnowrap
do not wrap the output in the pager
Definition: mailcap.h:49
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
Data to be displayed by PagerView.
Definition: lib.h:159
const char * fname
Name of the file to read.
Definition: lib.h:163
FILE * fp
Source stream.
Definition: lib.h:161
struct Body * body
Current attachment.
Definition: lib.h:160
struct AttachCtx * actx
Attachment information.
Definition: lib.h:162
Paged view into some data.
Definition: lib.h:170
struct PagerData * pdata
Data that pager displays. NOTNULL.
Definition: lib.h:171
enum PagerMode mode
Pager mode.
Definition: lib.h:172
PagerFlags flags
Additional settings to tweak pager's function.
Definition: lib.h:173
const char * banner
Title to display in status bar.
Definition: lib.h:174
FILE * fp_in
File to read from.
Definition: state.h:49
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:61
#define buf_mktemp(buf)
Definition: tmp.h:33
+ 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 343 of file mutt_attach.c.

344{
345 struct ListNode *np = NULL;
346 STAILQ_FOREACH(np, &MimeLookupList, entries)
347 {
348 const int i = (int) mutt_str_len(np->data) - 1;
349 if (((i > 0) && (np->data[i - 1] == '/') && (np->data[i] == '*') &&
350 mutt_istrn_equal(type, np->data, i)) ||
351 mutt_istr_equal(type, np->data))
352 {
353 struct Body tmp = { 0 };
354 enum ContentType n;
355 if ((n = mutt_lookup_mime_type(&tmp, b->filename)) != TYPE_OTHER ||
357 {
358 snprintf(type, len, "%s/%s",
359 (n == TYPE_AUDIO) ? "audio" :
360 (n == TYPE_APPLICATION) ? "application" :
361 (n == TYPE_IMAGE) ? "image" :
362 (n == TYPE_MESSAGE) ? "message" :
363 (n == TYPE_MODEL) ? "model" :
364 (n == TYPE_MULTIPART) ? "multipart" :
365 (n == TYPE_TEXT) ? "text" :
366 (n == TYPE_VIDEO) ? "video" :
367 "other",
368 tmp.subtype);
369 mutt_debug(LL_DEBUG1, "\"%s\" -> %s\n", b->filename, type);
370 }
371 FREE(&tmp.subtype);
372 FREE(&tmp.xtype);
373 }
374 }
375}
struct ListHead MimeLookupList
List of mime types that that shouldn't use the mailcap entry.
Definition: globals.c:50
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:672
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:496
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:453
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:390
enum ContentType mutt_lookup_mime_type(struct Body *b, const char *path)
Find the MIME type for an attachment.
Definition: sendlib.c:76
char * xtype
content-type if x-unknown
Definition: body.h:62
A List node for strings.
Definition: list.h:37
char * data
String.
Definition: list.h:38
+ 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 b)

Create an attachment.

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

Definition at line 120 of file mutt_attach.c.

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

Decode, then save an attachment.

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

Definition at line 1039 of file mutt_attach.c.

1041{
1042 struct State state = { 0 };
1043 unsigned int saved_encoding = 0;
1044 struct Body *saved_parts = NULL;
1045 struct Email *e_saved = NULL;
1046 int rc = 0;
1047
1048 state.flags = flags;
1049
1050 if (opt == MUTT_SAVE_APPEND)
1051 state.fp_out = mutt_file_fopen_masked(path, "a");
1052 else
1053 state.fp_out = mutt_file_fopen_masked(path, "w");
1054
1055 if (!state.fp_out)
1056 {
1057 mutt_perror("fopen");
1058 return -1;
1059 }
1060
1061 if (fp)
1062 {
1063 state.fp_in = fp;
1064 state.flags |= STATE_CHARCONV;
1065 }
1066 else
1067 {
1068 /* When called from the compose menu, the attachment isn't parsed,
1069 * so we need to do it here. */
1070 state.fp_in = mutt_file_fopen(b->filename, "r");
1071 if (!state.fp_in)
1072 {
1073 mutt_perror("fopen");
1074 mutt_file_fclose(&state.fp_out);
1075 return -1;
1076 }
1077
1078 struct stat st = { 0 };
1079 if (fstat(fileno(state.fp_in), &st) == -1)
1080 {
1081 mutt_perror("stat");
1082 mutt_file_fclose(&state.fp_in);
1083 mutt_file_fclose(&state.fp_out);
1084 return -1;
1085 }
1086
1087 saved_encoding = b->encoding;
1088 if (!is_multipart(b))
1089 b->encoding = ENC_8BIT;
1090
1091 b->length = st.st_size;
1092 b->offset = 0;
1093 saved_parts = b->parts;
1094 e_saved = b->email;
1095 mutt_parse_part(state.fp_in, b);
1096
1097 if (b->noconv || is_multipart(b))
1098 state.flags |= STATE_CHARCONV;
1099 }
1100
1101 mutt_body_handler(b, &state);
1102
1103 if (mutt_file_fsync_close(&state.fp_out) != 0)
1104 {
1105 mutt_perror("fclose");
1106 rc = -1;
1107 }
1108 if (!fp)
1109 {
1110 b->length = 0;
1111 b->encoding = saved_encoding;
1112 if (saved_parts)
1113 {
1114 email_free(&b->email);
1115 b->parts = saved_parts;
1116 b->email = e_saved;
1117 }
1118 mutt_file_fclose(&state.fp_in);
1119 }
1120
1121 return rc;
1122}
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:46
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1822
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:131
int mutt_body_handler(struct Body *b, struct State *state)
Handler for the Body of an email.
Definition: handler.c:1632
@ ENC_8BIT
8-bit text
Definition: mime.h:50
#define is_multipart(body)
Definition: mime.h:82
#define mutt_file_fopen_masked(PATH, MODE)
Definition: neomutt.h:75
bool noconv
Don't do character set conversion.
Definition: body.h:46
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:41
The envelope/body of an email.
Definition: email.h:39
char * path
Path of Email (for local Mailboxes)
Definition: email.h:70
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_edit_attachment()

bool mutt_edit_attachment ( struct Body b)

Edit an attachment.

Parameters
bEmail containing attachment
Return values
trueEditor found
falseEditor 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 265 of file mutt_attach.c.

266{
267 char type[256] = { 0 };
268 struct MailcapEntry *entry = mailcap_entry_new();
269 bool unlink_newfile = false;
270 bool rc = false;
271 struct Buffer *cmd = buf_pool_get();
272 struct Buffer *newfile = buf_pool_get();
273
274 snprintf(type, sizeof(type), "%s/%s", TYPE(b), b->subtype);
275 if (mailcap_lookup(b, type, sizeof(type), entry, MUTT_MC_EDIT))
276 {
277 if (entry->editcommand)
278 {
279 buf_strcpy(cmd, entry->editcommand);
280 mailcap_expand_filename(entry->nametemplate, b->filename, newfile);
281 mutt_debug(LL_DEBUG1, "oldfile: %s newfile: %s\n", b->filename,
282 buf_string(newfile));
283 if (mutt_file_symlink(b->filename, buf_string(newfile)) == -1)
284 {
285 if (query_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
286 goto bailout;
287 buf_strcpy(newfile, b->filename);
288 }
289 else
290 {
291 unlink_newfile = true;
292 }
293
294 if (mailcap_expand_command(b, buf_string(newfile), type, cmd))
295 {
296 /* For now, editing requires a file, no piping */
297 mutt_error(_("Mailcap Edit entry requires %%s"));
298 goto bailout;
299 }
300 else
301 {
302 mutt_endwin();
303 if (mutt_system(buf_string(cmd)) == -1)
304 {
305 mutt_error(_("Error running \"%s\""), buf_string(cmd));
306 goto bailout;
307 }
308 }
309 }
310 }
311 else if (b->type == TYPE_TEXT)
312 {
313 /* On text, default to editor */
314 const char *const c_editor = cs_subset_string(NeoMutt->sub, "editor");
315 mutt_edit_file(NONULL(c_editor), b->filename);
316 }
317 else
318 {
319 mutt_error(_("No mailcap edit entry for %s"), type);
320 goto bailout;
321 }
322
323 rc = true;
324
325bailout:
326
327 if (unlink_newfile)
328 unlink(buf_string(newfile));
329
330 buf_pool_release(&cmd);
331 buf_pool_release(&newfile);
332
333 mailcap_entry_free(&entry);
334 return rc;
335}
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition: curs_lib.c:116
@ MUTT_MC_EDIT
Mailcap edit field.
Definition: mailcap.h:58
char * editcommand
Definition: mailcap.h:42
+ 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 b)

Get a temporary copy of an attachment.

Parameters
bAttachment to copy
Return values
0Success
-1Error

Definition at line 72 of file mutt_attach.c.

73{
74 char type[256] = { 0 };
75
76 if (b->unlink)
77 return 0;
78
79 struct Buffer *tempfile = buf_pool_get();
80 struct MailcapEntry *entry = mailcap_entry_new();
81 snprintf(type, sizeof(type), "%s/%s", TYPE(b), b->subtype);
82 mailcap_lookup(b, type, sizeof(type), entry, MUTT_MC_NO_FLAGS);
83 mailcap_expand_filename(entry->nametemplate, b->filename, tempfile);
84
85 mailcap_entry_free(&entry);
86
87 FILE *fp_in = NULL, *fp_out = NULL;
88 if ((fp_in = mutt_file_fopen(b->filename, "r")) &&
89 (fp_out = mutt_file_fopen(buf_string(tempfile), "w")))
90 {
91 mutt_file_copy_stream(fp_in, fp_out);
92 mutt_str_replace(&b->filename, buf_string(tempfile));
93 b->unlink = true;
94
95 struct stat st = { 0 };
96 if ((fstat(fileno(fp_in), &st) == 0) && (b->stamp >= st.st_mtime))
97 {
99 }
100 }
101 else
102 {
103 mutt_perror("%s", fp_in ? buf_string(tempfile) : b->filename);
104 }
105
106 mutt_file_fclose(&fp_in);
107 mutt_file_fclose(&fp_out);
108
109 buf_pool_release(&tempfile);
110
111 return b->unlink ? 0 : -1;
112}
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:280
void mutt_stamp_attachment(struct Body *b)
Timestamp an Attachment.
Definition: sendlib.c:410
time_t stamp
Time stamp of last encoding update.
Definition: body.h:77
+ 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,
const 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 739 of file mutt_attach.c.

740{
741 pid_t pid = 0;
742 int out = -1, rc = 0;
743 bool is_flowed = false;
744 bool unlink_unstuff = false;
745 FILE *fp_filter = NULL, *fp_unstuff = NULL, *fp_in = NULL;
746 struct Buffer *unstuff_tempfile = NULL;
747
748 if (outfile && *outfile)
749 {
750 out = mutt_file_open(outfile, O_CREAT | O_EXCL | O_WRONLY, 0600);
751 if (out < 0)
752 {
753 mutt_perror("open");
754 return 0;
755 }
756 }
757
759 {
760 is_flowed = true;
761 unstuff_tempfile = buf_pool_get();
762 buf_mktemp(unstuff_tempfile);
763 }
764
765 mutt_endwin();
766
767 if (outfile && *outfile)
768 pid = filter_create_fd(path, &fp_filter, NULL, NULL, -1, out, -1, EnvList);
769 else
770 pid = filter_create(path, &fp_filter, NULL, NULL, EnvList);
771 if (pid < 0)
772 {
773 mutt_perror(_("Can't create filter"));
774 goto bail;
775 }
776
777 /* recv case */
778 if (fp)
779 {
780 struct State state = { 0 };
781
782 /* perform charset conversion on text attachments when piping */
783 state.flags = STATE_CHARCONV;
784
785 if (is_flowed)
786 {
787 fp_unstuff = mutt_file_fopen(buf_string(unstuff_tempfile), "w");
788 if (!fp_unstuff)
789 {
790 mutt_perror("mutt_file_fopen");
791 goto bail;
792 }
793 unlink_unstuff = true;
794
795 state.fp_in = fp;
796 state.fp_out = fp_unstuff;
797 mutt_decode_attachment(b, &state);
798 mutt_file_fclose(&fp_unstuff);
799
801
802 fp_unstuff = mutt_file_fopen(buf_string(unstuff_tempfile), "r");
803 if (!fp_unstuff)
804 {
805 mutt_perror("mutt_file_fopen");
806 goto bail;
807 }
808 mutt_file_copy_stream(fp_unstuff, fp_filter);
809 mutt_file_fclose(&fp_unstuff);
810 }
811 else
812 {
813 state.fp_in = fp;
814 state.fp_out = fp_filter;
815 mutt_decode_attachment(b, &state);
816 }
817 }
818 else
819 {
820 /* send case */
821 const char *infile = NULL;
822
823 if (is_flowed)
824 {
825 if (mutt_save_attachment(fp, b, buf_string(unstuff_tempfile),
826 MUTT_SAVE_NO_FLAGS, NULL) == -1)
827 {
828 goto bail;
829 }
830 unlink_unstuff = true;
832 infile = buf_string(unstuff_tempfile);
833 }
834 else
835 {
836 infile = b->filename;
837 }
838
839 fp_in = mutt_file_fopen(infile, "r");
840 if (!fp_in)
841 {
842 mutt_perror("fopen");
843 goto bail;
844 }
845
846 mutt_file_copy_stream(fp_in, fp_filter);
848 }
849
850 mutt_file_fclose(&fp_filter);
851 rc = 1;
852
853bail:
854 if (outfile && *outfile)
855 {
856 close(out);
857 if (rc == 0)
858 unlink(outfile);
859 else if (is_flowed)
861 }
862
863 mutt_file_fclose(&fp_unstuff);
864 mutt_file_fclose(&fp_filter);
866
867 if (unlink_unstuff)
868 mutt_file_unlink(buf_string(unstuff_tempfile));
869 buf_pool_release(&unstuff_tempfile);
870
871 /* check for error exit from child process */
872 if ((pid > 0) && (filter_wait(pid) != 0))
873 rc = 0;
874
875 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
876 if ((rc == 0) || c_wait_key)
878 return rc;
879}
void mutt_rfc3676_space_stuff_attachment(struct Body *b, const char *filename)
Stuff attachments.
Definition: rfc3676.c:539
bool mutt_rfc3676_is_format_flowed(struct Body *b)
Is the Email "format-flowed"?
Definition: rfc3676.c:394
+ 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 b 
)

Print out an attachment.

Parameters
fpFile to write to
bAttachment
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 1137 of file mutt_attach.c.

1138{
1139 char type[256] = { 0 };
1140 pid_t pid;
1141 FILE *fp_in = NULL, *fp_out = NULL;
1142 bool unlink_newfile = false;
1143 struct Buffer *newfile = buf_pool_get();
1144 struct Buffer *cmd = buf_pool_get();
1145
1146 int rc = 0;
1147
1148 snprintf(type, sizeof(type), "%s/%s", TYPE(b), b->subtype);
1149
1150 if (mailcap_lookup(b, type, sizeof(type), NULL, MUTT_MC_PRINT))
1151 {
1152 mutt_debug(LL_DEBUG2, "Using mailcap\n");
1153
1154 struct MailcapEntry *entry = mailcap_entry_new();
1155 mailcap_lookup(b, type, sizeof(type), entry, MUTT_MC_PRINT);
1156
1157 char *sanitized_fname = mutt_str_dup(b->filename);
1158 /* In send mode (!fp), we allow slashes because those are part of
1159 * the tempfile. The path will be removed in expand_filename */
1160 mutt_file_sanitize_filename(sanitized_fname, fp ? true : false);
1161 mailcap_expand_filename(entry->nametemplate, sanitized_fname, newfile);
1162 FREE(&sanitized_fname);
1163
1164 if (mutt_save_attachment(fp, b, buf_string(newfile), MUTT_SAVE_NO_FLAGS, NULL) == -1)
1165 {
1166 goto mailcap_cleanup;
1167 }
1168 unlink_newfile = 1;
1169
1171
1172 buf_strcpy(cmd, entry->printcommand);
1173
1174 bool piped = mailcap_expand_command(b, buf_string(newfile), type, cmd);
1175
1176 mutt_endwin();
1177
1178 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
1179 /* interactive program */
1180 if (piped)
1181 {
1182 fp_in = mutt_file_fopen(buf_string(newfile), "r");
1183 if (!fp_in)
1184 {
1185 mutt_perror("fopen");
1186 mailcap_entry_free(&entry);
1187 goto mailcap_cleanup;
1188 }
1189
1190 pid = filter_create(buf_string(cmd), &fp_out, NULL, NULL, EnvList);
1191 if (pid < 0)
1192 {
1193 mutt_perror(_("Can't create filter"));
1194 mailcap_entry_free(&entry);
1195 mutt_file_fclose(&fp_in);
1196 goto mailcap_cleanup;
1197 }
1198 mutt_file_copy_stream(fp_in, fp_out);
1199 mutt_file_fclose(&fp_out);
1200 mutt_file_fclose(&fp_in);
1201 if (filter_wait(pid) || c_wait_key)
1203 }
1204 else
1205 {
1206 int rc2 = mutt_system(buf_string(cmd));
1207 if (rc2 == -1)
1208 mutt_debug(LL_DEBUG1, "Error running \"%s\"\n", cmd->data);
1209
1210 if ((rc2 != 0) || c_wait_key)
1212 }
1213
1214 rc = 1;
1215
1216 mailcap_cleanup:
1217 if (unlink_newfile)
1218 mutt_file_unlink(buf_string(newfile));
1219
1220 mailcap_entry_free(&entry);
1221 goto out;
1222 }
1223
1224 const char *const c_print_command = cs_subset_string(NeoMutt->sub, "print_command");
1225 if (mutt_istr_equal("text/plain", type) || mutt_istr_equal("application/postscript", type))
1226 {
1227 rc = (mutt_pipe_attachment(fp, b, NONULL(c_print_command), NULL));
1228 goto out;
1229 }
1230 else if (mutt_can_decode(b))
1231 {
1232 /* decode and print */
1233
1234 fp_in = NULL;
1235 fp_out = NULL;
1236
1237 buf_mktemp(newfile);
1239 MUTT_SAVE_NO_FLAGS) == 0)
1240 {
1241 unlink_newfile = true;
1242 mutt_debug(LL_DEBUG2, "successfully decoded %s type attachment to %s\n",
1243 type, buf_string(newfile));
1244
1245 fp_in = mutt_file_fopen(buf_string(newfile), "r");
1246 if (!fp_in)
1247 {
1248 mutt_perror("fopen");
1249 goto decode_cleanup;
1250 }
1251
1252 mutt_debug(LL_DEBUG2, "successfully opened %s read-only\n", buf_string(newfile));
1253
1254 mutt_endwin();
1255 pid = filter_create(NONULL(c_print_command), &fp_out, NULL, NULL, EnvList);
1256 if (pid < 0)
1257 {
1258 mutt_perror(_("Can't create filter"));
1259 goto decode_cleanup;
1260 }
1261
1262 mutt_debug(LL_DEBUG2, "Filter created\n");
1263
1264 mutt_file_copy_stream(fp_in, fp_out);
1265
1266 mutt_file_fclose(&fp_out);
1267 mutt_file_fclose(&fp_in);
1268
1269 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
1270 if ((filter_wait(pid) != 0) || c_wait_key)
1272 rc = 1;
1273 }
1274 decode_cleanup:
1275 mutt_file_fclose(&fp_in);
1276 mutt_file_fclose(&fp_out);
1277 if (unlink_newfile)
1278 mutt_file_unlink(buf_string(newfile));
1279 }
1280 else
1281 {
1282 mutt_error(_("I don't know how to print that"));
1283 rc = 0;
1284 }
1285
1286out:
1287 buf_pool_release(&newfile);
1288 buf_pool_release(&cmd);
1289
1290 return rc;
1291}
bool mutt_can_decode(struct Body *b)
Will decoding the attachment produce any output.
Definition: handler.c:1866
@ MUTT_MC_PRINT
Mailcap print field.
Definition: mailcap.h:60
#define STATE_PRINTING
Are we printing? - STATE_DISPLAY "light".
Definition: state.h:38
int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, const char *outfile)
Pipe an attachment to a command.
Definition: mutt_attach.c:739
char * printcommand
Definition: mailcap.h:43
+ 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 b,
const char *  path,
enum SaveAttach  opt,
struct Email e 
)

Save an attachment.

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

Definition at line 905 of file mutt_attach.c.

907{
908 if (!b)
909 return -1;
910
911 if (fp)
912 {
913 /* recv mode */
914
915 if (e && b->email && (b->encoding != ENC_BASE64) &&
917 {
918 /* message type attachments are written to mail folders. */
919
920 char buf[8192] = { 0 };
921 struct Message *msg = NULL;
923 int rc = -1;
924
925 struct Email *e_new = b->email;
926 e_new->msgno = e->msgno; /* required for MH/maildir */
927 e_new->read = true;
928
929 if (!mutt_file_seek(fp, b->offset, SEEK_SET))
930 return -1;
931 if (!fgets(buf, sizeof(buf), fp))
932 return -1;
933 struct Mailbox *m_att = mx_path_resolve(path);
934 if (!mx_mbox_open(m_att, MUTT_APPEND | MUTT_QUIET))
935 {
936 mailbox_free(&m_att);
937 return -1;
938 }
939 msg = mx_msg_open_new(m_att, e_new,
940 is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
941 if (!msg)
942 {
943 mx_mbox_close(m_att);
944 return -1;
945 }
946 if ((m_att->type == MUTT_MBOX) || (m_att->type == MUTT_MMDF))
947 chflags = CH_FROM | CH_UPDATE_LEN;
948 chflags |= ((m_att->type == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
949 if ((mutt_copy_message_fp(msg->fp, fp, e_new, MUTT_CM_NO_FLAGS, chflags, 0) == 0) &&
950 (mx_msg_commit(m_att, msg) == 0))
951 {
952 rc = 0;
953 }
954 else
955 {
956 rc = -1;
957 }
958
959 mx_msg_close(m_att, &msg);
960 mx_mbox_close(m_att);
961 return rc;
962 }
963 else
964 {
965 /* In recv mode, extract from folder and decode */
966
967 struct State state = { 0 };
968
969 state.fp_out = save_attachment_open(path, opt);
970 if (!state.fp_out)
971 {
972 mutt_perror("fopen");
973 return -1;
974 }
975 if (!mutt_file_seek((state.fp_in = fp), b->offset, SEEK_SET))
976 {
977 mutt_file_fclose(&state.fp_out);
978 return -1;
979 }
980 mutt_decode_attachment(b, &state);
981
982 if (mutt_file_fsync_close(&state.fp_out) != 0)
983 {
984 mutt_perror("fclose");
985 return -1;
986 }
987 }
988 }
989 else
990 {
991 if (!b->filename)
992 return -1;
993
994 /* In send mode, just copy file */
995
996 FILE *fp_old = mutt_file_fopen(b->filename, "r");
997 if (!fp_old)
998 {
999 mutt_perror("fopen");
1000 return -1;
1001 }
1002
1003 FILE *fp_new = save_attachment_open(path, opt);
1004 if (!fp_new)
1005 {
1006 mutt_perror("fopen");
1007 mutt_file_fclose(&fp_old);
1008 return -1;
1009 }
1010
1011 if (mutt_file_copy_stream(fp_old, fp_new) == -1)
1012 {
1013 mutt_error(_("Write fault"));
1014 mutt_file_fclose(&fp_old);
1015 mutt_file_fclose(&fp_new);
1016 return -1;
1017 }
1018 mutt_file_fclose(&fp_old);
1019 if (mutt_file_fsync_close(&fp_new) != 0)
1020 {
1021 mutt_error(_("Write fault"));
1022 return -1;
1023 }
1024 }
1025
1026 return 0;
1027}
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:657
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:54
#define CH_NOSTATUS
Suppress the status and x-status fields.
Definition: copy.h:60
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:58
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:52
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:64
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:37
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:53
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:89
@ MUTT_MMDF
'mmdf' Mailbox type
Definition: mailbox.h:46
@ MUTT_MBOX
'mbox' Mailbox type
Definition: mailbox.h:45
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition: mailbox.h:48
bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
Is a string a 'From' header line?
Definition: from.c:49
@ 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:887
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition: mx.c:1184
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:288
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1044
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1163
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1640
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:598
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:39
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:38
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mxapi.h:42
#define MUTT_QUIET
Do not print any messages.
Definition: mxapi.h:44
bool read
Email is read.
Definition: email.h:50
int msgno
Number displayed to the user.
Definition: email.h:111
A mailbox.
Definition: mailbox.h:79
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
A local copy of an email.
Definition: message.h:34
FILE * fp
pointer to the message data
Definition: message.h:35
+ 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 1297 of file mutt_attach.c.

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

◆ mutt_temp_attachments_cleanup()

void mutt_temp_attachments_cleanup ( void  )

Delete all temporary attachments.

Definition at line 1305 of file mutt_attach.c.

1306{
1307 struct ListNode *np = NULL;
1308
1309 STAILQ_FOREACH(np, &TempAttachmentsList, entries)
1310 {
1311 (void) mutt_file_chmod_add(np->data, S_IWUSR);
1313 }
1314
1316}
int mutt_file_chmod_add(const char *path, mode_t mode)
Add permissions to a file.
Definition: file.c:1009
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:123
+ Here is the call graph for this function:
+ Here is the caller graph for this function: