diff options
Diffstat (limited to 'backends/libpurple/main.cpp')
-rw-r--r-- | backends/libpurple/main.cpp | 320 |
1 files changed, 102 insertions, 218 deletions
diff --git a/backends/libpurple/main.cpp b/backends/libpurple/main.cpp index ad855558..1d2172ee 100644 --- a/backends/libpurple/main.cpp +++ b/backends/libpurple/main.cpp @@ -57,19 +57,6 @@ bool firstPing = true; using namespace Transport; -template <class T> T fromString(const std::string &str) { - T i; - std::istringstream os(str); - os >> i; - return i; -} - -template <class T> std::string stringOf(T object) { - std::ostringstream os; - os << object; - return (os.str()); -} - static std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) { std::stringstream ss(s); std::string item; @@ -112,14 +99,6 @@ bool caching = true; static void *notify_user_info(PurpleConnection *gc, const char *who, PurpleNotifyUserInfo *user_info); -static gboolean ft_ui_ready(void *data) { - PurpleXfer *xfer = (PurpleXfer *) data; - FTData *ftdata = (FTData *) xfer->ui_data; - ftdata->timer = 0; - purple_xfer_ui_ready_wrapped((PurpleXfer *) data); - return FALSE; -} - /* Authorization requests from buddies are cached for the duration of the session. To authorize or deny, call the cached callbacks. @@ -241,6 +220,7 @@ static boost::mutex dblock; static std::string OAUTH_TOKEN = "hangouts_oauth_token"; static std::string STEAM_ACCESS_TOKEN = "steammobile_access_token"; static std::string DISCORD_ACCESS_TOKEN = "discord_access_token"; +static std::string WHATSMEOW_ACCESS_TOKEN = "credentials"; static bool getUserToken(const std::string user, const std::string token_name, std::string &token_value) { @@ -338,7 +318,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { break; case PURPLE_PREF_INT: - purple_account_set_int_wrapped(account, strippedKey.c_str(), fromString<int>(keyItem.second.as<std::string>())); + purple_account_set_int_wrapped(account, strippedKey.c_str(), std::stoi(keyItem.second.as<std::string>())); break; case PURPLE_PREF_STRING: @@ -352,7 +332,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { } if (!found) { - purple_account_set_string_wrapped(account, strippedKey.c_str(), keyItem.second.as<std::string>().c_str()); + LOG4CXX_ERROR(logger, "Unknown [purple] option: " << strippedKey); } i++; } @@ -361,7 +341,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { gsize length; gboolean ret = g_file_get_contents ("gfire.cfg", &contents, &length, NULL); if (ret) { - purple_account_set_int_wrapped(account, "version", fromString<int>(std::string(contents, length))); + purple_account_set_int_wrapped(account, "version", std::stoi(std::string(contents, length))); } @@ -487,6 +467,13 @@ class SpectrumNetworkPlugin : public NetworkPlugin { purple_account_set_string_wrapped(account, "token", token.c_str()); } } + else if (protocol == "prpl-hehoe-whatsmeow") { + std::string token; + getUserToken(user, WHATSMEOW_ACCESS_TOKEN, token); + if (!token.empty()) { + purple_account_set_string_wrapped(account, "credentials", token.c_str()); + } + } setDefaultAccountOptions(account); @@ -521,7 +508,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { account->ui_data = NULL; } if (purple_account_get_int_wrapped(account, "version", 0) != 0) { - std::string data = stringOf(purple_account_get_int_wrapped(account, "version", 0)); + std::string data = std::to_string(purple_account_get_int_wrapped(account, "version", 0)); g_file_set_contents ("gfire.cfg", data.c_str(), data.size(), NULL); } // VALGRIND_DO_LEAK_CHECK; @@ -891,44 +878,6 @@ class SpectrumNetworkPlugin : public NetworkPlugin { purple_conversation_destroy_wrapped(conv); } - void handleFTStartRequest(const std::string &user, const std::string &buddyName, const std::string &fileName, unsigned long size, unsigned long ftID) { - PurpleXfer *xfer = m_unhandledXfers[user + fileName + buddyName]; - if (xfer) { - m_unhandledXfers.erase(user + fileName + buddyName); - FTData *ftData = (FTData *) xfer->ui_data; - - ftData->id = ftID; - m_xfers[ftID] = xfer; - purple_xfer_request_accepted_wrapped(xfer, fileName.c_str()); - purple_xfer_ui_ready_wrapped(xfer); - } - } - - void handleFTFinishRequest(const std::string &user, const std::string &buddyName, const std::string &fileName, unsigned long size, unsigned long ftID) { - PurpleXfer *xfer = m_unhandledXfers[user + fileName + buddyName]; - if (xfer) { - m_unhandledXfers.erase(user + fileName + buddyName); - purple_xfer_request_denied_wrapped(xfer); - } - } - - void handleFTPauseRequest(unsigned long ftID) { - PurpleXfer *xfer = m_xfers[ftID]; - if (!xfer) - return; - FTData *ftData = (FTData *) xfer->ui_data; - ftData->paused = true; - } - - void handleFTContinueRequest(unsigned long ftID) { - PurpleXfer *xfer = m_xfers[ftID]; - if (!xfer) - return; - FTData *ftData = (FTData *) xfer->ui_data; - ftData->paused = false; - purple_xfer_ui_ready_wrapped(xfer); - } - void sendData(const std::string &string) { #ifdef WIN32 ::send(main_socket, string.c_str(), string.size(), 0); @@ -939,30 +888,12 @@ class SpectrumNetworkPlugin : public NetworkPlugin { writeInput = purple_input_add_wrapped(main_socket, PURPLE_INPUT_WRITE, &transportDataReceived, NULL); } - void readyForData() { - if (m_waitingXfers.empty()) - return; - std::vector<PurpleXfer *> tmp; - tmp.swap(m_waitingXfers); - - for (std::vector<PurpleXfer *>::const_iterator it = tmp.begin(); it != tmp.end(); it++) { - FTData *ftData = (FTData *) (*it)->ui_data; - if (ftData->timer == 0) { - ftData->timer = purple_timeout_add_wrapped(1, ft_ui_ready, *it); - } -// purple_xfer_ui_ready_wrapped(xfer); - } - } - std::map<std::string, PurpleAccount *> m_sessions; std::map<PurpleAccount *, std::string> m_accounts; std::map<std::string, unsigned int> m_vcards; AuthRequestList m_authRequests; std::map<std::string, inputRequest *> m_inputRequests; std::map<std::string, std::list<std::string> > m_rooms; - std::map<unsigned long, PurpleXfer *> m_xfers; - std::map<std::string, PurpleXfer *> m_unhandledXfers; - std::vector<PurpleXfer *> m_waitingXfers; std::string adminLegacyName; std::string adminAlias; }; @@ -1480,7 +1411,7 @@ static bool conv_msg_to_image(const char* msg, std::string* xhtml_, std::string* static void conv_write_im(PurpleConversation *conv, const char *who, const char *msg, PurpleMessageFlags flags, time_t mtime) { - LOG4CXX_INFO(logger, "conv_write_im()"); + LOG4CXX_DEBUG(logger, "conv_write_im(): msg='" << msg << "', flags=" << flags); bool isCarbon = false; if (purple_conversation_get_type_wrapped(conv) == PURPLE_CONV_TYPE_IM) { @@ -1506,8 +1437,6 @@ static void conv_write_im(PurpleConversation *conv, const char *who, const char std::string message_; //plain text std::string xhtml_; //enhanced xhtml, if available - LOG4CXX_DEBUG(logger, "conv_write_im(): msg='" << msg << "', flags=" << flags); - if (flags & PURPLE_MESSAGE_IMAGES) { //Store image locally and adjust the message if (!conv_msg_to_image(msg, &xhtml_, &message_)) @@ -1968,142 +1897,92 @@ static PurpleAccountUiOps accountUiOps = NULL }; -static void XferCreated(PurpleXfer *xfer) { - if (!xfer) { - return; - } - - PurpleAccount *account = purple_xfer_get_account_wrapped(xfer); - np->handleFTStart(np->m_accounts[account], xfer->who, purple_xfer_get_filename_wrapped(xfer), purple_xfer_get_size_wrapped(xfer)); -} - -static void XferDestroyed(PurpleXfer *xfer) { - std::remove(np->m_waitingXfers.begin(), np->m_waitingXfers.end(), xfer); - FTData *ftdata = (FTData *) xfer->ui_data; - if (ftdata && ftdata->timer) { - purple_timeout_remove_wrapped(ftdata->timer); - } - if (ftdata) { - np->m_xfers.erase(ftdata->id); +static gboolean +ensure_path_exists(const char *dir) +{ + if (!g_file_test(dir, G_FILE_TEST_IS_DIR)) + { + if (g_mkdir_with_parents(dir, S_IRUSR | S_IWUSR | S_IXUSR)) { + return FALSE; + } } + return TRUE; } -static void xferCanceled(PurpleXfer *xfer) { +static void newXfer(PurpleXfer *xfer) { PurpleAccount *account = purple_xfer_get_account_wrapped(xfer); - std::string filename(xfer ? purple_xfer_get_filename_wrapped(xfer) : ""); - std::string w = xfer->who; + std::string remote_filename(xfer ? purple_xfer_get_filename_wrapped(xfer) : ""); + std::string w = xfer->who ? xfer->who : ""; size_t pos = w.find("/"); if (pos != std::string::npos) w.erase((int) pos, w.length() - (int) pos); - - FTData *ftdata = (FTData *) xfer->ui_data; - - np->handleFTFinish(np->m_accounts[account], w, filename, purple_xfer_get_size_wrapped(xfer), ftdata ? ftdata->id : 0); - std::remove(np->m_waitingXfers.begin(), np->m_waitingXfers.end(), xfer); - if (ftdata && ftdata->timer) { - purple_timeout_remove_wrapped(ftdata->timer); + int count = 1; + gchar **name_and_ext; + const gchar *name; + gchar *ext; + std::string web_dir = CONFIG_STRING(config, "service.web_directory"); + std::string web_url = CONFIG_STRING(config, "service.web_url"); + if (web_dir.empty() || web_url.empty()) { + LOG4CXX_DEBUG(logger, "Denied " << remote_filename << " from " << w << ", web_directory is disabled."); + purple_xfer_request_denied_wrapped(xfer); + return; } - purple_xfer_unref_wrapped(xfer); -} - -static void fileSendStart(PurpleXfer *xfer) { -// FiletransferRepeater *repeater = (FiletransferRepeater *) xfer->ui_data; -// repeater->fileSendStart(); -} - -static void fileRecvStart(PurpleXfer *xfer) { -// FiletransferRepeater *repeater = (FiletransferRepeater *) xfer->ui_data; -// repeater->fileRecvStart(); - FTData *ftData = (FTData *) xfer->ui_data; - if (ftData->timer == 0) { - ftData->timer = purple_timeout_add_wrapped(1, ft_ui_ready, xfer); + LOG4CXX_INFO(logger, "Accepting " << remote_filename << " from " << w); + gchar *dirname = g_build_filename(web_dir.c_str(), NULL); + gchar *filename = g_build_filename(dirname, remote_filename.c_str(), NULL); + // Uniqifying code taken from Pidgin autoaccept plugin + /* Split at the first dot, to avoid uniquifying "foo.tar.gz" to "foo.tar-2.gz" */ + name_and_ext = g_strsplit(filename, ".", 2); + name = name_and_ext[0]; + if (name == NULL) + { + g_strfreev(name_and_ext); + g_return_if_reached(); } -} - -static void newXfer(PurpleXfer *xfer) { - PurpleAccount *account = purple_xfer_get_account_wrapped(xfer); - std::string filename(xfer ? purple_xfer_get_filename_wrapped(xfer) : ""); - purple_xfer_ref_wrapped(xfer); - std::string w = xfer->who; - size_t pos = w.find("/"); - if (pos != std::string::npos) - w.erase((int) pos, w.length() - (int) pos); - - FTData *ftdata = new FTData; - ftdata->paused = false; - ftdata->id = 0; - ftdata->timer = 0; - xfer->ui_data = (void *) ftdata; - - np->m_unhandledXfers[np->m_accounts[account] + filename + w] = xfer; - - np->handleFTStart(np->m_accounts[account], w, filename, purple_xfer_get_size_wrapped(xfer)); -} - -static void XferReceiveComplete(PurpleXfer *xfer) { -// FiletransferRepeater *repeater = (FiletransferRepeater *) xfer->ui_data; -// repeater->_tryToDeleteMe(); -// GlooxMessageHandler::instance()->ftManager->handleXferFileReceiveComplete(xfer); - std::remove(np->m_waitingXfers.begin(), np->m_waitingXfers.end(), xfer); - FTData *ftdata = (FTData *) xfer->ui_data; - if (ftdata && ftdata->timer) { - purple_timeout_remove_wrapped(ftdata->timer); - } - purple_xfer_unref_wrapped(xfer); -} - -static void XferSendComplete(PurpleXfer *xfer) { -// FiletransferRepeater *repeater = (FiletransferRepeater *) xfer->ui_data; -// repeater->_tryToDeleteMe(); - std::remove(np->m_waitingXfers.begin(), np->m_waitingXfers.end(), xfer); - FTData *ftdata = (FTData *) xfer->ui_data; - if (ftdata && ftdata->timer) { - purple_timeout_remove_wrapped(ftdata->timer); + if (name_and_ext[1] != NULL) + { + /* g_strsplit does not include the separator in each chunk. */ + ext = g_strdup_printf(".%s", name_and_ext[1]); } - purple_xfer_unref_wrapped(xfer); -} - -static gssize XferWrite(PurpleXfer *xfer, const guchar *buffer, gssize size) { - FTData *ftData = (FTData *) xfer->ui_data; - std::string data((const char *) buffer, (size_t) size); -// std::cout << "xferwrite\n"; - if (!ftData->paused) { -// std::cout << "adding xfer to waitingXfers queue\n"; - np->m_waitingXfers.push_back(xfer); + else + { + ext = g_strdup(""); + } + /* Make sure the file doesn't exist. Do we want some better checking than this? */ + /* FIXME: There is a race here: if the newly uniquified file name gets created between + * this g_file_test and the transfer starting, the file created in the meantime + * will be clobbered. But it's not at all straightforward to fix. + */ + while (g_file_test(filename, G_FILE_TEST_EXISTS)) + { + char *file = g_strdup_printf("%s-%d%s", name, count++, ext); + g_free(filename); + filename = g_build_filename(dirname, file, NULL); + g_free(file); } - np->handleFTData(ftData->id, data); - return size; -} -static void XferNotSent(PurpleXfer *xfer, const guchar *buffer, gsize size) { -// FiletransferRepeater *repeater = (FiletransferRepeater *) xfer->ui_data; -// repeater->handleDataNotSent(buffer, size); + purple_xfer_request_accepted_wrapped(xfer, filename); + g_strfreev(name_and_ext); + g_free(ext); + g_free(dirname); + g_free(filename); } -static gssize XferRead(PurpleXfer *xfer, guchar **buffer, gssize size) { -// FiletransferRepeater *repeater = (FiletransferRepeater *) xfer->ui_data; -// int data_size = repeater->getDataToSend(buffer, size); -// if (data_size == 0) -// return 0; -// -// return data_size; - return 0; +static void XferReceiveComplete(PurpleXfer *xfer) { + std::string filename(xfer ? purple_xfer_get_local_filename_wrapped(xfer) : ""); + std::string w = xfer->who ? xfer->who : ""; + std::string message = xfer->message ? xfer->message : ""; + LOG4CXX_INFO(logger, "Received " << filename << " from " << w); + PurpleAccount *account = purple_xfer_get_account_wrapped(xfer); + std::string web_url = CONFIG_STRING(config, "service.web_url"); + pbnetwork::Attachment attachment; + gchar *base_filename = g_path_get_basename(filename.c_str()); + attachment.set_url(web_url + "/" + std::string(base_filename)); + g_free(base_filename); + std::vector<pbnetwork::Attachment> attachments = { attachment }; + np->handleMessage(np->m_accounts[account], w, message, "", "", xfer->end_time? std::to_string(xfer->end_time) : "", false, false, false, attachments); } -static PurpleXferUiOps xferUiOps = -{ - XferCreated, - XferDestroyed, - NULL, - NULL, - xferCanceled, - xferCanceled, - XferWrite, - XferRead, - XferNotSent, - NULL -}; - static void RoomlistProgress(PurpleRoomlist *list, gboolean in_progress) { if (!in_progress) { @@ -2243,7 +2122,6 @@ static void transport_core_ui_init(void) purple_accounts_set_ui_ops_wrapped(&accountUiOps); purple_notify_set_ui_ops_wrapped(¬ifyUiOps); purple_request_set_ui_ops_wrapped(&requestUiOps); - purple_xfers_set_ui_ops_wrapped(&xferUiOps); purple_connections_set_ui_ops_wrapped(&conn_ui_ops); purple_conversations_set_ui_ops_wrapped(&conversation_ui_ops); purple_roomlist_set_ui_ops_wrapped(&roomlist_ui_ops); @@ -2357,6 +2235,9 @@ static void signed_on(PurpleConnection *gc, gpointer unused) { else if (CONFIG_STRING(config, "service.protocol") == "prpl-eionrobb-discord") { storeUserToken(np->m_accounts[account], DISCORD_ACCESS_TOKEN, purple_account_get_string_wrapped(account, "token", NULL)); } + else if (CONFIG_STRING(config, "service.protocol") == "prpl-hehoe-whatsmeow") { + storeUserToken(np->m_accounts[account], WHATSMEOW_ACCESS_TOKEN, purple_account_get_string_wrapped(account, "credentials", NULL)); + } } static void printDebug(PurpleDebugLevel level, const char *category, const char *arg_s) { @@ -2498,11 +2379,8 @@ static bool initPurple() { purple_signal_connect_wrapped(purple_blist_get_handle_wrapped(), "blist-node-removed", &blist_handle,PURPLE_CALLBACK(NodeRemoved), NULL); purple_signal_connect_wrapped(purple_conversations_get_handle_wrapped(), "chat-topic-changed", &conversation_handle, PURPLE_CALLBACK(conv_chat_topic_changed), NULL); static int xfer_handle; - purple_signal_connect_wrapped(purple_xfers_get_handle_wrapped(), "file-send-start", &xfer_handle, PURPLE_CALLBACK(fileSendStart), NULL); - purple_signal_connect_wrapped(purple_xfers_get_handle_wrapped(), "file-recv-start", &xfer_handle, PURPLE_CALLBACK(fileRecvStart), NULL); - purple_signal_connect_wrapped(purple_xfers_get_handle_wrapped(), "file-recv-request", &xfer_handle, PURPLE_CALLBACK(newXfer), NULL); - purple_signal_connect_wrapped(purple_xfers_get_handle_wrapped(), "file-recv-complete", &xfer_handle, PURPLE_CALLBACK(XferReceiveComplete), NULL); - purple_signal_connect_wrapped(purple_xfers_get_handle_wrapped(), "file-send-complete", &xfer_handle, PURPLE_CALLBACK(XferSendComplete), NULL); + purple_signal_connect_wrapped(purple_xfers_get_handle_wrapped(), "file-recv-request", &xfer_handle, PURPLE_CALLBACK(newXfer), &xfer_handle); + purple_signal_connect_wrapped(purple_xfers_get_handle_wrapped(), "file-recv-complete", &xfer_handle, PURPLE_CALLBACK(XferReceiveComplete), &xfer_handle); // // purple_commands_init(); @@ -2543,12 +2421,17 @@ static void transportDataReceived(gpointer data, gint source, PurpleInputConditi cfg.setNeedRegistration(false); } else { - PurplePlugin *plugin = purple_find_prpl_wrapped(CONFIG_STRING(config, "service.protocol").c_str()); - PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin); - if (prpl_info) { - bool isPasswordlessPlugin = prpl_info->options & OPT_PROTO_NO_PASSWORD; - LOG4CXX_INFO(logger, "passwordless backend: " << isPasswordlessPlugin); - cfg.setNeedPassword(!isPasswordlessPlugin); + std::string protocol = CONFIG_STRING(config, "service.protocol"); + PurplePlugin *plugin = purple_find_prpl_wrapped(protocol.c_str()); + if (plugin) { + PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin); + if (prpl_info) { + bool isPasswordlessPlugin = prpl_info->options & OPT_PROTO_NO_PASSWORD; + LOG4CXX_INFO(logger, "passwordless backend: " << isPasswordlessPlugin); + cfg.setNeedPassword(!isPasswordlessPlugin); + } + } else { + LOG4CXX_ERROR(logger, "Protocol not found: " << protocol); } cfg.setNeedRegistration(true); } @@ -2562,7 +2445,6 @@ static void transportDataReceived(gpointer data, gint source, PurpleInputConditi purple_input_remove_wrapped(writeInput); writeInput = 0; } - np->readyForData(); } } @@ -2593,7 +2475,9 @@ int main(int argc, char **argv) { config = std::shared_ptr<Config>(cfg); Logging::initBackendLogging(config.get()); - if (CONFIG_STRING(config, "service.protocol") == "prpl-hangouts" || CONFIG_STRING(config, "service.protocol") == "prpl-steam-mobile" || CONFIG_STRING(config, "service.protocol") == "prpl-eionrobb-discord") { + if (CONFIG_STRING(config, "service.protocol") == "prpl-hangouts" || CONFIG_STRING(config, "service.protocol") == "prpl-steam-mobile" + || CONFIG_STRING(config, "service.protocol") == "prpl-eionrobb-discord" || CONFIG_STRING(config, "service.protocol") == "prpl-hehoe-whatsmeow") + { storagebackend = StorageBackend::createBackend(config.get(), error); if (storagebackend == NULL) { LOG4CXX_ERROR(logger, "Error creating StorageBackend! " << error); |