Changeset - d53b3a54337f
[Not reviewed]
0 2 2
HanzZ - 13 years ago 2012-05-27 15:35:22
hanzz.k@gmail.com
libyahoo2 avatars supprot
4 files changed with 236 insertions and 3 deletions:
0 comments (0 inline, 0 general)
backends/libyahoo2/httpfetch.cpp
Show inline comments
 
new file 100644
 

	
 
#include "httpfetch.h"
 
#include "transport/logging.h"
 

	
 
DEFINE_LOGGER(logger, "HTTPFetch");
 

	
 
static int url_to_host_port_path(const char *url,
 
	char *host, int *port, char *path, int *ssl)
 
{
 
	char *urlcopy = NULL;
 
	char *slash = NULL;
 
	char *colon = NULL;
 

	
 
	/*
 
	 * http://hostname
 
	 * http://hostname/
 
	 * http://hostname/path
 
	 * http://hostname/path:foo
 
	 * http://hostname:port
 
	 * http://hostname:port/
 
	 * http://hostname:port/path
 
	 * http://hostname:port/path:foo
 
	 * and https:// variants of the above
 
	 */
 

	
 
	if (strstr(url, "http://") == url) {
 
		urlcopy = strdup(url + 7);
 
	} else if (strstr(url, "https://") == url) {
 
		urlcopy = strdup(url + 8);
 
		*ssl = 1;
 
	} else {
 
		return 0;
 
	}
 

	
 
	slash = strchr(urlcopy, '/');
 
	colon = strchr(urlcopy, ':');
 

	
 
	if (!colon || (slash && slash < colon)) {
 
		if (*ssl)
 
			*port = 443;
 
		else
 
			*port = 80;
 
	} else {
 
		*colon = 0;
 
		*port = atoi(colon + 1);
 
	}
 

	
 
	if (!slash) {
 
		strcpy(path, "/");
 
	} else {
 
		strcpy(path, slash);
 
		*slash = 0;
 
	}
 

	
 
	strcpy(host, urlcopy);
 

	
 
	free(urlcopy);
 

	
 
	return 1;
 
}
 

	
 
HTTPFetch::HTTPFetch(Swift::BoostIOServiceThread *ioService, Swift::ConnectionFactory *factory) : m_ioService(ioService), m_factory(factory) {
 
	m_afterHeader = false;
 
}
 

	
 
HTTPFetch::~HTTPFetch() {
 
}
 

	
 
void HTTPFetch::_connected(boost::shared_ptr<Swift::Connection> conn, const std::string url, bool error) {
 
	if (error) {
 
		_disconnected(conn);
 
	}
 
	else {
 
		char host[255];
 
		int port = 80;
 
		char path[255];
 
		int ssl = 0;
 
		if (!url_to_host_port_path(url.c_str(), host, &port, path, &ssl))
 
			return;
 

	
 
		static char buff[2048];
 
		snprintf(buff, sizeof(buff),
 
			"GET %s HTTP/1.1\r\n"
 
			"Host: %s\r\n"
 
			"User-Agent: Mozilla/4.5 [en] (1/1)\r\n"
 
			"Accept: */*\r\n"
 
			"%s" "\r\n", path, host,
 
			"Connection: close\r\n");
 
		LOG4CXX_INFO(logger, "Sending " << buff << "\n");
 
		conn->write(Swift::createSafeByteArray(buff));
 
	}
 
}
 

	
 
void HTTPFetch::_disconnected(boost::shared_ptr<Swift::Connection> conn) {
 
	conn->onConnectFinished.disconnect_all_slots();
 
	conn->onDisconnected.disconnect_all_slots();
 
	conn->onDataRead.disconnect_all_slots();
 

	
 
	if (m_buffer.size() == 0) {
 
		onURLFetched("");
 
	}
 
	else {
 
		std::string img = m_buffer.substr(m_buffer.find("\r\n\r\n") + 4);
 
		onURLFetched(img);
 
	}
 
}
 

	
 
void HTTPFetch::_read(boost::shared_ptr<Swift::Connection> conn, boost::shared_ptr<Swift::SafeByteArray> data) {
 
	std::string d(data->begin(), data->end());
 
// 			std::cout << d << "\n";
 
	std::string img = d.substr(d.find("\r\n\r\n") + 4);
 
	if (d.find("Location: ") == std::string::npos) {
 
		m_buffer += d;
 
	}
 
	else {
 
		d = d.substr(d.find("Location: ") + 10);
 
		if (d.find("\r") == std::string::npos) {
 
			d = d.substr(0, d.find("\n"));
 
		}
 
		else {
 
			d = d.substr(0, d.find("\r"));
 
		}
 
		LOG4CXX_INFO(logger, "Next url is '" << d << "'");
 
		fetchURL(d);
 
		conn->onConnectFinished.disconnect_all_slots();
 
		conn->onDisconnected.disconnect_all_slots();
 
		conn->onDataRead.disconnect_all_slots();
 
	}
 
}
 

	
 
bool HTTPFetch::fetchURL(const std::string &url) {
 
	char host[255];
 
	int port = 80;
 
	char path[255];
 
	char buff[1024];
 
	int ssl = 0;
 
	if (!url_to_host_port_path(url.c_str(), host, &port, path, &ssl)) {
 
		LOG4CXX_ERROR(logger, "Invalid URL " << url);
 
		return false;
 
	}
 

	
 
	LOG4CXX_INFO(logger, "Connecting to " << host << ":" << port);
 

	
 
	boost::asio::ip::tcp::resolver resolver(*m_ioService->getIOService());
 
	boost::asio::ip::tcp::resolver::query query(host, "");
 
	boost::asio::ip::address address;
 
	for(boost::asio::ip::tcp::resolver::iterator i = resolver.resolve(query); i != boost::asio::ip::tcp::resolver::iterator(); ++i) {
 
		boost::asio::ip::tcp::endpoint end = *i;
 
		address = end.address();
 
		break;
 
	}
 

	
 
	boost::shared_ptr<Swift::Connection> conn = m_factory->createConnection();
 
	conn->onConnectFinished.connect(boost::bind(&HTTPFetch::_connected, this, conn, url, _1));
 
	conn->onDisconnected.connect(boost::bind(&HTTPFetch::_disconnected, this, conn));
 
	conn->onDataRead.connect(boost::bind(&HTTPFetch::_read, this, conn, _1));
 
	conn->connect(Swift::HostAddressPort(Swift::HostAddress(address), port));
 
	return true;
 
}
backends/libyahoo2/httpfetch.h
Show inline comments
 
new file 100644
 
#pragma once
 

	
 
// Transport includes
 
#include "transport/config.h"
 
#include "transport/networkplugin.h"
 
#include "transport/logging.h"
 

	
 
// Swiften
 
#include "Swiften/Swiften.h"
 
#include "Swiften/TLS/OpenSSL/OpenSSLContextFactory.h"
 

	
 
// for signal handler
 
#include "unistd.h"
 
#include "signal.h"
 
#include "sys/wait.h"
 
#include "sys/signal.h"
 

	
 
// Boost
 
#include <boost/algorithm/string.hpp>
 

	
 
using namespace boost::filesystem;
 
using namespace boost::program_options;
 
using namespace Transport;
 

	
 
class HTTPFetch {
 
	public:
 
		HTTPFetch(Swift::BoostIOServiceThread *ioSerice, Swift::ConnectionFactory *factory);
 
		virtual ~HTTPFetch();
 

	
 
		bool fetchURL(const std::string &url);
 

	
 
		boost::signal<void (const std::string &data)> onURLFetched;
 

	
 
	private:
 
		void _connected(boost::shared_ptr<Swift::Connection> conn, const std::string url, bool error);
 
		void _disconnected(boost::shared_ptr<Swift::Connection> conn);
 
		void _read(boost::shared_ptr<Swift::Connection> conn, boost::shared_ptr<Swift::SafeByteArray> data);
 

	
 
		Swift::BoostIOServiceThread *m_ioService;
 
		Swift::ConnectionFactory *m_factory;
 
		std::string m_buffer;
 
		bool m_afterHeader;
 
};
backends/libyahoo2/main.cpp
Show inline comments
 
// Transport includes
 
#include "transport/config.h"
 
#include "transport/networkplugin.h"
 
#include "transport/logging.h"
 

	
 
// Yahoo2
 
#include <yahoo2.h>
 
#include <yahoo2_callbacks.h>
 
#include <stdio.h>
 
#include <stdarg.h>
 
#include <stdlib.h>
 

	
 
#include "yahoohandler.h"
 
#include "yahoolocalaccount.h"
 
#include "httpfetch.h"
 

	
 
// Swiften
 
#include "Swiften/Swiften.h"
 
#include "Swiften/TLS/OpenSSL/OpenSSLContextFactory.h"
 

	
 
// for signal handler
 
#include "unistd.h"
 
#include "signal.h"
 
#include "sys/wait.h"
 
#include "sys/signal.h"
 

	
 
// Boost
 
#include <boost/algorithm/string.hpp>
 
using namespace boost::filesystem;
 
using namespace boost::program_options;
 
using namespace Transport;
 

	
 
class YahooHandler;
 
class YahooLocalAccount;
 

	
 
static std::string *currently_read_data;
 
static YahooLocalAccount *currently_writting_account;
 

	
 
YahooHandler::YahooHandler(YahooLocalAccount *account, int conn_tag, int handler_tag, void *data, yahoo_input_condition cond) :
 
@@ -134,48 +135,68 @@ class YahooPlugin : public NetworkPlugin {
 
		void handleLogoutRequest(const std::string &user, const std::string &legacyName) {
 
			YahooLocalAccount *account = m_users[user];
 
			if (account) {
 
				yahoo_logoff(account->id);
 
				m_ids.erase(account->id);
 
				m_users.erase(user);
 
				delete account;
 
			}
 
		}
 

	
 
		void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "") {
 
			YahooLocalAccount *account = m_users[user];
 
			if (account) {
 
				LOG4CXX_INFO(logger, "Sending message from " << user << " to " << legacyName << ": " << message << ".");
 
				yahoo_send_im(account->id, NULL, legacyName.c_str(), message.c_str(), 0, 0);
 
				_yahoo_write_ready(account);
 
			}
 
		}
 

	
 
		void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector<std::string> &groups) {
 
			LOG4CXX_INFO(logger, user << ": Added buddy " << buddyName << ".");
 
			handleBuddyChanged(user, buddyName, alias, groups, pbnetwork::STATUS_ONLINE);
 
		}
 

	
 
		void _avatar_fetched(HTTPFetch *fetch, int account_id, unsigned int id, const std::string &img) {
 
			handleVCard(m_ids[account_id], id, "", "", "", img);
 
			delete fetch;
 
		}
 

	
 
		void handleVCardRequest(const std::string &user, const std::string &legacyName, unsigned int id) {
 
			YahooLocalAccount *account = m_users[user];
 
			if (!account) {
 
				return;
 
			}
 

	
 
			if (account->urls.find(legacyName) == account->urls.end()) {
 
				return;
 
			}
 

	
 
			HTTPFetch *fetch = new HTTPFetch(&m_boostIOServiceThread, m_factories->getConnectionFactory());
 
			fetch->onURLFetched.connect(boost::bind(&YahooPlugin::_avatar_fetched, this, fetch, account->id, id, _1));
 
			fetch->fetchURL(account->urls[legacyName]);
 
		}
 

	
 
		void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector<std::string> &groups) {
 

	
 
		}
 

	
 
		YahooLocalAccount *getAccount(int id) {
 
			return m_users[m_ids[id]];
 
		}
 

	
 
		void _yahoo_remove_account(YahooLocalAccount *account) {
 
			m_ids.erase(account->id);
 
			m_users.erase(account->user);
 
			delete account;
 
		}
 

	
 
		void _yahoo_connect_finished(YahooLocalAccount *account, yahoo_connect_callback callback, void *data, int conn_tag, bool error) {
 
			currently_writting_account = account;
 
			if (error) {
 
				LOG4CXX_ERROR(logger, account->user << ": Connection error!");
 
				callback(NULL, 0, data);
 
// 				np->handleDisconnected(user, 0, "Connection error.");
 
			}
 
			else {
 
				LOG4CXX_INFO(logger, account->user << ": Connected");
 
				// We will have dangling pointer here, but we can't pass boost::shared_ptr here...
 
@@ -335,68 +356,69 @@ static void ext_yahoo_status_changed(int id, const char *who, int stat, const ch
 
		case YAHOO_STATUS_NOTATHOME:
 
		case YAHOO_STATUS_NOTATDESK:
 
		case YAHOO_STATUS_NOTINOFFICE:
 
		case YAHOO_STATUS_ONPHONE:
 
		case YAHOO_STATUS_ONVACATION:
 
		case YAHOO_STATUS_OUTTOLUNCH:
 
		case YAHOO_STATUS_STEPPEDOUT:
 
			status = pbnetwork::STATUS_AWAY;
 
			break;
 
		case YAHOO_STATUS_BRB:
 
			status = pbnetwork::STATUS_XA;
 
			break;
 
		case YAHOO_STATUS_BUSY:
 
			status = pbnetwork::STATUS_DND;
 
			break;
 
		case YAHOO_STATUS_OFFLINE:
 
			status = pbnetwork::STATUS_NONE;
 
			break;
 
		default:
 
			status = pbnetwork::STATUS_ONLINE;
 
			break;
 
	}
 

	
 
	yahoo_buddyicon_request(id, who);
 
	np->_yahoo_write_ready(account);
 

	
 
	np->handleBuddyChanged(account->user, who, "", std::vector<std::string>(), status, msg ? msg : "");
 
}
 

	
 
static void ext_yahoo_got_buddies(int id, YList * buds) {
 
	YahooLocalAccount *account = np->getAccount(id);
 
	if (!account) {
 
		return;
 
	}
 

	
 
	LOG4CXX_INFO(logger, account->user << ": Got buddy list");
 
	for(; buds; buds = buds->next) {
 
		struct yahoo_buddy *bud = (struct yahoo_buddy *) buds->data;
 

	
 
		std::vector<std::string> groups;
 
		groups.push_back(bud->group);
 
		np->handleBuddyChanged(account->user, bud->id, bud->real_name ? bud->real_name : "", groups, pbnetwork::STATUS_NONE);
 
	}
 

	
 
	yahoo_set_away(id, YAHOO_STATUS_AVAILABLE, "", 1);
 
// 	yahoo_set_away(id, YAHOO_STATUS_AVAILABLE, "", 1);
 
	np->_yahoo_write_ready(account);
 
	np->handleConnected(account->user);
 
}
 

	
 
static void ext_yahoo_got_ignore(int id, YList * igns)
 
{
 
}
 

	
 
static void ext_yahoo_got_buzz(int id, const char *me, const char *who, long tm) {
 
}
 

	
 
static void ext_yahoo_got_im(int id, const char *me, const char *who, const char *msg, long tm, int stat, int utf8) {
 
	YahooLocalAccount *account = np->getAccount(id);
 
	if (!account) {
 
		return;
 
	}
 

	
 
	np->handleMessage(account->user, who, msg);
 
}
 

	
 
static void ext_yahoo_rejected(int id, const char *who, const char *msg) {
 
}
 

	
 
static void ext_yahoo_contact_added(int id, const char *myid, const char *who, const char *msg) {
 
@@ -581,61 +603,69 @@ static void ext_yahoo_file_transfer_done(int id, int response, void *data) {
 

	
 
static char *ext_yahoo_get_ip_addr(const char *domain) {
 
	return NULL;
 
}
 

	
 
static void ext_yahoo_got_ft_data(int id, const unsigned char *in, int count, void *data) {
 
}
 

	
 
static void ext_yahoo_got_identities(int id, YList * ids) {
 
}
 

	
 
static void ext_yahoo_chat_yahoologout(int id, const char *me) {
 
}
 

	
 
static void ext_yahoo_chat_yahooerror(int id, const char *me) {
 
}
 

	
 
static void ext_yahoo_got_ping(int id, const char *errormsg){
 
}
 

	
 
static void ext_yahoo_got_search_result(int id, int found, int start, int total, YList *contacts) {
 
}
 

	
 
static void ext_yahoo_got_buddyicon_checksum(int id, const char *a, const char *b, int checksum) {
 
	LOG4CXX_INFO(logger, "got buddyicon_checksum");
 
}
 

	
 
static void ext_yahoo_got_buddy_change_group(int id, const char *me, const char *who, const char *old_group, const char *new_group) {
 
}
 

	
 
static void ext_yahoo_got_buddyicon(int id, const char *a, const char *b, const char *c, int checksum) {
 
	LOG4CXX_INFO(logger, "got buddyicon " << c);
 
static void ext_yahoo_got_buddyicon(int id, const char *me, const char *who, const char *url, int checksum) {
 
	YahooLocalAccount *account = np->getAccount(id);
 
	if (!account) {
 
		return;
 
	}
 

	
 
	LOG4CXX_INFO(logger, account->user << ": got buddyicon of " << who);
 
	account->urls[who] = url;
 
}
 

	
 
static void ext_yahoo_buddyicon_uploaded(int id, const char *url) {
 
}
 

	
 
static void ext_yahoo_got_buddyicon_request(int id, const char *me, const char *who) {
 
	LOG4CXX_INFO(logger, "got buddyicon_request");
 
}
 

	
 
static int ext_yahoo_log(const char *fmt,...)
 
{
 
	static char log[8192];
 
	static std::string buffered;
 
	va_list ap;
 

	
 
	va_start(ap, fmt);
 

	
 
	vsnprintf(log, 8191, fmt, ap);
 
	buffered += log;
 
	if (buffered.find('\n') != std::string::npos) {
 
		buffered.erase(buffered.find('\n'), 1);
 
		LOG4CXX_INFO(logger, buffered);
 
		buffered.clear();
 
	}
 
	fflush(stderr);
 
	va_end(ap);
 
	return 0;
 
}
 

	
 
static void register_callbacks()
 
{
backends/libyahoo2/yahoolocalaccount.h
Show inline comments
 
@@ -27,29 +27,30 @@
 

	
 
using namespace boost::filesystem;
 
using namespace boost::program_options;
 
using namespace Transport;
 

	
 
class YahooHandler;
 

	
 
class YahooLocalAccount {
 
	public:
 
		YahooLocalAccount(const std::string &user, const std::string &legacyName, const std::string &password);
 
		virtual ~YahooLocalAccount();
 

	
 
		void login();
 

	
 
		void addHandler(YahooHandler *handler);
 
		void removeOldHandlers();
 
		void removeConn(int conn_tag);
 

	
 
		std::string user;
 
		int id;
 
		std::map<int, boost::shared_ptr<Swift::Connection> > conns;
 
		int conn_tag;
 
		std::map<int, YahooHandler *> handlers;
 
		std::map<int, std::map<int, YahooHandler *> > handlers_per_conn;
 
		std::map<std::string, std::string> urls;
 
		int handler_tag;
 
		int status;
 
		std::string msg;
 
		std::string buffer;
 
};
0 comments (0 inline, 0 general)