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;
  }
}
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;
}