2
0
mirror of https://github.com/ars3niy/tdlib-purple synced 2025-08-22 01:49:29 +00:00
tdlib-purple/test/libpurple-mock.cpp
2020-07-26 23:45:11 +02:00

1435 lines
40 KiB
C++

#include "libpurple-mock.h"
#include "purple-events.h"
#include <purple.h>
#include <stdarg.h>
#include <vector>
#include <gtest/gtest.h>
struct AccountInfo {
PurpleAccount *account;
std::vector<PurpleBuddy *> buddies;
std::vector<PurpleChat *> chats;
std::vector<PurpleConversation *> conversations;
std::map<std::string, std::string> stringsOptions;
};
std::vector<AccountInfo> g_accounts;
PurplePlugin *g_plugin;
extern "C" {
#define EVENT(type, ...) g_purpleEvents.addEvent(std::make_unique<type>(__VA_ARGS__))
void purple_debug_misc(const char *category, const char *format, ...)
{
va_list va;
va_start(va, format);
printf("%s: ", category);
vprintf(format, va);
va_end(va);
}
void purple_debug_info(const char *category, const char *format, ...)
{
va_list va;
va_start(va, format);
printf("Info: %s: ", category);
vprintf(format, va);
va_end(va);
}
void purple_debug_warning(const char *category, const char *format, ...)
{
va_list va;
va_start(va, format);
printf("Warning: %s: ", category);
vprintf(format, va);
va_end(va);
}
const char *purple_account_get_username(const PurpleAccount *account)
{
return account->username;
}
const char *purple_account_get_alias(const PurpleAccount *account)
{
return account->alias;
}
const gchar *purple_account_get_name_for_display(const PurpleAccount *account)
{
return purple_account_get_alias(account) ? : purple_account_get_username(account);
}
PurpleConnection *purple_account_get_connection(const PurpleAccount *account)
{
return account->gc;
}
gboolean purple_account_is_connected(const PurpleAccount *account)
{
return PURPLE_CONNECTION_IS_CONNECTED(account->gc);
}
void purple_account_set_alias(PurpleAccount *account, const char *alias)
{
free(account->alias);
account->alias = strdup(alias);
EVENT(AccountSetAliasEvent, account, alias);
}
PurpleAccount *purple_account_new(const char *username, const char *protocol_id)
{
PurpleAccount *account = new PurpleAccount;
account->username = strdup(username);
account->alias = nullptr;
account->proxy_info = NULL;
g_accounts.emplace_back();
g_accounts.back().account = account;
return account;
}
PurpleBlistNode root = {
.type = PURPLE_BLIST_OTHER_NODE,
.prev = NULL,
.next = NULL,
.parent = NULL,
.child = NULL,
.settings = NULL,
.ui_data = NULL,
.flags = (PurpleBlistNodeFlags)0
};
void purple_account_destroy(PurpleAccount *account)
{
free(account->username);
free(account->alias);
auto it = std::find_if(g_accounts.begin(), g_accounts.end(),
[account](const AccountInfo &info) { return (info.account == account); });
ASSERT_FALSE(it == g_accounts.end()) << "Destroying unknown account";
while (!it->buddies.empty())
purple_blist_remove_buddy(it->buddies.back());
while (!it->conversations.empty())
purple_conversation_destroy(it->conversations.back());
while (!it->chats.empty())
purple_blist_remove_chat(it->chats.back());
g_accounts.erase(it);
delete account;
ASSERT_EQ(nullptr, root.child) << "Blist nodes remain";
}
const char *purple_account_get_protocol_id(const PurpleAccount *account)
{
return "";
}
PurpleAccount *purple_accounts_find(const char *name, const char *protocol)
{
auto it = std::find_if(g_accounts.begin(), g_accounts.end(),
[name](const AccountInfo &account) {
return !strcmp(account.account->username, name);
});
if (it != g_accounts.end())
return it->account;
return NULL;
}
void purple_blist_add_account(PurpleAccount *account)
{
EVENT(ShowAccountEvent, account);
}
static void addNode(PurpleBlistNode &node)
{
node.next = root.child;
node.prev = NULL;
if (root.child)
root.child->prev = &node;
root.child = &node;
}
static void removeNode(PurpleBlistNode &node)
{
PurpleBlistNode *found;
for (found = root.child; found; found = found->next)
if (found == &node)
break;
ASSERT_TRUE(found != NULL) << "Removing unknown blist node";
if (node.prev)
node.prev->next = node.next;
if (node.next)
node.next->prev = node.prev;
if (&node == root.child)
root.child = node.next;
}
void purple_blist_add_buddy(PurpleBuddy *buddy, PurpleContact *contact, PurpleGroup *group, PurpleBlistNode *node)
{
ASSERT_EQ(NULL, node) << "Not supported";
auto pAccount = std::find_if(g_accounts.begin(), g_accounts.end(),
[buddy](const AccountInfo &info) { return (info.account == buddy->account); });
ASSERT_FALSE(pAccount == g_accounts.end()) << "Adding buddy with unknown account";
ASSERT_TRUE(std::find_if(pAccount->buddies.begin(), pAccount->buddies.end(),
[buddy](const PurpleBuddy *existing) {
return !strcmp(existing->name, buddy->name);
}) == pAccount->buddies.end())
<< "Buddy already exists in this account";
buddy->node.parent = group ? &group->node : NULL;
addNode(buddy->node);
pAccount->buddies.push_back(buddy);
EVENT(AddBuddyEvent, buddy->name, buddy->alias, buddy->account, contact, group, node);
}
void purple_blist_remove_account(PurpleAccount *account)
{
// TODO add event
}
void purple_blist_remove_buddy(PurpleBuddy *buddy)
{
auto pAccount = std::find_if(g_accounts.begin(), g_accounts.end(),
[buddy](const AccountInfo &info) { return (info.account == buddy->account); });
ASSERT_FALSE(pAccount == g_accounts.end()) << "Removing buddy with unknown account";
auto it = std::find(pAccount->buddies.begin(), pAccount->buddies.end(), buddy);
ASSERT_FALSE(it == pAccount->buddies.end()) << "Removing unkown buddy";
pAccount->buddies.erase(it);
EVENT(RemoveBuddyEvent, buddy->account, buddy->name);
removeNode(buddy->node);
purple_buddy_destroy(buddy);
}
static gboolean
purple_strings_are_different(const char *one, const char *two)
{
return !((one && two && g_utf8_collate(one, two) == 0) ||
((one == NULL || *one == '\0') && (two == NULL || *two == '\0')));
}
void purple_blist_alias_buddy(PurpleBuddy *buddy, const char *alias)
{
ASSERT_NE(nullptr, buddy);
// Similar to real libpurple
if (purple_strings_are_different(buddy->alias, alias)) {
free(buddy->alias);
buddy->alias = strdup(alias);
EVENT(AliasBuddyEvent, buddy->name, alias);
}
}
static char *getChatName(const PurpleChat *chat)
{
auto pluginInfo = (PurplePluginProtocolInfo *)g_plugin->info->extra_info;
GList *chatInfo = (pluginInfo)->chat_info(chat->account->gc);
const char *componentId = ((proto_chat_entry *)chatInfo->data)->identifier;
char *name = (char *)g_hash_table_lookup(chat->components, componentId);
g_list_free_full(chatInfo, g_free);
return name;
}
void purple_blist_remove_chat(PurpleChat *chat)
{
auto pAccount = std::find_if(g_accounts.begin(), g_accounts.end(),
[chat](const AccountInfo &info) { return (info.account == chat->account); });
ASSERT_FALSE(pAccount == g_accounts.end()) << "Removing buddy with unknown account";
auto it = std::find(pAccount->chats.begin(), pAccount->chats.end(), chat);
ASSERT_FALSE(it == pAccount->chats.end()) << "Removing unkown chat";
pAccount->chats.erase(it);
const char *inviteLink = (const char *)g_hash_table_lookup(chat->components, (char *)"link");
EVENT(RemoveChatEvent, getChatName(chat), inviteLink ? inviteLink : "");
free(chat->alias);
g_hash_table_destroy(chat->components);
removeNode(chat->node);
g_hash_table_destroy(chat->node.settings);
delete chat;
}
const char *purple_buddy_get_alias_only(PurpleBuddy *buddy)
{
return buddy->alias;
}
const char *purple_buddy_get_alias(PurpleBuddy *buddy)
{
return buddy->alias ? buddy->alias : buddy->name;
}
PurpleGroup *purple_buddy_get_group(PurpleBuddy *buddy)
{
return reinterpret_cast<PurpleGroup *>(buddy->node.parent);
}
const char *purple_buddy_get_name(const PurpleBuddy *buddy)
{
return buddy->name;
}
PurpleAccount *purple_buddy_get_account(const PurpleBuddy *buddy)
{
return buddy->account;
}
static void newNode(PurpleBlistNode &node, PurpleBlistNodeType type)
{
node.child = NULL;
node.next = NULL;
node.parent = NULL;
node.prev = NULL;
node.type = type;
node.settings = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
}
PurpleBuddy *purple_buddy_new(PurpleAccount *account, const char *name, const char *alias)
{
PurpleBuddy *buddy = new PurpleBuddy;
buddy->account = account;
buddy->name = strdup(name);
buddy->alias = alias ? strdup(alias) : NULL;
buddy->node.parent = NULL;
newNode(buddy->node, PURPLE_BLIST_BUDDY_NODE);
return buddy;
}
void purple_buddy_destroy(PurpleBuddy *buddy)
{
free(buddy->name);
free(buddy->alias);
g_hash_table_destroy(buddy->node.settings);
delete buddy;
}
void
purple_buddy_icons_set_for_user(PurpleAccount *account, const char *username,
void *icon_data, size_t icon_len,
const char *checksum)
{
EVENT(SetUserPhotoEvent, account, username, icon_data, icon_len);
}
PurpleStoredImage *
purple_buddy_icons_node_set_custom_icon(PurpleBlistNode *node,
guchar *icon_data, size_t icon_len)
{
EXPECT_TRUE(PURPLE_BLIST_NODE_IS_CHAT(node));
EVENT(SetUserPhotoEvent, PURPLE_CHAT(node)->account, getChatName(PURPLE_CHAT(node)), icon_data, icon_len);
return NULL;
}
PurpleChat *purple_chat_new(PurpleAccount *account, const char *alias, GHashTable *components)
{
PurpleChat *chat = new PurpleChat;
chat->account = account;
chat->alias = strdup(alias);
chat->components = components;
newNode(chat->node, PURPLE_BLIST_CHAT_NODE);
return chat;
}
void purple_blist_add_chat(PurpleChat *chat, PurpleGroup *group, PurpleBlistNode *node)
{
ASSERT_EQ(NULL, node) << "Not supported";
char *name = getChatName(chat);
auto pAccount = std::find_if(g_accounts.begin(), g_accounts.end(),
[chat](const AccountInfo &info) { return (info.account == chat->account); });
ASSERT_FALSE(pAccount == g_accounts.end()) << "Adding chat with unknown account";
ASSERT_TRUE(std::find_if(pAccount->chats.begin(), pAccount->chats.end(),
[name](const PurpleChat *existing) {
return !strcmp(getChatName(existing), name);
}) == pAccount->chats.end())
<< "Chat already exists in this account";
chat->node.parent = group ? &group->node : NULL;
addNode(chat->node);
pAccount->chats.push_back(chat);
EVENT(AddChatEvent, name, chat->alias, chat->account, group, node);
}
PurpleChat *purple_blist_find_chat(PurpleAccount *account, const char *name)
{
// real purple_blist_find_chat does this
if (!purple_account_is_connected(account))
return NULL;
auto pAccount = std::find_if(g_accounts.begin(), g_accounts.end(),
[account](const AccountInfo &info) { return (info.account == account); });
EXPECT_FALSE(pAccount == g_accounts.end()) << "Searching chat with unknown account";
if (pAccount != g_accounts.end()) {
auto it = std::find_if(pAccount->chats.begin(), pAccount->chats.end(),
[name](const PurpleChat *existing) {
return !strcmp(getChatName(existing), name);
});
if (it != pAccount->chats.end())
return *it;
}
return NULL;
}
const char *purple_chat_get_name(PurpleChat *chat)
{
if (chat->alias)
return chat->alias;
return getChatName(chat);
}
PurpleAccount *purple_chat_get_account(PurpleChat *chat)
{
return chat->account;
}
void purple_blist_alias_chat(PurpleChat *chat, const char *alias)
{
free(chat->alias);
chat->alias = strdup(alias);
EVENT(AliasChatEvent, getChatName(chat), alias);
}
void purple_connection_error(PurpleConnection *gc, const char *reason)
{
EVENT(ConnectionErrorEvent, gc, reason);
}
PurpleAccount *purple_connection_get_account(const PurpleConnection *gc)
{
return gc->account;
}
void *purple_connection_get_protocol_data(const PurpleConnection *connection)
{
return connection->proto_data;
}
PurpleConnectionState purple_connection_get_state(const PurpleConnection *gc)
{
return gc->state;
}
void purple_connection_set_protocol_data(PurpleConnection *connection, void *proto_data)
{
connection->proto_data = proto_data;
}
void purple_connection_set_state(PurpleConnection *gc, PurpleConnectionState state)
{
gc->state = state;
EVENT(ConnectionSetStateEvent, gc, state);
}
void purple_connection_update_progress(PurpleConnection *gc, const char *text,
size_t step, size_t count)
{
EVENT(ConnectionUpdateProgressEvent, gc, step, count);
}
static PurpleConversation *purple_conversation_new_impl(PurpleConversationType type,
PurpleAccount *account,
const char *name)
{
auto pAccount = std::find_if(g_accounts.begin(), g_accounts.end(),
[account](const AccountInfo &info) { return (info.account == account); });
EXPECT_FALSE(pAccount == g_accounts.end()) << "Adding conversation with unknown account";
if (pAccount != g_accounts.end()) {
PurpleConversation *conv = purple_find_conversation_with_account(type, name, account);
if (conv) {
if ((type == PURPLE_CONV_TYPE_CHAT) && purple_conv_chat_has_left(purple_conversation_get_chat_data(conv))) {
// Rejoin, like real libpurple does
purple_conversation_get_chat_data(conv)->left = FALSE;
return conv;
}
EXPECT_TRUE(false) << "Conversation with this name already exists to this account";
}
}
PurpleConversation *conv = new PurpleConversation;
conv->type = type;
conv->account = account;
conv->name = strdup(name);
conv->title = NULL;
if (conv->type == PURPLE_CONV_TYPE_IM) {
conv->u.im = new PurpleConvIm;
conv->u.im->conv = conv;
}
if (conv->type == PURPLE_CONV_TYPE_CHAT) {
conv->u.chat = new PurpleConvChat;
conv->u.chat->conv = conv;
conv->u.chat->left = FALSE;
conv->u.chat->id = 0;
}
if (pAccount != g_accounts.end())
pAccount->conversations.push_back(conv);
return conv;
}
PurpleConversation *purple_conversation_new(PurpleConversationType type,
PurpleAccount *account,
const char *name)
{
EVENT(NewConversationEvent, type, account, name);
return purple_conversation_new_impl(type, account, name);
}
void purple_conversation_destroy(PurpleConversation *conv)
{
auto pAccount = std::find_if(g_accounts.begin(), g_accounts.end(),
[conv](const AccountInfo &info) { return (info.account == conv->account); });
ASSERT_FALSE(pAccount == g_accounts.end()) << "Removing conversation with unknown account";
auto it = std::find(pAccount->conversations.begin(), pAccount->conversations.end(), conv);
ASSERT_FALSE(it == pAccount->conversations.end()) << "Removing unkown conversation";
pAccount->conversations.erase(it);
free(conv->name);
free(conv->title);
if (conv->type == PURPLE_CONV_TYPE_IM)
delete conv->u.im;
if (conv->type == PURPLE_CONV_TYPE_CHAT)
delete conv->u.chat;
delete conv;
}
PurpleConvIm *purple_conversation_get_im_data(const PurpleConversation *conv)
{
if (conv->type == PURPLE_CONV_TYPE_IM)
return conv->u.im;
return NULL;
}
PurpleConvChat *purple_conversation_get_chat_data(const PurpleConversation *conv)
{
if (conv->type == PURPLE_CONV_TYPE_CHAT)
return conv->u.chat;
return NULL;
}
PurpleAccount *purple_conversation_get_account(const PurpleConversation *conv)
{
return conv->account;
}
const char *purple_conversation_get_title(const PurpleConversation *conv)
{
return conv->title;
}
void purple_conversation_set_title(PurpleConversation *conv, const char *title)
{
conv->title = strdup(title);
EVENT(ConvSetTitleEvent, conv->name, title);
}
void purple_conversation_write(PurpleConversation *conv, const char *who,
const char *message, PurpleMessageFlags flags,
time_t mtime)
{
EVENT(ConversationWriteEvent, conv->name, who ? who : "", message, flags, mtime);
}
PurpleConversation *purple_conv_im_get_conversation(const PurpleConvIm *im)
{
return im->conv;
}
PurpleConversation *purple_conv_chat_get_conversation(const PurpleConvChat *chat)
{
return chat->conv;
}
int purple_conv_chat_get_id(const PurpleConvChat *chat)
{
return chat->id;
}
gboolean purple_conv_chat_has_left(PurpleConvChat *chat)
{
return chat->left;
}
void purple_conv_chat_left(PurpleConvChat *chat)
{
chat->left = TRUE;
}
void purple_conv_im_write(PurpleConvIm *im, const char *who,
const char *message, PurpleMessageFlags flags,
time_t mtime)
{
purple_conversation_write(purple_conv_im_get_conversation(im), who, message, flags, mtime);
}
void purple_conv_chat_write(PurpleConvChat *chat, const char *who,
const char *message, PurpleMessageFlags flags,
time_t mtime)
{
purple_conversation_write(purple_conv_chat_get_conversation(chat), who, message, flags, mtime);
}
void purple_conv_chat_set_topic(PurpleConvChat *chat, const char *who,
const char *topic)
{
EVENT(ChatSetTopicEvent, chat->conv->name, topic ? topic : "", who ? who : "");
}
gboolean purple_debug_is_enabled(void)
{
return true;
}
gboolean purple_debug_is_verbose(void)
{
return true;
}
PurpleBuddy *purple_find_buddy(PurpleAccount *account, const char *name)
{
// purple_blist_find_chat returns NULL if account is not connected, so just in case, assume
// purple_find_buddy will do likewise
if (!purple_account_is_connected(account))
return NULL;
auto pAccount = std::find_if(g_accounts.begin(), g_accounts.end(),
[account](const AccountInfo &info) { return (info.account == account); });
EXPECT_FALSE(pAccount == g_accounts.end()) << "Looking for buddy with unknown account";
if (pAccount != g_accounts.end()) {
auto it = std::find_if(pAccount->buddies.begin(), pAccount->buddies.end(),
[name](const PurpleBuddy *buddy) {
return !strcmp(purple_buddy_get_name(buddy), name);
});
if (it != pAccount->buddies.end())
return *it;
}
return NULL;
}
PurpleConversation *purple_find_chat(const PurpleConnection *gc, int id)
{
auto pAccount = std::find_if(g_accounts.begin(), g_accounts.end(),
[gc](const AccountInfo &info) { return (info.account == gc->account); });
EXPECT_FALSE(pAccount == g_accounts.end()) << "Looking for buddy with unknown account";
if (pAccount != g_accounts.end()) {
auto it = std::find_if(pAccount->conversations.begin(), pAccount->conversations.end(),
[id](const PurpleConversation *conv) {
return (conv->type == PURPLE_CONV_TYPE_CHAT) &&
(conv->u.chat->id == id);
});
if (it != pAccount->conversations.end())
return *it;
}
return NULL;
}
PurpleConversation *purple_find_conversation_with_account(
PurpleConversationType type, const char *name,
const PurpleAccount *account)
{
auto pAccount = std::find_if(g_accounts.begin(), g_accounts.end(),
[account](const AccountInfo &info) { return (info.account == account); });
EXPECT_FALSE(pAccount == g_accounts.end()) << "Adding conversation with unknown account";
if (pAccount != g_accounts.end()) {
auto it = std::find_if(pAccount->conversations.begin(), pAccount->conversations.end(),
[type, name](PurpleConversation *existing) {
return !strcmp(existing->name, name) && (existing->type == type);
});
if (it != pAccount->conversations.end())
return *it;
}
return NULL;
}
void *purple_notify_message(void *handle, PurpleNotifyMsgType type,
const char *title, const char *primary,
const char *secondary, PurpleNotifyCloseCallback cb,
gpointer user_data)
{
// TODO event
return NULL;
}
PurpleNotifyUserInfo *purple_notify_user_info_new(void)
{
return NULL;
}
GList *purple_notify_user_info_get_entries(PurpleNotifyUserInfo *user_info)
{
return NULL;
}
void purple_notify_user_info_add_section_break(PurpleNotifyUserInfo *user_info)
{
}
void purple_notify_user_info_add_pair(PurpleNotifyUserInfo *user_info, const char *label, const char *value)
{
}
void *purple_notify_userinfo(PurpleConnection *gc, const char *who,
PurpleNotifyUserInfo *user_info, PurpleNotifyCloseCallback cb,
gpointer user_data)
{
return NULL;
}
gboolean purple_plugin_register(PurplePlugin *plugin)
{
// TODO maybe event
g_plugin = plugin;
return TRUE;
}
const char *purple_primitive_get_id_from_type(PurpleStatusPrimitive type)
{
return (const char *)type;
}
void purple_prpl_got_user_status(PurpleAccount *account, const char *name,
const char *status_id, ...)
{
PurpleStatusPrimitive type = (PurpleStatusPrimitive)(unsigned long)status_id;
EVENT(UserStatusEvent, account, name, type);
}
void *purple_request_action(void *handle, const char *title, const char *primary,
const char *secondary, int default_action, PurpleAccount *account,
const char *who, PurpleConversation *conv, void *user_data,
size_t action_count, ...)
{
std::vector<std::string> buttons;
std::vector<PurpleRequestActionCb> callbacks;
va_list ap;
va_start(ap, action_count);
for (size_t i = 0; i < action_count; i++) {
buttons.emplace_back(va_arg(ap, char*));
callbacks.push_back(va_arg(ap, PurpleRequestActionCb));
}
va_end(ap);
EVENT(RequestActionEvent, handle, title, primary, secondary, account, who, conv, user_data, buttons, callbacks);
return NULL;
}
void *purple_request_input(void *handle, const char *title, const char *primary,
const char *secondary, const char *default_value, gboolean multiline,
gboolean masked, gchar *hint,
const char *ok_text, GCallback ok_cb,
const char *cancel_text, GCallback cancel_cb,
PurpleAccount *account, const char *who, PurpleConversation *conv,
void *user_data)
{
EVENT(RequestInputEvent, handle, title, primary, secondary, default_value, ok_text, ok_cb,
cancel_text, cancel_cb, account, who, conv, user_data);
// Just return some non-NULL pointer
return &g_accounts;
}
PurpleRoomlist *purple_roomlist_new(PurpleAccount *account)
{
PurpleRoomlist *roomlist = new PurpleRoomlist;
roomlist->ref = 1;
roomlist->ui_data = new RoomlistData;
return roomlist;
}
void purple_roomlist_set_in_progress(PurpleRoomlist *list, gboolean in_progress)
{
EVENT(RoomlistInProgressEvent, list, in_progress);
}
void purple_roomlist_ref(PurpleRoomlist *list)
{
list->ref++;
}
void purple_roomlist_unref(PurpleRoomlist *list)
{
ASSERT_NE(0u, list->ref);
list->ref--;
if (list->ref == 0) {
delete static_cast<RoomlistData *>(list->ui_data);
delete list;
}
}
PurpleRoomlistField *purple_roomlist_field_new(PurpleRoomlistFieldType type,
const gchar *label, const gchar *name,
gboolean hidden)
{
PurpleRoomlistField *field = new PurpleRoomlistField;
field->type = type;
field->name = strdup(name);
return field;
}
void purple_roomlist_set_fields(PurpleRoomlist *list, GList *fields)
{
RoomlistData *fieldStore = static_cast<RoomlistData *>(list->ui_data);
for (GList *field = fields; field; field = g_list_next(field)) {
PurpleRoomlistField *f = static_cast<PurpleRoomlistField *>(field->data);
fieldStore->emplace_back(f->type, f->name);
free(f->name);
delete f;
}
g_list_free(fields);
}
struct RealRoom {
std::vector<std::string> fieldValues;
GList firstField = {NULL, NULL, NULL};
};
PurpleRoomlistRoom *purple_roomlist_room_new(PurpleRoomlistRoomType type, const gchar *name,
PurpleRoomlistRoom *parent)
{
PurpleRoomlistRoom *room = reinterpret_cast<PurpleRoomlistRoom *>(new RealRoom);
return room;
}
void purple_roomlist_room_add_field(PurpleRoomlist *list, PurpleRoomlistRoom *notRoom, gconstpointer field)
{
RoomlistData *fieldList = static_cast<RoomlistData *>(list->ui_data);
RealRoom *room = reinterpret_cast<RealRoom *>(notRoom);
size_t index = room->fieldValues.size();
switch (fieldList->at(index).first) {
case PURPLE_ROOMLIST_FIELD_BOOL:
room->fieldValues.push_back(field ? "true" : "false");
break;
case PURPLE_ROOMLIST_FIELD_INT:
room->fieldValues.push_back(std::to_string(GPOINTER_TO_INT(field)));
break;
case PURPLE_ROOMLIST_FIELD_STRING:
room->fieldValues.push_back(static_cast<const char *>(field));
break;
}
}
GList * purple_roomlist_room_get_fields(PurpleRoomlistRoom *notRoom)
{
RealRoom *room = reinterpret_cast<RealRoom *>(notRoom);
if (!room->fieldValues.empty())
room->firstField.data = const_cast<char *>(room->fieldValues[0].c_str());
return &room->firstField;
}
void purple_roomlist_room_add(PurpleRoomlist *list, PurpleRoomlistRoom *notRoom)
{
RealRoom *room = reinterpret_cast<RealRoom *>(notRoom);
EVENT(RoomlistAddRoomEvent, list, room->fieldValues);
delete room;
}
void purple_serv_got_join_chat_failed(PurpleConnection *gc, GHashTable *data)
{
// TODO event
}
PurpleStatusType *purple_status_type_new_full(PurpleStatusPrimitive primitive,
const char *id, const char *name,
gboolean saveable,
gboolean user_settable,
gboolean independent)
{
return NULL;
}
const char *purple_user_dir(void)
{
return "purple_user_dir";
}
PurpleXfer *purple_xfer_new(PurpleAccount *account,
PurpleXferType type, const char *who)
{
PurpleXfer *xfer = new PurpleXfer;
xfer->account = account;
xfer->type = type;
xfer->who = strdup(who);
xfer->ref = 1;
xfer->local_filename = NULL;
xfer->status = PURPLE_XFER_STATUS_UNKNOWN;
xfer->size = 0;
memset(&xfer->ops, 0, sizeof(xfer->ops));
return xfer;
}
void purple_xfer_ref(PurpleXfer *xfer)
{
xfer->ref++;
}
void purple_xfer_unref(PurpleXfer *xfer)
{
if (--xfer->ref == 0) {
free(xfer->who);
free(xfer->local_filename);
delete xfer;
}
}
void purple_xfer_request(PurpleXfer *xfer)
{
}
std::map<std::string, size_t> fakeFiles;
void setFakeFileSize(const char *path, size_t size)
{
fakeFiles[path] = size;
}
void clearFakeFiles()
{
fakeFiles.clear();
}
void purple_xfer_request_accepted(PurpleXfer *xfer, const char *filename)
{
EVENT(XferAcceptedEvent, xfer, filename);
xfer->status = PURPLE_XFER_STATUS_ACCEPTED;
xfer->local_filename = strdup(filename);
if (xfer->type == PURPLE_XFER_SEND)
xfer->size = fakeFiles.at(filename);
if (xfer->ops.init)
xfer->ops.init(xfer);
}
void purple_xfer_set_init_fnc(PurpleXfer *xfer, void (*fnc)(PurpleXfer *))
{
xfer->ops.init = fnc;
}
void purple_xfer_set_cancel_send_fnc(PurpleXfer *xfer, void (*fnc)(PurpleXfer *))
{
xfer->ops.cancel_send = fnc;
}
void purple_xfer_set_cancel_recv_fnc(PurpleXfer *xfer, void (*fnc)(PurpleXfer *))
{
xfer->ops.cancel_recv = fnc;
}
void purple_xfer_set_end_fnc(PurpleXfer *xfer, void (*fnc)(PurpleXfer *))
{
xfer->ops.end = fnc;
}
const char *purple_xfer_get_remote_user(const PurpleXfer *xfer)
{
return xfer->who;
}
const char *purple_xfer_get_local_filename(const PurpleXfer *xfer)
{
return xfer->local_filename;
}
void purple_xfer_set_filename(PurpleXfer *xfer, const char *filename)
{
}
void purple_xfer_set_size(PurpleXfer *xfer, size_t size)
{
xfer->size = size;
}
void purple_xfer_start(PurpleXfer *xfer, int fd, const char *ip,
unsigned int port)
{
EVENT(XferStartEvent, xfer->local_filename);
xfer->status = PURPLE_XFER_STATUS_STARTED;
}
void purple_xfer_cancel_local(PurpleXfer *xfer)
{
EVENT(XferLocalCancelEvent, xfer->local_filename);
xfer->status = PURPLE_XFER_STATUS_CANCEL_LOCAL;
if ((xfer->type == PURPLE_XFER_SEND) && xfer->ops.cancel_send)
xfer->ops.cancel_send(xfer);
if ((xfer->type == PURPLE_XFER_RECEIVE) && xfer->ops.cancel_recv)
xfer->ops.cancel_recv(xfer);
purple_xfer_unref(xfer);
}
gboolean purple_xfer_is_canceled(const PurpleXfer *xfer)
{
return (xfer->status == PURPLE_XFER_STATUS_CANCEL_LOCAL) ||
(xfer->status == PURPLE_XFER_STATUS_CANCEL_REMOTE);
}
void purple_xfer_cancel_remote(PurpleXfer *xfer)
{
EVENT(XferRemoteCancelEvent, xfer->local_filename);
xfer->status = PURPLE_XFER_STATUS_CANCEL_REMOTE;
if ((xfer->type == PURPLE_XFER_SEND) && xfer->ops.cancel_send)
xfer->ops.cancel_send(xfer);
if ((xfer->type == PURPLE_XFER_RECEIVE) && xfer->ops.cancel_recv)
xfer->ops.cancel_recv(xfer);
purple_xfer_unref(xfer);
}
void purple_xfer_error(PurpleXferType type, PurpleAccount *account, const char *who, const char *msg)
{
purple_notify_error(account, "Xfer error", who, msg);
}
PurpleXferType purple_xfer_get_type(const PurpleXfer *xfer)
{
return xfer->type;
}
void purple_xfer_set_bytes_sent(PurpleXfer *xfer, size_t bytes_sent)
{
xfer->bytes_sent = bytes_sent;
}
void purple_xfer_set_completed(PurpleXfer *xfer, gboolean completed)
{
EVENT(XferCompletedEvent, xfer->local_filename, completed, xfer->bytes_sent);
}
void purple_xfer_update_progress(PurpleXfer *xfer)
{
EVENT(XferProgressEvent, xfer->local_filename, xfer->bytes_sent);
}
void purple_xfer_end(PurpleXfer *xfer)
{
EVENT(XferEndEvent, xfer->local_filename);
if (xfer->ops.end)
xfer->ops.end(xfer);
purple_xfer_unref(xfer);
}
PurpleXferStatusType purple_xfer_get_status(const PurpleXfer *xfer)
{
return xfer->status;
}
size_t purple_xfer_get_size(const PurpleXfer *xfer)
{
return xfer->size;
}
void serv_got_chat_in(PurpleConnection *g, int id, const char *who,
PurpleMessageFlags flags, const char *message, time_t mtime)
{
EVENT(ServGotChatEvent, g, id, who, message, flags, mtime);
}
void serv_got_im(PurpleConnection *gc, const char *who, const char *msg,
PurpleMessageFlags flags, time_t mtime)
{
if (purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, who, gc->account) == NULL) {
std::cout << "Adding conversation\n";
purple_conversation_new_impl(PURPLE_CONV_TYPE_IM, gc->account, who);
}
EVENT(ServGotImEvent, gc, who, msg, flags, mtime);
}
PurpleConversation *serv_got_joined_chat(PurpleConnection *gc,
int id, const char *name)
{
PurpleConversation *conv = purple_conversation_new_impl(PURPLE_CONV_TYPE_CHAT, gc->account, name);
purple_conversation_get_chat_data(conv)->id = id;
PurpleChat *chat = purple_blist_find_chat(gc->account, name);
if (chat && chat->alias)
conv->title = strdup(chat->alias);
EVENT(ServGotJoinedChatEvent, gc, id, name, conv->title ? conv->title : name);
return conv;
}
void serv_got_typing(PurpleConnection *gc, const char *name, int timeout,
PurpleTypingState state)
{
// TODO event
}
void serv_got_typing_stopped(PurpleConnection *gc, const char *name)
{
// TODO event
}
void purple_conversation_present(PurpleConversation *conv)
{
EVENT(PresentConversationEvent, conv->name);
}
void purple_conv_chat_add_user(PurpleConvChat *chat, const char *user,
const char *extra_msg, PurpleConvChatBuddyFlags flags,
gboolean new_arrival)
{
EVENT(ChatAddUserEvent, chat->conv->name, user, extra_msg ? extra_msg : "", flags, new_arrival);
}
void purple_conv_chat_add_users(PurpleConvChat *chat, GList *users, GList *extra_msgs,
GList *flags, gboolean new_arrivals)
{
GList *user, *flag;
for (user = users, flag = flags; user; user = user->next, flag = flag->next)
purple_conv_chat_add_user(chat, (const char *)user->data, NULL,
(PurpleConvChatBuddyFlags)GPOINTER_TO_INT(flag->data), new_arrivals);
}
void purple_conv_chat_clear_users(PurpleConvChat *chat)
{
EVENT(ChatClearUsersEvent, chat->conv->name);
}
PurpleBlistNode *purple_blist_get_root(void)
{
return &root;
}
PurpleBlistNode *purple_blist_node_get_sibling_next(PurpleBlistNode *node)
{
return node->next;
}
PurpleBlistNodeType purple_blist_node_get_type(PurpleBlistNode *node)
{
return node->type;
}
GHashTable *purple_chat_get_components(PurpleChat *chat)
{
return chat->components;
}
PurpleBlistNode *purple_blist_node_get_first_child(PurpleBlistNode *node)
{
return node->child;
}
void purple_blist_node_set_string(PurpleBlistNode *node, const char *key,
const char *value)
{
g_hash_table_insert(node->settings, (void *)key, g_strdup(value));
}
const char *purple_blist_node_get_string(PurpleBlistNode *node, const char *key)
{
return static_cast<const char *>(g_hash_table_lookup(node->settings, key));
}
void purple_blist_node_remove_setting(PurpleBlistNode *node, const char *key)
{
g_hash_table_remove(node->settings, key);
}
static char groupName[] = "Group";
PurpleGroup standardPurpleGroup = {
.node = PurpleBlistNode(),
.name = groupName,
.totalsize = 0,
.currentsize = 0,
.online = 0
};
PurpleGroup *purple_find_group(const char *name)
{
if (!strcmp(name, standardPurpleGroup.name))
return &standardPurpleGroup;
return NULL;
}
const char *purple_group_get_name(PurpleGroup *group)
{
return group->name;
}
struct _PurpleStoredImage {
std::vector<uint8_t> data;
};
std::vector<std::unique_ptr<PurpleStoredImage>> imageStore;
guint8 *arrayDup(gpointer data, size_t size)
{
guint8 *result = (guint8 *)g_malloc(size);
memmove(result, data, size);
return result;
}
int purple_imgstore_add_with_id(gpointer data, size_t size, const char *filename)
{
imageStore.push_back(std::make_unique<PurpleStoredImage>());
imageStore.back()->data = std::vector<uint8_t>(size);
memmove(imageStore.back()->data.data(), data, size);
g_free(data);
return imageStore.size();
}
int getLastImgstoreId()
{
return imageStore.size();
}
PurpleStoredImage *purple_imgstore_find_by_id(int id)
{
if ((id >= 1) && ((unsigned)id <= imageStore.size()))
return imageStore[id-1].get();
else
return NULL;
}
gconstpointer purple_imgstore_get_data(PurpleStoredImage *img)
{
return img->data.data();
}
size_t purple_imgstore_get_size(PurpleStoredImage *img)
{
return img->data.size();
}
gchar *purple_markup_escape_text(const gchar *text, gssize length)
{
std::string s(text, length);
size_t pos;
while ((pos = s.find('<')) != std::string::npos)
s.replace(pos, 1, "&lt;");
while ((pos = s.find('>')) != std::string::npos)
s.replace(pos, 1, "&gt;");
return g_strdup(s.c_str());
}
char *purple_unescape_html(const char *html)
{
std::string s(html);
size_t pos;
while ((pos = s.find("&lt;")) != std::string::npos)
s.replace(pos, 4, "<");
while ((pos = s.find("&gt;")) != std::string::npos)
s.replace(pos, 4, ">");
return g_strdup(s.c_str());
}
PurpleProxyInfo *purple_proxy_get_setup(PurpleAccount *account)
{
return account->proxy_info;
}
PurpleProxyType purple_proxy_info_get_type(const PurpleProxyInfo *info)
{
return info->type;
}
const char *purple_proxy_info_get_host(const PurpleProxyInfo *info)
{
return info->host;
}
int purple_proxy_info_get_port(const PurpleProxyInfo *info)
{
return info->port;
}
const char *purple_proxy_info_get_username(const PurpleProxyInfo *info)
{
return info->username;
}
const char *purple_proxy_info_get_password(const PurpleProxyInfo *info)
{
return info->password;
}
PurpleRequestFields *purple_request_fields_new(void)
{
return NULL;
}
PurpleRequestFieldGroup *purple_request_field_group_new(const char *title)
{
return NULL;
}
PurpleRequestField *purple_request_field_string_new(const char *id,
const char *text,
const char *default_value,
gboolean multiline)
{
return NULL;
}
void purple_request_field_set_type_hint(PurpleRequestField *field,
const char *type_hint)
{
}
void purple_request_field_string_set_masked(PurpleRequestField *field,
gboolean masked)
{
}
void purple_request_field_group_add_field(PurpleRequestFieldGroup *group,
PurpleRequestField *field)
{
}
void purple_request_fields_add_group(PurpleRequestFields *fields,
PurpleRequestFieldGroup *group)
{
}
const char *purple_request_fields_get_string(const PurpleRequestFields *fields,
const char *id)
{
return "";
}
void *purple_request_fields(void *handle, const char *title, const char *primary,
const char *secondary, PurpleRequestFields *fields,
const char *ok_text, GCallback ok_cb,
const char *cancel_text, GCallback cancel_cb,
PurpleAccount *account, const char *who, PurpleConversation *conv,
void *user_data)
{
return NULL;
}
PurpleMenuAction *purple_menu_action_new(const char *label, PurpleCallback callback,
gpointer data, GList *children)
{
PurpleMenuAction *action = new PurpleMenuAction;
action->label = strdup(label);
action->callback = callback;
action->children = NULL;
action->data = data;
return action;
}
void purple_menu_action_free(PurpleMenuAction *act)
{
free(act->label);
delete act;
}
PurplePluginAction *purple_plugin_action_new(const char* label, void (*callback)(PurplePluginAction *))
{
return NULL;
}
PurpleAccountOption *purple_account_option_string_new(const char *text,
const char *pref_name, const char *default_value)
{
return NULL;
}
PurpleAccountOption *purple_account_option_bool_new(const char *text,
const char *pref_name, gboolean default_value)
{
return NULL;
}
PurpleAccountOption *purple_account_option_list_new(const char *text,
const char *pref_name, GList *list)
{
for (GList *choice = list; choice; choice = g_list_next(choice)) {
PurpleKeyValuePair *kvp = static_cast<PurpleKeyValuePair *>(choice->data);
g_free(kvp->key);
g_free(kvp->value);
g_free(kvp);
}
g_list_free(list);
return NULL;
}
const char *purple_account_get_string(const PurpleAccount *account,
const char *name,
const char *default_value)
{
auto it = std::find_if(g_accounts.begin(), g_accounts.end(),
[account](const AccountInfo &info) { return (info.account == account); });
EXPECT_FALSE(it == g_accounts.end()) << "Unknown account";
if (it != g_accounts.end()) {
auto itOption = it->stringsOptions.find(name);
if (itOption != it->stringsOptions.end())
return itOption->second.c_str();
}
return default_value;
}
void purple_account_set_string(PurpleAccount *account, const char *name,
const char *value)
{
auto it = std::find_if(g_accounts.begin(), g_accounts.end(),
[account](const AccountInfo &info) { return (info.account == account); });
EXPECT_FALSE(it == g_accounts.end()) << "Unknown account";
if (it != g_accounts.end()) {
it->stringsOptions[name] = value;
}
}
gboolean purple_account_get_bool(const PurpleAccount *account, const char *name,
gboolean default_value)
{
return *purple_account_get_string(account, name, default_value ? "true" : "");
}
void purple_account_set_bool(PurpleAccount *account, const char *name,
gboolean value)
{
purple_account_set_string(account, name, value ? "true" : "");
}
char *purple_str_size_to_units(size_t size)
{
return g_strdup("purple_str_size_to_units");
}
PurpleCmdId purple_cmd_register(const gchar *cmd, const gchar *args, PurpleCmdPriority p, PurpleCmdFlag f,
const gchar *prpl_id, PurpleCmdFunc func, const gchar *helpstr, void *data)
{
g_purpleEvents.addCommand(cmd, func, data);
return 0;
}
PurpleMediaManager *purple_media_manager_get(void)
{
return NULL;
}
PurpleMediaCaps purple_media_manager_get_ui_caps(PurpleMediaManager *manager)
{
return PURPLE_MEDIA_CAPS_NONE;
}
};