diff options
-rw-r--r-- | .travis.yml | 2 | ||||
-rw-r--r-- | Makefile.am | 9 | ||||
-rw-r--r-- | configure.ac | 13 | ||||
-rwxr-xr-x | install-all.sh | 2 | ||||
-rw-r--r-- | src/command/command.c | 24 | ||||
-rw-r--r-- | src/command/commands.c | 66 | ||||
-rw-r--r-- | src/command/commands.h | 1 | ||||
-rw-r--r-- | src/config/account.c | 9 | ||||
-rw-r--r-- | src/config/account.h | 3 | ||||
-rw-r--r-- | src/config/accounts.c | 26 | ||||
-rw-r--r-- | src/config/accounts.h | 2 | ||||
-rw-r--r-- | src/main.c | 6 | ||||
-rw-r--r-- | src/pgp/gpg.c | 374 | ||||
-rw-r--r-- | src/pgp/gpg.h | 55 | ||||
-rw-r--r-- | src/profanity.c | 9 | ||||
-rw-r--r-- | src/ui/console.c | 4 | ||||
-rw-r--r-- | src/xmpp/message.c | 48 | ||||
-rw-r--r-- | src/xmpp/presence.c | 37 | ||||
-rw-r--r-- | src/xmpp/stanza.h | 2 | ||||
-rw-r--r-- | tests/config/stub_accounts.c | 2 | ||||
-rw-r--r-- | tests/pgp/stub_gpg.c | 25 | ||||
-rw-r--r-- | tests/test_cmd_account.c | 12 | ||||
-rw-r--r-- | tests/test_cmd_connect.c | 6 | ||||
-rw-r--r-- | tests/test_cmd_join.c | 8 | ||||
-rw-r--r-- | tests/test_cmd_otr.c | 2 |
25 files changed, 725 insertions, 22 deletions
diff --git a/.travis.yml b/.travis.yml index 534440d0..6efa5d82 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: c install: - sudo apt-get update - - sudo apt-get -y install libssl-dev libexpat1-dev libncursesw5-dev libglib2.0-dev libnotify-dev libcurl3-dev libxss-dev libotr2-dev + - sudo apt-get -y install libssl-dev libexpat1-dev libncursesw5-dev libglib2.0-dev libnotify-dev libcurl3-dev libxss-dev libotr2-dev libgpgme11-dev - git clone git://github.com/strophe/libstrophe.git - cd libstrophe - mkdir m4 diff --git a/Makefile.am b/Makefile.am index cd708a13..e14010a7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -44,6 +44,7 @@ tests_sources = \ src/xmpp/xmpp.h src/xmpp/form.c \ src/ui/ui.h \ src/otr/otr.h \ + src/pgp/gpg.h \ src/command/command.h src/command/command.c \ src/command/commands.h src/command/commands.c \ src/tools/parser.c \ @@ -63,6 +64,7 @@ tests_sources = \ src/server_events.c src/server_events.h \ tests/xmpp/stub_xmpp.c \ tests/ui/stub_ui.c \ + tests/pgp/stub_gpg.c \ tests/log/stub_log.c \ tests/config/stub_accounts.c \ tests/helpers.c tests/helpers.h \ @@ -95,6 +97,9 @@ main_source = src/main.c git_include = src/gitversion.h +pgp_sources = \ + src/pgp/gpg.h src/pgp/gpg.c + otr3_sources = \ src/otr/otrlib.h src/otr/otrlibv3.c src/otr/otr.h src/otr/otr.c @@ -110,6 +115,10 @@ script_sources = bootstrap.sh configure-debug install-all.sh man_sources = docs/profanity.1 +if BUILD_PGP +core_sources += $(pgp_sources) +endif + if BUILD_OTR tests_sources += $(otr_test_sources) if BUILD_OTR3 diff --git a/configure.ac b/configure.ac index 0653ab68..96b0e3ba 100644 --- a/configure.ac +++ b/configure.ac @@ -42,6 +42,8 @@ AC_ARG_ENABLE([notifications], [AS_HELP_STRING([--enable-notifications], [enable desktop notifications])]) AC_ARG_ENABLE([otr], [AS_HELP_STRING([--enable-otr], [enable otr encryption])]) +AC_ARG_ENABLE([pgp], + [AS_HELP_STRING([--enable-pgp], [enable pgp])]) AC_ARG_WITH([libxml2], [AS_HELP_STRING([--with-libxml2], [link with libxml2 instead of expat])]) AC_ARG_WITH([xscreensaver], @@ -183,6 +185,17 @@ elif test "x$with_xscreensaver" = x; then [AC_MSG_NOTICE([libX11 not found, falling back to profanity auto-away])]) fi +AM_CONDITIONAL([BUILD_PGP], [false]) +if test "x$enable_pgp" = xyes; then + AC_CHECK_LIB([gpgme], [main], + [AM_CONDITIONAL([BUILD_PGP], [true]) LIBS="-lgpgme $LIBS" AC_DEFINE([HAVE_LIBGPGME], [1], [Have libgpgme])], + [AC_MSG_ERROR([libgpgme is required for profanity])]) +elif test "x$enable_pgp" = x; then + AC_CHECK_LIB([gpgme], [main], + [AM_CONDITIONAL([BUILD_PGP], [true]) LIBS="-lgpgme $LIBS" AC_DEFINE([HAVE_LIBGPGME], [1], [Have libgpgme])], + [AC_MSG_NOTICE([libgpgme not found, pgp support not included.])]) +fi + AM_CONDITIONAL([BUILD_OTR], [false]) AM_CONDITIONAL([BUILD_OTR3], [false]) AM_CONDITIONAL([BUILD_OTR4], [false]) diff --git a/install-all.sh b/install-all.sh index a054e166..fc704bbc 100755 --- a/install-all.sh +++ b/install-all.sh @@ -24,7 +24,7 @@ debian_prepare() echo echo Profanity installer... installing dependencies echo - sudo apt-get -y install git automake autoconf libssl-dev libexpat1-dev libncursesw5-dev libglib2.0-dev libnotify-dev libcurl3-dev libxss-dev libotr5-dev libreadline-dev libtool + sudo apt-get -y install git automake autoconf libssl-dev libexpat1-dev libncursesw5-dev libglib2.0-dev libnotify-dev libcurl3-dev libxss-dev libotr5-dev libreadline-dev libtool libgpgme11-dev } diff --git a/src/command/command.c b/src/command/command.c index e165254e..994c1155 100644 --- a/src/command/command.c +++ b/src/command/command.c @@ -848,6 +848,16 @@ static struct cmd_t command_defs[] = "Send chat state notifications during chat sessions.", NULL } } }, + { "/pgp", + cmd_pgp, parse_args, 1, 1, NULL, + { "/pgp keys|libver", "Open PGP.", + { "/pgp keys|libver", + "----------------", + "Open PGP.", + "keys : List private keys." + "libver : Show which version of the libgpgme library is being used.", + NULL } } }, + { "/otr", cmd_otr, parse_args, 1, 3, NULL, { "/otr command [args..]", "Off The Record encryption commands.", @@ -1202,6 +1212,7 @@ static Autocomplete time_statusbar_ac; static Autocomplete resource_ac; static Autocomplete inpblock_ac; static Autocomplete receipts_ac; +static Autocomplete pgp_ac; /* * Initialise command autocompleter and history @@ -1358,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"); @@ -1365,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"); @@ -1563,6 +1576,11 @@ cmd_init(void) receipts_ac = autocomplete_new(); autocomplete_add(receipts_ac, "send"); autocomplete_add(receipts_ac, "request"); + + pgp_ac = autocomplete_new(); + autocomplete_add(pgp_ac, "keys"); + autocomplete_add(pgp_ac, "fps"); + autocomplete_add(pgp_ac, "libver"); } void @@ -1621,6 +1639,7 @@ cmd_uninit(void) autocomplete_free(resource_ac); autocomplete_free(inpblock_ac); autocomplete_free(receipts_ac); + autocomplete_free(pgp_ac); } gboolean @@ -1788,6 +1807,7 @@ cmd_reset_autocomplete() autocomplete_reset(resource_ac); autocomplete_reset(inpblock_ac); autocomplete_reset(receipts_ac); + autocomplete_reset(pgp_ac); if (ui_current_win_type() == WIN_CHAT) { ProfChatWin *chatwin = wins_get_current_chat(); @@ -1971,8 +1991,8 @@ _cmd_complete_parameters(const char * const input) } } - gchar *cmds[] = { "/help", "/prefs", "/disco", "/close", "/wins", "/subject", "/room" }; - Autocomplete completers[] = { help_ac, prefs_ac, disco_ac, close_ac, wins_ac, subject_ac, room_ac }; + gchar *cmds[] = { "/help", "/prefs", "/disco", "/close", "/wins", "/subject", "/room", "/pgp" }; + Autocomplete completers[] = { help_ac, prefs_ac, disco_ac, close_ac, wins_ac, subject_ac, room_ac, pgp_ac }; for (i = 0; i < ARRAY_SIZE(cmds); i++) { result = autocomplete_param_with_ac(input, cmds[i], completers[i], TRUE); diff --git a/src/command/commands.c b/src/command/commands.c index 2699924b..1d1b10e3 100644 --- a/src/command/commands.c +++ b/src/command/commands.c @@ -56,6 +56,9 @@ #ifdef HAVE_LIBOTR #include "otr/otr.h" #endif +#ifdef HAVE_LIBGPGME +#include "pgp/gpg.h" +#endif #include "profanity.h" #include "tools/autocomplete.h" #include "tools/parser.h" @@ -513,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; @@ -591,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(""); @@ -4069,6 +4080,61 @@ cmd_xa(gchar **args, struct cmd_help_t help) } gboolean +cmd_pgp(gchar **args, struct cmd_help_t help) +{ +#ifdef HAVE_LIBGPGME + if (g_strcmp0(args[0], "keys") == 0) { + GSList *keys = p_gpg_list_keys(); + if (keys) { + cons_show("PGP keys:"); + while (keys) { + ProfPGPKey *key = keys->data; + cons_show(" %s", key->name); + cons_show(" ID : %s", key->id); + cons_show(" Fingerprint : %s", key->fp); + keys = g_slist_next(keys); + } + } else { + cons_show("No keys found"); + } + g_slist_free_full(keys, (GDestroyNotify)p_gpg_free_key); + } else if (g_strcmp0(args[0], "fps") == 0) { + GHashTable *fingerprints = p_gpg_fingerprints(); + GList *jids = g_hash_table_get_keys(fingerprints); + if (jids) { + cons_show("Received PGP fingerprints:"); + GList *curr = jids; + while (curr) { + char *jid = curr->data; + char *fingerprint = g_hash_table_lookup(fingerprints, jid); + cons_show(" %s: %s", jid, fingerprint); + curr = g_list_next(curr); + } + } else { + cons_show("No PGP fingerprints received."); + } + g_list_free(jids); + } else if (g_strcmp0(args[0], "libver") == 0) { + const char *libver = p_gpg_libver(); + if (libver) { + GString *fullstr = g_string_new("Using libgpgme version "); + g_string_append(fullstr, libver); + cons_show("%s", fullstr->str); + g_string_free(fullstr, TRUE); + } else { + cons_show("Could not get libgpgme version"); + } + } + + return TRUE; +#else + cons_show("This version of Profanity has not been built with PGP support enabled"); + return TRUE; +#endif + +} + +gboolean cmd_otr(gchar **args, struct cmd_help_t help) { #ifdef HAVE_LIBOTR diff --git a/src/command/commands.h b/src/command/commands.h index 7b7e7c93..9fe645e3 100644 --- a/src/command/commands.h +++ b/src/command/commands.h @@ -103,6 +103,7 @@ gboolean cmd_nick(gchar **args, struct cmd_help_t help); gboolean cmd_notify(gchar **args, struct cmd_help_t help); gboolean cmd_online(gchar **args, struct cmd_help_t help); gboolean cmd_otr(gchar **args, struct cmd_help_t help); +gboolean cmd_pgp(gchar **args, struct cmd_help_t help); gboolean cmd_outtype(gchar **args, struct cmd_help_t help); gboolean cmd_prefs(gchar **args, struct cmd_help_t help); gboolean cmd_priority(gchar **args, struct cmd_help_t help); 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/main.c b/src/main.c index 3bb7eeb6..ea8f0cea 100644 --- a/src/main.c +++ b/src/main.c @@ -121,6 +121,12 @@ main(int argc, char **argv) g_print("OTR support: Disabled\n"); #endif +#ifdef HAVE_LIBGPGME + g_print("PGP support: Enabled\n"); +#else + g_print("PGP support: Disabled\n"); +#endif + return 0; } diff --git a/src/pgp/gpg.c b/src/pgp/gpg.c new file mode 100644 index 00000000..a998ecc9 --- /dev/null +++ b/src/pgp/gpg.c @@ -0,0 +1,374 @@ +/* + * gpg.c + * + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> + * + * This file is part of Profanity. + * + * Profanity is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Profanity 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Profanity. If not, see <http://www.gnu.org/licenses/>. + * + * In addition, as a special exception, the copyright holders give permission to + * link the code of portions of this program with the OpenSSL library under + * certain conditions as described in each individual source file, and + * distribute linked combinations including the two. + * + * You must obey the GNU General Public License in all respects for all of the + * code used other than OpenSSL. If you modify file(s) with this exception, you + * may extend this exception to your version of the file(s), but you are not + * obligated to do so. If you do not wish to do so, delete this exception + * statement from your version. If you delete this exception statement from all + * source files in the program, then also delete it here. + * + */ + +#include <locale.h> +#include <string.h> +#include <stdlib.h> + +#include <glib.h> +#include <gpgme.h> + +#include "pgp/gpg.h" +#include "log.h" + +#define PGP_SIGNATURE_HEADER "-----BEGIN PGP SIGNATURE-----" +#define PGP_SIGNATURE_FOOTER "-----END PGP SIGNATURE-----" +#define PGP_MESSAGE_HEADER "-----BEGIN PGP MESSAGE-----" +#define PGP_MESSAGE_FOOTER "-----END PGP MESSAGE-----" + +static const char *libversion; +static GHashTable *fingerprints; + +static char* _remove_header_footer(char *str, const char * const footer); +static char* _add_header_footer(const char * const str, const char * const header, const char * const footer); + +void +p_gpg_init(void) +{ + libversion = gpgme_check_version(NULL); + log_debug("GPG: Found gpgme version: %s", libversion); + gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL)); + + // TODO add close function to clean up + fingerprints = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); +} + +void +p_gpg_close(void) +{ + g_hash_table_destroy(fingerprints); +} + +GSList * +p_gpg_list_keys(void) +{ + gpgme_error_t error; + gpgme_ctx_t ctx; + gpgme_key_t key; + GSList *result = NULL; + + error = gpgme_new(&ctx); + if (error) { + log_error("GPG: Could not list keys. %s %s", gpgme_strsource(error), gpgme_strerror(error)); + return NULL; + } + + error = gpgme_op_keylist_start(ctx, NULL, 1); + if (error == GPG_ERR_NO_ERROR) { + while (!error) { + error = gpgme_op_keylist_next(ctx, &key); + if (error) { + break; + } + + ProfPGPKey *p_pgpkey = malloc(sizeof(ProfPGPKey)); + p_pgpkey->id = strdup(key->subkeys->keyid); + p_pgpkey->name = strdup(key->uids->uid); + p_pgpkey->fp = strdup(key->subkeys->fpr); + + result = g_slist_append(result, p_pgpkey); + + gpgme_key_release(key); + } + } else { + log_error("GPG: Could not list keys. %s %s", gpgme_strsource(error), gpgme_strerror(error)); + } + + gpgme_release(ctx); + + return result; +} + +GHashTable * +p_gpg_fingerprints(void) +{ + return fingerprints; +} + +const char* +p_gpg_libver(void) +{ + return libversion; +} + +void +p_gpg_free_key(ProfPGPKey *key) +{ + if (key) { + free(key->id); + free(key->name); + free(key->fp); + free(key); + } +} + +void +p_gpg_verify(const char * const barejid, const char *const sign) +{ + if (!sign) { + return; + } + + 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; + } + + gpgme_data_t sign_data; + gpgme_data_t plain_data; + char *sign_with_header_footer = _add_header_footer(sign, PGP_SIGNATURE_HEADER, PGP_SIGNATURE_FOOTER); + gpgme_data_new_from_mem(&sign_data, sign_with_header_footer, strlen(sign_with_header_footer), 1); + gpgme_data_new(&plain_data); + + error = gpgme_op_verify(ctx, sign_data, NULL, plain_data); + if (error) { + log_error("GPG: Failed to verify. %s %s", gpgme_strsource(error), gpgme_strerror(error)); + gpgme_release(ctx); + return; + } + + gpgme_verify_result_t result = gpgme_op_verify_result(ctx); + if (result) { + if (result->signatures) { + log_debug("Fingerprint found for %s: %s ", barejid, result->signatures->fpr); + g_hash_table_replace(fingerprints, strdup(barejid), strdup(result->signatures->fpr)); + } + } + + gpgme_data_release(sign_data); + gpgme_data_release(plain_data); +} + +char* +p_gpg_sign(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, PGP_SIGNATURE_FOOTER); + } + gpgme_free(signed_str); + gpgme_release(ctx); + free(str_or_empty); + + return result; +} + +char * +p_gpg_encrypt(const char * const barejid, const char * const message) +{ + char *fp = g_hash_table_lookup(fingerprints, barejid); + + if (!fp) { + return NULL; + } + + gpgme_key_t keys[2]; + + keys[0] = NULL; + keys[1] = NULL; + + 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; + error = gpgme_get_key(ctx, fp, &key, 0); + if (error || key == NULL) { + log_error("GPG: Failed to get key. %s %s", gpgme_strsource(error), gpgme_strerror(error)); + gpgme_release(ctx); + return NULL; + } + + keys[0] = key; + + gpgme_data_t plain; + gpgme_data_t cipher; + gpgme_data_new_from_mem(&plain, message, strlen(message), 1); + gpgme_data_new(&cipher); + + gpgme_set_armor(ctx, 1); + error = gpgme_op_encrypt(ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, plain, cipher); + if (error) { + log_error("GPG: Failed to encrypt message. %s %s", gpgme_strsource(error), gpgme_strerror(error)); + gpgme_release(ctx); + return NULL; + } + gpgme_data_release(plain); + + char *cipher_str = NULL; + char *result = NULL; + size_t len; + cipher_str = gpgme_data_release_and_get_mem(cipher, &len); + if (cipher_str) { + result = _remove_header_footer(cipher_str, PGP_MESSAGE_FOOTER); + } + + gpgme_free(cipher_str); + gpgme_release(ctx); + + return result; +} + +char * +p_gpg_decrypt(const char * const barejid, const char * const cipher) +{ + char *cipher_with_headers = _add_header_footer(cipher, PGP_MESSAGE_HEADER, PGP_MESSAGE_FOOTER); + + 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_data_t plain_data; + gpgme_data_t cipher_data; + gpgme_data_new_from_mem (&cipher_data, cipher_with_headers, strlen(cipher_with_headers), 1); + gpgme_data_new(&plain_data); + + error = gpgme_op_decrypt(ctx, cipher_data, plain_data); + if (error) { + log_error("GPG: Failed to encrypt message. %s %s", gpgme_strsource(error), gpgme_strerror(error)); + gpgme_release(ctx); + return NULL; + } + + gpgme_data_release(cipher_data); + + size_t len = 0; + char *plain_str = gpgme_data_release_and_get_mem(plain_data, &len); + char *result = NULL; + if (plain_str) { + plain_str[len] = 0; + result = g_strdup(plain_str); + } + gpgme_free(plain_str); + + gpgme_release(ctx); + + return result; +} + +static char* +_remove_header_footer(char *str, const char * const footer) +{ + int pos = 0; + int newlines = 0; + + while (newlines < 3) { + if (str[pos] == '\n') { + newlines++; + } + pos++; + + if (str[pos] == '\0') { + return NULL; + } + } + + char *stripped = strdup(&str[pos]); + char *footer_start = g_strrstr(stripped, footer); + footer_start[0] = '\0'; + + return stripped; +} + +static char* +_add_header_footer(const char * const str, const char * const header, const char * const footer) +{ + GString *result_str = g_string_new(""); + + g_string_append(result_str, header); + g_string_append(result_str, "\n\n"); + g_string_append(result_str, str); + g_string_append(result_str, "\n"); + g_string_append(result_str, footer); + + char *result = result_str->str; + g_string_free(result_str, FALSE); + + return result; +} diff --git a/src/pgp/gpg.h b/src/pgp/gpg.h new file mode 100644 index 00000000..fb1f0f6b --- /dev/null +++ b/src/pgp/gpg.h @@ -0,0 +1,55 @@ +/* + * gpg.h + * + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> + * + * This file is part of Profanity. + * + * Profanity is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Profanity 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Profanity. If not, see <http://www.gnu.org/licenses/>. + * + * In addition, as a special exception, the copyright holders give permission to + * link the code of portions of this program with the OpenSSL library under + * certain conditions as described in each individual source file, and + * distribute linked combinations including the two. + * + * You must obey the GNU General Public License in all respects for all of the + * code used other than OpenSSL. If you modify file(s) with this exception, you + * may extend this exception to your version of the file(s), but you are not + * obligated to do so. If you do not wish to do so, delete this exception + * statement from your version. If you delete this exception statement from all + * source files in the program, then also delete it here. + * + */ + +#ifndef GPG_H +#define GPG_H + +typedef struct pgp_key_t { + char *id; + char *name; + char *fp; +} ProfPGPKey; + +void p_gpg_init(void); +void p_gpg_close(void); +GSList* p_gpg_list_keys(void); +GHashTable* p_gpg_fingerprints(void); +const char* p_gpg_libver(void); +void p_gpg_free_key(ProfPGPKey *key); +char* p_gpg_sign(const char * const str, const char * const fp); +void p_gpg_verify(const char * const barejid, const char *const sign); +char* p_gpg_encrypt(const char * const barejid, const char * const message); +char* p_gpg_decrypt(const char * const barejid, const char * const cipher); + +#endif diff --git a/src/profanity.c b/src/profanity.c index 6a2966dd..47063ae8 100644 --- a/src/profanity.c +++ b/src/profanity.c @@ -59,6 +59,9 @@ #ifdef HAVE_LIBOTR #include "otr/otr.h" #endif +#ifdef HAVE_LIBGPGME +#include "pgp/gpg.h" +#endif #include "resource.h" #include "xmpp/xmpp.h" #include "ui/ui.h" @@ -241,6 +244,9 @@ _init(const int disable_tls, char *log_level) #ifdef HAVE_LIBOTR otr_init(); #endif +#ifdef HAVE_LIBGPGME + p_gpg_init(); +#endif atexit(_shutdown); ui_input_nonblocking(TRUE); } @@ -265,6 +271,9 @@ _shutdown(void) #ifdef HAVE_LIBOTR otr_shutdown(); #endif +#ifdef HAVE_LIBGPGME + p_gpg_close(); +#endif chat_log_close(); prefs_close(); theme_close(); 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/message.c b/src/xmpp/message.c index 02c748d9..c106517b 100644 --- a/src/xmpp/message.c +++ b/src/xmpp/message.c @@ -49,6 +49,7 @@ #include "roster_list.h" #include "xmpp/stanza.h" #include "xmpp/xmpp.h" +#include "pgp/gpg.h" #define HANDLE(ns, type, func) xmpp_handler_add(conn, func, ns, STANZA_NAME_MESSAGE, type, ctx) @@ -104,7 +105,36 @@ message_send_chat(const char * const barejid, const char * const msg) } char *id = create_unique_id("msg"); - xmpp_stanza_t *message = stanza_create_message(ctx, id, jid, STANZA_TYPE_CHAT, msg); + xmpp_stanza_t *message = NULL; + +#ifdef HAVE_LIBGPGME + char *account_name = jabber_get_account_name(); + ProfAccount *account = accounts_get_account(account_name); + if (account->pgp_keyid) { + Jid *jidp = jid_create(jid); + char *encrypted = p_gpg_encrypt(jidp->barejid, msg); + if (encrypted) { + message = stanza_create_message(ctx, id, jid, STANZA_TYPE_CHAT, "This message is encrypted."); + xmpp_stanza_t *x = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(x, STANZA_NAME_X); + xmpp_stanza_set_ns(x, STANZA_NS_ENCRYPTED); + xmpp_stanza_t *enc_st = xmpp_stanza_new(ctx); + xmpp_stanza_set_text(enc_st, encrypted); + xmpp_stanza_add_child(x, enc_st); + xmpp_stanza_release(enc_st); + xmpp_stanza_add_child(message, x); + xmpp_stanza_release(x); + free(encrypted); + } else { + message = stanza_create_message(ctx, id, jid, STANZA_TYPE_CHAT, msg); + } + } else { + message = stanza_create_message(ctx, id, jid, STANZA_TYPE_CHAT, msg); + } +#else + message = stanza_create_message(ctx, id, jid, STANZA_TYPE_CHAT, msg); +#endif + free(jid); if (state) { @@ -639,7 +669,23 @@ _chat_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, if (delayed) { handle_delayed_message(jid->barejid, message, tv_stamp); } else { +#ifdef HAVE_LIBGPGME + gboolean handled = FALSE; + xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_ENCRYPTED); + if (x) { + char *enc_message = xmpp_stanza_get_text(x); + char *decrypted = p_gpg_decrypt(jid->barejid, enc_message); + if (decrypted) { + handle_incoming_message(jid->barejid, jid->resourcepart, decrypted); + handled = TRUE; + } + } + if (!handled) { + handle_incoming_message(jid->barejid, jid->resourcepart, message); + } +#else handle_incoming_message(jid->barejid, jid->resourcepart, message); +#endif } if (id && prefs_get_boolean(PREF_RECEIPTS_SEND)) { xmpp_stanza_t *receipts = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_RECEIPTS); diff --git a/src/xmpp/presence.c b/src/xmpp/presence.c index f4c45318..07ac05dd 100644 --- a/src/xmpp/presence.c +++ b/src/xmpp/presence.c @@ -49,6 +49,9 @@ #include "xmpp/connection.h" #include "xmpp/stanza.h" #include "xmpp/xmpp.h" +#ifdef HAVE_LIBGPGME +#include "pgp/gpg.h" +#endif static Autocomplete sub_requests_ac; @@ -222,7 +225,31 @@ 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); + +#ifdef HAVE_LIBGPGME + char *account_name = jabber_get_account_name(); + ProfAccount *account = accounts_get_account(account_name); + if (account->pgp_keyid) { + char *signed_status = p_gpg_sign(msg, account->pgp_keyid); + + if (signed_status) { + 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); + 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); + } + } +#endif + stanza_attach_priority(ctx, presence, pri); stanza_attach_last_activity(ctx, presence, idle); stanza_attach_caps(ctx, presence); @@ -580,6 +607,16 @@ _available_handler(xmpp_conn_t * const conn, log_debug("Presence available handler fired for: %s", jid); } +#ifdef HAVE_LIBGPGME + xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_SIGNED); + if (x) { + char *sign = xmpp_stanza_get_text(x); + if (sign) { + p_gpg_verify(xmpp_presence->jid->barejid, sign); + } + } +#endif + const char *my_jid_str = xmpp_conn_get_jid(conn); Jid *my_jid = jid_create(my_jid_str); diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h index 89dbda57..042b6aea 100644 --- a/src/xmpp/stanza.h +++ b/src/xmpp/stanza.h @@ -160,6 +160,8 @@ #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_NS_ENCRYPTED "jabber:x:encrypted" #define STANZA_DATAFORM_SOFTWARE "urn:xmpp:dataforms:softwareinfo" diff --git a/tests/config/stub_accounts.c b/tests/config/stub_accounts.c index 32a80fda..c046be86 100644 --- a/tests/config/stub_accounts.c +++ b/tests/config/stub_accounts.c @@ -122,6 +122,7 @@ void accounts_set_otr_policy(const char * const account_name, const char * const } void accounts_set_last_presence(const char * const account_name, const char * const value) {} +void accounts_set_pgp_keyid(const char * const account_name, const char * const value) {} void accounts_set_login_presence(const char * const account_name, const char * const value) { @@ -182,4 +183,5 @@ 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) {} diff --git a/tests/pgp/stub_gpg.c b/tests/pgp/stub_gpg.c new file mode 100644 index 00000000..14cdfe96 --- /dev/null +++ b/tests/pgp/stub_gpg.c @@ -0,0 +1,25 @@ +#include <glib.h> + +#include "pgp/gpg.h" + +void p_gpg_init(void) {} +void p_gpg_close(void) {} + +GSList* p_gpg_list_keys(void) +{ + return NULL; +} + +GHashTable* +p_gpg_fingerprints(void) +{ + return NULL; +} + +const char* p_gpg_libver(void) +{ + return NULL; +} + +void p_gpg_free_key(ProfPGPKey *key) {} + diff --git a/tests/test_cmd_account.c b/tests/test_cmd_account.c index d02fc5ba..9dfc2c04 100644 --- a/tests/test_cmd_account.c +++ b/tests/test_cmd_account.c @@ -36,7 +36,7 @@ void cmd_account_shows_account_when_connected_and_no_args(void **state) { CommandHelp *help = malloc(sizeof(CommandHelp)); ProfAccount *account = account_new("jabber_org", "me@jabber.org", NULL, NULL, - TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL); + TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); gchar *args[] = { NULL }; will_return(jabber_get_connection_status, JABBER_CONNECTED); @@ -109,7 +109,7 @@ void cmd_account_show_shows_account_when_exists(void **state) CommandHelp *help = malloc(sizeof(CommandHelp)); gchar *args[] = { "show", "account_name", NULL }; ProfAccount *account = account_new("jabber_org", "me@jabber.org", NULL, NULL, - TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL); + TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); expect_any(accounts_get_account, name); will_return(accounts_get_account, account); @@ -478,7 +478,7 @@ void cmd_account_set_password_sets_password(void **state) CommandHelp *help = malloc(sizeof(CommandHelp)); gchar *args[] = { "set", "a_account", "password", "a_password", NULL }; ProfAccount *account = account_new("a_account", NULL, NULL, NULL, - TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL); + TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); expect_any(accounts_account_exists, account_name); @@ -504,7 +504,7 @@ void cmd_account_set_eval_password_sets_eval_password(void **state) CommandHelp *help = malloc(sizeof(CommandHelp)); gchar *args[] = { "set", "a_account", "eval_password", "a_password", NULL }; ProfAccount *account = account_new("a_account", NULL, NULL, NULL, - TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL); + TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); expect_any(accounts_account_exists, account_name); @@ -529,7 +529,7 @@ void cmd_account_set_password_when_eval_password_set(void **state) { CommandHelp *help = malloc(sizeof(CommandHelp)); gchar *args[] = { "set", "a_account", "password", "a_password", NULL }; ProfAccount *account = account_new("a_account", NULL, NULL, "a_password", - TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL); + TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); expect_any(accounts_account_exists, account_name); @@ -550,7 +550,7 @@ void cmd_account_set_eval_password_when_password_set(void **state) { CommandHelp *help = malloc(sizeof(CommandHelp)); gchar *args[] = { "set", "a_account", "eval_password", "a_password", NULL }; ProfAccount *account = account_new("a_account", NULL, "a_password", NULL, - TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL); + TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); expect_any(accounts_account_exists, account_name); diff --git a/tests/test_cmd_connect.c b/tests/test_cmd_connect.c index e2089a09..90b154d5 100644 --- a/tests/test_cmd_connect.c +++ b/tests/test_cmd_connect.c @@ -411,7 +411,7 @@ void cmd_connect_asks_password_when_not_in_account(void **state) CommandHelp *help = malloc(sizeof(CommandHelp)); gchar *args[] = { "jabber_org", NULL }; ProfAccount *account = account_new("jabber_org", "me@jabber.org", NULL, NULL, - TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL); + TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); will_return(jabber_get_connection_status, JABBER_DISCONNECTED); @@ -436,7 +436,7 @@ void cmd_connect_shows_message_when_connecting_with_account(void **state) CommandHelp *help = malloc(sizeof(CommandHelp)); gchar *args[] = { "jabber_org", NULL }; ProfAccount *account = account_new("jabber_org", "user@jabber.org", "password", NULL, - TRUE, NULL, 0, "laptop", NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL); + TRUE, NULL, 0, "laptop", NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); will_return(jabber_get_connection_status, JABBER_DISCONNECTED); @@ -459,7 +459,7 @@ void cmd_connect_connects_with_account(void **state) CommandHelp *help = malloc(sizeof(CommandHelp)); gchar *args[] = { "jabber_org", NULL }; ProfAccount *account = account_new("jabber_org", "me@jabber.org", "password", NULL, - TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL); + TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); will_return(jabber_get_connection_status, JABBER_DISCONNECTED); diff --git a/tests/test_cmd_join.c b/tests/test_cmd_join.c index 10ffa547..1fd2fcc5 100644 --- a/tests/test_cmd_join.c +++ b/tests/test_cmd_join.c @@ -93,7 +93,7 @@ void cmd_join_uses_account_mucservice_when_no_service_specified(void **state) CommandHelp *help = malloc(sizeof(CommandHelp)); gchar *args[] = { room, "nick", nick, NULL }; ProfAccount *account = account_new(account_name, "user@server.org", NULL, NULL, - TRUE, NULL, 0, "laptop", NULL, NULL, 0, 0, 0, 0, 0, account_service, NULL, NULL, NULL, NULL, NULL); + TRUE, NULL, 0, "laptop", NULL, NULL, 0, 0, 0, 0, 0, account_service, NULL, NULL, NULL, NULL, NULL, NULL); muc_init(); @@ -121,7 +121,7 @@ void cmd_join_uses_supplied_nick(void **state) CommandHelp *help = malloc(sizeof(CommandHelp)); gchar *args[] = { room, "nick", nick, NULL }; ProfAccount *account = account_new(account_name, "user@server.org", NULL, NULL, - TRUE, NULL, 0, "laptop", NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL); + TRUE, NULL, 0, "laptop", NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); muc_init(); @@ -149,7 +149,7 @@ void cmd_join_uses_account_nick_when_not_supplied(void **state) CommandHelp *help = malloc(sizeof(CommandHelp)); gchar *args[] = { room, NULL }; ProfAccount *account = account_new(account_name, "user@server.org", NULL, NULL, - TRUE, NULL, 0, "laptop", NULL, NULL, 0, 0, 0, 0, 0, NULL, account_nick, NULL, NULL, NULL, NULL); + TRUE, NULL, 0, "laptop", NULL, NULL, 0, 0, 0, 0, 0, NULL, account_nick, NULL, NULL, NULL, NULL, NULL); muc_init(); @@ -180,7 +180,7 @@ void cmd_join_uses_password_when_supplied(void **state) CommandHelp *help = malloc(sizeof(CommandHelp)); gchar *args[] = { room, "password", password, NULL }; ProfAccount *account = account_new(account_name, "user@server.org", NULL, NULL, - TRUE, NULL, 0, "laptop", NULL, NULL, 0, 0, 0, 0, 0, account_service, account_nick, NULL, NULL, NULL, NULL); + TRUE, NULL, 0, "laptop", NULL, NULL, 0, 0, 0, 0, 0, account_service, account_nick, NULL, NULL, NULL, NULL, NULL); muc_init(); diff --git a/tests/test_cmd_otr.c b/tests/test_cmd_otr.c index dae17947..8841be86 100644 --- a/tests/test_cmd_otr.c +++ b/tests/test_cmd_otr.c @@ -308,7 +308,7 @@ void cmd_otr_gen_generates_key_for_connected_account(void **state) gchar *args[] = { "gen", NULL }; char *account_name = "myaccount"; ProfAccount *account = account_new(account_name, "me@jabber.org", NULL, NULL, - TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL); + TRUE, NULL, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); will_return(jabber_get_connection_status, JABBER_CONNECTED); will_return(jabber_get_account_name, account_name); |