about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorJames Booth <boothj5@gmail.com>2015-03-23 23:38:06 +0000
committerJames Booth <boothj5@gmail.com>2015-03-23 23:38:06 +0000
commit475dfebd97b8adace3ee56683b968da752a3ae02 (patch)
treedac7c25cdb51c8b562ad9543b422709cbf7a658f /src
parent8a5d1fef2930036d34bf02d0b15d0b6239725ffd (diff)
downloadprofani-tty-475dfebd97b8adace3ee56683b968da752a3ae02.tar.gz
Added pgpkeyid account setting, send signed presence
Diffstat (limited to 'src')
-rw-r--r--src/command/command.c2
-rw-r--r--src/command/commands.c8
-rw-r--r--src/config/account.c9
-rw-r--r--src/config/account.h3
-rw-r--r--src/config/accounts.c26
-rw-r--r--src/config/accounts.h2
-rw-r--r--src/pgp/gpg.c93
-rw-r--r--src/pgp/gpg.h1
-rw-r--r--src/ui/console.c4
-rw-r--r--src/xmpp/presence.c22
-rw-r--r--src/xmpp/stanza.h1
11 files changed, 166 insertions, 5 deletions
diff --git a/src/command/command.c b/src/command/command.c
index 820ca058..8e709601 100644
--- a/src/command/command.c
+++ b/src/command/command.c
@@ -1369,6 +1369,7 @@ cmd_init(void)
     autocomplete_add(account_set_ac, "muc");
     autocomplete_add(account_set_ac, "nick");
     autocomplete_add(account_set_ac, "otr");
+    autocomplete_add(account_set_ac, "pgpkeyid");
 
     account_clear_ac = autocomplete_new();
     autocomplete_add(account_clear_ac, "password");
@@ -1376,6 +1377,7 @@ cmd_init(void)
     autocomplete_add(account_clear_ac, "server");
     autocomplete_add(account_clear_ac, "port");
     autocomplete_add(account_clear_ac, "otr");
+    autocomplete_add(account_clear_ac, "pgpkeyid");
 
     account_default_ac = autocomplete_new();
     autocomplete_add(account_default_ac, "set");
diff --git a/src/command/commands.c b/src/command/commands.c
index bb8c0381..0dc19e41 100644
--- a/src/command/commands.c
+++ b/src/command/commands.c
@@ -516,6 +516,10 @@ cmd_account(gchar **args, struct cmd_help_t help)
                         cons_show("Updated login status for account %s: %s", account_name, value);
                     }
                     cons_show("");
+                } else if (strcmp(property, "pgpkeyid") == 0) {
+                    accounts_set_pgp_keyid(account_name, value);
+                    cons_show("Updated PGP key ID for account %s: %s", account_name, value);
+                    cons_show("");
                 } else if (valid_resource_presence_string(property)) {
                     int intval;
                     char *err_msg = NULL;
@@ -594,6 +598,10 @@ cmd_account(gchar **args, struct cmd_help_t help)
                     accounts_clear_otr(account_name);
                     cons_show("OTR policy removed for account %s", account_name);
                     cons_show("");
+                } else if (strcmp(property, "pgpkeyid") == 0) {
+                    accounts_clear_pgp_keyid(account_name);
+                    cons_show("Removed PGP key ID for account %s", account_name);
+                    cons_show("");
                 } else {
                     cons_show("Invalid property: %s", property);
                     cons_show("");
diff --git a/src/config/account.c b/src/config/account.c
index 3896286b..82294dac 100644
--- a/src/config/account.c
+++ b/src/config/account.c
@@ -49,7 +49,7 @@ account_new(const gchar * const name, const gchar * const jid,
     int priority_away, int priority_xa, int priority_dnd,
     const gchar * const muc_service, const gchar * const muc_nick,
     const gchar * const otr_policy, GList *otr_manual, GList *otr_opportunistic,
-    GList *otr_always)
+    GList *otr_always, const gchar * const pgp_keyid)
 {
     ProfAccount *new_account = malloc(sizeof(ProfAccount));
 
@@ -142,6 +142,12 @@ account_new(const gchar * const name, const gchar * const jid,
     new_account->otr_opportunistic = otr_opportunistic;
     new_account->otr_always = otr_always;
 
+    if (pgp_keyid != NULL) {
+        new_account->pgp_keyid = strdup(pgp_keyid);
+    } else {
+        new_account->pgp_keyid = NULL;
+    }
+
     return new_account;
 }
 
@@ -170,6 +176,7 @@ account_free(ProfAccount *account)
         free(account->muc_service);
         free(account->muc_nick);
         free(account->otr_policy);
+        free(account->pgp_keyid);
         g_list_free_full(account->otr_manual, g_free);
         g_list_free_full(account->otr_opportunistic, g_free);
         g_list_free_full(account->otr_always, g_free);
diff --git a/src/config/account.h b/src/config/account.h
index c237a19e..a49aebd0 100644
--- a/src/config/account.h
+++ b/src/config/account.h
@@ -59,6 +59,7 @@ typedef struct prof_account_t {
     GList *otr_manual;
     GList *otr_opportunistic;
     GList *otr_always;
+    gchar *pgp_keyid;
 } ProfAccount;
 
 ProfAccount* account_new(const gchar * const name, const gchar * const jid,
@@ -68,7 +69,7 @@ ProfAccount* account_new(const gchar * const name, const gchar * const jid,
     int priority_away, int priority_xa, int priority_dnd,
     const gchar * const muc_service, const gchar * const muc_nick,
     const gchar * const otr_policy, GList *otr_manual, GList *otr_opportunistic,
-    GList *otr_always);
+    GList *otr_always, const gchar * const pgp_keyid);
 
 char* account_create_full_jid(ProfAccount *account);
 
diff --git a/src/config/accounts.c b/src/config/accounts.c
index 6c04549c..b18974ca 100644
--- a/src/config/accounts.c
+++ b/src/config/accounts.c
@@ -280,11 +280,16 @@ accounts_get_account(const char * const name)
             g_strfreev(always);
         }
 
+        gchar *pgp_keyid = NULL;
+        if (g_key_file_has_key(accounts, name, "pgp.keyid", NULL)) {
+            pgp_keyid = g_key_file_get_string(accounts, name, "pgp.keyid", NULL);
+        }
+
         ProfAccount *new_account = account_new(name, jid, password, eval_password, enabled,
             server, port, resource, last_presence, login_presence,
             priority_online, priority_chat, priority_away, priority_xa,
             priority_dnd, muc_service, muc_nick, otr_policy, otr_manual,
-            otr_opportunistic, otr_always);
+            otr_opportunistic, otr_always, pgp_keyid);
 
         g_free(jid);
         g_free(password);
@@ -296,6 +301,7 @@ accounts_get_account(const char * const name)
         g_free(muc_service);
         g_free(muc_nick);
         g_free(otr_policy);
+        g_free(pgp_keyid);
 
         return new_account;
     }
@@ -454,6 +460,15 @@ accounts_set_eval_password(const char * const account_name, const char * const v
 }
 
 void
+accounts_set_pgp_keyid(const char * const account_name, const char * const value)
+{
+    if (accounts_account_exists(account_name)) {
+        g_key_file_set_string(accounts, account_name, "pgp.keyid", value);
+        _save_accounts();
+    }
+}
+
+void
 accounts_clear_password(const char * const account_name)
 {
     if (accounts_account_exists(account_name)) {
@@ -490,6 +505,15 @@ accounts_clear_port(const char * const account_name)
 }
 
 void
+accounts_clear_pgp_keyid(const char * const account_name)
+{
+    if (accounts_account_exists(account_name)) {
+        g_key_file_remove_key(accounts, account_name, "pgp.keyid", NULL);
+        _save_accounts();
+    }
+}
+
+void
 accounts_clear_otr(const char * const account_name)
 {
     if (accounts_account_exists(account_name)) {
diff --git a/src/config/accounts.h b/src/config/accounts.h
index 50307b5b..eb981cb8 100644
--- a/src/config/accounts.h
+++ b/src/config/accounts.h
@@ -77,11 +77,13 @@ void accounts_set_priority_dnd(const char * const account_name, const gint value
 void accounts_set_priority_all(const char * const account_name, const gint value);
 gint accounts_get_priority_for_presence_type(const char * const account_name,
     resource_presence_t presence_type);
+void accounts_set_pgp_keyid(const char * const account_name, const char * const value);
 void accounts_clear_password(const char * const account_name);
 void accounts_clear_eval_password(const char * const account_name);
 void accounts_clear_server(const char * const account_name);
 void accounts_clear_port(const char * const account_name);
 void accounts_clear_otr(const char * const account_name);
+void accounts_clear_pgp_keyid(const char * const account_name);
 void accounts_add_otr_policy(const char * const account_name, const char * const contact_jid, const char * const policy);
 
 #endif
diff --git a/src/pgp/gpg.c b/src/pgp/gpg.c
index 67ea8794..0d0cae5a 100644
--- a/src/pgp/gpg.c
+++ b/src/pgp/gpg.c
@@ -42,8 +42,12 @@
 #include "pgp/gpg.h"
 #include "log.h"
 
+#define PGP_FOOTER "-----END PGP SIGNATURE-----"
+
 static const char *libversion;
 
+static char* _remove_header_footer(char *str);
+
 void
 p_gpg_init(void)
 {
@@ -62,7 +66,7 @@ p_gpg_list_keys(void)
 
     error = gpgme_new(&ctx);
     if (error) {
-        log_error("GPG: Could not list keys: %s %s", gpgme_strsource(error), gpgme_strerror(error));
+        log_error("GPG: Could not list keys. %s %s", gpgme_strsource(error), gpgme_strerror(error));
         return NULL;
     }
 
@@ -84,7 +88,7 @@ p_gpg_list_keys(void)
             gpgme_key_release(key);
         }
     } else {
-        log_error("GPG: Could not list keys: %s %s", gpgme_strsource(error), gpgme_strerror(error));
+        log_error("GPG: Could not list keys. %s %s", gpgme_strsource(error), gpgme_strerror(error));
     }
 
     gpgme_release(ctx);
@@ -107,4 +111,89 @@ p_gpg_free_key(ProfPGPKey *key)
         free(key->fp);
         free(key);
     }
+}
+
+char*
+p_gpg_sign_str(const char * const str, const char * const fp)
+{
+	gpgme_ctx_t ctx;
+	gpgme_error_t error = gpgme_new(&ctx);
+	if (error) {
+        log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error));
+		return NULL;
+	}
+
+	gpgme_key_t key = NULL;
+	error = gpgme_get_key(ctx, fp, &key, 1);
+	if (error || key == NULL) {
+        log_error("GPG: Failed to get key. %s %s", gpgme_strsource(error), gpgme_strerror(error));
+		gpgme_release (ctx);
+		return NULL;
+	}
+
+	gpgme_signers_clear(ctx);
+	error = gpgme_signers_add(ctx, key);
+	if (error) {
+        log_error("GPG: Failed to load signer. %s %s", gpgme_strsource(error), gpgme_strerror(error));
+		gpgme_release(ctx);
+		return NULL;
+	}
+
+	gpgme_data_t str_data;
+	gpgme_data_t signed_data;
+    char *str_or_empty = NULL;
+    if (str) {
+        str_or_empty = strdup(str);
+    } else {
+        str_or_empty = strdup("");
+    }
+	gpgme_data_new_from_mem(&str_data, str_or_empty, strlen(str_or_empty), 1);
+	gpgme_data_new(&signed_data);
+
+	gpgme_set_armor(ctx,1);
+	error = gpgme_op_sign(ctx,str_data,signed_data,GPGME_SIG_MODE_DETACH);
+	if (error) {
+        log_error("GPG: Failed to sign string. %s %s", gpgme_strsource(error), gpgme_strerror(error));
+		gpgme_release(ctx);
+		return NULL;
+	}
+
+    char *result = NULL;
+	gpgme_data_release(str_data);
+
+    size_t len = 0;
+	char *signed_str = gpgme_data_release_and_get_mem(signed_data, &len);
+	if (signed_str != NULL) {
+		signed_str[len] = 0;
+		result = _remove_header_footer(signed_str);
+	}
+	gpgme_free(signed_str);
+	gpgme_release(ctx);
+    free(str_or_empty);
+
+	return result;
+}
+
+static char*
+_remove_header_footer(char *str)
+{
+	char *pointer = str;
+
+	int newlines = 0;
+	while (newlines < 3) {
+		if (pointer[0] == '\n') {
+			newlines++;
+        }
+		pointer++;
+
+		if (strlen(pointer) == 0) {
+			return NULL;
+        }
+	}
+
+	char *stripped = malloc(strlen(pointer)+1-strlen(PGP_FOOTER));
+	strncpy(stripped,pointer,strlen(pointer)-strlen(PGP_FOOTER));
+	stripped[strlen(pointer)-strlen(PGP_FOOTER)] = '\0';
+
+	return stripped;
 }
\ No newline at end of file
diff --git a/src/pgp/gpg.h b/src/pgp/gpg.h
index f5271596..f017f14b 100644
--- a/src/pgp/gpg.h
+++ b/src/pgp/gpg.h
@@ -45,5 +45,6 @@ void p_gpg_init(void);
 GSList* p_gpg_list_keys(void);
 const char* p_gpg_libver(void);
 void p_gpg_free_key(ProfPGPKey *key);
+char* p_gpg_sign_str(const char * const str, const char * const fp);
 
 #endif
diff --git a/src/ui/console.c b/src/ui/console.c
index 328f59aa..055b4aa6 100644
--- a/src/ui/console.c
+++ b/src/ui/console.c
@@ -710,6 +710,10 @@ cons_show_account(ProfAccount *account)
         g_string_free(always, TRUE);
     }
 
+    if (account->pgp_keyid) {
+        cons_show   ("PGP Key ID        : %s", account->pgp_keyid);
+    }
+
     cons_show       ("Priority          : chat:%d, online:%d, away:%d, xa:%d, dnd:%d",
         account->priority_chat, account->priority_online, account->priority_away,
         account->priority_xa, account->priority_dnd);
diff --git a/src/xmpp/presence.c b/src/xmpp/presence.c
index f4c45318..fcb6b937 100644
--- a/src/xmpp/presence.c
+++ b/src/xmpp/presence.c
@@ -49,6 +49,7 @@
 #include "xmpp/connection.h"
 #include "xmpp/stanza.h"
 #include "xmpp/xmpp.h"
+#include "pgp/gpg.h"
 
 static Autocomplete sub_requests_ac;
 
@@ -222,7 +223,28 @@ presence_update(const resource_presence_t presence_type, const char * const msg,
     char *id = create_unique_id("presence");
     xmpp_stanza_set_id(presence, id);
     stanza_attach_show(ctx, presence, show);
+
     stanza_attach_status(ctx, presence, msg);
+
+    char *account_name = jabber_get_account_name();
+    ProfAccount *account = accounts_get_account(account_name);
+    if (account->pgp_keyid) {
+        xmpp_stanza_t *x = xmpp_stanza_new(ctx);
+        xmpp_stanza_set_name(x, STANZA_NAME_X);
+        xmpp_stanza_set_ns(x, STANZA_NS_SIGNED);
+        xmpp_stanza_t *signed_text = xmpp_stanza_new(ctx);
+
+        char *signed_status = p_gpg_sign_str(msg, account->pgp_keyid);
+
+        xmpp_stanza_set_text(signed_text, signed_status);
+        xmpp_stanza_add_child(x, signed_text);
+        xmpp_stanza_release(signed_text);
+        xmpp_stanza_add_child(presence, x);
+        xmpp_stanza_release(x);
+
+        free(signed_status);
+    }
+
     stanza_attach_priority(ctx, presence, pri);
     stanza_attach_last_activity(ctx, presence, idle);
     stanza_attach_caps(ctx, presence);
diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h
index 50f3dbd0..1460642d 100644
--- a/src/xmpp/stanza.h
+++ b/src/xmpp/stanza.h
@@ -159,6 +159,7 @@
 #define STANZA_NS_CARBONS "urn:xmpp:carbons:2"
 #define STANZA_NS_FORWARD "urn:xmpp:forward:0"
 #define STANZA_NS_RECEIPTS "urn:xmpp:receipts"
+#define STANZA_NS_SIGNED "jabber:x:signed"
 
 #define STANZA_DATAFORM_SOFTWARE "urn:xmpp:dataforms:softwareinfo"