# HG changeset patch # User Luke Schierer # Date 1062593117 0 # Node ID 7b878ee8f0643606c863ff67279fcb8c4e34a731 # Parent fa7359c3f93c2f4e74b167af08e7fc7bdb7a8d9e [gaim-migrate @ 7256] Tim Ringenbach (marv_sf) writes: " This adds Chat and Conference support to the Yahoo! prpl. I think I got all the major bugs out, and it works pretty good. You can invite others, and accept inventations for both chats and conferences, you can join a chat from the Buddies menu in the buddy list, like you would for irc, and you can initiate a conference by right clicking on a buddy, like you would for msn. You can also attempt to join user in chat, which will fail if they're not actually in a chat. (Apparently the offical version can't tell before hand either.) Oh, and you can chat." committer: Tailor Script diff -r fa7359c3f93c -r 7b878ee8f064 src/protocols/yahoo/Makefile.am --- a/src/protocols/yahoo/Makefile.am Wed Sep 03 12:31:08 2003 +0000 +++ b/src/protocols/yahoo/Makefile.am Wed Sep 03 12:45:17 2003 +0000 @@ -7,7 +7,9 @@ crypt.c \ md5.h \ yahoo.h \ + yahoochat.h \ yahoo.c \ + yahoochat.c \ util.c AM_CFLAGS = $(st) diff -r fa7359c3f93c -r 7b878ee8f064 src/protocols/yahoo/yahoo.c --- a/src/protocols/yahoo/yahoo.c Wed Sep 03 12:31:08 2003 +0000 +++ b/src/protocols/yahoo/yahoo.c Wed Sep 03 12:45:17 2003 +0000 @@ -34,6 +34,7 @@ #include "html.h" #include "yahoo.h" +#include "yahoochat.h" #include "md5.h" /* XXX */ @@ -53,93 +54,9 @@ #define YAHOO_PROTO_VER 0x0900 -enum yahoo_service { /* these are easier to see in hex */ - YAHOO_SERVICE_LOGON = 1, - YAHOO_SERVICE_LOGOFF, - YAHOO_SERVICE_ISAWAY, - YAHOO_SERVICE_ISBACK, - YAHOO_SERVICE_IDLE, /* 5 (placemarker) */ - YAHOO_SERVICE_MESSAGE, - YAHOO_SERVICE_IDACT, - YAHOO_SERVICE_IDDEACT, - YAHOO_SERVICE_MAILSTAT, - YAHOO_SERVICE_USERSTAT, /* 0xa */ - YAHOO_SERVICE_NEWMAIL, - YAHOO_SERVICE_CHATINVITE, - YAHOO_SERVICE_CALENDAR, - YAHOO_SERVICE_NEWPERSONALMAIL, - YAHOO_SERVICE_NEWCONTACT, - YAHOO_SERVICE_ADDIDENT, /* 0x10 */ - YAHOO_SERVICE_ADDIGNORE, - YAHOO_SERVICE_PING, - YAHOO_SERVICE_GROUPRENAME, - YAHOO_SERVICE_SYSMESSAGE = 0x14, - YAHOO_SERVICE_PASSTHROUGH2 = 0x16, - YAHOO_SERVICE_CONFINVITE = 0x18, - YAHOO_SERVICE_CONFLOGON, - YAHOO_SERVICE_CONFDECLINE, - YAHOO_SERVICE_CONFLOGOFF, - YAHOO_SERVICE_CONFADDINVITE, - YAHOO_SERVICE_CONFMSG, - YAHOO_SERVICE_CHATLOGON, - YAHOO_SERVICE_CHATLOGOFF, - YAHOO_SERVICE_CHATMSG = 0x20, - YAHOO_SERVICE_GAMELOGON = 0x28, - YAHOO_SERVICE_GAMELOGOFF, - YAHOO_SERVICE_GAMEMSG = 0x2a, - YAHOO_SERVICE_FILETRANSFER = 0x46, - YAHOO_SERVICE_NOTIFY = 0x4B, - YAHOO_SERVICE_AUTHRESP = 0x54, - YAHOO_SERVICE_LIST = 0x55, - YAHOO_SERVICE_AUTH = 0x57, - YAHOO_SERVICE_ADDBUDDY = 0x83, - YAHOO_SERVICE_REMBUDDY = 0x84 -}; - -enum yahoo_status { - YAHOO_STATUS_AVAILABLE = 0, - YAHOO_STATUS_BRB, - YAHOO_STATUS_BUSY, - YAHOO_STATUS_NOTATHOME, - YAHOO_STATUS_NOTATDESK, - YAHOO_STATUS_NOTINOFFICE, - YAHOO_STATUS_ONPHONE, - YAHOO_STATUS_ONVACATION, - YAHOO_STATUS_OUTTOLUNCH, - YAHOO_STATUS_STEPPEDOUT, - YAHOO_STATUS_INVISIBLE = 12, - YAHOO_STATUS_CUSTOM = 99, - YAHOO_STATUS_IDLE = 999, - YAHOO_STATUS_OFFLINE = 0x5a55aa56, /* don't ask */ - YAHOO_STATUS_TYPING = 0x16 -}; -#define YAHOO_STATUS_GAME 0x2 /* Games don't fit into the regular status model */ - -struct yahoo_data { - int fd; - guchar *rxqueue; - int rxlen; - GHashTable *hash; - GHashTable *games; - int current_status; - gboolean logged_in; -}; - -struct yahoo_pair { - int key; - char *value; -}; - -struct yahoo_packet { - guint16 service; - guint32 status; - guint32 id; - GSList *hash; -}; - #define YAHOO_PACKET_HDRLEN (4 + 2 + 2 + 2 + 2 + 4 + 4) -static struct yahoo_packet *yahoo_packet_new(enum yahoo_service service, enum yahoo_status status, int id) +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); @@ -150,7 +67,7 @@ return pkt; } -static void yahoo_packet_hash(struct yahoo_packet *pkt, int key, const char *value) +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; @@ -314,7 +231,7 @@ #endif } -static int yahoo_send_packet(struct yahoo_data *yd, struct yahoo_packet *pkt) +int yahoo_send_packet(struct yahoo_data *yd, struct yahoo_packet *pkt) { int pktlen = yahoo_packet_length(pkt); int len = YAHOO_PACKET_HDRLEN + pktlen; @@ -345,7 +262,7 @@ return ret; } -static void yahoo_packet_free(struct yahoo_packet *pkt) +void yahoo_packet_free(struct yahoo_packet *pkt) { while (pkt->hash) { struct yahoo_pair *pair = pkt->hash->data; @@ -917,6 +834,45 @@ case YAHOO_SERVICE_AUTH: yahoo_process_auth(gc, pkt); break; + case YAHOO_SERVICE_CONFINVITE: + case YAHOO_SERVICE_CONFADDINVITE: + yahoo_process_conference_invite(gc, pkt); + break; + case YAHOO_SERVICE_CONFDECLINE: + yahoo_process_conference_decline(gc, pkt); + break; + case YAHOO_SERVICE_CONFLOGON: + yahoo_process_conference_logon(gc, pkt); + break; + case YAHOO_SERVICE_CONFLOGOFF: + yahoo_process_conference_logoff(gc, pkt); + break; + case YAHOO_SERVICE_CONFMSG: + yahoo_process_conference_message(gc, pkt); + break; + case YAHOO_SERVICE_CHATONLINE: + yahoo_process_chat_online(gc, pkt); + break; + case YAHOO_SERVICE_CHATLOGOUT: + yahoo_process_chat_logout(gc, pkt); + break; + case YAHOO_SERVICE_CHATGOTO: + yahoo_process_chat_goto(gc, pkt); + break; + case YAHOO_SERVICE_CHATJOIN: + yahoo_process_chat_join(gc, pkt); + break; + case YAHOO_SERVICE_CHATLEAVE: /* XXX is this right? */ + case YAHOO_SERVICE_CHATEXIT: + yahoo_process_chat_exit(gc, pkt); + break; + case YAHOO_SERVICE_CHATINVITE: /* XXX never seen this one, might not do it right */ + case YAHOO_SERVICE_CHATADDINVITE: + yahoo_process_chat_addinvite(gc, pkt); + break; + case YAHOO_SERVICE_COMMENT: + yahoo_process_chat_message(gc, pkt); + break; default: gaim_debug(GAIM_DEBUG_ERROR, "yahoo", "Unhandled service 0x%02x\n", pkt->service); @@ -1030,6 +986,8 @@ yd->fd = -1; yd->hash = g_hash_table_new(g_str_hash, g_str_equal); yd->games = g_hash_table_new(g_str_hash, g_str_equal); + yd->confs = NULL; + yd->conf_id = 2; if (gaim_proxy_connect(account, gaim_account_get_string(account, "server", YAHOO_PAGER_HOST), gaim_account_get_int(account, "port", YAHOO_PAGER_PORT), @@ -1053,6 +1011,9 @@ g_hash_table_destroy(yd->hash); g_hash_table_foreach_remove(yd->games, yahoo_destroy_hash, NULL); g_hash_table_destroy(yd->games); + + g_slist_free(yd->confs); + if (yd->fd >= 0) close(yd->fd); @@ -1118,6 +1079,26 @@ } } +static void yahoo_initiate_conference(GaimConnection *gc, const char *name) +{ + GHashTable *components; + struct yahoo_data *yd; + int id; + + yd = gc->proto_data; + id = yd->conf_id; + + 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_printf("%s-%d", gaim_connection_get_display_name(gc), id)); + g_hash_table_replace(components, g_strdup("topic"), g_strdup("Join my conference...")); + g_hash_table_replace(components, g_strdup("type"), g_strdup("Conference")); + yahoo_c_join(gc, components); + g_hash_table_destroy(components); + + yahoo_c_invite(gc, id, "Join my conference...", name); +} + static void yahoo_game(GaimConnection *gc, const char *name) { struct yahoo_data *yd = (struct yahoo_data *)gc->proto_data; char *game = g_hash_table_lookup(yd->games, name); @@ -1183,6 +1164,18 @@ segfault and get the bug report. */ static char buf2[1024]; + pbm = g_new0(struct proto_buddy_menu, 1); + pbm->label = _("Join in Chat"); + pbm->callback = yahoo_chat_goto; + pbm->gc = gc; + m = g_list_append(m, pbm); + + pbm = g_new0(struct proto_buddy_menu, 1); + pbm->label = _("Initiate Conference"); + pbm->callback = yahoo_initiate_conference; + pbm->gc = gc; + m = g_list_append(m, pbm); + if (b->uc | YAHOO_STATUS_GAME) { char *game = g_hash_table_lookup(yd->games, b->name); char *room; @@ -1192,11 +1185,11 @@ char *t; pbm = g_new0(struct proto_buddy_menu, 1); if (!(room = strstr(game, "&follow="))) /* skip ahead to the url */ - return NULL; + return m; while (*room && *room != '\t') /* skip to the tab */ room++; t = room++; /* room as now at the name */ - while (*t != '\n') + while (*t != '\n') t++; /* replace the \n with a space */ *t = ' '; g_snprintf(buf2, sizeof buf2, "%s", room); @@ -1206,7 +1199,7 @@ m = g_list_append(m, pbm); } } - + return m; } @@ -1401,6 +1394,14 @@ struct yahoo_packet *pkt = yahoo_packet_new(YAHOO_SERVICE_PING, YAHOO_STATUS_AVAILABLE, 0); yahoo_send_packet(yd, pkt); yahoo_packet_free(pkt); + + if (!yd->chat_online) + return; + + pkt = yahoo_packet_new(YAHOO_SERVICE_CHATPING, YAHOO_STATUS_AVAILABLE, 0); + yahoo_packet_hash(pkt, 109, gaim_connection_get_display_name(gc)); + yahoo_send_packet(yd, pkt); + yahoo_packet_free(pkt); } static void yahoo_add_buddy(GaimConnection *gc, const char *who) @@ -1619,9 +1620,9 @@ static GaimPluginProtocolInfo prpl_info = { GAIM_PROTO_YAHOO, - OPT_PROTO_MAIL_CHECK, - NULL, - NULL, + OPT_PROTO_MAIL_CHECK | OPT_PROTO_CHAT_TOPIC, + NULL, /* user_splits */ + NULL, /* protocol_options */ yahoo_list_icon, yahoo_list_emblems, yahoo_status_text, @@ -1629,45 +1630,46 @@ yahoo_away_states, yahoo_actions, yahoo_buddy_menu, - NULL, + yahoo_c_info, yahoo_login, yahoo_close, yahoo_send_im, - NULL, + NULL, /* set info */ yahoo_send_typing, yahoo_get_info, yahoo_set_away, - NULL, - NULL, - NULL, - NULL, + NULL, /* get_away */ + NULL, /* set_dir */ + NULL, /* get_dir */ + NULL, /* dir_search */ yahoo_set_idle, - NULL, + NULL, /* change_passwd*/ yahoo_add_buddy, - NULL, + NULL, /* add_buddies */ yahoo_remove_buddy, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, + NULL, /*remove_buddies */ + NULL, /* add_permit */ + NULL, /* add_dey */ + NULL, /* rem_permit */ + NULL, /* rem_deny */ + NULL, /* set_permit_deny */ + NULL, /* warn */ + yahoo_c_join, + yahoo_c_invite, + yahoo_c_leave, + NULL, /* chat whisper */ + yahoo_c_send, yahoo_keepalive, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL + NULL, /* register_user */ + NULL, /* get_cb_info */ + NULL, /* get_cb_away */ + NULL, /* alias_buddy */ + NULL, /* change group */ + NULL, /* rename group */ + NULL, /* buddy_free */ + NULL, /* convo_closed */ + NULL, /* normalize */ + NULL /* set_buddy_icon */ }; static GaimPluginInfo info = diff -r fa7359c3f93c -r 7b878ee8f064 src/protocols/yahoo/yahoo.h --- a/src/protocols/yahoo/yahoo.h Wed Sep 03 12:31:08 2003 +0000 +++ b/src/protocols/yahoo/yahoo.h Wed Sep 03 12:45:17 2003 +0000 @@ -23,7 +23,118 @@ #ifndef _YAHOO_H_ #define _YAHOO_H_ +enum yahoo_service { /* these are easier to see in hex */ + YAHOO_SERVICE_LOGON = 1, + YAHOO_SERVICE_LOGOFF, + YAHOO_SERVICE_ISAWAY, + YAHOO_SERVICE_ISBACK, + YAHOO_SERVICE_IDLE, /* 5 (placemarker) */ + YAHOO_SERVICE_MESSAGE, + YAHOO_SERVICE_IDACT, + YAHOO_SERVICE_IDDEACT, + YAHOO_SERVICE_MAILSTAT, + YAHOO_SERVICE_USERSTAT, /* 0xa */ + YAHOO_SERVICE_NEWMAIL, + YAHOO_SERVICE_CHATINVITE, + YAHOO_SERVICE_CALENDAR, + YAHOO_SERVICE_NEWPERSONALMAIL, + YAHOO_SERVICE_NEWCONTACT, + YAHOO_SERVICE_ADDIDENT, /* 0x10 */ + YAHOO_SERVICE_ADDIGNORE, + YAHOO_SERVICE_PING, + YAHOO_SERVICE_GOTGROUPRENAME, + YAHOO_SERVICE_SYSMESSAGE = 0x14, + YAHOO_SERVICE_PASSTHROUGH2 = 0x16, + YAHOO_SERVICE_CONFINVITE = 0x18, + YAHOO_SERVICE_CONFLOGON, + YAHOO_SERVICE_CONFDECLINE, + YAHOO_SERVICE_CONFLOGOFF, + YAHOO_SERVICE_CONFADDINVITE, + YAHOO_SERVICE_CONFMSG, + YAHOO_SERVICE_CHATLOGON, + YAHOO_SERVICE_CHATLOGOFF, + YAHOO_SERVICE_CHATMSG = 0x20, + YAHOO_SERVICE_GAMELOGON = 0x28, + YAHOO_SERVICE_GAMELOGOFF, + YAHOO_SERVICE_GAMEMSG = 0x2a, + YAHOO_SERVICE_FILETRANSFER = 0x46, + YAHOO_SERVICE_VOICECHAT = 0x4A, + YAHOO_SERVICE_NOTIFY = 0x4B, + YAHOO_SERVICE_VERIFY, + YAHOO_SERVICE_P2PFILEXFER, + YAHOO_SERVICE_PEEPTOPEER = 0x4F, + YAHOO_SERVICE_WEBCAM, + YAHOO_SERVICE_AUTHRESP = 0x54, + YAHOO_SERVICE_LIST = 0x55, + YAHOO_SERVICE_AUTH = 0x57, + YAHOO_SERVICE_ADDBUDDY = 0x83, + YAHOO_SERVICE_REMBUDDY = 0x84, + YAHOO_SERVICE_IGNORECONTACT, /* > 1, 7, 13 < 1, 66, 13, 0*/ + YAHOO_SERVICE_REJECTCONTACT, + YAHOO_SERVICE_GROUPRENAME = 0x89, /* > 1, 65(new), 66(0), 67(old) */ + YAHOO_SERVICE_CHATONLINE = 0x96, /* > 109(id), 1, 6(abcde) < 0,1*/ + YAHOO_SERVICE_CHATGOTO, + YAHOO_SERVICE_CHATJOIN, /* > 1 104-room 129-1600326591 62-2 */ + YAHOO_SERVICE_CHATLEAVE, + YAHOO_SERVICE_CHATEXIT = 0x9b, + YAHOO_SERVICE_CHATADDINVITE = 0x9d, + YAHOO_SERVICE_CHATLOGOUT = 0xa0, + YAHOO_SERVICE_CHATPING, + YAHOO_SERVICE_COMMENT = 0xa8 +}; +enum yahoo_status { + YAHOO_STATUS_AVAILABLE = 0, + YAHOO_STATUS_BRB, + YAHOO_STATUS_BUSY, + YAHOO_STATUS_NOTATHOME, + YAHOO_STATUS_NOTATDESK, + YAHOO_STATUS_NOTINOFFICE, + YAHOO_STATUS_ONPHONE, + YAHOO_STATUS_ONVACATION, + YAHOO_STATUS_OUTTOLUNCH, + YAHOO_STATUS_STEPPEDOUT, + YAHOO_STATUS_INVISIBLE = 12, + YAHOO_STATUS_CUSTOM = 99, + YAHOO_STATUS_IDLE = 999, + YAHOO_STATUS_OFFLINE = 0x5a55aa56, /* don't ask */ + YAHOO_STATUS_TYPING = 0x16 +}; +#define YAHOO_STATUS_GAME 0x2 /* Games don't fit into the regular status model */ + +struct yahoo_data { + int fd; + guchar *rxqueue; + int rxlen; + GHashTable *hash; + GHashTable *games; + int current_status; + gboolean logged_in; + GSList *confs; + unsigned int conf_id; /* just a counter */ + gboolean chat_online; + gboolean in_chat; + char *chat_name; +}; + +struct yahoo_pair { + int key; + char *value; +}; + +struct yahoo_packet { + guint16 service; + guint32 status; + guint32 id; + GSList *hash; +}; + +struct yahoo_packet *yahoo_packet_new(enum yahoo_service service, enum yahoo_status status, int id); +void yahoo_packet_hash(struct yahoo_packet *pkt, int key, const char *value); +int yahoo_send_packet(struct yahoo_data *yd, struct yahoo_packet *pkt); +void yahoo_packet_free(struct yahoo_packet *pkt); + +/* util.c */ void yahoo_init_colorht(); void yahoo_dest_colorht(); char *yahoo_codes_to_html(const char *x); diff -r fa7359c3f93c -r 7b878ee8f064 src/protocols/yahoo/yahoochat.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/yahoo/yahoochat.c Wed Sep 03 12:45:17 2003 +0000 @@ -0,0 +1,855 @@ +/* + * gaim + * + * Some code copyright 2003 Tim Ringenbach + * (marv on irc.freenode.net) + * Some code borrowed from libyahoo2, copyright (C) 2002, Philip + * S Tellis + * + * 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 + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "debug.h" +#include "prpl.h" + +#include "conversation.h" +#include "notify.h" +#include "util.h" +#include "multi.h" +#include "internal.h" + +#include "yahoo.h" +#include "yahoochat.h" + +#define YAHOO_CHAT_ID (1) + +/* special function to log us on to the yahoo chat service */ +static void yahoo_chat_online(GaimConnection *gc) +{ + struct yahoo_data *yd = gc->proto_data; + struct yahoo_packet *pkt; + + + pkt = yahoo_packet_new(YAHOO_SERVICE_CHATONLINE, YAHOO_STATUS_AVAILABLE,0); + yahoo_packet_hash(pkt, 1, gaim_connection_get_display_name(gc)); + yahoo_packet_hash(pkt, 109, gaim_connection_get_display_name(gc)); + yahoo_packet_hash(pkt, 6, "abcde"); + + yahoo_send_packet(yd, pkt); + + yahoo_packet_free(pkt); +} + +static gint _mystrcmpwrapper(gconstpointer a, gconstpointer b) +{ + return strcmp(a, b); +} + +/* this is slow, and different from the gaim_* version in that it (hopefully) won't add a user twice */ +static void yahoo_chat_add_users(GaimChat *chat, GList *newusers) +{ + GList *users, *i, *j; + + users = gaim_chat_get_users(chat); + + for (i = newusers; i; i = i->next) { + j = g_list_find_custom(users, i->data, _mystrcmpwrapper); + if (j) + continue; + gaim_chat_add_user(chat, i->data, NULL); + } +} + +static void yahoo_chat_add_user(GaimChat *chat, const char *user, const char *reason) +{ + GList *users; + + users = gaim_chat_get_users(chat); + + if ((g_list_find_custom(users, user, _mystrcmpwrapper))) + return; + + gaim_chat_add_user(chat, user, reason); +} + +static GaimConversation *yahoo_find_conference(GaimConnection *gc, const char *name) +{ + struct yahoo_data *yd; + GSList *l; + + yd = gc->proto_data; + + for (l = yd->confs; l; l = l->next) { + GaimConversation *c = l->data; + if (!gaim_utf8_strcasecmp(gaim_conversation_get_name(c), name)) + return c; + } + return NULL; +} + + +void yahoo_process_conference_invite(GaimConnection *gc, struct yahoo_packet *pkt) +{ + GSList *l; + char *room = NULL; + char *who = NULL; + char *msg = NULL; + GString *members = NULL; + GHashTable *components; + + + if (pkt->status == 2) + return; /* XXX */ + + members = g_string_sized_new(512); + + for (l = pkt->hash; l; l = l->next) { + struct yahoo_pair *pair = l->data; + + switch (pair->key) { + case 1: /* us, but we already know who we are */ + break; + case 57: + room = pair->value; + break; + case 50: /* inviter */ + who = pair->value; + g_string_append_printf(members, "%s\n", who); + break; + case 52: /* members */ + g_string_append_printf(members, "%s\n", pair->value); + break; + case 58: + msg = pair->value; + break; + case 13: /* ? */ + break; + } + } + + if (!room) { + g_string_free(members, TRUE); + 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 (msg) + g_hash_table_replace(components, g_strdup("topic"), g_strdup(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)); + } + serv_got_chat_invite(gc, room, who, msg, components); + + g_string_free(members, TRUE); +} + +void yahoo_process_conference_decline(GaimConnection *gc, struct yahoo_packet *pkt) +{ + GSList *l; + char *room = NULL; + char *who = NULL; + char *msg = NULL; + + for (l = pkt->hash; l; l = l->next) { + struct yahoo_pair *pair = l->data; + + switch (pair->key) { + case 57: + room = pair->value; + break; + case 54: + who = pair->value; + break; + case 14: + msg = pair->value; + break; + } + } + + if (who && room) { + char *tmp; + + tmp = g_strdup_printf(_("%s declined your conference invitation to room \"%s\" because \"%s\"."), + who, room, msg?msg:""); + gaim_notify_info(gc, NULL, _("Invitation Rejected"), tmp); + g_free(tmp); + } +} + +void yahoo_process_conference_logon(GaimConnection *gc, struct yahoo_packet *pkt) +{ + GSList *l; + char *room = NULL; + char *who = NULL; + GaimConversation *c; + + for (l = pkt->hash; l; l = l->next) { + struct yahoo_pair *pair = l->data; + + switch (pair->key) { + case 57: + room = pair->value; + break; + case 53: + who = pair->value; + break; + } + } + + if (who && room) { + c = yahoo_find_conference(gc, room); + if (c) + yahoo_chat_add_user(GAIM_CHAT(c), who, NULL); + } +} + +void yahoo_process_conference_logoff(GaimConnection *gc, struct yahoo_packet *pkt) +{ + GSList *l; + char *room = NULL; + char *who = NULL; + GaimConversation *c; + + for (l = pkt->hash; l; l = l->next) { + struct yahoo_pair *pair = l->data; + + switch (pair->key) { + case 57: + room = pair->value; + break; + case 56: + who = pair->value; + break; + } + } + + if (who && room) { + c = yahoo_find_conference(gc, room); + if (c) + gaim_chat_remove_user(GAIM_CHAT(c), who, NULL); + } +} + +void yahoo_process_conference_message(GaimConnection *gc, struct yahoo_packet *pkt) +{ + GSList *l; + char *room = NULL; + char *who = NULL; + char *msg = NULL; + GaimConversation *c; + + for (l = pkt->hash; l; l = l->next) { + struct yahoo_pair *pair = l->data; + + switch (pair->key) { + case 57: + room = pair->value; + break; + case 3: + who = pair->value; + break; + case 14: + msg = pair->value; + break; + } + } + + if (room && who && msg) { + c = yahoo_find_conference(gc, room); + if (!c) + return; + msg = yahoo_codes_to_html(msg); + serv_got_chat_in(gc, gaim_chat_get_id(GAIM_CHAT(c)), who, 0, msg, time(NULL)); + g_free(msg); + } + +} + + +/* this is a comfirmation of yahoo_chat_online(); */ +void yahoo_process_chat_online(GaimConnection *gc, struct yahoo_packet *pkt) +{ + struct yahoo_data *yd = (struct yahoo_data *) gc->proto_data; + + if (pkt->status == 1) + yd->chat_online = 1; +} + +/* this is basicly the opposite of chat_online */ +void yahoo_process_chat_logout(GaimConnection *gc, struct yahoo_packet *pkt) +{ + struct yahoo_data *yd = (struct yahoo_data *) gc->proto_data; + + if (pkt->status == 1) + yd->chat_online = 0; +} + +void yahoo_process_chat_join(GaimConnection *gc, struct yahoo_packet *pkt) +{ + struct yahoo_data *yd = (struct yahoo_data *) gc->proto_data; + GaimConversation *c = NULL; + GSList *l; + GList *members = NULL; + char *room = NULL; + char *topic = NULL; + char *someid, *someotherid, *somebase64orhashosomething, *somenegativenumber; + + if (pkt->status == -1) { + gaim_notify_error(gc, NULL, _("Failed to join chat"), _("Maybe the room is full?")); + return; + } + + for (l = pkt->hash; l; l = l->next) { + struct yahoo_pair *pair = l->data; + + switch (pair->key) { + + case 104: + room = pair->value; + break; + case 105: + topic = pair->value; + break; + case 128: + someid = pair->value; + break; + case 108: /* number of joiners */ + break; + case 129: + someotherid = pair->value; + break; + case 130: + somebase64orhashosomething = pair->value; + break; + case 126: + somenegativenumber = pair->value; + break; + case 13: /* this is 1. maybe its the type of room? (normal, user created, private, etc?) */ + break; + case 61: /*this looks similiar to 130 */ + break; + + /* the previous section was just room info. this next section is + info about individual room members, (including us) */ + + case 109: /* the yahoo id */ + members = g_list_append(members, pair->value); + break; + case 110: /* age */ + break; + case 141: /* nickname */ + break; + case 142: /* location */ + break; + case 113: /* bitmask */ + break; + } + } + + if (!room) + return; + + if (yd->chat_name && gaim_utf8_strcasecmp(room, yd->chat_name)) + yahoo_c_leave(gc, YAHOO_CHAT_ID); + + c = gaim_find_chat(gc, YAHOO_CHAT_ID); + + if (!c) { + c = serv_got_joined_chat(gc, YAHOO_CHAT_ID, room); + if (topic) + gaim_chat_set_topic(GAIM_CHAT(c), NULL, topic); + yd->in_chat = 1; + yd->chat_name = g_strdup(room); + gaim_chat_add_users(GAIM_CHAT(c), members); + } else { + yahoo_chat_add_users(GAIM_CHAT(c), members); + } + + g_list_free(members); +} + +void yahoo_process_chat_exit(GaimConnection *gc, struct yahoo_packet *pkt) +{ + char *who = NULL; + GSList *l; + struct yahoo_data *yd; + + yd = gc->proto_data; + + for (l = pkt->hash; l; l = l->next) { + struct yahoo_pair *pair = l->data; + + if (pair->key == 109) + who = pair->value; + } + + + if (who) { + GaimConversation *c = gaim_find_chat(gc, YAHOO_CHAT_ID); + if (c) + gaim_chat_remove_user(GAIM_CHAT(c), who, NULL); + + } +} + +void yahoo_process_chat_message(GaimConnection *gc, struct yahoo_packet *pkt) +{ + char *room = NULL, *who = NULL, *msg = NULL; + int msgtype = 1; + GaimConversation *c = NULL; + GSList *l; + + for (l = pkt->hash; l; l = l->next) { + struct yahoo_pair *pair = l->data; + + switch (pair->key) { + + case 104: + room = pair->value; + break; + case 109: + who = pair->value; + break; + case 117: + msg = pair->value; + break; + case 124: + msgtype = strtol(pair->value, NULL, 10); + break; + } + } + + if (!who) + return; + + c = gaim_find_chat(gc, YAHOO_CHAT_ID); + if (!c) { + /* we still get messages after we part, funny that */ + return; + } + + if (!msg) { + gaim_debug(GAIM_DEBUG_MISC, "yahoo", "Got a message packet with no message.\nThis probably means something important, but we're ignoring it.\n"); + return; + } + msg = yahoo_codes_to_html(msg); + + if (msgtype == 2 || msgtype == 3) { + char *tmp; + tmp = g_strdup_printf("/me %s", msg); + g_free(msg); + msg = tmp; + } + + serv_got_chat_in(gc, YAHOO_CHAT_ID, who, 0, msg, time(NULL)); + g_free(msg); +} + +void yahoo_process_chat_addinvite(GaimConnection *gc, struct yahoo_packet *pkt) +{ + GSList *l; + char *room = NULL; + char *msg = NULL; + char *who = NULL; + + + for (l = pkt->hash; l; l = l->next) { + struct yahoo_pair *pair = l->data; + + switch (pair->key) { + case 104: + room = pair->value; + break; + case 129: /* room id? */ + break; + case 126: /* ??? */ + break; + case 117: + msg = pair->value; + break; + case 119: + who = pair->value; + break; + case 118: /* us */ + break; + } + } + + if (room && who) { + GHashTable *components; + + 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)); + serv_got_chat_invite(gc, room, who, msg, components); + } +} + +void yahoo_process_chat_goto(GaimConnection *gc, struct yahoo_packet *pkt) +{ + if (pkt->status == -1) + gaim_notify_error(gc, NULL, _("Failed to join buddy in chat"), + _("Maybe they're not in a chat?")); +} + + +/* + * Functions dealing with conferences + */ + +static void yahoo_conf_leave(struct yahoo_data *yd, const char *room, const char *dn, GList *who) +{ + struct yahoo_packet *pkt; + GList *w; + + + pkt = yahoo_packet_new(YAHOO_SERVICE_CONFLOGOFF, YAHOO_STATUS_AVAILABLE, 0); + + yahoo_packet_hash(pkt, 1, dn); + for (w = who; w; w = w->next) { + yahoo_packet_hash(pkt, 3, (char *)w->data); + } + + yahoo_packet_hash(pkt, 57, room); + + yahoo_send_packet(yd, pkt); + + yahoo_packet_free(pkt); +} + +static int yahoo_conf_send(struct yahoo_data *yd, const char *dn, const char *room, + GList *members, const char *what) +{ + struct yahoo_packet *pkt; + GList *who; + + pkt = yahoo_packet_new(YAHOO_SERVICE_CONFMSG, YAHOO_STATUS_AVAILABLE, 0); + + yahoo_packet_hash(pkt, 1, dn); + for (who = members; who; who = who->next) + yahoo_packet_hash(pkt, 53, (char *)who->data); + yahoo_packet_hash(pkt, 57, room); + yahoo_packet_hash(pkt, 14, what); + yahoo_packet_hash(pkt, 97, "1"); /* utf-8 */ + + yahoo_send_packet(yd, pkt); + + yahoo_packet_free(pkt); + + return 0; +} + +static void yahoo_conf_join(struct yahoo_data *yd, GaimConversation *c, const char *dn, const char *room, + const char *topic, const char *members) +{ + struct yahoo_packet *pkt; + char **memarr = NULL; + int i; + + if (members) + memarr = g_strsplit(members, "\n", 0); + + + pkt = yahoo_packet_new(YAHOO_SERVICE_CONFLOGON, YAHOO_STATUS_AVAILABLE, 0); + + yahoo_packet_hash(pkt, 1, dn); + yahoo_packet_hash(pkt, 3, dn); + yahoo_packet_hash(pkt, 57, room); + if (memarr) { + for(i = 0 ; memarr[i]; i++) { + if (!strcmp(memarr[i], "") || !strcmp(memarr[i], dn)) + continue; + yahoo_packet_hash(pkt, 3, memarr[i]); + gaim_chat_add_user(GAIM_CHAT(c), memarr[i], NULL); + } + } + yahoo_send_packet(yd, pkt); + + yahoo_packet_free(pkt); + + if (memarr) + g_strfreev(memarr); +} + +static void yahoo_conf_invite(struct yahoo_data *yd, GaimConversation *c, + const char *dn, const char *buddy, const char *room, const char *msg) +{ + struct yahoo_packet *pkt; + GList *members; + + members = gaim_chat_get_users(GAIM_CHAT(c)); + + pkt = yahoo_packet_new(YAHOO_SERVICE_CONFADDINVITE, YAHOO_STATUS_AVAILABLE, 0); + + yahoo_packet_hash(pkt, 1, dn); + yahoo_packet_hash(pkt, 51, buddy); + yahoo_packet_hash(pkt, 57, room); + yahoo_packet_hash(pkt, 58, msg?msg:""); + yahoo_packet_hash(pkt, 13, "0"); + for(; members; members = members->next) { + if (!strcmp(members->data, dn)) + continue; + yahoo_packet_hash(pkt, 52, (char *)members->data); + yahoo_packet_hash(pkt, 53, (char *)members->data); + } + yahoo_send_packet(yd, pkt); + + yahoo_packet_free(pkt); +} + +/* + * Functions dealing with chats + */ + +static void yahoo_chat_leave(struct yahoo_data *yd, const char *room, const char *dn) +{ + struct yahoo_packet *pkt; + + pkt = yahoo_packet_new(YAHOO_SERVICE_CHATEXIT, YAHOO_STATUS_AVAILABLE, 0); + + yahoo_packet_hash(pkt, 104, room); + yahoo_packet_hash(pkt, 109, dn); + yahoo_packet_hash(pkt, 108, "1"); + yahoo_packet_hash(pkt, 112, "0"); /* what does this one mean? */ + + yahoo_send_packet(yd, pkt); + + yahoo_packet_free(pkt); + + yd->in_chat = 0; + if (yd->chat_name) { + g_free(yd->chat_name); + yd->chat_name = NULL; + } + +} + +static int yahoo_chat_send(struct yahoo_data *yd, const char *dn, const char *room, const char *what) +{ + struct yahoo_packet *pkt; + const char *msg; + int me = 0; + + if (!g_ascii_strncasecmp(what, "/me ", 4)) { /* XXX fix this to ignore leading html */ + me = 1; + msg = what + 4; + } else + msg = what; + + pkt = yahoo_packet_new(YAHOO_SERVICE_COMMENT, YAHOO_STATUS_AVAILABLE, 0); + + yahoo_packet_hash(pkt, 1, dn); + yahoo_packet_hash(pkt, 104, room); + yahoo_packet_hash(pkt, 117, msg); + if (me) + yahoo_packet_hash(pkt, 124, "2"); + else + yahoo_packet_hash(pkt, 124, "1"); + /* fixme: what about /think? (124=3) */ + + yahoo_send_packet(yd, pkt); + yahoo_packet_free(pkt); + + return 0; +} + +static void yahoo_chat_join(struct yahoo_data *yd, const char *dn, const char *room, const char *topic) +{ + struct yahoo_packet *pkt; + + pkt = yahoo_packet_new(YAHOO_SERVICE_CHATJOIN, YAHOO_STATUS_AVAILABLE, 0); + + yahoo_packet_hash(pkt, 62, "2"); + yahoo_packet_hash(pkt, 104, room); + yahoo_packet_hash(pkt, 129, "0"); + + yahoo_send_packet(yd, pkt); + + yahoo_packet_free(pkt); +} + +static void yahoo_chat_invite(struct yahoo_data *yd, const char *dn, const char *buddy, + const char *room, const char *msg) +{ + struct yahoo_packet *pkt; + + pkt = yahoo_packet_new(YAHOO_SERVICE_CHATADDINVITE, YAHOO_STATUS_AVAILABLE, 0); + + yahoo_packet_hash(pkt, 1, dn); + yahoo_packet_hash(pkt, 118, buddy); + yahoo_packet_hash(pkt, 104, room); + yahoo_packet_hash(pkt, 117, (msg?msg:"")); + yahoo_packet_hash(pkt, 129, "0"); + + yahoo_send_packet(yd, pkt); + yahoo_packet_free(pkt); +} + +void yahoo_chat_goto(GaimConnection *gc, const char *name) +{ + struct yahoo_data *yd; + struct yahoo_packet *pkt; + + yd = gc->proto_data; + + if (!yd->chat_online) + yahoo_chat_online(gc); + + pkt = yahoo_packet_new(YAHOO_SERVICE_CHATGOTO, YAHOO_STATUS_AVAILABLE, 0); + + yahoo_packet_hash(pkt, 109, name); + yahoo_packet_hash(pkt, 1, gaim_connection_get_display_name(gc)); + yahoo_packet_hash(pkt, 62, "2"); + + yahoo_send_packet(yd, pkt); + yahoo_packet_free(pkt); +} +/* + * These are the functions registered with the core + * which get called for both chats and conferences. + */ + +void yahoo_c_leave(GaimConnection *gc, int id) +{ + struct yahoo_data *yd = (struct yahoo_data *) gc->proto_data; + GaimConversation *c; + + if (!yd) + return; + + + c = gaim_find_chat(gc, id); + if (!c) + return; + + if (id != YAHOO_CHAT_ID) { + yahoo_conf_leave(yd, gaim_conversation_get_name(c), + gaim_connection_get_display_name(gc), gaim_chat_get_users(GAIM_CHAT(c))); + yd->confs = g_slist_remove(yd->confs, c); + } else { + yahoo_chat_leave(yd, gaim_conversation_get_name(c), gaim_connection_get_display_name(gc)); + } + + serv_got_chat_left(gc, id); +} + +int yahoo_c_send(GaimConnection *gc, int id, const char *what) +{ + GaimConversation *c; + int ret; + struct yahoo_data *yd; + char *msg; + + yd = (struct yahoo_data *) gc->proto_data; + if (!yd) + return -1; + + c = gaim_find_chat(gc, id); + if (!c) + return -1; + + msg = yahoo_html_to_codes(what); + + if (id != YAHOO_CHAT_ID) { + ret = yahoo_conf_send(yd, gaim_connection_get_display_name(gc), + gaim_conversation_get_name(c), gaim_chat_get_users(GAIM_CHAT(c)), msg); + } else { + ret = yahoo_chat_send(yd, gaim_connection_get_display_name(gc), + gaim_conversation_get_name(c), msg); + if (!ret) + serv_got_chat_in(gc, gaim_chat_get_id(GAIM_CHAT(c)), + gaim_connection_get_display_name(gc), 0, what, time(NULL)); + } + + g_free(msg); + return ret; +} + +GList *yahoo_c_info(GaimConnection *gc) +{ + GList *m = NULL; + struct proto_chat_entry *pce; + + pce = g_new0(struct proto_chat_entry, 1); + pce->label = _("Room:"); + pce->identifier = "room"; + m = g_list_append(m, pce); + + return m; +} + +void yahoo_c_join(GaimConnection *gc, GHashTable *data) +{ + struct yahoo_data *yd; + char *room, *topic, *members, *type; + int id; + GaimConversation *c; + + yd = (struct yahoo_data *) gc->proto_data; + if (!yd) + return; + + room = g_hash_table_lookup(data, "room"); + if (!room) + return; + + topic = g_hash_table_lookup(data, "topic"); + if (!topic) + topic = ""; + + members = g_hash_table_lookup(data, "members"); + + + if ((type = g_hash_table_lookup(data, "type")) && !strcmp(type, "Conference")) { + id = yd->conf_id++; + c = serv_got_joined_chat(gc, id, room); + yd->confs = g_slist_prepend(yd->confs, c); + gaim_chat_set_topic(GAIM_CHAT(c), gaim_connection_get_display_name(gc), topic); + yahoo_conf_join(yd, c, gaim_connection_get_display_name(gc), room, topic, members); + return; + } else { + if (yd->in_chat) + yahoo_c_leave(gc, YAHOO_CHAT_ID); + if (!yd->chat_online) + yahoo_chat_online(gc); + yahoo_chat_join(yd, gaim_connection_get_display_name(gc), room, topic); + return; + } +} + +void yahoo_c_invite(GaimConnection *gc, int id, const char *msg, const char *name) +{ + struct yahoo_data *yd = (struct yahoo_data *) gc->proto_data; + GaimConversation *c; + + c = gaim_find_chat(gc, id); + if (!c || !c->name) + return; + + if (id != YAHOO_CHAT_ID) { + yahoo_conf_invite(yd, c, gaim_connection_get_display_name(gc), name, + gaim_conversation_get_name(c), msg); + } else { + yahoo_chat_invite(yd, gaim_connection_get_display_name(gc), name, + gaim_conversation_get_name(c), msg); + } +} + diff -r fa7359c3f93c -r 7b878ee8f064 src/protocols/yahoo/yahoochat.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/yahoo/yahoochat.h Wed Sep 03 12:45:17 2003 +0000 @@ -0,0 +1,48 @@ +/** + * @file yahoochat.h The Yahoo! protocol plugin, chat and conference stuff + * + * gaim + * + * Copyright (C) 2003 + * + * 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 + */ + +#ifndef _YAHOOCHAT_H_ +#define _YAHOOCHAT_H_ + +void yahoo_process_conference_invite(GaimConnection *gc, struct yahoo_packet *pkt); +void yahoo_process_conference_decline(GaimConnection *gc, struct yahoo_packet *pkt); +void yahoo_process_conference_logon(GaimConnection *gc, struct yahoo_packet *pkt); +void yahoo_process_conference_logoff(GaimConnection *gc, struct yahoo_packet *pkt); +void yahoo_process_conference_message(GaimConnection *gc, struct yahoo_packet *pkt); + +void yahoo_process_chat_online(GaimConnection *gc, struct yahoo_packet *pkt); +void yahoo_process_chat_logout(GaimConnection *gc, struct yahoo_packet *pkt); +void yahoo_process_chat_join(GaimConnection *gc, struct yahoo_packet *pkt); +void yahoo_process_chat_exit(GaimConnection *gc, struct yahoo_packet *pkt); +void yahoo_process_chat_message(GaimConnection *gc, struct yahoo_packet *pkt); +void yahoo_process_chat_addinvite(GaimConnection *gc, struct yahoo_packet *pkt); +void yahoo_process_chat_goto(GaimConnection *gc, struct yahoo_packet *pkt); + +void yahoo_c_leave(GaimConnection *gc, int id); +int yahoo_c_send(GaimConnection *gc, int id, const char *what); +GList *yahoo_c_info(GaimConnection *gc); +void yahoo_c_join(GaimConnection *gc, GHashTable *data); +void yahoo_c_invite(GaimConnection *gc, int id, const char *msg, const char *name); + +void yahoo_chat_goto(GaimConnection *gc, const char *name); + +#endif /* _YAHOO_CHAT_H_ */