NeoMutt  2025-12-11-980-ge38c27
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
rfc2231.h File Reference

RFC2231 MIME Charset routines. More...

#include <stddef.h>
+ Include dependency graph for rfc2231.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void rfc2231_decode_parameters (struct ParameterList *pl)
 Decode a Parameter list.
 
size_t rfc2231_encode_string (struct ParameterList *head, const char *attribute, char *value)
 Encode a string to be suitable for an RFC2231 header.
 

Detailed Description

RFC2231 MIME Charset routines.

Authors
  • Pietro Cerutti
  • Richard Russon

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 rfc2231.h.

Function Documentation

◆ rfc2231_decode_parameters()

void rfc2231_decode_parameters ( struct ParameterList * pl)

Decode a Parameter list.

Parameters
plList to decode

Definition at line 242 of file rfc2231.c.

243{
244 if (!pl)
245 return;
246
247 struct Rfc2231Parameter *conthead = NULL;
248 struct Rfc2231Parameter *conttmp = NULL;
249
250 char *s = NULL;
251 char *t = NULL;
252 char charset[256] = { 0 };
253
254 bool encoded;
255 int index = 0;
256 bool dirty = false; /* set when we may have created empty parameters. */
257
259
260 struct Parameter *np = NULL;
261 struct Parameter *tmp = NULL;
262 const bool c_rfc2047_parameters = cs_subset_bool(NeoMutt->sub, "rfc2047_parameters");
263 const struct Slist *c_assumed_charset = cc_assumed_charset();
264 const char *c_charset = cc_charset();
265
266 TAILQ_FOREACH_SAFE(np, pl, entries, tmp)
267 {
268 s = strchr(np->attribute, '*');
269 if (!s)
270 {
271 /* Single value, non encoded:
272 * attr=value
273 */
274 /* Using RFC2047 encoding in MIME parameters is explicitly
275 * forbidden by that document. Nevertheless, it's being
276 * generated by some software, including certain Lotus Notes to
277 * Internet Gateways. So we actually decode it. */
278
279 if (c_rfc2047_parameters && np->value && strstr(np->value, "=?"))
280 {
281 rfc2047_decode(&np->value);
282 }
283 else if (!slist_is_empty(c_assumed_charset))
284 {
285 mutt_ch_convert_nonmime_string(c_assumed_charset, c_charset, &np->value);
286 }
287 }
288 else if (s[1] == '\0')
289 {
290 /* Single value with encoding:
291 * attr*=us-ascii''the%20value
292 */
293 s[0] = '\0';
294
295 s = get_charset(np->value, charset, sizeof(charset));
296 decode_one(np->value, s);
297 mutt_ch_convert_string(&np->value, charset, c_charset, MUTT_ICONV_HOOK_FROM);
299 dirty = true;
300 }
301 else
302 {
303 /* A parameter continuation, which may or may not be encoded:
304 * attr*0=value
305 * -or-
306 * attr*0*=us-ascii''the%20value
307 */
308 s[0] = '\0';
309 s++; /* let s point to the first character of index. */
310 for (t = s; (t[0] != '\0') && mutt_isdigit(t[0]); t++)
311 ; // do nothing
312
313 encoded = (t[0] == '*');
314 t[0] = '\0';
315
316 /* RFC2231 says that the index starts at 0 and increments by 1,
317 * thus an overflow should never occur in a valid message, thus
318 * the value INT_MAX in case of overflow does not really matter
319 * (the goal is just to avoid undefined behaviour). */
320 if (!mutt_str_atoi_full(s, &index))
321 index = INT_MAX;
322
323 conttmp = parameter_new();
324 conttmp->attribute = np->attribute;
325 conttmp->value = np->value;
326 conttmp->encoded = encoded;
327 conttmp->index = index;
328
329 np->attribute = NULL;
330 np->value = NULL;
331 TAILQ_REMOVE(pl, np, entries);
332 FREE(&np);
333
334 list_insert(&conthead, conttmp);
335 }
336 }
337
338 if (conthead)
339 {
340 join_continuations(pl, conthead);
341 dirty = true;
342 }
343
344 if (dirty)
346}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
const char * cc_charset(void)
Get the cached value of $charset.
const struct Slist * cc_assumed_charset(void)
Get the cached value of $assumed_charset.
bool mutt_isdigit(int arg)
Wrapper for isdigit(3)
Definition ctype.c:66
int mutt_mb_filter_unprintable(char **s)
Replace unprintable characters.
Definition mbyte.c:424
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
int mutt_ch_convert_nonmime_string(const struct Slist *const assumed_charset, const char *charset, char **ps)
Try to convert a string using a list of character sets.
Definition charset.c:318
int mutt_ch_convert_string(char **ps, const char *from, const char *to, uint8_t flags)
Convert a string between encodings.
Definition charset.c:819
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition charset.h:67
bool slist_is_empty(const struct Slist *list)
Is the slist empty?
Definition slist.c:140
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition queue.h:792
#define TAILQ_REMOVE(head, elm, field)
Definition queue.h:901
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition rfc2047.c:679
static void purge_empty_parameters(struct ParameterList *pl)
Remove any ill-formed Parameters from a list.
Definition rfc2231.c:66
static void join_continuations(struct ParameterList *pl, struct Rfc2231Parameter *par)
Process continuation parameters.
Definition rfc2231.c:187
static char * get_charset(char *value, char *charset, size_t chslen)
Get the charset from an RFC2231 header.
Definition rfc2231.c:87
static void list_insert(struct Rfc2231Parameter **list, struct Rfc2231Parameter *par)
Insert parameter into an ordered list.
Definition rfc2231.c:147
static struct Rfc2231Parameter * parameter_new(void)
Create a new Rfc2231Parameter.
Definition rfc2231.c:134
static void decode_one(char *dest, char *src)
Decode one percent-encoded character.
Definition rfc2231.c:110
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
Attribute associated with a MIME part.
Definition parameter.h:33
char * attribute
Parameter name.
Definition parameter.h:34
char * value
Parameter value.
Definition parameter.h:35
MIME section parameter.
Definition rfc2231.c:54
bool encoded
Is the value encoded?
Definition rfc2231.c:58
int index
Index number in the list.
Definition rfc2231.c:57
char * value
Attribute value.
Definition rfc2231.c:56
char * attribute
Attribute name.
Definition rfc2231.c:55
String list.
Definition slist.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ rfc2231_encode_string()

size_t rfc2231_encode_string ( struct ParameterList * head,
const char * attribute,
char * value )

Encode a string to be suitable for an RFC2231 header.

Parameters
headString encoded as a ParameterList, empty on error
attributeName of attribute to encode
valueValue of attribute to encode
Return values
numNumber of Parameters in the List

If the value is large, the list will contain continuation lines.

Definition at line 357 of file rfc2231.c.

358{
359 if (!attribute || !value)
360 return 0;
361
362 size_t count = 0;
363 bool encode = false;
364 bool add_quotes = false;
365 bool free_src_value = false;
366 bool split = false;
367 int continuation_number = 0;
368 size_t dest_value_len = 0;
369 size_t max_value_len = 0;
370 size_t cur_value_len = 0;
371 char *cur = NULL;
372 char *charset = NULL;
373 char *src_value = NULL;
374 struct Parameter *current = NULL;
375
376 struct Buffer *cur_attribute = buf_pool_get();
377 struct Buffer *cur_value = buf_pool_get();
378
379 // Perform charset conversion
380 for (cur = value; *cur; cur++)
381 {
382 if ((*cur < 0x20) || (*cur >= 0x7f))
383 {
384 encode = true;
385 break;
386 }
387 }
388
389 if (encode)
390 {
391 const struct Slist *const c_send_charset = cs_subset_slist(NeoMutt->sub, "send_charset");
392 const char *c_charset = cc_charset();
393 if (c_charset && c_send_charset)
394 {
395 charset = mutt_ch_choose(c_charset, c_send_charset, value,
396 mutt_str_len(value), &src_value, NULL);
397 }
398 if (src_value)
399 free_src_value = true;
400 if (!charset)
401 charset = mutt_str_dup(c_charset ? c_charset : "unknown-8bit");
402 }
403 if (!src_value)
404 src_value = value;
405
406 // Count the size the resultant value will need in total
407 if (encode)
408 dest_value_len = mutt_str_len(charset) + 2; /* charset'' prefix */
409
410 for (cur = src_value; *cur; cur++)
411 {
412 dest_value_len++;
413
414 if (encode)
415 {
416 /* These get converted to %xx so need a total of three chars */
417 if ((*cur < 0x20) || (*cur >= 0x7f) || strchr(MimeSpecials, *cur) ||
418 strchr("*'%", *cur))
419 {
420 dest_value_len += 2;
421 }
422 }
423 else
424 {
425 /* rfc822_cat() will add outer quotes if it finds MimeSpecials. */
426 if (!add_quotes && strchr(MimeSpecials, *cur))
427 add_quotes = true;
428 /* rfc822_cat() will add a backslash if it finds '\' or '"'. */
429 if ((*cur == '\\') || (*cur == '"'))
430 dest_value_len++;
431 }
432 }
433
434 // Determine if need to split into parameter value continuations
435 max_value_len = 78 - // rfc suggested line length
436 1 - // Leading tab on continuation line
437 mutt_str_len(attribute) - // attribute
438 (encode ? 1 : 0) - // '*' encoding marker
439 1 - // '='
440 (add_quotes ? 2 : 0) - // "...."
441 1; // ';'
442
443 if (max_value_len < 30)
444 max_value_len = 30;
445
446 if (dest_value_len > max_value_len)
447 {
448 split = true;
449 max_value_len -= 4; /* '*n' continuation number and extra encoding
450 * space to keep loop below simpler */
451 }
452
453 // Generate list of parameter continuations
454 cur = src_value;
455 if (encode)
456 {
457 buf_printf(cur_value, "%s''", charset);
458 cur_value_len = buf_len(cur_value);
459 }
460
461 while (*cur)
462 {
463 current = mutt_param_new();
464 TAILQ_INSERT_TAIL(head, current, entries);
465 count++;
466
467 buf_strcpy(cur_attribute, attribute);
468 if (split)
469 buf_add_printf(cur_attribute, "*%d", continuation_number++);
470 if (encode)
471 buf_addch(cur_attribute, '*');
472
473 while (*cur && (!split || (cur_value_len < max_value_len)))
474 {
475 if (encode)
476 {
477 if ((*cur < 0x20) || (*cur >= 0x7f) || strchr(MimeSpecials, *cur) ||
478 strchr("*'%", *cur))
479 {
480 buf_add_printf(cur_value, "%%%02X", (unsigned char) *cur);
481 cur_value_len += 3;
482 }
483 else
484 {
485 buf_addch(cur_value, *cur);
486 cur_value_len++;
487 }
488 }
489 else
490 {
491 buf_addch(cur_value, *cur);
492 cur_value_len++;
493 if ((*cur == '\\') || (*cur == '"'))
494 cur_value_len++;
495 }
496
497 cur++;
498 }
499
500 current->attribute = buf_strdup(cur_attribute);
501 current->value = buf_strdup(cur_value);
502
503 buf_reset(cur_value);
504 cur_value_len = 0;
505 }
506
507 buf_pool_release(&cur_attribute);
508 buf_pool_release(&cur_value);
509
510 FREE(&charset);
511 if (free_src_value)
512 FREE(&src_value);
513
514 return count;
515}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:168
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition buffer.c:211
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition buffer.c:497
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:89
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:248
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:401
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:577
const struct Slist * cs_subset_slist(const struct ConfigSubset *sub, const char *name)
Get a string-list config item by name.
Definition helpers.c:242
const char MimeSpecials[]
Characters that need special treatment in MIME.
Definition mime.c:69
char * mutt_ch_choose(const char *fromcode, const struct Slist *charsets, const char *u, size_t ulen, char **d, size_t *dlen)
Figure the best charset to encode a string.
Definition charset.c:1096
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
struct Parameter * mutt_param_new(void)
Create a new Parameter.
Definition parameter.c:40
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition queue.h:866
static int encode(const char *d, size_t dlen, int col, const char *fromcode, const struct Slist *charsets, char **e, size_t *elen, const char *specials)
RFC2047-encode a string.
Definition rfc2047.c:438
String manipulation buffer.
Definition buffer.h:36
struct ListHead head
List containing values.
Definition slist.h:38
size_t count
Number of values in list.
Definition slist.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function: