changeset 5388:5d0df915ca09

[gaim-migrate @ 5764] This patch is Sofar's (Auke Kok) napster update warmenhovinated by me. So... the Napster PRPL works with Opennap servers now. Thanks Auke. There are a few places that still need a bit of work. Namely joining and parting chats. I don't have time to look at it right now, but search for XXX and // and you'll see the stuff that is relevant to it, if anyone wants to fix the memleak or two. For any potential Gaim hackers out there, a few notes: -Put all declarations at the top of a block--we're not all using C99 -Please don't use // comments, use /* */ (// is for C) -Try to use dynamic buffers rather than static buffers in most places. I think most of us Gaim people perfer dynamic rather than static. I wish oscar.c was this short. Or this clean. committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Thu, 15 May 2003 21:43:42 +0000
parents 1133ab0a26a2
children 3a4b9b057825
files ChangeLog src/blist.c src/protocols/napster/napster.c src/protocols/oscar/oscar.c
diffstat 4 files changed, 448 insertions(+), 424 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Thu May 15 20:36:37 2003 +0000
+++ b/ChangeLog	Thu May 15 21:43:42 2003 +0000
@@ -10,7 +10,8 @@
 	* MSN protocol plugin was rewritten, has experimental buddy icon
 	  support, and MSN Mobile support.
 	* Thanks to all the various people who submitted translation updates.
-	* Speed enhancements (Thanks Ethan Blanton).
+	* Buddy list speed enhancements (Thanks Ethan Blanton).
+	* Napster protocol updates (Thanks Auke Kok).
 
 version 0.62 (04/23/2003):
 	* Keyboard shortcuts in the buddy list work again (Thanks Joe 
--- a/src/blist.c	Thu May 15 20:36:37 2003 +0000
+++ b/src/blist.c	Thu May 15 21:43:42 2003 +0000
@@ -618,6 +618,7 @@
 	hb.account = buddy->account;
 	if (g_hash_table_lookup_extended(gaimbuddylist->buddies, &hb, (gpointer *)&key, (gpointer *)&val)) {
 		g_hash_table_remove(gaimbuddylist->buddies, &hb);
+		/* XXX - Is hb freed anywhere? */
 		g_free(key->name);
 		g_free(key);
 	}
--- a/src/protocols/napster/napster.c	Thu May 15 20:36:37 2003 +0000
+++ b/src/protocols/napster/napster.c	Thu May 15 21:43:42 2003 +0000
@@ -50,8 +50,6 @@
 /* for win32 compatability */
 G_MODULE_IMPORT GSList *connections;
 
-#define NAP_BUF_LEN 4096
-
 #define USEROPT_NAPSERVER 3
 #define NAP_SERVER "64.124.41.187"
 #define USEROPT_NAPPORT 4
@@ -68,51 +66,21 @@
 
 struct nap_data {
 	int fd;
-	int inpa;
-
 	gchar *email;
 	GSList *channels;
 };
 
-/* FIXME: Make this use va_arg stuff */
-static void nap_write_packet(struct gaim_connection *gc, unsigned short command, const char *message)
+static struct nap_channel *find_channel_by_name(struct gaim_connection *gc, char *name)
 {
 	struct nap_data *ndata = (struct nap_data *)gc->proto_data;
-	unsigned short size;
-
-	size = strlen(message);
-
-	write(ndata->fd, &size, 2);
-	write(ndata->fd, &command, 2);
-	write(ndata->fd, message, size);
-}
-
-static int nap_send_im(struct gaim_connection *gc, const char *who, const char *message, int len, int flags)
-{
-	gchar buf[NAP_BUF_LEN];
-
-	g_snprintf(buf, NAP_BUF_LEN, "%s %s", who, message);
-	nap_write_packet(gc, 0xCD, buf);
-
-	return 1;
-}
-
-static struct nap_channel *find_channel_by_name(struct gaim_connection *gc, char *name)
-{
 	struct nap_channel *channel;
-	struct nap_data *ndata = (struct nap_data *)gc->proto_data;
 	GSList *channels;
 
 	channels = ndata->channels;
-
 	while (channels) {
 		channel = (struct nap_channel *)channels->data;
-
-		if (channel) {
-			if (!gaim_utf8_strcasecmp(name, channel->name)) {
-				return channel;
-			}
-		}
+		if ((channel) && (!gaim_utf8_strcasecmp(name, channel->name)))
+			return channel;
 		channels = g_slist_next(channels);
 	}
 
@@ -121,18 +89,15 @@
 
 static struct nap_channel *find_channel_by_id(struct gaim_connection *gc, int id)
 {
+	struct nap_data *ndata = (struct nap_data *)gc->proto_data;
 	struct nap_channel *channel;
-	struct nap_data *ndata = (struct nap_data *)gc->proto_data;
 	GSList *channels;
 
 	channels = ndata->channels;
-
 	while (channels) {
 		channel = (struct nap_channel *)channels->data;
-		if (id == channel->id) {
+		if (id == channel->id)
 			return channel;
-		}
-
 		channels = g_slist_next(channels);
 	}
 
@@ -141,277 +106,449 @@
 
 static struct gaim_conversation *find_conversation_by_id(struct gaim_connection *gc, int id)
 {
-	GSList *bc = gc->buddy_chats;
 	struct gaim_conversation *b = NULL;
+	GSList *bc;
 
+	bc = gc->buddy_chats;
 	while (bc) {
 		b = (struct gaim_conversation *)bc->data;
 		if (id == gaim_chat_get_id(GAIM_CHAT(b)))
-			break;
+			return b;
+		bc = g_slist_next(bc);
+	}
+
+	return NULL;
+}
+
+static void nap_write_packet(struct gaim_connection *gc, unsigned short command, const char *format, ...)
+{
+	struct nap_data *ndata = (struct nap_data *)gc->proto_data;
+	va_list ap;
+	gchar *message;
+	unsigned short size;
+
+	va_start(ap, format);
+	message = g_strdup_vprintf(format, ap);
+	va_end(ap);
+
+	size = strlen(message);
+	gaim_debug(GAIM_DEBUG_MISC, "napster", "S %3hd: %s\n", command, message);
+
+	write(ndata->fd, &size, 2);
+	write(ndata->fd, &command, 2);
+	write(ndata->fd, message, size);
+
+	g_free(message);
+}
+
+static int nap_do_irc_style(struct gaim_connection *gc, const char *message, const char *channelname)
+{
+	gchar **res;
+
+        gaim_debug(GAIM_DEBUG_MISC, "napster", "C %s\n", message);
+
+	res = g_strsplit(message, " ", 2);
+
+	if (!strcasecmp(res[0], "/ME")) { /* MSG_CLIENT_PUBLIC */
+		nap_write_packet(gc, 824, "%s \"%s\"", channelname, res[1]);
+
+	} else if (!strcasecmp(res[0], "/MSG")) { /* MSG_CLIENT_PUBLIC */
+		nap_write_packet(gc, 205, "%s", res[1]);
 
-		bc = bc->next;
-		b = NULL;
+	} else if (!strcasecmp(res[0], "/JOIN")) { /* join chatroom MSG_CLIENT_JOIN */
+		if (!res[1]) {
+			g_strfreev(res);
+			return 1;
+		}
+		if (res[1][0] != '#')
+			nap_write_packet(gc, 400, "#%s", res[1]);
+		else
+			nap_write_packet(gc, 400, "%s", res[1]);
+
+	} else if (!strcasecmp(res[0], "/PART")) { /* partchatroom MSG_CLIENT_PART */
+		nap_write_packet(gc, 401, "%s", res[1] ? res[1] : channelname);
+
+	} else if (!strcasecmp(res[0], "/TOPIC")) { /* set topic MSG_SERVER_TOPIC */
+		nap_write_packet(gc, 410, "%s", res[1] ? res[1] : channelname);
+
+	} else if (!strcasecmp(res[0], "/WHOIS")) { /* whois request MSG_CLIENT_WHOIS */
+		nap_write_packet(gc, 603, "%s", res[1]);
+
+	} else if (!strcasecmp(res[0], "/PING")) { /* send ping MSG_CLIENT_PING */
+		nap_write_packet(gc, 751, "%s", res[1]);
+
+	} else if (!strcasecmp(res[0], "/KICK")) { /* kick asswipe MSG_CLIENT_KICK */
+		nap_write_packet(gc, 829, "%s", res[1]);
+
+	} else {
+		g_strfreev(res);
+		return 1;
+	}
+
+	g_strfreev(res);
+	return 0;
+}
+
+/* 205 - MSG_CLIENT_PRIVMSG */
+static int nap_send_im(struct gaim_connection *gc, const char *who, const char *message, int len, int flags)
+{
+
+	if ((strlen(message) < 2) || (message[0] != '/' ) || (message[1] == '/')) {
+		/* Actually send a chat message */
+		nap_write_packet(gc, 205, "%s %s", who, message);
+	} else {
+		/* user typed an IRC-style command */
+		nap_do_irc_style(gc, message, who);
 	}
 
-	return b;
+	return 1;
+}
+
+/* 207 - MSG_CLIENT_ADD_HOTLIST */
+static void nap_add_buddy(struct gaim_connection *gc, const char *name)
+{
+	nap_write_packet(gc, 207, "%s", name);
+}
+
+/* 208 - MSG_CLIENT_ADD_HOTLIST_SEQ */
+static void nap_add_buddies(struct gaim_connection *gc, GList *buddies)
+{
+	while (buddies) {
+		nap_write_packet(gc, 208, "%s", (char *)buddies->data);
+		buddies = buddies -> next;
+	}
+}
+
+/* 303 - MSG_CLIENT_REMOVE_HOTLIST */
+static void nap_remove_buddy(struct gaim_connection *gc, char *name, char *group)
+{
+	nap_write_packet(gc, 303, "%s", name);
+}
+
+/* 400 - MSG_CLIENT_JOIN */
+static void nap_join_chat(struct gaim_connection *gc, GHashTable *data)
+{
+	char *name;
+
+	if (!data)
+		return;
+
+	name = g_hash_table_lookup(data, "group");
+
+	/* Make sure the name has a # preceeding it */
+	if (name[0] != '#')
+		nap_write_packet(gc, 400, "#%s", name);
+	else
+		nap_write_packet(gc, 400, "%s", name);
+}
+
+/* 401 - MSG_CLIENT_PART */
+static void nap_chat_leave(struct gaim_connection *gc, int id)
+{
+	struct nap_data *ndata = (struct nap_data *)gc->proto_data;
+	struct nap_channel *channel = NULL;
+
+	channel = find_channel_by_id(gc, id);
+
+	if (!channel) /* Again, I'm not sure how this would happen */
+		return;
+
+	serv_got_chat_left(gc, id);
+
+	nap_write_packet(gc, 401, "%s", channel->name);
+
+	ndata->channels = g_slist_remove(ndata->channels, channel);
+	g_free(channel->name);
+	g_free(channel);
+}
+
+/* 402 - MSG_CLIENT_PUBLIC */
+static int nap_chat_send(struct gaim_connection *gc, int id, char *message)
+{
+	struct nap_channel *channel = NULL;
+
+	channel = find_channel_by_id(gc, id);
+
+	if (!channel) {
+		/* This shouldn't happen */
+		return -EINVAL;
+	}
+
+	if ((strlen(message) < 2) || (message[0] != '/' ) || (message[1] == '/')) {
+		/* Actually send a chat message */
+		nap_write_packet(gc, 402, "%s %s", channel->name, message);
+	} else {
+		/* user typed an IRC-style command */
+		nap_do_irc_style(gc, message, channel->name);
+	}
+
+	return 0;
+}
+
+/* 603 - MSG_CLIENT_WHOIS */
+static void nap_get_info(struct gaim_connection *gc, const char *who)
+{
+	nap_write_packet(gc, 603, "%s", who);
 }
 
 static void nap_callback(gpointer data, gint source, GaimInputCondition condition)
 {
 	struct gaim_connection *gc = data;
 	struct nap_data *ndata = gc->proto_data;
-	gchar *buf;
+	struct nap_channel *channel;
+	struct gaim_conversation *convo;
+	gchar *buf, *buf2, *buf3;
+	gchar **res;
 	unsigned short header[2];
 	int len;
 	int command;
-	gchar **res;
 	int i;
 
-	if (recv(source, (void*)header, 4, 0) != 4) {
-		hide_login_progress(gc, "Unable to read");
+	if (read(source, (void*)header, 4) != 4) {
+		hide_login_progress(gc, _("Unable to read header from server"));
 		signoff(gc);
 		return;
 	}
 
 	len = header[0];
 	command = header[1];	
-
-	buf = (gchar *)g_malloc(sizeof(gchar) * (len + 1));
+	buf = (gchar *)g_malloc((len + 1) * sizeof(gchar));
+	buf[len] = '\0';
 
 	i = 0;
 	do {
-		int tmp = recv(source, buf + i, len - i, 0);
+		int tmp = read(source, buf + i, len - i);
 		if (tmp <= 0) {
 			g_free(buf);
-			hide_login_progress(gc, "Unable to read");
+			buf = g_strdup_printf("Unable to read mesage from server.  Command is %hd, length is %hd.", len, command);
+			hide_login_progress(gc, buf);
+			g_free(buf);
 			signoff(gc);
 			return;
 		}
 		i += tmp;
 	} while (i != len);
 
-	buf[len] = 0;
-	
-	gaim_debug(GAIM_DEBUG_MISC, "napster", "DEBUG: %s\n", buf);
-
-	if (command == 0xd6) {
-		res = g_strsplit(buf, " ", 0);
-		/* Do we want to report what the users are doing? */ 
-		printf("users: %s, files: %s, size: %sGB\n", res[0], res[1], res[2]);
-		g_strfreev(res);
-		g_free(buf);
-		return;
-	}
-
-	if (command == 0x26d) {
-		/* Do we want to use the MOTD? */
-		g_free(buf);
-		return;
-	}
-
-	if (command == 0xCD) {
-		res = g_strsplit(buf, " ", 1);
-		serv_got_im(gc, res[0], res[1], 0, time(NULL), -1);
-		g_strfreev(res);
-		g_free(buf);
-		return;
-	}
-
-	if (command == 0x195) {
-		struct nap_channel *channel;
-	
-		channel = find_channel_by_name(gc, buf);
-
-		if (!channel) {
-			chat_id++;
-
-			channel = g_new0(struct nap_channel, 1);
-
-			channel->id = chat_id;
-			channel->name = g_strdup(buf);
-
-			ndata->channels = g_slist_append(ndata->channels, channel);
-
-			serv_got_joined_chat(gc, chat_id, buf);
-		}
-
-		g_free(buf);
-		return;
-	}
-
-	if (command == 0x198 || command == 0x196) {
-		struct nap_channel *channel;
-		struct gaim_conversation *convo;
-		gchar **res;
-
-		res = g_strsplit(buf, " ", 0);
-
-		channel = find_channel_by_name(gc, res[0]);
-		convo = find_conversation_by_id(gc, channel->id);
-
-		gaim_chat_add_user(GAIM_CHAT(convo), res[1], NULL);
-
-		g_strfreev(res);
-
-		g_free(buf);
-		return;
-	}
-
-	if (command == 0x197) {
-		struct nap_channel *channel;
-		struct gaim_conversation *convo;
-		gchar **res;
-
-		res = g_strsplit(buf, " ", 0);
-		
-		channel = find_channel_by_name(gc, res[0]);
-		convo = find_conversation_by_id(gc, channel->id);
-
-		gaim_chat_remove_user(GAIM_CHAT(convo), res[1], NULL);
-		
-		g_strfreev(res);
-		g_free(buf);
-		return;
-	}
-
-	if (command == 0x193) {
-		gchar **res;
-		struct nap_channel *channel;
-
-		res = g_strsplit(buf, " ", 2);
-
-		channel = find_channel_by_name(gc, res[0]);
-
-		if (channel)
-			serv_got_chat_in(gc, channel->id, res[1], 0, res[2], time((time_t)NULL));
+	gaim_debug(GAIM_DEBUG_MISC, "napster", "R %3hd: %s\n", command, buf);
 
-		g_strfreev(res);
-		g_free(buf);
-		return;
-	}
-
-	if (command == 0x194) {
+	switch (command) {
+	case 000: /* MSG_SERVER_ERROR */
 		do_error_dialog(buf, NULL, GAIM_ERROR);
-		g_free(buf);
-		return;
-	}
-
-	if (command == 0x12e) {
-		gchar buf2[NAP_BUF_LEN];
-
-		g_snprintf(buf2, NAP_BUF_LEN, "Unable to add '%s' to your Napster hotlist", buf);
-		do_error_dialog(buf2, NULL, GAIM_ERROR);
-
-		g_free(buf);
-		return;
-
-	}
-
-	if (command == 0x191) {
-		struct nap_channel *channel;
-
-		channel = find_channel_by_name(gc, buf);
-
-		if (!channel) /* I'm not sure how this would happen =) */
-			return;
-
-		serv_got_chat_left(gc, channel->id);
-		ndata->channels = g_slist_remove(ndata->channels, channel);
-
-		g_free(buf);
-		return;
-
-	}
-
-	if (command == 0xd1) {
-		gchar **res;
-
-		res = g_strsplit(buf, " ", 0);
-
-		serv_got_update(gc, res[0], 1, 0, 0, 0, 0);
-
-		g_strfreev(res);
-		g_free(buf);
-		return;
-	}
-
-	if (command == 0xd2) {
-		serv_got_update(gc, buf, 0, 0, 0, 0, 0);
-		g_free(buf);
-		return;
-	}
-
-	if (command == 0x12d) {
-		/* Our buddy was added successfully */
-		g_free(buf);
-		return;
-	}
-
-	if (command == 0x2ec) {
-		/* Looks like someone logged in as us! =-O */
-		g_free(buf);
-
-		signoff(gc);
-		return;
-	}
-
-	gaim_debug(GAIM_DEBUG_MISC, "napster",
-			   "NAP: [COMMAND: 0x%04x] %s\n", command, buf);
-
-	g_free(buf);
-}
-
-
-static void nap_login_callback(gpointer data, gint source, GaimInputCondition condition)
-{
-	struct gaim_connection *gc = data;
-	struct nap_data *ndata = gc->proto_data;
-	gchar buf[NAP_BUF_LEN];
-	unsigned short header[2];
-	int len;
-	int command;
-
-	read(source, header, 4);
-	len = header[0];
-	command = header[1];	
-
-	read(source, buf, len);
-	buf[len] = 0;
-
-	/* If we have some kind of error, get outta here */
-	if (command == 0x00)
-	{
-		do_error_dialog(buf, NULL, GAIM_ERROR);
-		gaim_input_remove(ndata->inpa);
-		ndata->inpa = 0;
+		gaim_input_remove(gc->inpa);
+		gc->inpa = 0;
 		close(source);
 		signoff(gc);
-		return;
-	}
+		break;
 
-	if (command == 0x03) {
-		printf("Registered with E-Mail address of: %s\n", buf);
+	case 003: /* MSG_SERVER_EMAIL */
+		gaim_debug(GAIM_DEBUG_MISC, "napster", "Registered with e-mail address: %s\n", buf);
 		ndata->email = g_strdup(buf);
 
-		/* Remove old inpa, add new one */
-		gaim_input_remove(ndata->inpa);
-		ndata->inpa = 0;
-		gc->inpa = gaim_input_add(ndata->fd, GAIM_INPUT_READ, nap_callback, gc);
-
 		/* Our signon is complete */
 		account_online(gc);
 		serv_finish_login(gc);
 
-		return;
+		break;
+
+	case 201: /* MSG_SERVER_SEARCH_RESULT */
+		res = g_strsplit(buf, " ", 0);
+		serv_got_update(gc, res[0], 1, 0, 0, 0, 0);
+		g_strfreev(res);
+		break;
+
+	case 202: /* MSG_SERVER_SEARCH_END */
+		serv_got_update(gc, buf, 0, 0, 0, 0, 0);
+		break;
+
+	case 205: /* MSG_CLIENT_PRIVMSG */
+		res = g_strsplit(buf, " ", 2);
+		serv_got_im(gc, res[0], res[1], 0, time(NULL), -1);
+		g_strfreev(res);
+		break;
+
+	case 209: /* MSG_SERVER_USER_SIGNON */
+		/* USERNAME SPEED */
+		res = g_strsplit(buf, " ", 2);
+		serv_got_update(gc, res[0], 1, 0, 0, 0, 0);
+		g_strfreev(res);
+		break;
+
+	case 210: /* MSG_SERVER_USER_SIGNOFF */
+		/* USERNAME SPEED */
+		res = g_strsplit(buf, " ", 2);
+		serv_got_update(gc, res[0], 0, 0, 0, 0, 0);
+		g_strfreev(res);
+		break;
+
+	case 214: /* MSG_SERVER_STATS */
+		res = g_strsplit(buf, " ", 3);
+		buf2 = g_strdup_printf(_("users: %s, files: %s, size: %sGB"), res[0], res[1], res[2]);
+		serv_got_im(gc, "server", buf2, 0, time(NULL), -1);
+		g_free(buf2);
+		g_strfreev(res);
+		break;
+
+	case 301: /* MSG_SERVER_HOTLIST_ACK */
+		/* Our buddy was added successfully */
+		break;
+
+	case 302: /* MSG_SERVER_HOTLIST_ERROR */
+		buf2 = g_strdup_printf(_("Unable to add \"%s\" to your Napster hotlist"), buf);
+		do_error_dialog(buf2, NULL, GAIM_ERROR);
+		g_free(buf2);
+		break;
+
+	case 316: /* MSG_SERVER_DISCONNECTING */
+		/* we have been kicked off =^( */
+		do_error_dialog(_("You were disconnected from the server."), NULL, GAIM_ERROR);
+                signoff(gc);
+		break;
+
+	case 401: /* MSG_CLIENT_PART */
+		/* XXX - this is not handled correctly now: a kick fails to get through here! */
+		channel = find_channel_by_name(gc, buf);
+		// convo = find_conversation_by_id(gc, channel->id);
+		// gaim_conversation_destroy(convo);
+		if (!channel) /* in case we closed the chat window */
+			break;
+		serv_got_chat_left(gc, channel->id);
+		ndata->channels = g_slist_remove(ndata->channels, channel);
+		// g_free(channel->name);
+		g_free(channel);
+		break;
+
+	case 403: /* MSG_SERVER_PUBLIC */
+		res = g_strsplit(buf, " ", 3);
+		channel = find_channel_by_name(gc, res[0]);
+		if (channel)
+			serv_got_chat_in(gc, channel->id, res[1], 0, res[2], time((time_t)NULL));
+		g_strfreev(res);
+		break;
+
+	case 404: /* MSG_SERVER_NOSUCH */
+		/* abused by opennap servers to broadcast stuff */
+		serv_got_im(gc, "server", buf, 0, time(NULL), -1);
+		break;
+
+	case 405: /* MSG_SERVER_JOIN_ACK */
+		channel = find_channel_by_name(gc, buf);
+		if (!channel) {
+			chat_id++;
+			channel = g_new0(struct nap_channel, 1);
+			channel->id = chat_id;
+			channel->name = g_strdup(buf); /* XXX - This doesn't get freed when parting */
+			ndata->channels = g_slist_append(ndata->channels, channel);
+			serv_got_joined_chat(gc, chat_id, buf);
+		}
+		break;
+
+	case 407: /* MSG_SERVER_PART */
+		res = g_strsplit(buf, " ", 0);
+		channel = find_channel_by_name(gc, res[0]);
+		convo = find_conversation_by_id(gc, channel->id);
+		// remove_chat_buddy(convo, res[1], NULL);
+		gaim_chat_remove_user(GAIM_CHAT(convo), res[1], NULL);
+		g_strfreev(res);
+		break;
+
+	case 406: /* MSG_SERVER_JOIN */
+	case 408: /* MSG_SERVER_CHANNEL_USER_LIST */
+		res = g_strsplit(buf, " ", 4);
+		channel = find_channel_by_name(gc, res[0]);
+		convo = find_conversation_by_id(gc, channel->id);
+		// add_chat_buddy(convo, res[1], NULL);
+		gaim_chat_add_user(GAIM_CHAT(convo), res[1], NULL);
+		g_strfreev(res);
+		break;
+
+	case 409: /* MSG_SERVER_CHANNEL_USER_LIST_END */
+		break;
+
+	case 410: /* MSG_SERVER_TOPIC */
+		/* display the topic in the channel */
+		res = g_strsplit(buf, " ", 2);
+		channel = find_channel_by_name(gc, res[0]);
+		convo = find_conversation_by_id(gc, channel->id);
+		gaim_chat_set_topic(GAIM_CHAT(convo), res[0], res[1]);
+		g_strfreev(res);
+		break;
+
+	case 603: /* MSG_CLIENT_WHOIS */
+		buf2 = g_strdup_printf(_("%s requested your information"), buf);
+		serv_got_im(gc, "server", buf2, 0, time(NULL), -1);
+		g_free(buf2);
+		break;
+
+	case 604: /* MSG_SERVER_WHOIS_RESPONSE */
+		/* XXX - Format is:   "Elite" 37 " " "Active" 0 0 0 0 "gaim 0.63cvs" 0 0 192.168.1.41 32798 0 unknown flounder */
+		res = g_strsplit(buf, " ", 2);
+		g_show_info_text(gc, res[0], 2, res[1], NULL);
+		g_strfreev(res);
+		break;
+
+	case 621:
+	case 622: /* MSG_CLIENT_MOTD */
+		/* also replaces MSG_SERVER_MOTD, so we should display it */
+		serv_got_im(gc, "motd", buf, 0, time(NULL), -1);
+		break;
+
+	case 627: /* MSG_CLIENT_WALLOP */
+		/* abused by opennap server maintainers to broadcast stuff */
+		serv_got_im(gc, "wallop", buf, 0, time(NULL), -1);
+		break;
+
+	case 628: /* MSG_CLIENT_ANNOUNCE */
+		serv_got_im(gc, "announce", buf, 0, time(NULL), -1);
+		break;
+
+	case 748: /* MSG_SERVER_GHOST */
+		/* Looks like someone logged in as us! =-O */
+		do_error_dialog(_("You were disconnected from the server, because you logged on from a different location"), NULL, GAIM_ERROR);
+		signoff(gc);
+		break;
+
+	case 751: /* MSG_CLIENT_PING */
+		buf2 = g_strdup_printf(_("%s requested a PING"), buf);
+		serv_got_im(gc, "server", buf2, 0, time(NULL), -1);
+		g_free(buf2);
+		/* send back a pong */
+		/* MSG_CLIENT_PONG */
+		nap_write_packet(gc, 752, "%s", buf);
+		break;
+
+	case 752: /* MSG_CLIENT_PONG */
+		buf2 = g_strdup_printf("Received pong from %s", buf);
+		do_error_dialog(buf2, NULL, GAIM_INFO);
+		g_free(buf2);
+		break;
+
+	case 824: /* MSG_CLIENT_EMOTE */
+		res = g_strsplit(buf, " ", 3);
+		buf2 = g_strndup(res[2]+1, strlen(res[2]) - 2); /* chomp off the surround quotes */
+		buf3 = g_strdup_printf("/me %s", buf2);
+		g_free(buf2);
+		if ((channel = find_channel_by_name(gc, res[0]))) {
+			convo = find_conversation_by_id(gc, channel->id);
+			gaim_chat_write(GAIM_CHAT(convo), res[1], buf3, WFLAG_NICK, time(NULL));
+		}
+		g_free(buf3);
+		g_strfreev(res);
+		break;
+
+	default:
+	        gaim_debug(GAIM_DEBUG_MISC, "napster", "Unknown packet %hd: %s\n", command, buf);
+		break;
 	}
+
+	g_free(buf);
 }
 
-
+/* 002 - MSG_CLIENT_LOGIN */
 static void nap_login_connect(gpointer data, gint source, GaimInputCondition cond)
 {
 	struct gaim_connection *gc = data;
-	struct nap_data *ndata;
-	char buf[NAP_BUF_LEN];
+	struct nap_data *ndata = (struct nap_data *)gc->proto_data;
+	gchar *buf;
 
 	if (!g_slist_find(connections, gc)) {
 		close(source);
@@ -424,129 +561,56 @@
 		return;
 	}
 
-	ndata = gc->proto_data;
 	ndata->fd = source;
 
-	/* And write our signon data */
-	g_snprintf(buf, NAP_BUF_LEN, "%s %s 0 \"gaimster\" 0", gc->username, gc->password);
-	nap_write_packet(gc, 0x02, buf);
-	
+	/* Update the login progress status display */
+	buf = g_strdup_printf("Logging in: %s", gc->username);
+	set_login_progress(gc, 4, buf);
+	g_free(buf);
+
+	/* Write our signon data */
+	nap_write_packet(gc, 2, "%s %s 0 \"gaim %s\" 0", gc->username, gc->password, VERSION);
+
 	/* And set up the input watcher */
-	ndata->inpa = gaim_input_add(ndata->fd, GAIM_INPUT_READ, nap_login_callback, gc);
+	gc->inpa = gaim_input_add(ndata->fd, GAIM_INPUT_READ, nap_callback, gc);
 }
 
-
 static void nap_login(struct gaim_account *account)
 {
 	struct gaim_connection *gc = new_gaim_conn(account);
+
+	set_login_progress(gc, 2, _("Connecting"));
+
 	gc->proto_data = g_new0(struct nap_data, 1);
-
 	if (proxy_connect(account, account->proto_opt[USEROPT_NAPSERVER][0] ?
 				account->proto_opt[USEROPT_NAPSERVER] : NAP_SERVER,
 				account->proto_opt[USEROPT_NAPPORT][0] ?
 				atoi(account->proto_opt[USEROPT_NAPPORT]) : NAP_PORT,
 				nap_login_connect, gc) != 0) {
-		hide_login_progress(gc, "Unable to connect");
+		hide_login_progress(gc, _("Unable to connect"));
 		signoff(gc);
 	}
 }
 
-static GList *nap_chat_info(struct gaim_connection *gc)
-{
-	GList *m = NULL;
-	struct proto_chat_entry *pce;
-
-	pce = g_new0(struct proto_chat_entry, 1);
-	pce->label = _("Join what group:");
-	pce->identifier = "name";
-	m = g_list_append(m, pce);
-
-	return m;
-}
-
-static void nap_join_chat(struct gaim_connection *gc, GHashTable *data)
-{
-	gchar buf[NAP_BUF_LEN];
-	char *name = g_hash_table_lookup(data, "name");
-
-	/* Make sure the name has a # preceeding it */
-	if (name[0] != '#') 
-		g_snprintf(buf, NAP_BUF_LEN, "#%s", name);
-	else
-		g_snprintf(buf, NAP_BUF_LEN, "%s", name);
-
-	nap_write_packet(gc, 0x190, buf);
-}
-
-static void nap_chat_leave(struct gaim_connection *gc, int id)
-{
-	struct nap_data *ndata = (struct nap_data *)gc->proto_data;
-	struct nap_channel *channel = NULL;
-	
-	channel = find_channel_by_id(gc, id);
-
-	if (!channel) /* Again, I'm not sure how this would happen */
-		return;
-
-	nap_write_packet(gc, 0x191, channel->name);
-	
-	ndata->channels = g_slist_remove(ndata->channels, channel);
-	g_free(channel->name);
-	g_free(channel);
-	
-}
-
-static int nap_chat_send(struct gaim_connection *gc, int id, char *message)
-{
-	struct nap_channel *channel = NULL;
-	gchar buf[NAP_BUF_LEN];
-	
-	channel = find_channel_by_id(gc, id);
-
-	if (!channel) {
-		/* This shouldn't happen */
-		return -EINVAL;
-	}
-
-	g_snprintf(buf, NAP_BUF_LEN, "%s %s", channel->name, message);
-	nap_write_packet(gc, 0x192, buf);
-	return 0;
-}
-
-static void nap_add_buddy(struct gaim_connection *gc, const char *name)
-{
-	nap_write_packet(gc, 0xCF, name);
-}
-
-static void nap_remove_buddy(struct gaim_connection *gc, char *name, char *group)
-{
-	nap_write_packet(gc, 0x12F, name);
-}
-
 static void nap_close(struct gaim_connection *gc)
 {
 	struct nap_data *ndata = (struct nap_data *)gc->proto_data;
 	struct nap_channel *channel;
-	
+
 	if (gc->inpa)
 		gaim_input_remove(gc->inpa);
 
+	if (!ndata)
+		return;
+
+	g_free(ndata->email);
 	while (ndata->channels) {
 		channel = (struct nap_channel *)ndata->channels->data;
 		g_free(channel->name);
 		ndata->channels = g_slist_remove(ndata->channels, channel);
 		g_free(channel);
 	}
-
-	g_free(gc->proto_data);
-}
-
-static void nap_add_buddies(struct gaim_connection *gc, GList *buddies)
-{
-	while (buddies) {
-		nap_write_packet(gc, 0xd0, (char *)buddies->data);
-		buddies = buddies -> next;
-	}
+	g_free(ndata);
 }
 
 static const char* nap_list_icon(struct gaim_account *a, struct buddy *b)
@@ -560,80 +624,39 @@
 		*se = "offline";
 }
 
-static GaimPlugin *my_protocol = NULL;
-
-#if 0
-G_MODULE_EXPORT void napster_init(struct prpl *ret)
+static GList *nap_buddy_menu(struct gaim_connection *gc, const char *who)
 {
-	struct proto_user_opt *puo;
-	ret->add_buddies = nap_add_buddies;
-	ret->remove_buddy = nap_remove_buddy;
-//	ret->add_permit = NULL;
-//	ret->rem_permit = NULL;
-//	ret->add_deny = NULL;
-//	ret->rem_deny = NULL;
-//	ret->warn = NULL;
-//	ret->chat_invite = NULL;
-	ret->chat_leave = nap_chat_leave;
-//	ret->chat_whisper = NULL;
-//	ret->keepalive = NULL;
-	ret->protocol = PROTO_NAPSTER;
-	ret->name = g_strdup("Napster");
-	ret->list_icon = nap_list_icon;
-	ret->list_emblems = nap_list_emblems;
-	ret->login = nap_login;
-	ret->close = nap_close;
-	ret->send_im = nap_send_im;
-//	ret->set_info = NULL;
-//	ret->get_info = NULL;
-//	ret->set_away = NULL;
-//	ret->set_dir = NULL;
-//	ret->get_dir = NULL;
-//	ret->dir_search = NULL;
-//	ret->set_idle = NULL;
-//	ret->change_passwd = NULL;
-	ret->add_buddy = nap_add_buddy;
-//	ret->add_permit = NULL;
-//	ret->rem_permit = NULL;
-//	ret->add_deny = NULL;
-//	ret->rem_deny = NULL;
-//	ret->warn = NULL;
-	ret->chat_info = nap_chat_info;
-	ret->join_chat = nap_join_chat;
-//	ret->chat_invite = NULL;
-//	ret->chat_whisper = NULL;
-	ret->chat_send = nap_chat_send;
-//	ret->keepalive = NULL;
+	GList *m = NULL;
+	struct proto_buddy_menu *pbm;
 
-	puo = g_new0(struct proto_user_opt, 1);
-	puo->label = g_strdup(_("Server:"));
-	puo->def = g_strdup(NAP_SERVER);
-	puo->pos = USEROPT_NAPSERVER;
-	ret->user_opts = g_list_append(ret->user_opts, puo);
+	pbm = g_new0(struct proto_buddy_menu, 1);
+	pbm->label = _("Get Info");
+	pbm->callback = nap_get_info;
+	pbm->gc = gc;
+	m = g_list_append(m, pbm);
 
-	puo = g_new0(struct proto_user_opt, 1);
-	puo->label = g_strdup(_("Port:"));
-	puo->def = g_strdup("8888");
-	puo->pos = USEROPT_NAPPORT;
-	ret->user_opts = g_list_append(ret->user_opts, puo);
-
-	my_protocol = ret;
+	return m;
 }
 
-#ifndef STATIC
-
-G_MODULE_EXPORT void gaim_prpl_init(struct prpl *prpl)
+static GList *nap_chat_info(struct gaim_connection *gc)
 {
-	napster_init(prpl);
-	prpl->plug->desc.api_version = PLUGIN_API_VERSION;
+	GList *m = NULL;
+	struct proto_chat_entry *pce;
+
+	pce = g_new0(struct proto_chat_entry, 1);
+	pce->label = _("Join what group:");
+	pce->identifier = "group";
+	m = g_list_append(m, pce);
+
+	return m;
 }
-#endif
-#endif
+
+static GaimPlugin *my_protocol = NULL;
 
 static GaimPluginProtocolInfo prpl_info =
 {
 	GAIM_PROTO_NAPSTER,
-	0,
+	OPT_PROTO_CHAT_TOPIC,
 	NULL,
 	NULL,
 	nap_list_icon,
@@ -642,14 +665,14 @@
 	NULL,
 	NULL,
 	NULL,
-	NULL,
+	nap_buddy_menu,
 	nap_chat_info,
 	nap_login,
 	nap_close,
 	nap_send_im,
 	NULL,
 	NULL,
-	NULL,
+	nap_get_info,
 	NULL,
 	NULL,
 	NULL,
@@ -693,8 +716,8 @@
 	NULL,                                             /**< dependencies   */
 	GAIM_PRIORITY_DEFAULT,                            /**< priority       */
 
-	"prpl-napster",                                     /**< id             */
-	"NAPSTER",                                        /**< name           */
+	"prpl-napster",                                   /**< id             */
+	"Napster",                                        /**< name           */
 	VERSION,                                          /**< version        */
 	                                                  /**  summary        */
 	N_("NAPSTER Protocol Plugin"),
@@ -711,19 +734,18 @@
 	&prpl_info                                        /**< extra_info     */
 };
 
-static void
-__init_plugin(GaimPlugin *plugin)
+static void __init_plugin(GaimPlugin *plugin)
 {
 	struct proto_user_opt *puo;
 
 	puo = g_new0(struct proto_user_opt, 1);
-	puo->label = g_strdup("Server");
+	puo->label = g_strdup(_("Server"));
 	puo->def   = g_strdup(NAP_SERVER);
 	puo->pos   = USEROPT_NAPSERVER;
 	prpl_info.user_opts = g_list_append(prpl_info.user_opts, puo);
 
 	puo = g_new0(struct proto_user_opt, 1);
-	puo->label = g_strdup("Port:");
+	puo->label = g_strdup(_("Port:"));
 	puo->def   = g_strdup("8888");
 	puo->pos   = USEROPT_NAPPORT;
 	prpl_info.user_opts = g_list_append(prpl_info.user_opts, puo);
--- a/src/protocols/oscar/oscar.c	Thu May 15 20:36:37 2003 +0000
+++ b/src/protocols/oscar/oscar.c	Thu May 15 21:43:42 2003 +0000
@@ -6070,13 +6070,13 @@
 	struct proto_user_opt *puo;
 
 	puo = g_new0(struct proto_user_opt, 1);
-	puo->label = g_strdup("Auth Host:");
+	puo->label = g_strdup(_("Auth Host:"));
 	puo->def   = g_strdup("login.oscar.aol.com");
 	puo->pos   = USEROPT_AUTH;
 	prpl_info.user_opts = g_list_append(prpl_info.user_opts, puo);
 
 	puo = g_new0(struct proto_user_opt, 1);
-	puo->label = g_strdup("Auth Port:");
+	puo->label = g_strdup(_("Auth Port:"));
 	puo->def   = g_strdup("5190");
 	puo->pos   = USEROPT_AUTHPORT;
 	prpl_info.user_opts = g_list_append(prpl_info.user_opts, puo);