summaryrefslogtreecommitdiff
path: root/pith
diff options
context:
space:
mode:
authorEduardo Chappa <chappa@washington.edu>2014-06-20 23:23:19 -0600
committerEduardo Chappa <chappa@washington.edu>2014-06-20 23:23:19 -0600
commit121a42f3d82c1b98c384857960d14b2057a95c41 (patch)
tree3dbd271cc59b33cee35acd5a3dd55a997c7848bc /pith
parent60b67de2ba4be4d2bfeeeea685869e9a5a7363c0 (diff)
downloadalpine-121a42f3d82c1b98c384857960d14b2057a95c41.tar.xz
* new version 2.19.9992
* Alpine would not parse options from the command line, such as -patterns-filters2, correctly. * Add /usr/local/include as a path to find include and libs files for openssl in FreeBSD. * Management certificate screen now prints, in addition to the e-mail address of the owner of the certificates, the dates of validity and the MD5 hash of such certificates. * crash when processing message/rfc822 attachments that are encoded in base64. * Openssl: if /usr/local/ssl exists, assume that this is the intended place where ssl libraries, include files and certificates are located. Typically, distributions do not use this directory, so its existence indicates that Openssl has been specially installed there, so it is probably a preferred place to get the system Openssl files. * Postponed messages whose content-type is text/html, text/enriched and text/richtext are sent with that content-type, even though, after resuming composition, Alpine had changed its type to text/plain. * HTML: <BR>, <BR />, and <BR/&> are considered the same inline tag; the same is valid for the <HR> tag.
Diffstat (limited to 'pith')
-rw-r--r--pith/conftype.h10
-rw-r--r--pith/filter.c209
-rw-r--r--pith/mimedesc.c2
-rw-r--r--pith/pine.hlp56
-rw-r--r--pith/reply.c2
-rw-r--r--pith/send.c5
-rw-r--r--pith/smime.c21
-rw-r--r--pith/smkeys.c132
-rw-r--r--pith/smkeys.h2
9 files changed, 324 insertions, 115 deletions
diff --git a/pith/conftype.h b/pith/conftype.h
index 8ba7941c..11bf778f 100644
--- a/pith/conftype.h
+++ b/pith/conftype.h
@@ -676,6 +676,9 @@ typedef enum {Public, Private, CACert} WhichCerts;
typedef struct certdata {
unsigned deleted:1; /* certificate is marked deleted */
unsigned renew:1; /* we must renew this list, set at top cert */
+ char *date_from; /* date from which certificate is valid */
+ char *date_to; /* date certificate expires */
+ char *md5; /* MD5 Hash */
} CertData;
typedef struct certlist {
@@ -740,8 +743,11 @@ typedef struct smime_stuff {
: ((X) == Private ? ".key" \
: ((X) == CACert ? ".crt" : ""))))
-#define DELETEDCERT(X) ((X)->data.deleted)
-#define RENEWCERT(X) ((X)->data.renew)
+#define DELETEDCERT(X) ((X)->data.deleted)
+#define RENEWCERT(X) ((X)->data.renew)
+#define DATEFROMCERT(X) ((X)->data.date_from)
+#define DATETOCERT(X) ((X)->data.date_to)
+#define MD5CERT(X) ((X)->data.md5)
#endif /* SMIME */
diff --git a/pith/filter.c b/pith/filter.c
index c60416b1..d1848f87 100644
--- a/pith/filter.c
+++ b/pith/filter.c
@@ -2803,8 +2803,10 @@ typedef struct handler_s {
*/
typedef struct _element_properties {
char *element;
+ size_t len;
int (*handler)(HANDLER_S *, int, int);
unsigned blocklevel:1;
+ unsigned alternate:1;
} ELPROP_S;
/*
@@ -3549,96 +3551,96 @@ static struct html_entities {
* Table of supported elements and corresponding handlers
*/
static ELPROP_S html_element_table[] = {
- {"HTML"}, /* HTML ignore if seen? */
- {"HEAD", html_head}, /* slurp until <BODY> ? */
- {"TITLE", html_title}, /* Document Title */
- {"BASE", html_base}, /* HREF base */
- {"BODY", html_body}, /* HTML BODY */
- {"A", html_a}, /* Anchor */
- {"ABBR", html_abbr}, /* Abbreviation */
- {"IMG", html_img}, /* Image */
- {"MAP", html_map}, /* Image Map */
- {"AREA", html_area}, /* Image Map Area */
- {"HR", html_hr, 1}, /* Horizontal Rule */
- {"BR", html_br}, /* Line Break */
- {"P", html_p, 1}, /* Paragraph */
- {"OL", html_ol, 1}, /* Ordered List */
- {"UL", html_ul, 1}, /* Unordered List */
- {"MENU", html_menu}, /* Menu List */
- {"DIR", html_dir}, /* Directory List */
- {"LI", html_li}, /* ... List Item */
- {"DL", html_dl, 1}, /* Definition List */
- {"DT", html_dt}, /* ... Def. Term */
- {"DD", html_dd}, /* ... Def. Definition */
- {"I", html_i}, /* Italic Text */
- {"EM", html_em}, /* Typographic Emphasis */
- {"STRONG", html_strong}, /* STRONG Typo Emphasis */
- {"VAR", html_i}, /* Variable Name */
- {"B", html_b}, /* Bold Text */
- {"U", html_u}, /* Underline Text */
- {"S", html_s}, /* Strike-Through Text */
- {"STRIKE", html_s}, /* Strike-Through Text */
- {"BIG", html_big}, /* Big Font Text */
- {"SMALL", html_small}, /* Small Font Text */
- {"FONT", html_font}, /* Font display directives */
- {"BLOCKQUOTE", html_blockquote, 1}, /* Blockquote */
- {"ADDRESS", html_address, 1}, /* Address */
- {"CENTER", html_center}, /* Centered Text v3.2 */
- {"DIV", html_div, 1}, /* Document Division 3.2 */
- {"SPAN", html_span}, /* Text Span */
- {"H1", html_h1, 1}, /* Headings... */
- {"H2", html_h2, 1},
- {"H3", html_h3,1},
- {"H4", html_h4, 1},
- {"H5", html_h5, 1},
- {"H6", html_h6, 1},
- {"PRE", html_pre, 1}, /* Preformatted Text */
- {"KBD", html_kbd}, /* Keyboard Input (NO OP) */
- {"DFN", html_dfn}, /* Definition (NO OP) */
- {"VAR", html_var}, /* Variable (NO OP) */
- {"TT", html_tt}, /* Typetype (NO OP) */
- {"SAMP", html_samp}, /* Sample Text (NO OP) */
- {"CITE", html_cite}, /* Citation (NO OP) */
- {"CODE", html_code}, /* Code Text (NO OP) */
- {"INS", html_ins}, /* Text Inseted (NO OP) */
- {"DEL", html_del}, /* Text Deleted (NO OP) */
- {"SUP", html_sup}, /* Text Superscript (NO OP) */
- {"SUB", html_sub}, /* Text Superscript (NO OP) */
- {"STYLE", html_style}, /* CSS Definitions */
+ {"HTML", 4}, /* HTML ignore if seen? */
+ {"HEAD", 4, html_head}, /* slurp until <BODY> ? */
+ {"TITLE", 5, html_title}, /* Document Title */
+ {"BASE", 4, html_base}, /* HREF base */
+ {"BODY", 4, html_body}, /* HTML BODY */
+ {"A", 1, html_a}, /* Anchor */
+ {"ABBR", 4, html_abbr}, /* Abbreviation */
+ {"IMG", 3, html_img}, /* Image */
+ {"MAP", 3, html_map}, /* Image Map */
+ {"AREA", 4, html_area}, /* Image Map Area */
+ {"HR", 2, html_hr, 1, 1}, /* Horizontal Rule */
+ {"BR", 2, html_br, 0, 1}, /* Line Break */
+ {"P", 1, html_p, 1}, /* Paragraph */
+ {"OL", 2, html_ol, 1}, /* Ordered List */
+ {"UL", 2, html_ul, 1}, /* Unordered List */
+ {"MENU", 4, html_menu}, /* Menu List */
+ {"DIR", 3, html_dir}, /* Directory List */
+ {"LI", 2, html_li}, /* ... List Item */
+ {"DL", 2, html_dl, 1}, /* Definition List */
+ {"DT", 2, html_dt}, /* ... Def. Term */
+ {"DD", 2, html_dd}, /* ... Def. Definition */
+ {"I", 1, html_i}, /* Italic Text */
+ {"EM", 2, html_em}, /* Typographic Emphasis */
+ {"STRONG", 6, html_strong}, /* STRONG Typo Emphasis */
+ {"VAR", 3, html_i}, /* Variable Name */
+ {"B", 1, html_b}, /* Bold Text */
+ {"U", 1, html_u}, /* Underline Text */
+ {"S", 1, html_s}, /* Strike-Through Text */
+ {"STRIKE", 6, html_s}, /* Strike-Through Text */
+ {"BIG", 3, html_big}, /* Big Font Text */
+ {"SMALL", 5, html_small}, /* Small Font Text */
+ {"FONT", 4, html_font}, /* Font display directives */
+ {"BLOCKQUOTE", 10, html_blockquote, 1}, /* Blockquote */
+ {"ADDRESS", 7, html_address, 1}, /* Address */
+ {"CENTER", 6, html_center}, /* Centered Text v3.2 */
+ {"DIV", 3, html_div, 1}, /* Document Division 3.2 */
+ {"SPAN", 4, html_span}, /* Text Span */
+ {"H1", 2, html_h1, 1}, /* Headings... */
+ {"H2", 2, html_h2, 1},
+ {"H3", 2, html_h3,1},
+ {"H4", 2, html_h4, 1},
+ {"H5", 2, html_h5, 1},
+ {"H6", 2, html_h6, 1},
+ {"PRE", 3, html_pre, 1}, /* Preformatted Text */
+ {"KBD", 3, html_kbd}, /* Keyboard Input (NO OP) */
+ {"DFN", 3, html_dfn}, /* Definition (NO OP) */
+ {"VAR", 3, html_var}, /* Variable (NO OP) */
+ {"TT", 2, html_tt}, /* Typetype (NO OP) */
+ {"SAMP", 4, html_samp}, /* Sample Text (NO OP) */
+ {"CITE", 4, html_cite}, /* Citation (NO OP) */
+ {"CODE", 4, html_code}, /* Code Text (NO OP) */
+ {"INS", 3, html_ins}, /* Text Inseted (NO OP) */
+ {"DEL", 3, html_del}, /* Text Deleted (NO OP) */
+ {"SUP", 3, html_sup}, /* Text Superscript (NO OP) */
+ {"SUB", 3, html_sub}, /* Text Superscript (NO OP) */
+ {"STYLE", 5, html_style}, /* CSS Definitions */
/*----- Handlers below UNIMPLEMENTED (and won't until later) -----*/
- {"FORM", html_form, 1}, /* form within a document */
- {"INPUT", html_input}, /* One input field, options */
- {"BUTTON", html_button}, /* Push Button */
- {"OPTION", html_option}, /* One option within Select */
- {"OPTION", html_optgroup}, /* Option Group Definition */
- {"SELECT", html_select}, /* Selection from a set */
- {"TEXTAREA", html_textarea}, /* A multi-line input field */
- {"LABEL", html_label}, /* Control Label */
- {"FIELDSET", html_fieldset, 1}, /* Fieldset Control Group */
+ {"FORM", 4, html_form, 1}, /* form within a document */
+ {"INPUT", 5, html_input}, /* One input field, options */
+ {"BUTTON", 6, html_button}, /* Push Button */
+ {"OPTION", 6, html_option}, /* One option within Select */
+ {"OPTION", 6, html_optgroup}, /* Option Group Definition */
+ {"SELECT", 6, html_select}, /* Selection from a set */
+ {"TEXTAREA", 8, html_textarea}, /* A multi-line input field */
+ {"LABEL", 5, html_label}, /* Control Label */
+ {"FIELDSET", 8, html_fieldset, 1}, /* Fieldset Control Group */
/*----- Handlers below NEVER TO BE IMPLEMENTED -----*/
- {"SCRIPT", html_script}, /* Embedded scripting statements */
- {"APPLET", NULL}, /* Embedded applet statements */
- {"OBJECT", NULL}, /* Embedded object statements */
- {"LINK", NULL}, /* References to external data */
- {"PARAM", NULL}, /* Applet/Object parameters */
+ {"SCRIPT", 6, html_script}, /* Embedded scripting statements */
+ {"APPLET", 6, NULL}, /* Embedded applet statements */
+ {"OBJECT", 6, NULL}, /* Embedded object statements */
+ {"LINK", 4, NULL}, /* References to external data */
+ {"PARAM", 5, NULL}, /* Applet/Object parameters */
/*----- Handlers below provide limited support for RFC 1942 Tables -----*/
- {"TABLE", html_table, 1}, /* Table */
- {"CAPTION", html_caption}, /* Table Caption */
- {"TR", html_tr}, /* Table Table Row */
- {"TD", html_td}, /* Table Table Data */
- {"TH", html_th}, /* Table Table Head */
- {"THEAD", html_thead}, /* Table Table Head */
- {"TBODY", html_tbody}, /* Table Table Body */
- {"TFOOT", html_tfoot}, /* Table Table Foot */
- {"COL", html_col}, /* Table Column Attibutes */
- {"COLGROUP", html_colgroup}, /* Table Column Group Attibutes */
-
- {NULL, NULL}
+ {"TABLE", 5, html_table, 1}, /* Table */
+ {"CAPTION", 7, html_caption}, /* Table Caption */
+ {"TR", 2, html_tr}, /* Table Table Row */
+ {"TD", 2, html_td}, /* Table Table Data */
+ {"TH", 2, html_th}, /* Table Table Head */
+ {"THEAD", 5, html_thead}, /* Table Table Head */
+ {"TBODY", 5, html_tbody}, /* Table Table Body */
+ {"TFOOT", 5, html_tfoot}, /* Table Table Foot */
+ {"COL", 3, html_col}, /* Table Column Attibutes */
+ {"COLGROUP", 8, html_colgroup}, /* Table Column Group Attibutes */
+
+ {NULL, 0, NULL}
};
@@ -3646,15 +3648,15 @@ static ELPROP_S html_element_table[] = {
* Table of supported RSS 2.0 elements
*/
static ELPROP_S rss_element_table[] = {
- {"RSS", rss_rss}, /* RSS 2.0 version */
- {"CHANNEL", rss_channel}, /* RSS 2.0 Channel */
- {"TITLE", rss_title}, /* RSS 2.0 Title */
- {"IMAGE", rss_image}, /* RSS 2.0 Channel Image */
- {"LINK", rss_link}, /* RSS 2.0 Channel/Item Link */
- {"DESCRIPTION", rss_description}, /* RSS 2.0 Channel/Item Description */
- {"ITEM", rss_item}, /* RSS 2.0 Channel ITEM */
- {"TTL", rss_ttl}, /* RSS 2.0 Item TTL */
- {NULL, NULL}
+ {"RSS", 3, rss_rss}, /* RSS 2.0 version */
+ {"CHANNEL", 7, rss_channel}, /* RSS 2.0 Channel */
+ {"TITLE", 5, rss_title}, /* RSS 2.0 Title */
+ {"IMAGE", 5, rss_image}, /* RSS 2.0 Channel Image */
+ {"LINK", 4, rss_link}, /* RSS 2.0 Channel/Item Link */
+ {"DESCRIPTION", 11, rss_description}, /* RSS 2.0 Channel/Item Description */
+ {"ITEM", 4, rss_item}, /* RSS 2.0 Channel ITEM */
+ {"TTL", 3, rss_ttl}, /* RSS 2.0 Item TTL */
+ {NULL, 0, NULL}
};
@@ -7167,9 +7169,14 @@ ELPROP_S *
element_properties(FILTER_S *fd, char *el_name)
{
register ELPROP_S *el_table = ELEMENTS(fd);
+ size_t len_name = strlen(el_name);
for(; el_table->element; el_table++)
- if(!strucmp(el_name, el_table->element))
+ if(!strucmp(el_name, el_table->element)
+ || (el_table->alternate
+ && len_name == el_table->len + 1
+ && el_name[el_table->len] == '/'
+ && !struncmp(el_name, el_table->element, el_table->len)))
return(el_table);
return(NULL);
@@ -7427,6 +7434,24 @@ html_element_collector(FILTER_S *fd, int ch)
if(!ED(fd)->hit_equal)
ED(fd)->hit_equal = (ch == '=');
}
+ else if(ch == '/' && ED(fd)->len && !ED(fd)->element){
+ ELPROP_S *ep;
+ ep = element_properties(fd, ED(fd)->buf);
+ if(ep){
+ if(!ep->alternate)
+ ED(fd)->badform = 1;
+ else{
+ if(ED(fd)->len < ((ED(fd)->element || !ED(fd)->hit_equal)
+ ? HTML_BUF_LEN:MAX_ELEMENT)){
+ ED(fd)->buf[(ED(fd)->len)++] = ch; /* add this exception */
+ }
+ else
+ ED(fd)->overrun = 1;
+ }
+ }
+ else
+ ED(fd)->badform = 1;
+ }
else
ED(fd)->badform = 1; /* unrecognized data?? */
diff --git a/pith/mimedesc.c b/pith/mimedesc.c
index 8a1d7f7d..67d52ae6 100644
--- a/pith/mimedesc.c
+++ b/pith/mimedesc.c
@@ -277,7 +277,7 @@ describe_mime(struct mail_bodystruct *body, char *prefix, int num,
snprintf(a->number, ll, "%s%d",prefix, num);
a->number[ll-1] = '\0';
(a+1)->description = NULL;
- if(body->type == TYPEMESSAGE && body->encoding <= ENCBINARY
+ if(body->type == TYPEMESSAGE && body->encoding <= ENCBASE64
&& body->subtype && strucmp(body->subtype, "rfc822") == 0){
body = body->nested.msg->body;
snprintf(numx, sizeof(numx), "%.*s%d.", sizeof(numx)-20, prefix, num);
diff --git a/pith/pine.hlp b/pith/pine.hlp
index 90be0132..cb0a6d63 100644
--- a/pith/pine.hlp
+++ b/pith/pine.hlp
@@ -140,7 +140,7 @@ with help text for the config screen and the composer that didn't have any
reasonable place to be called from.
Dummy change to get revision in pine.hlp
============= h_revision =================
-Alpine Commit 64 2014-05-31 21:36:57
+Alpine Commit 65 2014-06-20 23:23:15
============= h_news =================
<HTML>
<HEAD>
@@ -205,6 +205,10 @@ Additions include:
<LI> S/MIME: Forwarding a message will include the signed part as part
of the text and not as a multipart message, just as the reply
command does.
+ <LI> HTML: Style tag in body of html message causes Alpine to not write
+ its content until a new &lt;/style&gt;
+ <LI> HTML: &lt;BR&gt;, &lt;BR /&gt;, and &lt;BR/&gt; are considered
+ the same inline tag; the same is valid for the &lt;HR&gt; tag.
<LI> Add support to selective expunge through a subcommand of the
select-apply commands. Read more in the <A
HREF="h_index_cmd_expunge">help</A> for the expunge command.
@@ -296,6 +300,10 @@ Bugs that have been addressed include:
an index was based on scores that needed information from a remote
addressbook in the same server as the folder opened. Reported by
Peter Koellner.
+ <LI> Crash in message/rfc822 attachments encoded in base64.
+ <LI> Postponed messages whose content-type is text/html, text/enriched and
+ text/richtext are sent with that content-type, even though, after
+ resuming composition, Alpine had changed its type to text/plain.
<LI> Alpine cannot handle correctly some characters in the Windows-1256
character set, which might lead to a crash or a corruption in the
screen. Work was done to contain the bug. A more complete fix will
@@ -35154,8 +35162,20 @@ and private information about your key, with the <B>B</B> and
UNIX Alpine only.
<P>
-This screen allows you to manage your public certificates. Available commands and
-a short description of what they do follows.
+This screen allows you to manage your public certificates.
+<P>
+The format of this screen is as follows. There are five fields: The
+leftmost field is normally empty, but it could contain the letter
+&quot;D&quot; to indicate that that certificate has been marked for
+deletion. The next field is the e-mail address of the owner of the
+certificate, shown in its entirety. The third field is the first day of
+validity for that certificate; the fourth field in the last day that that
+certificate is valid, and the fifth field is what can be displayed of the
+MD5 hash of the certificate. You can use any of the last three fields to
+distinguish between two certificates for the same owner.
+<P>
+Available commands in this screen and a short description of what they
+do follows.
<UL>
<LI> <B>I</B> Imports a public certificate to this collection.
<LI> <B>V</B> View information about a certificate such as the name of the person the
@@ -35189,8 +35209,20 @@ All commands provide feedback to let you know about their success or failure.
UNIX Alpine only.
<P>
-This screen allows you to manage your private key. Available commands and
-a short description of what they do follows.
+This screen allows you to manage your private key.
+<P>
+The format of this screen is as follows. There are five fields: The
+leftmost field is normally empty, but it could contain the letter
+&quot;D&quot; to indicate that that certificate has been marked for
+deletion. The next field is the e-mail address of the owner of the
+certificate, shown in its entirety. The third field is the first day of
+validity for that certificate; the fourth field in the last day that that
+certificate is valid, and the fifth field is what can be displayed of the
+MD5 hash of the public certificate corresponding to this private key. You
+can use any of the last three fields to distinguish between two
+certificates for the same owner.
+<P>
+Available commands and a short description of what they do follows.
<UL>
<LI> <B>I</B> Imports a new public key to this collection.
<LI> <B>V</B> View information about the public certificate corresponding to this
@@ -35225,7 +35257,19 @@ All commands provide feedback to let you know about their success or failure.
UNIX Alpine only.
<P>
This screen allows you to manage your collection of certificates that you
-trust. Available commands and a short description of what they do follows.
+trust.
+<P>
+The format of this screen is as follows. There are five fields: The
+leftmost field is normally empty, but it could contain the letter
+&quot;D&quot; to indicate that that certificate has been marked for
+deletion. The next field is the e-mail address of the owner of the
+certificate, shown in its entirety. The third field is the first day of
+validity for that certificate; the fourth field in the last day that that
+certificate is valid, and the fifth field is what can be displayed of the
+MD5 hash of the certificate. You can use any of the last three fields to
+distinguish between two certificates for the same owner.
+<P>
+Available commands and a short description of what they do follows.
<UL>
<LI> <B>I</B> Imports a trusted certificate to this collection. This is
done by reading the certificate and validating it. Once a certificate
diff --git a/pith/reply.c b/pith/reply.c
index 2a8ab158..ec8293db 100644
--- a/pith/reply.c
+++ b/pith/reply.c
@@ -46,9 +46,7 @@ static char rcsid[] = "$Id: reply.c 1074 2008-06-04 00:08:43Z hubert@u.washingto
#include "../pith/ablookup.h"
#include "../pith/mailcmd.h"
#include "../pith/margin.h"
-#ifdef SMIME
#include "../pith/smime.h"
-#endif /* SMIME */
/*
diff --git a/pith/send.c b/pith/send.c
index b01ff7e5..e829d19c 100644
--- a/pith/send.c
+++ b/pith/send.c
@@ -890,7 +890,10 @@ redraft_work(MAILSTREAM **streamp, long int cont_msg, ENVELOPE **outgoing,
else{
*body = mail_newbody();
(*body)->type = TYPETEXT;
- if(b->subtype)
+ if(b->subtype /* these types are transformed to text/plain */
+ && strucmp(b->subtype, "richtext")
+ && strucmp(b->subtype, "enriched")
+ && strucmp(b->subtype, "html"))
(*body)->subtype = cpystr(b->subtype);
if((charset = parameter_val(b->parameter,"charset")) != NULL){
diff --git a/pith/smime.c b/pith/smime.c
index 44cc1955..f29e37df 100644
--- a/pith/smime.c
+++ b/pith/smime.c
@@ -903,6 +903,8 @@ CertList *
certlist_from_personal_certs(PERSONAL_CERT *pc)
{
CertList *cl;
+ X509 *x;
+ char buf[MAXPATH];
if(pc == NULL)
return NULL;
@@ -910,12 +912,21 @@ certlist_from_personal_certs(PERSONAL_CERT *pc)
cl = fs_get(sizeof(CertList));
memset((void *)cl, 0, sizeof(CertList));
cl->name = cpystr(pc->name);
+ x = get_cert_for(pc->name, Public);
+ if(x){
+ if(x->cert_info){
+ cl->data.date_from = smime_get_date(x->cert_info->validity->notBefore);
+ cl->data.date_to = smime_get_date(x->cert_info->validity->notAfter);
+ get_fingerprint(x, EVP_md5(), buf, sizeof(buf), NULL);
+ cl->data.md5 = cpystr(buf);
+ }
+ X509_free(x);
+ }
cl->next = certlist_from_personal_certs(pc->next);
return cl;
}
-
void
renew_cert_data(CertList **data, WhichCerts ctype)
{
@@ -928,8 +939,10 @@ renew_cert_data(CertList **data, WhichCerts ctype)
free_personal_certs(&pc);
setup_privatekey_storage();
*data = certlist_from_personal_certs((PERSONAL_CERT *)ps_global->smime->personal_certs);
- if(data && *data)
+ if(data && *data){
+ resort_certificates(data, ctype);
RENEWCERT(*data) = 0;
+ }
ps_global->smime->privatecertlist = *data;
}
if(ps_global->smime->privatecertlist)
@@ -948,8 +961,10 @@ renew_cert_data(CertList **data, WhichCerts ctype)
add_certs_in_dir(lookup, PATHCERTDIR(ctype), EXTCERT(ctype), data);
else /* if(SMHOLDERTYPE(ctype) == Container) */
*data = mem_to_certlist(CONTENTCERTLIST(ctype), ctype);
- if(data && *data)
+ if(data && *data){
+ resort_certificates(data, ctype);
RENEWCERT(*data) = 0;
+ }
if(ctype == Public)
ps_global->smime->publiccertlist = *data;
else
diff --git a/pith/smkeys.c b/pith/smkeys.c
index 18ed6f1b..437cba6f 100644
--- a/pith/smkeys.c
+++ b/pith/smkeys.c
@@ -32,6 +32,7 @@ static char rcsid[] = "$Id: smkeys.c 1266 2009-07-14 18:39:12Z hubert@u.washingt
#include "../pith/busy.h"
#include "../pith/osdep/lstcmpnt.h"
#include "../pith/util.h"
+#include "../pith/mailindx.h"
#include "smkeys.h"
#ifdef APPLEKEYCHAIN
@@ -45,6 +46,57 @@ static char rcsid[] = "$Id: smkeys.c 1266 2009-07-14 18:39:12Z hubert@u.washingt
/* internal prototypes */
static char *emailstrclean(char *string);
static int mem_add_extra_cacerts(char *contents, X509_LOOKUP *lookup);
+int compare_certs(const void *data1, const void *data2);
+
+int
+compare_certs(const void *data1, const void *data2)
+{
+ int rv;
+ char *s;
+
+ CertList *cl1 = *(CertList **) data1;
+ CertList *cl2 = *(CertList **) data2;
+
+ if((s = strchr(cl1->name, '@')) != NULL)
+ *s = '\0';
+
+ if((s = strchr(cl2->name, '@')) != NULL)
+ *s = '\0';
+
+ if((rv = strucmp(cl1->name, cl2->name)) == 0)
+ rv = strucmp(cl1->name + strlen(cl1->name) + 1, cl2->name + strlen(cl2->name) + 1);
+ cl1->name[strlen(cl1->name)] = '@';
+ cl2->name[strlen(cl2->name)] = '@';
+ return rv;
+}
+
+void
+resort_certificates(CertList **data, WhichCerts ctype)
+{
+ int i, j;
+ CertList *cl = *data;
+ CertList **cll;
+ char *s, *t;
+
+ for(i = 0; cl; cl = cl->next, i++)
+ if(ctype != Private){ /* ctype == Public or ctype == CACerts */
+ for(t = s = cl->name; t = strstr(s, ".crt"); s = t+1);
+ if (s) *(s-1) = '\0';
+ }
+ j = i;
+ cll = fs_get(i*sizeof(CertList *));
+ for(cl = *data, i = 0; cl; cl = cl->next, i++)
+ cll[i] = cl;
+ qsort((void *)cll, j, sizeof(CertList *), compare_certs);
+ for(i = 0; i < j - 1; i++){
+ cll[i]->next = cll[i+1];
+ if(ctype != Private)
+ cll[i]->name[strlen(cll[i]->name)]= '.'; /* restore ".crt" part */
+ }
+ cll[j-1]->next = NULL;
+ *data = cll[0];
+}
+
/* given a certificate and an email address, add the
* extension and md5 key to the name. return an allocated
@@ -56,11 +108,9 @@ smime_name(char *email, X509 *x, WhichCerts ctype)
char bufx[256];
char *rv;
- snprintf(bufx, sizeof(bufx), "%08lx",X509_subject_name_hash(x));
- rv = cpystr(bufx);
-// get_fingerprint(x, EVP_md5(), bufx, sizeof(bufx), NULL);
-// rv = fs_get(strlen(email) + 4 + 2 + strlen(bufx) + 1);
-// sprintf(rv, "%s%s.%s", email, EXTCERT(ctype), bufx);
+ get_fingerprint(x, EVP_md5(), bufx, sizeof(bufx), NULL);
+ rv = fs_get(strlen(email) + 4 + 2 + strlen(bufx) + 1);
+ sprintf(rv, "%s%s.%s", email, EXTCERT(ctype), bufx);
return rv;
}
@@ -128,8 +178,48 @@ emailstrclean(char *string)
}
+char *
+smime_get_date(ASN1_GENERALIZEDTIME *tm)
+{
+ BIO *mb = BIO_new(BIO_s_mem());
+ char iobuf[4096];
+ char date[MAILTMPLEN];
+ char buf[MAILTMPLEN];
+ char *m, *d, *t, *y, *z;
+
+ (void) BIO_reset(mb);
+ ASN1_UTCTIME_print(mb, tm);
+ (void) BIO_flush(mb);
+ BIO_read(mb, iobuf, sizeof(iobuf));
+
+ /* openssl returns the date in the format:
+ * "MONTH (as name) DAY (as number) TIME(hh:mm:ss) YEAR GMT"
+ */
+ m = iobuf;
+ d = strchr(iobuf, ' ');
+ *d++ = '\0';
+ while(*d == ' ') d++;
+ t = strchr(d+1, ' ');
+ *t++ = '\0';
+ while(*t == ' ') t++;
+ y = strchr(t+1, ' ');
+ *y++ = '\0';
+ while(*y == ' ') y++;
+ z = strchr(y+1, ' ');
+ *z++ = '\0';
+ while(*z == ' ') z++;
+
+ snprintf(date, sizeof(date), "%s %s %s %s (%s)", d, m, y, t, z);
+ date[sizeof(date)-1] = '\0';
+ date_str((char *) date, iSDateS1, 1, buf, sizeof(buf), 0);
+ if(buf[strlen(buf) - 1] == '!')
+ buf[strlen(buf) - 1] = '\0';
+
+ return cpystr(buf);
+}
+
/*
- * Add a lookup for each "*.crt" file in the given directory.
+ * Add a lookup for each "*.crt*" file in the given directory.
*/
int
add_certs_in_dir(X509_LOOKUP *lookup, char *path, char *ext, CertList **cdata)
@@ -150,14 +240,29 @@ add_certs_in_dir(X509_LOOKUP *lookup, char *path, char *ext, CertList **cdata)
ret = -1;
} else {
if(cdata){
+ BIO *in;
+ X509 *x;
+
cert = fs_get(sizeof(CertList));
memset((void *)cert, 0, sizeof(CertList));
cert->name = cpystr(d->d_name);
+ /* read buf into a bio and fill the CertData structure */
+ if((in = BIO_new_file(buf, "r"))!=0){
+ x = PEM_read_bio_X509(in, NULL, NULL, NULL);
+ if(x && x->cert_info){
+ cert->data.date_from = smime_get_date(x->cert_info->validity->notBefore);
+ cert->data.date_to = smime_get_date(x->cert_info->validity->notAfter);
+ get_fingerprint(x, EVP_md5(), buf, sizeof(buf), NULL);
+ cert->data.md5 = cpystr(buf);
+ X509_free(x);
+ }
+ BIO_free(in);
+ }
if(*cdata == NULL)
*cdata = cert;
else{
for (cl = *cdata; cl && cl->next; cl = cl->next);
- cl->next = cert;
+ cl->next = cert;
}
}
@@ -211,6 +316,7 @@ get_ca_store(void)
X509_STORE_free(store);
return NULL;
}
+ resort_certificates(&ps_global->smime->cacertlist, CACert);
}
if(!(lookup=X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()))){
@@ -966,13 +1072,23 @@ void
free_certlist(CertList **cl)
{
if(cl && *cl){
- free_certlist(&(*cl)->next);
+ if((*cl)->data.date_from)
+ fs_give((void **) &(*cl)->data.date_from);
+
+ if((*cl)->data.date_to)
+ fs_give((void **) &(*cl)->data.date_to);
+
+ if((*cl)->data.md5)
+ fs_give((void **) &(*cl)->data.md5);
+
if((*cl)->name)
fs_give((void **) &(*cl)->name);
if((*cl)->x509_cert)
X509_free((X509 *) (*cl)->x509_cert);
+ free_certlist(&(*cl)->next);
+
fs_give((void **) cl);
}
}
diff --git a/pith/smkeys.h b/pith/smkeys.h
index 0fe8faad..5214a369 100644
--- a/pith/smkeys.h
+++ b/pith/smkeys.h
@@ -61,6 +61,8 @@ void get_fingerprint(X509 *cert, const EVP_MD *type, char *buf, size_t ma
int certlist_to_file(char *filename, CertList *certlist);
int load_cert_for_key(char *pathdir, EVP_PKEY *pkey, char **certfile, X509 **pcert);
char *smime_name(char *email, X509 *x, WhichCerts ctype);
+char *smime_get_date(ASN1_GENERALIZEDTIME *tm);
+void resort_certificates(CertList **data, WhichCerts ctype);
#endif /* PITH_SMKEYS_INCLUDED */