changeset 3340:f56b36347375

[gaim-migrate @ 3359] Added support for Jabber invisibility. committer: Tailor Script <tailor@pidgin.im>
author Jim Seymour <jseymour>
date Sat, 29 Jun 2002 12:13:25 +0000
parents afa68a8feee2
children 9bfedef5dbf3
files doc/FAQ src/protocols/jabber/jabber.c
diffstat 2 files changed, 221 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- 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
 +--------------------------------------------------------------------------
--- 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) {