NeoMutt  2019-11-11
Teaching an old dog new tricks
DOXYGEN
mutt_attach.c File Reference

Handling of email attachments. More...

#include "config.h"
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mutt/mutt.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "mutt_attach.h"
#include "context.h"
#include "copy.h"
#include "curs_lib.h"
#include "filter.h"
#include "globals.h"
#include "handler.h"
#include "mailcap.h"
#include "mutt_window.h"
#include "muttlib.h"
#include "mx.h"
#include "ncrypt/ncrypt.h"
#include "options.h"
#include "pager.h"
#include "protos.h"
#include "sendlib.h"
#include "state.h"
+ Include dependency graph for mutt_attach.c:

Go to the source code of this file.

Functions

int mutt_get_tmp_attachment (struct Body *a)
 Get a temporary copy of an attachment. More...
 
int mutt_compose_attachment (struct Body *a)
 Create an attachment. More...
 
int mutt_edit_attachment (struct Body *a)
 Edit an attachment. More...
 
void mutt_check_lookup_list (struct Body *b, char *type, size_t len)
 Update the mime type. More...
 
int mutt_view_attachment (FILE *fp, struct Body *a, enum ViewAttachMode mode, struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
 View an attachment. More...
 
int mutt_pipe_attachment (FILE *fp, struct Body *b, const char *path, char *outfile)
 Pipe an attachment to a command. More...
 
static FILE * save_attachment_open (const char *path, enum SaveAttach opt)
 Open a file to write an attachment to. More...
 
int mutt_save_attachment (FILE *fp, struct Body *m, const char *path, enum SaveAttach opt, struct Email *e)
 Save an attachment. More...
 
int mutt_decode_save_attachment (FILE *fp, struct Body *m, const char *path, int displaying, enum SaveAttach opt)
 Decode, then save an attachment. More...
 
int mutt_print_attachment (FILE *fp, struct Body *a)
 Print out an attachment. More...
 
void mutt_add_temp_attachment (const char *filename)
 Add file to list of temporary attachments. More...
 
void mutt_unlink_temp_attachments (void)
 Delete all temporary attachments. More...
 

Detailed Description

Handling of email attachments.

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 mutt_attach.c.

Function Documentation

◆ mutt_get_tmp_attachment()

int mutt_get_tmp_attachment ( struct Body a)

Get a temporary copy of an attachment.

Parameters
aAttachment to copy
Return values
0Success
-1Error

Definition at line 66 of file mutt_attach.c.

67 {
68  char type[256];
69  struct stat st;
70 
71  if (a->unlink)
72  return 0;
73 
74  struct Buffer *tmpfile = mutt_buffer_pool_get();
75  struct MailcapEntry *entry = mailcap_entry_new();
76  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
77  mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_NO_FLAGS);
78  mailcap_expand_filename(entry->nametemplate, a->filename, tmpfile);
79 
80  mailcap_entry_free(&entry);
81 
82  if (stat(a->filename, &st) == -1)
83  {
84  mutt_buffer_pool_release(&tmpfile);
85  return -1;
86  }
87 
88  FILE *fp_in = NULL, *fp_out = NULL;
89  if ((fp_in = fopen(a->filename, "r")) &&
90  (fp_out = mutt_file_fopen(mutt_b2s(tmpfile), "w")))
91  {
92  mutt_file_copy_stream(fp_in, fp_out);
93  mutt_str_replace(&a->filename, mutt_b2s(tmpfile));
94  a->unlink = true;
95 
96  if (a->stamp >= st.st_mtime)
98  }
99  else
100  mutt_perror(fp_in ? mutt_b2s(tmpfile) : a->filename);
101 
102  mutt_file_fclose(&fp_in);
103  mutt_file_fclose(&fp_out);
104 
105  mutt_buffer_pool_release(&tmpfile);
106 
107  return a->unlink ? 0 : -1;
108 }
A mailcap entry.
Definition: mailcap.h:37
struct MailcapEntry * mailcap_entry_new(void)
Allocate memory for a new rfc1524 entry.
Definition: mailcap.c:429
void mutt_stamp_attachment(struct Body *a)
Timestamp an Attachment.
Definition: sendlib.c:1449
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
#define mutt_perror(...)
Definition: logging.h:85
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
String manipulation buffer.
Definition: buffer.h:33
No flags set.
Definition: mailcap.h:57
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:467
void mailcap_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: mailcap.c:522
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
char * subtype
content-type subtype
Definition: body.h:37
#define mutt_b2s(buf)
Definition: buffer.h:41
void mailcap_entry_free(struct MailcapEntry **ptr)
Deallocate an struct MailcapEntry.
Definition: mailcap.c:438
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
char * nametemplate
Definition: mailcap.h:45
#define TYPE(body)
Definition: mime.h:83
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:270
time_t stamp
Time stamp of last encoding update.
Definition: body.h:61
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:69
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:585
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_compose_attachment()

int mutt_compose_attachment ( struct Body a)

Create an attachment.

Parameters
aBody of email
Return values
1if require full screen redraw
0otherwise

Definition at line 116 of file mutt_attach.c.

117 {
118  char type[256];
119  struct MailcapEntry *entry = mailcap_entry_new();
120  bool unlink_newfile = false;
121  int rc = 0;
122  struct Buffer *cmd = mutt_buffer_pool_get();
123  struct Buffer *newfile = mutt_buffer_pool_get();
124  struct Buffer *tmpfile = mutt_buffer_pool_get();
125 
126  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
127  if (mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_COMPOSE))
128  {
129  if (entry->composecommand || entry->composetypecommand)
130  {
131  if (entry->composetypecommand)
133  else
134  mutt_buffer_strcpy(cmd, entry->composecommand);
135 
136  mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
137  mutt_debug(LL_DEBUG1, "oldfile: %s\t newfile: %s\n", a->filename, mutt_b2s(newfile));
138  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
139  {
140  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
141  goto bailout;
142  mutt_buffer_strcpy(newfile, a->filename);
143  }
144  else
145  unlink_newfile = true;
146 
147  if (mailcap_expand_command(a, mutt_b2s(newfile), type, cmd))
148  {
149  /* For now, editing requires a file, no piping */
150  mutt_error(_("Mailcap compose entry requires %%s"));
151  }
152  else
153  {
154  int r;
155 
156  mutt_endwin();
157  r = mutt_system(mutt_b2s(cmd));
158  if (r == -1)
159  mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
160 
161  if ((r != -1) && entry->composetypecommand)
162  {
163  struct Body *b = NULL;
164 
165  FILE *fp = mutt_file_fopen(a->filename, "r");
166  if (!fp)
167  {
168  mutt_perror(_("Failure to open file to parse headers"));
169  goto bailout;
170  }
171 
172  b = mutt_read_mime_header(fp, 0);
173  if (b)
174  {
175  if (!TAILQ_EMPTY(&b->parameter))
176  {
178  a->parameter = b->parameter;
179  TAILQ_INIT(&b->parameter);
180  }
181  if (b->description)
182  {
183  FREE(&a->description);
184  a->description = b->description;
185  b->description = NULL;
186  }
187  if (b->form_name)
188  {
189  FREE(&a->form_name);
190  a->form_name = b->form_name;
191  b->form_name = NULL;
192  }
193 
194  /* Remove headers by copying out data to another file, then
195  * copying the file back */
196  fseeko(fp, b->offset, SEEK_SET);
197  mutt_body_free(&b);
198  mutt_buffer_mktemp(tmpfile);
199  FILE *fp_tmp = mutt_file_fopen(mutt_b2s(tmpfile), "w");
200  if (!fp_tmp)
201  {
202  mutt_perror(_("Failure to open file to strip headers"));
203  mutt_file_fclose(&fp);
204  goto bailout;
205  }
206  mutt_file_copy_stream(fp, fp_tmp);
207  mutt_file_fclose(&fp);
208  mutt_file_fclose(&fp_tmp);
210  if (mutt_file_rename(mutt_b2s(tmpfile), a->filename) != 0)
211  {
212  mutt_perror(_("Failure to rename file"));
213  goto bailout;
214  }
215  }
216  }
217  }
218  }
219  }
220  else
221  {
222  mutt_message(_("No mailcap compose entry for %s, creating empty file"), type);
223  rc = 1;
224  goto bailout;
225  }
226 
227  rc = 1;
228 
229 bailout:
230 
231  if (unlink_newfile)
232  unlink(mutt_b2s(newfile));
233 
235  mutt_buffer_pool_release(&newfile);
236  mutt_buffer_pool_release(&tmpfile);
237 
238  mailcap_entry_free(&entry);
239  return rc;
240 }
A mailcap entry.
Definition: mailcap.h:37
struct MailcapEntry * mailcap_entry_new(void)
Allocate memory for a new rfc1524 entry.
Definition: mailcap.c:429
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:79
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
#define mutt_perror(...)
Definition: logging.h:85
#define mutt_message(...)
Definition: logging.h:83
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition: file.c:1334
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
char * composetypecommand
Definition: mailcap.h:42
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:194
String manipulation buffer.
Definition: buffer.h:33
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
#define _(a)
Definition: message.h:28
char * form_name
Content-Disposition form-data name param.
Definition: body.h:41
The body of an email.
Definition: body.h:34
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:467
int mailcap_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: mailcap.c:70
void mailcap_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: mailcap.c:522
Mailcap compose field.
Definition: mailcap.h:59
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:375
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
#define TAILQ_INIT(head)
Definition: queue.h:759
void mutt_param_free(struct ParameterList *pl)
Free a ParameterList.
Definition: parameter.c:61
char * subtype
content-type subtype
Definition: body.h:37
#define mutt_b2s(buf)
Definition: buffer.h:41
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:544
void mailcap_entry_free(struct MailcapEntry **ptr)
Deallocate an struct MailcapEntry.
Definition: mailcap.c:438
char * description
content-description
Definition: body.h:40
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
char * nametemplate
Definition: mailcap.h:45
#define TYPE(body)
Definition: mime.h:83
Log at debug level 1.
Definition: logging.h:56
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:270
#define mutt_error(...)
Definition: logging.h:84
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:69
char * composecommand
Definition: mailcap.h:41
#define FREE(x)
Definition: memory.h:40
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
#define TAILQ_EMPTY(head)
Definition: queue.h:715
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:296
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:585
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1290
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_edit_attachment()

int mutt_edit_attachment ( struct Body a)

Edit an attachment.

Parameters
aEmail containing attachment
Return values
1if editor found
0if not

Currently, this only works for send mode, as it assumes that the Body->filename actually contains the information. I'm not sure we want to deal with editing attachments we've already received, so this should be ok.

Returning 0 is useful to tell the calling menu to redraw

Definition at line 255 of file mutt_attach.c.

256 {
257  char type[256];
258  struct MailcapEntry *entry = mailcap_entry_new();
259  bool unlink_newfile = false;
260  int rc = 0;
261  struct Buffer *cmd = mutt_buffer_pool_get();
262  struct Buffer *newfile = mutt_buffer_pool_get();
263 
264  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
265  if (mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_EDIT))
266  {
267  if (entry->editcommand)
268  {
269  mutt_buffer_strcpy(cmd, entry->editcommand);
270  mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
271  mutt_debug(LL_DEBUG1, "oldfile: %s\t newfile: %s\n", a->filename, mutt_b2s(newfile));
272  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
273  {
274  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
275  goto bailout;
276  mutt_buffer_strcpy(newfile, a->filename);
277  }
278  else
279  unlink_newfile = true;
280 
281  if (mailcap_expand_command(a, mutt_b2s(newfile), type, cmd))
282  {
283  /* For now, editing requires a file, no piping */
284  mutt_error(_("Mailcap Edit entry requires %%s"));
285  goto bailout;
286  }
287  else
288  {
289  mutt_endwin();
290  if (mutt_system(mutt_b2s(cmd)) == -1)
291  {
292  mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
293  goto bailout;
294  }
295  }
296  }
297  }
298  else if (a->type == TYPE_TEXT)
299  {
300  /* On text, default to editor */
302  }
303  else
304  {
305  mutt_error(_("No mailcap edit entry for %s"), type);
306  rc = 0;
307  goto bailout;
308  }
309 
310  rc = 1;
311 
312 bailout:
313 
314  if (unlink_newfile)
315  unlink(mutt_b2s(newfile));
316 
318  mutt_buffer_pool_release(&newfile);
319 
320  mailcap_entry_free(&entry);
321  return rc;
322 }
A mailcap entry.
Definition: mailcap.h:37
struct MailcapEntry * mailcap_entry_new(void)
Allocate memory for a new rfc1524 entry.
Definition: mailcap.c:429
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
#define NONULL(x)
Definition: string2.h:37
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
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:467
int mailcap_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: mailcap.c:70
void mailcap_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: mailcap.c:522
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:375
char * editcommand
Definition: mailcap.h:43
char * subtype
content-type subtype
Definition: body.h:37
#define mutt_b2s(buf)
Definition: buffer.h:41
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:544
void mailcap_entry_free(struct MailcapEntry **ptr)
Deallocate an struct MailcapEntry.
Definition: mailcap.c:438
Type: &#39;text/*&#39;.
Definition: mime.h:38
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
unsigned int type
content-type primary type
Definition: body.h:65
char * nametemplate
Definition: mailcap.h:45
#define TYPE(body)
Definition: mime.h:83
Log at debug level 1.
Definition: logging.h:56
#define mutt_error(...)
Definition: logging.h:84
WHERE char * C_Editor
Config: External command to use as an email editor.
Definition: globals.h:111
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Mailcap edit field.
Definition: mailcap.h:58
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:296
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition: curs_lib.c:351
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_check_lookup_list()

void mutt_check_lookup_list ( struct Body b,
char *  type,
size_t  len 
)

Update the mime type.

Parameters
bMessage attachment body
typeBuffer with mime type of attachment in "type/subtype" format
lenBuffer length

Definition at line 330 of file mutt_attach.c.

331 {
332  struct ListNode *np = NULL;
333  STAILQ_FOREACH(np, &MimeLookupList, entries)
334  {
335  const int i = mutt_str_strlen(np->data) - 1;
336  if (((i > 0) && (np->data[i - 1] == '/') && (np->data[i] == '*') &&
337  (mutt_str_strncasecmp(type, np->data, i) == 0)) ||
338  (mutt_str_strcasecmp(type, np->data) == 0))
339  {
340  struct Body tmp = { 0 };
341  enum ContentType n;
342  if ((n = mutt_lookup_mime_type(&tmp, b->filename)) != TYPE_OTHER ||
343  (n = mutt_lookup_mime_type(&tmp, b->description)) != TYPE_OTHER)
344  {
345  snprintf(type, len, "%s/%s",
346  (n == TYPE_AUDIO) ?
347  "audio" :
348  (n == TYPE_APPLICATION) ?
349  "application" :
350  (n == TYPE_IMAGE) ?
351  "image" :
352  (n == TYPE_MESSAGE) ?
353  "message" :
354  (n == TYPE_MODEL) ?
355  "model" :
356  (n == TYPE_MULTIPART) ?
357  "multipart" :
358  (n == TYPE_TEXT) ? "text" : (n == TYPE_VIDEO) ? "video" : "other",
359  tmp.subtype);
360  mutt_debug(LL_DEBUG1, "\"%s\" -> %s\n", b->filename, type);
361  }
362  FREE(&tmp.subtype);
363  FREE(&tmp.xtype);
364  }
365  }
366 }
Unknown Content-Type.
Definition: mime.h:31
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
Type: &#39;audio/*&#39;.
Definition: mime.h:32
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
The body of an email.
Definition: body.h:34
Type: &#39;video/*&#39;.
Definition: mime.h:39
char * subtype
content-type subtype
Definition: body.h:37
int mutt_str_strncasecmp(const char *a, const char *b, size_t l)
Compare two strings ignoring case (to a maximum), safely.
Definition: string.c:656
Type: &#39;text/*&#39;.
Definition: mime.h:38
char * xtype
content-type if x-unknown
Definition: body.h:36
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
char * description
content-description
Definition: body.h:40
unsigned int type
content-type primary type
Definition: body.h:65
Type: &#39;message/*&#39;.
Definition: mime.h:35
char * data
String.
Definition: list.h:35
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
Log at debug level 1.
Definition: logging.h:56
enum ContentType mutt_lookup_mime_type(struct Body *att, const char *path)
Find the MIME type for an attachment.
Definition: sendlib.c:1122
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
Type: &#39;model/*&#39;.
Definition: mime.h:36
#define FREE(x)
Definition: memory.h:40
Type: &#39;image/*&#39;.
Definition: mime.h:34
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
A List node for strings.
Definition: list.h:33
Type: &#39;application/*&#39;.
Definition: mime.h:33
ContentType
Content-Type.
Definition: mime.h:29
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_view_attachment()

int mutt_view_attachment ( FILE *  fp,
struct Body a,
enum ViewAttachMode  mode,
struct Email e,
struct AttachCtx actx,
struct MuttWindow win 
)

View an attachment.

Parameters
fpSource file stream. Can be NULL
aThe message body containing the attachment
modeHow the attachment should be viewed, see ViewAttachMode
eCurrent Email. Can be NULL
actxAttachment context
winWindow
Return values
0If the viewer is run and exited successfully
-1Error
numReturn value of mutt_do_pager() when it is used

Display a message attachment using the viewer program configured in mailcap. If there is no mailcap entry for a file type, view the image as text. Viewer processes are opened and waited on synchronously so viewing an attachment this way will block the main neomutt process until the viewer process exits.

Definition at line 386 of file mutt_attach.c.

388 {
389  bool use_mailcap = false;
390  bool use_pipe = false;
391  bool use_pager = true;
392  char type[256];
393  char desc[256];
394  char *fname = NULL;
395  struct MailcapEntry *entry = NULL;
396  int rc = -1;
397  bool unlink_tempfile = false;
398 
399  bool is_message = mutt_is_message_type(a->type, a->subtype);
400  if ((WithCrypto != 0) && is_message && a->email &&
402  {
403  return rc;
404  }
405 
406  struct Buffer *tmpfile = mutt_buffer_pool_get();
407  struct Buffer *pagerfile = mutt_buffer_pool_get();
408  struct Buffer *cmd = mutt_buffer_pool_get();
409 
410  use_mailcap =
411  (mode == MUTT_VA_MAILCAP || (mode == MUTT_VA_REGULAR && mutt_needs_mailcap(a)));
412  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
413 
414  char columns[16];
415  snprintf(columns, sizeof(columns), "%d", win->cols);
416  mutt_envlist_set("COLUMNS", columns, true);
417 
418  if (use_mailcap)
419  {
420  entry = mailcap_entry_new();
421  if (!mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_NO_FLAGS))
422  {
423  if (mode == MUTT_VA_REGULAR)
424  {
425  /* fallback to view as text */
426  mailcap_entry_free(&entry);
427  mutt_error(_("No matching mailcap entry found. Viewing as text."));
428  mode = MUTT_VA_AS_TEXT;
429  use_mailcap = false;
430  }
431  else
432  goto return_error;
433  }
434  }
435 
436  if (use_mailcap)
437  {
438  if (!entry->command)
439  {
440  mutt_error(_("MIME type not defined. Can't view attachment."));
441  goto return_error;
442  }
443  mutt_buffer_strcpy(cmd, entry->command);
444 
445  if (fp)
446  {
447  fname = mutt_str_strdup(a->filename);
448  mutt_file_sanitize_filename(fname, true);
449  }
450  else
451  fname = a->filename;
452 
453  mailcap_expand_filename(entry->nametemplate, fname, tmpfile);
454  /* send case: the file is already there; symlink to it */
455  if (!fp)
456  {
457  if (mutt_file_symlink(a->filename, mutt_b2s(tmpfile)) == -1)
458  {
459  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
460  goto return_error;
461  mutt_buffer_strcpy(tmpfile, a->filename);
462  }
463  else
464  unlink_tempfile = true;
465  }
466  /* recv case: we need to save the attachment to a file */
467  else
468  {
469  FREE(&fname);
470  if (mutt_save_attachment(fp, a, mutt_b2s(tmpfile), MUTT_SAVE_NO_FLAGS, NULL) == -1)
471  goto return_error;
472  mutt_file_chmod(mutt_b2s(tmpfile), S_IRUSR);
473  }
474 
475  use_pipe = mailcap_expand_command(a, mutt_b2s(tmpfile), type, cmd);
476  use_pager = entry->copiousoutput;
477  }
478 
479  if (use_pager)
480  {
481  if (fp && !use_mailcap && a->filename)
482  {
483  /* recv case */
484  mutt_buffer_strcpy(pagerfile, a->filename);
485  mutt_adv_mktemp(pagerfile);
486  }
487  else
488  mutt_buffer_mktemp(pagerfile);
489  }
490 
491  if (use_mailcap)
492  {
493  pid_t pid = 0;
494  int fd_temp = -1, fd_pager = -1;
495 
496  if (!use_pager)
497  mutt_endwin();
498 
499  if (use_pager || use_pipe)
500  {
501  if (use_pager && ((fd_pager = mutt_file_open(mutt_b2s(pagerfile),
502  O_CREAT | O_EXCL | O_WRONLY)) == -1))
503  {
504  mutt_perror("open");
505  goto return_error;
506  }
507  if (use_pipe && ((fd_temp = open(mutt_b2s(tmpfile), 0)) == -1))
508  {
509  if (fd_pager != -1)
510  close(fd_pager);
511  mutt_perror("open");
512  goto return_error;
513  }
514 
515  pid = mutt_create_filter_fd(mutt_b2s(cmd), NULL, NULL, NULL,
516  use_pipe ? fd_temp : -1,
517  use_pager ? fd_pager : -1, -1);
518 
519  if (pid == -1)
520  {
521  if (fd_pager != -1)
522  close(fd_pager);
523 
524  if (fd_temp != -1)
525  close(fd_temp);
526 
527  mutt_error(_("Can't create filter"));
528  goto return_error;
529  }
530 
531  if (use_pager)
532  {
533  if (a->description)
534  {
535  snprintf(desc, sizeof(desc), _("---Command: %-20.20s Description: %s"),
536  mutt_b2s(cmd), a->description);
537  }
538  else
539  {
540  snprintf(desc, sizeof(desc), _("---Command: %-30.30s Attachment: %s"),
541  mutt_b2s(cmd), type);
542  }
543  }
544 
545  if ((mutt_wait_filter(pid) || (entry->needsterminal && C_WaitKey)) && !use_pager)
547 
548  if (fd_temp != -1)
549  close(fd_temp);
550  if (fd_pager != -1)
551  close(fd_pager);
552  }
553  else
554  {
555  /* interactive cmd */
556  int rv = mutt_system(mutt_b2s(cmd));
557  if (rv == -1)
558  mutt_debug(LL_DEBUG1, "Error running \"%s\"", cmd->data);
559 
560  if ((rv != 0) || (entry->needsterminal && C_WaitKey))
562  }
563  }
564  else
565  {
566  /* Don't use mailcap; the attachment is viewed in the pager */
567 
568  if (mode == MUTT_VA_AS_TEXT)
569  {
570  /* just let me see the raw data */
571  if (fp)
572  {
573  /* Viewing from a received message.
574  *
575  * Don't use mutt_save_attachment() because we want to perform charset
576  * conversion since this will be displayed by the internal pager. */
577  struct State decode_state = { 0 };
578 
579  decode_state.fp_out = mutt_file_fopen(mutt_b2s(pagerfile), "w");
580  if (!decode_state.fp_out)
581  {
582  mutt_debug(LL_DEBUG1, "mutt_file_fopen(%s) errno=%d %s\n",
583  mutt_b2s(pagerfile), errno, strerror(errno));
584  mutt_perror(mutt_b2s(pagerfile));
585  goto return_error;
586  }
587  decode_state.fp_in = fp;
588  decode_state.flags = MUTT_CHARCONV;
589  mutt_decode_attachment(a, &decode_state);
590  if (fclose(decode_state.fp_out) == EOF)
591  mutt_debug(LL_DEBUG1, "fclose(%s) errno=%d %s\n", mutt_b2s(pagerfile),
592  errno, strerror(errno));
593  }
594  else
595  {
596  /* in compose mode, just copy the file. we can't use
597  * mutt_decode_attachment() since it assumes the content-encoding has
598  * already been applied */
599  if (mutt_save_attachment(fp, a, mutt_b2s(pagerfile), MUTT_SAVE_NO_FLAGS, NULL))
600  goto return_error;
601  }
602  }
603  else
604  {
605  /* Use built-in handler */
606  OptViewAttach = true; /* disable the "use 'v' to view this part"
607  * message in case of error */
609  {
610  OptViewAttach = false;
611  goto return_error;
612  }
613  OptViewAttach = false;
614  }
615 
616  if (a->description)
617  mutt_str_strfcpy(desc, a->description, sizeof(desc));
618  else if (a->filename)
619  snprintf(desc, sizeof(desc), _("---Attachment: %s: %s"), a->filename, type);
620  else
621  snprintf(desc, sizeof(desc), _("---Attachment: %s"), type);
622  }
623 
624  /* We only reach this point if there have been no errors */
625 
626  if (use_pager)
627  {
628  struct Pager info = { 0 };
629  info.fp = fp;
630  info.body = a;
631  info.ctx = Context;
632  info.actx = actx;
633  info.email = e;
634 
635  rc = mutt_do_pager(desc, mutt_b2s(pagerfile),
637  &info);
638  mutt_buffer_reset(pagerfile);
639  }
640  else
641  rc = 0;
642 
643 return_error:
644 
645  if (!entry || !entry->xneomuttkeep)
646  {
647  if (fp && !mutt_buffer_is_empty(tmpfile))
648  {
649  /* add temporary file to TempAttachmentsList to be deleted on timeout hook */
651  }
652  else if (unlink_tempfile)
653  {
654  unlink(mutt_b2s(tmpfile));
655  }
656  }
657 
658  mailcap_entry_free(&entry);
659 
660  if (!mutt_buffer_is_empty(pagerfile))
661  mutt_file_unlink(mutt_b2s(pagerfile));
662 
663  mutt_buffer_pool_release(&tmpfile);
664  mutt_buffer_pool_release(&pagerfile);
666  mutt_envlist_unset("COLUMNS");
667 
668  return rc;
669 }
bool xneomuttkeep
do not remove the file on command exit
Definition: mailcap.h:49
A mailcap entry.
Definition: mailcap.h:37
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1797
FILE * fp
Source stream.
Definition: pager.h:70
struct MailcapEntry * mailcap_entry_new(void)
Allocate memory for a new rfc1524 entry.
Definition: mailcap.c:429
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:79
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1389
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
#define mutt_perror(...)
Definition: logging.h:85
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
#define MUTT_PAGER_MESSAGE
Definition: pager.h:58
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
No flags set.
Definition: mutt_attach.h:55
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:194
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
FILE * fp_out
File to write to.
Definition: state.h:47
struct Body * body
Current attachment.
Definition: pager.h:69
Force viewing as text.
Definition: mutt_attach.h:44
No flags set.
Definition: mailcap.h:57
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:797
An email being displayed.
Definition: pager.h:65
View using default method.
Definition: mutt_attach.h:42
#define SEC_ENCRYPT
Email is encrypted.
Definition: ncrypt.h:122
FILE * fp_in
File to read from.
Definition: state.h:46
#define MUTT_PAGER_ATTACHMENT
Attachments may exist.
Definition: pager.h:55
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:467
int mailcap_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: mailcap.c:70
void mailcap_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: mailcap.c:522
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:147
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:375
bool copiousoutput
needs pager, basically
Definition: mailcap.h:48
int mutt_file_chmod(const char *path, mode_t mode)
Set permissions of a file.
Definition: file.c:1033
void mutt_add_temp_attachment(const char *filename)
Add file to list of temporary attachments.
Definition: mutt_attach.c:1189
char * command
Definition: mailcap.h:39
char * subtype
content-type subtype
Definition: body.h:37
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition: file.c:615
#define mutt_b2s(buf)
Definition: buffer.h:41
struct Context * ctx
Current mailbox.
Definition: pager.h:67
WHERE struct Context * Context
Definition: globals.h:44
WHERE bool C_WaitKey
Config: Prompt to press a key after running external commands.
Definition: globals.h:269
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:544
bool mutt_envlist_unset(const char *name)
Unset an environment variable.
Definition: envlist.c:131
void mailcap_entry_free(struct MailcapEntry **ptr)
Deallocate an struct MailcapEntry.
Definition: mailcap.c:438
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:928
struct AttachCtx * actx
Attachment information.
Definition: pager.h:71
char * data
Pointer to data.
Definition: buffer.h:35
pid_t mutt_create_filter_fd(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, int fdin, int fdout, int fderr)
Run a command on a pipe (optionally connect stdin/stdout)
Definition: filter.c:65
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
char * description
content-description
Definition: body.h:40
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/ncrypt.h pgplib.h, smime.h
Definition: email.h:39
Force viewing using mailcap entry.
Definition: mutt_attach.h:43
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
unsigned int type
content-type primary type
Definition: body.h:65
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:577
char * nametemplate
Definition: mailcap.h:45
#define TYPE(body)
Definition: mime.h:83
struct Email * email
Current message.
Definition: pager.h:68
int mutt_file_open(const char *path, int flags)
Open a file.
Definition: file.c:519
Log at debug level 1.
Definition: logging.h:56
int mutt_do_pager(const char *banner, const char *tempfile, PagerFlags do_color, struct Pager *info)
Display some page-able text to the user.
Definition: curs_lib.c:631
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#define mutt_error(...)
Definition: logging.h:84
bool mutt_needs_mailcap(struct Body *m)
Does this type need a mailcap entry do display.
Definition: muttlib.c:425
void mutt_adv_mktemp(struct Buffer *buf)
Create a temporary file.
Definition: muttlib.c:96
#define FREE(x)
Definition: memory.h:40
Keep track when processing files.
Definition: state.h:44
WHERE bool OptViewAttach
(pseudo) signals that we are viewing attachments
Definition: options.h:53
bool mutt_envlist_set(const char *name, const char *value, bool overwrite)
Set an environment variable.
Definition: envlist.c:84
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:296
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:585
int mutt_wait_filter(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:221
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
struct Email * email
header information for message/rfc822
Definition: body.h:55
#define WithCrypto
Definition: ncrypt.h:160
bool needsterminal
endwin() and system
Definition: mailcap.h:47
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
#define MUTT_PAGER_NO_FLAGS
No flags are set.
Definition: pager.h:43
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_pipe_attachment()

int mutt_pipe_attachment ( FILE *  fp,
struct Body b,
const char *  path,
char *  outfile 
)

Pipe an attachment to a command.

Parameters
fpFile to pipe into the command
bAttachment
pathPath to command
outfileFile to save output to
Return values
1Success
0Error

Definition at line 680 of file mutt_attach.c.

681 {
682  pid_t pid;
683  int out = -1;
684  int rc = 0;
685 
686  if (outfile && *outfile)
687  {
688  out = mutt_file_open(outfile, O_CREAT | O_EXCL | O_WRONLY);
689  if (out < 0)
690  {
691  mutt_perror("open");
692  return 0;
693  }
694  }
695 
696  mutt_endwin();
697 
698  if (fp)
699  {
700  /* recv case */
701 
702  struct State s = { 0 };
703 
704  /* perform charset conversion on text attachments when piping */
705  s.flags = MUTT_CHARCONV;
706 
707  if (outfile && *outfile)
708  pid = mutt_create_filter_fd(path, &s.fp_out, NULL, NULL, -1, out, -1);
709  else
710  pid = mutt_create_filter(path, &s.fp_out, NULL, NULL);
711 
712  if (pid < 0)
713  {
714  mutt_perror(_("Can't create filter"));
715  goto bail;
716  }
717 
718  s.fp_in = fp;
719  mutt_decode_attachment(b, &s);
721  }
722  else
723  {
724  /* send case */
725  FILE *fp_in = fopen(b->filename, "r");
726  if (!fp_in)
727  {
728  mutt_perror("fopen");
729  if (outfile && *outfile)
730  {
731  close(out);
732  unlink(outfile);
733  }
734  return 0;
735  }
736 
737  FILE *fp_out = NULL;
738  if (outfile && *outfile)
739  pid = mutt_create_filter_fd(path, &fp_out, NULL, NULL, -1, out, -1);
740  else
741  pid = mutt_create_filter(path, &fp_out, NULL, NULL);
742 
743  if (pid < 0)
744  {
745  mutt_perror(_("Can't create filter"));
746  mutt_file_fclose(&fp_in);
747  goto bail;
748  }
749 
750  mutt_file_copy_stream(fp_in, fp_out);
751  mutt_file_fclose(&fp_out);
752  mutt_file_fclose(&fp_in);
753  }
754 
755  rc = 1;
756 
757 bail:
758 
759  if (outfile && *outfile)
760  close(out);
761 
762  /* check for error exit from child process */
763  if (mutt_wait_filter(pid) != 0)
764  rc = 0;
765 
766  if ((rc == 0) || C_WaitKey)
768  return rc;
769 }
pid_t mutt_create_filter(const char *s, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:210
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1797
FILE * fp
Source stream.
Definition: pager.h:70
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
#define mutt_perror(...)
Definition: logging.h:85
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
#define _(a)
Definition: message.h:28
FILE * fp_out
File to write to.
Definition: state.h:47
FILE * fp_in
File to read from.
Definition: state.h:46
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
WHERE bool C_WaitKey
Config: Prompt to press a key after running external commands.
Definition: globals.h:269
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:544
pid_t mutt_create_filter_fd(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, int fdin, int fdout, int fderr)
Run a command on a pipe (optionally connect stdin/stdout)
Definition: filter.c:65
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:577
int mutt_file_open(const char *path, int flags)
Open a file.
Definition: file.c:519
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:270
Keep track when processing files.
Definition: state.h:44
int mutt_wait_filter(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:221
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ save_attachment_open()

static FILE* save_attachment_open ( const char *  path,
enum SaveAttach  opt 
)
static

Open a file to write an attachment to.

Parameters
pathPath to file to open
optSave option, see SaveAttach
Return values
ptrFile handle to attachment file

Definition at line 777 of file mutt_attach.c.

778 {
779  if (opt == MUTT_SAVE_APPEND)
780  return fopen(path, "a");
781  if (opt == MUTT_SAVE_OVERWRITE)
782  return fopen(path, "w");
783 
784  return mutt_file_fopen(path, "w");
785 }
Overwrite existing file.
Definition: mutt_attach.h:57
Append to existing file.
Definition: mutt_attach.h:56
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:585
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_save_attachment()

int mutt_save_attachment ( FILE *  fp,
struct Body m,
const char *  path,
enum SaveAttach  opt,
struct Email e 
)

Save an attachment.

Parameters
fpSource file stream. Can be NULL
mEmail Body
pathWhere to save the attachment
optSave option, see SaveAttach
eCurrent Email. Can be NULL
Return values
0Success
-1Error

Definition at line 797 of file mutt_attach.c.

799 {
800  if (!m)
801  return -1;
802 
803  if (fp)
804  {
805  /* recv mode */
806 
807  if (e && m->email && (m->encoding != ENC_BASE64) &&
809  {
810  /* message type attachments are written to mail folders. */
811 
812  char buf[8192];
813  struct Message *msg = NULL;
814  CopyHeaderFlags chflags = CH_NO_FLAGS;
815  int rc = -1;
816 
817  struct Email *e_new = m->email;
818  e_new->msgno = e->msgno; /* required for MH/maildir */
819  e_new->read = true;
820 
821  if (fseeko(fp, m->offset, SEEK_SET) < 0)
822  return -1;
823  if (!fgets(buf, sizeof(buf), fp))
824  return -1;
825  struct Mailbox *m_att = mx_path_resolve(path);
826  struct Context *ctx = mx_mbox_open(m_att, MUTT_APPEND | MUTT_QUIET);
827  if (!ctx)
828  {
829  mailbox_free(&m_att);
830  return -1;
831  }
832  msg = mx_msg_open_new(ctx->mailbox, e_new,
833  is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
834  if (!msg)
835  {
836  mx_mbox_close(&ctx);
837  return -1;
838  }
839  if ((ctx->mailbox->magic == MUTT_MBOX) || (ctx->mailbox->magic == MUTT_MMDF))
840  chflags = CH_FROM | CH_UPDATE_LEN;
841  chflags |= ((ctx->mailbox->magic == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
842  if ((mutt_copy_message_fp(msg->fp, fp, e_new, MUTT_CM_NO_FLAGS, chflags, 0) == 0) &&
843  (mx_msg_commit(ctx->mailbox, msg) == 0))
844  {
845  rc = 0;
846  }
847  else
848  {
849  rc = -1;
850  }
851 
852  mx_msg_close(ctx->mailbox, &msg);
853  mx_mbox_close(&ctx);
854  return rc;
855  }
856  else
857  {
858  /* In recv mode, extract from folder and decode */
859 
860  struct State s = { 0 };
861 
862  s.fp_out = save_attachment_open(path, opt);
863  if (!s.fp_out)
864  {
865  mutt_perror("fopen");
866  return -1;
867  }
868  fseeko((s.fp_in = fp), m->offset, SEEK_SET);
869  mutt_decode_attachment(m, &s);
870 
871  if (mutt_file_fsync_close(&s.fp_out) != 0)
872  {
873  mutt_perror("fclose");
874  return -1;
875  }
876  }
877  }
878  else
879  {
880  if (!m->filename)
881  return -1;
882 
883  /* In send mode, just copy file */
884 
885  FILE *fp_old = fopen(m->filename, "r");
886  if (!fp_old)
887  {
888  mutt_perror("fopen");
889  return -1;
890  }
891 
892  FILE *fp_new = save_attachment_open(path, opt);
893  if (!fp_new)
894  {
895  mutt_perror("fopen");
896  mutt_file_fclose(&fp_old);
897  return -1;
898  }
899 
900  if (mutt_file_copy_stream(fp_old, fp_new) == -1)
901  {
902  mutt_error(_("Write fault"));
903  mutt_file_fclose(&fp_old);
904  mutt_file_fclose(&fp_new);
905  return -1;
906  }
907  mutt_file_fclose(&fp_old);
908  if (mutt_file_fsync_close(&fp_new) != 0)
909  {
910  mutt_error(_("Write fault"));
911  return -1;
912  }
913  }
914 
915  return 0;
916 }
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mx.h:52
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:63
The "current" mailbox.
Definition: context.h:36
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1797
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1389
The envelope/body of an email.
Definition: email.h:37
#define mutt_perror(...)
Definition: logging.h:85
int mx_mbox_close(struct Context **ptr)
Save changes and close mailbox.
Definition: mx.c:561
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:168
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:55
#define _(a)
Definition: message.h:28
#define CH_NOSTATUS
Suppress the status and x-status fields.
Definition: copy.h:57
struct Context * mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:253
FILE * fp_out
File to write to.
Definition: state.h:47
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:51
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:34
FILE * fp_in
File to read from.
Definition: state.h:46
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1101
bool read
Email is read.
Definition: email.h:51
struct Mailbox * mailbox
Definition: context.h:50
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:55
enum MailboxType magic
Mailbox type.
Definition: mailbox.h:116
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
unsigned int encoding
content-transfer-encoding
Definition: body.h:66
struct Message * mx_msg_open_new(struct Mailbox *m, struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:970
Base-64 encoded text.
Definition: mime.h:52
&#39;Maildir&#39; Mailbox type
Definition: mailbox.h:50
char * subtype
content-type subtype
Definition: body.h:37
A local copy of an email.
Definition: mx.h:81
A mailbox.
Definition: mailbox.h:92
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:50
&#39;mmdf&#39; Mailbox type
Definition: mailbox.h:48
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:61
#define MUTT_QUIET
Do not print any messages.
Definition: mx.h:54
unsigned int type
content-type primary type
Definition: body.h:65
&#39;mbox&#39; Mailbox type
Definition: mailbox.h:47
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:270
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:49
#define mutt_error(...)
Definition: logging.h:84
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1080
Quoted-printable text.
Definition: mime.h:51
FILE * fp
pointer to the message data
Definition: mx.h:83
struct Mailbox * mx_path_resolve(const char *path)
XXX.
Definition: mx.c:1552
Keep track when processing files.
Definition: state.h:44
static FILE * save_attachment_open(const char *path, enum SaveAttach opt)
Open a file to write an attachment to.
Definition: mutt_attach.c:777
bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
Is a string a &#39;From&#39; header line?
Definition: from.c:49
int mutt_copy_message_fp(FILE *fp_out, FILE *fp_in, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
make a copy of a message from a FILE pointer
Definition: copy.c:598
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:64
struct Email * email
header information for message/rfc822
Definition: body.h:55
int msgno
Number displayed to the user.
Definition: email.h:86
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_decode_save_attachment()

int mutt_decode_save_attachment ( FILE *  fp,
struct Body m,
const char *  path,
int  displaying,
enum SaveAttach  opt 
)

Decode, then save an attachment.

Parameters
fpFile to read from (OPTIONAL)
mAttachment
pathPath to save the Attachment to
displayingFlags, e.g. MUTT_DISPLAY
optSave option, see SaveAttach
Return values
0Success
-1Error

Definition at line 928 of file mutt_attach.c.

930 {
931  struct State s = { 0 };
932  unsigned int saved_encoding = 0;
933  struct Body *saved_parts = NULL;
934  struct Email *e_saved = NULL;
935  int rc = 0;
936 
937  s.flags = displaying;
938 
939  if (opt == MUTT_SAVE_APPEND)
940  s.fp_out = fopen(path, "a");
941  else if (opt == MUTT_SAVE_OVERWRITE)
942  s.fp_out = fopen(path, "w");
943  else
944  s.fp_out = mutt_file_fopen(path, "w");
945 
946  if (!s.fp_out)
947  {
948  mutt_perror("fopen");
949  return -1;
950  }
951 
952  if (!fp)
953  {
954  /* When called from the compose menu, the attachment isn't parsed,
955  * so we need to do it here. */
956  struct stat st;
957 
958  if (stat(m->filename, &st) == -1)
959  {
960  mutt_perror("stat");
962  return -1;
963  }
964 
965  s.fp_in = fopen(m->filename, "r");
966  if (!s.fp_in)
967  {
968  mutt_perror("fopen");
969  return -1;
970  }
971 
972  saved_encoding = m->encoding;
973  if (!is_multipart(m))
974  m->encoding = ENC_8BIT;
975 
976  m->length = st.st_size;
977  m->offset = 0;
978  saved_parts = m->parts;
979  e_saved = m->email;
980  mutt_parse_part(s.fp_in, m);
981 
982  if (m->noconv || is_multipart(m))
983  s.flags |= MUTT_CHARCONV;
984  }
985  else
986  {
987  s.fp_in = fp;
988  s.flags |= MUTT_CHARCONV;
989  }
990 
991  mutt_body_handler(m, &s);
992 
993  if (mutt_file_fsync_close(&s.fp_out) != 0)
994  {
995  mutt_perror("fclose");
996  rc = -1;
997  }
998  if (!fp)
999  {
1000  m->length = 0;
1001  m->encoding = saved_encoding;
1002  if (saved_parts)
1003  {
1004  email_free(&m->email);
1005  m->parts = saved_parts;
1006  m->email = e_saved;
1007  }
1008  mutt_file_fclose(&s.fp_in);
1009  }
1010 
1011  return rc;
1012 }
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
The envelope/body of an email.
Definition: email.h:37
#define mutt_perror(...)
Definition: logging.h:85
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
#define is_multipart(body)
Definition: mime.h:77
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:168
bool noconv
Don&#39;t do character set conversion.
Definition: body.h:73
Overwrite existing file.
Definition: mutt_attach.h:57
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
8-bit text
Definition: mime.h:50
FILE * fp_out
File to write to.
Definition: state.h:47
FILE * fp_in
File to read from.
Definition: state.h:46
The body of an email.
Definition: body.h:34
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
unsigned int encoding
content-transfer-encoding
Definition: body.h:66
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1404
char * path
Path of Email (for local Mailboxes)
Definition: email.h:91
Append to existing file.
Definition: mutt_attach.h:56
Keep track when processing files.
Definition: state.h:44
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1551
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:585
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:41
struct Email * email
header information for message/rfc822
Definition: body.h:55
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_print_attachment()

int mutt_print_attachment ( FILE *  fp,
struct Body a 
)

Print out an attachment.

Parameters
fpFile to write to
aAttachment
Return values
1Success
0Error

Ok, the difference between send and receive: recv: Body->filename is a suggested name, and Mailbox|Email points to the attachment in mailbox which is encoded send: Body->filename points to the un-encoded file which contains the attachment

Definition at line 1027 of file mutt_attach.c.

1028 {
1029  char type[256];
1030  pid_t pid;
1031  FILE *fp_in = NULL, *fp_out = NULL;
1032  bool unlink_newfile = false;
1033  struct Buffer *newfile = mutt_buffer_pool_get();
1034  struct Buffer *cmd = mutt_buffer_pool_get();
1035 
1036  int rc = 0;
1037 
1038  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
1039 
1040  if (mailcap_lookup(a, type, sizeof(type), NULL, MUTT_MC_PRINT))
1041  {
1042  int piped = false;
1043 
1044  mutt_debug(LL_DEBUG2, "Using mailcap\n");
1045 
1046  struct MailcapEntry *entry = mailcap_entry_new();
1047  mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_PRINT);
1048  mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
1049  /* send mode: symlink from existing file to the newfile */
1050  if (!fp)
1051  {
1052  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
1053  {
1054  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
1055  goto mailcap_cleanup;
1056  mutt_buffer_strcpy(newfile, a->filename);
1057  }
1058  else
1059  unlink_newfile = true;
1060  }
1061  /* in recv mode, save file to newfile first */
1062  else
1063  {
1064  if (mutt_save_attachment(fp, a, mutt_b2s(newfile), 0, NULL) == -1)
1065  goto mailcap_cleanup;
1066  }
1067 
1068  mutt_buffer_strcpy(cmd, entry->printcommand);
1069  piped = mailcap_expand_command(a, mutt_b2s(newfile), type, cmd);
1070 
1071  mutt_endwin();
1072 
1073  /* interactive program */
1074  if (piped)
1075  {
1076  fp_in = fopen(mutt_b2s(newfile), "r");
1077  if (!fp_in)
1078  {
1079  mutt_perror("fopen");
1080  mailcap_entry_free(&entry);
1081  goto mailcap_cleanup;
1082  }
1083 
1084  pid = mutt_create_filter(mutt_b2s(cmd), &fp_out, NULL, NULL);
1085  if (pid < 0)
1086  {
1087  mutt_perror(_("Can't create filter"));
1088  mailcap_entry_free(&entry);
1089  mutt_file_fclose(&fp_in);
1090  goto mailcap_cleanup;
1091  }
1092  mutt_file_copy_stream(fp_in, fp_out);
1093  mutt_file_fclose(&fp_out);
1094  mutt_file_fclose(&fp_in);
1095  if (mutt_wait_filter(pid) || C_WaitKey)
1097  }
1098  else
1099  {
1100  int rc2 = mutt_system(mutt_b2s(cmd));
1101  if (rc2 == -1)
1102  mutt_debug(LL_DEBUG1, "Error running \"%s\"", cmd->data);
1103 
1104  if ((rc2 != 0) || C_WaitKey)
1106  }
1107 
1108  rc = 1;
1109 
1110  mailcap_cleanup:
1111  if (fp)
1112  mutt_file_unlink(mutt_b2s(newfile));
1113  else if (unlink_newfile)
1114  unlink(mutt_b2s(newfile));
1115 
1116  mailcap_entry_free(&entry);
1117  goto out;
1118  }
1119 
1120  if ((mutt_str_strcasecmp("text/plain", type) == 0) ||
1121  (mutt_str_strcasecmp("application/postscript", type) == 0))
1122  {
1123  rc = (mutt_pipe_attachment(fp, a, NONULL(C_PrintCommand), NULL));
1124  goto out;
1125  }
1126  else if (mutt_can_decode(a))
1127  {
1128  /* decode and print */
1129 
1130  fp_in = NULL;
1131  fp_out = NULL;
1132 
1133  mutt_buffer_mktemp(newfile);
1134  if (mutt_decode_save_attachment(fp, a, mutt_b2s(newfile), MUTT_PRINTING, 0) == 0)
1135  {
1136  mutt_debug(LL_DEBUG2, "successfully decoded %s type attachment to %s\n",
1137  type, mutt_b2s(newfile));
1138 
1139  fp_in = fopen(mutt_b2s(newfile), "r");
1140  if (!fp_in)
1141  {
1142  mutt_perror("fopen");
1143  goto decode_cleanup;
1144  }
1145 
1146  mutt_debug(LL_DEBUG2, "successfully opened %s read-only\n", mutt_b2s(newfile));
1147 
1148  mutt_endwin();
1149  pid = mutt_create_filter(NONULL(C_PrintCommand), &fp_out, NULL, NULL);
1150  if (pid < 0)
1151  {
1152  mutt_perror(_("Can't create filter"));
1153  goto decode_cleanup;
1154  }
1155 
1156  mutt_debug(LL_DEBUG2, "Filter created\n");
1157 
1158  mutt_file_copy_stream(fp_in, fp_out);
1159 
1160  mutt_file_fclose(&fp_out);
1161  mutt_file_fclose(&fp_in);
1162 
1163  if ((mutt_wait_filter(pid) != 0) || C_WaitKey)
1165  rc = 1;
1166  }
1167  decode_cleanup:
1168  mutt_file_fclose(&fp_in);
1169  mutt_file_fclose(&fp_out);
1170  mutt_file_unlink(mutt_b2s(newfile));
1171  }
1172  else
1173  {
1174  mutt_error(_("I don't know how to print that"));
1175  rc = 0;
1176  }
1177 
1178 out:
1179  mutt_buffer_pool_release(&newfile);
1181 
1182  return rc;
1183 }
pid_t mutt_create_filter(const char *s, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:210
A mailcap entry.
Definition: mailcap.h:37
struct MailcapEntry * mailcap_entry_new(void)
Allocate memory for a new rfc1524 entry.
Definition: mailcap.c:429
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:79
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
#define NONULL(x)
Definition: string2.h:37
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
#define mutt_perror(...)
Definition: logging.h:85
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:194
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
#define MUTT_PRINTING
Are we printing? - MUTT_DISPLAY "light".
Definition: state.h:37
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:797
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:467
int mailcap_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: mailcap.c:70
void mailcap_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: mailcap.c:522
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:375
Log at debug level 2.
Definition: logging.h:57
Mailcap print field.
Definition: mailcap.h:60
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
char * subtype
content-type subtype
Definition: body.h:37
#define mutt_b2s(buf)
Definition: buffer.h:41
WHERE bool C_WaitKey
Config: Prompt to press a key after running external commands.
Definition: globals.h:269
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:544
void mailcap_entry_free(struct MailcapEntry **ptr)
Deallocate an struct MailcapEntry.
Definition: mailcap.c:438
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:928
bool mutt_can_decode(struct Body *a)
Will decoding the attachment produce any output.
Definition: handler.c:1756
char * data
Pointer to data.
Definition: buffer.h:35
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
char * printcommand
Definition: mailcap.h:44
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:577
char * nametemplate
Definition: mailcap.h:45
#define TYPE(body)
Definition: mime.h:83
Log at debug level 1.
Definition: logging.h:56
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:270
#define mutt_error(...)
Definition: logging.h:84
WHERE char * C_PrintCommand
Config: External command to print a message.
Definition: globals.h:138
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:296
int mutt_wait_filter(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:221
int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, char *outfile)
Pipe an attachment to a command.
Definition: mutt_attach.c:680
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_add_temp_attachment()

void mutt_add_temp_attachment ( const char *  filename)

Add file to list of temporary attachments.

Parameters
filenamefilename with full path

Definition at line 1189 of file mutt_attach.c.

1190 {
1191  mutt_list_insert_tail(&TempAttachmentsList, mutt_str_strdup(filename));
1192 }
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:65
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_unlink_temp_attachments()

void mutt_unlink_temp_attachments ( void  )

Delete all temporary attachments.

Definition at line 1197 of file mutt_attach.c.

1198 {
1199  struct ListNode *np = NULL;
1200 
1201  STAILQ_FOREACH(np, &TempAttachmentsList, entries)
1202  {
1203  mutt_file_chmod_add(np->data, S_IWUSR);
1204  mutt_file_unlink(np->data);
1205  }
1206 
1207  mutt_list_free(&TempAttachmentsList);
1208 }
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:194
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:123
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
char * data
String.
Definition: list.h:35
int mutt_file_chmod_add(const char *path, mode_t mode)
Add permissions to a file.
Definition: file.c:1057
A List node for strings.
Definition: list.h:33
+ Here is the call graph for this function:
+ Here is the caller graph for this function: