changeset 29516:a4e4d27fb810

propagate from branch 'im.pidgin.pidgin' (head 2ac9ba8bc7ccc501db6f24fdfe06025a3957852a) to branch 'im.pidgin.pidgin.next.minor' (head 4d360c89b5e0ebc5fd48382f6a6fbe5110c0c475)
author John Bailey <rekkanoryo@rekkanoryo.org>
date Mon, 12 Oct 2009 05:08:37 +0000
parents 9efe23192c0b (diff) 483f85dde1e7 (current diff)
children bb873040d7de
files ChangeLog configure.ac libpurple/account.c libpurple/protocols/msn/nexus.c libpurple/protocols/yahoo/libymsg.c pidgin/gtkcelllayout.c pidgin/gtkcelllayout.h pidgin/gtkcellrendererprogress.c pidgin/gtkcellrendererprogress.h pidgin/gtkcellview.c pidgin/gtkcellview.h pidgin/gtkcellviewmenuitem.c pidgin/gtkcellviewmenuitem.h pidgin/gtkexpander.c pidgin/gtkexpander.h pidgin/gtkprefs.c pidgin/pidgincombobox.c pidgin/pidgincombobox.h pidgin/win32/nsis/pidgin-installer.nsi
diffstat 38 files changed, 619 insertions(+), 280 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Oct 05 00:34:33 2009 +0000
+++ b/ChangeLog	Mon Oct 12 05:08:37 2009 +0000
@@ -20,11 +20,19 @@
 	  is specified.
 	* Fix a crash when adding a buddy without an '@'.
 
+	Yahoo:
+	* Fix sending /buzz.
+	* Fix blocking behavior for federated (MSN/OCS/Sametime) service users.
+	* Add support for adding OCS and Sametime buddies.  OCS users are added
+	  as "ocs/user@domain.tld" and Sametime users are added as
+	  "ibm/sametime_id".  (Jason Cohen)
+
 	General:
 	* New 'plugins' sub-command to 'debug' command (i.e. '/debug plugins')
 	  to announce the list of loaded plugins (in both Finch and Pidgin).
 	* Fix a crash when performing DNS queries on Unixes that use the
 	  blocking DNS lookups.  (Brian Lu)
+	* Fix building the GnuTLS plugin with older versions of GnuTLS.
 
 	Finch:
 	* The TinyURL plugin now creates shorter URLs for long non-conversation
--- a/configure.ac	Mon Oct 05 00:34:33 2009 +0000
+++ b/configure.ac	Mon Oct 12 05:08:37 2009 +0000
@@ -1773,6 +1773,23 @@
         LIBS="$LIBS_save"
 fi
 
+if test "x$enable_gnutls" = "xyes"; then
+	AC_MSG_CHECKING(for GNUTLS_CERT_INSECURE_ALGORITHM)
+	LIBS_save="$LIBS"
+	LIBS="$LIBS $GNUTLS_LIBS"
+	CPPFLAGS_save="$CPPFLAGS"
+	CPPFLAGS="$CPPFLAGS $GNUTLS_CFLAGS"
+	AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <gnutls/gnutls.h>]],
+                                        [[unsigned int verify = GNUTLS_CERT_INSECURE_ALGORITHM;]])],
+	               [AC_DEFINE([HAVE_GNUTLS_CERT_INSECURE_ALGORITHM], 1,
+                                  [Define if your gnutls has the GNUTLS_CERT_INSECURE_ALGORITHM flag])
+	                AC_MSG_RESULT(yes)],
+	               [AC_MSG_RESULT(no)])
+	CPPFLAGS="$CPPFLAGS_save"
+        LIBS="$LIBS_save"
+fi
+
+
 AM_CONDITIONAL(USE_GNUTLS, test "x$enable_gnutls" = "xyes")
 
 
--- a/finch/gntblist.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/finch/gntblist.c	Mon Oct 12 05:08:37 2009 +0000
@@ -1940,7 +1940,7 @@
 	} else if (!gnt_tree_is_searching(GNT_TREE(ggblist->tree))) {
 		if (strcmp(text, "t") == 0) {
 			finch_blist_toggle_tag_buddy(gnt_tree_get_selection_data(GNT_TREE(ggblist->tree)));
-			gnt_bindable_perform_action_named(GNT_BINDABLE(ggblist->tree), "move-down");
+			gnt_bindable_perform_action_named(GNT_BINDABLE(ggblist->tree), "move-down", NULL);
 		} else if (strcmp(text, "a") == 0) {
 			finch_blist_place_tagged(gnt_tree_get_selection_data(GNT_TREE(ggblist->tree)));
 		} else
--- a/finch/libgnt/gntbindable.h	Mon Oct 05 00:34:33 2009 +0000
+++ b/finch/libgnt/gntbindable.h	Mon Oct 12 05:08:37 2009 +0000
@@ -166,7 +166,7 @@
  *
  * @return  @c TRUE if the action was performed successfully, @c FALSE otherwise.
  */
-gboolean gnt_bindable_perform_action_named(GntBindable *bindable, const char *name, ...);
+gboolean gnt_bindable_perform_action_named(GntBindable *bindable, const char *name, ...) G_GNUC_NULL_TERMINATED;
 
 /**
  * Returns a GntTree populated with "key" -> "binding" for the widget.
--- a/finch/libgnt/gntbox.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/finch/libgnt/gntbox.c	Mon Oct 12 05:08:37 2009 +0000
@@ -687,8 +687,8 @@
 		get_title_thingies(b, prev, &pos, &right);
 		mvwhline(w->window, 0, pos - 1, ACS_HLINE | gnt_color_pair(GNT_COLOR_NORMAL),
 				right - pos + 2);
-		g_free(prev);
 	}
+	g_free(prev);
 }
 
 void gnt_box_set_pad(GntBox *box, int pad)
--- a/finch/libgnt/gntentry.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/finch/libgnt/gntentry.c	Mon Oct 12 05:08:37 2009 +0000
@@ -495,7 +495,7 @@
 {
 	GntEntry *entry = GNT_ENTRY(bind);
 	if (entry->ddown) {
-		gnt_bindable_perform_action_named(GNT_BINDABLE(entry->ddown), "move-down");
+		gnt_bindable_perform_action_named(GNT_BINDABLE(entry->ddown), "move-down", NULL);
 		return TRUE;
 	}
 	return show_suggest_dropdown(entry);
--- a/finch/libgnt/gntfilesel.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/finch/libgnt/gntfilesel.c	Mon Oct 12 05:08:37 2009 +0000
@@ -176,9 +176,13 @@
 	splits = g_strsplit(path, G_DIR_SEPARATOR_S, -1);
 	for (i = 0, j = 0; splits[i]; i++) {
 		if (strcmp(splits[i], ".") == 0) {
+			g_free(splits[i]);
+			splits[i] = NULL;
 		} else if (strcmp(splits[i], "..") == 0) {
 			if (j)
 				j--;
+			g_free(splits[i]);
+			splits[i] = NULL;
 		} else {
 			if (i != j) {
 				g_free(splits[j]);
@@ -625,6 +629,7 @@
 
 	sel->files = gnt_tree_new_with_columns(2);  /* Name, Size */
 	gnt_tree_set_compare_func(GNT_TREE(sel->files), (GCompareFunc)g_utf8_collate);
+	gnt_tree_set_hash_fns(GNT_TREE(sel->files), g_str_hash, g_str_equal, g_free);
 	gnt_tree_set_column_titles(GNT_TREE(sel->files), "Filename", "Size");
 	gnt_tree_set_show_title(GNT_TREE(sel->files), TRUE);
 	gnt_tree_set_col_width(GNT_TREE(sel->files), 0, 25);
--- a/finch/libgnt/gnttextview.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/finch/libgnt/gnttextview.c	Mon Oct 12 05:08:37 2009 +0000
@@ -767,6 +767,7 @@
 							line->segments = g_list_delete_link(line->segments, segs);
 							if (line->segments == NULL) {
 								free_text_line(line, NULL);
+								line = NULL;
 								if (view->list == iter) {
 									if (inext)
 										view->list = inext;
@@ -780,7 +781,8 @@
 							seg->start = tag->start;
 							seg->end = tag->end - change;
 						}
-						line->length -= change;
+						if (line)
+							line->length -= change;
 						/* XXX: Make things work if the tagged text spans over several lines. */
 					} else {
 						/* XXX: handle the rest of the conditions */
--- a/finch/libgnt/gntutils.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/finch/libgnt/gntutils.c	Mon Oct 12 05:08:37 2009 +0000
@@ -374,6 +374,7 @@
 	gnt_widget_from_xmlnode(node, data, num);
 
 	xmlFreeDoc(doc);
+	xmlFreeParserCtxt(ctxt);
 	xmlCleanupParser();
 	va_end(list);
 	g_free(data);
@@ -470,6 +471,7 @@
 		xmlFreeDoc(doc);
 		ret = TRUE;
 	}
+	xmlFreeParserCtxt(ctxt);
 	xmlCleanupParser();
 	return ret;
 #endif
--- a/finch/plugins/gnttinyurl.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/finch/plugins/gnttinyurl.c	Mon Oct 12 05:08:37 2009 +0000
@@ -148,7 +148,9 @@
 					url_buf = g_strndup(c, t - c);
 					if (!g_list_find_custom(ret, url_buf, (GCompareFunc)strcmp)) {
 						purple_debug_info("TinyURL", "Added URL %s\n", url_buf);
-						ret = g_list_append(ret, g_strdup(url_buf));
+						ret = g_list_append(ret, url_buf);
+					} else {
+						g_free(url_buf);
 					}
 					c = t;
 					break;
@@ -179,6 +181,8 @@
 						if (!g_list_find_custom(ret, url_buf, (GCompareFunc)strcmp)) {
 							purple_debug_info("TinyURL", "Added URL %s\n", url_buf);
 							ret = g_list_append(ret, url_buf);
+						} else {
+							g_free(url_buf);
 						}
 						c = t;
 						break;
@@ -231,7 +235,7 @@
 				PurpleConversation *conv, PurpleMessageFlags flags)
 {
 	GString *t;
-	GList *iter, *urls;
+	GList *iter, *urls, *next;
 	int c = 0;
 
 	if ((flags & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_INVISIBLE)))
@@ -247,7 +251,8 @@
 
 	t = g_string_new(*message);
 	g_free(*message);
-	for (iter = urls; iter; iter = iter->next) {
+	for (iter = urls; iter; iter = next) {
+		next = iter->next;
 		if (g_utf8_strlen((char *)iter->data, -1) >= purple_prefs_get_int(PREF_LENGTH)) {
 			int pos, x = 0;
 			gchar *j, *s, *str, *orig;
@@ -265,15 +270,8 @@
 			g_free(str);
 			continue;
 		} else {
-			if (iter->prev) {
-				iter = iter->prev;
-				g_free(iter->next->data);
-				urls = g_list_delete_link(urls, iter->next);
-			} else {
-				g_free(iter->data);
-				g_list_free(urls);
-				urls = NULL;
-			}
+			g_free(iter->data);
+			urls = g_list_delete_link(urls, iter);
 		}
 	}
 	*message = t->str;
--- a/libpurple/account.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/libpurple/account.c	Mon Oct 12 05:08:37 2009 +0000
@@ -1052,7 +1052,10 @@
 
 	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
 	PURPLE_DBUS_UNREGISTER_POINTER(priv->current_error);
-	g_free(priv->current_error);
+	if (priv->current_error) {
+		g_free(priv->current_error->description);
+		g_free(priv->current_error);
+	}
 	g_free(priv);
 
 	PURPLE_DBUS_UNREGISTER_POINTER(account);
--- a/libpurple/certificate.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/libpurple/certificate.c	Mon Oct 12 05:08:37 2009 +0000
@@ -97,8 +97,8 @@
 			         "automatically checked.");
 			break;
 		case PURPLE_CERTIFICATE_CA_UNKNOWN:
-			return _("The root certificate this one claims to be issued by is "
-			         "unknown.");
+			return _("The certificate is not trusted because no certificate "
+			         "that can verify it is currently trusted.");
 			break;
 		case PURPLE_CERTIFICATE_NOT_ACTIVATED:
 			return _("The certificate is not valid yet.");
--- a/libpurple/ft.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/libpurple/ft.c	Mon Oct 12 05:08:37 2009 +0000
@@ -1030,7 +1030,7 @@
 				 * watcher.
 				 */
 				if (xfer->watcher != 0) {
-					purple_timeout_remove(xfer->watcher);
+					purple_input_remove(xfer->watcher);
 					xfer->watcher = 0;
 				}
 
--- a/libpurple/plugins/perl/common/Prpl.xs	Mon Oct 05 00:34:33 2009 +0000
+++ b/libpurple/plugins/perl/common/Prpl.xs	Mon Oct 12 05:08:37 2009 +0000
@@ -62,11 +62,15 @@
 PREINIT:
 	PurplePluginProtocolInfo *prpl_info;
 CODE:
-	prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
-	if (prpl_info && prpl_info->send_raw != NULL) {
-		RETVAL = prpl_info->send_raw(gc, str, strlen(str));
-	} else {
+	if (!gc)
 		RETVAL = 0;
+	else {
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
+		if (prpl_info && prpl_info->send_raw != NULL) {
+			RETVAL = prpl_info->send_raw(gc, str, strlen(str));
+		} else {
+			RETVAL = 0;
+		}
 	}
 OUTPUT:
 	RETVAL
--- a/libpurple/plugins/perl/perl.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/libpurple/plugins/perl/perl.c	Mon Oct 12 05:08:37 2009 +0000
@@ -621,6 +621,9 @@
 			g_free(gps);
 			plugin->info->extra_info = NULL;
 		}
+
+		g_free(plugin->info);
+		plugin->info = NULL;
 	}
 }
 
--- a/libpurple/plugins/ssl/ssl-gnutls.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/libpurple/plugins/ssl/ssl-gnutls.c	Mon Oct 12 05:08:37 2009 +0000
@@ -698,9 +698,8 @@
 			crt_issuer_id =
 				purple_certificate_get_issuer_unique_id(crt);
 			purple_debug_info("gnutls/x509",
-					  "Certificate for %s claims to be "
-					  "issued by %s, but the certificate "
-					  "for %s does not match.\n",
+					  "Certificate %s is issued by "
+					  "%s, which does not match %s.\n",
 					  crt_id ? crt_id : "(null)",
 					  crt_issuer_id ? crt_issuer_id : "(null)",
 					  issuer_id ? issuer_id : "(null)");
@@ -730,6 +729,7 @@
 		return FALSE;
 	}
 
+#ifdef HAVE_GNUTLS_CERT_INSECURE_ALGORITHM
 	if (verify & GNUTLS_CERT_INSECURE_ALGORITHM) {
 		/*
 		 * A certificate in the chain is signed with an insecure
@@ -743,6 +743,7 @@
 				"Insecure hash algorithm used by %s to sign %s\n",
 				issuer_id, crt_id);
 	}
+#endif
 
 	if (verify & GNUTLS_CERT_INVALID) {
 		/* Signature didn't check out, but at least
--- a/libpurple/protocols/jabber/jabber.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Mon Oct 12 05:08:37 2009 +0000
@@ -68,8 +68,6 @@
 #include "jingle/jingle.h"
 #include "jingle/rtp.h"
 
-#define JABBER_CONNECT_STEPS (js->gsc ? 9 : 5)
-
 PurplePlugin *jabber_plugin = NULL;
 GList *jabber_features = NULL;
 GList *jabber_identities = NULL;
@@ -198,9 +196,10 @@
 void jabber_stream_features_parse(JabberStream *js, xmlnode *packet)
 {
 	if(xmlnode_get_child(packet, "starttls")) {
-		if(jabber_process_starttls(js, packet))
-
+		if(jabber_process_starttls(js, packet)) {
+			jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING_ENCRYPTION);
 			return;
+		}
 	} else if(purple_account_get_bool(js->gc->account, "require_tls", FALSE) && !jabber_stream_is_ssl(js)) {
 		purple_connection_error_reason(js->gc,
 			 PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR,
@@ -211,6 +210,7 @@
 	if(js->registration) {
 		jabber_register_start(js);
 	} else if(xmlnode_get_child(packet, "mechanisms")) {
+		jabber_stream_set_state(js, JABBER_STREAM_AUTHENTICATING);
 		jabber_auth_start(js, packet);
 	} else if(xmlnode_get_child(packet, "bind")) {
 		xmlnode *bind, *resource;
@@ -289,8 +289,10 @@
 		if(js->state == JABBER_STREAM_AUTHENTICATING)
 			jabber_auth_handle_failure(js, *packet);
 	} else if(!strcmp((*packet)->name, "proceed")) {
-		if(js->state == JABBER_STREAM_AUTHENTICATING && !js->gsc)
+		if (js->state == JABBER_STREAM_INITIALIZING_ENCRYPTION && !js->gsc)
 			tls_init(js);
+		else
+			purple_debug_warning("jabber", "Ignoring spurious <proceed/>\n");
 	} else {
 		purple_debug(PURPLE_DEBUG_WARNING, "jabber", "Unknown packet: %s\n",
 				(*packet)->name);
@@ -1570,6 +1572,8 @@
 
 void jabber_stream_set_state(JabberStream *js, JabberStreamState state)
 {
+#define JABBER_CONNECT_STEPS ((js->gsc || js->state == JABBER_STREAM_INITIALIZING_ENCRYPTION) ? 9 : 5)
+
 	js->state = state;
 	switch(state) {
 		case JABBER_STREAM_OFFLINE:
@@ -1607,6 +1611,8 @@
 			purple_connection_set_state(js->gc, PURPLE_CONNECTED);
 			break;
 	}
+
+#undef JABBER_CONNECT_STEPS
 }
 
 char *jabber_get_next_id(JabberStream *js)
--- a/libpurple/protocols/jabber/parser.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/libpurple/protocols/jabber/parser.c	Mon Oct 12 05:08:37 2009 +0000
@@ -62,11 +62,6 @@
 				g_free(attrib);
 			}
 		}
-		if(js->protocol_version == JABBER_PROTO_0_9)
-			js->auth_type = JABBER_AUTH_IQ_AUTH;
-
-		if(js->state == JABBER_STREAM_INITIALIZING || js->state == JABBER_STREAM_INITIALIZING_ENCRYPTION)
-			jabber_stream_set_state(js, JABBER_STREAM_AUTHENTICATING);
 	} else {
 
 		if(js->current)
@@ -256,5 +251,17 @@
 				break;
 		}
 	}
+
+	if (js->protocol_version == JABBER_PROTO_0_9 && !js->gc->disconnect_timeout &&
+			(js->state == JABBER_STREAM_INITIALIZING ||
+			 js->state == JABBER_STREAM_INITIALIZING_ENCRYPTION)) {
+		/*
+		 * Legacy servers don't advertise features, so if we've just gotten
+		 * the opening <stream:stream> and there was no version, we need to
+		 * immediately start legacy IQ auth.
+		 */
+		js->auth_type = JABBER_AUTH_IQ_AUTH;
+		jabber_stream_set_state(js, JABBER_STREAM_AUTHENTICATING);
+	}
 }
 
--- a/libpurple/protocols/jabber/roster.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/libpurple/protocols/jabber/roster.c	Mon Oct 12 05:08:37 2009 +0000
@@ -229,7 +229,7 @@
 		else
 			jb->subscription &= ~JABBER_SUB_PENDING;
 
-		if(jb->subscription == JABBER_SUB_REMOVE) {
+		if(jb->subscription & JABBER_SUB_REMOVE) {
 			remove_purple_buddies(js, jid);
 		} else {
 			GSList *groups = NULL;
--- a/libpurple/protocols/msn/contact.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/libpurple/protocols/msn/contact.c	Mon Oct 12 05:08:37 2009 +0000
@@ -206,6 +206,7 @@
 		                   "Operation {%s} failed. No response received from server.\n",
 		                   msn_contact_operation_str(state->action));
 		msn_session_set_error(state->session, MSN_ERROR_BAD_BLIST, NULL);
+		msn_callback_state_free(state);
 		return;
 	}
 
--- a/libpurple/protocols/msn/nexus.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/libpurple/protocols/msn/nexus.c	Mon Oct 12 05:08:37 2009 +0000
@@ -324,8 +324,10 @@
 			xmlnode *cipher = xmlnode_get_child(node, "RequestedSecurityToken/EncryptedData/CipherData/CipherValue");
 			xmlnode *secret = xmlnode_get_child(node, "RequestedProofToken/BinarySecret");
 
+			g_free(nexus->cipher);
 			nexus->cipher = xmlnode_get_data(cipher);
 			data = xmlnode_get_data(secret);
+			g_free(nexus->secret);
 			nexus->secret = (char *)purple_base64_decode(data, NULL);
 			g_free(data);
 
--- a/libpurple/protocols/msn/notification.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/libpurple/protocols/msn/notification.c	Mon Oct 12 05:08:37 2009 +0000
@@ -583,6 +583,7 @@
 	trans = msn_transaction_new(cmdproc, "FQY", "%d", payload_len);
 	msn_transaction_set_payload(trans, payload, payload_len);
 	msn_transaction_set_data(trans, data);
+	msn_transaction_set_data_free(trans, g_free);
 	msn_cmdproc_send_trans(cmdproc, trans);
 }
 
@@ -621,7 +622,7 @@
 				user->list_op & MSN_LIST_OP_MASK, network);
 		payload = xmlnode_to_str(adl_node, &payload_len);
 		msn_notification_post_adl(session->notification->cmdproc, payload, payload_len);
-
+		g_free(payload);
 	} else {
 		purple_debug_error("msn",
 		                   "Got FQY update for unknown user %s on network %d.\n",
@@ -962,9 +963,8 @@
 			if (cmd->trans->data) {
 				MsnFqyCbData *fqy_data = cmd->trans->data;
 				fqy_data->cb(session, passport, network, fqy_data->data);
-				/* TODO: This leaks, but the server responds to FQY multiple times, so we
-				         can't free it yet. We need to figure out somewhere else to do so.
-				g_free(fqy_data); */
+				/* Don't free fqy_data yet since the server responds to FQY multipe times.
+				   It will be freed when cmd->trans is freed. */
 			}
 
 			g_free(passport);
--- a/libpurple/protocols/msn/oim.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/libpurple/protocols/msn/oim.c	Mon Oct 12 05:08:37 2009 +0000
@@ -373,6 +373,7 @@
 								msg->oim_msg);
 							g_queue_push_head(oim->send_queue, msg);
 							msn_oim_send_msg(oim);
+							msg = NULL;
 						} else {
 							purple_debug_info("msn",
 								"Can't find lock key for OIM: %s\n",
@@ -393,6 +394,7 @@
 						purple_debug_info("msn", "Resending OIM: %s\n", msg->oim_msg);
 						g_queue_push_head(oim->send_queue, msg);
 						msn_oim_send_msg(oim);
+						msg = NULL;
 					}
 				} else {
 					/* Report the error */
@@ -426,6 +428,9 @@
 			}
 		}
 	}
+
+	if (msg)
+		msn_oim_free_send_req(msg);
 }
 
 void
--- a/libpurple/protocols/msn/servconn.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/libpurple/protocols/msn/servconn.c	Mon Oct 12 05:08:37 2009 +0000
@@ -86,7 +86,7 @@
 	if (servconn->tx_handler > 0)
 		purple_input_remove(servconn->tx_handler);
 	if (servconn->timeout_handle > 0)
-		purple_input_remove(servconn->timeout_handle);
+		purple_timeout_remove(servconn->timeout_handle);
 
 	msn_cmdproc_destroy(servconn->cmdproc);
 	g_free(servconn);
@@ -280,7 +280,7 @@
 
 	if (servconn->timeout_handle > 0)
 	{
-		purple_input_remove(servconn->timeout_handle);
+		purple_timeout_remove(servconn->timeout_handle);
 		servconn->timeout_handle = 0;
 	}
 
@@ -300,7 +300,7 @@
 servconn_idle_timeout_cb(MsnServConn *servconn)
 {
 	msn_servconn_disconnect(servconn);
-	servconn->timeout_handle = 0;
+	servconn->timeout_handle = 0;	/* XXX: servconn may not be valid anymore */
 	return FALSE;
 }
 
@@ -308,7 +308,7 @@
 servconn_timeout_renew(MsnServConn *servconn)
 {
 	if (servconn->timeout_handle) {
-		purple_input_remove(servconn->timeout_handle);
+		purple_timeout_remove(servconn->timeout_handle);
 		servconn->timeout_handle = 0;
 	}
 
@@ -440,11 +440,12 @@
 	memcpy(servconn->rx_buf + servconn->rx_len, buf, len + 1);
 	servconn->rx_len += len;
 
-	msn_servconn_process_data(servconn);
-	servconn_timeout_renew(servconn);
+	servconn = msn_servconn_process_data(servconn);
+	if (servconn)
+		servconn_timeout_renew(servconn);
 }
 
-void msn_servconn_process_data(MsnServConn *servconn)
+MsnServConn *msn_servconn_process_data(MsnServConn *servconn)
 {
 	char *cur, *end, *old_rx_buf;
 	int cur_len;
@@ -503,10 +504,13 @@
 
 	servconn->processing = FALSE;
 
-	if (servconn->wasted)
+	if (servconn->wasted) {
 		msn_servconn_destroy(servconn);
+		servconn = NULL;
+	}
 
 	g_free(old_rx_buf);
+	return servconn;
 }
 
 #if 0
--- a/libpurple/protocols/msn/servconn.h	Mon Oct 05 00:34:33 2009 +0000
+++ b/libpurple/protocols/msn/servconn.h	Mon Oct 12 05:08:37 2009 +0000
@@ -178,8 +178,10 @@
  * data from the socket.
  *
  * @param servconn The servconn.
+ *
+ * @return @c NULL if servconn was destroyed, 'servconn' otherwise.
  */
-void msn_servconn_process_data(MsnServConn *servconn);
+MsnServConn *msn_servconn_process_data(MsnServConn *servconn);
 
 /**
  * Set a idle timeout fot this servconn
--- a/libpurple/protocols/msn/transaction.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/libpurple/protocols/msn/transaction.c	Mon Oct 12 05:08:37 2009 +0000
@@ -59,6 +59,9 @@
 	g_free(trans->params);
 	g_free(trans->payload);
 
+	if (trans->data_free)
+		trans->data_free(trans->data);
+
 #if 0
 	if (trans->pendent_cmd != NULL)
 		msn_message_unref(trans->pendent_msg);
@@ -165,6 +168,12 @@
 	trans->data = data;
 }
 
+void msn_transaction_set_data_free(MsnTransaction *trans, GDestroyNotify fn)
+{
+	g_return_if_fail(trans != NULL);
+	trans->data_free = fn;
+}
+
 void
 msn_transaction_add_cb(MsnTransaction *trans, char *answer,
 					   MsnTransCb cb)
--- a/libpurple/protocols/msn/transaction.h	Mon Oct 05 00:34:33 2009 +0000
+++ b/libpurple/protocols/msn/transaction.h	Mon Oct 12 05:08:37 2009 +0000
@@ -48,6 +48,8 @@
 	guint timer;
 
 	void *data; /**< The data to be used on the different callbacks. */
+	GDestroyNotify data_free;  /**< The function to free 'data', or @c NULL */
+
 	GHashTable *callbacks;
 	gboolean has_custom_callbacks;
 	MsnErrorCb error_cb;
@@ -71,6 +73,7 @@
 void msn_transaction_set_payload(MsnTransaction *trans,
 								 const char *payload, int payload_len);
 void msn_transaction_set_data(MsnTransaction *trans, void *data);
+void msn_transaction_set_data_free(MsnTransaction *trans, GDestroyNotify fn);
 void msn_transaction_add_cb(MsnTransaction *trans, char *answer,
 							MsnTransCb cb);
 void msn_transaction_set_error_cb(MsnTransaction *trans, MsnErrorCb cb);
--- a/libpurple/protocols/yahoo/libymsg.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/libpurple/protocols/yahoo/libymsg.c	Mon Oct 12 05:08:37 2009 +0000
@@ -153,7 +153,7 @@
 	char *name = NULL;
 	gboolean unicode = FALSE;
 	char *message = NULL;
-	char *msn_name = NULL;
+	YahooFederation fed = YAHOO_FEDERATION_NONE;
 
 	if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) {
 		if (!purple_account_get_remember_password(account))
@@ -184,27 +184,35 @@
 			f = NULL;
 			if (pair->value && g_utf8_validate(pair->value, -1, NULL)) {
 				GSList *tmplist;
-				int protocol = 0;
 
 				name = pair->value;
 
-				/* Look ahead to see if we have the protocol info about the buddy */
+				/* Look ahead to see if we have the federation info about the buddy */
 				for (tmplist = l->next; tmplist; tmplist = tmplist->next) {
 					struct yahoo_pair *p = tmplist->data;
 					if (p->key == 7)
 						break;
 					if (p->key == 241) {
-						if(strtol(p->value, NULL, 10) == 2) {
-							g_free(msn_name);
-							msn_name = g_strconcat("msn/", name, NULL);
-							name = msn_name;
-							protocol = 2;
+						fed = strtol(p->value, NULL, 10);
+						switch (fed) {
+							case YAHOO_FEDERATION_MSN:
+								name = g_strconcat("msn/", name, NULL);
+								break;
+							case YAHOO_FEDERATION_OCS:
+								name = g_strconcat("ocs/", name, NULL);
+								break;
+							case YAHOO_FEDERATION_IBM:
+								name = g_strconcat("ibm/", name, NULL);
+								break;
+							case YAHOO_FEDERATION_NONE:
+							default:
+								break;
 						}
 						break;
 					}
 				}
 				f = yahoo_friend_find_or_new(gc, name);
-				f->protocol = protocol;
+				f->fed = fed;
 			}
 			break;
 		case 10: /* state */
@@ -361,7 +369,7 @@
 			if(f && strtol(pair->value, NULL, 10))
 				f->version_id = strtol(pair->value, NULL, 10);
 			break;
-		case 241: /* protocol buddy belongs to */
+		case 241: /* Federated network buddy belongs to */
 			break;  /* We process this when get '7' */
 		default:
 			purple_debug_warning("yahoo",
@@ -381,7 +389,7 @@
 		if (name) /* update the last buddy */
 			yahoo_update_status(gc, name, f);
 	}
-	g_free(msn_name);
+
 }
 
 static void yahoo_do_group_check(PurpleAccount *account, GHashTable *ht, const char *name, const char *group)
@@ -488,13 +496,13 @@
 	PurpleAccount *account = purple_connection_get_account(gc);
 	YahooData *yd = gc->proto_data;
 	GHashTable *ht;
-	char *norm_bud;
+	char *norm_bud = NULL;
 	char *temp = NULL;
 	YahooFriend *f = NULL; /* It's your friends. They're going to want you to share your StarBursts. */
 	                       /* But what if you had no friends? */
 	PurpleBuddy *b;
 	PurpleGroup *g;
-	int protocol = 0;
+	YahooFederation fed = YAHOO_FEDERATION_NONE;
 	int stealth = 0;
 
 	ht = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_slist_free);
@@ -519,11 +527,20 @@
 			break;
 		case 301: /* This is 319 before all s/n's in a group after the first. It is followed by an identical 300. */
 			if(temp != NULL) {
-				if(protocol == 2)
-					norm_bud = g_strconcat("msn/", temp, NULL);
-				else
-					norm_bud = g_strdup(temp);
-
+				switch (fed) {
+					case YAHOO_FEDERATION_MSN:
+						norm_bud = g_strconcat("msn/", temp, NULL);
+						break;
+					case YAHOO_FEDERATION_OCS:
+						norm_bud = g_strconcat("ocs/", temp, NULL);
+						break;
+					case YAHOO_FEDERATION_IBM:
+						norm_bud = g_strconcat("ibm/", temp, NULL);
+						break;
+					case YAHOO_FEDERATION_NONE:
+						norm_bud = g_strdup(temp);
+						break;
+				}
 				if (yd->current_list15_grp) {
 					/* This buddy is in a group */
 					f = yahoo_friend_find_or_new(gc, norm_bud);
@@ -536,15 +553,15 @@
 						purple_blist_add_buddy(b, NULL, g, NULL);
 					}
 					yahoo_do_group_check(account, ht, norm_bud, yd->current_list15_grp);
-					if(protocol != 0) {
-						f->protocol = protocol;
-						purple_debug_info("yahoo", "Setting protocol to %d\n", f->protocol);
+					if(fed) {
+						f->fed = fed;
+						purple_debug_info("yahoo", "Setting federation to %d\n", f->fed);
 					}
 					if(stealth == 2)
 						f->presence = YAHOO_PRESENCE_PERM_OFFLINE;
 
 					/* set p2p status not connected and no p2p packet sent */
-					if(protocol == 0) {
+					if(fed == YAHOO_FEDERATION_NONE) {
 						yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED);
 						f->p2p_packet_sent = 0;
 					} else
@@ -556,8 +573,8 @@
 				}
 
 				g_free(norm_bud);
-
-				protocol = 0;
+				norm_bud=NULL;
+				fed = YAHOO_FEDERATION_NONE;
 				stealth = 0;
 				g_free(temp);
 				temp = NULL;
@@ -573,8 +590,8 @@
 			g_free(temp);
 			temp = g_strdup(purple_normalize(account, pair->value));
 			break;
-		case 241: /* another protocol user */
-			protocol = strtol(pair->value, NULL, 10);
+		case 241: /* user on federated network */
+			fed = strtol(pair->value, NULL, 10);
 			break;
 		case 59: /* somebody told cookies come here too, but im not sure */
 			yahoo_process_cookie(yd, pair->value);
@@ -766,7 +783,7 @@
 	GSList *l = pkt->hash;
 	gint val_11 = 0;
 	YahooData *yd = gc->proto_data;
-	gboolean msn = FALSE;
+	YahooFederation fed = YAHOO_FEDERATION_NONE;
 
 	account = purple_connection_get_account(gc);
 
@@ -783,8 +800,7 @@
 		if (pair->key == 11)
 			val_11 = strtol(pair->value, NULL, 10);
 		if (pair->key == 241)
-			if(strtol(pair->value, NULL, 10) == 2)
-				msn = TRUE;
+			fed = strtol(pair->value, NULL, 10);
 		l = l->next;
 	}
 
@@ -802,20 +818,30 @@
 	if (!g_ascii_strncasecmp(msg, "TYPING", strlen("TYPING"))
 		&& (purple_privacy_check(account, from)))
 	{
-		if(msn) {
-			char *msn_from = g_strconcat("msn/", from, NULL);
-			if (*stat == '1')
-				serv_got_typing(gc, msn_from, 0, PURPLE_TYPING);
-			else
-				serv_got_typing_stopped(gc, msn_from);
-			g_free(msn_from);
+		char *fed_from = from;
+		switch (fed) {
+			case YAHOO_FEDERATION_MSN:
+				fed_from = g_strconcat("msn/", from, NULL);
+				break;
+			case YAHOO_FEDERATION_OCS:
+				fed_from = g_strconcat("ocs/", from, NULL);
+				break;
+			case YAHOO_FEDERATION_IBM:
+				fed_from = g_strconcat("ibm/", from, NULL);
+				break;
+			case YAHOO_FEDERATION_NONE:
+			default:
+				break;
 		}
-		else	{
-			if (*stat == '1')
-				serv_got_typing(gc, from, 0, PURPLE_TYPING);
-			else
-				serv_got_typing_stopped(gc, from);
-		}
+	
+		if (*stat == '1')
+			serv_got_typing(gc, fed_from, 0, PURPLE_TYPING);
+		else
+			serv_got_typing_stopped(gc, fed_from);
+		
+		if (fed_from != from)
+			g_free(fed_from);			
+	
 	} else if (!g_ascii_strncasecmp(msg, "GAME", strlen("GAME"))) {
 		PurpleBuddy *bud = purple_find_buddy(account, from);
 
@@ -852,7 +878,7 @@
 	int buddy_icon;
 	char *id;
 	char *msg;
-	gboolean msn;
+	YahooFederation fed;
 };
 
 static void yahoo_process_sms_message(PurpleConnection *gc, struct yahoo_packet *pkt)
@@ -926,6 +952,7 @@
 	struct _yahoo_im *im = NULL;
 	const char *imv = NULL;
 	gint val_11 = 0;
+	char *fed_from = NULL;
 
 	account = purple_connection_get_account(gc);
 
@@ -936,9 +963,10 @@
 			if (pair->key == 4 || pair->key == 1) {
 				im = g_new0(struct _yahoo_im, 1);
 				list = g_slist_append(list, im);
-				im->from = pair->value;
+				im->from = fed_from = pair->value;
 				im->time = time(NULL);
 				im->utf8 = TRUE;
+				im->fed = YAHOO_FEDERATION_NONE;
 			}
 			if (im && pair->key == 5)
 				im->active_id = pair->value;
@@ -956,8 +984,23 @@
 					im->msg = pair->value;
 			}
 			if (im && pair->key == 241) {
-				if(strtol(pair->value, NULL, 10) == 2)
-					im->msn = TRUE;
+				im->fed = strtol(pair->value, NULL, 10);
+				switch (im->fed) {
+					case YAHOO_FEDERATION_MSN:
+						fed_from = g_strconcat("msn/",im->from, NULL);
+						break;
+					case YAHOO_FEDERATION_OCS:
+						fed_from = g_strconcat("ocs/",im->from, NULL);
+						break;
+					case YAHOO_FEDERATION_IBM:
+						fed_from = g_strconcat("ibm/",im->from, NULL);
+						break;
+					case YAHOO_FEDERATION_NONE:
+					default:
+						break;
+				}
+				purple_debug_info("yahoo", "Message from federated (%d) buddy %s.\n", im->fed, fed_from);
+					
 			}
 			/* peer session id */
 			if (pair->key == 11) {
@@ -981,10 +1024,10 @@
 
 	/* disconnect the peer if connected through p2p and sends wrong value for session id */
 	if( (pkt_type == YAHOO_PKT_TYPE_P2P) && (val_11 != yd->session_id) ) {
-		purple_debug_warning("yahoo","p2p: %s sent us message with wrong session id. Disconnecting p2p connection to peer\n", im ? im->from : "(im was null)");
+		purple_debug_warning("yahoo","p2p: %s sent us message with wrong session id. Disconnecting p2p connection to peer\n", im ? fed_from : "(im was null)");
 		/* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
 		if (im) {
-			g_hash_table_remove(yd->peers, im->from);
+			g_hash_table_remove(yd->peers, fed_from);
 			g_free(im);
 		}
 		return;
@@ -992,6 +1035,7 @@
 
 	/* TODO: It seems that this check should be per IM, not global */
 	/* Check for the Doodle IMV */
+	/* no doodle with federated buddies -- assumption???  */
 	if (im != NULL && imv!= NULL && im->from != NULL)
 	{
 		g_hash_table_replace(yd->imvironments, g_strdup(im->from), g_strdup(imv));
@@ -1026,17 +1070,15 @@
 	for (l = list; l; l = l->next) {
 		YahooFriend *f;
 		char *m, *m2;
-		char *msn_from = NULL;
-		const char *from;
 		im = l->data;
 
-		if (!im->from || !im->msg) {
+		if (!fed_from || !im->msg) {
 			g_free(im);
 			continue;
 		}
 
-		if (!purple_privacy_check(account, im->from)) {
-			purple_debug_info("yahoo", "Message from %s dropped.\n", im->from);
+		if (!purple_privacy_check(account, fed_from)) {
+			purple_debug_info("yahoo", "Message from %s dropped.\n", fed_from);
 			return;
 		}
 
@@ -1071,34 +1113,25 @@
 		g_free(m);
 		m = m2;
 		purple_util_chrreplace(m, '\r', '\n');
-
-		if (im->msn) {
-			msn_from = g_strconcat("msn/", im->from, NULL);
-			from = msn_from;
-		} else {
-			from = im->from;
-		}
-
 		if (!strcmp(m, "<ding>")) {
 			char *username;
 
-			username = g_markup_escape_text(from, -1);
+			username = g_markup_escape_text(fed_from, -1);
 			purple_prpl_got_attention(gc, username, YAHOO_BUZZ);
 			g_free(username);
 			g_free(m);
 			g_free(im);
-			g_free(msn_from);
 			continue;
 		}
 
 		m2 = yahoo_codes_to_html(m);
 		g_free(m);
 
-		serv_got_im(gc, from, m2, 0, im->time);
+		serv_got_im(gc, fed_from, m2, 0, im->time);
 		g_free(m2);
 
-		/* laters : implement buddy icon for msn friends */
-		if (!im->msn) {
+		/* Official clients don't share buddy images with federated buddies */
+		if (im->fed == YAHOO_FEDERATION_NONE) {
 			if ((f = yahoo_friend_find(gc, im->from)) && im->buddy_icon == 2) {
 				if (yahoo_friend_get_buddy_icon_need_request(f)) {
 					yahoo_send_picture_request(gc, im->from);
@@ -1108,8 +1141,9 @@
 		}
 
 		g_free(im);
-		g_free(msn_from);
 	}
+	if (fed_from != im->from)
+		g_free(fed_from);
 	g_slist_free(list);
 }
 
@@ -1142,7 +1176,7 @@
 	PurpleConnection *gc;
 	char *id;
 	char *who;
-	int protocol;
+	YahooFederation fed;
 };
 
 static void
@@ -1153,16 +1187,24 @@
 	YahooData *yd = add_req->gc->proto_data;
 	const char *who = add_req->who;
 
-	if (add_req->protocol == 2)
+	pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH_REQ_15, YAHOO_STATUS_AVAILABLE, yd->session_id);
+	if (add_req->fed) {
 		who += 4;
-
-	pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH_REQ_15, YAHOO_STATUS_AVAILABLE, yd->session_id);
-	yahoo_packet_hash(pkt, "ssiii",
-					  1, add_req->id,
-					  5, who,
-					  241, add_req->protocol,
-					  13, 1,
-					  334, 0);
+		yahoo_packet_hash(pkt, "ssiii",
+						  1, add_req->id,
+						  5, who,
+						  241, add_req->fed,
+						  13, 1,
+						  334, 0);
+	}
+	else {
+		yahoo_packet_hash(pkt, "ssii",
+						  1, add_req->id,
+						  5, who,
+						  13, 1,
+						  334, 0);
+	}
+		
 	yahoo_packet_send_and_free(pkt, yd);
 
 	g_free(add_req->id);
@@ -1178,23 +1220,33 @@
 	char *encoded_msg = NULL;
 	const char *who = add_req->who;
 
-	if (add_req->protocol == 2)
-		who += 4; /* Skip 'msn/' */
-
 	if (msg && *msg)
 		encoded_msg = yahoo_string_encode(add_req->gc, msg, NULL);
 
 	pkt = yahoo_packet_new(YAHOO_SERVICE_AUTH_REQ_15,
 			YAHOO_STATUS_AVAILABLE, yd->session_id);
 
-	yahoo_packet_hash(pkt, "ssiiiis",
-			1, add_req->id,
-			5, who,
-			241, add_req->protocol,
-			13, 2,
-			334, 0,
-			97, 1,
-			14, encoded_msg ? encoded_msg : "");
+	if (add_req->fed) {
+		who += 4; /* Skip fed identifier (msn|ocs|ibm)/' */
+		yahoo_packet_hash(pkt, "ssiiiis",
+						  1, add_req->id,
+						  5, who,
+						  241, add_req->fed,
+						  13, 2,
+						  334, 0,
+						  97, 1,
+						  14, encoded_msg ? encoded_msg : "");
+	}
+	else {
+		yahoo_packet_hash(pkt, "ssiiis",
+						  1, add_req->id,
+						  5, who,
+						  13, 2,
+						  334, 0,
+						  97, 1,
+						  14, encoded_msg ? encoded_msg : "");
+	}
+
 
 	yahoo_packet_send_and_free(pkt, yd);
 
@@ -1249,8 +1301,7 @@
 	PurpleAccount *account;
 	GSList *l = pkt->hash;
 	const char *msg = NULL;
-	int protocol = 0;
-
+	
 	account = purple_connection_get_account(gc);
 
 	/* Buddy authorized/declined our addition */
@@ -1258,6 +1309,7 @@
 		char *temp = NULL;
 		char *who = NULL;
 		int response = 0;
+		YahooFederation fed = YAHOO_FEDERATION_NONE;
 
 		while (l) {
 			struct yahoo_pair *pair = l->data;
@@ -1273,16 +1325,27 @@
 				msg = pair->value;
 				break;
 			case 241:
-				protocol = strtol(pair->value, NULL, 10);
+				fed = strtol(pair->value, NULL, 10);
 				break;
 			}
 			l = l->next;
 		}
 
-		if(protocol == 0)
-			who = g_strdup(temp);
-		else if(protocol == 2)
-			who = g_strconcat("msn/", temp, NULL);
+		switch (fed) {
+			case YAHOO_FEDERATION_MSN:
+				who = g_strconcat("msn/", temp, NULL);
+				break;
+			case YAHOO_FEDERATION_OCS:
+				who = g_strconcat("ocs/", temp, NULL);
+				break;
+			case YAHOO_FEDERATION_IBM:
+				who = g_strconcat("ibm/", temp, NULL);
+				break;
+			case YAHOO_FEDERATION_NONE:
+			default:
+				who = g_strdup(temp);
+				break;
+		}
 
 		if (response == 1) /* Authorized */
 			purple_debug_info("yahoo", "Received authorization from buddy '%s'.\n", who ? who : "(Unknown Buddy)");
@@ -1301,6 +1364,7 @@
 
 		add_req = g_new0(struct yahoo_add_request, 1);
 		add_req->gc = gc;
+		add_req->fed = YAHOO_FEDERATION_NONE;
 
 		while (l) {
 			struct yahoo_pair *pair = l->data;
@@ -1319,7 +1383,7 @@
 				firstname = pair->value;
 				break;
 			case 241:
-				add_req->protocol = strtol(pair->value, NULL, 10);
+				add_req->fed = strtol(pair->value, NULL, 10);
 				break;
 			case 254:
 				lastname = pair->value;
@@ -1328,10 +1392,21 @@
 			}
 			l = l->next;
 		}
-		if(add_req->protocol == 2)
-			add_req->who = g_strconcat("msn/", temp, NULL);
-		else
-			add_req->who = g_strdup(temp);
+		switch (add_req->fed) {
+			case YAHOO_FEDERATION_MSN:
+				add_req->who = g_strconcat("msn/", temp, NULL);
+				break;
+			case YAHOO_FEDERATION_OCS:
+				add_req->who = g_strconcat("ocs/", temp, NULL);
+				break;
+			case YAHOO_FEDERATION_IBM:
+				add_req->who = g_strconcat("ibm/", temp, NULL);
+				break;
+			case YAHOO_FEDERATION_NONE:
+			default:
+				add_req->who = g_strdup(temp);
+				break;
+		}
 
 		if (add_req->id && add_req->who) {
 			char *alias = NULL, *dec_msg = NULL;
@@ -2125,8 +2200,7 @@
 	YahooFriend *f;
 	GSList *l = pkt->hash;
 	YahooData *yd = gc->proto_data;
-	int protocol = 0;
-	gboolean msn = FALSE;
+	YahooFederation fed = YAHOO_FEDERATION_NONE;
 
 	while (l) {
 		struct yahoo_pair *pair = l->data;
@@ -2142,9 +2216,7 @@
 			group = pair->value;
 			break;
 		case 241:
-			protocol = strtol(pair->value, NULL, 10);
-			if(protocol == 2)
-				msn = TRUE;
+			fed = strtol(pair->value, NULL, 10);
 			break;
 		}
 
@@ -2156,20 +2228,30 @@
 	if (!group)
 		group = "";
 
-	if(msn)
-		who = g_strconcat("msn/", temp, NULL);
-	else
-		who = g_strdup(temp);
+	switch (fed) {
+		case YAHOO_FEDERATION_MSN:
+			who = g_strconcat("msn/", temp, NULL);
+			break;
+		case YAHOO_FEDERATION_OCS:
+			who = g_strconcat("ocs/", temp, NULL);
+			break;
+		case YAHOO_FEDERATION_IBM:
+			who = g_strconcat("ibm/", temp, NULL);
+			break;
+		case YAHOO_FEDERATION_NONE:
+		default:
+			who = g_strdup(temp);
+			break;
+	}
 
 	if (!err || (err == 2)) { /* 0 = ok, 2 = already on serv list */
 		f = yahoo_friend_find_or_new(gc, who);
 		yahoo_update_status(gc, who, f);
-		if(protocol)
-			f->protocol = protocol;
+		f->fed = fed;
 
 		if( !g_hash_table_lookup(yd->peers, who) ) {
 			/* we are not connected as client, so set friend to not connected */
-			if(msn)
+			if(fed)
 				yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_DO_NOT_CONNECT);
 			else	{
 				yahoo_friend_set_p2p_status(f, YAHOO_P2PSTATUS_NOT_CONNECTED);
@@ -2541,7 +2623,7 @@
 		return;
 
 	/* Dont send p2p packet to buddies of other protocols */
-	if(f->protocol)
+	if(f->fed)
 		return;
 
 	/* Finally, don't try to connect to buddies not online or on sms */
@@ -3582,8 +3664,9 @@
 	if (purple_presence_is_online(presence)) {
 		if (yahoo_friend_get_game(f))
 			return "game";
-		if (f->protocol == 2)
-			return "msn";
+
+		if (f->fed)
+			return "external";
 	}
 	return NULL;
 }
@@ -4253,11 +4336,11 @@
 	gboolean utf8 = TRUE;
 	PurpleWhiteboard *wb;
 	int ret = 1;
-	YahooFriend *f = NULL;
+	const char *fed_who;
 	gsize lenb = 0;
 	glong lenc = 0;
 	struct yahoo_p2p_data *p2p_data;
-	gboolean msn = FALSE;
+	YahooFederation fed = YAHOO_FEDERATION_NONE;
 	msg2 = yahoo_string_encode(gc, msg, &utf8);
 
 	if(msg2) {
@@ -4275,7 +4358,17 @@
 		}
 	}
 
-	msn = !g_ascii_strncasecmp(who, "msn/", 4);
+	if (who[3] == '/') {
+		if (!g_ascii_strncasecmp(who, "msn/", 4)) {
+			fed = YAHOO_FEDERATION_MSN;
+		}
+		else if (!g_ascii_strncasecmp(who, "ocs/", 4)) {
+			fed = YAHOO_FEDERATION_OCS;
+		}
+		else if (!g_ascii_strncasecmp(who, "ibm/", 4)) {
+			fed = YAHOO_FEDERATION_IBM;
+		}
+	}
 
 	if (who[0] == '+') {
 		/* we have an sms to be sent */
@@ -4325,15 +4418,20 @@
 	}
 
 	pkt = yahoo_packet_new(YAHOO_SERVICE_MESSAGE, YAHOO_STATUS_OFFLINE, yd->session_id);
-	if(msn) {
-		yahoo_packet_hash(pkt, "ss", 1, purple_connection_get_display_name(gc), 5, who+4);
-		yahoo_packet_hash_int(pkt, 241, 2);
+	fed_who = who;
+	switch (fed) {
+		case YAHOO_FEDERATION_MSN:
+		case YAHOO_FEDERATION_OCS:
+		case YAHOO_FEDERATION_IBM:
+			fed_who += 4;
+			break;
+		case YAHOO_FEDERATION_NONE:
+		default:
+			break;
 	}
-	else	{
-		yahoo_packet_hash(pkt, "ss", 1, purple_connection_get_display_name(gc), 5, who);
-		if ((f = yahoo_friend_find(gc, who)) && f->protocol)
-			yahoo_packet_hash_int(pkt, 241, f->protocol);
-	}
+	yahoo_packet_hash(pkt, "ss", 1, purple_connection_get_display_name(gc), 5, fed_who);
+	if (fed)
+		yahoo_packet_hash_int(pkt, 241, fed);
 
 	if (utf8)
 		yahoo_packet_hash_str(pkt, 97, "1");
@@ -4349,7 +4447,7 @@
 	 * just so that we don't inadvertantly reset their IMVironment back
 	 * to nothing.
 	 *
-	 * If they have no set an IMVironment, then use the default.
+	 * If they have not set an IMVironment, then use the default.
 	 */
 	wb = purple_whiteboard_get_session(gc->account, who);
 	if (wb)
@@ -4374,13 +4472,13 @@
 	/* We may need to not send any packets over 2000 bytes, but I'm not sure yet. */
 	if ((YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt)) <= 2000) {
 		/* if p2p link exists, send through it. To-do: key 15, time value to be sent in case of p2p */
-		if( (p2p_data = g_hash_table_lookup(yd->peers, who)) && !msn ) {
+		if( (p2p_data = g_hash_table_lookup(yd->peers, who)) && !fed) {
 			yahoo_packet_hash_int(pkt, 11, p2p_data->session_id);
 			yahoo_p2p_write_pkt(p2p_data->source, pkt);
 		}
 		else	{
 			yahoo_packet_send(pkt, yd);
-			if(!msn)
+			if(!fed)
 				yahoo_send_p2p_pkt(gc, who, 0);		/* send p2p packet, with val_13=0 */
 		}
 	}
@@ -4399,9 +4497,21 @@
 {
 	YahooData *yd = gc->proto_data;
 	struct yahoo_p2p_data *p2p_data;
-	gboolean msn = !g_ascii_strncasecmp(who, "msn/", 4);
+	YahooFederation fed = YAHOO_FEDERATION_NONE;
 	struct yahoo_packet *pkt = NULL;
 
+	if (who[3] == '/') {
+		if (!g_ascii_strncasecmp(who, "msn/", 4)) {
+			fed = YAHOO_FEDERATION_MSN;
+		}
+		else if (!g_ascii_strncasecmp(who, "ocs/", 4)) {
+			fed = YAHOO_FEDERATION_OCS;
+		}
+		else if (!g_ascii_strncasecmp(who, "ibm/", 4)) {
+			fed = YAHOO_FEDERATION_IBM;
+		}
+	}
+
 	/* Don't do anything if sms is being typed */
 	if( strncmp(who, "+", 1) == 0 )
 		return 0;
@@ -4409,7 +4519,7 @@
 	pkt = yahoo_packet_new(YAHOO_SERVICE_NOTIFY, YAHOO_STATUS_TYPING, yd->session_id);
 
 	/* check to see if p2p link exists, send through it */
-	if( (p2p_data = g_hash_table_lookup(yd->peers, who)) && !msn ) {
+	if( (p2p_data = g_hash_table_lookup(yd->peers, who)) && !fed) {
 		yahoo_packet_hash(pkt, "sssssis", 49, "TYPING", 1, purple_connection_get_display_name(gc),
 	                  14, " ", 13, state == PURPLE_TYPING ? "1" : "0",
 	                  5, who, 11, p2p_data->session_id, 1002, "1");	/* To-do: key 15 to be sent in case of p2p */
@@ -4417,14 +4527,24 @@
 		yahoo_packet_free(pkt);
 	}
 	else	{	/* send through yahoo server */
-		if(msn)
-			yahoo_packet_hash(pkt, "sssssss", 49, "TYPING", 1, purple_connection_get_display_name(gc),
-	                  14, " ", 13, state == PURPLE_TYPING ? "1" : "0",
-	                  5, who+4, 1002, "1", 241, "2");
-		else
-			yahoo_packet_hash(pkt, "ssssss", 49, "TYPING", 1, purple_connection_get_display_name(gc),
-	                  14, " ", 13, state == PURPLE_TYPING ? "1" : "0",
-	                  5, who, 1002, "1");
+
+		const char *fed_who = who;
+		switch (fed) {
+			case YAHOO_FEDERATION_MSN:
+			case YAHOO_FEDERATION_OCS:
+			case YAHOO_FEDERATION_IBM:
+				fed_who += 4;
+				break;
+			case YAHOO_FEDERATION_NONE:
+			default:
+				break;
+		}
+		
+		yahoo_packet_hash(pkt, "ssssss", 49, "TYPING", 1, purple_connection_get_display_name(gc),
+                  14, " ", 13, state == PURPLE_TYPING ? "1" : "0",
+                  5, fed_who, 1002, "1");
+        if (fed)
+        	yahoo_packet_hash_int(pkt, 241, fed);
 		yahoo_packet_send_and_free(pkt, yd);
 	}
 
@@ -4671,17 +4791,29 @@
 	char *group2;
 	YahooFriend *f;
 	const char *bname;
-	gboolean msn = FALSE;
+	const char *fed_bname;
+	YahooFederation fed = YAHOO_FEDERATION_NONE;
 
 	if (!yd->logged_in)
 		return;
 
-	bname = purple_buddy_get_name(buddy);
+	fed_bname = bname = purple_buddy_get_name(buddy);
 	if (!purple_privacy_check(purple_connection_get_account(gc), bname))
 		return;
 
 	f = yahoo_friend_find(gc, bname);
-	msn = !g_ascii_strncasecmp(bname, "msn/", 4);
+	if (bname[3] == '/') {
+		fed_bname += 4;
+		if (!g_ascii_strncasecmp(bname, "msn/", 4)) {
+			fed = YAHOO_FEDERATION_MSN;
+		}
+		else if (!g_ascii_strncasecmp(bname, "ocs/", 4)) {
+			fed = YAHOO_FEDERATION_OCS;
+		}
+		else if (!g_ascii_strncasecmp(bname, "ibm/", 4)) {
+			fed = YAHOO_FEDERATION_IBM;
+		}
+	}
 
 	g = purple_buddy_get_group(buddy);
 	if (g)
@@ -4691,37 +4823,35 @@
 
 	group2 = yahoo_string_encode(gc, group, NULL);
 	pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id);
-	if(msn) {
-		yahoo_packet_hash(pkt, "sssssssssss",
-			14, "",
-			65, group2,
-			97, "1",
-			1, purple_connection_get_display_name(gc),
-			302, "319",
-			300, "319",
-			7, bname + 4,
-			241, "2",
-			334, "0",
-			301, "319",
-			303, "319"
+	if (fed) {
+		yahoo_packet_hash(pkt, "sssssssisss",
+						  14, "",
+						  65, group2,
+						  97, "1",
+						  1, purple_connection_get_display_name(gc),
+						  302, "319",
+						  300, "319",
+						  7, fed_bname,
+						  241, fed,
+						  334, "0",
+						  301, "319",
+						  303, "319"
 		);
 	}
-	else	{
+	else {
 		yahoo_packet_hash(pkt, "ssssssssss",
-			14, "",
-			65, group2,
-			97, "1",
-			1, purple_connection_get_display_name(gc),
-			302, "319",
-			300, "319",
-	                7, bname,
-			334, "0",
-			301, "319",
-			303, "319"
+						  14, "",
+						  65, group2,
+						  97, "1",
+						  1, purple_connection_get_display_name(gc),
+						  302, "319",
+						  300, "319",
+						  7, fed_bname,
+						  334, "0",
+						  301, "319",
+						  303, "319"
 		);
 	}
-	if (f && f->protocol && !msn)
-		yahoo_packet_hash_int(pkt, 241, f->protocol);
 
 	yahoo_packet_send_and_free(pkt, yd);
 	g_free(group2);
@@ -4737,17 +4867,16 @@
 	char *cg;
 	const char *bname, *gname;
 	YahooFriend *f = NULL;
-	gboolean msn = FALSE;
+	YahooFederation fed = YAHOO_FEDERATION_NONE;
 
 	bname = purple_buddy_get_name(buddy);
 	f = yahoo_friend_find(gc, bname);
 	if (!f)
 		return;
+	fed = f->fed;
 
 	gname = purple_group_get_name(group);
 	buddies = purple_find_buddies(purple_connection_get_account(gc), bname);
-	if(f->protocol == 2)
-		msn = TRUE;
 	for (l = buddies; l; l = l->next) {
 		g = purple_buddy_get_group(l->data);
 		if (purple_utf8_strcasecmp(gname, purple_group_get_name(g))) {
@@ -4758,20 +4887,29 @@
 
 	g_slist_free(buddies);
 
-	if (remove)
+	if (remove) {
 		g_hash_table_remove(yd->friends, bname);
+		f = NULL; /* f no longer valid - Just making it clear */
+	}
 
 	cg = yahoo_string_encode(gc, gname, NULL);
 	pkt = yahoo_packet_new(YAHOO_SERVICE_REMBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id);
 
-	if(msn)
-		yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc),
-	                  7, bname+4, 65, cg);
-	else
-		yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc),
+	switch (fed) {
+		case YAHOO_FEDERATION_MSN:
+		case YAHOO_FEDERATION_OCS:
+		case YAHOO_FEDERATION_IBM:
+			bname += 4;
+			break;
+		case YAHOO_FEDERATION_NONE:
+		default:
+			break;
+	}
+
+	yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc),
 	                  7, bname, 65, cg);
-	if(f->protocol)
-		yahoo_packet_hash_int(pkt, 241, f->protocol);
+	if (fed)
+		yahoo_packet_hash_int(pkt, 241, fed);
 	yahoo_packet_send_and_free(pkt, yd);
 	g_free(cg);
 }
@@ -4779,7 +4917,7 @@
 void yahoo_add_deny(PurpleConnection *gc, const char *who) {
 	YahooData *yd = (YahooData *)gc->proto_data;
 	struct yahoo_packet *pkt;
-	gboolean msn = FALSE;
+	YahooFederation fed = YAHOO_FEDERATION_NONE;
 
 	if (!yd->logged_in)
 		return;
@@ -4787,11 +4925,22 @@
 	if (!who || who[0] == '\0')
 		return;
 
-	msn = !g_ascii_strncasecmp(who, "msn/", 4);
+	if (who[3] == '/') {
+		if (!g_ascii_strncasecmp(who, "msn/", 4)) {
+			fed = YAHOO_FEDERATION_MSN;
+		}
+		else if (!g_ascii_strncasecmp(who, "ocs/", 4)) {
+			fed = YAHOO_FEDERATION_OCS;
+		}
+		else if (!g_ascii_strncasecmp(who, "ibm/", 4)) {
+			fed = YAHOO_FEDERATION_IBM;
+		}
+	}
+	
 	pkt = yahoo_packet_new(YAHOO_SERVICE_IGNORECONTACT, YAHOO_STATUS_AVAILABLE, yd->session_id);
 
-	if(msn)
-		yahoo_packet_hash(pkt, "ssss", 1, purple_connection_get_display_name(gc), 7, who+4, 241, "2", 13, "1");
+	if(fed)
+		yahoo_packet_hash(pkt, "ssis", 1, purple_connection_get_display_name(gc), 7, who+4, 241, fed, 13, "1");
 	else
 		yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc), 7, who, 13, "1");
 
@@ -4801,19 +4950,28 @@
 void yahoo_rem_deny(PurpleConnection *gc, const char *who) {
 	YahooData *yd = (YahooData *)gc->proto_data;
 	struct yahoo_packet *pkt;
-	gboolean msn = FALSE;
+	YahooFederation fed = YAHOO_FEDERATION_NONE;
 
 	if (!yd->logged_in)
 		return;
 
 	if (!who || who[0] == '\0')
 		return;
-
-	msn = !g_ascii_strncasecmp(who, "msn/", 4);
+	if (who[3] == '/') {
+		if (!g_ascii_strncasecmp(who, "msn/", 4)) {
+			fed = YAHOO_FEDERATION_MSN;
+		}
+		else if (!g_ascii_strncasecmp(who, "ocs/", 4)) {
+			fed = YAHOO_FEDERATION_OCS;
+		}
+		else if (!g_ascii_strncasecmp(who, "ibm/", 4)) {
+			fed = YAHOO_FEDERATION_IBM;
+		}
+	}
 	pkt = yahoo_packet_new(YAHOO_SERVICE_IGNORECONTACT, YAHOO_STATUS_AVAILABLE, yd->session_id);
 
-	if(msn)
-		yahoo_packet_hash(pkt, "ssss", 1, purple_connection_get_display_name(gc), 7, who+4, 241, "2", 13, "2");
+	if(fed)
+		yahoo_packet_hash(pkt, "ssis", 1, purple_connection_get_display_name(gc), 7, who+4, 241, fed, 13, "2");
 	else
 		yahoo_packet_hash(pkt, "sss", 1, purple_connection_get_display_name(gc), 7, who, 13, "2");
 	
@@ -4851,7 +5009,6 @@
 	struct yahoo_packet *pkt;
 	char *gpn, *gpo;
 	YahooFriend *f = yahoo_friend_find(gc, who);
-	gboolean msn = FALSE;
 	const char *temp = NULL;
 
 	/* Step 0:  If they aren't on the server list anyway,
@@ -4860,8 +5017,7 @@
 	if (!f)
 		return;
 
-	if(f->protocol == 2) {
-		msn = TRUE;
+	if(f->fed) {
 		temp = who+4;
 	} else
 		temp = who;
@@ -4879,9 +5035,9 @@
 	}
 
 	pkt = yahoo_packet_new(YAHOO_SERVICE_CHGRP_15, YAHOO_STATUS_AVAILABLE, yd->session_id);
-	if(f->protocol)
+	if(f->fed)
 		yahoo_packet_hash(pkt, "ssssissss", 1, purple_connection_get_display_name(gc),
-	                  302, "240", 300, "240", 7, temp, 241, f->protocol, 224, gpo, 264, gpn, 301,
+	                  302, "240", 300, "240", 7, temp, 241, f->fed, 224, gpo, 264, gpn, 301,
 	                  "240", 303, "240");
 	else
 		yahoo_packet_hash(pkt, "ssssssss", 1, purple_connection_get_display_name(gc),
--- a/libpurple/protocols/yahoo/libymsg.h	Mon Oct 05 00:34:33 2009 +0000
+++ b/libpurple/protocols/yahoo/libymsg.h	Mon Oct 12 05:08:37 2009 +0000
@@ -128,6 +128,20 @@
 	YAHOO_STATUS_DISCONNECTED = 0xffffffff /* in ymsg 15. doesnt mean the normal sense of 'disconnected' */
 };
 
+/*
+ * Yahoo federated networks.  Key 241 in ymsg.
+ * If it doesn't exist, it is on Yahoo's netowrk.
+ * It if does exist, send to another IM network.
+ */
+
+typedef enum {
+	YAHOO_FEDERATION_NONE = 0, /* No federation - Yahoo! network */
+	YAHOO_FEDERATION_OCS = 1,  /* LCS or OCS private networks */
+	YAHOO_FEDERATION_MSN = 2,  /* MSN or Windows Live network */
+	YAHOO_FEDERATION_IBM = 9   /* IBM/Sametime network */
+} YahooFederation;
+
+
 struct yahoo_buddy_icon_upload_data {
 	PurpleConnection *gc;
 	GString *str;
--- a/libpurple/protocols/yahoo/util.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/libpurple/protocols/yahoo/util.c	Mon Oct 12 05:08:37 2009 +0000
@@ -881,6 +881,9 @@
 						}
 						g_free(etag);
 					}
+				} else {
+					/* We don't know what the tag is. Send it unmodified. */
+					g_string_append(dest, tag);
 				}
 
 				i = j;
--- a/libpurple/protocols/yahoo/yahoo_friend.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/libpurple/protocols/yahoo/yahoo_friend.c	Mon Oct 12 05:08:37 2009 +0000
@@ -151,9 +151,8 @@
 	char *temp = NULL;
 	char *who = NULL;
 	int value = 0;
-	int protocol = 0;
-	gboolean msn = FALSE;
-
+	YahooFederation fed = YAHOO_FEDERATION_NONE;
+	
 	while (l) {
 		struct yahoo_pair *pair = l->data;
 
@@ -165,8 +164,7 @@
 				value = strtol(pair->value, NULL, 10);
 				break;
 			case 241:
-				protocol = strtol(pair->value, NULL, 10);
-				msn = TRUE;
+				fed = strtol(pair->value, NULL, 10);
 				break;
 		}
 
@@ -177,12 +175,21 @@
 		purple_debug_error("yahoo", "Received unknown value for presence key: %d\n", value);
 		return;
 	}
-
-	if(msn)
-		who = g_strconcat("msn/", temp, NULL);
-	else
-		who = g_strdup(temp);
-
+	
+	switch (fed) {
+		case YAHOO_FEDERATION_MSN:
+			who = g_strconcat("msn/", temp, NULL);
+			break;
+		case YAHOO_FEDERATION_OCS:
+			who = g_strconcat("ocs/", temp, NULL);
+			break;
+		case YAHOO_FEDERATION_IBM:
+			who = g_strconcat("ibm/", temp, NULL);
+			break;
+		case YAHOO_FEDERATION_NONE:
+			who = g_strdup(temp);
+			break;
+	}
 	g_return_if_fail(who != NULL);
 
 	f = yahoo_friend_find(gc, who);
@@ -228,12 +235,12 @@
 	f = yahoo_friend_find(gc, name);
 	if (!f)
 		return;
-
-	if(f->protocol == 2)
+	
+	if(f->fed != YAHOO_FEDERATION_NONE)
 		temp = name+4;
 	else
 		temp = name;
-
+    
 	/* No need to change the value if it is already correct */
 	if (f->presence == presence) {
 		purple_debug_info("yahoo", "Not setting presence because there are no changes.\n");
@@ -258,12 +265,12 @@
 		if (f->presence == YAHOO_PRESENCE_PERM_OFFLINE) {
 			pkt = yahoo_packet_new(YAHOO_SERVICE_PRESENCE_PERM,
 					YAHOO_STATUS_AVAILABLE, yd->session_id);
-			if(f->protocol)
+			if(f->fed)
 				yahoo_packet_hash(pkt, "ssssssiss",
 					1, purple_connection_get_display_name(gc),
 					31, "2", 13, "2",
 					302, "319", 300, "319",
-					7, temp, 241, f->protocol,
+					7, temp, 241, f->fed,
 					301, "319", 303, "319");
 			else
 				yahoo_packet_hash(pkt, "ssssssss",
@@ -285,12 +292,12 @@
 		pkt = yahoo_packet_new(service,
 				YAHOO_STATUS_AVAILABLE, yd->session_id);
 
-		if(f->protocol)
+		if(f->fed)
 			yahoo_packet_hash(pkt, "ssssssiss",
 				1, purple_connection_get_display_name(gc),
 				31, thirtyone, 13, thirteen,
 				302, "319", 300, "319",
-				7, temp, 241, f->protocol,
+				7, temp, 241, f->fed,
 				301, "319", 303, "319");
 		else
 			yahoo_packet_hash(pkt, "ssssssss",
--- a/libpurple/protocols/yahoo/yahoo_friend.h	Mon Oct 05 00:34:33 2009 +0000
+++ b/libpurple/protocols/yahoo/yahoo_friend.h	Mon Oct 12 05:08:37 2009 +0000
@@ -41,6 +41,7 @@
 	YAHOO_P2PSTATUS_WE_ARE_CLIENT
 } YahooP2PStatus;
 
+
 /* these are called friends instead of buddies mainly so I can use variables
  * named f and not confuse them with variables named b
  */
@@ -54,7 +55,7 @@
 	gchar *ip;
 	gboolean bicon_sent_request;
 	YahooPresenceVisibility presence;
-	int protocol; /* 1=LCS, 2=MSN*/
+	YahooFederation fed; 
 	long int version_id;
 	YahooPersonalDetails ypd;
 	YahooP2PStatus p2p_status;
--- a/libpurple/tests/test_yahoo_util.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/libpurple/tests/test_yahoo_util.c	Mon Oct 12 05:08:37 2009 +0000
@@ -180,6 +180,12 @@
 
 	assert_string_equal_free("\x1B[1mbold \x1B[#FF0000mred <font face=\"Comic Sans MS\" size=\"20\">larger \x1B[#000000mbacktoblack <font size=\"12\">normalsize</font>\x1B[#FF0000m</font>\x1B[#000000m\x1B[x1m",
 			yahoo_html_to_codes("<b>bold <font color=\"#FF0000\">red <font face=\"Comic Sans MS\" size=\"5\">larger <font color=\"#000000\">backtoblack <font size=\"3\">normalsize</font></font></font></font></b>"));
+
+	/* buzz/unknown tags */
+	assert_string_equal_free("<ding>",
+			yahoo_html_to_codes("<ding>"));
+	assert_string_equal_free("Unknown <tags>",
+			yahoo_html_to_codes("Unknown <tags>"));
 }
 END_TEST
 
--- a/pidgin/gtkprefs.c	Mon Oct 05 00:34:33 2009 +0000
+++ b/pidgin/gtkprefs.c	Mon Oct 12 05:08:37 2009 +0000
@@ -1833,7 +1833,7 @@
 			G_CALLBACK(network_stun_server_changed_cb), NULL);
 	gtk_widget_show(entry);
 
-	pidgin_add_widget_to_vbox(GTK_BOX(vbox), "ST_UN server:",
+	pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("ST_UN server:"),
 			sg, entry, TRUE, NULL);
 
 	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
--- a/pidgin/win32/nsis/pidgin-installer.nsi	Mon Oct 05 00:34:33 2009 +0000
+++ b/pidgin/win32/nsis/pidgin-installer.nsi	Mon Oct 12 05:08:37 2009 +0000
@@ -716,6 +716,7 @@
     Delete "$INSTDIR\ca-certs\AOL_Member_CA.pem"
     Delete "$INSTDIR\ca-certs\CAcert_Class3.pem"
     Delete "$INSTDIR\ca-certs\CAcert_Root.pem"
+    Delete "$INSTDIR\ca-certs\Entrust.net_Secure_Server_CA.pem"
     Delete "$INSTDIR\ca-certs\Equifax_Secure_CA.pem"
     Delete "$INSTDIR\ca-certs\Equifax_Secure_Global_eBusiness_CA-1.pem"
     Delete "$INSTDIR\ca-certs\GTE_CyberTrust_Global_Root.pem"
--- a/po/de.po	Mon Oct 05 00:34:33 2009 +0000
+++ b/po/de.po	Mon Oct 12 05:08:37 2009 +0000
@@ -11,8 +11,8 @@
 msgstr ""
 "Project-Id-Version: de\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-09-16 11:43+0200\n"
-"PO-Revision-Date: 2009-09-16 11:37+0200\n"
+"POT-Creation-Date: 2009-10-07 22:35+0200\n"
+"PO-Revision-Date: 2009-10-07 22:34+0200\n"
 "Last-Translator: Bjoern Voigt <bjoern@cs.tu-berlin.de>\n"
 "Language-Team: Deutsch <de@li.org>\n"
 "MIME-Version: 1.0\n"
@@ -951,6 +951,9 @@
 msgid "(none)"
 msgstr "(kein)"
 
+#. XXX: The following expects that finch_notify_message gets called. This
+#. * may not always happen, e.g. when another plugin sets its own
+#. * notify_message. So tread carefully.
 msgid "URI"
 msgstr "URI"
 
@@ -1041,10 +1044,10 @@
 msgstr "Alarm, wenn Buddy..."
 
 msgid "Signs on"
-msgstr "sich anmeldet"
+msgstr "sich angemeldet"
 
 msgid "Signs off"
-msgstr "sich abmeldet"
+msgstr "sich abgemeldet"
 
 msgid "Goes away"
 msgstr "hinausgeht"
@@ -1461,7 +1464,7 @@
 msgstr "%s hat eine Nachricht in %s gesendet"
 
 msgid "Buddy signs on/off"
-msgstr "Buddy sich an/abmeldet"
+msgstr "Buddy hat sich an- oder abgemeldet"
 
 msgid "You receive an IM"
 msgstr "Sie empfangen einen Nachricht"
@@ -1526,6 +1529,13 @@
 "\n"
 "Hole TinyURL..."
 
+#, c-format
+msgid "TinyURL for above: %s"
+msgstr "TinyURL für oben: %s"
+
+msgid "Please wait while TinyURL fetches a shorter URL ..."
+msgstr "Bitte warten Sie, während TinyURL eine kürzere URL holt ..."
+
 msgid "Only create TinyURL for URLs of this length or greater"
 msgstr "TinyURL nur für URLs mit mindestens dieser Länge generieren"
 
@@ -1885,6 +1895,10 @@
 msgstr "Auflösungsprozess hat sich beendet ohne die Anfrage zu beantworten"
 
 #, c-format
+msgid "Error converting %s to punycode: %d"
+msgstr "Fehler beim Konvertieren von %s zu Punycode: %d"
+
+#, c-format
 msgid "Thread creation failure: %s"
 msgstr "Fehler beim Erzeugen eines Threads: %s"
 
@@ -2898,7 +2912,7 @@
 msgstr "Buddy _untätig wird"
 
 msgid "Buddy _Signs On/Off"
-msgstr "Buddy _sich an/abmeldet"
+msgstr "Buddy hat_sich an- oder abgemeldet"
 
 #. *< type
 #. *< ui_requirement
@@ -5179,7 +5193,7 @@
 #, c-format
 msgid ""
 "Unable to add the buddy %s because the username is invalid.  Usernames must "
-"be a valid email address."
+"be valid email addresses."
 msgstr ""
 "Konnte den Buddy %s nicht hinzufügen, da der Benutzername ungültig ist.  "
 "Benutzernamen müssen gültige E-Mail-Adressen sein."
@@ -9708,6 +9722,17 @@
 msgid "Open Inbox"
 msgstr "Öffne Posteingang"
 
+msgid "Can't send SMS. Unable to obtain mobile carrier."
+msgstr ""
+"Die SMS kann nicht gesendet werden. Es konnte kein Mobilfunkkanal erreicht "
+"werden."
+
+msgid "Can't send SMS. Unknown mobile carrier."
+msgstr "Die SMS kann nicht gesendet werden. Unbekannter Mobilfunkkanal."
+
+msgid "Getting mobile carrier to send the SMS."
+msgstr "Hole einen Mobilfunkkanal zum Senden der SMS."
+
 #. Write a local message to this conversation showing that a request for a
 #. * Doodle session has been made
 #.
@@ -12376,7 +12401,7 @@
 msgstr "Verwerfen"
 
 msgid "<span weight=\"bold\" size=\"larger\">You have pounced!</span>"
-msgstr "<span weight=\"bold\" size=\"larger\">Sie haben geklopft!</span>"
+msgstr "<span weight=\"bold\" size=\"larger\">Sie wurden angestoßen!</span>"
 
 msgid "The following plugins will be unloaded."
 msgstr "Die folgenden Plugins werden entladen."
@@ -12440,10 +12465,10 @@
 msgstr "Budd_y-Name:"
 
 msgid "Si_gns on"
-msgstr "si_ch anmeldet"
+msgstr "si_ch angemeldet"
 
 msgid "Signs o_ff"
-msgstr "sich abmel_det"
+msgstr "sich abgemel_det"
 
 msgid "Goes a_way"
 msgstr "hinausgeh_t"
@@ -12509,7 +12534,7 @@
 msgstr "Hat beim Tippen angehalten"
 
 msgid "Signed on"
-msgstr "Hat sich anmeldet"
+msgstr "Hat sich angemeldet"
 
 msgid "Returned from being idle"
 msgstr "Ist nicht mehr inaktiv"
@@ -12521,7 +12546,7 @@
 msgstr "Hat das Tippen gestoppt"
 
 msgid "Signed off"
-msgstr "Hat sich abmeldet"
+msgstr "Hat sich abgemeldet"
 
 msgid "Became idle"
 msgstr "Wurde untätig"
@@ -12535,6 +12560,21 @@
 msgid "Unknown.... Please report this!"
 msgstr "Unbekannt.... Bitte berichten Sie dieses Problem!"
 
+msgid "(Custom)"
+msgstr "(Benutzerdefiniert)"
+
+msgid "(Default)"
+msgstr "(Standard)"
+
+msgid "The default Pidgin sound theme"
+msgstr "Das Standard-Klangthema für Pidgin"
+
+msgid "The default Pidgin buddy list theme"
+msgstr "Das Standard-Buddy-Listen-Thema für Pidgin"
+
+msgid "The default Pidgin status icon theme"
+msgstr "Das Standard-Status-Icon-Thema für Pidgin"
+
 msgid "Theme failed to unpack."
 msgstr "Thema konnte nicht entpackt werden."
 
@@ -14381,9 +14421,6 @@
 "\n"
 "* Hinweis: Dieses Plugin verlangt Win2000 oder höher."
 
-msgid "GTK+ Runtime Version"
-msgstr "GTK+ Runtime Version"
-
 #. Autostart
 msgid "Startup"
 msgstr "Start"
@@ -14392,6 +14429,9 @@
 msgid "_Start %s on Windows startup"
 msgstr "_Starte %s beim Windows-Start"
 
+msgid "Allow multiple instances"
+msgstr "Mehrere Instanzen erlauben"
+
 msgid "_Dockable Buddy List"
 msgstr "An_dockbare Buddy-Liste"
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/ca-certs/Entrust.net_Secure_Server_CA.pem	Mon Oct 12 05:08:37 2009 +0000
@@ -0,0 +1,28 @@
+-----BEGIN CERTIFICATE-----
+MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC
+VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u
+ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc
+KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u
+ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1
+MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE
+ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j
+b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF
+bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg
+U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA
+A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/
+I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3
+wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC
+AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb
+oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5
+BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p
+dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk
+MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp
+b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu
+dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0
+MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi
+E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa
+MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI
+hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN
+95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd
+2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=
+-----END CERTIFICATE-----
--- a/share/ca-certs/Makefile.am	Mon Oct 05 00:34:33 2009 +0000
+++ b/share/ca-certs/Makefile.am	Mon Oct 12 05:08:37 2009 +0000
@@ -2,6 +2,7 @@
 		America_Online_Root_Certification_Authority_1.pem \
 		CAcert_Root.pem \
 		CAcert_Class3.pem \
+		Entrust.net_Secure_Server_CA.pem \
 		Equifax_Secure_CA.pem \
 		Equifax_Secure_Global_eBusiness_CA-1.pem \
 		GTE_CyberTrust_Global_Root.pem \