[pkg-otr-team] [irssi-plugin-otr] 06/167: * README: * Makefile.mingw: * packaging/fedora/gaim-otr.spec: * packaging/windows/gaim-otr.nsi: * configure.ac: Change version to 3.0.0

Holger Levsen holger at moszumanska.debian.org
Mon Mar 3 21:55:28 UTC 2014


This is an automated email from the git hooks/post-receive script.

holger pushed a commit to tag 4.0.0
in repository irssi-plugin-otr.

commit 89e49d9b91bfbb732662f0cbd1419a6846bcb7c9
Author: cypherpunk <cypherpunk>
Date:   Fri Jun 24 21:33:29 2005 +0000

    	* README:
    	* Makefile.mingw:
    	* packaging/fedora/gaim-otr.spec:
    	* packaging/windows/gaim-otr.nsi:
    	* configure.ac: Change version to 3.0.0
    
    	* Makefile.mingw: add -lgtk_pixbuf-2.0-0 for the OTR button
    	pixmaps.
    
    	* configure.ac: Require libotr 3.x.
    
    	* dialogs.h:
    	* dialogs.c (otrg_dialog_unknown_fingerprint): This function now
    	merely informs the user that a new fingerprint has been
    	received, and doesn't require the user to confirm it before it
    	can be used.
    
    	* dialogs.h:
    	* dialogs.c (otrg_dialog_verify_fingerprint): New function to
    	allow the user to confirm the authenticity of a fingerprint.
    
    	* dialogs.h: Add #defines for the online help URLs.
    
    	* gtk-dialog.c: There are now three states a conversation can be
    	in: Not Private (not using OTR), Unverified (using OTR, but to a
    	fingerprint that hasn't been verified, so you are subject to a
    	straightforward active attack), and Private (using OTR with a
    	verified fingerprint).  There are new icons for these states
    	that appear in the OTR button.
    
    	* gtk-dialog.c: Callers of create_dialog can now specify
    	additional widgets to appear in the dialog boxes.  We use this
    	primarily for the "What's this?" help widgets.
    
    	* gtk-dialog.c (otrg_gtk_dialog_unknown_fingerprint): This
    	function no longer has to deal with callbacks to get the user's
    	response to the new fingerprint.
    
    	* gtk-dialog.c: Right-clicking the OTR button now produces an
    	OTR menu, with options to start or end the private conversation,
    	verify the fingerprint, view the secure session id, or get help.
    
    	* gtk-dialog.c (dialog_update_label_conv): Have the OTR button
    	obey the user's requested style (text only, pictures only,
    	pictures and text, none).  Note that if the user chooses "none",
    	there's currently no way to reach the aforementioned menu.
    
    	* gtk-dialog.c: The "private connection established", "private
    	connection refreshed", and "private connection ended" messages
    	no longer pop up dialog boxes.  Instead, they appear inline in
    	the conversation window.  The session id and fingerprint which
    	used to appear in the "private connection established" dialog
    	are now viewable via the OTR button right-click menu.
    
    	* gtk-dialog.c: New dialog to view and verify fingerprints.
    
    	* gtk-dialog.c: New dialog to view secure session id.
    
    	* gtk-ui.c: New "Verify fingerprint" button in the plugin UI,
    	and rearrangement of the (now four) buttons into a 2x2 table.
    
    	* gtk-ui.c: New "Verified" column in the Known Fingerprints
    	table.
    
    	* otr-plugin.c (confirm_fingerprint_cb): This function no longer
    	has to deal with callbacks due to the change in the libotr API.
    
    	* otr-plugin.h:
    	* otr-plugin.c (otrg_plugin_write_fingerprints): Refactored this
    	function so that other parts of the code can call it.
    
    	* otr-plugin.h:
    	* otr-plugin.c (otrg_plugin_conv_to_context)
    	(otrg_plugin_context_to_conv, otrg_plugin_context_to_trust): New
    	functions.
---
 ChangeLog                      |  78 ++++
 Makefile.mingw                 |   6 +-
 NEWS                           |  21 ++
 configure.ac                   |   4 +-
 dialogs.c                      |  23 +-
 dialogs.h                      |  30 +-
 gtk-dialog.c                   | 781 ++++++++++++++++++++++++++++++++---------
 gtk-ui.c                       |  75 ++--
 otr-plugin.c                   |  89 ++++-
 otr-plugin.h                   |  20 ++
 packaging/fedora/gaim-otr.spec |   4 +-
 packaging/windows/gaim-otr.nsi |   3 +-
 ui.c                           |   5 +-
 13 files changed, 897 insertions(+), 242 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 8f2cb8d..c65dec6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,81 @@
+2005-06-24
+
+	* README:
+	* Makefile.mingw:
+	* packaging/fedora/gaim-otr.spec:
+	* packaging/windows/gaim-otr.nsi:
+	* configure.ac: Change version to 3.0.0
+
+	* Makefile.mingw: add -lgtk_pixbuf-2.0-0 for the OTR button
+	pixmaps.
+
+	* configure.ac: Require libotr 3.x.
+
+	* dialogs.h:
+	* dialogs.c (otrg_dialog_unknown_fingerprint): This function now
+	merely informs the user that a new fingerprint has been
+	received, and doesn't require the user to confirm it before it
+	can be used.
+
+	* dialogs.h:
+	* dialogs.c (otrg_dialog_verify_fingerprint): New function to
+	allow the user to confirm the authenticity of a fingerprint.
+
+	* dialogs.h: Add #defines for the online help URLs.
+
+	* gtk-dialog.c: There are now three states a conversation can be
+	in: Not Private (not using OTR), Unverified (using OTR, but to a
+	fingerprint that hasn't been verified, so you are subject to a
+	straightforward active attack), and Private (using OTR with a
+	verified fingerprint).  There are new icons for these states
+	that appear in the OTR button.
+
+	* gtk-dialog.c: Callers of create_dialog can now specify
+	additional widgets to appear in the dialog boxes.  We use this
+	primarily for the "What's this?" help widgets.
+
+	* gtk-dialog.c (otrg_gtk_dialog_unknown_fingerprint): This
+	function no longer has to deal with callbacks to get the user's
+	response to the new fingerprint.
+
+	* gtk-dialog.c: Right-clicking the OTR button now produces an
+	OTR menu, with options to start or end the private conversation,
+	verify the fingerprint, view the secure session id, or get help.
+
+	* gtk-dialog.c (dialog_update_label_conv): Have the OTR button
+	obey the user's requested style (text only, pictures only,
+	pictures and text, none).  Note that if the user chooses "none",
+	there's currently no way to reach the aforementioned menu.
+
+	* gtk-dialog.c: The "private connection established", "private
+	connection refreshed", and "private connection ended" messages
+	no longer pop up dialog boxes.  Instead, they appear inline in
+	the conversation window.  The session id and fingerprint which
+	used to appear in the "private connection established" dialog
+	are now viewable via the OTR button right-click menu.
+
+	* gtk-dialog.c: New dialog to view and verify fingerprints.
+
+	* gtk-dialog.c: New dialog to view secure session id.
+
+	* gtk-ui.c: New "Verify fingerprint" button in the plugin UI,
+	and rearrangement of the (now four) buttons into a 2x2 table.
+
+	* gtk-ui.c: New "Verified" column in the Known Fingerprints
+	table.
+
+	* otr-plugin.c (confirm_fingerprint_cb): This function no longer
+	has to deal with callbacks due to the change in the libotr API.
+
+	* otr-plugin.h:
+	* otr-plugin.c (otrg_plugin_write_fingerprints): Refactored this
+	function so that other parts of the code can call it.
+
+	* otr-plugin.h:
+	* otr-plugin.c (otrg_plugin_conv_to_context)
+	(otrg_plugin_context_to_conv, otrg_plugin_context_to_trust): New
+	functions.
+
 2005-05-27
 
 	* otr-plugin.c:
diff --git a/Makefile.mingw b/Makefile.mingw
index bd113f1..5021a6a 100644
--- a/Makefile.mingw
+++ b/Makefile.mingw
@@ -1,7 +1,7 @@
 WIN32=1
 
 # The version number to put in the plugin info
-GAIM_OTR_VERSION = 2.0.2
+GAIM_OTR_VERSION = 3.0.0
 
 # Replace this with the path to the GAIM headers
 GAIM_SOURCE ?= /usr/include/gaim
@@ -27,8 +27,8 @@ LIBOTRLIBDIR = /usr/i586-mingw32msvc/lib
 TARGET = gaim-otr.dll
 LDFLAGS = -Wl,--enable-auto-image-base
 LDLIBS = $(LIBOTRLIBDIR)/libotr.a -lgtk-win32-2.0-0 -latk-1.0-0 -lpango-1.0-0 \
-         -lglib-2.0-0 -lgdk-win32-2.0-0 -lgobject-2.0-0 -lgaim \
-         -lgcrypt -lgpg-error
+         -lglib-2.0-0 -lgdk_pixbuf-2.0-0 -lgdk-win32-2.0-0 -lgobject-2.0-0 \
+	 -lgaim -lgcrypt -lgpg-error
 else
 FPIC = -fPIC
 LDFLAGS = -module -avoid-version
diff --git a/NEWS b/NEWS
index 16ebf9e..4e1a54f 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,24 @@
+24 Jun 2005:
+- There are now three states a conversation can be in:
+    * Not Private (not using OTR)
+    * Unverified (using OTR, but to a fingerprint that hasn't
+		  been verified, so you are subject to a straightforward
+		  active attack)
+    * Private (using OTR with a verified fingerprint)
+- There are new icons for these states that appear in the OTR button.
+- Right-clicking the OTR button now produces an OTR menu, with options
+  to start or end the private conversation, verify the fingerprint, view
+  the secure session id, or get help.
+- The OTR button obeys the user's requested style (text only, pictures
+  only, pictures and text, none).  Note that if the user chooses "none",
+  there's currently no way to reach the aforementioned menu.
+- The "private connection established", "private connection refreshed",
+  and "private connection ended" messages no longer pop up dialog boxes.
+  Instead, they appear inline in the conversation window.  The session
+  id and fingerprint which used to appear in the "private connection
+  established" dialog are now viewable via the OTR button right-click
+  menu.
+
 27 May 2005:
 - The OTR button no longer disappears if you change your button style in
   the gaim preferences.
diff --git a/configure.ac b/configure.ac
index 2f4d650..01c9970 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7,7 +7,7 @@ AC_INIT(otr-plugin.c)
 
 AM_CONFIG_HEADER(config.h)
 
-AM_INIT_AUTOMAKE(gaim-otr, 2.0.2)
+AM_INIT_AUTOMAKE(gaim-otr, 3.0.0)
 
 AC_PROG_CC
 
@@ -17,7 +17,7 @@ AM_PROG_LIBTOOL
 
 AM_PATH_LIBGCRYPT(1:1.2.0,,AC_MSG_ERROR(libgcrypt 1.2.0 or newer is required.))
 
-AM_PATH_LIBOTR(2.0.2,,AC_MSG_ERROR(libotr 2.0.2 or newer is required.))
+AM_PATH_LIBOTR(3.0.0,,AC_MSG_ERROR(libotr 3.0.0 or newer is required.))
 
 PKG_CHECK_MODULES(EXTRA, glib-2.0 >= 2.4 gtk+-2.0 >= 2.4 gaim >= 1.0, , AC_MSG_ERROR(glib, gtk and gaim required))
 
diff --git a/dialogs.c b/dialogs.c
index 95920a1..0eebe41 100644
--- a/dialogs.c
+++ b/dialogs.c
@@ -112,20 +112,17 @@ void otrg_dialog_private_key_wait_done(OtrgDialogWaitHandle handle)
 }
 
 /* Show a dialog informing the user that a correspondent (who) has sent
- * us a Key Exchange Message (kem) that contains an unknown fingerprint.
- * Ask the user whether to accept the fingerprint or not.  If yes, call
- * response_cb(us, ops, opdata, response_data, resp) with resp = 1.  If no,
- * set resp = 0.  If the user destroys the dialog without answering, set
- * resp = -1. */
+ * us a Key Exchange Message (kem) that contains an unknown fingerprint. */
 void otrg_dialog_unknown_fingerprint(OtrlUserState us, const char *accountname,
-	const char *protocol, const char *who, OTRKeyExchangeMsg kem,
-	void (*response_cb)(OtrlUserState us, OtrlMessageAppOps *ops,
-	    void *opdata, OTRConfirmResponse *response_data, int resp),
-	OtrlMessageAppOps *ops, void *opdata,
-	OTRConfirmResponse *response_data)
-{
-    ui_ops->unknown_fingerprint(us, accountname, protocol, who, kem,
-	    response_cb, ops, opdata, response_data);
+	const char *protocol, const char *who, OTRKeyExchangeMsg kem)
+{
+    ui_ops->unknown_fingerprint(us, accountname, protocol, who, kem);
+}
+
+/* Show a dialog asking the user to verify the given fingerprint. */
+void otrg_dialog_verify_fingerprint(Fingerprint *fprint)
+{
+    ui_ops->verify_fingerprint(fprint);
 }
 
 /* Call this when a context transitions from (a state other than
diff --git a/dialogs.h b/dialogs.h
index 893441d..a335f10 100644
--- a/dialogs.h
+++ b/dialogs.h
@@ -27,6 +27,13 @@
 #include <libotr/proto.h>
 #include <libotr/message.h>
 
+/* The various help URLs */
+#define BASE_HELPURL "http://otr-help.cypherpunks.ca/"
+#define FINGERPRINT_HELPURL   BASE_HELPURL "fingerprint.php"
+#define SESSIONID_HELPURL     BASE_HELPURL "sessionid.php"
+#define UNVERIFIED_HELPURL    BASE_HELPURL "unverified.php"
+#define BUTTON_HELPURL        BASE_HELPURL "buttonhelp.php"
+
 typedef struct s_OtrgDialogWait *OtrgDialogWaitHandle;
 
 typedef struct {
@@ -43,11 +50,9 @@ typedef struct {
     void (*private_key_wait_done)(OtrgDialogWaitHandle handle);
 
     void (*unknown_fingerprint)(OtrlUserState us, const char *accountname,
-	const char *protocol, const char *who, OTRKeyExchangeMsg kem,
-	void (*response_cb)(OtrlUserState us, OtrlMessageAppOps *ops,
-	    void *opdata, OTRConfirmResponse *response_data, int resp),
-	OtrlMessageAppOps *ops, void *opdata,
-	OTRConfirmResponse *response_data);
+	const char *protocol, const char *who, OTRKeyExchangeMsg kem);
+
+    void (*verify_fingerprint)(Fingerprint *fprint);
 
     void (*connected)(ConnContext *context);
 
@@ -106,17 +111,12 @@ OtrgDialogWaitHandle otrg_dialog_private_key_wait_start(const char *account,
 void otrg_dialog_private_key_wait_done(OtrgDialogWaitHandle handle);
 
 /* Show a dialog informing the user that a correspondent (who) has sent
- * us a Key Exchange Message (kem) that contains an unknown fingerprint.
- * Ask the user whether to accept the fingerprint or not.  If yes, call
- * response_cb(us, ops, opdata, response_data, resp) with resp = 1.  If no,
- * set resp = 0.  If the user destroys the dialog without answering, set
- * resp = -1. */
+ * us a Key Exchange Message (kem) that contains an unknown fingerprint. */
 void otrg_dialog_unknown_fingerprint(OtrlUserState us, const char *accountname,
-	const char *protocol, const char *who, OTRKeyExchangeMsg kem,
-	void (*response_cb)(OtrlUserState us, OtrlMessageAppOps *ops,
-	    void *opdata, OTRConfirmResponse *response_data, int resp),
-	OtrlMessageAppOps *ops, void *opdata,
-	OTRConfirmResponse *response_data);
+	const char *protocol, const char *who, OTRKeyExchangeMsg kem);
+
+/* Show a dialog asking the user to verify the given fingerprint. */
+void otrg_dialog_verify_fingerprint(Fingerprint *fprint);
 
 /* Call this when a context transitions from (a state other than
  * CONN_CONNECTED) to CONN_CONNECTED. */
diff --git a/gtk-dialog.c b/gtk-dialog.c
index 63d03db..b735dfd 100644
--- a/gtk-dialog.c
+++ b/gtk-dialog.c
@@ -30,6 +30,8 @@
 #include "plugin.h"
 #include "notify.h"
 #include "gtkconv.h"
+#include "gtkutils.h"
+#include "gtkimhtml.h"
 #include "util.h"
 
 /* libotr headers */
@@ -44,6 +46,126 @@
 #include "dialogs.h"
 #include "ui.h"
 
+/* The OTR icons */
+
+static const char * not_private_xpm[] = {
+"26 24 3 1",
+" 	c None",
+".	c #000000",
+"+	c #FF0000",
+"      ..            ...   ",
+"     .++.          .+++.  ",
+"     .++.         ..++++. ",
+"     .+++.       .++++++. ",
+"     .++++.     .+++++++. ",
+"      .++++.   .++++++++. ",
+"      .+++++. .+++++++++. ",
+"       .+++++..++++++++.  ",
+"        .+++++.+++++++.   ",
+"        .++++++++++++.    ",
+"        .+++++++++++.     ",
+"         .+++++++++.      ",
+"          .+++++++.       ",
+"         .+++++++++.      ",
+"        .+++++++++++.     ",
+"       .+++++++++++++.    ",
+"      .+++++++++++++++..  ",
+"      .+++++++.+++++++++. ",
+"     .++++++...++++++++++.",
+"    .++++++.   .+++++++++.",
+"   .++++++.     .++++++++.",
+" ..++++++.       .+++++++.",
+".+++++++.         .+++++. ",
+" .......           .....  "};
+
+static const char * unverified_xpm[] = {
+"16 24 3 1",
+" 	c None",
+".	c #000000",
+"+	c #FFFF00",
+"   ........     ",
+" ..++++++++..   ",
+".++++++++++++.  ",
+".++++...++++++. ",
+".+++.   .++++++.",
+".++.     .+++++.",
+".++.     .+++++.",
+" ..      .+++++.",
+"         .+++++.",
+"        .+++++. ",
+"       ..+++++. ",
+"      .++++++.  ",
+"     .+++++..   ",
+"     .++...     ",
+"     .++.       ",
+"     .++.       ",
+"     ....       ",
+"    .++++.      ",
+"   .++++++.     ",
+"   .++++++.     ",
+"   .++++++.     ",
+"   .++++++.     ",
+"    .++++.      ",
+"     ....       "};
+
+static const char * private_xpm[] = {
+"22 24 3 1",
+" 	c None",
+".	c #000000",
+"+	c #00FF00",
+"                    . ",
+"                   .+.",
+"                  .++.",
+"                 .+++.",
+"                .++++.",
+"               .+++++.",
+"              .++++++.",
+"             .+++++++.",
+"  ...       .+++++++. ",
+" .+++.     .+++++++.  ",
+".+++++.   .+++++++.   ",
+".+++++.  .+++++++.    ",
+".+++++. .+++++++.     ",
+".+++++..+++++++.      ",
+".+++++.+++++++.       ",
+".++++++++++++.        ",
+".+++++++++++.         ",
+".++++++++++.          ",
+".+++++++++.           ",
+".++++++++.            ",
+".+++++++.             ",
+".++++++.              ",
+" .++++.               ",
+"  ....                "};
+
+static GtkWidget *otr_icon(GtkWidget *image, TrustLevel level)
+{
+    GdkPixbuf *pixbuf = NULL;
+    const char **data = NULL;
+
+    switch(level) {
+	case TRUST_NOT_PRIVATE:
+	    data = not_private_xpm;
+	    break;
+	case TRUST_UNVERIFIED:
+	    data = unverified_xpm;
+	    break;
+	case TRUST_PRIVATE:
+	    data = private_xpm;
+	    break;
+    }
+
+    pixbuf = gdk_pixbuf_new_from_xpm_data(data);
+    if (image) {
+	gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
+    } else {
+	image = gtk_image_new_from_pixbuf(pixbuf);
+    }
+    gdk_pixbuf_unref(pixbuf);
+
+    return image;
+}
+
 static void message_response_cb(GtkDialog *dialog, gint id, GtkWidget *widget)
 {
     gtk_widget_destroy(GTK_WIDGET(widget));
@@ -51,10 +173,12 @@ static void message_response_cb(GtkDialog *dialog, gint id, GtkWidget *widget)
 
 static GtkWidget *create_dialog(GaimNotifyMsgType type, const char *title,
 	const char *primary, const char *secondary, int sensitive,
-	GtkWidget **labelp)
+	GtkWidget **labelp, void (*add_custom)(GtkWidget *vbox, void *data),
+	void *add_custom_data)
 {
     GtkWidget *dialog;
     GtkWidget *hbox;
+    GtkWidget *vbox;
     GtkWidget *label;
     GtkWidget *img = NULL;
     char *label_text;
@@ -102,6 +226,7 @@ static GtkWidget *create_dialog(GaimNotifyMsgType type, const char *title,
     gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), 6);
 
     hbox = gtk_hbox_new(FALSE, 12);
+    vbox = gtk_vbox_new(FALSE, 0);
     gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
 
     if (img != NULL) {
@@ -120,7 +245,11 @@ static GtkWidget *create_dialog(GaimNotifyMsgType type, const char *title,
     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(hbox), label, FALSE, FALSE, 0);
+    gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
+    if (add_custom) {
+	add_custom(vbox, add_custom_data);
+    }
+    gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
 
     gtk_widget_show_all(dialog);
 
@@ -135,7 +264,7 @@ static void otrg_gtk_dialog_notify_message(GaimNotifyMsgType type,
 	const char *accountname, const char *protocol, const char *username,
 	const char *title, const char *primary, const char *secondary)
 {
-    create_dialog(type, title, primary, secondary, 1, NULL);
+    create_dialog(type, title, primary, secondary, 1, NULL, NULL, NULL);
 }
 
 struct s_OtrgDialogWait {
@@ -166,7 +295,7 @@ static OtrgDialogWaitHandle otrg_gtk_dialog_private_key_wait_start(
 	    account, protocol_print);
 	
     dialog = create_dialog(GAIM_NOTIFY_MSG_INFO, title, primary, secondary,
-	    0, &label);
+	    0, &label, NULL, NULL);
     handle = malloc(sizeof(struct s_OtrgDialogWait));
     handle->dialog = dialog;
     handle->label = label;
@@ -218,35 +347,67 @@ static void otrg_gtk_dialog_private_key_wait_done(OtrgDialogWaitHandle handle)
     free(handle);
 }
 
-struct ufcbdata {
-    GtkDialog *dialog;
-    void (*response_cb)(OtrlUserState us, OtrlMessageAppOps *ops, void *opdata,
-	    OTRConfirmResponse *response_data, int resp);
-    OtrlUserState us;
-    OtrlMessageAppOps *ops;
-    void *opdata;
-    OTRConfirmResponse *response_data;
-    int response;
-};
-
-static void unknown_fingerprint_destroy(GtkWidget *w, struct ufcbdata *cbdata)
+/* Adds a "What's this?" expander to a vbox, containing { some "whatsthis"
+ * markup (displayed in a GtkLabel) and a "More..." expander, containing
+ * { some "more" markup (displayed in a GtkIMHTML) } }. */
+static void add_whatsthis_more(GtkWidget *vbox, const char *whatsthismarkup,
+	const char *moremarkup)
 {
-    if (cbdata->response_cb) {
-	cbdata->response_cb(cbdata->us, cbdata->ops, cbdata->opdata,
-		cbdata->response_data, cbdata->response);
-    }
-    free(cbdata);
+    GtkWidget *expander;
+    GtkWidget *ebox;
+    GtkWidget *whatsthis;
+    GtkWidget *more;
+    GtkWidget *frame;
+    GtkWidget *scrl;
+    GtkWidget *imh;
+    GdkFont *font;
+
+    expander = gtk_expander_new_with_mnemonic("_What's this?");
+    gtk_box_pack_start(GTK_BOX(vbox), expander, FALSE, FALSE, 0);
+    frame = gtk_frame_new(NULL);
+    gtk_container_add(GTK_CONTAINER(expander), frame);
+    ebox = gtk_vbox_new(FALSE, 10);
+    gtk_container_add(GTK_CONTAINER(frame), ebox);
+    whatsthis = gtk_label_new(NULL);
+    gtk_label_set_line_wrap(GTK_LABEL(whatsthis), TRUE);
+    gtk_label_set_markup(GTK_LABEL(whatsthis), whatsthismarkup);
+
+    gtk_box_pack_start(GTK_BOX(ebox), whatsthis, FALSE, FALSE, 0);
+    more = gtk_expander_new_with_mnemonic("_More...");
+    gtk_box_pack_start(GTK_BOX(ebox), more, FALSE, FALSE, 0);
+    scrl = gtk_scrolled_window_new(NULL, NULL);
+    gtk_container_add(GTK_CONTAINER(more), scrl);
+
+    imh = gtk_imhtml_new(NULL, NULL);
+    gaim_setup_imhtml(imh);
+    gtk_imhtml_append_text(GTK_IMHTML(imh), moremarkup, GTK_IMHTML_NO_SCROLL);
+
+    gtk_container_add(GTK_CONTAINER(scrl), imh);
+    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrl),
+	    GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+
+    /* This is a deprecated API, but mucking with PangoFontDescriptions
+     * is (a) complicated, and (b) not fully supported by older versions
+     * of libpango, which some people may have. */
+    font = gtk_style_get_font(imh->style);
+    gtk_widget_set_size_request(scrl, -1, 6 * (font->ascent + font->descent));
 }
 
-static void unknown_fingerprint_response(GtkWidget *w, int resp,
-	struct ufcbdata *cbdata)
+static void add_unk_fingerprint_expander(GtkWidget *vbox, void *data)
 {
-    if (resp == GTK_RESPONSE_OK) {
-	cbdata->response = 1;
-    } else if (resp == GTK_RESPONSE_CANCEL) {
-	cbdata->response = 0;
-    }
-    gtk_widget_destroy(GTK_WIDGET(cbdata->dialog));
+    add_whatsthis_more(vbox,
+	    "A <b>fingerprint</b> is a unique identifier that you should "
+	    "use to authenticate your buddy.  Right-click on the OTR button "
+	    "in your buddy's conversation window, and choose \"Verify "
+	    "fingerprint\".",
+
+	    "If your buddy has more than one IM account, or uses more than "
+	    "one computer, he may have multiple fingerprints.\n\n"
+	    "However, the only way an imposter could duplicate one of your "
+	    "buddy's fingerprints is by stealing information from his "
+	    "computer.\n\n"
+	    "<a href=\"" FINGERPRINT_HELPURL "\">"
+	    "Click here for more information about fingerprints.</a>");
 }
 
 /* Show a dialog informing the user that a correspondent (who) has sent
@@ -257,178 +418,391 @@ static void unknown_fingerprint_response(GtkWidget *w, int resp,
  * resp = -1. */
 static void otrg_gtk_dialog_unknown_fingerprint(OtrlUserState us,
 	const char *accountname, const char *protocol, const char *who,
-	OTRKeyExchangeMsg kem,
-	void (*response_cb)(OtrlUserState us, OtrlMessageAppOps *ops,
-	    void *opdata, OTRConfirmResponse *response_data, int resp),
-	OtrlMessageAppOps *ops, void *opdata,
-	OTRConfirmResponse *response_data)
+	OTRKeyExchangeMsg kem)
 {
     char hash[45];
-    GtkWidget *img;
-    GtkWidget *dialog;
-    GtkWidget *hbox;
-    GtkWidget *label;
-    char *label_text;
-    struct ufcbdata *cbd = malloc(sizeof(struct ufcbdata));
-    const char *icon_name = GAIM_STOCK_DIALOG_WARNING;
+    char *primary, *secondary;
     GaimPlugin *p = gaim_find_prpl(protocol);
     
-    img = gtk_image_new_from_stock(icon_name, GTK_ICON_SIZE_DIALOG);
-    gtk_misc_set_alignment(GTK_MISC(img), 0, 0);
-
-    dialog = gtk_dialog_new_with_buttons( "Unknown Fingerprint",
-	    NULL, GTK_DIALOG_NO_SEPARATOR, GTK_STOCK_OK, GTK_RESPONSE_OK,
-	    GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);
-    gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
-
-    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_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), 12);
-    gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), 6);
-
-    hbox = gtk_hbox_new(FALSE, 12);
-    gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
-
-    if (img != NULL)
-	gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
-
     otrl_privkey_hash_to_human(hash, kem->key_fingerprint);
-    label_text = g_strdup_printf("<span weight=\"bold\" size=\"larger\">%s "
-	    "(%s) has received an unknown fingerprint from %s:</span>\n\n"
-	    "%s\n\n"
-	    "Do you want to accept this fingerprint as valid?", accountname,
-	    (p && p->info->name) ? p->info->name : "Unknown", who, hash);
-
-    label = gtk_label_new(NULL);
+    primary = g_strdup_printf("%s (%s) has received an unknown fingerprint "
+	    "from %s:", accountname, 
+	    (p && p->info->name) ? p->info->name : "Unknown", who);
+    secondary = g_strdup_printf("%s\n", hash);
 
-    gtk_label_set_markup(GTK_LABEL(label), 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(hbox), label, FALSE, FALSE, 0);
-    g_free(label_text);
-
-    cbd->dialog = GTK_DIALOG(dialog);
-    cbd->response_cb = response_cb;
-    cbd->us = us;
-    cbd->ops = ops;
-    cbd->opdata = opdata;
-    cbd->response_data = response_data;
-    cbd->response = -1;
-    g_signal_connect(G_OBJECT(dialog), "destroy",
-	    G_CALLBACK(unknown_fingerprint_destroy), cbd);
-    g_signal_connect(G_OBJECT(dialog), "response",
-	    G_CALLBACK(unknown_fingerprint_response), cbd);
+    create_dialog(GAIM_NOTIFY_MSG_WARNING, "Unknown fingerprint",
+	    primary, secondary, 1, NULL, add_unk_fingerprint_expander, NULL);
 
-    gtk_widget_show_all(dialog);
+    g_free(primary);
+    g_free(secondary);
 }
 
 static void otrg_gtk_dialog_clicked_connect(GtkWidget *widget, gpointer data);
 
-static void dialog_update_label_conv(GaimConversation *conv, int is_private)
+static void dialog_update_label_conv(GaimConversation *conv, TrustLevel level)
 {
     GtkWidget *label;
+    GtkWidget *icon;
+    GtkWidget *icontext;
     GtkWidget *button;
-    GtkWidget *menuitem;
-    GtkWidget *menuitemlabel;
+    GtkWidget *menuquery;
+    GtkWidget *menuend;
+    GtkWidget *menuquerylabel;
+    GtkWidget *menuview;
+    GtkWidget *menuverf;
+    GaimButtonStyle buttonstyle;
     GaimGtkConversation *gtkconv = GAIM_GTK_CONVERSATION(conv);
     label = gaim_conversation_get_data(conv, "otr-label");
+    icon = gaim_conversation_get_data(conv, "otr-icon");
+    icontext = gaim_conversation_get_data(conv, "otr-icontext");
     button = gaim_conversation_get_data(conv, "otr-button");
-    menuitem = gaim_conversation_get_data(conv, "otr-menuitem");
-    menuitemlabel = gtk_bin_get_child(GTK_BIN(menuitem));
-
-    /* Set the button's label and tooltip. */
+    menuquery = gaim_conversation_get_data(conv, "otr-menuquery");
+    menuquerylabel = gtk_bin_get_child(GTK_BIN(menuquery));
+    menuend = gaim_conversation_get_data(conv, "otr-menuend");
+    menuview = gaim_conversation_get_data(conv, "otr-menuview");
+    menuverf = gaim_conversation_get_data(conv, "otr-menuverf");
+    buttonstyle = gaim_prefs_get_int("/gaim/gtk/conversations/button_type");
+
+    /* Set the button's icon, label and tooltip. */
+    otr_icon(icon, level);
     gtk_label_set_text(GTK_LABEL(label),
-	    is_private ? "OTR:\nPrivate" : "OTR:\nNot private");
+	    level == TRUST_PRIVATE ? "Private" :
+	    level == TRUST_UNVERIFIED ? "Unverified" :
+	    "Not private");
     gtk_tooltips_set_tip(gtkconv->tooltips, button,
-	    is_private ? "Refresh the private conversation"
-		       : "Start a private conversation", NULL);
+	    level == TRUST_NOT_PRIVATE ? "Start a private conversation" :
+		    "Refresh the private conversation", NULL);
+
+    /* Set the menu item label for the OTR Query item. */
+    gtk_label_set_markup_with_mnemonic(GTK_LABEL(menuquerylabel),
+	    level == TRUST_NOT_PRIVATE ? "Start _private conversation" :
+		    "Refresh _private conversation");
 
-    /* Set the menu item label. */
-    gtk_label_set_markup_with_mnemonic(GTK_LABEL(menuitemlabel),
-	    is_private ? "Refresh _private conversation"
-		       : "Start _private conversation");
+    /* Sensitize the menu items as appropriate. */
+    gtk_widget_set_sensitive(GTK_WIDGET(menuend), level != TRUST_NOT_PRIVATE);
+    gtk_widget_set_sensitive(GTK_WIDGET(menuview), level != TRUST_NOT_PRIVATE);
+    gtk_widget_set_sensitive(GTK_WIDGET(menuverf), level != TRUST_NOT_PRIVATE);
 
     /* Use any non-NULL value for "private", NULL for "not private" */
     gaim_conversation_set_data(conv, "otr-private",
-	    is_private ? conv : NULL);
+	    level == TRUST_NOT_PRIVATE ? NULL : conv);
+
+    /* Set the appropriate visibility */
+    gtk_widget_show_all(button);
+    if (buttonstyle == GAIM_BUTTON_IMAGE) {
+	/* Hide the text */
+	gtk_widget_hide(icontext);
+	gtk_widget_hide(label);
+    }
+    if (buttonstyle == GAIM_BUTTON_TEXT) {
+	/* Hide the icon */
+	gtk_widget_hide(icontext);
+	gtk_widget_hide(icon);
+    }
 }
 
-static void dialog_update_label(ConnContext *context, int is_private)
+static void dialog_update_label(ConnContext *context)
 {
     GaimAccount *account;
     GaimConversation *conv;
+    TrustLevel level = otrg_plugin_context_to_trust(context);
 
     account = gaim_accounts_find(context->accountname, context->protocol);
     if (!account) return;
     conv = gaim_find_conversation_with_account(context->username, account);
     if (!conv) return;
-    dialog_update_label_conv(conv, is_private);
+    dialog_update_label_conv(conv, level);
 }
 
-/* Call this when a context transitions from (a state other than
- * CONN_CONNECTED) to CONN_CONNECTED. */
-static void otrg_gtk_dialog_connected(ConnContext *context)
+/* Add the help text for the "view session id" dialog. */
+static void add_sessid_expander(GtkWidget *vbox, void *data)
+{
+    add_whatsthis_more(vbox,
+	    "You can use this <b>secure session id</b> to double-check "
+	    "the privacy of <i>this one conversation</i>.",
+
+	    "To verify the session id, contact your buddy via some "
+	    "<i>other</i> authenticated channel, such as the telephone "
+	    "or GPG-signed email.  Each of you should tell your bold "
+	    "half of the above session id to the other "
+	    "(your buddy will have the same session id as you, but with the "
+	    "other half bold).\n\nIf everything matches up, then <i>the "
+	    "current conversation</i> between your computer and your buddy's "
+	    "computer is private.\n\n"
+	    "<b>Note:</b> You will probably never have to do this.  You "
+	    "should normally use the \"Verify fingerprint\" functionality "
+	    "instead.\n\n"
+	    "<a href=\"" SESSIONID_HELPURL "\">"
+	    "Click here for more information about the secure "
+	    "session id.</a>");
+}
+
+static GtkWidget* otrg_gtk_dialog_view_sessionid(ConnContext *context)
 {
-    char fingerprint[45];
+    GtkWidget *dialog;
     unsigned char *sessionid;
     char sess1[21], sess2[21];
     char *primary = g_strdup_printf("Private connection with %s "
 	    "established.", context->username);
     char *secondary;
     int i;
-    SessionDirection dir = context->sesskeys[1][0].dir;
+    SessionDirection dir = context->sessiondir;
 
-    /* Make a human-readable version of the fingerprint */
-    otrl_privkey_hash_to_human(fingerprint,
-	    context->active_fingerprint->fingerprint);
     /* Make a human-readable version of the sessionid (in two parts) */
-    sessionid = context->sesskeys[1][0].sessionid;
+    sessionid = context->sessionid;
     for(i=0;i<10;++i) sprintf(sess1+(2*i), "%02x", sessionid[i]);
     sess1[20] = '\0';
     for(i=0;i<10;++i) sprintf(sess2+(2*i), "%02x", sessionid[i+10]);
     sess2[20] = '\0';
     
-    secondary = g_strdup_printf("Fingerprint for %s:\n%s\n\n"
-	    "Secure id for this session:\n"
-	    "<span %s>%s</span> <span %s>%s</span>", context->username,
-	    fingerprint,
+    secondary = g_strdup_printf("Secure session id:\n"
+	    "<span %s>%s</span> <span %s>%s</span>\n",
 	    dir == SESS_DIR_LOW ? "weight=\"bold\"" : "", sess1,
 	    dir == SESS_DIR_HIGH ? "weight=\"bold\"" : "", sess2);
 
-    otrg_dialog_notify_info(context->accountname, context->protocol,
-	    context->username, "Private connection established",
-	    primary, secondary);
+    dialog = create_dialog(GAIM_NOTIFY_MSG_INFO, "Private connection "
+	    "established", primary, secondary, 1, NULL,
+	    add_sessid_expander, NULL);
+
+    g_free(primary);
+    g_free(secondary);
+
+    return dialog;
+}
+
+struct vrfy_fingerprint_data {
+    Fingerprint *fprint;   /* You can use this pointer right away, but
+			      you can't rely on it sticking around for a
+			      while.  Use the copied pieces below
+			      instead. */
+    char *accountname, *username, *protocol;
+    unsigned char fingerprint[20];
+};
+
+static void vrfy_fingerprint_data_free(struct vrfy_fingerprint_data *vfd)
+{
+    free(vfd->accountname);
+    free(vfd->username);
+    free(vfd->protocol);
+    free(vfd);
+}
+
+static struct vrfy_fingerprint_data* vrfy_fingerprint_data_new(
+	Fingerprint *fprint)
+{
+    struct vrfy_fingerprint_data *vfd;
+    ConnContext *context = fprint->context;
+
+    vfd = malloc(sizeof(*vfd));
+    vfd->fprint = fprint;
+    vfd->accountname = strdup(context->accountname);
+    vfd->username = strdup(context->username);
+    vfd->protocol = strdup(context->protocol);
+    memmove(vfd->fingerprint, fprint->fingerprint, 20);
+
+    return vfd;
+}
+
+static void vrfy_fingerprint_destroyed(GtkWidget *w,
+	struct vrfy_fingerprint_data *vfd)
+{
+    vrfy_fingerprint_data_free(vfd);
+}
+
+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);
+    Fingerprint *fprint;
+    int oldtrust, trust;
+
+    if (context == NULL) return;
+
+    fprint = otrl_context_find_fingerprint(context, vfd->fingerprint,
+	    0, NULL);
+
+    if (fprint == NULL) return;
+
+    oldtrust = (fprint->trust && fprint->trust[0]);
+    trust = gtk_combo_box_get_active(combo) == 1 ? 1 : 0;
+
+    /* See if anything's changed */
+    if (trust != oldtrust) {
+	otrl_context_set_trust(fprint, trust ? "verified" : "");
+	/* Write the new info to disk, redraw the ui, and redraw the
+	 * OTR buttons. */
+	otrg_plugin_write_fingerprints();
+	otrg_ui_update_keylist();
+	otrg_dialog_resensitize_all();
+    }
+}
+
+/* Add the verify widget and the help text for the verify fingerprint box. */
+static void add_vrfy_fingerprint(GtkWidget *vbox, void *data)
+{
+    GtkWidget *hbox;
+    GtkWidget *combo, *label;
+    struct vrfy_fingerprint_data *vfd = data;
+    char *labelt;
+    int verified = 0;
+
+    if (vfd->fprint->trust && vfd->fprint->trust[0]) {
+	verified = 1;
+    }
+
+    hbox = gtk_hbox_new(FALSE, 0);
+    combo = gtk_combo_box_new_text();
+    gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "I have not");
+    gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "I have");
+    gtk_combo_box_set_active(GTK_COMBO_BOX(combo), verified);
+    label = gtk_label_new(" verified that this is in fact the correct");
+    gtk_box_pack_start(GTK_BOX(hbox), combo, FALSE, FALSE, 0);
+    gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+    gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+
+    g_signal_connect(G_OBJECT(combo), "changed",
+	    G_CALLBACK(vrfy_fingerprint_changed), vfd);
+
+    hbox = gtk_hbox_new(FALSE, 0);
+    labelt = g_strdup_printf("fingerprint for %s.",
+	    vfd->username);
+    label = gtk_label_new(labelt);
+    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);
+
+    add_whatsthis_more(vbox,
+	    "A <b>fingerprint</b> is a unique identifier that you should "
+	    "use to authenticate your buddy.",
+
+	    "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.\n\n"
+	    "If everything matches up, you should indicate in the above "
+	    "dialog that you <b>have</b> verified the fingerprint.\n\n"
+	    "If your buddy has more than one IM account, or uses more than "
+	    "one computer, he may have multiple fingerprints.\n\n"
+	    "However, the only way an imposter could duplicate one of your "
+	    "buddy's fingerprints is by stealing information from his "
+	    "computer.\n\n"
+	    "<a href=\"" FINGERPRINT_HELPURL "\">"
+	    "Click here for more information about fingerprints.</a>");
+}
+
+static void otrg_gtk_dialog_verify_fingerprint(Fingerprint *fprint)
+{
+    GtkWidget *dialog;
+    char our_hash[45], their_hash[45];
+    char *primary;
+    char *secondary;
+    struct vrfy_fingerprint_data *vfd;
+    ConnContext *context;
+    GaimPlugin *p;
+    char *proto_name;
+
+    if (fprint == NULL) return;
+    if (fprint->fingerprint == NULL) return;
+    context = fprint->context;
+    if (context == NULL) return;
+
+    primary = g_strdup_printf("Verify fingerprint for %s",
+	    context->username);
+    vfd = vrfy_fingerprint_data_new(fprint);
+
+    otrl_privkey_fingerprint(otrg_plugin_userstate, our_hash,
+	    context->accountname, context->protocol);
+
+    otrl_privkey_hash_to_human(their_hash, fprint->fingerprint);
+
+    p = gaim_find_prpl(context->protocol);
+    proto_name = (p && p->info->name) ? p->info->name : "Unknown";
+    secondary = 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);
+
+    dialog = create_dialog(GAIM_NOTIFY_MSG_INFO, "Verify fingerprint",
+	    primary, secondary, 1, NULL, add_vrfy_fingerprint, vfd);
+    g_signal_connect(G_OBJECT(dialog), "destroy",
+	    G_CALLBACK(vrfy_fingerprint_destroyed), vfd);
 
     g_free(primary);
     g_free(secondary);
-    dialog_update_label(context, 1);
+}
+
+/* Call this when a context transitions from (a state other than
+ * CONN_CONNECTED) to CONN_CONNECTED. */
+static void otrg_gtk_dialog_connected(ConnContext *context)
+{
+    GaimConversation *conv;
+    char *buf;
+    TrustLevel level;
+
+    conv = otrg_plugin_context_to_conv(context, 1);
+    level = otrg_plugin_context_to_trust(context);
+
+    buf = g_strdup_printf("%s conversation with %s started.",
+		level == TRUST_PRIVATE ? "Private" :
+		level == TRUST_UNVERIFIED ? "<a href=\"" UNVERIFIED_HELPURL
+			"\">Unverified</a>" :
+		    /* This last case should never happen, since we know
+		     * we're in CONN_CONNECTED. */
+		    "Not private",
+		gaim_conversation_get_name(conv));
+
+    gaim_conversation_write(conv, NULL, buf, GAIM_MESSAGE_SYSTEM, time(NULL));
+    g_free(buf);
+
+    dialog_update_label(context);
 }
 
 /* Call this when a context transitions from CONN_CONNECTED to
  * (a state other than CONN_CONNECTED). */
 static void otrg_gtk_dialog_disconnected(ConnContext *context)
 {
-    char *primary = g_strdup_printf("Private connection with %s lost.",
-	    context->username);
-    otrg_dialog_notify_warning(context->accountname, context->protocol,
-	    context->username, "Private connection lost", primary, NULL);
-    g_free(primary);
-    dialog_update_label(context, 0);
+    GaimConversation *conv;
+    char *buf;
+
+    conv = otrg_plugin_context_to_conv(context, 1);
+
+    buf = g_strdup_printf("Private conversation with %s lost.",
+	    gaim_conversation_get_name(conv));
+    gaim_conversation_write(conv, NULL, buf, GAIM_MESSAGE_SYSTEM, time(NULL));
+    g_free(buf);
+
+    dialog_update_label(context);
 }
 
 /* Call this when we receive a Key Exchange message that doesn't cause
  * our state to change (because it was just the keys we knew already). */
 static void otrg_gtk_dialog_stillconnected(ConnContext *context)
 {
-    char *secondary = g_strdup_printf("<span size=\"larger\">Successfully "
-	    "refreshed private connection with %s.</span>", context->username);
-    otrg_dialog_notify_info(context->accountname, context->protocol,
-	    context->username, "Refreshed private connection", NULL,
-	    secondary);
-    g_free(secondary);
-    dialog_update_label(context, 1);
+    GaimConversation *conv;
+    char *buf;
+    TrustLevel level;
+
+    conv = otrg_plugin_context_to_conv(context, 1);
+    level = otrg_plugin_context_to_trust(context);
+
+    buf = g_strdup_printf("Successfully refreshed the %s conversation "
+		"with %s.",
+		level == TRUST_PRIVATE ? "private" :
+		level == TRUST_UNVERIFIED ? "<a href=\"" UNVERIFIED_HELPURL
+			"\">unverified</a>" :
+		    /* This last case should never happen, since we know
+		     * we're in CONN_CONNECTED. */
+		    "not private",
+		gaim_conversation_get_name(conv));
+
+    gaim_conversation_write(conv, NULL, buf, GAIM_MESSAGE_SYSTEM, time(NULL));
+    g_free(buf);
+
+    dialog_update_label(context);
 }
 
 /* This is called when the OTR button in the button box is clicked, or
@@ -451,6 +825,39 @@ static void otrg_gtk_dialog_clicked_connect(GtkWidget *widget, gpointer data)
     otrg_plugin_send_default_query_conv(conv);
 }
 
+static void view_sessionid(GtkWidget *widget, gpointer data)
+{
+    GaimConversation *conv = data;
+    ConnContext *context = otrg_plugin_conv_to_context(conv);
+
+    if (context == NULL || context->state != CONN_CONNECTED) return;
+
+    otrg_gtk_dialog_view_sessionid(context);
+}
+
+static void verify_fingerprint(GtkWidget *widget, gpointer data)
+{
+    GaimConversation *conv = data;
+    ConnContext *context = otrg_plugin_conv_to_context(conv);
+
+    if (context == NULL || context->state != CONN_CONNECTED) return;
+
+    otrg_gtk_dialog_verify_fingerprint(context->active_fingerprint);
+}
+
+static void menu_whatsthis(GtkWidget *widget, gpointer data)
+{
+    gaim_notify_uri(otrg_plugin_handle, BUTTON_HELPURL);
+}
+
+static void menu_end_private_conversation(GtkWidget *widget, gpointer data)
+{
+    GaimConversation *conv = data;
+    ConnContext *context = otrg_plugin_conv_to_context(conv);
+
+    otrg_ui_disconnect_connection(context);
+}
+
 static void dialog_resensitize(GaimConversation *conv);
 
 /* If the OTR button is right-clicked, show the context menu. */
@@ -478,31 +885,44 @@ static void button_destroyed(GtkWidget *w, GaimConversation *conv)
     if (menu) gtk_object_destroy(GTK_OBJECT(menu));
     g_hash_table_remove(conv->data, "otr-label");
     g_hash_table_remove(conv->data, "otr-button");
+    g_hash_table_remove(conv->data, "otr-icon");
+    g_hash_table_remove(conv->data, "otr-icontext");
     g_hash_table_remove(conv->data, "otr-private");
     g_hash_table_remove(conv->data, "otr-menu");
-    g_hash_table_remove(conv->data, "otr-menuitem");
+    g_hash_table_remove(conv->data, "otr-menuquery");
+    g_hash_table_remove(conv->data, "otr-menuend");
+    g_hash_table_remove(conv->data, "otr-menuview");
+    g_hash_table_remove(conv->data, "otr-menuverf");
 }
 
 /* Set up the per-conversation information display */
 static void otrg_gtk_dialog_new_conv(GaimConversation *conv)
 {
     GaimGtkConversation *gtkconv = GAIM_GTK_CONVERSATION(conv);
-    GaimAccount *account;
-    char *username;
-    const char *accountname, *proto;
     ConnContext *context;
-    ConnectionState state;
     GtkWidget *bbox;
     GtkWidget *button;
     GtkWidget *label;
+    GtkWidget *bwbox;
+    GtkWidget *bvbox;
+    GtkWidget *iconbox;
+    GtkWidget *icon;
+    GtkWidget *icontext;
     GtkWidget *menu;
-    GtkWidget *menuitem;
+    GtkWidget *menuquery;
+    GtkWidget *menuend;
+    GtkWidget *menusep;
+    GtkWidget *menuview;
+    GtkWidget *menuverf;
+    GtkWidget *whatsthis;
 
     /* Do nothing if this isn't an IM conversation */
     if (gaim_conversation_get_type(conv) != GAIM_CONV_IM) return;
 
     bbox = gtkconv->bbox;
 
+    context = otrg_plugin_conv_to_context(conv);
+
     /* See if we're already set up */
     button = gaim_conversation_get_data(conv, "otr-button");
     if (button) {
@@ -514,40 +934,81 @@ static void otrg_gtk_dialog_new_conv(GaimConversation *conv)
 	    gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
 	}
 	g_list_free(children);
+	dialog_update_label_conv(conv, otrg_plugin_context_to_trust(context));
 	return;
     }
 
-    account = gaim_conversation_get_account(conv);
-    accountname = gaim_account_get_username(account);
-    proto = gaim_account_get_protocol_id(account);
-    username = g_strdup(
-	    gaim_normalize(account, gaim_conversation_get_name(conv)));
-
-    context = otrl_context_find(otrg_plugin_userstate, username, accountname,
-	    proto, 0, NULL, NULL, NULL);
-    state = context ? context->state : CONN_UNCONNECTED;
-    g_free(username);
-
+    /* Make the button */
     button = gtk_button_new();
-    label = gtk_label_new(NULL);
     gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
-    gtk_container_add(GTK_CONTAINER(button), label);
     gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
 
+    bwbox = gtk_vbox_new(FALSE, 0);
+    gtk_container_add(GTK_CONTAINER(button), bwbox);
+    bvbox = gtk_vbox_new(FALSE, 0);
+    gtk_box_pack_start(GTK_BOX(bwbox), bvbox, TRUE, FALSE, 0);
+    iconbox = gtk_hbox_new(FALSE, 3);
+    gtk_box_pack_start(GTK_BOX(bvbox), iconbox, FALSE, FALSE, 0);
+    label = gtk_label_new(NULL);
+    gtk_box_pack_start(GTK_BOX(bvbox), label, FALSE, FALSE, 0);
+    icontext = gtk_label_new("OTR:");
+    gtk_box_pack_start(GTK_BOX(iconbox), icontext, FALSE, FALSE, 0);
+    icon = otr_icon(NULL, TRUST_NOT_PRIVATE);
+    gtk_box_pack_start(GTK_BOX(iconbox), icon, TRUE, FALSE, 0);
+
+    gtk_widget_show_all(button);
+
     /* Make the context menu */
     menu = gtk_menu_new();
     gtk_menu_set_title(GTK_MENU(menu), "OTR Messaging");
 
-    menuitem = gtk_menu_item_new_with_mnemonic("");
-    gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
-    gtk_widget_show(menuitem);
+    menuquery = gtk_menu_item_new_with_mnemonic("");
+    gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuquery);
+    gtk_widget_show(menuquery);
+
+    menuend = gtk_menu_item_new_with_mnemonic("_End private conversation");
+    gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuend);
+    gtk_widget_show(menuend);
+
+    menusep = gtk_separator_menu_item_new();
+    gtk_menu_shell_append(GTK_MENU_SHELL(menu), menusep);
+    gtk_widget_show(menusep);
+
+    menuverf = gtk_menu_item_new_with_mnemonic("_Verify fingerprint");
+    gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuverf);
+    gtk_widget_show(menuverf);
+
+    menuview = gtk_menu_item_new_with_mnemonic("View _secure session id");
+    gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuview);
+    gtk_widget_show(menuview);
+
+    menusep = gtk_separator_menu_item_new();
+    gtk_menu_shell_append(GTK_MENU_SHELL(menu), menusep);
+    gtk_widget_show(menusep);
+
+    whatsthis = gtk_menu_item_new_with_mnemonic("_What's this?");
+    gtk_menu_shell_append(GTK_MENU_SHELL(menu), whatsthis);
+    gtk_widget_show(whatsthis);
 
     gaim_conversation_set_data(conv, "otr-label", label);
     gaim_conversation_set_data(conv, "otr-button", button);
+    gaim_conversation_set_data(conv, "otr-icon", icon);
+    gaim_conversation_set_data(conv, "otr-icontext", icontext);
     gaim_conversation_set_data(conv, "otr-menu", menu);
-    gaim_conversation_set_data(conv, "otr-menuitem", menuitem);
-    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
+    gaim_conversation_set_data(conv, "otr-menuquery", menuquery);
+    gaim_conversation_set_data(conv, "otr-menuend", menuend);
+    gaim_conversation_set_data(conv, "otr-menuview", menuview);
+    gaim_conversation_set_data(conv, "otr-menuverf", menuverf);
+    gtk_signal_connect(GTK_OBJECT(menuquery), "activate",
 	    GTK_SIGNAL_FUNC(otrg_gtk_dialog_clicked_connect), conv);
+    gtk_signal_connect(GTK_OBJECT(menuend), "activate",
+	    GTK_SIGNAL_FUNC(menu_end_private_conversation), conv);
+    gtk_signal_connect(GTK_OBJECT(menuverf), "activate",
+	    GTK_SIGNAL_FUNC(verify_fingerprint), conv);
+    gtk_signal_connect(GTK_OBJECT(menuview), "activate",
+	    GTK_SIGNAL_FUNC(view_sessionid), conv);
+    gtk_signal_connect(GTK_OBJECT(whatsthis), "activate",
+	    GTK_SIGNAL_FUNC(menu_whatsthis), conv);
     gtk_signal_connect(GTK_OBJECT(button), "clicked",
 	    GTK_SIGNAL_FUNC(otrg_gtk_dialog_clicked_connect), conv);
     g_signal_connect(G_OBJECT(button), "destroy",
@@ -555,9 +1016,8 @@ static void otrg_gtk_dialog_new_conv(GaimConversation *conv)
     g_signal_connect(G_OBJECT(button), "button-press-event",
 	    G_CALLBACK(button_pressed), conv);
 
-    dialog_update_label_conv(conv, state == CONN_CONNECTED);
+    dialog_update_label_conv(conv, otrg_plugin_context_to_trust(context));
     dialog_resensitize(conv);
-    gtk_widget_show_all(button);
 }
 
 /* Remove the per-conversation information display */
@@ -620,6 +1080,7 @@ static const OtrgDialogUiOps gtk_dialog_ui_ops = {
     otrg_gtk_dialog_private_key_wait_start,
     otrg_gtk_dialog_private_key_wait_done,
     otrg_gtk_dialog_unknown_fingerprint,
+    otrg_gtk_dialog_verify_fingerprint,
     otrg_gtk_dialog_connected,
     otrg_gtk_dialog_disconnected,
     otrg_gtk_dialog_stillconnected,
diff --git a/gtk-ui.c b/gtk-ui.c
index 0e01700..ea16d82 100644
--- a/gtk-ui.c
+++ b/gtk-ui.c
@@ -54,6 +54,7 @@ static struct {
     GtkWidget *connect_button;
     GtkWidget *disconnect_button;
     GtkWidget *forget_button;
+    GtkWidget *verify_button;
     struct otroptionsdata oo;
 } ui_layout;
 
@@ -97,6 +98,8 @@ static GtkWidget *accountmenu_get_selected_item(void)
 {
     GtkWidget *menu;
 
+    if (ui_layout.accountmenu == NULL) return NULL;
+
     menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(ui_layout.accountmenu));
     return gtk_menu_get_active(GTK_MENU(menu));
 }
@@ -117,6 +120,8 @@ static void otrg_gtk_ui_update_fingerprint(void)
 
     item = accountmenu_get_selected_item();
 
+    if (!item) return;
+
     account   = item_get_account(item);
     user_data = g_object_get_data(G_OBJECT(ui_layout.accountmenu),
 	    "user_data");
@@ -134,13 +139,14 @@ static void clist_all_unselected(void)
     gtk_widget_set_sensitive(ui_layout.connect_button, 0);
     gtk_widget_set_sensitive(ui_layout.disconnect_button, 0);
     gtk_widget_set_sensitive(ui_layout.forget_button, 0);
+    gtk_widget_set_sensitive(ui_layout.verify_button, 0);
     ui_layout.selected_fprint = NULL;
 }
 
 /* Update the keylist, if it's visible */
 static void otrg_gtk_ui_update_keylist(void)
 {
-    gchar *titles[4];
+    gchar *titles[5];
     char hash[45];
     ConnContext * context;
     Fingerprint * fingerprint;
@@ -171,14 +177,16 @@ static void otrg_gtk_ui_update_keylist(void)
 		titles[1] =
 		    (gchar *) otrl_context_statestr[context->state];
 	    }
+	    titles[2] = (fingerprint->trust && fingerprint->trust[0]) ?
+		"Yes" : "No";
 	    otrl_privkey_hash_to_human(hash, fingerprint->fingerprint);
-	    titles[2] = hash;
+	    titles[3] = hash;
 	    p = gaim_find_prpl(context->protocol);
 	    proto_name = (p && p->info->name) ? p->info->name : "Unknown";
-	    titles[3] = g_strdup_printf("%s (%s)", context->accountname,
+	    titles[4] = g_strdup_printf("%s (%s)", context->accountname,
 		proto_name);
 	    i = gtk_clist_append(GTK_CLIST(keylist), titles);
-	    g_free(titles[3]);
+	    g_free(titles[4]);
 	    gtk_clist_set_row_data(GTK_CLIST(keylist), i, fingerprint);
 	    if (ui_layout.selected_fprint == fingerprint) {
 		selected_row = i;
@@ -223,6 +231,7 @@ static void ui_destroyed(GtkObject *object)
     ui_layout.connect_button = NULL;
     ui_layout.disconnect_button = NULL;
     ui_layout.forget_button = NULL;
+    ui_layout.verify_button = NULL;
     ui_layout.oo.enablebox = NULL;
     ui_layout.oo.automaticbox = NULL;
     ui_layout.oo.onlyprivatebox = NULL;
@@ -234,6 +243,7 @@ static void clist_selected(GtkWidget *widget, gint row, gint column,
     int connect_sensitive = 0;
     int disconnect_sensitive = 0;
     int forget_sensitive = 0;
+    int verify_sensitive = 0;
     Fingerprint *f = gtk_clist_get_row_data(GTK_CLIST(ui_layout.keylist),
 	    row);
     if (f && f->context->state == CONN_CONNECTED &&
@@ -253,11 +263,15 @@ static void clist_selected(GtkWidget *widget, gint row, gint column,
     if (f && f->context->state == CONN_UNCONNECTED) {
 	connect_sensitive = 1;
     }
+    if (f) {
+	verify_sensitive = 1;
+    }
     gtk_widget_set_sensitive(ui_layout.connect_button,
 	    connect_sensitive);
     gtk_widget_set_sensitive(ui_layout.disconnect_button,
 	    disconnect_sensitive);
     gtk_widget_set_sensitive(ui_layout.forget_button, forget_sensitive);
+    gtk_widget_set_sensitive(ui_layout.verify_button, verify_sensitive);
     ui_layout.selected_fprint = f;
 }
 
@@ -350,6 +364,13 @@ static void forget_fingerprint(GtkWidget *widget, gpointer data)
     otrg_ui_forget_fingerprint(fingerprint);
 }
 
+static void verify_fingerprint(GtkWidget *widget, gpointer data)
+{
+    Fingerprint *fingerprint = ui_layout.selected_fprint;
+
+    otrg_dialog_verify_fingerprint(fingerprint);
+}
+
 static void otroptions_clicked_cb(GtkButton *button, struct otroptionsdata *oo)
 {
     gtk_widget_set_sensitive(oo->enablebox, TRUE);
@@ -576,18 +597,21 @@ static void make_options_ui(GtkWidget *vbox)
 static void make_fingerprints_ui(GtkWidget *vbox)
 {
     GtkWidget *hbox;
+    GtkWidget *table;
     GtkWidget *label;
-    char *titles[4] = { "Screenname", "Status", "Fingerprint", "Account" };
+    char *titles[5] = { "Screenname", "Status", "Verified",
+	"Fingerprint", "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);
 
-    ui_layout.keylist = gtk_clist_new_with_titles(4, titles);
+    ui_layout.keylist = gtk_clist_new_with_titles(5, titles);
     gtk_clist_set_column_width(GTK_CLIST(ui_layout.keylist), 0, 90);
     gtk_clist_set_column_width(GTK_CLIST(ui_layout.keylist), 1, 90);
-    gtk_clist_set_column_width(GTK_CLIST(ui_layout.keylist), 2, 400);
-    gtk_clist_set_column_width(GTK_CLIST(ui_layout.keylist), 3, 200);
+    gtk_clist_set_column_width(GTK_CLIST(ui_layout.keylist), 2, 60);
+    gtk_clist_set_column_width(GTK_CLIST(ui_layout.keylist), 3, 400);
+    gtk_clist_set_column_width(GTK_CLIST(ui_layout.keylist), 4, 200);
     gtk_clist_set_selection_mode(GTK_CLIST(ui_layout.keylist),
 	    GTK_SELECTION_SINGLE);
     gtk_clist_column_titles_active(GTK_CLIST(ui_layout.keylist));
@@ -601,6 +625,12 @@ static void make_fingerprints_ui(GtkWidget *vbox)
     hbox = gtk_hbox_new(FALSE, 5);
     gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
 
+    table = gtk_table_new(2, 2, TRUE);
+    gtk_table_set_row_spacings(GTK_TABLE(table), 5);
+    gtk_table_set_col_spacings(GTK_TABLE(table), 20);
+
+    gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(""), TRUE, TRUE, 0);
+    gtk_box_pack_start(GTK_BOX(hbox), table, FALSE, FALSE, 0);
     gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(""), TRUE, TRUE, 0);
 
     ui_layout.connect_button = gtk_button_new();
@@ -608,30 +638,32 @@ static void make_fingerprints_ui(GtkWidget *vbox)
 	    GTK_SIGNAL_FUNC(connect_connection), NULL);
     label = gtk_label_new("Start private connection");
     gtk_container_add(GTK_CONTAINER(ui_layout.connect_button), label);
-    gtk_box_pack_start(GTK_BOX(hbox), ui_layout.connect_button,
-	    FALSE, FALSE, 0);
-
-    gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(""), TRUE, TRUE, 0);
+    gtk_table_attach_defaults(GTK_TABLE(table), ui_layout.connect_button,
+	    0, 1, 0, 1);
 
     ui_layout.disconnect_button = gtk_button_new();
     gtk_signal_connect(GTK_OBJECT(ui_layout.disconnect_button), "clicked",
 	    GTK_SIGNAL_FUNC(disconnect_connection), NULL);
     label = gtk_label_new("End private connection");
     gtk_container_add(GTK_CONTAINER(ui_layout.disconnect_button), label);
-    gtk_box_pack_start(GTK_BOX(hbox), ui_layout.disconnect_button,
-	    FALSE, FALSE, 0);
+    gtk_table_attach_defaults(GTK_TABLE(table), ui_layout.disconnect_button,
+	    0, 1, 1, 2);
 
-    gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(""), TRUE, TRUE, 0);
+    ui_layout.verify_button = gtk_button_new();
+    gtk_signal_connect(GTK_OBJECT(ui_layout.verify_button), "clicked",
+	    GTK_SIGNAL_FUNC(verify_fingerprint), NULL);
+    label = gtk_label_new("Verify fingerprint");
+    gtk_container_add(GTK_CONTAINER(ui_layout.verify_button), label);
+    gtk_table_attach_defaults(GTK_TABLE(table), ui_layout.verify_button,
+	    1, 2, 0, 1);
 
     ui_layout.forget_button = gtk_button_new();
     gtk_signal_connect(GTK_OBJECT(ui_layout.forget_button), "clicked",
 	    GTK_SIGNAL_FUNC(forget_fingerprint), NULL);
     label = gtk_label_new("Forget fingerprint");
     gtk_container_add(GTK_CONTAINER(ui_layout.forget_button), label);
-    gtk_box_pack_start(GTK_BOX(hbox), ui_layout.forget_button,
-	    FALSE, FALSE, 0);
-
-    gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(""), TRUE, TRUE, 0);
+    gtk_table_attach_defaults(GTK_TABLE(table), ui_layout.forget_button,
+	    1, 2, 1, 2);
 
     gtk_signal_connect(GTK_OBJECT(vbox), "destroy",
 	    GTK_SIGNAL_FUNC(ui_destroyed), NULL);
@@ -648,10 +680,7 @@ static void make_fingerprints_ui(GtkWidget *vbox)
     ui_layout.sortcol = 0;
     ui_layout.sortdir = 1;
 
-    gtk_widget_set_sensitive(ui_layout.connect_button, 0);
-    gtk_widget_set_sensitive(ui_layout.disconnect_button, 0);
-    gtk_widget_set_sensitive(ui_layout.forget_button, 0);
-    ui_layout.selected_fprint = NULL;
+    clist_all_unselected();
 }
 
 /* Construct the OTR UI widget */
diff --git a/otr-plugin.c b/otr-plugin.c
index 489c778..b16697c 100644
--- a/otr-plugin.c
+++ b/otr-plugin.c
@@ -208,19 +208,16 @@ static void update_context_list_cb(void *opdata)
     otrg_ui_update_keylist();
 }
 
-/* Forward declaration because we need to use &ui_ops in this function */
 static void confirm_fingerprint_cb(OtrlUserState us, void *opdata,
 	const char *accountname, const char *protocol, const char *username,
-	OTRKeyExchangeMsg kem,
-	void (*response_cb)(OtrlUserState us, OtrlMessageAppOps *ops,
-	    void *opdata, OTRConfirmResponse *response_data, int resp),
-	OTRConfirmResponse *response_data);
+	OTRKeyExchangeMsg kem)
+{
+    otrg_dialog_unknown_fingerprint(us, accountname, protocol, username, kem);
+}
 
 static void write_fingerprints_cb(void *opdata)
 {
-    gchar *storefile = g_build_filename(gaim_user_dir(), STOREFNAME, NULL);
-    otrl_privkey_write_fingerprints(otrg_plugin_userstate, storefile);
-    g_free(storefile);
+    otrg_plugin_write_fingerprints();
 }
 
 static void gone_secure_cb(void *opdata, ConnContext *context)
@@ -263,17 +260,6 @@ static OtrlMessageAppOps ui_ops = {
     log_message_cb
 };
 
-static void confirm_fingerprint_cb(OtrlUserState us, void *opdata,
-	const char *accountname, const char *protocol, const char *username,
-	OTRKeyExchangeMsg kem,
-	void (*response_cb)(OtrlUserState us, OtrlMessageAppOps *ops,
-	    void *opdata, OTRConfirmResponse *response_data, int resp),
-	OTRConfirmResponse *response_data)
-{
-    otrg_dialog_unknown_fingerprint(us, accountname, protocol, username, kem,
-	    response_cb, &ui_ops, opdata, response_data);
-}
-
 static void process_sending_im(GaimAccount *account, char *who, char **message,
 	void *m)
 {
@@ -458,6 +444,71 @@ void otrg_plugin_disconnect(ConnContext *context)
 	    context->accountname, context->protocol, context->username);
 }
 
+/* Write the fingerprints to disk. */
+void otrg_plugin_write_fingerprints(void)
+{
+    gchar *storefile = g_build_filename(gaim_user_dir(), STOREFNAME, NULL);
+    otrl_privkey_write_fingerprints(otrg_plugin_userstate, storefile);
+    g_free(storefile);
+}
+
+/* Find the ConnContext appropriate to a given GaimConversation. */
+ConnContext *otrg_plugin_conv_to_context(GaimConversation *conv)
+{
+    GaimAccount *account;
+    char *username;
+    const char *accountname, *proto;
+    ConnContext *context;
+
+    account = gaim_conversation_get_account(conv);
+    accountname = gaim_account_get_username(account);
+    proto = gaim_account_get_protocol_id(account);
+    username = g_strdup(
+	    gaim_normalize(account, gaim_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 GaimConversation appropriate to the given ConnContext.  If
+ * one doesn't yet exist, create it if force_create is true. */
+GaimConversation *otrg_plugin_context_to_conv(ConnContext *context,
+	int force_create)
+{
+    GaimAccount *account;
+    GaimConversation *conv;
+
+    account = gaim_accounts_find(context->accountname, context->protocol);
+    if (account == NULL) return NULL;
+
+    conv = gaim_find_conversation_with_account(context->username, account);
+    if (conv == NULL && force_create) {
+	conv = gaim_conversation_new(GAIM_CONV_IM, account, context->username);
+    }
+
+    return conv;
+}
+
+/* What level of trust do we have in the privacy of this ConnContext? */
+TrustLevel otrg_plugin_context_to_trust(ConnContext *context)
+{
+    TrustLevel level = TRUST_NOT_PRIVATE;
+
+    if (context && context->state == CONN_CONNECTED) {
+	if (context->active_fingerprint->trust &&
+		context->active_fingerprint->trust[0] != '\0') {
+	    level = TRUST_PRIVATE;
+	} else {
+	    level = TRUST_UNVERIFIED;
+	}
+    }
+
+    return level;
+}
+
 static guint button_type_cbid;
 
 static gboolean otr_plugin_load(GaimPlugin *handle)
diff --git a/otr-plugin.h b/otr-plugin.h
index 67c2f3a..6ead10a 100644
--- a/otr-plugin.h
+++ b/otr-plugin.h
@@ -58,6 +58,26 @@ void otrg_plugin_send_default_query_conv(GaimConversation *conv);
  * appropriate. */
 void otrg_plugin_disconnect(ConnContext *context);
 
+/* Write the fingerprints to disk. */
+void otrg_plugin_write_fingerprints(void);
+
+/* Find the ConnContext appropriate to a given GaimConversation. */
+ConnContext *otrg_plugin_conv_to_context(GaimConversation *conv);
+
+/* Find the GaimConversation appropriate to the given ConnContext.  If
+ * one doesn't yet exist, create it if force_create is true. */
+GaimConversation *otrg_plugin_context_to_conv(ConnContext *context,
+	int force_create);
+
+typedef enum {
+    TRUST_NOT_PRIVATE,
+    TRUST_UNVERIFIED,
+    TRUST_PRIVATE
+} TrustLevel;
+
+/* What level of trust do we have in the privacy of this ConnContext? */
+TrustLevel otrg_plugin_context_to_trust(ConnContext *context);
+
 /* Return 1 if the given protocol supports OTR, 0 otherwise. */
 int otrg_plugin_proto_supports_otr(const char *proto);
 
diff --git a/packaging/fedora/gaim-otr.spec b/packaging/fedora/gaim-otr.spec
index d5d9da7..b611337 100644
--- a/packaging/fedora/gaim-otr.spec
+++ b/packaging/fedora/gaim-otr.spec
@@ -1,7 +1,7 @@
 Summary: Off-The-Record Messaging plugin for GAIM
 Name: gaim-otr
-Version: 2.0.2
-Release: 2%{?dist}
+Version: 3.0.0
+Release: 1%{?dist}
 Source: http://www.cypherpunks.ca/otr/%{name}-%{version}.tar.gz
 Url: http://www.cypherpunks.ca/otr/
 License: GPL
diff --git a/packaging/windows/gaim-otr.nsi b/packaging/windows/gaim-otr.nsi
index fda604d..9ad658e 100644
--- a/packaging/windows/gaim-otr.nsi
+++ b/packaging/windows/gaim-otr.nsi
@@ -3,6 +3,7 @@
 ;
 ; known issue. installer induced uninstaller abortion causes overwrite by installer without
 ; uninstall.
+; v3.0.0   - Bump version number.
 ; v2.0.2   - Bump version number.
 ; v2.0.1   - Bump version number.
 ; v2.0.0-2 - linking to libotr-2.0.1
@@ -21,7 +22,7 @@
 ; todo: SetBrandingImage
 ; HM NIS Edit Wizard helper defines
 !define PRODUCT_NAME "gaim-otr"
-!define PRODUCT_VERSION "2.0.2"
+!define PRODUCT_VERSION "3.0.0"
 !define PRODUCT_PUBLISHER "Cypherpunks CA"
 !define PRODUCT_WEB_SITE "http://www.cypherpunks.ca/otr/"
 !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
diff --git a/ui.c b/ui.c
index 446ae90..34e898c 100644
--- a/ui.c
+++ b/ui.c
@@ -103,7 +103,6 @@ void otrg_ui_disconnect_connection(ConnContext *context)
 void otrg_ui_forget_fingerprint(Fingerprint *fingerprint)
 {
     ConnContext *context;
-    gchar *storefile;
 	
     if (fingerprint == NULL) return;
 
@@ -114,9 +113,7 @@ void otrg_ui_forget_fingerprint(Fingerprint *fingerprint)
 	    context->active_fingerprint == fingerprint) return;
 	
     otrl_context_forget_fingerprint(fingerprint, 1);
-    storefile = g_build_filename(gaim_user_dir(), STOREFNAME, NULL);
-    otrl_privkey_write_fingerprints(otrg_plugin_userstate, storefile);
-    g_free(storefile);
+    otrg_plugin_write_fingerprints();
 	
     otrg_ui_update_keylist();
 }

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-otr/packages/irssi-plugin-otr.git



More information about the Pkg-otr-team mailing list