NeoMutt  2025-12-11-911-gd8d604
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
mutt_attach.h File Reference

Handling of email attachments. More...

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

Go to the source code of this file.

Enumerations

enum  ViewAttachMode { MUTT_VA_REGULAR = 1 , MUTT_VA_MAILCAP , MUTT_VA_AS_TEXT , MUTT_VA_PAGER }
 Options for mutt_view_attachment() More...
 
enum  SaveAttach { MUTT_SAVE_NONE = 0 , MUTT_SAVE_APPEND = 1U << 0 }
 Options for saving attachments. More...
 

Functions

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

Detailed Description

Handling of email attachments.

Authors
  • Richard Russon

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

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

Definition in file mutt_attach.h.

Enumeration Type Documentation

◆ ViewAttachMode

Options for mutt_view_attachment()

Enumerator
MUTT_VA_REGULAR 

View using default method.

MUTT_VA_MAILCAP 

Force viewing using mailcap entry.

MUTT_VA_AS_TEXT 

Force viewing as text.

MUTT_VA_PAGER 

View attachment in pager using copiousoutput mailcap.

Definition at line 43 of file mutt_attach.h.

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

◆ SaveAttach

enum SaveAttach

Options for saving attachments.

See also
mutt_save_attachment(), mutt_decode_save_attachment(), save_attachment_open(), mutt_check_overwrite()
Enumerator
MUTT_SAVE_NONE 

Overwrite existing file (the default)

MUTT_SAVE_APPEND 

Append to existing file.

Definition at line 57 of file mutt_attach.h.

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

Function Documentation

◆ mutt_attach_display_loop()

int mutt_attach_display_loop ( struct ConfigSubset * sub,
struct Menu * menu,
int op,
struct Email * e,
struct AttachCtx * actx,
bool recv )

Event loop for the Attachment menu.

Parameters
subConfig Subset
menuMenu listing Attachments
opOperation, e.g. OP_ATTACH_VIEW
eEmail
actxAttachment context
recvtrue if these are received attachments (rather than in compose)
Return values
numOperation performed

Definition at line 917 of file recvattach.c.

919{
920 do
921 {
922 switch (op)
923 {
924 case OP_DISPLAY_HEADERS:
925 bool_str_toggle(NeoMutt->sub, "weed", NULL);
927
928 case OP_ATTACH_VIEW:
929 {
930 struct AttachPtr *cur_att = current_attachment(actx, menu);
931 if (!cur_att->fp)
932 {
933 if (cur_att->body->type == TYPE_MULTIPART)
934 {
935 struct Body *b = cur_att->body->parts;
936 while (b && b->parts)
937 b = b->parts;
938 if (b)
939 cur_att = b->aptr;
940 }
941 }
942 op = mutt_view_attachment(cur_att->fp, cur_att->body, MUTT_VA_REGULAR,
943 e, actx, menu->win);
944 break;
945 }
946
947 case OP_NEXT_ENTRY:
948 case OP_MAIN_NEXT_UNDELETED: /* hack */
949 {
950 const int index = menu_get_index(menu) + 1;
951 if (index < menu->max)
952 {
953 menu_set_index(menu, index);
954 op = OP_ATTACH_VIEW;
955 }
956 else
957 {
958 op = OP_NULL;
959 }
960 break;
961 }
962
963 case OP_PREV_ENTRY:
964 case OP_MAIN_PREV_UNDELETED: /* hack */
965 {
966 const int index = menu_get_index(menu) - 1;
967 if (index >= 0)
968 {
969 menu_set_index(menu, index);
970 op = OP_ATTACH_VIEW;
971 }
972 else
973 {
974 op = OP_NULL;
975 }
976 break;
977 }
978
979 case OP_ATTACH_EDIT_TYPE:
980 {
981 struct AttachPtr *cur_att = current_attachment(actx, menu);
982 /* when we edit the content-type, we should redisplay the attachment
983 * immediately */
984 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
985 if (recv)
986 recvattach_edit_content_type(actx, menu, e);
987 else
988 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
989
991 op = OP_ATTACH_VIEW;
992 break;
993 }
994 /* functions which are passed through from the pager */
995 case OP_PIPE:
996 {
997 struct AttachPtr *cur_att = current_attachment(actx, menu);
998 struct AttachPtrArray aa = ARRAY_HEAD_INITIALIZER;
999 ARRAY_ADD(&aa, cur_att);
1000 mutt_pipe_attachment_list(&aa, false);
1001 ARRAY_FREE(&aa);
1002 op = OP_ATTACH_VIEW;
1003 break;
1004 }
1005 case OP_ATTACH_PRINT:
1006 {
1007 struct AttachPtr *cur_att = current_attachment(actx, menu);
1008 struct AttachPtrArray aa = ARRAY_HEAD_INITIALIZER;
1009 ARRAY_ADD(&aa, cur_att);
1011 ARRAY_FREE(&aa);
1012 op = OP_ATTACH_VIEW;
1013 break;
1014 }
1015 case OP_ATTACH_SAVE:
1016 {
1017 struct AttachPtr *cur_att = current_attachment(actx, menu);
1018 struct AttachPtrArray aa = ARRAY_HEAD_INITIALIZER;
1019 ARRAY_ADD(&aa, cur_att);
1020 mutt_save_attachment_list(&aa, e, NULL);
1021 ARRAY_FREE(&aa);
1022 op = OP_ATTACH_VIEW;
1023 break;
1024 }
1025 case OP_CHECK_TRADITIONAL:
1027 {
1028 op = OP_NULL;
1029 break;
1030 }
1032
1033 case OP_ATTACH_COLLAPSE:
1034 if (recv)
1035 return op;
1037
1038 default:
1039 op = OP_NULL;
1040 }
1041 } while (op != OP_NULL);
1042
1043 return op;
1044}
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:157
#define ARRAY_FREE(head)
Release all memory.
Definition array.h:209
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition array.h:58
int bool_str_toggle(struct ConfigSubset *sub, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition bool.c:231
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition external.c:1073
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition menu.c:179
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition menu.c:155
@ MENU_REDRAW_INDEX
Redraw the index.
Definition lib.h:61
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition menu.c:169
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition mime.h:37
#define FALLTHROUGH
Definition lib.h:117
int mutt_view_attachment(FILE *fp, struct Body *b, enum ViewAttachMode mode, struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
View an attachment.
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition lib.h:108
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:106
#define WithCrypto
Definition lib.h:132
void mutt_save_attachment_list(struct AttachPtrArray *aa, struct Email *e, struct Menu *menu)
Save a list of selected attachments.
Definition recvattach.c:423
void mutt_pipe_attachment_list(struct AttachPtrArray *aa, bool filter)
Pipe selected attachments to a command.
Definition recvattach.c:697
struct AttachPtr * current_attachment(struct AttachCtx *actx, struct Menu *menu)
Get the current attachment.
Definition recvattach.c:71
void mutt_print_attachment_list(struct AttachPtrArray *aa)
Print selected attachments.
Definition recvattach.c:846
void recvattach_edit_content_type(struct AttachCtx *actx, struct Menu *menu, struct Email *e)
Edit the content type of an attachment.
Definition recvattach.c:887
An email to which things will be attached.
Definition attach.h:36
struct Body * body
Attachment.
Definition attach.h:37
FILE * fp
Used in the recvattach menu.
Definition attach.h:38
The body of an email.
Definition body.h:36
struct Body * parts
parts of a multipart or message/rfc822
Definition body.h:73
struct AttachPtr * aptr
Menu information, used in recvattach.c.
Definition body.h:75
unsigned int type
content-type primary type, ContentType
Definition body.h:40
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition email.h:43
struct MuttWindow * win
Window holding the Menu.
Definition lib.h:94
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_save_attachment_list()

void mutt_save_attachment_list ( struct AttachPtrArray * aa,
struct Email * e,
struct Menu * menu )

Save a list of selected attachments.

Parameters
aaSelected attachments
eParent email
menuMenu listing attachments

Definition at line 423 of file recvattach.c.

424{
425 char *directory = NULL;
426 int rc = 1;
427 int last = menu ? menu_get_index(menu) : 0;
428 FILE *fp_out = NULL;
429 int saved_attachments = 0;
430
431 struct Buffer *buf = buf_pool_get();
432 struct Buffer *tfile = buf_pool_get();
433
434 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
435 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
436 const bool c_attach_save_without_prompting = cs_subset_bool(NeoMutt->sub, "attach_save_without_prompting");
437
438 struct AttachPtr **app = NULL;
439 ARRAY_FOREACH(app, aa)
440 {
441 FILE *fp = (*app)->fp;
442 struct Body *b = (*app)->body;
443
444 /* Iterate through attachments.
445 * Behavior depends on attach_split: if true, save each to its own file;
446 * if false, concatenate all into one file with optional separator. */
447 if (c_attach_split)
448 {
449 if (menu)
450 {
451 menu_set_index(menu, (*app)->num);
453 menu_redraw(menu);
454 }
455 if (c_attach_save_without_prompting)
456 {
457 // Save each file, with no prompting, using the configured 'AttachSaveDir'
458 rc = save_without_prompting(fp, b, e);
459 if (rc == 0)
460 saved_attachments++;
461 }
462 else
463 {
464 // Save each file, prompting the user for the location each time.
465 if (query_save_attachment(fp, b, e, &directory) == -1)
466 break;
467 }
468 }
469 else
470 {
471 enum SaveAttach opt = MUTT_SAVE_NONE;
472
473 if (buf_is_empty(buf))
474 {
476 prepend_savedir(buf);
477
478 struct FileCompletionData cdata = { false, NULL, NULL, NULL, NULL };
479 if ((mw_get_field(_("Save to file: "), buf, MUTT_COMP_CLEAR, HC_FILE,
480 &CompleteFileOps, &cdata) != 0) ||
481 buf_is_empty(buf))
482 {
483 goto cleanup;
484 }
485 expand_path(buf, false);
486 if (mutt_check_overwrite(b->filename, buf_string(buf), tfile, &opt, NULL))
487 goto cleanup;
488 }
489 else
490 {
491 opt = MUTT_SAVE_APPEND;
492 }
493
494 rc = save_attachment_flowed_helper(fp, b, buf_string(tfile), opt, e);
495 if ((rc == 0) && c_attach_sep && (fp_out = mutt_file_fopen(buf_string(tfile), "a")))
496 {
497 fprintf(fp_out, "%s", c_attach_sep);
498 mutt_file_fclose(&fp_out);
499 }
500 }
501 }
502
503 FREE(&directory);
504
505 if ((ARRAY_SIZE(aa) > 1) && menu)
506 {
507 menu_set_index(menu, last);
509 }
510
511 if (rc == 0)
512 {
513 if (!c_attach_split)
514 saved_attachments = 1;
515
516 if (!c_attach_split || c_attach_save_without_prompting)
517 {
518 mutt_message(ngettext("Attachment saved", "%d attachments saved", saved_attachments),
519 saved_attachments);
520 }
521 }
522
523cleanup:
524 buf_pool_release(&buf);
525 buf_pool_release(&tfile);
526}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
#define ARRAY_SIZE(head)
The number of elements stored.
Definition array.h:87
const struct CompleteOps CompleteFileOps
Auto-Completion of Files.
Definition complete.c:152
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:291
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
int menu_redraw(struct Menu *menu)
Redraw the parts of the screen that have been flagged to be redrawn.
Definition draw.c:499
@ MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition wdata.h:47
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition window.c:502
#define mutt_message(...)
Definition logging2.h:93
@ HC_FILE
Files.
Definition lib.h:59
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
@ MENU_REDRAW_MOTION
Redraw after moving the menu list.
Definition lib.h:62
#define _(a)
Definition message.h:28
const char * mutt_path_basename(const char *path)
Find the last component for a pathname.
Definition path.c:282
SaveAttach
Options for saving attachments.
Definition mutt_attach.h:58
void expand_path(struct Buffer *buf, bool regex)
Create the canonical path.
Definition muttlib.c:122
int mutt_check_overwrite(const char *attname, const char *path, struct Buffer *fname, enum SaveAttach *opt, char **directory)
Ask the user if overwriting is necessary.
Definition muttlib.c:524
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
static int save_attachment_flowed_helper(FILE *fp, struct Body *b, const char *path, enum SaveAttach flags, struct Email *e)
Helper for unstuffing attachments.
Definition recvattach.c:226
static int save_without_prompting(FILE *fp, struct Body *b, struct Email *e)
Save the attachment, without prompting each time.
Definition recvattach.c:376
static void prepend_savedir(struct Buffer *buf)
Add $attach_save_dir to the beginning of a path.
Definition recvattach.c:167
static int query_save_attachment(FILE *fp, struct Body *b, struct Email *e, char **directory)
Ask the user if we should save the attachment.
Definition recvattach.c:272
#define NONULL(x)
Definition string2.h:44
char * filename
When sending a message, this is the file to which this structure refers.
Definition body.h:59
String manipulation buffer.
Definition buffer.h:36
Input for the file completion function.
Definition curs_lib.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_pipe_attachment_list()

void mutt_pipe_attachment_list ( struct AttachPtrArray * aa,
bool filter )

Pipe selected attachments to a command.

Parameters
aaSelected attachments
filterIs this command a filter?

Definition at line 697 of file recvattach.c.

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

◆ mutt_print_attachment_list()

void mutt_print_attachment_list ( struct AttachPtrArray * aa)

Print selected attachments.

Parameters
aaSelected attachments

Definition at line 846 of file recvattach.c.

847{
848 char prompt[128] = { 0 };
849 struct State state = { 0 };
850 const int count = ARRAY_SIZE(aa);
851
852 if (count == 0)
853 return;
854
855 snprintf(prompt, sizeof(prompt),
856 ngettext("Print attachment?", "Print %d attachments?", count), count);
857 if (query_quadoption(prompt, NeoMutt->sub, "print") != MUTT_YES)
858 return;
859
860 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
861 if (c_attach_split)
862 {
863 print_attachment_list(aa, &state);
864 }
865 else
866 {
867 if (!can_print(aa))
868 return;
869 mutt_endwin();
870 const char *const c_print_command = cs_subset_string(NeoMutt->sub, "print_command");
871 pid_t pid = filter_create(NONULL(c_print_command), &state.fp_out, NULL,
872 NULL, NeoMutt->env);
873 print_attachment_list(aa, &state);
874 mutt_file_fclose(&state.fp_out);
875 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
876 if ((filter_wait(pid) != 0) || c_wait_key)
878 }
879}
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition quad.h:39
enum QuadOption query_quadoption(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition question.c:384
static void print_attachment_list(struct AttachPtrArray *aa, struct State *state)
Print a list of Attachments.
Definition recvattach.c:782
static bool can_print(struct AttachPtrArray *aa)
Do we know how to print this attachment type?
Definition recvattach.c:750
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_view_attachment()

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

View an attachment.

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

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

Definition at line 418 of file mutt_attach.c.

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

◆ mutt_check_lookup_list()

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

Update the mime type.

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

Definition at line 339 of file mutt_attach.c.

340{
342 ASSERT(mod_data);
343
344 struct ListNode *np = NULL;
345 STAILQ_FOREACH(np, &mod_data->mime_lookup, entries)
346 {
347 const int i = (int) mutt_str_len(np->data) - 1;
348 if (((i > 0) && (np->data[i - 1] == '/') && (np->data[i] == '*') &&
349 mutt_istrn_equal(type, np->data, i)) ||
350 mutt_istr_equal(type, np->data))
351 {
352 struct Body tmp = { 0 };
353 enum ContentType n;
354 if ((n = mutt_lookup_mime_type(&tmp, b->filename)) != TYPE_OTHER ||
356 {
357 snprintf(type, len, "%s/%s",
358 (n == TYPE_AUDIO) ? "audio" :
359 (n == TYPE_APPLICATION) ? "application" :
360 (n == TYPE_IMAGE) ? "image" :
361 (n == TYPE_MESSAGE) ? "message" :
362 (n == TYPE_MODEL) ? "model" :
363 (n == TYPE_MULTIPART) ? "multipart" :
364 (n == TYPE_TEXT) ? "text" :
365 (n == TYPE_VIDEO) ? "video" :
366 "other",
367 tmp.subtype);
368 mutt_debug(LL_DEBUG1, "\"%s\" -> %s\n", b->filename, type);
369 }
370 FREE(&tmp.subtype);
371 FREE(&tmp.xtype);
372 }
373 }
374}
ContentType
Content-Type.
Definition mime.h:30
@ TYPE_AUDIO
Type: 'audio/*'.
Definition mime.h:32
@ TYPE_IMAGE
Type: 'image/*'.
Definition mime.h:34
@ TYPE_OTHER
Unknown Content-Type.
Definition mime.h:31
@ TYPE_MESSAGE
Type: 'message/*'.
Definition mime.h:35
@ TYPE_MODEL
Type: 'model/*'.
Definition mime.h:36
@ TYPE_APPLICATION
Type: 'application/*'.
Definition mime.h:33
@ TYPE_TEXT
Type: 'text/*'.
Definition mime.h:38
@ TYPE_VIDEO
Type: 'video/*'.
Definition mime.h:39
@ MODULE_ID_ATTACH
ModuleAttach, Attachments
Definition module_api.h:49
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:677
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
bool mutt_istrn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings ignoring case (to a maximum), safely.
Definition string.c:457
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:663
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
enum ContentType mutt_lookup_mime_type(struct Body *b, const char *path)
Find the MIME type for an attachment.
Definition sendlib.c:75
#define ASSERT(COND)
Definition signal2.h:59
Attach private Module data.
Definition module_data.h:32
struct ListHead mime_lookup
List of mime types that that shouldn't use the mailcap entry.
Definition module_data.h:42
char * xtype
content-type if x-unknown
Definition body.h:62
A List node for strings.
Definition list.h:37
char * data
String.
Definition list.h:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_compose_attachment()

int mutt_compose_attachment ( struct Body * b)

Create an attachment.

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

Definition at line 116 of file mutt_attach.c.

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

◆ mutt_decode_save_attachment()

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

Decode, then save an attachment.

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

Definition at line 1036 of file mutt_attach.c.

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

◆ mutt_edit_attachment()

bool mutt_edit_attachment ( struct Body * b)

Edit an attachment.

Parameters
bEmail containing attachment
Return values
trueEditor found
falseEditor not found

Currently, this only works for send mode, as it assumes that the Body->filename actually contains the information. I'm not sure we want to deal with editing attachments we've already received, so this should be ok.

Returning 0 is useful to tell the calling menu to redraw

Definition at line 261 of file mutt_attach.c.

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

◆ mutt_get_tmp_attachment()

int mutt_get_tmp_attachment ( struct Body * b)

Get a temporary copy of an attachment.

Parameters
bAttachment to copy
Return values
0Success
-1Error

Definition at line 68 of file mutt_attach.c.

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

◆ mutt_pipe_attachment()

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

Pipe an attachment to a command.

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

Definition at line 737 of file mutt_attach.c.

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

◆ mutt_print_attachment()

int mutt_print_attachment ( FILE * fp,
struct Body * b )

Print out an attachment.

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

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

Definition at line 1134 of file mutt_attach.c.

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

◆ mutt_save_attachment()

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

Save an attachment.

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

Definition at line 903 of file mutt_attach.c.

905{
906 if (!b)
907 return -1;
908
909 if (fp)
910 {
911 /* recv mode */
912
913 if (e && b->email && (b->encoding != ENC_BASE64) &&
915 {
916 /* message type attachments are written to mail folders. */
917
918 char buf[8192] = { 0 };
919 struct Message *msg = NULL;
920 CopyHeaderFlags chflags = CH_NONE;
921 int rc = -1;
922
923 struct Email *e_new = b->email;
924 e_new->msgno = e->msgno; /* required for MH/maildir */
925 e_new->read = true;
926
927 if (!mutt_file_seek(fp, b->offset, SEEK_SET))
928 return -1;
929 if (!fgets(buf, sizeof(buf), fp))
930 return -1;
931 struct Mailbox *m_att = mx_path_resolve(path);
932 if (!mx_mbox_open(m_att, MUTT_APPEND | MUTT_QUIET))
933 {
934 mailbox_free(&m_att);
935 return -1;
936 }
937 msg = mx_msg_open_new(m_att, e_new, is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NONE : MUTT_ADD_FROM);
938 if (!msg)
939 {
940 mx_mbox_close(m_att);
941 return -1;
942 }
943 if ((m_att->type == MUTT_MBOX) || (m_att->type == MUTT_MMDF))
944 chflags = CH_FROM | CH_UPDATE_LEN;
945 chflags |= ((m_att->type == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
946 if ((mutt_copy_message_fp(msg->fp, fp, e_new, MUTT_CM_NONE, chflags, 0) == 0) &&
947 (mx_msg_commit(m_att, msg) == 0))
948 {
949 rc = 0;
950 }
951 else
952 {
953 rc = -1;
954 }
955
956 mx_msg_close(m_att, &msg);
957 mx_mbox_close(m_att);
958 return rc;
959 }
960 else
961 {
962 /* In recv mode, extract from folder and decode */
963
964 struct State state = { 0 };
965
966 state.fp_out = save_attachment_open(path, opt);
967 if (!state.fp_out)
968 {
969 mutt_perror("fopen");
970 return -1;
971 }
972 if (!mutt_file_seek((state.fp_in = fp), b->offset, SEEK_SET))
973 {
974 mutt_file_fclose(&state.fp_out);
975 return -1;
976 }
977 mutt_decode_attachment(b, &state);
978
979 if (mutt_file_fsync_close(&state.fp_out) != 0)
980 {
981 mutt_perror("fclose");
982 return -1;
983 }
984 }
985 }
986 else
987 {
988 if (!b->filename)
989 return -1;
990
991 /* In send mode, just copy file */
992
993 FILE *fp_old = mutt_file_fopen(b->filename, "r");
994 if (!fp_old)
995 {
996 mutt_perror("fopen");
997 return -1;
998 }
999
1000 FILE *fp_new = save_attachment_open(path, opt);
1001 if (!fp_new)
1002 {
1003 mutt_perror("fopen");
1004 mutt_file_fclose(&fp_old);
1005 return -1;
1006 }
1007
1008 if (mutt_file_copy_stream(fp_old, fp_new) == -1)
1009 {
1010 mutt_error(_("Write fault"));
1011 mutt_file_fclose(&fp_old);
1012 mutt_file_fclose(&fp_new);
1013 return -1;
1014 }
1015 mutt_file_fclose(&fp_old);
1016 if (mutt_file_fsync_close(&fp_new) != 0)
1017 {
1018 mutt_error(_("Write fault"));
1019 return -1;
1020 }
1021 }
1022
1023 return 0;
1024}
int mutt_copy_message_fp(FILE *fp_out, FILE *fp_in, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Make a copy of a message from a FILE pointer.
Definition copy_email.c:663
@ MUTT_CM_NONE
No flags are set.
Definition copy_email.h:41
uint32_t CopyHeaderFlags
Definition copy_email.h:89
@ CH_UPDATE
Update the status and x-status fields?
Definition copy_email.h:66
@ CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition copy_email.h:76
@ CH_FROM
Retain the "From " message separator?
Definition copy_email.h:70
@ CH_NOSTATUS
Suppress the status and x-status fields.
Definition copy_email.h:72
@ CH_NONE
No flags are set.
Definition copy_email.h:65
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition mailbox.c:90
@ MUTT_MMDF
'mmdf' Mailbox type
Definition mailbox.h:45
@ MUTT_MBOX
'mbox' Mailbox type
Definition mailbox.h:44
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition mailbox.h:47
bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
Is a string a 'From' header line?
Definition from.c:49
@ ENC_BASE64
Base-64 encoded text.
Definition mime.h:52
@ ENC_QUOTED_PRINTABLE
Quoted-printable text.
Definition mime.h:51
static FILE * save_attachment_open(const char *path, enum SaveAttach opt)
Open a file to write an attachment to.
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition mx.c:1182
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition mx.c:285
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition mx.c:1041
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition mx.c:1161
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition mx.c:1647
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition mx.c:595
@ MUTT_ADD_FROM
add a From_ line
Definition mx.h:43
@ MUTT_MSG_NONE
No flags are set.
Definition mx.h:42
@ MUTT_QUIET
Do not print any messages.
Definition mxapi.h:46
@ MUTT_APPEND
Open mailbox for appending messages.
Definition mxapi.h:44
bool read
Email is read.
Definition email.h:50
int msgno
Number displayed to the user.
Definition email.h:111
A mailbox.
Definition mailbox.h:81
enum MailboxType type
Mailbox type.
Definition mailbox.h:104
A local copy of an email.
Definition message.h:34
FILE * fp
pointer to the message data
Definition message.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_add_temp_attachment()

void mutt_add_temp_attachment ( const char * filename)

Add file to list of temporary attachments.

Parameters
filenamefilename with full path

Definition at line 1294 of file mutt_attach.c.

1295{
1297 ASSERT(mod_data);
1298
1300}
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition list.c:65
struct ListHead temp_attachments
List of temporary files for displaying attachments.
Definition module_data.h:43
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_temp_attachments_cleanup()

void mutt_temp_attachments_cleanup ( struct ListHead * list)

Delete all temporary attachments.

Parameters
listList of temporary attachment files

Definition at line 1306 of file mutt_attach.c.

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