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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
static int smime_encrypt(struct mailprivacy * privacy,
    mailmessage * msg,
    struct mailmime * mime, struct mailmime ** result)
{
  char encrypted_filename[PATH_MAX];
  int res;
  int r;
  int col;
  char description_filename[PATH_MAX];
  char decrypted_filename[PATH_MAX];
  FILE * decrypted_f;
  char command[PATH_MAX];
  char quoted_decrypted_filename[PATH_MAX];
  struct mailmime * encrypted_mime;
  struct mailmime * root;
  struct mailimf_fields * fields;
  char recipient[PATH_MAX];
  
  root = mime;
  while (root->mm_parent != NULL)
    root = root->mm_parent;
  
  fields = NULL;
  if (root->mm_type == MAILMIME_MESSAGE)
    fields = root->mm_data.mm_message.mm_fields;

  /* recipient */
  r = collect_smime_cert(recipient, sizeof(recipient), fields);
  if (r != MAIL_NO_ERROR) {
    res = r;
    goto err;
  }

  /* part to encrypt */

  /* encode quoted printable all text parts */
  
  mailprivacy_prepare_mime(mime);
  
  decrypted_f = mailprivacy_get_tmp_file(privacy,
      decrypted_filename,
      sizeof(decrypted_filename));
  if (decrypted_f == NULL) {
    res = MAIL_ERROR_FILE;
    goto err;
  }
  
  col = 0;
  r = mailmime_write(decrypted_f, &col, mime);
  if (r != MAILIMF_NO_ERROR) {
    fclose(decrypted_f);
    res = MAIL_ERROR_FILE;
    goto unlink_decrypted;
  }
  
  fclose(decrypted_f);
  
  /* prepare destination file for encryption */
  
  r = mailprivacy_get_tmp_filename(privacy, encrypted_filename,
      sizeof(encrypted_filename));
  if (r != MAIL_NO_ERROR) {
    res = MAIL_ERROR_FILE;
    goto unlink_decrypted;
  }
  
  r = mailprivacy_get_tmp_filename(privacy, description_filename,
      sizeof(description_filename));
  if (r != MAIL_NO_ERROR) {
    res = MAIL_ERROR_FILE;
    goto unlink_encrypted;
  }
  
  r = mail_quote_filename(quoted_decrypted_filename,
      sizeof(quoted_decrypted_filename), decrypted_filename);
  if (r < 0) {
    res = MAIL_ERROR_MEMORY;
    goto unlink_description;
  }
  
  snprintf(command, sizeof(command), "openssl smime -encrypt -in '%s' %s",
      quoted_decrypted_filename, recipient);
  
  r = smime_command_passphrase(privacy, msg, command,
      NULL, encrypted_filename, description_filename);
  switch (r) {
  case NO_ERROR_SMIME:
    break;
  case ERROR_SMIME_NOPASSPHRASE:
  case ERROR_SMIME_CHECK:
    res = MAIL_ERROR_COMMAND;
    goto unlink_description;
    break;
  case ERROR_SMIME_COMMAND:
    res = MAIL_ERROR_COMMAND;
    goto unlink_encrypted;
  case ERROR_SMIME_FILE:
    res = MAIL_ERROR_FILE;
    goto unlink_description;
  }
  
  /* encrypted part */
  
  r = mailprivacy_get_part_from_file(privacy, 0, 0,
      encrypted_filename, &encrypted_mime);
  if (r != MAIL_NO_ERROR) {
    res = r;
    goto unlink_description;
  }
  strip_mime_headers(encrypted_mime);

  unlink(description_filename);
  unlink(encrypted_filename);
  unlink(decrypted_filename);
  
  * result = encrypted_mime;
  
  return MAIL_NO_ERROR;

 unlink_description:
  unlink(description_filename);
 unlink_encrypted:
  unlink(encrypted_filename);
 unlink_decrypted:
  unlink(decrypted_filename);
 err:
  return res;
}
static int smime_sign(struct mailprivacy * privacy,
    mailmessage * msg,
    struct mailmime * mime, struct mailmime ** result)
{
  char signed_filename[PATH_MAX];
  FILE * signed_f;
  int res;
  int r;
  int col;
  char description_filename[PATH_MAX];
  char signature_filename[PATH_MAX];
  char command[PATH_MAX];
  char quoted_signed_filename[PATH_MAX];
  struct mailmime * signed_mime;
  char * smime_cert;
  char * smime_key;
  char quoted_smime_cert[PATH_MAX];
  char quoted_smime_key[PATH_MAX];
  char * email;
  
  /* get signing key */
  
  email = get_first_from_addr(mime);
  if (email == NULL) {
    res = MAIL_ERROR_INVAL;
    goto err;
  }
  
  smime_key = get_private_key_file(email);
  smime_cert = get_cert_file(email);
  if ((smime_cert == NULL) || (smime_key == NULL)) {
    res = MAIL_ERROR_INVAL;
    goto err;
  }

  /* part to sign */

  /* encode quoted printable all text parts */
  
  mailprivacy_prepare_mime(mime);
  
  signed_f = mailprivacy_get_tmp_file(privacy,
      signed_filename, sizeof(signed_filename));
  if (signed_f == NULL) {
    res = MAIL_ERROR_FILE;
    goto err;
  }
  
  col = 0;
  r = mailmime_write(signed_f, &col, mime);
  if (r != MAILIMF_NO_ERROR) {
    fclose(signed_f);
    res = MAIL_ERROR_FILE;
    goto unlink_signed;
  }
  
  fclose(signed_f);
  
  /* prepare destination file for signature */
  
  r = mailprivacy_get_tmp_filename(privacy, signature_filename,
      sizeof(signature_filename));
  if (r != MAIL_NO_ERROR) {
    res = r;
    goto unlink_signed;
  }

  r = mailprivacy_get_tmp_filename(privacy, description_filename,
      sizeof(description_filename));
  if (r != MAIL_NO_ERROR) {
    res = r;
    goto unlink_signature;
  }
  
  r = mail_quote_filename(quoted_signed_filename,
       sizeof(quoted_signed_filename), signed_filename);
  if (r < 0) {
    res = MAIL_ERROR_MEMORY;
    goto unlink_description;
  }
  
  r = mail_quote_filename(quoted_smime_key,
       sizeof(quoted_smime_key), smime_key);
  if (r < 0) {
    res = MAIL_ERROR_MEMORY;
    goto unlink_description;
  }

  r = mail_quote_filename(quoted_smime_cert,
       sizeof(quoted_smime_cert), smime_cert);
  if (r < 0) {
    res = MAIL_ERROR_MEMORY;
    goto unlink_description;
  }

  snprintf(command, sizeof(command),
      "openssl smime -sign -passin fd:0 -in '%s' -signer '%s' -inkey '%s'",
      quoted_signed_filename,
      quoted_smime_cert, quoted_smime_key);

  r = smime_command_passphrase(privacy, msg, command,
      email, signature_filename, description_filename);
  switch (r) {
  case NO_ERROR_SMIME:
    break;
  case ERROR_SMIME_NOPASSPHRASE:
  case ERROR_SMIME_CHECK:
    res = MAIL_ERROR_COMMAND;
    goto unlink_description;
    break;
  case ERROR_SMIME_COMMAND:
    res = MAIL_ERROR_COMMAND;
    goto unlink_description;
  case ERROR_SMIME_FILE:
    res = MAIL_ERROR_FILE;
    goto unlink_description;
  }
  
  /* signature part */
  
  r = mailprivacy_get_part_from_file(privacy, 0, 0,
      signature_filename, &signed_mime);
  if (r != MAIL_NO_ERROR) {
    res = r;
    goto unlink_description;
  }
  strip_mime_headers(signed_mime);
  
  unlink(description_filename);
  /* unlink(signature_filename); */
  /* unlink(signed_filename); */
  
  * result = signed_mime;
  
  return MAIL_NO_ERROR;
  
 unlink_description:
  unlink(description_filename);
 unlink_signature:
  unlink(signature_filename);
 unlink_signed:
  unlink(signed_filename);
 err:
  return res;
}
static int smime_decrypt(struct mailprivacy * privacy,
    mailmessage * msg,
    struct mailmime * mime, struct mailmime ** result)
{
  char smime_filename[PATH_MAX];
  char quoted_smime_filename[PATH_MAX];
  char description_filename[PATH_MAX];
  char decrypted_filename[PATH_MAX];
  char command[PATH_MAX];
  struct mailmime * description_mime;
  struct mailmime * decrypted_mime;
  int r;
  int res;
  int sign_ok;
  struct mailmime * multipart;
  char * smime_cert;
  char * smime_key;
  char quoted_smime_cert[PATH_MAX];
  char quoted_smime_key[PATH_MAX];
  char * email;
  chashiter * iter;
  
  /* fetch the whole multipart and write it to a file */
  
  r = mailprivacy_fetch_mime_body_to_file(privacy,
      smime_filename, sizeof(smime_filename),
      msg, mime);
  if (r != MAIL_NO_ERROR) {
    res = r;
    goto err;
  }
  
  /* we are in a safe directory */
  
  r = mailprivacy_get_tmp_filename(privacy, decrypted_filename,
      sizeof(decrypted_filename));
  if (r != MAIL_NO_ERROR) {
    res = MAIL_ERROR_FILE;
    goto unlink_smime;
  }
  
  /* description */
  
  r = mailprivacy_get_tmp_filename(privacy, description_filename,
      sizeof(description_filename));
  if (r != MAIL_NO_ERROR) {
    res = MAIL_ERROR_FILE;
    goto unlink_decrypted;
  }
  
  sign_ok = 0;
  for(iter = chash_begin(private_keys) ; iter != NULL ;
      iter = chash_next(private_keys, iter)) {
    chashdatum key;
    char email_buf[BUF_SIZE];
    
    chash_key(iter, &key);
    
    if (key.len >= sizeof(email_buf))
      continue;
    
    strncpy(email_buf, key.data, key.len);
    email_buf[key.len] = '\0';
    email = email_buf;
    
    /* get encryption key */
    
    smime_key = get_private_key_file(email);
    smime_cert = get_cert_file(email);
    if ((smime_cert == NULL) || (smime_key == NULL)) {
      res = MAIL_ERROR_INVAL;
      goto unlink_description;
    }
  
    r = mail_quote_filename(quoted_smime_cert, sizeof(quoted_smime_cert),
        smime_cert);
    if (r < 0) {
      res = MAIL_ERROR_MEMORY;
      goto unlink_description;
    }
  
    r = mail_quote_filename(quoted_smime_key, sizeof(quoted_smime_key),
        smime_key);
    if (r < 0) {
      res = MAIL_ERROR_MEMORY;
      goto unlink_description;
    }
  
    /* run the command */
  
    r = mail_quote_filename(quoted_smime_filename,
        sizeof(quoted_smime_filename), smime_filename);
    if (r < 0) {
      res = MAIL_ERROR_MEMORY;
      goto unlink_description;
    }
    
    sign_ok = 0;
    snprintf(command, sizeof(command),
        "openssl smime -decrypt -passin fd:0 -in '%s' -inkey '%s' -recip '%s'",
        quoted_smime_filename, quoted_smime_key, quoted_smime_cert);
    
    unlink(description_filename);
    r = smime_command_passphrase(privacy, msg, command,
        email, decrypted_filename, description_filename);
    switch (r) {
    case NO_ERROR_SMIME:
      sign_ok = 1;
      break;
    case ERROR_SMIME_CHECK:
    case ERROR_SMIME_NOPASSPHRASE:
      sign_ok = 0;
      break;
    case ERROR_SMIME_COMMAND:
      res = MAIL_ERROR_COMMAND;
      goto unlink_description;
    case ERROR_SMIME_FILE:
      res = MAIL_ERROR_FILE;
      goto unlink_description;
    }
    
    if (sign_ok) {
      break;
    }
  }
  
  if (!sign_ok) {
    if (chash_count(private_keys) == 0) {
      FILE * description_f;
      
      description_f = mailprivacy_get_tmp_file(privacy, description_filename,
          sizeof(description_filename));
      if (description_f == NULL) {
        res = MAIL_ERROR_FILE;
        goto unlink_decrypted;
      }
      fprintf(description_f, SMIME_DECRYPT_FAILED);
      fclose(description_f);
    }
  }
  else {
    mailprivacy_smime_encryption_id_list_clear(privacy, msg);
  }
  
  /* building multipart */

  r = mailmime_new_with_content("multipart/x-decrypted", NULL, &multipart);
  if (r != MAILIMF_NO_ERROR) {
    res = MAIL_ERROR_MEMORY;
    goto unlink_description;
  }
  
  /* building the description part */
  
  description_mime = mailprivacy_new_file_part(privacy,
      description_filename,
      "text/plain", MAILMIME_MECHANISM_8BIT);
  if (description_mime == NULL) {
    mailprivacy_mime_clear(multipart);
    mailmime_free(multipart);
    res = MAIL_ERROR_MEMORY;
    goto unlink_description;
  }
  
  /* adds the description part */
  
  r = mailmime_smart_add_part(multipart, description_mime);
  if (r != MAIL_NO_ERROR) {
    mailprivacy_mime_clear(description_mime);
    mailmime_free(description_mime);
    mailprivacy_mime_clear(multipart);
    mailmime_free(multipart);
    res = MAIL_ERROR_MEMORY;
    goto unlink_description;
  }
  
  /* building the decrypted part */
  
  r = mailprivacy_get_part_from_file(privacy, 1, 0,
      decrypted_filename, &decrypted_mime);
  if (r == MAIL_NO_ERROR) {
    /* adds the decrypted part */
    
    r = mailmime_smart_add_part(multipart, decrypted_mime);
    if (r != MAIL_NO_ERROR) {
      mailprivacy_mime_clear(decrypted_mime);
      mailmime_free(decrypted_mime);
      mailprivacy_mime_clear(multipart);
      mailmime_free(multipart);
      res = MAIL_ERROR_MEMORY;
      goto unlink_description;
    }
  }
  
  unlink(description_filename);
  unlink(decrypted_filename);
  unlink(smime_filename);
  
  * result = multipart;
  
  return MAIL_NO_ERROR;
  
 unlink_description:
  unlink(description_filename);
 unlink_decrypted:
  unlink(decrypted_filename);
 unlink_smime:
  unlink(smime_filename);
 err:
  return res;
}
void mailprivacy_smime_set_CA_dir(struct mailprivacy * privacy,
    char * directory)
{
  DIR * dir;
  struct dirent * ent;
  FILE * f_CA;
  char CA_filename[PATH_MAX];
  
  if (directory == NULL)
    return;
  
  if (* directory == '\0')
    return;
  
  /* make a temporary file that contains all the CAs */
  
  if (CAfile != NULL) {
    unlink(CAfile);
    free(CAfile);
    CAfile = NULL;
  }
  
  f_CA = mailprivacy_get_tmp_file(privacy, CA_filename, sizeof(CA_filename));
  if (f_CA == NULL)
    return;
  
  strncpy(CAcert_dir, directory, sizeof(CAcert_dir));
  CAcert_dir[sizeof(CAcert_dir) - 1] = '\0';
  
  dir = opendir(directory);
  if (dir == NULL) {
    fclose(f_CA);
    goto unlink_CA;
  }
  
  while ((ent = readdir(dir)) != NULL) {
    char filename[PATH_MAX];
    char buf[MAX_BUF];
    FILE * f;
    
    snprintf(filename, sizeof(filename),
        "%s/%s", directory, ent->d_name);
    
    f = fopen(filename, "r");
    if (f == NULL)
      continue;
    
    while (fgets(buf, sizeof(buf), f) != NULL)
      fputs(buf, f_CA);
    
    fclose(f);
  }
  
  closedir(dir);
  
  fclose(f_CA);
  
  CAfile = strdup(CA_filename);
  if (CAfile == NULL)
    goto unlink_CA;
  
  return;
  
 unlink_CA:
  unlink(CA_filename);
}