NeoMutt  2023-05-17-33-gce4425
Teaching an old dog new tricks
DOXYGEN
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. More...
 
size_t rfc2231_encode_string (struct ParameterList *head, const char *attribute, char *value)
 Encode a string to be suitable for an RFC2231 header. More...
 

Detailed Description

RFC2231 MIME Charset routines.

Authors
  • 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 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 238 of file rfc2231.c.

239{
240 if (!pl)
241 return;
242
243 struct Rfc2231Parameter *conthead = NULL;
244 struct Rfc2231Parameter *conttmp = NULL;
245
246 char *s = NULL, *t = NULL;
247 char charset[256] = { 0 };
248
249 bool encoded;
250 int index;
251 bool dirty = false; /* set when we may have created empty parameters. */
252
254
255 struct Parameter *np = NULL, *tmp = NULL;
256 const bool c_rfc2047_parameters = cs_subset_bool(NeoMutt->sub, "rfc2047_parameters");
257 const struct Slist *c_assumed_charset = cc_assumed_charset();
258 const char *c_charset = cc_charset();
259
260 TAILQ_FOREACH_SAFE(np, pl, entries, tmp)
261 {
262 s = strchr(np->attribute, '*');
263 if (!s)
264 {
265 /* Single value, non encoded:
266 * attr=value
267 */
268 /* Using RFC2047 encoding in MIME parameters is explicitly
269 * forbidden by that document. Nevertheless, it's being
270 * generated by some software, including certain Lotus Notes to
271 * Internet Gateways. So we actually decode it. */
272
273 if (c_rfc2047_parameters && np->value && strstr(np->value, "=?"))
274 {
275 rfc2047_decode(&np->value);
276 }
277 else if (!slist_is_empty(c_assumed_charset))
278 {
279 mutt_ch_convert_nonmime_string(c_assumed_charset, c_charset, &np->value);
280 }
281 }
282 else if (s[1] == '\0')
283 {
284 /* Single value with encoding:
285 * attr*=us-ascii''the%20value
286 */
287 s[0] = '\0';
288
289 s = get_charset(np->value, charset, sizeof(charset));
290 decode_one(np->value, s);
291 mutt_ch_convert_string(&np->value, charset, c_charset, MUTT_ICONV_HOOK_FROM);
293 dirty = true;
294 }
295 else
296 {
297 /* A parameter continuation, which may or may not be encoded:
298 * attr*0=value
299 * -or-
300 * attr*0*=us-ascii''the%20value
301 */
302 s[0] = '\0';
303 s++; /* let s point to the first character of index. */
304 for (t = s; (t[0] != '\0') && isdigit((unsigned char) t[0]); t++)
305 ; // do nothing
306
307 encoded = (t[0] == '*');
308 t[0] = '\0';
309
310 /* RFC2231 says that the index starts at 0 and increments by 1,
311 * thus an overflow should never occur in a valid message, thus
312 * the value INT_MAX in case of overflow does not really matter
313 * (the goal is just to avoid undefined behaviour). */
314 if (!mutt_str_atoi_full(s, &index))
315 index = INT_MAX;
316
317 conttmp = parameter_new();
318 conttmp->attribute = np->attribute;
319 conttmp->value = np->value;
320 conttmp->encoded = encoded;
321 conttmp->index = index;
322
323 np->attribute = NULL;
324 np->value = NULL;
325 TAILQ_REMOVE(pl, np, entries);
326 FREE(&np);
327
328 list_insert(&conthead, conttmp);
329 }
330 }
331
332 if (conthead)
333 {
334 join_continuations(pl, conthead);
335 dirty = true;
336 }
337
338 if (dirty)
340}
const char * cc_charset(void)
Get the cached value of $charset.
Definition: cache.c:106
const struct Slist * cc_assumed_charset(void)
Get the cached value of $assumed_charset.
Definition: cache.c:91
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
int mutt_mb_filter_unprintable(char **s)
Replace unprintable characters.
Definition: mbyte.c:423
#define FREE(x)
Definition: memory.h:43
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:324
int mutt_ch_convert_string(char **ps, const char *from, const char *to, uint8_t flags)
Convert a string between encodings.
Definition: charset.c:822
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition: charset.h:72
bool slist_is_empty(const struct Slist *list)
Is the slist empty?
Definition: slist.c:176
#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:656
static void purge_empty_parameters(struct ParameterList *pl)
Remove any ill-formed Parameters from a list.
Definition: rfc2231.c:64
static void join_continuations(struct ParameterList *pl, struct Rfc2231Parameter *par)
Process continuation parameters.
Definition: rfc2231.c:183
static char * get_charset(char *value, char *charset, size_t chslen)
Get the charset from an RFC2231 header.
Definition: rfc2231.c:84
static void list_insert(struct Rfc2231Parameter **list, struct Rfc2231Parameter *par)
Insert parameter into an ordered list.
Definition: rfc2231.c:145
static struct Rfc2231Parameter * parameter_new(void)
Create a new Rfc2231Parameter.
Definition: rfc2231.c:132
static void decode_one(char *dest, char *src)
Decode one percent-encoded character.
Definition: rfc2231.c:107
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
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:52
bool encoded
Is the value encoded?
Definition: rfc2231.c:56
int index
Index number in the list.
Definition: rfc2231.c:55
char * value
Attribute value.
Definition: rfc2231.c:54
char * attribute
Attribute name.
Definition: rfc2231.c:53
String list.
Definition: slist.h:47
+ 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 351 of file rfc2231.c.

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