NeoMutt
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
mutt_attach.h File Reference

Handling of email attachments. More...

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

Go to the source code of this file.

Enumerations

enum  ViewAttachMode { MUTT_VA_REGULAR = 1 , MUTT_VA_MAILCAP , MUTT_VA_AS_TEXT , MUTT_VA_PAGER }
 Options for mutt_view_attachment() More...
 
enum  SaveAttach { MUTT_SAVE_NO_FLAGS = 0 , MUTT_SAVE_APPEND , 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.
 
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.
 
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.
 
void mutt_print_attachment_list (struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top)
 Print a list of Attachments.
 
int mutt_view_attachment (FILE *fp, struct Body *a, 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 *a)
 Create an attachment.
 
int mutt_decode_save_attachment (FILE *fp, struct Body *m, const char *path, StateFlags flags, enum SaveAttach opt)
 Decode, then save an attachment.
 
bool mutt_edit_attachment (struct Body *a)
 Edit an attachment.
 
int mutt_get_tmp_attachment (struct Body *a)
 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 *a)
 Print out an attachment.
 
int mutt_save_attachment (FILE *fp, struct Body *m, const char *path, enum SaveAttach opt, struct Email *e)
 Save an attachment.
 
void mutt_add_temp_attachment (const char *filename)
 Add file to list of temporary attachments.
 
void mutt_temp_attachments_cleanup (void)
 Delete all temporary attachments.
 

Detailed Description

Handling of email attachments.

Authors
  • 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 958 of file recvattach.c.

960{
961 do
962 {
963 switch (op)
964 {
965 case OP_DISPLAY_HEADERS:
966 bool_str_toggle(NeoMutt->sub, "weed", NULL);
967 /* fallthrough */
968
969 case OP_ATTACHMENT_VIEW:
970 {
971 struct AttachPtr *cur_att = current_attachment(actx, menu);
972 if (!cur_att->fp)
973 {
974 if (cur_att->body->type == TYPE_MULTIPART)
975 {
976 struct Body *b = cur_att->body->parts;
977 while (b->parts)
978 b = b->parts;
979 cur_att = b->aptr;
980 }
981 }
982 op = mutt_view_attachment(cur_att->fp, cur_att->body, MUTT_VA_REGULAR,
983 e, actx, menu->win);
984 break;
985 }
986
987 case OP_NEXT_ENTRY:
988 case OP_MAIN_NEXT_UNDELETED: /* hack */
989 {
990 const int index = menu_get_index(menu) + 1;
991 if (index < menu->max)
992 {
993 menu_set_index(menu, index);
994 op = OP_ATTACHMENT_VIEW;
995 }
996 else
997 {
998 op = OP_NULL;
999 }
1000 break;
1001 }
1002
1003 case OP_PREV_ENTRY:
1004 case OP_MAIN_PREV_UNDELETED: /* hack */
1005 {
1006 const int index = menu_get_index(menu) - 1;
1007 if (index >= 0)
1008 {
1009 menu_set_index(menu, index);
1010 op = OP_ATTACHMENT_VIEW;
1011 }
1012 else
1013 {
1014 op = OP_NULL;
1015 }
1016 break;
1017 }
1018
1019 case OP_ATTACHMENT_EDIT_TYPE:
1020 {
1021 struct AttachPtr *cur_att = current_attachment(actx, menu);
1022 /* when we edit the content-type, we should redisplay the attachment
1023 * immediately */
1024 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1025 if (recv)
1026 recvattach_edit_content_type(actx, menu, e);
1027 else
1028 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1029
1031 op = OP_ATTACHMENT_VIEW;
1032 break;
1033 }
1034 /* functions which are passed through from the pager */
1035 case OP_PIPE:
1036 {
1037 struct AttachPtr *cur_att = current_attachment(actx, menu);
1038 mutt_pipe_attachment_list(actx, cur_att->fp, false, cur_att->body, false);
1039 op = OP_ATTACHMENT_VIEW;
1040 break;
1041 }
1042 case OP_ATTACHMENT_PRINT:
1043 {
1044 struct AttachPtr *cur_att = current_attachment(actx, menu);
1045 mutt_print_attachment_list(actx, cur_att->fp, false, cur_att->body);
1046 op = OP_ATTACHMENT_VIEW;
1047 break;
1048 }
1049 case OP_ATTACHMENT_SAVE:
1050 {
1051 struct AttachPtr *cur_att = current_attachment(actx, menu);
1052 mutt_save_attachment_list(actx, cur_att->fp, false, cur_att->body, e, NULL);
1053 op = OP_ATTACHMENT_VIEW;
1054 break;
1055 }
1056 case OP_CHECK_TRADITIONAL:
1058 {
1059 op = OP_NULL;
1060 break;
1061 }
1062 /* fallthrough */
1063 case OP_ATTACHMENT_COLLAPSE:
1064 if (recv)
1065 return op;
1066 /* fallthrough */
1067 default:
1068 op = OP_NULL;
1069 }
1070 } while (op != OP_NULL);
1071
1072 return op;
1073}
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:1078
#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:180
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:156
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:170
@ 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:423
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition: lib.h:93
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:91
#define WithCrypto
Definition: lib.h:117
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:429
struct AttachPtr * current_attachment(struct AttachCtx *actx, struct Menu *menu)
Get the current attachment.
Definition: recvattach.c:71
void mutt_pipe_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, bool filter)
Pipe a list of attachments to a command.
Definition: recvattach.c:721
void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top)
Print a list of Attachments.
Definition: recvattach.c:884
void recvattach_edit_content_type(struct AttachCtx *actx, struct Menu *menu, struct Email *e)
Edit the content type of an attachment.
Definition: recvattach.c:928
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:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
+ 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 429 of file recvattach.c.

431{
432 char *directory = NULL;
433 int rc = 1;
434 int last = menu_get_index(menu);
435 FILE *fp_out = NULL;
436 int saved_attachments = 0;
437
438 struct Buffer *buf = buf_pool_get();
439 struct Buffer *tfile = buf_pool_get();
440
441 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
442 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
443 const bool c_attach_save_without_prompting = cs_subset_bool(NeoMutt->sub, "attach_save_without_prompting");
444
445 for (int i = 0; !tag || (i < actx->idxlen); i++)
446 {
447 if (tag)
448 {
449 fp = actx->idx[i]->fp;
450 top = actx->idx[i]->body;
451 }
452 if (!tag || top->tagged)
453 {
454 if (c_attach_split)
455 {
456 if (tag && menu && top->aptr)
457 {
458 menu_set_index(menu, top->aptr->num);
460
461 menu_redraw(menu);
462 }
463 if (c_attach_save_without_prompting)
464 {
465 // Save each file, with no prompting, using the configured 'AttachSaveDir'
466 rc = save_without_prompting(fp, top, e);
467 if (rc == 0)
468 saved_attachments++;
469 }
470 else
471 {
472 // Save each file, prompting the user for the location each time.
473 if (query_save_attachment(fp, top, e, &directory) == -1)
474 break;
475 }
476 }
477 else
478 {
480
481 if (buf_is_empty(buf))
482 {
484 prepend_savedir(buf);
485
486 struct FileCompletionData cdata = { false, NULL, NULL, NULL };
487 if ((mw_get_field(_("Save to file: "), buf, MUTT_COMP_CLEAR, HC_FILE,
488 &CompleteMailboxOps, &cdata) != 0) ||
489 buf_is_empty(buf))
490 {
491 goto cleanup;
492 }
493 buf_expand_path(buf);
494 if (mutt_check_overwrite(top->filename, buf_string(buf), tfile, &opt, NULL))
495 goto cleanup;
496 }
497 else
498 {
499 opt = MUTT_SAVE_APPEND;
500 }
501
502 rc = save_attachment_flowed_helper(fp, top, buf_string(tfile), opt, e);
503 if ((rc == 0) && c_attach_sep && (fp_out = fopen(buf_string(tfile), "a")))
504 {
505 fprintf(fp_out, "%s", c_attach_sep);
506 mutt_file_fclose(&fp_out);
507 }
508 }
509 }
510 if (!tag)
511 break;
512 }
513
514 FREE(&directory);
515
516 if (tag && menu)
517 {
518 menu_set_index(menu, last);
520 }
521
522 if (rc == 0)
523 {
524 if (!c_attach_split)
525 saved_attachments = 1;
526
527 if (!c_attach_split || c_attach_save_without_prompting)
528 {
529 mutt_message(ngettext("Attachment saved", "%d attachments saved", saved_attachments),
530 saved_attachments);
531 }
532 }
533
534cleanup:
535 buf_pool_release(&buf);
536 buf_pool_release(&tfile);
537}
const struct CompleteOps CompleteMailboxOps
Auto-Completion of Files / Mailboxes.
Definition: complete.c:160
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:303
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:407
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
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_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
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:275
#define mutt_message(...)
Definition: logging2.h:91
@ HC_FILE
Files.
Definition: lib.h:52
#define FREE(x)
Definition: memory.h:45
#define MENU_REDRAW_MOTION
Redraw after moving the menu list.
Definition: lib.h:58
#define _(a)
Definition: message.h:28
const char * mutt_path_basename(const char *path)
Find the last component for a pathname.
Definition: path.c:314
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:56
SaveAttach
Options for saving attachments.
Definition: mutt_attach.h:57
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:335
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:584
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
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:227
static void prepend_savedir(struct Buffer *buf)
Add $attach_save_dir to the beginning of a path.
Definition: recvattach.c:167
static int save_without_prompting(FILE *fp, struct Body *body, struct Email *e)
Save the attachment, without prompting each time.
Definition: recvattach.c:379
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:274
#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
Input for the file completion function.
Definition: curs_lib.h:49
+ 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 721 of file recvattach.c.

723{
724 struct State state = { 0 };
725 struct Buffer *buf = NULL;
726
727 if (fp)
728 filter = false; /* sanity check: we can't filter in the recv case yet */
729
730 buf = buf_pool_get();
731 /* perform charset conversion on text attachments when piping */
732 state.flags = STATE_CHARCONV;
733
734 if (mw_get_field((filter ? _("Filter through: ") : _("Pipe to: ")), buf,
736 {
737 goto cleanup;
738 }
739
740 if (buf_len(buf) == 0)
741 goto cleanup;
742
743 buf_expand_path(buf);
744
745 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
746 if (!filter && !c_attach_split)
747 {
748 mutt_endwin();
749 pid_t pid = filter_create(buf_string(buf), &state.fp_out, NULL, NULL, EnvList);
750 pipe_attachment_list(buf_string(buf), actx, fp, tag, top, filter, &state);
751 mutt_file_fclose(&state.fp_out);
752 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
753 if ((filter_wait(pid) != 0) || c_wait_key)
755 }
756 else
757 {
758 pipe_attachment_list(buf_string(buf), actx, fp, tag, top, filter, &state);
759 }
760
761cleanup:
762 buf_pool_release(&buf);
763}
const struct CompleteOps CompleteFileOps
Auto-Completion of Files.
Definition: complete.c:153
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:466
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:188
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:154
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:218
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:207
char ** EnvList
Private copy of the environment variables.
Definition: globals.c:85
@ HC_COMMAND
NeoMutt commands.
Definition: lib.h:51
#define STATE_CHARCONV
Do character set conversions.
Definition: state.h:36
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:55
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:689
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 884 of file recvattach.c.

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

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

◆ mutt_check_lookup_list()

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

Update the mime type.

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

Definition at line 343 of file mutt_attach.c.

344{
345 struct ListNode *np = NULL;
346 STAILQ_FOREACH(np, &MimeLookupList, entries)
347 {
348 const int i = mutt_str_len(np->data) - 1;
349 if (((i > 0) && (np->data[i - 1] == '/') && (np->data[i] == '*') &&
350 mutt_istrn_equal(type, np->data, i)) ||
351 mutt_istr_equal(type, np->data))
352 {
353 struct Body tmp = { 0 };
354 enum ContentType n;
355 if ((n = mutt_lookup_mime_type(&tmp, b->filename)) != TYPE_OTHER ||
357 {
358 snprintf(type, len, "%s/%s",
359 (n == TYPE_AUDIO) ? "audio" :
360 (n == TYPE_APPLICATION) ? "application" :
361 (n == TYPE_IMAGE) ? "image" :
362 (n == TYPE_MESSAGE) ? "message" :
363 (n == TYPE_MODEL) ? "model" :
364 (n == TYPE_MULTIPART) ? "multipart" :
365 (n == TYPE_TEXT) ? "text" :
366 (n == TYPE_VIDEO) ? "video" :
367 "other",
368 tmp.subtype);
369 mutt_debug(LL_DEBUG1, "\"%s\" -> %s\n", b->filename, type);
370 }
371 FREE(&tmp.subtype);
372 FREE(&tmp.xtype);
373 }
374 }
375}
struct ListHead MimeLookupList
List of mime types that that shouldn't use the mailcap entry.
Definition: globals.c:52
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:810
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:568
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:525
#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:74
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 118 of file mutt_attach.c.

119{
120 char type[256] = { 0 };
121 struct MailcapEntry *entry = mailcap_entry_new();
122 bool unlink_newfile = false;
123 int rc = 0;
124 struct Buffer *cmd = buf_pool_get();
125 struct Buffer *newfile = buf_pool_get();
126 struct Buffer *tmpfile = buf_pool_get();
127
128 snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
129 if (mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_COMPOSE))
130 {
131 if (entry->composecommand || entry->composetypecommand)
132 {
133 if (entry->composetypecommand)
134 buf_strcpy(cmd, entry->composetypecommand);
135 else
136 buf_strcpy(cmd, entry->composecommand);
137
138 mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
139 mutt_debug(LL_DEBUG1, "oldfile: %s newfile: %s\n", a->filename,
140 buf_string(newfile));
141 if (mutt_file_symlink(a->filename, buf_string(newfile)) == -1)
142 {
143 if (query_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
144 goto bailout;
145 buf_strcpy(newfile, a->filename);
146 }
147 else
148 {
149 unlink_newfile = true;
150 }
151
152 if (mailcap_expand_command(a, buf_string(newfile), type, cmd))
153 {
154 /* For now, editing requires a file, no piping */
155 mutt_error(_("Mailcap compose entry requires %%s"));
156 }
157 else
158 {
159 int r;
160
161 mutt_endwin();
162 r = mutt_system(buf_string(cmd));
163 if (r == -1)
164 mutt_error(_("Error running \"%s\""), buf_string(cmd));
165
166 if ((r != -1) && entry->composetypecommand)
167 {
168 struct Body *b = NULL;
169
170 FILE *fp = mutt_file_fopen(a->filename, "r");
171 if (!fp)
172 {
173 mutt_perror(_("Failure to open file to parse headers"));
174 goto bailout;
175 }
176
177 b = mutt_read_mime_header(fp, 0);
178 if (b)
179 {
180 if (!TAILQ_EMPTY(&b->parameter))
181 {
183 a->parameter = b->parameter;
185 }
186 if (b->description)
187 {
188 FREE(&a->description);
189 a->description = b->description;
190 b->description = NULL;
191 }
192 if (b->form_name)
193 {
194 FREE(&a->form_name);
195 a->form_name = b->form_name;
196 b->form_name = NULL;
197 }
198
199 /* Remove headers by copying out data to another file, then
200 * copying the file back */
201 const LOFF_T offset = b->offset;
202 mutt_body_free(&b);
203 if (!mutt_file_seek(fp, offset, SEEK_SET))
204 {
205 goto bailout;
206 }
207
208 buf_mktemp(tmpfile);
209 FILE *fp_tmp = mutt_file_fopen(buf_string(tmpfile), "w");
210 if (!fp_tmp)
211 {
212 mutt_perror(_("Failure to open file to strip headers"));
213 mutt_file_fclose(&fp);
214 goto bailout;
215 }
216 mutt_file_copy_stream(fp, fp_tmp);
217 mutt_file_fclose(&fp);
218 mutt_file_fclose(&fp_tmp);
220 if (mutt_file_rename(buf_string(tmpfile), a->filename) != 0)
221 {
222 mutt_perror(_("Failure to rename file"));
223 goto bailout;
224 }
225 }
226 }
227 }
228 }
229 }
230 else
231 {
232 mutt_message(_("No mailcap compose entry for %s, creating empty file"), type);
233 rc = 1;
234 goto bailout;
235 }
236
237 rc = 1;
238
239bailout:
240
241 if (unlink_newfile)
242 unlink(buf_string(newfile));
243
244 buf_pool_release(&cmd);
245 buf_pool_release(&newfile);
246 buf_pool_release(&tmpfile);
247
248 mailcap_entry_free(&entry);
249 return rc;
250}
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1344
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:262
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:733
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition: file.c:1412
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:290
@ MUTT_MC_COMPOSE
Mailcap compose field.
Definition: mailcap.h:58
void mutt_param_free(struct ParameterList *pl)
Free a ParameterList.
Definition: parameter.c:61
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:330
#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 state.fp_in = fp;
1075 state.flags |= STATE_CHARCONV;
1076 }
1077 else
1078 {
1079 /* When called from the compose menu, the attachment isn't parsed,
1080 * so we need to do it here. */
1081 state.fp_in = fopen(m->filename, "r");
1082 if (!state.fp_in)
1083 {
1084 mutt_perror("fopen");
1085 mutt_file_fclose(&state.fp_out);
1086 return -1;
1087 }
1088
1089 struct stat st = { 0 };
1090 if (fstat(fileno(state.fp_in), &st) == -1)
1091 {
1092 mutt_perror("stat");
1093 mutt_file_fclose(&state.fp_in);
1094 mutt_file_fclose(&state.fp_out);
1095 return -1;
1096 }
1097
1098 saved_encoding = m->encoding;
1099 if (!is_multipart(m))
1100 m->encoding = ENC_8BIT;
1101
1102 m->length = st.st_size;
1103 m->offset = 0;
1104 saved_parts = m->parts;
1105 e_saved = m->email;
1106 mutt_parse_part(state.fp_in, m);
1107
1108 if (m->noconv || is_multipart(m))
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
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1779
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:168
int mutt_body_handler(struct Body *b, struct State *state)
Handler for the Body of an email.
Definition: handler.c:1618
@ ENC_8BIT
8-bit text
Definition: mime.h:50
#define is_multipart(body)
Definition: mime.h:82
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 265 of file mutt_attach.c.

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

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

747{
748 pid_t pid = 0;
749 int out = -1, rc = 0;
750 bool is_flowed = false;
751 bool unlink_unstuff = false;
752 FILE *fp_filter = NULL, *fp_unstuff = NULL, *fp_in = NULL;
753 struct Buffer *unstuff_tempfile = NULL;
754
755 if (outfile && *outfile)
756 {
757 out = mutt_file_open(outfile, O_CREAT | O_EXCL | O_WRONLY);
758 if (out < 0)
759 {
760 mutt_perror("open");
761 return 0;
762 }
763 }
764
766 {
767 is_flowed = true;
768 unstuff_tempfile = buf_pool_get();
769 buf_mktemp(unstuff_tempfile);
770 }
771
772 mutt_endwin();
773
774 if (outfile && *outfile)
775 pid = filter_create_fd(path, &fp_filter, NULL, NULL, -1, out, -1, EnvList);
776 else
777 pid = filter_create(path, &fp_filter, NULL, NULL, EnvList);
778 if (pid < 0)
779 {
780 mutt_perror(_("Can't create filter"));
781 goto bail;
782 }
783
784 /* recv case */
785 if (fp)
786 {
787 struct State state = { 0 };
788
789 /* perform charset conversion on text attachments when piping */
790 state.flags = STATE_CHARCONV;
791
792 if (is_flowed)
793 {
794 fp_unstuff = mutt_file_fopen(buf_string(unstuff_tempfile), "w");
795 if (!fp_unstuff)
796 {
797 mutt_perror("mutt_file_fopen");
798 goto bail;
799 }
800 unlink_unstuff = true;
801
802 state.fp_in = fp;
803 state.fp_out = fp_unstuff;
804 mutt_decode_attachment(b, &state);
805 mutt_file_fclose(&fp_unstuff);
806
808
809 fp_unstuff = mutt_file_fopen(buf_string(unstuff_tempfile), "r");
810 if (!fp_unstuff)
811 {
812 mutt_perror("mutt_file_fopen");
813 goto bail;
814 }
815 mutt_file_copy_stream(fp_unstuff, fp_filter);
816 mutt_file_fclose(&fp_unstuff);
817 }
818 else
819 {
820 state.fp_in = fp;
821 state.fp_out = fp_filter;
822 mutt_decode_attachment(b, &state);
823 }
824 }
825 else
826 {
827 /* send case */
828 const char *infile = NULL;
829
830 if (is_flowed)
831 {
832 if (mutt_save_attachment(fp, b, buf_string(unstuff_tempfile),
833 MUTT_SAVE_NO_FLAGS, NULL) == -1)
834 {
835 goto bail;
836 }
837 unlink_unstuff = true;
839 infile = buf_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(buf_string(unstuff_tempfile));
876 buf_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 = buf_pool_get();
1155 struct Buffer *cmd = buf_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, buf_string(newfile), MUTT_SAVE_NO_FLAGS, NULL) == -1)
1176 {
1177 goto mailcap_cleanup;
1178 }
1179 unlink_newfile = 1;
1180
1182
1183 buf_strcpy(cmd, entry->printcommand);
1184
1185 bool piped = mailcap_expand_command(a, buf_string(newfile), type, cmd);
1186
1187 mutt_endwin();
1188
1189 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
1190 /* interactive program */
1191 if (piped)
1192 {
1193 fp_in = fopen(buf_string(newfile), "r");
1194 if (!fp_in)
1195 {
1196 mutt_perror("fopen");
1197 mailcap_entry_free(&entry);
1198 goto mailcap_cleanup;
1199 }
1200
1201 pid = filter_create(buf_string(cmd), &fp_out, NULL, NULL, EnvList);
1202 if (pid < 0)
1203 {
1204 mutt_perror(_("Can't create filter"));
1205 mailcap_entry_free(&entry);
1206 mutt_file_fclose(&fp_in);
1207 goto mailcap_cleanup;
1208 }
1209 mutt_file_copy_stream(fp_in, fp_out);
1210 mutt_file_fclose(&fp_out);
1211 mutt_file_fclose(&fp_in);
1212 if (filter_wait(pid) || c_wait_key)
1214 }
1215 else
1216 {
1217 int rc2 = mutt_system(buf_string(cmd));
1218 if (rc2 == -1)
1219 mutt_debug(LL_DEBUG1, "Error running \"%s\"\n", cmd->data);
1220
1221 if ((rc2 != 0) || c_wait_key)
1223 }
1224
1225 rc = 1;
1226
1227 mailcap_cleanup:
1228 if (unlink_newfile)
1229 mutt_file_unlink(buf_string(newfile));
1230
1231 mailcap_entry_free(&entry);
1232 goto out;
1233 }
1234
1235 const char *const c_print_command = cs_subset_string(NeoMutt->sub, "print_command");
1236 if (mutt_istr_equal("text/plain", type) || mutt_istr_equal("application/postscript", type))
1237 {
1238 rc = (mutt_pipe_attachment(fp, a, NONULL(c_print_command), NULL));
1239 goto out;
1240 }
1241 else if (mutt_can_decode(a))
1242 {
1243 /* decode and print */
1244
1245 fp_in = NULL;
1246 fp_out = NULL;
1247
1248 buf_mktemp(newfile);
1250 MUTT_SAVE_NO_FLAGS) == 0)
1251 {
1252 unlink_newfile = true;
1253 mutt_debug(LL_DEBUG2, "successfully decoded %s type attachment to %s\n",
1254 type, buf_string(newfile));
1255
1256 fp_in = fopen(buf_string(newfile), "r");
1257 if (!fp_in)
1258 {
1259 mutt_perror("fopen");
1260 goto decode_cleanup;
1261 }
1262
1263 mutt_debug(LL_DEBUG2, "successfully opened %s read-only\n", buf_string(newfile));
1264
1265 mutt_endwin();
1266 pid = filter_create(NONULL(c_print_command), &fp_out, NULL, NULL, EnvList);
1267 if (pid < 0)
1268 {
1269 mutt_perror(_("Can't create filter"));
1270 goto decode_cleanup;
1271 }
1272
1273 mutt_debug(LL_DEBUG2, "Filter created\n");
1274
1275 mutt_file_copy_stream(fp_in, fp_out);
1276
1277 mutt_file_fclose(&fp_out);
1278 mutt_file_fclose(&fp_in);
1279
1280 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
1281 if ((filter_wait(pid) != 0) || c_wait_key)
1283 rc = 1;
1284 }
1285 decode_cleanup:
1286 mutt_file_fclose(&fp_in);
1287 mutt_file_fclose(&fp_out);
1288 if (unlink_newfile)
1289 mutt_file_unlink(buf_string(newfile));
1290 }
1291 else
1292 {
1293 mutt_error(_("I don't know how to print that"));
1294 rc = 0;
1295 }
1296
1297out:
1298 buf_pool_release(&newfile);
1299 buf_pool_release(&cmd);
1300
1301 return rc;
1302}
bool mutt_can_decode(struct Body *b)
Will decoding the attachment produce any output.
Definition: handler.c:1852
@ 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, const char *outfile)
Pipe an attachment to a command.
Definition: mutt_attach.c:746
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:649
#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:90
@ 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 **ptr)
Close a message.
Definition: mx.c:1206
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:304
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1066
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1185
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1697
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:615
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:40
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:39
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mxapi.h:42
#define MUTT_QUIET
Do not print any messages.
Definition: mxapi.h:44
bool read
Email is read.
Definition: email.h: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: 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 1308 of file mutt_attach.c.

1309{
1311}
struct ListHead TempAttachmentsList
List of temporary files for displaying attachments.
Definition: globals.c:54
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_temp_attachments_cleanup()

void mutt_temp_attachments_cleanup ( void  )

Delete all temporary attachments.

Definition at line 1316 of file mutt_attach.c.

1317{
1318 struct ListNode *np = NULL;
1319
1320 STAILQ_FOREACH(np, &TempAttachmentsList, entries)
1321 {
1322 (void) mutt_file_chmod_add(np->data, S_IWUSR);
1324 }
1325
1327}
int mutt_file_chmod_add(const char *path, mode_t mode)
Add permissions to a file.
Definition: file.c:1135
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: