NeoMutt  2025-12-11-694-ga89709
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:665
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:463
#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: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
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition muttlib.c:690
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 /* Iterate through attachments (or just the single one if not tagging).
443 * Behavior depends on attach_split: if true, save each to its own file;
444 * if false, concatenate all into one file with optional separator. */
445 for (int i = 0; !tag || (i < actx->idxlen); i++)
446 {
447 if (tag)
448 {
449 fp = actx->idx[i]->fp;
450 b = actx->idx[i]->body;
451 }
452 if (!tag || b->tagged)
453 {
454 if (c_attach_split)
455 {
456 if (tag && menu && b->aptr)
457 {
458 menu_set_index(menu, b->aptr->num);
460
461 menu_redraw(menu);
462 }
463 if (c_attach_save_without_prompting)
464 {
465 // Save each file, with no prompting, using the configured 'AttachSaveDir'
466 rc = save_without_prompting(fp, b, e);
467 if (rc == 0)
468 saved_attachments++;
469 }
470 else
471 {
472 // Save each file, prompting the user for the location each time.
473 if (query_save_attachment(fp, b, e, &directory) == -1)
474 break;
475 }
476 }
477 else
478 {
480
481 if (buf_is_empty(buf))
482 {
484 prepend_savedir(buf);
485
486 struct FileCompletionData cdata = { false, NULL, NULL, NULL, NULL };
487 if ((mw_get_field(_("Save to file: "), buf, MUTT_COMP_CLEAR, HC_FILE,
488 &CompleteFileOps, &cdata) != 0) ||
489 buf_is_empty(buf))
490 {
491 goto cleanup;
492 }
493 expand_path(buf, false);
494 if (mutt_check_overwrite(b->filename, buf_string(buf), tfile, &opt, NULL))
495 goto cleanup;
496 }
497 else
498 {
499 opt = MUTT_SAVE_APPEND;
500 }
501
502 rc = save_attachment_flowed_helper(fp, b, buf_string(tfile), opt, e);
503 if ((rc == 0) && c_attach_sep && (fp_out = mutt_file_fopen(buf_string(tfile), "a")))
504 {
505 fprintf(fp_out, "%s", c_attach_sep);
506 mutt_file_fclose(&fp_out);
507 }
508 }
509 }
510 if (!tag)
511 break;
512 }
513
514 FREE(&directory);
515
516 if (tag && menu)
517 {
518 menu_set_index(menu, last);
520 }
521
522 if (rc == 0)
523 {
524 if (!c_attach_split)
525 saved_attachments = 1;
526
527 if (!c_attach_split || c_attach_save_without_prompting)
528 {
529 mutt_message(ngettext("Attachment saved", "%d attachments saved", saved_attachments),
530 saved_attachments);
531 }
532 }
533
534cleanup:
535 buf_pool_release(&buf);
536 buf_pool_release(&tfile);
537}
const 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
#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 546 of file recvattach.c.

547{
548 struct Buffer *tfile = buf_pool_get();
549
550 if (filter)
551 {
552 char warning[PATH_MAX + 256];
553 snprintf(warning, sizeof(warning),
554 _("WARNING! You are about to overwrite %s, continue?"), b->filename);
555 if (query_yesorno(warning, MUTT_NO) != MUTT_YES)
556 {
557 msgwin_clear_text(NULL);
558 buf_pool_release(&tfile);
559 return;
560 }
561 buf_mktemp(tfile);
562 }
563
564 if (mutt_pipe_attachment(fp, b, command, buf_string(tfile)))
565 {
566 if (filter)
567 {
571 mutt_message(_("Attachment filtered"));
572 }
573 }
574 else
575 {
576 if (filter && !buf_is_empty(tfile))
578 }
579 buf_pool_release(&tfile);
580}
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition file.c:1257
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:329
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 588 of file recvattach.c.

589{
590 if (!state || !state->fp_out)
591 return;
592
593 FILE *fp_in = NULL;
594 FILE *fp_unstuff = NULL;
595 bool is_flowed = false, unlink_unstuff = false;
596 struct Buffer *unstuff_tempfile = NULL;
597
599 {
600 is_flowed = true;
601 unstuff_tempfile = buf_pool_get();
602 buf_mktemp(unstuff_tempfile);
603 }
604
605 if (fp)
606 {
607 state->fp_in = fp;
608
609 if (is_flowed)
610 {
611 fp_unstuff = mutt_file_fopen(buf_string(unstuff_tempfile), "w");
612 if (!fp_unstuff)
613 {
614 mutt_perror("mutt_file_fopen");
615 goto bail;
616 }
617 unlink_unstuff = true;
618
619 FILE *filter_fp = state->fp_out;
620 state->fp_out = fp_unstuff;
621 mutt_decode_attachment(b, state);
622 mutt_file_fclose(&fp_unstuff);
623 state->fp_out = filter_fp;
624
625 fp_unstuff = mutt_file_fopen(buf_string(unstuff_tempfile), "r");
626 if (!fp_unstuff)
627 {
628 mutt_perror("mutt_file_fopen");
629 goto bail;
630 }
631 mutt_file_copy_stream(fp_unstuff, filter_fp);
632 mutt_file_fclose(&fp_unstuff);
633 }
634 else
635 {
636 mutt_decode_attachment(b, state);
637 }
638 }
639 else
640 {
641 const char *infile = NULL;
642
643 if (is_flowed)
644 {
645 if (mutt_save_attachment(fp, b, buf_string(unstuff_tempfile), 0, NULL) == -1)
646 goto bail;
647 unlink_unstuff = true;
649 infile = buf_string(unstuff_tempfile);
650 }
651 else
652 {
653 infile = b->filename;
654 }
655
656 fp_in = mutt_file_fopen(infile, "r");
657 if (!fp_in)
658 {
659 mutt_perror("fopen");
660 goto bail;
661 }
662 mutt_file_copy_stream(fp_in, state->fp_out);
663 mutt_file_fclose(&fp_in);
664 }
665
666 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
667 if (c_attach_sep)
668 state_puts(state, c_attach_sep);
669
670bail:
671 mutt_file_fclose(&fp_unstuff);
672 mutt_file_fclose(&fp_in);
673
674 if (unlink_unstuff)
675 mutt_file_unlink(buf_string(unstuff_tempfile));
676 buf_pool_release(&unstuff_tempfile);
677}
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition file.c:224
#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
#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 689 of file recvattach.c.

692{
693 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
694 for (int i = 0; !tag || (i < actx->idxlen); i++)
695 {
696 if (tag)
697 {
698 fp = actx->idx[i]->fp;
699 top = actx->idx[i]->body;
700 }
701 if (!tag || top->tagged)
702 {
703 if (!filter && !c_attach_split)
704 pipe_attachment(fp, top, state);
705 else
706 query_pipe_attachment(command, fp, top, filter);
707 }
708 if (!tag)
709 break;
710 }
711}
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:546
static void pipe_attachment(FILE *fp, struct Body *b, struct State *state)
Pipe the attachment to a command.
Definition recvattach.c:588
+ 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 721 of file recvattach.c.

723{
724 struct State state = { 0 };
725 struct Buffer *buf = NULL;
726
727 if (fp)
728 filter = false; /* sanity check: we can't filter in the recv case yet */
729
730 buf = buf_pool_get();
731 /* perform charset conversion on text attachments when piping */
732 state.flags = STATE_CHARCONV;
733
734 if (mw_get_field((filter ? _("Filter through: ") : _("Pipe to: ")), buf,
736 {
737 goto cleanup;
738 }
739
740 if (buf_is_empty(buf))
741 goto cleanup;
742
743 expand_path(buf, false);
744
745 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
746 if (!filter && !c_attach_split)
747 {
748 mutt_endwin();
749 pid_t pid = filter_create(buf_string(buf), &state.fp_out, NULL, NULL,
750 NeoMutt->env);
751 pipe_attachment_list(buf_string(buf), actx, fp, tag, b, filter, &state);
752 mutt_file_fclose(&state.fp_out);
753 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
754 if ((filter_wait(pid) != 0) || c_wait_key)
756 }
757 else
758 {
759 pipe_attachment_list(buf_string(buf), actx, fp, tag, b, filter, &state);
760 }
761
762cleanup:
763 buf_pool_release(&buf);
764}
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: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
#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:689
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 773 of file recvattach.c.

774{
775 char type[256] = { 0 };
776
777 for (int i = 0; !tag || (i < actx->idxlen); i++)
778 {
779 if (tag)
780 b = actx->idx[i]->body;
781 snprintf(type, sizeof(type), "%s/%s", BODY_TYPE(b), b->subtype);
782 if (!tag || b->tagged)
783 {
784 if (!mailcap_lookup(b, type, sizeof(type), NULL, MUTT_MC_PRINT))
785 {
786 if (!mutt_istr_equal("text/plain", b->subtype) &&
787 !mutt_istr_equal("application/postscript", b->subtype))
788 {
789 if (!mutt_can_decode(b))
790 {
791 /* L10N: s gets replaced by a MIME type, e.g. "text/plain" or
792 application/octet-stream. */
793 mutt_error(_("I don't know how to print %s attachments"), type);
794 return false;
795 }
796 }
797 }
798 }
799 if (!tag)
800 break;
801 }
802 return true;
803}
#define mutt_error(...)
Definition logging2.h:94
bool mutt_can_decode(struct Body *b)
Will decoding the attachment produce any output.
Definition handler.c:1898
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:677
+ 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 813 of file recvattach.c.

815{
816 char type[256] = { 0 };
817
818 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
819 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
820
821 for (int i = 0; !tag || (i < actx->idxlen); i++)
822 {
823 if (tag)
824 {
825 fp = actx->idx[i]->fp;
826 b = actx->idx[i]->body;
827 }
828 if (!tag || b->tagged)
829 {
830 snprintf(type, sizeof(type), "%s/%s", BODY_TYPE(b), b->subtype);
831 if (!c_attach_split && !mailcap_lookup(b, type, sizeof(type), NULL, MUTT_MC_PRINT))
832 {
833 if (mutt_istr_equal("text/plain", b->subtype) ||
834 mutt_istr_equal("application/postscript", b->subtype))
835 {
836 pipe_attachment(fp, b, state);
837 }
838 else if (mutt_can_decode(b))
839 {
840 /* decode and print */
841
842 FILE *fp_in = NULL;
843 struct Buffer *newfile = buf_pool_get();
844
845 buf_mktemp(newfile);
846 if (mutt_decode_save_attachment(fp, b, buf_string(newfile),
848 {
849 if (!state->fp_out)
850 {
851 mutt_error("BUG in print_attachment_list(). Please report this. ");
853 buf_pool_release(&newfile);
854 return;
855 }
856
857 fp_in = mutt_file_fopen(buf_string(newfile), "r");
858 if (fp_in)
859 {
860 mutt_file_copy_stream(fp_in, state->fp_out);
861 mutt_file_fclose(&fp_in);
862 if (c_attach_sep)
863 state_puts(state, c_attach_sep);
864 }
865 }
867 buf_pool_release(&newfile);
868 }
869 }
870 else
871 {
873 }
874 }
875 if (!tag)
876 break;
877 }
878}
#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 887 of file recvattach.c.

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

933{
934 struct AttachPtr *cur_att = current_attachment(actx, menu);
935 if (!mutt_edit_content_type(e, cur_att->body, cur_att->fp))
936 return;
937
938 /* The mutt_update_recvattach_menu() will overwrite any changes
939 * made to a decrypted cur_att->body, so warn the user. */
940 if (cur_att->decrypted)
941 {
942 mutt_message(_("Structural changes to decrypted attachments are not supported"));
943 mutt_sleep(1);
944 }
945 /* Editing the content type can rewrite the body structure. */
946 for (int i = 0; i < actx->idxlen; i++)
947 actx->idx[i]->body = NULL;
949 mutt_update_recvattach_menu(actx, menu, true);
950}
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:787
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_ATTACH_VIEW
eEmail
actxAttachment context
recvtrue if these are received attachments (rather than in compose)
Return values
numOperation performed

Definition at line 962 of file recvattach.c.

964{
965 do
966 {
967 switch (op)
968 {
969 case OP_DISPLAY_HEADERS:
970 bool_str_toggle(NeoMutt->sub, "weed", NULL);
972
973 case OP_ATTACH_VIEW:
974 {
975 struct AttachPtr *cur_att = current_attachment(actx, menu);
976 if (!cur_att->fp)
977 {
978 if (cur_att->body->type == TYPE_MULTIPART)
979 {
980 struct Body *b = cur_att->body->parts;
981 while (b && b->parts)
982 b = b->parts;
983 if (b)
984 cur_att = b->aptr;
985 }
986 }
987 op = mutt_view_attachment(cur_att->fp, cur_att->body, MUTT_VA_REGULAR,
988 e, actx, menu->win);
989 break;
990 }
991
992 case OP_NEXT_ENTRY:
993 case OP_MAIN_NEXT_UNDELETED: /* hack */
994 {
995 const int index = menu_get_index(menu) + 1;
996 if (index < menu->max)
997 {
998 menu_set_index(menu, index);
999 op = OP_ATTACH_VIEW;
1000 }
1001 else
1002 {
1003 op = OP_NULL;
1004 }
1005 break;
1006 }
1007
1008 case OP_PREV_ENTRY:
1009 case OP_MAIN_PREV_UNDELETED: /* hack */
1010 {
1011 const int index = menu_get_index(menu) - 1;
1012 if (index >= 0)
1013 {
1014 menu_set_index(menu, index);
1015 op = OP_ATTACH_VIEW;
1016 }
1017 else
1018 {
1019 op = OP_NULL;
1020 }
1021 break;
1022 }
1023
1024 case OP_ATTACH_EDIT_TYPE:
1025 {
1026 struct AttachPtr *cur_att = current_attachment(actx, menu);
1027 /* when we edit the content-type, we should redisplay the attachment
1028 * immediately */
1029 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1030 if (recv)
1031 recvattach_edit_content_type(actx, menu, e);
1032 else
1033 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1034
1036 op = OP_ATTACH_VIEW;
1037 break;
1038 }
1039 /* functions which are passed through from the pager */
1040 case OP_PIPE:
1041 {
1042 struct AttachPtr *cur_att = current_attachment(actx, menu);
1043 mutt_pipe_attachment_list(actx, cur_att->fp, false, cur_att->body, false);
1044 op = OP_ATTACH_VIEW;
1045 break;
1046 }
1047 case OP_ATTACH_PRINT:
1048 {
1049 struct AttachPtr *cur_att = current_attachment(actx, menu);
1050 mutt_print_attachment_list(actx, cur_att->fp, false, cur_att->body);
1051 op = OP_ATTACH_VIEW;
1052 break;
1053 }
1054 case OP_ATTACH_SAVE:
1055 {
1056 struct AttachPtr *cur_att = current_attachment(actx, menu);
1057 mutt_save_attachment_list(actx, cur_att->fp, false, cur_att->body, e, NULL);
1058 op = OP_ATTACH_VIEW;
1059 break;
1060 }
1061 case OP_CHECK_TRADITIONAL:
1063 {
1064 op = OP_NULL;
1065 break;
1066 }
1068
1069 case OP_ATTACH_COLLAPSE:
1070 if (recv)
1071 return op;
1073
1074 default:
1075 op = OP_NULL;
1076 }
1077 } while (op != OP_NULL);
1078
1079 return op;
1080}
int bool_str_toggle(struct ConfigSubset *sub, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition bool.c:231
#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:721
void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b)
Print a list of Attachments.
Definition recvattach.c:887
void recvattach_edit_content_type(struct AttachCtx *actx, struct Menu *menu, struct Email *e)
Edit the content type of an attachment.
Definition recvattach.c:932
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 1092 of file recvattach.c.

1095{
1096 struct Body *bp = NULL;
1097 struct Body *new_body = NULL;
1098 FILE *fp_new = NULL;
1100
1101 for (bp = b; bp; bp = bp->next)
1102 {
1103 bool need_secured = false;
1104 bool secured = false;
1105
1107 {
1108 need_secured = true;
1109
1110 if (type & SEC_ENCRYPT)
1111 {
1113 goto decrypt_failed;
1114
1115 if (e->env)
1117 }
1118
1119 secured = (crypt_smime_decrypt_mime(fp, &fp_new, bp, &new_body) == 0);
1120 /* If the decrypt/verify-opaque doesn't generate mime output, an empty
1121 * text/plain type will still be returned by mutt_read_mime_header().
1122 * We can't distinguish an actual part from a failure, so only use a
1123 * text/plain that results from a single top-level part. */
1124 if (secured && (new_body->type == TYPE_TEXT) &&
1125 mutt_istr_equal("plain", new_body->subtype) && ((b != bp) || bp->next))
1126 {
1127 mutt_body_free(&new_body);
1128 mutt_file_fclose(&fp_new);
1129 goto decrypt_failed;
1130 }
1131
1132 if (secured && (type & SEC_ENCRYPT))
1133 e->security |= SMIME_ENCRYPT;
1134 }
1135
1136 if (((WithCrypto & APPLICATION_PGP) != 0) &&
1138 {
1139 need_secured = true;
1140
1142 goto decrypt_failed;
1143
1144 secured = (crypt_pgp_decrypt_mime(fp, &fp_new, bp, &new_body) == 0);
1145
1146 if (secured)
1147 e->security |= PGP_ENCRYPT;
1148 }
1149
1150 if (need_secured && secured)
1151 {
1152 mutt_actx_add_fp(actx, fp_new);
1153 mutt_actx_add_body(actx, new_body);
1154 mutt_generate_recvattach_list(actx, e, new_body, fp_new, parent_type, level, 1);
1155 continue;
1156 }
1157
1158 decrypt_failed:
1159 /* Fall through and show the original parts if decryption fails */
1160 if (need_secured && !secured)
1161 mutt_error(_("Can't decrypt encrypted message"));
1162
1163 struct AttachPtr *ap = mutt_aptr_new();
1164 mutt_actx_add_attach(actx, ap);
1165
1166 ap->body = bp;
1167 ap->fp = fp;
1168 bp->aptr = ap;
1170 ap->level = level;
1171 ap->decrypted = decrypted;
1172
1173 if (mutt_is_message_type(bp->type, bp->subtype))
1174 {
1175 mutt_generate_recvattach_list(actx, bp->email, bp->parts, fp, bp->type,
1176 level + 1, decrypted);
1177 e->security |= bp->email->security;
1178 }
1179 else
1180 {
1181 mutt_generate_recvattach_list(actx, e, bp->parts, fp, bp->type, level + 1, decrypted);
1182 }
1183 }
1184}
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 1190 of file recvattach.c.

1191{
1192 /* Collapse the attachments if '$digest_collapse' is set AND if...
1193 * the outer container is of type 'multipart/digest' */
1194 bool digest = mutt_istr_equal(actx->email->body->subtype, "digest");
1195
1196 const bool c_digest_collapse = cs_subset_bool(NeoMutt->sub, "digest_collapse");
1197 for (int i = 0; i < actx->idxlen; i++)
1198 {
1199 actx->idx[i]->body->tagged = false;
1200
1201 /* OR an inner container is of type 'multipart/digest' */
1202 actx->idx[i]->collapsed = (c_digest_collapse &&
1203 (digest ||
1204 ((actx->idx[i]->body->type == TYPE_MULTIPART) &&
1205 mutt_istr_equal(actx->idx[i]->body->subtype, "digest"))));
1206 }
1207}
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 1215 of file recvattach.c.

1216{
1217 if (init)
1218 {
1219 mutt_generate_recvattach_list(actx, actx->email, actx->email->body,
1220 actx->fp_root, -1, 0, 0);
1221 mutt_attach_init(actx);
1222 }
1223
1224 mutt_update_tree(actx);
1225
1226 menu->max = actx->vcount;
1227
1228 const int index = menu_get_index(menu);
1229 if (index >= menu->max)
1230 menu_set_index(menu, menu->max - 1);
1232}
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 1242 of file recvattach.c.

1243{
1244 if (!ba || !actx || !menu)
1245 return -1;
1246
1247 if (menu->tag_prefix)
1248 {
1249 for (int i = 0; i < actx->idxlen; i++)
1250 {
1251 struct Body *b = actx->idx[i]->body;
1252 if (b->tagged)
1253 {
1254 ARRAY_ADD(ba, b);
1255 }
1256 }
1257 }
1258 else
1259 {
1260 struct AttachPtr *cur = current_attachment(actx, menu);
1261 if (!cur)
1262 return -1;
1263
1264 ARRAY_ADD(ba, cur->body);
1265 }
1266
1267 return ARRAY_SIZE(ba);
1268}
#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: