void jabber_chat_invite(PurpleConnection *gc, int id, const char *msg, const char *name) { JabberStream *js = gc->proto_data; JabberChat *chat; xmlnode *message, *body, *x, *invite; char *room_jid; chat = jabber_chat_find_by_id(js, id); if(!chat) return; message = xmlnode_new("message"); room_jid = g_strdup_printf("%s@%s", chat->room, chat->server); if(chat->muc) { xmlnode_set_attrib(message, "to", room_jid); x = xmlnode_new_child(message, "x"); xmlnode_set_namespace(x, "http://jabber.org/protocol/muc#user"); invite = xmlnode_new_child(x, "invite"); xmlnode_set_attrib(invite, "to", name); if (msg) { body = xmlnode_new_child(invite, "reason"); xmlnode_insert_data(body, msg, -1); } } else { xmlnode_set_attrib(message, "to", name); /* * Putting the reason into the body was an 'undocumented protocol, * ...not part of "groupchat 1.0"'. * http://xmpp.org/extensions/attic/jep-0045-1.16.html#invite * * Left here for compatibility. */ if (msg) { body = xmlnode_new_child(message, "body"); xmlnode_insert_data(body, msg, -1); } x = xmlnode_new_child(message, "x"); xmlnode_set_attrib(x, "jid", room_jid); /* The better place for it! XEP-0249 style. */ if (msg) xmlnode_set_attrib(x, "reason", msg); xmlnode_set_namespace(x, "jabber:x:conference"); } jabber_send(js, message); xmlnode_free(message); g_free(room_jid); }
void jabber_mam_request(JabberStream *js, const char* after) { if (!js->mam) return; JabberIq *iq = jabber_iq_new_query(js, JABBER_IQ_SET, NS_XMPP_MAM); xmlnode *query = xmlnode_get_child(iq->node, "query"); xmlnode *x = xmlnode_new_child(query, "x"); xmlnode_set_namespace(x, "jabber:x:data"); xmlnode *field = xmlnode_new_child(x, "field"); xmlnode_set_attrib(field, "type", "hidden"); xmlnode_set_attrib(field, "var", "FORM_TYPE"); xmlnode *value = xmlnode_new_child(field, "value"); xmlnode_insert_data(value, NS_XMPP_MAM, -1); if (after) { xmlnode *set = xmlnode_new_child(query, "set"); xmlnode_set_namespace(set, NS_RSM); value = xmlnode_new_child(set, "after"); xmlnode_insert_data(value, after, -1); } if (js->mam->current->start) { field = xmlnode_new_child(x, "field"); xmlnode_set_attrib(field, "var", "start"); value = xmlnode_new_child(field, "value"); xmlnode_insert_data(value, js->mam->current->start, -1); } if (js->mam->current->end) { field = xmlnode_new_child(x, "field"); xmlnode_set_attrib(field, "var", "end"); value = xmlnode_new_child(field, "value"); xmlnode_insert_data(value, js->mam->current->end, -1); } if (js->mam->current->with) { field = xmlnode_new_child(x, "field"); xmlnode_set_attrib(field, "var", "with"); value = xmlnode_new_child(field, "value"); xmlnode_insert_data(value, js->mam->current->with, -1); } jabber_iq_send(iq); }
static void jabber_si_xfer_send_request(GaimXfer *xfer) { JabberSIXfer *jsx = xfer->data; JabberIq *iq; xmlnode *si, *file, *feature, *x, *field, *option, *value; char buf[32]; xfer->filename = g_path_get_basename(xfer->local_filename); iq = jabber_iq_new(jsx->js, JABBER_IQ_SET); xmlnode_set_attrib(iq->node, "to", xfer->who); si = xmlnode_new_child(iq->node, "si"); xmlnode_set_namespace(si, "http://jabber.org/protocol/si"); jsx->stream_id = jabber_get_next_id(jsx->js); xmlnode_set_attrib(si, "id", jsx->stream_id); xmlnode_set_attrib(si, "profile", "http://jabber.org/protocol/si/profile/file-transfer"); file = xmlnode_new_child(si, "file"); xmlnode_set_namespace(file, "http://jabber.org/protocol/si/profile/file-transfer"); xmlnode_set_attrib(file, "name", xfer->filename); g_snprintf(buf, sizeof(buf), "%" G_GSIZE_FORMAT, xfer->size); xmlnode_set_attrib(file, "size", buf); /* maybe later we'll do hash and date attribs */ 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", "form"); field = xmlnode_new_child(x, "field"); xmlnode_set_attrib(field, "var", "stream-method"); xmlnode_set_attrib(field, "type", "list-single"); option = xmlnode_new_child(field, "option"); value = xmlnode_new_child(option, "value"); xmlnode_insert_data(value, "http://jabber.org/protocol/bytestreams", -1); /* option = xmlnode_new_child(field, "option"); value = xmlnode_new_child(option, "value"); xmlnode_insert_data(value, "http://jabber.org/protocol/ibb", -1); */ jabber_iq_set_callback(iq, jabber_si_xfer_send_method_cb, xfer); jabber_iq_send(iq); }
void jabber_gmail_init(JabberStream *js) { JabberIq *iq; xmlnode *usersetting, *mailnotifications; if (!purple_account_get_check_mail(purple_connection_get_account(js->gc))) return; /* * Quoting http://code.google.com/apis/talk/jep_extensions/usersettings.html: * To ensure better compatibility with other clients, rather than * setting this value to "false" to turn off notifications, it is * recommended that a client set this to "true" and filter incoming * email notifications itself. */ iq = jabber_iq_new(js, JABBER_IQ_SET); usersetting = xmlnode_new_child(iq->node, "usersetting"); xmlnode_set_namespace(usersetting, "google:setting"); mailnotifications = xmlnode_new_child(usersetting, "mailnotifications"); xmlnode_set_attrib(mailnotifications, "value", "true"); jabber_iq_send(iq); iq = jabber_iq_new_query(js, JABBER_IQ_GET, NS_GOOGLE_MAIL_NOTIFY); jabber_iq_set_callback(iq, jabber_gmail_parse, NULL); jabber_iq_send(iq); }
static void jabber_bosh_connection_received(PurpleBOSHConnection *conn, xmlnode *node) { xmlnode *child; JabberStream *js = conn->js; g_return_if_fail(node != NULL); if (jabber_bosh_connection_error_check(conn, node)) return; child = node->child; while (child != NULL) { /* jabber_process_packet might free child */ xmlnode *next = child->next; if (child->type == XMLNODE_TYPE_TAG) { const char *xmlns = xmlnode_get_namespace(child); /* * Workaround for non-compliant servers that don't stamp * the right xmlns on these packets. See #11315. */ if ((xmlns == NULL /* shouldn't happen, but is equally wrong */ || g_str_equal(xmlns, NS_BOSH)) && (g_str_equal(child->name, "iq") || g_str_equal(child->name, "message") || g_str_equal(child->name, "presence"))) { xmlnode_set_namespace(child, NS_XMPP_CLIENT); } jabber_process_packet(js, &child); } child = next; } }
static JabberSaslState fb_start(JabberStream *js, xmlnode *packet, xmlnode **response, char **error) { PurpleAccount *account; const char *username; gchar **parts; account = purple_connection_get_account(js->gc); username = purple_account_get_username(account); purple_debug_error("auth_fb", "account name is %s", username); parts = g_strsplit(username, "@", 0); if (parts[0] && strlen(parts[0]) && g_str_has_prefix(parts[0], "-")) { /* When connecting with X-FACEBOOK-PLATFORM, the password field must be set to the * OAUTH 2.0 session key. * * X-FACEBOOK-PLATFORM is only valid for a facebook userID, which is prefixed with '-' */ xmlnode *auth = xmlnode_new("auth"); xmlnode_set_namespace(auth, "urn:ietf:params:xml:ns:xmpp-sasl"); xmlnode_set_attrib(auth, "mechanism", "X-FACEBOOK-PLATFORM"); *response = auth; g_strfreev(parts); return JABBER_SASL_STATE_CONTINUE; } else { g_strfreev(parts); return JABBER_SASL_STATE_FAIL; } }
xmlnode * jingle_transport_to_xml_internal(JingleTransport *transport, xmlnode *content, JingleActionType action) { xmlnode *node = xmlnode_new_child(content, "transport"); xmlnode_set_namespace(node, jingle_transport_get_transport_type(transport)); return node; }
xmlnode * jabber_data_get_xml_request(const gchar *cid) { xmlnode *tag = xmlnode_new("data"); xmlnode_set_namespace(tag, NS_BOB); xmlnode_set_attrib(tag, "cid", cid); return tag; }
static xmlnode * google_session_create_xmlnode(GoogleSession *session, const char *type) { xmlnode *node = xmlnode_new("session"); xmlnode_set_namespace(node, NS_GOOGLE_SESSION); xmlnode_set_attrib(node, "id", session->id.id); xmlnode_set_attrib(node, "initiator", session->id.initiator); xmlnode_set_attrib(node, "type", type); return node; }
static JabberSaslState digest_md5_start(JabberStream *js, xmlnode *packet, xmlnode **response, char **error) { xmlnode *auth = xmlnode_new("auth"); xmlnode_set_namespace(auth, NS_XMPP_SASL); xmlnode_set_attrib(auth, "mechanism", "DIGEST-MD5"); *response = auth; return JABBER_SASL_STATE_CONTINUE; }
JabberIq *jabber_iq_new_query(JabberStream *js, JabberIqType type, const char *xmlns) { JabberIq *iq = jabber_iq_new(js, type); xmlnode *query; query = xmlnode_new_child(iq->node, "query"); xmlnode_set_namespace(query, xmlns); return iq; }
static JabberSaslState jabber_cyrus_handle_challenge(JabberStream *js, xmlnode *packet, xmlnode **reply, char **error) { char *enc_in = xmlnode_get_data(packet); unsigned char *dec_in; char *enc_out; const char *c_out; unsigned int clen; gsize declen; dec_in = purple_base64_decode(enc_in, &declen); js->sasl_state = sasl_client_step(js->sasl, (char*)dec_in, declen, NULL, &c_out, &clen); g_free(enc_in); g_free(dec_in); if (js->sasl_state != SASL_CONTINUE && js->sasl_state != SASL_OK) { gchar *tmp = g_strdup_printf(_("SASL error: %s"), sasl_errdetail(js->sasl)); purple_debug_error("jabber", "Error is %d : %s\n", js->sasl_state, sasl_errdetail(js->sasl)); *error = tmp; return JABBER_SASL_STATE_FAIL; } else { xmlnode *response = xmlnode_new("response"); xmlnode_set_namespace(response, NS_XMPP_SASL); if (clen > 0) { /* Cyrus SASL 2.1.22 appears to contain code to add the charset * to the response for DIGEST-MD5 but there is no possibility * it will be executed. * * My reading of the digestmd5 plugin indicates the username and * realm are always encoded in UTF-8 (they seem to be the values * we pass in), so we need to ensure charset=utf-8 is set. */ if (!purple_strequal(js->current_mech, "DIGEST-MD5") || strstr(c_out, ",charset=")) /* If we're not using DIGEST-MD5 or Cyrus SASL is fixed */ enc_out = purple_base64_encode((unsigned char*)c_out, clen); else { char *tmp = g_strdup_printf("%s,charset=utf-8", c_out); enc_out = purple_base64_encode((unsigned char*)tmp, clen + 14); g_free(tmp); } xmlnode_insert_data(response, enc_out, -1); g_free(enc_out); } *reply = response; return JABBER_SASL_STATE_CONTINUE; } }
static void xmlnode_parser_element_start_libxml(void *user_data, const xmlChar *element_name, const xmlChar *prefix, const xmlChar *xmlns, int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **attributes) { struct _xmlnode_parser_data *xpd = user_data; xmlnode *node; int i, j; if(!element_name || xpd->error) { return; } else { if(xpd->current) node = xmlnode_new_child(xpd->current, (const char*) element_name); else node = xmlnode_new((const char *) element_name); xmlnode_set_namespace(node, (const char *) xmlns); xmlnode_set_prefix(node, (const char *)prefix); if (nb_namespaces != 0) { node->namespace_map = g_hash_table_new_full( g_str_hash, g_str_equal, g_free, g_free); for (i = 0, j = 0; i < nb_namespaces; i++, j += 2) { const char *key = (const char *)namespaces[j]; const char *val = (const char *)namespaces[j + 1]; g_hash_table_insert(node->namespace_map, g_strdup(key ? key : ""), g_strdup(val ? val : "")); } } for(i=0; i < nb_attributes * 5; i+=5) { const char *prefix = (const char *)attributes[i + 1]; char *txt; int attrib_len = attributes[i+4] - attributes[i+3]; char *attrib = g_malloc(attrib_len + 1); memcpy(attrib, attributes[i+3], attrib_len); attrib[attrib_len] = '\0'; txt = attrib; attrib = purple_unescape_html(txt); g_free(txt); if (prefix && *prefix) { xmlnode_set_attrib_with_prefix(node, (const char*) attributes[i], prefix, attrib); } else { xmlnode_set_attrib(node, (const char*) attributes[i], attrib); } g_free(attrib); } xpd->current = node; } }
static void xep_ft_si_result(PurpleXfer *xfer, char *to) { xmlnode *si_node, *feature, *field, *value, *x; XepIq *iq; XepXfer *xf; BonjourData *bd; if(!to || !xfer) return; xf = xfer->data; if(!xf) return; bd = xf->data; purple_debug_info("bonjour", "xep file transfer stream initialization result.\n"); iq = xep_iq_new(bd, XEP_IQ_RESULT, to, bonjour_get_jid(bd->jabber_data->account), xf->iq_id); if(iq == NULL) return; si_node = xmlnode_new_child(iq->node, "si"); xmlnode_set_namespace(si_node, "http://jabber.org/protocol/si"); /*xmlnode_set_attrib(si_node, "profile", "http://jabber.org/protocol/si/profile/file-transfer");*/ feature = xmlnode_new_child(si_node, "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"); xmlnode_insert_data(value, "http://jabber.org/protocol/bytestreams", -1); xep_iq_send_and_free(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); }
static void xep_ft_si_reject(BonjourData *bd, const char *id, const char *to, const char *error_code, const char *error_type) { xmlnode *error_node; XepIq *iq; g_return_if_fail(error_code != NULL); g_return_if_fail(error_type != NULL); if(!to || !id) { purple_debug_info("bonjour", "xep file transfer stream initialization error.\n"); return; } iq = xep_iq_new(bd, XEP_IQ_ERROR, to, bonjour_get_jid(bd->jabber_data->account), id); if(iq == NULL) return; error_node = xmlnode_new_child(iq->node, "error"); xmlnode_set_attrib(error_node, "code", error_code); xmlnode_set_attrib(error_node, "type", error_type); /* TODO: Make this better */ if (purple_strequal(error_code, "403")) { xmlnode *tmp_node = xmlnode_new_child(error_node, "forbidden"); xmlnode_set_namespace(tmp_node, "urn:ietf:params:xml:ns:xmpp-stanzas"); tmp_node = xmlnode_new_child(error_node, "text"); xmlnode_set_namespace(tmp_node, "urn:ietf:params:xml:ns:xmpp-stanzas"); xmlnode_insert_data(tmp_node, "Offer Declined", -1); } else if (purple_strequal(error_code, "404")) { xmlnode *tmp_node = xmlnode_new_child(error_node, "item-not-found"); xmlnode_set_namespace(tmp_node, "urn:ietf:params:xml:ns:xmpp-stanzas"); } xep_iq_send_and_free(iq); }
void jabber_chat_invite(PurpleConnection *gc, int id, const char *msg, const char *name) { JabberStream *js = gc->proto_data; JabberChat *chat; xmlnode *message, *body, *x, *invite; char *room_jid; chat = jabber_chat_find_by_id(js, id); if(!chat) return; message = xmlnode_new("message"); room_jid = g_strdup_printf("%s@%s", chat->room, chat->server); if(chat->muc) { xmlnode_set_attrib(message, "to", room_jid); x = xmlnode_new_child(message, "x"); xmlnode_set_namespace(x, "http://jabber.org/protocol/muc#user"); invite = xmlnode_new_child(x, "invite"); xmlnode_set_attrib(invite, "to", name); body = xmlnode_new_child(invite, "reason"); xmlnode_insert_data(body, msg, -1); } else { xmlnode_set_attrib(message, "to", name); body = xmlnode_new_child(message, "body"); xmlnode_insert_data(body, msg, -1); x = xmlnode_new_child(message, "x"); xmlnode_set_attrib(x, "jid", room_jid); xmlnode_set_namespace(x, "jabber:x:conference"); } jabber_send(js, message); xmlnode_free(message); g_free(room_jid); }
static void do_nick_set(JabberStream *js, const char *nick) { xmlnode *publish, *nicknode; publish = xmlnode_new("publish"); xmlnode_set_attrib(publish,"node","http://jabber.org/protocol/nick"); nicknode = xmlnode_new_child(xmlnode_new_child(publish, "item"), "nick"); xmlnode_set_namespace(nicknode, "http://jabber.org/protocol/nick"); if(nick && nick[0] != '\0') xmlnode_insert_data(nicknode, nick, -1); jabber_pep_publish(js, publish); /* publish is freed by jabber_pep_publish -> jabber_iq_send -> jabber_iq_free (yay for well-defined memory management rules) */ }
static void bonjour_bytestreams_listen(int sock, gpointer data) { PurpleXfer *xfer = data; XepXfer *xf; XepIq *iq; xmlnode *query, *streamhost; gchar *port; GSList *local_ips; BonjourData *bd; purple_debug_info("bonjour", "Bonjour-bytestreams-listen. sock=%d.\n", sock); if (sock < 0 || xfer == NULL) { /*purple_xfer_cancel_local(xfer);*/ return; } xfer->watcher = purple_input_add(sock, PURPLE_INPUT_READ, bonjour_sock5_request_cb, xfer); xf = (XepXfer*)xfer->data; xf->listen_data = NULL; bd = xf->data; iq = xep_iq_new(bd, XEP_IQ_SET, xfer->who, bonjour_get_jid(bd->jabber_data->account), xf->sid); query = xmlnode_new_child(iq->node, "query"); xmlnode_set_namespace(query, "http://jabber.org/protocol/bytestreams"); xmlnode_set_attrib(query, "sid", xf->sid); xmlnode_set_attrib(query, "mode", "tcp"); xfer->local_port = purple_network_get_port_from_fd(sock); local_ips = bonjour_jabber_get_local_ips(sock); port = g_strdup_printf("%hu", (guint16)purple_xfer_get_local_port(xfer)); while(local_ips) { streamhost = xmlnode_new_child(query, "streamhost"); xmlnode_set_attrib(streamhost, "jid", xf->sid); xmlnode_set_attrib(streamhost, "host", local_ips->data); xmlnode_set_attrib(streamhost, "port", port); g_free(local_ips->data); local_ips = g_slist_delete_link(local_ips, local_ips); } g_free(port); xep_iq_send_and_free(iq); }
xmlnode * jabber_data_get_xml_definition(const JabberData *data) { xmlnode *tag = xmlnode_new("data"); char *base64data = purple_base64_encode(data->data, data->size); xmlnode_set_namespace(tag, NS_BOB); xmlnode_set_attrib(tag, "cid", data->cid); xmlnode_set_attrib(tag, "type", data->type); xmlnode_insert_data(tag, base64data, -1); g_free(base64data); return tag; }
static void jabber_x_data_cancel_cb(struct jabber_x_data_data *data, GaimRequestFields *fields) { xmlnode *result = xmlnode_new("x"); jabber_x_data_cb cb = data->cb; gpointer user_data = data->user_data; JabberStream *js = data->js; g_hash_table_destroy(data->fields); while(data->values) { g_free(data->values->data); data->values = g_slist_delete_link(data->values, data->values); } g_free(data); xmlnode_set_namespace(result, "jabber:x:data"); xmlnode_set_attrib(result, "type", "cancel"); cb(js, result, user_data); }
JabberChat *jabber_join_chat(JabberStream *js, const char *room, const char *server, const char *handle, const char *password, GHashTable *data) { JabberChat *chat; PurpleConnection *gc; PurpleAccount *account; PurpleStatus *status; xmlnode *presence, *x; JabberBuddyState state; char *msg; int priority; char *jid; chat = jabber_chat_new(js, room, server, handle, password, data); if (chat == NULL) return NULL; gc = js->gc; account = purple_connection_get_account(gc); status = purple_account_get_active_status(account); purple_status_to_jabber(status, &state, &msg, &priority); presence = jabber_presence_create_js(js, state, msg, priority); g_free(msg); jid = g_strdup_printf("%s@%s/%s", room, server, handle); xmlnode_set_attrib(presence, "to", jid); g_free(jid); x = xmlnode_new_child(presence, "x"); xmlnode_set_namespace(x, "http://jabber.org/protocol/muc"); if (password && *password) { xmlnode *p = xmlnode_new_child(x, "password"); xmlnode_insert_data(p, password, -1); } jabber_send(js, presence); xmlnode_free(presence); return chat; }
static xmlnode * jingle_content_to_xml_internal(JingleContent *content, xmlnode *jingle, JingleActionType action) { xmlnode *node = xmlnode_new_child(jingle, "content"); gchar *creator = jingle_content_get_creator(content); gchar *name = jingle_content_get_name(content); gchar *senders = jingle_content_get_senders(content); gchar *disposition = jingle_content_get_disposition(content); xmlnode_set_attrib(node, "creator", creator); xmlnode_set_attrib(node, "name", name); xmlnode_set_attrib(node, "senders", senders); if (strcmp("session", disposition)) xmlnode_set_attrib(node, "disposition", disposition); g_free(disposition); g_free(senders); g_free(name); g_free(creator); if (action != JINGLE_CONTENT_REMOVE) { JingleTransport *transport; if (action != JINGLE_TRANSPORT_ACCEPT && action != JINGLE_TRANSPORT_INFO && action != JINGLE_TRANSPORT_REJECT && action != JINGLE_TRANSPORT_REPLACE) { xmlnode *description = xmlnode_new_child(node, "description"); xmlnode_set_namespace(description, jingle_content_get_description_type(content)); } if (action != JINGLE_TRANSPORT_REJECT && action == JINGLE_TRANSPORT_REPLACE) transport = jingle_content_get_pending_transport(content); else transport = jingle_content_get_transport(content); jingle_transport_to_xml(transport, node, action); g_object_unref(transport); } return node; }
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); }
void jabber_pep_request_item(JabberStream *js, const char *to, const char *node, const char *id, JabberPEPHandler cb) { JabberIq *iq = jabber_iq_new(js, JABBER_IQ_GET); xmlnode *pubsub, *items, *item; xmlnode_set_attrib(iq->node,"to",to); pubsub = xmlnode_new_child(iq->node,"pubsub"); xmlnode_set_namespace(pubsub,"http://jabber.org/protocol/pubsub"); items = xmlnode_new_child(pubsub, "items"); xmlnode_set_attrib(items,"node",node); item = xmlnode_new_child(items, "item"); if(id) xmlnode_set_attrib(item, "id", id); jabber_iq_set_callback(iq,do_pep_iq_request_item_callback,(gpointer)cb); jabber_iq_send(iq); }
void jabber_chat_create_instant_room(JabberChat *chat) { JabberIq *iq; xmlnode *query, *x; char *room_jid; if(!chat) return; chat->config_dialog_handle = NULL; iq = jabber_iq_new_query(chat->js, JABBER_IQ_SET, "http://jabber.org/protocol/muc#owner"); query = xmlnode_get_child(iq->node, "query"); x = xmlnode_new_child(query, "x"); room_jid = g_strdup_printf("%s@%s", chat->room, chat->server); xmlnode_set_attrib(iq->node, "to", room_jid); xmlnode_set_namespace(x, "jabber:x:data"); xmlnode_set_attrib(x, "type", "submit"); jabber_iq_send(iq); g_free(room_jid); }
static gboolean handle_presence_contact(JabberStream *js, JabberPresence *presence) { JabberBuddyResource *jbr; PurpleAccount *account; PurpleBuddy *b; char *buddy_name; PurpleConversation *conv; buddy_name = jabber_id_get_bare_jid(presence->jid_from); account = purple_connection_get_account(js->gc); b = purple_find_buddy(account, buddy_name); /* * Unbind/unlock from sending messages to a specific resource on * presence changes. This is locked to a specific resource when * receiving a message (in message.c). */ conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, buddy_name, account); if (conv) { purple_debug_info("jabber", "Changed conversation binding from %s to %s\n", purple_conversation_get_name(conv), buddy_name); purple_conversation_set_name(conv, buddy_name); } if (b == NULL) { if (presence->jb != js->user_jb) { purple_debug_warning("jabber", "Got presence for unknown buddy %s on account %s (%p)\n", buddy_name, purple_account_get_username(account), account); g_free(buddy_name); return FALSE; } else { /* this is a different resource of our own account. Resume even when this account isn't on our blist */ } } if (b && presence->vcard_avatar_hash) { const char *ah = presence->vcard_avatar_hash[0] != '\0' ? presence->vcard_avatar_hash : NULL; const char *ah2 = purple_buddy_icons_get_checksum_for_user(b); if (!purple_strequal(ah, ah2)) { /* XXX this is a crappy way of trying to prevent * someone from spamming us with presence packets * and causing us to DoS ourselves...what we really * need is a queue system that can throttle itself, * but i'm too tired to write that right now */ if(!g_slist_find(js->pending_avatar_requests, presence->jb)) { JabberIq *iq; xmlnode *vcard; js->pending_avatar_requests = g_slist_prepend(js->pending_avatar_requests, presence->jb); iq = jabber_iq_new(js, JABBER_IQ_GET); xmlnode_set_attrib(iq->node, "to", buddy_name); vcard = xmlnode_new_child(iq->node, "vCard"); xmlnode_set_namespace(vcard, "vcard-temp"); jabber_iq_set_callback(iq, jabber_vcard_parse_avatar, NULL); jabber_iq_send(iq); } } } if (presence->state == JABBER_BUDDY_STATE_ERROR || presence->type == JABBER_PRESENCE_UNAVAILABLE || presence->type == JABBER_PRESENCE_UNSUBSCRIBED) { jabber_buddy_remove_resource(presence->jb, presence->jid_from->resource); } else { jbr = jabber_buddy_track_resource(presence->jb, presence->jid_from->resource, presence->priority, presence->state, presence->status); jbr->idle = presence->idle ? time(NULL) - presence->idle : 0; } jbr = jabber_buddy_find_resource(presence->jb, NULL); if (jbr) { jabber_google_presence_incoming(js, buddy_name, jbr); purple_prpl_got_user_status(account, buddy_name, jabber_buddy_state_get_status_id(jbr->state), "priority", jbr->priority, "message", jbr->status, NULL); purple_prpl_got_user_idle(account, buddy_name, jbr->idle, jbr->idle); if (presence->nickname) serv_got_alias(js->gc, buddy_name, presence->nickname); } else { purple_prpl_got_user_status(account, buddy_name, jabber_buddy_state_get_status_id(JABBER_BUDDY_STATE_UNAVAILABLE), presence->status ? "message" : NULL, presence->status, NULL); } g_free(buddy_name); return TRUE; }
static void xep_ft_si_offer(PurpleXfer *xfer, const gchar *to) { xmlnode *si_node, *feature, *field, *file, *x; XepIq *iq; XepXfer *xf = xfer->data; BonjourData *bd = NULL; char buf[32]; if(!xf) return; bd = xf->data; if(!bd) return; purple_debug_info("bonjour", "xep file transfer stream initialization offer-id=%d.\n", next_id); /* Assign stream id. */ g_free(xf->iq_id); xf->iq_id = g_strdup_printf("%u", next_id++); iq = xep_iq_new(xf->data, XEP_IQ_SET, to, bonjour_get_jid(bd->jabber_data->account), xf->iq_id); if(iq == NULL) return; /*Construct Stream initialization offer message.*/ si_node = xmlnode_new_child(iq->node, "si"); xmlnode_set_namespace(si_node, "http://jabber.org/protocol/si"); xmlnode_set_attrib(si_node, "profile", "http://jabber.org/protocol/si/profile/file-transfer"); g_free(xf->sid); xf->sid = g_strdup(xf->iq_id); xmlnode_set_attrib(si_node, "id", xf->sid); file = xmlnode_new_child(si_node, "file"); xmlnode_set_namespace(file, "http://jabber.org/protocol/si/profile/file-transfer"); xmlnode_set_attrib(file, "name", xfer->filename); g_snprintf(buf, sizeof(buf), "%" G_GSIZE_FORMAT, xfer->size); xmlnode_set_attrib(file, "size", buf); feature = xmlnode_new_child(si_node, "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", "form"); field = xmlnode_new_child(x, "field"); xmlnode_set_attrib(field, "var", "stream-method"); xmlnode_set_attrib(field, "type", "list-single"); if (xf->mode & XEP_BYTESTREAMS) { xmlnode *option = xmlnode_new_child(field, "option"); xmlnode *value = xmlnode_new_child(option, "value"); xmlnode_insert_data(value, "http://jabber.org/protocol/bytestreams", -1); } if (xf->mode & XEP_IBB) { xmlnode *option = xmlnode_new_child(field, "option"); xmlnode *value = xmlnode_new_child(option, "value"); xmlnode_insert_data(value, "http://jabber.org/protocol/ibb", -1); } xep_iq_send_and_free(iq); }
xmlnode *jabber_presence_create_js(JabberStream *js, JabberBuddyState state, const char *msg, int priority) { xmlnode *show, *status, *presence, *pri, *c; const char *show_string = NULL; #ifdef USE_VV gboolean audio_enabled, video_enabled; #endif presence = xmlnode_new("presence"); if(state == JABBER_BUDDY_STATE_UNAVAILABLE) xmlnode_set_attrib(presence, "type", "unavailable"); else if(state != JABBER_BUDDY_STATE_ONLINE && state != JABBER_BUDDY_STATE_UNKNOWN && state != JABBER_BUDDY_STATE_ERROR) show_string = jabber_buddy_state_get_show(state); if(show_string) { show = xmlnode_new_child(presence, "show"); xmlnode_insert_data(show, show_string, -1); } if(msg) { status = xmlnode_new_child(presence, "status"); xmlnode_insert_data(status, msg, -1); } if(priority) { char *pstr = g_strdup_printf("%d", priority); pri = xmlnode_new_child(presence, "priority"); xmlnode_insert_data(pri, pstr, -1); g_free(pstr); } /* if we are idle and not offline, include idle */ if (js->idle && state != JABBER_BUDDY_STATE_UNAVAILABLE) { xmlnode *query = xmlnode_new_child(presence, "query"); gchar seconds[10]; g_snprintf(seconds, 10, "%d", (int) (time(NULL) - js->idle)); xmlnode_set_namespace(query, NS_LAST_ACTIVITY); xmlnode_set_attrib(query, "seconds", seconds); } /* JEP-0115 */ /* calculate hash */ jabber_caps_calculate_own_hash(js); /* create xml */ c = xmlnode_new_child(presence, "c"); xmlnode_set_namespace(c, "http://jabber.org/protocol/caps"); xmlnode_set_attrib(c, "node", CAPS0115_NODE); xmlnode_set_attrib(c, "hash", "sha-1"); xmlnode_set_attrib(c, "ver", jabber_caps_get_own_hash(js)); #ifdef USE_VV /* * MASSIVE HUGE DISGUSTING HACK * This is a huge hack. As far as I can tell, Google Talk's gmail client * doesn't bother to check the actual features we advertise; they * just assume that if we specify a 'voice-v1' ext (ignoring that * these are to be assigned no semantic value), we support receiving voice * calls. * * Ditto for 'video-v1'. */ audio_enabled = jabber_audio_enabled(js, NULL /* unused */); video_enabled = jabber_video_enabled(js, NULL /* unused */); if (audio_enabled && video_enabled) xmlnode_set_attrib(c, "ext", "voice-v1 camera-v1 video-v1"); else if (audio_enabled) xmlnode_set_attrib(c, "ext", "voice-v1"); else if (video_enabled) xmlnode_set_attrib(c, "ext", "camera-v1 video-v1"); #endif return presence; }
static void google_session_ready(GoogleSession *session) { PurpleMedia *media = ((GoogleAVSessionData *)session->session_data)->media; gboolean video = ((GoogleAVSessionData *)session->session_data)->video; if (purple_media_codecs_ready(media, NULL) && purple_media_candidates_prepared(media, NULL, NULL)) { gchar *me = g_strdup_printf("%s@%s/%s", session->js->user->node, session->js->user->domain, session->js->user->resource); JabberIq *iq; xmlnode *sess, *desc, *payload; GList *codecs, *iter; gboolean is_initiator = !strcmp(session->id.initiator, me); if (!is_initiator && !purple_media_accepted(media, NULL, NULL)) { g_free(me); return; } iq = jabber_iq_new(session->js, JABBER_IQ_SET); if (is_initiator) { xmlnode_set_attrib(iq->node, "to", session->remote_jid); xmlnode_set_attrib(iq->node, "from", session->id.initiator); sess = google_session_create_xmlnode(session, "initiate"); } else { google_session_send_candidates(media, "google-voice", session->remote_jid, session); google_session_send_candidates(media, "google-video", session->remote_jid, session); xmlnode_set_attrib(iq->node, "to", session->remote_jid); xmlnode_set_attrib(iq->node, "from", me); sess = google_session_create_xmlnode(session, "accept"); } xmlnode_insert_child(iq->node, sess); desc = xmlnode_new_child(sess, "description"); if (video) xmlnode_set_namespace(desc, NS_GOOGLE_SESSION_VIDEO); else xmlnode_set_namespace(desc, NS_GOOGLE_SESSION_PHONE); codecs = purple_media_get_codecs(media, "google-video"); for (iter = codecs; iter; iter = g_list_next(iter)) { PurpleMediaCodec *codec = (PurpleMediaCodec*)iter->data; gchar *id = g_strdup_printf("%d", purple_media_codec_get_id(codec)); gchar *encoding_name = purple_media_codec_get_encoding_name(codec); payload = xmlnode_new_child(desc, "payload-type"); xmlnode_set_attrib(payload, "id", id); xmlnode_set_attrib(payload, "name", encoding_name); xmlnode_set_attrib(payload, "width", "320"); xmlnode_set_attrib(payload, "height", "200"); xmlnode_set_attrib(payload, "framerate", "30"); g_free(encoding_name); g_free(id); } purple_media_codec_list_free(codecs); codecs = purple_media_get_codecs(media, "google-voice"); for (iter = codecs; iter; iter = g_list_next(iter)) { PurpleMediaCodec *codec = (PurpleMediaCodec*)iter->data; gchar *id = g_strdup_printf("%d", purple_media_codec_get_id(codec)); gchar *encoding_name = purple_media_codec_get_encoding_name(codec); gchar *clock_rate = g_strdup_printf("%d", purple_media_codec_get_clock_rate(codec)); payload = xmlnode_new_child(desc, "payload-type"); if (video) xmlnode_set_namespace(payload, NS_GOOGLE_SESSION_PHONE); xmlnode_set_attrib(payload, "id", id); /* * Hack to make Gmail accept speex as the codec. * It shouldn't have to be case sensitive. */ if (purple_strequal(encoding_name, "SPEEX")) xmlnode_set_attrib(payload, "name", "speex"); else xmlnode_set_attrib(payload, "name", encoding_name); xmlnode_set_attrib(payload, "clockrate", clock_rate); g_free(clock_rate); g_free(encoding_name); g_free(id); } purple_media_codec_list_free(codecs); jabber_iq_send(iq); if (is_initiator) { google_session_send_candidates(media, "google-voice", session->remote_jid, session); google_session_send_candidates(media, "google-video", session->remote_jid, session); } g_signal_handlers_disconnect_by_func(G_OBJECT(media), G_CALLBACK(google_session_ready), session); } }