diff src/protocols/jabber/jabber.c @ 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 e77fcff466a1
children 000546860da7
line wrap: on
line diff
--- 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) {