diff --git a/backends/swiften/main.cpp b/backends/swiften/main.cpp index 3ccc632e86584f736ef2cc2331f58f129243410b..5a2c1f37eb2d344053d8449adc0ed318de1ab0c8 100644 --- a/backends/swiften/main.cpp +++ b/backends/swiften/main.cpp @@ -30,6 +30,7 @@ using namespace boost::program_options; using namespace Transport; DEFINE_LOGGER(logger, "Swiften"); +DEFINE_LOGGER(logger_xml, "backend.xml"); // eventloop Swift::SimpleEventLoop *loop_; @@ -37,96 +38,60 @@ Swift::SimpleEventLoop *loop_; // Plugins class SwiftenPlugin; NetworkPlugin *np = NULL; +Swift::XMPPSerializer *serializer; -class MUCController { +class ForwardIQHandler : public Swift::IQHandler { public: - MUCController(const std::string &user, boost::shared_ptr client, const std::string &room, const std::string &nickname, const std::string &password) { - m_user = user; - m_room = room; - muc = client->getMUCManager()->createMUC(room); - if (!password.empty()) { - muc->setPassword(password); - } - - muc->onJoinComplete.connect(boost::bind(&MUCController::handleJoinComplete, this, _1)); - muc->onJoinFailed.connect(boost::bind(&MUCController::handleJoinFailed, this, _1)); - muc->onOccupantJoined.connect(boost::bind(&MUCController::handleOccupantJoined, this, _1)); - muc->onOccupantPresenceChange.connect(boost::bind(&MUCController::handleOccupantPresenceChange, this, _1)); - muc->onOccupantLeft.connect(boost::bind(&MUCController::handleOccupantLeft, this, _1, _2, _3)); - muc->onOccupantRoleChanged.connect(boost::bind(&MUCController::handleOccupantRoleChanged, this, _1, _2, _3)); - muc->onOccupantAffiliationChanged.connect(boost::bind(&MUCController::handleOccupantAffiliationChanged, this, _1, _2, _3)); - - muc->joinAs(nickname); - } - - virtual ~MUCController() { - muc->onJoinComplete.disconnect(boost::bind(&MUCController::handleJoinComplete, this, _1)); - muc->onJoinFailed.disconnect(boost::bind(&MUCController::handleJoinFailed, this, _1)); - muc->onOccupantJoined.disconnect(boost::bind(&MUCController::handleOccupantJoined, this, _1)); - muc->onOccupantPresenceChange.disconnect(boost::bind(&MUCController::handleOccupantPresenceChange, this, _1)); - muc->onOccupantLeft.disconnect(boost::bind(&MUCController::handleOccupantLeft, this, _1, _2, _3)); - muc->onOccupantRoleChanged.disconnect(boost::bind(&MUCController::handleOccupantRoleChanged, this, _1, _2, _3)); - muc->onOccupantAffiliationChanged.disconnect(boost::bind(&MUCController::handleOccupantAffiliationChanged, this, _1, _2, _3)); - } - - const std::string &getNickname() { - //return muc->getCurrentNick(); - return m_nick; - } - - void handleOccupantJoined(const Swift::MUCOccupant& occupant) { - np->handleParticipantChanged(m_user, occupant.getNick(), m_room, occupant.getRole() == Swift::MUCOccupant::Moderator, pbnetwork::STATUS_ONLINE); - } - - void handleOccupantLeft(const Swift::MUCOccupant& occupant, Swift::MUC::LeavingType type, const std::string& reason) { - np->handleParticipantChanged(m_user, occupant.getNick(), m_room, occupant.getRole() == Swift::MUCOccupant::Moderator, pbnetwork::STATUS_NONE); - } + std::map m_id2resource; - void handleOccupantPresenceChange(boost::shared_ptr presence) { - const Swift::MUCOccupant& occupant = muc->getOccupant(presence->getFrom().getResource()); - np->handleParticipantChanged(m_user, presence->getFrom().getResource(), m_room, (int) occupant.getRole() == Swift::MUCOccupant::Moderator, (pbnetwork::StatusType) presence->getShow(), presence->getStatus()); - } - - void handleOccupantRoleChanged(const std::string& nick, const Swift::MUCOccupant& occupant, const Swift::MUCOccupant::Role& oldRole) { - - } - - void handleOccupantAffiliationChanged(const std::string& nick, const Swift::MUCOccupant::Affiliation& affiliation, const Swift::MUCOccupant::Affiliation& oldAffiliation) { -// np->handleParticipantChanged(m_user, occupant->getNick(), m_room, (int) occupant.getRole() == Swift::MUCOccupant::Moderator, pbnetwork::STATUS_ONLINE); - } - - void handleJoinComplete(const std::string& nick) { - m_nick = nick; + ForwardIQHandler(NetworkPlugin *np, const std::string &user) { + m_np = np; + m_user = user; } - void handleJoinFailed(boost::shared_ptr error) { - - } + bool handleIQ(boost::shared_ptr iq) { + if (iq->getPayload() != NULL) { + return false; + } + if (iq->getType() == Swift::IQ::Get) { + m_id2resource[iq->getID()] = iq->getFrom().getResource(); + } - void part() { - muc->part(); + iq->setTo(m_user); + std::string xml = safeByteArrayToString(serializer->serializeElement(iq)); + m_np->sendRawXML(xml); + return true; } private: - Swift::MUC::ref muc; + NetworkPlugin *m_np; std::string m_user; - std::string m_room; - std::string m_nick; + }; -class SwiftenPlugin : public NetworkPlugin { +class SwiftenPlugin : public NetworkPlugin, Swift::XMPPParserClient { public: Swift::BoostNetworkFactories *m_factories; Swift::BoostIOServiceThread m_boostIOServiceThread; boost::shared_ptr m_conn; + bool m_firstPing; + + Swift::FullPayloadSerializerCollection collection; + Swift::XMPPParser *m_xmppParser; + Swift::FullPayloadParserFactoryCollection m_collection2; SwiftenPlugin(Config *config, Swift::SimpleEventLoop *loop, const std::string &host, int port) : NetworkPlugin() { this->config = config; + m_firstPing = true; m_factories = new Swift::BoostNetworkFactories(loop); m_conn = m_factories->getConnectionFactory()->createConnection(); m_conn->onDataRead.connect(boost::bind(&SwiftenPlugin::_handleDataRead, this, _1)); m_conn->connect(Swift::HostAddressPort(Swift::HostAddress(host), port)); + serializer = new Swift::XMPPSerializer(&collection, Swift::ClientStreamType); + m_xmppParser = new Swift::XMPPParser(this, &m_collection2, m_factories->getXMLParserFactory()); + m_xmppParser->parse(""); + LOG4CXX_INFO(logger, "Starting the plugin."); } @@ -137,10 +102,61 @@ class SwiftenPlugin : public NetworkPlugin { // This method has to call handleDataRead with all received data from network plugin server void _handleDataRead(boost::shared_ptr data) { + if (m_firstPing) { + m_firstPing = false; + NetworkPlugin::PluginConfig cfg; + cfg.setRawXML(true); + sendConfig(cfg); + } std::string d(data->begin(), data->end()); handleDataRead(d); } + void handleStreamStart(const Swift::ProtocolHeader&) {} + + void handleElement(boost::shared_ptr element) { + boost::shared_ptr stanza = boost::dynamic_pointer_cast(element); + if (!stanza) { + return; + } + + std::string user = stanza->getFrom().toBare(); + + boost::shared_ptr client = m_users[user]; + if (!client) + return; + + stanza->setFrom(client->getJID()); + + boost::shared_ptr message = boost::dynamic_pointer_cast(stanza); + if (message) { + client->sendMessage(message); + return; + } + + boost::shared_ptr presence = boost::dynamic_pointer_cast(stanza); + if (presence) { + client->sendPresence(presence); + return; + } + + boost::shared_ptr iq = boost::dynamic_pointer_cast(stanza); + if (iq) { + if (m_handlers[user]->m_id2resource.find(stanza->getID()) != m_handlers[user]->m_id2resource.end()) { + iq->setTo(Swift::JID(iq->getTo().getNode(), iq->getTo().getDomain(), m_handlers[user]->m_id2resource[stanza->getID()])); + m_handlers[user]->m_id2resource.erase(stanza->getID()); + } + client->getIQRouter()->sendIQ(iq); + return; + } + } + + void handleStreamEnd() {} + + void handleRawXML(const std::string &xml) { + m_xmppParser->parse(xml); + } + void handleSwiftDisconnected(const std::string &user, const boost::optional &error) { std::string message = ""; bool reconnect = false; @@ -186,7 +202,7 @@ class SwiftenPlugin : public NetworkPlugin { client->onDisconnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftDisconnected, this, user, _1)); client->onMessageReceived.disconnect(boost::bind(&SwiftenPlugin::handleSwiftMessageReceived, this, user, _1)); m_users.erase(user); - m_mucs.erase(user); + m_handlers.erase(user); } #ifndef WIN32 @@ -219,67 +235,53 @@ class SwiftenPlugin : public NetworkPlugin { } void handleSwiftPresenceChanged(const std::string &user, Swift::Presence::ref presence) { - boost::shared_ptr client = m_users[user]; - if (client->getMUCRegistry()->isMUC(presence->getFrom().toBare())) { - return; - } - - if (presence->getPayload() != NULL || presence->getPayload() != NULL) { - return; - } - - LOG4CXX_INFO(logger, user << ": " << presence->getFrom().toBare().toString() << " presence changed"); - - std::string message = presence->getStatus(); - std::string photo = ""; - - boost::shared_ptr update = presence->getPayload(); - if (update) { - photo = update->getPhotoHash(); - } - - boost::optional item = m_users[user]->getRoster()->getItem(presence->getFrom()); - if (item) { - handleBuddyChanged(user, presence->getFrom().toBare().toString(), item->getName(), item->getGroups(), (pbnetwork::StatusType) presence->getShow(), message, photo); - } - else { - std::vector groups; - handleBuddyChanged(user, presence->getFrom().toBare().toString(), presence->getFrom().toBare(), groups, (pbnetwork::StatusType) presence->getShow(), message, photo); - } +// boost::shared_ptr client = m_users[user]; +// if (client->getMUCRegistry()->isMUC(presence->getFrom().toBare())) { +// return; +// } +// +// if (presence->getPayload() != NULL || presence->getPayload() != NULL) { +// return; +// } +// +// LOG4CXX_INFO(logger, user << ": " << presence->getFrom().toBare().toString() << " presence changed"); +// +// std::string message = presence->getStatus(); +// std::string photo = ""; +// +// boost::shared_ptr update = presence->getPayload(); +// if (update) { +// photo = update->getPhotoHash(); +// } +// +// boost::optional item = m_users[user]->getRoster()->getItem(presence->getFrom()); +// if (item) { +// handleBuddyChanged(user, presence->getFrom().toBare().toString(), item->getName(), item->getGroups(), (pbnetwork::StatusType) presence->getShow(), message, photo); +// } +// else { +// std::vector groups; +// handleBuddyChanged(user, presence->getFrom().toBare().toString(), presence->getFrom().toBare(), groups, (pbnetwork::StatusType) presence->getShow(), message, photo); +// } + presence->setTo(user); + std::string xml = safeByteArrayToString(serializer->serializeElement(presence)); + sendRawXML(xml); } void handleSwiftMessageReceived(const std::string &user, Swift::Message::ref message) { - std::string body = message->getBody(); - boost::shared_ptr client = m_users[user]; - if (client) { - if (message->getType() == Swift::Message::Groupchat) { - boost::shared_ptr delay = message->getPayload(); - std::string timestamp = ""; - if (delay) { - timestamp = boost::posix_time::to_iso_string(delay->getStamp()); - } - handleMessage(user, message->getFrom().toBare().toString(), body, message->getFrom().getResource(), "", timestamp); - } - else { - if (client->getMUCRegistry()->isMUC(message->getFrom().toBare())) { - handleMessage(user, message->getFrom().toBare().toString(), body, message->getFrom().getResource(), "", "", false, true); - } - else { - handleMessage(user, message->getFrom().toBare().toString(), body, "", ""); - } - } - } + message->setTo(user); + std::string xml = safeByteArrayToString(serializer->serializeElement(message)); + sendRawXML(xml); } - void handleSwiftVCardReceived(const std::string &user, unsigned int id, Swift::VCard::ref vcard, Swift::ErrorPayload::ref error) { - if (error || !vcard) { - LOG4CXX_INFO(logger, user << ": error fetching VCard with id=" << id); - handleVCard(user, id, "", "", "", ""); - return; + void handleSwiftenDataRead(const Swift::SafeByteArray &data) { + std::string d = safeByteArrayToString(data); + if (!boost::starts_with(d, "onMessageReceived.connect(boost::bind(&SwiftenPlugin::handleSwiftMessageReceived, this, user, _1)); client->getRoster()->onInitialRosterPopulated.connect(boost::bind(&SwiftenPlugin::handleSwiftRosterReceived, this, user)); client->getPresenceOracle()->onPresenceChange.connect(boost::bind(&SwiftenPlugin::handleSwiftPresenceChanged, this, user, _1)); + client->onDataRead.connect(boost::bind(&SwiftenPlugin::handleSwiftenDataRead, this, _1)); + client->onDataWritten.connect(boost::bind(&SwiftenPlugin::handleSwiftenDataWritten, this, _1)); + client->getSubscriptionManager()->onPresenceSubscriptionRequest.connect(boost::bind(&SwiftenPlugin::handleSubscriptionRequest, this, user, _1, _2, _3)); + client->getSubscriptionManager()->onPresenceSubscriptionRevoked.connect(boost::bind(&SwiftenPlugin::handleSubscriptionRevoked, this, user, _1, _2)); Swift::ClientOptions opt; opt.allowPLAINWithoutTLS = true; client->connect(opt); + + boost::shared_ptr handler = boost::make_shared(this, user); + client->getIQRouter()->addHandler(handler); + m_handlers[user] = handler; + } + + void handleSubscriptionRequest(const std::string &user, const Swift::JID& jid, const std::string& message, Swift::Presence::ref presence) { + handleSwiftPresenceChanged(user, presence); + } + + void handleSubscriptionRevoked(const std::string &user, const Swift::JID& jid, const std::string& message) { + Swift::Presence::ref presence = Swift::Presence::create(); + presence->setTo(user); + presence->setFrom(jid); + presence->setType(Swift::Presence::Unsubscribe); + handleSwiftPresenceChanged(user, presence); } void handleLogoutRequest(const std::string &user, const std::string &legacyName) { @@ -306,43 +328,20 @@ class SwiftenPlugin : public NetworkPlugin { client->getRoster()->onInitialRosterPopulated.disconnect(boost::bind(&SwiftenPlugin::handleSwiftRosterReceived, this, user)); client->getPresenceOracle()->onPresenceChange.disconnect(boost::bind(&SwiftenPlugin::handleSwiftPresenceChanged, this, user, _1)); client->disconnect(); - m_mucs.erase(user); } } void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &msg, const std::string &xhtml = "", const std::string &id = "") { - LOG4CXX_INFO(logger, "Sending message from " << user << " to " << legacyName << "."); - boost::shared_ptr client = m_users[user]; - if (client) { - boost::shared_ptr message(new Swift::Message()); - message->setTo(Swift::JID(legacyName)); - message->setFrom(client->getJID()); - message->setBody(msg); - if (client->getMUCRegistry()->isMUC(legacyName)) { - message->setType(Swift::Message::Groupchat); - boost::shared_ptr muc = m_mucs[user][legacyName]; -// handleMessage(user, legacyName, msg, muc->getNickname(), xhtml); - } - - client->sendMessage(message); - } } void handleVCardRequest(const std::string &user, const std::string &legacyName, unsigned int id) { - boost::shared_ptr client = m_users[user]; - if (client) { - LOG4CXX_INFO(logger, user << ": fetching VCard of " << legacyName << " id=" << id); - Swift::GetVCardRequest::ref request = Swift::GetVCardRequest::create(Swift::JID(legacyName), client->getIQRouter()); - request->onResponse.connect(boost::bind(&SwiftenPlugin::handleSwiftVCardReceived, this, user, id, _1, _2)); - request->send(); - } } void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups) { boost::shared_ptr client = m_users[user]; if (client) { LOG4CXX_INFO(logger, user << ": Added/Updated buddy " << buddyName << "."); - if (!client->getRoster()->containsJID(buddyName)) { + if (!client->getRoster()->containsJID(buddyName) || client->getRoster()->getSubscriptionStateForJID(buddyName) != Swift::RosterItemPayload::Both) { Swift::RosterItemPayload item; item.setName(alias); item.setJID(buddyName); @@ -381,39 +380,17 @@ class SwiftenPlugin : public NetworkPlugin { } void handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) { - boost::shared_ptr client = m_users[user]; - if (client) { - if (client->getMUCRegistry()->isMUC(room)) { - return; - } - boost::shared_ptr muc = boost::shared_ptr( new MUCController(user, client, room, nickname, password)); - m_mucs[user][room] = muc; - } } void handleLeaveRoomRequest(const std::string &user, const std::string &room) { - boost::shared_ptr client = m_users[user]; - if (client) { - if (!client->getMUCRegistry()->isMUC(room)) { - return; - } - boost::shared_ptr muc = m_mucs[user][room]; - if (!muc) { - m_mucs[user].erase(room); - return; - } - - muc->part(); - m_mucs[user].erase(room); - } } private: Config *config; std::map > m_users; - std::map > > m_mucs; + std::map > m_handlers; }; #ifndef WIN32