Changeset - 3256e6e10cc1
[Not reviewed]
0 3 0
Sarang Bharadwaj - 13 years ago 2012-05-26 23:33:25
sarang.bh@gmail.com
Made proxy settings and consumer key/secret configurable via config file
3 files changed with 51 insertions and 19 deletions:
0 comments (0 inline, 0 general)
backends/twitter/main.cpp
Show inline comments
 
#include "transport/config.h"
 
#include "transport/networkplugin.h"
 
#include "transport/logging.h"
 
#include "Swiften/Swiften.h"
 
#include "unistd.h"
 
#include "signal.h"
 
#include "sys/wait.h"
 
#include "sys/signal.h"
 
#include <boost/algorithm/string.hpp>
 
#include "twitcurl.h"
 

	
 
#include <iostream>
 
#include <sstream>
 
#include <map>
 
#include <vector>
 
#include <cstdio>
 
#include "userdb.h"
 

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

	
 
DEFINE_LOGGER(logger, "Twitter Backend");
 
Swift::SimpleEventLoop *loop_; // Event Loop
 
class TwitterPlugin; // The plugin
 
TwitterPlugin * np = NULL;
 

	
 
class TwitterPlugin : public NetworkPlugin {
 
	public:
 
		Swift::BoostNetworkFactories *m_factories;
 
		Swift::BoostIOServiceThread m_boostIOServiceThread;
 
		boost::shared_ptr<Swift::Connection> m_conn;
 

	
 
		TwitterPlugin(Config *config, Swift::SimpleEventLoop *loop, const std::string &host, int port) : NetworkPlugin() {
 
			this->config = config;
 

	
 
			if(CONFIG_HAS_KEY(config, "twitter.consumer_key") == false ||
 
			   CONFIG_HAS_KEY(config, "twitter.consumer_secret") == false) {
 
				LOG4CXX_ERROR(logger, "Couldn't find consumer key and/or secret. Please check config file.");
 
				exit(0);
 
			}
 
			consumerKey = CONFIG_STRING(config, "twitter.consumer_key");
 
			consumerSecret = CONFIG_STRING(config, "twitter.consumer_secret");
 

	
 
			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));
 
			
 
			db = new UserDB(std::string("user.db"));
 
			registeredUsers = db->getRegisteredUsers();
 
			
 
			LOG4CXX_INFO(logger, "Starting the plugin.");
 
		}
 

	
 
		~TwitterPlugin() {
 
			delete db;
 
			std::map<std::string, twitCurl*>::iterator it;
 
			for(it = sessions.begin() ; it != sessions.end() ; it++) delete it->second;
 
		}
 

	
 
		// Send data to NetworkPlugin server
 
		void 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 _handleDataRead(boost::shared_ptr<Swift::SafeByteArray> data) {
 
			std::string d(data->begin(), data->end());
 
			handleDataRead(d);
 
		}
 
		
 
		// User trying to login into his twitter account
 
		void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) {
 
			if(connectionState.count(user) && (connectionState[user] == NEW || 
 
						                        connectionState[user] == CONNECTED || 
 
												connectionState[user] == 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)
 
			//twitCurl &twitterObj = sessions[user];
 
			//std::string myOAuthAccessTokenSecret, myOAuthAccessTokenKey;
 
        	//twitterObj.getOAuth().getOAuthTokenKey( myOAuthAccessTokenKey );
 
        	//twitterObj.getOAuth().getOAuthTokenSecret( myOAuthAccessTokenSecret );
 

	
 
			//if(myOAuthAccessTokenSecret.size() && myOAuthAccessTokenKey.size()) {	
 
			//}
 
			
 
			std::string username = user.substr(0,user.find('@'));
 
			std::string passwd = password;
 
			LOG4CXX_INFO(logger, username + "  " + passwd)
 

	
 
			sessions[user] = new twitCurl();
 
			handleConnected(user);
 
			handleBuddyChanged(user, "twitter-account", "twitter", std::vector<std::string>(), pbnetwork::STATUS_ONLINE);
 
	        
 
//			std::string ip = "10.93.0.36";
 
//			std::string port = "3128";
 
//			std::string puser = "cs09s022";
 
//			std::string ppasswd = "";
 
//			sessions[user]->setProxyServerIp(ip);
 
//	        sessions[user]->setProxyServerPort(port);
 
//	        sessions[user]->setProxyUserName(puser);
 
//	        sessions[user]->setProxyPassword(ppasswd);
 
			
 
			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)
 

	
 
				sessions[user]->setProxyServerIp(ip);
 
		        sessions[user]->setProxyServerPort(port);
 
		        sessions[user]->setProxyUserName(puser);
 
		        sessions[user]->setProxyPassword(ppasswd);
 
			}
 
			connectionState[user] = NEW;
 
			
 
			sessions[user]->setTwitterUsername(username);
 
			sessions[user]->setTwitterPassword(passwd); 
 
			sessions[user]->getOAuth().setConsumerKey( std::string( "qxfSCX7WN7SZl7dshqGZA" ) );
 
			sessions[user]->getOAuth().setConsumerSecret( std::string( "ypWapSj87lswvnksZ46hMAoAZvST4ePGPxAQw6S2o" ) );
 
			sessions[user]->getOAuth().setConsumerKey(consumerKey);
 
			sessions[user]->getOAuth().setConsumerSecret(consumerSecret);
 

	
 
//			sessions[user]->getOAuth().setConsumerKey( std::string( "qxfSCX7WN7SZl7dshqGZA" ) );
 
//			sessions[user]->getOAuth().setConsumerSecret( std::string( "ypWapSj87lswvnksZ46hMAoAZvST4ePGPxAQw6S2o" ) );
 
			
 
			if(registeredUsers.count(user) == 0) {	
 
				std::string authUrl;
 
				if (sessions[user]->oAuthRequestToken( authUrl ) == false ) {
 
					LOG4CXX_ERROR(logger, "Error creating twitter authorization url!");
 
					handleLogoutRequest(user, username);
 
					return;
 
				}
 
				handleMessage(user, "twitter-account", std::string("Please visit the following link and authorize this application: ") + authUrl);
 
				handleMessage(user, "twitter-account", std::string("Please reply with the PIN provided by twitter. Prefix the pin with 'pin:'. Ex. 'pin: 1234'"));
 
				connectionState[user] = WAITING_FOR_PIN;	
 
			} else {
 
				std::vector<std::string> keysecret;
 
				db->fetch(user, keysecret);
 
				sessions[user]->getOAuth().setOAuthTokenKey( keysecret[0] );
 
				sessions[user]->getOAuth().setOAuthTokenSecret( keysecret[1] );
 
				connectionState[user] = CONNECTED;
 
			}
 
		}
 
		
 
		// User logging out
 
		void handleLogoutRequest(const std::string &user, const std::string &legacyName) {
 
			delete sessions[user];
 
			sessions[user] = NULL;
 
@@ -136,75 +150,78 @@ class TwitterPlugin : public NetworkPlugin {
 
				std::string data = message.substr(message.find(':') + 1);
 
				
 
				handleMessage(user, "twitter-account", cmd + " " + data);
 

	
 
				if(cmd == "pin") {
 
					sessions[user]->getOAuth().setOAuthPin( data );
 
					sessions[user]->oAuthAccessToken();
 
					
 
					std::string OAuthAccessTokenKey, OAuthAccessTokenSecret;
 
					sessions[user]->getOAuth().getOAuthTokenKey( OAuthAccessTokenKey );
 
					sessions[user]->getOAuth().getOAuthTokenSecret( OAuthAccessTokenSecret );
 
					db->insert(UserData(user, OAuthAccessTokenKey, OAuthAccessTokenSecret));
 
					registeredUsers.insert(user);
 

	
 
					connectionState[user] = CONNECTED;
 
					LOG4CXX_INFO(logger, "Sent PIN " << data << " and obtained access token");
 
				}
 

	
 
				if(cmd == "status") {
 
					if(connectionState[user] != CONNECTED) {
 
						LOG4CXX_ERROR(logger, "Trying to update status for " << user << " when not connected!");
 
						return;
 
					}
 

	
 
					LOG4CXX_INFO(logger, "Updating status for " << user << ": " << data);
 
					std::string replyMsg; 
 
					if( sessions[user]->statusUpdate( data ) ) {
 
						sessions[user]->getLastWebResponse( replyMsg );
 
						LOG4CXX_INFO(logger, "twitterClient:: twitCurl::statusUpdate web response: " << replyMsg );
 
					}
 
					else {
 
						sessions[user]->getLastCurlError( replyMsg );
 
						LOG4CXX_INFO(logger, "twitterClient:: twitCurl::statusUpdate error: " << replyMsg );
 
					}
 
					
 
					LOG4CXX_INFO(logger, "Updated status for " << user << ": " << data);
 
				}
 
			}
 
		}
 

	
 
		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 handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector<std::string> &groups) {
 

	
 
		}
 

	
 
	private:
 
		enum status {NEW, WAITING_FOR_PIN, CONNECTED, DISCONNECTED};
 
		Config *config;
 
		UserDB *db;
 
		std::string consumerKey;
 
		std::string consumerSecret;
 
		std::set<std::string> registeredUsers;
 
		std::map<std::string, twitCurl*> sessions;
 
		std::map<std::string, status> connectionState;
 
};
 

	
 
static void spectrum_sigchld_handler(int sig)
 
{
 
	int status;
 
	pid_t pid;
 

	
 
	do {
 
		pid = waitpid(-1, &status, WNOHANG);
 
	} while (pid != 0 && pid != (pid_t)-1);
 

	
 
	if ((pid == (pid_t) - 1) && (errno != ECHILD)) {
 
		char errmsg[BUFSIZ];
 
		snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid);
 
		perror(errmsg);
 
	}
 
}
 

	
 

	
 
int main (int argc, char* argv[]) {
 
	std::string host;
spectrum/src/sample.cfg
Show inline comments
 
@@ -18,24 +18,32 @@ backend=../../backends/twitter/spectrum_twitter_backend
 
protocol=prpl-jabber
 
#protocol=prpl-msn
 
#protocol=any
 
#protocol=prpl-icq
 
working_dir=./
 

	
 
[backend]
 
#default_avatar=catmelonhead.jpg
 
#no_vcard_fetch=true
 

	
 
[logging]
 
#config=logging.cfg # log4cxx/log4j logging configuration file
 
#backend_config=/home/hanzz/code/libtransport/spectrum/src/backend-logging.cfg # log4cxx/log4j logging configuration file for backends
 

	
 
[database]
 
type = none # or "none" without database backend
 
database = test.sql
 
prefix=icq
 
#type = mysql # or "none" without database backend.......................................................................................................................
 
#database = test
 
#prefix=
 
#user=root
 
#password=yourrootsqlpassword
 
#encryption_key=hanzzik
 
[twitter]
 
consumer_key=qxfSCX7WN7SZl7dshqGZA
 
consumer_secret=ypWapSj87lswvnksZ46hMAoAZvST4ePGPxAQw6S2o
 
[proxy]
 
server=10.93.0.36
 
port=3128
 
user=cs09s022
 
password=your_proxy_password
src/config.cpp
Show inline comments
 
@@ -91,48 +91,55 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description
 
		("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.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.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)")
 
		("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.")
 
		("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.")
 
		("twitter.consumer_key", value<std::string>()->default_value(""), "Twitter APP Consumer Key.")
 
		("twitter.consumer_secret", value<std::string>()->default_value(""), "Twitter APP Consumer Secret")
 
		("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.")
 

	
 
	;
 

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

	
 
	bool found_working = false;
 
	bool found_pidfile = 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));
 
			}
0 comments (0 inline, 0 general)