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...