NeoMutt  2025-12-11-435-g4ac674
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 241 of file rfc2231.c.

242{
243 if (!pl)
244 return;
245
246 struct Rfc2231Parameter *conthead = NULL;
247 struct Rfc2231Parameter *conttmp = NULL;
248
249 char *s = NULL, *t = NULL;
250 char charset[256] = { 0 };
251
252 bool encoded;
253 int index;
254 bool dirty = false; /* set when we may have created empty parameters. */
255
257
258 struct Parameter *np = NULL, *tmp = NULL;
259 const bool c_rfc2047_parameters = cs_subset_bool(NeoMutt->sub, "rfc2047_parameters");
260 const struct Slist *c_assumed_charset = cc_assumed_charset();
261 const char *c_charset = cc_charset();
262
263 TAILQ_FOREACH_SAFE(np, pl, entries, tmp)
264 {
265 s = strchr(np->attribute, '*');
266 if (!s)
267 {
268 /* Single value, non encoded:
269 * attr=value
270 */
271 /* Using RFC2047 encoding in MIME parameters is explicitly
272 * forbidden by that document. Nevertheless, it's being
273 * generated by some software, including certain Lotus Notes to
274 * Internet Gateways. So we actually decode it. */
275
276 if (c_rfc2047_parameters && np->value && strstr(np->value, "=?"))
277 {
278 rfc2047_decode(&np->value);
279 }
280 else if (!slist_is_empty(c_assumed_charset))
281 {
282 mutt_ch_convert_nonmime_string(c_assumed_charset, c_charset, &np->value);
283 }
284 }
285 else if (s[1] == '\0')
286 {
287 /* Single value with encoding:
288 * attr*=us-ascii''the%20value
289 */
290 s[0] = '\0';
291
292 s = get_charset(np->value, charset, sizeof(charset));
293 decode_one(np->value, s);
294 mutt_ch_convert_string(&np->value, charset, c_charset, MUTT_ICONV_HOOK_FROM);
296 dirty = true;
297 }
298 else
299 {
300 /* A parameter continuation, which may or may not be encoded:
301 * attr*0=value
302 * -or-
303 * attr*0*=us-ascii''the%20value
304 */
305 s[0] = '\0';
306 s++; /* let s point to the first character of index. */
307 for (t = s; (t[0] != '\0') && mutt_isdigit(t[0]); t++)
308 ; // do nothing
309
310 encoded = (t[0] == '*');
311 t[0] = '\0';
312
313 /* RFC2231 says that the index starts at 0 and increments by 1,
314 * thus an overflow should never occur in a valid message, thus
315 * the value INT_MAX in case of overflow does not really matter
316 * (the goal is just to avoid undefined behaviour). */
317 if (!mutt_str_atoi_full(s, &index))
318 index = INT_MAX;
319
320 conttmp = parameter_new();
321 conttmp->attribute = np->attribute;
322 conttmp->value = np->value;
323 conttmp->encoded = encoded;
324 conttmp->index = index;
325
326 np->attribute = NULL;
327 np->value = NULL;
328 TAILQ_REMOVE(pl, np, entries);
329 FREE(&np);
330
331 list_insert(&conthead, conttmp);
332 }
333 }
334
335 if (conthead)
336 {
337 join_continuations(pl, conthead);
338 dirty = true;
339 }
340
341 if (dirty)
343}
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:317
int mutt_ch_convert_string(char **ps, const char *from, const char *to, uint8_t flags)
Convert a string between encodings.
Definition charset.c:817
#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:665
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:186
static char * get_charset(char *value, char *charset, size_t chslen)
Get the charset from an RFC2231 header.
Definition rfc2231.c:86
static void list_insert(struct Rfc2231Parameter **list, struct Rfc2231Parameter *par)
Insert parameter into an ordered list.
Definition rfc2231.c:146
static struct Rfc2231Parameter * parameter_new(void)
Create a new Rfc2231Parameter.
Definition rfc2231.c:133
static void decode_one(char *dest, char *src)
Decode one percent-encoded character.
Definition rfc2231.c:109
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 354 of file rfc2231.c.

355{
356 if (!attribute || !value)
357 return 0;
358
359 size_t count = 0;
360 bool encode = false;
361 bool add_quotes = false;
362 bool free_src_value = false;
363 bool split = false;
364 int continuation_number = 0;
365 size_t dest_value_len = 0, max_value_len = 0, cur_value_len = 0;
366 char *cur = NULL, *charset = NULL, *src_value = NULL;
367 struct Parameter *current = NULL;
368
369 struct Buffer *cur_attribute = buf_pool_get();
370 struct Buffer *cur_value = buf_pool_get();
371
372 // Perform charset conversion
373 for (cur = value; *cur; cur++)
374 {
375 if ((*cur < 0x20) || (*cur >= 0x7f))
376 {
377 encode = true;
378 break;
379 }
380 }
381
382 if (encode)
383 {
384 const struct Slist *const c_send_charset = cs_subset_slist(NeoMutt->sub, "send_charset");
385 const char *c_charset = cc_charset();
386 if (c_charset && c_send_charset)
387 {
388 charset = mutt_ch_choose(c_charset, c_send_charset, value,
389 mutt_str_len(value), &src_value, NULL);
390 }
391 if (src_value)
392 free_src_value = true;
393 if (!charset)
394 charset = mutt_str_dup(c_charset ? c_charset : "unknown-8bit");
395 }
396 if (!src_value)
397 src_value = value;
398
399 // Count the size the resultant value will need in total
400 if (encode)
401 dest_value_len = mutt_str_len(charset) + 2; /* charset'' prefix */
402
403 for (cur = src_value; *cur; cur++)
404 {
405 dest_value_len++;
406
407 if (encode)
408 {
409 /* These get converted to %xx so need a total of three chars */
410 if ((*cur < 0x20) || (*cur >= 0x7f) || strchr(MimeSpecials, *cur) ||
411 strchr("*'%", *cur))
412 {
413 dest_value_len += 2;
414 }
415 }
416 else
417 {
418 /* rfc822_cat() will add outer quotes if it finds MimeSpecials. */
419 if (!add_quotes && strchr(MimeSpecials, *cur))
420 add_quotes = true;
421 /* rfc822_cat() will add a backslash if it finds '\' or '"'. */
422 if ((*cur == '\\') || (*cur == '"'))
423 dest_value_len++;
424 }
425 }
426
427 // Determine if need to split into parameter value continuations
428 max_value_len = 78 - // rfc suggested line length
429 1 - // Leading tab on continuation line
430 mutt_str_len(attribute) - // attribute
431 (encode ? 1 : 0) - // '*' encoding marker
432 1 - // '='
433 (add_quotes ? 2 : 0) - // "...."
434 1; // ';'
435
436 if (max_value_len < 30)
437 max_value_len = 30;
438
439 if (dest_value_len > max_value_len)
440 {
441 split = true;
442 max_value_len -= 4; /* '*n' continuation number and extra encoding
443 * space to keep loop below simpler */
444 }
445
446 // Generate list of parameter continuations
447 cur = src_value;
448 if (encode)
449 {
450 buf_printf(cur_value, "%s''", charset);
451 cur_value_len = buf_len(cur_value);
452 }
453
454 while (*cur)
455 {
456 current = mutt_param_new();
457 TAILQ_INSERT_TAIL(head, current, entries);
458 count++;
459
460 buf_strcpy(cur_attribute, attribute);
461 if (split)
462 buf_add_printf(cur_attribute, "*%d", continuation_number++);
463 if (encode)
464 buf_addch(cur_attribute, '*');
465
466 while (*cur && (!split || (cur_value_len < max_value_len)))
467 {
468 if (encode)
469 {
470 if ((*cur < 0x20) || (*cur >= 0x7f) || strchr(MimeSpecials, *cur) ||
471 strchr("*'%", *cur))
472 {
473 buf_add_printf(cur_value, "%%%02X", (unsigned char) *cur);
474 cur_value_len += 3;
475 }
476 else
477 {
478 buf_addch(cur_value, *cur);
479 cur_value_len++;
480 }
481 }
482 else
483 {
484 buf_addch(cur_value, *cur);
485 cur_value_len++;
486 if ((*cur == '\\') || (*cur == '"'))
487 cur_value_len++;
488 }
489
490 cur++;
491 }
492
493 current->attribute = buf_strdup(cur_attribute);
494 current->value = buf_strdup(cur_value);
495
496 buf_reset(cur_value);
497 cur_value_len = 0;
498 }
499
500 buf_pool_release(&cur_attribute);
501 buf_pool_release(&cur_value);
502
503 FREE(&charset);
504 if (free_src_value)
505 FREE(&src_value);
506
507 return count;
508}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:161
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition buffer.c:204
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition buffer.c:491
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:241
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:571
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:67
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:1094
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:500
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:430
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: