pidgin/pidgin

77664079d0f0
Merge with a fair number of conflicts. Nothing too crazy.

I didn't merge a lot of changes from 07e827917960
libpurple/protocols/gg/gg.c I think maybe that code has either been
removed or changed significantly in main.
--- a/COPYRIGHT Mon Jan 20 07:39:26 2014 +0530
+++ b/COPYRIGHT Mon Jan 20 00:02:17 2014 -0800
@@ -350,6 +350,7 @@
Robert Mibus
David Michael
Lars T. Mikkelsen
+Mantas Mikulėnas
Benjamin Miller
Kevin Miller
Paul Miller
--- a/ChangeLog Mon Jan 20 07:39:26 2014 +0530
+++ b/ChangeLog Mon Jan 20 00:02:17 2014 -0800
@@ -67,30 +67,80 @@
Python 3. (Ashish Gupta) (#15624)
libpurple:
+ * Fix potential crash if libpurple gets an error attempting to read a
+ reply from a STUN server. (Discovered by Coverity static analysis)
+ (CVE-2013-6484)
+ * Fix potential crash parsing a malformed HTTP response. (Discovered by
+ Jacob Appelbaum of the Tor Project) (CVE-2013-6479)
+ * Fix buffer overflow when parsing a malformed HTTP response with
+ chunked Transfer-Encoding. (Discovered by Matt Jones, Volvent)
+ (CVE-2013-6485)
+ * Better handling of HTTP proxy responses with negative Content-Lengths.
+ (Discovered by Matt Jones, Volvent)
* Fix handling of SSL certificates without subjects when using libnss.
* Fix handling of SSL certificates with timestamps in the distant future
when using libnss. (#15586)
+ * Impose maximum download size for all HTTP fetches.
Pidgin:
+ * Fix crash displaying tooltip of long URLs. (CVE-2013-6478)
* Better handling of URLs longer than 1000 letters.
* Fix handling of multibyte UTF-8 characters in smiley themes. (#15756)
Windows-Specific Changes:
+ * When clicking file:// links, show the file in Explorer rather than
+ attempting to run the file. This reduces the chances of a user
+ clicking on a link and mistakenly running a malicious file.
+ (Originally discovered by James Burton, Insomnia Security. Rediscovered
+ by Yves Younan of Sourcefire VRT.) (CVE-2013-6486)
* Fix Tcl scripts. (#15520)
* Fix crash-on-startup when ASLR is always on. (#15521)
* Updates to dependencies:
- * NSS 3.15.3 and NSPR 4.10.2
+ * NSS 3.15.4 and NSPR 4.10.2
+
+ AIM:
+ * Fix untrusted certificate error.
+
+ AIM and ICQ:
+ * Fix a possible crash when receiving a malformed message in a Direct IM
+ session.
Gadu-Gadu:
+ * Fix buffer overflow with remote code execution potential. Only
+ triggerable by a Gadu-Gadu server or a man-in-the-middle.
+ (Discovered by Yves Younan and Ryan Pentney of Sourcefire VRT)
+ (CVE-2013-6487)
* Disabled buddy list import/export from/to server (it didn't work
anymore). Buddy list synchronization will be implemented in 3.0.0.
+ * Disabled new account registration and password change options, as it
+ didn't work either. Account registration also caused a crash. Both
+ functions are available using official Gadu-Gadu website.
IRC:
+ * Fix bug where a malicious server or man-in-the-middle could trigger
+ a crash by not sending enough arguments with various messages.
+ (Discovered by Daniel Atallah) (CVE-2014-0020)
* Fix bug where initial IRC status would not be set correctly.
* Fix bug where IRC wasn't available when libpurple was compiled with
Cyrus SASL support. (#15517)
+ MSN:
+ * Fix NULL pointer dereference parsing headers in MSN.
+ (Discovered by Fabian Yamaguchi and Christian Wressnegger of the
+ University of Goettingen) (CVE-2013-6482)
+ * Fix NULL pointer dereference parsing OIM data in MSN.
+ (Discovered by Fabian Yamaguchi and Christian Wressnegger of the
+ University of Goettingen) (CVE-2013-6482)
+ * Fix NULL pointer dereference parsing SOAP data in MSN.
+ (Discovered by Fabian Yamaguchi and Christian Wressnegger of the
+ University of Goettingen) (CVE-2013-6482)
+ * Fix possible crash when sending very long messages. Not
+ remotely-triggerable. (Discovered by Matt Jones, Volvent)
+
MXit:
+ * Fix buffer overflow with remote code execution potential.
+ (Discovered by Yves Younan and Pawel Janic of Sourcefire VRT)
+ (CVE-2013-6487)
* Fix sporadic crashes that can happen after user is disconnected.
* Fix crash when attempting to add a contact via search results.
* Show error message if file transfer fails.
@@ -100,7 +150,17 @@
SILC:
* Correctly set whiteboard dimensions in whiteboard sessions.
+ SIMPLE:
+ * Fix buffer overflow with remote code execution potential.
+ (Discovered by Yves Younan of Sourcefire VRT) (CVE-2013-6487)
+
XMPP:
+ * Prevent spoofing of iq replies by verifying that the 'from' address
+ matches the 'to' address of the iq request. (Discovered by Fabian
+ Yamaguchi and Christian Wressnegger of the University of Goettingen)
+ (CVE-2013-6483)
+ * Fix crash on some systems when receiving fake delay timestamps with
+ extreme values. (Discovered by Jaime Breva Ribes) (CVE-2013-6477)
* Fix possible crash or other erratic behavior when selecting a very
small file for your own buddy icon.
* Fix crash if the user tries to initiate a voice/video session with a
@@ -108,6 +168,14 @@
* Fix login errors when the first two available auth mechanisms fail but
a subsequent mechanism would otherwise work when using Cyrus SASL.
(#15524)
+ * Fix dropping incoming stanzas on BOSH connections when we receive
+ multiple HTTP responses at once. (#15684)
+
+ Yahoo!:
+ * Fix possible crashes handling incoming strings that are not UTF-8.
+ (Discovered by Thijs Alkemade and Robert Vehse) (CVE-2012-6152)
+ * Fix a bug reading a peer to peer message where a remote user could
+ trigger a crash. (CVE-2013-6481)
Plugins:
* Fix crash in contact availability plugin.
--- a/libpurple/conversationtypes.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/conversationtypes.c Mon Jan 20 00:02:17 2014 -0800
@@ -809,6 +809,14 @@
if (purple_chat_conversation_is_ignored_user(PURPLE_CHAT_CONVERSATION(conv), who))
return;
+ if (mtime < 0) {
+ purple_debug_error("conversation",
+ "purple_conv_chat_write ignoring negative timestamp\n");
+ /* TODO: Would be more appropriate to use a value that indicates
+ that the timestamp is unknown, and surface that in the UI. */
+ mtime = time(NULL);
+ }
+
if (!(flags & PURPLE_MESSAGE_WHISPER)) {
const char *str;
--- a/libpurple/log.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/log.c Mon Jan 20 00:02:17 2014 -0800
@@ -779,7 +779,7 @@
{
gboolean show_date;
char *date;
- struct tm tm;
+ struct tm *tm;
show_date = (log->type == PURPLE_LOG_SYSTEM) || (time(NULL) > when + 20*60);
@@ -789,11 +789,11 @@
if (date != NULL)
return date;
- tm = *(localtime(&when));
+ tm = localtime(&when);
if (show_date)
- return g_strdup(purple_date_format_long(&tm));
+ return g_strdup(purple_date_format_long(tm));
else
- return g_strdup(purple_time_format(&tm));
+ return g_strdup(purple_time_format(tm));
}
/* NOTE: This can return msg (which you may or may not want to g_free())
--- a/libpurple/protocols/gg/lib/http.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/protocols/gg/lib/http.c Mon Jan 20 00:02:17 2014 -0800
@@ -39,6 +39,8 @@
#include <string.h>
#include <unistd.h>
+#define GG_HTTP_MAX_LENGTH 1000000000
+
/**
* Rozpoczyna połączenie HTTP.
*
@@ -356,6 +358,11 @@
h->body_size = left;
}
+ if (h->body_size > GG_HTTP_MAX_LENGTH) {
+ gg_debug(GG_DEBUG_MISC, "=> http, content-length too big\n");
+ h->body_size = GG_HTTP_MAX_LENGTH;
+ }
+
if (left > h->body_size) {
gg_debug(GG_DEBUG_MISC, "=> http, oversized reply (%d bytes needed, %d bytes left)\n", h->body_size, left);
h->body_size = left;
--- a/libpurple/protocols/irc/irc.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/protocols/irc/irc.c Mon Jan 20 00:02:17 2014 -0800
@@ -396,7 +396,7 @@
static gboolean do_login(PurpleConnection *gc) {
char *buf, *tmp = NULL;
char *server;
- const char *username, *realname;
+ const char *nickname, *identname, *realname;
struct irc_conn *irc = purple_connection_get_protocol_data(gc);
const char *pass = purple_connection_get_password(gc);
#ifdef HAVE_CYRUS_SASL
@@ -418,14 +418,14 @@
}
realname = purple_account_get_string(irc->account, "realname", "");
- username = purple_account_get_string(irc->account, "username", "");
+ identname = purple_account_get_string(irc->account, "username", "");
- if (username == NULL || *username == '\0') {
- username = g_get_user_name();
+ if (identname == NULL || *identname == '\0') {
+ identname = g_get_user_name();
}
- if (username != NULL && strchr(username, ' ') != NULL) {
- tmp = g_strdup(username);
+ if (identname != NULL && strchr(identname, ' ') != NULL) {
+ tmp = g_strdup(identname);
while ((buf = strchr(tmp, ' ')) != NULL) {
*buf = '_';
}
@@ -438,7 +438,7 @@
server = g_strdup(irc->server);
}
- buf = irc_format(irc, "vvvv:", "USER", tmp ? tmp : username, "*", server,
+ buf = irc_format(irc, "vvvv:", "USER", tmp ? tmp : identname, "*", server,
strlen(realname) ? realname : IRC_DEFAULT_ALIAS);
g_free(tmp);
g_free(server);
@@ -447,9 +447,9 @@
return FALSE;
}
g_free(buf);
- username = purple_connection_get_display_name(gc);
- buf = irc_format(irc, "vn", "NICK", username);
- irc->reqnick = g_strdup(username);
+ nickname = purple_connection_get_display_name(gc);
+ buf = irc_format(irc, "vn", "NICK", nickname);
+ irc->reqnick = g_strdup(nickname);
irc->nickused = FALSE;
if (irc_send(irc, buf) < 0) {
g_free(buf);
@@ -1068,7 +1068,7 @@
option = purple_account_option_bool_new(_("Auto-detect incoming UTF-8"), "autodetect_utf8", IRC_DEFAULT_AUTODETECT);
prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
- option = purple_account_option_string_new(_("Username"), "username", "");
+ option = purple_account_option_string_new(_("Ident name"), "username", "");
prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
option = purple_account_option_string_new(_("Real name"), "realname", "");
--- a/libpurple/protocols/irc/msgs.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/protocols/irc/msgs.c Mon Jan 20 00:02:17 2014 -0800
@@ -20,6 +20,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
+/*
+ * Note: If you change any of these functions to use additional args you
+ * MUST ensure the arg count is correct in parse.c. Otherwise it may be
+ * possible for a malicious server or man-in-the-middle to trigger a crash.
+ */
+
#include "internal.h"
#include "conversation.h"
@@ -201,9 +207,6 @@
gchar **features;
int i;
- if (!args || !args[0] || !args[1])
- return;
-
features = g_strsplit(args[1], " ", -1);
for (i = 0; features[i]; i++) {
char *val;
@@ -218,9 +221,6 @@
void irc_msg_luser(struct irc_conn *irc, const char *name, const char *from, char **args)
{
- if (!args || !args[0])
- return;
-
if (!strcmp(name, "251")) {
/* 251 is required, so we pluck our nick from here and
* finalize connection */
@@ -236,9 +236,6 @@
PurpleConnection *gc;
char *msg;
- if (!args || !args[1])
- return;
-
if (irc->whois.nick && !purple_utf8_strcasecmp(irc->whois.nick, args[1])) {
/* We're doing a whois, show this in the whois dialog */
irc_msg_whois(irc, name, from, args);
@@ -257,8 +254,7 @@
{
PurpleConnection *gc = purple_account_get_connection(irc->account);
- if (!args || !args[1] || !gc)
- return;
+ g_return_if_fail(gc);
purple_notify_error(gc, NULL, _("Bad mode"), args[1],
purple_request_cpar_from_connection(gc));
@@ -268,16 +264,12 @@
{
PurpleChatConversation *chat;
- if (!args || !args[0] || !args[1])
- return;
-
chat = purple_conversations_find_chat_with_account(args[1], irc->account);
if (!strcmp(name, "367")) {
char *msg = NULL;
/* Ban list entry */
- if (!args[2])
- return;
+ g_return_if_fail(args[2]);
if (args[3] && args[4]) {
/* This is an extended syntax, not in RFC 1459 */
int t1 = atoi(args[4]);
@@ -313,8 +305,7 @@
PurpleConnection *gc = purple_account_get_connection(irc->account);
char *buf;
- if (!args || !args[1] || !gc)
- return;
+ g_return_if_fail(gc);
buf = g_strdup_printf(_("You are banned from %s."), args[1]);
purple_notify_error(gc, _("Banned"), _("Banned"), buf,
@@ -327,9 +318,6 @@
PurpleChatConversation *chat;
char *buf, *nick;
- if (!args || !args[0] || !args[1] || !args[2])
- return;
-
chat = purple_conversations_find_chat_with_account(args[1], irc->account);
if (!chat)
return;
@@ -348,9 +336,6 @@
PurpleChatConversation *chat;
char *buf, *escaped;
- if (!args || !args[1] || !args[2])
- return;
-
chat = purple_conversations_find_chat_with_account(args[1], irc->account);
if (!chat) /* XXX punt on channels we are not in for now */
return;
@@ -482,13 +467,6 @@
PurpleChatUserFlags flags;
- if (!args || !args[0] || !args[1] || !args[2] || !args[3]
- || !args[4] || !args[5] || !args[6] || !args[7]) {
- purple_debug(PURPLE_DEBUG_ERROR, "irc",
- "Got a WHO response with not enough arguments\n");
- return;
- }
-
chat = purple_conversations_find_chat_with_account(args[1], irc->account);
if (!chat) {
purple_debug(PURPLE_DEBUG_ERROR, "irc","Got a WHO response for %s, which doesn't exist\n", args[1]);
@@ -551,9 +529,6 @@
PurpleRoomlistRoom *room;
char *topic;
- if (!args[0] || !args[1] || !args[2] || !args[3])
- return;
-
if (!purple_roomlist_get_in_progress(irc->roomlist)) {
purple_debug_warning("irc", "Buggy server didn't send RPL_LISTSTART.\n");
purple_roomlist_set_in_progress(irc->roomlist, TRUE);
@@ -575,13 +550,13 @@
PurpleChatConversation *chat;
if (!strcmp(name, "topic")) {
- if (!args[0] || !args[1])
- return;
+ g_return_if_fail(args[0]);
+ g_return_if_fail(args[1]);
chan = args[0];
topic = irc_mirc2txt (args[1]);
} else {
- if (!args[0] || !args[1] || !args[2])
- return;
+ g_return_if_fail(args[1]);
+ g_return_if_fail(args[2]);
chan = args[1];
topic = irc_mirc2txt (args[2]);
}
@@ -634,9 +609,6 @@
struct tm *tm;
time_t t;
char *msg, *timestamp, *datestamp;
-
- if (!args || !args[1] || !args[2] || !args[3])
- return;
chat = purple_conversations_find_chat_with_account(args[1], irc->account);
if (!chat) {
@@ -666,8 +638,7 @@
PurpleConnection *gc = purple_account_get_connection(irc->account);
char *buf;
- if (!args || !args[1] || !gc)
- return;
+ g_return_if_fail(gc);
buf = g_strdup_printf(_("Unknown message '%s'"), args[1]);
purple_notify_error(gc, _("Unknown message"), buf, _("The IRC server "
@@ -758,9 +729,6 @@
{
char *escaped;
- if (!args || !args[0])
- return;
-
if (!strcmp(name, "375")) {
if (irc->motd)
g_string_free(irc->motd, TRUE);
@@ -800,8 +768,8 @@
PurpleConnection *gc;
gc = purple_account_get_connection(irc->account);
- if (gc == NULL || args == NULL || args[2] == NULL)
- return;
+
+ g_return_if_fail(gc);
purple_notify_message(gc, PURPLE_NOTIFY_MSG_INFO, _("Time Response"),
_("The IRC server's local time is:"), args[2], NULL, NULL,
@@ -812,8 +780,7 @@
{
PurpleConnection *gc = purple_account_get_connection(irc->account);
- if (gc == NULL || args == NULL || args[1] == NULL)
- return;
+ g_return_if_fail(gc);
purple_notify_error(gc, NULL, _("No such channel"), args[1],
purple_request_cpar_from_connection(gc));
@@ -877,9 +844,6 @@
{
PurpleChatConversation *chat;
- if (!args || !args[1] || !args[2])
- return;
-
chat = purple_conversations_find_chat_with_account(args[1], irc->account);
if (!chat)
return;
@@ -893,8 +857,7 @@
GHashTable *components;
gchar *nick;
- if (!args || !args[1] || !gc)
- return;
+ g_return_if_fail(gc);
components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
nick = irc_mask_nick(from);
@@ -910,8 +873,7 @@
PurpleConnection *gc = purple_account_get_connection(irc->account);
char *buf;
- if (!args || !args[1] || !gc)
- return;
+ g_return_if_fail(gc);
buf = g_strdup_printf(_("Joining %s requires an invitation."), args[1]);
purple_notify_error(gc, _("Invitation only"), _("Invitation only"), buf,
@@ -925,9 +887,6 @@
struct irc_buddy *ib;
int i;
- if (!args || !args[1])
- return;
-
nicks = g_strsplit(args[1], " ", -1);
for (i = 0; nicks[i]; i++) {
if ((ib = g_hash_table_lookup(irc->buddies, (gconstpointer)nicks[i])) == NULL) {
@@ -967,14 +926,13 @@
PurpleChatConversation *chat;
PurpleChatUser *cb;
- char *nick = irc_mask_nick(from), *userhost, *buf;
+ char *nick, *userhost, *buf;
struct irc_buddy *ib;
static int id = 1;
- if (!gc) {
- g_free(nick);
- return;
- }
+ g_return_if_fail(gc);
+
+ nick = irc_mask_nick(from);
if (!purple_utf8_strcasecmp(nick, purple_connection_get_display_name(gc))) {
/* We are joining a channel for the first time */
@@ -1030,12 +988,11 @@
{
PurpleConnection *gc = purple_account_get_connection(irc->account);
PurpleChatConversation *chat = purple_conversations_find_chat_with_account(args[0], irc->account);
- char *nick = irc_mask_nick(from), *buf;
+ char *nick, *buf;
- if (!gc) {
- g_free(nick);
- return;
- }
+ g_return_if_fail(gc);
+
+ nick = irc_mask_nick(from);
if (!chat) {
purple_debug(PURPLE_DEBUG_ERROR, "irc", "Received a KICK for unknown channel %s\n", args[0]);
@@ -1181,9 +1138,6 @@
char *newnick, *buf, *end;
PurpleConnection *gc = purple_account_get_connection(irc->account);
- if (!args || !args[1])
- return;
-
if (gc && purple_connection_get_state(gc) == PURPLE_CONNECTION_CONNECTED) {
/* We only want to do the following dance if the connection
has not been successfully completed. If it has, just
@@ -1222,9 +1176,6 @@
void irc_msg_notice(struct irc_conn *irc, const char *name, const char *from, char **args)
{
- if (!args || !args[0] || !args[1])
- return;
-
irc_msg_handle_privmsg(irc, name, from, args[0], args[1], TRUE);
}
@@ -1232,8 +1183,7 @@
{
PurpleConnection *gc = purple_account_get_connection(irc->account);
- if (!args || !args[2] || !gc)
- return;
+ g_return_if_fail(gc);
purple_notify_error(gc, _("Cannot change nick"),
_("Could not change nick"), args[2],
@@ -1246,8 +1196,7 @@
PurpleChatConversation *chat;
char *nick, *msg, *channel;
- if (!args || !args[0] || !gc)
- return;
+ g_return_if_fail(gc);
/* Undernet likes to :-quote the channel name, for no good reason
* that I can see. This catches that. */
@@ -1280,8 +1229,6 @@
void irc_msg_ping(struct irc_conn *irc, const char *name, const char *from, char **args)
{
char *buf;
- if (!args || !args[0])
- return;
buf = irc_format(irc, "v:", "PONG", args[0]);
irc_send(irc, buf);
@@ -1295,9 +1242,6 @@
char **parts, *msg;
time_t oldstamp;
- if (!args || !args[1])
- return;
-
parts = g_strsplit(args[1], " ", 2);
if (!parts[0] || !parts[1]) {
@@ -1329,9 +1273,6 @@
void irc_msg_privmsg(struct irc_conn *irc, const char *name, const char *from, char **args)
{
- if (!args || !args[0] || !args[1])
- return;
-
irc_msg_handle_privmsg(irc, name, from, args[0], args[1], FALSE);
}
@@ -1384,8 +1325,7 @@
PurpleConnection *gc = purple_account_get_connection(irc->account);
char *msg;
- if (!args || !args[1] || !args[2] || !gc)
- return;
+ g_return_if_fail(gc);
if (purple_conversations_find_chat_with_account(args[1], irc->account)) {
/* This is a channel we're already in; for some reason,
@@ -1407,8 +1347,7 @@
struct irc_buddy *ib;
char *data[2];
- if (!args || !args[0] || !gc)
- return;
+ g_return_if_fail(gc);
data[0] = irc_mask_nick(from);
data[1] = args[0];
@@ -1429,9 +1368,6 @@
{
PurpleConnection *gc = purple_account_get_connection(irc->account);
- if (!args || !args[1])
- return;
-
purple_notify_error(gc, NULL, _("Nick or channel is temporarily "
"unavailable."), args[1],
purple_request_cpar_from_connection(gc));
@@ -1442,8 +1378,7 @@
PurpleConnection *gc = purple_account_get_connection(irc->account);
char *nick, *msg;
- if (!args || !args[0] || !gc)
- return;
+ g_return_if_fail(gc);
nick = irc_mask_nick(from);
msg = g_strdup_printf (_("Wallops from %s"), nick);
@@ -1621,7 +1556,7 @@
PurpleConnection *gc = purple_account_get_connection(irc->account);
const char *mech_list = NULL;
- if (!args[1] || !args[2] || strncmp(args[2], "sasl ", 6))
+ if (strncmp(args[2], "sasl ", 6))
return;
if (strncmp(args[1], "ACK", 4)) {
const char *tmp = _("SASL authentication failed: Server does not support SASL authentication.");
@@ -1724,7 +1659,10 @@
return;
}
- authinfo = purple_base64_encode((const guchar*)c_out, clen);
+ if (clen > 0)
+ authinfo = purple_base64_encode((const guchar*)c_out, clen);
+ else
+ authinfo = g_strdup("+");
buf = irc_format(irc, "vv", "AUTHENTICATE", authinfo);
irc_send(irc, buf);
--- a/libpurple/protocols/irc/parse.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/protocols/irc/parse.c Mon Jan 20 00:02:17 2014 -0800
@@ -50,80 +50,85 @@
static struct _irc_msg {
char *name;
char *format;
+
+ /** The required parameter count, based on values we use, not protocol
+ * specification. */
+ int req_cnt;
+
void (*cb)(struct irc_conn *irc, const char *name, const char *from, char **args);
} _irc_msgs[] = {
- { "005", "n*", irc_msg_features }, /* Feature list */
- { "251", "n:", irc_msg_luser }, /* Client & Server count */
- { "255", "n:", irc_msg_luser }, /* Client & Server count Mk. II */
- { "301", "nn:", irc_msg_away }, /* User is away */
- { "303", "n:", irc_msg_ison }, /* ISON reply */
- { "311", "nnvvv:", irc_msg_whois }, /* Whois user */
- { "312", "nnv:", irc_msg_whois }, /* Whois server */
- { "313", "nn:", irc_msg_whois }, /* Whois ircop */
- { "317", "nnvv", irc_msg_whois }, /* Whois idle */
- { "318", "nt:", irc_msg_endwhois }, /* End of WHOIS */
- { "319", "nn:", irc_msg_whois }, /* Whois channels */
- { "320", "nn:", irc_msg_whois }, /* Whois (fn ident) */
- { "314", "nnnvv:", irc_msg_whois }, /* Whowas user */
- { "315", "nt:", irc_msg_who }, /* end of WHO channel */
- { "369", "nt:", irc_msg_endwhois }, /* End of WHOWAS */
- { "321", "*", irc_msg_list }, /* Start of list */
- { "322", "ncv:", irc_msg_list }, /* List. */
- { "323", ":", irc_msg_list }, /* End of list. */
- { "324", "ncv:", irc_msg_chanmode }, /* Channel modes */
- { "331", "nc:", irc_msg_topic }, /* No channel topic */
- { "332", "nc:", irc_msg_topic }, /* Channel topic */
- { "333", "ncvv", irc_msg_topicinfo }, /* Topic setter stuff */
- { "352", "ncvvvnv:", irc_msg_who }, /* Channel WHO */
- { "353", "nvc:", irc_msg_names }, /* Names list */
- { "366", "nc:", irc_msg_names }, /* End of names */
- { "367", "ncnnv", irc_msg_ban }, /* Ban list */
- { "368", "nc:", irc_msg_ban }, /* End of ban list */
- { "372", "n:", irc_msg_motd }, /* MOTD */
- { "375", "n:", irc_msg_motd }, /* Start MOTD */
- { "376", "n:", irc_msg_motd }, /* End of MOTD */
- { "391", "nv:", irc_msg_time }, /* Time reply */
- { "401", "nt:", irc_msg_nonick }, /* No such nick/chan */
- { "406", "nt:", irc_msg_nonick }, /* No such nick for WHOWAS */
- { "403", "nc:", irc_msg_nochan }, /* No such channel */
- { "404", "nt:", irc_msg_nosend }, /* Cannot send to chan */
- { "421", "nv:", irc_msg_unknown }, /* Unknown command */
- { "422", "n:", irc_msg_motd }, /* MOTD file missing */
- { "432", "vn:", irc_msg_badnick }, /* Erroneous nickname */
- { "433", "vn:", irc_msg_nickused }, /* Nickname already in use */
- { "437", "nc:", irc_msg_unavailable }, /* Nick/channel is unavailable */
- { "438", "nn:", irc_msg_nochangenick }, /* Nick may not change */
- { "442", "nc:", irc_msg_notinchan }, /* Not in channel */
- { "473", "nc:", irc_msg_inviteonly }, /* Tried to join invite-only */
- { "474", "nc:", irc_msg_banned }, /* Banned from channel */
- { "477", "nc:", irc_msg_regonly }, /* Registration Required */
- { "478", "nct:", irc_msg_banfull }, /* Banlist is full */
- { "482", "nc:", irc_msg_notop }, /* Need to be op to do that */
- { "501", "n:", irc_msg_badmode }, /* Unknown mode flag */
- { "506", "nc:", irc_msg_nosend }, /* Must identify to send */
- { "515", "nc:", irc_msg_regonly }, /* Registration required */
+ { "005", "n*", 2, irc_msg_features }, /* Feature list */
+ { "251", "n:", 1, irc_msg_luser }, /* Client & Server count */
+ { "255", "n:", 1, irc_msg_luser }, /* Client & Server count Mk. II */
+ { "301", "nn:", 3, irc_msg_away }, /* User is away */
+ { "303", "n:", 2, irc_msg_ison }, /* ISON reply */
+ { "311", "nnvvv:", 6, irc_msg_whois }, /* Whois user */
+ { "312", "nnv:", 4, irc_msg_whois }, /* Whois server */
+ { "313", "nn:", 2, irc_msg_whois }, /* Whois ircop */
+ { "317", "nnvv", 4, irc_msg_whois }, /* Whois idle */
+ { "318", "nt:", 2, irc_msg_endwhois }, /* End of WHOIS */
+ { "319", "nn:", 3, irc_msg_whois }, /* Whois channels */
+ { "320", "nn:", 2, irc_msg_whois }, /* Whois (fn ident) */
+ { "314", "nnnvv:", 6, irc_msg_whois }, /* Whowas user */
+ { "315", "nt:", 0, irc_msg_who }, /* end of WHO channel */
+ { "369", "nt:", 2, irc_msg_endwhois }, /* End of WHOWAS */
+ { "321", "*", 0, irc_msg_list }, /* Start of list */
+ { "322", "ncv:", 4, irc_msg_list }, /* List. */
+ { "323", ":", 0, irc_msg_list }, /* End of list. */
+ { "324", "ncv:", 3, irc_msg_chanmode }, /* Channel modes */
+ { "331", "nc:", 3, irc_msg_topic }, /* No channel topic */
+ { "332", "nc:", 3, irc_msg_topic }, /* Channel topic */
+ { "333", "ncvv", 4, irc_msg_topicinfo }, /* Topic setter stuff */
+ { "352", "ncvvvnv:", 8, irc_msg_who }, /* Channel WHO */
+ { "353", "nvc:", 4, irc_msg_names }, /* Names list */
+ { "366", "nc:", 2, irc_msg_names }, /* End of names */
+ { "367", "ncnnv", 3, irc_msg_ban }, /* Ban list */
+ { "368", "nc:", 2, irc_msg_ban }, /* End of ban list */
+ { "372", "n:", 1, irc_msg_motd }, /* MOTD */
+ { "375", "n:", 1, irc_msg_motd }, /* Start MOTD */
+ { "376", "n:", 1, irc_msg_motd }, /* End of MOTD */
+ { "391", "nv:", 3, irc_msg_time }, /* Time reply */
+ { "401", "nt:", 2, irc_msg_nonick }, /* No such nick/chan */
+ { "406", "nt:", 2, irc_msg_nonick }, /* No such nick for WHOWAS */
+ { "403", "nc:", 2, irc_msg_nochan }, /* No such channel */
+ { "404", "nt:", 3, irc_msg_nosend }, /* Cannot send to chan */
+ { "421", "nv:", 2, irc_msg_unknown }, /* Unknown command */
+ { "422", "n:", 1, irc_msg_motd }, /* MOTD file missing */
+ { "432", "vn:", 0, irc_msg_badnick }, /* Erroneous nickname */
+ { "433", "vn:", 2, irc_msg_nickused }, /* Nickname already in use */
+ { "437", "nc:", 2, irc_msg_unavailable }, /* Nick/channel is unavailable */
+ { "438", "nn:", 3, irc_msg_nochangenick }, /* Nick may not change */
+ { "442", "nc:", 3, irc_msg_notinchan }, /* Not in channel */
+ { "473", "nc:", 2, irc_msg_inviteonly }, /* Tried to join invite-only */
+ { "474", "nc:", 2, irc_msg_banned }, /* Banned from channel */
+ { "477", "nc:", 3, irc_msg_regonly }, /* Registration Required */
+ { "478", "nct:", 3, irc_msg_banfull }, /* Banlist is full */
+ { "482", "nc:", 3, irc_msg_notop }, /* Need to be op to do that */
+ { "501", "n:", 2, irc_msg_badmode }, /* Unknown mode flag */
+ { "506", "nc:", 3, irc_msg_nosend }, /* Must identify to send */
+ { "515", "nc:", 3, irc_msg_regonly }, /* Registration required */
#ifdef HAVE_CYRUS_SASL
- { "903", "*", irc_msg_authok}, /* SASL auth successful */
- { "904", "*", irc_msg_authtryagain }, /* SASL auth failed, can recover */
- { "905", "*", irc_msg_authfail }, /* SASL auth failed */
- { "906", "*", irc_msg_authfail }, /* SASL auth failed */
- { "907", "*", irc_msg_authfail }, /* SASL auth failed */
- { "cap", "vv:", irc_msg_cap }, /* SASL capable */
+ { "903", "*", 0, irc_msg_authok}, /* SASL auth successful */
+ { "904", "*", 0, irc_msg_authtryagain }, /* SASL auth failed, can recover*/
+ { "905", "*", 0, irc_msg_authfail }, /* SASL auth failed */
+ { "906", "*", 0, irc_msg_authfail }, /* SASL auth failed */
+ { "907", "*", 0, irc_msg_authfail }, /* SASL auth failed */
+ { "cap", "vv:", 3, irc_msg_cap }, /* SASL capable */
#endif
- { "invite", "n:", irc_msg_invite }, /* Invited */
- { "join", ":", irc_msg_join }, /* Joined a channel */
- { "kick", "cn:", irc_msg_kick }, /* KICK */
- { "mode", "tv:", irc_msg_mode }, /* MODE for channel */
- { "nick", ":", irc_msg_nick }, /* Nick change */
- { "notice", "t:", irc_msg_notice }, /* NOTICE recv */
- { "part", "c:", irc_msg_part }, /* Parted a channel */
- { "ping", ":", irc_msg_ping }, /* Received PING from server */
- { "pong", "v:", irc_msg_pong }, /* Received PONG from server */
- { "privmsg", "t:", irc_msg_privmsg }, /* Received private message */
- { "topic", "c:", irc_msg_topic }, /* TOPIC command */
- { "quit", ":", irc_msg_quit }, /* QUIT notice */
- { "wallops", ":", irc_msg_wallops }, /* WALLOPS command */
- { NULL, NULL, NULL }
+ { "invite", "n:", 2, irc_msg_invite }, /* Invited */
+ { "join", ":", 1, irc_msg_join }, /* Joined a channel */
+ { "kick", "cn:", 3, irc_msg_kick }, /* KICK */
+ { "mode", "tv:", 2, irc_msg_mode }, /* MODE for channel */
+ { "nick", ":", 1, irc_msg_nick }, /* Nick change */
+ { "notice", "t:", 2, irc_msg_notice }, /* NOTICE recv */
+ { "part", "c:", 1, irc_msg_part }, /* Parted a channel */
+ { "ping", ":", 1, irc_msg_ping }, /* Received PING from server */
+ { "pong", "v:", 2, irc_msg_pong }, /* Received PONG from server */
+ { "privmsg", "t:", 2, irc_msg_privmsg }, /* Received private message */
+ { "topic", "c:", 2, irc_msg_topic }, /* TOPIC command */
+ { "quit", ":", 1, irc_msg_quit }, /* QUIT notice */
+ { "wallops", ":", 1, irc_msg_wallops }, /* WALLOPS command */
+ { NULL, NULL, 0, NULL }
};
static struct _irc_user_cmd {
@@ -664,6 +669,8 @@
char *cur, *end, *tmp, *from, *msgname, *fmt, **args, *msg;
guint i;
PurpleConnection *gc = purple_account_get_connection(irc->account);
+ gboolean fmt_valid;
+ int args_cnt;
irc->recv_time = time(NULL);
@@ -720,7 +727,9 @@
}
g_free(msgname);
+ fmt_valid = TRUE;
args = g_new0(char *, strlen(msgent->format));
+ args_cnt = 0;
for (cur = end, fmt = msgent->format, i = 0; fmt[i] && *cur++; i++) {
switch (fmt[i]) {
case 'v':
@@ -757,12 +766,23 @@
break;
default:
purple_debug(PURPLE_DEBUG_ERROR, "irc", "invalid message format character '%c'\n", fmt[i]);
+ fmt_valid = FALSE;
break;
}
+ if (fmt_valid)
+ args_cnt = i + 1;
}
- tmp = irc_recv_convert(irc, from);
- (msgent->cb)(irc, msgent->name, tmp, args);
- g_free(tmp);
+ if (G_UNLIKELY(!fmt_valid)) {
+ purple_debug_error("irc", "message format was invalid");
+ } else if (G_LIKELY(args_cnt >= msgent->req_cnt)) {
+ tmp = irc_recv_convert(irc, from);
+ (msgent->cb)(irc, msgent->name, tmp, args);
+ g_free(tmp);
+ } else {
+ purple_debug_error("irc", "args count (%d) doesn't reach "
+ "expected value of %d for the '%s' command",
+ args_cnt, msgent->req_cnt, msgent->name);
+ }
for (i = 0; i < strlen(msgent->format); i++) {
g_free(args[i]);
}
--- a/libpurple/protocols/jabber/iq.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/protocols/jabber/iq.c Mon Jan 20 00:02:17 2014 -0800
@@ -49,6 +49,18 @@
static GHashTable *iq_handlers = NULL;
static GHashTable *signal_iq_handlers = NULL;
+struct _JabberIqCallbackData {
+ JabberIqCallback *callback;
+ gpointer data;
+ JabberID *to;
+};
+
+void jabber_iq_callbackdata_free(JabberIqCallbackData *jcd)
+{
+ jabber_id_free(jcd->to);
+ g_free(jcd);
+}
+
JabberIq *jabber_iq_new(JabberStream *js, JabberIqType type)
{
JabberIq *iq;
@@ -98,11 +110,6 @@
return iq;
}
-typedef struct _JabberCallbackData {
- JabberIqCallback *callback;
- gpointer data;
-} JabberCallbackData;
-
void
jabber_iq_set_callback(JabberIq *iq, JabberIqCallback *callback, gpointer data)
{
@@ -125,15 +132,17 @@
void jabber_iq_send(JabberIq *iq)
{
- JabberCallbackData *jcd;
+ JabberIqCallbackData *jcd;
g_return_if_fail(iq != NULL);
jabber_send(iq->js, iq->node);
if(iq->id && iq->callback) {
- jcd = g_new0(JabberCallbackData, 1);
+ jcd = g_new0(JabberIqCallbackData, 1);
jcd->callback = iq->callback;
jcd->data = iq->callback_data;
+ jcd->to = jabber_id_new(purple_xmlnode_get_attrib(iq->node, "to"));
+
g_hash_table_insert(iq->js->iq_callbacks, g_strdup(iq->id), jcd);
}
@@ -276,18 +285,30 @@
void jabber_iq_parse(JabberStream *js, PurpleXmlNode *packet)
{
- JabberCallbackData *jcd;
+ JabberIqCallbackData *jcd;
PurpleXmlNode *child, *error, *x;
const char *xmlns;
const char *iq_type, *id, *from;
JabberIqType type = JABBER_IQ_NONE;
gboolean signal_return;
+ JabberID *from_id;
from = purple_xmlnode_get_attrib(packet, "from");
id = purple_xmlnode_get_attrib(packet, "id");
iq_type = purple_xmlnode_get_attrib(packet, "type");
/*
+ * Ensure the 'from' attribute is valid. No point in handling a stanza
+ * of which we don't understand where it came from.
+ */
+ from_id = jabber_id_new(from);
+
+ if (from && !from_id) {
+ purple_debug_error("jabber", "Received an iq with an invalid from: %s\n", from);
+ return;
+ }
+
+ /*
* child will be either the first tag child or NULL if there is no child.
* Historically, we used just the 'query' subchild, but newer XEPs use
* differently named children. Grabbing the first child is (for the time
@@ -312,6 +333,7 @@
if (type == JABBER_IQ_NONE) {
purple_debug_error("jabber", "IQ with invalid type ('%s') - ignoring.\n",
iq_type ? iq_type : "(null)");
+ jabber_id_free(from_id);
return;
}
@@ -342,20 +364,38 @@
purple_debug_error("jabber", "IQ of type '%s' missing id - ignoring.\n",
iq_type);
+ jabber_id_free(from_id);
return;
}
signal_return = GPOINTER_TO_INT(purple_signal_emit_return_1(purple_connection_get_prpl(js->gc),
"jabber-receiving-iq", js->gc, iq_type, id, from, packet));
- if (signal_return)
+ if (signal_return) {
+ jabber_id_free(from_id);
return;
+ }
/* First, lets see if a special callback got registered */
if(type == JABBER_IQ_RESULT || type == JABBER_IQ_ERROR) {
if((jcd = g_hash_table_lookup(js->iq_callbacks, id))) {
- jcd->callback(js, from, type, id, packet, jcd->data);
- jabber_iq_remove_callback_by_id(js, id);
- return;
+ if(jabber_id_equal(js, jcd->to, from_id)) {
+ jcd->callback(js, from, type, id, packet, jcd->data);
+ jabber_iq_remove_callback_by_id(js, id);
+ jabber_id_free(from_id);
+ return;
+ } else {
+ char *expected_to;
+
+ if (jcd->to) {
+ expected_to = jabber_id_get_full_jid(jcd->to);
+ } else {
+ expected_to = jabber_id_get_bare_jid(js->user);
+ }
+
+ purple_debug_error("jabber", "Got a result iq with id %s from %s instead of expected %s!\n", id, from ? from : "(null)", expected_to);
+
+ g_free(expected_to);
+ }
}
}
@@ -372,12 +412,15 @@
if (signal_ref > 0) {
signal_return = GPOINTER_TO_INT(purple_signal_emit_return_1(purple_connection_get_prpl(js->gc), "jabber-watched-iq",
js->gc, iq_type, id, from, child));
- if (signal_return)
+ if (signal_return) {
+ jabber_id_free(from_id);
return;
+ }
}
if(jih) {
jih(js, from, type, id, child);
+ jabber_id_free(from_id);
return;
}
}
@@ -404,6 +447,8 @@
jabber_iq_send(iq);
}
+
+ jabber_id_free(from_id);
}
void jabber_iq_register_handler(const char *node, const char *xmlns, JabberIqHandler *handlerfunc)
--- a/libpurple/protocols/jabber/iq.h Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/protocols/jabber/iq.h Mon Jan 20 00:02:17 2014 -0800
@@ -36,6 +36,7 @@
#include "connection.h"
typedef struct _JabberIq JabberIq;
+typedef struct _JabberIqCallbackData JabberIqCallbackData;
/**
* A JabberIqHandler is called to process an incoming IQ stanza.
@@ -96,6 +97,7 @@
void jabber_iq_parse(JabberStream *js, PurpleXmlNode *packet);
+void jabber_iq_callbackdata_free(JabberIqCallbackData *jcd);
void jabber_iq_remove_callback_by_id(JabberStream *js, const char *id);
void jabber_iq_set_callback(JabberIq *iq, JabberIqCallback *cb, gpointer data);
void jabber_iq_set_id(JabberIq *iq, const char *id);
--- a/libpurple/protocols/jabber/jabber.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/protocols/jabber/jabber.c Mon Jan 20 00:02:17 2014 -0800
@@ -991,7 +991,7 @@
js->user_jb->subscription |= JABBER_SUB_BOTH;
js->iq_callbacks = g_hash_table_new_full(g_str_hash, g_str_equal,
- g_free, g_free);
+ g_free, (GDestroyNotify)jabber_iq_callbackdata_free);
js->chats = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, (GDestroyNotify)jabber_chat_free);
js->next_id = g_random_int();
--- a/libpurple/protocols/jabber/jutil.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/protocols/jabber/jutil.c Mon Jan 20 00:02:17 2014 -0800
@@ -511,6 +511,34 @@
}
}
+
+gboolean
+jabber_id_equal(JabberStream *js, const JabberID *jid1, const JabberID *jid2)
+{
+ const JabberID *j1, *j2;
+ JabberID *bare_user_jid;
+ gboolean equal;
+
+ /* If an outgoing stanza has no 'to', or an incoming has no 'from',
+ * then those are "the server acting as my account". This function will
+ * handle that correctly.
+ */
+ if (!jid1 && !jid2)
+ return TRUE;
+
+ bare_user_jid = jabber_id_to_bare_jid(js->user);
+ j1 = jid1 ? jid1 : bare_user_jid;
+ j2 = jid2 ? jid2 : bare_user_jid;
+
+ equal = purple_strequal(j1->node, j2->node) &&
+ purple_strequal(j1->domain, j2->domain) &&
+ purple_strequal(j1->resource, j2->resource);
+
+ jabber_id_free(bare_user_jid);
+
+ return equal;
+}
+
char *jabber_get_domain(const char *in)
{
JabberID *jid = jabber_id_new(in);
@@ -539,6 +567,17 @@
return out;
}
+JabberID *
+jabber_id_to_bare_jid(const JabberID *jid)
+{
+ JabberID *result = g_new0(JabberID, 1);
+
+ result->node = g_strdup(jid->node);
+ result->domain = g_strdup(jid->domain);
+
+ return result;
+}
+
char *
jabber_get_bare_jid(const char *in)
{
@@ -564,6 +603,19 @@
NULL);
}
+char *
+jabber_id_get_full_jid(const JabberID *jid)
+{
+ g_return_val_if_fail(jid != NULL, NULL);
+
+ return g_strconcat(jid->node ? jid->node : "",
+ jid->node ? "@" : "",
+ jid->domain,
+ jid->resource ? "/" : "",
+ jid->resource ? jid->resource : "",
+ NULL);
+}
+
gboolean
jabber_jid_is_domain(const char *jid)
{
--- a/libpurple/protocols/jabber/jutil.h Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/protocols/jabber/jutil.h Mon Jan 20 00:02:17 2014 -0800
@@ -44,12 +44,23 @@
#include "jabber.h"
JabberID* jabber_id_new(const char *str);
+
+/**
+ * Compare two JIDs for equality.
+ *
+ * Warning: If either JID is NULL then this function uses the user's
+ * bare JID, instead!
+ */
+gboolean jabber_id_equal(JabberStream *js, const JabberID *jid1, const JabberID *jid2);
+
void jabber_id_free(JabberID *jid);
char *jabber_get_domain(const char *jid);
char *jabber_get_resource(const char *jid);
char *jabber_get_bare_jid(const char *jid);
char *jabber_id_get_bare_jid(const JabberID *jid);
+char *jabber_id_get_full_jid(const JabberID *jid);
+JabberID *jabber_id_to_bare_jid(const JabberID *jid);
gboolean jabber_jid_is_domain(const char *jid);
--- a/libpurple/protocols/msn/msg.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/protocols/msn/msg.c Mon Jan 20 00:02:17 2014 -0800
@@ -178,6 +178,8 @@
g_free(tmp_base);
g_return_if_reached();
}
+
+ /* NUL-terminate the end of the headers - it'll get skipped over below */
*end = '\0';
/* Split the headers and parse each one */
@@ -195,10 +197,12 @@
/* The only one I care about is 'boundary' (which is folded from
the key 'Content-Type'), so only process that. */
- if (!strcmp(key, "boundary")) {
+ if (!strcmp(key, "boundary") && value) {
char *end = strchr(value, '\"');
- *end = '\0';
- msn_message_set_header(msg, key, value);
+ if (end) {
+ *end = '\0';
+ msn_message_set_header(msg, key, value);
+ }
}
g_strfreev(tokens);
@@ -210,18 +214,15 @@
key = tokens[0];
value = tokens[1];
- /*if not MIME content ,then return*/
if (!strcmp(key, "MIME-Version"))
{
- g_strfreev(tokens);
- continue;
+ /* Ignore MIME-Version header */
}
-
- if (!strcmp(key, "Content-Type"))
+ else if (!strcmp(key, "Content-Type"))
{
char *charset, *c;
- if ((c = strchr(value, ';')) != NULL)
+ if (value && (c = strchr(value, ';')) != NULL)
{
if ((charset = strchr(c, '=')) != NULL)
{
@@ -365,11 +366,12 @@
n += strlen(n);
}
- n += g_strlcpy(n, "\r\n", end - n);
+ if ((end - n) > 2)
+ n += g_strlcpy(n, "\r\n", end - n);
body = msn_message_get_bin_data(msg, &body_len);
- if (body != NULL)
+ if (body != NULL && (size_t)(end - n) > body_len)
{
memcpy(n, body, body_len);
n += body_len;
--- a/libpurple/protocols/msn/oim.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/protocols/msn/oim.c Mon Jan 20 00:02:17 2014 -0800
@@ -361,11 +361,12 @@
if (faultcode) {
char *faultcode_str = purple_xmlnode_get_data(faultcode);
- if (g_str_equal(faultcode_str, "q0:AuthenticationFailed")) {
+ if (faultcode_str && g_str_equal(faultcode_str, "q0:AuthenticationFailed")) {
PurpleXmlNode *challengeNode = purple_xmlnode_get_child(faultNode,
"detail/LockKeyChallenge");
+ char *challenge = NULL;
- if (challengeNode == NULL) {
+ if (challengeNode == NULL || (challenge = purple_xmlnode_get_data(challengeNode)) == NULL) {
if (oim->challenge) {
g_free(oim->challenge);
oim->challenge = NULL;
@@ -383,7 +384,6 @@
} else {
char buf[33];
- char *challenge = purple_xmlnode_get_data(challengeNode);
msn_handle_chl(challenge, buf);
g_free(oim->challenge);
@@ -399,22 +399,23 @@
}
} else {
/* Report the error */
- const char *str_reason;
-
- if (g_str_equal(faultcode_str, "q0:SystemUnavailable")) {
- str_reason = _("Message was not sent because the system is "
- "unavailable. This normally happens when the "
- "user is blocked or does not exist.");
+ const char *str_reason = NULL;
- } else if (g_str_equal(faultcode_str, "q0:SenderThrottleLimitExceeded")) {
- str_reason = _("Message was not sent because messages "
- "are being sent too quickly.");
+ if (faultcode_str) {
+ if (g_str_equal(faultcode_str, "q0:SystemUnavailable")) {
+ str_reason = _("Message was not sent because the system is "
+ "unavailable. This normally happens when the "
+ "user is blocked or does not exist.");
+ } else if (g_str_equal(faultcode_str, "q0:SenderThrottleLimitExceeded")) {
+ str_reason = _("Message was not sent because messages "
+ "are being sent too quickly.");
+ } else if (g_str_equal(faultcode_str, "q0:InvalidContent")) {
+ str_reason = _("Message was not sent because an unknown "
+ "encoding error occurred.");
+ }
+ }
- } else if (g_str_equal(faultcode_str, "q0:InvalidContent")) {
- str_reason = _("Message was not sent because an unknown "
- "encoding error occurred.");
-
- } else {
+ if (str_reason == NULL) {
str_reason = _("Message was not sent because an unknown "
"error occurred.");
}
@@ -823,10 +824,10 @@
char *unread = purple_xmlnode_get_data(iu_node);
const char *passports[2] = { msn_user_get_passport(session->user) };
const char *urls[2] = { session->passport_info.mail_url };
- int count = atoi(unread);
+ int count;
/* XXX/khc: pretty sure this is wrong */
- if (count > 0)
+ if (unread && (count = atoi(unread)) > 0)
purple_notify_emails(purple_account_get_connection(session->account), count, FALSE, NULL,
NULL, passports, urls, NULL, NULL);
g_free(unread);
--- a/libpurple/protocols/msn/soap.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/protocols/msn/soap.c Mon Jan 20 00:02:17 2014 -0800
@@ -193,9 +193,11 @@
if (xml_url != NULL)
url = purple_xmlnode_get_data(xml_url);
- msn_soap_service_send_message_simple(sreq->soaps,
- sreq->message, url, sreq->secure, sreq->cb,
- sreq->cb_data);
+ if (url) {
+ msn_soap_service_send_message_simple(sreq->soaps,
+ sreq->message, url, sreq->secure, sreq->cb,
+ sreq->cb_data);
+ }
/* Steal the message, passed to another call. */
sreq->message = NULL;
@@ -208,7 +210,10 @@
if (g_strcmp0(faultdata, "wsse:FailedAuthentication") == 0) {
PurpleXmlNode *xml_reason =
purple_xmlnode_get_child(xml_fault, "faultstring");
- gchar *reasondata = purple_xmlnode_get_data(xml_reason);
+ gchar *reasondata = NULL;
+
+ if (xml_reason)
+ reasondata = purple_xmlnode_get_data(xml_reason);
msn_session_set_error(sreq->soaps->session, MSN_ERROR_AUTH,
reasondata);
--- a/libpurple/protocols/mxit/markup.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/protocols/mxit/markup.c Mon Jan 20 00:02:17 2014 -0800
@@ -204,7 +204,8 @@
*/
static int asn_getUtf8( const gchar* data, gchar type, char** utf8 )
{
- int len;
+ unsigned int len;
+ gchar *out_str;
/* validate the field type [1 byte] */
if ( data[0] != type ) {
@@ -213,10 +214,12 @@
return -1;
}
- len = data[1]; /* length field [1 bytes] */
- *utf8 = g_malloc( len + 1 );
- memcpy( *utf8, &data[2], len ); /* data field */
- (*utf8)[len] = '\0';
+ len = (uint8_t)data[1]; /* length field [1 byte] */
+ out_str = g_malloc(len + 1);
+ memcpy(out_str, &data[2], len); /* data field */
+ out_str[len] = '\0';
+
+ *utf8 = out_str;
return ( len + 2 );
}
--- a/libpurple/protocols/oscar/odc.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/protocols/oscar/odc.c Mon Jan 20 00:02:17 2014 -0800
@@ -267,7 +267,6 @@
* problems while parsing the binary data section then we stop
* parsing it, and the local user will see broken image icons.
*/
- /* TODO: Use a length argument when looking for the <binary> tag! */
binary_start = purple_strcasestr(msg, "<binary>");
if (binary_start == NULL)
msgend = dataend;
@@ -279,7 +278,6 @@
tmp = binary_start + 8;
/* The embedded binary markup has a mimimum length of 29 bytes */
- /* TODO: Use a length argument when looking for the <data> tag! */
while ((tmp + 29 <= dataend) &&
purple_markup_find_tag("data", tmp, &start, &tmp, &attributes))
{
@@ -472,6 +470,10 @@
if (bs->offset < bs->len)
/* Waiting for more data to arrive */
return;
+ /* TODO: Instead of null-terminating this, it would be better if we just
+ respected the length of the buffer when parsing it. But it doesn't
+ really matter and this is easy. */
+ bs->data[bs->len] = '\0';
/* We have a complete ODC/OFT frame! Handle it and continue reading */
byte_stream_rewind(bs);
@@ -621,7 +623,7 @@
}
/* We have payload data! Switch to the ODC watcher to read it. */
- frame->payload.data = g_new(guint8, frame->payload.len);
+ frame->payload.data = g_new(guint8, frame->payload.len + 1);
frame->payload.offset = 0;
conn->frame = frame;
purple_input_remove(conn->watcher_incoming);
--- a/libpurple/protocols/simple/simple.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/protocols/simple/simple.c Mon Jan 20 00:02:17 2014 -0800
@@ -1643,7 +1643,7 @@
cur += 2;
restlen = conn->inbufused - (cur - conn->inbuf);
if(restlen >= msg->bodylen) {
- dummy = g_malloc(msg->bodylen + 1);
+ dummy = g_new(char, msg->bodylen + 1);
memcpy(dummy, cur, msg->bodylen);
dummy[msg->bodylen] = '\0';
msg->body = dummy;
--- a/libpurple/protocols/simple/sipmsg.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/protocols/simple/sipmsg.c Mon Jan 20 00:02:17 2014 -0800
@@ -35,6 +35,8 @@
#include "simple.h"
#include "sipmsg.h"
+#define MAX_CONTENT_LENGTH 30000000
+
struct sipmsg *sipmsg_parse_msg(const gchar *msg) {
const char *tmp = strstr(msg, "\r\n\r\n");
char *line;
@@ -114,6 +116,16 @@
tmp2 = sipmsg_find_header(msg, "Content-Length");
if (tmp2 != NULL)
msg->bodylen = strtol(tmp2, NULL, 10);
+ if (msg->bodylen < 0) {
+ purple_debug_warning("simple", "Invalid body length: %d",
+ msg->bodylen);
+ msg->bodylen = 0;
+ } else if (msg->bodylen > MAX_CONTENT_LENGTH) {
+ purple_debug_warning("simple", "Got Content-Length of %d bytes on "
+ "incoming message (max is %u bytes). Ignoring message body.\n",
+ msg->bodylen, MAX_CONTENT_LENGTH);
+ msg->bodylen = 0;
+ }
if(msg->response) {
tmp2 = sipmsg_find_header(msg, "CSeq");
--- a/libpurple/protocols/yahoo/libymsg.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/protocols/yahoo/libymsg.c Mon Jan 20 00:02:17 2014 -0800
@@ -21,6 +21,12 @@
*
*/
+/*
+ * Note: When handling the list of struct yahoo_pair's from an incoming
+ * packet the value might not be UTF-8. You should either validate that
+ * it is UTF-8 using g_utf8_validate() or use yahoo_string_decode().
+ */
+
#include "internal.h"
#include "account.h"
@@ -598,14 +604,24 @@
yd->current_list15_grp = yahoo_string_decode(gc, pair->value, FALSE);
break;
case 7: /* buddy's s/n */
- g_free(temp);
- temp = g_strdup(purple_normalize(account, pair->value));
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ g_free(temp);
+ temp = g_strdup(purple_normalize(account, pair->value));
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_list_15 "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
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);
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ yahoo_process_cookie(yd, pair->value);
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_list_15 "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 317: /* Stealth Setting */
stealth = strtol(pair->value, NULL, 10);
@@ -667,22 +683,42 @@
g_string_append(yd->tmp_serv_blist, pair->value);
break;
case 88:
- if (!yd->tmp_serv_ilist)
- yd->tmp_serv_ilist = g_string_new(pair->value);
- else
- g_string_append(yd->tmp_serv_ilist, pair->value);
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ if (!yd->tmp_serv_ilist)
+ yd->tmp_serv_ilist = g_string_new(pair->value);
+ else
+ g_string_append(yd->tmp_serv_ilist, pair->value);
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_list "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 89:
- yd->profiles = g_strsplit(pair->value, ",", -1);
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ yd->profiles = g_strsplit(pair->value, ",", -1);
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_list "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 59: /* cookies, yum */
- yahoo_process_cookie(yd, pair->value);
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ yahoo_process_cookie(yd, pair->value);
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_list "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case YAHOO_SERVICE_PRESENCE_PERM:
- if (!yd->tmp_serv_plist)
- yd->tmp_serv_plist = g_string_new(pair->value);
- else
- g_string_append(yd->tmp_serv_plist, pair->value);
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ if (!yd->tmp_serv_plist)
+ yd->tmp_serv_plist = g_string_new(pair->value);
+ else
+ g_string_append(yd->tmp_serv_plist, pair->value);
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_list "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
}
}
@@ -705,6 +741,12 @@
grp = yahoo_string_decode(gc, split[0], FALSE);
buddies = g_strsplit(split[1], ",", -1);
for (bud = buddies; bud && *bud; bud++) {
+ if (!g_utf8_validate(*bud, -1, NULL)) {
+ purple_debug_warning("yahoo", "yahoo_process_list "
+ "got non-UTF-8 string for bud\n");
+ continue;
+ }
+
norm_bud = g_strdup(purple_normalize(account, *bud));
f = yahoo_friend_find_or_new(gc, norm_bud);
@@ -798,14 +840,26 @@
while (l) {
struct yahoo_pair *pair = l->data;
- if (pair->key == 4 || pair->key == 1)
- from = pair->value;
+ if (pair->key == 4 || pair->key == 1) {
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ from = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_notify "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
+ }
if (pair->key == 49)
msg = pair->value;
if (pair->key == 13)
stat = pair->value;
- if (pair->key == 14)
- game = pair->value;
+ if (pair->key == 14) {
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ game = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_notify "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
+ }
if (pair->key == 11)
val_11 = strtol(pair->value, NULL, 10);
if (pair->key == 241)
@@ -909,10 +963,15 @@
while (l != NULL) {
struct yahoo_pair *pair = l->data;
if (pair->key == 4) {
- sms = g_new0(struct _yahoo_im, 1);
- sms->from = g_strdup_printf("+%s", pair->value);
- sms->time = time(NULL);
- sms->utf8 = TRUE;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ sms = g_new0(struct _yahoo_im, 1);
+ sms->from = g_strdup_printf("+%s", pair->value);
+ sms->time = time(NULL);
+ sms->utf8 = TRUE;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_sms_message "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
}
if (pair->key == 14) {
if (sms)
@@ -921,8 +980,14 @@
if (pair->key == 68)
if(sms)
g_hash_table_insert(yd->sms_carrier, g_strdup(sms->from), g_strdup(pair->value));
- if (pair->key == 16)
- server_msg = pair->value;
+ if (pair->key == 16) {
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ server_msg = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_sms_message "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
+ }
l = l->next;
}
@@ -979,13 +1044,18 @@
while (l != NULL) {
struct yahoo_pair *pair = l->data;
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->time = time(NULL);
- im->utf8 = TRUE;
- im->fed = YAHOO_FEDERATION_NONE;
- im->fed_from = g_strdup(im->from);
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ im = g_new0(struct _yahoo_im, 1);
+ list = g_slist_append(list, im);
+ im->from = pair->value;
+ im->time = time(NULL);
+ im->utf8 = TRUE;
+ im->fed = YAHOO_FEDERATION_NONE;
+ im->fed_from = g_strdup(im->from);
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_message "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
}
if (im && pair->key == 5)
im->active_id = pair->value;
@@ -1041,7 +1111,7 @@
}
}
/* IMV key */
- if (im && pair->key == 63)
+ if (im && pair->key == 63 && g_utf8_validate(pair->value, -1, NULL))
{
/* Check for the Doodle IMV, no IMvironment for federated buddies */
if (im->from != NULL && im->fed == YAHOO_FEDERATION_NONE)
@@ -1178,10 +1248,22 @@
while (l) {
struct yahoo_pair *pair = l->data;
- if (pair->key == 5)
- me = pair->value;
- if (pair->key == 14)
- msg = pair->value;
+ if (pair->key == 5) {
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ me = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_sysmessage "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
+ }
+ if (pair->key == 14) {
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ msg = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_sysmessage "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
+ }
l = l->next;
}
@@ -1325,7 +1407,12 @@
switch (pair->key) {
case 4:
- temp = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ temp = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_buddy_auth_req_15 "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 13:
response = strtol(pair->value, NULL, 10);
@@ -1380,22 +1467,42 @@
switch (pair->key) {
case 4:
- temp = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ temp = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_buddy_auth_req_15 "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 5:
- add_req->id = g_strdup(pair->value);
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ add_req->id = g_strdup(pair->value);
+ } else {
+ purple_debug_warning("yahoo", "yahoo_buddy_auth_req_15 "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 14:
msg = pair->value;
break;
case 216:
- firstname = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ firstname = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_buddy_auth_req_15 "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 241:
add_req->fed = strtol(pair->value, NULL, 10);
break;
case 254:
- lastname = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ lastname = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_buddy_auth_req_15 "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
}
@@ -1476,10 +1583,20 @@
switch (pair->key) {
case 1:
- add_req->id = g_strdup(pair->value);
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ add_req->id = g_strdup(pair->value);
+ } else {
+ purple_debug_warning("yahoo", "yahoo_buddy_added_us "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 3:
- add_req->who = g_strdup(pair->value);
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ add_req->who = g_strdup(pair->value);
+ } else {
+ purple_debug_warning("yahoo", "yahoo_buddy_added_us "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 15: /* time, for when they add us and we're offline */
break;
@@ -1531,10 +1648,20 @@
switch (pair->key) {
case 3:
- who = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ who = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_buddy_denied_our_add_old "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 14:
- msg = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ msg = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_buddy_denied_our_add_old "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
}
l = l->next;
@@ -1631,12 +1758,28 @@
struct yahoo_pair *pair = l->data;
if (pair->key == 9)
count = strtol(pair->value, NULL, 10);
- else if (pair->key == 43)
- who = pair->value;
- else if (pair->key == 42)
- email = pair->value;
- else if (pair->key == 18)
- subj = pair->value;
+ else if (pair->key == 43) {
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ who = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_mail "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
+ } else if (pair->key == 42) {
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ email = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_mail "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
+ } else if (pair->key == 18) {
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ subj = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_mail "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
+ }
l = l->next;
}
@@ -2025,8 +2168,14 @@
while (l) {
struct yahoo_pair *pair = l->data;
- if (pair->key == 94)
- seed = pair->value;
+ if (pair->key == 94) {
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ seed = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_auth "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
+ }
/* (pair->key == 1) -> sn */
if (pair->key == 13)
m = atoi(pair->value);
@@ -2099,7 +2248,12 @@
struct yahoo_pair *pair = l->data;
switch (pair->key) {
case 0:
- who = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ who = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_ignore "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
/* 1 -> me */
case 13:
@@ -2196,8 +2350,14 @@
if (pair->key == 66)
err = strtol(pair->value, NULL, 10);
- else if (pair->key == 20)
- url = pair->value;
+ else if (pair->key == 20) {
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ url = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_authresp "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
+ }
l = l->next;
}
@@ -2276,7 +2436,12 @@
err = strtol(pair->value, NULL, 10);
break;
case 7:
- temp = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ temp = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_addbuddy "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 65:
group = pair->value;
@@ -2436,11 +2601,16 @@
switch (pair->key) {
case 4:
- who = pair->value;
- if(strncmp(who, p2p_data->host_username, strlen(p2p_data->host_username)) != 0) {
- /* from whom are we receiving the packets ?? */
- purple_debug_warning("yahoo","p2p: received data from wrong user\n");
- return;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ who = pair->value;
+ if(strncmp(who, p2p_data->host_username, strlen(p2p_data->host_username)) != 0) {
+ /* from whom are we receiving the packets ?? */
+ purple_debug_warning("yahoo","p2p: received data from wrong user\n");
+ return;
+ }
+ } else {
+ purple_debug_warning("yahoo", "yahoo_p2p_process_p2pfilexfer "
+ "got non-UTF-8 string for key %d\n", pair->key);
}
break;
case 13:
@@ -2507,7 +2677,7 @@
int pos = 0;
int pktlen;
struct yahoo_packet *pkt;
- guchar *start = NULL;
+ guchar *start;
struct yahoo_p2p_data *p2p_data;
YahooData *yd;
@@ -2529,19 +2699,29 @@
return;
}
+ /* TODO: It looks like there's a bug here (and above) where an incorrect
+ * assumtion is being made that the buffer will be added to when this
+ * is next called, but that's not really the case! */
if(len < YAHOO_PACKET_HDRLEN)
return;
- if(strncmp((char *)buf, "YMSG", MIN(4, len)) != 0) {
+ if(strncmp((char *)buf, "YMSG", 4) != 0) {
/* Not a YMSG packet */
+ purple_debug_warning("yahoo", "p2p: Got something other than YMSG packet\n");
+
+ start = (guchar *) g_strstr_len((char *) buf + 1, len - 1 ,"YMSG");
+ if (start == NULL) {
+ /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
+ if (g_hash_table_lookup(yd->peers, p2p_data->host_username))
+ g_hash_table_remove(yd->peers, p2p_data->host_username);
+ else
+ yahoo_p2p_disconnect_destroy_data(data);
+ return;
+ }
purple_debug_warning("yahoo","p2p: Got something other than YMSG packet\n");
- start = memchr(buf + 1, 'Y', len - 1);
- if (start == NULL)
- return;
-
- g_memmove(buf, start, len - (start - buf));
- len -= start - buf;
+ len -= (start - buf);
+ g_memmove(buf, start, len);
}
pos += 4; /* YMSG */
@@ -2549,7 +2729,17 @@
pos += 2;
pktlen = yahoo_get16(buf + pos); pos += 2;
- purple_debug_misc("yahoo", "p2p: %d bytes to read\n", len);
+ if (len < (YAHOO_PACKET_HDRLEN + pktlen)) {
+ purple_debug_error("yahoo", "p2p: packet length(%d) > buffer length(%d)\n",
+ pktlen, (len - pos));
+ /* remove from p2p connection lists, also calls yahoo_p2p_disconnect_destroy_data */
+ if (g_hash_table_lookup(yd->peers, p2p_data->host_username))
+ g_hash_table_remove(yd->peers, p2p_data->host_username);
+ else
+ yahoo_p2p_disconnect_destroy_data(data);
+ return;
+ } else
+ purple_debug_misc("yahoo", "p2p: %d bytes to read\n", pktlen);
pkt = yahoo_packet_new(0, 0, 0);
pkt->service = yahoo_get16(buf + pos); pos += 2;
@@ -2809,15 +2999,25 @@
/* our identity */
break;
case 4:
- who = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ who = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_p2p "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 1:
/* who again, the master identity this time? */
break;
case 12:
- base64 = pair->value;
- /* so, this is an ip address. in base64. decoded it's in ascii.
- after strtol, it's in reversed byte order. Who thought this up?*/
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ base64 = pair->value;
+ /* so, this is an ip address. in base64. decoded it's in ascii.
+ after strtol, it's in reversed byte order. Who thought this up?*/
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_p2p "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 13:
val_13 = strtol(pair->value, NULL, 10);
@@ -2906,7 +3106,12 @@
switch (pair->key) {
case 4:
- who = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ who = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_audible "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 5:
/* us */
@@ -2914,11 +3119,21 @@
case 230:
/* the audible, in foo.locale.bar.baz format
eg: base.tw.smiley.smiley43 */
- id = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ id = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_audible "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 231:
/* the text of the audible */
- msg = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ msg = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_audible "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 232:
/* SHA-1 hash of audible SWF file (eg: 4e8691499d9c0fb8374478ff9720f4a9ea4a4915) */
--- a/libpurple/protocols/yahoo/util.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/protocols/yahoo/util.c Mon Jan 20 00:02:17 2014 -0800
@@ -133,6 +133,7 @@
YahooData *yd = purple_connection_get_protocol_data(gc);
char *ret;
const char *to_codeset;
+ GError *error = NULL;
if (yd->jp)
return g_strdup(str);
@@ -141,12 +142,22 @@
return g_strdup(str);
to_codeset = purple_account_get_string(purple_connection_get_account(gc), "local_charset", "ISO-8859-1");
- ret = g_convert_with_fallback(str, -1, to_codeset, "UTF-8", "?", NULL, NULL, NULL);
+ ret = g_convert_with_fallback(str, -1, to_codeset, "UTF-8", "?", NULL, NULL, &error);
+ if (!ret) {
+ if (error) {
+ purple_debug_error("yahoo", "Could not convert %s from UTF-8 to "
+ "%s: %d - %s\n", str ? str : "(null)", to_codeset,
+ error->code,
+ error->message ? error->message : "(null)");
+ g_error_free(error);
+ } else {
+ purple_debug_error("yahoo", "Could not convert %s from UTF-8 to "
+ "%s: unkown error\n", str ? str : "(null)", to_codeset);
+ }
+ return g_strdup("");
+ }
- if (ret)
- return ret;
- else
- return g_strdup("");
+ return ret;
}
/**
@@ -162,10 +173,13 @@
YahooData *yd = purple_connection_get_protocol_data(gc);
char *ret;
const char *from_codeset;
+ GError *error = NULL;
if (utf8) {
if (g_utf8_validate(str, -1, NULL))
return g_strdup(str);
+ purple_debug_warning("yahoo", "Server told us a string was supposed "
+ "to be UTF-8, but it was not. Will try another encoding.\n");
}
if (yd->jp)
@@ -173,12 +187,22 @@
else
from_codeset = purple_account_get_string(purple_connection_get_account(gc), "local_charset", "ISO-8859-1");
- ret = g_convert_with_fallback(str, -1, "UTF-8", from_codeset, NULL, NULL, NULL, NULL);
+ ret = g_convert_with_fallback(str, -1, "UTF-8", from_codeset, NULL, NULL, NULL, &error);
+ if (!ret) {
+ if (error) {
+ purple_debug_error("yahoo", "Could not convert %s from %s to "
+ "UTF-8: %d - %s\n", str ? str : "(null)", from_codeset,
+ error->code, error->message ? error->message : "(null)");
+ g_error_free(error);
+ } else {
+ purple_debug_error("yahoo", "Could not convert %s from %s to "
+ "UTF-8: unkown error\n", str ? str : "(null)",
+ from_codeset);
+ }
+ return g_strdup("");
+ }
- if (ret)
- return ret;
- else
- return g_strdup("");
+ return ret;
}
char *yahoo_convert_to_numeric(const char *str)
--- a/libpurple/protocols/yahoo/yahoo_aliases.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/protocols/yahoo/yahoo_aliases.c Mon Jan 20 00:02:17 2014 -0800
@@ -673,8 +673,14 @@
struct yahoo_pair *pair = l->data;
switch (pair->key) {
case 4:
- who = pair->value; /* This is the person who sent us the details.
- But not necessarily about himself. */
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ /* This is the person who sent us the details.
+ But not necessarily about himself. */
+ who = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_contact_details "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 5:
break;
@@ -686,8 +692,13 @@
and look into the xml instead to see who the information is about. */
break;
case 280:
- xml = pair->value;
- parse_contact_details(yd, who, xml);
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ xml = pair->value;
+ parse_contact_details(yd, who, xml);
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_contact_details "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
}
}
--- a/libpurple/protocols/yahoo/yahoo_filexfer.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/protocols/yahoo/yahoo_filexfer.c Mon Jan 20 00:02:17 2014 -0800
@@ -395,22 +395,52 @@
switch(pair->key) {
case 5: /* Get who the packet is for */
- me = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ me = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_p2pfilexfer "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 4: /* Get who the packet is from */
- from = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ from = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_p2pfilexfer "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 49: /* Get the type of service */
- service = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ service = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_p2pfilexfer "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 14: /* Get the 'message' of the packet */
- message = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ message = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_p2pfilexfer "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 13: /* Get the command associated with this packet */
- command = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ command = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_p2pfilexfer "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 63: /* IMVironment name and version */
- imv = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ imv = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_p2pfilexfer "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 64: /* Not sure, but it does vary with initialization of Doodle */
break;
@@ -612,19 +642,34 @@
switch (pair->key) {
case 4:
- from = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ from = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_filetrans_15 "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 5: /* to */
break;
case 265:
- xfer_peer_idstring = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ xfer_peer_idstring = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_filetrans_15 "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 27:
filename_list = g_slist_prepend(filename_list, g_strdup(pair->value));
nooffiles++;
break;
case 28:
- size_list = g_slist_prepend(size_list, g_strdup(pair->value));
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ size_list = g_slist_prepend(size_list, g_strdup(pair->value));
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_filetrans_15 "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 222:
val_222 = atol(pair->value);
@@ -633,10 +678,20 @@
/* check for p2p and imviron .... not sure it comes by this service packet. Since it was bundled with filexfer in old ymsg version, still keeping it. */
case 49:
- service = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ service = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_filetrans_15 "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 63:
- imv = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ imv = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_filetrans_15 "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
/* end check */
@@ -929,7 +984,12 @@
case 5: /* to */
break;
case 265:
- xfer_peer_idstring = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ xfer_peer_idstring = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_filetrans_info_15 "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 27: /* filename */
break;
@@ -941,10 +1001,20 @@
/* 249 has value 1 or 2 when doing p2p transfer and value 3 when relaying through yahoo server */
break;
case 250:
- url = pair->value; /* TODO: rename to host? what about non-relay? */
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ url = pair->value; /* TODO: rename to host? what about non-relay? */
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_filetrans_info_15 "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 251:
- xfer_idstring_for_relay = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ xfer_idstring_for_relay = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_filetrans_info_15 "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
}
}
@@ -1024,10 +1094,20 @@
switch (pair->key) {
case 251:
- xfer_idstring_for_relay = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ xfer_idstring_for_relay = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_filetrans_acc_15 "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 265:
- xfer_peer_idstring = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ xfer_peer_idstring = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_filetrans_acc_15 "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 66:
val_66 = atol(pair->value);
@@ -1036,7 +1116,13 @@
val_249 = atol(pair->value);
break;
case 250:
- url = pair->value; /* we get a p2p url here when sending file, connected as client */
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ /* we get a p2p url here when sending file, connected as client */
+ url = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_filetrans_acc_15 "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
}
}
--- a/libpurple/protocols/yahoo/yahoo_friend.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/protocols/yahoo/yahoo_friend.c Mon Jan 20 00:02:17 2014 -0800
@@ -160,7 +160,12 @@
switch (pair->key) {
case 7:
- temp = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ temp = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_presence "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 31:
value = strtol(pair->value, NULL, 10);
--- a/libpurple/protocols/yahoo/yahoo_picture.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/protocols/yahoo/yahoo_picture.c Mon Jan 20 00:02:17 2014 -0800
@@ -85,7 +85,12 @@
switch (pair->key) {
case 1:
case 4:
- who = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ who = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_picture "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 5: /* us */
break;
@@ -100,7 +105,12 @@
break;
}
case 20:
- url = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ url = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_picture "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 192:
checksum = strtol(pair->value, NULL, 10);
@@ -146,7 +156,12 @@
switch (pair->key) {
case 4:
- who = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ who = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_picture_checksum "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 5:
/* us */
@@ -189,7 +204,12 @@
/* filename on our computer. */
break;
case 20: /* url at yahoo */
- url = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ url = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_picture_upload "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
case 38: /* timestamp */
break;
}
@@ -217,7 +237,12 @@
switch (pair->key) {
case 4:
- who = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ who = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_avatar_upload "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 5:
/* us */
--- a/libpurple/protocols/yahoo/yahoochat.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/protocols/yahoo/yahoochat.c Mon Jan 20 00:02:17 2014 -0800
@@ -156,15 +156,25 @@
room = yahoo_string_decode(gc, pair->value, FALSE);
break;
case 50: /* inviter */
- who = pair->value;
- g_string_append_printf(members, "%s\n", who);
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ who = pair->value;
+ g_string_append_printf(members, "%s\n", who);
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_conference_invite "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 51: /* This user is being invited to the conference. Comes with status = 11, so we wont reach here */
break;
case 52: /* Invited users. Assuming us invited, since we got this packet */
break; /* break needed, or else we add the users to the conference before they accept the invitation */
case 53: /* members who have already joined the conference */
- g_string_append_printf(members, "%s\n", pair->value);
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ g_string_append_printf(members, "%s\n", pair->value);
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_conference_invite "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 58:
g_free(msg);
@@ -220,7 +230,12 @@
room = yahoo_string_decode(gc, pair->value, FALSE);
break;
case 54:
- who = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ who = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_conference_decline "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 14:
g_free(msg);
@@ -278,7 +293,12 @@
room = yahoo_string_decode(gc, pair->value, FALSE);
break;
case 53:
- who = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ who = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_conference_logon "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
}
}
@@ -310,7 +330,12 @@
room = yahoo_string_decode(gc, pair->value, FALSE);
break;
case 56:
- who = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ who = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_conference_logoff "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
}
}
@@ -341,7 +366,12 @@
room = yahoo_string_decode(gc, pair->value, FALSE);
break;
case 3:
- who = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ who = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_conference_message "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 14:
msg = pair->value;
@@ -533,7 +563,12 @@
info about individual room members, (including us) */
case 109: /* the yahoo id */
- members = g_list_append(members, pair->value);
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ members = g_list_append(members, pair->value);
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_chat_join "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 110: /* age */
break;
@@ -630,8 +665,14 @@
g_free(room);
room = yahoo_string_decode(gc, pair->value, TRUE);
}
- if (pair->key == 109)
- who = pair->value;
+ if (pair->key == 109) {
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ who = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_chat_exit "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
+ }
}
if (who && room) {
@@ -664,10 +705,20 @@
room = yahoo_string_decode(gc, pair->value, TRUE);
break;
case 109:
- who = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ who = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_chat_message "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 117:
- msg = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ msg = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_chat_message "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 124:
msgtype = strtol(pair->value, NULL, 10);
@@ -730,7 +781,12 @@
msg = yahoo_string_decode(gc, pair->value, FALSE);
break;
case 119:
- who = pair->value;
+ if (g_utf8_validate(pair->value, -1, NULL)) {
+ who = pair->value;
+ } else {
+ purple_debug_warning("yahoo", "yahoo_process_chat_addinvite "
+ "got non-UTF-8 string for key %d\n", pair->key);
+ }
break;
case 118: /* us */
break;
--- a/libpurple/proxy.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/proxy.c Mon Jan 20 00:02:17 2014 -0800
@@ -994,22 +994,34 @@
p = g_strrstr((const gchar *)connect_data->read_buffer, "Content-Length: ");
if (p != NULL) {
gchar *tmp;
- int len = 0;
+ gsize content_len;
char tmpc;
+
p += strlen("Content-Length: ");
tmp = strchr(p, '\r');
if(tmp)
*tmp = '\0';
- len = atoi(p);
+ if (sscanf(p, "%" G_GSIZE_FORMAT, &content_len) != 1) {
+ /* Couldn't read content length */
+ purple_debug_error("proxy", "Couldn't read content length value "
+ "from %s\n", p);
+ if(tmp)
+ *tmp = '\r';
+ purple_proxy_connect_data_disconnect_formatted(connect_data,
+ _("Unable to parse response from HTTP proxy: %s"),
+ connect_data->read_buffer);
+ return;
+ }
if(tmp)
*tmp = '\r';
/* Compensate for what has already been read */
- len -= connect_data->read_len - headers_len;
+ content_len -= connect_data->read_len - headers_len;
/* I'm assuming that we're doing this to prevent the server from
complaining / breaking since we don't read the whole page */
- while (len--) {
+ while (content_len--) {
/* TODO: deal with EAGAIN (and other errors) better */
+ /* TODO: Reading 1 byte at a time is horrible and stupid. */
if (read(connect_data->fd, &tmpc, 1) < 0 && errno != EAGAIN)
break;
}
--- a/libpurple/server.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/server.c Mon Jan 20 00:02:17 2014 -0800
@@ -553,6 +553,14 @@
account = purple_connection_get_account(gc);
+ if (mtime < 0) {
+ purple_debug_error("server",
+ "serv_got_im ignoring negative timestamp\n");
+ /* TODO: Would be more appropriate to use a value that indicates
+ that the timestamp is unknown, and surface that in the UI. */
+ mtime = time(NULL);
+ }
+
/*
* XXX: Should we be setting this here, or relying on prpls to set it?
*/
@@ -879,6 +887,14 @@
g_return_if_fail(who != NULL);
g_return_if_fail(message != NULL);
+ if (mtime < 0) {
+ purple_debug_error("server",
+ "serv_got_chat_in ignoring negative timestamp\n");
+ /* TODO: Would be more appropriate to use a value that indicates
+ that the timestamp is unknown, and surface that in the UI. */
+ mtime = time(NULL);
+ }
+
for (bcs = purple_connection_get_active_chats(g); bcs != NULL; bcs = bcs->next) {
if (purple_chat_conversation_get_id(
PURPLE_CHAT_CONVERSATION(bcs->data)) == id) {
--- a/libpurple/util.c Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/util.c Mon Jan 20 00:02:17 2014 -0800
@@ -3650,24 +3650,26 @@
return ret;
}
-const char *
-purple_strcasestr(const char *haystack, const char *needle)
+/** TODO: Expose this when we can add API */
+static const char *
+purple_strcasestr_len(const char *haystack, gssize hlen, const char *needle, gssize nlen)
{
- size_t hlen, nlen;
const char *tmp, *ret;
g_return_val_if_fail(haystack != NULL, NULL);
g_return_val_if_fail(needle != NULL, NULL);
- hlen = strlen(haystack);
- nlen = strlen(needle);
+ if (hlen == -1)
+ hlen = strlen(haystack);
+ if (nlen == -1)
+ nlen = strlen(needle);
tmp = haystack,
ret = NULL;
g_return_val_if_fail(hlen > 0, NULL);
g_return_val_if_fail(nlen > 0, NULL);
- while (*tmp && !ret) {
+ while (*tmp && !ret && (hlen - (tmp - haystack)) >= nlen) {
if (!g_ascii_strncasecmp(needle, tmp, nlen))
ret = tmp;
else
@@ -3677,6 +3679,12 @@
return ret;
}
+const char *
+purple_strcasestr(const char *haystack, const char *needle)
+{
+ return purple_strcasestr_len(haystack, -1, needle, -1);
+}
+
char *
purple_str_size_to_units(goffset size)
{
--- a/libpurple/win32/global.mak Mon Jan 20 07:39:26 2014 +0530
+++ b/libpurple/win32/global.mak Mon Jan 20 00:02:17 2014 -0800
@@ -19,7 +19,7 @@
JSON_GLIB_TOP ?= $(WIN32_DEV_TOP)/json-glib-0.14
LIBXML2_TOP ?= $(WIN32_DEV_TOP)/libxml2-2.9
MEANWHILE_TOP ?= $(WIN32_DEV_TOP)/meanwhile-1.0
-NSS_TOP ?= $(WIN32_DEV_TOP)/nss-3.14
+NSS_TOP ?= $(WIN32_DEV_TOP)/nss-3.15.4-nspr-4.10.2
PERL_LIB_TOP ?= $(WIN32_DEV_TOP)/perl-5.10
SILC_TOOLKIT ?= $(WIN32_DEV_TOP)/silc-toolkit-1.1
TCL_LIB_TOP ?= $(WIN32_DEV_TOP)/tcl-8.5
--- a/pidgin/gtkimhtml.c Mon Jan 20 07:39:26 2014 +0530
+++ b/pidgin/gtkimhtml.c Mon Jan 20 00:02:17 2014 -0800
@@ -558,7 +558,13 @@
g_return_val_if_fail(GTK_IS_IMHTML(imhtml), FALSE);
- layout = gtk_widget_create_pango_layout(imhtml->tip_window, imhtml->tip);
+ /* We set the text in a separate function call so we can specify a
+ max length. This is important so the tooltip isn't too wide for
+ the screen, and also because some X library function exits the
+ process when it can't allocate enough memory for a super wide
+ tooltip. */
+ layout = gtk_widget_create_pango_layout(imhtml->tip_window, NULL);
+ pango_layout_set_text(layout, imhtml->tip, 200);
style = gtk_widget_get_style(imhtml->tip_window);
#if GTK_CHECK_VERSION(3,0,0)
@@ -627,7 +633,15 @@
#endif
gtk_widget_ensure_style (imhtml->tip_window);
- layout = gtk_widget_create_pango_layout(imhtml->tip_window, imhtml->tip);
+
+ /* We set the text in a separate function call so we can specify a
+ max length. This is important so the tooltip isn't too wide for
+ the screen, and also because some X library function exits the
+ process when it can't allocate enough memory for a super wide
+ tooltip. */
+ layout = gtk_widget_create_pango_layout(imhtml->tip_window, NULL);
+ pango_layout_set_text(layout, imhtml->tip, 200);
+
font = pango_context_load_font(pango_layout_get_context(layout),
style->font_desc);
--- a/pidgin/gtknotify.c Mon Jan 20 07:39:26 2014 +0530
+++ b/pidgin/gtknotify.c Mon Jan 20 00:02:17 2014 -0800
@@ -1246,51 +1246,85 @@
}
#ifndef _WIN32
-static gint
-uri_command(const char *command, gboolean sync)
+static gboolean
+uri_command(GSList *arg_list, gboolean sync)
{
gchar *tmp;
GError *error = NULL;
- gint ret = 0;
+ GSList *it;
+ gchar **argv;
+ gint argc, i;
+ gchar *program;
- purple_debug_misc("gtknotify", "Executing %s\n", command);
+ g_return_val_if_fail(arg_list != NULL, FALSE);
- if (!purple_program_is_valid(command))
- {
- tmp = g_strdup_printf(_("The browser command \"%s\" is invalid."),
- command ? command : "(none)");
+ program = arg_list->data;
+ purple_debug_misc("gtknotify", "Executing %s (%s)\n", program,
+ sync ? "sync" : "async");
+
+ if (!purple_program_is_valid(program)) {
+ purple_debug_error("gtknotify", "Command \"%s\" is invalid\n",
+ program);
+ tmp = g_strdup_printf(
+ _("The browser command \"%s\" is invalid."),
+ program ? program : "(null)");
purple_notify_error(NULL, NULL, _("Unable to open URL"), tmp, NULL);
g_free(tmp);
- }
- else if (sync)
- {
- gint status;
-
- if (!g_spawn_command_line_sync(command, NULL, NULL, &status, &error))
- {
- tmp = g_strdup_printf(_("Error launching \"%s\": %s"),
- command, error->message);
- purple_notify_error(NULL, NULL, _("Unable to open URL"), tmp, NULL);
- g_free(tmp);
- g_error_free(error);
- }
- else
- ret = status;
- }
- else
- {
- if (!g_spawn_command_line_async(command, &error))
- {
- tmp = g_strdup_printf(_("Error launching \"%s\": %s"),
- command, error->message);
- purple_notify_error(NULL, NULL, _("Unable to open URL"), tmp, NULL);
- g_free(tmp);
- g_error_free(error);
- }
+ return FALSE;
}
- return ret;
+ argc = g_slist_length(arg_list);
+ argv = g_new(gchar*, argc + 1);
+ i = 0;
+ for (it = arg_list; it; it = g_slist_next(it)) {
+ if (purple_debug_is_verbose()) {
+ purple_debug_misc("gtknotify", "argv[%d] = \"%s\"\n",
+ i, (gchar*)it->data);
+ }
+ argv[i++] = it->data;
+ }
+ argv[i] = NULL;
+
+ if (sync) {
+ gint exit_status = 0;
+
+ if (g_spawn_sync(NULL, argv, NULL, G_SPAWN_SEARCH_PATH |
+ G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
+ NULL, NULL, NULL, NULL, &exit_status, &error) &&
+ exit_status == 0)
+ {
+ g_free(argv);
+ return TRUE;
+ }
+
+ purple_debug_error("gtknotify",
+ "Error launching \"%s\": %s (status: %d)\n", program,
+ error ? error->message : "(null)", exit_status);
+ tmp = g_strdup_printf(_("Error launching \"%s\": %s"), program,
+ error ? error->message : "(null)");
+ g_error_free(error);
+ purple_notify_error(NULL, NULL, _("Unable to open URL"), tmp, NULL);
+ g_free(tmp);
+
+ g_free(argv);
+ return FALSE;
+ }
+
+ if (g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH |
+ G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, NULL,
+ NULL, NULL, &error))
+ {
+ g_free(argv);
+ return TRUE;
+ }
+
+ purple_debug_warning("gtknotify", "Error launching \"%s\": %s\n",
+ program, error ? error->message : "(null)");
+ g_error_free(error);
+
+ g_free(argv);
+ return FALSE;
}
#endif /* _WIN32 */
@@ -1298,160 +1332,196 @@
pidgin_notify_uri(const char *uri)
{
#ifndef _WIN32
- char *escaped = g_shell_quote(uri);
- char *command = NULL;
- char *remote_command = NULL;
const char *web_browser;
int place;
+ gchar *uri_escaped, *uri_custom = NULL;
+ GSList *argv = NULL, *argv_remote = NULL;
+ gchar **usercmd_argv = NULL;
- web_browser = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/browsers/browser");
+ /* Replace some special characters like $ with their percent-encoded
+ value. This shouldn't be necessary because we shell-escape the entire
+ arg before exec'ing the browser, however, we had a report that a URL
+ containing $(xterm) was causing xterm to start on his system. This is
+ obviously a bug on his system, but it's pretty easy for us to protect
+ against it. */
+ uri_escaped = g_uri_escape_string(uri, ":;/%#,+?=&@", FALSE);
+
+ web_browser = purple_prefs_get_string(PIDGIN_PREFS_ROOT
+ "/browsers/browser");
place = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/browsers/place");
/* if they are running gnome, use the gnome web browser */
- if (purple_running_gnome() == TRUE)
- {
+ if (purple_running_gnome() == TRUE) {
char *tmp = g_find_program_in_path("xdg-open");
if (tmp == NULL)
- command = g_strdup_printf("gnome-open %s", escaped);
+ argv = g_slist_append(argv, "gnome-open");
else
- command = g_strdup_printf("xdg-open %s", escaped);
+ argv = g_slist_append(argv, "xdg-open");
g_free(tmp);
- }
- else if (purple_running_osx() == TRUE)
- {
- command = g_strdup_printf("open %s", escaped);
- }
- else if (!strcmp(web_browser, "epiphany") ||
+ argv = g_slist_append(argv, uri_escaped);
+ } else if (purple_running_osx() == TRUE) {
+ argv = g_slist_append(argv, "open");
+ argv = g_slist_append(argv, uri_escaped);
+ } else if (!strcmp(web_browser, "epiphany") ||
!strcmp(web_browser, "galeon"))
{
+ argv = g_slist_append(argv, (gpointer)web_browser);
+
if (place == PIDGIN_BROWSER_NEW_WINDOW)
- command = g_strdup_printf("%s -w %s", web_browser, escaped);
+ argv = g_slist_append(argv, "-w");
else if (place == PIDGIN_BROWSER_NEW_TAB)
- command = g_strdup_printf("%s -n %s", web_browser, escaped);
- else
- command = g_strdup_printf("%s %s", web_browser, escaped);
- }
- else if (!strcmp(web_browser, "xdg-open"))
- {
- command = g_strdup_printf("xdg-open %s", escaped);
- }
- else if (!strcmp(web_browser, "gnome-open"))
- {
- command = g_strdup_printf("gnome-open %s", escaped);
- }
- else if (!strcmp(web_browser, "kfmclient"))
- {
- command = g_strdup_printf("kfmclient openURL %s", escaped);
+ argv = g_slist_append(argv, "-n");
+
+ argv = g_slist_append(argv, uri_escaped);
+ } else if (!strcmp(web_browser, "xdg-open")) {
+ argv = g_slist_append(argv, "xdg-open");
+ argv = g_slist_append(argv, uri_escaped);
+ } else if (!strcmp(web_browser, "gnome-open")) {
+ argv = g_slist_append(argv, "gnome-open");
+ argv = g_slist_append(argv, uri_escaped);
+ } else if (!strcmp(web_browser, "kfmclient")) {
+ argv = g_slist_append(argv, "kfmclient");
+ argv = g_slist_append(argv, "openURL");
+ argv = g_slist_append(argv, uri_escaped);
/*
* Does Konqueror have options to open in new tab
* and/or current window?
*/
- }
- else if (!strcmp(web_browser, "mozilla") ||
- !strcmp(web_browser, "mozilla-firebird") ||
- !strcmp(web_browser, "firefox") ||
- !strcmp(web_browser, "seamonkey"))
+ } else if (!strcmp(web_browser, "mozilla") ||
+ !strcmp(web_browser, "mozilla-firebird") ||
+ !strcmp(web_browser, "firefox") ||
+ !strcmp(web_browser, "seamonkey"))
{
- char *args = "";
+ argv = g_slist_append(argv, (gpointer)web_browser);
+ argv = g_slist_append(argv, uri_escaped);
- command = g_strdup_printf("%s %s", web_browser, escaped);
+ g_assert(uri_custom == NULL);
+ if (place == PIDGIN_BROWSER_NEW_WINDOW) {
+ uri_custom = g_strdup_printf("openURL(%s,new-window)",
+ uri_escaped);
+ } else if (place == PIDGIN_BROWSER_NEW_TAB) {
+ uri_custom = g_strdup_printf("openURL(%s,new-tab)",
+ uri_escaped);
+ }
- /*
- * Firefox 0.9 and higher require a "-a firefox" option when
- * using -remote commands. This breaks older versions of
- * mozilla. So we include this other handly little string
- * when calling firefox. If the API for remote calls changes
- * any more in firefox then firefox should probably be split
- * apart from mozilla-firebird and mozilla... but this is good
- * for now.
- */
- if (!strcmp(web_browser, "firefox"))
- args = "-a firefox";
+ if (uri_custom != NULL) {
+ argv_remote = g_slist_append(argv_remote,
+ (gpointer)web_browser);
+
+ /* Firefox 0.9 and higher require a "-a firefox" option
+ * when using -remote commands. This breaks older
+ * versions of mozilla. So we include this other handly
+ * little string when calling firefox. If the API for
+ * remote calls changes any more in firefox then firefox
+ * should probably be split apart from mozilla-firebird
+ * and mozilla... but this is good for now.
+ */
+ if (!strcmp(web_browser, "firefox")) {
+ argv_remote = g_slist_append(argv_remote, "-a");
+ argv_remote = g_slist_append(argv_remote,
+ "firefox");
+ }
+
+ argv_remote = g_slist_append(argv_remote, "-remote");
+ argv_remote = g_slist_append(argv_remote, uri_custom);
+ }
+ } else if (!strcmp(web_browser, "opera")) {
+ argv = g_slist_append(argv, "opera");
if (place == PIDGIN_BROWSER_NEW_WINDOW)
- remote_command = g_strdup_printf("%s %s -remote "
- "openURL(%s,new-window)",
- web_browser, args, escaped);
+ argv = g_slist_append(argv, "-newwindow");
else if (place == PIDGIN_BROWSER_NEW_TAB)
- remote_command = g_strdup_printf("%s %s -remote "
- "openURL(%s,new-tab)",
- web_browser, args, escaped);
- }
- else if (!strcmp(web_browser, "opera"))
- {
- if (place == PIDGIN_BROWSER_NEW_WINDOW)
- command = g_strdup_printf("opera -newwindow %s", escaped);
- else if (place == PIDGIN_BROWSER_NEW_TAB)
- command = g_strdup_printf("opera -newpage %s", escaped);
- else
- command = g_strdup_printf("opera %s", escaped);
+ argv = g_slist_append(argv, "-newpage");
+ /* `opera -remote "openURL(%s)"` command causes Pidgin to hang,
+ * if there is no Opera instance running.
+ */
- }
- else if (!strcmp(web_browser, "google-chrome"))
- {
- /* Google Chrome doesn't have command-line arguments that control the
- * opening of links from external calls. This is controlled solely from
- * a preference within Google Chrome. */
- command = g_strdup_printf("google-chrome %s", escaped);
- }
- else if (!strcmp(web_browser, "chrome"))
- {
+ argv = g_slist_append(argv, uri_escaped);
+ } else if (!strcmp(web_browser, "google-chrome")) {
+ /* Google Chrome doesn't have command-line arguments that
+ * control the opening of links from external calls. This is
+ * controlled solely from a preference within Google Chrome.
+ */
+ argv = g_slist_append(argv, "google-chrome");
+ argv = g_slist_append(argv, uri_escaped);
+ } else if (!strcmp(web_browser, "chrome")) {
+ /* Chromium doesn't have command-line arguments that control
+ * the opening of links from external calls. This is controlled
+ * solely from a preference within Chromium.
+ */
+ argv = g_slist_append(argv, "chrome");
+ argv = g_slist_append(argv, uri_escaped);
+ } else if (!strcmp(web_browser, "chromium-browser")) {
/* Chromium doesn't have command-line arguments that control the
- * opening of links from external calls. This is controlled solely from
- * a preference within Chromium. */
- command = g_strdup_printf("chrome %s", escaped);
- }
- else if (!strcmp(web_browser, "chromium-browser"))
- {
- /* Chromium doesn't have command-line arguments that control the
- * opening of links from external calls. This is controlled solely from
- * a preference within Chromium. */
- command = g_strdup_printf("chromium-browser %s", escaped);
- }
- else if (!strcmp(web_browser, "custom"))
- {
- const char *web_command;
+ * opening of links from external calls. This is controlled
+ * solely from a preference within Chromium.
+ */
+ argv = g_slist_append(argv, "chromium-browser");
+ argv = g_slist_append(argv, uri_escaped);
+ } else if (!strcmp(web_browser, "custom")) {
+ GError *error = NULL;
+ const char *usercmd_command;
+ gint usercmd_argc, i;
+ gboolean uri_added = FALSE;
- web_command = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/browsers/manual_command");
+ usercmd_command = purple_prefs_get_string(PIDGIN_PREFS_ROOT
+ "/browsers/manual_command");
- if (web_command == NULL || *web_command == '\0')
- {
+ if (usercmd_command == NULL || *usercmd_command == '\0') {
purple_notify_error(NULL, NULL, _("Unable to open URL"),
_("The 'Manual' browser command has been "
"chosen, but no command has been set."), NULL);
+ g_free(uri_escaped);
+ return NULL;
+ }
+
+ if (!g_shell_parse_argv(usercmd_command, &usercmd_argc,
+ &usercmd_argv, &error))
+ {
+ purple_notify_error(NULL, NULL, _("Unable to open URL: "
+ "the 'Manual' browser command seems invalid."),
+ error ? error->message : NULL, NULL);
+ g_error_free(error);
+ g_free(uri_escaped);
return NULL;
}
- if (strstr(web_command, "%s"))
- command = purple_strreplace(web_command, "%s", escaped);
- else
- {
- /*
- * There is no "%s" in the browser command. Assume the user
- * wanted the URL tacked on to the end of the command.
- */
- command = g_strdup_printf("%s %s", web_command, escaped);
+ for (i = 0; i < usercmd_argc; i++) {
+ gchar *cmd_part = usercmd_argv[i];
+
+ if (uri_added || strstr(cmd_part, "%s") == NULL) {
+ argv = g_slist_append(argv, cmd_part);
+ continue;
+ }
+
+ uri_custom = purple_strreplace(cmd_part, "%s",
+ uri_escaped);
+ argv = g_slist_append(argv, uri_custom);
+ uri_added = TRUE;
}
+
+ /* There is no "%s" in the browser command. Assume the user
+ * wanted the URL tacked on to the end of the command.
+ */
+ if (!uri_added)
+ argv = g_slist_append(argv, uri_escaped);
}
- g_free(escaped);
-
- if (remote_command != NULL)
- {
+ if (argv_remote != NULL) {
/* try the remote command first */
- if (uri_command(remote_command, TRUE) != 0)
- uri_command(command, FALSE);
+ if (!uri_command(argv_remote, TRUE))
+ uri_command(argv, FALSE);
+ } else
+ uri_command(argv, FALSE);
- g_free(remote_command);
-
- }
- else
- uri_command(command, FALSE);
-
- g_free(command);
+ g_strfreev(usercmd_argv);
+ g_free(uri_escaped);
+ g_free(uri_custom);
+ g_slist_free(argv);
+ g_slist_free(argv_remote);
#else /* !_WIN32 */
- winpidgin_notify_uri(uri);
+ winpidgin_notify_uri(uri_escaped);
#endif /* !_WIN32 */
return NULL;
--- a/pidgin/gtkutils.c Mon Jan 20 07:39:26 2014 +0530
+++ b/pidgin/gtkutils.c Mon Jan 20 00:02:17 2014 -0800
@@ -3220,33 +3220,28 @@
return TRUE;
}
+/**
+ * @param filename The path to a file. Specifically this is the link target
+ * from a link in an IM window with the leading "file://" removed.
+ */
static void
-file_open_uri(GtkWebView *webview, const char *uri)
+open_file(GtkWebView *webview, const char *filename)
{
/* Copied from gtkft.c:open_button_cb */
#ifdef _WIN32
/* If using Win32... */
int code;
- if (purple_str_has_prefix(uri, "file://"))
- {
- gchar *escaped = g_shell_quote(uri);
- gchar *param = g_strconcat("/select,\"", uri, "\"", NULL);
- wchar_t *wc_param = g_utf8_to_utf16(param, -1, NULL, NULL, NULL);
-
- code = (int)ShellExecuteW(NULL, L"OPEN", L"explorer.exe", wc_param, NULL, SW_NORMAL);
-
- g_free(wc_param);
- g_free(param);
- g_free(escaped);
- } else {
- wchar_t *wc_filename = g_utf8_to_utf16(
- uri, -1, NULL, NULL, NULL);
-
- code = (int)ShellExecuteW(NULL, NULL, wc_filename, NULL, NULL,
- SW_SHOW);
-
- g_free(wc_filename);
- }
+ /* Escape URI by replacing double-quote with 2 double-quotes. */
+ gchar *escaped = purple_strreplace(filename, "\"", "\"\"");
+ gchar *param = g_strconcat("/select,\"", escaped, "\"", NULL);
+ wchar_t *wc_param = g_utf8_to_utf16(param, -1, NULL, NULL, NULL);
+
+ /* TODO: Better to use SHOpenFolderAndSelectItems()? */
+ code = (int)ShellExecuteW(NULL, L"OPEN", L"explorer.exe", wc_param, NULL, SW_NORMAL);
+
+ g_free(wc_param);
+ g_free(param);
+ g_free(escaped);
if (code == SE_ERR_ASSOCINCOMPLETE || code == SE_ERR_NOASSOC)
{
@@ -3258,7 +3253,8 @@
{
purple_notify_error(webview, NULL,
_("An error occurred while opening the file."), NULL, NULL);
- purple_debug_warning("gtkutils", "filename: %s; code: %d\n", uri, code);
+ purple_debug_warning("gtkutils", "filename: %s; code: %d\n",
+ filename, code);
}
#else
char *command = NULL;
@@ -3267,15 +3263,15 @@
if (purple_running_gnome())
{
- char *escaped = g_shell_quote(uri);
+ char *escaped = g_shell_quote(filename);
command = g_strdup_printf("gnome-open %s", escaped);
g_free(escaped);
}
else if (purple_running_kde())
{
- char *escaped = g_shell_quote(uri);
-
- if (purple_str_has_suffix(uri, ".desktop"))
+ char *escaped = g_shell_quote(filename);
+
+ if (purple_str_has_suffix(filename, ".desktop"))
command = g_strdup_printf("kfmclient openURL %s 'text/plain'", escaped);
else
command = g_strdup_printf("kfmclient openURL %s", escaped);
@@ -3283,7 +3279,7 @@
}
else
{
- purple_notify_uri(NULL, uri);
+ purple_notify_uri(NULL, filename);
return;
}
@@ -3293,7 +3289,7 @@
if (!g_spawn_command_line_sync(command, NULL, NULL, &exit_status, &error))
{
tmp = g_strdup_printf(_("Error launching %s: %s"),
- uri, error->message);
+ filename, error->message);
purple_notify_error(webview, NULL, _("Unable to open file."), tmp, NULL);
g_free(tmp);
g_error_free(error);
@@ -3314,7 +3310,8 @@
static gboolean
file_clicked_cb(GtkWebView *webview, const char *uri)
{
- file_open_uri(webview, uri + FILELINKSIZE);
+ /* Strip "file://" from the URI. */
+ open_file(webview, uri + FILELINKSIZE);
return TRUE;
}
@@ -3322,7 +3319,7 @@
open_containing_cb(GtkWebView *webview, const char *uri)
{
char *dir = g_path_get_dirname(uri + FILELINKSIZE);
- file_open_uri(webview, dir);
+ open_file(webview, dir);
g_free(dir);
return TRUE;
}
--- a/share/ca-certs/CAcert_Class3.pem Mon Jan 20 07:39:26 2014 +0530
+++ b/share/ca-certs/CAcert_Class3.pem Mon Jan 20 00:02:17 2014 -0800
@@ -1,35 +1,42 @@
-----BEGIN CERTIFICATE-----
-MIIGCDCCA/CgAwIBAgIBATANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290
-IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB
-IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA
-Y2FjZXJ0Lm9yZzAeFw0wNTEwMTQwNzM2NTVaFw0zMzAzMjgwNzM2NTVaMFQxFDAS
-BgNVBAoTC0NBY2VydCBJbmMuMR4wHAYDVQQLExVodHRwOi8vd3d3LkNBY2VydC5v
-cmcxHDAaBgNVBAMTE0NBY2VydCBDbGFzcyAzIFJvb3QwggIiMA0GCSqGSIb3DQEB
-AQUAA4ICDwAwggIKAoICAQCrSTURSHzSJn5TlM9Dqd0o10Iqi/OHeBlYfA+e2ol9
-4fvrcpANdKGWZKufoCSZc9riVXbHF3v1BKxGuMO+f2SNEGwk82GcwPKQ+lHm9WkB
-Y8MPVuJKQs/iRIwlKKjFeQl9RrmK8+nzNCkIReQcn8uUBByBqBSzmGXEQ+xOgo0J
-0b2qW42S0OzekMV/CsLj6+YxWl50PpczWejDAz1gM7/30W9HxM3uYoNSbi4ImqTZ
-FRiRpoWSR7CuSOtttyHshRpocjWr//AQXcD0lKdq1TuSfkyQBX6TwSyLpI5idBVx
-bgtxA+qvFTia1NIFcm+M+SvrWnIl+TlG43IbPgTDZCciECqKT1inA62+tC4T7V2q
-SNfVfdQqe1z6RgRQ5MwOQluM7dvyz/yWk+DbETZUYjQ4jwxgmzuXVjit89Jbi6Bb
-6k6WuHzX1aCGcEDTkSm3ojyt9Yy7zxqSiuQ0e8DYbF/pCsLDpyCaWt8sXVJcukfV
-m+8kKHA4IC/VfynAskEDaJLM4JzMl0tF7zoQCqtwOpiVcK01seqFK6QcgCExqa5g
-eoAmSAC4AcCTY1UikTxW56/bOiXzjzFU6iaLgVn5odFTEcV7nQP2dBHgbbEsPyyG
-kZlxmqZ3izRg0RS0LKydr4wQ05/EavhvE/xzWfdmQnQeiuP43NJvmJzLR5iVQAX7
-6QIDAQABo4G/MIG8MA8GA1UdEwEB/wQFMAMBAf8wXQYIKwYBBQUHAQEEUTBPMCMG
-CCsGAQUFBzABhhdodHRwOi8vb2NzcC5DQWNlcnQub3JnLzAoBggrBgEFBQcwAoYc
-aHR0cDovL3d3dy5DQWNlcnQub3JnL2NhLmNydDBKBgNVHSAEQzBBMD8GCCsGAQQB
-gZBKMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuQ0FjZXJ0Lm9yZy9pbmRleC5w
-aHA/aWQ9MTAwDQYJKoZIhvcNAQEEBQADggIBAH8IiKHaGlBJ2on7oQhy84r3HsQ6
-tHlbIDCxRd7CXdNlafHCXVRUPIVfuXtCkcKZ/RtRm6tGpaEQU55tiKxzbiwzpvD0
-nuB1wT6IRanhZkP+VlrRekF490DaSjrxC1uluxYG5sLnk7mFTZdPsR44Q4Dvmw2M
-77inYACHV30eRBzLI++bPJmdr7UpHEV5FpZNJ23xHGzDwlVks7wU4vOkHx4y/CcV
-Bc/dLq4+gmF78CEQGPZE6lM5+dzQmiDgxrvgu1pPxJnIB721vaLbLmINQjRBvP+L
-ivVRIqqIMADisNS8vmW61QNXeZvo3MhN+FDtkaVSKKKs+zZYPumUK5FQhxvWXtaM
-zPcPEAxSTtAWYeXlCmy/F8dyRlecmPVsYGN6b165Ti/Iubm7aoW8mA3t+T6XhDSU
-rgCvoeXnkm5OvfPi2RSLXNLrAWygF6UtEOucekq9ve7O/e0iQKtwOIj1CodqwqsF
-YMlIBdpTwd5Ed2qz8zw87YC8pjhKKSRf/lk7myV6VmMAZLldpGJ9VzZPrYPvH5JT
-oI53V93lYRE9IwCQTDz6o2CTBKOvNfYOao9PSmCnhQVsRqGP9Md246FZV/dxssRu
-FFxtbUFm3xuTsdQAw+7Lzzw9IYCpX2Nl/N3gX6T0K/CFcUHUZyX7GrGXrtaZghNB
-0m6lG5kngOcLqagA
+MIIHWTCCBUGgAwIBAgIDCkGKMA0GCSqGSIb3DQEBCwUAMHkxEDAOBgNVBAoTB1Jv
+b3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAGA1UEAxMZ
+Q0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSc3VwcG9y
+dEBjYWNlcnQub3JnMB4XDTExMDUyMzE3NDgwMloXDTIxMDUyMDE3NDgwMlowVDEU
+MBIGA1UEChMLQ0FjZXJ0IEluYy4xHjAcBgNVBAsTFWh0dHA6Ly93d3cuQ0FjZXJ0
+Lm9yZzEcMBoGA1UEAxMTQ0FjZXJ0IENsYXNzIDMgUm9vdDCCAiIwDQYJKoZIhvcN
+AQEBBQADggIPADCCAgoCggIBAKtJNRFIfNImflOUz0Op3SjXQiqL84d4GVh8D57a
+iX3h++tykA10oZZkq5+gJJlz2uJVdscXe/UErEa4w75/ZI0QbCTzYZzA8pD6Ueb1
+aQFjww9W4kpCz+JEjCUoqMV5CX1GuYrz6fM0KQhF5Byfy5QEHIGoFLOYZcRD7E6C
+jQnRvapbjZLQ7N6QxX8KwuPr5jFaXnQ+lzNZ6MMDPWAzv/fRb0fEze5ig1JuLgia
+pNkVGJGmhZJHsK5I6223IeyFGmhyNav/8BBdwPSUp2rVO5J+TJAFfpPBLIukjmJ0
+FXFuC3ED6q8VOJrU0gVyb4z5K+taciX5OUbjchs+BMNkJyIQKopPWKcDrb60LhPt
+XapI19V91Cp7XPpGBFDkzA5CW4zt2/LP/JaT4NsRNlRiNDiPDGCbO5dWOK3z0luL
+oFvqTpa4fNfVoIZwQNORKbeiPK31jLvPGpKK5DR7wNhsX+kKwsOnIJpa3yxdUly6
+R9Wb7yQocDggL9V/KcCyQQNokszgnMyXS0XvOhAKq3A6mJVwrTWx6oUrpByAITGp
+rmB6gCZIALgBwJNjVSKRPFbnr9s6JfOPMVTqJouBWfmh0VMRxXudA/Z0EeBtsSw/
+LIaRmXGapneLNGDRFLQsrJ2vjBDTn8Rq+G8T/HNZ92ZCdB6K4/jc0m+YnMtHmJVA
+BfvpAgMBAAGjggINMIICCTAdBgNVHQ4EFgQUdahxYEyIE/B42Yl3tW3Fid+8sXow
+gaMGA1UdIwSBmzCBmIAUFrUyG9TH8+DmjvO90rA67rI5GNGhfaR7MHkxEDAOBgNV
+BAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAG
+A1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS
+c3VwcG9ydEBjYWNlcnQub3JnggEAMA8GA1UdEwEB/wQFMAMBAf8wXQYIKwYBBQUH
+AQEEUTBPMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5DQWNlcnQub3JnLzAoBggr
+BgEFBQcwAoYcaHR0cDovL3d3dy5DQWNlcnQub3JnL2NhLmNydDBKBgNVHSAEQzBB
+MD8GCCsGAQQBgZBKMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuQ0FjZXJ0Lm9y
+Zy9pbmRleC5waHA/aWQ9MTAwNAYJYIZIAYb4QgEIBCcWJWh0dHA6Ly93d3cuQ0Fj
+ZXJ0Lm9yZy9pbmRleC5waHA/aWQ9MTAwUAYJYIZIAYb4QgENBEMWQVRvIGdldCB5
+b3VyIG93biBjZXJ0aWZpY2F0ZSBmb3IgRlJFRSwgZ28gdG8gaHR0cDovL3d3dy5D
+QWNlcnQub3JnMA0GCSqGSIb3DQEBCwUAA4ICAQApKIWuRKm5r6R5E/CooyuXYPNc
+7uMvwfbiZqARrjY3OnYVBFPqQvX56sAV2KaC2eRhrnILKVyQQ+hBsuF32wITRHhH
+Va9Y/MyY9kW50SD42CEH/m2qc9SzxgfpCYXMO/K2viwcJdVxjDm1Luq+GIG6sJO4
+D+Pm1yaMMVpyA4RS5qb1MyJFCsgLDYq4Nm+QCaGrvdfVTi5xotSu+qdUK+s1jVq3
+VIgv7nSf7UgWyg1I0JTTrKSi9iTfkuO960NAkW4cGI5WtIIS86mTn9S8nK2cde5a
+lxuV53QtHA+wLJef+6kzOXrnAzqSjiL2jA3k2X4Ndhj3AfnvlpaiVXPAPHG0HRpW
+Q7fDCo1y/OIQCQtBzoyUoPkD/XFzS4pXM+WOdH4VAQDmzEoc53+VGS3FpQyLu7Xt
+hbNc09+4ufLKxw0BFKxwWMWMjTPUnWajGlCVI/xI4AZDEtnNp4Y5LzZyo4AQ5OHz
+0ctbGsDkgJp8E3MGT9ujayQKurMcvEp4u+XjdTilSKeiHq921F73OIZWWonO1sOn
+ebJSoMbxhbQljPI/lrMQ2Y1sVzufb4Y6GIIiNsiwkTjbKqGTqoQ/9SdlrnPVyNXT
+d+pLncdBu8fA46A/5H2kjXPmEkvfoXNzczqA6NXLji/L6hOn1kGLrPo8idck9U60
+4GGSt/M3mMS+lqO3ig==
-----END CERTIFICATE-----
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/share/ca-certs/Entrust.net_2048.pem Mon Jan 20 00:02:17 2014 -0800
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIEnzCCBAigAwIBAgIERp6RGjANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC
+VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u
+ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc
+KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u
+ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wOTAz
+MjMxNTE4MjdaFw0xOTAzMjMxNTQ4MjdaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5l
+dDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkg
+cmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5u
+ZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBB
+dXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+rU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL
+Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3ed
+Vc3kw37XamSrhRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4
+LeksyZB2ZnuU4q941mVTXTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5
+CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N
+328mz8MYIWJmQ3DW1cAH4QIDAQABo4IBJzCCASMwDgYDVR0PAQH/BAQDAgEGMA8G
+A1UdEwEB/wQFMAMBAf8wMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzABhhdodHRw
+Oi8vb2NzcC5lbnRydXN0Lm5ldDAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3Js
+LmVudHJ1c3QubmV0L3NlcnZlcjEuY3JsMDsGA1UdIAQ0MDIwMAYEVR0gADAoMCYG
+CCsGAQUFBwIBFhpodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NQUzAdBgNVHQ4EFgQU
+VeSB0RGAvtiJuQijMfmhJAkWuXAwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX
+8+1i0BowGQYJKoZIhvZ9B0EABAwwChsEVjcuMQMCAIEwDQYJKoZIhvcNAQEFBQAD
+gYEAj2WiMI4mq4rsNRaY6QPwjRdfvExsAvZ0UuDCxh/O8qYRDKixDk2Ei3E277M1
+RfPB+JbFi1WkzGuDFiAy2r77r5u3n+F+hJ+ePFCnP1zCvouGuAiS7vhCKw0T43aF
+SApKv9ClOwqwVLht4wj5NI0LjosSzBcaM4eVyJ4K3FBTF3s=
+-----END CERTIFICATE-----
--- a/share/ca-certs/Makefile.am Mon Jan 20 07:39:26 2014 +0530
+++ b/share/ca-certs/Makefile.am Mon Jan 20 00:02:17 2014 -0800
@@ -7,12 +7,12 @@
Deutsche_Telekom_Root_CA_2.pem \
DigiCertHighAssuranceEVRootCA.pem \
Entrust.net_Secure_Server_CA.pem \
+ Entrust.net_2048.pem \
Equifax_Secure_CA.pem \
Equifax_Secure_Global_eBusiness_CA-1.pem \
Go_Daddy_Class_2_CA.pem \
GTE_CyberTrust_Global_Root.pem \
StartCom_Certification_Authority.pem \
- StartCom_Free_SSL_CA.pem \
Thawte_Premium_Server_CA.pem \
Thawte_Primary_Root_CA.pem \
ValiCert_Class_2_VA.pem \
@@ -21,6 +21,8 @@
VeriSign_Class_3_Public_Primary_Certification_Authority_-_G5.pem \
VeriSign_Class_3_Public_Primary_Certification_Authority_-_G5_2.pem
+# TODO: Microsoft_Secure_Server_Authority_2010.pem is going to expire
+# on 19-05-2014. After this date, remove it.
EXTRA_CERTS = \
AOL_Member_CA.pem \
DigiCertHighAssuranceCA-3.pem \
--- a/share/ca-certs/StartCom_Free_SSL_CA.pem Mon Jan 20 07:39:26 2014 +0530
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIFFjCCBH+gAwIBAgIBADANBgkqhkiG9w0BAQQFADCBsDELMAkGA1UEBhMCSUwx
-DzANBgNVBAgTBklzcmFlbDEOMAwGA1UEBxMFRWlsYXQxFjAUBgNVBAoTDVN0YXJ0
-Q29tIEx0ZC4xGjAYBgNVBAsTEUNBIEF1dGhvcml0eSBEZXAuMSkwJwYDVQQDEyBG
-cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS
-YWRtaW5Ac3RhcnRjb20ub3JnMB4XDTA1MDMxNzE3Mzc0OFoXDTM1MDMxMDE3Mzc0
-OFowgbAxCzAJBgNVBAYTAklMMQ8wDQYDVQQIEwZJc3JhZWwxDjAMBgNVBAcTBUVp
-bGF0MRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMRowGAYDVQQLExFDQSBBdXRob3Jp
-dHkgRGVwLjEpMCcGA1UEAxMgRnJlZSBTU0wgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
-dHkxITAfBgkqhkiG9w0BCQEWEmFkbWluQHN0YXJ0Y29tLm9yZzCBnzANBgkqhkiG
-9w0BAQEFAAOBjQAwgYkCgYEA7YRgACOeyEpRKSfeOqE5tWmrCbIvNP1h3D3TsM+x
-18LEwrHkllbEvqoUDufMOlDIOmKdw6OsWXuO7lUaHEe+o5c5s7XvIywI6Nivcy+5
-yYPo7QAPyHWlLzRMGOh2iCNJitu27Wjaw7ViKUylS7eYtAkUEKD4/mJ2IhULpNYI
-LzUCAwEAAaOCAjwwggI4MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgHmMB0G
-A1UdDgQWBBQcicOWzL3+MtUNjIExtpidjShkjTCB3QYDVR0jBIHVMIHSgBQcicOW
-zL3+MtUNjIExtpidjShkjaGBtqSBszCBsDELMAkGA1UEBhMCSUwxDzANBgNVBAgT
-BklzcmFlbDEOMAwGA1UEBxMFRWlsYXQxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4x
-GjAYBgNVBAsTEUNBIEF1dGhvcml0eSBEZXAuMSkwJwYDVQQDEyBGcmVlIFNTTCBD
-ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSYWRtaW5Ac3Rh
-cnRjb20ub3JnggEAMB0GA1UdEQQWMBSBEmFkbWluQHN0YXJ0Y29tLm9yZzAdBgNV
-HRIEFjAUgRJhZG1pbkBzdGFydGNvbS5vcmcwEQYJYIZIAYb4QgEBBAQDAgAHMC8G
-CWCGSAGG+EIBDQQiFiBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAy
-BglghkgBhvhCAQQEJRYjaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL2NhLWNybC5j
-cmwwKAYJYIZIAYb4QgECBBsWGWh0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy8wOQYJ
-YIZIAYb4QgEIBCwWKmh0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9pbmRleC5waHA/
-YXBwPTExMTANBgkqhkiG9w0BAQQFAAOBgQBscSXhnjSRIe/bbL0BCFaPiNhBOlP1
-ct8nV0t2hPdopP7rPwl+KLhX6h/BquL/lp9JmeaylXOWxkjHXo0Hclb4g4+fd68p
-00UOpO6wNnQt8M2YI3s3S9r+UZjEHjQ8iP2ZO1CnwYszx8JSFhKVU2Ui77qLzmLb
-cCOxgN8aIDjnfg==
------END CERTIFICATE-----