NeoMutt  2025-12-11-435-g4ac674
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
recvattach.c File Reference

Attachment code. More...

#include "config.h"
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "mutt/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "gui/lib.h"
#include "recvattach.h"
#include "browser/lib.h"
#include "editor/lib.h"
#include "history/lib.h"
#include "hooks/lib.h"
#include "menu/lib.h"
#include "ncrypt/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "attach.h"
#include "external.h"
#include "mutt_attach.h"
#include "muttlib.h"
#include <libintl.h>
+ Include dependency graph for recvattach.c:

Go to the source code of this file.

Functions

struct AttachPtrcurrent_attachment (struct AttachCtx *actx, struct Menu *menu)
 Get the current attachment.
 
static void mutt_update_v2r (struct AttachCtx *actx)
 Update the virtual list of attachments.
 
void mutt_update_tree (struct AttachCtx *actx)
 Refresh the list of attachments.
 
static void prepend_savedir (struct Buffer *buf)
 Add $attach_save_dir to the beginning of a path.
 
static bool has_a_message (struct Body *b)
 Determine if the Body has a message (to save)
 
static int save_attachment_flowed_helper (FILE *fp, struct Body *b, const char *path, enum SaveAttach flags, struct Email *e)
 Helper for unstuffing attachments.
 
static int query_save_attachment (FILE *fp, struct Body *b, struct Email *e, char **directory)
 Ask the user if we should save the attachment.
 
static int save_without_prompting (FILE *fp, struct Body *b, struct Email *e)
 Save the attachment, without prompting each time.
 
void mutt_save_attachment_list (struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b, struct Email *e, struct Menu *menu)
 Save a list of attachments.
 
static void query_pipe_attachment (const char *command, FILE *fp, struct Body *b, bool filter)
 Ask the user if we should pipe the attachment.
 
static void pipe_attachment (FILE *fp, struct Body *b, struct State *state)
 Pipe the attachment to a command.
 
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.
 
void mutt_pipe_attachment_list (struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b, bool filter)
 Pipe a list of attachments to a command.
 
static bool can_print (struct AttachCtx *actx, struct Body *b, bool tag)
 Do we know how to print this attachment type?
 
static void print_attachment_list (struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b, struct State *state)
 Print a list of Attachments.
 
void mutt_print_attachment_list (struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b)
 Print a list of Attachments.
 
void recvattach_edit_content_type (struct AttachCtx *actx, struct Menu *menu, struct Email *e)
 Edit the content type of an attachment.
 
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_generate_recvattach_list (struct AttachCtx *actx, struct Email *e, struct Body *b, FILE *fp, int parent_type, int level, bool decrypted)
 Create a list of attachments.
 
void mutt_attach_init (struct AttachCtx *actx)
 Create a new Attachment context.
 
void mutt_update_recvattach_menu (struct AttachCtx *actx, struct Menu *menu, bool init)
 Update the Attachment Menu.
 
int ba_add_tagged (struct BodyArray *ba, struct AttachCtx *actx, struct Menu *menu)
 Get an array of tagged Attachments.
 

Detailed Description

Attachment code.

Authors
  • Anton Rieger
  • Richard Russon
  • Reis Radomil
  • David Harrigan
  • Pietro Cerutti
  • David Purton
  • Dennis Schön
  • Rayford Shireman

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 recvattach.c.

Function Documentation

◆ current_attachment()

struct AttachPtr * current_attachment ( struct AttachCtx * actx,
struct Menu * menu )

Get the current attachment.

Parameters
actxAttachment context
menuMenu
Return values
ptrCurrent Attachment

Definition at line 71 of file recvattach.c.

72{
73 const int virt = menu_get_index(menu);
74 const int index = actx->v2r[virt];
75
76 return actx->idx[index];
77}
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition menu.c:164
struct AttachPtr ** idx
Array of attachments.
Definition attach.h:67
short * v2r
Mapping from virtual to real attachment.
Definition attach.h:71
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_update_v2r()

static void mutt_update_v2r ( struct AttachCtx * actx)
static

Update the virtual list of attachments.

Parameters
actxAttachment context

Update the record of the number of attachments and the status of the tree.

Definition at line 85 of file recvattach.c.

86{
87 int vindex, rindex, curlevel;
88
89 vindex = 0;
90 rindex = 0;
91
92 while (rindex < actx->idxlen)
93 {
94 actx->v2r[vindex++] = rindex;
95 if (actx->idx[rindex]->collapsed)
96 {
97 curlevel = actx->idx[rindex]->level;
98 do
99 {
100 rindex++;
101 } while ((rindex < actx->idxlen) && (actx->idx[rindex]->level > curlevel));
102 }
103 else
104 {
105 rindex++;
106 }
107 }
108
109 actx->vcount = vindex;
110}
short vcount
The number of virtual attachments.
Definition attach.h:72
bool collapsed
Group is collapsed.
Definition attach.h:44
int level
Nesting depth of attachment.
Definition attach.h:40
+ Here is the caller graph for this function:

◆ mutt_update_tree()

void mutt_update_tree ( struct AttachCtx * actx)

Refresh the list of attachments.

Parameters
actxAttachment context

Definition at line 116 of file recvattach.c.

117{
118 char buf[256] = { 0 };
119 char *s = NULL;
120
121 mutt_update_v2r(actx);
122
123 for (int vindex = 0; vindex < actx->vcount; vindex++)
124 {
125 const int rindex = actx->v2r[vindex];
126 actx->idx[rindex]->num = vindex;
127 if ((2 * (actx->idx[rindex]->level + 2)) < sizeof(buf))
128 {
129 if (actx->idx[rindex]->level)
130 {
131 s = buf + 2 * (actx->idx[rindex]->level - 1);
132 *s++ = (actx->idx[rindex]->body->next) ? MUTT_TREE_LTEE : MUTT_TREE_LLCORNER;
133 *s++ = MUTT_TREE_HLINE;
134 *s++ = MUTT_TREE_RARROW;
135 }
136 else
137 {
138 s = buf;
139 }
140 *s = '\0';
141 }
142
143 if (actx->idx[rindex]->tree)
144 {
145 if (!mutt_str_equal(actx->idx[rindex]->tree, buf))
146 mutt_str_replace(&actx->idx[rindex]->tree, buf);
147 }
148 else
149 {
150 actx->idx[rindex]->tree = mutt_str_dup(buf);
151 }
152
153 if (((2 * (actx->idx[rindex]->level + 2)) < sizeof(buf)) &&
154 actx->idx[rindex]->level)
155 {
156 s = buf + 2 * (actx->idx[rindex]->level - 1);
157 *s++ = (actx->idx[rindex]->body->next) ? MUTT_TREE_VLINE : MUTT_TREE_SPACE;
158 *s++ = MUTT_TREE_SPACE;
159 }
160 }
161}
@ MUTT_TREE_LLCORNER
Lower left corner.
Definition thread.h:57
@ MUTT_TREE_RARROW
Right arrow.
Definition thread.h:63
@ MUTT_TREE_LTEE
Left T-piece.
Definition thread.h:59
@ MUTT_TREE_VLINE
Vertical line.
Definition thread.h:61
@ MUTT_TREE_HLINE
Horizontal line.
Definition thread.h:60
@ MUTT_TREE_SPACE
Blank space.
Definition thread.h:62
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:662
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
static void mutt_update_v2r(struct AttachCtx *actx)
Update the virtual list of attachments.
Definition recvattach.c:85
struct Body * body
Attachment.
Definition attach.h:36
char * tree
Tree characters to display.
Definition attach.h:39
int num
Attachment index number.
Definition attach.h:41
struct Body * next
next attachment in the list
Definition body.h:72
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ prepend_savedir()

static void prepend_savedir ( struct Buffer * buf)
static

Add $attach_save_dir to the beginning of a path.

Parameters
bufBuffer for the result

Definition at line 167 of file recvattach.c.

168{
169 if (buf_is_empty(buf) || (buf_at(buf, 0) == '/'))
170 return;
171
172 struct Buffer *tmp = buf_pool_get();
173 const char *const c_attach_save_dir = cs_subset_path(NeoMutt->sub, "attach_save_dir");
174 if (c_attach_save_dir)
175 {
176 buf_addstr(tmp, c_attach_save_dir);
177 if (tmp->dptr[-1] != '/')
178 buf_addch(tmp, '/');
179 }
180 else
181 {
182 buf_addstr(tmp, "./");
183 }
184
185 buf_addstr(tmp, buf_string(buf));
186 buf_copy(buf, tmp);
187 buf_pool_release(&tmp);
188}
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:291
char buf_at(const struct Buffer *buf, size_t offset)
Return the character at the given offset.
Definition buffer.c:668
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:241
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:226
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition buffer.c:601
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_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition helpers.c:168
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
String manipulation buffer.
Definition buffer.h:36
char * dptr
Current read/write position.
Definition buffer.h:38
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:

◆ has_a_message()

static bool has_a_message ( struct Body * b)
static

Determine if the Body has a message (to save)

Parameters
[in]bBody of the message
Return values
trueSuitable for saving

Definition at line 195 of file recvattach.c.

196{
197 return (b->email && (b->encoding != ENC_BASE64) && (b->encoding != ENC_QUOTED_PRINTABLE) &&
199}
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition parse.c:1506
@ ENC_BASE64
Base-64 encoded text.
Definition mime.h:52
@ ENC_QUOTED_PRINTABLE
Quoted-printable text.
Definition mime.h:51
struct Email * email
header information for message/rfc822
Definition body.h:74
char * subtype
content-type subtype
Definition body.h:61
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition body.h:41
unsigned int type
content-type primary type, ContentType
Definition body.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ save_attachment_flowed_helper()

static int save_attachment_flowed_helper ( FILE * fp,
struct Body * b,
const char * path,
enum SaveAttach flags,
struct Email * e )
static

Helper for unstuffing attachments.

Parameters
fpAttachment to work on
bBody of email
pathPath to save the attachment
flagsFlags, e.g. MUTT_SAVE_APPEND
eEmail
Return values
0Success
-1Failure

This is a proxy between the mutt_save_attachment_list() calls and mutt_save_attachment(). It (currently) exists solely to unstuff format=flowed text attachments.

Direct modification of mutt_save_attachment() wasn't easily possible because: 1) other callers of mutt_save_attachment() should not have unstuffing performed, such as replying/forwarding attachments. 2) the attachment saving can append to a file, making the unstuffing inside difficult with current functions. 3) we can't unstuff before-hand because decoding hasn't occurred.

So, I apologize for this horrific proxy, but it was the most straightforward method.

Definition at line 226 of file recvattach.c.

228{
229 int rc = -1;
230
232 {
233 struct Body b_fake = { 0 };
234
235 struct Buffer *tempfile = buf_pool_get();
236 buf_mktemp(tempfile);
237
238 rc = mutt_save_attachment(fp, b, buf_string(tempfile), MUTT_SAVE_NO_FLAGS, e);
239 if (rc != 0)
240 goto cleanup;
241
243
244 /* Now "really" save it. Send mode does this without touching anything,
245 * so force send-mode. */
246 memset(&b_fake, 0, sizeof(struct Body));
247 b_fake.filename = tempfile->data;
248 rc = mutt_save_attachment(NULL, &b_fake, path, flags, e);
249
250 mutt_file_unlink(buf_string(tempfile));
251
252 cleanup:
253 buf_pool_release(&tempfile);
254 }
255 else
256 {
257 rc = mutt_save_attachment(fp, b, path, flags, e);
258 }
259
260 return rc;
261}
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition file.c:156
int mutt_save_attachment(FILE *fp, struct Body *b, const char *path, enum SaveAttach opt, struct Email *e)
Save an attachment.
@ MUTT_SAVE_NO_FLAGS
Overwrite existing file (the default)
Definition mutt_attach.h:58
void mutt_rfc3676_space_unstuff_attachment(struct Body *b, const char *filename)
Unstuff attachments.
Definition rfc3676.c:522
bool mutt_rfc3676_is_format_flowed(struct Body *b)
Is the Email "format-flowed"?
Definition rfc3676.c:398
The body of an email.
Definition body.h:36
char * filename
When sending a message, this is the file to which this structure refers.
Definition body.h:59
char * data
Pointer to data.
Definition buffer.h:37
#define buf_mktemp(buf)
Definition tmp.h:33
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ query_save_attachment()

static int query_save_attachment ( FILE * fp,
struct Body * b,
struct Email * e,
char ** directory )
static

Ask the user if we should save the attachment.

Parameters
[in]fpFile handle to the attachment (OPTIONAL)
[in]bAttachment
[in]eEmail
[out]directoryWhere the attachment was saved
Return values
0Success
-1Failure

Definition at line 272 of file recvattach.c.

273{
274 char *prompt = NULL;
276 int rc = -1;
277
278 struct Buffer *buf = buf_pool_get();
279 struct Buffer *tfile = buf_pool_get();
280
281 if (b->filename)
282 {
283 if (directory && *directory)
284 {
285 buf_concat_path(buf, *directory, mutt_path_basename(b->filename));
286 }
287 else
288 {
289 buf_strcpy(buf, b->filename);
290 }
291 }
292 else if (has_a_message(b))
293 {
294 mutt_default_save(buf, b->email);
295 }
296
297 prepend_savedir(buf);
298
299 prompt = _("Save to file: ");
300 while (prompt)
301 {
302 struct FileCompletionData cdata = { false, NULL, NULL, NULL, NULL };
303 if ((mw_get_field(prompt, buf, MUTT_COMP_CLEAR, HC_FILE, &CompleteFileOps, &cdata) != 0) ||
304 buf_is_empty(buf))
305 {
306 goto cleanup;
307 }
308
309 prompt = NULL;
310 expand_path(buf, false);
311
312 bool is_message = (fp && has_a_message(b));
313
314 if (is_message)
315 {
316 struct stat st = { 0 };
317
318 /* check to make sure that this file is really the one the user wants */
319 rc = mutt_save_confirm(buf_string(buf), &st);
320 if (rc == 1)
321 {
322 prompt = _("Save to file: ");
323 continue;
324 }
325 else if (rc == -1)
326 {
327 goto cleanup;
328 }
329 buf_copy(tfile, buf);
330 }
331 else
332 {
333 rc = mutt_check_overwrite(b->filename, buf_string(buf), tfile, &opt, directory);
334 if (rc == -1)
335 {
336 goto cleanup;
337 }
338 else if (rc == 1)
339 {
340 prompt = _("Save to file: ");
341 continue;
342 }
343 }
344
345 mutt_message(_("Saving..."));
346 if (save_attachment_flowed_helper(fp, b, buf_string(tfile), opt,
347 (e || !is_message) ? e : b->email) == 0)
348 {
349 // This uses ngettext to avoid duplication of messages
350 int num = 1;
351 mutt_message(ngettext("Attachment saved", "%d attachments saved", num), num);
352 rc = 0;
353 goto cleanup;
354 }
355 else
356 {
357 prompt = _("Save to file: ");
358 continue;
359 }
360 }
361
362cleanup:
363 buf_pool_release(&buf);
364 buf_pool_release(&tfile);
365 return rc;
366}
const struct CompleteOps CompleteFileOps
Auto-Completion of Files.
Definition complete.c:152
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition buffer.c:509
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition wdata.h:43
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition window.c:270
#define mutt_message(...)
Definition logging2.h:93
@ HC_FILE
Files.
Definition lib.h:58
void mutt_default_save(struct Buffer *path, struct Email *e)
Find the default save path for an email.
Definition exec.c:214
#define _(a)
Definition message.h:28
const char * mutt_path_basename(const char *path)
Find the last component for a pathname.
Definition path.c:282
SaveAttach
Options for saving attachments.
Definition mutt_attach.h:57
void expand_path(struct Buffer *buf, bool regex)
Create the canonical path.
Definition muttlib.c:121
int mutt_check_overwrite(const char *attname, const char *path, struct Buffer *fname, enum SaveAttach *opt, char **directory)
Ask the user if overwriting is necessary.
Definition muttlib.c:523
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition muttlib.c:689
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 void prepend_savedir(struct Buffer *buf)
Add $attach_save_dir to the beginning of a path.
Definition recvattach.c:167
static bool has_a_message(struct Body *b)
Determine if the Body has a message (to save)
Definition recvattach.c:195
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:

◆ save_without_prompting()

static int save_without_prompting ( FILE * fp,
struct Body * b,
struct Email * e )
static

Save the attachment, without prompting each time.

Parameters
[in]fpFile handle to the attachment (OPTIONAL)
[in]bAttachment
[in]eEmail
Return values
0Success
-1Failure

Definition at line 376 of file recvattach.c.

377{
379 int rc = -1;
380 struct Buffer *buf = buf_pool_get();
381 struct Buffer *tfile = buf_pool_get();
382
383 if (b->filename)
384 {
385 buf_strcpy(buf, b->filename);
386 }
387 else if (has_a_message(b))
388 {
389 mutt_default_save(buf, b->email);
390 }
391
392 prepend_savedir(buf);
393 expand_path(buf, false);
394
395 bool is_message = (fp && has_a_message(b));
396
397 if (is_message)
398 {
399 buf_copy(tfile, buf);
400 }
401 else
402 {
403 rc = mutt_check_overwrite(b->filename, buf_string(buf), tfile, &opt, NULL);
404 if (rc == -1) // abort or cancel
405 goto cleanup;
406 }
407
408 rc = save_attachment_flowed_helper(fp, b, buf_string(tfile), opt,
409 (e || !is_message) ? e : b->email);
410
411cleanup:
412 buf_pool_release(&buf);
413 buf_pool_release(&tfile);
414 return rc;
415}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_save_attachment_list()

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

Save a list of attachments.

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

Definition at line 426 of file recvattach.c.

428{
429 char *directory = NULL;
430 int rc = 1;
431 int last = menu_get_index(menu);
432 FILE *fp_out = NULL;
433 int saved_attachments = 0;
434
435 struct Buffer *buf = buf_pool_get();
436 struct Buffer *tfile = buf_pool_get();
437
438 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
439 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
440 const bool c_attach_save_without_prompting = cs_subset_bool(NeoMutt->sub, "attach_save_without_prompting");
441
442 for (int i = 0; !tag || (i < actx->idxlen); i++)
443 {
444 if (tag)
445 {
446 fp = actx->idx[i]->fp;
447 b = actx->idx[i]->body;
448 }
449 if (!tag || b->tagged)
450 {
451 if (c_attach_split)
452 {
453 if (tag && menu && b->aptr)
454 {
455 menu_set_index(menu, b->aptr->num);
457
458 menu_redraw(menu);
459 }
460 if (c_attach_save_without_prompting)
461 {
462 // Save each file, with no prompting, using the configured 'AttachSaveDir'
463 rc = save_without_prompting(fp, b, e);
464 if (rc == 0)
465 saved_attachments++;
466 }
467 else
468 {
469 // Save each file, prompting the user for the location each time.
470 if (query_save_attachment(fp, b, e, &directory) == -1)
471 break;
472 }
473 }
474 else
475 {
477
478 if (buf_is_empty(buf))
479 {
481 prepend_savedir(buf);
482
483 struct FileCompletionData cdata = { false, NULL, NULL, NULL, NULL };
484 if ((mw_get_field(_("Save to file: "), buf, MUTT_COMP_CLEAR, HC_FILE,
485 &CompleteFileOps, &cdata) != 0) ||
486 buf_is_empty(buf))
487 {
488 goto cleanup;
489 }
490 expand_path(buf, false);
491 if (mutt_check_overwrite(b->filename, buf_string(buf), tfile, &opt, NULL))
492 goto cleanup;
493 }
494 else
495 {
496 opt = MUTT_SAVE_APPEND;
497 }
498
499 rc = save_attachment_flowed_helper(fp, b, buf_string(tfile), opt, e);
500 if ((rc == 0) && c_attach_sep && (fp_out = mutt_file_fopen(buf_string(tfile), "a")))
501 {
502 fprintf(fp_out, "%s", c_attach_sep);
503 mutt_file_fclose(&fp_out);
504 }
505 }
506 }
507 if (!tag)
508 break;
509 }
510
511 FREE(&directory);
512
513 if (tag && menu)
514 {
515 menu_set_index(menu, last);
517 }
518
519 if (rc == 0)
520 {
521 if (!c_attach_split)
522 saved_attachments = 1;
523
524 if (!c_attach_split || c_attach_save_without_prompting)
525 {
526 mutt_message(ngettext("Attachment saved", "%d attachments saved", saved_attachments),
527 saved_attachments);
528 }
529 }
530
531cleanup:
532 buf_pool_release(&buf);
533 buf_pool_release(&tfile);
534}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
int menu_redraw(struct Menu *menu)
Redraw the parts of the screen that have been flagged to be redrawn.
Definition draw.c:482
#define mutt_file_fclose(FP)
Definition file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition menu.c:188
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition menu.c:178
#define MENU_REDRAW_MOTION
Redraw after moving the menu list.
Definition lib.h:58
@ MUTT_SAVE_APPEND
Append to existing file.
Definition mutt_attach.h:59
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 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
short idxlen
Number of attachmentes.
Definition attach.h:68
FILE * fp
Used in the recvattach menu.
Definition attach.h:37
struct AttachPtr * aptr
Menu information, used in recvattach.c.
Definition body.h:75
bool tagged
This attachment is tagged.
Definition body.h:90
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ query_pipe_attachment()

static void query_pipe_attachment ( const char * command,
FILE * fp,
struct Body * b,
bool filter )
static

Ask the user if we should pipe the attachment.

Parameters
commandCommand to pipe the attachment to
fpFile handle to the attachment (OPTIONAL)
bAttachment
filterIs this command a filter?

Definition at line 543 of file recvattach.c.

544{
545 struct Buffer *tfile = buf_pool_get();
546
547 if (filter)
548 {
549 char warning[PATH_MAX + 256];
550 snprintf(warning, sizeof(warning),
551 _("WARNING! You are about to overwrite %s, continue?"), b->filename);
552 if (query_yesorno(warning, MUTT_NO) != MUTT_YES)
553 {
554 msgwin_clear_text(NULL);
555 buf_pool_release(&tfile);
556 return;
557 }
558 buf_mktemp(tfile);
559 }
560
561 if (mutt_pipe_attachment(fp, b, command, buf_string(tfile)))
562 {
563 if (filter)
564 {
568 mutt_message(_("Attachment filtered"));
569 }
570 }
571 else
572 {
573 if (filter && !buf_is_empty(tfile))
575 }
576 buf_pool_release(&tfile);
577}
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition file.c:1261
void msgwin_clear_text(struct MuttWindow *win)
Clear the text in the Message Window.
Definition msgwin.c:518
#define PATH_MAX
Definition mutt.h:49
int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, const char *outfile)
Pipe an attachment to a command.
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition quad.h:38
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition quad.h:39
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition question.c:326
void mutt_update_encoding(struct Body *b, struct ConfigSubset *sub)
Update the encoding type.
Definition sendlib.c:421
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pipe_attachment()

static void pipe_attachment ( FILE * fp,
struct Body * b,
struct State * state )
static

Pipe the attachment to a command.

Parameters
fpFile handle to the attachment (OPTIONAL)
bAttachment
stateFile state for decoding the attachment

Definition at line 585 of file recvattach.c.

586{
587 if (!state || !state->fp_out)
588 return;
589
590 FILE *fp_in = NULL;
591 FILE *fp_unstuff = NULL;
592 bool is_flowed = false, unlink_unstuff = false;
593 struct Buffer *unstuff_tempfile = NULL;
594
596 {
597 is_flowed = true;
598 unstuff_tempfile = buf_pool_get();
599 buf_mktemp(unstuff_tempfile);
600 }
601
602 if (fp)
603 {
604 state->fp_in = fp;
605
606 if (is_flowed)
607 {
608 fp_unstuff = mutt_file_fopen(buf_string(unstuff_tempfile), "w");
609 if (!fp_unstuff)
610 {
611 mutt_perror("mutt_file_fopen");
612 goto bail;
613 }
614 unlink_unstuff = true;
615
616 FILE *filter_fp = state->fp_out;
617 state->fp_out = fp_unstuff;
618 mutt_decode_attachment(b, state);
619 mutt_file_fclose(&fp_unstuff);
620 state->fp_out = filter_fp;
621
622 fp_unstuff = mutt_file_fopen(buf_string(unstuff_tempfile), "r");
623 if (!fp_unstuff)
624 {
625 mutt_perror("mutt_file_fopen");
626 goto bail;
627 }
628 mutt_file_copy_stream(fp_unstuff, filter_fp);
629 mutt_file_fclose(&fp_unstuff);
630 }
631 else
632 {
633 mutt_decode_attachment(b, state);
634 }
635 }
636 else
637 {
638 const char *infile = NULL;
639
640 if (is_flowed)
641 {
642 if (mutt_save_attachment(fp, b, buf_string(unstuff_tempfile), 0, NULL) == -1)
643 goto bail;
644 unlink_unstuff = true;
646 infile = buf_string(unstuff_tempfile);
647 }
648 else
649 {
650 infile = b->filename;
651 }
652
653 fp_in = mutt_file_fopen(infile, "r");
654 if (!fp_in)
655 {
656 mutt_perror("fopen");
657 goto bail;
658 }
659 mutt_file_copy_stream(fp_in, state->fp_out);
660 mutt_file_fclose(&fp_in);
661 }
662
663 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
664 if (c_attach_sep)
665 state_puts(state, c_attach_sep);
666
667bail:
668 mutt_file_fclose(&fp_unstuff);
669 mutt_file_fclose(&fp_in);
670
671 if (unlink_unstuff)
672 mutt_file_unlink(buf_string(unstuff_tempfile));
673 buf_pool_release(&unstuff_tempfile);
674}
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition file.c:222
#define mutt_perror(...)
Definition logging2.h:95
void mutt_decode_attachment(const struct Body *b, struct State *state)
Decode an email's attachment.
Definition handler.c:1933
#define state_puts(STATE, STR)
Definition state.h:58
FILE * fp_out
File to write to.
Definition state.h:50
FILE * fp_in
File to read from.
Definition state.h:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pipe_attachment_list()

static void pipe_attachment_list ( const char * command,
struct AttachCtx * actx,
FILE * fp,
bool tag,
struct Body * top,
bool filter,
struct State * state )
static

Pipe a list of attachments to a command.

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

Definition at line 686 of file recvattach.c.

689{
690 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
691 for (int i = 0; !tag || (i < actx->idxlen); i++)
692 {
693 if (tag)
694 {
695 fp = actx->idx[i]->fp;
696 top = actx->idx[i]->body;
697 }
698 if (!tag || top->tagged)
699 {
700 if (!filter && !c_attach_split)
701 pipe_attachment(fp, top, state);
702 else
703 query_pipe_attachment(command, fp, top, filter);
704 }
705 if (!tag)
706 break;
707 }
708}
static void query_pipe_attachment(const char *command, FILE *fp, struct Body *b, bool filter)
Ask the user if we should pipe the attachment.
Definition recvattach.c:543
static void pipe_attachment(FILE *fp, struct Body *b, struct State *state)
Pipe the attachment to a command.
Definition recvattach.c:585
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_pipe_attachment_list()

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

Pipe a list of attachments to a command.

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

Definition at line 718 of file recvattach.c.

720{
721 struct State state = { 0 };
722 struct Buffer *buf = NULL;
723
724 if (fp)
725 filter = false; /* sanity check: we can't filter in the recv case yet */
726
727 buf = buf_pool_get();
728 /* perform charset conversion on text attachments when piping */
729 state.flags = STATE_CHARCONV;
730
731 if (mw_get_field((filter ? _("Filter through: ") : _("Pipe to: ")), buf,
733 {
734 goto cleanup;
735 }
736
737 if (buf_is_empty(buf))
738 goto cleanup;
739
740 expand_path(buf, false);
741
742 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
743 if (!filter && !c_attach_split)
744 {
745 mutt_endwin();
746 pid_t pid = filter_create(buf_string(buf), &state.fp_out, NULL, NULL,
747 NeoMutt->env);
748 pipe_attachment_list(buf_string(buf), actx, fp, tag, b, filter, &state);
749 mutt_file_fclose(&state.fp_out);
750 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
751 if ((filter_wait(pid) != 0) || c_wait_key)
753 }
754 else
755 {
756 pipe_attachment_list(buf_string(buf), actx, fp, tag, b, filter, &state);
757 }
758
759cleanup:
760 buf_pool_release(&buf);
761}
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition curs_lib.c:173
void mutt_endwin(void)
Shutdown curses.
Definition curs_lib.c:151
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition wdata.h:42
@ HC_EXT_COMMAND
External commands.
Definition lib.h:55
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition filter.c:220
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, char **envlist)
Set up filter program.
Definition filter.c:209
#define STATE_CHARCONV
Do character set conversions.
Definition state.h:37
static void pipe_attachment_list(const char *command, struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, bool filter, struct State *state)
Pipe a list of attachments to a command.
Definition recvattach.c:686
char ** env
Private copy of the environment variables.
Definition neomutt.h:58
Keep track when processing files.
Definition state.h:48
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition state.h:52
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ can_print()

static bool can_print ( struct AttachCtx * actx,
struct Body * b,
bool tag )
static

Do we know how to print this attachment type?

Parameters
actxAttachment
bBody of email
tagApply to all tagged Attachments
Return values
true(all) the Attachment(s) are printable

Definition at line 770 of file recvattach.c.

771{
772 char type[256] = { 0 };
773
774 for (int i = 0; !tag || (i < actx->idxlen); i++)
775 {
776 if (tag)
777 b = actx->idx[i]->body;
778 snprintf(type, sizeof(type), "%s/%s", BODY_TYPE(b), b->subtype);
779 if (!tag || b->tagged)
780 {
781 if (!mailcap_lookup(b, type, sizeof(type), NULL, MUTT_MC_PRINT))
782 {
783 if (!mutt_istr_equal("text/plain", b->subtype) &&
784 !mutt_istr_equal("application/postscript", b->subtype))
785 {
786 if (!mutt_can_decode(b))
787 {
788 /* L10N: s gets replaced by a MIME type, e.g. "text/plain" or
789 application/octet-stream. */
790 mutt_error(_("I don't know how to print %s attachments"), type);
791 return false;
792 }
793 }
794 }
795 }
796 if (!tag)
797 break;
798 }
799 return true;
800}
#define mutt_error(...)
Definition logging2.h:94
bool mutt_can_decode(struct Body *b)
Will decoding the attachment produce any output.
Definition handler.c:1893
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
@ MUTT_MC_PRINT
Mailcap print field.
Definition mailcap.h:60
#define BODY_TYPE(body)
Get the type name of a body part.
Definition mime.h:93
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:674
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ print_attachment_list()

static void print_attachment_list ( struct AttachCtx * actx,
FILE * fp,
bool tag,
struct Body * b,
struct State * state )
static

Print a list of Attachments.

Parameters
actxAttachment context
fpFile handle to the attachment (OPTIONAL)
tagApply to all tagged Attachments
bFirst Attachment
stateFile state for decoding the attachments

Definition at line 810 of file recvattach.c.

812{
813 char type[256] = { 0 };
814
815 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
816 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
817
818 for (int i = 0; !tag || (i < actx->idxlen); i++)
819 {
820 if (tag)
821 {
822 fp = actx->idx[i]->fp;
823 b = actx->idx[i]->body;
824 }
825 if (!tag || b->tagged)
826 {
827 snprintf(type, sizeof(type), "%s/%s", BODY_TYPE(b), b->subtype);
828 if (!c_attach_split && !mailcap_lookup(b, type, sizeof(type), NULL, MUTT_MC_PRINT))
829 {
830 if (mutt_istr_equal("text/plain", b->subtype) ||
831 mutt_istr_equal("application/postscript", b->subtype))
832 {
833 pipe_attachment(fp, b, state);
834 }
835 else if (mutt_can_decode(b))
836 {
837 /* decode and print */
838
839 FILE *fp_in = NULL;
840 struct Buffer *newfile = buf_pool_get();
841
842 buf_mktemp(newfile);
843 if (mutt_decode_save_attachment(fp, b, buf_string(newfile),
845 {
846 if (!state->fp_out)
847 {
848 mutt_error("BUG in print_attachment_list(). Please report this. ");
850 buf_pool_release(&newfile);
851 return;
852 }
853
854 fp_in = mutt_file_fopen(buf_string(newfile), "r");
855 if (fp_in)
856 {
857 mutt_file_copy_stream(fp_in, state->fp_out);
858 mutt_file_fclose(&fp_in);
859 if (c_attach_sep)
860 state_puts(state, c_attach_sep);
861 }
862 }
864 buf_pool_release(&newfile);
865 }
866 }
867 else
868 {
870 }
871 }
872 if (!tag)
873 break;
874 }
875}
#define STATE_PRINTING
Are we printing? - STATE_DISPLAY "light".
Definition state.h:38
int mutt_decode_save_attachment(FILE *fp, struct Body *b, const char *path, StateFlags flags, enum SaveAttach opt)
Decode, then save an attachment.
int mutt_print_attachment(FILE *fp, struct Body *b)
Print out an attachment.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_print_attachment_list()

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

Print a list of Attachments.

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

Definition at line 884 of file recvattach.c.

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

◆ recvattach_edit_content_type()

void recvattach_edit_content_type ( struct AttachCtx * actx,
struct Menu * menu,
struct Email * e )

Edit the content type of an attachment.

Parameters
actxAttachment context
menuMenu listing Attachments
eEmail

Definition at line 929 of file recvattach.c.

930{
931 struct AttachPtr *cur_att = current_attachment(actx, menu);
932 if (!mutt_edit_content_type(e, cur_att->body, cur_att->fp))
933 return;
934
935 /* The mutt_update_recvattach_menu() will overwrite any changes
936 * made to a decrypted cur_att->body, so warn the user. */
937 if (cur_att->decrypted)
938 {
939 mutt_message(_("Structural changes to decrypted attachments are not supported"));
940 mutt_sleep(1);
941 }
942 /* Editing the content type can rewrite the body structure. */
943 for (int i = 0; i < actx->idxlen; i++)
944 actx->idx[i]->body = NULL;
946 mutt_update_recvattach_menu(actx, menu, true);
947}
void mutt_actx_entries_free(struct AttachCtx *actx)
Free entries in an Attachment Context.
Definition attach.c:162
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition external.c:1072
void mutt_sleep(short s)
Sleep for a while.
Definition muttlib.c:786
void mutt_update_recvattach_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
Update the Attachment Menu.
struct AttachPtr * current_attachment(struct AttachCtx *actx, struct Menu *menu)
Get the current attachment.
Definition recvattach.c:71
An email to which things will be attached.
Definition attach.h:35
bool decrypted
Not part of message as stored in the email->body.
Definition attach.h:43
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_attach_display_loop()

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

Event loop for the Attachment menu.

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

Definition at line 959 of file recvattach.c.

961{
962 do
963 {
964 switch (op)
965 {
966 case OP_DISPLAY_HEADERS:
967 bool_str_toggle(NeoMutt->sub, "weed", NULL);
969
970 case OP_ATTACHMENT_VIEW:
971 {
972 struct AttachPtr *cur_att = current_attachment(actx, menu);
973 if (!cur_att->fp)
974 {
975 if (cur_att->body->type == TYPE_MULTIPART)
976 {
977 struct Body *b = cur_att->body->parts;
978 while (b && b->parts)
979 b = b->parts;
980 if (b)
981 cur_att = b->aptr;
982 }
983 }
984 op = mutt_view_attachment(cur_att->fp, cur_att->body, MUTT_VA_REGULAR,
985 e, actx, menu->win);
986 break;
987 }
988
989 case OP_NEXT_ENTRY:
990 case OP_MAIN_NEXT_UNDELETED: /* hack */
991 {
992 const int index = menu_get_index(menu) + 1;
993 if (index < menu->max)
994 {
995 menu_set_index(menu, index);
996 op = OP_ATTACHMENT_VIEW;
997 }
998 else
999 {
1000 op = OP_NULL;
1001 }
1002 break;
1003 }
1004
1005 case OP_PREV_ENTRY:
1006 case OP_MAIN_PREV_UNDELETED: /* hack */
1007 {
1008 const int index = menu_get_index(menu) - 1;
1009 if (index >= 0)
1010 {
1011 menu_set_index(menu, index);
1012 op = OP_ATTACHMENT_VIEW;
1013 }
1014 else
1015 {
1016 op = OP_NULL;
1017 }
1018 break;
1019 }
1020
1021 case OP_ATTACHMENT_EDIT_TYPE:
1022 {
1023 struct AttachPtr *cur_att = current_attachment(actx, menu);
1024 /* when we edit the content-type, we should redisplay the attachment
1025 * immediately */
1026 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1027 if (recv)
1028 recvattach_edit_content_type(actx, menu, e);
1029 else
1030 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1031
1033 op = OP_ATTACHMENT_VIEW;
1034 break;
1035 }
1036 /* functions which are passed through from the pager */
1037 case OP_PIPE:
1038 {
1039 struct AttachPtr *cur_att = current_attachment(actx, menu);
1040 mutt_pipe_attachment_list(actx, cur_att->fp, false, cur_att->body, false);
1041 op = OP_ATTACHMENT_VIEW;
1042 break;
1043 }
1044 case OP_ATTACHMENT_PRINT:
1045 {
1046 struct AttachPtr *cur_att = current_attachment(actx, menu);
1047 mutt_print_attachment_list(actx, cur_att->fp, false, cur_att->body);
1048 op = OP_ATTACHMENT_VIEW;
1049 break;
1050 }
1051 case OP_ATTACHMENT_SAVE:
1052 {
1053 struct AttachPtr *cur_att = current_attachment(actx, menu);
1054 mutt_save_attachment_list(actx, cur_att->fp, false, cur_att->body, e, NULL);
1055 op = OP_ATTACHMENT_VIEW;
1056 break;
1057 }
1058 case OP_CHECK_TRADITIONAL:
1060 {
1061 op = OP_NULL;
1062 break;
1063 }
1065
1066 case OP_ATTACHMENT_COLLAPSE:
1067 if (recv)
1068 return op;
1070
1071 default:
1072 op = OP_NULL;
1073 }
1074 } while (op != OP_NULL);
1075
1076 return op;
1077}
int bool_str_toggle(struct ConfigSubset *sub, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition bool.c:229
#define MENU_REDRAW_INDEX
Redraw the index.
Definition lib.h:57
@ 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.
@ MUTT_VA_REGULAR
View using default method.
Definition mutt_attach.h:44
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition lib.h:100
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:98
#define WithCrypto
Definition lib.h:124
void mutt_save_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b, struct Email *e, struct Menu *menu)
Save a list of attachments.
Definition recvattach.c:426
void mutt_pipe_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b, bool filter)
Pipe a list of attachments to a command.
Definition recvattach.c:718
void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b)
Print a list of Attachments.
Definition recvattach.c:884
void recvattach_edit_content_type(struct AttachCtx *actx, struct Menu *menu, struct Email *e)
Edit the content type of an attachment.
Definition recvattach.c:929
struct Body * parts
parts of a multipart or message/rfc822
Definition body.h:73
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition email.h:43
struct MuttWindow * win
Window holding the Menu.
Definition lib.h:88
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_generate_recvattach_list()

void mutt_generate_recvattach_list ( struct AttachCtx * actx,
struct Email * e,
struct Body * b,
FILE * fp,
int parent_type,
int level,
bool decrypted )

Create a list of attachments.

Parameters
actxAttachment context
eEmail
bBody of email
fpFile to read from
parent_typeType, e.g. TYPE_MULTIPART
levelAttachment depth
decryptedTrue if attachment has been decrypted

Definition at line 1089 of file recvattach.c.

1092{
1093 struct Body *bp = NULL;
1094 struct Body *new_body = NULL;
1095 FILE *fp_new = NULL;
1097
1098 for (bp = b; bp; bp = bp->next)
1099 {
1100 bool need_secured = false;
1101 bool secured = false;
1102
1104 {
1105 need_secured = true;
1106
1107 if (type & SEC_ENCRYPT)
1108 {
1110 goto decrypt_failed;
1111
1112 if (e->env)
1114 }
1115
1116 secured = (crypt_smime_decrypt_mime(fp, &fp_new, bp, &new_body) == 0);
1117 /* If the decrypt/verify-opaque doesn't generate mime output, an empty
1118 * text/plain type will still be returned by mutt_read_mime_header().
1119 * We can't distinguish an actual part from a failure, so only use a
1120 * text/plain that results from a single top-level part. */
1121 if (secured && (new_body->type == TYPE_TEXT) &&
1122 mutt_istr_equal("plain", new_body->subtype) && ((b != bp) || bp->next))
1123 {
1124 mutt_body_free(&new_body);
1125 mutt_file_fclose(&fp_new);
1126 goto decrypt_failed;
1127 }
1128
1129 if (secured && (type & SEC_ENCRYPT))
1130 e->security |= SMIME_ENCRYPT;
1131 }
1132
1133 if (((WithCrypto & APPLICATION_PGP) != 0) &&
1135 {
1136 need_secured = true;
1137
1139 goto decrypt_failed;
1140
1141 secured = (crypt_pgp_decrypt_mime(fp, &fp_new, bp, &new_body) == 0);
1142
1143 if (secured)
1144 e->security |= PGP_ENCRYPT;
1145 }
1146
1147 if (need_secured && secured)
1148 {
1149 mutt_actx_add_fp(actx, fp_new);
1150 mutt_actx_add_body(actx, new_body);
1151 mutt_generate_recvattach_list(actx, e, new_body, fp_new, parent_type, level, 1);
1152 continue;
1153 }
1154
1155 decrypt_failed:
1156 /* Fall through and show the original parts if decryption fails */
1157 if (need_secured && !secured)
1158 mutt_error(_("Can't decrypt encrypted message"));
1159
1160 struct AttachPtr *ap = mutt_aptr_new();
1161 mutt_actx_add_attach(actx, ap);
1162
1163 ap->body = bp;
1164 ap->fp = fp;
1165 bp->aptr = ap;
1167 ap->level = level;
1168 ap->decrypted = decrypted;
1169
1170 if (mutt_is_message_type(bp->type, bp->subtype))
1171 {
1172 mutt_generate_recvattach_list(actx, bp->email, bp->parts, fp, bp->type,
1173 level + 1, decrypted);
1174 e->security |= bp->email->security;
1175 }
1176 else
1177 {
1178 mutt_generate_recvattach_list(actx, e, bp->parts, fp, bp->type, level + 1, decrypted);
1179 }
1180 }
1181}
void mutt_actx_add_attach(struct AttachCtx *actx, struct AttachPtr *attach)
Add an Attachment to an Attachment Context.
Definition attach.c:65
void mutt_actx_add_fp(struct AttachCtx *actx, FILE *fp_new)
Save a File handle to the Attachment Context.
Definition attach.c:121
struct AttachPtr * mutt_aptr_new(void)
Create a new Attachment Pointer.
Definition attach.c:40
void mutt_actx_add_body(struct AttachCtx *actx, struct Body *b)
Add an email body to an Attachment Context.
Definition attach.c:142
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition crypt.c:609
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition crypt.c:131
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition crypt.c:443
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition crypt.c:504
int crypt_pgp_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **b_dec)
Wrapper for CryptModuleSpecs::decrypt_mime()
Definition cryptglue.c:210
void crypt_smime_getkeys(struct Envelope *env)
Wrapper for CryptModuleSpecs::smime_getkeys()
Definition cryptglue.c:454
int crypt_smime_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **b_dec)
Wrapper for CryptModuleSpecs::decrypt_mime()
Definition cryptglue.c:432
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition body.c:58
@ TYPE_TEXT
Type: 'text/*'.
Definition mime.h:38
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition lib.h:84
#define PGP_ENCRYPT
Email is PGP encrypted.
Definition lib.h:104
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:99
#define SEC_ENCRYPT
Email is encrypted.
Definition lib.h:86
#define SMIME_ENCRYPT
Email is S/MIME encrypted.
Definition lib.h:110
void mutt_generate_recvattach_list(struct AttachCtx *actx, struct Email *e, struct Body *b, FILE *fp, int parent_type, int level, bool decrypted)
Create a list of attachments.
int parent_type
Type of parent attachment, e.g. TYPE_MULTIPART.
Definition attach.h:38
struct Envelope * env
Envelope information.
Definition email.h:68
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_attach_init()

void mutt_attach_init ( struct AttachCtx * actx)

Create a new Attachment context.

Parameters
actxAttachment context

Definition at line 1187 of file recvattach.c.

1188{
1189 /* Collapse the attachments if '$digest_collapse' is set AND if...
1190 * the outer container is of type 'multipart/digest' */
1191 bool digest = mutt_istr_equal(actx->email->body->subtype, "digest");
1192
1193 const bool c_digest_collapse = cs_subset_bool(NeoMutt->sub, "digest_collapse");
1194 for (int i = 0; i < actx->idxlen; i++)
1195 {
1196 actx->idx[i]->body->tagged = false;
1197
1198 /* OR an inner container is of type 'multipart/digest' */
1199 actx->idx[i]->collapsed = (c_digest_collapse &&
1200 (digest ||
1201 ((actx->idx[i]->body->type == TYPE_MULTIPART) &&
1202 mutt_istr_equal(actx->idx[i]->body->subtype, "digest"))));
1203 }
1204}
struct Email * email
Used by recvattach for updating.
Definition attach.h:64
struct Body * body
List of MIME parts.
Definition email.h:69
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_update_recvattach_menu()

void mutt_update_recvattach_menu ( struct AttachCtx * actx,
struct Menu * menu,
bool init )

Update the Attachment Menu.

Parameters
actxAttachment context
menuMenu listing Attachments
initIf true, create a new Attachments context

Definition at line 1212 of file recvattach.c.

1213{
1214 if (init)
1215 {
1216 mutt_generate_recvattach_list(actx, actx->email, actx->email->body,
1217 actx->fp_root, -1, 0, 0);
1218 mutt_attach_init(actx);
1219 }
1220
1221 mutt_update_tree(actx);
1222
1223 menu->max = actx->vcount;
1224
1225 const int index = menu_get_index(menu);
1226 if (index >= menu->max)
1227 menu_set_index(menu, menu->max - 1);
1229}
void mutt_attach_init(struct AttachCtx *actx)
Create a new Attachment context.
void mutt_update_tree(struct AttachCtx *actx)
Refresh the list of attachments.
Definition recvattach.c:116
FILE * fp_root
Used by recvattach for updating.
Definition attach.h:65
int max
Number of entries in the menu.
Definition lib.h:82
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ ba_add_tagged()

int ba_add_tagged ( struct BodyArray * ba,
struct AttachCtx * actx,
struct Menu * menu )

Get an array of tagged Attachments.

Parameters
baEmpty BodyArray to populate
actxList of Attachments
menuMenu
Return values
numNumber of selected Attachments
-1Error

Definition at line 1239 of file recvattach.c.

1240{
1241 if (!ba || !actx || !menu)
1242 return -1;
1243
1244 if (menu->tag_prefix)
1245 {
1246 for (int i = 0; i < actx->idxlen; i++)
1247 {
1248 struct Body *b = actx->idx[i]->body;
1249 if (b->tagged)
1250 {
1251 ARRAY_ADD(ba, b);
1252 }
1253 }
1254 }
1255 else
1256 {
1257 struct AttachPtr *cur = current_attachment(actx, menu);
1258 if (!cur)
1259 return -1;
1260
1261 ARRAY_ADD(ba, cur->body);
1262 }
1263
1264 return ARRAY_SIZE(ba);
1265}
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:157
#define ARRAY_SIZE(head)
The number of elements stored.
Definition array.h:87
bool tag_prefix
User has pressed <tag-prefix>
Definition lib.h:86
+ Here is the call graph for this function:
+ Here is the caller graph for this function: