NeoMutt  2022-04-29-215-gc12b98
Teaching an old dog new tricks
DOXYGEN
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 <unistd.h>
#include "mutt/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "recvattach.h"
#include "enter/lib.h"
#include "menu/lib.h"
#include "ncrypt/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "attach.h"
#include "commands.h"
#include "handler.h"
#include "hook.h"
#include "mailcap.h"
#include "mutt_attach.h"
#include "mutt_thread.h"
#include "muttlib.h"
#include "opcodes.h"
#include "rfc3676.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. More...
 
static void mutt_update_v2r (struct AttachCtx *actx)
 Update the virtual list of attachments. More...
 
void mutt_update_tree (struct AttachCtx *actx)
 Refresh the list of attachments. More...
 
static void prepend_savedir (struct Buffer *buf)
 Add $attach_save_dir to the beginning of a path. More...
 
static bool has_a_message (struct Body *body)
 Determine if the Body has a message (to save) More...
 
static int save_attachment_flowed_helper (FILE *fp, struct Body *b, const char *path, enum SaveAttach flags, struct Email *e)
 Helper for unstuffing attachments. More...
 
static int query_save_attachment (FILE *fp, struct Body *body, struct Email *e, char **directory)
 Ask the user if we should save the attachment. More...
 
static int save_without_prompting (FILE *fp, struct Body *body, struct Email *e)
 Save the attachment, without prompting each time. More...
 
void mutt_save_attachment_list (struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, struct Email *e, struct Menu *menu)
 Save a list of attachments. More...
 
static void query_pipe_attachment (const char *command, FILE *fp, struct Body *body, bool filter)
 Ask the user if we should pipe the attachment. More...
 
static void pipe_attachment (FILE *fp, struct Body *b, struct State *state)
 Pipe the attachment to a command. More...
 
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. More...
 
void mutt_pipe_attachment_list (struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, bool filter)
 Pipe a list of attachments to a command. More...
 
static bool can_print (struct AttachCtx *actx, struct Body *top, bool tag)
 Do we know how to print this attachment type? More...
 
static void print_attachment_list (struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, struct State *state)
 Print a list of Attachments. More...
 
void mutt_print_attachment_list (struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top)
 Print a list of Attachments. More...
 
void recvattach_edit_content_type (struct AttachCtx *actx, struct Menu *menu, struct Email *e)
 Edit the content type of an attachment. More...
 
int mutt_attach_display_loop (struct ConfigSubset *sub, struct Menu *menu, int op, struct Email *e, struct AttachCtx *actx, bool recv)
 Event loop for the Attachment menu. More...
 
void mutt_generate_recvattach_list (struct AttachCtx *actx, struct Email *e, struct Body *parts, FILE *fp, int parent_type, int level, bool decrypted)
 Create a list of attachments. More...
 
void mutt_attach_init (struct AttachCtx *actx)
 Create a new Attachment context. More...
 
void mutt_update_recvattach_menu (struct AttachCtx *actx, struct Menu *menu, bool init)
 Update the Attachment Menu. More...
 
int ba_add_tagged (struct BodyArray *ba, struct AttachCtx *actx, struct Menu *menu)
 Get an array of tagged Attachments. More...
 

Detailed Description

Attachment code.

Authors
  • Michael R. Elkins
  • Thomas Roessler

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 69 of file recvattach.c.

70{
71 const int virt = menu_get_index(menu);
72 const int index = actx->v2r[virt];
73
74 return actx->idx[index];
75}
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:154
struct AttachPtr ** idx
Array of attachments.
Definition: attach.h:55
short * v2r
Mapping from virtual to real attachment.
Definition: attach.h:59
+ 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 83 of file recvattach.c.

84{
85 int vindex, rindex, curlevel;
86
87 vindex = 0;
88 rindex = 0;
89
90 while (rindex < actx->idxlen)
91 {
92 actx->v2r[vindex++] = rindex;
93 if (actx->idx[rindex]->collapsed)
94 {
95 curlevel = actx->idx[rindex]->level;
96 do
97 {
98 rindex++;
99 } while ((rindex < actx->idxlen) && (actx->idx[rindex]->level > curlevel));
100 }
101 else
102 rindex++;
103 }
104
105 actx->vcount = vindex;
106}
short vcount
The number of virtual attachments.
Definition: attach.h:60
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 112 of file recvattach.c.

113{
114 char buf[256] = { 0 };
115 char *s = NULL;
116
117 mutt_update_v2r(actx);
118
119 for (int vindex = 0; vindex < actx->vcount; vindex++)
120 {
121 const int rindex = actx->v2r[vindex];
122 actx->idx[rindex]->num = vindex;
123 if ((2 * (actx->idx[rindex]->level + 2)) < sizeof(buf))
124 {
125 if (actx->idx[rindex]->level)
126 {
127 s = buf + 2 * (actx->idx[rindex]->level - 1);
128 *s++ = (actx->idx[rindex]->body->next) ? MUTT_TREE_LTEE : MUTT_TREE_LLCORNER;
129 *s++ = MUTT_TREE_HLINE;
130 *s++ = MUTT_TREE_RARROW;
131 }
132 else
133 s = buf;
134 *s = '\0';
135 }
136
137 if (actx->idx[rindex]->tree)
138 {
139 if (!mutt_str_equal(actx->idx[rindex]->tree, buf))
140 mutt_str_replace(&actx->idx[rindex]->tree, buf);
141 }
142 else
143 actx->idx[rindex]->tree = mutt_str_dup(buf);
144
145 if (((2 * (actx->idx[rindex]->level + 2)) < sizeof(buf)) &&
146 actx->idx[rindex]->level)
147 {
148 s = buf + 2 * (actx->idx[rindex]->level - 1);
149 *s++ = (actx->idx[rindex]->body->next) ? '\005' : '\006';
150 *s++ = '\006';
151 }
152 }
153}
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:807
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
@ MUTT_TREE_LLCORNER
Lower left corner.
Definition: mutt_thread.h:44
@ MUTT_TREE_RARROW
Right arrow.
Definition: mutt_thread.h:50
@ MUTT_TREE_LTEE
Left T-piece.
Definition: mutt_thread.h:46
@ MUTT_TREE_HLINE
Horizontal line.
Definition: mutt_thread.h:47
static void mutt_update_v2r(struct AttachCtx *actx)
Update the virtual list of attachments.
Definition: recvattach.c:83
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:71
+ 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 159 of file recvattach.c.

160{
161 if (!buf || !buf->data || (buf->data[0] == '/'))
162 return;
163
164 struct Buffer *tmp = mutt_buffer_pool_get();
165 const char *const c_attach_save_dir = cs_subset_path(NeoMutt->sub, "attach_save_dir");
166 if (c_attach_save_dir)
167 {
168 mutt_buffer_addstr(tmp, c_attach_save_dir);
169 if (tmp->dptr[-1] != '/')
170 mutt_buffer_addch(tmp, '/');
171 }
172 else
173 mutt_buffer_addstr(tmp, "./");
174
176 mutt_buffer_copy(buf, tmp);
178}
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:248
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:233
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:462
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
String manipulation buffer.
Definition: buffer.h:34
char * dptr
Current read/write position.
Definition: buffer.h:36
char * data
Pointer to data.
Definition: buffer.h:35
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ has_a_message()

static bool has_a_message ( struct Body body)
static

Determine if the Body has a message (to save)

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

Definition at line 185 of file recvattach.c.

186{
187 return (body->email && (body->encoding != ENC_BASE64) &&
188 (body->encoding != ENC_QUOTED_PRINTABLE) &&
189 mutt_is_message_type(body->type, body->subtype));
190}
@ ENC_BASE64
Base-64 encoded text.
Definition: mime.h:52
@ ENC_QUOTED_PRINTABLE
Quoted-printable text.
Definition: mime.h:51
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1442
struct Email * email
header information for message/rfc822
Definition: body.h:73
char * subtype
content-type subtype
Definition: body.h:60
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 217 of file recvattach.c.

219{
220 int rc = -1;
221
223 {
224 struct Body b_fake = { 0 };
225
226 struct Buffer *tempfile = mutt_buffer_pool_get();
227 mutt_buffer_mktemp(tempfile);
228
229 /* Pass MUTT_SAVE_NO_FLAGS to force mutt_file_fopen("w") */
231 if (rc != 0)
232 goto cleanup;
233
235
236 /* Now "really" save it. Send mode does this without touching anything,
237 * so force send-mode. */
238 memset(&b_fake, 0, sizeof(struct Body));
239 b_fake.filename = tempfile->data;
240 rc = mutt_save_attachment(NULL, &b_fake, path, flags, e);
241
243
244 cleanup:
245 mutt_buffer_pool_release(&tempfile);
246 }
247 else
248 {
249 rc = mutt_save_attachment(fp, b, path, flags, e);
250 }
251
252 return rc;
253}
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:194
int mutt_save_attachment(FILE *fp, struct Body *m, const char *path, enum SaveAttach opt, struct Email *e)
Save an attachment.
Definition: mutt_attach.c:896
@ MUTT_SAVE_NO_FLAGS
No flags set.
Definition: mutt_attach.h:57
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:74
void mutt_rfc3676_space_unstuff_attachment(struct Body *b, const char *filename)
Unstuff attachments.
Definition: rfc3676.c:513
bool mutt_rfc3676_is_format_flowed(struct Body *b)
Is the Email "format-flowed"?
Definition: rfc3676.c:389
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:58
+ 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 body,
struct Email e,
char **  directory 
)
static

Ask the user if we should save the attachment.

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

Definition at line 264 of file recvattach.c.

265{
266 char *prompt = NULL;
268 int rc = -1;
269
270 struct Buffer *buf = mutt_buffer_pool_get();
271 struct Buffer *tfile = mutt_buffer_pool_get();
272
273 if (body->filename)
274 {
275 if (directory && *directory)
276 {
277 mutt_buffer_concat_path(buf, *directory, mutt_path_basename(body->filename));
278 }
279 else
280 mutt_buffer_strcpy(buf, body->filename);
281 }
282 else if (has_a_message(body))
283 {
284 mutt_default_save(buf->data, buf->dsize, body->email);
286 }
287
288 prepend_savedir(buf);
289
290 prompt = _("Save to file: ");
291 while (prompt)
292 {
294 false, NULL, NULL, NULL) != 0) ||
296 {
297 goto cleanup;
298 }
299
300 prompt = NULL;
302
303 bool is_message = (fp && has_a_message(body));
304
305 if (is_message)
306 {
307 struct stat st = { 0 };
308
309 /* check to make sure that this file is really the one the user wants */
311 if (rc == 1)
312 {
313 prompt = _("Save to file: ");
314 continue;
315 }
316 else if (rc == -1)
317 goto cleanup;
318 mutt_buffer_copy(tfile, buf);
319 }
320 else
321 {
322 rc = mutt_check_overwrite(body->filename, mutt_buffer_string(buf), tfile,
323 &opt, directory);
324 if (rc == -1)
325 goto cleanup;
326 else if (rc == 1)
327 {
328 prompt = _("Save to file: ");
329 continue;
330 }
331 }
332
333 mutt_message(_("Saving..."));
334 if (save_attachment_flowed_helper(fp, body, mutt_buffer_string(tfile), opt,
335 (e || !is_message) ? e : body->email) == 0)
336 {
337 // This uses ngettext to avoid duplication of messages
338 mutt_message(ngettext("Attachment saved", "%d attachments saved", 1), 1);
339 rc = 0;
340 goto cleanup;
341 }
342 else
343 {
344 prompt = _("Save to file: ");
345 continue;
346 }
347 }
348
349cleanup:
352 return rc;
353}
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:260
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:327
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:189
size_t mutt_buffer_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:389
int mutt_buffer_get_field(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, struct Mailbox *m, char ***files, int *numfiles)
Ask the user for a string.
Definition: window.c:180
#define mutt_message(...)
Definition: logging.h:86
void mutt_default_save(char *path, size_t pathlen, struct Email *e)
Find the default save path for an email.
Definition: hook.c:737
#define _(a)
Definition: message.h:28
const char * mutt_path_basename(const char *f)
Find the last component for a pathname.
Definition: path.c:329
#define MUTT_COMP_FILE
File completion (in browser)
Definition: mutt.h:55
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:62
SaveAttach
Options for saving attachments.
Definition: mutt_attach.h:56
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:322
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:621
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition: muttlib.c:1356
static bool has_a_message(struct Body *body)
Determine if the Body has a message (to save)
Definition: recvattach.c:185
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:217
static void prepend_savedir(struct Buffer *buf)
Add $attach_save_dir to the beginning of a path.
Definition: recvattach.c:159
size_t dsize
Length of data.
Definition: buffer.h:37
+ 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 body,
struct Email e 
)
static

Save the attachment, without prompting each time.

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

Definition at line 363 of file recvattach.c.

364{
366 int rc = -1;
367 struct Buffer *buf = mutt_buffer_pool_get();
368 struct Buffer *tfile = mutt_buffer_pool_get();
369
370 if (body->filename)
371 {
372 mutt_buffer_strcpy(buf, body->filename);
373 }
374 else if (has_a_message(body))
375 {
376 mutt_default_save(buf->data, buf->dsize, body->email);
377 }
378
379 prepend_savedir(buf);
381
382 bool is_message = (fp && has_a_message(body));
383
384 if (is_message)
385 {
386 mutt_buffer_copy(tfile, buf);
387 }
388 else
389 {
390 rc = mutt_check_overwrite(body->filename, mutt_buffer_string(buf), tfile, &opt, NULL);
391 if (rc == -1) // abort or cancel
392 goto cleanup;
393 }
394
395 rc = save_attachment_flowed_helper(fp, body, mutt_buffer_string(tfile), opt,
396 (e || !is_message) ? e : body->email);
397
398cleanup:
401 return rc;
402}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_save_attachment_list()

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

Save a list of attachments.

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

Definition at line 413 of file recvattach.c.

415{
416 char *directory = NULL;
417 int rc = 1;
418 int last = menu_get_index(menu);
419 FILE *fp_out = NULL;
420 int saved_attachments = 0;
421
422 struct Buffer *buf = mutt_buffer_pool_get();
423 struct Buffer *tfile = mutt_buffer_pool_get();
424
425 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
426 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
427 const bool c_attach_save_without_prompting = cs_subset_bool(NeoMutt->sub, "attach_save_without_prompting");
428
429 for (int i = 0; !tag || (i < actx->idxlen); i++)
430 {
431 if (tag)
432 {
433 fp = actx->idx[i]->fp;
434 top = actx->idx[i]->body;
435 }
436 if (!tag || top->tagged)
437 {
438 if (!c_attach_split)
439 {
440 if (mutt_buffer_is_empty(buf))
441 {
443
445 prepend_savedir(buf);
446
447 if ((mutt_buffer_get_field(_("Save to file: "), buf, MUTT_COMP_FILE | MUTT_COMP_CLEAR,
448 false, NULL, NULL, NULL) != 0) ||
450 {
451 goto cleanup;
452 }
454 if (mutt_check_overwrite(top->filename, mutt_buffer_string(buf), tfile, &opt, NULL))
455 goto cleanup;
456 rc = save_attachment_flowed_helper(fp, top, mutt_buffer_string(tfile), opt, e);
457 if ((rc == 0) && c_attach_sep && (fp_out = fopen(mutt_buffer_string(tfile), "a")))
458 {
459 fprintf(fp_out, "%s", c_attach_sep);
460 mutt_file_fclose(&fp_out);
461 }
462 }
463 else
464 {
467 if ((rc == 0) && c_attach_sep && (fp_out = fopen(mutt_buffer_string(tfile), "a")))
468 {
469 fprintf(fp_out, "%s", c_attach_sep);
470 mutt_file_fclose(&fp_out);
471 }
472 }
473 }
474 else
475 {
476 if (tag && menu && top->aptr)
477 {
478 menu_set_index(menu, top->aptr->num);
480
481 menu_redraw(menu);
482 }
483 if (c_attach_save_without_prompting)
484 {
485 // Save each file, with no prompting, using the configured 'AttachSaveDir'
486 rc = save_without_prompting(fp, top, e);
487 if (rc == 0)
488 saved_attachments++;
489 }
490 else
491 {
492 // Save each file, prompting the user for the location each time.
493 if (query_save_attachment(fp, top, e, &directory) == -1)
494 break;
495 }
496 }
497 }
498 if (!tag)
499 break;
500 }
501
502 FREE(&directory);
503
504 if (tag && menu)
505 {
506 menu_set_index(menu, last);
508 }
509
510 if (rc == 0)
511 {
512 if (!c_attach_split)
513 saved_attachments = 1;
514
515 if (!c_attach_split || c_attach_save_without_prompting)
516 {
517 mutt_message(ngettext("Attachment saved", "%d attachments saved", saved_attachments),
518 saved_attachments);
519 }
520 }
521
522cleanup:
525}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
int menu_redraw(struct Menu *menu)
Redraw the parts of the screen that have been flagged to be redrawn.
Definition: draw.c:481
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
#define FREE(x)
Definition: memory.h:43
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition: menu.c:178
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:168
#define MENU_REDRAW_MOTION
Redraw after moving the menu list.
Definition: lib.h:57
@ MUTT_SAVE_APPEND
Append to existing file.
Definition: mutt_attach.h:58
static int save_without_prompting(FILE *fp, struct Body *body, struct Email *e)
Save the attachment, without prompting each time.
Definition: recvattach.c:363
static int query_save_attachment(FILE *fp, struct Body *body, struct Email *e, char **directory)
Ask the user if we should save the attachment.
Definition: recvattach.c:264
#define NONULL(x)
Definition: string2.h:37
short idxlen
Number of attachmentes.
Definition: attach.h:56
FILE * fp
Used in the recvattach menu.
Definition: attach.h:37
struct AttachPtr * aptr
Menu information, used in recvattach.c.
Definition: body.h:74
bool tagged
This attachment is tagged.
Definition: body.h:89
+ 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 body,
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)
bodyAttachment
filterIs this command a filter?

Definition at line 534 of file recvattach.c.

535{
536 char tfile[PATH_MAX] = { 0 };
537
538 if (filter)
539 {
540 char warning[PATH_MAX + 256];
541 snprintf(warning, sizeof(warning),
542 _("WARNING! You are about to overwrite %s, continue?"), body->filename);
543 if (mutt_yesorno(warning, MUTT_NO) != MUTT_YES)
544 {
546 return;
547 }
548 mutt_mktemp(tfile, sizeof(tfile));
549 }
550 else
551 tfile[0] = '\0';
552
553 if (mutt_pipe_attachment(fp, body, command, tfile))
554 {
555 if (filter)
556 {
558 mutt_file_rename(tfile, body->filename);
560 mutt_message(_("Attachment filtered"));
561 }
562 }
563 else
564 {
565 if (filter && tfile[0])
566 mutt_file_unlink(tfile);
567 }
568}
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition: file.c:1403
void msgwin_clear_text(void)
Clear the text in the Message Window.
Definition: msgwin.c:249
#define PATH_MAX
Definition: mutt.h:40
int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, char *outfile)
Pipe an attachment to a command.
Definition: mutt_attach.c:729
#define mutt_mktemp(buf, buflen)
Definition: muttlib.h:71
@ 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 mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:194
void mutt_update_encoding(struct Body *a, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:413
+ 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 576 of file recvattach.c.

577{
578 if (!state || !state->fp_out)
579 return;
580
581 FILE *fp_in = NULL;
582 FILE *fp_unstuff = NULL;
583 bool is_flowed = false, unlink_unstuff = false;
584 struct Buffer *unstuff_tempfile = NULL;
585
587 {
588 is_flowed = true;
589 unstuff_tempfile = mutt_buffer_pool_get();
590 mutt_buffer_mktemp(unstuff_tempfile);
591 }
592
593 if (fp)
594 {
595 state->fp_in = fp;
596
597 if (is_flowed)
598 {
599 fp_unstuff = mutt_file_fopen(mutt_buffer_string(unstuff_tempfile), "w");
600 if (fp_unstuff == NULL)
601 {
602 mutt_perror("mutt_file_fopen");
603 goto bail;
604 }
605 unlink_unstuff = true;
606
607 FILE *filter_fp = state->fp_out;
608 state->fp_out = fp_unstuff;
609 mutt_decode_attachment(b, state);
610 mutt_file_fclose(&fp_unstuff);
611 state->fp_out = filter_fp;
612
613 fp_unstuff = mutt_file_fopen(mutt_buffer_string(unstuff_tempfile), "r");
614 if (fp_unstuff == NULL)
615 {
616 mutt_perror("mutt_file_fopen");
617 goto bail;
618 }
619 mutt_file_copy_stream(fp_unstuff, filter_fp);
620 mutt_file_fclose(&fp_unstuff);
621 }
622 else
623 mutt_decode_attachment(b, state);
624 }
625 else
626 {
627 const char *infile = NULL;
628
629 if (is_flowed)
630 {
631 if (mutt_save_attachment(fp, b, mutt_buffer_string(unstuff_tempfile), 0, NULL) == -1)
632 goto bail;
633 unlink_unstuff = true;
635 infile = mutt_buffer_string(unstuff_tempfile);
636 }
637 else
638 infile = b->filename;
639
640 fp_in = fopen(infile, "r");
641 if (!fp_in)
642 {
643 mutt_perror("fopen");
644 goto bail;
645 }
646 mutt_file_copy_stream(fp_in, state->fp_out);
647 mutt_file_fclose(&fp_in);
648 }
649
650 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
651 if (c_attach_sep)
652 state_puts(state, c_attach_sep);
653
654bail:
655 mutt_file_fclose(&fp_unstuff);
656 mutt_file_fclose(&fp_in);
657
658 if (unlink_unstuff)
659 mutt_file_unlink(mutt_buffer_string(unstuff_tempfile));
660 mutt_buffer_pool_release(&unstuff_tempfile);
661}
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:260
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:618
#define mutt_perror(...)
Definition: logging.h:88
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email's attachment.
Definition: handler.c:1867
#define state_puts(STATE, STR)
Definition: state.h:56
FILE * fp_out
File to write to.
Definition: state.h:48
FILE * fp_in
File to read from.
Definition: state.h:47
+ 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 673 of file recvattach.c.

676{
677 for (int i = 0; !tag || (i < actx->idxlen); i++)
678 {
679 if (tag)
680 {
681 fp = actx->idx[i]->fp;
682 top = actx->idx[i]->body;
683 }
684 if (!tag || top->tagged)
685 {
686 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
687 if (!filter && !c_attach_split)
688 pipe_attachment(fp, top, state);
689 else
690 query_pipe_attachment(command, fp, top, filter);
691 }
692 if (!tag)
693 break;
694 }
695}
static void pipe_attachment(FILE *fp, struct Body *b, struct State *state)
Pipe the attachment to a command.
Definition: recvattach.c:576
static void query_pipe_attachment(const char *command, FILE *fp, struct Body *body, bool filter)
Ask the user if we should pipe the attachment.
Definition: recvattach.c:534
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_pipe_attachment_list()

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

Pipe a list of attachments to a command.

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

Definition at line 705 of file recvattach.c.

707{
708 struct State state = { 0 };
709 struct Buffer *buf = NULL;
710
711 if (fp)
712 filter = false; /* sanity check: we can't filter in the recv case yet */
713
714 buf = mutt_buffer_pool_get();
715 /* perform charset conversion on text attachments when piping */
716 state.flags = MUTT_CHARCONV;
717
718 if (mutt_buffer_get_field((filter ? _("Filter through: ") : _("Pipe to: ")), buf,
719 MUTT_COMP_FILE_SIMPLE, false, NULL, NULL, NULL) != 0)
720 {
721 goto cleanup;
722 }
723
724 if (mutt_buffer_len(buf) == 0)
725 goto cleanup;
726
728
729 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
730 if (!filter && !c_attach_split)
731 {
732 mutt_endwin();
733 pid_t pid = filter_create(mutt_buffer_string(buf), &state.fp_out, NULL, NULL);
734 pipe_attachment_list(mutt_buffer_string(buf), actx, fp, tag, top, filter, &state);
735 mutt_file_fclose(&state.fp_out);
736 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
737 if ((filter_wait(pid) != 0) || c_wait_key)
739 }
740 else
741 pipe_attachment_list(mutt_buffer_string(buf), actx, fp, tag, top, filter, &state);
742
743cleanup:
745}
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:371
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:387
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:354
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
#define MUTT_COMP_FILE_SIMPLE
File completion (no browser)
Definition: mutt.h:57
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:673
Keep track when processing files.
Definition: state.h:46
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:50
+ 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 top,
bool  tag 
)
static

Do we know how to print this attachment type?

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

Definition at line 754 of file recvattach.c.

755{
756 char type[256] = { 0 };
757
758 for (int i = 0; !tag || (i < actx->idxlen); i++)
759 {
760 if (tag)
761 top = actx->idx[i]->body;
762 snprintf(type, sizeof(type), "%s/%s", TYPE(top), top->subtype);
763 if (!tag || top->tagged)
764 {
765 if (!mailcap_lookup(top, type, sizeof(type), NULL, MUTT_MC_PRINT))
766 {
767 if (!mutt_istr_equal("text/plain", top->subtype) &&
768 !mutt_istr_equal("application/postscript", top->subtype))
769 {
770 if (!mutt_can_decode(top))
771 {
772 /* L10N: s gets replaced by a MIME type, e.g. "text/plain" or
773 application/octet-stream. */
774 mutt_error(_("I don't know how to print %s attachments"), type);
775 return false;
776 }
777 }
778 }
779 }
780 if (!tag)
781 break;
782 }
783 return true;
784}
#define mutt_error(...)
Definition: logging.h:87
bool mutt_can_decode(struct Body *b)
Will decoding the attachment produce any output.
Definition: handler.c:1827
bool mailcap_lookup(struct Body *a, char *type, size_t typelen, struct MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: mailcap.c:473
@ MUTT_MC_PRINT
Mailcap print field.
Definition: mailcap.h:59
#define TYPE(body)
Definition: mime.h:89
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:819
+ 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 top,
struct State state 
)
static

Print a list of Attachments.

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

Definition at line 794 of file recvattach.c.

796{
797 char type[256] = { 0 };
798
799 for (int i = 0; !tag || (i < actx->idxlen); i++)
800 {
801 if (tag)
802 {
803 fp = actx->idx[i]->fp;
804 top = actx->idx[i]->body;
805 }
806 if (!tag || top->tagged)
807 {
808 snprintf(type, sizeof(type), "%s/%s", TYPE(top), top->subtype);
809 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
810 if (!c_attach_split && !mailcap_lookup(top, type, sizeof(type), NULL, MUTT_MC_PRINT))
811 {
812 if (mutt_istr_equal("text/plain", top->subtype) ||
813 mutt_istr_equal("application/postscript", top->subtype))
814 {
815 pipe_attachment(fp, top, state);
816 }
817 else if (mutt_can_decode(top))
818 {
819 /* decode and print */
820
821 FILE *fp_in = NULL;
822 struct Buffer *newfile = mutt_buffer_pool_get();
823
824 mutt_buffer_mktemp(newfile);
827 {
828 if (!state->fp_out)
829 {
830 mutt_error("BUG in print_attachment_list(). Please report this. ");
831 return;
832 }
833
834 fp_in = fopen(mutt_buffer_string(newfile), "r");
835 if (fp_in)
836 {
837 mutt_file_copy_stream(fp_in, state->fp_out);
838 mutt_file_fclose(&fp_in);
839 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
840 if (c_attach_sep)
841 state_puts(state, c_attach_sep);
842 }
843 }
845 mutt_buffer_pool_release(&newfile);
846 }
847 }
848 else
849 mutt_print_attachment(fp, top);
850 }
851 if (!tag)
852 break;
853 }
854}
#define MUTT_PRINTING
Are we printing? - MUTT_DISPLAY "light".
Definition: state.h:37
int mutt_decode_save_attachment(FILE *fp, struct Body *m, const char *path, int displaying, enum SaveAttach opt)
Decode, then save an attachment.
Definition: mutt_attach.c:1030
int mutt_print_attachment(FILE *fp, struct Body *a)
Print out an attachment.
Definition: mutt_attach.c:1130
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_print_attachment_list()

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

Print a list of Attachments.

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

Definition at line 863 of file recvattach.c.

864{
865 char prompt[128] = { 0 };
866 struct State state = { 0 };
867 int tagmsgcount = 0;
868
869 if (tag)
870 for (int i = 0; i < actx->idxlen; i++)
871 if (actx->idx[i]->body->tagged)
872 tagmsgcount++;
873
874 snprintf(prompt, sizeof(prompt),
875 tag ? ngettext("Print tagged attachment?", "Print %d tagged attachments?", tagmsgcount) :
876 _("Print attachment?"),
877 tagmsgcount);
878 const enum QuadOption c_print = cs_subset_quad(NeoMutt->sub, "print");
879 if (query_quadoption(c_print, prompt) != MUTT_YES)
880 return;
881
882 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
883 if (c_attach_split)
884 {
885 print_attachment_list(actx, fp, tag, top, &state);
886 }
887 else
888 {
889 if (!can_print(actx, top, tag))
890 return;
891 mutt_endwin();
892 const char *const c_print_command = cs_subset_string(NeoMutt->sub, "print_command");
893 pid_t pid = filter_create(NONULL(c_print_command), &state.fp_out, NULL, NULL);
894 print_attachment_list(actx, fp, tag, top, &state);
895 mutt_file_fclose(&state.fp_out);
896 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
897 if ((filter_wait(pid) != 0) || c_wait_key)
899 }
900}
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:218
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: question.c:386
static void print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, struct State *state)
Print a list of Attachments.
Definition: recvattach.c:794
static bool can_print(struct AttachCtx *actx, struct Body *top, bool tag)
Do we know how to print this attachment type?
Definition: recvattach.c:754
+ 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 908 of file recvattach.c.

909{
910 struct AttachPtr *cur_att = current_attachment(actx, menu);
911 if (!mutt_edit_content_type(e, cur_att->body, cur_att->fp))
912 return;
913
914 /* The mutt_update_recvattach_menu() will overwrite any changes
915 * made to a decrypted cur_att->body, so warn the user. */
916 if (cur_att->decrypted)
917 {
918 mutt_message(_("Structural changes to decrypted attachments are not supported"));
919 mutt_sleep(1);
920 }
921 /* Editing the content type can rewrite the body structure. */
922 for (int i = 0; i < actx->idxlen; i++)
923 actx->idx[i]->body = NULL;
925 mutt_update_recvattach_menu(actx, menu, true);
926}
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: commands.c:1105
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1455
void mutt_update_recvattach_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
Update the Attachment Menu.
Definition: recvattach.c:1192
struct AttachPtr * current_attachment(struct AttachCtx *actx, struct Menu *menu)
Get the current attachment.
Definition: recvattach.c:69
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 938 of file recvattach.c.

940{
941 do
942 {
943 switch (op)
944 {
945 case OP_DISPLAY_HEADERS:
946 bool_str_toggle(NeoMutt->sub, "weed", NULL);
947 /* fallthrough */
948
949 case OP_ATTACHMENT_VIEW:
950 {
951 struct AttachPtr *cur_att = current_attachment(actx, menu);
952 if (!cur_att->fp)
953 {
954 if (cur_att->body->type == TYPE_MULTIPART)
955 {
956 struct Body *b = cur_att->body->parts;
957 while (b->parts)
958 b = b->parts;
959 cur_att = b->aptr;
960 }
961 }
962 op = mutt_view_attachment(cur_att->fp, cur_att->body, MUTT_VA_REGULAR,
963 e, actx, menu->win);
964 break;
965 }
966
967 case OP_NEXT_ENTRY:
968 case OP_MAIN_NEXT_UNDELETED: /* hack */
969 {
970 const int index = menu_get_index(menu) + 1;
971 if (index < menu->max)
972 {
973 menu_set_index(menu, index);
974 op = OP_ATTACHMENT_VIEW;
975 }
976 else
977 op = OP_NULL;
978 break;
979 }
980
981 case OP_PREV_ENTRY:
982 case OP_MAIN_PREV_UNDELETED: /* hack */
983 {
984 const int index = menu_get_index(menu) - 1;
985 if (index >= 0)
986 {
987 menu_set_index(menu, index);
988 op = OP_ATTACHMENT_VIEW;
989 }
990 else
991 op = OP_NULL;
992 break;
993 }
994
995 case OP_ATTACHMENT_EDIT_TYPE:
996 {
997 struct AttachPtr *cur_att = current_attachment(actx, menu);
998 /* when we edit the content-type, we should redisplay the attachment
999 * immediately */
1000 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1001 if (recv)
1002 recvattach_edit_content_type(actx, menu, e);
1003 else
1004 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1005
1007 op = OP_ATTACHMENT_VIEW;
1008 break;
1009 }
1010 /* functions which are passed through from the pager */
1011 case OP_PIPE:
1012 {
1013 struct AttachPtr *cur_att = current_attachment(actx, menu);
1014 mutt_pipe_attachment_list(actx, cur_att->fp, false, cur_att->body, false);
1015 op = OP_ATTACHMENT_VIEW;
1016 break;
1017 }
1018 case OP_ATTACHMENT_PRINT:
1019 {
1020 struct AttachPtr *cur_att = current_attachment(actx, menu);
1021 mutt_print_attachment_list(actx, cur_att->fp, false, cur_att->body);
1022 op = OP_ATTACHMENT_VIEW;
1023 break;
1024 }
1025 case OP_ATTACHMENT_SAVE:
1026 {
1027 struct AttachPtr *cur_att = current_attachment(actx, menu);
1028 mutt_save_attachment_list(actx, cur_att->fp, false, cur_att->body, e, NULL);
1029 op = OP_ATTACHMENT_VIEW;
1030 break;
1031 }
1032 case OP_CHECK_TRADITIONAL:
1034 {
1035 op = OP_NULL;
1036 break;
1037 }
1038 /* fallthrough */
1039 case OP_ATTACHMENT_COLLAPSE:
1040 if (recv)
1041 return op;
1042 /* fallthrough */
1043 default:
1044 op = OP_NULL;
1045 }
1046 } while (op != OP_NULL);
1047
1048 return op;
1049}
int bool_str_toggle(struct ConfigSubset *sub, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition: bool.c:214
#define MENU_REDRAW_INDEX
Redraw the index.
Definition: lib.h:56
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
int mutt_view_attachment(FILE *fp, struct Body *a, enum ViewAttachMode mode, struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
View an attachment.
Definition: mutt_attach.c:416
@ MUTT_VA_REGULAR
View using default method.
Definition: mutt_attach.h:43
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition: lib.h:92
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:90
#define WithCrypto
Definition: lib.h:116
void mutt_save_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, struct Email *e, struct Menu *menu)
Save a list of attachments.
Definition: recvattach.c:413
void mutt_pipe_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, bool filter)
Pipe a list of attachments to a command.
Definition: recvattach.c:705
void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top)
Print a list of Attachments.
Definition: recvattach.c:863
void recvattach_edit_content_type(struct AttachCtx *actx, struct Menu *menu, struct Email *e)
Edit the content type of an attachment.
Definition: recvattach.c:908
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:72
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
struct MuttWindow * win
Window holding the Menu.
Definition: lib.h:76
+ 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 parts,
FILE *  fp,
int  parent_type,
int  level,
bool  decrypted 
)

Create a list of attachments.

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

Definition at line 1061 of file recvattach.c.

1064{
1065 struct Body *m = NULL;
1066 struct Body *new_body = NULL;
1067 FILE *fp_new = NULL;
1069
1070 for (m = parts; m; m = m->next)
1071 {
1072 bool need_secured = false;
1073 bool secured = false;
1074
1076 {
1077 need_secured = true;
1078
1079 if (type & SEC_ENCRYPT)
1080 {
1082 goto decrypt_failed;
1083
1084 if (e->env)
1086 }
1087
1088 secured = (crypt_smime_decrypt_mime(fp, &fp_new, m, &new_body) == 0);
1089 /* If the decrypt/verify-opaque doesn't generate mime output, an empty
1090 * text/plain type will still be returned by mutt_read_mime_header().
1091 * We can't distinguish an actual part from a failure, so only use a
1092 * text/plain that results from a single top-level part. */
1093 if (secured && (new_body->type == TYPE_TEXT) &&
1094 mutt_istr_equal("plain", new_body->subtype) && ((parts != m) || m->next))
1095 {
1096 mutt_body_free(&new_body);
1097 mutt_file_fclose(&fp_new);
1098 goto decrypt_failed;
1099 }
1100
1101 if (secured && (type & SEC_ENCRYPT))
1102 e->security |= SMIME_ENCRYPT;
1103 }
1104
1105 if (((WithCrypto & APPLICATION_PGP) != 0) &&
1107 {
1108 need_secured = true;
1109
1111 goto decrypt_failed;
1112
1113 secured = (crypt_pgp_decrypt_mime(fp, &fp_new, m, &new_body) == 0);
1114
1115 if (secured)
1116 e->security |= PGP_ENCRYPT;
1117 }
1118
1119 if (need_secured && secured)
1120 {
1121 mutt_actx_add_fp(actx, fp_new);
1122 mutt_actx_add_body(actx, new_body);
1123 mutt_generate_recvattach_list(actx, e, new_body, fp_new, parent_type, level, 1);
1124 continue;
1125 }
1126
1127 decrypt_failed:
1128 /* Fall through and show the original parts if decryption fails */
1129 if (need_secured && !secured)
1130 mutt_error(_("Can't decrypt encrypted message"));
1131
1132 /* Strip out the top level multipart */
1133 if ((m->type == TYPE_MULTIPART) && m->parts && !need_secured &&
1134 ((parent_type == -1) && !mutt_istr_equal("alternative", m->subtype) &&
1135 !mutt_istr_equal("multilingual", m->subtype)))
1136 {
1137 mutt_generate_recvattach_list(actx, e, m->parts, fp, m->type, level, decrypted);
1138 }
1139 else
1140 {
1141 struct AttachPtr *ap = mutt_aptr_new();
1142 mutt_actx_add_attach(actx, ap);
1143
1144 ap->body = m;
1145 ap->fp = fp;
1146 m->aptr = ap;
1148 ap->level = level;
1149 ap->decrypted = decrypted;
1150
1151 if (m->type == TYPE_MULTIPART)
1152 mutt_generate_recvattach_list(actx, e, m->parts, fp, m->type, level + 1, decrypted);
1153 else if (mutt_is_message_type(m->type, m->subtype))
1154 {
1156 level + 1, decrypted);
1157 e->security |= m->email->security;
1158 }
1159 }
1160 }
1161}
void mutt_actx_add_body(struct AttachCtx *actx, struct Body *new_body)
Add an email body to an Attachment Context.
Definition: attach.c:142
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
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:601
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:134
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:439
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition: crypt.c:500
int crypt_smime_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
Wrapper for CryptModuleSpecs::decrypt_mime()
Definition: cryptglue.c:433
void crypt_smime_getkeys(struct Envelope *env)
Wrapper for CryptModuleSpecs::smime_getkeys()
Definition: cryptglue.c:455
int crypt_pgp_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
Wrapper for CryptModuleSpecs::decrypt_mime()
Definition: cryptglue.c:211
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
@ TYPE_TEXT
Type: 'text/*'.
Definition: mime.h:38
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:76
#define PGP_ENCRYPT
Definition: lib.h:96
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:91
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:78
#define SMIME_ENCRYPT
Definition: lib.h:102
void mutt_generate_recvattach_list(struct AttachCtx *actx, struct Email *e, struct Body *parts, FILE *fp, int parent_type, int level, bool decrypted)
Create a list of attachments.
Definition: recvattach.c:1061
int parent_type
Type of parent attachment, e.g. TYPE_MULTIPART.
Definition: attach.h:38
struct Envelope * env
Envelope information.
Definition: email.h:66
+ 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 1167 of file recvattach.c.

1168{
1169 /* Collapse the attachments if '$digest_collapse' is set AND if...
1170 * the outer container is of type 'multipart/digest' */
1171 bool digest = mutt_istr_equal(actx->email->body->subtype, "digest");
1172
1173 const bool c_digest_collapse = cs_subset_bool(NeoMutt->sub, "digest_collapse");
1174 for (int i = 0; i < actx->idxlen; i++)
1175 {
1176 actx->idx[i]->body->tagged = false;
1177
1178 /* OR an inner container is of type 'multipart/digest' */
1179 actx->idx[i]->collapsed = (c_digest_collapse &&
1180 (digest ||
1181 ((actx->idx[i]->body->type == TYPE_MULTIPART) &&
1182 mutt_istr_equal(actx->idx[i]->body->subtype, "digest"))));
1183 }
1184}
struct Email * email
Used by recvattach for updating.
Definition: attach.h:52
struct Body * body
List of MIME parts.
Definition: email.h:67
+ 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 1192 of file recvattach.c.

1193{
1194 if (init)
1195 {
1196 mutt_generate_recvattach_list(actx, actx->email, actx->email->body,
1197 actx->fp_root, -1, 0, 0);
1198 mutt_attach_init(actx);
1199 }
1200
1201 mutt_update_tree(actx);
1202
1203 menu->max = actx->vcount;
1204
1205 const int index = menu_get_index(menu);
1206 if (index >= menu->max)
1207 menu_set_index(menu, menu->max - 1);
1209}
void mutt_attach_init(struct AttachCtx *actx)
Create a new Attachment context.
Definition: recvattach.c:1167
void mutt_update_tree(struct AttachCtx *actx)
Refresh the list of attachments.
Definition: recvattach.c:112
FILE * fp_root
Used by recvattach for updating.
Definition: attach.h:53
int max
Number of entries in the menu.
Definition: lib.h:71
+ 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 1219 of file recvattach.c.

1220{
1221 if (!ba || !actx || !menu)
1222 return -1;
1223
1224 if (menu->tag_prefix)
1225 {
1226 for (int i = 0; i < actx->idxlen; i++)
1227 {
1228 struct Body *b = actx->idx[i]->body;
1229 if (b->tagged)
1230 {
1231 ARRAY_ADD(ba, b);
1232 }
1233 }
1234 }
1235 else
1236 {
1237 struct AttachPtr *cur = current_attachment(actx, menu);
1238 if (!cur)
1239 return -1;
1240
1241 ARRAY_ADD(ba, cur->body);
1242 }
1243
1244 return ARRAY_SIZE(ba);
1245}
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition: array.h:155
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:86
bool tag_prefix
User has pressed <tag-prefix>
Definition: lib.h:75
+ Here is the call graph for this function:
+ Here is the caller graph for this function: