Replace use of Sequoia's backend with a custom key store.
- Sequoia's key store doesn't meet pep's needs (in particular, the
ability to search on a key's user id) and trying to shoehorn pep's
needs onto Sequoia's key store abstractions is just introducing
overhead with no appreciable gain in functionality.
- This patch changes the Sequoia backend to use a local sqlite
database to store the public keys.
1 // This file is under GNU General Public License 3.0
4 #include "etpan_mime.h"
5 #ifndef mailmime_param_new_with_data
6 #include <libetpan/mailprivacy_tools.h>
16 #define MAX_MESSAGE_ID 128
18 static char * generate_boundary(void)
20 char id[MAX_MESSAGE_ID];
22 // no cryptographically strong random needed here
23 const long value1 = random();
24 const long value2 = random();
25 const long value3 = random();
26 const long value4 = random();
28 snprintf(id, MAX_MESSAGE_ID, "%.4lx%.4lx%.4lx%.4lx", value1, value2,
34 struct mailmime * part_new_empty(
35 struct mailmime_content * content,
36 struct mailmime_fields * mime_fields,
40 struct mailmime * build_info;
44 char * attr_name = NULL;
45 char * attr_value = NULL;
46 struct mailmime_parameter * param = NULL;
47 clist * parameters = NULL;
48 char *boundary = NULL;
53 mime_type = MAILMIME_SINGLE;
56 switch (content->ct_type->tp_type) {
57 case MAILMIME_TYPE_DISCRETE_TYPE:
58 mime_type = MAILMIME_SINGLE;
61 case MAILMIME_TYPE_COMPOSITE_TYPE:
62 switch (content->ct_type->tp_data.tp_composite_type->ct_type) {
63 case MAILMIME_COMPOSITE_TYPE_MULTIPART:
64 mime_type = MAILMIME_MULTIPLE;
67 case MAILMIME_COMPOSITE_TYPE_MESSAGE:
68 if (strcasecmp(content->ct_subtype, "rfc822") == 0)
69 mime_type = MAILMIME_MESSAGE;
71 mime_type = MAILMIME_SINGLE;
84 if (mime_type == MAILMIME_MULTIPLE) {
90 attr_name = strdup("boundary");
92 if (attr_name == NULL)
95 boundary = generate_boundary();
97 attr_value = boundary;
98 if (attr_value == NULL)
101 param = mailmime_parameter_new(attr_name, attr_value);
108 if (content->ct_parameters == NULL) {
109 parameters = clist_new();
111 if (parameters == NULL)
115 parameters = content->ct_parameters;
118 r = clist_append(parameters, param);
123 if (content->ct_parameters == NULL)
124 content->ct_parameters = parameters;
127 build_info = mailmime_new(mime_type, NULL, 0, mime_fields, content, NULL,
128 NULL, NULL, list, NULL, NULL);
129 if (build_info == NULL)
139 if (content->ct_parameters == NULL)
141 clist_free(parameters);
143 mailmime_parameter_free(param);
147 struct mailmime * get_pgp_encrypted_part(void)
149 struct mailmime * mime = NULL;
150 struct mailmime_fields * mime_fields = NULL;
151 struct mailmime_content * content = NULL;
154 content = mailmime_content_new_with_str("application/pgp-encrypted");
158 mime_fields = mailmime_fields_new_empty();
159 if (mime_fields == NULL)
162 mime = part_new_empty(content, mime_fields, 1);
168 r = mailmime_set_body_text(mime, "Version: 1\n", 10);
176 mailmime_content_free(content);
178 mailmime_fields_free(mime_fields);
185 struct mailmime * get_text_part(
186 pEp_rid_list_t* resource,
187 const char * mime_type,
193 char * disposition_name = NULL;
194 struct mailmime_fields * mime_fields = NULL;
195 struct mailmime * mime = NULL;
196 struct mailmime_content * content = NULL;
197 struct mailmime_parameter * param = NULL;
198 struct mailmime_disposition * disposition = NULL;
199 struct mailmime_mechanism * encoding = NULL;
200 char* content_id = NULL;
203 if (resource != NULL && resource->rid != NULL) {
204 switch (resource->rid_type) {
206 content_id = strdup(resource->rid);
208 case PEP_RID_FILENAME:
210 disposition_name = strdup(resource->rid);
211 if (disposition_name == NULL)
215 mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
216 disposition_name, NULL, NULL, NULL, (size_t) -1);
218 if (disposition == NULL)
221 disposition_name = NULL;
227 encoding = mailmime_mechanism_new(encoding_type, NULL);
228 if (encoding == NULL)
232 mime_fields = mailmime_fields_new_with_data(encoding, content_id, NULL,
234 if (mime_fields == NULL)
240 content = mailmime_content_new_with_str(mime_type);
244 if (encoding_type != MAILMIME_MECHANISM_7BIT) {
245 param = mailmime_param_new_with_data("charset", "utf-8");
246 r = clist_append(content->ct_parameters, param);
251 mime = part_new_empty(content, mime_fields, 1);
258 r = mailmime_set_body_text(mime, (char *) text, length);
266 free(disposition_name);
268 mailmime_fields_free(mime_fields);
272 mailmime_content_free(content);
274 mailmime_parameter_free(param);
276 mailmime_disposition_free(disposition);
278 mailmime_mechanism_free(encoding);
283 struct mailmime * get_file_part(
284 pEp_rid_list_t* resource,
285 const char * mime_type,
288 bool transport_encode
291 char * disposition_name = NULL;
293 struct mailmime_disposition * disposition = NULL;
294 struct mailmime_mechanism * encoding = NULL;
295 struct mailmime_content * content = NULL;
296 struct mailmime * mime = NULL;
297 struct mailmime_fields * mime_fields = NULL;
298 char* content_id = NULL;
301 if (resource != NULL && resource->rid != NULL) {
302 switch (resource->rid_type) {
304 content_id = strdup(resource->rid);
306 mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
307 NULL, NULL, NULL, NULL, (size_t) -1);
308 if (disposition == NULL)
311 case PEP_RID_FILENAME:
313 disposition_name = strdup(resource->rid);
314 if (disposition_name == NULL)
318 mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_ATTACHMENT,
319 disposition_name, NULL, NULL, NULL, (size_t) -1);
321 if (disposition == NULL)
323 disposition_name = NULL;
330 content = mailmime_content_new_with_str(mime_type);
336 if (transport_encode) {
337 encoding_type = MAILMIME_MECHANISM_BASE64;
338 encoding = mailmime_mechanism_new(encoding_type, NULL);
339 if (encoding == NULL)
343 mime_fields = mailmime_fields_new_with_data(encoding, content_id, NULL,
345 if (mime_fields == NULL)
350 mime = part_new_empty(content, mime_fields, 1);
358 r = mailmime_set_body_text(mime, data, length);
366 free(disposition_name);
368 mailmime_disposition_free(disposition);
370 mailmime_mechanism_free(encoding);
372 mailmime_content_free(content);
374 mailmime_fields_free(mime_fields);
381 struct mailmime * part_multiple_new(const char *type)
383 struct mailmime_fields *mime_fields = NULL;
384 struct mailmime_content *content = NULL;
385 struct mailmime *mp = NULL;
387 mime_fields = mailmime_fields_new_empty();
388 if (mime_fields == NULL)
391 content = mailmime_content_new_with_str(type);
395 mp = part_new_empty(content, mime_fields, 0);
403 mailmime_content_free(content);
405 mailmime_fields_free(mime_fields);
410 struct mailimf_field * _new_field(
412 _new_func_t new_func,
416 void *data = new_func(value);
421 struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
423 if (result == NULL) {
428 result->fld_type = type;
429 result->fld_data.fld_return_path = data;
434 void _free_field(struct mailimf_field *field)
437 free(field->fld_data.fld_return_path);
444 _new_func_t new_func,
449 struct mailimf_field * field;
455 field = _new_field(type, new_func, value);
459 r = clist_append(list, field);
466 // http://media2.giga.de/2014/02/Image-28.jpg
468 struct mailimf_date_time * timestamp_to_etpantime(const struct tm *ts)
470 struct mailimf_date_time * result = calloc(1,
471 sizeof(struct mailimf_date_time));
478 result->dt_sec = ts->tm_sec;
479 result->dt_min = ts->tm_min;
480 result->dt_hour = ts->tm_hour;
481 result->dt_day = ts->tm_mday;
482 result->dt_month = ts->tm_mon + 1;
483 result->dt_year = ts->tm_year + 1900;
485 result->dt_zone = (int) (ts->tm_gmtoff / 36L);
490 struct tm * etpantime_to_timestamp(const struct mailimf_date_time *et)
492 struct tm * result = calloc(1, sizeof(struct tm));
499 result->tm_sec = et->dt_sec;
500 result->tm_min = et->dt_min;
501 result->tm_hour = et->dt_hour;
502 result->tm_mday = et->dt_day;
503 result->tm_mon = et->dt_month - 1;
504 result->tm_year = et->dt_year - 1900;
506 result->tm_gmtoff = 36L * (long) et->dt_zone;
511 struct mailimf_mailbox * mailbox_from_string(
516 struct mailimf_mailbox *mb = NULL;
518 char *_address = NULL;
522 _name = name ? strdup(name) : strdup("");
526 _address = strdup(address);
527 if (_address == NULL)
530 mb = mailimf_mailbox_new(_name, _address);
545 struct mailimf_field * create_optional_field(
552 struct mailimf_optional_field *optional_field = NULL;
554 _field = strdup(field);
558 if (!must_field_value_be_encoded(value))
559 _value = strdup(value);
561 _value = mailmime_encode_subject_header("utf-8", value, 0);
565 optional_field = mailimf_optional_field_new(_field, _value);
566 if (optional_field == NULL)
569 struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
574 result->fld_type = MAILIMF_FIELD_OPTIONAL_FIELD;
575 result->fld_data.fld_optional_field = optional_field;
580 if (optional_field) {
581 mailimf_optional_field_free(optional_field);
591 int _append_optional_field(
598 struct mailimf_field * optional_field =
599 create_optional_field(field, value);
601 if (optional_field == NULL)
604 r = clist_append(list, optional_field);
606 mailimf_field_free(optional_field);
611 clist * _get_fields(struct mailmime * mime)
613 clist * _fieldlist = NULL;
617 if (mime->mm_data.mm_message.mm_fields &&
618 mime->mm_data.mm_message.mm_fields->fld_list) {
619 _fieldlist = mime->mm_data.mm_message.mm_fields->fld_list;
625 struct mailmime_content * _get_content(struct mailmime * mime)
627 struct mailmime_content * content = NULL;
631 if (mime->mm_data.mm_message.mm_msg_mime)
632 content = mime->mm_data.mm_message.mm_msg_mime->mm_content_type;
638 /* Return a list of identifier_type and resource id (filename, cid, etc) */
639 pEp_rid_list_t* _get_resource_id_list(struct mailmime *mime)
641 clist * _fieldlist = NULL;
645 if (mime->mm_mime_fields && mime->mm_mime_fields->fld_list)
646 _fieldlist = mime->mm_mime_fields->fld_list;
652 pEp_rid_list_t* rid_list = NULL;
653 pEp_rid_list_t** rid_list_curr_p = &rid_list;
655 for (cur = clist_begin(_fieldlist); cur; cur = clist_next(cur)) {
656 struct mailmime_field * _field = clist_content(cur);
658 if (_field && _field->fld_type == MAILMIME_FIELD_ID) {
659 pEp_rid_list_t* new_rid = (pEp_rid_list_t*)calloc(1, sizeof(pEp_rid_list_t));
660 new_rid->rid_type = PEP_RID_CID;
661 new_rid->rid = strdup(_field->fld_data.fld_id);
662 *rid_list_curr_p = new_rid;
663 rid_list_curr_p = &new_rid->next;
665 else if (_field && _field->fld_type == MAILMIME_FIELD_DISPOSITION) {
667 if (_field->fld_data.fld_disposition &&
668 _field->fld_data.fld_disposition->dsp_parms) {
670 _field->fld_data.fld_disposition->dsp_parms;
672 for (cur2 = clist_begin(_parmlist); cur2; cur2 =
674 struct mailmime_disposition_parm * param =
676 if (param->pa_type == MAILMIME_DISPOSITION_PARM_FILENAME) {
677 pEp_rid_list_t* new_rid = (pEp_rid_list_t*)calloc(1, sizeof(pEp_rid_list_t));
678 new_rid->rid_type = PEP_RID_FILENAME;
679 new_rid->rid = strdup(param->pa_data.pa_filename);
680 *rid_list_curr_p = new_rid;
681 rid_list_curr_p = &new_rid->next;
687 /* Will almost certainly usually be a singleton, but we need to be able to decide */
692 /* FIXME: about to be obsoleted? */
693 char * _get_filename_or_cid(struct mailmime *mime)
695 clist * _fieldlist = NULL;
699 if (mime->mm_mime_fields && mime->mm_mime_fields->fld_list)
700 _fieldlist = mime->mm_mime_fields->fld_list;
706 char* _temp_filename_ptr = NULL;
708 for (cur = clist_begin(_fieldlist); cur; cur = clist_next(cur)) {
709 struct mailmime_field * _field = clist_content(cur);
710 if (_field && _field->fld_type == MAILMIME_FIELD_ID) {
711 /* We prefer CIDs to filenames when both are present */
712 free(_temp_filename_ptr); /* can be null, it's ok */
713 return build_uri("cid", _field->fld_data.fld_id);
715 else if (_field && _field->fld_type == MAILMIME_FIELD_DISPOSITION) {
716 if (_field->fld_data.fld_disposition &&
717 _field->fld_data.fld_disposition->dsp_parms &&
718 !_temp_filename_ptr) {
720 _field->fld_data.fld_disposition->dsp_parms;
722 for (cur2 = clist_begin(_parmlist); cur2; cur2 =
724 struct mailmime_disposition_parm * param =
726 if (param->pa_type == MAILMIME_DISPOSITION_PARM_FILENAME) {
727 _temp_filename_ptr = build_uri("file", param->pa_data.pa_filename);
734 /* Ok, it wasn't a CID */
735 return _temp_filename_ptr;
738 static bool parameter_has_value(
739 struct mailmime_content *content,
749 clist * list = content->ct_parameters;
753 for (cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
754 struct mailmime_parameter * param = clist_content(cur);
756 param->pa_name && strcasecmp(name, param->pa_name) == 0 &&
757 param->pa_value && strcasecmp(value, param->pa_value) == 0)
764 bool _is_multipart(struct mailmime_content *content, const char *subtype)
768 if (content->ct_type && content->ct_type->tp_type ==
769 MAILMIME_TYPE_COMPOSITE_TYPE &&
770 content->ct_type->tp_data.tp_composite_type &&
771 content->ct_type->tp_data.tp_composite_type->ct_type ==
772 MAILMIME_COMPOSITE_TYPE_MULTIPART) {
774 return content->ct_subtype &&
775 strcasecmp(content->ct_subtype, subtype) == 0;
783 bool _is_PGP_MIME(struct mailmime_content *content)
787 if (_is_multipart(content, "encrypted") &&
788 parameter_has_value(content, "protocol",
789 "application/pgp-encrypted"))
795 bool _is_text_part(struct mailmime_content *content, const char *subtype)
799 if (content->ct_type && content->ct_type->tp_type ==
800 MAILMIME_TYPE_DISCRETE_TYPE &&
801 content->ct_type->tp_data.tp_discrete_type &&
802 content->ct_type->tp_data.tp_discrete_type->dt_type ==
803 MAILMIME_DISCRETE_TYPE_TEXT) {
805 return content->ct_subtype &&
806 strcasecmp(content->ct_subtype, subtype) == 0;
814 int _get_content_type(
815 const struct mailmime_content *content,
821 char *_charset = NULL;
830 if (content->ct_subtype == NULL)
833 if (content->ct_type && content->ct_type->tp_data.tp_discrete_type) {
835 const char *_main_type;
837 switch (content->ct_type->tp_data.tp_discrete_type->dt_type) {
838 case MAILMIME_DISCRETE_TYPE_TEXT:
841 case MAILMIME_DISCRETE_TYPE_IMAGE:
842 _main_type = "image";
844 case MAILMIME_DISCRETE_TYPE_AUDIO:
845 _main_type = "audio";
847 case MAILMIME_DISCRETE_TYPE_VIDEO:
848 _main_type = "video";
850 case MAILMIME_DISCRETE_TYPE_APPLICATION:
851 _main_type = "application";
853 case MAILMIME_DISCRETE_TYPE_EXTENSION:
854 _main_type = "extension";
860 len = strlen(_main_type) + 1 + strlen(content->ct_subtype) + 1;
861 _type = calloc(1, len);
866 strncpy(_type, _main_type, len);
867 len -= strlen(_main_type);
868 strncat(_type, "/", len--);
869 strncat(_type, content->ct_subtype, len);
871 if (content->ct_parameters) {
873 for (cur = clist_begin(content->ct_parameters); cur; cur =
875 struct mailmime_parameter * param = clist_content(cur);
876 if (param && param->pa_name && strcasecmp(param->pa_name,
878 _charset = param->pa_value;
883 *charset = strdup(_charset);
893 // Only for null-terminated field strings.
894 // can this field be transported as is without modification?)
895 // (See rfc2822, section 2.2.3 - libetpan's handling isn't quite what
897 bool must_field_value_be_encoded(const char* field_value) {
901 return must_chunk_be_encoded((const void*)field_value, strlen(field_value), false);
904 bool must_chunk_be_encoded(const void* value, size_t size, bool ignore_fws) {
906 const char* begin_ptr = (const char*)value;
908 const char* end_ptr = begin_ptr + size;
910 const char* cur_char_ptr = begin_ptr;
911 while (cur_char_ptr < end_ptr) {
912 char cur_char = *cur_char_ptr;
913 if (cur_char > 127 || cur_char < 0)
915 // FIXME - do we need to deal with CRCRLF here?
916 // I guess in the worst case, it gets encoded, which
917 // is *supposed* to be harmless...
919 if (cur_char == '\r') {
920 const char* next = cur_char_ptr + 1;
921 const char* nextnext = next + 1;
922 if (next >= end_ptr || nextnext >= end_ptr
924 || (*nextnext != ' ' && *nextnext != '\t')) {
928 else if (cur_char == '\n') {
929 const char* prev = cur_char_ptr - 1;
930 if (prev == begin_ptr || *prev != '\r')