# HG changeset patch # User Jim Seymour # Date 1025352805 0 # Node ID f56b3634737533c19c7fb205a845d1d921a8cf71 # Parent afa68a8feee22bd15d35fa9aeaa8e3a004468d05 [gaim-migrate @ 3359] Added support for Jabber invisibility. committer: Tailor Script diff -r afa68a8feee2 -r f56b36347375 doc/FAQ --- a/doc/FAQ Fri Jun 28 01:47:12 2002 +0000 +++ b/doc/FAQ Sat Jun 29 12:13:25 2002 +0000 @@ -39,6 +39,11 @@ 7.2 How do I change my Jabber resource to be other than the default of "/GAIM"? 7.3 How do I register a new Jabber account? + 7.4 How do I use invisibility? + 7.5 I've a buddy that I keep removing from my buddy list, but + he keeps coming back! How can I stop this? + 7.6 What does "Remove From Roster" do? + 7.7 What does "Cancel Presence Notification" do? 8 Scripts and Plugins 8.1 Where can I find documentation on writing plugins and @@ -322,6 +327,65 @@ you're hosed. +7.4 How do I use invisibility? + + Jabber invisibility support is available in Gaim version 0.60 and later. + + There are two ways to use Jabber invisibility: on a per-buddy and on a + per-server basis. + + To use per-buddy invisibility: right-click on the buddy on the Online + buddy list and select "Temporarily Hide From." You will appear to that + buddy to be off-line. To make yourself seen by that buddy again: + right-click on the buddy and select "Un-hide From." Note that the menu + changes based on whether you're currently invisible to that buddy or + not. + + The "Temporarily" part is a dead give-away. Your invisibility to + that buddy will last only until the next time you log on or until + you set server invisibility (discussed next) on and off. + + To use per-server invisibility: click "Tools -> Away," select the Jabber + server login for the server upon which you wish to become invisible (if + necessary) and select "Invisible." To become visible again: select + anything else from that same menu (such as "Online"), or set your away + status or log off the server and back on again. + + You can set yourself invisible per-server and subsequently make yourself + visible to selected buddies only. + + Gaim currently does not retain invisibility settings between logins, + just as it doesn't currently retain "away" status. + + +7.5 I've a buddy that I keep removing from my buddy list but the entry + keeps coming back every time I log in again! How can I stop this? + + As of Gaim version 0.59 and later: Select the Edit Buddies tab, right- + click on the offending entry, and select "Remove From Roster." + + +7.6 Can I remove a buddy from my Jabber roster entirely? + + As of Gaim version 0.59 and later: yes. In the Edit Buddies tab, right- + click on a buddy and Select "Remove From Roster." + + The buddy will disappear from your buddy list and also will no longer + receive presence notifications from you. + + +7.7 What does "Cancel Presence Notification" do? + + This selection, available in Gaim version 0.60 and later, and found by + right-clicking on a buddy entry in the Edit Buddies tab, prevents that + Jabber I.D. from receiving future presence notifications when you log on + to the server. + + After you do this, that buddy will have to re-request a subscription to + your presence (and you will have to approve it) for them to again see you + on-line. + + +-------------------------------------------------------------------------- | 8 Scripts and Plugins +-------------------------------------------------------------------------- diff -r afa68a8feee2 -r f56b36347375 src/protocols/jabber/jabber.c --- a/src/protocols/jabber/jabber.c Fri Jun 28 01:47:12 2002 +0000 +++ b/src/protocols/jabber/jabber.c Sat Jun 29 12:13:25 2002 +0000 @@ -143,11 +143,19 @@ }; /* + * Used in jabber_buddy_data.invisible, below + */ +#define JABBER_NOT_INVIS 0x00 +#define JABBER_SERV_INVIS 0x01 /* Invisible set on server */ +#define JABBER_BUD_INVIS 0x02 /* Invisible set on buddy */ + +/* * It is *this* to which we point the buddy proto_data */ struct jabber_buddy_data { GSList *resources; char *error_msg; + unsigned invisible; /* We've set presence type invisible for this buddy */ }; /* @@ -973,6 +981,9 @@ } } +/* + * Return pointer to jabber_buddy_data if buddy found. Create if necessary. + */ static struct jabber_buddy_data* jabber_find_buddy(struct gaim_connection *gc, char *buddy) { struct jabber_data *jd = gc->proto_data; @@ -991,6 +1002,7 @@ struct jabber_buddy_data *jbd = g_new0(struct jabber_buddy_data, 1); jbd->error_msg = NULL; jbd->resources = NULL; + jbd->invisible = JABBER_NOT_INVIS; g_hash_table_insert(jd->buddies, g_strdup(realwho), jbd); g_free(realwho); return jbd; @@ -2396,20 +2408,123 @@ */ static void jabber_remove_buddy_roster_item(struct gaim_connection *gc, char *name) { - xmlnode x, y; + gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; char *realwho; + + if((realwho = get_realwho(gjc, name, FALSE, NULL)) != NULL) { + xmlnode x = jutil_iqnew(JPACKET__SET, NS_ROSTER); + xmlnode y = xmlnode_insert_tag(xmlnode_get_tag(x, "query"), "item"); + xmlnode_put_attrib(y, "jid", realwho); + xmlnode_put_attrib(y, "subscription", "remove"); + gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); + g_free(realwho); + xmlnode_free(x); + } +} + +/* + * Unsubscribe a buddy from our presence + */ +static void jabber_unsubscribe_buddy_from_us(struct gaim_connection *gc, char *name) +{ + gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; + char *realwho; + + if((realwho = get_realwho(gjc, name, FALSE, NULL)) != NULL) { + xmlnode g = xmlnode_new_tag("presence"); + xmlnode_put_attrib(g, "to", realwho); + xmlnode_put_attrib(g, "type", "unsubscribed"); + gjab_send(gjc, g); + xmlnode_free(g); + } +} + +/* + * Common code for setting ourselves invisible/visible to buddy + */ +static void jabber_invisible_to_buddy_common(struct gaim_connection *gc, char *name, gboolean invisible) +{ gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; - - if(!name || (realwho = get_realwho(gjc, name, FALSE, NULL)) == NULL) - return; - - x = jutil_iqnew(JPACKET__SET, NS_ROSTER); - y = xmlnode_insert_tag(xmlnode_get_tag(x, "query"), "item"); - xmlnode_put_attrib(y, "jid", realwho); - xmlnode_put_attrib(y, "subscription", "remove"); - gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); - g_free(realwho); - xmlnode_free(x); + char *realwho; + + if((realwho = get_realwho(gjc, name, FALSE, NULL)) != NULL) { + struct jabber_buddy_data *jbd = jabber_find_buddy(gc, realwho); + xmlnode g = xmlnode_new_tag("presence"); + + xmlnode_put_attrib(g, "to", realwho); + + if(invisible) + xmlnode_put_attrib(g, "type", "invisible"); + + gjab_send(gjc, g); + + g_free(realwho); + xmlnode_free(g); + + if(jbd) { + if(invisible) { + jbd->invisible |= JABBER_BUD_INVIS; + } else { + jbd->invisible &= ~JABBER_BUD_INVIS; + } + } + } +} + +/* + * Make ourselves temporarily invisible to a buddy + */ +static void jabber_invisible_to_buddy(struct gaim_connection *gc, char *name) +{ + jabber_invisible_to_buddy_common(gc, name, TRUE); +} + +/* + * Make ourselves visible to a buddy + */ +static void jabber_visible_to_buddy(struct gaim_connection *gc, char *name) +{ + jabber_invisible_to_buddy_common(gc, name, FALSE); +} + +/* + * Function used by the g_hash_table_foreach() in invisible_to_all_buddies() to + * actually set the status. + * + * key is unused + * value is the pointer to the jabber_buddy_data struct + * data is gboolean: TRUE (invisible) or FALSE (not invisible) + */ +static void set_invisible_to_buddy_status(gpointer key, gpointer val, gpointer data) { + struct jabber_buddy_data *jbd = val; + gboolean invisible = (gboolean) data; + + if(jbd) { + if(invisible) { + jbd->invisible = JABBER_SERV_INVIS | JABBER_BUD_INVIS; + } else { + /* + * If we've asserted server-level invisibility, cancelling + * it removes explicit buddy invisibility settings too. + */ + if(jbd->invisible & JABBER_SERV_INVIS) + jbd->invisible = JABBER_NOT_INVIS; + } + } +} + +/* + * Show we've set ourselves invisible/visible to all buddies on the server + * + * Used when we set server-wide invisibility so that individual buddy menu + * entries show the proper option. + */ +static void invisible_to_all_buddies(struct gaim_connection *gc, gboolean invisible) +{ + struct jabber_data *jd = gc->proto_data; + + if(jd->buddies != NULL) + g_hash_table_foreach(jd->buddies, set_invisible_to_buddy_status, (gpointer) invisible); } static char **jabber_list_icon(int uc) @@ -2867,6 +2982,12 @@ pbm->gc = gc; m = g_list_append(m, pbm); } else { + gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; + char *realwho = get_realwho(gjc, who, FALSE, NULL); + struct jabber_buddy_data *jbd = jabber_find_buddy(gc, realwho); + + g_free(realwho); + pbm = g_new0(struct proto_buddy_menu, 1); pbm->label = _("Get Info"); pbm->callback = jabber_get_info; @@ -2877,6 +2998,17 @@ pbm->callback = jabber_get_away_msg; pbm->gc = gc; m = g_list_append(m, pbm); + + pbm = g_new0(struct proto_buddy_menu, 1); + if(jbd && (jbd->invisible & JABBER_BUD_INVIS)) { + pbm->label = _("Un-hide From"); + pbm->callback = jabber_visible_to_buddy; + } else { + pbm->label = _("Temporarily Hide From"); + pbm->callback = jabber_invisible_to_buddy; + } + pbm->gc = gc; + m = g_list_append(m, pbm); } return m; @@ -2894,6 +3026,11 @@ pbm->callback = jabber_remove_buddy_roster_item; pbm->gc = gc; m = g_list_append(m, pbm); + pbm = g_new0(struct proto_buddy_menu, 1); + pbm->label = _("Cancel Presence Notification"); + pbm->callback = jabber_unsubscribe_buddy_from_us; + pbm->gc = gc; + m = g_list_append(m, pbm); return m; } @@ -2906,6 +3043,7 @@ m = g_list_append(m, "Away"); m = g_list_append(m, "Extended Away"); m = g_list_append(m, "Do Not Disturb"); + m = g_list_append(m, "Invisible"); return m; } @@ -2918,6 +3056,7 @@ GSList *jcs; struct jabber_chat *jc; char *chatname; + gboolean invisible = FALSE; gc->away = NULL; /* never send an auto-response */ @@ -2955,6 +3094,10 @@ y = xmlnode_insert_tag(x, "show"); xmlnode_insert_cdata(y, "dnd", -1); gc->away = ""; + } else if (!strcmp(state, "Invisible")) { + xmlnode_put_attrib(x, "type", "invisible"); + gc->away = ""; + invisible = TRUE; } } @@ -2977,6 +3120,8 @@ } xmlnode_free(x); + + invisible_to_all_buddies(gc, invisible); } static void jabber_set_idle(struct gaim_connection *gc, int idle) {