summaryrefslogtreecommitdiff
path: root/pith
diff options
context:
space:
mode:
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 */