NeoMutt  2018-07-16 +1783-b00bd9
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 <limits.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 "mutt.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 "mailbox.h"
#include "muttlib.h"
#include "mx.h"
#include "ncrypt/ncrypt.h"
#include "options.h"
#include "pager.h"
#include "protos.h"
#include "rfc1524.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)
 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

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

68 {
69  char type[256];
70  struct stat st;
71 
72  if (a->unlink)
73  return 0;
74 
75  struct Buffer *tmpfile = mutt_buffer_pool_get();
76  struct Rfc1524MailcapEntry *entry = rfc1524_new_entry();
77  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
80 
81  rfc1524_free_entry(&entry);
82 
83  if (stat(a->filename, &st) == -1)
84  {
85  mutt_buffer_pool_release(&tmpfile);
86  return -1;
87  }
88 
89  FILE *fp_in = NULL, *fp_out = NULL;
90  if ((fp_in = fopen(a->filename, "r")) &&
91  (fp_out = mutt_file_fopen(mutt_b2s(tmpfile), "w")))
92  {
93  mutt_file_copy_stream(fp_in, fp_out);
94  mutt_str_replace(&a->filename, mutt_b2s(tmpfile));
95  a->unlink = true;
96 
97  if (a->stamp >= st.st_mtime)
99  }
100  else
101  mutt_perror(fp_in ? mutt_b2s(tmpfile) : a->filename);
102 
103  mutt_file_fclose(&fp_in);
104  mutt_file_fclose(&fp_out);
105 
106  mutt_buffer_pool_release(&tmpfile);
107 
108  return a->unlink ? 0 : -1;
109 }
void mutt_stamp_attachment(struct Body *a)
Timestamp an Attachment.
Definition: sendlib.c:1410
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:48
#define mutt_perror(...)
Definition: logging.h:84
bool rfc1524_mailcap_lookup(struct Body *a, char *type, struct Rfc1524MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: rfc1524.c:468
String manipulation buffer.
Definition: buffer.h:33
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
char * nametemplate
Definition: rfc1524.h:45
char * subtype
content-type subtype
Definition: body.h:37
#define mutt_b2s(buf)
Definition: buffer.h:42
void rfc1524_free_entry(struct Rfc1524MailcapEntry **entry)
Deallocate an struct Rfc1524MailcapEntry.
Definition: rfc1524.c:440
int mutt_rfc1524_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: rfc1524.c:533
A mailcap entry.
Definition: rfc1524.h:37
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:456
#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:264
No flags set.
Definition: rfc1524.h:57
time_t stamp
time stamp of last encoding update.
Definition: body.h:68
bool unlink
flag to indicate the file named by "filename" should be unlink()ed before free()ing this structure ...
Definition: body.h:76
struct Rfc1524MailcapEntry * rfc1524_new_entry(void)
Allocate memory for a new rfc1524 entry.
Definition: rfc1524.c:431
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:578
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: buffer.c:409
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: buffer.c:398

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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 117 of file mutt_attach.c.

118 {
119  char type[256];
120  struct Rfc1524MailcapEntry *entry = rfc1524_new_entry();
121  bool unlink_newfile = false;
122  int rc = 0;
123  struct Buffer *cmd = mutt_buffer_pool_get();
124  struct Buffer *newfile = mutt_buffer_pool_get();
125  struct Buffer *tmpfile = mutt_buffer_pool_get();
126 
127  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
128  if (rfc1524_mailcap_lookup(a, type, entry, MUTT_MC_COMPOSE))
129  {
130  if (entry->composecommand || entry->composetypecommand)
131  {
132  if (entry->composetypecommand)
134  else
135  mutt_buffer_strcpy(cmd, entry->composecommand);
136 
137  if (mutt_rfc1524_expand_filename(entry->nametemplate, a->filename, newfile))
138  {
139  mutt_debug(LL_DEBUG1, "oldfile: %s\t newfile: %s\n", a->filename, mutt_b2s(newfile));
140  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
141  {
142  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
143  goto bailout;
144  }
145  else
146  unlink_newfile = true;
147  }
148  else
149  mutt_buffer_strcpy(newfile, a->filename);
150 
151  if (mutt_buffer_rfc1524_expand_command(a, mutt_b2s(newfile), type, cmd))
152  {
153  /* For now, editing requires a file, no piping */
154  mutt_error(_("Mailcap compose entry requires %%s"));
155  }
156  else
157  {
158  int r;
159 
160  mutt_endwin();
161  r = mutt_system(mutt_b2s(cmd));
162  if (r == -1)
163  mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
164 
165  if ((r != -1) && entry->composetypecommand)
166  {
167  struct Body *b = NULL;
168 
169  FILE *fp = mutt_file_fopen(a->filename, "r");
170  if (!fp)
171  {
172  mutt_perror(_("Failure to open file to parse headers"));
173  goto bailout;
174  }
175 
176  b = mutt_read_mime_header(fp, 0);
177  if (b)
178  {
179  if (!TAILQ_EMPTY(&b->parameter))
180  {
182  a->parameter = b->parameter;
183  TAILQ_INIT(&b->parameter);
184  }
185  if (b->description)
186  {
187  FREE(&a->description);
188  a->description = b->description;
189  b->description = NULL;
190  }
191  if (b->form_name)
192  {
193  FREE(&a->form_name);
194  a->form_name = b->form_name;
195  b->form_name = NULL;
196  }
197 
198  /* Remove headers by copying out data to another file, then
199  * copying the file back */
200  fseeko(fp, b->offset, SEEK_SET);
201  mutt_body_free(&b);
202  mutt_buffer_mktemp(tmpfile);
203  FILE *fp_tmp = mutt_file_fopen(mutt_b2s(tmpfile), "w");
204  if (!fp_tmp)
205  {
206  mutt_perror(_("Failure to open file to strip headers"));
207  mutt_file_fclose(&fp);
208  goto bailout;
209  }
210  mutt_file_copy_stream(fp, fp_tmp);
211  mutt_file_fclose(&fp);
212  mutt_file_fclose(&fp_tmp);
214  if (mutt_file_rename(mutt_b2s(tmpfile), a->filename) != 0)
215  {
216  mutt_perror(_("Failure to rename file"));
217  goto bailout;
218  }
219  }
220  }
221  }
222  }
223  }
224  else
225  {
226  mutt_message(_("No mailcap compose entry for %s, creating empty file"), type);
227  rc = 1;
228  goto bailout;
229  }
230 
231  rc = 1;
232 
233 bailout:
234 
235  if (unlink_newfile)
236  unlink(mutt_b2s(newfile));
237 
239  mutt_buffer_pool_release(&newfile);
240  mutt_buffer_pool_release(&tmpfile);
241 
242  rfc1524_free_entry(&entry);
243  return rc;
244 }
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:77
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:48
#define mutt_perror(...)
Definition: logging.h:84
bool rfc1524_mailcap_lookup(struct Body *a, char *type, struct Rfc1524MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: rfc1524.c:468
#define mutt_message(...)
Definition: logging.h:82
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition: file.c:1312
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:191
String manipulation buffer.
Definition: buffer.h:33
LOFF_T offset
offset where the actual data begins
Definition: body.h:46
#define _(a)
Definition: message.h:28
Mailcap compose field.
Definition: rfc1524.h:59
char * form_name
Content-Disposition form-data name param.
Definition: body.h:41
The body of an email.
Definition: body.h:34
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:332
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
#define TAILQ_INIT(head)
Definition: queue.h:759
char * nametemplate
Definition: rfc1524.h:45
char * subtype
content-type subtype
Definition: body.h:37
#define mutt_b2s(buf)
Definition: buffer.h:42
int mutt_buffer_rfc1524_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: rfc1524.c:155
void rfc1524_free_entry(struct Rfc1524MailcapEntry **entry)
Deallocate an struct Rfc1524MailcapEntry.
Definition: rfc1524.c:440
void mutt_param_free(struct ParameterList *p)
Free a ParameterList.
Definition: parameter.c:61
void mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:322
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:499
int mutt_rfc1524_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: rfc1524.c:533
A mailcap entry.
Definition: rfc1524.h:37
char * description
content-description
Definition: body.h:40
char * composetypecommand
Definition: rfc1524.h:42
char * composecommand
Definition: rfc1524.h:41
#define TYPE(body)
Definition: mime.h:83
void mutt_body_free(struct Body **p)
Free a Body.
Definition: body.c:57
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:264
#define mutt_error(...)
Definition: logging.h:83
bool unlink
flag to indicate the file named by "filename" should be unlink()ed before free()ing this structure ...
Definition: body.h:76
struct Rfc1524MailcapEntry * rfc1524_new_entry(void)
Allocate memory for a new rfc1524 entry.
Definition: rfc1524.c:431
#define FREE(x)
Definition: memory.h:40
#define mutt_debug(LEVEL,...)
Definition: logging.h:80
#define TAILQ_EMPTY(head)
Definition: queue.h:715
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:290
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:578
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: buffer.c:409
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:50
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1161
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: buffer.c:398

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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 259 of file mutt_attach.c.

260 {
261  char type[256];
262  struct Rfc1524MailcapEntry *entry = rfc1524_new_entry();
263  bool unlink_newfile = false;
264  int rc = 0;
265  struct Buffer *cmd = mutt_buffer_pool_get();
266  struct Buffer *newfile = mutt_buffer_pool_get();
267 
268  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
269  if (rfc1524_mailcap_lookup(a, type, entry, MUTT_MC_EDIT))
270  {
271  if (entry->editcommand)
272  {
273  mutt_buffer_strcpy(cmd, entry->editcommand);
274  if (mutt_rfc1524_expand_filename(entry->nametemplate, a->filename, newfile))
275  {
276  mutt_debug(LL_DEBUG1, "oldfile: %s\t newfile: %s\n", a->filename, mutt_b2s(newfile));
277  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
278  {
279  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
280  goto bailout;
281  }
282  else
283  unlink_newfile = true;
284  }
285  else
286  mutt_buffer_strcpy(newfile, a->filename);
287 
288  if (mutt_buffer_rfc1524_expand_command(a, mutt_b2s(newfile), type, cmd))
289  {
290  /* For now, editing requires a file, no piping */
291  mutt_error(_("Mailcap Edit entry requires %%s"));
292  goto bailout;
293  }
294  else
295  {
296  mutt_endwin();
297  if (mutt_system(mutt_b2s(cmd)) == -1)
298  {
299  mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
300  goto bailout;
301  }
302  }
303  }
304  }
305  else if (a->type == TYPE_TEXT)
306  {
307  /* On text, default to editor */
309  }
310  else
311  {
312  mutt_error(_("No mailcap edit entry for %s"), type);
313  rc = 0;
314  goto bailout;
315  }
316 
317  rc = 1;
318 
319 bailout:
320 
321  if (unlink_newfile)
322  unlink(mutt_b2s(newfile));
323 
325  mutt_buffer_pool_release(&newfile);
326 
327  rfc1524_free_entry(&entry);
328  return rc;
329 }
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:48
#define NONULL(x)
Definition: string2.h:36
bool rfc1524_mailcap_lookup(struct Body *a, char *type, struct Rfc1524MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: rfc1524.c:468
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
Mailcap edit field.
Definition: rfc1524.h:58
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:332
char * nametemplate
Definition: rfc1524.h:45
char * subtype
content-type subtype
Definition: body.h:37
#define mutt_b2s(buf)
Definition: buffer.h:42
int mutt_buffer_rfc1524_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: rfc1524.c:155
void rfc1524_free_entry(struct Rfc1524MailcapEntry **entry)
Deallocate an struct Rfc1524MailcapEntry.
Definition: rfc1524.c:440
void mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:322
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:499
Type: &#39;text/*&#39;.
Definition: mime.h:38
int mutt_rfc1524_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: rfc1524.c:533
A mailcap entry.
Definition: rfc1524.h:37
unsigned int type
content-type primary type
Definition: body.h:72
#define TYPE(body)
Definition: mime.h:83
Log at debug level 1.
Definition: logging.h:56
#define mutt_error(...)
Definition: logging.h:83
WHERE char * C_Editor
Config: External command to use as an email editor.
Definition: globals.h:104
char * editcommand
Definition: rfc1524.h:43
struct Rfc1524MailcapEntry * rfc1524_new_entry(void)
Allocate memory for a new rfc1524 entry.
Definition: rfc1524.c:431
#define mutt_debug(LEVEL,...)
Definition: logging.h:80
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:290
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: buffer.c:409
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition: curs_lib.c:308
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:50
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: buffer.c:398

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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 337 of file mutt_attach.c.

338 {
339  struct ListNode *np = NULL;
340  STAILQ_FOREACH(np, &MimeLookupList, entries)
341  {
342  const int i = mutt_str_strlen(np->data) - 1;
343  if (((i > 0) && (np->data[i - 1] == '/') && (np->data[i] == '*') &&
344  (mutt_str_strncasecmp(type, np->data, i) == 0)) ||
345  (mutt_str_strcasecmp(type, np->data) == 0))
346  {
347  struct Body tmp = { 0 };
348  int n;
349  n = mutt_lookup_mime_type(&tmp, b->filename);
350  if (n != TYPE_OTHER)
351  {
352  snprintf(type, len, "%s/%s",
353  (n == TYPE_AUDIO) ?
354  "audio" :
355  (n == TYPE_APPLICATION) ?
356  "application" :
357  (n == TYPE_IMAGE) ?
358  "image" :
359  (n == TYPE_MESSAGE) ?
360  "message" :
361  (n == TYPE_MODEL) ?
362  "model" :
363  (n == TYPE_MULTIPART) ?
364  "multipart" :
365  (n == TYPE_TEXT) ? "text" : (n == TYPE_VIDEO) ? "video" : "other",
366  tmp.subtype);
367  mutt_debug(LL_DEBUG1, "\"%s\" -> %s\n", b->filename, type);
368  }
369  if (tmp.subtype)
370  FREE(&tmp.subtype);
371  if (tmp.xtype)
372  FREE(&tmp.xtype);
373  }
374  }
375 }
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:48
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:669
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:659
Type: &#39;text/*&#39;.
Definition: mime.h:38
char * xtype
content-type if x-unknown
Definition: body.h:36
int mutt_lookup_mime_type(struct Body *att, const char *path)
Find the MIME type for an attachment.
Definition: sendlib.c:1088
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
unsigned int type
content-type primary type
Definition: body.h:72
Type: &#39;message/*&#39;.
Definition: mime.h:35
char * data
Definition: list.h:35
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
Log at debug level 1.
Definition: logging.h:56
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:631
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:80
A List node for strings.
Definition: list.h:33
Type: &#39;application/*&#39;.
Definition: mime.h:33

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

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
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 394 of file mutt_attach.c.

396 {
397  bool use_mailcap = false;
398  bool use_pipe = false;
399  bool use_pager = true;
400  char type[256];
401  char desc[256];
402  char *fname = NULL;
403  struct Rfc1524MailcapEntry *entry = NULL;
404  int rc = -1;
405  bool unlink_tempfile = false;
406 
407  bool is_message = mutt_is_message_type(a->type, a->subtype);
408  if ((WithCrypto != 0) && is_message && a->email &&
410  {
411  return rc;
412  }
413 
414  struct Buffer *tmpfile = mutt_buffer_pool_get();
415  struct Buffer *pagerfile = mutt_buffer_pool_get();
416  struct Buffer *cmd = mutt_buffer_pool_get();
417 
418  use_mailcap =
419  (mode == MUTT_VA_MAILCAP || (mode == MUTT_VA_REGULAR && mutt_needs_mailcap(a)));
420  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
421 
422  if (use_mailcap)
423  {
424  entry = rfc1524_new_entry();
425  if (!rfc1524_mailcap_lookup(a, type, entry, MUTT_MC_NO_FLAGS))
426  {
427  if (mode == MUTT_VA_REGULAR)
428  {
429  /* fallback to view as text */
430  rfc1524_free_entry(&entry);
431  mutt_error(_("No matching mailcap entry found. Viewing as text."));
432  mode = MUTT_VA_AS_TEXT;
433  use_mailcap = false;
434  }
435  else
436  goto return_error;
437  }
438  }
439 
440  if (use_mailcap)
441  {
442  if (!entry->command)
443  {
444  mutt_error(_("MIME type not defined. Can't view attachment."));
445  goto return_error;
446  }
447  mutt_buffer_strcpy(cmd, entry->command);
448 
449  if (fp)
450  {
451  fname = mutt_str_strdup(a->filename);
452  mutt_file_sanitize_filename(fname, true);
453  }
454  else
455  fname = a->filename;
456 
457  if (mutt_rfc1524_expand_filename(entry->nametemplate, fname, tmpfile))
458  {
459  if (!fp && (mutt_str_strcmp(mutt_b2s(tmpfile), a->filename) != 0))
460  {
461  /* send case: the file is already there */
462  if (mutt_file_symlink(a->filename, mutt_b2s(tmpfile)) == -1)
463  {
464  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) == MUTT_YES)
465  mutt_buffer_strcpy(tmpfile, a->filename);
466  else
467  goto return_error;
468  }
469  else
470  unlink_tempfile = true;
471  }
472  }
473  else if (!fp) /* send case */
474  mutt_buffer_strcpy(tmpfile, a->filename);
475 
476  if (fp)
477  {
478  /* recv case: we need to save the attachment to a file */
479  FREE(&fname);
480  if (mutt_save_attachment(fp, a, mutt_b2s(tmpfile), MUTT_SAVE_NO_FLAGS, NULL) == -1)
481  goto return_error;
482  mutt_file_chmod(mutt_b2s(tmpfile), S_IRUSR);
483  }
484 
485  use_pipe = mutt_buffer_rfc1524_expand_command(a, mutt_b2s(tmpfile), type, cmd);
486  use_pager = entry->copiousoutput;
487  }
488 
489  if (use_pager)
490  {
491  if (fp && !use_mailcap && a->filename)
492  {
493  /* recv case */
494  mutt_buffer_strcpy(pagerfile, a->filename);
495  mutt_adv_mktemp(pagerfile);
496  }
497  else
498  mutt_buffer_mktemp(pagerfile);
499  }
500 
501  if (use_mailcap)
502  {
503  pid_t pid = 0;
504  int fd_temp = -1, fd_pager = -1;
505 
506  if (!use_pager)
507  mutt_endwin();
508 
509  if (use_pager || use_pipe)
510  {
511  if (use_pager && ((fd_pager = mutt_file_open(mutt_b2s(pagerfile),
512  O_CREAT | O_EXCL | O_WRONLY)) == -1))
513  {
514  mutt_perror("open");
515  goto return_error;
516  }
517  if (use_pipe && ((fd_temp = open(mutt_b2s(tmpfile), 0)) == -1))
518  {
519  if (fd_pager != -1)
520  close(fd_pager);
521  mutt_perror("open");
522  goto return_error;
523  }
524 
525  pid = mutt_create_filter_fd(mutt_b2s(cmd), NULL, NULL, NULL,
526  use_pipe ? fd_temp : -1,
527  use_pager ? fd_pager : -1, -1);
528  if (pid == -1)
529  {
530  if (fd_pager != -1)
531  close(fd_pager);
532 
533  if (fd_temp != -1)
534  close(fd_temp);
535 
536  mutt_error(_("Can't create filter"));
537  goto return_error;
538  }
539 
540  if (use_pager)
541  {
542  if (a->description)
543  {
544  snprintf(desc, sizeof(desc), _("---Command: %-20.20s Description: %s"),
545  mutt_b2s(cmd), a->description);
546  }
547  else
548  {
549  snprintf(desc, sizeof(desc), _("---Command: %-30.30s Attachment: %s"),
550  mutt_b2s(cmd), type);
551  }
552  }
553 
554  if ((mutt_wait_filter(pid) || (entry->needsterminal && C_WaitKey)) && !use_pager)
556 
557  if (fd_temp != -1)
558  close(fd_temp);
559  if (fd_pager != -1)
560  close(fd_pager);
561  }
562  else
563  {
564  /* interactive cmd */
565  int rv = mutt_system(mutt_b2s(cmd));
566  if (rv == -1)
567  mutt_debug(LL_DEBUG1, "Error running \"%s\"", cmd);
568 
569  if ((rv != 0) || (entry->needsterminal && C_WaitKey))
571  }
572  }
573  else
574  {
575  /* Don't use mailcap; the attachment is viewed in the pager */
576 
577  if (mode == MUTT_VA_AS_TEXT)
578  {
579  /* just let me see the raw data */
580  if (fp)
581  {
582  /* Viewing from a received message.
583  *
584  * Don't use mutt_save_attachment() because we want to perform charset
585  * conversion since this will be displayed by the internal pager. */
586  struct State decode_state = { 0 };
587 
588  decode_state.fp_out = mutt_file_fopen(mutt_b2s(pagerfile), "w");
589  if (!decode_state.fp_out)
590  {
591  mutt_debug(LL_DEBUG1, "mutt_file_fopen(%s) errno=%d %s\n",
592  mutt_b2s(pagerfile), errno, strerror(errno));
593  mutt_perror(mutt_b2s(pagerfile));
594  goto return_error;
595  }
596  decode_state.fp_in = fp;
597  decode_state.flags = MUTT_CHARCONV;
598  mutt_decode_attachment(a, &decode_state);
599  if (fclose(decode_state.fp_out) == EOF)
600  mutt_debug(LL_DEBUG1, "fclose(%s) errno=%d %s\n", mutt_b2s(pagerfile),
601  errno, strerror(errno));
602  }
603  else
604  {
605  /* in compose mode, just copy the file. we can't use
606  * mutt_decode_attachment() since it assumes the content-encoding has
607  * already been applied */
608  if (mutt_save_attachment(fp, a, mutt_b2s(pagerfile), MUTT_SAVE_NO_FLAGS, NULL))
609  goto return_error;
610  }
611  }
612  else
613  {
614  /* Use built-in handler */
615  OptViewAttach = true; /* disable the "use 'v' to view this part"
616  * message in case of error */
618  {
619  OptViewAttach = false;
620  goto return_error;
621  }
622  OptViewAttach = false;
623  }
624 
625  if (a->description)
626  mutt_str_strfcpy(desc, a->description, sizeof(desc));
627  else if (a->filename)
628  snprintf(desc, sizeof(desc), _("---Attachment: %s: %s"), a->filename, type);
629  else
630  snprintf(desc, sizeof(desc), _("---Attachment: %s"), type);
631  }
632 
633  /* We only reach this point if there have been no errors */
634 
635  if (use_pager)
636  {
637  struct Pager info = { 0 };
638  info.fp = fp;
639  info.body = a;
640  info.ctx = Context;
641  info.actx = actx;
642  info.email = e;
643 
644  rc = mutt_do_pager(desc, mutt_b2s(pagerfile),
646  &info);
647  mutt_buffer_reset(pagerfile);
648  }
649  else
650  rc = 0;
651 
652 return_error:
653 
654  if (!entry || !entry->xneomuttkeep)
655  {
656  if (fp && mutt_b2s(tmpfile)[0])
657  {
658  /* add temporary file to TempAttachmentsList to be deleted on timeout hook */
660  }
661  else if (unlink_tempfile)
662  {
663  unlink(mutt_b2s(tmpfile));
664  }
665  }
666 
667  if (entry)
668  rfc1524_free_entry(&entry);
669 
670  if (mutt_b2s(pagerfile)[0] != '\0')
671  mutt_file_unlink(mutt_b2s(pagerfile));
672 
673  mutt_buffer_pool_release(&tmpfile);
674  mutt_buffer_pool_release(&pagerfile);
676 
677  return rc;
678 }
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1789
FILE * fp
source stream
Definition: pager.h:70
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:77
#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:48
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:83
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1260
#define mutt_perror(...)
Definition: logging.h:84
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
bool rfc1524_mailcap_lookup(struct Body *a, char *type, struct Rfc1524MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: rfc1524.c:468
#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:54
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:191
String manipulation buffer.
Definition: buffer.h:33
bool needsterminal
endwin() and system
Definition: rfc1524.h:47
#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:43
bool xneomuttkeep
do not remove the file on command exit
Definition: rfc1524.h:49
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:806
An email being displayed.
Definition: pager.h:65
View using default method.
Definition: mutt_attach.h:41
#define SEC_ENCRYPT
Email is encrypted.
Definition: ncrypt.h:120
FILE * fp_in
File to read from.
Definition: state.h:46
#define MUTT_PAGER_ATTACHMENT
Attachments may exist.
Definition: pager.h:55
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:143
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:332
int mutt_file_chmod(const char *path, mode_t mode)
Set permissions of a file.
Definition: file.c:1023
void mutt_add_temp_attachment(const char *filename)
Add file to list of temporary attachments.
Definition: mutt_attach.c:1198
char * nametemplate
Definition: rfc1524.h:45
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:608
#define mutt_b2s(buf)
Definition: buffer.h:42
int mutt_buffer_rfc1524_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: rfc1524.c:155
struct Context * ctx
current mailbox
Definition: pager.h:67
void rfc1524_free_entry(struct Rfc1524MailcapEntry **entry)
Deallocate an struct Rfc1524MailcapEntry.
Definition: rfc1524.c:440
void mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:322
WHERE struct Context * Context
Definition: globals.h:41
WHERE bool C_WaitKey
Config: Prompt to press a key after running external commands.
Definition: globals.h:258
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:499
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:937
struct AttachCtx * actx
attachment information
Definition: pager.h:71
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:64
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:753
int mutt_rfc1524_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: rfc1524.c:533
A mailcap entry.
Definition: rfc1524.h:37
char * description
content-description
Definition: body.h:40
SecurityFlags security
bit 0-8: flags, bit 9,10: application.
Definition: email.h:39
Force viewing using mailcap entry.
Definition: mutt_attach.h:42
unsigned int type
content-type primary type
Definition: body.h:72
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:532
#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:515
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:570
No flags set.
Definition: rfc1524.h:57
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#define mutt_error(...)
Definition: logging.h:83
bool mutt_needs_mailcap(struct Body *m)
Does this type need a mailcap entry do display.
Definition: muttlib.c:409
void mutt_adv_mktemp(struct Buffer *buf)
Create a temporary file.
Definition: muttlib.c:89
struct Rfc1524MailcapEntry * rfc1524_new_entry(void)
Allocate memory for a new rfc1524 entry.
Definition: rfc1524.c:431
#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:52
#define mutt_debug(LEVEL,...)
Definition: logging.h:80
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:290
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:578
int mutt_wait_filter(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:227
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: buffer.c:409
struct Email * email
header information for message/rfc822
Definition: body.h:62
#define WithCrypto
Definition: ncrypt.h:155
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:618
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:50
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: buffer.c:398
#define MUTT_PAGER_NO_FLAGS
No flags are set.
Definition: pager.h:43
bool copiousoutput
needs pager, basically
Definition: rfc1524.h:48

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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 689 of file mutt_attach.c.

690 {
691  pid_t pid;
692  int out = -1;
693  int rc = 0;
694 
695  if (outfile && *outfile)
696  {
697  out = mutt_file_open(outfile, O_CREAT | O_EXCL | O_WRONLY);
698  if (out < 0)
699  {
700  mutt_perror("open");
701  return 0;
702  }
703  }
704 
705  mutt_endwin();
706 
707  if (fp)
708  {
709  /* recv case */
710 
711  struct State s = { 0 };
712 
713  /* perform charset conversion on text attachments when piping */
714  s.flags = MUTT_CHARCONV;
715 
716  if (outfile && *outfile)
717  pid = mutt_create_filter_fd(path, &s.fp_out, NULL, NULL, -1, out, -1);
718  else
719  pid = mutt_create_filter(path, &s.fp_out, NULL, NULL);
720 
721  if (pid < 0)
722  {
723  mutt_perror(_("Can't create filter"));
724  goto bail;
725  }
726 
727  s.fp_in = fp;
728  mutt_decode_attachment(b, &s);
730  }
731  else
732  {
733  /* send case */
734  FILE *fp_in = fopen(b->filename, "r");
735  if (!fp_in)
736  {
737  mutt_perror("fopen");
738  if (outfile && *outfile)
739  {
740  close(out);
741  unlink(outfile);
742  }
743  return 0;
744  }
745 
746  FILE *fp_out = NULL;
747  if (outfile && *outfile)
748  pid = mutt_create_filter_fd(path, &fp_out, NULL, NULL, -1, out, -1);
749  else
750  pid = mutt_create_filter(path, &fp_out, NULL, NULL);
751 
752  if (pid < 0)
753  {
754  mutt_perror(_("Can't create filter"));
755  mutt_file_fclose(&fp_in);
756  goto bail;
757  }
758 
759  mutt_file_copy_stream(fp_in, fp_out);
760  mutt_file_fclose(&fp_out);
761  mutt_file_fclose(&fp_in);
762  }
763 
764  rc = 1;
765 
766 bail:
767 
768  if (outfile && *outfile)
769  close(out);
770 
771  /* check for error exit from child process */
772  if (mutt_wait_filter(pid) != 0)
773  rc = 0;
774 
775  if ((rc == 0) || C_WaitKey)
777  return rc;
778 }
pid_t mutt_create_filter(const char *s, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:216
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1789
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:48
#define mutt_perror(...)
Definition: logging.h:84
#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:149
WHERE bool C_WaitKey
Config: Prompt to press a key after running external commands.
Definition: globals.h:258
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:499
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:64
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:532
int mutt_file_open(const char *path, int flags)
Open a file.
Definition: file.c:515
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:264
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:227

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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 786 of file mutt_attach.c.

787 {
788  if (opt == MUTT_SAVE_APPEND)
789  return fopen(path, "a");
790  if (opt == MUTT_SAVE_OVERWRITE)
791  return fopen(path, "w");
792 
793  return mutt_file_fopen(path, "w");
794 }
Overwrite existing file.
Definition: mutt_attach.h:56
Append to existing file.
Definition: mutt_attach.h:55
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:578

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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 806 of file mutt_attach.c.

808 {
809  if (!m)
810  return -1;
811 
812  if (fp)
813  {
814  /* recv mode */
815 
816  if (e && m->email && (m->encoding != ENC_BASE64) &&
818  {
819  /* message type attachments are written to mail folders. */
820 
821  char buf[8192];
822  struct Message *msg = NULL;
823  CopyHeaderFlags chflags = CH_NO_FLAGS;
824  int rc = -1;
825 
826  struct Email *en = m->email;
827  en->msgno = e->msgno; /* required for MH/maildir */
828  en->read = true;
829 
830  if (fseeko(fp, m->offset, SEEK_SET) < 0)
831  return -1;
832  if (!fgets(buf, sizeof(buf), fp))
833  return -1;
834  struct Mailbox *m_att = mx_path_resolve(path);
835  struct Context *ctx = mx_mbox_open(m_att, MUTT_APPEND | MUTT_QUIET);
836  if (!ctx)
837  {
838  mailbox_free(&m_att);
839  return -1;
840  }
841  msg = mx_msg_open_new(ctx->mailbox, en,
842  is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
843  if (!msg)
844  {
845  mx_mbox_close(&ctx);
846  return -1;
847  }
848  if ((ctx->mailbox->magic == MUTT_MBOX) || (ctx->mailbox->magic == MUTT_MMDF))
849  chflags = CH_FROM | CH_UPDATE_LEN;
850  chflags |= ((ctx->mailbox->magic == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
851  if ((mutt_copy_message_fp(msg->fp, fp, en, MUTT_CM_NO_FLAGS, chflags) == 0) &&
852  (mx_msg_commit(ctx->mailbox, msg) == 0))
853  {
854  rc = 0;
855  }
856  else
857  {
858  rc = -1;
859  }
860 
861  mx_msg_close(ctx->mailbox, &msg);
862  mx_mbox_close(&ctx);
863  return rc;
864  }
865  else
866  {
867  /* In recv mode, extract from folder and decode */
868 
869  struct State s = { 0 };
870 
871  s.fp_out = save_attachment_open(path, opt);
872  if (!s.fp_out)
873  {
874  mutt_perror("fopen");
875  return -1;
876  }
877  fseeko((s.fp_in = fp), m->offset, SEEK_SET);
878  mutt_decode_attachment(m, &s);
879 
880  if (mutt_file_fsync_close(&s.fp_out) != 0)
881  {
882  mutt_perror("fclose");
883  return -1;
884  }
885  }
886  }
887  else
888  {
889  if (!m->filename)
890  return -1;
891 
892  /* In send mode, just copy file */
893 
894  FILE *fp_old = fopen(m->filename, "r");
895  if (!fp_old)
896  {
897  mutt_perror("fopen");
898  return -1;
899  }
900 
901  FILE *fp_new = save_attachment_open(path, opt);
902  if (!fp_new)
903  {
904  mutt_perror("fopen");
905  mutt_file_fclose(&fp_old);
906  return -1;
907  }
908 
909  if (mutt_file_copy_stream(fp_old, fp_new) == -1)
910  {
911  mutt_error(_("Write fault"));
912  mutt_file_fclose(&fp_old);
913  mutt_file_fclose(&fp_new);
914  return -1;
915  }
916  mutt_file_fclose(&fp_old);
917  if (mutt_file_fsync_close(&fp_new) != 0)
918  {
919  mutt_error(_("Write fault"));
920  return -1;
921  }
922  }
923 
924  return 0;
925 }
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mx.h:50
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:61
The "current" mailbox.
Definition: context.h:38
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1789
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:48
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1260
The envelope/body of an email.
Definition: email.h:37
#define mutt_perror(...)
Definition: logging.h:84
int mx_mbox_close(struct Context **ptr)
Save changes and close mailbox.
Definition: mx.c:546
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:165
&#39;Maildir&#39; Mailbox type
Definition: magic.h:40
&#39;mmdf&#39; Mailbox type
Definition: magic.h:38
int mutt_copy_message_fp(FILE *fp_out, FILE *fp_in, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags)
make a copy of a message from a FILE pointer
Definition: copy.c:592
LOFF_T offset
offset where the actual data begins
Definition: body.h:46
#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:247
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:1077
bool read
Definition: email.h:51
struct Mailbox * mailbox
Definition: context.h:52
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:105
enum MailboxType magic
mailbox type
Definition: mailbox.h:105
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
unsigned int encoding
content-transfer-encoding
Definition: body.h:73
struct Message * mx_msg_open_new(struct Mailbox *m, struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:946
Base-64 encoded text.
Definition: mime.h:52
char * subtype
content-type subtype
Definition: body.h:37
&#39;mbox&#39; Mailbox type
Definition: magic.h:37
A local copy of an email.
Definition: mx.h:79
A mailbox.
Definition: mailbox.h:83
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:50
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:61
#define MUTT_QUIET
Do not print any messages.
Definition: mx.h:52
unsigned int type
content-type primary type
Definition: body.h:72
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:264
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:49
#define mutt_error(...)
Definition: logging.h:83
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1056
Quoted-printable text.
Definition: mime.h:51
FILE * fp
pointer to the message data
Definition: mx.h:81
struct Mailbox * mx_path_resolve(const char *path)
XXX.
Definition: mx.c:1531
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:786
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
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:62
struct Email * email
header information for message/rfc822
Definition: body.h:62
int msgno
number displayed to the user
Definition: email.h:89

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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 937 of file mutt_attach.c.

939 {
940  struct State s = { 0 };
941  unsigned int saved_encoding = 0;
942  struct Body *saved_parts = NULL;
943  struct Email *saved_hdr = NULL;
944  int rc = 0;
945 
946  s.flags = displaying;
947 
948  if (opt == MUTT_SAVE_APPEND)
949  s.fp_out = fopen(path, "a");
950  else if (opt == MUTT_SAVE_OVERWRITE)
951  s.fp_out = fopen(path, "w");
952  else
953  s.fp_out = mutt_file_fopen(path, "w");
954 
955  if (!s.fp_out)
956  {
957  mutt_perror("fopen");
958  return -1;
959  }
960 
961  if (!fp)
962  {
963  /* When called from the compose menu, the attachment isn't parsed,
964  * so we need to do it here. */
965  struct stat st;
966 
967  if (stat(m->filename, &st) == -1)
968  {
969  mutt_perror("stat");
971  return -1;
972  }
973 
974  s.fp_in = fopen(m->filename, "r");
975  if (!s.fp_in)
976  {
977  mutt_perror("fopen");
978  return -1;
979  }
980 
981  saved_encoding = m->encoding;
982  if (!is_multipart(m))
983  m->encoding = ENC_8BIT;
984 
985  m->length = st.st_size;
986  m->offset = 0;
987  saved_parts = m->parts;
988  saved_hdr = m->email;
989  mutt_parse_part(s.fp_in, m);
990 
991  if (m->noconv || is_multipart(m))
992  s.flags |= MUTT_CHARCONV;
993  }
994  else
995  {
996  s.fp_in = fp;
997  s.flags |= MUTT_CHARCONV;
998  }
999 
1000  mutt_body_handler(m, &s);
1001 
1002  if (mutt_file_fsync_close(&s.fp_out) != 0)
1003  {
1004  mutt_perror("fclose");
1005  rc = -1;
1006  }
1007  if (!fp)
1008  {
1009  m->length = 0;
1010  m->encoding = saved_encoding;
1011  if (saved_parts)
1012  {
1013  mutt_email_free(&m->email);
1014  m->parts = saved_parts;
1015  m->email = saved_hdr;
1016  }
1017  mutt_file_fclose(&s.fp_in);
1018  }
1019 
1020  return rc;
1021 }
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:48
The envelope/body of an email.
Definition: email.h:37
#define mutt_perror(...)
Definition: logging.h:84
#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:165
bool noconv
don&#39;t do character set conversion
Definition: body.h:82
Overwrite existing file.
Definition: mutt_attach.h:56
LOFF_T offset
offset where the actual data begins
Definition: body.h:46
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:149
unsigned int encoding
content-transfer-encoding
Definition: body.h:73
LOFF_T length
length (in bytes) of attachment
Definition: body.h:47
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:61
void mutt_email_free(struct Email **e)
Free an Email.
Definition: email.c:41
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1275
char * path
Definition: email.h:94
Append to existing file.
Definition: mutt_attach.h:55
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:1544
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:578
struct Email * email
header information for message/rfc822
Definition: body.h:62

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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 1036 of file mutt_attach.c.

1037 {
1038  char type[256];
1039  pid_t pid;
1040  FILE *fp_in = NULL, *fp_out = NULL;
1041  bool unlink_newfile = false;
1042  struct Buffer *newfile = mutt_buffer_pool_get();
1043  struct Buffer *cmd = mutt_buffer_pool_get();
1044 
1045  int rc = 0;
1046 
1047  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
1048 
1049  if (rfc1524_mailcap_lookup(a, type, NULL, MUTT_MC_PRINT))
1050  {
1051  int piped = false;
1052 
1053  mutt_debug(LL_DEBUG2, "Using mailcap\n");
1054 
1055  struct Rfc1524MailcapEntry *entry = rfc1524_new_entry();
1056  rfc1524_mailcap_lookup(a, type, entry, MUTT_MC_PRINT);
1057  if (mutt_rfc1524_expand_filename(entry->nametemplate, a->filename, newfile))
1058  {
1059  if (!fp)
1060  {
1061  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
1062  {
1063  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
1064  {
1065  rfc1524_free_entry(&entry);
1066  goto out;
1067  }
1068  mutt_buffer_strcpy(newfile, a->filename);
1069  }
1070  else
1071  unlink_newfile = true;
1072  }
1073  }
1074 
1075  /* in recv mode, save file to newfile first */
1076  if (fp && (mutt_save_attachment(fp, a, mutt_b2s(newfile), MUTT_SAVE_NO_FLAGS, NULL) != 0))
1077  return 0;
1078 
1079  mutt_buffer_strcpy(cmd, entry->printcommand);
1080  piped = mutt_buffer_rfc1524_expand_command(a, mutt_b2s(newfile), type, cmd);
1081 
1082  mutt_endwin();
1083 
1084  /* interactive program */
1085  if (piped)
1086  {
1087  fp_in = fopen(mutt_b2s(newfile), "r");
1088  if (!fp_in)
1089  {
1090  mutt_perror("fopen");
1091  rfc1524_free_entry(&entry);
1092  goto out;
1093  }
1094 
1095  pid = mutt_create_filter(mutt_b2s(cmd), &fp_out, NULL, NULL);
1096  if (pid < 0)
1097  {
1098  mutt_perror(_("Can't create filter"));
1099  rfc1524_free_entry(&entry);
1100  mutt_file_fclose(&fp_in);
1101  goto out;
1102  }
1103  mutt_file_copy_stream(fp_in, fp_out);
1104  mutt_file_fclose(&fp_out);
1105  mutt_file_fclose(&fp_in);
1106  if (mutt_wait_filter(pid) || C_WaitKey)
1108  }
1109  else
1110  {
1111  int rc2 = mutt_system(mutt_b2s(cmd));
1112  if (rc2 == -1)
1113  mutt_debug(LL_DEBUG1, "Error running \"%s\"", cmd);
1114 
1115  if ((rc2 != 0) || C_WaitKey)
1117  }
1118 
1119  if (fp)
1120  mutt_file_unlink(mutt_b2s(newfile));
1121  else if (unlink_newfile)
1122  unlink(mutt_b2s(newfile));
1123 
1124  rfc1524_free_entry(&entry);
1125  rc = 1;
1126  goto out;
1127  }
1128 
1129  if ((mutt_str_strcasecmp("text/plain", type) == 0) ||
1130  (mutt_str_strcasecmp("application/postscript", type) == 0))
1131  {
1132  rc = (mutt_pipe_attachment(fp, a, NONULL(C_PrintCommand), NULL));
1133  goto out;
1134  }
1135  else if (mutt_can_decode(a))
1136  {
1137  /* decode and print */
1138 
1139  fp_in = NULL;
1140  fp_out = NULL;
1141 
1142  mutt_buffer_mktemp(newfile);
1143  if (mutt_decode_save_attachment(fp, a, mutt_b2s(newfile), MUTT_PRINTING, 0) == 0)
1144  {
1145  mutt_debug(LL_DEBUG2, "successfully decoded %s type attachment to %s\n",
1146  type, mutt_b2s(newfile));
1147 
1148  fp_in = fopen(mutt_b2s(newfile), "r");
1149  if (!fp_in)
1150  {
1151  mutt_perror("fopen");
1152  goto bail0;
1153  }
1154 
1155  mutt_debug(LL_DEBUG2, "successfully opened %s read-only\n", mutt_b2s(newfile));
1156 
1157  mutt_endwin();
1158  pid = mutt_create_filter(NONULL(C_PrintCommand), &fp_out, NULL, NULL);
1159  if (pid < 0)
1160  {
1161  mutt_perror(_("Can't create filter"));
1162  goto bail0;
1163  }
1164 
1165  mutt_debug(LL_DEBUG2, "Filter created\n");
1166 
1167  mutt_file_copy_stream(fp_in, fp_out);
1168 
1169  mutt_file_fclose(&fp_out);
1170  mutt_file_fclose(&fp_in);
1171 
1172  if ((mutt_wait_filter(pid) != 0) || C_WaitKey)
1174  rc = 1;
1175  }
1176  bail0:
1177  mutt_file_fclose(&fp_in);
1178  mutt_file_fclose(&fp_out);
1179  mutt_file_unlink(mutt_b2s(newfile));
1180  }
1181  else
1182  {
1183  mutt_error(_("I don't know how to print that"));
1184  rc = 0;
1185  }
1186 
1187 out:
1188  mutt_buffer_pool_release(&newfile);
1190 
1191  return rc;
1192 }
pid_t mutt_create_filter(const char *s, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:216
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:77
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:48
#define NONULL(x)
Definition: string2.h:36
#define mutt_perror(...)
Definition: logging.h:84
bool rfc1524_mailcap_lookup(struct Body *a, char *type, struct Rfc1524MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: rfc1524.c:468
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
No flags set.
Definition: mutt_attach.h:54
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:191
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:806
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:332
Log at debug level 2.
Definition: logging.h:57
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
Mailcap print field.
Definition: rfc1524.h:60
char * nametemplate
Definition: rfc1524.h:45
char * subtype
content-type subtype
Definition: body.h:37
#define mutt_b2s(buf)
Definition: buffer.h:42
int mutt_buffer_rfc1524_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: rfc1524.c:155
void rfc1524_free_entry(struct Rfc1524MailcapEntry **entry)
Deallocate an struct Rfc1524MailcapEntry.
Definition: rfc1524.c:440
void mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:322
WHERE bool C_WaitKey
Config: Prompt to press a key after running external commands.
Definition: globals.h:258
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:499
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:937
bool mutt_can_decode(struct Body *a)
Will decoding the attachment produce any output.
Definition: handler.c:1748
int mutt_rfc1524_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: rfc1524.c:533
A mailcap entry.
Definition: rfc1524.h:37
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:532
#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:264
#define mutt_error(...)
Definition: logging.h:83
WHERE char * C_PrintCommand
Config: External command to print a message.
Definition: globals.h:134
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:631
struct Rfc1524MailcapEntry * rfc1524_new_entry(void)
Allocate memory for a new rfc1524 entry.
Definition: rfc1524.c:431
char * printcommand
Definition: rfc1524.h:44
#define mutt_debug(LEVEL,...)
Definition: logging.h:80
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:290
int mutt_wait_filter(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:227
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: buffer.c:409
int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, char *outfile)
Pipe an attachment to a command.
Definition: mutt_attach.c:689
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:50
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: buffer.c:398

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void mutt_add_temp_attachment ( const char *  filename)

Add file to list of temporary attachments.

Parameters
filenamefilename with full path

Definition at line 1198 of file mutt_attach.c.

1199 {
1200  mutt_list_insert_tail(&TempAttachmentsList, mutt_str_strdup(filename));
1201 }
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:61
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:

void mutt_unlink_temp_attachments ( void  )

Delete all temporary attachments.

Definition at line 1206 of file mutt_attach.c.

1207 {
1208  struct ListNode *np = NULL;
1209 
1210  STAILQ_FOREACH(np, &TempAttachmentsList, entries)
1211  {
1212  mutt_file_chmod_add(np->data, S_IWUSR);
1213  mutt_file_unlink(np->data);
1214  }
1215 
1216  mutt_list_free(&TempAttachmentsList);
1217 }
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:191
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:117
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
char * data
Definition: list.h:35
int mutt_file_chmod_add(const char *path, mode_t mode)
Add permissions to a file.
Definition: file.c:1044
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: