# HG changeset patch
# User masca@cpw.pidgin.im
# Date 1266335914 0
# Node ID cc6d733a192a1e780ea0ebc4b12a4ecf6514a654
# Parent 5c9c4557fec25b76eabf41ff449a517646c1b6d9# Parent a786d893df2b4e99d464ae4242b1f0b150dfd574
propagate from branch 'im.pidgin.pidgin' (head be77df4826034ac2521177bb6af6b60be3d1b4c4)
to branch 'im.pidgin.cpw.qulogic.msnp16' (head f5a627bac792429540cdc52a086a28cadcbafdb3)
diff -r 5c9c4557fec2 -r cc6d733a192a libpurple/protocols/msn/cmdproc.c
--- a/libpurple/protocols/msn/cmdproc.c Tue Feb 16 15:16:28 2010 +0000
+++ b/libpurple/protocols/msn/cmdproc.c Tue Feb 16 15:58:34 2010 +0000
@@ -243,58 +243,71 @@
msn_cmdproc_process_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
{
MsnMsgTypeCb cb;
- const char *messageId = NULL;
+ const char *message_id = NULL;
/* Multi-part messages */
- if ((messageId = msn_message_get_attr(msg, "Message-ID")) != NULL) {
- const char *chunk_text = msn_message_get_attr(msg, "Chunks");
+ message_id = msn_message_get_header_value(msg, "Message-ID");
+ if (message_id != NULL) {
+ /* This is the first in a series of chunks */
+
+ const char *chunk_text = msn_message_get_header_value(msg, "Chunks");
guint chunk;
if (chunk_text != NULL) {
chunk = strtol(chunk_text, NULL, 10);
- /* 1024 chunks of ~1300 bytes is ~1MB, which seems OK to prevent
+ /* 1024 chunks of ~1300 bytes is ~1MB, which seems OK to prevent
some random client causing pidgin to hog a ton of memory.
Probably should figure out the maximum that the official client
actually supports, though. */
if (chunk > 0 && chunk < 1024) {
msg->total_chunks = chunk;
msg->received_chunks = 1;
- g_hash_table_insert(cmdproc->multiparts, (gpointer)messageId, msn_message_ref(msg));
- purple_debug_info("msn", "Received chunked message, messageId: '%s', total chunks: %d\n",
- messageId, chunk);
+ g_hash_table_insert(cmdproc->multiparts, (gpointer)message_id, msn_message_ref(msg));
+ purple_debug_info("msn", "Received chunked message, message_id: '%s', total chunks: %d\n",
+ message_id, chunk);
} else {
- purple_debug_error("msn", "MessageId '%s' has too many chunks: %d\n", messageId, chunk);
+ purple_debug_error("msn", "MessageId '%s' has too many chunks: %d\n", message_id, chunk);
}
return;
} else {
- chunk_text = msn_message_get_attr(msg, "Chunk");
+ chunk_text = msn_message_get_header_value(msg, "Chunk");
if (chunk_text != NULL) {
- MsnMessage *first = g_hash_table_lookup(cmdproc->multiparts, messageId);
+ /* This is one chunk in a series of chunks */
+
+ MsnMessage *first = g_hash_table_lookup(cmdproc->multiparts, message_id);
chunk = strtol(chunk_text, NULL, 10);
if (first == NULL) {
purple_debug_error("msn",
- "Unable to find first chunk of messageId '%s' to correspond with chunk %d.\n",
- messageId, chunk+1);
- } else if (first->received_chunks == chunk) {
- /* Chunk is from 1 to total-1 (doesn't count first one) */
- purple_debug_info("msn", "Received chunk %d of %d, messageId: '%s'\n",
- chunk+1, first->total_chunks, messageId);
- first->body = g_realloc(first->body, first->body_len + msg->body_len);
- memcpy(first->body + first->body_len, msg->body, msg->body_len);
- first->body_len += msg->body_len;
- first->received_chunks++;
- if (first->received_chunks != first->total_chunks)
- return;
- else
- /* We're done! Send it along... The caller takes care of
- freeing the old one. */
- msg = first;
- } else {
- /* TODO: Can you legitimately receive chunks out of order? */
- g_hash_table_remove(cmdproc->multiparts, messageId);
+ "Unable to find first chunk of message_id '%s' to correspond with chunk %d.\n",
+ message_id, chunk + 1);
+ } else if (first->received_chunks != chunk) {
+ /*
+ * We received an out of order chunk number (i.e. not the
+ * next one in the sequence). Not sure if this can happen
+ * legitimately, but we definitely don't handle it right
+ * now.
+ */
+ g_hash_table_remove(cmdproc->multiparts, message_id);
return;
}
+
+ /* Chunk is from 1 to total-1 (doesn't count first one) */
+ purple_debug_info("msn", "Received chunk %d of %d, message_id: '%s'\n",
+ chunk + 1, first->total_chunks, message_id);
+ first->body = g_realloc(first->body, first->body_len + msg->body_len);
+ memcpy(first->body + first->body_len, msg->body, msg->body_len);
+ first->body_len += msg->body_len;
+ first->received_chunks++;
+ if (first->received_chunks != first->total_chunks)
+ /* We're waiting for more chunks */
+ return;
+
+ /*
+ * We have all the chunks for this message, great! Send
+ * it along... The caller takes care of freeing the old one.
+ */
+ msg = first;
} else {
- purple_debug_error("msn", "Received MessageId '%s' with no chunk number!\n", messageId);
+ purple_debug_error("msn", "Received MessageId '%s' with no chunk number!\n", message_id);
}
}
}
@@ -314,8 +327,8 @@
purple_debug_warning("msn", "Unhandled content-type '%s'\n",
msn_message_get_content_type(msg));
- if (messageId != NULL)
- g_hash_table_remove(cmdproc->multiparts, messageId);
+ if (message_id != NULL)
+ g_hash_table_remove(cmdproc->multiparts, message_id);
}
void
diff -r 5c9c4557fec2 -r cc6d733a192a libpurple/protocols/msn/msg.c
--- a/libpurple/protocols/msn/msg.c Tue Feb 16 15:16:28 2010 +0000
+++ b/libpurple/protocols/msn/msg.c Tue Feb 16 15:58:34 2010 +0000
@@ -36,7 +36,7 @@
if (purple_debug_is_verbose())
purple_debug_info("msn", "message new (%p)(%d)\n", msg, type);
- msg->attr_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+ msg->header_table = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, g_free);
msn_message_ref(msg);
@@ -64,8 +64,8 @@
g_free(msg->content_type);
g_free(msg->charset);
- g_hash_table_destroy(msg->attr_table);
- g_list_free(msg->attr_list);
+ g_hash_table_destroy(msg->header_table);
+ g_list_free(msg->header_list);
g_free(msg);
}
@@ -112,11 +112,11 @@
msg = msn_message_new(MSN_MSG_TEXT);
msg->retries = 1;
- msn_message_set_attr(msg, "User-Agent", PACKAGE_NAME "/" VERSION);
+ msn_message_set_header(msg, "User-Agent", PACKAGE_NAME "/" VERSION);
msn_message_set_content_type(msg, "text/plain");
msn_message_set_charset(msg, "UTF-8");
msn_message_set_flag(msg, 'A');
- msn_message_set_attr(msg, "X-MMS-IM-Format",
+ msn_message_set_header(msg, "X-MMS-IM-Format",
"FN=Segoe%20UI; EF=; CO=0; CS=1;PF=0");
message_cr = purple_str_add_cr(message);
@@ -133,7 +133,7 @@
msg = msn_message_new(MSN_MSG_SLP);
- msn_message_set_attr(msg, "User-Agent", NULL);
+ msn_message_set_header(msg, "User-Agent", NULL);
msg->msnslp_message = TRUE;
@@ -169,7 +169,7 @@
g_return_if_reached();
}
- /* Import the header. */
+ /* Extract the binary SLP header */
memcpy(&header, tmp, sizeof(header));
tmp += sizeof(header);
@@ -183,7 +183,7 @@
msg->msnslp_header.ack_sub_id = GUINT32_FROM_LE(header.ack_sub_id);
msg->msnslp_header.ack_size = GUINT64_FROM_LE(header.ack_size);
- /* Import the body. */
+ /* Extract the body */
body_len = len - (tmp - body);
/* msg->body_len = msg->msnslp_header.length; */
@@ -211,7 +211,7 @@
memcpy(tmp_base, payload, payload_len);
tmp_base[payload_len] = '\0';
- /* Parse the attributes. */
+ /* Find the end of the headers */
end = strstr(tmp, body_dem);
/* TODO? some clients use \r delimiters instead of \r\n, the official client
* doesn't send such messages, but does handle receiving them. We'll just
@@ -222,8 +222,8 @@
}
*end = '\0';
+ /* Split the headers and parse each one */
elems = g_strsplit(tmp, line_dem, 0);
-
for (cur = elems; *cur != NULL; cur++)
{
const char *key, *value;
@@ -240,7 +240,7 @@
if (!strcmp(key, "boundary")) {
char *end = strchr(value, '\"');
*end = '\0';
- msn_message_set_attr(msg, key, value);
+ msn_message_set_header(msg, key, value);
}
g_strfreev(tokens);
@@ -278,12 +278,11 @@
}
else
{
- msn_message_set_attr(msg, key, value);
+ msn_message_set_header(msg, key, value);
}
g_strfreev(tokens);
}
-
g_strfreev(elems);
/* Proceed to the end of the "\r\n\r\n" */
@@ -306,7 +305,7 @@
msg->msnslp_message = TRUE;
- /* Import the header. */
+ /* Extract the binary SLP header */
memcpy(&header, tmp, sizeof(header));
tmp += sizeof(header);
@@ -322,7 +321,7 @@
body_len = payload_len - (tmp - tmp_base) - sizeof(footer);
- /* Import the body. */
+ /* Extract the body */
if (body_len > 0) {
msg->body_len = body_len;
g_free(msg->body);
@@ -332,7 +331,7 @@
tmp += body_len;
}
- /* Import the footer. */
+ /* Extract the footer */
if (body_len >= 0) {
memcpy(&footer, tmp, sizeof(footer));
tmp += sizeof(footer);
@@ -348,7 +347,7 @@
memcpy(msg->body, tmp, msg->body_len);
msg->body[msg->body_len] = '\0';
}
-
+
if ((!content_type || !strcmp(content_type, "text/plain"))
&& msg->charset == NULL) {
char *body = g_convert(msg->body, msg->body_len, "UTF-8",
@@ -454,13 +453,13 @@
n += strlen(n);
- for (l = msg->attr_list; l != NULL; l = l->next)
+ for (l = msg->header_list; l != NULL; l = l->next)
{
const char *key;
const char *value;
key = l->data;
- value = msn_message_get_attr(msg, key);
+ value = msn_message_get_header_value(msg, key);
g_snprintf(n, end - n, "%s: %s\r\n", key, value);
n += strlen(n);
@@ -610,15 +609,15 @@
}
void
-msn_message_set_attr(MsnMessage *msg, const char *attr, const char *value)
+msn_message_set_header(MsnMessage *msg, const char *name, const char *value)
{
const char *temp;
- char *new_attr;
+ char *new_name;
g_return_if_fail(msg != NULL);
- g_return_if_fail(attr != NULL);
+ g_return_if_fail(name != NULL);
- temp = msn_message_get_attr(msg, attr);
+ temp = msn_message_get_header_value(msg, name);
if (value == NULL)
{
@@ -626,37 +625,37 @@
{
GList *l;
- for (l = msg->attr_list; l != NULL; l = l->next)
+ for (l = msg->header_list; l != NULL; l = l->next)
{
- if (!g_ascii_strcasecmp(l->data, attr))
+ if (!g_ascii_strcasecmp(l->data, name))
{
- msg->attr_list = g_list_remove(msg->attr_list, l->data);
+ msg->header_list = g_list_remove(msg->header_list, l->data);
break;
}
}
- g_hash_table_remove(msg->attr_table, attr);
+ g_hash_table_remove(msg->header_table, name);
}
return;
}
- new_attr = g_strdup(attr);
+ new_name = g_strdup(name);
- g_hash_table_insert(msg->attr_table, new_attr, g_strdup(value));
+ g_hash_table_insert(msg->header_table, new_name, g_strdup(value));
if (temp == NULL)
- msg->attr_list = g_list_append(msg->attr_list, new_attr);
+ msg->header_list = g_list_append(msg->header_list, new_name);
}
const char *
-msn_message_get_attr(const MsnMessage *msg, const char *attr)
+msn_message_get_header_value(const MsnMessage *msg, const char *name)
{
g_return_val_if_fail(msg != NULL, NULL);
- g_return_val_if_fail(attr != NULL, NULL);
+ g_return_val_if_fail(name != NULL, NULL);
- return g_hash_table_lookup(msg->attr_table, attr);
+ return g_hash_table_lookup(msg->header_table, name);
}
GHashTable *
@@ -741,13 +740,13 @@
msg->content_type, msg->charset);
}
- for (l = msg->attr_list; l; l = l->next)
+ for (l = msg->header_list; l; l = l->next)
{
char *key;
const char *value;
key = l->data;
- value = msn_message_get_attr(msg, key);
+ value = msn_message_get_header_value(msg, key);
g_string_append_printf(str, "%s: %s\r\n", key, value);
}
@@ -817,7 +816,6 @@
{
PurpleConnection *gc;
const char *body;
- char *body_str;
char *body_enc;
char *body_final;
size_t body_len;
@@ -827,9 +825,7 @@
gc = cmdproc->session->account->gc;
body = msn_message_get_bin_data(msg, &body_len);
- body_str = g_strndup(body, body_len);
- body_enc = g_markup_escape_text(body_str, -1);
- g_free(body_str);
+ body_enc = g_markup_escape_text(body, body_len);
passport = msg->remote_user;
@@ -840,13 +836,13 @@
}
#if 0
- if ((value = msn_message_get_attr(msg, "User-Agent")) != NULL)
+ if ((value = msn_message_get_header_value(msg, "User-Agent")) != NULL)
{
purple_debug_misc("msn", "User-Agent = '%s'\n", value);
}
#endif
- if ((value = msn_message_get_attr(msg, "X-MMS-IM-Format")) != NULL)
+ if ((value = msn_message_get_header_value(msg, "X-MMS-IM-Format")) != NULL)
{
char *pre, *post;
@@ -914,7 +910,7 @@
gc = cmdproc->session->account->gc;
passport = msg->remote_user;
- if (msn_message_get_attr(msg, "TypingUser") == NULL)
+ if (msn_message_get_header_value(msg, "TypingUser") == NULL)
return;
if (cmdproc->servconn->type == MSN_SERVCONN_SB) {
diff -r 5c9c4557fec2 -r cc6d733a192a libpurple/protocols/msn/msg.h
--- a/libpurple/protocols/msn/msg.h Tue Feb 16 15:16:28 2010 +0000
+++ b/libpurple/protocols/msn/msg.h Tue Feb 16 15:58:34 2010 +0000
@@ -109,8 +109,8 @@
MsnSlpHeader msnslp_header;
MsnSlpFooter msnslp_footer;
- GHashTable *attr_table;
- GList *attr_list;
+ GHashTable *header_table;
+ GList *header_list;
gboolean ack_ref; /**< A flag that states if this message has
been ref'ed for using it in a callback. */
@@ -295,24 +295,24 @@
const char *msn_message_get_charset(const MsnMessage *msg);
/**
- * Sets an attribute in a message.
+ * Sets a header in a message.
*
- * @param msg The message.
- * @param attr The attribute name.
- * @param value The attribute value.
+ * @param msg The message.
+ * @param header The header name.
+ * @param value The header value.
*/
-void msn_message_set_attr(MsnMessage *msg, const char *attr,
+void msn_message_set_header(MsnMessage *msg, const char *name,
const char *value);
/**
- * Returns an attribute from a message.
+ * Returns the value of a header from a message.
*
- * @param msg The message.
- * @param attr The attribute.
+ * @param msg The message.
+ * @param header The header value.
*
* @return The value, or @c NULL if not found.
*/
-const char *msn_message_get_attr(const MsnMessage *msg, const char *attr);
+const char *msn_message_get_header_value(const MsnMessage *msg, const char *name);
/**
* Parses the body and returns it in the form of a hashtable.
diff -r 5c9c4557fec2 -r cc6d733a192a libpurple/protocols/msn/msn.c
--- a/libpurple/protocols/msn/msn.c Tue Feb 16 15:16:28 2010 +0000
+++ b/libpurple/protocols/msn/msn.c Tue Feb 16 15:58:34 2010 +0000
@@ -364,6 +364,115 @@
g_free(tmp);
}
+typedef struct MsnLocationData {
+ PurpleAccount *account;
+ MsnSession *session;
+ PurpleRequestFieldGroup *group;
+} MsnLocationData;
+
+static void
+update_endpoint_cb(MsnLocationData *data, PurpleRequestFields *fields)
+{
+ PurpleAccount *account;
+ MsnSession *session;
+ const char *old_name;
+ const char *name;
+ GList *others;
+
+ session = data->session;
+ account = data->account;
+
+ /* Update the current location's name */
+ old_name = purple_account_get_string(account, "endpoint-name", NULL);
+ name = purple_request_fields_get_string(fields, "endpoint-name");
+ if (!g_str_equal(old_name, name)) {
+ purple_account_set_string(account, "endpoint-name", name);
+ msn_notification_send_uux_private_endpointdata(session);
+ }
+
+ /* Sign out other locations */
+ for (others = purple_request_field_group_get_fields(data->group);
+ others;
+ others = g_list_next(others)) {
+ PurpleRequestField *field = others->data;
+ if (purple_request_field_get_type(field) != PURPLE_REQUEST_FIELD_BOOLEAN)
+ continue;
+ if (purple_request_field_bool_get_value(field)) {
+ const char *id = purple_request_field_get_id(field);
+ char *user;
+ purple_debug_info("msn", "Disconnecting Endpoint %s\n", id);
+
+ user = g_strdup_printf("%s;%s", purple_account_get_username(account), id);
+ msn_notification_send_uun(session, user, MSN_UNIFIED_NOTIFICATION_MPOP, "goawyplzthxbye");
+ g_free(user);
+ }
+ }
+
+ g_free(data);
+}
+
+static void
+create_endpoint_fields(gpointer key, gpointer value, gpointer user_data)
+{
+ const char *id = key;
+ MsnUserEndpoint *ep = value;
+ MsnLocationData *data = user_data;
+ PurpleRequestField *field;
+
+ if (g_str_equal(id, data->session->guid))
+ return;
+
+ field = purple_request_field_bool_new(id, ep->name, FALSE);
+ purple_request_field_group_add_field(data->group, field);
+}
+
+static void
+msn_show_locations(PurplePluginAction *action)
+{
+ PurpleConnection *pc;
+ PurpleAccount *account;
+ MsnSession *session;
+ PurpleRequestFields *fields;
+ PurpleRequestFieldGroup *group;
+ PurpleRequestField *field;
+ MsnLocationData *data;
+
+ pc = (PurpleConnection *)action->context;
+ account = purple_connection_get_account(pc);
+ session = purple_connection_get_protocol_data(pc);
+
+ fields = purple_request_fields_new();
+
+ group = purple_request_field_group_new(_("This Location"));
+ purple_request_fields_add_group(fields, group);
+ field = purple_request_field_label_new("endpoint-label", _("This is the name that identifies this location"));
+ purple_request_field_group_add_field(group, field);
+ field = purple_request_field_string_new("endpoint-name",
+ _("Name"),
+ purple_account_get_string(account, "endpoint-name", NULL),
+ FALSE);
+ purple_request_field_set_required(field, TRUE);
+ purple_request_field_group_add_field(group, field);
+
+ group = purple_request_field_group_new(_("Other Locations"));
+ purple_request_fields_add_group(fields, group);
+ field = purple_request_field_label_new("others-label", _("You can sign out from other locations here"));
+ purple_request_field_group_add_field(group, field);
+
+ data = g_new0(MsnLocationData, 1);
+ data->account = account;
+ data->session = session;
+ data->group = group;
+ g_hash_table_foreach(session->user->endpoints, create_endpoint_fields, data);
+
+ purple_request_fields(pc, NULL, NULL, NULL,
+ fields,
+ _("OK"), G_CALLBACK(update_endpoint_cb),
+ _("Cancel"), G_CALLBACK(g_free),
+ account, NULL, NULL,
+ data);
+}
+
static void
msn_show_set_home_phone(PurplePluginAction *action)
{
@@ -937,6 +1046,11 @@
m = g_list_append(m, act);
m = g_list_append(m, NULL);
+ act = purple_plugin_action_new(_("View Locations..."),
+ msn_show_locations);
+ m = g_list_append(m, act);
+ m = g_list_append(m, NULL);
+
act = purple_plugin_action_new(_("Set Home Phone Number..."),
msn_show_set_home_phone);
m = g_list_append(m, act);
@@ -1071,6 +1185,10 @@
username = purple_account_get_string(account, "display-name", NULL);
purple_connection_set_display_name(gc, username);
+ if (purple_account_get_string(account, "endpoint-name", NULL) == NULL) {
+ purple_account_set_string(account, "endpoint-name", "Pidgin");
+ }
+
if (!msn_session_connect(session, host, port, http_method))
purple_connection_error_reason(gc,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
@@ -1281,7 +1399,7 @@
msg = msn_message_new_plain(msgtext);
msg->remote_user = g_strdup(who);
- msn_message_set_attr(msg, "X-MMS-IM-Format", msgformat);
+ msn_message_set_header(msg, "X-MMS-IM-Format", msgformat);
g_free(msgformat);
g_free(msgtext);
@@ -1314,7 +1432,7 @@
body_enc = g_markup_escape_text(body_str, -1);
g_free(body_str);
- format = msn_message_get_attr(msg, "X-MMS-IM-Format");
+ format = msn_message_get_header_value(msg, "X-MMS-IM-Format");
msn_parse_format(format, &pre, &post);
body_str = g_strdup_printf("%s%s%s", pre ? pre : "",
body_enc ? body_enc : "", post ? post : "");
@@ -1389,7 +1507,7 @@
msg = msn_message_new(MSN_MSG_TYPING);
msn_message_set_content_type(msg, "text/x-msmsgscontrol");
msn_message_set_flag(msg, 'U');
- msn_message_set_attr(msg, "TypingUser",
+ msn_message_set_header(msg, "TypingUser",
purple_account_get_username(account));
msn_message_set_bin_data(msg, "\r\n", 2);
@@ -1796,7 +1914,7 @@
}
msg = msn_message_new_plain(msgtext);
- msn_message_set_attr(msg, "X-MMS-IM-Format", msgformat);
+ msn_message_set_header(msg, "X-MMS-IM-Format", msgformat);
smileys = msn_msg_grab_emoticons(msg->body, username);
while (smileys) {
diff -r 5c9c4557fec2 -r cc6d733a192a libpurple/protocols/msn/msn.h
--- a/libpurple/protocols/msn/msn.h Tue Feb 16 15:16:28 2010 +0000
+++ b/libpurple/protocols/msn/msn.h Tue Feb 16 15:58:34 2010 +0000
@@ -109,9 +109,9 @@
#define MSN_SERVER "messenger.hotmail.com"
#define MSN_HTTPCONN_SERVER "gateway.messenger.hotmail.com"
#define MSN_PORT 1863
-#define WLM_PROT_VER 15
+#define WLM_PROT_VER 16
-#define WLM_MAX_PROTOCOL 15
+#define WLM_MAX_PROTOCOL 16
#define WLM_MIN_PROTOCOL 15
#define MSN_TYPING_RECV_TIMEOUT 6
@@ -134,15 +134,14 @@
/* Index into attention_types */
#define MSN_NUDGE 0
-#define MSN_CLIENT_ID_VERSION MSN_CLIENT_VER_7_0
+#define MSN_CLIENT_ID_VERSION MSN_CLIENT_VER_9_0
#define MSN_CLIENT_ID_CAPABILITIES (MSN_CLIENT_CAP_PACKET|MSN_CLIENT_CAP_INK_GIF|MSN_CLIENT_CAP_VOICEIM)
+#define MSN_CLIENT_ID_EXT_CAPS (0)
#define MSN_CLIENT_ID \
((MSN_CLIENT_ID_VERSION << 24) | \
(MSN_CLIENT_ID_CAPABILITIES))
-#define MSN_CLIENT_EXT_ID 0
-
gboolean msn_email_is_valid(const char *passport);
void msn_act_id(PurpleConnection *gc, const char *entry);
void msn_send_privacy(PurpleConnection *gc);
diff -r 5c9c4557fec2 -r cc6d733a192a libpurple/protocols/msn/notification.c
--- a/libpurple/protocols/msn/notification.c Tue Feb 16 15:16:28 2010 +0000
+++ b/libpurple/protocols/msn/notification.c Tue Feb 16 15:58:34 2010 +0000
@@ -22,6 +22,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
#include "msn.h"
+#include "core.h"
#include "notification.h"
#include "contact.h"
#include "state.h"
@@ -161,7 +162,10 @@
msn_session_set_login_step(session, MSN_LOGIN_STEP_AUTH_END);
- msn_cmdproc_send(cmdproc, "USR", "SSO S %s %s", ticket, response);
+ if (session->protocol_ver >= 16)
+ msn_cmdproc_send(cmdproc, "USR", "SSO S %s %s %s", ticket, response, session->guid);
+ else
+ msn_cmdproc_send(cmdproc, "USR", "SSO S %s %s", ticket, response);
}
static void
@@ -233,20 +237,22 @@
MsnSession *session;
PurpleAccount *account;
gboolean protocol_supported = FALSE;
- char proto_str[8];
+ int proto_ver;
size_t i;
session = cmdproc->session;
account = session->account;
- g_snprintf(proto_str, sizeof(proto_str), "MSNP%d", session->protocol_ver);
-
+ session->protocol_ver = 0;
for (i = 1; i < cmd->param_count; i++)
{
- if (!strcmp(cmd->params[i], proto_str))
- {
- protocol_supported = TRUE;
- break;
+ if (sscanf(cmd->params[i], "MSNP%d", &proto_ver) == 1) {
+ if (proto_ver >= WLM_MIN_PROTOCOL
+ && proto_ver <= WLM_MAX_PROTOCOL
+ && proto_ver > session->protocol_ver) {
+ protocol_supported = TRUE;
+ session->protocol_ver = proto_ver;
+ }
}
}
@@ -257,6 +263,8 @@
return;
}
+ purple_debug_info("msn", "Negotiated protocol version %d with the server.\n", session->protocol_ver);
+
/*
* Windows Live Messenger 8.5
* Notice :CVR String discriminate!
@@ -393,7 +401,7 @@
body = msn_message_get_bin_data(msg, &body_len);
body_enc = g_markup_escape_text(body, body_len);
- if ((value = msn_message_get_attr(msg, "X-MMS-IM-Format")) != NULL) {
+ if ((value = msn_message_get_header_value(msg, "X-MMS-IM-Format")) != NULL) {
char *pre, *post;
msn_parse_format(value, &pre, &post);
@@ -407,7 +415,7 @@
g_free(body_final);
}
if(!strcmp(content_type,"text/x-msmsgscontrol")){
- if(msn_message_get_attr(msg, "TypingUser") != NULL){
+ if(msn_message_get_header_value(msg, "TypingUser") != NULL){
serv_got_typing(gc, passport, MSN_TYPING_RECV_TIMEOUT,
PURPLE_TYPING);
}
@@ -1081,7 +1089,8 @@
PurpleConnection *gc;
MsnUser *user;
MsnObject *msnobj = NULL;
- unsigned long clientid;
+ unsigned long clientid, extcaps;
+ char *extcap_str;
int networkid = 0;
const char *state, *passport;
char *friendly;
@@ -1102,7 +1111,11 @@
/* Yahoo! Buddy, looks like */
networkid = atoi(cmd->params[3]);
friendly = g_strdup(purple_url_decode(cmd->params[4]));
- clientid = strtoul(cmd->params[5], NULL, 10);
+ clientid = strtoul(cmd->params[5], &extcap_str, 10);
+ if (session->protocol_ver >= 16 && extcap_str && *extcap_str)
+ extcaps = strtoul(extcap_str+1, NULL, 10);
+ else
+ extcaps = 0;
/* cmd->params[7] seems to be a URL to a Yahoo! icon:
https://sec.yimg.com/i/us/nt/b/purpley.1.0.png
@@ -1112,7 +1125,11 @@
/* MSNP14+ with Display Picture object */
networkid = atoi(cmd->params[3]);
friendly = g_strdup(purple_url_decode(cmd->params[4]));
- clientid = strtoul(cmd->params[5], NULL, 10);
+ clientid = strtoul(cmd->params[5], &extcap_str, 10);
+ if (session->protocol_ver >= 16 && extcap_str && *extcap_str)
+ extcaps = strtoul(extcap_str+1, NULL, 10);
+ else
+ extcaps = 0;
msnobj = msn_object_new_from_string(purple_url_decode(cmd->params[6]));
} else if (cmd->param_count == 6) {
/* Yes, this is 5. The friendly name could start with a number,
@@ -1121,17 +1138,29 @@
/* MSNP14 without Display Picture object */
networkid = atoi(cmd->params[3]);
friendly = g_strdup(purple_url_decode(cmd->params[4]));
- clientid = strtoul(cmd->params[5], NULL, 10);
+ clientid = strtoul(cmd->params[5], &extcap_str, 10);
+ if (session->protocol_ver >= 16 && extcap_str && *extcap_str)
+ extcaps = strtoul(extcap_str+1, NULL, 10);
+ else
+ extcaps = 0;
} else {
/* MSNP8+ with Display Picture object */
friendly = g_strdup(purple_url_decode(cmd->params[3]));
- clientid = strtoul(cmd->params[4], NULL, 10);
+ clientid = strtoul(cmd->params[4], &extcap_str, 10);
+ if (session->protocol_ver >= 16 && extcap_str && *extcap_str)
+ extcaps = strtoul(extcap_str+1, NULL, 10);
+ else
+ extcaps = 0;
msnobj = msn_object_new_from_string(purple_url_decode(cmd->params[5]));
}
} else if (cmd->param_count == 5) {
/* MSNP8+ without Display Picture object */
friendly = g_strdup(purple_url_decode(cmd->params[3]));
- clientid = strtoul(cmd->params[4], NULL, 10);
+ clientid = strtoul(cmd->params[4], &extcap_str, 10);
+ if (session->protocol_ver >= 16 && extcap_str && *extcap_str)
+ extcaps = strtoul(extcap_str+1, NULL, 10);
+ else
+ extcaps = 0;
} else {
purple_debug_warning("msn", "Received ILN with unknown number of parameters.\n");
return;
@@ -1146,6 +1175,7 @@
user->mobile = (clientid & MSN_CLIENT_CAP_MSNMOBILE) || (user->extinfo && user->extinfo->phone_mobile && user->extinfo->phone_mobile[0] == '+');
msn_user_set_clientid(user, clientid);
+ msn_user_set_extcaps(user, extcaps);
msn_user_set_network(user, networkid);
msn_user_set_state(user, state);
@@ -1284,7 +1314,8 @@
PurpleConnection *gc;
MsnUser *user;
MsnObject *msnobj;
- unsigned long clientid;
+ unsigned long clientid, extcaps;
+ char *extcap_str;
int networkid;
const char *state, *passport, *friendly;
@@ -1297,7 +1328,10 @@
networkid = atoi(cmd->params[2]);
friendly = purple_url_decode(cmd->params[3]);
- user = msn_userlist_find_user(session->userlist, passport);
+ if (g_str_equal(passport, session->user->passport))
+ user = session->user;
+ else
+ user = msn_userlist_find_user(session->userlist, passport);
if (user == NULL) return;
if (msn_user_set_friendly_name(user, friendly))
@@ -1315,10 +1349,16 @@
msn_user_set_object(user, NULL);
}
- clientid = strtoul(cmd->params[4], NULL, 10);
+ clientid = strtoul(cmd->params[4], &extcap_str, 10);
+ if (session->protocol_ver >= 16 && extcap_str && *extcap_str)
+ extcaps = strtoul(extcap_str+1, NULL, 10);
+ else
+ extcaps = 0;
+
user->mobile = (clientid & MSN_CLIENT_CAP_MSNMOBILE) || (user->extinfo && user->extinfo->phone_mobile && user->extinfo->phone_mobile[0] == '+');
msn_user_set_clientid(user, clientid);
+ msn_user_set_extcaps(user, extcaps);
msn_user_set_network(user, networkid);
msn_user_set_state(user, state);
@@ -1599,6 +1639,77 @@
/*get the payload content*/
}
+static void
+parse_user_endpoints(MsnUser *user, xmlnode *payloadNode)
+{
+ xmlnode *epNode, *capsNode;
+ MsnUserEndpoint data;
+ const char *id;
+ char *caps, *tmp;
+
+ purple_debug_info("msn", "Get EndpointData\n");
+
+ for (epNode = xmlnode_get_child(payloadNode, "EndpointData");
+ epNode;
+ epNode = xmlnode_get_next_twin(epNode)) {
+ id = xmlnode_get_attrib(epNode, "id");
+ capsNode = xmlnode_get_child(epNode, "Capabilities");
+
+ if (capsNode != NULL) {
+ caps = xmlnode_get_data(capsNode);
+
+ data.clientid = strtoul(caps, &tmp, 10);
+ if (tmp && *tmp)
+ data.extcaps = strtoul(tmp + 1, NULL, 10);
+ else
+ data.extcaps = 0;
+
+ g_free(caps);
+
+ } else {
+ data.clientid = 0;
+ data.extcaps = 0;
+ }
+
+ msn_user_set_endpoint_data(user, id, &data);
+ }
+
+ /* Need to shortcut this check, probably... */
+ if (user == user->userlist->session->user) {
+ for (epNode = xmlnode_get_child(payloadNode, "PrivateEndpointData");
+ epNode;
+ epNode = xmlnode_get_next_twin(epNode)) {
+ MsnUserEndpoint *ep;
+ xmlnode *nameNode, *clientNode;
+
+ /*
+ Endpoint Name
+ true/false
+ 1
+ NLN
+
+ */
+ id = xmlnode_get_attrib(epNode, "id");
+ ep = msn_user_get_endpoint_data(user, id);
+
+ if (ep != NULL) {
+ nameNode = xmlnode_get_child(epNode, "EpName");
+ if (nameNode != NULL) {
+ g_free(ep->name);
+ ep->name = xmlnode_get_data(nameNode);
+ }
+
+ clientNode = xmlnode_get_child(epNode, "ClientType");
+ if (clientNode != NULL) {
+ tmp = xmlnode_get_data(clientNode);
+ ep->type = strtoul(tmp, NULL, 10);
+ g_free(tmp);
+ }
+ }
+ }
+ }
+}
+
static void parse_currentmedia(MsnUser *user, const char *cmedia)
{
char **cmedia_array;
@@ -1669,13 +1780,17 @@
PurpleAccount *account;
MsnUser *user;
const char *passport;
+ xmlnode *payloadNode;
char *psm_str, *str;
session = cmdproc->session;
account = session->account;
passport = cmd->params[0];
- user = msn_userlist_find_user(session->userlist, passport);
+ if (g_str_equal(passport, session->user->passport))
+ user = session->user;
+ else
+ user = msn_userlist_find_user(session->userlist, passport);
if (user == NULL) {
char *str = g_strndup(payload, len);
purple_debug_info("msn", "unknown user %s, payload is %s\n",
@@ -1695,13 +1810,28 @@
}
if (len != 0) {
- psm_str = msn_get_psm(cmd->payload,len);
+ payloadNode = xmlnode_from_str(payload, len);
+ if (!payloadNode) {
+ purple_debug_error("msn", "UBX XML parse Error!\n");
+
+ msn_user_set_statusline(user, NULL);
+
+ msn_user_update(user);
+ return;
+ }
+
+ psm_str = msn_get_psm(payloadNode);
msn_user_set_statusline(user, psm_str);
g_free(psm_str);
- str = msn_get_currentmedia(cmd->payload, len);
+ str = msn_get_currentmedia(payloadNode);
parse_currentmedia(user, str);
g_free(str);
+
+ parse_user_endpoints(user, payloadNode);
+
+ xmlnode_free(payloadNode);
+
} else {
msn_user_set_statusline(user, NULL);
}
@@ -1734,6 +1864,158 @@
cmd->payload_len = atoi(cmd->params[1]);
}
+void
+msn_notification_send_uux(MsnSession *session, const char *payload)
+{
+ MsnTransaction *trans;
+ MsnCmdProc *cmdproc;
+ size_t len = strlen(payload);
+
+ cmdproc = session->notification->cmdproc;
+ purple_debug_misc("msn", "Sending UUX command with payload: %s\n", payload);
+ trans = msn_transaction_new(cmdproc, "UUX", "%" G_GSIZE_FORMAT, len);
+ msn_transaction_set_payload(trans, payload, len);
+ msn_cmdproc_send_trans(cmdproc, trans);
+}
+
+void msn_notification_send_uux_endpointdata(MsnSession *session)
+{
+ xmlnode *epDataNode;
+ xmlnode *capNode;
+ char *caps;
+ char *payload;
+ int length;
+
+ epDataNode = xmlnode_new("EndpointData");
+
+ capNode = xmlnode_new_child(epDataNode, "Capabilities");
+ caps = g_strdup_printf("%d:%02d", MSN_CLIENT_ID_CAPABILITIES, MSN_CLIENT_ID_EXT_CAPS);
+ xmlnode_insert_data(capNode, caps, -1);
+ g_free(caps);
+
+ payload = xmlnode_to_str(epDataNode, &length);
+
+ msn_notification_send_uux(session, payload);
+
+ xmlnode_free(epDataNode);
+ g_free(payload);
+}
+
+void msn_notification_send_uux_private_endpointdata(MsnSession *session)
+{
+ xmlnode *private;
+ const char *name;
+ xmlnode *epname;
+ xmlnode *idle;
+ GHashTable *ui_info;
+ const gchar *ui_type;
+ xmlnode *client_type;
+ xmlnode *state;
+ char *payload;
+ int length;
+
+ private = xmlnode_new("PrivateEndpointData");
+
+ name = purple_account_get_string(session->account, "endpoint-name", NULL);
+ epname = xmlnode_new_child(private, "EpName");
+ xmlnode_insert_data(epname, name, -1);
+
+ idle = xmlnode_new_child(private, "Idle");
+ xmlnode_insert_data(idle, "false", -1);
+
+ /* ClientType info (from amsn guys):
+ 0: None
+ 1: Computer
+ 2: Website
+ 3: Mobile / none
+ 4: Xbox / phone /mobile
+ 9: MsnGroup
+ 32: Email member, currently Yahoo!
+ */
+ client_type = xmlnode_new_child(private, "ClientType");
+ ui_info = purple_core_get_ui_info();
+ ui_type = ui_info ? g_hash_table_lookup(ui_info, "client_type") : NULL;
+ if (ui_type) {
+ if (strcmp(ui_type, "pc") == 0)
+ xmlnode_insert_data(client_type, "1", -1);
+ else if (strcmp(ui_type, "web") == 0)
+ xmlnode_insert_data(client_type, "2", -1);
+ else if (strcmp(ui_type, "phone") == 0)
+ xmlnode_insert_data(client_type, "3", -1);
+ else if (strcmp(ui_type, "handheld") == 0)
+ xmlnode_insert_data(client_type, "3", -1);
+ else
+ xmlnode_insert_data(client_type, "1", -1);
+ }
+ else
+ xmlnode_insert_data(client_type, "1", -1);
+
+ state = xmlnode_new_child(private, "State");
+ xmlnode_insert_data(state, msn_state_get_text(msn_state_from_account(session->account)), -1);
+
+ payload = xmlnode_to_str(private, &length);
+
+ msn_notification_send_uux(session, payload);
+
+ xmlnode_free(private);
+ g_free(payload);
+}
+
+static void
+ubn_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload,
+ size_t len)
+{
+ /* Do Nothing, right now. */
+ if (payload != NULL)
+ purple_debug_info("msn", "UBN payload:\n%s\n", payload);
+}
+
+static void
+ubn_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+ purple_debug_misc("msn", "UBN received from %s.\n", cmd->params[0]);
+ cmdproc->last_cmd->payload_cb = ubn_cmd_post;
+ cmd->payload_len = atoi(cmd->params[2]);
+}
+
+static void
+uun_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload,
+ size_t len)
+{
+ /* Do Nothing, right now. */
+ if (payload != NULL)
+ purple_debug_info("msn", "UUN payload:\n%s\n", payload);
+}
+
+static void
+uun_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+ if (strcmp(cmd->params[1], "OK") != 0) {
+ purple_debug_misc("msn", "UUN received.\n");
+ cmdproc->last_cmd->payload_cb = uun_cmd_post;
+ cmd->payload_len = atoi(cmd->params[1]);
+ }
+ else
+ purple_debug_misc("msn", "UUN OK received.\n");
+}
+
+void
+msn_notification_send_uun(MsnSession *session, const char *user,
+ MsnUnifiedNotificationType type, const char *payload)
+{
+ MsnTransaction *trans;
+ MsnCmdProc *cmdproc;
+ size_t len = strlen(payload);
+
+ cmdproc = session->notification->cmdproc;
+ purple_debug_misc("msn", "Sending UUN command %d to %s with payload: %s\n",
+ type, user, payload);
+ trans = msn_transaction_new(cmdproc, "UUN", "%s %d %" G_GSIZE_FORMAT,
+ user, type, len);
+ msn_transaction_set_payload(trans, payload, len);
+ msn_cmdproc_send_trans(cmdproc, trans);
+}
+
/**************************************************************************
* Message Types
**************************************************************************/
@@ -1751,39 +2033,39 @@
/* This isn't an official message. */
return;
- if ((value = msn_message_get_attr(msg, "kv")) != NULL)
+ if ((value = msn_message_get_header_value(msg, "kv")) != NULL)
{
g_free(session->passport_info.kv);
session->passport_info.kv = g_strdup(value);
}
- if ((value = msn_message_get_attr(msg, "sid")) != NULL)
+ if ((value = msn_message_get_header_value(msg, "sid")) != NULL)
{
g_free(session->passport_info.sid);
session->passport_info.sid = g_strdup(value);
}
- if ((value = msn_message_get_attr(msg, "MSPAuth")) != NULL)
+ if ((value = msn_message_get_header_value(msg, "MSPAuth")) != NULL)
{
g_free(session->passport_info.mspauth);
session->passport_info.mspauth = g_strdup(value);
}
- if ((value = msn_message_get_attr(msg, "ClientIP")) != NULL)
+ if ((value = msn_message_get_header_value(msg, "ClientIP")) != NULL)
{
g_free(session->passport_info.client_ip);
session->passport_info.client_ip = g_strdup(value);
}
- if ((value = msn_message_get_attr(msg, "ClientPort")) != NULL)
+ if ((value = msn_message_get_header_value(msg, "ClientPort")) != NULL)
{
session->passport_info.client_port = ntohs(atoi(value));
}
- if ((value = msn_message_get_attr(msg, "LoginTime")) != NULL)
+ if ((value = msn_message_get_header_value(msg, "LoginTime")) != NULL)
session->passport_info.sl = atol(value);
- if ((value = msn_message_get_attr(msg, "EmailEnabled")) != NULL)
+ if ((value = msn_message_get_header_value(msg, "EmailEnabled")) != NULL)
session->passport_info.email_enabled = (gboolean)atol(value);
/*starting retrieve the contact list*/
@@ -2190,6 +2472,9 @@
msn_table_add_cmd(cbs_table, NULL, "UBX", ubx_cmd);
msn_table_add_cmd(cbs_table, NULL, "UUX", uux_cmd);
+ msn_table_add_cmd(cbs_table, NULL, "UBN", ubn_cmd);
+ msn_table_add_cmd(cbs_table, NULL, "UUN", uun_cmd);
+
msn_table_add_cmd(cbs_table, NULL, "URL", url_cmd);
msn_table_add_cmd(cbs_table, "fallback", "XFR", xfr_cmd);
diff -r 5c9c4557fec2 -r cc6d733a192a libpurple/protocols/msn/notification.h
--- a/libpurple/protocols/msn/notification.h Tue Feb 16 15:16:28 2010 +0000
+++ b/libpurple/protocols/msn/notification.h Tue Feb 16 15:58:34 2010 +0000
@@ -62,6 +62,15 @@
typedef void (*MsnFqyCb)(MsnSession *session, const char *passport, MsnNetwork network, gpointer data);
+/* Type used for msn_notification_send_uun */
+typedef enum {
+ MSN_UNIFIED_NOTIFICATION_SHARED_FOLDERS = 1,
+ MSN_UNIFIED_NOTIFICATION_UNKNOWN1 = 2,
+ MSN_UNIFIED_NOTIFICATION_P2P = 3,
+ MSN_UNIFIED_NOTIFICATION_MPOP = 4
+
+} MsnUnifiedNotificationType;
+
void uum_send_msg(MsnSession *session, MsnMessage *msg);
void msn_notification_end(void);
@@ -83,6 +92,17 @@
void msn_notification_disconnect(MsnNotification *notification);
void msn_notification_dump_contact(MsnSession *session);
+void msn_notification_send_uux(MsnSession *session, const char *payload);
+
+void msn_notification_send_uux_endpointdata(MsnSession *session);
+
+void msn_notification_send_uux_private_endpointdata(MsnSession *session);
+
+void msn_notification_send_uun(MsnSession *session,
+ const char *user,
+ MsnUnifiedNotificationType type,
+ const char *payload);
+
/**
* Closes a notification.
*
diff -r 5c9c4557fec2 -r cc6d733a192a libpurple/protocols/msn/oim.c
--- a/libpurple/protocols/msn/oim.c Tue Feb 16 15:16:28 2010 +0000
+++ b/libpurple/protocols/msn/oim.c Tue Feb 16 15:58:34 2010 +0000
@@ -618,7 +618,7 @@
MSG_OIM_LINE_DEM, MSG_OIM_BODY_DEM);
purple_debug_info("msn", "oim body:{%s}\n", message->body);
- boundary = msn_message_get_attr(message, "boundary");
+ boundary = msn_message_get_header_value(message, "boundary");
if (boundary != NULL) {
char *bounds;
@@ -656,7 +656,7 @@
decode_msg = (char *)purple_base64_decode(message->body, &body_len);
}
- from = msn_message_get_attr(message, "X-OIM-originatingSource");
+ from = msn_message_get_header_value(message, "X-OIM-originatingSource");
/* Match number to user's mobile number, FROM is a phone number
if the other side pages you using your phone number */
@@ -671,7 +671,7 @@
if (passport == NULL) {
char *start, *end;
- from = msn_message_get_attr(message, "From");
+ from = msn_message_get_header_value(message, "From");
tokens = g_strsplit(from, " ", 2);
if (tokens[1] != NULL)
@@ -690,7 +690,7 @@
g_strfreev(tokens);
}
- date = msn_message_get_attr(message, "Date");
+ date = msn_message_get_header_value(message, "Date");
stamp = msn_oim_parse_timestamp(date);
purple_debug_info("msn", "oim Date:{%s},passport{%s}\n",
date, passport);
diff -r 5c9c4557fec2 -r cc6d733a192a libpurple/protocols/msn/session.c
--- a/libpurple/protocols/msn/session.c Tue Feb 16 15:16:28 2010 +0000
+++ b/libpurple/protocols/msn/session.c Tue Feb 16 15:58:34 2010 +0000
@@ -22,6 +22,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
#include "msn.h"
+#include "msnutils.h"
#include "session.h"
#include "notification.h"
#include "oim.h"
@@ -45,7 +46,9 @@
purple_account_get_username(account), NULL);
session->oim = msn_oim_new(session);
- session->protocol_ver = WLM_PROT_VER;
+ session->protocol_ver = 0;
+
+ session->guid = rand_guid();
return session;
}
@@ -90,6 +93,7 @@
msn_userlist_destroy(session->userlist);
g_free(session->psm);
+ g_free(session->guid);
g_free(session->abch_cachekey);
#if 0
g_free(session->blocked_text);
@@ -448,6 +452,11 @@
msn_session_sync_users(session);
}
+ if (session->protocol_ver >= 16) {
+ /* TODO: Send this when updating status instead? */
+ msn_notification_send_uux_endpointdata(session);
+ msn_notification_send_uux_private_endpointdata(session);
+ }
msn_change_status(session);
}
diff -r 5c9c4557fec2 -r cc6d733a192a libpurple/protocols/msn/session.h
--- a/libpurple/protocols/msn/session.h Tue Feb 16 15:16:28 2010 +0000
+++ b/libpurple/protocols/msn/session.h Tue Feb 16 15:58:34 2010 +0000
@@ -119,6 +119,7 @@
GHashTable *soap_table;
guint soap_cleanup_handle;
+ char *guid;
};
/**
diff -r 5c9c4557fec2 -r cc6d733a192a libpurple/protocols/msn/slp.c
--- a/libpurple/protocols/msn/slp.c Tue Feb 16 15:16:28 2010 +0000
+++ b/libpurple/protocols/msn/slp.c Tue Feb 16 15:58:34 2010 +0000
@@ -740,6 +740,7 @@
if (!strncmp(body, "INVITE", strlen("INVITE")))
{
+ /* This is an INVITE request */
char *branch;
char *content;
char *content_type;
@@ -783,6 +784,7 @@
}
else if (!strncmp(body, "MSNSLP/1.0 ", strlen("MSNSLP/1.0 ")))
{
+ /* This is a response */
char *content;
char *content_type;
/* Make sure this is "OK" */
@@ -832,6 +834,7 @@
}
else if (!strncmp(body, "BYE", strlen("BYE")))
{
+ /* This is a BYE request */
char *call_id;
call_id = get_token(body, "Call-ID: {", "}");
diff -r 5c9c4557fec2 -r cc6d733a192a libpurple/protocols/msn/slplink.c
--- a/libpurple/protocols/msn/slplink.c Tue Feb 16 15:16:28 2010 +0000
+++ b/libpurple/protocols/msn/slplink.c Tue Feb 16 15:58:34 2010 +0000
@@ -390,7 +390,7 @@
msg->msnslp_header.total_size = slpmsg->size;
- msn_message_set_attr(msg, "P2P-Dest", slplink->remote_user);
+ msn_message_set_header(msg, "P2P-Dest", slplink->remote_user);
msg->ack_cb = msg_ack;
msg->nak_cb = msg_nak;
@@ -497,7 +497,6 @@
const char *data;
guint64 offset;
gsize len;
- PurpleXfer *xfer = NULL;
if (purple_debug_is_verbose())
msn_slpmsg_show(msg);
@@ -508,8 +507,11 @@
if (msg->msnslp_header.total_size < msg->msnslp_header.length)
{
- purple_debug_error("msn", "This can't be good\n");
- g_return_if_reached();
+ /* We seem to have received a bad header */
+ purple_debug_warning("msn", "Total size listed in SLP binary header "
+ "was less than length of this particular message. This "
+ "should not happen. Dropping message.\n");
+ return;
}
data = msn_message_get_bin_data(msg, &len);
@@ -526,15 +528,13 @@
if (slpmsg->session_id)
{
- if (slpmsg->slpcall == NULL)
- slpmsg->slpcall = msn_slplink_find_slp_call_with_session_id(slplink, slpmsg->session_id);
-
+ slpmsg->slpcall = msn_slplink_find_slp_call_with_session_id(slplink, slpmsg->session_id);
if (slpmsg->slpcall != NULL)
{
if (slpmsg->flags == 0x20 ||
slpmsg->flags == 0x1000020 || slpmsg->flags == 0x1000030)
{
- xfer = slpmsg->slpcall->xfer;
+ PurpleXfer *xfer = slpmsg->slpcall->xfer;
if (xfer != NULL)
{
slpmsg->ft = TRUE;
@@ -578,10 +578,9 @@
if (slpmsg->ft)
{
- xfer = slpmsg->slpcall->xfer;
slpmsg->slpcall->u.incoming_data =
g_byte_array_append(slpmsg->slpcall->u.incoming_data, (const guchar *)data, len);
- purple_xfer_prpl_ready(xfer);
+ purple_xfer_prpl_ready(slpmsg->slpcall->xfer);
}
else if (slpmsg->size && slpmsg->buffer)
{
diff -r 5c9c4557fec2 -r cc6d733a192a libpurple/protocols/msn/state.c
--- a/libpurple/protocols/msn/state.c Tue Feb 16 15:16:28 2010 +0000
+++ b/libpurple/protocols/msn/state.c Tue Feb 16 15:58:34 2010 +0000
@@ -27,6 +27,7 @@
#include "core.h"
#include "msn.h"
+#include "notification.h"
#include "state.h"
static const char *away_text[] =
@@ -43,10 +44,6 @@
N_("Available")
};
-/* Local Function Prototype*/
-static char *msn_build_psm(const char *psmstr,const char *mediastr,
- const char *guidstr);
-
/*
* WLM media PSM info build prcedure
*
@@ -56,7 +53,7 @@
* \0Office\01\0Office Message\0Office App Name\0"
*/
static char *
-msn_build_psm(const char *psmstr,const char *mediastr, const char *guidstr)
+msn_build_psm(const char *psmstr,const char *mediastr, const char *guidstr, guint protocol_ver)
{
xmlnode *dataNode,*psmNode,*mediaNode,*guidNode;
char *result;
@@ -82,60 +79,50 @@
}
xmlnode_insert_child(dataNode, guidNode);
+ if (protocol_ver >= 16) {
+ /* TODO: What is this for? */
+ xmlnode *ddpNode = xmlnode_new("DDP");
+ xmlnode_insert_child(dataNode, ddpNode);
+ }
+
result = xmlnode_to_str(dataNode, &length);
xmlnode_free(dataNode);
return result;
}
-/* get the CurrentMedia info from the XML string */
+/* get the CurrentMedia info from the XML node */
char *
-msn_get_currentmedia(char *xml_str, gsize len)
+msn_get_currentmedia(xmlnode *payloadNode)
{
- xmlnode *payloadNode, *currentmediaNode;
+ xmlnode *currentmediaNode;
char *currentmedia;
purple_debug_info("msn", "Get CurrentMedia\n");
- payloadNode = xmlnode_from_str(xml_str, len);
- if (!payloadNode) {
- purple_debug_error("msn", "PSM XML parse Error!\n");
- return NULL;
- }
currentmediaNode = xmlnode_get_child(payloadNode, "CurrentMedia");
if (currentmediaNode == NULL) {
purple_debug_info("msn", "No CurrentMedia Node\n");
- xmlnode_free(payloadNode);
return NULL;
}
currentmedia = xmlnode_get_data(currentmediaNode);
- xmlnode_free(payloadNode);
-
return currentmedia;
}
-/*get the PSM info from the XML string*/
+/* Get the PSM info from the XML node */
char *
-msn_get_psm(char *xml_str, gsize len)
+msn_get_psm(xmlnode *payloadNode)
{
- xmlnode *payloadNode, *psmNode;
+ xmlnode *psmNode;
char *psm;
purple_debug_info("msn", "msn get PSM\n");
- payloadNode = xmlnode_from_str(xml_str, len);
- if (!payloadNode) {
- purple_debug_error("msn", "PSM XML parse Error!\n");
- return NULL;
- }
psmNode = xmlnode_get_child(payloadNode, "PSM");
if (psmNode == NULL) {
purple_debug_info("msn", "No PSM status Node\n");
- xmlnode_free(payloadNode);
return NULL;
}
psm = xmlnode_get_data(psmNode);
- xmlnode_free(payloadNode);
-
return psm;
}
@@ -181,8 +168,6 @@
PurpleAccount *account;
PurplePresence *presence;
PurpleStatus *status;
- MsnCmdProc *cmdproc;
- MsnTransaction *trans;
char *payload;
const char *statusline;
gchar *statusline_stripped, *media = NULL;
@@ -191,7 +176,6 @@
g_return_if_fail(session->notification != NULL);
account = session->account;
- cmdproc = session->notification->cmdproc;
/* Get the PSM string from Purple's Status Line */
presence = purple_account_get_presence(account);
@@ -202,13 +186,11 @@
statusline_stripped = purple_markup_strip_html(statusline);
media = create_media_string(presence);
g_free(session->psm);
- session->psm = msn_build_psm(statusline_stripped, media, NULL);
+ session->psm = msn_build_psm(statusline_stripped, media, session->protocol_ver >= 16 ? session->guid : NULL, session->protocol_ver);
payload = session->psm;
- purple_debug_misc("msn", "Sending UUX command with payload: %s\n", payload);
- trans = msn_transaction_new(cmdproc, "UUX", "%" G_GSIZE_FORMAT, strlen(payload));
- msn_transaction_set_payload(trans, payload, strlen(payload));
- msn_cmdproc_send_trans(cmdproc, trans);
+
+ msn_notification_send_uux(session, payload);
g_free(statusline_stripped);
g_free(media);
@@ -256,11 +238,16 @@
if (!session->logged_in)
return;
+ msn_set_psm(session);
+
msnobj = msn_user_get_object(user);
if (msnobj == NULL)
{
- msn_cmdproc_send(cmdproc, "CHG", "%s %d", state_text, caps);
+ if (session->protocol_ver >= 16)
+ msn_cmdproc_send(cmdproc, "CHG", "%s %u:%02u 0", state_text, caps, MSN_CLIENT_ID_EXT_CAPS);
+ else
+ msn_cmdproc_send(cmdproc, "CHG", "%s %d", state_text, caps);
}
else
{
@@ -268,12 +255,15 @@
msnobj_str = msn_object_to_string(msnobj);
- msn_cmdproc_send(cmdproc, "CHG", "%s %d %s", state_text,
- caps, purple_url_encode(msnobj_str));
+ if (session->protocol_ver >= 16)
+ msn_cmdproc_send(cmdproc, "CHG", "%s %u:%02u %s", state_text,
+ caps, MSN_CLIENT_ID_EXT_CAPS, purple_url_encode(msnobj_str));
+ else
+ msn_cmdproc_send(cmdproc, "CHG", "%s %d %s", state_text,
+ caps, purple_url_encode(msnobj_str));
g_free(msnobj_str);
}
- msn_set_psm(session);
}
const char *
diff -r 5c9c4557fec2 -r cc6d733a192a libpurple/protocols/msn/state.h
--- a/libpurple/protocols/msn/state.h Tue Feb 16 15:16:28 2010 +0000
+++ b/libpurple/protocols/msn/state.h Tue Feb 16 15:58:34 2010 +0000
@@ -60,11 +60,11 @@
void msn_set_psm(MsnSession *session);
-/* Get the CurrentMedia info from the XML string */
-char *msn_get_currentmedia(char *xml_str, gsize len);
+/* Get the CurrentMedia info from the XML node */
+char *msn_get_currentmedia(xmlnode *payloadNode);
-/*get the PSM info from the XML string*/
-char *msn_get_psm(char *xml_str, gsize len);
+/* Get the PSM info from the XML node */
+char *msn_get_psm(xmlnode *payloadNode);
MsnAwayType msn_state_from_account(PurpleAccount *account);
diff -r 5c9c4557fec2 -r cc6d733a192a libpurple/protocols/msn/switchboard.c
--- a/libpurple/protocols/msn/switchboard.c Tue Feb 16 15:16:28 2010 +0000
+++ b/libpurple/protocols/msn/switchboard.c Tue Feb 16 15:58:34 2010 +0000
@@ -243,6 +243,12 @@
return;
}
+ /* Don't add ourselves either... */
+ if (g_str_equal(passport, purple_account_get_username(account))) {
+ g_free(passport);
+ return;
+ }
+
swboard->users = g_list_prepend(swboard->users, passport);
swboard->current_users++;
swboard->empty = FALSE;
@@ -265,7 +271,7 @@
PURPLE_CBFLAGS_NONE, TRUE);
msn_servconn_set_idle_timeout(swboard->servconn, 0);
}
- else if (swboard->current_users > 1 || swboard->total_users > 1)
+ else if (swboard->current_users > 1)
{
msn_servconn_set_idle_timeout(swboard->servconn, 0);
if (swboard->conv == NULL ||
@@ -505,7 +511,7 @@
body_enc = g_markup_escape_text(body_str, -1);
g_free(body_str);
- format = msn_message_get_attr(msg, "X-MMS-IM-Format");
+ format = msn_message_get_header_value(msg, "X-MMS-IM-Format");
msn_parse_format(format, &pre, &post);
body_str = g_strdup_printf("%s%s%s", pre ? pre : "",
body_enc ? body_enc : "", post ? post : "");
@@ -964,6 +970,7 @@
MsnTransaction *trans;
MsnCmdProc *cmdproc;
PurpleAccount *account;
+ char *username;
cmdproc = servconn->cmdproc;
g_return_if_fail(cmdproc != NULL);
@@ -972,24 +979,33 @@
swboard = cmdproc->data;
g_return_if_fail(swboard != NULL);
+ if (servconn->session->protocol_ver >= 16)
+ username = g_strdup_printf("%s;{%s}",
+ purple_account_get_username(account),
+ servconn->session->guid);
+ else
+ username = g_strdup(purple_account_get_username(account));
+
if (msn_switchboard_is_invited(swboard))
{
swboard->empty = FALSE;
trans = msn_transaction_new(cmdproc, "ANS", "%s %s %s",
- purple_account_get_username(account),
+ username,
swboard->auth_key, swboard->session_id);
}
else
{
trans = msn_transaction_new(cmdproc, "USR", "%s %s",
- purple_account_get_username(account),
+ username,
swboard->auth_key);
}
msn_transaction_set_error_cb(trans, ans_usr_error);
msn_transaction_set_data(trans, swboard);
msn_cmdproc_send_trans(cmdproc, trans);
+
+ g_free(username);
}
static void
diff -r 5c9c4557fec2 -r cc6d733a192a libpurple/protocols/msn/user.c
--- a/libpurple/protocols/msn/user.c Tue Feb 16 15:16:28 2010 +0000
+++ b/libpurple/protocols/msn/user.c Tue Feb 16 15:58:34 2010 +0000
@@ -25,6 +25,8 @@
#include "user.h"
#include "slp.h"
+static void free_user_endpoint(MsnUserEndpoint *data);
+
/*new a user object*/
MsnUser *
msn_user_new(MsnUserList *userlist, const char *passport,
@@ -39,6 +41,9 @@
msn_user_set_passport(user, passport);
msn_user_set_friendly_name(user, friendly_name);
+ user->endpoints = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, (GDestroyNotify)free_user_endpoint);
+
return user;
}
@@ -48,6 +53,9 @@
{
g_return_if_fail(user != NULL);
+ if (user->endpoints != NULL)
+ g_hash_table_destroy(user->endpoints);
+
if (user->clientcaps != NULL)
g_hash_table_destroy(user->clientcaps);
@@ -186,6 +194,9 @@
{
g_return_val_if_fail(user != NULL, FALSE);
+ if (user == user->userlist->session->user)
+ return FALSE;
+
if (user->friendly_name && name && (!strcmp(user->friendly_name, name) ||
!strcmp(user->passport, name)))
return FALSE;
@@ -216,6 +227,44 @@
user->uid = g_strdup(uid);
}
+static void
+free_user_endpoint(MsnUserEndpoint *data)
+{
+ g_free(data->id);
+ g_free(data->name);
+ g_free(data);
+}
+
+void
+msn_user_set_endpoint_data(MsnUser *user, const char *input, MsnUserEndpoint *data)
+{
+ MsnUserEndpoint *new;
+ char *endpoint;
+
+ g_return_if_fail(user != NULL);
+ g_return_if_fail(input != NULL);
+
+ endpoint = g_ascii_strdown(input, -1);
+
+ if (data == NULL) {
+ g_hash_table_remove(user->endpoints, endpoint);
+ g_free(endpoint);
+ return;
+ }
+
+ new = g_hash_table_lookup(user->endpoints, endpoint);
+ if (!new) {
+ new = g_new0(MsnUserEndpoint, 1);
+ new->id = g_strdup(endpoint);
+ g_hash_table_insert(user->endpoints, g_strdup(endpoint), new);
+ }
+
+ new->clientid = data->clientid;
+ new->extcaps = data->extcaps;
+
+ g_free(endpoint);
+}
+
void
msn_user_set_op(MsnUser *user, MsnListOp list_op)
{
@@ -406,6 +455,14 @@
}
void
+msn_user_set_extcaps(MsnUser *user, guint extcaps)
+{
+ g_return_if_fail(user != NULL);
+
+ user->extcaps = extcaps;
+}
+
+void
msn_user_set_network(MsnUser *user, MsnNetwork network)
{
g_return_if_fail(user != NULL);
@@ -423,7 +480,7 @@
user->msnobj = obj;
- if (user->list_op & MSN_LIST_FL_OP)
+ if (user != user->userlist->session->user && user->list_op & MSN_LIST_FL_OP)
msn_queue_buddy_icon_request(user);
}
@@ -496,6 +553,30 @@
return user->clientid;
}
+guint
+msn_user_get_extcaps(const MsnUser *user)
+{
+ g_return_val_if_fail(user != NULL, 0);
+
+ return user->extcaps;
+}
+
+MsnUserEndpoint *
+msn_user_get_endpoint_data(MsnUser *user, const char *input)
+{
+ char *endpoint;
+ MsnUserEndpoint *data;
+
+ g_return_val_if_fail(user != NULL, NULL);
+ g_return_val_if_fail(input != NULL, NULL);
+
+ endpoint = g_ascii_strdown(input, -1);
+ data = g_hash_table_lookup(user->endpoints, endpoint);
+ g_free(endpoint);
+
+ return data;
+}
+
MsnObject *
msn_user_get_object(const MsnUser *user)
{
@@ -520,3 +601,22 @@
return user->invite_message;
}
+gboolean
+msn_user_is_capable(MsnUser *user, char *endpoint, guint capability, guint extcap)
+{
+ g_return_val_if_fail(user != NULL, FALSE);
+
+ if (endpoint != NULL) {
+ MsnUserEndpoint *ep = g_hash_table_lookup(user->endpoints, endpoint);
+ if (ep != NULL)
+ return (ep->clientid & capability) == capability
+ && (ep->extcaps & extcap) == extcap;
+ else
+ return FALSE;
+ }
+
+ return (user->clientid & capability) == capability
+ && (user->extcaps & extcap) == extcap;
+}
+
+
diff -r 5c9c4557fec2 -r cc6d733a192a libpurple/protocols/msn/user.h
--- a/libpurple/protocols/msn/user.h Tue Feb 16 15:16:28 2010 +0000
+++ b/libpurple/protocols/msn/user.h Tue Feb 16 15:58:34 2010 +0000
@@ -83,6 +83,7 @@
char *friendly_name; /**< The friendly name. */
char *uid; /*< User ID */
+ GHashTable *endpoints; /*< Endpoint-specific data */
const char *status; /**< The state of the user. */
char *statusline; /**< The state of the user. */
@@ -102,6 +103,7 @@
GHashTable *clientcaps; /**< The client's capabilities. */
guint clientid; /**< The client's ID */
+ guint extcaps; /**< The client's extended capabilities */
MsnNetwork networkid; /**< The user's network */
@@ -116,6 +118,18 @@
char *invite_message; /**< Invite message of user request */
};
+/**
+ * A specific user endpoint.
+ */
+typedef struct MsnUserEndpoint {
+ char *id; /**< The client's endpoint ID */
+ char *name; /**< The client's endpoint's name */
+ int type; /**< The client's endpoint type */
+ guint clientid; /**< The client's ID */
+ guint extcaps; /**< The client's extended capabilites */
+
+} MsnUserEndpoint;
+
/**************************************************************************
** @name User API *
**************************************************************************/
@@ -252,6 +266,16 @@
void msn_user_set_uid(MsnUser *user, const char *uid);
/**
+ * Sets endpoint data for a user.
+ *
+ * @param user The user.
+ * @param endpoint The endpoint.
+ * @param data The endpoint data.
+ */
+void
+msn_user_set_endpoint_data(MsnUser *user, const char *endpoint, MsnUserEndpoint *data);
+
+/**
* Sets the client id for a user.
*
* @param user The user.
@@ -260,6 +284,14 @@
void msn_user_set_clientid(MsnUser *user, guint clientid);
/**
+ * Sets the client id for a user.
+ *
+ * @param user The user.
+ * @param extcaps The client's extended capabilities.
+ */
+void msn_user_set_extcaps(MsnUser *user, guint extcaps);
+
+/**
* Sets the network id for a user.
*
* @param user The user.
@@ -346,6 +378,17 @@
const char *msn_user_get_mobile_phone(const MsnUser *user);
/**
+ * Gets endpoint data for a user.
+ *
+ * @param user The user.
+ * @param endpoint The endpoint.
+ *
+ * @return The user's endpoint data.
+ */
+MsnUserEndpoint *
+msn_user_get_endpoint_data(MsnUser *user, const char *endpoint);
+
+/**
* Returns the client id for a user.
*
* @param user The user.
@@ -355,6 +398,15 @@
guint msn_user_get_clientid(const MsnUser *user);
/**
+ * Returns the extended capabilities for a user.
+ *
+ * @param user The user.
+ *
+ * @return The user's extended capabilities.
+ */
+guint msn_user_get_extcaps(const MsnUser *user);
+
+/**
* Returns the network id for a user.
*
* @param user The user.
@@ -398,11 +450,24 @@
/**
* check to see if user is Yahoo User
*/
-gboolean msn_user_is_yahoo(PurpleAccount *account ,const char *name);
+gboolean msn_user_is_yahoo(PurpleAccount *account, const char *name);
void msn_user_set_op(MsnUser *user, MsnListOp list_op);
void msn_user_unset_op(MsnUser *user, MsnListOp list_op);
+/**
+ * Checks whether a user is capable of some task.
+ *
+ * @param user The user.
+ * @param endpoint The endpoint. Can be @NULL to check overall capabilities.
+ * @param capability The capability (including client version).
+ * @param extcap The extended capability.
+ *
+ * @return Whether the user supports the capability.
+ */
+gboolean
+msn_user_is_capable(MsnUser *user, char *endpoint, guint capability, guint extcap);
+
/*@}*/
#endif /* MSN_USER_H */