diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/command/command.c | 72 | ||||
-rw-r--r-- | src/command/commands.c | 218 | ||||
-rw-r--r-- | src/command/commands.h | 2 | ||||
-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/config/preferences.c | 35 | ||||
-rw-r--r-- | src/config/preferences.h | 5 | ||||
-rw-r--r-- | src/config/theme.c | 2 | ||||
-rw-r--r-- | src/event/client_events.c | 78 | ||||
-rw-r--r-- | src/event/server_events.c | 138 | ||||
-rw-r--r-- | src/event/server_events.h | 8 | ||||
-rw-r--r-- | src/log.c | 34 | ||||
-rw-r--r-- | src/log.h | 2 | ||||
-rw-r--r-- | src/main.c | 6 | ||||
-rw-r--r-- | src/otr/otr.c | 57 | ||||
-rw-r--r-- | src/otr/otr.h | 4 | ||||
-rw-r--r-- | src/pgp/gpg.c | 380 | ||||
-rw-r--r-- | src/pgp/gpg.h | 56 | ||||
-rw-r--r-- | src/profanity.c | 9 | ||||
-rw-r--r-- | src/ui/console.c | 21 | ||||
-rw-r--r-- | src/ui/core.c | 27 | ||||
-rw-r--r-- | src/ui/titlebar.c | 98 | ||||
-rw-r--r-- | src/ui/ui.h | 3 | ||||
-rw-r--r-- | src/ui/win_types.h | 3 | ||||
-rw-r--r-- | src/xmpp/message.c | 124 | ||||
-rw-r--r-- | src/xmpp/presence.c | 27 | ||||
-rw-r--r-- | src/xmpp/stanza.h | 2 | ||||
-rw-r--r-- | src/xmpp/xmpp.h | 6 |
30 files changed, 1267 insertions, 190 deletions
diff --git a/src/command/command.c b/src/command/command.c index 43bca08b..1d99e56a 100644 --- a/src/command/command.c +++ b/src/command/command.c @@ -83,6 +83,7 @@ static char * _roster_autocomplete(ProfWin *window, const char * const input); static char * _group_autocomplete(ProfWin *window, const char * const input); static char * _bookmark_autocomplete(ProfWin *window, const char * const input); static char * _otr_autocomplete(ProfWin *window, const char * const input); +static char * _pgp_autocomplete(ProfWin *window, const char * const input); static char * _connect_autocomplete(ProfWin *window, const char * const input); static char * _statuses_autocomplete(ProfWin *window, const char * const input); static char * _alias_autocomplete(ProfWin *window, const char * const input); @@ -667,6 +668,14 @@ static struct cmd_t command_defs[] = "If the terminal does not support sounds, it may attempt to flash the screen instead.", NULL } } }, + { "/encwarn", + cmd_encwarn, parse_args, 1, 1, &cons_encwarn_setting, + { "/encwarn on|off", "Titlebar encryption warning.", + { "/encwarn on|off", + "---------------", + "Enabled or disable the unencrypted warning message in the titlebar.", + NULL } } }, + { "/presence", cmd_presence, parse_args, 1, 1, &cons_presence_setting, { "/presence on|off", "Show the contacts presence in the titlebar.", @@ -859,6 +868,21 @@ static struct cmd_t command_defs[] = "Send chat state notifications during chat sessions.", NULL } } }, + { "/pgp", + cmd_pgp, parse_args, 1, 2, NULL, + { "/pgp command [args..]", "Open PGP commands.", + { "/pgp command [args..]", + "---------------------", + "Open PGP commands.", + "", + "keys : List private keys.", + "libver : Show which version of the libgpgme library is being used.", + "fps : Show received fingerprints.", + "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|redact : PGP message logging, default: redact.", + NULL } } }, + { "/otr", cmd_otr, parse_args, 1, 3, NULL, { "/otr command [args..]", "Off The Record encryption commands.", @@ -1214,6 +1238,8 @@ static Autocomplete time_statusbar_ac; static Autocomplete resource_ac; static Autocomplete inpblock_ac; static Autocomplete receipts_ac; +static Autocomplete pgp_ac; +static Autocomplete pgp_log_ac; /* * Initialise command autocompleter and history @@ -1370,6 +1396,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"); @@ -1377,6 +1404,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"); @@ -1467,7 +1495,6 @@ cmd_init(void) autocomplete_add(otr_ac, "untrust"); autocomplete_add(otr_ac, "secret"); autocomplete_add(otr_ac, "log"); - autocomplete_add(otr_ac, "warn"); autocomplete_add(otr_ac, "libver"); autocomplete_add(otr_ac, "policy"); autocomplete_add(otr_ac, "question"); @@ -1579,6 +1606,19 @@ 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"); + autocomplete_add(pgp_ac, "start"); + autocomplete_add(pgp_ac, "end"); + autocomplete_add(pgp_ac, "log"); + + pgp_log_ac = autocomplete_new(); + autocomplete_add(pgp_log_ac, "on"); + autocomplete_add(pgp_log_ac, "off"); + autocomplete_add(pgp_log_ac, "redact"); } void @@ -1638,6 +1678,8 @@ cmd_uninit(void) autocomplete_free(resource_ac); autocomplete_free(inpblock_ac); autocomplete_free(receipts_ac); + autocomplete_free(pgp_ac); + autocomplete_free(pgp_log_ac); } gboolean @@ -1810,6 +1852,8 @@ cmd_reset_autocomplete(ProfWin *window) autocomplete_reset(resource_ac); autocomplete_reset(inpblock_ac); autocomplete_reset(receipts_ac); + autocomplete_reset(pgp_ac); + autocomplete_reset(pgp_log_ac); if (window->type == WIN_CHAT) { ProfChatWin *chatwin = (ProfChatWin*)window; @@ -1932,7 +1976,7 @@ _cmd_complete_parameters(ProfWin *window, const char * const input) // autocomplete boolean settings gchar *boolean_choices[] = { "/beep", "/intype", "/states", "/outtype", "/flash", "/splash", "/chlog", "/grlog", "/mouse", "/history", - "/vercheck", "/privileges", "/presence", "/wrap", "/winstidy", "/carbons" }; + "/vercheck", "/privileges", "/presence", "/wrap", "/winstidy", "/carbons", "/encwarn" }; for (i = 0; i < ARRAY_SIZE(boolean_choices); i++) { result = autocomplete_param_with_func(input, boolean_choices[i], prefs_autocomplete_boolean_choice); @@ -2020,6 +2064,7 @@ _cmd_complete_parameters(ProfWin *window, const char * const input) g_hash_table_insert(ac_funcs, "/bookmark", _bookmark_autocomplete); g_hash_table_insert(ac_funcs, "/autoconnect", _autoconnect_autocomplete); g_hash_table_insert(ac_funcs, "/otr", _otr_autocomplete); + g_hash_table_insert(ac_funcs, "/pgp", _pgp_autocomplete); g_hash_table_insert(ac_funcs, "/connect", _connect_autocomplete); g_hash_table_insert(ac_funcs, "/statuses", _statuses_autocomplete); g_hash_table_insert(ac_funcs, "/alias", _alias_autocomplete); @@ -2434,13 +2479,30 @@ _otr_autocomplete(ProfWin *window, const char * const input) return found; } - found = autocomplete_param_with_func(input, "/otr warn", - prefs_autocomplete_boolean_choice); + found = autocomplete_param_with_ac(input, "/otr", otr_ac, TRUE); if (found) { return found; } - found = autocomplete_param_with_ac(input, "/otr", otr_ac, TRUE); + return NULL; +} + +static char * +_pgp_autocomplete(ProfWin *window, const char * const input) +{ + char *found = NULL; + + found = autocomplete_param_with_func(input, "/pgp start", roster_contact_autocomplete); + if (found) { + return found; + } + + found = autocomplete_param_with_ac(input, "/pgp log", pgp_log_ac, TRUE); + if (found) { + return found; + } + + found = autocomplete_param_with_ac(input, "/pgp", pgp_ac, TRUE); if (found) { return found; } diff --git a/src/command/commands.c b/src/command/commands.c index 73dc4d47..38f15a74 100644 --- a/src/command/commands.c +++ b/src/command/commands.c @@ -57,6 +57,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" @@ -477,6 +480,10 @@ cmd_account(ProfWin *window, 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; @@ -555,6 +562,10 @@ cmd_account(ProfWin *window, 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(""); @@ -4126,6 +4137,188 @@ cmd_xa(ProfWin *window, gchar **args, struct cmd_help_t help) } gboolean +cmd_pgp(ProfWin *window, gchar **args, struct cmd_help_t help) +{ +#ifdef HAVE_LIBGPGME + if (args[0] == NULL) { + cons_show("Usage: %s", help.usage); + return TRUE; + } + + if (g_strcmp0(args[0], "log") == 0) { + char *choice = args[1]; + if (g_strcmp0(choice, "on") == 0) { + prefs_set_string(PREF_PGP_LOG, "on"); + cons_show("PGP messages will be logged as plaintext."); + if (!prefs_get_boolean(PREF_CHLOG)) { + cons_show("Chat logging is currently disabled, use '/chlog on' to enable."); + } + } else if (g_strcmp0(choice, "off") == 0) { + prefs_set_string(PREF_PGP_LOG, "off"); + cons_show("PGP message logging disabled."); + } else if (g_strcmp0(choice, "redact") == 0) { + prefs_set_string(PREF_PGP_LOG, "redact"); + cons_show("PGP messages will be logged as '[redacted]'."); + if (!prefs_get_boolean(PREF_CHLOG)) { + cons_show("Chat logging is currently disabled, use '/chlog on' to enable."); + } + } else { + cons_show("Usage: %s", help.usage); + } + return TRUE; + } + + if (g_strcmp0(args[0], "keys") == 0) { + GSList *keys = p_gpg_list_keys(); + if (!keys) { + cons_show("No keys found"); + return TRUE; + } + + cons_show("PGP keys:"); + GSList *curr = keys; + while (curr) { + ProfPGPKey *key = curr->data; + cons_show(" %s", key->name); + cons_show(" ID : %s", key->id); + cons_show(" Fingerprint : %s", key->fp); + curr = g_slist_next(curr); + } + g_slist_free_full(keys, (GDestroyNotify)p_gpg_free_key); + return TRUE; + } + + if (g_strcmp0(args[0], "fps") == 0) { + jabber_conn_status_t conn_status = jabber_get_connection_status(); + if (conn_status != JABBER_CONNECTED) { + cons_show("You are not currently connected."); + return TRUE; + } + GHashTable *fingerprints = p_gpg_fingerprints(); + GList *jids = g_hash_table_get_keys(fingerprints); + if (!jids) { + cons_show("No PGP fingerprints received."); + return TRUE; + } + + 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); + } + g_list_free(jids); + return TRUE; + } + + if (g_strcmp0(args[0], "libver") == 0) { + const char *libver = p_gpg_libver(); + if (!libver) { + cons_show("Could not get libgpgme version"); + return TRUE; + } + + GString *fullstr = g_string_new("Using libgpgme version "); + g_string_append(fullstr, libver); + cons_show("%s", fullstr->str); + g_string_free(fullstr, TRUE); + + return TRUE; + } + + if (g_strcmp0(args[0], "start") == 0) { + jabber_conn_status_t conn_status = jabber_get_connection_status(); + if (conn_status != JABBER_CONNECTED) { + cons_show("You must be connected to start PGP encrpytion."); + return TRUE; + } + + if (window->type != WIN_CHAT && args[1] == NULL) { + cons_show("You must be in a regular chat window to start PGP 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 = ui_ev_new_chat_win(barejid); + } + ui_ev_focus_win((ProfWin*)chatwin); + } else { + chatwin = (ProfChatWin*)window; + assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); + } + + if (chatwin->enc_mode == PROF_ENC_OTR) { + ui_current_print_formatted_line('!', 0, "You must end the OTR session to start PGP encryption."); + return TRUE; + } + + if (chatwin->enc_mode == PROF_ENC_PGP) { + ui_current_print_formatted_line('!', 0, "You have already started PGP encryption."); + return TRUE; + } + + ProfAccount *account = accounts_get_account(jabber_get_account_name()); + if (!account->pgp_keyid) { + ui_current_print_formatted_line('!', 0, "You must specify a PGP key ID for this account to start PGP encryption."); + account_free(account); + return TRUE; + } + account_free(account); + + if (!p_gpg_available(chatwin->barejid)) { + ui_current_print_formatted_line('!', 0, "No PGP key found for %s.", chatwin->barejid); + return TRUE; + } + + chatwin->enc_mode = PROF_ENC_PGP; + ui_current_print_formatted_line('!', 0, "PGP encyption enabled."); + return TRUE; + } + + if (g_strcmp0(args[0], "end") == 0) { + jabber_conn_status_t conn_status = jabber_get_connection_status(); + if (conn_status != JABBER_CONNECTED) { + cons_show("You are not currently connected."); + return TRUE; + } + + if (window->type != WIN_CHAT) { + cons_show("You must be in a regular chat window to end PGP encrpytion."); + return TRUE; + } + + ProfChatWin *chatwin = (ProfChatWin*)window; + if (chatwin->enc_mode != PROF_ENC_PGP) { + ui_current_print_formatted_line('!', 0, "PGP encryption is not currently enabled."); + return TRUE; + } + + chatwin->enc_mode = PROF_ENC_NONE; + ui_current_print_formatted_line('!', 0, "PGP encyption disabled."); + return TRUE; + } + + return TRUE; +#else + cons_show("This version of Profanity has not been built with PGP support enabled"); + return TRUE; +#endif + +} + +gboolean cmd_otr(ProfWin *window, gchar **args, struct cmd_help_t help) { #ifdef HAVE_LIBOTR @@ -4156,11 +4349,6 @@ cmd_otr(ProfWin *window, gchar **args, struct cmd_help_t help) } return TRUE; - } else if (strcmp(args[0], "warn") == 0) { - gboolean result = _cmd_set_boolean_preference(args[1], help, - "OTR warning message", PREF_OTR_WARN); - return result; - } else if (strcmp(args[0], "libver") == 0) { char *version = otr_libotr_version(); cons_show("Using libotr version %s", version); @@ -4257,6 +4445,11 @@ cmd_otr(ProfWin *window, gchar **args, struct cmd_help_t help) } ui_ev_focus_win((ProfWin*)chatwin); + if (chatwin->enc_mode == PROF_ENC_PGP) { + ui_current_print_formatted_line('!', 0, "You must disable PGP encryption before starting an OTR session."); + return TRUE; + } + if (chatwin->enc_mode == PROF_ENC_OTR) { ui_current_print_formatted_line('!', 0, "You are already in an OTR session."); return TRUE; @@ -4269,7 +4462,7 @@ cmd_otr(ProfWin *window, gchar **args, struct cmd_help_t help) if (!otr_is_secure(barejid)) { char *otr_query_message = otr_start_query(); - message_send_chat_encrypted(barejid, otr_query_message); + message_send_chat_otr(barejid, otr_query_message); return TRUE; } @@ -4285,6 +4478,11 @@ cmd_otr(ProfWin *window, gchar **args, struct cmd_help_t help) ProfChatWin *chatwin = (ProfChatWin*)window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); + if (chatwin->enc_mode == PROF_ENC_PGP) { + ui_current_print_formatted_line('!', 0, "You must disable PGP encryption before starting an OTR session."); + return TRUE; + } + if (chatwin->enc_mode == PROF_ENC_OTR) { ui_current_print_formatted_line('!', 0, "You are already in an OTR session."); return TRUE; @@ -4296,7 +4494,7 @@ cmd_otr(ProfWin *window, gchar **args, struct cmd_help_t help) } char *otr_query_message = otr_start_query(); - message_send_chat_encrypted(chatwin->barejid, otr_query_message); + message_send_chat_otr(chatwin->barejid, otr_query_message); return TRUE; } @@ -4428,6 +4626,12 @@ cmd_otr(ProfWin *window, gchar **args, struct cmd_help_t help) #endif } +gboolean +cmd_encwarn(ProfWin *window, gchar **args, struct cmd_help_t help) +{ + return _cmd_set_boolean_preference(args[0], help, "Encryption warning message", PREF_ENC_WARN); +} + // helper function for status change commands static void _update_presence(const resource_presence_t resource_presence, diff --git a/src/command/commands.h b/src/command/commands.h index 2af24180..6f2bada2 100644 --- a/src/command/commands.h +++ b/src/command/commands.h @@ -105,6 +105,7 @@ gboolean cmd_nick(ProfWin *window, gchar **args, struct cmd_help_t help); gboolean cmd_notify(ProfWin *window, gchar **args, struct cmd_help_t help); gboolean cmd_online(ProfWin *window, gchar **args, struct cmd_help_t help); gboolean cmd_otr(ProfWin *window, gchar **args, struct cmd_help_t help); +gboolean cmd_pgp(ProfWin *window, gchar **args, struct cmd_help_t help); gboolean cmd_outtype(ProfWin *window, gchar **args, struct cmd_help_t help); gboolean cmd_prefs(ProfWin *window, gchar **args, struct cmd_help_t help); gboolean cmd_priority(ProfWin *window, gchar **args, struct cmd_help_t help); @@ -145,6 +146,7 @@ gboolean cmd_wrap(ProfWin *window, gchar **args, struct cmd_help_t help); gboolean cmd_time(ProfWin *window, gchar **args, struct cmd_help_t help); gboolean cmd_resource(ProfWin *window, gchar **args, struct cmd_help_t help); gboolean cmd_inpblock(ProfWin *window, gchar **args, struct cmd_help_t help); +gboolean cmd_encwarn(ProfWin *window, gchar **args, struct cmd_help_t help); gboolean cmd_form_field(ProfWin *window, char *tag, gchar **args); diff --git a/src/config/account.c b/src/config/account.c index 857d049b..de48ba02 100644 --- a/src/config/account.c +++ b/src/config/account.c @@ -51,7 +51,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)); @@ -144,6 +144,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; } @@ -210,6 +216,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 218f8ce7..22c29161 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); gboolean account_eval_password(ProfAccount *account); void account_free(ProfAccount *account); diff --git a/src/config/accounts.c b/src/config/accounts.c index d68f3a55..218e9d30 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/config/preferences.c b/src/config/preferences.c index 62e2522b..fef0db0b 100644 --- a/src/config/preferences.c +++ b/src/config/preferences.c @@ -55,6 +55,7 @@ #define PREF_GROUP_CONNECTION "connection" #define PREF_GROUP_ALIAS "alias" #define PREF_GROUP_OTR "otr" +#define PREF_GROUP_PGP "pgp" #define INPBLOCK_DEFAULT 1000 @@ -75,8 +76,6 @@ void prefs_load(void) { GError *err; - -// log_info("Loading preferences"); prefs_loc = _get_preferences_file(); if (g_file_test(prefs_loc, G_FILE_TEST_EXISTS)) { @@ -94,22 +93,12 @@ prefs_load(void) g_error_free(err); } - // move pre 0.4.6 OTR warn preferences to [ui] group + // move pre 0.4.7 otr.warn to enc.warn err = NULL; - gboolean otr_warn = g_key_file_get_boolean(prefs, PREF_GROUP_OTR, "warn", &err); + gboolean otr_warn = g_key_file_get_boolean(prefs, PREF_GROUP_UI, "otr.warn", &err); if (err == NULL) { - g_key_file_set_boolean(prefs, PREF_GROUP_UI, _get_key(PREF_OTR_WARN), otr_warn); - g_key_file_remove_key(prefs, PREF_GROUP_OTR, "warn", NULL); - } else { - g_error_free(err); - } - - // move pre 0.4.6 titlebar preference - err = NULL; - gchar *old_titlebar = g_key_file_get_string(prefs, PREF_GROUP_UI, "titlebar", &err); - if (err == NULL) { - g_key_file_set_string(prefs, PREF_GROUP_UI, _get_key(PREF_TITLEBAR_SHOW), old_titlebar); - g_key_file_remove_key(prefs, PREF_GROUP_UI, "titlebar", NULL); + g_key_file_set_boolean(prefs, PREF_GROUP_UI, _get_key(PREF_ENC_WARN), otr_warn); + g_key_file_remove_key(prefs, PREF_GROUP_UI, "otr.warn", NULL); } else { g_error_free(err); } @@ -510,7 +499,7 @@ _get_group(preference_t pref) case PREF_ROSTER_BY: case PREF_RESOURCE_TITLE: case PREF_RESOURCE_MESSAGE: - case PREF_OTR_WARN: + case PREF_ENC_WARN: case PREF_INPBLOCK_DYNAMIC: return PREF_GROUP_UI; case PREF_STATES: @@ -545,6 +534,8 @@ _get_group(preference_t pref) case PREF_OTR_LOG: case PREF_OTR_POLICY: return PREF_GROUP_OTR; + case PREF_PGP_LOG: + return PREF_GROUP_PGP; default: return NULL; } @@ -637,8 +628,6 @@ _get_key(preference_t pref) return "defaccount"; case PREF_OTR_LOG: return "log"; - case PREF_OTR_WARN: - return "otr.warn"; case PREF_OTR_POLICY: return "policy"; case PREF_LOG_ROTATE: @@ -669,6 +658,10 @@ _get_key(preference_t pref) return "resource.message"; case PREF_INPBLOCK_DYNAMIC: return "inpblock.dynamic"; + case PREF_ENC_WARN: + return "enc.warn"; + case PREF_PGP_LOG: + return "log"; default: return NULL; } @@ -681,7 +674,7 @@ _get_default_boolean(preference_t pref) { switch (pref) { - case PREF_OTR_WARN: + case PREF_ENC_WARN: case PREF_AUTOAWAY_CHECK: case PREF_LOG_ROTATE: case PREF_LOG_SHARED: @@ -735,6 +728,8 @@ _get_default_string(preference_t pref) return "seconds"; case PREF_TIME_STATUSBAR: return "minutes"; + case PREF_PGP_LOG: + return "redact"; default: return NULL; } diff --git a/src/config/preferences.h b/src/config/preferences.h index 273ce6bb..9e8d2898 100644 --- a/src/config/preferences.h +++ b/src/config/preferences.h @@ -98,11 +98,12 @@ typedef enum { PREF_LOG_ROTATE, PREF_LOG_SHARED, PREF_OTR_LOG, - PREF_OTR_WARN, PREF_OTR_POLICY, PREF_RESOURCE_TITLE, PREF_RESOURCE_MESSAGE, - PREF_INPBLOCK_DYNAMIC + PREF_INPBLOCK_DYNAMIC, + PREF_ENC_WARN, + PREF_PGP_LOG } preference_t; typedef struct prof_alias_t { diff --git a/src/config/theme.c b/src/config/theme.c index 640b7298..d870b371 100644 --- a/src/config/theme.c +++ b/src/config/theme.c @@ -463,7 +463,7 @@ _load_preferences(void) _set_boolean_preference("presence", PREF_PRESENCE); _set_boolean_preference("intype", PREF_INTYPE); - _set_boolean_preference("otr.warn", PREF_OTR_WARN); + _set_boolean_preference("enc.warn", PREF_ENC_WARN); } static gchar * diff --git a/src/event/client_events.c b/src/event/client_events.c index 54cc0247..1ddb3d22 100644 --- a/src/event/client_events.c +++ b/src/event/client_events.c @@ -43,6 +43,9 @@ #ifdef HAVE_LIBOTR #include "otr/otr.h" #endif +#ifdef HAVE_LIBGPGME +#include "pgp/gpg.h" +#endif jabber_conn_status_t cl_ev_connect_jid(const char * const jid, const char * const passwd, const char * const altdomain, const int port) @@ -64,7 +67,19 @@ cl_ev_connect_account(ProfAccount *account) void cl_ev_presence_send(const resource_presence_t presence_type, const char * const msg, const int idle) { - presence_send(presence_type, msg, idle); + char *signed_status = NULL; + +#ifdef HAVE_LIBGPGME + char *account_name = jabber_get_account_name(); + ProfAccount *account = accounts_get_account(account_name); + if (account->pgp_keyid) { + signed_status = p_gpg_sign(msg, account->pgp_keyid); + } +#endif + + presence_send(presence_type, msg, idle, signed_status); + + free(signed_status); } void @@ -72,13 +87,70 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char * const msg) { chat_state_active(chatwin->state); +// OTR suported, PGP supported +#ifdef HAVE_LIBOTR +#ifdef HAVE_LIBGPGME + prof_enc_t enc_mode = chatwin->enc_mode; + if (enc_mode == PROF_ENC_NONE || enc_mode == PROF_ENC_OTR) { + gboolean handled = otr_on_message_send(chatwin, msg); + if (!handled) { + char *id = message_send_chat(chatwin->barejid, msg); + chat_log_msg_out(chatwin->barejid, msg); + ui_outgoing_chat_msg(chatwin, msg, id); + free(id); + } + } else { // enc_mode = PROF_ENC_PGP + char *id = message_send_chat_pgp(chatwin->barejid, msg); + chat_log_pgp_msg_out(chatwin->barejid, msg); + ui_outgoing_chat_msg(chatwin, msg, id); + free(id); + } + return; +#endif +#endif + +// OTR supported, PGP unsupported #ifdef HAVE_LIBOTR - otr_on_message_send(chatwin, msg); -#else +#ifndef HAVE_LIBGPGME + gboolean handled = otr_on_message_send(chatwin, msg); + if (!handled) { + char *id = message_send_chat(chatwin->barejid, msg); + chat_log_msg_out(chatwin->barejid, msg); + ui_outgoing_chat_msg(chatwin, msg, id); + free(id); + } + return; +#endif +#endif + +// OTR unsupported, PGP supported +#ifndef HAVE_LIBOTR +#ifdef HAVE_LIBGPGME + prof_enc_t enc_mode = chatwin->enc_mode; + if (enc_mode == PROF_ENC_NONE) { + char *id = message_send_chat(chatwin->barejid, msg); + chat_log_msg_out(chatwin->barejid, msg); + ui_outgoing_chat_msg(chatwin, msg, id); + free(id); + } else if (enc_mode == PROF_ENC_PGP) { + char *id = message_send_chat_pgp(chatwin->barejid, msg); + chat_log_pgp_msg_out(chatwin->barejid, msg); + ui_outgoing_chat_msg(chatwin, msg, id); + free(id); + } + return; +#endif +#endif + +// OTR unsupported, PGP unsupported +#ifndef HAVE_LIBOTR +#ifndef HAVE_LIBGPGME char *id = message_send_chat(chatwin->barejid, msg); chat_log_msg_out(chatwin->barejid, msg); ui_outgoing_chat_msg(chatwin, msg, id); free(id); + return; +#endif #endif } diff --git a/src/event/server_events.c b/src/event/server_events.c index e2e910a3..004e743b 100644 --- a/src/event/server_events.c +++ b/src/event/server_events.c @@ -43,10 +43,14 @@ #include "config/preferences.h" #include "config/account.h" #include "roster_list.h" +#include "window_list.h" #ifdef HAVE_LIBOTR #include "otr/otr.h" #endif +#ifdef HAVE_LIBGPGME +#include "pgp/gpg.h" +#endif #include "ui/ui.h" @@ -160,19 +164,125 @@ sv_ev_incoming_private_message(const char * const fulljid, char *message) } void -sv_ev_carbon(char *barejid, char *message) +sv_ev_outgoing_carbon(char *barejid, char *message) { ui_outgoing_chat_msg_carbon(barejid, message); } void -sv_ev_incoming_message(char *barejid, char *resource, char *message) +sv_ev_incoming_carbon(char *barejid, char *resource, char *message) +{ + gboolean new_win = FALSE; + ProfChatWin *chatwin = wins_get_chat(barejid); + if (!chatwin) { + ProfWin *window = wins_new_chat(barejid); + chatwin = (ProfChatWin*)window; + new_win = TRUE; + } + + ui_incoming_msg(chatwin, resource, message, NULL, new_win); + chat_log_msg_in(barejid, message); +} + +void +sv_ev_incoming_message(char *barejid, char *resource, char *message, char *enc_message) { + gboolean new_win = FALSE; + ProfChatWin *chatwin = wins_get_chat(barejid); + if (!chatwin) { + ProfWin *window = wins_new_chat(barejid); + chatwin = (ProfChatWin*)window; + new_win = TRUE; + } + +// OTR suported, PGP supported +#ifdef HAVE_LIBOTR +#ifdef HAVE_LIBGPGME + prof_enc_t enc_mode = chatwin->enc_mode; + if (enc_message) { + if (enc_mode == PROF_ENC_OTR) { + win_println((ProfWin*)chatwin, "PGP encrypted message received whilst in OTR session."); + } else { // PROF_ENC_NONE, PROF_ENC_PGP + char *decrypted = p_gpg_decrypt(barejid, enc_message); + if (decrypted) { + if (enc_mode == PROF_ENC_NONE) { + win_println((ProfWin*)chatwin, "PGP encryption enabled."); + } + ui_incoming_msg(chatwin, resource, decrypted, NULL, new_win); + chat_log_pgp_msg_in(barejid, decrypted); + chatwin->enc_mode = PROF_ENC_PGP; + } else { + ui_incoming_msg(chatwin, resource, message, NULL, new_win); + chat_log_msg_in(barejid, message); + chatwin->enc_mode = PROF_ENC_NONE; + } + } + } else { + if (enc_mode == PROF_ENC_PGP) { + win_println((ProfWin*)chatwin, "PGP encryption disabled."); + ui_incoming_msg(chatwin, resource, message, NULL, new_win); + chat_log_msg_in(barejid, message); + chatwin->enc_mode = PROF_ENC_NONE; + } else { + gboolean decrypted = FALSE; + char *otr_res = otr_on_message_recv(barejid, resource, message, &decrypted); + if (otr_res) { + ui_incoming_msg(chatwin, resource, otr_res, NULL, new_win); + chat_log_otr_msg_in(barejid, otr_res, decrypted); + otr_free_message(otr_res); + } + } + } + return; +#endif +#endif + +// OTR supported, PGP unsupported #ifdef HAVE_LIBOTR - otr_on_message_recv(barejid, resource, message); -#else - ui_incoming_msg(barejid, resource, message, NULL); +#ifndef HAVE_LIBGPGME + gboolean decrypted = FALSE; + char *otr_res = otr_on_message_recv(barejid, resource, message, &decrypted); + if (otr_res) { + ui_incoming_msg(chatwin, resource, otr_res, NULL, new_win); + chat_log_otr_msg_in(barejid, otr_res, decrypted); + otr_free_message(otr_res); + } + return; +#endif +#endif + +// OTR unsupported, PGP supported +#ifndef HAVE_LIBOTR +#ifdef HAVE_LIBGPGME + prof_enc_t enc_mode = chatwin->enc_mode; + if (enc_message) { + char *decrypted = p_gpg_decrypt(jid->barejid, enc_message); + if (decrypted) { + ui_incoming_msg(chatwin, resource, decrypted, NULL, new_win); + chat_log_pgp_msg_in(barejid, decrypted); + chatwin->enc_mode = PROF_ENC_PGP; + } else { + ui_incoming_msg(chatwin, resource, message, NULL, new_win); + chat_log_msg_in(barejid, message); + chatwin->enc_mode = PROF_ENC_NONE; + } + } else { + ui_incoming_msg(chatwin, resource, message, NULL, new_win); + chat_log_msg_in(barejid, message); + chatwin->enc_mode = PROF_ENC_NONE; + } + return; +#endif +#endif + +// OTR unsupported, PGP unsupported +#ifndef HAVE_LIBOTR +#ifndef HAVE_LIBGPGME + ui_incoming_msg(chatwin, resource, message, NULL, new_win); chat_log_msg_in(barejid, message); + chatwin->enc_mode = PROF_ENC_NONE; + return; +#endif #endif } @@ -185,7 +295,15 @@ sv_ev_delayed_private_message(const char * const fulljid, char *message, GTimeVa void sv_ev_delayed_message(char *barejid, char *message, GTimeVal tv_stamp) { - ui_incoming_msg(barejid, NULL, message, &tv_stamp); + gboolean new_win = FALSE; + ProfChatWin *chatwin = wins_get_chat(barejid); + if (!chatwin) { + ProfWin *window = wins_new_chat(barejid); + chatwin = (ProfChatWin*)window; + new_win = TRUE; + } + + ui_incoming_msg(chatwin, NULL, message, &tv_stamp, new_win); chat_log_msg_in_delayed(barejid, message, &tv_stamp); } @@ -280,7 +398,7 @@ sv_ev_contact_offline(char *barejid, char *resource, char *status) } void -sv_ev_contact_online(char *barejid, Resource *resource, GDateTime *last_activity) +sv_ev_contact_online(char *barejid, Resource *resource, GDateTime *last_activity, char *pgpsig) { gboolean updated = roster_update_presence(barejid, resource, last_activity); @@ -288,6 +406,12 @@ sv_ev_contact_online(char *barejid, Resource *resource, GDateTime *last_activity ui_contact_online(barejid, resource, last_activity); } +#ifdef HAVE_LIBGPGME + if (pgpsig) { + p_gpg_verify(barejid, pgpsig); + } +#endif + rosterwin_roster(); chat_session_remove(barejid); } diff --git a/src/event/server_events.h b/src/event/server_events.h index 46d485da..51564d5c 100644 --- a/src/event/server_events.h +++ b/src/event/server_events.h @@ -50,7 +50,7 @@ void sv_ev_room_history(const char * const room_jid, const char * const nick, GTimeVal tv_stamp, const char * const message); void sv_ev_room_message(const char * const room_jid, const char * const nick, const char * const message); -void sv_ev_incoming_message(char *barejid, char *resource, char *message); +void sv_ev_incoming_message(char *barejid, char *resource, char *message, char *enc_message); void sv_ev_incoming_private_message(const char * const fulljid, char *message); void sv_ev_delayed_message(char *fulljid, char *message, GTimeVal tv_stamp); void sv_ev_delayed_private_message(const char * const fulljid, char *message, GTimeVal tv_stamp); @@ -62,8 +62,7 @@ void sv_ev_gone(const char * const barejid, const char * const resource); void sv_ev_subscription(const char *from, jabber_subscr_t type); void sv_ev_message_receipt(char *barejid, char *id); void sv_ev_contact_offline(char *contact, char *resource, char *status); -void sv_ev_contact_online(char *contact, Resource *resource, - GDateTime *last_activity); +void sv_ev_contact_online(char *contact, Resource *resource, GDateTime *last_activity, char *pgpkey); void sv_ev_leave_room(const char * const room); void sv_ev_room_destroy(const char * const room); void sv_ev_room_occupant_offline(const char * const room, const char * const nick, @@ -76,7 +75,8 @@ void sv_ev_room_occupent_kicked(const char * const room, const char * const nick void sv_ev_room_banned(const char * const room, const char * const actor, const char * const reason); void sv_ev_room_occupent_banned(const char * const room, const char * const nick, const char * const actor, const char * const reason); -void sv_ev_carbon(char *barejid, char *message); +void sv_ev_outgoing_carbon(char *barejid, char *message); +void sv_ev_incoming_carbon(char *barejid, char *resource, char *message); void sv_ev_xmpp_stanza(const char * const msg); void sv_ev_muc_self_online(const char * const room, const char * const nick, gboolean config_required, const char * const role, const char * const affiliation, const char * const actor, const char * const reason, diff --git a/src/log.c b/src/log.c index a7727e8b..941bea6f 100644 --- a/src/log.c +++ b/src/log.c @@ -280,6 +280,23 @@ chat_log_otr_msg_out(const char * const barejid, const char * const msg) } void +chat_log_pgp_msg_out(const char * const barejid, const char * const msg) +{ + if (prefs_get_boolean(PREF_CHLOG)) { + const char *jid = jabber_get_fulljid(); + Jid *jidp = jid_create(jid); + char *pref_pgp_log = prefs_get_string(PREF_PGP_LOG); + if (strcmp(pref_pgp_log, "on") == 0) { + _chat_log_chat(jidp->barejid, barejid, msg, PROF_OUT_LOG, NULL); + } else if (strcmp(pref_pgp_log, "redact") == 0) { + _chat_log_chat(jidp->barejid, barejid, "[redacted]", PROF_OUT_LOG, NULL); + } + prefs_free_string(pref_pgp_log); + jid_destroy(jidp); + } +} + +void chat_log_otr_msg_in(const char * const barejid, const char * const msg, gboolean was_decrypted) { if (prefs_get_boolean(PREF_CHLOG)) { @@ -297,6 +314,23 @@ chat_log_otr_msg_in(const char * const barejid, const char * const msg, gboolean } void +chat_log_pgp_msg_in(const char * const barejid, const char * const msg) +{ + if (prefs_get_boolean(PREF_CHLOG)) { + const char *jid = jabber_get_fulljid(); + Jid *jidp = jid_create(jid); + char *pref_pgp_log = prefs_get_string(PREF_PGP_LOG); + if (strcmp(pref_pgp_log, "on") == 0) { + _chat_log_chat(jidp->barejid, barejid, msg, PROF_IN_LOG, NULL); + } else if (strcmp(pref_pgp_log, "redact") == 0) { + _chat_log_chat(jidp->barejid, barejid, "[redacted]", PROF_IN_LOG, NULL); + } + prefs_free_string(pref_pgp_log); + jid_destroy(jidp); + } +} + +void chat_log_msg_in(const char * const barejid, const char * const msg) { if (prefs_get_boolean(PREF_CHLOG)) { diff --git a/src/log.h b/src/log.h index 0689e2e6..3c98c3bd 100644 --- a/src/log.h +++ b/src/log.h @@ -67,10 +67,12 @@ void chat_log_init(void); void chat_log_msg_out(const char * const barejid, const char * const msg); void chat_log_otr_msg_out(const char * const barejid, const char * const msg); +void chat_log_pgp_msg_out(const char * const barejid, const char * const msg); void chat_log_msg_in(const char * const barejid, const char * const msg); void chat_log_msg_in_delayed(const char * const barejid, const char * msg, GTimeVal *tv_stamp); void chat_log_otr_msg_in(const char * const barejid, const char * const msg, gboolean was_decrypted); +void chat_log_pgp_msg_in(const char * const barejid, const char * const msg); void chat_log_close(void); GSList * chat_log_get_previous(const gchar * const login, 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/otr/otr.c b/src/otr/otr.c index 1f63c8f9..e61a0e47 100644 --- a/src/otr/otr.c +++ b/src/otr/otr.c @@ -110,7 +110,7 @@ static void cb_inject_message(void *opdata, const char *accountname, const char *protocol, const char *recipient, const char *message) { - message_send_chat_encrypted(recipient, message); + message_send_chat_otr(recipient, message); } static void @@ -272,12 +272,9 @@ otr_on_connect(ProfAccount *account) return; } -void -otr_on_message_recv(const char * const barejid, const char * const resource, const char * const message) +char* +otr_on_message_recv(const char * const barejid, const char * const resource, const char * const message, gboolean *was_decrypted) { - gboolean was_decrypted = FALSE; - char *decrypted; - prof_otrpolicy_t policy = otr_get_policy(barejid); char *whitespace_base = strstr(message, OTRL_MESSAGE_TAG_BASE); @@ -294,65 +291,65 @@ otr_on_message_recv(const char * const barejid, const char * const resource, con memmove(whitespace_base, whitespace_base+tag_length, tag_length); char *otr_query_message = otr_start_query(); cons_show("OTR Whitespace pattern detected. Attempting to start OTR session..."); - message_send_chat_encrypted(barejid, otr_query_message); + message_send_chat_otr(barejid, otr_query_message); } } } - decrypted = otr_decrypt_message(barejid, message, &was_decrypted); - // internal OTR message - if (decrypted == NULL) { - return; + char *decrypted = otr_decrypt_message(barejid, message, was_decrypted); + if (!decrypted) { // internal OTR message + return NULL; } - if (policy == PROF_OTRPOLICY_ALWAYS && !was_decrypted && !whitespace_base) { + if (policy == PROF_OTRPOLICY_ALWAYS && *was_decrypted == FALSE && !whitespace_base) { char *otr_query_message = otr_start_query(); cons_show("Attempting to start OTR session..."); - message_send_chat_encrypted(barejid, otr_query_message); + message_send_chat_otr(barejid, otr_query_message); } - ui_incoming_msg(barejid, resource, decrypted, NULL); - chat_log_otr_msg_in(barejid, decrypted, was_decrypted); - otr_free_message(decrypted); + return decrypted; } -void +gboolean otr_on_message_send(ProfChatWin *chatwin, const char * const message) { char *id = NULL; - prof_otrpolicy_t policy = otr_get_policy(chatwin->barejid); + // Send encrypted message if (otr_is_secure(chatwin->barejid)) { char *encrypted = otr_encrypt_message(chatwin->barejid, message); if (encrypted) { - id = message_send_chat_encrypted(chatwin->barejid, encrypted); + id = message_send_chat_otr(chatwin->barejid, encrypted); chat_log_otr_msg_out(chatwin->barejid, message); ui_outgoing_chat_msg(chatwin, message, id); otr_free_message(encrypted); + free(id); + return TRUE; } else { ui_win_error_line((ProfWin*)chatwin, "Failed to encrypt and send message."); - return; + return TRUE; } + } - } else if (policy == PROF_OTRPOLICY_ALWAYS) { + // show error if not secure and policy always + if (policy == PROF_OTRPOLICY_ALWAYS) { ui_win_error_line((ProfWin*)chatwin, "Failed to send message. OTR policy set to: always"); - return; + return TRUE; + } - } else if (policy == PROF_OTRPOLICY_OPPORTUNISTIC) { + // tag and send for policy opportunistic + if (policy == PROF_OTRPOLICY_OPPORTUNISTIC) { char *otr_tagged_msg = otr_tag_message(message); - id = message_send_chat_encrypted(chatwin->barejid, otr_tagged_msg); + id = message_send_chat_otr(chatwin->barejid, otr_tagged_msg); ui_outgoing_chat_msg(chatwin, message, id); chat_log_msg_out(chatwin->barejid, message); free(otr_tagged_msg); - - } else { - id = message_send_chat(chatwin->barejid, message); - ui_outgoing_chat_msg(chatwin, message, id); - chat_log_msg_out(chatwin->barejid, message); + free(id); + return TRUE; } - free(id); + return FALSE; } void diff --git a/src/otr/otr.h b/src/otr/otr.h index 3c46ac3d..45abdc20 100644 --- a/src/otr/otr.h +++ b/src/otr/otr.h @@ -58,8 +58,8 @@ char* otr_start_query(void); void otr_poll(void); void otr_on_connect(ProfAccount *account); -void otr_on_message_recv(const char * const barejid, const char * const resource, const char * const message); -void otr_on_message_send(ProfChatWin *chatwin, const char * const message); +char* otr_on_message_recv(const char * const barejid, const char * const resource, const char * const message, gboolean *was_decrypted); +gboolean otr_on_message_send(ProfChatWin *chatwin, const char * const message); void otr_keygen(ProfAccount *account); diff --git a/src/pgp/gpg.c b/src/pgp/gpg.c new file mode 100644 index 00000000..ce40690f --- /dev/null +++ b/src/pgp/gpg.c @@ -0,0 +1,380 @@ +/* + * 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)); + + 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); + } +} + +gboolean +p_gpg_available(const char * const barejid) +{ + char *fp = g_hash_table_lookup(fingerprints, barejid); + return (fp != NULL); +} + +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) { + 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..74d86568 --- /dev/null +++ b/src/pgp/gpg.h @@ -0,0 +1,56 @@ +/* + * 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); +gboolean p_gpg_available(const char * const barejid); +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 0e11a933..569c875e 100644 --- a/src/profanity.c +++ b/src/profanity.c @@ -60,6 +60,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" @@ -246,6 +249,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); } @@ -270,6 +276,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 7e071bd9..ac18c7da 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); @@ -881,6 +885,16 @@ cons_winstidy_setting(void) } void +cons_encwarn_setting(void) +{ + if (prefs_get_boolean(PREF_ENC_WARN)) { + cons_show("Warn unencrypted (/encwarn) : ON"); + } else { + cons_show("Warn unencrypted (/encwarn) : OFF"); + } +} + +void cons_presence_setting(void) { if (prefs_get_boolean(PREF_PRESENCE)) @@ -1054,6 +1068,7 @@ cons_show_ui_prefs(void) cons_roster_setting(); cons_privileges_setting(); cons_titlebar_setting(); + cons_encwarn_setting(); cons_presence_setting(); cons_inpblock_setting(); @@ -1394,12 +1409,6 @@ cons_show_otr_prefs(void) cons_show("OTR policy (/otr policy) : %s", policy_value); prefs_free_string(policy_value); - if (prefs_get_boolean(PREF_OTR_WARN)) { - cons_show("Warn non-OTR (/otr warn) : ON"); - } else { - cons_show("Warn non-OTR (/otr warn) : OFF"); - } - char *log_value = prefs_get_string(PREF_OTR_LOG); if (strcmp(log_value, "on") == 0) { cons_show("OTR logging (/otr log) : ON"); diff --git a/src/ui/core.c b/src/ui/core.c index 10c5d347..ec5ae9af 100644 --- a/src/ui/core.c +++ b/src/ui/core.c @@ -416,21 +416,12 @@ ui_message_receipt(const char * const barejid, const char * const id) } void -ui_incoming_msg(const char * const barejid, const char * const resource, const char * const message, GTimeVal *tv_stamp) +ui_incoming_msg(ProfChatWin *chatwin, const char * const resource, const char * const message, GTimeVal *tv_stamp, gboolean win_created) { - gboolean win_created = FALSE; - - ProfChatWin *chatwin = wins_get_chat(barejid); - if (chatwin == NULL) { - ProfWin *window = wins_new_chat(barejid); - chatwin = (ProfChatWin*)window; - win_created = TRUE; - } - - ProfWin *window = (ProfWin*) chatwin; + ProfWin *window = (ProfWin*)chatwin; int num = wins_get_num(window); - char *display_name = roster_get_msg_display_name(barejid, resource); + char *display_name = roster_get_msg_display_name(chatwin->barejid, resource); // currently viewing chat window with sender if (wins_is_current(window)) { @@ -449,12 +440,12 @@ ui_incoming_msg(const char * const barejid, const char * const resource, const c chatwin->unread++; if (prefs_get_boolean(PREF_CHLOG) && prefs_get_boolean(PREF_HISTORY)) { - _win_show_history(chatwin, barejid); + _win_show_history(chatwin, chatwin->barejid); } // show users status first, when receiving message via delayed delivery - if (tv_stamp && (win_created)) { - PContact pcontact = roster_get_contact(barejid); + if (tv_stamp && win_created) { + PContact pcontact = roster_get_contact(chatwin->barejid); if (pcontact) { win_show_contact(window, pcontact); } @@ -1277,12 +1268,6 @@ ui_new_chat_win(const char * const barejid) ProfWin *window = wins_new_chat(barejid); ProfChatWin *chatwin = (ProfChatWin *)window; -#ifdef HAVE_LIBOTR - if (otr_is_secure(barejid)) { - chatwin->enc_mode = PROF_ENC_OTR; - } -#endif - if (prefs_get_boolean(PREF_CHLOG) && prefs_get_boolean(PREF_HISTORY)) { _win_show_history(chatwin, barejid); } diff --git a/src/ui/titlebar.c b/src/ui/titlebar.c index 746d2782..16a9eaff 100644 --- a/src/ui/titlebar.c +++ b/src/ui/titlebar.c @@ -58,9 +58,7 @@ static GTimer *typing_elapsed; static void _title_bar_draw(void); static void _show_self_presence(void); static void _show_contact_presence(ProfChatWin *chatwin); -#ifdef HAVE_LIBOTR static void _show_privacy(ProfChatWin *chatwin); -#endif void create_title_bar(void) @@ -174,10 +172,7 @@ _title_bar_draw(void) ProfChatWin *chatwin = (ProfChatWin*) current; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); _show_contact_presence(chatwin); - -#ifdef HAVE_LIBOTR _show_privacy(chatwin); -#endif if (typing) { wprintw(win, " (typing...)"); @@ -246,66 +241,81 @@ _show_self_presence(void) wattroff(win, bracket_attrs); } -#ifdef HAVE_LIBOTR static void _show_privacy(ProfChatWin *chatwin) { int bracket_attrs = theme_attrs(THEME_TITLE_BRACKET); + int encrypted_attrs = theme_attrs(THEME_TITLE_ENCRYPTED); + int unencrypted_attrs = theme_attrs(THEME_TITLE_UNENCRYPTED); + int trusted_attrs = theme_attrs(THEME_TITLE_TRUSTED); + int untrusted_attrs = theme_attrs(THEME_TITLE_UNTRUSTED); + + switch (chatwin->enc_mode) { + case PROF_ENC_NONE: + if (prefs_get_boolean(PREF_ENC_WARN)) { + wprintw(win, " "); + wattron(win, bracket_attrs); + wprintw(win, "["); + wattroff(win, bracket_attrs); + wattron(win, unencrypted_attrs); + wprintw(win, "unencrypted"); + wattroff(win, unencrypted_attrs); + wattron(win, bracket_attrs); + wprintw(win, "]"); + wattroff(win, bracket_attrs); + } + break; - if (chatwin->enc_mode == PROF_ENC_NONE) { - if (prefs_get_boolean(PREF_OTR_WARN)) { - int unencrypted_attrs = theme_attrs(THEME_TITLE_UNENCRYPTED); + case PROF_ENC_OTR: wprintw(win, " "); wattron(win, bracket_attrs); wprintw(win, "["); wattroff(win, bracket_attrs); - wattron(win, unencrypted_attrs); - wprintw(win, "unencrypted"); - wattroff(win, unencrypted_attrs); + wattron(win, encrypted_attrs); + wprintw(win, "OTR"); + wattroff(win, encrypted_attrs); wattron(win, bracket_attrs); wprintw(win, "]"); wattroff(win, bracket_attrs); - } - } else { - int encrypted_attrs = theme_attrs(THEME_TITLE_ENCRYPTED); - wprintw(win, " "); - wattron(win, bracket_attrs); - wprintw(win, "["); - wattroff(win, bracket_attrs); - wattron(win, encrypted_attrs); - wprintw(win, "OTR"); - wattroff(win, encrypted_attrs); - wattron(win, bracket_attrs); - wprintw(win, "]"); - wattroff(win, bracket_attrs); - if (chatwin->otr_is_trusted) { - int trusted_attrs = theme_attrs(THEME_TITLE_TRUSTED); - wprintw(win, " "); - wattron(win, bracket_attrs); - wprintw(win, "["); - wattroff(win, bracket_attrs); - wattron(win, trusted_attrs); - wprintw(win, "trusted"); - wattroff(win, trusted_attrs); - wattron(win, bracket_attrs); - wprintw(win, "]"); - wattroff(win, bracket_attrs); - } else { - int untrusted_attrs = theme_attrs(THEME_TITLE_UNTRUSTED); + if (chatwin->otr_is_trusted) { + wprintw(win, " "); + wattron(win, bracket_attrs); + wprintw(win, "["); + wattroff(win, bracket_attrs); + wattron(win, trusted_attrs); + wprintw(win, "trusted"); + wattroff(win, trusted_attrs); + wattron(win, bracket_attrs); + wprintw(win, "]"); + wattroff(win, bracket_attrs); + } else { + wprintw(win, " "); + wattron(win, bracket_attrs); + wprintw(win, "["); + wattroff(win, bracket_attrs); + wattron(win, untrusted_attrs); + wprintw(win, "untrusted"); + wattroff(win, untrusted_attrs); + wattron(win, bracket_attrs); + wprintw(win, "]"); + wattroff(win, bracket_attrs); + } + break; + + case PROF_ENC_PGP: wprintw(win, " "); wattron(win, bracket_attrs); wprintw(win, "["); wattroff(win, bracket_attrs); - wattron(win, untrusted_attrs); - wprintw(win, "untrusted"); - wattroff(win, untrusted_attrs); + wattron(win, encrypted_attrs); + wprintw(win, "PGP"); + wattroff(win, encrypted_attrs); wattron(win, bracket_attrs); wprintw(win, "]"); wattroff(win, bracket_attrs); - } + break; } } -#endif static void _show_contact_presence(ProfChatWin *chatwin) diff --git a/src/ui/ui.h b/src/ui/ui.h index 396bae1c..b5bfb482 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -101,7 +101,7 @@ void ui_handle_stanza(const char * const msg); // ui events void ui_contact_online(char *barejid, Resource *resource, GDateTime *last_activity); void ui_contact_typing(const char * const barejid, const char * const resource); -void ui_incoming_msg(const char * const from, const char * const resource, const char * const message, GTimeVal *tv_stamp); +void ui_incoming_msg(ProfChatWin *chatwin, const char * const resource, const char * const message, GTimeVal *tv_stamp, gboolean win_created); void ui_incoming_private_msg(const char * const fulljid, const char * const message, GTimeVal *tv_stamp); void ui_message_receipt(const char * const barejid, const char * const id); @@ -288,6 +288,7 @@ void cons_privileges_setting(void); void cons_beep_setting(void); void cons_flash_setting(void); void cons_splash_setting(void); +void cons_encwarn_setting(void); void cons_vercheck_setting(void); void cons_occupants_setting(void); void cons_roster_setting(void); diff --git a/src/ui/win_types.h b/src/ui/win_types.h index 7e757b88..3214fa94 100644 --- a/src/ui/win_types.h +++ b/src/ui/win_types.h @@ -91,7 +91,8 @@ typedef enum { typedef enum { PROF_ENC_NONE, - PROF_ENC_OTR + PROF_ENC_OTR, + PROF_ENC_PGP } prof_enc_t; typedef struct prof_win_t { diff --git a/src/xmpp/message.c b/src/xmpp/message.c index bc702199..4cc440ea 100644 --- a/src/xmpp/message.c +++ b/src/xmpp/message.c @@ -50,6 +50,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) @@ -76,37 +77,57 @@ message_add_handlers(void) HANDLE(STANZA_NS_RECEIPTS, NULL, _receipt_received_handler); } -char * -message_send_chat(const char * const barejid, const char * const msg) +static char* +_session_jid(const char * const barejid) { - xmpp_conn_t * const conn = connection_get_conn(); - xmpp_ctx_t * const ctx = connection_get_ctx(); - ChatSession *session = chat_session_get(barejid); - char *state = NULL; char *jid = NULL; if (session) { - if (prefs_get_boolean(PREF_STATES) && session->send_states) { - state = STANZA_NAME_ACTIVE; - } Jid *jidp = jid_create_from_bare_and_resource(session->barejid, session->resource); jid = strdup(jidp->fulljid); jid_destroy(jidp); + } else { + jid = strdup(barejid); + } + return jid; +} + +static char* +_session_state(const char * const barejid) +{ + ChatSession *session = chat_session_get(barejid); + char *state = NULL; + if (session) { + if (prefs_get_boolean(PREF_STATES) && session->send_states) { + state = STANZA_NAME_ACTIVE; + } } else { if (prefs_get_boolean(PREF_STATES)) { state = STANZA_NAME_ACTIVE; } - jid = strdup(barejid); } + return state; +} + +char * +message_send_chat(const char * const barejid, const char * const msg) +{ + xmpp_conn_t * const conn = connection_get_conn(); + xmpp_ctx_t * const ctx = connection_get_ctx(); + + char *state = _session_state(barejid); + char *jid = _session_jid(barejid); char *id = create_unique_id("msg"); + xmpp_stanza_t *message = stanza_create_message(ctx, id, jid, STANZA_TYPE_CHAT, msg); free(jid); if (state) { stanza_attach_state(ctx, message, state); } + if (prefs_get_boolean(PREF_RECEIPTS_REQUEST)) { stanza_attach_receipt_request(ctx, message); } @@ -118,36 +139,80 @@ message_send_chat(const char * const barejid, const char * const msg) } char * -message_send_chat_encrypted(const char * const barejid, const char * const msg) +message_send_chat_pgp(const char * const barejid, const char * const msg) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); - ChatSession *session = chat_session_get(barejid); - char *state = NULL; - char *jid = NULL; - if (session) { - if (prefs_get_boolean(PREF_STATES) && session->send_states) { - state = STANZA_NAME_ACTIVE; + char *state = _session_state(barejid); + char *jid = _session_jid(barejid); + char *id = create_unique_id("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); } - Jid *jidp = jid_create_from_bare_and_resource(session->barejid, session->resource); - jid = strdup(jidp->fulljid); - jid_destroy(jidp); } else { - if (prefs_get_boolean(PREF_STATES)) { - state = STANZA_NAME_ACTIVE; - } - jid = strdup(barejid); + 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) { + stanza_attach_state(ctx, message, state); + } + + stanza_attach_carbons_private(ctx, message); + + if (prefs_get_boolean(PREF_RECEIPTS_REQUEST)) { + stanza_attach_receipt_request(ctx, message); + } + + xmpp_send(conn, message); + xmpp_stanza_release(message); + + return id; +} + +char * +message_send_chat_otr(const char * const barejid, const char * const msg) +{ + xmpp_conn_t * const conn = connection_get_conn(); + xmpp_ctx_t * const ctx = connection_get_ctx(); + + char *state = _session_state(barejid); + char *jid = _session_jid(barejid); char *id = create_unique_id("msg"); + xmpp_stanza_t *message = stanza_create_message(ctx, id, barejid, STANZA_TYPE_CHAT, msg); free(jid); if (state) { stanza_attach_state(ctx, message, state); } + stanza_attach_carbons_private(ctx, message); + if (prefs_get_boolean(PREF_RECEIPTS_REQUEST)) { stanza_attach_receipt_request(ctx, message); } @@ -640,11 +705,11 @@ _handle_carbons(xmpp_stanza_t * const stanza) if (message) { // if we are the recipient, treat as standard incoming message if(g_strcmp0(my_jid->barejid, jid_to->barejid) == 0){ - sv_ev_incoming_message(jid_from->barejid, jid_from->resourcepart, message); + sv_ev_incoming_carbon(jid_from->barejid, jid_from->resourcepart, message); } // else treat as a sent message else{ - sv_ev_carbon(jid_to->barejid, message); + sv_ev_outgoing_carbon(jid_to->barejid, message); } xmpp_free(ctx, message); } @@ -703,7 +768,12 @@ _chat_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * con if (delayed) { sv_ev_delayed_message(jid->barejid, message, tv_stamp); } else { - sv_ev_incoming_message(jid->barejid, jid->resourcepart, message); + char *enc_message = NULL; + xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_ENCRYPTED); + if (x) { + enc_message = xmpp_stanza_get_text(x); + } + sv_ev_incoming_message(jid->barejid, jid->resourcepart, message, enc_message); } _receipt_request_handler(stanza); diff --git a/src/xmpp/presence.c b/src/xmpp/presence.c index e46730e3..4cf648dc 100644 --- a/src/xmpp/presence.c +++ b/src/xmpp/presence.c @@ -193,7 +193,7 @@ presence_reset_sub_request_search(void) } void -presence_send(const resource_presence_t presence_type, const char * const msg, const int idle) +presence_send(const resource_presence_t presence_type, const char * const msg, const int idle, char *signed_status) { if (jabber_get_connection_status() != JABBER_CONNECTED) { log_warning("Error setting presence, not connected."); @@ -218,7 +218,21 @@ presence_send(const resource_presence_t presence_type, const char * const msg, c char *id = create_unique_id("presence"); xmpp_stanza_set_id(presence, id); stanza_attach_show(ctx, presence, show); + stanza_attach_status(ctx, presence, msg); + + 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); + } + stanza_attach_priority(ctx, presence, pri); stanza_attach_last_activity(ctx, presence, idle); stanza_attach_caps(ctx, presence); @@ -603,7 +617,14 @@ _available_handler(xmpp_conn_t * const conn, if (g_strcmp0(xmpp_presence->jid->barejid, my_jid->barejid) == 0) { connection_add_available_resource(resource); } else { - sv_ev_contact_online(xmpp_presence->jid->barejid, resource, xmpp_presence->last_activity); + char *pgpsig = NULL; + xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_SIGNED); + if (x) { + pgpsig = xmpp_stanza_get_text(x); + } + sv_ev_contact_online(xmpp_presence->jid->barejid, resource, xmpp_presence->last_activity, pgpsig); + xmpp_ctx_t *ctx = connection_get_ctx(); + xmpp_free(ctx, pgpsig); } jid_destroy(my_jid); @@ -783,4 +804,4 @@ _muc_user_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * jid_destroy(from_jid); return 1; -} \ No newline at end of file +} 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/src/xmpp/xmpp.h b/src/xmpp/xmpp.h index 6b985b08..575f9ae1 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -146,7 +146,8 @@ GList * jabber_get_available_resources(void); // message functions char* message_send_chat(const char * const barejid, const char * const msg); -char* message_send_chat_encrypted(const char * const barejid, const char * const msg); +char* message_send_chat_otr(const char * const barejid, const char * const msg); +char* message_send_chat_pgp(const char * const barejid, const char * const msg); void message_send_private(const char * const fulljid, const char * const msg); void message_send_groupchat(const char * const roomjid, const char * const msg); void message_send_groupchat_subject(const char * const roomjid, const char * const subject); @@ -168,8 +169,7 @@ char * presence_sub_request_find(const char * const search_str); void presence_join_room(char *room, char *nick, char * passwd); void presence_change_room_nick(const char * const room, const char * const nick); void presence_leave_chat_room(const char * const room_jid); -void presence_send(resource_presence_t status, const char * const msg, - int idle); +void presence_send(resource_presence_t status, const char * const msg, int idle, char *signed_status); gboolean presence_sub_request_exists(const char * const bare_jid); // iq functions |