NeoMutt  2024-02-01-35-geee02f
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 <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 "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:159
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 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: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 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) ? '\005' : '\006';
164 *s++ = '\006';
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:709
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:329
@ 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_HLINE
Horizontal line.
Definition: mutt_thread.h:61
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: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 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:258
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:243
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:618
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:97
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:169
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
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:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
+ 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:1454
@ 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: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 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 /* Pass MUTT_SAVE_NO_FLAGS to force mutt_file_fopen("w") */
245 rc = mutt_save_attachment(fp, b, buf_string(tempfile), MUTT_SAVE_NO_FLAGS, e);
246 if (rc != 0)
247 goto cleanup;
248
250
251 /* Now "really" save it. Send mode does this without touching anything,
252 * so force send-mode. */
253 memset(&b_fake, 0, sizeof(struct Body));
254 b_fake.filename = tempfile->data;
255 rc = mutt_save_attachment(NULL, &b_fake, path, flags, e);
256
257 mutt_file_unlink(buf_string(tempfile));
258
259 cleanup:
260 buf_pool_release(&tempfile);
261 }
262 else
263 {
264 rc = mutt_save_attachment(fp, b, path, flags, e);
265 }
266
267 return rc;
268}
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:216
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
No flags set.
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:58
#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 279 of file recvattach.c.

280{
281 char *prompt = NULL;
283 int rc = -1;
284
285 struct Buffer *buf = buf_pool_get();
286 struct Buffer *tfile = buf_pool_get();
287
288 if (b->filename)
289 {
290 if (directory && *directory)
291 {
292 buf_concat_path(buf, *directory, mutt_path_basename(b->filename));
293 }
294 else
295 {
296 buf_strcpy(buf, b->filename);
297 }
298 }
299 else if (has_a_message(b))
300 {
301 mutt_default_save(buf, b->email);
302 }
303
304 prepend_savedir(buf);
305
306 prompt = _("Save to file: ");
307 while (prompt)
308 {
309 struct FileCompletionData cdata = { false, NULL, NULL, NULL };
310 if ((mw_get_field(prompt, buf, MUTT_COMP_CLEAR, HC_FILE, &CompleteFileOps, &cdata) != 0) ||
311 buf_is_empty(buf))
312 {
313 goto cleanup;
314 }
315
316 prompt = NULL;
317 buf_expand_path(buf);
318
319 bool is_message = (fp && has_a_message(b));
320
321 if (is_message)
322 {
323 struct stat st = { 0 };
324
325 /* check to make sure that this file is really the one the user wants */
326 rc = mutt_save_confirm(buf_string(buf), &st);
327 if (rc == 1)
328 {
329 prompt = _("Save to file: ");
330 continue;
331 }
332 else if (rc == -1)
333 {
334 goto cleanup;
335 }
336 buf_copy(tfile, buf);
337 }
338 else
339 {
340 rc = mutt_check_overwrite(b->filename, buf_string(buf), tfile, &opt, directory);
341 if (rc == -1)
342 {
343 goto cleanup;
344 }
345 else if (rc == 1)
346 {
347 prompt = _("Save to file: ");
348 continue;
349 }
350 }
351
352 mutt_message(_("Saving..."));
353 if (save_attachment_flowed_helper(fp, b, buf_string(tfile), opt,
354 (e || !is_message) ? e : b->email) == 0)
355 {
356 // This uses ngettext to avoid duplication of messages
357 const int num = 1;
358 mutt_message(ngettext("Attachment saved", "%d attachments saved", num), num);
359 rc = 0;
360 goto cleanup;
361 }
362 else
363 {
364 prompt = _("Save to file: ");
365 continue;
366 }
367 }
368
369cleanup:
370 buf_pool_release(&buf);
371 buf_pool_release(&tfile);
372 return rc;
373}
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:308
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:412
size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:526
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:274
#define mutt_message(...)
Definition: logging2.h:91
@ HC_FILE
Files.
Definition: lib.h:54
void mutt_default_save(struct Buffer *path, struct Email *e)
Find the default save path for an email.
Definition: hook.c:748
#define _(a)
Definition: message.h:28
const char * mutt_path_basename(const char *path)
Find the last component for a pathname.
Definition: path.c:281
#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:331
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:579
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition: muttlib.c:1324
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 383 of file recvattach.c.

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

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

551{
552 struct Buffer *tfile = buf_pool_get();
553
554 if (filter)
555 {
556 char warning[PATH_MAX + 256];
557 snprintf(warning, sizeof(warning),
558 _("WARNING! You are about to overwrite %s, continue?"), b->filename);
559 if (query_yesorno(warning, MUTT_NO) != MUTT_YES)
560 {
561 msgwin_clear_text(NULL);
562 buf_pool_release(&tfile);
563 return;
564 }
565 buf_mktemp(tfile);
566 }
567
568 if (mutt_pipe_attachment(fp, b, command, buf_string(tfile)))
569 {
570 if (filter)
571 {
575 mutt_message(_("Attachment filtered"));
576 }
577 }
578 else
579 {
580 if (filter && !buf_is_empty(tfile))
582 }
583 buf_pool_release(&tfile);
584}
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition: file.c:1412
void msgwin_clear_text(struct MuttWindow *win)
Clear the text in the Message Window.
Definition: msgwin.c:516
#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:737
@ 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:334
void mutt_update_encoding(struct Body *b, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:421
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pipe_attachment()

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

Pipe the attachment to a command.

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

Definition at line 592 of file recvattach.c.

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

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

727{
728 struct State state = { 0 };
729 struct Buffer *buf = NULL;
730
731 if (fp)
732 filter = false; /* sanity check: we can't filter in the recv case yet */
733
734 buf = buf_pool_get();
735 /* perform charset conversion on text attachments when piping */
736 state.flags = STATE_CHARCONV;
737
738 if (mw_get_field((filter ? _("Filter through: ") : _("Pipe to: ")), buf,
740 {
741 goto cleanup;
742 }
743
744 if (buf_is_empty(buf))
745 goto cleanup;
746
747 buf_expand_path(buf);
748
749 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
750 if (!filter && !c_attach_split)
751 {
752 mutt_endwin();
753 pid_t pid = filter_create(buf_string(buf), &state.fp_out, NULL, NULL, EnvList);
754 pipe_attachment_list(buf_string(buf), actx, fp, tag, b, filter, &state);
755 mutt_file_fclose(&state.fp_out);
756 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
757 if ((filter_wait(pid) != 0) || c_wait_key)
759 }
760 else
761 {
762 pipe_attachment_list(buf_string(buf), actx, fp, tag, b, filter, &state);
763 }
764
765cleanup:
766 buf_pool_release(&buf);
767}
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:175
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:153
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:219
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:208
char ** EnvList
Private copy of the environment variables.
Definition: globals.c:78
@ HC_EXT_COMMAND
External commands.
Definition: lib.h:51
#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:693
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 776 of file recvattach.c.

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

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

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

◆ recvattach_edit_content_type()

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

Edit the content type of an attachment.

Parameters
actxAttachment context
menuMenu listing Attachments
eEmail

Definition at line 932 of file recvattach.c.

933{
934 struct AttachPtr *cur_att = current_attachment(actx, menu);
935 if (!mutt_edit_content_type(e, cur_att->body, cur_att->fp))
936 return;
937
938 /* The mutt_update_recvattach_menu() will overwrite any changes
939 * made to a decrypted cur_att->body, so warn the user. */
940 if (cur_att->decrypted)
941 {
942 mutt_message(_("Structural changes to decrypted attachments are not supported"));
943 mutt_sleep(1);
944 }
945 /* Editing the content type can rewrite the body structure. */
946 for (int i = 0; i < actx->idxlen; i++)
947 actx->idx[i]->body = NULL;
949 mutt_update_recvattach_menu(actx, menu, true);
950}
void mutt_actx_entries_free(struct AttachCtx *actx)
Free entries in an Attachment Context.
Definition: attach.c:162
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition: external.c:1073
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1421
void mutt_update_recvattach_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
Update the Attachment Menu.
Definition: recvattach.c:1214
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 962 of file recvattach.c.

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

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

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

1215{
1216 if (init)
1217 {
1218 mutt_generate_recvattach_list(actx, actx->email, actx->email->body,
1219 actx->fp_root, -1, 0, 0);
1220 mutt_attach_init(actx);
1221 }
1222
1223 mutt_update_tree(actx);
1224
1225 menu->max = actx->vcount;
1226
1227 const int index = menu_get_index(menu);
1228 if (index >= menu->max)
1229 menu_set_index(menu, menu->max - 1);
1231}
void mutt_attach_init(struct AttachCtx *actx)
Create a new Attachment context.
Definition: recvattach.c:1189
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: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 1241 of file recvattach.c.

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