1594 lines
35 KiB
C
1594 lines
35 KiB
C
/*
|
|
* libEtPan! -- a mail library
|
|
*
|
|
* Copyright (C) 2001, 2005 - DINH Viet Hoa
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of the libEtPan! project nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
/*
|
|
* $Id: mailprivacy_tools.c,v 1.18 2011/01/06 00:09:52 hoa Exp $
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#include "mailprivacy_tools.h"
|
|
#include "mailprivacy_tools_private.h"
|
|
|
|
#if __APPLE__
|
|
#include <TargetConditionals.h>
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#ifdef WIN32
|
|
# include "win_etpan.h"
|
|
#else
|
|
# include <libgen.h>
|
|
# include <sys/mman.h>
|
|
# include <sys/wait.h>
|
|
#endif
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <libetpan/mailmessage.h>
|
|
#include <ctype.h>
|
|
#include "mailprivacy.h"
|
|
#include <libetpan/libetpan-config.h>
|
|
#include <libetpan/data_message_driver.h>
|
|
#include <errno.h>
|
|
|
|
#include "../data-types/syscall_wrappers.h"
|
|
|
|
void mailprivacy_mime_clear(struct mailmime * mime)
|
|
{
|
|
struct mailmime_data * data;
|
|
clistiter * cur;
|
|
|
|
switch (mime->mm_type) {
|
|
case MAILMIME_SINGLE:
|
|
data = mime->mm_data.mm_single;
|
|
if (data != NULL) {
|
|
if (data->dt_type == MAILMIME_DATA_FILE)
|
|
unlink(data->dt_data.dt_filename);
|
|
}
|
|
break;
|
|
|
|
case MAILMIME_MULTIPLE:
|
|
data = mime->mm_data.mm_multipart.mm_preamble;
|
|
if (data != NULL) {
|
|
if (data->dt_type == MAILMIME_DATA_FILE)
|
|
unlink(data->dt_data.dt_filename);
|
|
}
|
|
data = mime->mm_data.mm_multipart.mm_epilogue;
|
|
if (data != NULL) {
|
|
if (data->dt_type == MAILMIME_DATA_FILE)
|
|
unlink(data->dt_data.dt_filename);
|
|
}
|
|
|
|
for(cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list) ;
|
|
cur != NULL ; cur = clist_next(cur)) {
|
|
struct mailmime * submime;
|
|
|
|
submime = clist_content(cur);
|
|
|
|
mailprivacy_mime_clear(submime);
|
|
}
|
|
break;
|
|
|
|
case MAILMIME_MESSAGE:
|
|
if (mime->mm_data.mm_message.mm_msg_mime != NULL) {
|
|
mailprivacy_mime_clear(mime->mm_data.mm_message.mm_msg_mime);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
static FILE * get_tmp_file(char * filename)
|
|
{
|
|
int fd;
|
|
mode_t old_mask;
|
|
FILE * f;
|
|
|
|
old_mask = umask(0077);
|
|
fd = Mkstemp(filename);
|
|
umask(old_mask);
|
|
if (fd == -1)
|
|
return NULL;
|
|
|
|
f = Fdopen(fd, "r+");
|
|
if (f == NULL) {
|
|
int r;
|
|
Close(fd);
|
|
unlink(filename);
|
|
}
|
|
|
|
return f;
|
|
}
|
|
|
|
FILE * mailprivacy_get_tmp_file(struct mailprivacy * privacy,
|
|
char * filename, size_t size)
|
|
{
|
|
snprintf(filename, size, "%s/libetpan-privacy-XXXXXX", privacy->tmp_dir);
|
|
return get_tmp_file(filename);
|
|
}
|
|
|
|
int mailprivacy_get_tmp_filename(struct mailprivacy * privacy,
|
|
char * filename, size_t size)
|
|
{
|
|
FILE * f;
|
|
|
|
f = mailprivacy_get_tmp_file(privacy, filename, size);
|
|
if (f == NULL)
|
|
return MAIL_ERROR_FILE;
|
|
|
|
Fclose(f);
|
|
|
|
return MAIL_NO_ERROR;
|
|
}
|
|
|
|
static char * dup_file(struct mailprivacy * privacy,
|
|
char * source_filename)
|
|
{
|
|
char filename[PATH_MAX];
|
|
FILE * dest_f;
|
|
int r;
|
|
struct stat stat_info;
|
|
char * dest_filename;
|
|
char * mapping;
|
|
size_t written;
|
|
int fd;
|
|
|
|
dest_f = mailprivacy_get_tmp_file(privacy, filename, sizeof(filename));
|
|
if (dest_f == NULL)
|
|
goto err;
|
|
|
|
dest_filename = strdup(filename);
|
|
if (dest_filename == NULL)
|
|
goto close_dest;
|
|
|
|
fd = Open(source_filename, O_RDONLY);
|
|
if (fd < 0)
|
|
goto free_dest;
|
|
|
|
r = fstat(fd, &stat_info);
|
|
if (r < 0)
|
|
goto close_src;
|
|
|
|
mapping = mmap(NULL, stat_info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
|
if (mapping == (char *)MAP_FAILED)
|
|
goto close_src;
|
|
|
|
written = Fwrite(mapping, 1, stat_info.st_size, dest_f);
|
|
if (written != (size_t) stat_info.st_size)
|
|
goto unmap;
|
|
|
|
munmap(mapping, stat_info.st_size);
|
|
Close(fd);
|
|
Fclose(dest_f);
|
|
|
|
return dest_filename;
|
|
|
|
unmap:
|
|
munmap(mapping, stat_info.st_size);
|
|
close_src:
|
|
Close(fd);
|
|
free_dest:
|
|
free(dest_filename);
|
|
close_dest:
|
|
Fclose(dest_f);
|
|
err:
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
mime_data_replace()
|
|
|
|
write a mime part to a file and change the reference of mailmime_data
|
|
to the file.
|
|
*/
|
|
|
|
static int mime_data_replace(struct mailprivacy * privacy,
|
|
int encoding_type,
|
|
struct mailmime_data * data,
|
|
int reencode)
|
|
{
|
|
char filename[PATH_MAX];
|
|
FILE * f;
|
|
size_t written;
|
|
char * dup_filename;
|
|
int res;
|
|
int r;
|
|
int decoded;
|
|
|
|
if (data->dt_type != MAILMIME_DATA_TEXT) {
|
|
res = MAIL_NO_ERROR;
|
|
goto err;
|
|
}
|
|
|
|
f = mailprivacy_get_tmp_file(privacy, filename, sizeof(filename));
|
|
if (f == NULL) {
|
|
res = MAIL_ERROR_FILE;
|
|
goto err;
|
|
}
|
|
|
|
decoded = 0;
|
|
if (reencode) {
|
|
if (encoding_type != -1) {
|
|
char * content;
|
|
size_t content_len;
|
|
size_t cur_token;
|
|
|
|
cur_token = 0;
|
|
r = mailmime_part_parse(data->dt_data.dt_text.dt_data,
|
|
data->dt_data.dt_text.dt_length,
|
|
&cur_token, encoding_type, &content, &content_len);
|
|
|
|
if (r == MAILIMF_NO_ERROR) {
|
|
/* write decoded */
|
|
written = Fwrite(content, 1, content_len, f);
|
|
if (written != content_len) {
|
|
Fclose(f);
|
|
unlink(filename);
|
|
res = MAIL_ERROR_FILE;
|
|
goto err;
|
|
}
|
|
mmap_string_unref(content);
|
|
|
|
decoded = 1;
|
|
data->dt_encoded = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!decoded) {
|
|
written = Fwrite(data->dt_data.dt_text.dt_data, 1,
|
|
data->dt_data.dt_text.dt_length, f);
|
|
if (written != data->dt_data.dt_text.dt_length) {
|
|
Fclose(f);
|
|
unlink(filename);
|
|
res = MAIL_ERROR_FILE;
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
Fclose(f);
|
|
|
|
dup_filename = strdup(filename);
|
|
if (dup_filename == NULL) {
|
|
unlink(filename);
|
|
res = MAIL_ERROR_MEMORY;
|
|
goto err;
|
|
}
|
|
|
|
data->dt_type = MAILMIME_DATA_FILE;
|
|
data->dt_data.dt_filename = dup_filename;
|
|
|
|
return MAIL_NO_ERROR;
|
|
|
|
err:
|
|
return res;
|
|
}
|
|
|
|
|
|
/*
|
|
recursive_replace_single_parts()
|
|
|
|
write all parts of the given mime part to file.
|
|
*/
|
|
|
|
static int recursive_replace_single_parts(struct mailprivacy * privacy,
|
|
struct mailmime * mime, int reencode)
|
|
{
|
|
int r;
|
|
int res;
|
|
clistiter * cur;
|
|
|
|
mime->mm_mime_start = NULL;
|
|
|
|
switch(mime->mm_type) {
|
|
case MAILMIME_SINGLE:
|
|
if (mime->mm_data.mm_single != NULL) {
|
|
int encoding_type;
|
|
struct mailmime_single_fields single_fields;
|
|
|
|
mailmime_single_fields_init(&single_fields, mime->mm_mime_fields,
|
|
mime->mm_content_type);
|
|
|
|
if (single_fields.fld_encoding != NULL)
|
|
encoding_type = single_fields.fld_encoding->enc_type;
|
|
else
|
|
encoding_type = -1;
|
|
|
|
r = mime_data_replace(privacy, encoding_type,
|
|
mime->mm_data.mm_single, reencode);
|
|
if (r != MAIL_NO_ERROR) {
|
|
res = r;
|
|
goto err;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MAILMIME_MULTIPLE:
|
|
if (mime->mm_data.mm_multipart.mm_preamble != NULL) {
|
|
r = mime_data_replace(privacy, -1,
|
|
mime->mm_data.mm_multipart.mm_preamble, reencode);
|
|
if (r != MAIL_NO_ERROR) {
|
|
res = r;
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
if (mime->mm_data.mm_multipart.mm_epilogue != NULL) {
|
|
r = mime_data_replace(privacy, -1,
|
|
mime->mm_data.mm_multipart.mm_epilogue, reencode);
|
|
if (r != MAIL_NO_ERROR) {
|
|
res = r;
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
for(cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list) ;
|
|
cur != NULL ; cur = clist_next(cur)) {
|
|
struct mailmime * child;
|
|
|
|
child = clist_content(cur);
|
|
|
|
r = recursive_replace_single_parts(privacy, child, reencode);
|
|
if (r != MAIL_NO_ERROR) {
|
|
res = r;
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case MAILMIME_MESSAGE:
|
|
if (mime->mm_data.mm_message.mm_msg_mime != NULL) {
|
|
r = recursive_replace_single_parts(privacy,
|
|
mime->mm_data.mm_message.mm_msg_mime, reencode);
|
|
if (r != MAIL_NO_ERROR) {
|
|
res = r;
|
|
goto err;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return MAIL_NO_ERROR;
|
|
|
|
err:
|
|
return res;
|
|
}
|
|
|
|
/*
|
|
mailprivacy_get_mime()
|
|
|
|
parse the message in MIME structure,
|
|
all single MIME parts are stored in files.
|
|
|
|
privacy can be set to NULL to disable privacy check.
|
|
*/
|
|
|
|
int mailprivacy_get_mime(struct mailprivacy * privacy,
|
|
int check_privacy, int reencode,
|
|
char * content, size_t content_len,
|
|
struct mailmime ** result_mime)
|
|
{
|
|
struct mailmime * mime;
|
|
mailmessage * msg;
|
|
int r;
|
|
int res;
|
|
|
|
#if 0
|
|
int check_privacy;
|
|
|
|
check_privacy = (privacy != NULL);
|
|
#endif
|
|
|
|
/*
|
|
use message data driver, get bodystructure and
|
|
convert all the data part in MAILMIME_SINGLE to files.
|
|
*/
|
|
|
|
msg = data_message_init(content, content_len);
|
|
if (msg == NULL) {
|
|
res = MAIL_ERROR_MEMORY;
|
|
goto err;
|
|
}
|
|
|
|
#if 0
|
|
if (msg->mime == NULL) {
|
|
if (check_privacy) {
|
|
r = mailprivacy_msg_get_bodystructure(privacy, msg, &mime);
|
|
}
|
|
else {
|
|
/*
|
|
don't use etpan_msg_get_bodystructure because it is not useful
|
|
and to avoid loops due to security part
|
|
*/
|
|
r = mailmessage_get_bodystructure(msg, &mime);
|
|
}
|
|
}
|
|
else {
|
|
mime = msg->mime;
|
|
}
|
|
#endif
|
|
|
|
if (check_privacy)
|
|
r = mailprivacy_msg_get_bodystructure(privacy, msg, &mime);
|
|
else
|
|
r = mailmessage_get_bodystructure(msg, &mime);
|
|
if (r != MAIL_NO_ERROR) {
|
|
res = r;
|
|
goto free_msg;
|
|
}
|
|
|
|
/*
|
|
should be done so that the MIME structure need not to be unregistered.
|
|
*/
|
|
mailprivacy_recursive_unregister_mime(privacy, mime);
|
|
|
|
r = recursive_replace_single_parts(privacy, mime, reencode);
|
|
if (r != MAIL_NO_ERROR) {
|
|
res = r;
|
|
goto clear_mime;
|
|
}
|
|
|
|
data_message_detach_mime(msg);
|
|
#if 0
|
|
if (check_privacy)
|
|
mailprivacy_msg_flush(privacy, msg);
|
|
else
|
|
mailmessage_flush(msg);
|
|
#endif
|
|
mailprivacy_msg_flush(privacy, msg);
|
|
mailmessage_free(msg);
|
|
|
|
* result_mime = mime;
|
|
|
|
return MAIL_NO_ERROR;
|
|
|
|
clear_mime:
|
|
mailprivacy_mime_clear(mime);
|
|
mailprivacy_msg_flush(privacy, msg);
|
|
free_msg:
|
|
mailmessage_free(msg);
|
|
err:
|
|
return res;
|
|
}
|
|
|
|
#ifndef LIBETPAN_SYSTEM_BASENAME
|
|
static char * libetpan_basename(char * filename)
|
|
{
|
|
char * next;
|
|
char * p;
|
|
|
|
p = filename;
|
|
next = strchr(p, '/');
|
|
|
|
while (next != NULL) {
|
|
p = next;
|
|
next = strchr(p + 1, '/');
|
|
}
|
|
|
|
if (p == filename)
|
|
return filename;
|
|
else
|
|
return p + 1;
|
|
}
|
|
#else
|
|
#define libetpan_basename(a) basename(a)
|
|
#endif
|
|
|
|
struct mailmime *
|
|
mailprivacy_new_file_part(struct mailprivacy * privacy,
|
|
char * filename,
|
|
char * default_content_type, int default_encoding)
|
|
{
|
|
char basename_buf[PATH_MAX];
|
|
char * name;
|
|
struct mailmime_mechanism * encoding;
|
|
struct mailmime_content * content;
|
|
struct mailmime * mime;
|
|
int r;
|
|
char * dup_filename;
|
|
struct mailmime_fields * mime_fields;
|
|
int encoding_type;
|
|
char * content_type_str;
|
|
int do_encoding;
|
|
|
|
if (filename != NULL) {
|
|
strncpy(basename_buf, filename, PATH_MAX);
|
|
name = libetpan_basename(basename_buf);
|
|
}
|
|
else {
|
|
name = NULL;
|
|
}
|
|
|
|
encoding = NULL;
|
|
|
|
/* default content-type */
|
|
if (default_content_type == NULL)
|
|
content_type_str = "application/octet-stream";
|
|
else
|
|
content_type_str = default_content_type;
|
|
|
|
content = mailmime_content_new_with_str(content_type_str);
|
|
if (content == NULL) {
|
|
goto free_content;
|
|
}
|
|
|
|
do_encoding = 1;
|
|
if (content->ct_type->tp_type == MAILMIME_TYPE_COMPOSITE_TYPE) {
|
|
struct mailmime_composite_type * composite;
|
|
|
|
composite = content->ct_type->tp_data.tp_composite_type;
|
|
|
|
switch (composite->ct_type) {
|
|
case MAILMIME_COMPOSITE_TYPE_MESSAGE:
|
|
if (strcasecmp(content->ct_subtype, "rfc822") == 0)
|
|
do_encoding = 0;
|
|
break;
|
|
|
|
case MAILMIME_COMPOSITE_TYPE_MULTIPART:
|
|
do_encoding = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (do_encoding) {
|
|
if (default_encoding == -1)
|
|
encoding_type = MAILMIME_MECHANISM_BASE64;
|
|
else
|
|
encoding_type = default_encoding;
|
|
|
|
/* default Content-Transfer-Encoding */
|
|
encoding = mailmime_mechanism_new(encoding_type, NULL);
|
|
if (encoding == NULL) {
|
|
goto free_content;
|
|
}
|
|
}
|
|
|
|
mime_fields = mailmime_fields_new_with_data(encoding,
|
|
NULL, NULL, NULL, NULL);
|
|
if (mime_fields == NULL) {
|
|
goto free_content;
|
|
}
|
|
|
|
mime = mailmime_new_empty(content, mime_fields);
|
|
if (mime == NULL) {
|
|
goto free_mime_fields;
|
|
}
|
|
|
|
if ((filename != NULL) && (mime->mm_type == MAILMIME_SINGLE)) {
|
|
/*
|
|
duplicates the file so that the file can be deleted when
|
|
the MIME part is done
|
|
*/
|
|
dup_filename = dup_file(privacy, filename);
|
|
if (dup_filename == NULL) {
|
|
goto free_mime;
|
|
}
|
|
|
|
r = mailmime_set_body_file(mime, dup_filename);
|
|
if (r != MAILIMF_NO_ERROR) {
|
|
free(dup_filename);
|
|
goto free_mime;
|
|
}
|
|
}
|
|
|
|
return mime;
|
|
|
|
free_mime:
|
|
mailmime_free(mime);
|
|
goto err;
|
|
free_mime_fields:
|
|
mailmime_fields_free(mime_fields);
|
|
mailmime_content_free(content);
|
|
goto err;
|
|
free_content:
|
|
if (encoding != NULL)
|
|
mailmime_mechanism_free(encoding);
|
|
if (content != NULL)
|
|
mailmime_content_free(content);
|
|
err:
|
|
return NULL;
|
|
}
|
|
|
|
|
|
int mailmime_substitute(struct mailmime * old_mime,
|
|
struct mailmime * new_mime)
|
|
{
|
|
struct mailmime * parent;
|
|
|
|
parent = old_mime->mm_parent;
|
|
if (parent == NULL)
|
|
return MAIL_ERROR_INVAL;
|
|
|
|
if (old_mime->mm_parent_type == MAILMIME_MESSAGE)
|
|
parent->mm_data.mm_message.mm_msg_mime = new_mime;
|
|
else /* MAILMIME_MULTIPLE */
|
|
old_mime->mm_multipart_pos->data = new_mime;
|
|
new_mime->mm_parent = parent;
|
|
new_mime->mm_parent_type = old_mime->mm_parent_type;
|
|
|
|
/* detach old_mime */
|
|
old_mime->mm_parent = NULL;
|
|
old_mime->mm_parent_type = MAILMIME_NONE;
|
|
|
|
return MAIL_NO_ERROR;
|
|
}
|
|
|
|
|
|
|
|
/* write mime headers and body to a file, CR LF fixed */
|
|
|
|
int mailprivacy_fetch_mime_body_to_file(struct mailprivacy * privacy,
|
|
char * filename, size_t size,
|
|
mailmessage * msg, struct mailmime * mime)
|
|
{
|
|
int r;
|
|
int res;
|
|
FILE * f;
|
|
char * content;
|
|
size_t content_len;
|
|
int col;
|
|
|
|
if (mime->mm_parent_type == MAILMIME_NONE) {
|
|
res = MAIL_ERROR_INVAL;
|
|
goto err;
|
|
}
|
|
|
|
f = mailprivacy_get_tmp_file(privacy, filename, size);
|
|
if (f == NULL) {
|
|
res = MAIL_ERROR_FETCH;
|
|
goto err;
|
|
}
|
|
|
|
r = mailprivacy_msg_fetch_section_mime(privacy, msg, mime,
|
|
&content, &content_len);
|
|
if (r != MAIL_NO_ERROR) {
|
|
res = MAIL_ERROR_FETCH;
|
|
goto Close;
|
|
}
|
|
|
|
col = 0;
|
|
r = mailimf_string_write(f, &col, content, content_len);
|
|
mailprivacy_msg_fetch_result_free(privacy, msg, content);
|
|
if (r != MAILIMF_NO_ERROR) {
|
|
res = r;
|
|
goto Close;
|
|
}
|
|
|
|
r = mailprivacy_msg_fetch_section(privacy, msg, mime,
|
|
&content, &content_len);
|
|
if (r != MAIL_NO_ERROR) {
|
|
res = MAIL_ERROR_FETCH;
|
|
goto Close;
|
|
}
|
|
|
|
r = mailimf_string_write(f, &col, content, content_len);
|
|
mailprivacy_msg_fetch_result_free(privacy, msg, content);
|
|
if (r != MAILIMF_NO_ERROR) {
|
|
res = r;
|
|
goto Close;
|
|
}
|
|
|
|
Fclose(f);
|
|
|
|
return MAIL_NO_ERROR;
|
|
|
|
Close:
|
|
Fclose(f);
|
|
unlink(filename);
|
|
err:
|
|
return res;
|
|
}
|
|
|
|
|
|
int mailprivacy_get_part_from_file(struct mailprivacy * privacy,
|
|
int check_security, int reencode, char * filename,
|
|
struct mailmime ** result_mime)
|
|
{
|
|
int fd;
|
|
struct mailmime * mime;
|
|
int r;
|
|
struct stat stat_info;
|
|
int res;
|
|
char * mapping;
|
|
|
|
fd = Open(filename, O_RDONLY);
|
|
if (fd < 0) {
|
|
res = MAIL_ERROR_FILE;
|
|
goto err;
|
|
}
|
|
|
|
r = fstat(fd, &stat_info);
|
|
if (r < 0) {
|
|
res = MAIL_ERROR_FILE;
|
|
goto Close;
|
|
}
|
|
|
|
mapping = mmap(NULL, stat_info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
|
if (mapping == (char *)MAP_FAILED) {
|
|
res = MAIL_ERROR_FILE;
|
|
goto Close;
|
|
}
|
|
|
|
mime = NULL;
|
|
/* check recursive parts if privacy is set */
|
|
r = mailprivacy_get_mime(privacy, check_security, reencode,
|
|
mapping, stat_info.st_size, &mime);
|
|
if (r != MAIL_NO_ERROR) {
|
|
res = r;
|
|
goto unmap;
|
|
}
|
|
|
|
if (mime->mm_type == MAILMIME_MESSAGE) {
|
|
struct mailmime * submime;
|
|
|
|
submime = mime->mm_data.mm_message.mm_msg_mime;
|
|
if (mime->mm_data.mm_message.mm_msg_mime != NULL) {
|
|
mailmime_remove_part(submime);
|
|
mailmime_free(mime);
|
|
|
|
mime = submime;
|
|
}
|
|
}
|
|
|
|
munmap(mapping, stat_info.st_size);
|
|
|
|
Close(fd);
|
|
|
|
* result_mime = mime;
|
|
|
|
return MAIL_NO_ERROR;
|
|
|
|
unmap:
|
|
munmap(mapping, stat_info.st_size);
|
|
Close:
|
|
Close(fd);
|
|
err:
|
|
return res;
|
|
}
|
|
|
|
int mail_quote_filename(char * result, size_t size, char * path)
|
|
{
|
|
char * p;
|
|
char * result_p;
|
|
size_t remaining;
|
|
|
|
result_p = result;
|
|
remaining = size;
|
|
|
|
for(p = path ; * p != '\0' ; p ++) {
|
|
int quote_not_needed;
|
|
|
|
#if 0
|
|
quote_not_needed = (isalpha(* p) || isdigit(* p) || (* p == '/'));
|
|
#else
|
|
quote_not_needed = (* p != '\\') && (* p != '\'') && (* p != '\"');
|
|
#endif
|
|
if (quote_not_needed) {
|
|
if (remaining > 0) {
|
|
* result_p = * p;
|
|
result_p ++;
|
|
remaining --;
|
|
}
|
|
else {
|
|
result[size - 1] = '\0';
|
|
return -1;
|
|
}
|
|
}
|
|
else {
|
|
if (remaining >= 2) {
|
|
* result_p = '\\';
|
|
result_p ++;
|
|
* result_p = * p;
|
|
result_p ++;
|
|
remaining -= 2;
|
|
}
|
|
else {
|
|
result[size - 1] = '\0';
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
if (remaining > 0) {
|
|
* result_p = '\0';
|
|
}
|
|
else {
|
|
result[size - 1] = '\0';
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void prepare_mime_single(struct mailmime * mime)
|
|
{
|
|
struct mailmime_single_fields single_fields;
|
|
int encoding;
|
|
int r;
|
|
|
|
if (mime->mm_mime_fields != NULL) {
|
|
mailmime_single_fields_init(&single_fields, mime->mm_mime_fields,
|
|
mime->mm_content_type);
|
|
if (single_fields.fld_encoding != NULL) {
|
|
encoding = single_fields.fld_encoding->enc_type;
|
|
switch (encoding) {
|
|
case MAILMIME_MECHANISM_8BIT:
|
|
case MAILMIME_MECHANISM_7BIT:
|
|
case MAILMIME_MECHANISM_BINARY:
|
|
single_fields.fld_encoding->enc_type =
|
|
MAILMIME_MECHANISM_QUOTED_PRINTABLE;
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
struct mailmime_mechanism * mechanism;
|
|
struct mailmime_field * field;
|
|
|
|
mechanism =
|
|
mailmime_mechanism_new(MAILMIME_MECHANISM_QUOTED_PRINTABLE, NULL);
|
|
if (mechanism == NULL)
|
|
return;
|
|
|
|
field = mailmime_field_new(MAILMIME_FIELD_TRANSFER_ENCODING,
|
|
NULL, mechanism, NULL, NULL, 0, NULL, NULL, NULL);
|
|
if (field == NULL) {
|
|
mailmime_mechanism_free(mechanism);
|
|
return;
|
|
}
|
|
|
|
r = clist_append(mime->mm_mime_fields->fld_list, field);
|
|
if (r < 0) {
|
|
mailmime_field_free(field);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mime->mm_type == MAILMIME_SINGLE) {
|
|
switch (mime->mm_data.mm_single->dt_encoding) {
|
|
case MAILMIME_MECHANISM_8BIT:
|
|
case MAILMIME_MECHANISM_7BIT:
|
|
case MAILMIME_MECHANISM_BINARY:
|
|
mime->mm_data.mm_single->dt_encoding =
|
|
MAILMIME_MECHANISM_QUOTED_PRINTABLE;
|
|
mime->mm_data.mm_single->dt_encoded = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
mailprivacy_prepare_mime()
|
|
|
|
we assume we built ourself the message.
|
|
*/
|
|
|
|
void mailprivacy_prepare_mime(struct mailmime * mime)
|
|
{
|
|
clistiter * cur;
|
|
|
|
switch (mime->mm_type) {
|
|
case MAILMIME_SINGLE:
|
|
if (mime->mm_data.mm_single != NULL) {
|
|
prepare_mime_single(mime);
|
|
}
|
|
break;
|
|
|
|
case MAILMIME_MULTIPLE:
|
|
for(cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list) ;
|
|
cur != NULL ; cur = clist_next(cur)) {
|
|
struct mailmime * child;
|
|
|
|
child = clist_content(cur);
|
|
|
|
mailprivacy_prepare_mime(child);
|
|
}
|
|
break;
|
|
|
|
case MAILMIME_MESSAGE:
|
|
if (mime->mm_data.mm_message.mm_msg_mime) {
|
|
mailprivacy_prepare_mime(mime->mm_data.mm_message.mm_msg_mime);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
char * mailprivacy_dup_imf_file(struct mailprivacy * privacy,
|
|
char * source_filename)
|
|
{
|
|
char filename[PATH_MAX];
|
|
FILE * dest_f;
|
|
int r;
|
|
struct stat stat_info;
|
|
char * dest_filename;
|
|
char * mapping;
|
|
int fd;
|
|
int col;
|
|
|
|
dest_f = mailprivacy_get_tmp_file(privacy,
|
|
filename, sizeof(filename));
|
|
if (dest_f == NULL)
|
|
goto err;
|
|
|
|
dest_filename = strdup(filename);
|
|
if (dest_filename == NULL)
|
|
goto close_dest;
|
|
|
|
fd = Open(source_filename, O_RDONLY);
|
|
if (fd < 0)
|
|
goto free_dest;
|
|
|
|
r = fstat(fd, &stat_info);
|
|
if (r < 0)
|
|
goto close_src;
|
|
|
|
mapping = mmap(NULL, stat_info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
|
if (mapping == (char *)MAP_FAILED)
|
|
goto close_src;
|
|
|
|
col = 0;
|
|
r = mailimf_string_write(dest_f, &col, mapping, stat_info.st_size);
|
|
if (r != MAILIMF_NO_ERROR)
|
|
goto unmap;
|
|
|
|
munmap(mapping, stat_info.st_size);
|
|
Close(fd);
|
|
Fclose(dest_f);
|
|
|
|
return dest_filename;
|
|
|
|
unmap:
|
|
munmap(mapping, stat_info.st_size);
|
|
close_src:
|
|
Close(fd);
|
|
free_dest:
|
|
free(dest_filename);
|
|
close_dest:
|
|
Fclose(dest_f);
|
|
err:
|
|
return NULL;
|
|
}
|
|
|
|
/* TODO : better function to duplicate mime fields, currenly such inelegant */
|
|
|
|
struct mailmime_fields *
|
|
mailprivacy_mime_fields_dup(struct mailprivacy * privacy,
|
|
struct mailmime_fields * mime_fields)
|
|
{
|
|
FILE * f;
|
|
char tmp_file[PATH_MAX];
|
|
int col;
|
|
int r;
|
|
struct mailmime_fields * dup_mime_fields;
|
|
int fd;
|
|
char * mapping;
|
|
struct stat stat_info;
|
|
struct mailimf_fields * fields;
|
|
size_t cur_token;
|
|
|
|
f = mailprivacy_get_tmp_file(privacy, tmp_file, sizeof(tmp_file));
|
|
if (f == NULL)
|
|
goto err;
|
|
|
|
col = 0;
|
|
r = mailmime_fields_write(f, &col, mime_fields);
|
|
if (r != MAILIMF_NO_ERROR)
|
|
goto unlink;
|
|
|
|
Fflush(f);
|
|
|
|
fd = fileno(f);
|
|
if (fd == -1)
|
|
goto unlink;
|
|
|
|
r = fstat(fd, &stat_info);
|
|
if (r < 0)
|
|
goto unlink;
|
|
|
|
mapping = mmap(NULL, stat_info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
|
if (mapping == (char *)MAP_FAILED)
|
|
goto unlink;
|
|
|
|
cur_token = 0;
|
|
r = mailimf_optional_fields_parse(mapping, stat_info.st_size,
|
|
&cur_token, &fields);
|
|
if (r != MAILIMF_NO_ERROR)
|
|
goto unmap;
|
|
|
|
r = mailmime_fields_parse(fields, &dup_mime_fields);
|
|
mailimf_fields_free(fields);
|
|
if (r != MAILIMF_NO_ERROR)
|
|
goto unmap;
|
|
|
|
munmap(mapping, stat_info.st_size);
|
|
Fclose(f);
|
|
unlink(tmp_file);
|
|
|
|
return dup_mime_fields;
|
|
|
|
unmap:
|
|
munmap(mapping, stat_info.st_size);
|
|
unlink:
|
|
Fclose(f);
|
|
unlink(tmp_file);
|
|
err:
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
struct mailmime_parameter *
|
|
mailmime_parameter_dup(struct mailmime_parameter * param)
|
|
{
|
|
char * name;
|
|
char * value;
|
|
struct mailmime_parameter * dup_param;
|
|
|
|
name = strdup(param->pa_name);
|
|
if (name == NULL)
|
|
goto err;
|
|
|
|
value = strdup(param->pa_value);
|
|
if (value == NULL)
|
|
goto free_name;
|
|
|
|
dup_param = mailmime_parameter_new(name, value);
|
|
if (dup_param == NULL)
|
|
goto free_value;
|
|
|
|
return dup_param;
|
|
|
|
free_value:
|
|
free(value);
|
|
free_name:
|
|
free(name);
|
|
err:
|
|
return NULL;
|
|
}
|
|
|
|
struct mailmime_composite_type *
|
|
mailmime_composite_type_dup(struct mailmime_composite_type * composite_type)
|
|
{
|
|
struct mailmime_composite_type * dup_composite;
|
|
char * token;
|
|
|
|
token = NULL;
|
|
if (composite_type->ct_token != NULL) {
|
|
token = strdup(composite_type->ct_token);
|
|
if (token == NULL)
|
|
goto err;
|
|
}
|
|
|
|
dup_composite = mailmime_composite_type_new(composite_type->ct_type, token);
|
|
if (dup_composite == NULL)
|
|
goto free_token;
|
|
|
|
return dup_composite;
|
|
|
|
free_token:
|
|
if (token != NULL)
|
|
free(token);
|
|
err:
|
|
return NULL;
|
|
}
|
|
|
|
struct mailmime_discrete_type *
|
|
mailmime_discrete_type_dup(struct mailmime_discrete_type * discrete_type)
|
|
{
|
|
struct mailmime_discrete_type * dup_discrete;
|
|
char * extension;
|
|
|
|
extension = NULL;
|
|
if (discrete_type->dt_extension != NULL) {
|
|
extension = strdup(discrete_type->dt_extension);
|
|
if (extension == NULL)
|
|
goto err;
|
|
}
|
|
|
|
dup_discrete = mailmime_discrete_type_new(discrete_type->dt_type, extension);
|
|
if (dup_discrete == NULL)
|
|
goto free_extension;
|
|
|
|
return dup_discrete;
|
|
|
|
free_extension:
|
|
if (extension != NULL)
|
|
free(extension);
|
|
err:
|
|
return NULL;
|
|
}
|
|
|
|
struct mailmime_type * mailmime_type_dup(struct mailmime_type * type)
|
|
{
|
|
struct mailmime_type * dup_type;
|
|
struct mailmime_discrete_type * discrete_type;
|
|
struct mailmime_composite_type * composite_type;
|
|
|
|
discrete_type = NULL;
|
|
composite_type = NULL;
|
|
switch (type->tp_type) {
|
|
case MAILMIME_TYPE_DISCRETE_TYPE:
|
|
discrete_type =
|
|
mailmime_discrete_type_dup(type->tp_data.tp_discrete_type);
|
|
if (discrete_type == NULL)
|
|
goto err;
|
|
break;
|
|
|
|
composite_type =
|
|
mailmime_composite_type_dup(type->tp_data.tp_composite_type);
|
|
if (composite_type == NULL)
|
|
goto free_discrete;
|
|
}
|
|
|
|
dup_type = mailmime_type_new(type->tp_type, discrete_type, composite_type);
|
|
if (dup_type == NULL)
|
|
goto free_composite;
|
|
|
|
return dup_type;
|
|
|
|
free_composite:
|
|
if (composite_type != NULL)
|
|
mailmime_composite_type_free(composite_type);
|
|
free_discrete:
|
|
if (discrete_type != NULL)
|
|
mailmime_discrete_type_free(discrete_type);
|
|
err:
|
|
return NULL;
|
|
}
|
|
|
|
struct mailmime_content *
|
|
mailmime_content_dup(struct mailmime_content * content)
|
|
{
|
|
clist * list;
|
|
struct mailmime_type * type;
|
|
int r;
|
|
struct mailmime_content * dup_content;
|
|
char * subtype;
|
|
|
|
type = mailmime_type_dup(content->ct_type);
|
|
if (type == NULL)
|
|
goto err;
|
|
|
|
subtype = strdup(content->ct_subtype);
|
|
if (subtype == NULL)
|
|
goto free_type;
|
|
|
|
list = clist_new();
|
|
if (list == NULL)
|
|
goto free_subtype;
|
|
|
|
if (content->ct_parameters != NULL) {
|
|
clistiter * cur;
|
|
|
|
for(cur = clist_begin(content->ct_parameters) ;
|
|
cur != NULL ; cur = clist_next(cur)) {
|
|
struct mailmime_parameter * param;
|
|
|
|
param = mailmime_parameter_dup(clist_content(cur));
|
|
if (param == NULL)
|
|
goto free_list;
|
|
|
|
r = clist_append(list, param);
|
|
if (r < 0) {
|
|
mailmime_parameter_free(param);
|
|
goto free_list;
|
|
}
|
|
}
|
|
}
|
|
|
|
dup_content = mailmime_content_new(type, subtype, list);
|
|
if (dup_content == NULL)
|
|
goto free_list;
|
|
|
|
return dup_content;
|
|
|
|
free_list:
|
|
clist_foreach(list, (clist_func) mailmime_parameter_free, NULL);
|
|
free_subtype:
|
|
free(subtype);
|
|
free_type:
|
|
mailmime_type_free(type);
|
|
err:
|
|
return NULL;
|
|
}
|
|
|
|
|
|
int mailprivacy_fetch_decoded_to_file(struct mailprivacy * privacy,
|
|
char * filename, size_t size,
|
|
mailmessage * msg, struct mailmime * mime)
|
|
{
|
|
int r;
|
|
int res;
|
|
FILE * f;
|
|
char * content;
|
|
size_t content_len;
|
|
size_t written;
|
|
struct mailmime_single_fields single_fields;
|
|
int encoding;
|
|
size_t cur_token;
|
|
char * parsed_content;
|
|
size_t parsed_content_len;
|
|
|
|
mailmime_single_fields_init(&single_fields, mime->mm_mime_fields,
|
|
mime->mm_content_type);
|
|
if (single_fields.fld_encoding != NULL)
|
|
encoding = single_fields.fld_encoding->enc_type;
|
|
else
|
|
encoding = MAILMIME_MECHANISM_8BIT;
|
|
|
|
r = mailprivacy_msg_fetch_section(privacy, msg, mime,
|
|
&content, &content_len);
|
|
if (r != MAIL_NO_ERROR) {
|
|
res = MAIL_ERROR_FETCH;
|
|
goto err;
|
|
}
|
|
|
|
cur_token = 0;
|
|
r = mailmime_part_parse(content, content_len, &cur_token,
|
|
encoding, &parsed_content, &parsed_content_len);
|
|
mailprivacy_msg_fetch_result_free(privacy, msg, content);
|
|
if (r != MAILIMF_NO_ERROR) {
|
|
res = MAIL_ERROR_PARSE;
|
|
goto err;
|
|
}
|
|
|
|
f = mailprivacy_get_tmp_file(privacy, filename, size);
|
|
if (f == NULL) {
|
|
res = MAIL_ERROR_FETCH;
|
|
goto free_fetch;
|
|
}
|
|
written = Fwrite(parsed_content, 1, parsed_content_len, f);
|
|
if (written != parsed_content_len) {
|
|
res = MAIL_ERROR_FILE;
|
|
goto Close;
|
|
}
|
|
Fclose(f);
|
|
|
|
mmap_string_unref(parsed_content);
|
|
|
|
return MAIL_NO_ERROR;
|
|
|
|
Close:
|
|
Fclose(f);
|
|
unlink(filename);
|
|
free_fetch:
|
|
mmap_string_unref(parsed_content);
|
|
err:
|
|
return res;
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_MINGW32_SYSTEM
|
|
/* Define to 1 do enable debugging. */
|
|
#define DEBUG_W32_SPAWN 0
|
|
|
|
/* Create pipe where the read end is inheritable. */
|
|
static int
|
|
create_inheritable_pipe (HANDLE filedes[2])
|
|
{
|
|
HANDLE r, w, h;
|
|
SECURITY_ATTRIBUTES sec_attr;
|
|
|
|
memset (&sec_attr, 0, sizeof sec_attr);
|
|
sec_attr.nLength = sizeof sec_attr;
|
|
sec_attr.bInheritHandle = FALSE;
|
|
|
|
if (!CreatePipe (&r, &w, &sec_attr, 0))
|
|
return -1;
|
|
|
|
if (!DuplicateHandle (GetCurrentProcess(), r,
|
|
GetCurrentProcess(), &h, 0,
|
|
TRUE, DUPLICATE_SAME_ACCESS ))
|
|
{
|
|
CloseHandle (r);
|
|
CloseHandle (w);
|
|
return -1;
|
|
}
|
|
CloseHandle (w);
|
|
w = h;
|
|
|
|
filedes[0] = r;
|
|
filedes[1] = w;
|
|
return 0;
|
|
}
|
|
#endif /*HAVE_MINGW32_SYSTEM*/
|
|
|
|
|
|
int mailprivacy_spawn_and_wait(char * command, char * passphrase,
|
|
char * stdoutfile, char * stderrfile,
|
|
int * bad_passphrase)
|
|
{
|
|
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
|
|
//https://github.com/dinhviethoa/libetpan/issues/275
|
|
//mailprivacy_spawn_and_wait is not needed on iOS
|
|
return MAIL_ERROR_COMMAND;
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
int res;
|
|
SECURITY_ATTRIBUTES sec_attr;
|
|
PROCESS_INFORMATION pi =
|
|
{
|
|
NULL, /* Returns process handle. */
|
|
0, /* Returns primary thread handle. */
|
|
0, /* Returns pid. */
|
|
0 /* Returns tid. */
|
|
};
|
|
STARTUPINFO si;
|
|
int cr_flags;
|
|
HANDLE wp_passphrase[2];
|
|
HANDLE fd_out;
|
|
HANDLE fd_err;
|
|
int code;
|
|
|
|
/* Prepare security attributes. */
|
|
memset (&sec_attr, 0, sizeof sec_attr);
|
|
sec_attr.nLength = sizeof sec_attr;
|
|
sec_attr.bInheritHandle = TRUE;
|
|
|
|
fd_out = CreateFile (stdoutfile,
|
|
GENERIC_READ|GENERIC_WRITE,
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
|
&sec_attr,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
if (fd_out == INVALID_HANDLE_VALUE)
|
|
{
|
|
res = ERROR_PASSPHRASE_FILE;
|
|
goto err;
|
|
}
|
|
|
|
fd_err = CreateFile (stderrfile,
|
|
GENERIC_READ|GENERIC_WRITE,
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
|
&sec_attr,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
if (fd_err == INVALID_HANDLE_VALUE)
|
|
{
|
|
res = ERROR_PASSPHRASE_FILE;
|
|
goto close_out;
|
|
}
|
|
|
|
/* Create a pipe for the passphrase. */
|
|
if (create_inheritable_pipe (wp_passphrase))
|
|
{
|
|
res = ERROR_PASSPHRASE_FILE;
|
|
goto close_err;
|
|
}
|
|
|
|
/* Prepare security attributes. */
|
|
memset (&sec_attr, 0, sizeof sec_attr);
|
|
sec_attr.nLength = sizeof sec_attr;
|
|
sec_attr.bInheritHandle = FALSE;
|
|
|
|
/* Start the process. */
|
|
memset (&si, 0, sizeof si);
|
|
si.cb = sizeof (si);
|
|
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
|
|
si.wShowWindow = DEBUG_W32_SPAWN ? SW_SHOW : SW_MINIMIZE;
|
|
si.hStdInput = wp_passphrase[0];
|
|
si.hStdOutput = fd_out;
|
|
si.hStdError = fd_err;
|
|
|
|
cr_flags = (CREATE_DEFAULT_ERROR_MODE
|
|
| GetPriorityClass (GetCurrentProcess ())
|
|
| CREATE_SUSPENDED);
|
|
if (!CreateProcess (NULL, /* Program to start. */
|
|
command, /* Command line arguments. */
|
|
&sec_attr, /* Process security attributes. */
|
|
&sec_attr, /* Thread security attributes. */
|
|
TRUE, /* Inherit handles. */
|
|
cr_flags, /* Creation flags. */
|
|
NULL, /* Environment. */
|
|
NULL, /* Use current drive/directory. */
|
|
&si, /* Startup information. */
|
|
&pi /* Returns process information. */
|
|
))
|
|
{
|
|
CloseHandle (wp_passphrase[0]);
|
|
CloseHandle (wp_passphrase[1]);
|
|
|
|
res = ERROR_PASSPHRASE_COMMAND;
|
|
goto close_err;
|
|
}
|
|
|
|
/* Close the other end of the pipe. */
|
|
CloseHandle (wp_passphrase[0]);
|
|
CloseHandle (fd_out);
|
|
CloseHandle (fd_err);
|
|
/* Process has been created suspended; resume it now. */
|
|
ResumeThread (pi.hThread);
|
|
CloseHandle (pi.hThread);
|
|
|
|
if ((passphrase != NULL) && (strlen(passphrase) > 0)) {
|
|
DWORD written;
|
|
WriteFile (wp_passphrase[1], passphrase, strlen(passphrase),
|
|
&written, NULL);
|
|
}
|
|
else {
|
|
DWORD written;
|
|
/* dummy password */
|
|
WriteFile(wp_passphrase[1], "*dummy*", 7, &written, NULL);
|
|
}
|
|
CloseHandle(wp_passphrase[1]);
|
|
|
|
code = WaitForSingleObject (pi.hProcess, INFINITE);
|
|
if (code == WAIT_OBJECT_0)
|
|
{
|
|
DWORD exc;
|
|
if (GetExitCodeProcess (pi.hProcess, &exc))
|
|
{
|
|
if (exc)
|
|
*bad_passphrase = 1;
|
|
}
|
|
else
|
|
res = ERROR_PASSPHRASE_COMMAND;
|
|
}
|
|
else
|
|
res = ERROR_PASSPHRASE_COMMAND;
|
|
|
|
CloseHandle (pi.hProcess);
|
|
return 0;
|
|
|
|
close_err:
|
|
CloseHandle (fd_err);
|
|
close_out:
|
|
CloseHandle (fd_out);
|
|
err:
|
|
return res;
|
|
#else
|
|
int res;
|
|
int fd_out;
|
|
int fd_err;
|
|
pid_t pid;
|
|
int passphrase_input[2];
|
|
int r;
|
|
|
|
fd_out = Open(stdoutfile, O_RDWR | O_CREAT | O_TRUNC, 0600);
|
|
if (fd_out < 0) {
|
|
res = ERROR_PASSPHRASE_FILE;
|
|
goto err;
|
|
}
|
|
|
|
fd_err = Open(stderrfile, O_RDWR | O_CREAT | O_TRUNC, 0600);
|
|
if (fd_err < 0) {
|
|
res = ERROR_PASSPHRASE_FILE;
|
|
goto close_out;
|
|
}
|
|
|
|
r = pipe(passphrase_input);
|
|
if (r < 0) {
|
|
res = ERROR_PASSPHRASE_FILE;
|
|
goto close_err;
|
|
}
|
|
|
|
pid = fork();
|
|
switch (pid) {
|
|
case -1:
|
|
{
|
|
Close(passphrase_input[0]);
|
|
Close(passphrase_input[1]);
|
|
res = ERROR_PASSPHRASE_COMMAND;
|
|
goto close_err;
|
|
}
|
|
|
|
case 0:
|
|
/* child */
|
|
{
|
|
int status;
|
|
|
|
/* close unneeded fd */
|
|
Close(passphrase_input[1]);
|
|
|
|
Dup2(passphrase_input[0], 0);
|
|
Close(passphrase_input[0]);
|
|
Dup2(fd_out, 1);
|
|
Close(fd_out);
|
|
Dup2(fd_err, 2);
|
|
Close(fd_err);
|
|
|
|
#if !TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
|
|
//https://github.com/dinhviethoa/libetpan/issues/275
|
|
//system() is not supported on iOS 11.
|
|
|
|
// BUG: status may be -1 and errno may be EINTR if waitpid(2) was
|
|
// interrupted by a signal; to handle that properly the PID of the
|
|
// fork(2)ed child has to be determined and waitpid(2) has to be
|
|
// called again
|
|
status = system(command);
|
|
#endif
|
|
|
|
exit(WEXITSTATUS(status));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
/* parent */
|
|
{
|
|
int status;
|
|
|
|
/* close unneeded fd */
|
|
Close(fd_err);
|
|
Close(fd_out);
|
|
Close(passphrase_input[0]);
|
|
|
|
if ((passphrase != NULL) && (strlen(passphrase) > 0)) {
|
|
do {
|
|
r = (int) Write(passphrase_input[1], passphrase, strlen(passphrase));
|
|
} while (r == -1 && errno == EINTR);
|
|
if (r != (int) strlen(passphrase)) {
|
|
Close(passphrase_input[1]);
|
|
return ERROR_PASSPHRASE_FILE;
|
|
}
|
|
}
|
|
else {
|
|
/* dummy password */
|
|
r = (int) Write(passphrase_input[1], "*dummy*", 7);
|
|
if (r != 7) {
|
|
Close(passphrase_input[1]);
|
|
return ERROR_PASSPHRASE_FILE;
|
|
}
|
|
}
|
|
Close(passphrase_input[1]);
|
|
|
|
r = Waitpid(pid, &status, 0);
|
|
|
|
if (WEXITSTATUS(status) != 0)
|
|
*bad_passphrase = 1;
|
|
|
|
return MAIL_NO_ERROR;
|
|
}
|
|
break;
|
|
}
|
|
|
|
close_err:
|
|
Close(fd_err);
|
|
close_out:
|
|
Close(fd_out);
|
|
err:
|
|
return res;
|
|
#endif
|
|
}
|
|
|
|
|