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; }
void jabber_presence_send(JabberStream *js, gboolean force) { PurpleAccount *account; xmlnode *presence, *x, *photo; char *stripped = NULL; JabberBuddyState state; int priority; const char *artist = NULL, *title = NULL, *source = NULL, *uri = NULL, *track = NULL; int length = -1; gboolean allowBuzz; PurplePresence *p; PurpleStatus *status, *tune; account = purple_connection_get_account(js->gc); p = purple_account_get_presence(account); status = purple_presence_get_active_status(p); /* we don't want to send presence before we've gotten our roster */ if (js->state != JABBER_STREAM_CONNECTED) { purple_debug_misc("jabber", "attempt to send presence before roster retrieved\n"); return; } purple_status_to_jabber(status, &state, &stripped, &priority); /* check for buzz support */ allowBuzz = purple_status_get_attr_boolean(status,"buzz"); /* changing the buzz state has to trigger a re-broadcasting of the presence for caps */ tune = purple_presence_get_status(p, "tune"); if (js->googletalk && !stripped && purple_status_is_active(tune)) { stripped = jabber_google_presence_outgoing(tune); } #define CHANGED(a,b) ((!a && b) || (a && a[0] == '\0' && b && b[0] != '\0') || \ (a && !b) || (a && a[0] != '\0' && b && b[0] == '\0') || (a && b && strcmp(a,b))) /* check if there are any differences to the <presence> and send them in that case */ if (force || allowBuzz != js->allowBuzz || js->old_state != state || CHANGED(js->old_msg, stripped) || js->old_priority != priority || CHANGED(js->old_avatarhash, js->avatar_hash) || js->old_idle != js->idle) { /* Need to update allowBuzz before creating the presence (with caps) */ js->allowBuzz = allowBuzz; presence = jabber_presence_create_js(js, state, stripped, priority); /* Per XEP-0153 4.1, we must always send the <x> */ x = xmlnode_new_child(presence, "x"); xmlnode_set_namespace(x, "vcard-temp:x:update"); /* * FIXME: Per XEP-0153 4.3.2 bullet 2, we must not publish our * image hash if another resource has logged in and updated the * vcard avatar. Requires changes in jabber_presence_parse. */ if (js->vcard_fetched) { /* Always publish a <photo>; it's empty if we have no image. */ photo = xmlnode_new_child(x, "photo"); if (js->avatar_hash) xmlnode_insert_data(photo, js->avatar_hash, -1); } jabber_send(js, presence); g_hash_table_foreach(js->chats, chats_send_presence_foreach, presence); xmlnode_free(presence); /* update old values */ if(js->old_msg) g_free(js->old_msg); if(js->old_avatarhash) g_free(js->old_avatarhash); js->old_msg = g_strdup(stripped); js->old_avatarhash = g_strdup(js->avatar_hash); js->old_state = state; js->old_priority = priority; js->old_idle = js->idle; } g_free(stripped); /* next, check if there are any changes to the tune values */ if (purple_status_is_active(tune)) { artist = purple_status_get_attr_string(tune, PURPLE_TUNE_ARTIST); title = purple_status_get_attr_string(tune, PURPLE_TUNE_TITLE); source = purple_status_get_attr_string(tune, PURPLE_TUNE_ALBUM); uri = purple_status_get_attr_string(tune, PURPLE_TUNE_URL); track = purple_status_get_attr_string(tune, PURPLE_TUNE_TRACK); length = (!purple_status_get_attr_value(tune, PURPLE_TUNE_TIME)) ? -1 : purple_status_get_attr_int(tune, PURPLE_TUNE_TIME); } if(CHANGED(artist, js->old_artist) || CHANGED(title, js->old_title) || CHANGED(source, js->old_source) || CHANGED(uri, js->old_uri) || CHANGED(track, js->old_track) || (length != js->old_length)) { PurpleJabberTuneInfo tuneinfo = { (char*)artist, (char*)title, (char*)source, (char*)track, length, (char*)uri }; jabber_tune_set(js->gc, &tuneinfo); /* update old values */ g_free(js->old_artist); g_free(js->old_title); g_free(js->old_source); g_free(js->old_uri); g_free(js->old_track); js->old_artist = g_strdup(artist); js->old_title = g_strdup(title); js->old_source = g_strdup(source); js->old_uri = g_strdup(uri); js->old_length = length; js->old_track = g_strdup(track); } #undef CHANGED jabber_presence_fake_to_self(js, status); }
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; }
/** * \fn xmlnode_received_cb * \brief Reacts to requests and receipts */ static void xmlnode_received_cb(PurpleConnection *gc, xmlnode **packet, gpointer null) { if(*packet != NULL) { if(strcmp((*packet)->name, "message") == 0) { #ifdef DEBUG printf("got message\n"); #endif xmlnode* nodeRequest = xmlnode_get_child (*packet, "request"); const char* strFrom = xmlnode_get_attrib(*packet , "from"); //Answer to an request and verify namespace if(nodeRequest) { #ifdef DEBUG printf("got request\n"); #endif const char* strId = xmlnode_get_attrib(*packet , "id"); const char* strNS = xmlnode_get_namespace(nodeRequest); if(strcmp(strNS, "urn:xmpp:receipts") == 0) { xmlnode *message = xmlnode_new("message"); xmlnode_set_attrib(message, "to", strFrom); xmlnode *received = xmlnode_new_child(message, "received"); xmlnode_set_namespace(received, "urn:xmpp:receipts"); xmlnode_set_attrib(received, "id", strId); purple_signal_emit(purple_connection_get_prpl(gc), "jabber-sending-xmlnode", gc, &message); if (message != NULL) xmlnode_free(message); } } //Find incoming receipt and call the display-function xmlnode* nodeReceived = xmlnode_get_child (*packet, "received"); if(nodeReceived) { #ifdef DEBUG printf("got received\n"); #endif const char* strNS = xmlnode_get_namespace(nodeReceived); const char* strId = xmlnode_get_attrib(nodeReceived , "id"); if (strcmp(strNS, "urn:xmpp:receipts") == 0) { display_message_receipt(strId); } } } } }
static void jabber_x_data_ok_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; GList *groups, *flds; xmlnode_set_namespace(result, "jabber:x:data"); xmlnode_set_attrib(result, "type", "submit"); for(groups = gaim_request_fields_get_groups(fields); groups; groups = groups->next) { for(flds = gaim_request_field_group_get_fields(groups->data); flds; flds = flds->next) { xmlnode *fieldnode, *valuenode; GaimRequestField *field = flds->data; const char *id = gaim_request_field_get_id(field); jabber_x_data_field_type type = GPOINTER_TO_INT(g_hash_table_lookup(data->fields, id)); switch(type) { case JABBER_X_DATA_TEXT_SINGLE: case JABBER_X_DATA_JID_SINGLE: { const char *value = gaim_request_field_string_get_value(field); fieldnode = xmlnode_new_child(result, "field"); xmlnode_set_attrib(fieldnode, "var", id); valuenode = xmlnode_new_child(fieldnode, "value"); if(value) xmlnode_insert_data(valuenode, value, -1); break; } case JABBER_X_DATA_TEXT_MULTI: { char **pieces, **p; const char *value = gaim_request_field_string_get_value(field); fieldnode = xmlnode_new_child(result, "field"); xmlnode_set_attrib(fieldnode, "var", id); pieces = g_strsplit(value, "\n", -1); for(p = pieces; *p != NULL; p++) { valuenode = xmlnode_new_child(fieldnode, "value"); xmlnode_insert_data(valuenode, *p, -1); } g_strfreev(pieces); } break; case JABBER_X_DATA_LIST_SINGLE: case JABBER_X_DATA_LIST_MULTI: { const GList *selected = gaim_request_field_list_get_selected(field); char *value; fieldnode = xmlnode_new_child(result, "field"); xmlnode_set_attrib(fieldnode, "var", id); while(selected) { value = gaim_request_field_list_get_data(field, selected->data); valuenode = xmlnode_new_child(fieldnode, "value"); if(value) xmlnode_insert_data(valuenode, value, -1); selected = selected->next; } } break; case JABBER_X_DATA_BOOLEAN: fieldnode = xmlnode_new_child(result, "field"); xmlnode_set_attrib(fieldnode, "var", id); valuenode = xmlnode_new_child(fieldnode, "value"); if(gaim_request_field_bool_get_value(field)) xmlnode_insert_data(valuenode, "1", -1); else xmlnode_insert_data(valuenode, "0", -1); break; case JABBER_X_DATA_IGNORE: break; } } } 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); cb(js, result, user_data); }
void AddMobileBuddy(struct fetion_account_data *sip, struct sipmsg *msg, struct transaction *tc) { gint xml_len; xmlnode *root, *son, *item; gchar *body; const gchar *uri, *name, *group_id; struct group_attr *g_attr = NULL; gchar *buddy_name; PurpleBuddy *b; PurpleGroup *g = NULL; struct fetion_buddy *bs; struct sipmsg *old = NULL; const gchar *real_name; real_name = purple_account_get_string(sip->account, "realname", sip->username); if (!real_name || strlen(real_name) < 1) { real_name = sip->username; } g_return_if_fail(tc->msg != NULL); old = tc->msg; g_return_if_fail(old != NULL); purple_debug_info("fetion:", "AddMobileBuddy:oldmsg[%s]", old->body); root = xmlnode_from_str(old->body, old->bodylen); item = xmlnode_get_child(root, "contacts/buddies/buddy"); g_return_if_fail(item != NULL); uri = xmlnode_get_attrib(item, "uri"); name = xmlnode_get_attrib(item, "local-name"); group_id = xmlnode_get_attrib(item, "buddy-lists"); buddy_name = g_strdup_printf("%s", uri); g_attr = g_hash_table_lookup(sip->group, group_id); g_return_if_fail(g_attr != NULL); 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); } 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); xmlnode_free(root); root = xmlnode_new("args"); g_return_if_fail(root != NULL); son = xmlnode_new_child(root, "contacts"); g_return_if_fail(son != NULL); son = xmlnode_new_child(son, "mobile-buddies"); g_return_if_fail(son != NULL); item = xmlnode_new_child(son, "mobile-buddy"); g_return_if_fail(item != NULL); xmlnode_set_attrib(item, "expose-mobile-no", "1"); xmlnode_set_attrib(item, "expose-name", "1"); xmlnode_set_attrib(item, "invite", "1"); xmlnode_set_attrib(item, "uri", buddy_name); xmlnode_set_attrib(item, "buddy-lists", "1"); //xmlnode_set_attrib(item,"desc",sip->mobileno); xmlnode_set_attrib(item, "desc", real_name); body = g_strdup_printf("%s",xmlnode_to_str(root, &xml_len)); purple_debug_info("fetion:", "add_buddy:body=[%s]", body); send_sip_request(sip->gc, "S", "", "", "N: AddMobileBuddy\r\n", body, NULL, (TransCallback) AddMobileBuddy_cb); g_free(buddy_name); xmlnode_free(root); g_free(body); }
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; char *history_maxchars; char *history_maxstanzas; char *history_seconds; char *history_since; struct tm history_since_datetime; const char *history_since_string = NULL; 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); history_maxchars = g_hash_table_lookup(data, "history_maxchars"); history_maxstanzas = g_hash_table_lookup(data, "history_maxstanzas"); history_seconds = g_hash_table_lookup(data, "history_seconds"); history_since = g_hash_table_lookup(data, "history_since"); if (history_since) { if (purple_str_to_time(history_since, TRUE, &history_since_datetime, NULL, NULL) != 0) { history_since_string = purple_utf8_strftime("%Y-%m-%dT%H:%M:%SZ", &history_since_datetime); } else { history_since_string = NULL; purple_debug_error("jabber", "Invalid date format for history_since" " while requesting history: %s", history_since); } } 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); } if ((history_maxchars && *history_maxchars) || (history_maxstanzas && *history_maxstanzas) || (history_seconds && *history_seconds) || (history_since_string && *history_since_string)) { xmlnode *history = xmlnode_new_child(x, "history"); if (history_maxchars && *history_maxchars) { xmlnode_set_attrib(history, "maxchars", history_maxchars); } if (history_maxstanzas && *history_maxstanzas) { xmlnode_set_attrib(history, "maxstanzas", history_maxstanzas); } if (history_seconds && *history_seconds) { xmlnode_set_attrib(history, "seconds", history_seconds); } if (history_since_string && *history_since_string) { xmlnode_set_attrib(history, "since", history_since_string); } } jabber_send(js, presence); xmlnode_free(presence); return chat; }
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); } }
/* ------------------ * called on received message * ------------------ */ static gboolean jabber_message_received(PurpleConnection *pc, const char *type, const char *id, const char *from, const char *to, xmlnode *message) { const xmlnode* parent_node = message; xmlnode* x_node = NULL; xmlnode* body_node = NULL; if (parent_node == NULL) return FALSE; // check if message is a key body_node = xmlnode_get_child(parent_node,"body"); if (body_node != NULL) { char* data = xmlnode_get_data(body_node); if (data != NULL) { char* header = "-----BEGIN PGP PUBLIC KEY BLOCK-----"; if (strncmp(data,header,strlen(header)) == 0) { // if we received a ascii armored key // try to import it //purple_conversation_write(conv,"","received key",PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG,time(NULL)); if (import_key(data) == TRUE) { xmlnode_clear_data(body_node); xmlnode_insert_data(body_node,"key import ok",-1); } else { xmlnode_clear_data(body_node); xmlnode_insert_data(body_node,"key import failed",-1); } } } } // check if the user with the jid=from has signed his presence char* bare_jid = get_bare_jid(from); // get stored info about user struct list_item* item = g_hash_table_lookup(list_fingerprints,bare_jid); if (item == NULL) { //TODO: maybe create item in list? }else { // set default value to "not encrypted mode" item->mode_sec = FALSE; } free(bare_jid); // check if message has special "x" child node => encrypted message x_node = xmlnode_get_child_with_namespace(parent_node,"x",NS_ENC); if (x_node != NULL) { purple_debug_info(PLUGIN_ID, "user %s sent us an encrypted message\n",from); // get data of "x" node char* cipher_str = xmlnode_get_data(x_node); if (cipher_str != NULL) { // try to decrypt char* plain_str = decrypt(cipher_str); if (plain_str != NULL) { purple_debug_info(PLUGIN_ID, "decrypted message: %s\n",plain_str); // find body node xmlnode *body_node = xmlnode_get_child(parent_node,"body"); if (body_node != NULL) { // clear body node data if it is found xmlnode_clear_data(body_node); }else { // add body node if it is not found body_node = xmlnode_new_child(message,"body"); } // set "body" content node to decrypted string //xmlnode_insert_data(body_node,"Encrypted message: ",-1); xmlnode_insert_data(body_node,plain_str,-1); // only set to encrypted mode, if we know other users key fingerprint if (item != NULL) { // all went well, we received an encrypted message item->mode_sec = TRUE; } }else { purple_debug_error(PLUGIN_ID, "could not decrypt message!\n"); } }else { purple_debug_error(PLUGIN_ID, "xml token had no data!\n"); } } /* We don't want the plugin to stop processing */ return FALSE; }
static void yahoo_set_userinfo_cb(PurpleConnection *gc, PurpleRequestFields *fields) { xmlnode *node = xmlnode_new("ab"); xmlnode *ct = xmlnode_new_child(node, "ct"); YahooData *yd = purple_connection_get_protocol_data(gc); PurpleAccount *account; PurpleUtilFetchUrlData *url_data; char *webaddress, *webpage; char *request, *content; int len; int i; char * yfields[] = { "fn", "ln", "nn", "mn", "hp", "wp", "mo", NULL }; account = purple_connection_get_account(gc); xmlnode_set_attrib(node, "k", purple_connection_get_display_name(gc)); xmlnode_set_attrib(node, "cc", "1"); /* XXX: ? */ xmlnode_set_attrib(ct, "e", "1"); xmlnode_set_attrib(ct, "yi", purple_request_fields_get_string(fields, "yname")); xmlnode_set_attrib(ct, "id", purple_request_fields_get_string(fields, "yid")); xmlnode_set_attrib(ct, "pr", "0"); for (i = 0; yfields[i]; i++) { const char *v = purple_request_fields_get_string(fields, yfields[i]); xmlnode_set_attrib(ct, yfields[i], v ? v : ""); } content = xmlnode_to_formatted_str(node, &len); xmlnode_free(node); purple_url_parse(yd->jp ? YAHOOJP_USERINFO_URL : YAHOO_USERINFO_URL, &webaddress, NULL, &webpage, NULL, NULL); request = g_strdup_printf("POST %s HTTP/1.1\r\n" "User-Agent: " YAHOO_CLIENT_USERAGENT "\r\n" "Cookie: T=%s; path=/; domain=.yahoo.com; Y=%s;\r\n" "Host: %s\r\n" "Content-Length: %d\r\n" "Cache-Control: no-cache\r\n\r\n" "%s\r\n\r\n", webpage, yd->cookie_t, yd->cookie_y, webaddress, len + 4, content); #if 0 { /* This is if we wanted to send our contact details to everyone * in the buddylist. But this cannot be done now, because in the * official messenger, doing this pops a conversation window at * the receiver's end, which is stupid, and thus not really * surprising. */ struct yahoo_userinfo *ui = g_new(struct yahoo_userinfo, 1); node = xmlnode_new("contact"); for (i = 0; yfields[i]; i++) { const char *v = purple_request_fields_get_string(fields, yfields[i]); if (v) { xmlnode *nd = xmlnode_new_child(node, yfields[i]); xmlnode_insert_data(nd, v, -1); } } ui->yd = yd; ui->xml = xmlnode_to_str(node, NULL); xmlnode_free(node); } #endif url_data = purple_util_fetch_url_request_len_with_account(account, webaddress, FALSE, YAHOO_CLIENT_USERAGENT, TRUE, request, FALSE, -1, yahoo_fetch_aliases_cb, gc); if (url_data != NULL) yd->url_datas = g_slist_prepend(yd->url_datas, url_data); g_free(webaddress); g_free(webpage); g_free(content); g_free(request); }
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); } }
static void got_file_send_progress(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, gsize len, const gchar *error_message) { SkypeWebFileTransfer *swft = user_data; PurpleXfer *xfer = swft->xfer; SkypeWebAccount *sa = swft->sa; JsonParser *parser; JsonNode *node; JsonObject *obj; sa->url_datas = g_slist_remove(sa->url_datas, url_data); //{"content_length":0,"content_full_length":0,"view_length":0,"content_state":"no content","view_state":"none","view_location":"https://nus1-api.asm.skype.com/v1/objects/0-cus-d1-61121cfae8cf601944627a66afdb77ad/views/original","status_location":"https://nus1-api.asm.skype.com/v1/objects/0-cus-d1-61121cfae8cf601944627a66afdb77ad/views/original/status"} parser = json_parser_new(); if (!json_parser_load_from_data(parser, url_text, len, NULL)) { //probably bad poll_file_send_progress(swft); return; } node = json_parser_get_root(parser); if (node == NULL || json_node_get_node_type(node) != JSON_NODE_OBJECT) { //probably bad poll_file_send_progress(swft); return; } obj = json_node_get_object(node); if (json_object_has_member(obj, "status_location")) { g_free(swft->url); swft->url = g_strdup(json_object_get_string_member(obj, "status_location")); } if (json_object_has_member(obj, "content_state") && g_str_equal(json_object_get_string_member(obj, "content_state"), "ready")) { xmlnode *uriobject = xmlnode_new("URIObject"); xmlnode *title = xmlnode_new_child(uriobject, "Title"); xmlnode *description = xmlnode_new_child(uriobject, "Description"); xmlnode *anchor = xmlnode_new_child(uriobject, "a"); xmlnode *originalname = xmlnode_new_child(uriobject, "OriginalName"); xmlnode *filesize = xmlnode_new_child(uriobject, "FileSize"); gchar *message, *temp; //We finally did it! // May the pesants rejoyce purple_xfer_set_completed(xfer, TRUE); // Don't forget to let the other end know about it xmlnode_set_attrib(uriobject, "type", "File.1"); temp = g_strconcat("https://" SKYPEWEB_XFER_HOST "/v1/objects/", purple_url_encode(swft->id), NULL); xmlnode_set_attrib(uriobject, "uri", temp); g_free(temp); temp = g_strconcat("https://" SKYPEWEB_XFER_HOST "/v1/objects/", purple_url_encode(swft->id), "/views/thumbnail", NULL); xmlnode_set_attrib(uriobject, "url_thumbnail", temp); g_free(temp); xmlnode_insert_data(title, purple_xfer_get_filename(xfer), -1); xmlnode_insert_data(description, "Description: ", -1); temp = g_strconcat("https://login.skype.com/login/sso?go=webclient.xmm&docid=", purple_url_encode(swft->id), NULL); xmlnode_set_attrib(anchor, "href", temp); xmlnode_insert_data(anchor, temp, -1); g_free(temp); xmlnode_set_attrib(originalname, "v", purple_xfer_get_filename(xfer)); temp = g_strdup_printf("%d", purple_xfer_get_size(xfer)); xmlnode_set_attrib(filesize, "v", temp); g_free(temp); message = xmlnode_to_str(uriobject, NULL); skypeweb_send_im(sa->pc, swft->from, message, PURPLE_MESSAGE_SEND); g_free(message); skypeweb_free_xfer(xfer); purple_xfer_unref(xfer); xmlnode_free(uriobject); g_object_unref(parser); return; } g_object_unref(parser); // probably good poll_file_send_progress(swft); }
void jabber_iq_parse(JabberStream *js, xmlnode *packet) { JabberCallbackData *jcd; xmlnode *query, *error, *x; const char *xmlns; const char *type, *id, *from; JabberIqHandler *jih; query = xmlnode_get_child(packet, "query"); type = xmlnode_get_attrib(packet, "type"); from = xmlnode_get_attrib(packet, "from"); id = xmlnode_get_attrib(packet, "id"); if(type == NULL || !(!strcmp(type, "get") || !strcmp(type, "set") || !strcmp(type, "result") || !strcmp(type, "error"))) { purple_debug_error("jabber", "IQ with invalid type ('%s') - ignoring.\n", type ? type : "(null)"); return; } /* All IQs must have an ID, so send an error for a set/get that doesn't */ if(!id || !*id) { if(!strcmp(type, "set") || !strcmp(type, "get")) { JabberIq *iq = jabber_iq_new(js, JABBER_IQ_ERROR); xmlnode_free(iq->node); iq->node = xmlnode_copy(packet); xmlnode_set_attrib(iq->node, "to", from); xmlnode_remove_attrib(iq->node, "from"); xmlnode_set_attrib(iq->node, "type", "error"); /* This id is clearly not useful, but we must put something there for a valid stanza */ iq->id = jabber_get_next_id(js); xmlnode_set_attrib(iq->node, "id", iq->id); error = xmlnode_new_child(iq->node, "error"); xmlnode_set_attrib(error, "type", "modify"); x = xmlnode_new_child(error, "bad-request"); xmlnode_set_namespace(x, "urn:ietf:params:xml:ns:xmpp-stanzas"); jabber_iq_send(iq); } else purple_debug_error("jabber", "IQ of type '%s' missing id - ignoring.\n", type); return; } /* First, lets see if a special callback got registered */ if(!strcmp(type, "result") || !strcmp(type, "error")) { if(id && *id && (jcd = g_hash_table_lookup(js->iq_callbacks, id))) { jcd->callback(js, packet, jcd->data); jabber_iq_remove_callback_by_id(js, id); return; } } /* Apparently not, so lets see if we have a pre-defined handler */ if(query && (xmlns = xmlnode_get_namespace(query))) { if((jih = g_hash_table_lookup(iq_handlers, xmlns))) { jih(js, packet); return; } } if(xmlnode_get_child_with_namespace(packet, "si", "http://jabber.org/protocol/si")) { jabber_si_parse(js, packet); return; } if(xmlnode_get_child_with_namespace(packet, "new-mail", "google:mail:notify")) { jabber_gmail_poke(js, packet); return; } purple_debug_info("jabber", "jabber_iq_parse\n"); if(xmlnode_get_child_with_namespace(packet, "ping", "urn:xmpp:ping")) { jabber_ping_parse(js, packet); return; } if (xmlnode_get_child_with_namespace(packet, "data", XEP_0231_NAMESPACE)) { jabber_data_parse(js, packet); return; } /* If we get here, send the default error reply mandated by XMPP-CORE */ if(!strcmp(type, "set") || !strcmp(type, "get")) { JabberIq *iq = jabber_iq_new(js, JABBER_IQ_ERROR); xmlnode_free(iq->node); iq->node = xmlnode_copy(packet); xmlnode_set_attrib(iq->node, "to", from); xmlnode_remove_attrib(iq->node, "from"); xmlnode_set_attrib(iq->node, "type", "error"); error = xmlnode_new_child(iq->node, "error"); xmlnode_set_attrib(error, "type", "cancel"); xmlnode_set_attrib(error, "code", "501"); x = xmlnode_new_child(error, "feature-not-implemented"); xmlnode_set_namespace(x, "urn:ietf:params:xml:ns:xmpp-stanzas"); jabber_iq_send(iq); } }
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 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); } }
/* ------------------ * called on every sent packet * ------------------ */ void jabber_send_signal_cb(PurpleConnection *pc, xmlnode **packet, gpointer unused) { if (NULL == packet) return; g_return_if_fail(PURPLE_CONNECTION_IS_VALID(pc)); // if we are sending a presence stanza, add new child node // so others know we support openpgp if (g_str_equal((*packet)->name, "presence")) { const char* status_str = NULL; xmlnode* status_node; // check if user selected a main key const char* fpr = purple_prefs_get_string(PREF_MY_KEY); if (fpr == NULL) fpr = ""; if (strcmp(fpr,"") != 0) {// user did select a key // get status message from packet status_node = xmlnode_get_child(*packet,"status"); if (status_node != NULL) { status_str = xmlnode_get_data(status_node); } // sign status message if (status_str == NULL) status_str = ""; purple_debug_info(PLUGIN_ID, "signing status '%s' with key %s\n",status_str,fpr); char* sig_str = sign(status_str,fpr); if (sig_str == NULL) { purple_debug_error(PLUGIN_ID,"sign failed\n"); return; } // create special "x" childnode purple_debug_info(PLUGIN_ID, "sending presence with signature\n"); xmlnode *x_node = xmlnode_new_child(*packet,"x"); xmlnode_set_namespace(x_node, NS_SIGNED); xmlnode_insert_data(x_node, sig_str,-1); }else { purple_debug_info(PLUGIN_ID, "no key selecteded!\n"); } }else if (g_str_equal((*packet)->name, "message")) { const char* to = xmlnode_get_attrib(*packet,"to"); xmlnode* body_node = xmlnode_get_child(*packet,"body"); if (body_node != NULL && to != NULL) { // get message char* message = g_strdup(xmlnode_get_data(body_node)); char* enc_str = NULL; char* bare_jid = get_bare_jid(to); // get encryption key struct list_item *item = g_hash_table_lookup(list_fingerprints,bare_jid); if (item == NULL) { purple_debug_info(PLUGIN_ID, "there is no key for encrypting message to %s\n",bare_jid); return; } // do not encrypt if mode_sec is disabled if (item->mode_sec == FALSE) return; char* fpr_to = item->fpr; purple_debug_info(PLUGIN_ID, "found key for encryption to user %s: %s\n",bare_jid,fpr_to); free(bare_jid); // encrypt message enc_str = encrypt(message,fpr_to); if (enc_str != NULL) { // remove message from body xmlnode_clear_data(body_node); xmlnode_insert_data(body_node,"[ERROR: This message is encrypted, and you are unable to decrypt it.]",-1); // add special "x" childnode for encrypted text purple_debug_info(PLUGIN_ID, "sending encrypted message\n"); xmlnode *x_node = xmlnode_new_child(*packet,"x"); xmlnode_set_namespace(x_node, NS_ENC); xmlnode_insert_data(x_node, enc_str,-1); }else { purple_debug_error(PLUGIN_ID, "could not encrypt message\n"); } }else { // ignore this type of messages //purple_debug_warning(PLUGIN_ID, "empty message or empty 'to'\n"); } } }
/* jabber_roster_update frees the GSList* passed in */ static void jabber_roster_update(JabberStream *js, const char *name, GSList *groups) { PurpleBuddy *b; PurpleGroup *g; GSList *l; JabberIq *iq; xmlnode *query, *item, *group; const char *balias; if (js->currently_parsing_roster_push) return; if(!(b = purple_find_buddy(js->gc->account, name))) return; if (groups) { char *tmp = roster_groups_join(groups); purple_debug_info("jabber", "jabber_roster_update(%s): [Source: " "groups]: groups: %s\n", name, tmp); g_free(tmp); } else { GSList *buddies = purple_find_buddies(js->gc->account, name); char *tmp; if(!buddies) return; while(buddies) { b = buddies->data; g = purple_buddy_get_group(b); groups = g_slist_append(groups, (char *)purple_group_get_name(g)); buddies = g_slist_remove(buddies, b); } tmp = roster_groups_join(groups); purple_debug_info("jabber", "jabber_roster_update(%s): [Source: local blist]: groups: %s\n", name, tmp); g_free(tmp); } iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:roster"); query = xmlnode_get_child(iq->node, "query"); item = xmlnode_new_child(query, "item"); xmlnode_set_attrib(item, "jid", name); balias = purple_buddy_get_local_buddy_alias(b); xmlnode_set_attrib(item, "name", balias ? balias : ""); for(l = groups; l; l = l->next) { group = xmlnode_new_child(item, "group"); xmlnode_insert_data(group, l->data, -1); } g_slist_free(groups); if (js->server_caps & JABBER_CAP_GOOGLE_ROSTER) { jabber_google_roster_outgoing(js, query, item); xmlnode_set_attrib(query, "xmlns:gr", "google:roster"); xmlnode_set_attrib(query, "gr:ext", "2"); } jabber_iq_send(iq); }
void jabber_chat_join(PurpleConnection *gc, GHashTable *data) { JabberChat *chat; char *room, *server, *handle, *passwd; xmlnode *presence, *x; char *tmp, *room_jid, *full_jid; JabberStream *js = gc->proto_data; PurplePresence *gpresence; PurpleStatus *status; JabberBuddyState state; char *msg; int priority; room = g_hash_table_lookup(data, "room"); server = g_hash_table_lookup(data, "server"); handle = g_hash_table_lookup(data, "handle"); passwd = g_hash_table_lookup(data, "password"); if(!room || !server) return; if(!handle) handle = js->user->node; if(!jabber_nodeprep_validate(room)) { char *buf = g_strdup_printf(_("%s is not a valid room name"), room); purple_notify_error(gc, _("Invalid Room Name"), _("Invalid Room Name"), buf); g_free(buf); return; } else if(!jabber_nameprep_validate(server)) { char *buf = g_strdup_printf(_("%s is not a valid server name"), server); purple_notify_error(gc, _("Invalid Server Name"), _("Invalid Server Name"), buf); g_free(buf); return; } else if(!jabber_resourceprep_validate(handle)) { char *buf = g_strdup_printf(_("%s is not a valid room handle"), handle); purple_notify_error(gc, _("Invalid Room Handle"), _("Invalid Room Handle"), buf); } if(jabber_chat_find(js, room, server)) return; tmp = g_strdup_printf("%s@%s", room, server); room_jid = g_strdup(jabber_normalize(NULL, tmp)); g_free(tmp); chat = g_new0(JabberChat, 1); chat->js = gc->proto_data; chat->room = g_strdup(room); chat->server = g_strdup(server); chat->handle = g_strdup(handle); chat->members = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, (GDestroyNotify)jabber_chat_member_free); g_hash_table_insert(js->chats, room_jid, chat); gpresence = purple_account_get_presence(gc->account); status = purple_presence_get_active_status(gpresence); purple_status_to_jabber(status, &state, &msg, &priority); presence = jabber_presence_create(state, msg, priority); full_jid = g_strdup_printf("%s/%s", room_jid, handle); xmlnode_set_attrib(presence, "to", full_jid); g_free(full_jid); g_free(msg); x = xmlnode_new_child(presence, "x"); xmlnode_set_namespace(x, "http://jabber.org/protocol/muc"); if(passwd && *passwd) { xmlnode *password = xmlnode_new_child(x, "password"); xmlnode_insert_data(password, passwd, -1); } jabber_send(js, presence); xmlnode_free(presence); }
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); }
gint hybrid_logs_write(HybridLogs *log, const gchar *name, const gchar *msg, gboolean sendout) { xmlnode *head_node; xmlnode *body_node; xmlnode *time_node; xmlnode *font_node; xmlnode *name_node; xmlnode *cont_node; xmlnode *node; time_t now; const gchar *body; gchar *title; gchar *content; struct tm *local_time; gchar time_str[128]; g_return_val_if_fail(log != NULL, HYBRID_ERROR); g_return_val_if_fail(name != NULL, HYBRID_ERROR); now = time(NULL); local_time = localtime(&now); /* log file doesn't exist, we create one. */ if (!log->root) { body = "<html></html>"; title = g_strdup_printf(_("Conversation with %s (%s) at %d-%d-%d"), name, log->id, local_time->tm_year + 1900, local_time->tm_mon, local_time->tm_mday); log->root = xmlnode_root(body, strlen(body)); head_node = xmlnode_new_child(log->root, "head"); node = xmlnode_new_child(head_node, "meta"); xmlnode_new_prop(node, "http-equiv", "content-type"); xmlnode_new_prop(node, "content", "text/html; charset=UTF-8"); node = xmlnode_new_child(head_node, "title"); xmlnode_set_content(node, title); node = xmlnode_new_child(log->root, "body"); node = xmlnode_new_child(node, "h3"); xmlnode_set_content(node, title); g_free(title); } if (!(body_node = xmlnode_find(log->root, "body"))) { hybrid_debug_error("logs", "invalid log file."); g_free(title); return HYBRID_ERROR; } node = xmlnode_new_child(body_node, "span"); font_node = xmlnode_new_child(node, "font"); if (sendout) { xmlnode_new_prop(font_node, "color", "#16569E"); } else { xmlnode_new_prop(font_node, "color", "#A82F2F"); } time_node = xmlnode_new_child(font_node, "font"); xmlnode_new_prop(time_node, "size", "2"); memset(time_str, 0, sizeof(time_str)); strftime(time_str, sizeof(time_str) - 1, "(%H:%M:%S) ", local_time); xmlnode_set_content(time_node, time_str); content = g_strdup_printf("%s: ", name); name_node = xmlnode_new_child(font_node, "b"); xmlnode_set_content(name_node, content); g_free(content); cont_node = xmlnode_new_child(node, "font"); xmlnode_set_content(cont_node, msg); xmlnode_new_child(node, "br"); xmlnode_save_file(log->root, log->log_path); return HYBRID_OK; }