changeset 3105:da324fe688b3

[gaim-migrate @ 3119] Jabber improvements (Jim Seymour) and good handling of sigchld (Jim Seymour and Luke Schierer) committer: Tailor Script <tailor@pidgin.im>
author Sean Egan <seanegan@gmail.com>
date Thu, 28 Mar 2002 20:07:45 +0000
parents 1b8b05f76ae9
children d3cb7d47fcb4
files ChangeLog src/aim.c src/gtkspell.c src/gtkspell.h src/protocols/jabber/jabber.c src/util.c
diffstat 6 files changed, 176 insertions(+), 90 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Thu Mar 28 19:58:58 2002 +0000
+++ b/ChangeLog	Thu Mar 28 20:07:45 2002 +0000
@@ -1,8 +1,7 @@
 Gaim: The Pimpin' Penguin IM Clone thats good for the soul! 
 
 version 0.55:
-	* Better Jabber list management when using multiple
-	  resources (Thanks Jim Seymour)
+	* Jabber improvements (Thanks Jim Seymour)
 	* Various sound cleanups (Thanks Robert McQueen)
 	* Login process shown in single window (Thanks Michael 
 	  Golden)
--- a/src/aim.c	Thu Mar 28 19:58:58 2002 +0000
+++ b/src/aim.c	Thu Mar 28 20:07:45 2002 +0000
@@ -84,6 +84,28 @@
 
 void BuddyTickerCreateWindow(void);
 
+#if HAVE_SIGNAL_H
+/*
+ * Lists of signals we wish to catch and those we wish to ignore.
+ * Each list terminated with -1
+ */
+static int catch_sig_list[] = {
+	SIGSEGV,
+	SIGHUP,
+	SIGINT,
+	SIGTERM,
+	SIGQUIT,
+	SIGCHLD,
+	-1
+};
+
+static int ignore_sig_list[] = {
+	SIGPIPE,
+	-1
+};
+#endif
+
+
 void cancel_logon(void)
 {
 #ifdef USE_APPLET
@@ -408,6 +430,9 @@
 		break;
 	case SIGCHLD:
 		clean_pid();
+#if HAVE_SIGNAL_H
+		signal(SIGCHLD, sighandler);	/* restore signal catching on this one! */
+#endif
 		break;
 	default:
 		debug_printf("caught signal %d\n", sig);
@@ -527,6 +552,10 @@
 {
 	int opt_acct = 0, opt_help = 0, opt_version = 0, opt_login = 0, do_login_ret = -1;
 	char *opt_user_arg = NULL, *opt_login_arg = NULL;
+#if HAVE_SIGNAL_H
+	int sig_indx;	/* for setting up signal catching */
+	void (*prev_sig_disp)();
+#endif
 #ifndef USE_APPLET
 	int opt, opt_user = 0;
 	int i;
@@ -573,13 +602,23 @@
 
 #if HAVE_SIGNAL_H
 	/* Let's not violate any PLA's!!!! */
-	signal(SIGSEGV, sighandler);
-	signal(SIGHUP, sighandler);
-	signal(SIGINT, sighandler);
-	signal(SIGTERM, sighandler);
-	signal(SIGQUIT, sighandler);
-	signal(SIGPIPE, SIG_IGN);
-	signal(SIGCHLD, sighandler);
+	/* jseymour: whatever the fsck that means */
+	for(sig_indx = 0; catch_sig_list[sig_indx] != -1; ++sig_indx) {
+		if((prev_sig_disp = signal(catch_sig_list[sig_indx], sighandler)) == SIG_ERR) {
+			char errmsg[BUFSIZ];
+			sprintf(errmsg, "Warning: couldn't set signal %d for catching",
+				catch_sig_list[sig_indx]);
+			perror(errmsg);
+		}
+	}
+	for(sig_indx = 0; ignore_sig_list[sig_indx] != -1; ++sig_indx) {
+		if((prev_sig_disp = signal(ignore_sig_list[sig_indx], SIG_IGN)) == SIG_ERR) {
+			char errmsg[BUFSIZ];
+			sprintf(errmsg, "Warning: couldn't set signal %d to ignore",
+				ignore_sig_list[sig_indx]);
+			perror(errmsg);
+		}
+	}
 #endif
 
 
--- a/src/gtkspell.c	Thu Mar 28 19:58:58 2002 +0000
+++ b/src/gtkspell.c	Thu Mar 28 20:07:45 2002 +0000
@@ -55,7 +55,18 @@
 static void set_up_signal();
 
 int gtkspell_running() {
-	return (spell_pid > 0);
+	return (spell_pid > 0? spell_pid : 0);
+}
+
+/*
+ * Set to "gtkspell not running" status
+ *
+ * May seem a bit silly, but it allows us to keep the file-global
+ * variable from going program-global.  And if we need to do
+ * something else additional later, well...
+ */
+void gtkspell_notrunning() {
+    spell_pid = 0;
 }
 
 /*
@@ -170,11 +181,6 @@
 		gtkspell_stop();
 	}
 
-	if (!signal_set_up) {
-		set_up_signal();
-		signal_set_up = 1;
-	}
-
 	pipe(fd_write);
 	pipe(fd_read);
 	pipe(fd_error);
@@ -689,21 +695,3 @@
 	gtkspell_uncheck_all(gtktext);
 }
 
-static void sigchld(int param) {
-	if (gtkspell_running() &&
-		(waitpid(spell_pid, NULL, WNOHANG) == spell_pid)) {
-		spell_pid = 0;
-	} else {
-		/* a default SIGCHLD handler.
-		 * what else to do here? */
-		waitpid(-1, NULL, WNOHANG);
-	}
-}
-
-static void set_up_signal() {
-	struct sigaction sigact;
-	memset(&sigact, 0, sizeof(struct sigaction));
-
-	sigact.sa_handler = sigchld;
-	sigaction(SIGCHLD, &sigact, NULL);
-}
--- a/src/gtkspell.h	Thu Mar 28 19:58:58 2002 +0000
+++ b/src/gtkspell.h	Thu Mar 28 20:07:45 2002 +0000
@@ -55,7 +55,7 @@
 /* Is gtkspell running?
  *
  * Return:
- * 	nonzero if it running
+ * 	nonzero, positive pid if it's running
  * 	zero if is not running
  *
  * Example:
@@ -63,6 +63,17 @@
  *  	printf("gtkspell is running.\n");
  */
 
+extern void gtkspell_notrunning(void);
+/*
+ * Set gtkspell status to "not running"
+ * Intended to be used only by signal-catcher
+ * when the SIGCHLD signal it catches matches
+ * the gtkspell process i.d.
+ *
+ * Example:
+ *	gtkspell_notrunning();
+ */
+
 extern void gtkspell_attach(GtkText *text);
 /* Attach GtkSpell to a GtkText Widget.
  * This enables checking as you type and the popup menu.
--- a/src/protocols/jabber/jabber.c	Thu Mar 28 19:58:58 2002 +0000
+++ b/src/protocols/jabber/jabber.c	Thu Mar 28 20:07:45 2002 +0000
@@ -401,14 +401,14 @@
 	if (!gjc || gjc->state == JCONN_STATE_OFF)
 		return;
 
-	if ((len = read(gjc->fd, buf, sizeof(buf) - 1))) {
+	if ((len = read(gjc->fd, buf, sizeof(buf))) > 0) {
 		struct jabber_data *jd = GJ_GC(gjc)->proto_data;
 		buf[len] = '\0';
 		debug_printf("input (len %d): %s\n", len, buf);
 		XML_Parse(gjc->parser, buf, len, 0);
 		if (jd->die)
 			signoff(GJ_GC(gjc));
-	} else if (len <= 0) {
+	} else if (len < 0 || errno != EAGAIN) {
 		STATE_EVT(JCONN_STATE_OFF)
 	}
 }
@@ -686,7 +686,7 @@
 /*
  * keep track of away msg same as yahoo plugin
  */
-static void jabber_track_away(gjconn gjc, jpacket p, char *name)
+static void jabber_track_away(gjconn gjc, jpacket p, char *name, char *type)
 {
 	struct jabber_data *jd = GJ_GC(gjc)->proto_data;
 	gpointer val = g_hash_table_lookup(jd->hash, name);
@@ -695,15 +695,19 @@
 	char *status = NULL;
 	char *msg = NULL;
 
-	if((show = xmlnode_get_tag_data(p->x, "show")) != NULL) {
-		if (!strcasecmp(show, "away")) {
-			vshow = _("Away");
-		} else if (!strcasecmp(show, "chat")) {
-			vshow = _("Online");
-		} else if (!strcasecmp(show, "xa")) {
-			vshow = _("Extended Away");
-		} else if (!strcasecmp(show, "dnd")) {
-			vshow = _("Do Not Disturb");
+	if (type && (strcasecmp(type, "unavailable") == 0)) {
+		vshow = _("Unavailable");
+	} else {
+		if((show = xmlnode_get_tag_data(p->x, "show")) != NULL) {
+			if (!strcasecmp(show, "away")) {
+				vshow = _("Away");
+			} else if (!strcasecmp(show, "chat")) {
+				vshow = _("Online");
+			} else if (!strcasecmp(show, "xa")) {
+				vshow = _("Extended Away");
+			} else if (!strcasecmp(show, "dnd")) {
+				vshow = _("Do Not Disturb");
+			}
 		}
 	}
 
@@ -715,6 +719,8 @@
 			(vshow == NULL? "" : vshow),
 			(vshow == NULL || status == NULL? "" : ": "),
 			(status == NULL? "" : status));
+	} else {
+		msg = g_strdup(_("Online"));
 	}
 
 	if (val) {
@@ -845,11 +851,12 @@
 				if (!find_chat_buddy(jc->b, p->from->resource)) {
 					add_chat_buddy(jc->b, p->from->resource);
 				} else if ((y = xmlnode_get_tag(p->x, "status"))) {
-					char buf[8192];
-
-					g_snprintf(buf, sizeof(buf), "%s@%s/%s",
+					char *buf;
+
+					buf = g_strdup_printf("%s@%s/%s",
 						p->from->user, p->from->server, p->from->resource);
-					jabber_track_away(gjc, p, buf);
+					jabber_track_away(gjc, p, buf, NULL);
+					g_free(buf);
 
 				}
 			} else if (jc->b && msg) {
@@ -949,6 +956,9 @@
 				resources = resources->next;
 			}
 
+		/* keep track of away msg same as yahoo plugin */
+		jabber_track_away(gjc, p, normalize(b->name), type);
+
 		if (type && (strcasecmp(type, "unavailable") == 0)) {
 			if (resources) {
 				g_free(resources->data);
@@ -958,9 +968,6 @@
 				serv_got_update(GJ_GC(gjc), buddy, 0, 0, 0, 0, 0, 0);
 			}
 		} else {
-			/* keep track of away msg same as yahoo plugin */
-			jabber_track_away(gjc, p, normalize(b->name));
-
 			if (!resources) {
 				b->proto_data = g_slist_append(b->proto_data, g_strdup(res));
 			}
@@ -970,6 +977,12 @@
 		}
 	} else {
 		if (who->resource) {
+			char *buf;
+
+			buf = g_strdup_printf("%s@%s/%s", who->user, who->server, who->resource);
+			jabber_track_away(gjc, p, buf, type);
+			g_free(buf);
+
 			if (type && !strcasecmp(type, "unavailable")) {
 				struct jabber_data *jd;
 				if (!jc && !(jc = find_existing_chat(GJ_GC(gjc), who))) {
@@ -998,11 +1011,6 @@
 				}
 				if (!find_chat_buddy(jc->b, who->resource)) {
 					add_chat_buddy(jc->b, who->resource);
-				} else {
-					char buf[8192];
-					g_snprintf(buf, sizeof(buf), "%s@%s/%s",
-						who->user, who->server, who->resource);
-					jabber_track_away(gjc, p, buf);
 				}
 			}
 		}
@@ -1544,6 +1552,63 @@
 	return 1;
 }
 
+/*
+ * Add/update buddy's roster entry on server
+ */
+static void jabber_roster_update(struct gaim_connection *gc, char *name)
+{
+	xmlnode x, y;
+	char *realwho;
+	gjconn gjc;
+	struct buddy *buddy = NULL;
+	struct group *buddy_group = NULL;
+	
+	if(gc && gc->proto_data && ((struct jabber_data *)gc->proto_data)->gjc && name) {
+		gjc = ((struct jabber_data *)gc->proto_data)->gjc;
+
+		if (!strchr(name, '@'))
+			realwho = g_strdup_printf("%s@%s", name, gjc->user->server);
+		else {
+			jid who = jid_new(gjc->p, name);
+			if (who->user == NULL) {
+				/* FIXME: transport */
+				return;
+			}
+			realwho = g_strdup_printf("%s@%s", who->user, who->server);
+		}
+
+
+		x = jutil_iqnew(JPACKET__SET, NS_ROSTER);
+		y = xmlnode_insert_tag(xmlnode_get_tag(x, "query"), "item");
+		xmlnode_put_attrib(y, "jid", realwho);
+
+
+		/* If we can find the buddy, there's an alias for him, it's not 0-length
+		 * and it doesn't match his JID, add the "name" attribute.
+		 */
+		if((buddy = find_buddy(gc, realwho)) != NULL &&
+			buddy->show != NULL && strcmp(realwho, buddy->show)) {
+
+			xmlnode_put_attrib(y, "name", buddy->show);
+		}
+
+		/*
+		 * Find out what group the buddy's in and send that along
+		 * with the roster item.
+		 */
+		if((buddy_group = find_group_by_buddy(gc, realwho)) != NULL) {
+			xmlnode z;
+			z = xmlnode_insert_tag(y, "group");
+			xmlnode_insert_cdata(z, buddy_group->name, -1);
+		}
+
+		gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x);
+
+		xmlnode_free(x);
+		g_free(realwho);
+	}
+}
+
 static void jabber_add_buddy(struct gaim_connection *gc, char *name)
 {
 	xmlnode x, y;
@@ -1572,39 +1637,14 @@
 		realwho = g_strdup_printf("%s@%s", who->user, who->server);
 	}
 
-
-	x = jutil_iqnew(JPACKET__SET, NS_ROSTER);
-	y = xmlnode_insert_tag(xmlnode_get_tag(x, "query"), "item");
-	xmlnode_put_attrib(y, "jid", realwho);
-
-	/* If we can find the buddy, there's an alias for him and
-	 * it's not 0-length, add the "name" attribute.
-	 */
-	if((buddy = find_buddy(gc, realwho)) != NULL &&
-		buddy->show != NULL && (buddy->show)[0] != '\0') {
-
-		xmlnode_put_attrib(y, "name", buddy->show);
-	}
-
-	/*
-	 * Find out what group the buddy's in and send that along
-	 * with the roster item.
-	 */
-	if((buddy_group = find_group_by_buddy(gc, realwho)) != NULL) {
-		xmlnode z;
-		z = xmlnode_insert_tag(y, "group");
-		xmlnode_insert_cdata(z, buddy_group->name, -1);
-	}
-
-	gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x);
-	xmlnode_free(x);
-
 	x = xmlnode_new_tag("presence");
 	xmlnode_put_attrib(x, "to", realwho);
 	xmlnode_put_attrib(x, "type", "subscribe");
 	gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x);
 	xmlnode_free(x);
 
+	jabber_roster_update(gc, realwho);
+
 	g_free(realwho);
 }
 
@@ -1976,7 +2016,7 @@
 	*ap++ = g_strdup_printf("<B>Jabber ID:</B> %s<BR>\n", realwho);
 
 	if((status = g_hash_table_lookup(jd->hash, realwho)) == NULL) {
-		status = _("Online");
+		status = _("Unknown");
 	}
 	*ap++ = g_strdup_printf("<B>Status:</B> %s<BR>\n", status);
 
@@ -2315,7 +2355,7 @@
 	}
 
 	if((status = g_hash_table_lookup(jd->hash, buddy)) == NULL) {
-		status = _("Online");
+		status = _("Unknown");
 	}
 	*ap++ = g_strdup_printf("<B>Status:</B> %s<BR>\n", status);
 
--- a/src/util.c	Thu Mar 28 19:58:58 2002 +0000
+++ b/src/util.c	Thu Mar 28 20:07:45 2002 +0000
@@ -35,6 +35,7 @@
 #include <math.h>
 #include "gaim.h"
 #include "prpl.h"
+#include "gtkspell.h"
 
 char *full_date()
 {
@@ -616,10 +617,18 @@
 void clean_pid(void)
 {
 	int status;
-	pid_t pid;
+	pid_t pid, spell_pid;
 
-	printf ("clean_pid\n");
-	pid = waitpid(-1, &status, WNOHANG);
+	while((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+		if((spell_pid = gtkspell_running()) != 0 && pid == spell_pid) {
+			gtkspell_notrunning();
+		}
+	}
+	if(pid < 0 && errno != ECHILD) {
+		char errmsg[BUFSIZ];
+		sprintf(errmsg, "Warning: waitpid() returned %d", pid);
+		perror(errmsg);
+	}
 }
 
 struct aim_user *find_user(const char *name, int protocol)