Changeset - 65d5b4fe996f
[Not reviewed]
0 2 0
Jan Kaluza - 10 years ago 2016-02-18 14:30:18
jkaluza@redhat.com
Libpurple: When service.web_directory and service.web_url is set, PURPLE_MESSAGE_IMAGES are stored to web_directory and link is forwarded to the user. Tested only with Facebook for now. Fix #106
2 files changed with 100 insertions and 19 deletions:
0 comments (0 inline, 0 general)
backends/libpurple/main.cpp
Show inline comments
 
#include "utils.h"
 

	
 
#include "glib.h"
 

	
 
// win32/libc_interface.h defines its own socket(), read() and so on.
 
// We don't want to use it here.
 
#define _LIBC_INTERFACE_H_ 1
 

	
 
#include "purple.h"
 
#include <algorithm>
 
#include <iostream>
 
#include <fstream> 
 

	
 
#include "transport/NetworkPlugin.h"
 
#include "transport/Logging.h"
 
#include "transport/Config.h"
 
#include "geventloop.h"
 

	
 
// #include "valgrind/memcheck.h"
 
#if !defined(__FreeBSD__) && !defined(__APPLE__)
 
#include "malloc.h"
 
#endif
 
#include <algorithm>
 
#include "errno.h"
 
#include <boost/make_shared.hpp>
 

	
 
#ifdef WITH_LIBEVENT
 
#include <event.h>
 
#endif
 

	
 
#ifdef WIN32
 
#include "win32/win32dep.h"
 
#define close closesocket
 
#define ssize_t SSIZE_T
 
#include <process.h>
 
#define getpid _getpid
 
#endif
 

	
 
#include "purple_defs.h"
 

	
 
DEFINE_LOGGER(logger_libpurple, "libpurple");
 
DEFINE_LOGGER(logger, "backend");
 

	
 
int main_socket;
 
static int writeInput;
 
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;
 
    while(std::getline(ss, item, delim)) {
 
        elems.push_back(item);
 
    }
 
    return elems;
 
}
 

	
 

	
 
static std::vector<std::string> split(const std::string &s, char delim) {
 
    std::vector<std::string> elems;
 
    return split(s, delim, elems);
 
}
 

	
 
static void transportDataReceived(gpointer data, gint source, PurpleInputCondition cond);
 

	
 
class SpectrumNetworkPlugin;
 

	
 
boost::shared_ptr<Config> config;
 
SpectrumNetworkPlugin *np;
 

	
 
static std::string host;
 
static int port = 10000;
 

	
 
struct FTData {
 
	unsigned long id;
 
	unsigned long timer;
 
	bool paused;
 
};
 

	
 
struct NodeCache {
 
	PurpleAccount *account;
 
	std::map<PurpleBlistNode *, int> nodes;
 
	int timer;
 
};
 

	
 
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;
 
}
 

	
 
struct authRequest {
 
	PurpleAccountRequestAuthorizationCb authorize_cb;
 
	PurpleAccountRequestAuthorizationCb deny_cb;
 
	void *user_data;
 
	std::string who;
 
	PurpleAccount *account;
 
	std::string mainJID;	// JID of user connected with this request
 
};
 

	
 
static void * requestInput(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) {
 
	if (primary) {
 
		std::string primaryString(primary);
 
		if (primaryString == "Authorization Request Message:") {
 
			LOG4CXX_INFO(logger, "Authorization Request Message: calling ok_cb(...)");
 
			((PurpleRequestInputCb) ok_cb)(user_data, "Please authorize me.");
 
			return NULL;
 
		}
 
		else if (primaryString == "Authorization Request Message:") {
 
			LOG4CXX_INFO(logger, "Authorization Request Message: calling ok_cb(...)");
 
			((PurpleRequestInputCb) ok_cb)(user_data, "Please authorize me.");
 
			return NULL;
 
		}
 
		else if (primaryString == "Authorization Denied Message:") {
 
			LOG4CXX_INFO(logger, "Authorization Deined Message: calling ok_cb(...)");
 
			((PurpleRequestInputCb) ok_cb)(user_data, "Authorization denied.");
 
			return NULL;
 
		}
 
		else {
 
			LOG4CXX_WARN(logger, "Unhandled request input. primary=" << primaryString);
 
		}
 
	}
 
	else if (title) {
 
		std::string titleString(title);
 
		if (titleString == "Xfire Invitation Message") {
 
			LOG4CXX_INFO(logger, "Authorization Request Message: calling ok_cb(...)");
 
			((PurpleRequestInputCb) ok_cb)(user_data, "Please authorize me.");
 
			return NULL;
 
		}
 
		else {
 
			LOG4CXX_WARN(logger, "Unhandled request input. title=" << titleString);
 
		}
 
	}
 
	else {
 
		LOG4CXX_WARN(logger, "Request input without primary string");
 
	}
 
	return NULL;
 
}
 

	
 
static void *requestAction(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, va_list actions){
 
	std::string t(title ? title : "NULL");
 
	if (t == "SSL Certificate Verification") {
 
		LOG4CXX_INFO(logger,  "accepting SSL certificate");
 
		va_arg(actions, char *);
 
		((PurpleRequestActionCb) va_arg(actions, GCallback)) (user_data, 2);
 
	}
 
	else if (t == "Plaintext Authentication") {
 
		LOG4CXX_INFO(logger,  "Rejecting plaintext authentification");
 
		va_arg(actions, char *);
 
		va_arg(actions, GCallback);
 
		va_arg(actions, char *);
 
		((PurpleRequestActionCb) va_arg(actions, GCallback)) (user_data, 2);
 
	}
 
	else {
 
		if (title) {
 
			std::string headerString(title);
 
			LOG4CXX_INFO(logger,  "header string: " << headerString);
 
			if (headerString == "SSL Certificate Verification") {
 
				va_arg(actions, char *);
 
				((PurpleRequestActionCb) va_arg(actions, GCallback)) (user_data, 2);
 
			}
 
		}
 
	}
 
	return NULL;
 
}
 

	
 
static std::string getAlias(PurpleBuddy *m_buddy) {
 
	std::string alias;
 
	PurpleContact *contact = PURPLE_CONTACT(PURPLE_BLIST_NODE(m_buddy)->parent);
 
	if (contact && contact->alias) {
 
		alias = contact->alias;
 
	}
 
	else if (purple_buddy_get_alias_wrapped(m_buddy)) {
 
		alias = (std::string) purple_buddy_get_alias_wrapped(m_buddy);
 
	}
 
	else {
 
		alias = (std::string) purple_buddy_get_server_alias_wrapped(m_buddy);
 
	}
 
	return alias;
 
}
 

	
 
class SpectrumNetworkPlugin : public NetworkPlugin {
 
	public:
 
		SpectrumNetworkPlugin() : NetworkPlugin() {
 

	
 
		}
 

	
 
		void handleExitRequest() {
 
			LOG4CXX_INFO(logger, "Exiting...");
 
			exit(0);
 
		}
 

	
 
		void getProtocolAndName(const std::string &legacyName, std::string &name, std::string &protocol) {
 
			name = legacyName;
 
			protocol = CONFIG_STRING(config, "service.protocol");
 
			if (protocol == "any") {
 
				protocol = name.substr(0, name.find("."));
 
				name = name.substr(name.find(".") + 1);
 
			}
 
		}
 

	
 
		void setDefaultAvatar(PurpleAccount *account, const std::string &legacyName) {
 
			char* contents;
 
			gsize length;
 
			gboolean ret = false;
 
			if (!CONFIG_STRING(config, "backend.avatars_directory").empty()) {
 
				std::string f = CONFIG_STRING(config, "backend.avatars_directory") + "/" + legacyName;
 
				ret = g_file_get_contents (f.c_str(), &contents, &length, NULL);
 
			}
 

	
 
			if (!CONFIG_STRING(config, "backend.default_avatar").empty() && !ret) {
 
				ret = g_file_get_contents (CONFIG_STRING(config, "backend.default_avatar").c_str(),
 
											&contents, &length, NULL);
 
			}
 

	
 
			if (ret) {
 
				purple_buddy_icons_set_account_icon_wrapped(account, (guchar *) contents, length);
 
			}
 
		}
 

	
 
		void setDefaultAccountOptions(PurpleAccount *account) {
 
			int i = 0;
 
			Config::SectionValuesCont purpleConfigValues = config->getSectionValues("purple");
 

	
 
			BOOST_FOREACH ( const Config::SectionValuesCont::value_type & keyItem, purpleConfigValues )
 
			{
 
				std::string key = keyItem.first;
 
				std::string strippedKey = boost::erase_first_copy(key, "purple.");
 

	
 
				if (strippedKey == "fb_api_key" || strippedKey == "fb_api_secret") {
 
					purple_account_set_bool_wrapped(account, "auth_fb", TRUE);
 
 				}
 

	
 
				PurplePlugin *plugin = purple_find_prpl_wrapped(purple_account_get_protocol_id_wrapped(account));
 
				PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin);
 
				bool found = false;
 
				for (GList *l = prpl_info->protocol_options; l != NULL; l = l->next) {
 
					PurpleAccountOption *option = (PurpleAccountOption *) l->data;
 
					PurplePrefType type = purple_account_option_get_type_wrapped(option);
 
					std::string key2(purple_account_option_get_setting_wrapped(option));
 
					if (strippedKey != key2) {
 
						continue;
 
					}
 
					
 
					found = true;
 
					switch (type) {
 
						case PURPLE_PREF_BOOLEAN:
 
							purple_account_set_bool_wrapped(account, strippedKey.c_str(), fromString<bool>(keyItem.second.as<std::string>()));
 
							break;
 

	
 
						case PURPLE_PREF_INT:
 
							purple_account_set_int_wrapped(account, strippedKey.c_str(), fromString<int>(keyItem.second.as<std::string>()));
 
							break;
 

	
 
						case PURPLE_PREF_STRING:
 
						case PURPLE_PREF_STRING_LIST:
 
							purple_account_set_string_wrapped(account, strippedKey.c_str(), keyItem.second.as<std::string>().c_str());
 
							break;
 
						default:
 
							continue;
 
					}
 
					break;
 
				}
 

	
 
				if (!found) {
 
					purple_account_set_string_wrapped(account, strippedKey.c_str(), keyItem.second.as<std::string>().c_str());
 
				}
 
				i++;
 
			}
 

	
 
			char* contents;
 
			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)));
 
			}
 

	
 

	
 
			if (CONFIG_STRING(config, "service.protocol") == "prpl-novell") {
 
				std::string username(purple_account_get_username_wrapped(account));
 
				std::vector <std::string> u = split(username, '@');
 
				purple_account_set_username_wrapped(account, (const char*) u.front().c_str());
 
				std::vector <std::string> s = split(u.back(), ':'); 
 
				purple_account_set_string_wrapped(account, "server", s.front().c_str());
 
				purple_account_set_int_wrapped(account, "port", atoi(s.back().c_str()));  
 
			}
 

	
 
			if (!CONFIG_STRING_DEFAULTED(config, "proxy.type", "").empty()) {
 
				PurpleProxyInfo *info = purple_proxy_info_new_wrapped();
 
				if (CONFIG_STRING_DEFAULTED(config, "proxy.type", "") == "http") {
 
					purple_proxy_info_set_type_wrapped(info, PURPLE_PROXY_HTTP);
 
				}
 
				else if (CONFIG_STRING_DEFAULTED(config, "proxy.type", "") == "socks4") {
 
					purple_proxy_info_set_type_wrapped(info, PURPLE_PROXY_SOCKS4);
 
				}
 
				else if (CONFIG_STRING_DEFAULTED(config, "proxy.type", "") == "socks5") {
 
					purple_proxy_info_set_type_wrapped(info, PURPLE_PROXY_SOCKS5);
 
				}
 
				else {
 
					LOG4CXX_ERROR(logger, "Unknown proxy.type " << CONFIG_STRING_DEFAULTED(config, "proxy.type", ""));
 
				}
 

	
 
				info->username = NULL;
 
				info->password = NULL;
 

	
 
				purple_proxy_info_set_type_wrapped(info, PURPLE_PROXY_SOCKS5);
 
				purple_proxy_info_set_host_wrapped(info, CONFIG_STRING_DEFAULTED(config, "proxy.host", "").c_str());
 
				if (CONFIG_INT_DEFAULTED(config, "proxy.port", 0)) {
 
					purple_proxy_info_set_port_wrapped(info, CONFIG_INT_DEFAULTED(config, "proxy.port", 0));
 
				}
 
				if (!CONFIG_STRING_DEFAULTED(config, "proxy.username", "").empty()) {
 
					purple_proxy_info_set_username_wrapped(info, CONFIG_STRING_DEFAULTED(config, "proxy.username", "").c_str());
 
				}
 

	
 
				if (!CONFIG_STRING_DEFAULTED(config, "proxy.password", "").empty()) {
 
					purple_proxy_info_set_password_wrapped(info, CONFIG_STRING_DEFAULTED(config, "proxy.password", "").c_str());
 
				}
 

	
 
				purple_account_set_proxy_info_wrapped(account, info);
 
			}
 
		}
 

	
 
		void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) {
 
			PurpleAccount *account = NULL;
 

	
 
			std::string name;
 
			std::string protocol;
 
			getProtocolAndName(legacyName, name, protocol);
 

	
 
			if (password.empty() && CONFIG_STRING(config, "service.protocol") != "prpl-telegram") {
 
				LOG4CXX_INFO(logger,  name.c_str() << ": Empty password");
 
				np->handleDisconnected(user, 0, "Empty password.");
 
				return;
 
			}
 

	
 
			if (!purple_find_prpl_wrapped(protocol.c_str())) {
 
				LOG4CXX_INFO(logger,  name.c_str() << ": Invalid protocol '" << protocol << "'");
 
				np->handleDisconnected(user, 0, "Invalid protocol " + protocol);
 
				return;
 
			}
 

	
 
			if (purple_accounts_find_wrapped(name.c_str(), protocol.c_str()) != NULL) {
 
				account = purple_accounts_find_wrapped(name.c_str(), protocol.c_str());
 
				if (m_accounts.find(account) != m_accounts.end() && m_accounts[account] != user) {
 
					LOG4CXX_INFO(logger, "Account '" << name << "' is already used by '" << m_accounts[account] << "'");
 
					np->handleDisconnected(user, 0, "Account '" + name + "' is already used by '" + m_accounts[account] + "'");
 
					return;
 
				}
 
				LOG4CXX_INFO(logger, "Using previously created account with name '" << name.c_str() << "' and protocol '" << protocol << "'");
 
			}
 
			else {
 
				LOG4CXX_INFO(logger, "Creating account with name '" << name.c_str() << "' and protocol '" << protocol << "'");
 
				account = purple_account_new_wrapped(name.c_str(), protocol.c_str());
 
				purple_accounts_add_wrapped(account);
 
			}
 

	
 
			m_sessions[user] = account;
 
			m_accounts[account] = user;
 

	
 
			// Default avatar
 
			setDefaultAvatar(account, legacyName);
 

	
 
			purple_account_set_password_wrapped(account, password.c_str());
 
			purple_account_set_bool_wrapped(account, "custom_smileys", FALSE);
 
			purple_account_set_bool_wrapped(account, "direct_connect", FALSE);
 
			purple_account_set_bool_wrapped(account, "compat-verification", TRUE);
 

	
 
			setDefaultAccountOptions(account);
 

	
 
			// Enable account + privacy lists
 
			purple_account_set_enabled_wrapped(account, "spectrum", TRUE);
 

	
 
#if PURPLE_MAJOR_VERSION >= 2 && PURPLE_MINOR_VERSION >= 7
 
			if (CONFIG_BOOL(config, "service.enable_privacy_lists")) {
 
				purple_account_set_privacy_type_wrapped(account, PURPLE_PRIVACY_DENY_USERS);
 
			}
 
@@ -742,827 +743,905 @@ class SpectrumNetworkPlugin : public NetworkPlugin {
 
			PurpleConversation *conv = purple_find_conversation_with_account_wrapped(PURPLE_CONV_TYPE_CHAT, room.c_str(), account);
 
			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);
 
#else
 
			write(main_socket, string.c_str(), string.size());
 
#endif
 
			if (writeInput == 0)
 
				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;
 
		std::map<std::string, authRequest *> m_authRequests;
 
		std::map<unsigned long, PurpleXfer *> m_xfers;
 
		std::map<std::string, PurpleXfer *> m_unhandledXfers;
 
		std::vector<PurpleXfer *> m_waitingXfers;
 
};
 

	
 
static bool getStatus(PurpleBuddy *m_buddy, pbnetwork::StatusType &status, std::string &statusMessage) {
 
	PurplePresence *pres = purple_buddy_get_presence_wrapped(m_buddy);
 
	if (pres == NULL)
 
		return false;
 
	PurpleStatus *stat = purple_presence_get_active_status_wrapped(pres);
 
	if (stat == NULL)
 
		return false;
 
	int st = purple_status_type_get_primitive_wrapped(purple_status_get_type_wrapped(stat));
 

	
 
	switch(st) {
 
		case PURPLE_STATUS_AVAILABLE: {
 
			status = pbnetwork::STATUS_ONLINE;
 
			break;
 
		}
 
		case PURPLE_STATUS_AWAY: {
 
			status = pbnetwork::STATUS_AWAY;
 
			break;
 
		}
 
		case PURPLE_STATUS_UNAVAILABLE: {
 
			status = pbnetwork::STATUS_DND;
 
			break;
 
		}
 
		case PURPLE_STATUS_EXTENDED_AWAY: {
 
			status = pbnetwork::STATUS_XA;
 
			break;
 
		}
 
		case PURPLE_STATUS_OFFLINE: {
 
			status = pbnetwork::STATUS_NONE;
 
			break;
 
		}
 
		default:
 
			status = pbnetwork::STATUS_ONLINE;
 
			break;
 
	}
 

	
 
	const char *message = purple_status_get_attr_string_wrapped(stat, "message");
 

	
 
	if (message != NULL) {
 
		char *stripped = purple_markup_strip_html_wrapped(message);
 
		statusMessage = std::string(stripped);
 
		g_free(stripped);
 
	}
 
	else
 
		statusMessage = "";
 
	return true;
 
}
 

	
 
static std::string getIconHash(PurpleBuddy *m_buddy) {
 
	char *avatarHash = NULL;
 
	PurpleBuddyIcon *icon = purple_buddy_icons_find_wrapped(purple_buddy_get_account_wrapped(m_buddy), purple_buddy_get_name_wrapped(m_buddy));
 
	if (icon) {
 
		avatarHash = purple_buddy_icon_get_full_path_wrapped(icon);
 
		purple_buddy_icon_unref_wrapped(icon);
 
	}
 

	
 
	if (avatarHash) {
 
		// Check if it's patched libpurple which saves icons to directories
 
		char *hash = strrchr(avatarHash,'/');
 
		std::string h;
 
		if (hash) {
 
			char *dot;
 
			hash++;
 
			dot = strchr(hash, '.');
 
			if (dot)
 
				*dot = '\0';
 

	
 
			std::string ret(hash);
 
			g_free(avatarHash);
 
			return ret;
 
		}
 
		else {
 
			std::string ret(avatarHash);
 
			g_free(avatarHash);
 
			return ret;
 
		}
 
	}
 

	
 
	return "";
 
}
 

	
 
static std::vector<std::string> getGroups(PurpleBuddy *m_buddy) {
 
	std::vector<std::string> groups;
 
	if (purple_buddy_get_name_wrapped(m_buddy)) {
 
		GSList *buddies = purple_find_buddies_wrapped(purple_buddy_get_account_wrapped(m_buddy), purple_buddy_get_name_wrapped(m_buddy));
 
		while(buddies) {
 
			PurpleGroup *g = purple_buddy_get_group_wrapped((PurpleBuddy *) buddies->data);
 
			buddies = g_slist_delete_link(buddies, buddies);
 

	
 
			if(g && purple_group_get_name_wrapped(g)) {
 
				groups.push_back(purple_group_get_name_wrapped(g));
 
			}
 
		}
 
	}
 

	
 
	if (groups.empty()) {
 
		groups.push_back("Buddies");
 
	}
 

	
 
	return groups;
 
}
 

	
 
void buddyListNewNode(PurpleBlistNode *node);
 

	
 
static gboolean new_node_cache(void *data) {
 
	NodeCache *cache = (NodeCache *) data;
 
	caching = false;
 
	for (std::map<PurpleBlistNode *, int>::const_iterator it = cache->nodes.begin(); it != cache->nodes.end(); it++) {
 
		buddyListNewNode(it->first);
 
	}
 
	caching = true;
 

	
 
	cache->account->ui_data = NULL;
 
	delete cache;
 

	
 
	return FALSE;
 
}
 

	
 
static void buddyNodeRemoved(PurpleBuddyList *list, PurpleBlistNode *node) {
 
	if (!PURPLE_BLIST_NODE_IS_BUDDY_WRAPPED(node))
 
		return;
 
	PurpleBuddy *buddy = (PurpleBuddy *) node;
 
	PurpleAccount *account = purple_buddy_get_account_wrapped(buddy);
 

	
 
	if (!account->ui_data) {
 
		return;
 
	}
 

	
 
	NodeCache *cache = (NodeCache *) account->ui_data;
 
	cache->nodes.erase(node);
 
}
 

	
 
void buddyListNewNode(PurpleBlistNode *node) {
 
	if (!PURPLE_BLIST_NODE_IS_BUDDY_WRAPPED(node))
 
		return;
 
	PurpleBuddy *buddy = (PurpleBuddy *) node;
 
	PurpleAccount *account = purple_buddy_get_account_wrapped(buddy);
 

	
 
	if (caching) {
 
		if (!account->ui_data) {
 
			NodeCache *cache = new NodeCache;
 
			cache->account = account;
 
			cache->timer = purple_timeout_add_wrapped(400, new_node_cache, cache);
 
			account->ui_data = (void *) cache;
 
		}
 

	
 
		NodeCache *cache = (NodeCache *) account->ui_data;
 
		cache->nodes[node] = 1;
 
		return;
 
	}
 
	
 

	
 
	std::vector<std::string> groups = getGroups(buddy);
 
	LOG4CXX_INFO(logger, "Buddy updated " << np->m_accounts[account] << " " << purple_buddy_get_name_wrapped(buddy) << " " << getAlias(buddy) << " group (" << groups.size() << ")=" << groups[0]);
 

	
 
	// Status
 
	pbnetwork::StatusType status = pbnetwork::STATUS_NONE;
 
	std::string message;
 
	getStatus(buddy, status, message);
 

	
 
	// Tooltip
 
	PurplePlugin *prpl = purple_find_prpl_wrapped(purple_account_get_protocol_id_wrapped(account));
 
	PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
 

	
 
	bool blocked = false;
 
	if (CONFIG_BOOL(config, "service.enable_privacy_lists")) {
 
		if (prpl_info && prpl_info->tooltip_text) {
 
			PurpleNotifyUserInfo *user_info = purple_notify_user_info_new_wrapped();
 
			prpl_info->tooltip_text(buddy, user_info, true);
 
			GList *entries = purple_notify_user_info_get_entries_wrapped(user_info);
 

	
 
			while (entries) {
 
				PurpleNotifyUserInfoEntry *entry = (PurpleNotifyUserInfoEntry *)(entries->data);
 
				if (purple_notify_user_info_entry_get_label_wrapped(entry) && purple_notify_user_info_entry_get_value_wrapped(entry)) {
 
					std::string label = purple_notify_user_info_entry_get_label_wrapped(entry);
 
					if (label == "Blocked" ) {
 
						if (std::string(purple_notify_user_info_entry_get_value_wrapped(entry)) == "Yes") {
 
							blocked = true;
 
							break;
 
						}
 
					}
 
				}
 
				entries = entries->next;
 
			}
 
			purple_notify_user_info_destroy_wrapped(user_info);
 
		}
 

	
 
		if (!blocked) {
 
			blocked = purple_privacy_check_wrapped(account, purple_buddy_get_name_wrapped(buddy)) == false;
 
		}
 
		else {
 
			bool purpleBlocked = purple_privacy_check_wrapped(account, purple_buddy_get_name_wrapped(buddy)) == false;
 
			if (blocked != purpleBlocked) {
 
				purple_privacy_deny_wrapped(account, purple_buddy_get_name_wrapped(buddy), FALSE, FALSE);
 
			}
 
		}
 
	}
 

	
 
	np->handleBuddyChanged(np->m_accounts[account], purple_buddy_get_name_wrapped(buddy), getAlias(buddy), getGroups(buddy), status, message, getIconHash(buddy),
 
		blocked
 
	);
 
}
 

	
 
static void buddyListUpdate(PurpleBuddyList *list, PurpleBlistNode *node) {
 
	if (!PURPLE_BLIST_NODE_IS_BUDDY_WRAPPED(node))
 
		return;
 
	buddyListNewNode(node);
 
}
 

	
 
static void buddyPrivacyChanged(PurpleBlistNode *node, void *data) {
 
	if (!PURPLE_BLIST_NODE_IS_BUDDY_WRAPPED(node))
 
		return;
 
	buddyListUpdate(NULL, node);
 
}
 

	
 
static void NodeRemoved(PurpleBlistNode *node, void *data) {
 
	if (!PURPLE_BLIST_NODE_IS_BUDDY_WRAPPED(node))
 
		return;
 
// 	PurpleBuddy *buddy = (PurpleBuddy *) node;
 
}
 

	
 
static void buddyListSaveNode(PurpleBlistNode *node) {
 
	if (!PURPLE_BLIST_NODE_IS_BUDDY_WRAPPED(node))
 
		return;
 
}
 

	
 
static void buddyListSaveAccount(PurpleAccount *account) {
 
}
 

	
 
static void buddyListRemoveNode(PurpleBlistNode *node) {
 
	if (!PURPLE_BLIST_NODE_IS_BUDDY_WRAPPED(node))
 
		return;
 
}
 

	
 
static PurpleBlistUiOps blistUiOps =
 
{
 
	NULL,
 
	buddyListNewNode,
 
	NULL,
 
	buddyListUpdate,
 
	buddyNodeRemoved,
 
	NULL,
 
	NULL,
 
	NULL, // buddyListAddBuddy,
 
	NULL,
 
	NULL,
 
	buddyListSaveNode,
 
	buddyListRemoveNode,
 
	buddyListSaveAccount,
 
	NULL
 
};
 

	
 
static void conv_write(PurpleConversation *conv, const char *who, const char *alias, const char *msg, PurpleMessageFlags flags, time_t mtime) {
 
	if (flags & PURPLE_MESSAGE_SYSTEM && CONFIG_STRING(config, "service.protocol") == "prpl-telegram") {
 
		PurpleAccount *account = purple_conversation_get_account_wrapped(conv);
 

	
 
	// 	char *striped = purple_markup_strip_html_wrapped(message);
 
	// 	std::string msg = striped;
 
	// 	g_free(striped);
 

	
 

	
 
		// Escape HTML characters.
 
		char *newline = purple_strdup_withhtml_wrapped(msg);
 
		char *strip, *xhtml;
 
		purple_markup_html_to_xhtml_wrapped(newline, &xhtml, &strip);
 
	// 	xhtml_linkified = spectrum_markup_linkify(xhtml);
 
		std::string message_(strip);
 

	
 
		std::string xhtml_(xhtml);
 
		g_free(newline);
 
		g_free(xhtml);
 
	// 	g_free(xhtml_linkified);
 
		g_free(strip);
 

	
 
		// AIM and XMPP adds <body>...</body> here...
 
		if (xhtml_.find("<body>") == 0) {
 
			xhtml_ = xhtml_.substr(6);
 
			if (xhtml_.find("</body>") != std::string::npos) {
 
				xhtml_ = xhtml_.substr(0, xhtml_.find("</body>"));
 
			}
 
		}
 

	
 
		if (xhtml_ == message_) {
 
			xhtml_ = "";
 
		}
 

	
 
		std::string timestamp;
 
		if (mtime && (unsigned long) time(NULL)-10 > (unsigned long) mtime/* && (unsigned long) time(NULL) - 31536000 < (unsigned long) mtime*/) {
 
			char buf[80];
 
			strftime(buf, sizeof(buf), "%Y%m%dT%H%M%S", gmtime(&mtime));
 
			timestamp = buf;
 
		}
 

	
 
	// 	LOG4CXX_INFO(logger, "Received message body='" << message_ << "' xhtml='" << xhtml_ << "'");
 

	
 
		if (purple_conversation_get_type_wrapped(conv) == PURPLE_CONV_TYPE_IM) {
 
			std::string w = purple_normalize_wrapped(account, who);
 
			size_t pos = w.find("/");
 
			if (pos != std::string::npos)
 
				w.erase((int) pos, w.length() - (int) pos);
 
			np->handleMessage(np->m_accounts[account], w, message_, "", xhtml_, timestamp);
 
		}
 
		else {
 
			LOG4CXX_INFO(logger, "Received message body='" << message_ << "' name='" << purple_conversation_get_name_wrapped(conv) << "' " << who);
 
			np->handleMessage(np->m_accounts[account], purple_conversation_get_name_wrapped(conv), message_, who, xhtml_, timestamp);
 
		}
 
	}
 
}
 

	
 
static char *calculate_data_hash(guchar *data, size_t len,
 
    const gchar *hash_algo)
 
{
 
	PurpleCipherContext *context;
 
	static gchar digest[129]; /* 512 bits hex + \0 */
 

	
 
	context = purple_cipher_context_new_by_name(hash_algo, NULL);
 
	if (context == NULL)
 
	{
 
		purple_debug_error("jabber", "Could not find %s cipher\n", hash_algo);
 
		g_return_val_if_reached(NULL);
 
	}
 

	
 
	/* Hash the data */
 
	purple_cipher_context_append(context, data, len);
 
	if (!purple_cipher_context_digest_to_str(context, sizeof(digest), digest, NULL))
 
	{
 
		purple_debug_error("jabber", "Failed to get digest for %s cipher.\n",
 
		    hash_algo);
 
		g_return_val_if_reached(NULL);
 
	}
 
	purple_cipher_context_destroy(context);
 

	
 
	return g_strdup(digest);
 
}
 

	
 
static void conv_write_im(PurpleConversation *conv, const char *who, const char *msg, PurpleMessageFlags flags, time_t mtime) {
 
	// Don't forwards our own messages.
 
	if (purple_conversation_get_type_wrapped(conv) == PURPLE_CONV_TYPE_IM && (flags & PURPLE_MESSAGE_SEND || flags & PURPLE_MESSAGE_SYSTEM)) {
 
		return;
 
	}
 
	PurpleAccount *account = purple_conversation_get_account_wrapped(conv);
 

	
 
// 	char *striped = purple_markup_strip_html_wrapped(message);
 
// 	std::string msg = striped;
 
// 	g_free(striped);
 

	
 
	std::string message_;
 
	std::string xhtml_;
 

	
 
	if (flags & PURPLE_MESSAGE_IMAGES && !CONFIG_STRING(config, "service.web_directory").empty() && !CONFIG_STRING(config, "service.web_url").empty() ) {
 
		LOG4CXX_INFO(logger, "Received image body='" << msg << "'");
 
		std::string body = msg;
 
		std::string plain = msg;
 
		size_t i;
 
		while ((i = body.find("<img id=\"")) != std::string::npos) {
 
			int from = i + strlen("<img id=\"");
 
			int to = body.find("\"", from + 1);
 
			std::string id = body.substr(from, to - from);
 
			LOG4CXX_INFO(logger, "Image ID = '" << id << "' " << from << " " << to);
 

	
 
			PurpleStoredImage *image = purple_imgstore_find_by_id(atoi(id.c_str()));
 
			if (!image) {
 
				LOG4CXX_ERROR(logger, "Cannot find image with id " << id << ".");
 
				return;
 
			}
 

	
 
	// Escape HTML characters.
 
	char *newline = purple_strdup_withhtml_wrapped(msg);
 
	char *strip, *xhtml;
 
	purple_markup_html_to_xhtml_wrapped(newline, &xhtml, &strip);
 
// 	xhtml_linkified = spectrum_markup_linkify(xhtml);
 
	std::string message_(strip);
 
			std::string ext = "icon";
 
			std::string name;
 
			guchar * data = (guchar *) purple_imgstore_get_data_wrapped(image);
 
			size_t len = purple_imgstore_get_size_wrapped(image);
 
			if (len < 300000 && data) {
 
				ext = purple_imgstore_get_extension(image);
 
				char *hash = calculate_data_hash(data, len, "sha1");
 
				if (!hash) {
 
					return;
 
				}
 
				name = hash;
 
				g_free(hash);
 

	
 
	std::string xhtml_(xhtml);
 
	g_free(newline);
 
	g_free(xhtml);
 
// 	g_free(xhtml_linkified);
 
	g_free(strip);
 
				std::ofstream output;
 
				output.open(std::string(CONFIG_STRING(config, "service.web_directory") + "/" + name + "." + ext).c_str(), std::ios::out | std::ios::binary);
 
				output.write((char *)data, len);
 
				output.close();
 
			}
 
			else {
 
				purple_imgstore_unref_wrapped(image);
 
				return;
 
			}
 
			purple_imgstore_unref_wrapped(image);
 
			
 
			std::string src = CONFIG_STRING(config, "service.web_url") + "/" + name + "." + ext;
 
			std::string img = "<img src=\"" + src + "\"/>";
 
			boost::replace_all(body, "<img id=\"" + id + "\">", img);
 
			boost::replace_all(plain, "<img id=\"" + id + "\">", src);
 
		}
 
		LOG4CXX_INFO(logger, "New image body='" << body << "'");
 
		char *strip, *xhtml;
 
		purple_markup_html_to_xhtml_wrapped(body.c_str(), &xhtml, &strip);
 
		message_ = strip;
 
		if (message_.empty()) {
 
			message_ = plain;
 
		}
 
		xhtml_ = xhtml;
 
		g_free(xhtml);
 
		g_free(strip);
 
	}
 
	else {
 
		// Escape HTML characters.
 
		char *newline = purple_strdup_withhtml_wrapped(msg);
 
		char *strip, *xhtml;
 
		purple_markup_html_to_xhtml_wrapped(newline, &xhtml, &strip);
 
		message_ = strip;
 
		xhtml_ = xhtml;
 
		g_free(newline);
 
		g_free(xhtml);
 
		g_free(strip);
 
	}
 

	
 
	// AIM and XMPP adds <body>...</body> here...
 
	if (xhtml_.find("<body>") == 0) {
 
		xhtml_ = xhtml_.substr(6);
 
		if (xhtml_.find("</body>") != std::string::npos) {
 
			xhtml_ = xhtml_.substr(0, xhtml_.find("</body>"));
 
		}
 
	}
 

	
 
	if (xhtml_ == message_) {
 
		xhtml_ = "";
 
	}
 

	
 
	std::string timestamp;
 
	if (mtime && (unsigned long) time(NULL)-10 > (unsigned long) mtime/* && (unsigned long) time(NULL) - 31536000 < (unsigned long) mtime*/) {
 
		char buf[80];
 
		strftime(buf, sizeof(buf), "%Y%m%dT%H%M%S", gmtime(&mtime));
 
		timestamp = buf;
 
	}
 

	
 
// 	LOG4CXX_INFO(logger, "Received message body='" << message_ << "' xhtml='" << xhtml_ << "'");
 

	
 
	if (purple_conversation_get_type_wrapped(conv) == PURPLE_CONV_TYPE_IM) {
 
		std::string w = purple_normalize_wrapped(account, who);
 
		std::string n;
 
		size_t pos = w.find("/");
 
		if (pos != std::string::npos) {
 
			n = w.substr((int) pos + 1, w.length() - (int) pos);
 
			w.erase((int) pos, w.length() - (int) pos);
 
		}
 
		LOG4CXX_INFO(logger, "Received message body='" << message_ << "' name='" << w);
 
		LOG4CXX_INFO(logger, "Received message body='" << message_ << "' xhtml='" << xhtml_ << "' name='" << w << "'");
 
		np->handleMessage(np->m_accounts[account], w, message_, n, xhtml_, timestamp);
 
	}
 
	else {
 
		LOG4CXX_INFO(logger, "Received message body='" << message_ << "' name='" << purple_conversation_get_name_wrapped(conv) << "' " << who);
 
		LOG4CXX_INFO(logger, "Received message body='" << message_ << "' xhtml='" << xhtml_ << "' name='" << purple_conversation_get_name_wrapped(conv) << "' " << who);
 
		np->handleMessage(np->m_accounts[account], purple_conversation_get_name_wrapped(conv), message_, who, xhtml_, timestamp);
 
	}
 
}
 

	
 
static void conv_chat_add_users(PurpleConversation *conv, GList *cbuddies, gboolean new_arrivals) {
 
	PurpleAccount *account = purple_conversation_get_account_wrapped(conv);
 

	
 
	GList *l = cbuddies;
 
	while (l != NULL) {
 
		PurpleConvChatBuddy *cb = (PurpleConvChatBuddy *)l->data;
 
		std::string name(cb->name);
 
		std::string alias = cb->alias ? cb->alias : cb->name;
 
		int flags = GPOINTER_TO_INT(cb->flags);
 
		if (flags & PURPLE_CBFLAGS_OP || flags & PURPLE_CBFLAGS_HALFOP) {
 
// 			item->addAttribute("affiliation", "admin");
 
// 			item->addAttribute("role", "moderator");
 
			flags = 1;
 
		}
 
		else if (flags & PURPLE_CBFLAGS_FOUNDER) {
 
// 			item->addAttribute("affiliation", "owner");
 
// 			item->addAttribute("role", "moderator");
 
			flags = 1;
 
		}
 
		else {
 
			flags = 0;
 
// 			item->addAttribute("affiliation", "member");
 
// 			item->addAttribute("role", "participant");
 
		}
 

	
 
		np->handleParticipantChanged(np->m_accounts[account], name, purple_conversation_get_name_wrapped(conv), (int) flags, pbnetwork::STATUS_ONLINE, "", "", alias);
 

	
 
		l = l->next;
 
	}
 
}
 

	
 
static void conv_chat_remove_users(PurpleConversation *conv, GList *users) {
 
	PurpleAccount *account = purple_conversation_get_account_wrapped(conv);
 

	
 
	GList *l = users;
 
	while (l != NULL) {
 
		std::string name((char *) l->data);
 
		np->handleParticipantChanged(np->m_accounts[account], name, purple_conversation_get_name_wrapped(conv), 0, pbnetwork::STATUS_NONE);
 

	
 
		l = l->next;
 
	}
 
}
 

	
 
static gboolean conv_has_focus(PurpleConversation *conv) {
 
	return TRUE;
 
}
 

	
 
static void conv_chat_topic_changed(PurpleConversation *conv, const char *who, const char *topic) {
 
	PurpleAccount *account = purple_conversation_get_account_wrapped(conv);
 
	np->handleSubject(np->m_accounts[account], purple_conversation_get_name_wrapped(conv), topic ? topic : "", who ? who : "Spectrum 2");
 
}
 

	
 
static void conv_present(PurpleConversation *conv) {
 
	if (purple_conversation_get_type_wrapped(conv) == PURPLE_CONV_TYPE_CHAT) {
 
		const char *topic = purple_conv_chat_get_topic(PURPLE_CONV_CHAT_WRAPPED(conv));
 
		if (topic && *topic != '\0') {
 
			conv_chat_topic_changed(conv, topic, PURPLE_CONV_CHAT_WRAPPED(conv)->who);
 
		}
 
	}
 
}
 

	
 
static PurpleConversationUiOps conversation_ui_ops =
 
{
 
	NULL,
 
	NULL,
 
	conv_write_im,//conv_write_chat,                              /* write_chat           */
 
	conv_write_im,             /* write_im             */
 
	conv_write,//conv_write_conv,           /* write_conv           */
 
	conv_chat_add_users,       /* chat_add_users       */
 
	NULL,//conv_chat_rename_user,     /* chat_rename_user     */
 
	conv_chat_remove_users,    /* chat_remove_users    */
 
	NULL,//pidgin_conv_chat_update_user,     /* chat_update_user     */
 
	conv_present,//pidgin_conv_present_conversation, /* present              */
 
	conv_has_focus,//pidgin_conv_has_focus,            /* has_focus            */
 
	NULL,//pidgin_conv_custom_smiley_add,    /* custom_smiley_add    */
 
	NULL,//pidgin_conv_custom_smiley_write,  /* custom_smiley_write  */
 
	NULL,//pidgin_conv_custom_smiley_close,  /* custom_smiley_close  */
 
	NULL,//pidgin_conv_send_confirm,         /* send_confirm         */
 
	NULL,
 
	NULL,
 
	NULL,
 
	NULL
 
};
 

	
 
struct Dis {
 
	std::string name;
 
	std::string protocol;
 
};
 

	
 
static gboolean disconnectMe(void *data) {
 
	Dis *d = (Dis *) data;
 
	PurpleAccount *account = purple_accounts_find_wrapped(d->name.c_str(), d->protocol.c_str());
 
	delete d;
 

	
 
	if (account) {
 
		np->handleLogoutRequest(np->m_accounts[account], purple_account_get_username_wrapped(account));
 
	}
 
	return FALSE;
 
}
 

	
 
static gboolean pingTimeout(void *data) {
 
	np->checkPing();
 
	return TRUE;
 
}
 

	
 
static void connection_report_disconnect(PurpleConnection *gc, PurpleConnectionError reason, const char *text){
 
	PurpleAccount *account = purple_connection_get_account_wrapped(gc);
 
	np->handleDisconnected(np->m_accounts[account], (int) reason, text ? text : "");
 
// 	Dis *d = new Dis;
 
// 	d->name = purple_account_get_username_wrapped(account);
 
// 	d->protocol = purple_account_get_protocol_id_wrapped(account);
 
// 	purple_timeout_add_seconds_wrapped(10, disconnectMe, d);
 
}
 

	
 
static PurpleConnectionUiOps conn_ui_ops =
 
{
 
	NULL,
 
	NULL,
 
	NULL,//connection_disconnected,
 
	NULL,
 
	NULL,
 
	NULL,
 
	NULL,
 
	connection_report_disconnect,
 
	NULL,
 
	NULL,
 
	NULL
 
};
 

	
 
static void *notify_user_info(PurpleConnection *gc, const char *who, PurpleNotifyUserInfo *user_info) {
 
	PurpleAccount *account = purple_connection_get_account_wrapped(gc);
 
	std::string name(purple_normalize_wrapped(account, who));
 

	
 
	size_t pos = name.find("/");
 
	if (pos != std::string::npos)
 
		name.erase((int) pos, name.length() - (int) pos);
 

	
 
	
 
	GList *vcardEntries = purple_notify_user_info_get_entries_wrapped(user_info);
 
	PurpleNotifyUserInfoEntry *vcardEntry;
 
	std::string firstName;
 
	std::string lastName;
 
	std::string fullName;
 
	std::string nickname;
 
	std::string header;
 
	std::string label;
 
	std::string photo;
 

	
 
	while (vcardEntries) {
 
		vcardEntry = (PurpleNotifyUserInfoEntry *)(vcardEntries->data);
 
		if (purple_notify_user_info_entry_get_label_wrapped(vcardEntry) && purple_notify_user_info_entry_get_value_wrapped(vcardEntry)){
 
			label = purple_notify_user_info_entry_get_label_wrapped(vcardEntry);
 
			if (label == "Given Name" || label == "First Name") {
 
				firstName = purple_notify_user_info_entry_get_value_wrapped(vcardEntry);
 
			}
 
			else if (label == "Family Name" || label == "Last Name") {
 
				lastName = purple_notify_user_info_entry_get_value_wrapped(vcardEntry);
 
			}
 
			else if (label=="Nickname" || label == "Nick") {
 
				nickname = purple_notify_user_info_entry_get_value_wrapped(vcardEntry);
 
			}
 
			else if (label=="Full Name" || label == "Display name") {
 
				fullName = purple_notify_user_info_entry_get_value_wrapped(vcardEntry);
 
			}
 
			else {
 
				LOG4CXX_WARN(logger, "Unhandled VCard Label '" << purple_notify_user_info_entry_get_label_wrapped(vcardEntry) << "' " << purple_notify_user_info_entry_get_value_wrapped(vcardEntry));
 
			}
 
		}
 
		vcardEntries = vcardEntries->next;
 
	}
 

	
 
	if ((!firstName.empty() || !lastName.empty()) && fullName.empty())
 
		fullName = firstName + " " + lastName;
 

	
 
	if (nickname.empty() && !fullName.empty()) {
 
		nickname = fullName;
 
	}
 

	
 
	bool ownInfo = name == purple_account_get_username_wrapped(account);
 

	
 
	if (ownInfo) {
 
		const gchar *displayname = purple_connection_get_display_name_wrapped(gc);
 
#if PURPLE_MAJOR_VERSION >= 2 && PURPLE_MINOR_VERSION >= 7
 
		if (!displayname) {
 
			displayname = purple_account_get_name_for_display_wrapped(account);
 
		}
 
#endif
 

	
 
		if (displayname && nickname.empty()) {
 
			nickname = displayname;
 
		}
 

	
 
		// avatar
 
		PurpleStoredImage *avatar = purple_buddy_icons_find_account_icon_wrapped(account);
 
		if (avatar) {
 
			const gchar * data = (const gchar *) purple_imgstore_get_data_wrapped(avatar);
 
			size_t len = purple_imgstore_get_size_wrapped(avatar);
 
			if (len < 300000 && data) {
 
				photo = std::string(data, len);
 
			}
 
			purple_imgstore_unref_wrapped(avatar);
 
		}
 
	}
 

	
 
	PurpleBuddy *buddy = purple_find_buddy_wrapped(purple_connection_get_account_wrapped(gc), who);
 
	if (buddy && photo.size() == 0) {
 
		gsize len;
 
		PurpleBuddyIcon *icon = NULL;
 
		icon = purple_buddy_icons_find_wrapped(purple_connection_get_account_wrapped(gc), name.c_str());
 
		if (icon) {
 
			if (true) {
 
				gchar *data;
 
				gchar *path = purple_buddy_icon_get_full_path_wrapped(icon);
 
				if (path) {
 
					if (g_file_get_contents(path, &data, &len, NULL)) {
 
						photo = std::string(data, len);
 
						g_free(data);
 
					}
 
					g_free(path);
 
				}
 
			}
 
			else {
 
				const gchar * data = (gchar*)purple_buddy_icon_get_data_wrapped(icon, &len);
 
				if (len < 300000 && data) {
 
					photo = std::string(data, len);
 
				}
 
			}
 
			purple_buddy_icon_unref_wrapped(icon);
 
		}
 
	}
 

	
 
	np->handleVCard(np->m_accounts[account], np->m_vcards[np->m_accounts[account] + name], name, fullName, nickname, photo);
 
	np->m_vcards.erase(np->m_accounts[account] + name);
 

	
 
	return NULL;
 
}
 

	
 
static PurpleNotifyUiOps notifyUiOps =
 
{
 
		NULL,
 
		NULL,
 
		NULL,
 
		NULL,
 
		NULL,
 
		NULL,
 
		notify_user_info,
 
		NULL,
 
		NULL,
 
		NULL,
 
		NULL,
 
		NULL,
 
		NULL
 
};
 

	
 
static PurpleRequestUiOps requestUiOps =
 
{
 
	requestInput,
 
	NULL,
 
	requestAction,
 
	NULL,
 
	NULL,
 
	NULL, //requestClose,
 
	NULL,
 
	NULL,
 
	NULL,
 
	NULL,
 
	NULL
 
};
 

	
 
static void * accountRequestAuth(PurpleAccount *account, const char *remote_user, const char *id, const char *alias, const char *message, gboolean on_list, PurpleAccountRequestAuthorizationCb authorize_cb, PurpleAccountRequestAuthorizationCb deny_cb, void *user_data) {
 
	authRequest *req = new authRequest;
 
	req->authorize_cb = authorize_cb;
 
	req->deny_cb = deny_cb;
 
	req->user_data = user_data;
 
	req->account = account;
 
	req->who = remote_user;
 
	req->mainJID = np->m_accounts[account];
 
	np->m_authRequests[req->mainJID + req->who] = req;
 

	
 
	np->handleAuthorization(req->mainJID, req->who);
 

	
 
	return req;
 
}
 

	
 
static void accountRequestClose(void *data){
 
	authRequest *req = (authRequest *) data;
 
	np->m_authRequests.erase(req->mainJID + req->who);
 
}
 

	
 

	
 
static PurpleAccountUiOps accountUiOps =
 
{
 
	NULL,
 
	NULL,
 
	NULL,
 
	accountRequestAuth,
 
	accountRequestClose,
 
	NULL,
 
	NULL,
 
	NULL,
 
	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, xfer, "", xhtml_);
 
}
 

	
 
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 void xferCanceled(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;
 
	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);
 
	}
 
	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);
 
	}
 
}
 

	
 
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);
libtransport/Config.cpp
Show inline comments
 
/**
 
 * libtransport -- C++ library for easy XMPP Transports development
 
 *
 
 * Copyright (C) 2011, Jan Kaluza <hanzz.k@gmail.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 "transport/Config.h"
 
#include <fstream>
 

	
 
#ifdef _WIN32
 
#include <direct.h>
 
#define getcwd _getcwd
 
#include <windows.h>
 
#ifdef _MSC_VER
 
#define PATH_MAX MAX_PATH
 
#endif
 
#endif
 

	
 
#include "iostream"
 
#include "boost/version.hpp"
 
#include "boost/algorithm/string.hpp"
 

	
 
#define BOOST_MAJOR_VERSION BOOST_VERSION / 100000
 
#define BOOST_MINOR_VERSION BOOST_VERSION / 100 % 1000
 

	
 
using namespace boost::program_options;
 

	
 
namespace Transport {
 
static int getRandomPort(const std::string &s) {
 
	unsigned long r = 0;
 
	BOOST_FOREACH(char c, s) {
 
		r += (int) c;
 
	}
 
	srand(time(NULL) + r);
 
	return 30000 + rand() % 10000;
 
}
 

	
 
bool Config::load(const std::string &configfile, boost::program_options::options_description &opts, const std::string &jid) {
 
	std::ifstream ifs(configfile.c_str());
 
	if (!ifs.is_open())
 
		return false;
 

	
 
	m_file = configfile;
 
	m_jid = jid;
 
	bool ret = load(ifs, opts, jid);
 
	ifs.close();
 
#ifndef WIN32
 
	char path[PATH_MAX] = "";
 
	if (m_file.find_first_of("/") != 0) {
 
		getcwd(path, PATH_MAX);
 
		m_file = std::string(path) + "/" + m_file;
 
	}
 
#endif
 

	
 
	return ret;
 
}
 

	
 
bool Config::load(std::istream &ifs, boost::program_options::options_description &opts, const std::string &_jid) {
 
	m_unregistered.clear();
 
	opts.add_options()
 
		("service.jid", value<std::string>()->default_value(""), "Transport Jabber ID")
 
		("service.server", value<std::string>()->default_value(""), "Server to connect to")
 
		("service.password", value<std::string>()->default_value(""), "Password used to auth the server")
 
		("service.port", value<int>()->default_value(0), "Port the server is listening on")
 
		("service.user", value<std::string>()->default_value(""), "The name of user Spectrum runs as.")
 
		("service.group", value<std::string>()->default_value(""), "The name of group Spectrum runs as.")
 
		("service.backend", value<std::string>()->default_value("libpurple_backend"), "Backend")
 
		("service.protocol", value<std::string>()->default_value(""), "Protocol")
 
		("service.pidfile", value<std::string>()->default_value("/var/run/spectrum2/$jid.pid"), "Full path to pid file")
 
		("service.portfile", value<std::string>()->default_value("/var/run/spectrum2/$jid.port"), "File to store backend_port to. It's used by spectrum2_manager.")
 
		("service.working_dir", value<std::string>()->default_value("/var/lib/spectrum2/$jid"), "Working dir")
 
		("service.allowed_servers", value<std::vector<std::string> >()->multitoken(), "Only users from these servers can connect")
 
		("service.server_mode", value<bool>()->default_value(false), "True if Spectrum should behave as server")
 
		("service.users_per_backend", value<int>()->default_value(100), "Number of users per one legacy network backend")
 
		("service.backend_host", value<std::string>()->default_value("localhost"), "Host to bind backend server to")
 
		("service.backend_port", value<std::string>()->default_value("0"), "Port to bind backend server to")
 
		("service.cert", value<std::string>()->default_value(""), "PKCS#12 Certificate.")
 
		("service.cert_password", value<std::string>()->default_value(""), "PKCS#12 Certificate password.")
 
		("service.admin_jid", value<std::vector<std::string> >()->multitoken(), "Administrator jid.")
 
		("service.admin_password", value<std::string>()->default_value(""), "Administrator password.")
 
		("service.reuse_old_backends", value<bool>()->default_value(true), "True if Spectrum should use old backends which were full in the past.")
 
		("service.idle_reconnect_time", value<int>()->default_value(0), "Time in seconds after which idle users are reconnected to let their backend die.")
 
		("service.memory_collector_time", value<int>()->default_value(0), "Time in seconds after which backend with most memory is set to die.")
 
		("service.more_resources", value<bool>()->default_value(false), "Allow more resources to be connected in server mode at the same time.")
 
		("service.enable_privacy_lists", value<bool>()->default_value(true), "")
 
		("service.enable_xhtml", value<bool>()->default_value(true), "")
 
		("service.max_room_list_size", value<int>()->default_value(100), "")
 
		("service.login_delay", value<int>()->default_value(0), "")
 
		("service.jid_escaping", value<bool>()->default_value(true), "")
 
		("service.vip_only", value<bool>()->default_value(false), "")
 
		("service.vip_message", value<std::string>()->default_value(""), "")
 
		("service.reconnect_all_users", value<bool>()->default_value(false), "")
 
		("service.web_directory", value<std::string>()->default_value(""), "Full path to directory used to save files to which the links are sent to users.")
 
		("service.web_url", value<std::string>()->default_value(""), "URL on which files in web_directory are accessible.")
 
		("vhosts.vhost", value<std::vector<std::string> >()->multitoken(), "")
 
		("identity.name", value<std::string>()->default_value("Spectrum 2 Transport"), "Name showed in service discovery.")
 
		("identity.category", value<std::string>()->default_value("gateway"), "Disco#info identity category. 'gateway' by default.")
 
		("identity.type", value<std::string>()->default_value(""), "Type of transport ('icq','msn','gg','irc', ...)")
 
		("registration.enable_public_registration", value<bool>()->default_value(true), "True if users should be able to register.")
 
		("registration.language", value<std::string>()->default_value("en"), "Default language for registration form")
 
		("registration.instructions", value<std::string>()->default_value("Enter your legacy network username and password."), "Instructions showed to user in registration form")
 
		("registration.username_label", value<std::string>()->default_value("Legacy network username:"), "Label for username field")
 
		("registration.username_mask", value<std::string>()->default_value(""), "Username mask")
 
		("registration.allowed_usernames", value<std::string>()->default_value(""), "Allowed usernames")
 
		("registration.auto_register", value<bool>()->default_value(false), "Register new user automatically when the presence arrives.")
 
		("registration.encoding", value<std::string>()->default_value("utf8"), "Default encoding in registration form")
 
		("registration.require_local_account", value<bool>()->default_value(false), "True if users have to have a local account to register to this transport from remote servers.")
 
		("registration.notify_jid", value<std::vector<std::string> >()->multitoken(), "Send message to this JID if user registers/unregisters")
 
		("registration.local_username_label", value<std::string>()->default_value("Local username:"), "Label for local usernme field")
 
		("registration.local_account_server", value<std::string>()->default_value("localhost"), "The server on which the local accounts will be checked for validity")
 
		("registration.local_account_server_timeout", value<int>()->default_value(10000), "Timeout when checking local user on local_account_server (msecs)")
 
		("gateway_responder.prompt", value<std::string>()->default_value("Contact ID"), "Value of <prompt> </promt> field")
 
		("gateway_responder.label", value<std::string>()->default_value("Enter legacy network contact ID."), "Label for add contact ID field")
 
		("database.type", value<std::string>()->default_value("none"), "Database type.")
 
		("database.database", value<std::string>()->default_value("/var/lib/spectrum2/$jid/database.sql"), "Database used to store data")
 
		("database.server", value<std::string>()->default_value("localhost"), "Database server.")
 
		("database.user", value<std::string>()->default_value(""), "Database user.")
 
		("database.password", value<std::string>()->default_value(""), "Database Password.")
 
		("database.port", value<int>()->default_value(0), "Database port.")
 
		("database.prefix", value<std::string>()->default_value(""), "Prefix of tables in database")
 
		("database.encryption_key", value<std::string>()->default_value(""), "Encryption key.")
 
		("database.vip_statement", value<std::string>()->default_value(""), "Encryption key.")
 
		("logging.config", value<std::string>()->default_value(""), "Path to log4cxx config file which is used for Spectrum 2 instance")
 
		("logging.backend_config", value<std::string>()->default_value(""), "Path to log4cxx config file which is used for backends")
 
		("backend.default_avatar", value<std::string>()->default_value(""), "Full path to default avatar")
 
		("backend.avatars_directory", value<std::string>()->default_value(""), "Path to directory with avatars")
 
		("backend.no_vcard_fetch", value<bool>()->default_value(false), "True if VCards for buddies should not be fetched. Only avatars will be forwarded.")
 
		("proxy.server", value<std::string>()->default_value("localhost"), "Proxy IP.")
 
		("proxy.user", value<std::string>()->default_value(""), "Proxy user.")
 
		("proxy.password", value<std::string>()->default_value(""), "Proxy Password.")
 
		("proxy.port", value<int>()->default_value(0), "Proxy port.")
 
		("twitter.fetch_timeout", value<int>()->default_value(90000), "Proxy port.")
 

	
 
	;
 

	
 
	parsed_options parsed = parse_config_file(ifs, opts, true);
 

	
 
	bool found_working = false;
 
	bool found_pidfile = false;
 
	bool found_portfile = false;
 
	bool found_backend_port = false;
 
	bool found_database = false;
 
	std::string jid = "";
 
	BOOST_FOREACH(option &opt, parsed.options) {
 
		if (opt.string_key == "service.jid") {
 
			if (_jid.empty()) {
 
				jid = opt.value[0];
 
			}
 
			else {
 
				opt.value[0] = _jid;
 
				jid = _jid;
 
			}
 
		}
 
		else if (opt.string_key == "service.backend_port") {
 
			found_backend_port = true;
 
			if (opt.value[0] == "0") {
 
				opt.value[0] = boost::lexical_cast<std::string>(getRandomPort(_jid.empty() ? jid : _jid));
 
			}
 
		}
 
		else if (opt.string_key == "service.working_dir") {
 
			found_working = true;
 
		}
 
		else if (opt.string_key == "service.pidfile") {
 
			found_pidfile = true;
 
		}
 
		else if (opt.string_key == "service.portfile") {
 
			found_portfile = true;
 
		}
 
		else if (opt.string_key == "database.database") {
 
			found_database = true;
 
		}
 
	}
 

	
 
	if (!found_working) {
 
		std::vector<std::string> value;
 
		value.push_back("/var/lib/spectrum2/$jid");
 
		parsed.options.push_back(boost::program_options::basic_option<char>("service.working_dir", value));
 
	}
 
	if (!found_pidfile) {
 
		std::vector<std::string> value;
 
		value.push_back("/var/run/spectrum2/$jid.pid");
 
		parsed.options.push_back(boost::program_options::basic_option<char>("service.pidfile", value));
 
	}
 
	if (!found_portfile) {
 
		std::vector<std::string> value;
 
		value.push_back("/var/run/spectrum2/$jid.port");
 
		parsed.options.push_back(boost::program_options::basic_option<char>("service.portfile", value));
 
	}
 
	if (!found_backend_port) {
 
		std::vector<std::string> value;
 
		std::string p = boost::lexical_cast<std::string>(getRandomPort(_jid.empty() ? jid : _jid));
 
		value.push_back(p);
 
		parsed.options.push_back(boost::program_options::basic_option<char>("service.backend_port", value));
 
	}
 
	if (!found_database) {
 
		std::vector<std::string> value;
 
		value.push_back("/var/lib/spectrum2/$jid/database.sql");
 
		parsed.options.push_back(boost::program_options::basic_option<char>("database.database", value));
 
	}
 

	
 
	std::list<std::string> has_key;
 
	BOOST_FOREACH(option &opt, parsed.options) {
 
		if (opt.unregistered) {
 
			if (std::find(has_key.begin(), has_key.end(), opt.string_key) == has_key.end()) {
 
				has_key.push_back(opt.string_key);
 
				m_unregistered[opt.string_key] = variable_value(opt.value[0], false);
 
			}
 
			else {
 
				std::list<std::string> list;
 
				try {
 
					list = m_unregistered[opt.string_key].as<std::list<std::string> >();
 
				}
 
				catch(...) {
 
					list.push_back(m_unregistered[opt.string_key].as<std::string>());
 
				}
 
				
 
				list.push_back(opt.value[0]);
 
				m_unregistered[opt.string_key] = variable_value(list, false);
 
			}
 
		}
 
		else if (opt.value[0].find("$jid") != std::string::npos) {
 
			boost::replace_all(opt.value[0], "$jid", jid);
 
		}
 
	}
 

	
 
	// Load configs passed by command line
 
	if (m_argc != 0 && m_argv) {
 
		basic_command_line_parser<char> parser = command_line_parser(m_argc, m_argv).options(opts).allow_unregistered();
 
		parsed_options parsed = parser.run();
 
		BOOST_FOREACH(option &opt, parsed.options) {
 
			if (opt.unregistered && !opt.value.empty()) {
 
				m_unregistered[opt.string_key] = variable_value(opt.value[0], false);
 
			}
 
		}
 
		store(parsed, m_variables);
 
	}
 

	
 
	store(parsed, m_variables);
 
	notify(m_variables);
 

	
 
	onConfigReloaded();
 

	
 
	return true;
 
}
 

	
 
bool Config::load(std::istream &ifs) {
 
	options_description opts("Transport options");
 
	return load(ifs, opts);
 
}
 

	
 
bool Config::load(const std::string &configfile, const std::string &jid) {
 
	try {
 
		options_description opts("Transport options");
 
		return load(configfile, opts, jid);
 
	} catch ( const boost::program_options::multiple_occurrences& e ) {
 
#if (BOOST_MAJOR_VERSION >= 1 && BOOST_MINOR_VERSION >= 42)
 
		std::cerr << configfile << " parsing error: " << e.what() << " from option: " << e.get_option_name() << std::endl;
 
#else
 
		std::cerr << configfile << " parsing error: " << e.what() << std::endl;
 
#endif
 
		return false;
 
	}
 
}
 

	
 
bool Config::reload() {
 
	if (m_file.empty()) {
 
		return false;
 
	}
 

	
 
	return load(m_file, m_jid);
 
}
 

	
 
Config::SectionValuesCont Config::getSectionValues(const std::string& sectionName) {
 
	SectionValuesCont sectionValues;
 

	
 
	std::string sectionSearchString = sectionName + ".";
 
	BOOST_FOREACH (const Variables::value_type & varItem, m_variables) {
 
		if (boost::istarts_with(varItem.first, sectionSearchString))
 
			sectionValues[varItem.first] = varItem.second;
 
	}
 

	
 
	BOOST_FOREACH (const UnregisteredCont::value_type & varItem, m_unregistered) {
 
		if (boost::istarts_with(varItem.first, sectionSearchString))
 
			sectionValues[varItem.first] = varItem.second;
 
	}
 

	
 
	return sectionValues;
 
}
 

	
 
std::string Config::getCommandLineArgs() const {
 
	std::ostringstream commandLineArgs;
 

	
 
	// Return the command-line arguments that were passed to us originally (but remove the initial .exe part)
 
	for (int i = 1; i < m_argc; ++i) 	{
 
		commandLineArgs << "\"" << m_argv[i] << "\" ";
 
	}
 

	
 
	return commandLineArgs.str();
 
}
 

	
 
void Config::updateBackendConfig(const std::string &backendConfig) {
 
	options_description opts("Backend options");
 
	opts.add_options()
 
		("registration.needPassword", value<bool>()->default_value(true), "")
 
		("registration.needRegistration", value<bool>()->default_value(true), "")
 
		("registration.extraField", value<std::vector<std::string> >()->multitoken(), "")
 
		("features.receipts", value<bool>()->default_value(false), "")
 
		("features.muc", value<bool>()->default_value(false), "")
 
		("features.rawxml", value<bool>()->default_value(false), "")
 
		("features.disable_jid_escaping", value<bool>()->default_value(false), "")
 
		("features.send_buddies_on_login", value<bool>()->default_value(false), "")
 
	;
 

	
 
	std::stringstream ifs(backendConfig);
 
	parsed_options parsed = parse_config_file(ifs, opts, true);
 

	
 
	store(parsed, m_backendConfig);
 
	notify(m_backendConfig);
 

	
 
	onBackendConfigUpdated();
 

	
 
	if (CONFIG_BOOL_DEFAULTED(this, "features.disable_jid_escaping", false)) {
 
		Variables::iterator it(m_variables.find("service.jid_escaping"));
 
		boost::program_options::variable_value& vx(it->second);
 
		vx.value() = false;
 
	}
 
}
 

	
 
Config *Config::createFromArgs(int argc, char **argv, std::string &error, std::string &host, int &port) {
 
	std::string jid;
 
	std::ostringstream os;
 
	std::string configFile;
 
	boost::program_options::variables_map vm;
 
	boost::program_options::options_description desc("Usage: spectrum <config_file.cfg>\nAllowed options");
 
	desc.add_options()
 
		("help", "help")
 
		("host,h", boost::program_options::value<std::string>(&host)->default_value(""), "Host to connect to")
 
		("port,p", boost::program_options::value<int>(&port)->default_value(10000), "Port to connect to")
 
		("no-daemonize,n", "Do not run spectrum as daemon")
 
		("no-debug,d", "Create coredumps on crash")
 
		("jid,j", boost::program_options::value<std::string>(&jid)->default_value(""), "Specify JID of transport manually")
 
		("config", boost::program_options::value<std::string>(&configFile)->default_value(""), "Config file")
 
		;
 

	
 
	os << desc;
 
	try
 
	{
 
		boost::program_options::positional_options_description p;
 
		p.add("config", -1);
 
		boost::program_options::store(boost::program_options::command_line_parser(argc, argv).
 
			options(desc).positional(p).allow_unregistered().run(), vm);
 
		boost::program_options::notify(vm);
 
			
 
		if(vm.count("help"))
 
		{
 
			error = os.str();
 
			return NULL;
 
		}
 

	
 
		if(vm.count("config") == 0) {
 
			error = os.str();
 
			return NULL;
 
		}
 
	}
 
	catch (std::runtime_error& e)
 
	{
 
		error = std::string(e.what()) + "\n" + os.str();
 
		return NULL;
 
	}
 
	catch (...)
 
	{
 
		error = os.str();
 
		return NULL;
 
	}
 

	
 
	Config *config = new Config(argc, argv);
 
	if (!config->load(configFile)) {
 
		error = "Can't open " + configFile + " configuration file.\n";
 
		delete config;
 
		return NULL;
 
	}
 
	return config;
 
}
 

	
 
}
0 comments (0 inline, 0 general)