From d53b3a54337f0aa16d581c59b6002ba1f2aaf9f1 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sun, 27 May 2012 15:35:22 +0200 Subject: [PATCH] libyahoo2 avatars supprot --- backends/libyahoo2/httpfetch.cpp | 159 +++++++++++++++++++++++++ backends/libyahoo2/httpfetch.h | 43 +++++++ backends/libyahoo2/main.cpp | 36 +++++- backends/libyahoo2/yahoolocalaccount.h | 1 + 4 files changed, 236 insertions(+), 3 deletions(-) create mode 100644 backends/libyahoo2/httpfetch.cpp create mode 100644 backends/libyahoo2/httpfetch.h diff --git a/backends/libyahoo2/httpfetch.cpp b/backends/libyahoo2/httpfetch.cpp new file mode 100644 index 00000000..90e52620 --- /dev/null +++ b/backends/libyahoo2/httpfetch.cpp @@ -0,0 +1,159 @@ + +#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 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 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 conn, boost::shared_ptr 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 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; +} diff --git a/backends/libyahoo2/httpfetch.h b/backends/libyahoo2/httpfetch.h new file mode 100644 index 00000000..1d9a3899 --- /dev/null +++ b/backends/libyahoo2/httpfetch.h @@ -0,0 +1,43 @@ +#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 + +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 onURLFetched; + + private: + void _connected(boost::shared_ptr conn, const std::string url, bool error); + void _disconnected(boost::shared_ptr conn); + void _read(boost::shared_ptr conn, boost::shared_ptr data); + + Swift::BoostIOServiceThread *m_ioService; + Swift::ConnectionFactory *m_factory; + std::string m_buffer; + bool m_afterHeader; +}; diff --git a/backends/libyahoo2/main.cpp b/backends/libyahoo2/main.cpp index c99bb14c..c6e2c6b4 100644 --- a/backends/libyahoo2/main.cpp +++ b/backends/libyahoo2/main.cpp @@ -12,6 +12,7 @@ #include "yahoohandler.h" #include "yahoolocalaccount.h" +#include "httpfetch.h" // Swiften #include "Swiften/Swiften.h" @@ -155,6 +156,26 @@ class YahooPlugin : public NetworkPlugin { 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 &groups) { } @@ -356,6 +377,7 @@ static void ext_yahoo_status_changed(int id, const char *who, int stat, const ch } yahoo_buddyicon_request(id, who); + np->_yahoo_write_ready(account); np->handleBuddyChanged(account->user, who, "", std::vector(), status, msg ? msg : ""); } @@ -375,7 +397,7 @@ static void ext_yahoo_got_buddies(int id, YList * buds) { 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); } @@ -602,19 +624,27 @@ static void ext_yahoo_got_search_result(int id, int found, int start, int total, } 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,...) diff --git a/backends/libyahoo2/yahoolocalaccount.h b/backends/libyahoo2/yahoolocalaccount.h index ab6c1b17..19eb42c8 100644 --- a/backends/libyahoo2/yahoolocalaccount.h +++ b/backends/libyahoo2/yahoolocalaccount.h @@ -48,6 +48,7 @@ class YahooLocalAccount { int conn_tag; std::map handlers; std::map > handlers_per_conn; + std::map urls; int handler_tag; int status; std::string msg;