static void jabber_si_bytestreams_connect_cb(gpointer data, gint source, const gchar *error_message) { GaimXfer *xfer = data; JabberSIXfer *jsx = xfer->data; JabberIq *iq; xmlnode *query, *su; struct bytestreams_streamhost *streamhost = jsx->streamhosts->data; gaim_proxy_info_destroy(jsx->gpi); jsx->connect_data = NULL; if(source < 0) { jsx->streamhosts = g_list_remove(jsx->streamhosts, streamhost); g_free(streamhost->jid); g_free(streamhost->host); g_free(streamhost); jabber_si_bytestreams_attempt_connect(xfer); return; } iq = jabber_iq_new_query(jsx->js, JABBER_IQ_RESULT, "http://jabber.org/protocol/bytestreams"); xmlnode_set_attrib(iq->node, "to", xfer->who); jabber_iq_set_id(iq, jsx->iq_id); query = xmlnode_get_child(iq->node, "query"); su = xmlnode_new_child(query, "streamhost-used"); xmlnode_set_attrib(su, "jid", streamhost->jid); jabber_iq_send(iq); gaim_xfer_start(xfer, source, NULL, -1); }
static void jabber_iq_last_parse(JabberStream *js, xmlnode *packet) { JabberIq *iq; const char *type; const char *from; const char *id; xmlnode *query; char *idle_time; type = xmlnode_get_attrib(packet, "type"); from = xmlnode_get_attrib(packet, "from"); id = xmlnode_get_attrib(packet, "id"); if(type && !strcmp(type, "get")) { iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, "jabber:iq:last"); jabber_iq_set_id(iq, id); xmlnode_set_attrib(iq->node, "to", from); query = xmlnode_get_child(iq->node, "query"); idle_time = g_strdup_printf("%ld", js->idle ? time(NULL) - js->idle : 0); xmlnode_set_attrib(query, "seconds", idle_time); g_free(idle_time); jabber_iq_send(iq); } }
static void jabber_iq_version_parse(JabberStream *js, xmlnode *packet) { JabberIq *iq; const char *type, *from, *id; xmlnode *query; type = xmlnode_get_attrib(packet, "type"); if(type && !strcmp(type, "get")) { GHashTable *ui_info; const char *ui_name = NULL, *ui_version = NULL; #if 0 char *os = NULL; if(!purple_prefs_get_bool("/plugins/prpl/jabber/hide_os")) { struct utsname osinfo; uname(&osinfo); os = g_strdup_printf("%s %s %s", osinfo.sysname, osinfo.release, osinfo.machine); } #endif from = xmlnode_get_attrib(packet, "from"); id = xmlnode_get_attrib(packet, "id"); iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, "jabber:iq:version"); xmlnode_set_attrib(iq->node, "to", from); jabber_iq_set_id(iq, id); query = xmlnode_get_child(iq->node, "query"); ui_info = purple_core_get_ui_info(); if(NULL != ui_info) { ui_name = g_hash_table_lookup(ui_info, "name"); ui_version = g_hash_table_lookup(ui_info, "version"); } if(NULL != ui_name && NULL != ui_version) { char *version_complete = g_strdup_printf("%s (libpurple " VERSION ")", ui_version); xmlnode_insert_data(xmlnode_new_child(query, "name"), ui_name, -1); xmlnode_insert_data(xmlnode_new_child(query, "version"), version_complete, -1); g_free(version_complete); } else { xmlnode_insert_data(xmlnode_new_child(query, "name"), "libpurple", -1); xmlnode_insert_data(xmlnode_new_child(query, "version"), VERSION, -1); } #if 0 if(os) { xmlnode_insert_data(xmlnode_new_child(query, "os"), os, -1); g_free(os); } #endif jabber_iq_send(iq); } }
void jabber_ibb_session_accept(JabberIBBSession *sess) { JabberIq *result = jabber_iq_new(jabber_ibb_session_get_js(sess), JABBER_IQ_RESULT); purple_xmlnode_set_attrib(result->node, "to", jabber_ibb_session_get_who(sess)); jabber_iq_set_id(result, sess->id); jabber_iq_send(result); sess->state = JABBER_IBB_SESSION_OPENED; }
JabberIq * jingle_session_create_ack(JingleSession *session, const PurpleXmlNode *jingle) { JabberIq *result = jabber_iq_new( jingle_session_get_js(session), JABBER_IQ_RESULT); PurpleXmlNode *packet = purple_xmlnode_get_parent(jingle); jabber_iq_set_id(result, purple_xmlnode_get_attrib(packet, "id")); purple_xmlnode_set_attrib(result->node, "from", purple_xmlnode_get_attrib(packet, "to")); purple_xmlnode_set_attrib(result->node, "to", purple_xmlnode_get_attrib(packet, "from")); return result; }
static void jabber_oob_xfer_end(PurpleXfer *xfer) { JabberOOBXfer *jox = xfer->data; JabberIq *iq; iq = jabber_iq_new(jox->js, JABBER_IQ_RESULT); xmlnode_set_attrib(iq->node, "to", xfer->who); jabber_iq_set_id(iq, jox->iq_id); jabber_iq_send(iq); jabber_oob_xfer_free(xfer); }
static void jabber_iq_time_parse(JabberStream *js, xmlnode *packet) { const char *type, *from, *id, *xmlns; JabberIq *iq; xmlnode *query; time_t now_t; struct tm *now; time(&now_t); now = localtime(&now_t); type = xmlnode_get_attrib(packet, "type"); from = xmlnode_get_attrib(packet, "from"); id = xmlnode_get_attrib(packet, "id"); /* we're gonna throw this away in a moment, but we need it * to get the xmlns, so we can figure out if this is * jabber:iq:time or urn:xmpp:time */ query = xmlnode_get_child(packet, "query"); xmlns = xmlnode_get_namespace(query); if(type && !strcmp(type, "get")) { xmlnode *utc; const char *date; iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, xmlns); jabber_iq_set_id(iq, id); xmlnode_set_attrib(iq->node, "to", from); query = xmlnode_get_child(iq->node, "query"); date = purple_utf8_strftime("%Y%m%dT%T", now); utc = xmlnode_new_child(query, "utc"); xmlnode_insert_data(utc, date, -1); if(!strcmp("urn:xmpp:time", xmlns)) { xmlnode_insert_data(utc, "Z", 1); /* of COURSE the thing that is the same is different */ date = purple_get_tzoff_str(now, TRUE); xmlnode_insert_data(xmlnode_new_child(query, "tzo"), date, -1); } else { /* jabber:iq:time */ date = purple_utf8_strftime("%Z", now); xmlnode_insert_data(xmlnode_new_child(query, "tz"), date, -1); date = purple_utf8_strftime("%d %b %Y %T", now); xmlnode_insert_data(xmlnode_new_child(query, "display"), date, -1); } jabber_iq_send(iq); } }
static void jabber_ibb_send_error_response(JabberStream *js, const char *to, const char *id) { JabberIq *result = jabber_iq_new(js, JABBER_IQ_ERROR); PurpleXmlNode *error = purple_xmlnode_new("error"); PurpleXmlNode *item_not_found = purple_xmlnode_new("item-not-found"); purple_xmlnode_set_namespace(item_not_found, NS_XMPP_STANZAS); purple_xmlnode_set_attrib(error, "code", "440"); purple_xmlnode_set_attrib(error, "type", "cancel"); jabber_iq_set_id(result, id); purple_xmlnode_set_attrib(result->node, "to", to); purple_xmlnode_insert_child(error, item_not_found); purple_xmlnode_insert_child(result->node, error); jabber_iq_send(result); }
static void urn_xmpp_ping_parse(JabberStream *js, xmlnode *packet) { const char *type, *id, *from; JabberIq *iq; type = xmlnode_get_attrib(packet, "type"); from = xmlnode_get_attrib(packet, "from"); id = xmlnode_get_attrib(packet, "id"); if(type && !strcmp(type, "get")) { iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, "urn:xmpp:ping"); jabber_iq_set_id(iq, id); xmlnode_set_attrib(iq->node, "to", from); jabber_iq_send(iq); } else { /* XXX: error */ } }
static void jabber_time_parse(JabberStream *js, const char *from, JabberIqType type, const char *id, PurpleXmlNode *child) { JabberIq *iq; time_t now_t; struct tm *tm; time(&now_t); if(type == JABBER_IQ_GET) { PurpleXmlNode *tzo, *utc; const char *date, *tz; iq = jabber_iq_new(js, JABBER_IQ_RESULT); jabber_iq_set_id(iq, id); if (from) purple_xmlnode_set_attrib(iq->node, "to", from); child = purple_xmlnode_new_child(iq->node, child->name); purple_xmlnode_set_namespace(child, NS_ENTITY_TIME); /* <tzo>-06:00</tzo> */ tm = localtime(&now_t); tz = purple_get_tzoff_str(tm, TRUE); tzo = purple_xmlnode_new_child(child, "tzo"); purple_xmlnode_insert_data(tzo, tz, -1); /* <utc>2006-12-19T17:58:35Z</utc> */ tm = gmtime(&now_t); date = purple_utf8_strftime("%Y-%m-%dT%H:%M:%SZ", tm); utc = purple_xmlnode_new_child(child, "utc"); purple_xmlnode_insert_data(utc, date, -1); jabber_iq_send(iq); } else { /* TODO: Errors */ } }
static void jabber_iq_last_parse(JabberStream *js, const char *from, JabberIqType type, const char *id, PurpleXmlNode *packet) { JabberIq *iq; PurpleXmlNode *query; char *idle_time; if(type == JABBER_IQ_GET) { iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, NS_LAST_ACTIVITY); jabber_iq_set_id(iq, id); if (from) purple_xmlnode_set_attrib(iq->node, "to", from); query = purple_xmlnode_get_child(iq->node, "query"); idle_time = g_strdup_printf("%ld", js->idle ? time(NULL) - js->idle : 0); purple_xmlnode_set_attrib(query, "seconds", idle_time); g_free(idle_time); jabber_iq_send(iq); } }
static void jabber_oob_xfer_recv_error(PurpleXfer *xfer, const char *code) { JabberOOBXfer *jox = xfer->data; JabberIq *iq; xmlnode *y, *z; iq = jabber_iq_new(jox->js, JABBER_IQ_ERROR); xmlnode_set_attrib(iq->node, "to", xfer->who); jabber_iq_set_id(iq, jox->iq_id); y = xmlnode_new_child(iq->node, "error"); xmlnode_set_attrib(y, "code", code); if(purple_strequal(code, "406")) { z = xmlnode_new_child(y, "not-acceptable"); xmlnode_set_attrib(y, "type", "modify"); xmlnode_set_namespace(z, NS_XMPP_STANZAS); } else if(purple_strequal(code, "404")) { z = xmlnode_new_child(y, "not-found"); xmlnode_set_attrib(y, "type", "cancel"); xmlnode_set_namespace(z, NS_XMPP_STANZAS); } jabber_iq_send(iq); jabber_oob_xfer_free(xfer); }
void jabber_roster_parse(JabberStream *js, const char *from, JabberIqType type, const char *id, xmlnode *query) { xmlnode *item, *group; #if 0 const char *ver; #endif 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 (g_str_equal(subscription, "remove")) jb->subscription = JABBER_SUB_REMOVE; else if (jb == js->user_jb) jb->subscription = JABBER_SUB_BOTH; else if (g_str_equal(subscription, "none")) jb->subscription = JABBER_SUB_NONE; else if (g_str_equal(subscription, "to")) jb->subscription = JABBER_SUB_TO; else if (g_str_equal(subscription, "from")) jb->subscription = JABBER_SUB_FROM; else if (g_str_equal(subscription, "both")) jb->subscription = JABBER_SUB_BOTH; } 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; } /* * See the note in add_purple_buddy_to_groups; the core handles * names case-insensitively and this is required to not * end up with duplicates if a buddy is in, e.g., * 'XMPP' and 'xmpp' */ if (g_slist_find_custom(groups, group_name, (GCompareFunc)purple_utf8_strcasecmp)) g_free(group_name); else 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); } } #if 0 ver = xmlnode_get_attrib(query, "ver"); if (ver) { PurpleAccount *account = purple_connection_get_account(js->gc); purple_account_set_string(account, "roster_ver", ver); } #endif if (type == JABBER_IQ_SET) { JabberIq *ack = jabber_iq_new(js, JABBER_IQ_RESULT); jabber_iq_set_id(ack, id); jabber_iq_send(ack); } js->currently_parsing_roster_push = FALSE; }
static void google_session_handle_accept(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id) { xmlnode *desc_element = xmlnode_get_child(sess, "description"); xmlnode *codec_element = xmlnode_get_child( desc_element, "payload-type"); GList *codecs = NULL, *video_codecs = NULL; JabberIq *result = NULL; const gchar *xmlns = xmlnode_get_namespace(desc_element); gboolean video = (xmlns && !strcmp(xmlns, NS_GOOGLE_SESSION_VIDEO)); GoogleAVSessionData *session_data = (GoogleAVSessionData *) session->session_data; for (; codec_element; codec_element = codec_element->next) { const gchar *xmlns, *encoding_name, *id, *clock_rate, *width, *height, *framerate; gboolean video_codec = FALSE; if (!purple_strequal(codec_element->name, "payload-type")) continue; xmlns = xmlnode_get_namespace(codec_element); encoding_name = xmlnode_get_attrib(codec_element, "name"); id = xmlnode_get_attrib(codec_element, "id"); if (!video || purple_strequal(xmlns, NS_GOOGLE_SESSION_PHONE)) clock_rate = xmlnode_get_attrib( codec_element, "clockrate"); else { clock_rate = "90000"; width = xmlnode_get_attrib(codec_element, "width"); height = xmlnode_get_attrib(codec_element, "height"); framerate = xmlnode_get_attrib( codec_element, "framerate"); video_codec = TRUE; } if (id && encoding_name) { PurpleMediaCodec *codec = purple_media_codec_new( atoi(id), encoding_name, video_codec ? PURPLE_MEDIA_VIDEO : PURPLE_MEDIA_AUDIO, clock_rate ? atoi(clock_rate) : 0); if (video_codec) video_codecs = g_list_append( video_codecs, codec); else codecs = g_list_append(codecs, codec); } } if (codecs) purple_media_set_remote_codecs(session_data->media, "google-voice", session->remote_jid, codecs); if (video_codecs) purple_media_set_remote_codecs(session_data->media, "google-video", session->remote_jid, video_codecs); purple_media_stream_info(session_data->media, PURPLE_MEDIA_INFO_ACCEPT, NULL, NULL, FALSE); 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 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 void jabber_google_relay_response_session_handle_initiate_cb(GoogleSession *session, const gchar *relay_ip, guint relay_udp, guint relay_tcp, guint relay_ssltcp, const gchar *relay_username, const gchar *relay_password) { GParameter *params; guint num_params; JabberStream *js = session->js; xmlnode *codec_element; const gchar *xmlns; PurpleMediaCodec *codec; GList *video_codecs = NULL; GList *codecs = NULL; JabberIq *result; GoogleAVSessionData *session_data = (GoogleAVSessionData *) session->session_data; params = jabber_google_session_get_params(js, relay_ip, relay_udp, relay_tcp, relay_ssltcp, relay_username, relay_password, &num_params); if (purple_media_add_stream(session_data->media, "google-voice", session->remote_jid, PURPLE_MEDIA_AUDIO, FALSE, "nice", num_params, params) == FALSE || (session_data->video && purple_media_add_stream( session_data->media, "google-video", session->remote_jid, PURPLE_MEDIA_VIDEO, FALSE, "nice", num_params, params) == FALSE)) { purple_media_error(session_data->media, "Error adding stream."); purple_media_stream_info(session_data->media, PURPLE_MEDIA_INFO_REJECT, NULL, NULL, TRUE); } else { /* successfully added stream(s) */ session_data->added_streams = TRUE; if (session_data->remote_audio_candidates) { purple_media_add_remote_candidates(session_data->media, "google-voice", session->remote_jid, session_data->remote_audio_candidates); purple_media_candidate_list_free(session_data->remote_audio_candidates); session_data->remote_audio_candidates = NULL; } if (session_data->remote_video_candidates) { purple_media_add_remote_candidates(session_data->media, "google-video", session->remote_jid, session_data->remote_video_candidates); purple_media_candidate_list_free(session_data->remote_video_candidates); session_data->remote_video_candidates = NULL; } } g_free(params); for (codec_element = xmlnode_get_child(session->description, "payload-type"); codec_element; codec_element = codec_element->next) { const char *id, *encoding_name, *clock_rate, *width, *height, *framerate; gboolean video; if (codec_element->name && strcmp(codec_element->name, "payload-type")) continue; xmlns = xmlnode_get_namespace(codec_element); encoding_name = xmlnode_get_attrib(codec_element, "name"); id = xmlnode_get_attrib(codec_element, "id"); if (!session_data->video || (xmlns && !strcmp(xmlns, NS_GOOGLE_SESSION_PHONE))) { clock_rate = xmlnode_get_attrib( codec_element, "clockrate"); video = FALSE; } else { width = xmlnode_get_attrib(codec_element, "width"); height = xmlnode_get_attrib(codec_element, "height"); framerate = xmlnode_get_attrib( codec_element, "framerate"); clock_rate = "90000"; video = TRUE; } if (id) { codec = purple_media_codec_new(atoi(id), encoding_name, video ? PURPLE_MEDIA_VIDEO : PURPLE_MEDIA_AUDIO, clock_rate ? atoi(clock_rate) : 0); if (video) video_codecs = g_list_append( video_codecs, codec); else codecs = g_list_append(codecs, codec); } } if (codecs) purple_media_set_remote_codecs(session_data->media, "google-voice", session->remote_jid, codecs); if (video_codecs) purple_media_set_remote_codecs(session_data->media, "google-video", session->remote_jid, video_codecs); purple_media_codec_list_free(codecs); purple_media_codec_list_free(video_codecs); result = jabber_iq_new(js, JABBER_IQ_RESULT); jabber_iq_set_id(result, session->iq_id); xmlnode_set_attrib(result->node, "to", session->remote_jid); jabber_iq_send(result); }
static void jabber_si_xfer_init(GaimXfer *xfer) { JabberSIXfer *jsx = xfer->data; JabberIq *iq; if(gaim_xfer_get_type(xfer) == GAIM_XFER_SEND) { JabberBuddy *jb; JabberBuddyResource *jbr = NULL; jb = jabber_buddy_find(jsx->js, xfer->who, TRUE); /* XXX */ if(!jb) return; /* XXX: for now, send to the first resource available */ if(g_list_length(jb->resources) >= 1) { char **who_v = g_strsplit(xfer->who, "/", 2); char *who; jbr = jabber_buddy_find_resource(jb, NULL); who = g_strdup_printf("%s/%s", who_v[0], jbr->name); g_strfreev(who_v); g_free(xfer->who); xfer->who = who; jabber_disco_info_do(jsx->js, who, jabber_si_xfer_send_disco_cb, xfer); } else { return; /* XXX: ick */ } } else { xmlnode *si, *feature, *x, *field, *value; iq = jabber_iq_new(jsx->js, JABBER_IQ_RESULT); xmlnode_set_attrib(iq->node, "to", xfer->who); if(jsx->iq_id) jabber_iq_set_id(iq, jsx->iq_id); jsx->accepted = TRUE; si = xmlnode_new_child(iq->node, "si"); xmlnode_set_namespace(si, "http://jabber.org/protocol/si"); feature = xmlnode_new_child(si, "feature"); xmlnode_set_namespace(feature, "http://jabber.org/protocol/feature-neg"); x = xmlnode_new_child(feature, "x"); xmlnode_set_namespace(x, "jabber:x:data"); xmlnode_set_attrib(x, "type", "submit"); field = xmlnode_new_child(x, "field"); xmlnode_set_attrib(field, "var", "stream-method"); value = xmlnode_new_child(field, "value"); if(jsx->stream_method & STREAM_METHOD_BYTESTREAMS) xmlnode_insert_data(value, "http://jabber.org/protocol/bytestreams", -1); /* else if(jsx->stream_method & STREAM_METHOD_IBB) xmlnode_insert_data(value, "http://jabber.org/protocol/ibb", -1); */ jabber_iq_send(iq); } }
void jabber_ibb_parse(JabberStream *js, const char *who, JabberIqType type, const char *id, PurpleXmlNode *child) { const char *name = child->name; gboolean data = g_str_equal(name, "data"); gboolean close = g_str_equal(name, "close"); gboolean open = g_str_equal(name, "open"); const gchar *sid = (data || close) ? purple_xmlnode_get_attrib(child, "sid") : NULL; JabberIBBSession *sess = sid ? g_hash_table_lookup(jabber_ibb_sessions, sid) : NULL; if (sess) { if (strcmp(who, jabber_ibb_session_get_who(sess)) != 0) { /* the iq comes from a different JID than the remote JID of the session, ignore it */ purple_debug_error("jabber", "Got IBB iq from wrong JID, ignoring\n"); } else if (data) { const gchar *seq_attr = purple_xmlnode_get_attrib(child, "seq"); guint16 seq = (seq_attr ? atoi(seq_attr) : 0); /* reject the data, and set the session in error if we get an out-of-order packet */ if (seq_attr && seq == jabber_ibb_session_get_recv_seq(sess)) { /* sequence # is the expected... */ JabberIq *result = jabber_iq_new(js, JABBER_IQ_RESULT); jabber_iq_set_id(result, id); purple_xmlnode_set_attrib(result->node, "to", who); if (sess->data_received_cb) { gchar *base64 = purple_xmlnode_get_data(child); gsize size; gpointer rawdata = purple_base64_decode(base64, &size); g_free(base64); if (rawdata) { purple_debug_info("jabber", "got %" G_GSIZE_FORMAT " bytes of data on IBB stream\n", size); /* we accept other clients to send up to block-size of _unencoded_ data, since there's been some confusions regarding the interpretation of this attribute (including previous versions of libpurple) */ if (size > jabber_ibb_session_get_block_size(sess)) { purple_debug_error("jabber", "IBB: received a too large packet\n"); if (sess->error_cb) sess->error_cb(sess); g_free(rawdata); return; } else { purple_debug_info("jabber", "calling IBB callback for received data\n"); sess->data_received_cb(sess, rawdata, size); } g_free(rawdata); } else { purple_debug_error("jabber", "IBB: invalid BASE64 data received\n"); if (sess->error_cb) sess->error_cb(sess); return; } } (sess->recv_seq)++; jabber_iq_send(result); } else { purple_debug_error("jabber", "Received an out-of-order/invalid IBB packet\n"); sess->state = JABBER_IBB_SESSION_ERROR; if (sess->error_cb) { sess->error_cb(sess); } } } else if (close) { sess->state = JABBER_IBB_SESSION_CLOSED; purple_debug_info("jabber", "IBB: received close\n"); if (sess->closed_cb) { purple_debug_info("jabber", "IBB: calling closed handler\n"); sess->closed_cb(sess); } } } else if (open) { JabberIq *result; const GList *iterator; /* run all open handlers registered until one returns true */ for (iterator = open_handlers ; iterator ; iterator = g_list_next(iterator)) { JabberIBBOpenHandler *handler = iterator->data; if (handler(js, who, id, child)) { result = jabber_iq_new(js, JABBER_IQ_RESULT); purple_xmlnode_set_attrib(result->node, "to", who); jabber_iq_set_id(result, id); jabber_iq_send(result); return; } } /* no open callback returned success, reject */ jabber_ibb_send_error_response(js, who, id); } else { /* send error reply */ jabber_ibb_send_error_response(js, who, id); } }
static void jabber_si_bytestreams_attempt_connect(GaimXfer *xfer) { JabberSIXfer *jsx = xfer->data; struct bytestreams_streamhost *streamhost; char *dstaddr, *p; int i; unsigned char hashval[20]; JabberID *dstjid; if(!jsx->streamhosts) { JabberIq *iq = jabber_iq_new(jsx->js, JABBER_IQ_ERROR); xmlnode *error, *inf; if(jsx->iq_id) jabber_iq_set_id(iq, jsx->iq_id); xmlnode_set_attrib(iq->node, "to", xfer->who); error = xmlnode_new_child(iq->node, "error"); xmlnode_set_attrib(error, "code", "404"); xmlnode_set_attrib(error, "type", "cancel"); inf = xmlnode_new_child(error, "item-not-found"); xmlnode_set_namespace(inf, "urn:ietf:params:xml:ns:xmpp-stanzas"); jabber_iq_send(iq); gaim_xfer_cancel_local(xfer); return; } streamhost = jsx->streamhosts->data; dstjid = jabber_id_new(xfer->who); if(dstjid != NULL) { jsx->gpi = gaim_proxy_info_new(); gaim_proxy_info_set_type(jsx->gpi, GAIM_PROXY_SOCKS5); gaim_proxy_info_set_host(jsx->gpi, streamhost->host); gaim_proxy_info_set_port(jsx->gpi, streamhost->port); dstaddr = g_strdup_printf("%s%s@%s/%s%s@%s/%s", jsx->stream_id, dstjid->node, dstjid->domain, dstjid->resource, jsx->js->user->node, jsx->js->user->domain, jsx->js->user->resource); gaim_cipher_digest_region("sha1", (guchar *)dstaddr, strlen(dstaddr), sizeof(hashval), hashval, NULL); g_free(dstaddr); dstaddr = g_malloc(41); p = dstaddr; for(i=0; i<20; i++, p+=2) snprintf(p, 3, "%02x", hashval[i]); jsx->connect_data = gaim_proxy_connect_socks5(NULL, jsx->gpi, dstaddr, 0, jabber_si_bytestreams_connect_cb, xfer); g_free(dstaddr); jabber_id_free(dstjid); } if (jsx->connect_data == NULL) { jsx->streamhosts = g_list_remove(jsx->streamhosts, streamhost); g_free(streamhost->jid); g_free(streamhost->host); g_free(streamhost); jabber_si_bytestreams_attempt_connect(xfer); } }