📄 presence.c
字号:
/* * purple - Jabber Protocol Plugin * * Copyright (C) 2003, Nathan Walp <faceprint@faceprint.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */#include "internal.h"#include "account.h"#include "cipher.h"#include "conversation.h"#include "debug.h"#include "notify.h"#include "request.h"#include "server.h"#include "status.h"#include "util.h"#include "xmlnode.h"#include "buddy.h"#include "chat.h"#include "presence.h"#include "iq.h"#include "jutil.h"static void chats_send_presence_foreach(gpointer key, gpointer val, gpointer user_data){ JabberChat *chat = val; xmlnode *presence = user_data; char *chat_full_jid; if(!chat->conv) return; chat_full_jid = g_strdup_printf("%s@%s/%s", chat->room, chat->server, chat->handle); xmlnode_set_attrib(presence, "to", chat_full_jid); jabber_send(chat->js, presence); g_free(chat_full_jid);}void jabber_presence_fake_to_self(JabberStream *js, const PurpleStatus *gstatus) { char *my_base_jid; if(!js->user) return; my_base_jid = g_strdup_printf("%s@%s", js->user->node, js->user->domain); if(purple_find_buddy(js->gc->account, my_base_jid)) { JabberBuddy *jb; JabberBuddyResource *jbr; if((jb = jabber_buddy_find(js, my_base_jid, TRUE))) { JabberBuddyState state; char *msg; int priority; purple_status_to_jabber(gstatus, &state, &msg, &priority); if (state == JABBER_BUDDY_STATE_UNAVAILABLE || state == JABBER_BUDDY_STATE_UNKNOWN) { jabber_buddy_remove_resource(jb, js->user->resource); } else { jabber_buddy_track_resource(jb, js->user->resource, priority, state, msg); } if((jbr = jabber_buddy_find_resource(jb, NULL))) { purple_prpl_got_user_status(js->gc->account, my_base_jid, jabber_buddy_state_get_status_id(jbr->state), "priority", jbr->priority, jbr->status ? "message" : NULL, jbr->status, NULL); } else { purple_prpl_got_user_status(js->gc->account, my_base_jid, "offline", msg ? "message" : NULL, msg, NULL); } g_free(msg); } } g_free(my_base_jid);}void jabber_presence_send(PurpleAccount *account, PurpleStatus *status){ PurpleConnection *gc = NULL; JabberStream *js = NULL; gboolean disconnected; int primitive; xmlnode *presence, *x, *photo; char *stripped = NULL; JabberBuddyState state; int priority; if(!purple_status_is_active(status)) return; disconnected = purple_account_is_disconnected(account); if(disconnected) return; primitive = purple_status_type_get_primitive(purple_status_get_type(status)); gc = purple_account_get_connection(account); js = gc->proto_data; purple_status_to_jabber(status, &state, &stripped, &priority); presence = jabber_presence_create(state, stripped, priority); g_free(stripped); if(js->avatar_hash) { x = xmlnode_new_child(presence, "x"); xmlnode_set_namespace(x, "vcard-temp:x:update"); photo = xmlnode_new_child(x, "photo"); 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); jabber_presence_fake_to_self(js, status);}xmlnode *jabber_presence_create(JabberBuddyState state, const char *msg, int priority){ xmlnode *show, *status, *presence, *pri, *c; const char *show_string = NULL; 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); } /* JEP-0115 */ 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, "ver", VERSION); return presence;}struct _jabber_add_permit { PurpleConnection *gc; JabberStream *js; char *who;};static void authorize_add_cb(struct _jabber_add_permit *jap){ jabber_presence_subscription_set(jap->gc->proto_data, jap->who, "subscribed"); g_free(jap->who); g_free(jap);}static void deny_add_cb(struct _jabber_add_permit *jap){ jabber_presence_subscription_set(jap->gc->proto_data, jap->who, "unsubscribed"); g_free(jap->who); g_free(jap);}static void jabber_vcard_parse_avatar(JabberStream *js, xmlnode *packet, gpointer blah){ JabberBuddy *jb = NULL; xmlnode *vcard, *photo, *binval; char *text; guchar *data; gsize size; const char *from = xmlnode_get_attrib(packet, "from"); if(!from) return; jb = jabber_buddy_find(js, from, TRUE); js->pending_avatar_requests = g_slist_remove(js->pending_avatar_requests, jb); if((vcard = xmlnode_get_child(packet, "vCard")) || (vcard = xmlnode_get_child_with_namespace(packet, "query", "vcard-temp"))) { if((photo = xmlnode_get_child(vcard, "PHOTO")) && (( (binval = xmlnode_get_child(photo, "BINVAL")) && (text = xmlnode_get_data(binval))) || (text = xmlnode_get_data(photo)))) { unsigned char hashval[20]; char hash[41], *p; int i; data = purple_base64_decode(text, &size); purple_cipher_digest_region("sha1", data, size, sizeof(hashval), hashval, NULL); p = hash; for(i=0; i<20; i++, p+=2) snprintf(p, 3, "%02x", hashval[i]); purple_buddy_icons_set_for_user(js->gc->account, from, data, size, hash); g_free(text); } }}void jabber_presence_parse(JabberStream *js, xmlnode *packet){ const char *from = xmlnode_get_attrib(packet, "from"); const char *type = xmlnode_get_attrib(packet, "type"); const char *real_jid = NULL; const char *affiliation = NULL; const char *role = NULL; char *status = NULL; int priority = 0; JabberID *jid; JabberChat *chat; JabberBuddy *jb; JabberBuddyResource *jbr = NULL, *found_jbr = NULL; PurpleConvChatBuddyFlags flags = PURPLE_CBFLAGS_NONE; gboolean delayed = FALSE; PurpleBuddy *b = NULL; char *buddy_name; JabberBuddyState state = JABBER_BUDDY_STATE_UNKNOWN; xmlnode *y; gboolean muc = FALSE; char *avatar_hash = NULL; if(!(jb = jabber_buddy_find(js, from, TRUE))) return; if(!(jid = jabber_id_new(from))) return; if(jb->error_msg) { g_free(jb->error_msg); jb->error_msg = NULL; } if(type && !strcmp(type, "error")) { char *msg = jabber_parse_error(js, packet); state = JABBER_BUDDY_STATE_ERROR; jb->error_msg = msg ? msg : g_strdup(_("Unknown Error in presence")); } else if(type && !strcmp(type, "subscribe")) { struct _jabber_add_permit *jap = g_new0(struct _jabber_add_permit, 1); gboolean onlist = FALSE; PurpleBuddy *buddy = purple_find_buddy(purple_connection_get_account(js->gc), from); JabberBuddy *jb = NULL; if (buddy) { jb = jabber_buddy_find(js, from, TRUE); if ((jb->subscription & JABBER_SUB_TO)) onlist = TRUE; } jap->gc = js->gc; jap->who = g_strdup(from); jap->js = js; purple_account_request_authorization(purple_connection_get_account(js->gc), from, NULL, NULL, NULL, onlist, G_CALLBACK(authorize_add_cb), G_CALLBACK(deny_add_cb), jap); jabber_id_free(jid); return; } else if(type && !strcmp(type, "subscribed")) { /* we've been allowed to see their presence, but we don't care */ jabber_id_free(jid); return; } else if(type && !strcmp(type, "unsubscribe")) { /* XXX I'm not sure this is the right way to handle this, it * might be better to add "unsubscribe" to the presence status * if lower down, but I'm not sure. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -