NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
serialize.c
Go to the documentation of this file.
1 
32 #include "config.h"
33 #include <stdbool.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include "mutt/lib.h"
37 #include "address/lib.h"
38 #include "config/lib.h"
39 #include "email/lib.h"
40 #include "core/lib.h"
41 #include "serialize.h"
42 
50 void lazy_realloc(void *ptr, size_t size)
51 {
52  void **p = (void **) ptr;
53 
54  if (p && (size < 4096))
55  return;
56 
57  mutt_mem_realloc(ptr, size);
58 }
59 
67 unsigned char *serial_dump_int(unsigned int i, unsigned char *d, int *off)
68 {
69  lazy_realloc(&d, *off + sizeof(int));
70  memcpy(d + *off, &i, sizeof(int));
71  (*off) += sizeof(int);
72 
73  return d;
74 }
75 
83 unsigned char *serial_dump_uint32_t(uint32_t s, unsigned char *d, int *off)
84 {
85  lazy_realloc(&d, *off + sizeof(uint32_t));
86  memcpy(d + *off, &s, sizeof(uint32_t));
87  (*off) += sizeof(uint32_t);
88 
89  return d;
90 }
91 
98 void serial_restore_int(unsigned int *i, const unsigned char *d, int *off)
99 {
100  memcpy(i, d + *off, sizeof(int));
101  (*off) += sizeof(int);
102 }
103 
110 void serial_restore_uint32_t(uint32_t *s, const unsigned char *d, int *off)
111 {
112  memcpy(s, d + *off, sizeof(uint32_t));
113  (*off) += sizeof(uint32_t);
114 }
115 
125 unsigned char *serial_dump_char_size(char *c, ssize_t size, unsigned char *d,
126  int *off, bool convert)
127 {
128  char *p = c;
129 
130  if (!c)
131  {
132  size = 0;
133  d = serial_dump_int(size, d, off);
134  return d;
135  }
136 
137  if (convert && !mutt_str_is_ascii(c, size))
138  {
139  p = mutt_strn_dup(c, size);
140  const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
141  if (mutt_ch_convert_string(&p, c_charset, "utf-8", MUTT_ICONV_NO_FLAGS) == 0)
142  {
143  size = mutt_str_len(p) + 1;
144  }
145  }
146 
147  d = serial_dump_int(size, d, off);
148  lazy_realloc(&d, *off + size);
149  memcpy(d + *off, p, size);
150  *off += size;
151 
152  if (p != c)
153  FREE(&p);
154 
155  return d;
156 }
157 
166 unsigned char *serial_dump_char(char *c, unsigned char *d, int *off, bool convert)
167 {
168  return serial_dump_char_size(c, mutt_str_len(c) + 1, d, off, convert);
169 }
170 
178 void serial_restore_char(char **c, const unsigned char *d, int *off, bool convert)
179 {
180  unsigned int size;
181  serial_restore_int(&size, d, off);
182 
183  if (size == 0)
184  {
185  *c = NULL;
186  return;
187  }
188 
189  *c = mutt_mem_malloc(size);
190  memcpy(*c, d + *off, size);
191  if (convert && !mutt_str_is_ascii(*c, size))
192  {
193  char *tmp = mutt_str_dup(*c);
194  const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
195  if (mutt_ch_convert_string(&tmp, "utf-8", c_charset, MUTT_ICONV_NO_FLAGS) == 0)
196  {
197  FREE(c);
198  *c = tmp;
199  }
200  else
201  {
202  FREE(&tmp);
203  }
204  }
205  *off += size;
206 }
207 
216 unsigned char *serial_dump_address(struct AddressList *al, unsigned char *d,
217  int *off, bool convert)
218 {
219  unsigned int counter = 0;
220  unsigned int start_off = *off;
221 
222  d = serial_dump_int(0xdeadbeef, d, off);
223 
224  struct Address *a = NULL;
225  TAILQ_FOREACH(a, al, entries)
226  {
227  d = serial_dump_char(a->personal, d, off, convert);
228  d = serial_dump_char(a->mailbox, d, off, false);
229  d = serial_dump_int(a->group, d, off);
230  counter++;
231  }
232 
233  memcpy(d + start_off, &counter, sizeof(int));
234 
235  return d;
236 }
237 
245 void serial_restore_address(struct AddressList *al, const unsigned char *d,
246  int *off, bool convert)
247 {
248  unsigned int counter = 0;
249  unsigned int g = 0;
250 
251  serial_restore_int(&counter, d, off);
252 
253  while (counter)
254  {
255  struct Address *a = mutt_addr_new();
256  serial_restore_char(&a->personal, d, off, convert);
257  serial_restore_char(&a->mailbox, d, off, false);
258  serial_restore_int(&g, d, off);
259  a->group = !!g;
260  mutt_addrlist_append(al, a);
261  counter--;
262  }
263 }
264 
273 unsigned char *serial_dump_stailq(struct ListHead *l, unsigned char *d, int *off, bool convert)
274 {
275  unsigned int counter = 0;
276  unsigned int start_off = *off;
277 
278  d = serial_dump_int(0xdeadbeef, d, off);
279 
280  struct ListNode *np = NULL;
281  STAILQ_FOREACH(np, l, entries)
282  {
283  d = serial_dump_char(np->data, d, off, convert);
284  counter++;
285  }
286 
287  memcpy(d + start_off, &counter, sizeof(int));
288 
289  return d;
290 }
291 
299 void serial_restore_stailq(struct ListHead *l, const unsigned char *d, int *off, bool convert)
300 {
301  unsigned int counter;
302 
303  serial_restore_int(&counter, d, off);
304 
305  struct ListNode *np = NULL;
306  while (counter)
307  {
308  np = mutt_list_insert_tail(l, NULL);
309  serial_restore_char(&np->data, d, off, convert);
310  counter--;
311  }
312 }
313 
322 unsigned char *serial_dump_buffer(struct Buffer *buf, unsigned char *d, int *off, bool convert)
323 {
324  if (!buf)
325  {
326  d = serial_dump_int(0, d, off);
327  return d;
328  }
329 
330  d = serial_dump_int(1, d, off);
331 
332  d = serial_dump_char_size(buf->data, buf->dsize + 1, d, off, convert);
333  d = serial_dump_int(buf->dptr - buf->data, d, off);
334  d = serial_dump_int(buf->dsize, d, off);
335 
336  return d;
337 }
338 
346 void serial_restore_buffer(struct Buffer *buf, const unsigned char *d, int *off, bool convert)
347 {
348  unsigned int used;
349  unsigned int offset;
350  serial_restore_int(&used, d, off);
351  if (!used)
352  {
353  return;
354  }
355 
356  serial_restore_char(&buf->data, d, off, convert);
357  serial_restore_int(&offset, d, off);
358  mutt_buffer_seek(buf, offset);
359  serial_restore_int(&used, d, off);
360  buf->dsize = used;
361 }
362 
371 unsigned char *serial_dump_parameter(struct ParameterList *pl, unsigned char *d,
372  int *off, bool convert)
373 {
374  unsigned int counter = 0;
375  unsigned int start_off = *off;
376 
377  d = serial_dump_int(0xdeadbeef, d, off);
378 
379  struct Parameter *np = NULL;
380  TAILQ_FOREACH(np, pl, entries)
381  {
382  d = serial_dump_char(np->attribute, d, off, false);
383  d = serial_dump_char(np->value, d, off, convert);
384  counter++;
385  }
386 
387  memcpy(d + start_off, &counter, sizeof(int));
388 
389  return d;
390 }
391 
399 void serial_restore_parameter(struct ParameterList *pl, const unsigned char *d,
400  int *off, bool convert)
401 {
402  unsigned int counter;
403 
404  serial_restore_int(&counter, d, off);
405 
406  struct Parameter *np = NULL;
407  while (counter)
408  {
409  np = mutt_param_new();
410  serial_restore_char(&np->attribute, d, off, false);
411  serial_restore_char(&np->value, d, off, convert);
412  TAILQ_INSERT_TAIL(pl, np, entries);
413  counter--;
414  }
415 }
416 
425 unsigned char *serial_dump_body(struct Body *c, unsigned char *d, int *off, bool convert)
426 {
427  struct Body nb;
428 
429  memcpy(&nb, c, sizeof(struct Body));
430 
431  /* some fields are not safe to cache */
432  nb.content = NULL;
433  nb.charset = NULL;
434  nb.next = NULL;
435  nb.parts = NULL;
436  nb.email = NULL;
437  nb.aptr = NULL;
438  nb.mime_headers = NULL;
439  nb.language = NULL;
440 
441  lazy_realloc(&d, *off + sizeof(struct Body));
442  memcpy(d + *off, &nb, sizeof(struct Body));
443  *off += sizeof(struct Body);
444 
445  d = serial_dump_char(nb.xtype, d, off, false);
446  d = serial_dump_char(nb.subtype, d, off, false);
447 
448  d = serial_dump_parameter(&nb.parameter, d, off, convert);
449 
450  d = serial_dump_char(nb.description, d, off, convert);
451  d = serial_dump_char(nb.form_name, d, off, convert);
452  d = serial_dump_char(nb.filename, d, off, convert);
453  d = serial_dump_char(nb.d_filename, d, off, convert);
454 
455  return d;
456 }
457 
465 void serial_restore_body(struct Body *c, const unsigned char *d, int *off, bool convert)
466 {
467  memcpy(c, d + *off, sizeof(struct Body));
468  *off += sizeof(struct Body);
469  c->language = NULL;
470 
471  serial_restore_char(&c->xtype, d, off, false);
472  serial_restore_char(&c->subtype, d, off, false);
473 
474  TAILQ_INIT(&c->parameter);
475  serial_restore_parameter(&c->parameter, d, off, convert);
476 
477  serial_restore_char(&c->description, d, off, convert);
478  serial_restore_char(&c->form_name, d, off, convert);
479  serial_restore_char(&c->filename, d, off, convert);
480  serial_restore_char(&c->d_filename, d, off, convert);
481 }
482 
491 unsigned char *serial_dump_envelope(struct Envelope *env, unsigned char *d,
492  int *off, bool convert)
493 {
494  d = serial_dump_address(&env->return_path, d, off, convert);
495  d = serial_dump_address(&env->from, d, off, convert);
496  d = serial_dump_address(&env->to, d, off, convert);
497  d = serial_dump_address(&env->cc, d, off, convert);
498  d = serial_dump_address(&env->bcc, d, off, convert);
499  d = serial_dump_address(&env->sender, d, off, convert);
500  d = serial_dump_address(&env->reply_to, d, off, convert);
501  d = serial_dump_address(&env->mail_followup_to, d, off, convert);
502 
503  d = serial_dump_char(env->list_post, d, off, convert);
504  d = serial_dump_char(env->subject, d, off, convert);
505 
506  if (env->real_subj)
507  d = serial_dump_int(env->real_subj - env->subject, d, off);
508  else
509  d = serial_dump_int(-1, d, off);
510 
511  d = serial_dump_char(env->message_id, d, off, false);
512  d = serial_dump_char(env->supersedes, d, off, false);
513  d = serial_dump_char(env->date, d, off, false);
514  d = serial_dump_char(env->x_label, d, off, convert);
515  d = serial_dump_char(env->organization, d, off, convert);
516 
517  d = serial_dump_buffer(&env->spam, d, off, convert);
518 
519  d = serial_dump_stailq(&env->references, d, off, false);
520  d = serial_dump_stailq(&env->in_reply_to, d, off, false);
521  d = serial_dump_stailq(&env->userhdrs, d, off, convert);
522 
523 #ifdef USE_NNTP
524  d = serial_dump_char(env->xref, d, off, false);
525  d = serial_dump_char(env->followup_to, d, off, false);
526  d = serial_dump_char(env->x_comment_to, d, off, convert);
527 #endif
528 
529  return d;
530 }
531 
539 void serial_restore_envelope(struct Envelope *env, const unsigned char *d, int *off, bool convert)
540 {
541  int real_subj_off;
542 
543  serial_restore_address(&env->return_path, d, off, convert);
544  serial_restore_address(&env->from, d, off, convert);
545  serial_restore_address(&env->to, d, off, convert);
546  serial_restore_address(&env->cc, d, off, convert);
547  serial_restore_address(&env->bcc, d, off, convert);
548  serial_restore_address(&env->sender, d, off, convert);
549  serial_restore_address(&env->reply_to, d, off, convert);
550  serial_restore_address(&env->mail_followup_to, d, off, convert);
551 
552  serial_restore_char(&env->list_post, d, off, convert);
553 
554  const bool c_auto_subscribe = cs_subset_bool(NeoMutt->sub, "auto_subscribe");
555  if (c_auto_subscribe)
557 
558  serial_restore_char(&env->subject, d, off, convert);
559  serial_restore_int((unsigned int *) (&real_subj_off), d, off);
560 
561  if (real_subj_off >= 0)
562  env->real_subj = env->subject + real_subj_off;
563  else
564  env->real_subj = NULL;
565 
566  serial_restore_char(&env->message_id, d, off, false);
567  serial_restore_char(&env->supersedes, d, off, false);
568  serial_restore_char(&env->date, d, off, false);
569  serial_restore_char(&env->x_label, d, off, convert);
570  serial_restore_char(&env->organization, d, off, convert);
571 
572  serial_restore_buffer(&env->spam, d, off, convert);
573 
574  serial_restore_stailq(&env->references, d, off, false);
575  serial_restore_stailq(&env->in_reply_to, d, off, false);
576  serial_restore_stailq(&env->userhdrs, d, off, convert);
577 
578 #ifdef USE_NNTP
579  serial_restore_char(&env->xref, d, off, false);
580  serial_restore_char(&env->followup_to, d, off, false);
581  serial_restore_char(&env->x_comment_to, d, off, convert);
582 #endif
583 }
584 
592 unsigned char *serial_dump_tags(const struct TagList *tags, unsigned char *d, int *off)
593 {
594  unsigned int counter = 0;
595  unsigned int start_off = *off;
596 
597  d = serial_dump_int(0xdeadbeef, d, off);
598 
599  struct Tag *t = NULL;
600  STAILQ_FOREACH(t, tags, entries)
601  {
602  d = serial_dump_char(t->name, d, off, false);
603  counter++;
604  }
605 
606  memcpy(d + start_off, &counter, sizeof(int));
607 
608  return d;
609 }
610 
617 void serial_restore_tags(struct TagList *tags, const unsigned char *d, int *off)
618 {
619  unsigned int counter = 0;
620 
621  serial_restore_int(&counter, d, off);
622 
623  while (counter)
624  {
625  char *name = NULL;
626  serial_restore_char(&name, d, off, false);
627  driver_tags_add(tags, name);
628  counter--;
629  }
630 }
char * attribute
Parameter name.
Definition: parameter.h:34
void serial_restore_parameter(struct ParameterList *pl, const unsigned char *d, int *off, bool convert)
Unpack a Parameter from a binary blob.
Definition: serialize.c:399
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:63
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
struct Content * content
Detailed info about the content of the attachment.
Definition: body.h:51
struct AddressList mail_followup_to
Email&#39;s &#39;mail-followup-to&#39;.
Definition: envelope.h:63
void driver_tags_add(struct TagList *list, char *new_tag)
Add a tag to header.
Definition: tags.c:81
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
Structs that make up an email.
struct AddressList reply_to
Email&#39;s &#39;reply-to&#39;.
Definition: envelope.h:62
char * supersedes
Supersedes header.
Definition: envelope.h:70
struct AddressList bcc
Email&#39;s &#39;Bcc&#39; list.
Definition: envelope.h:60
struct Parameter * mutt_param_new(void)
Create a new Parameter.
Definition: parameter.c:39
char * xref
List of cross-references.
Definition: envelope.h:76
char * date
Sent date.
Definition: envelope.h:71
LinkedList Tag Element.
Definition: tags.h:37
void serial_restore_body(struct Body *c, const unsigned char *d, int *off, bool convert)
Unpack a Body from a binary blob.
Definition: serialize.c:465
char * name
Tag name.
Definition: tags.h:39
unsigned char * serial_dump_envelope(struct Envelope *env, unsigned char *d, int *off, bool convert)
Pack an Envelope into a binary blob.
Definition: serialize.c:491
unsigned char * serial_dump_address(struct AddressList *al, unsigned char *d, int *off, bool convert)
Pack an Address into a binary blob.
Definition: serialize.c:216
void serial_restore_char(char **c, const unsigned char *d, int *off, bool convert)
Unpack a variable-length string from a binary blob.
Definition: serialize.c:178
String manipulation buffer.
Definition: buffer.h:33
unsigned char * serial_dump_uint32_t(uint32_t s, unsigned char *d, int *off)
Pack a uint32_t into a binary blob.
Definition: serialize.c:83
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
unsigned char * serial_dump_buffer(struct Buffer *buf, unsigned char *d, int *off, bool convert)
Pack a Buffer into a binary blob.
Definition: serialize.c:322
struct ListHead userhdrs
user defined headers
Definition: envelope.h:83
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:385
char * real_subj
Offset of the real subject.
Definition: envelope.h:67
struct Body * next
next attachment in the list
Definition: body.h:53
int mutt_ch_convert_string(char **ps, const char *from, const char *to, uint8_t flags)
Convert a string between encodings.
Definition: charset.c:758
An email address.
Definition: address.h:35
void serial_restore_int(unsigned int *i, const unsigned char *d, int *off)
Unpack an integer from a binary blob.
Definition: serialize.c:98
char * mailbox
Mailbox and host address.
Definition: address.h:38
#define MUTT_ICONV_NO_FLAGS
No flags are set.
Definition: charset.h:71
char * form_name
Content-Disposition form-data name param.
Definition: body.h:41
Container for Accounts, Notifications.
Definition: neomutt.h:36
The body of an email.
Definition: body.h:34
Convenience wrapper for the config headers.
void serial_restore_uint32_t(uint32_t *s, const unsigned char *d, int *off)
Unpack an uint32_t from a binary blob.
Definition: serialize.c:110
Email Address Handling.
size_t dsize
Length of data.
Definition: buffer.h:37
void serial_restore_buffer(struct Buffer *buf, const unsigned char *d, int *off, bool convert)
Unpack a Buffer from a binary blob.
Definition: serialize.c:346
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:82
char * message_id
Message ID.
Definition: envelope.h:69
unsigned char * serial_dump_stailq(struct ListHead *l, unsigned char *d, int *off, bool convert)
Pack a STAILQ into a binary blob.
Definition: serialize.c:273
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:548
Convenience wrapper for the core headers.
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
#define TAILQ_INIT(head)
Definition: queue.h:765
Email-object serialiser.
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
char * subtype
content-type subtype
Definition: body.h:37
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
char * x_comment_to
List of &#39;X-comment-to&#39; fields.
Definition: envelope.h:78
bool mutt_str_is_ascii(const char *str, size_t len)
Is a string ASCII (7-bit)?
Definition: string.c:981
unsigned char * serial_dump_int(unsigned int i, unsigned char *d, int *off)
Pack an integer into a binary blob.
Definition: serialize.c:67
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
struct AttachPtr * aptr
Menu information, used in recvattach.c.
Definition: body.h:57
char * dptr
Current read/write position.
Definition: buffer.h:36
char * data
Pointer to data.
Definition: buffer.h:35
char * xtype
content-type if x-unknown
Definition: body.h:36
void serial_restore_address(struct AddressList *al, const unsigned char *d, int *off, bool convert)
Unpack an Address from a binary blob.
Definition: serialize.c:245
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
char * charset
Send mode: charset of attached file as stored on disk.
Definition: body.h:49
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
unsigned char * serial_dump_char_size(char *c, ssize_t size, unsigned char *d, int *off, bool convert)
Pack a fixed-length string into a binary blob.
Definition: serialize.c:125
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:809
unsigned char * serial_dump_char(char *c, unsigned char *d, int *off, bool convert)
Pack a variable-length string into a binary blob.
Definition: serialize.c:166
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
char * description
content-description
Definition: body.h:40
char * list_post
This stores a mailto URL, or nothing.
Definition: envelope.h:65
char * personal
Real name of address.
Definition: address.h:37
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:664
char * data
String.
Definition: list.h:36
char * subject
Email&#39;s subject.
Definition: envelope.h:66
char * value
Parameter value.
Definition: parameter.h:35
struct AddressList return_path
Return path for the Email.
Definition: envelope.h:56
bool group
Group mailbox?
Definition: address.h:39
void serial_restore_tags(struct TagList *tags, const unsigned char *d, int *off)
Unpack a TagList from a binary blob.
Definition: serialize.c:617
char * followup_to
List of &#39;followup-to&#39; fields.
Definition: envelope.h:77
void lazy_realloc(void *ptr, size_t size)
Reallocate some memory.
Definition: serialize.c:50
void serial_restore_stailq(struct ListHead *l, const unsigned char *d, int *off, bool convert)
Unpack a STAILQ from a binary blob.
Definition: serialize.c:299
Attribute associated with a MIME part.
Definition: parameter.h:32
unsigned char * serial_dump_tags(const struct TagList *tags, unsigned char *d, int *off)
Pack a TagList into a binary blob.
Definition: serialize.c:592
#define FREE(x)
Definition: memory.h:40
char * organization
Organisation header.
Definition: envelope.h:73
char * language
content-language (RFC8255)
Definition: body.h:38
unsigned char * serial_dump_body(struct Body *c, unsigned char *d, int *off, bool convert)
Pack an Body into a binary blob.
Definition: serialize.c:425
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
struct AddressList sender
Email&#39;s sender.
Definition: envelope.h:61
char * d_filename
filename to be used for the content-disposition header.
Definition: body.h:47
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
void mutt_buffer_seek(struct Buffer *buf, size_t offset)
set current read/write position to offset from beginning
Definition: buffer.c:466
Convenience wrapper for the library headers.
struct ListHead references
message references (in reverse order)
Definition: envelope.h:81
A List node for strings.
Definition: list.h:34
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
unsigned char * serial_dump_parameter(struct ParameterList *pl, unsigned char *d, int *off, bool convert)
Pack a Parameter into a binary blob.
Definition: serialize.c:371
char * x_label
X-Label.
Definition: envelope.h:72
struct Email * email
header information for message/rfc822
Definition: body.h:55
void serial_restore_envelope(struct Envelope *env, const unsigned char *d, int *off, bool convert)
Unpack an Envelope from a binary blob.
Definition: serialize.c:539
The header of an Email.
Definition: envelope.h:54
struct Buffer spam
Spam header.
Definition: envelope.h:80
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1490
void mutt_auto_subscribe(const char *mailto)
Check if user is subscribed to mailing list.
Definition: parse.c:69