static void purple_smileys_load(void) { xmlnode *root_node, *profile_node; xmlnode *smileyset_node = NULL; xmlnode *smiley_node; smileys_loaded = TRUE; root_node = purple_util_read_xml_from_file(XML_FILE_NAME, _(SMILEYS_LOG_ID)); if (root_node == NULL) return; /* See the top comments above to understand why initial tag elements * are not being considered by now. */ profile_node = xmlnode_get_child(root_node, XML_PROFILE_TAG); if (profile_node) smileyset_node = xmlnode_get_child(profile_node, XML_SMILEY_SET_TAG); if (smileyset_node) { smiley_node = xmlnode_get_child(smileyset_node, XML_SMILEY_TAG); for (; smiley_node != NULL; smiley_node = xmlnode_get_next_twin(smiley_node)) { PurpleSmiley *smiley; smiley = parse_smiley(smiley_node); } } xmlnode_free(root_node); }
static gfire_game *gfire_game_create_from_xml(xmlnode *p_node, gboolean *p_external) { gfire_game *ret = g_malloc0(sizeof(gfire_game)); if(xmlnode_get_attrib(p_node, "id")) sscanf(xmlnode_get_attrib(p_node, "id"), "%u", &ret->id); if(xmlnode_get_attrib(p_node, "name")) ret->name = g_strdup(xmlnode_get_attrib(p_node, "name")); if(xmlnode_get_attrib(p_node, "shortname")) ret->short_name = g_strdup(xmlnode_get_attrib(p_node, "shortname")); if(xmlnode_get_child(p_node, "voice")) ret->is_voice = TRUE; // Get all detection sets xmlnode *dset_node = xmlnode_get_child(p_node, "detection"); while(dset_node) { gfire_game_detection_set *dset = gfire_game_detection_set_create_from_xml(dset_node); if(dset) { ret->detection_sets = g_list_append(ret->detection_sets, dset); *p_external = (*p_external || dset->external); } dset_node = xmlnode_get_next_twin(dset_node); } return ret; }
static void shinima_message_links_foreach(gchar **message, void(*foreach_func)(xmlnode*, const gchar*, gchar**, gboolean*, gpointer), gboolean *_changed, gpointer *user_data) { xmlnode *root, *a; gboolean *changed = (_changed != NULL) ? changed : g_malloc(sizeof(gboolean)); g_return_if_fail(foreach_func != NULL); root = xmlnode_from_str(*message, -1); for(a=xmlnode_get_child(root, "a"); a; a=xmlnode_get_next_twin(a)) { const gchar *href = xmlnode_get_attrib(a, "href"); if(href) foreach_func(a, href, message, changed, user_data); } if(changed) { g_free(*message); *message = xmlnode_to_str(root, NULL); } if(_changed == NULL) g_free(changed); xmlnode_free(root); }
static void jabber_chat_room_configure_cb(JabberStream *js, xmlnode *packet, gpointer data) { xmlnode *query, *x; const char *type = xmlnode_get_attrib(packet, "type"); const char *from = xmlnode_get_attrib(packet, "from"); char *msg; JabberChat *chat; JabberID *jid; if(!type || !from) return; if(!strcmp(type, "result")) { jid = jabber_id_new(from); if(!jid) return; chat = jabber_chat_find(js, jid->node, jid->domain); jabber_id_free(jid); if(!chat) return; if(!(query = xmlnode_get_child(packet, "query"))) return; for(x = xmlnode_get_child(query, "x"); x; x = xmlnode_get_next_twin(x)) { const char *xmlns; if(!(xmlns = xmlnode_get_namespace(x))) continue; if(!strcmp(xmlns, "jabber:x:data")) { chat->config_dialog_type = PURPLE_REQUEST_FIELDS; chat->config_dialog_handle = jabber_x_data_request(js, x, jabber_chat_room_configure_x_data_cb, chat); return; } } } else if(!strcmp(type, "error")) { char *msg = jabber_parse_error(js, packet); purple_notify_error(js->gc, _("Configuration error"), _("Configuration error"), msg); if(msg) g_free(msg); return; } msg = g_strdup_printf("Unable to configure room %s", from); purple_notify_info(js->gc, _("Unable to configure"), _("Unable to configure"), msg); g_free(msg); }
static void roomlist_disco_result_cb(JabberStream *js, const char *from, JabberIqType type, const char *id, xmlnode *packet, gpointer data) { xmlnode *query; xmlnode *item; if(!js->roomlist) return; if (type == JABBER_IQ_ERROR) { char *err = jabber_parse_error(js, packet, NULL); purple_notify_error(js->gc, _("Error"), _("Error retrieving room list"), err); purple_roomlist_set_in_progress(js->roomlist, FALSE); purple_roomlist_unref(js->roomlist); js->roomlist = NULL; g_free(err); return; } if(!(query = xmlnode_get_child(packet, "query"))) { char *err = jabber_parse_error(js, packet, NULL); purple_notify_error(js->gc, _("Error"), _("Error retrieving room list"), err); purple_roomlist_set_in_progress(js->roomlist, FALSE); purple_roomlist_unref(js->roomlist); js->roomlist = NULL; g_free(err); return; } for(item = xmlnode_get_child(query, "item"); item; item = xmlnode_get_next_twin(item)) { const char *name; PurpleRoomlistRoom *room; JabberID *jid; if(!(jid = jabber_id_new(xmlnode_get_attrib(item, "jid")))) continue; name = xmlnode_get_attrib(item, "name"); room = purple_roomlist_room_new(PURPLE_ROOMLIST_ROOMTYPE_ROOM, jid->node, NULL); purple_roomlist_room_add_field(js->roomlist, room, jid->node); purple_roomlist_room_add_field(js->roomlist, room, jid->domain); purple_roomlist_room_add_field(js->roomlist, room, name ? name : ""); purple_roomlist_room_add(js->roomlist, room); jabber_id_free(jid); } purple_roomlist_set_in_progress(js->roomlist, FALSE); purple_roomlist_unref(js->roomlist); js->roomlist = NULL; }
gboolean gfire_game_load_config_xml(gboolean p_force) { if(!p_force && gfire_games_config) return TRUE; xmlnode *node = NULL; gchar *filename = g_build_filename(purple_user_dir(), "gfire_game_config.xml", NULL); if(filename) { purple_debug(PURPLE_DEBUG_INFO, "gfire", "Loading Game Launch Data from: %s\n", filename); g_free(filename); } node = purple_util_read_xml_from_file("gfire_game_config.xml", "Gfire Game Config List"); if(!node) { purple_debug(PURPLE_DEBUG_ERROR, "gfire", "gfire_game_load_config_xml: Couldn't load game config.\n"); return FALSE; } // Check for a valid game config if(g_utf8_collate(node->name, "game_config")) { xmlnode_free(node); return FALSE; } // Check for a valid version if(!xmlnode_get_attrib(node, "version") || g_utf8_collate(xmlnode_get_attrib(node, "version"), "2")) { xmlnode_free(node); return FALSE; } // Delete all old configurations gfire_game_config_cleanup(); // Parse all games xmlnode *game_node = xmlnode_get_child(node, "game"); while(game_node) { gfire_game_configuration *gconf = gfire_game_configuration_create_from_xml(game_node); if(gconf) gfire_games_config = g_list_append(gfire_games_config, gconf); game_node = xmlnode_get_next_twin(game_node); } gfire_game_config_sort(); xmlnode_free(node); return TRUE; }
static void jabber_chat_register_cb(JabberStream *js, const char *from, JabberIqType type, const char *id, xmlnode *packet, gpointer data) { xmlnode *query, *x; char *msg; JabberChat *chat; JabberID *jid; if (!from) return; if (type == JABBER_IQ_RESULT) { jid = jabber_id_new(from); if(!jid) return; chat = jabber_chat_find(js, jid->node, jid->domain); jabber_id_free(jid); if(!chat) return; if(!(query = xmlnode_get_child(packet, "query"))) return; for(x = xmlnode_get_child(query, "x"); x; x = xmlnode_get_next_twin(x)) { const char *xmlns; if(!(xmlns = xmlnode_get_namespace(x))) continue; if(!strcmp(xmlns, "jabber:x:data")) { jabber_x_data_request(js, x, jabber_chat_register_x_data_cb, chat); return; } } } else if (type == JABBER_IQ_ERROR) { char *msg = jabber_parse_error(js, packet, NULL); purple_notify_error(js->gc, _("Registration error"), _("Registration error"), msg); if(msg) g_free(msg); return; } msg = g_strdup_printf("Unable to configure room %s", from); purple_notify_info(js->gc, _("Unable to configure"), _("Unable to configure"), msg); g_free(msg); }
static void roomlist_disco_result_cb(JabberStream *js, xmlnode *packet, gpointer data) { xmlnode *query; xmlnode *item; const char *type; if(!js->roomlist) return; if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "result")) { char *err = jabber_parse_error(js,packet); gaim_notify_error(js->gc, _("Error"), _("Error retrieving room list"), err); gaim_roomlist_set_in_progress(js->roomlist, FALSE); gaim_roomlist_unref(js->roomlist); js->roomlist = NULL; g_free(err); return; } if(!(query = xmlnode_get_child(packet, "query"))) { char *err = jabber_parse_error(js, packet); gaim_notify_error(js->gc, _("Error"), _("Error retrieving room list"), err); gaim_roomlist_set_in_progress(js->roomlist, FALSE); gaim_roomlist_unref(js->roomlist); js->roomlist = NULL; g_free(err); return; } for(item = xmlnode_get_child(query, "item"); item; item = xmlnode_get_next_twin(item)) { const char *name; GaimRoomlistRoom *room; JabberID *jid; if(!(jid = jabber_id_new(xmlnode_get_attrib(item, "jid")))) continue; name = xmlnode_get_attrib(item, "name"); room = gaim_roomlist_room_new(GAIM_ROOMLIST_ROOMTYPE_ROOM, jid->node, NULL); gaim_roomlist_room_add_field(js->roomlist, room, jid->node); gaim_roomlist_room_add_field(js->roomlist, room, jid->domain); gaim_roomlist_room_add_field(js->roomlist, room, name ? name : ""); gaim_roomlist_room_add(js->roomlist, room); jabber_id_free(jid); } gaim_roomlist_set_in_progress(js->roomlist, FALSE); gaim_roomlist_unref(js->roomlist); js->roomlist = NULL; }
gboolean gfire_game_load_games_xml() { xmlnode *node = NULL; gchar *filename = g_build_filename(purple_user_dir(), "gfire_games.xml", NULL); if(filename) { purple_debug(PURPLE_DEBUG_INFO, "gfire", "Loading Game Data from: %s\n", filename); g_free(filename); } node = purple_util_read_xml_from_file("gfire_games.xml", "Gfire Games List"); if(!node) { purple_debug(PURPLE_DEBUG_ERROR, "gfire", "gfire_game_load_games_xml: Couldn't load game list.\n"); return FALSE; } // Delete all old games gfire_game_cleanup(); // Read the games version if(g_utf8_collate(node->name, "games")) { xmlnode_free(node); return FALSE; } if(!xmlnode_get_attrib(node, "version")) gfire_games_version = 0; else sscanf(xmlnode_get_attrib(node, "version"), "%u", &gfire_games_version); // Read all games xmlnode *game_node = xmlnode_get_child(node, "game"); while(game_node) { gboolean external = FALSE; gfire_game *game = gfire_game_create_from_xml(game_node, &external); if(game) { gfire_games = g_list_append(gfire_games, game); if(external) gfire_games_external = g_list_append(gfire_games_external, game); } game_node = xmlnode_get_next_twin(game_node); } xmlnode_free(node); return TRUE; }
static void jingle_handle_content_accept(JingleSession *session, xmlnode *jingle) { xmlnode *content = xmlnode_get_child(jingle, "content"); jabber_iq_send(jingle_session_create_ack(session, jingle)); for (; content; content = xmlnode_get_next_twin(content)) { const gchar *name = xmlnode_get_attrib(content, "name"); const gchar *creator = xmlnode_get_attrib(content, "creator"); jingle_session_accept_content(session, name, creator); /* signal here */ } }
void jabber_bytestreams_parse(JabberStream *js, xmlnode *packet) { GaimXfer *xfer; JabberSIXfer *jsx; xmlnode *query, *streamhost; const char *sid, *from, *type; if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "set")) return; if(!(from = xmlnode_get_attrib(packet, "from"))) return; if(!(query = xmlnode_get_child(packet, "query"))) return; if(!(sid = xmlnode_get_attrib(query, "sid"))) return; if(!(xfer = jabber_si_xfer_find(js, sid, from))) return; jsx = xfer->data; if(!jsx->accepted) return; if(jsx->iq_id) g_free(jsx->iq_id); jsx->iq_id = g_strdup(xmlnode_get_attrib(packet, "id")); for(streamhost = xmlnode_get_child(query, "streamhost"); streamhost; streamhost = xmlnode_get_next_twin(streamhost)) { const char *jid, *host, *port; int portnum; if((jid = xmlnode_get_attrib(streamhost, "jid")) && (host = xmlnode_get_attrib(streamhost, "host")) && (port = xmlnode_get_attrib(streamhost, "port")) && (portnum = atoi(port))) { struct bytestreams_streamhost *sh = g_new0(struct bytestreams_streamhost, 1); sh->jid = g_strdup(jid); sh->host = g_strdup(host); sh->port = portnum; jsx->streamhosts = g_list_append(jsx->streamhosts, sh); } } jabber_si_bytestreams_attempt_connect(xfer); }
static void jingle_handle_transport_reject(JingleSession *session, xmlnode *jingle) { xmlnode *content = xmlnode_get_child(jingle, "content"); jabber_iq_send(jingle_session_create_ack(session, jingle)); for (; content; content = xmlnode_get_next_twin(content)) { const gchar *name = xmlnode_get_attrib(content, "name"); const gchar *creator = xmlnode_get_attrib(content, "creator"); JingleContent *content = jingle_session_find_content(session, name, creator); jingle_content_remove_pending_transport(content); } }
static JabberSaslState jabber_cyrus_start(JabberStream *js, xmlnode *mechanisms, xmlnode **reply, char **error) { xmlnode *mechnode; JabberSaslState ret; js->sasl_mechs = g_string_new(""); for(mechnode = xmlnode_get_child(mechanisms, "mechanism"); mechnode; mechnode = xmlnode_get_next_twin(mechnode)) { char *mech_name = xmlnode_get_data(mechnode); /* Ignore blank mechanisms and EXTERNAL. External isn't * supported, and Cyrus SASL's mechanism returns * SASL_NOMECH when the caller (us) doesn't configure it. * Except SASL_NOMECH is supposed to mean "no concordant * mechanisms"... Easiest just to blacklist it (for now). */ if (!mech_name || !*mech_name || g_str_equal(mech_name, "EXTERNAL")) { g_free(mech_name); continue; } g_string_append(js->sasl_mechs, mech_name); g_string_append_c(js->sasl_mechs, ' '); g_free(mech_name); } /* Strip off the trailing ' ' */ if (js->sasl_mechs->len > 1) g_string_truncate(js->sasl_mechs, js->sasl_mechs->len - 1); jabber_sasl_build_callbacks(js); ret = jabber_auth_start_cyrus(js, reply, error); /* * Triggered if no overlap between server and client * supported mechanisms. */ if (ret == JABBER_SASL_STATE_FAIL && *error == NULL) *error = g_strdup(_("Server does not use any supported authentication method")); return ret; }
static gboolean __xep_bytestreams_parse(PurpleBuddy *pb, PurpleXfer *xfer, xmlnode *streamhost, const char *iq_id) { char *tmp_iq_id; const char *jid, *host, *port; int portnum; XepXfer *xf = NULL; xf = (XepXfer*)xfer->data; for(; streamhost; streamhost = xmlnode_get_next_twin(streamhost)) { if(!(jid = xmlnode_get_attrib(streamhost, "jid")) || !(host = xmlnode_get_attrib(streamhost, "host")) || !(port = xmlnode_get_attrib(streamhost, "port")) || !(portnum = atoi(port))) { purple_debug_info("bonjour", "bytestream offer Message parse error.\n"); continue; } /* skip IPv6 link local addresses with no interface scope * (but try to add a new one with an interface scope then) */ if(add_ipv6_link_local_ifaces(streamhost, host, pb)) continue; tmp_iq_id = g_strdup(iq_id); g_free(xf->iq_id); g_free(xf->jid); g_free(xf->proxy_host); xf->iq_id = tmp_iq_id; xf->jid = g_strdup(jid); xf->proxy_host = g_strdup(host); xf->proxy_port = portnum; xf->streamhost = streamhost; xf->pb = pb; purple_debug_info("bonjour", "bytestream offer parse" "jid=%s host=%s port=%d.\n", jid, host, portnum); bonjour_bytestreams_connect(xfer); return TRUE; } return FALSE; }
static void jingle_handle_session_initiate(JingleSession *session, xmlnode *jingle) { xmlnode *content = xmlnode_get_child(jingle, "content"); for (; content; content = xmlnode_get_next_twin(content)) { JingleContent *parsed_content = jingle_content_parse(content); if (parsed_content == NULL) { purple_debug_error("jingle", "Error parsing content\n"); /* XXX: send error */ } else { jingle_session_add_content(session, parsed_content); jingle_content_handle_action(parsed_content, content, JINGLE_SESSION_INITIATE); } } jabber_iq_send(jingle_session_create_ack(session, jingle)); }
static void bonjour_bytestreams_connect_cb(gpointer data, gint source, const gchar *error_message) { PurpleXfer *xfer = data; XepXfer *xf = xfer->data; XepIq *iq; xmlnode *q_node, *tmp_node; BonjourData *bd; gboolean ret = FALSE; xf->proxy_connection = NULL; if(source < 0) { purple_debug_error("bonjour", "Error connecting via SOCKS5 to %s - %s\n", xf->proxy_host, error_message ? error_message : "(null)"); tmp_node = xmlnode_get_next_twin(xf->streamhost); ret = __xep_bytestreams_parse(xf->pb, xfer, tmp_node, xf->iq_id); if (!ret) { xep_ft_si_reject(xf->data, xf->iq_id, purple_xfer_get_remote_user(xfer), "404", "cancel"); /* Cancel the connection */ purple_xfer_cancel_local(xfer); } return; } purple_debug_info("bonjour", "Connected successfully via SOCKS5, starting transfer.\n"); bd = xf->data; /* Here, start the file transfer.*/ /* Notify Initiator of Connection */ iq = xep_iq_new(bd, XEP_IQ_RESULT, xfer->who, bonjour_get_jid(bd->jabber_data->account), xf->iq_id); q_node = xmlnode_new_child(iq->node, "query"); xmlnode_set_namespace(q_node, "http://jabber.org/protocol/bytestreams"); tmp_node = xmlnode_new_child(q_node, "streamhost-used"); xmlnode_set_attrib(tmp_node, "jid", xf->jid); xep_iq_send_and_free(iq); purple_xfer_start(xfer, source, NULL, -1); }
static void jingle_handle_content_add(JingleSession *session, xmlnode *jingle) { xmlnode *content = xmlnode_get_child(jingle, "content"); jabber_iq_send(jingle_session_create_ack(session, jingle)); for (; content; content = xmlnode_get_next_twin(content)) { JingleContent *pending_content = jingle_content_parse(content); if (pending_content == NULL) { purple_debug_error("jingle", "Error parsing \"content-add\" content.\n"); /* XXX: send error here */ } else { jingle_session_add_pending_content(session, pending_content); } } /* XXX: signal here */ }
static void jingle_handle_transport_info(JingleSession *session, xmlnode *jingle) { xmlnode *content = xmlnode_get_child(jingle, "content"); jabber_iq_send(jingle_session_create_ack(session, jingle)); for (; content; content = xmlnode_get_next_twin(content)) { const gchar *name = xmlnode_get_attrib(content, "name"); const gchar *creator = xmlnode_get_attrib(content, "creator"); JingleContent *parsed_content = jingle_session_find_content(session, name, creator); if (parsed_content == NULL) { purple_debug_error("jingle", "Error parsing content\n"); /* XXX: send error */ } else { jingle_content_handle_action(parsed_content, content, JINGLE_TRANSPORT_INFO); } } }
static void jabber_chat_affiliation_list_cb(JabberStream *js, const char *from, JabberIqType type, const char *id, xmlnode *packet, gpointer data) { JabberChat *chat; xmlnode *query, *item; int chat_id = GPOINTER_TO_INT(data); GString *buf; if(!(chat = jabber_chat_find_by_id(js, chat_id))) return; if (type == JABBER_IQ_ERROR) return; if(!(query = xmlnode_get_child(packet, "query"))) return; buf = g_string_new(_("Affiliations:")); item = xmlnode_get_child(query, "item"); if (item) { for( ; item; item = xmlnode_get_next_twin(item)) { const char *jid = xmlnode_get_attrib(item, "jid"); const char *affiliation = xmlnode_get_attrib(item, "affiliation"); if (jid && affiliation) g_string_append_printf(buf, "\n%s %s", jid, affiliation); } } else { buf = g_string_append_c(buf, '\n'); buf = g_string_append_len(buf, _("No users found"), -1); } purple_conv_chat_write(PURPLE_CONV_CHAT(chat->conv), "", buf->str, PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG, time(NULL)); g_string_free(buf, TRUE); }
static void jabber_si_xfer_send_method_cb(JabberStream *js, xmlnode *packet, gpointer data) { GaimXfer *xfer = data; xmlnode *si, *feature, *x, *field, *value; if(!(si = xmlnode_get_child_with_namespace(packet, "si", "http://jabber.org/protocol/si"))) { gaim_xfer_cancel_remote(xfer); return; } if(!(feature = xmlnode_get_child_with_namespace(si, "feature", "http://jabber.org/protocol/feature-neg"))) { gaim_xfer_cancel_remote(xfer); return; } if(!(x = xmlnode_get_child_with_namespace(feature, "x", "jabber:x:data"))) { gaim_xfer_cancel_remote(xfer); return; } for(field = xmlnode_get_child(x, "field"); field; field = xmlnode_get_next_twin(field)) { const char *var = xmlnode_get_attrib(field, "var"); if(var && !strcmp(var, "stream-method")) { if((value = xmlnode_get_child(field, "value"))) { char *val = xmlnode_get_data(value); if(val && !strcmp(val, "http://jabber.org/protocol/bytestreams")) { jabber_si_xfer_bytestreams_send_init(xfer); g_free(val); return; } g_free(val); } } } gaim_xfer_cancel_remote(xfer); }
static void jabber_chat_disco_traffic_cb(JabberStream *js, const char *from, JabberIqType type, const char *id, xmlnode *packet, gpointer data) { JabberChat *chat; #if 0 xmlnode *query, *x; #endif int chat_id = GPOINTER_TO_INT(data); if(!(chat = jabber_chat_find_by_id(js, chat_id))) return; /* defaults, in case the conference server doesn't * support this request */ chat->xhtml = TRUE; /* disabling this until more MUC servers support * announcing this */ #if 0 if (type == JABBER_IQ_ERROR) { return; } if(!(query = xmlnode_get_child(packet, "query"))) return; chat->xhtml = FALSE; for(x = xmlnode_get_child(query, "feature"); x; x = xmlnode_get_next_twin(x)) { const char *var = xmlnode_get_attrib(x, "var"); if(var && !strcmp(var, NS_XHTML_IM)) { chat->xhtml = TRUE; } } #endif }
static void jingle_handle_content_modify(JingleSession *session, xmlnode *jingle) { xmlnode *content = xmlnode_get_child(jingle, "content"); jabber_iq_send(jingle_session_create_ack(session, jingle)); for (; content; content = xmlnode_get_next_twin(content)) { const gchar *name = xmlnode_get_attrib(content, "name"); const gchar *creator = xmlnode_get_attrib(content, "creator"); JingleContent *local_content = jingle_session_find_content(session, name, creator); if (local_content != NULL) { const gchar *senders = xmlnode_get_attrib(content, "senders"); gchar *local_senders = jingle_content_get_senders(local_content); if (strcmp(senders, local_senders)) jingle_content_modify(local_content, senders); g_free(local_senders); } else { purple_debug_error("jingle", "content_modify: unknown content\n"); /* XXX: send error */ } } }
static void jingle_handle_session_accept(JingleSession *session, xmlnode *jingle) { xmlnode *content = xmlnode_get_child(jingle, "content"); jabber_iq_send(jingle_session_create_ack(session, jingle)); jingle_session_accept_session(session); for (; content; content = xmlnode_get_next_twin(content)) { const gchar *name = xmlnode_get_attrib(content, "name"); const gchar *creator = xmlnode_get_attrib(content, "creator"); JingleContent *parsed_content = jingle_session_find_content(session, name, creator); if (parsed_content == NULL) { purple_debug_error("jingle", "Error parsing content\n"); jabber_iq_send(jingle_session_terminate_packet(session, "unsupported-applications")); } else { jingle_content_handle_action(parsed_content, content, JINGLE_SESSION_ACCEPT); } } }
gboolean GetContactList_cb(struct fetion_account_data *sip, struct sipmsg *msg, struct transaction *tc) { xmlnode *item, *group, *isc; const gchar *name_group, *group_id; PurpleBuddy *b; PurpleGroup *g = NULL; struct fetion_buddy *bs; struct group_attr *g_attr; gint len = msg->bodylen; purple_debug(PURPLE_DEBUG_MISC, "fetion", "in process GetContactList response response: %d\n", msg->response); switch (msg->response) { case 200: /*Convert the contact from XML to Purple Buddies */ isc = xmlnode_from_str(msg->body, len); purple_debug_info("fetion:", "after xmlnode to str\n"); group = xmlnode_get_child(isc, "contacts/buddy-lists"); g_return_val_if_fail(group != NULL, FALSE); /* ToDo. Find for all groups */ sip->GetContactFlag = 1; for ((group = xmlnode_get_child(group, "buddy-list")); group; group = xmlnode_get_next_twin(group)) { purple_debug_info("fetion:", "buddy-list\n"); name_group = xmlnode_get_attrib(group, "name"); group_id = xmlnode_get_attrib(group, "id"); g_return_val_if_fail(name_group != NULL, FALSE); purple_debug_info("fetion", "name_group->%s\n", name_group); g = purple_find_group(name_group); if (!g) { g = purple_group_new(name_group); } g_attr = g_new0(struct group_attr, 1); g_attr->name = g_strdup(name_group); g_attr->id = g_strdup(group_id); g_hash_table_insert(sip->group, g_attr->id, g_attr); g_hash_table_insert(sip->group2id, g_attr->name, g_attr); } group = xmlnode_get_child(isc, "contacts/buddies"); g_return_val_if_fail(group != NULL, FALSE); for (item = xmlnode_get_child(group, "buddy"); item; item = xmlnode_get_next_twin(item)) { const gchar *uri, *name; char *buddy_name; const gchar *g_id; uri = xmlnode_get_attrib(item, "uri"); name = xmlnode_get_attrib(item, "local-name"); g_id = xmlnode_get_attrib(item, "buddy-lists"); buddy_name = g_strdup_printf("%s", uri); if ((g_id == NULL) || (*g_id == '\0') || strlen(g_id) > 1) { g = purple_find_group("未分组"); if (!g) g = purple_group_new("未分组"); } else { g_attr = g_hash_table_lookup(sip->group, g_id); g_return_val_if_fail(g_attr != NULL, FALSE); g = purple_find_group(g_attr->name); if (!g) g = purple_group_new(g_attr->name); } b = purple_find_buddy(sip->account, buddy_name); if (!b) { b = purple_buddy_new(sip->account, buddy_name, NULL); } g_free(buddy_name); purple_blist_add_buddy(b, NULL, g, NULL); if (name != NULL && *name != '\0') purple_blist_alias_buddy(b, name); bs = g_new0(struct fetion_buddy, 1); bs->name = g_strdup(b->name); g_hash_table_insert(sip->buddies, bs->name, bs); purple_prpl_got_user_status(sip->account, uri, "mobile", NULL); } group = xmlnode_get_child(isc, "contacts/mobile-buddies"); g_return_val_if_fail(group != NULL, FALSE); for (item = xmlnode_get_child(group, "mobile-buddy"); item; item = xmlnode_get_next_twin(item)) { const gchar *uri, *name; gchar *buddy_name; const gchar *g_id; uri = xmlnode_get_attrib(item, "uri"); name = xmlnode_get_attrib(item, "local-name"); g_id = xmlnode_get_attrib(item, "buddy-lists"); buddy_name = g_strdup_printf("%s", uri); if ((g_id == NULL) || (*g_id == '\0') || strlen(g_id) > 1) { g = purple_find_group("未分组"); if (!g) g = purple_group_new("未分组"); } else { g_attr = g_hash_table_lookup(sip->group, g_id); //g_return_val_if_fail(g_attr!=NULL,FALSE); if (g_attr == NULL) continue; g = purple_find_group(g_attr->name); if (!g) g = purple_group_new(g_attr->name); } b = purple_find_buddy(sip->account, buddy_name); if (!b) { b = purple_buddy_new(sip->account, buddy_name, uri); } g_free(buddy_name); purple_blist_add_buddy(b, NULL, g, NULL); if (name != NULL && *name != '\0') purple_blist_alias_buddy(b, name); else purple_blist_alias_buddy(b, uri); bs = g_new0(struct fetion_buddy, 1); bs->name = g_strdup(b->name); g_hash_table_insert(sip->buddies, bs->name, bs); purple_prpl_got_user_status(sip->account, uri, "mobile", NULL); } fetion_subscribe_exp(sip, NULL); //Add youself b = purple_find_buddy(sip->account, sip->uri); if (!b) { b = purple_buddy_new(sip->account, sip->uri, NULL); } purple_blist_add_buddy(b, NULL, g, NULL); purple_blist_alias_buddy(b, "轰炸自己"); bs = g_new0(struct fetion_buddy, 1); bs->name = g_strdup(b->name); g_hash_table_insert(sip->buddies, bs->name, bs); purple_prpl_got_user_status(sip->account, sip->uri, "mobile", NULL); xmlnode_free(isc); break; default: GetContactList(sip); break; } return TRUE; }
void jabber_roster_parse(JabberStream *js, const char *from, JabberIqType type, const char *id, xmlnode *query) { xmlnode *item, *group; if (!jabber_is_own_account(js, from)) { purple_debug_warning("jabber", "Received bogon roster push from %s\n", from); return; } js->currently_parsing_roster_push = TRUE; for(item = xmlnode_get_child(query, "item"); item; item = xmlnode_get_next_twin(item)) { const char *jid, *name, *subscription, *ask; JabberBuddy *jb; subscription = xmlnode_get_attrib(item, "subscription"); jid = xmlnode_get_attrib(item, "jid"); name = xmlnode_get_attrib(item, "name"); ask = xmlnode_get_attrib(item, "ask"); if(!jid) continue; if(!(jb = jabber_buddy_find(js, jid, TRUE))) continue; if(subscription) { if (jb == js->user_jb) jb->subscription = JABBER_SUB_BOTH; else if(!strcmp(subscription, "none")) jb->subscription = JABBER_SUB_NONE; else if(!strcmp(subscription, "to")) jb->subscription = JABBER_SUB_TO; else if(!strcmp(subscription, "from")) jb->subscription = JABBER_SUB_FROM; else if(!strcmp(subscription, "both")) jb->subscription = JABBER_SUB_BOTH; else if(!strcmp(subscription, "remove")) jb->subscription = JABBER_SUB_REMOVE; } if(purple_strequal(ask, "subscribe")) jb->subscription |= JABBER_SUB_PENDING; else jb->subscription &= ~JABBER_SUB_PENDING; if(jb->subscription & JABBER_SUB_REMOVE) { remove_purple_buddies(js, jid); } else { GSList *groups = NULL; gboolean seen_empty = FALSE; if (js->server_caps & JABBER_CAP_GOOGLE_ROSTER) if (!jabber_google_roster_incoming(js, item)) continue; for(group = xmlnode_get_child(item, "group"); group; group = xmlnode_get_next_twin(group)) { char *group_name = xmlnode_get_data(group); if (!group_name && !seen_empty) { group_name = g_strdup(""); seen_empty = TRUE; } groups = g_slist_prepend(groups, group_name); } add_purple_buddy_to_groups(js, jid, name, groups); if (jb == js->user_jb) jabber_presence_fake_to_self(js, NULL); } } js->currently_parsing_roster_push = FALSE; /* if we're just now parsing the roster for the first time, * then now would be the time to declare ourselves connected. */ if (js->state != JABBER_STREAM_CONNECTED) jabber_stream_set_state(js, JABBER_STREAM_CONNECTED); }
static void nexus_got_update_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) { MsnNexusUpdateData *ud = data; MsnNexus *nexus = ud->nexus; char iv[8] = {0,0,0,0,0,0,0,0}; xmlnode *enckey; char *tmp; char *nonce; gsize len; char *key; GSList *updates; #if 0 char *decrypted_pp; #endif char *decrypted_data; if (resp == NULL) return; purple_debug_info("msn", "Got Update Response for %s.\n", ticket_domains[ud->id][SSO_VALID_TICKET_DOMAIN]); enckey = xmlnode_get_child(resp->xml, "Header/Security/DerivedKeyToken"); while (enckey) { if (g_str_equal(xmlnode_get_attrib(enckey, "Id"), "EncKey")) break; enckey = xmlnode_get_next_twin(enckey); } if (!enckey) { purple_debug_error("msn", "Invalid response in token update.\n"); return; } tmp = xmlnode_get_data(xmlnode_get_child(enckey, "Nonce")); nonce = (char *)purple_base64_decode(tmp, &len); key = rps_create_key(nexus->secret, 24, nonce, len); g_free(tmp); g_free(nonce); #if 0 /* Don't know what this is for yet */ tmp = xmlnode_get_data(xmlnode_get_child(resp->xml, "Header/EncryptedPP/EncryptedData/CipherData/CipherValue")); if (tmp) { decrypted_pp = des3_cbc(key, iv, tmp, len, TRUE); g_free(tmp); purple_debug_info("msn", "Got Response Header EncryptedPP: %s\n", decrypted_pp); g_free(decrypted_pp); } #endif tmp = xmlnode_get_data(xmlnode_get_child(resp->xml, "Body/EncryptedData/CipherData/CipherValue")); if (tmp) { char *unescaped; xmlnode *rstresponse; unescaped = (char *)purple_base64_decode(tmp, &len); g_free(tmp); decrypted_data = des3_cbc(key, iv, unescaped, len, TRUE); g_free(unescaped); purple_debug_info("msn", "Got Response Body EncryptedData: %s\n", decrypted_data); rstresponse = xmlnode_from_str(decrypted_data, -1); if (g_str_equal(rstresponse->name, "RequestSecurityTokenResponse")) nexus_parse_token(nexus, ud->id, rstresponse); else nexus_parse_collection(nexus, ud->id, rstresponse); g_free(decrypted_data); } updates = nexus->tokens[ud->id].updates; nexus->tokens[ud->id].updates = NULL; while (updates != NULL) { MsnNexusUpdateCallback *update = updates->data; if (update->cb) purple_timeout_add(0, update->cb, update->data); g_free(update); updates = g_slist_delete_link(updates, updates); } g_free(ud); g_free(key); }
static void msn_parse_oim_xml(MsnOim *oim, xmlnode *node) { xmlnode *mNode; xmlnode *iu_node; MsnSession *session = oim->session; g_return_if_fail(node != NULL); if (strcmp(node->name, "MD") != 0) { char *xmlmsg = xmlnode_to_str(node, NULL); purple_debug_info("msn", "WTF is this? %s\n", xmlmsg); g_free(xmlmsg); return; } iu_node = xmlnode_get_child(node, "E/IU"); if (iu_node != NULL && purple_account_get_check_mail(session->account)) { char *unread = 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); /* XXX/khc: pretty sure this is wrong */ if (count > 0) purple_notify_emails(session->account->gc, count, FALSE, NULL, NULL, passports, urls, NULL, NULL); g_free(unread); } for(mNode = xmlnode_get_child(node, "M"); mNode; mNode = xmlnode_get_next_twin(mNode)){ char *passport, *msgid, *nickname, *rtime = NULL; xmlnode *e_node, *i_node, *n_node, *rt_node; e_node = xmlnode_get_child(mNode, "E"); passport = xmlnode_get_data(e_node); i_node = xmlnode_get_child(mNode, "I"); msgid = xmlnode_get_data(i_node); n_node = xmlnode_get_child(mNode, "N"); nickname = xmlnode_get_data(n_node); rt_node = xmlnode_get_child(mNode, "RT"); if (rt_node != NULL) { rtime = xmlnode_get_data(rt_node); } /* purple_debug_info("msn", "E:{%s},I:{%s},rTime:{%s}\n",passport,msgid,rTime); */ if (!g_list_find_custom(oim->oim_list, msgid, (GCompareFunc)msn_recv_data_equal)) { MsnOimRecvData *data = msn_oim_recv_data_new(oim, msgid); msn_oim_post_single_get_msg(oim, data); msgid = NULL; } g_free(passport); g_free(msgid); g_free(rtime); g_free(nickname); } }
static void google_session_handle_candidates(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id) { JabberIq *result; GList *list = NULL, *video_list = NULL; xmlnode *cand; static int name = 0; char n[4]; GoogleAVSessionData *session_data = (GoogleAVSessionData *) session->session_data; for (cand = xmlnode_get_child(sess, "candidate"); cand; cand = xmlnode_get_next_twin(cand)) { PurpleMediaCandidate *info; const gchar *cname = xmlnode_get_attrib(cand, "name"); const gchar *type = xmlnode_get_attrib(cand, "type"); const gchar *protocol = xmlnode_get_attrib(cand, "protocol"); const gchar *address = xmlnode_get_attrib(cand, "address"); const gchar *port = xmlnode_get_attrib(cand, "port"); const gchar *preference = xmlnode_get_attrib(cand, "preference"); guint component_id; if (cname && type && address && port) { PurpleMediaCandidateType candidate_type; guint prio = preference ? g_ascii_strtod(preference, NULL) * 1000 : 0; g_snprintf(n, sizeof(n), "S%d", name++); if (g_str_equal(type, "local")) candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_HOST; else if (g_str_equal(type, "stun")) candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX; else if (g_str_equal(type, "relay")) candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_RELAY; else candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_HOST; if (purple_strequal(cname, "rtcp") || purple_strequal(cname, "video_rtcp")) component_id = PURPLE_MEDIA_COMPONENT_RTCP; else component_id = PURPLE_MEDIA_COMPONENT_RTP; info = purple_media_candidate_new(n, component_id, candidate_type, purple_strequal(protocol, "udp") ? PURPLE_MEDIA_NETWORK_PROTOCOL_UDP : PURPLE_MEDIA_NETWORK_PROTOCOL_TCP, address, atoi(port)); g_object_set(info, "username", xmlnode_get_attrib(cand, "username"), "password", xmlnode_get_attrib(cand, "password"), "priority", prio, NULL); if (!strncmp(cname, "video_", 6)) { if (session_data->added_streams) { video_list = g_list_append(video_list, info); } else { session_data->remote_video_candidates = g_list_append(session_data->remote_video_candidates, info); } } else { if (session_data->added_streams) { list = g_list_append(list, info); } else { session_data->remote_audio_candidates = g_list_append(session_data->remote_audio_candidates, info); } } } } if (list) { purple_media_add_remote_candidates(session_data->media, "google-voice", session->remote_jid, list); purple_media_candidate_list_free(list); } if (video_list) { purple_media_add_remote_candidates(session_data->media, "google-video", session->remote_jid, video_list); purple_media_candidate_list_free(video_list); } result = jabber_iq_new(js, JABBER_IQ_RESULT); jabber_iq_set_id(result, iq_id); xmlnode_set_attrib(result->node, "to", session->remote_jid); jabber_iq_send(result); }
static gchar* purple_upnp_parse_description_response(const gchar* httpResponse, gsize len, const gchar* httpURL, const gchar* serviceType) { gchar *xmlRoot, *baseURL, *controlURL, *service; xmlnode *xmlRootNode, *serviceTypeNode, *controlURLNode, *baseURLNode; char *tmp; /* make sure we have a valid http response */ if(g_strstr_len(httpResponse, len, HTTP_OK) == NULL) { purple_debug_error("upnp", "parse_description_response(): Failed In HTTP_OK\n"); return NULL; } /* find the root of the xml document */ if((xmlRoot = g_strstr_len(httpResponse, len, "<root")) == NULL) { purple_debug_error("upnp", "parse_description_response(): Failed finding root\n"); return NULL; } /* create the xml root node */ if((xmlRootNode = xmlnode_from_str(xmlRoot, len - (xmlRoot - httpResponse))) == NULL) { purple_debug_error("upnp", "parse_description_response(): Could not parse xml root node\n"); return NULL; } /* get the baseURL of the device */ if((baseURLNode = xmlnode_get_child(xmlRootNode, "URLBase")) != NULL) { baseURL = xmlnode_get_data(baseURLNode); } else { baseURL = g_strdup(httpURL); } /* get the serviceType child that has the service type as its data */ /* get urn:schemas-upnp-org:device:InternetGatewayDevice:1 and its devicelist */ serviceTypeNode = xmlnode_get_child(xmlRootNode, "device"); while(!purple_upnp_compare_device(serviceTypeNode, "urn:schemas-upnp-org:device:InternetGatewayDevice:1") && serviceTypeNode != NULL) { serviceTypeNode = xmlnode_get_next_twin(serviceTypeNode); } if(serviceTypeNode == NULL) { purple_debug_error("upnp", "parse_description_response(): could not get serviceTypeNode 1\n"); g_free(baseURL); xmlnode_free(xmlRootNode); return NULL; } serviceTypeNode = xmlnode_get_child(serviceTypeNode, "deviceList"); if(serviceTypeNode == NULL) { purple_debug_error("upnp", "parse_description_response(): could not get serviceTypeNode 2\n"); g_free(baseURL); xmlnode_free(xmlRootNode); return NULL; } /* get urn:schemas-upnp-org:device:WANDevice:1 and its devicelist */ serviceTypeNode = xmlnode_get_child(serviceTypeNode, "device"); while(!purple_upnp_compare_device(serviceTypeNode, "urn:schemas-upnp-org:device:WANDevice:1") && serviceTypeNode != NULL) { serviceTypeNode = xmlnode_get_next_twin(serviceTypeNode); } if(serviceTypeNode == NULL) { purple_debug_error("upnp", "parse_description_response(): could not get serviceTypeNode 3\n"); g_free(baseURL); xmlnode_free(xmlRootNode); return NULL; } serviceTypeNode = xmlnode_get_child(serviceTypeNode, "deviceList"); if(serviceTypeNode == NULL) { purple_debug_error("upnp", "parse_description_response(): could not get serviceTypeNode 4\n"); g_free(baseURL); xmlnode_free(xmlRootNode); return NULL; } /* get urn:schemas-upnp-org:device:WANConnectionDevice:1 and its servicelist */ serviceTypeNode = xmlnode_get_child(serviceTypeNode, "device"); while(serviceTypeNode && !purple_upnp_compare_device(serviceTypeNode, "urn:schemas-upnp-org:device:WANConnectionDevice:1")) { serviceTypeNode = xmlnode_get_next_twin(serviceTypeNode); } if(serviceTypeNode == NULL) { purple_debug_error("upnp", "parse_description_response(): could not get serviceTypeNode 5\n"); g_free(baseURL); xmlnode_free(xmlRootNode); return NULL; } serviceTypeNode = xmlnode_get_child(serviceTypeNode, "serviceList"); if(serviceTypeNode == NULL) { purple_debug_error("upnp", "parse_description_response(): could not get serviceTypeNode 6\n"); g_free(baseURL); xmlnode_free(xmlRootNode); return NULL; } /* get the serviceType variable passed to this function */ service = g_strdup_printf(SEARCH_REQUEST_DEVICE, serviceType); serviceTypeNode = xmlnode_get_child(serviceTypeNode, "service"); while(!purple_upnp_compare_service(serviceTypeNode, service) && serviceTypeNode != NULL) { serviceTypeNode = xmlnode_get_next_twin(serviceTypeNode); } g_free(service); if(serviceTypeNode == NULL) { purple_debug_error("upnp", "parse_description_response(): could not get serviceTypeNode 7\n"); g_free(baseURL); xmlnode_free(xmlRootNode); return NULL; } /* get the controlURL of the service */ if((controlURLNode = xmlnode_get_child(serviceTypeNode, "controlURL")) == NULL) { purple_debug_error("upnp", "parse_description_response(): Could not find controlURL\n"); g_free(baseURL); xmlnode_free(xmlRootNode); return NULL; } tmp = xmlnode_get_data(controlURLNode); if(baseURL && !purple_str_has_prefix(tmp, "http://") && !purple_str_has_prefix(tmp, "HTTP://")) { /* Handle absolute paths in a relative URL. This probably * belongs in util.c. */ if (tmp[0] == '/') { size_t length; const char *path, *start = strstr(baseURL, "://"); start = start ? start + 3 : baseURL; path = strchr(start, '/'); length = path ? path - baseURL : strlen(baseURL); controlURL = g_strdup_printf("%.*s%s", (int)length, baseURL, tmp); } else { controlURL = g_strdup_printf("%s%s", baseURL, tmp); } g_free(tmp); }else{ controlURL = tmp; } g_free(baseURL); xmlnode_free(xmlRootNode); return controlURL; }
static void fb_got_notifications_cb(FacebookAccount *fba, gchar *url_text, gsize len, gpointer userdata) { gchar *salvaged; time_t last_fetch_time; time_t time_of_message; time_t newest_message = 0; xmlnode *channel;//VOXOX - CJC - 2009.07.06 xmlnode *rss_root;//VOXOX - CJC - 2009.07.06 xmlnode *item;//VOXOX - CJC - 2009.07.06 xmlnode *link;//VOXOX - CJC - 2009.07.06 xmlnode *title;//VOXOX - CJC - 2009.07.06 gchar *tmp; gchar month_string[4], weekday[4]; guint year, month, day, hour, minute, second; long timezone; gchar *subject, *url; month_string[3] = weekday[3] = '\0'; year = month = day = hour = minute = second = 0; if (!url_text || !len) return; last_fetch_time = purple_account_get_int(fba->account, "facebook_notifications_last_fetch", 0); /* purple_debug_info("facebook", "last fetch time: %zu\n", last_fetch_time); */ salvaged = purple_utf8_salvage(url_text); rss_root = xmlnode_from_str(salvaged, -1); g_free(salvaged); if (rss_root == NULL) { purple_debug_error("facebook", "Could not load RSS file\n"); return; } channel = xmlnode_get_child(rss_root, "channel"); if (channel == NULL) { purple_debug_warning("facebook", "Invalid RSS feed\n"); xmlnode_free(rss_root); return; } item = xmlnode_get_child(channel, "item"); if (item == NULL) { purple_debug_info("facebook", "No new notifications\n"); } for (; item != NULL; item = xmlnode_get_next_twin(item)) { xmlnode *pubDate = xmlnode_get_child(item, "pubDate"); if (!pubDate) continue; tmp = xmlnode_get_data_unescaped(pubDate); /* rss times are in Thu, 19 Jun 2008 15:51:25 -1100 format */ sscanf(tmp, "%3s, %2u %3s %4u %2u:%2u:%2u %5ld", (char*)&weekday, &day, (char*)&month_string, &year, &hour, &minute, &second, &timezone); if (g_str_equal(month_string, "Jan")) month = 0; else if (g_str_equal(month_string, "Feb")) month = 1; else if (g_str_equal(month_string, "Mar")) month = 2; else if (g_str_equal(month_string, "Apr")) month = 3; else if (g_str_equal(month_string, "May")) month = 4; else if (g_str_equal(month_string, "Jun")) month = 5; else if (g_str_equal(month_string, "Jul")) month = 6; else if (g_str_equal(month_string, "Aug")) month = 7; else if (g_str_equal(month_string, "Sep")) month = 8; else if (g_str_equal(month_string, "Oct")) month = 9; else if (g_str_equal(month_string, "Nov")) month = 10; else if (g_str_equal(month_string, "Dec")) month = 11; g_free(tmp); /* try using pidgin's functions */ tmp = g_strdup_printf("%04u%02u%02uT%02u%02u%02u%05ld", year, month, day, hour, minute, second, timezone); time_of_message = purple_str_to_time(tmp, FALSE, NULL, NULL, NULL); g_free(tmp); if (time_of_message <= 0) { /* there's no cross-platform, portable way of converting string to time which doesn't need a new version of glib, so just cheat */ time_of_message = second + 60*minute + 3600*hour + 86400*day + 2592000*month + 31536000*(year-1970); } if (time_of_message > newest_message) { /* we'll keep the newest message to save */ newest_message = time_of_message; } if (time_of_message <= last_fetch_time) { /* fortunatly, rss messages are ordered from newest to oldest */ /* so if this message is older than the last one, ignore rest */ break; } link = xmlnode_get_child(item, "link"); if (link) { url = xmlnode_get_data_unescaped(link); } else { url = g_strdup(""); } title = xmlnode_get_child(item, "title"); if (title) { subject = xmlnode_get_data_unescaped(title); } else { subject = g_strdup(""); } purple_notify_email(fba->pc, subject, NULL, fba->account->username, url, NULL, NULL); g_free(subject); g_free(url); } xmlnode_free(rss_root); if (newest_message > last_fetch_time) { /* update the last fetched time if we had newer messages */ purple_account_set_int(fba->account, "facebook_notifications_last_fetch", newest_message); } }