pidgin/pidgin

Merge to default to fix conflicts

2016-10-24, Mike Ruprecht
6dc8cae57962
Merge to default to fix conflicts
/*
* MXit Protocol libPurple Plugin
*
* -- MultiMx GroupChat --
*
* Andrew Victor <libpurple@mxit.com>
*
* (C) Copyright 2009 MXit Lifestyle (Pty) Ltd.
* <http://www.mxitlifestyle.com>
*
* 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 "internal.h"
#include "debug.h"
#include "client.h"
#include "mxit.h"
#include "multimx.h"
#include "markup.h"
#if 0
static void multimx_dump(struct multimx* multimx)
{
purple_debug_info(MXIT_PLUGIN_ID, "MultiMX:\n");
purple_debug_info(MXIT_PLUGIN_ID, " Chat ID: %i\n", multimx->chatid);
purple_debug_info(MXIT_PLUGIN_ID, " Username: %s\n", multimx->roomid);
purple_debug_info(MXIT_PLUGIN_ID, " Alias: %s\n", multimx->roomname);
purple_debug_info(MXIT_PLUGIN_ID, " State: %i\n", multimx->state);
}
#endif
/*------------------------------------------------------------------------
* Find a MultiMx session based on libpurple chatID.
*
* @param session The MXit session object
* @param id The libpurple group-chat ID
* @return The MultiMX room object (or NULL if not found)
*/
static struct multimx* find_room_by_id(struct MXitSession* session, int id)
{
GList* x = session->rooms;
while (x != NULL) {
struct multimx* multimx = (struct multimx *) x->data;
if (multimx->chatid == id)
return multimx;
x = g_list_next(x);
}
return NULL;
}
/*------------------------------------------------------------------------
* Find a MultiMx session based on Alias
*
* @param session The MXit session object
* @param roomname The UI room-name
* @return The MultiMX room object (or NULL if not found)
*/
static struct multimx* find_room_by_alias(struct MXitSession* session, const char* roomname)
{
GList* x = session->rooms;
while (x != NULL) {
struct multimx* multimx = (struct multimx *) x->data;
if (!strcmp(multimx->roomname, roomname))
return multimx;
x = g_list_next(x);
}
return NULL;
}
/*------------------------------------------------------------------------
* Find a MultiMx session based on Username (MXit RoomId)
*
* @param session The MXit session object
* @param username The MXit RoomID (MultiMX contact username)
* @return The MultiMX room object (or NULL if not found)
*/
static struct multimx* find_room_by_username(struct MXitSession* session, const char* username)
{
GList* x = session->rooms;
while (x != NULL) {
struct multimx* multimx = (struct multimx *) x->data;
if (!strcmp(multimx->roomid, username))
return multimx;
x = g_list_next(x);
}
return NULL;
}
/*------------------------------------------------------------------------
* Create a GroupChat room, and add to list of rooms.
*
* @param session The MXit session object
* @param roomid The MXit RoomID (MultiMX contact username)
* @param roomname The UI room-name
* @param state The initial state of the room (see multimx.h)
* @return The MultiMX room object
*/
static struct multimx* room_create(struct MXitSession* session, const char* roomid, const char* roomname, short state)
{
struct multimx* multimx = NULL;
static int groupchatID = 1;
purple_debug_info(MXIT_PLUGIN_ID, "Groupchat create - roomid='%s' roomname='%s'\n", roomid, roomname);
/* Create a new GroupChat */
multimx = g_new0(struct multimx, 1);
/* Initialize groupchat */
g_strlcpy(multimx->roomid, roomid, sizeof(multimx->roomid));
g_strlcpy(multimx->roomname, roomname, sizeof(multimx->roomname));
multimx->chatid = groupchatID++;
multimx->state = state;
/* determine our nickname (from profile) */
if (session->profile && (session->profile->nickname[0] != '\0'))
multimx->nickname = g_strdup(session->profile->nickname);
/* Add to GroupChat list */
session->rooms = g_list_append(session->rooms, multimx);
return multimx;
}
/*------------------------------------------------------------------------
* Free the Groupchat room.
*
* @param session The MXit session object
* @param multimx The MultiMX room object to deallocate
*/
static void room_remove(struct MXitSession* session, struct multimx* multimx)
{
/* Remove from GroupChat list */
session->rooms = g_list_remove(session->rooms, multimx);
/* free nickname */
g_free(multimx->nickname);
/* Deallocate it */
g_free (multimx);
multimx = NULL;
}
/*------------------------------------------------------------------------
* Another user has join the GroupChat, add them to the member-list.
*
* @param convo The Conversation object
* @param nickname The nickname of the user who joined the room
*/
static void member_added(PurpleChatConversation* chat, const char* nickname)
{
purple_debug_info(MXIT_PLUGIN_ID, "member_added: '%s'\n", nickname);
purple_chat_conversation_add_user(chat, nickname, NULL, PURPLE_CHAT_USER_NONE, TRUE);
}
/*------------------------------------------------------------------------
* Another user has left the GroupChat, remove them from the member-list.
*
* @param convo The Conversation object
* @param nickname The nickname of the user who left the room
*/
static void member_removed(PurpleChatConversation* chat, const char* nickname)
{
purple_debug_info(MXIT_PLUGIN_ID, "member_removed: '%s'\n", nickname);
purple_chat_conversation_remove_user(chat, nickname, NULL);
}
/*------------------------------------------------------------------------
* A user was kicked from the GroupChat, remove them from the member-list.
*
* @param convo The Conversation object
* @param nickname The nickname of the user who was kicked
*/
static void member_kicked(PurpleChatConversation* chat, const char* nickname)
{
purple_debug_info(MXIT_PLUGIN_ID, "member_kicked: '%s'\n", nickname);
purple_chat_conversation_remove_user(chat, nickname, _("was kicked"));
}
/*------------------------------------------------------------------------
* You were kicked from the GroupChat.
*
* @param convo The Conversation object
* @param session The MXit session object
* @param multimx The MultiMX room object
*/
static void you_kicked(PurpleChatConversation* chat, struct MXitSession* session, struct multimx* multimx)
{
purple_debug_info(MXIT_PLUGIN_ID, "you_kicked\n");
purple_conversation_write_system_message(PURPLE_CONVERSATION(chat),
_("You have been kicked from this MultiMX."), 0);
purple_chat_conversation_clear_users(chat);
purple_serv_got_chat_left(session->con, multimx->chatid);
}
/*------------------------------------------------------------------------
* Update the full GroupChat member list.
*
* @param convo The Conversation object
* @param data The nicknames of the users in the room (separated by \n)
*/
static void member_update(PurpleChatConversation* chat, char* data)
{
gchar** userlist;
int i = 0;
purple_debug_info(MXIT_PLUGIN_ID, "member_update: '%s'\n", data);
/* Clear list */
purple_chat_conversation_clear_users(chat);
/* Add each member */
data = g_strstrip(data); /* string leading & trailing whitespace */
userlist = g_strsplit(data, "\n", 0); /* tokenize string */
while (userlist[i] != NULL) {
purple_debug_info(MXIT_PLUGIN_ID, "member_update - adding: '%s'\n", userlist[i]);
purple_chat_conversation_add_user(chat, userlist[i], NULL, PURPLE_CHAT_USER_NONE, FALSE);
i++;
}
g_strfreev(userlist);
}
/* -------------------------------------------------------------------------------------------------
* Calls from MXit Protocol layer
* ------------------------------------------------------------------------------------------------- */
/*------------------------------------------------------------------------
* Received a Subscription Request to a MultiMX room.
*
* @param session The MXit session object
* @param contact The invited MultiMX room's contact information
* @param creator The nickname of the room's creator / invitor
*/
void multimx_invite(struct MXitSession* session, struct contact* contact, const char* creator)
{
GHashTable *components;
purple_debug_info(MXIT_PLUGIN_ID, "Groupchat invite to '%s' (roomid='%s') by '%s'\n", contact->alias, contact->username, creator);
/* Check if the room already exists (ie, already joined or invite pending) */
if (find_room_by_username(session, contact->username) != NULL)
return;
/* Create a new room */
room_create(session, contact->username, contact->alias, STATE_INVITED);
components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
g_hash_table_insert(components, g_strdup("room"), g_strdup(contact->alias));
/* Call libpurple - will trigger either 'mxit_chat_join' or 'mxit_chat_reject' */
purple_serv_got_chat_invite(session->con, contact->alias, creator, NULL, components);
}
/*------------------------------------------------------------------------
* MultiMX room has been added to the roster.
*
* @param session The MXit session object
* @param contact The MultiMX room's contact information
*/
void multimx_created(struct MXitSession* session, struct contact* contact)
{
PurpleConnection *gc = session->con;
struct multimx* multimx = NULL;
purple_debug_info(MXIT_PLUGIN_ID, "Groupchat '%s' created as '%s'\n", contact->alias, contact->username);
/* Find matching MultiMX group */
multimx = find_room_by_username(session, contact->username);
if (multimx == NULL) {
multimx = room_create(session, contact->username, contact->alias, TRUE);
}
else if (multimx->state == STATE_INVITED) {
/* After successfully accepting an invitation */
multimx->state = STATE_JOINED;
}
/* Call libpurple - will trigger 'mxit_chat_join' */
purple_serv_got_joined_chat(gc, multimx->chatid, multimx->roomname);
/* Send ".list" command to GroupChat server to retrieve current member-list */
mxit_send_message(session, multimx->roomid, ".list", FALSE, FALSE);
}
/*------------------------------------------------------------------------
* Is this username a MultiMX contact?
*
* @param session The MXit session object
* @param username The username of the contact
* @return TRUE if this contacts matches the RoomID of a MultiMX room.
*/
gboolean is_multimx_contact(struct MXitSession* session, const char* username)
{
/* Check for username in list of open rooms */
return (find_room_by_username(session, username) != NULL);
}
/*------------------------------------------------------------------------
* Received a message from a MultiMX room.
*
*/
void multimx_message_received(struct RXMsgData* mx, char* msg, int msglen, short msgtype, int msgflags)
{
struct multimx* multimx = NULL;
purple_debug_info(MXIT_PLUGIN_ID, "Groupchat message received: %s\n", msg);
/* Find matching multimx group */
multimx = find_room_by_username(mx->session, mx->from);
if (multimx == NULL) {
purple_debug_error(MXIT_PLUGIN_ID, "Groupchat '%s' not found\n", mx->from);
return;
}
/* Determine if system message or a message from a contact */
if (msg[0] == '<') {
/* Message contains embedded nickname - must be from contact */
unsigned int i;
for (i = 1; i < strlen(msg); i++) { /* search for end of nickname */
if ((msg[i] == '>') && (msg[i+1] == '\n')) {
msg[i] = '\0';
g_free(mx->from);
mx->from = g_strdup(&msg[1]);
msg = &msg[i+2]; /* skip '>' and newline */
break;
}
}
/* now do markup processing on the message */
mx->chatid = multimx->chatid;
mxit_parse_markup(mx, msg, strlen(msg), msgtype, msgflags);
}
else {
/* Must be a service message */
char* ofs;
PurpleChatConversation* chat = purple_conversations_find_chat_with_account(multimx->roomname, mx->session->acc);
if (chat == NULL) {
purple_debug_error(MXIT_PLUGIN_ID, "Conversation '%s' not found\n", multimx->roomname);
return;
}
/* Determine if somebody has joined or left - update member-list */
if ((ofs = strstr(msg, " has joined")) != NULL) {
/* Somebody has joined */
*ofs = '\0';
member_added(chat, msg);
mx->processed = TRUE;
}
else if ((ofs = strstr(msg, " has left")) != NULL) {
/* Somebody has left */
*ofs = '\0';
member_removed(chat, msg);
mx->processed = TRUE;
}
else if ((ofs = strstr(msg, " has been kicked")) != NULL) {
/* Somebody has been kicked */
*ofs = '\0';
member_kicked(chat, msg);
mx->processed = TRUE;
}
else if (strcmp(msg, "You have been kicked.") == 0) {
/* You have been kicked */
you_kicked(chat, mx->session, multimx);
mx->processed = TRUE;
}
else if (g_str_has_prefix(msg, "The following users are in this MultiMx:") == TRUE) {
member_update(chat, msg + strlen("The following users are in this MultiMx:") + 1);
mx->processed = TRUE;
}
else {
/* Display server message in chat window */
purple_serv_got_chat_in(mx->session->con, multimx->chatid, "MXit", PURPLE_MESSAGE_SYSTEM, msg, mx->timestamp);
mx->processed = TRUE;
}
}
}
/* -------------------------------------------------------------------------------------------------
* Callbacks from libpurple
* ------------------------------------------------------------------------------------------------- */
/*------------------------------------------------------------------------
* User has selected "Add Chat" from the main menu.
*
* @param gc The connection object
* @return A list of chat configuration values
*/
GList* mxit_chat_info(PurpleConnection *gc)
{
GList *m = NULL;
PurpleProtocolChatEntry *pce;
/* Configuration option: Room Name */
pce = g_new0(PurpleProtocolChatEntry, 1);
pce->label = _( "_Room Name:" );
pce->identifier = "room";
pce->required = TRUE;
m = g_list_append(m, pce);
return m;
}
/*------------------------------------------------------------------------
* User has joined a chatroom, either because they are creating it or they
* accepted an invite.
*
* @param gc The connection object
* @param components The list of chat configuration values
*/
void mxit_chat_join(PurpleConnection *gc, GHashTable *components)
{
struct MXitSession* session = purple_connection_get_protocol_data(gc);
const char* roomname = NULL;
struct multimx* multimx = NULL;
purple_debug_info(MXIT_PLUGIN_ID, "mxit_chat_join\n");
/* Determine if groupchat already exists */
roomname = g_hash_table_lookup(components, "room");
multimx = find_room_by_alias(session, roomname);
if (multimx != NULL) {
/* The room information already exists */
if (multimx->state == STATE_INVITED) {
/* Invite is pending */
purple_debug_info(MXIT_PLUGIN_ID, "Groupchat %i accept sent\n", multimx->chatid);
/* Send Subscription Accept to MXit */
mxit_send_allow_sub(session, multimx->roomid, multimx->roomname);
}
else {
/* Join existing room */
purple_debug_info(MXIT_PLUGIN_ID, "Groupchat %i rejoined\n", multimx->chatid);
purple_serv_got_joined_chat(gc, multimx->chatid, multimx->roomname);
}
}
else {
/* Send Groupchat Create to MXit */
mxit_send_groupchat_create(session, roomname, 0, NULL);
}
}
/*------------------------------------------------------------------------
* User has rejected an invite to join a MultiMX room.
*
* @param gc The connection object
* @param components The list of chat configuration values
*/
void mxit_chat_reject(PurpleConnection *gc, GHashTable* components)
{
struct MXitSession* session = purple_connection_get_protocol_data(gc);
const char* roomname = NULL;
struct multimx* multimx = NULL;
purple_debug_info(MXIT_PLUGIN_ID, "mxit_chat_reject\n");
roomname = g_hash_table_lookup(components, "room");
multimx = find_room_by_alias(session, roomname);
if (multimx == NULL) {
purple_debug_error(MXIT_PLUGIN_ID, "Groupchat '%s' not found\n", roomname);
return;
}
/* Send Subscription Reject to MXit */
mxit_send_deny_sub(session, multimx->roomid, NULL);
/* Remove from our list of rooms */
room_remove(session, multimx);
}
/*------------------------------------------------------------------------
* Return name of chatroom (on mouse hover)
*
* @param components The list of chat configuration values.
* @return The name of the chat room
*/
char* mxit_chat_name(GHashTable *components)
{
return g_strdup(g_hash_table_lookup(components, "room"));
}
/*------------------------------------------------------------------------
* User has selected to invite somebody to a chatroom.
*
* @param gc The connection object
* @param id The chat room ID
* @param msg The invitation message entered by the user
* @param name The username of the person to invite
*/
void mxit_chat_invite(PurpleConnection *gc, int id, const char *msg, const char *username)
{
struct MXitSession* session = purple_connection_get_protocol_data(gc);
struct multimx* multimx = NULL;
PurpleBuddy* buddy;
PurpleChatConversation *chat;
char* tmp;
purple_debug_info(MXIT_PLUGIN_ID, "Groupchat invite to '%s'\n", username);
/* Find matching MultiMX group */
multimx = find_room_by_id(session, id);
if (multimx == NULL) {
purple_debug_error(MXIT_PLUGIN_ID, "Could not find groupchat %i\n", id);
return;
}
/* Send invite to MXit */
mxit_send_groupchat_invite(session, multimx->roomid, 1, &username);
/* Find the buddy information for this contact (reference: "libpurple/buddylist.h") */
buddy = purple_blist_find_buddy(session->acc, username);
if (!buddy) {
purple_debug_warning(MXIT_PLUGIN_ID, "mxit_chat_invite: unable to find the buddy '%s'\n", username);
return;
}
chat = purple_conversations_find_chat_with_account(multimx->roomname, session->acc);
if (chat == NULL) {
purple_debug_error(MXIT_PLUGIN_ID, "Conversation '%s' not found\n", multimx->roomname);
return;
}
/* Display system message in chat window */
tmp = g_strdup_printf("%s: %s", _("You have invited"), purple_buddy_get_alias(buddy));
purple_conversation_write_system_message(PURPLE_CONVERSATION(chat), tmp, 0);
g_free(tmp);
}
/*------------------------------------------------------------------------
* User as closed the chat window, and the chatroom is not marked as persistent.
*
* @param gc The connection object
* @param id The chat room ID
*/
void mxit_chat_leave(PurpleConnection *gc, int id)
{
struct MXitSession* session = purple_connection_get_protocol_data(gc);
struct multimx* multimx = NULL;
purple_debug_info(MXIT_PLUGIN_ID, "Groupchat %i leave\n", id);
/* Find matching multimx group */
multimx = find_room_by_id(session, id);
if (multimx == NULL) {
purple_debug_error(MXIT_PLUGIN_ID, "Could not find groupchat %i\n", id);
return;
}
/* Send Remove Groupchat to MXit */
mxit_send_remove(session, multimx->roomid);
/* Remove from our list of rooms */
room_remove(session, multimx);
}
/*------------------------------------------------------------------------
* User has entered a message in a chatroom window, send it to the MXit server.
*
* @param gc The connection object
* @param id The chat room ID
* @param msg The sent message data
* @return Indicates success / failure
*/
int mxit_chat_send(PurpleConnection *gc, int id, PurpleMessage *msg)
{
struct MXitSession* session = purple_connection_get_protocol_data(gc);
struct multimx* multimx = NULL;
const char* nickname;
/* Find matching MultiMX group */
multimx = find_room_by_id(session, id);
if (multimx == NULL) {
purple_debug_error(MXIT_PLUGIN_ID, "Could not find groupchat %i\n", id);
return -1;
}
/* Send packet to MXit */
mxit_send_message(session, multimx->roomid,
purple_message_get_contents(msg), TRUE, FALSE);
/* Determine our nickname to display */
if (multimx->nickname)
nickname = multimx->nickname;
else
nickname = purple_account_get_private_alias(purple_connection_get_account(gc)); /* local alias */
/* Display message in chat window */
purple_serv_got_chat_in(gc, id, nickname, purple_message_get_flags(msg),
purple_message_get_contents(msg), time(NULL));
return 0;
}