diff --git a/backends/twitter/TwitterPlugin.cpp b/backends/twitter/TwitterPlugin.cpp index 543e2dbb9c72b051b60f5ceda03a20035759646e..a91d288e7e442748f4956ede6a13be0a9ed54477 100644 --- a/backends/twitter/TwitterPlugin.cpp +++ b/backends/twitter/TwitterPlugin.cpp @@ -1,894 +1,894 @@ -#include "TwitterPlugin.h" -#include "Requests/StatusUpdateRequest.h" -#include "Requests/DirectMessageRequest.h" -#include "Requests/TimelineRequest.h" -#include "Requests/FetchFriends.h" -#include "Requests/HelpMessageRequest.h" -#include "Requests/PINExchangeProcess.h" -#include "Requests/OAuthFlow.h" -#include "Requests/CreateFriendRequest.h" -#include "Requests/DestroyFriendRequest.h" -#include "Requests/RetweetRequest.h" -#include "Requests/ProfileImageRequest.h" -#include "Swiften/StringCodecs/Hexify.h" - -DEFINE_LOGGER(logger, "Twitter Backend"); - -TwitterPlugin *np = NULL; -Swift::SimpleEventLoop *loop_; // Event Loop - -const std::string OLD_APP_KEY = "PCWAdQpyyR12ezp2fVwEhw"; -const std::string OLD_APP_SECRET = "EveLmCXJIg2R7BTCpm6OWV8YyX49nI0pxnYXh7JMvDg"; - -#define abs(x) ((x)<0?-(x):(x)) -#define SHA(x) (Swift::Hexify::hexify(Swift::SHA1::getHash(Swift::createByteArray((x))))) - -//Compares two +ve intergers 'a' and 'b' represented as strings -static int cmp(std::string a, std::string b) -{ - int diff = abs((int)a.size() - (int)b.size()); - if(a.size() < b.size()) a = std::string(diff,'0') + a; - else b = std::string(diff,'0') + b; - - if(a == b) return 0; - if(a < b) return -1; - return 1; -} - - -TwitterPlugin::TwitterPlugin(Config *config, Swift::SimpleEventLoop *loop, StorageBackend *storagebackend, const std::string &host, int port) : NetworkPlugin() -{ - this->config = config; - this->storagebackend = storagebackend; - this->m_firstPing = true; - - if (CONFIG_HAS_KEY(config, "twitter.consumer_key") == false) { - consumerKey = "5mFePMiJi0KpeURONkelg"; - } - else { - consumerKey = CONFIG_STRING(config, "twitter.consumer_key"); - } - if (CONFIG_HAS_KEY(config, "twitter.consumer_secret") == false) { - consumerSecret = "YFZCDJwRhbkccXEnaYr1waCQejTJcOY8F7l5Wim3FA"; - } - else { - consumerSecret = CONFIG_STRING(config, "twitter.consumer_secret"); - } - - if (consumerSecret.empty() || consumerKey.empty()) { - LOG4CXX_ERROR(logger, "Consumer key and Consumer secret can't be empty."); - exit(1); - } - - adminLegacyName = "twitter.com"; - adminChatRoom = "#twitter"; - adminNickName = "twitter"; - adminAlias = "twitter"; - - OAUTH_KEY = "twitter_oauth_token"; - OAUTH_SECRET = "twitter_oauth_secret"; - MODE = "mode"; - - m_factories = new Swift::BoostNetworkFactories(loop); - m_conn = m_factories->getConnectionFactory()->createConnection(); - m_conn->onDataRead.connect(boost::bind(&TwitterPlugin::_handleDataRead, this, _1)); - m_conn->connect(Swift::HostAddressPort(Swift::HostAddress(host), port)); - - tp = new ThreadPool(loop_, 10); - - tweet_timer = m_factories->getTimerFactory()->createTimer(90000); - message_timer = m_factories->getTimerFactory()->createTimer(90000); - - tweet_timer->onTick.connect(boost::bind(&TwitterPlugin::pollForTweets, this)); - message_timer->onTick.connect(boost::bind(&TwitterPlugin::pollForDirectMessages, this)); - - tweet_timer->start(); - message_timer->start(); - - LOG4CXX_INFO(logger, "Starting the plugin."); -} - -TwitterPlugin::~TwitterPlugin() -{ - delete storagebackend; - std::set::iterator it; - for(it = onlineUsers.begin() ; it != onlineUsers.end() ; it++) delete userdb[*it].sessions; - delete tp; -} - -// Send data to NetworkPlugin server -void TwitterPlugin::sendData(const std::string &string) -{ - m_conn->write(Swift::createSafeByteArray(string)); -} - -// Receive date from the NetworkPlugin server and invoke the appropirate payload handler (implement in the NetworkPlugin class) -void TwitterPlugin::_handleDataRead(boost::shared_ptr data) -{ - if (m_firstPing) { - m_firstPing = false; - // Users can join the network without registering if we allow - // one user to connect multiple IRC networks. - NetworkPlugin::PluginConfig cfg; - cfg.setNeedPassword(false); - sendConfig(cfg); - } - - std::string d(data->begin(), data->end()); - handleDataRead(d); -} - -// User trying to login into his twitter account -void TwitterPlugin::handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) -{ - if(userdb.count(user) && (userdb[user].connectionState == NEW || - userdb[user].connectionState == CONNECTED || - userdb[user].connectionState == WAITING_FOR_PIN)) { - LOG4CXX_INFO(logger, std::string("A session corresponding to ") + user + std::string(" is already active")) - return; - } - - LOG4CXX_INFO(logger, std::string("Received login request for ") + user) - initUserSession(user, legacyName, password); - handleConnected(user); - - LOG4CXX_INFO(logger, "SPECTRUM 1 USER? - " << (userdb[user].spectrum1User? "true" : "false")) - - LOG4CXX_INFO(logger, user << ": Adding Buddy " << adminLegacyName << " " << adminAlias) - handleBuddyChanged(user, adminLegacyName, adminAlias, std::vector(), pbnetwork::STATUS_ONLINE); - userdb[user].nickName = ""; - - LOG4CXX_INFO(logger, "Querying database for usersettings of " << user) - std::string key, secret; - getUserOAuthKeyAndSecret(user, key, secret); - - if(key == "" || secret == "") { - LOG4CXX_INFO(logger, "Intiating OAuth Flow for user " << user) - setTwitterMode(user, 0); - tp->runAsThread(new OAuthFlow(np, userdb[user].sessions, user, userdb[user].sessions->getTwitterUsername())); - } else { - LOG4CXX_INFO(logger, user << " is already registerd. Using the stored oauth key and secret") - LOG4CXX_INFO(logger, key << " " << secret) - pinExchangeComplete(user, key, secret); - } -} - -// User logging out -void TwitterPlugin::handleLogoutRequest(const std::string &user, const std::string &legacyName) -{ - if (userdb.count(user)) { - delete userdb[user].sessions; - userdb[user].sessions = NULL; - userdb[user].connectionState = DISCONNECTED; - } - - if(onlineUsers.count(user)) { - onlineUsers.erase(user); - } -} - -// User joining a Chatroom -void TwitterPlugin::handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) -{ - if(room == adminChatRoom) { - LOG4CXX_INFO(logger, "Received Join Twitter room request for " << user) - - setTwitterMode(user, 2); - handleParticipantChanged(user, adminNickName, room, 0, pbnetwork::STATUS_ONLINE); - userdb[user].nickName = nickname; - handleMessage(user, adminChatRoom, "Connected to Twitter room! Populating your followers list", adminNickName); - tp->runAsThread(new FetchFriends(userdb[user].sessions, user, - boost::bind(&TwitterPlugin::populateRoster, this, _1, _2, _3, _4))); - } else { - setTwitterMode(user, 0); - LOG4CXX_ERROR(logger, "Couldn't connect to chatroom - " << room <<"! Try twitter-chatroom as the chatroom to access Twitter account") - handleMessage(user, adminLegacyName, "Couldn't connect to chatroom! Try twitter-chatroom as the chatroom to access Twitter account"); - } -} - -// User leaving a Chatroom -void TwitterPlugin::handleLeaveRoomRequest(const std::string &user, const std::string &room) -{ - if(room == adminChatRoom && onlineUsers.count(user)) { - LOG4CXX_INFO(logger, "Leaving chatroom! Switching back to default mode 0") - setTwitterMode(user, 0); - handleBuddyChanged(user, adminLegacyName, adminAlias, std::vector(), pbnetwork::STATUS_ONLINE); - } -} - -// Messages to be sent to Twitter -void TwitterPlugin::handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml, const std::string &/*id*/) -{ - - LOG4CXX_INFO(logger, "Received " << user << " --> " << legacyName << " - " << message) - - if(legacyName == adminLegacyName || legacyName == adminChatRoom) { - std::string cmd = "", data = ""; - - /** Parsing the message - Assuming message format to be [ ]***/ - int i; - for(i=0 ; irunAsThread(new PINExchangeProcess(np, userdb[user].sessions, user, data)); - else if(cmd == "#help") - tp->runAsThread(new HelpMessageRequest(user, CONFIG_STRING(config, "service.jid"), boost::bind(&TwitterPlugin::helpMessageResponse, this, _1, _2))); - else if(cmd[0] == '@') { - std::string username = cmd.substr(1); - tp->runAsThread(new DirectMessageRequest(userdb[user].sessions, user, username, data, - boost::bind(&TwitterPlugin::directMessageResponse, this, _1, _2, _3, _4))); - } - else if(cmd == "#status") - tp->runAsThread(new StatusUpdateRequest(userdb[user].sessions, user, data, - boost::bind(&TwitterPlugin::statusUpdateResponse, this, _1, _2))); - else if(cmd == "#timeline") - tp->runAsThread(new TimelineRequest(userdb[user].sessions, user, data, "", - boost::bind(&TwitterPlugin::displayTweets, this, _1, _2, _3, _4))); - else if(cmd == "#friends") - tp->runAsThread(new FetchFriends(userdb[user].sessions, user, - boost::bind(&TwitterPlugin::displayFriendlist, this, _1, _2, _3, _4))); - else if(cmd == "#follow") - tp->runAsThread(new CreateFriendRequest(userdb[user].sessions, user, data.substr(0,data.find('@')), - boost::bind(&TwitterPlugin::createFriendResponse, this, _1, _2, _3, _4))); - else if(cmd == "#unfollow") - tp->runAsThread(new DestroyFriendRequest(userdb[user].sessions, user, data.substr(0,data.find('@')), - boost::bind(&TwitterPlugin::deleteFriendResponse, this, _1, _2, _3))); - else if(cmd == "#retweet") - tp->runAsThread(new RetweetRequest(userdb[user].sessions, user, data, - boost::bind(&TwitterPlugin::RetweetResponse, this, _1, _2))); - else if(cmd == "#mode") { - int m = 0; - m = atoi(data.c_str()); - mode prevm = userdb[user].twitterMode; - - if((mode)m == userdb[user].twitterMode) return; //If same as current mode return - if(m < 0 || m > 2) { // Invalid modes - handleMessage(user, adminLegacyName, std::string("Error! Unknown mode ") + data + ". Allowed values 0,1,2." ); - return; - } - - setTwitterMode(user, m); - if((userdb[user].twitterMode == SINGLECONTACT || userdb[user].twitterMode == CHATROOM) && prevm == MULTIPLECONTACT) clearRoster(user); - else if(userdb[user].twitterMode == MULTIPLECONTACT) - tp->runAsThread(new FetchFriends(userdb[user].sessions, user, boost::bind(&TwitterPlugin::populateRoster, this, _1, _2, _3, _4))); - - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - std::string("Changed mode to ") + data, userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - - LOG4CXX_INFO(logger, user << ": Changed mode to " << data << " <" << (userdb[user].twitterMode == CHATROOM ? adminNickName : "") << ">" ) - } - - else if(userdb[user].twitterMode == CHATROOM) { - std::string buddy = message.substr(0, message.find(":")); - if(userdb[user].buddies.count(buddy) == 0) { - tp->runAsThread(new StatusUpdateRequest(userdb[user].sessions, user, message, - boost::bind(&TwitterPlugin::statusUpdateResponse, this, _1, _2))); - } else { - data = message.substr(message.find(":")+1); //Can parse better??:P - tp->runAsThread(new DirectMessageRequest(userdb[user].sessions, user, buddy, data, - boost::bind(&TwitterPlugin::directMessageResponse, this, _1, _2, _3, _4))); - } - } - else handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - "Unknown command! Type #help for a list of available commands.", userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - } - - else { - std::string buddy = legacyName; - if(userdb[user].twitterMode == CHATROOM) buddy = legacyName.substr(legacyName.find("/") + 1); - if(legacyName != "twitter") { - tp->runAsThread(new DirectMessageRequest(userdb[user].sessions, user, buddy, message, - boost::bind(&TwitterPlugin::directMessageResponse, this, _1, _2, _3, _4))); - } - } -} - -void TwitterPlugin::handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups) -{ - if(userdb[user].connectionState != CONNECTED) { - LOG4CXX_ERROR(logger, user << " is not connected to twitter!") - return; - } - - LOG4CXX_INFO(logger, user << " - Adding Twitter contact " << buddyName) - tp->runAsThread(new CreateFriendRequest(userdb[user].sessions, user, buddyName, - boost::bind(&TwitterPlugin::createFriendResponse, this, _1, _2, _3, _4))); -} - -void TwitterPlugin::handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector &groups) -{ - if(userdb[user].connectionState != CONNECTED) { - LOG4CXX_ERROR(logger, user << " is not connected to twitter!") - return; - } - - LOG4CXX_INFO(logger, user << " - Removing Twitter contact " << buddyName) - tp->runAsThread(new DestroyFriendRequest(userdb[user].sessions, user, buddyName, - boost::bind(&TwitterPlugin::deleteFriendResponse, this, _1, _2, _3))); -} - -void TwitterPlugin::handleVCardRequest(const std::string &user, const std::string &legacyName, unsigned int id) -{ - if(userdb[user].connectionState != CONNECTED) { - LOG4CXX_ERROR(logger, user << " is not connected to twitter!") - return; - } - - LOG4CXX_INFO(logger, user << " - VCardRequest for " << legacyName << ", " << userdb[user].buddiesInfo[legacyName].getProfileImgURL()) - - if(getTwitterMode(user) != SINGLECONTACT && userdb[user].buddies.count(legacyName) - && userdb[user].buddiesInfo[legacyName].getProfileImgURL().length()) { - if(userdb[user].buddiesImgs.count(legacyName) == 0) { - tp->runAsThread(new ProfileImageRequest(config, user, legacyName, userdb[user].buddiesInfo[legacyName].getProfileImgURL(), id, - boost::bind(&TwitterPlugin::profileImageResponse, this, _1, _2, _3, _4, _5))); - } - handleVCard(user, id, legacyName, legacyName, "", userdb[user].buddiesImgs[legacyName]); - } -} - -void TwitterPlugin::pollForTweets() -{ - boost::mutex::scoped_lock lock(userlock); - std::set::iterator it = onlineUsers.begin(); - while(it != onlineUsers.end()) { - std::string user = *it; - tp->runAsThread(new TimelineRequest(userdb[user].sessions, user, "", getMostRecentTweetIDUnsafe(user), - boost::bind(&TwitterPlugin::displayTweets, this, _1, _2, _3, _4))); - it++; - } - tweet_timer->start(); -} - -void TwitterPlugin::pollForDirectMessages() -{ - boost::mutex::scoped_lock lock(userlock); - std::set::iterator it = onlineUsers.begin(); - while(it != onlineUsers.end()) { - std::string user = *it; - tp->runAsThread(new DirectMessageRequest(userdb[user].sessions, user, "", getMostRecentDMIDUnsafe(user), - boost::bind(&TwitterPlugin::directMessageResponse, this, _1, _2, _3, _4))); - it++; - } - message_timer->start(); -} - - -bool TwitterPlugin::getUserOAuthKeyAndSecret(const std::string user, std::string &key, std::string &secret) -{ - boost::mutex::scoped_lock lock(dblock); - - UserInfo info; - if(storagebackend->getUser(user, info) == false) { - LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") - return false; - } - - key="", secret=""; int type; - storagebackend->getUserSetting((long)info.id, OAUTH_KEY, type, key); - storagebackend->getUserSetting((long)info.id, OAUTH_SECRET, type, secret); - return true; -} - -bool TwitterPlugin::checkSpectrum1User(const std::string user) -{ - boost::mutex::scoped_lock lock(dblock); - - UserInfo info; - if(storagebackend->getUser(user, info) == false) { - LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") - return false; - } - - std::string first_synchronization_done = ""; - int type; - storagebackend->getUserSetting((long)info.id, "first_synchronization_done", type, first_synchronization_done); - - LOG4CXX_INFO(logger, "first_synchronization_done: " << first_synchronization_done) - - if(first_synchronization_done.length()) return true; - return false; -} - -int TwitterPlugin::getTwitterMode(const std::string user) -{ - boost::mutex::scoped_lock lock(dblock); - - UserInfo info; - if(storagebackend->getUser(user, info) == false) { - LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") - return -1; - } - - int type; int m; - std::string s_m; - storagebackend->getUserSetting((long)info.id, MODE, type, s_m); - if(s_m == "") { - s_m = "0"; - storagebackend->updateUserSetting((long)info.id, MODE, s_m); - } - m = atoi(s_m.c_str()); - return m; -} - -bool TwitterPlugin::setTwitterMode(const std::string user, int m) -{ - boost::mutex::scoped_lock lock(dblock); - - UserInfo info; - if(storagebackend->getUser(user, info) == false) { - LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") - return false; - } - - if(m < 0 || m > 2) { - LOG4CXX_ERROR(logger, "Unknown mode " << m <<". Using default mode 0") - m = 0; - } - - userdb[user].twitterMode = (mode)m; - - //int type; - std::string s_m = std::string(1,m+'0'); - LOG4CXX_ERROR(logger, "Storing mode " << m <<" for user " << user) - storagebackend->updateUserSetting((long)info.id, MODE, s_m); - return true; -} - -bool TwitterPlugin::storeUserOAuthKeyAndSecret(const std::string user, const std::string OAuthKey, const std::string OAuthSecret) -{ - - boost::mutex::scoped_lock lock(dblock); - - UserInfo info; - if(storagebackend->getUser(user, info) == false) { - LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") - return false; - } - - storagebackend->updateUserSetting((long)info.id, OAUTH_KEY, OAuthKey); - storagebackend->updateUserSetting((long)info.id, OAUTH_SECRET, OAuthSecret); - return true; -} - -void TwitterPlugin::initUserSession(const std::string user, const std::string legacyName, const std::string password) -{ - boost::mutex::scoped_lock lock(userlock); - - std::string username = legacyName; - std::string passwd = password; - LOG4CXX_INFO(logger, username + " " + passwd) - - userdb[user].sessions = new twitCurl(); - if(CONFIG_HAS_KEY(config,"proxy.server")) { - std::string ip = CONFIG_STRING(config,"proxy.server"); - - std::ostringstream out; - out << CONFIG_INT(config,"proxy.port"); - std::string port = out.str(); - - std::string puser = CONFIG_STRING(config,"proxy.user"); - std::string ppasswd = CONFIG_STRING(config,"proxy.password"); - - LOG4CXX_INFO(logger, ip << " " << port << " " << puser << " " << ppasswd) - - if(ip != "localhost" && port != "0") { - userdb[user].sessions->setProxyServerIp(ip); - userdb[user].sessions->setProxyServerPort(port); - userdb[user].sessions->setProxyUserName(puser); - userdb[user].sessions->setProxyPassword(ppasswd); - } - } - - //Check if the user is spectrum1 user - userdb[user].spectrum1User = checkSpectrum1User(user); - - userdb[user].connectionState = NEW; - userdb[user].legacyName = username; - userdb[user].sessions->setTwitterUsername(username); - userdb[user].sessions->setTwitterPassword(passwd); - - if(!userdb[user].spectrum1User) { - userdb[user].sessions->getOAuth().setConsumerKey(consumerKey); - userdb[user].sessions->getOAuth().setConsumerSecret(consumerSecret); - } else { - userdb[user].sessions->getOAuth().setConsumerKey(OLD_APP_KEY); - userdb[user].sessions->getOAuth().setConsumerSecret(OLD_APP_SECRET); - } -} - -void TwitterPlugin::OAuthFlowComplete(const std::string user, twitCurl *obj) -{ - boost::mutex::scoped_lock lock(userlock); - - delete userdb[user].sessions; - userdb[user].sessions = obj->clone(); - userdb[user].connectionState = WAITING_FOR_PIN; -} - -void TwitterPlugin::pinExchangeComplete(const std::string user, const std::string OAuthAccessTokenKey, const std::string OAuthAccessTokenSecret) -{ - boost::mutex::scoped_lock lock(userlock); - - userdb[user].sessions->getOAuth().setOAuthTokenKey( OAuthAccessTokenKey ); - userdb[user].sessions->getOAuth().setOAuthTokenSecret( OAuthAccessTokenSecret ); - userdb[user].connectionState = CONNECTED; - userdb[user].twitterMode = (mode)getTwitterMode(user); - - if(userdb[user].twitterMode == MULTIPLECONTACT) { - tp->runAsThread(new FetchFriends(userdb[user].sessions, user, boost::bind(&TwitterPlugin::populateRoster, this, _1, _2, _3, _4))); - } - - onlineUsers.insert(user); - userdb[user].mostRecentTweetID = ""; - userdb[user].mostRecentDirectMessageID = ""; -} - -void TwitterPlugin::updateLastTweetID(const std::string user, const std::string ID) -{ - boost::mutex::scoped_lock lock(userlock); - userdb[user].mostRecentTweetID = ID; - - UserInfo info; - if(storagebackend->getUser(user, info) == false) { - LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") - return; - } - - storagebackend->updateUserSetting((long)info.id, "twitter_last_tweet", ID); -} - -std::string TwitterPlugin::getMostRecentTweetIDUnsafe(const std::string user) -{ - std::string ID = ""; - if(onlineUsers.count(user)) { - ID = userdb[user].mostRecentTweetID; - if (ID.empty()) { - int type; - UserInfo info; - if(storagebackend->getUser(user, info) == false) { - LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") - } - else { - storagebackend->getUserSetting(info.id, "twitter_last_tweet", type, ID); - } - } - } - return ID; -} - -std::string TwitterPlugin::getMostRecentTweetID(const std::string user) -{ - boost::mutex::scoped_lock lock(userlock); - return getMostRecentTweetIDUnsafe(user); -} - -void TwitterPlugin::updateLastDMID(const std::string user, const std::string ID) -{ - boost::mutex::scoped_lock lock(userlock); - userdb[user].mostRecentDirectMessageID = ID; - - UserInfo info; - if(storagebackend->getUser(user, info) == false) { - LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") - return; - } - - storagebackend->updateUserSetting((long)info.id, "twitter_last_dm", ID); -} - -std::string TwitterPlugin::getMostRecentDMIDUnsafe(const std::string user) { - std::string ID = ""; - if(onlineUsers.count(user)) { - ID = userdb[user].mostRecentDirectMessageID; - if (ID.empty()) { - int type; - UserInfo info; - if(storagebackend->getUser(user, info) == false) { - LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") - } - else { - storagebackend->getUserSetting(info.id, "twitter_last_dm", type, ID); - } - } - } - return ID; -} - -std::string TwitterPlugin::getMostRecentDMID(const std::string user) -{ - boost::mutex::scoped_lock lock(userlock); - return getMostRecentDMIDUnsafe(user); -} - -/************************************** Twitter response functions **********************************/ -void TwitterPlugin::statusUpdateResponse(std::string &user, Error &errMsg) -{ - if(errMsg.getMessage().length()) { - if (errMsg.isCurlError()) { - handleDisconnected(user, 3, errMsg.getMessage()); - return; - } - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - } else { - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - "Status Update successful", userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - } -} - -void TwitterPlugin::helpMessageResponse(std::string &user, std::string &msg) -{ - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - msg, userdb[user].twitterMode == CHATROOM ? adminNickName : ""); -} - -void TwitterPlugin::clearRoster(const std::string user) -{ - if(userdb[user].buddies.size() == 0) return; - std::set::iterator it = userdb[user].buddies.begin(); - while(it != userdb[user].buddies.end()) { - handleBuddyRemoved(user, *it); - it++; - } - userdb[user].buddies.clear(); -} - -void TwitterPlugin::populateRoster(std::string &user, std::vector &friends, std::vector &friendAvatars, Error &errMsg) -{ - if(errMsg.getMessage().length() == 0) - { - for(int i=0 ; i(), -#if HAVE_SWIFTEN_3 - pbnetwork::STATUS_ONLINE, lastTweet, Swift::byteArrayToString(cryptoProvider->getSHA1Hash(Swift::createByteArray(friendAvatars[i])))); -#else - pbnetwork::STATUS_ONLINE, lastTweet, SHA(friendAvatars[i])); -#endif - } - else if(userdb[user].twitterMode == CHATROOM) - handleParticipantChanged(user, friends[i].getScreenName(), adminChatRoom, 0, pbnetwork::STATUS_ONLINE); - - /*handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - friends[i].getScreenName() + " - " + friends[i].getLastStatus().getTweet(), - userdb[user].twitterMode == CHATROOM ? adminNickName : "");*/ - } - } else { - if (errMsg.isCurlError()) { - handleDisconnected(user, 3, errMsg.getMessage()); - return; - } - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - std::string("Error populating roster - ") + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - } - - if(userdb[user].twitterMode == CHATROOM) handleParticipantChanged(user, userdb[user].nickName, adminChatRoom, 0, pbnetwork::STATUS_ONLINE); -} - -void TwitterPlugin::displayFriendlist(std::string &user, std::vector &friends, std::vector &friendAvatars, Error &errMsg) -{ - if(errMsg.getMessage().length() == 0) - { - std::string userlist = "\n***************USER LIST****************\n"; - for(int i=0 ; i < friends.size() ; i++) { - userlist += " - " + friends[i].getUserName() + " (" + friends[i].getScreenName() + ")\n"; - } - userlist += "***************************************\n"; - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - userlist, userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - } else { - if (errMsg.isCurlError()) { - handleDisconnected(user, 3, errMsg.getMessage()); - return; - } - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - } - -} - -void TwitterPlugin::displayTweets(std::string &user, std::string &userRequested, std::vector &tweets , Error &errMsg) -{ - if(errMsg.getMessage().length() == 0) { - std::map lastTweet; - std::map::iterator it; - - for(int i = tweets.size() - 1 ; i >= 0 ; i--) { - if(userdb[user].twitterMode != CHATROOM) { - std::string m = " - " + tweets[i].getUserData().getScreenName() + ": " + tweets[i].getTweet() + " (MsgId: " + (tweets[i].getRetweetID().empty() ? tweets[i].getID() : tweets[i].getRetweetID()) + ")\n"; - handleMessage(user, adminLegacyName, m, "", "", tweets[i].getCreationTime(), true); - - std::string scrname = tweets[i].getUserData().getScreenName(); - if(lastTweet.count(scrname) == 0 || cmp(tweets[lastTweet[scrname]].getID(), tweets[i].getID()) <= 0) lastTweet[scrname] = i; - - } else { - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - tweets[i].getTweet() + " (MsgId: " + (tweets[i].getRetweetID().empty() ? tweets[i].getID() : tweets[i].getRetweetID()) + ")", tweets[i].getUserData().getScreenName(), "", tweets[i].getCreationTime(), true); - } - } - - if(userdb[user].twitterMode == MULTIPLECONTACT) { - //Set as status user's last tweet - for(it=lastTweet.begin() ; it!=lastTweet.end() ; it++) { - int t = it->second; - handleBuddyChanged(user, tweets[t].getUserData().getScreenName(), tweets[t].getUserData().getUserName(), - std::vector(), pbnetwork::STATUS_ONLINE, tweets[t].getTweet()); - } - } - - if((userRequested == "" || userRequested == user) && tweets.size()) { - std::string tweetID = getMostRecentTweetID(user); - if(tweetID != tweets[0].getID()) updateLastTweetID(user, tweets[0].getID()); - } - - } else { - if (errMsg.isCurlError()) { - handleDisconnected(user, 3, errMsg.getMessage()); - return; - } - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - } -} - -void TwitterPlugin::directMessageResponse(std::string &user, std::string &username, std::vector &messages, Error &errMsg) -{ - if(errMsg.getCode() == "93") //Permission Denied - return; - - if(errMsg.getMessage().length()) { - if (errMsg.isCurlError()) { - handleDisconnected(user, 3, errMsg.getMessage()); - return; - } - - if(username != "") - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - std::string("Error while sending direct message! - ") + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - else - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - std::string("Error while fetching direct messages! - ") + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - return; - } - - if(username != "") { - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - "Message delivered!", userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - return; - } - - if(!messages.size()) return; - - if(userdb[user].twitterMode == SINGLECONTACT) { - - std::string msglist = ""; - std::string msgID = getMostRecentDMID(user); - std::string maxID = msgID; - - for(int i=0 ; i < messages.size() ; i++) { - if(cmp(msgID, messages[i].getID()) == -1) { - msglist += " - " + messages[i].getSenderData().getScreenName() + ": " + messages[i].getMessage() + "\n"; - if(cmp(maxID, messages[i].getID()) == -1) maxID = messages[i].getID(); - } - } - - if(msglist.length()) handleMessage(user, adminLegacyName, msglist, ""); - updateLastDMID(user, maxID); - - } else { - - std::string msgID = getMostRecentDMID(user); - std::string maxID = msgID; - - for(int i=0 ; i < messages.size() ; i++) { - if(cmp(msgID, messages[i].getID()) == -1) { - if(userdb[user].twitterMode == MULTIPLECONTACT) - handleMessage(user, messages[i].getSenderData().getScreenName(), messages[i].getMessage(), ""); - else - handleMessage(user, adminChatRoom, messages[i].getMessage() + " - ", messages[i].getSenderData().getScreenName()); - if(cmp(maxID, messages[i].getID()) == -1) maxID = messages[i].getID(); - } - } - - if(maxID == getMostRecentDMID(user)) LOG4CXX_INFO(logger, "No new direct messages for " << user) - updateLastDMID(user, maxID); - } -} - -void TwitterPlugin::createFriendResponse(std::string &user, User &frnd, std::string &img, Error &errMsg) -{ - if(errMsg.getMessage().length()) { - if (errMsg.isCurlError()) { - handleDisconnected(user, 3, errMsg.getMessage()); - return; - } - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - return; - } - - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - std::string("You are now following ") + frnd.getScreenName(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - - userdb[user].buddies.insert(frnd.getScreenName()); - userdb[user].buddiesInfo[frnd.getScreenName()] = frnd; - userdb[user].buddiesImgs[frnd.getScreenName()] = img; - - LOG4CXX_INFO(logger, user << " - " << frnd.getScreenName() << ", " << frnd.getProfileImgURL()) - if(userdb[user].twitterMode == MULTIPLECONTACT) { -#if HAVE_SWIFTEN_3 - handleBuddyChanged(user, frnd.getScreenName(), frnd.getUserName(), std::vector(), pbnetwork::STATUS_ONLINE, "", Swift::byteArrayToString(cryptoProvider->getSHA1Hash(Swift::createByteArray(img)))); -#else - handleBuddyChanged(user, frnd.getScreenName(), frnd.getUserName(), std::vector(), pbnetwork::STATUS_ONLINE, "", SHA(img)); -#endif - } else if(userdb[user].twitterMode == CHATROOM) { - handleParticipantChanged(user, frnd.getScreenName(), adminChatRoom, 0, pbnetwork::STATUS_ONLINE); - } -} - -void TwitterPlugin::deleteFriendResponse(std::string &user, User &frnd, Error &errMsg) -{ - if(errMsg.getMessage().length()) { - if (errMsg.isCurlError()) { - handleDisconnected(user, 3, errMsg.getMessage()); - return; - } - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - return; - } - - LOG4CXX_INFO(logger, user << " - " << frnd.getScreenName() << ", " << frnd.getProfileImgURL()) - userdb[user].buddies.erase(frnd.getScreenName()); - - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - std::string("You are not following ") + frnd.getScreenName() + " anymore", userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - - if (userdb[user].twitterMode == CHATROOM) { - handleParticipantChanged(user, frnd.getScreenName(), adminLegacyName, 0, pbnetwork::STATUS_NONE); - } - - if(userdb[user].twitterMode == MULTIPLECONTACT) { - handleBuddyRemoved(user, frnd.getScreenName()); - } -} - - -void TwitterPlugin::RetweetResponse(std::string &user, Error &errMsg) -{ - if(errMsg.getMessage().length()) { - if (errMsg.isCurlError()) { - handleDisconnected(user, 3, errMsg.getMessage()); - return; - } - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - } else { - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - "Retweet successful", userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - } -} - -void TwitterPlugin::profileImageResponse(std::string &user, std::string &buddy, std::string &img, unsigned int reqID, Error &errMsg) -{ - if(errMsg.getMessage().length()) { - if (errMsg.isCurlError()) { - handleDisconnected(user, 3, errMsg.getMessage()); - return; - } - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - } else { - LOG4CXX_INFO(logger, user << " - Sending VCard for " << buddy) - handleVCard(user, reqID, buddy, buddy, "", img); - } -} +#include "TwitterPlugin.h" +#include "Requests/StatusUpdateRequest.h" +#include "Requests/DirectMessageRequest.h" +#include "Requests/TimelineRequest.h" +#include "Requests/FetchFriends.h" +#include "Requests/HelpMessageRequest.h" +#include "Requests/PINExchangeProcess.h" +#include "Requests/OAuthFlow.h" +#include "Requests/CreateFriendRequest.h" +#include "Requests/DestroyFriendRequest.h" +#include "Requests/RetweetRequest.h" +#include "Requests/ProfileImageRequest.h" +#include "Swiften/StringCodecs/Hexify.h" + +DEFINE_LOGGER(logger, "Twitter Backend"); + +TwitterPlugin *np = NULL; +Swift::SimpleEventLoop *loop_; // Event Loop + +const std::string OLD_APP_KEY = "PCWAdQpyyR12ezp2fVwEhw"; +const std::string OLD_APP_SECRET = "EveLmCXJIg2R7BTCpm6OWV8YyX49nI0pxnYXh7JMvDg"; + +#define abs(x) ((x)<0?-(x):(x)) +#define SHA(x) (Swift::Hexify::hexify(Swift::SHA1::getHash(Swift::createByteArray((x))))) + +//Compares two +ve intergers 'a' and 'b' represented as strings +static int cmp(std::string a, std::string b) +{ + int diff = abs((int)a.size() - (int)b.size()); + if(a.size() < b.size()) a = std::string(diff,'0') + a; + else b = std::string(diff,'0') + b; + + if(a == b) return 0; + if(a < b) return -1; + return 1; +} + + +TwitterPlugin::TwitterPlugin(Config *config, Swift::SimpleEventLoop *loop, StorageBackend *storagebackend, const std::string &host, int port) : NetworkPlugin() +{ + this->config = config; + this->storagebackend = storagebackend; + this->m_firstPing = true; + + if (CONFIG_HAS_KEY(config, "twitter.consumer_key") == false) { + consumerKey = "5mFePMiJi0KpeURONkelg"; + } + else { + consumerKey = CONFIG_STRING(config, "twitter.consumer_key"); + } + if (CONFIG_HAS_KEY(config, "twitter.consumer_secret") == false) { + consumerSecret = "YFZCDJwRhbkccXEnaYr1waCQejTJcOY8F7l5Wim3FA"; + } + else { + consumerSecret = CONFIG_STRING(config, "twitter.consumer_secret"); + } + + if (consumerSecret.empty() || consumerKey.empty()) { + LOG4CXX_ERROR(logger, "Consumer key and Consumer secret can't be empty."); + exit(1); + } + + adminLegacyName = "twitter.com"; + adminChatRoom = "#twitter"; + adminNickName = "twitter"; + adminAlias = "twitter"; + + OAUTH_KEY = "twitter_oauth_token"; + OAUTH_SECRET = "twitter_oauth_secret"; + MODE = "mode"; + + m_factories = new Swift::BoostNetworkFactories(loop); + m_conn = m_factories->getConnectionFactory()->createConnection(); + m_conn->onDataRead.connect(boost::bind(&TwitterPlugin::_handleDataRead, this, _1)); + m_conn->connect(Swift::HostAddressPort(Swift::HostAddress(host), port)); + + tp = new ThreadPool(loop_, 10); + + tweet_timer = m_factories->getTimerFactory()->createTimer(90000); + message_timer = m_factories->getTimerFactory()->createTimer(90000); + + tweet_timer->onTick.connect(boost::bind(&TwitterPlugin::pollForTweets, this)); + message_timer->onTick.connect(boost::bind(&TwitterPlugin::pollForDirectMessages, this)); + + tweet_timer->start(); + message_timer->start(); + + LOG4CXX_INFO(logger, "Starting the plugin."); +} + +TwitterPlugin::~TwitterPlugin() +{ + delete storagebackend; + std::set::iterator it; + for(it = onlineUsers.begin() ; it != onlineUsers.end() ; it++) delete userdb[*it].sessions; + delete tp; +} + +// Send data to NetworkPlugin server +void TwitterPlugin::sendData(const std::string &string) +{ + m_conn->write(Swift::createSafeByteArray(string)); +} + +// Receive date from the NetworkPlugin server and invoke the appropirate payload handler (implement in the NetworkPlugin class) +void TwitterPlugin::_handleDataRead(boost::shared_ptr data) +{ + if (m_firstPing) { + m_firstPing = false; + // Users can join the network without registering if we allow + // one user to connect multiple IRC networks. + NetworkPlugin::PluginConfig cfg; + cfg.setNeedPassword(false); + sendConfig(cfg); + } + + std::string d(data->begin(), data->end()); + handleDataRead(d); +} + +// User trying to login into his twitter account +void TwitterPlugin::handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) +{ + if(userdb.count(user) && (userdb[user].connectionState == NEW || + userdb[user].connectionState == CONNECTED || + userdb[user].connectionState == WAITING_FOR_PIN)) { + LOG4CXX_INFO(logger, std::string("A session corresponding to ") + user + std::string(" is already active")) + return; + } + + LOG4CXX_INFO(logger, std::string("Received login request for ") + user) + initUserSession(user, legacyName, password); + handleConnected(user); + + LOG4CXX_INFO(logger, "SPECTRUM 1 USER? - " << (userdb[user].spectrum1User? "true" : "false")) + + LOG4CXX_INFO(logger, user << ": Adding Buddy " << adminLegacyName << " " << adminAlias) + handleBuddyChanged(user, adminLegacyName, adminAlias, std::vector(), pbnetwork::STATUS_ONLINE); + userdb[user].nickName = ""; + + LOG4CXX_INFO(logger, "Querying database for usersettings of " << user) + std::string key, secret; + getUserOAuthKeyAndSecret(user, key, secret); + + if(key == "" || secret == "") { + LOG4CXX_INFO(logger, "Intiating OAuth Flow for user " << user) + setTwitterMode(user, 0); + tp->runAsThread(new OAuthFlow(np, userdb[user].sessions, user, userdb[user].sessions->getTwitterUsername())); + } else { + LOG4CXX_INFO(logger, user << " is already registerd. Using the stored oauth key and secret") + LOG4CXX_INFO(logger, key << " " << secret) + pinExchangeComplete(user, key, secret); + } +} + +// User logging out +void TwitterPlugin::handleLogoutRequest(const std::string &user, const std::string &legacyName) +{ + if (userdb.count(user)) { + delete userdb[user].sessions; + userdb[user].sessions = NULL; + userdb[user].connectionState = DISCONNECTED; + } + + if(onlineUsers.count(user)) { + onlineUsers.erase(user); + } +} + +// User joining a Chatroom +void TwitterPlugin::handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) +{ + if(room == adminChatRoom) { + LOG4CXX_INFO(logger, "Received Join Twitter room request for " << user) + + setTwitterMode(user, 2); + handleParticipantChanged(user, adminNickName, room, 0, pbnetwork::STATUS_ONLINE); + userdb[user].nickName = nickname; + handleMessage(user, adminChatRoom, "Connected to Twitter room! Populating your followers list", adminNickName); + tp->runAsThread(new FetchFriends(userdb[user].sessions, user, + boost::bind(&TwitterPlugin::populateRoster, this, _1, _2, _3, _4))); + } else { + setTwitterMode(user, 0); + LOG4CXX_ERROR(logger, "Couldn't connect to chatroom - " << room <<"! Try twitter-chatroom as the chatroom to access Twitter account") + handleMessage(user, adminLegacyName, "Couldn't connect to chatroom! Try twitter-chatroom as the chatroom to access Twitter account"); + } +} + +// User leaving a Chatroom +void TwitterPlugin::handleLeaveRoomRequest(const std::string &user, const std::string &room) +{ + if(room == adminChatRoom && onlineUsers.count(user)) { + LOG4CXX_INFO(logger, "Leaving chatroom! Switching back to default mode 0") + setTwitterMode(user, 0); + handleBuddyChanged(user, adminLegacyName, adminAlias, std::vector(), pbnetwork::STATUS_ONLINE); + } +} + +// Messages to be sent to Twitter +void TwitterPlugin::handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml, const std::string &/*id*/) +{ + + LOG4CXX_INFO(logger, "Received " << user << " --> " << legacyName << " - " << message) + + if(legacyName == adminLegacyName || legacyName == adminChatRoom) { + std::string cmd = "", data = ""; + + /** Parsing the message - Assuming message format to be [ ]***/ + int i; + for(i=0 ; irunAsThread(new PINExchangeProcess(np, userdb[user].sessions, user, data)); + else if(cmd == "#help") + tp->runAsThread(new HelpMessageRequest(user, CONFIG_STRING(config, "service.jid"), boost::bind(&TwitterPlugin::helpMessageResponse, this, _1, _2))); + else if(cmd[0] == '@') { + std::string username = cmd.substr(1); + tp->runAsThread(new DirectMessageRequest(userdb[user].sessions, user, username, data, + boost::bind(&TwitterPlugin::directMessageResponse, this, _1, _2, _3, _4))); + } + else if(cmd == "#status") + tp->runAsThread(new StatusUpdateRequest(userdb[user].sessions, user, data, + boost::bind(&TwitterPlugin::statusUpdateResponse, this, _1, _2))); + else if(cmd == "#timeline") + tp->runAsThread(new TimelineRequest(userdb[user].sessions, user, data, "", + boost::bind(&TwitterPlugin::displayTweets, this, _1, _2, _3, _4))); + else if(cmd == "#friends") + tp->runAsThread(new FetchFriends(userdb[user].sessions, user, + boost::bind(&TwitterPlugin::displayFriendlist, this, _1, _2, _3, _4))); + else if(cmd == "#follow") + tp->runAsThread(new CreateFriendRequest(userdb[user].sessions, user, data.substr(0,data.find('@')), + boost::bind(&TwitterPlugin::createFriendResponse, this, _1, _2, _3, _4))); + else if(cmd == "#unfollow") + tp->runAsThread(new DestroyFriendRequest(userdb[user].sessions, user, data.substr(0,data.find('@')), + boost::bind(&TwitterPlugin::deleteFriendResponse, this, _1, _2, _3))); + else if(cmd == "#retweet") + tp->runAsThread(new RetweetRequest(userdb[user].sessions, user, data, + boost::bind(&TwitterPlugin::RetweetResponse, this, _1, _2))); + else if(cmd == "#mode") { + int m = 0; + m = atoi(data.c_str()); + mode prevm = userdb[user].twitterMode; + + if((mode)m == userdb[user].twitterMode) return; //If same as current mode return + if(m < 0 || m > 2) { // Invalid modes + handleMessage(user, adminLegacyName, std::string("Error! Unknown mode ") + data + ". Allowed values 0,1,2." ); + return; + } + + setTwitterMode(user, m); + if((userdb[user].twitterMode == SINGLECONTACT || userdb[user].twitterMode == CHATROOM) && prevm == MULTIPLECONTACT) clearRoster(user); + else if(userdb[user].twitterMode == MULTIPLECONTACT) + tp->runAsThread(new FetchFriends(userdb[user].sessions, user, boost::bind(&TwitterPlugin::populateRoster, this, _1, _2, _3, _4))); + + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + std::string("Changed mode to ") + data, userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + + LOG4CXX_INFO(logger, user << ": Changed mode to " << data << " <" << (userdb[user].twitterMode == CHATROOM ? adminNickName : "") << ">" ) + } + + else if(userdb[user].twitterMode == CHATROOM) { + std::string buddy = message.substr(0, message.find(":")); + if(userdb[user].buddies.count(buddy) == 0) { + tp->runAsThread(new StatusUpdateRequest(userdb[user].sessions, user, message, + boost::bind(&TwitterPlugin::statusUpdateResponse, this, _1, _2))); + } else { + data = message.substr(message.find(":")+1); //Can parse better??:P + tp->runAsThread(new DirectMessageRequest(userdb[user].sessions, user, buddy, data, + boost::bind(&TwitterPlugin::directMessageResponse, this, _1, _2, _3, _4))); + } + } + else handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + "Unknown command! Type #help for a list of available commands.", userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + } + + else { + std::string buddy = legacyName; + if(userdb[user].twitterMode == CHATROOM) buddy = legacyName.substr(legacyName.find("/") + 1); + if(legacyName != "twitter") { + tp->runAsThread(new DirectMessageRequest(userdb[user].sessions, user, buddy, message, + boost::bind(&TwitterPlugin::directMessageResponse, this, _1, _2, _3, _4))); + } + } +} + +void TwitterPlugin::handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups) +{ + if(userdb[user].connectionState != CONNECTED) { + LOG4CXX_ERROR(logger, user << " is not connected to twitter!") + return; + } + + LOG4CXX_INFO(logger, user << " - Adding Twitter contact " << buddyName) + tp->runAsThread(new CreateFriendRequest(userdb[user].sessions, user, buddyName, + boost::bind(&TwitterPlugin::createFriendResponse, this, _1, _2, _3, _4))); +} + +void TwitterPlugin::handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector &groups) +{ + if(userdb[user].connectionState != CONNECTED) { + LOG4CXX_ERROR(logger, user << " is not connected to twitter!") + return; + } + + LOG4CXX_INFO(logger, user << " - Removing Twitter contact " << buddyName) + tp->runAsThread(new DestroyFriendRequest(userdb[user].sessions, user, buddyName, + boost::bind(&TwitterPlugin::deleteFriendResponse, this, _1, _2, _3))); +} + +void TwitterPlugin::handleVCardRequest(const std::string &user, const std::string &legacyName, unsigned int id) +{ + if(userdb[user].connectionState != CONNECTED) { + LOG4CXX_ERROR(logger, user << " is not connected to twitter!") + return; + } + + LOG4CXX_INFO(logger, user << " - VCardRequest for " << legacyName << ", " << userdb[user].buddiesInfo[legacyName].getProfileImgURL()) + + if(getTwitterMode(user) != SINGLECONTACT && userdb[user].buddies.count(legacyName) + && userdb[user].buddiesInfo[legacyName].getProfileImgURL().length()) { + if(userdb[user].buddiesImgs.count(legacyName) == 0) { + tp->runAsThread(new ProfileImageRequest(config, user, legacyName, userdb[user].buddiesInfo[legacyName].getProfileImgURL(), id, + boost::bind(&TwitterPlugin::profileImageResponse, this, _1, _2, _3, _4, _5))); + } + handleVCard(user, id, legacyName, legacyName, "", userdb[user].buddiesImgs[legacyName]); + } +} + +void TwitterPlugin::pollForTweets() +{ + boost::mutex::scoped_lock lock(userlock); + std::set::iterator it = onlineUsers.begin(); + while(it != onlineUsers.end()) { + std::string user = *it; + tp->runAsThread(new TimelineRequest(userdb[user].sessions, user, "", getMostRecentTweetIDUnsafe(user), + boost::bind(&TwitterPlugin::displayTweets, this, _1, _2, _3, _4))); + it++; + } + tweet_timer->start(); +} + +void TwitterPlugin::pollForDirectMessages() +{ + boost::mutex::scoped_lock lock(userlock); + std::set::iterator it = onlineUsers.begin(); + while(it != onlineUsers.end()) { + std::string user = *it; + tp->runAsThread(new DirectMessageRequest(userdb[user].sessions, user, "", getMostRecentDMIDUnsafe(user), + boost::bind(&TwitterPlugin::directMessageResponse, this, _1, _2, _3, _4))); + it++; + } + message_timer->start(); +} + + +bool TwitterPlugin::getUserOAuthKeyAndSecret(const std::string user, std::string &key, std::string &secret) +{ + boost::mutex::scoped_lock lock(dblock); + + UserInfo info; + if(storagebackend->getUser(user, info) == false) { + LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") + return false; + } + + key="", secret=""; int type; + storagebackend->getUserSetting((long)info.id, OAUTH_KEY, type, key); + storagebackend->getUserSetting((long)info.id, OAUTH_SECRET, type, secret); + return true; +} + +bool TwitterPlugin::checkSpectrum1User(const std::string user) +{ + boost::mutex::scoped_lock lock(dblock); + + UserInfo info; + if(storagebackend->getUser(user, info) == false) { + LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") + return false; + } + + std::string first_synchronization_done = ""; + int type; + storagebackend->getUserSetting((long)info.id, "first_synchronization_done", type, first_synchronization_done); + + LOG4CXX_INFO(logger, "first_synchronization_done: " << first_synchronization_done) + + if(first_synchronization_done.length()) return true; + return false; +} + +int TwitterPlugin::getTwitterMode(const std::string user) +{ + boost::mutex::scoped_lock lock(dblock); + + UserInfo info; + if(storagebackend->getUser(user, info) == false) { + LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") + return -1; + } + + int type; int m; + std::string s_m; + storagebackend->getUserSetting((long)info.id, MODE, type, s_m); + if(s_m == "") { + s_m = "0"; + storagebackend->updateUserSetting((long)info.id, MODE, s_m); + } + m = atoi(s_m.c_str()); + return m; +} + +bool TwitterPlugin::setTwitterMode(const std::string user, int m) +{ + boost::mutex::scoped_lock lock(dblock); + + UserInfo info; + if(storagebackend->getUser(user, info) == false) { + LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") + return false; + } + + if(m < 0 || m > 2) { + LOG4CXX_ERROR(logger, "Unknown mode " << m <<". Using default mode 0") + m = 0; + } + + userdb[user].twitterMode = (mode)m; + + //int type; + std::string s_m = std::string(1,m+'0'); + LOG4CXX_ERROR(logger, "Storing mode " << m <<" for user " << user) + storagebackend->updateUserSetting((long)info.id, MODE, s_m); + return true; +} + +bool TwitterPlugin::storeUserOAuthKeyAndSecret(const std::string user, const std::string OAuthKey, const std::string OAuthSecret) +{ + + boost::mutex::scoped_lock lock(dblock); + + UserInfo info; + if(storagebackend->getUser(user, info) == false) { + LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") + return false; + } + + storagebackend->updateUserSetting((long)info.id, OAUTH_KEY, OAuthKey); + storagebackend->updateUserSetting((long)info.id, OAUTH_SECRET, OAuthSecret); + return true; +} + +void TwitterPlugin::initUserSession(const std::string user, const std::string legacyName, const std::string password) +{ + boost::mutex::scoped_lock lock(userlock); + + std::string username = legacyName; + std::string passwd = password; + LOG4CXX_INFO(logger, username + " " + passwd) + + userdb[user].sessions = new twitCurl(); + if(CONFIG_HAS_KEY(config,"proxy.server")) { + std::string ip = CONFIG_STRING(config,"proxy.server"); + + std::ostringstream out; + out << CONFIG_INT(config,"proxy.port"); + std::string port = out.str(); + + std::string puser = CONFIG_STRING(config,"proxy.user"); + std::string ppasswd = CONFIG_STRING(config,"proxy.password"); + + LOG4CXX_INFO(logger, ip << " " << port << " " << puser << " " << ppasswd) + + if(ip != "localhost" && port != "0") { + userdb[user].sessions->setProxyServerIp(ip); + userdb[user].sessions->setProxyServerPort(port); + userdb[user].sessions->setProxyUserName(puser); + userdb[user].sessions->setProxyPassword(ppasswd); + } + } + + //Check if the user is spectrum1 user + userdb[user].spectrum1User = checkSpectrum1User(user); + + userdb[user].connectionState = NEW; + userdb[user].legacyName = username; + userdb[user].sessions->setTwitterUsername(username); + userdb[user].sessions->setTwitterPassword(passwd); + + if(!userdb[user].spectrum1User) { + userdb[user].sessions->getOAuth().setConsumerKey(consumerKey); + userdb[user].sessions->getOAuth().setConsumerSecret(consumerSecret); + } else { + userdb[user].sessions->getOAuth().setConsumerKey(OLD_APP_KEY); + userdb[user].sessions->getOAuth().setConsumerSecret(OLD_APP_SECRET); + } +} + +void TwitterPlugin::OAuthFlowComplete(const std::string user, twitCurl *obj) +{ + boost::mutex::scoped_lock lock(userlock); + + delete userdb[user].sessions; + userdb[user].sessions = obj->clone(); + userdb[user].connectionState = WAITING_FOR_PIN; +} + +void TwitterPlugin::pinExchangeComplete(const std::string user, const std::string OAuthAccessTokenKey, const std::string OAuthAccessTokenSecret) +{ + boost::mutex::scoped_lock lock(userlock); + + userdb[user].sessions->getOAuth().setOAuthTokenKey( OAuthAccessTokenKey ); + userdb[user].sessions->getOAuth().setOAuthTokenSecret( OAuthAccessTokenSecret ); + userdb[user].connectionState = CONNECTED; + userdb[user].twitterMode = (mode)getTwitterMode(user); + + if(userdb[user].twitterMode == MULTIPLECONTACT) { + tp->runAsThread(new FetchFriends(userdb[user].sessions, user, boost::bind(&TwitterPlugin::populateRoster, this, _1, _2, _3, _4))); + } + + onlineUsers.insert(user); + userdb[user].mostRecentTweetID = ""; + userdb[user].mostRecentDirectMessageID = ""; +} + +void TwitterPlugin::updateLastTweetID(const std::string user, const std::string ID) +{ + boost::mutex::scoped_lock lock(userlock); + userdb[user].mostRecentTweetID = ID; + + UserInfo info; + if(storagebackend->getUser(user, info) == false) { + LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") + return; + } + + storagebackend->updateUserSetting((long)info.id, "twitter_last_tweet", ID); +} + +std::string TwitterPlugin::getMostRecentTweetIDUnsafe(const std::string user) +{ + std::string ID = ""; + if(onlineUsers.count(user)) { + ID = userdb[user].mostRecentTweetID; + if (ID.empty()) { + int type; + UserInfo info; + if(storagebackend->getUser(user, info) == false) { + LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") + } + else { + storagebackend->getUserSetting(info.id, "twitter_last_tweet", type, ID); + } + } + } + return ID; +} + +std::string TwitterPlugin::getMostRecentTweetID(const std::string user) +{ + boost::mutex::scoped_lock lock(userlock); + return getMostRecentTweetIDUnsafe(user); +} + +void TwitterPlugin::updateLastDMID(const std::string user, const std::string ID) +{ + boost::mutex::scoped_lock lock(userlock); + userdb[user].mostRecentDirectMessageID = ID; + + UserInfo info; + if(storagebackend->getUser(user, info) == false) { + LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") + return; + } + + storagebackend->updateUserSetting((long)info.id, "twitter_last_dm", ID); +} + +std::string TwitterPlugin::getMostRecentDMIDUnsafe(const std::string user) { + std::string ID = ""; + if(onlineUsers.count(user)) { + ID = userdb[user].mostRecentDirectMessageID; + if (ID.empty()) { + int type; + UserInfo info; + if(storagebackend->getUser(user, info) == false) { + LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") + } + else { + storagebackend->getUserSetting(info.id, "twitter_last_dm", type, ID); + } + } + } + return ID; +} + +std::string TwitterPlugin::getMostRecentDMID(const std::string user) +{ + boost::mutex::scoped_lock lock(userlock); + return getMostRecentDMIDUnsafe(user); +} + +/************************************** Twitter response functions **********************************/ +void TwitterPlugin::statusUpdateResponse(std::string &user, Error &errMsg) +{ + if(errMsg.getMessage().length()) { + if (errMsg.isCurlError()) { + handleDisconnected(user, 3, errMsg.getMessage()); + return; + } + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + } else { + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + "Status Update successful", userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + } +} + +void TwitterPlugin::helpMessageResponse(std::string &user, std::string &msg) +{ + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + msg, userdb[user].twitterMode == CHATROOM ? adminNickName : ""); +} + +void TwitterPlugin::clearRoster(const std::string user) +{ + if(userdb[user].buddies.size() == 0) return; + std::set::iterator it = userdb[user].buddies.begin(); + while(it != userdb[user].buddies.end()) { + handleBuddyRemoved(user, *it); + it++; + } + userdb[user].buddies.clear(); +} + +void TwitterPlugin::populateRoster(std::string &user, std::vector &friends, std::vector &friendAvatars, Error &errMsg) +{ + if(errMsg.getMessage().length() == 0) + { + for(int i=0 ; i(), +#if HAVE_SWIFTEN_3 + pbnetwork::STATUS_ONLINE, lastTweet, Swift::byteArrayToString(cryptoProvider->getSHA1Hash(Swift::createByteArray(friendAvatars[i])))); +#else + pbnetwork::STATUS_ONLINE, lastTweet, SHA(friendAvatars[i])); +#endif + } + else if(userdb[user].twitterMode == CHATROOM) + handleParticipantChanged(user, friends[i].getScreenName(), adminChatRoom, 0, pbnetwork::STATUS_ONLINE); + + /*handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + friends[i].getScreenName() + " - " + friends[i].getLastStatus().getTweet(), + userdb[user].twitterMode == CHATROOM ? adminNickName : "");*/ + } + } else { + if (errMsg.isCurlError()) { + handleDisconnected(user, 3, errMsg.getMessage()); + return; + } + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + std::string("Error populating roster - ") + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + } + + if(userdb[user].twitterMode == CHATROOM) handleParticipantChanged(user, userdb[user].nickName, adminChatRoom, 0, pbnetwork::STATUS_ONLINE); +} + +void TwitterPlugin::displayFriendlist(std::string &user, std::vector &friends, std::vector &friendAvatars, Error &errMsg) +{ + if(errMsg.getMessage().length() == 0) + { + std::string userlist = "\n***************USER LIST****************\n"; + for(int i=0 ; i < friends.size() ; i++) { + userlist += " - " + friends[i].getUserName() + " (" + friends[i].getScreenName() + ")\n"; + } + userlist += "***************************************\n"; + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + userlist, userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + } else { + if (errMsg.isCurlError()) { + handleDisconnected(user, 3, errMsg.getMessage()); + return; + } + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + } + +} + +void TwitterPlugin::displayTweets(std::string &user, std::string &userRequested, std::vector &tweets , Error &errMsg) +{ + if(errMsg.getMessage().length() == 0) { + std::map lastTweet; + std::map::iterator it; + + for(int i = tweets.size() - 1 ; i >= 0 ; i--) { + if(userdb[user].twitterMode != CHATROOM) { + std::string m = " - " + tweets[i].getUserData().getScreenName() + ": " + tweets[i].getTweet() + " (MsgId: " + (tweets[i].getRetweetID().empty() ? tweets[i].getID() : tweets[i].getRetweetID()) + ")\n"; + handleMessage(user, adminLegacyName, m, "", "", tweets[i].getCreationTime(), true); + + std::string scrname = tweets[i].getUserData().getScreenName(); + if(lastTweet.count(scrname) == 0 || cmp(tweets[lastTweet[scrname]].getID(), tweets[i].getID()) <= 0) lastTweet[scrname] = i; + + } else { + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + tweets[i].getTweet() + " (MsgId: " + (tweets[i].getRetweetID().empty() ? tweets[i].getID() : tweets[i].getRetweetID()) + ")", tweets[i].getUserData().getScreenName(), "", tweets[i].getCreationTime(), true); + } + } + + if(userdb[user].twitterMode == MULTIPLECONTACT) { + //Set as status user's last tweet + for(it=lastTweet.begin() ; it!=lastTweet.end() ; it++) { + int t = it->second; + handleBuddyChanged(user, tweets[t].getUserData().getScreenName(), tweets[t].getUserData().getUserName(), + std::vector(), pbnetwork::STATUS_ONLINE, tweets[t].getTweet()); + } + } + + if((userRequested == "" || userRequested == user) && tweets.size()) { + std::string tweetID = getMostRecentTweetID(user); + if(tweetID != tweets[0].getID()) updateLastTweetID(user, tweets[0].getID()); + } + + } else { + if (errMsg.isCurlError()) { + handleDisconnected(user, 3, errMsg.getMessage()); + return; + } + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + } +} + +void TwitterPlugin::directMessageResponse(std::string &user, std::string &username, std::vector &messages, Error &errMsg) +{ + if(errMsg.getCode() == "93") //Permission Denied + return; + + if(errMsg.getMessage().length()) { + if (errMsg.isCurlError()) { + handleDisconnected(user, 3, errMsg.getMessage()); + return; + } + + if(username != "") + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + std::string("Error while sending direct message! - ") + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + else + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + std::string("Error while fetching direct messages! - ") + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + return; + } + + if(username != "") { + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + "Message delivered!", userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + return; + } + + if(!messages.size()) return; + + if(userdb[user].twitterMode == SINGLECONTACT) { + + std::string msglist = ""; + std::string msgID = getMostRecentDMID(user); + std::string maxID = msgID; + + for(int i=0 ; i < messages.size() ; i++) { + if(cmp(msgID, messages[i].getID()) == -1) { + msglist += " - " + messages[i].getSenderData().getScreenName() + ": " + messages[i].getMessage() + "\n"; + if(cmp(maxID, messages[i].getID()) == -1) maxID = messages[i].getID(); + } + } + + if(msglist.length()) handleMessage(user, adminLegacyName, msglist, ""); + updateLastDMID(user, maxID); + + } else { + + std::string msgID = getMostRecentDMID(user); + std::string maxID = msgID; + + for(int i=0 ; i < messages.size() ; i++) { + if(cmp(msgID, messages[i].getID()) == -1) { + if(userdb[user].twitterMode == MULTIPLECONTACT) + handleMessage(user, messages[i].getSenderData().getScreenName(), messages[i].getMessage(), ""); + else + handleMessage(user, adminChatRoom, messages[i].getMessage() + " - ", messages[i].getSenderData().getScreenName()); + if(cmp(maxID, messages[i].getID()) == -1) maxID = messages[i].getID(); + } + } + + if(maxID == getMostRecentDMID(user)) LOG4CXX_INFO(logger, "No new direct messages for " << user) + updateLastDMID(user, maxID); + } +} + +void TwitterPlugin::createFriendResponse(std::string &user, User &frnd, std::string &img, Error &errMsg) +{ + if(errMsg.getMessage().length()) { + if (errMsg.isCurlError()) { + handleDisconnected(user, 3, errMsg.getMessage()); + return; + } + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + return; + } + + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + std::string("You are now following ") + frnd.getScreenName(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + + userdb[user].buddies.insert(frnd.getScreenName()); + userdb[user].buddiesInfo[frnd.getScreenName()] = frnd; + userdb[user].buddiesImgs[frnd.getScreenName()] = img; + + LOG4CXX_INFO(logger, user << " - " << frnd.getScreenName() << ", " << frnd.getProfileImgURL()) + if(userdb[user].twitterMode == MULTIPLECONTACT) { +#if HAVE_SWIFTEN_3 + handleBuddyChanged(user, frnd.getScreenName(), frnd.getUserName(), std::vector(), pbnetwork::STATUS_ONLINE, "", Swift::byteArrayToString(cryptoProvider->getSHA1Hash(Swift::createByteArray(img)))); +#else + handleBuddyChanged(user, frnd.getScreenName(), frnd.getUserName(), std::vector(), pbnetwork::STATUS_ONLINE, "", SHA(img)); +#endif + } else if(userdb[user].twitterMode == CHATROOM) { + handleParticipantChanged(user, frnd.getScreenName(), adminChatRoom, 0, pbnetwork::STATUS_ONLINE); + } +} + +void TwitterPlugin::deleteFriendResponse(std::string &user, User &frnd, Error &errMsg) +{ + if(errMsg.getMessage().length()) { + if (errMsg.isCurlError()) { + handleDisconnected(user, 3, errMsg.getMessage()); + return; + } + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + return; + } + + LOG4CXX_INFO(logger, user << " - " << frnd.getScreenName() << ", " << frnd.getProfileImgURL()) + userdb[user].buddies.erase(frnd.getScreenName()); + + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + std::string("You are not following ") + frnd.getScreenName() + " anymore", userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + + if (userdb[user].twitterMode == CHATROOM) { + handleParticipantChanged(user, frnd.getScreenName(), adminLegacyName, 0, pbnetwork::STATUS_NONE); + } + + if(userdb[user].twitterMode == MULTIPLECONTACT) { + handleBuddyRemoved(user, frnd.getScreenName()); + } +} + + +void TwitterPlugin::RetweetResponse(std::string &user, Error &errMsg) +{ + if(errMsg.getMessage().length()) { + if (errMsg.isCurlError()) { + handleDisconnected(user, 3, errMsg.getMessage()); + return; + } + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + } else { + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + "Retweet successful", userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + } +} + +void TwitterPlugin::profileImageResponse(std::string &user, std::string &buddy, std::string &img, unsigned int reqID, Error &errMsg) +{ + if(errMsg.getMessage().length()) { + if (errMsg.isCurlError()) { + handleDisconnected(user, 3, errMsg.getMessage()); + return; + } + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + } else { + LOG4CXX_INFO(logger, user << " - Sending VCard for " << buddy) + handleVCard(user, reqID, buddy, buddy, "", img); + } +}