diff -P -c -r gaim-1.1.0/src/protocols/Makefile.am gaim-1.1.0n/src/protocols/Makefile.am
*** gaim-1.1.0/src/protocols/Makefile.am	Sun May  2 19:57:10 2004
--- gaim-1.1.0n/src/protocols/Makefile.am	Tue Dec  7 14:12:36 2004
***************
*** 1,3 ****
! DIST_SUBDIRS = gg irc jabber msn napster novell oscar rendezvous silc toc trepia yahoo zephyr
  
  SUBDIRS = $(DYNAMIC_PRPLS) $(STATIC_PRPLS)
--- 1,3 ----
! DIST_SUBDIRS = gg irc jabber msn napster novell oscar rendezvous silc toc trepia yahoo zephyr tsn
  
  SUBDIRS = $(DYNAMIC_PRPLS) $(STATIC_PRPLS)
diff -P -c -r gaim-1.1.0/src/protocols/tsn/Makefile.am gaim-1.1.0n/src/protocols/tsn/Makefile.am
*** gaim-1.1.0/src/protocols/tsn/Makefile.am	Thu Jan  1 01:00:00 1970
--- gaim-1.1.0n/src/protocols/tsn/Makefile.am	Mon Dec 13 11:36:55 2004
***************
*** 0 ****
--- 1,30 ----
+ EXTRA_DIST = \
+ 		Makefile.mingw
+ 
+ pkgdir = $(libdir)/gaim
+ 
+ TSNSOURCES = tsn.c
+ 
+ libtsn_la_LDFLAGS = -module -avoid-version
+ 
+ if STATIC_TSN
+ 
+ st = -DGAIM_STATIC_PRPL
+ noinst_LIBRARIES = libtsn.a
+ libtsn_a_SOURCES = $(TSNSOURCES)
+ libtsn_a_CFLAGS  = $(AM_CFLAGS)
+ 
+ else
+ 
+ st =
+ pkg_LTLIBRARIES   = libtsn.la
+ libtsn_la_SOURCES = $(TSNSOURCES)
+ 
+ endif
+ 
+ AM_CFLAGS = $(st)
+ 
+ AM_CPPFLAGS = \
+ 	-I$(top_srcdir)/src \
+ 	$(GLIB_CFLAGS) \
+ 	$(DEBUG_CFLAGS)
diff -P -c -r gaim-1.1.0/src/protocols/tsn/Makefile.mingw gaim-1.1.0n/src/protocols/tsn/Makefile.mingw
*** gaim-1.1.0/src/protocols/tsn/Makefile.mingw	Thu Jan  1 01:00:00 1970
--- gaim-1.1.0n/src/protocols/tsn/Makefile.mingw	Mon Dec 13 11:36:55 2004
***************
*** 0 ****
--- 1,133 ----
+ #
+ # Makefile.mingw
+ #
+ # Description: Makefile for win32 (mingw) version of libtsn
+ #
+ 
+ #
+ # PATHS
+ #
+ 
+ INCLUDE_DIR :=		.
+ GTK_TOP :=		../../../../win32-dev/gtk_2_0
+ GAIM_TOP :=		../../..
+ NAPSTER_ROOT :=		.
+ GAIM_INSTALL_DIR :=	$(GAIM_TOP)/win32-install-dir
+ 
+ ##
+ ## VARIABLE DEFINITIONS
+ ##
+ 
+ TARGET = libnapster
+ 
+ # Compiler Options
+ 
+ CFLAGS =
+ 
+ DEFINES =
+ 
+ # Static or Plugin... 
+ ifeq ($(TYPE),STATIC)
+   DEFINES += -DSTATIC
+   DLL_INSTALL_DIR =	$(GAIM_INSTALL_DIR)
+ else
+ ifeq ($(TYPE),PLUGIN)
+   DLL_INSTALL_DIR =	$(GAIM_INSTALL_DIR)/plugins
+ endif
+ endif
+ 
+ 
+ ##
+ ## INCLUDE  MAKEFILES
+ ##
+ 
+ include $(GAIM_TOP)/src/win32/global.mak
+ 
+ ##
+ ## INCLUDE PATHS
+ ##
+ 
+ INCLUDE_PATHS +=	-I$(NAPSTER_ROOT) \
+ 			-I$(GTK_TOP)/include \
+ 			-I$(GTK_TOP)/include/gtk-2.0 \
+ 			-I$(GTK_TOP)/include/glib-2.0 \
+ 			-I$(GTK_TOP)/include/pango-1.0 \
+ 			-I$(GTK_TOP)/include/atk-1.0 \
+ 			-I$(GTK_TOP)/lib/glib-2.0/include \
+ 			-I$(GTK_TOP)/lib/gtk-2.0/include \
+ 			-I$(GAIM_TOP)/src \
+ 			-I$(GAIM_TOP)/src/win32 \
+ 			-I$(GAIM_TOP)
+ 
+ 
+ LIB_PATHS =		-L$(GTK_TOP)/lib \
+ 			-L$(GAIM_TOP)/src
+ 
+ 
+ ##
+ ##  SOURCES, OBJECTS
+ ##
+ 
+ C_SRC =			napster.c
+ 
+ 
+ OBJECTS = $(C_SRC:%.c=%.o)
+ 
+ 
+ ##
+ ## LIBRARIES
+ ##
+ 
+ LIBS =			-lgtk-win32-2.0 \
+ 			-lglib-2.0 \
+ 			-lgdk-win32-2.0 \
+ 			-lgmodule-2.0 \
+ 			-lgobject-2.0 \
+ 			-lws2_32 \
+ 			-lintl \
+ 			-lgaim
+ 
+ 
+ ##
+ ## RULES
+ ##
+ 
+ # How to make a C file
+ 
+ %.o: %.c
+ 	$(CC) $(CFLAGS) $(DEFINES) $(INCLUDE_PATHS) -o $@ -c $<
+ 
+ ##
+ ## TARGET DEFINITIONS
+ ##
+ 
+ .PHONY: all clean
+ 
+ all: $(TARGET).dll
+ 
+ install:
+ 	cp $(NAPSTER_ROOT)/$(TARGET).dll $(DLL_INSTALL_DIR)
+ 
+ 
+ ##
+ ## BUILD Dependencies
+ ##
+ 
+ $(GAIM_TOP)/src/gaim.lib:
+ 	$(MAKE) -C $(GAIM_TOP)/src -f Makefile.mingw gaim.lib
+ 
+ ##
+ ## BUILD DLL
+ ##
+ 
+ $(TARGET).dll: $(OBJECTS) $(GAIM_TOP)/src/gaim.lib
+ 	$(CC) -shared $(OBJECTS) $(LIB_PATHS) $(LIBS) $(DLL_LD_FLAGS) -Wl,--out-implib,$(TARGET).lib -o $(TARGET).dll
+ 
+ ##
+ ## CLEAN RULES
+ ##
+ 
+ clean:
+ 	rm -rf *.o
+ 	rm -rf $(TARGET).dll
+ 	rm -rf $(TARGET).lib
diff -P -c -r gaim-1.1.0/src/protocols/tsn/tsn.c gaim-1.1.0n/src/protocols/tsn/tsn.c
*** gaim-1.1.0/src/protocols/tsn/tsn.c	Thu Jan  1 01:00:00 1970
--- gaim-1.1.0n/src/protocols/tsn/tsn.c	Tue Feb 15 14:40:54 2005
***************
*** 0 ****
--- 1,906 ----
+ #include "internal.h"
+ 
+ #include "account.h"
+ #include "accountopt.h"
+ #include "blist.h"
+ #include "conversation.h"
+ #include "debug.h"
+ #include "notify.h"
+ #include "prpl.h"
+ #include "proxy.h"
+ #include "util.h"
+ #include "request.h"
+ #include "version.h"
+ #include "roomlist.h"
+ 
+ #define TSN_SERVER "localhost"
+ #define TSN_PORT 8888
+ 
+ #define TSN_CONNECT_STEPS 2
+ 
+ GSList *tsn_connections = NULL;
+ 
+ int chat_id=0;
+ 
+ //HACK
+ char ALREADY_LOOKING = FALSE;
+ 
+ // /HACK
+ struct tsn_data {
+ 	int fd;
+ 	gchar *login;
+ };
+ 
+ GaimRoomlist* local_chats;
+ 
+ // Use a macro to not process variable arguments
+ #define TSN_SEND_PACKET(gc, command, format, args...) {char buffer[1024];  snprintf(buffer, sizeof(buffer), format, ##args); tsn_write_packet(gc, command, buffer);}
+ 
+ // Macro to check strings
+ #define EQUALS(strx,stry) (!strncmp(strx, stry, strlen(stry)))
+ 
+ 
+ static void tsn_close(GaimConnection *gc);
+ 
+ 
+ // Send a packet to the TSN daemon
+ static void tsn_write_packet(GaimConnection *gc, 
+ 			     const char* command, 
+ 			     const char *message)
+ {
+     struct tsn_data *tsndata = (struct tsn_data *)gc->proto_data;
+     int len, wrote;
+ 
+     // Calculate length
+     len = strlen(command) + strlen(message) + 3;
+     
+     wrote = write(tsndata->fd, (const void*) &len, 4);
+     if (wrote != 4) {
+ 	printf("Error sending length: (%d) %s\n",wrote, strerror(errno));
+     }
+     wrote += write(tsndata->fd, (const void*) command, strlen(command));
+     wrote += write(tsndata->fd, (const void*) "+|+", 3);
+     wrote += write(tsndata->fd, (const void*) message, strlen(message));
+ 
+     
+     if (wrote <= 0) {
+ 	printf("Error sending data %s\n",strerror(errno));
+     }
+ }
+ 
+ 
+ //Called when user has selected witch chat to talk in
+ static void tsn_select_chat_cb(GaimConnection *gc, const char *entry){
+ 	TSN_SEND_PACKET(gc, "select_chat", "%s",entry);
+ }
+ 
+ //Returns a pointer to the chat given as input
+ static GaimConversation *tsn_find_chat(GaimConnection *gc, const char *name)
+ {
+ 	GSList *bcs = gc->buddy_chats;
+ 
+ 	while (bcs) {
+ 		GaimConversation *b = bcs->data;
+ 		if (!gaim_utf8_strcasecmp(b->name, name))
+ 			return b;
+ 		bcs = bcs->next;
+ 	}
+ 
+ 	return NULL;
+ }
+ 
+ //Called when Gaim receives a message from the local server
+ static void tsn_callback(gpointer data, 
+ 			 gint source, 
+ 			 GaimInputCondition condition)
+ {
+ 	GaimConnectionUiOps *ops;
+ 	GaimConnection *gc = data;
+ 	struct tsn_data *tsndata = gc->proto_data;
+ 	GaimConversation *c;
+ 	GaimAccount *account;
+ 	GaimConvIm *gcim;
+ 	GaimConvChat *gcchat;
+ 	gchar* command;
+ 	
+ 	int len;
+ 
+ 	gchar buffer[10240];
+ 	
+ 	memset(buffer, 0, sizeof(buffer));
+ 
+ 	if (read(source, &len, 4) < 4) {
+ 	    printf("Missing length\n");
+ 	    // Close down
+ 	    tsn_close(gc);
+ 	    return;
+ 	}
+ 	
+ 	if( len > sizeof(buffer)) {
+ 	    printf("Message too long (%d > %d)\n", len, sizeof(buffer));
+ 	    return;
+ 	}
+ 
+ 	if (read(source, buffer, len) < len) {
+ 	    printf("Read too few bytes!\n");
+ 	    return;
+ 	}
+ 
+ 	//printf("Got data '%s'\n",buffer);
+ 
+ 	// The buffer should be in the form:
+ 	// command+|+data
+ 
+ 	// Analyze callback
+ 	command = strtok(buffer, "+|+");
+ 	
+ 	if (command == NULL) {
+ 	    gaim_connection_error(gc, _("Bad message from server, missing command"));
+ 	    return;
+ 	}
+ 	
+ 	if EQUALS(command, "login") {
+ 	    
+ 	    gchar* user;
+ 	    user = strtok(NULL, "+|+");
+ 
+ 	    gaim_debug(GAIM_DEBUG_MISC, "tsn", "Received login command for user: %s\n", user);
+ 	    tsndata->login = g_strdup(user);
+ 	    
+ 	    //Our signon is complete
+ 	    gaim_connection_set_state(gc, GAIM_CONNECTED);
+ 	    serv_finish_login(gc);
+ 	    gaim_debug(GAIM_DEBUG_MISC, "tsn", "Finished logging on account\n");
+ 
+ 	    return;
+ 	}
+ 	
+ 	if EQUALS(command, "shutdown") {
+ 	    tsn_close(gc);
+ 	    return;
+ 	}
+ 
+ 	if EQUALS(command, "signon") {
+ 
+ 	    gchar* user;
+ 	    user = strtok(NULL, "+|+");
+ 
+ 	    //A buddy has signed on
+ 	    gaim_debug(GAIM_DEBUG_MISC, "tsn", "Buddy: %s signed on\n",user);
+ 	    serv_got_update(gc, user, 1, 0, 0, 0, 0);
+ 	    return;
+ 	}
+ 
+ 	if EQUALS(command, "signoff") {
+ 
+ 	    gchar* user;
+ 	    user = strtok(NULL, "+|+");
+ 
+ 	    //A buddy has signed off
+ 	    gaim_debug(GAIM_DEBUG_MISC, "tsn", "Buddy: %s signed off\n",user);
+ 	    serv_got_update(gc, user, 0, 0, 0, 0, 0);
+ 	    return;
+ 	}
+ 	
+ 	if EQUALS(command, "im") {
+ 	    //A IM has been received
+ 	    gchar *user, *msg;
+ 	    
+ 	    user = strtok(NULL, "+|+");
+ 	    msg = strtok(NULL, "+|+");
+ 
+ 	    gaim_debug(GAIM_DEBUG_MISC, "tsn", 
+ 		       "Received IM from: %s\n", user);
+ 	    
+ 	    account = gaim_connection_get_account(gc);
+ 	    c=gaim_conversation_new(GAIM_CONV_IM,account,user);
+ 	    gcim=gaim_conversation_get_im_data(c);
+ 	    gaim_conv_im_write(gcim,user,msg,GAIM_MESSAGE_RECV,time(NULL));
+ 	    
+ 	    return;
+ 	}
+ 
+ 	if EQUALS(command, "error") {
+ 	    char *msg;
+ 	    msg = strtok(NULL, "+|+");
+ 
+ 	    //A error message has been received
+ 	    //This is a rewite of the gaim_connection_error function, 
+ 	    //that does not close Gaim account on error
+ 	    gaim_debug(GAIM_DEBUG_MISC, "tsn", "Received error message\n");
+ 	    ops = gaim_connections_get_ui_ops();
+ 	    if (ops != NULL) {
+ 		if (ops->report_disconnect != NULL)
+ 		    ops->report_disconnect(gc, msg);
+ 	    }
+ 	    return;
+ 	}
+ 
+ 	if EQUALS(command, "join_chat") {
+ 	    
+ 	    char *user, *chat;
+ 	    user = strtok(NULL, "+|+");
+ 	    chat = strtok(NULL, "+|+");
+ 
+ 	    account = gaim_connection_get_account(gc);
+ 	    c=tsn_find_chat(gc,chat);
+ 	    gaim_debug(GAIM_DEBUG_MISC, "tsn", 
+ 		       "Adding user %s to chat %s\n", user, chat);
+ 	    gaim_conv_chat_add_user(GAIM_CONV_CHAT(c), 
+ 				    user, NULL, GAIM_CBFLAGS_NONE, TRUE);
+ 	    return;
+ 	}
+ 	
+ 	if EQUALS(command, "chat_msg") {
+ 
+ 	    char *user, *chat, *msg;
+ 	    user = strtok(NULL, "+|+");
+ 	    chat = strtok(NULL, "+|+");
+ 	    msg = strtok(NULL, "+|+");
+ 	    
+ 	    gaim_debug(GAIM_DEBUG_MISC, "tsn", 
+ 		       "Received a chat message from: %s on chat %s\n", 
+ 		       user, chat);
+ 	    c=tsn_find_chat(gc,chat);
+ 	    gcchat = GAIM_CONV_CHAT(c);
+ 	    gaim_conv_chat_write(gcchat,user,msg,1,time(NULL));
+ 	    return;
+ 	}
+ 	
+ 	if EQUALS(command, "leave_chat") {
+ 	    
+ 	    char *user, *chat;
+ 	    user = strtok(NULL, "+|+");
+ 	    chat = strtok(NULL, "+|+");
+ 
+ 	    gaim_debug(GAIM_DEBUG_MISC, "tsn", 
+ 		       "Removed user %s from chat %s\n", user, chat);
+ 	    c=tsn_find_chat(gc, chat);
+ 	    gcchat = GAIM_CONV_CHAT(c);
+ 	    gaim_conv_chat_remove_user(gcchat, user, NULL);
+ 	    return;
+ 	}
+ 
+ 	
+ 	if (EQUALS(command, "found_chat") || EQUALS(command, "found_local_chat")) {
+ 	 
+ 	    int i, total;
+ 
+ 	    total = atoi(strtok(NULL, "+|+"));
+ 	    
+ 	    // If we're getting a local chat room list, we already have the
+ 	    // window open, otherwise we have to create a window first
+ 	    if EQUALS(command, "found_chat") {
+ 		// Make gaim show the room list thingy
+ 		ALREADY_LOOKING = TRUE;
+ 		gaim_roomlist_show_with_account(gaim_connection_get_account(gc));
+ 		ALREADY_LOOKING = FALSE;
+ 	    }
+ 	    
+ 	    // Fill in the data
+ 	    for (i=0; i<total; i++) {
+ 		
+ 		gchar *name, *desc, *ownerid, *num_users;
+ 
+ 		GaimRoomlistRoom *room;
+ 		
+ 		name = strtok(NULL, "+|+");
+ 		desc = strtok(NULL, "+|+");
+ 		ownerid = strtok(NULL, "+|+");
+ 		//num_users = strtok(NULL, "+|+");
+ 		num_users = 0;
+ 		
+ 		room = gaim_roomlist_room_new(GAIM_ROOMLIST_ROOMTYPE_ROOM, 
+ 					      name, 
+ 					      NULL);
+ 		
+ 		gaim_roomlist_room_add_field(local_chats, room, ownerid);
+ 		gaim_roomlist_room_add_field(local_chats, room, desc);
+ 
+ 		gaim_roomlist_room_add(local_chats, room);
+ 	    }
+ 
+ 	    gaim_roomlist_set_in_progress(local_chats, FALSE);
+ 	}
+ 
+ 	if EQUALS(command, "add_user") {
+ 	    
+ 	    char *ID, *Nick;
+ 	    GaimBuddy *Buddy;
+ 
+ 	    ID = strtok(NULL, "+|+");
+ 	    Nick = strtok(NULL, "+|+");
+ 	    
+ 	    account = gaim_connection_get_account(gc);
+ 
+ 	    // Gaim seems to be slightly off about buddies...
+ 	    Buddy = gaim_find_buddy(account, ID);
+ 
+ 	    if (Buddy == NULL) {
+ 		Buddy = gaim_buddy_new(account, ID, Nick);
+ 
+ 		gaim_blist_add_buddy(Buddy, 
+ 				     NULL, // GaimContact
+ 				     NULL, // GaimGroup
+ 				     NULL);  // GaimBListNode - let this be NULL
+ 
+ 		gaim_blist_alias_buddy(Buddy, Nick);
+ 	    } else {
+ 		// Update here or what?
+ 	    }
+ 	}
+ 	
+ 	if EQUALS(command, "user_info") {
+ 	    
+ 	    char *Id, *Nick, *Desc, *Keywords, *URL;
+ 	    
+ 	    Id = strtok(NULL, "+|+");
+ 	    Nick = strtok(NULL, "+|+");
+ 	    Desc = strtok(NULL, "+|+");
+ 	    Keywords = strtok(NULL, "+|+");
+ 	    URL = strtok(NULL, "+|+");
+ 	    
+ 	    gchar buffer[1024];
+ 	    
+ 	    snprintf(buffer, sizeof(buffer), 
+ 		     "<b>Description</b>: %s<br>"
+ 		     "<b>Keywords</b>: <i>%s</i><br>"
+ 		     "<b>URL:</b><a href=\"%s\">%s</a>",
+ 		     Desc?Desc:"", Keywords?Keywords:"", 
+ 		     URL?URL:"", URL?URL:"");
+ 	    
+ 	    gaim_notify_userinfo(gc, 
+ 				 Nick, 
+ 				 _("User information"), // Title
+ 				 _("User information"), // Primary 
+ 				 Nick,                  // Secondary
+ 				 buffer,                // Text
+ 				 NULL,                  // Callback
+ 				 NULL);                 // User data
+ 	}
+ 	
+ 	/*
+ 	    //Received result for search after chattes, Gaim request input witch chat to join  
+ 		case 6:
+ 			gaim_debug(GAIM_DEBUG_MISC, "tsn", "Received chat search result\n");
+ 			gaim_request_input(gc, NULL, _("Search result"), _(buf),NULL, FALSE, FALSE, NULL,_("Select chat nr"), G_CALLBACK(tsn_select_chat_cb),_("Cancel"), NULL, gc);
+ 			break;
+ 
+ 		//Received initiate new chat message
+ 		case 7:
+ 			gaim_debug(GAIM_DEBUG_MISC, "tsn", "Initiated chat: %s\n",buf);
+ 			account = gaim_connection_get_account(gc);
+ 			c=gaim_conversation_new(GAIM_CONV_CHAT,account,buf);
+ 			gcchat = GAIM_CONV_CHAT(c);
+ 			if (!g_slist_find(gc->buddy_chats, c))
+ 				gc->buddy_chats = g_slist_append(gc->buddy_chats, c);
+ 			chat_id++;
+ 			gaim_conv_chat_set_id(gcchat,chat_id);
+ 			gaim_conv_window_show(gaim_conversation_get_window(c));
+ 			gaim_conv_window_switch_conversation(gaim_conversation_get_window(c),gaim_conversation_get_index(c));			
+ 			break;
+ 		
+ 		//Add a new user to chat
+ 		case 8:
+ 
+ 
+ 
+ 		//Used to send test msg to test if the connection to Gaim is active, this is done if we get a unidentified exception
+ 		case 99:
+ 			gaim_debug(GAIM_DEBUG_MISC, "tsn", "%s\n", buf);
+ 			break;
+ 
+ 	}	
+ 	g_free(buf);
+ 	*/
+ }
+ 
+ //Called during login, connects to the local server
+ static void tsn_login_connect(gpointer data, gint source, GaimInputCondition cond)
+ {
+ 	GaimConnection *gc = data;
+ 	struct tsn_data *tsndata = (struct tsn_data *)gc->proto_data;
+ 	gchar *buf;
+ 
+ 	if (!g_list_find(gaim_connections_get_all(), gc)) {
+ 		close(source);
+ 		return;
+ 	}
+ 
+ 	if (source < 0) {
+ 		gaim_connection_error(gc, _("Unable to connect."));
+ 		return;
+ 	}
+ 
+ 	tsndata->fd = source;
+ 
+ 	// Update the login progress status display 
+ 	buf = g_strdup_printf("Logging in: %s", 
+ 			      gaim_account_get_username(gc->account));
+ 	gaim_connection_update_progress(gc, buf, 1, TSN_CONNECT_STEPS);
+ 	g_free(buf);
+ 
+ 	// Write our signon data 
+ 	TSN_SEND_PACKET(gc, "login", "%s+|+%s+|+%s+|+%s",
+ 			gaim_account_get_username(gc->account),
+ 			gaim_account_get_alias(gc->account),
+ 			VERSION,
+ 			gaim_account_get_string(gc->account, "keywords", ""));
+ 
+ 	// And set up the input watcher
+ 	gc->inpa = gaim_input_add(tsndata->fd, 
+ 				  GAIM_INPUT_READ, 
+ 				  tsn_callback, 
+ 				  gc);
+ 
+ }
+ 
+ //Called during login, start the login prosedure
+ static void tsn_login(GaimAccount *account)
+ {
+ 	GaimConnection *gc = gaim_account_get_connection(account);
+ 
+ 	gaim_connection_update_progress(gc, _("Connecting"), 0, TSN_CONNECT_STEPS);
+ 
+ 	gc->proto_data = g_new0(struct tsn_data, 1);
+ 	if (gaim_proxy_connect(account,
+ 				gaim_account_get_string(account, "server", TSN_SERVER),
+ 				gaim_account_get_int(account, "port", TSN_PORT),
+ 				tsn_login_connect, gc) != 0) {
+ 		gaim_connection_error(gc, _("Unable to connect."));
+ 	}
+ }
+ 
+ //Called when Gaim user signs off, responsible for cleaning up and informing the local server
+ static void tsn_close(GaimConnection *gc)
+ {
+ 	struct tsn_data *tsndata = (struct tsn_data *)gc->proto_data;
+ 
+ 	if (gc->inpa)
+ 		gaim_input_remove(gc->inpa);
+ 
+ 	if (!tsndata)
+ 		return;
+ 
+ 	TSN_SEND_PACKET(gc, "signoff", "%s", gaim_account_get_username(gc->account));
+ 	close(tsndata->fd);
+ 
+ 	g_free(tsndata->login);
+ 	g_free(tsndata);
+ 
+ }
+ 
+ // Create an initiate-chat window thingy
+ GList *tsn_chat_info(GaimConnection *gc)
+ {
+ 	GList *m = NULL;
+ 	struct proto_chat_entry *pce;
+ 
+ 	pce = g_new0(struct proto_chat_entry, 1);
+ 	pce->label = _("_Name:");
+ 	pce->identifier = "name";
+ 	m = g_list_append(m, pce);
+ 
+ 	pce = g_new0(struct proto_chat_entry, 1);
+ 	pce->label = _("_Description:");
+ 	pce->identifier = "description";
+ 	m = g_list_append(m, pce);
+ 
+ 
+ 	pce = g_new0(struct proto_chat_entry, 1);
+ 	pce->label = _("_Keywords:");
+ 	pce->identifier = "keywords";
+ 	m = g_list_append(m, pce);
+ 	
+ 	return m;
+ }
+ 
+ 
+ static const char* tsn_list_icon(GaimAccount *a, GaimBuddy *b)
+ {
+ 	//Returns the name of the icon used by Gaim to represent the protocol
+ 	return "tsn";
+ }
+ 
+ static void tsn_list_emblems(GaimBuddy *b, char **se, char **sw, char **nw, char **ne)
+ {
+ 	if (b->present == GAIM_BUDDY_OFFLINE)
+ 		*se = "offline";
+ }
+ 
+ //Called when Gaim user wants to add a new buddy
+ static void tsn_add_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group)
+ {
+ 	TSN_SEND_PACKET(gc, "add_buddy", "%s+|+%s", buddy->name, buddy->alias);
+ }
+ 
+ //Called when Gaim user wants to add more then one buddy
+ static void tsn_add_buddies(GaimConnection *gc, GList *buddies, GList *groups)
+ {
+ 	while (buddies) {
+ 		GaimBuddy *buddy = buddies->data;
+ 		gaim_debug(GAIM_DEBUG_MISC, "tsn", "Buddy: %s\n",buddy->name);
+ 		TSN_SEND_PACKET(gc, "add_buddy", "%s+|+%s", buddy->name, buddy->alias);
+ 		buddies = buddies->next;
+ 	}
+ }
+ 
+ //Called whwn Gaim user wants to remove a buddy from his buddylist
+ static void tsn_remove_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group)
+ {
+ 	TSN_SEND_PACKET(gc, "remove_buddy", "%s", buddy->name);
+ }
+ 
+ //Called when a buddy wants to send a IM
+ static int tsn_send_im(GaimConnection *gc, const char *who, const char *message, GaimConvImFlags flags)
+ {
+ 	TSN_SEND_PACKET(gc, "send_im", "%s+|+%s", who, message);
+ 	return 1;
+ }
+ 
+ //Called when Gaim user wants to send a chat message
+ static int tsn_chat_send(GaimConnection *gc, int id, const char *message)
+ {
+ 	GaimConversation *c = gaim_find_chat(gc, id);
+ 	GaimConvChat *gcchat;
+ 	if (!c){
+ 	    return -EINVAL;
+ 	}
+ 	//gcchat = GAIM_CONV_CHAT(c);
+ 	//gaim_conv_chat_write(gcchat,gaim_account_get_username(gc->account),message,1,time(NULL));
+ 	TSN_SEND_PACKET(gc, "send_chat_msg", "%s+|+%s",c->name, message);
+ 	
+ 	return 0;
+ }
+ 
+ static void tsn_start_chat(GaimConnection *gc, 
+ 			   const char* name) 
+ {
+ 	GaimConversation *c;
+ 	GaimAccount *account;
+ 	GaimConvChat *gcchat;
+ 	int id;
+     
+ 	account = gaim_connection_get_account(gc);
+ 
+ 	c=gaim_conversation_new(GAIM_CONV_CHAT,account,name);
+ 	
+ 	gcchat = GAIM_CONV_CHAT(c);
+ 	if (!g_slist_find(gc->buddy_chats, c))
+ 		gc->buddy_chats = g_slist_append(gc->buddy_chats, c);
+ 	chat_id++;
+ 	gaim_conv_chat_set_id(gcchat,chat_id);
+ 	gaim_conv_window_show(gaim_conversation_get_window(c));
+ 	gaim_conv_window_switch_conversation(gaim_conversation_get_window(c),gaim_conversation_get_index(c));
+ 	//gaim_conv_chat_add_user(gcchat,
+ 	//			gaim_account_get_alias(gc->account),
+ 	//			NULL,GAIM_CBFLAGS_NONE,TRUE);
+ 
+ 	id=gaim_conv_chat_get_id(gcchat);
+ 
+ }
+ 
+ void tsn_get_info(GaimConnection *gc, const char* who) {
+ 
+     TSN_SEND_PACKET(gc, "get_info", "%s", who);
+ }
+ 
+ //Called when a user joins a chat
+ void tsn_chat_join(GaimConnection *gc, GHashTable *data)
+ {
+     //GaimConversation *c = gaim_find_chat(gc, id);
+     char *name, *description, *keywords;
+ 
+     name = g_hash_table_lookup(data, "name");
+     //ownerid = g_hash_table_lookup(data, "owner");
+ 
+     // Create local chat window
+     tsn_start_chat(gc, name);
+ 
+     // Create or join?
+     // If we have more info here, we might need to create the chat first!
+     description = g_hash_table_lookup(data, "description");
+     keywords = g_hash_table_lookup(data, "keywords");
+ 
+     if (description != NULL) {
+ 	// Create
+ 	TSN_SEND_PACKET(gc, "new_chat", "%s+|+%s+|+%s+|+global", name, 
+ 			description, keywords);
+     } else {
+ 	// Join
+ 	TSN_SEND_PACKET(gc, "join_chat", "%s", name);
+     }
+ }
+ 
+ //Called when a user leaves a chat
+ static void tsn_chat_leave(GaimConnection *gc, int id)
+ {
+ 	GaimConversation *c = gaim_find_chat(gc, id);
+ 	if (!c)
+ 		return;
+ 	TSN_SEND_PACKET(gc, "leave_chat", "%s",c->name);
+ }
+ 
+ 
+ // Callback for search
+ static void tsn_search_for_user_cb(GaimConnection *gc, const char *entry)
+ {
+ 	TSN_SEND_PACKET(gc, "find_user", "%s", entry);
+ }    
+ 
+ 
+ // Called when the user wants to search for another user
+ static void tsn_search_for_user(GaimPluginAction *action)
+ {
+ 	GaimConnection *gc;
+ 	gc = (GaimConnection *) action->context;
+ 	gaim_request_input(gc, 
+ 			   NULL, 
+ 			   _("Search for user"), 
+ 			   _("Look for:"),
+ 			   NULL, 
+ 			   FALSE, 
+ 			   FALSE, 
+ 			   NULL,_("Search"), 
+ 			   G_CALLBACK(tsn_search_for_user_cb),
+ 			   _("Cancel"), 
+ 			   NULL, 
+ 			   gc);
+ }
+ 
+ 
+ //Called when a user initiates a new chat, responsible for starting the chat
+ static void tsn_initiate_chat_cb(GaimConnection *gc,
+ 				 GaimRequestFields *fields)
+ {
+ 	const gchar *name, *description, *keywords;
+ 
+ 	name = gaim_request_fields_get_string(fields, "name");
+ 	description = gaim_request_fields_get_string(fields, "description");
+ 	keywords = gaim_request_fields_get_string(fields, "keywords");
+ 	
+ 	tsn_start_chat(gc, name);
+ 	
+ 	TSN_SEND_PACKET(gc, "new_chat", "%s+|+%s+|+%s+|+global", name, 
+ 			description, keywords);
+ }
+ 
+ 
+ //Called when user initiates a new chat, responsible for starting the input requester
+ static void tsn_initiate_new_chat(GaimPluginAction *action)
+ {
+ 	GaimConnection *gc;
+ 	GaimRequestFields *fields;
+ 	GaimRequestFieldGroup *group;
+ 	GaimRequestField *field;
+ 
+ 	gc = (GaimConnection *) action->context;
+ 
+ 	fields = gaim_request_fields_new();
+ 	group = gaim_request_field_group_new(NULL);
+ 	gaim_request_fields_add_group(fields, group);
+ 
+ 	field = gaim_request_field_string_new("name", _("Name"),
+ 					      "", FALSE);
+ 
+ 	gaim_request_field_group_add_field(group, field);
+ 
+ 	field = gaim_request_field_string_new("description", 
+ 					      _("Description"),
+ 					      "", FALSE);
+ 
+ 	gaim_request_field_group_add_field(group, field);
+ 
+ 	field = gaim_request_field_string_new("keywords", 
+ 					      _("Keywords"),
+ 					      "", FALSE);
+ 
+ 	gaim_request_field_group_add_field(group, field);
+ 
+ 	gaim_request_fields(gc, 
+ 			    _("Create new chat"),
+ 			    _("Create new chat"), 
+ 			    _("Please describe the new chat"),
+ 			    fields, 
+ 			    _("OK"), 
+ 			    G_CALLBACK(tsn_initiate_chat_cb),
+ 			    _("Cancel"), 
+ 			    NULL, 
+ 			    gc);
+ }
+ 
+ //Called when user searches for a chat, responcible for sending chat search to local server
+ static void tsn_search_for_chat_cb(GaimConnection *gc, const char *entry)
+ {
+ 	TSN_SEND_PACKET(gc, "find_chat", "global+|+%s", entry);
+ }
+ 
+ //Called during chat search, responcible for starting the input requestor
+ static void tsn_search_for_chat(GaimPluginAction *action)
+ {
+ 	GaimConnection *gc;
+ 	gc = (GaimConnection *) action->context;
+ 	gaim_request_input(gc, NULL, _("Search for chat."), _("Write the topic you would like to chat about"),NULL, FALSE, FALSE, NULL,_("Search"), G_CALLBACK(tsn_search_for_chat_cb),_("Cancel"), NULL, gc);
+ }
+ 
+ 
+ 
+ GaimRoomlist *list_local_chats(GaimConnection *gc)
+ {
+     GList *fields = NULL;
+     GaimRoomlistField *f;
+ 
+ 
+     // Create room list
+     local_chats = gaim_roomlist_new(gaim_connection_get_account(gc));
+ 
+ 
+     // Specify layout
+     f = gaim_roomlist_field_new(GAIM_ROOMLIST_FIELD_STRING, "", "ownerid", TRUE);
+     fields = g_list_append(fields, f);
+     
+ 
+     f = gaim_roomlist_field_new(GAIM_ROOMLIST_FIELD_STRING, _("Topic"), "topic", FALSE);
+     fields = g_list_append(fields, f);
+     
+     gaim_roomlist_set_fields(local_chats, fields);
+ 
+     // TODO: Can I more elegantly solve this???
+     if (!ALREADY_LOOKING) {
+ 	TSN_SEND_PACKET(gc, "find_chat", "local");
+     }
+     
+     //rl->proto_data = g_list_append(rl->proto_data, yrl);
+ 
+     gaim_roomlist_set_in_progress(local_chats, TRUE);
+ 
+     return local_chats;
+ }
+ 
+ 
+ //Called when users try to search for all chats on local network
+ static void tsn_search_for_local_chats(GaimPluginAction *action)
+ {
+ 	GaimConnection *gc;
+ 	gc = (GaimConnection *) action->context;
+ 	TSN_SEND_PACKET(gc, "find_chat", "local");
+ }
+ 
+ //This method describes witch actions are available on this account,
+ //and witch function should be called to handle the specific actions
+ static GList * tsn_actions(GaimPlugin *plugin, gpointer context)
+ {
+ 	GList *m = NULL;
+ 	GaimPluginAction *act;
+ 
+ 	act = gaim_plugin_action_new(_("Search for users"),tsn_search_for_user);
+ 	m = g_list_append(m, act);
+ 
+ 	act = gaim_plugin_action_new(_("Initiate new chat"),tsn_initiate_new_chat);
+ 	m = g_list_append(m, act);
+ 	
+ 	act = gaim_plugin_action_new(_("Search for chat"),tsn_search_for_chat);
+ 	m = g_list_append(m, act);
+ 
+ 	return m;
+ }
+ 
+ static GaimPlugin *my_protocol = NULL;
+ 
+ //Describes witch function should be called to handle a spesific type of event
+ static GaimPluginProtocolInfo prpl_info =
+ {
+ 	0,
+ 	NULL,					/* user_splits */
+ 	NULL,					/* protocol_options */
+ 	NO_BUDDY_ICONS,			/* icon_spec */
+ 	tsn_list_icon,			/* list_icon */
+ 	tsn_list_emblems,		/* list_emblems */
+ 	NULL,					/* status_text */
+ 	NULL,					/* tooltip_text */
+ 	NULL,					/* away_states */
+ 	NULL,					/* blist_node_menu */
+ 	tsn_chat_info,				/* chat_info */
+ 	NULL,					/* chat_info_defaults */
+ 	tsn_login,				/* login */
+ 	tsn_close,				/* close */
+ 	tsn_send_im,			/* send_im */
+ 	NULL,					/* set_info */
+ 	NULL,					/* send_typing */
+ 	tsn_get_info,				/* get_info */
+ 	NULL,					/* set_away */
+ 	NULL,					/* set_idle */
+ 	NULL,					/* change_passwd */
+ 	tsn_add_buddy,			/* add_buddy */
+ 	tsn_add_buddies,		/* add_buddies */
+ 	tsn_remove_buddy,		/* remove_buddy */
+ 	NULL,					/* remove_buddies */
+ 	NULL,					/* add_permit */
+ 	NULL,					/* add_deny */
+ 	NULL,					/* rem_permit */
+ 	NULL,					/* rem_deny */
+ 	NULL,					/* set_permit_deny */
+ 	NULL,					/* warn */
+ 	tsn_chat_join,				/* join_chat */
+ 	NULL,					/* reject chat invite */
+ 	NULL,					/* chat_invite */
+ 	NULL,
+ 	tsn_chat_leave,			/* chat_leave */
+ 	NULL,					/* chat_whisper */
+ 	tsn_chat_send,			/* chat_send */
+ 	NULL,					/* keepalive */
+ 	NULL,					/* register_user */
+ 	NULL,					/* get_cb_info */
+ 	NULL,					/* get_cb_away */
+ 	NULL,					/* alias_buddy */
+ 	NULL,					/* group_buddy */
+ 	NULL,					/* rename_group */
+ 	NULL,					/* buddy_free */
+ 	NULL,					/* convo_closed */
+ 	NULL,					/* normalize */
+ 	NULL,					/* set_buddy_icon */
+ 	NULL,					/* remove_group */
+ 	NULL,					/* get_cb_real_name */
+ 	NULL,					/* set_chat_topic */
+ 	NULL,					/* find_blist_chat */
+ 	list_local_chats,       		/* roomlist_get_list */
+ 	NULL,			                /* roomlist_cancel */
+ 	NULL,					/* roomlist_expand_category */
+ 	NULL,					/* can_receive_file */
+ 	NULL					/* send_file */
+ };
+ 
+ static GaimPluginInfo info =
+ {
+ 	GAIM_PLUGIN_MAGIC,
+ 	GAIM_MAJOR_VERSION,
+ 	GAIM_MINOR_VERSION,
+ 
+ 	GAIM_PLUGIN_PROTOCOL,                             /**< type           */
+ 	NULL,                                             /**< ui_requirement */
+ 	0,                                                /**< flags          */
+ 	NULL,                                             /**< dependencies   */
+ 	GAIM_PRIORITY_DEFAULT,                            /**< priority       */
+ 	"prpl-tsn",	                                  /**< id             */
+ 	"TSN",		                                  /**< name           */
+ 	VERSION,                                          /**< version        */
+ 	                                                  /**  summary        */
+ 	N_("TSN Protocol Plugin"),
+ 	                                                  /**  description    */
+ 	N_("TSN Protocol Plugin"),
+ 	N_("Njaal Borch"),                                /**< author         */
+ 	N_("http://the.socialized.net"),                  /**< homepage       */
+ 
+ 	NULL,                                             /**< load           */
+ 	NULL,                                             /**< unload         */
+ 	NULL,                                             /**< destroy        */
+ 
+ 	NULL,                                             /**< ui_info        */
+ 	&prpl_info,                                       /**< extra_info     */
+ 	NULL,
+ 	tsn_actions
+ };
+ 
+ //This function is called during startup, responcible for setting up initial data
+ static void init_plugin(GaimPlugin *plugin)
+ {
+ 	GaimAccountOption *option;
+ 
+ 	option = gaim_account_option_string_new(_("Keywords"), "keywords", "");
+ 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, 
+ 						   option);
+ 
+ 
+ 	option = gaim_account_option_string_new(_("Server"), "server",
+ 						TSN_SERVER);
+ 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
+ 						   option);
+ 	
+ 	option = gaim_account_option_int_new(_("Port"), "port", 8888);
+ 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
+ 						   option);
+ 	
+ 	my_protocol = plugin;
+ }
+ 
+ GAIM_INIT_PLUGIN(tsn, init_plugin, info);

