changeset 1043:ebbde723614b

Store contacts PGP keys Contacts PGP keys are retrieved from presence/message signatures; they're displayed with /info.
author Mikael Berthe <mikael@lilotux.net>
date Sun, 26 Nov 2006 17:08:21 +0100
parents 8a395c2cafc4
children 52cfe9bf9840
files mcabber/src/commands.c mcabber/src/jabglue.c mcabber/src/roster.c mcabber/src/roster.h
diffstat 4 files changed, 113 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/mcabber/src/commands.c	Sun Nov 26 10:42:25 2006 +0100
+++ b/mcabber/src/commands.c	Sun Nov 26 17:08:21 2006 +0100
@@ -1302,11 +1302,13 @@
       enum imstatus rstatus;
       const char *rst_msg;
       time_t rst_time;
+      struct pgp_data *rpgp;
 
       rprio   = buddy_getresourceprio(bud, resources->data);
       rstatus = buddy_getstatus(bud, resources->data);
       rst_msg = buddy_getstatusmsg(bud, resources->data);
       rst_time = buddy_getstatustime(bud, resources->data);
+      rpgp = buddy_resource_pgp(bud, resources->data);
 
       snprintf(buffer, 4095, "Resource: [%c] (%d) %s", imstatus2char[rstatus],
                rprio, (char*)resources->data);
@@ -1322,6 +1324,19 @@
         snprintf(buffer, 127, "Status timestamp: %s", tbuf);
         scr_WriteIncomingMessage(jid, buffer, 0, HBB_PREFIX_NONE);
       }
+#ifdef HAVE_GPGME
+      if (rpgp && rpgp->sign_keyid) {
+        snprintf(buffer, 4095, "PGP key id: %s", rpgp->sign_keyid);
+        scr_WriteIncomingMessage(jid, buffer, 0, HBB_PREFIX_NONE);
+        if (rpgp->last_sigsum) {
+          gpgme_sigsum_t ss = rpgp->last_sigsum;
+          snprintf(buffer, 4095, "Last PGP signature: %s",
+                  (ss & GPGME_SIGSUM_GREEN ? "good":
+                   (ss & GPGME_SIGSUM_RED ? "bad" : "unknown")));
+          scr_WriteIncomingMessage(jid, buffer, 0, HBB_PREFIX_NONE);
+        }
+      }
+#endif
     }
   } else {
     if (name) scr_LogPrint(LPRINT_NORMAL, "Name: %s", name);
--- a/mcabber/src/jabglue.c	Sun Nov 26 10:42:25 2006 +0100
+++ b/mcabber/src/jabglue.c	Sun Nov 26 17:08:21 2006 +0100
@@ -1402,12 +1402,61 @@
                  "Warning: you're not connected to the server.");
 }
 
+//  check_signature(barejid, resourcename, xmldata, text)
+// Verify the signature (in xmldata) of "text" for the contact
+// barejid/resourcename.
+// xmldata is the 'jabber:x:signed' stanza.
+// If the key id is found, the contact's PGP data are updated.
+static void check_signature(const char *barejid, const char *rname,
+                            xmlnode xmldata, const char *text)
+{
+#ifdef HAVE_GPGME
+  char *p, *key;
+  GSList *sl_buddy;
+  struct pgp_data *res_pgpdata;
+  gpgme_sigsum_t sigsum;
+
+  // All parameters must be valid
+  if (!(xmldata && barejid && rname && text && *text))
+    return;
+
+  if (!gpg_enabled())
+    return;
+
+  // Get the resource PGP data structure
+  sl_buddy = roster_find(barejid, jidsearch, ROSTER_TYPE_USER);
+  if (!sl_buddy)
+    return;
+  res_pgpdata = buddy_resource_pgp(sl_buddy->data, rname);
+  if (!res_pgpdata)
+    return;
+
+  p = xmlnode_get_name(xmldata);
+  if (!p || strcmp(p, "x"))
+    return; // We expect "<x xmlns='jabber:x:signed'>"
+
+  // Get signature
+  p = xmlnode_get_data(xmldata);
+  if (!p)
+    return;
+
+  key = gpg_verify(p, text, &sigsum);
+  if (key) {
+    g_free(res_pgpdata->sign_keyid);
+    res_pgpdata->sign_keyid = key;
+    res_pgpdata->last_sigsum = sigsum;
+  }
+#endif
+}
+
 static void gotmessage(char *type, const char *from, const char *body,
-                       const char *enc, time_t timestamp)
+                       const char *enc, time_t timestamp,
+                       xmlnode xmldata_signed)
 {
   char *jid;
   const char *rname, *s;
   char *decrypted = NULL;
+  /* bool sigchecked = FALSE; */
 
   jid = jidtodisp(from);
 
@@ -1417,9 +1466,19 @@
 #ifdef HAVE_GPGME
   if (enc && gpg_enabled()) {
     decrypted = gpg_decrypt(enc);
-    if (decrypted)
+    if (decrypted) {
       body = decrypted;
+      /*
+      if (xmldata_signed) {
+        check_signature(jid, rname, xmldata_signed, decrypted);
+        sigchecked = TRUE;
+      }
+      */
+    }
   }
+  // Check signature of an unencrypted message
+  if (xmldata_signed /* && !sigchecked */ && gpg_enabled())
+    check_signature(jid, rname, xmldata_signed, decrypted);
 #endif
 
   // Check for unexpected groupchat messages
@@ -1962,10 +2021,13 @@
     // Not a MUC message, so this is a regular buddy...
     // Call hk_statuschange() if status has changed or if the
     // status message is different
-    const char *m = roster_getstatusmsg(r, rname);
+    const char *m;
+    m = roster_getstatusmsg(r, rname);
     if ((ust != roster_getstatus(r, rname)) ||
         (!ustmsg && m && m[0]) || (ustmsg && (!m || strcmp(ustmsg, m))))
       hk_statuschange(r, rname, bpprio, timestamp, ust, ustmsg);
+    // Presence signature processing
+    check_signature(r, rname, xml_get_xmlns(xmldata, NS_SIGNED), ustmsg);
   }
 
   g_free(r);
@@ -2044,7 +2106,8 @@
 #endif
   }
   if (from && body)
-    gotmessage(type, from, body, enc, timestamp);
+    gotmessage(type, from, body, enc, timestamp,
+               xml_get_xmlns(xmldata, NS_SIGNED));
   g_free(tmp);
 }
 
--- a/mcabber/src/roster.c	Sun Nov 26 10:42:25 2006 +0100
+++ b/mcabber/src/roster.c	Sun Nov 26 17:08:21 2006 +0100
@@ -58,6 +58,9 @@
 #ifdef JEP0085
   struct jep0085 jep85;
 #endif
+#ifdef HAVE_GPGME
+  struct pgp_data pgpdata;
+#endif
 } res;
 
 /* This is a private structure type for the roster */
@@ -125,6 +128,9 @@
     g_free(p_res->jep22.last_msgid_sent);
     g_free(p_res->jep22.last_msgid_rcvd);
 #endif
+#ifdef HAVE_GPGME
+    g_free(p_res->pgpdata.sign_keyid);
+#endif
   }
   // Free all nodes but the first (which is static)
   g_slist_free(*reslist);
@@ -223,6 +229,9 @@
   g_free(p_res->jep22.last_msgid_sent);
   g_free(p_res->jep22.last_msgid_rcvd);
 #endif
+#ifdef HAVE_GPGME
+  g_free(p_res->pgpdata.sign_keyid);
+#endif
   rost->resource = g_slist_delete_link(rost->resource, p_res_elt);
   return;
 }
@@ -1117,6 +1126,18 @@
   return NULL;
 }
 
+struct pgp_data *buddy_resource_pgp(gpointer rosterdata, const char *resname)
+{
+#ifdef HAVE_GPGME
+  roster *roster_usr = rosterdata;
+  res *p_res = get_resource(roster_usr, resname);
+  if (p_res)
+    return &p_res->pgpdata;
+#endif
+  return NULL;
+}
+
+
 enum imrole buddy_getrole(gpointer rosterdata, const char *resname)
 {
   roster *roster_usr = rosterdata;
--- a/mcabber/src/roster.h	Sun Nov 26 10:42:25 2006 +0100
+++ b/mcabber/src/roster.h	Sun Nov 26 17:08:21 2006 +0100
@@ -4,6 +4,8 @@
 #include <glib.h>
 #include <time.h>
 
+#include "pgp.h"
+
 #define SPECIAL_BUFFER_STATUS_ID  "[status]"
 
 enum imstatus {
@@ -97,6 +99,13 @@
   CHATSTATES_SUPPORT_OK
 };
 
+struct pgp_data {
+  gchar *sign_keyid;
+#ifdef HAVE_GPGME
+  gpgme_sigsum_t last_sigsum;
+#endif
+};
+
 /* Message event and chat state flags */
 #define ROSTER_EVENT_NONE      0U
 /* JEP-22 Message Events */
@@ -177,6 +186,7 @@
 guint   buddy_resource_getevents(gpointer rosterdata, const char *resname);
 struct jep0022 *buddy_resource_jep22(gpointer rosterdata, const char *resname);
 struct jep0085 *buddy_resource_jep85(gpointer rosterdata, const char *resname);
+struct pgp_data *buddy_resource_pgp(gpointer rosterdata, const char *resname);
 enum imrole buddy_getrole(gpointer rosterdata, const char *resname);
 enum imaffiliation buddy_getaffil(gpointer rosterdata, const char *resname);
 const char *buddy_getrjid(gpointer rosterdata, const char *resname);