changeset 998:70c685de2be5

[gaim-migrate @ 1008] this is going to make it easier to add more protocols. each protocol now sets up connections with protocol-specific data. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Sun, 15 Oct 2000 03:50:32 +0000
parents 56cff2fba28c
children 0b5db8cdd30f
files src/conversation.c src/multi.c src/multi.h src/oscar.c src/toc.c
diffstat 5 files changed, 162 insertions(+), 120 deletions(-) [+]
line wrap: on
line diff
--- a/src/conversation.c	Sun Oct 15 02:00:05 2000 +0000
+++ b/src/conversation.c	Sun Oct 15 03:50:32 2000 +0000
@@ -391,14 +391,17 @@
 		serv_chat_leave(c->gc, c->id);
 	} else {
 		if (c->is_direct) {
+			/* FIXME
 			if (c->gc->protocol == PROTO_OSCAR) {
 				gdk_input_remove(c->watcher);
 				sprintf(debug_buff, "Closing DirectIM conversation (%p)\n", c->conn);
 				debug_print(debug_buff);
-				aim_conn_kill(c->gc->oscar_sess, &c->conn);
+				aim_conn_kill(((struct oscar_data *)c->gc->proto_data)->sess,
+						&c->conn);
 			} else {
-				/* Direct IM TOC FIXME */
+				Direct IM TOC FIXME
 			}
+			*/
 		}
 	        delete_conversation(c);
 	}
--- a/src/multi.c	Sun Oct 15 02:00:05 2000 +0000
+++ b/src/multi.c	Sun Oct 15 03:50:32 2000 +0000
@@ -54,7 +54,11 @@
 	g_snprintf(gc->username, sizeof(gc->username), "%s", username);
 	g_snprintf(gc->password, sizeof(gc->password), "%s", password);
 	gc->keepalive = -1;
+	gc->inpa = -1;
+	gc->buddy_chats = NULL;
 
+	/* this got moved to the void *proto_data, and each protocol can set this up
+	 * itself, thank you very much
 	switch(proto) {
 		case PROTO_TOC:
 			gc->toc_fd = -1;
@@ -72,10 +76,8 @@
 			gc->create_name = NULL;
 			gc->oscar_chats = NULL;
 			break;
-		default: /* damn plugins */
-			/* PRPL */
-			break;
 	}
+	*/
 
 	connections = g_slist_append(connections, gc);
 
--- a/src/multi.h	Sun Oct 15 02:00:05 2000 +0000
+++ b/src/multi.h	Sun Oct 15 03:50:32 2000 +0000
@@ -36,28 +36,15 @@
 	int protocol;
 	struct prpl *prpl;
 
-	/* let's do the oscar-specific stuff first since i know it better */
-	struct aim_session_t *oscar_sess;
-	struct aim_conn_t *oscar_conn; /* we don't particularly need this since it
-					  will be in oscar_sess, but it's useful to
-					  still keep our own reference to it */
-	int inpa; /* do we really need this? it's for the BOS conn */
-	int cnpa; /* chat nav input watcher */
-	int paspa; /* for changing passwords, which doesn't work yet */
+	/* all connections need an input watcher */
+	int inpa;
 
-	int create_exchange;
-	char *create_name;
-
-	GSList *oscar_chats;
+	/* all connections need a list of chats, even if they don't have chat */
 	GSList *buddy_chats;
 
-	/* that's all we need for oscar. now then, on to TOC.... */
-	int toc_fd;
-	int seqno;
-	int state;
-	/* int inpa; input watcher, dual-declared for oscar as well */
+	/* each connection then can have its own protocol-specific data */
+	void *proto_data;
 
-	/* now we'll do stuff that both of them need */
 	char username[64];
 	char password[32];
 	char user_info[2048];
--- a/src/oscar.c	Sun Oct 15 02:00:05 2000 +0000
+++ b/src/oscar.c	Sun Oct 15 03:50:32 2000 +0000
@@ -50,10 +50,22 @@
 
 int gaim_caps = AIM_CAPS_CHAT | AIM_CAPS_SENDFILE | AIM_CAPS_GETFILE |
 		AIM_CAPS_VOICE | AIM_CAPS_IMIMAGE | AIM_CAPS_BUDDYICON;
-int keepalv = -1;
+
+struct oscar_data {
+	struct aim_session_t *sess;
+	struct aim_conn_t *conn;
+
+	int cnpa;
+	int paspa;
+
+	int create_exchange;
+	char *create_name;
+
+	GSList *oscar_chats;
+};
 
 struct chat_connection *find_oscar_chat(struct gaim_connection *gc, char *name) {
-	GSList *g = gc->oscar_chats;
+	GSList *g = ((struct oscar_data *)gc->proto_data)->oscar_chats;
 	struct chat_connection *c = NULL;
 	if (gc->protocol != PROTO_OSCAR) return NULL;
 
@@ -70,7 +82,7 @@
 
 static struct chat_connection *find_oscar_chat_by_conn(struct gaim_connection *gc,
 							struct aim_conn_t *conn) {
-	GSList *g = gc->oscar_chats;
+	GSList *g = ((struct oscar_data *)gc->proto_data)->oscar_chats;
 	struct chat_connection *c = NULL;
 
 	while (g) {
@@ -90,7 +102,7 @@
 
 	while (g) {
 		gc = (struct gaim_connection *)g->data;
-		if (sess == gc->oscar_sess)
+		if (sess == ((struct oscar_data *)gc->proto_data)->sess)
 			break;
 		g = g->next;
 		gc = NULL;
@@ -110,7 +122,7 @@
 			g = g->next;
 			continue;
 		}
-		s = c->oscar_sess->connlist;
+		s = ((struct oscar_data *)c->proto_data)->sess->connlist;
 		while (s) {
 			if (conn == s)
 				break;
@@ -186,6 +198,7 @@
 				GdkInputCondition condition) {
 	struct aim_conn_t *conn = (struct aim_conn_t *)data;
 	struct gaim_connection *gc = find_gaim_conn_by_oscar_conn(conn);
+	struct oscar_data *odata = (struct oscar_data *)gc->proto_data;
 	if (!gc) {
 		/* oh boy. this is probably bad. i guess the only thing we can really do
 		 * is return? */
@@ -201,12 +214,12 @@
 	if (condition & GDK_INPUT_READ) {
 		if (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) {
 			debug_print("got information on rendezvous\n");
-			if (aim_handlerendconnect(gc->oscar_sess, conn) < 0) {
+			if (aim_handlerendconnect(odata->sess, conn) < 0) {
 				debug_print(_("connection error (rend)\n"));
 			}
 		} else {
-			if (aim_get_command(gc->oscar_sess, conn) >= 0) {
-				aim_rxdispatch(gc->oscar_sess);
+			if (aim_get_command(odata->sess, conn) >= 0) {
+				aim_rxdispatch(odata->sess);
 			} else {
 				if (conn->type == AIM_CONN_TYPE_RENDEZVOUS &&
 				    conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) {
@@ -216,9 +229,9 @@
 					if (cnv) {
 						make_direct(cnv, FALSE, NULL, 0);
 					}
-					aim_conn_kill(gc->oscar_sess, &conn);
+					aim_conn_kill(odata->sess, &conn);
 				} else if ((conn->type == AIM_CONN_TYPE_BOS) ||
-					   !(aim_getconn_type(gc->oscar_sess, AIM_CONN_TYPE_BOS))) {
+					   !(aim_getconn_type(odata->sess, AIM_CONN_TYPE_BOS))) {
 					debug_print(_("major connection error\n"));
 					hide_login_progress(gc, _("Disconnected."));
 					signoff(gc);
@@ -232,20 +245,20 @@
 						gdk_input_remove(c->inpa);
 					c->inpa = -1;
 					c->fd = -1;
-					aim_conn_kill(gc->oscar_sess, &conn);
+					aim_conn_kill(odata->sess, &conn);
 					sprintf(buf, _("You have been disconnected from chat room %s."), c->name);
 					do_error_dialog(buf, _("Chat Error!"));
 				} else if (conn->type == AIM_CONN_TYPE_CHATNAV) {
-					if (gc->cnpa > -1)
-						gdk_input_remove(gc->cnpa);
-					gc->cnpa = -1;
+					if (odata->cnpa > -1)
+						gdk_input_remove(odata->cnpa);
+					odata->cnpa = -1;
 					debug_print("removing chatnav input watcher\n");
-					aim_conn_kill(gc->oscar_sess, &conn);
+					aim_conn_kill(odata->sess, &conn);
 				} else {
 					sprintf(debug_buff, "holy crap! generic connection error! %d\n",
 							conn->type);
 					debug_print(debug_buff);
-					aim_conn_kill(gc->oscar_sess, &conn);
+					aim_conn_kill(odata->sess, &conn);
 				}
 			}
 		}
@@ -257,6 +270,7 @@
 	struct aim_conn_t *conn;
 	char buf[256];
 	struct gaim_connection *gc = new_gaim_conn(PROTO_OSCAR, user->username, user->password);
+	struct oscar_data *odata = gc->proto_data = g_new0(struct oscar_data, 1);
 
 	sprintf(debug_buff, _("Logging in %s\n"), user->username);
 	debug_print(debug_buff);
@@ -266,7 +280,7 @@
 	/* we need an immediate queue because we don't use a while-loop to
 	 * see if things need to be sent. */
 	sess->tx_enqueue = &aim_tx_enqueue__immediate;
-	gc->oscar_sess = sess;
+	odata->sess = sess;
 
 	sprintf(buf, _("Looking up %s"), FAIM_LOGIN_SERVER);
 	set_login_progress(gc, 1, buf);
@@ -312,18 +326,17 @@
 }
 
 void oscar_close(struct gaim_connection *gc) {
+	struct oscar_data *odata = (struct oscar_data *)gc->proto_data;
 	if (gc->protocol != PROTO_OSCAR) return;
 	if (gc->inpa > 0)
 		gdk_input_remove(gc->inpa);
-	gc->inpa = -1;
-	if (gc->cnpa > 0)
-		gdk_input_remove(gc->cnpa);
-	gc->cnpa = -1;
-	if (gc->paspa > 0)
-		gdk_input_remove(gc->paspa);
-	gc->paspa = -1;
-	aim_logoff(gc->oscar_sess);
-	g_free(gc->oscar_sess);
+	if (odata->cnpa > 0)
+		gdk_input_remove(odata->cnpa);
+	if (odata->paspa > 0)
+		gdk_input_remove(odata->paspa);
+	aim_logoff(odata->sess);
+	g_free(odata->sess);
+	g_free(gc->proto_data);
 	debug_print(_("Signed off.\n"));
 }
 
@@ -420,7 +433,7 @@
 	aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD, gaim_parse_motd, 0);
 
 	aim_auth_sendcookie(sess, bosconn, sess->logininfo.cookie);
-	gc->oscar_conn = bosconn;
+	((struct oscar_data *)gc->proto_data)->conn = bosconn;
 	gc->inpa = gdk_input_add(bosconn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
 			oscar_callback, bosconn);
 	set_login_progress(gc, 4, _("Connection established, cookie sent"));
@@ -489,6 +502,7 @@
 	char *ip;
 	unsigned char *cookie;
 	struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess);
+	struct oscar_data *odata = (struct oscar_data *)gc->proto_data;
 
 	va_start(ap, command);
 	serviceid = va_arg(ap, int);
@@ -503,7 +517,7 @@
 		if (tstconn == NULL || tstconn->status >= AIM_CONN_STATUS_RESOLVERR)
 			debug_print("unable to reconnect with authorizer\n");
 		else {
-			gc->paspa = gdk_input_add(tstconn->fd,
+			odata->paspa = gdk_input_add(tstconn->fd,
 					GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
 					oscar_callback, tstconn);
 			aim_auth_sendcookie(sess, tstconn, cookie);
@@ -519,7 +533,7 @@
 		}
 		aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, gaim_server_ready, 0);
 		aim_auth_sendcookie(sess, tstconn, cookie);
-		gc->cnpa = gdk_input_add(tstconn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
+		odata->cnpa = gdk_input_add(tstconn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
 					oscar_callback, tstconn);
 		}
 		debug_print("chatnav: connected\n");
@@ -545,7 +559,7 @@
 				GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
 				oscar_callback, tstconn);
 
-		gc->oscar_chats = g_slist_append(gc->oscar_chats, ccon);
+		odata->oscar_chats = g_slist_append(odata->oscar_chats, ccon);
 		
 		aim_chat_attachname(tstconn, roomname);
 		aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, gaim_server_ready, 0);
@@ -617,19 +631,21 @@
 	struct aim_conn_t *newconn;
 	struct aim_directim_priv *priv;
 	struct gaim_connection *gc;
+	struct oscar_data *odata;
 	int watcher;
 
 	priv = (struct aim_directim_priv *)gtk_object_get_user_data(GTK_OBJECT(m));
 	gc = (struct gaim_connection *)gtk_object_get_user_data(GTK_OBJECT(w));
+	odata = (struct oscar_data *)gc->proto_data;
 	gtk_widget_destroy(m);
 
-	if (!(newconn = aim_directim_connect(gc->oscar_sess, gc->oscar_conn, priv))) {
+	if (!(newconn = aim_directim_connect(odata->sess, odata->conn, priv))) {
 		debug_print("imimage: could not connect\n");
 		return;
 	}
 
-	aim_conn_addhandler(gc->oscar_sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, gaim_directim_incoming, 0);
-	aim_conn_addhandler(gc->oscar_sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, gaim_directim_typing, 0);
+	aim_conn_addhandler(odata->sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, gaim_directim_incoming, 0);
+	aim_conn_addhandler(odata->sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, gaim_directim_typing, 0);
 
 	watcher = gdk_input_add(newconn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
 				oscar_callback, newconn);
@@ -914,6 +930,7 @@
 	va_list ap;
 	u_short type;
 	struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess);
+	struct oscar_data *odata = (struct oscar_data *)gc->proto_data;
 
 	va_start(ap, command);
 	type = (u_short)va_arg(ap, u_int);
@@ -943,14 +960,14 @@
 				debug_print(debug_buff);
 				i++;
 			}
-			if (gc->create_exchange) {
-				sprintf(debug_buff, "creating room %s\n",
-						gc->create_name);
+			if (odata->create_exchange) {
+				sprintf(debug_buff, "creating room %s\n", odata->create_name);
 				debug_print(debug_buff);
-				aim_chatnav_createroom(sess, command->conn, gc->create_name, gc->create_exchange);
-				gc->create_exchange = 0;
-				g_free(gc->create_name);
-				gc->create_name = NULL;
+				aim_chatnav_createroom(sess, command->conn, odata->create_name,
+						odata->create_exchange);
+				odata->create_exchange = 0;
+				g_free(odata->create_name);
+				odata->create_name = NULL;
 			}
 			}
 			break;
@@ -977,11 +994,11 @@
 			if (flags & 0x4) {
 				sprintf(debug_buff, "joining %s on exchange 5\n", name);
 				debug_print(debug_buff);
-				aim_chat_join(gc->oscar_sess, gc->oscar_conn, 5, ck);
+				aim_chat_join(odata->sess, odata->conn, 5, ck);
 			} else 
 				sprintf(debug_buff, "joining %s on exchange 4\n", name);{
 				debug_print(debug_buff);
-				aim_chat_join(gc->oscar_sess, gc->oscar_conn, 4, ck);
+				aim_chat_join(odata->sess, odata->conn, 4, ck);
 			}
 			}
 			break;
@@ -1302,15 +1319,18 @@
 }
 
 void oscar_do_directim(struct gaim_connection *gc, char *name) {
-	struct aim_conn_t *newconn = aim_directim_initiate(gc->oscar_sess, gc->oscar_conn, NULL, name);
-	struct conversation *cnv = find_conversation(name); /* this will never be null because it just got set up */
+	struct oscar_data *odata = (struct oscar_data *)gc->proto_data;
+	struct aim_conn_t *newconn = aim_directim_initiate(odata->sess, odata->conn, NULL, name);
+	struct conversation *cnv = find_conversation(name); /* this will never be null because
+							       it just got set up */
 	cnv->conn = newconn;
 	cnv->watcher = gdk_input_add(newconn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, oscar_callback, newconn);
-	aim_conn_addhandler(gc->oscar_sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINITIATE, gaim_directim_initiate, 0);
+	aim_conn_addhandler(odata->sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINITIATE, gaim_directim_initiate, 0);
 }
 
 static void oscar_keepalive(struct gaim_connection *gc) {
-	aim_flap_nop(gc->oscar_sess, gc->oscar_conn);
+	struct oscar_data *odata = (struct oscar_data *)gc->proto_data;
+	aim_flap_nop(odata->sess, odata->conn);
 }
 
 static char *oscar_name() {
@@ -1318,100 +1338,114 @@
 }
 
 static void oscar_send_im(struct gaim_connection *gc, char *name, char *message, int away) {
+	struct oscar_data *odata = (struct oscar_data *)gc->proto_data;
 	struct conversation *cnv = find_conversation(name);
 	if (cnv && cnv->is_direct) {
 		debug_printf("Sending DirectIM to %s\n", name);
-		aim_send_im_direct(gc->oscar_sess, cnv->conn, message);
+		aim_send_im_direct(odata->sess, cnv->conn, message);
 	} else {
 		if (away)
-			aim_send_im(gc->oscar_sess, gc->oscar_conn, name, AIM_IMFLAGS_AWAY, message);
+			aim_send_im(odata->sess, odata->conn, name, AIM_IMFLAGS_AWAY, message);
 		else
-			aim_send_im(gc->oscar_sess, gc->oscar_conn, name, AIM_IMFLAGS_ACK, message);
+			aim_send_im(odata->sess, odata->conn, name, AIM_IMFLAGS_ACK, message);
 	}
 }
 
 static void oscar_get_info(struct gaim_connection *g, char *name) {
-	aim_getinfo(g->oscar_sess, g->oscar_conn, name, AIM_GETINFO_GENERALINFO);
+	struct oscar_data *odata = (struct oscar_data *)g->proto_data;
+	aim_getinfo(odata->sess, odata->conn, name, AIM_GETINFO_GENERALINFO);
 }
 
 static void oscar_get_away_msg(struct gaim_connection *g, char *name) {
-	aim_getinfo(g->oscar_sess, g->oscar_conn, name, AIM_GETINFO_AWAYMESSAGE);
+	struct oscar_data *odata = (struct oscar_data *)g->proto_data;
+	aim_getinfo(odata->sess, odata->conn, name, AIM_GETINFO_AWAYMESSAGE);
 }
 
 static void oscar_set_dir(struct gaim_connection *g, char *first, char *middle, char *last,
 			  char *maiden, char *city, char *state, char *country, int web) {
 	/* FIXME : some of these things are wrong, but i'm lazy */
-	aim_setdirectoryinfo(g->oscar_sess, g->oscar_conn, first, middle, last,
+	struct oscar_data *odata = (struct oscar_data *)g->proto_data;
+	aim_setdirectoryinfo(odata->sess, odata->conn, first, middle, last,
 				maiden, NULL, NULL, city, state, NULL, 0, web);
 }
 
 
 static void oscar_set_idle(struct gaim_connection *g, int time) {
-	aim_bos_setidle(g->oscar_sess, g->oscar_conn, time);
+	struct oscar_data *odata = (struct oscar_data *)g->proto_data;
+	aim_bos_setidle(odata->sess, odata->conn, time);
 }
 
 static void oscar_set_info(struct gaim_connection *g, char *info) {
+	struct oscar_data *odata = (struct oscar_data *)g->proto_data;
 	if (awaymessage)
-		aim_bos_setprofile(g->oscar_sess, g->oscar_conn, info,
+		aim_bos_setprofile(odata->sess, odata->conn, info,
 					awaymessage->message, gaim_caps);
 	else
-		aim_bos_setprofile(g->oscar_sess, g->oscar_conn, info,
+		aim_bos_setprofile(odata->sess, odata->conn, info,
 					NULL, gaim_caps);
 }
 
 static void oscar_set_away(struct gaim_connection *g, char *message) {
-	aim_bos_setprofile(g->oscar_sess, g->oscar_conn, g->user_info, message, gaim_caps);
+	struct oscar_data *odata = (struct oscar_data *)g->proto_data;
+	aim_bos_setprofile(odata->sess, odata->conn, g->user_info, message, gaim_caps);
 }
 
 static void oscar_warn(struct gaim_connection *g, char *name, int anon) {
-	aim_send_warning(g->oscar_sess, g->oscar_conn, name, anon);
+	struct oscar_data *odata = (struct oscar_data *)g->proto_data;
+	aim_send_warning(odata->sess, odata->conn, name, anon);
 }
 
 static void oscar_dir_search(struct gaim_connection *g, char *first, char *middle, char *last,
 			     char *maiden, char *city, char *state, char *country, char *email) {
+	struct oscar_data *odata = (struct oscar_data *)g->proto_data;
 	if (strlen(email))
-		aim_usersearch_address(g->oscar_sess, g->oscar_conn, email);
+		aim_usersearch_address(odata->sess, odata->conn, email);
 }
 
 static void oscar_add_buddy(struct gaim_connection *g, char *name) {
-	aim_add_buddy(g->oscar_sess, g->oscar_conn, name);
+	struct oscar_data *odata = (struct oscar_data *)g->proto_data;
+	aim_add_buddy(odata->sess, odata->conn, name);
 }
 
 static void oscar_add_buddies(struct gaim_connection *g, GList *buddies) {
+	struct oscar_data *odata = (struct oscar_data *)g->proto_data;
 	char buf[MSG_LEN];
 	int n = 0;
 	while (buddies) {
 		if (n > MSG_LEN - 18) {
-			aim_bos_setbuddylist(g->oscar_sess, g->oscar_conn, buf);
+			aim_bos_setbuddylist(odata->sess, odata->conn, buf);
 			n = 0;
 		}
 		n += g_snprintf(buf + n, sizeof(buf) - n, "%s&", (char *)buddies->data);
 		buddies = buddies->next;
 	}
-	aim_bos_setbuddylist(g->oscar_sess, g->oscar_conn, buf);
+	aim_bos_setbuddylist(odata->sess, odata->conn, buf);
 }
 
 static void oscar_remove_buddy(struct gaim_connection *g, char *name) {
-	aim_remove_buddy(g->oscar_sess, g->oscar_conn, name);
+	struct oscar_data *odata = (struct oscar_data *)g->proto_data;
+	aim_remove_buddy(odata->sess, odata->conn, name);
 }
 
 static void oscar_join_chat(struct gaim_connection *g, int exchange, char *name) {
+	struct oscar_data *odata = (struct oscar_data *)g->proto_data;
 	struct aim_conn_t *cur = NULL;
 	sprintf(debug_buff, "Attempting to join chat room %s.\n", name);
 	debug_print(debug_buff);
-	if ((cur = aim_getconn_type(g->oscar_sess, AIM_CONN_TYPE_CHATNAV))) {
+	if ((cur = aim_getconn_type(odata->sess, AIM_CONN_TYPE_CHATNAV))) {
 		debug_print("chatnav exists, creating room\n");
-		aim_chatnav_createroom(g->oscar_sess, cur, name, exchange);
+		aim_chatnav_createroom(odata->sess, cur, name, exchange);
 	} else {
 		/* this gets tricky */
 		debug_print("chatnav does not exist, opening chatnav\n");
-		g->create_exchange = exchange;
-		g->create_name = g_strdup(name);
-		aim_bos_reqservice(g->oscar_sess, g->oscar_conn, AIM_CONN_TYPE_CHATNAV);
+		odata->create_exchange = exchange;
+		odata->create_name = g_strdup(name);
+		aim_bos_reqservice(odata->sess, odata->conn, AIM_CONN_TYPE_CHATNAV);
 	}
 }
 
 static void oscar_chat_invite(struct gaim_connection *g, int id, char *message, char *name) {
+	struct oscar_data *odata = (struct oscar_data *)g->proto_data;
 	GSList *bcs = g->buddy_chats;
 	struct conversation *b = NULL;
 
@@ -1426,11 +1460,12 @@
 	if (!b)
 		return;
 
-	aim_chat_invite(g->oscar_sess, g->oscar_conn, name,
+	aim_chat_invite(odata->sess, odata->conn, name,
 			message ? message : "", 0x4, b->name, 0x0);
 }
 
 static void oscar_chat_leave(struct gaim_connection *g, int id) {
+	struct oscar_data *odata = g ? (struct oscar_data *)g->proto_data : NULL;
 	GSList *bcs = g->buddy_chats;
 	struct conversation *b = NULL;
 	struct chat_connection *c = NULL;
@@ -1454,10 +1489,11 @@
 	
 	c = find_oscar_chat(g, b->name);
 	if (c != NULL) {
-		g->oscar_chats = g_slist_remove(g->oscar_chats, c);
+		if (odata)
+			odata->oscar_chats = g_slist_remove(odata->oscar_chats, c);
 		gdk_input_remove(c->inpa);
-		if (g && g->oscar_sess)
-			aim_conn_kill(g->oscar_sess, &c->conn);
+		if (g && odata->sess)
+			aim_conn_kill(odata->sess, &c->conn);
 		g_free(c->name);
 		g_free(c);
 	}
@@ -1471,6 +1507,7 @@
 }
 
 static void oscar_chat_send(struct gaim_connection *g, int id, char *message) {
+	struct oscar_data *odata = (struct oscar_data *)g->proto_data;
 	struct aim_conn_t *cn; 
 	GSList *bcs = g->buddy_chats;
 	struct conversation *b = NULL;
@@ -1485,8 +1522,8 @@
 	if (!b)
 		return;
 
-	cn = aim_chat_getconn(g->oscar_sess, b->name);
-	aim_chat_send_im(g->oscar_sess, cn, message);
+	cn = aim_chat_getconn(odata->sess, b->name);
+	aim_chat_send_im(odata->sess, cn, message);
 }
 
 struct prpl *oscar_init() {
--- a/src/toc.c	Sun Oct 15 02:00:05 2000 +0000
+++ b/src/toc.c	Sun Oct 15 03:50:32 2000 +0000
@@ -40,7 +40,13 @@
 #include "gaim.h"
 #include "gnome_applet_mgr.h"
 
-#define REVISION "gaim:$Revision: 998 $"
+#define REVISION "gaim:$Revision: 1008 $"
+
+struct toc_data {
+	int toc_fd;
+	int seqno;
+	int state;
+};
 
 
 static unsigned int peer_ver=0;
@@ -60,10 +66,12 @@
 	char *config;
         struct in_addr *sin;
 	struct gaim_connection *gc;
+	struct toc_data *tdt;
 	char buf[80];
 	char buf2[2048];
 
 	gc = new_gaim_conn(PROTO_TOC, user->username, user->password);
+	gc->proto_data = tdt = g_new0(struct toc_data, 1);
 	
 	g_snprintf(buf, sizeof(buf), "Looking up %s", aim_host);	
 	set_login_progress(gc, 1, buf);
@@ -86,9 +94,9 @@
 	
 
 
-	gc->toc_fd = connect_address(sin->s_addr, aim_port);
+	tdt->toc_fd = connect_address(sin->s_addr, aim_port);
 
-        if (gc->toc_fd < 0) {
+        if (tdt->toc_fd < 0) {
 		g_snprintf(buf, sizeof(buf), "Connect to %s failed",
 			 inet_ntoa(*sin));
 		hide_login_progress(gc, buf);
@@ -129,7 +137,7 @@
 		gtk_main_iteration();
 
 	config = toc_wait_config(gc);
-	gc->state = STATE_ONLINE;
+	tdt->state = STATE_ONLINE;
 
 	if (mainwindow)
 		gtk_widget_hide(mainwindow);
@@ -176,7 +184,7 @@
         if (gc->inpa > 0)
 		gdk_input_remove(gc->inpa);
 	gc->inpa = -1;
-	close(gc->toc_fd);
+	close(((struct toc_data *)gc->proto_data)->toc_fd);
 }
 
 unsigned char *roast_password(char *pass)
@@ -224,6 +232,7 @@
 	int slen=0;
 	struct sflap_hdr hdr;
 	char obuf[MSG_LEN];
+	struct toc_data *tdt = (struct toc_data *)gc->proto_data;
 
 	/* One _last_ 2048 check here!  This shouldn't ever
 	 * get hit though, hopefully.  If it gets hit on an IM
@@ -242,7 +251,7 @@
 		len = olen;
 	hdr.ast = '*';
 	hdr.type = type;
-	hdr.seqno = htons(gc->seqno++ & 0xffff);
+	hdr.seqno = htons(tdt->seqno++ & 0xffff);
         hdr.len = htons(len + (type == TYPE_SIGNON ? 0 : 1));
 
     sprintf(debug_buff,"Escaped message is '%s'\n",buf);
@@ -258,7 +267,7 @@
 	}
 	print_buffer(obuf, slen);
 
-	return write(gc->toc_fd, obuf, slen);
+	return write(tdt->toc_fd, obuf, slen);
 }
 
 
@@ -267,6 +276,7 @@
         size_t res=-1;
 	int read_rv = -1;
 	struct sflap_hdr *hdr=(struct sflap_hdr *)buffer;
+	struct toc_data *tdt = (struct toc_data *)gc->proto_data;
         char *c;
 
 	if(buflen < sizeof(struct sflap_hdr)) {
@@ -275,7 +285,7 @@
 	    return -1;
 	}
 
-        while((read_rv = read(gc->toc_fd, buffer, 1))) {
+        while((read_rv = read(tdt->toc_fd, buffer, 1))) {
 		if (read_rv < 0 || read_rv > 1)
 			return -1;
 		if (buffer[0] == '*')
@@ -283,7 +293,7 @@
 
 	}
 
-	read_rv = read(gc->toc_fd, buffer+1, sizeof(struct sflap_hdr) - 1);
+	read_rv = read(tdt->toc_fd, buffer+1, sizeof(struct sflap_hdr) - 1);
 
         if (read_rv < 0)
 		return read_rv;
@@ -302,7 +312,7 @@
 	}
 
         while (res < (sizeof(struct sflap_hdr) + ntohs(hdr->len))) {
-		read_rv = read(gc->toc_fd, buffer + res, (ntohs(hdr->len) + sizeof(struct sflap_hdr)) - res);
+		read_rv = read(tdt->toc_fd, buffer + res, (ntohs(hdr->len) + sizeof(struct sflap_hdr)) - res);
 		if(read_rv < 0) return read_rv;
 		res += read_rv;
 		/* my feeling is this will kill us. if there's data pending then we'll come right back
@@ -322,14 +332,14 @@
 	case TYPE_SIGNON:
 		memcpy(&peer_ver, buffer + sizeof(struct sflap_hdr), 4);
 		peer_ver = ntohl(peer_ver);
-		gc->seqno = ntohs(hdr->seqno);
-		gc->state = STATE_SIGNON_REQUEST;
+		tdt->seqno = ntohs(hdr->seqno);
+		tdt->state = STATE_SIGNON_REQUEST;
 		break;
 	case TYPE_DATA:
 		if (!strncasecmp(buffer + sizeof(struct sflap_hdr), "SIGN_ON:", strlen("SIGN_ON:")))
-			gc->state = STATE_SIGNON_ACK;
+			tdt->state = STATE_SIGNON_ACK;
 		else if (!strncasecmp(buffer + sizeof(struct sflap_hdr), "CONFIG:", strlen("CONFIG:"))) {
-			gc->state = STATE_CONFIG;
+			tdt->state = STATE_CONFIG;
 		} else if (!strncasecmp(buffer + sizeof(struct sflap_hdr), "ERROR:", strlen("ERROR:"))) {
 			c = strtok(buffer + sizeof(struct sflap_hdr) + strlen("ERROR:"), ":");
 			show_error_dialog(c);
@@ -702,21 +712,22 @@
 	char buf[BUF_LONG];
 	int res;
 	struct signon so;
+	struct toc_data *tdt = (struct toc_data *)gc->proto_data;
 
-        sprintf(debug_buff,"State = %d\n", gc->state);
+        sprintf(debug_buff,"State = %d\n", tdt->state);
 	debug_print(debug_buff);
 
-	if ((res = write(gc->toc_fd, FLAPON, strlen(FLAPON))) < 0)
+	if ((res = write(tdt->toc_fd, FLAPON, strlen(FLAPON))) < 0)
 		return res;
 	/* Wait for signon packet */
 
-	gc->state = STATE_FLAPON;
+	tdt->state = STATE_FLAPON;
 
 	if ((res = wait_reply(gc, buf, sizeof(buf)) < 0))
 		return res;
 	
-	if (gc->state != STATE_SIGNON_REQUEST) {
-			sprintf(debug_buff, "State should be %d, but is %d instead\n", STATE_SIGNON_REQUEST, gc->state);
+	if (tdt->state != STATE_SIGNON_REQUEST) {
+			sprintf(debug_buff, "State should be %d, but is %d instead\n", STATE_SIGNON_REQUEST, tdt->state);
 			debug_print(debug_buff);
 			return -1;
 	}
@@ -743,13 +754,14 @@
 int toc_wait_signon(struct gaim_connection *gc)
 {
 	/* Wait for the SIGNON to be approved */
+	struct toc_data *tdt = (struct toc_data *)gc->proto_data;
 	char buf[BUF_LONG];
 	int res;
 	res = wait_reply(gc, buf, sizeof(buf));
 	if (res < 0)
 		return res;
-	if (gc->state != STATE_SIGNON_ACK) {
-			sprintf(debug_buff, "State should be %d, but is %d instead\n",STATE_SIGNON_ACK, gc->state);
+	if (tdt->state != STATE_SIGNON_ACK) {
+			sprintf(debug_buff, "State should be %d, but is %d instead\n",STATE_SIGNON_ACK, tdt->state);
 			debug_print(debug_buff);
 		return -1;
 	}
@@ -785,6 +797,7 @@
 char *toc_wait_config(struct gaim_connection *gc)
 {
 	/* Waits for configuration packet, returning the contents of the packet */
+	struct toc_data *tdt = (struct toc_data *)gc->proto_data;
 	static char buf[BUF_LONG];
 	int res;
 	res = wait_reply(gc, buf, sizeof(buf));
@@ -792,17 +805,17 @@
 		return NULL;
 /* Apparently, the toc_config is optional.  *VERY* Optional
 */
-	if (gc->state != STATE_CONFIG) {
+	if (tdt->state != STATE_CONFIG) {
 		res = 0;
 	} else {
 		res = 1;
 	}
 	/* At this point, it's time to setup automatic handling of incoming packets */
-	gc->state = STATE_ONLINE;
+	tdt->state = STATE_ONLINE;
 #ifdef _WIN32
 	win32_r = gtk_timeout_add(1000, (GtkFunction)win32_read, NULL);
 #else
-	gc->inpa = gdk_input_add(gc->toc_fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, toc_callback, gc);
+	gc->inpa = gdk_input_add(tdt->toc_fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, toc_callback, gc);
 #endif
 	if (res)
 		return buf;