NeoMutt  2018-07-16 +2388-bcedc8
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 "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 65 of file mutt_attach.c.

66 {
67  char type[256];
68  struct stat st;
69 
70  if (a->unlink)
71  return 0;
72 
73  struct Buffer *tmpfile = mutt_buffer_pool_get();
74  struct Rfc1524MailcapEntry *entry = rfc1524_new_entry();
75  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
78 
79  rfc1524_free_entry(&entry);
80 
81  if (stat(a->filename, &st) == -1)
82  {
83  mutt_buffer_pool_release(&tmpfile);
84  return -1;
85  }
86 
87  FILE *fp_in = NULL, *fp_out = NULL;
88  if ((fp_in = fopen(a->filename, "r")) &&
89  (fp_out = mutt_file_fopen(mutt_b2s(tmpfile), "w")))
90  {
91  mutt_file_copy_stream(fp_in, fp_out);
92  mutt_str_replace(&a->filename, mutt_b2s(tmpfile));
93  a->unlink = true;
94 
95  if (a->stamp >= st.st_mtime)
97  }
98  else
99  mutt_perror(fp_in ? mutt_b2s(tmpfile) : a->filename);
100 
101  mutt_file_fclose(&fp_in);
102  mutt_file_fclose(&fp_out);
103 
104  mutt_buffer_pool_release(&tmpfile);
105 
106  return a->unlink ? 0 : -1;
107 }
void 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:518
void mutt_stamp_attachment(struct Body *a)
Timestamp an Attachment.
Definition: sendlib.c:1418
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:75
#define mutt_perror(...)
Definition: logging.h:85
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:465
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:86
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:41
void rfc1524_free_entry(struct Rfc1524MailcapEntry **entry)
Deallocate an struct Rfc1524MailcapEntry.
Definition: rfc1524.c:437
A mailcap entry.
Definition: rfc1524.h:37
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
#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:267
No flags set.
Definition: rfc1524.h:57
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
struct Rfc1524MailcapEntry * rfc1524_new_entry(void)
Allocate memory for a new rfc1524 entry.
Definition: rfc1524.c:428
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:584

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

116 {
117  char type[256];
118  struct Rfc1524MailcapEntry *entry = rfc1524_new_entry();
119  bool unlink_newfile = false;
120  int rc = 0;
121  struct Buffer *cmd = mutt_buffer_pool_get();
122  struct Buffer *newfile = mutt_buffer_pool_get();
123  struct Buffer *tmpfile = mutt_buffer_pool_get();
124 
125  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
126  if (rfc1524_mailcap_lookup(a, type, entry, MUTT_MC_COMPOSE))
127  {
128  if (entry->composecommand || entry->composetypecommand)
129  {
130  if (entry->composetypecommand)
132  else
133  mutt_buffer_strcpy(cmd, entry->composecommand);
134 
136  mutt_debug(LL_DEBUG1, "oldfile: %s\t newfile: %s\n", a->filename, mutt_b2s(newfile));
137  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
138  {
139  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
140  goto bailout;
141  mutt_buffer_strcpy(newfile, a->filename);
142  }
143  else
144  unlink_newfile = true;
145 
146  if (mutt_rfc1524_expand_command(a, mutt_b2s(newfile), type, cmd))
147  {
148  /* For now, editing requires a file, no piping */
149  mutt_error(_("Mailcap compose entry requires %%s"));
150  }
151  else
152  {
153  int r;
154 
155  mutt_endwin();
156  r = mutt_system(mutt_b2s(cmd));
157  if (r == -1)
158  mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
159 
160  if ((r != -1) && entry->composetypecommand)
161  {
162  struct Body *b = NULL;
163 
164  FILE *fp = mutt_file_fopen(a->filename, "r");
165  if (!fp)
166  {
167  mutt_perror(_("Failure to open file to parse headers"));
168  goto bailout;
169  }
170 
171  b = mutt_read_mime_header(fp, 0);
172  if (b)
173  {
174  if (!TAILQ_EMPTY(&b->parameter))
175  {
177  a->parameter = b->parameter;
178  TAILQ_INIT(&b->parameter);
179  }
180  if (b->description)
181  {
182  FREE(&a->description);
183  a->description = b->description;
184  b->description = NULL;
185  }
186  if (b->form_name)
187  {
188  FREE(&a->form_name);
189  a->form_name = b->form_name;
190  b->form_name = NULL;
191  }
192 
193  /* Remove headers by copying out data to another file, then
194  * copying the file back */
195  fseeko(fp, b->offset, SEEK_SET);
196  mutt_body_free(&b);
197  mutt_buffer_mktemp(tmpfile);
198  FILE *fp_tmp = mutt_file_fopen(mutt_b2s(tmpfile), "w");
199  if (!fp_tmp)
200  {
201  mutt_perror(_("Failure to open file to strip headers"));
202  mutt_file_fclose(&fp);
203  goto bailout;
204  }
205  mutt_file_copy_stream(fp, fp_tmp);
206  mutt_file_fclose(&fp);
207  mutt_file_fclose(&fp_tmp);
209  if (mutt_file_rename(mutt_b2s(tmpfile), a->filename) != 0)
210  {
211  mutt_perror(_("Failure to rename file"));
212  goto bailout;
213  }
214  }
215  }
216  }
217  }
218  }
219  else
220  {
221  mutt_message(_("No mailcap compose entry for %s, creating empty file"), type);
222  rc = 1;
223  goto bailout;
224  }
225 
226  rc = 1;
227 
228 bailout:
229 
230  if (unlink_newfile)
231  unlink(mutt_b2s(newfile));
232 
234  mutt_buffer_pool_release(&newfile);
235  mutt_buffer_pool_release(&tmpfile);
236 
237  rfc1524_free_entry(&entry);
238  return rc;
239 }
void 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:518
int mutt_rfc1524_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: rfc1524.c:70
#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:75
#define mutt_perror(...)
Definition: logging.h:85
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:465
#define mutt_message(...)
Definition: logging.h:83
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition: file.c:1333
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:86
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:44
#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
void mutt_param_free(struct ParameterList *pl)
Free a ParameterList.
Definition: parameter.c:61
char * nametemplate
Definition: rfc1524.h:45
char * subtype
content-type subtype
Definition: body.h:37
#define mutt_b2s(buf)
Definition: buffer.h:41
void rfc1524_free_entry(struct Rfc1524MailcapEntry **entry)
Deallocate an struct Rfc1524MailcapEntry.
Definition: rfc1524.c:437
void mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:314
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:499
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:267
#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
struct Rfc1524MailcapEntry * rfc1524_new_entry(void)
Allocate memory for a new rfc1524 entry.
Definition: rfc1524.c:428
#define FREE(x)
Definition: memory.h:40
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
#define TAILQ_EMPTY(head)
Definition: queue.h:715
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:293
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:584
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:1286

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

255 {
256  char type[256];
257  struct Rfc1524MailcapEntry *entry = rfc1524_new_entry();
258  bool unlink_newfile = false;
259  int rc = 0;
260  struct Buffer *cmd = mutt_buffer_pool_get();
261  struct Buffer *newfile = mutt_buffer_pool_get();
262 
263  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
264  if (rfc1524_mailcap_lookup(a, type, entry, MUTT_MC_EDIT))
265  {
266  if (entry->editcommand)
267  {
268  mutt_buffer_strcpy(cmd, entry->editcommand);
270  mutt_debug(LL_DEBUG1, "oldfile: %s\t newfile: %s\n", a->filename, mutt_b2s(newfile));
271  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
272  {
273  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
274  goto bailout;
275  mutt_buffer_strcpy(newfile, a->filename);
276  }
277  else
278  unlink_newfile = true;
279 
280  if (mutt_rfc1524_expand_command(a, mutt_b2s(newfile), type, cmd))
281  {
282  /* For now, editing requires a file, no piping */
283  mutt_error(_("Mailcap Edit entry requires %%s"));
284  goto bailout;
285  }
286  else
287  {
288  mutt_endwin();
289  if (mutt_system(mutt_b2s(cmd)) == -1)
290  {
291  mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
292  goto bailout;
293  }
294  }
295  }
296  }
297  else if (a->type == TYPE_TEXT)
298  {
299  /* On text, default to editor */
301  }
302  else
303  {
304  mutt_error(_("No mailcap edit entry for %s"), type);
305  rc = 0;
306  goto bailout;
307  }
308 
309  rc = 1;
310 
311 bailout:
312 
313  if (unlink_newfile)
314  unlink(mutt_b2s(newfile));
315 
317  mutt_buffer_pool_release(&newfile);
318 
319  rfc1524_free_entry(&entry);
320  return rc;
321 }
void 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:518
int mutt_rfc1524_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: rfc1524.c:70
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:75
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:465
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:86
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:41
void rfc1524_free_entry(struct Rfc1524MailcapEntry **entry)
Deallocate an struct Rfc1524MailcapEntry.
Definition: rfc1524.c:437
void mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:314
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:499
Type: &#39;text/*&#39;.
Definition: mime.h:38
A mailcap entry.
Definition: rfc1524.h:37
unsigned int type
content-type primary type
Definition: body.h:65
#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:113
char * editcommand
Definition: rfc1524.h:43
struct Rfc1524MailcapEntry * rfc1524_new_entry(void)
Allocate memory for a new rfc1524 entry.
Definition: rfc1524.c:428
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:293
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:51

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

330 {
331  struct ListNode *np = NULL;
332  STAILQ_FOREACH(np, &MimeLookupList, entries)
333  {
334  const int i = mutt_str_strlen(np->data) - 1;
335  if (((i > 0) && (np->data[i - 1] == '/') && (np->data[i] == '*') &&
336  (mutt_str_strncasecmp(type, np->data, i) == 0)) ||
337  (mutt_str_strcasecmp(type, np->data) == 0))
338  {
339  struct Body tmp = { 0 };
340  enum ContentType n;
341  if ((n = mutt_lookup_mime_type(&tmp, b->filename)) != TYPE_OTHER ||
342  (n = mutt_lookup_mime_type(&tmp, b->description)) != TYPE_OTHER)
343  {
344  snprintf(type, len, "%s/%s",
345  (n == TYPE_AUDIO) ?
346  "audio" :
347  (n == TYPE_APPLICATION) ?
348  "application" :
349  (n == TYPE_IMAGE) ?
350  "image" :
351  (n == TYPE_MESSAGE) ?
352  "message" :
353  (n == TYPE_MODEL) ?
354  "model" :
355  (n == TYPE_MULTIPART) ?
356  "multipart" :
357  (n == TYPE_TEXT) ? "text" : (n == TYPE_VIDEO) ? "video" : "other",
358  tmp.subtype);
359  mutt_debug(LL_DEBUG1, "\"%s\" -> %s\n", b->filename, type);
360  }
361  if (tmp.subtype)
362  FREE(&tmp.subtype);
363  if (tmp.xtype)
364  FREE(&tmp.xtype);
365  }
366  }
367 }
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
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:1101
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:

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 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 Rfc1524MailcapEntry *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  if (use_mailcap)
415  {
416  entry = rfc1524_new_entry();
417  if (!rfc1524_mailcap_lookup(a, type, entry, MUTT_MC_NO_FLAGS))
418  {
419  if (mode == MUTT_VA_REGULAR)
420  {
421  /* fallback to view as text */
422  rfc1524_free_entry(&entry);
423  mutt_error(_("No matching mailcap entry found. Viewing as text."));
424  mode = MUTT_VA_AS_TEXT;
425  use_mailcap = false;
426  }
427  else
428  goto return_error;
429  }
430  }
431 
432  if (use_mailcap)
433  {
434  if (!entry->command)
435  {
436  mutt_error(_("MIME type not defined. Can't view attachment."));
437  goto return_error;
438  }
439  mutt_buffer_strcpy(cmd, entry->command);
440 
441  if (fp)
442  {
443  fname = mutt_str_strdup(a->filename);
444  mutt_file_sanitize_filename(fname, true);
445  }
446  else
447  fname = a->filename;
448 
449  mutt_rfc1524_expand_filename(entry->nametemplate, fname, tmpfile);
450  /* send case: the file is already there; symlink to it */
451  if (!fp)
452  {
453  if (mutt_file_symlink(a->filename, mutt_b2s(tmpfile)) == -1)
454  {
455  if (mutt_yesorno(_("Can't match nametemplate, continue?"), MUTT_YES) != MUTT_YES)
456  goto return_error;
457  mutt_buffer_strcpy(tmpfile, a->filename);
458  }
459  else
460  unlink_tempfile = true;
461  }
462  /* recv case: we need to save the attachment to a file */
463  else
464  {
465  FREE(&fname);
466  if (mutt_save_attachment(fp, a, mutt_b2s(tmpfile), MUTT_SAVE_NO_FLAGS, NULL) == -1)
467  goto return_error;
468  mutt_file_chmod(mutt_b2s(tmpfile), S_IRUSR);
469  }
470 
471  use_pipe = mutt_rfc1524_expand_command(a, mutt_b2s(tmpfile), type, cmd);
472  use_pager = entry->copiousoutput;
473  }
474 
475  if (use_pager)
476  {
477  if (fp && !use_mailcap && a->filename)
478  {
479  /* recv case */
480  mutt_buffer_strcpy(pagerfile, a->filename);
481  mutt_adv_mktemp(pagerfile);
482  }
483  else
484  mutt_buffer_mktemp(pagerfile);
485  }
486 
487  if (use_mailcap)
488  {
489  pid_t pid = 0;
490  int fd_temp = -1, fd_pager = -1;
491 
492  if (!use_pager)
493  mutt_endwin();
494 
495  if (use_pager || use_pipe)
496  {
497  if (use_pager && ((fd_pager = mutt_file_open(mutt_b2s(pagerfile),
498  O_CREAT | O_EXCL | O_WRONLY)) == -1))
499  {
500  mutt_perror("open");
501  goto return_error;
502  }
503  if (use_pipe && ((fd_temp = open(mutt_b2s(tmpfile), 0)) == -1))
504  {
505  if (fd_pager != -1)
506  close(fd_pager);
507  mutt_perror("open");
508  goto return_error;
509  }
510 
511  pid = mutt_create_filter_fd(mutt_b2s(cmd), NULL, NULL, NULL,
512  use_pipe ? fd_temp : -1,
513  use_pager ? fd_pager : -1, -1);
514  if (pid == -1)
515  {
516  if (fd_pager != -1)
517  close(fd_pager);
518 
519  if (fd_temp != -1)
520  close(fd_temp);
521 
522  mutt_error(_("Can't create filter"));
523  goto return_error;
524  }
525 
526  if (use_pager)
527  {
528  if (a->description)
529  {
530  snprintf(desc, sizeof(desc), _("---Command: %-20.20s Description: %s"),
531  mutt_b2s(cmd), a->description);
532  }
533  else
534  {
535  snprintf(desc, sizeof(desc), _("---Command: %-30.30s Attachment: %s"),
536  mutt_b2s(cmd), type);
537  }
538  }
539 
540  if ((mutt_wait_filter(pid) || (entry->needsterminal && C_WaitKey)) && !use_pager)
542 
543  if (fd_temp != -1)
544  close(fd_temp);
545  if (fd_pager != -1)
546  close(fd_pager);
547  }
548  else
549  {
550  /* interactive cmd */
551  int rv = mutt_system(mutt_b2s(cmd));
552  if (rv == -1)
553  mutt_debug(LL_DEBUG1, "Error running \"%s\"", cmd->data);
554 
555  if ((rv != 0) || (entry->needsterminal && C_WaitKey))
557  }
558  }
559  else
560  {
561  /* Don't use mailcap; the attachment is viewed in the pager */
562 
563  if (mode == MUTT_VA_AS_TEXT)
564  {
565  /* just let me see the raw data */
566  if (fp)
567  {
568  /* Viewing from a received message.
569  *
570  * Don't use mutt_save_attachment() because we want to perform charset
571  * conversion since this will be displayed by the internal pager. */
572  struct State decode_state = { 0 };
573 
574  decode_state.fp_out = mutt_file_fopen(mutt_b2s(pagerfile), "w");
575  if (!decode_state.fp_out)
576  {
577  mutt_debug(LL_DEBUG1, "mutt_file_fopen(%s) errno=%d %s\n",
578  mutt_b2s(pagerfile), errno, strerror(errno));
579  mutt_perror(mutt_b2s(pagerfile));
580  goto return_error;
581  }
582  decode_state.fp_in = fp;
583  decode_state.flags = MUTT_CHARCONV;
584  mutt_decode_attachment(a, &decode_state);
585  if (fclose(decode_state.fp_out) == EOF)
586  mutt_debug(LL_DEBUG1, "fclose(%s) errno=%d %s\n", mutt_b2s(pagerfile),
587  errno, strerror(errno));
588  }
589  else
590  {
591  /* in compose mode, just copy the file. we can't use
592  * mutt_decode_attachment() since it assumes the content-encoding has
593  * already been applied */
594  if (mutt_save_attachment(fp, a, mutt_b2s(pagerfile), MUTT_SAVE_NO_FLAGS, NULL))
595  goto return_error;
596  }
597  }
598  else
599  {
600  /* Use built-in handler */
601  OptViewAttach = true; /* disable the "use 'v' to view this part"
602  * message in case of error */
604  {
605  OptViewAttach = false;
606  goto return_error;
607  }
608  OptViewAttach = false;
609  }
610 
611  if (a->description)
612  mutt_str_strfcpy(desc, a->description, sizeof(desc));
613  else if (a->filename)
614  snprintf(desc, sizeof(desc), _("---Attachment: %s: %s"), a->filename, type);
615  else
616  snprintf(desc, sizeof(desc), _("---Attachment: %s"), type);
617  }
618 
619  /* We only reach this point if there have been no errors */
620 
621  if (use_pager)
622  {
623  struct Pager info = { 0 };
624  info.fp = fp;
625  info.body = a;
626  info.ctx = Context;
627  info.actx = actx;
628  info.email = e;
629 
630  rc = mutt_do_pager(desc, mutt_b2s(pagerfile),
632  &info);
633  mutt_buffer_reset(pagerfile);
634  }
635  else
636  rc = 0;
637 
638 return_error:
639 
640  if (!entry || !entry->xneomuttkeep)
641  {
642  if (fp && mutt_b2s(tmpfile)[0])
643  {
644  /* add temporary file to TempAttachmentsList to be deleted on timeout hook */
646  }
647  else if (unlink_tempfile)
648  {
649  unlink(mutt_b2s(tmpfile));
650  }
651  }
652 
653  rfc1524_free_entry(&entry);
654 
655  if (mutt_b2s(pagerfile)[0] != '\0')
656  mutt_file_unlink(mutt_b2s(pagerfile));
657 
658  mutt_buffer_pool_release(&tmpfile);
659  mutt_buffer_pool_release(&pagerfile);
661 
662  return rc;
663 }
void 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:518
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1790
FILE * fp
Source stream.
Definition: pager.h:70
int mutt_rfc1524_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: rfc1524.c:70
#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:76
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1385
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:75
#define mutt_perror(...)
Definition: logging.h:85
#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:465
#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_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:86
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:791
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:122
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:147
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:1032
void mutt_add_temp_attachment(const char *filename)
Add file to list of temporary attachments.
Definition: mutt_attach.c:1183
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:614
#define mutt_b2s(buf)
Definition: buffer.h:41
struct Context * ctx
Current mailbox.
Definition: pager.h:67
void rfc1524_free_entry(struct Rfc1524MailcapEntry **entry)
Deallocate an struct Rfc1524MailcapEntry.
Definition: rfc1524.c:437
void mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:314
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:275
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:922
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
A mailcap entry.
Definition: rfc1524.h:37
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:41
Force viewing using mailcap entry.
Definition: mutt_attach.h:42
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:544
#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:518
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:582
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:84
bool mutt_needs_mailcap(struct Body *m)
Does this type need a mailcap entry do display.
Definition: muttlib.c:405
void mutt_adv_mktemp(struct Buffer *buf)
Create a temporary file.
Definition: muttlib.c:90
struct Rfc1524MailcapEntry * rfc1524_new_entry(void)
Allocate memory for a new rfc1524 entry.
Definition: rfc1524.c:428
#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
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:293
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:584
int mutt_wait_filter(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:228
struct Email * email
header information for message/rfc822
Definition: body.h:55
#define WithCrypto
Definition: ncrypt.h:160
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
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 674 of file mutt_attach.c.

675 {
676  pid_t pid;
677  int out = -1;
678  int rc = 0;
679 
680  if (outfile && *outfile)
681  {
682  out = mutt_file_open(outfile, O_CREAT | O_EXCL | O_WRONLY);
683  if (out < 0)
684  {
685  mutt_perror("open");
686  return 0;
687  }
688  }
689 
690  mutt_endwin();
691 
692  if (fp)
693  {
694  /* recv case */
695 
696  struct State s = { 0 };
697 
698  /* perform charset conversion on text attachments when piping */
699  s.flags = MUTT_CHARCONV;
700 
701  if (outfile && *outfile)
702  pid = mutt_create_filter_fd(path, &s.fp_out, NULL, NULL, -1, out, -1);
703  else
704  pid = mutt_create_filter(path, &s.fp_out, NULL, NULL);
705 
706  if (pid < 0)
707  {
708  mutt_perror(_("Can't create filter"));
709  goto bail;
710  }
711 
712  s.fp_in = fp;
713  mutt_decode_attachment(b, &s);
715  }
716  else
717  {
718  /* send case */
719  FILE *fp_in = fopen(b->filename, "r");
720  if (!fp_in)
721  {
722  mutt_perror("fopen");
723  if (outfile && *outfile)
724  {
725  close(out);
726  unlink(outfile);
727  }
728  return 0;
729  }
730 
731  FILE *fp_out = NULL;
732  if (outfile && *outfile)
733  pid = mutt_create_filter_fd(path, &fp_out, NULL, NULL, -1, out, -1);
734  else
735  pid = mutt_create_filter(path, &fp_out, NULL, NULL);
736 
737  if (pid < 0)
738  {
739  mutt_perror(_("Can't create filter"));
740  mutt_file_fclose(&fp_in);
741  goto bail;
742  }
743 
744  mutt_file_copy_stream(fp_in, fp_out);
745  mutt_file_fclose(&fp_out);
746  mutt_file_fclose(&fp_in);
747  }
748 
749  rc = 1;
750 
751 bail:
752 
753  if (outfile && *outfile)
754  close(out);
755 
756  /* check for error exit from child process */
757  if (mutt_wait_filter(pid) != 0)
758  rc = 0;
759 
760  if ((rc == 0) || C_WaitKey)
762  return rc;
763 }
pid_t mutt_create_filter(const char *s, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:217
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1790
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:149
WHERE bool C_WaitKey
Config: Prompt to press a key after running external commands.
Definition: globals.h:275
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: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:544
int mutt_file_open(const char *path, int flags)
Open a file.
Definition: file.c:518
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:267
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:228

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

772 {
773  if (opt == MUTT_SAVE_APPEND)
774  return fopen(path, "a");
775  if (opt == MUTT_SAVE_OVERWRITE)
776  return fopen(path, "w");
777 
778  return mutt_file_fopen(path, "w");
779 }
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:584

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

793 {
794  if (!m)
795  return -1;
796 
797  if (fp)
798  {
799  /* recv mode */
800 
801  if (e && m->email && (m->encoding != ENC_BASE64) &&
803  {
804  /* message type attachments are written to mail folders. */
805 
806  char buf[8192];
807  struct Message *msg = NULL;
808  CopyHeaderFlags chflags = CH_NO_FLAGS;
809  int rc = -1;
810 
811  struct Email *e_new = m->email;
812  e_new->msgno = e->msgno; /* required for MH/maildir */
813  e_new->read = true;
814 
815  if (fseeko(fp, m->offset, SEEK_SET) < 0)
816  return -1;
817  if (!fgets(buf, sizeof(buf), fp))
818  return -1;
819  struct Mailbox *m_att = mx_path_resolve(path);
820  struct Context *ctx = mx_mbox_open(m_att, MUTT_APPEND | MUTT_QUIET);
821  if (!ctx)
822  {
823  mailbox_free(&m_att);
824  return -1;
825  }
826  msg = mx_msg_open_new(ctx->mailbox, e_new,
827  is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
828  if (!msg)
829  {
830  mx_mbox_close(&ctx);
831  return -1;
832  }
833  if ((ctx->mailbox->magic == MUTT_MBOX) || (ctx->mailbox->magic == MUTT_MMDF))
834  chflags = CH_FROM | CH_UPDATE_LEN;
835  chflags |= ((ctx->mailbox->magic == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
836  if ((mutt_copy_message_fp(msg->fp, fp, e_new, MUTT_CM_NO_FLAGS, chflags) == 0) &&
837  (mx_msg_commit(ctx->mailbox, msg) == 0))
838  {
839  rc = 0;
840  }
841  else
842  {
843  rc = -1;
844  }
845 
846  mx_msg_close(ctx->mailbox, &msg);
847  mx_mbox_close(&ctx);
848  return rc;
849  }
850  else
851  {
852  /* In recv mode, extract from folder and decode */
853 
854  struct State s = { 0 };
855 
856  s.fp_out = save_attachment_open(path, opt);
857  if (!s.fp_out)
858  {
859  mutt_perror("fopen");
860  return -1;
861  }
862  fseeko((s.fp_in = fp), m->offset, SEEK_SET);
863  mutt_decode_attachment(m, &s);
864 
865  if (mutt_file_fsync_close(&s.fp_out) != 0)
866  {
867  mutt_perror("fclose");
868  return -1;
869  }
870  }
871  }
872  else
873  {
874  if (!m->filename)
875  return -1;
876 
877  /* In send mode, just copy file */
878 
879  FILE *fp_old = fopen(m->filename, "r");
880  if (!fp_old)
881  {
882  mutt_perror("fopen");
883  return -1;
884  }
885 
886  FILE *fp_new = save_attachment_open(path, opt);
887  if (!fp_new)
888  {
889  mutt_perror("fopen");
890  mutt_file_fclose(&fp_old);
891  return -1;
892  }
893 
894  if (mutt_file_copy_stream(fp_old, fp_new) == -1)
895  {
896  mutt_error(_("Write fault"));
897  mutt_file_fclose(&fp_old);
898  mutt_file_fclose(&fp_new);
899  return -1;
900  }
901  mutt_file_fclose(&fp_old);
902  if (mutt_file_fsync_close(&fp_new) != 0)
903  {
904  mutt_error(_("Write fault"));
905  return -1;
906  }
907  }
908 
909  return 0;
910 }
#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:1790
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:1385
The envelope/body of an email.
Definition: email.h:39
#define mutt_perror(...)
Definition: logging.h:85
int mx_mbox_close(struct Context **ptr)
Save changes and close mailbox.
Definition: mx.c:558
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:165
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:597
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:254
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:1089
bool read
Email is read.
Definition: email.h:53
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:149
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:958
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:267
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:1068
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:1541
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:771
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:64
struct Email * email
header information for message/rfc822
Definition: body.h:55
int msgno
Number displayed to the user.
Definition: email.h:88

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

924 {
925  struct State s = { 0 };
926  unsigned int saved_encoding = 0;
927  struct Body *saved_parts = NULL;
928  struct Email *e_saved = NULL;
929  int rc = 0;
930 
931  s.flags = displaying;
932 
933  if (opt == MUTT_SAVE_APPEND)
934  s.fp_out = fopen(path, "a");
935  else if (opt == MUTT_SAVE_OVERWRITE)
936  s.fp_out = fopen(path, "w");
937  else
938  s.fp_out = mutt_file_fopen(path, "w");
939 
940  if (!s.fp_out)
941  {
942  mutt_perror("fopen");
943  return -1;
944  }
945 
946  if (!fp)
947  {
948  /* When called from the compose menu, the attachment isn't parsed,
949  * so we need to do it here. */
950  struct stat st;
951 
952  if (stat(m->filename, &st) == -1)
953  {
954  mutt_perror("stat");
956  return -1;
957  }
958 
959  s.fp_in = fopen(m->filename, "r");
960  if (!s.fp_in)
961  {
962  mutt_perror("fopen");
963  return -1;
964  }
965 
966  saved_encoding = m->encoding;
967  if (!is_multipart(m))
968  m->encoding = ENC_8BIT;
969 
970  m->length = st.st_size;
971  m->offset = 0;
972  saved_parts = m->parts;
973  e_saved = m->email;
974  mutt_parse_part(s.fp_in, m);
975 
976  if (m->noconv || is_multipart(m))
977  s.flags |= MUTT_CHARCONV;
978  }
979  else
980  {
981  s.fp_in = fp;
982  s.flags |= MUTT_CHARCONV;
983  }
984 
985  mutt_body_handler(m, &s);
986 
987  if (mutt_file_fsync_close(&s.fp_out) != 0)
988  {
989  mutt_perror("fclose");
990  rc = -1;
991  }
992  if (!fp)
993  {
994  m->length = 0;
995  m->encoding = saved_encoding;
996  if (saved_parts)
997  {
998  email_free(&m->email);
999  m->parts = saved_parts;
1000  m->email = e_saved;
1001  }
1002  mutt_file_fclose(&s.fp_in);
1003  }
1004 
1005  return rc;
1006 }
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:39
#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:165
bool noconv
Don&#39;t do character set conversion.
Definition: body.h:73
Overwrite existing file.
Definition: mutt_attach.h:56
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:149
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:1400
char * path
Path of Email (for local Mailboxes)
Definition: email.h:93
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:1545
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:584
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:

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

1022 {
1023  char type[256];
1024  pid_t pid;
1025  FILE *fp_in = NULL, *fp_out = NULL;
1026  bool unlink_newfile = false;
1027  struct Buffer *newfile = mutt_buffer_pool_get();
1028  struct Buffer *cmd = mutt_buffer_pool_get();
1029 
1030  int rc = 0;
1031 
1032  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
1033 
1034  if (rfc1524_mailcap_lookup(a, type, NULL, MUTT_MC_PRINT))
1035  {
1036  int piped = false;
1037 
1038  mutt_debug(LL_DEBUG2, "Using mailcap\n");
1039 
1040  struct Rfc1524MailcapEntry *entry = rfc1524_new_entry();
1041  rfc1524_mailcap_lookup(a, type, entry, MUTT_MC_PRINT);
1042  mutt_rfc1524_expand_filename(entry->nametemplate, a->filename, newfile);
1043  /* send mode: symlink from existing file to the newfile */
1044  if (!fp)
1045  {
1046  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
1047  {
1048  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
1049  goto mailcap_cleanup;
1050  mutt_buffer_strcpy(newfile, a->filename);
1051  }
1052  else
1053  unlink_newfile = true;
1054  }
1055  /* in recv mode, save file to newfile first */
1056  else
1057  {
1058  if (mutt_save_attachment(fp, a, mutt_b2s(newfile), 0, NULL) == -1)
1059  goto mailcap_cleanup;
1060  }
1061 
1062  mutt_buffer_strcpy(cmd, entry->printcommand);
1063  piped = mutt_rfc1524_expand_command(a, mutt_b2s(newfile), type, cmd);
1064 
1065  mutt_endwin();
1066 
1067  /* interactive program */
1068  if (piped)
1069  {
1070  fp_in = fopen(mutt_b2s(newfile), "r");
1071  if (!fp_in)
1072  {
1073  mutt_perror("fopen");
1074  rfc1524_free_entry(&entry);
1075  goto mailcap_cleanup;
1076  }
1077 
1078  pid = mutt_create_filter(mutt_b2s(cmd), &fp_out, NULL, NULL);
1079  if (pid < 0)
1080  {
1081  mutt_perror(_("Can't create filter"));
1082  rfc1524_free_entry(&entry);
1083  mutt_file_fclose(&fp_in);
1084  goto mailcap_cleanup;
1085  }
1086  mutt_file_copy_stream(fp_in, fp_out);
1087  mutt_file_fclose(&fp_out);
1088  mutt_file_fclose(&fp_in);
1089  if (mutt_wait_filter(pid) || C_WaitKey)
1091  }
1092  else
1093  {
1094  int rc2 = mutt_system(mutt_b2s(cmd));
1095  if (rc2 == -1)
1096  mutt_debug(LL_DEBUG1, "Error running \"%s\"", cmd->data);
1097 
1098  if ((rc2 != 0) || C_WaitKey)
1100  }
1101 
1102  rc = 1;
1103 
1104  mailcap_cleanup:
1105  if (fp)
1106  mutt_file_unlink(mutt_b2s(newfile));
1107  else if (unlink_newfile)
1108  unlink(mutt_b2s(newfile));
1109 
1110  rfc1524_free_entry(&entry);
1111  goto out;
1112  }
1113 
1114  if ((mutt_str_strcasecmp("text/plain", type) == 0) ||
1115  (mutt_str_strcasecmp("application/postscript", type) == 0))
1116  {
1117  rc = (mutt_pipe_attachment(fp, a, NONULL(C_PrintCommand), NULL));
1118  goto out;
1119  }
1120  else if (mutt_can_decode(a))
1121  {
1122  /* decode and print */
1123 
1124  fp_in = NULL;
1125  fp_out = NULL;
1126 
1127  mutt_buffer_mktemp(newfile);
1128  if (mutt_decode_save_attachment(fp, a, mutt_b2s(newfile), MUTT_PRINTING, 0) == 0)
1129  {
1130  mutt_debug(LL_DEBUG2, "successfully decoded %s type attachment to %s\n",
1131  type, mutt_b2s(newfile));
1132 
1133  fp_in = fopen(mutt_b2s(newfile), "r");
1134  if (!fp_in)
1135  {
1136  mutt_perror("fopen");
1137  goto decode_cleanup;
1138  }
1139 
1140  mutt_debug(LL_DEBUG2, "successfully opened %s read-only\n", mutt_b2s(newfile));
1141 
1142  mutt_endwin();
1143  pid = mutt_create_filter(NONULL(C_PrintCommand), &fp_out, NULL, NULL);
1144  if (pid < 0)
1145  {
1146  mutt_perror(_("Can't create filter"));
1147  goto decode_cleanup;
1148  }
1149 
1150  mutt_debug(LL_DEBUG2, "Filter created\n");
1151 
1152  mutt_file_copy_stream(fp_in, fp_out);
1153 
1154  mutt_file_fclose(&fp_out);
1155  mutt_file_fclose(&fp_in);
1156 
1157  if ((mutt_wait_filter(pid) != 0) || C_WaitKey)
1159  rc = 1;
1160  }
1161  decode_cleanup:
1162  mutt_file_fclose(&fp_in);
1163  mutt_file_fclose(&fp_out);
1164  mutt_file_unlink(mutt_b2s(newfile));
1165  }
1166  else
1167  {
1168  mutt_error(_("I don't know how to print that"));
1169  rc = 0;
1170  }
1171 
1172 out:
1173  mutt_buffer_pool_release(&newfile);
1175 
1176  return rc;
1177 }
pid_t mutt_create_filter(const char *s, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:217
void 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:518
int mutt_rfc1524_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: rfc1524.c:70
#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:75
#define mutt_perror(...)
Definition: logging.h:85
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:465
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:86
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:791
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:41
void rfc1524_free_entry(struct Rfc1524MailcapEntry **entry)
Deallocate an struct Rfc1524MailcapEntry.
Definition: rfc1524.c:437
void mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:314
WHERE bool C_WaitKey
Config: Prompt to press a key after running external commands.
Definition: globals.h:275
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:922
bool mutt_can_decode(struct Body *a)
Will decoding the attachment produce any output.
Definition: handler.c:1749
char * data
Pointer to data.
Definition: buffer.h:35
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:544
#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:267
#define mutt_error(...)
Definition: logging.h:84
WHERE char * C_PrintCommand
Config: External command to print a message.
Definition: globals.h:143
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
struct Rfc1524MailcapEntry * rfc1524_new_entry(void)
Allocate memory for a new rfc1524 entry.
Definition: rfc1524.c:428
char * printcommand
Definition: rfc1524.h:44
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:293
int mutt_wait_filter(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:228
int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, char *outfile)
Pipe an attachment to a command.
Definition: mutt_attach.c:674
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:

void mutt_add_temp_attachment ( const char *  filename)

Add file to list of temporary attachments.

Parameters
filenamefilename with full path

Definition at line 1183 of file mutt_attach.c.

1184 {
1185  mutt_list_insert_tail(&TempAttachmentsList, mutt_str_strdup(filename));
1186 }
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:

void mutt_unlink_temp_attachments ( void  )

Delete all temporary attachments.

Definition at line 1191 of file mutt_attach.c.

1192 {
1193  struct ListNode *np = NULL;
1194 
1195  STAILQ_FOREACH(np, &TempAttachmentsList, entries)
1196  {
1197  mutt_file_chmod_add(np->data, S_IWUSR);
1198  mutt_file_unlink(np->data);
1199  }
1200 
1201  mutt_list_free(&TempAttachmentsList);
1202 }
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:123
#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:1056
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: