NeoMutt  2024-04-16-36-g75b6fb
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, *t = NULL;
251 char charset[256] = { 0 };
252
253 bool encoded;
254 int index;
255 bool dirty = false; /* set when we may have created empty parameters. */
256
258
259 struct Parameter *np = NULL, *tmp = NULL;
260 const bool c_rfc2047_parameters = cs_subset_bool(NeoMutt->sub, "rfc2047_parameters");
261 const struct Slist *c_assumed_charset = cc_assumed_charset();
262 const char *c_charset = cc_charset();
263
264 TAILQ_FOREACH_SAFE(np, pl, entries, tmp)
265 {
266 s = strchr(np->attribute, '*');
267 if (!s)
268 {
269 /* Single value, non encoded:
270 * attr=value
271 */
272 /* Using RFC2047 encoding in MIME parameters is explicitly
273 * forbidden by that document. Nevertheless, it's being
274 * generated by some software, including certain Lotus Notes to
275 * Internet Gateways. So we actually decode it. */
276
277 if (c_rfc2047_parameters && np->value && strstr(np->value, "=?"))
278 {
279 rfc2047_decode(&np->value);
280 }
281 else if (!slist_is_empty(c_assumed_charset))
282 {
283 mutt_ch_convert_nonmime_string(c_assumed_charset, c_charset, &np->value);
284 }
285 }
286 else if (s[1] == '\0')
287 {
288 /* Single value with encoding:
289 * attr*=us-ascii''the%20value
290 */
291 s[0] = '\0';
292
293 s = get_charset(np->value, charset, sizeof(charset));
294 decode_one(np->value, s);
295 mutt_ch_convert_string(&np->value, charset, c_charset, MUTT_ICONV_HOOK_FROM);
297 dirty = true;
298 }
299 else
300 {
301 /* A parameter continuation, which may or may not be encoded:
302 * attr*0=value
303 * -or-
304 * attr*0*=us-ascii''the%20value
305 */
306 s[0] = '\0';
307 s++; /* let s point to the first character of index. */
308 for (t = s; (t[0] != '\0') && isdigit((unsigned char) t[0]); t++)
309 ; // do nothing
310
311 encoded = (t[0] == '*');
312 t[0] = '\0';
313
314 /* RFC2231 says that the index starts at 0 and increments by 1,
315 * thus an overflow should never occur in a valid message, thus
316 * the value INT_MAX in case of overflow does not really matter
317 * (the goal is just to avoid undefined behaviour). */
318 if (!mutt_str_atoi_full(s, &index))
319 index = INT_MAX;
320
321 conttmp = parameter_new();
322 conttmp->attribute = np->attribute;
323 conttmp->value = np->value;
324 conttmp->encoded = encoded;
325 conttmp->index = index;
326
327 np->attribute = NULL;
328 np->value = NULL;
329 TAILQ_REMOVE(pl, np, entries);
330 FREE(&np);
331
332 list_insert(&conthead, conttmp);
333 }
334 }
335
336 if (conthead)
337 {
338 join_continuations(pl, conthead);
339 dirty = true;
340 }
341
342 if (dirty)
344}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
const char * cc_charset(void)
Get the cached value of $charset.
Definition: config_cache.c:116
const struct Slist * cc_assumed_charset(void)
Get the cached value of $assumed_charset.
Definition: config_cache.c:101
int mutt_mb_filter_unprintable(char **s)
Replace unprintable characters.
Definition: mbyte.c:423
#define FREE(x)
Definition: memory.h:45
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:331
int mutt_ch_convert_string(char **ps, const char *from, const char *to, uint8_t flags)
Convert a string between encodings.
Definition: charset.c:831
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition: charset.h:73
bool slist_is_empty(const struct Slist *list)
Is the slist empty?
Definition: slist.c:142
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:735
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:841
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:662
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:86
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:109
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
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 355 of file rfc2231.c.

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