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

RFC1524 Mailcap routines. More...

#include "config.h"
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "mutt/mutt.h"
#include "email/lib.h"
#include "mailcap.h"
#include "globals.h"
#include "mutt_attach.h"
#include "muttlib.h"
#include "protos.h"
+ Include dependency graph for mailcap.c:

Go to the source code of this file.

Functions

int mailcap_expand_command (struct Body *a, const char *filename, const char *type, struct Buffer *command)
 Expand expandos in a command. More...
 
static char * get_field (char *s)
 NUL terminate a RFC1524 field. More...
 
static int get_field_text (char *field, char **entry, const char *type, const char *filename, int line)
 Get the matching text from a mailcap. More...
 
static bool rfc1524_mailcap_parse (struct Body *a, const char *filename, const char *type, struct MailcapEntry *entry, enum MailcapLookup opt)
 Parse a mailcap entry. More...
 
struct MailcapEntrymailcap_entry_new (void)
 Allocate memory for a new rfc1524 entry. More...
 
void mailcap_entry_free (struct MailcapEntry **ptr)
 Deallocate an struct MailcapEntry. More...
 
bool mailcap_lookup (struct Body *a, char *type, size_t typelen, struct MailcapEntry *entry, enum MailcapLookup opt)
 Find given type in the list of mailcap files. More...
 
void mailcap_expand_filename (const char *nametemplate, const char *oldfile, struct Buffer *newfile)
 Expand a new filename from a template or existing filename. More...
 

Variables

bool C_MailcapSanitize
 Config: Restrict the possible characters in mailcap expandos. More...
 

Detailed Description

RFC1524 Mailcap routines.

Authors
  • Michael R. Elkins

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

Function Documentation

◆ mailcap_expand_command()

int mailcap_expand_command ( struct Body a,
const char *  filename,
const char *  type,
struct Buffer command 
)

Expand expandos in a command.

Parameters
aEmail Body
filenameFile containing the email text
typeType, e.g. "text/plain"
commandBuffer containing command
Return values
0Command works on a file
1Command works on a pipe

The command semantics include the following: s is the filename that contains the mail body data t is the content type, like text/plain %{parameter} is replaced by the parameter value from the content-type field % is % Unsupported rfc1524 parameters: these would probably require some doing by neomutt, and can probably just be done by piping the message to metamail n is the integer number of sub-parts in the multipart F is "content-type filename" repeated for each sub-part

Definition at line 70 of file mailcap.c.

72 {
73  int needspipe = true;
74  struct Buffer *buf = mutt_buffer_pool_get();
75  struct Buffer *quoted = mutt_buffer_pool_get();
76  struct Buffer *param = NULL;
77  struct Buffer *type2 = NULL;
78 
79  const char *cptr = mutt_b2s(command);
80  while (*cptr)
81  {
82  if (*cptr == '\\')
83  {
84  cptr++;
85  if (*cptr)
86  mutt_buffer_addch(buf, *cptr++);
87  }
88  else if (*cptr == '%')
89  {
90  cptr++;
91  if (*cptr == '{')
92  {
93  const char *pvalue2 = NULL;
94 
95  if (param)
96  mutt_buffer_reset(param);
97  else
98  param = mutt_buffer_pool_get();
99 
100  /* Copy parameter name into param buffer */
101  cptr++;
102  while (*cptr && (*cptr != '}'))
103  mutt_buffer_addch(param, *cptr++);
104 
105  /* In send mode, use the current charset, since the message hasn't
106  * been converted yet. If noconv is set, then we assume the
107  * charset parameter has the correct value instead. */
108  if ((mutt_str_strcasecmp(mutt_b2s(param), "charset") == 0) && a->charset && !a->noconv)
109  pvalue2 = a->charset;
110  else
111  pvalue2 = mutt_param_get(&a->parameter, mutt_b2s(param));
112 
113  /* Now copy the parameter value into param buffer */
114  if (C_MailcapSanitize)
115  mutt_buffer_sanitize_filename(param, NONULL(pvalue2), false);
116  else
117  mutt_buffer_strcpy(param, NONULL(pvalue2));
118 
119  mutt_buffer_quote_filename(quoted, mutt_b2s(param), true);
120  mutt_buffer_addstr(buf, mutt_b2s(quoted));
121  }
122  else if ((*cptr == 's') && filename)
123  {
124  mutt_buffer_quote_filename(quoted, filename, true);
125  mutt_buffer_addstr(buf, mutt_b2s(quoted));
126  needspipe = false;
127  }
128  else if (*cptr == 't')
129  {
130  if (!type2)
131  {
132  type2 = mutt_buffer_pool_get();
133  if (C_MailcapSanitize)
134  mutt_buffer_sanitize_filename(type2, type, false);
135  else
136  mutt_buffer_strcpy(type2, type);
137  }
138  mutt_buffer_quote_filename(quoted, mutt_b2s(type2), true);
139  mutt_buffer_addstr(buf, mutt_b2s(quoted));
140  }
141 
142  if (*cptr)
143  cptr++;
144  }
145  else
146  mutt_buffer_addch(buf, *cptr++);
147  }
148  mutt_buffer_copy(command, buf);
149 
151  mutt_buffer_pool_release(&quoted);
152  mutt_buffer_pool_release(&param);
153  mutt_buffer_pool_release(&type2);
154 
155  return needspipe;
156 }
void mutt_buffer_quote_filename(struct Buffer *buf, const char *filename, bool add_outer)
Quote a filename to survive the shell&#39;s quoting rules.
Definition: file.c:834
#define NONULL(x)
Definition: string2.h:37
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer&#39;s contents to another Buffer.
Definition: buffer.c:445
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
bool noconv
Don&#39;t do character set conversion.
Definition: body.h:73
String manipulation buffer.
Definition: buffer.h:33
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
#define mutt_b2s(buf)
Definition: buffer.h:41
char * charset
Send mode: charset of attached file as stored on disk.
Definition: body.h:49
bool C_MailcapSanitize
Config: Restrict the possible characters in mailcap expandos.
Definition: mailcap.c:49
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
void mutt_buffer_sanitize_filename(struct Buffer *buf, const char *path, short slash)
Replace unsafe characters in a filename.
Definition: muttlib.c:1757
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_field()

static char* get_field ( char *  s)
static

NUL terminate a RFC1524 field.

Parameters
sString to alter
Return values
ptrStart of next field
NULLError

Definition at line 164 of file mailcap.c.

165 {
166  if (!s)
167  return NULL;
168 
169  char *ch = NULL;
170 
171  while ((ch = strpbrk(s, ";\\")))
172  {
173  if (*ch == '\\')
174  {
175  s = ch + 1;
176  if (*s)
177  s++;
178  }
179  else
180  {
181  *ch = '\0';
182  ch = mutt_str_skip_email_wsp(ch + 1);
183  break;
184  }
185  }
187  return ch;
188 }
void mutt_str_remove_trailing_ws(char *s)
Trim trailing whitespace from a string.
Definition: string.c:734
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:776
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_field_text()

static int get_field_text ( char *  field,
char **  entry,
const char *  type,
const char *  filename,
int  line 
)
static

Get the matching text from a mailcap.

Parameters
fieldString to parse
entrySave the entry here
typeType, e.g. "text/plain"
filenameMailcap filename
lineMailcap line
Return values
1Success
0Failure

Definition at line 200 of file mailcap.c.

202 {
203  field = mutt_str_skip_whitespace(field);
204  if (*field == '=')
205  {
206  if (entry)
207  {
208  field++;
209  field = mutt_str_skip_whitespace(field);
210  mutt_str_replace(entry, field);
211  }
212  return 1;
213  }
214  else
215  {
216  mutt_error(_("Improperly formatted entry for type %s in \"%s\" line %d"),
217  type, filename, line);
218  return 0;
219  }
220 }
char * mutt_str_skip_whitespace(const char *p)
Find the first non-whitespace character in a string.
Definition: string.c:720
#define _(a)
Definition: message.h:28
const char * line
Definition: common.c:36
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
#define mutt_error(...)
Definition: logging.h:84
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ rfc1524_mailcap_parse()

static bool rfc1524_mailcap_parse ( struct Body a,
const char *  filename,
const char *  type,
struct MailcapEntry entry,
enum MailcapLookup  opt 
)
static

Parse a mailcap entry.

Parameters
aEmail Body
filenameFilename
typeType, e.g. "text/plain"
entryEntry, e.g. "compose"
optOption, see MailcapLookup
Return values
trueSuccess
falseFailure

Definition at line 232 of file mailcap.c.

234 {
235  char *buf = NULL;
236  bool found = false;
237  int line = 0;
238 
239  /* rfc1524 mailcap file is of the format:
240  * base/type; command; extradefs
241  * type can be * for matching all
242  * base with no /type is an implicit wild
243  * command contains a %s for the filename to pass, default to pipe on stdin
244  * extradefs are of the form:
245  * def1="definition"; def2="define \;";
246  * line wraps with a \ at the end of the line
247  * # for comments */
248 
249  /* find length of basetype */
250  char *ch = strchr(type, '/');
251  if (!ch)
252  return false;
253  const int btlen = ch - type;
254 
255  FILE *fp = fopen(filename, "r");
256  if (fp)
257  {
258  size_t buflen;
259  while (!found && (buf = mutt_file_read_line(buf, &buflen, fp, &line, MUTT_CONT)))
260  {
261  /* ignore comments */
262  if (*buf == '#')
263  continue;
264  mutt_debug(LL_DEBUG2, "mailcap entry: %s\n", buf);
265 
266  /* check type */
267  ch = get_field(buf);
268  if ((mutt_str_strcasecmp(buf, type) != 0) &&
269  ((mutt_str_strncasecmp(buf, type, btlen) != 0) ||
270  ((buf[btlen] != '\0') && /* implicit wild */
271  (mutt_str_strcmp(buf + btlen, "/*") != 0)))) /* wildsubtype */
272  {
273  continue;
274  }
275 
276  /* next field is the viewcommand */
277  char *field = ch;
278  ch = get_field(ch);
279  if (entry)
280  entry->command = mutt_str_strdup(field);
281 
282  /* parse the optional fields */
283  found = true;
284  bool copiousoutput = false;
285  bool composecommand = false;
286  bool editcommand = false;
287  bool printcommand = false;
288 
289  while (ch)
290  {
291  field = ch;
292  ch = get_field(ch);
293  mutt_debug(LL_DEBUG2, "field: %s\n", field);
294  size_t plen;
295 
296  if (mutt_str_strcasecmp(field, "needsterminal") == 0)
297  {
298  if (entry)
299  entry->needsterminal = true;
300  }
301  else if (mutt_str_strcasecmp(field, "copiousoutput") == 0)
302  {
303  copiousoutput = true;
304  if (entry)
305  entry->copiousoutput = true;
306  }
307  else if ((plen = mutt_str_startswith(field, "composetyped", CASE_IGNORE)))
308  {
309  /* this compare most occur before compose to match correctly */
310  if (get_field_text(field + plen, entry ? &entry->composetypecommand : NULL,
311  type, filename, line))
312  {
313  composecommand = true;
314  }
315  }
316  else if ((plen = mutt_str_startswith(field, "compose", CASE_IGNORE)))
317  {
318  if (get_field_text(field + plen, entry ? &entry->composecommand : NULL,
319  type, filename, line))
320  {
321  composecommand = true;
322  }
323  }
324  else if ((plen = mutt_str_startswith(field, "print", CASE_IGNORE)))
325  {
326  if (get_field_text(field + plen, entry ? &entry->printcommand : NULL,
327  type, filename, line))
328  {
329  printcommand = true;
330  }
331  }
332  else if ((plen = mutt_str_startswith(field, "edit", CASE_IGNORE)))
333  {
334  if (get_field_text(field + plen, entry ? &entry->editcommand : NULL,
335  type, filename, line))
336  editcommand = true;
337  }
338  else if ((plen = mutt_str_startswith(field, "nametemplate", CASE_IGNORE)))
339  {
340  get_field_text(field + plen, entry ? &entry->nametemplate : NULL,
341  type, filename, line);
342  }
343  else if ((plen = mutt_str_startswith(field, "x-convert", CASE_IGNORE)))
344  {
345  get_field_text(field + plen, entry ? &entry->convert : NULL, type, filename, line);
346  }
347  else if ((plen = mutt_str_startswith(field, "test", CASE_IGNORE)))
348  {
349  /* This routine executes the given test command to determine
350  * if this is the right entry. */
351  char *test_command = NULL;
352 
353  if (get_field_text(field + plen, &test_command, type, filename, line) && test_command)
354  {
355  struct Buffer *command = mutt_buffer_pool_get();
356  struct Buffer *afilename = mutt_buffer_pool_get();
357  mutt_buffer_strcpy(command, test_command);
358  if (C_MailcapSanitize)
359  mutt_buffer_sanitize_filename(afilename, NONULL(a->filename), true);
360  else
361  mutt_buffer_strcpy(afilename, NONULL(a->filename));
362  mailcap_expand_command(a, mutt_b2s(afilename), type, command);
363  if (mutt_system(mutt_b2s(command)))
364  {
365  /* a non-zero exit code means test failed */
366  found = false;
367  }
368  FREE(&test_command);
369  mutt_buffer_pool_release(&command);
370  mutt_buffer_pool_release(&afilename);
371  }
372  }
373  else if (mutt_str_startswith(field, "x-neomutt-keep", CASE_IGNORE))
374  {
375  if (entry)
376  entry->xneomuttkeep = true;
377  }
378  } /* while (ch) */
379 
380  if (opt == MUTT_MC_AUTOVIEW)
381  {
382  if (!copiousoutput)
383  found = false;
384  }
385  else if (opt == MUTT_MC_COMPOSE)
386  {
387  if (!composecommand)
388  found = false;
389  }
390  else if (opt == MUTT_MC_EDIT)
391  {
392  if (!editcommand)
393  found = false;
394  }
395  else if (opt == MUTT_MC_PRINT)
396  {
397  if (!printcommand)
398  found = false;
399  }
400 
401  if (!found)
402  {
403  /* reset */
404  if (entry)
405  {
406  FREE(&entry->command);
407  FREE(&entry->composecommand);
408  FREE(&entry->composetypecommand);
409  FREE(&entry->editcommand);
410  FREE(&entry->printcommand);
411  FREE(&entry->nametemplate);
412  FREE(&entry->convert);
413  entry->needsterminal = false;
414  entry->copiousoutput = false;
415  entry->xneomuttkeep = false;
416  }
417  }
418  } /* while (!found && (buf = mutt_file_read_line ())) */
419  mutt_file_fclose(&fp);
420  } /* if ((fp = fopen ())) */
421  FREE(&buf);
422  return found;
423 }
bool xneomuttkeep
do not remove the file on command exit
Definition: mailcap.h:49
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
#define NONULL(x)
Definition: string2.h:37
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
char * convert
Definition: mailcap.h:46
Mailcap autoview field.
Definition: mailcap.h:61
char * composetypecommand
Definition: mailcap.h:42
static size_t plen
Length of cached packet.
Definition: pgppacket.c:38
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
String manipulation buffer.
Definition: buffer.h:33
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, int flags)
Read a line from a file.
Definition: file.c:664
#define MUTT_CONT
-continuation
Definition: file.h:38
int mailcap_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: mailcap.c:70
Mailcap compose field.
Definition: mailcap.h:59
Log at debug level 2.
Definition: logging.h:57
Mailcap print field.
Definition: mailcap.h:60
bool copiousoutput
needs pager, basically
Definition: mailcap.h:48
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
char * editcommand
Definition: mailcap.h:43
char * command
Definition: mailcap.h:39
#define mutt_b2s(buf)
Definition: buffer.h:41
const char * line
Definition: common.c:36
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
static int get_field_text(char *field, char **entry, const char *type, const char *filename, int line)
Get the matching text from a mailcap.
Definition: mailcap.c:200
Ignore case when comparing strings.
Definition: string2.h:68
bool C_MailcapSanitize
Config: Restrict the possible characters in mailcap expandos.
Definition: mailcap.c:49
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:168
char * printcommand
Definition: mailcap.h:44
char * nametemplate
Definition: mailcap.h:45
void mutt_buffer_sanitize_filename(struct Buffer *buf, const char *path, short slash)
Replace unsafe characters in a filename.
Definition: muttlib.c:1757
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
char * composecommand
Definition: mailcap.h:41
#define FREE(x)
Definition: memory.h:40
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Mailcap edit field.
Definition: mailcap.h:58
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:615
bool needsterminal
endwin() and system
Definition: mailcap.h:47
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
static char * get_field(char *s)
NUL terminate a RFC1524 field.
Definition: mailcap.c:164
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mailcap_entry_new()

struct MailcapEntry* mailcap_entry_new ( void  )

Allocate memory for a new rfc1524 entry.

Return values
ptrAn un-initialized struct MailcapEntry

Definition at line 429 of file mailcap.c.

430 {
431  return mutt_mem_calloc(1, sizeof(struct MailcapEntry));
432 }
A mailcap entry.
Definition: mailcap.h:37
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mailcap_entry_free()

void mailcap_entry_free ( struct MailcapEntry **  ptr)

Deallocate an struct MailcapEntry.

Parameters
[out]ptrMailcapEntry to deallocate

Definition at line 438 of file mailcap.c.

439 {
440  if (!ptr || !*ptr)
441  return;
442 
443  struct MailcapEntry *me = *ptr;
444 
445  FREE(&me->command);
446  FREE(&me->testcommand);
447  FREE(&me->composecommand);
448  FREE(&me->composetypecommand);
449  FREE(&me->editcommand);
450  FREE(&me->printcommand);
451  FREE(&me->nametemplate);
452  FREE(ptr);
453 }
A mailcap entry.
Definition: mailcap.h:37
char * composetypecommand
Definition: mailcap.h:42
char * editcommand
Definition: mailcap.h:43
char * command
Definition: mailcap.h:39
char * printcommand
Definition: mailcap.h:44
char * nametemplate
Definition: mailcap.h:45
char * composecommand
Definition: mailcap.h:41
#define FREE(x)
Definition: memory.h:40
char * testcommand
Definition: mailcap.h:40
+ Here is the caller graph for this function:

◆ mailcap_lookup()

bool mailcap_lookup ( struct Body a,
char *  type,
size_t  typelen,
struct MailcapEntry entry,
enum MailcapLookup  opt 
)

Find given type in the list of mailcap files.

Parameters
aMessage body
typeText type in "type/subtype" format
typelenLength of the type
entrystruct MailcapEntry to populate with results
optType of mailcap entry to lookup, see MailcapLookup
Return values
trueIf *entry is not NULL it populates it with the mailcap entry
falseNo matching entry is found

Find the given type in the list of mailcap files.

Definition at line 467 of file mailcap.c.

469 {
470  /* rfc1524 specifies that a path of mailcap files should be searched.
471  * joy. They say
472  * $HOME/.mailcap:/etc/mailcap:/usr/etc/mailcap:/usr/local/etc/mailcap, etc
473  * and overridden by the MAILCAPS environment variable, and, just to be nice,
474  * we'll make it specifiable in .neomuttrc */
475  if (!C_MailcapPath || (C_MailcapPath->count == 0))
476  {
477  mutt_error(_("No mailcap path specified"));
478  return false;
479  }
480 
481  mutt_check_lookup_list(a, type, typelen);
482 
483  struct Buffer *path = mutt_buffer_pool_get();
484  bool found = false;
485 
486  struct ListNode *np = NULL;
487  STAILQ_FOREACH(np, &C_MailcapPath->head, entries)
488  {
489  mutt_buffer_strcpy(path, np->data);
491 
492  mutt_debug(LL_DEBUG2, "Checking mailcap file: %s\n", mutt_b2s(path));
493  found = rfc1524_mailcap_parse(a, mutt_b2s(path), type, entry, opt);
494  if (found)
495  break;
496  }
497 
499 
500  if (entry && !found)
501  mutt_error(_("mailcap entry for type %s not found"), type);
502 
503  return found;
504 }
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
Log at debug level 2.
Definition: logging.h:57
struct ListHead head
Definition: slist.h:45
size_t count
Definition: slist.h:46
#define mutt_b2s(buf)
Definition: buffer.h:41
WHERE struct Slist * C_MailcapPath
Config: Colon-separated list of mailcap files.
Definition: globals.h:120
static bool rfc1524_mailcap_parse(struct Body *a, const char *filename, const char *type, struct MailcapEntry *entry, enum MailcapLookup opt)
Parse a mailcap entry.
Definition: mailcap.c:232
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
char * data
String.
Definition: list.h:35
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:343
void mutt_check_lookup_list(struct Body *b, char *type, size_t len)
Update the mime type.
Definition: mutt_attach.c:330
#define mutt_error(...)
Definition: logging.h:84
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
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:

◆ mailcap_expand_filename()

void mailcap_expand_filename ( const char *  nametemplate,
const char *  oldfile,
struct Buffer newfile 
)

Expand a new filename from a template or existing filename.

Parameters
nametemplateTemplate
oldfileOriginal filename
newfileBuffer for new filename

If there is no nametemplate, the stripped oldfile name is used as the template for newfile.

If there is no oldfile, the stripped nametemplate name is used as the template for newfile.

If both a nametemplate and oldfile are specified, the template is checked for a "%s". If none is found, the nametemplate is used as the template for newfile. The first path component of the nametemplate and oldfile are ignored.

Definition at line 522 of file mailcap.c.

524 {
525  int i, j, k;
526  char *s = NULL;
527  bool lmatch = false, rmatch = false;
528 
529  mutt_buffer_reset(newfile);
530 
531  /* first, ignore leading path components */
532 
533  if (nametemplate && (s = strrchr(nametemplate, '/')))
534  nametemplate = s + 1;
535 
536  if (oldfile && (s = strrchr(oldfile, '/')))
537  oldfile = s + 1;
538 
539  if (!nametemplate)
540  {
541  if (oldfile)
542  mutt_buffer_strcpy(newfile, oldfile);
543  }
544  else if (!oldfile)
545  {
546  mutt_file_expand_fmt(newfile, nametemplate, "neomutt");
547  }
548  else /* oldfile && nametemplate */
549  {
550  /* first, compare everything left from the "%s"
551  * (if there is one). */
552 
553  lmatch = true;
554  bool ps = false;
555  for (i = 0; nametemplate[i]; i++)
556  {
557  if ((nametemplate[i] == '%') && (nametemplate[i + 1] == 's'))
558  {
559  ps = true;
560  break;
561  }
562 
563  /* note that the following will _not_ read beyond oldfile's end. */
564 
565  if (lmatch && (nametemplate[i] != oldfile[i]))
566  lmatch = false;
567  }
568 
569  if (ps)
570  {
571  /* If we had a "%s", check the rest. */
572 
573  /* now, for the right part: compare everything right from
574  * the "%s" to the final part of oldfile.
575  *
576  * The logic here is as follows:
577  *
578  * - We start reading from the end.
579  * - There must be a match _right_ from the "%s",
580  * thus the i + 2.
581  * - If there was a left hand match, this stuff
582  * must not be counted again. That's done by the
583  * condition (j >= (lmatch ? i : 0)). */
584 
585  rmatch = true;
586 
587  for (j = mutt_str_strlen(oldfile) - 1, k = mutt_str_strlen(nametemplate) - 1;
588  (j >= (lmatch ? i : 0)) && (k >= (i + 2)); j--, k--)
589  {
590  if (nametemplate[k] != oldfile[j])
591  {
592  rmatch = false;
593  break;
594  }
595  }
596 
597  /* Now, check if we had a full match. */
598 
599  if (k >= i + 2)
600  rmatch = false;
601 
602  struct Buffer *left = mutt_buffer_pool_get();
603  struct Buffer *right = mutt_buffer_pool_get();
604 
605  if (!lmatch)
606  mutt_buffer_strcpy_n(left, nametemplate, i);
607  if (!rmatch)
608  mutt_buffer_strcpy(right, nametemplate + i + 2);
609  mutt_buffer_printf(newfile, "%s%s%s", mutt_b2s(left), oldfile, mutt_b2s(right));
610 
612  mutt_buffer_pool_release(&right);
613  }
614  else
615  {
616  /* no "%s" in the name template. */
617  mutt_buffer_strcpy(newfile, nametemplate);
618  }
619  }
620 
621  mutt_adv_mktemp(newfile);
622 }
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
String manipulation buffer.
Definition: buffer.h:33
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
#define mutt_b2s(buf)
Definition: buffer.h:41
size_t mutt_buffer_strcpy_n(struct Buffer *buf, const char *s, size_t len)
Copy a string into a Buffer.
Definition: buffer.c:327
void mutt_file_expand_fmt(struct Buffer *dest, const char *fmt, const char *src)
Replace s in a string with a filename.
Definition: file.c:1434
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
void mutt_adv_mktemp(struct Buffer *buf)
Create a temporary file.
Definition: muttlib.c:96
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ C_MailcapSanitize

bool C_MailcapSanitize

Config: Restrict the possible characters in mailcap expandos.

Definition at line 49 of file mailcap.c.