changeset 28283:46cf492641d4

merge of '605082e5e72e95dface3580569a0737cbd95e368' and 'ad3059728a95ccf78fc978ee56938a5176224948'
author Elliott Sales de Andrade <qulogic@pidgin.im>
date Tue, 22 Sep 2009 02:07:26 +0000
parents 23615d141245 (diff) 5ef119455f0d (current diff)
children 7983230cc1c0
files
diffstat 19 files changed, 235 insertions(+), 203 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sat Sep 12 02:25:38 2009 +0000
+++ b/ChangeLog	Tue Sep 22 02:07:26 2009 +0000
@@ -4,6 +4,10 @@
 	XMPP:
 	* Fix a crash when attempting to validate an invalid JID.
 
+	General:
+	* New 'plugins' sub-command to 'debug' command (i.e. '/debug plugins')
+	  to announce the list of loaded plugins (in both Finch and Pidgin).
+
 version 2.6.2 (09/05/2009):
 	libpurple:
 	* Fix --disable-avahi to actually disable it in configure, as opposed
--- a/ChangeLog.API	Sat Sep 12 02:25:38 2009 +0000
+++ b/ChangeLog.API	Tue Sep 22 02:07:26 2009 +0000
@@ -34,7 +34,6 @@
 		  and fwrite for saving a file locally. These allow a UI to stream a
 		  file through a socket without buffering the file on the local disk.
 		* Jabber plugin signals (see jabber-signals.dox)
-		* purple_account_get_name_for_display
 		* purple_account_remove_setting
 		* purple_buddy_destroy
 		* purple_buddy_get_protocol_data
--- a/doc/finch.1.in	Sat Sep 12 02:25:38 2009 +0000
+++ b/doc/finch.1.in	Tue Sep 22 02:07:26 2009 +0000
@@ -40,14 +40,14 @@
 The following options are provided by \fBfinch\fR using the standard GNU
 command line syntax:
 .TP
+.B \-c, \-\-config=\fIDIR\fB
+Use \fIDIR\fR as the directory for config files instead of \fI~/.purple\fR.
+.TP
 .B \-d, \-\-debug
 Print debugging messages to stderr and start with the \fBDebug\fR window. The
 messages shown in the \fBDebug\fR window are the same as the ones printed in
 stderr.
 .TP
-.B \-c, \-\-config=\fIDIR\fB
-Use \fIDIR\fR as the directory for config files instead of \fI~/.purple\fR.
-.TP
 .B \-h, \-\-help
 Print this help and exit.
 .TP
--- a/doc/pidgin.1.in	Sat Sep 12 02:25:38 2009 +0000
+++ b/doc/pidgin.1.in	Tue Sep 22 02:07:26 2009 +0000
@@ -49,6 +49,10 @@
 Print debugging messages to stdout.  These are the same debugging messages
 that are displayed in the \fBDebug Window\fR.
 .TP
+.B \-f, \-\-force-online
+Try to be online even if the network is reported (by Windows, or NetworkManager
+on Linux) to be unavailable.
+.TP
 .B \-h, \-\-help
 Print a summary of command line options and exit.
 .TP
--- a/finch/gntconv.c	Sat Sep 12 02:25:38 2009 +0000
+++ b/finch/gntconv.c	Tue Sep 22 02:07:26 2009 +0000
@@ -29,6 +29,7 @@
 #include <internal.h>
 
 #include <cmds.h>
+#include <core.h>
 #include <idle.h>
 #include <prefs.h>
 #include <util.h>
@@ -1181,22 +1182,43 @@
                  const char *cmd, char **args, char **error, void *data)
 {
 	char *tmp, *markup;
-	PurpleCmdStatus status;
 
 	if (!g_ascii_strcasecmp(args[0], "version")) {
-		tmp = g_strdup_printf("me is using Finch v%s.", DISPLAY_VERSION);
-		markup = g_markup_escape_text(tmp, -1);
-
-		status = purple_cmd_do_command(conv, tmp, markup, error);
+		tmp = g_strdup_printf("Using Finch v%s with libpurple v%s.",
+				DISPLAY_VERSION, purple_core_get_version());
+	} else if (!g_ascii_strcasecmp(args[0], "plugins")) {
+		/* Show all the loaded plugins, including the protocol plugins and plugin loaders.
+		 * This is intentional, since third party prpls are often sources of bugs, and some
+		 * plugin loaders (e.g. mono) can also be buggy.
+		 */
+		GString *str = g_string_new("Loaded Plugins: ");
+		const GList *plugins = purple_plugins_get_loaded();
+		if (plugins) {
+			for (; plugins; plugins = plugins->next) {
+				str = g_string_append(str, purple_plugin_get_name(plugins->data));
+				if (plugins->next)
+					str = g_string_append(str, ", ");
+			}
+		} else {
+			str = g_string_append(str, "(none)");
+		}
 
-		g_free(tmp);
-		g_free(markup);
-		return status;
+		tmp = g_string_free(str, FALSE);
 	} else {
-		purple_conversation_write(conv, NULL, _("Supported debug options are:  version"),
+		purple_conversation_write(conv, NULL, _("Supported debug options are: plugins version"),
 		                        PURPLE_MESSAGE_NO_LOG|PURPLE_MESSAGE_ERROR, time(NULL));
-		return PURPLE_CMD_STATUS_OK;
+		return PURPLE_CMD_RET_OK;
 	}
+
+	markup = g_markup_escape_text(tmp, -1);
+	if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM)
+		purple_conv_im_send(PURPLE_CONV_IM(conv), markup);
+	else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT)
+		purple_conv_chat_send(PURPLE_CONV_CHAT(conv), markup);
+
+	g_free(tmp);
+	g_free(markup);
+	return PURPLE_CMD_RET_OK;
 }
 
 /* Xerox */
@@ -1207,7 +1229,7 @@
 	FinchConv *ggconv = FINCH_GET_DATA(conv);
 	gnt_text_view_clear(GNT_TEXT_VIEW(ggconv->tv));
 	purple_conversation_clear_message_history(conv);
-	return PURPLE_CMD_STATUS_OK;
+	return PURPLE_CMD_RET_OK;
 }
 
 /* Xerox */
@@ -1247,7 +1269,7 @@
 	purple_conversation_write(conv, NULL, s->str, PURPLE_MESSAGE_NO_LOG, time(NULL));
 	g_string_free(s, TRUE);
 
-	return PURPLE_CMD_STATUS_OK;
+	return PURPLE_CMD_RET_OK;
 }
 
 static PurpleCmdRet
@@ -1255,7 +1277,7 @@
 {
 	void (*callback)(void) = data;
 	callback();
-	return PURPLE_CMD_STATUS_OK;
+	return PURPLE_CMD_RET_OK;
 }
 
 #if GLIB_CHECK_VERSION(2,6,0)
@@ -1278,26 +1300,26 @@
 	else {
 		if (error)
 			*error = g_strdup_printf(_("%s is not a valid message class. See '/help msgcolor' for valid message classes."), args[0]);
-		return PURPLE_CMD_STATUS_FAILED;
+		return PURPLE_CMD_RET_FAILED;
 	}
 
 	fg = gnt_colors_get_color(args[1]);
 	if (fg == -EINVAL) {
 		if (error)
 			*error = g_strdup_printf(_("%s is not a valid color. See '/help msgcolor' for valid colors."), args[1]);
-		return PURPLE_CMD_STATUS_FAILED;
+		return PURPLE_CMD_RET_FAILED;
 	}
 
 	bg = gnt_colors_get_color(args[2]);
 	if (bg == -EINVAL) {
 		if (error)
 			*error = g_strdup_printf(_("%s is not a valid color. See '/help msgcolor' for valid colors."), args[2]);
-		return PURPLE_CMD_STATUS_FAILED;
+		return PURPLE_CMD_RET_FAILED;
 	}
 
 	init_pair(*msgclass, fg, bg);
 
-	return PURPLE_CMD_STATUS_OK;
+	return PURPLE_CMD_RET_OK;
 }
 #endif
 
@@ -1307,7 +1329,7 @@
 	FinchConv *fc = FINCH_GET_DATA(conv);
 	FinchConvChat *ch;
 	if (!fc)
-		return PURPLE_CMD_STATUS_FAILED;
+		return PURPLE_CMD_RET_FAILED;
 
 	ch = fc->u.chat;
 	gnt_widget_set_visible(ch->userlist,
@@ -1315,7 +1337,7 @@
 	gnt_box_readjust(GNT_BOX(fc->window));
 	gnt_box_give_focus_to_child(GNT_BOX(fc->window), fc->entry);
 	purple_prefs_set_bool(PREF_USERLIST, !(GNT_WIDGET_IS_FLAG_SET(ch->userlist, GNT_WIDGET_INVISIBLE)));
-	return PURPLE_CMD_STATUS_OK;
+	return PURPLE_CMD_RET_OK;
 }
 
 void finch_conversation_init()
--- a/libpurple/account.c	Sat Sep 12 02:25:38 2009 +0000
+++ b/libpurple/account.c	Tue Sep 22 02:07:26 2009 +0000
@@ -2019,42 +2019,6 @@
 	return account->gc;
 }
 
-const gchar *
-purple_account_get_name_for_display(const PurpleAccount *account)
-{
-	PurpleBuddy *self = NULL;
-	PurpleConnection *gc = NULL;
-	const gchar *name = NULL, *username = NULL, *displayname = NULL;
-
-	name = purple_account_get_alias(account);
-
-	if (name) {
-		return name;
-	}
-
-	username = purple_account_get_username(account);
-	self = purple_find_buddy((PurpleAccount *)account, username);
-
-	if (self) {
-		const gchar *calias= purple_buddy_get_contact_alias(self);
-
-		/* We don't want to return the buddy name if the buddy/contact
-		 * doesn't have an alias set. */
-		if (!purple_strequal(username, calias)) {
-			return calias;
-		}
-	}
-
-	gc = purple_account_get_connection(account);
-	displayname = purple_connection_get_display_name(gc);
-
-	if (displayname) {
-		return displayname;
-	}
-
-	return username;
-}
-
 gboolean
 purple_account_get_remember_password(const PurpleAccount *account)
 {
--- a/libpurple/account.h	Sat Sep 12 02:25:38 2009 +0000
+++ b/libpurple/account.h	Tue Sep 22 02:07:26 2009 +0000
@@ -630,20 +630,6 @@
 PurpleConnection *purple_account_get_connection(const PurpleAccount *account);
 
 /**
- * Returns a name for this account appropriate for display to the user. In
- * order of preference: the account's alias; the contact or buddy alias (if
- * the account exists on its own buddy list); the connection's display name;
- * the account's username.
- *
- * @param account The account.
- *
- * @return The name to display.
- *
- * @since 2.7.0
- */
-const gchar *purple_account_get_name_for_display(const PurpleAccount *account);
-
-/**
  * Returns whether or not this account should save its password.
  *
  * @param account The account.
--- a/libpurple/media.c	Sat Sep 12 02:25:38 2009 +0000
+++ b/libpurple/media.c	Tue Sep 22 02:07:26 2009 +0000
@@ -2153,7 +2153,7 @@
 			GstElement *lastElement = NULL;
 			while (!GST_IS_PIPELINE(element)) {
 				if (element == media->priv->confbin) {
-					purple_media_error(media, _("Conference error."));
+					purple_media_error(media, _("Conference error"));
 					purple_media_end(media, NULL, NULL);
 					break;
 				}
@@ -2167,9 +2167,9 @@
 
 					if (session->src == lastElement) {
 						if (session->type & PURPLE_MEDIA_AUDIO)
-							purple_media_error(media, _("Error with your microphone."));
+							purple_media_error(media, _("Error with your microphone"));
 						else
-							purple_media_error(media, _("Error with your webcam."));
+							purple_media_error(media, _("Error with your webcam"));
 						purple_media_end(media, NULL, NULL);
 						break;
 					}
--- a/libpurple/protocols/jabber/jabber.c	Sat Sep 12 02:25:38 2009 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Tue Sep 22 02:07:26 2009 +0000
@@ -3465,15 +3465,16 @@
 
 	/* Jingle features! */
 	jabber_add_feature(JINGLE, 0);
-	jabber_add_feature(JINGLE_TRANSPORT_RAWUDP, 0);
 
 #ifdef USE_VV
 	jabber_add_feature("http://www.google.com/xmpp/protocol/session", jabber_audio_enabled);
 	jabber_add_feature("http://www.google.com/xmpp/protocol/voice/v1", jabber_audio_enabled);
 	jabber_add_feature("http://www.google.com/xmpp/protocol/video/v1", jabber_video_enabled);
 	jabber_add_feature("http://www.google.com/xmpp/protocol/camera/v1", jabber_video_enabled);
+	jabber_add_feature(JINGLE_APP_RTP, 0);
 	jabber_add_feature(JINGLE_APP_RTP_SUPPORT_AUDIO, jabber_audio_enabled);
 	jabber_add_feature(JINGLE_APP_RTP_SUPPORT_VIDEO, jabber_video_enabled);
+	jabber_add_feature(JINGLE_TRANSPORT_RAWUDP, 0);
 	jabber_add_feature(JINGLE_TRANSPORT_ICEUDP, 0);
 #endif
 
--- a/libpurple/protocols/msn/msn.c	Sat Sep 12 02:25:38 2009 +0000
+++ b/libpurple/protocols/msn/msn.c	Tue Sep 22 02:07:26 2009 +0000
@@ -1423,7 +1423,7 @@
 	{
 		PurpleBuddy * buddy = purple_find_buddy(session->account, who);
 		gchar *buf;
-		buf = g_strdup_printf(_("Unable to add the buddy %s because the username is invalid.  Usernames must be a valid email address."), who);
+		buf = g_strdup_printf(_("Unable to add the buddy %s because the username is invalid.  Usernames must be valid email addresses."), who);
 		if (!purple_conv_present_error(who, session->account, buf))
 			purple_notify_error(purple_account_get_connection(session->account), NULL, _("Unable to Add"), buf);
 		g_free(buf);
@@ -1513,7 +1513,7 @@
 
 	if (!purple_email_is_valid(bname)) {
 		gchar *buf;
-		buf = g_strdup_printf(_("Unable to add the buddy %s because the username is invalid.  Usernames must be a valid email address."), bname);
+		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);
--- a/libpurple/protocols/msn/oim.c	Sat Sep 12 02:25:38 2009 +0000
+++ b/libpurple/protocols/msn/oim.c	Tue Sep 22 02:07:26 2009 +0000
@@ -172,8 +172,18 @@
 
 	if (faultcode) {
 		gchar *faultcode_str = xmlnode_get_data(faultcode);
+		gboolean need_token_update = FALSE;
 
-		if (faultcode_str && g_str_equal(faultcode_str, "q0:BadContextToken")) {
+		if (faultcode_str) {
+			if (g_str_equal(faultcode_str, "q0:BadContextToken") ||
+				g_str_equal(faultcode_str, "AuthenticationFailed"))
+				need_token_update = TRUE;
+			else if (g_str_equal(faultcode_str, "q0:AuthenticationFailed") &&
+				xmlnode_get_child(fault, "detail/RequiredAuthPolicy") != NULL)
+				need_token_update = TRUE;
+		}
+
+		if (need_token_update) {
 			purple_debug_warning("msn", "OIM Request Error, Updating token now.\n");
 			msn_nexus_update_token(data->oim->session->nexus,
 				data->send ? MSN_AUTH_LIVE_SECURE : MSN_AUTH_MESSENGER_WEB,
@@ -181,16 +191,8 @@
 			g_free(faultcode_str);
 			return;
 
-		} else if (faultcode_str && g_str_equal(faultcode_str, "q0:AuthenticationFailed")) {
-			if (xmlnode_get_child(fault, "detail/RequiredAuthPolicy") != NULL) {
-				purple_debug_warning("msn", "OIM Request Error, Updating token now.\n");
-				msn_nexus_update_token(data->oim->session->nexus,
-					data->send ? MSN_AUTH_LIVE_SECURE : MSN_AUTH_MESSENGER_WEB,
-					(GSourceFunc)msn_oim_request_helper, data);
-				g_free(faultcode_str);
-				return;
-			}
 		}
+
 		g_free(faultcode_str);
 	}
 
--- a/libpurple/protocols/oscar/oscarcommon.h	Sat Sep 12 02:25:38 2009 +0000
+++ b/libpurple/protocols/oscar/oscarcommon.h	Tue Sep 22 02:07:26 2009 +0000
@@ -44,8 +44,8 @@
 #define OSCAR_DEFAULT_WEB_AWARE FALSE
 #define OSCAR_DEFAULT_ALWAYS_USE_RV_PROXY FALSE
 #define OSCAR_DEFAULT_ALLOW_MULTIPLE_LOGINS TRUE
-#define OSCAR_DEFAULT_USE_SSL FALSE
-#define OSCAR_DEFAULT_USE_CLIENTLOGIN FALSE
+#define OSCAR_DEFAULT_USE_SSL TRUE
+#define OSCAR_DEFAULT_USE_CLIENTLOGIN TRUE
 
 #ifdef _WIN32
 const char *oscar_get_locale_charset(void);
--- a/libpurple/protocols/yahoo/libymsg.c	Sat Sep 12 02:25:38 2009 +0000
+++ b/libpurple/protocols/yahoo/libymsg.c	Tue Sep 22 02:07:26 2009 +0000
@@ -2025,11 +2025,11 @@
 				break;
 			}
 		case 2:
-			purple_debug_info("yahoo", "Server reported that %s is already in the ignore list.",
+			purple_debug_info("yahoo", "Server reported that %s is already in the ignore list.\n",
 							  who);
 			break;
 		case 3:
-			purple_debug_info("yahoo", "Server reported that %s is not in the ignore list; could not delete",
+			purple_debug_info("yahoo", "Server reported that %s is not in the ignore list; could not delete\n",
 							  who);
 		case 0:
 		default:
@@ -4149,14 +4149,13 @@
 	struct yahoo_sms_carrier_cb_data *sms_cb_data = user_data;
 	PurpleConnection *gc = sms_cb_data->gc;
 	YahooData *yd = gc->proto_data;
-	char *mobile_no = NULL;
 	char *status = NULL;
 	char *carrier = NULL;
 	PurpleAccount *account = purple_connection_get_account(gc);
 	PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, sms_cb_data->who, account);
 
 	if (error_message != NULL) {
-		purple_conversation_write(conv, NULL, "Cant send SMS, Unable to obtain mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL));
+		purple_conversation_write(conv, NULL, _("Can't send SMS. Unable to obtain mobile carrier."), PURPLE_MESSAGE_SYSTEM, time(NULL));
 
 		g_free(sms_cb_data->who);
 		g_free(sms_cb_data->what);
@@ -4166,7 +4165,7 @@
 	else if (len > 0 && webdata && *webdata) {
 		xmlnode *validate_data_root = xmlnode_from_str(webdata, -1);
 		xmlnode *validate_data_child = xmlnode_get_child(validate_data_root, "mobile_no");
-		mobile_no = (char *)xmlnode_get_attrib(validate_data_child, "msisdn");
+		const char *mobile_no = xmlnode_get_attrib(validate_data_child, "msisdn");
 
 		validate_data_root = xmlnode_copy(validate_data_child);
 		validate_data_child = xmlnode_get_child(validate_data_root, "status");
@@ -4183,7 +4182,7 @@
 		}
 		else	{
 			g_hash_table_insert(yd->sms_carrier, g_strdup_printf("+%s", mobile_no), g_strdup("Unknown"));
-			purple_conversation_write(conv, NULL, "Cant send SMS, Unknown mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL));
+			purple_conversation_write(conv, NULL, _("Can't send SMS. Unknown mobile carrier."), PURPLE_MESSAGE_SYSTEM, time(NULL));
 		}
 
 		xmlnode_free(validate_data_child);
@@ -4191,7 +4190,6 @@
 		g_free(sms_cb_data->who);
 		g_free(sms_cb_data->what);
 		g_free(sms_cb_data);
-		g_free(mobile_no);
 		g_free(status);
 		g_free(carrier);
 	}
@@ -4248,7 +4246,7 @@
 	if (!url_data) {
 		PurpleAccount *account = purple_connection_get_account(gc);
 		PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, sms_cb_data->who, account);
-		purple_conversation_write(conv, NULL, "Cant send SMS, Unable to obtain mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL));
+		purple_conversation_write(conv, NULL, _("Can't send SMS. Unable to obtain mobile carrier."), PURPLE_MESSAGE_SYSTEM, time(NULL));
 		g_free(sms_cb_data->who);
 		g_free(sms_cb_data->what);
 		g_free(sms_cb_data);
@@ -4303,7 +4301,7 @@
 			sms_cb_data->who = g_strdup(who);
 			sms_cb_data->what = g_strdup(what);
 
-			purple_conversation_write(conv, NULL, "Getting mobile carrier to send the sms", PURPLE_MESSAGE_SYSTEM, time(NULL));
+			purple_conversation_write(conv, NULL, _("Getting mobile carrier to send the SMS."), PURPLE_MESSAGE_SYSTEM, time(NULL));
 
 			yahoo_get_sms_carrier(gc, sms_cb_data);
 
@@ -4312,7 +4310,7 @@
 			return ret;
 		}
 		else if( strcmp(carrier,"Unknown") == 0 ) {
-			purple_conversation_write(conv, NULL, "Cant send SMS, Unknown mobile carrier", PURPLE_MESSAGE_SYSTEM, time(NULL));
+			purple_conversation_write(conv, NULL, _("Can't send SMS. Unknown mobile carrier."), PURPLE_MESSAGE_SYSTEM, time(NULL));
 
 			g_free(msg);
 			g_free(msg2);
--- a/libpurple/tests/test_jabber_jutil.c	Sat Sep 12 02:25:38 2009 +0000
+++ b/libpurple/tests/test_jabber_jutil.c	Tue Sep 22 02:07:26 2009 +0000
@@ -142,13 +142,20 @@
 
 	/* Cyrillic capital EF (U+0424) maps to lowercase EF (U+0444) */
 	assert_jid_parts("ф", "darkrain42.org", "Ф@darkrain42.org");
+
+#ifdef USE_IDN
 	/*
 	 * These character (U+A664 and U+A665) are not mapped to anything in
 	 * RFC3454 B.2. This first test *fails* when not using IDN because glib's
-	 * case-folding/utf8_strdown improperly lowercases the character.
+	 * case-folding/utf8_strdown improperly (for XMPP) lowercases the character.
+	 *
+	 * This is known, but not (very?) likely to actually cause a problem, so
+	 * this test is commented out when using glib's functions.
 	 */
 	assert_jid_parts("Ꙥ", "darkrain42.org", "Ꙥ@darkrain42.org");
 	assert_jid_parts("ꙥ", "darkrain42.org", "ꙥ@darkrain42.org");
+#endif
+
 	/* U+04E9 to U+04E9 */
 	assert_jid_parts("paul", "өarkrain42.org", "paul@Өarkrain42.org");
 }
--- a/pidgin/gtkconv.c	Sat Sep 12 02:25:38 2009 +0000
+++ b/pidgin/gtkconv.c	Tue Sep 22 02:07:26 2009 +0000
@@ -327,23 +327,43 @@
                  const char *cmd, char **args, char **error, void *data)
 {
 	char *tmp, *markup;
-	PurpleCmdStatus status;
 
 	if (!g_ascii_strcasecmp(args[0], "version")) {
-		tmp = g_strdup_printf("me is using Pidgin v%s with libpurple v%s.",
+		tmp = g_strdup_printf("Using Pidgin v%s with libpurple v%s.",
 				DISPLAY_VERSION, purple_core_get_version());
-		markup = g_markup_escape_text(tmp, -1);
-
-		status = purple_cmd_do_command(conv, tmp, markup, error);
-
-		g_free(tmp);
-		g_free(markup);
-		return status;
+	} else if (!g_ascii_strcasecmp(args[0], "plugins")) {
+		/* Show all the loaded plugins, including the protocol plugins and plugin loaders.
+		 * This is intentional, since third party prpls are often sources of bugs, and some
+		 * plugin loaders (e.g. mono) can also be buggy.
+		 */
+		GString *str = g_string_new("Loaded Plugins: ");
+		const GList *plugins = purple_plugins_get_loaded();
+		if (plugins) {
+			for (; plugins; plugins = plugins->next) {
+				str = g_string_append(str, purple_plugin_get_name(plugins->data));
+				if (plugins->next)
+					str = g_string_append(str, ", ");
+			}
+		} else {
+			str = g_string_append(str, "(none)");
+		}
+
+		tmp = g_string_free(str, FALSE);
 	} else {
-		purple_conversation_write(conv, NULL, _("Supported debug options are:  version"),
+		purple_conversation_write(conv, NULL, _("Supported debug options are: plugins version"),
 		                        PURPLE_MESSAGE_NO_LOG|PURPLE_MESSAGE_ERROR, time(NULL));
-		return PURPLE_CMD_STATUS_OK;
-	}
+		return PURPLE_CMD_RET_OK;
+	}
+
+	markup = g_markup_escape_text(tmp, -1);
+	if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM)
+		purple_conv_im_send(PURPLE_CONV_IM(conv), markup);
+	else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT)
+		purple_conv_chat_send(PURPLE_CONV_CHAT(conv), markup);
+
+	g_free(tmp);
+	g_free(markup);
+	return PURPLE_CMD_RET_OK;
 }
 
 static void clear_conversation_scrollback(PurpleConversation *conv)
@@ -363,7 +383,7 @@
                  const char *cmd, char **args, char **error, void *data)
 {
 	clear_conversation_scrollback(conv);
-	return PURPLE_CMD_STATUS_OK;
+	return PURPLE_CMD_RET_OK;
 }
 
 static PurpleCmdRet
@@ -371,7 +391,7 @@
                  const char *cmd, char **args, char **error, void *data)
 {
 	purple_conversation_foreach(clear_conversation_scrollback);
-	return PURPLE_CMD_STATUS_OK;
+	return PURPLE_CMD_RET_OK;
 }
 
 static PurpleCmdRet
@@ -410,7 +430,7 @@
 	purple_conversation_write(conv, NULL, s->str, PURPLE_MESSAGE_NO_LOG, time(NULL));
 	g_string_free(s, TRUE);
 
-	return PURPLE_CMD_STATUS_OK;
+	return PURPLE_CMD_RET_OK;
 }
 
 static void
@@ -3867,7 +3887,7 @@
 	gtk_size_group_add_widget(sg, image);
 
 	/* Make our menu item */
-	text = g_strdup_printf("%s (%s)", name, purple_account_get_name_for_display(account));
+	text = g_strdup_printf("%s (%s)", name, purple_account_get_username(account));
 	menuitem = gtk_radio_menu_item_new_with_label(*group, text);
 	g_free(text);
 	*group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menuitem));
@@ -7277,7 +7297,8 @@
 			pidgin_setup_gtkspell(GTK_TEXT_VIEW(gtkconv->entry));
 		else {
 			spell = gtkspell_get_from_text_view(GTK_TEXT_VIEW(gtkconv->entry));
-			gtkspell_detach(spell);
+			if (spell)
+				gtkspell_detach(spell);
 		}
 	}
 #endif
--- a/pidgin/gtkprefs.c	Sat Sep 12 02:25:38 2009 +0000
+++ b/pidgin/gtkprefs.c	Tue Sep 22 02:07:26 2009 +0000
@@ -459,13 +459,24 @@
 	return row_ref;
 }
 
+static gchar *
+get_theme_markup(const char *name, gboolean custom, const char *author,
+				 const char *description)
+{
+
+	return g_strdup_printf("<b>%s</b>%s%s%s%s\n<span foreground='dim grey'>%s</span>",
+						   name, custom ? " " : "", custom ? _("(Custom)") : "",
+						   author != NULL ? " - " : "", author != NULL ? author : "",
+						   description != NULL ? description : "");
+}
+
 /* Rebuild the markup for the sound theme selection for "(Custom)" themes */
 static void
 pref_sound_generate_markup(void)
 {
 	gboolean print_custom, customized;
-	const gchar *name, *author, *description, *current_theme;
-	gchar *markup;
+	const gchar *author, *description, *current_theme;
+	gchar *name, *markup;
 	PurpleSoundTheme *theme;
 	GtkTreeIter iter;
 
@@ -476,23 +487,24 @@
 		do {
 			gtk_tree_model_get(GTK_TREE_MODEL(prefs_sound_themes), &iter, 2, &name, -1);
 
-			print_custom = customized && g_str_equal(current_theme, name);
-
-			if (!name || *name == '\0')
-				markup = g_strdup_printf("<b>(Default)</b>%s%s - None\n<span foreground='dim grey'>The default Pidgin sound theme</span>",
-							 print_custom ? " " : "", print_custom ? "(Custom)" : "");
-			else {
+			print_custom = customized && name && g_str_equal(current_theme, name);
+
+			if (!name || *name == '\0') {
+				g_free(name);
+				name = g_strdup(_("(Default)"));
+				author = _("None");
+				description = _("The default Pidgin sound theme");
+			} else {
 				theme = PURPLE_SOUND_THEME(purple_theme_manager_find_theme(name, "sound"));
 				author = purple_theme_get_author(PURPLE_THEME(theme));
 				description = purple_theme_get_description(PURPLE_THEME(theme));
-
-				markup = g_strdup_printf("<b>%s</b>%s%s%s%s\n<span foreground='dim grey'>%s</span>",
-							 name, print_custom ? " " : "", print_custom ? "(Custom)" : "",
-							 author != NULL ? " - " : "", author != NULL ? author : "", description != NULL ? description : "");
 			}
 
+			markup = get_theme_markup(name, print_custom, author, description);
+
 			gtk_list_store_set(prefs_sound_themes, &iter, 1, markup, -1);
 
+			g_free(name);
 			g_free(markup);
 
 		} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(prefs_sound_themes), &iter));
@@ -514,7 +526,8 @@
 		if (image_full != NULL){
 			pixbuf = gdk_pixbuf_new_from_file_at_scale(image_full, PREFS_OPTIMAL_ICON_SIZE, PREFS_OPTIMAL_ICON_SIZE, TRUE, NULL);
 			g_free(image_full);
-		} else pixbuf = NULL;
+		} else
+			pixbuf = NULL;
 
 		gtk_list_store_append(prefs_sound_themes, &iter);
 		gtk_list_store_set(prefs_sound_themes, &iter, 0, pixbuf, 2, purple_theme_get_name(theme), -1);
@@ -527,20 +540,21 @@
 
 		if (PIDGIN_IS_BLIST_THEME(theme))
 			store = prefs_blist_themes;
-		else store = prefs_status_icon_themes;
+		else
+			store = prefs_status_icon_themes;
 
 		image_full = purple_theme_get_image_full(theme);
 		if (image_full != NULL){
 			pixbuf = gdk_pixbuf_new_from_file_at_scale(image_full, PREFS_OPTIMAL_ICON_SIZE, PREFS_OPTIMAL_ICON_SIZE, TRUE, NULL);
 			g_free(image_full);
-		} else pixbuf = NULL;
+		} else
+			pixbuf = NULL;
 
 		name = purple_theme_get_name(theme);
 		author = purple_theme_get_author(theme);
 		description = purple_theme_get_description(theme);
 
-		markup = g_strdup_printf("<b>%s</b>%s%s\n<span foreground='dim grey'>%s</span>", name, author != NULL ? " - " : "",
-					 author != NULL ? author : "", description != NULL ? description : "");
+		markup = get_theme_markup(name, FALSE, author, description);
 
 		gtk_list_store_append(store, &iter);
 		gtk_list_store_set(store, &iter, 0, pixbuf, 1, markup, 2, name, -1);
@@ -579,16 +593,16 @@
 prefs_themes_refresh(void)
 {
 	GdkPixbuf *pixbuf = NULL;
-	gchar *filename;
+	gchar *tmp;
 	GtkTreeIter iter;
 
 	prefs_sound_themes_loading = TRUE;
 	/* refresh the list of themes in the manager */
 	purple_theme_manager_refresh();
 
-	filename = g_build_filename(DATADIR, "icons", "hicolor", "32x32", "apps", "pidgin.png", NULL);
-	pixbuf = gdk_pixbuf_new_from_file_at_scale(filename, PREFS_OPTIMAL_ICON_SIZE, PREFS_OPTIMAL_ICON_SIZE, TRUE, NULL);
-	g_free(filename);
+	tmp = g_build_filename(DATADIR, "icons", "hicolor", "32x32", "apps", "pidgin.png", NULL);
+	pixbuf = gdk_pixbuf_new_from_file_at_scale(tmp, PREFS_OPTIMAL_ICON_SIZE, PREFS_OPTIMAL_ICON_SIZE, TRUE, NULL);
+	g_free(tmp);
 
 	/* sound themes */
 	gtk_list_store_clear(prefs_sound_themes);
@@ -598,16 +612,18 @@
 	/* blist themes */
 	gtk_list_store_clear(prefs_blist_themes);
 	gtk_list_store_append(prefs_blist_themes, &iter);
-	gtk_list_store_set(prefs_blist_themes, &iter, 0, pixbuf, 1,
-	                   "<b>(Default)</b> - None\n<span color='dim grey'>"
-	                   "The default Pidgin buddy list theme</span>", 2, "", -1);
+	tmp = get_theme_markup(_("(Default)"), FALSE, _("None"),
+		_("The default Pidgin buddy list theme"));
+	gtk_list_store_set(prefs_blist_themes, &iter, 0, pixbuf, 1, tmp, 2, "", -1);
+	g_free(tmp);
 
 	/* status icon themes */
 	gtk_list_store_clear(prefs_status_icon_themes);
 	gtk_list_store_append(prefs_status_icon_themes, &iter);
-	gtk_list_store_set(prefs_status_icon_themes, &iter, 0, pixbuf, 1,
-	                   "<b>(Default)</b> - None\n<span color='dim grey'>"
-	                   "The default Pidgin status icon theme</span>", 2, "", -1);
+	tmp = get_theme_markup(_("(Default)"), FALSE, _("None"),
+		_("The default Pidgin status icon theme"));
+	gtk_list_store_set(prefs_status_icon_themes, &iter, 0, pixbuf, 1, tmp, 2, "", -1);
+	g_free(tmp);
 	g_object_unref(G_OBJECT(pixbuf));
 
 	purple_theme_manager_for_each_theme(prefs_themes_sort);
@@ -676,6 +692,17 @@
 	return TRUE;
 }
 
+static void
+free_theme_info(struct theme_info *info)
+{
+	if (info != NULL) {
+		g_free(info->type);
+		g_free(info->extension);
+		g_free(info->original_name);
+		g_free(info);
+	}
+}
+
 /* installs a theme, info is freed by function */
 static void
 theme_install_theme(char *path, struct theme_info *info)
@@ -683,7 +710,8 @@
 #ifndef _WIN32
 	gchar *command;
 #endif
-	gchar *destdir, *tail, *type, *original_name;
+	gchar *destdir;
+	const char *tail;
 	GtkTreeRowReference *theme_rowref;
 	gboolean is_smiley_theme, is_archive;
 	PurpleTheme *theme = NULL;
@@ -691,30 +719,23 @@
 	if (info == NULL)
 		return;
 
-	original_name = info->original_name;
-	type = info->type;
-
 	/* check the extension */
-	tail = info->extension ? info->extension : g_strdup(strrchr(path, '.'));
+	tail = info->extension ? info->extension : strrchr(path, '.');
 
 	if (!tail) {
-		g_free(type);
-		g_free(original_name);
-		g_free(info);
+		free_theme_info(info);
 		return;
-	} else
-		g_free(info);
+	}
 
 	is_archive = !g_ascii_strcasecmp(tail, ".gz") || !g_ascii_strcasecmp(tail, ".tgz");
 
-	g_free(tail);
-
 	/* Just to be safe */
 	g_strchomp(path);
 
-	if ((is_smiley_theme = g_str_equal(type, "smiley")))
+	if ((is_smiley_theme = g_str_equal(info->type, "smiley")))
 		destdir = g_build_filename(purple_user_dir(), "smileys", NULL);
-	else destdir = g_build_filename(purple_user_dir(), "themes", "temp", NULL);
+	else
+		destdir = g_build_filename(purple_user_dir(), "themes", "temp", NULL);
 
 	/* We'll check this just to make sure. This also lets us do something different on
 	 * other platforms, if need be */
@@ -735,15 +756,14 @@
 			purple_notify_error(NULL, NULL, _("Theme failed to unpack."), NULL);
 			g_free(command);
 			g_free(destdir);
-			g_free(type);
-			g_free(original_name);
+			free_theme_info(info);
 			return;
 		}
 #else
-		if(!winpidgin_gz_untar(path, destdir)) {
+		if (!winpidgin_gz_untar(path, destdir)) {
+			purple_notify_error(NULL, NULL, _("Theme failed to unpack."), NULL);
 			g_free(destdir);
-			g_free(type);
-			g_free(original_name);
+			free_theme_info(info);
 			return;
 		}
 #endif
@@ -763,13 +783,13 @@
 		}
 
 	} else if (is_archive) {
-		theme = prefs_theme_find_theme(destdir, type);
+		theme = prefs_theme_find_theme(destdir, info->type);
 
 		if (PURPLE_IS_THEME(theme)) {
 			/* create the location for the theme */
 			gchar *theme_dest = g_build_filename(purple_user_dir(), "themes",
 						 purple_theme_get_name(theme),
-						 "purple", type, NULL);
+						 "purple", info->type, NULL);
 
 			if (!g_file_test(theme_dest, G_FILE_TEST_IS_DIR))
 				purple_build_dir(theme_dest, S_IRUSR | S_IWUSR | S_IXUSR);
@@ -777,7 +797,7 @@
 			g_free(theme_dest);
 			theme_dest = g_build_filename(purple_user_dir(), "themes",
 						 purple_theme_get_name(theme),
-						 "purple", type, NULL);
+						 "purple", info->type, NULL);
 
 			/* move the entire directory to new location */
 			g_rename(purple_theme_get_dir(theme), theme_dest);
@@ -799,9 +819,9 @@
 
 		temp_path = g_build_filename(purple_user_dir(), "themes", "temp", "sub_folder", NULL);
 
-		if (original_name != NULL) {
+		if (info->original_name != NULL) {
 			/* name was changed from the original (probably a dnd) change it back before loading */
-			temp_file = g_build_filename(temp_path, original_name, NULL);
+			temp_file = g_build_filename(temp_path, info->original_name, NULL);
 
 		} else {
 			gchar *source_name = g_path_get_basename(path);
@@ -814,12 +834,12 @@
 
 		if (purple_theme_file_copy(path, temp_file)) {
 			/* find the theme, could be in subfolder */
-			theme = prefs_theme_find_theme(temp_path, type);
+			theme = prefs_theme_find_theme(temp_path, info->type);
 
 			if (PURPLE_IS_THEME(theme)) {
 				gchar *theme_dest = g_build_filename(purple_user_dir(), "themes",
 							 purple_theme_get_name(theme),
-							 "purple", type, NULL);
+							 "purple", info->type, NULL);
 
 				if(!g_file_test(theme_dest, G_FILE_TEST_IS_DIR))
 					purple_build_dir(theme_dest, S_IRUSR | S_IWUSR | S_IXUSR);
@@ -842,9 +862,8 @@
 		g_free(temp_path);
 	}
 
-	g_free(type);
-	g_free(original_name);
 	g_free(destdir);
+	free_theme_info(info);
 }
 
 static void
@@ -855,8 +874,10 @@
 	gchar *path;
 	size_t wc;
 
-	if ((error_message != NULL) || (len == 0))
+	if ((error_message != NULL) || (len == 0)) {
+		free_theme_info(user_data);
 		return;
+	}
 
 	f = purple_mkstemp(&path, TRUE);
 	wc = fwrite(themedata, len, 1, f);
@@ -865,6 +886,7 @@
 		fclose(f);
 		g_unlink(path);
 		g_free(path);
+		free_theme_info(user_data);
 		return;
 	}
 	fclose(f);
@@ -900,6 +922,7 @@
 				purple_debug(PURPLE_DEBUG_ERROR, "theme dnd", "%s\n",
 						   (converr ? converr->message :
 							"g_filename_from_uri error"));
+				free_theme_info(info);
 				return;
 			}
 			theme_install_theme(tmp, info);
@@ -920,7 +943,8 @@
 
 			purple_util_fetch_url(tmp, TRUE, NULL, FALSE, theme_got_url, info);
 			g_free(tmp);
-		}
+		} else
+			free_theme_info(info);
 
 		gtk_drag_finish(dc, TRUE, FALSE, t);
 	}
@@ -930,7 +954,7 @@
 
 /* builds a theme combo box from a list store with colums: icon preview, markup, theme name */
 static GtkWidget *
-prefs_build_theme_combo_box(GtkListStore *store, const gchar *current_theme, gchar *type)
+prefs_build_theme_combo_box(GtkListStore *store, const char *current_theme, const char *type)
 {
 	GtkCellRenderer *cell_rend;
 	GtkWidget *combo_box;
@@ -959,7 +983,7 @@
 	gtk_drag_dest_set(combo_box, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, te,
 					sizeof(te) / sizeof(GtkTargetEntry) , GDK_ACTION_COPY | GDK_ACTION_MOVE);
 
-	g_signal_connect(G_OBJECT(combo_box), "drag_data_received", G_CALLBACK(theme_dnd_recv), type);
+	g_signal_connect(G_OBJECT(combo_box), "drag_data_received", G_CALLBACK(theme_dnd_recv), (gpointer) type);
 
 	return combo_box;
 }
@@ -980,7 +1004,7 @@
 		purple_prefs_set_string(PIDGIN_PREFS_ROOT "/sound/theme", new_theme);
 
 		/* New theme removes all customization */
-		for(i=0; i <  PURPLE_NUM_SOUNDS; i++){
+		for(i = 0; i < PURPLE_NUM_SOUNDS; i++){
 			pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/file/%s",
 						pidgin_sound_get_event_option(i));
 			purple_prefs_set_path(pref, "");
@@ -1037,8 +1061,6 @@
 {
 	struct theme_info *info = g_new0(struct theme_info, 1);
 	info->type = g_strdup("smiley");
-	info->extension = NULL;
-	info->original_name = NULL;
 
 	theme_install_theme(theme_file_name, info);
 }
--- a/pidgin/gtksound.c	Sat Sep 12 02:25:38 2009 +0000
+++ b/pidgin/gtksound.c	Tue Sep 22 02:07:26 2009 +0000
@@ -212,6 +212,8 @@
 		return;
 
 	if (flags & PURPLE_MESSAGE_NICK || purple_utf8_has_word(message, chat->nick))
+		/* This isn't quite right; if you have the PURPLE_SOUND_CHAT_NICK event disabled
+		 * and the PURPLE_SOUND_CHAT_SAY event enabled, you won't get a sound at all */
 		play_conv_event(conv, PURPLE_SOUND_CHAT_NICK);
 	else
 		play_conv_event(conv, event);
@@ -591,6 +593,7 @@
 				purple_debug_error("sound", "The file: (%s) %s\n from theme: %s, was not found or wasn't readable\n",
 							sounds[event].pref, filename, theme_name);
 				g_free(filename);
+				filename = NULL;
 			}
 		}
 
@@ -614,19 +617,16 @@
 pidgin_sound_is_customized(void)
 {
 	gint i;
-	gchar *path, *file;
+	gchar *path;
+	const char *file;
 
 	for (i = 0; i < PURPLE_NUM_SOUNDS; i++) {
 		path = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/file/%s", sounds[i].pref);
-		file = g_strdup(purple_prefs_get_path(path));
+		file = purple_prefs_get_path(path);
 		g_free(path);
 
-		if (file && file[0] != '\0'){
-			g_free(file);
+		if (file && file[0] != '\0')
 			return TRUE;
-		}
-
-		g_free(file);
 	}
 
 	return FALSE;
--- a/pidgin/win32/nsis/pidgin-installer.nsi	Sat Sep 12 02:25:38 2009 +0000
+++ b/pidgin/win32/nsis/pidgin-installer.nsi	Tue Sep 22 02:07:26 2009 +0000
@@ -1345,13 +1345,14 @@
   StrCpy $LANGUAGE_SET "0"
   ClearErrors
   ${GetOptions} "$R3" "/L=" $R1
-  IfErrors +3
+  IfErrors +4
   StrCpy $LANGUAGE $R1
   StrCpy $LANGUAGE_SET "1"
   Goto skip_lang
 
   ; Select Language
     ; Display Language selection dialog
+    !define MUI_LANGDLL_ALWAYSSHOW
     !insertmacro MUI_LANGDLL_DISPLAY
     skip_lang:
 
--- a/po/de.po	Sat Sep 12 02:25:38 2009 +0000
+++ b/po/de.po	Tue Sep 22 02:07:26 2009 +0000
@@ -11,9 +11,9 @@
 msgstr ""
 "Project-Id-Version: de\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-09-11 17:57+0200\n"
-"PO-Revision-Date: 2009-09-11 17:57+0200\n"
-"Last-Translator: Jochen Kemnade <jochenkemnade@web.de>\n"
+"POT-Creation-Date: 2009-09-16 11:43+0200\n"
+"PO-Revision-Date: 2009-09-16 11:37+0200\n"
+"Last-Translator: Bjoern Voigt <bjoern@cs.tu-berlin.de>\n"
 "Language-Team: Deutsch <de@li.org>\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
@@ -267,7 +267,7 @@
 msgstr "Empfange..."
 
 msgid "Get Info"
-msgstr "Benutzer-Info"
+msgstr "Info abrufen"
 
 msgid "Add Buddy Pounce"
 msgstr "Buddy-Alarm hinzufügen"
@@ -644,8 +644,8 @@
 msgstr[0] "Liste von %d Benutzer:\n"
 msgstr[1] "Liste von %d Benutzern:\n"
 
-msgid "Supported debug options are:  version"
-msgstr "Unterstützte Debug-Optionen sind:  version"
+msgid "Supported debug options are: plugins version"
+msgstr "Unterstützte Debug-Optionen sind: plugins version"
 
 msgid "No such command (in this context)."
 msgstr "Kein solches Kommando (in diesem Kontext)."
@@ -2201,13 +2201,13 @@
 msgid "A non-recoverable Farsight2 error has occurred."
 msgstr "Ein nicht behebbarer Farsight2-Fehler ist aufgetreten."
 
-msgid "Conference error."
+msgid "Conference error"
 msgstr "Konferenz-Fehler"
 
-msgid "Error with your microphone."
+msgid "Error with your microphone"
 msgstr "Fehler mit Ihrem Mikrofon"
 
-msgid "Error with your webcam."
+msgid "Error with your webcam"
 msgstr "Fehler mit Ihrer Webcam"
 
 #, c-format
@@ -7104,7 +7104,7 @@
 msgstr "V_erbinden"
 
 msgid "You closed the connection."
-msgstr "Sie haben die Verbindung beendet"
+msgstr "Sie haben die Verbindung beendet."
 
 msgid "Get AIM Info"
 msgstr "AIM-Info"
@@ -11093,7 +11093,7 @@
 msgstr "/Unterhaltung/_Buddy-Alarm hinzufügen..."
 
 msgid "/Conversation/_Get Info"
-msgstr "/Unterhaltung/Ben_utzer-Info abrufen"
+msgstr "/Unterhaltung/_Info abrufen"
 
 msgid "/Conversation/In_vite..."
 msgstr "/Unterhaltung/_Einladen..."
@@ -13253,7 +13253,7 @@
 msgstr "_Reiter schließen"
 
 msgid "_Get Info"
-msgstr "_Benutzer-Info"
+msgstr "_Info abrufen"
 
 msgid "_Invite"
 msgstr "_Einladen"
@@ -14317,12 +14317,13 @@
 #. *< name
 #. *< version
 msgid "Configure your microphone and webcam."
-msgstr "Mikrofon und Webcam konfigurieren"
+msgstr "Mikrofon und Webcam konfigurieren."
 
 #. *< summary
 msgid "Configure microphone and webcam settings for voice/video calls."
 msgstr ""
-"Die Mikrofon- und Webcam-Einstellungen für Audio- und Video-Anrufe bearbeiten"
+"Die Mikrofon- und Webcam-Einstellungen für Audio- und Video-Anrufe "
+"bearbeiten."
 
 msgid "Opacity:"
 msgstr "Durchlässigkeit:"