NeoMutt  2023-03-22-27-g3cb248
Teaching an old dog new tricks
DOXYGEN
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 , MUTT_SAVE_OVERWRITE }
 Options for saving attachments. More...
 

Functions

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

Detailed Description

Handling of email attachments.

Authors
  • Michael R. Elkins

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

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

Definition in file mutt_attach.h.

Enumeration Type Documentation

◆ ViewAttachMode

Options for mutt_view_attachment()

Enumerator
MUTT_VA_REGULAR 

View using default method.

MUTT_VA_MAILCAP 

Force viewing using mailcap entry.

MUTT_VA_AS_TEXT 

Force viewing as text.

MUTT_VA_PAGER 

View attachment in pager using copiousoutput mailcap.

Definition at line 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 

No flags set.

MUTT_SAVE_APPEND 

Append to existing file.

MUTT_SAVE_OVERWRITE 

Overwrite existing file.

Definition at line 56 of file mutt_attach.h.

57{
61};
@ MUTT_SAVE_APPEND
Append to existing file.
Definition: mutt_attach.h:59
@ MUTT_SAVE_OVERWRITE
Overwrite existing file.
Definition: mutt_attach.h:60
@ MUTT_SAVE_NO_FLAGS
No flags set.
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 955 of file recvattach.c.

957{
958 do
959 {
960 switch (op)
961 {
962 case OP_DISPLAY_HEADERS:
963 bool_str_toggle(NeoMutt->sub, "weed", NULL);
964 /* fallthrough */
965
966 case OP_ATTACHMENT_VIEW:
967 {
968 struct AttachPtr *cur_att = current_attachment(actx, menu);
969 if (!cur_att->fp)
970 {
971 if (cur_att->body->type == TYPE_MULTIPART)
972 {
973 struct Body *b = cur_att->body->parts;
974 while (b->parts)
975 b = b->parts;
976 cur_att = b->aptr;
977 }
978 }
979 op = mutt_view_attachment(cur_att->fp, cur_att->body, MUTT_VA_REGULAR,
980 e, actx, menu->win);
981 break;
982 }
983
984 case OP_NEXT_ENTRY:
985 case OP_MAIN_NEXT_UNDELETED: /* hack */
986 {
987 const int index = menu_get_index(menu) + 1;
988 if (index < menu->max)
989 {
990 menu_set_index(menu, index);
991 op = OP_ATTACHMENT_VIEW;
992 }
993 else
994 {
995 op = OP_NULL;
996 }
997 break;
998 }
999
1000 case OP_PREV_ENTRY:
1001 case OP_MAIN_PREV_UNDELETED: /* hack */
1002 {
1003 const int index = menu_get_index(menu) - 1;
1004 if (index >= 0)
1005 {
1006 menu_set_index(menu, index);
1007 op = OP_ATTACHMENT_VIEW;
1008 }
1009 else
1010 {
1011 op = OP_NULL;
1012 }
1013 break;
1014 }
1015
1016 case OP_ATTACHMENT_EDIT_TYPE:
1017 {
1018 struct AttachPtr *cur_att = current_attachment(actx, menu);
1019 /* when we edit the content-type, we should redisplay the attachment
1020 * immediately */
1021 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1022 if (recv)
1023 recvattach_edit_content_type(actx, menu, e);
1024 else
1025 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1026
1028 op = OP_ATTACHMENT_VIEW;
1029 break;
1030 }
1031 /* functions which are passed through from the pager */
1032 case OP_PIPE:
1033 {
1034 struct AttachPtr *cur_att = current_attachment(actx, menu);
1035 mutt_pipe_attachment_list(actx, cur_att->fp, false, cur_att->body, false);
1036 op = OP_ATTACHMENT_VIEW;
1037 break;
1038 }
1039 case OP_ATTACHMENT_PRINT:
1040 {
1041 struct AttachPtr *cur_att = current_attachment(actx, menu);
1042 mutt_print_attachment_list(actx, cur_att->fp, false, cur_att->body);
1043 op = OP_ATTACHMENT_VIEW;
1044 break;
1045 }
1046 case OP_ATTACHMENT_SAVE:
1047 {
1048 struct AttachPtr *cur_att = current_attachment(actx, menu);
1049 mutt_save_attachment_list(actx, cur_att->fp, false, cur_att->body, e, NULL);
1050 op = OP_ATTACHMENT_VIEW;
1051 break;
1052 }
1053 case OP_CHECK_TRADITIONAL:
1055 {
1056 op = OP_NULL;
1057 break;
1058 }
1059 /* fallthrough */
1060 case OP_ATTACHMENT_COLLAPSE:
1061 if (recv)
1062 return op;
1063 /* fallthrough */
1064 default:
1065 op = OP_NULL;
1066 }
1067 } while (op != OP_NULL);
1068
1069 return op;
1070}
int bool_str_toggle(struct ConfigSubset *sub, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition: bool.c:214
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition: external.c:1092
#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:178
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:154
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:168
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
int mutt_view_attachment(FILE *fp, struct Body *a, enum ViewAttachMode mode, struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
View an attachment.
Definition: mutt_attach.c:422
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition: lib.h:92
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:90
#define WithCrypto
Definition: lib.h:116
void mutt_save_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, struct Email *e, struct Menu *menu)
Save a list of attachments.
Definition: recvattach.c:425
struct AttachPtr * current_attachment(struct AttachCtx *actx, struct Menu *menu)
Get the current attachment.
Definition: recvattach.c:69
void mutt_pipe_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, bool filter)
Pipe a list of attachments to a command.
Definition: recvattach.c:718
void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top)
Print a list of Attachments.
Definition: recvattach.c:880
void recvattach_edit_content_type(struct AttachCtx *actx, struct Menu *menu, struct Email *e)
Edit the content type of an attachment.
Definition: recvattach.c:925
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:72
struct AttachPtr * aptr
Menu information, used in recvattach.c.
Definition: body.h:74
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:41
struct MuttWindow * win
Window holding the Menu.
Definition: lib.h:77
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_save_attachment_list()

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

Save a list of attachments.

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

Definition at line 425 of file recvattach.c.

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

◆ mutt_pipe_attachment_list()

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

Pipe a list of attachments to a command.

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

Definition at line 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 = mutt_buffer_pool_get();
728 /* perform charset conversion on text attachments when piping */
729 state.flags = STATE_CHARCONV;
730
731 if (mutt_buffer_get_field((filter ? _("Filter through: ") : _("Pipe to: ")), buf,
732 MUTT_COMP_FILE_SIMPLE, false, NULL, NULL, NULL) != 0)
733 {
734 goto cleanup;
735 }
736
737 if (mutt_buffer_len(buf) == 0)
738 goto cleanup;
739
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(mutt_buffer_string(buf), &state.fp_out, NULL, NULL);
747 pipe_attachment_list(mutt_buffer_string(buf), actx, fp, tag, top, filter, &state);
748 mutt_file_fclose(&state.fp_out);
749 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
750 if ((filter_wait(pid) != 0) || c_wait_key)
752 }
753 else
754 {
755 pipe_attachment_list(mutt_buffer_string(buf), actx, fp, tag, top, filter, &state);
756 }
757
758cleanup:
760}
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:409
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:386
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:353
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
#define STATE_CHARCONV
Do character set conversions.
Definition: state.h:36
#define MUTT_COMP_FILE_SIMPLE
File completion (no browser)
Definition: mutt.h:60
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
Keep track when processing files.
Definition: state.h:47
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition: state.h:51
FILE * fp_out
File to write to.
Definition: state.h:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_print_attachment_list()

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

Print a list of Attachments.

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

Definition at line 880 of file recvattach.c.

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

◆ mutt_view_attachment()

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

View an attachment.

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

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

Definition at line 422 of file mutt_attach.c.

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

343{
344 struct ListNode *np = NULL;
345 STAILQ_FOREACH(np, &MimeLookupList, entries)
346 {
347 const int i = 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}
struct ListHead MimeLookupList
List of mime types that that shouldn't use the mailcap entry.
Definition: globals.c:51
ContentType
Content-Type.
Definition: mime.h:30
@ TYPE_AUDIO
Type: 'audio/*'.
Definition: mime.h:32
@ TYPE_IMAGE
Type: 'image/*'.
Definition: mime.h:34
@ TYPE_OTHER
Unknown Content-Type.
Definition: mime.h:31
@ TYPE_MESSAGE
Type: 'message/*'.
Definition: mime.h:35
@ TYPE_MODEL
Type: 'model/*'.
Definition: mime.h:36
@ TYPE_APPLICATION
Type: 'application/*'.
Definition: mime.h:33
@ TYPE_TEXT
Type: 'text/*'.
Definition: mime.h:38
@ TYPE_VIDEO
Type: 'video/*'.
Definition: mime.h:39
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:819
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:567
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:524
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
enum ContentType mutt_lookup_mime_type(struct Body *att, const char *path)
Find the MIME type for an attachment.
Definition: sendlib.c:69
char * xtype
content-type if x-unknown
Definition: body.h:61
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_compose_attachment()

int mutt_compose_attachment ( struct Body a)

Create an attachment.

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

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

◆ mutt_decode_save_attachment()

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

Decode, then save an attachment.

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

Definition at line 1048 of file mutt_attach.c.

1050{
1051 struct State state = { 0 };
1052 unsigned int saved_encoding = 0;
1053 struct Body *saved_parts = NULL;
1054 struct Email *e_saved = NULL;
1055 int rc = 0;
1056
1057 state.flags = flags;
1058
1059 if (opt == MUTT_SAVE_APPEND)
1060 state.fp_out = fopen(path, "a");
1061 else if (opt == MUTT_SAVE_OVERWRITE)
1062 state.fp_out = fopen(path, "w");
1063 else
1064 state.fp_out = mutt_file_fopen(path, "w");
1065
1066 if (!state.fp_out)
1067 {
1068 mutt_perror("fopen");
1069 return -1;
1070 }
1071
1072 if (!fp)
1073 {
1074 /* When called from the compose menu, the attachment isn't parsed,
1075 * so we need to do it here. */
1076 state.fp_in = fopen(m->filename, "r");
1077 if (!state.fp_in)
1078 {
1079 mutt_perror("fopen");
1080 mutt_file_fclose(&state.fp_out);
1081 return -1;
1082 }
1083
1084 struct stat st = { 0 };
1085 if (fstat(fileno(state.fp_in), &st) == -1)
1086 {
1087 mutt_perror("stat");
1088 mutt_file_fclose(&state.fp_in);
1089 mutt_file_fclose(&state.fp_out);
1090 return -1;
1091 }
1092
1093 saved_encoding = m->encoding;
1094 if (!is_multipart(m))
1095 m->encoding = ENC_8BIT;
1096
1097 m->length = st.st_size;
1098 m->offset = 0;
1099 saved_parts = m->parts;
1100 e_saved = m->email;
1101 mutt_parse_part(state.fp_in, m);
1102
1103 if (m->noconv || is_multipart(m))
1104 state.flags |= STATE_CHARCONV;
1105 }
1106 else
1107 {
1108 state.fp_in = fp;
1109 state.flags |= STATE_CHARCONV;
1110 }
1111
1112 mutt_body_handler(m, &state);
1113
1114 if (mutt_file_fsync_close(&state.fp_out) != 0)
1115 {
1116 mutt_perror("fclose");
1117 rc = -1;
1118 }
1119 if (!fp)
1120 {
1121 m->length = 0;
1122 m->encoding = saved_encoding;
1123 if (saved_parts)
1124 {
1125 email_free(&m->email);
1126 m->parts = saved_parts;
1127 m->email = e_saved;
1128 }
1129 mutt_file_fclose(&state.fp_in);
1130 }
1131
1132 return rc;
1133}
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:165
int mutt_body_handler(struct Body *b, struct State *state)
Handler for the Body of an email.
Definition: handler.c:1619
@ ENC_8BIT
8-bit text
Definition: mime.h:50
#define is_multipart(body)
Definition: mime.h:82
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1745
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:37
char * path
Path of Email (for local Mailboxes)
Definition: email.h:68
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_edit_attachment()

bool mutt_edit_attachment ( struct Body a)

Edit an attachment.

Parameters
aEmail 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 264 of file mutt_attach.c.

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

◆ mutt_get_tmp_attachment()

int mutt_get_tmp_attachment ( struct Body a)

Get a temporary copy of an attachment.

Parameters
aAttachment to copy
Return values
0Success
-1Error

Definition at line 69 of file mutt_attach.c.

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

◆ mutt_pipe_attachment()

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

Pipe an attachment to a command.

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

Definition at line 745 of file mutt_attach.c.

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

◆ mutt_print_attachment()

int mutt_print_attachment ( FILE *  fp,
struct Body a 
)

Print out an attachment.

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

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

Definition at line 1148 of file mutt_attach.c.

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

◆ mutt_save_attachment()

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

Save an attachment.

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

Definition at line 914 of file mutt_attach.c.

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

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

◆ mutt_unlink_temp_attachments()

void mutt_unlink_temp_attachments ( void  )

Delete all temporary attachments.

Definition at line 1318 of file mutt_attach.c.

1319{
1320 struct ListNode *np = NULL;
1321
1322 STAILQ_FOREACH(np, &TempAttachmentsList, entries)
1323 {
1324 (void) mutt_file_chmod_add(np->data, S_IWUSR);
1326 }
1327
1329}
int mutt_file_chmod_add(const char *path, mode_t mode)
Add permissions to a file.
Definition: file.c:1110
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
+ Here is the call graph for this function:
+ Here is the caller graph for this function: