|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
* @file etpan_mime.c
|
|
|
|
* @brief File description for doxygen missing. FIXME
|
|
|
|
* @license GNU General Public License 3.0 - see LICENSE.txt
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "etpan_mime.h"
|
|
|
|
#ifndef mailmime_param_new_with_data
|
|
|
|
#include <libetpan/mailprivacy_tools.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "pEp_internal.h"
|
|
|
|
#include "platform.h"
|
|
|
|
#include "mime.h"
|
|
|
|
#include "wrappers.h"
|
|
|
|
#include "resource_id.h"
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#define MAX_MESSAGE_ID 128
|
|
|
|
|
|
|
|
#define MAX_IMF_LINE_LEN 998
|
|
|
|
|
|
|
|
static bool ascii_exceeds_line_length(const char* data, size_t size) {
|
|
|
|
|
|
|
|
const char* curr_pos = data;
|
|
|
|
const char* last_pos = data;
|
|
|
|
const char* end_pos = data + size;
|
|
|
|
const char* crlf = "\r\n";
|
|
|
|
|
|
|
|
while ((curr_pos + MAX_IMF_LINE_LEN) < end_pos) {
|
|
|
|
last_pos = curr_pos;
|
|
|
|
curr_pos = strnstr(curr_pos, crlf, end_pos - curr_pos);
|
|
|
|
if (!curr_pos)
|
|
|
|
return true;
|
|
|
|
if (curr_pos - last_pos > MAX_IMF_LINE_LEN)
|
|
|
|
return true;
|
|
|
|
curr_pos += 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
*
|
|
|
|
* <!-- generate_boundary() -->
|
|
|
|
*
|
|
|
|
* @brief TODO
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static char * generate_boundary(void)
|
|
|
|
{
|
|
|
|
char id[MAX_MESSAGE_ID];
|
|
|
|
|
|
|
|
// no cryptographically strong random needed here
|
|
|
|
const long value1 = random();
|
|
|
|
const long value2 = random();
|
|
|
|
const long value3 = random();
|
|
|
|
const long value4 = random();
|
|
|
|
|
|
|
|
snprintf(id, MAX_MESSAGE_ID, "%.4lx%.4lx%.4lx%.4lx", value1, value2,
|
|
|
|
value3, value4);
|
|
|
|
|
|
|
|
return strdup(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct mailmime * part_new_empty(
|
|
|
|
struct mailmime_content * content,
|
|
|
|
struct mailmime_fields * mime_fields,
|
|
|
|
stringpair_list_t* param_keyvals,
|
|
|
|
int force_single
|
|
|
|
)
|
|
|
|
{
|
|
|
|
struct mailmime * build_info;
|
|
|
|
clist * list = NULL;
|
|
|
|
int r;
|
|
|
|
int mime_type;
|
|
|
|
char * attr_name = NULL;
|
|
|
|
char * attr_value = NULL;
|
|
|
|
struct mailmime_parameter * param = NULL;
|
|
|
|
clist * parameters = NULL;
|
|
|
|
char *boundary = NULL;
|
|
|
|
|
|
|
|
list = NULL;
|
|
|
|
|
|
|
|
if (force_single) {
|
|
|
|
mime_type = MAILMIME_SINGLE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
switch (content->ct_type->tp_type) {
|
|
|
|
case MAILMIME_TYPE_DISCRETE_TYPE:
|
|
|
|
mime_type = MAILMIME_SINGLE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MAILMIME_TYPE_COMPOSITE_TYPE:
|
|
|
|
switch (content->ct_type->tp_data.tp_composite_type->ct_type) {
|
|
|
|
case MAILMIME_COMPOSITE_TYPE_MULTIPART:
|
|
|
|
mime_type = MAILMIME_MULTIPLE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MAILMIME_COMPOSITE_TYPE_MESSAGE:
|
|
|
|
if (strcasecmp(content->ct_subtype, "rfc822") == 0)
|
|
|
|
mime_type = MAILMIME_MESSAGE;
|
|
|
|
else
|
|
|
|
mime_type = MAILMIME_SINGLE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
goto enomem;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
goto enomem;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mime_type == MAILMIME_MULTIPLE) {
|
|
|
|
list = clist_new();
|
|
|
|
assert(list);
|
|
|
|
if (list == NULL)
|
|
|
|
goto enomem;
|
|
|
|
|
|
|
|
attr_name = strdup("boundary");
|
|
|
|
assert(attr_name);
|
|
|
|
if (attr_name == NULL)
|
|
|
|
goto enomem;
|
|
|
|
|
|
|
|
boundary = generate_boundary();
|
|
|
|
assert(boundary);
|
|
|
|
attr_value = boundary;
|
|
|
|
if (attr_value == NULL)
|
|
|
|
goto enomem;
|
|
|
|
|
|
|
|
param = mailmime_parameter_new(attr_name, attr_value);
|
|
|
|
assert(param);
|
|
|
|
if (param == NULL)
|
|
|
|
goto enomem;
|
|
|
|
attr_name = NULL;
|
|
|
|
attr_value = NULL;
|
|
|
|
|
|
|
|
if (content->ct_parameters == NULL) {
|
|
|
|
parameters = clist_new();
|
|
|
|
assert(parameters);
|
|
|
|
if (parameters == NULL)
|
|
|
|
goto enomem;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
parameters = content->ct_parameters;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = clist_append(parameters, param);
|
|
|
|
if (r)
|
|
|
|
goto enomem;
|
|
|
|
param = NULL;
|
|
|
|
|
|
|
|
if (content->ct_parameters == NULL)
|
|
|
|
content->ct_parameters = parameters;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (param_keyvals) {
|
|
|
|
stringpair_list_t* cur;
|
|
|
|
for (cur = param_keyvals; cur; cur = cur->next) {
|
|
|
|
attr_name = strdup(cur->value->key);
|
|
|
|
attr_value = strdup(cur->value->value);
|
|
|
|
|
|
|
|
param = mailmime_parameter_new(attr_name, attr_value);
|
|
|
|
assert(param);
|
|
|
|
if (param == NULL)
|
|
|
|
goto enomem;
|
|
|
|
|
|
|
|
attr_name = NULL;
|
|
|
|
attr_value = NULL;
|
|
|
|
|
|
|
|
if (content->ct_parameters == NULL) {
|
|
|
|
parameters = clist_new();
|
|
|
|
assert(parameters);
|
|
|
|
if (parameters == NULL)
|
|
|
|
goto enomem;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
parameters = content->ct_parameters;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = clist_append(parameters, param);
|
|
|
|
if (r)
|
|
|
|
goto enomem;
|
|
|
|
param = NULL;
|
|
|
|
|
|
|
|
if (content->ct_parameters == NULL)
|
|
|
|
content->ct_parameters = parameters;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
build_info = mailmime_new(mime_type, NULL, 0, mime_fields, content, NULL,
|
|
|
|
NULL, NULL, list, NULL, NULL);
|
|
|
|
if (build_info == NULL)
|
|
|
|
goto enomem;
|
|
|
|
|
|
|
|
return build_info;
|
|
|
|
|
|
|
|
enomem:
|
|
|
|
if (list)
|
|
|
|
clist_free(list);
|
|
|
|
free(attr_name);
|
|
|
|
free(attr_value);
|
|
|
|
if (content->ct_parameters == NULL)
|
|
|
|
if (parameters)
|
|
|
|
clist_free(parameters);
|
|
|
|
if (param)
|
|
|
|
mailmime_parameter_free(param);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct mailmime * get_pgp_encrypted_part(void)
|
|
|
|
{
|
|
|
|
struct mailmime * mime = NULL;
|
|
|
|
struct mailmime_fields * mime_fields = NULL;
|
|
|
|
struct mailmime_content * content = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
content = mailmime_content_new_with_str("application/pgp-encrypted");
|
|
|
|
if (content == NULL)
|
|
|
|
goto enomem;
|
|
|
|
|
|
|
|
mime_fields = mailmime_fields_new_empty();
|
|
|
|
if (mime_fields == NULL)
|
|
|
|
goto enomem;
|
|
|
|
|
|
|
|
mime = part_new_empty(content, mime_fields, NULL, 1);
|
|
|
|
if (mime == NULL)
|
|
|
|
goto enomem;
|
|
|
|
mime_fields = NULL;
|
|
|
|
content = NULL;
|
|
|
|
|
|
|
|
r = mailmime_set_body_text(mime, "Version: 1\n", 10);
|
|
|
|
if (r != 0)
|
|
|
|
goto enomem;
|
|
|
|
|
|
|
|
return mime;
|
|
|
|
|
|
|
|
enomem:
|
|
|
|
if (content)
|
|
|
|
mailmime_content_free(content);
|
|
|
|
if (mime_fields)
|
|
|
|
mailmime_fields_free(mime_fields);
|
|
|
|
if (mime)
|
|
|
|
mailmime_free(mime);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct mailmime * get_text_part(
|
|
|
|
pEp_rid_list_t* resource,
|
|
|
|
const char * mime_type,
|
|
|
|
const char * text,
|
|
|
|
size_t length,
|
|
|
|
int encoding_type
|
|
|
|
)
|
|
|
|
{
|
|
|
|
char * disposition_name = NULL;
|
|
|
|
struct mailmime_fields * mime_fields = NULL;
|
|
|
|
struct mailmime * mime = NULL;
|
|
|
|
struct mailmime_content * content = NULL;
|
|
|
|
struct mailmime_parameter * param = NULL;
|
|
|
|
struct mailmime_disposition * disposition = NULL;
|
|
|
|
struct mailmime_mechanism * encoding = NULL;
|
|
|
|
char* content_id = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (resource != NULL && resource->rid != NULL) {
|
|
|
|
switch (resource->rid_type) {
|
|
|
|
case PEP_RID_CID:
|
|
|
|
content_id = strdup(resource->rid);
|
|
|
|
break;
|
|
|
|
case PEP_RID_FILENAME:
|
|
|
|
default:
|
|
|
|
disposition_name = strdup(resource->rid);
|
|
|
|
if (disposition_name == NULL)
|
|
|
|
goto enomem;
|
|
|
|
|
|
|
|
disposition =
|
|
|
|
mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
|
|
|
|
disposition_name, NULL, NULL, NULL, (size_t) -1);
|
|
|
|
|
|
|
|
if (disposition == NULL)
|
|
|
|
goto enomem;
|
|
|
|
|
|
|
|
disposition_name = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (encoding_type) {
|
|
|
|
encoding = mailmime_mechanism_new(encoding_type, NULL);
|
|
|
|
if (encoding == NULL)
|
|
|
|
goto enomem;
|
|
|
|
}
|
|
|
|
|
|
|
|
mime_fields = mailmime_fields_new_with_data(encoding, content_id, NULL,
|
|
|
|
disposition, NULL);
|
|
|
|
if (mime_fields == NULL)
|
|
|
|
goto enomem;
|
|
|
|
encoding = NULL;
|
|
|
|
disposition = NULL;
|
|
|
|
content_id = NULL;
|
|
|
|
|
|
|
|
content = mailmime_content_new_with_str(mime_type);
|
|
|
|
if (content == NULL)
|
|
|
|
goto enomem;
|
|
|
|
|
|
|
|
if (encoding_type != MAILMIME_MECHANISM_7BIT) {
|
|
|
|
param = mailmime_param_new_with_data("charset", "utf-8");
|
|
|
|
r = clist_append(content->ct_parameters, param);
|
|
|
|
if (r != 0)
|
|
|
|
goto enomem;
|
|
|
|
}
|
|
|
|
|
|
|
|
mime = part_new_empty(content, mime_fields, NULL, 1);
|
|
|
|
if (mime == NULL)
|
|
|
|
goto enomem;
|
|
|
|
content = NULL;
|
|
|
|
mime_fields = NULL;
|
|
|
|
|
|
|
|
if (text) {
|
|
|
|
r = mailmime_set_body_text(mime, (char *) text, length);
|
|
|
|
if (r != 0)
|
|
|
|
goto enomem;
|
|
|
|
}
|
|
|
|
|
|
|
|
return mime;
|
|
|
|
|
|
|
|
enomem:
|
|
|
|
free(disposition_name);
|
|
|
|
if (mime_fields)
|
|
|
|
mailmime_fields_free(mime_fields);
|
|
|
|
if (mime)
|
|
|
|
mailmime_free(mime);
|
|
|
|
if (content)
|
|
|
|
mailmime_content_free(content);
|
|
|
|
if (param)
|
|
|
|
mailmime_parameter_free(param);
|
|
|
|
if (disposition)
|
|
|
|
mailmime_disposition_free(disposition);
|
|
|
|
if (encoding)
|
|
|
|
mailmime_mechanism_free(encoding);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct mailmime * get_file_part(
|
|
|
|
pEp_rid_list_t* resource,
|
|
|
|
const char * mime_type,
|
|
|
|
char * data,
|
|
|
|
size_t length,
|
|
|
|
bool is_nf_message_attachment // non-forwarded msg as att
|
|
|
|
)
|
|
|
|
{
|
|
|
|
char * disposition_name = NULL;
|
|
|
|
int encoding_type;
|
|
|
|
struct mailmime_disposition * disposition = NULL;
|
|
|
|
struct mailmime_mechanism * encoding = NULL;
|
|
|
|
struct mailmime_content * content = NULL;
|
|
|
|
struct mailmime * mime = NULL;
|
|
|
|
struct mailmime_fields * mime_fields = NULL;
|
|
|
|
char* content_id = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (resource != NULL && resource->rid != NULL) {
|
|
|
|
switch (resource->rid_type) {
|
|
|
|
case PEP_RID_CID:
|
|
|
|
content_id = strdup(resource->rid);
|
|
|
|
disposition =
|
|
|
|
mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
|
|
|
|
NULL, NULL, NULL, NULL, (size_t) -1);
|
|
|
|
if (disposition == NULL)
|
|
|
|
goto enomem;
|
|
|
|
break;
|
|
|
|
case PEP_RID_FILENAME:
|
|
|
|
default:
|
|
|
|
disposition_name = strdup(resource->rid);
|
|
|
|
if (disposition_name == NULL)
|
|
|
|
goto enomem;
|
|
|
|
|
|
|
|
disposition =
|
|
|
|
mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_ATTACHMENT,
|
|
|
|
disposition_name, NULL, NULL, NULL, (size_t) -1);
|
|
|
|
|
|
|
|
if (disposition == NULL)
|
|
|
|
goto enomem;
|
|
|
|
disposition_name = NULL;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
content = mailmime_content_new_with_str(mime_type);
|
|
|
|
if (content == NULL)
|
|
|
|
goto enomem;
|
|
|
|
|
|
|
|
encoding = NULL;
|
|
|
|
|
|
|
|
bool already_ascii = !(must_chunk_be_encoded(data, length, true));
|
|
|
|
|
|
|
|
// check to be sure, if it is already ascii, that line lengths aren't also
|
|
|
|
// exceeded. Otherwise, we should base64-encode anyway.
|
|
|
|
|
|
|
|
if (!is_nf_message_attachment && !already_ascii) {
|
|
|
|
encoding_type = MAILMIME_MECHANISM_BASE64;
|
|
|
|
encoding = mailmime_mechanism_new(encoding_type, NULL);
|
|
|
|
if (encoding == NULL)
|
|
|
|
goto enomem;
|
|
|
|
}
|
|
|
|
|
|
|
|
mime_fields = mailmime_fields_new_with_data(encoding, content_id, NULL,
|
|
|
|
disposition, NULL);
|
|
|
|
if (mime_fields == NULL)
|
|
|
|
goto enomem;
|
|
|
|
encoding = NULL;
|
|
|
|
disposition = NULL;
|
|
|
|
|
|
|
|
stringpair_list_t* extra_params = NULL;
|
|
|
|
|
|
|
|
if (is_nf_message_attachment)
|
|
|
|
extra_params = new_stringpair_list(new_stringpair("forwarded", "no"));
|
|
|
|
|
|
|
|
mime = part_new_empty(content, mime_fields, extra_params, 1);
|
|
|
|
free_stringpair_list(extra_params);
|
|
|
|
if (mime == NULL)
|
|
|
|
goto enomem;
|
|
|
|
content = NULL;
|
|
|
|
mime_fields = NULL;
|
|
|
|
|
|
|
|
if(length > 0)
|
|
|
|
{
|
|
|
|
r = mailmime_set_body_text(mime, data, length);
|
|
|
|
if (r != 0)
|
|
|
|
goto enomem;
|
|
|
|
}
|
|
|
|
|
|
|
|
return mime;
|
|
|
|
|
|
|
|
enomem:
|
|
|
|
free(disposition_name);
|
|
|
|
if (disposition)
|
|
|
|
mailmime_disposition_free(disposition);
|
|
|
|
if (encoding)
|
|
|
|
mailmime_mechanism_free(encoding);
|
|
|
|
if (content)
|
|
|
|
mailmime_content_free(content);
|
|
|
|
if (mime_fields)
|
|
|
|
mailmime_fields_free(mime_fields);
|
|
|
|
if (mime)
|
|
|
|
mailmime_free(mime);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct mailmime * part_multiple_new(const char *type)
|
|
|
|
{
|
|
|
|
struct mailmime_fields *mime_fields = NULL;
|
|
|
|
struct mailmime_content *content = NULL;
|
|
|
|
struct mailmime *mp = NULL;
|
|
|
|
|
|
|
|
mime_fields = mailmime_fields_new_empty();
|
|
|
|
if (mime_fields == NULL)
|
|
|
|
goto enomem;
|
|
|
|
|
|
|
|
content = mailmime_content_new_with_str(type);
|
|
|
|
if (content == NULL)
|
|
|
|
goto enomem;
|
|
|
|
|
|
|
|
mp = part_new_empty(content, mime_fields, NULL, 0);
|
|
|
|
if (mp == NULL)
|
|
|
|
goto enomem;
|
|
|
|
|
|
|
|
return mp;
|
|
|
|
|
|
|
|
enomem:
|
|
|
|
if (content)
|
|
|
|
mailmime_content_free(content);
|
|
|
|
if (mime_fields)
|
|
|
|
mailmime_fields_free(mime_fields);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct mailimf_field * _new_field(
|
|
|
|
int type,
|
|
|
|
_new_func_t new_func,
|
|
|
|
void *value
|
|
|
|
)
|
|
|
|
{
|
|
|
|
void *data = new_func(value);
|
|
|
|
assert(data);
|
|
|
|
if (data == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
|
|
|
|
assert(result);
|
|
|
|
if (result == NULL) {
|
|
|
|
free(data);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
result->fld_type = type;
|
|
|
|
result->fld_data.fld_return_path = data;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void _free_field(struct mailimf_field *field)
|
|
|
|
{
|
|
|
|
if (field)
|
|
|
|
free(field->fld_data.fld_return_path);
|
|
|
|
free(field);
|
|
|
|
}
|
|
|
|
|
|
|
|
int _append_field(
|
|
|
|
clist *list,
|
|
|
|
int type,
|
|
|
|
_new_func_t new_func,
|
|
|
|
void *value
|
|
|
|
)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
struct mailimf_field * field;
|
|
|
|
|
|
|
|
assert(list);
|
|
|
|
assert(new_func);
|
|
|
|
assert(value);
|
|
|
|
|
|
|
|
field = _new_field(type, new_func, value);
|
|
|
|
if (field == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
r = clist_append(list, field);
|
|
|
|
if (r)
|
|
|
|
_free_field(field);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
// http://media2.giga.de/2014/02/Image-28.jpg
|
|
|
|
|
|
|
|
struct mailimf_date_time * timestamp_to_etpantime(const timestamp *ts)
|
|
|
|
{
|
|
|
|
struct mailimf_date_time * result = calloc(1,
|
|
|
|
sizeof(struct mailimf_date_time));
|
|
|
|
assert(result);
|
|
|
|
if (result == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
assert(ts);
|
|
|
|
|
|
|
|
result->dt_sec = ts->tm_sec;
|
|
|
|
result->dt_min = ts->tm_min;
|
|
|
|
result->dt_hour = ts->tm_hour;
|
|
|
|
result->dt_day = ts->tm_mday;
|
|
|
|
result->dt_month = ts->tm_mon + 1;
|
|
|
|
result->dt_year = ts->tm_year + 1900;
|
|
|
|
#ifndef __MVS__
|
|
|
|
result->dt_zone = (int) (ts->tm_gmtoff / 36L);
|
|
|
|
#endif
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
timestamp * etpantime_to_timestamp(const struct mailimf_date_time *et)
|
|
|
|
{
|
|
|
|
timestamp * result = calloc(1, sizeof(timestamp));
|
|
|
|
assert(result);
|
|
|
|
if (result == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
assert(et);
|
|
|
|
|
|
|
|
result->tm_sec = et->dt_sec;
|
|
|
|
result->tm_min = et->dt_min;
|
|
|
|
result->tm_hour = et->dt_hour;
|
|
|
|
result->tm_mday = et->dt_day;
|
|
|
|
result->tm_mon = et->dt_month - 1;
|
|
|
|
result->tm_year = et->dt_year - 1900;
|
|
|
|
#ifndef __MVS__
|
|
|
|
result->tm_gmtoff = 36L * (long) et->dt_zone;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Normalize to UTC and then forget the offset.
|
|
|
|
time_t t = timegm_with_gmtoff(result);
|
|
|
|
gmtime_r(&t, result);
|
|
|
|
#ifndef __MVS__
|
|
|
|
result->tm_gmtoff = 0;
|
|
|
|
#endif
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct mailimf_mailbox * mailbox_from_string(
|
|
|
|
const char *name,
|
|
|
|
const char *address
|
|
|
|
)
|
|
|
|
{
|
|
|
|
assert(address);
|
|
|
|
if (!address)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
struct mailimf_mailbox *mb = NULL;
|
|
|
|
char *_name = NULL;
|
|
|
|
char *_address = NULL;
|
|
|
|
|
|
|
|
_name = name ? strdup(name) : strdup("");
|
|
|
|
if (_name == NULL)
|
|
|
|
goto enomem;
|
|
|
|
|
|
|
|
char* at = strstr(address, "@");
|
|
|
|
if (!at) {
|
|
|
|
// Presumed URI
|
|
|
|
int added_char_len = 6; // " " @URI
|
|
|
|
int new_addr_len = strlen(address) + added_char_len + 1;
|
|
|
|
_address = calloc(new_addr_len, 1);
|
|
|
|
if (_address == NULL)
|
|
|
|
goto enomem;
|
|
|
|
|
|
|
|
_address[0] = '"';
|
|
|
|
strlcat(_address, address, new_addr_len);
|
|
|
|
strlcat(_address, "\"@URI", new_addr_len);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
_address = strdup(address);
|
|
|
|
if (_address == NULL)
|
|
|
|
goto enomem;
|
|
|
|
}
|
|
|
|
|
|
|
|
mb = mailimf_mailbox_new(_name, _address);
|
|
|
|
assert(mb);
|
|
|
|
if (mb == NULL)
|
|
|
|
goto enomem;
|
|
|
|
|
|
|
|
return mb;
|
|
|
|
|
|
|
|
enomem:
|
|
|
|
free(_name);
|
|
|
|
free(_address);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct mailimf_field * create_optional_field(
|
|
|
|
const char *field,
|
|
|
|
const char *value
|
|
|
|
)
|
|
|
|
{
|
|
|
|
char *_field = NULL;
|
|
|
|
char *_value = NULL;
|
|
|
|
struct mailimf_optional_field *optional_field = NULL;
|
|
|
|
|
|
|
|
_field = strdup(field);
|
|
|
|
if (_field == NULL)
|
|
|
|
goto enomem;
|
|
|
|
|
|
|
|
if (!must_field_value_be_encoded(value))
|
|
|
|
_value = strdup(value);
|
|
|
|
else
|
|
|
|
_value = mailmime_encode_subject_header("utf-8", value, 0);
|
|
|
|
if (_value == NULL)
|
|
|
|
goto enomem;
|
|
|
|
|
|
|
|
optional_field = mailimf_optional_field_new(_field, _value);
|
|
|
|
if (optional_field == NULL)
|
|
|
|
goto enomem;
|
|
|
|
|
|
|
|
struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
|
|
|
|
assert(result);
|
|
|
|
if (result == NULL)
|
|
|
|
goto enomem;
|
|
|
|
|
|
|
|
result->fld_type = MAILIMF_FIELD_OPTIONAL_FIELD;
|
|
|
|
result->fld_data.fld_optional_field = optional_field;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
enomem:
|
|
|
|
if (optional_field) {
|
|
|
|
mailimf_optional_field_free(optional_field);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
free(_field);
|
|
|
|
free(_value);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int _append_optional_field(
|
|
|
|
clist *list,
|
|
|
|
const char *field,
|
|
|
|
const char *value
|
|
|
|
)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
struct mailimf_field * optional_field =
|
|
|
|
create_optional_field(field, value);
|
|
|
|
|
|
|
|
if (optional_field == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
r = clist_append(list, optional_field);
|
|
|
|
if (r)
|
|
|
|
mailimf_field_free(optional_field);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
clist * _get_fields(struct mailmime * mime)
|
|
|
|
{
|
|
|
|
clist * _fieldlist = NULL;
|
|
|
|
|
|
|
|
assert(mime);
|
|
|
|
|
|
|
|
if (mime->mm_data.mm_message.mm_fields &&
|
|
|
|
mime->mm_data.mm_message.mm_fields->fld_list) {
|
|
|
|
_fieldlist = mime->mm_data.mm_message.mm_fields->fld_list;
|
|
|
|
}
|
|
|
|
|
|
|
|
return _fieldlist;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct mailmime_content * _get_content(struct mailmime * mime)
|
|
|
|
{
|
|
|
|
struct mailmime_content * content = NULL;
|
|
|
|
|
|
|
|
assert(mime);
|
|
|
|
|
|
|
|
if (mime->mm_data.mm_message.mm_msg_mime)
|
|
|
|
content = mime->mm_data.mm_message.mm_msg_mime->mm_content_type;
|
|
|
|
|
|
|
|
return content;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Return a list of identifier_type and resource id (filename, cid, etc) */
|
|
|
|
pEp_rid_list_t* _get_resource_id_list(struct mailmime *mime)
|
|
|
|
{
|
|
|
|
clist * _fieldlist = NULL;
|
|
|
|
|
|
|
|
assert(mime);
|
|
|
|
|
|
|
|
if (mime->mm_mime_fields && mime->mm_mime_fields->fld_list)
|
|
|
|
_fieldlist = mime->mm_mime_fields->fld_list;
|
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
clistiter *cur;
|
|
|
|
|
|
|
|
pEp_rid_list_t* rid_list = NULL;
|
|
|
|
pEp_rid_list_t** rid_list_curr_p = &rid_list;
|
|
|
|
|
|
|
|
for (cur = clist_begin(_fieldlist); cur; cur = clist_next(cur)) {
|
|
|
|
struct mailmime_field * _field = clist_content(cur);
|
|
|
|
/* content_id */
|
|
|
|
if (_field && _field->fld_type == MAILMIME_FIELD_ID) {
|
|
|
|
pEp_rid_list_t* new_rid = (pEp_rid_list_t*)calloc(1, sizeof(pEp_rid_list_t));
|
|
|
|
new_rid->rid_type = PEP_RID_CID;
|
|
|
|
new_rid->rid = strdup(_field->fld_data.fld_id);
|
|
|
|
*rid_list_curr_p = new_rid;
|
|
|
|
rid_list_curr_p = &new_rid->next;
|
|
|
|
}
|
|
|
|
else if (_field && _field->fld_type == MAILMIME_FIELD_DISPOSITION) {
|
|
|
|
/* filename */
|
|
|
|
if (_field->fld_data.fld_disposition &&
|
|
|
|
_field->fld_data.fld_disposition->dsp_parms) {
|
|
|
|
clist * _parmlist =
|
|
|
|
_field->fld_data.fld_disposition->dsp_parms;
|
|
|
|
clistiter *cur2;
|
|
|
|
for (cur2 = clist_begin(_parmlist); cur2; cur2 =
|
|
|
|
clist_next(cur2)) {
|
|
|
|
struct mailmime_disposition_parm * param =
|
|
|
|
clist_content(cur2);
|
|
|
|
if (param->pa_type == MAILMIME_DISPOSITION_PARM_FILENAME) {
|
|
|
|
pEp_rid_list_t* new_rid = (pEp_rid_list_t*)calloc(1, sizeof(pEp_rid_list_t));
|
|
|
|
new_rid->rid_type = PEP_RID_FILENAME;
|
|
|
|
new_rid->rid = strdup(param->pa_data.pa_filename);
|
|
|
|
*rid_list_curr_p = new_rid;
|
|
|
|
rid_list_curr_p = &new_rid->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Will almost certainly usually be a singleton, but we need to be able to decide */
|
|
|
|
return rid_list;
|
|
|
|
}
|
|