NeoMutt
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 *body)
 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 *body, struct Email *e, char **directory)
 Ask the user if we should save the attachment.
 
static int save_without_prompting (FILE *fp, struct Body *body, struct Email *e)
 Save the attachment, without prompting each time.
 
void mutt_save_attachment_list (struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, struct Email *e, struct Menu *menu)
 Save a list of attachments.
 
static void query_pipe_attachment (const char *command, FILE *fp, struct Body *body, 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 *top, bool filter)
 Pipe a list of attachments to a command.
 
static bool can_print (struct AttachCtx *actx, struct Body *top, 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 *top, struct State *state)
 Print a list of Attachments.
 
void mutt_print_attachment_list (struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top)
 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 *parts, 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
  • Michael R. Elkins
  • Thomas Roessler

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file recvattach.c.

Function Documentation

◆ current_attachment()

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

Get the current attachment.

Parameters
actxAttachment context
menuMenu
Return values
ptrCurrent Attachment

Definition at line 71 of file recvattach.c.

72{
73 const int virt = menu_get_index(menu);
74 const int index = actx->v2r[virt];
75
76 return actx->idx[index];
77}
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:156
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 85 of file recvattach.c.

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

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

168{
169 if (!buf || !buf->data || (buf->data[0] == '/'))
170 return;
171
172 struct Buffer *tmp = buf_pool_get();
173 const char *const c_attach_save_dir = cs_subset_path(NeoMutt->sub, "attach_save_dir");
174 if (c_attach_save_dir)
175 {
176 buf_addstr(tmp, c_attach_save_dir);
177 if (tmp->dptr[-1] != '/')
178 buf_addch(tmp, '/');
179 }
180 else
181 {
182 buf_addstr(tmp, "./");
183 }
184
185 buf_addstr(tmp, buf_string(buf));
186 buf_copy(buf, tmp);
187 buf_pool_release(&tmp);
188}
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:253
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:238
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:572
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
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:34
char * dptr
Current read/write position.
Definition: buffer.h:36
char * data
Pointer to data.
Definition: buffer.h:35
Container for Accounts, Notifications.
Definition: neomutt.h: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 body)
static

Determine if the Body has a message (to save)

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

Definition at line 195 of file recvattach.c.

196{
197 return (body->email && (body->encoding != ENC_BASE64) &&
198 (body->encoding != ENC_QUOTED_PRINTABLE) &&
199 mutt_is_message_type(body->type, body->subtype));
200}
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1482
@ 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 227 of file recvattach.c.

229{
230 int rc = -1;
231
233 {
234 struct Body b_fake = { 0 };
235
236 struct Buffer *tempfile = buf_pool_get();
237 buf_mktemp(tempfile);
238
239 /* Pass MUTT_SAVE_NO_FLAGS to force mutt_file_fopen("w") */
240 rc = mutt_save_attachment(fp, b, buf_string(tempfile), MUTT_SAVE_NO_FLAGS, e);
241 if (rc != 0)
242 goto cleanup;
243
245
246 /* Now "really" save it. Send mode does this without touching anything,
247 * so force send-mode. */
248 memset(&b_fake, 0, sizeof(struct Body));
249 b_fake.filename = tempfile->data;
250 rc = mutt_save_attachment(NULL, &b_fake, path, flags, e);
251
252 mutt_file_unlink(buf_string(tempfile));
253
254 cleanup:
255 buf_pool_release(&tempfile);
256 }
257 else
258 {
259 rc = mutt_save_attachment(fp, b, path, flags, e);
260 }
261
262 return rc;
263}
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:196
int mutt_save_attachment(FILE *fp, struct Body *m, const char *path, enum SaveAttach opt, struct Email *e)
Save an attachment.
Definition: mutt_attach.c:914
@ 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:515
bool mutt_rfc3676_is_format_flowed(struct Body *b)
Is the Email "format-flowed"?
Definition: rfc3676.c:391
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 body,
struct Email e,
char **  directory 
)
static

Ask the user if we should save the attachment.

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

Definition at line 274 of file recvattach.c.

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

◆ save_without_prompting()

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

Save the attachment, without prompting each time.

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

Definition at line 379 of file recvattach.c.

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

◆ mutt_save_attachment_list()

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

Save a list of attachments.

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

Definition at line 429 of file recvattach.c.

431{
432 char *directory = NULL;
433 int rc = 1;
434 int last = menu_get_index(menu);
435 FILE *fp_out = NULL;
436 int saved_attachments = 0;
437
438 struct Buffer *buf = buf_pool_get();
439 struct Buffer *tfile = buf_pool_get();
440
441 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
442 const char *const c_attach_sep = cs_subset_string(NeoMutt->sub, "attach_sep");
443 const bool c_attach_save_without_prompting = cs_subset_bool(NeoMutt->sub, "attach_save_without_prompting");
444
445 for (int i = 0; !tag || (i < actx->idxlen); i++)
446 {
447 if (tag)
448 {
449 fp = actx->idx[i]->fp;
450 top = actx->idx[i]->body;
451 }
452 if (!tag || top->tagged)
453 {
454 if (c_attach_split)
455 {
456 if (tag && menu && top->aptr)
457 {
458 menu_set_index(menu, top->aptr->num);
460
461 menu_redraw(menu);
462 }
463 if (c_attach_save_without_prompting)
464 {
465 // Save each file, with no prompting, using the configured 'AttachSaveDir'
466 rc = save_without_prompting(fp, top, e);
467 if (rc == 0)
468 saved_attachments++;
469 }
470 else
471 {
472 // Save each file, prompting the user for the location each time.
473 if (query_save_attachment(fp, top, e, &directory) == -1)
474 break;
475 }
476 }
477 else
478 {
480
481 if (buf_is_empty(buf))
482 {
484 prepend_savedir(buf);
485
486 struct FileCompletionData cdata = { false, NULL, NULL, NULL };
487 if ((mw_get_field(_("Save to file: "), buf, MUTT_COMP_CLEAR, HC_FILE,
488 &CompleteMailboxOps, &cdata) != 0) ||
489 buf_is_empty(buf))
490 {
491 goto cleanup;
492 }
493 buf_expand_path(buf);
494 if (mutt_check_overwrite(top->filename, buf_string(buf), tfile, &opt, NULL))
495 goto cleanup;
496 }
497 else
498 {
499 opt = MUTT_SAVE_APPEND;
500 }
501
502 rc = save_attachment_flowed_helper(fp, top, buf_string(tfile), opt, e);
503 if ((rc == 0) && c_attach_sep && (fp_out = fopen(buf_string(tfile), "a")))
504 {
505 fprintf(fp_out, "%s", c_attach_sep);
506 mutt_file_fclose(&fp_out);
507 }
508 }
509 }
510 if (!tag)
511 break;
512 }
513
514 FREE(&directory);
515
516 if (tag && menu)
517 {
518 menu_set_index(menu, last);
520 }
521
522 if (rc == 0)
523 {
524 if (!c_attach_split)
525 saved_attachments = 1;
526
527 if (!c_attach_split || c_attach_save_without_prompting)
528 {
529 mutt_message(ngettext("Attachment saved", "%d attachments saved", saved_attachments),
530 saved_attachments);
531 }
532 }
533
534cleanup:
535 buf_pool_release(&buf);
536 buf_pool_release(&tfile);
537}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c: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:474
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
#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:180
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:170
#define MENU_REDRAW_MOTION
Redraw after moving the menu list.
Definition: lib.h:58
@ MUTT_SAVE_APPEND
Append to existing file.
Definition: mutt_attach.h:59
static int save_without_prompting(FILE *fp, struct Body *body, struct Email *e)
Save the attachment, without prompting each time.
Definition: recvattach.c:379
static int query_save_attachment(FILE *fp, struct Body *body, struct Email *e, char **directory)
Ask the user if we should save the attachment.
Definition: recvattach.c:274
#define NONULL(x)
Definition: string2.h:37
short idxlen
Number of attachmentes.
Definition: attach.h:56
FILE * fp
Used in the recvattach menu.
Definition: attach.h:37
struct AttachPtr * aptr
Menu information, used in recvattach.c.
Definition: body.h:74
bool tagged
This attachment is tagged.
Definition: body.h:89
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ query_pipe_attachment()

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

Ask the user if we should pipe the attachment.

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

Definition at line 546 of file recvattach.c.

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

◆ pipe_attachment()

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

Pipe the attachment to a command.

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

Definition at line 588 of file recvattach.c.

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

◆ pipe_attachment_list()

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

Pipe a list of attachments to a command.

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

Definition at line 689 of file recvattach.c.

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

◆ mutt_pipe_attachment_list()

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

Pipe a list of attachments to a command.

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

Definition at line 721 of file recvattach.c.

723{
724 struct State state = { 0 };
725 struct Buffer *buf = NULL;
726
727 if (fp)
728 filter = false; /* sanity check: we can't filter in the recv case yet */
729
730 buf = buf_pool_get();
731 /* perform charset conversion on text attachments when piping */
732 state.flags = STATE_CHARCONV;
733
734 if (mw_get_field((filter ? _("Filter through: ") : _("Pipe to: ")), buf,
736 {
737 goto cleanup;
738 }
739
740 if (buf_len(buf) == 0)
741 goto cleanup;
742
743 buf_expand_path(buf);
744
745 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
746 if (!filter && !c_attach_split)
747 {
748 mutt_endwin();
749 pid_t pid = filter_create(buf_string(buf), &state.fp_out, NULL, NULL, EnvList);
750 pipe_attachment_list(buf_string(buf), actx, fp, tag, top, filter, &state);
751 mutt_file_fclose(&state.fp_out);
752 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
753 if ((filter_wait(pid) != 0) || c_wait_key)
755 }
756 else
757 {
758 pipe_attachment_list(buf_string(buf), actx, fp, tag, top, filter, &state);
759 }
760
761cleanup:
762 buf_pool_release(&buf);
763}
const struct CompleteOps CompleteFileOps
Auto-Completion of Files.
Definition: complete.c:153
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:466
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:188
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:154
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:218
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:207
char ** EnvList
Private copy of the environment variables.
Definition: globals.c:85
@ HC_COMMAND
NeoMutt commands.
Definition: lib.h:51
#define STATE_CHARCONV
Do character set conversions.
Definition: state.h:36
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:55
static void pipe_attachment_list(const char *command, struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, bool filter, struct State *state)
Pipe a list of attachments to a command.
Definition: recvattach.c:689
Keep track when processing files.
Definition: state.h:47
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition: state.h:51
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ can_print()

static bool can_print ( struct AttachCtx actx,
struct Body top,
bool  tag 
)
static

Do we know how to print this attachment type?

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

Definition at line 772 of file recvattach.c.

773{
774 char type[256] = { 0 };
775
776 for (int i = 0; !tag || (i < actx->idxlen); i++)
777 {
778 if (tag)
779 top = actx->idx[i]->body;
780 snprintf(type, sizeof(type), "%s/%s", TYPE(top), top->subtype);
781 if (!tag || top->tagged)
782 {
783 if (!mailcap_lookup(top, type, sizeof(type), NULL, MUTT_MC_PRINT))
784 {
785 if (!mutt_istr_equal("text/plain", top->subtype) &&
786 !mutt_istr_equal("application/postscript", top->subtype))
787 {
788 if (!mutt_can_decode(top))
789 {
790 /* L10N: s gets replaced by a MIME type, e.g. "text/plain" or
791 application/octet-stream. */
792 mutt_error(_("I don't know how to print %s attachments"), type);
793 return false;
794 }
795 }
796 }
797 }
798 if (!tag)
799 break;
800 }
801 return true;
802}
#define mutt_error(...)
Definition: logging2.h:92
bool mutt_can_decode(struct Body *b)
Will decoding the attachment produce any output.
Definition: handler.c:1852
bool mailcap_lookup(struct Body *a, char *type, size_t typelen, struct MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: mailcap.c:480
@ MUTT_MC_PRINT
Mailcap print field.
Definition: mailcap.h:59
#define TYPE(body)
Definition: mime.h:89
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:810
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ print_attachment_list()

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

Print a list of Attachments.

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

Definition at line 812 of file recvattach.c.

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

◆ mutt_print_attachment_list()

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

Print a list of Attachments.

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

Definition at line 884 of file recvattach.c.

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

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

◆ mutt_attach_display_loop()

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

Event loop for the Attachment menu.

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

Definition at line 958 of file recvattach.c.

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

◆ mutt_generate_recvattach_list()

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

Create a list of attachments.

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

Definition at line 1085 of file recvattach.c.

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

◆ mutt_attach_init()

void mutt_attach_init ( struct AttachCtx actx)

Create a new Attachment context.

Parameters
actxAttachment context

Definition at line 1183 of file recvattach.c.

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

◆ mutt_update_recvattach_menu()

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

Update the Attachment Menu.

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

Definition at line 1208 of file recvattach.c.

1209{
1210 if (init)
1211 {
1212 mutt_generate_recvattach_list(actx, actx->email, actx->email->body,
1213 actx->fp_root, -1, 0, 0);
1214 mutt_attach_init(actx);
1215 }
1216
1217 mutt_update_tree(actx);
1218
1219 menu->max = actx->vcount;
1220
1221 const int index = menu_get_index(menu);
1222 if (index >= menu->max)
1223 menu_set_index(menu, menu->max - 1);
1225}
void mutt_attach_init(struct AttachCtx *actx)
Create a new Attachment context.
Definition: recvattach.c:1183
void mutt_update_tree(struct AttachCtx *actx)
Refresh the list of attachments.
Definition: recvattach.c:116
FILE * fp_root
Used by recvattach for updating.
Definition: attach.h:53
int max
Number of entries in the menu.
Definition: lib.h:72
+ 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 1235 of file recvattach.c.

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