NeoMutt  2025-12-11-980-ge38c27
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_NONE = 0 , MUTT_SAVE_APPEND = 1U << 0 }
 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 AttachPtrArray *aa, struct Email *e, struct Menu *menu)
 Save a list of selected attachments.
 
void mutt_pipe_attachment_list (struct AttachPtrArray *aa, bool filter)
 Pipe selected attachments to a command.
 
void mutt_print_attachment_list (struct AttachPtrArray *aa)
 Print selected 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 (struct ListHead *list)
 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 43 of file mutt_attach.h.

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

◆ 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_NONE 

Overwrite existing file (the default)

MUTT_SAVE_APPEND 

Append to existing file.

Definition at line 57 of file mutt_attach.h.

58{
59 MUTT_SAVE_NONE = 0,
60 MUTT_SAVE_APPEND = 1U << 0,
61};
@ MUTT_SAVE_APPEND
Append to existing file.
Definition mutt_attach.h:60
@ MUTT_SAVE_NONE
Overwrite existing file (the default)
Definition mutt_attach.h:59

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

Definition at line 919 of file recvattach.c.

921{
922 do
923 {
924 switch (op)
925 {
926 case OP_DISPLAY_HEADERS:
927 bool_str_toggle(NeoMutt->sub, "weed", NULL);
929
930 case OP_ATTACH_VIEW:
931 {
932 struct AttachPtr *cur_att = current_attachment(actx, menu);
933 if (!cur_att->fp)
934 {
935 if (cur_att->body->type == TYPE_MULTIPART)
936 {
937 struct Body *b = cur_att->body->parts;
938 while (b && b->parts)
939 b = b->parts;
940 if (b)
941 cur_att = b->aptr;
942 }
943 }
944 op = mutt_view_attachment(cur_att->fp, cur_att->body, MUTT_VA_REGULAR,
945 e, actx, menu->win);
946 break;
947 }
948
949 case OP_NEXT_ENTRY:
950 case OP_MAIN_NEXT_UNDELETED: /* hack */
951 {
952 const int index = menu_get_index(menu) + 1;
953 if (index < menu->max)
954 {
955 menu_set_index(menu, index);
956 op = OP_ATTACH_VIEW;
957 }
958 else
959 {
960 op = OP_NULL;
961 }
962 break;
963 }
964
965 case OP_PREV_ENTRY:
966 case OP_MAIN_PREV_UNDELETED: /* hack */
967 {
968 const int index = menu_get_index(menu) - 1;
969 if (index >= 0)
970 {
971 menu_set_index(menu, index);
972 op = OP_ATTACH_VIEW;
973 }
974 else
975 {
976 op = OP_NULL;
977 }
978 break;
979 }
980
981 case OP_ATTACH_EDIT_TYPE:
982 {
983 struct AttachPtr *cur_att = current_attachment(actx, menu);
984 /* when we edit the content-type, we should redisplay the attachment
985 * immediately */
986 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
987 if (recv)
988 recvattach_edit_content_type(actx, menu, e);
989 else
990 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
991
993 op = OP_ATTACH_VIEW;
994 break;
995 }
996 /* functions which are passed through from the pager */
997 case OP_PIPE:
998 {
999 struct AttachPtr *cur_att = current_attachment(actx, menu);
1000 struct AttachPtrArray aa = ARRAY_HEAD_INITIALIZER;
1001 ARRAY_ADD(&aa, cur_att);
1002 mutt_pipe_attachment_list(&aa, false);
1003 ARRAY_FREE(&aa);
1004 op = OP_ATTACH_VIEW;
1005 break;
1006 }
1007 case OP_ATTACH_PRINT:
1008 {
1009 struct AttachPtr *cur_att = current_attachment(actx, menu);
1010 struct AttachPtrArray aa = ARRAY_HEAD_INITIALIZER;
1011 ARRAY_ADD(&aa, cur_att);
1013 ARRAY_FREE(&aa);
1014 op = OP_ATTACH_VIEW;
1015 break;
1016 }
1017 case OP_ATTACH_SAVE:
1018 {
1019 struct AttachPtr *cur_att = current_attachment(actx, menu);
1020 struct AttachPtrArray aa = ARRAY_HEAD_INITIALIZER;
1021 ARRAY_ADD(&aa, cur_att);
1022 mutt_save_attachment_list(&aa, e, NULL);
1023 ARRAY_FREE(&aa);
1024 op = OP_ATTACH_VIEW;
1025 break;
1026 }
1027 case OP_CHECK_TRADITIONAL:
1029 {
1030 op = OP_NULL;
1031 break;
1032 }
1034
1035 case OP_ATTACH_COLLAPSE:
1036 if (recv)
1037 return op;
1039
1040 default:
1041 op = OP_NULL;
1042 }
1043 } while (op != OP_NULL);
1044
1045 return op;
1046}
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:157
#define ARRAY_FREE(head)
Release all memory.
Definition array.h:209
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition array.h:58
int bool_str_toggle(struct ConfigSubset *sub, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition bool.c:231
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition external.c:1073
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition menu.c:177
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition menu.c:153
@ MENU_REDRAW_INDEX
Redraw the index.
Definition lib.h:61
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition menu.c:167
@ 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:108
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:106
#define WithCrypto
Definition lib.h:132
void mutt_save_attachment_list(struct AttachPtrArray *aa, struct Email *e, struct Menu *menu)
Save a list of selected attachments.
Definition recvattach.c:425
void mutt_pipe_attachment_list(struct AttachPtrArray *aa, bool filter)
Pipe selected attachments to a command.
Definition recvattach.c:699
struct AttachPtr * current_attachment(struct AttachCtx *actx, struct Menu *menu)
Get the current attachment.
Definition recvattach.c:71
void mutt_print_attachment_list(struct AttachPtrArray *aa)
Print selected attachments.
Definition recvattach.c:848
void recvattach_edit_content_type(struct AttachCtx *actx, struct Menu *menu, struct Email *e)
Edit the content type of an attachment.
Definition recvattach.c:889
An email to which things will be attached.
Definition attach.h:36
struct Body * body
Attachment.
Definition attach.h:37
FILE * fp
Used in the recvattach menu.
Definition attach.h:38
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:94
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 AttachPtrArray * aa,
struct Email * e,
struct Menu * menu )

Save a list of selected attachments.

Parameters
aaSelected attachments
eParent email
menuMenu listing attachments

Definition at line 425 of file recvattach.c.

426{
427 char *directory = NULL;
428 int rc = 1;
429 int last = menu ? menu_get_index(menu) : 0;
430 FILE *fp_out = NULL;
431 int saved_attachments = 0;
432
433 struct Buffer *buf = buf_pool_get();
434 struct Buffer *tfile = buf_pool_get();
435
436 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
437 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
438 const bool c_attach_save_without_prompting = cs_subset_bool(NeoMutt->sub, "attach_save_without_prompting");
439
440 struct AttachPtr **app = NULL;
441 ARRAY_FOREACH(app, aa)
442 {
443 FILE *fp = (*app)->fp;
444 struct Body *b = (*app)->body;
445
446 /* Iterate through attachments.
447 * Behavior depends on attach_split: if true, save each to its own file;
448 * if false, concatenate all into one file with optional separator. */
449 if (c_attach_split)
450 {
451 if (menu)
452 {
453 menu_set_index(menu, (*app)->num);
455 menu_redraw(menu);
456 }
457 if (c_attach_save_without_prompting)
458 {
459 // Save each file, with no prompting, using the configured 'AttachSaveDir'
460 rc = save_without_prompting(fp, b, e);
461 if (rc == 0)
462 saved_attachments++;
463 }
464 else
465 {
466 // Save each file, prompting the user for the location each time.
467 if (query_save_attachment(fp, b, e, &directory) == -1)
468 break;
469 }
470 }
471 else
472 {
473 enum SaveAttach opt = MUTT_SAVE_NONE;
474
475 if (buf_is_empty(buf))
476 {
478 prepend_savedir(buf);
479
480 struct FileCompletionData cdata = { false, NULL, NULL, NULL, NULL };
481 if ((mw_get_field(_("Save to file: "), buf, MUTT_COMP_CLEAR, HC_FILE,
482 &CompleteFileOps, &cdata) != 0) ||
483 buf_is_empty(buf))
484 {
485 goto cleanup;
486 }
487 expand_path(buf, false);
488 if (mutt_check_overwrite(b->filename, buf_string(buf), tfile, &opt, NULL))
489 goto cleanup;
490 }
491 else
492 {
493 opt = MUTT_SAVE_APPEND;
494 }
495
496 rc = save_attachment_flowed_helper(fp, b, buf_string(tfile), opt, e);
497 if ((rc == 0) && c_attach_sep && (fp_out = mutt_file_fopen(buf_string(tfile), "a")))
498 {
499 fprintf(fp_out, "%s", c_attach_sep);
500 mutt_file_fclose(&fp_out);
501 }
502 }
503 }
504
505 FREE(&directory);
506
507 if ((ARRAY_SIZE(aa) > 1) && menu)
508 {
509 menu_set_index(menu, last);
511 }
512
513 if (rc == 0)
514 {
515 if (!c_attach_split)
516 saved_attachments = 1;
517
518 if (!c_attach_split || c_attach_save_without_prompting)
519 {
520 mutt_message(ngettext("Attachment saved", "%d attachments saved", saved_attachments),
521 saved_attachments);
522 }
523 }
524
525cleanup:
526 buf_pool_release(&buf);
527 buf_pool_release(&tfile);
528}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
#define ARRAY_SIZE(head)
The number of elements stored.
Definition array.h:87
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:298
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:401
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:486
@ MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition wdata.h:47
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
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:502
#define mutt_message(...)
Definition logging2.h:93
@ HC_FILE
Files.
Definition lib.h:59
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
@ MENU_REDRAW_MOTION
Redraw after moving the menu list.
Definition lib.h:62
#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:58
void expand_path(struct Buffer *buf, bool regex)
Create the canonical path.
Definition muttlib.c:122
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:524
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:228
static int save_without_prompting(FILE *fp, struct Body *b, struct Email *e)
Save the attachment, without prompting each time.
Definition recvattach.c:378
static void prepend_savedir(struct Buffer *buf)
Add $attach_save_dir to the beginning of a path.
Definition recvattach.c:169
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:274
#define NONULL(x)
Definition string2.h:44
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 AttachPtrArray * aa,
bool filter )

Pipe selected attachments to a command.

Parameters
aaSelected attachments
filterIs this command a filter?

Definition at line 699 of file recvattach.c.

700{
701 struct State state = { 0 };
702 struct Buffer *buf = NULL;
703
704 if (ARRAY_EMPTY(aa))
705 return;
706
707 struct AttachPtr **first = ARRAY_GET(aa, 0);
708 if (first && (*first)->fp)
709 filter = false; /* sanity check: we can't filter in the recv case yet */
710
711 buf = buf_pool_get();
712 /* perform charset conversion on text attachments when piping */
713 state.flags = STATE_CHARCONV;
714
715 if (mw_get_field((filter ? _("Filter through: ") : _("Pipe to: ")), buf,
717 {
718 goto cleanup;
719 }
720
721 if (buf_is_empty(buf))
722 goto cleanup;
723
724 expand_path(buf, false);
725
726 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
727 if (!filter && !c_attach_split)
728 {
729 mutt_endwin();
730 pid_t pid = filter_create(buf_string(buf), &state.fp_out, NULL, NULL,
731 NeoMutt->env);
732 pipe_attachment_list(buf_string(buf), aa, filter, &state);
733 mutt_file_fclose(&state.fp_out);
734 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
735 if ((filter_wait(pid) != 0) || c_wait_key)
737 }
738 else
739 {
740 pipe_attachment_list(buf_string(buf), aa, filter, &state);
741 }
742
743cleanup:
744 buf_pool_release(&buf);
745}
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition array.h:74
#define ARRAY_GET(head, idx)
Return the element at index.
Definition array.h:109
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition curs_lib.c:174
void mutt_endwin(void)
Shutdown curses.
Definition curs_lib.c:152
@ MUTT_COMP_NONE
No flags are set.
Definition wdata.h:46
@ HC_EXT_COMMAND
External commands.
Definition lib.h:56
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition filter.c:231
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:220
@ STATE_CHARCONV
Do character set conversions.
Definition state.h:41
static void pipe_attachment_list(const char *command, struct AttachPtrArray *aa, bool filter, struct State *state)
Pipe a list of attachments to a command.
Definition recvattach.c:677
char ** env
Private copy of the environment variables.
Definition neomutt.h:57
Keep track when processing files.
Definition state.h:54
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition state.h:58
FILE * fp_out
File to write to.
Definition state.h:56
+ 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 AttachPtrArray * aa)

Print selected attachments.

Parameters
aaSelected attachments

Definition at line 848 of file recvattach.c.

849{
850 char prompt[128] = { 0 };
851 struct State state = { 0 };
852 const int count = ARRAY_SIZE(aa);
853
854 if (count == 0)
855 return;
856
857 snprintf(prompt, sizeof(prompt),
858 ngettext("Print attachment?", "Print %d attachments?", count), count);
859 if (query_quadoption(prompt, NeoMutt->sub, "print") != MUTT_YES)
860 return;
861
862 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
863 if (c_attach_split)
864 {
865 print_attachment_list(aa, &state);
866 }
867 else
868 {
869 if (!can_print(aa))
870 return;
871 mutt_endwin();
872 const char *const c_print_command = cs_subset_string(NeoMutt->sub, "print_command");
873 pid_t pid = filter_create(NONULL(c_print_command), &state.fp_out, NULL,
874 NULL, NeoMutt->env);
875 print_attachment_list(aa, &state);
876 mutt_file_fclose(&state.fp_out);
877 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
878 if ((filter_wait(pid) != 0) || c_wait_key)
880 }
881}
@ 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:384
static void print_attachment_list(struct AttachPtrArray *aa, struct State *state)
Print a list of Attachments.
Definition recvattach.c:784
static bool can_print(struct AttachPtrArray *aa)
Do we know how to print this attachment type?
Definition recvattach.c:752
+ 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", BODY_TYPE(b), b->subtype);
448
449 char columns[16] = { 0 };
450 snprintf(columns, sizeof(columns), "%d", win->state.cols);
451 envlist_set(&NeoMutt->env, "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_NONE;
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;
539 int fd_pager = -1;
540
541 if (!use_pager)
542 mutt_endwin();
543
544 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
545 if (use_pager || use_pipe)
546 {
547 if (use_pager &&
548 ((fd_pager = mutt_file_open(buf_string(pagerfile),
549 O_CREAT | O_EXCL | O_WRONLY, 0600)) == -1))
550 {
551 mutt_perror("open");
552 goto return_error;
553 }
554 unlink_pagerfile = true;
555
556 if (use_pipe && ((fd_temp = open(buf_string(tempfile), 0)) == -1))
557 {
558 if (fd_pager != -1)
559 close(fd_pager);
560 mutt_perror("open");
561 goto return_error;
562 }
563 unlink_pagerfile = true;
564
565 pid = filter_create_fd(buf_string(cmd), NULL, NULL, NULL, use_pipe ? fd_temp : -1,
566 use_pager ? fd_pager : -1, -1, NeoMutt->env);
567
568 if (pid == -1)
569 {
570 if (fd_pager != -1)
571 close(fd_pager);
572
573 if (fd_temp != -1)
574 close(fd_temp);
575
576 mutt_error(_("Can't create filter"));
577 goto return_error;
578 }
579
580 if (use_pager)
581 {
582 if (b->description)
583 {
584 snprintf(desc, sizeof(desc), _("---Command: %-20.20s Description: %s"),
585 buf_string(cmd), b->description);
586 }
587 else
588 {
589 snprintf(desc, sizeof(desc), _("---Command: %-30.30s Attachment: %s"),
590 buf_string(cmd), type);
591 }
592 filter_wait(pid);
593 }
594 else
595 {
596 if (wait_interactive_filter(pid) || (entry->needsterminal && c_wait_key))
598 }
599
600 if (fd_temp != -1)
601 close(fd_temp);
602 if (fd_pager != -1)
603 close(fd_pager);
604 }
605 else
606 {
607 /* interactive cmd */
608 int rv = mutt_system(buf_string(cmd));
609 if (rv == -1)
610 mutt_debug(LL_DEBUG1, "Error running \"%s\"\n", cmd->data);
611
612 if ((rv != 0) || (entry->needsterminal && c_wait_key))
614 }
615 }
616 else
617 {
618 /* Don't use mailcap; the attachment is viewed in the pager */
619
620 if (mode == MUTT_VA_AS_TEXT)
621 {
622 /* just let me see the raw data */
623 if (fp)
624 {
625 /* Viewing from a received message.
626 *
627 * Don't use mutt_save_attachment() because we want to perform charset
628 * conversion since this will be displayed by the internal pager. */
629 struct State state = { 0 };
630
631 state.fp_out = mutt_file_fopen(buf_string(pagerfile), "w");
632 if (!state.fp_out)
633 {
634 mutt_debug(LL_DEBUG1, "mutt_file_fopen(%s) errno=%d %s\n",
635 buf_string(pagerfile), errno, strerror(errno));
636 mutt_perror("%s", buf_string(pagerfile));
637 goto return_error;
638 }
639 state.fp_in = fp;
640 state.flags = STATE_CHARCONV;
641 mutt_decode_attachment(b, &state);
642 mutt_file_fclose(&state.fp_out);
643 }
644 else
645 {
646 /* in compose mode, just copy the file. we can't use
647 * mutt_decode_attachment() since it assumes the content-encoding has
648 * already been applied */
649 if (mutt_save_attachment(fp, b, buf_string(pagerfile), MUTT_SAVE_NONE, NULL))
650 goto return_error;
651 unlink_pagerfile = true;
652 }
654 }
655 else
656 {
658 const char *const c_pager = pager_get_pager(NeoMutt->sub);
659 if (!c_pager)
661
662 /* Use built-in handler */
664 {
665 goto return_error;
666 }
667 unlink_pagerfile = true;
668 }
669
670 if (b->description)
671 mutt_str_copy(desc, b->description, sizeof(desc));
672 else if (b->filename)
673 snprintf(desc, sizeof(desc), _("---Attachment: %s: %s"), b->filename, type);
674 else
675 snprintf(desc, sizeof(desc), _("---Attachment: %s"), type);
676 }
677
678 /* We only reach this point if there have been no errors */
679
680 if (use_pager)
681 {
682 struct PagerData pdata = { 0 };
683 struct PagerView pview = { &pdata };
684
685 pdata.actx = actx;
686 pdata.body = b;
687 pdata.fname = buf_string(pagerfile);
688 pdata.fp = fp;
689
690 pview.banner = desc;
692 (is_message ? MUTT_PAGER_MESSAGE : MUTT_PAGER_NONE) |
693 ((use_mailcap && entry->xneomuttnowrap) ? MUTT_PAGER_NOWRAP : MUTT_PAGER_NONE);
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 list of files 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(&NeoMutt->env, "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:89
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:1620
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:140
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition file.c:582
int mutt_file_open(const char *path, uint32_t flags, mode_t mode)
Open a file.
Definition file.c:516
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:1943
@ 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:568
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_NONE
No flags set.
Definition mailcap.h:57
@ MUTT_MC_AUTOVIEW
Mailcap autoview field.
Definition mailcap.h:61
#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
uint16_t StateFlags
Definition state.h:48
@ STATE_PAGER
Output will be displayed in the Pager.
Definition state.h:46
@ STATE_DISPLAY_ATTACH
We are displaying an attachment.
Definition state.h:45
@ STATE_DISPLAY
Output is displayed to the user.
Definition state.h:37
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:666
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:587
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:368
#define mutt_adv_mktemp(buf)
Definition muttlib.h:39
@ SEC_ENCRYPT
Email is encrypted.
Definition lib.h:92
const char * pager_get_pager(struct ConfigSubset *sub)
Get the value of $pager.
Definition config.c:111
#define MUTT_PAGER_NOWRAP
Format for term width, ignore $wrap.
Definition lib.h:74
#define MUTT_PAGER_NONE
No flags are set.
Definition lib.h:63
@ 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:140
#define MUTT_PAGER_MESSAGE
Definition lib.h:78
#define MUTT_PAGER_ATTACHMENT
Attachments may exist.
Definition lib.h:73
#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:524
struct Body ** body_idx
Extra struct Body* used for decryption.
Definition attach.h:80
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:162
const char * fname
Name of the file to read.
Definition lib.h:166
FILE * fp
Source stream.
Definition lib.h:164
struct Body * body
Current attachment.
Definition lib.h:163
struct AttachCtx * actx
Attachment information.
Definition lib.h:165
Paged view into some data.
Definition lib.h:173
struct PagerData * pdata
Data that pager displays. NOTNULL.
Definition lib.h:174
enum PagerMode mode
Pager mode.
Definition lib.h:175
PagerFlags flags
Additional settings to tweak pager's function.
Definition lib.h:176
const char * banner
Title to display in status bar.
Definition lib.h:177
FILE * fp_in
File to read from.
Definition state.h:55
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 340 of file mutt_attach.c.

341{
343 ASSERT(mod_data);
344
345 struct ListNode *np = NULL;
346 STAILQ_FOREACH(np, &mod_data->mime_lookup, 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}
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:678
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
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:666
#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:42
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 117 of file mutt_attach.c.

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

1043{
1044 struct State state = { 0 };
1045 unsigned int saved_encoding = 0;
1046 struct Body *saved_parts = NULL;
1047 struct Email *e_saved = NULL;
1048 int rc = 0;
1049
1050 state.flags = flags;
1051
1052 if (opt == MUTT_SAVE_APPEND)
1053 state.fp_out = mutt_file_fopen_masked(path, "a");
1054 else
1055 state.fp_out = mutt_file_fopen_masked(path, "w");
1056
1057 if (!state.fp_out)
1058 {
1059 mutt_perror("fopen");
1060 return -1;
1061 }
1062
1063 if (fp)
1064 {
1065 state.fp_in = fp;
1066 state.flags |= STATE_CHARCONV;
1067 }
1068 else
1069 {
1070 /* When called from the compose menu, the attachment isn't parsed,
1071 * so we need to do it here. */
1072 state.fp_in = mutt_file_fopen(b->filename, "r");
1073 if (!state.fp_in)
1074 {
1075 mutt_perror("fopen");
1076 mutt_file_fclose(&state.fp_out);
1077 return -1;
1078 }
1079
1080 struct stat st = { 0 };
1081 if (fstat(fileno(state.fp_in), &st) == -1)
1082 {
1083 mutt_perror("stat");
1084 mutt_file_fclose(&state.fp_in);
1085 mutt_file_fclose(&state.fp_out);
1086 return -1;
1087 }
1088
1089 saved_encoding = b->encoding;
1090 if (!is_multipart(b))
1091 b->encoding = ENC_8BIT;
1092
1093 b->length = st.st_size;
1094 b->offset = 0;
1095 saved_parts = b->parts;
1096 e_saved = b->email;
1097 mutt_parse_part(state.fp_in, b);
1098
1099 if (b->noconv || is_multipart(b))
1100 state.flags |= STATE_CHARCONV;
1101 }
1102
1103 mutt_body_handler(b, &state);
1104
1105 if (mutt_file_fsync_close(&state.fp_out) != 0)
1106 {
1107 mutt_perror("fclose");
1108 rc = -1;
1109 }
1110 if (!fp)
1111 {
1112 b->length = 0;
1113 b->encoding = saved_encoding;
1114 if (saved_parts)
1115 {
1116 email_free(&b->email);
1117 b->parts = saved_parts;
1118 b->email = e_saved;
1119 }
1120 mutt_file_fclose(&state.fp_in);
1121 }
1122
1123 return rc;
1124}
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:1949
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:1668
@ 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:92
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 262 of file mutt_attach.c.

263{
264 char type[256] = { 0 };
265 struct MailcapEntry *entry = mailcap_entry_new();
266 bool unlink_newfile = false;
267 bool rc = false;
268 struct Buffer *cmd = buf_pool_get();
269 struct Buffer *newfile = buf_pool_get();
270
271 snprintf(type, sizeof(type), "%s/%s", BODY_TYPE(b), b->subtype);
272 if (mailcap_lookup(b, type, sizeof(type), entry, MUTT_MC_EDIT))
273 {
274 if (entry->editcommand)
275 {
276 buf_strcpy(cmd, entry->editcommand);
277 mailcap_expand_filename(entry->nametemplate, b->filename, newfile);
278 mutt_debug(LL_DEBUG1, "oldfile: %s newfile: %s\n", b->filename,
279 buf_string(newfile));
280 if (mutt_file_symlink(b->filename, buf_string(newfile)) == -1)
281 {
282 if (query_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
283 goto bailout;
284 buf_strcpy(newfile, b->filename);
285 }
286 else
287 {
288 unlink_newfile = true;
289 }
290
291 if (mailcap_expand_command(b, buf_string(newfile), type, cmd))
292 {
293 /* For now, editing requires a file, no piping */
294 mutt_error(_("Mailcap Edit entry requires %%s"));
295 goto bailout;
296 }
297 else
298 {
299 mutt_endwin();
300 if (mutt_system(buf_string(cmd)) == -1)
301 {
302 mutt_error(_("Error running \"%s\""), buf_string(cmd));
303 goto bailout;
304 }
305 }
306 }
307 }
308 else if (b->type == TYPE_TEXT)
309 {
310 /* On text, default to editor */
311 const char *const c_editor = cs_subset_string(NeoMutt->sub, "editor");
312 mutt_edit_file(NONULL(c_editor), b->filename);
313 }
314 else
315 {
316 mutt_error(_("No mailcap edit entry for %s"), type);
317 goto bailout;
318 }
319
320 rc = true;
321
322bailout:
323
324 if (unlink_newfile)
325 unlink(buf_string(newfile));
326
327 buf_pool_release(&cmd);
328 buf_pool_release(&newfile);
329
330 mailcap_entry_free(&entry);
331 return rc;
332}
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition curs_lib.c:117
@ 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_NONE);
79 mailcap_expand_filename(entry->nametemplate, b->filename, tempfile);
80
81 mailcap_entry_free(&entry);
82
83 FILE *fp_in = NULL;
84 FILE *fp_out = NULL;
85 if ((fp_in = mutt_file_fopen(b->filename, "r")) &&
86 (fp_out = mutt_file_fopen(buf_string(tempfile), "w")))
87 {
88 mutt_file_copy_stream(fp_in, fp_out);
89 mutt_str_replace(&b->filename, buf_string(tempfile));
90 b->unlink = true;
91
92 struct stat st = { 0 };
93 if ((fstat(fileno(fp_in), &st) == 0) && (b->stamp >= st.st_mtime))
94 {
96 }
97 }
98 else
99 {
100 mutt_perror("%s", fp_in ? buf_string(tempfile) : b->filename);
101 }
102
103 mutt_file_fclose(&fp_in);
104 mutt_file_fclose(&fp_out);
105
106 buf_pool_release(&tempfile);
107
108 return b->unlink ? 0 : -1;
109}
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:412
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;
743 int rc = 0;
744 bool is_flowed = false;
745 bool unlink_unstuff = false;
746 FILE *fp_filter = NULL;
747 FILE *fp_unstuff = NULL;
748 FILE *fp_in = NULL;
749 struct Buffer *unstuff_tempfile = NULL;
750
751 if (outfile && *outfile)
752 {
753 out = mutt_file_open(outfile, O_CREAT | O_EXCL | O_WRONLY, 0600);
754 if (out < 0)
755 {
756 mutt_perror("open");
757 return 0;
758 }
759 }
760
762 {
763 is_flowed = true;
764 unstuff_tempfile = buf_pool_get();
765 buf_mktemp(unstuff_tempfile);
766 }
767
768 mutt_endwin();
769
770 if (outfile && *outfile)
771 pid = filter_create_fd(path, &fp_filter, NULL, NULL, -1, out, -1, NeoMutt->env);
772 else
773 pid = filter_create(path, &fp_filter, NULL, NULL, NeoMutt->env);
774 if (pid < 0)
775 {
776 mutt_perror(_("Can't create filter"));
777 goto bail;
778 }
779
780 /* recv case */
781 if (fp)
782 {
783 struct State state = { 0 };
784
785 /* perform charset conversion on text attachments when piping */
786 state.flags = STATE_CHARCONV;
787
788 if (is_flowed)
789 {
790 fp_unstuff = mutt_file_fopen(buf_string(unstuff_tempfile), "w");
791 if (!fp_unstuff)
792 {
793 mutt_perror("mutt_file_fopen");
794 goto bail;
795 }
796 unlink_unstuff = true;
797
798 state.fp_in = fp;
799 state.fp_out = fp_unstuff;
800 mutt_decode_attachment(b, &state);
801 mutt_file_fclose(&fp_unstuff);
802
804
805 fp_unstuff = mutt_file_fopen(buf_string(unstuff_tempfile), "r");
806 if (!fp_unstuff)
807 {
808 mutt_perror("mutt_file_fopen");
809 goto bail;
810 }
811 mutt_file_copy_stream(fp_unstuff, fp_filter);
812 mutt_file_fclose(&fp_unstuff);
813 }
814 else
815 {
816 state.fp_in = fp;
817 state.fp_out = fp_filter;
818 mutt_decode_attachment(b, &state);
819 }
820 }
821 else
822 {
823 /* send case */
824 const char *infile = NULL;
825
826 if (is_flowed)
827 {
828 if (mutt_save_attachment(fp, b, buf_string(unstuff_tempfile),
829 MUTT_SAVE_NONE, NULL) == -1)
830 {
831 goto bail;
832 }
833 unlink_unstuff = true;
835 infile = buf_string(unstuff_tempfile);
836 }
837 else
838 {
839 infile = b->filename;
840 }
841
842 fp_in = mutt_file_fopen(infile, "r");
843 if (!fp_in)
844 {
845 mutt_perror("fopen");
846 goto bail;
847 }
848
849 mutt_file_copy_stream(fp_in, fp_filter);
851 }
852
853 mutt_file_fclose(&fp_filter);
854 rc = 1;
855
856bail:
857 if (outfile && *outfile)
858 {
859 close(out);
860 if (rc == 0)
861 unlink(outfile);
862 else if (is_flowed)
864 }
865
866 mutt_file_fclose(&fp_unstuff);
867 mutt_file_fclose(&fp_filter);
869
870 if (unlink_unstuff)
871 mutt_file_unlink(buf_string(unstuff_tempfile));
872 buf_pool_release(&unstuff_tempfile);
873
874 /* check for error exit from child process */
875 if ((pid > 0) && (filter_wait(pid) != 0))
876 rc = 0;
877
878 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
879 if ((rc == 0) || c_wait_key)
881 return rc;
882}
void mutt_rfc3676_space_stuff_attachment(struct Body *b, const char *filename)
Stuff attachments.
Definition rfc3676.c:545
bool mutt_rfc3676_is_format_flowed(struct Body *b)
Is the Email "format-flowed"?
Definition rfc3676.c:400
+ 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 1139 of file mutt_attach.c.

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

910{
911 if (!b)
912 return -1;
913
914 if (fp)
915 {
916 /* recv mode */
917
918 if (e && b->email && (b->encoding != ENC_BASE64) &&
920 {
921 /* message type attachments are written to mail folders. */
922
923 char buf[8192] = { 0 };
924 struct Message *msg = NULL;
925 CopyHeaderFlags chflags = CH_NONE;
926 int rc = -1;
927
928 struct Email *e_new = b->email;
929 e_new->msgno = e->msgno; /* required for MH/maildir */
930 e_new->read = true;
931
932 if (!mutt_file_seek(fp, b->offset, SEEK_SET))
933 return -1;
934 if (!fgets(buf, sizeof(buf), fp))
935 return -1;
936 struct Mailbox *m_att = mx_path_resolve(path);
937 if (!mx_mbox_open(m_att, MUTT_APPEND | MUTT_QUIET))
938 {
939 mailbox_free(&m_att);
940 return -1;
941 }
942 msg = mx_msg_open_new(m_att, e_new, is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NONE : MUTT_ADD_FROM);
943 if (!msg)
944 {
945 mx_mbox_close(m_att);
946 return -1;
947 }
948 if ((m_att->type == MUTT_MBOX) || (m_att->type == MUTT_MMDF))
949 chflags = CH_FROM | CH_UPDATE_LEN;
950 chflags |= ((m_att->type == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
951 if ((mutt_copy_message_fp(msg->fp, fp, e_new, MUTT_CM_NONE, chflags, 0) == 0) &&
952 (mx_msg_commit(m_att, msg) == 0))
953 {
954 rc = 0;
955 }
956 else
957 {
958 rc = -1;
959 }
960
961 mx_msg_close(m_att, &msg);
962 mx_mbox_close(m_att);
963 return rc;
964 }
965 else
966 {
967 /* In recv mode, extract from folder and decode */
968
969 struct State state = { 0 };
970
971 state.fp_out = save_attachment_open(path, opt);
972 if (!state.fp_out)
973 {
974 mutt_perror("fopen");
975 return -1;
976 }
977 if (!mutt_file_seek((state.fp_in = fp), b->offset, SEEK_SET))
978 {
979 mutt_file_fclose(&state.fp_out);
980 return -1;
981 }
982 mutt_decode_attachment(b, &state);
983
984 if (mutt_file_fsync_close(&state.fp_out) != 0)
985 {
986 mutt_perror("fclose");
987 return -1;
988 }
989 }
990 }
991 else
992 {
993 if (!b->filename)
994 return -1;
995
996 /* In send mode, just copy file */
997
998 FILE *fp_old = mutt_file_fopen(b->filename, "r");
999 if (!fp_old)
1000 {
1001 mutt_perror("fopen");
1002 return -1;
1003 }
1004
1005 FILE *fp_new = save_attachment_open(path, opt);
1006 if (!fp_new)
1007 {
1008 mutt_perror("fopen");
1009 mutt_file_fclose(&fp_old);
1010 return -1;
1011 }
1012
1013 if (mutt_file_copy_stream(fp_old, fp_new) == -1)
1014 {
1015 mutt_error(_("Write fault"));
1016 mutt_file_fclose(&fp_old);
1017 mutt_file_fclose(&fp_new);
1018 return -1;
1019 }
1020 mutt_file_fclose(&fp_old);
1021 if (mutt_file_fsync_close(&fp_new) != 0)
1022 {
1023 mutt_error(_("Write fault"));
1024 return -1;
1025 }
1026 }
1027
1028 return 0;
1029}
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
@ MUTT_CM_NONE
No flags are set.
Definition copy_email.h:41
uint32_t CopyHeaderFlags
Definition copy_email.h:89
@ CH_UPDATE
Update the status and x-status fields?
Definition copy_email.h:66
@ CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition copy_email.h:76
@ CH_FROM
Retain the "From " message separator?
Definition copy_email.h:70
@ CH_NOSTATUS
Suppress the status and x-status fields.
Definition copy_email.h:72
@ CH_NONE
No flags are set.
Definition copy_email.h:65
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:1185
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: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:1164
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition mx.c:1650
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition mx.c:595
@ MUTT_ADD_FROM
add a From_ line
Definition mx.h:43
@ MUTT_MSG_NONE
No flags are set.
Definition mx.h:42
@ MUTT_QUIET
Do not print any messages.
Definition mxapi.h:46
@ MUTT_APPEND
Open mailbox for appending 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:81
enum MailboxType type
Mailbox type.
Definition mailbox.h:104
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 1300 of file mutt_attach.c.

1301{
1303 ASSERT(mod_data);
1304
1306}
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:43
+ 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 ( struct ListHead * list)

Delete all temporary attachments.

Parameters
listList of temporary attachment files

Definition at line 1312 of file mutt_attach.c.

1313{
1314 if (!list)
1315 return;
1316
1317 struct ListNode *np = NULL;
1318
1319 STAILQ_FOREACH(np, list, entries)
1320 {
1321 (void) mutt_file_chmod_add(np->data, S_IWUSR);
1323 }
1324
1325 mutt_list_free(list);
1326}
int mutt_file_chmod_add(const char *path, mode_t mode)
Add permissions to a file.
Definition file.c:1002
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: