Index: protocols/jabber/iq.c
===================================================================
--- protocols/jabber/iq.c	(revision b3117f2524775ff7c61ead7c3bdb3799064ed97f)
+++ protocols/jabber/iq.c	(revision 4e041946706d3fc3aed405152028b02ec2794902)
@@ -51,8 +51,9 @@
 	{
 		if( !( ( c = xt_find_node( node->children, "query" ) ) ||
-		       ( c = xt_find_node( node->children, "ping" ) ) ) || /* O_o WHAT is wrong with just <query/> ????? */
+		       ( c = xt_find_node( node->children, "ping" ) ) ) ||
 		    !( s = xt_find_attr( c, "xmlns" ) ) )
 		{
-			imcb_log( ic, "Warning: Received incomplete IQ-%s packet", type );
+			/* Sigh. Who decided to suddenly invent new elements
+			   instead of just sticking with <query/>? */
 			return XT_HANDLED;
 		}
Index: protocols/jabber/jabber.h
===================================================================
--- protocols/jabber/jabber.h	(revision b3117f2524775ff7c61ead7c3bdb3799064ed97f)
+++ protocols/jabber/jabber.h	(revision 4e041946706d3fc3aed405152028b02ec2794902)
@@ -27,6 +27,7 @@
 #include <glib.h>
 
+#include "bitlbee.h"
+#include "md5.h"
 #include "xmltree.h"
-#include "bitlbee.h"
 
 extern GSList *jabber_connections;
Index: protocols/nogaim.c
===================================================================
--- protocols/nogaim.c	(revision b3117f2524775ff7c61ead7c3bdb3799064ed97f)
+++ protocols/nogaim.c	(revision 4e041946706d3fc3aed405152028b02ec2794902)
@@ -33,6 +33,8 @@
 
 #define BITLBEE_CORE
+#include <ctype.h>
+
 #include "nogaim.h"
-#include <ctype.h>
+#include "chat.h"
 
 static int remove_chat_buddy_silent( struct groupchat *b, const char *handle );
@@ -522,7 +524,6 @@
 }
 
-/* prpl.c */
-
-struct show_got_added_data
+
+struct imcb_ask_cb_data
 {
 	struct im_connection *ic;
@@ -530,23 +531,61 @@
 };
 
-void show_got_added_no( void *data )
-{
-	g_free( ((struct show_got_added_data*)data)->handle );
+static void imcb_ask_auth_cb_no( void *data )
+{
+	struct imcb_ask_cb_data *cbd = data;
+	
+	cbd->ic->acc->prpl->auth_deny( cbd->ic, cbd->handle );
+	
+	g_free( cbd->handle );
+	g_free( cbd );
+}
+
+static void imcb_ask_auth_cb_yes( void *data )
+{
+	struct imcb_ask_cb_data *cbd = data;
+	
+	cbd->ic->acc->prpl->auth_allow( cbd->ic, cbd->handle );
+	
+	g_free( cbd->handle );
+	g_free( cbd );
+}
+
+void imcb_ask_auth( struct im_connection *ic, const char *handle, const char *realname )
+{
+	struct imcb_ask_cb_data *data = g_new0( struct imcb_ask_cb_data, 1 );
+	char *s, *realname_ = NULL;
+	
+	if( realname != NULL )
+		realname_ = g_strdup_printf( " (%s)", realname );
+	
+	s = g_strdup_printf( "The user %s%s wants to add you to his/her buddy list.",
+	                     handle, realname_ ?: "" );
+	
+	g_free( realname_ );
+	
+	data->ic = ic;
+	data->handle = g_strdup( handle );
+	query_add( ic->irc, ic, s, imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, data );
+}
+
+
+static void imcb_ask_add_cb_no( void *data )
+{
+	g_free( ((struct imcb_ask_cb_data*)data)->handle );
 	g_free( data );
 }
 
-void show_got_added_yes( void *data )
-{
-	struct show_got_added_data *sga = data;
-	
-	sga->ic->acc->prpl->add_buddy( sga->ic, sga->handle, NULL );
-	/* imcb_add_buddy( sga->ic, NULL, sga->handle, sga->handle ); */
-	
-	return show_got_added_no( data );
-}
-
-void imcb_ask_add( struct im_connection *ic, char *handle, const char *realname )
-{
-	struct show_got_added_data *data = g_new0( struct show_got_added_data, 1 );
+static void imcb_ask_add_cb_yes( void *data )
+{
+	struct imcb_ask_cb_data *cbd = data;
+	
+	cbd->ic->acc->prpl->add_buddy( cbd->ic, cbd->handle, NULL );
+	
+	return imcb_ask_add_cb_no( data );
+}
+
+void imcb_ask_add( struct im_connection *ic, const char *handle, const char *realname )
+{
+	struct imcb_ask_cb_data *data = g_new0( struct imcb_ask_cb_data, 1 );
 	char *s;
 	
@@ -559,5 +598,5 @@
 	data->ic = ic;
 	data->handle = g_strdup( handle );
-	query_add( ic->irc, ic, s, show_got_added_yes, show_got_added_no, data );
+	query_add( ic->irc, ic, s, imcb_ask_add_cb_yes, imcb_ask_add_cb_no, data );
 }
 
Index: protocols/nogaim.h
===================================================================
--- protocols/nogaim.h	(revision b3117f2524775ff7c61ead7c3bdb3799064ed97f)
+++ protocols/nogaim.h	(revision 4e041946706d3fc3aed405152028b02ec2794902)
@@ -39,9 +39,10 @@
 #define _NOGAIM_H
 
+#include <stdint.h>
+
 #include "bitlbee.h"
 #include "account.h"
 #include "proxy.h"
 #include "query.h"
-#include "md5.h"
 
 #define BUDDY_ALIAS_MAXLEN 388   /* because MSN names can be 387 characters */
@@ -224,4 +225,8 @@
 	 * - Most protocols will just want to set this to g_strcasecmp().*/
 	int (* handle_cmp) (const char *who1, const char *who2);
+
+	/* Implement these callbacks if you want to use imcb_ask_auth() */
+	void (* auth_allow)	(struct im_connection *, const char *who);
+	void (* auth_deny)	(struct im_connection *, const char *who);
 };
 
@@ -252,4 +257,5 @@
 /* To tell the user an error, ie. before logging out when an error occurs. */
 G_MODULE_EXPORT void imcb_error( struct im_connection *ic, char *format, ... ) G_GNUC_PRINTF( 2, 3 );
+
 /* To ask a your about something.
  * - 'msg' is the question.
@@ -258,5 +264,11 @@
  */
 G_MODULE_EXPORT void imcb_ask( struct im_connection *ic, char *msg, void *data, query_callback doit, query_callback dont );
-G_MODULE_EXPORT void imcb_ask_add( struct im_connection *ic, char *handle, const char *realname );
+
+/* Two common questions you may want to ask:
+ * - X added you to his contact list, allow?
+ * - X is not in your contact list, want to add?
+ */
+G_MODULE_EXPORT void imcb_ask_auth( struct im_connection *ic, const char *handle, const char *realname );
+G_MODULE_EXPORT void imcb_ask_add( struct im_connection *ic, const char *handle, const char *realname );
 
 /* Buddy management */
Index: protocols/yahoo/libyahoo2.c
===================================================================
--- protocols/yahoo/libyahoo2.c	(revision b3117f2524775ff7c61ead7c3bdb3799064ed97f)
+++ protocols/yahoo/libyahoo2.c	(revision 4e041946706d3fc3aed405152028b02ec2794902)
@@ -90,6 +90,4 @@
 #include "base64.h"
 #include "http_client.h"
-
-static void yahoo_process_auth_response(struct http_request *req);
 
 #ifdef USE_STRUCT_CALLBACKS
@@ -212,31 +210,21 @@
 	YAHOO_SERVICE_CHATPING,
 	YAHOO_SERVICE_COMMENT = 0xa8,
-	YAHOO_SERVICE_GAME_INVITE = 0xb7,
-	YAHOO_SERVICE_STEALTH_PERM = 0xb9,
-	YAHOO_SERVICE_STEALTH_SESSION = 0xba,
-	YAHOO_SERVICE_AVATAR = 0xbc,
+	YAHOO_SERVICE_STEALTH = 0xb9,
 	YAHOO_SERVICE_PICTURE_CHECKSUM = 0xbd,
 	YAHOO_SERVICE_PICTURE = 0xbe,
 	YAHOO_SERVICE_PICTURE_UPDATE = 0xc1,
 	YAHOO_SERVICE_PICTURE_UPLOAD = 0xc2,
-	YAHOO_SERVICE_YAB_UPDATE = 0xc4,
-	YAHOO_SERVICE_Y6_VISIBLE_TOGGLE = 0xc5, /* YMSG13, key 13: 2 = invisible, 1 = visible */
-	YAHOO_SERVICE_Y6_STATUS_UPDATE = 0xc6,  /* YMSG13 */
-	YAHOO_SERVICE_PICTURE_STATUS = 0xc7,    /* YMSG13, key 213: 0 = none, 1 = avatar, 2 = picture */
-	YAHOO_SERVICE_VERIFY_ID_EXISTS = 0xc8,
-	YAHOO_SERVICE_AUDIBLE = 0xd0,
-	YAHOO_SERVICE_Y7_PHOTO_SHARING = 0xd2,
-	YAHOO_SERVICE_Y7_CONTACT_DETAILS = 0xd3,/* YMSG13 */
-	YAHOO_SERVICE_Y7_CHAT_SESSION = 0xd4,
-	YAHOO_SERVICE_Y7_AUTHORIZATION = 0xd6,  /* YMSG13 */
-	YAHOO_SERVICE_Y7_FILETRANSFER = 0xdc,   /* YMSG13 */
-	YAHOO_SERVICE_Y7_FILETRANSFERINFO,      /* YMSG13 */
-	YAHOO_SERVICE_Y7_FILETRANSFERACCEPT,    /* YMSG13 */
-	YAHOO_SERVICE_Y7_MINGLE = 0xe1, /* YMSG13 */
-	YAHOO_SERVICE_Y7_CHANGE_GROUP = 0xe7, /* YMSG13 */
-	YAHOO_SERVICE_Y8_STATUS = 0xf0,                 /* YMSG15 */
-	YAHOO_SERVICE_Y8_LIST = 0Xf1,                   /* YMSG15 */
-	YAHOO_SERVICE_WEBLOGIN = 0x0226,
-	YAHOO_SERVICE_SMS_MSG = 0x02ea
+	YAHOO_SERVICE_Y6_VISIBILITY=0xc5,
+	YAHOO_SERVICE_Y6_STATUS_UPDATE=0xc6,
+	YAHOO_PHOTOSHARE_INIT=0xd2,	
+	YAHOO_SERVICE_CONTACT_YMSG13=0xd6,
+	YAHOO_PHOTOSHARE_PREV=0xd7,
+	YAHOO_PHOTOSHARE_KEY=0xd8,
+	YAHOO_PHOTOSHARE_TRANS=0xda,
+	YAHOO_FILE_TRANSFER_INIT_YMSG13=0xdc,
+	YAHOO_FILE_TRANSFER_GET_YMSG13=0xdd,
+	YAHOO_FILE_TRANSFER_PUT_YMSG13=0xde,
+	YAHOO_SERVICE_YMSG15_STATUS=0xf0,
+	YAHOO_SERVICE_YMSG15_BUDDY_LIST=0xf1,
 };
 
@@ -776,5 +764,5 @@
 		yahoo_send_data(yid->fd, data, len);
 	else
-	yahoo_add_to_send_queue(yid, data, len);
+		yahoo_add_to_send_queue(yid, data, len);
 	FREE(data);
 }
@@ -1496,7 +1484,13 @@
 
 		if (u->name != NULL) {
-			if (pkt->service == YAHOO_SERVICE_LOGOFF || u->flags == 0) {
+			if (pkt->service == YAHOO_SERVICE_LOGOFF) { /* || u->flags == 0) { Not in YMSG16 */
 				YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, u->name, YAHOO_STATUS_OFFLINE, NULL, 1, 0, 0);
 			} else {
+				/* Key 47 always seems to be 1 for YMSG16 */
+				if(!u->state)
+					u->away = 0;
+				else
+					u->away = 1;
+
 				YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, u->name, u->state, u->msg, u->away, u->idle, u->mobile);
 			}
@@ -2313,18 +2307,188 @@
 }
 
+struct yahoo_https_auth_data
+{
+	struct yahoo_input_data *yid;
+	char *token;
+	char *chal;
+};
+
+static void yahoo_https_auth_token_init(struct yahoo_https_auth_data *had);
+static void yahoo_https_auth_token_finish(struct http_request *req);
+static void yahoo_https_auth_init(struct yahoo_https_auth_data *had);
+static void yahoo_https_auth_finish(struct http_request *req);
+
+/* Extract a value from a login.yahoo.com response. Assume CRLF-linebreaks
+   and FAIL miserably if they're not there... */
+static char *yahoo_ha_find_key(char *response, char *key)
+{
+	char *s, *end;
+	int len = strlen(key);
+	
+	s = response;
+	do {
+		if (strncmp(s, key, len) == 0 && s[len] == '=') {
+			s += len + 1;
+			if ((end = strchr(s, '\r')))
+				return g_strndup(s, end - s);
+			else
+				return g_strdup(s);
+		}
+		
+		if ((s = strchr(s, '\n')))
+			s ++;
+	} while (s && *s);
+	
+	return NULL;
+}
+
+static enum yahoo_status yahoo_https_status_parse(int code)
+{
+	switch (code)
+	{
+		case 1212: return YAHOO_LOGIN_PASSWD;
+		case 1213: return YAHOO_LOGIN_LOCK;
+		case 1235: return YAHOO_LOGIN_UNAME;
+		default: return (enum yahoo_status) code;
+	}
+}
+
 static void yahoo_process_auth_0x10(struct yahoo_input_data *yid, const char *seed, const char *sn)
 {
+	struct yahoo_https_auth_data *had = g_new0(struct yahoo_https_auth_data, 1);
+	
+	had->yid = yid;
+	had->chal = g_strdup(seed);
+	
+	yahoo_https_auth_token_init(had);
+}
+
+static void yahoo_https_auth_token_init(struct yahoo_https_auth_data *had)
+{
+	struct yahoo_input_data *yid = had->yid;
+	struct yahoo_data *yd = yid->yd;
+	struct http_request *req;
+	char *login, *passwd, *chal;
 	char *url;
-
-	yid->yd->login_cookie = strdup(seed);
-
-	url = g_strdup_printf(
-		"https://login.yahoo.com/config/pwtoken_get?"
-		"src=ymsgr&ts=&login=%s&passwd=%s&chal=%s",
-		yid->yd->user, yid->yd->password, seed);
-
-	http_dorequest_url(url, yahoo_process_auth_response, yid);
+	
+	login = g_strndup(yd->user, 3 * strlen(yd->user));
+	http_encode(login);
+	passwd = g_strndup(yd->password, 3 * strlen(yd->password));
+	http_encode(passwd);
+	chal = g_strndup(had->chal, 3 * strlen(had->chal));
+	http_encode(chal);
+	
+	url = g_strdup_printf("https://login.yahoo.com/config/pwtoken_get?src=ymsgr&ts=%d&login=%s&passwd=%s&chal=%s",
+	                       (int) time(NULL), login, passwd, chal);
+	
+	req = http_dorequest_url(url, yahoo_https_auth_token_finish, had);
 	
 	g_free(url);
+	g_free(chal);
+	g_free(passwd);
+	g_free(login);
+}
+
+static void yahoo_https_auth_token_finish(struct http_request *req)
+{
+	struct yahoo_https_auth_data *had = req->data;
+	struct yahoo_input_data *yid = had->yid;
+	struct yahoo_data *yd = yid->yd;
+	int st;
+	
+	if (req->status_code != 200) {
+		YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 2000 + req->status_code, NULL);
+		goto fail;
+	}
+	
+	if (sscanf(req->reply_body, "%d", &st) != 1 || st != 0) {
+		YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, yahoo_https_status_parse(st), NULL);
+		goto fail;
+	}
+	
+	if ((had->token = yahoo_ha_find_key(req->reply_body, "ymsgr")) == NULL) {
+		YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 3001, NULL);
+		goto fail;
+	}
+	
+	return yahoo_https_auth_init(had);
+	
+fail:
+	g_free(had->token);
+	g_free(had->chal);
+	g_free(had);
+}
+
+static void yahoo_https_auth_init(struct yahoo_https_auth_data *had)
+{
+	struct http_request *req;
+	char *url;
+	
+	url = g_strdup_printf("https://login.yahoo.com/config/pwtoken_login?src=ymsgr&ts=%d&token=%s",
+	                      (int) time(NULL), had->token);
+	
+	req = http_dorequest_url(url, yahoo_https_auth_finish, had);
+	
+	g_free(url);
+}
+
+static void yahoo_https_auth_finish(struct http_request *req)
+{
+	struct yahoo_https_auth_data *had = req->data;
+	struct yahoo_input_data *yid = had->yid;
+	struct yahoo_data *yd = yid->yd;
+	struct yahoo_packet *pack;
+	char *crumb;
+	int st;
+	
+	md5_byte_t result[16];
+	md5_state_t ctx;
+	
+	unsigned char yhash[32];
+
+	if (req->status_code != 200) {
+		YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 2000 + req->status_code, NULL);
+		goto fail;
+	}
+	
+	if (sscanf(req->reply_body, "%d", &st) != 1 || st != 0) {
+		YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, yahoo_https_status_parse(st), NULL);
+		goto fail;
+	}
+	
+	if ((yd->cookie_y = yahoo_ha_find_key(req->reply_body, "Y")) == NULL ||
+	    (yd->cookie_t = yahoo_ha_find_key(req->reply_body, "T")) == NULL ||
+	    (crumb = yahoo_ha_find_key(req->reply_body, "crumb")) == NULL) {
+		YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 3002, NULL);
+		goto fail;
+	}
+	
+	md5_init(&ctx);  
+	md5_append(&ctx, (unsigned char*) crumb, 11);
+	md5_append(&ctx, (unsigned char*) had->chal, strlen(had->chal));
+	md5_finish(&ctx, result);
+	to_y64(yhash, result, 16);
+
+	pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yd->initial_status, yd->session_id);
+	yahoo_packet_hash(pack, 1, yd->user);
+	yahoo_packet_hash(pack, 0, yd->user);
+	yahoo_packet_hash(pack, 277, yd->cookie_y);
+	yahoo_packet_hash(pack, 278, yd->cookie_t);
+	yahoo_packet_hash(pack, 307, (char*) yhash);
+	yahoo_packet_hash(pack, 244, "524223");
+	yahoo_packet_hash(pack, 2, yd->user);
+	yahoo_packet_hash(pack, 2, "1");
+	yahoo_packet_hash(pack, 98, "us");
+	yahoo_packet_hash(pack, 135, "7.5.0.647");
+	
+	yahoo_send_packet(yid, pack, 0);
+		
+	yahoo_packet_free(pack);
+	
+fail:
+	g_free(crumb);
+	g_free(had->token);
+	g_free(had->chal);
+	g_free(had);
 }
 
@@ -2358,5 +2522,4 @@
 			break;
 		case 2:
-			/* HTTPS */
 			yahoo_process_auth_0x10(yid, seed, sn);
 			break;
@@ -2515,5 +2678,5 @@
 		
 		yd->buddies = y_list_append(yd->buddies, bud);
-		
+	
 		/* Possibly called already, but at least the call above doesn't
 		   seem to happen every time (not anytime I tried). */
@@ -2522,4 +2685,24 @@
 
 /*	YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, who, status, NULL, (status==YAHOO_STATUS_AVAILABLE?0:1)); */
+}
+
+static void yahoo_process_contact_ymsg13(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
+{
+	char* who=NULL;
+	char* me=NULL;	
+	char* msg=NULL;
+	YList *l;
+	for (l = pkt->hash; l; l = l->next) {
+		struct yahoo_pair *pair = l->data;
+		if (pair->key == 4)
+			who = pair->value;
+		else if (pair->key == 5)
+			me = pair->value;
+		else
+			DEBUG_MSG(("unknown key: %d = %s", pair->key, pair->value));
+	}
+
+	if(pkt->status==3)
+		YAHOO_CALLBACK(ext_yahoo_contact_auth_request)(yid->yd->client_id, me, who, msg);
 }
 
@@ -2735,5 +2918,5 @@
 
 	YList *l;
-	yahoo_dump_unhandled(pkt);
+	// yahoo_dump_unhandled(pkt);
 	for (l = pkt->hash; l; l = l->next) {
 		struct yahoo_pair *pair = l->data;
@@ -2757,4 +2940,5 @@
 {
 	DEBUG_MSG(("yahoo_packet_process: 0x%02x", pkt->service));
+	yahoo_dump_unhandled(pkt);
 	switch (pkt->service)
 	{
@@ -2769,5 +2953,5 @@
 	case YAHOO_SERVICE_IDDEACT:
 	case YAHOO_SERVICE_Y6_STATUS_UPDATE:
-	case YAHOO_SERVICE_Y8_STATUS:
+	case YAHOO_SERVICE_YMSG15_STATUS:
 		yahoo_process_status(yid, pkt);
 		break;
@@ -2783,4 +2967,5 @@
 		yahoo_process_mail(yid, pkt);
 		break;
+	case YAHOO_SERVICE_REJECTCONTACT:
 	case YAHOO_SERVICE_NEWCONTACT:
 		yahoo_process_contact(yid, pkt);
@@ -2823,4 +3008,7 @@
 		yahoo_process_buddyadd(yid, pkt);
 		break;
+	case YAHOO_SERVICE_CONTACT_YMSG13:
+		yahoo_process_contact_ymsg13(yid,pkt);
+		break;
 	case YAHOO_SERVICE_REMBUDDY:
 		yahoo_process_buddydel(yid, pkt);
@@ -2851,5 +3039,4 @@
 	case YAHOO_SERVICE_CHATLOGOFF:
 	case YAHOO_SERVICE_CHATMSG:
-	case YAHOO_SERVICE_REJECTCONTACT:
 	case YAHOO_SERVICE_PEERTOPEER:
 		WARNING(("unhandled service 0x%02x", pkt->service));
@@ -2865,5 +3052,5 @@
 		yahoo_process_picture_upload(yid, pkt);
 		break;	
-	case YAHOO_SERVICE_Y8_LIST:	/* Buddy List */
+	case YAHOO_SERVICE_YMSG15_BUDDY_LIST:	/* Buddy List */
 		yahoo_process_buddy_list(yid, pkt);
 	default:
@@ -3643,178 +3830,4 @@
 }
 
-/* #define LOG(x...) printf x */
-
-static void yahoo_process_auth_response(struct http_request *req)
-{
-	char *line_end;
-	char *token;
-	char *cookie;
-
-	int error_code = 0;
-	int is_ymsgr = 0;
-
-	struct yahoo_input_data *yid = req->data;
-
-	char crypt_hash[25];
-
-	md5_byte_t result[16];
-	md5_state_t ctx;
-
-	struct yahoo_packet *packet = NULL;
-	
-	if (y_list_find(inputs, yid) == NULL)
-		return;
-	
-	if (req->status_code != 200) {
-		error_code = 3000 + req->status_code;
-		goto FAIL;
-	}
-
-	token = req->reply_body;
-	line_end = strstr(token, "\r\n");
-
-	if (line_end) {
-		*line_end = '\0';
-
-		line_end += 2;
-	}
-	
-	if (sscanf(token, "%d", &error_code) != 1) {
-		error_code = 3000;
-		goto FAIL;
-	}
-
-	switch(error_code) {
-		case 0:
-			/* successful */
-			break;
-
-		case 1212:
-			LOG(("Incorrect ID or password\n"));
-			error_code = YAHOO_LOGIN_PASSWD;
-			goto FAIL;
-
-		case 1213:
-			LOG(("Security lock from too many failed login attempts\n"));
-			error_code = YAHOO_LOGIN_LOCK;
-			goto FAIL;
-
-		case 1214:
-			LOG(("Security lock\n"));
-			goto FAIL;
-
-		case 1235:
-			LOG(("User ID not taken yet\n"));
-			error_code = YAHOO_LOGIN_UNAME;
-			goto FAIL;
-
-		case 1216:
-			LOG(("Seems to be a lock, but shows the same generic User ID/Password failure\n"));
-			goto FAIL;
-
-		default:
-			/* Unknown error code */
-			LOG(("Unknown Error\n"));
-			goto FAIL;
-	}
-
-	if ( !strncmp(line_end, "ymsgr=", 6) ) {
-		is_ymsgr = 1;
-	}
-	else if ( strncmp(line_end, "crumb=", 6) ) {
-		LOG(("Oops! There was no ymsgr=. Where do I get my token from now :("));
-		LOG(("I got this:\n\n%s\n",line_end));
-		error_code = 2201;
-		goto FAIL;
-	}
-
-	token = line_end+6;
-
-	line_end = strstr(token, "\r\n");
-
-	if(line_end) {
-		*line_end = '\0';
-		line_end += 2;
-	}
-
-	/* Go for the crumb */
-	if(is_ymsgr) {
-		char *url;
-
-		url = g_strdup_printf(
-			"https://login.yahoo.com/config/pwtoken_login?"
-			"src=ymsgr&ts=&token=%s", token);
-
-		http_dorequest_url(url, yahoo_process_auth_response, yid);
-
-        	g_free(url);
-
-		return;
-	}
-
-	/* token is actually crumb */
-
-	if(!line_end) {
-		/* We did not get our cookies. Cry. */
-	}
-
-	if((cookie = strstr(req->reply_headers, "Set-Cookie: Y=")) &&
-	   (line_end = strstr(cookie + 14, "\r\n"))) {
-		*line_end = '\0';
-		yid->yd->cookie_y = strdup(cookie + 14);
-		*line_end = ';';
-	} else {
-		/* Cry. */
-		LOG(("NO Y Cookie!"));
-		error_code = 2202;
-		goto FAIL;
-	}
-
-	if((cookie = strstr(req->reply_headers, "Set-Cookie: T=")) &&
-	   (line_end = strstr(cookie + 14, "\r\n"))) {
-		*line_end = '\0';
-		yid->yd->cookie_t = strdup(cookie + 14);
-		*line_end = ';';
-	} else {
-		/* Cry. */
-		LOG(("NO T Cookie!"));
-		error_code = 2203;
-		goto FAIL;
-	}
-
-	md5_init(&ctx);
-	md5_append(&ctx, (md5_byte_t *)token, strlen(token));
-	md5_append(&ctx, (md5_byte_t *)yid->yd->login_cookie, strlen(yid->yd->login_cookie));
-	md5_finish(&ctx, result);
-
-	to_y64((unsigned char*)crypt_hash, result, 16);
-
-	packet = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yid->yd->initial_status, yid->yd->session_id);
-	yahoo_packet_hash(packet, 1, yid->yd->user);
-	yahoo_packet_hash(packet, 0, yid->yd->user);
-	yahoo_packet_hash(packet, 277, yid->yd->cookie_y);
-	yahoo_packet_hash(packet, 278, yid->yd->cookie_t);
-	yahoo_packet_hash(packet, 307, crypt_hash);
-	yahoo_packet_hash(packet, 244, "2097087");	/* Rekkanoryo says this is the build number */
-	yahoo_packet_hash(packet, 2, yid->yd->user);
-	yahoo_packet_hash(packet, 2, "1");
-	yahoo_packet_hash(packet, 98, "us");		/* TODO Put country code */
-	yahoo_packet_hash(packet, 135, "9.0.0.1389");
-		
-	yahoo_send_packet(yid, packet, 0);
-
-	yahoo_packet_free(packet);
-
-	/* We don't need this anymore */
-	free(yid->yd->login_cookie);
-	yid->yd->login_cookie = NULL;
-	
-	return;
-
-FAIL:
-	YAHOO_CALLBACK(ext_yahoo_login_response)(yid->yd->client_id, error_code, NULL);
-}
-
-
 static void (*yahoo_process_connection[])(struct yahoo_input_data *, int over) = {
 	yahoo_process_pager_connection,
@@ -4045,5 +4058,5 @@
 
 	yahoo_packet_hash(pkt, 5, who);
-	yahoo_packet_hash(pkt, 4, from?from:yd->user);
+	yahoo_packet_hash(pkt, 1, from?from:yd->user);
 	yahoo_packet_hash(pkt, 14, " ");
 	yahoo_packet_hash(pkt, 13, typ ? "1" : "0");
@@ -4060,5 +4073,5 @@
 	struct yahoo_data *yd;
 	struct yahoo_packet *pkt = NULL;
-	int service;
+	int old_status;
 	char s[4];
 
@@ -4068,5 +4081,7 @@
 	yd = yid->yd;
 
-	if (msg) {
+	old_status = yd->current_status;
+
+	if (msg && strncmp(msg,"Invisible",9)) {
 		yd->current_status = YAHOO_STATUS_CUSTOM;
 	} else {
@@ -4074,30 +4089,35 @@
 	}
 
-	if (yd->current_status == YAHOO_STATUS_AVAILABLE)
-		service = YAHOO_SERVICE_ISBACK;
-	else
-		service = YAHOO_SERVICE_ISAWAY;
+	/* Thank you libpurple :) */
+	if (yd->current_status == YAHOO_STATUS_INVISIBLE) {
+		pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBILITY, YAHOO_STATUS_AVAILABLE, 0);
+		yahoo_packet_hash(pkt, 13, "2");
+		yahoo_send_packet(yid, pkt, 0);
+		yahoo_packet_free(pkt);
+
+		return;
+	}
+
+	pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_STATUS_UPDATE, yd->current_status, yd->session_id);
+	snprintf(s, sizeof(s), "%d", yd->current_status);
+	yahoo_packet_hash(pkt, 10, s);
 	 
-	if ((away == 2) && (yd->current_status == YAHOO_STATUS_AVAILABLE)) {
-		pkt = yahoo_packet_new(YAHOO_SERVICE_ISAWAY, YAHOO_STATUS_BRB, yd->session_id);
-		yahoo_packet_hash(pkt, 10, "999");
-		yahoo_packet_hash(pkt, 47, "2");
-	}else {
-		pkt = yahoo_packet_new(service, YAHOO_STATUS_AVAILABLE, yd->session_id);
-		snprintf(s, sizeof(s), "%d", yd->current_status);
-		yahoo_packet_hash(pkt, 10, s);
-		if (yd->current_status == YAHOO_STATUS_CUSTOM) {
-			yahoo_packet_hash(pkt, 19, msg);
-			yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0");
-		} else {
-			yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0");
-		}
-		
-		
-		
-	}
+	if (yd->current_status == YAHOO_STATUS_CUSTOM) {
+		yahoo_packet_hash(pkt, 19, msg);
+	} else {
+		yahoo_packet_hash(pkt, 19, "");
+	}
+	
+	yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0");
 
 	yahoo_send_packet(yid, pkt, 0);
 	yahoo_packet_free(pkt);
+
+	if(old_status == YAHOO_STATUS_INVISIBLE) {
+		pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBILITY, YAHOO_STATUS_AVAILABLE, 0);
+		yahoo_packet_hash(pkt, 13, "1");
+		yahoo_send_packet(yid, pkt, 0);
+		yahoo_packet_free(pkt);
+	}
 }
 
@@ -4114,5 +4134,8 @@
 	LOG(("yahoo_logoff: current status: %d", yd->current_status));
 
-	if(yd->current_status != -1) {
+	if(yd->current_status != -1 && 0) {
+		/* Meh. Don't send this. The event handlers are not going to
+		   get to do this so it'll just leak memory. And the TCP
+		   connection reset will hopefully be clear enough. */
 		pkt = yahoo_packet_new(YAHOO_SERVICE_LOGOFF, YAHOO_STATUS_AVAILABLE, yd->session_id);
 		yd->current_status = -1;
@@ -4347,10 +4370,22 @@
 		return;
 
-	pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id);
-	yahoo_packet_hash(pkt, 1, yd->user);
-	yahoo_packet_hash(pkt, 7, who);
-	yahoo_packet_hash(pkt, 65, group);
+	pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YPACKET_STATUS_DEFAULT, yd->session_id);
+
 	if (msg != NULL) /* add message/request "it's me add me" */
 		yahoo_packet_hash(pkt, 14, msg);
+	else
+		yahoo_packet_hash(pkt,14,"");
+
+	yahoo_packet_hash(pkt, 65, group);
+	yahoo_packet_hash(pkt, 97, "1");
+	yahoo_packet_hash(pkt, 1, yd->user);
+	yahoo_packet_hash(pkt, 302, "319");
+	yahoo_packet_hash(pkt, 300, "319");
+	yahoo_packet_hash(pkt, 7, who);
+	yahoo_packet_hash(pkt, 334, "0");
+	yahoo_packet_hash(pkt, 301, "319");
+	yahoo_packet_hash(pkt, 303, "319");
+
+
 	yahoo_send_packet(yid, pkt, 0);
 	yahoo_packet_free(pkt);
@@ -4374,4 +4409,47 @@
 	yahoo_send_packet(yid, pkt, 0);
 	yahoo_packet_free(pkt);
+}
+
+void yahoo_accept_buddy_ymsg13(int id,const char* me,const char* who){
+	struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+	struct yahoo_data *yd;
+
+	if(!yid)
+		return;
+	yd = yid->yd;
+
+	struct yahoo_packet* pkt=NULL;
+	pkt= yahoo_packet_new(YAHOO_SERVICE_CONTACT_YMSG13,YAHOO_STATUS_AVAILABLE,0);
+
+	yahoo_packet_hash(pkt,1,me ?: yd->user);	
+	yahoo_packet_hash(pkt,5,who);
+	yahoo_packet_hash(pkt,13,"1");
+	yahoo_packet_hash(pkt,334,"0");
+	yahoo_send_packet(yid, pkt, 0);
+	yahoo_packet_free(pkt);
+}
+
+void yahoo_reject_buddy_ymsg13(int id,const char* me,const char* who,const char* msg){
+	struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
+	struct yahoo_data *yd;
+
+	if(!yid)
+		return;
+	yd = yid->yd;
+
+	struct yahoo_packet* pkt=NULL;
+	pkt= yahoo_packet_new(YAHOO_SERVICE_CONTACT_YMSG13,YAHOO_STATUS_AVAILABLE,0);
+
+	yahoo_packet_hash(pkt,1,me ?: yd->user);	
+	yahoo_packet_hash(pkt,5,who);
+//	yahoo_packet_hash(pkt,241,YAHOO_PROTO_VER);
+	yahoo_packet_hash(pkt,13,"2");
+	yahoo_packet_hash(pkt,334,"0");
+	yahoo_packet_hash(pkt,97,"1");
+	yahoo_packet_hash(pkt,14,msg?:"");
+
+	yahoo_send_packet(yid, pkt, 0);
+	yahoo_packet_free(pkt);
+
 }
 
@@ -4431,5 +4509,5 @@
 		return;
 
-	pkt = yahoo_packet_new(YAHOO_SERVICE_STEALTH_PERM, YAHOO_STATUS_AVAILABLE, yd->session_id);
+	pkt = yahoo_packet_new(YAHOO_SERVICE_STEALTH, YAHOO_STATUS_AVAILABLE, yd->session_id);
 	yahoo_packet_hash(pkt, 1, yd->user);
 	yahoo_packet_hash(pkt, 7, who);
Index: protocols/yahoo/yahoo.c
===================================================================
--- protocols/yahoo/yahoo.c	(revision b3117f2524775ff7c61ead7c3bdb3799064ed97f)
+++ protocols/yahoo/yahoo.c	(revision 4e041946706d3fc3aed405152028b02ec2794902)
@@ -254,18 +254,21 @@
 static GList *byahoo_away_states( struct im_connection *ic )
 {
-	GList *m = NULL;
-
-	m = g_list_append( m, "Available" );
-	m = g_list_append( m, "Be Right Back" );
-	m = g_list_append( m, "Busy" );
-	m = g_list_append( m, "Not At Home" );
-	m = g_list_append( m, "Not At Desk" );
-	m = g_list_append( m, "Not In Office" );
-	m = g_list_append( m, "On Phone" );
-	m = g_list_append( m, "On Vacation" );
-	m = g_list_append( m, "Out To Lunch" );
-	m = g_list_append( m, "Stepped Out" );
-	m = g_list_append( m, "Invisible" );
-	m = g_list_append( m, GAIM_AWAY_CUSTOM );
+	static GList *m = NULL;
+
+	if( m == NULL )
+	{
+		m = g_list_append( m, "Available" );
+		m = g_list_append( m, "Be Right Back" );
+		m = g_list_append( m, "Busy" );
+		m = g_list_append( m, "Not At Home" );
+		m = g_list_append( m, "Not At Desk" );
+		m = g_list_append( m, "Not In Office" );
+		m = g_list_append( m, "On Phone" );
+		m = g_list_append( m, "On Vacation" );
+		m = g_list_append( m, "Out To Lunch" );
+		m = g_list_append( m, "Stepped Out" );
+		m = g_list_append( m, "Invisible" );
+		m = g_list_append( m, GAIM_AWAY_CUSTOM );
+	}
 	
 	return m;
@@ -346,4 +349,18 @@
 	
 	return c;
+}
+
+static void byahoo_auth_allow( struct im_connection *ic, const char *who )
+{
+	struct byahoo_data *yd = (struct byahoo_data *) ic->proto_data;
+	
+	yahoo_accept_buddy_ymsg13( yd->y2_id, NULL, who );
+}
+
+static void byahoo_auth_deny( struct im_connection *ic, const char *who )
+{
+	struct byahoo_data *yd = (struct byahoo_data *) ic->proto_data;
+	
+	yahoo_reject_buddy_ymsg13( yd->y2_id, NULL, who, NULL );
 }
 
@@ -373,4 +390,7 @@
 	ret->handle_cmp = g_strcasecmp;
 	
+	ret->auth_allow = byahoo_auth_allow;
+	ret->auth_deny = byahoo_auth_deny;
+	
 	register_protocol(ret);
 }
@@ -452,7 +472,5 @@
 	struct byahoo_write_ready_data *d = data;
 	
-	yahoo_write_ready( d->id, d->fd, d->data );
-	
-	return FALSE;
+	return yahoo_write_ready( d->id, d->fd, d->data );
 }
 
@@ -922,9 +940,16 @@
 }
 
+void ext_yahoo_contact_auth_request( int id, const char *myid, const char *who, const char *msg )
+{
+	struct im_connection *ic = byahoo_get_ic_by_id( id );
+	
+	imcb_ask_auth( ic, who, NULL );
+}
+
 void ext_yahoo_contact_added( int id, const char *myid, const char *who, const char *msg )
 {
-	/* Groups schmoups. If I want to handle groups properly I can get the
-	   buddy data from some internal libyahoo2 structure. */
-	imcb_add_buddy( byahoo_get_ic_by_id( id ), (char*) who, NULL );
+	struct im_connection *ic = byahoo_get_ic_by_id( id );
+	
+	imcb_add_buddy( ic, (char*) who, NULL );
 }
 
Index: protocols/yahoo/yahoo2.h
===================================================================
--- protocols/yahoo/yahoo2.h	(revision b3117f2524775ff7c61ead7c3bdb3799064ed97f)
+++ protocols/yahoo/yahoo2.h	(revision 4e041946706d3fc3aed405152028b02ec2794902)
@@ -217,4 +217,7 @@
 void yahoo_buddyicon_request(int id, const char *who);
 
+void yahoo_accept_buddy_ymsg13(int,const char*,const char*);
+void yahoo_reject_buddy_ymsg13(int,const char*,const char*,const char*);
+
 #include "yahoo_httplib.h"
 
Index: protocols/yahoo/yahoo2_callbacks.h
===================================================================
--- protocols/yahoo/yahoo2_callbacks.h	(revision b3117f2524775ff7c61ead7c3bdb3799064ed97f)
+++ protocols/yahoo/yahoo2_callbacks.h	(revision 4e041946706d3fc3aed405152028b02ec2794902)
@@ -361,4 +361,16 @@
 
 /*
+ * Name: ext_yahoo_contact_auth_request
+ * 	Called when a contact wants to add you to his/her contact list
+ * Params:
+ * 	id   - the id that identifies the server connection
+ * 	myid - the identity s/he added
+ * 	who  - who did it
+ * 	msg  - any message sent
+ */
+void YAHOO_CALLBACK_TYPE(ext_yahoo_contact_auth_request)(int id, const char *myid, const char *who, const char *msg);
+
+
+/*
  * Name: ext_yahoo_contact_added
  * 	Called when a contact is added to your list
Index: protocols/yahoo/yahoo2_types.h
===================================================================
--- protocols/yahoo/yahoo2_types.h	(revision b3117f2524775ff7c61ead7c3bdb3799064ed97f)
+++ protocols/yahoo/yahoo2_types.h	(revision 4e041946706d3fc3aed405152028b02ec2794902)
@@ -57,5 +57,18 @@
 	YAHOO_LOGIN_LOCK = 14,
 	YAHOO_LOGIN_DUPL = 99,
-	YAHOO_LOGIN_SOCK = -1
+	YAHOO_LOGIN_SOCK = -1,
+};
+
+enum ypacket_status {
+	YPACKET_STATUS_DISCONNECTED = -1,
+	YPACKET_STATUS_DEFAULT = 0,
+	YPACKET_STATUS_SERVERACK = 1,
+	YPACKET_STATUS_GAME     = 0x2,
+	YPACKET_STATUS_AWAY     = 0x4,
+	YPACKET_STATUS_CONTINUED = 0x5,
+	YPACKET_STATUS_INVISIBLE = 12,
+	YPACKET_STATUS_NOTIFY = 0x16, /* TYPING */
+	YPACKET_STATUS_WEBLOGIN = 0x5a55aa55,
+	YPACKET_STATUS_OFFLINE = 0x5a55aa56
 };
 
@@ -133,5 +146,4 @@
 #define YAHOO_CHAT_MALE 0x8000
 #define YAHOO_CHAT_FEMALE 0x10000
-#define YAHOO_CHAT_FEMALE 0x10000
 #define YAHOO_CHAT_DUNNO 0x400
 #define YAHOO_CHAT_WEBCAM 0x10
