NeoMutt  2023-03-22
Teaching an old dog new tricks
DOXYGEN
recvattach.c File Reference

Attachment code. More...

#include "config.h"
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mutt/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "recvattach.h"
#include "enter/lib.h"
#include "menu/lib.h"
#include "ncrypt/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "attach.h"
#include "external.h"
#include "handler.h"
#include "hook.h"
#include "mailcap.h"
#include "mutt_attach.h"
#include "mutt_thread.h"
#include "muttlib.h"
#include "opcodes.h"
#include "rfc3676.h"
#include <libintl.h>
+ Include dependency graph for recvattach.c:

Go to the source code of this file.

Functions

struct AttachPtrcurrent_attachment (struct AttachCtx *actx, struct Menu *menu)
 Get the current attachment. More...
 
static void mutt_update_v2r (struct AttachCtx *actx)
 Update the virtual list of attachments. More...
 
void mutt_update_tree (struct AttachCtx *actx)
 Refresh the list of attachments. More...
 
static void prepend_savedir (struct Buffer *buf)
 Add $attach_save_dir to the beginning of a path. More...
 
static bool has_a_message (struct Body *body)
 Determine if the Body has a message (to save) More...
 
static int save_attachment_flowed_helper (FILE *fp, struct Body *b, const char *path, enum SaveAttach flags, struct Email *e)
 Helper for unstuffing attachments. More...
 
static int query_save_attachment (FILE *fp, struct Body *body, struct Email *e, char **directory)
 Ask the user if we should save the attachment. More...
 
static int save_without_prompting (FILE *fp, struct Body *body, struct Email *e)
 Save the attachment, without prompting each time. More...
 
void mutt_save_attachment_list (struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, struct Email *e, struct Menu *menu)
 Save a list of attachments. More...
 
static void query_pipe_attachment (const char *command, FILE *fp, struct Body *body, bool filter)
 Ask the user if we should pipe the attachment. More...
 
static void pipe_attachment (FILE *fp, struct Body *b, struct State *state)
 Pipe the attachment to a command. More...
 
static void pipe_attachment_list (const char *command, struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, bool filter, struct State *state)
 Pipe a list of attachments to a command. More...
 
void mutt_pipe_attachment_list (struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, bool filter)
 Pipe a list of attachments to a command. More...
 
static bool can_print (struct AttachCtx *actx, struct Body *top, bool tag)
 Do we know how to print this attachment type? More...
 
static void print_attachment_list (struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, struct State *state)
 Print a list of Attachments. More...
 
void mutt_print_attachment_list (struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top)
 Print a list of Attachments. More...
 
void recvattach_edit_content_type (struct AttachCtx *actx, struct Menu *menu, struct Email *e)
 Edit the content type of an attachment. More...
 
int mutt_attach_display_loop (struct ConfigSubset *sub, struct Menu *menu, int op, struct Email *e, struct AttachCtx *actx, bool recv)
 Event loop for the Attachment menu. More...
 
void mutt_generate_recvattach_list (struct AttachCtx *actx, struct Email *e, struct Body *parts, FILE *fp, int parent_type, int level, bool decrypted)
 Create a list of attachments. More...
 
void mutt_attach_init (struct AttachCtx *actx)
 Create a new Attachment context. More...
 
void mutt_update_recvattach_menu (struct AttachCtx *actx, struct Menu *menu, bool init)
 Update the Attachment Menu. More...
 
int ba_add_tagged (struct BodyArray *ba, struct AttachCtx *actx, struct Menu *menu)
 Get an array of tagged Attachments. More...
 

Detailed Description

Attachment code.

Authors
  • Michael R. Elkins
  • Thomas Roessler

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

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

Definition in file recvattach.c.

Function Documentation

◆ current_attachment()

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

Get the current attachment.

Parameters
actxAttachment context
menuMenu
Return values
ptrCurrent Attachment

Definition at line 69 of file recvattach.c.

70{
71 const int virt = menu_get_index(menu);
72 const int index = actx->v2r[virt];
73
74 return actx->idx[index];
75}
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:154
struct AttachPtr ** idx
Array of attachments.
Definition: attach.h:55
short * v2r
Mapping from virtual to real attachment.
Definition: attach.h:59
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_update_v2r()

static void mutt_update_v2r ( struct AttachCtx actx)
static

Update the virtual list of attachments.

Parameters
actxAttachment context

Update the record of the number of attachments and the status of the tree.

Definition at line 83 of file recvattach.c.

84{
85 int vindex, rindex, curlevel;
86
87 vindex = 0;
88 rindex = 0;
89
90 while (rindex < actx->idxlen)
91 {
92 actx->v2r[vindex++] = rindex;
93 if (actx->idx[rindex]->collapsed)
94 {
95 curlevel = actx->idx[rindex]->level;
96 do
97 {
98 rindex++;
99 } while ((rindex < actx->idxlen) && (actx->idx[rindex]->level > curlevel));
100 }
101 else
102 rindex++;
103 }
104
105 actx->vcount = vindex;
106}
short vcount
The number of virtual attachments.
Definition: attach.h:60
bool collapsed
Group is collapsed.
Definition: attach.h:44
int level
Nesting depth of attachment.
Definition: attach.h:40
+ Here is the caller graph for this function:

◆ mutt_update_tree()

void mutt_update_tree ( struct AttachCtx actx)

Refresh the list of attachments.

Parameters
actxAttachment context

Definition at line 112 of file recvattach.c.

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

◆ prepend_savedir()

static void prepend_savedir ( struct Buffer buf)
static

Add $attach_save_dir to the beginning of a path.

Parameters
bufBuffer for the result

Definition at line 159 of file recvattach.c.

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

◆ has_a_message()

static bool has_a_message ( struct Body body)
static

Determine if the Body has a message (to save)

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

Definition at line 185 of file recvattach.c.

186{
187 return (body->email && (body->encoding != ENC_BASE64) &&
188 (body->encoding != ENC_QUOTED_PRINTABLE) &&
189 mutt_is_message_type(body->type, body->subtype));
190}
@ ENC_BASE64
Base-64 encoded text.
Definition: mime.h:52
@ ENC_QUOTED_PRINTABLE
Quoted-printable text.
Definition: mime.h:51
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1441
struct Email * email
header information for message/rfc822
Definition: body.h:73
char * subtype
content-type subtype
Definition: body.h:60
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:41
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ save_attachment_flowed_helper()

static int save_attachment_flowed_helper ( FILE *  fp,
struct Body b,
const char *  path,
enum SaveAttach  flags,
struct Email e 
)
static

Helper for unstuffing attachments.

Parameters
fpAttachment to work on
bBody of email
pathPath to save the attachment
flagsFlags, e.g. MUTT_SAVE_APPEND
eEmail
Return values
0Success
-1Failure

This is a proxy between the mutt_save_attachment_list() calls and mutt_save_attachment(). It (currently) exists solely to unstuff format=flowed text attachments.

Direct modification of mutt_save_attachment() wasn't easily possible because: 1) other callers of mutt_save_attachment() should not have unstuffing performed, such as replying/forwarding attachments. 2) the attachment saving can append to a file, making the unstuffing inside difficult with current functions. 3) we can't unstuff before-hand because decoding hasn't occurred.

So, I apologize for this horrific proxy, but it was the most straightforward method.

Definition at line 217 of file recvattach.c.

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

◆ query_save_attachment()

static int query_save_attachment ( FILE *  fp,
struct Body body,
struct Email e,
char **  directory 
)
static

Ask the user if we should save the attachment.

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

Definition at line 264 of file recvattach.c.

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

◆ save_without_prompting()

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

Save the attachment, without prompting each time.

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

Definition at line 363 of file recvattach.c.

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

◆ mutt_save_attachment_list()

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

Save a list of attachments.

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

Definition at line 413 of file recvattach.c.

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

◆ query_pipe_attachment()

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

Ask the user if we should pipe the attachment.

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

Definition at line 529 of file recvattach.c.

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

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

◆ pipe_attachment_list()

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

Pipe a list of attachments to a command.

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

Definition at line 668 of file recvattach.c.

671{
672 for (int i = 0; !tag || (i < actx->idxlen); i++)
673 {
674 if (tag)
675 {
676 fp = actx->idx[i]->fp;
677 top = actx->idx[i]->body;
678 }
679 if (!tag || top->tagged)
680 {
681 const bool c_attach_split = cs_subset_bool(NeoMutt->sub, "attach_split");
682 if (!filter && !c_attach_split)
683 pipe_attachment(fp, top, state);
684 else
685 query_pipe_attachment(command, fp, top, filter);
686 }
687 if (!tag)
688 break;
689 }
690}
static void pipe_attachment(FILE *fp, struct Body *b, struct State *state)
Pipe the attachment to a command.
Definition: recvattach.c:571
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:529
+ 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 700 of file recvattach.c.

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

◆ can_print()

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

Do we know how to print this attachment type?

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

Definition at line 749 of file recvattach.c.

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

◆ print_attachment_list()

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

Print a list of Attachments.

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

Definition at line 789 of file recvattach.c.

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

◆ mutt_print_attachment_list()

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

Print a list of Attachments.

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

Definition at line 858 of file recvattach.c.

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

904{
905 struct AttachPtr *cur_att = current_attachment(actx, menu);
906 if (!mutt_edit_content_type(e, cur_att->body, cur_att->fp))
907 return;
908
909 /* The mutt_update_recvattach_menu() will overwrite any changes
910 * made to a decrypted cur_att->body, so warn the user. */
911 if (cur_att->decrypted)
912 {
913 mutt_message(_("Structural changes to decrypted attachments are not supported"));
914 mutt_sleep(1);
915 }
916 /* Editing the content type can rewrite the body structure. */
917 for (int i = 0; i < actx->idxlen; i++)
918 actx->idx[i]->body = NULL;
920 mutt_update_recvattach_menu(actx, menu, true);
921}
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:1088
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1456
void mutt_update_recvattach_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
Update the Attachment Menu.
Definition: recvattach.c:1187
struct AttachPtr * current_attachment(struct AttachCtx *actx, struct Menu *menu)
Get the current attachment.
Definition: recvattach.c:69
An email to which things will be attached.
Definition: attach.h:35
bool decrypted
Not part of message as stored in the email->body.
Definition: attach.h:43
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_attach_display_loop()

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

Event loop for the Attachment menu.

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

Definition at line 933 of file recvattach.c.

935{
936 do
937 {
938 switch (op)
939 {
940 case OP_DISPLAY_HEADERS:
941 bool_str_toggle(NeoMutt->sub, "weed", NULL);
942 /* fallthrough */
943
944 case OP_ATTACHMENT_VIEW:
945 {
946 struct AttachPtr *cur_att = current_attachment(actx, menu);
947 if (!cur_att->fp)
948 {
949 if (cur_att->body->type == TYPE_MULTIPART)
950 {
951 struct Body *b = cur_att->body->parts;
952 while (b->parts)
953 b = b->parts;
954 cur_att = b->aptr;
955 }
956 }
957 op = mutt_view_attachment(cur_att->fp, cur_att->body, MUTT_VA_REGULAR,
958 e, actx, menu->win);
959 break;
960 }
961
962 case OP_NEXT_ENTRY:
963 case OP_MAIN_NEXT_UNDELETED: /* hack */
964 {
965 const int index = menu_get_index(menu) + 1;
966 if (index < menu->max)
967 {
968 menu_set_index(menu, index);
969 op = OP_ATTACHMENT_VIEW;
970 }
971 else
972 op = OP_NULL;
973 break;
974 }
975
976 case OP_PREV_ENTRY:
977 case OP_MAIN_PREV_UNDELETED: /* hack */
978 {
979 const int index = menu_get_index(menu) - 1;
980 if (index >= 0)
981 {
982 menu_set_index(menu, index);
983 op = OP_ATTACHMENT_VIEW;
984 }
985 else
986 op = OP_NULL;
987 break;
988 }
989
990 case OP_ATTACHMENT_EDIT_TYPE:
991 {
992 struct AttachPtr *cur_att = current_attachment(actx, menu);
993 /* when we edit the content-type, we should redisplay the attachment
994 * immediately */
995 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
996 if (recv)
997 recvattach_edit_content_type(actx, menu, e);
998 else
999 mutt_edit_content_type(e, cur_att->body, cur_att->fp);
1000
1002 op = OP_ATTACHMENT_VIEW;
1003 break;
1004 }
1005 /* functions which are passed through from the pager */
1006 case OP_PIPE:
1007 {
1008 struct AttachPtr *cur_att = current_attachment(actx, menu);
1009 mutt_pipe_attachment_list(actx, cur_att->fp, false, cur_att->body, false);
1010 op = OP_ATTACHMENT_VIEW;
1011 break;
1012 }
1013 case OP_ATTACHMENT_PRINT:
1014 {
1015 struct AttachPtr *cur_att = current_attachment(actx, menu);
1016 mutt_print_attachment_list(actx, cur_att->fp, false, cur_att->body);
1017 op = OP_ATTACHMENT_VIEW;
1018 break;
1019 }
1020 case OP_ATTACHMENT_SAVE:
1021 {
1022 struct AttachPtr *cur_att = current_attachment(actx, menu);
1023 mutt_save_attachment_list(actx, cur_att->fp, false, cur_att->body, e, NULL);
1024 op = OP_ATTACHMENT_VIEW;
1025 break;
1026 }
1027 case OP_CHECK_TRADITIONAL:
1029 {
1030 op = OP_NULL;
1031 break;
1032 }
1033 /* fallthrough */
1034 case OP_ATTACHMENT_COLLAPSE:
1035 if (recv)
1036 return op;
1037 /* fallthrough */
1038 default:
1039 op = OP_NULL;
1040 }
1041 } while (op != OP_NULL);
1042
1043 return op;
1044}
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:416
@ MUTT_VA_REGULAR
View using default method.
Definition: mutt_attach.h:43
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition: lib.h:92
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:90
#define WithCrypto
Definition: lib.h:116
void mutt_save_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, struct Email *e, struct Menu *menu)
Save a list of attachments.
Definition: recvattach.c:413
void mutt_pipe_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, bool filter)
Pipe a list of attachments to a command.
Definition: recvattach.c:700
void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top)
Print a list of Attachments.
Definition: recvattach.c:858
void recvattach_edit_content_type(struct AttachCtx *actx, struct Menu *menu, struct Email *e)
Edit the content type of an attachment.
Definition: recvattach.c:903
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 1056 of file recvattach.c.

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

1163{
1164 /* Collapse the attachments if '$digest_collapse' is set AND if...
1165 * the outer container is of type 'multipart/digest' */
1166 bool digest = mutt_istr_equal(actx->email->body->subtype, "digest");
1167
1168 const bool c_digest_collapse = cs_subset_bool(NeoMutt->sub, "digest_collapse");
1169 for (int i = 0; i < actx->idxlen; i++)
1170 {
1171 actx->idx[i]->body->tagged = false;
1172
1173 /* OR an inner container is of type 'multipart/digest' */
1174 actx->idx[i]->collapsed = (c_digest_collapse &&
1175 (digest ||
1176 ((actx->idx[i]->body->type == TYPE_MULTIPART) &&
1177 mutt_istr_equal(actx->idx[i]->body->subtype, "digest"))));
1178 }
1179}
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 1187 of file recvattach.c.

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

1215{
1216 if (!ba || !actx || !menu)
1217 return -1;
1218
1219 if (menu->tag_prefix)
1220 {
1221 for (int i = 0; i < actx->idxlen; i++)
1222 {
1223 struct Body *b = actx->idx[i]->body;
1224 if (b->tagged)
1225 {
1226 ARRAY_ADD(ba, b);
1227 }
1228 }
1229 }
1230 else
1231 {
1232 struct AttachPtr *cur = current_attachment(actx, menu);
1233 if (!cur)
1234 return -1;
1235
1236 ARRAY_ADD(ba, cur->body);
1237 }
1238
1239 return ARRAY_SIZE(ba);
1240}
#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: