changeset 9488:2770a0e659ca

[gaim-migrate @ 10313] Stu Tomlinson assures me that this is a bunch of new and fancy features for SILC that we really need. I believe him because his name is pronounceable backward. This is from Patch #975859, and additionally fixes bug #981066 and mitigates #981080. We love you, Stu. committer: Tailor Script <tailor@pidgin.im>
author Ethan Blanton <elb@pidgin.im>
date Thu, 08 Jul 2004 18:45:01 +0000
parents c23f7045357c
children 85caa0722dfc
files ChangeLog src/protocols/silc/buddy.c src/protocols/silc/chat.c src/protocols/silc/ops.c src/protocols/silc/silc.c src/protocols/silc/silcgaim.h src/protocols/silc/util.c
diffstat 7 files changed, 610 insertions(+), 244 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Thu Jul 08 17:37:33 2004 +0000
+++ b/ChangeLog	Thu Jul 08 18:45:01 2004 +0000
@@ -2,6 +2,7 @@
 
 version 0.80cvs:
 	New Features:
+	* Yet more new commands and features for SILC (Stu Tomlinson)
 	* Support for the Epiphany web browser (Leonardo Serra)
 	* Status messages in Gadu-Gadu (Andrew (proton) Wellington)
 	* Ability to send files from the conversation window (Daniel Atallah)
--- a/src/protocols/silc/buddy.c	Thu Jul 08 17:37:33 2004 +0000
+++ b/src/protocols/silc/buddy.c	Thu Jul 08 18:45:01 2004 +0000
@@ -1426,11 +1426,7 @@
 	SilcClientConnection conn = sg->conn;
 	SilcClientID *client_id = b->proto_data;
 	SilcClientEntry client_entry;
-	SilcAttributePayload attr;
-	SilcAttributeMood mood = 0;
-	SilcAttributeContact contact;
-	SilcAttributeObjDevice device;
-	SilcAttributeObjGeo geo;
+	char *moodstr, *statusstr, *contactstr, *langstr, *devicestr, *tzstr, *geostr;
 	GString *s;
 	char *buf;
 	char tmp[256];
@@ -1449,104 +1445,47 @@
 	  g_string_append_printf(s, "\n<b>%s:</b> %s@%s", _("Username"),
 				 client_entry->username, client_entry->hostname);
 	if (client_entry->mode) {
-	  g_string_append_printf(s, "\n<b>%s:</b> ", _("Modes"));
+	  g_string_append_printf(s, "\n<b>%s:</b> ", _("User Modes"));
 	  memset(tmp, 0, sizeof(tmp));
 	  silcgaim_get_umode_string(client_entry->mode,
 				    tmp, sizeof(tmp) - strlen(tmp));
 	  g_string_append_printf(s, "%s", tmp);
 	}
 
-	attr = silcgaim_get_attr(client_entry->attrs, SILC_ATTRIBUTE_STATUS_MOOD);
-	if (attr && silc_attribute_get_object(attr, &mood, sizeof(mood))) {
-		if (mood)
-			g_string_append_printf(s, "\n<b>%s:</b> ", _("Mood"));
-		if (mood & SILC_ATTRIBUTE_MOOD_HAPPY)
-			g_string_append_printf(s, "[%s] ", _("Happy"));
-		if (mood & SILC_ATTRIBUTE_MOOD_SAD)
-			g_string_append_printf(s, "[%s] ", _("Sad"));
-		if (mood & SILC_ATTRIBUTE_MOOD_ANGRY)
-			g_string_append_printf(s, "[%s] ", _("Angry"));
-		if (mood & SILC_ATTRIBUTE_MOOD_JEALOUS)
-			g_string_append_printf(s, "[%s] ", _("Jealous"));
-		if (mood & SILC_ATTRIBUTE_MOOD_ASHAMED)
-			g_string_append_printf(s, "[%s] ", _("Ashamed"));
-		if (mood & SILC_ATTRIBUTE_MOOD_INVINCIBLE)
-			g_string_append_printf(s, "[%s] ", _("Invincible"));
-		if (mood & SILC_ATTRIBUTE_MOOD_INLOVE)
-			g_string_append_printf(s, "[%s] ", _("In Love"));
-		if (mood & SILC_ATTRIBUTE_MOOD_SLEEPY)
-			g_string_append_printf(s, "[%s] ", _("Sleepy"));
-		if (mood & SILC_ATTRIBUTE_MOOD_BORED)
-			g_string_append_printf(s, "[%s] ", _("Bored"));
-		if (mood & SILC_ATTRIBUTE_MOOD_EXCITED)
-			g_string_append_printf(s, "[%s] ", _("Excited"));
-		if (mood & SILC_ATTRIBUTE_MOOD_ANXIOUS)
-			g_string_append_printf(s, "[%s] ", _("Anxious"));
+	silcgaim_parse_attrs(client_entry->attrs, &moodstr, &statusstr, &contactstr, &langstr, &devicestr, &tzstr, &geostr);
+		if (moodstr) {
+			g_string_append_printf(s, "\n<b>%s:</b> %s", _("Mood"), moodstr);
+			g_free(moodstr);
+		}
+	if (statusstr) {
+		g_string_append_printf(s, "\n<b>%s:</b> %s", _("Status Text"), statusstr);
+		g_free(statusstr);
 	}
 
-	attr = silcgaim_get_attr(client_entry->attrs, SILC_ATTRIBUTE_STATUS_FREETEXT);
-	memset(tmp, 0, sizeof(tmp));
-	if (attr && silc_attribute_get_object(attr, tmp, sizeof(tmp)))
-		g_string_append_printf(s, "\n<b>%s:</b> %s", _("Status Text"), tmp);
+		if (contactstr) {
+			g_string_append_printf(s, "\n<b>%s:</b> %s", _("Preferred Contact"), contactstr);
+			g_free(contactstr);
+		}
 
-	attr = silcgaim_get_attr(client_entry->attrs, SILC_ATTRIBUTE_PREFERRED_CONTACT);
-	if (attr && silc_attribute_get_object(attr, &contact, sizeof(contact))) {
-		if (contact)
-			g_string_append_printf(s, "\n<b>%s:</b> ", _("Preferred Contact"));
-		if (contact & SILC_ATTRIBUTE_CONTACT_CHAT)
-			g_string_append_printf(s, "[%s] ", _("Chat"));
-		if (contact & SILC_ATTRIBUTE_CONTACT_EMAIL)
-			g_string_append_printf(s, "[%s] ", _("Email"));
-		if (contact & SILC_ATTRIBUTE_CONTACT_CALL)
-			g_string_append_printf(s, "[%s] ", _("Phone"));
-		if (contact & SILC_ATTRIBUTE_CONTACT_PAGE)
-			g_string_append_printf(s, "[%s] ", _("Paging"));
-		if (contact & SILC_ATTRIBUTE_CONTACT_SMS)
-			g_string_append_printf(s, "[%s] ", _("SMS"));
-		if (contact & SILC_ATTRIBUTE_CONTACT_MMS)
-			g_string_append_printf(s, "[%s] ", _("MMS"));
-		if (contact & SILC_ATTRIBUTE_CONTACT_VIDEO)
-			g_string_append_printf(s, "[%s] ", _("Video Conferencing"));
+	if (langstr) {
+		g_string_append_printf(s, "\n<b>%s:</b> %s", _("Preferred Language"), langstr);
+		g_free(langstr);
 	}
 
-	attr = silcgaim_get_attr(client_entry->attrs, SILC_ATTRIBUTE_PREFERRED_LANGUAGE);
-	memset(tmp, 0, sizeof(tmp));
-	if (attr && silc_attribute_get_object(attr, tmp, sizeof(tmp)))
-		g_string_append_printf(s, "\n<b>%s:</b> %s", _("Preferred Language"), tmp);
-
-	attr = silcgaim_get_attr(client_entry->attrs, SILC_ATTRIBUTE_DEVICE_INFO);
-	memset(&device, 0, sizeof(device));
-	if (attr && silc_attribute_get_object(attr, &device, sizeof(device))) {
-		g_string_append_printf(s, "\n<b>%s:</b> ", _("Device"));
-		if (device.type == SILC_ATTRIBUTE_DEVICE_COMPUTER)
-		    g_string_append_printf(s, "%s: ", _("Computer"));
-		if (device.type == SILC_ATTRIBUTE_DEVICE_MOBILE_PHONE)
-		    g_string_append_printf(s, "%s: ", _("Mobile Phone"));
-		if (device.type == SILC_ATTRIBUTE_DEVICE_PDA)
-		    g_string_append_printf(s, "%s: ", _("PDA"));
-		if (device.type == SILC_ATTRIBUTE_DEVICE_TERMINAL)
-		    g_string_append_printf(s, "%s: ", _("Terminal"));
-		g_string_append_printf(s, "%s %s %s %s",
-				       device.manufacturer ? device.manufacturer : "",
-				       device.version ? device.version : "",
-				       device.model ? device.model : "",
-				       device.language ? device.language : "");
+	if (devicestr) {
+		g_string_append_printf(s, "\n<b>%s:</b> %s", _("Device"), devicestr);
+		g_free(devicestr);
 	}
 
-	attr = silcgaim_get_attr(client_entry->attrs, SILC_ATTRIBUTE_TIMEZONE);
-	memset(tmp, 0, sizeof(tmp));
-	if (attr && silc_attribute_get_object(attr, tmp, sizeof(tmp)))
-		g_string_append_printf(s, "\n<b>%s:</b> %s", _("Timezone"), tmp);
+	if (tzstr) {
+		g_string_append_printf(s, "\n<b>%s:</b> %s", _("Timezone"), tzstr);
+		g_free(tzstr);
+	}
 
-	attr = silcgaim_get_attr(client_entry->attrs, SILC_ATTRIBUTE_GEOLOCATION);
-	memset(&geo, 0, sizeof(geo));
-	if (attr && silc_attribute_get_object(attr, &geo, sizeof(geo)))
-		g_string_append_printf(s, "\n<b>%s:</b> %s %s %s (%s)",
-				       _("Geolocation"),
-				       geo.longitude ? geo.longitude : "",
-				       geo.latitude ? geo.latitude : "",
-				       geo.altitude ? geo.altitude : "",
-				       geo.accuracy ? geo.accuracy : "");
+	if (geostr) {
+		g_string_append_printf(s, "\n<b>%s:</b> %s", _("Geolocation"), geostr);
+		g_free(geostr);
+	}
 
 	buf = g_string_free(s, FALSE);
 	return buf;
--- a/src/protocols/silc/chat.c	Thu Jul 08 17:37:33 2004 +0000
+++ b/src/protocols/silc/chat.c	Thu Jul 08 18:45:01 2004 +0000
@@ -78,7 +78,7 @@
 {
 	SilcGaim sg = gc->proto_data;
 	const char *chname;
-	char *buf, tmp[256];
+	char *buf, tmp[256], *tmp2;
 	GString *s;
 	SilcChannelEntry channel;
 	SilcHashTableList htl;
@@ -101,36 +101,42 @@
 	}
 
 	s = g_string_new("");
-	g_string_append_printf(s, _("Channel Name:\t\t%s\n"), channel->channel_name);
+	tmp2 = gaim_escape_html(channel->channel_name);
+	g_string_append_printf(s, _("<b>Channel Name:</b> %s"), tmp2);
+	g_free(tmp2);
 	if (channel->user_list && silc_hash_table_count(channel->user_list))
-		g_string_append_printf(s, _("User Count:\t\t%d\n"),
+		g_string_append_printf(s, _("<br><b>User Count:</b> %d"),
 				       (int)silc_hash_table_count(channel->user_list));
 
 	silc_hash_table_list(channel->user_list, &htl);
 	while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
 		if (chu->mode & SILC_CHANNEL_UMODE_CHANFO) {
-			g_string_append_printf(s, _("Channel Founder:\t%s\n"),
-					       chu->client->nickname);
+			tmp2 = gaim_escape_html(chu->client->nickname);
+			g_string_append_printf(s, _("<br><b>Channel Founder:</b> %s"),
+					       tmp2);
+			g_free(tmp2);
 			break;
 		}
 	}
 	silc_hash_table_list_reset(&htl);
 
 	if (channel->channel_key)
-		g_string_append_printf(s, _("Channel Cipher:\t\t%s\n"),
+		g_string_append_printf(s, _("<br><b>Channel Cipher:</b> %s"),
 				       silc_cipher_get_name(channel->channel_key));
 	if (channel->hmac)
-		g_string_append_printf(s, _("Channel HMAC:\t\t%s\n"),
+		g_string_append_printf(s, _("<br><b>Channel HMAC:</b> %s"),
 				       silc_hmac_get_name(channel->hmac));
 
-	if (channel->topic)
-		g_string_append_printf(s, _("\nChannel Topic:\n\t%s\n"), channel->topic);
+	if (channel->topic) {
+		tmp2 = gaim_escape_html(channel->topic);
+		g_string_append_printf(s, _("<br><b>Channel Topic:</b><br>%s"), tmp2);
+		g_free(tmp2);
+	}
 
 	if (channel->mode) {
-		g_string_append_printf(s, _("\nChannel Modes:\n"));
+		g_string_append_printf(s, _("<br><b>Channel Modes:</b> "));
 		silcgaim_get_chmode_string(channel->mode, tmp, sizeof(tmp));
 		g_string_append_printf(s, tmp);
-		g_string_append_printf(s, "\n");
 	}
 
 	if (channel->founder_key) {
@@ -141,8 +147,8 @@
 		fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
 		babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
 
-		g_string_append_printf(s, _("\nFounder Key Fingerprint:\n%s\n\n"), fingerprint);
-		g_string_append_printf(s, _("Founder Key Babbleprint:\n%s"), babbleprint);
+		g_string_append_printf(s, _("<br><b>Founder Key Fingerprint:</b><br>%s"), fingerprint);
+		g_string_append_printf(s, _("<br><b>Founder Key Babbleprint:</b><br>%s"), babbleprint);
 
 		silc_free(fingerprint);
 		silc_free(babbleprint);
@@ -150,10 +156,7 @@
 	}
 
 	buf = g_string_free(s, FALSE);
-	gaim_notify_message(NULL, GAIM_NOTIFY_MSG_INFO,
-			    _("Channel Information"),
-			    _("Channel Information"),
-			    buf, NULL, NULL);
+	gaim_notify_formatted(gc, NULL, _("Channel Information"), NULL, buf, NULL, NULL);
 	g_free(buf);
 }
 
--- a/src/protocols/silc/ops.c	Thu Jul 08 17:37:33 2004 +0000
+++ b/src/protocols/silc/ops.c	Thu Jul 08 18:45:01 2004 +0000
@@ -911,13 +911,14 @@
 			SilcUInt32 idle, mode;
 			SilcBuffer channels, user_modes;
 			SilcClientEntry client_entry;
-			char *buf, tmp[1024];
+			char *buf, tmp[1024], *tmp2;
+			char *moodstr, *statusstr, *contactstr, *langstr, *devicestr, *tzstr, *geostr;
 			GString *s;
 
 			if (!success) {
 				gaim_notify_error(gc, _("User Information"),
-						  _("Cannot get user information"),
-						  silc_get_status_message(status));
+						_("Cannot get user information"),
+						silc_get_status_message(status));
 				break;
 			}
 
@@ -934,38 +935,88 @@
 			user_modes = va_arg(vp, SilcBuffer);
 
 			s = g_string_new("");
-			g_string_append_printf(s, "%s:\t\t%s\n", _("Nickname"), client_entry->nickname);
-			if (client_entry->realname)
-				g_string_append_printf(s, "%s:\t%s\n", _("Realname"), client_entry->realname);
-			if (client_entry->username)
-				g_string_append_printf(s, "%s:\t\t%s\n", _("Username"), client_entry->username);
-			if (client_entry->hostname)
-				g_string_append_printf(s, "%s:\t\t%s\n", _("Hostname"), client_entry->hostname);
+			tmp2 = gaim_escape_html(client_entry->nickname);
+			g_string_append_printf(s, "<b>%s:</b> %s", _("Nickname"), tmp2);
+			g_free(tmp2);
+			if (client_entry->realname) {
+				tmp2 = gaim_escape_html(client_entry->realname);
+				g_string_append_printf(s, "<br><b>%s:</b> %s", _("Realname"), tmp2);
+				g_free(tmp2);
+			}
+			if (client_entry->username) {
+				tmp2 = gaim_escape_html(client_entry->username);
+				if (client_entry->hostname)
+					g_string_append_printf(s, "<br><b>%s:</b> %s@%s", _("Username"), tmp2, client_entry->hostname);
+				else
+					g_string_append_printf(s, "<br><b>%s:</b> %s", _("Username"), tmp2);
+				g_free(tmp2);
+			}
+
+			if (client_entry->mode) {
+				g_string_append_printf(s, "<br><b>%s:</b> ", _("User Modes"));
+				memset(tmp, 0, sizeof(tmp));
+				silcgaim_get_umode_string(client_entry->mode,
+						tmp, sizeof(tmp) - strlen(tmp));
+				g_string_append_printf(s, "%s", tmp);
+			}
+
+			silcgaim_parse_attrs(client_entry->attrs, &moodstr, &statusstr, &contactstr, &langstr, &devicestr, &tzstr, &geostr);
+			if (moodstr) {
+				g_string_append_printf(s, "<br><b>%s:</b> %s", _("Mood"), moodstr);
+				g_free(moodstr);
+			}
+
+			if (statusstr) {
+				tmp2 = gaim_escape_html(statusstr);
+				g_string_append_printf(s, "<br><b>%s:</b> %s", _("Status Text"), tmp2);
+				g_free(statusstr);
+				g_free(tmp2);
+			}
+
+			if (contactstr) {
+				g_string_append_printf(s, "<br><b>%s:</b> %s", _("Preferred Contact"), contactstr);
+				g_free(contactstr);
+			}
+
+			if (langstr) {
+				g_string_append_printf(s, "<br><b>%s:</b> %s", _("Preferred Language"), langstr);
+				g_free(langstr);
+			}
+
+			if (devicestr) {
+				g_string_append_printf(s, "<br><b>%s:</b> %s", _("Device"), devicestr);
+				g_free(devicestr);
+			}
+
+			if (tzstr) {
+				g_string_append_printf(s, "<br><b>%s:</b> %s", _("Timezone"), tzstr);
+				g_free(tzstr);
+			}
+
+			if (geostr) {
+				g_string_append_printf(s, "<br><b>%s:</b> %s", _("Geolocation"), geostr);
+				g_free(geostr);
+			}
+
 			if (client_entry->server)
-				g_string_append_printf(s, "%s:\t\t%s\n", _("Server"), client_entry->server);
-
-			if (mode) {
-				memset(tmp, 0, sizeof(tmp));
-				silcgaim_get_umode_string(mode, tmp, sizeof(tmp) - 1);
-				g_string_append_printf(s, "%s:\t%s\n", _("User Mode"), tmp);
-			}
+				g_string_append_printf(s, "<br><b>%s:</b> %s", _("Server"), client_entry->server);
 
 			if (channels && user_modes) {
 				SilcUInt32 *umodes;
 				SilcDList list =
 					silc_channel_payload_parse_list(channels->data,
-									channels->len);
+							channels->len);
 				if (list && silc_get_mode_list(user_modes,
-							       silc_dlist_count(list),
-							       &umodes)) {
+							silc_dlist_count(list),
+							&umodes)) {
 					SilcChannelPayload entry;
 					int i = 0;
 
-					g_string_append_printf(s, "\n%s:\n", _("Channels"));
+					g_string_append_printf(s, "<br><b>%s:</b> ", _("Currently on"));
 					memset(tmp, 0, sizeof(tmp));
 					silc_dlist_start(list);
 					while ((entry = silc_dlist_get(list))
-					       != SILC_LIST_END) {
+							!= SILC_LIST_END) {
 						SilcUInt32 name_len;
 						char *m = silc_client_chumode_char(umodes[i++]);
 						char *name = silc_channel_get_name(entry, &name_len);
@@ -976,7 +1027,9 @@
 						silc_free(m);
 
 					}
-					g_string_append_printf(s, "%s\n", tmp);
+					tmp2 = gaim_escape_html(tmp);
+					g_string_append_printf(s, "%s", tmp2);
+					g_free(tmp2);
 					silc_free(umodes);
 				}
 			}
@@ -988,8 +1041,8 @@
 				pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len);
 				fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
 				babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
-				g_string_append_printf(s, "\n%s:\n%s\n\n", _("Public Key Fingerprint"), fingerprint);
-				g_string_append_printf(s, "%s:\n%s", _("Public Key Babbleprint"), babbleprint);
+				g_string_append_printf(s, "<br><b>%s:</b><br>%s", _("Public Key Fingerprint"), fingerprint);
+				g_string_append_printf(s, "<br><b>%s:</b><br>%s", _("Public Key Babbleprint"), babbleprint);
 				silc_free(fingerprint);
 				silc_free(babbleprint);
 				silc_free(pk);
@@ -999,14 +1052,74 @@
 #if 0 /* XXX for now, let's not show attrs here */
 			if (client_entry->attrs)
 				gaim_request_action(NULL, _("User Information"),
-						    _("User Information"),
-						    buf, 1, client_entry, 2,
-						    _("OK"), G_CALLBACK(silcgaim_whois_more),
-						    _("More..."), G_CALLBACK(silcgaim_whois_more));
+						_("User Information"),
+						buf, 1, client_entry, 2,
+						_("OK"), G_CALLBACK(silcgaim_whois_more),
+						_("More..."), G_CALLBACK(silcgaim_whois_more));
 			else
 #endif
-				gaim_notify_info(NULL, _("User Information"),
-						 _("User Information"), buf);
+				gaim_notify_formatted(gc, NULL, _("Buddy Information"), NULL, buf, NULL, NULL);
+			g_free(buf);
+		}
+		break;
+
+	case SILC_COMMAND_WHOWAS:
+		{
+			SilcClientEntry client_entry;
+			char *buf, *nickname, *realname, *username, *tmp;
+			GString *s;
+
+			if (!success) {
+				gaim_notify_error(gc, _("User Information"),
+						  _("Cannot get user information"),
+						  silc_get_status_message(status));
+				break;
+			}
+
+			client_entry = va_arg(vp, SilcClientEntry);
+			nickname = va_arg(vp, char *);
+			username = va_arg(vp, char *);
+			realname = va_arg(vp, char *);
+			if (!nickname)
+				break;
+
+			s = g_string_new("");
+			tmp = gaim_escape_html(nickname);
+			g_string_append_printf(s, "<b>%s:</b> %s", _("Nickname"), tmp);
+			g_free(tmp);
+			if (realname) {
+				tmp = gaim_escape_html(realname);
+				g_string_append_printf(s, "<br><b>%s:</b> %s", _("Realname"), tmp);
+				g_free(tmp);
+			}
+			if (username) {
+				tmp = gaim_escape_html(username);
+				if (client_entry && client_entry->hostname)
+					g_string_append_printf(s, "<br><b>%s:</b> %s@%s", _("Username"), tmp, client_entry->hostname);
+				else
+					g_string_append_printf(s, "<br><b>%s:</b> %s", _("Username"), tmp);
+				g_free(tmp);
+			}
+			if (client_entry && client_entry->server)
+				g_string_append_printf(s, "<br><b>%s:</b> %s", _("Server"), client_entry->server);
+
+
+			if (client_entry && client_entry->public_key) {
+				char *fingerprint, *babbleprint;
+				unsigned char *pk;
+				SilcUInt32 pk_len;
+				pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len);
+				fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
+				babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
+				g_string_append_printf(s, "<br><b>%s:</b><br>%s", _("Public Key Fingerprint"), fingerprint);
+				g_string_append_printf(s, "<br><b>%s:</b><br>%s", _("Public Key Babbleprint"), babbleprint);
+				silc_free(fingerprint);
+				silc_free(babbleprint);
+				silc_free(pk);
+			}
+
+			buf = g_string_free(s, FALSE);
+			gaim_notify_formatted(gc, NULL, _("Buddy Information"), NULL, buf, NULL, NULL);
 			g_free(buf);
 		}
 		break;
@@ -1062,6 +1175,8 @@
 			const char *oldnick;
 
 			if (!success) {
+				gaim_notify_error(gc, _("Nick"), _("Failed to change nickname"),
+						silc_get_status_message(status));
 				return;
 			}
 
@@ -1082,6 +1197,8 @@
 				}
 			}
 			silc_hash_table_list_reset(&htl);
+
+			gaim_connection_set_display_name(gc, local_entry->nickname);
 		}
 		break;
 
@@ -1170,13 +1287,97 @@
 				g_snprintf(tmp, sizeof(tmp), "Server: %s\n%s",
 					   server_name, server_info);
 				msg = g_markup_escape_text(tmp, strlen(tmp));
-				gaim_notify_info(NULL, _("Server Information"),
-						 _("Server Information"), msg);
+				gaim_notify_info(gc, NULL, _("Server Information"), msg);
 				g_free(msg);
 			}
 		}
 		break;
 
+	case SILC_COMMAND_STATS:
+		{
+			SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
+			my_router_ops, cell_clients, cell_channels, cell_servers,
+			clients, channels, servers, routers, server_ops, router_ops;
+			SilcUInt32 buffer_length;
+			SilcBufferStruct buf;
+
+			unsigned char *server_stats;
+			char *msg;
+
+			if (!success) {
+				gaim_notify_error(gc, _("Server Statistics"),
+						_("Cannot get server statisticss"),
+						silc_get_status_message(status));
+				return;
+			}
+
+			server_stats = va_arg(vp, unsigned char *);
+			buffer_length = va_arg(vp, SilcUInt32);
+			if (!server_stats || !buffer_length) {
+				gaim_notify_error(gc, _("Server Statistics"),
+						_("No server statisitics available"), NULL);
+				break;
+			}
+			silc_buffer_set(&buf, server_stats, buffer_length);
+			silc_buffer_unformat(&buf,
+					SILC_STR_UI_INT(&starttime),
+					SILC_STR_UI_INT(&uptime),
+					SILC_STR_UI_INT(&my_clients),
+					SILC_STR_UI_INT(&my_channels),
+					SILC_STR_UI_INT(&my_server_ops),
+					SILC_STR_UI_INT(&my_router_ops),
+					SILC_STR_UI_INT(&cell_clients),
+					SILC_STR_UI_INT(&cell_channels),
+					SILC_STR_UI_INT(&cell_servers),
+					SILC_STR_UI_INT(&clients),
+					SILC_STR_UI_INT(&channels),
+					SILC_STR_UI_INT(&servers),
+					SILC_STR_UI_INT(&routers),
+					SILC_STR_UI_INT(&server_ops),
+					SILC_STR_UI_INT(&router_ops),
+					SILC_STR_END);
+
+			msg = g_strdup_printf(_("Local server start time: %s\n"
+					"Local server uptime: %s\n"
+					"Local server clients: %d\n"
+					"Local server channels: %d\n"
+					"Local server operators: %d\n"
+					"Local router operators: %d\n"
+					"Local cell clients: %d\n"
+					"Local cell channels: %d\n"
+					"Local cell servers: %d\n"
+					"Total clients: %d\n"
+					"Total channels: %d\n"
+					"Total servers: %d\n"
+					"Total routers: %d\n"
+					"Total server operators: %d\n"
+					"Total router operators: %d\n"),
+					silc_get_time(starttime),
+					gaim_str_seconds_to_string((int)uptime),
+					(int)my_clients, (int)my_channels, (int)my_server_ops, (int)my_router_ops,
+					(int)cell_clients, (int)cell_channels, (int)cell_servers,
+					(int)clients, (int)channels, (int)servers, (int)routers,
+					(int)server_ops, (int)router_ops);
+
+			gaim_notify_info(gc, NULL,
+					_("Network Statistics"), msg);
+			g_free(msg);
+		}
+		break;
+
+	case SILC_COMMAND_PING:
+		{
+			if (!success) {
+				gaim_notify_error(gc, _("Ping"), _("Ping failed"),
+								  silc_get_status_message(status));
+				return;
+			}
+
+			gaim_notify_info(gc, _("Ping"), _("Ping reply received from server"),
+							 NULL);
+		}
+		break;
+
 	case SILC_COMMAND_KILL:
 		if (!success) {
 			gaim_notify_error(gc, _("Kill User"),
@@ -1219,7 +1420,7 @@
 
 /* Called to indicate that connection was either successfully established
    or connecting failed.  This is also the first time application receives
-   the SilcClientConnection objecet which it should save somewhere.
+   the SilcClientConnection object which it should save somewhere.
    If the `success' is FALSE the application must always call the function
    silc_client_close_connection. */
 
@@ -1251,16 +1452,15 @@
 		if (reject_watch || block_invites || block_ims) {
 			char m[5];
 			g_snprintf(m, sizeof(m), "+%s%s%s",
-				   reject_watch ? "w" : "",
-				   block_invites ? "I" : "",
-				   block_ims ? "P" : "");
+					   reject_watch ? "w" : "",
+					   block_invites ? "I" : "",
+					   block_ims ? "P" : "");
 			silc_client_command_call(sg->client, sg->conn, NULL,
-						 "UMODE", m, NULL);
+					"UMODE", m, NULL);
 		}
 
 		return;
 		break;
-
 	case SILC_CLIENT_CONN_ERROR:
 		gaim_connection_error(gc, _("Error during connecting to SILC Server"));
 		unlink(silcgaim_session_file(gaim_account_get_username(sg->account)));
--- a/src/protocols/silc/silc.c	Thu Jul 08 17:37:33 2004 +0000
+++ b/src/protocols/silc/silc.c	Thu Jul 08 18:45:01 2004 +0000
@@ -715,6 +715,7 @@
 {
 	GaimConnection *gc = (GaimConnection *) action->context;
 	SilcGaim sg;
+	char *tmp;
 
 	if (!gc)
 		return;
@@ -729,8 +730,10 @@
 		return;
 	}
 
-	gaim_notify_formatted(gc, _("Message of the Day"), _("Message of the Day"), NULL,
-			      sg->motd, NULL, NULL);
+	tmp = gaim_escape_html(sg->motd);
+	gaim_notify_formatted(gc, NULL, _("Message of the Day"), NULL,
+			      tmp, NULL, NULL);
+	g_free(tmp);
 }
 
 static void
@@ -955,8 +958,10 @@
 	} else
 		convo = conv;
 
-	if (gaim_conversation_get_type(convo) != GAIM_CONV_CHAT)
+	if (gaim_conversation_get_type(convo) != GAIM_CONV_CHAT) {
+		*error = g_strdup(_("Failed to leave channel"));
 		return GAIM_CMD_RET_FAILED;
+	}
 
 	id = gaim_conv_chat_get_id(GAIM_CONV_CHAT(convo));
 
@@ -974,6 +979,8 @@
 {
 	GaimConnection *gc;
 	int id = 0;
+	char *buf, *tmp;
+	const char *topic;
 
 	gc = gaim_conversation_get_gc(conv);
 	id = gaim_conv_chat_get_id(GAIM_CONV_CHAT(conv));
@@ -981,6 +988,25 @@
 	if (gc == NULL || id == 0)
 		return GAIM_CMD_RET_FAILED;
 
+	if (!args || !args[0]) {
+		topic = gaim_conv_chat_get_topic (GAIM_CONV_CHAT(conv));
+		if (topic) {
+			tmp = gaim_escape_html(topic);
+			buf = g_strdup_printf(_("current topic is: %s"), tmp);
+			g_free(tmp);
+		} else
+			buf = g_strdup(_("No topic is set"));
+		gaim_conv_chat_write(GAIM_CONV_CHAT(conv), gc->account->username, buf,
+							 GAIM_MESSAGE_SYSTEM|GAIM_MESSAGE_NO_LOG, time(NULL));
+		g_free(buf);
+
+	}
+
+	if (args && args[0] && (strlen(args[0]) > 255)) {
+		*error = g_strdup(_("Topic too long"));
+		return GAIM_CMD_RET_FAILED;
+	}
+
 	silcgaim_chat_set_topic(gc, id, args ? args[0] : NULL);
 
 	return GAIM_CMD_RET_OK;
@@ -1057,8 +1083,10 @@
 	GaimConnection *gc;
 	GaimAccount *account;
 
-	if (!args || !args[0])
+	if (!args || !args[0]) {
+		*error = g_strdup(_("You must specify a nick"));
 		return GAIM_CMD_RET_FAILED;
+	}
 
 	gc = gaim_conversation_get_gc(conv);
 
@@ -1086,6 +1114,7 @@
 {
 	GaimConnection *gc;
 	SilcGaim sg;
+	char *tmp;
 
 	gc = gaim_conversation_get_gc(conv);
 
@@ -1098,13 +1127,14 @@
 		return GAIM_CMD_RET_FAILED;
 
 	if (!sg->motd) {
-		gaim_notify_error(gc, _("Message of the Day"), _("No Message of the Day available"),
-						  _("There is no Message of the Day associated with this connection"));
+		*error = g_strdup(_("There is no Message of the Day associated with this connection"));
 		return GAIM_CMD_RET_FAILED;
 	}
 
-	gaim_notify_formatted(gc, _("Message of the Day"), _("Message of the Day"), NULL,
-			sg->motd, NULL, NULL);
+	tmp = gaim_escape_html(sg->motd);
+	gaim_notify_formatted(gc, NULL, _("Message of the Day"), NULL,
+			tmp, NULL, NULL);
+	g_free(tmp);
 
 	return GAIM_CMD_RET_OK;
 }
@@ -1131,6 +1161,59 @@
 	return GAIM_CMD_RET_OK;
 }
 
+static GaimCmdRet silcgaim_cmd_cmode(GaimConversation *conv,
+		const char *cmd, char **args, char **error)
+{
+	GaimConnection *gc;
+	SilcGaim sg;
+	SilcChannelEntry channel;
+	char *silccmd, *silcargs, *msg, tmp[256];
+	const char *chname;
+
+	gc = gaim_conversation_get_gc(conv);
+
+	if (gc == NULL || !args || gc->proto_data == NULL)
+		return GAIM_CMD_RET_FAILED;
+
+	sg = gc->proto_data;
+
+	if (args[0])
+		chname = args[0];
+	else
+		chname = gaim_conversation_get_name(conv);
+
+	if (!args[1]) {
+		channel = silc_client_get_channel(sg->client, sg->conn,
+										  (char *)chname);
+		if (!channel) {
+			*error = g_strdup_printf(_("channel %s not found"), chname);
+			return GAIM_CMD_RET_FAILED;
+		}
+		if (channel->mode) {
+			silcgaim_get_chmode_string(channel->mode, tmp, sizeof(tmp));
+			msg = g_strdup_printf(_("channel modes for %s: %s"), chname, tmp);
+		} else {
+			msg = g_strdup_printf(_("no channel modes are set on %s"), chname);
+		}
+		gaim_conv_chat_write(GAIM_CONV_CHAT(conv), "",
+							 msg, GAIM_MESSAGE_SYSTEM|GAIM_MESSAGE_NO_LOG, time(NULL));
+		g_free(msg);
+		return GAIM_CMD_RET_OK;
+	}
+
+	silcargs = g_strjoinv(" ", args);
+	silccmd = g_strconcat(cmd, " ", args ? silcargs : NULL, NULL);
+	g_free(silcargs);
+	if (!silc_client_command_call(sg->client, sg->conn, silccmd)) {
+		g_free(silccmd);
+		*error = g_strdup_printf(_("Failed to set cmodes for %s"), args[0]);
+		return GAIM_CMD_RET_FAILED;
+	}
+	g_free(silccmd);
+
+	return GAIM_CMD_RET_OK;
+}
+
 static GaimCmdRet silcgaim_cmd_generic(GaimConversation *conv,
 		const char *cmd, char **args, char **error)
 {
@@ -1153,6 +1236,7 @@
 	g_free(silcargs);
 	if (!silc_client_command_call(sg->client, sg->conn, silccmd)) {
 		g_free(silccmd);
+		*error = g_strdup_printf(_("Unknown command: %s, (may be a Gaim bug)"), cmd);
 		return GAIM_CMD_RET_FAILED;
 	}
 	g_free(silccmd);
@@ -1198,8 +1282,10 @@
 	if (sg == NULL)
 		return GAIM_CMD_RET_FAILED;
 
-	if (!silc_client_command_call(sg->client, sg->conn, args[0]))
+	if (!silc_client_command_call(sg->client, sg->conn, args[0])) {
+		*error = g_strdup_printf(_("Unknown command: %s"), args[0]);
 		return GAIM_CMD_RET_FAILED;
+	}
 
 	return GAIM_CMD_RET_OK;
 }
@@ -1213,11 +1299,11 @@
 	gaim_cmd_register("part", "w", GAIM_CMD_P_PRPL,
 			GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT |
 			GAIM_CMD_FLAG_PRPL_ONLY | GAIM_CMD_FLAG_ALLOW_WRONG_ARGS,
-			"prpl-silc", silcgaim_cmd_chat_part, _("part:  Leave the chat"));
+			"prpl-silc", silcgaim_cmd_chat_part, _("part [channel]:  Leave the chat"));
 	gaim_cmd_register("leave", "w", GAIM_CMD_P_PRPL,
 			GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT |
 			GAIM_CMD_FLAG_PRPL_ONLY | GAIM_CMD_FLAG_ALLOW_WRONG_ARGS,
-			"prpl-silc", silcgaim_cmd_chat_part, _("leave:  Leave the chat"));
+			"prpl-silc", silcgaim_cmd_chat_part, _("leave [channel]:  Leave the chat"));
 	gaim_cmd_register("topic", "s", GAIM_CMD_P_PRPL,
 			GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY |
 			GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc",
@@ -1254,73 +1340,77 @@
 	gaim_cmd_register("quit", "s", GAIM_CMD_P_PRPL,
 			GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY |
 			GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcgaim_cmd_quit,
-			"");
+			_("quit [message]:  Disconnect from the server, with an optional message"));
 	gaim_cmd_register("call", "s", GAIM_CMD_P_PRPL,
 			GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY,
 			"prpl-silc", silcgaim_cmd_call,
-			"");
+			_("call &lt;command&gt;:  Call any silc client command"));
 	/* These below just get passed through for the silc client library to deal with */
 	gaim_cmd_register("kill", "ws", GAIM_CMD_P_PRPL,
 			GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY |
 			GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcgaim_cmd_generic,
-			"");
+			_("kill &lt;nick&gt; [-pubkey|&lt;reason&gt;]:  Kill nick"));
 	gaim_cmd_register("nick", "w", GAIM_CMD_P_PRPL,
 			GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY,
 			"prpl-silc", silcgaim_cmd_generic,
-			"");
-	gaim_cmd_register("cmode", "wws", GAIM_CMD_P_PRPL,
+			_("nick &lt;newnick&gt;:  Change your nickname"));
+	gaim_cmd_register("whowas", "ww", GAIM_CMD_P_PRPL,
 			GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY |
 			GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcgaim_cmd_generic,
-			"");
+			_("whowas &lt;nick&gt;:  View nick's information"));
+	gaim_cmd_register("cmode", "wws", GAIM_CMD_P_PRPL,
+			GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY |
+			GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcgaim_cmd_cmode,
+			_("cmode &lt;channel&gt; [+|-&lt;modes&gt]; [arguments]:  Change or display channel modes"));
 	gaim_cmd_register("cumode", "wws", GAIM_CMD_P_PRPL,
 			GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY |
 			GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcgaim_cmd_generic,
-			"");
+			_("cumode &lt;channel&gt; +|-&lt;modes&gt; &lt;nick&gt;:  Change nick's modes on channel"));
 	gaim_cmd_register("umode", "w", GAIM_CMD_P_PRPL,
 			GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY,
 			"prpl-silc", silcgaim_cmd_generic,
-			_("umode &lt;usermodes&gt;:  Set your user options"));
+			_("umode &lt;usermodes&gt;:  Set your modes in the network"));
 	gaim_cmd_register("oper", "s", GAIM_CMD_P_PRPL,
 			GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY,
 			"prpl-silc", silcgaim_cmd_generic,
-			"");
+			_("oper &lt;nick&gt; [-pubkey]:  Get server operator privileges"));
 	gaim_cmd_register("invite", "ws", GAIM_CMD_P_PRPL,
 			GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY |
 			GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcgaim_cmd_generic,
-			"");
+			_("invite &lt;channel&gt; [-|+]&lt;nick&gt;:  invite nick or add/remove from channel invite list"));
 	gaim_cmd_register("kick", "wws", GAIM_CMD_P_PRPL,
 			GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY |
 			GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcgaim_cmd_generic,
-			"");
-	gaim_cmd_register("info", "ww", GAIM_CMD_P_PRPL,
+			_("kick &lt;channel&gt; &lt;nick&gt; [comment]:  Kick client from channel"));
+	gaim_cmd_register("info", "w", GAIM_CMD_P_PRPL,
 			GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY |
 			GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcgaim_cmd_generic,
-			"");
+			_("info [server]:  View server administrative details"));
 	gaim_cmd_register("ban", "ww", GAIM_CMD_P_PRPL,
 			GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY |
 			GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcgaim_cmd_generic,
-			"");
+			_("ban [&lt;channel&gt; +|-&lt;nick&gt;]:  Ban client from channel"));
+	gaim_cmd_register("getkey", "w", GAIM_CMD_P_PRPL,
+			GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY,
+			"prpl-silc", silcgaim_cmd_generic,
+			_("getkey &lt;nick|server&gt;:  Retrieve client's or server's public key"));
+	gaim_cmd_register("stats", "", GAIM_CMD_P_PRPL,
+			GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY,
+			"prpl-silc", silcgaim_cmd_generic,
+			_("stats:  View server and network statistics"));
 	gaim_cmd_register("ping", "", GAIM_CMD_P_PRPL,
 			GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY,
 			"prpl-silc", silcgaim_cmd_generic,
-			"");
-#if 0 /* Gaim doesn't handle the reply for these yet */
-	gaim_cmd_register("stats", "", GAIM_CMD_P_PRPL,
-			GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY,
-			"prpl-silc", silcgaim_cmd_generic,
-			"");
-	gaim_cmd_register("whowas", "ww", GAIM_CMD_P_PRPL,
-			GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY |
-			GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcgaim_cmd_generic,
-			"");
-	gaim_cmd_register("users", "s", GAIM_CMD_P_PRPL,
-			GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY,
-			"prpl-silc", silcgaim_cmd_generic,
-			"");
-	gaim_cmd_register("getkey", "w", GAIM_CMD_P_PRPL,
-			GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY,
-			"prpl-silc", silcgaim_cmd_generic,
-			"");
+			_("ping:  Send PING to the connected server"));
+#if 0 /* Gaim doesn't handle these yet */
+	gaim_cmd_register("users", "w", GAIM_CMD_P_PRPL,
+			GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY,
+			"prpl-silc", silcgaim_cmd_users,
+			_("users &lt;channel&gt;:  List users in channel"));
+	gaim_cmd_register("names", "ww", GAIM_CMD_P_PRPL,
+			GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY |
+			GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-silc", silcgaim_cmd_names,
+			_("names [-count|-ops|-halfops|-voices|-normal] &lt;channel(s)&gt;:  List specific users in channel(s)"));
 #endif
 }
 
@@ -1384,61 +1474,61 @@
 	GAIM_PRPL_API_VERSION,
 	OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME |
 	OPT_PROTO_PASSWORD_OPTIONAL,
-	NULL,
-	NULL,
-	NO_BUDDY_ICONS,
-	silcgaim_list_icon,
-	silcgaim_list_emblems,
-	silcgaim_status_text,
-	silcgaim_tooltip_text,
-	silcgaim_away_states,
-	silcgaim_blist_node_menu,
-	silcgaim_chat_info,
-	silcgaim_login,
-	silcgaim_close,
-	silcgaim_send_im,
-	silcgaim_set_info,
-	NULL,
-	silcgaim_get_info,
-	silcgaim_set_away,
-	silcgaim_idle_set,
-	silcgaim_change_passwd,
-	silcgaim_add_buddy,
-	NULL,
-	silcgaim_remove_buddy,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	silcgaim_chat_join,
-	NULL,
-	silcgaim_chat_invite,
-	silcgaim_chat_leave,
-	NULL,
-	silcgaim_chat_send,
-	silcgaim_keepalive,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	silcgaim_chat_set_topic,
-	NULL,
-	silcgaim_roomlist_get_list,
-	silcgaim_roomlist_cancel,
-	NULL,
-	NULL,
-	silcgaim_ftp_send_file
+	NULL,						/* user_splits */
+	NULL,						/* protocol_options */
+	NO_BUDDY_ICONS,				/* icon_spec */
+	silcgaim_list_icon,			/* list_icon */
+	silcgaim_list_emblems,		/* list_emblems */
+	silcgaim_status_text,		/* status_text */
+	silcgaim_tooltip_text,		/* tooltip_text */
+	silcgaim_away_states,		/* away_states */
+	silcgaim_blist_node_menu,	/* blist_node_menu */
+	silcgaim_chat_info,			/* chat_info */
+	silcgaim_login,				/* login */
+	silcgaim_close,				/* close */
+	silcgaim_send_im,			/* send_im */
+	silcgaim_set_info,			/* set_info */
+	NULL,						/* send_typing */
+	silcgaim_get_info,			/* get_info */
+	silcgaim_set_away,			/* set_away */
+	silcgaim_idle_set,			/* set_idle */
+	silcgaim_change_passwd,		/* change_passwd */
+	silcgaim_add_buddy,			/* add_buddy */
+	NULL,						/* add_buddies */
+	silcgaim_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 */
+	silcgaim_chat_join,			/* join_chat */
+	NULL,						/* reject_chat */
+	silcgaim_chat_invite,		/* chat_invite */
+	silcgaim_chat_leave,		/* chat_leave */
+	NULL,						/* chat_whisper */
+	silcgaim_chat_send,			/* chat_send */
+	silcgaim_keepalive,			/* 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 */
+	silcgaim_chat_set_topic,	/* set_chat_topic */
+	NULL,						/* find_blist_chat */
+	silcgaim_roomlist_get_list,	/* roomlist_get_list */
+	silcgaim_roomlist_cancel,	/* roomlist_cancel */
+	NULL,						/* roomlist_expand_category */
+	NULL,						/* can_receive_file */
+	silcgaim_ftp_send_file		/* send_file */
 };
 
 static GaimPluginInfo info =
--- a/src/protocols/silc/silcgaim.h	Thu Jul 08 17:37:33 2004 +0000
+++ b/src/protocols/silc/silcgaim.h	Thu Jul 08 18:45:01 2004 +0000
@@ -126,6 +126,9 @@
 void silcgaim_roomlist_cancel(GaimRoomlist *list);
 void silcgaim_chat_chauth_show(SilcGaim sg, SilcChannelEntry channel,
 			       SilcBuffer channel_pubkeys);
+void silcgaim_parse_attrs(SilcDList attrs, char **moodstr, char **statusstr,
+					 char **contactstr, char **langstr, char **devicestr,
+					 char **tzstr, char **geostr);
 
 #ifdef _WIN32
 typedef int uid_t;
--- a/src/protocols/silc/util.c	Thu Jul 08 17:37:33 2004 +0000
+++ b/src/protocols/silc/util.c	Thu Jul 08 18:45:01 2004 +0000
@@ -318,7 +318,7 @@
 		g_string_append_printf(s, _("Organization: \t%s\n"), ident->org);
 	if (ident->country)
 		g_string_append_printf(s, _("Country: \t%s\n"), ident->country);
-	g_string_append_printf(s, _("Algorithm: \t\t%s\n"), public_key->name);
+	g_string_append_printf(s, _("Algorithm: \t%s\n"), public_key->name);
 	g_string_append_printf(s, _("Key Length: \t%d bits\n"), (int)key_len);
 	g_string_append_printf(s, "\n");
 	g_string_append_printf(s, _("Public Key Fingerprint:\n%s\n\n"), fingerprint);
@@ -436,3 +436,133 @@
 	if (mode & SILC_CHANNEL_UMODE_QUIET)
 		strcat(buf, "[quieted] ");
 }
+
+void
+silcgaim_parse_attrs(SilcDList attrs, char **moodstr, char **statusstr,
+					 char **contactstr, char **langstr, char **devicestr,
+					 char **tzstr, char **geostr)
+{
+	SilcAttributePayload attr;
+	SilcAttributeMood mood = 0;
+	SilcAttributeContact contact;
+	SilcAttributeObjDevice device;
+	SilcAttributeObjGeo geo;
+
+	char tmp[1024];
+	GString *s;
+
+	*moodstr = NULL;
+	*statusstr = NULL;
+	*contactstr = NULL;
+	*langstr = NULL;
+	*devicestr = NULL;
+	*tzstr = NULL;
+	*geostr = NULL;
+
+	if (!attrs)
+		return;
+
+	s = g_string_new("");
+	attr = silcgaim_get_attr(attrs, SILC_ATTRIBUTE_STATUS_MOOD);
+	if (attr && silc_attribute_get_object(attr, &mood, sizeof(mood))) {
+		if (mood & SILC_ATTRIBUTE_MOOD_HAPPY)
+			g_string_append_printf(s, "[%s] ", _("Happy"));
+		if (mood & SILC_ATTRIBUTE_MOOD_SAD)
+			g_string_append_printf(s, "[%s] ", _("Sad"));
+		if (mood & SILC_ATTRIBUTE_MOOD_ANGRY)
+			g_string_append_printf(s, "[%s] ", _("Angry"));
+		if (mood & SILC_ATTRIBUTE_MOOD_JEALOUS)
+			g_string_append_printf(s, "[%s] ", _("Jealous"));
+		if (mood & SILC_ATTRIBUTE_MOOD_ASHAMED)
+			g_string_append_printf(s, "[%s] ", _("Ashamed"));
+		if (mood & SILC_ATTRIBUTE_MOOD_INVINCIBLE)
+			g_string_append_printf(s, "[%s] ", _("Invincible"));
+		if (mood & SILC_ATTRIBUTE_MOOD_INLOVE)
+			g_string_append_printf(s, "[%s] ", _("In Love"));
+		if (mood & SILC_ATTRIBUTE_MOOD_SLEEPY)
+			g_string_append_printf(s, "[%s] ", _("Sleepy"));
+		if (mood & SILC_ATTRIBUTE_MOOD_BORED)
+			g_string_append_printf(s, "[%s] ", _("Bored"));
+		if (mood & SILC_ATTRIBUTE_MOOD_EXCITED)
+			g_string_append_printf(s, "[%s] ", _("Excited"));
+		if (mood & SILC_ATTRIBUTE_MOOD_ANXIOUS)
+			g_string_append_printf(s, "[%s] ", _("Anxious"));
+	}
+	if (strlen(s->str)) {
+		*moodstr = s->str;
+		g_string_free(s, FALSE);
+	} else
+		g_string_free(s, TRUE);
+
+	attr = silcgaim_get_attr(attrs, SILC_ATTRIBUTE_STATUS_FREETEXT);
+	memset(tmp, 0, sizeof(tmp));
+	if (attr && silc_attribute_get_object(attr, tmp, sizeof(tmp)))
+		*statusstr = g_strdup(tmp);
+
+	s = g_string_new("");
+	attr = silcgaim_get_attr(attrs, SILC_ATTRIBUTE_PREFERRED_CONTACT);
+	if (attr && silc_attribute_get_object(attr, &contact, sizeof(contact))) {
+		if (contact & SILC_ATTRIBUTE_CONTACT_CHAT)
+			g_string_append_printf(s, "[%s] ", _("Chat"));
+		if (contact & SILC_ATTRIBUTE_CONTACT_EMAIL)
+			g_string_append_printf(s, "[%s] ", _("Email"));
+		if (contact & SILC_ATTRIBUTE_CONTACT_CALL)
+			g_string_append_printf(s, "[%s] ", _("Phone"));
+		if (contact & SILC_ATTRIBUTE_CONTACT_PAGE)
+			g_string_append_printf(s, "[%s] ", _("Paging"));
+		if (contact & SILC_ATTRIBUTE_CONTACT_SMS)
+			g_string_append_printf(s, "[%s] ", _("SMS"));
+		if (contact & SILC_ATTRIBUTE_CONTACT_MMS)
+			g_string_append_printf(s, "[%s] ", _("MMS"));
+		if (contact & SILC_ATTRIBUTE_CONTACT_VIDEO)
+			g_string_append_printf(s, "[%s] ", _("Video Conferencing"));
+	}
+	if (strlen(s->str)) {
+		*contactstr = s->str;
+		g_string_free(s, FALSE);
+	} else
+		g_string_free(s, TRUE);
+
+	attr = silcgaim_get_attr(attrs, SILC_ATTRIBUTE_PREFERRED_LANGUAGE);
+	memset(tmp, 0, sizeof(tmp));
+	if (attr && silc_attribute_get_object(attr, tmp, sizeof(tmp)))
+		*langstr = g_strdup(tmp);
+
+	s = g_string_new("");
+	attr = silcgaim_get_attr(attrs, SILC_ATTRIBUTE_DEVICE_INFO);
+	memset(&device, 0, sizeof(device));
+	if (attr && silc_attribute_get_object(attr, &device, sizeof(device))) {
+		if (device.type == SILC_ATTRIBUTE_DEVICE_COMPUTER)
+			g_string_append_printf(s, "%s: ", _("Computer"));
+		if (device.type == SILC_ATTRIBUTE_DEVICE_MOBILE_PHONE)
+			g_string_append_printf(s, "%s: ", _("Mobile Phone"));
+		if (device.type == SILC_ATTRIBUTE_DEVICE_PDA)
+			g_string_append_printf(s, "%s: ", _("PDA"));
+		if (device.type == SILC_ATTRIBUTE_DEVICE_TERMINAL)
+			g_string_append_printf(s, "%s: ", _("Terminal"));
+		g_string_append_printf(s, "%s %s %s %s",
+				device.manufacturer ? device.manufacturer : "",
+				device.version ? device.version : "",
+				device.model ? device.model : "",
+				device.language ? device.language : "");
+	}
+	if (strlen(s->str)) {
+		*devicestr = s->str;
+		g_string_free(s, FALSE);
+	} else
+		g_string_free(s, TRUE);
+
+	attr = silcgaim_get_attr(attrs, SILC_ATTRIBUTE_TIMEZONE);
+	memset(tmp, 0, sizeof(tmp));
+	if (attr && silc_attribute_get_object(attr, tmp, sizeof(tmp)))
+		*tzstr = g_strdup(tmp);
+
+	attr = silcgaim_get_attr(attrs, SILC_ATTRIBUTE_GEOLOCATION);
+	memset(&geo, 0, sizeof(geo));
+	if (attr && silc_attribute_get_object(attr, &geo, sizeof(geo)))
+		*geostr = g_strdup_printf("%s %s %s (%s)",
+				geo.longitude ? geo.longitude : "",
+				geo.latitude ? geo.latitude : "",
+				geo.altitude ? geo.altitude : "",
+				geo.accuracy ? geo.accuracy : "");
+}