NeoMutt  2025-12-11-435-g4ac674
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 959 of file recvattach.c.

961{
962 do
963 {
964 switch (op)
965 {
966 case OP_DISPLAY_HEADERS:
967 bool_str_toggle(NeoMutt->sub, "weed", NULL);
969
970 case OP_ATTACHMENT_VIEW:
971 {
972 struct AttachPtr *cur_att = current_attachment(actx, menu);
973 if (!cur_att->fp)
974 {
975 if (cur_att->body->type == TYPE_MULTIPART)
976 {
977 struct Body *b = cur_att->body->parts;
978 while (b && b->parts)
979 b = b->parts;
980 if (b)
981 cur_att = b->aptr;
982 }
983 }
984 op = mutt_view_attachment(cur_att->fp, cur_att->body, MUTT_VA_REGULAR,
985 e, actx, menu->win);
986 break;
987 }
988
989 case OP_NEXT_ENTRY:
990 case OP_MAIN_NEXT_UNDELETED: /* hack */
991 {
992 const int index = menu_get_index(menu) + 1;
993 if (index < menu->max)
994 {
995 menu_set_index(menu, index);
996 op = OP_ATTACHMENT_VIEW;
997 }
998 else
999 {
1000 op = OP_NULL;
1001 }
1002 break;
1003 }
1004
1005 case OP_PREV_ENTRY:
1006 case OP_MAIN_PREV_UNDELETED: /* hack */
1007 {
1008 const int index = menu_get_index(menu) - 1;
1009 if (index >= 0)
1010 {
1011 menu_set_index(menu, index);
1012 op = OP_ATTACHMENT_VIEW;
1013 }
1014 else
1015 {
1016 op = OP_NULL;
1017 }
1018 break;
1019 }
1020
1021 case OP_ATTACHMENT_EDIT_TYPE:
1022 {
1023 struct AttachPtr *cur_att = current_attachment(actx, menu);
1024 /* when we edit the content-type, we should redisplay the attachment
1025 * immediately */
1026 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1027 if (recv)
1028 recvattach_edit_content_type(actx, menu, e);
1029 else
1030 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1031
1033 op = OP_ATTACHMENT_VIEW;
1034 break;
1035 }
1036 /* functions which are passed through from the pager */
1037 case OP_PIPE:
1038 {
1039 struct AttachPtr *cur_att = current_attachment(actx, menu);
1040 mutt_pipe_attachment_list(actx, cur_att->fp, false, cur_att->body, false);
1041 op = OP_ATTACHMENT_VIEW;
1042 break;
1043 }
1044 case OP_ATTACHMENT_PRINT:
1045 {
1046 struct AttachPtr *cur_att = current_attachment(actx, menu);
1047 mutt_print_attachment_list(actx, cur_att->fp, false, cur_att->body);
1048 op = OP_ATTACHMENT_VIEW;
1049 break;
1050 }
1051 case OP_ATTACHMENT_SAVE:
1052 {
1053 struct AttachPtr *cur_att = current_attachment(actx, menu);
1054 mutt_save_attachment_list(actx, cur_att->fp, false, cur_att->body, e, NULL);
1055 op = OP_ATTACHMENT_VIEW;
1056 break;
1057 }
1058 case OP_CHECK_TRADITIONAL:
1060 {
1061 op = OP_NULL;
1062 break;
1063 }
1065
1066 case OP_ATTACHMENT_COLLAPSE:
1067 if (recv)
1068 return op;
1070
1071 default:
1072 op = OP_NULL;
1073 }
1074 } while (op != OP_NULL);
1075
1076 return op;
1077}
int bool_str_toggle(struct ConfigSubset *sub, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition bool.c:229
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition external.c:1072
#define MENU_REDRAW_INDEX
Redraw the index.
Definition lib.h:57
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition menu.c:188
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition menu.c:164
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition menu.c:178
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition mime.h:37
#define FALLTHROUGH
Definition lib.h:117
int mutt_view_attachment(FILE *fp, struct Body *b, enum ViewAttachMode mode, struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
View an attachment.
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition lib.h:100
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:98
#define WithCrypto
Definition lib.h:124
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:426
struct AttachPtr * current_attachment(struct AttachCtx *actx, struct Menu *menu)
Get the current attachment.
Definition recvattach.c:71
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:718
void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b)
Print a list of Attachments.
Definition recvattach.c:884
void recvattach_edit_content_type(struct AttachCtx *actx, struct Menu *menu, struct Email *e)
Edit the content type of an attachment.
Definition recvattach.c:929
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:88
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
+ 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 426 of file recvattach.c.

428{
429 char *directory = NULL;
430 int rc = 1;
431 int last = menu_get_index(menu);
432 FILE *fp_out = NULL;
433 int saved_attachments = 0;
434
435 struct Buffer *buf = buf_pool_get();
436 struct Buffer *tfile = buf_pool_get();
437
438 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
439 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
440 const bool c_attach_save_without_prompting = cs_subset_bool(NeoMutt->sub, "attach_save_without_prompting");
441
442 for (int i = 0; !tag || (i < actx->idxlen); i++)
443 {
444 if (tag)
445 {
446 fp = actx->idx[i]->fp;
447 b = actx->idx[i]->body;
448 }
449 if (!tag || b->tagged)
450 {
451 if (c_attach_split)
452 {
453 if (tag && menu && b->aptr)
454 {
455 menu_set_index(menu, b->aptr->num);
457
458 menu_redraw(menu);
459 }
460 if (c_attach_save_without_prompting)
461 {
462 // Save each file, with no prompting, using the configured 'AttachSaveDir'
463 rc = save_without_prompting(fp, b, e);
464 if (rc == 0)
465 saved_attachments++;
466 }
467 else
468 {
469 // Save each file, prompting the user for the location each time.
470 if (query_save_attachment(fp, b, e, &directory) == -1)
471 break;
472 }
473 }
474 else
475 {
477
478 if (buf_is_empty(buf))
479 {
481 prepend_savedir(buf);
482
483 struct FileCompletionData cdata = { false, NULL, NULL, NULL, NULL };
484 if ((mw_get_field(_("Save to file: "), buf, MUTT_COMP_CLEAR, HC_FILE,
485 &CompleteFileOps, &cdata) != 0) ||
486 buf_is_empty(buf))
487 {
488 goto cleanup;
489 }
490 expand_path(buf, false);
491 if (mutt_check_overwrite(b->filename, buf_string(buf), tfile, &opt, NULL))
492 goto cleanup;
493 }
494 else
495 {
496 opt = MUTT_SAVE_APPEND;
497 }
498
499 rc = save_attachment_flowed_helper(fp, b, buf_string(tfile), opt, e);
500 if ((rc == 0) && c_attach_sep && (fp_out = mutt_file_fopen(buf_string(tfile), "a")))
501 {
502 fprintf(fp_out, "%s", c_attach_sep);
503 mutt_file_fclose(&fp_out);
504 }
505 }
506 }
507 if (!tag)
508 break;
509 }
510
511 FREE(&directory);
512
513 if (tag && menu)
514 {
515 menu_set_index(menu, last);
517 }
518
519 if (rc == 0)
520 {
521 if (!c_attach_split)
522 saved_attachments = 1;
523
524 if (!c_attach_split || c_attach_save_without_prompting)
525 {
526 mutt_message(ngettext("Attachment saved", "%d attachments saved", saved_attachments),
527 saved_attachments);
528 }
529 }
530
531cleanup:
532 buf_pool_release(&buf);
533 buf_pool_release(&tfile);
534}
const struct CompleteOps CompleteFileOps
Auto-Completion of Files.
Definition complete.c:152
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:482
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition wdata.h:43
#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:270
#define mutt_message(...)
Definition logging2.h:93
@ HC_FILE
Files.
Definition lib.h:58
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define MENU_REDRAW_MOTION
Redraw after moving the menu list.
Definition lib.h:58
#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
SaveAttach
Options for saving attachments.
Definition mutt_attach.h:57
void expand_path(struct Buffer *buf, bool regex)
Create the canonical path.
Definition muttlib.c:121
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:523
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
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:226
static int save_without_prompting(FILE *fp, struct Body *b, struct Email *e)
Save the attachment, without prompting each time.
Definition recvattach.c:376
static void prepend_savedir(struct Buffer *buf)
Add $attach_save_dir to the beginning of a path.
Definition recvattach.c:167
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:272
#define NONULL(x)
Definition string2.h:44
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:39
+ 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 718 of file recvattach.c.

720{
721 struct State state = { 0 };
722 struct Buffer *buf = NULL;
723
724 if (fp)
725 filter = false; /* sanity check: we can't filter in the recv case yet */
726
727 buf = buf_pool_get();
728 /* perform charset conversion on text attachments when piping */
729 state.flags = STATE_CHARCONV;
730
731 if (mw_get_field((filter ? _("Filter through: ") : _("Pipe to: ")), buf,
733 {
734 goto cleanup;
735 }
736
737 if (buf_is_empty(buf))
738 goto cleanup;
739
740 expand_path(buf, false);
741
742 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
743 if (!filter && !c_attach_split)
744 {
745 mutt_endwin();
746 pid_t pid = filter_create(buf_string(buf), &state.fp_out, NULL, NULL,
747 NeoMutt->env);
748 pipe_attachment_list(buf_string(buf), actx, fp, tag, b, filter, &state);
749 mutt_file_fclose(&state.fp_out);
750 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
751 if ((filter_wait(pid) != 0) || c_wait_key)
753 }
754 else
755 {
756 pipe_attachment_list(buf_string(buf), actx, fp, tag, b, filter, &state);
757 }
758
759cleanup:
760 buf_pool_release(&buf);
761}
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
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition wdata.h:42
@ HC_EXT_COMMAND
External commands.
Definition lib.h:55
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
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:686
char ** env
Private copy of the environment variables.
Definition neomutt.h:58
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 884 of file recvattach.c.

885{
886 char prompt[128] = { 0 };
887 struct State state = { 0 };
888 int tagmsgcount = 0;
889
890 if (tag)
891 for (int i = 0; i < actx->idxlen; i++)
892 if (actx->idx[i]->body->tagged)
893 tagmsgcount++;
894
895 snprintf(prompt, sizeof(prompt),
896 tag ? ngettext("Print tagged attachment?", "Print %d tagged attachments?", tagmsgcount) :
897 _("Print attachment?"),
898 tagmsgcount);
899 if (query_quadoption(prompt, NeoMutt->sub, "print") != MUTT_YES)
900 return;
901
902 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
903 if (c_attach_split)
904 {
905 print_attachment_list(actx, fp, tag, b, &state);
906 }
907 else
908 {
909 if (!can_print(actx, b, tag))
910 return;
911 mutt_endwin();
912 const char *const c_print_command = cs_subset_string(NeoMutt->sub, "print_command");
913 pid_t pid = filter_create(NONULL(c_print_command), &state.fp_out, NULL,
914 NULL, NeoMutt->env);
915 print_attachment_list(actx, fp, tag, b, &state);
916 mutt_file_fclose(&state.fp_out);
917 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
918 if ((filter_wait(pid) != 0) || c_wait_key)
920 }
921}
@ 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:378
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:810
static bool can_print(struct AttachCtx *actx, struct Body *b, bool tag)
Do we know how to print this attachment type?
Definition recvattach.c:770
+ 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 418 of file mutt_attach.c.

420{
421 bool use_mailcap = false;
422 bool use_pipe = false;
423 bool use_pager = true;
424 char type[256] = { 0 };
425 char desc[512] = { 0 };
426 char *fname = NULL;
427 struct MailcapEntry *entry = NULL;
428 int rc = -1;
429 bool has_tempfile = false;
430 bool unlink_pagerfile = false;
431
432 bool is_message = mutt_is_message_type(b->type, b->subtype);
433 if ((WithCrypto != 0) && is_message && b->email &&
435 {
436 return rc;
437 }
438
439 struct Buffer *tempfile = buf_pool_get();
440 struct Buffer *pagerfile = buf_pool_get();
441 struct Buffer *cmd = buf_pool_get();
442
443 use_mailcap = ((mode == MUTT_VA_MAILCAP) ||
444 ((mode == MUTT_VA_REGULAR) && mutt_needs_mailcap(b)) ||
445 (mode == MUTT_VA_PAGER));
446 snprintf(type, sizeof(type), "%s/%s", BODY_TYPE(b), b->subtype);
447
448 char columns[16] = { 0 };
449 snprintf(columns, sizeof(columns), "%d", win->state.cols);
450 envlist_set(&NeoMutt->env, "COLUMNS", columns, true);
451
452 if (use_mailcap)
453 {
454 entry = mailcap_entry_new();
455 enum MailcapLookup mailcap_opt = (mode == MUTT_VA_PAGER) ? MUTT_MC_AUTOVIEW : MUTT_MC_NO_FLAGS;
456 if (!mailcap_lookup(b, type, sizeof(type), entry, mailcap_opt))
457 {
458 if ((mode == MUTT_VA_REGULAR) || (mode == MUTT_VA_PAGER))
459 {
460 /* fallback to view as text */
461 mailcap_entry_free(&entry);
462 mutt_error(_("No matching mailcap entry found. Viewing as text."));
463 mode = MUTT_VA_AS_TEXT;
464 use_mailcap = false;
465 }
466 else
467 {
468 goto return_error;
469 }
470 }
471 }
472
473 if (use_mailcap)
474 {
475 if (!entry->command)
476 {
477 mutt_error(_("MIME type not defined. Can't view attachment."));
478 goto return_error;
479 }
480 buf_strcpy(cmd, entry->command);
481
482 fname = mutt_str_dup(b->filename);
483 /* In send mode(!fp), we allow slashes because those are part of
484 * the tempfile. The path will be removed in expand_filename */
485 mutt_file_sanitize_filename(fname, fp ? true : false);
486 mailcap_expand_filename(entry->nametemplate, fname, tempfile);
487 FREE(&fname);
488
489 if (mutt_save_attachment(fp, b, buf_string(tempfile), 0, NULL) == -1)
490 goto return_error;
491 has_tempfile = true;
492
494
495 /* check for multipart/related and save attachments with b Content-ID */
496 if (mutt_str_equal(type, "text/html"))
497 {
498 struct Body *related_ancestor = NULL;
499 if (actx->body_idx && (WithCrypto != 0) && (e->security & SEC_ENCRYPT))
500 related_ancestor = attach_body_ancestor(actx->body_idx[0], b, "related");
501 else
502 related_ancestor = attach_body_ancestor(e->body, b, "related");
503 if (related_ancestor)
504 {
505 struct CidMapList cid_map_list = STAILQ_HEAD_INITIALIZER(cid_map_list);
506 mutt_debug(LL_DEBUG2, "viewing text/html attachment in multipart/related group\n");
507 /* save attachments and build cid_map_list Content-ID to filename mapping list */
508 cid_save_attachments(related_ancestor->parts, &cid_map_list);
509 /* replace Content-IDs with filenames */
510 cid_to_filename(tempfile, &cid_map_list);
511 /* empty Content-ID to filename mapping list */
512 cid_map_list_clear(&cid_map_list);
513 }
514 }
515
516 use_pipe = mailcap_expand_command(b, buf_string(tempfile), type, cmd);
517 use_pager = entry->copiousoutput;
518 }
519
520 if (use_pager)
521 {
522 if (fp && !use_mailcap && b->filename)
523 {
524 /* recv case */
525 buf_strcpy(pagerfile, b->filename);
526 mutt_adv_mktemp(pagerfile);
527 }
528 else
529 {
530 buf_mktemp(pagerfile);
531 }
532 }
533
534 if (use_mailcap)
535 {
536 pid_t pid = 0;
537 int fd_temp = -1, fd_pager = -1;
538
539 if (!use_pager)
540 mutt_endwin();
541
542 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
543 if (use_pager || use_pipe)
544 {
545 if (use_pager &&
546 ((fd_pager = mutt_file_open(buf_string(pagerfile),
547 O_CREAT | O_EXCL | O_WRONLY, 0600)) == -1))
548 {
549 mutt_perror("open");
550 goto return_error;
551 }
552 unlink_pagerfile = true;
553
554 if (use_pipe && ((fd_temp = open(buf_string(tempfile), 0)) == -1))
555 {
556 if (fd_pager != -1)
557 close(fd_pager);
558 mutt_perror("open");
559 goto return_error;
560 }
561 unlink_pagerfile = true;
562
563 pid = filter_create_fd(buf_string(cmd), NULL, NULL, NULL, use_pipe ? fd_temp : -1,
564 use_pager ? fd_pager : -1, -1, NeoMutt->env);
565
566 if (pid == -1)
567 {
568 if (fd_pager != -1)
569 close(fd_pager);
570
571 if (fd_temp != -1)
572 close(fd_temp);
573
574 mutt_error(_("Can't create filter"));
575 goto return_error;
576 }
577
578 if (use_pager)
579 {
580 if (b->description)
581 {
582 snprintf(desc, sizeof(desc), _("---Command: %-20.20s Description: %s"),
583 buf_string(cmd), b->description);
584 }
585 else
586 {
587 snprintf(desc, sizeof(desc), _("---Command: %-30.30s Attachment: %s"),
588 buf_string(cmd), type);
589 }
590 filter_wait(pid);
591 }
592 else
593 {
594 if (wait_interactive_filter(pid) || (entry->needsterminal && c_wait_key))
596 }
597
598 if (fd_temp != -1)
599 close(fd_temp);
600 if (fd_pager != -1)
601 close(fd_pager);
602 }
603 else
604 {
605 /* interactive cmd */
606 int rv = mutt_system(buf_string(cmd));
607 if (rv == -1)
608 mutt_debug(LL_DEBUG1, "Error running \"%s\"\n", cmd->data);
609
610 if ((rv != 0) || (entry->needsterminal && c_wait_key))
612 }
613 }
614 else
615 {
616 /* Don't use mailcap; the attachment is viewed in the pager */
617
618 if (mode == MUTT_VA_AS_TEXT)
619 {
620 /* just let me see the raw data */
621 if (fp)
622 {
623 /* Viewing from a received message.
624 *
625 * Don't use mutt_save_attachment() because we want to perform charset
626 * conversion since this will be displayed by the internal pager. */
627 struct State state = { 0 };
628
629 state.fp_out = mutt_file_fopen(buf_string(pagerfile), "w");
630 if (!state.fp_out)
631 {
632 mutt_debug(LL_DEBUG1, "mutt_file_fopen(%s) errno=%d %s\n",
633 buf_string(pagerfile), errno, strerror(errno));
634 mutt_perror("%s", buf_string(pagerfile));
635 goto return_error;
636 }
637 state.fp_in = fp;
638 state.flags = STATE_CHARCONV;
639 mutt_decode_attachment(b, &state);
640 mutt_file_fclose(&state.fp_out);
641 }
642 else
643 {
644 /* in compose mode, just copy the file. we can't use
645 * mutt_decode_attachment() since it assumes the content-encoding has
646 * already been applied */
647 if (mutt_save_attachment(fp, b, buf_string(pagerfile), MUTT_SAVE_NO_FLAGS, NULL))
648 goto return_error;
649 unlink_pagerfile = true;
650 }
652 }
653 else
654 {
656 const char *const c_pager = pager_get_pager(NeoMutt->sub);
657 if (!c_pager)
659
660 /* Use built-in handler */
662 {
663 goto return_error;
664 }
665 unlink_pagerfile = true;
666 }
667
668 if (b->description)
669 mutt_str_copy(desc, b->description, sizeof(desc));
670 else if (b->filename)
671 snprintf(desc, sizeof(desc), _("---Attachment: %s: %s"), b->filename, type);
672 else
673 snprintf(desc, sizeof(desc), _("---Attachment: %s"), type);
674 }
675
676 /* We only reach this point if there have been no errors */
677
678 if (use_pager)
679 {
680 struct PagerData pdata = { 0 };
681 struct PagerView pview = { &pdata };
682
683 pdata.actx = actx;
684 pdata.body = b;
685 pdata.fname = buf_string(pagerfile);
686 pdata.fp = fp;
687
688 pview.banner = desc;
690 (is_message ? MUTT_PAGER_MESSAGE : MUTT_PAGER_NO_FLAGS) |
691 ((use_mailcap && entry->xneomuttnowrap) ? MUTT_PAGER_NOWRAP :
693 pview.mode = PAGER_MODE_ATTACH;
694
695 rc = mutt_do_pager(&pview, e);
696
697 buf_reset(pagerfile);
698 unlink_pagerfile = false;
699 }
700 else
701 {
702 rc = 0;
703 }
704
705return_error:
706
707 if (!entry || !entry->xneomuttkeep)
708 {
709 if ((fp && !buf_is_empty(tempfile)) || has_tempfile)
710 {
711 /* add temporary file to list of files to be deleted on timeout hook */
713 }
714 }
715
716 mailcap_entry_free(&entry);
717
718 if (unlink_pagerfile)
719 mutt_file_unlink(buf_string(pagerfile));
720
721 buf_pool_release(&tempfile);
722 buf_pool_release(&pagerfile);
723 buf_pool_release(&cmd);
724 envlist_unset(&NeoMutt->env, "COLUMNS");
725
726 return rc;
727}
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:172
void cid_to_filename(struct Buffer *filename, const struct CidMapList *cid_map_list)
Replace Content-IDs with filenames.
Definition cid.c:182
void cid_map_list_clear(struct CidMapList *cid_map_list)
Empty a CidMapList.
Definition cid.c:80
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition crypt.c:131
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:1506
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:586
int mutt_file_open(const char *path, uint32_t flags, mode_t mode)
Open a file.
Definition file.c:512
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition file.c:156
#define mutt_error(...)
Definition logging2.h:94
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
#define mutt_perror(...)
Definition logging2.h:95
void mutt_decode_attachment(const struct Body *b, struct State *state)
Decode an email's attachment.
Definition handler.c:1933
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
void mailcap_entry_free(struct MailcapEntry **ptr)
Deallocate an struct MailcapEntry.
Definition mailcap.c:455
struct MailcapEntry * mailcap_entry_new(void)
Allocate memory for a new rfc1524 entry.
Definition mailcap.c:446
int mailcap_expand_command(struct Body *b, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition mailcap.c:70
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:553
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:484
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 BODY_TYPE(body)
Get the type name of a body part.
Definition mime.h:93
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:257
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:662
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:583
int mutt_system(const char *cmd)
Run an external command.
Definition system.c:51
static int wait_interactive_filter(pid_t pid)
Wait after an interactive filter.
int mutt_save_attachment(FILE *fp, struct Body *b, const char *path, enum SaveAttach opt, struct Email *e)
Save 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.
void mutt_add_temp_attachment(const char *filename)
Add file to list of temporary attachments.
bool mutt_needs_mailcap(struct Body *b)
Does this type need a mailcap entry do display.
Definition muttlib.c:367
void mutt_adv_mktemp(struct Buffer *buf)
Create a temporary file.
Definition muttlib.c:83
#define SEC_ENCRYPT
Email is encrypted.
Definition lib.h:86
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:62
#define MUTT_PAGER_NOWRAP
Format for term width, ignore $wrap.
Definition lib.h:73
@ 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:139
#define MUTT_PAGER_MESSAGE
Definition lib.h:77
#define MUTT_PAGER_ATTACHMENT
Attachments may exist.
Definition lib.h:72
#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:522
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
Filename template.
Definition mailcap.h:44
char * command
Command to run.
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.
Data to be displayed by PagerView.
Definition lib.h:161
const char * fname
Name of the file to read.
Definition lib.h:165
FILE * fp
Source stream.
Definition lib.h:163
struct Body * body
Current attachment.
Definition lib.h:162
struct AttachCtx * actx
Attachment information.
Definition lib.h:164
Paged view into some data.
Definition lib.h:172
struct PagerData * pdata
Data that pager displays. NOTNULL.
Definition lib.h:173
enum PagerMode mode
Pager mode.
Definition lib.h:174
PagerFlags flags
Additional settings to tweak pager's function.
Definition lib.h:175
const char * banner
Title to display in status bar.
Definition lib.h:176
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:60
#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 339 of file mutt_attach.c.

340{
342 ASSERT(md);
343
344 struct ListNode *np = NULL;
345 STAILQ_FOREACH(np, &md->mime_lookup, entries)
346 {
347 const int i = (int) mutt_str_len(np->data) - 1;
348 if (((i > 0) && (np->data[i - 1] == '/') && (np->data[i] == '*') &&
349 mutt_istrn_equal(type, np->data, i)) ||
350 mutt_istr_equal(type, np->data))
351 {
352 struct Body tmp = { 0 };
353 enum ContentType n;
354 if ((n = mutt_lookup_mime_type(&tmp, b->filename)) != TYPE_OTHER ||
356 {
357 snprintf(type, len, "%s/%s",
358 (n == TYPE_AUDIO) ? "audio" :
359 (n == TYPE_APPLICATION) ? "application" :
360 (n == TYPE_IMAGE) ? "image" :
361 (n == TYPE_MESSAGE) ? "message" :
362 (n == TYPE_MODEL) ? "model" :
363 (n == TYPE_MULTIPART) ? "multipart" :
364 (n == TYPE_TEXT) ? "text" :
365 (n == TYPE_VIDEO) ? "video" :
366 "other",
367 tmp.subtype);
368 mutt_debug(LL_DEBUG1, "\"%s\" -> %s\n", b->filename, type);
369 }
370 FREE(&tmp.subtype);
371 FREE(&tmp.xtype);
372 }
373 }
374}
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
@ MODULE_ID_ATTACH
ModuleAttach, Attachments
Definition module_api.h:49
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:674
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:500
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:457
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:585
#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:75
#define ASSERT(COND)
Definition signal2.h:59
Attach private Module data.
Definition module_data.h:32
struct ListHead mime_lookup
List of mime types that that shouldn't use the mailcap entry.
Definition module_data.h:39
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 116 of file mutt_attach.c.

117{
118 char type[256] = { 0 };
119 struct MailcapEntry *entry = mailcap_entry_new();
120 bool unlink_newfile = false;
121 int rc = 0;
122 struct Buffer *cmd = buf_pool_get();
123 struct Buffer *newfile = buf_pool_get();
124 struct Buffer *tempfile = buf_pool_get();
125
126 snprintf(type, sizeof(type), "%s/%s", BODY_TYPE(b), b->subtype);
127 if (mailcap_lookup(b, type, sizeof(type), entry, MUTT_MC_COMPOSE))
128 {
129 if (entry->composecommand || entry->composetypecommand)
130 {
131 if (entry->composetypecommand)
132 buf_strcpy(cmd, entry->composetypecommand);
133 else
134 buf_strcpy(cmd, entry->composecommand);
135
136 mailcap_expand_filename(entry->nametemplate, b->filename, newfile);
137 mutt_debug(LL_DEBUG1, "oldfile: %s newfile: %s\n", b->filename,
138 buf_string(newfile));
139 if (mutt_file_symlink(b->filename, buf_string(newfile)) == -1)
140 {
141 if (query_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
142 goto bailout;
143 buf_strcpy(newfile, b->filename);
144 }
145 else
146 {
147 unlink_newfile = true;
148 }
149
150 if (mailcap_expand_command(b, buf_string(newfile), type, cmd))
151 {
152 /* For now, editing requires a file, no piping */
153 mutt_error(_("Mailcap compose entry requires %%s"));
154 }
155 else
156 {
157 int r;
158
159 mutt_endwin();
160 r = mutt_system(buf_string(cmd));
161 if (r == -1)
162 mutt_error(_("Error running \"%s\""), buf_string(cmd));
163
164 if ((r != -1) && entry->composetypecommand)
165 {
166 FILE *fp = mutt_file_fopen(b->filename, "r");
167 if (!fp)
168 {
169 mutt_perror(_("Failure to open file to parse headers"));
170 goto bailout;
171 }
172
173 struct Body *b_mime = mutt_read_mime_header(fp, 0);
174 if (b_mime)
175 {
176 if (!TAILQ_EMPTY(&b_mime->parameter))
177 {
179 b->parameter = b_mime->parameter;
180 TAILQ_INIT(&b_mime->parameter);
181 }
182 if (b_mime->description)
183 {
184 FREE(&b->description);
185 b->description = b_mime->description;
186 b_mime->description = NULL;
187 }
188 if (b_mime->form_name)
189 {
190 FREE(&b->form_name);
191 b->form_name = b_mime->form_name;
192 b_mime->form_name = NULL;
193 }
194
195 /* Remove headers by copying out data to another file, then
196 * copying the file back */
197 const LOFF_T offset = b_mime->offset;
198 mutt_body_free(&b_mime);
199 if (!mutt_file_seek(fp, offset, SEEK_SET))
200 {
201 goto bailout;
202 }
203
204 buf_mktemp(tempfile);
205 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w");
206 if (!fp_tmp)
207 {
208 mutt_perror(_("Failure to open file to strip headers"));
209 mutt_file_fclose(&fp);
210 goto bailout;
211 }
212 mutt_file_copy_stream(fp, fp_tmp);
213 mutt_file_fclose(&fp);
214 mutt_file_fclose(&fp_tmp);
216 if (mutt_file_rename(buf_string(tempfile), b->filename) != 0)
217 {
218 mutt_perror(_("Failure to rename file"));
219 goto bailout;
220 }
221 }
222 }
223 }
224 }
225 }
226 else
227 {
228 mutt_message(_("No mailcap compose entry for %s, creating empty file"), type);
229 rc = 1;
230 goto bailout;
231 }
232
233 rc = 1;
234
235bailout:
236
237 if (unlink_newfile)
238 unlink(buf_string(newfile));
239
240 buf_pool_release(&cmd);
241 buf_pool_release(&newfile);
242 buf_pool_release(&tempfile);
243
244 mailcap_entry_free(&entry);
245 return rc;
246}
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:1370
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition file.c:222
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:652
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition file.c:1261
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition file.c:250
@ 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:326
#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
Compose command.
Definition mailcap.h:40
char * composetypecommand
Compose type command.
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 1038 of file mutt_attach.c.

1040{
1041 struct State state = { 0 };
1042 unsigned int saved_encoding = 0;
1043 struct Body *saved_parts = NULL;
1044 struct Email *e_saved = NULL;
1045 int rc = 0;
1046
1047 state.flags = flags;
1048
1049 if (opt == MUTT_SAVE_APPEND)
1050 state.fp_out = mutt_file_fopen_masked(path, "a");
1051 else
1052 state.fp_out = mutt_file_fopen_masked(path, "w");
1053
1054 if (!state.fp_out)
1055 {
1056 mutt_perror("fopen");
1057 return -1;
1058 }
1059
1060 if (fp)
1061 {
1062 state.fp_in = fp;
1063 state.flags |= STATE_CHARCONV;
1064 }
1065 else
1066 {
1067 /* When called from the compose menu, the attachment isn't parsed,
1068 * so we need to do it here. */
1069 state.fp_in = mutt_file_fopen(b->filename, "r");
1070 if (!state.fp_in)
1071 {
1072 mutt_perror("fopen");
1073 mutt_file_fclose(&state.fp_out);
1074 return -1;
1075 }
1076
1077 struct stat st = { 0 };
1078 if (fstat(fileno(state.fp_in), &st) == -1)
1079 {
1080 mutt_perror("stat");
1081 mutt_file_fclose(&state.fp_in);
1082 mutt_file_fclose(&state.fp_out);
1083 return -1;
1084 }
1085
1086 saved_encoding = b->encoding;
1087 if (!is_multipart(b))
1088 b->encoding = ENC_8BIT;
1089
1090 b->length = st.st_size;
1091 b->offset = 0;
1092 saved_parts = b->parts;
1093 e_saved = b->email;
1094 mutt_parse_part(state.fp_in, b);
1095
1096 if (b->noconv || is_multipart(b))
1097 state.flags |= STATE_CHARCONV;
1098 }
1099
1100 mutt_body_handler(b, &state);
1101
1102 if (mutt_file_fsync_close(&state.fp_out) != 0)
1103 {
1104 mutt_perror("fclose");
1105 rc = -1;
1106 }
1107 if (!fp)
1108 {
1109 b->length = 0;
1110 b->encoding = saved_encoding;
1111 if (saved_parts)
1112 {
1113 email_free(&b->email);
1114 b->parts = saved_parts;
1115 b->email = e_saved;
1116 }
1117 mutt_file_fclose(&state.fp_in);
1118 }
1119
1120 return rc;
1121}
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:1833
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition file.c:128
int mutt_body_handler(struct Body *b, struct State *state)
Handler for the Body of an email.
Definition handler.c:1659
@ ENC_8BIT
8-bit text
Definition mime.h:50
#define is_multipart(body)
Check if a body part is multipart or a message container.
Definition mime.h:85
#define mutt_file_fopen_masked(PATH, MODE)
Open a file with proper permissions, tracked for debugging.
Definition neomutt.h:90
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 261 of file mutt_attach.c.

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

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

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

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

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

1297{
1299 ASSERT(md);
1300
1302}
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition list.c:65
struct ListHead temp_attachments
List of temporary files for displaying attachments.
Definition module_data.h:40
+ 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 1307 of file mutt_attach.c.

1308{
1310 ASSERT(md);
1311
1312 struct ListNode *np = NULL;
1313
1314 STAILQ_FOREACH(np, &md->temp_attachments, entries)
1315 {
1316 (void) mutt_file_chmod_add(np->data, S_IWUSR);
1318 }
1319
1321}
int mutt_file_chmod_add(const char *path, mode_t mode)
Add permissions to a file.
Definition file.c:1006
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: