NeoMutt  2025-01-09-41-g086358
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 "mutt.h"
#include "recvattach.h"
#include "browser/lib.h"
#include "editor/lib.h"
#include "history/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 "globals.h"
#include "handler.h"
#include "hook.h"
#include "mailcap.h"
#include "mutt_attach.h"
#include "mutt_thread.h"
#include "muttlib.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.
 
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 77 of file recvattach.c.

78{
79 const int virt = menu_get_index(menu);
80 const int index = actx->v2r[virt];
81
82 return actx->idx[index];
83}
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:160
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 91 of file recvattach.c.

92{
93 int vindex, rindex, curlevel;
94
95 vindex = 0;
96 rindex = 0;
97
98 while (rindex < actx->idxlen)
99 {
100 actx->v2r[vindex++] = rindex;
101 if (actx->idx[rindex]->collapsed)
102 {
103 curlevel = actx->idx[rindex]->level;
104 do
105 {
106 rindex++;
107 } while ((rindex < actx->idxlen) && (actx->idx[rindex]->level > curlevel));
108 }
109 else
110 {
111 rindex++;
112 }
113 }
114
115 actx->vcount = vindex;
116}
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 122 of file recvattach.c.

123{
124 char buf[256] = { 0 };
125 char *s = NULL;
126
127 mutt_update_v2r(actx);
128
129 for (int vindex = 0; vindex < actx->vcount; vindex++)
130 {
131 const int rindex = actx->v2r[vindex];
132 actx->idx[rindex]->num = vindex;
133 if ((2 * (actx->idx[rindex]->level + 2)) < sizeof(buf))
134 {
135 if (actx->idx[rindex]->level)
136 {
137 s = buf + 2 * (actx->idx[rindex]->level - 1);
138 *s++ = (actx->idx[rindex]->body->next) ? MUTT_TREE_LTEE : MUTT_TREE_LLCORNER;
139 *s++ = MUTT_TREE_HLINE;
140 *s++ = MUTT_TREE_RARROW;
141 }
142 else
143 {
144 s = buf;
145 }
146 *s = '\0';
147 }
148
149 if (actx->idx[rindex]->tree)
150 {
151 if (!mutt_str_equal(actx->idx[rindex]->tree, buf))
152 mutt_str_replace(&actx->idx[rindex]->tree, buf);
153 }
154 else
155 {
156 actx->idx[rindex]->tree = mutt_str_dup(buf);
157 }
158
159 if (((2 * (actx->idx[rindex]->level + 2)) < sizeof(buf)) &&
160 actx->idx[rindex]->level)
161 {
162 s = buf + 2 * (actx->idx[rindex]->level - 1);
163 *s++ = (actx->idx[rindex]->body->next) ? MUTT_TREE_VLINE : MUTT_TREE_SPACE;
164 *s++ = MUTT_TREE_SPACE;
165 }
166 }
167}
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:280
@ MUTT_TREE_LLCORNER
Lower left corner.
Definition: mutt_thread.h:58
@ MUTT_TREE_RARROW
Right arrow.
Definition: mutt_thread.h:64
@ MUTT_TREE_LTEE
Left T-piece.
Definition: mutt_thread.h:60
@ MUTT_TREE_VLINE
Vertical line.
Definition: mutt_thread.h:62
@ MUTT_TREE_HLINE
Horizontal line.
Definition: mutt_thread.h:61
@ MUTT_TREE_SPACE
Blank space.
Definition: mutt_thread.h:63
static void mutt_update_v2r(struct AttachCtx *actx)
Update the virtual list of attachments.
Definition: recvattach.c:91
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 173 of file recvattach.c.

174{
175 if (!buf || !buf->data || (buf->data[0] == '/'))
176 return;
177
178 struct Buffer *tmp = buf_pool_get();
179 const char *const c_attach_save_dir = cs_subset_path(NeoMutt->sub, "attach_save_dir");
180 if (c_attach_save_dir)
181 {
182 buf_addstr(tmp, c_attach_save_dir);
183 if (tmp->dptr[-1] != '/')
184 buf_addch(tmp, '/');
185 }
186 else
187 {
188 buf_addstr(tmp, "./");
189 }
190
191 buf_addstr(tmp, buf_string(buf));
192 buf_copy(buf, tmp);
193 buf_pool_release(&tmp);
194}
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:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:96
String manipulation buffer.
Definition: buffer.h:36
char * dptr
Current read/write position.
Definition: buffer.h:38
char * data
Pointer to data.
Definition: buffer.h:37
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
+ 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 201 of file recvattach.c.

202{
203 return (b->email && (b->encoding != ENC_BASE64) && (b->encoding != ENC_QUOTED_PRINTABLE) &&
205}
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1498
@ 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 232 of file recvattach.c.

234{
235 int rc = -1;
236
238 {
239 struct Body b_fake = { 0 };
240
241 struct Buffer *tempfile = buf_pool_get();
242 buf_mktemp(tempfile);
243
244 rc = mutt_save_attachment(fp, b, buf_string(tempfile), MUTT_SAVE_NO_FLAGS, e);
245 if (rc != 0)
246 goto cleanup;
247
249
250 /* Now "really" save it. Send mode does this without touching anything,
251 * so force send-mode. */
252 memset(&b_fake, 0, sizeof(struct Body));
253 b_fake.filename = tempfile->data;
254 rc = mutt_save_attachment(NULL, &b_fake, path, flags, e);
255
256 mutt_file_unlink(buf_string(tempfile));
257
258 cleanup:
259 buf_pool_release(&tempfile);
260 }
261 else
262 {
263 rc = mutt_save_attachment(fp, b, path, flags, e);
264 }
265
266 return rc;
267}
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:159
int mutt_save_attachment(FILE *fp, struct Body *b, const char *path, enum SaveAttach opt, struct Email *e)
Save an attachment.
Definition: mutt_attach.c:905
@ 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:518
bool mutt_rfc3676_is_format_flowed(struct Body *b)
Is the Email "format-flowed"?
Definition: rfc3676.c:394
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
#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 278 of file recvattach.c.

279{
280 char *prompt = NULL;
282 int rc = -1;
283
284 struct Buffer *buf = buf_pool_get();
285 struct Buffer *tfile = buf_pool_get();
286
287 if (b->filename)
288 {
289 if (directory && *directory)
290 {
291 buf_concat_path(buf, *directory, mutt_path_basename(b->filename));
292 }
293 else
294 {
295 buf_strcpy(buf, b->filename);
296 }
297 }
298 else if (has_a_message(b))
299 {
300 mutt_default_save(buf, b->email);
301 }
302
303 prepend_savedir(buf);
304
305 prompt = _("Save to file: ");
306 while (prompt)
307 {
308 struct FileCompletionData cdata = { false, NULL, NULL, NULL };
309 if ((mw_get_field(prompt, buf, MUTT_COMP_CLEAR, HC_FILE, &CompleteFileOps, &cdata) != 0) ||
310 buf_is_empty(buf))
311 {
312 goto cleanup;
313 }
314
315 prompt = NULL;
316 buf_expand_path(buf);
317
318 bool is_message = (fp && has_a_message(b));
319
320 if (is_message)
321 {
322 struct stat st = { 0 };
323
324 /* check to make sure that this file is really the one the user wants */
325 rc = mutt_save_confirm(buf_string(buf), &st);
326 if (rc == 1)
327 {
328 prompt = _("Save to file: ");
329 continue;
330 }
331 else if (rc == -1)
332 {
333 goto cleanup;
334 }
335 buf_copy(tfile, buf);
336 }
337 else
338 {
339 rc = mutt_check_overwrite(b->filename, buf_string(buf), tfile, &opt, directory);
340 if (rc == -1)
341 {
342 goto cleanup;
343 }
344 else if (rc == 1)
345 {
346 prompt = _("Save to file: ");
347 continue;
348 }
349 }
350
351 mutt_message(_("Saving..."));
352 if (save_attachment_flowed_helper(fp, b, buf_string(tfile), opt,
353 (e || !is_message) ? e : b->email) == 0)
354 {
355 // This uses ngettext to avoid duplication of messages
356 int num = 1;
357 mutt_message(ngettext("Attachment saved", "%d attachments saved", num), num);
358 rc = 0;
359 goto cleanup;
360 }
361 else
362 {
363 prompt = _("Save to file: ");
364 continue;
365 }
366 }
367
368cleanup:
369 buf_pool_release(&buf);
370 buf_pool_release(&tfile);
371 return rc;
372}
const struct CompleteOps CompleteFileOps
Auto-Completion of Files.
Definition: complete.c:153
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:291
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
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
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:273
#define mutt_message(...)
Definition: logging2.h:91
@ HC_FILE
Files.
Definition: lib.h:56
void mutt_default_save(struct Buffer *path, struct Email *e)
Find the default save path for an email.
Definition: hook.c:777
#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
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:57
SaveAttach
Options for saving attachments.
Definition: mutt_attach.h:57
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:315
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:541
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition: muttlib.c:745
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:232
static void prepend_savedir(struct Buffer *buf)
Add $attach_save_dir to the beginning of a path.
Definition: recvattach.c:173
static bool has_a_message(struct Body *b)
Determine if the Body has a message (to save)
Definition: recvattach.c:201
Input for the file completion function.
Definition: curs_lib.h:40
+ 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 382 of file recvattach.c.

383{
385 int rc = -1;
386 struct Buffer *buf = buf_pool_get();
387 struct Buffer *tfile = buf_pool_get();
388
389 if (b->filename)
390 {
391 buf_strcpy(buf, b->filename);
392 }
393 else if (has_a_message(b))
394 {
395 mutt_default_save(buf, b->email);
396 }
397
398 prepend_savedir(buf);
399 buf_expand_path(buf);
400
401 bool is_message = (fp && has_a_message(b));
402
403 if (is_message)
404 {
405 buf_copy(tfile, buf);
406 }
407 else
408 {
409 rc = mutt_check_overwrite(b->filename, buf_string(buf), tfile, &opt, NULL);
410 if (rc == -1) // abort or cancel
411 goto cleanup;
412 }
413
414 rc = save_attachment_flowed_helper(fp, b, buf_string(tfile), opt,
415 (e || !is_message) ? e : b->email);
416
417cleanup:
418 buf_pool_release(&buf);
419 buf_pool_release(&tfile);
420 return rc;
421}
+ 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 432 of file recvattach.c.

434{
435 char *directory = NULL;
436 int rc = 1;
437 int last = menu_get_index(menu);
438 FILE *fp_out = NULL;
439 int saved_attachments = 0;
440
441 struct Buffer *buf = buf_pool_get();
442 struct Buffer *tfile = buf_pool_get();
443
444 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
445 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
446 const bool c_attach_save_without_prompting = cs_subset_bool(NeoMutt->sub, "attach_save_without_prompting");
447
448 for (int i = 0; !tag || (i < actx->idxlen); i++)
449 {
450 if (tag)
451 {
452 fp = actx->idx[i]->fp;
453 b = actx->idx[i]->body;
454 }
455 if (!tag || b->tagged)
456 {
457 if (c_attach_split)
458 {
459 if (tag && menu && b->aptr)
460 {
461 menu_set_index(menu, b->aptr->num);
463
464 menu_redraw(menu);
465 }
466 if (c_attach_save_without_prompting)
467 {
468 // Save each file, with no prompting, using the configured 'AttachSaveDir'
469 rc = save_without_prompting(fp, b, e);
470 if (rc == 0)
471 saved_attachments++;
472 }
473 else
474 {
475 // Save each file, prompting the user for the location each time.
476 if (query_save_attachment(fp, b, e, &directory) == -1)
477 break;
478 }
479 }
480 else
481 {
483
484 if (buf_is_empty(buf))
485 {
487 prepend_savedir(buf);
488
489 struct FileCompletionData cdata = { false, NULL, NULL, NULL };
490 if ((mw_get_field(_("Save to file: "), buf, MUTT_COMP_CLEAR, HC_FILE,
491 &CompleteFileOps, &cdata) != 0) ||
492 buf_is_empty(buf))
493 {
494 goto cleanup;
495 }
496 buf_expand_path(buf);
497 if (mutt_check_overwrite(b->filename, buf_string(buf), tfile, &opt, NULL))
498 goto cleanup;
499 }
500 else
501 {
502 opt = MUTT_SAVE_APPEND;
503 }
504
505 rc = save_attachment_flowed_helper(fp, b, buf_string(tfile), opt, e);
506 if ((rc == 0) && c_attach_sep && (fp_out = mutt_file_fopen(buf_string(tfile), "a")))
507 {
508 fprintf(fp_out, "%s", c_attach_sep);
509 mutt_file_fclose(&fp_out);
510 }
511 }
512 }
513 if (!tag)
514 break;
515 }
516
517 FREE(&directory);
518
519 if (tag && menu)
520 {
521 menu_set_index(menu, last);
523 }
524
525 if (rc == 0)
526 {
527 if (!c_attach_split)
528 saved_attachments = 1;
529
530 if (!c_attach_split || c_attach_save_without_prompting)
531 {
532 mutt_message(ngettext("Attachment saved", "%d attachments saved", saved_attachments),
533 saved_attachments);
534 }
535 }
536
537cleanup:
538 buf_pool_release(&buf);
539 buf_pool_release(&tfile);
540}
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:481
#define mutt_file_fclose(FP)
Definition: file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:138
#define FREE(x)
Definition: memory.h:55
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition: menu.c:184
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:174
#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:59
static int save_without_prompting(FILE *fp, struct Body *b, struct Email *e)
Save the attachment, without prompting each time.
Definition: recvattach.c:382
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:278
#define NONULL(x)
Definition: string2.h:37
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 549 of file recvattach.c.

550{
551 struct Buffer *tfile = buf_pool_get();
552
553 if (filter)
554 {
555 char warning[PATH_MAX + 256];
556 snprintf(warning, sizeof(warning),
557 _("WARNING! You are about to overwrite %s, continue?"), b->filename);
558 if (query_yesorno(warning, MUTT_NO) != MUTT_YES)
559 {
560 msgwin_clear_text(NULL);
561 buf_pool_release(&tfile);
562 return;
563 }
564 buf_mktemp(tfile);
565 }
566
567 if (mutt_pipe_attachment(fp, b, command, buf_string(tfile)))
568 {
569 if (filter)
570 {
574 mutt_message(_("Attachment filtered"));
575 }
576 }
577 else
578 {
579 if (filter && !buf_is_empty(tfile))
581 }
582 buf_pool_release(&tfile);
583}
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition: file.c:1264
void msgwin_clear_text(struct MuttWindow *win)
Clear the text in the Message Window.
Definition: msgwin.c:519
#define PATH_MAX
Definition: mutt.h:42
int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, const char *outfile)
Pipe an attachment to a command.
Definition: mutt_attach.c:739
@ 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:327
void mutt_update_encoding(struct Body *b, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:422
+ 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 591 of file recvattach.c.

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

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

726{
727 struct State state = { 0 };
728 struct Buffer *buf = NULL;
729
730 if (fp)
731 filter = false; /* sanity check: we can't filter in the recv case yet */
732
733 buf = buf_pool_get();
734 /* perform charset conversion on text attachments when piping */
735 state.flags = STATE_CHARCONV;
736
737 if (mw_get_field((filter ? _("Filter through: ") : _("Pipe to: ")), buf,
739 {
740 goto cleanup;
741 }
742
743 if (buf_is_empty(buf))
744 goto cleanup;
745
746 buf_expand_path(buf);
747
748 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
749 if (!filter && !c_attach_split)
750 {
751 mutt_endwin();
752 pid_t pid = filter_create(buf_string(buf), &state.fp_out, NULL, NULL, EnvList);
753 pipe_attachment_list(buf_string(buf), actx, fp, tag, b, filter, &state);
754 mutt_file_fclose(&state.fp_out);
755 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
756 if ((filter_wait(pid) != 0) || c_wait_key)
758 }
759 else
760 {
761 pipe_attachment_list(buf_string(buf), actx, fp, tag, b, filter, &state);
762 }
763
764cleanup:
765 buf_pool_release(&buf);
766}
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
char ** EnvList
Private copy of the environment variables.
Definition: globals.c:75
@ HC_EXT_COMMAND
External commands.
Definition: lib.h:53
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:220
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, char **envlist)
Set up filter program.
Definition: filter.c:209
#define STATE_CHARCONV
Do character set conversions.
Definition: state.h:37
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:56
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:692
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 775 of file recvattach.c.

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

817{
818 char type[256] = { 0 };
819
820 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
821 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
822
823 for (int i = 0; !tag || (i < actx->idxlen); i++)
824 {
825 if (tag)
826 {
827 fp = actx->idx[i]->fp;
828 b = actx->idx[i]->body;
829 }
830 if (!tag || b->tagged)
831 {
832 snprintf(type, sizeof(type), "%s/%s", TYPE(b), b->subtype);
833 if (!c_attach_split && !mailcap_lookup(b, type, sizeof(type), NULL, MUTT_MC_PRINT))
834 {
835 if (mutt_istr_equal("text/plain", b->subtype) ||
836 mutt_istr_equal("application/postscript", b->subtype))
837 {
838 pipe_attachment(fp, b, state);
839 }
840 else if (mutt_can_decode(b))
841 {
842 /* decode and print */
843
844 FILE *fp_in = NULL;
845 struct Buffer *newfile = buf_pool_get();
846
847 buf_mktemp(newfile);
848 if (mutt_decode_save_attachment(fp, b, buf_string(newfile),
850 {
851 if (!state->fp_out)
852 {
853 mutt_error("BUG in print_attachment_list(). Please report this. ");
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.
Definition: mutt_attach.c:1039
int mutt_print_attachment(FILE *fp, struct Body *b)
Print out an attachment.
Definition: mutt_attach.c:1137
+ 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, NULL, EnvList);
917 print_attachment_list(actx, fp, tag, b, &state);
918 mutt_file_fclose(&state.fp_out);
919 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
920 if ((filter_wait(pid) != 0) || c_wait_key)
922 }
923}
enum QuadOption query_quadoption(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition: question.c:379
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:815
static bool can_print(struct AttachCtx *actx, struct Body *b, bool tag)
Do we know how to print this attachment type?
Definition: recvattach.c:775
+ 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 931 of file recvattach.c.

932{
933 struct AttachPtr *cur_att = current_attachment(actx, menu);
934 if (!mutt_edit_content_type(e, cur_att->body, cur_att->fp))
935 return;
936
937 /* The mutt_update_recvattach_menu() will overwrite any changes
938 * made to a decrypted cur_att->body, so warn the user. */
939 if (cur_att->decrypted)
940 {
941 mutt_message(_("Structural changes to decrypted attachments are not supported"));
942 mutt_sleep(1);
943 }
944 /* Editing the content type can rewrite the body structure. */
945 for (int i = 0; i < actx->idxlen; i++)
946 actx->idx[i]->body = NULL;
948 mutt_update_recvattach_menu(actx, menu, true);
949}
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:1070
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:842
void mutt_update_recvattach_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
Update the Attachment Menu.
Definition: recvattach.c:1213
struct AttachPtr * current_attachment(struct AttachCtx *actx, struct Menu *menu)
Get the current attachment.
Definition: recvattach.c:77
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 961 of file recvattach.c.

963{
964 do
965 {
966 switch (op)
967 {
968 case OP_DISPLAY_HEADERS:
969 bool_str_toggle(NeoMutt->sub, "weed", NULL);
971
972 case OP_ATTACHMENT_VIEW:
973 {
974 struct AttachPtr *cur_att = current_attachment(actx, menu);
975 if (!cur_att->fp)
976 {
977 if (cur_att->body->type == TYPE_MULTIPART)
978 {
979 struct Body *b = cur_att->body->parts;
980 while (b->parts)
981 b = b->parts;
982 cur_att = b->aptr;
983 }
984 }
985 op = mutt_view_attachment(cur_att->fp, cur_att->body, MUTT_VA_REGULAR,
986 e, actx, menu->win);
987 break;
988 }
989
990 case OP_NEXT_ENTRY:
991 case OP_MAIN_NEXT_UNDELETED: /* hack */
992 {
993 const int index = menu_get_index(menu) + 1;
994 if (index < menu->max)
995 {
996 menu_set_index(menu, index);
997 op = OP_ATTACHMENT_VIEW;
998 }
999 else
1000 {
1001 op = OP_NULL;
1002 }
1003 break;
1004 }
1005
1006 case OP_PREV_ENTRY:
1007 case OP_MAIN_PREV_UNDELETED: /* hack */
1008 {
1009 const int index = menu_get_index(menu) - 1;
1010 if (index >= 0)
1011 {
1012 menu_set_index(menu, index);
1013 op = OP_ATTACHMENT_VIEW;
1014 }
1015 else
1016 {
1017 op = OP_NULL;
1018 }
1019 break;
1020 }
1021
1022 case OP_ATTACHMENT_EDIT_TYPE:
1023 {
1024 struct AttachPtr *cur_att = current_attachment(actx, menu);
1025 /* when we edit the content-type, we should redisplay the attachment
1026 * immediately */
1027 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1028 if (recv)
1029 recvattach_edit_content_type(actx, menu, e);
1030 else
1031 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1032
1034 op = OP_ATTACHMENT_VIEW;
1035 break;
1036 }
1037 /* functions which are passed through from the pager */
1038 case OP_PIPE:
1039 {
1040 struct AttachPtr *cur_att = current_attachment(actx, menu);
1041 mutt_pipe_attachment_list(actx, cur_att->fp, false, cur_att->body, false);
1042 op = OP_ATTACHMENT_VIEW;
1043 break;
1044 }
1045 case OP_ATTACHMENT_PRINT:
1046 {
1047 struct AttachPtr *cur_att = current_attachment(actx, menu);
1048 mutt_print_attachment_list(actx, cur_att->fp, false, cur_att->body);
1049 op = OP_ATTACHMENT_VIEW;
1050 break;
1051 }
1052 case OP_ATTACHMENT_SAVE:
1053 {
1054 struct AttachPtr *cur_att = current_attachment(actx, menu);
1055 mutt_save_attachment_list(actx, cur_att->fp, false, cur_att->body, e, NULL);
1056 op = OP_ATTACHMENT_VIEW;
1057 break;
1058 }
1059 case OP_CHECK_TRADITIONAL:
1061 {
1062 op = OP_NULL;
1063 break;
1064 }
1066
1067 case OP_ATTACHMENT_COLLAPSE:
1068 if (recv)
1069 return op;
1071
1072 default:
1073 op = OP_NULL;
1074 }
1075 } while (op != OP_NULL);
1076
1077 return op;
1078}
int bool_str_toggle(struct ConfigSubset *sub, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition: bool.c:224
#define MENU_REDRAW_INDEX
Redraw the index.
Definition: lib.h:56
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
#define FALLTHROUGH
Definition: lib.h:111
int mutt_view_attachment(FILE *fp, struct Body *b, enum ViewAttachMode mode, struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
View an attachment.
Definition: mutt_attach.c:419
@ 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:98
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:96
#define WithCrypto
Definition: lib.h:122
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:432
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:724
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:931
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:86
+ 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 1090 of file recvattach.c.

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

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

1214{
1215 if (init)
1216 {
1217 mutt_generate_recvattach_list(actx, actx->email, actx->email->body,
1218 actx->fp_root, -1, 0, 0);
1219 mutt_attach_init(actx);
1220 }
1221
1222 mutt_update_tree(actx);
1223
1224 menu->max = actx->vcount;
1225
1226 const int index = menu_get_index(menu);
1227 if (index >= menu->max)
1228 menu_set_index(menu, menu->max - 1);
1230}
void mutt_attach_init(struct AttachCtx *actx)
Create a new Attachment context.
Definition: recvattach.c:1188
void mutt_update_tree(struct AttachCtx *actx)
Refresh the list of attachments.
Definition: recvattach.c:122
FILE * fp_root
Used by recvattach for updating.
Definition: attach.h:65
int max
Number of entries in the menu.
Definition: lib.h:81
+ 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 1240 of file recvattach.c.

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