changeset 19555:858d279314b2

merge of '493b97b58c0685edae9397f741d0171f9bcc7d2e' and '6f5c855ee2435b317e7ddb8c9551fd17cd0328fe'
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Fri, 31 Aug 2007 17:57:50 +0000
parents 5d178cf627e9 (current diff) c07a9c6f0263 (diff)
children 11de4598b4c5
files
diffstat 12 files changed, 358 insertions(+), 234 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog.win32	Fri Aug 31 17:48:33 2007 +0000
+++ b/ChangeLog.win32	Fri Aug 31 17:57:50 2007 +0000
@@ -1,4 +1,5 @@
 version 2.2.0 (??/??/2007):
+	* Updated gtkspell to 2.0.11
 	* Upgrade SILC to use the 1.1.2 toolkit
 
 version 2.1.1 (08/20/2007):
--- a/libpurple/Makefile.am	Fri Aug 31 17:48:33 2007 +0000
+++ b/libpurple/Makefile.am	Fri Aug 31 17:57:50 2007 +0000
@@ -22,9 +22,9 @@
 		win32/giowin32.c \
 		win32/win32dep.h
 
-# if USE_GCONFTOOL
-# GCONF_DIR=gconf
-# endif
+if USE_GCONFTOOL
+GCONF_DIR=gconf
+endif
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = purple.pc
--- a/libpurple/certificate.c	Fri Aug 31 17:48:33 2007 +0000
+++ b/libpurple/certificate.c	Fri Aug 31 17:57:50 2007 +0000
@@ -1205,7 +1205,14 @@
 	/* Load up the cached certificate */
 	cached_crt = purple_certificate_pool_retrieve(
 		tls_peers, vrq->subject_name);
-	g_assert(cached_crt);
+	if ( !cached_crt ) {
+		purple_debug_error("certificate/x509/tls_cached",
+				   "Lookup failed on cached certificate!\n"
+				   "It was here just a second ago. Forwarding "
+				   "to cert_changed.\n");
+		/* vrq now becomes the problem of cert_changed */
+		x509_tls_cached_peer_cert_changed(vrq);
+	}
 
 	/* Now get SHA1 sums for both and compare them */
 	/* TODO: This is not an elegant way to compare certs */
@@ -1338,7 +1345,14 @@
 
 	ca_crt = purple_certificate_pool_retrieve(ca, ca_id);
 	g_free(ca_id);
-	g_assert(ca_crt);
+	if (!ca_crt) {
+		purple_debug_error("certificate/x509/tls_cached",
+				   "Certificate authority disappeared out "
+				   "underneath me!\n");
+		purple_certificate_verify_complete(vrq,
+						   PURPLE_CERTIFICATE_INVALID);
+		return;
+	}
 	
 	/* Check the signature */
 	if ( !purple_certificate_signed_by(end_crt, ca_crt) ) {
@@ -1375,9 +1389,11 @@
 						 "tls_peers");
 
 	if (tls_peers) {
-		g_assert(purple_certificate_pool_store(tls_peers,
-						       vrq->subject_name,
-						       peer_crt) );
+		if (!purple_certificate_pool_store(tls_peers,vrq->subject_name,
+						   peer_crt) ) {
+			purple_debug_error("certificate/x509/tls_cached",
+					   "FAILED to cache peer certificate\n");
+		}
 	} else {
 		purple_debug_error("certificate/x509/tls_cached",
 				   "Unable to locate tls_peers certificate "
@@ -1790,7 +1806,6 @@
 	GByteArray *sha_bin;
 	gchar *cn;
 	time_t activation, expiration;
-	/* Length of these buffers is dictated by 'man ctime_r' */
 	gchar *activ_str, *expir_str;
 	gchar *secondary;
 
@@ -1807,7 +1822,11 @@
 	/* Get the certificate times */
 	/* TODO: Check the times against localtime */
 	/* TODO: errorcheck? */
-	g_assert(purple_certificate_get_times(crt, &activation, &expiration));
+	if (!purple_certificate_get_times(crt, &activation, &expiration)) {
+		purple_debug_error("certificate",
+				   "Failed to get certificate times!\n");
+		activation = expiration = 0;
+	}
 	activ_str = g_strdup(ctime(&activation));
 	expir_str = g_strdup(ctime(&expiration));
 
--- a/libpurple/example/nullclient.c	Fri Aug 31 17:48:33 2007 +0000
+++ b/libpurple/example/nullclient.c	Fri Aug 31 17:57:50 2007 +0000
@@ -197,7 +197,7 @@
 	purple_util_set_user_dir(CUSTOM_USER_DIRECTORY);
 
 	/* We do not want any debugging for now to keep the noise to a minimum. */
-	purple_debug_set_enabled(TRUE);
+	purple_debug_set_enabled(FALSE);
 
 	/* Set the core-uiops, which is used to
 	 * 	- initialize the ui specific preferences.
@@ -257,24 +257,6 @@
 				PURPLE_CALLBACK(signed_on), NULL);
 }
 
-
-
-
-void signedOn( PurpleConnection *gc, gpointer dummy ) { 
-
-    
-    if( gc ) {
-
-        PurpleAccount* a = purple_connection_get_account( gc );
-
-        if( a ) {
-            
-            purple_presence_set_idle( purple_account_get_presence( a ), TRUE, time( NULL ) );
-        }
-    }    
-}
-
-
 int main()
 {
 	GList *iter;
@@ -300,26 +282,30 @@
 			names = g_list_append(names, info->id);
 		}
 	}
+	printf("Select the protocol [0-%d]: ", i-1);
+	fgets(name, sizeof(name), stdin);
+	sscanf(name, "%d", &num);
+	prpl = g_list_nth_data(names, num);
+
+	printf("Username: ");
+	fgets(name, sizeof(name), stdin);
+	name[strlen(name) - 1] = 0;  /* strip the \n at the end */
 
 	/* Create the account */
-	account = purple_account_new("msimprpl@xyzzy.cjb.net", "prpl-myspace" );
-	purple_account_set_password(account, "4224jc" );
+	account = purple_account_new(name, prpl);
+
+	/* Get the password for the account */
+	password = getpass("Password: ");
+	purple_account_set_password(account, password);
 
 	/* It's necessary to enable the account first. */
 	purple_account_set_enabled(account, UI_ID, TRUE);
 
-#if 0 
-	static int handle;    
-	purple_signal_connect( purple_connections_get_handle(), 
-                           "signed-on", &handle,
-                           PURPLE_CALLBACK( signedOn ), 
-                           NULL );
-    
 	/* Now, to connect the account(s), create a status and activate it. */
-	purple_savedstatus_activate( purple_savedstatus_get_default() );
+	status = purple_savedstatus_new(NULL, PURPLE_STATUS_AVAILABLE);
+	purple_savedstatus_activate(status);
 
 	connect_to_signals_for_demonstration_purposes_only();
-#endif
 
 	g_main_loop_run(loop);
 
--- a/libpurple/plugins/ssl/ssl-gnutls.c	Fri Aug 31 17:48:33 2007 +0000
+++ b/libpurple/plugins/ssl/ssl-gnutls.c	Fri Aug 31 17:57:50 2007 +0000
@@ -60,7 +60,7 @@
 		(gnutls_realloc_function) g_realloc, /* realloc */
 		(gnutls_free_function)    g_free     /* free */
 		);
-	
+
 	gnutls_global_init();
 
 	gnutls_certificate_allocate_credentials(&xcred);
@@ -73,7 +73,7 @@
 static gboolean
 ssl_gnutls_init(void)
 {
-   return TRUE;
+	return TRUE;
 }
 
 static void
@@ -130,17 +130,18 @@
 
 		purple_ssl_close(gsc);
 	} else {
-		purple_debug_info("gnutls", "Handshake complete\n");
-
-		/* TODO: Remove all this debugging babble */
 		/* Now we are cooking with gas! */
 		PurpleSslOps *ops = purple_ssl_get_ops();
 		GList * peers = ops->get_peer_certificates(gsc);
-		
+
 		PurpleCertificateScheme *x509 =
 			purple_certificate_find_scheme("x509");
 
 		GList * l;
+
+		/* TODO: Remove all this debugging babble */
+		purple_debug_info("gnutls", "Handshake complete\n");
+
 		for (l=peers; l; l = l->next) {
 			PurpleCertificate *crt = l->data;
 			GByteArray *z =
@@ -155,72 +156,71 @@
 
 			/* Kill the cert! */
 			x509->destroy_certificate(crt);
-			
+
 			g_free(fpr);
 			g_byte_array_free(z, TRUE);
 		}
 		g_list_free(peers);
-		
+
 		{
-		  const gnutls_datum_t *cert_list;
-		  unsigned int cert_list_size = 0;
-		  gnutls_session_t session=gnutls_data->session;
-		  
-		  cert_list =
-		    gnutls_certificate_get_peers(session, &cert_list_size);
-		  
-		  purple_debug_info("gnutls",
-				    "Peer provided %d certs\n",
-				    cert_list_size);
-		  int i;
-		  for (i=0; i<cert_list_size; i++)
-		    {
-		      gchar fpr_bin[256];
-		      gsize fpr_bin_sz = sizeof(fpr_bin);
-		      gchar * fpr_asc = NULL;
-		      gchar tbuf[256];
-		      gsize tsz=sizeof(tbuf);
-		      gchar * tasc = NULL;
-		      gnutls_x509_crt_t cert;
-		      
-		      gnutls_x509_crt_init(&cert);
-		      gnutls_x509_crt_import (cert, &cert_list[i],
-					      GNUTLS_X509_FMT_DER);
-		      
-		      gnutls_x509_crt_get_fingerprint(cert, GNUTLS_MAC_SHA,
-						      fpr_bin, &fpr_bin_sz);
-		      
-		      fpr_asc =
-			purple_base16_encode_chunked(fpr_bin,fpr_bin_sz);
-		      
-		      purple_debug_info("gnutls", 
-					"Lvl %d SHA1 fingerprint: %s\n",
-					i, fpr_asc);
-		      
-		      tsz=sizeof(tbuf);
-		      gnutls_x509_crt_get_serial(cert,tbuf,&tsz);
-		      tasc=
-			purple_base16_encode_chunked(tbuf, tsz);
-		      purple_debug_info("gnutls",
-					"Serial: %s\n",
-					tasc);
-		      g_free(tasc);
+			const gnutls_datum_t *cert_list;
+			unsigned int cert_list_size = 0;
+			gnutls_session_t session=gnutls_data->session;
+			int i;
+
+			cert_list =
+				gnutls_certificate_get_peers(session, &cert_list_size);
+
+			purple_debug_info("gnutls",
+					    "Peer provided %d certs\n",
+					    cert_list_size);
+			for (i=0; i<cert_list_size; i++)
+			{
+				gchar fpr_bin[256];
+				gsize fpr_bin_sz = sizeof(fpr_bin);
+				gchar * fpr_asc = NULL;
+				gchar tbuf[256];
+				gsize tsz=sizeof(tbuf);
+				gchar * tasc = NULL;
+				gnutls_x509_crt_t cert;
+
+				gnutls_x509_crt_init(&cert);
+				gnutls_x509_crt_import (cert, &cert_list[i],
+						GNUTLS_X509_FMT_DER);
+
+				gnutls_x509_crt_get_fingerprint(cert, GNUTLS_MAC_SHA,
+						fpr_bin, &fpr_bin_sz);
 
-		      tsz=sizeof(tbuf);
-		      gnutls_x509_crt_get_dn (cert, tbuf, &tsz);
-		      purple_debug_info("gnutls",
-					"Cert DN: %s\n",
-					tbuf);
-		      tsz=sizeof(tbuf);
-		      gnutls_x509_crt_get_issuer_dn (cert, tbuf, &tsz);
-		      purple_debug_info("gnutls",
-					"Cert Issuer DN: %s\n",
-					tbuf);
+				fpr_asc =
+						purple_base16_encode_chunked((const guchar *)fpr_bin, fpr_bin_sz);
+
+				purple_debug_info("gnutls",
+						"Lvl %d SHA1 fingerprint: %s\n",
+						i, fpr_asc);
+
+				tsz=sizeof(tbuf);
+				gnutls_x509_crt_get_serial(cert,tbuf,&tsz);
+				tasc=purple_base16_encode_chunked((const guchar *)tbuf, tsz);
+				purple_debug_info("gnutls",
+						"Serial: %s\n",
+						tasc);
+				g_free(tasc);
 
-		      g_free(fpr_asc); fpr_asc = NULL;
-		      gnutls_x509_crt_deinit(cert);
-		    }
-		  
+				tsz=sizeof(tbuf);
+				gnutls_x509_crt_get_dn (cert, tbuf, &tsz);
+				purple_debug_info("gnutls",
+						"Cert DN: %s\n",
+						tbuf);
+				tsz=sizeof(tbuf);
+				gnutls_x509_crt_get_issuer_dn (cert, tbuf, &tsz);
+				purple_debug_info("gnutls",
+						"Cert Issuer DN: %s\n",
+						tbuf);
+
+				g_free(fpr_asc);
+				fpr_asc = NULL;
+				gnutls_x509_crt_deinit(cert);
+			}
 		}
 
 		/* TODO: The following logic should really be in libpurple */
@@ -378,7 +378,7 @@
 	unsigned int cert_list_size = 0;
 
 	unsigned int i;
-	
+
 	/* This should never, ever happen. */
 	g_return_val_if_fail( gnutls_certificate_type_get (gnutls_data->session) == GNUTLS_CRT_X509, NULL);
 
@@ -426,12 +426,14 @@
 static void
 x509_crtdata_delref(x509_crtdata_t *cd)
 {
-	g_assert(cd->refcount > 0);
-	
 	(cd->refcount)--;
 
+	if (cd->refcount < 0)
+		g_critical("Refcount of x509_crtdata_t is %d, which is less "
+				"than zero!\n", cd->refcount);
+
 	/* If the refcount reaches zero, kill the structure */
-	if (cd->refcount == 0) {
+	if (cd->refcount <= 0) {
 		purple_debug_info("gnutls/x509",
 				  "Freeing unused cert data at %p\n",
 				  cd);
@@ -466,11 +468,11 @@
 	certdat = g_new0(x509_crtdata_t, 1);
 	gnutls_x509_crt_init(&(certdat->crt));
 	certdat->refcount = 0;
-	
+
 	/* Perform the actual certificate parse */
 	/* Yes, certdat->crt should be passed as-is */
 	gnutls_x509_crt_import(certdat->crt, &dt, mode);
-	
+
 	/* Allocate the certificate and load it with data */
 	crt = g_new0(PurpleCertificate, 1);
 	crt->scheme = &x509_gnutls;
@@ -495,7 +497,7 @@
 	purple_debug_info("gnutls",
 			  "Attempting to load X.509 certificate from %s\n",
 			  filename);
-	
+
 	/* Next, we'll simply yank the entire contents of the file
 	   into memory */
 	/* TODO: Should I worry about very large files here? */
@@ -506,7 +508,7 @@
 			    NULL      /* No error checking for now */
 		),
 		NULL);
-	
+
 	/* Load the datum struct */
 	dt.data = (unsigned char *) buf;
 	dt.size = buf_sz;
@@ -514,7 +516,7 @@
 	/* Perform the conversion */
 	crt = x509_import_from_datum(dt,
 				     GNUTLS_X509_FMT_PEM); // files should be in PEM format
-	
+
 	/* Cleanup */
 	g_free(buf);
 
@@ -571,7 +573,6 @@
 	success = purple_util_write_data_to_file_absolute(filename,
 							  out_buf, out_size);
 
-	
 	g_free(out_buf);
 	g_return_val_if_fail(success, FALSE);
 	return success;
@@ -596,10 +597,10 @@
 }
 /** Frees a Certificate
  *
- *  Destroys a Certificate's internal data structures and frees the pointer
- *  given.
- *  @param crt  Certificate instance to be destroyed. It WILL NOT be destroyed
- *              if it is not of the correct CertificateScheme. Can be NULL
+ * Destroys a Certificate's internal data structures and frees the pointer
+ * given.
+ * @param crt Certificate instance to be destroyed. It WILL NOT be destroyed
+ *            if it is not of the correct CertificateScheme. Can be NULL
  *
  */
 static void
@@ -622,7 +623,7 @@
 	/* Use the reference counting system to free (or not) the
 	   underlying data */
 	x509_crtdata_delref((x509_crtdata_t *)crt->data);
-	
+
 	/* Kill the structure itself */
 	g_free(crt);
 }
@@ -643,7 +644,7 @@
 	gnutls_x509_crt_t issuer_dat;
 	unsigned int verify; /* used to store result from GnuTLS verifier */
 	int ret;
-	
+
 	g_return_val_if_fail(crt, FALSE);
 	g_return_val_if_fail(issuer, FALSE);
 
@@ -685,7 +686,7 @@
 		/* The issuer is not correct, or there were errors */
 		return FALSE;
 	}
-	
+
 	/* Now, check the signature */
 	/* The second argument is a ptr to an array of "trusted" issuer certs,
 	   but we're only using one trusted one */
@@ -696,7 +697,7 @@
 					current standard) */
 				     GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT,
 				     &verify);
-	
+
 	if (ret != 0) {
 		purple_debug_error("gnutls/x509",
 				   "Attempted certificate verification caused a GnuTLS error code %d. I will just say the signature is bad, but you should look into this.\n", ret);
@@ -713,7 +714,7 @@
 				  issuer_id, crt_id);
 		g_free(crt_id);
 		g_free(issuer_id);
-		
+
 		return FALSE;
 	} /* if (ret, etc.) */
 
@@ -742,7 +743,7 @@
 
 	/* This shouldn't happen */
 	g_return_val_if_fail(tmpsz == hashlen, NULL);
-	
+
 	/* Okay, now create and fill hash array */
 	hash = g_byte_array_new();
 	g_byte_array_append(hash, hashbuf, hashlen);
@@ -776,7 +777,7 @@
 		g_free(dn);
 		return NULL;
 	}
-	
+
 	return dn;
 }
 
@@ -807,7 +808,7 @@
 		g_free(dn);
 		return NULL;
 	}
-	
+
 	return dn;
 }
 
@@ -848,7 +849,6 @@
 		return NULL;
 	}
 
-	
 	return cn;
 }
 
@@ -893,7 +893,7 @@
 	if (*activation == errval || *expiration == errval) {
 		return FALSE;
 	}
-	
+
 	return TRUE;
 }
 
--- a/libpurple/protocols/bonjour/issues.txt	Fri Aug 31 17:48:33 2007 +0000
+++ b/libpurple/protocols/bonjour/issues.txt	Fri Aug 31 17:57:50 2007 +0000
@@ -2,6 +2,5 @@
 ============= Known issues ===============
 ==========================================
 
-* Status changes don't work
 * File transfers
 * Typing notifications
--- a/libpurple/protocols/yahoo/yahoo.c	Fri Aug 31 17:48:33 2007 +0000
+++ b/libpurple/protocols/yahoo/yahoo.c	Fri Aug 31 17:57:50 2007 +0000
@@ -969,7 +969,6 @@
 	PurpleConnection *gc;
 	char *id;
 	char *who;
-	char *msg;
 	int protocol;
 };
 
@@ -987,7 +986,6 @@
 
 	g_free(add_req->id);
 	g_free(add_req->who);
-	g_free(add_req->msg);
 	g_free(add_req);
 }
 
@@ -1018,7 +1016,6 @@
 
 	g_free(add_req->id);
 	g_free(add_req->who);
-	g_free(add_req->msg);
 	g_free(add_req);
 }
 
@@ -1132,10 +1129,18 @@
 			l = l->next;
 		}
 
-		if (add_req->id) {
-			char *alias = NULL;
+		if (add_req->id && add_req->who) {
+			char *alias = NULL, *dec_msg = NULL;
+
+			if (!yahoo_privacy_check(gc, add_req->who)) {
+				purple_debug_misc("yahoo", "Auth. request from %s dropped and automatically denied due to privacy settings!\n",
+						  add_req->who);
+				yahoo_buddy_add_deny_cb(add_req, NULL);
+				return;
+			}
+
 			if (msg)
-				add_req->msg = yahoo_string_decode(gc, msg, FALSE);
+				dec_msg = yahoo_string_decode(gc, msg, FALSE);
 
 			if (firstname && lastname)
 				alias = g_strdup_printf("%s %s", firstname, lastname);
@@ -1144,20 +1149,19 @@
 			else if (lastname)
 				alias = g_strdup(lastname);
 
-
 			/* DONE! this is almost exactly the same as what MSN does,
 			 * this should probably be moved to the core.
 			 */
 			 purple_account_request_authorization(purple_connection_get_account(gc), add_req->who, add_req->id,
-						    alias, add_req->msg, purple_find_buddy(purple_connection_get_account(gc),add_req->who) != NULL,
+						    alias, dec_msg, purple_find_buddy(purple_connection_get_account(gc), add_req->who) != NULL,
 						    yahoo_buddy_add_authorize_cb,
 						    yahoo_buddy_add_deny_reason_cb,
 						    add_req);
 			g_free(alias);
+			g_free(dec_msg);
 		} else {
 			g_free(add_req->id);
 			g_free(add_req->who);
-			/*g_free(add_req->msg);*/
 			g_free(add_req);
 		}
 	} else {
@@ -1165,6 +1169,7 @@
 	}
 }
 
+/* I don't think this happens anymore in Version 15 */
 static void yahoo_buddy_added_us(PurpleConnection *gc, struct yahoo_packet *pkt) {
 	struct yahoo_add_request *add_req;
 	char *msg = NULL;
@@ -1192,22 +1197,31 @@
 		l = l->next;
 	}
 
-	if (add_req->id) {
+	if (add_req->id && add_req->who) {
+		char *dec_msg = NULL;
+
+		if (!yahoo_privacy_check(gc, add_req->who)) {
+			purple_debug_misc("yahoo", "Auth. request from %s dropped and automatically denied due to privacy settings!\n",
+					  add_req->who);
+			yahoo_buddy_add_deny_cb(add_req, NULL);
+			return;
+		}
+
 		if (msg)
-			add_req->msg = yahoo_string_decode(gc, msg, FALSE);
+			dec_msg = yahoo_string_decode(gc, msg, FALSE);
 
 		/* DONE! this is almost exactly the same as what MSN does,
 		 * this should probably be moved to the core.
 		 */
 		 purple_account_request_authorization(purple_connection_get_account(gc), add_req->who, add_req->id,
-                                                    NULL, add_req->msg, purple_find_buddy(purple_connection_get_account(gc),add_req->who) != NULL,
+                                                    NULL, dec_msg, purple_find_buddy(purple_connection_get_account(gc),add_req->who) != NULL,
 						    yahoo_buddy_add_authorize_cb,
 						    yahoo_buddy_add_deny_reason_cb,
                                                     add_req);
+		g_free(dec_msg);
 	} else {
 		g_free(add_req->id);
 		g_free(add_req->who);
-		/*g_free(add_req->msg);*/
 		g_free(add_req);
 	}
 }
@@ -3016,6 +3030,11 @@
 	if (yd->ycht)
 		ycht_connection_close(yd->ycht);
 
+	g_free(yd->pending_chat_room);
+	g_free(yd->pending_chat_id);
+	g_free(yd->pending_chat_topic);
+	g_free(yd->pending_chat_goto);
+
 	g_free(yd);
 	gc->proto_data = NULL;
 }
--- a/libpurple/protocols/yahoo/yahoo.h	Fri Aug 31 17:48:33 2007 +0000
+++ b/libpurple/protocols/yahoo/yahoo.h	Fri Aug 31 17:57:50 2007 +0000
@@ -130,6 +130,10 @@
 	gboolean chat_online;
 	gboolean in_chat;
 	char *chat_name;
+	char *pending_chat_room;
+	char *pending_chat_id;
+	char *pending_chat_topic;
+	char *pending_chat_goto;
 	char *auth;
 	gsize auth_written;
 	char *cookie_y;
--- a/libpurple/protocols/yahoo/yahoochat.c	Fri Aug 31 17:48:33 2007 +0000
+++ b/libpurple/protocols/yahoo/yahoochat.c	Fri Aug 31 17:57:50 2007 +0000
@@ -55,16 +55,24 @@
 {
 	struct yahoo_data *yd = gc->proto_data;
 	struct yahoo_packet *pkt;
+	const char *rll;
 
 	if (yd->wm) {
 		ycht_connection_open(gc);
 		return;
 	}
 
+	rll = purple_account_get_string(purple_connection_get_account(gc),
+								  "room_list_locale", YAHOO_ROOMLIST_LOCALE);
+
 	pkt = yahoo_packet_new(YAHOO_SERVICE_CHATONLINE, YAHOO_STATUS_AVAILABLE,0);
-	yahoo_packet_hash(pkt, "ssss", 1, purple_connection_get_display_name(gc),
-	                  109, purple_connection_get_display_name(gc), 6, "abcde",
-	                  135, "ym8.1.0.415");
+	yahoo_packet_hash(pkt, "sssss",
+					  109, purple_connection_get_display_name(gc),
+					  1, purple_connection_get_display_name(gc),
+					  6, "abcde",
+					/* I'm not sure this is the correct way to set this. */
+					  98, rll,
+					  135, "ym8.1.0.415");
 	yahoo_packet_send_and_free(pkt, yd);
 }
 
@@ -125,6 +133,7 @@
 		case 1: /* us, but we already know who we are */
 			break;
 		case 57:
+			g_free(room);
 			room = yahoo_string_decode(gc, pair->value, FALSE);
 			break;
 		case 50: /* inviter */
@@ -136,6 +145,7 @@
 			g_string_append_printf(members, "%s\n", pair->value);
 			break;
 		case 58:
+			g_free(msg);
 			msg = yahoo_string_decode(gc, pair->value, FALSE);
 			break;
 		case 13: /* ? */
@@ -145,6 +155,17 @@
 
 	if (!room) {
 		g_string_free(members, TRUE);
+		g_free(msg);
+		return;
+	}
+
+	if (!yahoo_privacy_check(gc, who) ||
+			(purple_account_get_bool(purple_connection_get_account(gc), "ignore_invites", FALSE))) {
+		purple_debug_info("yahoo",
+		    "Invite to conference %s from %s has been dropped.\n", room, who);
+		g_free(room);
+		g_free(msg);
+		g_string_free(members, TRUE);
 		return;
 	}
 
@@ -153,19 +174,9 @@
 	if (msg)
 		g_hash_table_replace(components, g_strdup("topic"), msg);
 	g_hash_table_replace(components, g_strdup("type"), g_strdup("Conference"));
-	if (members) {
-		g_hash_table_replace(components, g_strdup("members"), g_strdup(members->str));
-	}
-	if (!yahoo_privacy_check(gc, who) ||
-		(purple_account_get_bool(purple_connection_get_account(gc), "ignore_invites", FALSE))) {
-		purple_debug_info("yahoo",
-		    "Invite to conference %s from %s has been dropped.\n", room, who);
-		g_string_free(members, TRUE);
-		return;
-	}
+	g_hash_table_replace(components, g_strdup("members"), g_string_free(members, FALSE));
 	serv_got_chat_invite(gc, room, who, msg, components);
 
-	g_string_free(members, TRUE);
 }
 
 void yahoo_process_conference_decline(PurpleConnection *gc, struct yahoo_packet *pkt)
@@ -180,20 +191,21 @@
 
 		switch (pair->key) {
 		case 57:
+			g_free(room);
 			room = yahoo_string_decode(gc, pair->value, FALSE);
 			break;
 		case 54:
 			who = pair->value;
 			break;
 		case 14:
+			g_free(msg);
 			msg = yahoo_string_decode(gc, pair->value, FALSE);
 			break;
 		}
 	}
 	if (!yahoo_privacy_check(gc, who)) {
 		g_free(room);
-		if (msg != NULL)
-			g_free(msg);
+		g_free(msg);
 		return;
 	}
 
@@ -209,8 +221,7 @@
 		}
 
 		g_free(room);
-		if (msg)
-			g_free(msg);
+		g_free(msg);
 	}
 }
 
@@ -226,6 +237,7 @@
 
 		switch (pair->key) {
 		case 57:
+			g_free(room);
 			room = yahoo_string_decode(gc, pair->value, FALSE);
 			break;
 		case 53:
@@ -254,6 +266,7 @@
 
 		switch (pair->key) {
 		case 57:
+			g_free(room);
 			room = yahoo_string_decode(gc, pair->value, FALSE);
 			break;
 		case 56:
@@ -276,7 +289,6 @@
 	char *room = NULL;
 	char *who = NULL;
 	char *msg = NULL;
-	char *msg2;
 	int utf8 = 0;
 	PurpleConversation *c;
 
@@ -285,6 +297,7 @@
 
 		switch (pair->key) {
 		case 57:
+			g_free(room);
 			room = yahoo_string_decode(gc, pair->value, FALSE);
 			break;
 		case 3:
@@ -299,28 +312,82 @@
 		}
 	}
 
-		if (room && who && msg) {
-			msg2 = yahoo_string_decode(gc, msg, utf8);
-			c = yahoo_find_conference(gc, room);
-			if (!c)
-				return;
-			msg = yahoo_codes_to_html(msg2);
-			serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(c)), who, 0, msg, time(NULL));
-			g_free(msg);
-			g_free(msg2);
+	if (room && who && msg) {
+		char *msg2;
+
+		c = yahoo_find_conference(gc, room);
+		if (!c) {
+			g_free(room);
+			return;
 		}
-		if (room)
-			g_free(room);
+
+		msg2 = yahoo_string_decode(gc, msg, utf8);
+		msg = yahoo_codes_to_html(msg2);
+		serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(c)), who, 0, msg, time(NULL));
+		g_free(msg);
+		g_free(msg2);
+	}
+
+	g_free(room);
 }
 
+static void yahoo_chat_join(PurpleConnection *gc, const char *dn, const char *room, const char *topic, const char *id)
+{
+	struct yahoo_data *yd = gc->proto_data;
+	struct yahoo_packet *pkt;
+	char *room2;
+	gboolean utf8 = TRUE;
+
+	if (yd->wm) {
+		g_return_if_fail(yd->ycht != NULL);
+		ycht_chat_join(yd->ycht, room);
+		return;
+	}
+
+	/* apparently room names are always utf8, or else always not utf8,
+	 * so we don't have to actually pass the flag in the packet. Or something. */
+	room2 = yahoo_string_encode(gc, room, &utf8);
+
+	pkt = yahoo_packet_new(YAHOO_SERVICE_CHATJOIN, YAHOO_STATUS_AVAILABLE, 0);
+	yahoo_packet_hash(pkt, "ssss",
+						1, purple_connection_get_display_name(gc),
+						104, room2,
+						62, "2",
+						129, id ? id : "0");
+	yahoo_packet_send_and_free(pkt, yd);
+	g_free(room2);
+}
 
 /* this is a confirmation of yahoo_chat_online(); */
 void yahoo_process_chat_online(PurpleConnection *gc, struct yahoo_packet *pkt)
 {
 	struct yahoo_data *yd = (struct yahoo_data *) gc->proto_data;
 
-	if (pkt->status == 1)
+	if (pkt->status == 1) {
 		yd->chat_online = 1;
+
+		/* We need to goto a user in chat */
+		if (yd->pending_chat_goto) {
+			struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_CHATGOTO, YAHOO_STATUS_AVAILABLE, 0);
+			yahoo_packet_hash(pkt, "sss",
+				109, yd->pending_chat_goto,
+				1, purple_connection_get_display_name(gc),
+				62, "2");
+			yahoo_packet_send_and_free(pkt, yd);
+		} else if (yd->pending_chat_room) {
+			yahoo_chat_join(gc, purple_connection_get_display_name(gc), yd->pending_chat_room,
+				yd->pending_chat_topic, yd->pending_chat_id);
+		}
+
+		g_free(yd->pending_chat_room);
+		yd->pending_chat_room = NULL;
+		g_free(yd->pending_chat_id);
+		yd->pending_chat_id = NULL;
+		g_free(yd->pending_chat_topic);
+		yd->pending_chat_topic = NULL;
+		g_free(yd->pending_chat_goto);
+		yd->pending_chat_goto = NULL;
+	}
 }
 
 /* this is basicly the opposite of chat_online */
@@ -340,6 +407,14 @@
 
 	if (pkt->status == 1) {
 		yd->chat_online = 0;
+		g_free(yd->pending_chat_room);
+		yd->pending_chat_room = NULL;
+		g_free(yd->pending_chat_id);
+		yd->pending_chat_id = NULL;
+		g_free(yd->pending_chat_topic);
+		yd->pending_chat_topic = NULL;
+		g_free(yd->pending_chat_goto);
+		yd->pending_chat_goto = NULL;
 		if (yd->in_chat)
 			yahoo_c_leave(gc, YAHOO_CHAT_ID);
 	}
@@ -384,9 +459,11 @@
 		switch (pair->key) {
 
 		case 104:
+			g_free(room);
 			room = yahoo_string_decode(gc, pair->value, TRUE);
 			break;
 		case 105:
+			g_free(topic);
 			topic = yahoo_string_decode(gc, pair->value, TRUE);
 			break;
 		case 128:
@@ -445,8 +522,11 @@
 			purple_conversation_set_name(c, room);
 
 			c = serv_got_joined_chat(gc, YAHOO_CHAT_ID, room);
-			if (topic)
+			if (topic) {
 				purple_conv_chat_set_topic(PURPLE_CONV_CHAT(c), NULL, topic);
+				/* Also print the topic to the backlog so that the captcha link is clickable */
+				purple_conv_chat_write(PURPLE_CONV_CHAT(c), "", topic, PURPLE_MESSAGE_SYSTEM, time(NULL));
+			}
 			yd->in_chat = 1;
 			yd->chat_name = g_strdup(room);
 			purple_conv_chat_add_users(PURPLE_CONV_CHAT(c), members, NULL, flags, FALSE);
@@ -456,14 +536,22 @@
 			g_free(tmpmsg);
 		} else {
 			c = serv_got_joined_chat(gc, YAHOO_CHAT_ID, room);
-			if (topic)
+			if (topic) {
 				purple_conv_chat_set_topic(PURPLE_CONV_CHAT(c), NULL, topic);
+				/* Also print the topic to the backlog so that the captcha link is clickable */
+				purple_conv_chat_write(PURPLE_CONV_CHAT(c), "", topic, PURPLE_MESSAGE_SYSTEM, time(NULL));
+			}
 			yd->in_chat = 1;
 			yd->chat_name = g_strdup(room);
 			purple_conv_chat_add_users(PURPLE_CONV_CHAT(c), members, NULL, flags, FALSE);
 		}
 		g_list_free(flags);
 	} else if (c) {
+		if (topic) {
+			const char *cur_topic = purple_conv_chat_get_topic(PURPLE_CONV_CHAT(c));
+			if (cur_topic == NULL || strcmp(cur_topic, topic) != 0)
+				purple_conv_chat_set_topic(PURPLE_CONV_CHAT(c), NULL, topic);
+		}
 		yahoo_chat_add_users(PURPLE_CONV_CHAT(c), members);
 	}
 
@@ -497,8 +585,10 @@
 	for (l = pkt->hash; l; l = l->next) {
 		struct yahoo_pair *pair = l->data;
 
-		if (pair->key == 104)
+		if (pair->key == 104) {
+			g_free(room);
 			room = yahoo_string_decode(gc, pair->value, TRUE);
+		}
 		if (pair->key == 109)
 			who = pair->value;
 	}
@@ -529,6 +619,7 @@
 			utf8 = strtol(pair->value, NULL, 10);
 			break;
 		case 104:
+			g_free(room);
 			room = yahoo_string_decode(gc, pair->value, TRUE);
 			break;
 		case 109:
@@ -583,6 +674,7 @@
 
 		switch (pair->key) {
 		case 104:
+			g_free(room);
 			room = yahoo_string_decode(gc, pair->value, TRUE);
 			break;
 		case 129: /* room id? */
@@ -590,6 +682,7 @@
 		case 126: /* ??? */
 			break;
 		case 117:
+			g_free(msg);
 			msg = yahoo_string_decode(gc, pair->value, FALSE);
 			break;
 		case 119:
@@ -603,24 +696,21 @@
 	if (room && who) {
 		GHashTable *components;
 
+		if (!yahoo_privacy_check(gc, who) ||
+				(purple_account_get_bool(purple_connection_get_account(gc), "ignore_invites", FALSE))) {
+			purple_debug_info("yahoo", "Invite to room %s from %s has been dropped.\n", room, who);
+			g_free(room);
+			g_free(msg);
+			return;
+		}
+
 		components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
 		g_hash_table_replace(components, g_strdup("room"), g_strdup(room));
-		if (!yahoo_privacy_check(gc, who) ||
-			(purple_account_get_bool(purple_connection_get_account(gc), "ignore_invites", FALSE))) {
-			purple_debug_info("yahoo",
-			"Invite to room %s from %s has been dropped.\n", room, who);
-			if (room != NULL)
-				g_free(room);
-			if (msg != NULL)
-				g_free(msg);
-			return;
-		}
 		serv_got_chat_invite(gc, room, who, msg, components);
 	}
-	if (room)
-		g_free(room);
-	if (msg)
-		g_free(msg);
+
+	g_free(room);
+	g_free(msg);
 }
 
 void yahoo_process_chat_goto(PurpleConnection *gc, struct yahoo_packet *pkt)
@@ -783,6 +873,14 @@
 	yahoo_packet_send_and_free(pkt, yd);
 
 	yd->chat_online = 0;
+	g_free(yd->pending_chat_room);
+	yd->pending_chat_room = NULL;
+	g_free(yd->pending_chat_id);
+	yd->pending_chat_id = NULL;
+	g_free(yd->pending_chat_topic);
+	yd->pending_chat_topic = NULL;
+	g_free(yd->pending_chat_goto);
+	yd->pending_chat_goto = NULL;
 	g_free(eroom);
 }
 
@@ -829,29 +927,6 @@
 	return 0;
 }
 
-static void yahoo_chat_join(PurpleConnection *gc, const char *dn, const char *room, const char *topic)
-{
-	struct yahoo_data *yd = gc->proto_data;
-	struct yahoo_packet *pkt;
-	char *room2;
-	gboolean utf8 = TRUE;
-
-	if (yd->wm) {
-		g_return_if_fail(yd->ycht != NULL);
-		ycht_chat_join(yd->ycht, room);
-		return;
-	}
-
-	/* apparently room names are always utf8, or else always not utf8,
-	 * so we don't have to actually pass the flag in the packet. Or something. */
-	room2 = yahoo_string_encode(gc, room, &utf8);
-
-	pkt = yahoo_packet_new(YAHOO_SERVICE_CHATJOIN, YAHOO_STATUS_AVAILABLE, 0);
-	yahoo_packet_hash(pkt, "ssss", 1, purple_connection_get_display_name(gc),
-	                  62, "2", 104, room2, 129, "0");
-	yahoo_packet_send_and_free(pkt, yd);
-	g_free(room2);
-}
 
 static void yahoo_chat_invite(PurpleConnection *gc, const char *dn, const char *buddy,
 							const char *room, const char *msg)
@@ -892,8 +967,18 @@
 		return;
 	}
 
-	if (!yd->chat_online)
+	if (!yd->chat_online) {
 		yahoo_chat_online(gc);
+		g_free(yd->pending_chat_room);
+		yd->pending_chat_room = NULL;
+		g_free(yd->pending_chat_id);
+		yd->pending_chat_id = NULL;
+		g_free(yd->pending_chat_topic);
+		yd->pending_chat_topic = NULL;
+		g_free(yd->pending_chat_goto);
+		yd->pending_chat_goto = g_strdup(name);
+		return;
+	}
 
 	pkt = yahoo_packet_new(YAHOO_SERVICE_CHATGOTO, YAHOO_STATUS_AVAILABLE, 0);
 	yahoo_packet_hash(pkt, "sss", 109, name, 1, purple_connection_get_display_name(gc), 62, "2");
@@ -988,8 +1073,7 @@
 void yahoo_c_join(PurpleConnection *gc, GHashTable *data)
 {
 	struct yahoo_data *yd;
-	char *room, *topic, *members, *type;
-	int id;
+	char *room, *topic, *type;
 	PurpleConversation *c;
 
 	yd = (struct yahoo_data *) gc->proto_data;
@@ -1004,9 +1088,9 @@
 	if (!topic)
 		topic = "";
 
-	members = g_hash_table_lookup(data, "members");
-
 	if ((type = g_hash_table_lookup(data, "type")) && !strcmp(type, "Conference")) {
+		int id;
+		const char *members = g_hash_table_lookup(data, "members");
 		id = yd->conf_id++;
 		c = serv_got_joined_chat(gc, id, room);
 		yd->confs = g_slist_prepend(yd->confs, c);
@@ -1014,13 +1098,27 @@
 		yahoo_conf_join(yd, c, purple_connection_get_display_name(gc), room, topic, members);
 		return;
 	} else {
-		if (yd->in_chat)
+		const char *id;
+		/*if (yd->in_chat)
 			yahoo_chat_leave(gc, room,
 					purple_connection_get_display_name(gc),
-					FALSE);
-		if (!yd->chat_online)
+					FALSE);*/
+
+		id = g_hash_table_lookup(data, "id");
+
+		if (!yd->chat_online) {
 			yahoo_chat_online(gc);
-		yahoo_chat_join(gc, purple_connection_get_display_name(gc), room, topic);
+			g_free(yd->pending_chat_room);
+			yd->pending_chat_room = g_strdup(room);
+			g_free(yd->pending_chat_id);
+			yd->pending_chat_id = g_strdup(id);
+			g_free(yd->pending_chat_topic);
+			yd->pending_chat_topic = g_strdup(topic);
+			g_free(yd->pending_chat_goto);
+			yd->pending_chat_goto = NULL;
+		} else {
+			yahoo_chat_join(gc, purple_connection_get_display_name(gc), room, topic, id);
+		}
 		return;
 	}
 }
@@ -1148,16 +1246,13 @@
 
 		for (i = 0; anames[i]; i++) {
 			if (!strcmp(anames[i], "id")) {
-				if (s->room.id)
-					g_free(s->room.id);
+				g_free(s->room.id);
 				s->room.id = g_strdup(avalues[i]);
 			} else if (!strcmp(anames[i], "name")) {
-				if (s->room.name)
-					g_free(s->room.name);
+				g_free(s->room.name);
 				s->room.name = g_strdup(avalues[i]);
 			} else if (!strcmp(anames[i], "topic")) {
-				if (s->room.topic)
-					g_free(s->room.topic);
+				g_free(s->room.topic);
 				s->room.topic = g_strdup(avalues[i]);
 			} else if (!strcmp(anames[i], "type")) {
 				if (!strcmp("yahoo", avalues[i]))
--- a/pidgin/gtksourceundomanager.c	Fri Aug 31 17:48:33 2007 +0000
+++ b/pidgin/gtksourceundomanager.c	Fri Aug 31 17:57:50 2007 +0000
@@ -677,8 +677,6 @@
 	if (um->priv->running_not_undoable_actions > 0)
 		return;
 
-	g_return_if_fail (strlen (text) >= (guint)length);
-	
 	undo_action.action_type = GTK_SOURCE_UNDO_ACTION_INSERT;
 
 	undo_action.action.insert.pos    = gtk_text_iter_get_offset (pos);
@@ -774,7 +772,7 @@
 		*action = *undo_action;
 
 		if (action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT)
-			action->action.insert.text = g_strdup (undo_action->action.insert.text);
+			action->action.insert.text = g_strndup (undo_action->action.insert.text, undo_action->action.insert.length);
 		else if (action->action_type == GTK_SOURCE_UNDO_ACTION_DELETE)
 			action->action.delete.text = g_strdup (undo_action->action.delete.text); 
 		else
--- a/pidgin/win32/nsis/pidgin-installer.nsi	Fri Aug 31 17:48:33 2007 +0000
+++ b/pidgin/win32/nsis/pidgin-installer.nsi	Fri Aug 31 17:57:50 2007 +0000
@@ -693,6 +693,8 @@
     ; Remove Language preference info (TODO: check if NSIS removes this)
 
     Delete "$INSTDIR\ca-certs\Equifax_Secure_CA.pem"
+    Delete "$INSTDIR\ca-certs\GTE_CyberTrust_Global_Root.pem"
+    Delete "$INSTDIR\ca-certs\Verisign_Class3_Primary_CA.pem"
     Delete "$INSTDIR\ca-certs\Verisign_RSA_Secure_Server_CA.pem"
     RMDir "$INSTDIR\ca-certs"
     RMDir /r "$INSTDIR\locale"
--- a/share/ca-certs/Makefile.am	Fri Aug 31 17:48:33 2007 +0000
+++ b/share/ca-certs/Makefile.am	Fri Aug 31 17:57:50 2007 +0000
@@ -5,6 +5,7 @@
 		Verisign_RSA_Secure_Server_CA.pem \
 		Verisign_Class3_Primary_CA.pem
 
-EXTRA_DIST = \
-                $(cacerts_DATA)
+EXTRA_DIST =	\
+		Makefile.mingw \
+		$(cacerts_DATA)