# HG changeset patch # User Sean Egan # Date 1166072214 0 # Node ID f814b2df9cce6d8681845af3399cd1978f6d8b8d # Parent b8ae75fa8d6704c83a8755f8fc0a112354cd862f [gaim-migrate @ 17993] Blocking on Google Talk. Our Privacy API sucks so bad that even with no prior support for blocking in Jabber, this has no interface changes. If someone wanted to implement the deprecated Jabber privacy lists API, though, that would be ok by me. committer: Tailor Script diff -r b8ae75fa8d67 -r f814b2df9cce libgaim/protocols/jabber/disco.c --- a/libgaim/protocols/jabber/disco.c Thu Dec 14 04:17:02 2006 +0000 +++ b/libgaim/protocols/jabber/disco.c Thu Dec 14 04:56:54 2006 +0000 @@ -27,7 +27,7 @@ #include "iq.h" #include "disco.h" #include "jabber.h" - +#include "roster.h" struct _jabber_disco_info_cb_data { gpointer data; @@ -262,8 +262,14 @@ if (!strcmp("google:mail:notify", var)) { js->server_caps |= JABBER_CAP_GMAIL_NOTIFY; jabber_gmail_init(js); + } else if (!strcmp("google:roster", var)) { + js->server_caps |= JABBER_CAP_GOOGLE_ROSTER; + jabber_google_roster_init(js); } } + + if (!js->server_caps & JABBER_CAP_GOOGLE_ROSTER) + jabber_roster_request(js); } static void diff -r b8ae75fa8d67 -r f814b2df9cce libgaim/protocols/jabber/google.c --- a/libgaim/protocols/jabber/google.c Thu Dec 14 04:17:02 2006 +0000 +++ b/libgaim/protocols/jabber/google.c Thu Dec 14 04:56:54 2006 +0000 @@ -21,8 +21,12 @@ #include "internal.h" #include "debug.h" +#include "privacy.h" + +#include "buddy.h" #include "google.h" #include "jabber.h" +#include "presence.h" #include "iq.h" static void @@ -167,3 +171,190 @@ jabber_iq_set_callback(iq, jabber_gmail_parse, NULL); jabber_iq_send(iq); } + +void jabber_google_roster_init(JabberStream *js) +{ + JabberIq *iq; + xmlnode *query; + + iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:roster"); + query = xmlnode_get_child(iq->node, "query"); + + xmlnode_set_attrib(query, "xmlns:gr", "google:roster"); + xmlnode_set_attrib(query, "gr:ext", "2"); + + jabber_iq_send(iq); +} + +void jabber_google_roster_outgoing(JabberStream *js, xmlnode *query, xmlnode *item) +{ + GaimAccount *account = gaim_connection_get_account(js->gc); + GSList *list = account->deny; + const char *jid = xmlnode_get_attrib(item, "jid"); + char *jid_norm = g_strdup(jabber_normalize(account, jid)); + + while (list) { + if (!strcmp(jid_norm, (char*)list->data)) { + xmlnode_set_attrib(query, "xmlns:gr", "google:roster"); + xmlnode_set_attrib(item, "gr:t", "B"); + xmlnode_set_attrib(query, "xmlns:gr", "google:roster"); + xmlnode_set_attrib(query, "gr:ext", "2"); + return; + } + list = list->next; + } + +} + +void jabber_google_roster_incoming(JabberStream *js, xmlnode *item) +{ + GaimAccount *account = gaim_connection_get_account(js->gc); + GSList *list = account->deny; + const char *jid = xmlnode_get_attrib(item, "jid"); + gboolean on_block_list = FALSE; + + char *jid_norm = g_strdup(jabber_normalize(account, jid)); + + const char *grt = xmlnode_get_attrib_with_namespace(item, "t", "google:roster"); + + while (list) { + if (!strcmp(jid_norm, (char*)list->data)) { + on_block_list = TRUE; + break; + } + list = list->next; + } + + if (!on_block_list && (grt && (*grt == 'B' || *grt == 'b'))) { + gaim_debug_info("jabber", "Blocking %s\n", jid_norm); + gaim_privacy_deny_add(account, jid_norm, TRUE); + } else if (on_block_list && (!grt || (*grt != 'B' && *grt != 'b' ))){ + gaim_debug_info("jabber", "Unblocking %s\n", jid_norm); + gaim_privacy_deny_remove(account, jid_norm, TRUE); + } +} + +void jabber_google_roster_add_deny(GaimConnection *gc, const char *who) +{ + JabberStream *js; + GSList *buddies; + JabberIq *iq; + xmlnode *query; + xmlnode *item; + xmlnode *group; + GaimBuddy *b; + JabberBuddy *jb; + + js = (JabberStream*)(gc->proto_data); + + if (!js || !js->server_caps & JABBER_CAP_GOOGLE_ROSTER) + return; + + jb = jabber_buddy_find(js, who, TRUE); + + buddies = gaim_find_buddies(js->gc->account, who); + if(!buddies) + return; + + b = buddies->data; + + 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"); + + while(buddies) { + GaimGroup *g; + + b = buddies->data; + g = gaim_buddy_get_group(b); + + group = xmlnode_new_child(item, "group"); + xmlnode_insert_data(group, g->name, -1); + + buddies = buddies->next; + } + + 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", who); + xmlnode_set_attrib(item, "name", b->alias ? b->alias : ""); + xmlnode_set_attrib(item, "gr:t", "B"); + xmlnode_set_attrib(query, "xmlns:gr", "google:roster"); + xmlnode_set_attrib(query, "gr:ext", "2"); + + jabber_iq_send(iq); + + /* Synthesize a sign-off */ + if (jb) { + JabberBuddyResource *jbr; + GList *l = jb->resources; + while (l) { + jbr = l->data; + printf("ASDFA %s\n", jbr->name); + jabber_buddy_remove_resource(jb, jbr->name); + l = l->next; + } + } + gaim_prpl_got_user_status(gaim_connection_get_account(gc), who, "offline", NULL); +} + +void jabber_google_roster_rem_deny(GaimConnection *gc, const char *who) +{ + JabberStream *js; + GSList *buddies; + JabberIq *iq; + xmlnode *query; + xmlnode *item; + xmlnode *group; + GaimBuddy *b; + + g_return_if_fail(gc != NULL); + g_return_if_fail(who != NULL); + + js = (JabberStream*)(gc->proto_data); + + if (!js || !js->server_caps & JABBER_CAP_GOOGLE_ROSTER) + return; + + buddies = gaim_find_buddies(js->gc->account, who); + if(!buddies) + return; + + b = buddies->data; + + 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"); + + while(buddies) { + GaimGroup *g; + + b = buddies->data; + g = gaim_buddy_get_group(b); + + group = xmlnode_new_child(item, "group"); + xmlnode_insert_data(group, g->name, -1); + + buddies = buddies->next; + } + + 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", who); + xmlnode_set_attrib(item, "name", b->alias ? b->alias : ""); + xmlnode_set_attrib(query, "xmlns:gr", "google:roster"); + xmlnode_set_attrib(query, "gr:ext", "2"); + + jabber_iq_send(iq); + + /* See if he's online */ + jabber_presence_subscription_set(js, who, "probe"); +} diff -r b8ae75fa8d67 -r f814b2df9cce libgaim/protocols/jabber/google.h --- a/libgaim/protocols/jabber/google.h Thu Dec 14 04:17:02 2006 +0000 +++ b/libgaim/protocols/jabber/google.h Thu Dec 14 04:56:54 2006 +0000 @@ -29,4 +29,12 @@ void jabber_gmail_init(JabberStream *js); void jabber_gmail_poke(JabberStream *js, xmlnode *node); +void jabber_google_roster_init(JabberStream *js); +void jabber_google_roster_outgoing(JabberStream *js, xmlnode *query, xmlnode *item); +void jabber_google_roster_incoming(JabberStream *js, xmlnode *item); +void jabber_google_roster_add_deny(GaimConnection *gc, const char *who); +void jabber_google_roster_rem_deny(GaimConnection *gc, const char *who); + + + #endif /* _GAIM_GOOGLE_H_ */ diff -r b8ae75fa8d67 -r f814b2df9cce libgaim/protocols/jabber/jabber.c --- a/libgaim/protocols/jabber/jabber.c Thu Dec 14 04:17:02 2006 +0000 +++ b/libgaim/protocols/jabber/jabber.c Thu Dec 14 04:56:54 2006 +0000 @@ -41,6 +41,7 @@ #include "buddy.h" #include "chat.h" #include "disco.h" +#include "google.h" #include "iq.h" #include "jutil.h" #include "message.h" @@ -1041,7 +1042,6 @@ break; case JABBER_STREAM_CONNECTED: - jabber_roster_request(js); gpresence = gaim_account_get_presence(js->gc->account); status = gaim_presence_get_active_status(gpresence); jabber_presence_send(js->gc->account, status); @@ -1875,9 +1875,9 @@ jabber_roster_remove_buddy, /* remove_buddy */ NULL, /* remove_buddies */ NULL, /* add_permit */ - NULL, /* add_deny */ + jabber_google_roster_add_deny, /* add_deny */ NULL, /* rem_permit */ - NULL, /* rem_deny */ + jabber_google_roster_rem_deny, /* rem_deny */ NULL, /* set_permit_deny */ jabber_chat_join, /* join_chat */ NULL, /* reject_chat */ diff -r b8ae75fa8d67 -r f814b2df9cce libgaim/protocols/jabber/jabber.h --- a/libgaim/protocols/jabber/jabber.h Thu Dec 14 04:17:02 2006 +0000 +++ b/libgaim/protocols/jabber/jabber.h Thu Dec 14 04:56:54 2006 +0000 @@ -55,6 +55,7 @@ * http://code.google.com/apis/talk/jep_extensions/extensions.html */ JABBER_CAP_GMAIL_NOTIFY = 1 << 9, + JABBER_CAP_GOOGLE_ROSTER = 1 << 10, JABBER_CAP_RETRIEVED = 1 << 31 } JabberCapabilities; diff -r b8ae75fa8d67 -r f814b2df9cce libgaim/protocols/jabber/parser.c --- a/libgaim/protocols/jabber/parser.c Thu Dec 14 04:17:02 2006 +0000 +++ b/libgaim/protocols/jabber/parser.c Thu Dec 14 04:56:54 2006 +0000 @@ -76,13 +76,21 @@ char *txt; int attrib_len = attributes[i+4] - attributes[i+3]; char *attrib = g_malloc(attrib_len + 1); + char *attrib_ns = NULL; + + if (attributes[i+2]) { + attrib_ns = g_strdup(attributes[i+2]);; + } + memcpy(attrib, attributes[i+3], attrib_len); attrib[attrib_len] = '\0'; + txt = attrib; attrib = gaim_unescape_html(txt); g_free(txt); - xmlnode_set_attrib(node, (const char*) attributes[i], attrib); + xmlnode_set_attrib_with_namespace(node, (const char*) attributes[i], attrib_ns, attrib); g_free(attrib); + g_free(attrib_ns); } js->current = node; diff -r b8ae75fa8d67 -r f814b2df9cce libgaim/protocols/jabber/roster.c --- a/libgaim/protocols/jabber/roster.c Thu Dec 14 04:17:02 2006 +0000 +++ b/libgaim/protocols/jabber/roster.c Thu Dec 14 04:56:54 2006 +0000 @@ -24,6 +24,7 @@ #include "util.h" #include "buddy.h" +#include "google.h" #include "presence.h" #include "roster.h" #include "iq.h" @@ -224,6 +225,8 @@ if (g_slist_find_custom(groups, group_name, (GCompareFunc)gaim_utf8_strcasecmp) == NULL) groups = g_slist_append(groups, group_name); } + if (js->server_caps & JABBER_CAP_GOOGLE_ROSTER) + jabber_google_roster_incoming(js, item); add_gaim_buddies_in_groups(js, jid, name, groups); } } @@ -271,7 +274,12 @@ if(!grps) 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); } diff -r b8ae75fa8d67 -r f814b2df9cce libgaim/xmlnode.c --- a/libgaim/xmlnode.c Thu Dec 14 04:17:02 2006 +0000 +++ b/libgaim/xmlnode.c Thu Dec 14 04:56:54 2006 +0000 @@ -142,6 +142,34 @@ } } + +void +xmlnode_remove_attrib_with_namespace(xmlnode *node, const char *attr, const char *xmlns) +{ + xmlnode *attr_node, *sibling = NULL; + + g_return_if_fail(node != NULL); + g_return_if_fail(attr != NULL); + + for(attr_node = node->child; attr_node; attr_node = attr_node->next) + { + if(attr_node->type == XMLNODE_TYPE_ATTRIB && + !strcmp(attr_node->name, attr) && + !strcmp(attr_node->xmlns, xmlns)) { + if(node->child == attr_node) { + node->child = attr_node->next; + } else if (node->lastchild == attr_node) { + node->lastchild = sibling; + } else { + sibling->next = attr_node->next; + } + xmlnode_free(attr_node); + return; + } + sibling = attr_node; + } +} + void xmlnode_set_attrib(xmlnode *node, const char *attr, const char *value) { @@ -160,6 +188,25 @@ xmlnode_insert_child(node, attrib_node); } +void +xmlnode_set_attrib_with_namespace(xmlnode *node, const char *attr, const char *xmlns, const char *value) +{ + xmlnode *attrib_node; + + g_return_if_fail(node != NULL); + g_return_if_fail(attr != NULL); + g_return_if_fail(value != NULL); + + xmlnode_remove_attrib_with_namespace(node, attr, xmlns); + + attrib_node = new_node(attr, XMLNODE_TYPE_ATTRIB); + + attrib_node->data = g_strdup(value); + attrib_node->xmlns = g_strdup(xmlns); + + xmlnode_insert_child(node, attrib_node); +} + const char * xmlnode_get_attrib(xmlnode *node, const char *attr) { @@ -176,6 +223,23 @@ return NULL; } +const char * +xmlnode_get_attrib_with_namespace(xmlnode *node, const char *attr, const char *xmlns) +{ + xmlnode *x; + + g_return_val_if_fail(node != NULL, NULL); + + for(x = node->child; x; x = x->next) { + if(x->type == XMLNODE_TYPE_ATTRIB && + !strcmp(attr, x->name) && !strcmp(x->xmlns, xmlns)) { + return x->data; + } + } + + return NULL; +} + void xmlnode_set_namespace(xmlnode *node, const char *xmlns) { diff -r b8ae75fa8d67 -r f814b2df9cce libgaim/xmlnode.h --- a/libgaim/xmlnode.h Thu Dec 14 04:17:02 2006 +0000 +++ b/libgaim/xmlnode.h Thu Dec 14 04:56:54 2006 +0000 @@ -143,6 +143,16 @@ void xmlnode_set_attrib(xmlnode *node, const char *attr, const char *value); /** + * Sets a namespaced attribute for a node + * + * @param node The node to set an attribute for. + * @param attr The name of the attribute to set + * @param xmlns The namespace of the attribute to ste + * @param value The value of the attribute + */ +void xmlnode_set_attrib_with_namespace(xmlnode *node, const char *attr, const char *xmlns, const char *value); + +/** * Gets an attribute from a node. * * @param node The node to get an attribute from. @@ -153,6 +163,17 @@ const char *xmlnode_get_attrib(xmlnode *node, const char *attr); /** + * Gets a namespaced attribute from a node + * + * @param node The node to get an attribute from. + * @param attr The attribute to get + * @param xmlns The namespace of the attribute to get + * + * @return The value of the attribute/ + */ +const char *xmlnode_get_attrib_with_namespace(xmlnode *node, const char *attr, const char *xmlns); + +/** * Removes an attribute from a node. * * @param node The node to remove an attribute from. @@ -161,6 +182,15 @@ void xmlnode_remove_attrib(xmlnode *node, const char *attr); /** + * Removes a namespaced attribute from a node + * + * @param node The node to remove an attribute from + * @param attr The attribute to remove + * @param xmlns The namespace of the attribute to remove + */ +void xmlnode_remove_attrib_with_namespace(xmlnode *node, const char *attr, const char *xmlns); + +/** * Sets the namespace of a node * * @param node The node to qualify