diff options
author | Eduardo Chappa <chappa@washington.edu> | 2014-06-20 23:23:19 -0600 |
---|---|---|
committer | Eduardo Chappa <chappa@washington.edu> | 2014-06-20 23:23:19 -0600 |
commit | 121a42f3d82c1b98c384857960d14b2057a95c41 (patch) | |
tree | 3dbd271cc59b33cee35acd5a3dd55a997c7848bc | |
parent | 60b67de2ba4be4d2bfeeeea685869e9a5a7363c0 (diff) | |
download | alpine-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.
-rw-r--r-- | VERSION | 2 | ||||
-rw-r--r-- | alpine/arg.c | 21 | ||||
-rw-r--r-- | alpine/conftype.h | 1 | ||||
-rw-r--r-- | alpine/mailpart.c | 3 | ||||
-rw-r--r-- | alpine/osdep/mswin.rc | 8 | ||||
-rw-r--r-- | alpine/smime.c | 52 | ||||
-rwxr-xr-x | configure | 33 | ||||
-rw-r--r-- | configure.ac | 16 | ||||
-rw-r--r-- | doc/alpine.1 | 2 | ||||
-rw-r--r-- | doc/tech-notes/index.html | 2 | ||||
-rw-r--r-- | doc/tech-notes/tech-notes.txt | 2 | ||||
-rw-r--r-- | imap/src/c-client/rfc822.c | 94 | ||||
-rw-r--r-- | mapi/pmapi.c | 2 | ||||
-rw-r--r-- | mapi/pmapi.rc | 8 | ||||
-rw-r--r-- | pith/conftype.h | 10 | ||||
-rw-r--r-- | pith/filter.c | 209 | ||||
-rw-r--r-- | pith/mimedesc.c | 2 | ||||
-rw-r--r-- | pith/pine.hlp | 56 | ||||
-rw-r--r-- | pith/reply.c | 2 | ||||
-rw-r--r-- | pith/send.c | 5 | ||||
-rw-r--r-- | pith/smime.c | 21 | ||||
-rw-r--r-- | pith/smkeys.c | 132 | ||||
-rw-r--r-- | pith/smkeys.h | 2 | ||||
-rw-r--r-- | po/Makefile.in | 2 |
24 files changed, 514 insertions, 173 deletions
@@ -1 +1 @@ -2.19.9991 +2.19.9992 diff --git a/alpine/arg.c b/alpine/arg.c index b256de62..592adb64 100644 --- a/alpine/arg.c +++ b/alpine/arg.c @@ -4,8 +4,8 @@ static char rcsid[] = "$Id: arg.c 900 2008-01-05 01:13:26Z hubert@u.washington.e /* * ======================================================================== - * Copyright 2006-2008 University of Washington * Copyright 2013-2014 Eduardo Chappa + * Copyright 2006-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -1190,13 +1190,21 @@ pinerc_cmdline_opt(char *arg) if(!arg || !arg[0]) return 0; + if((value = strchr(arg, '=')) != NULL){ + i = value - arg; + arg[i] = '\0'; + } + else + i = -1; + for(v = ps_global->vars; v->name != NULL; v++){ - if(v->is_used && struncmp(v->name, arg, strlen(v->name)) == 0){ + if(v->is_used && strucmp(v->name, arg) == 0){ p1 = arg + strlen(v->name); + if(i > 0) arg[i] = '='; - /*----- Skip to '=' -----*/ + /*----- Skip to '=' -----*/ while(*p1 && (*p1 == '\t' || *p1 == ' ')) - p1++; + p1++; if(*p1 != '='){ char buf[MAILTMPLEN]; @@ -1208,8 +1216,11 @@ pinerc_cmdline_opt(char *arg) p1++; break; - } + } } + + + if(i > 0) arg[i] = '='; /* no match, check for a feature name used directly */ if(v->name == NULL){ diff --git a/alpine/conftype.h b/alpine/conftype.h index f6d98704..6333c819 100644 --- a/alpine/conftype.h +++ b/alpine/conftype.h @@ -64,6 +64,7 @@ typedef struct conf_line { struct smime_data { WhichCerts ctype; int deleted; + char address[MAILTMPLEN]; } s; #endif /* SMIME */ struct context_and_screen { diff --git a/alpine/mailpart.c b/alpine/mailpart.c index 56ee8afa..0a7e1b5e 100644 --- a/alpine/mailpart.c +++ b/alpine/mailpart.c @@ -2704,6 +2704,9 @@ format_msg_att(long int msgno, ATTACH_S **a, HANDLE_S **handlesp, gf_io_t pc, in && gf_puts("text segment]", pc) && gf_puts(NEWLINE, pc))) rv = 0; + + ++(*a); + } else if((*a)->body->subtype && strucmp((*a)->body->subtype, "external-body") == 0) { diff --git a/alpine/osdep/mswin.rc b/alpine/osdep/mswin.rc index 370044fe..97c7e06d 100644 --- a/alpine/osdep/mswin.rc +++ b/alpine/osdep/mswin.rc @@ -244,8 +244,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,19,9991,0 - PRODUCTVERSION 2,19,9991,0 + FILEVERSION 2,19,9992,0 + PRODUCTVERSION 2,19,9992,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -267,12 +267,12 @@ BEGIN #else VALUE "FileDescription", "Alpine\0" #endif - VALUE "FileVersion", "2.19.9991\0" + VALUE "FileVersion", "2.19.9992\0" VALUE "InternalName", "alpine\0" VALUE "LegalCopyright", "Copyright 2006-2009 University of Washington, Copyright 2013-2014\0" VALUE "OriginalFilename", "alpine.exe\0" VALUE "ProductName", "alpine\0" - VALUE "ProductVersion", "2.19.9991\0" + VALUE "ProductVersion", "2.19.9992\0" END END BLOCK "VarFileInfo" diff --git a/alpine/smime.c b/alpine/smime.c index caf0581a..2987d9bf 100644 --- a/alpine/smime.c +++ b/alpine/smime.c @@ -1211,12 +1211,12 @@ manage_certs_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned flags) if(PATHCERTDIR(ctype) == NULL) return 0; - if((cert = get_cert_for((*cl)->value+3, ctype)) == NULL){ + if((cert = get_cert_for((*cl)->d.s.address, ctype)) == NULL){ q_status_message(SM_ORDER, 1, 3, _("Problem Reading Certificate")); rv = 0; } else{ - display_certificate_information(ps, cert, (*cl)->value+3, ctype, (*cl)->varmem); + display_certificate_information(ps, cert, (*cl)->d.s.address, ctype, (*cl)->varmem); rv = 10 + (*cl)->varmem; } break; @@ -1288,6 +1288,20 @@ manage_certs_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned flags) return rv; } +void +smime_setup_size(char **s, size_t n) +{ + char *t = *s; + *t++ = ' '; + *t++ = '%'; + *t++ = '-'; + sprintf(t+strlen(t), "%d.%d", n, n); + t += strlen(t); + *t++ = 's'; + *t++ = ' '; + *s = t; +} + void smime_manage_certs_init(struct pine *ps, CONF_S **ctmp, CONF_S **first_line, WhichCerts ctype, int fline) { char tmp[200]; @@ -1329,6 +1343,28 @@ void smime_manage_certs_init(struct pine *ps, CONF_S **ctmp, CONF_S **first_line if(data){ CertList *cl; int i; + int s, e, df, dt, md5; /* sizes of certain fields */ + int nf; /* number of fields */ + char u[MAILTMPLEN], *t; + + for(cl = data, e = 0; cl; cl = cl->next) + if(cl->name && strlen(cl->name) > e) + e = strlen(cl->name); + + if(ctype != Private) + e -= 4; /* remove extension length */ + nf = 5; /* there are 5 fields */ + s = 3; /* status has fixed size */ + df = dt = 8; /* date from and date to have fixed size */ + md5 = ps->ttyo->screen_cols - s - df - dt - e - 2*nf; + + memset(u, '\0', sizeof(u)); + t = u; + smime_setup_size(&t, s); + smime_setup_size(&t, e); + smime_setup_size(&t, df); + smime_setup_size(&t, dt); + smime_setup_size(&t, md5); for(cl = data, i = 0; cl; cl = cl->next) if(cl->name){ @@ -1343,10 +1379,16 @@ void smime_manage_certs_init(struct pine *ps, CONF_S **ctmp, CONF_S **first_line (*ctmp)->help = ctype == Public ? h_config_smime_manage_public_menu : (ctype == Private ? h_config_smime_manage_private_menu : h_config_smime_manage_cacerts_menu); - snprintf(tmp, sizeof(tmp), " %s\t%s", (*ctmp)->d.s.deleted ? "D" : " ", cl->name); + if(ctype != Private) + cl->name[strlen(cl->name) - 4] = '\0'; + strncpy((*ctmp)->d.s.address, cl->name, sizeof((*ctmp)->d.s.address)); + (*ctmp)->d.s.address[sizeof((*ctmp)->d.s.address) - 1] = '\0'; + snprintf(tmp, sizeof(tmp), u, + (*ctmp)->d.s.deleted ? "D" : " ", + cl->name, DATEFROMCERT(cl), DATETOCERT(cl), MD5CERT(cl)); + if(ctype != Private) + cl->name[strlen(cl->name)] = '.'; (*ctmp)->value = cpystr(tmp); - for(s = (*ctmp)->value; s && (t = strstr(s, ext)) != NULL; s = t+1); - if(s) *(s-1) = '\0'; if(i == fline+1 && first_line && !*first_line) *first_line = *ctmp; } @@ -1,7 +1,7 @@ #! /bin/sh # From configure.ac Rev:14 by chappa@washington.edu. # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for alpine 2.19.9991. +# Generated by GNU Autoconf 2.69 for alpine 2.19.9992. # # Report bugs to <chappa@washington.edu>. # @@ -730,8 +730,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='alpine' PACKAGE_TARNAME='alpine' -PACKAGE_VERSION='2.19.9991' -PACKAGE_STRING='alpine 2.19.9991' +PACKAGE_VERSION='2.19.9992' +PACKAGE_STRING='alpine 2.19.9992' PACKAGE_BUGREPORT='chappa@washington.edu' PACKAGE_URL='' @@ -1596,7 +1596,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures alpine 2.19.9991 to adapt to many kinds of systems. +\`configure' configures alpine 2.19.9992 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1666,7 +1666,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of alpine 2.19.9991:";; + short | recursive ) echo "Configuration of alpine 2.19.9992:";; esac cat <<\_ACEOF @@ -1953,7 +1953,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -alpine configure 2.19.9991 +alpine configure 2.19.9992 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2559,7 +2559,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by alpine $as_me 2.19.9991, which was +It was created by alpine $as_me 2.19.9992, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3380,7 +3380,7 @@ fi # Define the identity of the package. PACKAGE='alpine' - VERSION='2.19.9991' + VERSION='2.19.9992' cat >>confdefs.h <<_ACEOF @@ -15652,6 +15652,8 @@ fi if test "x$with_ssl" = "xno" ; then alpine_SSLTYPE="none" +elif test -d /usr/local/ssl ; then + alpine_SSLDIR="/usr/local/ssl" else case $host in *-linux-gnu*) @@ -15720,6 +15722,8 @@ else alpine_SSLLIB="/sw/lib" alpine_SSLCERTS="/sw/etc/ssl/certs" alpine_SSLKEYS="/sw/etc/ssl/private" + elif test -d /usr/local/ssl ; then + alpine_SSLDIR="/usr/local/ssl" elif test -d /System/Library/OpenSSL ; then alpine_SSLDIR="/System/Library/OpenSSL" alpine_SSLCERTS="$alpine_SSLDIR/certs" @@ -15751,8 +15755,13 @@ else alpine_SSLDIR="/etc/ssl" alpine_SSLCERTS="$alpine_SSLDIR/certs" alpine_SSLKEYS="$alpine_SSLDIR/private" - alpine_SSLINCLUDE="/usr/include/openssl" - alpine_SSLLIB="/usr/lib" + if test -d /usr/local/include/openssl ; then + alpine_SSLINCLUDE="/usr/local/include/openssl" + alpine_SSLLIB="/usr/local/lib" + else + alpine_SSLINCLUDE="/usr/include/openssl" + alpine_SSLLIB="/usr/lib" + fi ;; *-*-openbsd*) alpine_SSLDIR="/etc/ssl" @@ -20355,7 +20364,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by alpine $as_me 2.19.9991, which was +This file was extended by alpine $as_me 2.19.9992, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -20421,7 +20430,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -alpine config.status 2.19.9991 +alpine config.status 2.19.9992 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 672a0bdb..5796364f 100644 --- a/configure.ac +++ b/configure.ac @@ -715,6 +715,11 @@ AC_ARG_WITH(ssl, if test "x$with_ssl" = "xno" ; then alpine_SSLTYPE="none" +elif test -d /usr/local/ssl ; then +dnl When the system has openssl installed in its default location +dnl instead of the one used by the distribution assume that this +dnl is the one intended to be used. + alpine_SSLDIR="/usr/local/ssl" else dnl preload c-client default locations/options case $host in @@ -787,6 +792,8 @@ dnl find it anywhere else. alpine_SSLLIB="/sw/lib" alpine_SSLCERTS="/sw/etc/ssl/certs" alpine_SSLKEYS="/sw/etc/ssl/private" + elif test -d /usr/local/ssl ; then + alpine_SSLDIR="/usr/local/ssl" elif test -d /System/Library/OpenSSL ; then alpine_SSLDIR="/System/Library/OpenSSL" alpine_SSLCERTS="$alpine_SSLDIR/certs" @@ -818,8 +825,13 @@ dnl find it anywhere else. alpine_SSLDIR="/etc/ssl" alpine_SSLCERTS="$alpine_SSLDIR/certs" alpine_SSLKEYS="$alpine_SSLDIR/private" - alpine_SSLINCLUDE="/usr/include/openssl" - alpine_SSLLIB="/usr/lib" + if test -d /usr/local/include/openssl ; then + alpine_SSLINCLUDE="/usr/local/include/openssl" + alpine_SSLLIB="/usr/local/lib" + else + alpine_SSLINCLUDE="/usr/include/openssl" + alpine_SSLLIB="/usr/lib" + fi ;; *-*-openbsd*) alpine_SSLDIR="/etc/ssl" diff --git a/doc/alpine.1 b/doc/alpine.1 index a0e78957..52d8140c 100644 --- a/doc/alpine.1 +++ b/doc/alpine.1 @@ -1,4 +1,4 @@ -.TH alpine 1 "Version 2.19.9991" +.TH alpine 1 "Version 2.19.9992" .SH NAME alpine \- an Alternatively Licensed Program for Internet News and Email .SH SYNTAX diff --git a/doc/tech-notes/index.html b/doc/tech-notes/index.html index 3ec86306..78e9d2aa 100644 --- a/doc/tech-notes/index.html +++ b/doc/tech-notes/index.html @@ -3,7 +3,7 @@ <BODY> <H1>Alpine Technical Notes</H1> -Version 2.19.9991, May 2014 +Version 2.19.9992, June 2014 <H2><A NAME="TOC">Table of Contents</A></H2><P> diff --git a/doc/tech-notes/tech-notes.txt b/doc/tech-notes/tech-notes.txt index 356e49c5..885789eb 100644 --- a/doc/tech-notes/tech-notes.txt +++ b/doc/tech-notes/tech-notes.txt @@ -1,7 +1,7 @@ Alpine Technical Notes - Version 2.19.9991, May 2014 + Version 2.19.9992, June 2014 Table of Contents diff --git a/imap/src/c-client/rfc822.c b/imap/src/c-client/rfc822.c index 03e92ca3..93663e65 100644 --- a/imap/src/c-client/rfc822.c +++ b/imap/src/c-client/rfc822.c @@ -1,4 +1,5 @@ /* ======================================================================== + * Copyright 2013-2014 Eduardo Chappa * Copyright 2008-2010 Mark Crispin * ======================================================================== */ @@ -36,6 +37,10 @@ #include "c-client.h" +/* internal prototype */ +void initialize_body(BODY *b, char *h, char *t); + + /* Support for deprecated features in earlier specifications. Note that this * module follows RFC 2822, and all use of "rfc822" in function names is * for compatibility. Only the code identified by the conditionals below @@ -259,6 +264,23 @@ void rfc822_parse_msg_full (ENVELOPE **en,BODY **bdy,char *s,unsigned long i, /* now parse the body */ if (body) rfc822_parse_content (body,bs,host,depth,flags); } + +void +initialize_body(BODY *b, char *h, char *t) +{ + if(b->type==TYPEMULTIPART){ + PART *p; + cpytxt(&b->mime.text, h+b->mime.offset, b->mime.text.size); + cpytxt(&b->contents.text, t + b->contents.offset, b->size.bytes); + + for(p=b->nested.part; p; p=p->next) + initialize_body((BODY *)p, h, t); + } + else { + cpytxt(&b->mime.text, h+b->mime.offset, b->mime.text.size); + cpytxt(&b->contents.text, t + b->contents.offset, b->size.bytes); + } +} /* Parse a message body content * Accepts: pointer to body structure @@ -337,33 +359,65 @@ void rfc822_parse_content (BODY *body,STRING *bs,char *h,unsigned long depth, case ENC7BIT: /* these are valid nested encodings */ case ENC8BIT: case ENCBINARY: + case ENCBASE64: /* message/rfc822 message encoded as base64 */ break; default: MM_LOG ("Ignoring nested encoding of message contents",PARSE); } - /* hunt for blank line */ + for (c = '\012',j = 0; (i > j) && ((c != '\012') || (CHR(bs) != '\012')); j++) if ((c1 = SNX (bs)) != '\015') c = c1; - if (i > j) { /* unless no more text */ - c1 = SNX (bs); /* body starts here */ - j++; /* advance count */ + + switch(body->encoding){ + case ENCBASE64: + SETPOS (bs,body->contents.offset); + s = (char *) fs_get ((size_t) j + 1); + for (s1 = s,k = j; k--; *s1++ = SNX (bs)); + s[j] = '\0'; /* decode encoded text */ + if((s1 = strstr(s, "--")) != NULL) + *(s1-2) = '\0'; + s1 = (char *) rfc822_base64 (s, strlen(s), &k); + if(s1){ + char *t = strstr(s1, "\r\n\r\n"); + + if(t != NULL){ + char *u; + STRING b; + + t += 4; + u = cpystr(t); + INIT(&b, mail_string, t, strlen(t)); + rfc822_parse_msg_full(&body->nested.msg->env, &body->nested.msg->body, t, + strlen(t), &b, BADHOST, 0, 0); + initialize_body(body->nested.msg->body, u, u); + } + fs_give((void **)&s1); + } + fs_give((void **)&s); + break; + + default: + if (i > j) { /* unless no more text */ + c1 = SNX (bs); /* body starts here */ + j++; /* advance count */ + } + /* note body text offset and header size */ + body->nested.msg->header.text.size = j; + body->nested.msg->text.text.size = body->contents.text.size - j; + body->nested.msg->text.offset = GETPOS (bs); + body->nested.msg->full.offset = body->nested.msg->header.offset = + body->contents.offset; + body->nested.msg->full.text.size = body->contents.text.size; + /* copy header string */ + SETPOS (bs,body->contents.offset); + s = (char *) fs_get ((size_t) j + 1); + for (s1 = s,k = j; k--; *s1++ = SNX (bs)); + s[j] = '\0'; /* tie off string (not really necessary) */ + /* now parse the body */ + rfc822_parse_msg_full (&body->nested.msg->env,&body->nested.msg->body,s, + j,bs,h,depth+1,flags); + fs_give ((void **) &s); /* free header string */ } - /* note body text offset and header size */ - body->nested.msg->header.text.size = j; - body->nested.msg->text.text.size = body->contents.text.size - j; - body->nested.msg->text.offset = GETPOS (bs); - body->nested.msg->full.offset = body->nested.msg->header.offset = - body->contents.offset; - body->nested.msg->full.text.size = body->contents.text.size; - /* copy header string */ - SETPOS (bs,body->contents.offset); - s = (char *) fs_get ((size_t) j + 1); - for (s1 = s,k = j; k--; *s1++ = SNX (bs)); - s[j] = '\0'; /* tie off string (not really necessary) */ - /* now parse the body */ - rfc822_parse_msg_full (&body->nested.msg->env,&body->nested.msg->body,s, - j,bs,h,depth+1,flags); - fs_give ((void **) &s); /* free header string */ /* restore position */ SETPOS (bs,body->contents.offset); } diff --git a/mapi/pmapi.c b/mapi/pmapi.c index 036e19ef..acbc2d5b 100644 --- a/mapi/pmapi.c +++ b/mapi/pmapi.c @@ -1952,7 +1952,7 @@ BOOL APIENTRY DllMain( now = time((time_t *)0); tm_now = localtime(&now); - fprintf(ms_global->dfd, "pmapi32.dll for Alpine Version 2.19.9991\r\n"); + fprintf(ms_global->dfd, "pmapi32.dll for Alpine Version 2.19.9992\r\n"); fprintf(ms_global->dfd, " Build date: %s\r\n", datestamp); fprintf(ms_global->dfd, " please report all bugs to chappa@gmx.com\r\n"); diff --git a/mapi/pmapi.rc b/mapi/pmapi.rc index 815a7a4e..31505bfc 100644 --- a/mapi/pmapi.rc +++ b/mapi/pmapi.rc @@ -98,8 +98,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,19,9991,0 - PRODUCTVERSION 2,19,9991,0 + FILEVERSION 2,19,9992,0 + PRODUCTVERSION 2,19,9992,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x29L @@ -117,14 +117,14 @@ BEGIN VALUE "Comments", "alpine info: http://patches.freeiz.com/alpine\0" VALUE "CompanyName", "Patches for Alpine\0" VALUE "FileDescription", "Simple MAPI DLL for Alpine for Windows\0" - VALUE "FileVersion", "2.19.9991\0" + VALUE "FileVersion", "2.19.9992\0" VALUE "InternalName", "pmapi32\0" VALUE "LegalCopyright", "Copyright ? University of Washington 2006-2009, Eduardo Chappa 2013-2014\0" VALUE "LegalTrademarks", "Apache License, Version 2.0\0" VALUE "OriginalFilename", "pmapi32.dll\0" VALUE "PrivateBuild", " \0" VALUE "ProductName", "Simple MAPI for Alpine for Windows\0" - VALUE "ProductVersion", "2.19.9991\0" + VALUE "ProductVersion", "2.19.9992\0" VALUE "SpecialBuild", " \0" END END 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 </style> + <LI> HTML: <BR>, <BR />, and <BR/> are considered + the same inline tag; the same is valid for the <HR> 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 +"D" 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 +"D" 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 +"D" 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 */ diff --git a/po/Makefile.in b/po/Makefile.in index 4b532b75..858d6983 100644 --- a/po/Makefile.in +++ b/po/Makefile.in @@ -11,7 +11,7 @@ # Origin: gettext-0.16 PACKAGE = alpine -VERSION = 2.19.999 +VERSION = 2.19.9999 PACKAGE_BUGREPORT = chappa@washington.edu SHELL = /bin/sh |