diff --git a/src/command/command.c b/src/command/command.c index 23d5bae4..82e53c05 100644 --- a/src/command/command.c +++ b/src/command/command.c @@ -594,9 +594,9 @@ static struct cmd_t command_defs[] = { "/otr", cmd_otr, parse_args, 1, 2, NULL, - { "/otr gen|myfp|theirfp|start|end|trust|untrust|log|warn|libver", "Off The Record encryption commands.", - { "/otr gen|myfp|theirfp|start|end|trust|untrust|log|warn|libver", - "-------------------------------------------------------------", + { "/otr gen|myfp|theirfp|start|end|trust|untrust|log|warn|libver|policy", "Off The Record encryption commands.", + { "/otr gen|myfp|theirfp|start|end|trust|untrust|log|warn|libver|policy", + "--------------------------------------------------------------------", "gen - Generate your private key.", "myfp - Show your fingerprint.", "theirfp - Show contacts fingerprint.", @@ -607,6 +607,7 @@ static struct cmd_t command_defs[] = "log - How to log OTR messages, options are 'on', 'off' and 'redact', with redaction being the default.", "warn - Show when unencrypted messaging is being used in the title bar, options are 'on' and 'off' with 'on' being the default.", "libver - Show which version of the libotr library is being used.", + "policy - manual, opportunistic or always.", NULL } } }, { "/outtype", @@ -1327,6 +1328,10 @@ cmd_execute_default(const char * const inp) ui_current_print_line("You are not currently connected."); } else { #ifdef HAVE_LIBOTR + if ((strcmp(prefs_get_string(PREF_OTR_POLICY), "always") == 0) && !otr_is_secure(recipient)) { + cons_show_error("Failed to send message. Please check OTR policy"); + return TRUE; + } if (otr_is_secure(recipient)) { char *encrypted = otr_encrypt_message(recipient, inp); if (encrypted != NULL) { diff --git a/src/command/commands.c b/src/command/commands.c index 0a96d318..c0729630 100644 --- a/src/command/commands.c +++ b/src/command/commands.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "chat_session.h" #include "command/commands.h" @@ -967,7 +968,24 @@ cmd_msg(gchar **args, struct cmd_help_t help) cons_show_error("Failed to encrypt and send message,"); } } else { - message_send(msg, usr_jid); + char *policy = prefs_get_string(PREF_OTR_POLICY); + + if (strcmp(policy, "always") == 0) { + cons_show_error("Failed to send message. Please check OTR policy"); + return TRUE; + } else if (strcmp(policy, "opportunistic") == 0) { + char *otr_base_tag = OTRL_MESSAGE_TAG_BASE; + char *otr_v2_tag = OTRL_MESSAGE_TAG_V2; + int N = strlen(otr_base_tag) + strlen(otr_v2_tag) + strlen(msg) + 1; + char *temp = (char *) malloc( (unsigned) N*sizeof(char *) ); + strcpy( temp , msg ); + strcat( temp , otr_base_tag); + strcat( temp, otr_v2_tag); + message_send(temp, usr_jid); + free(temp); + } else { + message_send(msg, usr_jid); + } ui_outgoing_msg("me", usr_jid, msg); if (((win_type == WIN_CHAT) || (win_type == WIN_CONSOLE)) && prefs_get_boolean(PREF_CHLOG)) { @@ -2610,6 +2628,27 @@ cmd_otr(gchar **args, struct cmd_help_t help) char *version = otr_libotr_version(); cons_show("Using libotr version %s", version); return TRUE; + } else if (strcmp(args[0], "policy") == 0) { + if (args[1] == NULL) { + char *policy = prefs_get_string(PREF_OTR_POLICY); + cons_show("OTR policy is now set to: %s", policy); + return TRUE; + } + + char *choice = args[1]; + if (g_strcmp0(choice, "manual") == 0) { + prefs_set_string(PREF_OTR_POLICY, "manual"); + cons_show("OTR policy is now set to: manual"); + } else if (g_strcmp0(choice, "opportunistic") == 0) { + prefs_set_string(PREF_OTR_POLICY, "opportunistic"); + cons_show("OTR policy is now set to: opportunistic"); + } else if (g_strcmp0(choice, "always") == 0) { + prefs_set_string(PREF_OTR_POLICY, "always"); + cons_show("OTR policy is now set to: always"); + } else { + cons_show("OTR policy can be set to: manual, opportunistic or always."); + } + return TRUE; } if (jabber_get_connection_status() != JABBER_CONNECTED) { diff --git a/src/config/preferences.c b/src/config/preferences.c index 9cc91cb6..2d6aee79 100644 --- a/src/config/preferences.c +++ b/src/config/preferences.c @@ -45,6 +45,7 @@ #define PREF_GROUP_PRESENCE "presence" #define PREF_GROUP_CONNECTION "connection" #define PREF_GROUP_ALIAS "alias" +#define PREF_GROUP_OTR_POLICY "policy" static gchar *prefs_loc; static GKeyFile *prefs; @@ -396,6 +397,8 @@ _get_group(preference_t pref) case PREF_LOG_ROTATE: case PREF_LOG_SHARED: return PREF_GROUP_LOGGING; + case PREF_OTR_POLICY: + return PREF_GROUP_OTR_POLICY; case PREF_AUTOAWAY_CHECK: case PREF_AUTOAWAY_MODE: case PREF_AUTOAWAY_MESSAGE: @@ -466,6 +469,8 @@ _get_key(preference_t pref) return "otr"; case PREF_OTR_WARN: return "otr.warn"; + case PREF_OTR_POLICY: + return "otr.policy"; case PREF_LOG_ROTATE: return "rotate"; case PREF_LOG_SHARED: @@ -500,6 +505,8 @@ _get_default_string(preference_t pref) return "off"; case PREF_OTR_LOG: return "redact"; + case PREF_OTR_POLICY: + return "manual"; case PREF_STATUSES_CONSOLE: case PREF_STATUSES_CHAT: case PREF_STATUSES_MUC: @@ -507,4 +514,4 @@ _get_default_string(preference_t pref) default: return NULL; } -} +} \ No newline at end of file diff --git a/src/config/preferences.h b/src/config/preferences.h index 310b9032..48748883 100644 --- a/src/config/preferences.h +++ b/src/config/preferences.h @@ -64,7 +64,8 @@ typedef enum { PREF_OTR_LOG, PREF_OTR_WARN, PREF_LOG_ROTATE, - PREF_LOG_SHARED + PREF_LOG_SHARED, + PREF_OTR_POLICY } preference_t; typedef struct prof_alias_t { diff --git a/src/otr/otrlibv3.c b/src/otr/otrlibv3.c index 633d07b8..d1495c9a 100644 --- a/src/otr/otrlibv3.c +++ b/src/otr/otrlibv3.c @@ -34,7 +34,7 @@ otrlib_policy(void) char * otrlib_start_query(void) { - return "?OTR?v2?"; + return "?OTR?v2? This user has requested an Off-the-Record private conversation. However, you do not have a plugin to support that. See http://otr.cypherpunks.ca/ for more information."; } static int diff --git a/src/otr/otrlibv4.c b/src/otr/otrlibv4.c index 01afa868..c55d2972 100644 --- a/src/otr/otrlibv4.c +++ b/src/otr/otrlibv4.c @@ -35,7 +35,7 @@ otrlib_policy(void) char * otrlib_start_query(void) { - return "?OTR?v2?"; + return "?OTR?v2? This user has requested an Off-the-Record private conversation. However, you do not have a plugin to support that. See http://otr.cypherpunks.ca/ for more information."; } static const char* diff --git a/src/server_events.c b/src/server_events.c index 79cc0e26..bd63de82 100644 --- a/src/server_events.c +++ b/src/server_events.c @@ -32,6 +32,7 @@ #ifdef HAVE_LIBOTR #include "otr/otr.h" +#include #endif #include "ui/ui.h" @@ -206,7 +207,28 @@ handle_incoming_message(char *from, char *message, gboolean priv) #ifdef HAVE_LIBOTR gboolean was_decrypted = FALSE; char *newmessage; - if (!priv) { + + if (!priv) { + //check for OTR whitespace (opportunistic or always) + char *policy = prefs_get_string(PREF_OTR_POLICY); + if (strcmp(policy, "opportunistic") == 0 || strcmp(policy, "always") == 0) { + char *whitespace_base = strstr(message,OTRL_MESSAGE_TAG_BASE); + if (whitespace_base) { + if (strstr(message, OTRL_MESSAGE_TAG_V2) || strstr(message, OTRL_MESSAGE_TAG_V1)) { + // Remove whitespace pattern for proper display in UI + // Handle both BASE+TAGV1/2(16+8) and BASE+TAGV1+TAGV2(16+8+8) + int tag_length = 24; + if (strstr(message, OTRL_MESSAGE_TAG_V2) && strstr(message, OTRL_MESSAGE_TAG_V1)) { + tag_length = 32; + } + memmove(whitespace_base, whitespace_base+tag_length, tag_length); + log_debug("<%s>", message); + char *otr_query_message = otr_start_query(); + cons_show("OTR Whitespace pattern detected. Attempting to start OTR session..."); + message_send(otr_query_message, from); + } + } + } newmessage = otr_decrypt_message(from, message, &was_decrypted); // internal OTR message diff --git a/src/xmpp/message.c b/src/xmpp/message.c index 6da2b367..4fc71f63 100644 --- a/src/xmpp/message.c +++ b/src/xmpp/message.c @@ -522,4 +522,3 @@ message_init_module(void) message_send_inactive = _message_send_inactive; message_send_gone = _message_send_gone; } -