about summary refs log tree commit diff stats
path: root/src/command
diff options
context:
space:
mode:
authorDebXWoody <stefan@debxwoody.de>2020-06-21 09:43:42 +0200
committerMichael Vetter <jubalh@iodoru.org>2020-06-29 19:05:41 +0200
commit2c94ee5a88f64332a3f41f41a4d314fc52200e31 (patch)
tree6209fd4796609a7706f950b18a9bb652c6c137fb /src/command
parent3afd854dc862696c4842b2ed93efcad44d617910 (diff)
downloadprofani-tty-2c94ee5a88f64332a3f41f41a4d314fc52200e31.tar.gz
Feature request - XEP-0373: OpenPGP for XMPP (OX)
Basic implementation of XEP-0373: OpenPGP for XMPP.
https://xmpp.org/extensions/xep-0373.html

Command /ox

Issue: #1331
Diffstat (limited to 'src/command')
-rw-r--r--src/command/cmd_ac.c97
-rw-r--r--src/command/cmd_defs.c42
-rw-r--r--src/command/cmd_funcs.c163
-rw-r--r--src/command/cmd_funcs.h3
4 files changed, 305 insertions, 0 deletions
diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c
index 09de573c..eefca0cc 100644
--- a/src/command/cmd_ac.c
+++ b/src/command/cmd_ac.c
@@ -78,6 +78,7 @@ static char* _otr_autocomplete(ProfWin *window, const char *const input, gboolea
 #endif
 #ifdef HAVE_LIBGPGME
 static char* _pgp_autocomplete(ProfWin *window, const char *const input, gboolean previous);
+static char* _ox_autocomplete(ProfWin *window, const char *const input, gboolean previous);
 #endif
 #ifdef HAVE_OMEMO
 static char* _omemo_autocomplete(ProfWin *window, const char *const input, gboolean previous);
@@ -224,6 +225,9 @@ static Autocomplete receipts_ac;
 static Autocomplete pgp_ac;
 static Autocomplete pgp_log_ac;
 static Autocomplete pgp_sendfile_ac;
+static Autocomplete ox_ac;
+static Autocomplete ox_log_ac;
+static Autocomplete ox_sendfile_ac;
 #endif
 static Autocomplete tls_ac;
 static Autocomplete titlebar_ac;
@@ -261,6 +265,13 @@ static Autocomplete correction_ac;
 static Autocomplete avatar_ac;
 static Autocomplete executable_ac;
 
+/*!
+ * \brief Initialization of auto completion for commands.
+ *
+ * This function implements the auto completion for profanity's commands.
+ *
+ */
+
 void
 cmd_ac_init(void)
 {
@@ -842,6 +853,29 @@ cmd_ac_init(void)
     pgp_sendfile_ac = autocomplete_new();
     autocomplete_add(pgp_sendfile_ac, "on");
     autocomplete_add(pgp_sendfile_ac, "off");
+
+    // XEP-0373: OX
+    ox_ac = autocomplete_new();
+    autocomplete_add(ox_ac, "keys");
+    autocomplete_add(ox_ac, "contacts");
+    autocomplete_add(ox_ac, "start");
+    autocomplete_add(ox_ac, "end");
+    autocomplete_add(ox_ac, "log");
+    autocomplete_add(ox_ac, "char");
+    autocomplete_add(ox_ac, "sendfile");
+    autocomplete_add(ox_ac, "announce");
+    autocomplete_add(ox_ac, "discover");
+    autocomplete_add(ox_ac, "request");
+
+    pgp_log_ac = autocomplete_new();
+    autocomplete_add(ox_log_ac, "on");
+    autocomplete_add(ox_log_ac, "off");
+    autocomplete_add(ox_log_ac, "redact");
+
+    pgp_sendfile_ac = autocomplete_new();
+    autocomplete_add(ox_sendfile_ac, "on");
+    autocomplete_add(ox_sendfile_ac, "off");
+
 #endif
 
     tls_ac = autocomplete_new();
@@ -1707,6 +1741,7 @@ _cmd_ac_complete_params(ProfWin *window, const char *const input, gboolean previ
 #endif
 #ifdef HAVE_LIBGPGME
     g_hash_table_insert(ac_funcs, "/pgp",           _pgp_autocomplete);
+    g_hash_table_insert(ac_funcs, "/ox",            _ox_autocomplete);
 #endif
 #ifdef HAVE_OMEMO
     g_hash_table_insert(ac_funcs, "/omemo",         _omemo_autocomplete);
@@ -2420,6 +2455,68 @@ _pgp_autocomplete(ProfWin *window, const char *const input, gboolean previous)
 
     return NULL;
 }
+
+/*!
+ * \brief Auto completion for XEP-0373: OpenPGP for XMPP command.
+ *
+ *
+ */
+static char*
+_ox_autocomplete(ProfWin *window, const char *const input, gboolean previous)
+{
+    char *found = NULL;
+
+    jabber_conn_status_t conn_status = connection_get_status();
+
+    if (conn_status == JABBER_CONNECTED) {
+        found = autocomplete_param_with_func(input, "/ox start", roster_contact_autocomplete, previous, NULL);
+        if (found) {
+            return found;
+        }
+    }
+
+    found = autocomplete_param_with_ac(input, "/ox log", ox_log_ac, TRUE, previous);
+    if (found) {
+        return found;
+    }
+
+    found = autocomplete_param_with_ac(input, "/ox sendfile", ox_sendfile_ac, TRUE, previous);
+    if (found) {
+        return found;
+    }
+
+    gboolean result;
+    gchar **args = parse_args(input, 2, 3, &result);
+    if ((strncmp(input, "/ox", 4) == 0) && (result == TRUE)) {
+        GString *beginning = g_string_new("/ox ");
+        g_string_append(beginning, args[0]);
+        if (args[1]) {
+            g_string_append(beginning, " ");
+            g_string_append(beginning, args[1]);
+        }
+        found = autocomplete_param_with_func(input, beginning->str, p_gpg_autocomplete_key, previous, NULL);
+        g_string_free(beginning, TRUE);
+        if (found) {
+            g_strfreev(args);
+            return found;
+        }
+    }
+    g_strfreev(args);
+
+    if (conn_status == JABBER_CONNECTED) {
+        found = autocomplete_param_with_func(input, "/ox setkey", roster_barejid_autocomplete, previous, NULL);
+        if (found) {
+            return found;
+        }
+    }
+
+    found = autocomplete_param_with_ac(input, "/ox", ox_ac, TRUE, previous);
+    if (found) {
+        return found;
+    }
+
+    return NULL;
+}
 #endif
 
 #ifdef HAVE_OMEMO
diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c
index 85140430..815fe9d8 100644
--- a/src/command/cmd_defs.c
+++ b/src/command/cmd_defs.c
@@ -1691,6 +1691,48 @@ static struct cmd_t command_defs[] =
             "/pgp char P")
     },
 
+// XEP-0373: OpenPGP for XMPP
+#ifdef HAVE_LIBGPGME
+    { "/ox",
+        parse_args, 1, 3, NULL,
+        CMD_NOSUBFUNCS
+        CMD_MAINFUNC(cmd_ox)
+        CMD_TAGS(
+            CMD_TAG_CHAT,
+            CMD_TAG_UI)
+        CMD_SYN(
+            "/ox keys",
+            "/ox contacts",
+            "/ox start [<contact>]",
+            "/ox end",
+            "/ox log on|off|redact",
+            "/ox char <char>",
+            "/ox sendfile on|off",
+            "/ox announce <file>",
+            "/ox discover",
+            "/ox request <jid>")
+        CMD_DESC(
+            "OpenPGP (OX) commands to manage keys, and perform PGP encryption during chat sessions. ")
+        CMD_ARGS(
+            { "keys",                     "List all keys known to the system." },
+            { "contacts",                 "Show contacts with assigned public keys." },
+            { "start [<contact>]",        "Start PGP encrypted chat, current contact will be used if not specified." },
+            { "end",                      "End PGP encrypted chat with the current recipient." },
+            { "log on|off",               "Enable or disable plaintext logging of PGP encrypted messages." },
+            { "log redact",               "Log PGP encrypted messages, but replace the contents with [redacted]. This is the default." },
+            { "char <char>",              "Set the character to be displayed next to PGP encrypted messages." },
+            { "announce <file>",          "Announce a public key by pushing it on the XMPP Server"},
+            { "discover <jid>",           "Discover public keys of a jid "},
+            { "request <jid>",            "Request public keys"},
+            { "sendfile on|off",          "Allow /sendfile to send unencrypted files while otherwise using PGP."})
+        CMD_EXAMPLES(
+            "/ox log off",
+            "/ox start odin@valhalla.edda",
+            "/ox end",
+            "/ox char X")
+    },
+#endif // HAVE_LIBGPGME
+
     { "/otr",
         parse_args, 1, 3, NULL,
         CMD_SUBFUNCS(
diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c
index 735e197b..7d779e87 100644
--- a/src/command/cmd_funcs.c
+++ b/src/command/cmd_funcs.c
@@ -7418,6 +7418,169 @@ cmd_pgp(ProfWin *window, const char *const command, gchar **args)
 #endif
 }
 
+#ifdef HAVE_LIBGPGME
+
+/*!
+ * \brief Command for XEP-0373: OpenPGP for XMPP
+ *
+ */
+
+gboolean
+cmd_ox(ProfWin *window, const char *const command, gchar **args)
+{
+    if (args[0] == NULL) {
+        cons_bad_cmd_usage(command);
+        return TRUE;
+    }
+
+    // The '/ox keys' command - same like in pgp
+    // Should we move this to a common command
+    // e.g. '/openpgp keys'?.
+    else if (g_strcmp0(args[0], "keys") == 0) {
+        GHashTable *keys = p_gpg_list_keys();
+        if (!keys || g_hash_table_size(keys) == 0) {
+            cons_show("No keys found");
+            return TRUE;
+        }
+
+        cons_show("OpenPGP keys:");
+        GList *keylist = g_hash_table_get_keys(keys);
+        GList *curr = keylist;
+        while (curr) {
+            ProfPGPKey *key = g_hash_table_lookup(keys, curr->data);
+            cons_show("  %s", key->name);
+            cons_show("    ID          : %s", key->id);
+            char *format_fp = p_gpg_format_fp_str(key->fp);
+            cons_show("    Fingerprint : %s", format_fp);
+            free(format_fp);
+            if (key->secret) {
+                cons_show("    Type        : PUBLIC, PRIVATE");
+            } else {
+                cons_show("    Type        : PUBLIC");
+            }
+            curr = g_list_next(curr);
+        }
+        g_list_free(keylist);
+        p_gpg_free_keys(keys);
+        return TRUE;
+    }
+
+    else if (g_strcmp0(args[0], "contacts") == 0) {
+        GHashTable *keys = ox_gpg_public_keys();
+        cons_show("OpenPGP keys:");
+        GList *keylist = g_hash_table_get_keys(keys);
+        GList *curr = keylist;
+
+
+        GSList *roster_list = NULL;
+        jabber_conn_status_t conn_status = connection_get_status();
+        if (conn_status != JABBER_CONNECTED) {
+            cons_show("You are not currently connected.");
+        } else {
+            roster_list = roster_get_contacts(ROSTER_ORD_NAME);
+        }
+
+        while (curr) {
+            ProfPGPKey *key = g_hash_table_lookup(keys, curr->data);
+            PContact contact = NULL;
+            if (roster_list) {
+                GSList *curr_c = roster_list;
+                while ( !contact && curr_c){
+                    contact = curr_c->data;
+                    const char *jid = p_contact_barejid(contact);
+                    GString* xmppuri = g_string_new("xmpp:");
+                    g_string_append(xmppuri, jid);
+                    if( g_strcmp0(key->name, xmppuri->str)) {
+                        contact = NULL;
+                    }
+                    curr_c = g_slist_next(curr_c);
+                }
+            }
+
+            if(contact) {
+                cons_show("%s - %s", key->fp, key->name);
+            } else {
+                cons_show("%s - %s (not in roster)", key->fp, key->name);
+            }
+            curr = g_list_next(curr);
+        }
+
+    } else if (g_strcmp0(args[0], "start") == 0) {
+        jabber_conn_status_t conn_status = connection_get_status();
+        if (conn_status != JABBER_CONNECTED) {
+            cons_show("You must be connected to start OX encrpytion.");
+            return TRUE;
+        }
+
+        if (window->type != WIN_CHAT && args[1] == NULL) {
+            cons_show("You must be in a regular chat window to start OX encrpytion.");
+            return TRUE;
+        }
+
+        ProfChatWin *chatwin = NULL;
+
+        if (args[1]) {
+            char *contact = args[1];
+            char *barejid = roster_barejid_from_name(contact);
+            if (barejid == NULL) {
+                barejid = contact;
+            }
+
+            chatwin = wins_get_chat(barejid);
+            if (!chatwin) {
+                chatwin = chatwin_new(barejid);
+            }
+            ui_focus_win((ProfWin*)chatwin);
+        } else {
+            chatwin = (ProfChatWin*)window;
+            assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
+        }
+
+        if (chatwin->is_otr) {
+            win_println(window, THEME_DEFAULT, "!", "You must end the OTR session to start OX encryption.");
+            return TRUE;
+        }
+
+        if (chatwin->pgp_send) {
+            win_println(window, THEME_DEFAULT, "!", "You must end the PGP session to start OX encryption.");
+            return TRUE;
+        }
+
+        if (chatwin->is_ox) {
+            win_println(window, THEME_DEFAULT, "!", "You have already started OX encryption.");
+            return TRUE;
+        }
+
+        ProfAccount *account = accounts_get_account(session_get_account_name());
+
+        if ( !ox_is_private_key_available(account->jid) ) {
+            win_println(window, THEME_DEFAULT, "!", "No private OpenPGP found, cannot start OX encryption.");
+            account_free(account);
+            return TRUE;
+        }
+        account_free(account);
+
+        if (!ox_is_public_key_available(chatwin->barejid)) {
+            win_println(window, THEME_DEFAULT, "!", "No OX-OpenPGP key found for %s.", chatwin->barejid);
+            return TRUE;
+        }
+
+        chatwin->is_ox = TRUE;
+        win_println(window, THEME_DEFAULT, "!", "OX encryption enabled.");
+        return TRUE;
+    } else if (g_strcmp0(args[0], "push") == 0) {
+        if( args[1] ) {
+            cons_show("Push file...%s ", args[1] );
+        } else {
+            cons_show("Filename is required");
+        }
+    } else {
+        cons_show("OX not implemented");
+    }
+    return TRUE;
+}
+#endif // HAVE_LIBGPGME
+
 gboolean
 cmd_otr_char(ProfWin *window, const char *const command, gchar **args)
 {
diff --git a/src/command/cmd_funcs.h b/src/command/cmd_funcs.h
index d0d37efa..b75755cb 100644
--- a/src/command/cmd_funcs.h
+++ b/src/command/cmd_funcs.h
@@ -107,6 +107,9 @@ gboolean cmd_msg(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_nick(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_notify(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_pgp(ProfWin *window, const char *const command, gchar **args);
+#ifdef HAVE_LIBGPGME
+gboolean cmd_ox(ProfWin *window, const char *const command, gchar **args);
+#endif // HAVE_LIBGPGME
 gboolean cmd_outtype(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_prefs(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_priority(ProfWin *window, const char *const command, gchar **args);