diff options
| -rw-r--r-- | Swift/Controllers/MUCController.cpp | 3 | ||||
| -rw-r--r-- | Swift/Controllers/MUCController.h | 2 | ||||
| -rw-r--r-- | Swift/Controllers/MainController.cpp | 10 | ||||
| -rw-r--r-- | Swift/Controllers/MainController.h | 2 | ||||
| -rw-r--r-- | Swiften/Client/DummyStanzaChannel.h | 10 | ||||
| -rw-r--r-- | Swiften/Client/StanzaChannel.h | 5 | ||||
| -rw-r--r-- | Swiften/Elements/Presence.h | 5 | ||||
| -rw-r--r-- | Swiften/MUC/MUC.cpp | 67 | ||||
| -rw-r--r-- | Swiften/MUC/MUC.h | 29 | ||||
| -rw-r--r-- | Swiften/Presence/PresenceSender.cpp | 49 | ||||
| -rw-r--r-- | Swiften/Presence/PresenceSender.h | 24 | ||||
| -rw-r--r-- | Swiften/SConscript | 2 |
12 files changed, 147 insertions, 61 deletions
diff --git a/Swift/Controllers/MUCController.cpp b/Swift/Controllers/MUCController.cpp index 848f540..da7a9e7 100644 --- a/Swift/Controllers/MUCController.cpp +++ b/Swift/Controllers/MUCController.cpp @@ -1,77 +1,78 @@ #include "Swift/Controllers/MUCController.h" #include <boost/bind.hpp> #include "Swiften/Base/foreach.h" #include "Swift/Controllers/ChatWindow.h" #include "Swift/Controllers/ChatWindowFactory.h" #include "Swiften/MUC/MUC.h" #include "Swiften/Client/StanzaChannel.h" #include "Swiften/Roster/Roster.h" #include "Swiften/Roster/SetPresence.h" #include "Swiften/Roster/TreeWidgetFactory.h" namespace Swift { /** * The controller does not gain ownership of the stanzaChannel, nor the factory. */ MUCController::MUCController ( const JID& self, const JID &muc, const String &nick, StanzaChannel* stanzaChannel, + PresenceSender* presenceSender, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, TreeWidgetFactory *treeWidgetFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager) : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc, presenceOracle, avatarManager), - muc_(new MUC(stanzaChannel, muc)), + muc_(new MUC(stanzaChannel, presenceSender, muc)), nick_(nick), treeWidgetFactory_(treeWidgetFactory) { roster_ = new Roster(chatWindow_->getTreeWidget(), treeWidgetFactory_); chatWindow_->onClosed.connect(boost::bind(&MUCController::handleWindowClosed, this)); muc_->joinAs(nick); 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)); chatWindow_->convertToMUC(); chatWindow_->show(); } MUCController::~MUCController() { delete muc_; delete roster_; } void MUCController::handleWindowClosed() { muc_->part(); } void MUCController::handleOccupantJoined(const MUCOccupant& occupant) { roster_->addContact(JID(toJID_.getNode(), toJID_.getDomain(), occupant.getNick()), occupant.getNick(), "Occupants"); } void MUCController::handleOccupantLeft(const MUCOccupant& occupant, MUC::LeavingType, const String& /*reason*/) { roster_->removeContact(JID(toJID_.getNode(), toJID_.getDomain(), occupant.getNick())); } void MUCController::handleOccupantPresenceChange(boost::shared_ptr<Presence> presence) { roster_->applyOnItems(SetPresence(presence, JID::WithResource)); } bool MUCController::isIncomingMessageFromMe(boost::shared_ptr<Message> message) { JID from = message->getFrom(); return nick_ == from.getResource(); } String MUCController::senderDisplayNameFromMessage(const JID& from) { return from.getResource(); } void MUCController::preSendMessageRequest(boost::shared_ptr<Message> message) { message->setType(Swift::Message::Groupchat); } } diff --git a/Swift/Controllers/MUCController.h b/Swift/Controllers/MUCController.h index af4a23a..7ee6e81 100644 --- a/Swift/Controllers/MUCController.h +++ b/Swift/Controllers/MUCController.h @@ -1,47 +1,47 @@ #ifndef SWIFTEN_MUCController_H #define SWIFTEN_MUCController_H #include <boost/shared_ptr.hpp> #include "Swiften/Base/String.h" #include "Swift/Controllers/ChatControllerBase.h" #include "Swiften/Elements/Message.h" #include "Swiften/Elements/DiscoInfo.h" #include "Swiften/JID/JID.h" #include "Swiften/MUC/MUC.h" #include "Swiften/MUC/MUCOccupant.h" namespace Swift { class StanzaChannel; class IQRouter; class ChatWindow; class ChatWindowFactory; class Roster; class TreeWidgetFactory; class AvatarManager; class MUCController : public ChatControllerBase { public: - MUCController(const JID& self, const JID &muc, const String &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, TreeWidgetFactory *treeWidgetFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager); + MUCController(const JID& self, const JID &muc, const String &nick, StanzaChannel* stanzaChannel, PresenceSender* presenceSender, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, TreeWidgetFactory *treeWidgetFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager); ~MUCController(); protected: void preSendMessageRequest(boost::shared_ptr<Message> message); bool isIncomingMessageFromMe(boost::shared_ptr<Message> message); String senderDisplayNameFromMessage(const JID& from); private: void handleWindowClosed(); void handleOccupantJoined(const MUCOccupant& occupant); void handleOccupantLeft(const MUCOccupant& occupant, MUC::LeavingType type, const String& reason); void handleOccupantPresenceChange(boost::shared_ptr<Presence> presence); private: MUC *muc_; String nick_; TreeWidgetFactory *treeWidgetFactory_; Roster *roster_; }; } #endif diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp index f54e0a2..22d71e5 100644 --- a/Swift/Controllers/MainController.cpp +++ b/Swift/Controllers/MainController.cpp @@ -1,308 +1,312 @@ #include "Swift/Controllers/MainController.h" #include <boost/bind.hpp> #include <boost/lexical_cast.hpp> #include <boost/shared_ptr.hpp> #include <stdlib.h> #include "Swiften/Application/Application.h" #include "Swiften/Application/ApplicationMessageDisplay.h" #include "Swift/Controllers/ChatController.h" #include "Swift/Controllers/ChatWindowFactory.h" #include "Swift/Controllers/EventController.h" #include "Swift/Controllers/LoginWindow.h" #include "Swift/Controllers/LoginWindowFactory.h" #include "Swift/Controllers/MainWindow.h" #include "Swift/Controllers/MainWindowFactory.h" #include "Swift/Controllers/MUCController.h" #include "Swift/Controllers/NickResolver.h" #include "Swift/Controllers/ProfileSettingsProvider.h" #include "Swift/Controllers/RosterController.h" #include "Swift/Controllers/SoundEventController.h" #include "Swift/Controllers/SoundPlayer.h" #include "Swift/Controllers/SystemTray.h" #include "Swift/Controllers/SystemTrayController.h" #include "Swift/Controllers/XMPPRosterController.h" #include "Swiften/Base/foreach.h" #include "Swiften/Base/String.h" #include "Swiften/Client/Client.h" +#include "Swiften/Presence/PresenceSender.h" #include "Swiften/Elements/Presence.h" #include "Swiften/Elements/VCardUpdate.h" #include "Swiften/Queries/Responders/SoftwareVersionResponder.h" #include "Swiften/Roster/TreeWidgetFactory.h" #include "Swiften/Settings/SettingsProvider.h" #include "Swiften/Elements/DiscoInfo.h" #include "Swiften/Queries/Responders/DiscoInfoResponder.h" #include "Swiften/Disco/CapsInfoGenerator.h" #include "Swiften/Queries/Requests/GetDiscoInfoRequest.h" #include "Swiften/Queries/Requests/GetVCardRequest.h" #include "Swiften/Avatars/AvatarFileStorage.h" #include "Swiften/Avatars/AvatarManager.h" #include "Swiften/StringCodecs/SHA1.h" namespace { void printIncomingData(const Swift::String& data) { std::cout << "<- " << data << std::endl; } void printOutgoingData(const Swift::String& data) { std::cout << "-> " << data << std::endl; } } namespace Swift { static const String CLIENT_NAME = "Swift"; static const String CLIENT_VERSION = "0.3"; static const String CLIENT_NODE = "http://swift.im"; typedef std::pair<JID, ChatController*> JIDChatControllerPair; typedef std::pair<JID, MUCController*> JIDMUCControllerPair; MainController::MainController(ChatWindowFactory* chatWindowFactory, MainWindowFactory *mainWindowFactory, LoginWindowFactory *loginWindowFactory, TreeWidgetFactory *treeWidgetFactory, SettingsProvider *settings, Application* application, SystemTray* systemTray, SoundPlayer* soundPlayer) - : timerFactory_(&boostIOServiceThread_.getIOService()), idleDetector_(&idleQuerier_, &timerFactory_, 100), client_(NULL), chatWindowFactory_(chatWindowFactory), mainWindowFactory_(mainWindowFactory), loginWindowFactory_(loginWindowFactory), treeWidgetFactory_(treeWidgetFactory), settings_(settings), xmppRosterController_(NULL), rosterController_(NULL), loginWindow_(NULL), clientVersionResponder_(NULL), nickResolver_(NULL), discoResponder_(NULL) { + : timerFactory_(&boostIOServiceThread_.getIOService()), idleDetector_(&idleQuerier_, &timerFactory_, 100), client_(NULL), presenceSender_(NULL), chatWindowFactory_(chatWindowFactory), mainWindowFactory_(mainWindowFactory), loginWindowFactory_(loginWindowFactory), treeWidgetFactory_(treeWidgetFactory), settings_(settings), xmppRosterController_(NULL), rosterController_(NULL), loginWindow_(NULL), clientVersionResponder_(NULL), nickResolver_(NULL), discoResponder_(NULL) { application_ = application; presenceOracle_ = NULL; avatarManager_ = NULL; avatarStorage_ = new AvatarFileStorage(application_->getAvatarDir()); eventController_ = new EventController(); eventController_->onEventQueueLengthChange.connect(boost::bind(&MainController::handleEventQueueLengthChange, this, _1)); systemTrayController_ = new SystemTrayController(eventController_, systemTray); soundEventController_ = new SoundEventController(eventController_, soundPlayer, settings->getBoolSetting("playSounds", true)); loginWindow_ = loginWindowFactory_->createLoginWindow(); foreach (String profile, settings->getAvailableProfiles()) { ProfileSettingsProvider* profileSettings = new ProfileSettingsProvider(profile, settings); loginWindow_->addAvailableAccount(profileSettings->getStringSetting("jid"), profileSettings->getStringSetting("pass"), profileSettings->getStringSetting("certificate")); delete profileSettings; } loginWindow_->onLoginRequest.connect(boost::bind(&MainController::handleLoginRequest, this, _1, _2, _3, _4)); loginWindow_->onCancelLoginRequest.connect(boost::bind(&MainController::handleCancelLoginRequest, this)); idleDetector_.setIdleTimeSeconds(600); idleDetector_.onIdleChanged.connect(boost::bind(&MainController::handleInputIdleChanged, this, _1)); } MainController::~MainController() { foreach (JIDChatControllerPair controllerPair, chatControllers_) { delete controllerPair.second; } foreach (JIDMUCControllerPair controllerPair, mucControllers_) { delete controllerPair.second; } delete systemTrayController_; delete soundEventController_; delete avatarStorage_; resetClient(); } void MainController::resetClient() { serverDiscoInfo_ = boost::shared_ptr<DiscoInfo>(); xmppRoster_ = boost::shared_ptr<XMPPRoster>(); delete presenceOracle_; presenceOracle_ = NULL; delete nickResolver_; nickResolver_ = NULL; delete avatarManager_; avatarManager_ = NULL; delete rosterController_; rosterController_ = NULL; delete xmppRosterController_; xmppRosterController_ = NULL; delete clientVersionResponder_; clientVersionResponder_ = NULL; delete discoResponder_; discoResponder_ = NULL; + delete presenceSender_; + presenceSender_ = NULL; delete client_; client_ = NULL; } void MainController::handleConnected() { //FIXME: this freshLogin thing is temporary so I can see what's what before I split into a seperate method. bool freshLogin = rosterController_ == NULL; if (freshLogin) { serverDiscoInfo_ = boost::shared_ptr<DiscoInfo>(new DiscoInfo()); xmppRoster_ = boost::shared_ptr<XMPPRoster>(new XMPPRoster()); presenceOracle_ = new PresenceOracle(client_); lastSentPresence_ = boost::shared_ptr<Presence>(); client_->onPresenceReceived.connect(boost::bind(&MainController::handleIncomingPresence, this, _1)); nickResolver_ = new NickResolver(xmppRoster_); avatarManager_ = new AvatarManager(client_, client_, avatarStorage_, this); rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, treeWidgetFactory_, nickResolver_); rosterController_->onStartChatRequest.connect(boost::bind(&MainController::handleChatRequest, this, _1)); rosterController_->onJoinMUCRequest.connect(boost::bind(&MainController::handleJoinMUCRequest, this, _1, _2)); rosterController_->onChangeStatusRequest.connect(boost::bind(&MainController::handleChangeStatusRequest, this, _1, _2)); rosterController_->onSignOutRequest.connect(boost::bind(&MainController::signOut, this)); xmppRosterController_ = new XMPPRosterController(client_, xmppRoster_); xmppRosterController_->requestRoster(); clientVersionResponder_ = new SoftwareVersionResponder(CLIENT_NAME, CLIENT_VERSION, client_); loginWindow_->morphInto(rosterController_->getWindow()); DiscoInfo discoInfo; discoInfo.addIdentity(DiscoInfo::Identity(CLIENT_NAME, "client", "pc")); discoInfo.addFeature("urn:xmpp:sec-label:0"); capsInfo_ = boost::shared_ptr<CapsInfo>(new CapsInfo(CapsInfoGenerator(CLIENT_NODE).generateCapsInfo(discoInfo))); discoResponder_ = new DiscoInfoResponder(client_); discoResponder_->setDiscoInfo(discoInfo); discoResponder_->setDiscoInfo(capsInfo_->getNode() + "#" + capsInfo_->getVersion(), discoInfo); serverDiscoInfo_ = boost::shared_ptr<DiscoInfo>(new DiscoInfo()); } boost::shared_ptr<GetDiscoInfoRequest> discoInfoRequest(new GetDiscoInfoRequest(JID(), client_)); discoInfoRequest->onResponse.connect(boost::bind(&MainController::handleServerDiscoInfoResponse, this, _1, _2)); discoInfoRequest->send(); boost::shared_ptr<GetVCardRequest> vCardRequest(new GetVCardRequest(JID(), client_)); vCardRequest->onResponse.connect(boost::bind(&MainController::handleOwnVCardReceived, this, _1, _2)); vCardRequest->send(); //Send presence last to catch all the incoming presences. boost::shared_ptr<Presence> initialPresence; if (queuedPresence_.get() != NULL) { initialPresence = queuedPresence_; } else { initialPresence = boost::shared_ptr<Presence>(new Presence()); } initialPresence->addPayload(capsInfo_); setManagersEnabled(true); sendPresence(initialPresence); } void MainController::handleEventQueueLengthChange(int count) { application_->getApplicationMessageDisplay()->setMessage(count == 0 ? "" : boost::lexical_cast<std::string>(count).c_str()); } void MainController::reconnectAfterError() { performLoginFromCachedCredentials(); sendPresence(queuedPresence_); } void MainController::handleChangeStatusRequest(StatusShow::Type show, const String &statusText) { boost::shared_ptr<Presence> presence(new Presence()); if (show == StatusShow::None) { // FIXME: This is wrong. None doesn't mean unavailable presence->setType(Presence::Unavailable); } else { presence->setShow(show); } presence->setStatus(statusText); if (presence->getType() != Presence::Unavailable && !client_->isAvailable()) { performLoginFromCachedCredentials(); queuedPresence_ = presence; } else { sendPresence(presence); } } void MainController::sendPresence(boost::shared_ptr<Presence> presence) { if (!vCardPhotoHash_.isEmpty()) { presence->addPayload(boost::shared_ptr<VCardUpdate>(new VCardUpdate(vCardPhotoHash_))); } presence->addPayload(capsInfo_); lastSentPresence_ = presence; - client_->sendPresence(presence); + presenceSender_->sendPresence(presence); if (presence->getType() == Presence::Unavailable) { logout(); } } void MainController::handleInputIdleChanged(bool idle) { if (!client_ || !client_->isAvailable()) { return; } if (idle) { preIdlePresence_ = lastSentPresence_; boost::shared_ptr<Presence> presence(new Presence()); presence->setShow(StatusShow::Away); presence->setStatus("Auto-away"); sendPresence(presence); } else { if (client_) { sendPresence(preIdlePresence_); } else { queuedPresence_ = preIdlePresence_; } } } void MainController::handleIncomingPresence(boost::shared_ptr<Presence> presence) { //FIXME: subscribe, subscribed rosterController_->handleIncomingPresence(presence); } void MainController::handleLoginRequest(const String &username, const String &password, const String& certificateFile, bool remember) { loginWindow_->setMessage(""); ProfileSettingsProvider* profileSettings = new ProfileSettingsProvider(username, settings_); profileSettings->storeString("jid", username); profileSettings->storeString("certificate", certificateFile); profileSettings->storeString("pass", remember ? password : ""); loginWindow_->addAvailableAccount(profileSettings->getStringSetting("jid"), profileSettings->getStringSetting("pass"), profileSettings->getStringSetting("certificate")); delete profileSettings; jid_ = JID(username); password_ = password; certificateFile_ = certificateFile; performLoginFromCachedCredentials(); } void MainController::performLoginFromCachedCredentials() { if (!client_) { client_ = new Swift::Client(jid_, password_); + presenceSender_ = new PresenceSender(client_); //client_->onDataRead.connect(&printIncomingData); //client_->onDataWritten.connect(&printOutgoingData); if (!certificateFile_.isEmpty()) { client_->setCertificate(certificateFile_); } client_->onError.connect(boost::bind(&MainController::handleError, this, _1)); client_->onConnected.connect(boost::bind(&MainController::handleConnected, this)); client_->onMessageReceived.connect(boost::bind(&MainController::handleIncomingMessage, this, _1)); } client_->connect(); } void MainController::handleError(const ClientError& error) { String message; switch(error.getType()) { case ClientError::UnknownError: message = "Unknown Error"; break; case ClientError::DomainNameResolveError: message = "Unable to find server"; break; case ClientError::ConnectionError: message = "Error connecting to server"; break; case ClientError::ConnectionReadError: message = "Error while receiving server data"; break; case ClientError::ConnectionWriteError: message = "Error while sending data to the server"; break; case ClientError::XMLError: message = "Error parsing server data"; break; case ClientError::AuthenticationFailedError: message = "Login/password invalid"; break; case ClientError::ServerVerificationFailedError: message = "Server verification failed"; break; case ClientError::NoSupportedAuthMechanismsError: message = "Authentication mechanisms not supported"; break; case ClientError::UnexpectedElementError: message = "Unexpected response"; break; case ClientError::ResourceBindError: message = "Error binding resource"; break; case ClientError::SessionStartError: message = "Error starting session"; break; case ClientError::TLSError: message = "Encryption error"; break; case ClientError::ClientCertificateLoadError: message = "Error loading certificate (Invalid password?)"; break; case ClientError::ClientCertificateError: message = "Certificate not authorized"; break; } if (!rosterController_) { //hasn't been logged in yet signOut(); loginWindow_->setMessage(message); } logout(); if (rosterController_) { //reconnectAfterError(); } } void MainController::handleCancelLoginRequest() { signOut(); } void MainController::signOut() { logout(); loginWindow_->loggedOut(); @@ -323,97 +327,97 @@ void MainController::logout() { if (client_ && client_->isAvailable()) { client_->disconnect(); } if (rosterController_) { rosterController_->getWindow()->setMyStatusType(StatusShow::None); rosterController_->getWindow()->setMyStatusText(""); } setManagersEnabled(false); } void MainController::setManagersEnabled(bool enabled) { foreach (JIDChatControllerPair controllerPair, chatControllers_) { //printf("Setting enabled on %d to %d\n", controllerPair.second, enabled); controllerPair.second->setEnabled(enabled); } foreach (JIDMUCControllerPair controllerPair, mucControllers_) { controllerPair.second->setEnabled(enabled); } if (rosterController_) { rosterController_->setEnabled(enabled); } } void MainController::handleChatRequest(const String &contact) { ChatController* controller = getChatController(JID(contact)); controller->showChatWindow(); controller->activateChatWindow(); } ChatController* MainController::getChatController(const JID &contact) { JID lookupContact(contact); if (chatControllers_.find(lookupContact) == chatControllers_.end()) { lookupContact = JID(contact.toBare()); } if (chatControllers_.find(lookupContact) == chatControllers_.end()) { chatControllers_[contact] = new ChatController(jid_, client_, client_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_); chatControllers_[contact]->setAvailableServerFeatures(serverDiscoInfo_); lookupContact = contact; } return chatControllers_[lookupContact]; } void MainController::handleChatControllerJIDChanged(const JID& from, const JID& to) { chatControllers_[to] = chatControllers_[from]; chatControllers_.erase(from); } void MainController::handleJoinMUCRequest(const JID &muc, const String &nick) { - mucControllers_[muc] = new MUCController(jid_, muc, nick, client_, client_, chatWindowFactory_, treeWidgetFactory_, presenceOracle_, avatarManager_); + mucControllers_[muc] = new MUCController(jid_, muc, nick, client_, presenceSender_, client_, chatWindowFactory_, treeWidgetFactory_, presenceOracle_, avatarManager_); mucControllers_[muc]->setAvailableServerFeatures(serverDiscoInfo_); } void MainController::handleIncomingMessage(boost::shared_ptr<Message> message) { JID jid = message->getFrom(); boost::shared_ptr<MessageEvent> event(new MessageEvent(message)); // Try to deliver it to a MUC if (message->getType() == Message::Groupchat || message->getType() == Message::Error) { std::map<JID, MUCController*>::iterator i = mucControllers_.find(jid.toBare()); if (i != mucControllers_.end()) { i->second->handleIncomingMessage(event); return; } else if (message->getType() == Message::Groupchat) { //FIXME: Error handling - groupchat messages from an unknown muc. return; } } //if not a mucroom eventController_->handleIncomingEvent(event); // FIXME: This logic should go into a chat manager if (event->isReadable()) { getChatController(jid)->handleIncomingMessage(event); } } void MainController::handleServerDiscoInfoResponse(boost::shared_ptr<DiscoInfo> info, const boost::optional<ErrorPayload>& error) { if (!error) { serverDiscoInfo_ = info; foreach (JIDChatControllerPair pair, chatControllers_) { pair.second->setAvailableServerFeatures(info); } foreach (JIDMUCControllerPair pair, mucControllers_) { pair.second->setAvailableServerFeatures(info); } } } bool MainController::isMUC(const JID& jid) const { return mucControllers_.find(jid.toBare()) != mucControllers_.end(); } void MainController::handleOwnVCardReceived(boost::shared_ptr<VCard> vCard, const boost::optional<ErrorPayload>& error) { if (!error && !vCard->getPhoto().isEmpty()) { vCardPhotoHash_ = SHA1::getHexHash(vCard->getPhoto()); diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h index 270b131..78e49a2 100644 --- a/Swift/Controllers/MainController.h +++ b/Swift/Controllers/MainController.h @@ -1,121 +1,123 @@ #pragma once #include <boost/signals.hpp> #include <boost/shared_ptr.hpp> #include <vector> #include "Swiften/Network/BoostIOServiceThread.h" #include "Swiften/Network/BoostTimerFactory.h" #include "SwifTools/Idle/PlatformIdleQuerier.h" #include "SwifTools/Idle/ActualIdleDetector.h" #include "Swiften/Base/String.h" #include "Swiften/Client/ClientError.h" #include "Swiften/JID/JID.h" #include "Swiften/Elements/VCard.h" #include "Swiften/Elements/DiscoInfo.h" #include "Swiften/Elements/ErrorPayload.h" #include "Swiften/Elements/Presence.h" #include "Swiften/Elements/Message.h" #include "Swiften/Settings/SettingsProvider.h" #include "Swiften/Elements/CapsInfo.h" #include "Swiften/MUC/MUCRegistry.h" #include "Swiften/Roster/XMPPRoster.h" namespace Swift { class AvatarStorage; class Application; class Client; class ChatWindowFactory; class ChatController; class EventController; class MainWindowFactory; class MainWindow; class NickResolver; class RosterController; class XMPPRosterController; + class PresenceSender; class DiscoInfoResponder; class AvatarManager; class LoginWindow; class EventLoop; class SoftwareVersionResponder; class LoginWindowFactory; class TreeWidgetFactory; class MUCController; class PresenceOracle; class SystemTray; class SystemTrayController; class SoundEventController; class SoundPlayer; class MainController : public MUCRegistry { public: MainController(ChatWindowFactory* chatWindowFactory, MainWindowFactory *mainWindowFactory, LoginWindowFactory *loginWindowFactory, TreeWidgetFactory* treeWidgetFactory, SettingsProvider *settings, Application* application, SystemTray* systemTray, SoundPlayer* soundPlayer); ~MainController(); private: void resetClient(); void handleConnected(); void handleLoginRequest(const String& username, const String& password, const String& certificateFile, bool remember); void handleCancelLoginRequest(); void handleChatRequest(const String& contact); void handleJoinMUCRequest(const JID& muc, const String& nick); void handleIncomingPresence(boost::shared_ptr<Presence> presence); void handleChatControllerJIDChanged(const JID& from, const JID& to); void handleIncomingMessage(boost::shared_ptr<Message> message); void handleChangeStatusRequest(StatusShow::Type show, const String &statusText); void handleError(const ClientError& error); void handleServerDiscoInfoResponse(boost::shared_ptr<DiscoInfo>, const boost::optional<ErrorPayload>&); void handleEventQueueLengthChange(int count); void handleOwnVCardReceived(boost::shared_ptr<VCard> vCard, const boost::optional<ErrorPayload>& error); ChatController* getChatController(const JID &contact); void sendPresence(boost::shared_ptr<Presence> presence); void handleInputIdleChanged(bool); void logout(); void signOut(); virtual bool isMUC(const JID& muc) const; void performLoginFromCachedCredentials(); void reconnectAfterError(); void setManagersEnabled(bool enabled); BoostIOServiceThread boostIOServiceThread_; BoostTimerFactory timerFactory_; PlatformIdleQuerier idleQuerier_; ActualIdleDetector idleDetector_; Client* client_; + PresenceSender* presenceSender_; ChatWindowFactory* chatWindowFactory_; MainWindowFactory* mainWindowFactory_; LoginWindowFactory* loginWindowFactory_; TreeWidgetFactory* treeWidgetFactory_; SettingsProvider *settings_; Application* application_; AvatarStorage* avatarStorage_; ChatController* chatController_; XMPPRosterController* xmppRosterController_; RosterController* rosterController_; EventController* eventController_; LoginWindow* loginWindow_; SoftwareVersionResponder* clientVersionResponder_; NickResolver* nickResolver_; DiscoInfoResponder* discoResponder_; boost::shared_ptr<CapsInfo> capsInfo_; std::map<JID, MUCController*> mucControllers_; std::map<JID, ChatController*> chatControllers_; boost::shared_ptr<DiscoInfo> serverDiscoInfo_; boost::shared_ptr<XMPPRoster> xmppRoster_;; JID jid_; PresenceOracle* presenceOracle_; SystemTrayController* systemTrayController_; SoundEventController* soundEventController_; AvatarManager* avatarManager_; boost::shared_ptr<Presence> lastSentPresence_; boost::shared_ptr<Presence> preIdlePresence_; String vCardPhotoHash_; boost::shared_ptr<Presence> queuedPresence_; String password_; String certificateFile_; }; } diff --git a/Swiften/Client/DummyStanzaChannel.h b/Swiften/Client/DummyStanzaChannel.h index 052c470..d618167 100644 --- a/Swiften/Client/DummyStanzaChannel.h +++ b/Swiften/Client/DummyStanzaChannel.h @@ -1,38 +1,38 @@ #pragma once #include <vector> #include "Swiften/Client/StanzaChannel.h" namespace Swift { class DummyStanzaChannel : public StanzaChannel { public: DummyStanzaChannel() {} virtual void sendStanza(boost::shared_ptr<Stanza> stanza) { - sentStanzas_.push_back(stanza); + sentStanzas.push_back(stanza); } virtual void sendIQ(boost::shared_ptr<IQ> iq) { - sentStanzas_.push_back(iq); + sentStanzas.push_back(iq); } virtual void sendMessage(boost::shared_ptr<Message> message) { - sentStanzas_.push_back(message); + sentStanzas.push_back(message); } virtual void sendPresence(boost::shared_ptr<Presence> presence) { - sentStanzas_.push_back(presence); + sentStanzas.push_back(presence); } virtual String getNewIQID() { return "test-id"; } virtual bool isAvailable() { return true; } - std::vector<boost::shared_ptr<Stanza> > sentStanzas_; + std::vector<boost::shared_ptr<Stanza> > sentStanzas; }; } diff --git a/Swiften/Client/StanzaChannel.h b/Swiften/Client/StanzaChannel.h index 37c58c7..a0e291d 100644 --- a/Swiften/Client/StanzaChannel.h +++ b/Swiften/Client/StanzaChannel.h @@ -1,23 +1,20 @@ -#ifndef SWIFTEN_MessageChannel_H -#define SWIFTEN_MessageChannel_H +#pragma once #include <boost/signal.hpp> #include <boost/shared_ptr.hpp> #include "Swiften/Queries/IQChannel.h" #include "Swiften/Elements/Message.h" #include "Swiften/Elements/Presence.h" namespace Swift { class StanzaChannel : public IQChannel { public: virtual void sendMessage(boost::shared_ptr<Message>) = 0; virtual void sendPresence(boost::shared_ptr<Presence>) = 0; virtual bool isAvailable() = 0; boost::signal<void (boost::shared_ptr<Message>)> onMessageReceived; boost::signal<void (boost::shared_ptr<Presence>) > onPresenceReceived; }; } - -#endif diff --git a/Swiften/Elements/Presence.h b/Swiften/Elements/Presence.h index 002ed0e..a1f15fa 100644 --- a/Swiften/Elements/Presence.h +++ b/Swiften/Elements/Presence.h @@ -1,61 +1,58 @@ -#ifndef SWIFTEN_Presence -#define SWIFTEN_Presence +#pragma once #include "Swiften/Elements/Stanza.h" #include "Swiften/Elements/Status.h" #include "Swiften/Elements/StatusShow.h" #include "Swiften/Elements/Priority.h" namespace Swift { class Presence : public Stanza { public: enum Type { Available, Error, Probe, Subscribe, Subscribed, Unavailable, Unsubscribe, Unsubscribed }; Presence() : type_(Available) /*, showType_(Online)*/ {} Presence(const String& status) : type_(Available) { setStatus(status); } Type getType() const { return type_; } void setType(Type type) { type_ = type; } StatusShow::Type getShow() const { boost::shared_ptr<StatusShow> show(getPayload<StatusShow>()); if (show) { return show->getType(); } return type_ == Available ? StatusShow::Online : StatusShow::None; } void setShow(const StatusShow::Type &show) { updatePayload(boost::shared_ptr<StatusShow>(new StatusShow(show))); } String getStatus() const { boost::shared_ptr<Status> status(getPayload<Status>()); if (status) { return status->getText(); } return ""; } void setStatus(const String& status) { updatePayload(boost::shared_ptr<Status>(new Status(status))); } int getPriority() const { boost::shared_ptr<Priority> priority(getPayload<Priority>()); return (priority ? priority->getPriority() : 0); } void setPriority(int priority) { updatePayload(boost::shared_ptr<Priority>(new Priority(priority))); } private: Presence::Type type_; }; } - -#endif diff --git a/Swiften/MUC/MUC.cpp b/Swiften/MUC/MUC.cpp index 2b8054f..a6fbcbd 100644 --- a/Swiften/MUC/MUC.cpp +++ b/Swiften/MUC/MUC.cpp @@ -1,69 +1,70 @@ #include "Swiften/MUC/MUC.h" #include <boost/bind.hpp> #include <boost/shared_ptr.hpp> +#include "Swiften/Presence/PresenceSender.h" #include "Swiften/Client/StanzaChannel.h" #include "Swiften/Elements/IQ.h" -#include "Swiften/Elements/Message.h" #include "Swiften/Elements/MUCPayload.h" -#include "Swiften/Elements/Presence.h" namespace Swift { typedef std::pair<String, MUCOccupant> StringMUCOccupantPair; -MUC::MUC(StanzaChannel* stanzaChannel, const JID &muc) : muc_(muc), stanzaChannel_(stanzaChannel) { - stanzaChannel_->onPresenceReceived.connect(boost::bind(&MUC::handleIncomingPresence, this, _1)); -} - -MUC::~MUC() { +MUC::MUC(StanzaChannel* stanzaChannel, PresenceSender* presenceSender, const JID &muc) : ownMUCJID(muc), stanzaChannel(stanzaChannel), presenceSender(presenceSender) { + stanzaChannel->onPresenceReceived.connect(boost::bind(&MUC::handleIncomingPresence, this, _1)); } void MUC::joinAs(const String &nick) { + firstPresenceSeen = false; + + ownMUCJID = JID(ownMUCJID.getNode(), ownMUCJID.getDomain(), nick); + boost::shared_ptr<Presence> joinPresence(new Presence()); - joinPresence->setTo(JID(muc_.getNode(), muc_.getDomain(), nick)); + joinPresence->setTo(ownMUCJID); joinPresence->addPayload(boost::shared_ptr<Payload>(new MUCPayload())); - stanzaChannel_->sendPresence(joinPresence); - myNick_ = nick; + presenceSender->sendPresence(joinPresence); } void MUC::part() { - boost::shared_ptr<Presence> partPresence(new Presence()); - partPresence->setType(Presence::Unavailable); - partPresence->setTo(JID(muc_.getNode(), muc_.getDomain(), myNick_)); - stanzaChannel_->sendPresence(partPresence); + presenceSender->removeDirectedPresenceReceiver(ownMUCJID); } void MUC::handleIncomingPresence(boost::shared_ptr<Presence> presence) { - if (presence->getFrom().toBare() != muc_ || presence->getFrom().getResource() == "") { + if (!isFromMUC(presence->getFrom())) { return; } + + if (!firstPresenceSeen) { + if (presence->getType() == Presence::Error) { + onJoinComplete(JoinFailed); + return; + } + firstPresenceSeen = true; + onJoinComplete(JoinSucceeded); + presenceSender->addDirectedPresenceReceiver(ownMUCJID); + } + String nick = presence->getFrom().getResource(); + if (nick.isEmpty()) { + return; + } if (presence->getType() == Presence::Unavailable) { - foreach (StringMUCOccupantPair occupantPair, occupants_) { - if (occupantPair.first == nick) { - occupants_.erase(nick); - onOccupantLeft(occupantPair.second, Part, ""); - break; - } - } - } else if (presence->getType() == Presence::Available) { - bool found = false; - foreach (StringMUCOccupantPair occupantPair, occupants_) { - if (occupantPair.first == nick) { - found = true; - break; - } + std::map<String,MUCOccupant>::iterator i = occupants.find(nick); + if (i != occupants.end()) { + onOccupantLeft(i->second, Part, ""); + occupants.erase(i); } - if (!found) { - MUCOccupant occupant(nick); - occupants_.insert(occupants_.end(), std::pair<String, MUCOccupant>(nick, occupant)); - onOccupantJoined(occupant); + } + else if (presence->getType() == Presence::Available) { + std::pair<std::map<String,MUCOccupant>::iterator, bool> result = occupants.insert(std::make_pair(nick, MUCOccupant(nick))); + if (result.second) { + onOccupantJoined(result.first->second); } onOccupantPresenceChange(presence); } } } diff --git a/Swiften/MUC/MUC.h b/Swiften/MUC/MUC.h index 45bcbd3..2a327f4 100644 --- a/Swiften/MUC/MUC.h +++ b/Swiften/MUC/MUC.h @@ -1,49 +1,58 @@ -#ifndef SWIFTEN_MUC_H -#define SWIFTEN_MUC_H +#pragma once #include "Swiften/JID/JID.h" #include "Swiften/Base/String.h" #include "Swiften/Elements/Message.h" #include "Swiften/Elements/Presence.h" #include "Swiften/MUC/MUCOccupant.h" #include <boost/signals.hpp> #include <boost/shared_ptr.hpp> #include <map> namespace Swift { class StanzaChannel; + class PresenceSender; class MUC { public: enum JoinResult { JoinSucceeded, JoinFailed }; enum LeavingType { Part }; public: - MUC(StanzaChannel* stanzaChannel, const JID &muc); - ~MUC(); + MUC(StanzaChannel* stanzaChannel, PresenceSender* presenceSender, const JID &muc); void joinAs(const String &nick); String getCurrentNick(); void part(); void handleIncomingMessage(boost::shared_ptr<Message> message); public: boost::signal<void (JoinResult)> onJoinComplete; boost::signal<void (boost::shared_ptr<Message>)> onMessageReceived; boost::signal<void (boost::shared_ptr<Presence>)> onOccupantPresenceChange; boost::signal<void (const MUCOccupant&)> onOccupantJoined; /**Occupant, type, and reason. */ boost::signal<void (const MUCOccupant&, LeavingType, const String&)> onOccupantLeft; private: + bool isFromMUC(const JID& j) const { + return ownMUCJID.equals(j, JID::WithoutResource); + } + + const String& getOwnNick() const { + return ownMUCJID.getResource(); + } + + private: void handleIncomingPresence(boost::shared_ptr<Presence> presence); - JID muc_; - StanzaChannel *stanzaChannel_; - String myNick_; - std::map<String, MUCOccupant> occupants_; + + private: + JID ownMUCJID; + StanzaChannel* stanzaChannel; + PresenceSender* presenceSender; + std::map<String, MUCOccupant> occupants; + bool firstPresenceSeen; }; } - -#endif diff --git a/Swiften/Presence/PresenceSender.cpp b/Swiften/Presence/PresenceSender.cpp new file mode 100644 index 0000000..8e7ef68 --- /dev/null +++ b/Swiften/Presence/PresenceSender.cpp @@ -0,0 +1,49 @@ +#include "Swiften/Presence/PresenceSender.h" +#include "Swiften/Base/foreach.h" +#include "Swiften/Client/StanzaChannel.h" + +namespace Swift { + +PresenceSender::PresenceSender(StanzaChannel* channel) : channel(channel) { +} + +void PresenceSender::sendPresence(boost::shared_ptr<Presence> presence) { + if (!channel->isAvailable()) { + return; + } + + channel->sendPresence(presence); + + if (!presence->getTo().isValid()) { + boost::shared_ptr<Presence> presenceCopy(new Presence(*presence)); + foreach(const JID& jid, directedPresenceReceivers) { + presenceCopy->setTo(jid); + channel->sendPresence(presenceCopy); + } + + lastSentUndirectedPresence = presence; + } +} + +void PresenceSender::addDirectedPresenceReceiver(const JID& jid) { + directedPresenceReceivers.insert(jid); + if (channel->isAvailable()) { + if (lastSentUndirectedPresence && lastSentUndirectedPresence->getType() == Presence::Available) { + boost::shared_ptr<Presence> presenceCopy(new Presence(*lastSentUndirectedPresence)); + presenceCopy->setTo(jid); + channel->sendPresence(presenceCopy); + } + } +} + +void PresenceSender::removeDirectedPresenceReceiver(const JID& jid) { + directedPresenceReceivers.erase(jid); + if (channel->isAvailable()) { + boost::shared_ptr<Presence> presence(new Presence()); + presence->setType(Presence::Unavailable); + presence->setTo(jid); + channel->sendPresence(presence); + } +} + +} diff --git a/Swiften/Presence/PresenceSender.h b/Swiften/Presence/PresenceSender.h new file mode 100644 index 0000000..ef69447 --- /dev/null +++ b/Swiften/Presence/PresenceSender.h @@ -0,0 +1,24 @@ +#pragma once + +#include <set> + +#include "Swiften/Elements/Presence.h" + +namespace Swift { + class StanzaChannel; + + class PresenceSender { + public: + PresenceSender(StanzaChannel*); + + void addDirectedPresenceReceiver(const JID&); + void removeDirectedPresenceReceiver(const JID&); + + void sendPresence(boost::shared_ptr<Presence>); + + private: + boost::shared_ptr<Presence> lastSentUndirectedPresence; + StanzaChannel* channel; + std::set<JID> directedPresenceReceivers; + }; +} diff --git a/Swiften/SConscript b/Swiften/SConscript index 9742768..e7e1582 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -1,83 +1,84 @@ Import("env") env["SWIFTEN_FLAGS"] = { "LIBPATH": [Dir(".")], "LIBS": ["Swiften"] } swiften_env = env.Clone() swiften_env.MergeFlags(swiften_env["BOOST_FLAGS"]) Export("swiften_env") # TODO: Move all this to a submodule SConscript myenv = swiften_env.Clone() myenv.MergeFlags(myenv["ZLIB_FLAGS"]) myenv.MergeFlags(myenv["OPENSSL_FLAGS"]) sources = [ "Avatars/AvatarFileStorage.cpp", "Avatars/AvatarManager.cpp", "Avatars/AvatarStorage.cpp", "Client/Client.cpp", "Client/ClientSession.cpp", "Compress/ZLibCodecompressor.cpp", "Disco/CapsInfoGenerator.cpp", "Elements/DiscoInfo.cpp", "Elements/Element.cpp", "Elements/IQ.cpp", "Elements/MUCPayload.cpp", "Elements/Payload.cpp", "Elements/RosterPayload.cpp", "Elements/Stanza.cpp", "MUC/MUC.cpp", "MUC/MUCOccupant.cpp", "MUC/MUCRegistry.cpp", "Notifier/Notifier.cpp", "Presence/PresenceOracle.cpp", + "Presence/PresenceSender.cpp", "Queries/IQChannel.cpp", "Queries/IQHandler.cpp", "Queries/IQRouter.cpp", "Queries/Request.cpp", "Queries/Responders/DiscoInfoResponder.cpp", "Queries/Responders/SoftwareVersionResponder.cpp", "Roster/ContactRosterItem.cpp", "Roster/Roster.cpp", "Roster/XMPPRoster.cpp", "Serializer/AuthRequestSerializer.cpp", "Serializer/AuthSuccessSerializer.cpp", "Serializer/AuthChallengeSerializer.cpp", "Serializer/AuthResponseSerializer.cpp", "Serializer/CompressRequestSerializer.cpp", "Serializer/ElementSerializer.cpp", "Serializer/MessageSerializer.cpp", "Serializer/PayloadSerializer.cpp", "Serializer/PayloadSerializerCollection.cpp", "Serializer/PayloadSerializers/CapsInfoSerializer.cpp", "Serializer/PayloadSerializers/DiscoInfoSerializer.cpp", "Serializer/PayloadSerializers/ErrorSerializer.cpp", "Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp", "Serializer/PayloadSerializers/MUCPayloadSerializer.cpp", "Serializer/PayloadSerializers/ResourceBindSerializer.cpp", "Serializer/PayloadSerializers/RosterSerializer.cpp", "Serializer/PayloadSerializers/SecurityLabelSerializer.cpp", "Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.cpp", "Serializer/PayloadSerializers/SoftwareVersionSerializer.cpp", "Serializer/PayloadSerializers/VCardSerializer.cpp", "Serializer/PayloadSerializers/VCardUpdateSerializer.cpp", "Serializer/PayloadSerializers/StorageSerializer.cpp", "Serializer/PayloadSerializers/PrivateStorageSerializer.cpp", "Serializer/PresenceSerializer.cpp", "Serializer/StanzaSerializer.cpp", "Serializer/StreamFeaturesSerializer.cpp", "Serializer/XML/XMLElement.cpp", "Serializer/XML/XMLNode.cpp", "Serializer/XMPPSerializer.cpp", "Server/ServerFromClientSession.cpp", "Server/ServerSession.cpp", "Server/ServerStanzaRouter.cpp", "Server/SimpleUserRegistry.cpp", "Server/UserRegistry.cpp", "Session/Session.cpp", "Session/SessionStream.cpp", "Session/BasicSessionStream.cpp", "StringCodecs/Base64.cpp", "StringCodecs/SHA1.cpp", @@ -110,84 +111,85 @@ env.Append(UNITTEST_SOURCES = [ File("Application/UnitTest/ApplicationTest.cpp"), File("Base/UnitTest/IDGeneratorTest.cpp"), File("Base/UnitTest/StringTest.cpp"), File("Base/UnitTest/ByteArrayTest.cpp"), File("Client/UnitTest/ClientSessionTest.cpp"), File("Compress/UnitTest/ZLibCompressorTest.cpp"), File("Compress/UnitTest/ZLibDecompressorTest.cpp"), File("Disco/UnitTest/CapsInfoGeneratorTest.cpp"), File("Elements/UnitTest/IQTest.cpp"), File("Elements/UnitTest/StanzaTest.cpp"), File("Elements/UnitTest/StanzasTest.cpp"), File("EventLoop/UnitTest/EventLoopTest.cpp"), File("EventLoop/UnitTest/SimpleEventLoopTest.cpp"), File("History/UnitTest/SQLiteHistoryManagerTest.cpp"), File("JID/UnitTest/JIDTest.cpp"), File("LinkLocal/UnitTest/LinkLocalConnectorTest.cpp"), File("LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp"), File("LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp"), File("LinkLocal/UnitTest/LinkLocalServiceTest.cpp"), File("Network/UnitTest/HostAddressTest.cpp"), File("Network/UnitTest/ConnectorTest.cpp"), File("Parser/PayloadParsers/UnitTest/BodyParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/DiscoInfoParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/ErrorParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/PriorityParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/RawXMLPayloadParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/ResourceBindParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/RosterParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/SecurityLabelParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/SecurityLabelsCatalogParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/SoftwareVersionParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/StatusParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/StatusShowParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/VCardParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/StorageParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/PrivateStorageParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/VCardUpdateParserTest.cpp"), File("Parser/UnitTest/AttributeMapTest.cpp"), File("Parser/UnitTest/IQParserTest.cpp"), File("Parser/UnitTest/MessageParserTest.cpp"), File("Parser/UnitTest/PayloadParserFactoryCollectionTest.cpp"), File("Parser/UnitTest/PresenceParserTest.cpp"), File("Parser/UnitTest/SerializingParserTest.cpp"), File("Parser/UnitTest/StanzaParserTest.cpp"), File("Parser/UnitTest/StreamFeaturesParserTest.cpp"), File("Parser/UnitTest/XMLParserTest.cpp"), File("Parser/UnitTest/XMPPParserTest.cpp"), File("Presence/UnitTest/PresenceOracleTest.cpp"), + File("Presence/UnitTest/PresenceSenderTest.cpp"), File("Queries/Requests/UnitTest/GetPrivateStorageRequestTest.cpp"), File("Queries/Responders/UnitTest/DiscoInfoResponderTest.cpp"), File("Queries/UnitTest/IQRouterTest.cpp"), File("Queries/UnitTest/RequestTest.cpp"), File("Queries/UnitTest/ResponderTest.cpp"), File("Roster/UnitTest/OfflineRosterFilterTest.cpp"), File("Roster/UnitTest/RosterTest.cpp"), File("Roster/UnitTest/XMPPRosterTest.cpp"), File("SASL/UnitTest/PLAINMessageTest.cpp"), File("SASL/UnitTest/PLAINClientAuthenticatorTest.cpp"), File("SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/PayloadsSerializer.cpp"), File("Serializer/PayloadSerializers/UnitTest/CapsInfoSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/DiscoInfoSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/ErrorSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/PrioritySerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/ResourceBindSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/RosterSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/SecurityLabelSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/SecurityLabelsCatalogSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/SoftwareVersionSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/StatusSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/StatusShowSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/VCardUpdateSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/StorageSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/PrivateStorageSerializerTest.cpp"), File("Serializer/UnitTest/StreamFeaturesSerializerTest.cpp"), File("Serializer/XML/UnitTest/XMLElementTest.cpp"), File("Server/UnitTest/ServerStanzaRouterTest.cpp"), File("StreamStack/UnitTest/StreamStackTest.cpp"), File("StreamStack/UnitTest/XMPPLayerTest.cpp"), File("StringCodecs/UnitTest/Base64Test.cpp"), File("StringCodecs/UnitTest/SHA1Test.cpp"), File("StringCodecs/UnitTest/HMACSHA1Test.cpp"), File("StringCodecs/UnitTest/PBKDF2Test.cpp"), ]) |
Swift