Re: [gtk-vnc-devel] PATCH 2/2: API for gathering credentials



This is the patch whichs adds the APIs for gathering credentials

  - Adds the vnc_display_set_credential method for providing data
 
  - Adds the vnc-auth-credential signal for requesting credential
    data from the app

  - Adds a generic GSource for efficiently waiting in the main loop for
    a boolean  condition to be satisified

  - Extends the C & python example programs to demonstrate ahead of time
    and synchronous authentication processes.

Dan.
-- 
|=- Red Hat, Engineering, Emerging Technologies, Boston.  +1 978 392 2496 -=|
|=-           Perl modules: http://search.cpan.org/~danberr/              -=|
|=-               Projects: http://freshmeat.net/~danielpb/               -=|
|=-  GnuPG: 7D3B9505   F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505  -=| 
changeset:   23:7f9c4f423f86
tag:         tip
user:        "Daniel P. Berrange <berrange redhat com>"
date:        Thu Jul 05 13:48:15 2007 -0400
summary:     Added API for getting authentication credentials from application

diff -r b77ea47300ab -r 7f9c4f423f86 examples/gvncviewer.c
--- a/examples/gvncviewer.c	Wed Jul 04 15:32:55 2007 -0400
+++ b/examples/gvncviewer.c	Thu Jul 05 13:48:15 2007 -0400
@@ -7,16 +7,83 @@
 #include <netinet/tcp.h>
 #include <arpa/inet.h>
 
+GtkWidget *window;
+
+void vnc_disconnect(GtkWidget *vnc)
+{
+	printf("VNC widget disconnected\n");
+	gtk_main_quit();
+}
+
+void vnc_initialized(GtkWidget *vnc)
+{
+	printf("VNC widget initialized\n");
+	gtk_widget_show_all(GTK_WIDGET(window));
+}
+
+void vnc_credential(GtkWidget *vnc, int cred)
+{
+	GtkWidget *dialog, *label, *entry, *box, *vbox;
+	const char *data, *title;
+	int response;
+
+	printf("Got credential request for %d\n", cred);
+	if (cred != VNC_DISPLAY_CREDENTIAL_PASSWORD &&
+	    cred != VNC_DISPLAY_CREDENTIAL_USERNAME) {
+		printf("Unsupported credential type\n");
+		vnc_display_close(VNC_DISPLAY(vnc));
+		return;
+	}
+
+	dialog = gtk_dialog_new_with_buttons("Authentication required",
+					     NULL,
+					     0,
+					     GTK_STOCK_CANCEL,
+					     GTK_RESPONSE_CANCEL,
+					     GTK_STOCK_OK,
+					     GTK_RESPONSE_OK,
+					     NULL);
+
+	box = gtk_hbox_new(6, TRUE);
+
+	if (cred == VNC_DISPLAY_CREDENTIAL_PASSWORD)
+		label = gtk_label_new("Password:");
+	else
+		label = gtk_label_new("Username:");
+
+	entry = gtk_entry_new();
+
+	vbox = gtk_bin_get_child(GTK_BIN(dialog));
+
+	gtk_container_add(GTK_CONTAINER(vbox), box);
+	gtk_container_add(GTK_CONTAINER(box), label);
+	gtk_container_add(GTK_CONTAINER(box), entry);
+
+	gtk_widget_show_all(dialog);
+	response = gtk_dialog_run(GTK_DIALOG(dialog));
+	gtk_widget_hide(GTK_WIDGET(dialog));
+
+	data = gtk_entry_get_text(GTK_ENTRY(entry));
+
+	if (response == GTK_RESPONSE_OK && data) {
+		printf("Setting credentials\n");
+		vnc_display_set_credential(VNC_DISPLAY(vnc), cred, data);
+	} else {
+		printf("Aborting connection\n");
+		vnc_display_close(VNC_DISPLAY(vnc));
+	}
+
+	gtk_widget_destroy(GTK_WIDGET(dialog));
+}
 
 int main(int argc, char **argv)
 {
-	GtkWidget *window;
 	GtkWidget *vnc;
 	char *ret = NULL;
 
 	if (argc != 3 && argc != 4) {
-	  fprintf(stderr, "syntax: vnc-test ipaddress port [password]\n");
-	  return 1;
+		fprintf(stderr, "syntax: vnc-test ipaddress port [password]\n");
+		return 1;
 	}
 
 	gtk_init(&argc, &argv);
@@ -25,19 +92,35 @@ int main(int argc, char **argv)
 	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 
 	gtk_container_add(GTK_CONTAINER(window), vnc);
-	gtk_widget_show_all(window);
+	gtk_widget_realize(GTK_WIDGET(vnc));
 
 	if (argc == 4)
-	  vnc_display_set_password(VNC_DISPLAY(vnc), argv[3]);
+		vnc_display_set_credential(VNC_DISPLAY(vnc), VNC_DISPLAY_CREDENTIAL_PASSWORD, argv[3]);
+
 	vnc_display_open_name(VNC_DISPLAY(vnc), argv[1], argv[2]);
 
 	gtk_signal_connect(GTK_OBJECT(window), "delete-event",
 			   GTK_SIGNAL_FUNC(gtk_main_quit), NULL);
 
+	gtk_signal_connect(GTK_OBJECT(vnc), "vnc-initialized",
+			   GTK_SIGNAL_FUNC(vnc_initialized), NULL);
+
 	gtk_signal_connect(GTK_OBJECT(vnc), "vnc-disconnected",
-			   GTK_SIGNAL_FUNC(gtk_main_quit), NULL);
+			   GTK_SIGNAL_FUNC(vnc_disconnect), NULL);
+
+	gtk_signal_connect(GTK_OBJECT(vnc), "vnc-auth-credential",
+			   GTK_SIGNAL_FUNC(vnc_credential), NULL);
 
 	gtk_main();
 
 	return 0;
 }
+
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff -r b77ea47300ab -r 7f9c4f423f86 examples/gvncviewer.py
--- a/examples/gvncviewer.py	Wed Jul 04 15:32:55 2007 -0400
+++ b/examples/gvncviewer.py	Thu Jul 05 13:48:15 2007 -0400
@@ -2,17 +2,63 @@
 
 import gtk
 import gtkvnc
+import sys
 
+if len(sys.argv) != 3 and len(sys.argv) != 4:
+    print "syntax: gvncviewer.py host port [password]"
+    sys.exit(1)
 
 w = gtk.Window()
 
+def vnc_disconnect(src):
+    print "VNC disconnected"
+    gtk.main_quit()
+
+def vnc_initialize(src):
+    print "VNC initialized"
+    w.show_all()
+
+def vnc_credential(src, type):
+    print "VNC auth credential %d" % type
+
+    if type != gtkvnc.CREDENTIAL_PASSWORD and type != gtkvnc.CREDENTIAL_USERNAME:
+        src.close()
+        return
+
+    dialog = gtk.Dialog("Authentication required", None, 0, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK))
+    vbox = dialog.get_child()
+    box = gtk.HBox()
+    if type == gtkvnc.CREDENTIAL_PASSWORD:
+        label = gtk.Label("Password:")
+    else:
+        label = gtk.Label("Username:")
+    entry = gtk.Entry()
+
+    box.add(label)
+    box.add(entry)
+    vbox.add(box)
+
+    dialog.show_all()
+    res = dialog.run()
+    dialog.hide()
+    data = entry.get_text()
+    if res == gtk.RESPONSE_CANCEL or data is None or data == "":
+        src.close()
+    else:
+        src.set_credential(type, data)
+    dialog.destroy()
+
 v = gtkvnc.Display()
+w.add(v)
+v.realize()
 
-w.add(v)
-w.show_all()
+if len(sys.argv) == 4:
+    v.set_credential(gtkvnc.CREDENTIAL_PASSWORD, sys.argv[3])
 
-v.set_password("123456")
-v.open_name("localhost", "5901")
-v.connect("vnc-disconnected", gtk.main_quit)
+v.open_name(sys.argv[1], sys.argv[2])
+v.connect("vnc-disconnected", vnc_disconnect)
+v.connect("vnc-initialized", vnc_initialize)
+v.connect("vnc-auth-credential", vnc_credential)
+w.connect("delete-event", gtk.main_quit)
 
 gtk.main()
diff -r b77ea47300ab -r 7f9c4f423f86 src/gvnc.c
--- a/src/gvnc.c	Wed Jul 04 15:32:55 2007 -0400
+++ b/src/gvnc.c	Thu Jul 05 13:48:15 2007 -0400
@@ -38,24 +38,6 @@
 #define KEY_FILE "key.pem"
 #define CERT_FILE "cert.pem"
 
-static gboolean g_io_wait_helper(GIOChannel *channel G_GNUC_UNUSED,
-				 GIOCondition cond,
-				 gpointer data)
-{
-	struct coroutine *to = data;
-	yieldto(to, &cond);
-	return FALSE;
-}
-
-static GIOCondition g_io_wait(GIOChannel *channel, GIOCondition cond)
-{
-	GIOCondition *ret;
-
-	g_io_add_watch(channel, cond, g_io_wait_helper, coroutine_self());
-	ret = yield(NULL);
-
-	return *ret;
-}
 
 typedef void gvnc_blt_func(struct gvnc *, uint8_t *, int, int, int, int, int);
 
@@ -80,6 +62,12 @@ struct gvnc
 	int minor;
 	gnutls_session_t tls_session;
 
+	/* Auth related params */
+	unsigned int auth_type;
+	unsigned int auth_subtype;
+	char *cred_username;
+	char *cred_password;
+
 	char read_buffer[4096];
 	size_t read_offset;
 	size_t read_size;
@@ -98,33 +86,118 @@ struct gvnc
 
 	int shared_memory_enabled;
 
-	struct gvnc_ops ops;
+	const struct gvnc_ops *ops;
 	gpointer ops_data;
 
 	int absolute;
 };
 
-enum {
-  GVNC_AUTH_INVALID = 0,
-  GVNC_AUTH_NONE = 1,
-  GVNC_AUTH_VNC = 2,
-  GVNC_AUTH_RA2 = 5,
-  GVNC_AUTH_RA2NE = 6,
-  GVNC_AUTH_TIGHT = 16,
-  GVNC_AUTH_ULTRA = 17,
-  GVNC_AUTH_TLS = 18,
-  GVNC_AUTH_VENCRYPT = 19
+
+/* Main loop helper functions */
+static gboolean g_io_wait_helper(GIOChannel *channel G_GNUC_UNUSED,
+				 GIOCondition cond,
+				 gpointer data)
+{
+	struct coroutine *to = data;
+	yieldto(to, &cond);
+	return FALSE;
+}
+
+static GIOCondition g_io_wait(GIOChannel *channel, GIOCondition cond)
+{
+	GIOCondition *ret;
+
+	g_io_add_watch(channel, cond, g_io_wait_helper, coroutine_self());
+	ret = yield(NULL);
+
+	return *ret;
+}
+
+
+/*
+ * A special GSource impl which allows us to wait on a certain
+ * condition to be satisified. This is effectively a boolean test
+ * run on each iteration of the main loop. So whenever a file has
+ * new I/O, or a timer occurrs, etc we'll do the check. This is
+ * pretty efficient compared to a normal GLib Idle func which has
+ * to busy wait on a timeout, since our condition is only checked
+ * when some other source's state changes
+ */
+typedef gboolean (*g_condition_wait_func)(gpointer);
+
+struct g_condition_wait_source {
+        GSource src;
+        struct coroutine *co;
+	g_condition_wait_func func;
+	gpointer data;
 };
 
-enum {
-  GVNC_AUTH_VENCRYPT_PLAIN = 256,
-  GVNC_AUTH_VENCRYPT_TLSNONE = 257,
-  GVNC_AUTH_VENCRYPT_TLSVNC = 258,
-  GVNC_AUTH_VENCRYPT_TLSPLAIN = 259,
-  GVNC_AUTH_VENCRYPT_X509NONE = 260,
-  GVNC_AUTH_VENCRYPT_X509VNC = 261,
-  GVNC_AUTH_VENCRYPT_X509PLAIN = 262,
+/*
+ * Call immediately before the main loop does an iteration. Returns
+ * true if the condition we're checking is ready for dispatch
+ */
+static gboolean g_condition_wait_prepare(GSource *src,
+					 int *timeout) {
+        struct g_condition_wait_source *vsrc = (struct g_condition_wait_source *)src;
+        *timeout = -1;
+        return vsrc->func(vsrc->data);
+}
+
+/*
+ * Call immediately after the main loop does an iteration. Returns
+ * true if the condition we're checking is ready for dispatch
+ */
+static gboolean g_condition_wait_check(GSource *src) {
+        struct g_condition_wait_source *vsrc = (struct g_condition_wait_source *)src;
+        return vsrc->func(vsrc->data);
+}
+
+static gboolean g_condition_wait_dispatch(GSource *src G_GNUC_UNUSED,
+					  GSourceFunc cb,
+					  gpointer data) {
+        return cb(data);
+}
+
+GSourceFuncs waitFuncs = {
+        .prepare = g_condition_wait_prepare,
+        .check = g_condition_wait_check,
+        .dispatch = g_condition_wait_dispatch,
 };
+
+static gboolean g_condition_wait_helper(gpointer data)
+{
+        struct coroutine *co = (struct coroutine *)data;
+        yieldto(co, NULL);
+        return FALSE;
+}
+
+static gboolean g_condition_wait(g_condition_wait_func func, gpointer data)
+{
+	GSource *src;
+	struct g_condition_wait_source *vsrc;
+
+	/* Short-circuit check in case we've got it ahead of time */
+	if (func(data)) {
+		return TRUE;
+	}
+
+	/*
+	 * Don't have it, so yield to the main loop, checking the condition
+	 * on each iteration of the main loop
+	 */
+	src = g_source_new(&waitFuncs, sizeof(struct g_condition_wait_source));
+	vsrc = (struct g_condition_wait_source *)src;
+
+	vsrc->func = func;
+	vsrc->data = data;
+	vsrc->co = coroutine_self();
+
+	g_source_attach(src, NULL);
+	g_source_set_callback(src, g_condition_wait_helper, coroutine_self(), NULL);
+	yield(NULL);
+	return TRUE;
+}
+
 
 
 #define DEBUG 0
@@ -812,55 +885,62 @@ static void gvnc_hextile_update(struct g
 
 static void gvnc_update(struct gvnc *gvnc, int x, int y, int width, int height)
 {
-	if (gvnc->has_error || !gvnc->ops.update)
+	if (gvnc->has_error || !gvnc->ops->update)
 		return;
-	gvnc->has_error = !gvnc->ops.update(gvnc->ops_data, x, y, width, height);
+	if (!gvnc->ops->update(gvnc->ops_data, x, y, width, height))
+		gvnc->has_error = TRUE;
 }
 
 static void gvnc_set_color_map_entry(struct gvnc *gvnc, uint16_t color,
 				     uint16_t red, uint16_t green,
 				     uint16_t blue)
 {
-	if (gvnc->has_error || !gvnc->ops.set_color_map_entry)
+	if (gvnc->has_error || !gvnc->ops->set_color_map_entry)
 		return;
-	gvnc->has_error = !gvnc->ops.set_color_map_entry(gvnc->ops_data, color,
-							 red, green, blue);
+	if (!gvnc->ops->set_color_map_entry(gvnc->ops_data, color,
+					    red, green, blue))
+		gvnc->has_error = TRUE;
 }
 
 static void gvnc_bell(struct gvnc *gvnc)
 {
-	if (gvnc->has_error || !gvnc->ops.bell)
+	if (gvnc->has_error || !gvnc->ops->bell)
 		return;
-	gvnc->has_error = !gvnc->ops.bell(gvnc->ops_data);
+	if (!gvnc->ops->bell(gvnc->ops_data))
+		gvnc->has_error = TRUE;
 }
 
 static void gvnc_server_cut_text(struct gvnc *gvnc, const void *data,
 				 size_t len)
 {
-	if (gvnc->has_error || !gvnc->ops.server_cut_text)
+	if (gvnc->has_error || !gvnc->ops->server_cut_text)
 		return;
-	gvnc->has_error = !gvnc->ops.server_cut_text(gvnc->ops_data, data, len);
+	if (!gvnc->ops->server_cut_text(gvnc->ops_data, data, len))
+		gvnc->has_error = TRUE;
 }
 
 static void gvnc_resize(struct gvnc *gvnc, int width, int height)
 {
-	if (gvnc->has_error || !gvnc->ops.resize)
+	if (gvnc->has_error || !gvnc->ops->resize)
 		return;
-	gvnc->has_error = !gvnc->ops.resize(gvnc->ops_data, width, height);
+	if (!gvnc->ops->resize(gvnc->ops_data, width, height))
+		gvnc->has_error = TRUE;
 }
 
 static void gvnc_pointer_type_change(struct gvnc *gvnc, int absolute)
 {
-	if (gvnc->has_error || !gvnc->ops.pointer_type_change)
+	if (gvnc->has_error || !gvnc->ops->pointer_type_change)
 		return;
-	gvnc->has_error = !gvnc->ops.pointer_type_change(gvnc->ops_data, absolute);
+	if (!gvnc->ops->pointer_type_change(gvnc->ops_data, absolute))
+		gvnc->has_error = TRUE;
 }
 
 static void gvnc_shared_memory_rmid(struct gvnc *gvnc, int shmid)
 {
-	if (gvnc->has_error || !gvnc->ops.shared_memory_rmid)
+	if (gvnc->has_error || !gvnc->ops->shared_memory_rmid)
 		return;
-	gvnc->has_error = !gvnc->ops.shared_memory_rmid(gvnc->ops_data, shmid);
+	if (!gvnc->ops->shared_memory_rmid(gvnc->ops_data, shmid))
+		gvnc->has_error = TRUE;
 }
 
 static void gvnc_framebuffer_update(struct gvnc *gvnc, int32_t etype,
@@ -1020,19 +1100,19 @@ static gboolean gvnc_check_auth_result(s
 	return FALSE;
 }
 
-static gboolean gvnc_perform_auth_vnc(struct gvnc *gvnc, const char *password)
+static gboolean gvnc_perform_auth_vnc(struct gvnc *gvnc)
 {
 	uint8_t challenge[16];
 	uint8_t key[8];
 
 	GVNC_DEBUG("Do Challenge\n");
-	if (!password)
+	if (!gvnc->cred_password)
 		return FALSE;
 
 	gvnc_read(gvnc, challenge, 16);
 
 	memset(key, 0, 8);
-	strncpy((char*)key, (char*)password, 8);
+	strncpy((char*)key, (char*)gvnc->cred_password, 8);
 
 	deskey(key, EN0);
 	des(challenge, challenge);
@@ -1140,9 +1220,109 @@ static gboolean gvnc_start_tls(struct gv
 	}
 }
 
-static gboolean gvnc_perform_auth_vencrypt(struct gvnc *gvnc, const char *password)
-{
-	int major, minor, status, wantAuth = GVNC_AUTH_INVALID, anonTLS;
+static gboolean gvnc_wants_credential_password(struct gvnc *gvnc)
+{
+        if (gvnc->auth_type == GVNC_AUTH_VNC)
+                return TRUE;
+
+        if (gvnc->auth_type == GVNC_AUTH_VENCRYPT) {
+                if (gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_PLAIN ||
+                    gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_TLSVNC ||
+                    gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_TLSPLAIN ||
+                    gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_X509VNC ||
+                    gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_X509PLAIN)
+                        return TRUE;
+        }
+
+        return FALSE;
+}
+
+static gboolean gvnc_wants_credential_username(struct gvnc *gvnc)
+{
+        if (gvnc->auth_type == GVNC_AUTH_VENCRYPT) {
+                if (gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_PLAIN ||
+                    gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_TLSPLAIN ||
+                    gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_X509PLAIN)
+                        return TRUE;
+        }
+
+        return FALSE;
+}
+
+static gboolean gvnc_has_credential_username(gpointer data)
+{
+	struct gvnc *gvnc = (struct gvnc *)data;
+
+	if (gvnc->has_error)
+		return TRUE;
+	if (gvnc->cred_username == NULL)
+		return FALSE;
+	return TRUE;
+}
+static gboolean gvnc_has_credential_password(gpointer data)
+{
+	struct gvnc *gvnc = (struct gvnc *)data;
+
+	if (gvnc->has_error)
+		return TRUE;
+	if (gvnc->cred_password == NULL)
+		return FALSE;
+	return TRUE;
+}
+
+
+static gboolean gvnc_gather_credentials(struct gvnc *gvnc)
+{
+	if (gvnc_wants_credential_username(gvnc) && !gvnc->cred_username) {
+		GVNC_DEBUG("Requesting username\n");
+		if (gvnc->has_error | !gvnc->ops->cred_username) {
+			gvnc->has_error = TRUE;
+			return TRUE;
+		}
+		if (!gvnc->ops->cred_username(gvnc->ops_data))
+		    gvnc->has_error = TRUE;
+		if (gvnc->has_error)
+			return TRUE;
+		GVNC_DEBUG("Waiting for username credential\n");
+		g_condition_wait(gvnc_has_credential_username, gvnc);
+		GVNC_DEBUG("Got username credential: %s\n", gvnc->cred_username);
+		if (gvnc->has_error)
+			return TRUE;
+	}
+	if (gvnc_wants_credential_password(gvnc) && !gvnc->cred_password) {
+		GVNC_DEBUG("Requesting password\n");
+		if (gvnc->has_error | !gvnc->ops->cred_password) {
+			gvnc->has_error = TRUE;
+			return TRUE;
+		}
+		if (!gvnc->ops->cred_password(gvnc->ops_data))
+		    gvnc->has_error = TRUE;
+		if (gvnc->has_error)
+			return TRUE;
+		GVNC_DEBUG("Waiting for password credential\n");
+		g_condition_wait(gvnc_has_credential_password, gvnc);
+		GVNC_DEBUG("Got password credential: %s\n", gvnc->cred_password);
+		if (gvnc->has_error)
+			return TRUE;
+	}
+	return gvnc_has_error(gvnc);
+}
+
+static gboolean gvnc_has_auth_subtype(gpointer data)
+{
+	struct gvnc *gvnc = (struct gvnc *)data;
+
+	if (gvnc->has_error)
+		return TRUE;
+	if (gvnc->auth_subtype == GVNC_AUTH_INVALID)
+		return FALSE;
+	return TRUE;
+}
+
+
+static gboolean gvnc_perform_auth_vencrypt(struct gvnc *gvnc)
+{
+	int major, minor, status, anonTLS;
 	unsigned int nauth, i;
 	unsigned int auth[20];
 
@@ -1178,41 +1358,48 @@ static gboolean gvnc_perform_auth_vencry
 		GVNC_DEBUG("Possible auth %d\n", auth[i]);
 	}
 
+	if (gvnc->has_error || !gvnc->ops->auth_subtype)
+		return FALSE;
+
+	if (!gvnc->ops->auth_subtype(gvnc->ops_data, nauth, auth))
+		gvnc->has_error = TRUE;
 	if (gvnc->has_error)
 		return FALSE;
 
-	for (i = 0 ; i < nauth ; i++) {
-		if (auth[i] == GVNC_AUTH_VENCRYPT_TLSNONE ||
-		    auth[i] == GVNC_AUTH_VENCRYPT_TLSPLAIN ||
-		    auth[i] == GVNC_AUTH_VENCRYPT_TLSVNC ||
-		    auth[i] == GVNC_AUTH_VENCRYPT_X509NONE ||
-		    auth[i] == GVNC_AUTH_VENCRYPT_X509PLAIN ||
-		    auth[i] == GVNC_AUTH_VENCRYPT_X509VNC) {
-			wantAuth = auth[i];
-			break;
-		}
-	}
-
-	if (wantAuth == GVNC_AUTH_VENCRYPT_PLAIN) {
+	GVNC_DEBUG("Waiting for auth subtype\n");
+	g_condition_wait(gvnc_has_auth_subtype, gvnc);
+	if (gvnc->has_error)
+		return FALSE;
+
+	GVNC_DEBUG("Choose auth %d\n", gvnc->auth_subtype);
+
+	if (gvnc_gather_credentials(gvnc))
+		return FALSE;
+
+#if !DEBUG
+	if (gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_PLAIN) {
 		GVNC_DEBUG("Cowardly refusing to transmit plain text password\n");
 		return FALSE;
 	}
-
-	GVNC_DEBUG("Choose auth %d\n", wantAuth);
-	gvnc_write_u32(gvnc, wantAuth);
+#endif
+
+	gvnc_write_u32(gvnc, gvnc->auth_subtype);
 	gvnc_flush(gvnc);
 	status = gvnc_read_u8(gvnc);
 	if (status != 1) {
-		GVNC_DEBUG("Server refused VeNCrypt auth %d %d\n", wantAuth, status);
-		return FALSE;
-	}
-
-	if (wantAuth == GVNC_AUTH_VENCRYPT_TLSNONE ||
-	    wantAuth ==  GVNC_AUTH_VENCRYPT_TLSPLAIN ||
-	    wantAuth ==  GVNC_AUTH_VENCRYPT_TLSVNC)
+		GVNC_DEBUG("Server refused VeNCrypt auth %d %d\n", gvnc->auth_subtype, status);
+		return FALSE;
+	}
+
+	switch (gvnc->auth_subtype) {
+	case GVNC_AUTH_VENCRYPT_TLSNONE:
+	case GVNC_AUTH_VENCRYPT_TLSPLAIN:
+	case GVNC_AUTH_VENCRYPT_TLSVNC:
 		anonTLS = 1;
-	else
+		break;
+	default:
 		anonTLS = 0;
+	}
 
 	if (!gvnc_start_tls(gvnc, anonTLS)) {
 		GVNC_DEBUG("Could not start TLS\n");
@@ -1220,7 +1407,7 @@ static gboolean gvnc_perform_auth_vencry
 	}
 	GVNC_DEBUG("Completed TLS setup\n");
 
-	switch (wantAuth) {
+	switch (gvnc->auth_subtype) {
 		/* Plain certificate based auth */
 	case GVNC_AUTH_VENCRYPT_TLSNONE:
 	case GVNC_AUTH_VENCRYPT_X509NONE:
@@ -1231,16 +1418,26 @@ static gboolean gvnc_perform_auth_vencry
 	case GVNC_AUTH_VENCRYPT_TLSVNC:
 	case GVNC_AUTH_VENCRYPT_X509VNC:
 		GVNC_DEBUG("Handing off to VNC auth\n");
-		return gvnc_perform_auth_vnc(gvnc, password);
+		return gvnc_perform_auth_vnc(gvnc);
 
 	default:
 		return FALSE;
 	}
 }
 
-static gboolean gvnc_perform_auth(struct gvnc *gvnc, const char *password)
-{
-	int wantAuth = GVNC_AUTH_INVALID;
+static gboolean gvnc_has_auth_type(gpointer data)
+{
+	struct gvnc *gvnc = (struct gvnc *)data;
+
+	if (gvnc->has_error)
+		return TRUE;
+	if (gvnc->auth_type == GVNC_AUTH_INVALID)
+		return FALSE;
+	return TRUE;
+}
+
+static gboolean gvnc_perform_auth(struct gvnc *gvnc)
+{
 	unsigned int nauth, i;
 	unsigned int auth[10];
 
@@ -1267,40 +1464,56 @@ static gboolean gvnc_perform_auth(struct
 		GVNC_DEBUG("Possible auth %d\n", auth[i]);
 	}
 
+	if (gvnc->has_error || !gvnc->ops->auth_type)
+		return FALSE;
+
+	if (!gvnc->ops->auth_type(gvnc->ops_data, nauth, auth))
+		gvnc->has_error = TRUE;
 	if (gvnc->has_error)
 		return FALSE;
 
-	for (i = 0 ; i < nauth ; i++) {
-		if (auth[i] == GVNC_AUTH_NONE ||
-		    auth[i] == GVNC_AUTH_VNC ||
-		    auth[i] == GVNC_AUTH_VENCRYPT) {
-			wantAuth = auth[i];
-			break;
-		}
-	}
+	GVNC_DEBUG("Waiting for auth type\n");
+	g_condition_wait(gvnc_has_auth_type, gvnc);
+	if (gvnc->has_error)
+		return FALSE;
+
+	GVNC_DEBUG("Choose auth %d\n", gvnc->auth_type);
+	if (gvnc_gather_credentials(gvnc))
+		return FALSE;
 
 	if (gvnc->minor > 6) {
-		GVNC_DEBUG("Chose auth %d\n", wantAuth);
-		gvnc_write_u8(gvnc, wantAuth);
+		gvnc_write_u8(gvnc, gvnc->auth_type);
 		gvnc_flush(gvnc);
 	}
 
-	switch (wantAuth) {
+	switch (gvnc->auth_type) {
 	case GVNC_AUTH_NONE:
 		if (gvnc->minor == 8)
 			return gvnc_check_auth_result(gvnc);
 		return TRUE;
 	case GVNC_AUTH_VNC:
-		return gvnc_perform_auth_vnc(gvnc, password);
+		return gvnc_perform_auth_vnc(gvnc);
 
 	case GVNC_AUTH_VENCRYPT:
-		return gvnc_perform_auth_vencrypt(gvnc, password);
+		return gvnc_perform_auth_vencrypt(gvnc);
 
 	default:
 		return FALSE;
 	}
 
 	return TRUE;
+}
+
+static void gvnc_init(struct gvnc *gvnc, const struct gvnc_ops *ops, gpointer ops_data)
+{
+	memset(gvnc, 0, sizeof(*gvnc));
+	gvnc->fd = -1;
+
+	gvnc->ops = ops;
+	gvnc->ops_data = ops_data;
+
+	gvnc->auth_type = GVNC_AUTH_INVALID;
+	gvnc->auth_subtype = GVNC_AUTH_INVALID;
 }
 
 struct gvnc *gvnc_new(const struct gvnc_ops *ops, gpointer ops_data)
@@ -1309,11 +1522,7 @@ struct gvnc *gvnc_new(const struct gvnc_
 	if (gvnc == NULL)
 		return NULL;
 
-	memset(gvnc, 0, sizeof(*gvnc));
-	gvnc->fd = -1;
-
-	memcpy(&gvnc->ops, ops, sizeof(*ops));
-	gvnc->ops_data = ops_data;
+	gvnc_init(gvnc, ops, ops_data);
 
 	return gvnc;
 }
@@ -1328,29 +1537,29 @@ void gvnc_free(struct gvnc *gvnc)
 
 void gvnc_close(struct gvnc *gvnc)
 {
-	if (gvnc->tls_session) {
+	const struct gvnc_ops *ops = gvnc->ops;
+	gpointer ops_data = gvnc->ops_data;
+
+	if (gvnc->tls_session)
 		gnutls_bye(gvnc->tls_session, GNUTLS_SHUT_RDWR);
-		gvnc->tls_session = NULL;
-	}
-	if (gvnc->channel) {
+	if (gvnc->channel)
 		g_io_channel_unref(gvnc->channel);
-		gvnc->channel = NULL;
-	}
-	if (gvnc->fd != -1) {
+	if (gvnc->fd != -1)
 		close(gvnc->fd);
-		gvnc->fd = -1;
-	}
 
 	free(gvnc->host);
-	gvnc->host = NULL;
-
 	free(gvnc->port);
-	gvnc->port = NULL;
-
 	free(gvnc->name);
-	gvnc->name = NULL;
-
-	gvnc->has_error = 0;
+	free(gvnc->cred_username);
+	free(gvnc->cred_password);
+
+	gvnc_init(gvnc, ops, ops_data);
+}
+
+void gvnc_shutdown(struct gvnc *gvnc)
+{
+	GVNC_DEBUG("Marking connection with error\n");
+	gvnc->has_error = TRUE;
 }
 
 gboolean gvnc_is_connected(struct gvnc *gvnc)
@@ -1363,7 +1572,7 @@ gboolean gvnc_is_connected(struct gvnc *
 }
 
 
-static gboolean gvnc_connect(struct gvnc *gvnc, gboolean shared_flag, const char *password)
+static gboolean gvnc_connect(struct gvnc *gvnc, gboolean shared_flag)
 {
 	int ret;
 	char version[13];
@@ -1392,7 +1601,7 @@ static gboolean gvnc_connect(struct gvnc
 	gvnc_flush(gvnc);
 	GVNC_DEBUG("Negotiated protocol %d %d\n", gvnc->major, gvnc->minor);
 
-	if (!gvnc_perform_auth(gvnc, password)) {
+	if (!gvnc_perform_auth(gvnc)) {
 		GVNC_DEBUG("Auth failed\n");
 		goto fail;
 	}
@@ -1420,11 +1629,11 @@ static gboolean gvnc_connect(struct gvnc
 	return gvnc_has_error(gvnc);
 
  fail:
-	gvnc->has_error = 1;
+	gvnc->has_error = TRUE;
 	return gvnc_has_error(gvnc);
 }
 
-gboolean gvnc_connect_fd(struct gvnc *gvnc, int fd,  gboolean shared_flag, const char *password)
+gboolean gvnc_connect_fd(struct gvnc *gvnc, int fd,  gboolean shared_flag)
 {
 	int flags;
 	if (gvnc_is_connected(gvnc))
@@ -1441,10 +1650,10 @@ gboolean gvnc_connect_fd(struct gvnc *gv
 		return TRUE;
 	gvnc->fd = fd;
 
-	return gvnc_connect(gvnc, shared_flag, password);
-}
-
-gboolean gvnc_connect_name(struct gvnc *gvnc, const char *host, const char *port,  gboolean shared_flag, const char *password)
+	return gvnc_connect(gvnc, shared_flag);
+}
+
+gboolean gvnc_connect_name(struct gvnc *gvnc, const char *host, const char *port,  gboolean shared_flag)
 {
         struct addrinfo *ai, *runp, hints;
         int ret;
@@ -1486,14 +1695,16 @@ gboolean gvnc_connect_name(struct gvnc *
                 }
 
         reconnect:
+		GVNC_DEBUG("Trying to connect\n");
                 if (connect(fd, runp->ai_addr, runp->ai_addrlen) == 0) {
                         gvnc->channel = chan;
                         gvnc->fd = fd;
                         freeaddrinfo(ai);
-                        return gvnc_connect(gvnc, shared_flag, password);
+                        return gvnc_connect(gvnc, shared_flag);
                 }
 
                 if (errno == EINPROGRESS) {
+			GVNC_DEBUG("Waiting for connect to continue\n");
                         g_io_wait(chan, G_IO_OUT|G_IO_ERR|G_IO_HUP);
                         goto reconnect;
                 } else if (errno != ECONNREFUSED) {
@@ -1510,6 +1721,65 @@ gboolean gvnc_connect_name(struct gvnc *
 }
 
 
+gboolean gvnc_set_auth_type(struct gvnc *gvnc, unsigned int type)
+{
+        GVNC_DEBUG("Requested auth type %d\n", type);
+        if (gvnc->auth_type != GVNC_AUTH_INVALID) {
+                gvnc->has_error = TRUE;
+                return gvnc_has_error(gvnc);
+        }
+        if (type != GVNC_AUTH_NONE &&
+            type != GVNC_AUTH_VNC &&
+            type != GVNC_AUTH_VENCRYPT) {
+                gvnc->has_error = TRUE;
+                return gvnc_has_error(gvnc);
+        }
+        gvnc->auth_type = type;
+        gvnc->auth_subtype = GVNC_AUTH_INVALID;
+
+	return gvnc_has_error(gvnc);
+}
+
+gboolean gvnc_set_auth_subtype(struct gvnc *gvnc, unsigned int type)
+{
+        GVNC_DEBUG("Requested auth subtype %d\n", type);
+        if (gvnc->auth_type != GVNC_AUTH_VENCRYPT) {
+                gvnc->has_error = TRUE;
+		return gvnc_has_error(gvnc);
+        }
+        if (gvnc->auth_subtype != GVNC_AUTH_INVALID) {
+                gvnc->has_error = TRUE;
+		return gvnc_has_error(gvnc);
+        }
+        gvnc->auth_subtype = type;
+
+	return gvnc_has_error(gvnc);
+}
+
+gboolean gvnc_set_credential_password(struct gvnc *gvnc, const char *password)
+{
+        GVNC_DEBUG("Set password credential\n");
+        if (gvnc->cred_password)
+                free(gvnc->cred_password);
+        if (!(gvnc->cred_password = strdup(password))) {
+                gvnc->has_error = TRUE;
+                return FALSE;
+        }
+        return TRUE;
+}
+
+gboolean gvnc_set_credential_username(struct gvnc *gvnc, const char *username)
+{
+        GVNC_DEBUG("Set username credential %s\n", username);
+        if (gvnc->cred_username)
+                free(gvnc->cred_username);
+        if (!(gvnc->cred_username = strdup(username))) {
+                gvnc->has_error = TRUE;
+                return FALSE;
+        }
+        return TRUE;
+}
+
 
 gboolean gvnc_set_local(struct gvnc *gvnc, struct gvnc_framebuffer *fb)
 {
diff -r b77ea47300ab -r 7f9c4f423f86 src/gvnc.h
--- a/src/gvnc.h	Wed Jul 04 15:32:55 2007 -0400
+++ b/src/gvnc.h	Thu Jul 05 13:48:15 2007 -0400
@@ -8,6 +8,10 @@ struct gvnc;
 
 struct gvnc_ops
 {
+	gboolean (*cred_username)(void *);
+	gboolean (*cred_password)(void *);
+	gboolean (*auth_type)(void *, unsigned int, unsigned int *);
+	gboolean (*auth_subtype)(void *, unsigned int, unsigned int *);
 	gboolean (*update)(void *, int, int, int, int);
 	gboolean (*set_color_map_entry)(void *, int, int, int, int);
 	gboolean (*bell)(void *);
@@ -71,13 +75,42 @@ enum {
 	GVNC_ENCODING_SHARED_MEMORY = -258,
 };
 
+enum {
+	GVNC_AUTH_INVALID = 0,
+	GVNC_AUTH_NONE = 1,
+	GVNC_AUTH_VNC = 2,
+	GVNC_AUTH_RA2 = 5,
+	GVNC_AUTH_RA2NE = 6,
+	GVNC_AUTH_TIGHT = 16,
+	GVNC_AUTH_ULTRA = 17,
+	GVNC_AUTH_TLS = 18,
+	GVNC_AUTH_VENCRYPT = 19
+};
+
+enum {
+	GVNC_AUTH_VENCRYPT_PLAIN = 256,
+	GVNC_AUTH_VENCRYPT_TLSNONE = 257,
+	GVNC_AUTH_VENCRYPT_TLSVNC = 258,
+	GVNC_AUTH_VENCRYPT_TLSPLAIN = 259,
+	GVNC_AUTH_VENCRYPT_X509NONE = 260,
+	GVNC_AUTH_VENCRYPT_X509VNC = 261,
+	GVNC_AUTH_VENCRYPT_X509PLAIN = 262,
+};
+
 struct gvnc *gvnc_new(const struct gvnc_ops *ops, gpointer ops_data);
 void gvnc_free(struct gvnc *gvnc);
 void gvnc_close(struct gvnc *gvnc);
+void gvnc_shutdown(struct gvnc *gvnc);
 
 gboolean gvnc_is_connected(struct gvnc *gvnc);
-gboolean gvnc_connect_fd(struct gvnc *gvnc, int fd, gboolean shared_flag, const char *password);
-gboolean gvnc_connect_name(struct gvnc *gvnc, const char *host, const char *port, gboolean shared_flag, const char *password);
+gboolean gvnc_connect_fd(struct gvnc *gvnc, int fd, gboolean shared_flag);
+gboolean gvnc_connect_name(struct gvnc *gvnc, const char *host, const char *port, gboolean shared_flag);
+
+gboolean gvnc_set_auth_type(struct gvnc *gvnc, unsigned int type);
+gboolean gvnc_set_auth_subtype(struct gvnc *gvnc, unsigned int type);
+
+gboolean gvnc_set_credential_password(struct gvnc *gvnc, const char *password);
+gboolean gvnc_set_credential_username(struct gvnc *gvnc, const char *username);
 
 gboolean gvnc_server_message(struct gvnc *gvnc);
 
diff -r b77ea47300ab -r 7f9c4f423f86 src/libgtk-vnc_sym.version
--- a/src/libgtk-vnc_sym.version	Wed Jul 04 15:32:55 2007 -0400
+++ b/src/libgtk-vnc_sym.version	Thu Jul 05 13:48:15 2007 -0400
@@ -1,10 +1,17 @@
 {
   global:
     vnc_display_get_type;
+    vnc_display_credential_get_type;
+
     vnc_display_new;
+
     vnc_display_open_fd;
     vnc_display_open_name;
-    vnc_display_set_password;
+    vnc_display_is_open;
+    vnc_display_close;
+
+    vnc_display_set_credential;
+
     vnc_display_set_use_shm;
     vnc_display_get_width;
     vnc_display_get_height;
diff -r b77ea47300ab -r 7f9c4f423f86 src/vncdisplay.c
--- a/src/vncdisplay.c	Wed Jul 04 15:32:55 2007 -0400
+++ b/src/vncdisplay.c	Thu Jul 05 13:48:15 2007 -0400
@@ -41,7 +41,6 @@ struct _VncDisplayPrivate
 	int button_mask;
 	int last_x;
 	int last_y;
-	const char *password;
 
 	int absolute;
 
@@ -51,12 +50,14 @@ struct _VncDisplayPrivate
 /* Signals */
 enum
 {
+	VNC_CONNECTED,
 	VNC_INITIALIZED,
 	VNC_DISCONNECTED,
+	VNC_AUTH_CREDENTIAL,
 	LAST_SIGNAL
 };
 
-static guint signals[LAST_SIGNAL] = { 0, 0 };
+static guint signals[LAST_SIGNAL] = { 0, 0, 0, 0 };
 
 GtkWidget *vnc_display_new(void)
 {
@@ -370,7 +371,66 @@ static gboolean on_shared_memory_rmid(vo
 	return TRUE;
 }
 
+static gboolean on_cred_username(void *opaque)
+{
+	VncDisplay *obj = VNC_DISPLAY(opaque);
+
+	g_signal_emit (G_OBJECT (obj),
+		       signals[VNC_AUTH_CREDENTIAL],
+		       0,
+		       VNC_DISPLAY_CREDENTIAL_USERNAME);
+
+	return TRUE;
+}
+
+static gboolean on_cred_password(void *opaque)
+{
+	VncDisplay *obj = VNC_DISPLAY(opaque);
+
+	g_signal_emit (G_OBJECT (obj),
+		       signals[VNC_AUTH_CREDENTIAL],
+		       0,
+		       VNC_DISPLAY_CREDENTIAL_PASSWORD);
+
+	return TRUE;
+}
+
+static gboolean on_auth_type(void *opaque, unsigned int ntype, unsigned int *types)
+{
+	VncDisplay *obj = VNC_DISPLAY(opaque);
+	VncDisplayPrivate *priv = obj->priv;
+
+	/*
+	 * XXX lame - we should have some prioritization. That
+	 * said most servers only support 1 auth type at any time
+	 */
+	if (ntype)
+		gvnc_set_auth_type(priv->gvnc, types[0]);
+
+	return TRUE;
+}
+
+static gboolean on_auth_subtype(void *opaque, unsigned int ntype, unsigned int *types)
+{
+	VncDisplay *obj = VNC_DISPLAY(opaque);
+	VncDisplayPrivate *priv = obj->priv;
+
+	/*
+	 * XXX lame - we should have some prioritization. That
+	 * said most servers only support 1 auth type at any time
+	 */
+	if (ntype)
+		gvnc_set_auth_subtype(priv->gvnc, types[0]);
+
+	return TRUE;
+}
+
+
 static const struct gvnc_ops vnc_display_ops = {
+	.cred_username = on_cred_username,
+	.cred_password = on_cred_password,
+	.auth_type = on_auth_type,
+	.auth_subtype = on_auth_subtype,
 	.update = on_update,
 	.resize = on_resize,
 	.pointer_type_change = on_pointer_type_change,
@@ -390,17 +450,19 @@ static void *vnc_coroutine(void *opaque)
 
 	int ret;
 
-	priv->gvnc = gvnc_new(&vnc_display_ops, obj);
-	if (priv->gvnc == NULL)
-		return NULL;
-
 	if (priv->fd != -1) {
-		if (gvnc_connect_fd(priv->gvnc, priv->fd, FALSE, priv->password))
+		if (gvnc_connect_fd(priv->gvnc, priv->fd, FALSE))
 			goto cleanup;
 	} else {
-		if (gvnc_connect_name(priv->gvnc, priv->host, priv->port, FALSE, priv->password))
+		if (gvnc_connect_name(priv->gvnc, priv->host, priv->port, FALSE))
 			goto cleanup;
 	}
+
+	/* XXX this should be emitted after socket connects, but before
+	   protocol negoitiation starts */
+	g_signal_emit (G_OBJECT (obj),
+		       signals[VNC_CONNECTED],
+		       0);
 
 	g_signal_emit (G_OBJECT (obj),
 		       signals[VNC_INITIALIZED],
@@ -419,8 +481,7 @@ static void *vnc_coroutine(void *opaque)
 	}
 
  cleanup:
-	gvnc_free(priv->gvnc);
-	priv->gvnc = NULL;
+	gvnc_close(priv->gvnc);
 	g_signal_emit (G_OBJECT (obj),
 		       signals[VNC_DISCONNECTED],
 		       0);
@@ -446,7 +507,10 @@ static gboolean do_vnc_display_open(gpoi
 
 gboolean vnc_display_open_fd(VncDisplay *obj, int fd)
 {
-	if (obj->priv->gvnc)
+	if (!obj->priv->gvnc)
+		return FALSE;
+
+	if (gvnc_is_connected(obj->priv->gvnc))
 		return FALSE;
 
 	obj->priv->fd = fd;
@@ -459,7 +523,10 @@ gboolean vnc_display_open_fd(VncDisplay 
 
 gboolean vnc_display_open_name(VncDisplay *obj, const char *host, const char *port)
 {
-	if (obj->priv->gvnc)
+	if (!obj->priv->gvnc)
+		return FALSE;
+
+	if (gvnc_is_connected(obj->priv->gvnc))
 		return FALSE;
 
 	obj->priv->host = strdup(host);
@@ -477,9 +544,41 @@ gboolean vnc_display_open_name(VncDispla
 	return TRUE;
 }
 
+
+gboolean vnc_display_is_open(VncDisplay *obj)
+{
+	if (!obj->priv->gvnc)
+		return FALSE;
+
+	if (gvnc_is_connected(obj->priv->gvnc))
+		return TRUE;
+
+	return FALSE;
+}
+
+gboolean vnc_display_close(VncDisplay *obj)
+{
+	if (!vnc_display_is_open(obj))
+		return FALSE;
+
+	gvnc_shutdown(obj->priv->gvnc);
+
+	return TRUE;
+}
+
 static void vnc_display_class_init(VncDisplayClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	signals[VNC_CONNECTED] =
+		g_signal_new ("vnc-connected",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (VncDisplayClass, vnc_connected),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE,
+			      0);
 
 	signals[VNC_INITIALIZED] =
 		g_signal_new ("vnc-initialized",
@@ -500,6 +599,17 @@ static void vnc_display_class_init(VncDi
 			      g_cclosure_marshal_VOID__VOID,
 			      G_TYPE_NONE,
 			      0);
+
+	signals[VNC_AUTH_CREDENTIAL] =
+		g_signal_new ("vnc-auth-credential",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (VncDisplayClass, vnc_auth_credential),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__INT,
+			      G_TYPE_NONE,
+			      1,
+			      G_TYPE_INT);
 
 	klass->enter_grab_event_id =
 		g_signal_new("enter-grab-event",
@@ -566,11 +676,25 @@ static void vnc_display_init(GTypeInstan
 	display->priv->absolute = 1;
 	display->priv->fb.shm_id = -1;
 	display->priv->fd = -1;
-}
-
-void vnc_display_set_password(VncDisplay *obj, const gchar *password)
-{
-	obj->priv->password = password;
+
+	display->priv->gvnc = gvnc_new(&vnc_display_ops, obj);
+}
+
+gboolean vnc_display_set_credential(VncDisplay *obj, int type, const gchar *data)
+{
+	switch (type) {
+	case VNC_DISPLAY_CREDENTIAL_PASSWORD:
+		if (gvnc_set_credential_password(obj->priv->gvnc, data))
+			return FALSE;
+		return TRUE;
+
+	case VNC_DISPLAY_CREDENTIAL_USERNAME:
+		if (gvnc_set_credential_username(obj->priv->gvnc, data))
+			return FALSE;
+		return TRUE;
+	}
+
+	return FALSE;
 }
 
 void vnc_display_set_use_shm(VncDisplay *obj, gboolean enable)
@@ -604,6 +728,26 @@ GType vnc_display_get_type(void)
 
 	return type;
 }
+
+
+GType vnc_display_credential_get_type(void)
+{
+	static GType etype = 0;
+
+	if (etype == 0) {
+		static const GEnumValue values[] = {
+			{ VNC_DISPLAY_CREDENTIAL_PASSWORD, "VNC_DISPLAY_CREDENTIAL_PASSWORD", "password" },
+			{ VNC_DISPLAY_CREDENTIAL_USERNAME, "VNC_DISPLAY_CREDENTIAL_USERNAME", "username" },
+			{ 0, NULL, NULL }
+		};
+		etype = g_enum_register_static ("VncDisplayCredentialType", values );
+	}
+
+	return etype;
+}
+
+
+
 
 int vnc_display_get_width(VncDisplay *obj)
 {
diff -r b77ea47300ab -r 7f9c4f423f86 src/vncdisplay.h
--- a/src/vncdisplay.h	Wed Jul 04 15:32:55 2007 -0400
+++ b/src/vncdisplay.h	Thu Jul 05 13:48:15 2007 -0400
@@ -19,6 +19,7 @@ typedef struct _VncDisplayPrivate VncDis
 #include <glib.h>
 
 #define VNC_TYPE_DISPLAY (vnc_display_get_type())
+#define VNC_TYPE_DISPLAY_CREDENTIAL (vnc_display_credential_get_type())
 
 #define VNC_DISPLAY(obj) \
         (G_TYPE_CHECK_INSTANCE_CAST((obj), VNC_TYPE_DISPLAY, VncDisplay))
@@ -47,22 +48,34 @@ struct _VncDisplayClass
 	GtkDrawingAreaClass parent_class;
 
 	/* Signals */
+	void		(* vnc_connected)	(VncDisplay *display);
 	void		(* vnc_initialized)	(VncDisplay *display);
 	void		(* vnc_disconnected)	(VncDisplay *display);
+	void		(* vnc_auth_credential)	(VncDisplay *display, int credential);
 
 	int enter_grab_event_id;
 	int leave_grab_event_id;
 };
 
+typedef enum
+{
+	VNC_DISPLAY_CREDENTIAL_PASSWORD,
+	VNC_DISPLAY_CREDENTIAL_USERNAME,
+} VncDisplayCredential;
+
 G_BEGIN_DECLS
 
 GType		vnc_display_get_type(void);
+GType		vnc_display_credential_get_type(void);
+
 GtkWidget *	vnc_display_new(void);
 
 gboolean	vnc_display_open_fd(VncDisplay *obj, int fd);
 gboolean	vnc_display_open_name(VncDisplay *obj, const char *host, const char *port);
+gboolean	vnc_display_is_open(VncDisplay *obj);
+gboolean	vnc_display_close(VncDisplay *obj);
 
-void		vnc_display_set_password(VncDisplay *obj, const gchar *password);
+gboolean	vnc_display_set_credential(VncDisplay *obj, int type, const gchar *data);
 
 void		vnc_display_set_use_shm(VncDisplay *obj, gboolean enable);
 
diff -r b77ea47300ab -r 7f9c4f423f86 src/vncmodule.c
--- a/src/vncmodule.c	Wed Jul 04 15:32:55 2007 -0400
+++ b/src/vncmodule.c	Thu Jul 05 13:48:15 2007 -0400
@@ -21,6 +21,7 @@
 #include <pygobject.h>
  
 void gtkvnc_register_classes (PyObject *d); 
+void gtkvnc_add_constants(PyObject *module, const gchar *strip_prefix);
 extern PyMethodDef gtkvnc_functions[];
  
 DL_EXPORT(void) initgtkvnc(void);
@@ -39,6 +40,7 @@ DL_EXPORT(void) initgtkvnc(void)
     if (PyErr_Occurred())
 	Py_FatalError("can't get dict");
  
+    gtkvnc_add_constants(m, "VNC_DISPLAY_");
     gtkvnc_register_classes (d);
  
     if (PyErr_Occurred ()) {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]