⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 yahoo.c

📁 yahoo message protocol stack
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * gaim * * Gaim is the legal property of its developers, whose names are too numerous * to list here.  Please refer to the COPYRIGHT file distributed with this * source distribution. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * */#include "internal.h"#include "account.h"#include "accountopt.h"#include "blist.h"#include "debug.h"#include "notify.h"#include "privacy.h"#include "prpl.h"#include "proxy.h"#include "request.h"#include "server.h"#include "util.h"#include "version.h"#include "sha.h"#include "yahoo.h"#include "yahoo_friend.h"#include "yahoochat.h"#include "ycht.h"#include "yahoo_auth.h"#include "yahoo_filexfer.h"#include "yahoo_picture.h"#include "md5.h"extern char *yahoo_crypt(const char *, const char *);/* #define YAHOO_DEBUG */static void yahoo_add_buddy(GaimConnection *gc, GaimBuddy *, GaimGroup *);static void yahoo_login_page_cb(void *user_data, const char *buf, size_t len);struct yahoo_packet *yahoo_packet_new(enum yahoo_service service, enum yahoo_status status, int id){	struct yahoo_packet *pkt = g_new0(struct yahoo_packet, 1);	pkt->service = service;	pkt->status = status;	pkt->id = id;	return pkt;}void yahoo_packet_hash(struct yahoo_packet *pkt, int key, const char *value){	struct yahoo_pair *pair = g_new0(struct yahoo_pair, 1);	pair->key = key;	pair->value = g_strdup(value);	pkt->hash = g_slist_append(pkt->hash, pair);}int yahoo_packet_length(struct yahoo_packet *pkt){	GSList *l;	int len = 0;	l = pkt->hash;	while (l) {		struct yahoo_pair *pair = l->data;		int tmp = pair->key;		do {			tmp /= 10;			len++;		} while (tmp);		len += 2;		len += strlen(pair->value);		len += 2;		l = l->next;	}	return len;}static void yahoo_packet_read(struct yahoo_packet *pkt, guchar *data, int len){	int pos = 0;	while (pos + 1 < len) {		char key[64], *value = NULL, *esc;		int accept;		int x;		struct yahoo_pair *pair = g_new0(struct yahoo_pair, 1);		/* this is weird, and in one of the chat packets, and causes us		 * think all the values are keys and all the keys are values after		 * this point if we don't handle it */		if (data[pos] == '\0') {			while (pos + 1 < len) {				if (data[pos] == 0xc0 && data[pos + 1] == 0x80)					break;				pos++;			}			pos += 2;			g_free(pair);			continue;		}		x = 0;		while (pos + 1 < len) {			if (data[pos] == 0xc0 && data[pos + 1] == 0x80)				break;			if (x >= sizeof(key)-1) {				x++;				pos++;				continue;			}			key[x++] = data[pos++];		}		if (x >= sizeof(key)-1) {			x = 0;		}		key[x] = 0;		pos += 2;		pair->key = strtol(key, NULL, 10);		accept = x; /* if x is 0 there was no key, so don't accept it */		if (len - pos + 1 <= 0) {			/* Truncated. Garbage or something. */			accept = 0;		}		if (accept) {			value = g_malloc(len - pos + 1);			x = 0;			while (pos + 1 < len) {				if (data[pos] == 0xc0 && data[pos + 1] == 0x80)					break;				value[x++] = data[pos++];			}			value[x] = 0;			pair->value = g_strdup(value);			g_free(value);			pkt->hash = g_slist_append(pkt->hash, pair);			esc = g_strescape(pair->value, NULL);			gaim_debug(GAIM_DEBUG_MISC, "yahoo",					   "Key: %d  \tValue: %s\n", pair->key, esc);			g_free(esc);		} else {			g_free(pair);		}		pos += 2;		/* Skip over garbage we've noticed in the mail notifications */		if (data[0] == '9' && data[pos] == 0x01)			pos++;	}}void yahoo_packet_write(struct yahoo_packet *pkt, guchar *data){	GSList *l = pkt->hash;	int pos = 0;	while (l) {		struct yahoo_pair *pair = l->data;		guchar buf[100];		g_snprintf(buf, sizeof(buf), "%d", pair->key);		strcpy(data + pos, buf);		pos += strlen(buf);		data[pos++] = 0xc0;		data[pos++] = 0x80;		strcpy(data + pos, pair->value);		pos += strlen(pair->value);		data[pos++] = 0xc0;		data[pos++] = 0x80;		l = l->next;	}}static void yahoo_packet_dump(guchar *data, int len){#ifdef YAHOO_DEBUG	int i;	gaim_debug(GAIM_DEBUG_MISC, "yahoo", "");	for (i = 0; i + 1 < len; i += 2) {		if ((i % 16 == 0) && i) {			gaim_debug(GAIM_DEBUG_MISC, NULL, "\n");			gaim_debug(GAIM_DEBUG_MISC, "yahoo", "");		}		gaim_debug(GAIM_DEBUG_MISC, NULL, "%02x%02x ", data[i], data[i + 1]);	}	if (i < len)		gaim_debug(GAIM_DEBUG_MISC, NULL, "%02x", data[i]);	gaim_debug(GAIM_DEBUG_MISC, NULL, "\n");	gaim_debug(GAIM_DEBUG_MISC, "yahoo", "");	for (i = 0; i < len; i++) {		if ((i % 16 == 0) && i) {			gaim_debug(GAIM_DEBUG_MISC, NULL, "\n");			gaim_debug(GAIM_DEBUG_MISC, "yahoo", "");		}		if (g_ascii_isprint(data[i]))			gaim_debug(GAIM_DEBUG_MISC, NULL, "%c ", data[i]);		else			gaim_debug(GAIM_DEBUG_MISC, NULL, ". ");	}	gaim_debug(GAIM_DEBUG_MISC, NULL, "\n");#endif}int yahoo_send_packet(struct yahoo_data *yd, struct yahoo_packet *pkt){	int pktlen = yahoo_packet_length(pkt);	int len = YAHOO_PACKET_HDRLEN + pktlen;	int ret;	guchar *data;	int pos = 0;	if (yd->fd < 0)		return -1;	data = g_malloc0(len + 1);	memcpy(data + pos, "YMSG", 4); pos += 4;	if (yd->wm)		pos += yahoo_put16(data + pos, YAHOO_WEBMESSENGER_PROTO_VER);	else		pos += yahoo_put16(data + pos, YAHOO_PROTO_VER);	pos += yahoo_put16(data + pos, 0x0000);	pos += yahoo_put16(data + pos, pktlen);	pos += yahoo_put16(data + pos, pkt->service);	pos += yahoo_put32(data + pos, pkt->status);	pos += yahoo_put32(data + pos, pkt->id);	yahoo_packet_write(pkt, data + pos);	yahoo_packet_dump(data, len);	ret = write(yd->fd, data, len);	if (ret != len)		gaim_debug_warning("yahoo", "Only wrote %d of %d bytes!", ret, len);	g_free(data);	return ret;}int yahoo_send_packet_special(int fd, struct yahoo_packet *pkt, int pad){	int pktlen = yahoo_packet_length(pkt);	int len = YAHOO_PACKET_HDRLEN + pktlen;	int ret;	guchar *data;	int pos = 0;	if (fd < 0)		return -1;	data = g_malloc0(len + 1);	memcpy(data + pos, "YMSG", 4); pos += 4;	pos += yahoo_put16(data + pos, YAHOO_PROTO_VER);	pos += yahoo_put16(data + pos, 0x0000);	pos += yahoo_put16(data + pos, pktlen + pad);	pos += yahoo_put16(data + pos, pkt->service);	pos += yahoo_put32(data + pos, pkt->status);	pos += yahoo_put32(data + pos, pkt->id);	yahoo_packet_write(pkt, data + pos);	ret = write(fd, data, len);	g_free(data);	return ret;}void yahoo_packet_free(struct yahoo_packet *pkt){	while (pkt->hash) {		struct yahoo_pair *pair = pkt->hash->data;		g_free(pair->value);		g_free(pair);		pkt->hash = g_slist_remove(pkt->hash, pair);	}	g_free(pkt);}static void yahoo_update_status(GaimConnection *gc, const char *name, YahooFriend *f){	gboolean online = TRUE;	if (!gc || !name || !f || !gaim_find_buddy(gaim_connection_get_account(gc), name))		return;	if (f->status == YAHOO_STATUS_OFFLINE)		online = FALSE;	serv_got_update(gc, name, online, 0, 0, f->idle, f->away ? UC_UNAVAILABLE : 0);}static void yahoo_process_status(GaimConnection *gc, struct yahoo_packet *pkt){	struct yahoo_data *yd = gc->proto_data;	GSList *l = pkt->hash;	YahooFriend *f = NULL;	char *name = NULL;	if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) {		gc->wants_to_die = TRUE;		gaim_connection_error(gc, _("You have been logged off as you have logged in on a different machine or device."));		return;	}	while (l) {		struct yahoo_pair *pair = l->data;		switch (pair->key) {		case 0: /* we won't actually do anything with this */			break;		case 1: /* we don't get the full buddy list here. */			if (!yd->logged_in) {				gaim_connection_set_display_name(gc, pair->value);				gaim_connection_set_state(gc, GAIM_CONNECTED);				serv_finish_login(gc);				yd->logged_in = TRUE;				if (yd->picture_upload_todo) {					yahoo_buddy_icon_upload(gc, yd->picture_upload_todo);					yd->picture_upload_todo = NULL;				}				/* this requests the list. i have a feeling that this is very evil				 *				 * scs.yahoo.com sends you the list before this packet without  it being				 * requested				 *				 * do_import(gc, NULL);				 * newpkt = yahoo_packet_new(YAHOO_SERVICE_LIST, YAHOO_STATUS_OFFLINE, 0);				 * yahoo_send_packet(yd, newpkt);				 * yahoo_packet_free(newpkt);				 */				}			break;		case 8: /* how many online buddies we have */			break;		case 7: /* the current buddy */			name = pair->value;			if (name && g_utf8_validate(name, -1, NULL))				f = yahoo_friend_find_or_new(gc, name);			else {				f = NULL;				name = NULL;			}			break;		case 10: /* state */			if (!f)				break;			f->status = strtol(pair->value, NULL, 10);			if ((f->status >= YAHOO_STATUS_BRB) && (f->status <= YAHOO_STATUS_STEPPEDOUT))				f->away = 1;			else				f->away = 0;			if (f->status == YAHOO_STATUS_IDLE)				f->idle = time(NULL);			else				f->idle = 0;			if (f->status != YAHOO_STATUS_CUSTOM)				yahoo_friend_set_status_message(f, NULL);			f->sms = 0;			break;		case 19: /* custom message */			if (f)				yahoo_friend_set_status_message(f, yahoo_string_decode(gc, pair->value, FALSE));			break;		case 11: /* this is the buddy's session id */			break;		case 17: /* in chat? */			break;		case 47: /* is custom status away or not? 2=idle*/			if (!f)				break;			/* I have no idea what it means when this is			 * set when someone's available, but it doesn't			 * mean idle. */			if (f->status == YAHOO_STATUS_AVAILABLE)				break;			f->away = strtol(pair->value, NULL, 10);			if (f->away == 2)				f->idle = time(NULL);			break;		case 138: /* either we're not idle, or we are but won't say how long */			if (!f)				break;			if (f->idle)				f->idle = -1;			break;		case 137: /* usually idle time in seconds, sometimes login time */			if (!f)				break;			if (f->status != YAHOO_STATUS_AVAILABLE)				f->idle = time(NULL) - strtol(pair->value, NULL, 10);			break;		case 13: /* bitmask, bit 0 = pager, bit 1 = chat, bit 2 = game */			if (strtol(pair->value, NULL, 10) == 0) {				if (f)					f->status = YAHOO_STATUS_OFFLINE;				serv_got_update(gc, name, FALSE, 0, 0, 0, 0);				break;			}			if (f)				yahoo_update_status(gc, name, f);			break;		case 60: /* SMS */			if (f) {				f->sms = strtol(pair->value, NULL, 10);				yahoo_update_status(gc, name, f);			}			break;		case 197: /* Avatars */		{			char *decoded, *tmp;			guint len;			if (pair->value) {				gaim_base64_decode(pair->value, &decoded, &len);				if (len) {					tmp = gaim_str_binary_to_ascii(decoded, len);					gaim_debug_info("yahoo", "Got key 197, value = %s\n", tmp);					g_free(tmp);				}				g_free(decoded);			}			break;		}		case 192: /* Pictures, aka Buddy Icons, checksum */		{			int cksum = strtol(pair->value, NULL, 10);			GaimBuddy *b;			if (!name)				break;			b = gaim_find_buddy(gc->account, name);			if (!cksum || (cksum == -1)) {				if (f)					yahoo_friend_set_buddy_icon_need_request(f, TRUE);				gaim_buddy_icons_set_for_user(gc->account, name, NULL, 0);				if (b)					gaim_blist_node_remove_setting((GaimBlistNode *)b, YAHOO_ICON_CHECKSUM_KEY);				break;			}			if (!f)				break;			yahoo_friend_set_buddy_icon_need_request(f, FALSE);			if (cksum != gaim_blist_node_get_int((GaimBlistNode*)b, YAHOO_ICON_CHECKSUM_KEY))				yahoo_send_picture_request(gc, name);			break;		}		case 16: /* Custom error message */			{				char *tmp = yahoo_string_decode(gc, pair->value, TRUE);				gaim_notify_error(gc, NULL, tmp, NULL);				g_free(tmp);			}			break;		default:			gaim_debug(GAIM_DEBUG_ERROR, "yahoo",					   "Unknown status key %d\n", pair->key);			break;		}		l = l->next;	}}static void yahoo_do_group_check(GaimAccount *account, GHashTable *ht, const char *name, const char *group){	GaimBuddy *b;	GaimGroup *g;	GSList *list, *i;	gboolean onlist = 0;	char *oname = NULL;	char **oname_p = &oname;	GSList **list_p = &list;	if (!g_hash_table_lookup_extended(ht, gaim_normalize(account, name), (gpointer *) oname_p, (gpointer *) list_p))		list = gaim_find_buddies(account, name);	else		g_hash_table_steal(ht, name);	for (i = list; i; i = i->next) {		b = i->data;		g = gaim_find_buddys_group(b);		if (!gaim_utf8_strcasecmp(group, g->name)) {			gaim_debug(GAIM_DEBUG_MISC, "yahoo",				"Oh good, %s is in the right group (%s).\n", name, group);			list = g_slist_delete_link(list, i);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -