[gmime: 11/23] Autocrypt: introduce GMimeAutocryptHeader



commit 639aba8f70c2fc31d3733bc0fb6854945c077a61
Author: Daniel Kahn Gillmor <dkg fifthhorseman net>
Date:   Wed Oct 18 01:17:36 2017 -0400

    Autocrypt: introduce GMimeAutocryptHeader
    
    Autocrypt is "encrypted e-mail for humans" (see
    https://autocrypt.org/).  It uses an in-band key transport (a simple
    e-mail header, "Autocrypt:") for the local MUA to learn which keys
    that belong to its peers.
    
    GMimeAutocryptHeader represents a parsed Autocrypt: header.  It is
    intended to help MUAs process received e-mails as they consider
    updating their internal Autocrypt state.

 docs/reference/gmime-docs.sgml    |    1 +
 docs/reference/gmime-sections.txt |   38 +++
 gmime/Makefile.am                 |    2 +
 gmime/gmime-autocrypt.c           |  618 +++++++++++++++++++++++++++++++++++++
 gmime/gmime-autocrypt.h           |  112 +++++++
 5 files changed, 771 insertions(+), 0 deletions(-)
---
diff --git a/docs/reference/gmime-docs.sgml b/docs/reference/gmime-docs.sgml
index 10e0a8c..890d68e 100644
--- a/docs/reference/gmime-docs.sgml
+++ b/docs/reference/gmime-docs.sgml
@@ -62,6 +62,7 @@
 <!ENTITY GMimeCryptoContext SYSTEM "xml/gmime-crypto-context.xml">
 <!ENTITY GMimeGpgContext SYSTEM "xml/gmime-gpg-context.xml">
 <!ENTITY GMimePkcs7Context SYSTEM "xml/gmime-pkcs7-context.xml">
+<!ENTITY GMimeAutocrypt SYSTEM "xml/gmime-autocrypt.xml">
 
 <!ENTITY index-Class-Tree SYSTEM "tree_index.sgml">
 
diff --git a/docs/reference/gmime-sections.txt b/docs/reference/gmime-sections.txt
index 29c5ae0..4b4e410 100644
--- a/docs/reference/gmime-sections.txt
+++ b/docs/reference/gmime-sections.txt
@@ -1585,3 +1585,41 @@ GMIME_IS_PKCS7_CONTEXT_CLASS
 GMIME_PKCS7_CONTEXT_GET_CLASS
 GMimePkcs7ContextClass
 </SECTION>
+
+
+<SECTION>
+<FILE>gmime-autocrypt</FILE>
+GMimeAutocryptPreferEncrypt
+GMimeAutocryptHeader
+g_mime_autocrypt_header_new
+g_mime_autocrypt_header_new_from_string
+g_mime_autocrypt_header_get_actype
+g_mime_autocrypt_header_set_actype
+g_mime_autocrypt_header_get_address
+g_mime_autocrypt_header_set_address
+g_mime_autocrypt_header_set_address_from_string
+g_mime_autocrypt_header_get_address_as_string
+g_mime_autocrypt_header_get_prefer_encrypt
+g_mime_autocrypt_header_set_prefer_encrypt
+g_mime_autocrypt_header_get_keydata
+g_mime_autocrypt_header_set_keydata
+g_mime_autocrypt_header_get_effective_date
+g_mime_autocrypt_header_set_effective_date
+g_mime_autocrypt_header_is_complete
+g_mime_autocrypt_header_get_string
+g_mime_autocrypt_header_compare
+g_mime_autocrypt_header_clone
+
+
+<SUBSECTION Private>
+g_mime_autocrypt_header_get_type
+
+<SUBSECTION Standard>
+GMIME_AUTOCRYPT_HEADER
+GMIME_IS_AUTOCRYPT_HEADER
+GMIME_TYPE_AUTOCRYPT_HEADER
+GMIME_AUTOCRYPT_HEADER_CLASS
+GMIME_IS_AUTOCRYPT_HEADER_CLASS
+GMIME_AUTOCRYPT_HEADER_GET_CLASS
+GMimeAutocryptHeaderClass
+</SECTION>
diff --git a/gmime/Makefile.am b/gmime/Makefile.am
index d9accb1..10fa06d 100644
--- a/gmime/Makefile.am
+++ b/gmime/Makefile.am
@@ -22,6 +22,7 @@ lib_LTLIBRARIES = libgmime-3.0.la
 libgmime_3_0_la_SOURCES =              \
        gmime.c                         \
        gmime-application-pkcs7-mime.c  \
+       gmime-autocrypt.c               \
        gmime-certificate.c             \
        gmime-charset.c                 \
        gmime-common.c                  \
@@ -86,6 +87,7 @@ libgmime_3_0_la_SOURCES =             \
 gmimeinclude_HEADERS =                         \
        gmime.h                         \
        gmime-application-pkcs7-mime.h  \
+       gmime-autocrypt.h               \
        gmime-certificate.h             \
        gmime-charset.h                 \
        gmime-content-type.h            \
diff --git a/gmime/gmime-autocrypt.c b/gmime/gmime-autocrypt.c
new file mode 100644
index 0000000..8bd4321
--- /dev/null
+++ b/gmime/gmime-autocrypt.c
@@ -0,0 +1,618 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*  GMimeAutocrypt
+ *  Copyright (C) 2017 Daniel Kahn Gillmor
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "gmime-autocrypt.h"
+
+/**
+ * SECTION: gmime-autocrypt-header
+ * @title: GMimeAutocryptHeader
+ * @short_description: A header containing cryptographic information about the sending address
+ * @see_also: https://autocrypt.org
+ *
+ * A #GMimeAutocryptHeader is an object containing information derived
+ * from a message about the sender's cryptographic keys and
+ * preferences.  It can be used in conjunction with local storage and
+ * business logic to make a better user experience for encrypted
+ * e-mail.
+ **/
+
+
+static void g_mime_autocrypt_header_class_init (GMimeAutocryptHeaderClass *klass);
+static void g_mime_autocrypt_header_init (GMimeAutocryptHeader *ah, GMimeAutocryptHeaderClass *klass);
+static void g_mime_autocrypt_header_finalize (GObject *object);
+
+static GObjectClass *parent_class = NULL;
+
+
+GType
+g_mime_autocrypt_header_get_type (void)
+{
+       static GType type = 0;
+       
+       if (!type) {
+               static const GTypeInfo info = {
+                       sizeof (GMimeAutocryptHeaderClass),
+                       NULL, /* base_class_init */
+                       NULL, /* base_class_finalize */
+                       (GClassInitFunc) g_mime_autocrypt_header_class_init,
+                       NULL, /* class_finalize */
+                       NULL, /* class_data */
+                       sizeof (GMimeAutocryptHeader),
+                       0,    /* n_preallocs */
+                       (GInstanceInitFunc) g_mime_autocrypt_header_init,
+               };
+               
+               type = g_type_register_static (G_TYPE_OBJECT, "GMimeAutocryptHeader", &info, 0);
+       }
+       
+       return type;
+}
+
+static void
+g_mime_autocrypt_header_class_init (GMimeAutocryptHeaderClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       
+       parent_class = g_type_class_ref (G_TYPE_OBJECT);
+       
+       object_class->finalize = g_mime_autocrypt_header_finalize;
+}
+
+static void
+g_mime_autocrypt_header_init (GMimeAutocryptHeader *ah, GMimeAutocryptHeaderClass *klass)
+{
+       ah->actype = 1;
+       ah->address = NULL;
+       ah->prefer_encrypt = GMIME_AUTOCRYPT_PREFER_ENCRYPT_NONE;
+       ah->keydata = NULL;
+       ah->effective_date = NULL;
+}
+
+static void
+g_mime_autocrypt_header_finalize (GObject *object)
+{
+       GMimeAutocryptHeader *ah = (GMimeAutocryptHeader *) object;
+       
+       if (ah->address)
+               g_object_unref (ah->address);
+       if (ah->keydata)
+               g_byte_array_unref (ah->keydata);
+       if (ah->effective_date)
+               g_date_time_unref (ah->effective_date);
+       
+       G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+/**
+ * g_mime_autocrypt_header_new:
+ *
+ * Creates a new #GMimeAutocryptHeader object.
+ * 
+ * Returns: (transfer full): a new #GMimeAutocryptHeader object.
+ **/
+GMimeAutocryptHeader *
+g_mime_autocrypt_header_new (void)
+{
+       return g_object_new (GMIME_TYPE_AUTOCRYPT_HEADER, NULL);
+}
+
+
+/**
+ * g_mime_autocrypt_header_new_from_string:
+ *
+ * Creates a new #GMimeAutocryptHeader object based on the value of an
+ * Autocrypt: header.
+ *
+ * Note that this will not have an @effective_date set, since the
+ * @effective_date is derived from the Date: line in the same block of
+ * e-mail headers, but cannot be extracted from the raw Autocrypt:
+ * header itself.
+ * 
+ * Returns: (transfer full): a new #GMimeAutocryptHeader object, or %NULL on error.
+ **/
+GMimeAutocryptHeader *
+g_mime_autocrypt_header_new_from_string (const char *string)
+{
+       GMimeAutocryptHeader *ret = NULL;
+       gchar **ksplit = NULL;
+       gchar *kjoined = NULL;
+       GByteArray *newkeydata = NULL;
+       if (string == NULL)
+               return NULL;
+       
+       /* TODO: this doesn't deal with quoting or RFC 2047 encoding,
+          both of which might happen to mails in transit. So this
+          could be improved.  It's also probably not currently the
+          most efficient implementation. */
+
+       struct _attr { char *val; const char *name; size_t sz; int count; };
+#define attr(n, str) struct _attr n = { .name = str, .sz = sizeof(str)-1 }
+       attr(t, "type");
+       attr(k, "keydata");
+       attr(p, "prefer-encrypt");
+       attr(a, "addr");
+#undef attr
+       struct _attr *attrs[] = { &t, &k, &p, &a };
+       
+       gchar **vals = g_strsplit (string, ";", -1);
+       gchar **x;
+       for (x = vals; *x; x++) {
+               gboolean known = FALSE;
+               int i;
+               g_strstrip (*x);
+               
+               for (i = 0; i < G_N_ELEMENTS(attrs); i++) {
+                       if (g_ascii_strncasecmp (attrs[i]->name, *x, attrs[i]->sz) == 0 &&
+                           (*x)[attrs[i]->sz] == '=') {
+                               attrs[i]->val = (*x) + attrs[i]->sz+1;
+                               attrs[i]->count++;
+                               known = TRUE;
+                               break;
+                       }
+               }
+               if (!known) {
+                       /* skip a line that has a critical element we
+                          do not understnd */
+                       if ((*x)[0] != '_') 
+                               goto done;
+                       
+               }
+       }
+
+       if (k.count != 1)
+               goto done;
+       if (a.count != 1)
+               goto done;
+       if (t.count > 1)
+               goto done;
+       if (p.count > 1)
+               goto done;
+       gchar *endptr=NULL;
+       guint64 newtype = 1;
+       GMimeAutocryptPreferEncrypt newpref = GMIME_AUTOCRYPT_PREFER_ENCRYPT_NONE;
+
+       if (t.count) {
+               newtype = g_ascii_strtoull (t.val, &endptr, 10);
+               if (*endptr) /* should be NULL after the unsigned int conversion */
+                       goto done;
+               if (newtype > G_MAXINT)
+                       goto done;
+       }
+       if (p.count && (g_ascii_strcasecmp ("mutual", p.val) == 0))
+               newpref = GMIME_AUTOCRYPT_PREFER_ENCRYPT_MUTUAL;
+       
+       ret = g_object_new (GMIME_TYPE_AUTOCRYPT_HEADER, NULL);
+       g_mime_autocrypt_header_set_address_from_string (ret, a.val);
+       g_mime_autocrypt_header_set_actype (ret, newtype);
+       g_mime_autocrypt_header_set_prefer_encrypt (ret, newpref);
+       ksplit = g_strsplit_set (k.val, " \r\n\t", -1);
+       kjoined = g_strjoinv ("", ksplit);
+       gsize decodedlen = 0;
+       g_base64_decode_inplace (kjoined, &decodedlen);
+       newkeydata = g_byte_array_new_take (kjoined, decodedlen);
+       kjoined = NULL;
+       g_mime_autocrypt_header_set_keydata (ret, newkeydata);
+       
+ done:
+       if (vals)
+               g_strfreev (vals);
+       if (ksplit)
+               g_strfreev (ksplit);
+       if (newkeydata)
+               g_byte_array_unref (newkeydata);
+       g_free (kjoined);
+       return ret;
+}
+
+
+/**
+ * g_mime_autocrypt_header_set_actype:
+ * @ah: a #GMimeAutocryptHeader object
+ * @type: an integer value associated with the type
+ *
+ * Set the type associated with the Autocrypt header.
+ **/
+void
+g_mime_autocrypt_header_set_actype (GMimeAutocryptHeader *ah, gint actype)
+{
+       g_return_if_fail (GMIME_IS_AUTOCRYPT_HEADER (ah));
+
+       ah->actype = actype;
+}
+
+/**
+ * g_mime_autocrypt_header_get_actype:
+ * @ah: a #GMimeAutocryptHeader object
+ *
+ * Gets the type of the Autocrypt header.
+ *
+ * Returns: the type of the Autocrypt header
+ **/
+gint
+g_mime_autocrypt_header_get_actype (GMimeAutocryptHeader *ah)
+{
+       g_return_val_if_fail (GMIME_IS_AUTOCRYPT_HEADER (ah), 0);
+
+       return ah->actype;
+}
+
+
+/**
+ * g_mime_autocrypt_header_set_address_from_string:
+ * @ah: a #GMimeAutocryptHeader object
+ * @address: a %NULL-terminated string that is a raw e-mail address
+ *
+ * Set the address associated with the autocrypt_header.
+ **/
+void
+g_mime_autocrypt_header_set_address_from_string (GMimeAutocryptHeader *ah, const char *address)
+{
+       g_return_if_fail (GMIME_IS_AUTOCRYPT_HEADER (ah));
+
+       if (ah->address)
+               g_object_unref (ah->address);
+       ah->address = INTERNET_ADDRESS_MAILBOX(internet_address_mailbox_new (NULL, address));
+}
+
+/**
+ * g_mime_autocrypt_header_set_address:
+ * @ah: a #GMimeAutocryptHeader object
+ * @address: a #InternetAddressMailbox value
+ *
+ * Set the address associated with the autocrypt_header.
+ **/
+void
+g_mime_autocrypt_header_set_address (GMimeAutocryptHeader *ah, InternetAddressMailbox *address)
+{
+       g_return_if_fail (GMIME_IS_AUTOCRYPT_HEADER (ah));
+
+       if (ah->address)
+               g_object_unref (ah->address);
+       
+       ah->address = address;
+       g_object_ref (address);
+}
+
+/**
+ * g_mime_autocrypt_header_get_address:
+ * @ah: a #GMimeAutocryptHeader object
+ *
+ * Gets the internal address of the Autocrypt header, or %NULL if not set.
+ *
+ * Returns: (transfer none): the address associated with the Autocrypt header
+ **/
+InternetAddressMailbox*
+g_mime_autocrypt_header_get_address (GMimeAutocryptHeader *ah)
+{
+       g_return_val_if_fail (GMIME_IS_AUTOCRYPT_HEADER (ah), NULL);
+
+       return ah->address;
+}
+
+
+/**
+ * g_mime_autocrypt_header_get_address_as_string:
+ * @ah: a #GMimeAutocryptHeader object
+ *
+ * Gets the internal address of the Autocrypt header as a C string, or %NULL if not set.
+ *
+ * Returns: (transfer none): the address associated with the Autocrypt header
+ **/
+const char*
+g_mime_autocrypt_header_get_address_as_string (GMimeAutocryptHeader *ah)
+{
+       g_return_val_if_fail (GMIME_IS_AUTOCRYPT_HEADER (ah), NULL);
+
+       return ah->address->addr;
+}
+
+
+/**
+ * g_mime_autocrypt_header_set_prefer_encrypt:
+ * @ah: a #GMimeAutocryptHeader object
+ * @pref: a #GMimeAutocryptPreferEncrypt value
+ *
+ * Set the encryption preference associated with the Autocrypt header.
+ **/
+void
+g_mime_autocrypt_header_set_prefer_encrypt (GMimeAutocryptHeader *ah, GMimeAutocryptPreferEncrypt pref)
+{
+       g_return_if_fail (GMIME_IS_AUTOCRYPT_HEADER (ah));
+
+       ah->prefer_encrypt = pref;
+}
+
+/**
+ * g_mime_autocrypt_header_get_prefer_encrypt:
+ * @ah: a #GMimeAutocryptHeader object
+ *
+ * Gets the encryption preference stated by the Autocrypt header.
+ *
+ * Returns: the encryption preference associated with the Autocrypt header
+ **/
+GMimeAutocryptPreferEncrypt
+g_mime_autocrypt_header_get_prefer_encrypt (GMimeAutocryptHeader *ah)
+{
+       g_return_val_if_fail (GMIME_IS_AUTOCRYPT_HEADER (ah), GMIME_AUTOCRYPT_PREFER_ENCRYPT_NONE);
+
+       return ah->prefer_encrypt;
+}
+
+
+/**
+ * g_mime_autocrypt_header_set_keydata:
+ * @ah: a #GMimeAutocryptHeader object
+ * @keydata: a #GByteArray object
+ *
+ * Set the raw key data associated with the Autocrypt header.
+ **/
+void
+g_mime_autocrypt_header_set_keydata (GMimeAutocryptHeader *ah, GByteArray *keydata)
+{
+       g_return_if_fail (GMIME_IS_AUTOCRYPT_HEADER (ah));
+
+       if (ah->keydata)
+               g_byte_array_unref (ah->keydata);
+       
+       ah->keydata = keydata;
+       if (keydata)
+               g_byte_array_ref (keydata);
+}
+
+/**
+ * g_mime_autocrypt_header_get_keydata:
+ * @ah: a #GMimeAutocryptHeader object
+ *
+ * Gets the raw keydata of the Autocrypt header, or %NULL if not set.
+ *
+ * Returns: (transfer none): the raw key data associated with the Autocrypt header
+ **/
+GByteArray*
+g_mime_autocrypt_header_get_keydata (GMimeAutocryptHeader *ah)
+{
+       g_return_val_if_fail (GMIME_IS_AUTOCRYPT_HEADER (ah), NULL);
+
+       return ah->keydata;
+}
+
+
+/**
+ * g_mime_autocrypt_header_set_effective_date:
+ * @ah: a #GMimeAutocryptHeader object
+ * @effective_date: a #GDateTime object
+ *
+ * Set the effective date associated with the Autocrypt header.
+ **/
+void
+g_mime_autocrypt_header_set_effective_date (GMimeAutocryptHeader *ah, GDateTime *effective_date)
+{
+       g_return_if_fail (GMIME_IS_AUTOCRYPT_HEADER (ah));
+
+       if (ah->effective_date)
+               g_date_time_unref (ah->effective_date);
+       
+       ah->effective_date = effective_date;
+       g_date_time_ref (effective_date);
+}
+
+/**
+ * g_mime_autocrypt_header_get_effective_date:
+ * @ah: a #GMimeAutocryptHeader object
+ *
+ * Gets the effective date of the Autocrypt header, or %NULL if not set.
+ *
+ * Returns: (transfer none): the effective date associated with the Autocrypt header
+ **/
+GDateTime*
+g_mime_autocrypt_header_get_effective_date (GMimeAutocryptHeader *ah)
+{
+       g_return_val_if_fail (GMIME_IS_AUTOCRYPT_HEADER (ah), NULL);
+
+       return ah->effective_date;
+}
+
+/**
+ * g_mime_autocrypt_header_is_complete:
+ * @ah: a #GMimeAutocryptHeader object
+ *
+ * When dealing with Autocrypt headers derived from a message, some
+ * sender addresses will not have a legitimate/complete header
+ * associated with them.  When a given sender address has no complete
+ * header of a specific type, it should "reset" the state of the
+ * associated address.
+ *
+ * Returns: %TRUE if the header is complete, or %FALSE if it is incomplete.
+ */
+gboolean
+g_mime_autocrypt_header_is_complete (GMimeAutocryptHeader *ah)
+{
+       g_return_val_if_fail (GMIME_IS_AUTOCRYPT_HEADER (ah), FALSE);
+       return (ah->address && ah->address->addr && ah->keydata && ah->keydata->len && ah->keydata->data);
+}
+
+
+/**
+ * g_mime_autocrypt_header_get_string:
+ * @ah: a #GMimeAutocryptHeader object
+ *
+ * Gets the string representation of the Autocrypt header, or %NULL on
+ * error.  For example, it might return:
+ *
+ *     type=1; prefer-encrypt=mutual; addr=bob\@example.com keydata=AAAB15BE...
+ *
+ * Returns: (transfer full): the string representation of the
+ * Autocrypt header.
+ **/
+char *
+g_mime_autocrypt_header_get_string (GMimeAutocryptHeader *ah)
+{
+       g_return_val_if_fail (GMIME_IS_AUTOCRYPT_HEADER (ah), NULL);
+       if (!g_mime_autocrypt_header_is_complete (ah))
+               return NULL;
+       char *pe = "";
+       if (ah->prefer_encrypt == GMIME_AUTOCRYPT_PREFER_ENCRYPT_MUTUAL)
+               pe = "prefer-encrypt=mutual; ";
+       const char *addr = internet_address_mailbox_get_addr (ah->address);
+       GPtrArray *lines = g_ptr_array_new_with_free_func (g_free);
+
+       gchar * first = g_strdup_printf("addr=%s; type=%d; %skeydata=",
+                                       addr, ah->actype, pe);
+       size_t n = strlen (first);
+       const size_t maxwid = 72;
+       const size_t firstline = maxwid - sizeof ("Autocrypt:");
+       gsize offset = 0;
+       if (n < firstline) {
+               gsize firstlinekeylen = ((firstline - n)/4)*3;
+               if (firstlinekeylen > ah->keydata->len)
+                       firstlinekeylen = ah->keydata->len;
+               gchar *kdata = g_base64_encode (ah->keydata->data, firstlinekeylen);
+               gchar *newfirst = g_strconcat (first, kdata, NULL);
+               g_free (first);
+               g_free (kdata);
+               first = newfirst;
+               offset = firstlinekeylen;
+       }
+       g_ptr_array_add (lines, first);
+
+       while (offset < ah->keydata->len) {
+               gsize newsz = MIN((maxwid/4)*3, ah->keydata->len - offset);
+               g_ptr_array_add (lines, g_base64_encode (ah->keydata->data + offset, newsz));
+               offset += newsz;
+       }
+
+       g_ptr_array_add (lines, NULL);
+
+       char *ret = g_strjoinv ("\r\n ", (gchar**)(lines->pdata));
+       g_ptr_array_unref (lines);
+       return ret;
+}
+
+/**
+ * g_mime_autocrypt_header_compare:
+ * @ah1: a #GMimeAutocryptHeader object
+ * @ah2: a #GMimeAutocryptHeader object
+ *
+ * Compare two Autocrypt Headers.  This is useful for comparison, as well as for
+ * sorting headers by:
+ *
+ *  - address
+ *  - actype
+ *  - effective_date
+ *  - keydata
+ *  - prefer_encrypt
+ *
+ * Returns: -1, 0, or 1 @ah1 is less than, equal to, or greater than @ah2.
+ **/
+int
+g_mime_autocrypt_header_compare (GMimeAutocryptHeader *ah1, GMimeAutocryptHeader *ah2)
+{
+       /* note that NULL values sort before non-NULL values */
+       int ret;
+       if ((!ah1->address || !ah1->address->addr) && (ah2->address && ah2->address->addr))
+               return -1;
+       if ((ah1->address && ah1->address->addr) && (!ah2->address || !ah2->address->addr))
+               return 1;
+       if (ah1->address && ah1->address->addr && ah2->address && ah2->address->addr) {
+               ret = strcmp (ah1->address->addr, ah2->address->addr);
+               if (ret)
+                       return ret;
+       }
+       
+       if (ah1->actype < ah2->actype)
+               return -1;
+       if (ah1->actype > ah2->actype)
+               return 1;
+       
+       if (!ah1->effective_date && ah2->effective_date)
+               return -1;
+       if (ah1->effective_date && !ah2->effective_date)
+               return 1;
+       if (ah1->effective_date && ah2->effective_date) {
+               ret = g_date_time_compare (ah1->effective_date, ah2->effective_date);
+               if (ret)
+                       return ret;
+       }
+
+       if (!ah1->keydata && ah2->keydata)
+               return -1;
+       if (ah1->keydata && !ah2->keydata)
+               return 1;
+       if (ah1->keydata && ah2->keydata) {
+               if (ah1->keydata->len < ah2->keydata->len)
+                       return -1;
+               if (ah1->keydata->len > ah2->keydata->len)
+                       return 1;
+               ret = memcmp (ah1->keydata->data, ah2->keydata->data, ah1->keydata->len);
+               if (ret)
+                       return ret;
+       }
+
+       if (ah1->prefer_encrypt < ah2->prefer_encrypt)
+               return -1;
+       if (ah1->prefer_encrypt > ah2->prefer_encrypt)
+               return 1;
+       return 0;
+}
+
+/**
+ * g_mime_autocrypt_header_clone:
+ * @dst: a #GMimeAutocryptHeader object
+ * @src: a #GMimeAutocryptHeader object
+ *
+ * If address and type already match between @src and @dst, copy
+ * keydata, prefer_encrypt, effective_date from @src to @dst.
+ *
+ **/
+void
+g_mime_autocrypt_header_clone (GMimeAutocryptHeader *dst, GMimeAutocryptHeader *src)
+{
+       if (dst->actype != src->actype)
+               return;
+       if (!dst->address || !src->address)
+               return;
+       if (g_strcmp0 (internet_address_mailbox_get_idn_addr (dst->address), 
internet_address_mailbox_get_idn_addr (src->address)))
+               return;
+
+       if (dst->keydata)
+               g_byte_array_unref (dst->keydata);
+       if (src->keydata) {
+               g_byte_array_ref (src->keydata);
+               dst->keydata = src->keydata;
+       } else
+               dst->keydata = NULL;
+
+       dst->prefer_encrypt = src->prefer_encrypt;
+
+       if (dst->effective_date)
+               g_date_time_unref (dst->effective_date);
+       if (src->effective_date) {
+               g_date_time_ref (src->effective_date);
+               dst->effective_date = src->effective_date;
+       } else
+               dst->effective_date = NULL;
+}
diff --git a/gmime/gmime-autocrypt.h b/gmime/gmime-autocrypt.h
new file mode 100644
index 0000000..859733b
--- /dev/null
+++ b/gmime/gmime-autocrypt.h
@@ -0,0 +1,112 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*  GMime Autocrypt
+ *  Copyright (C) 2017 Daniel Kahn Gillmor
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+
+#ifndef __GMIME_AUTOCRYPT_H__
+#define __GMIME_AUTOCRYPT_H__
+
+#include <glib.h>
+#include <glib/gprintf.h>
+#include <glib-object.h>
+#include <gmime/internet-address.h>
+
+G_BEGIN_DECLS
+
+#define GMIME_TYPE_AUTOCRYPT_HEADER                  (g_mime_autocrypt_header_get_type ())
+#define GMIME_AUTOCRYPT_HEADER(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GMIME_TYPE_AUTOCRYPT_HEADER, GMimeAutocryptHeader))
+#define GMIME_AUTOCRYPT_HEADER_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), 
GMIME_TYPE_AUTOCRYPT_HEADER, GMimeAutocryptHeaderClass))
+#define GMIME_IS_AUTOCRYPT_HEADER(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
GMIME_TYPE_AUTOCRYPT_HEADER))
+#define GMIME_IS_AUTOCRYPT_HEADER_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), 
GMIME_TYPE_AUTOCRYPT_HEADER))
+#define GMIME_AUTOCRYPT_HEADER_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), 
GMIME_TYPE_AUTOCRYPT_HEADER, GMimeAutocryptHeaderClass))
+
+typedef struct _GMimeAutocryptHeader GMimeAutocryptHeader;
+typedef struct _GMimeAutocryptHeaderClass GMimeAutocryptHeaderClass;
+
+/**
+ * GMimeAutocryptPreferEncrypt:
+ * @GMIME_AUTOCRYPT_PREFER_ENCRYPT_NONE: No preference stated.
+ * @GMIME_AUTOCRYPT_PREFER_ENCRYPT_MUTUAL: Please encrypt, if you also have this preference
+ *
+ * A description of the user's preference for encrypted messaging.
+ **/
+typedef enum {
+       GMIME_AUTOCRYPT_PREFER_ENCRYPT_NONE     = 0,
+       GMIME_AUTOCRYPT_PREFER_ENCRYPT_MUTUAL   = 1
+} GMimeAutocryptPreferEncrypt;
+
+/**
+ * GMimeAutocryptHeader:
+ * @parent_object: parent #GObject
+ * @address: the #InternetAddressMailbox associated with this Autocrypt header.
+ * @actype: the Autocrypt type parameter (defaults to 1).
+ * @prefer_encrypt: a #GMimeAutocryptPreferEncrypt value (defaults to @GMIME_AUTOCRYPT_PREFER_ENCRYPT_NONE).
+ * @keydata: the raw binary form of the encoded key.
+ * @effective_date: the date associated with the Autocrypt header in this message.
+ *
+ * An object containing Autocrypt information about a given e-mail
+ * address, as derived from a message header.
+ *
+ * See https://autocrypt.org/ for details and motivation.
+ **/
+struct _GMimeAutocryptHeader {
+       GObject parent_object;
+
+       gint actype;
+       InternetAddressMailbox *address;
+       GMimeAutocryptPreferEncrypt prefer_encrypt;
+       GByteArray *keydata;
+       GDateTime *effective_date;
+};
+
+struct _GMimeAutocryptHeaderClass {
+       GObjectClass parent_class;
+};
+
+GType g_mime_autocrypt_header_get_type (void);
+
+GMimeAutocryptHeader *g_mime_autocrypt_header_new (void);
+GMimeAutocryptHeader *g_mime_autocrypt_header_new_from_string (const char* header);
+
+void g_mime_autocrypt_header_set_actype (GMimeAutocryptHeader *ah, gint actype);
+gint g_mime_autocrypt_header_get_actype (GMimeAutocryptHeader *ah);
+
+void g_mime_autocrypt_header_set_address (GMimeAutocryptHeader *ah, InternetAddressMailbox *address);
+InternetAddressMailbox *g_mime_autocrypt_header_get_address (GMimeAutocryptHeader *ah);
+void g_mime_autocrypt_header_set_address_from_string (GMimeAutocryptHeader *ah, const char *address);
+const char *g_mime_autocrypt_header_get_address_as_string (GMimeAutocryptHeader *ah);
+
+void g_mime_autocrypt_header_set_prefer_encrypt (GMimeAutocryptHeader *ah, GMimeAutocryptPreferEncrypt pref);
+GMimeAutocryptPreferEncrypt g_mime_autocrypt_header_get_prefer_encrypt (GMimeAutocryptHeader *ah);
+
+void g_mime_autocrypt_header_set_keydata (GMimeAutocryptHeader *ah, GByteArray *data);
+GByteArray *g_mime_autocrypt_header_get_keydata (GMimeAutocryptHeader *ah);
+
+void g_mime_autocrypt_header_set_effective_date (GMimeAutocryptHeader *ah, GDateTime *effective_date);
+GDateTime *g_mime_autocrypt_header_get_effective_date (GMimeAutocryptHeader *ah);
+
+char *g_mime_autocrypt_header_get_string (GMimeAutocryptHeader *ah);
+gboolean g_mime_autocrypt_header_is_complete (GMimeAutocryptHeader *ah);
+
+int g_mime_autocrypt_header_compare (GMimeAutocryptHeader *ah1, GMimeAutocryptHeader *ah2);
+void g_mime_autocrypt_header_clone (GMimeAutocryptHeader *dst, GMimeAutocryptHeader *src);
+
+G_END_DECLS
+
+#endif /* __GMIME_AUTOCRYPT_H__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]