Mercurial > pidgin
view libpurple/protocols/mxit/multimx.c @ 29685:6797736dbe37
Does anyone know the purpose of the ui_write, ui_read and data_not_sent
FT UI callbacks? It looks like they allow a UI to decide how to safe
incoming file transfers? They're not used in Pidgin or Finch. Are
they used elsewhere?
Valgrind is complaining about an invalid free. I think it happens either
when the local user cancels a file transfer or when the remote user
cancels a file transfer. I think this change fixes it.
Revision fa4ce539e5025eb07aad3ca824cd4c512010d8a8 is related to these
callbacks and to this change by foufou33@ gee male dot com
The valgrind error is:
==23064== Invalid free() / delete / delete[]
==23064== at 0x4C24D68: free (vg_replace_malloc.c:325)
==23064== by 0x9293209: g_array_free (in /lib/libglib-2.0.so.0.2200.3)
==23064== by 0x95B1995: purple_xfer_priv_data_destroy (ft.c:71)
==23064== by 0x92AA5D1: ??? (in /lib/libglib-2.0.so.0.2200.3)
==23064== by 0x92AAE17: g_hash_table_remove_all (in /lib/libglib-2.0.so.0.2200.3)
==23064== by 0x92AAFC4: g_hash_table_destroy (in /lib/libglib-2.0.so.0.2200.3)
==23064== by 0x95B579C: purple_xfers_uninit (ft.c:1642)
==23064== by 0x95ACF08: purple_core_quit (core.c:238)
==23064== by 0x43EB3E: gtk_blist_delete_cb (gtkblist.c:227)
==23064== by 0x6F9A727: ??? (in /usr/lib/libgtk-x11-2.0.so.0.1800.3)
==23064== Address 0x2355f0e0 is not stack'd, malloc'd or (recently) free'd
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Tue, 06 Apr 2010 09:52:27 +0000 |
parents | 81ea740f92a4 |
children | 5139aa9b4077 |
line wrap: on
line source
/* * 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 "purple.h" #include "prpl.h" #include "protocol.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; /* 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); /* Deallocate it */ free (multimx); multimx = NULL; } /*------------------------------------------------------------------------ * Another user has join the GroupChat, add them to the member-list. * * @param session The MXit session object * @param multimx The MultiMX room object * @param nickname The nickname of the user who joined the room */ static void member_added(struct MXitSession* session, struct multimx* multimx, const char* nickname) { PurpleConversation *convo; purple_debug_info(MXIT_PLUGIN_ID, "member_added: '%s'\n", nickname); convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, multimx->roomname, session->acc); if (convo == NULL) { purple_debug_error(MXIT_PLUGIN_ID, "Conversation '%s' not found\n", multimx->roomname); return; } purple_conv_chat_add_user(PURPLE_CONV_CHAT(convo), nickname, NULL, PURPLE_CBFLAGS_NONE, TRUE); } /*------------------------------------------------------------------------ * Another user has left the GroupChat, remove them from the member-list. * * @param session The MXit session object * @param multimx The MultiMX room object * @param nickname The nickname of the user who left the room */ static void member_removed(struct MXitSession* session, struct multimx* multimx, const char* nickname) { PurpleConversation *convo; purple_debug_info(MXIT_PLUGIN_ID, "member_removed: '%s'\n", nickname); convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, multimx->roomname, session->acc); if (convo == NULL) { purple_debug_error(MXIT_PLUGIN_ID, "Conversation '%s' not found\n", multimx->roomname); return; } purple_conv_chat_remove_user(PURPLE_CONV_CHAT(convo), nickname, NULL); } /*------------------------------------------------------------------------ * Update the full GroupChat member list. * * @param session The MXit session object * @param multimx The MultiMX room object * @param data The nicknames of the users in the room (separated by \n) */ static void member_update(struct MXitSession* session, struct multimx* multimx, char* data) { PurpleConversation *convo; gchar** userlist; int i = 0; purple_debug_info(MXIT_PLUGIN_ID, "member_update: '%s'\n", data); convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, multimx->roomname, session->acc); if (convo == NULL) { purple_debug_error(MXIT_PLUGIN_ID, "Conversation '%s' not found\n", multimx->roomname); return; } /* Clear list */ purple_conv_chat_clear_users(PURPLE_CONV_CHAT(convo)); /* 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_conv_chat_add_user(PURPLE_CONV_CHAT(convo), userlist[i], NULL, PURPLE_CBFLAGS_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; struct multimx* multimx = NULL; purple_debug_info(MXIT_PLUGIN_ID, "Groupchat invite to '%s' by '%s'\n", contact->alias, creator); /* Create a new room */ multimx = 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' */ 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' */ 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] = '\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; /* Determine if somebody has joined or left - update member-list */ if ((ofs = strstr(msg, " has joined")) != NULL) { /* Somebody has joined */ *ofs = '\0'; member_added(mx->session, multimx, msg); mx->processed = TRUE; } else if ((ofs = strstr(msg, " has left")) != NULL) { /* Somebody has left */ *ofs = '\0'; member_removed(mx->session, multimx, msg); mx->processed = TRUE; } else if (g_str_has_prefix(msg, "The following users are in this MultiMx:") == TRUE) { member_update(mx->session, multimx, msg + strlen("The following users are in this MultiMx:") + 1); mx->processed = TRUE; } else { /* Display server message in chat window */ 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; struct proto_chat_entry *pce; /* Configuration option: Room Name */ pce = g_new0(struct proto_chat_entry, 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 = (struct MXitSession*) gc->proto_data; 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); 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 = (struct MXitSession*) gc->proto_data; 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); /* 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 = (struct MXitSession*) gc->proto_data; struct multimx* multimx = NULL; 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); } /*------------------------------------------------------------------------ * 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 = (struct MXitSession*) gc->proto_data; 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 message The sent message data * @param flags The message flags * @return Indicates success / failure */ int mxit_chat_send(PurpleConnection *gc, int id, const char *message, PurpleMessageFlags flags) { struct MXitSession* session = (struct MXitSession*) gc->proto_data; struct multimx* multimx = NULL; const char* nickname; purple_debug_info(MXIT_PLUGIN_ID, "Groupchat %i message send: '%s'\n", id, message); /* 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, message, TRUE, FALSE); /* Determine our nickname to display */ if (session->profile && (session->profile->nickname[0] != '\0')) /* default is profile name (since that's what everybody else sees) */ nickname = session->profile->nickname; else nickname = purple_account_get_alias(purple_connection_get_account(gc)); /* local alias */ /* Display message in chat window */ serv_got_chat_in(gc, id, nickname, flags, message, time(NULL)); return 0; }