changeset 32663:79a8ed88de20

propagate from branch 'im.pidgin.pidgin' (head bfb757dfe6b2549ab37a9b19f78f5f1f2f9df0cd) to branch 'im.pidgin.cpw.qulogic.gtk3' (head 73a08f798ab6ede72ea1c28a63c2dc0cc23db620)
author Elliott Sales de Andrade <qulogic@pidgin.im>
date Mon, 21 Mar 2011 01:53:46 +0000
parents 1b4988e242fc (current diff) 62dc884f2dec (diff)
children d1315b4e1e4a
files pidgin/gtkaccount.c pidgin/gtkblist.c pidgin/gtkconv.c pidgin/gtkutils.h
diffstat 38 files changed, 367 insertions(+), 204 deletions(-) [+]
line wrap: on
line diff
--- a/.mtn-ignore	Tue Mar 15 04:33:51 2011 +0000
+++ b/.mtn-ignore	Mon Mar 21 01:53:46 2011 +0000
@@ -1,8 +1,8 @@
+(.*/)?TAGS$
 (.*/)?\.svn
+.*/?.*\.pc$
 .*/?Makefile(\.in)?$
 .*/?Makefile\.am\.mingw$
-(.*/)?TAGS$
-.*/?.*\.pc$
 .*/perl/common/[^/]+\.c$
 .*/perl/common/blib.*
 .*/perl/common/pm_to_blib$
@@ -11,8 +11,9 @@
 .*\.dll$
 .*\.exe$
 .*\.loT$
-intltool-.*
 Doxyfile(\.mingw)?$
+VERSION$
+\.tx
 aclocal.m4
 autogen.args
 compile
@@ -24,42 +25,15 @@
 config.status
 config.sub
 configure$
+depcomp
+doc/finch.1$
+doc/html
+doc/pidgin.1$
 finch/finch$
 finch/libgnt/gntmarshal.c
 finch/libgnt/gntmarshal.h
-depcomp
-doc/finch.1$
-doc/pidgin.1$
-doc/html
-package_revision.h
-package_revision_raw.txt
-pidgin.apspec$
-pidgin.desktop$
-pidgin.spec$
-pidgin-.*.tar.gz
-pidgin-.*.tar.bz2
-pidgin-*.*.*-dbgsym$
-pidgin-*.*.*-dbgsym.zip$
-pidgin-*.*.*-win32bin$
-pidgin-*.*.*-win32-bin.zip$
-pidgin/pidgin$
-pidgin/pixmaps/emotes/default/24/theme
-pidgin/pixmaps/emotes/none/theme
-pidgin/pixmaps/emotes/small/16/theme
-pidgin/plugins/musicmessaging/music-messaging-bindings.c
-pidgin/plugins/perl/common/Makefile.PL$
-pidgin/plugins/perl/common/Makefile.old
-pidgin/win32/pidgin_dll_rc.rc$
-pidgin/win32/pidgin_exe_rc.rc$
-pidgin/win32/nsis/gtk-runtime-*.*.*.*.zip
-pidgin/win32/nsis/gtk_runtime_stage$
-pidgin/win32/nsis/pidgin-translations.nsh$
-pidgin/win32/nsis/langmacros.nsh
-pidgin/win32/nsis/nsis_translations.desktop
-pidgin/win32/nsis/pidgin-spellcheck-preselect.nsh
-pidgin/win32/nsis/pidgin-spellcheck.nsh
-pidgin/win32/nsis/translations
 install-sh
+intltool-.*
 libpurple/dbus-bindings.c
 libpurple/dbus-signals.c
 libpurple/dbus-types.c
@@ -73,10 +47,10 @@
 libpurple/plugins/perl/common/const-c.inc
 libpurple/plugins/perl/common/const-xs.inc
 libpurple/plugins/perl/common/lib
-libpurple/purple.h$
 libpurple/purple-client-bindings.c
 libpurple/purple-client-bindings.h
 libpurple/purple-client-example
+libpurple/purple.h$
 libpurple/tests/check_libpurple
 libpurple/tests/libpurple..
 libpurple/version.h$
@@ -86,6 +60,34 @@
 ltmain.sh
 missing
 mkinstalldirs
+package_revision.h
+package_revision_raw.txt
+pidgin-*.*.*-dbgsym$
+pidgin-*.*.*-dbgsym.zip$
+pidgin-*.*.*-win32-bin.zip$
+pidgin-*.*.*-win32bin$
+pidgin-.*.tar.bz2
+pidgin-.*.tar.gz
+pidgin.apspec$
+pidgin.desktop$
+pidgin.spec$
+pidgin/pidgin$
+pidgin/pixmaps/emotes/default/24/theme
+pidgin/pixmaps/emotes/none/theme
+pidgin/pixmaps/emotes/small/16/theme
+pidgin/plugins/musicmessaging/music-messaging-bindings.c
+pidgin/plugins/perl/common/Makefile.PL$
+pidgin/plugins/perl/common/Makefile.old
+pidgin/win32/nsis/gtk-runtime-*.*.*.*.zip
+pidgin/win32/nsis/gtk_runtime_stage$
+pidgin/win32/nsis/langmacros.nsh
+pidgin/win32/nsis/nsis_translations.desktop
+pidgin/win32/nsis/pidgin-spellcheck-preselect.nsh
+pidgin/win32/nsis/pidgin-spellcheck.nsh
+pidgin/win32/nsis/pidgin-translations.nsh$
+pidgin/win32/nsis/translations
+pidgin/win32/pidgin_dll_rc.rc$
+pidgin/win32/pidgin_exe_rc.rc$
 po/Makefile.in.in
 po/POTFILES$
 po/missing
@@ -94,4 +96,3 @@
 po/stamp-it
 stamp-h1
 win32-install-dir(\.release)?
-VERSION$
--- a/ChangeLog	Tue Mar 15 04:33:51 2011 +0000
+++ b/ChangeLog	Mon Mar 21 01:53:46 2011 +0000
@@ -14,6 +14,7 @@
 	  #13095)
 	* Simple Silence Suppression is optional per-account. (Jakub Adam) (half
 	  of #13180)
+	* Fix purple-url-handler being unable to find an account.
 
 	Pidgin:
 	* Duplicate code cleanup.  (Gabriel Schulhof) (#10599)
--- a/ChangeLog.API	Tue Mar 15 04:33:51 2011 +0000
+++ b/ChangeLog.API	Mon Mar 21 01:53:46 2011 +0000
@@ -5,11 +5,21 @@
 		Added:
 		* account-authorization-requested-with-message signal (Stefan Ott)
 		  (#8690)
+		* purple_account_add_buddy_with_invite
+		* purple_account_add_buddies_with_invite
 		* purple_notify_user_info_add_pair_plaintext
 		* purple_media_get_active_local_candidates
 		* purple_media_get_active_remote_candidates
 		* purple_media_manager_get_video_caps (Jakub Adam) (#13095)
 		* purple_media_manager_set_video_caps (Jakub Adam) (#13095)
+		* Added add_buddy_with_invite to PurplePluginProtocolInfo
+		* Added add_buddies_with_invite to PurplePluginProtocolInfo
+
+		Deprecated:
+		* purple_account_add_buddy
+		* purple_account_add_buddies_with_invite
+		* add_buddy from PurplePluginProtocolInfo struct
+		* add_buddies from PurplePluginProtocolInfo struct
 
 	Pidgin:
 		Added:
--- a/finch/gntblist.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/finch/gntblist.c	Mon Mar 21 01:53:46 2011 +0000
@@ -626,6 +626,7 @@
 	const char *username = purple_request_fields_get_string(allfields, "screenname");
 	const char *alias = purple_request_fields_get_string(allfields, "alias");
 	const char *group = purple_request_fields_get_string(allfields, "group");
+	const char *invite = purple_request_fields_get_string(allfields, "invite");
 	PurpleAccount *account = purple_request_fields_get_account(allfields, "account");
 	const char *error = NULL;
 	PurpleGroup *grp;
@@ -662,7 +663,7 @@
 		purple_blist_add_buddy(buddy, NULL, grp, NULL);
 	}
 
-	purple_account_add_buddy(account, buddy);
+	purple_account_add_buddy_with_invite(account, buddy, invite);
 }
 
 static void
@@ -680,6 +681,9 @@
 	field = purple_request_field_string_new("alias", _("Alias (optional)"), alias, FALSE);
 	purple_request_field_group_add_field(group, field);
 
+	field = purple_request_field_string_new("invite", _("Invite message (optional)"), NULL, FALSE);
+	purple_request_field_group_add_field(group, field);
+
 	field = purple_request_field_string_new("group", _("Add in group"), grp, FALSE);
 	purple_request_field_group_add_field(group, field);
 	purple_request_field_set_type_hint(field, "group");
--- a/libpurple/account.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/account.c	Mon Mar 21 01:53:46 2011 +0000
@@ -2540,8 +2540,37 @@
 	if (prpl != NULL)
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
 
-	if (prpl_info != NULL && prpl_info->add_buddy != NULL)
-		prpl_info->add_buddy(gc, buddy, purple_buddy_get_group(buddy));
+	if (prpl_info != NULL) {
+		if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, add_buddy_with_invite))
+			prpl_info->add_buddy_with_invite(gc, buddy, purple_buddy_get_group(buddy), NULL);
+		else if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, add_buddy))
+			prpl_info->add_buddy(gc, buddy, purple_buddy_get_group(buddy));
+	}
+}
+
+void
+purple_account_add_buddy_with_invite(PurpleAccount *account, PurpleBuddy *buddy, const char *message)
+{
+	PurplePluginProtocolInfo *prpl_info = NULL;
+	PurpleConnection *gc;
+	PurplePlugin *prpl = NULL;
+
+	g_return_if_fail(account != NULL);
+	g_return_if_fail(buddy != NULL);
+
+	gc = purple_account_get_connection(account);
+	if (gc != NULL)
+		prpl = purple_connection_get_prpl(gc);
+
+	if (prpl != NULL)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+
+	if (prpl_info != NULL) {
+		if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, add_buddy_with_invite))
+			prpl_info->add_buddy_with_invite(gc, buddy, purple_buddy_get_group(buddy), message);
+		else if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, add_buddy))
+			prpl_info->add_buddy(gc, buddy, purple_buddy_get_group(buddy));
+	}
 }
 
 void
@@ -2566,9 +2595,69 @@
 			groups = g_list_append(groups, purple_buddy_get_group(buddy));
 		}
 
-		if (prpl_info->add_buddies != NULL)
+		if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, add_buddies_with_invite))
+			prpl_info->add_buddies_with_invite(gc, buddies, groups, NULL);
+		else if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, add_buddies))
 			prpl_info->add_buddies(gc, buddies, groups);
-		else if (prpl_info->add_buddy != NULL) {
+		else if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, add_buddy_with_invite)) {
+			GList *curb = buddies, *curg = groups;
+
+			while ((curb != NULL) && (curg != NULL)) {
+				prpl_info->add_buddy_with_invite(gc, curb->data, curg->data, NULL);
+				curb = curb->next;
+				curg = curg->next;
+			}
+		}
+		else if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, add_buddy)) {
+			GList *curb = buddies, *curg = groups;
+
+			while ((curb != NULL) && (curg != NULL)) {
+				prpl_info->add_buddy(gc, curb->data, curg->data);
+				curb = curb->next;
+				curg = curg->next;
+			}
+		}
+
+		g_list_free(groups);
+	}
+}
+
+void
+purple_account_add_buddies_with_invite(PurpleAccount *account, GList *buddies, const char *message)
+{
+	PurplePluginProtocolInfo *prpl_info = NULL;
+	PurpleConnection *gc = purple_account_get_connection(account);
+	PurplePlugin *prpl = NULL;
+
+	if (gc != NULL)
+		prpl = purple_connection_get_prpl(gc);
+
+	if (prpl != NULL)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+
+	if (prpl_info) {
+		GList *cur, *groups = NULL;
+
+		/* Make a list of what group each buddy is in */
+		for (cur = buddies; cur != NULL; cur = cur->next) {
+			PurpleBuddy *buddy = cur->data;
+			groups = g_list_append(groups, purple_buddy_get_group(buddy));
+		}
+
+		if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, add_buddies_with_invite))
+			prpl_info->add_buddies_with_invite(gc, buddies, groups, message);
+		else if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, add_buddy_with_invite)) {
+			GList *curb = buddies, *curg = groups;
+
+			while ((curb != NULL) && (curg != NULL)) {
+				prpl_info->add_buddy_with_invite(gc, curb->data, curg->data, message);
+				curb = curb->next;
+				curg = curg->next;
+			}
+		}
+		else if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, add_buddies))
+			prpl_info->add_buddies(gc, buddies, groups);
+		else if (PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, add_buddy)) {
 			GList *curb = buddies, *curg = groups;
 
 			while ((curb != NULL) && (curg != NULL)) {
--- a/libpurple/account.h	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/account.h	Mon Mar 21 01:53:46 2011 +0000
@@ -958,15 +958,40 @@
  *
  * @param account The account.
  * @param buddy The buddy to add.
+ *
+ * @deprecated Use purple_account_add_buddy_with_invite and \c NULL message.
  */
 void purple_account_add_buddy(PurpleAccount *account, PurpleBuddy *buddy);
 /**
+ * Adds a buddy to the server-side buddy list for the specified account.
+ *
+ * @param account The account.
+ * @param buddy The buddy to add.
+ * @param message The invite message.  This may be ignored by a prpl.
+ *
+ * @since 2.8.0
+ */
+void purple_account_add_buddy_with_invite(PurpleAccount *account, PurpleBuddy *buddy, const char *message);
+
+/**
  * Adds a list of buddies to the server-side buddy list.
  *
  * @param account The account.
  * @param buddies The list of PurpleBlistNodes representing the buddies to add.
+ *
+ * @deprecated Use purple_account_add_buddies_with_invite and \c NULL message.
  */
 void purple_account_add_buddies(PurpleAccount *account, GList *buddies);
+/**
+ * Adds a list of buddies to the server-side buddy list.
+ *
+ * @param account The account.
+ * @param buddies The list of PurpleBlistNodes representing the buddies to add.
+ * @param message The invite message.  This may be ignored by a prpl.
+ *
+ * @since 2.8.0
+ */
+void purple_account_add_buddies_with_invite(PurpleAccount *account, GList *buddies, const char *message);
 
 /**
  * Removes a buddy from the server-side buddy list.
--- a/libpurple/conversation.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/conversation.c	Mon Mar 21 01:53:46 2011 +0000
@@ -1218,7 +1218,7 @@
 
 	c = purple_conv_im_get_conversation(im);
 
-    if ((flags & PURPLE_MESSAGE_RECV) == PURPLE_MESSAGE_RECV) {
+	if ((flags & PURPLE_MESSAGE_RECV) == PURPLE_MESSAGE_RECV) {
 		purple_conv_im_set_typing_state(im, PURPLE_NOT_TYPING);
 	}
 
--- a/libpurple/plugins/fortuneprofile.pl	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/plugins/fortuneprofile.pl	Mon Mar 21 01:53:46 2011 +0000
@@ -51,7 +51,7 @@
 	summary          => "Sets your AIM profile to a fortune (with a header and footer of your choice).",
 	description      => "Sets your AIM profile to a fortune (with a header and footer of your choice).",
 	author           => "Sean Egan <seanegan\@gmail.com>",
-	url              => "http://gaim.sf.net/",
+	url              => "http://pidgin.im/",
 
 	load             => "plugin_load"
 );
--- a/libpurple/protocols/bonjour/bonjour.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/protocols/bonjour/bonjour.c	Mon Mar 21 01:53:46 2011 +0000
@@ -534,7 +534,9 @@
 	NULL,                                                    /* get_media_caps */
 	NULL,                                                    /* get_moods */
 	NULL,                                                    /* set_public_alias */
-	NULL                                                     /* get_public_alias */
+	NULL,                                                    /* get_public_alias */
+	NULL,                                                    /* add_buddy_with_invite */
+	NULL                                                     /* add_buddies_with_invite */
 };
 
 static PurplePluginInfo info =
--- a/libpurple/protocols/gg/gg.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/protocols/gg/gg.c	Mon Mar 21 01:53:46 2011 +0000
@@ -2580,7 +2580,9 @@
 	NULL,                            /* can_do_media */
 	NULL,				/* get_moods */
 	NULL,				/* set_public_alias */
-	NULL				/* get_public_alias */
+	NULL,				/* get_public_alias */
+	NULL,				/* add_buddy_with_invite */
+	NULL				/* add_buddies_with_invite */
 };
 
 static PurplePluginInfo info = {
--- a/libpurple/protocols/gg/lib/libgadu.h	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/protocols/gg/lib/libgadu.h	Mon Mar 21 01:53:46 2011 +0000
@@ -33,10 +33,11 @@
 #ifndef __GG_LIBGADU_H
 #define __GG_LIBGADU_H
 
-#ifdef __cplusplus
 #ifdef _WIN32
 #pragma pack(push, 1)
 #endif
+
+#ifdef __cplusplus
 extern "C" {
 #endif
 
@@ -2056,10 +2057,11 @@
 
 #ifdef __cplusplus
 }
+#endif
+
 #ifdef _WIN32
 #pragma pack(pop)
 #endif
-#endif
 
 #endif /* __GG_LIBGADU_H */
 
--- a/libpurple/protocols/irc/irc.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/protocols/irc/irc.c	Mon Mar 21 01:53:46 2011 +0000
@@ -990,7 +990,9 @@
 	NULL,					 /* get_media_caps */
 	NULL,					 /* get_moods */
 	NULL,					 /* set_public_alias */
-	NULL					 /* get_public_alias */
+	NULL,					 /* get_public_alias */
+	NULL,					 /* add_buddy_with_invite */
+	NULL					 /* add_buddies_with_invite */
 };
 
 static gboolean load_plugin (PurplePlugin *plugin) {
--- a/libpurple/protocols/jabber/libxmpp.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/protocols/jabber/libxmpp.c	Mon Mar 21 01:53:46 2011 +0000
@@ -129,7 +129,9 @@
 	jabber_get_media_caps,                  /* get_media_caps */
 	jabber_get_moods,  							/* get_moods */
 	NULL, /* set_public_alias */
-	NULL  /* get_public_alias */
+	NULL, /* get_public_alias */
+	NULL, /* add_buddy_with_invite */
+	NULL  /* add_buddies_with_invite */
 };
 
 static gboolean load_plugin(PurplePlugin *plugin)
--- a/libpurple/protocols/msn/msn.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/protocols/msn/msn.c	Mon Mar 21 01:53:46 2011 +0000
@@ -95,13 +95,6 @@
 	MsnObject *obj;
 } MsnEmoticon;
 
-typedef struct
-{
-	PurpleConnection *pc;
-	PurpleBuddy *buddy;
-	PurpleGroup *group;
-} MsnAddReqData;
-
 static const char *
 msn_normalize(const PurpleAccount *account, const char *str)
 {
@@ -1775,29 +1768,18 @@
 }
 
 static void
-finish_auth_request(MsnAddReqData *data, char *msg)
+msn_add_buddy(PurpleConnection *pc, PurpleBuddy *buddy, PurpleGroup *group, const char *message)
 {
-	PurpleConnection *pc;
-	PurpleBuddy *buddy;
-	PurpleGroup *group;
 	PurpleAccount *account;
+	const char *bname, *gname;
 	MsnSession *session;
 	MsnUserList *userlist;
-	const char *who, *gname;
 	MsnUser *user;
 
-	pc = data->pc;
-	buddy = data->buddy;
-	group = data->group;
-	g_free(data);
-
 	account = purple_connection_get_account(pc);
-	session = pc->proto_data;
-	userlist = session->userlist;
-
-	who = msn_normalize(account, purple_buddy_get_name(buddy));
-	gname = group ? purple_group_get_name(group) : NULL;
-	purple_debug_info("msn", "Add user:%s to group:%s\n", who, gname ? gname : "(null)");
+	session = purple_connection_get_protocol_data(pc);
+	bname = purple_buddy_get_name(buddy);
+
 	if (!session->logged_in)
 	{
 		purple_debug_error("msn", "msn_add_buddy called before connected\n");
@@ -1811,22 +1793,47 @@
 	 * KingAnt: But PurpleBuddys must always exist inside PurpleGroups, so
 	 * won't group always be non-NULL here?
 	 */
-	user = msn_userlist_find_user(userlist, who);
+	bname = msn_normalize(account, bname);
+	gname = group ? purple_group_get_name(group) : NULL;
+	purple_debug_info("msn", "Add user:%s to group:%s\n",
+	                  bname, gname ? gname : "(null)");
+
+	if (!msn_email_is_valid(bname)) {
+		gchar *buf;
+		buf = g_strdup_printf(_("Unable to add the buddy %s because the username is invalid.  Usernames must be valid email addresses."), bname);
+		if (!purple_conv_present_error(bname, account, buf))
+			purple_notify_error(pc, NULL, _("Unable to Add"), buf);
+		g_free(buf);
+
+		/* Remove from local list */
+		purple_blist_remove_buddy(buddy);
+
+		return;
+	}
+
+	/* Make sure name is normalized */
+	purple_blist_rename_buddy(buddy, bname);
+
+	userlist = session->userlist;
+	user = msn_userlist_find_user(userlist, bname);
+	if (user && user->authorized) {
+		message = NULL;
+	}
 	if ((user != NULL) && (user->networkid != MSN_NETWORK_UNKNOWN)) {
 		/* We already know this buddy and their network. This function knows
 		   what to do with users already in the list and stuff... */
-		msn_user_set_invite_message(user, msg);
-		msn_userlist_add_buddy(userlist, who, gname);
+		msn_user_set_invite_message(user, message);
+		msn_userlist_add_buddy(userlist, bname, gname);
 	} else {
 		char **tokens;
 		char *fqy;
 		/* We need to check the network for this buddy first */
-		user = msn_user_new(userlist, who, NULL);
-		msn_user_set_invite_message(user, msg);
+		user = msn_user_new(userlist, bname, NULL);
+		msn_user_set_invite_message(user, message);
 		msn_user_set_pending_group(user, gname);
 		msn_user_set_network(user, MSN_NETWORK_UNKNOWN);
 		/* Should probably re-use the msn_add_contact_xml function here */
-		tokens = g_strsplit(who, "@", 2);
+		tokens = g_strsplit(bname, "@", 2);
 		fqy = g_strdup_printf("<ml><d n=\"%s\"><c n=\"%s\"/></d></ml>",
 		                      tokens[1],
 		                      tokens[0]);
@@ -1840,57 +1847,6 @@
 }
 
 static void
-cancel_auth_request(MsnAddReqData *data, char *msg)
-{
-	/* Remove from local list */
-	purple_blist_remove_buddy(data->buddy);
-
-	g_free(data);
-}
-
-static void
-msn_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
-{
-	const char *bname;
-	MsnAddReqData *data;
-	MsnSession *session;
-	MsnUser *user;
-
-	bname = purple_buddy_get_name(buddy);
-
-	if (!msn_email_is_valid(bname)) {
-		gchar *buf;
-		buf = g_strdup_printf(_("Unable to add the buddy %s because the username is invalid.  Usernames must be valid email addresses."), bname);
-		if (!purple_conv_present_error(bname, purple_connection_get_account(gc), buf))
-			purple_notify_error(gc, NULL, _("Unable to Add"), buf);
-		g_free(buf);
-
-		/* Remove from local list */
-		purple_blist_remove_buddy(buddy);
-
-		return;
-	}
-
-	data = g_new0(MsnAddReqData, 1);
-	data->pc = gc;
-	data->buddy = buddy;
-	data->group = group;
-
-	session = purple_connection_get_protocol_data(gc);
-	user = msn_userlist_find_user(session->userlist, bname);
-	if (user && user->authorized) {
-		finish_auth_request(data, NULL);
-	} else {
-		purple_request_input(gc, NULL, _("Authorization Request Message:"),
-		                     NULL, _("Please authorize me!"), TRUE, FALSE, NULL,
-		                     _("_OK"), G_CALLBACK(finish_auth_request),
-		                     _("_Cancel"), G_CALLBACK(cancel_auth_request),
-		                     purple_connection_get_account(gc), bname, NULL,
-		                     data);
-	}
-}
-
-static void
 msn_rem_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
 {
 	MsnSession *session;
@@ -2971,7 +2927,7 @@
 
 static PurplePluginProtocolInfo prpl_info =
 {
-	OPT_PROTO_MAIL_CHECK,
+	OPT_PROTO_MAIL_CHECK|OPT_PROTO_INVITE_MESSAGE,
 	NULL,                               /* user_splits */
 	NULL,                               /* protocol_options */
 	{"png,gif", 0, 0, 96, 96, 0, PURPLE_ICON_SCALE_SEND},   /* icon_spec */
@@ -2992,7 +2948,7 @@
 	msn_set_status,                     /* set_away */
 	msn_set_idle,                       /* set_idle */
 	NULL,                               /* change_passwd */
-	msn_add_buddy,                      /* add_buddy */
+	NULL,                               /* add_buddy */
 	NULL,                               /* add_buddies */
 	msn_rem_buddy,                      /* remove_buddy */
 	NULL,                               /* remove_buddies */
@@ -3042,7 +2998,9 @@
 	NULL,                               /* get_media_caps */
 	NULL,                               /* get_moods */
 	msn_set_public_alias,               /* set_public_alias */
-	msn_get_public_alias                /* get_public_alias */
+	msn_get_public_alias,               /* get_public_alias */
+	msn_add_buddy,                      /* add_buddy_with_invite */
+	NULL                                /* add_buddies_with_invite */
 };
 
 static PurplePluginInfo info =
--- a/libpurple/protocols/mxit/mxit.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/protocols/mxit/mxit.c	Mon Mar 21 01:53:46 2011 +0000
@@ -742,7 +742,9 @@
 	mxit_media_caps,		/* get_media_caps */
 	mxit_get_moods,			/* get_moods */
 	NULL,					/* set_public_alias */
-	NULL					/* get_public_alias */
+	NULL,					/* get_public_alias */
+	NULL,					/* add_buddy_with_invite */
+	NULL					/* add_buddies_with_invite */
 };
 
 
--- a/libpurple/protocols/myspace/myspace.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/protocols/myspace/myspace.c	Mon Mar 21 01:53:46 2011 +0000
@@ -3097,7 +3097,9 @@
 	NULL,                   /* get_media_caps */
 	NULL,                   /* get_moods */
 	NULL,                   /* set_public_alias */
-	NULL                    /* get_public_alias */
+	NULL,                   /* get_public_alias */
+	NULL,                   /* add_buddy_with_invite */
+	NULL                    /* add_buddies_with_invite */
 };
 
 /**
--- a/libpurple/protocols/novell/novell.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/protocols/novell/novell.c	Mon Mar 21 01:53:46 2011 +0000
@@ -3531,7 +3531,9 @@
 	NULL,						/* get_media_caps */
 	NULL,						/* get_moods */
 	NULL,						/* set_public_alias */
-	NULL						/* get_public_alias */
+	NULL,						/* get_public_alias */
+	NULL,						/* add_buddy_with_invite */
+	NULL						/* add_buddies_with_invite */
 };
 
 static PurplePluginInfo info = {
--- a/libpurple/protocols/null/nullprpl.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/protocols/null/nullprpl.c	Mon Mar 21 01:53:46 2011 +0000
@@ -1120,9 +1120,11 @@
   NULL,                                /* get_account_text_table */
   NULL,                                /* initiate_media */
   NULL,                                /* get_media_caps */
+  NULL,                                /* get_moods */
   NULL,                                /* set_public_alias */
   NULL,                                /* get_public_alias */
-  NULL                                 /* get_moods */
+  NULL,                                /* add_buddy_with_invite */
+  NULL                                 /* add_buddies_with_invite */
 };
 
 static void nullprpl_init(PurplePlugin *plugin)
--- a/libpurple/protocols/oscar/authorization.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/protocols/oscar/authorization.c	Mon Mar 21 01:53:46 2011 +0000
@@ -25,20 +25,19 @@
 #include "oscar.h"
 #include "request.h"
 
-static void
-oscar_auth_request(struct name_data *data, char *msg)
+/* When you ask other people for authorization */
+void
+oscar_auth_sendrequest(PurpleConnection *gc, const char *bname, const char *msg)
 {
-	PurpleConnection *gc;
 	OscarData *od;
 	PurpleAccount *account;
 	PurpleBuddy *buddy;
 	PurpleGroup *group;
-	const char *bname, *gname;
+	const char *gname;
 
-	gc = data->gc;
 	od = purple_connection_get_protocol_data(gc);
 	account = purple_connection_get_account(gc);
-	buddy = purple_find_buddy(account, data->name);
+	buddy = purple_find_buddy(account, bname);
 	if (buddy != NULL)
 		group = purple_buddy_get_group(buddy);
 	else
@@ -46,11 +45,10 @@
 
 	if (group != NULL)
 	{
-		bname = purple_buddy_get_name(buddy);
 		gname = purple_group_get_name(group);
 		purple_debug_info("oscar", "ssi: adding buddy %s to group %s\n",
 				   bname, gname);
-		aim_ssi_sendauthrequest(od, data->name, msg ? msg : _("Please authorize me so I can add you to my buddy list."));
+		aim_ssi_sendauthrequest(od, bname, msg ? msg : _("Please authorize me so I can add you to my buddy list."));
 		if (!aim_ssi_itemlist_finditem(od->ssi.local, gname, bname, AIM_SSI_TYPE_BUDDY))
 		{
 			aim_ssi_addbuddy(od, bname, gname, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, TRUE);
@@ -66,8 +64,6 @@
 			}
 		}
 	}
-
-	oscar_free_name_data(data);
 }
 
 static void
@@ -105,24 +101,6 @@
 					   data);
 }
 
-/* When you ask other people for authorization */
-void
-oscar_auth_sendrequest(PurpleConnection *gc, const char *name)
-{
-	struct name_data *data;
-
-	data = g_new0(struct name_data, 1);
-	data->gc = gc;
-	data->name = g_strdup(name);
-
-	purple_request_input(data->gc, NULL, _("Authorization Request Message:"),
-					   NULL, _("Please authorize me!"), TRUE, FALSE, NULL,
-					   _("_OK"), G_CALLBACK(oscar_auth_request),
-					   _("_Cancel"), G_CALLBACK(oscar_free_name_data),
-					   purple_connection_get_account(gc), name, NULL,
-					   data);
-}
-
 void
 oscar_auth_sendrequest_menu(PurpleBlistNode *node, gpointer ignored)
 {
@@ -133,7 +111,7 @@
 
 	buddy = (PurpleBuddy *) node;
 	gc = purple_account_get_connection(purple_buddy_get_account(buddy));
-	oscar_auth_sendrequest(gc, purple_buddy_get_name(buddy));
+	oscar_auth_sendrequest(gc, purple_buddy_get_name(buddy), NULL);
 }
 
 /* When other people ask you for authorization */
@@ -150,4 +128,4 @@
 	purple_account_request_authorization(account, data->name, NULL, data->nick,
 		reason, purple_find_buddy(account, data->name) != NULL,
 		oscar_auth_grant, oscar_auth_dontgrant_msgprompt, data);
-}
\ No newline at end of file
+}
--- a/libpurple/protocols/oscar/family_feedbag.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/protocols/oscar/family_feedbag.c	Mon Mar 21 01:53:46 2011 +0000
@@ -1682,7 +1682,7 @@
  * granted, denied, or dropped.
  *
  */
-int aim_ssi_sendauthrequest(OscarData *od, char *bn, const char *msg)
+int aim_ssi_sendauthrequest(OscarData *od, const char *bn, const char *msg)
 {
 	FlapConnection *conn;
 	ByteStream bs;
@@ -1759,7 +1759,7 @@
  * if reply=0x01 then grant
  *
  */
-int aim_ssi_sendauthreply(OscarData *od, char *bn, guint8 reply, const char *msg)
+int aim_ssi_sendauthreply(OscarData *od, const char *bn, guint8 reply, const char *msg)
 {
 	FlapConnection *conn;
 	ByteStream bs;
--- a/libpurple/protocols/oscar/libaim.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/protocols/oscar/libaim.c	Mon Mar 21 01:53:46 2011 +0000
@@ -29,7 +29,7 @@
 
 static PurplePluginProtocolInfo prpl_info =
 {
-	OPT_PROTO_MAIL_CHECK | OPT_PROTO_IM_IMAGE,
+	OPT_PROTO_MAIL_CHECK | OPT_PROTO_IM_IMAGE | OPT_PROTO_INVITE_MESSAGE,
 	NULL,					/* user_splits */
 	NULL,					/* protocol_options */
 	{"gif,jpeg,bmp,ico", 0, 0, 100, 100, 7168, PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */
@@ -50,7 +50,7 @@
 	oscar_set_status,		/* set_status */
 	oscar_set_idle,			/* set_idle */
 	oscar_change_passwd,	/* change_passwd */
-	oscar_add_buddy,		/* add_buddy */
+	NULL,					/* add_buddy */
 	NULL,					/* add_buddies */
 	oscar_remove_buddy,		/* remove_buddy */
 	NULL,					/* remove_buddies */
@@ -100,7 +100,9 @@
 	NULL,					/* get_media_caps */
 	NULL,					/* get_moods */
 	NULL,					/* set_public_alias */
-	NULL					/* get_public_alias */
+	NULL,					/* get_public_alias */
+	oscar_add_buddy,		/* add_buddy_with_invite */
+	NULL					/* add_buddies_with_invite */
 };
 
 static PurplePluginInfo info =
--- a/libpurple/protocols/oscar/libicq.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/protocols/oscar/libicq.c	Mon Mar 21 01:53:46 2011 +0000
@@ -38,7 +38,7 @@
 
 static PurplePluginProtocolInfo prpl_info =
 {
-	OPT_PROTO_MAIL_CHECK | OPT_PROTO_IM_IMAGE,
+	OPT_PROTO_MAIL_CHECK | OPT_PROTO_IM_IMAGE | OPT_PROTO_INVITE_MESSAGE,
 	NULL,					/* user_splits */
 	NULL,					/* protocol_options */
 	{"gif,jpeg,bmp,ico", 0, 0, 100, 100, 7168, PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */
@@ -59,7 +59,7 @@
 	oscar_set_status,		/* set_status */
 	oscar_set_idle,			/* set_idle */
 	oscar_change_passwd,	/* change_passwd */
-	oscar_add_buddy,		/* add_buddy */
+	NULL,					/* add_buddy */
 	NULL,					/* add_buddies */
 	oscar_remove_buddy,		/* remove_buddy */
 	NULL,					/* remove_buddies */
@@ -110,7 +110,9 @@
 	NULL,					/* can_do_media */
 	oscar_get_purple_moods, /* get_moods */
 	NULL,					/* set_public_alias */
-	NULL					/* get_public_alias */
+	NULL,					/* get_public_alias */
+	oscar_add_buddy,		/* add_buddy_with_invite */
+	NULL					/* add_buddies_with_invite */
 };
 
 static PurplePluginInfo info =
--- a/libpurple/protocols/oscar/oscar.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Mon Mar 21 01:53:46 2011 +0000
@@ -3685,7 +3685,8 @@
 }
 
 void
-oscar_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) {
+oscar_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group, const char *msg)
+{
 	OscarData *od;
 	PurpleAccount *account;
 	const char *bname, *gname;
@@ -3725,7 +3726,7 @@
 		                                  aim_ssi_itemlist_findparentname(od->ssi.local, bname),
 		                                  bname)) {
 			/* Not authorized -- Re-request authorization */
-			oscar_auth_sendrequest(gc, bname);
+			oscar_auth_sendrequest(gc, bname, msg);
 		}
 	}
 
@@ -4175,7 +4176,7 @@
 
 			case 0x000e: { /* buddy requires authorization */
 				if ((retval->action == SNAC_SUBTYPE_FEEDBAG_ADD) && (retval->name))
-					oscar_auth_sendrequest(gc, retval->name);
+					oscar_auth_sendrequest(gc, retval->name, NULL);
 			} break;
 
 			default: { /* La la la */
@@ -5060,16 +5061,22 @@
 {
 	PurpleBuddy *buddy;
 	PurpleConnection *gc;
+	OscarData *od;
 	PurpleAccount *account;
+	const char *bname;
 
 	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
 
 	buddy = (PurpleBuddy *)node;
-	gc = purple_account_get_connection(buddy->account);
-	account = purple_connection_get_account(gc);
-	purple_debug_info("oscar", "Manual X-Status Get From %s to %s:\n", purple_buddy_get_name(buddy), account->username);
-
-	icq_im_xstatus_request(gc->proto_data, purple_buddy_get_name(buddy));
+	bname = purple_buddy_get_name(buddy);
+
+	account = purple_buddy_get_account(buddy);
+	gc = purple_account_get_connection(account);
+	od = purple_connection_get_protocol_data(gc);
+
+	purple_debug_info("oscar", "Manual X-Status Get From %s to %s:\n", bname, purple_account_get_username(account));
+
+	icq_im_xstatus_request(od, bname);
 }
 
 static void
--- a/libpurple/protocols/oscar/oscar.h	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/protocols/oscar/oscar.h	Mon Mar 21 01:53:46 2011 +0000
@@ -912,8 +912,8 @@
 /* 0x0007 */ int aim_ssi_enable(OscarData *od);
 /* 0x0011 */ int aim_ssi_modbegin(OscarData *od);
 /* 0x0012 */ int aim_ssi_modend(OscarData *od);
-/* 0x0018 */ int aim_ssi_sendauthrequest(OscarData *od, char *bn, const char *msg);
-/* 0x001a */ int aim_ssi_sendauthreply(OscarData *od, char *bn, guint8 reply, const char *msg);
+/* 0x0018 */ int aim_ssi_sendauthrequest(OscarData *od, const char *bn, const char *msg);
+/* 0x001a */ int aim_ssi_sendauthreply(OscarData *od, const char *bn, guint8 reply, const char *msg);
 
 /* Client functions for retrieving SSI data */
 struct aim_ssi_item *aim_ssi_itemlist_find(struct aim_ssi_item *list, guint16 gid, guint16 bid);
@@ -1311,7 +1311,7 @@
 void oscar_user_info_display_aim(OscarData *od, aim_userinfo_t *userinfo);
 
 /* authorization.c - OSCAR authorization requests */
-void oscar_auth_sendrequest(PurpleConnection *gc, const char *name);
+void oscar_auth_sendrequest(PurpleConnection *gc, const char *name, const char *msg);
 void oscar_auth_sendrequest_menu(PurpleBlistNode *node, gpointer ignored);
 void oscar_auth_recvrequest(PurpleConnection *gc, gchar *name, gchar *nick, gchar *reason);
 
--- a/libpurple/protocols/oscar/oscarcommon.h	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/protocols/oscar/oscarcommon.h	Mon Mar 21 01:53:46 2011 +0000
@@ -79,7 +79,7 @@
 void oscar_set_status(PurpleAccount *account, PurpleStatus *status);
 void oscar_set_idle(PurpleConnection *gc, int time);
 void oscar_change_passwd(PurpleConnection *gc, const char *old, const char *new);
-void oscar_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group);
+void oscar_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group, const char *msg);
 void oscar_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group);
 void oscar_add_permit(PurpleConnection *gc, const char *who);
 void oscar_add_deny(PurpleConnection *gc, const char *who);
--- a/libpurple/protocols/qq/qq.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/protocols/qq/qq.c	Mon Mar 21 01:53:46 2011 +0000
@@ -1042,7 +1042,9 @@
 	NULL,							/* get_media_caps */
 	NULL,							/* get_moods */
 	NULL,							/* set_public_alias */
-	NULL							/* get_public_alias */
+	NULL,							/* get_public_alias */
+	NULL,							/* add_buddy_with_invite */
+	NULL							/* add_buddies_with_invite */
 };
 
 static PurplePluginInfo info = {
--- a/libpurple/protocols/silc/silc.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/protocols/silc/silc.c	Mon Mar 21 01:53:46 2011 +0000
@@ -2123,7 +2123,9 @@
 	NULL,				        /* get_media_caps */
 	NULL,				        /* get_moods */
 	NULL,				        /* set_public_alias */
-	NULL				        /* get_public_alias */
+	NULL,				        /* get_public_alias */
+	NULL,				        /* add_buddy_with_invite */
+	NULL				        /* add_buddies_with_invite */
 };
 
 static PurplePluginInfo info =
--- a/libpurple/protocols/silc10/silc.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/protocols/silc10/silc.c	Mon Mar 21 01:53:46 2011 +0000
@@ -1845,7 +1845,9 @@
 	NULL,                       /* get_media_caps */
 	NULL,                       /* get_moods */
 	NULL,                       /* set_public_alias */
-	NULL                        /* get_public_alias */
+	NULL,                       /* get_public_alias */
+	NULL,                       /* add_buddy_with_invite */
+	NULL                        /* add_buddies_with_invite */
 };
 
 static PurplePluginInfo info =
--- a/libpurple/protocols/simple/simple.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/protocols/simple/simple.c	Mon Mar 21 01:53:46 2011 +0000
@@ -2112,7 +2112,9 @@
 	NULL,					/* get_media_caps */
 	NULL,					/* get_moods */
 	NULL,					/* set_public_alias */
-	NULL					/* get_public_alias */
+	NULL,					/* get_public_alias */
+	NULL,					/* add_buddy_with_invite */
+	NULL					/* add_buddies_with_invite */
 };
 
 
--- a/libpurple/protocols/yahoo/libyahoo.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/protocols/yahoo/libyahoo.c	Mon Mar 21 01:53:46 2011 +0000
@@ -267,7 +267,9 @@
 	NULL,  /* get_media_caps */
 	NULL,  /* get_moods */
 	NULL,  /* set_public_alias */
-	NULL   /* get_public_alias */
+	NULL,  /* get_public_alias */
+	NULL,  /* add_buddy_with_invite */
+	NULL   /* add_buddies_with_invite */
 };
 
 static PurplePluginInfo info =
--- a/libpurple/protocols/yahoo/libyahoojp.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/protocols/yahoo/libyahoojp.c	Mon Mar 21 01:53:46 2011 +0000
@@ -163,7 +163,9 @@
 	NULL, /* get_media_caps */
 	NULL, /* get_moods */
 	NULL, /* set_public_alias */
-	NULL  /* get_public_alias */
+	NULL, /* get_public_alias */
+	NULL, /* add_buddy_with_invite */
+	NULL  /* add_buddies_with_invite */
 };
 
 static PurplePluginInfo info =
--- a/libpurple/protocols/zephyr/zephyr.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/protocols/zephyr/zephyr.c	Mon Mar 21 01:53:46 2011 +0000
@@ -2911,7 +2911,9 @@
 	NULL,					/* get_media_caps */
 	NULL,					/* get_moods */
 	NULL,					/* set_public_alias */
-	NULL					/* get_public_alias */
+	NULL,					/* get_public_alias */
+	NULL,					/* add_buddy_with_invite */
+	NULL					/* add_buddies_with_invite */
 };
 
 static PurplePluginInfo info = {
--- a/libpurple/prpl.h	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/prpl.h	Mon Mar 21 01:53:46 2011 +0000
@@ -202,7 +202,14 @@
 	 * Used as a hint that unknown commands should not be sent as messages.
 	 * @since 2.1.0
 	 */
-	OPT_PROTO_SLASH_COMMANDS_NATIVE = 0x00000400
+	OPT_PROTO_SLASH_COMMANDS_NATIVE = 0x00000400,
+
+	/**
+	 * Indicates that this protocol supports sending a user-supplied message
+	 * along with an invitation.
+	 * @since 2.8.0
+	 */
+	OPT_PROTO_INVITE_MESSAGE = 0x00000800
 
 } PurpleProtocolOptions;
 
@@ -333,6 +340,9 @@
 	 * already in the specified group. If the protocol supports
 	 * authorization and the user is not already authorized to see the
 	 * status of \a buddy, \a add_buddy should request authorization.
+	 *
+	 * @deprecated Since 2.8.0, add_buddy_with_invite is preferred.
+	 * @see add_buddy_with_invite
 	 */
 	void (*add_buddy)(PurpleConnection *, PurpleBuddy *buddy, PurpleGroup *group);
 	void (*add_buddies)(PurpleConnection *, GList *buddies, GList *groups);
@@ -622,6 +632,21 @@
 	void (*get_public_alias)(PurpleConnection *gc,
 	                         PurpleGetPublicAliasSuccessCallback success_cb,
 	                         PurpleGetPublicAliasFailureCallback failure_cb);
+
+	/**
+	 * Add a buddy to a group on the server.
+	 *
+	 * This PRPL function may be called in situations in which the buddy is
+	 * already in the specified group. If the protocol supports
+	 * authorization and the user is not already authorized to see the
+	 * status of \a buddy, \a add_buddy should request authorization.
+	 *
+	 * If authorization is required, then use the supplied invite message.
+	 *
+	 * @since 2.8.0
+	 */
+	void (*add_buddy_with_invite)(PurpleConnection *pc, PurpleBuddy *buddy, PurpleGroup *group, const char *message);
+	void (*add_buddies_with_invite)(PurpleConnection *pc, GList *buddies, GList *groups, const char *message);
 };
 
 #define PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl, member) \
--- a/libpurple/purple-url-handler	Tue Mar 15 04:33:51 2011 +0000
+++ b/libpurple/purple-url-handler	Mon Mar 21 01:53:46 2011 +0000
@@ -73,7 +73,7 @@
 def findaccount(protocolname, accountname="", matcher=None):
     if matcher:
         for account in cpurple.PurpleAccountsGetAll():
-            if (protocolname != cpurple.PurpleAccountGetProtocolID(account)) or \
+            if (protocolname != cpurple.PurpleAccountGetProtocolId(account)) or \
                (accountname != "" and accountname != cpurple.PurpleAccountGetUsername(account)):
                 continue
             if matcher(account):
@@ -188,7 +188,7 @@
         print "Invalid irc URI: %s" % uri
         return
 
-    server = urllib.unquote_plus(match.group(2)) or ""
+    server = urllib.unquote_plus(match.group(2) or "")
     target = match.group(3) or ""
     query = match.group(5) or ""
 
--- a/pidgin/gtkaccount.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/pidgin/gtkaccount.c	Mon Mar 21 01:53:46 2011 +0000
@@ -1207,7 +1207,7 @@
 add_voice_options(AccountPrefsDialog *dialog)
 {
 #ifdef USE_VV
-	if (!dialog->prpl_info || !dialog->prpl_info->initiate_media) {
+	if (!dialog->prpl_info || !PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(dialog->prpl_info, initiate_media)) {
 		if (dialog->voice_frame) {
 			gtk_widget_destroy(dialog->voice_frame);
 			dialog->voice_frame = NULL;
--- a/pidgin/gtkblist.c	Tue Mar 15 04:33:51 2011 +0000
+++ b/pidgin/gtkblist.c	Mon Mar 21 01:53:46 2011 +0000
@@ -85,6 +85,7 @@
 	GtkWidget *combo;
 	GtkWidget *entry;
 	GtkWidget *entry_for_alias;
+	GtkWidget *entry_for_invite;
 
 } PidginAddBuddyData;
 
@@ -7151,8 +7152,24 @@
 add_buddy_select_account_cb(GObject *w, PurpleAccount *account,
 							PidginAddBuddyData *data)
 {
+	PurpleConnection *pc = NULL;
+	PurplePlugin *prpl = NULL;
+	PurplePluginProtocolInfo *prpl_info = NULL;
+	gboolean invite_enabled = TRUE;
+
 	/* Save our account */
 	data->rq_data.account = account;
+
+	if (account)
+		pc = purple_account_get_connection(account);
+	if (pc)
+		prpl = purple_connection_get_prpl(pc);
+	if (prpl)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+	if (prpl_info && !(prpl_info->options & OPT_PROTO_INVITE_MESSAGE))
+		invite_enabled = FALSE;
+
+	gtk_widget_set_sensitive(data->entry_for_invite, invite_enabled);
 }
 
 static void
@@ -7164,7 +7181,7 @@
 static void
 add_buddy_cb(GtkWidget *w, int resp, PidginAddBuddyData *data)
 {
-	const char *grp, *who, *whoalias;
+	const char *grp, *who, *whoalias, *invite;
 	PurpleAccount *account;
 	PurpleGroup *g;
 	PurpleBuddy *b;
@@ -7178,6 +7195,9 @@
 		whoalias = gtk_entry_get_text(GTK_ENTRY(data->entry_for_alias));
 		if (*whoalias == '\0')
 			whoalias = NULL;
+		invite = gtk_entry_get_text(GTK_ENTRY(data->entry_for_invite));
+		if (*invite == '\0')
+			invite = NULL;
 
 		account = data->rq_data.account;
 
@@ -7203,7 +7223,7 @@
 			purple_blist_add_buddy(b, NULL, g, NULL);
 		}
 
-		purple_account_add_buddy(account, b);
+		purple_account_add_buddy_with_invite(account, b, invite);
 
 		/* Offer to merge people with the same alias. */
 		if (whoalias != NULL && g != NULL)
@@ -7241,9 +7261,11 @@
 {
 	PidginAddBuddyData *data = g_new0(PidginAddBuddyData, 1);
 
+	if (account == NULL)
+		account = purple_connection_get_account(purple_connections_get_all()->data);
+
 	make_blist_request_dialog((PidginBlistRequestData *)data,
-		(account != NULL
-			? account : purple_connection_get_account(purple_connections_get_all()->data)),
+		account,
 		_("Add Buddy"), "add_buddy",
 		_("Add a buddy.\n"),
 		G_CALLBACK(add_buddy_select_account_cb), NULL,
@@ -7287,11 +7309,19 @@
 	if (username != NULL)
 		gtk_widget_grab_focus(GTK_WIDGET(data->entry_for_alias));
 
+	data->entry_for_invite = gtk_entry_new();
+	pidgin_add_widget_to_vbox(data->rq_data.vbox, _("(Optional) _Invite message:"),
+	                          data->rq_data.sg, data->entry_for_invite, TRUE,
+	                          NULL);
+
 	data->combo = pidgin_text_combo_box_entry_new(group, groups_tree());
 	pidgin_add_widget_to_vbox(data->rq_data.vbox, _("Add buddy to _group:"),
 	                          data->rq_data.sg, data->combo, TRUE, NULL);
 
 	gtk_widget_show_all(data->rq_data.window);
+
+	/* Force update of invite message entry sensitivity */
+	add_buddy_select_account_cb(NULL, account, data);
 }
 
 static void
--- a/pidgin/gtkutils.h	Tue Mar 15 04:33:51 2011 +0000
+++ b/pidgin/gtkutils.h	Mon Mar 21 01:53:46 2011 +0000
@@ -364,7 +364,7 @@
  * Add autocompletion of screenames to an entry, supporting a filtering function.
  *
  * @param entry       The GtkEntry on which to setup autocomplete.
- * @param optmenu     A menu for accounts, returned by gaim_gtk_account_option_menu_new().
+ * @param optmenu     A menu for accounts, returned by pidgin_account_option_menu_new().
  *                    If @a optmenu is not @c NULL, it'll be updated when a username is chosen
  *                    from the autocomplete list.
  * @param filter_func A function for checking if an autocomplete entry
--- a/po/l10n.xsl	Tue Mar 15 04:33:51 2011 +0000
+++ b/po/l10n.xsl	Mon Mar 21 01:53:46 2011 +0000
@@ -12,7 +12,6 @@
 			<head>
 				<title><xsl:value-of select='@name'/> translation statistics</title>
 				<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-				<!-- <link rel="Stylesheet" href="/gaim.css" type="text/css" media="screen" /> -->
 				<style type="text/css">
 					.bargraph {
 						width: 200px;