[Pkg-privacy-commits] [pidgin-otr] 80/255: 2012-04-30
Ximin Luo
infinity0 at moszumanska.debian.org
Sat Aug 22 12:51:26 UTC 2015
This is an automated email from the git hooks/post-receive script.
infinity0 pushed a commit to branch experimental
in repository pidgin-otr.
commit c276bfa786bef8a4572a37d5633cf40f480d3ae0
Author: Rob Smits <rdfsmits at cs.uwaterloo.ca>
Date: Wed May 2 17:28:16 2012 -0400
2012-04-30
* gtk-dialog.c:
* gtk-ui.c:
* otr-plugin.c:
* otr-plugin.h:
* ui.c: More changes for instance tags. Some logging-
related changes too (output whether pidgin is logging,
change default not to log otr conversations). -- Rob
Smits
2009-06-11
* gtk-dialog.c:
* otr-plugin.c:
* otr-plugin.h: Initial instance tags implementation
from Lisa Du
---
AUTHORS | 2 +-
ChangeLog | 18 +
INSTALL | 2 +
Makefile.mingw | 47 +-
Makefile.mingw.notes | 40 +
README | 8 +-
dialogs.c | 4 +-
dialogs.h | 2 +-
gtk-dialog.c | 2045 ++++++++++++++++++++++++++------------
gtk-dialog.h | 2 +-
gtk-ui.c | 247 +++--
gtk-ui.h | 2 +-
otr-icons.h | 18 +-
otr-plugin.c | 752 ++++++++------
otr-plugin.h | 26 +-
packaging/fedora/pidgin-otr.spec | 21 +-
packaging/windows/pidgin-otr.nsi | 35 +-
tooltipmenu.c | 196 ++--
tooltipmenu.h | 10 +-
ui.c | 41 +-
ui.h | 2 +-
21 files changed, 2299 insertions(+), 1221 deletions(-)
diff --git a/AUTHORS b/AUTHORS
index d9c4f0e..05f434a 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -2,7 +2,7 @@ Off-the-Record Messaging plugin for pidgin
Authors:
- Ian Goldberg, Rob Smits, Chris Alexander, Willy Lew, Nikita Borisov
+ Ian Goldberg, Rob Smits, Chris Alexander, Willy Lew, Lisa Du, Nikita Borisov
<otr at cypherpunks.ca>
See the README file for mailing list information
diff --git a/ChangeLog b/ChangeLog
index 21fb8e3..12af88a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2012-04-30
+
+ * gtk-dialog.c:
+ * gtk-ui.c:
+ * otr-plugin.c:
+ * otr-plugin.h:
+ * ui.c: More changes for instance tags. Some logging-
+ related changes too (output whether pidgin is logging,
+ change default not to log otr conversations). -- Rob
+ Smits
+
2010-03-02
* po/vi.po: Vietnamese translation from Lyndon Johnson
@@ -9,6 +20,13 @@
the fingerprints in the manual authentication dialog
selectable (but not selected by default).
+2009-06-11
+
+ * gtk-dialog.c:
+ * otr-plugin.c:
+ * otr-plugin.h: Initial instance tags implementation
+ from Lisa Du
+
2009-08-24
* po/fr.po: Fixed \n errors
diff --git a/INSTALL b/INSTALL
index 7c4aacc..ff3fb10 100644
--- a/INSTALL
+++ b/INSTALL
@@ -51,6 +51,8 @@ Use the provided Makefile.mingw:
make -f Makefile.mingw
+See Makefile.mingw.notes for a few hints.
+
INSTALLATION
You should be able to simply do "make install". If you want to install
diff --git a/Makefile.mingw b/Makefile.mingw
index e7626cd..3ed5c74 100644
--- a/Makefile.mingw
+++ b/Makefile.mingw
@@ -1,17 +1,35 @@
WIN32=1
# The version number to put in the plugin info
-PIDGIN_OTR_VERSION = 3.2.0
+PIDGIN_OTR_VERSION = 4.0.0
# Name of the gettext domain
GETTEXT_PACKAGE = pidgin-otr
# Replace this with the path to the pidgin and purple headers
-PIDGIN_HEADERS ?= /usr/i586-mingw32msvc/include/pidgin
-PURPLE_HEADERS ?= /usr/i586-mingw32msvc/include/libpurple
+PIDGIN_HEADERS ?= -I/usr/i586-mingw32msvc/include/pidgin \
+ -I/usr/i586-mingw32msvc/include/pidgin/win32
+PURPLE_HEADERS ?= -I/usr/i586-mingw32msvc/include/libpurple \
+ -I/usr/i586-mingw32msvc/include/libpurple/win32
-# If you don't have pkg-config, put the appropriate -I entry on the next line
+# Replace this with the path to the extracted GTK+ "all-in-one" win32 bundle
+GTK_WIN32_BUNDLE ?= /usr/i586-mingw32msvc/misc/gtk_bundle
+
+# Replace this with the to path DLL files from a Win32 Pidgin distributable
+# (i.e. pidgin.dll and libpurple.dll)
+PIDGIN_WIN32_LIBS ?= /usr/i586-mingw32msvc/misc/pidgin_dlls
+
+# If you don't have pkg-config, uncomment the -I lines below
GTK_HDRS ?= `pkg-config --cflags glib-2.0 gtk+-2.0`
+#GTK_HDRS ?= -I$(GTK_WIN32_BUNDLE)/include/gtk-2.0 \
+# -I$(GTK_WIN32_BUNDLE)/include/glib-2.0 \
+# -I$(GTK_WIN32_BUNDLE)/include/cairo \
+# -I$(GTK_WIN32_BUNDLE)/include/pango-1.0 \
+# -I$(GTK_WIN32_BUNDLE)/include/atk-1.0 \
+# -I$(GTK_WIN32_BUNDLE)/include/gdk-pixbuf-2.0 \
+# -I$(GTK_WIN32_BUNDLE)/lib/glib-2.0/include \
+# -I$(GTK_WIN32_BUNDLE)/lib/gtk-2.0/include
+
# The location of the libotr include files. Note that if, for example,
# the full path of message.h is /usr/include/libotr/message.h, you
@@ -41,12 +59,13 @@ ZIPFILE = pidgin-otr-$(PIDGIN_OTR_VERSION).zip
CC = i586-mingw32msvc-gcc
LDFLAGS = -Wl,--enable-auto-image-base
-LDLIBS = $(LIBOTRLIBDIR)/libotr.a -lgtk-win32-2.0 -lglib-2.0 -lgdk_pixbuf-2.0 \
- -lgobject-2.0 -lpidgin -llibpurple -lgcrypt -lgpg-error \
- -L$(LIBINTLLIBDIR) -lintl
+LDLIBS = $(LIBOTRLIBDIR)/libotr.a -L$(GTK_WIN32_BUNDLE)/lib \
+ -L$(PIDGIN_WIN32_LIBS) -lgtk-win32-2.0 -lglib-2.0 \
+ -lgdk_pixbuf-2.0 -lgobject-2.0 -lpidgin -llibpurple \
+ -lgcrypt -lgpg-error -L$(LIBINTLLIBDIR) -lintl
CC ?= gcc
-override CFLAGS += -g -O2 -Wall -I$(PIDGIN_HEADERS) -I$(PURPLE_HEADERS) \
+override CFLAGS += -g -O2 -Wall $(PIDGIN_HEADERS) $(PURPLE_HEADERS) \
$(GTK_HDRS) -I$(LIBOTRINCDIR) $(FPIC) -DUSING_GTK -DPURPLE_PLUGINS \
-DPIDGIN_OTR_VERSION=\"$(PIDGIN_OTR_VERSION)\" \
-DPIDGIN_NAME=\"Pidgin\" -I$(LIBINTLINCDIR) -DENABLE_NLS \
@@ -66,8 +85,8 @@ clean:
distclean: clean
$(MAKE) -C po -f Makefile.mingw distclean
-## Package up all the pieces needed to build the installer
-zip: all
+## Prepare the win32_export directory
+prepare_win32_export: all
mkdir win32_export
# Copy pieces over from the libotr source dir
for f in otr_mackey.exe otr_parse.exe otr_remac.exe otr_modify.exe \
@@ -90,8 +109,16 @@ zip: all
i586-mingw32msvc-strip *.exe *.dll; \
perl -pi -e 's/$$/\r/' README.Toolkit.txt Protocol-v2.html \
COPYING.txt COPYING.LIB.txt README.txt; \
+
+installer: prepare_win32_export
+ makensis packaging/windows/pidgin-otr-rob.nsi
+ rm -rf win32_export
+
+## Package up all the pieces needed to build the installer
+zip: prepare_win32_export
rm -f ../$(ZIPFILE); \
zip -r ../$(ZIPFILE) README.txt \
README.Toolkit.txt Protocol-v2.html COPYING.txt \
COPYING.LIB.txt *.exe *.dll *.nsi locale
rm -rf win32_export
+
diff --git a/Makefile.mingw.notes b/Makefile.mingw.notes
new file mode 100644
index 0000000..62b28f4
--- /dev/null
+++ b/Makefile.mingw.notes
@@ -0,0 +1,40 @@
+Here are some rough notes that might help you create a pidgin-otr Win32 build on
+a Linux system with mingw32. These have been tested on Ubuntu 11.04.
+
+I am listing packages and their build instructions in the order they should be
+built. Good luck!
+
+libgpg-error-1.0:
+ (before configure)
+ HOST_CC=gcc
+ DLLTOOL=i586-mingw32msvc-dlltool
+ AS=i586-mingw32msvc-as
+ export HOST_CC DLLTOOL AS
+ ./configure --with-pic --build=`./config.guess` --host=i586-mingw32msvc --prefix=/usr/i586-mingw32msvc
+ make
+ sudo make install
+
+gcrypt-1.2.1:
+ w32root=i586-mingw32msvc ./autogen.sh --build-w32
+ Then append #undef HAVE_GETTIMEOFDAY to libgcrypt config.h
+ Apply windows slow random fix (patch on otr website, listed as "Note that if you're compiling from source on win32...")
+ make
+ sudo make install
+
+libotr:
+ ./configure --with-pic --build=`./config.guess` --host=i586-mingw32msvc --prefix=/usr/i586-mingw32msvc --with-libgcrypt-prefix=/usr/i586-mingw32msvc
+ make
+ sudo make install
+
+pidgin-otr:
+ You will need: Pidgin source code distributable, Pidgin Win32 distributable, and an "all-in-one bundle" of the GTK+ stack 2.14.7 or greater (e.g., gtk+-bundle_2.24.10-20120208_win32.zip).
+ In Makefile.mingw, specify the location of PIDGIN_HEADERS, PURPLE_HEADERS, GTK_WIN32_BUNDLE, and PIDGIN_WIN32_LIBS
+ Ensure either pkg-config will correctly resolve all the dependencies for glib-2.0 and gtk+-2.0 (there is a README in the GTK+ bundle about this), or uncomment (and perhaps revise) the hardcoded list of includes for GTK_HDRS
+ make -f Makefile.mingw
+
+nsis:
+ sudo apt-get install nsis
+ Locate the "nsisunz" plugin (a google search for "nsisunz.zip" should be sufficient)
+ Extract the DLL to /usr/local/share/nsis/Plugins (yes it's a DLL extension, but it will still work for GNU/Linux nsis)
+ make -f Makefile.mingw installer <-- This should now build the nsis installer
+
diff --git a/README b/README
index e208e8e..ddee61b 100644
--- a/README
+++ b/README
@@ -1,5 +1,5 @@
Off-the-Record Messaging plugin for pidgin
- v3.2.0, 15 Jun 2008
+ v4.0.0, 2012
This is a pidgin plugin which implements Off-the-Record (OTR) Messaging.
It is known to work (at least) under the Linux and Windows versions of
@@ -300,9 +300,9 @@ The Off-the-Record Messaging plugin for pidgin is covered by the following
(GPL) license:
Off-the-Record Messaging plugin for pidgin
- Copyright (C) 2004-2009 Ian Goldberg, Rob Smits,
+ Copyright (C) 2004-2012 Ian Goldberg, Rob Smits,
Chris Alexander, Willy Lew,
- Nikita Borisov
+ Lisa Du, Nikita Borisov
<otr at cypherpunks.ca>
@@ -325,7 +325,7 @@ CONTACT
To report problems, comments, suggestions, patches, etc., you can email
the authors:
-Ian Goldberg, Rob Smits, Chris Alexander, and Nikita Borisov
+Ian Goldberg, Rob Smits, Chris Alexander, Willy Lew, Lisa Du, Nikita Borisov
<otr at cypherpunks.ca>
For more information on Off-the-Record Messaging, visit
diff --git a/dialogs.c b/dialogs.c
index 4a4e99e..5bbc1b1 100644
--- a/dialogs.c
+++ b/dialogs.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging plugin for pidgin
- * Copyright (C) 2004-2009 Ian Goldberg, Rob Smits,
+ * Copyright (C) 2004-2012 Ian Goldberg, Rob Smits,
* Chris Alexander, Willy Lew,
* Nikita Borisov
* <otr at cypherpunks.ca>
@@ -109,7 +109,7 @@ int otrg_dialog_display_otr_message( const char *accountname,
int force_create)
{
return ui_ops->display_otr_message(accountname, protocol, username, msg,
- force_create);
+ force_create);
}
/* Put up a Please Wait dialog. This dialog can not be cancelled.
diff --git a/dialogs.h b/dialogs.h
index bf89368..a2a6456 100644
--- a/dialogs.h
+++ b/dialogs.h
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging plugin for pidgin
- * Copyright (C) 2004-2009 Ian Goldberg, Rob Smits,
+ * Copyright (C) 2004-2012 Ian Goldberg, Rob Smits,
* Chris Alexander, Willy Lew,
* Nikita Borisov
* <otr at cypherpunks.ca>
diff --git a/gtk-dialog.c b/gtk-dialog.c
index 6cae9df..fc6bf75 100644
--- a/gtk-dialog.c
+++ b/gtk-dialog.c
@@ -1,8 +1,8 @@
/*
* Off-the-Record Messaging plugin for pidgin
- * Copyright (C) 2004-2009 Ian Goldberg, Rob Smits,
+ * Copyright (C) 2004-2012 Ian Goldberg, Rob Smits,
* Chris Alexander, Willy Lew,
- * Nikita Borisov
+ * Lisa Du, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This program is free software; you can redistribute it and/or modify
@@ -56,6 +56,7 @@
#include <libotr/proto.h>
#include <libotr/message.h>
#include <libotr/userstate.h>
+#include <libotr/instag.h>
/* purple-otr headers */
#include "otr-plugin.h"
@@ -75,11 +76,13 @@ static int img_id_finished = 0;
typedef struct {
ConnContext *context; /* The context used to fire library code */
- GtkEntry* question_entry; /* The text entry field containing the user question */
+ GtkEntry* question_entry; /* The text entry field containing the user
+ * question */
GtkEntry *entry; /* The text entry field containing the secret */
- int smp_type; /* Whether the SMP type is based on question challenge (0) or shared secret (1) */
+ int smp_type; /* Whether the SMP type is based on question
+ * challenge (0) or shared secret (1) */
gboolean responder; /* Whether or not this is the first side to give
- their secret */
+ * their secret */
} SmpResponsePair;
/* Information used by the plugin that is specific to both the
@@ -90,6 +93,7 @@ typedef struct dialog_context_data {
GtkWidget *smp_progress_dialog;
GtkWidget *smp_progress_bar;
GtkWidget *smp_progress_label;
+ otrl_instag_t their_instance;
} SMPData;
typedef struct {
@@ -99,6 +103,39 @@ typedef struct {
GtkWidget *notebook;
} AuthSignalData;
+typedef struct {
+ enum {
+ convctx_none,
+ convctx_conv,
+ convctx_ctx
+ } convctx_type;
+ PurpleConversation *conv;
+ ConnContext *context;
+} ConvOrContext;
+
+gint get_new_instance_index(PurpleConversation *conv) {
+ gint max_index = (gint) purple_conversation_get_data(conv, "otr-max_idx");
+ max_index++;
+ purple_conversation_set_data(conv, "otr-max_idx", (gpointer) max_index);
+ return max_index;
+}
+
+gint get_context_instance_to_index(PurpleConversation *conv,
+ ConnContext *context) {
+ GHashTable * conv_to_idx_map =
+ purple_conversation_get_data(conv, "otr-conv_to_idx");
+ gint index = 0;
+ gpointer key = NULL;
+
+ if (!g_hash_table_lookup_extended(conv_to_idx_map, context, &key,
+ (void**)&index)) {
+ index = get_new_instance_index(conv);
+ g_hash_table_replace(conv_to_idx_map, context, (gpointer)index);
+ }
+
+ return index;
+}
+
static void close_progress_window(SMPData *smp_data)
{
if (smp_data->smp_progress_dialog) {
@@ -137,6 +174,9 @@ static void otrg_gtk_dialog_add_smp_data(PurpleConversation *conv)
smp_data->smp_progress_dialog = NULL;
smp_data->smp_progress_bar = NULL;
smp_data->smp_progress_label = NULL;
+ /* Chosen as initialized value since libotr should never allow
+ * this as a "their_instance" value */
+ smp_data->their_instance = OTRL_INSTAG_BEST;
purple_conversation_set_data(conv, "otr-smpdata", smp_data);
}
@@ -180,7 +220,8 @@ static void message_response_cb(GtkDialog *dialog, gint id, GtkWidget *widget)
gtk_widget_destroy(GTK_WIDGET(widget));
}
-/* Forward declarations for the benefit of smp_message_response_cb/redraw authvbox */
+/* Forward declarations for the benefit of smp_message_response_cb/redraw
+ * authvbox */
static void verify_fingerprint(GtkWindow *parent, Fingerprint *fprint);
static void add_vrfy_fingerprint(GtkWidget *vbox, void *data);
static struct vrfy_fingerprint_data* vrfy_fingerprint_data_new(
@@ -198,7 +239,7 @@ static void smp_progress_response_cb(GtkDialog *dialog, gint response,
{
PurpleConversation *conv = otrg_plugin_context_to_conv(context, 0);
SMPData *smp_data = NULL;
-
+
if (conv) {
gdouble frac;
@@ -235,58 +276,58 @@ static void smp_secret_response_cb(GtkDialog *dialog, gint response,
SmpResponsePair *smppair;
if (!auth_opt_data) return;
-
+
smppair = auth_opt_data->smppair;
-
+
if (!smppair) return;
context = smppair->context;
if (response == GTK_RESPONSE_ACCEPT && smppair->entry) {
- GtkEntry* entry = smppair->entry;
- char *secret;
- size_t secret_len;
-
- GtkEntry* question_entry = smppair->question_entry;
-
- const char *user_question = NULL;
-
-
- if (context == NULL || context->msgstate != OTRL_MSGSTATE_ENCRYPTED) {
- return;
- }
-
- secret = g_strdup(gtk_entry_get_text(entry));
- secret_len = strlen(secret);
-
- if (smppair->responder) {
- otrg_plugin_continue_smp(context, (const unsigned char *)secret,
- secret_len);
-
- } else {
-
- if (smppair->smp_type == 0) {
- if (!question_entry) {
- return;
- }
-
- user_question = gtk_entry_get_text(question_entry);
-
- if (user_question == NULL || strlen(user_question) == 0) {
- return;
- }
- }
-
- /* pass user question here */
- otrg_plugin_start_smp(context, user_question,
- (const unsigned char *)secret, secret_len);
-
- }
-
- g_free(secret);
-
- /* launch progress bar window */
- create_smp_progress_dialog(GTK_WINDOW(dialog), context);
+ GtkEntry* entry = smppair->entry;
+ char *secret;
+ size_t secret_len;
+
+ GtkEntry* question_entry = smppair->question_entry;
+
+ const char *user_question = NULL;
+
+
+ if (context == NULL || context->msgstate != OTRL_MSGSTATE_ENCRYPTED) {
+ return;
+ }
+
+ secret = g_strdup(gtk_entry_get_text(entry));
+ secret_len = strlen(secret);
+
+ if (smppair->responder) {
+ otrg_plugin_continue_smp(context, (const unsigned char *)secret,
+ secret_len);
+
+ } else {
+
+ if (smppair->smp_type == 0) {
+ if (!question_entry) {
+ return;
+ }
+
+ user_question = gtk_entry_get_text(question_entry);
+
+ if (user_question == NULL || strlen(user_question) == 0) {
+ return;
+ }
+ }
+
+ /* pass user question here */
+ otrg_plugin_start_smp(context, user_question,
+ (const unsigned char *)secret, secret_len);
+
+ }
+
+ g_free(secret);
+
+ /* launch progress bar window */
+ create_smp_progress_dialog(GTK_WINDOW(dialog), context);
} else if (response == GTK_RESPONSE_HELP) {
char *helpurl = g_strdup_printf("%s%s&context=%s",
AUTHENTICATE_HELPURL, _("?lang=en"),
@@ -307,19 +348,19 @@ static void smp_secret_response_cb(GtkDialog *dialog, gint response,
/* Don't destroy the window */
return;
} else {
- otrg_plugin_abort_smp(context);
+ otrg_plugin_abort_smp(context);
}
-
+
/* In all cases except HELP, destroy the current window */
gtk_widget_destroy(GTK_WIDGET(dialog));
-
+
/* Clean up references to this window */
conv = otrg_plugin_context_to_conv(smppair->context, 0);
smp_data = purple_conversation_get_data(conv, "otr-smpdata");
-
+
if (smp_data) {
- smp_data->smp_secret_dialog = NULL;
- smp_data->smp_secret_smppair = NULL;
+ smp_data->smp_secret_dialog = NULL;
+ smp_data->smp_secret_smppair = NULL;
}
/* Free memory */
@@ -382,7 +423,7 @@ static GtkWidget *create_dialog(GtkWindow *parent,
gtk_window_set_role(GTK_WINDOW(dialog), "notify_dialog");
g_signal_connect(G_OBJECT(dialog), "response",
- G_CALLBACK(message_response_cb), dialog);
+ G_CALLBACK(message_response_cb), dialog);
gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT,
sensitive);
@@ -401,10 +442,10 @@ static GtkWidget *create_dialog(GtkWindow *parent,
}
label_text = g_strdup_printf(
- "<span weight=\"bold\" size=\"larger\">%s</span>%s%s",
- (primary ? primary : ""),
- (primary ? "\n\n" : ""),
- (secondary ? secondary : ""));
+ "<span weight=\"bold\" size=\"larger\">%s</span>%s%s",
+ (primary ? primary : ""),
+ (primary ? "\n\n" : ""),
+ (secondary ? secondary : ""));
label = gtk_label_new(NULL);
@@ -431,19 +472,19 @@ static void add_to_vbox_init_one_way_auth(GtkWidget *vbox,
GtkWidget *entry;
GtkWidget *label;
GtkWidget *label2;
- char *label_text;
-
+ char *label_text;
+
SmpResponsePair* smppair = auth_opt_data->smppair;
-
+
if (smppair->responder) {
- label_text = g_strdup_printf("<small><i>\n%s\n</i></small>",
+ label_text = g_strdup_printf("<small><i>\n%s\n</i></small>",
_("Your buddy is attempting to determine if he or she is really "
"talking to you, or if it's someone pretending to be you. "
"Your buddy has asked a question, indicated below. "
"To authenticate to your buddy, enter the answer and "
"click OK."));
} else {
- label_text = g_strdup_printf("<small><i>\n%s\n</i></small>",
+ label_text = g_strdup_printf("<small><i>\n%s\n</i></small>",
_("To authenticate using a question, pick a question whose "
"answer is known only to you and your buddy. Enter this "
"question and this answer, then wait for your buddy to "
@@ -459,57 +500,58 @@ static void add_to_vbox_init_one_way_auth(GtkWidget *vbox,
gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
-
-
+
+
if (smppair->responder) {
- label_text = g_strdup_printf(_("This is the question asked by "
- "your buddy:"));
+ label_text = g_strdup_printf(_("This is the question asked by "
+ "your buddy:"));
} else {
- label_text = g_strdup_printf(_("Enter question here:"));
+ label_text = g_strdup_printf(_("Enter question here:"));
}
-
+
label = gtk_label_new(label_text);
gtk_label_set_selectable(GTK_LABEL(label), FALSE);
g_free(label_text);
gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
-
-
+
+
if (smppair->responder && question) {
- label_text = g_markup_printf_escaped("<span background=\"white\" foreground=\"black\" weight=\"bold\">%s</span>", question);
- label = gtk_label_new(NULL);
- gtk_label_set_markup (GTK_LABEL(label), label_text);
- gtk_label_set_selectable(GTK_LABEL(label), FALSE);
- g_free(label_text);
- gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
- gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
- gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
- smppair->question_entry = NULL;
+ label_text = g_markup_printf_escaped("<span background=\"white\" "
+ "foreground=\"black\" weight=\"bold\">%s</span>", question);
+ label = gtk_label_new(NULL);
+ gtk_label_set_markup (GTK_LABEL(label), label_text);
+ gtk_label_set_selectable(GTK_LABEL(label), FALSE);
+ g_free(label_text);
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
+ smppair->question_entry = NULL;
} else {
- /* Create the text view where the user enters their question */
- question_entry = gtk_entry_new ();
- smppair->question_entry = GTK_ENTRY(question_entry);
- gtk_box_pack_start(GTK_BOX(vbox), question_entry, FALSE, FALSE, 0);
+ /* Create the text view where the user enters their question */
+ question_entry = gtk_entry_new ();
+ smppair->question_entry = GTK_ENTRY(question_entry);
+ gtk_box_pack_start(GTK_BOX(vbox), question_entry, FALSE, FALSE, 0);
}
-
+
if (context->active_fingerprint->trust &&
- context->active_fingerprint->trust[0] && !(smppair->responder)) {
- label2 = gtk_label_new(_("This buddy is already authenticated."));
+ context->active_fingerprint->trust[0] && !(smppair->responder)) {
+ label2 = gtk_label_new(_("This buddy is already authenticated."));
} else {
- label2 = NULL;
+ label2 = NULL;
}
-
+
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
-
+
/* Leave a blank line */
gtk_box_pack_start(GTK_BOX(vbox), gtk_label_new(NULL), FALSE,
- FALSE, 0);
+ FALSE, 0);
label_text = g_strdup_printf(_("Enter secret answer here "
- "(case sensitive):"));
+ "(case sensitive):"));
label = gtk_label_new(NULL);
@@ -529,15 +571,15 @@ static void add_to_vbox_init_one_way_auth(GtkWidget *vbox,
gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
-
+
/* Leave a blank line */
gtk_box_pack_start(GTK_BOX(vbox), gtk_label_new(NULL), FALSE,
- FALSE, 0);
-
+ FALSE, 0);
+
if (label2) {
- gtk_box_pack_start(GTK_BOX(vbox), label2, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(vbox), gtk_label_new(NULL), FALSE,
- FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), label2, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), gtk_label_new(NULL), FALSE,
+ FALSE, 0);
}
}
@@ -546,13 +588,13 @@ static void add_to_vbox_init_two_way_auth(GtkWidget *vbox,
GtkWidget *entry;
GtkWidget *label;
GtkWidget *label2;
- char *label_text;
-
+ char *label_text;
+
label_text = g_strdup_printf("<small><i>\n%s\n</i></small>",
- _("To authenticate, pick a secret known "
- "only to you and your buddy. Enter this secret, then "
- "wait for your buddy to enter it too. If the secrets "
- "don't match, then you may be talking to an imposter."));
+ _("To authenticate, pick a secret known "
+ "only to you and your buddy. Enter this secret, then "
+ "wait for your buddy to enter it too. If the secrets "
+ "don't match, then you may be talking to an imposter."));
label = gtk_label_new(NULL);
@@ -562,7 +604,7 @@ static void add_to_vbox_init_two_way_auth(GtkWidget *vbox,
gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
-
+
label_text = g_strdup_printf(_("Enter secret here:"));
label = gtk_label_new(label_text);
gtk_label_set_selectable(GTK_LABEL(label), FALSE);
@@ -570,8 +612,8 @@ static void add_to_vbox_init_two_way_auth(GtkWidget *vbox,
gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
-
-
+
+
/* Create the text view where the user enters their secret */
entry = gtk_entry_new();
gtk_entry_set_text(GTK_ENTRY(entry), "");
@@ -579,27 +621,28 @@ static void add_to_vbox_init_two_way_auth(GtkWidget *vbox,
auth_opt_data->two_way_entry = GTK_ENTRY(entry);
if (context->active_fingerprint->trust &&
- context->active_fingerprint->trust[0]) {
- label2 = gtk_label_new(_("This buddy is already authenticated."));
+ context->active_fingerprint->trust[0]) {
+ label2 = gtk_label_new(_("This buddy is already authenticated."));
} else {
- label2 = NULL;
+ label2 = NULL;
}
gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
-
+
/* Leave a blank line */
gtk_box_pack_start(GTK_BOX(vbox), gtk_label_new(NULL), FALSE,
- FALSE, 0);
-
+ FALSE, 0);
+
if (label2) {
- gtk_box_pack_start(GTK_BOX(vbox), label2, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(vbox), gtk_label_new(NULL), FALSE,
- FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), label2, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), gtk_label_new(NULL), FALSE,
+ FALSE, 0);
}
}
-static void add_to_vbox_verify_fingerprint(GtkWidget *vbox, ConnContext *context, SmpResponsePair* smppair) {
+static void add_to_vbox_verify_fingerprint(GtkWidget *vbox,
+ ConnContext *context, SmpResponsePair* smppair) {
char our_hash[45], their_hash[45];
GtkWidget *label;
char *label_text;
@@ -610,16 +653,14 @@ static void add_to_vbox_verify_fingerprint(GtkWidget *vbox, ConnContext *context
if (fprint == NULL) return;
if (fprint->fingerprint == NULL) return;
- context = fprint->context;
- if (context == NULL) return;
label_text = g_strdup_printf("<small><i>\n%s %s\n</i></small>",
_("To verify the fingerprint, contact your buddy via some "
"<i>other</i> authenticated channel, such as the telephone "
"or GPG-signed email. Each of you should tell your fingerprint "
"to the other."),
- _("If everything matches up, you should indicate in the above "
- "dialog that you <b>have</b> verified the fingerprint."));
+ _("If everything matches up, you should chose <b>I have</b> "
+ "in the menu below."));
label = gtk_label_new(NULL);
gtk_label_set_markup(GTK_LABEL(label), label_text);
gtk_label_set_selectable(GTK_LABEL(label), FALSE);
@@ -631,18 +672,18 @@ static void add_to_vbox_verify_fingerprint(GtkWidget *vbox, ConnContext *context
strcpy(our_hash, _("[none]"));
otrl_privkey_fingerprint(otrg_plugin_userstate, our_hash,
- context->accountname, context->protocol);
+ context->accountname, context->protocol);
otrl_privkey_hash_to_human(their_hash, fprint->fingerprint);
p = purple_find_prpl(context->protocol);
proto_name = (p && p->info->name) ? p->info->name : _("Unknown");
label_text = g_strdup_printf(_("Fingerprint for you, %s (%s):\n%s\n\n"
- "Purported fingerprint for %s:\n%s\n"), context->accountname,
- proto_name, our_hash, context->username, their_hash);
-
+ "Purported fingerprint for %s:\n%s\n"), context->accountname,
+ proto_name, our_hash, context->username, their_hash);
+
label = gtk_label_new(NULL);
-
+
gtk_label_set_markup(GTK_LABEL(label), label_text);
/* Make the label containing the fingerprints selectable, but
* not auto-selected. */
@@ -653,7 +694,7 @@ static void add_to_vbox_verify_fingerprint(GtkWidget *vbox, ConnContext *context
gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
-
+
add_vrfy_fingerprint(vbox, vfd);
g_signal_connect(G_OBJECT(vbox), "destroy",
G_CALLBACK(vrfy_fingerprint_destroyed), vfd);
@@ -665,25 +706,25 @@ static void redraw_auth_vbox(GtkComboBox *combo, void *data) {
GtkWidget *notebook = auth_data ? auth_data->notebook : NULL;
int selected;
-
+
if (auth_data == NULL) return;
selected = gtk_combo_box_get_active(combo);
-
+
if (selected == 0) {
- gtk_notebook_set_current_page (GTK_NOTEBOOK(notebook), 0);
- auth_data->smppair->entry = auth_data->one_way_entry;
- auth_data->smppair->smp_type = 0;
+ gtk_notebook_set_current_page (GTK_NOTEBOOK(notebook), 0);
+ auth_data->smppair->entry = auth_data->one_way_entry;
+ auth_data->smppair->smp_type = 0;
} else if (selected == 1) {
- gtk_notebook_set_current_page (GTK_NOTEBOOK(notebook), 1);
- auth_data->smppair->entry = auth_data->two_way_entry;
- auth_data->smppair->smp_type = 1;
+ gtk_notebook_set_current_page (GTK_NOTEBOOK(notebook), 1);
+ auth_data->smppair->entry = auth_data->two_way_entry;
+ auth_data->smppair->smp_type = 1;
} else if (selected == 2) {
- auth_data->smppair->entry = NULL;
- gtk_notebook_set_current_page (GTK_NOTEBOOK(notebook), 2);
- auth_data->smppair->smp_type = -1;
+ auth_data->smppair->entry = NULL;
+ gtk_notebook_set_current_page (GTK_NOTEBOOK(notebook), 2);
+ auth_data->smppair->smp_type = -1;
}
-
+
}
static void add_other_authentication_options(GtkWidget *vbox,
@@ -693,7 +734,7 @@ static void add_other_authentication_options(GtkWidget *vbox,
char *labeltext;
labeltext = g_strdup_printf("\n%s",
- _("How would you like to authenticate your buddy?"));
+ _("How would you like to authenticate your buddy?"));
label = gtk_label_new(labeltext);
g_free(labeltext);
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
@@ -714,9 +755,9 @@ static void add_other_authentication_options(GtkWidget *vbox,
gtk_box_pack_start(GTK_BOX(vbox), combo, FALSE, FALSE, 0);
data->notebook = notebook;
-
+
g_signal_connect (combo, "changed",
- G_CALLBACK (redraw_auth_vbox), data);
+ G_CALLBACK (redraw_auth_vbox), data);
}
@@ -729,124 +770,132 @@ static GtkWidget *create_smp_dialog(const char *title, const char *primary,
SMPData *smp_data = purple_conversation_get_data(conv, "otr-smpdata");
close_progress_window(smp_data);
-
+
+ if (smp_data->their_instance != context->their_instance) {
+ otrg_gtk_dialog_free_smp_data(conv);
+ otrg_gtk_dialog_add_smp_data(conv);
+ }
+
if (!(smp_data->smp_secret_dialog)) {
- GtkWidget *hbox;
- GtkWidget *vbox;
- GtkWidget *auth_vbox;
- GtkWidget *label;
- GtkWidget *img = NULL;
- char *label_text;
- const char *icon_name = NULL;
- SmpResponsePair* smppair;
- GtkWidget *notebook;
- AuthSignalData *auth_opt_data;
-
- icon_name = PIDGIN_STOCK_DIALOG_INFO;
- img = gtk_image_new_from_stock(icon_name,
+ GtkWidget *hbox;
+ GtkWidget *vbox;
+ GtkWidget *auth_vbox;
+ GtkWidget *label;
+ GtkWidget *img = NULL;
+ char *label_text;
+ const char *icon_name = NULL;
+ SmpResponsePair* smppair;
+ GtkWidget *notebook;
+ AuthSignalData *auth_opt_data;
+
+ smp_data->their_instance = context->their_instance;
+ icon_name = PIDGIN_STOCK_DIALOG_INFO;
+ img = gtk_image_new_from_stock(icon_name,
gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_HUGE));
- gtk_misc_set_alignment(GTK_MISC(img), 0, 0);
-
- dialog = gtk_dialog_new_with_buttons(title ? title :
+ gtk_misc_set_alignment(GTK_MISC(img), 0, 0);
+
+ dialog = gtk_dialog_new_with_buttons(title ? title :
PIDGIN_ALERT_TITLE, NULL, 0,
- GTK_STOCK_HELP, GTK_RESPONSE_HELP,
- GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
- _("_Authenticate"), GTK_RESPONSE_ACCEPT, NULL);
- gtk_dialog_set_default_response(GTK_DIALOG(dialog),
+ GTK_STOCK_HELP, GTK_RESPONSE_HELP,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
+ _("_Authenticate"), GTK_RESPONSE_ACCEPT, NULL);
+ gtk_dialog_set_default_response(GTK_DIALOG(dialog),
GTK_RESPONSE_ACCEPT);
-
- auth_vbox = gtk_vbox_new(FALSE, 0);
- hbox = gtk_hbox_new(FALSE, 15);
- vbox = gtk_vbox_new(FALSE, 0);
-
- smppair = malloc(sizeof(SmpResponsePair));
- smppair->responder = responder;
- smppair->context = context;
-
-
- notebook = gtk_notebook_new();
- auth_opt_data = malloc(sizeof(AuthSignalData));
- auth_opt_data->smppair = smppair;
-
- gtk_window_set_focus_on_map(GTK_WINDOW(dialog), !responder);
- gtk_window_set_role(GTK_WINDOW(dialog), "notify_dialog");
-
- gtk_container_set_border_width(GTK_CONTAINER(dialog), 6);
- gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
- gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
- gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), 12);
- gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), 6);
-
- gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
-
- gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
-
- label_text = g_strdup_printf(
- "<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s",
- (primary ? primary : ""),
+
+ auth_vbox = gtk_vbox_new(FALSE, 0);
+ hbox = gtk_hbox_new(FALSE, 15);
+ vbox = gtk_vbox_new(FALSE, 0);
+
+ smppair = malloc(sizeof(SmpResponsePair));
+ smppair->responder = responder;
+ smppair->context = context;
+
+
+ notebook = gtk_notebook_new();
+ auth_opt_data = malloc(sizeof(AuthSignalData));
+ auth_opt_data->smppair = smppair;
+
+ gtk_window_set_focus_on_map(GTK_WINDOW(dialog), !responder);
+ gtk_window_set_role(GTK_WINDOW(dialog), "notify_dialog");
+
+ gtk_container_set_border_width(GTK_CONTAINER(dialog), 6);
+ gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
+ gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
+ gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), 12);
+ gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox),
+ 6);
+
+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
+
+ gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
+
+ label_text = g_strdup_printf(
+ "<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s",
+ (primary ? primary : ""),
_("Authenticating a buddy helps ensure that the person "
- "you are talking to is who he or she claims to be."));
-
- label = gtk_label_new(NULL);
-
- gtk_label_set_markup(GTK_LABEL(label), label_text);
- gtk_label_set_selectable(GTK_LABEL(label), FALSE);
- g_free(label_text);
- gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
- gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
- gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
-
- if (!responder) {
- add_other_authentication_options(vbox, notebook, context, auth_opt_data);
- }
-
- g_signal_connect(G_OBJECT(dialog), "response",
- G_CALLBACK(smp_secret_response_cb),
- auth_opt_data);
-
- if (!responder || (responder && question != NULL)) {
- GtkWidget *one_way_vbox = gtk_vbox_new(FALSE, 0);
- add_to_vbox_init_one_way_auth(one_way_vbox, context,
+ "you are talking to is who he or she claims to be."));
+
+ label = gtk_label_new(NULL);
+
+ gtk_label_set_markup(GTK_LABEL(label), label_text);
+ gtk_label_set_selectable(GTK_LABEL(label), FALSE);
+ g_free(label_text);
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
+
+ if (!responder) {
+ add_other_authentication_options(vbox, notebook, context,
+ auth_opt_data);
+ }
+
+ g_signal_connect(G_OBJECT(dialog), "response",
+ G_CALLBACK(smp_secret_response_cb),
+ auth_opt_data);
+
+ if (!responder || (responder && question != NULL)) {
+ GtkWidget *one_way_vbox = gtk_vbox_new(FALSE, 0);
+ add_to_vbox_init_one_way_auth(one_way_vbox, context,
auth_opt_data, question);
- gtk_notebook_append_page(GTK_NOTEBOOK(notebook), one_way_vbox,
- gtk_label_new("0"));
- smppair->entry = auth_opt_data->one_way_entry;
- smppair->smp_type = 0;
- }
-
- if (!responder || (responder && question == NULL)) {
- GtkWidget *two_way_vbox = gtk_vbox_new(FALSE, 0);
- add_to_vbox_init_two_way_auth(two_way_vbox, context, auth_opt_data);
- gtk_notebook_append_page(GTK_NOTEBOOK(notebook), two_way_vbox,
- gtk_label_new("1"));
-
- if (responder && question == NULL) {
- smppair->entry = auth_opt_data->two_way_entry;
- smppair->smp_type = 1;
- }
- }
-
- if (!responder) {
- GtkWidget *fingerprint_vbox = gtk_vbox_new(FALSE, 0);
- add_to_vbox_verify_fingerprint(fingerprint_vbox, context, smppair);
- gtk_notebook_append_page(GTK_NOTEBOOK(notebook), fingerprint_vbox,
- gtk_label_new("2"));
- }
-
- gtk_notebook_set_show_tabs (GTK_NOTEBOOK(notebook), FALSE);
-
- gtk_notebook_set_show_border (GTK_NOTEBOOK(notebook), FALSE);
- gtk_box_pack_start(GTK_BOX(auth_vbox), notebook, FALSE, FALSE, 0);
- gtk_widget_show(notebook);
-
-
- gtk_box_pack_start(GTK_BOX(vbox), auth_vbox, FALSE, FALSE, 0);
-
- gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
-
- gtk_widget_show_all(dialog);
-
- gtk_notebook_set_current_page (GTK_NOTEBOOK(notebook), 0);
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), one_way_vbox,
+ gtk_label_new("0"));
+ smppair->entry = auth_opt_data->one_way_entry;
+ smppair->smp_type = 0;
+ }
+
+ if (!responder || (responder && question == NULL)) {
+ GtkWidget *two_way_vbox = gtk_vbox_new(FALSE, 0);
+ add_to_vbox_init_two_way_auth(two_way_vbox, context, auth_opt_data);
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), two_way_vbox,
+ gtk_label_new("1"));
+
+ if (responder && question == NULL) {
+ smppair->entry = auth_opt_data->two_way_entry;
+ smppair->smp_type = 1;
+ }
+ }
+
+ if (!responder) {
+ GtkWidget *fingerprint_vbox = gtk_vbox_new(FALSE, 0);
+ add_to_vbox_verify_fingerprint(fingerprint_vbox, context, smppair);
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), fingerprint_vbox,
+ gtk_label_new("2"));
+ }
+
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK(notebook), FALSE);
+
+ gtk_notebook_set_show_border (GTK_NOTEBOOK(notebook), FALSE);
+ gtk_box_pack_start(GTK_BOX(auth_vbox), notebook, FALSE, FALSE, 0);
+ gtk_widget_show(notebook);
+
+
+ gtk_box_pack_start(GTK_BOX(vbox), auth_vbox, FALSE, FALSE, 0);
+
+ gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
+
+ gtk_widget_show_all(dialog);
+
+ gtk_notebook_set_current_page (GTK_NOTEBOOK(notebook), 0);
if (!responder) {
gtk_window_set_focus(GTK_WINDOW(dialog),
@@ -855,16 +904,16 @@ static GtkWidget *create_smp_dialog(const char *title, const char *primary,
gtk_window_set_focus(GTK_WINDOW(dialog),
GTK_WIDGET(smppair->entry));
}
-
- smp_data->smp_secret_dialog = dialog;
- smp_data->smp_secret_smppair = smppair;
-
+
+ smp_data->smp_secret_dialog = dialog;
+ smp_data->smp_secret_smppair = smppair;
+
} else {
- /* Set the responder field to TRUE if we were passed that value,
- * even if the window was already up. */
- if (responder) {
- smp_data->smp_secret_smppair->responder = responder;
- }
+ /* Set the responder field to TRUE if we were passed that value,
+ * even if the window was already up. */
+ if (responder) {
+ smp_data->smp_secret_smppair->responder = responder;
+ }
}
return smp_data->smp_secret_dialog;
@@ -892,9 +941,9 @@ static GtkWidget *create_smp_progress_dialog(GtkWindow *parent,
dialog = gtk_dialog_new_with_buttons(
context->smstate->received_question ?
- /* Translators: you are asked to authenticate yourself */
+ /* Translators: you are asked to authenticate yourself */
_("Authenticating to Buddy") :
- /* Translators: you asked your buddy to authenticate him/herself */
+ /* Translators: you asked your buddy to authenticate him/herself */
_("Authenticating Buddy"),
parent, 0, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
@@ -922,8 +971,8 @@ static GtkWidget *create_smp_progress_dialog(GtkWindow *parent,
label_pat = g_strdup_printf("<span weight=\"bold\" size=\"larger\">"
"%s</span>\n", context->smstate->received_question ?
- _("Authenticating to %s") :
- _("Authenticating %s"));
+ _("Authenticating to %s") :
+ _("Authenticating %s"));
label_text = g_strdup_printf(label_pat, context->username);
g_free(label_pat);
@@ -941,12 +990,12 @@ static GtkWidget *create_smp_progress_dialog(GtkWindow *parent,
gtk_label_set_line_wrap(GTK_LABEL(proglabel), TRUE);
gtk_misc_set_alignment(GTK_MISC(proglabel), 0, 0);
gtk_box_pack_start(GTK_BOX(vbox), proglabel, FALSE, FALSE, 0);
-
+
/* Create the progress bar */
bar = gtk_progress_bar_new();
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(bar), 0.1);
gtk_box_pack_start(GTK_BOX(vbox), bar, FALSE, FALSE, 0);
-
+
gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
conv = otrg_plugin_context_to_conv(context, 0);
@@ -959,8 +1008,8 @@ static GtkWidget *create_smp_progress_dialog(GtkWindow *parent,
gtk_label_set_text(GTK_LABEL(proglabel), _("Waiting for buddy..."));
g_signal_connect(G_OBJECT(dialog), "response",
- G_CALLBACK(smp_progress_response_cb),
- context);
+ G_CALLBACK(smp_progress_response_cb),
+ context);
gtk_widget_show_all(dialog);
@@ -999,11 +1048,11 @@ static OtrgDialogWaitHandle otrg_gtk_dialog_private_key_wait_start(
p = purple_find_prpl(protocol);
protocol_print = (p ? p->info->name : _("Unknown"));
-
+
/* Create the Please Wait... dialog */
secondary = g_strdup_printf(_("Generating private key for %s (%s)..."),
account, protocol_print);
-
+
dialog = create_dialog(NULL, PURPLE_NOTIFY_MSG_INFO, title, primary,
secondary, 0, &label, NULL, NULL);
handle = malloc(sizeof(struct s_OtrgDialogWait));
@@ -1015,7 +1064,7 @@ static OtrgDialogWaitHandle otrg_gtk_dialog_private_key_wait_start(
while (gtk_events_pending ()) {
gtk_main_iteration ();
}
-
+
g_free(secondary);
return handle;
@@ -1026,13 +1075,15 @@ static int otrg_gtk_dialog_display_otr_message(const char *accountname,
int force_create)
{
/* See if there's a conversation window we can put this in. */
- PurpleConversation *conv;
+ PurpleConversation *conv = otrg_plugin_userinfo_to_conv(accountname,
+ protocol, username, force_create);
+
- conv = otrg_plugin_userinfo_to_conv(accountname, protocol, username,
- force_create);
if (!conv) return -1;
- purple_conversation_write(conv, NULL, msg, PURPLE_MESSAGE_SYSTEM, time(NULL));
+
+ purple_conversation_write(conv, NULL, msg, PURPLE_MESSAGE_SYSTEM,
+ time(NULL));
return 0;
}
@@ -1067,8 +1118,9 @@ static void otrg_gtk_dialog_unknown_fingerprint(OtrlUserState us,
/* Figure out if this is the first fingerprint we've seen for this
* user. */
- context = otrl_context_find(us, who, accountname, protocol, FALSE,
- NULL, NULL, NULL);
+ context = otrl_context_find(us, who, accountname, protocol,
+ OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL);
+
if (context) {
Fingerprint *fp = context->fingerprint_root.next;
while(fp) {
@@ -1094,26 +1146,30 @@ static void otrg_gtk_dialog_unknown_fingerprint(OtrlUserState us,
conv = otrg_plugin_userinfo_to_conv(accountname, protocol, who, TRUE);
- purple_conversation_write(conv, NULL, buf, PURPLE_MESSAGE_SYSTEM, time(NULL));
-
+ purple_conversation_write(conv, NULL, buf, PURPLE_MESSAGE_SYSTEM,
+ time(NULL));
+
g_free(buf);
}
static void otrg_gtk_dialog_clicked_connect(GtkWidget *widget, gpointer data);
-static void build_otr_menu(PurpleConversation *conv, GtkWidget *menu,
+static void build_otr_menu(ConvOrContext *convctx, GtkWidget *menu,
TrustLevel level);
static void otr_refresh_otr_buttons(PurpleConversation *conv);
static void otr_destroy_top_menu_objects(PurpleConversation *conv);
static void otr_add_top_otr_menu(PurpleConversation *conv);
static void otr_add_buddy_top_menus(PurpleConversation *conv);
-static void otr_check_conv_status_change( PurpleConversation *conv);
+static void otr_check_conv_status_change(PurpleConversation *conv);
static void destroy_menuitem(GtkWidget *widget, gpointer data)
{
gtk_widget_destroy(widget);
}
+static void otr_build_status_submenu(PidginWindow *win,
+ ConvOrContext *convctx, GtkWidget *menu, TrustLevel level);
+
static void dialog_update_label_conv(PurpleConversation *conv, TrustLevel level)
{
GtkWidget *label;
@@ -1130,6 +1186,9 @@ static void dialog_update_label_conv(PurpleConversation *conv, TrustLevel level)
GtkWidget *menuview;
GtkWidget *menuverf;
GtkWidget *menusmp;
+#else
+ ConvOrContext *convctx;
+ GHashTable * conv_or_ctx_map;
#endif
PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
label = purple_conversation_get_data(conv, "otr-label");
@@ -1208,7 +1267,19 @@ static void dialog_update_label_conv(PurpleConversation *conv, TrustLevel level)
#ifdef OLD_OTR_BUTTON
#else
- build_otr_menu(conv, menu, level);
+ conv_or_ctx_map = purple_conversation_get_data(conv, "otr-convorctx");
+ convctx = g_hash_table_lookup(conv_or_ctx_map, conv);
+
+ if (!convctx) {
+ convctx = malloc(sizeof(ConvOrContext));
+ g_hash_table_insert(conv_or_ctx_map, conv, (gpointer)convctx);
+ }
+
+ convctx->convctx_type = convctx_conv;
+ convctx->conv = conv;
+ build_otr_menu(convctx, menu, level);
+ otr_build_status_submenu(pidgin_conv_get_window(gtkconv), convctx, menu,
+ level);
#endif
conv = gtkconv->active_conv;
@@ -1216,7 +1287,7 @@ static void dialog_update_label_conv(PurpleConversation *conv, TrustLevel level)
/* Update other widgets */
if (gtkconv != pidgin_conv_window_get_active_gtkconv(gtkconv->win)) {
- return;
+ return;
}
otr_destroy_top_menu_objects(conv);
@@ -1231,9 +1302,11 @@ static void dialog_update_label(ConnContext *context)
PurpleConversation *conv;
TrustLevel level = otrg_plugin_context_to_trust(context);
+
account = purple_accounts_find(context->accountname, context->protocol);
if (!account) return;
- conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, context->username, account);
+ conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
+ context->username, account);
if (!conv) return;
dialog_update_label_conv(conv, level);
}
@@ -1244,6 +1317,7 @@ struct vrfy_fingerprint_data {
while. Use the copied pieces below
instead. */
char *accountname, *username, *protocol;
+ otrl_instag_t their_instance;
unsigned char fingerprint[20];
};
@@ -1266,6 +1340,7 @@ static struct vrfy_fingerprint_data* vrfy_fingerprint_data_new(
vfd->accountname = strdup(context->accountname);
vfd->username = strdup(context->username);
vfd->protocol = strdup(context->protocol);
+ vfd->their_instance = context->their_instance;
memmove(vfd->fingerprint, fprint->fingerprint, 20);
return vfd;
@@ -1281,15 +1356,14 @@ static void vrfy_fingerprint_changed(GtkComboBox *combo, void *data)
{
struct vrfy_fingerprint_data *vfd = data;
ConnContext *context = otrl_context_find(otrg_plugin_userstate,
- vfd->username, vfd->accountname, vfd->protocol, 0, NULL,
- NULL, NULL);
+ vfd->username, vfd->accountname, vfd->protocol, vfd->their_instance,
+ 0, NULL, NULL, NULL);
Fingerprint *fprint;
int oldtrust, trust;
if (context == NULL) return;
- fprint = otrl_context_find_fingerprint(context, vfd->fingerprint,
- 0, NULL);
+ fprint = otrl_context_find_fingerprint(context, vfd->fingerprint, 0, NULL);
if (fprint == NULL) return;
@@ -1304,7 +1378,7 @@ static void vrfy_fingerprint_changed(GtkComboBox *combo, void *data)
otrg_plugin_write_fingerprints();
otrg_ui_update_keylist();
otrg_dialog_resensitize_all();
-
+
}
}
@@ -1323,10 +1397,10 @@ static void add_vrfy_fingerprint(GtkWidget *vbox, void *data)
hbox = gtk_hbox_new(FALSE, 0);
combo = gtk_combo_box_new_text();
- /* Translators: the following four messages should give alternative sentences.
- The user selects the first or second message in a combo box;
- the third message, a new line, a fingerprint, a new line, and
- the fourth message will follow it. */
+ /* Translators: the following four messages should give alternative
+ * sentences. The user selects the first or second message in a combo box;
+ * the third message, a new line, a fingerprint, a new line, and
+ * the fourth message will follow it. */
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("I have not"));
/* 2nd message */
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("I have"));
@@ -1348,7 +1422,7 @@ static void add_vrfy_fingerprint(GtkWidget *vbox, void *data)
g_free(labelt);
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
-
+
/* Leave a blank line */
gtk_box_pack_start(GTK_BOX(vbox), gtk_label_new(NULL), FALSE, FALSE, 0);
}
@@ -1382,8 +1456,8 @@ static void verify_fingerprint(GtkWindow *parent, Fingerprint *fprint)
p = purple_find_prpl(context->protocol);
proto_name = (p && p->info->name) ? p->info->name : _("Unknown");
secondary = g_strdup_printf(_("<small><i>%s %s\n\n</i></small>"
- "Fingerprint for you, %s (%s):\n%s\n\n"
- "Purported fingerprint for %s:\n%s\n"),
+ "Fingerprint for you, %s (%s):\n%s\n\n"
+ "Purported fingerprint for %s:\n%s\n"),
_("To verify the fingerprint, contact your buddy via some "
"<i>other</i> authenticated channel, such as the telephone "
"or GPG-signed email. Each of you should tell your fingerprint "
@@ -1421,18 +1495,16 @@ static void otrg_gtk_dialog_socialist_millionaires(ConnContext *context,
if (context == NULL) return;
if (responder && question) {
- primary = g_strdup_printf(_("Authentication from %s"),
- context->username);
+ primary = g_strdup_printf(_("Authentication from %s"),
+ context->username);
} else {
- primary = g_strdup_printf(_("Authenticate %s"),
- context->username);
+ primary = g_strdup_printf(_("Authenticate %s"),
+ context->username);
}
-
- /* fprintf(stderr, "Question = ``%s''\n", question); */
p = purple_find_prpl(context->protocol);
proto_name = (p && p->info->name) ? p->info->name : _("Unknown");
-
+
dialog = create_smp_dialog(_("Authenticate Buddy"),
primary, context, responder, question);
@@ -1457,7 +1529,7 @@ static void otrg_gtk_dialog_update_smp(ConnContext *context,
/* If the counter is reset to absolute zero, the protocol has aborted */
if (progress_level == 0.0) {
- GtkDialog *dialog = GTK_DIALOG(smp_data->smp_progress_dialog);
+ GtkDialog *dialog = GTK_DIALOG(smp_data->smp_progress_dialog);
gtk_dialog_set_response_sensitive(dialog, GTK_RESPONSE_ACCEPT, 1);
gtk_dialog_set_response_sensitive(dialog, GTK_RESPONSE_REJECT, 0);
@@ -1469,14 +1541,14 @@ static void otrg_gtk_dialog_update_smp(ConnContext *context,
return;
} else if (progress_level == 1.0) {
/* If the counter reaches 1.0, the protocol is complete */
- GtkDialog *dialog = GTK_DIALOG(smp_data->smp_progress_dialog);
+ GtkDialog *dialog = GTK_DIALOG(smp_data->smp_progress_dialog);
gtk_dialog_set_response_sensitive(dialog, GTK_RESPONSE_ACCEPT, 1);
gtk_dialog_set_response_sensitive(dialog, GTK_RESPONSE_REJECT, 0);
gtk_dialog_set_default_response(GTK_DIALOG(dialog),
GTK_RESPONSE_ACCEPT);
- if (smp_event == OTRL_SMPEVENT_SUCCESS) {
+ if (smp_event == OTRL_SMPEVENT_SUCCESS) {
if (context->active_fingerprint->trust &&
context->active_fingerprint->trust[0]) {
gtk_label_set_text(GTK_LABEL(smp_data->smp_progress_label),
@@ -1484,10 +1556,10 @@ static void otrg_gtk_dialog_update_smp(ConnContext *context,
} else {
gtk_label_set_text(GTK_LABEL(smp_data->smp_progress_label),
_("Your buddy has successfully authenticated you. "
- "You may want to authenticate your buddy as "
- "well by asking your own question."));
+ "You may want to authenticate your buddy as "
+ "well by asking your own question."));
}
- } else {
+ } else {
gtk_label_set_text(GTK_LABEL(smp_data->smp_progress_label),
_("Authentication failed."));
}
@@ -1505,6 +1577,7 @@ static void otrg_gtk_dialog_connected(ConnContext *context)
char *format_buf;
TrustLevel level;
OtrgUiPrefs prefs;
+ gboolean is_multi_inst;
conv = otrg_plugin_context_to_conv(context, TRUE);
level = otrg_plugin_context_to_trust(context);
@@ -1517,33 +1590,55 @@ static void otrg_gtk_dialog_connected(ConnContext *context)
switch(level) {
case TRUST_PRIVATE:
- format_buf = g_strdup(_("Private conversation with %s started.%s"));
- break;
+ format_buf = g_strdup(
+ _("Private conversation with %s started.%s%s"));
+ break;
case TRUST_UNVERIFIED:
- format_buf = g_strdup_printf(_("<a href=\"%s%s\">Unverified</a> "
- "conversation with %%s started.%%s"),
- UNVERIFIED_HELPURL, _("?lang=en"));
- break;
+ format_buf = g_strdup_printf(_("<a href=\"%s%s\">Unverified</a> "
+ "conversation with %%s started.%%s%%s"),
+ UNVERIFIED_HELPURL, _("?lang=en"));
+ break;
default:
- /* This last case should never happen, since we know
- * we're in ENCRYPTED. */
- format_buf = g_strdup(_("Not private conversation with %s "
- "started.%s"));
- break;
+ /* This last case should never happen, since we know
+ * we're in ENCRYPTED. */
+ format_buf = g_strdup(_("Not private conversation with %s "
+ "started.%s%s"));
+ break;
}
buf = g_strdup_printf(format_buf,
purple_conversation_get_name(conv),
context->protocol_version == 1 ? _(" Warning: using old "
- "protocol version 1.") : "");
+ "protocol version 1.") : "", conv->logging ?
+ _(" Your client is logging this conversation.") :
+ _(" Your client is not logging this conversation."));
+
+ purple_conversation_write(conv, NULL, buf, PURPLE_MESSAGE_SYSTEM,
+ time(NULL));
- purple_conversation_write(conv, NULL, buf, PURPLE_MESSAGE_SYSTEM, time(NULL));
-
g_free(buf);
g_free(format_buf);
dialog_update_label(context);
+
+ is_multi_inst = (gboolean) purple_conversation_get_data(conv,
+ "otr-conv_multi_instances");
+
+ if (is_multi_inst) {
+ gboolean have_warned_instances = (gboolean)
+ purple_conversation_get_data(conv, "otr-warned_instances");
+
+ if (!have_warned_instances) {
+ purple_conversation_set_data(conv, "otr-warned_instances",
+ (gpointer)1);
+ otrg_gtk_dialog_display_otr_message(context->accountname,
+ context->protocol, context->username,
+ _("Your buddy is logged in multiple times and OTR has "
+ "established multiple sessions. Use the icon menu above if "
+ "you wish to select the outgoing session."), 0);
+ }
+ }
}
/* Call this when a context transitions to PLAINTEXT. */
@@ -1557,16 +1652,16 @@ static void otrg_gtk_dialog_disconnected(ConnContext *context)
buf = g_strdup_printf(_("Private conversation with %s lost."),
purple_conversation_get_name(conv));
-
- purple_conversation_write(conv, NULL, buf, PURPLE_MESSAGE_SYSTEM, time(NULL));
-
+
+ purple_conversation_write(conv, NULL, buf, PURPLE_MESSAGE_SYSTEM,
+ time(NULL));
+
g_free(buf);
otrg_ui_get_prefs(&prefs, purple_conversation_get_account(conv),
context->username);
if (prefs.avoid_logging_otr) {
- if (purple_prefs_get_bool("/purple/logging/log_ims"))
- {
+ if (purple_prefs_get_bool("/purple/logging/log_ims")) {
purple_conversation_set_logging(conv, TRUE);
}
}
@@ -1593,11 +1688,12 @@ static void otrg_gtk_dialog_finished(const char *accountname,
if (!conv) return;
buf = g_strdup_printf(_("%s has ended his/her private conversation with "
- "you; you should do the same."),
+ "you; you should do the same."),
purple_conversation_get_name(conv));
-
- purple_conversation_write(conv, NULL, buf, PURPLE_MESSAGE_SYSTEM, time(NULL));
-
+
+ purple_conversation_write(conv, NULL, buf, PURPLE_MESSAGE_SYSTEM,
+ time(NULL));
+
g_free(buf);
dialog_update_label_conv(conv, TRUST_FINISHED);
@@ -1617,33 +1713,34 @@ static void otrg_gtk_dialog_stillconnected(ConnContext *context)
level = otrg_plugin_context_to_trust(context);
switch(level) {
- case TRUST_PRIVATE:
- format_buf = g_strdup(_("Successfully refreshed the private "
- "conversation with %s.%s"));
- break;
+ case TRUST_PRIVATE:
+ format_buf = g_strdup(_("Successfully refreshed the private "
+ "conversation with %s.%s"));
+ break;
- case TRUST_UNVERIFIED:
- format_buf = g_strdup_printf(_("Successfully refreshed the "
- "<a href=\"%s%s\">unverified</a> conversation with "
- "%%s.%%s"),
- UNVERIFIED_HELPURL, _("?lang=en"));
- break;
+ case TRUST_UNVERIFIED:
+ format_buf = g_strdup_printf(_("Successfully refreshed the "
+ "<a href=\"%s%s\">unverified</a> conversation with "
+ "%%s.%%s"),
+ UNVERIFIED_HELPURL, _("?lang=en"));
+ break;
- default:
- /* This last case should never happen, since we know
- * we're in ENCRYPTED. */
- format_buf = g_strdup(_("Successfully refreshed the not private "
- "conversation with %s.%s"));
- break;
+ default:
+ /* This last case should never happen, since we know
+ * we're in ENCRYPTED. */
+ format_buf = g_strdup(_("Successfully refreshed the not private "
+ "conversation with %s.%s"));
+ break;
}
buf = g_strdup_printf(format_buf,
purple_conversation_get_name(conv),
context->protocol_version == 1 ? _(" Warning: using old "
- "protocol version 1.") : "");
+ "protocol version 1.") : "");
+
+ purple_conversation_write(conv, NULL, buf, PURPLE_MESSAGE_SYSTEM,
+ time(NULL));
- purple_conversation_write(conv, NULL, buf, PURPLE_MESSAGE_SYSTEM, time(NULL));
-
g_free(buf);
g_free(format_buf);
@@ -1660,7 +1757,7 @@ static void otrg_gtk_dialog_clicked_connect(GtkWidget *widget, gpointer data)
PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
if (gtkconv->active_conv != conv) {
- pidgin_conv_switch_active_conversation(conv);
+ pidgin_conv_switch_active_conversation(conv);
}
if (purple_conversation_get_data(conv, "otr-private")) {
@@ -1669,19 +1766,28 @@ static void otrg_gtk_dialog_clicked_connect(GtkWidget *widget, gpointer data)
format = _("Attempting to start a private conversation with %s...");
}
buf = g_strdup_printf(format, purple_conversation_get_name(conv));
-
- purple_conversation_write(conv, NULL, buf, PURPLE_MESSAGE_SYSTEM, time(NULL));
-
+
+ purple_conversation_write(conv, NULL, buf, PURPLE_MESSAGE_SYSTEM,
+ time(NULL));
+
g_free(buf);
-
+
otrg_plugin_send_default_query_conv(conv);
}
/* Called when SMP verification option selected from menu */
static void socialist_millionaires(GtkWidget *widget, gpointer data)
{
- PurpleConversation *conv = data;
- ConnContext *context = otrg_plugin_conv_to_context(conv);
+ ConvOrContext *convctx = data;
+ PurpleConversation *conv;
+ ConnContext *context;
+
+ if (convctx->convctx_type == convctx_conv) {
+ conv = convctx->conv;
+ context = otrg_plugin_conv_to_selected_context(conv, 0);
+ } else if (convctx->convctx_type == convctx_ctx) {
+ context = convctx->context;
+ }
if (context == NULL || context->msgstate != OTRL_MSGSTATE_ENCRYPTED)
return;
@@ -1698,8 +1804,17 @@ static void menu_whatsthis(GtkWidget *widget, gpointer data)
static void menu_end_private_conversation(GtkWidget *widget, gpointer data)
{
- PurpleConversation *conv = data;
- ConnContext *context = otrg_plugin_conv_to_context(conv);
+ PurpleConversation *conv;
+ ConnContext *context;
+ ConvOrContext *convctx = data;
+
+ if (convctx->convctx_type == convctx_conv) {
+ conv = convctx->conv;
+ context = otrg_plugin_conv_to_selected_context(conv, 0);
+ } else if (convctx->convctx_type == convctx_ctx) {
+ context = convctx->context;
+ }
+
otrg_ui_disconnect_connection(context);
}
@@ -1746,8 +1861,8 @@ static void otr_refresh_otr_buttons(PurpleConversation *conv) {
for (;list_iter;list_iter = list_iter->next) {
- current_conv = list_iter->data;
- button = purple_conversation_get_data(current_conv, "otr-button");
+ current_conv = list_iter->data;
+ button = purple_conversation_get_data(current_conv, "otr-button");
if (button) {
if (current_conv == gtkconv->active_conv) {
@@ -1759,24 +1874,41 @@ static void otr_refresh_otr_buttons(PurpleConversation *conv) {
}
}
-static void otr_destroy_top_menu_objects(PurpleConversation *conv) {
- PidginConversation *gtkconv = PIDGIN_CONVERSATION ( conv );
- PidginWindow *win = pidgin_conv_get_window ( gtkconv );
+/* Menu has been destroyed -- let's remove it from the menu_list
+ so that it won't be destroyed again */
+static void otr_menu_destroy(GtkWidget *widget, gpointer pdata) {
+ PidginWindow *win = (PidginWindow *) pdata ;
+ GtkWidget *top_menu = widget;
+
GList * menu_list = g_hash_table_lookup ( otr_win_menus, win );
- GList * iter;
- GList * next;
+ menu_list = g_list_remove ( menu_list, top_menu );
+ g_hash_table_replace ( otr_win_menus, win, menu_list );
+}
+
+static void otr_clear_win_menu_list(PidginWindow *win) {
+ GList * head = g_hash_table_lookup ( otr_win_menus, win ); /* menu_list */
+ GList * old_head = 0;
- if ( menu_list != NULL ) {
- iter = menu_list;
- while ( iter ) {
- if ( iter->data ) gtk_object_destroy ( GTK_OBJECT ( iter->data ) );
- next = iter->next;
- menu_list = g_list_remove ( menu_list, iter->data );
- iter = next;
- }
+ while(head) {
+ old_head = head;
+ gtk_object_destroy ( GTK_OBJECT ( head->data ) );
+ head = g_hash_table_lookup ( otr_win_menus, win );
+
+ if (head && head == old_head) {
+ /* The head was not removed by the "destroyed" callback
+ Something is wrong */
+ break;
+ }
}
- g_hash_table_replace ( otr_win_menus, win, menu_list );
+ g_hash_table_replace ( otr_win_menus, win, head );
+}
+
+static void otr_destroy_top_menu_objects(PurpleConversation *conv) {
+ PidginConversation *gtkconv = PIDGIN_CONVERSATION ( conv );
+ PidginWindow *win = pidgin_conv_get_window ( gtkconv );
+
+ otr_clear_win_menu_list(win);
}
static int otr_get_menu_insert_pos(PurpleConversation *conv) {
@@ -1784,13 +1916,13 @@ static int otr_get_menu_insert_pos(PurpleConversation *conv) {
PidginWindow *win = pidgin_conv_get_window ( gtkconv );
GtkWidget *menu_bar = win->menu.menubar;
- GList * list_iter = gtk_container_get_children ( GTK_CONTAINER ( menu_bar ) );
+ GList * list_iter = gtk_container_get_children(GTK_CONTAINER(menu_bar));
GList * head = list_iter;
int pos = 0;
while ( list_iter ) {
- pos++;
- list_iter = list_iter->next;
+ pos++;
+ list_iter = list_iter->next;
}
if (pos != 0) pos--;
@@ -1800,23 +1932,40 @@ static int otr_get_menu_insert_pos(PurpleConversation *conv) {
return pos;
}
-static void otr_set_menu_labels(PurpleConversation *conv, GtkWidget *query, GtkWidget *end, GtkWidget *smp) {
- int insecure = purple_conversation_get_data(conv, "otr-private") ? 0 : 1;
- int authen = purple_conversation_get_data(conv, "otr-authenticated") ?
- 1 : 0;
- int finished = purple_conversation_get_data(conv, "otr-finished") ? 1 : 0;
+static void otr_set_menu_labels(ConvOrContext *convctx, GtkWidget *query,
+ GtkWidget *end, GtkWidget *smp) {
+ PurpleConversation *conv;
+ int insecure = 0;
+ int authen = 0;
+ int finished = 0;
+ TrustLevel level = TRUST_NOT_PRIVATE;
+
+
+ if (convctx->convctx_type == convctx_conv) {
+ conv = convctx->conv;
+ insecure = purple_conversation_get_data(conv, "otr-private") ? 0 : 1;
+ authen = purple_conversation_get_data(conv, "otr-authenticated") ? 1 :0;
+ finished = purple_conversation_get_data(conv, "otr-finished") ? 1 : 0;
+ } else if (convctx->convctx_type == convctx_ctx) {
+ level = otrg_plugin_context_to_trust(convctx->context);
+ insecure = level == TRUST_UNVERIFIED || level == TRUST_PRIVATE ? 0 : 1;
+ authen = level == TRUST_PRIVATE ? 1 : 0;
+ finished = level == TRUST_FINISHED ? 1 : 0;
+ } else {
+ return;
+ }
GtkWidget * label = gtk_bin_get_child(GTK_BIN(query));
gtk_label_set_markup_with_mnemonic(GTK_LABEL(label),
- insecure ? _("Start _private conversation") :
- _("Refresh _private conversation"));
+ insecure ? _("Start _private conversation") :
+ _("Refresh _private conversation"));
label = gtk_bin_get_child(GTK_BIN(smp));
gtk_label_set_markup_with_mnemonic(GTK_LABEL(label),
- (!insecure && authen) ? _("Re_authenticate buddy") :
- _("_Authenticate buddy"));
+ (!insecure && authen) ? _("Re_authenticate buddy") :
+ _("_Authenticate buddy"));
gtk_widget_set_sensitive(GTK_WIDGET(end), !insecure || finished);
gtk_widget_set_sensitive(GTK_WIDGET(smp), !insecure);
@@ -1828,7 +1977,7 @@ static void force_deselect(GtkItem *item, gpointer data)
}
static void otr_build_status_submenu(PidginWindow *win,
- PurpleConversation *conv, GtkWidget *menu, TrustLevel level) {
+ ConvOrContext *convctx, GtkWidget *menu, TrustLevel level) {
char *status = "";
GtkWidget *image;
GtkWidget *levelimage;
@@ -1838,8 +1987,21 @@ static void otr_build_status_submenu(PidginWindow *win,
GdkPixbuf *pixbuf;
GtkWidget *whatsthis;
- gchar *text = g_strdup_printf("%s (%s)", conv->name,
+ gchar *text = NULL;
+
+ PurpleConversation *conv;
+
+ if (convctx->convctx_type == convctx_conv) {
+ conv = convctx->conv;
+ } else if (convctx->convctx_type == convctx_ctx) {
+ conv = otrg_plugin_context_to_conv(convctx->context, 0);
+ } else {
+ return;
+ }
+
+ text = g_strdup_printf("%s (%s)", conv->name,
purple_account_get_username(conv->account));
+
buddy_name = gtk_image_menu_item_new_with_label(text);
g_free(text);
@@ -1856,24 +2018,24 @@ static void otr_build_status_submenu(PidginWindow *win,
gtk_image_menu_item_set_image ( GTK_IMAGE_MENU_ITEM ( buddy_name ), image);
switch(level) {
- case TRUST_NOT_PRIVATE:
- status = _("Not Private");
- break;
- case TRUST_UNVERIFIED:
- status = _("Unverified");
- break;
- case TRUST_PRIVATE:
- status = _("Private");
- break;
- case TRUST_FINISHED:
- status = _("Finished");
- break;
- }
+ case TRUST_NOT_PRIVATE:
+ status = _("Not Private");
+ break;
+ case TRUST_UNVERIFIED:
+ status = _("Unverified");
+ break;
+ case TRUST_PRIVATE:
+ status = _("Private");
+ break;
+ case TRUST_FINISHED:
+ status = _("Finished");
+ break;
+ }
buddy_status = gtk_image_menu_item_new_with_label(status);
levelimage = otr_icon(NULL, level, 1);
-
+
gtk_image_menu_item_set_image ( GTK_IMAGE_MENU_ITEM ( buddy_status ),
levelimage);
@@ -1882,8 +2044,8 @@ static void otr_build_status_submenu(PidginWindow *win,
whatsthis = gtk_image_menu_item_new_with_mnemonic(_("_What's this?"));
gtk_image_menu_item_set_image ( GTK_IMAGE_MENU_ITEM ( whatsthis ),
gtk_image_new_from_stock(GTK_STOCK_HELP,
- gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL)));
-
+ gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL)));
+
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menusep);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), buddy_name);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), buddy_status);
@@ -1897,24 +2059,39 @@ static void otr_build_status_submenu(PidginWindow *win,
gtk_widget_show_all(whatsthis);
gtk_signal_connect(GTK_OBJECT(buddy_name), "select",
- GTK_SIGNAL_FUNC(force_deselect), NULL);
+ GTK_SIGNAL_FUNC(force_deselect), NULL);
gtk_signal_connect(GTK_OBJECT(buddy_status), "select",
- GTK_SIGNAL_FUNC(force_deselect), NULL);
+ GTK_SIGNAL_FUNC(force_deselect), NULL);
gtk_signal_connect(GTK_OBJECT(whatsthis), "activate",
- GTK_SIGNAL_FUNC(menu_whatsthis), conv);
+ GTK_SIGNAL_FUNC(menu_whatsthis), conv);
}
-static void build_otr_menu(PurpleConversation *conv, GtkWidget *menu,
+static void build_otr_menu(ConvOrContext *convctx, GtkWidget *menu,
TrustLevel level)
{
- PidginConversation *gtkconv = PIDGIN_CONVERSATION ( conv );
- PidginWindow *win = pidgin_conv_get_window ( gtkconv );
+ PurpleConversation *conv;
+ PidginConversation *gtkconv;
+ PidginWindow *win;
- GtkWidget *buddymenuquery = gtk_menu_item_new_with_mnemonic(_("Start _private conversation"));
- GtkWidget *buddymenuend = gtk_menu_item_new_with_mnemonic(_("_End private conversation"));
- GtkWidget *buddymenusmp = gtk_menu_item_new_with_mnemonic(_("_Authenticate buddy"));
+ if (convctx->convctx_type == convctx_conv) {
+ conv = convctx->conv;
+ } else if (convctx->convctx_type == convctx_ctx) {
+ conv = otrg_plugin_context_to_conv(convctx->context, 0);
+ } else {
+ return;
+ }
+
+ gtkconv = PIDGIN_CONVERSATION ( conv );
+ win = pidgin_conv_get_window ( gtkconv );
- otr_set_menu_labels(conv, buddymenuquery, buddymenuend, buddymenusmp);
+ GtkWidget *buddymenuquery = gtk_menu_item_new_with_mnemonic(
+ _("Start _private conversation"));
+ GtkWidget *buddymenuend = gtk_menu_item_new_with_mnemonic(
+ _("_End private conversation"));
+ GtkWidget *buddymenusmp = gtk_menu_item_new_with_mnemonic(
+ _("_Authenticate buddy"));
+
+ otr_set_menu_labels(convctx, buddymenuquery, buddymenuend, buddymenusmp);
/* Empty out the menu */
gtk_container_foreach(GTK_CONTAINER(menu), destroy_menuitem, NULL);
@@ -1928,13 +2105,12 @@ static void build_otr_menu(PurpleConversation *conv, GtkWidget *menu,
gtk_widget_show(buddymenusmp);
gtk_signal_connect(GTK_OBJECT(buddymenuquery), "activate",
- GTK_SIGNAL_FUNC(otrg_gtk_dialog_clicked_connect), conv);
+ GTK_SIGNAL_FUNC(otrg_gtk_dialog_clicked_connect), conv);
gtk_signal_connect(GTK_OBJECT(buddymenuend), "activate",
- GTK_SIGNAL_FUNC(menu_end_private_conversation), conv);
+ GTK_SIGNAL_FUNC(menu_end_private_conversation), convctx);
gtk_signal_connect(GTK_OBJECT(buddymenusmp), "activate",
- GTK_SIGNAL_FUNC(socialist_millionaires), conv);
+ GTK_SIGNAL_FUNC(socialist_millionaires), convctx);
- otr_build_status_submenu(win, conv, menu, level);
}
static void otr_add_top_otr_menu(PurpleConversation *conv) {
@@ -1948,7 +2124,12 @@ static void otr_add_top_otr_menu(PurpleConversation *conv) {
GtkWidget *topmenuitem;
TrustLevel level = TRUST_NOT_PRIVATE;
- ConnContext *context = otrg_plugin_conv_to_context(conv);
+ ConnContext *context = otrg_plugin_conv_to_selected_context(conv, 1);
+
+ ConvOrContext *convctx;
+
+ GHashTable * conv_or_ctx_map = purple_conversation_get_data(conv,
+ "otr-convorctx");
int pos = otr_get_menu_insert_pos(conv);
@@ -1956,12 +2137,22 @@ static void otr_add_top_otr_menu(PurpleConversation *conv) {
topmenuitem = gtk_menu_item_new_with_label ( "OTR" );
topmenu = gtk_menu_new();
-
+
if (context != NULL) {
- level = otrg_plugin_context_to_trust(context);
+ level = otrg_plugin_context_to_trust(context);
+ }
+
+ convctx = g_hash_table_lookup(conv_or_ctx_map, conv);
+
+ if (!convctx) {
+ convctx = malloc(sizeof(ConvOrContext));
+ g_hash_table_insert(conv_or_ctx_map, conv, (gpointer)convctx);
}
-
- build_otr_menu(conv, topmenu, level);
+
+ convctx->convctx_type = convctx_conv;
+ convctx->conv = conv;
+ build_otr_menu(convctx, topmenu, level);
+ otr_build_status_submenu(win, convctx, topmenu, level);
gtk_menu_item_set_submenu ( GTK_MENU_ITEM ( topmenuitem ), topmenu );
@@ -1970,6 +2161,8 @@ static void otr_add_top_otr_menu(PurpleConversation *conv) {
gtk_menu_shell_insert ( GTK_MENU_SHELL ( menu_bar ), topmenuitem, pos++ );
+ g_signal_connect(G_OBJECT(topmenuitem), "destroy",
+ G_CALLBACK(otr_menu_destroy), win);
menu_list = g_list_append(menu_list, topmenuitem);
@@ -1981,175 +2174,642 @@ static GList* otr_get_full_buddy_list(PurpleConversation *conv) {
GList *pres_list = NULL;
GList *conv_list = NULL;
-
+
GSList *l, *buds;
/* This code is derived from pidgin's 'generating sendto menu' stuff */
if ( gtkconv->active_conv->type == PURPLE_CONV_TYPE_IM ) {
- buds = purple_find_buddies ( gtkconv->active_conv->account, gtkconv->active_conv->name );
-
- if ( buds == NULL) { /* buddy not on list */
- conv_list = g_list_prepend ( conv_list, conv);
- } else {
- for ( l = buds; l != NULL; l = l->next ) {
- PurpleBlistNode *node = ( PurpleBlistNode * ) purple_buddy_get_contact ( ( PurpleBuddy * ) l->data );
-
- for ( node = node->child; node != NULL; node = node->next ) {
- PurpleBuddy *buddy = ( PurpleBuddy * ) node;
- PurpleAccount *account;
-
- if ( !PURPLE_BLIST_NODE_IS_BUDDY ( node ) )
- continue;
-
- account = purple_buddy_get_account ( buddy );
- if ( purple_account_is_connected ( account ) ) {
- /* Use the PurplePresence to get unique buddies. */
- PurplePresence *presence = purple_buddy_get_presence ( buddy );
- if ( !g_list_find ( pres_list, presence ) ) {
-
- PurpleConversation * currentConv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, \
- purple_buddy_get_name ( buddy ), purple_buddy_get_account ( buddy ));
-
- pres_list = g_list_prepend ( pres_list, presence );
-
- if (currentConv != NULL) {
- conv_list = g_list_prepend ( conv_list, currentConv);
- }
-
- }
- }
- }
- }
-
- g_slist_free ( buds );
- g_list_free( pres_list );
- }
- }
-
+ buds = purple_find_buddies ( gtkconv->active_conv->account,
+ gtkconv->active_conv->name );
+
+ if ( buds == NULL) { /* buddy not on list */
+ conv_list = g_list_prepend ( conv_list, conv);
+ } else {
+ for ( l = buds; l != NULL; l = l->next ) {
+ PurpleBlistNode *node = ( PurpleBlistNode * )
+ purple_buddy_get_contact ( ( PurpleBuddy * ) l->data );
+
+ for ( node = node->child; node != NULL; node = node->next ) {
+ PurpleBuddy *buddy = ( PurpleBuddy * ) node;
+ PurpleAccount *account;
+
+ if ( !PURPLE_BLIST_NODE_IS_BUDDY ( node ) )
+ continue;
+
+ account = purple_buddy_get_account ( buddy );
+ if ( purple_account_is_connected ( account ) ) {
+ /* Use the PurplePresence to get unique buddies. */
+ PurplePresence *presence =
+ purple_buddy_get_presence( buddy );
+ if ( !g_list_find ( pres_list, presence ) ) {
+
+ PurpleConversation * currentConv =
+ purple_find_conversation_with_account(
+ PURPLE_CONV_TYPE_IM, \
+ purple_buddy_get_name ( buddy ),
+ purple_buddy_get_account ( buddy ));
+
+ pres_list = g_list_prepend ( pres_list, presence );
+
+ if (currentConv != NULL) {
+ conv_list = g_list_prepend ( conv_list,
+ currentConv );
+ }
+
+ }
+ }
+ }
+ }
+
+ g_slist_free ( buds );
+ g_list_free( pres_list );
+ }
+ }
+
return conv_list;
}
-static void otr_add_buddy_top_menus(PurpleConversation *conv) {
- PidginConversation *gtkconv = PIDGIN_CONVERSATION ( conv );
- PidginWindow *win = pidgin_conv_get_window ( gtkconv );
-
- PurpleConversation * currentConv;
+static void unselect_meta_ctx(PurpleConversation *conv) {
+ GtkWidget *select_best = (GtkWidget *) purple_conversation_get_data(conv,
+ "otr-select_best");
+ GtkWidget *select_recent = (GtkWidget *) purple_conversation_get_data(conv,
+ "otr-select_recent");
+
+ GTK_CHECK_MENU_ITEM(select_recent)->active = 0;
+ GTK_CHECK_MENU_ITEM(select_best)->active = 0;
+}
+
+static void select_meta_ctx(GtkWidget *widget, gpointer data) {
+ PurpleConversation *conv = (PurpleConversation *) data;
+ GtkWidget *select_best = (GtkWidget *) purple_conversation_get_data(conv,
+ "otr-select_best");
+ GtkWidget *select_recent = (GtkWidget *) purple_conversation_get_data(conv,
+ "otr-select_recent");
+ gboolean value = gtk_check_menu_item_get_active(
+ GTK_CHECK_MENU_ITEM(widget));
+ otrl_instag_t selected_instance = (otrl_instag_t)
+ purple_conversation_get_data(conv, "otr-ui_selected_ctx");
+ ConnContext * context = NULL;
+ ConnContext * recent_context = NULL;
+
+ if (widget == select_best) {
+ GTK_CHECK_MENU_ITEM(select_recent)->active = !value;
+
+ if (value) {
+ selected_instance = OTRL_INSTAG_BEST;
+ purple_conversation_set_data(conv, "otr-ui_selected_ctx",
+ (gpointer)selected_instance);
+ context = (ConnContext *) otrg_plugin_conv_to_selected_context(conv,
+ 1);
+
+ recent_context = (ConnContext *) otrg_plugin_conv_to_context(conv,
+ OTRL_INSTAG_RECENT_RECEIVED, 0);
+ if (context != recent_context) {
+ gchar *buf = g_strdup_printf(_("Warning: The selected outgoing "
+ "OTR session %u (%x) is not the most recently active "
+ "one %u (%x). Your buddy may not receive your messages."
+ " Use the icon menu above to select a different "
+ "outgoing session."), get_context_instance_to_index(
+ conv, context), context->their_instance,
+ get_context_instance_to_index(conv, recent_context),
+ recent_context->their_instance);
+ otrg_gtk_dialog_display_otr_message(context->accountname,
+ context->protocol, context->username, buf, 0);
+ g_free(buf);
+ }
+ }
+
+ } else if (widget == select_recent) {
+ GTK_CHECK_MENU_ITEM(select_best)->active = !value;
+
+ if (value) {
+ selected_instance = OTRL_INSTAG_RECENT_RECEIVED;
+ purple_conversation_set_data(conv, "otr-ui_selected_ctx",
+ (gpointer)selected_instance);
+ }
+ }
+
+ if (!context) context = (ConnContext *)
+ otrg_plugin_conv_to_selected_context(conv, 1);
+ dialog_update_label(context);
+}
+
+static void select_menu_ctx(GtkWidget *widget, gpointer data) {
+ ConnContext *context = (ConnContext *) data;
+ PurpleConversation * conv = otrg_plugin_context_to_conv(context, 1);
+ ConnContext *recent_context = (ConnContext *) otrg_plugin_conv_to_context(
+ conv, (otrl_instag_t)OTRL_INSTAG_RECENT_RECEIVED, 0);
+ otrl_instag_t selected_instance = (otrl_instag_t)
+ purple_conversation_get_data(conv, "otr-ui_selected_ctx");
+
+ selected_instance = context->their_instance;
+ purple_conversation_set_data(conv, "otr-ui_selected_ctx",
+ (gpointer)selected_instance);
+
+ unselect_meta_ctx(conv);
+
+ pidgin_conv_switch_active_conversation(conv);
+ dialog_update_label(context);
+
+ if (context != recent_context) {
+ gchar *buf = g_strdup_printf(_("Warning: The selected outgoing OTR "
+ "session %u (%x) is not the most recently active one %u (%x). "
+ "Your buddy may not receive your messages. Use the icon menu "
+ "above to select a different outgoing session."),
+ get_context_instance_to_index(conv, context),
+ context->their_instance,
+ get_context_instance_to_index(conv, recent_context),
+ recent_context->their_instance);
+ otrg_gtk_dialog_display_otr_message(context->accountname,
+ context->protocol, context->username, buf, 0);
+ g_free(buf);
+ }
+}
+
+static void build_meta_instance_submenu( PurpleConversation *conv,
+ GtkWidget *menu) {
+ GtkWidget *menusep = gtk_separator_menu_item_new();
+ GtkWidget *select_best = gtk_check_menu_item_new_with_label(
+ _("Send to most secure"));
+ GtkWidget *select_recent = gtk_check_menu_item_new_with_label(
+ _("Send to most recent"));
+ otrl_instag_t selected_instance;
+ gboolean selected_existed = g_hash_table_lookup_extended(conv->data,
+ "otr-ui_selected_ctx", NULL, (void**)&selected_instance);
+
+ if (selected_existed) {
+ if (selected_instance == OTRL_INSTAG_BEST) {
+ GTK_CHECK_MENU_ITEM(select_recent)->active = 0;
+ GTK_CHECK_MENU_ITEM(select_best)->active = 1;
+ } else if (selected_instance == OTRL_INSTAG_RECENT_RECEIVED) {
+ GTK_CHECK_MENU_ITEM(select_recent)->active = 1;
+ GTK_CHECK_MENU_ITEM(select_best)->active = 0;
+ } else {
+ GTK_CHECK_MENU_ITEM(select_recent)->active = 0;
+ GTK_CHECK_MENU_ITEM(select_best)->active = 0;
+ }
+ } else {
+ GTK_CHECK_MENU_ITEM(select_recent)->active = 0;
+ GTK_CHECK_MENU_ITEM(select_best)->active = 1;
+ }
+
+ purple_conversation_set_data(conv, "otr-select_best", select_best);
+ purple_conversation_set_data(conv, "otr-select_recent", select_recent);
+
+ gtk_signal_connect(GTK_OBJECT(select_best), "toggled",
+ GTK_SIGNAL_FUNC(select_meta_ctx), conv);
+ gtk_signal_connect(GTK_OBJECT(select_recent), "toggled",
+ GTK_SIGNAL_FUNC(select_meta_ctx), conv);
+
+ gtk_widget_show(menusep);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menusep);
+ gtk_widget_show(select_best);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_best);
+ gtk_widget_show(select_recent);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_recent);
+}
+
+static void otr_add_buddy_instances_top_menu(PidginConversation *gtkconv, GList
+ *instances, gboolean active_conv, char *username, const char
+ *accountname, int *pos) {
+ PidginWindow *win = pidgin_conv_get_window ( gtkconv );
GtkWidget *menu_bar = win->menu.menubar;
+ GtkWidget *menu;
+ GtkWidget *menu_image;
+ GtkWidget * tooltip_menu;
+ gchar *tooltip_text;
+ PurpleAccount *account;
+ otrl_instag_t instance;
+ gboolean selection_exists = 0;
+ ConnContext * context = instances->data;
+ TrustLevel level = TRUST_NOT_PRIVATE;
+ GHashTable * conv_or_ctx_map;
+ PurpleConversation * conv = NULL;
+ ConvOrContext convctx;
+ GList * menu_list;
+ guint num_active_instances = g_list_length(instances);
+
+ menu = gtk_menu_new();
+
+ conv = otrg_plugin_context_to_conv(context, 0);
+ selection_exists = g_hash_table_lookup_extended(conv->data,
+ "otr-ui_selected_ctx", NULL, (void**)&instance);
+
+ /* Find the selected or default instance */
+ if (selection_exists) {
+ context = otrl_context_find(otrg_plugin_userstate,
+ context->username, context->accountname, context->protocol,
+ instance, 0, NULL, NULL, NULL);
+ } else {
+ context = otrl_context_find(otrg_plugin_userstate,
+ context->username, context->accountname, context->protocol,
+ OTRL_INSTAG_BEST, 0, NULL, NULL, NULL);
+ }
+
+ menu = gtk_menu_new();
+
+ conv_or_ctx_map = purple_conversation_get_data(conv, "otr-convorctx");
+
+ for (; instances; instances = instances->next) {
+ GtkWidget *instance_menu_item;
+ GtkWidget *instance_submenu;
+ gchar text[35] ;
+ ConnContext *curr_context = instances->data;
+ ConvOrContext * curr_convctx = g_hash_table_lookup(conv_or_ctx_map,
+ curr_context);
+ gboolean selected = (curr_context->their_instance ==
+ context->their_instance);
+ gint instance_i = -1;
+
+ if (curr_context->their_instance == OTRL_INSTAG_MASTER &&
+ curr_context->msgstate == OTRL_MSGSTATE_PLAINTEXT) {
+ continue;
+ }
+
+ if (!curr_convctx) {
+ curr_convctx = malloc(sizeof(ConvOrContext));
+ g_hash_table_insert(conv_or_ctx_map, curr_context,
+ (gpointer)curr_convctx);
+ curr_convctx->convctx_type = convctx_ctx;
+ curr_convctx->context = curr_context;
+ }
+
+
+ instance_i = get_context_instance_to_index(conv, curr_context);
+
+ g_snprintf(text, 35, _("Session %u (%x)"), instance_i,
+ curr_context->their_instance);
+
+ instance_menu_item = gtk_image_menu_item_new_with_label(text);
+ instance_submenu = gtk_menu_new();
+
+ level = otrg_plugin_context_to_trust(curr_context);
+ menu_image = otr_icon(NULL, level, selected);
+
+ gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(instance_menu_item),
+ menu_image);
+ gtk_image_menu_item_set_always_show_image(
+ GTK_IMAGE_MENU_ITEM(instance_menu_item), 1);
+
+ build_otr_menu(curr_convctx, instance_submenu, level);
+
+ if (!selection_exists || instance != curr_context->their_instance) {
+ GtkWidget *select_ctx = gtk_menu_item_new_with_label(_("Select"));
+ GtkWidget *menusep = gtk_separator_menu_item_new();
+
+ gtk_signal_connect(GTK_OBJECT(select_ctx), "activate",
+ GTK_SIGNAL_FUNC(select_menu_ctx), curr_context);
+
+ gtk_menu_shell_prepend(GTK_MENU_SHELL(instance_submenu), menusep);
+ gtk_widget_show(menusep);
+
+ gtk_menu_shell_prepend(GTK_MENU_SHELL(instance_submenu),
+ select_ctx);
+ gtk_widget_show(select_ctx);
+ } else if (selection_exists &&
+ instance == curr_context->their_instance) {
+ GtkWidget *selected_ctx =
+ gtk_menu_item_new_with_label(_("Selected"));
+ GtkWidget *menusep = gtk_separator_menu_item_new();
+
+ gtk_signal_connect(GTK_OBJECT(selected_ctx), "select",
+ GTK_SIGNAL_FUNC(force_deselect), NULL);
+
+ gtk_menu_shell_prepend(GTK_MENU_SHELL(instance_submenu), menusep);
+ gtk_widget_show(menusep);
+
+ gtk_menu_shell_prepend(GTK_MENU_SHELL(instance_submenu),
+ selected_ctx);
+ gtk_widget_show(selected_ctx);
+ }
+
+ gtk_widget_show(menu_image);
+ gtk_widget_show(instance_menu_item);
+ gtk_widget_show(instance_submenu);
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (instance_menu_item),
+ instance_submenu);
+
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), instance_menu_item);
+
+ }
+
+
+ level = otrg_plugin_context_to_trust(context);
+ menu_image = otr_icon(NULL, level, active_conv);
+ convctx.convctx_type = convctx_ctx;
+ convctx.context = context;
+
+ build_meta_instance_submenu(conv, menu);
+
+ otr_build_status_submenu(win, &convctx, menu, level);
+
+ tooltip_menu = tooltip_menu_new();
+
+ gtk_widget_show ( menu_image );
+ gtk_widget_show(tooltip_menu);
+ gtk_menu_shell_insert ( GTK_MENU_SHELL(menu_bar), tooltip_menu, (*pos)++);
+ gtk_menu_item_set_submenu ( GTK_MENU_ITEM(tooltip_menu), menu);
+
+ tooltip_text = g_strdup_printf("%s (%s)", username, accountname);
+ tooltip_menu_prepend(TOOLTIP_MENU(tooltip_menu), menu_image, tooltip_text);
+ g_free(tooltip_text);
+
+ menu_list = g_hash_table_lookup ( otr_win_menus, win );
+
+ g_signal_connect(G_OBJECT(tooltip_menu), "destroy",
+ G_CALLBACK(otr_menu_destroy), win);
+
+ menu_list = g_list_append(menu_list, tooltip_menu);
+
+ g_hash_table_replace ( otr_win_menus, win, menu_list );
+}
+static void otr_add_buddy_top_menu(PidginConversation *gtkconv, ConvOrContext
+ *convctx, gboolean active_conv, char *username, const char
+ *accountname, int *pos) {
+ PidginWindow *win = pidgin_conv_get_window ( gtkconv );
+ GtkWidget *menu_bar = win->menu.menubar;
GtkWidget *menu;
GtkWidget *menu_image;
+ TrustLevel level;
+ ConnContext *context;
+ GList * menu_list;
+ GtkWidget * tooltip_menu;
+ gchar *tooltip_text;
+ PurpleAccount *account;
+ GtkWidget *select_ctx = NULL;
+
+ if (convctx->convctx_type == convctx_ctx) {
+ context = convctx->context;
+ } else if (convctx->convctx_type == convctx_conv) {
+ context = otrg_plugin_conv_to_selected_context(convctx->conv, 0);
+ }
+
+ level = TRUST_NOT_PRIVATE;
+
+ if (context != NULL) {
+ level = otrg_plugin_context_to_trust(context);
+ }
+
+ menu_image = otr_icon(NULL, level, active_conv);
+
+ menu = gtk_menu_new();
+
+ build_otr_menu(convctx, menu, level);
+ otr_build_status_submenu(win, convctx, menu, level);
+
+ if (!active_conv) {
+ select_ctx = gtk_menu_item_new_with_label(_("Select"));
+
+ gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), select_ctx);
+ gtk_widget_show(select_ctx);
+
+ gtk_signal_connect(GTK_OBJECT(select_ctx), "activate",
+ GTK_SIGNAL_FUNC(select_menu_ctx), context);
+ }
+
+ tooltip_menu = tooltip_menu_new();
+
+ gtk_widget_show ( menu_image );
+ gtk_widget_show(tooltip_menu);
+ gtk_menu_shell_insert ( GTK_MENU_SHELL(menu_bar), tooltip_menu, (*pos)++);
+ gtk_menu_item_set_submenu ( GTK_MENU_ITEM ( tooltip_menu ), menu );
+
+ tooltip_text = g_strdup_printf("%s (%s)", username, accountname);
+ tooltip_menu_prepend(TOOLTIP_MENU(tooltip_menu), menu_image, tooltip_text);
+ g_free(tooltip_text);
+
+ menu_list = g_hash_table_lookup ( otr_win_menus, win );
+
+ g_signal_connect(G_OBJECT(tooltip_menu), "destroy",
+ G_CALLBACK(otr_menu_destroy), win);
+
+ menu_list = g_list_append(menu_list, tooltip_menu);
+
+ g_hash_table_replace ( otr_win_menus, win, menu_list );
+}
+
+static void otr_add_buddy_top_menus(PurpleConversation *conv) {
+ PidginConversation *gtkconv = PIDGIN_CONVERSATION ( conv );
+
+ PurpleConversation * currentConv = NULL; /* Auxiliary variables re-used */
+ ConnContext *currentContext = NULL; /* within loops. */
GList *full_buddy_list = NULL;
- GList * list_iter;
-
- int pos;
-
+ GList *list_iter;
+
+ int pos = otr_get_menu_insert_pos(conv);
+
+
+ GHashTable *conv_to_context_map = g_hash_table_new(g_direct_hash,
+ g_direct_equal);
+
+ GHashTable * conv_or_ctx_map = purple_conversation_get_data(conv,
+ "otr-convorctx");
+
full_buddy_list = otr_get_full_buddy_list(conv);
list_iter = full_buddy_list;
- pos = otr_get_menu_insert_pos(conv);
-
- for (list_iter = g_list_last ( full_buddy_list ); list_iter != NULL; list_iter = list_iter->prev) {
- TrustLevel level;
- ConnContext *context;
- GList * menu_list;
- GtkWidget * tooltip_menu;
- gchar *tooltip_text;
-
- currentConv = list_iter->data;
-
- if (currentConv == NULL) {
- continue;
- }
-
- if (purple_conversation_get_type(currentConv) != PURPLE_CONV_TYPE_IM) continue;
-
- level = TRUST_NOT_PRIVATE;
- context = otrg_plugin_conv_to_context(currentConv);
-
- if (context != NULL) {
- level = otrg_plugin_context_to_trust(context);
- }
-
- menu_image = otr_icon(NULL, level, 1);
-
- if (currentConv == gtkconv->active_conv) {
- menu_image = otr_icon(menu_image, level, 1);
- } else {
- menu_image = otr_icon(menu_image, level, 0);
- }
- menu = gtk_menu_new();
-
- build_otr_menu(currentConv, menu, level);
-
- tooltip_menu = tooltip_menu_new();
-
- gtk_widget_show ( menu_image );
- gtk_widget_show(tooltip_menu);
- gtk_menu_shell_insert ( GTK_MENU_SHELL ( menu_bar ), tooltip_menu, pos++ );
- gtk_menu_item_set_submenu ( GTK_MENU_ITEM ( tooltip_menu ), menu );
-
- tooltip_text = g_strdup_printf("%s (%s)", currentConv->name, purple_account_get_username(currentConv->account));
- tooltip_menu_prepend(TOOLTIP_MENU(tooltip_menu), menu_image, tooltip_text);
- g_free(tooltip_text);
-
- menu_list = g_hash_table_lookup ( otr_win_menus, win );
- menu_list = g_list_append(menu_list, tooltip_menu);
-
- g_hash_table_replace ( otr_win_menus, win, menu_list );
-
-
- }
-
+ /* First determine how many contexts are associated with each conv */
+ for (list_iter = g_list_last ( full_buddy_list ); list_iter != NULL;
+ list_iter = list_iter->prev) {
+ int numContexts = 0;
+ PurpleAccount *account;
+ char *username;
+ const char *accountname, *proto;
+
+ currentConv = list_iter->data;
+
+ if (currentConv == NULL) {
+ continue;
+ }
+
+ if (purple_conversation_get_type(currentConv) != PURPLE_CONV_TYPE_IM) {
+ continue;
+ }
+
+ account = purple_conversation_get_account(currentConv);
+ accountname = purple_account_get_username(account);
+ proto = purple_account_get_protocol_id(account);
+ username = g_strdup(purple_normalize(account,
+ purple_conversation_get_name(currentConv)));
+ GList * contexts = NULL;
+
+ for (currentContext = otrg_plugin_userstate->context_root;
+ currentContext != NULL;
+ currentContext = currentContext->next) {
+
+ if (!strcmp(currentContext->accountname, accountname) &&
+ !strcmp(currentContext->protocol, proto) &&
+ !strcmp(currentContext->username, username)) {
+ contexts = g_list_append(contexts, currentContext);
+ }
+ }
+
+ g_hash_table_insert(conv_to_context_map,
+ currentConv, (gpointer) contexts);
+
+ }
+
+ list_iter = full_buddy_list;
+
+ for (list_iter = g_list_last ( full_buddy_list ); list_iter != NULL;
+ list_iter = list_iter->prev) {
+ GList * contexts = NULL;
+ GList * contexts_iter = NULL;
+ gboolean active_conv = 0;
+ ConvOrContext * convctx = NULL;
+ ConnContext * m_context = NULL;
+ PurpleAccount * account = NULL;
+ char * username = NULL;
+ const char * accountname = NULL;
+ int num_contexts = 0;
+
+ currentConv = list_iter->data;
+
+ if (currentConv == NULL) {
+ continue;
+ }
+
+ active_conv = (currentConv == gtkconv->active_conv);
+
+ contexts = (GList *) g_hash_table_lookup(conv_to_context_map,
+ currentConv);
+
+ if (purple_conversation_get_type(currentConv) != PURPLE_CONV_TYPE_IM) {
+ continue;
+ }
+
+ num_contexts = g_list_length(contexts);
+
+ if (num_contexts > 1) {
+ /* We will need the master context */
+ currentContext = (ConnContext *) contexts->data;
+
+ m_context = currentContext->m_context;
+ }
+
+ if (num_contexts <= 1) {
+ /* Just add a menu for the possibly not yet created master inst */
+ convctx = g_hash_table_lookup(conv_or_ctx_map, currentConv);
+
+ if (!convctx) {
+ convctx = malloc(sizeof(ConvOrContext));
+ g_hash_table_insert(conv_or_ctx_map, currentConv,
+ (gpointer)convctx);
+ convctx->convctx_type = convctx_conv;
+ convctx->conv = currentConv;
+ }
+
+ account = purple_conversation_get_account(currentConv);
+ accountname = purple_account_get_username(account);
+ username = g_strdup(
+ purple_normalize(account,
+ purple_conversation_get_name(currentConv)));
+
+ otr_add_buddy_top_menu(gtkconv, convctx, active_conv, username,
+ accountname, &pos);
+ g_free(username);
+
+ } else if (num_contexts == 2 &&
+ m_context->msgstate == OTRL_MSGSTATE_PLAINTEXT) {
+ /* Just add a menu for the non_master instance */
+ contexts_iter = contexts;
+ currentContext = contexts_iter->data;
+
+ while (currentContext->their_instance == OTRL_INSTAG_MASTER &&
+ contexts_iter->next != NULL) {
+ contexts_iter = contexts_iter->next;
+ currentContext = contexts_iter->data;
+ }
+
+ convctx = g_hash_table_lookup(conv_or_ctx_map, currentContext);
+
+ if (!convctx) {
+ convctx = malloc(sizeof(ConvOrContext));
+ g_hash_table_insert(conv_or_ctx_map, currentContext,
+ (gpointer)convctx);
+ convctx->convctx_type = convctx_ctx;
+ convctx->context = currentContext;
+ }
+
+ otr_add_buddy_top_menu(gtkconv, convctx, active_conv,
+ currentContext->username, currentContext->accountname,
+ &pos);
+
+ } else {
+ /* Multi-instances */
+ purple_conversation_set_data(currentConv,
+ "otr-conv_multi_instances", (gpointer)1);
+ otr_add_buddy_instances_top_menu(gtkconv, contexts, active_conv,
+ currentContext->username, currentContext->accountname,
+ &pos);
+ }
+
+ if (contexts) {
+ g_list_free(contexts);
+ }
+ }
+
+ g_hash_table_destroy (conv_to_context_map);
g_list_free ( full_buddy_list );
}
+
static void otr_check_conv_status_change( PurpleConversation *conv) {
PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
TrustLevel current_level = TRUST_NOT_PRIVATE;
- ConnContext *context = otrg_plugin_conv_to_context(conv);
-
+ ConnContext *context = otrg_plugin_conv_to_context(conv,
+ OTRL_INSTAG_RECENT, 0);
+ otrl_instag_t last_received_instance;
+ gboolean have_received = 0;
+
int *previous_level;
char *buf;
char *status = "";
-
+
if (context != NULL) {
- current_level = otrg_plugin_context_to_trust(context);
+ current_level = otrg_plugin_context_to_trust(context);
}
-
- previous_level = g_hash_table_lookup ( otr_win_status, gtkconv );
-
- if (!previous_level || (previous_level && *previous_level == current_level)) {
- return;
+
+ previous_level = g_hash_table_lookup ( otr_win_status, gtkconv );
+
+ if (!previous_level ||
+ (previous_level && *previous_level == current_level)) {
+ return;
}
-
- buf = _("The privacy status of the current conversation is now: <a href=\"%s%s\">%s</a>");
-
+
+ buf = _("The privacy status of the current conversation is now: "
+ "<a href=\"%s%s\">%s</a>");
+
switch(current_level) {
- case TRUST_NOT_PRIVATE:
- status = _("Not Private");
- break;
- case TRUST_UNVERIFIED:
- status = _("Unverified");
- break;
- case TRUST_PRIVATE:
- status = _("Private");
- break;
- case TRUST_FINISHED:
- status = _("Finished");
- break;
- }
-
+ case TRUST_NOT_PRIVATE:
+ status = _("Not Private");
+ break;
+ case TRUST_UNVERIFIED:
+ status = _("Unverified");
+ break;
+ case TRUST_PRIVATE:
+ status = _("Private");
+ break;
+ case TRUST_FINISHED:
+ status = _("Finished");
+ break;
+ }
+
buf = g_strdup_printf(buf, LEVELS_HELPURL, _("?lang=en"), status);
-
- /* Write a new message indicating the level change. The timestamp image will be appended as the message
- timestamp signal is caught, which will also update the privacy level for this gtkconv */
- purple_conversation_write(conv, NULL, buf, PURPLE_MESSAGE_SYSTEM, time(NULL));
-
+
+ /* Write a new message indicating the level change. The timestamp image will
+ * be appended as the message timestamp signal is caught, which will also
+ * update the privacy level for this gtkconv */
+ purple_conversation_write(conv, NULL, buf, PURPLE_MESSAGE_SYSTEM,
+ time(NULL));
+
g_free(buf);
+
}
/* If the conversation switches on us */
@@ -2164,13 +2824,23 @@ static void conversation_switched ( PurpleConversation *conv, void * data ) {
* pointing to it. */
static void conversation_destroyed(PurpleConversation *conv, void *data)
{
- GtkWidget *menu = purple_conversation_get_data(conv, "otr-menu");
+ GtkWidget *menu = (GtkWidget *) purple_conversation_get_data(conv,
+ "otr-menu");
PidginConversation *gtkconv;
PidginWindow *win;
- GList * menu_list;
GList * iter;
-
+ GHashTable * conv_or_ctx_map;
+ GHashTable * conv_to_idx_map;
+
+
if (menu) gtk_object_destroy(GTK_OBJECT(menu));
+
+ conv_or_ctx_map = purple_conversation_get_data(conv, "otr-convorctx");
+ g_hash_table_destroy(conv_or_ctx_map);
+
+ conv_to_idx_map = purple_conversation_get_data(conv, "otr-conv_to_idx");
+ g_hash_table_destroy(conv_to_idx_map);
+
g_hash_table_remove(conv->data, "otr-label");
g_hash_table_remove(conv->data, "otr-button");
g_hash_table_remove(conv->data, "otr-icon");
@@ -2178,6 +2848,16 @@ static void conversation_destroyed(PurpleConversation *conv, void *data)
g_hash_table_remove(conv->data, "otr-private");
g_hash_table_remove(conv->data, "otr-authenticated");
g_hash_table_remove(conv->data, "otr-finished");
+ g_hash_table_remove(conv->data, "otr-select_best");
+ g_hash_table_remove(conv->data, "otr-select_recent");
+ g_hash_table_remove(conv->data, "otr-convorctx");
+ g_hash_table_remove(conv->data, "otr-conv_to_idx");
+ g_hash_table_remove(conv->data, "otr-max_idx");
+ g_hash_table_remove(conv->data, "otr-conv_multi_instances");
+ g_hash_table_remove(conv->data, "otr-warned_instances");
+ g_hash_table_remove(conv->data, "otr-last_msg_event");
+ g_hash_table_remove(conv->data, "otr-last_received_ctx");
+
#ifdef OLD_OTR_BUTTON
g_hash_table_remove(conv->data, "otr-icontext");
g_hash_table_remove(conv->data, "otr-menuquery");
@@ -2197,19 +2877,11 @@ static void conversation_destroyed(PurpleConversation *conv, void *data)
}
win = pidgin_conv_get_window ( gtkconv );
- menu_list = g_hash_table_lookup ( otr_win_menus, win );
- iter = menu_list;
- while ( iter ) {
- GList * next;
- if ( iter->data ) gtk_object_destroy ( GTK_OBJECT ( iter->data ) );
- next = iter->next;
- menu_list = g_list_remove ( menu_list, iter->data );
- iter = next;
- }
+ otr_clear_win_menu_list(win);
g_hash_table_remove(otr_win_menus, win);
- g_list_free(menu_list);
+
}
/* Set up the per-conversation information display */
@@ -2234,6 +2906,8 @@ static void otrg_gtk_dialog_new_purple_conv(PurpleConversation *conv)
*/
GtkWidget *menusmp;
GtkWidget *whatsthis;
+#else
+ ConvOrContext *convctx;
#endif
GtkWidget *icon;
GtkWidget *menu;
@@ -2242,6 +2916,9 @@ static void otrg_gtk_dialog_new_purple_conv(PurpleConversation *conv)
const char *name;
OtrgUiPrefs prefs;
+ GHashTable * conv_or_ctx_map;
+ GHashTable * ctx_to_idx_map;
+
/* Do nothing if this isn't an IM conversation */
if (purple_conversation_get_type(conv) != PURPLE_CONV_TYPE_IM) return;
@@ -2256,7 +2933,7 @@ static void otrg_gtk_dialog_new_purple_conv(PurpleConversation *conv)
bbox = gtkconv->toolbar;
#endif
- context = otrg_plugin_conv_to_context(conv);
+ context = otrg_plugin_conv_to_selected_context(conv, 0);
/* See if we're already set up */
button = purple_conversation_get_data(conv, "otr-button");
@@ -2279,6 +2956,15 @@ static void otrg_gtk_dialog_new_purple_conv(PurpleConversation *conv)
return;
}
+ conv_or_ctx_map = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
+ free);
+ purple_conversation_set_data(conv, "otr-convorctx", conv_or_ctx_map);
+
+ ctx_to_idx_map = g_hash_table_new(g_direct_hash, g_direct_equal);
+ purple_conversation_set_data(conv, "otr-conv_to_idx", ctx_to_idx_map);
+
+ purple_conversation_set_data(conv, "otr-max_idx", (gpointer) 0);
+
/* Make the button */
button = gtk_button_new();
@@ -2362,7 +3048,13 @@ static void otrg_gtk_dialog_new_purple_conv(PurpleConversation *conv)
gtk_menu_shell_append(GTK_MENU_SHELL(menu), whatsthis);
gtk_widget_show(whatsthis);
#else
- build_otr_menu(conv, menu, TRUST_NOT_PRIVATE);
+ convctx = malloc(sizeof(ConvOrContext));
+ convctx->convctx_type = convctx_conv;
+ convctx->conv = conv;
+ g_hash_table_replace ( conv_or_ctx_map, conv, convctx );
+ build_otr_menu(convctx, menu, TRUST_NOT_PRIVATE);
+ otr_build_status_submenu(pidgin_conv_get_window(gtkconv), convctx, menu,
+ TRUST_NOT_PRIVATE);
#endif
purple_conversation_set_data(conv, "otr-label", label);
@@ -2449,7 +3141,7 @@ static void dialog_resensitize(PurpleConversation *conv)
if (prefs.policy == OTRL_POLICY_NEVER) {
otrg_gtk_dialog_remove_conv(conv);
} else {
- otrg_gtk_dialog_new_conv(conv);
+ otrg_gtk_dialog_new_conv(conv);
}
button = purple_conversation_get_data(conv, "otr-button");
if (!button) return;
@@ -2457,7 +3149,7 @@ static void dialog_resensitize(PurpleConversation *conv)
connection = purple_account_get_connection(account);
if (connection) {
/* Set the button to "sensitive" */
- gtk_widget_set_sensitive(button, 1);
+ gtk_widget_set_sensitive(button, 1);
return;
}
}
@@ -2473,86 +3165,124 @@ static void otrg_gtk_dialog_resensitize_all(void)
}
static void foreach_free_lists(void * key, void * value, void* data) {
- GList * menu_list = (GList *) value;
- GList * iter = menu_list;
-
- while ( iter ) {
- GList * next;
- if ( iter->data ) gtk_object_destroy ( GTK_OBJECT ( iter->data ) );
- next = iter->next;
- menu_list = g_list_remove ( menu_list, iter->data );
- iter = next;
- }
+ PidginWindow *win = (PidginWindow *) key;
- g_list_free(menu_list);
+ otr_clear_win_menu_list(win);
}
+
+
static char* conversation_timestamp(PurpleConversation *conv, time_t mtime,
- gboolean show_date) {
+ gboolean show_date) {
PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
TrustLevel current_level = TRUST_NOT_PRIVATE;
- ConnContext *context = otrg_plugin_conv_to_context(conv);
-
+ ConnContext *context = (ConnContext *) otrg_plugin_conv_to_context(conv,
+ OTRL_INSTAG_RECENT, 0);
int *previous_level;
int id;
-
-
+
+
if (context != NULL) {
- current_level = otrg_plugin_context_to_trust(context);
+ current_level = otrg_plugin_context_to_trust(context);
}
-
- previous_level = g_hash_table_lookup ( otr_win_status, gtkconv );
-
-
+
+ previous_level = g_hash_table_lookup ( otr_win_status, gtkconv );
+
+
if (previous_level && *previous_level == current_level) {
- return NULL;
+ return NULL;
}
-
- /* We want to update this gtkconv's privacy level only if the new privacy level we
- received corresponds to the active conversation. */
+
+ /* We want to update this gtkconv's privacy level only if the new privacy
+ * level we received corresponds to the active conversation. */
if (conv == gtkconv->active_conv) {
- int * current_level_ptr = malloc(sizeof(int)); /* 'free' is handled by the hashtable */
- *current_level_ptr = current_level;
- g_hash_table_replace ( otr_win_status, gtkconv, current_level_ptr );
+ /* 'free' is handled by the hashtable */
+ int * current_level_ptr = malloc(sizeof(int));
+ *current_level_ptr = current_level;
+ g_hash_table_replace ( otr_win_status, gtkconv, current_level_ptr );
}
-
+
if (!previous_level) {
- return NULL;
+ return NULL;
}
-
+
id = -1;
switch(current_level) {
- case TRUST_NOT_PRIVATE:
- id = img_id_not_private;
- break;
- case TRUST_UNVERIFIED:
- id = img_id_unverified;
- break;
- case TRUST_PRIVATE:
- id = img_id_private;
- break;
- case TRUST_FINISHED:
- id = img_id_finished;
- break;
- }
-
+ case TRUST_NOT_PRIVATE:
+ id = img_id_not_private;
+ break;
+ case TRUST_UNVERIFIED:
+ id = img_id_unverified;
+ break;
+ case TRUST_PRIVATE:
+ id = img_id_private;
+ break;
+ case TRUST_FINISHED:
+ id = img_id_finished;
+ break;
+ }
+
if (id > 0 ) {
- char * msg = g_strdup_printf("<IMG ID=\"%d\"> ", id);
- gtk_imhtml_append_text_with_images((GtkIMHtml*)gtkconv->imhtml, msg, 0, NULL);
- g_free(msg);
+ char * msg = g_strdup_printf("<IMG ID=\"%d\"> ", id);
+ gtk_imhtml_append_text_with_images((GtkIMHtml*)gtkconv->imhtml, msg, 0,
+ NULL);
+ g_free(msg);
}
-
-
+
+
return NULL;
}
+/* If the user has selected a meta instance, an incoming message may trigger an
+ * instance change... we need to update the GUI appropriately */
+static gboolean check_incoming_instance_change(PurpleAccount *account,
+ char *sender, char *message, PurpleConversation *conv,
+ PurpleMessageFlags flags) {
+ otrl_instag_t last_received_instance;
+ otrl_instag_t selected_instance;
+ gboolean have_received = 0;
+ ConnContext *received_context = NULL;
+ ConnContext *current_out = NULL;
+
+
+ if (!conv) {
+ return 0;
+ }
+
+ selected_instance = otrg_plugin_conv_to_selected_instag(conv, 0);
+ current_out = otrg_plugin_conv_to_selected_context(conv, 0);
+
+ have_received = g_hash_table_lookup_extended(conv->data,
+ "otr-last_received_ctx", NULL, (void**)&last_received_instance);
+ received_context = (ConnContext *) otrg_plugin_conv_to_context(conv,
+ (otrl_instag_t)OTRL_INSTAG_RECENT_RECEIVED, 0);
+
+ if (!received_context) {
+ return 0;
+ }
+
+ if (have_received &&
+ last_received_instance != received_context->their_instance &&
+ selected_instance != OTRL_INSTAG_MASTER &&
+ selected_instance <= 0xFF) {
+ dialog_update_label_conv(conv,
+ otrg_plugin_context_to_trust(current_out));
+ }
+
+ last_received_instance = received_context->their_instance;
+ purple_conversation_set_data(conv, "otr-last_received_ctx",
+ (gpointer)last_received_instance);
+
+ return 0;
+}
+
static void unref_img_by_id(int *id)
{
if (id && *id > 0) {
- purple_imgstore_unref_by_id(*id);
+ purple_imgstore_unref_by_id(*id);
*id = -1;
}
}
@@ -2573,26 +3303,27 @@ static void dialog_quitting(void)
static void otrg_gtk_dialog_init(void)
{
otr_win_menus = g_hash_table_new(g_direct_hash, g_direct_equal);
- otr_win_status = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, free);
-
-
+ otr_win_status = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
+ free);
+
+
img_id_not_private = purple_imgstore_add_with_id(
g_memdup(not_private_png, sizeof(not_private_png)),
sizeof(not_private_png), "");
-
+
img_id_unverified = purple_imgstore_add_with_id(
g_memdup(unverified_png, sizeof(unverified_png)),
sizeof(unverified_png), "");
-
+
img_id_private = purple_imgstore_add_with_id(
g_memdup(private_png, sizeof(private_png)),
sizeof(private_png), "");
-
+
img_id_finished = purple_imgstore_add_with_id(
g_memdup(finished_png, sizeof(finished_png)),
sizeof(finished_png), "");
-
+
purple_signal_connect(pidgin_conversations_get_handle(),
"conversation-switched", otrg_plugin_handle,
PURPLE_CALLBACK(conversation_switched), NULL);
@@ -2600,14 +3331,18 @@ static void otrg_gtk_dialog_init(void)
purple_signal_connect(purple_conversations_get_handle(),
"deleting-conversation", otrg_plugin_handle,
PURPLE_CALLBACK(conversation_destroyed), NULL);
-
+
purple_signal_connect(pidgin_conversations_get_handle(),
- "conversation-timestamp", otrg_plugin_handle,
- PURPLE_CALLBACK(conversation_timestamp), NULL);
+ "conversation-timestamp", otrg_plugin_handle,
+ PURPLE_CALLBACK(conversation_timestamp), NULL);
+
+ purple_signal_connect(purple_conversations_get_handle(),
+ "received-im-msg", otrg_plugin_handle,
+ PURPLE_CALLBACK(check_incoming_instance_change), NULL);
purple_signal_connect(purple_get_core(),
- "quitting", otrg_plugin_handle, PURPLE_CALLBACK(dialog_quitting),
- NULL);
+ "quitting", otrg_plugin_handle,
+ PURPLE_CALLBACK(dialog_quitting), NULL);
}
/* Deinitialize the OTR dialog subsystem */
@@ -2621,13 +3356,17 @@ static void otrg_gtk_dialog_cleanup(void)
PURPLE_CALLBACK(conversation_switched));
purple_signal_disconnect(pidgin_conversations_get_handle(),
- "conversation-timestamp", otrg_plugin_handle,
- PURPLE_CALLBACK(conversation_timestamp));
+ "conversation-timestamp", otrg_plugin_handle,
+ PURPLE_CALLBACK(conversation_timestamp));
purple_signal_disconnect(purple_conversations_get_handle(),
"deleting-conversation", otrg_plugin_handle,
PURPLE_CALLBACK(conversation_destroyed));
+ purple_signal_disconnect(pidgin_conversations_get_handle(),
+ "received-im-msg", otrg_plugin_handle,
+ PURPLE_CALLBACK(check_incoming_instance_change));
+
/* If we're quitting, the imgstore will already have been destroyed
* by purple, but we should have already called dialog_quitting(),
* so the img_id_* should be -1, and all should be OK. */
@@ -2635,11 +3374,11 @@ static void otrg_gtk_dialog_cleanup(void)
unref_img_by_id(&img_id_unverified);
unref_img_by_id(&img_id_private);
unref_img_by_id(&img_id_finished);
-
+
g_hash_table_foreach(otr_win_menus, foreach_free_lists, NULL);
g_hash_table_destroy(otr_win_menus);
-
+
g_hash_table_destroy(otr_win_status);
}
diff --git a/gtk-dialog.h b/gtk-dialog.h
index 07152b1..6eafbaa 100644
--- a/gtk-dialog.h
+++ b/gtk-dialog.h
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging plugin for pidgin
- * Copyright (C) 2004-2009 Ian Goldberg, Rob Smits,
+ * Copyright (C) 2004-2012 Ian Goldberg, Rob Smits,
* Chris Alexander, Willy Lew,
* Nikita Borisov
* <otr at cypherpunks.ca>
diff --git a/gtk-ui.c b/gtk-ui.c
index 29cc065..459097f 100644
--- a/gtk-ui.c
+++ b/gtk-ui.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging plugin for pidgin
- * Copyright (C) 2004-2009 Ian Goldberg, Rob Smits,
+ * Copyright (C) 2004-2012 Ian Goldberg, Rob Smits,
* Chris Alexander, Willy Lew,
* Nikita Borisov
* <otr at cypherpunks.ca>
@@ -91,7 +91,7 @@ static void account_menu_changed_cb(GtkWidget *item, PurpleAccount *account,
GtkWidget *fprint = ui_layout.fprint_label;
char s[100];
char *fingerprint;
-
+
if (account) {
char fingerprint_buf[45];
accountname = purple_account_get_username(account);
@@ -123,7 +123,9 @@ static void account_menu_changed_cb(GtkWidget *item, PurpleAccount *account,
* UI, if visible. */
static void otrg_gtk_ui_update_fingerprint(void)
{
- g_signal_emit_by_name(G_OBJECT(ui_layout.accountmenu), "changed");
+ if (ui_layout.accountmenu) {
+ g_signal_emit_by_name(G_OBJECT(ui_layout.accountmenu), "changed");
+ }
}
static void account_menu_added_removed_cb(PurpleAccount *account, void *data)
@@ -162,26 +164,54 @@ static void otrg_gtk_ui_update_keylist(void)
int i;
PurplePlugin *p;
char *proto_name;
+
+ if (context->their_instance != OTRL_INSTAG_MASTER) continue;
+
fingerprint = context->fingerprint_root.next;
/* If there's no fingerprint, don't add it to the known
* fingerprints list */
while(fingerprint) {
+ ConnContext *context_iter;
+ TrustLevel best_level = TRUST_NOT_PRIVATE;
+ int used = 0;
+
titles[0] = context->username;
- if (context->msgstate == OTRL_MSGSTATE_ENCRYPTED &&
- context->active_fingerprint != fingerprint) {
- titles[1] = _("Unused");
- } else {
+ titles[1] = _("Unused");
+
+ for (context_iter = context->m_context;
+ context_iter && context_iter->m_context == context->m_context;
+ context_iter = context_iter->next) {
+
+ TrustLevel this_level = TRUST_NOT_PRIVATE;
+
+ if (context_iter->active_fingerprint == fingerprint) {
+ this_level = otrg_plugin_context_to_trust(context_iter);
+ used = 1;
+
+ if (this_level == TRUST_PRIVATE) {
+ best_level = TRUST_PRIVATE;
+ } else if (this_level == TRUST_UNVERIFIED
+ && best_level != TRUST_PRIVATE) {
+ best_level = TRUST_UNVERIFIED;
+ } else if (this_level == TRUST_FINISHED
+ && best_level == TRUST_NOT_PRIVATE) {
+ best_level = TRUST_FINISHED;
+ }
+ }
+ }
+
+ if (used) {
titles[1] = (gchar *)
- _(trust_states[otrg_plugin_context_to_trust(context)]);
+ _(trust_states[best_level]);
}
titles[2] = (fingerprint->trust && fingerprint->trust[0]) ?
- _("Yes") : _("No");
+ _("Yes") : _("No");
otrl_privkey_hash_to_human(hash, fingerprint->fingerprint);
titles[3] = hash;
p = purple_find_prpl(context->protocol);
proto_name = (p && p->info->name) ? p->info->name : _("Unknown");
titles[4] = g_strdup_printf("%s (%s)", context->accountname,
- proto_name);
+ proto_name);
i = gtk_clist_append(GTK_CLIST(keylist), titles);
g_free(titles[4]);
gtk_clist_set_row_data(GTK_CLIST(keylist), i, fingerprint);
@@ -208,9 +238,9 @@ static void generate(GtkWidget *widget, gpointer data)
{
PurpleAccount *account;
account = pidgin_account_option_menu_get_selected(ui_layout.accountmenu);
-
+
if (account == NULL) return;
-
+
otrg_plugin_create_privkey(purple_account_get_username(account),
purple_account_get_protocol_id(account));
}
@@ -243,26 +273,33 @@ static void clist_selected(GtkWidget *widget, gint row, gint column,
int verify_sensitive = 0;
Fingerprint *f = gtk_clist_get_row_data(GTK_CLIST(ui_layout.keylist),
row);
- if (f && f->context->msgstate == OTRL_MSGSTATE_ENCRYPTED &&
- f->context->active_fingerprint == f) {
- disconnect_sensitive = 1;
- }
- if (f && f->context->msgstate == OTRL_MSGSTATE_FINISHED) {
- disconnect_sensitive = 1;
- }
- if (f && (f->context->msgstate != OTRL_MSGSTATE_ENCRYPTED ||
- f->context->active_fingerprint != f)) {
- forget_sensitive = 1;
- }
- if (f && f->context->msgstate == OTRL_MSGSTATE_PLAINTEXT) {
- connect_sensitive = 1;
- }
- if (f && f->context->msgstate == OTRL_MSGSTATE_FINISHED) {
- connect_sensitive = 1;
- }
+ ConnContext *context_iter;
+
if (f) {
verify_sensitive = 1;
+ forget_sensitive = 1;
+
+ if (f->context && f->context->m_context) {
+ for (context_iter = f->context;
+ context_iter && context_iter->m_context ==
+ f->context->m_context;
+ context_iter = context_iter->next) {
+
+ if (context_iter->msgstate == OTRL_MSGSTATE_ENCRYPTED &&
+ context_iter->active_fingerprint == f) {
+ disconnect_sensitive = 1;
+ forget_sensitive = 0;
+ }
+ else if (context_iter->msgstate == OTRL_MSGSTATE_FINISHED) {
+ connect_sensitive = 1;
+ }
+ else if (context_iter->msgstate == OTRL_MSGSTATE_PLAINTEXT) {
+ connect_sensitive = 1;
+ }
+ }
+ }
}
+
gtk_widget_set_sensitive(ui_layout.connect_button,
connect_sensitive);
gtk_widget_set_sensitive(ui_layout.disconnect_button,
@@ -280,23 +317,44 @@ static void clist_unselected(GtkWidget *widget, gint row, gint column,
static int fngsortval(Fingerprint *f)
{
- int is_active = (f->context->msgstate == OTRL_MSGSTATE_ENCRYPTED &&
- f->context->active_fingerprint == f);
- TrustLevel level = otrg_plugin_context_to_trust(f->context);
-
- switch(level) {
- case TRUST_PRIVATE:
- return is_active ? 0 : 100;
- case TRUST_UNVERIFIED:
- return is_active ? 1 : 100;
- case TRUST_FINISHED:
- return 2;
- case TRUST_NOT_PRIVATE:
- return 3;
+ int result = 200;
+ ConnContext *context_iter;
+
+ for (context_iter = f->context->m_context;
+ context_iter && context_iter->m_context == f->context->m_context;
+ context_iter = context_iter->next) {
+
+ int is_active = 0;
+ TrustLevel level;
+
+ if (context_iter->msgstate == OTRL_MSGSTATE_ENCRYPTED &&
+ context_iter->active_fingerprint == f) {
+ is_active = 1;
+ }
+
+ level = otrg_plugin_context_to_trust(context_iter);
+
+ if (level == TRUST_PRIVATE) {
+ if (is_active) {
+ result = 0;
+ break;
+ } else {
+ result = result > 100 ? 100 : result;
+ }
+ } else if (level == TRUST_UNVERIFIED) {
+ if (is_active) {
+ result = 1;
+ } else {
+ result = result > 100 ? 100 : result;
+ }
+ } else if (level == TRUST_FINISHED) {
+ result = result > 2 ? 2 : result;
+ } else if (level == TRUST_NOT_PRIVATE) {
+ result = result > 3 ? 3 : result;
+ }
}
- /* Shouldn't get here, but anyway. */
- return 200;
+ return result;
}
static gint statuscmp(GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2)
@@ -345,20 +403,25 @@ static void disconnect_connection(GtkWidget *widget, gpointer data)
{
/* Forget whatever state we've got with this context */
ConnContext *context;
+ ConnContext *context_iter;
if (ui_layout.selected_fprint == NULL) return;
context = ui_layout.selected_fprint->context;
if (context == NULL) return;
-
- /* Don't do anything with fingerprints other than the active one
- * if we're in the ENCRYPTED state */
- if (context->msgstate == OTRL_MSGSTATE_ENCRYPTED &&
- context->active_fingerprint != ui_layout.selected_fprint) {
- return;
+
+ for (context_iter = context->m_context;
+ context_iter && context_iter->m_context == context->m_context;
+ context_iter = context_iter->next) {
+
+ /* Don't do anything with fingerprints other than the active one
+ * if we're in the ENCRYPTED state */
+ if (context_iter->msgstate == OTRL_MSGSTATE_ENCRYPTED &&
+ context_iter->active_fingerprint == ui_layout.selected_fprint) {
+ otrg_ui_disconnect_connection(context_iter);
+ }
}
-
- otrg_ui_disconnect_connection(context);
+
}
static void forget_fingerprint(GtkWidget *widget, gpointer data)
@@ -383,7 +446,7 @@ static void otrsettings_clicked_cb(GtkButton *button,
GTK_TOGGLE_BUTTON(os->enablebox))) {
gtk_widget_set_sensitive(os->automaticbox, TRUE);
if (gtk_toggle_button_get_active(
- GTK_TOGGLE_BUTTON(os->automaticbox))) {
+ GTK_TOGGLE_BUTTON(os->automaticbox))) {
gtk_widget_set_sensitive(os->onlyprivatebox, TRUE);
} else {
gtk_widget_set_sensitive(os->onlyprivatebox, FALSE);
@@ -431,13 +494,13 @@ static void create_otrsettings_buttons(struct otrsettingsdata *os,
gtk_box_pack_start(GTK_BOX(vbox), os->avoidloggingotrbox, FALSE, FALSE, 5);
g_signal_connect(G_OBJECT(os->enablebox), "clicked",
- G_CALLBACK(otrsettings_clicked_cb), os);
+ G_CALLBACK(otrsettings_clicked_cb), os);
g_signal_connect(G_OBJECT(os->automaticbox), "clicked",
- G_CALLBACK(otrsettings_clicked_cb), os);
+ G_CALLBACK(otrsettings_clicked_cb), os);
g_signal_connect(G_OBJECT(os->onlyprivatebox), "clicked",
- G_CALLBACK(otrsettings_clicked_cb), os);
+ G_CALLBACK(otrsettings_clicked_cb), os);
g_signal_connect(G_OBJECT(os->avoidloggingotrbox), "clicked",
- G_CALLBACK(otrsettings_clicked_cb), os);
+ G_CALLBACK(otrsettings_clicked_cb), os);
}
static void otroptions_clicked_cb(GtkButton *button,
@@ -461,7 +524,7 @@ static void create_otroptions_buttons(struct otroptionsdata *oo,
gtk_box_pack_start(GTK_BOX(vbox), oo->showotrbutton, FALSE, FALSE, 0);
g_signal_connect(G_OBJECT(oo->showotrbutton), "clicked",
- G_CALLBACK(otroptions_clicked_cb), oo);
+ G_CALLBACK(otroptions_clicked_cb), oo);
}
/* Load the global OTR prefs */
@@ -478,8 +541,8 @@ static void otrg_gtk_ui_global_prefs_load(gboolean *enabledp,
*enabledp = TRUE;
*automaticp = TRUE;
*onlyprivatep = FALSE;
- *avoidloggingotrp = FALSE;
- }
+ *avoidloggingotrp = TRUE;
+ }
}
/* Save the global OTR prefs */
@@ -512,7 +575,7 @@ static void otrg_gtk_ui_buddy_prefs_load(PurpleBuddy *buddy,
*automaticp = purple_blist_node_get_bool(node, "OTR/automatic");
*onlyprivatep = purple_blist_node_get_bool(node, "OTR/onlyprivate");
*avoidloggingotrp =
- purple_blist_node_get_bool(node, "OTR/avoidloggingotr");
+ purple_blist_node_get_bool(node, "OTR/avoidloggingotr");
}
}
@@ -686,13 +749,13 @@ static void make_settings_ui(GtkWidget *vbox)
load_otrsettings(&(ui_layout.os));
g_signal_connect(G_OBJECT(ui_layout.os.enablebox), "clicked",
- G_CALLBACK(otrsettings_save_cb), &(ui_layout.os));
+ G_CALLBACK(otrsettings_save_cb), &(ui_layout.os));
g_signal_connect(G_OBJECT(ui_layout.os.automaticbox), "clicked",
- G_CALLBACK(otrsettings_save_cb), &(ui_layout.os));
+ G_CALLBACK(otrsettings_save_cb), &(ui_layout.os));
g_signal_connect(G_OBJECT(ui_layout.os.onlyprivatebox), "clicked",
- G_CALLBACK(otrsettings_save_cb), &(ui_layout.os));
+ G_CALLBACK(otrsettings_save_cb), &(ui_layout.os));
g_signal_connect(G_OBJECT(ui_layout.os.avoidloggingotrbox), "clicked",
- G_CALLBACK(otrsettings_save_cb), &(ui_layout.os));
+ G_CALLBACK(otrsettings_save_cb), &(ui_layout.os));
}
/* Make the options UI, and pack it into the vbox */
@@ -713,7 +776,7 @@ static void make_options_ui(GtkWidget *vbox)
load_otroptions(&(ui_layout.oo));
g_signal_connect(G_OBJECT(ui_layout.oo.showotrbutton), "clicked",
- G_CALLBACK(otroptions_save_cb), &(ui_layout.oo));
+ G_CALLBACK(otroptions_save_cb), &(ui_layout.oo));
}
/* Create the fingerprint UI, and pack it into the vbox */
@@ -731,8 +794,8 @@ static void make_fingerprints_ui(GtkWidget *vbox)
titles[4] = _("Account");
ui_layout.scrollwin = gtk_scrolled_window_new(0, 0);
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ui_layout.scrollwin),
- GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ui_layout.scrollwin),
+ GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS);
ui_layout.keylist = gtk_clist_new_with_titles(5, titles);
gtk_clist_set_column_width(GTK_CLIST(ui_layout.keylist), 0, 90);
@@ -906,19 +969,19 @@ static void config_buddy_destroy_cb(GtkWidget *w, struct cbdata *data)
static void config_buddy_clicked_cb(GtkButton *button, struct cbdata *data)
{
gboolean enabled = gtk_toggle_button_get_active(
- GTK_TOGGLE_BUTTON(data->os.enablebox));
-
+ GTK_TOGGLE_BUTTON(data->os.enablebox));
+
/* Apply the changes */
otrg_gtk_ui_buddy_prefs_save(data->buddy,
- gtk_toggle_button_get_active(
- GTK_TOGGLE_BUTTON(data->defaultbox)),
- enabled,
- gtk_toggle_button_get_active(
- GTK_TOGGLE_BUTTON(data->os.automaticbox)),
- gtk_toggle_button_get_active(
- GTK_TOGGLE_BUTTON(data->os.onlyprivatebox)),
- gtk_toggle_button_get_active(
- GTK_TOGGLE_BUTTON(data->os.avoidloggingotrbox)));
+ gtk_toggle_button_get_active(
+ GTK_TOGGLE_BUTTON(data->defaultbox)),
+ enabled,
+ gtk_toggle_button_get_active(
+ GTK_TOGGLE_BUTTON(data->os.automaticbox)),
+ gtk_toggle_button_get_active(
+ GTK_TOGGLE_BUTTON(data->os.onlyprivatebox)),
+ gtk_toggle_button_get_active(
+ GTK_TOGGLE_BUTTON(data->os.avoidloggingotrbox)));
otrg_dialog_resensitize_all();
}
@@ -940,9 +1003,9 @@ static void otrg_gtk_ui_config_buddy(PurpleBuddy *buddy)
if (!data) return;
dialog = gtk_dialog_new_with_buttons(_("OTR Settings"),
- NULL, 0,
- GTK_STOCK_OK, GTK_RESPONSE_OK,
- NULL);
+ NULL, 0,
+ GTK_STOCK_OK, GTK_RESPONSE_OK,
+ NULL);
gtk_window_set_accept_focus(GTK_WINDOW(dialog), FALSE);
gtk_window_set_role(GTK_WINDOW(dialog), "otr_settings");
@@ -986,25 +1049,25 @@ static void otrg_gtk_ui_config_buddy(PurpleBuddy *buddy)
create_otrsettings_buttons(&(data->os), GTK_DIALOG(dialog)->vbox);
g_signal_connect(G_OBJECT(data->defaultbox), "clicked",
- G_CALLBACK(default_clicked_cb), data);
+ G_CALLBACK(default_clicked_cb), data);
g_signal_connect(G_OBJECT(data->defaultbox), "clicked",
- G_CALLBACK(config_buddy_clicked_cb), data);
+ G_CALLBACK(config_buddy_clicked_cb), data);
g_signal_connect(G_OBJECT(data->os.enablebox), "clicked",
- G_CALLBACK(config_buddy_clicked_cb), data);
+ G_CALLBACK(config_buddy_clicked_cb), data);
g_signal_connect(G_OBJECT(data->os.automaticbox), "clicked",
- G_CALLBACK(config_buddy_clicked_cb), data);
+ G_CALLBACK(config_buddy_clicked_cb), data);
g_signal_connect(G_OBJECT(data->os.onlyprivatebox), "clicked",
- G_CALLBACK(config_buddy_clicked_cb), data);
+ G_CALLBACK(config_buddy_clicked_cb), data);
g_signal_connect(G_OBJECT(data->os.avoidloggingotrbox), "clicked",
- G_CALLBACK(config_buddy_clicked_cb), data);
+ G_CALLBACK(config_buddy_clicked_cb), data);
/* Set the inital states of the buttons */
load_buddyprefs(data);
g_signal_connect(G_OBJECT(dialog), "destroy",
- G_CALLBACK(config_buddy_destroy_cb), data);
+ G_CALLBACK(config_buddy_destroy_cb), data);
g_signal_connect(G_OBJECT(dialog), "response",
- G_CALLBACK(config_buddy_response_cb), data);
+ G_CALLBACK(config_buddy_response_cb), data);
gtk_widget_show_all(dialog);
}
@@ -1016,12 +1079,12 @@ static void otrg_gtk_ui_get_prefs(OtrgUiPrefs *prefsp, PurpleAccount *account,
PurpleBuddy *buddy;
gboolean otrenabled, otrautomatic, otronlyprivate, otravoidloggingotr;
gboolean buddyusedefault, buddyenabled, buddyautomatic, buddyonlyprivate,
- buddyavoidloggingotr;
+ buddyavoidloggingotr;
prefsp->policy = OTRL_POLICY_DEFAULT;
prefsp->avoid_logging_otr = FALSE;
prefsp->show_otr_button = FALSE;
-
+
/* Get the default policy */
otrg_gtk_ui_global_prefs_load(&otrenabled, &otrautomatic, &otronlyprivate,
&otravoidloggingotr);
diff --git a/gtk-ui.h b/gtk-ui.h
index 8797850..c20dd3d 100644
--- a/gtk-ui.h
+++ b/gtk-ui.h
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging plugin for pidgin
- * Copyright (C) 2004-2009 Ian Goldberg, Rob Smits,
+ * Copyright (C) 2004-2012 Ian Goldberg, Rob Smits,
* Chris Alexander, Willy Lew,
* Nikita Borisov
* <otr at cypherpunks.ca>
diff --git a/otr-icons.h b/otr-icons.h
index f9ff68a..4abaeb3 100644
--- a/otr-icons.h
+++ b/otr-icons.h
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging plugin for pidgin
- * Copyright (C) 2004-2009 Ian Goldberg, Rob Smits,
+ * Copyright (C) 2004-2012 Ian Goldberg, Rob Smits,
* Chris Alexander, Willy Lew,
* Nikita Borisov
* <otr at cypherpunks.ca>
@@ -32,9 +32,9 @@
#pragma align 4 (not_private_pixbuf)
#endif
#ifdef __GNUC__
-static const guint8 not_private_pixbuf[] __attribute__ ((__aligned__ (4))) =
+static const guint8 not_private_pixbuf[] __attribute__ ((__aligned__ (4))) =
#else
-static const guint8 not_private_pixbuf[] =
+static const guint8 not_private_pixbuf[] =
#endif
{ ""
/* Pixbuf magic (0x47646b50) */
@@ -153,9 +153,9 @@ static const char not_private_png[] =
#pragma align 4 (unverified_pixbuf)
#endif
#ifdef __GNUC__
-static const guint8 unverified_pixbuf[] __attribute__ ((__aligned__ (4))) =
+static const guint8 unverified_pixbuf[] __attribute__ ((__aligned__ (4))) =
#else
-static const guint8 unverified_pixbuf[] =
+static const guint8 unverified_pixbuf[] =
#endif
{ ""
/* Pixbuf magic (0x47646b50) */
@@ -270,9 +270,9 @@ static const char unverified_png[] =
#pragma align 4 (private_pixbuf)
#endif
#ifdef __GNUC__
-static const guint8 private_pixbuf[] __attribute__ ((__aligned__ (4))) =
+static const guint8 private_pixbuf[] __attribute__ ((__aligned__ (4))) =
#else
-static const guint8 private_pixbuf[] =
+static const guint8 private_pixbuf[] =
#endif
{ ""
/* Pixbuf magic (0x47646b50) */
@@ -387,9 +387,9 @@ static const char private_png[] =
#pragma align 4 (finished_pixbuf)
#endif
#ifdef __GNUC__
-static const guint8 finished_pixbuf[] __attribute__ ((__aligned__ (4))) =
+static const guint8 finished_pixbuf[] __attribute__ ((__aligned__ (4))) =
#else
-static const guint8 finished_pixbuf[] =
+static const guint8 finished_pixbuf[] =
#endif
{ ""
/* Pixbuf magic (0x47646b50) */
diff --git a/otr-plugin.c b/otr-plugin.c
index 26c7a17..1e213f4 100644
--- a/otr-plugin.c
+++ b/otr-plugin.c
@@ -1,8 +1,8 @@
/*
* Off-the-Record Messaging plugin for pidgin
- * Copyright (C) 2004-2009 Ian Goldberg, Rob Smits,
+ * Copyright (C) 2004-2012 Ian Goldberg, Rob Smits,
* Chris Alexander, Willy Lew,
- * Nikita Borisov
+ * Lisa Du, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This program is free software; you can redistribute it and/or modify
@@ -64,6 +64,7 @@
#include <libotr/tlv.h>
#include <libotr/message.h>
#include <libotr/userstate.h>
+#include <libotr/instag.h>
/* purple-otr headers */
#include "ui.h"
@@ -100,6 +101,7 @@ OtrlUserState otrg_plugin_userstate = NULL;
* protocols. */
GHashTable* mms_table;
+
/* Send an IM from the given account to the given recipient. Display an
* error dialog if that account isn't currently logged in. */
void otrg_plugin_inject_message(PurpleAccount *account, const char *recipient,
@@ -126,25 +128,25 @@ void otrg_plugin_inject_message(PurpleAccount *account, const char *recipient,
/* Display a notification message for a particular accountname /
* protocol / username conversation. */
static void notify(void *opdata, OtrlNotifyLevel level,
- const char *accountname, const char *protocol, const char *username,
- const char *title, const char *primary, const char *secondary)
+ const char *accountname, const char *protocol, const char *username,
+ const char *title, const char *primary, const char *secondary)
{
PurpleNotifyMsgType purplelevel = PURPLE_NOTIFY_MSG_ERROR;
switch (level) {
- case OTRL_NOTIFY_ERROR:
- purplelevel = PURPLE_NOTIFY_MSG_ERROR;
- break;
- case OTRL_NOTIFY_WARNING:
- purplelevel = PURPLE_NOTIFY_MSG_WARNING;
- break;
- case OTRL_NOTIFY_INFO:
- purplelevel = PURPLE_NOTIFY_MSG_INFO;
- break;
+ case OTRL_NOTIFY_ERROR:
+ purplelevel = PURPLE_NOTIFY_MSG_ERROR;
+ break;
+ case OTRL_NOTIFY_WARNING:
+ purplelevel = PURPLE_NOTIFY_MSG_WARNING;
+ break;
+ case OTRL_NOTIFY_INFO:
+ purplelevel = PURPLE_NOTIFY_MSG_INFO;
+ break;
}
otrg_dialog_notify_message(purplelevel, accountname, protocol,
- username, title, primary, secondary);
+ username, title, primary, secondary);
}
/* Display an OTR control message for a particular accountname /
@@ -153,16 +155,16 @@ static void notify(void *opdata, OtrlNotifyLevel level,
* conversation window will be created and the message will be displayed
* there. Returns 0 if message is successfully displayed. */
static int display_otr_message(void *opdata, const char *accountname,
- const char *protocol, const char *username, const char *msg,
- int force_create)
+ const char *protocol, const char *username, const char *msg,
+ int force_create)
{
return otrg_dialog_display_otr_message(accountname, protocol,
- username, msg, force_create);
+ username, msg, force_create);
}
static void log_message(void *opdata, const char *message)
{
- purple_debug_info("otr", message);
+ purple_debug_info("otr", "%s", message);
}
static OtrlPolicy policy_cb(void *opdata, ConnContext *context)
@@ -190,7 +192,8 @@ void otrg_plugin_create_privkey(const char *accountname,
#endif /* WIN32 */
FILE *privf;
- gchar *privkeyfile = g_build_filename(purple_user_dir(), PRIVKEYFNAME, NULL);
+ gchar *privkeyfile = g_build_filename(purple_user_dir(),
+ PRIVKEYFNAME, NULL);
if (!privkeyfile) {
fprintf(stderr, _("Out of memory building filenames!\n"));
return;
@@ -226,6 +229,38 @@ static void create_privkey_cb(void *opdata, const char *accountname,
otrg_plugin_create_privkey(accountname, protocol);
}
+/* Generate a instance tag for the given accountname/protocol */
+void otrg_plugin_create_instag(const char *accountname,
+ const char *protocol)
+{
+ OtrgDialogWaitHandle waithandle;
+ FILE *instagf;
+
+ gchar *instagfile = g_build_filename(purple_user_dir(), INSTAGFNAME, NULL);
+ if (!instagfile) {
+ fprintf(stderr, _("Out of memory building filenames!\n"));
+ return;
+ }
+ instagf = g_fopen(instagfile, "w+b");
+ g_free(instagfile);
+ if (!instagf) {
+ fprintf(stderr, _("Could not write private key file\n"));
+ return;
+ }
+
+ /* Generate the key */
+ otrl_instag_generate_FILEp(otrg_plugin_userstate, instagf,
+ accountname, protocol);
+ fclose(instagf);
+
+}
+
+static void create_instag_cb(void *opdata, const char *accountname,
+ const char *protocol)
+{
+ otrg_plugin_create_instag(accountname, protocol);
+}
+
static int is_logged_in_cb(void *opdata, const char *accountname,
const char *protocol, const char *recipient)
{
@@ -299,13 +334,13 @@ static int max_message_size_cb(void *opdata, ConnContext *context)
{
void* lookup_result = g_hash_table_lookup(mms_table, context->protocol);
if (!lookup_result)
- return 0;
+ return 0;
else
- return *((int*)lookup_result);
+ return *((int*)lookup_result);
}
static const char* otr_error_message_cb(void *opdata, ConnContext *context,
- OtrlErrorCode err_code)
+ OtrlErrorCode err_code)
{
char *err_msg = NULL;
switch (err_code)
@@ -313,20 +348,21 @@ static const char* otr_error_message_cb(void *opdata, ConnContext *context,
case OTRL_ERRCODE_NONE :
break;
case OTRL_ERRCODE_ENCRYPTION_ERROR :
- err_msg = g_strdup(_("Error occurred encrypting message."));
- break;
+ err_msg = g_strdup(_("Error occurred encrypting message."));
+ break;
case OTRL_ERRCODE_MSG_NOT_IN_PRIVATE :
- if (context) {
- err_msg = g_strdup_printf(_("You sent encrypted data to %s, who"
- " wasn't expecting it."), context->accountname);
- }
- break;
+ if (context) {
+ err_msg = g_strdup_printf(_("You sent encrypted data to %s, who"
+ " wasn't expecting it."), context->accountname);
+ }
+ break;
case OTRL_ERRCODE_MSG_UNREADABLE :
- err_msg = g_strdup(_("You transmitted an unreadable encrypted message."));
- break;
+ err_msg =
+ g_strdup(_("You transmitted an unreadable encrypted message."));
+ break;
case OTRL_ERRCODE_MSG_MALFORMED :
- err_msg = g_strdup(_("You transmitted a malformed data message."));
- break;
+ err_msg = g_strdup(_("You transmitted a malformed data message."));
+ break;
}
return err_msg;
}
@@ -347,242 +383,283 @@ static void resent_msg_prefix_free_cb(void *opdata, const char *prefix)
}
static void handle_smp_event_cb(void *opdata, OtrlSMPEvent smp_event,
- ConnContext *context, unsigned short progress_percent,
+ ConnContext *context, unsigned short progress_percent,
char *question)
{
if (!context) return;
switch (smp_event)
{
- case OTRL_SMPEVENT_NONE :
+ case OTRL_SMPEVENT_NONE :
+ break;
+ case OTRL_SMPEVENT_ASK_FOR_SECRET :
+ otrg_dialog_socialist_millionaires(context);
break;
- case OTRL_SMPEVENT_ASK_FOR_SECRET :
- otrg_dialog_socialist_millionaires(context);
- break;
- case OTRL_SMPEVENT_ASK_FOR_ANSWER :
- otrg_dialog_socialist_millionaires_q(context, question);
- break;
- case OTRL_SMPEVENT_CHEATED :
- otrg_plugin_abort_smp(context);
+ case OTRL_SMPEVENT_ASK_FOR_ANSWER :
+ otrg_dialog_socialist_millionaires_q(context, question);
+ break;
+ case OTRL_SMPEVENT_CHEATED :
+ otrg_plugin_abort_smp(context);
/* FALLTHROUGH */
- case OTRL_SMPEVENT_IN_PROGRESS :
- case OTRL_SMPEVENT_SUCCESS :
- case OTRL_SMPEVENT_FAILURE :
- case OTRL_SMPEVENT_ABORT :
- otrg_dialog_update_smp(context,
+ case OTRL_SMPEVENT_IN_PROGRESS :
+ case OTRL_SMPEVENT_SUCCESS :
+ case OTRL_SMPEVENT_FAILURE :
+ case OTRL_SMPEVENT_ABORT :
+ otrg_dialog_update_smp(context,
smp_event, ((gdouble)progress_percent)/100.0);
- break;
- case OTRL_SMPEVENT_ERROR :
- otrg_plugin_abort_smp(context);
- break;
+ break;
+ case OTRL_SMPEVENT_ERROR :
+ otrg_plugin_abort_smp(context);
+ break;
}
}
+void otrg_emit_msg_received(ConnContext *context, const char* message) {
+ PurpleConversation *conv = otrg_plugin_userinfo_to_conv(
+ context->accountname, context->protocol, context->username, 1);
+ PurpleMessageFlags flags = PURPLE_MESSAGE_RECV | PURPLE_MESSAGE_SYSTEM
+ | PURPLE_MESSAGE_NOTIFY;
+ PurpleAccount * account = purple_conversation_get_account(conv);
+
+ purple_signal_emit(purple_conversations_get_handle(), "received-im-msg",
+ account, context->username, message, conv, flags);
+}
+
static void handle_msg_event_cb(void *opdata, OtrlMessageEvent msg_event,
- ConnContext *context, const char* message, gcry_error_t err)
+ ConnContext *context, const char* message, gcry_error_t err)
{
+ PurpleConversation *conv = NULL;
if (!context) return;
char *buf;
const char *format;
+ OtrlMessageEvent last_msg_event;
+ gboolean value_existed;
+
+ conv = otrg_plugin_context_to_conv(context, 1);
+ value_existed = g_hash_table_lookup_extended(conv->data,
+ "otr-last_msg_event", NULL, (void**)&last_msg_event);
+
+ purple_conversation_set_data(conv, "otr-last_msg_event",
+ (gpointer)msg_event);
switch (msg_event)
{
- case OTRL_MSGEVENT_NONE:
+ case OTRL_MSGEVENT_NONE:
+ break;
+ case OTRL_MSGEVENT_ENCRYPTION_REQUIRED:
+ if (display_otr_message(opdata, context->accountname,
+ context->protocol, context->username, _("Attempting to"
+ " start a private conversation..."), 1)) {
+ format = _("You attempted to send an "
+ "unencrypted message to %s");
+ buf = malloc(strlen(format) +
+ strlen(context->username) - 1);
+ if (buf) {
+ sprintf(buf, format, context->username);
+ notify(opdata, OTRL_NOTIFY_WARNING, context->accountname,
+ context->protocol, context->username, _("OTR Policy"
+ " Violation"), buf,
+ _("Unencrypted messages to this recipient are "
+ "not allowed. Attempting to start a private "
+ "conversation.\n\nYour message will be "
+ "retransmitted when the private conversation "
+ "starts."));
+ free(buf);
+ }
+ }
+ break;
+ case OTRL_MSGEVENT_ENCRYPTION_ERROR:
+ if (display_otr_message(opdata, context->accountname,
+ context->protocol, context->username, _("An error occurred "
+ "when encrypting your message. The message was not sent."
+ ), 1)) {
+ notify(opdata, OTRL_NOTIFY_ERROR,
+ context->accountname, context->protocol,
+ context->username,
+ _("Error encrypting message"),
+ _("An error occurred when encrypting your message"),
+ _("The message was not sent."));
+ }
+ break;
+ case OTRL_MSGEVENT_CONNECTION_ENDED:
+ if (display_otr_message(opdata, context->accountname,
+ context->protocol, context->username, _("Your message"
+ "was not sent. Either end your private conversation, "
+ "or restart it."), 1)) {
+ format = _("%s has already closed his/her private "
+ "connection to you");
+ buf = malloc(strlen(format) + strlen(context->username) - 1);
+ if (buf) {
+ sprintf(buf, format, context->username);
+ notify(opdata, OTRL_NOTIFY_ERROR,
+ context->accountname, context->protocol,
+ context->username,
+ _("Private connection closed"), buf,
+ _("Your message was not sent. Either close your "
+ "private connection to him, or refresh it."));
+ free(buf);
+ }
+ }
+ break;
+ case OTRL_MSGEVENT_SETUP_ERROR:
+ if (!err) {
+ err = GPG_ERR_INV_VALUE;
+ }
+ format = _("Error setting up private conversation: %s");
+ const char *strerr;
+
+ switch(gcry_err_code(err)) {
+ case GPG_ERR_INV_VALUE:
+ strerr = _("Malformed message received");
+ break;
+ default:
+ strerr = gcry_strerror(err);
+ break;
+ }
+ buf = malloc(strlen(format) + strlen(strerr) - 1);
+ if (buf) {
+ sprintf(buf, format, strerr);
+ }
+ if (display_otr_message(opdata, context->accountname,
+ context->protocol, context->username, buf, 1)) {
+ notify(opdata, OTRL_NOTIFY_ERROR, context->accountname,
+ context->protocol, context->username, "OTR error",
+ buf, NULL);
+ }
+ free(buf);
+ break;
+ case OTRL_MSGEVENT_MSG_REFLECTED:
+ if (display_otr_message(opdata,
+ context->accountname, context->protocol,
+ context->username,
+ _("We are receiving our own OTR messages. "
+ "You are either trying to talk to yourself, "
+ "or someone is reflecting your messages back "
+ "at you."), 1)) {
+ notify(opdata, OTRL_NOTIFY_ERROR,
+ context->accountname, context->protocol,
+ context->username, "OTR Error",
+ _("We are receiving our own OTR messages."),
+ _("You are either trying to talk to yourself, "
+ "or someone is reflecting your messages back "
+ "at you."));
+ }
+ break;
+ case OTRL_MSGEVENT_MSG_RESENT:
+ format = _("<b>The last message to %s was resent.</b>");
+ buf = malloc(strlen(format) +
+ strlen(context->username) - 1);
+ if (buf) {
+ sprintf(buf, format, context->username);
+ display_otr_message(opdata, context->accountname,
+ context->protocol, context->username, buf, 1);
+ free(buf);
+ }
+ break;
+ case OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE:
+ format = _("<b>The encrypted message received from %s is "
+ "unreadable, as you are not currently communicating "
+ "privately.</b>");
+ buf = malloc(strlen(format) +
+ strlen(context->username) - 1);
+ if (buf) {
+ sprintf(buf, format, context->username);
+ display_otr_message(opdata, context->accountname,
+ context->protocol, context->username, buf, 1);
+ free(buf);
+ }
+ break;
+ case OTRL_MSGEVENT_RCVDMSG_UNREADABLE:
+ format = _("We received an unreadable "
+ "encrypted message from %s.");
+ buf = malloc(strlen(format) + strlen(context->username) - 1);
+ if (buf) {
+ sprintf(buf, format, context->username);
+ if (display_otr_message(opdata,
+ context->accountname, context->protocol,
+ context->username, buf, 1)) {
+ notify(opdata, OTRL_NOTIFY_ERROR,
+ context->accountname, context->protocol,
+ context->username, "OTR Error", buf, NULL);
+ }
+ free(buf);
+ }
+ break;
+ case OTRL_MSGEVENT_RCVDMSG_MALFORMED:
+ format = _("We received a malformed data "
+ "message from %s.");
+ buf = malloc(strlen(format) + strlen(context->username) - 1);
+ if (buf) {
+ sprintf(buf, format, context->username);
+ if (display_otr_message(opdata,
+ context->accountname, context->protocol,
+ context->username, buf, 1)) {
+ notify(opdata, OTRL_NOTIFY_ERROR,
+ context->accountname, context->protocol,
+ context->username, "OTR Error", buf, NULL);
+ }
+ free(buf);
+ }
+ break;
+ case OTRL_MSGEVENT_LOG_HEARTBEAT_RCVD:
+ format = _("Heartbeat received from %s.\n");
+ buf = malloc(strlen(format) + strlen(context->username) - 1);
+ if (buf) {
+ sprintf(buf, format, context->username);
+ log_message(opdata, buf);
+ free(buf);
+ }
+ break;
+ case OTRL_MSGEVENT_LOG_HEARTBEAT_SENT:
+ format = _("Heartbeat sent to %s.\n");
+ buf = malloc(strlen(format) + strlen(context->username) - 1);
+ if (buf) {
+ sprintf(buf, format, context->username);
+ log_message(opdata, buf);
+ free(buf);
+ }
+ break;
+ case OTRL_MSGEVENT_RCVDMSG_GENERAL_ERR:
+ display_otr_message(opdata, context->accountname,
+ context->protocol, context->username, message, 1);
+ break;
+ case OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED:
+ format = _("<b>The following message received "
+ "from %s was <i>not</i> encrypted: [</b>%s<b>]</b>");
+ buf = malloc(strlen(format) + strlen(context->username)
+ + strlen(message) - 3);
+ /* Remove "%s%s", add username + message + '\0' */
+ if (buf) {
+ sprintf(buf, format, context->username, message);
+ display_otr_message(opdata, context->accountname,
+ context->protocol, context->username, buf, 1);
+ otrg_emit_msg_received(context, buf);
+ free(buf);
+ }
+ break;
+ case OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED:
+ format = _("Unrecognized OTR message received from %s.\n");
+ buf = malloc(strlen(format) + strlen(context->username) - 1);
+ if (buf) {
+ sprintf(buf, format, context->username);
+ log_message(opdata, buf);
+ free(buf);
+ }
+ break;
+ case OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE:
+ if (value_existed && last_msg_event == msg_event) {
+ break;
+ }
+ format = _("%s has sent a message intended for a different session."
+ "If you are logged in multiple times, another session may "
+ "have received the message.");
+ buf = malloc(strlen(format) + strlen(context->username) - 1);
+ if (buf) {
+ sprintf(buf, format, context->username);
+ display_otr_message(opdata, context->accountname,
+ context->protocol, context->username, buf, 1);
+ free(buf);
+ }
break;
- case OTRL_MSGEVENT_ENCRYPTION_REQUIRED:
- if (display_otr_message(opdata, context->accountname,
- context->protocol, context->username, _("Attempting to start a "
- "private conversation..."), 1)) {
- format = _("You attempted to send an "
- "unencrypted message to %s");
- buf = malloc(strlen(format) +
- strlen(context->username) - 1);
- if (buf) {
- sprintf(buf, format, context->username);
- notify(opdata, OTRL_NOTIFY_WARNING, context->accountname,
- context->protocol, context->username, _("OTR Policy Violation"),
- buf,
- _("Unencrypted messages to this recipient are "
- "not allowed. Attempting to start a private "
- "conversation.\n\nYour message will be "
- "retransmitted when the private conversation "
- "starts."));
- free(buf);
- }
- }
- break;
- case OTRL_MSGEVENT_ENCRYPTION_ERROR:
- if (display_otr_message(opdata, context->accountname,
- context->protocol, context->username, _("An error occurred when "
- "encrypting your message. The message was not sent."), 1)) {
- notify(opdata, OTRL_NOTIFY_ERROR,
- context->accountname, context->protocol, context->username,
- _("Error encrypting message"),
- _("An error occurred when encrypting your message"),
- _("The message was not sent."));
- }
- break;
- case OTRL_MSGEVENT_CONNECTION_ENDED:
- if (display_otr_message(opdata, context->accountname,
- context->protocol, context->username, _("Your message was not sent. "
- "Either end your private conversation, or restart it."), 1)) {
- format = _("%s has already closed his/her private "
- "connection to you");
- buf = malloc(strlen(format) + strlen(context->username) - 1);
- if (buf) {
- sprintf(buf, format, context->username);
- notify(opdata, OTRL_NOTIFY_ERROR,
- context->accountname, context->protocol, context->username,
- _("Private connection closed"), buf,
- _("Your message was not sent. Either close your "
- "private connection to him, or refresh it."));
- free(buf);
- }
- }
- break;
- case OTRL_MSGEVENT_SETUP_ERROR:
- if (!err) {
- err = GPG_ERR_INV_VALUE;
- }
- format = _("Error setting up private conversation: %s");
- const char *strerr;
-
- switch(gcry_err_code(err)) {
- case GPG_ERR_INV_VALUE:
- strerr = _("Malformed message received");
- break;
- default:
- strerr = gcry_strerror(err);
- break;
- }
- buf = malloc(strlen(format) + strlen(strerr) - 1);
- if (buf) {
- sprintf(buf, format, strerr);
- }
- if (display_otr_message(opdata, context->accountname,
- context->protocol, context->username, buf, 1)) {
- notify(opdata, OTRL_NOTIFY_ERROR, context->accountname,
- context->protocol, context->username, "OTR error",
- buf, NULL);
- }
- free(buf);
- break;
- case OTRL_MSGEVENT_MSG_REFLECTED:
- if (display_otr_message(opdata,
- context->accountname, context->protocol,
- context->username,
- _("We are receiving our own OTR messages. "
- "You are either trying to talk to yourself, "
- "or someone is reflecting your messages back "
- "at you."), 1)) {
- notify(opdata, OTRL_NOTIFY_ERROR,
- context->accountname, context->protocol,
- context->username, "OTR Error",
- _("We are receiving our own OTR messages."),
- _("You are either trying to talk to yourself, "
- "or someone is reflecting your messages back "
- "at you."));
- }
- break;
- case OTRL_MSGEVENT_MSG_RESENT:
- format = _("<b>The last message to %s was resent.</b>");
- buf = malloc(strlen(format) +
- strlen(context->username) - 1);
- if (buf) {
- sprintf(buf, format, context->username);
- display_otr_message(opdata, context->accountname,
- context->protocol, context->username, buf, 1);
- free(buf);
- }
- break;
- case OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE:
- format = _("<b>The encrypted message received from %s is "
- "unreadable, as you are not currently communicating "
- "privately.</b>");
- buf = malloc(strlen(format) +
- strlen(context->username) - 1);
- if (buf) {
- sprintf(buf, format, context->username);
- display_otr_message(opdata, context->accountname,
- context->protocol, context->username, buf, 1);
- free(buf);
- }
- break;
- case OTRL_MSGEVENT_RCVDMSG_UNREADABLE:
- format = _("We received an unreadable "
- "encrypted message from %s.");
- buf = malloc(strlen(format) + strlen(context->username) - 1);
- if (buf) {
- sprintf(buf, format, context->username);
- if (display_otr_message(opdata,
- context->accountname, context->protocol,
- context->username, buf, 1)) {
- notify(opdata, OTRL_NOTIFY_ERROR,
- context->accountname, context->protocol,
- context->username, "OTR Error", buf, NULL);
- }
- free(buf);
- }
- break;
- case OTRL_MSGEVENT_RCVDMSG_MALFORMED:
- format = _("We received a malformed data "
- "message from %s.");
- buf = malloc(strlen(format) + strlen(context->username) - 1);
- if (buf) {
- sprintf(buf, format, context->username);
- if (display_otr_message(opdata,
- context->accountname, context->protocol,
- context->username, buf, 1)) {
- notify(opdata, OTRL_NOTIFY_ERROR,
- context->accountname, context->protocol,
- context->username, "OTR Error", buf, NULL);
- }
- free(buf);
- }
- break;
- case OTRL_MSGEVENT_LOG_HEARTBEAT_RCVD:
- format = _("Heartbeat received from %s.\n");
- buf = malloc(strlen(format) + strlen(context->username) - 1);
- if (buf) {
- sprintf(buf, format, context->username);
- log_message(opdata, buf);
- free(buf);
- }
- break;
- case OTRL_MSGEVENT_LOG_HEARTBEAT_SENT:
- format = _("Heartbeat sent to %s.\n");
- buf = malloc(strlen(format) + strlen(context->username) - 1);
- if (buf) {
- sprintf(buf, format, context->username);
- log_message(opdata, buf);
- free(buf);
- }
- break;
- case OTRL_MSGEVENT_RCVDMSG_GENERAL_ERR:
- display_otr_message(opdata, context->accountname,
- context->protocol, context->username, message, 1);
- break;
- case OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED:
- format = _("<b>The following message received "
- "from %s was <i>not</i> encrypted: [</b>%s<b>]</b>");
- buf = malloc(strlen(format) + strlen(context->username)
- + strlen(message) - 3);
- /* Remove "%s%s", add username + message + '\0' */
- if (buf) {
- sprintf(buf, format, context->username, message);
- display_otr_message(opdata, context->accountname,
- context->protocol, context->username, buf, 1);
- free(buf);
- }
- break;
- case OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED:
- format = _("Unrecognized OTR message received from %s.\n");
- buf = malloc(strlen(format) + strlen(context->username) - 1);
- if (buf) {
- sprintf(buf, format, context->username);
- log_message(opdata, buf);
- free(buf);
- }
- break;
}
}
@@ -629,9 +706,15 @@ static OtrlMessageAppOps ui_ops = {
resent_msg_prefix_cb,
resent_msg_prefix_free_cb,
handle_smp_event_cb,
- handle_msg_event_cb
+ handle_msg_event_cb,
+ create_instag_cb,
+ NULL, /* convert_data */
+ NULL /* convert_data_free */
};
+otrl_instag_t otrg_plugin_conv_to_selected_instag(PurpleConversation *conv,
+ otrl_instag_t default_value);
+
static void process_sending_im(PurpleAccount *account, char *who,
char **message, void *m)
{
@@ -640,24 +723,32 @@ static void process_sending_im(PurpleAccount *account, char *who,
const char *protocol = purple_account_get_protocol_id(account);
char *username;
gcry_error_t err;
+ PurpleConversation * conv = NULL;
+ otrl_instag_t instance;
if (!who || !message || !*message)
return;
username = strdup(purple_normalize(account, who));
+ conv = otrg_plugin_userinfo_to_conv(accountname, protocol, username, 1);
+
+ instance = otrg_plugin_conv_to_selected_instag(conv, OTRL_INSTAG_BEST);
+
err = otrl_message_sending(otrg_plugin_userstate, &ui_ops, NULL,
- accountname, protocol, username, message, NULL, &newmessage,
- OTRL_FRAGMENT_SEND_ALL_BUT_LAST, NULL, NULL, NULL, NULL);
+ accountname, protocol, username, instance, *message, NULL,
+ &newmessage, OTRL_FRAGMENT_SEND_ALL_BUT_LAST, NULL, NULL, NULL);
if (err) {
- /* Do not send out plain text */
- char *ourm = strdup("");
- free(*message);
- *message = ourm;
+ /* Do not send out plain text */
+ char *ourm = strdup("");
+ free(*message);
+ *message = ourm;
+ } else if (newmessage) {
+ *message = strdup(newmessage);
}
- otrl_message_free(newmessage);
+ otrl_message_free(newmessage);
free(username);
}
@@ -701,7 +792,7 @@ void otrg_plugin_send_default_query(ConnContext *context, void *vaccount)
msg = otrl_proto_default_query_msg(context->accountname,
prefs.policy);
otrg_plugin_inject_message(account, context->username,
- msg ? msg : "?OTRv2?");
+ msg ? msg : "?OTRv23?");
free(msg);
}
@@ -720,12 +811,12 @@ void otrg_plugin_send_default_query_conv(PurpleConversation *conv)
otrg_ui_get_prefs(&prefs, account, username);
msg = otrl_proto_default_query_msg(accountname, prefs.policy);
- otrg_plugin_inject_message(account, username, msg ? msg : "?OTRv2?");
+ otrg_plugin_inject_message(account, username, msg ? msg : "?OTRv23?");
free(msg);
}
static gboolean process_receiving_im(PurpleAccount *account, char **who,
- char **message, int *flags, void *m)
+ char **message, int *flags, void *m)
{
char *newmessage = NULL;
OtrlTLV *tlvs = NULL;
@@ -736,7 +827,7 @@ static gboolean process_receiving_im(PurpleAccount *account, char **who,
const char *protocol;
if (!who || !*who || !message || !*message)
- return 0;
+ return 0;
username = strdup(purple_normalize(account, *who));
accountname = purple_account_get_username(account);
@@ -744,7 +835,7 @@ static gboolean process_receiving_im(PurpleAccount *account, char **who,
res = otrl_message_receiving(otrg_plugin_userstate, &ui_ops, NULL,
accountname, protocol, username, *message,
- &newmessage, &tlvs, NULL, NULL, NULL, NULL);
+ &newmessage, &tlvs, NULL, NULL, NULL);
if (newmessage) {
char *ourm = malloc(strlen(newmessage) + 1);
@@ -778,9 +869,63 @@ static gboolean process_receiving_im(PurpleAccount *account, char **who,
return res;
}
+/* Find the ConnContext appropriate to a given PurpleConversation. */
+ConnContext *otrg_plugin_conv_to_context(PurpleConversation *conv,
+ otrl_instag_t their_instance, int force_create)
+{
+ PurpleAccount *account;
+ char *username;
+ const char *accountname, *proto;
+ ConnContext *context;
+
+ account = purple_conversation_get_account(conv);
+ accountname = purple_account_get_username(account);
+ proto = purple_account_get_protocol_id(account);
+ username = g_strdup(
+ purple_normalize(account, purple_conversation_get_name(conv)));
+
+ context = otrl_context_find(otrg_plugin_userstate, username, accountname,
+ proto, their_instance, force_create, NULL, NULL, NULL);
+
+ g_free(username);
+
+ return context;
+}
+
+/* Given a PurpleConversation, return the selected instag */
+otrl_instag_t otrg_plugin_conv_to_selected_instag(PurpleConversation *conv,
+ otrl_instag_t default_val)
+{
+ otrl_instag_t selected_instance;
+
+ if (!g_hash_table_lookup_extended(conv->data, "otr-ui_selected_ctx", NULL,
+ (void**)&selected_instance)) {
+ selected_instance = default_val;
+ }
+
+ return selected_instance;
+}
+
+/* Given a PurpleConversation, return the selected ConnContext */
+ConnContext* otrg_plugin_conv_to_selected_context(PurpleConversation *conv,
+ int force_create)
+{
+ otrl_instag_t selected_instance;
+ ConnContext *result = NULL;
+
+ selected_instance = otrg_plugin_conv_to_selected_instag(conv,
+ OTRL_INSTAG_BEST);
+
+ return otrg_plugin_conv_to_context(conv, selected_instance, force_create);
+}
+
static void process_conv_create(PurpleConversation *conv, void *data)
{
- if (conv) otrg_dialog_new_conv(conv);
+ if (!conv) return;
+
+ purple_conversation_set_data(conv, "otr-ui_selected_ctx",
+ (gpointer)OTRL_INSTAG_BEST);
+ otrg_dialog_new_conv(conv);
}
static void process_conv_updated(PurpleConversation *conv,
@@ -794,7 +939,7 @@ static void process_conv_updated(PurpleConversation *conv,
PurpleAccount *account = purple_conversation_get_account(conv);
otrg_ui_get_prefs(&prefs, account, purple_conversation_get_name(conv));
- context = otrg_plugin_conv_to_context(conv);
+ context = otrg_plugin_conv_to_selected_context(conv, 0);
if (context && prefs.avoid_logging_otr &&
context->msgstate == OTRL_MSGSTATE_ENCRYPTED &&
conv->logging == TRUE) {
@@ -803,6 +948,11 @@ static void process_conv_updated(PurpleConversation *conv,
}
}
+static void process_conv_destroyed(PurpleConversation *conv)
+{
+ g_hash_table_remove(conv->data, "otr-ui_selected_ctx");
+}
+
static void process_connection_change(PurpleConnection *conn, void *data)
{
/* If we log in or out of a connection, make sure all of the OTR
@@ -840,12 +990,21 @@ static void supply_extended_menu(PurpleBlistNode *node, GList **menu)
*menu = g_list_append(*menu, act);
}
+/* Disconnect all context instances, sending a notice to the other side, if
+ * appropriate. */
+void otrg_plugin_disconnect_all_instances(ConnContext *context)
+{
+ otrl_message_disconnect_all_instances(otrg_plugin_userstate, &ui_ops, NULL,
+ context->accountname, context->protocol, context->username);
+}
+
/* Disconnect a context, sending a notice to the other side, if
* appropriate. */
void otrg_plugin_disconnect(ConnContext *context)
{
otrl_message_disconnect(otrg_plugin_userstate, &ui_ops, NULL,
- context->accountname, context->protocol, context->username);
+ context->accountname, context->protocol, context->username,
+ context->their_instance);
}
/* Write the fingerprints to disk. */
@@ -869,27 +1028,6 @@ void otrg_plugin_write_fingerprints(void)
fclose(storef);
}
-/* Find the ConnContext appropriate to a given PurpleConversation. */
-ConnContext *otrg_plugin_conv_to_context(PurpleConversation *conv)
-{
- PurpleAccount *account;
- char *username;
- const char *accountname, *proto;
- ConnContext *context;
-
- account = purple_conversation_get_account(conv);
- accountname = purple_account_get_username(account);
- proto = purple_account_get_protocol_id(account);
- username = g_strdup(
- purple_normalize(account, purple_conversation_get_name(conv)));
-
- context = otrl_context_find(otrg_plugin_userstate, username, accountname,
- proto, 0, NULL, NULL, NULL);
- g_free(username);
-
- return context;
-}
-
/* Find the PurpleConversation appropriate to the given userinfo. If
* one doesn't yet exist, create it if force_create is true. */
PurpleConversation *otrg_plugin_userinfo_to_conv(const char *accountname,
@@ -925,7 +1063,8 @@ TrustLevel otrg_plugin_context_to_trust(ConnContext *context)
TrustLevel level = TRUST_NOT_PRIVATE;
if (context && context->msgstate == OTRL_MSGSTATE_ENCRYPTED) {
- if (context->active_fingerprint->trust &&
+ if (context->active_fingerprint &&
+ context->active_fingerprint->trust &&
context->active_fingerprint->trust[0] != '\0') {
level = TRUST_PRIVATE;
} else {
@@ -978,7 +1117,7 @@ static void mms_read_FILEp(FILE *mmsf, GHashTable *ght)
mms = tab + 1;
tab = strchr(mms, '\t');
if (tab) continue;
- eol = strchr(mms, '\r');
+ eol = strchr(mms, '\r');
if (!eol) eol = strchr(mms, '\n');
if (!eol) continue;
*eol = '\0';
@@ -1006,10 +1145,10 @@ static void otrg_init_mms_table()
* protocols. These can be overridden in the user's MAXMSGSIZEFNAME
* file. */
static const struct s_OtrgIdProtPair {
- char *protid;
+ char *protid;
int maxmsgsize;
} mmsPairs[8] = {{"prpl-msn", 1409}, {"prpl-icq", 2346},
- {"prpl-aim", 2343}, {"prpl-yahoo", 832}, {"prpl-gg", 1999},
+ {"prpl-aim", 2343}, {"prpl-yahoo", 799}, {"prpl-gg", 1999},
{"prpl-irc", 417}, {"prpl-oscar", 2343}, {NULL, 0}};
int i = 0;
gchar *maxmsgsizefile;
@@ -1019,10 +1158,10 @@ static void otrg_init_mms_table()
otrg_str_free, otrg_int_free);
for (i=0; mmsPairs[i].protid != NULL; i++) {
- char* nextprot = g_strdup(mmsPairs[i].protid);
- int* nextsize = g_malloc(sizeof(int));
- *nextsize = mmsPairs[i].maxmsgsize;
- g_hash_table_insert(mms_table, nextprot, nextsize);
+ char* nextprot = g_strdup(mmsPairs[i].protid);
+ int* nextsize = g_malloc(sizeof(int));
+ *nextsize = mmsPairs[i].maxmsgsize;
+ g_hash_table_insert(mms_table, nextprot, nextsize);
}
maxmsgsizefile = g_build_filename(purple_user_dir(),
@@ -1049,23 +1188,28 @@ static gboolean otr_plugin_load(PurplePlugin *handle)
gchar *privkeyfile = g_build_filename(purple_user_dir(), PRIVKEYFNAME,
NULL);
gchar *storefile = g_build_filename(purple_user_dir(), STOREFNAME, NULL);
+ gchar *instagfile = g_build_filename(purple_user_dir(), INSTAGFNAME, NULL);
void *conv_handle = purple_conversations_get_handle();
void *conn_handle = purple_connections_get_handle();
void *blist_handle = purple_blist_get_handle();
void *core_handle = purple_get_core();
FILE *privf;
FILE *storef;
+ FILE *instagf;
- if (!privkeyfile || !storefile) {
+ if (!privkeyfile || !storefile || !instagfile) {
g_free(privkeyfile);
g_free(storefile);
+ g_free(instagfile);
return 0;
}
privf = g_fopen(privkeyfile, "rb");
storef = g_fopen(storefile, "rb");
+ instagf = g_fopen(instagfile, "rb");
g_free(privkeyfile);
g_free(storefile);
+ g_free(instagfile);
otrg_init_mms_table();
@@ -1077,21 +1221,25 @@ static gboolean otr_plugin_load(PurplePlugin *handle)
otrl_privkey_read_FILEp(otrg_plugin_userstate, privf);
otrl_privkey_read_fingerprints_FILEp(otrg_plugin_userstate, storef,
NULL, NULL);
+ otrl_instag_read_FILEp(otrg_plugin_userstate, instagf);
if (privf) fclose(privf);
if (storef) fclose(storef);
+ if (instagf) fclose(instagf);
otrg_ui_update_fingerprint();
purple_signal_connect(core_handle, "quitting", otrg_plugin_handle,
PURPLE_CALLBACK(process_quitting), NULL);
purple_signal_connect(conv_handle, "sending-im-msg", otrg_plugin_handle,
- PURPLE_CALLBACK(process_sending_im), NULL);
+ PURPLE_CALLBACK(process_sending_im), NULL);
purple_signal_connect(conv_handle, "receiving-im-msg", otrg_plugin_handle,
- PURPLE_CALLBACK(process_receiving_im), NULL);
+ PURPLE_CALLBACK(process_receiving_im), NULL);
purple_signal_connect(conv_handle, "conversation-updated",
otrg_plugin_handle, PURPLE_CALLBACK(process_conv_updated), NULL);
purple_signal_connect(conv_handle, "conversation-created",
otrg_plugin_handle, PURPLE_CALLBACK(process_conv_create), NULL);
+ purple_signal_connect(conv_handle, "deleting-conversation",
+ otrg_plugin_handle, PURPLE_CALLBACK(process_conv_destroyed), NULL);
purple_signal_connect(conn_handle, "signed-on", otrg_plugin_handle,
PURPLE_CALLBACK(process_connection_change), NULL);
purple_signal_connect(conn_handle, "signed-off", otrg_plugin_handle,
@@ -1130,6 +1278,8 @@ static gboolean otr_plugin_unload(PurplePlugin *handle)
otrg_plugin_handle, PURPLE_CALLBACK(process_conv_updated));
purple_signal_disconnect(conv_handle, "conversation-created",
otrg_plugin_handle, PURPLE_CALLBACK(process_conv_create));
+ purple_signal_disconnect(conv_handle, "deleting-conversation",
+ otrg_plugin_handle, PURPLE_CALLBACK(process_conv_destroyed));
purple_signal_disconnect(conn_handle, "signed-on", otrg_plugin_handle,
PURPLE_CALLBACK(process_connection_change));
purple_signal_disconnect(conn_handle, "signed-off", otrg_plugin_handle,
@@ -1174,8 +1324,8 @@ static PurplePluginInfo info =
{
PURPLE_PLUGIN_MAGIC,
- /* Use the 2.0.x API */
- 2, /* major version */
+ /* Use the 2.0.x API */
+ 2, /* major version */
0, /* minor version */
PURPLE_PLUGIN_STANDARD, /* type */
@@ -1188,7 +1338,7 @@ static PurplePluginInfo info =
PIDGIN_OTR_VERSION, /* version */
NULL, /* summary */
NULL, /* description */
- /* author */
+ /* author */
"Ian Goldberg, Rob Smits,\n"
"\t\t\tChris Alexander, Willy Lew, Nikita Borisov\n"
"\t\t\t<otr at cypherpunks.ca>",
@@ -1229,7 +1379,7 @@ __init_plugin(PurplePlugin *plugin)
info.name = _("Off-the-Record Messaging");
info.summary = _("Provides private and secure conversations");
info.description = _("Preserves the privacy of IM communications "
- "by providing encryption, authentication, "
+ "by providing encryption, authentication, "
"deniability, and perfect forward secrecy.");
}
diff --git a/otr-plugin.h b/otr-plugin.h
index 97afced..f3c7b7e 100644
--- a/otr-plugin.h
+++ b/otr-plugin.h
@@ -1,8 +1,8 @@
/*
* Off-the-Record Messaging plugin for pidgin
- * Copyright (C) 2004-2009 Ian Goldberg, Rob Smits,
+ * Copyright (C) 2004-2012 Ian Goldberg, Rob Smits,
* Chris Alexander, Willy Lew,
- * Nikita Borisov
+ * Lisa Du, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This program is free software; you can redistribute it and/or modify
@@ -29,15 +29,25 @@
/* libotr headers */
#include <libotr/context.h>
#include <libotr/userstate.h>
+#include <libotr/instag.h>
#define PRIVKEYFNAME "otr.private_key"
#define STOREFNAME "otr.fingerprints"
+#define INSTAGFNAME "otr.instance_tags"
#define MAXMSGSIZEFNAME "otr.max_message_size"
extern PurplePlugin *otrg_plugin_handle;
extern OtrlUserState otrg_plugin_userstate;
+/* Given a PurpleConversation, return the selected ConnContext */
+ConnContext* otrg_plugin_conv_to_selected_context(PurpleConversation *conv,
+ int force_create);
+
+/* Given a PurpleConversation, return the selected instag */
+otrl_instag_t otrg_plugin_conv_to_selected_instag(PurpleConversation *conv,
+ otrl_instag_t default_value);
+
/* Send an IM from the given account to the given recipient. Display an
* error dialog if that account isn't currently logged in. */
void otrg_plugin_inject_message(PurpleAccount *account, const char *recipient,
@@ -47,6 +57,10 @@ void otrg_plugin_inject_message(PurpleAccount *account, const char *recipient,
void otrg_plugin_create_privkey(const char *accountname,
const char *protocol);
+/* Generate a instance tag for the given accountname/protocol */
+void otrg_plugin_create_instag(const char *accountname,
+ const char *protocol);
+
/* Start the Socialist Millionaires' Protocol over the current connection,
* using the given initial secret, and optionally a question to pass to
* the buddy. */
@@ -77,7 +91,8 @@ void otrg_plugin_disconnect(ConnContext *context);
void otrg_plugin_write_fingerprints(void);
/* Find the ConnContext appropriate to a given PurpleConversation. */
-ConnContext *otrg_plugin_conv_to_context(PurpleConversation *conv);
+ConnContext *otrg_plugin_conv_to_context(PurpleConversation *conv,
+ otrl_instag_t their_instance, int force_create);
/* Find the PurpleConversation appropriate to the given userinfo. If
* one doesn't yet exist, create it if force_create is true. */
@@ -89,6 +104,11 @@ PurpleConversation *otrg_plugin_userinfo_to_conv(const char *accountname,
PurpleConversation *otrg_plugin_context_to_conv(ConnContext *context,
int force_create);
+/* Cause the "msg-received" signal to be emitted with the given message
+ * payload. This causes the message to pop-up in the notification area when the
+ * user has the libnotify plugin enabled. */
+void otrg_emit_msg_received(ConnContext *context, const char* message);
+
typedef enum {
TRUST_NOT_PRIVATE,
TRUST_UNVERIFIED,
diff --git a/packaging/fedora/pidgin-otr.spec b/packaging/fedora/pidgin-otr.spec
index 705360f..15fa31f 100644
--- a/packaging/fedora/pidgin-otr.spec
+++ b/packaging/fedora/pidgin-otr.spec
@@ -1,19 +1,20 @@
Summary: Off-The-Record Messaging plugin for pidgin
Name: pidgin-otr
-Version: 3.1.0
+Version: 4.0.0
Release: 1%{?dist}
Source: http://otr.cypherpunks.ca/%{name}-%{version}.tar.gz
Url: http://otr.cypherpunks.ca/
-License: GPL
+License: GPLv2
Group: Applications/Internet
Provides: gaim-otr = %{version}
Obsoletes: gaim-otr
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
-Requires: pidgin >= 2.0.0, libotr >= 3.1.0
-BuildRequires: glib2-devel, gtk2-devel, libgcrypt-devel >= 1.2.0, libgpg-error-devel, pidgin-devel >= 2.0.0, libotr-devel >= 3.1.0, libpurple-devel
+Requires: pidgin >= 2.0.0, libotr >= 4.0.0
+BuildRequires: glib2-devel, gtk2-devel, libgcrypt-devel >= 1.2.0
+BuildRequires: libgpg-error-devel, pidgin-devel >= 2.0.0
+BuildRequires: libotr-devel >= 4.0.0, perl(XML::Parser), gettext
%description
-
This is a pidgin plugin which implements Off-the-Record (OTR) Messaging.
It is known to work (at least) under the Linux and Windows versions of
pidgin (2.x).
@@ -22,6 +23,11 @@ pidgin (2.x).
%setup -q
%build
+if [ \! -f configure ]; then
+ echo "Building from pre-release"
+ intltoolize --force --copy
+ autoreconf -s -i
+fi
%configure
make %{?_smp_mflags} all
@@ -44,6 +50,11 @@ rm -rf $RPM_BUILD_ROOT
%{_libdir}/pidgin/pidgin-otr.so
%changelog
+* Thu Jun 11 2009 Paul Wouters <paul at xelerance.com> - 4.0.0-1
+- Upgraded to 4.0.0.
+- Updated buildrequires
+- Fix license tag
+
* Thu Jul 26 2007 Paul Wouters <paul at cypherpunks.ca> 3.1.0-preview2
- Added locale support to spec file
- Upgraded to current version
diff --git a/packaging/windows/pidgin-otr.nsi b/packaging/windows/pidgin-otr.nsi
index 54beb3d..b667a37 100644
--- a/packaging/windows/pidgin-otr.nsi
+++ b/packaging/windows/pidgin-otr.nsi
@@ -3,6 +3,7 @@
;
; known issue. installer induced uninstaller abortion causes overwrite
; by installer without uninstall.
+; v4.0.0 - New source version.
; v3.2.0 - New source version.
; v3.1.0 - New source version. Install and uninstall i18n files.
; v3.0.0 - Version for pidgin-2.0.0
@@ -25,7 +26,7 @@
; todo: SetBrandingImage
; HM NIS Edit Wizard helper defines
!define PRODUCT_NAME "pidgin-otr"
-!define PRODUCT_VERSION "3.2.0-1"
+!define PRODUCT_VERSION "4.0.0-0"
!define PRODUCT_PUBLISHER "Cypherpunks CA"
!define PRODUCT_WEB_SITE "http://otr.cypherpunks.ca/"
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
@@ -42,7 +43,7 @@
; Welcome page
!insertmacro MUI_PAGE_WELCOME
; License page
-!insertmacro MUI_PAGE_LICENSE "c:\otr\COPYING.txt"
+!insertmacro MUI_PAGE_LICENSE "../../../libotr/COPYING"
; Directory page
!insertmacro MUI_PAGE_DIRECTORY
; Instfiles page
@@ -81,29 +82,29 @@ Section "MainSection" SEC01
SetOutPath "$PidginDir\locale"
SetOverwrite on
- ; What the next line means is to recursively search c:\otr\locale
+ ; What the next line means is to recursively search /usr/share/locale
; and install all files under there named pidgin-otr.mo
- File /r "c:\otr\locale\pidgin-otr.mo"
+ File /r "/usr/share/locale/pidgin-otr.mo"
SetOutPath "$INSTDIR"
SetOverwrite on
- File "c:\otr\pidgin-otr.dll"
+ File "../../win32_export/pidgin-otr.dll"
; move to pidgin plugin directory, check if not busy (pidgin is running)
call CopyDLL
; hard part is done, do the rest now.
SetOverwrite on
- File "c:\otr\README.Toolkit.txt"
- File "c:\otr\README.txt"
- File "c:\otr\Protocol-v2.html"
- File "c:\otr\COPYING.txt"
- File "c:\otr\COPYING.LIB.txt"
- File "c:\otr\otr_mackey.exe"
- File "c:\otr\otr_modify.exe"
- File "c:\otr\otr_parse.exe"
- File "c:\otr\otr_readforge.exe"
- File "c:\otr\otr_remac.exe"
- File "c:\otr\otr_sesskeys.exe"
- File "c:\otr\pidgin-otr.nsi"
+ File "../../win32_export/README.Toolkit.txt"
+ File "../../win32_export/README.txt"
+ File "../../win32_export/COPYING.txt"
+ File "../../win32_export/COPYING.LIB.txt"
+ File "../../win32_export/Protocol-v2.html"
+ File "../../win32_export/otr_mackey.exe"
+ File "../../win32_export/otr_modify.exe"
+ File "../../win32_export/otr_parse.exe"
+ File "../../win32_export/otr_readforge.exe"
+ File "../../win32_export/otr_remac.exe"
+ File "../../win32_export/otr_sesskeys.exe"
+ File "pidgin-otr.nsi"
SectionEnd
Section -AdditionalIcons
diff --git a/tooltipmenu.c b/tooltipmenu.c
index 880cebb..1478d27 100644
--- a/tooltipmenu.c
+++ b/tooltipmenu.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging plugin for pidgin
- * Copyright (C) 2004-2009 Ian Goldberg, Rob Smits,
+ * Copyright (C) 2004-2012 Ian Goldberg, Rob Smits,
* Chris Alexander, Willy Lew,
* Nikita Borisov
* <otr at cypherpunks.ca>
@@ -53,8 +53,8 @@
* Enums
*****************************************************************************/
enum {
- PROP_ZERO = 0,
- PROP_BOX
+ PROP_ZERO = 0,
+ PROP_BOX
};
/******************************************************************************
@@ -88,69 +88,69 @@ tooltip_menu_deselect(GtkItem *item) {
*****************************************************************************/
static void
tooltip_menu_get_property(GObject *obj, guint param_id, GValue *value,
- GParamSpec *pspec)
+ GParamSpec *pspec)
{
- TooltipMenu *tooltip_menu = TOOLTIP_MENU(obj);
-
- switch(param_id) {
- case PROP_BOX:
- g_value_set_object(value, tooltip_menu_get_box(tooltip_menu));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
- break;
- }
+ TooltipMenu *tooltip_menu = TOOLTIP_MENU(obj);
+
+ switch(param_id) {
+ case PROP_BOX:
+ g_value_set_object(value, tooltip_menu_get_box(tooltip_menu));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+ break;
+ }
}
static void
tooltip_menu_finalize(GObject *obj) {
#if 0
- /* This _might_ be leaking, but I have a sneaking suspicion that the widget is
- * getting destroyed in GtkContainer's finalize function. But if were are
- * leaking here, be sure to figure out why this causes a crash.
- * -- Gary
- */
- TooltipMenu *tray = TOOLTIP_MENU(obj);
-
- if(GTK_IS_WIDGET(tray->tray))
- gtk_widget_destroy(GTK_WIDGET(tray->tray));
+ /* This _might_ be leaking, but I have a sneaking suspicion that the widget is
+ * getting destroyed in GtkContainer's finalize function. But if were are
+ * leaking here, be sure to figure out why this causes a crash.
+ * -- Gary
+ */
+ TooltipMenu *tray = TOOLTIP_MENU(obj);
+
+ if(GTK_IS_WIDGET(tray->tray))
+ gtk_widget_destroy(GTK_WIDGET(tray->tray));
#endif
- G_OBJECT_CLASS(parent_class)->finalize(obj);
+ G_OBJECT_CLASS(parent_class)->finalize(obj);
}
static void
tooltip_menu_class_init(TooltipMenuClass *klass) {
- GObjectClass *object_class = G_OBJECT_CLASS(klass);
- GParamSpec *pspec;
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ GParamSpec *pspec;
- parent_class = g_type_class_peek_parent(klass);
+ parent_class = g_type_class_peek_parent(klass);
- object_class->finalize = tooltip_menu_finalize;
- object_class->get_property = tooltip_menu_get_property;
+ object_class->finalize = tooltip_menu_finalize;
+ object_class->get_property = tooltip_menu_get_property;
- pspec = g_param_spec_object("box", "The box",
+ pspec = g_param_spec_object("box", "The box",
"The box",
GTK_TYPE_BOX,
G_PARAM_READABLE);
- g_object_class_install_property(object_class, PROP_BOX, pspec);
+ g_object_class_install_property(object_class, PROP_BOX, pspec);
}
static void
tooltip_menu_init(TooltipMenu *tooltip_menu) {
- GtkWidget *widget = GTK_WIDGET(tooltip_menu);
- gtk_menu_item_set_right_justified(GTK_MENU_ITEM(tooltip_menu), TRUE);
+ GtkWidget *widget = GTK_WIDGET(tooltip_menu);
+ gtk_menu_item_set_right_justified(GTK_MENU_ITEM(tooltip_menu), TRUE);
- if(!GTK_IS_WIDGET(tooltip_menu->tray))
- tooltip_menu->tray = gtk_hbox_new(FALSE, 0);
+ if(!GTK_IS_WIDGET(tooltip_menu->tray))
+ tooltip_menu->tray = gtk_hbox_new(FALSE, 0);
- tooltip_menu->tooltips = gtk_tooltips_new();
+ tooltip_menu->tooltips = gtk_tooltips_new();
- gtk_widget_set_size_request(widget, -1, -1);
+ gtk_widget_set_size_request(widget, -1, -1);
- gtk_container_add(GTK_CONTAINER(tooltip_menu), tooltip_menu->tray);
+ gtk_container_add(GTK_CONTAINER(tooltip_menu), tooltip_menu->tray);
- gtk_widget_show(tooltip_menu->tray);
+ gtk_widget_show(tooltip_menu->tray);
}
/******************************************************************************
@@ -158,96 +158,96 @@ tooltip_menu_init(TooltipMenu *tooltip_menu) {
*****************************************************************************/
GType
tooltip_menu_get_gtype(void) {
- static GType type = 0;
-
- if(type == 0) {
- static const GTypeInfo info = {
- sizeof(TooltipMenuClass),
- NULL,
- NULL,
- (GClassInitFunc)tooltip_menu_class_init,
- NULL,
- NULL,
- sizeof(TooltipMenu),
- 0,
- (GInstanceInitFunc)tooltip_menu_init,
- NULL
- };
-
- type = g_type_register_static(GTK_TYPE_MENU_ITEM,
- "TooltipMenu",
- &info, 0);
- }
-
- return type;
+ static GType type = 0;
+
+ if(type == 0) {
+ static const GTypeInfo info = {
+ sizeof(TooltipMenuClass),
+ NULL,
+ NULL,
+ (GClassInitFunc)tooltip_menu_class_init,
+ NULL,
+ NULL,
+ sizeof(TooltipMenu),
+ 0,
+ (GInstanceInitFunc)tooltip_menu_init,
+ NULL
+ };
+
+ type = g_type_register_static(GTK_TYPE_MENU_ITEM,
+ "TooltipMenu",
+ &info, 0);
+ }
+
+ return type;
}
GtkWidget *
tooltip_menu_new() {
- return g_object_new(TYPE_TOOLTIP_MENU, NULL);
+ return g_object_new(TYPE_TOOLTIP_MENU, NULL);
}
GtkWidget *
tooltip_menu_get_box(TooltipMenu *tooltip_menu) {
- g_return_val_if_fail(IS_TOOLTIP_MENU(tooltip_menu), NULL);
- return tooltip_menu->tray;
+ g_return_val_if_fail(IS_TOOLTIP_MENU(tooltip_menu), NULL);
+ return tooltip_menu->tray;
}
static void
tooltip_menu_add(TooltipMenu *tooltip_menu, GtkWidget *widget,
- const char *tooltip, gboolean prepend)
+ const char *tooltip, gboolean prepend)
{
- g_return_if_fail(IS_TOOLTIP_MENU(tooltip_menu));
- g_return_if_fail(GTK_IS_WIDGET(widget));
+ g_return_if_fail(IS_TOOLTIP_MENU(tooltip_menu));
+ g_return_if_fail(GTK_IS_WIDGET(widget));
- if (GTK_WIDGET_NO_WINDOW(widget))
- {
- GtkWidget *event;
+ if (GTK_WIDGET_NO_WINDOW(widget))
+ {
+ GtkWidget *event;
- event = gtk_event_box_new();
- gtk_container_add(GTK_CONTAINER(event), widget);
- gtk_widget_show(event);
- widget = event;
- }
+ event = gtk_event_box_new();
+ gtk_container_add(GTK_CONTAINER(event), widget);
+ gtk_widget_show(event);
+ widget = event;
+ }
- tooltip_menu_set_tooltip(tooltip_menu, widget, tooltip);
+ tooltip_menu_set_tooltip(tooltip_menu, widget, tooltip);
- if (prepend)
- gtk_box_pack_start(GTK_BOX(tooltip_menu->tray), widget, FALSE, FALSE, 0);
- else
- gtk_box_pack_end(GTK_BOX(tooltip_menu->tray), widget, FALSE, FALSE, 0);
+ if (prepend)
+ gtk_box_pack_start(GTK_BOX(tooltip_menu->tray), widget, FALSE, FALSE, 0);
+ else
+ gtk_box_pack_end(GTK_BOX(tooltip_menu->tray), widget, FALSE, FALSE, 0);
}
void
tooltip_menu_append(TooltipMenu *tooltip_menu, GtkWidget *widget, const char *tooltip)
{
- tooltip_menu_add(tooltip_menu, widget, tooltip, FALSE);
+ tooltip_menu_add(tooltip_menu, widget, tooltip, FALSE);
}
void
tooltip_menu_prepend(TooltipMenu *tooltip_menu, GtkWidget *widget, const char *tooltip)
{
- tooltip_menu_add(tooltip_menu, widget, tooltip, TRUE);
+ tooltip_menu_add(tooltip_menu, widget, tooltip, TRUE);
}
void
tooltip_menu_set_tooltip(TooltipMenu *tooltip_menu, GtkWidget *widget, const char *tooltip)
{
- if (!tooltip_menu->tooltips)
- return;
-
- /* Should we check whether widget is a child of tooltip_menu? */
-
- /*
- * If the widget does not have it's own window, then it
- * must have automatically been added to an event box
- * when it was added to the menu tray. If this is the
- * case, we want to set the tooltip on the widget's parent,
- * not on the widget itself.
- */
- if (GTK_WIDGET_NO_WINDOW(widget))
- widget = widget->parent;
-
- gtk_tooltips_set_tip(tooltip_menu->tooltips, widget, tooltip, NULL);
+ if (!tooltip_menu->tooltips)
+ return;
+
+ /* Should we check whether widget is a child of tooltip_menu? */
+
+ /*
+ * If the widget does not have it's own window, then it
+ * must have automatically been added to an event box
+ * when it was added to the menu tray. If this is the
+ * case, we want to set the tooltip on the widget's parent,
+ * not on the widget itself.
+ */
+ if (GTK_WIDGET_NO_WINDOW(widget))
+ widget = widget->parent;
+
+ gtk_tooltips_set_tip(tooltip_menu->tooltips, widget, tooltip, NULL);
}
diff --git a/tooltipmenu.h b/tooltipmenu.h
index b5395d0..24a6ee5 100644
--- a/tooltipmenu.h
+++ b/tooltipmenu.h
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging plugin for pidgin
- * Copyright (C) 2004-2009 Ian Goldberg, Rob Smits,
+ * Copyright (C) 2004-2012 Ian Goldberg, Rob Smits,
* Chris Alexander, Willy Lew,
* Nikita Borisov
* <otr at cypherpunks.ca>
@@ -57,13 +57,13 @@ typedef struct _TooltipMenu TooltipMenu;
typedef struct _TooltipMenuClass TooltipMenuClass;
struct _TooltipMenu {
- GtkMenuItem gparent; /**< The parent instance */
- GtkWidget *tray; /**< The tray */
- GtkTooltips *tooltips; /**< Tooltips */
+ GtkMenuItem gparent; /**< The parent instance */
+ GtkWidget *tray; /**< The tray */
+ GtkTooltips *tooltips; /**< Tooltips */
};
struct _TooltipMenuClass {
- GtkMenuItemClass gparent; /**< The parent class */
+ GtkMenuItemClass gparent; /**< The parent class */
};
G_BEGIN_DECLS
diff --git a/ui.c b/ui.c
index 95a32ea..47477f0 100644
--- a/ui.c
+++ b/ui.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging plugin for pidgin
- * Copyright (C) 2004-2009 Ian Goldberg, Rob Smits,
+ * Copyright (C) 2004-2012 Ian Goldberg, Rob Smits,
* Chris Alexander, Willy Lew,
* Nikita Borisov
* <otr at cypherpunks.ca>
@@ -99,52 +99,59 @@ void otrg_ui_connect_connection(ConnContext *context)
/* Send an OTR Query to the other side. */
PurpleAccount *account;
char *msg;
-
+
/* Don't do this if we're already ENCRYPTED */
if (context == NULL || context->msgstate == OTRL_MSGSTATE_ENCRYPTED)
return;
-
+
account = purple_accounts_find(context->accountname, context->protocol);
if (!account) {
PurplePlugin *p = purple_find_prpl(context->protocol);
msg = g_strdup_printf(_("Account %s (%s) could not be found"),
- context->accountname,
- (p && p->info->name) ? p->info->name : _("Unknown"));
+ context->accountname,
+ (p && p->info->name) ? p->info->name : _("Unknown"));
otrg_dialog_notify_error(context->accountname, context->protocol,
context->username, _("Account not found"), msg, NULL);
g_free(msg);
return;
}
- otrg_plugin_send_default_query(context, account);
+ otrg_plugin_send_default_query(context, account);
}
/* Drop a context to PLAINTEXT state */
void otrg_ui_disconnect_connection(ConnContext *context)
{
- /* Don't do anything with PLAINTEXT fingerprints */
- if (context == NULL || context->msgstate == OTRL_MSGSTATE_PLAINTEXT)
+
+ if (context == NULL)
return;
-
+
otrg_plugin_disconnect(context);
- otrg_dialog_disconnected(context);
+ otrg_dialog_disconnected(context);
}
/* Forget a fingerprint */
void otrg_ui_forget_fingerprint(Fingerprint *fingerprint)
{
ConnContext *context;
-
+ ConnContext *context_iter;
+
if (fingerprint == NULL) return;
/* Don't do anything with the active fingerprint if we're in the
* ENCRYPTED state. */
context = fingerprint->context;
- if (context->msgstate == OTRL_MSGSTATE_ENCRYPTED &&
- context->active_fingerprint == fingerprint) return;
-
+
+ for (context_iter = context->m_context;
+ context_iter && context_iter->m_context == context->m_context;
+ context_iter = context_iter->next) {
+
+ if (context_iter->msgstate == OTRL_MSGSTATE_ENCRYPTED &&
+ context_iter->active_fingerprint == fingerprint) return;
+ }
+
otrl_context_forget_fingerprint(fingerprint, 1);
otrg_plugin_write_fingerprints();
-
+
otrg_ui_update_keylist();
}
@@ -164,7 +171,7 @@ void otrg_ui_get_prefs(OtrgUiPrefs *prefsp, PurpleAccount *account,
const char *proto = purple_account_get_protocol_id(account);
if (!otrg_plugin_proto_supports_otr(proto)) {
prefsp->policy = OTRL_POLICY_NEVER;
- prefsp->avoid_logging_otr = FALSE;
+ prefsp->avoid_logging_otr = TRUE;
prefsp->show_otr_button = FALSE;
return;
}
@@ -175,6 +182,6 @@ void otrg_ui_get_prefs(OtrgUiPrefs *prefsp, PurpleAccount *account,
}
/* If we've got no other way to get the prefs, use sensible defaults */
prefsp->policy = OTRL_POLICY_DEFAULT;
- prefsp->avoid_logging_otr = FALSE;
+ prefsp->avoid_logging_otr = TRUE;
prefsp->show_otr_button = FALSE;
}
diff --git a/ui.h b/ui.h
index 9ef64e6..c1c6481 100644
--- a/ui.h
+++ b/ui.h
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging plugin for pidgin
- * Copyright (C) 2004-2009 Ian Goldberg, Rob Smits,
+ * Copyright (C) 2004-2012 Ian Goldberg, Rob Smits,
* Chris Alexander, Willy Lew,
* Nikita Borisov
* <otr at cypherpunks.ca>
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-privacy/packages/pidgin-otr.git
More information about the Pkg-privacy-commits
mailing list