changeset 9328:33e6b2b92cfe

[gaim-migrate @ 10136] "Initial Comment: This fixes a few more bugs, patches up some memory leaks, and adds things to the todo list: Uncomment and fix handle_unknown to print debug info for unhandled zephyrs. Fix triple_subset for some odd cases class "*" and recipient "*" only match themselves. Notifies when a message to chat fails. Zephyrs to <message,personal,recipient> (where recipient!=username), now get treated as chat messages, instead of IM's. Incoming IM's from user@thisrealm appear from user instead of user@thisrealm. Sets the default sending instance for chats to "PERSONAL" if not specified or set to * (wildcard) for compatibility with zwrite. Add miscellaneous code comments. Joining chats from a buddy list does the right thing when the instance or recipient aren't specified. When joining chats from a dialog box (or buddy list), new messages sent from that chat window caused a second nonfunctional window for the same chat to popup. This is fixed here." --Arun A Tharuvai committer: Tailor Script <tailor@pidgin.im>
author Luke Schierer <lschiere@pidgin.im>
date Sun, 20 Jun 2004 14:46:24 +0000
parents ef8e4740254d
children d42f3e4fd7ad
files ChangeLog src/protocols/zephyr/.todo src/protocols/zephyr/zephyr.c
diffstat 3 files changed, 163 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sun Jun 20 08:02:39 2004 +0000
+++ b/ChangeLog	Sun Jun 20 14:46:24 2004 +0000
@@ -43,6 +43,7 @@
 	* Protocol-specific settings for accounts were being removed whenever the
 	  account was modified. Now they're only removed when the protocol type
 	  changes, as it should be.
+	* Zepher bug fixes and memory leak plugs (Arun A Tharuvai)
 
 version 0.78 (05/30/2004):
 	New Features:
--- a/src/protocols/zephyr/.todo	Sun Jun 20 08:02:39 2004 +0000
+++ b/src/protocols/zephyr/.todo	Sun Jun 20 14:46:24 2004 +0000
@@ -1,5 +1,51 @@
+<!-- Automagically generated by the ToDo program on Sat Jun 19 20:54:24 2004 -->
 <todo version="0.1.17">
-        <note priority="veryhigh" time="1036046748">
-            God help us.
-        </note>
+    <note priority="veryhigh" time="1036046748">
+        God help us.
+    </note>
+    <note priority="high" time="1087689758">
+        write code to output a WGFILE with a sane name
+    </note>
+    <note priority="high" time="1087689986">
+        get server supplied subscriptions to properly get added as chats
+    </note>
+    <note priority="high" time="1087691868">
+        zephyr freezes up sometimes (possibly when zlocating, and possibly when krb tickets have expired)? Debug and fix
+    </note>
+    <note priority="medium" time="1087689774">
+        get non-kerberized zephyr working for windows
+    </note>
+    <note priority="medium" time="1087689784">
+        get kerberized zephyr working for windows
+    </note>
+    <note priority="medium" time="1087689886">
+        get opener and closer tags for @ formatting to only match the correct closing tag, not any closing tag (e.g. [ matches ], and not )
+    </note>
+    <note priority="medium" time="1087689920">
+        use tzc as a backend
+    </note>
+    <note priority="medium" time="1087690034">
+        properly detect when subscriptions get lost
+    </note>
+    <note priority="medium" time="1087690121">
+        support zcrypt (maybe a plugin would be better?)
+    </note>
+    <note priority="medium" time="1087690133">
+        support /commands
+    </note>
+    <note priority="medium" time="1087692864">
+        look for more memory leaks
+    </note>
+    <note priority="low" time="1087690041">
+        support multiple zephyr accounts (depends on "use tzc as a backend")
+    </note>
+    <note priority="low" time="1087691895">
+        import chats into blist.xml and autojoin on startup?
+    </note>
+    <note priority="verylow" time="1087690240">
+        support gpg
+    </note>
+    <note priority="verylow" time="1087690286">
+        support kzwrite
+    </note>
 </todo>
--- a/src/protocols/zephyr/zephyr.c	Sun Jun 20 08:02:39 2004 +0000
+++ b/src/protocols/zephyr/zephyr.c	Sun Jun 20 14:46:24 2004 +0000
@@ -76,8 +76,33 @@
 					return;\
 				}
 
-static const char *local_zephyr_normalize(const char *);
+char *local_zephyr_normalize(const char *);
 static const char *zephyr_normalize(const GaimAccount *, const char *);
+static const char *gaim_zephyr_get_realm();
+
+char *zephyr_strip_foreign_realm(const char* user){
+/*
+	Takes in a username of the form username or username@realm 
+	and returns:
+	username, if there is no realm, or the realm is the local realm
+	or:
+	username@realm if there is a realm and it is foreign
+*/
+	char *tmp = g_strdup(user);
+	char *at = strchr(tmp,'@');
+	if (at && !g_ascii_strcasecmp(at+1,gaim_zephyr_get_realm())) {
+		/* We're passed in a username of the form user@users-realm */
+		char* tmp2;
+		*at = '\0';
+		tmp2 = g_strdup(tmp);
+		g_free(tmp);
+		return tmp2;
+	}
+	else {
+		/* We're passed in a username of the form user or user@foreign-realm */
+		return tmp;
+	}
+}
 
 /* this is so bad, and if Zephyr weren't so fucked up to begin with I
  * wouldn't do this. but it is so i will. */
@@ -88,21 +113,21 @@
 static GSList *subscrips = NULL;
 static int last_id = 0;
 
-/* just for debugging
+/* just for debugging */
 static void handle_unknown(ZNotice_t notice)
 {
-	gaim_debug(GAIM_DEBUG_MISC, "z_packet: %s\n", notice.z_packet);
-	gaim_debug(GAIM_DEBUG_MISC, "z_version: %s\n", notice.z_version);
-	gaim_debug(GAIM_DEBUG_MISC, "z_kind: %d\n", notice.z_kind);
-	gaim_debug(GAIM_DEBUG_MISC, "z_class: %s\n", notice.z_class);
-	gaim_debug(GAIM_DEBUG_MISC, "z_class_inst: %s\n", notice.z_class_inst);
-	gaim_debug(GAIM_DEBUG_MISC, "z_opcode: %s\n", notice.z_opcode);
-	gaim_debug(GAIM_DEBUG_MISC, "z_sender: %s\n", notice.z_sender);
-	gaim_debug(GAIM_DEBUG_MISC, "z_recipient: %s\n", notice.z_recipient);
-	gaim_debug(GAIM_DEBUG_MISC, "z_message: %s\n", notice.z_message);
-	gaim_debug(GAIM_DEBUG_MISC, "z_message_len: %d\n", notice.z_message_len);
+	gaim_debug(GAIM_DEBUG_MISC, "zephyr","z_packet: %s\n", notice.z_packet);
+	gaim_debug(GAIM_DEBUG_MISC, "zephyr","z_version: %s\n", notice.z_version);
+	gaim_debug(GAIM_DEBUG_MISC, "zephyr","z_kind: %d\n", (int)(notice.z_kind));
+	gaim_debug(GAIM_DEBUG_MISC, "zephyr","z_class: %s\n", notice.z_class);
+	gaim_debug(GAIM_DEBUG_MISC, "zephyr","z_class_inst: %s\n", notice.z_class_inst);
+	gaim_debug(GAIM_DEBUG_MISC, "zephyr","z_opcode: %s\n", notice.z_opcode);
+	gaim_debug(GAIM_DEBUG_MISC, "zephyr","z_sender: %s\n", notice.z_sender);
+	gaim_debug(GAIM_DEBUG_MISC, "zephyr","z_recipient: %s\n", notice.z_recipient);
+	gaim_debug(GAIM_DEBUG_MISC, "zephyr","z_message: %s\n", notice.z_message);
+	gaim_debug(GAIM_DEBUG_MISC, "zephyr","z_message_len: %d\n", notice.z_message_len);
 }
-*/
+
 
 static zephyr_triple *new_triple(const char *c, const char *i, const char *r)
 {
@@ -141,17 +166,25 @@
 	return ZGetRealm();
 }
 
-/* returns true if zt1 is a subset of zt2, i.e. zt2 has the same thing or
- * wildcards in each field of zt1. */
+/* returns true if zt1 is a subset of zt2.  This function is used to
+   determine whether a zephyr sent to zt1 should be placed in the chat
+   with triple zt2
+ 
+   zt1 is a subset of zt2 
+   iff. the classnames are identical ignoring case 
+   AND. the instance names are identical (ignoring case), or zt2->instance is *.
+   AND. the recipient names are identical
+*/
+
 static gboolean triple_subset(zephyr_triple * zt1, zephyr_triple * zt2)
 {
-	if (g_ascii_strcasecmp(zt2->class, zt1->class) && g_ascii_strcasecmp(zt2->class, "*")) {
+	if (g_ascii_strcasecmp(zt2->class, zt1->class)) {
 		return FALSE;
 	}
 	if (g_ascii_strcasecmp(zt2->instance, zt1->instance) && g_ascii_strcasecmp(zt2->instance, "*")) {
 		return FALSE;
 	}
-	if (g_ascii_strcasecmp(zt2->recipient, zt1->recipient) && g_ascii_strcasecmp(zt2->recipient, "*")) {
+	if (g_ascii_strcasecmp(zt2->recipient, zt1->recipient)) {
 		return FALSE;
 	}
 	return TRUE;
@@ -185,6 +218,10 @@
 	return NULL;
 }
 
+/* 
+   Convert incoming zephyr to utf-8 if necessary using user specified encoding
+*/
+
 static gchar *zephyr_recv_convert(char *string, int len)
 {
 	gchar *utf8;
@@ -511,7 +548,8 @@
 	GList *curr;
 
 	for (curr = pending_zloc_names; curr != NULL; curr = curr->next) {
-		if (!g_ascii_strcasecmp(local_zephyr_normalize(who), (char *)curr->data)) {
+		char* normalized_who = local_zephyr_normalize(who);
+		if (!g_ascii_strcasecmp(normalized_who, (char *)curr->data)) {
 			g_free((char *)curr->data);
 			pending_zloc_names = g_list_remove(pending_zloc_names, curr->data);
 			return TRUE;
@@ -520,10 +558,14 @@
 	return FALSE;
 }
 
+/* Called when the server notifies us a message couldn't get sent */
+
 static void message_failed(ZNotice_t notice, struct sockaddr_in from)
 {
 	if (g_ascii_strcasecmp(notice.z_class, "message")) {
-		/* message to chat failed ignore for now */
+		gchar* chat_failed = g_strdup_printf(_("Unable send to chat %s,%s,%s"),notice.z_class,notice.z_class_inst,notice.z_recipient);
+		gaim_notify_error(zgc,"",chat_failed,NULL);
+		g_free(chat_failed);
 	} else {
 		gaim_notify_error(zgc, notice.z_recipient, _("User is offline"), NULL);
 	}
@@ -575,7 +617,6 @@
 	} else {
 		char *buf, *buf2, *buf3;
 		char *send_inst;
-		char *realmptr;
 		GaimConversation *gconv1;
 		GaimConvChat *gcc;
 		char *ptr = notice.z_message + strlen(notice.z_message) + 1;
@@ -596,10 +637,14 @@
 			g_free(buf);
 			g_free(tmpescape);
 
-			if (!g_ascii_strcasecmp(notice.z_class, "MESSAGE") && !g_ascii_strcasecmp(notice.z_class_inst, "PERSONAL")) {
+			if (!g_ascii_strcasecmp(notice.z_class, "MESSAGE") && !g_ascii_strcasecmp(notice.z_class_inst, "PERSONAL") 
+                            && !g_ascii_strcasecmp(notice.z_recipient,gaim_zephyr_get_sender())) {
+				gchar* stripped_sender;
 				if (!g_ascii_strcasecmp(notice.z_message, "Automated reply:"))
 					flags |= GAIM_CONV_IM_AUTO_RESP;
-				serv_got_im(zgc, notice.z_sender, buf3, flags, time(NULL));
+				stripped_sender = zephyr_strip_foreign_realm(notice.z_sender);
+				serv_got_im(zgc, stripped_sender, buf3, flags, time(NULL));
+				g_free(stripped_sender);
 			} else {
 				zephyr_triple *zt1, *zt2;
 
@@ -619,21 +664,11 @@
 						gaim_conv_chat_set_topic(gcc, sendertmp, notice.z_class_inst);
 
 					}
+					g_free(sendertmp); /* fix memory leak? */
 					/* If the person is in the default Realm, then strip the 
 					   Realm from the sender field */
-					sendertmp = g_strdup_printf("%s", notice.z_sender);
-					if ((realmptr = strchr(sendertmp, '@')) != NULL) {
-						realmptr++;
-						if (!g_ascii_strcasecmp(realmptr, gaim_zephyr_get_realm())) {
-							realmptr--;
-							sprintf(realmptr, "%c", '\0');
-							send_inst = g_strdup_printf("%s %s", sendertmp, notice.z_class_inst);
-						} else {
-							send_inst = g_strdup_printf("%s %s", notice.z_sender, notice.z_class_inst);
-						}
-					} else {
-						send_inst = g_strdup_printf("%s %s", sendertmp, notice.z_class_inst);
-					}
+					sendertmp = zephyr_strip_foreign_realm(notice.z_sender);
+					send_inst = g_strdup_printf("%s %s",sendertmp,notice.z_class_inst);					
 					serv_got_chat_in(zgc, zt2->id, send_inst, FALSE, buf3, time(NULL));
 
 					gconv1 = gaim_find_conversation_with_account(zt2->name, zgc->account);
@@ -646,9 +681,12 @@
 					if (!found) {
 						/* force interpretation in network byte order */
 						unsigned char *addrs = (unsigned char *)&(notice.z_sender_addr.s_addr);
+						gchar* ipaddr = g_strdup_printf("%hhd.%hhd.%hhd.%hhd", (unsigned char)addrs[0], 
+										(unsigned char)addrs[1], (unsigned char)addrs[2], 
+										(unsigned char) addrs[3]);
 
-						gaim_conv_chat_add_user(gcc, sendertmp, g_strdup_printf("%hhd.%hhd.%hhd.%hhd", (unsigned char)addrs[0], (unsigned char)addrs[1], (unsigned char)addrs[2], (unsigned char)
-																				addrs[3]));
+						gaim_conv_chat_add_user(gcc, sendertmp, ipaddr);
+						g_free(ipaddr); /* fix memory leak? */
 
 					}
 					g_free(sendertmp);
@@ -680,9 +718,12 @@
 				message_failed(notice, from);
 			}
 			break;
+		case CLIENTACK:
+			gaim_debug(GAIM_DEBUG_ERROR,"zephyr", "Client ack received\n");
 		default:
 			/* we'll just ignore things for now */
-			gaim_debug(GAIM_DEBUG_WARNING, "zephyr", "Unhandled notice.\n");
+			handle_unknown(notice);
+			gaim_debug(GAIM_DEBUG_ERROR, "zephyr", "Unhandled notice.\n");
 			break;
 		}
 
@@ -1038,18 +1079,12 @@
 
 	gconv1 = gaim_find_conversation_with_account(zt->name, zgc->account);
 	gcc = gaim_conversation_get_chat_data(gconv1);
+	
+	/* Woops. Setting instance to "PERSONAL" which is the default
+	   sending instance if no instance is set */
 
-	/* This patently does not make sense ... if inst is not set by
-	 * gaim_conv_chat_get_topic, we set it to the uninitialized
-	 * value of notice.z_class_inst, only to set notice.z_class_inst
-	 * back to inst in a half a dozen lines.  I'm just going to let
-	 * it remain NULL instead.
-	 * 
 	if (!(inst = (char *)gaim_conv_chat_get_topic(gcc)))
-		inst = (char *)notice.z_class_inst;
-	 */
-	inst = (char *)gaim_conv_chat_get_topic(gcc);
-	/* There, now isn't that better? */
+		inst = "PERSONAL";
 
 	bzero((char *)&notice, sizeof(notice));
 	notice.z_kind = ACKED;
@@ -1101,7 +1136,7 @@
 	notice.z_class = "MESSAGE";
 	notice.z_class_inst = "PERSONAL";
 	notice.z_sender = 0;
-	notice.z_recipient = who;
+	notice.z_recipient = local_zephyr_normalize(who);
 	notice.z_default_format = "Class $class, Instance $instance:\n" "To: @bold($recipient) at $time $date\n" "From: @bold($1) <$sender>\n\n$2";
 	notice.z_message_len = strlen(html_buf2) + strlen(sig) + 2;
 	notice.z_message = buf;
@@ -1115,6 +1150,7 @@
 
 static const char *zephyr_normalize(const GaimAccount * account, const char *orig)
 {
+	/* returns the string you gave it. Maybe this function shouldn't be here */
 	static char buf[80];
 
 	if (!g_ascii_strcasecmp(orig, "")) {
@@ -1127,8 +1163,12 @@
 }
 
 
-static const char *local_zephyr_normalize(const char *orig)
+char *local_zephyr_normalize(const char *orig)
 {
+	/* 
+	   Basically the inverse of zephyr_strip_foreign_realm 
+	   
+	 */	
 	static char buf[80];
 
 	if (!g_ascii_strcasecmp(orig, "")) {
@@ -1147,10 +1187,11 @@
 static void zephyr_zloc(GaimConnection *gc, const char *who)
 {
 	ZAsyncLocateData_t ald;
+	gchar* normalized_who = local_zephyr_normalize(who);
 
-	if (ZRequestLocations(local_zephyr_normalize(who), &ald, UNACKED, ZAUTH) == ZERR_NONE) {
+	if (ZRequestLocations(normalized_who, &ald, UNACKED, ZAUTH) == ZERR_NONE) {
 		pending_zloc_names = g_list_append(pending_zloc_names,
-				g_strdup(local_zephyr_normalize(who)));
+				g_strdup(normalized_who));
 	}
 }
 
@@ -1214,14 +1255,19 @@
 	const char *classname;
 	const char *instname;
 	const char *recip;
+	GaimConversation *gconv;
+	GaimConvChat *gcc;
 
 	classname = g_hash_table_lookup(data, "class");
 	instname = g_hash_table_lookup(data, "instance");
 	recip = g_hash_table_lookup(data, "recipient");
 
-	if (!classname || !instname || !recip)
+	if (!classname)
 		return;
-
+	if (!instname || !strlen(instname))
+		instname = "*";
+	if (!recip || (*recip == '*'))
+		recip = "";
 	if (!g_ascii_strcasecmp(recip, "%me%"))
 		recip = gaim_zephyr_get_sender();
 
@@ -1229,8 +1275,15 @@
 	zt2 = find_sub_by_triple(zt1);
 	if (zt2) {
 		free_triple(zt1);
-		if (!zt2->open)
+		if (!zt2->open) {
 			serv_got_joined_chat(gc, zt2->id, zt2->name);
+			gconv = gaim_find_conversation_with_account(zt2->name, zgc->account);
+			gcc = gaim_conversation_get_chat_data(gconv);
+			if (!g_ascii_strcasecmp(instname,"*")) 
+				instname = "PERSONAL";
+			gaim_conv_chat_set_topic(gcc, gaim_zephyr_get_sender(), instname);
+			zt2->open = TRUE;
+		}	
 		return;
 	}
 
@@ -1246,6 +1299,11 @@
 	subscrips = g_slist_append(subscrips, zt1);
 	zt1->open = TRUE;
 	serv_got_joined_chat(gc, zt1->id, zt1->name);
+	gconv = gaim_find_conversation_with_account(zt1->name, zgc->account);
+	gcc = gaim_conversation_get_chat_data(gconv);
+	if (!g_ascii_strcasecmp(instname,"*")) 
+		instname = "PERSONAL";
+	gaim_conv_chat_set_topic(gcc, gaim_zephyr_get_sender(), instname);
 }
 
 static void zephyr_chat_leave(GaimConnection * gc, int id)