NeoMutt  2021-10-22-8-g9cb437
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 "menu/lib.h"
#include "ncrypt/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "commands.h"
#include "handler.h"
#include "hook.h"
#include "mailcap.h"
#include "mutt_attach.h"
#include "mutt_thread.h"
#include "muttlib.h"
#include "opcodes.h"
#include "rfc3676.h"
#include <libintl.h>
+ Include dependency graph for recvattach.c:

Go to the source code of this file.

Functions

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

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

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

82 {
83  int vindex, rindex, curlevel;
84 
85  vindex = 0;
86  rindex = 0;
87 
88  while (rindex < actx->idxlen)
89  {
90  actx->v2r[vindex++] = rindex;
91  if (actx->idx[rindex]->body->collapsed)
92  {
93  curlevel = actx->idx[rindex]->level;
94  do
95  {
96  rindex++;
97  } while ((rindex < actx->idxlen) && (actx->idx[rindex]->level > curlevel));
98  }
99  else
100  rindex++;
101  }
102 
103  actx->vcount = vindex;
104 }
short vcount
The number of virtual attachments.
Definition: attach.h:59
struct Body * body
Attachment.
Definition: attach.h:36
int level
Nesting depth of attachment.
Definition: attach.h:40
bool collapsed
Used by recvattach.
Definition: body.h:86
+ 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 110 of file recvattach.c.

111 {
112  char buf[256];
113  char *s = NULL;
114 
115  mutt_update_v2r(actx);
116 
117  for (int vindex = 0; vindex < actx->vcount; vindex++)
118  {
119  const int rindex = actx->v2r[vindex];
120  actx->idx[rindex]->num = vindex;
121  if ((2 * (actx->idx[rindex]->level + 2)) < sizeof(buf))
122  {
123  if (actx->idx[rindex]->level)
124  {
125  s = buf + 2 * (actx->idx[rindex]->level - 1);
126  *s++ = (actx->idx[rindex]->body->next) ? MUTT_TREE_LTEE : MUTT_TREE_LLCORNER;
127  *s++ = MUTT_TREE_HLINE;
128  *s++ = MUTT_TREE_RARROW;
129  }
130  else
131  s = buf;
132  *s = '\0';
133  }
134 
135  if (actx->idx[rindex]->tree)
136  {
137  if (!mutt_str_equal(actx->idx[rindex]->tree, buf))
138  mutt_str_replace(&actx->idx[rindex]->tree, buf);
139  }
140  else
141  actx->idx[rindex]->tree = mutt_str_dup(buf);
142 
143  if (((2 * (actx->idx[rindex]->level + 2)) < sizeof(buf)) &&
144  actx->idx[rindex]->level)
145  {
146  s = buf + 2 * (actx->idx[rindex]->level - 1);
147  *s++ = (actx->idx[rindex]->body->next) ? '\005' : '\006';
148  *s++ = '\006';
149  }
150  }
151 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
@ 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:81
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:70
+ 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 157 of file recvattach.c.

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

◆ has_a_message()

static bool has_a_message ( struct Body body)
static

Determine if the Body has a message (to save)

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

Definition at line 184 of file recvattach.c.

185 {
186  return (body->email && (body->encoding != ENC_BASE64) &&
187  (body->encoding != ENC_QUOTED_PRINTABLE) &&
188  mutt_is_message_type(body->type, body->subtype));
189 }
@ 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:1428
struct Email * email
header information for message/rfc822
Definition: body.h:72
char * subtype
content-type subtype
Definition: body.h:59
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:40
unsigned int type
content-type primary type, ContentType
Definition: body.h:39
+ 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 216 of file recvattach.c.

218 {
219  int rc = -1;
220 
222  {
223  struct Body b_fake = { 0 };
224 
225  struct Buffer *tempfile = mutt_buffer_pool_get();
226  mutt_buffer_mktemp(tempfile);
227 
228  /* Pass MUTT_SAVE_NO_FLAGS to force mutt_file_fopen("w") */
230  if (rc != 0)
231  goto cleanup;
232 
234 
235  /* Now "really" save it. Send mode does this without touching anything,
236  * so force send-mode. */
237  memset(&b_fake, 0, sizeof(struct Body));
238  b_fake.filename = tempfile->data;
239  rc = mutt_save_attachment(NULL, &b_fake, path, flags, e);
240 
242 
243  cleanup:
244  mutt_buffer_pool_release(&tempfile);
245  }
246  else
247  {
248  rc = mutt_save_attachment(fp, b, path, flags, e);
249  }
250 
251  return rc;
252 }
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:195
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:879
@ 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: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:35
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:57
+ 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 263 of file recvattach.c.

264 {
265  char *prompt = NULL;
266  enum SaveAttach opt = MUTT_SAVE_NO_FLAGS;
267  int rc = -1;
268 
269  struct Buffer *buf = mutt_buffer_pool_get();
270  struct Buffer *tfile = mutt_buffer_pool_get();
271 
272  if (body->filename)
273  {
274  if (directory && *directory)
275  {
276  mutt_buffer_concat_path(buf, *directory, mutt_path_basename(body->filename));
277  }
278  else
279  mutt_buffer_strcpy(buf, body->filename);
280  }
281  else if (has_a_message(body))
282  {
283  mutt_default_save(buf->data, buf->dsize, body->email);
285  }
286 
287  prepend_savedir(buf);
288 
289  prompt = _("Save to file: ");
290  while (prompt)
291  {
292  if ((mutt_buffer_get_field(prompt, buf, MUTT_FILE | MUTT_CLEAR, false, NULL,
293  NULL, NULL) != 0) ||
295  {
296  goto cleanup;
297  }
298 
299  prompt = NULL;
301 
302  bool is_message = (fp && has_a_message(body));
303 
304  if (is_message)
305  {
306  struct stat st = { 0 };
307 
308  /* check to make sure that this file is really the one the user wants */
309  rc = mutt_save_confirm(mutt_buffer_string(buf), &st);
310  if (rc == 1)
311  {
312  prompt = _("Save to file: ");
313  continue;
314  }
315  else if (rc == -1)
316  goto cleanup;
317  mutt_buffer_copy(tfile, buf);
318  }
319  else
320  {
321  rc = mutt_check_overwrite(body->filename, mutt_buffer_string(buf), tfile,
322  &opt, directory);
323  if (rc == -1)
324  goto cleanup;
325  else if (rc == 1)
326  {
327  prompt = _("Save to file: ");
328  continue;
329  }
330  }
331 
332  mutt_message(_("Saving..."));
333  if (save_attachment_flowed_helper(fp, body, mutt_buffer_string(tfile), opt,
334  (e || !is_message) ? e : body->email) == 0)
335  {
336  // This uses ngettext to avoid duplication of messages
337  mutt_message(ngettext("Attachment saved", "%d attachments saved", 1), 1);
338  rc = 0;
339  goto cleanup;
340  }
341  else
342  {
343  prompt = _("Save to file: ");
344  continue;
345  }
346  }
347 
348 cleanup:
350  mutt_buffer_pool_release(&tfile);
351  return rc;
352 }
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:181
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:374
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: curs_lib.c:267
#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:676
#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_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:58
#define MUTT_FILE
Do file completion.
Definition: mutt.h:54
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:625
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition: muttlib.c:1360
static bool has_a_message(struct Body *body)
Determine if the Body has a message (to save)
Definition: recvattach.c:184
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:216
static void prepend_savedir(struct Buffer *buf)
Add $attach_save_dir to the beginning of a path.
Definition: recvattach.c:157
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 362 of file recvattach.c.

363 {
364  enum SaveAttach opt = MUTT_SAVE_NO_FLAGS;
365  int rc = -1;
366  struct Buffer *buf = mutt_buffer_pool_get();
367  struct Buffer *tfile = mutt_buffer_pool_get();
368 
369  if (body->filename)
370  {
371  mutt_buffer_strcpy(buf, body->filename);
372  }
373  else if (has_a_message(body))
374  {
375  mutt_default_save(buf->data, buf->dsize, body->email);
376  }
377 
378  prepend_savedir(buf);
380 
381  bool is_message = (fp && has_a_message(body));
382 
383  if (is_message)
384  {
385  mutt_buffer_copy(tfile, buf);
386  }
387  else
388  {
389  rc = mutt_check_overwrite(body->filename, mutt_buffer_string(buf), tfile, &opt, NULL);
390  if (rc == -1) // abort or cancel
391  goto cleanup;
392  }
393 
394  rc = save_attachment_flowed_helper(fp, body, mutt_buffer_string(tfile), opt,
395  (e || !is_message) ? e : body->email);
396 
397 cleanup:
399  mutt_buffer_pool_release(&tfile);
400  return rc;
401 }
+ 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 412 of file recvattach.c.

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

◆ query_pipe_attachment()

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

Ask the user if we should pipe the attachment.

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

Definition at line 534 of file recvattach.c.

535 {
536  char tfile[PATH_MAX];
537 
538  if (filter)
539  {
540  char warning[PATH_MAX + 256];
541  snprintf(warning, sizeof(warning),
542  _("WARNING! You are about to overwrite %s, continue?"), body->filename);
543  if (mutt_yesorno(warning, MUTT_NO) != MUTT_YES)
544  {
546  return;
547  }
548  mutt_mktemp(tfile, sizeof(tfile));
549  }
550  else
551  tfile[0] = '\0';
552 
553  if (mutt_pipe_attachment(fp, body, command, tfile))
554  {
555  if (filter)
556  {
557  mutt_file_unlink(body->filename);
558  mutt_file_rename(tfile, body->filename);
560  mutt_message(_("Attachment filtered"));
561  }
562  }
563  else
564  {
565  if (filter && tfile[0])
566  mutt_file_unlink(tfile);
567  }
568 }
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition: file.c:1354
void msgwin_clear_text(void)
Clear the text in the Message Window.
Definition: msgwin.c:240
#define PATH_MAX
Definition: mutt.h:40
int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, char *outfile)
Pipe an attachment to a command.
Definition: mutt_attach.c:712
#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:182
void mutt_update_encoding(struct Body *a, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:908
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pipe_attachment()

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

Pipe the attachment to a command.

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

Definition at line 576 of file recvattach.c.

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

◆ pipe_attachment_list()

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

Pipe a list of attachments to a command.

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

Definition at line 673 of file recvattach.c.

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

◆ mutt_pipe_attachment_list()

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

Pipe a list of attachments to a command.

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

Definition at line 705 of file recvattach.c.

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

◆ can_print()

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

Do we know how to print this attachment type?

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

Definition at line 754 of file recvattach.c.

755 {
756  char type[256];
757 
758  for (int i = 0; !tag || (i < actx->idxlen); i++)
759  {
760  if (tag)
761  top = actx->idx[i]->body;
762  snprintf(type, sizeof(type), "%s/%s", TYPE(top), top->subtype);
763  if (!tag || top->tagged)
764  {
765  if (!mailcap_lookup(top, type, sizeof(type), NULL, MUTT_MC_PRINT))
766  {
767  if (!mutt_istr_equal("text/plain", top->subtype) &&
768  !mutt_istr_equal("application/postscript", top->subtype))
769  {
770  if (!mutt_can_decode(top))
771  {
772  /* L10N: s gets replaced by a MIME type, e.g. "text/plain" or
773  application/octet-stream. */
774  mutt_error(_("I don't know how to print %s attachments"), type);
775  return false;
776  }
777  }
778  }
779  }
780  if (!tag)
781  break;
782  }
783  return true;
784 }
#define mutt_error(...)
Definition: logging.h:87
bool mutt_can_decode(struct Body *a)
Will decoding the attachment produce any output.
Definition: handler.c:1814
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:475
@ 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:916
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ print_attachment_list()

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

Print a list of Attachments.

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

Definition at line 794 of file recvattach.c.

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

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

◆ recvattach_edit_content_type()

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

Edit the content type of an attachment.

Parameters
actxAttachment context
menuMenu listing Attachments
eEmail

Definition at line 910 of file recvattach.c.

911 {
912  struct AttachPtr *cur_att = current_attachment(actx, menu);
913  if (!mutt_edit_content_type(e, cur_att->body, cur_att->fp))
914  return;
915 
916  /* The mutt_update_recvattach_menu() will overwrite any changes
917  * made to a decrypted cur_att->body, so warn the user. */
918  if (cur_att->decrypted)
919  {
920  mutt_message(
921  _("Structural changes to decrypted attachments are not supported"));
922  mutt_sleep(1);
923  }
924  /* Editing the content type can rewrite the body structure. */
925  for (int i = 0; i < actx->idxlen; i++)
926  actx->idx[i]->body = NULL;
928  mutt_update_recvattach_menu(actx, menu, true);
929 }
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition: commands.c:1094
void mutt_actx_entries_free(struct AttachCtx *actx)
Free entries in an Attachment Context.
Definition: attach.c:103
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1461
void mutt_update_recvattach_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
Update the Attachment Menu.
Definition: recvattach.c:1165
struct AttachPtr * current_attachment(struct AttachCtx *actx, struct Menu *menu)
Get the current attachment.
Definition: recvattach.c:67
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_VIEW_ATTACH
eEmail
actxAttachment context
recvtrue if these are received attachments (rather than in compose)
Return values
numOperation performed

Definition at line 941 of file recvattach.c.

943 {
944  do
945  {
946  switch (op)
947  {
948  case OP_DISPLAY_HEADERS:
949  bool_str_toggle(NeoMutt->sub, "weed", NULL);
950  /* fallthrough */
951 
952  case OP_VIEW_ATTACH:
953  {
954  struct AttachPtr *cur_att = current_attachment(actx, menu);
955  op = mutt_view_attachment(cur_att->fp, cur_att->body, MUTT_VA_REGULAR,
956  e, actx, menu->win);
957  break;
958  }
959 
960  case OP_NEXT_ENTRY:
961  case OP_MAIN_NEXT_UNDELETED: /* hack */
962  {
963  const int index = menu_get_index(menu) + 1;
964  if (index < menu->max)
965  {
966  menu_set_index(menu, index);
967  op = OP_VIEW_ATTACH;
968  }
969  else
970  op = OP_NULL;
971  break;
972  }
973 
974  case OP_PREV_ENTRY:
975  case OP_MAIN_PREV_UNDELETED: /* hack */
976  {
977  const int index = menu_get_index(menu) - 1;
978  if (index >= 0)
979  {
980  menu_set_index(menu, index);
981  op = OP_VIEW_ATTACH;
982  }
983  else
984  op = OP_NULL;
985  break;
986  }
987 
988  case OP_EDIT_TYPE:
989  {
990  struct AttachPtr *cur_att = current_attachment(actx, menu);
991  /* when we edit the content-type, we should redisplay the attachment
992  * immediately */
993  mutt_edit_content_type(e, cur_att->body, cur_att->fp);
994  if (recv)
995  recvattach_edit_content_type(actx, menu, e);
996  else
997  mutt_edit_content_type(e, cur_att->body, cur_att->fp);
998 
1000  op = OP_VIEW_ATTACH;
1001  break;
1002  }
1003  /* functions which are passed through from the pager */
1004  case OP_CHECK_TRADITIONAL:
1006  {
1007  op = OP_NULL;
1008  break;
1009  }
1010  /* fallthrough */
1011  case OP_ATTACH_COLLAPSE:
1012  if (recv)
1013  return op;
1014  /* fallthrough */
1015  default:
1016  op = OP_NULL;
1017  }
1018  } while (op != OP_NULL);
1019 
1020  return op;
1021 }
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:52
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:415
@ 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:89
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
#define WithCrypto
Definition: lib.h:113
void recvattach_edit_content_type(struct AttachCtx *actx, struct Menu *menu, struct Email *e)
Edit the content type of an attachment.
Definition: recvattach.c:910
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:74
+ 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 1033 of file recvattach.c.

1036 {
1037  struct Body *m = NULL;
1038  struct Body *new_body = NULL;
1039  FILE *fp_new = NULL;
1041  int need_secured, secured;
1042 
1043  for (m = parts; m; m = m->next)
1044  {
1045  need_secured = 0;
1046  secured = 0;
1047 
1049  {
1050  need_secured = 1;
1051 
1052  if (type & SEC_ENCRYPT)
1053  {
1055  goto decrypt_failed;
1056 
1057  if (e->env)
1059  }
1060 
1061  secured = !crypt_smime_decrypt_mime(fp, &fp_new, m, &new_body);
1062  /* If the decrypt/verify-opaque doesn't generate mime output, an empty
1063  * text/plain type will still be returned by mutt_read_mime_header().
1064  * We can't distinguish an actual part from a failure, so only use a
1065  * text/plain that results from a single top-level part. */
1066  if (secured && (new_body->type == TYPE_TEXT) &&
1067  mutt_istr_equal("plain", new_body->subtype) && ((parts != m) || m->next))
1068  {
1069  mutt_body_free(&new_body);
1070  mutt_file_fclose(&fp_new);
1071  goto decrypt_failed;
1072  }
1073 
1074  if (secured && (type & SEC_ENCRYPT))
1075  e->security |= SMIME_ENCRYPT;
1076  }
1077 
1078  if (((WithCrypto & APPLICATION_PGP) != 0) &&
1080  {
1081  need_secured = 1;
1082 
1084  goto decrypt_failed;
1085 
1086  secured = !crypt_pgp_decrypt_mime(fp, &fp_new, m, &new_body);
1087 
1088  if (secured)
1089  e->security |= PGP_ENCRYPT;
1090  }
1091 
1092  if (need_secured && secured)
1093  {
1094  mutt_actx_add_fp(actx, fp_new);
1095  mutt_actx_add_body(actx, new_body);
1096  mutt_generate_recvattach_list(actx, e, new_body, fp_new, parent_type, level, 1);
1097  continue;
1098  }
1099 
1100  decrypt_failed:
1101  /* Fall through and show the original parts if decryption fails */
1102  if (need_secured && !secured)
1103  mutt_error(_("Can't decrypt encrypted message"));
1104 
1105  /* Strip out the top level multipart */
1106  if ((m->type == TYPE_MULTIPART) && m->parts && !need_secured &&
1107  ((parent_type == -1) && !mutt_istr_equal("alternative", m->subtype)))
1108  {
1109  mutt_generate_recvattach_list(actx, e, m->parts, fp, m->type, level, decrypted);
1110  }
1111  else
1112  {
1113  struct AttachPtr *ap = mutt_mem_calloc(1, sizeof(struct AttachPtr));
1114  mutt_actx_add_attach(actx, ap);
1115 
1116  ap->body = m;
1117  ap->fp = fp;
1118  m->aptr = ap;
1119  ap->parent_type = parent_type;
1120  ap->level = level;
1121  ap->decrypted = decrypted;
1122 
1123  if (m->type == TYPE_MULTIPART)
1124  mutt_generate_recvattach_list(actx, e, m->parts, fp, m->type, level + 1, decrypted);
1125  else if (mutt_is_message_type(m->type, m->subtype))
1126  {
1127  mutt_generate_recvattach_list(actx, m->email, m->parts, fp, m->type,
1128  level + 1, decrypted);
1129  e->security |= m->email->security;
1130  }
1131  }
1132  }
1133 }
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:617
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:454
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition: crypt.c:515
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:434
void crypt_smime_getkeys(struct Envelope *env)
Wrapper for CryptModuleSpecs::smime_getkeys()
Definition: cryptglue.c:456
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:212
void mutt_actx_add_body(struct AttachCtx *actx, struct Body *new_body)
Add an email box to an Attachment Context.
Definition: attach.c:83
void mutt_actx_add_attach(struct AttachCtx *actx, struct AttachPtr *attach)
Add an Attachment to an Attachment Context.
Definition: attach.c:40
void mutt_actx_add_fp(struct AttachCtx *actx, FILE *fp_new)
Save a File handle to the Attachment Context.
Definition: attach.c:62
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
@ TYPE_TEXT
Type: 'text/*'.
Definition: mime.h:38
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:71
#define PGP_ENCRYPT
Definition: lib.h:93
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:88
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:75
#define SMIME_ENCRYPT
Definition: lib.h:99
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:1033
int parent_type
Type of parent attachment, e.g. TYPE_MULTIPART.
Definition: attach.h:38
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:71
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 1139 of file recvattach.c.

1140 {
1141  /* Collapse the attachments if '$digest_collapse' is set AND if...
1142  * the outer container is of type 'multipart/digest' */
1143  bool digest = mutt_istr_equal(actx->email->body->subtype, "digest");
1144 
1145  const bool c_digest_collapse =
1146  cs_subset_bool(NeoMutt->sub, "digest_collapse");
1147  for (int i = 0; i < actx->idxlen; i++)
1148  {
1149  actx->idx[i]->body->tagged = false;
1150 
1151  /* OR an inner container is of type 'multipart/digest' */
1152  actx->idx[i]->body->collapsed =
1153  (c_digest_collapse &&
1154  (digest || ((actx->idx[i]->body->type == TYPE_MULTIPART) &&
1155  mutt_istr_equal(actx->idx[i]->body->subtype, "digest"))));
1156  }
1157 }
struct Email * email
Used by recvattach for updating.
Definition: attach.h:51
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 1165 of file recvattach.c.

1166 {
1167  if (init)
1168  {
1169  mutt_generate_recvattach_list(actx, actx->email, actx->email->body,
1170  actx->fp_root, -1, 0, 0);
1171  mutt_attach_init(actx);
1172  menu->mdata = actx;
1173  }
1174 
1175  mutt_update_tree(actx);
1176 
1177  menu->max = actx->vcount;
1178 
1179  const int index = menu_get_index(menu);
1180  if (index >= menu->max)
1181  menu_set_index(menu, menu->max - 1);
1183 }
void mutt_attach_init(struct AttachCtx *actx)
Create a new Attachment context.
Definition: recvattach.c:1139
void mutt_update_tree(struct AttachCtx *actx)
Refresh the list of attachments.
Definition: recvattach.c:110
FILE * fp_root
Used by recvattach for updating.
Definition: attach.h:52
void * mdata
Private data.
Definition: lib.h:153
int max
Number of entries in the menu.
Definition: lib.h:69
+ Here is the call graph for this function:
+ Here is the caller graph for this function: