* Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * Component written by Tomek Wasilczyk (http://www.wasilczyk.pl). * This file is dual-licensed under the GPL2+ and the X11 (MIT) licences. * As a recipient of this file you may choose, which license to receive the * code under. As a contributor, you have to ensure the new code is * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA #include "message-prpl.h" typedef struct _ggp_chat_local_info ggp_chat_local_info; struct _ggp_chat_session_data ggp_chat_local_info *chats; gboolean got_all_chats_info; struct _ggp_chat_local_info PurpleChatConversation *conv; gboolean previously_joined; static ggp_chat_local_info * ggp_chat_new(PurpleConnection *gc, uint64_t id); static ggp_chat_local_info * ggp_chat_get(PurpleConnection *gc, uint64_t id); static void ggp_chat_open_conv(ggp_chat_local_info *chat); static ggp_chat_local_info * ggp_chat_get_local(PurpleConnection *gc, static void ggp_chat_joined(ggp_chat_local_info *chat, uin_t uin); static void ggp_chat_left(ggp_chat_local_info *chat, uin_t uin); static const gchar * ggp_chat_get_name_from_id(uint64_t id); static uint64_t ggp_chat_get_id_from_name(const gchar * name); static void ggp_chat_join_id(PurpleConnection *gc, uint64_t id); static inline ggp_chat_session_data * ggp_chat_get_sdata(PurpleConnection *gc) GGPInfo *accdata = purple_connection_get_protocol_data(gc); return accdata->chat_data; void ggp_chat_setup(PurpleConnection *gc) GGPInfo *accdata = purple_connection_get_protocol_data(gc); ggp_chat_session_data *sdata = g_new0(ggp_chat_session_data, 1); accdata->chat_data = sdata; void ggp_chat_cleanup(PurpleConnection *gc) ggp_chat_session_data *sdata = ggp_chat_get_sdata(gc); g_slist_free_full(sdata->pending_joins, g_free); for (i = 0; i < sdata->chats_count; i++) g_free(sdata->chats[i].participants); static ggp_chat_local_info * ggp_chat_new(PurpleConnection *gc, uint64_t id) ggp_chat_session_data *sdata = ggp_chat_get_sdata(gc); ggp_chat_local_info *chat; if (NULL != (chat = ggp_chat_get(gc, id))) local_id = sdata->chats_count++; sdata->chats = g_realloc(sdata->chats, sdata->chats_count * sizeof(ggp_chat_local_info)); chat = &sdata->chats[local_id]; chat->local_id = local_id; chat->previously_joined = FALSE; chat->participants = NULL; chat->participants_count = 0; static ggp_chat_local_info * ggp_chat_get(PurpleConnection *gc, uint64_t id) ggp_chat_session_data *sdata = ggp_chat_get_sdata(gc); for (i = 0; i < sdata->chats_count; i++) { if (sdata->chats[i].id == id) static void ggp_chat_open_conv(ggp_chat_local_info *chat) chat->conv = purple_serv_got_joined_chat(chat->gc, chat->local_id, ggp_chat_get_name_from_id(chat->id)); if (chat->previously_joined) { purple_conversation_write_system_message( PURPLE_CONVERSATION(chat->conv), _("You have re-joined the chat"), 0); chat->previously_joined = TRUE; purple_chat_conversation_clear_users(chat->conv); for (i = 0; i < chat->participants_count; i++) { purple_chat_conversation_add_user(chat->conv, ggp_uin_to_str(chat->participants[i]), NULL, PURPLE_CHAT_USER_NONE, FALSE); static ggp_chat_local_info * ggp_chat_get_local(PurpleConnection *gc, ggp_chat_session_data *sdata = ggp_chat_get_sdata(gc); for (i = 0; i < sdata->chats_count; i++) { if (sdata->chats[i].local_id == local_id) void ggp_chat_got_event(PurpleConnection *gc, const struct gg_event *ev) ggp_chat_session_data *sdata = ggp_chat_get_sdata(gc); ggp_chat_local_info *chat; if (ev->type == GG_EVENT_CHAT_INFO) { const struct gg_event_chat_info *eci = &ev->event.chat_info; chat = ggp_chat_new(gc, eci->id); for (i = 0; i < eci->participants_count; i++) ggp_chat_joined(chat, eci->participants[i]); } else if (ev->type == GG_EVENT_CHAT_INFO_GOT_ALL) { GSList *it = sdata->pending_joins; sdata->got_all_chats_info = TRUE; uint64_t *id_p = it->data; ggp_chat_join_id(gc, *id_p); g_slist_free_full(sdata->pending_joins, g_free); sdata->pending_joins = NULL; } else if (ev->type == GG_EVENT_CHAT_INFO_UPDATE) { const struct gg_event_chat_info_update *eciu = &ev->event.chat_info_update; chat = ggp_chat_get(gc, eciu->id); purple_debug_error("gg", "ggp_chat_got_event: " "chat %" G_GUINT64_FORMAT " not found\n", if (eciu->type == GG_CHAT_INFO_UPDATE_ENTERED) ggp_chat_joined(chat, eciu->participant); else if (eciu->type == GG_CHAT_INFO_UPDATE_EXITED) ggp_chat_left(chat, eciu->participant); purple_debug_warning("gg", "ggp_chat_got_event: " "unknown update type - %d", eciu->type); } else if (ev->type == GG_EVENT_CHAT_CREATED) { const struct gg_event_chat_created *ecc = uin_t me = ggp_str_to_uin(purple_account_get_username( purple_connection_get_account(gc))); chat = ggp_chat_new(gc, ecc->id); ggp_chat_joined(chat, me); ggp_chat_open_conv(chat); } else if (ev->type == GG_EVENT_CHAT_INVITE_ACK) { purple_debug_fatal("gg", "ggp_chat_got_event: unexpected event " static int ggp_chat_participant_find(ggp_chat_local_info *chat, uin_t uin) for (i = 0; i < chat->participants_count; i++) if (chat->participants[i] == uin) static void ggp_chat_joined(ggp_chat_local_info *chat, uin_t uin) int idx = ggp_chat_participant_find(chat, uin); purple_debug_warning("gg", "ggp_chat_joined: " "user %u is already present in chat %" G_GUINT64_FORMAT chat->participants_count++; chat->participants = g_realloc(chat->participants, sizeof(uin) * chat->participants_count); chat->participants[chat->participants_count - 1] = uin; purple_chat_conversation_add_user(chat->conv, ggp_uin_to_str(uin), NULL, PURPLE_CHAT_USER_NONE, TRUE); static void ggp_chat_left(ggp_chat_local_info *chat, uin_t uin) int idx = ggp_chat_participant_find(chat, uin); purple_debug_warning("gg", "ggp_chat_joined: " "user %u isn't present in chat %" G_GUINT64_FORMAT "\n", chat->participants[idx] = chat->participants[chat->participants_count - 1]; chat->participants_count--; chat->participants = g_realloc(chat->participants, sizeof(uin) * chat->participants_count); me = ggp_str_to_uin(purple_account_get_username( purple_connection_get_account(chat->gc))); purple_conversation_write_system_message( PURPLE_CONVERSATION(chat->conv), _("You have left the chat"), 0); purple_serv_got_chat_left(chat->gc, chat->local_id); purple_chat_conversation_remove_user(chat->conv, ggp_uin_to_str(uin), NULL); GList * ggp_chat_info(PurpleConnection *gc) PurpleProtocolChatEntry *pce; pce = g_new0(PurpleProtocolChatEntry, 1); pce->label = _("_Conference identifier:"); m = g_list_append(m, pce); GHashTable * ggp_chat_info_defaults(PurpleConnection *gc, const char *chat_name) defaults = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free); if (chat_name != NULL && ggp_chat_get_id_from_name(chat_name) != 0) g_hash_table_insert(defaults, "id", g_strdup(chat_name)); char * ggp_chat_get_name(GHashTable *components) return g_strdup((gchar*)g_hash_table_lookup(components, "id")); static const gchar * ggp_chat_get_name_from_id(uint64_t id) g_snprintf(buff, sizeof(buff), "%" G_GUINT64_FORMAT, id); static uint64_t ggp_chat_get_id_from_name(const gchar * name) id = g_ascii_strtoull(name, &endptr, 10); if (*endptr != '\0' || id == G_MAXUINT64) void ggp_chat_join(PurpleConnection *gc, GHashTable *components) ggp_chat_session_data *sdata = ggp_chat_get_sdata(gc); GGPInfo *info = purple_connection_get_protocol_data(gc); id_cs = g_hash_table_lookup(components, "id"); if (id_s == NULL || id_s[0] == '\0') { if (gg_chat_create(info->session) < 0) { purple_debug_error("gg", "ggp_chat_join; " purple_serv_got_join_chat_failed(gc, components); id = ggp_chat_get_id_from_name(id_s); char *buff = g_strdup_printf( _("%s is not a valid room identifier"), id_cs); purple_notify_error(gc, _("Invalid Room Identifier"), _("Invalid Room Identifier"), buff, NULL); purple_serv_got_join_chat_failed(gc, components); if (sdata->got_all_chats_info) ggp_chat_join_id(gc, id); uint64_t *id_p = g_new(uint64_t, 1); sdata->pending_joins = g_slist_append(sdata->pending_joins, id_p); static void ggp_chat_join_id(PurpleConnection *gc, uint64_t id) ggp_chat_local_info *chat = ggp_chat_get(gc, id); if (chat && !chat->left) { ggp_chat_open_conv(chat); char *id_s = g_strdup_printf("%" G_GUINT64_FORMAT, id); char *buff = g_strdup_printf( _("%s is not a valid room identifier"), id_s); purple_notify_error(gc, _("Invalid Room Identifier"), _("Invalid Room Identifier"), buff, NULL); } else { /* if (chat->left) */ purple_notify_error(gc, _("Could not join chat room"), _("Could not join chat room"), _("You have to ask for invitation from another chat " components = ggp_chat_info_defaults(gc, ggp_chat_get_name_from_id(id)); purple_serv_got_join_chat_failed(gc, components); g_hash_table_destroy(components); void ggp_chat_leave(PurpleConnection *gc, int local_id) GGPInfo *info = purple_connection_get_protocol_data(gc); ggp_chat_local_info *chat; chat = ggp_chat_get_local(gc, local_id); purple_debug_error("gg", "ggp_chat_leave: " "chat %u doesn't exists\n", local_id); if (gg_chat_leave(info->session, chat->id) < 0) { purple_debug_error("gg", "ggp_chat_leave: " "unable to leave chat %" G_GUINT64_FORMAT "\n", me = ggp_str_to_uin(purple_account_get_username( purple_connection_get_account(chat->gc))); void ggp_chat_invite(PurpleConnection *gc, int local_id, const char *message, GGPInfo *info = purple_connection_get_protocol_data(gc); ggp_chat_local_info *chat; chat = ggp_chat_get_local(gc, local_id); purple_debug_error("gg", "ggp_chat_invite: " "chat %u doesn't exists\n", local_id); invited = ggp_str_to_uin(who); if (gg_chat_invite(info->session, chat->id, &invited, 1) < 0) { purple_debug_error("gg", "ggp_chat_invite: " "unable to invite %s to chat %" G_GUINT64_FORMAT "\n", int ggp_chat_send(PurpleConnection *gc, int local_id, PurpleMessage *msg) GGPInfo *info = purple_connection_get_protocol_data(gc); PurpleChatConversation *conv; ggp_chat_local_info *chat; chat = ggp_chat_get_local(gc, local_id); purple_debug_error("gg", "ggp_chat_send: " "chat %u doesn't exists\n", local_id); conv = purple_conversations_find_chat_with_account( ggp_chat_get_name_from_id(chat->id), purple_connection_get_account(gc)); gg_msg = ggp_message_format_to_gg(PURPLE_CONVERSATION(conv), purple_message_get_contents(msg)); if (gg_chat_send_message(info->session, chat->id, gg_msg, TRUE) < 0) me = purple_account_get_username(purple_connection_get_account(gc)); purple_serv_got_chat_in(gc, chat->local_id, me, purple_message_get_flags(msg), purple_message_get_contents(msg), purple_message_get_time(msg)); void ggp_chat_got_message(PurpleConnection *gc, uint64_t chat_id, const char *message, time_t time, uin_t who) ggp_chat_local_info *chat; me = ggp_str_to_uin(purple_account_get_username( purple_connection_get_account(gc))); chat = ggp_chat_get(gc, chat_id); purple_debug_error("gg", "ggp_chat_got_message: " "chat %" G_GUINT64_FORMAT " doesn't exists\n", chat_id); ggp_chat_open_conv(chat); pmsg = purple_message_new_outgoing( ggp_uin_to_str(who), message, 0); purple_message_set_time(pmsg, time); purple_conversation_write_message( PURPLE_CONVERSATION(chat->conv), pmsg); purple_serv_got_chat_in(gc, chat->local_id, ggp_uin_to_str(who), PURPLE_MESSAGE_RECV, message, time); static gboolean ggp_chat_roomlist_get_list_finish(gpointer roomlist) purple_roomlist_set_in_progress(PURPLE_ROOMLIST(roomlist), FALSE); g_object_unref(roomlist); PurpleRoomlist * ggp_chat_roomlist_get_list(PurpleConnection *gc) ggp_chat_session_data *sdata = ggp_chat_get_sdata(gc); PurpleRoomlist *roomlist; purple_debug_info("gg", "ggp_chat_roomlist_get_list\n"); roomlist = purple_roomlist_new(purple_connection_get_account(gc)); fields = g_list_append(fields, purple_roomlist_field_new( PURPLE_ROOMLIST_FIELD_STRING, _("Conference identifier"), "id", fields = g_list_append(fields, purple_roomlist_field_new( PURPLE_ROOMLIST_FIELD_STRING, _("Start Date"), "date", fields = g_list_append(fields, purple_roomlist_field_new( PURPLE_ROOMLIST_FIELD_INT, _("User Count"), "users", fields = g_list_append(fields, purple_roomlist_field_new( PURPLE_ROOMLIST_FIELD_STRING, _("Status"), "status", purple_roomlist_set_fields(roomlist, fields); for (i = sdata->chats_count - 1; i >= 0 ; i--) { PurpleRoomlistRoom *room; ggp_chat_local_info *chat = &sdata->chats[i]; int count = chat->participants_count; date = (uint32_t)(chat->id >> 32); /* Translators: For Gadu-Gadu, this is one possible status for a chat room. It means you had previously joined the chat room but you have since left it. You cannot rejoin without another status = _("Can join chat"); name = ggp_chat_get_name_from_id(chat->id); room = purple_roomlist_room_new(PURPLE_ROOMLIST_ROOMTYPE_ROOM, purple_roomlist_room_add_field(roomlist, room, name); purple_roomlist_room_add_field(roomlist, room, purple_date_format_full(localtime(&date))); purple_roomlist_room_add_field(roomlist, room, GINT_TO_POINTER(count)); purple_roomlist_room_add_field(roomlist, room, status); purple_roomlist_room_add(roomlist, room); * purple_roomlist_set_in_progress(roomlist, FALSE); g_timeout_add(1, ggp_chat_roomlist_get_list_finish, roomlist);