aboutsummaryrefslogtreecommitdiffstats
path: root/protocols/msn/ns.c
diff options
context:
space:
mode:
authordequis <dx@dxzone.com.ar>2015-03-19 07:48:48 -0300
committerdequis <dx@dxzone.com.ar>2015-04-10 14:10:41 -0300
commitcd5fdcf1b6b3ee4e5072e6332b6b8ef83dd5b2b3 (patch)
treee90900cb48408a2cdb0c3452df727488892b6cca /protocols/msn/ns.c
parent3058c309ef7a3ac35e8942a3c414fbc868cdffbf (diff)
msn: handle NFY PUT (presence notifications), refactor a bit
Diffstat (limited to 'protocols/msn/ns.c')
-rw-r--r--protocols/msn/ns.c131
1 files changed, 109 insertions, 22 deletions
diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c
index a9236b07..611c96e0 100644
--- a/protocols/msn/ns.c
+++ b/protocols/msn/ns.c
@@ -37,6 +37,9 @@ static gboolean msn_ns_callback(gpointer data, gint source, b_input_condition co
static void msn_ns_send_adl_start(struct im_connection *ic);
static void msn_ns_send_adl(struct im_connection *ic);
+static void msn_ns_structured_message(struct msn_data *handler, char *msg, int msglen, char **cmd);
+static void msn_ns_sdg(struct msn_data *handler, char *who, char **parts, char *action);
+static void msn_ns_nfy(struct msn_data *handler, char *who, char **parts, char *action, gboolean is_put);
int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...)
{
@@ -484,32 +487,116 @@ int msn_ns_message(struct msn_data *handler, char *msg, int msglen, char **cmd,
}
}
}
- } else if (strcmp(cmd[0], "SDG") == 0) {
- char **parts = g_strsplit(msg, "\r\n\r\n", 4);
- char *from = NULL;
- char *mt = NULL;
- char *who = NULL;
- char *s = NULL;
-
- if ((from = get_rfc822_header(parts[0], "From", 0)) &&
- (mt = get_rfc822_header(parts[2], "Message-Type", 0)) &&
- (s = strchr(from, ';'))) {
-
- who = g_strndup(from + 2, s - from - 2);
-
- if (strcmp(mt, "Control/Typing") == 0) {
- imcb_buddy_typing(ic, who, OPT_TYPING);
- } else if (strcmp(mt, "Text") == 0) {
- imcb_buddy_msg(ic, who, parts[3], 0, 0);
+ } else if ((strcmp(cmd[0], "SDG") == 0) || (strcmp(cmd[0], "NFY") == 0)) {
+ msn_ns_structured_message(handler, msg, msglen, cmd);
+ }
+
+ return 1;
+}
+
+static void msn_ns_structured_message(struct msn_data *handler, char *msg, int msglen, char **cmd)
+{
+ char **parts = NULL;
+ char *semicolon = NULL;
+ char *action = NULL;
+ char *from = NULL;
+ char *who = NULL;
+
+ parts = g_strsplit(msg, "\r\n\r\n", 4);
+
+ if (!(from = get_rfc822_header(parts[0], "From", 0))) {
+ goto cleanup;
+ }
+
+ /* either the semicolon or the end of the string */
+ semicolon = strchr(from, ';') ? : (from + strlen(from));
+
+ who = g_strndup(from + 2, semicolon - from - 2);
+
+ if ((strcmp(cmd[0], "SDG") == 0) && (action = get_rfc822_header(parts[2], "Message-Type", 0))) {
+ msn_ns_sdg(handler, who, parts, action);
+
+ } else if ((strcmp(cmd[0], "NFY") == 0) && (action = get_rfc822_header(parts[2], "Uri", 0))) {
+ gboolean is_put = (strcmp(cmd[1], "PUT") == 0);
+ msn_ns_nfy(handler, who, parts, action, is_put);
+ }
+
+cleanup:
+ g_strfreev(parts);
+ g_free(action);
+ g_free(from);
+ g_free(who);
+}
+
+static void msn_ns_sdg(struct msn_data *handler, char *who, char **parts, char *action)
+{
+ struct im_connection *ic = handler->ic;
+
+ if (strcmp(action, "Control/Typing") == 0) {
+ imcb_buddy_typing(ic, who, OPT_TYPING);
+ } else if (strcmp(action, "Text") == 0) {
+ imcb_buddy_msg(ic, who, parts[3], 0, 0);
+ }
+}
+
+static void msn_ns_nfy(struct msn_data *handler, char *who, char **parts, char *action, gboolean is_put)
+{
+ struct im_connection *ic = handler->ic;
+ struct xt_node *body = NULL;
+ struct xt_node *s = NULL;
+ const char *state = NULL;
+ char *nick = NULL;
+ char *psm = NULL;
+ int flags = OPT_LOGGED_IN;
+
+ if (strcmp(action, "/user") != 0) {
+ return;
+ }
+
+ if (!(body = xt_from_string(parts[3], 0))) {
+ goto cleanup;
+ }
+
+ s = body->children;
+ while ((s = xt_find_node(s, "s"))) {
+ struct xt_node *s2;
+ char *n = xt_find_attr(s, "n"); /* service name: IM, PE, etc */
+
+ if (strcmp(n, "IM") == 0) {
+ /* IM has basic presence information */
+ if (!is_put) {
+ /* NFY DEL with a <s> usually means log out from the last endpoint */
+ flags &= ~OPT_LOGGED_IN;
+ break;
+ }
+
+ s2 = xt_find_node(s->children, "Status");
+ if (s2 && s2->text_len) {
+ const struct msn_away_state *msn_state = msn_away_state_by_code(s2->text);
+ state = msn_state->name;
+ if (msn_state != msn_away_state_list) {
+ flags |= OPT_AWAY;
+ }
+ }
+ } else if (strcmp(n, "PE") == 0) {
+ if ((s2 = xt_find_node(s->children, "PSM")) && s2->text_len) {
+ psm = s2->text;
+ }
+ if ((s2 = xt_find_node(s->children, "FriendlyName")) && s2->text_len) {
+ nick = s2->text;
}
}
- g_free(from);
- g_free(mt);
- g_free(who);
- return 1;
+ s = s->next;
}
- return 1;
+ imcb_buddy_status(ic, who, flags, state, psm);
+
+ if (nick) {
+ imcb_rename_buddy(ic, who, nick);
+ }
+
+cleanup:
+ xt_free_node(body);
}
void msn_auth_got_passport_token(struct im_connection *ic, const char *token, const char *error)