From: Pierre Habouzit Date: Fri, 6 Apr 2007 23:10:44 +0000 (+0200) Subject: various rewrites and cleanups. X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=commitdiff_plain;h=73359dc55ff8f4da32149f7270f7ceaccd658256 various rewrites and cleanups. Signed-off-by: Pierre Habouzit --- diff --git a/compose.c b/compose.c index 4d4cc8b..72e6737 100644 --- a/compose.c +++ b/compose.c @@ -1252,7 +1252,7 @@ int mutt_compose_menu (HEADER * msg, /* structure for new message */ } msg->security = 0; } - msg->security = crypt_send_menu (msg, &menu->redraw, 1); + msg->security = crypt_send_menu(msg, &menu->redraw, 1); redraw_crypt_lines (msg); mutt_message_hook (NULL, msg, M_SEND2HOOK); break; diff --git a/crypt.c b/crypt.c index bf8c81d..ba50f4a 100644 --- a/crypt.c +++ b/crypt.c @@ -37,113 +37,96 @@ #define CRYPT_KV_STRONGID 8 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING) -/* - * Type definitions. - */ - -struct crypt_cache { - char *what; - char *dflt; - struct crypt_cache *next; -}; - struct dn_array_s { - char *key; - char *value; + char *key; + char *value; }; /* We work based on user IDs, getting from a user ID to the key is check and does not need any memory (gpgme uses reference counting). */ -typedef struct crypt_keyinfo { - struct crypt_keyinfo *next; - gpgme_key_t kobj; - int idx; /* and the user ID at this index */ - const char *uid; /* and for convenience point to this user ID */ - unsigned int flags; /* global and per uid flags (for convenience) */ -} crypt_key_t; +typedef struct cryptkey_t { + struct cryptkey_t *next; + int idx; /* and the user ID at this index */ + int flags; /* global and per uid flags (for convenience) */ + gpgme_key_t kobj; + const char *uid; /* and for convenience point to this user ID */ +} cryptkey_t; + +DO_INIT(cryptkey_t, cryptkey); +static void cryptkey_wipe(cryptkey_t *key) { + gpgme_key_release(key->kobj); +} +DO_NEW(cryptkey_t, cryptkey); +DO_DELETE(cryptkey_t, cryptkey); +DO_SLIST(cryptkey_t, key, cryptkey_delete); + +static cryptkey_t *cryptkey_dup(const cryptkey_t *k) +{ + cryptkey_t *res = cryptkey_new(); + *res = *k; + res->next = NULL; + gpgme_key_ref(k->kobj); + return res; +} typedef struct crypt_entry { - ssize_t num; - crypt_key_t *key; + ssize_t num; + cryptkey_t *key; } crypt_entry_t; - -static struct crypt_cache *id_defaults = NULL; static gpgme_key_t signature_key = NULL; -/* - * General helper functions. - */ - static void convert_to_7bit (BODY * a) { - while (a) { - if (a->type == TYPEMULTIPART) { - if (a->encoding != ENC7BIT) { - a->encoding = ENC7BIT; - convert_to_7bit (a->parts); - } else { - convert_to_7bit (a->parts); - } - } - else if (a->type == TYPEMESSAGE && - m_strcasecmp(a->subtype, "delivery-status")) { - if (a->encoding != ENC7BIT) - mutt_message_to_7bit (a, NULL); + for (; a; a = a->next) { + int tok = mime_which_token(a->subtype, -1); + + if (a->type == TYPEMULTIPART) { + a->encoding = ENC7BIT; + convert_to_7bit(a->parts); + } else if (a->type == TYPEMESSAGE && tok == MIME_DELIVERY_STATUS) { + if (a->encoding != ENC7BIT) + mutt_message_to_7bit(a, NULL); + } else if (a->encoding == ENC8BIT) { + a->encoding = ENCQUOTEDPRINTABLE; + } else if (a->encoding == ENCBINARY) { + a->encoding = ENCBASE64; + } else if (a->content && a->encoding != ENCBASE64 + && (a->content->from || a->content->space)) + { + a->encoding = ENCQUOTEDPRINTABLE; + } } - else if (a->encoding == ENC8BIT) - a->encoding = ENCQUOTEDPRINTABLE; - else if (a->encoding == ENCBINARY) - a->encoding = ENCBASE64; - else if (a->content && a->encoding != ENCBASE64 && - (a->content->from || a->content->space)) - a->encoding = ENCQUOTEDPRINTABLE; - a = a->next; - } } /* Print the utf-8 encoded string BUF of length LEN bytes to stream FP. Convert the character set. */ static void print_utf8 (FILE * fp, const char *buf, ssize_t len) { - char *tstr; + char *tstr; - tstr = p_dupstr(buf, len); - mutt_convert_string (&tstr, "utf-8", MCharset.charset, M_ICONV_HOOK_FROM); - fputs (tstr, fp); - p_delete(&tstr); + tstr = p_dupstr(buf, len); + mutt_convert_string(&tstr, "utf-8", MCharset.charset, M_ICONV_HOOK_FROM); + fputs(tstr, fp); + p_delete(&tstr); } - -/* - * Key management. - */ - /* Return the keyID for the key K. Note that this string is valid as long as K is valid */ -static const char *crypt_keyid (crypt_key_t * k) +static const char *crypt_keyid (cryptkey_t * k) { - const char *s = "????????"; - - if (k->kobj && k->kobj->subkeys) { - s = k->kobj->subkeys->keyid; - if ((!option (OPTPGPLONGIDS)) && (m_strlen(s) == 16)) - /* Return only the short keyID. */ - s += 8; - } + if (k->kobj && k->kobj->subkeys) { + const char *s = k->kobj->subkeys->keyid; + return m_strlen(s) == 16 ? s + 8 : s; + } - return s; + return "????????"; } /* Return the hexstring fingerprint from the key K. */ -static const char *crypt_fpr (crypt_key_t * k) +static const char *crypt_fpr (cryptkey_t * k) { - const char *s = ""; - - if (k->kobj && k->kobj->subkeys) - s = k->kobj->subkeys->fpr; - - return s; + return k->kobj && k->kobj->subkeys ? k->kobj->subkeys->fpr : ""; } /* Parse FLAGS and return a statically allocated(!) string with them. */ @@ -185,301 +168,240 @@ static char crypt_flags (int flags) return ' '; } -/* Return a copy of KEY. */ -static crypt_key_t *crypt_copy_key (crypt_key_t *key) -{ - crypt_key_t *k; - - k = p_new(crypt_key_t, 1); - k->kobj = key->kobj; - gpgme_key_ref (key->kobj); - k->idx = key->idx; - k->uid = key->uid; - k->flags = key->flags; - - return k; -} - -/* Release all the keys at the address of KEYLIST and set the address - to NULL. */ -static void crypt_free_key (crypt_key_t ** keylist) -{ - while (*keylist) { - crypt_key_t *k = (*keylist)->next; - - p_delete(&k); - *keylist = k; - } -} - -/* Return trute when key K is valid. */ -static int crypt_key_is_valid (crypt_key_t * k) -{ - if (k->flags & KEYFLAG_CANTUSE) - return 0; - return 1; -} - /* Return true whe validity of KEY is sufficient. */ -static int crypt_id_is_strong (crypt_key_t * key) +static int crypt_id_is_strong (cryptkey_t * key) { - gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN; - gpgme_user_id_t uid = NULL; - int is_strong = 0; - int i = 0; - - if ((key->flags & KEYFLAG_ISX509)) - return 1; - - for (i = 0, uid = key->kobj->uids; (i < key->idx) && uid; - i++, uid = uid->next); - if (uid) - val = uid->validity; - - switch (val) { - case GPGME_VALIDITY_UNKNOWN: - case GPGME_VALIDITY_UNDEFINED: - case GPGME_VALIDITY_NEVER: - case GPGME_VALIDITY_MARGINAL: - is_strong = 0; - break; + gpgme_user_id_t uid; + int i; - case GPGME_VALIDITY_FULL: - case GPGME_VALIDITY_ULTIMATE: - is_strong = 1; - break; - } + if (key->flags & KEYFLAG_ISX509) + return 1; - return is_strong; -} + for (i = 0, uid = key->kobj->uids; uid; i++, uid = uid->next) { + if (i == key->idx) { + return uid->validity == GPGME_VALIDITY_FULL + || uid->validity == GPGME_VALIDITY_ULTIMATE; + } + } -/* Return true when the KEY is valid, i.e. not marked as unusable. */ -static int crypt_id_is_valid (crypt_key_t * key) -{ - return !(key->flags & KEYFLAG_CANTUSE); + return 0; } /* Return a bit vector describing how well the addresses ADDR and U_ADDR match and whether KEY is valid. */ -static int crypt_id_matches_addr (address_t * addr, address_t * u_addr, - crypt_key_t * key) +static int +crypt_id_matches_addr(address_t *addr, address_t *u_addr, cryptkey_t *key) { - int rv = 0; + int rv = 0; - if (crypt_id_is_valid (key)) - rv |= CRYPT_KV_VALID; + if (!(key->flags & KEYFLAG_CANTUSE)) + rv |= CRYPT_KV_VALID; - if (crypt_id_is_strong (key)) - rv |= CRYPT_KV_STRONGID; + if (crypt_id_is_strong(key)) + rv |= CRYPT_KV_STRONGID; - if (addr->mailbox && u_addr->mailbox - && m_strcasecmp(addr->mailbox, u_addr->mailbox) == 0) - rv |= CRYPT_KV_ADDR; + if (addr->mailbox && !m_strcasecmp(addr->mailbox, u_addr->mailbox)) + rv |= CRYPT_KV_ADDR; - if (addr->personal && u_addr->personal - && m_strcasecmp(addr->personal, u_addr->personal) == 0) - rv |= CRYPT_KV_STRING; + if (addr->personal && m_strcasecmp(addr->personal, u_addr->personal)) + rv |= CRYPT_KV_STRING; - return rv; + return rv; } -/* - * GPGME convenient functions. - */ - /* Create a new gpgme context and return it. With FOR_SMIME set to true, the protocol of the context is set to CMS. */ -static gpgme_ctx_t create_gpgme_context (int for_smime) +static gpgme_ctx_t create_gpgme_context(int for_smime) { - gpgme_error_t err; - gpgme_ctx_t ctx; - - err = gpgme_new (&ctx); - if (err) { - mutt_error (_("error creating gpgme context: %s\n"), gpgme_strerror (err)); - sleep (2); - mutt_exit (1); - } + gpgme_error_t err; + gpgme_ctx_t ctx; - if (for_smime) { - err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS); + err = gpgme_new (&ctx); if (err) { - mutt_error (_("error enabling CMS protocol: %s\n"), gpgme_strerror (err)); - sleep (2); - mutt_exit (1); + mutt_error(_("error creating gpgme context: %s\n"), + gpgme_strerror(err)); + sleep(2); + mutt_exit(1); } - } + if (!for_smime) + return ctx; - return ctx; + err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS); + if (err) { + mutt_error(_("error enabling CMS protocol: %s\n"), gpgme_strerror(err)); + sleep(2); + mutt_exit(1); + } + return ctx; } /* Create a new gpgme data object. This is a wrapper to die on error. */ -static gpgme_data_t create_gpgme_data (void) +static gpgme_data_t create_gpgme_data(void) { - gpgme_error_t err; - gpgme_data_t data; + gpgme_error_t err; + gpgme_data_t data; - err = gpgme_data_new (&data); - if (err) { - mutt_error (_("error creating gpgme data object: %s\n"), - gpgme_strerror (err)); - sleep (2); - mutt_exit (1); - } - return data; + err = gpgme_data_new(&data); + if (err) { + mutt_error(_("error creating gpgme data object: %s\n"), + gpgme_strerror(err)); + sleep(2); + mutt_exit(1); + } + return data; } /* Create a new GPGME Data object from the mail body A. With CONVERT passed as true, the lines are converted to CR,LF if required. Return NULL on error or the gpgme_data_t object on success. */ -static gpgme_data_t body_to_data_object (BODY * a, int convert) +static gpgme_data_t body_to_data_object(BODY *a, int convert) { - char tempfile[_POSIX_PATH_MAX]; - FILE *fptmp; - int err = 0; - gpgme_data_t data; + gpgme_data_t data; + int err = 0; + FILE *fptmp = tmpfile(); - fptmp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL); - if (!fptmp) { - mutt_perror (_("Can't create temporary file")); - return NULL; - } + if (!fptmp) { + mutt_perror (_("Can't create temporary file")); + return NULL; + } - mutt_write_mime_header (a, fptmp); - fputc ('\n', fptmp); - mutt_write_mime_body (a, fptmp); + mutt_write_mime_header(a, fptmp); + fputc('\n', fptmp); + mutt_write_mime_body(a, fptmp); + rewind(fptmp); - if (convert) { - int c, hadcr = 0; - unsigned char buf[1]; + if (convert) { + char buf[STRING]; + int spare = 0; - data = create_gpgme_data (); - rewind (fptmp); - while ((c = fgetc (fptmp)) != EOF) { - if (c == '\r') - hadcr = 1; - else { - if (c == '\n' && !hadcr) { - buf[0] = '\r'; - gpgme_data_write (data, buf, 1); - } + data = create_gpgme_data(); + while (fgets(buf + spare, sizeof(buf) - 1, fptmp)) { + int l = m_strlen(buf); - hadcr = 0; - } - /* FIXME: This is quite suboptimal */ - buf[0] = c; - gpgme_data_write (data, buf, 1); + spare = buf[l - 1] != '\n'; + if (!spare) { + if (l > 2 && buf[l - 2] == '\r') { + buf[l - 2] = '\n'; + l--; + } + } + gpgme_data_write(data, buf, l - spare); + if (spare) + buf[0] = buf[l - 1]; + } + if (spare) + gpgme_data_write(data, buf, 1); + gpgme_data_seek(data, 0, SEEK_SET); + } else { + err = gpgme_data_new_from_stream(&data, fptmp); + } + m_fclose(&fptmp); + if (err) { + mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err)); + return NULL; } - gpgme_data_seek (data, 0, SEEK_SET); - } else { - err = gpgme_data_new_from_file (&data, tempfile, 1); - } - m_fclose(&fptmp); - unlink (tempfile); - if (err) { - mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err)); - return NULL; - } - return data; + return data; } /* Create a GPGME data object from the stream FP but limit the object to LENGTH bytes starting at OFFSET bytes from the beginning of the file. */ -static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length) +static gpgme_data_t file_to_data_object(FILE *fp, long offset, long length) { - int err = 0; - gpgme_data_t data; + int err = 0; + gpgme_data_t data; - err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length); - if (err) { - mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err)); - return NULL; - } + err = gpgme_data_new_from_filepart(&data, NULL, fp, offset, length); + if (err) { + mutt_error(_("error allocating data object: %s\n"), + gpgme_strerror(err)); + return NULL; + } - return data; + return data; } /* Write a GPGME data object to the stream FP. */ -static int data_object_to_stream (gpgme_data_t data, FILE * fp) +static int data_object_to_stream(gpgme_data_t data, FILE * fp) { - int err; - char buf[4096], *p; - ssize_t nread; - - err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1) - ? gpgme_error_from_errno (errno) : 0); - if (err) { - mutt_error (_("error rewinding data object: %s\n"), gpgme_strerror (err)); - return -1; - } + int err; + char buf[4096], *p; + ssize_t nread; - while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) { - /* fixme: we are not really converting CRLF to LF but just - skipping CR. Doing it correctly needs a more complex logic */ - for (p = buf; nread; p++, nread--) { - if (*p != '\r') - putc (*p, fp); + err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1) + ? gpgme_error_from_errno (errno) : 0); + if (err) { + mutt_error (_("error rewinding data object: %s\n"), gpgme_strerror (err)); + return -1; } - if (ferror (fp)) { - mutt_perror ("[tempfile]"); - return -1; + while ((nread = gpgme_data_read(data, buf, sizeof (buf)))) { + /* fixme: we are not really converting CRLF to LF but just + skipping CR. Doing it correctly needs a more complex logic */ + for (p = buf; nread; p++, nread--) { + if (*p != '\r') + putc (*p, fp); + } + + if (ferror (fp)) { + mutt_perror ("[tempfile]"); + return -1; + } } - } - if (nread == -1) { - mutt_error (_("error reading data object: %s\n"), strerror (errno)); - return -1; - } - return 0; + if (nread == -1) { + mutt_error (_("error reading data object: %s\n"), strerror (errno)); + return -1; + } + return 0; } /* Copy a data object to a newly created temporay file and return that filename. Caller must free. With RET_FP not NULL, don't close the stream but return it there. */ -static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp) +static char *data_object_to_tempfile(gpgme_data_t data, FILE ** ret_fp) { - int err; - char tempfile[_POSIX_PATH_MAX]; - FILE *fp; - ssize_t nread = 0; + int err; + char tempfile[_POSIX_PATH_MAX]; + FILE *fp; + ssize_t nread = 0; - fp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL); - if (!fp) { - mutt_perror (_("Can't create temporary file")); - return NULL; - } + fp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL); + if (!fp) { + mutt_perror (_("Can't create temporary file")); + return NULL; + } - err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1) - ? gpgme_error_from_errno (errno) : 0); - if (!err) { - char buf[4096]; + err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1) + ? gpgme_error_from_errno (errno) : 0); + if (!err) { + char buf[4096]; + + while ((nread = gpgme_data_read(data, buf, sizeof(buf)))) { + if (fwrite (buf, nread, 1, fp) != 1) { + mutt_perror (_("Can't create temporary file")); + m_fclose(&fp); + unlink (tempfile); + return NULL; + } + } + } - while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) { - if (fwrite (buf, nread, 1, fp) != 1) { - mutt_perror (_("Can't create temporary file")); - m_fclose(&fp); + if (nread == -1) { + mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err)); unlink (tempfile); + m_fclose(&fp); return NULL; - } } - } - if (ret_fp) - rewind (fp); - else - m_fclose(&fp); - if (nread == -1) { - mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err)); - unlink (tempfile); - m_fclose(&fp); - return NULL; - } - if (ret_fp) - *ret_fp = fp; - return m_strdup(tempfile); + if (ret_fp) { + rewind(fp); + *ret_fp = fp; + } else { + m_fclose(&fp); + } + return m_strdup(tempfile); } @@ -512,8 +434,8 @@ gpgme_get_key2 (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key, /* Create a GpgmeRecipientSet from the keys in the string KEYLIST. The keys must be space delimited. */ -static gpgme_key_t *create_recipient_set (const char *keylist, - gpgme_protocol_t protocol) +static gpgme_key_t * +create_recipient_set(const char *keylist, gpgme_protocol_t protocol) { int err; const char *s; @@ -598,8 +520,8 @@ static int set_signer (gpgme_ctx_t ctx, int for_smime) } err = gpgme_op_keylist_next (listctx, &key2); if (!err) { - gpgme_key_release (key); - gpgme_key_release (key2); + gpgme_key_unref(key); + gpgme_key_unref(key2); gpgme_release (listctx); mutt_error (_("ambiguous specification of secret key `%s'\n"), signid); return -1; @@ -609,7 +531,7 @@ static int set_signer (gpgme_ctx_t ctx, int for_smime) gpgme_signers_clear (ctx); err = gpgme_signers_add (ctx, key); - gpgme_key_release (key); + gpgme_key_unref(key); if (err) { mutt_error (_("error setting secret key `%s': %s\n"), signid, gpgme_strerror (err)); @@ -710,7 +632,7 @@ static void print_time (time_t t, STATE * s) /* Sign the MESSAGE in body A either using OpenPGP or S/MIME when USE_SMIME is passed as true. Returns the new body or NULL on error. */ -static BODY *sign_message (BODY * a, int use_smime) +static BODY *sign_message(BODY * a, int use_smime) { BODY *t; char *sigfile; @@ -721,7 +643,7 @@ static BODY *sign_message (BODY * a, int use_smime) convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */ - message = body_to_data_object (a, 1); + message = body_to_data_object(a, 1); if (!message) return NULL; signature = create_gpgme_data (); @@ -798,10 +720,6 @@ static BODY *sign_message (BODY * a, int use_smime) return a; } -/* - * Implementation of `encrypt_message'. - */ - /* Encrypt the mail body A to all keys given as space separated keyids or fingerprints in KEYLIST and return the encrypted body. */ static BODY *crypt_pgp_encrypt_message (BODY * a, char *keylist, int sign) @@ -817,7 +735,7 @@ static BODY *crypt_pgp_encrypt_message (BODY * a, char *keylist, int sign) if (sign) convert_to_7bit (a); - plaintext = body_to_data_object (a, 0); + plaintext = body_to_data_object(a, 0); if (!plaintext) { p_delete(&rset); return NULL; @@ -852,16 +770,11 @@ static BODY *crypt_pgp_encrypt_message (BODY * a, char *keylist, int sign) t->parts->next->use_disp = 1; t->parts->next->disposition = DISPINLINE; t->parts->next->unlink = 1; /* delete after sending the message */ - t->parts->next->d_filename = m_strdup("msg.asc"); /* non pgp/mime - can save */ + t->parts->next->d_filename = m_strdup("msg.asc"); return t; } -/* - * Implementation of `smime_build_smime_entity'. - */ - /* Encrypt the mail body A to all keys given as space separated fingerprints in KEYLIST and return the S/MIME encrypted body. */ static BODY *crypt_smime_build_smime_entity (BODY * a, char *keylist) @@ -875,7 +788,7 @@ static BODY *crypt_smime_build_smime_entity (BODY * a, char *keylist) if (!rset) return NULL; - plaintext = body_to_data_object (a, 0); + plaintext = body_to_data_object(a, 0); if (!plaintext) { p_delete(&rset); return NULL; @@ -904,9 +817,6 @@ static BODY *crypt_smime_build_smime_entity (BODY * a, char *keylist) return t; } - -/* Implementation of `verify_one'. */ - /* Display the common attributes of the signature summary SUM. Return 1 if there is is a severe warning. */ @@ -1116,7 +1026,7 @@ static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s) return -1; /* Signature not found. */ if (signature_key) { - gpgme_key_release (signature_key); + gpgme_key_unref(signature_key); signature_key = NULL; } @@ -1196,7 +1106,7 @@ static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s) } if (key != signature_key) - gpgme_key_release (key); + gpgme_key_unref(key); } return anybad ? 1 : anywarn ? 2 : 0; @@ -1248,7 +1158,7 @@ static int crypt_verify_one(BODY *sigbdy, STATE *s, FILE *fp, int is_smime) int anybad = 0; if (signature_key) { - gpgme_key_release (signature_key); + gpgme_key_unref(signature_key); signature_key = NULL; } @@ -1301,18 +1211,14 @@ static int crypt_verify_one(BODY *sigbdy, STATE *s, FILE *fp, int is_smime) return badsig ? 1 : anywarn ? 2 : 0; } -/* - * Implementation of `decrypt_part'. - */ - /* Decrypt a PGP or SMIME message (depending on the boolean flag IS_SMIME) with body A described further by state S. Write plaintext out to file FPOUT and return a new body. For PGP returns a flag in R_IS_SIGNED to indicate whether this is a combined encrypted and signed message, for S/MIME it returns true when it is not a encrypted but a signed message. */ -static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime, - int *r_is_signed) +static BODY * +decrypt_part(BODY *a, STATE *s, FILE *fpout, int is_smime, int *r_is_signed) { struct stat info; BODY *tattach; @@ -1479,8 +1385,7 @@ int crypt_pgp_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur) /* Decrypt a S/MIME message in FPIN and B and return a new body and the stream in CUR and FPOUT. Returns 0 on success. */ -int crypt_smime_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, - BODY ** cur) +int crypt_smime_decrypt_mime(FILE *fpin, FILE **fpout, BODY *b, BODY **cur) { char tempfile[_POSIX_PATH_MAX]; STATE s; @@ -1598,12 +1503,8 @@ int crypt_smime_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, } -/* - * Implementation of `pgp_check_traditional'. - */ - -static int pgp_check_traditional_one_body (FILE * fp, BODY * b, - int tagged_only) +static int +pgp_check_traditional_one_body(FILE *fp, BODY *b, int tagged_only) { char tempfile[_POSIX_PATH_MAX]; char buf[HUGE_STRING]; @@ -1652,7 +1553,7 @@ static int pgp_check_traditional_one_body (FILE * fp, BODY * b, return 1; } -int crypt_pgp_check_traditional (FILE * fp, BODY * b, int tagged_only) +int crypt_pgp_check_traditional(FILE *fp, BODY *b, int tagged_only) { int rv = 0; int r; @@ -1670,9 +1571,6 @@ int crypt_pgp_check_traditional (FILE * fp, BODY * b, int tagged_only) return rv; } - -/* Implementation of `application_handler'. */ - /* Copy a clearsigned message, and strip the signature and PGP's dash-escaping. @@ -1684,8 +1582,7 @@ int crypt_pgp_check_traditional (FILE * fp, BODY * b, int tagged_only) (Note that we aren't worse than Outlook & Cie in this, and also note that we can successfully handle anything produced by any existing versions of mutt.) */ - -static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset) +static void copy_clearsigned(gpgme_data_t data, STATE * s, char *charset) { char buf[HUGE_STRING]; short complete, armor_header; @@ -1732,9 +1629,8 @@ static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset) m_fclose(&fp); } - /* Support for classic_application/pgp */ -int crypt_pgp_application_pgp_handler (BODY * m, STATE * s) +int crypt_pgp_application_pgp_handler(BODY *m, STATE *s) { int needpass = -1, pgp_keyblock = 0; int clearsign = 0; @@ -1958,8 +1854,6 @@ int crypt_pgp_application_pgp_handler (BODY * m, STATE * s) return (err); } -/* Implementation of `encrypted_handler'. */ - /* MIME handler for pgp/mime encrypted messages. */ int crypt_pgp_encrypted_handler (BODY * a, STATE * s) { @@ -2122,7 +2016,7 @@ crypt_entry_fmt (char *dest, ssize_t destlen, char op, { char fmt[16]; crypt_entry_t *entry; - crypt_key_t *key; + cryptkey_t *key; int kflags = 0; int optional = (flags & M_FORMAT_OPTIONAL); const char *s = NULL; @@ -2308,10 +2202,10 @@ crypt_entry_fmt (char *dest, ssize_t destlen, char op, /* Used by the display fucntion to format a line. */ static void crypt_entry (char *s, ssize_t l, MUTTMENU * menu, int num) { - crypt_key_t **key_table = (crypt_key_t **) menu->data; + cryptkey_t **cryptkey_table = (cryptkey_t **) menu->data; crypt_entry_t entry; - entry.key = key_table[num]; + entry.key = cryptkey_table[num]; entry.num = num + 1; m_strformat(s, l, COLS - SW, PgpEntryFormat, crypt_entry_fmt, &entry, @@ -2321,8 +2215,8 @@ static void crypt_entry (char *s, ssize_t l, MUTTMENU * menu, int num) /* Compare two addresses and the keyid to be used for sorting. */ static int _crypt_compare_address (const void *a, const void *b) { - crypt_key_t **s = (crypt_key_t **) a; - crypt_key_t **t = (crypt_key_t **) b; + cryptkey_t **s = (cryptkey_t **) a; + cryptkey_t **t = (cryptkey_t **) b; int r; if ((r = m_strcasecmp((*s)->uid, (*t)->uid))) @@ -2341,8 +2235,8 @@ static int crypt_compare_address (const void *a, const void *b) /* Compare two key IDs and the addresses to be used for sorting. */ static int _crypt_compare_keyid (const void *a, const void *b) { - crypt_key_t **s = (crypt_key_t **) a; - crypt_key_t **t = (crypt_key_t **) b; + cryptkey_t **s = (cryptkey_t **) a; + cryptkey_t **t = (cryptkey_t **) b; int r; if ((r = m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t)))) @@ -2360,8 +2254,8 @@ static int crypt_compare_keyid (const void *a, const void *b) /* Compare 2 creation dates and the addresses. For sorting. */ static int _crypt_compare_date (const void *a, const void *b) { - crypt_key_t **s = (crypt_key_t **) a; - crypt_key_t **t = (crypt_key_t **) b; + cryptkey_t **s = (cryptkey_t **) a; + cryptkey_t **t = (cryptkey_t **) b; unsigned long ts = 0, tt = 0; if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0)) @@ -2387,8 +2281,8 @@ static int crypt_compare_date (const void *a, const void *b) addresses and the key IDs. For sorting. */ static int _crypt_compare_trust (const void *a, const void *b) { - crypt_key_t **s = (crypt_key_t **) a; - crypt_key_t **t = (crypt_key_t **) b; + cryptkey_t **s = (cryptkey_t **) a; + cryptkey_t **t = (cryptkey_t **) b; unsigned long ts = 0, tt = 0; int r; @@ -2649,12 +2543,12 @@ static void parse_and_print_user_id(FILE * fp, const char *userid) } typedef enum { - KEY_CAP_CAN_ENCRYPT, - KEY_CAP_CAN_SIGN, - KEY_CAP_CAN_CERTIFY + KEY_CAP_CAN_ENCRYPT, + KEY_CAP_CAN_SIGN, + KEY_CAP_CAN_CERTIFY } key_cap_t; -static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap) +static unsigned int key_check_cap(gpgme_key_t key, key_cap_t cap) { gpgme_subkey_t subkey = NULL; unsigned int ret = 0; @@ -2905,7 +2799,7 @@ static void print_key_info (gpgme_key_t key, FILE * fp) /* Show detailed information about the selected key */ -static void verify_key (crypt_key_t * key) +static void verify_key (cryptkey_t * key) { FILE *fp; char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX]; @@ -2938,7 +2832,7 @@ static void verify_key (crypt_key_t * key) while ((s = k->chain_id) && k->subkeys && m_strcmp(s, k->subkeys->fpr)) { putc ('\n', fp); err = gpgme_op_keylist_start (listctx, s, 0); - gpgme_key_release (k); + gpgme_key_unref(k); k = NULL; if (!err) err = gpgme_op_keylist_next (listctx, &k); @@ -2957,7 +2851,7 @@ static void verify_key (crypt_key_t * key) } leave: - gpgme_key_release (k); + gpgme_key_unref(k); gpgme_release (listctx); m_fclose(&fp); mutt_clear_error (); @@ -2967,211 +2861,122 @@ leave: /* Implementation of `findkeys'. */ -/* Convert string_list_t into a pattern string suitable to be passed to GPGME. - We need to convert spaces in an item into a '+' and '%' into - "%25". */ -static char *list_to_pattern (string_list_t * list) +static void add_hints(string_array *arr, const char *s) { - string_list_t *l; - char *pattern, *p; - const char *s; - ssize_t n; + if (!s) + return; - n = 0; - for (l = list; l; l = l->next) { - for (s = l->data; *s; s++) { - if (*s == '%') - n += 2; - n++; + while (*s) { + int l = strcspn(s, " ,.:\"()<>\n"); + string_array_append(arr, p_dupstr(s, l)); + s += l; + s += strspn(s, " ,.:\"()<>\n"); } - n++; /* delimiter or end of string */ - } - n++; /* make sure to allocate at least one byte */ - pattern = p = p_new(char, n); - for (l = list; l; l = l->next) { - s = l->data; - if (*s) { - if (l != list) - *p++ = ' '; - for (s = l->data; *s; s++) { - if (*s == '%') { - *p++ = '%'; - *p++ = '2'; - *p++ = '5'; - } - else if (*s == '+') { - *p++ = '%'; - *p++ = '2'; - *p++ = 'B'; - } - else if (*s == ' ') - *p++ = '+'; - else - *p++ = *s; - } - } - } - *p = 0; - return pattern; } -/* Return a list of keys which are candidates for the selection. - Select by looking at the HINTS list. */ -static crypt_key_t *get_candidates (string_list_t * hints, unsigned int app, - int secret) +/* Return a list of keys which are candidates for the selection. */ +static cryptkey_t * +get_candidates(string_array *hints, unsigned int app, int secret) { - crypt_key_t *db, *k, **kend; - char *pattern; - gpgme_error_t err; - gpgme_ctx_t ctx; - gpgme_key_t key; - int idx; - gpgme_user_id_t uid = NULL; - - pattern = list_to_pattern (hints); - if (!pattern) - return NULL; - - err = gpgme_new (&ctx); - if (err) { - mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err)); - p_delete(&pattern); - return NULL; - } - - db = NULL; - kend = &db; - - if ((app & APPLICATION_PGP)) { - /* Its all a mess. That old GPGME expects different things - depending on the protocol. For gpg we don' t need percent - escaped pappert but simple strings passed in an array to the - keylist_ext_start function. */ - string_list_t *l; - ssize_t n; - char **patarr; + cryptkey_t *res = NULL, **kend = &res; + gpgme_error_t err; + gpgme_ctx_t ctx; + gpgme_key_t key; - for (l = hints, n = 0; l; l = l->next) { - if (l->data && *l->data) - n++; - } - if (!n) - goto no_pgphints; + if (hints->len <= 0) + return NULL; + string_array_append(hints, NULL); + ctx = create_gpgme_context(0); - patarr = p_new(char *, n + 1); - for (l = hints, n = 0; l; l = l->next) { - if (l->data && *l->data) - patarr[n++] = m_strdup(l->data); - } - patarr[n] = NULL; - err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0); - for (n = 0; patarr[n]; n++) - p_delete(&patarr[n]); - p_delete(&patarr); - if (err) { - mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err)); - gpgme_release (ctx); - p_delete(&pattern); - return NULL; - } + if ((app & APPLICATION_PGP)) { + err = gpgme_op_keylist_ext_start(ctx, (const char **)hints->arr, + secret, 0); + if (err) { + mutt_error(_("gpgme_op_keylist_start failed: %s"), + gpgme_strerror(err)); + gpgme_release(ctx); + return NULL; + } - while (!(err = gpgme_op_keylist_next (ctx, &key))) { - unsigned int flags = 0; - - if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) - flags |= KEYFLAG_CANENCRYPT; - if (key_check_cap (key, KEY_CAP_CAN_SIGN)) - flags |= KEYFLAG_CANSIGN; - - for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) { - k = p_new(crypt_key_t, 1); - k->kobj = key; - k->idx = idx; - k->uid = uid->uid; - k->flags = flags; - *kend = k; - kend = &k->next; - } + while (!(err = gpgme_op_keylist_next(ctx, &key))) { + gpgme_user_id_t uid = NULL; + unsigned int flags = 0; + int idx; + + if (key_check_cap(key, KEY_CAP_CAN_ENCRYPT)) + flags |= KEYFLAG_CANENCRYPT; + if (key_check_cap(key, KEY_CAP_CAN_SIGN)) + flags |= KEYFLAG_CANSIGN; + + for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) { + cryptkey_t *k = p_new(cryptkey_t, 1); + k->kobj = key; + k->idx = idx; + k->uid = uid->uid; + k->flags = flags; + *kend = k; + kend = &k->next; + } + } + if (gpg_err_code(err) != GPG_ERR_EOF) + mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err)); + gpgme_op_keylist_end(ctx); } - if (gpg_err_code (err) != GPG_ERR_EOF) - mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err)); - gpgme_op_keylist_end (ctx); - no_pgphints: - ; - } - if ((app & APPLICATION_SMIME)) { - /* and now look for x509 certificates */ - gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS); - err = gpgme_op_keylist_start (ctx, pattern, 0); - if (err) { - mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err)); - gpgme_release (ctx); - p_delete(&pattern); - return NULL; - } + if ((app & APPLICATION_SMIME)) { + gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS); + err = gpgme_op_keylist_ext_start(ctx, (const char **)hints->arr, + secret, 0); + if (err) { + mutt_error(_("gpgme_op_keylist_start failed: %s"), + gpgme_strerror(err)); + gpgme_release(ctx); + return NULL; + } - while (!(err = gpgme_op_keylist_next (ctx, &key))) { - unsigned int flags = KEYFLAG_ISX509; - - if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) - flags |= KEYFLAG_CANENCRYPT; - if (key_check_cap (key, KEY_CAP_CAN_SIGN)) - flags |= KEYFLAG_CANSIGN; - - for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) { - k = p_new(crypt_key_t, 1); - k->kobj = key; - k->idx = idx; - k->uid = uid->uid; - k->flags = flags; - *kend = k; - kend = &k->next; - } + while (!(err = gpgme_op_keylist_next(ctx, &key))) { + gpgme_user_id_t uid = NULL; + unsigned int flags = KEYFLAG_ISX509; + int idx; + + if (key_check_cap(key, KEY_CAP_CAN_ENCRYPT)) + flags |= KEYFLAG_CANENCRYPT; + if (key_check_cap(key, KEY_CAP_CAN_SIGN)) + flags |= KEYFLAG_CANSIGN; + + for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) { + cryptkey_t *k = p_new(cryptkey_t, 1); + k->kobj = key; + k->idx = idx; + k->uid = uid->uid; + k->flags = flags; + *kend = k; + kend = &k->next; + } + } + if (gpg_err_code(err) != GPG_ERR_EOF) + mutt_error(_("gpgme_op_keylist_next failed: %s"), + gpgme_strerror(err)); + gpgme_op_keylist_end(ctx); } - if (gpg_err_code (err) != GPG_ERR_EOF) - mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err)); - gpgme_op_keylist_end (ctx); - } - - gpgme_release (ctx); - p_delete(&pattern); - return db; -} - -/* Add the string STR to the list HINTS. This list is later used to - match addresses. */ -static string_list_t *crypt_add_string_to_hints (string_list_t * hints, const char *str) -{ - char *scratch; - char *t; - - if ((scratch = m_strdup(str)) == NULL) - return hints; - - for (t = strtok (scratch, " ,.:\"()<>\n"); t; - t = strtok (NULL, " ,.:\"()<>\n")) { - if (m_strlen(t) > 3) - hints = mutt_add_list(hints, t); - } - p_delete(&scratch); - return hints; + gpgme_release(ctx); + return res; } /* Display a menu to select a key from the array KEYS. FORCED_VALID will be set to true on return if the user did override the the key's validity. */ -static crypt_key_t *crypt_select_key (crypt_key_t * keys, +static cryptkey_t *crypt_select_key (cryptkey_t * keys, address_t * p, const char *s, unsigned int app, int *forced_valid) { int keymax; - crypt_key_t **key_table; + cryptkey_t **cryptkey_table; MUTTMENU *menu; int i, done = 0; char helpstr[STRING], buf[LONG_STRING]; - crypt_key_t *k; + cryptkey_t *k; int (*f) (const void *, const void *); int menu_to_use = 0; int unusable = 0; @@ -3180,7 +2985,7 @@ static crypt_key_t *crypt_select_key (crypt_key_t * keys, /* build the key table */ keymax = i = 0; - key_table = NULL; + cryptkey_table = NULL; for (k = keys; k; k = k->next) { if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) { unusable = 1; @@ -3189,10 +2994,10 @@ static crypt_key_t *crypt_select_key (crypt_key_t * keys, if (i == keymax) { keymax += 20; - p_realloc(&key_table, keymax); + p_realloc(&cryptkey_table, keymax); } - key_table[i++] = k; + cryptkey_table[i++] = k; } if (!i && unusable) { @@ -3217,7 +3022,7 @@ static crypt_key_t *crypt_select_key (crypt_key_t * keys, f = crypt_compare_trust; break; } - qsort (key_table, i, sizeof (crypt_key_t *), f); + qsort (cryptkey_table, i, sizeof (cryptkey_t *), f); if (app & APPLICATION_PGP) menu_to_use = MENU_KEY_SELECT_PGP; @@ -3241,7 +3046,7 @@ static crypt_key_t *crypt_select_key (crypt_key_t * keys, menu->make_entry = crypt_entry; menu->menu = menu_to_use; menu->help = helpstr; - menu->data = key_table; + menu->data = cryptkey_table; { const char *ts; @@ -3268,32 +3073,32 @@ static crypt_key_t *crypt_select_key (crypt_key_t * keys, *forced_valid = 0; switch (mutt_menuLoop (menu)) { case OP_VERIFY_KEY: - verify_key (key_table[menu->current]); + verify_key (cryptkey_table[menu->current]); menu->redraw = REDRAW_FULL; break; case OP_VIEW_ID: - mutt_message ("%s", key_table[menu->current]->uid); + mutt_message ("%s", cryptkey_table[menu->current]->uid); break; case OP_GENERIC_SELECT_ENTRY: /* FIXME make error reporting more verbose - this should be easy because gpgme provides more information */ if (option (OPTPGPCHECKTRUST)) { - if (!crypt_key_is_valid (key_table[menu->current])) { - mutt_error _("This key can't be used: " - "expired/disabled/revoked."); + if (cryptkey_table[menu->current]->flags & KEYFLAG_CANTUSE ) { + mutt_error(_("This key can't be used: " + "expired/disabled/revoked.")); break; } } if (option (OPTPGPCHECKTRUST) && - (!crypt_id_is_valid (key_table[menu->current]) - || !crypt_id_is_strong (key_table[menu->current]))) { + ((cryptkey_table[menu->current]->flags & KEYFLAG_CANTUSE) + || !crypt_id_is_strong (cryptkey_table[menu->current]))) { const char *warn_s; char buff[LONG_STRING]; - if (key_table[menu->current]->flags & KEYFLAG_CANTUSE) + if (cryptkey_table[menu->current]->flags & KEYFLAG_CANTUSE) s = N_("ID is expired/disabled/revoked."); else { gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN; @@ -3302,8 +3107,8 @@ static crypt_key_t *crypt_select_key (crypt_key_t * keys, warn_s = "??"; - uid = key_table[menu->current]->kobj->uids; - for (j = 0; (j < key_table[menu->current]->idx) && uid; + uid = cryptkey_table[menu->current]->kobj->uids; + for (j = 0; (j < cryptkey_table[menu->current]->idx) && uid; j++, uid = uid->next); if (uid) val = uid->validity; @@ -3335,7 +3140,7 @@ static crypt_key_t *crypt_select_key (crypt_key_t * keys, } } - k = crypt_copy_key (key_table[menu->current]); + k = cryptkey_dup(cryptkey_table[menu->current]); done = 1; break; @@ -3347,18 +3152,17 @@ static crypt_key_t *crypt_select_key (crypt_key_t * keys, } mutt_menuDestroy (&menu); - p_delete(&key_table); + p_delete(&cryptkey_table); set_option (OPTNEEDREDRAW); return k; } -static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities, +static cryptkey_t *crypt_getkeybyaddr (address_t * a, short abilities, unsigned int app, int *forced_valid) { address_t *r, *p; - string_list_t *hints = NULL; int weak = 0; int invalid = 0; @@ -3368,22 +3172,23 @@ static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities, int this_key_has_invalid; int match; - crypt_key_t *keys, *k; - crypt_key_t *the_valid_key = NULL; - crypt_key_t *matches = NULL; - crypt_key_t **matches_endp = &matches; + cryptkey_t *keys, *k; + cryptkey_t *the_valid_key = NULL; + cryptkey_t *matches = NULL; + cryptkey_t **matches_endp = &matches; *forced_valid = 0; - if (a && a->mailbox) - hints = crypt_add_string_to_hints (hints, a->mailbox); - if (a && a->personal) - hints = crypt_add_string_to_hints (hints, a->personal); - - mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox); - keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN)); + { + string_array hints; + string_array_init(&hints); + add_hints(&hints, a->mailbox); + add_hints(&hints, a->personal); - string_list_wipe(&hints); + mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox); + keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN)); + string_array_wipe(&hints); + } if (!keys) return NULL; @@ -3425,20 +3230,19 @@ static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities, address_list_wipe(&r); if (match) { - crypt_key_t *tmp; + cryptkey_t *tmp; if (!this_key_has_strong && this_key_has_invalid) invalid = 1; if (!this_key_has_strong && this_key_has_weak) weak = 1; - *matches_endp = tmp = crypt_copy_key (k); + *matches_endp = tmp = cryptkey_dup(k); matches_endp = &tmp->next; the_valid_key = tmp; } } - - crypt_free_key (&keys); + key_list_wipe(&keys); if (matches) { if (the_valid_key && !multi && !weak @@ -3450,383 +3254,328 @@ static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities, * * Proceed without asking the user. */ - k = crypt_copy_key (the_valid_key); - } - else { + k = cryptkey_dup(the_valid_key); + } else { /* * Else: Ask the user. */ k = crypt_select_key (matches, a, NULL, app, forced_valid); } - crypt_free_key (&matches); - } - else + key_list_wipe(&matches); + } else { k = NULL; + } return k; } -static crypt_key_t *crypt_getkeybystr (const char *p, short abilities, +static cryptkey_t *crypt_getkeybystr (const char *p, short abilities, unsigned int app, int *forced_valid) { - string_list_t *hints = NULL; - crypt_key_t *keys; - crypt_key_t *matches = NULL; - crypt_key_t **matches_endp = &matches; - crypt_key_t *k; + cryptkey_t *keys; + cryptkey_t *matches = NULL; + cryptkey_t **matches_endp = &matches; + cryptkey_t *k; int match; mutt_message (_("Looking for keys matching \"%s\"..."), p); *forced_valid = 0; - hints = crypt_add_string_to_hints (hints, p); - keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN)); - string_list_wipe(&hints); + { + string_array hints; + string_array_init(&hints); + add_hints(&hints, p); + keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN)); + string_array_wipe(&hints); + } if (!keys) return NULL; for (k = keys; k; k = k->next) { + const char *s = crypt_keyid(k); + if (abilities && !(k->flags & abilities)) continue; match = 0; - if (!*p || !m_strcasecmp(p, crypt_keyid (k)) - || (!m_strncasecmp(p, "0x", 2) - && !m_strcasecmp(p + 2, crypt_keyid (k))) - || (option (OPTPGPLONGIDS) - && !m_strncasecmp(p, "0x", 2) - && !m_strcasecmp(p + 2, crypt_keyid (k) + 8)) - || m_stristr(k->uid, p)) { - crypt_key_t *tmp; + if (!*p || !m_strcasecmp(p, s) + || (!m_strncasecmp(p, "0x", 2) && !m_strcasecmp(p + 2, s)) + || m_stristr(k->uid, p)) + { + cryptkey_t *tmp; - *matches_endp = tmp = crypt_copy_key (k); + *matches_endp = tmp = cryptkey_dup(k); matches_endp = &tmp->next; } } - - crypt_free_key (&keys); + key_list_wipe(&keys); if (matches) { k = crypt_select_key (matches, NULL, p, app, forced_valid); - crypt_free_key (&matches); + key_list_wipe(&matches); return k; } return NULL; } -/* Display TAG as a prompt to ask for a key. If WHATFOR is not null - use it as default and store it under that label as the next - default. ABILITIES describe the required key abilities (sign, - encrypt) and APP the type of the requested key; ether S/MIME or - PGP. Return a copy of the key or NULL if not found. */ -static crypt_key_t * -crypt_ask_for_key(char *tag, char *whatfor, short abilities, - unsigned int app, int *forced_valid) +/* Display TAG as a prompt to ask for a key. + * ABILITIES describe the required key abilities (sign, encrypt) and APP the + * type of the requested key; ether S/MIME or PGP. + * Return a copy of the key or NULL if not found. */ +static cryptkey_t * +crypt_ask_for_key(const char *tag, int abilities, int app, int *forced_valid) { - crypt_key_t *key; - char resp[STRING]; - struct crypt_cache *l = NULL; - int dummy; + cryptkey_t *key; + char resp[STRING]; + int dummy; - if (!forced_valid) - forced_valid = &dummy; + if (!forced_valid) + forced_valid = &dummy; + *forced_valid = 0; - mutt_clear_error (); + mutt_clear_error(); + for (;;) { + resp[0] = 0; + if (mutt_get_field(tag, resp, sizeof(resp), M_CLEAR) != 0) + return NULL; - *forced_valid = 0; - resp[0] = 0; - if (whatfor) { - for (l = id_defaults; l; l = l->next) - if (!m_strcasecmp(whatfor, l->what)) { - m_strcpy(resp, sizeof(resp), NONULL(l->dflt)); - break; - } - } + if (m_strisempty(resp)) + return NULL; - for (;;) { - resp[0] = 0; - if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0) - return NULL; + if ((key = crypt_getkeybystr(resp, abilities, app, forced_valid))) + return key; - if (whatfor) { - if (l) - m_strreplace(&l->dflt, resp); - else { - l = p_new(struct crypt_cache, 1); - l->next = id_defaults; - id_defaults = l; - l->what = m_strdup(whatfor); - l->dflt = m_strdup(resp); - } + BEEP (); } - - if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid))) - return key; - - BEEP (); - } - /* not reached */ } /* This routine attempts to find the keyids of the recipients of a message. It returns NULL if any of the keys can not be found. */ -static char *find_keys (address_t * to, address_t * cc, address_t * bcc, - unsigned int app) +static char *find_keys(ENVELOPE *env, unsigned int app) { - char *keylist = NULL, *t; - const char *keyID; - ssize_t keylist_size = 0; - ssize_t keylist_used = 0; - address_t *tmp = NULL, *addr = NULL; - address_t **last = &tmp; - address_t *p, *q; - int i; - crypt_key_t *k_info, *key; - const char *fqdn = mutt_fqdn (1); + address_t *lst = NULL, *addr; + buffer_t *keylist = buffer_new(); -#if 0 - *r_application = APPLICATION_PGP | APPLICATION_SMIME; -#endif - - for (i = 0; i < 3; i++) { - switch (i) { - case 0: - p = to; - break; - case 1: - p = cc; - break; - case 2: - p = bcc; - break; - default: - abort (); - } - - *last = address_list_dup (p); - while (*last) - last = &((*last)->next); - } - - rfc822_qualify(tmp, fqdn); - address_list_uniq(tmp); - - for (p = tmp; p; p = p->next) { - char buf[LONG_STRING]; - int forced_valid = 0; - - q = p; - k_info = NULL; + { + address_t **last = &lst; + *last = address_list_dup(env->to); + last = address_list_last(last); + *last = address_list_dup(env->cc); + last = address_list_last(last); + *last = address_list_dup(env->bcc); + + rfc822_qualify(lst, mutt_fqdn(1)); + address_list_uniq(lst); + } + + while ((addr = address_list_pop(&lst))) { + char buf[STRING]; + int forced_valid = 0; + const char *keyID; + cryptkey_t *key = NULL; + + if ((keyID = mutt_crypt_hook(addr))) { + int r; + + snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyID, + addr->mailbox); + r = mutt_yesorno(buf, M_YES); + + if (r == -1) { + address_list_wipe(&lst); + address_list_wipe(&addr); + buffer_delete(&keylist); + return NULL; + } - if ((keyID = mutt_crypt_hook (p)) != NULL) { - int r; + if (r == M_YES) { + address_t *a; + /* check for e-mail address */ + if (strchr(keyID, '@') && (a = rfc822_parse_adrlist(NULL, keyID))) { + rfc822_qualify(a, mutt_fqdn(1)); + address_list_wipe(&addr); + addr = a; + } else { + key = crypt_getkeybystr(keyID, KEYFLAG_CANENCRYPT, app, + &forced_valid); + } + } + } - snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"), - keyID, p->mailbox); - if ((r = mutt_yesorno (buf, M_YES)) == M_YES) { - /* check for e-mail address */ - if ((t = strchr (keyID, '@')) && - (addr = rfc822_parse_adrlist (NULL, keyID))) { - rfc822_qualify(addr, fqdn); - q = addr; + if (!key) { + key = crypt_getkeybyaddr(addr, KEYFLAG_CANENCRYPT, app, &forced_valid); } - else { - k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT, - app, &forced_valid); + if (!key) { + snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), addr->mailbox); + key = crypt_ask_for_key(buf, KEYFLAG_CANENCRYPT, app, + &forced_valid); + if (!key) { + address_list_wipe(&lst); + address_list_wipe(&addr); + buffer_delete(&keylist); + return NULL; + } } - } - else if (r == -1) { - p_delete(&keylist); - address_list_wipe(&tmp); - address_list_wipe(&addr); - return NULL; - } - } - if (k_info == NULL - && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT, - app, &forced_valid)) == NULL) { - snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox); + if (keylist->len) + buffer_addch(keylist, ' '); + buffer_addstr(keylist, "0x"); + buffer_addstr(keylist, crypt_fpr(key)); + if (forced_valid) + buffer_addch(keylist, '!'); - if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT, app, - &forced_valid)) == NULL) - { - p_delete(&keylist); - address_list_wipe(&tmp); + key_list_wipe(&key); address_list_wipe(&addr); - return NULL; - } - } - else - key = k_info; - - { - const char *s = crypt_fpr (key); - - keylist_size += m_strlen(s) + 4 + 1; - p_realloc(&keylist, keylist_size); - sprintf (keylist + keylist_used, "%s0x%s%s", - keylist_used ? " " : "", s, forced_valid ? "!" : ""); } - keylist_used = m_strlen(keylist); - crypt_free_key (&key); - address_list_wipe(&addr); - } - address_list_wipe(&tmp); - return (keylist); + address_list_wipe(&lst); + return buffer_unwrap(&keylist); } -int crypt_get_keys (HEADER * msg, char **keylist) +int crypt_get_keys(HEADER *msg, char **keylist) { - /* Do a quick check to make sure that we can find all of the encryption - * keys if the user has requested this service. - */ + /* Do a quick check to make sure that we can find all of the encryption + * keys if the user has requested this service. + */ - *keylist = NULL; + *keylist = NULL; - if (msg->security & ENCRYPT) { - if (msg->security & APPLICATION_PGP) { - set_option(OPTPGPCHECKTRUST); - *keylist = find_keys(msg->env->to, msg->env->cc, msg->env->bcc, - APPLICATION_PGP); - unset_option(OPTPGPCHECKTRUST); - if (!*keylist) - return -1; - } + if (msg->security & ENCRYPT) { + if (msg->security & APPLICATION_PGP) { + set_option(OPTPGPCHECKTRUST); + *keylist = find_keys(msg->env, APPLICATION_PGP); + unset_option(OPTPGPCHECKTRUST); + if (!*keylist) + return -1; + } - if (msg->security & APPLICATION_SMIME) { - *keylist = find_keys(msg->env->to, msg->env->cc, msg->env->bcc, - APPLICATION_SMIME); - if (!*keylist) - return -1; + if (msg->security & APPLICATION_SMIME) { + *keylist = find_keys(msg->env, APPLICATION_SMIME); + if (!*keylist) + return -1; + } } - } - return (0); + return 0; } int crypt_send_menu (HEADER * msg, int *redraw, int is_smime) { - crypt_key_t *p; - char input_signas[STRING]; - int choice; + cryptkey_t *p; + char buf[STRING]; + int choice; + + if (msg->security & APPLICATION_SMIME) + is_smime = 1; + if (msg->security & APPLICATION_PGP) + is_smime = 0; + + choice = is_smime + ? mutt_multi_choice(_("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"), + _("esabpc")) + : mutt_multi_choice(_("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"), + _("esabmc")); + + switch (choice) { + case 1: /* (e)ncrypt */ + msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT); + msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN); + break; - if (msg->security & APPLICATION_PGP) - is_smime = 0; - else if (msg->security & APPLICATION_SMIME) - is_smime = 1; + case 2: /* (s)ign */ + msg->security |= (is_smime ? SMIMESIGN : PGPSIGN); + msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT); + break; - if (is_smime) - choice = - mutt_multi_choice (_ - ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"), - _("esabpc")); - else - choice = - mutt_multi_choice (_ - ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"), - _("esabmc")); - - switch (choice) { - case 1: /* (e)ncrypt */ - msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT); - msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN); - break; + case 3: /* sign (a)s */ + p = crypt_ask_for_key(_("Sign as: "), KEYFLAG_CANSIGN, + is_smime ? APPLICATION_SMIME : APPLICATION_PGP, + NULL); + if (p) { + snprintf(buf, sizeof(buf), "0x%s", crypt_keyid(p)); + m_strreplace(is_smime ? &SmimeDefaultKey : &PgpSignAs, buf); + key_list_wipe(&p); + msg->security |= (is_smime ? SMIMESIGN : PGPSIGN); + } + *redraw = REDRAW_FULL; + break; - case 2: /* (s)ign */ - msg->security |= (is_smime ? SMIMESIGN : PGPSIGN); - msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT); - break; + case 4: /* (b)oth */ + if (is_smime) { + msg->security = SMIMEENCRYPT | SMIMESIGN; + } else { + msg->security = PGPENCRYPT | PGPSIGN; + } + break; - case 3: /* sign (a)s */ - if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN, - is_smime ? APPLICATION_SMIME : - APPLICATION_PGP, NULL))) - { - snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p)); - m_strreplace(is_smime ? &SmimeDefaultKey : &PgpSignAs, - input_signas); - crypt_free_key (&p); + case 5: /* (p)gp or s/(m)ime */ + is_smime = !is_smime; + break; - msg->security |= (is_smime ? SMIMESIGN : PGPSIGN); + case 6: /* (c)lear */ + return msg->security = 0; } - *redraw = REDRAW_FULL; - break; - - case 4: /* (b)oth */ - msg->security = - (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN)); - break; - - case 5: /* (p)gp or s/(m)ime */ - is_smime = !is_smime; - break; - - case 6: /* (c)lear */ - return msg->security = 0; - } - if (is_smime) { - msg->security &= ~APPLICATION_PGP; - msg->security |= APPLICATION_SMIME; - } else { - msg->security &= ~APPLICATION_SMIME; - msg->security |= APPLICATION_PGP; - } + if (is_smime) { + msg->security &= ~APPLICATION_PGP; + msg->security |= APPLICATION_SMIME; + } else { + msg->security &= ~APPLICATION_SMIME; + msg->security |= APPLICATION_PGP; + } - return msg->security; + return msg->security; } -int crypt_smime_verify_sender (HEADER * h) +int crypt_smime_verify_sender(HEADER *h) { - address_t *sender = NULL; - unsigned int ret = 1; + address_t *sender = NULL; + unsigned int ret = 1; - if (h->env->from) { - h->env->from = mutt_expand_aliases (h->env->from); - sender = h->env->from; - } - else if (h->env->sender) { - h->env->sender = mutt_expand_aliases (h->env->sender); - sender = h->env->sender; - } + if (h->env->from) { + h->env->from = mutt_expand_aliases(h->env->from); + sender = h->env->from; + } else if (h->env->sender) { + h->env->sender = mutt_expand_aliases (h->env->sender); + sender = h->env->sender; + } - if (sender) { - if (signature_key) { - gpgme_key_t key = signature_key; - gpgme_user_id_t uid = NULL; - int sender_length = 0; - int uid_length = 0; - - sender_length = m_strlen(sender->mailbox); - for (uid = key->uids; uid && ret; uid = uid->next) { - uid_length = m_strlen(uid->email); - if (1 && (uid->email[0] == '<') - && (uid->email[uid_length - 1] == '>') - && (uid_length == sender_length + 2) - && (!m_strncmp (uid->email + 1, sender->mailbox, sender_length))) - ret = 0; - } + if (!sender) { + mutt_any_key_to_continue ("Failed to figure out sender"); + goto end; } - else - mutt_any_key_to_continue ("Failed to verify sender"); - } - else - mutt_any_key_to_continue ("Failed to figure out sender"); - if (signature_key) { - gpgme_key_release (signature_key); - signature_key = NULL; - } + if (signature_key) { + gpgme_key_t key = signature_key; + gpgme_user_id_t uid = NULL; + int sender_length = 0; + int uid_length = 0; + + sender_length = m_strlen(sender->mailbox); + for (uid = key->uids; uid && ret; uid = uid->next) { + uid_length = m_strlen(uid->email); + if (1 && (uid->email[0] == '<') + && (uid->email[uid_length - 1] == '>') + && (uid_length == sender_length + 2) + && (!m_strncmp (uid->email + 1, sender->mailbox, sender_length))) + ret = 0; + } + } else { + mutt_any_key_to_continue ("Failed to verify sender"); + } - return ret; + end: + if (signature_key) { + gpgme_key_unref(signature_key); + signature_key = NULL; + } + return ret; } static void crypt_invoke_import(FILE *stream, int smime) diff --git a/init.h b/init.h index 046fecd..1dac55d 100644 --- a/init.h +++ b/init.h @@ -1652,12 +1652,6 @@ struct option_t MuttVars[] = { ** .pp ** (PGP only) */ - {"pgp_long_ids", DT_BOOL, R_NONE, OPTPGPLONGIDS, "no" }, - /* - ** .pp - ** If \fIset\fP, use 64 bit PGP key IDs. \fIUnset\fP uses the normal 32 bit Key IDs. - ** (PGP only) - */ {"pgp_retainable_sigs", DT_BOOL, R_NONE, OPTPGPRETAINABLESIG, "no" }, /* ** .pp diff --git a/lib-lib/array.h b/lib-lib/array.h index f0f6c9c..dd23a35 100644 --- a/lib-lib/array.h +++ b/lib-lib/array.h @@ -35,7 +35,7 @@ static inline void \ prefix##_array_wipe(prefix##_array *array) { \ while (array->len) { \ - (dtor)(&array->arr[--array->len]); \ + dtor(&array->arr[--array->len]); \ } \ p_delete(&array->arr); \ } \ @@ -57,4 +57,7 @@ DO_ARRAY_TYPE(void, _); void __array_insert(__array *array, ssize_t pos, void *item); void *__array_take(__array *array, ssize_t pos); +DO_ARRAY_TYPE(char *, string); +DO_ARRAY_FUNCS(char *, string, p_delete); + #endif /* MUTT_LIB_LIB_ARRAY_H */ diff --git a/lib-ui/enter.c b/lib-ui/enter.c index d42c855..0d61f2d 100644 --- a/lib-ui/enter.c +++ b/lib-ui/enter.c @@ -177,7 +177,7 @@ int mutt_enter_string (char *buf, size_t buflen, int y, int x, int flags) int rv; ENTER_STATE *es = mutt_new_enter_state (); - rv = _mutt_enter_string (buf, buflen, y, x, flags, 0, NULL, NULL, es); + rv = _mutt_enter_string(buf, buflen, y, x, flags, 0, NULL, NULL, es); mutt_free_enter_state (&es); return rv; } diff --git a/mutt.h b/mutt.h index 43d7ffb..1ee8fb4 100644 --- a/mutt.h +++ b/mutt.h @@ -341,7 +341,6 @@ enum { OPTCRYPTREPLYSIGN, OPTCRYPTREPLYSIGNENCRYPTED, OPTSMIMEISDEFAULT, - OPTPGPLONGIDS, OPTPGPAUTODEC, OPTPGPRETAINABLESIG, OPTFORWDECRYPT,