TOC plugin

"A. Craig West" <[email protected]> Mon, 10 May 2004 17:22:44 -0400 (EDT)
Newsgroups gmane.network.everybuddy.devel
Message-ID <[email protected]>
As promised, here are my nifty new toc patches relative to the head of
subversion. This change makes all socket connections asyncronous, which works
much better than syncronous now, and it re-organizes the code to more closely
follow the structure of the MSN and Yahoo code.

---------- patch begins -----------
Index: plugins/toc/libtoc.h
===================================================================
--- plugins/toc/libtoc.h	(revision 353)
+++ plugins/toc/libtoc.h	(working copy)
@@ -65,8 +65,8 @@
 extern void (*toc_user_info)(toc_conn  * conn, char * user, char * message );
 
 void toc_callback( toc_conn * conn );
-toc_conn * toc_signon( char * username, char * password,
-		char * server, short port, char * info );
+void toc_signon( char * username, char * password,
+		char * server, short port, char * info, void (*callback)(void * data, toc_conn * conn), void * data);
 void toc_send_keep_alive( toc_conn * conn );
 void toc_signoff( toc_conn * conn );
 void toc_send_im( toc_conn * conn, char * username, char * message );
Index: plugins/toc/toc.c
===================================================================
--- plugins/toc/toc.c	(revision 353)
+++ plugins/toc/toc.c	(working copy)
@@ -35,6 +35,9 @@
 
 int eb_toc_init(void);
 int eb_toc_finish(void);
+void eb_toc_login(eb_local_account * ela);
+void eb_toc_logout(eb_local_account * ela);
+void eb_toc_disconnect (toc_conn * conn);
 
 eb_plugin_info toc_LTX_plugin_info={"AIM/ICQ via TOC", "Torrey Searle's libtoc", "Who knows?", "Who cares?", eb_toc_init, eb_toc_finish};
 
@@ -94,85 +97,144 @@
 void eb_toc_set_state(eb_local_account * ela, char * state)
 {
   eb_toc_lad * lad=GET_LAD(ela);
+  char * st_str = NULL;
 
-  if(!strcmp(state, "Online") || !strcmp(state, "Away"))
+  if(!strcmp(state, "Offline"))
   {
-    if(ela->connected)
+    eb_toc_logout(ela);
+    return;
+  }
+  else
+  {
+    /* Check if we are connected yet */
+    if (!ela->connected)
     {
-      if(ela->ready && state[0]=='A' && !lad->away)
+      /* connect to the server */
+      eb_toc_login(ela);
+    }
+    else if (ela->ready)
+    {
+      /* Only set the away message if the connection is ready */
+
+      if(!strcmp(state, "Online"))
       {
-        toc_set_away(lad->conn, "This user is away.");
-        lad->away=1;
-        free(ela->status_string);
-        ela->status_string=strdup("Away");
+	if (lad->away)
+	{
+	  toc_set_away(lad->conn, NULL);
+	  lad->away = 0;
+	}
       }
+      else
+      {
+	/* when changing the away message, need to change to not away first */
+        if (lad->away)
+	{
+	  toc_set_away(lad->conn, NULL);
+	}
+	else
+	{
+	  lad->away = 1;
+	}
 
-      if(ela->ready && state[0]=='O' && lad->away)
-      {
-        toc_set_away(lad->conn, NULL);
-        lad->away=0;
-        free(ela->status_string);
-        ela->status_string=strdup("Online");
+	if(!strcmp(state, "Away"))
+	{
+	  toc_set_away(lad->conn, "This user is away.");
+	}
+	else
+	{
+	  toc_set_away(lad->conn, state);
+	}
       }
 
+      free(ela->status_string);
+      ela->status_string = strdup(state);
       eb_local_account_update(ela);
-      return;
     }
+  }
+}
 
-    ela->connected=1;
-    eb_local_account_update(ela);
+void eb_toc_signon_cb(void * data, toc_conn * conn)
+{
+  eb_local_account * ela = data;
 
-    lad->conn=toc_signon(ela->handle, eb_get_value(ela->config_key, "password"),
-      eb_get_value(ela->config_key, "toc/server"), atoi(eb_get_value(ela->config_key, "toc/port")),
-      eb_get_value(ela->config_key, "user_info"));
+  eb_toc_lad * lad = GET_LAD(ela);
 
-    if(lad->conn==NULL)
-    {
-      eb_show_error("Could not log into TOC server. Check your preferences and try again.", "Connection failed");
-      ela->connected=0;
-      eb_local_account_update(ela);
-      return;
-    }
+  if (lad == NULL)
+  {
+    if (conn)
+      free(conn);
+    return;
+  }
 
-    lad->fd_tag=eb_input_add(lad->conn->fd, EB_INPUT_READ|EB_INPUT_EXCEPTION, eb_toc_callback, lad->conn);
-
-    lad->conn->account=ela;
-
-    ela->ready=1;
-    if(state[0]=='A')
-    {
-      toc_set_away(lad->conn, "This user is away");
-      lad->away=1;
-      free(ela->status_string);
-      ela->status_string=strdup("Away");
-    } else {
-      free(ela->status_string);
-      ela->status_string=strdup("Online");
-    }
+  if (conn == NULL)
+  {
+    eb_show_error("Could not log into TOC server. Check your preferences and try again.", "Connection failed");
+    ela->connected = ela->ready = 0;
     eb_local_account_update(ela);
     return;
   }
 
-  if(!strcmp(state, "Offline"))
-  {
-    if(!ela->connected) { return; }
+  lad->conn = conn;
 
-    toc_signoff(lad->conn);
-    eb_local_account_update(ela);
-  }
+  lad->conn->account = ela;
+
+  lad->fd_tag = eb_input_add(lad->conn->fd, EB_INPUT_READ|EB_INPUT_EXCEPTION, eb_toc_callback, lad->conn);
+
+  ela->ready = 1;
+  eb_toc_set_state(ela, "Online");
 }
 
 void eb_toc_login(eb_local_account * ela)
 {
-  if(atoi(eb_get_value(ela->config_key, "excl_soa")))
+  eb_toc_lad * lad = GET_LAD(ela);
+
+  if (atoi(eb_get_value(ela->config_key, "excl_soa")))
   { return; }
 
-  eb_toc_set_state(ela, "Online");
+  ela->connected = 1;
+  ela->ready = 0;
+  eb_local_account_update(ela);
+
+  if (lad->conn != NULL)
+  {
+    eb_toc_disconnect(lad->conn);
+  }
+
+  toc_signon(ela->handle, eb_get_value(ela->config_key, "password"),
+    eb_get_value(ela->config_key, "toc/server"), atoi(eb_get_value(ela->config_key, "toc/port")),
+    eb_get_value(ela->config_key, "user_info"), eb_toc_signon_cb, ela);
 }
 
 void eb_toc_logout(eb_local_account * ela)
 {
-  eb_toc_set_state(ela, "Offline");
+  EList * en;
+  eb_toc_lad * lad = GET_LAD(ela);
+
+  if (!ela->connected)
+    return;
+
+  for (en = ela->buddies; en != NULL; en = en->next)
+  {
+    eb_account * acc = (eb_account *)en->data;
+    if (acc->status != EB_ACCOUNT_OFFLINE)
+    {
+      free(acc->status_string);
+      acc->status_string = strdup("Offline");
+      acc->status = EB_ACCOUNT_OFFLINE;
+      eb_buddy_update_status(acc);
+      eb_buddy_logout(acc);
+    }
+  }
+
+  free(ela->status_string);
+  ela->status_string = strdup("Offline");
+  ela->ready = ela->connected = 0;
+  eb_local_account_update(ela);
+  if (lad->conn != NULL)
+  {
+    eb_toc_disconnect(lad->conn);
+  }
+  lad->away=0;
 }
 
 void eb_toc_setup_local_account(eb_local_account * ela)
@@ -273,33 +335,12 @@
 
 void eb_toc_set_away(eb_local_account * ela, char * short_msg, char * long_msg)
 {
-  eb_toc_lad * lad=GET_LAD(ela);
-
-  if(lad->away)
-  { toc_set_away(lad->conn, NULL); }
-
-  toc_set_away(lad->conn, long_msg);
-
-  free(ela->status_string);
-  ela->status_string=strdup("Away");
-  eb_local_account_update(ela);
-
-  lad->away=1;
+  eb_toc_set_state(ela, long_msg);
 }
 
 void eb_toc_unset_away(eb_local_account * ela)
 {
-  eb_toc_lad * lad=GET_LAD(ela);
-
-  if(lad->away)
-  {
-    toc_set_away(lad->conn, NULL);
-    lad->away=0;
-
-    free(ela->status_string);
-    ela->status_string=strdup("Online");
-    eb_local_account_update(ela);
-  }
+  eb_toc_set_state(ela, "Online");
 }
 
 void eb_toc_join_group_chat(eb_local_account * ela, char * name)
@@ -427,54 +468,84 @@
 void eb_toc_update_user_status (toc_conn * conn, char * user, int online, time_t idle, int evil, int unavailable )
 {
   eb_local_account * ela=GET_ELA(conn);
-  eb_account * acc=eb_toc_get_account(ela, user);
+  eb_account * acc;
   char buf[64];
-  char buf2[32];
+  char buf2[64];
+  int do_login = 0;
+  int do_logout = 0;
 
-  if(acc==NULL)
+  if (ela == NULL)
   {
     printf("Martian buddy update (%s)\n", user);
     return;
   }
 
-  if(acc->status!=EB_ACCOUNT_OFFLINE && !online)
-  { eb_buddy_logout(acc); return; }
+  acc = eb_toc_get_account(ela, user);
+  if (acc == NULL)
+  {
+    acc = eb_add_account_plus("Unknown", user, ela, user);
+  }
 
-  if(acc->status==EB_ACCOUNT_OFFLINE && online)
-  { eb_buddy_login(acc); }
+  if (acc->status == EB_ACCOUNT_OFFLINE)
+  {
+    do_login = 1;
+  }
 
-  buf[0]='\0';
-  if(idle>0)
+  free(acc->status_string);
+  if (online)
   {
-    int mins=(time(NULL)-idle)/60;
-    buf[0]='(';
-    buf[1]='\0';
+    if (unavailable)
+    {
+      acc->status = EB_ACCOUNT_AWAY;
+      sprintf(buf, "Away");
+    }
+    else
+    {
+      acc->status = EB_ACCOUNT_ONLINE;
+      sprintf(buf, "");
+    }
 
-    if(mins/(60*24))
+    if (idle > 0)
     {
-      sprintf(buf2, "%d:", mins/(60*24));
+      int mins = (time(NULL) - idle) / 60;
+      strcat(buf, "(");
+
+      if (mins / (60 * 24))
+      {
+	sprintf(buf2, "%d:", mins / (60 * 24));
+	strcat(buf, buf2);
+	mins %= (60 * 24);
+      }
+
+      sprintf(buf2, "%d:%02d)", mins / 60, mins % 60);
       strcat(buf, buf2);
-      mins%=(60*24);
     }
 
-    sprintf(buf2, "%d:%02d)", mins/60, mins%60);
-    strcat(buf, buf2);
+    if (evil)
+    {
+      sprintf(buf2, " [%d%%]", evil);
+      strcat(buf, buf2);
+    }
+
+    acc->status_string = strdup(buf);
   }
+  else
+  {
+    acc->status = EB_ACCOUNT_OFFLINE;
+    acc->status_string = strdup("Offline");
+    do_login = 0;
+    do_logout = 1;
+  }
 
-  if(evil)
+  if (do_login)
   {
-    char buf2[32];
-    sprintf(buf2, " [%d%%]", evil);
-    strcat(buf, buf2);
+    eb_buddy_login(acc);
   }
-
-  if(unavailable)
-  { acc->status=EB_ACCOUNT_AWAY; } else { acc->status=EB_ACCOUNT_ONLINE; }
-
-  free(acc->status_string);
-  acc->status_string=strdup(buf);
-
   eb_buddy_update_status(acc);
+  if (do_logout)
+  {
+    eb_buddy_logout(acc);
+  }
 }
 
 void eb_toc_error_message(char * message)
@@ -485,36 +556,28 @@
 void eb_toc_disconnect (toc_conn * conn)
 {
   eb_local_account * ela=GET_ELA(conn);
+  eb_toc_lad * lad;
   EList * n;
 
-  if(ela==NULL) { return; }
+  if (conn == NULL)
+    return;
 
-  if(ela->connected)
+  if (ela == NULL)
   {
-    ela->connected=0;
-    toc_signoff(conn);
   } else {
-    printf("I'm going all loopy...\n");
-  }
+    lad=GET_LAD(ela);
 
-  GET_LAD(ela)->away=0;
+    lad->conn = NULL; /* Make sure that logout doesn't try to call us */
 
-  ela->connected=0;
-  ela->ready=0;
-  GET_LAD(ela)->conn=NULL;
-  free(ela->status_string);
-  ela->status_string=strdup("Offline");
-  eb_input_remove(GET_LAD(ela)->fd_tag);
-
-  for(n=ela->buddies; n!=NULL; n=n->next)
-  {
-    eb_account * a=(eb_account *)n->data;
-
-    if(a->status!=EB_ACCOUNT_OFFLINE)
-    { eb_buddy_logout(a); }
+    if(ela->connected)
+    {
+      eb_toc_logout(ela);
+    }
+    eb_input_remove(lad->fd_tag);
   }
 
-  eb_local_account_update(ela);
+  toc_signoff(conn);
+  free(conn);
 }
 
 void eb_toc_join_ack (toc_conn * conn, char * id, char * name)
Index: plugins/toc/libtoc.c
===================================================================
--- plugins/toc/libtoc.c	(revision 353)
+++ plugins/toc/libtoc.c	(working copy)
@@ -501,119 +501,142 @@
 	}
 }
 
-void toc_get_file( char * ip, short port, char * cookie, char * filename )
+struct get_file_callback_data
 {
-		int fd;
-		char buff[2048];
-		char buff2[7];
+	char *cookie;
+	char *filename;
+};
 
-		FILE * file;
+void toc_get_file_callback(int fd, void *data)
+{
+	struct get_file_callback_data * cbd = data;
+	char buff[2048];
+	char buff2[7];
+	FILE * file;
+	toc_file_conn * conn = new0( toc_file_conn, 1 );
 
-		toc_file_conn * conn = new0( toc_file_conn, 1 );
+	typedef struct _file_header
+	{
+		short magic;
+		char cookie[8];
+		short encryption;
+		short compression;
+		short total_num_files;
+		short total_num_files_left;
+		short total_num_parts;
+		short total_num_parts_left;
+		long total_file_size;
+		long file_size;
+		long modified_time;
+		long checksum;
+		long res_fork_checksum;
+		long res_fork_size;
+		long creation_time;
+		long res_fork_checksum2;
+		long num_recieved;
+		long recieved_checksum;
+		char id_string[32];
+		char flags;
+		char list_name_offset;
+		char list_size_offset;
+		char dummy[69];
+		char mac_file_info[16];
+		short name_encoding;
+		short name_language;
+	} file_header;
 
+	file_header * fh = (file_header *)buff;
+	short header_size;
+	char * cookie2 = base64_decode(cbd->cookie);
 
-		typedef struct _file_header
-		{
-			short magic;
-			char cookie[8];
-			short encryption;
-			short compression;
-			short total_num_files;
-			short total_num_files_left;
-			short total_num_parts;
-			short total_num_parts_left;
-			long total_file_size;
-			long file_size;
-			long modified_time;
-			long checksum;
-			long res_fork_checksum;
-			long res_fork_size;
-			long creation_time;
-			long res_fork_checksum2;
-			long num_recieved;
-			long recieved_checksum;
-			char id_string[32];
-			char flags;
-			char list_name_offset;
-			char list_size_offset;
-			char dummy[69];
-			char mac_file_info[16];
-			short name_encoding;
-			short name_language;
-		} file_header;
-
-		file_header * fh = (file_header *)buff;
-		short header_size;
-		char * cookie2 = base64_decode(cookie);
-		int i;
-
-		for( i = 0; (fd = eb_connect_sync_socket(ip, port)) < 0 && i < 10; i++ );
-
-
+	if (fd < 0)
+	{
 #ifdef DEBUG
-		fprintf(stderr, "connected to %s\n", ip );
+		fprintf(stderr, "error connecting to get file: %s\n", cbd->filename);
 #endif
+		free(cbd->cookie);
+		free(cbd->filename);
+		free(cbd);
 
-		recv( fd, buff2, 6, 0 );
-		buff2[6] = '\0';
-		header_size =ntohs(*((short*)(buff2+4)));
+		return;
+	}
 
+	recv(fd, buff2, 6, 0);
+	buff2[6] = '\0';
+	header_size = ntohs(*((short*)(buff2+4)));
+
 #ifdef DEBUG
-		fprintf(stderr, "header_size = %d\n", header_size );
+	fprintf(stderr, "header_size = %d\n", header_size);
 #endif
 
-		recv( fd, buff, header_size - 6, 0 );
+	recv(fd, buff, header_size - 6, 0);
 
-		if( fh->magic != 0x0101 )
-		{
+	if (fh->magic != 0x0101)
+	{
 #ifdef DEBUG
-			fprintf(stderr, "bad magic number %x\n", fh->magic );
+		fprintf(stderr, "bad magic number %x\n", fh->magic);
 #endif
-			close(fd);
-			return;
-		}
+		close(fd);
+		free(cbd->cookie);
+		free(cbd->filename);
+		free(cbd);
+		return;
+	}
 
 #ifdef DEBUG
-		fprintf( stderr, "magic = %04x\n", fh->magic );
+	fprintf(stderr, "magic = %04x\n", fh->magic);
 #endif
 
-		fh->magic = htons(0x0202);
-		memcpy(fh->cookie, cookie2, 8);
-		free(cookie2);
+	fh->magic = htons(0x0202);
+	memcpy(fh->cookie, cookie2, 8);
+	free(cookie2);
 #ifdef DEBUG
-		fprintf(stderr, "id_string = %s\n", buff + 62 );
-		fprintf(stderr, "file_name = %s\n", buff + 186 );
+	fprintf(stderr, "id_string = %s\n", buff + 62);
+	fprintf(stderr, "file_name = %s\n", buff + 186);
 #endif
-		memset(buff + 62, 0, 32);
-		strcpy(buff + 62, "TIK");
-		fh->encryption = 0;
-		fh->compression = 0;
-		fh->total_num_parts = htons(1);
-		fh->total_num_parts_left = htons(1);
+	memset(buff + 62, 0, 32);
+	strcpy(buff + 62, "TIK");
+	fh->encryption = 0;
+	fh->compression = 0;
+	fh->total_num_parts = htons(1);
+	fh->total_num_parts_left = htons(1);
 
 #ifdef DEBUG
-		fprintf(stderr, "total_num_parts = %04x total_num_parts_left = %04x file_size = %ld\n",
-		fh->total_num_parts, fh->total_num_parts_left, ntohl(*((long*)(buff+22))));
+	fprintf(stderr, "total_num_parts = %04x total_num_parts_left = %04x file_size = %ld\n",
+	fh->total_num_parts, fh->total_num_parts_left, ntohl(*((long*)(buff+22))));
 
 #endif
 
-		send( fd, buff2, 6, 0 );
-		send( fd, buff, header_size - 6, 0 );
+	send(fd, buff2, 6, 0);
+	send(fd, buff, header_size - 6, 0);
 
-		file = fopen( filename, "w" );
+	file = fopen(cbd->filename, "w");
 
-		memcpy(conn->header1, buff2, 7 );
-		memcpy(conn->header2, buff, 2048 );
-		conn->fd = fd;
-		conn->amount = 0;
-		conn->file = file;
+	memcpy(conn->header1, buff2, 7 );
+	memcpy(conn->header2, buff, 2048 );
+	conn->fd = fd;
+	conn->amount = 0;
+	conn->file = file;
 
-		conn->progress = toc_begin_file_recieve( filename,  ntohl(*((long*)(buff+22))) );
+	conn->progress = toc_begin_file_recieve(cbd->filename,  ntohl(*((long*)(buff+22))));
 
-		conn->handle = eb_input_add(fd, EB_INPUT_READ, toc_get_file_data, conn);
+	conn->handle = eb_input_add(fd, EB_INPUT_READ, toc_get_file_data, conn);
 
+	free(cbd->cookie);
+	free(cbd->filename);
+	free(cbd);
 }
 
+void toc_get_file(char * ip, short port, char * cookie, char * filename)
+{
+	int fd;
+	struct get_file_callback_data * cbd = new0(struct get_file_callback_data, 1);
+	cbd->cookie = strdup(cookie);
+	cbd->filename = strdup(filename);
+
+	fd = eb_connect_socket(ip, port, toc_get_file_callback, cbd);
+}
+
 void toc_get_talk( char * ip, short port, char * cookie )
 {
 //		int fd;
@@ -1212,14 +1235,24 @@
 	return c - a + b + 71665152;
 }
 
+struct connected_data
+{
+	void (*callback)(void * data, toc_conn * conn);
+	void * callback_data;
+	char * username;
+	char * password;
+	char * server;
+	short port;
+	char * tinfo;
 
+};
 
-toc_conn * toc_signon( char * username, char * password,
-		    char * server, short port, char * tinfo )
+void toc_connected(int fd, void *data)
 {
+	struct connected_data * cd = data;
 	fd_set fs;
+	char *flap_result = NULL;
 	toc_conn * conn = new0(toc_conn, 1);
-	char *flap_result=NULL;
 
 	/*
 	 *     4 byte FLAP version (1)
@@ -1231,48 +1264,61 @@
 	char buff[2048];
 
 
-	char * normalized_username = aim_normalize(username);
+	char * normalized_username = aim_normalize(cd->username);
 	unsigned short username_length = htons(strlen(normalized_username));
 //	char * c;
 
 	flap_header fh;
 
+	if (fd < 0) // error connecting
+	{
+		(cd->callback)(cd->callback_data, NULL); // Signal error
+		free(cd->username);
+		free(cd->password);
+		free(cd->server);
+		free(cd->tinfo);
+		free(cd);
+		free(conn);
+
+		return;
+	}
+
         // HACK ALERT begin user info hack
-        info=strdup(tinfo);
+        info=strdup(cd->tinfo);
         // end hack (user info)
 
-	strcpy(conn->server, server);
-	conn->port = port;
+	strncpy(conn->server, cd->server, sizeof(conn->server));
+	conn->server[sizeof(conn->server) - 1] = '\0';
+	conn->port = cd->port;
+	conn->fd = fd;
 
-
-	conn->fd = eb_connect_sync_socket(server, port);
-
-	if ( conn->fd <= 0 )
-	{
-		free(conn);
-		return NULL;
-	}
-
 	/* Client sends "FLAPON\r\n\r\n" */
 
-	write(conn->fd, "FLAPON\r\n\n\0", 10);
+	write(fd, "FLAPON\r\n\n\0", 10);
 
 	/* TOC sends Client FLAP SIGNON */
 
 	FD_ZERO(&fs);
-	FD_SET(conn->fd, &fs);
+	FD_SET(fd, &fs);
 
-	//select(conn->fd+1, &fs, NULL, NULL, NULL );
+	//select(fd+1, &fs, NULL, NULL, NULL );
 
-	flap_result=get_flap(conn);
-	if(flap_result)
-		memcpy( buff, flap_result,10);
+	flap_result = get_flap(conn);
+	if (flap_result)
+		memcpy(buff, flap_result, 10);
 	else
 	{
 #ifdef DEBUG
 		fprintf(stderr, "Error!  get_flap failed\n");
 #endif
-		return NULL;
+		(cd->callback)(cd->callback_data, NULL); // Signal error
+		free(cd->username);
+		free(cd->password);
+		free(cd->server);
+		free(cd->tinfo);
+		free(cd);
+
+		return;
 	}
 
 	buff[10] = 0;
@@ -1283,14 +1329,14 @@
 	fh.ast = '*';
 	fh.type = 1;
 	fh.seq = htons(conn->seq_num++);
-	fh.len = htons((short)(strlen(normalized_username)+8));
+	fh.len = htons((short)(strlen(normalized_username) + 8));
 
 	memcpy(buff, &fh, sizeof(flap_header));
-	memcpy(buff+6, sflap_header, 6);
-	memcpy(buff+12,&username_length,2);
-	memcpy(buff+14,normalized_username, strlen(normalized_username));
+	memcpy(buff + 6, sflap_header, 6);
+	memcpy(buff + 12, &username_length, 2);
+	memcpy(buff + 14, normalized_username, strlen(normalized_username));
 
-	write(conn->fd, buff, strlen(normalized_username)+14);
+	write(fd, buff, strlen(normalized_username) + 14);
 
 	/* Client sends TOC "toc_signon" message */
 
@@ -1301,21 +1347,41 @@
 	 */
 
 	snprintf(buff, 2048, "toc2_signon %s %d %s %s %s \"%s\" 160 %d",
-			"login.oscar.aol.com", 29999, normalized_username, roast_password(password),
+			"login.oscar.aol.com", 29999, normalized_username, roast_password(cd->password),
 			"english-US", REVISION,
-			generate_code(normalized_username, password) );
+			generate_code(normalized_username, cd->password));
 
-	send_flap(conn, DATA, buff );
+	send_flap(conn, DATA, buff);
 
 #ifdef DEBUG
-	printf( "toc_signon AFTER %d %d\n", conn->fd, conn->seq_num );
+	printf("toc_signon AFTER %d %d\n", fd, conn->seq_num);
 #endif
 
-	return conn;
+	(cd->callback)(cd->callback_data, conn); // Signal completion
 
+	free(cd->username);
+	free(cd->password);
+	free(cd->server);
+	free(cd->tinfo);
+	free(cd);
 }
 
+void toc_signon(char * username, char * password,
+		    char * server, short port, char * tinfo, void (*callback)(void * data, toc_conn * conn), void * data)
+{
+	int fd;
+	struct connected_data * cd = new0(struct connected_data, 1);
+	cd->callback = callback;
+	cd->callback_data = data;
+	cd->username = strdup(username);
+	cd->password = strdup(password);
+	cd->server = strdup(server);
+	cd->port = port;
+	cd->tinfo = strdup(tinfo);
 
+	fd = eb_connect_socket(server, port, toc_connected, cd);
+}
+
 void toc_signoff( toc_conn * conn )
 {
 	if (!conn)
---------- patch ends -----------

-- 
Craig West         Ph: (416) 666-1645	|  It's not a bug,
[email protected]              	|  It's a feature...