summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--3rdParty/Boost/SConscript6
-rw-r--r--3rdParty/Lua/SConscript4
-rw-r--r--BuildTools/CLang/.gitignore4
-rw-r--r--BuildTools/CLang/CLangDiagnosticsFlagsTool.cpp228
-rw-r--r--BuildTools/CLang/SConscript15
-rwxr-xr-xBuildTools/CheckHeaders.py21
-rwxr-xr-xBuildTools/Copyrighter.py2
-rw-r--r--BuildTools/SCons/SConstruct74
-rw-r--r--BuildTools/SCons/Tools/AppBundle.py14
-rw-r--r--COPYING1
-rw-r--r--Documentation/BuildingOnUnix.txt9
-rw-r--r--Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayload.h3
-rw-r--r--Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayloadParserFactory.h6
-rw-r--r--Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayloadSerializer.h4
-rw-r--r--Documentation/SwiftenDevelopersGuide/Examples/EchoBot/SConscript12
-rw-r--r--QA/UnitTest/SConscript14
-rw-r--r--Slimber/Cocoa/CocoaMenulet.h2
-rw-r--r--Slimber/Cocoa/SConscript1
-rw-r--r--Slimber/Server.cpp2
-rw-r--r--Sluift/Lua/Value.cpp4
-rw-r--r--Sluift/SConscript4
-rw-r--r--Sluift/sluift.cpp16
-rw-r--r--SwifTools/Application/SConscript7
-rw-r--r--SwifTools/Cocoa/CocoaAction.h (renamed from Slimber/Cocoa/CocoaAction.h)0
-rw-r--r--SwifTools/Cocoa/CocoaAction.mm (renamed from Slimber/Cocoa/CocoaAction.mm)8
-rw-r--r--SwifTools/Cocoa/SConscript8
-rw-r--r--SwifTools/Idle/PlatformIdleQuerier.cpp4
-rw-r--r--SwifTools/LastLineTracker.cpp30
-rw-r--r--SwifTools/LastLineTracker.h19
-rw-r--r--SwifTools/Linkify.cpp2
-rw-r--r--SwifTools/SConscript3
-rw-r--r--SwifTools/URIHandler/MacOSXURIHandler.h24
-rw-r--r--SwifTools/URIHandler/MacOSXURIHandler.mm59
-rw-r--r--SwifTools/URIHandler/MacOSXURIHandlerHelpers.h (renamed from Swiften/Elements/JingleTransport.h)5
-rw-r--r--SwifTools/URIHandler/MacOSXURIHandlerHelpers.mm16
-rw-r--r--SwifTools/URIHandler/NullURIHandler.h20
-rw-r--r--SwifTools/URIHandler/SConscript23
-rw-r--r--SwifTools/URIHandler/URIHandler.cpp15
-rw-r--r--SwifTools/URIHandler/URIHandler.h20
-rw-r--r--SwifTools/URIHandler/UnitTest/XMPPURITest.cpp191
-rw-r--r--SwifTools/URIHandler/XMPPURI.cpp144
-rw-r--r--SwifTools/URIHandler/XMPPURI.h72
-rw-r--r--SwifTools/UnitTest/LastLineTrackerTest.cpp64
-rw-r--r--SwifTools/UnitTest/SConscript3
-rw-r--r--Swift/Controllers/AdHocManager.cpp69
-rw-r--r--Swift/Controllers/AdHocManager.h40
-rw-r--r--Swift/Controllers/CertificateMemoryStorageFactory.h28
-rw-r--r--Swift/Controllers/Chat/ChatController.cpp42
-rw-r--r--Swift/Controllers/Chat/ChatController.h1
-rw-r--r--Swift/Controllers/Chat/ChatControllerBase.cpp20
-rw-r--r--Swift/Controllers/Chat/ChatControllerBase.h9
-rw-r--r--Swift/Controllers/Chat/ChatsManager.cpp67
-rw-r--r--Swift/Controllers/Chat/ChatsManager.h28
-rw-r--r--Swift/Controllers/Chat/MUCController.cpp55
-rw-r--r--Swift/Controllers/Chat/MUCController.h19
-rw-r--r--Swift/Controllers/Chat/MUCSearchController.cpp5
-rw-r--r--Swift/Controllers/Chat/MUCSearchController.h8
-rw-r--r--Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp14
-rw-r--r--Swift/Controllers/Chat/UnitTest/MockChatListWindow.h24
-rw-r--r--Swift/Controllers/Chat/UserSearchController.cpp2
-rw-r--r--Swift/Controllers/ChatMessageSummarizer.cpp45
-rw-r--r--Swift/Controllers/ChatMessageSummarizer.h20
-rw-r--r--Swift/Controllers/DiscoServiceWalker.cpp1
-rw-r--r--Swift/Controllers/MainController.cpp57
-rw-r--r--Swift/Controllers/MainController.h10
-rw-r--r--Swift/Controllers/ProfileSettingsProvider.h1
-rw-r--r--Swift/Controllers/Roster/ContactRosterItem.cpp2
-rw-r--r--Swift/Controllers/Roster/GroupRosterItem.cpp19
-rw-r--r--Swift/Controllers/Roster/GroupRosterItem.h4
-rw-r--r--Swift/Controllers/Roster/RosterGroupExpandinessPersister.cpp1
-rw-r--r--Swift/Controllers/Roster/RosterItem.cpp4
-rw-r--r--Swift/Controllers/Roster/RosterItem.h4
-rw-r--r--Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp1
-rw-r--r--Swift/Controllers/Roster/UnitTest/RosterTest.cpp17
-rw-r--r--Swift/Controllers/SConscript16
-rw-r--r--Swift/Controllers/Storages/AvatarFileStorage.cpp (renamed from Swiften/Avatars/AvatarFileStorage.cpp)5
-rw-r--r--Swift/Controllers/Storages/AvatarFileStorage.h (renamed from Swiften/Avatars/AvatarFileStorage.h)2
-rw-r--r--Swift/Controllers/Storages/CapsFileStorage.cpp34
-rw-r--r--Swift/Controllers/Storages/CapsFileStorage.h (renamed from Swiften/Disco/CapsFileStorage.h)2
-rw-r--r--Swift/Controllers/Storages/CertificateFileStorage.cpp (renamed from Swift/Controllers/CertificateFileStorage.cpp)2
-rw-r--r--Swift/Controllers/Storages/CertificateFileStorage.h (renamed from Swift/Controllers/CertificateFileStorage.h)2
-rw-r--r--Swift/Controllers/Storages/CertificateFileStorageFactory.h (renamed from Swift/Controllers/CertificateFileStorageFactory.h)4
-rw-r--r--Swift/Controllers/Storages/CertificateMemoryStorage.cpp27
-rw-r--r--Swift/Controllers/Storages/CertificateMemoryStorage.h25
-rw-r--r--Swift/Controllers/Storages/CertificateStorage.cpp (renamed from Swift/Controllers/CertificateStorage.cpp)2
-rw-r--r--Swift/Controllers/Storages/CertificateStorage.h (renamed from Swift/Controllers/CertificateStorage.h)0
-rw-r--r--Swift/Controllers/Storages/CertificateStorageFactory.cpp (renamed from Swift/Controllers/CertificateStorageFactory.cpp)2
-rw-r--r--Swift/Controllers/Storages/CertificateStorageFactory.h (renamed from Swift/Controllers/CertificateStorageFactory.h)0
-rw-r--r--Swift/Controllers/Storages/CertificateStorageTrustChecker.h (renamed from Swift/Controllers/CertificateStorageTrustChecker.h)2
-rw-r--r--Swift/Controllers/Storages/FileStorages.cpp (renamed from Swiften/Client/FileStorages.cpp)15
-rw-r--r--Swift/Controllers/Storages/FileStorages.h (renamed from Swiften/Client/FileStorages.h)5
-rw-r--r--Swift/Controllers/Storages/FileStoragesFactory.h (renamed from Swift/Controllers/FileStoragesFactory.h)4
-rw-r--r--Swift/Controllers/Storages/MemoryStoragesFactory.h (renamed from Swift/Controllers/MemoryStoragesFactory.h)4
-rw-r--r--Swift/Controllers/Storages/RosterFileStorage.cpp26
-rw-r--r--Swift/Controllers/Storages/RosterFileStorage.h24
-rw-r--r--Swift/Controllers/Storages/StoragesFactory.h (renamed from Swift/Controllers/StoragesFactory.h)1
-rw-r--r--Swift/Controllers/Storages/VCardFileStorage.cpp (renamed from Swiften/VCards/VCardFileStorage.cpp)40
-rw-r--r--Swift/Controllers/Storages/VCardFileStorage.h (renamed from Swiften/VCards/VCardFileStorage.h)2
-rw-r--r--Swift/Controllers/UIEvents/RequestAdHocUIEvent.h21
-rw-r--r--Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h13
-rw-r--r--Swift/Controllers/UIInterfaces/AdHocCommandWindow.h14
-rw-r--r--Swift/Controllers/UIInterfaces/AdHocCommandWindowFactory.h22
-rw-r--r--Swift/Controllers/UIInterfaces/ChatListWindow.h20
-rw-r--r--Swift/Controllers/UIInterfaces/ChatWindow.h5
-rw-r--r--Swift/Controllers/UIInterfaces/MainWindow.h2
-rw-r--r--Swift/Controllers/UIInterfaces/UIFactory.h4
-rw-r--r--Swift/Controllers/UnitTest/ChatMessageSummarizerTest.cpp122
-rw-r--r--Swift/Controllers/UnitTest/MockChatWindow.h3
-rw-r--r--Swift/Controllers/UnitTest/MockMainWindow.h1
-rw-r--r--Swift/Controllers/XMPPEvents/EventController.cpp1
-rw-r--r--Swift/Controllers/XMPPURIController.cpp38
-rw-r--r--Swift/Controllers/XMPPURIController.h32
-rw-r--r--Swift/QtUI/.gitignore1
-rw-r--r--Swift/QtUI/ChatList/ChatListDelegate.cpp55
-rw-r--r--Swift/QtUI/ChatList/ChatListDelegate.h5
-rw-r--r--Swift/QtUI/ChatList/ChatListGroupItem.h7
-rw-r--r--Swift/QtUI/ChatList/ChatListMUCItem.h12
-rw-r--r--Swift/QtUI/ChatList/ChatListModel.cpp22
-rw-r--r--Swift/QtUI/ChatList/ChatListModel.h11
-rw-r--r--Swift/QtUI/ChatList/ChatListRecentItem.cpp34
-rw-r--r--Swift/QtUI/ChatList/ChatListRecentItem.h33
-rw-r--r--Swift/QtUI/ChatList/QtChatListWindow.cpp31
-rw-r--r--Swift/QtUI/ChatList/QtChatListWindow.h5
-rw-r--r--Swift/QtUI/ChatSnippet.h7
-rw-r--r--Swift/QtUI/QtAdHocCommandWindow.cpp137
-rw-r--r--Swift/QtUI/QtAdHocCommandWindow.h48
-rw-r--r--Swift/QtUI/QtChatTabs.cpp14
-rw-r--r--Swift/QtUI/QtChatView.cpp32
-rw-r--r--Swift/QtUI/QtChatView.h5
-rw-r--r--Swift/QtUI/QtChatWindow.cpp75
-rw-r--r--Swift/QtUI/QtChatWindow.h17
-rw-r--r--Swift/QtUI/QtDBUSURIHandler.cpp41
-rw-r--r--Swift/QtUI/QtDBUSURIHandler.h17
-rw-r--r--Swift/QtUI/QtFormWidget.cpp242
-rw-r--r--Swift/QtUI/QtFormWidget.h31
-rw-r--r--Swift/QtUI/QtLoginWindow.cpp19
-rw-r--r--Swift/QtUI/QtLoginWindow.h8
-rw-r--r--Swift/QtUI/QtMainWindow.cpp72
-rw-r--r--Swift/QtUI/QtMainWindow.h12
-rw-r--r--Swift/QtUI/QtSwift.cpp32
-rw-r--r--Swift/QtUI/QtSwift.h2
-rw-r--r--Swift/QtUI/QtTextEdit.cpp16
-rw-r--r--Swift/QtUI/QtUIFactory.cpp4
-rw-r--r--Swift/QtUI/QtUIFactory.h1
-rw-r--r--Swift/QtUI/QtURIHandler.cpp36
-rw-r--r--Swift/QtUI/QtURIHandler.h22
-rw-r--r--Swift/QtUI/SConscript23
-rw-r--r--Swift/QtUI/swift-open-uri.cpp30
-rw-r--r--Swift/Translations/swift_nl.ts63
-rw-r--r--Swiften/AdHoc/OutgoingAdHocCommandSession.cpp102
-rw-r--r--Swiften/AdHoc/OutgoingAdHocCommandSession.h88
-rw-r--r--Swiften/AdHoc/SConscript6
-rw-r--r--Swiften/Avatars/AvatarManager.h2
-rw-r--r--Swiften/Avatars/AvatarProvider.h3
-rw-r--r--Swiften/Avatars/AvatarStorage.h2
-rw-r--r--Swiften/Avatars/SConscript1
-rw-r--r--Swiften/Avatars/VCardAvatarManager.h3
-rw-r--r--Swiften/Base/ByteArray.cpp45
-rw-r--r--Swiften/Base/ByteArray.h34
-rw-r--r--Swiften/Base/IDGenerator.h5
-rw-r--r--Swiften/Base/Paths.cpp6
-rw-r--r--Swiften/Base/Paths.h2
-rw-r--r--Swiften/Base/Platform.h9
-rw-r--r--Swiften/Base/String.h1
-rw-r--r--Swiften/Base/UnitTest/ByteArrayTest.cpp29
-rw-r--r--Swiften/Base/foreach.h5
-rw-r--r--Swiften/Base/format.h1
-rw-r--r--Swiften/Base/sleep.h5
-rw-r--r--Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp1
-rw-r--r--Swiften/Client/Client.cpp8
-rw-r--r--Swiften/Client/Client.h8
-rw-r--r--Swiften/Client/ClientOptions.h39
-rw-r--r--Swiften/Client/ClientSession.cpp2
-rw-r--r--Swiften/Client/ClientSession.h5
-rw-r--r--Swiften/Client/ClientSessionStanzaChannel.cpp1
-rw-r--r--Swiften/Client/ClientXMLTracer.cpp31
-rw-r--r--Swiften/Client/ClientXMLTracer.h20
-rw-r--r--Swiften/Client/CoreClient.cpp58
-rw-r--r--Swiften/Client/CoreClient.h93
-rw-r--r--Swiften/Client/DummyStanzaChannel.h16
-rw-r--r--Swiften/Client/MemoryStorages.cpp8
-rw-r--r--Swiften/Client/MemoryStorages.h2
-rw-r--r--Swiften/Client/NickResolver.h2
-rw-r--r--Swiften/Client/Storages.cpp12
-rw-r--r--Swiften/Client/Storages.h4
-rw-r--r--Swiften/Component/ComponentSessionStanzaChannel.cpp1
-rw-r--r--Swiften/Component/ComponentXMLTracer.cpp31
-rw-r--r--Swiften/Component/ComponentXMLTracer.h20
-rw-r--r--Swiften/Component/CoreComponent.cpp1
-rw-r--r--Swiften/Component/SConscript1
-rw-r--r--Swiften/Compress/ZLibCompressor.cpp2
-rw-r--r--Swiften/Compress/ZLibCompressor.h2
-rw-r--r--Swiften/Compress/ZLibDecompressor.cpp2
-rw-r--r--Swiften/Compress/ZLibDecompressor.h2
-rw-r--r--Swiften/Config/swiften-config.cpp1
-rw-r--r--Swiften/Disco/CapsFileStorage.cpp61
-rw-r--r--Swiften/Disco/CapsManager.cpp1
-rw-r--r--Swiften/Disco/DummyEntityCapsProvider.cpp21
-rw-r--r--Swiften/Disco/DummyEntityCapsProvider.h10
-rw-r--r--Swiften/Disco/GetDiscoItemsRequest.h9
-rw-r--r--Swiften/Disco/SConscript2
-rw-r--r--Swiften/Elements/Body.h5
-rw-r--r--Swiften/Elements/Bytestreams.h2
-rw-r--r--Swiften/Elements/CapsInfo.h2
-rw-r--r--Swiften/Elements/ChatState.h1
-rw-r--r--Swiften/Elements/Command.h2
-rw-r--r--Swiften/Elements/ComponentHandshake.h2
-rw-r--r--Swiften/Elements/Delay.h2
-rw-r--r--Swiften/Elements/DiscoInfo.cpp7
-rw-r--r--Swiften/Elements/DiscoInfo.h9
-rw-r--r--Swiften/Elements/DiscoItems.h3
-rw-r--r--Swiften/Elements/Element.h5
-rw-r--r--Swiften/Elements/ErrorPayload.h2
-rw-r--r--Swiften/Elements/Form.h3
-rw-r--r--Swiften/Elements/FormField.h3
-rw-r--r--Swiften/Elements/IBB.h14
-rw-r--r--Swiften/Elements/InBandRegistrationPayload.h2
-rw-r--r--Swiften/Elements/JingleContentPayload.h (renamed from Swiften/Elements/JingleContent.h)31
-rw-r--r--Swiften/Elements/JingleIBBTransportPayload.h (renamed from Swiften/Elements/JingleIBBTransport.h)8
-rw-r--r--Swiften/Elements/JinglePayload.h8
-rw-r--r--Swiften/Elements/JingleS5BTransportPayload.h (renamed from Swiften/Elements/JingleS5BTransport.h)6
-rw-r--r--Swiften/Elements/JingleTransportPayload.h18
-rw-r--r--Swiften/Elements/MUCPayload.h2
-rw-r--r--Swiften/Elements/Message.h1
-rw-r--r--Swiften/Elements/Payload.h4
-rw-r--r--Swiften/Elements/Presence.cpp46
-rw-r--r--Swiften/Elements/Presence.h37
-rw-r--r--Swiften/Elements/Priority.h4
-rw-r--r--Swiften/Elements/Replace.h27
-rw-r--r--Swiften/Elements/RosterItemExchangePayload.cpp18
-rw-r--r--Swiften/Elements/RosterItemExchangePayload.h83
-rw-r--r--Swiften/Elements/RosterItemPayload.h14
-rw-r--r--Swiften/Elements/RosterPayload.h9
-rw-r--r--Swiften/Elements/SecurityLabelsCatalog.h8
-rw-r--r--Swiften/Elements/SoftwareVersion.h4
-rw-r--r--Swiften/Elements/Stanza.cpp5
-rw-r--r--Swiften/Elements/Stanza.h27
-rw-r--r--Swiften/Elements/Status.h5
-rw-r--r--Swiften/Elements/StatusShow.cpp12
-rw-r--r--Swiften/Elements/StatusShow.h25
-rw-r--r--Swiften/Elements/StreamFeatures.cpp21
-rw-r--r--Swiften/Elements/StreamFeatures.h23
-rw-r--r--Swiften/Elements/StreamManagementEnabled.cpp15
-rw-r--r--Swiften/Elements/StreamManagementEnabled.h28
-rw-r--r--Swiften/Elements/StreamResume.cpp15
-rw-r--r--Swiften/Elements/StreamResume.h40
-rw-r--r--Swiften/Elements/StreamResumed.cpp15
-rw-r--r--Swiften/Elements/StreamResumed.h40
-rw-r--r--Swiften/Elements/UnitTest/StanzaTest.cpp1
-rw-r--r--Swiften/Entity/Entity.cpp27
-rw-r--r--Swiften/Entity/Entity.h24
-rw-r--r--Swiften/Entity/GenericPayloadPersister.h36
-rw-r--r--Swiften/Entity/PayloadPersister.cpp53
-rw-r--r--Swiften/Entity/PayloadPersister.h30
-rw-r--r--Swiften/EventLoop/DummyEventLoop.cpp24
-rw-r--r--Swiften/EventLoop/DummyEventLoop.h14
-rw-r--r--Swiften/EventLoop/EventLoop.cpp2
-rw-r--r--Swiften/EventLoop/SConscript1
-rw-r--r--Swiften/Examples/BenchTool/BenchTool.cpp1
-rw-r--r--Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp1
-rw-r--r--Swiften/Examples/SendFile/ReceiveFile.cpp3
-rw-r--r--Swiften/Examples/SendFile/SendFile.cpp8
-rw-r--r--Swiften/Examples/SendMessage/SendMessage.cpp2
-rw-r--r--Swiften/FileTransfer/ByteArrayReadBytestream.h19
-rw-r--r--Swiften/FileTransfer/ByteArrayWriteBytestream.h28
-rw-r--r--Swiften/FileTransfer/FileReadBytestream.cpp6
-rw-r--r--Swiften/FileTransfer/FileReadBytestream.h4
-rw-r--r--Swiften/FileTransfer/FileWriteBytestream.cpp4
-rw-r--r--Swiften/FileTransfer/FileWriteBytestream.h6
-rw-r--r--Swiften/FileTransfer/IBBReceiveSession.cpp111
-rw-r--r--Swiften/FileTransfer/IBBReceiveSession.h20
-rw-r--r--Swiften/FileTransfer/IBBSendSession.cpp4
-rw-r--r--Swiften/FileTransfer/IncomingFileTransfer.cpp11
-rw-r--r--Swiften/FileTransfer/IncomingFileTransferManager.cpp16
-rw-r--r--Swiften/FileTransfer/IncomingFileTransferManager.h4
-rw-r--r--Swiften/FileTransfer/IncomingJingleFileTransfer.cpp152
-rw-r--r--Swiften/FileTransfer/IncomingJingleFileTransfer.h57
-rw-r--r--Swiften/FileTransfer/JingleIncomingIBBTransport.cpp23
-rw-r--r--Swiften/FileTransfer/JingleIncomingIBBTransport.h27
-rw-r--r--Swiften/FileTransfer/JingleTransport.cpp15
-rw-r--r--Swiften/FileTransfer/JingleTransport.h25
-rw-r--r--Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp14
-rw-r--r--Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h27
-rw-r--r--Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.cpp14
-rw-r--r--Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h18
-rw-r--r--Swiften/FileTransfer/OutgoingFileTransfer.cpp68
-rw-r--r--Swiften/FileTransfer/OutgoingFileTransfer.h41
-rw-r--r--Swiften/FileTransfer/OutgoingSIFileTransfer.cpp78
-rw-r--r--Swiften/FileTransfer/OutgoingSIFileTransfer.h53
-rw-r--r--Swiften/FileTransfer/ReadBytestream.h5
-rw-r--r--Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp14
-rw-r--r--Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h29
-rw-r--r--Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.cpp14
-rw-r--r--Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h18
-rw-r--r--Swiften/FileTransfer/SConscript17
-rw-r--r--Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp3
-rw-r--r--Swiften/FileTransfer/UnitTest/IBBReceiveSessionTest.cpp188
-rw-r--r--Swiften/FileTransfer/UnitTest/IBBSendSessionTest.cpp9
-rw-r--r--Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp36
-rw-r--r--Swiften/FileTransfer/WriteBytestream.h5
-rw-r--r--Swiften/JID/JID.cpp82
-rw-r--r--Swiften/JID/JID.h14
-rw-r--r--Swiften/JID/UnitTest/JIDTest.cpp55
-rw-r--r--Swiften/Jingle/IncomingJingleSession.cpp15
-rw-r--r--Swiften/Jingle/IncomingJingleSession.h20
-rw-r--r--Swiften/Jingle/IncomingJingleSessionHandler.h4
-rw-r--r--Swiften/Jingle/Jingle.h25
-rw-r--r--Swiften/Jingle/JingleContentID.h23
-rw-r--r--Swiften/Jingle/JingleResponder.cpp8
-rw-r--r--Swiften/Jingle/JingleSession.cpp12
-rw-r--r--Swiften/Jingle/JingleSession.h42
-rw-r--r--Swiften/Jingle/JingleSessionImpl.cpp42
-rw-r--r--Swiften/Jingle/JingleSessionImpl.h30
-rw-r--r--Swiften/Jingle/JingleSessionManager.cpp9
-rw-r--r--Swiften/Jingle/JingleSessionManager.h8
-rw-r--r--Swiften/Jingle/SConscript4
-rw-r--r--Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.cpp60
-rw-r--r--Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h47
-rw-r--r--Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.cpp101
-rw-r--r--Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h86
-rw-r--r--Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.cpp22
-rw-r--r--Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h8
-rw-r--r--Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.cpp65
-rw-r--r--Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h52
-rw-r--r--Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h2
-rw-r--r--Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp2
-rw-r--r--Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h14
-rw-r--r--Swiften/LinkLocal/OutgoingLinkLocalSession.cpp1
-rw-r--r--Swiften/LinkLocal/SConscript6
-rw-r--r--Swiften/LinkLocal/UnitTest/LinkLocalConnectorTest.cpp2
-rw-r--r--Swiften/MUC/MUC.cpp1
-rw-r--r--Swiften/MUC/MUCBookmarkManager.cpp1
-rw-r--r--Swiften/Network/BoostConnection.cpp2
-rw-r--r--Swiften/Network/BoostConnection.h3
-rw-r--r--Swiften/Network/BoostConnectionFactory.h2
-rw-r--r--Swiften/Network/BoostConnectionServer.cpp1
-rw-r--r--Swiften/Network/BoostConnectionServer.h3
-rw-r--r--Swiften/Network/BoostIOServiceThread.h4
-rw-r--r--Swiften/Network/BoostTimer.cpp1
-rw-r--r--Swiften/Network/BoostTimer.h4
-rw-r--r--Swiften/Network/BoostTimerFactory.h2
-rw-r--r--Swiften/Network/CAresDomainNameResolver.h2
-rw-r--r--Swiften/Network/ChainedConnector.cpp82
-rw-r--r--Swiften/Network/ChainedConnector.h47
-rw-r--r--Swiften/Network/Connection.cpp15
-rw-r--r--Swiften/Network/Connection.h12
-rw-r--r--Swiften/Network/DummyConnection.cpp30
-rw-r--r--Swiften/Network/DummyConnection.h18
-rw-r--r--Swiften/Network/EnvironmentProxyProvider.cpp48
-rw-r--r--Swiften/Network/EnvironmentProxyProvider.h24
-rw-r--r--Swiften/Network/FakeConnection.cpp64
-rw-r--r--Swiften/Network/FakeConnection.h52
-rw-r--r--Swiften/Network/GConfProxyProvider.cpp51
-rw-r--r--Swiften/Network/GConfProxyProvider.h24
-rw-r--r--Swiften/Network/HTTPConnectProxiedConnection.cpp100
-rw-r--r--Swiften/Network/HTTPConnectProxiedConnection.h54
-rw-r--r--Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp20
-rw-r--r--Swiften/Network/HTTPConnectProxiedConnectionFactory.h23
-rw-r--r--Swiften/Network/HostAddress.cpp6
-rw-r--r--Swiften/Network/HostAddress.h7
-rw-r--r--Swiften/Network/HostAddressPort.cpp23
-rw-r--r--Swiften/Network/HostAddressPort.h14
-rw-r--r--Swiften/Network/MacOSXProxyProvider.cpp97
-rw-r--r--Swiften/Network/MacOSXProxyProvider.h18
-rw-r--r--Swiften/Network/NullProxyProvider.cpp20
-rw-r--r--Swiften/Network/NullProxyProvider.h19
-rw-r--r--Swiften/Network/PlatformDomainNameAddressQuery.cpp2
-rw-r--r--Swiften/Network/PlatformDomainNameAddressQuery.h2
-rw-r--r--Swiften/Network/PlatformDomainNameResolver.h2
-rw-r--r--Swiften/Network/PlatformProxyProvider.h26
-rw-r--r--Swiften/Network/ProxyProvider.cpp19
-rw-r--r--Swiften/Network/ProxyProvider.h23
-rw-r--r--Swiften/Network/SConscript27
-rw-r--r--Swiften/Network/SOCKS5ProxiedConnection.cpp174
-rw-r--r--Swiften/Network/SOCKS5ProxiedConnection.h59
-rw-r--r--Swiften/Network/SOCKS5ProxiedConnectionFactory.cpp20
-rw-r--r--Swiften/Network/SOCKS5ProxiedConnectionFactory.h23
-rw-r--r--Swiften/Network/UnitTest/ChainedConnectorTest.cpp161
-rw-r--r--Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp244
-rw-r--r--Swiften/Network/UnixProxyProvider.cpp55
-rw-r--r--Swiften/Network/UnixProxyProvider.h25
-rw-r--r--Swiften/Network/WindowsProxyProvider.cpp113
-rw-r--r--Swiften/Network/WindowsProxyProvider.h22
-rw-r--r--Swiften/Parser/Attribute.h33
-rw-r--r--Swiften/Parser/AttributeMap.cpp62
-rw-r--r--Swiften/Parser/AttributeMap.h62
-rw-r--r--Swiften/Parser/ExpatParser.cpp2
-rw-r--r--Swiften/Parser/IQParser.cpp17
-rw-r--r--Swiften/Parser/IQParser.h5
-rw-r--r--Swiften/Parser/LibXMLParser.cpp12
-rw-r--r--Swiften/Parser/MessageParser.cpp16
-rw-r--r--Swiften/Parser/PayloadParser.h2
-rw-r--r--Swiften/Parser/PayloadParsers/BytestreamsParser.cpp2
-rw-r--r--Swiften/Parser/PayloadParsers/DelayParser.cpp1
-rw-r--r--Swiften/Parser/PayloadParsers/DelayParserFactory.cpp1
-rw-r--r--Swiften/Parser/PayloadParsers/DiscoInfoParser.cpp2
-rw-r--r--Swiften/Parser/PayloadParsers/FormParser.cpp5
-rw-r--r--Swiften/Parser/PayloadParsers/FormParser.h1
-rw-r--r--Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp4
-rw-r--r--Swiften/Parser/PayloadParsers/IBBParser.cpp6
-rw-r--r--Swiften/Parser/PayloadParsers/PriorityParser.cpp2
-rw-r--r--Swiften/Parser/PayloadParsers/ReplaceParser.cpp29
-rw-r--r--Swiften/Parser/PayloadParsers/ReplaceParser.h23
-rw-r--r--Swiften/Parser/PayloadParsers/RosterItemExchangeParser.cpp68
-rw-r--r--Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h34
-rw-r--r--Swiften/Parser/PayloadParsers/RosterParser.cpp11
-rw-r--r--Swiften/Parser/PayloadParsers/StreamInitiationParser.cpp2
-rw-r--r--Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp4
-rw-r--r--Swiften/Parser/PayloadParsers/UnitTest/IBBParserTest.cpp2
-rw-r--r--Swiften/Parser/PayloadParsers/UnitTest/PriorityParserTest.cpp4
-rw-r--r--Swiften/Parser/PayloadParsers/UnitTest/ReplaceTest.cpp36
-rw-r--r--Swiften/Parser/PayloadParsers/UnitTest/RosterItemExchangeParserTest.cpp52
-rw-r--r--Swiften/Parser/PayloadParsers/UnitTest/RosterParserTest.cpp22
-rw-r--r--Swiften/Parser/PresenceParser.cpp21
-rw-r--r--Swiften/Parser/SConscript5
-rw-r--r--Swiften/Parser/SerializingParser.cpp6
-rw-r--r--Swiften/Parser/StanzaParser.cpp19
-rw-r--r--Swiften/Parser/StreamFeaturesParser.cpp3
-rw-r--r--Swiften/Parser/StreamManagementEnabledParser.cpp29
-rw-r--r--Swiften/Parser/StreamManagementEnabledParser.h18
-rw-r--r--Swiften/Parser/StreamResumeParser.cpp36
-rw-r--r--Swiften/Parser/StreamResumeParser.h27
-rw-r--r--Swiften/Parser/UnitTest/AttributeMapTest.cpp20
-rw-r--r--Swiften/Parser/UnitTest/StanzaParserTest.cpp10
-rw-r--r--Swiften/Parser/UnitTest/StreamFeaturesParserTest.cpp2
-rw-r--r--Swiften/Parser/UnitTest/StreamManagementEnabledParserTest.cpp34
-rw-r--r--Swiften/Parser/UnitTest/XMLParserTest.cpp32
-rw-r--r--Swiften/Parser/XMPPParser.cpp7
-rw-r--r--Swiften/Presence/PayloadAddingPresenceSender.cpp2
-rw-r--r--Swiften/Presence/PayloadAddingPresenceSender.h8
-rw-r--r--Swiften/QA/ClientTest/ClientTest.cpp1
-rw-r--r--Swiften/QA/ProxyProviderTest/.gitignore1
-rw-r--r--Swiften/QA/ProxyProviderTest/ProxyProviderTest.cpp35
-rw-r--r--Swiften/QA/ProxyProviderTest/SConscript11
-rw-r--r--Swiften/QA/SConscript3
-rw-r--r--Swiften/QA/StorageTest/FileReadBytestreamTest.cpp7
-rw-r--r--Swiften/Queries/RawRequest.h2
-rw-r--r--Swiften/Queries/Request.h11
-rw-r--r--Swiften/Queries/Requests/SubmitInBandRegistrationFormRequest.h4
-rw-r--r--Swiften/Roster/GetRosterRequest.h6
-rw-r--r--Swiften/Roster/RosterMemoryStorage.cpp23
-rw-r--r--Swiften/Roster/RosterMemoryStorage.h25
-rw-r--r--Swiften/Roster/RosterStorage.cpp14
-rw-r--r--Swiften/Roster/RosterStorage.h21
-rw-r--r--Swiften/Roster/SetRosterRequest.h8
-rw-r--r--Swiften/Roster/UnitTest/XMPPRosterControllerTest.cpp173
-rw-r--r--Swiften/Roster/UnitTest/XMPPRosterSignalHandler.cpp28
-rw-r--r--Swiften/Roster/UnitTest/XMPPRosterSignalHandler.h39
-rw-r--r--Swiften/Roster/XMPPRosterController.cpp48
-rw-r--r--Swiften/Roster/XMPPRosterController.h12
-rw-r--r--Swiften/SASL/SConscript1
-rw-r--r--Swiften/SConscript33
-rw-r--r--Swiften/Serializer/IQSerializer.h2
-rw-r--r--Swiften/Serializer/PayloadSerializer.h11
-rw-r--r--Swiften/Serializer/PayloadSerializers/CommandSerializer.cpp2
-rw-r--r--Swiften/Serializer/PayloadSerializers/DelaySerializer.cpp1
-rw-r--r--Swiften/Serializer/PayloadSerializers/FormSerializer.cpp8
-rw-r--r--Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp4
-rw-r--r--Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.cpp3
-rw-r--r--Swiften/Serializer/PayloadSerializers/ReplaceSerializer.h22
-rw-r--r--Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.cpp46
-rw-r--r--Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h19
-rw-r--r--Swiften/Serializer/PayloadSerializers/RosterSerializer.cpp3
-rw-r--r--Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.cpp2
-rw-r--r--Swiften/Serializer/PayloadSerializers/UnitTest/FormSerializerTest.cpp11
-rw-r--r--Swiften/Serializer/PayloadSerializers/UnitTest/ReplaceSerializerTest.cpp30
-rw-r--r--Swiften/Serializer/PayloadSerializers/UnitTest/RosterItemExchangeSerializerTest.cpp54
-rw-r--r--Swiften/Serializer/PayloadSerializers/UnitTest/RosterSerializerTest.cpp27
-rw-r--r--Swiften/Serializer/PresenceSerializer.h2
-rw-r--r--Swiften/Serializer/StanzaSerializer.cpp1
-rw-r--r--Swiften/Serializer/StreamFeaturesSerializer.cpp5
-rw-r--r--Swiften/Serializer/StreamManagementEnabledSerializer.cpp29
-rw-r--r--Swiften/Serializer/StreamManagementEnabledSerializer.h8
-rw-r--r--Swiften/Serializer/StreamResumeSerializer.cpp28
-rw-r--r--Swiften/Serializer/StreamResumeSerializer.h21
-rw-r--r--Swiften/Serializer/StreamResumedSerializer.cpp28
-rw-r--r--Swiften/Serializer/StreamResumedSerializer.h21
-rw-r--r--Swiften/Serializer/UnitTest/StreamFeaturesSerializerTest.cpp2
-rw-r--r--Swiften/Serializer/XMPPSerializer.cpp52
-rw-r--r--Swiften/Session/SessionTracer.cpp28
-rw-r--r--Swiften/Session/SessionTracer.h17
-rw-r--r--Swiften/StreamManagement/StanzaAckRequester.cpp1
-rw-r--r--Swiften/StreamStack/CompressionLayer.h4
-rw-r--r--Swiften/StreamStack/ConnectionLayer.cpp21
-rw-r--r--Swiften/StreamStack/ConnectionLayer.h11
-rw-r--r--Swiften/StreamStack/SConscript1
-rw-r--r--Swiften/StreamStack/StreamStack.h5
-rw-r--r--Swiften/StringCodecs/SHA1.cpp69
-rw-r--r--Swiften/StringCodecs/SHA1.h27
-rw-r--r--Swiften/StringCodecs/UnitTest/SHA1Test.cpp53
-rw-r--r--Swiften/VCards/SConscript1
-rw-r--r--Swiftob/Commands.cpp1
-rw-r--r--Swiftob/LuaCommands.cpp2
-rw-r--r--Swiftob/LuaCommands.h3
-rw-r--r--Swiftob/MUCs.cpp4
-rw-r--r--Swiftob/SConscript2
-rw-r--r--Swiftob/Users.cpp1
-rw-r--r--Swiftob/linit.cpp (renamed from Swiftob/linit.c)0
499 files changed, 9602 insertions, 1616 deletions
diff --git a/.gitignore b/.gitignore
index 7c78bc1..b5a8577 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,6 +21,7 @@
*.ilk
*.res
*.moc
+*.patch
*~
_CL_*
*.manifest
diff --git a/3rdParty/Boost/SConscript b/3rdParty/Boost/SConscript
index 562b1b0..fc53b45 100644
--- a/3rdParty/Boost/SConscript
+++ b/3rdParty/Boost/SConscript
@@ -90,7 +90,6 @@ elif env.get("BOOST_BUNDLED", False) :
"src/libs/program_options/src/config_file.cpp",
"src/libs/program_options/src/convert.cpp",
"src/libs/program_options/src/options_description.cpp",
- "src/libs/program_options/src/parsers.cpp",
"src/libs/program_options/src/positional_options.cpp",
"src/libs/program_options/src/split.cpp",
"src/libs/program_options/src/program_options_utf8_codecvt_facet.cpp",
@@ -98,6 +97,11 @@ elif env.get("BOOST_BUNDLED", False) :
"src/libs/program_options/src/variables_map.cpp",
"src/libs/program_options/src/winmain.cpp"]
+ if env["PLATFORM"] != "darwin" or env["target"] == "native" :
+ sources += [
+ "src/libs/program_options/src/parsers.cpp",
+ ]
+
if env["PLATFORM"] != "win32" :
sources += [
"src/libs/thread/src/pthread/once.cpp",
diff --git a/3rdParty/Lua/SConscript b/3rdParty/Lua/SConscript
index 3baa2d8..68f4e36 100644
--- a/3rdParty/Lua/SConscript
+++ b/3rdParty/Lua/SConscript
@@ -30,6 +30,10 @@ if env.get("LUA_BUNDLED", False) :
if env["SCONS_STAGE"] == "build" :
myenv = env.Clone()
+ if env["PLATFORM"] == "win32" :
+ myenv.Append(CFLAGS = ["/TP"])
+ else :
+ myenv.Append(CFLAGS = ["-x", "c++"])
# Remove warn flags
myenv.Replace(CCFLAGS = [flag for flag in env["CCFLAGS"] if flag not in ["-W", "-Wall"]])
diff --git a/BuildTools/CLang/.gitignore b/BuildTools/CLang/.gitignore
new file mode 100644
index 0000000..df682c0
--- /dev/null
+++ b/BuildTools/CLang/.gitignore
@@ -0,0 +1,4 @@
+CLangDiagnosticsFlags
+CLangDiagnosticsFlagsTool.sh
+CLangDiagnosticsFlagsTool
+clang-diagnostics-overview.*
diff --git a/BuildTools/CLang/CLangDiagnosticsFlagsTool.cpp b/BuildTools/CLang/CLangDiagnosticsFlagsTool.cpp
new file mode 100644
index 0000000..82cc902
--- /dev/null
+++ b/BuildTools/CLang/CLangDiagnosticsFlagsTool.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <iostream>
+#include <set>
+#include <vector>
+#include <cassert>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/graph/graph_traits.hpp>
+#include <boost/graph/adjacency_list.hpp>
+#include <boost/graph/topological_sort.hpp>
+#include <boost/graph/topological_sort.hpp>
+#include <boost/graph/graphviz.hpp>
+
+// -----------------------------------------------------------------------------
+// Include diagnostics data from CLang
+// -----------------------------------------------------------------------------
+
+#define DIAG(name, a, b, c, d, e, f, g) name,
+
+namespace diag {
+ enum LexKinds {
+#include <clang/Basic/DiagnosticLexKinds.inc>
+#include <clang/Basic/DiagnosticParseKinds.inc>
+#include <clang/Basic/DiagnosticCommonKinds.inc>
+#include <clang/Basic/DiagnosticDriverKinds.inc>
+#include <clang/Basic/DiagnosticFrontendKinds.inc>
+#include <clang/Basic/DiagnosticSemaKinds.inc>
+ };
+}
+
+#define GET_DIAG_ARRAYS
+#include <clang/Basic/DiagnosticGroups.inc>
+#undef GET_DIAG_ARRAYS
+
+struct DiagTableEntry {
+ const char* name;
+ const short* array;
+ const short* group;
+};
+
+static const DiagTableEntry diagnostics[] = {
+#define GET_DIAG_TABLE
+#include <clang/Basic/DiagnosticGroups.inc>
+#undef GET_DIAG_TABLE
+};
+static const size_t diagnostics_count = sizeof(diagnostics) / sizeof(diagnostics[0]);
+
+// -----------------------------------------------------------------------------
+
+using namespace boost;
+
+struct Properties {
+ Properties() : missing(false), redundant(false) {
+ }
+
+ std::string name;
+ bool have;
+ bool implicitHave;
+ bool dontWant;
+ bool implicitDontWant;
+ bool ignored;
+ bool available;
+ bool missing;
+ bool redundant;
+ bool alreadyCovered;
+};
+
+class GraphVizLabelWriter {
+ public:
+ GraphVizLabelWriter(const std::vector<Properties>& properties) : properties(properties) {
+ }
+
+ template <class VertexOrEdge>
+ void operator()(std::ostream& out, const VertexOrEdge& v) const {
+ std::string color;
+ if (properties[v].missing) {
+ color = "orange";
+ }
+ else if (properties[v].redundant) {
+ color = "lightblue";
+ }
+ else if (properties[v].have) {
+ color = "darkgreen";
+ }
+ else if (properties[v].implicitHave) {
+ color = "green";
+ }
+ else if (properties[v].dontWant) {
+ color = "red";
+ }
+ else if (properties[v].implicitDontWant) {
+ color = "pink";
+ }
+ else if (properties[v].ignored) {
+ color = "white";
+ }
+ else if (properties[v].available) {
+ color = "yellow";
+ }
+ else {
+ assert(false);
+ }
+ out << "[label=" << escape_dot_string(properties[v].name) << " fillcolor=\"" << color << "\" style=filled]";
+ }
+
+ private:
+ const std::vector<Properties> properties;
+};
+
+int main(int argc, char* argv[]) {
+ // Parse command-line arguments
+ std::set<std::string> have;
+ std::set<std::string> dontWant;
+ std::string outputDir;
+ for (int i = 1; i < argc; ++i) {
+ std::string arg(argv[i]);
+ if (starts_with(arg, "-W")) {
+ have.insert(arg.substr(2, arg.npos));
+ }
+ else if (starts_with(arg, "-w")) {
+ dontWant.insert(arg.substr(2, arg.npos));
+ }
+ else if (starts_with(arg, "-O")) {
+ outputDir = arg.substr(2, arg.npos) + "/";
+ }
+ }
+
+ // Build the graph and initialize properties
+ typedef adjacency_list<vecS, vecS, bidirectionalS> Graph;
+ typedef graph_traits<Graph>::vertex_descriptor Vertex;
+ Graph g(diagnostics_count);
+ std::vector<Properties> properties(num_vertices(g));
+ for (size_t i = 0; i < diagnostics_count; ++i) {
+ std::string name(diagnostics[i].name);
+ properties[i].name = name;
+ properties[i].implicitHave = properties[i].have = have.find(name) != have.end();
+ properties[i].implicitDontWant = properties[i].dontWant = dontWant.find(name) != dontWant.end();
+ properties[i].ignored = diagnostics[i].group == 0 && diagnostics[i].array == 0;
+ properties[i].alreadyCovered = false;
+ properties[i].available = true;
+ for (const short* j = diagnostics[i].group; j && *j != -1; ++j) {
+ add_edge(i, *j, g);
+ }
+ }
+
+ // Sort the diagnostics
+ std::list<Vertex> sortedDiagnostics;
+ boost::topological_sort(g, std::front_inserter(sortedDiagnostics));
+
+ // Propagate dontWant and have properties down
+ for(std::list<Vertex>::const_iterator i = sortedDiagnostics.begin(); i != sortedDiagnostics.end(); ++i) {
+ graph_traits<Graph>::adjacency_iterator adjacentIt, adjacentEnd;
+ for (tie(adjacentIt, adjacentEnd) = adjacent_vertices(*i, g); adjacentIt != adjacentEnd; ++adjacentIt) {
+ properties[*adjacentIt].implicitDontWant = properties[*i].implicitDontWant || properties[*adjacentIt].implicitDontWant;
+ properties[*adjacentIt].implicitHave = properties[*i].implicitHave || properties[*adjacentIt].implicitHave;
+ }
+ }
+
+ // Propagate 'available' property upwards
+ for(std::list<Vertex>::const_reverse_iterator i = sortedDiagnostics.rbegin(); i != sortedDiagnostics.rend(); ++i) {
+ properties[*i].available = properties[*i].available && !properties[*i].implicitDontWant;
+ graph_traits<Graph>::in_edge_iterator edgesIt, edgesEnd;
+ graph_traits<Graph>::edge_descriptor edge;
+ for (tie(edgesIt, edgesEnd) = in_edges(*i, g); edgesIt != edgesEnd; ++edgesIt) {
+ properties[source(*edgesIt, g)].available = properties[source(*edgesIt, g)].available && properties[*i].available;
+ }
+ }
+
+ // Collect missing & redundant flags
+ std::set<std::string> missing;
+ std::set<std::string> redundant;
+ for(std::list<Vertex>::const_iterator i = sortedDiagnostics.begin(); i != sortedDiagnostics.end(); ++i) {
+ bool markChildrenCovered = true;
+ if (properties[*i].alreadyCovered) {
+ if (properties[*i].have) {
+ properties[*i].redundant = true;
+ redundant.insert(properties[*i].name);
+ }
+ }
+ else {
+ if (properties[*i].available) {
+ if (!properties[*i].implicitHave && !properties[*i].ignored) {
+ properties[*i].missing = true;
+ missing.insert(properties[*i].name);
+ }
+ }
+ else {
+ markChildrenCovered = false;
+ }
+ }
+ if (markChildrenCovered) {
+ graph_traits<Graph>::adjacency_iterator adjacentIt, adjacentEnd;
+ for (tie(adjacentIt, adjacentEnd) = adjacent_vertices(*i, g); adjacentIt != adjacentEnd; ++adjacentIt) {
+ properties[*adjacentIt].alreadyCovered = true;
+ }
+ }
+ }
+
+ // Write information
+ if (!missing.empty()) {
+ std::cout << "Missing diagnostic flags: ";
+ for(std::set<std::string>::const_iterator i = missing.begin(); i != missing.end(); ++i) {
+ std::cout << "-W" << *i << " ";
+ }
+ std::cout<< std::endl;
+ }
+
+ if (!redundant.empty()) {
+ std::cout << "Redundant diagnostic flags: ";
+ for(std::set<std::string>::const_iterator i = redundant.begin(); i != redundant.end(); ++i) {
+ std::cout << "-W" << *i << " ";
+ }
+ std::cout<< std::endl;
+ }
+
+ // Write graphviz file
+ if (!outputDir.empty()) {
+ std::ofstream f((outputDir + "clang-diagnostics-overview.dot").c_str());
+ write_graphviz(f, g, GraphVizLabelWriter(properties));
+ f.close();
+ }
+
+ return 0;
+}
diff --git a/BuildTools/CLang/SConscript b/BuildTools/CLang/SConscript
new file mode 100644
index 0000000..850c35c
--- /dev/null
+++ b/BuildTools/CLang/SConscript
@@ -0,0 +1,15 @@
+Import("env")
+
+#myenv = Environment()
+#myenv.Append(CPPPATH = ["."])
+#myenv.Program("CLangDiagnosticsFlagsTool", ["CLangDiagnosticsFlagsTool.cpp"])
+#
+#disabledDiagnostics = ["-wunreachable-code", "-wunused-macros", "-wmissing-noreturn", "-wlong-long", "-wcast-align", "-wglobal-constructors", "-wmissing-prototypes", "-wpadded", "-wshadow"]
+#clangDiagnosticsFlagsToolCommand = "BuildTools/CLang/CLangDiagnosticsFlagsTool -O" + env.Dir(".").abspath + " " + " ".join(disabledDiagnostics) + " "
+#clangDiagnosticsFlagsToolCommand += " ".join([flag for flag in env["CXXFLAGS"] if flag.startswith("-W")])
+#clangDiagnosticsFlagsToolCommand += "\n"
+#clangDiagnosticsFlagsToolCommand += "dot -Tpng " + env.Dir(".").abspath + "/clang-diagnostics-overview.dot > " + env.Dir(".").abspath + "/clang-diagnostics-overview.png\n"
+#v = env.WriteVal("#/BuildTools/CLang/CLangDiagnosticsFlagsTool.sh", env.Value(clangDiagnosticsFlagsToolCommand))
+#env.AddPostAction(v, Chmod(v[0], 0755))
+#
+#
diff --git a/BuildTools/CheckHeaders.py b/BuildTools/CheckHeaders.py
new file mode 100755
index 0000000..73f49db
--- /dev/null
+++ b/BuildTools/CheckHeaders.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+import os, sys
+
+foundBadHeaders = False
+
+for (path, dirs, files) in os.walk(".") :
+ if "3rdParty" in path or ".sconf" in path or ".framework" in path :
+ continue
+ if not "Swiften" in path :
+ continue
+
+ for filename in [os.path.join(path, file) for file in files if file.endswith(".h")] :
+ file = open(filename, "r")
+ for line in file.readlines() :
+ for include in ["iostream", "algorithm", "cassert", "boost/bind.hpp", "boost/filesystem.hpp", "Base/foreach.h", "Base/Log.h", "boost/date_time/date_time.hpp", "boost/filesystem/filesystem.hpp"] :
+ if "#include" in line and include in line and not "Base/Log" in filename :
+ print "Found " + include + " include in " + filename
+ foundBadHeaders = True
+
+sys.exit(foundBadHeaders)
diff --git a/BuildTools/Copyrighter.py b/BuildTools/Copyrighter.py
index a768f0d..8916316 100755
--- a/BuildTools/Copyrighter.py
+++ b/BuildTools/Copyrighter.py
@@ -136,7 +136,7 @@ elif sys.argv[1] == "check-all-copyrights" :
for (path, dirs, files) in os.walk(".") :
if "3rdParty" in path or ".sconf" in path or "Swift.app" in path :
continue
- for filename in [os.path.join(path, file) for file in files if (file.endswith(".cpp") or file.endswith(".h")) and not "ui_" in file and not "moc_" in file and not "qrc_" in file and not "BuildVersion.h" in file and not "Swiften.h" in file and not "Version.h" in file and not "swiften-config.h" in file] :
+ for filename in [os.path.join(path, file) for file in files if (file.endswith(".cpp") or file.endswith(".h")) and not "ui_" in file and not "moc_" in file and not "qrc_" in file and not "BuildVersion.h" in file and not "Swiften.h" in file and not "Version.h" in file and not "swiften-config.h" in file and not "linit.cpp" in file ] :
ok &= check_copyright(filename)
if not ok :
sys.exit(-1)
diff --git a/BuildTools/SCons/SConstruct b/BuildTools/SCons/SConstruct
index bc7781b..2d9d200 100644
--- a/BuildTools/SCons/SConstruct
+++ b/BuildTools/SCons/SConstruct
@@ -42,6 +42,9 @@ vars.Add("expat_libname", "Expat library name", "libexpat" if os.name == "nt" el
vars.Add(PathVariable("libidn_includedir", "LibIDN headers location", None, PathVariable.PathAccept))
vars.Add(PathVariable("libidn_libdir", "LibIDN library location", None, PathVariable.PathAccept))
vars.Add("libidn_libname", "LibIDN library name", "libidn" if os.name == "nt" else "idn")
+vars.Add(PathVariable("sqlite_includedir", "SQLite headers location", None, PathVariable.PathAccept))
+vars.Add(PathVariable("sqlite_libdir", "SQLite library location", None, PathVariable.PathAccept))
+vars.Add("sqlite_libname", "SQLite library name", "libsqlite3" if os.name == "nt" else "sqlite3")
vars.Add(PathVariable("avahi_includedir", "Avahi headers location", None, PathVariable.PathAccept))
vars.Add(PathVariable("avahi_libdir", "Avahi library location", None, PathVariable.PathAccept))
vars.Add(PathVariable("qt", "Qt location", "", PathVariable.PathAccept))
@@ -178,7 +181,14 @@ else :
env.Append(CXXFLAGS = ["-Werror"])
gccVersion = env["CCVERSION"].split(".")
if gccVersion >= ["4", "5", "0"] :
- env.Append(CCFLAGS = ["-Wlogical-op"])
+ env.Append(CXXFLAGS = ["-Wlogical-op"])
+ if "clang" in env["CC"] :
+ env.Append(CXXFLAGS = ["-W#warnings", "-W-Wc++0x-compat", "-Wc++0x-compat", "-Waddress-of-temporary", "-Wambiguous-member-template", "-Warray-bounds", "-Watomic-properties", "-Wbind-to-temporary-copy", "-Wbuiltin-macro-redefined", "-Wc++-compat", "-Wc++0x-extensions", "-Wcomments", "-Wconditional-uninitialized", "-Wconstant-logical-operand", "-Wdeclaration-after-statement", "-Wdeprecated", "-Wdeprecated-implementations", "-Wdeprecated-writable-strings", "-Wduplicate-method-arg", "-Wempty-body", "-Wendif-labels", "-Wenum-compare", "-Wformat=2", "-Wfour-char-constants", "-Wgnu", "-Wincomplete-implementation", "-Winvalid-noreturn", "-Winvalid-offsetof", "-Winvalid-token-paste", "-Wlocal-type-template-args", "-Wmethod-signatures", "-Wmicrosoft", "-Wmissing-declarations", "-Wnon-pod-varargs", "-Wnonfragile-abi2", "-Wnull-dereference", "-Wout-of-line-declaration", "-Woverlength-strings", "-Wpacked", "-Wpointer-arith", "-Wpointer-sign", "-Wprotocol", "-Wreadonly-setter-attrs", "-Wselector", "-Wshift-overflow", "-Wshift-sign-overflow", "-Wstrict-selector-match", "-Wsuper-class-method-mismatch", "-Wtautological-compare", "-Wtypedef-redefinition", "-Wundeclared-selector", "-Wunknown-attributes", "-Wunknown-warning-option", "-Wunnamed-type-template-args", "-Wunused-exception-parameter", "-Wunused-member-function", "-Wused-but-marked-unused", "-Wvariadic-macros"])
+# To enable:
+# "-Wheader-hygiene"
+# "-Wnon-gcc",
+# "-Wweak-vtables",
+# "-Wlarge-by-value-copy",
if env.get("coverage", 0) :
assert(env["PLATFORM"] != "win32")
@@ -186,7 +196,7 @@ if env.get("coverage", 0) :
env.Append(LINKFLAGS = ["-fprofile-arcs", "-ftest-coverage"])
if env["PLATFORM"] == "win32" :
- env.Append(LIBS = ["user32", "crypt32", "dnsapi", "ws2_32", "wsock32"])
+ env.Append(LIBS = ["user32", "crypt32", "dnsapi", "ws2_32", "wsock32", "Advapi32"])
env.Append(CCFLAGS = ["/EHsc", "/nologo"])
# FIXME: We should find a decent solution for MSVS 10
if int(env["MSVS_VERSION"].split(".")[0]) < 10 :
@@ -194,7 +204,7 @@ if env["PLATFORM"] == "win32" :
env["SHLINKCOM"] = [env["SHLINKCOM"], 'mt.exe -nologo -manifest ${TARGET}.manifest -outputresource:$TARGET;2']
if env["PLATFORM"] == "darwin" and not env["target"] in ["iphone-device", "iphone-simulator", "xcode"] :
- env.Append(FRAMEWORKS = ["IOKit", "AppKit"])
+ env.Append(FRAMEWORKS = ["IOKit", "AppKit", "SystemConfiguration"])
# Testing
env["TEST_TYPE"] = env["test"]
@@ -205,6 +215,7 @@ env["TEST"] = (env["TEST_TYPE"] != "none") or env.GetOption("clean")
if env.get("valgrind", 0) :
env["TEST_RUNNER"] = "valgrind --suppressions=QA/valgrind.supp -q --leak-check=full --track-origins=yes "
env["TEST_IGNORE_RESULT"] = "ignore_test_result" in ARGUMENTS
+env["TEST_CREATE_LIBRARIES"] = "create_test_libraries" in ARGUMENTS
# Packaging
env["DIST"] = "dist" in ARGUMENTS or env.GetOption("clean")
@@ -231,12 +242,12 @@ if target in ["iphone-device", "iphone-simulator", "xcode"] :
# Hard code values
env["XCODE_PLATFORM_DEVELOPER_BIN_DIR"] = "/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin"
if target == "iphone-device":
- env["XCODE_ARCH_FLAGS"] = ["-arch", "armv6"]
+ env["XCODE_ARCH_FLAGS"] = ["-arch", "armv6", "-arch", "armv7"]
sdkPart = "iPhoneOS"
else :
env["XCODE_ARCH_FLAGS"] = ["-arch", "i386"]
sdkPart = "iPhoneSimulator"
- sdkVer = "4.0"
+ sdkVer = "4.3"
env["XCODE_SDKROOT"] = "/Developer/Platforms/" + sdkPart + ".platform/Developer/SDKs/" + sdkPart + sdkVer + ".sdk"
# Set the build flags
@@ -244,7 +255,7 @@ if target in ["iphone-device", "iphone-simulator", "xcode"] :
env["CXX"] = "$XCODE_PLATFORM_DEVELOPER_BIN_DIR/g++"
env["OBJCCFLAGS"] = ["-fobjc-abi-version=2", "-fobjc-legacy-dispatch"]
env["LD"] = env["CC"]
- env.Append(CCFLAGS = env["XCODE_ARCH_FLAGS"])
+ env.Append(CCFLAGS = env["XCODE_ARCH_FLAGS"] + ["-fvisibility=hidden"])
env.Append(LINKFLAGS = env["XCODE_ARCH_FLAGS"])
env.Append(CPPFLAGS = ["-isysroot", "$XCODE_SDKROOT"])
env.Append(FRAMEWORKS = ["CoreFoundation", "Foundation", "UIKit", "CoreGraphics"])
@@ -320,6 +331,12 @@ def checkObjCHeader(context, header) :
if ARGUMENTS.get("force-configure", 0) :
SCons.SConf.SetCacheMode("force")
+def CheckPKG(context, name):
+ context.Message( 'Checking for package %s... ' % name )
+ ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0]
+ context.Result( ret )
+ return ret
+
conf = Configure(conf_env)
if not conf.CheckCXX() or not conf.CheckCC() :
@@ -414,6 +431,31 @@ if env["PLATFORM"] != "win32" and env["PLATFORM"] != "darwin" :
env["XSS_FLAGS"] = xss_flags
conf.Finish()
+# GConf
+env["HAVE_GCONF"] = 0
+if env["PLATFORM"] != "win32" and env["PLATFORM"] != "darwin" :
+ gconf_env = conf_env.Clone()
+ conf = Configure(gconf_env, custom_tests = {"CheckPKG": CheckPKG})
+ if conf.CheckPKG("gconf-2.0") :
+ gconf_bare_env = Environment()
+ gconf_bare_env.ParseConfig('pkg-config --cflags gconf-2.0 --libs gconf-2.0')
+ gconf_flags = {
+ "LIBS": gconf_bare_env["LIBS"],
+ "CCFLAGS": gconf_bare_env["CCFLAGS"],
+ "CPPPATH": gconf_bare_env["CPPPATH"],
+ "CPPDEFINES": gconf_bare_env["CPPDEFINES"],
+ }
+ gconf_env.MergeFlags(gconf_flags)
+ if conf.CheckCHeader("gconf/gconf-client.h") and conf.CheckLib("gconf-2") :
+ env["HAVE_GCONF"] = 1
+ env["GCONF_FLAGS"] = {
+ "LIBS": gconf_env["LIBS"],
+ "CCFLAGS": gconf_env["CCFLAGS"],
+ "CPPPATH": gconf_env["CPPPATH"],
+ "CPPDEFINES": gconf_env["CPPDEFINES"],
+ }
+ conf.Finish()
+
# Sparkle
env["HAVE_SPARKLE"] = 0
if env["PLATFORM"] == "darwin" :
@@ -507,6 +549,23 @@ else :
env["LIBIDN_BUNDLED"] = 1
conf.Finish()
+# SQLite
+sqlite_conf_env = conf_env.Clone()
+sqlite_flags = {}
+if env.get("sqlite_libdir", None) :
+ sqlite_flags["LIBPATH"] = [env["sqlite_libdir"]]
+if env.get("sqlite_includedir", None) :
+ sqlite_flags["CPPPATH"] = [env["sqlite_includedir"]]
+sqlite_conf_env.MergeFlags(sqlite_flags)
+conf = Configure(sqlite_conf_env)
+if conf.CheckCHeader("sqlite3.h") and conf.CheckLib(env["sqlite_libname"]) :
+ env["HAVE_SQLITE"] = 1
+ env["SQLITE_FLAGS"] = { "LIBS": [env["sqlite_libname"]] }
+ env["SQLITE_FLAGS"].update(sqlite_flags)
+else :
+ env["SQLITE_BUNDLED"] = 1
+conf.Finish()
+
# Lua
env["LUA_BUNDLED"] = 1
@@ -621,6 +680,9 @@ if env.Dir("#/.git").exists() :
# Project files
################################################################################
+# Build tools
+env.SConscript(dirs = ["#/BuildTools/CLang"])
+
# Modules
modules = []
for dir in os.listdir(Dir("#/3rdParty").abspath) :
diff --git a/BuildTools/SCons/Tools/AppBundle.py b/BuildTools/SCons/Tools/AppBundle.py
index c271575..6a343f6 100644
--- a/BuildTools/SCons/Tools/AppBundle.py
+++ b/BuildTools/SCons/Tools/AppBundle.py
@@ -1,7 +1,7 @@
import SCons.Util, os.path
def generate(env) :
- def createAppBundle(env, bundle, version = "1.0", resources = [], frameworks = [], info = {}) :
+ def createAppBundle(env, bundle, version = "1.0", resources = [], frameworks = [], info = {}, handlesXMPPURIs = False) :
bundleDir = bundle + ".app"
bundleContentsDir = bundleDir + "/Contents"
resourcesDir = bundleContentsDir + "/Resources"
@@ -32,6 +32,18 @@ def generate(env) :
for key, value in infoDict.items() :
plist += "<key>" + key + "</key>\n"
plist += "<string>" + value.encode("utf-8") + "</string>\n"
+ if handlesXMPPURIs :
+ plist += """<key>CFBundleURLTypes</key>
+<array>
+ <dict>
+ <key>CFBundleURLName</key>
+ <string>XMPP URL</string>
+ <key>CFBundleURLSchemes</key>
+ <array>
+ <string>xmpp</string>
+ </array>
+ </dict>
+</array>\n"""
plist += """</dict>
</plist>
"""
diff --git a/COPYING b/COPYING
index dfc2bc6..a6e4bbb 100644
--- a/COPYING
+++ b/COPYING
@@ -825,6 +825,7 @@ Swift contains some code contributed under the BSD License, under the following
--- START OF BSD LICENSE
Copyright (c) 2011, Arnt Gulbrandsen
Copyright (c) 2011, Thilo Cestonaro
+Copyright (c) 2011, Vlad Voicu
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
diff --git a/Documentation/BuildingOnUnix.txt b/Documentation/BuildingOnUnix.txt
index 8de73c8..fa5759e 100644
--- a/Documentation/BuildingOnUnix.txt
+++ b/Documentation/BuildingOnUnix.txt
@@ -20,6 +20,9 @@ Running tests
-------------
- Run
./scons test=unit
- for running the unit tests, or
- ./scons test=all
- for running all tests.
+ for running the unit tests.
+
+Installing
+----------
+- To install swift in /usr/local, run
+ ./scons SWIFT_INSTALLDIR=/usr/local /usr/local
diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayload.h b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayload.h
index 7533a1e..62ea495 100644
--- a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayload.h
+++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayload.h
@@ -8,9 +8,8 @@
#include <Swiften/Swiften.h>
-using namespace Swift;
//...
-class EchoPayload : public Payload {
+class EchoPayload : public Swift::Payload {
public:
EchoPayload() {}
diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayloadParserFactory.h b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayloadParserFactory.h
index 9cbb795..33a8c41 100644
--- a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayloadParserFactory.h
+++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayloadParserFactory.h
@@ -9,9 +9,7 @@
#include <Swiften/Swiften.h>
#include "EchoPayload.h"
-using namespace Swift;
-
-class EchoPayloadParser : public GenericPayloadParser<EchoPayload> {
+class EchoPayloadParser : public Swift::GenericPayloadParser<EchoPayload> {
public:
EchoPayloadParser() : currentDepth(0) {}
@@ -36,7 +34,7 @@ class EchoPayloadParser : public GenericPayloadParser<EchoPayload> {
std::string currentText;
};
-class EchoPayloadParserFactory : public GenericPayloadParserFactory<EchoPayloadParser> {
+class EchoPayloadParserFactory : public Swift::GenericPayloadParserFactory<EchoPayloadParser> {
public:
EchoPayloadParserFactory() :
GenericPayloadParserFactory<EchoPayloadParser>("echo", "http://swift.im/echo") {}
diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayloadSerializer.h b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayloadSerializer.h
index 85e8e67..068113c 100644
--- a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayloadSerializer.h
+++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayloadSerializer.h
@@ -9,9 +9,7 @@
#include <Swiften/Swiften.h>
#include "EchoPayload.h"
-using namespace Swift;
-
-class EchoPayloadSerializer : public GenericPayloadSerializer<EchoPayload> {
+class EchoPayloadSerializer : public Swift::GenericPayloadSerializer<EchoPayload> {
public:
std::string serializePayload(boost::shared_ptr<EchoPayload> payload) const {
XMLElement element("echo", "http://swift.im/protocol/echo");
diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/SConscript b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/SConscript
index 1960609..c6349bd 100644
--- a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/SConscript
+++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/SConscript
@@ -15,11 +15,11 @@ if env["PLATFORM"] == "win32" :
if int(env["MSVS_VERSION"].split(".")[0]) >= 10 :
cpp0x = True
else :
- pass
-# Disabling C++0x compilation, because older boosts are not compliant yet
-# if env["CCVERSION"].split(".") >= ["4", "5", "0"] :
-# cpp0x = True
-# cpp0x_env.Replace(CXXFLAGS = [flag for flag in env["CXXFLAGS"] if flag != "-Werror"])
-# cpp0x_env.Append(CXXFLAGS = ["-std=c++0x"])
+ if env["CCVERSION"].split(".") >= ["4", "5", "0"] :
+ # Temporarily disabling c++0x mode because of problems with boost::thread
+ # on some platforms
+ #cpp0x = True
+ cpp0x_env.Replace(CXXFLAGS = [flag for flag in env["CXXFLAGS"] if flag != "-Werror"])
+ cpp0x_env.Append(CXXFLAGS = ["-std=c++0x"])
if cpp0x :
cpp0x_env.Program("EchoBot0x", "EchoBot0x.cpp")
diff --git a/QA/UnitTest/SConscript b/QA/UnitTest/SConscript
index 25e9b05..e5923ce 100644
--- a/QA/UnitTest/SConscript
+++ b/QA/UnitTest/SConscript
@@ -26,8 +26,12 @@ if env["TEST"] :
myenv.Append(CPPDEFINES = ["HAVE_LIBXML"])
if env.get("HAVE_EXPAT") :
myenv.Append(CPPDEFINES = ["HAVE_EXPAT"])
- checker = myenv.Program("checker", env["UNITTEST_SOURCES"] + env["UNITTEST_OBJECTS"])
- for i in ["HOME", "USERPROFILE", "APPDATA"]:
- if os.environ.get(i, "") :
- myenv["ENV"][i] = os.environ[i]
- myenv.Test(checker, is_checker = True)
+ if env["TEST_CREATE_LIBRARIES"] :
+ lib = myenv.StaticLibrary("Swift_UnitTests", env["UNITTEST_SOURCES"] + env["UNITTEST_OBJECTS"])
+ myenv.Program("checker", lib)
+ else :
+ checker = myenv.Program("checker", env["UNITTEST_SOURCES"] + env["UNITTEST_OBJECTS"])
+ for i in ["HOME", "USERPROFILE", "APPDATA"]:
+ if os.environ.get(i, "") :
+ myenv["ENV"][i] = os.environ[i]
+ myenv.Test(checker, is_checker = True)
diff --git a/Slimber/Cocoa/CocoaMenulet.h b/Slimber/Cocoa/CocoaMenulet.h
index 7f2758b..5c7c33e 100644
--- a/Slimber/Cocoa/CocoaMenulet.h
+++ b/Slimber/Cocoa/CocoaMenulet.h
@@ -9,7 +9,7 @@
#include <Cocoa/Cocoa.h>
#include "Slimber/Menulet.h"
-#include "Slimber/Cocoa/CocoaAction.h"
+#include <SwifTools/Cocoa/CocoaAction.h>
class CocoaMenulet : public Menulet {
public:
diff --git a/Slimber/Cocoa/SConscript b/Slimber/Cocoa/SConscript
index e2d8221..d664846 100644
--- a/Slimber/Cocoa/SConscript
+++ b/Slimber/Cocoa/SConscript
@@ -16,7 +16,6 @@ myenv.Program("Slimber", [
"main.mm",
"CocoaController.mm",
"CocoaMenulet.mm",
- "CocoaAction.mm"
])
myenv.Nib("MainMenu")
diff --git a/Slimber/Server.cpp b/Slimber/Server.cpp
index 380ce6a..809c56a 100644
--- a/Slimber/Server.cpp
+++ b/Slimber/Server.cpp
@@ -8,7 +8,9 @@
#include <string>
#include <boost/bind.hpp>
+#include <iostream>
+#include <Swiften/Base/foreach.h>
#include "Swiften/Base/String.h"
#include "Swiften/LinkLocal/LinkLocalConnector.h"
#include "Swiften/Network/Connection.h"
diff --git a/Sluift/Lua/Value.cpp b/Sluift/Lua/Value.cpp
index c03e633..3164ec6 100644
--- a/Sluift/Lua/Value.cpp
+++ b/Sluift/Lua/Value.cpp
@@ -6,9 +6,7 @@
#include "Value.h"
-extern "C" {
- #include <lualib.h>
-}
+#include <lualib.h>
#include <boost/variant/apply_visitor.hpp>
#include <Swiften/Base/foreach.h>
diff --git a/Sluift/SConscript b/Sluift/SConscript
index 576eae5..7c434de 100644
--- a/Sluift/SConscript
+++ b/Sluift/SConscript
@@ -22,6 +22,10 @@ if env["SCONS_STAGE"] == "build" :
myenv.Append(CPPDEFINES = ["SLUIFT_BUILD_DLL"])
elif myenv["PLATFORM"] == "darwin" :
myenv["SHLIBSUFFIX"] = ".so"
+ if env["PLATFORM"] == "win32" :
+ myenv.Append(CFLAGS = ["/TP"])
+ else :
+ myenv.Append(CFLAGS = ["-x", "c++"])
myenv["SLUIFT_VERSION"] = Version.getBuildVersion(env.Dir("#").abspath, "sluift")
def patchLua(env, target, source) :
diff --git a/Sluift/sluift.cpp b/Sluift/sluift.cpp
index 49cfec4..b911772 100644
--- a/Sluift/sluift.cpp
+++ b/Sluift/sluift.cpp
@@ -4,16 +4,15 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-extern "C" {
- #include "sluift.h"
- #include <lauxlib.h>
-}
+#include "sluift.h"
+#include <lauxlib.h>
#include <iostream>
#include <string>
#include <deque>
#include <boost/assign/list_of.hpp>
+#include <Swiften/Base/foreach.h>
#include <Swiften/Swiften.h>
#include "Watchdog.h"
@@ -63,6 +62,10 @@ class SluiftClient {
return client;
}
+ ClientOptions& getOptions() {
+ return options;
+ }
+
void connect() {
rosterReceived = false;
client->connect();
@@ -179,6 +182,7 @@ class SluiftClient {
private:
Client* client;
+ ClientOptions options;
ClientXMLTracer* tracer;
bool rosterReceived;
std::deque<Stanza::ref> pendingEvents;
@@ -453,12 +457,12 @@ static int sluift_client_set_options(lua_State* L) {
luaL_checktype(L, 2, LUA_TTABLE);
lua_getfield(L, 2, "compress");
if (!lua_isnil(L, -1)) {
- client->getClient()->setUseStreamCompression(lua_toboolean(L, -1));
+ client->getOptions().useStreamCompression = lua_toboolean(L, -1);
}
lua_getfield(L, 2, "tls");
if (!lua_isnil(L, -1)) {
bool useTLS = lua_toboolean(L, -1);
- client->getClient()->setUseTLS(useTLS ? Client::UseTLSWhenAvailable : Client::NeverUseTLS);
+ client->getOptions().useTLS = (useTLS ? ClientOptions::UseTLSWhenAvailable : ClientOptions::NeverUseTLS);
}
lua_pushvalue(L, 1);
return 0;
diff --git a/SwifTools/Application/SConscript b/SwifTools/Application/SConscript
index 0097bca..32924fc 100644
--- a/SwifTools/Application/SConscript
+++ b/SwifTools/Application/SConscript
@@ -21,6 +21,7 @@ else :
objects = swiftools_env.StaticObject(sources)
swiftools_env.Append(SWIFTOOLS_OBJECTS = [objects])
-env.Append(UNITTEST_SOURCES = [
- File("UnitTest/ApplicationPathProviderTest.cpp")
- ])
+if swiftools_env["PLATFORM"] != "darwin" or swiftools_env["target"] == "native" :
+ env.Append(UNITTEST_SOURCES = [
+ File("UnitTest/ApplicationPathProviderTest.cpp")
+ ])
diff --git a/Slimber/Cocoa/CocoaAction.h b/SwifTools/Cocoa/CocoaAction.h
index a46ef7c..a46ef7c 100644
--- a/Slimber/Cocoa/CocoaAction.h
+++ b/SwifTools/Cocoa/CocoaAction.h
diff --git a/Slimber/Cocoa/CocoaAction.mm b/SwifTools/Cocoa/CocoaAction.mm
index 15498a1..d560787 100644
--- a/Slimber/Cocoa/CocoaAction.mm
+++ b/SwifTools/Cocoa/CocoaAction.mm
@@ -1,4 +1,10 @@
-#include "Slimber/Cocoa/CocoaAction.h"
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <SwifTools/Cocoa/CocoaAction.h>
@implementation CocoaAction
diff --git a/SwifTools/Cocoa/SConscript b/SwifTools/Cocoa/SConscript
new file mode 100644
index 0000000..4ae4a07
--- /dev/null
+++ b/SwifTools/Cocoa/SConscript
@@ -0,0 +1,8 @@
+Import("swiftools_env", "env")
+
+sources = []
+if swiftools_env["PLATFORM"] == "darwin" and swiftools_env["target"] == "native" :
+ sources += ["CocoaAction.mm"]
+
+objects = swiftools_env.StaticObject(sources)
+swiftools_env.Append(SWIFTOOLS_OBJECTS = [objects])
diff --git a/SwifTools/Idle/PlatformIdleQuerier.cpp b/SwifTools/Idle/PlatformIdleQuerier.cpp
index a28e701..6735348 100644
--- a/SwifTools/Idle/PlatformIdleQuerier.cpp
+++ b/SwifTools/Idle/PlatformIdleQuerier.cpp
@@ -7,7 +7,7 @@
#include "SwifTools/Idle/PlatformIdleQuerier.h"
#include "Swiften/Base/Platform.h"
-#if defined(SWIFTEN_PLATFORM_MACOSX) && defined(HAVE_IOKIT)
+#if defined(SWIFTEN_PLATFORM_MACOSX) && defined(HAVE_IOKIT) && !defined(SWIFTEN_PLATFORM_IPHONE)
#include "SwifTools/Idle/MacOSXIdleQuerier.h"
#elif defined(SWIFTEN_PLATFORM_WINDOWS)
#include "SwifTools/Idle/WindowsIdleQuerier.h"
@@ -23,7 +23,7 @@ namespace Swift {
PlatformIdleQuerier::PlatformIdleQuerier() : querier(NULL) {
#if defined(SWIFTEN_PLATFORM_MACOSX)
-#if defined(HAVE_IOKIT)
+#if defined(HAVE_IOKIT) && !defined(SWIFTEN_PLATFORM_IPHONE)
querier = new MacOSXIdleQuerier();
#else
querier = new DummyIdleQuerier();
diff --git a/SwifTools/LastLineTracker.cpp b/SwifTools/LastLineTracker.cpp
new file mode 100644
index 0000000..a7360a8
--- /dev/null
+++ b/SwifTools/LastLineTracker.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2011 Vlad Voicu
+ * Licensed under the Simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "LastLineTracker.h"
+
+using namespace Swift;
+
+LastLineTracker::LastLineTracker() {
+ lastFocus = true;
+ shouldMove = false;
+}
+
+void LastLineTracker::setHasFocus(bool focus) {
+ if (!focus && lastFocus) {
+ shouldMove = true;
+ lastFocus = focus;
+ return;
+ }
+ shouldMove = false;
+ lastFocus = focus;
+}
+
+bool LastLineTracker::getShouldMoveLastLine() {
+ bool ret = shouldMove;
+ shouldMove = false;
+ return ret;
+}
diff --git a/SwifTools/LastLineTracker.h b/SwifTools/LastLineTracker.h
new file mode 100644
index 0000000..b7c9a3b
--- /dev/null
+++ b/SwifTools/LastLineTracker.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2011 Vlad Voicu
+ * Licensed under the Simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+namespace Swift {
+ class LastLineTracker {
+ public:
+ LastLineTracker();
+ void setHasFocus(bool focus);
+ bool getShouldMoveLastLine();
+ private:
+ bool lastFocus;
+ bool shouldMove;
+ };
+}
diff --git a/SwifTools/Linkify.cpp b/SwifTools/Linkify.cpp
index 91c713f..a5deccb 100644
--- a/SwifTools/Linkify.cpp
+++ b/SwifTools/Linkify.cpp
@@ -12,7 +12,7 @@
namespace Swift {
-static boost::regex linkifyRegexp("^https?://.*");
+static boost::regex linkifyRegexp("^(https?://|xmpp:).*");
std::string Linkify::linkify(const std::string& input) {
std::ostringstream result;
diff --git a/SwifTools/SConscript b/SwifTools/SConscript
index d4747db..e5085cc 100644
--- a/SwifTools/SConscript
+++ b/SwifTools/SConscript
@@ -27,6 +27,7 @@ if env["SCONS_STAGE"] == "build" :
"AutoUpdater/PlatformAutoUpdaterFactory.cpp",
"Linkify.cpp",
"TabComplete.cpp",
+ "LastLineTracker.cpp",
]
if swiftools_env.get("HAVE_SPARKLE", 0) :
@@ -50,8 +51,10 @@ if env["SCONS_STAGE"] == "build" :
"Application",
"Dock",
"Notifier",
+ "URIHandler",
"Idle/IdleQuerierTest",
"Idle/UnitTest",
+ "Cocoa",
"UnitTest"
])
diff --git a/SwifTools/URIHandler/MacOSXURIHandler.h b/SwifTools/URIHandler/MacOSXURIHandler.h
new file mode 100644
index 0000000..f803420
--- /dev/null
+++ b/SwifTools/URIHandler/MacOSXURIHandler.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <SwifTools/URIHandler/URIHandler.h>
+
+namespace Swift {
+ class MacOSXURIHandler : public URIHandler {
+ public:
+ MacOSXURIHandler();
+ virtual ~MacOSXURIHandler();
+
+ virtual void start();
+ virtual void stop();
+
+ private:
+ class Private;
+ Private* p;
+ };
+}
diff --git a/SwifTools/URIHandler/MacOSXURIHandler.mm b/SwifTools/URIHandler/MacOSXURIHandler.mm
new file mode 100644
index 0000000..3542e2f
--- /dev/null
+++ b/SwifTools/URIHandler/MacOSXURIHandler.mm
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <SwifTools/URIHandler/MacOSXURIHandler.h>
+
+#include <Cocoa/Cocoa.h>
+#include <iostream>
+
+using namespace Swift;
+
+@interface MacOSXURIEventHandler : NSObject {
+ URIHandler* handler;
+}
+- (id) initWithHandler: (URIHandler*) handler;
+- (void) getUrl: (NSAppleEventDescriptor*) event withReplyEvent: (NSAppleEventDescriptor*) replyEvent;
+
+@end
+@implementation MacOSXURIEventHandler
+ - (id) initWithHandler: (URIHandler*) h {
+ if ([super init]) {
+ handler = h;
+ }
+ return self;
+ }
+
+ - (void) getUrl: (NSAppleEventDescriptor*) event withReplyEvent: (NSAppleEventDescriptor*) replyEvent {
+ (void) replyEvent;
+ NSString* url = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
+ handler->onURI(std::string([url UTF8String]));
+ }
+@end
+
+class MacOSXURIHandler::Private {
+ public:
+ MacOSXURIEventHandler* eventHandler;
+};
+
+MacOSXURIHandler::MacOSXURIHandler() {
+ p = new Private();
+ p->eventHandler = [[MacOSXURIEventHandler alloc] initWithHandler: this];
+}
+
+MacOSXURIHandler::~MacOSXURIHandler() {
+ [p->eventHandler release];
+ delete p;
+}
+
+void MacOSXURIHandler::start() {
+ [[NSAppleEventManager sharedAppleEventManager] setEventHandler:p->eventHandler andSelector:@selector(getUrl:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
+ NSString* bundleID = [[NSBundle mainBundle] bundleIdentifier];
+ LSSetDefaultHandlerForURLScheme((CFStringRef)@"xmpp", (CFStringRef)bundleID);
+}
+
+void MacOSXURIHandler::stop() {
+ [[NSAppleEventManager sharedAppleEventManager] removeEventHandlerForEventClass:kInternetEventClass andEventID:kAEGetURL];
+}
diff --git a/Swiften/Elements/JingleTransport.h b/SwifTools/URIHandler/MacOSXURIHandlerHelpers.h
index ecd2a34..5a2db7a 100644
--- a/Swiften/Elements/JingleTransport.h
+++ b/SwifTools/URIHandler/MacOSXURIHandlerHelpers.h
@@ -6,9 +6,6 @@
#pragma once
-#include <Swiften/Elements/Payload.h>
-
namespace Swift {
- class JingleTransport : public Payload {
- };
+ void registerAppAsDefaultXMPPURIHandler();
}
diff --git a/SwifTools/URIHandler/MacOSXURIHandlerHelpers.mm b/SwifTools/URIHandler/MacOSXURIHandlerHelpers.mm
new file mode 100644
index 0000000..dca91b8
--- /dev/null
+++ b/SwifTools/URIHandler/MacOSXURIHandlerHelpers.mm
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <SwifTools/URIHandler/MacOSXURIHandlerHelpers.h>
+
+#include <Cocoa/Cocoa.h>
+
+namespace Swift {
+ void registerAppAsDefaultXMPPURIHandler() {
+ NSString* bundleID = [[NSBundle mainBundle] bundleIdentifier];
+ LSSetDefaultHandlerForURLScheme((CFStringRef)@"xmpp", (CFStringRef)bundleID);
+ }
+}
diff --git a/SwifTools/URIHandler/NullURIHandler.h b/SwifTools/URIHandler/NullURIHandler.h
new file mode 100644
index 0000000..28c35bb
--- /dev/null
+++ b/SwifTools/URIHandler/NullURIHandler.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <SwifTools/URIHandler/URIHandler.h>
+
+namespace Swift {
+ class NullURIHandler : public URIHandler {
+ public:
+ virtual void start() {
+ }
+
+ virtual void stop() {
+ }
+ };
+}
diff --git a/SwifTools/URIHandler/SConscript b/SwifTools/URIHandler/SConscript
new file mode 100644
index 0000000..42c6ca8
--- /dev/null
+++ b/SwifTools/URIHandler/SConscript
@@ -0,0 +1,23 @@
+Import("swiftools_env", "env")
+
+sources = [
+ "XMPPURI.cpp",
+ "URIHandler.cpp",
+ ]
+
+if swiftools_env["PLATFORM"] == "darwin" and swiftools_env["target"] == "native" :
+ sources += [
+ "MacOSXURIHandler.mm",
+ "MacOSXURIHandlerHelpers.mm",
+ ]
+elif swiftools_env["PLATFORM"] == "win32" :
+ sources += []
+else :
+ sources += []
+
+objects = swiftools_env.StaticObject(sources)
+swiftools_env.Append(SWIFTOOLS_OBJECTS = [objects])
+
+env.Append(UNITTEST_SOURCES = [
+ File("UnitTest/XMPPURITest.cpp"),
+ ])
diff --git a/SwifTools/URIHandler/URIHandler.cpp b/SwifTools/URIHandler/URIHandler.cpp
new file mode 100644
index 0000000..91e54e5
--- /dev/null
+++ b/SwifTools/URIHandler/URIHandler.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <SwifTools/URIHandler/URIHandler.h>
+
+using namespace Swift;
+
+URIHandler::URIHandler() {
+}
+
+URIHandler::~URIHandler() {
+}
diff --git a/SwifTools/URIHandler/URIHandler.h b/SwifTools/URIHandler/URIHandler.h
new file mode 100644
index 0000000..9dd13a8
--- /dev/null
+++ b/SwifTools/URIHandler/URIHandler.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <string>
+#include <Swiften/Base/boost_bsignals.h>
+
+namespace Swift {
+ class URIHandler {
+ public:
+ URIHandler();
+ virtual ~URIHandler();
+
+ boost::signal<void (const std::string&)> onURI;
+ };
+}
diff --git a/SwifTools/URIHandler/UnitTest/XMPPURITest.cpp b/SwifTools/URIHandler/UnitTest/XMPPURITest.cpp
new file mode 100644
index 0000000..8d03b60
--- /dev/null
+++ b/SwifTools/URIHandler/UnitTest/XMPPURITest.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include <SwifTools/URIHandler/XMPPURI.h>
+
+using namespace Swift;
+
+class XMPPURITest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(XMPPURITest);
+ CPPUNIT_TEST(testFromString_Authority);
+ CPPUNIT_TEST(testFromString_AuthorityWithPath);
+ CPPUNIT_TEST(testFromString_AuthorityWithFragment);
+ CPPUNIT_TEST(testFromString_AuthorityWithPathAndFragment);
+ CPPUNIT_TEST(testFromString_AuthorityWithIntlChars);
+ CPPUNIT_TEST(testFromString_AuthorityWithQueryWithoutParameters);
+ CPPUNIT_TEST(testFromString_AuthorityWithQueryWithParameters);
+ CPPUNIT_TEST(testFromString_AuthorityWithQueryWithoutParametersWithFragment);
+ CPPUNIT_TEST(testFromString_AuthorityWithQueryWithParametersWithFragment);
+ CPPUNIT_TEST(testFromString_Path);
+ CPPUNIT_TEST(testFromString_PathWithFragment);
+ CPPUNIT_TEST(testFromString_PathWithIntlChars);
+ CPPUNIT_TEST(testFromString_PathWithInvalidEscapedChar);
+ CPPUNIT_TEST(testFromString_PathWithIncompleteEscapedChar);
+ CPPUNIT_TEST(testFromString_PathWithIncompleteEscapedChar2);
+ CPPUNIT_TEST(testFromString_PathWithQueryWithoutParameters);
+ CPPUNIT_TEST(testFromString_PathWithQueryWithParameters);
+ CPPUNIT_TEST(testFromString_PathWithQueryWithoutParametersWithFragment);
+ CPPUNIT_TEST(testFromString_PathWithQueryWithParametersWithFragment);
+ CPPUNIT_TEST(testFromString_NoPrefix);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void testFromString_Authority() {
+ XMPPURI testling = XMPPURI::fromString("xmpp://foo@bar.com");
+
+ CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com"), testling.getAuthority());
+ }
+
+ void testFromString_AuthorityWithPath() {
+ XMPPURI testling = XMPPURI::fromString("xmpp://foo@bar.com/baz@example.com");
+
+ CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com"), testling.getAuthority());
+ CPPUNIT_ASSERT_EQUAL(JID("baz@example.com"), testling.getPath());
+ }
+
+ void testFromString_AuthorityWithFragment() {
+ XMPPURI testling = XMPPURI::fromString("xmpp://foo@bar.com#myfragment");
+
+ CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com"), testling.getAuthority());
+ CPPUNIT_ASSERT_EQUAL(std::string("myfragment"), testling.getFragment());
+ }
+
+ void testFromString_AuthorityWithPathAndFragment() {
+ XMPPURI testling = XMPPURI::fromString("xmpp://foo@bar.com/baz@example.com#myfragment");
+
+ CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com"), testling.getAuthority());
+ CPPUNIT_ASSERT_EQUAL(JID("baz@example.com"), testling.getPath());
+ CPPUNIT_ASSERT_EQUAL(std::string("myfragment"), testling.getFragment());
+ }
+
+ void testFromString_AuthorityWithIntlChars() {
+ XMPPURI testling = XMPPURI::fromString("xmpp://nasty!%23$%25()*+,-.;=\%3F\%5B\%5C\%5D\%5E_\%60\%7B\%7C\%7D~node@example.com");
+
+ CPPUNIT_ASSERT_EQUAL(JID("nasty!#$\%()*+,-.;=?[\\]^_`{|}~node@example.com"), testling.getAuthority());
+ }
+
+ void testFromString_AuthorityWithQueryWithoutParameters() {
+ XMPPURI testling = XMPPURI::fromString("xmpp://test@example.com?message");
+
+ CPPUNIT_ASSERT_EQUAL(JID("test@example.com"), testling.getAuthority());
+ CPPUNIT_ASSERT_EQUAL(std::string("message"), testling.getQueryType());
+ }
+
+ void testFromString_AuthorityWithQueryWithParameters() {
+ XMPPURI testling = XMPPURI::fromString("xmpp://test@example.com?message;subject=Test%20Message;body=Here%27s%20a%20test%20message");
+
+ CPPUNIT_ASSERT_EQUAL(JID("test@example.com"), testling.getAuthority());
+ CPPUNIT_ASSERT_EQUAL(std::string("message"), testling.getQueryType());
+ CPPUNIT_ASSERT_EQUAL(std::string("Test Message"), get(testling.getQueryParameters(), "subject"));
+ CPPUNIT_ASSERT_EQUAL(std::string("Here's a test message"), get(testling.getQueryParameters(), "body"));
+ }
+
+ void testFromString_AuthorityWithQueryWithoutParametersWithFragment() {
+ XMPPURI testling = XMPPURI::fromString("xmpp://test@example.com?message#myfragment");
+
+ CPPUNIT_ASSERT_EQUAL(JID("test@example.com"), testling.getAuthority());
+ CPPUNIT_ASSERT_EQUAL(std::string("message"), testling.getQueryType());
+ CPPUNIT_ASSERT_EQUAL(std::string("myfragment"), testling.getFragment());
+ }
+
+ void testFromString_AuthorityWithQueryWithParametersWithFragment() {
+ XMPPURI testling = XMPPURI::fromString("xmpp://test@example.com?message;subject=Test%20Message;body=Here%27s%20a%20test%20message#myfragment");
+
+ CPPUNIT_ASSERT_EQUAL(JID("test@example.com"), testling.getAuthority());
+ CPPUNIT_ASSERT_EQUAL(std::string("message"), testling.getQueryType());
+ CPPUNIT_ASSERT_EQUAL(std::string("Test Message"), get(testling.getQueryParameters(), "subject"));
+ CPPUNIT_ASSERT_EQUAL(std::string("Here's a test message"), get(testling.getQueryParameters(), "body"));
+ CPPUNIT_ASSERT_EQUAL(std::string("myfragment"), testling.getFragment());
+ }
+
+ void testFromString_Path() {
+ XMPPURI testling = XMPPURI::fromString("xmpp:baz@example.com");
+
+ CPPUNIT_ASSERT_EQUAL(JID("baz@example.com"), testling.getPath());
+ }
+
+ void testFromString_PathWithFragment() {
+ XMPPURI testling = XMPPURI::fromString("xmpp:baz@example.com#myfragment");
+
+ CPPUNIT_ASSERT_EQUAL(JID("baz@example.com"), testling.getPath());
+ CPPUNIT_ASSERT_EQUAL(std::string("myfragment"), testling.getFragment());
+ }
+
+ void testFromString_PathWithIntlChars() {
+ XMPPURI testling = XMPPURI::fromString("xmpp:nasty!%23$%25()*+,-.;=\%3F\%5B\%5C\%5D\%5E_\%60\%7B\%7C\%7D~node@example.com");
+
+ CPPUNIT_ASSERT_EQUAL(JID("nasty!#$\%()*+,-.;=?[\\]^_`{|}~node@example.com"), testling.getPath());
+ }
+
+ void testFromString_PathWithInvalidEscapedChar() {
+ XMPPURI testling = XMPPURI::fromString("xmpp:test%%@example.com");
+
+ CPPUNIT_ASSERT_EQUAL(JID(), testling.getPath());
+ }
+
+ void testFromString_PathWithIncompleteEscapedChar() {
+ XMPPURI testling = XMPPURI::fromString("xmpp:test@example.com%");
+
+ CPPUNIT_ASSERT_EQUAL(JID(), testling.getPath());
+ }
+
+ void testFromString_PathWithIncompleteEscapedChar2() {
+ XMPPURI testling = XMPPURI::fromString("xmpp:test@example.com%1");
+
+ CPPUNIT_ASSERT_EQUAL(JID(), testling.getPath());
+ }
+
+ void testFromString_PathWithQueryWithoutParameters() {
+ XMPPURI testling = XMPPURI::fromString("xmpp:test@example.com?message");
+
+ CPPUNIT_ASSERT_EQUAL(JID("test@example.com"), testling.getPath());
+ CPPUNIT_ASSERT_EQUAL(std::string("message"), testling.getQueryType());
+ }
+
+ void testFromString_PathWithQueryWithParameters() {
+ XMPPURI testling = XMPPURI::fromString("xmpp:test@example.com?message;subject=Test%20Message;body=Here%27s%20a%20test%20message");
+
+ CPPUNIT_ASSERT_EQUAL(JID("test@example.com"), testling.getPath());
+ CPPUNIT_ASSERT_EQUAL(std::string("message"), testling.getQueryType());
+ CPPUNIT_ASSERT_EQUAL(std::string("Test Message"), get(testling.getQueryParameters(), "subject"));
+ CPPUNIT_ASSERT_EQUAL(std::string("Here's a test message"), get(testling.getQueryParameters(), "body"));
+ }
+
+ void testFromString_PathWithQueryWithoutParametersWithFragment() {
+ XMPPURI testling = XMPPURI::fromString("xmpp:test@example.com?message#myfragment");
+
+ CPPUNIT_ASSERT_EQUAL(JID("test@example.com"), testling.getPath());
+ CPPUNIT_ASSERT_EQUAL(std::string("message"), testling.getQueryType());
+ CPPUNIT_ASSERT_EQUAL(std::string("myfragment"), testling.getFragment());
+ }
+
+ void testFromString_PathWithQueryWithParametersWithFragment() {
+ XMPPURI testling = XMPPURI::fromString("xmpp:test@example.com?message;subject=Test%20Message;body=Here%27s%20a%20test%20message#myfragment");
+
+ CPPUNIT_ASSERT_EQUAL(JID("test@example.com"), testling.getPath());
+ CPPUNIT_ASSERT_EQUAL(std::string("message"), testling.getQueryType());
+ CPPUNIT_ASSERT_EQUAL(std::string("Test Message"), get(testling.getQueryParameters(), "subject"));
+ CPPUNIT_ASSERT_EQUAL(std::string("Here's a test message"), get(testling.getQueryParameters(), "body"));
+ CPPUNIT_ASSERT_EQUAL(std::string("myfragment"), testling.getFragment());
+ }
+
+ void testFromString_NoPrefix() {
+ XMPPURI testling = XMPPURI::fromString("baz@example.com");
+
+ CPPUNIT_ASSERT(testling.isNull());
+ }
+
+ private:
+ std::string get(const std::map<std::string, std::string>& m, const std::string& k) {
+ std::map<std::string, std::string>::const_iterator i = m.find(k);
+ return i == m.end() ? "" : i->second;
+ }
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(XMPPURITest);
diff --git a/SwifTools/URIHandler/XMPPURI.cpp b/SwifTools/URIHandler/XMPPURI.cpp
new file mode 100644
index 0000000..de83ac2
--- /dev/null
+++ b/SwifTools/URIHandler/XMPPURI.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <SwifTools/URIHandler/XMPPURI.h>
+
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/algorithm/string/find_format.hpp>
+#include <boost/algorithm/string/formatter.hpp>
+#include <boost/algorithm/string/find_iterator.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/classification.hpp>
+#include <sstream>
+#include <stdexcept>
+#include <vector>
+
+using namespace Swift;
+
+// Should be in anonymous namespace, but older GCCs complain if we do that
+struct PercentEncodedCharacterFinder {
+ template<typename Iterator>
+ boost::iterator_range<Iterator> operator()(Iterator begin, Iterator end) {
+ boost::iterator_range<Iterator> r = boost::first_finder("%")(begin, end);
+ if (r.end() == end) {
+ return r;
+ }
+ else {
+ if (r.end() + 1 == end || r.end() + 2 == end) {
+ throw std::runtime_error("Incomplete escape character");
+ }
+ else {
+ r.advance_end(2);
+ return r;
+ }
+ }
+ }
+};
+
+struct PercentUnencodeFormatter {
+ template<typename FindResult>
+ std::string operator()(const FindResult& match) const {
+ std::stringstream s;
+ s << std::hex << std::string(match.begin() + 1, match.end());
+ unsigned int value;
+ s >> value;
+ if (s.fail() || s.bad()) {
+ throw std::runtime_error("Invalid escape character");
+ }
+ unsigned char charValue = static_cast<unsigned char>(value);
+ return std::string(reinterpret_cast<const char*>(&charValue), 1);
+ }
+};
+
+namespace {
+ std::string unescape(const std::string& s) {
+ try {
+ return boost::find_format_all_copy(s, PercentEncodedCharacterFinder(), PercentUnencodeFormatter());
+ }
+ catch (const std::exception&) {
+ return "";
+ }
+ }
+}
+
+XMPPURI::XMPPURI() {
+}
+
+XMPPURI XMPPURI::fromString(const std::string& s) {
+ XMPPURI result;
+ if (boost::starts_with(s, "xmpp:")) {
+ std::string uri = s.substr(5, s.npos);
+ bool parsePath = true;
+ bool parseQuery = true;
+ bool parseFragment = true;
+
+ // Parse authority
+ if (boost::starts_with(uri, "//")) {
+ size_t i = uri.find_first_of("/#?", 2);
+ result.setAuthority(JID(unescape(uri.substr(2, i - 2))));
+ if (i == uri.npos) {
+ uri = "";
+ parsePath = parseQuery = parseFragment = false;
+ }
+ else {
+ if (uri[i] == '?') {
+ parsePath = false;
+ }
+ else if (uri[i] == '#') {
+ parseQuery = parsePath = false;
+ }
+ uri = uri.substr(i + 1, uri.npos);
+ }
+ }
+
+ // Parse path
+ if (parsePath) {
+ size_t i = uri.find_first_of("#?");
+ result.setPath(JID(unescape(uri.substr(0, i))));
+ if (i == uri.npos) {
+ uri = "";
+ parseQuery = parseFragment = false;
+ }
+ else {
+ if (uri[i] == '#') {
+ parseQuery = false;
+ }
+ uri = uri.substr(i + 1, uri.npos);
+ }
+ }
+
+ // Parse query
+ if (parseQuery) {
+ size_t end = uri.find_first_of("#");
+ std::string query = uri.substr(0, end);
+ bool haveType = false;
+ typedef boost::split_iterator<std::string::iterator> split_iterator;
+ for (split_iterator it = boost::make_split_iterator(query, boost::first_finder(";")); it != split_iterator(); ++it) {
+ if (haveType) {
+ std::vector<std::string> keyValue;
+ boost::split(keyValue, *it, boost::is_any_of("="));
+ if (keyValue.size() == 1) {
+ result.addQueryParameter(unescape(keyValue[0]), "");
+ }
+ else if (keyValue.size() >= 2) {
+ result.addQueryParameter(unescape(keyValue[0]), unescape(keyValue[1]));
+ }
+ }
+ else {
+ result.setQueryType(unescape(boost::copy_range<std::string>(*it)));
+ haveType = true;
+ }
+ }
+ uri = (end == uri.npos ? "" : uri.substr(end + 1, uri.npos));
+ }
+
+ // Parse fragment
+ if (parseFragment) {
+ result.setFragment(unescape(uri));
+ }
+ }
+ return result;
+}
diff --git a/SwifTools/URIHandler/XMPPURI.h b/SwifTools/URIHandler/XMPPURI.h
new file mode 100644
index 0000000..266b79b
--- /dev/null
+++ b/SwifTools/URIHandler/XMPPURI.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <string>
+#include <map>
+
+#include <Swiften/JID/JID.h>
+
+namespace Swift {
+ class XMPPURI {
+ public:
+ XMPPURI();
+
+ const JID& getAuthority() const {
+ return authority;
+ }
+
+ void setAuthority(const JID& j) {
+ authority = j;
+ }
+
+ const JID& getPath() const {
+ return path;
+ }
+
+ void setPath(const JID& j) {
+ path = j;
+ }
+
+ const std::string& getQueryType() const {
+ return queryType;
+ }
+
+ void setQueryType(const std::string& q) {
+ queryType = q;
+ }
+
+ const std::map<std::string, std::string>& getQueryParameters() const {
+ return queryParameters;
+ }
+
+ void addQueryParameter(const std::string& key, const std::string& path) {
+ queryParameters[key] = path;
+ }
+
+ const std::string& getFragment() const {
+ return fragment;
+ }
+
+ void setFragment(const std::string& f) {
+ fragment = f;
+ }
+
+ bool isNull() const {
+ return !authority.isValid() && !path.isValid();
+ }
+
+ static XMPPURI fromString(const std::string&);
+
+ private:
+ JID authority;
+ JID path;
+ std::string fragment;
+ std::string queryType;
+ std::map<std::string, std::string> queryParameters;
+ };
+}
diff --git a/SwifTools/UnitTest/LastLineTrackerTest.cpp b/SwifTools/UnitTest/LastLineTrackerTest.cpp
new file mode 100644
index 0000000..374f4de
--- /dev/null
+++ b/SwifTools/UnitTest/LastLineTrackerTest.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2011 Vlad Voicu
+ * Licensed under the Simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include "SwifTools/LastLineTracker.h"
+
+using namespace Swift;
+
+class LastLineTrackerTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(LastLineTrackerTest);
+ CPPUNIT_TEST(testFocusNormal);
+ CPPUNIT_TEST(testFocusOut);
+ CPPUNIT_TEST(testFocusOtherTab);
+ CPPUNIT_TEST(testRepeatedFocusOut);
+ CPPUNIT_TEST(testRepeatedFocusIn);
+ CPPUNIT_TEST_SUITE_END();
+ public:
+ LastLineTrackerTest () {
+ };
+ void testFocusNormal() {
+ LastLineTracker testling;
+ testling.setHasFocus(true);
+ CPPUNIT_ASSERT_EQUAL(false, testling.getShouldMoveLastLine());
+ }
+ void testFocusOut() {
+ LastLineTracker testling;
+ testling.setHasFocus(false);
+ CPPUNIT_ASSERT_EQUAL(true, testling.getShouldMoveLastLine());
+ CPPUNIT_ASSERT_EQUAL(false, testling.getShouldMoveLastLine());
+ CPPUNIT_ASSERT_EQUAL(false, testling.getShouldMoveLastLine());
+ }
+ void testFocusOtherTab() {
+ LastLineTracker testling;
+ testling.setHasFocus(true);
+ testling.setHasFocus(false);
+ CPPUNIT_ASSERT_EQUAL(true, testling.getShouldMoveLastLine());
+ CPPUNIT_ASSERT_EQUAL(false, testling.getShouldMoveLastLine());
+ }
+
+ void testRepeatedFocusOut() {
+ LastLineTracker testling;
+ testling.setHasFocus(true);
+ CPPUNIT_ASSERT_EQUAL(false, testling.getShouldMoveLastLine());
+ testling.setHasFocus(false);
+ CPPUNIT_ASSERT_EQUAL(true, testling.getShouldMoveLastLine());
+ testling.setHasFocus(false);
+ CPPUNIT_ASSERT_EQUAL(false, testling.getShouldMoveLastLine());
+ }
+ void testRepeatedFocusIn() {
+ LastLineTracker testling;
+ testling.setHasFocus(false);
+ CPPUNIT_ASSERT_EQUAL(true, testling.getShouldMoveLastLine());
+ testling.setHasFocus(true);
+ testling.setHasFocus(false);
+ CPPUNIT_ASSERT_EQUAL(true, testling.getShouldMoveLastLine());
+ }
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(LastLineTrackerTest);
diff --git a/SwifTools/UnitTest/SConscript b/SwifTools/UnitTest/SConscript
index 8034905..e469deb 100644
--- a/SwifTools/UnitTest/SConscript
+++ b/SwifTools/UnitTest/SConscript
@@ -2,5 +2,6 @@ Import("env")
env.Append(UNITTEST_SOURCES = [
File("LinkifyTest.cpp"),
- File("TabCompleteTest.cpp")
+ File("TabCompleteTest.cpp"),
+ File("LastLineTrackerTest.cpp"),
])
diff --git a/Swift/Controllers/AdHocManager.cpp b/Swift/Controllers/AdHocManager.cpp
new file mode 100644
index 0000000..0fa63a1
--- /dev/null
+++ b/Swift/Controllers/AdHocManager.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2010-2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swift/Controllers/AdHocManager.h>
+
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/foreach.h>
+#include <Swiften/Queries/IQRouter.h>
+#include <Swiften/AdHoc/OutgoingAdHocCommandSession.h>
+#include <Swift/Controllers/UIInterfaces/MainWindow.h>
+#include <Swift/Controllers/UIInterfaces/AdHocCommandWindowFactory.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/Controllers/UIEvents/RequestAdHocUIEvent.h>
+
+namespace Swift {
+
+AdHocManager::AdHocManager(const JID& jid, AdHocCommandWindowFactory* factory, IQRouter* iqRouter, UIEventStream* uiEventStream, MainWindow* mainWindow) : jid_(jid) {
+ iqRouter_ = iqRouter;
+ uiEventStream_ = uiEventStream;
+ mainWindow_ = mainWindow;
+ factory_ = factory;
+
+ uiEventStream_->onUIEvent.connect(boost::bind(&AdHocManager::handleUIEvent, this, _1));
+}
+
+AdHocManager::~AdHocManager() {
+ uiEventStream_->onUIEvent.disconnect(boost::bind(&AdHocManager::handleUIEvent, this, _1));
+}
+
+void AdHocManager::setServerDiscoInfo(boost::shared_ptr<DiscoInfo> info) {
+ if (iqRouter_->isAvailable() && info->hasFeature(DiscoInfo::CommandsFeature)) {
+ if (discoItemsRequest_) {
+ discoItemsRequest_->onResponse.disconnect(boost::bind(&AdHocManager::handleServerDiscoItemsResponse, this, _1, _2));
+ discoItemsRequest_.reset();
+ }
+ discoItemsRequest_ = GetDiscoItemsRequest::create(JID(jid_.getDomain()), DiscoInfo::CommandsFeature, iqRouter_);
+ discoItemsRequest_->onResponse.connect(boost::bind(&AdHocManager::handleServerDiscoItemsResponse, this, _1, _2));
+ discoItemsRequest_->send();
+ } else {
+ mainWindow_->setAvailableAdHocCommands(std::vector<DiscoItems::Item>());
+ }
+
+}
+
+void AdHocManager::handleServerDiscoItemsResponse(boost::shared_ptr<DiscoItems> items, ErrorPayload::ref error) {
+ std::vector<DiscoItems::Item> commands;
+ if (!error) {
+ foreach (DiscoItems::Item item, items->getItems()) {
+ if (item.getNode() != "http://isode.com/xmpp/commands#test") {
+ commands.push_back(item);
+ }
+ }
+ }
+ mainWindow_->setAvailableAdHocCommands(commands);
+}
+
+void AdHocManager::handleUIEvent(boost::shared_ptr<UIEvent> event) {
+ boost::shared_ptr<RequestAdHocUIEvent> adHocEvent = boost::dynamic_pointer_cast<RequestAdHocUIEvent>(event);
+ if (adHocEvent) {
+ factory_->createAdHocCommandWindow(boost::shared_ptr<OutgoingAdHocCommandSession>(new OutgoingAdHocCommandSession(adHocEvent->getCommand(), factory_, iqRouter_)));
+ }
+}
+
+}
diff --git a/Swift/Controllers/AdHocManager.h b/Swift/Controllers/AdHocManager.h
new file mode 100644
index 0000000..47b03cd
--- /dev/null
+++ b/Swift/Controllers/AdHocManager.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2010-2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+#include <vector>
+
+#include <Swiften/Base/boost_bsignals.h>
+#include <Swiften/JID/JID.h>
+#include <Swiften/Elements/DiscoInfo.h>
+#include <Swiften/Elements/DiscoItems.h>
+#include <Swiften/Elements/ErrorPayload.h>
+#include <Swiften/Disco/GetDiscoItemsRequest.h>
+#include <Swift/Controllers/UIEvents/UIEvent.h>
+
+namespace Swift {
+ class IQRouter;
+ class MainWindow;
+ class UIEventStream;
+ class AdHocCommandWindowFactory;
+ class AdHocManager {
+ public:
+ AdHocManager(const JID& jid, AdHocCommandWindowFactory* factory, IQRouter* iqRouter, UIEventStream* uiEventStream, MainWindow* mainWindow);
+ ~AdHocManager();
+ void setServerDiscoInfo(boost::shared_ptr<DiscoInfo> info);
+ private:
+ void handleUIEvent(boost::shared_ptr<UIEvent> event);
+ void handleServerDiscoItemsResponse(boost::shared_ptr<DiscoItems>, ErrorPayload::ref error);
+ JID jid_;
+ IQRouter* iqRouter_;
+ UIEventStream* uiEventStream_;
+ MainWindow* mainWindow_;
+ AdHocCommandWindowFactory* factory_;
+ GetDiscoItemsRequest::ref discoItemsRequest_;
+ };
+}
diff --git a/Swift/Controllers/CertificateMemoryStorageFactory.h b/Swift/Controllers/CertificateMemoryStorageFactory.h
new file mode 100644
index 0000000..adbce80
--- /dev/null
+++ b/Swift/Controllers/CertificateMemoryStorageFactory.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swift/Controllers/Storages/CertificateStorageFactory.h>
+#include <Swift/Controllers/Storages/CertificateMemoryStorage.h>
+
+namespace Swift {
+ class CertificateFactory;
+
+ class CertificateMemoryStorageFactory : public CertificateStorageFactory {
+ public:
+ CertificateMemoryStorageFactory() {
+ }
+
+ virtual CertificateStorage* createCertificateStorage(const JID&) const {
+ return new CertificateMemoryStorage();
+ }
+
+ private:
+ boost::filesystem::path basePath;
+ CertificateFactory* certificateFactory;
+ };
+}
diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp
index 22ef68d..9767f8d 100644
--- a/Swift/Controllers/Chat/ChatController.cpp
+++ b/Swift/Controllers/Chat/ChatController.cpp
@@ -102,8 +102,23 @@ void ChatController::preHandleIncomingMessage(boost::shared_ptr<MessageEvent> me
setToJID(from);
}
}
- chatStateNotifier_->receivedMessageFromContact(message->getPayload<ChatState>());
+ boost::shared_ptr<Replace> replace = message->getPayload<Replace>();
+ if (replace) {
+ // Determine the timestamp
+ boost::posix_time::ptime timeStamp = boost::posix_time::microsec_clock::universal_time();
+ boost::optional<boost::posix_time::ptime> messageTimeStamp = getMessageTimestamp(message);
+ if (messageTimeStamp) {
+ timeStamp = *messageTimeStamp;
+ }
+ std::string body = message->getBody();
+ chatWindow_->replaceMessage(body, lastMessageUIID_, timeStamp);
+ replacedMessage_ = true;
+ }
+ else {
+ replacedMessage_ = false;
+ }
chatStateTracker_->handleMessageReceived(message);
+ chatStateNotifier_->receivedMessageFromContact(message->getPayload<ChatState>());
}
void ChatController::postHandleIncomingMessage(boost::shared_ptr<MessageEvent> messageEvent) {
@@ -116,21 +131,30 @@ void ChatController::preSendMessageRequest(boost::shared_ptr<Message> message) {
}
void ChatController::postSendMessage(const std::string& body, boost::shared_ptr<Stanza> sentStanza) {
- std::string id = addMessage(body, QT_TRANSLATE_NOOP("", "me"), true, labelsEnabled_ ? chatWindow_->getSelectedSecurityLabel().getLabel() : boost::shared_ptr<SecurityLabel>(), std::string(avatarManager_->getAvatarPath(selfJID_).string()), boost::posix_time::microsec_clock::universal_time());
- if (stanzaChannel_->getStreamManagementEnabled()) {
- chatWindow_->setAckState(id, ChatWindow::Pending);
- unackedStanzas_[sentStanza] = id;
+ if (stanzaChannel_->getStreamManagementEnabled() && !myLastMessageUIID_.empty()) {
+ chatWindow_->setAckState(myLastMessageUIID_, ChatWindow::Pending);
+ unackedStanzas_[sentStanza] = myLastMessageUIID_;
+ }
+ boost::shared_ptr<Replace> replace = sentStanza->getPayload<Replace>();
+ if (replace) {
+ chatWindow_->replaceMessage(body, myLastMessageUIID_, boost::posix_time::microsec_clock::universal_time());
+ } else {
+ myLastMessageUIID_ = addMessage(body, QT_TRANSLATE_NOOP("", "me"), true, labelsEnabled_ ? chatWindow_->getSelectedSecurityLabel().getLabel() : boost::shared_ptr<SecurityLabel>(), std::string(avatarManager_->getAvatarPath(selfJID_).string()), boost::posix_time::microsec_clock::universal_time());
+ if (stanzaChannel_->getStreamManagementEnabled()) {
+ chatWindow_->setAckState(myLastMessageUIID_, ChatWindow::Pending);
+ unackedStanzas_[sentStanza] = myLastMessageUIID_;
+ }
}
lastWasPresence_ = false;
chatStateNotifier_->userSentMessage();
}
void ChatController::handleStanzaAcked(boost::shared_ptr<Stanza> stanza) {
- std::string id = unackedStanzas_[stanza];
- if (id != "") {
- chatWindow_->setAckState(id, ChatWindow::Received);
+ std::map<boost::shared_ptr<Stanza>, std::string>::iterator unackedStanza = unackedStanzas_.find(stanza);
+ if (unackedStanza != unackedStanzas_.end()) {
+ chatWindow_->setAckState(unackedStanza->second, ChatWindow::Received);
+ unackedStanzas_.erase(unackedStanza);
}
- unackedStanzas_.erase(unackedStanzas_.find(stanza));
}
void ChatController::setOnline(bool online) {
diff --git a/Swift/Controllers/Chat/ChatController.h b/Swift/Controllers/Chat/ChatController.h
index dd4bf90..4fafb44 100644
--- a/Swift/Controllers/Chat/ChatController.h
+++ b/Swift/Controllers/Chat/ChatController.h
@@ -40,6 +40,7 @@ namespace Swift {
NickResolver* nickResolver_;
ChatStateNotifier* chatStateNotifier_;
ChatStateTracker* chatStateTracker_;
+ std::string myLastMessageUIID_;
bool isInMUC_;
bool lastWasPresence_;
std::string lastStatusChangeString_;
diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp
index 281d968..14e17cd 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.cpp
+++ b/Swift/Controllers/Chat/ChatControllerBase.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -30,9 +30,10 @@ namespace Swift {
ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory) : selfJID_(self), stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle), avatarManager_(avatarManager), useDelayForLatency_(useDelayForLatency), eventController_(eventController), timerFactory_(timerFactory) {
chatWindow_ = chatWindowFactory_->createChatWindow(toJID, eventStream);
chatWindow_->onAllMessagesRead.connect(boost::bind(&ChatControllerBase::handleAllMessagesRead, this));
- chatWindow_->onSendMessageRequest.connect(boost::bind(&ChatControllerBase::handleSendMessageRequest, this, _1));
+ chatWindow_->onSendMessageRequest.connect(boost::bind(&ChatControllerBase::handleSendMessageRequest, this, _1, _2));
setOnline(stanzaChannel->isAvailable() && iqRouter->isAvailable());
createDayChangeTimer();
+ replacedMessage_ = false;
}
ChatControllerBase::~ChatControllerBase() {
@@ -88,7 +89,7 @@ void ChatControllerBase::handleAllMessagesRead() {
chatWindow_->setUnreadMessageCount(0);
}
-void ChatControllerBase::handleSendMessageRequest(const std::string &body) {
+void ChatControllerBase::handleSendMessageRequest(const std::string &body, bool isCorrectionMessage) {
if (!stanzaChannel_->isAvailable() || body.empty()) {
return;
}
@@ -104,8 +105,13 @@ void ChatControllerBase::handleSendMessageRequest(const std::string &body) {
boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
message->addPayload(boost::shared_ptr<Delay>(new Delay(now, selfJID_)));
}
+ if (isCorrectionMessage) {
+ message->addPayload(boost::shared_ptr<Replace> (new Replace(lastSentMessageStanzaID_)));
+ }
+ message->setID(lastSentMessageStanzaID_ = idGenerator_.generateID());
stanzaChannel_->sendMessage(message);
postSendMessage(message->getBody(), boost::dynamic_pointer_cast<Stanza>(message));
+ onActivity(message->getBody());
}
void ChatControllerBase::handleSecurityLabelsCatalogResponse(boost::shared_ptr<SecurityLabelsCatalog> catalog, ErrorPayload::ref error) {
@@ -163,7 +169,7 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> m
JID from = message->getFrom();
std::vector<boost::shared_ptr<Delay> > delayPayloads = message->getPayloads<Delay>();
for (size_t i = 0; useDelayForLatency_ && i < delayPayloads.size(); i++) {
- if (!delayPayloads[i]->getFrom()) {
+ if (!delayPayloads[i]->getFrom()) {
continue;
}
boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
@@ -179,8 +185,10 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> m
if (messageTimeStamp) {
timeStamp = *messageTimeStamp;
}
-
- addMessage(body, senderDisplayNameFromMessage(from), isIncomingMessageFromMe(message), label, std::string(avatarManager_->getAvatarPath(from).string()), timeStamp);
+ onActivity(body);
+ if (!replacedMessage_) {
+ lastMessageUIID_ = addMessage(body, senderDisplayNameFromMessage(from), isIncomingMessageFromMe(message), label, std::string(avatarManager_->getAvatarPath(from).string()), timeStamp);
+ }
}
chatWindow_->show();
chatWindow_->setUnreadMessageCount(unreadMessages_.size());
diff --git a/Swift/Controllers/Chat/ChatControllerBase.h b/Swift/Controllers/Chat/ChatControllerBase.h
index 9573b1b..e0f1b94 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.h
+++ b/Swift/Controllers/Chat/ChatControllerBase.h
@@ -26,6 +26,7 @@
#include "Swiften/Elements/ErrorPayload.h"
#include "Swiften/Presence/PresenceOracle.h"
#include "Swiften/Queries/IQRouter.h"
+#include "Swiften/Base/IDGenerator.h"
namespace Swift {
class IQRouter;
@@ -47,6 +48,8 @@ namespace Swift {
virtual void setOnline(bool online);
virtual void setEnabled(bool enabled);
virtual void setToJID(const JID& jid) {toJID_ = jid;};
+ /** Used for determining when something is recent.*/
+ boost::signal<void (const std::string& /*activity*/)> onActivity;
protected:
ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory);
@@ -64,8 +67,10 @@ namespace Swift {
virtual void dayTicked() {};
private:
+ IDGenerator idGenerator_;
+ std::string lastSentMessageStanzaID_;
void createDayChangeTimer();
- void handleSendMessageRequest(const std::string &body);
+ void handleSendMessageRequest(const std::string &body, bool isCorrectionMessage);
void handleAllMessagesRead();
void handleSecurityLabelsCatalogResponse(boost::shared_ptr<SecurityLabelsCatalog>, ErrorPayload::ref error);
std::string getErrorMessage(boost::shared_ptr<ErrorPayload>);
@@ -80,6 +85,8 @@ namespace Swift {
ChatWindow* chatWindow_;
JID toJID_;
bool labelsEnabled_;
+ bool replacedMessage_;
+ std::string lastMessageUIID_;
PresenceOracle* presenceOracle_;
AvatarManager* avatarManager_;
bool useDelayForLatency_;
diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp
index 94d4b9a..b60f9a3 100644
--- a/Swift/Controllers/Chat/ChatsManager.cpp
+++ b/Swift/Controllers/Chat/ChatsManager.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -7,7 +7,9 @@
#include "Swift/Controllers/Chat/ChatsManager.h"
#include <boost/bind.hpp>
+#include <boost/algorithm/string.hpp>
+#include <Swiften/Base/foreach.h>
#include "Swift/Controllers/Chat/ChatController.h"
#include "Swift/Controllers/Chat/MUCSearchController.h"
#include "Swift/Controllers/XMPPEvents/EventController.h"
@@ -26,12 +28,15 @@
#include "Swiften/MUC/MUCManager.h"
#include "Swiften/Elements/ChatState.h"
#include "Swiften/MUC/MUCBookmarkManager.h"
+#include <Swift/Controllers/ProfileSettingsProvider.h>
namespace Swift {
typedef std::pair<JID, ChatController*> JIDChatControllerPair;
typedef std::pair<JID, MUCController*> JIDMUCControllerPair;
+#define RECENT_CHATS "recent_chats"
+
ChatsManager::ChatsManager(
JID jid, StanzaChannel* stanzaChannel,
IQRouter* iqRouter,
@@ -49,7 +54,7 @@ ChatsManager::ChatsManager(
EntityCapsProvider* entityCapsProvider,
MUCManager* mucManager,
MUCSearchWindowFactory* mucSearchWindowFactory,
- SettingsProvider* settings) :
+ ProfileSettingsProvider* settings) :
jid_(jid),
joinMUCWindowFactory_(joinMUCWindowFactory),
useDelayForLatency_(useDelayForLatency),
@@ -68,6 +73,7 @@ ChatsManager::ChatsManager(
presenceSender_ = presenceSender;
uiEventStream_ = uiEventStream;
mucBookmarkManager_ = NULL;
+ profileSettings_ = settings;
presenceOracle_->onPresenceChange.connect(boost::bind(&ChatsManager::handlePresenceChange, this, _1));
uiEventConnection_ = uiEventStream_->onUIEvent.connect(boost::bind(&ChatsManager::handleUIEvent, this, _1));
chatListWindow_ = chatListWindowFactory->createChatListWindow(uiEventStream_);
@@ -75,6 +81,7 @@ ChatsManager::ChatsManager(
mucSearchController_ = new MUCSearchController(jid_, mucSearchWindowFactory, iqRouter, settings);
mucSearchController_->onMUCSelected.connect(boost::bind(&ChatsManager::handleMUCSelectedAfterSearch, this, _1));
setupBookmarks();
+ loadRecents();
}
ChatsManager::~ChatsManager() {
@@ -89,6 +96,44 @@ ChatsManager::~ChatsManager() {
delete mucSearchController_;
}
+void ChatsManager::saveRecents() {
+ std::string recents;
+ foreach (ChatListWindow::Chat chat, recentChats_) {
+ std::vector<std::string> activity;
+ boost::split(activity, chat.activity, boost::is_any_of("\t\n"));
+ std::string recent = chat.jid.toString() + "\t" + activity[0] + "\t" + (chat.isMUC ? "true" : "false") + "\t" + chat.nick;
+ recents += recent + "\n";
+ }
+ profileSettings_->storeString(RECENT_CHATS, recents);
+}
+
+void ChatsManager::loadRecents() {
+ std::string recentsString(profileSettings_->getStringSetting(RECENT_CHATS));
+ std::vector<std::string> recents;
+ boost::split(recents, recentsString, boost::is_any_of("\n"));
+ int i = 0;
+ foreach (std::string recentString, recents) {
+ if (i++ > 30) {
+ break;
+ }
+ std::vector<std::string> recent;
+ boost::split(recent, recentString, boost::is_any_of("\t"));
+ if (recent.size() < 4) {
+ continue;
+ }
+ JID jid(recent[0]);
+ if (!jid.isValid()) {
+ continue;
+ }
+ std::string activity(recent[1]);
+ bool isMUC = recent[2] == "true";
+ std::string nick(recent[3]);
+ ChatListWindow::Chat chat(jid, nickResolver_->jidToNick(jid), activity, isMUC, nick);
+ recentChats_.push_back(chat);
+ chatListWindow_->setRecents(recentChats_);
+ }
+}
+
void ChatsManager::setupBookmarks() {
if (!mucBookmarkManager_) {
mucBookmarkManager_ = new MUCBookmarkManager(iqRouter_);
@@ -98,7 +143,7 @@ void ChatsManager::setupBookmarks() {
if (chatListWindow_) {
chatListWindow_->setBookmarksEnabled(false);
- chatListWindow_->clear();
+ chatListWindow_->clearBookmarks();
}
}
}
@@ -122,6 +167,16 @@ void ChatsManager::handleMUCBookmarkRemoved(const MUCBookmark& bookmark) {
chatListWindow_->removeMUCBookmark(bookmark);
}
+void ChatsManager::handleChatActivity(const JID& jid, const std::string& activity) {
+ /* FIXME: MUC use requires changes here. */
+ ChatListWindow::Chat chat(jid, nickResolver_->jidToNick(jid), activity, false);
+ /* FIXME: handle nick changes */
+ recentChats_.erase(std::remove(recentChats_.begin(), recentChats_.end(), chat), recentChats_.end());
+ recentChats_.push_front(chat);
+ chatListWindow_->setRecents(recentChats_);
+ saveRecents();
+}
+
void ChatsManager::handleUserLeftMUC(MUCController* mucController) {
std::map<JID, MUCController*>::iterator it;
for (it = mucControllers_.begin(); it != mucControllers_.end(); it++) {
@@ -157,13 +212,13 @@ void ChatsManager::handleUIEvent(boost::shared_ptr<UIEvent> event) {
else if (JoinMUCUIEvent::ref joinEvent = boost::dynamic_pointer_cast<JoinMUCUIEvent>(event)) {
handleJoinMUCRequest(joinEvent->getJID(), joinEvent->getNick(), false);
}
- else if (boost::dynamic_pointer_cast<RequestJoinMUCUIEvent>(event)) {
+ else if (boost::shared_ptr<RequestJoinMUCUIEvent> joinEvent = boost::dynamic_pointer_cast<RequestJoinMUCUIEvent>(event)) {
if (!joinMUCWindow_) {
joinMUCWindow_ = joinMUCWindowFactory_->createJoinMUCWindow();
joinMUCWindow_->onJoinMUC.connect(boost::bind(&ChatsManager::handleJoinMUCRequest, this, _1, _2, _3));
joinMUCWindow_->onSearchMUC.connect(boost::bind(&ChatsManager::handleSearchMUCRequest, this));
}
- joinMUCWindow_->setMUC("");
+ joinMUCWindow_->setMUC(joinEvent->getRoom());
joinMUCWindow_->setNick(nickResolver_->jidToNick(jid_));
joinMUCWindow_->show();
}
@@ -244,6 +299,7 @@ ChatController* ChatsManager::createNewChatController(const JID& contact) {
ChatController* controller = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_, mucRegistry_->isMUC(contact.toBare()), useDelayForLatency_, uiEventStream_, eventController_, timerFactory_, entityCapsProvider_);
chatControllers_[contact] = controller;
controller->setAvailableServerFeatures(serverDiscoInfo_);
+ controller->onActivity.connect(boost::bind(&ChatsManager::handleChatActivity, this, contact, _1));
return controller;
}
@@ -302,6 +358,7 @@ void ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::optional
controller->onUserLeft.connect(boost::bind(&ChatsManager::handleUserLeftMUC, this, controller));
}
mucControllers_[mucJID]->activateChatWindow();
+ /* FIXME: handleChatActivity connection for recents, and changes to that method.*/
}
void ChatsManager::handleSearchMUCRequest() {
diff --git a/Swift/Controllers/Chat/ChatsManager.h b/Swift/Controllers/Chat/ChatsManager.h
index 3740186..f489034 100644
--- a/Swift/Controllers/Chat/ChatsManager.h
+++ b/Swift/Controllers/Chat/ChatsManager.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -11,13 +11,14 @@
#include <boost/shared_ptr.hpp>
#include <string>
-#include "Swiften/Elements/DiscoInfo.h"
-#include "Swiften/Elements/Message.h"
-#include "Swiften/Elements/Presence.h"
-#include "Swiften/JID/JID.h"
-#include "Swiften/MUC/MUCRegistry.h"
-#include "Swift/Controllers/UIEvents/UIEventStream.h"
-#include "Swiften/MUC/MUCBookmark.h"
+#include <Swiften/Elements/DiscoInfo.h>
+#include <Swiften/Elements/Message.h>
+#include <Swiften/Elements/Presence.h>
+#include <Swiften/JID/JID.h>
+#include <Swiften/MUC/MUCRegistry.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/Controllers/UIInterfaces/ChatListWindow.h>
+#include <Swiften/MUC/MUCBookmark.h>
namespace Swift {
class EventController;
@@ -34,18 +35,17 @@ namespace Swift {
class IQRouter;
class PresenceSender;
class MUCBookmarkManager;
- class ChatListWindow;
class ChatListWindowFactory;
class TimerFactory;
class EntityCapsProvider;
class DirectedPresenceSender;
class MUCSearchWindowFactory;
- class SettingsProvider;
+ class ProfileSettingsProvider;
class MUCSearchController;
class ChatsManager {
public:
- ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, JoinMUCWindowFactory* joinMUCWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsProvider* entityCapsProvider, MUCManager* mucManager, MUCSearchWindowFactory* mucSearchWindowFactory, SettingsProvider* settings);
+ ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, JoinMUCWindowFactory* joinMUCWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsProvider* entityCapsProvider, MUCManager* mucManager, MUCSearchWindowFactory* mucSearchWindowFactory, ProfileSettingsProvider* settings);
virtual ~ChatsManager();
void setAvatarManager(AvatarManager* avatarManager);
void setOnline(bool enabled);
@@ -63,7 +63,11 @@ namespace Swift {
void handleMUCBookmarkRemoved(const MUCBookmark& bookmark);
void handleUserLeftMUC(MUCController* mucController);
void handleBookmarksReady();
+ void handleChatActivity(const JID& jid, const std::string& activity);
void setupBookmarks();
+ void loadRecents();
+ void saveRecents();
+ void handleChatMadeRecent();
ChatController* getChatControllerOrFindAnother(const JID &contact);
ChatController* createNewChatController(const JID &contact);
ChatController* getChatControllerOrCreate(const JID &contact);
@@ -92,5 +96,7 @@ namespace Swift {
EntityCapsProvider* entityCapsProvider_;
MUCManager* mucManager;
MUCSearchController* mucSearchController_;
+ std::list<ChatListWindow::Chat> recentChats_;
+ ProfileSettingsProvider* profileSettings_;
};
}
diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp
index 2914116..3c6f965 100644
--- a/Swift/Controllers/Chat/MUCController.cpp
+++ b/Swift/Controllers/Chat/MUCController.cpp
@@ -4,7 +4,7 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#include "Swift/Controllers/Chat/MUCController.h"
+#include <Swift/Controllers/Chat/MUCController.h>
#include <boost/bind.hpp>
#include <boost/regex.hpp>
@@ -12,23 +12,24 @@
#include <Swift/Controllers/Intl.h>
#include <Swiften/Base/format.h>
-#include "Swiften/Network/Timer.h"
-#include "Swiften/Network/TimerFactory.h"
-#include "Swiften/Base/foreach.h"
-#include "SwifTools/TabComplete.h"
-#include "Swiften/Base/foreach.h"
-#include "Swift/Controllers/XMPPEvents/EventController.h"
-#include "Swift/Controllers/UIInterfaces/ChatWindow.h"
-#include "Swift/Controllers/UIInterfaces/ChatWindowFactory.h"
-#include "Swift/Controllers/UIEvents/UIEventStream.h"
-#include "Swift/Controllers/UIEvents/RequestChatUIEvent.h"
-#include "Swiften/Avatars/AvatarManager.h"
-#include "Swiften/Elements/Delay.h"
-#include "Swiften/MUC/MUC.h"
-#include "Swiften/Client/StanzaChannel.h"
-#include "Swift/Controllers/Roster/Roster.h"
-#include "Swift/Controllers/Roster/SetAvatar.h"
-#include "Swift/Controllers/Roster/SetPresence.h"
+#include <Swiften/Network/Timer.h>
+#include <Swiften/Network/TimerFactory.h>
+#include <Swiften/Base/foreach.h>
+#include <SwifTools/TabComplete.h>
+#include <Swiften/Base/foreach.h>
+#include <Swift/Controllers/XMPPEvents/EventController.h>
+#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
+#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
+#include <Swift/Controllers/Roster/GroupRosterItem.h>
+#include <Swiften/Avatars/AvatarManager.h>
+#include <Swiften/Elements/Delay.h>
+#include <Swiften/MUC/MUC.h>
+#include <Swiften/Client/StanzaChannel.h>
+#include <Swift/Controllers/Roster/Roster.h>
+#include <Swift/Controllers/Roster/SetAvatar.h>
+#include <Swift/Controllers/Roster/SetPresence.h>
#define MUC_JOIN_WARNING_TIMEOUT_MILLISECONDS 60000
@@ -206,7 +207,9 @@ void MUCController::handleOccupantJoined(const MUCOccupant& occupant) {
currentOccupants_.insert(occupant.getNick());
NickJoinPart event(occupant.getNick(), Join);
appendToJoinParts(joinParts_, event);
- roster_->addContact(jid, realJID, occupant.getNick(), roleToGroupName(occupant.getRole()), avatarManager_->getAvatarPath(jid).string());
+ std::string groupName(roleToGroupName(occupant.getRole()));
+ roster_->addContact(jid, realJID, occupant.getNick(), groupName, avatarManager_->getAvatarPath(jid).string());
+ roster_->getGroup(groupName)->setManualSort(roleToSortName(occupant.getRole()));
if (joined_) {
std::string joinString;
MUCOccupant::Role role = occupant.getRole();
@@ -248,6 +251,16 @@ std::string MUCController::roleToFriendlyName(MUCOccupant::Role role) {
return "";
}
+std::string MUCController::roleToSortName(MUCOccupant::Role role) {
+ switch (role) {
+ case MUCOccupant::Moderator: return "1";
+ case MUCOccupant::Participant: return "2";
+ case MUCOccupant::Visitor: return "3";
+ case MUCOccupant::NoRole: return "4";
+ }
+ return "5";
+}
+
JID MUCController::nickToJID(const std::string& nick) {
return JID(toJID_.getNode(), toJID_.getDomain(), nick);
}
@@ -309,7 +322,9 @@ void MUCController::handleOccupantRoleChanged(const std::string& nick, const MUC
if (occupant.getRealJID()) {
realJID = occupant.getRealJID().get();
}
- roster_->addContact(jid, realJID, nick, roleToGroupName(occupant.getRole()), avatarManager_->getAvatarPath(jid).string());
+ std::string group(roleToGroupName(occupant.getRole()));
+ roster_->addContact(jid, realJID, nick, group, avatarManager_->getAvatarPath(jid).string());
+ roster_->getGroup(group)->setManualSort(roleToSortName(occupant.getRole()));
chatWindow_->addSystemMessage(str(format(QT_TRANSLATE_NOOP("", "%1% is now a %2%")) % nick % roleToFriendlyName(occupant.getRole())));
}
diff --git a/Swift/Controllers/Chat/MUCController.h b/Swift/Controllers/Chat/MUCController.h
index ebdd6cd..6b05a8e 100644
--- a/Swift/Controllers/Chat/MUCController.h
+++ b/Swift/Controllers/Chat/MUCController.h
@@ -7,18 +7,18 @@
#pragma once
#include <boost/shared_ptr.hpp>
-#include "Swiften/Base/boost_bsignals.h"
+#include <Swiften/Base/boost_bsignals.h>
#include <boost/signals/connection.hpp>
-#include <set>
+#include <set>
#include <string>
-#include "Swiften/Network/Timer.h"
-#include "Swift/Controllers/Chat/ChatControllerBase.h"
-#include "Swiften/Elements/Message.h"
-#include "Swiften/Elements/DiscoInfo.h"
-#include "Swiften/JID/JID.h"
-#include "Swiften/MUC/MUC.h"
-#include "Swiften/Elements/MUCOccupant.h"
+#include <Swiften/Network/Timer.h>
+#include <Swift/Controllers/Chat/ChatControllerBase.h>
+#include <Swiften/Elements/Message.h>
+#include <Swiften/Elements/DiscoInfo.h>
+#include <Swiften/JID/JID.h>
+#include <Swiften/MUC/MUC.h>
+#include <Swiften/Elements/MUCOccupant.h>
namespace Swift {
class StanzaChannel;
@@ -71,6 +71,7 @@ namespace Swift {
void handleJoinFailed(boost::shared_ptr<ErrorPayload> error);
void handleJoinTimeoutTick();
std::string roleToGroupName(MUCOccupant::Role role);
+ std::string roleToSortName(MUCOccupant::Role role);
JID nickToJID(const std::string& nick);
std::string roleToFriendlyName(MUCOccupant::Role role);
void receivedActivity();
diff --git a/Swift/Controllers/Chat/MUCSearchController.cpp b/Swift/Controllers/Chat/MUCSearchController.cpp
index 743aabb..2cb89b4 100644
--- a/Swift/Controllers/Chat/MUCSearchController.cpp
+++ b/Swift/Controllers/Chat/MUCSearchController.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -11,6 +11,7 @@
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
+#include <Swiften/Base/foreach.h>
#include <Swiften/Disco/GetDiscoItemsRequest.h>
#include <Swiften/Base/Log.h>
#include <Swiften/Base/String.h>
@@ -23,7 +24,7 @@ namespace Swift {
static const std::string SEARCHED_SERVICES = "searchedServices";
-MUCSearchController::MUCSearchController(const JID& jid, MUCSearchWindowFactory* factory, IQRouter* iqRouter, SettingsProvider* settings) : jid_(jid), factory_(factory), iqRouter_(iqRouter), settings_(settings), window_(NULL), walker_(NULL) {
+MUCSearchController::MUCSearchController(const JID& jid, MUCSearchWindowFactory* factory, IQRouter* iqRouter, ProfileSettingsProvider* settings) : jid_(jid), factory_(factory), iqRouter_(iqRouter), settings_(settings), window_(NULL), walker_(NULL) {
itemsInProgress_ = 0;
loadSavedServices();
}
diff --git a/Swift/Controllers/Chat/MUCSearchController.h b/Swift/Controllers/Chat/MUCSearchController.h
index c8040ed..f90e4a7 100644
--- a/Swift/Controllers/Chat/MUCSearchController.h
+++ b/Swift/Controllers/Chat/MUCSearchController.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -16,7 +16,7 @@
#include "Swiften/JID/JID.h"
#include "Swift/Controllers/UIEvents/UIEvent.h"
-#include "Swift/Controllers/Settings/SettingsProvider.h"
+#include "Swift/Controllers/ProfileSettingsProvider.h"
#include "Swiften/Elements/DiscoInfo.h"
#include "Swiften/Elements/DiscoItems.h"
#include "Swiften/Elements/ErrorPayload.h"
@@ -87,7 +87,7 @@ namespace Swift {
class MUCSearchController {
public:
- MUCSearchController(const JID& jid, MUCSearchWindowFactory* mucSearchWindowFactory, IQRouter* iqRouter, SettingsProvider* settings);
+ MUCSearchController(const JID& jid, MUCSearchWindowFactory* mucSearchWindowFactory, IQRouter* iqRouter, ProfileSettingsProvider* settings);
~MUCSearchController();
void openSearchWindow();
@@ -112,7 +112,7 @@ namespace Swift {
JID jid_;
MUCSearchWindowFactory* factory_;
IQRouter* iqRouter_;
- SettingsProvider* settings_;
+ ProfileSettingsProvider* settings_;
MUCSearchWindow* window_;
DiscoServiceWalker* walker_;
std::list<JID> services_;
diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
index 40f7445..f8fda9a 100644
--- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -10,6 +10,7 @@
#include "Swift/Controllers/Chat/ChatsManager.h"
+#include "Swift/Controllers/Chat/UnitTest/MockChatListWindow.h"
#include "Swift/Controllers/UIInterfaces/ChatWindow.h"
#include "Swift/Controllers/Settings/DummySettingsProvider.h"
#include "Swift/Controllers/UIInterfaces/ChatWindowFactory.h"
@@ -38,6 +39,7 @@
#include "Swift/Controllers/UIEvents/RequestChatUIEvent.h"
#include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h"
#include "Swift/Controllers/UIEvents/UIEventStream.h"
+#include <Swift/Controllers/ProfileSettingsProvider.h>
using namespace Swift;
@@ -82,8 +84,10 @@ public:
chatListWindowFactory_ = mocks_->InterfaceMock<ChatListWindowFactory>();
mucSearchWindowFactory_ = mocks_->InterfaceMock<MUCSearchWindowFactory>();
settings_ = new DummySettingsProvider();
- mocks_->ExpectCall(chatListWindowFactory_, ChatListWindowFactory::createChatListWindow).With(uiEventStream_).Return(NULL);
- manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, joinMUCWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, NULL, mucRegistry_, entityCapsManager_, mucManager_, mucSearchWindowFactory_, settings_);
+ profileSettings_ = new ProfileSettingsProvider("a", settings_);
+ chatListWindow_ = new MockChatListWindow();
+ mocks_->ExpectCall(chatListWindowFactory_, ChatListWindowFactory::createChatListWindow).With(uiEventStream_).Return(chatListWindow_);
+ manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, joinMUCWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, NULL, mucRegistry_, entityCapsManager_, mucManager_, mucSearchWindowFactory_, profileSettings_);
avatarManager_ = new NullAvatarManager();
manager_->setAvatarManager(avatarManager_);
@@ -92,6 +96,7 @@ public:
void tearDown() {
//delete chatListWindowFactory_;
delete settings_;
+ delete profileSettings_;
delete mocks_;
delete avatarManager_;
delete manager_;
@@ -109,6 +114,7 @@ public:
delete xmppRoster_;
delete entityCapsManager_;
delete capsProvider_;
+ delete chatListWindow_;
}
void testFirstOpenWindowIncoming() {
@@ -346,6 +352,8 @@ private:
CapsProvider* capsProvider_;
MUCManager* mucManager_;
DummySettingsProvider* settings_;
+ ProfileSettingsProvider* profileSettings_;
+ ChatListWindow* chatListWindow_;
};
CPPUNIT_TEST_SUITE_REGISTRATION(ChatsManagerTest);
diff --git a/Swift/Controllers/Chat/UnitTest/MockChatListWindow.h b/Swift/Controllers/Chat/UnitTest/MockChatListWindow.h
new file mode 100644
index 0000000..408a490
--- /dev/null
+++ b/Swift/Controllers/Chat/UnitTest/MockChatListWindow.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include "Swift/Controllers/UIInterfaces/ChatListWindow.h"
+
+namespace Swift {
+
+ class MockChatListWindow : public ChatListWindow {
+ public:
+ MockChatListWindow() {};
+ virtual ~MockChatListWindow() {};
+ void addMUCBookmark(const MUCBookmark& /*bookmark*/) {}
+ void removeMUCBookmark(const MUCBookmark& /*bookmark*/) {}
+ void setBookmarksEnabled(bool /*enabled*/) {}
+ void setRecents(const std::list<ChatListWindow::Chat>& /*recents*/) {}
+ void clearBookmarks() {}
+ };
+
+}
diff --git a/Swift/Controllers/Chat/UserSearchController.cpp b/Swift/Controllers/Chat/UserSearchController.cpp
index b3403d7..deac2f9 100644
--- a/Swift/Controllers/Chat/UserSearchController.cpp
+++ b/Swift/Controllers/Chat/UserSearchController.cpp
@@ -9,9 +9,9 @@
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
+#include <Swiften/Base/foreach.h>
#include <Swiften/Disco/GetDiscoInfoRequest.h>
#include <Swiften/Disco/GetDiscoItemsRequest.h>
-
#include <Swift/Controllers/DiscoServiceWalker.h>
#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/UIEvents/RequestChatWithUserDialogUIEvent.h>
diff --git a/Swift/Controllers/ChatMessageSummarizer.cpp b/Swift/Controllers/ChatMessageSummarizer.cpp
new file mode 100644
index 0000000..682d88b
--- /dev/null
+++ b/Swift/Controllers/ChatMessageSummarizer.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swift/Controllers/ChatMessageSummarizer.h>
+
+#include <Swiften/Base/format.h>
+#include <Swift/Controllers/Intl.h>
+#include <Swiften/Base/foreach.h>
+
+using namespace Swift;
+using namespace std;
+
+string ChatMessageSummarizer::getSummary(const string& current, const vector<UnreadPair>& unreads) {
+ vector<UnreadPair> others;
+ int currentUnread = 0;
+ int otherCount = 0;
+ foreach (UnreadPair unread, unreads) {
+ if (unread.first == current) {
+ currentUnread += unread.second;
+ } else {
+ if (unread.second > 0) {
+ otherCount += unread.second;
+ others.push_back(unread);
+ }
+ }
+ }
+ string myString(current);
+
+ if (currentUnread > 0) {
+ string result(QT_TRANSLATE_NOOP("", "%1% (%2%)"));
+ myString = str(format(result) % current % currentUnread);
+ }
+
+ if (others.size() > 1) {
+ string result(QT_TRANSLATE_NOOP("", "%1% and %2% others (%3%)"));
+ myString = str(format(result) % myString % others.size() % otherCount);
+ } else if (others.size() > 0) {
+ string result(QT_TRANSLATE_NOOP("", "%1%, %2% (%3%)"));
+ myString = str(format(result) % myString % others[0].first % otherCount);
+ }
+ return myString;
+}
diff --git a/Swift/Controllers/ChatMessageSummarizer.h b/Swift/Controllers/ChatMessageSummarizer.h
new file mode 100644
index 0000000..d4ff188
--- /dev/null
+++ b/Swift/Controllers/ChatMessageSummarizer.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <vector>
+#include <utility>
+#include <string>
+
+namespace Swift {
+typedef std::pair<std::string, int> UnreadPair;
+
+ class ChatMessageSummarizer {
+ public:
+ std::string getSummary(const std::string& current, const std::vector<UnreadPair>& unreads);
+ };
+}
diff --git a/Swift/Controllers/DiscoServiceWalker.cpp b/Swift/Controllers/DiscoServiceWalker.cpp
index ce29927..6aed6eb 100644
--- a/Swift/Controllers/DiscoServiceWalker.cpp
+++ b/Swift/Controllers/DiscoServiceWalker.cpp
@@ -6,6 +6,7 @@
#include <Swift/Controllers/DiscoServiceWalker.h>
#include <Swiften/Base/Log.h>
+#include <Swiften/Base/foreach.h>
#include <boost/bind.hpp>
diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp
index 9a35cc1..c00c080 100644
--- a/Swift/Controllers/MainController.cpp
+++ b/Swift/Controllers/MainController.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -18,10 +18,8 @@
#include <Swift/Controllers/UIInterfaces/UIFactory.h>
#include "Swiften/Network/TimerFactory.h"
#include "Swift/Controllers/BuildVersion.h"
-#include "Swift/Controllers/StoragesFactory.h"
#include "Swiften/Client/Storages.h"
#include "Swiften/VCards/VCardManager.h"
-#include "Swift/Controllers/Chat/MUCSearchController.h"
#include "Swift/Controllers/Chat/UserSearchController.h"
#include "Swift/Controllers/Chat/ChatsManager.h"
#include "Swift/Controllers/XMPPEvents/EventController.h"
@@ -41,6 +39,7 @@
#include "Swift/Controllers/UIEvents/UIEventStream.h"
#include "Swift/Controllers/PresenceNotifier.h"
#include "Swift/Controllers/EventNotifier.h"
+#include "Swift/Controllers/Storages/StoragesFactory.h"
#include "SwifTools/Dock/Dock.h"
#include "SwifTools/Notifier/TogglableNotifier.h"
#include "Swiften/Base/foreach.h"
@@ -60,11 +59,13 @@
#include "Swift/Controllers/UIEvents/RequestChatUIEvent.h"
#include "Swift/Controllers/UIEvents/ToggleNotificationsUIEvent.h"
#include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h"
-#include "Swift/Controllers/CertificateStorageFactory.h"
-#include "Swift/Controllers/CertificateStorageTrustChecker.h"
+#include "Swift/Controllers/Storages/CertificateStorageFactory.h"
+#include "Swift/Controllers/Storages/CertificateStorageTrustChecker.h"
#include "Swiften/Network/NetworkFactories.h"
#include <Swift/Controllers/ProfileController.h>
#include <Swift/Controllers/ContactEditController.h>
+#include <Swift/Controllers/XMPPURIController.h>
+#include "Swift/Controllers/AdHocManager.h"
namespace Swift {
@@ -84,6 +85,7 @@ MainController::MainController(
CertificateStorageFactory* certificateStorageFactory,
Dock* dock,
Notifier* notifier,
+ URIHandler* uriHandler,
bool useDelayForLatency) :
eventLoop_(eventLoop),
networkFactories_(networkFactories),
@@ -92,6 +94,7 @@ MainController::MainController(
storagesFactory_(storagesFactory),
certificateStorageFactory_(certificateStorageFactory),
settings_(settings),
+ uriHandler_(uriHandler),
loginWindow_(NULL) ,
useDelayForLatency_(useDelayForLatency) {
storages_ = NULL;
@@ -121,6 +124,8 @@ MainController::MainController(
loginWindow_ = uiFactory_->createLoginWindow(uiEventStream_);
soundEventController_ = new SoundEventController(eventController_, soundPlayer, settings, uiEventStream_);
+ xmppURIController_ = new XMPPURIController(uriHandler_, uiEventStream_);
+
std::string selectedLoginJID = settings_->getStringSetting("lastLoginJID");
bool loginAutomatically = settings_->getBoolSetting("loginAutomatically", false);
std::string cachedPassword;
@@ -167,6 +172,7 @@ MainController::~MainController() {
resetClient();
delete xmlConsoleController_;
+ delete xmppURIController_;
delete soundEventController_;
delete systemTrayController_;
delete eventController_;
@@ -247,7 +253,7 @@ void MainController::handleConnected() {
contactEditController_ = new ContactEditController(rosterController_, uiFactory_, uiEventStream_);
- chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, settings_);
+ chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_);
client_->onMessageReceived.connect(boost::bind(&ChatsManager::handleIncomingMessage, chatsManager_, _1));
chatsManager_->setAvatarManager(client_->getAvatarManager());
@@ -262,14 +268,14 @@ void MainController::handleConnected() {
client_->getDiscoManager()->setCapsNode(CLIENT_NODE);
client_->getDiscoManager()->setDiscoInfo(discoInfo);
-
userSearchControllerChat_ = new UserSearchController(UserSearchController::StartChat, jid_, uiEventStream_, uiFactory_, client_->getIQRouter(), rosterController_);
userSearchControllerAdd_ = new UserSearchController(UserSearchController::AddContact, jid_, uiEventStream_, uiFactory_, client_->getIQRouter(), rosterController_);
+ adHocManager_ = new AdHocManager(boundJID_, uiFactory_, client_->getIQRouter(), uiEventStream_, rosterController_->getWindow());
}
client_->requestRoster();
- GetDiscoInfoRequest::ref discoInfoRequest = GetDiscoInfoRequest::create(JID(), client_->getIQRouter());
+ GetDiscoInfoRequest::ref discoInfoRequest = GetDiscoInfoRequest::create(boundJID_.toBare(), client_->getIQRouter());
discoInfoRequest->onResponse.connect(boost::bind(&MainController::handleServerDiscoInfoResponse, this, _1, _2));
discoInfoRequest->send();
@@ -356,19 +362,25 @@ void MainController::handleInputIdleChanged(bool idle) {
}
void MainController::handleLoginRequest(const std::string &username, const std::string &password, const std::string& certificateFile, bool remember, bool loginAutomatically) {
- loginWindow_->setMessage("");
- loginWindow_->setIsLoggingIn(true);
- profileSettings_ = new ProfileSettingsProvider(username, settings_);
- profileSettings_->storeString("jid", username);
- profileSettings_->storeString("certificate", certificateFile);
- profileSettings_->storeString("pass", (remember || loginAutomatically) ? password : "");
- settings_->storeString("lastLoginJID", username);
- settings_->storeBool("loginAutomatically", loginAutomatically);
- loginWindow_->addAvailableAccount(profileSettings_->getStringSetting("jid"), profileSettings_->getStringSetting("pass"), profileSettings_->getStringSetting("certificate"));
jid_ = JID(username);
- password_ = password;
- certificateFile_ = certificateFile;
- performLoginFromCachedCredentials();
+ if (!jid_.isValid() || jid_.getNode().empty()) {
+ loginWindow_->setMessage(QT_TRANSLATE_NOOP("", "User address invalid. User address should be of the form 'alice@wonderland.lit'"));
+ loginWindow_->setIsLoggingIn(false);
+ } else {
+ loginWindow_->setMessage("");
+ loginWindow_->setIsLoggingIn(true);
+ profileSettings_ = new ProfileSettingsProvider(username, settings_);
+ profileSettings_->storeString("jid", username);
+ profileSettings_->storeString("certificate", certificateFile);
+ profileSettings_->storeString("pass", (remember || loginAutomatically) ? password : "");
+ settings_->storeString("lastLoginJID", username);
+ settings_->storeBool("loginAutomatically", loginAutomatically);
+ loginWindow_->addAvailableAccount(profileSettings_->getStringSetting("jid"), profileSettings_->getStringSetting("pass"), profileSettings_->getStringSetting("certificate"));
+
+ password_ = password;
+ certificateFile_ = certificateFile;
+ performLoginFromCachedCredentials();
+ }
}
void MainController::handlePurgeSavedLoginRequest(const std::string& username) {
@@ -483,6 +495,7 @@ void MainController::handleDisconnected(const boost::optional<ClientError>& erro
else if (!rosterController_) { //hasn't been logged in yet
signOut();
loginWindow_->setMessage(message);
+ loginWindow_->setIsLoggingIn(false);
} else {
logout();
setReconnectTimer();
@@ -496,6 +509,9 @@ void MainController::handleDisconnected(const boost::optional<ClientError>& erro
eventController_->handleIncomingEvent(lastDisconnectError_);
}
}
+ else if (!rosterController_) { //hasn't been logged in yet
+ loginWindow_->setIsLoggingIn(false);
+ }
}
void MainController::setReconnectTimer() {
@@ -554,6 +570,7 @@ void MainController::setManagersOffline() {
void MainController::handleServerDiscoInfoResponse(boost::shared_ptr<DiscoInfo> info, ErrorPayload::ref error) {
if (!error) {
chatsManager_->setServerDiscoInfo(info);
+ adHocManager_->setServerDiscoInfo(info);
}
}
diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h
index f402f8f..757abb8 100644
--- a/Swift/Controllers/MainController.h
+++ b/Swift/Controllers/MainController.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -62,6 +62,10 @@ namespace Swift {
class Storages;
class StoragesFactory;
class NetworkFactories;
+ class URIHandler;
+ class XMPPURIController;
+ class AdHocManager;
+ class AdHocCommandWindowFactory;
class MainController {
public:
@@ -76,6 +80,7 @@ namespace Swift {
CertificateStorageFactory* certificateStorageFactory,
Dock* dock,
Notifier* notifier,
+ URIHandler* uriHandler,
bool useDelayForLatency);
~MainController();
@@ -123,12 +128,14 @@ namespace Swift {
SettingsProvider *settings_;
ProfileSettingsProvider* profileSettings_;
Dock* dock_;
+ URIHandler* uriHandler_;
TogglableNotifier* notifier_;
PresenceNotifier* presenceNotifier_;
EventNotifier* eventNotifier_;
RosterController* rosterController_;
EventController* eventController_;
EventWindowController* eventWindowController_;
+ AdHocManager* adHocManager_;
LoginWindow* loginWindow_;
UIEventStream* uiEventStream_;
XMLConsoleController* xmlConsoleController_;
@@ -139,6 +146,7 @@ namespace Swift {
JID boundJID_;
SystemTrayController* systemTrayController_;
SoundEventController* soundEventController_;
+ XMPPURIController* xmppURIController_;
std::string vCardPhotoHash_;
std::string password_;
std::string certificateFile_;
diff --git a/Swift/Controllers/ProfileSettingsProvider.h b/Swift/Controllers/ProfileSettingsProvider.h
index 74bcd12..8ba250c 100644
--- a/Swift/Controllers/ProfileSettingsProvider.h
+++ b/Swift/Controllers/ProfileSettingsProvider.h
@@ -7,6 +7,7 @@
#pragma once
#include "Swift/Controllers/Settings/SettingsProvider.h"
+#include <Swiften/Base/foreach.h>
namespace Swift {
diff --git a/Swift/Controllers/Roster/ContactRosterItem.cpp b/Swift/Controllers/Roster/ContactRosterItem.cpp
index 0fe88aa..894f64b 100644
--- a/Swift/Controllers/Roster/ContactRosterItem.cpp
+++ b/Swift/Controllers/Roster/ContactRosterItem.cpp
@@ -7,6 +7,8 @@
#include "Swift/Controllers/Roster/ContactRosterItem.h"
#include "Swift/Controllers/Roster/GroupRosterItem.h"
+#include <Swiften/Base/foreach.h>
+
namespace Swift {
diff --git a/Swift/Controllers/Roster/GroupRosterItem.cpp b/Swift/Controllers/Roster/GroupRosterItem.cpp
index f0a377a..2b56d1f 100644
--- a/Swift/Controllers/Roster/GroupRosterItem.cpp
+++ b/Swift/Controllers/Roster/GroupRosterItem.cpp
@@ -12,7 +12,7 @@
namespace Swift {
-GroupRosterItem::GroupRosterItem(const std::string& name, GroupRosterItem* parent, bool sortByStatus) : RosterItem(name, parent), sortByStatus_(sortByStatus) {
+GroupRosterItem::GroupRosterItem(const std::string& name, GroupRosterItem* parent, bool sortByStatus) : RosterItem(name, parent), sortByStatus_(sortByStatus), manualSort_(false) {
expanded_ = true;
}
@@ -20,6 +20,20 @@ GroupRosterItem::~GroupRosterItem() {
}
+void GroupRosterItem::setManualSort(const std::string& manualSortValue) {
+ manualSort_ = true;
+ bool changed = manualSortValue_ != manualSortValue;
+ manualSortValue_ = manualSortValue;
+ if (changed) {
+ onChildrenChanged();
+ onDataChanged();
+ }
+}
+
+const std::string& GroupRosterItem::getSortableDisplayName() const {
+ return manualSort_ ? manualSortValue_ : RosterItem::getSortableDisplayName();
+}
+
bool GroupRosterItem::isExpanded() const {
return expanded_;
}
@@ -210,7 +224,8 @@ void GroupRosterItem::handleChildrenChanged(GroupRosterItem* group) {
} else {
displayedChildren_.erase(std::remove(displayedChildren_.begin(), displayedChildren_.end(), group), displayedChildren_.end());
}
- if (oldSize != getDisplayedChildren().size()) {
+
+ if (oldSize != getDisplayedChildren().size() || sortDisplayed()) {
onChildrenChanged();
onDataChanged();
}
diff --git a/Swift/Controllers/Roster/GroupRosterItem.h b/Swift/Controllers/Roster/GroupRosterItem.h
index 57fa9fa..beb7705 100644
--- a/Swift/Controllers/Roster/GroupRosterItem.h
+++ b/Swift/Controllers/Roster/GroupRosterItem.h
@@ -31,6 +31,8 @@ class GroupRosterItem : public RosterItem {
void setExpanded(bool expanded);
bool isExpanded() const;
boost::signal<void (bool)> onExpandedChanged;
+ void setManualSort(const std::string& manualSortValue);
+ virtual const std::string& getSortableDisplayName() const;
private:
void handleChildrenChanged(GroupRosterItem* group);
void handleDataChanged(RosterItem* item);
@@ -40,6 +42,8 @@ class GroupRosterItem : public RosterItem {
std::vector<RosterItem*> children_;
std::vector<RosterItem*> displayedChildren_;
bool sortByStatus_;
+ bool manualSort_;
+ std::string manualSortValue_;
};
}
diff --git a/Swift/Controllers/Roster/RosterGroupExpandinessPersister.cpp b/Swift/Controllers/Roster/RosterGroupExpandinessPersister.cpp
index c1045ee..0a242ae 100644
--- a/Swift/Controllers/Roster/RosterGroupExpandinessPersister.cpp
+++ b/Swift/Controllers/Roster/RosterGroupExpandinessPersister.cpp
@@ -9,6 +9,7 @@
#include <boost/bind.hpp>
#include <vector>
+#include <Swiften/Base/foreach.h>
#include "Swiften/Base/String.h"
#include "Swift/Controllers/Roster/GroupRosterItem.h"
diff --git a/Swift/Controllers/Roster/RosterItem.cpp b/Swift/Controllers/Roster/RosterItem.cpp
index 3f130bb..77db8a3 100644
--- a/Swift/Controllers/Roster/RosterItem.cpp
+++ b/Swift/Controllers/Roster/RosterItem.cpp
@@ -33,11 +33,11 @@ void RosterItem::setDisplayName(const std::string& name) {
onDataChanged();
}
-std::string RosterItem::getDisplayName() const {
+const std::string& RosterItem::getDisplayName() const {
return name_;
}
-std::string RosterItem::getSortableDisplayName() const {
+const std::string& RosterItem::getSortableDisplayName() const {
return sortableDisplayName_;
}
diff --git a/Swift/Controllers/Roster/RosterItem.h b/Swift/Controllers/Roster/RosterItem.h
index ed8cb16..769f72d 100644
--- a/Swift/Controllers/Roster/RosterItem.h
+++ b/Swift/Controllers/Roster/RosterItem.h
@@ -20,8 +20,8 @@ class RosterItem {
boost::signal<void ()> onDataChanged;
GroupRosterItem* getParent() const;
void setDisplayName(const std::string& name);
- std::string getDisplayName() const;
- std::string getSortableDisplayName() const;
+ const std::string& getDisplayName() const;
+ virtual const std::string& getSortableDisplayName() const;
private:
std::string name_;
std::string sortableDisplayName_;
diff --git a/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp b/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp
index 16f2745..ca74dbb 100644
--- a/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp
+++ b/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp
@@ -8,6 +8,7 @@
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <Swiften/Base/foreach.h>
#include "Swift/Controllers/Roster/RosterController.h"
#include "Swift/Controllers/UnitTest/MockMainWindowFactory.h"
// #include "Swiften/Elements/Payload.h"
diff --git a/Swift/Controllers/Roster/UnitTest/RosterTest.cpp b/Swift/Controllers/Roster/UnitTest/RosterTest.cpp
index cbef787..4444e8a 100644
--- a/Swift/Controllers/Roster/UnitTest/RosterTest.cpp
+++ b/Swift/Controllers/Roster/UnitTest/RosterTest.cpp
@@ -21,6 +21,7 @@ class RosterTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testRemoveSecondContact);
CPPUNIT_TEST(testRemoveSecondContactSameBare);
CPPUNIT_TEST(testApplyPresenceLikeMUC);
+ CPPUNIT_TEST(testReSortLikeMUC);
CPPUNIT_TEST_SUITE_END();
public:
@@ -117,6 +118,22 @@ class RosterTest : public CppUnit::TestFixture {
}
+ void testReSortLikeMUC() {
+ JID jid4a("a@b/c");
+ JID jid4b("a@b/d");
+ JID jid4c("a@b/e");
+ roster_->addContact(jid4a, JID(), "Bird", "group1", "");
+ roster_->addContact(jid4b, JID(), "Cookie", "group2", "");
+ roster_->addContact(jid4b, JID(), "Ernie", "group1", "");
+ roster_->getGroup("group1")->setManualSort("2");
+ roster_->getGroup("group2")->setManualSort("1");
+ GroupRosterItem* root = roster_->getRoot();
+ const std::vector<RosterItem*> kids = root->getDisplayedChildren();
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), kids.size());
+ CPPUNIT_ASSERT_EQUAL(std::string("group2"), kids[0]->getDisplayName());
+ CPPUNIT_ASSERT_EQUAL(std::string("group1"), kids[1]->getDisplayName());
+ }
+
private:
Roster *roster_;
JID jid1_;
diff --git a/Swift/Controllers/SConscript b/Swift/Controllers/SConscript
index 61da9fb..eed1f4d 100644
--- a/Swift/Controllers/SConscript
+++ b/Swift/Controllers/SConscript
@@ -44,16 +44,25 @@ if env["SCONS_STAGE"] == "build" :
"StatusTracker.cpp",
"PresenceNotifier.cpp",
"EventNotifier.cpp",
+ "AdHocManager.cpp",
"XMPPEvents/EventController.cpp",
"UIEvents/UIEvent.cpp",
"UIInterfaces/XMLConsoleWidget.cpp",
"UIInterfaces/ChatListWindow.cpp",
"PreviousStatusStore.cpp",
- "CertificateStorageFactory.cpp",
- "CertificateStorage.cpp",
- "CertificateFileStorage.cpp",
+ "Storages/CertificateStorageFactory.cpp",
+ "Storages/CertificateStorage.cpp",
+ "Storages/CertificateFileStorage.cpp",
+ "Storages/CertificateMemoryStorage.cpp",
+ "Storages/AvatarFileStorage.cpp",
+ "Storages/FileStorages.cpp",
+ "Storages/RosterFileStorage.cpp",
+ "Storages/CapsFileStorage.cpp",
+ "Storages/VCardFileStorage.cpp",
"StatusUtil.cpp",
"Translator.cpp",
+ "XMPPURIController.cpp",
+ "ChatMessageSummarizer.cpp",
])
env.Append(UNITTEST_SOURCES = [
@@ -64,4 +73,5 @@ if env["SCONS_STAGE"] == "build" :
File("Chat/UnitTest/ChatsManagerTest.cpp"),
File("Chat/UnitTest/MUCControllerTest.cpp"),
File("UnitTest/MockChatWindow.cpp"),
+ File("UnitTest/ChatMessageSummarizerTest.cpp"),
])
diff --git a/Swiften/Avatars/AvatarFileStorage.cpp b/Swift/Controllers/Storages/AvatarFileStorage.cpp
index 4f76c80..288f6fd 100644
--- a/Swiften/Avatars/AvatarFileStorage.cpp
+++ b/Swift/Controllers/Storages/AvatarFileStorage.cpp
@@ -4,10 +4,11 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#include <Swiften/Avatars/AvatarFileStorage.h>
+#include <Swift/Controllers/Storages/AvatarFileStorage.h>
#include <iostream>
#include <boost/filesystem/fstream.hpp>
+#include <boost/filesystem.hpp>
#include <Swiften/Base/foreach.h>
#include <Swiften/Base/String.h>
@@ -58,7 +59,7 @@ void AvatarFileStorage::addAvatar(const std::string& hash, const ByteArray& avat
}
}
boost::filesystem::ofstream file(avatarPath, boost::filesystem::ofstream::binary|boost::filesystem::ofstream::out);
- file.write(reinterpret_cast<const char*>(avatar.getData()), avatar.getSize());
+ file.write(reinterpret_cast<const char*>(avatar.getData()), static_cast<std::streamsize>(avatar.getSize()));
file.close();
}
diff --git a/Swiften/Avatars/AvatarFileStorage.h b/Swift/Controllers/Storages/AvatarFileStorage.h
index e736230..b7e73f5 100644
--- a/Swiften/Avatars/AvatarFileStorage.h
+++ b/Swift/Controllers/Storages/AvatarFileStorage.h
@@ -8,7 +8,7 @@
#include <map>
#include <string>
-#include <boost/filesystem.hpp>
+#include <boost/filesystem/path.hpp>
#include <Swiften/JID/JID.h>
#include "Swiften/Base/ByteArray.h"
diff --git a/Swift/Controllers/Storages/CapsFileStorage.cpp b/Swift/Controllers/Storages/CapsFileStorage.cpp
new file mode 100644
index 0000000..b7593fd
--- /dev/null
+++ b/Swift/Controllers/Storages/CapsFileStorage.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include "Swift/Controllers/Storages/CapsFileStorage.h"
+
+#include <Swiften/Entity/GenericPayloadPersister.h>
+#include "Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.h"
+#include "Swiften/Parser/PayloadParsers/DiscoInfoParser.h"
+#include "Swiften/StringCodecs/Hexify.h"
+#include "Swiften/StringCodecs/Base64.h"
+
+using namespace Swift;
+
+typedef GenericPayloadPersister<DiscoInfo, DiscoInfoParser, DiscoInfoSerializer> DiscoInfoPersister;
+
+CapsFileStorage::CapsFileStorage(const boost::filesystem::path& path) : path(path) {
+}
+
+DiscoInfo::ref CapsFileStorage::getDiscoInfo(const std::string& hash) const {
+ return DiscoInfoPersister().loadPayloadGeneric(getCapsPath(hash));
+}
+
+void CapsFileStorage::setDiscoInfo(const std::string& hash, DiscoInfo::ref discoInfo) {
+ DiscoInfo::ref bareDiscoInfo(new DiscoInfo(*discoInfo.get()));
+ bareDiscoInfo->setNode("");
+ DiscoInfoPersister().savePayload(bareDiscoInfo, getCapsPath(hash));
+}
+
+boost::filesystem::path CapsFileStorage::getCapsPath(const std::string& hash) const {
+ return path / (Hexify::hexify(Base64::decode(hash)) + ".xml");
+}
diff --git a/Swiften/Disco/CapsFileStorage.h b/Swift/Controllers/Storages/CapsFileStorage.h
index 5faf08b..b3757e0 100644
--- a/Swiften/Disco/CapsFileStorage.h
+++ b/Swift/Controllers/Storages/CapsFileStorage.h
@@ -6,7 +6,7 @@
#pragma once
-#include <boost/filesystem.hpp>
+#include <boost/filesystem/path.hpp>
#include "Swiften/Disco/CapsStorage.h"
#include <string>
diff --git a/Swift/Controllers/CertificateFileStorage.cpp b/Swift/Controllers/Storages/CertificateFileStorage.cpp
index cf924ee..31af949 100644
--- a/Swift/Controllers/CertificateFileStorage.cpp
+++ b/Swift/Controllers/Storages/CertificateFileStorage.cpp
@@ -4,7 +4,7 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#include <Swift/Controllers/CertificateFileStorage.h>
+#include <Swift/Controllers/Storages/CertificateFileStorage.h>
#include <iostream>
#include <boost/filesystem/fstream.hpp>
diff --git a/Swift/Controllers/CertificateFileStorage.h b/Swift/Controllers/Storages/CertificateFileStorage.h
index 2b853ed..f7a60b9 100644
--- a/Swift/Controllers/CertificateFileStorage.h
+++ b/Swift/Controllers/Storages/CertificateFileStorage.h
@@ -8,7 +8,7 @@
#include <boost/filesystem.hpp>
-#include "Swift/Controllers/CertificateStorage.h"
+#include "Swift/Controllers/Storages/CertificateStorage.h"
namespace Swift {
class CertificateFactory;
diff --git a/Swift/Controllers/CertificateFileStorageFactory.h b/Swift/Controllers/Storages/CertificateFileStorageFactory.h
index 7ed8287..b215165 100644
--- a/Swift/Controllers/CertificateFileStorageFactory.h
+++ b/Swift/Controllers/Storages/CertificateFileStorageFactory.h
@@ -6,8 +6,8 @@
#pragma once
-#include <Swift/Controllers/CertificateStorageFactory.h>
-#include <Swift/Controllers/CertificateFileStorage.h>
+#include <Swift/Controllers/Storages/CertificateStorageFactory.h>
+#include <Swift/Controllers/Storages/CertificateFileStorage.h>
namespace Swift {
class CertificateFactory;
diff --git a/Swift/Controllers/Storages/CertificateMemoryStorage.cpp b/Swift/Controllers/Storages/CertificateMemoryStorage.cpp
new file mode 100644
index 0000000..71d7c4a
--- /dev/null
+++ b/Swift/Controllers/Storages/CertificateMemoryStorage.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swift/Controllers/Storages/CertificateMemoryStorage.h>
+
+#include <Swiften/Base/foreach.h>
+
+using namespace Swift;
+
+CertificateMemoryStorage::CertificateMemoryStorage() {
+}
+
+bool CertificateMemoryStorage::hasCertificate(Certificate::ref certificate) const {
+ foreach(Certificate::ref storedCert, certificates) {
+ if (storedCert->toDER() == certificate->toDER()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void CertificateMemoryStorage::addCertificate(Certificate::ref certificate) {
+ certificates.push_back(certificate);
+}
diff --git a/Swift/Controllers/Storages/CertificateMemoryStorage.h b/Swift/Controllers/Storages/CertificateMemoryStorage.h
new file mode 100644
index 0000000..5c0333d
--- /dev/null
+++ b/Swift/Controllers/Storages/CertificateMemoryStorage.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include <Swift/Controllers/Storages/CertificateStorage.h>
+
+namespace Swift {
+ class CertificateMemoryStorage : public CertificateStorage {
+ public:
+ CertificateMemoryStorage();
+
+ virtual bool hasCertificate(Certificate::ref certificate) const;
+ virtual void addCertificate(Certificate::ref certificate);
+
+ private:
+ std::vector<Certificate::ref> certificates;
+ };
+
+}
diff --git a/Swift/Controllers/CertificateStorage.cpp b/Swift/Controllers/Storages/CertificateStorage.cpp
index 343fccd..ee942c0 100644
--- a/Swift/Controllers/CertificateStorage.cpp
+++ b/Swift/Controllers/Storages/CertificateStorage.cpp
@@ -4,7 +4,7 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#include "Swift/Controllers/CertificateStorage.h"
+#include "Swift/Controllers/Storages/CertificateStorage.h"
namespace Swift {
diff --git a/Swift/Controllers/CertificateStorage.h b/Swift/Controllers/Storages/CertificateStorage.h
index f8c6fb5..f8c6fb5 100644
--- a/Swift/Controllers/CertificateStorage.h
+++ b/Swift/Controllers/Storages/CertificateStorage.h
diff --git a/Swift/Controllers/CertificateStorageFactory.cpp b/Swift/Controllers/Storages/CertificateStorageFactory.cpp
index 613a8c3..ba0179a 100644
--- a/Swift/Controllers/CertificateStorageFactory.cpp
+++ b/Swift/Controllers/Storages/CertificateStorageFactory.cpp
@@ -4,7 +4,7 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#include <Swift/Controllers/CertificateStorageFactory.h>
+#include <Swift/Controllers/Storages/CertificateStorageFactory.h>
namespace Swift {
diff --git a/Swift/Controllers/CertificateStorageFactory.h b/Swift/Controllers/Storages/CertificateStorageFactory.h
index 5b85757..5b85757 100644
--- a/Swift/Controllers/CertificateStorageFactory.h
+++ b/Swift/Controllers/Storages/CertificateStorageFactory.h
diff --git a/Swift/Controllers/CertificateStorageTrustChecker.h b/Swift/Controllers/Storages/CertificateStorageTrustChecker.h
index f33287c..40838dd 100644
--- a/Swift/Controllers/CertificateStorageTrustChecker.h
+++ b/Swift/Controllers/Storages/CertificateStorageTrustChecker.h
@@ -7,7 +7,7 @@
#pragma once
#include <Swiften/TLS/CertificateTrustChecker.h>
-#include <Swift/Controllers/CertificateStorage.h>
+#include <Swift/Controllers/Storages/CertificateStorage.h>
namespace Swift {
/**
diff --git a/Swiften/Client/FileStorages.cpp b/Swift/Controllers/Storages/FileStorages.cpp
index 3c76c46..6447099 100644
--- a/Swiften/Client/FileStorages.cpp
+++ b/Swift/Controllers/Storages/FileStorages.cpp
@@ -4,10 +4,11 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#include "Swiften/Client/FileStorages.h"
-#include "Swiften/VCards/VCardFileStorage.h"
-#include "Swiften/Avatars/AvatarFileStorage.h"
-#include "Swiften/Disco/CapsFileStorage.h"
+#include "Swift/Controllers/Storages/FileStorages.h"
+#include "Swift/Controllers/Storages/VCardFileStorage.h"
+#include "Swift/Controllers/Storages/AvatarFileStorage.h"
+#include "Swift/Controllers/Storages/CapsFileStorage.h"
+#include "Swift/Controllers/Storages/RosterFileStorage.h"
namespace Swift {
@@ -16,9 +17,11 @@ FileStorages::FileStorages(const boost::filesystem::path& baseDir, const JID& ji
vcardStorage = new VCardFileStorage(baseDir / profile / "vcards");
capsStorage = new CapsFileStorage(baseDir / "caps");
avatarStorage = new AvatarFileStorage(baseDir / "avatars", baseDir / profile / "avatars");
+ rosterStorage = new RosterFileStorage(baseDir / profile / "roster.xml");
}
FileStorages::~FileStorages() {
+ delete rosterStorage;
delete avatarStorage;
delete capsStorage;
delete vcardStorage;
@@ -36,4 +39,8 @@ AvatarStorage* FileStorages::getAvatarStorage() const {
return avatarStorage;
}
+RosterStorage* FileStorages::getRosterStorage() const {
+ return rosterStorage;
+}
+
}
diff --git a/Swiften/Client/FileStorages.h b/Swift/Controllers/Storages/FileStorages.h
index 451105f..28df314 100644
--- a/Swiften/Client/FileStorages.h
+++ b/Swift/Controllers/Storages/FileStorages.h
@@ -6,7 +6,7 @@
#pragma once
-#include <boost/filesystem.hpp>
+#include <boost/filesystem/path.hpp>
#include "Swiften/Client/Storages.h"
@@ -14,6 +14,7 @@ namespace Swift {
class VCardFileStorage;
class AvatarFileStorage;
class CapsFileStorage;
+ class RosterFileStorage;
class JID;
/**
@@ -41,10 +42,12 @@ namespace Swift {
virtual VCardStorage* getVCardStorage() const;
virtual AvatarStorage* getAvatarStorage() const;
virtual CapsStorage* getCapsStorage() const;
+ virtual RosterStorage* getRosterStorage() const;
private:
VCardFileStorage* vcardStorage;
AvatarFileStorage* avatarStorage;
CapsFileStorage* capsStorage;
+ RosterFileStorage* rosterStorage;
};
}
diff --git a/Swift/Controllers/FileStoragesFactory.h b/Swift/Controllers/Storages/FileStoragesFactory.h
index bd7cdfb..0676bc3 100644
--- a/Swift/Controllers/FileStoragesFactory.h
+++ b/Swift/Controllers/Storages/FileStoragesFactory.h
@@ -6,8 +6,8 @@
#pragma once
-#include "Swift/Controllers/StoragesFactory.h"
-#include "Swiften/Client/FileStorages.h"
+#include "Swift/Controllers/Storages/StoragesFactory.h"
+#include "Swift/Controllers/Storages/FileStorages.h"
namespace Swift {
class FileStoragesFactory : public StoragesFactory {
diff --git a/Swift/Controllers/MemoryStoragesFactory.h b/Swift/Controllers/Storages/MemoryStoragesFactory.h
index 8408e10..0dea349 100644
--- a/Swift/Controllers/MemoryStoragesFactory.h
+++ b/Swift/Controllers/Storages/MemoryStoragesFactory.h
@@ -6,10 +6,12 @@
#pragma once
-#include "Swift/Controllers/StoragesFactory.h"
+#include "Swift/Controllers/Storages/StoragesFactory.h"
#include "Swiften/Client/MemoryStorages.h"
namespace Swift {
+ class JID;
+
class MemoryStoragesFactory : public StoragesFactory {
public:
MemoryStoragesFactory() {}
diff --git a/Swift/Controllers/Storages/RosterFileStorage.cpp b/Swift/Controllers/Storages/RosterFileStorage.cpp
new file mode 100644
index 0000000..73e582f
--- /dev/null
+++ b/Swift/Controllers/Storages/RosterFileStorage.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swift/Controllers/Storages/RosterFileStorage.h>
+
+#include <Swiften/Entity/GenericPayloadPersister.h>
+#include <Swiften/Serializer/PayloadSerializers/RosterSerializer.h>
+#include <Swiften/Parser/PayloadParsers/RosterParser.h>
+
+using namespace Swift;
+
+typedef GenericPayloadPersister<RosterPayload, RosterParser, RosterSerializer> RosterPersister;
+
+RosterFileStorage::RosterFileStorage(const boost::filesystem::path& path) : path(path) {
+}
+
+boost::shared_ptr<RosterPayload> RosterFileStorage::getRoster() const {
+ return RosterPersister().loadPayloadGeneric(path);
+}
+
+void RosterFileStorage::setRoster(boost::shared_ptr<RosterPayload> roster) {
+ RosterPersister().savePayload(roster, path);
+}
diff --git a/Swift/Controllers/Storages/RosterFileStorage.h b/Swift/Controllers/Storages/RosterFileStorage.h
new file mode 100644
index 0000000..cb00969
--- /dev/null
+++ b/Swift/Controllers/Storages/RosterFileStorage.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/filesystem/path.hpp>
+
+#include <Swiften/Roster/RosterStorage.h>
+
+namespace Swift {
+ class RosterFileStorage : public RosterStorage {
+ public:
+ RosterFileStorage(const boost::filesystem::path& path);
+
+ virtual boost::shared_ptr<RosterPayload> getRoster() const;
+ virtual void setRoster(boost::shared_ptr<RosterPayload>);
+
+ private:
+ boost::filesystem::path path;
+ };
+}
diff --git a/Swift/Controllers/StoragesFactory.h b/Swift/Controllers/Storages/StoragesFactory.h
index 441a4e9..203f9c9 100644
--- a/Swift/Controllers/StoragesFactory.h
+++ b/Swift/Controllers/Storages/StoragesFactory.h
@@ -8,6 +8,7 @@
namespace Swift {
class Storages;
+ class JID;
class StoragesFactory {
public:
diff --git a/Swiften/VCards/VCardFileStorage.cpp b/Swift/Controllers/Storages/VCardFileStorage.cpp
index a246838..4933d0c 100644
--- a/Swiften/VCards/VCardFileStorage.cpp
+++ b/Swift/Controllers/Storages/VCardFileStorage.cpp
@@ -4,22 +4,26 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#include "Swiften/VCards/VCardFileStorage.h"
+#include "Swift/Controllers/Storages/VCardFileStorage.h"
#include <boost/filesystem/fstream.hpp>
+#include <boost/filesystem.hpp>
+#include <iostream>
+#include <Swiften/Entity/GenericPayloadPersister.h>
#include <Swiften/Base/String.h>
#include <Swiften/StringCodecs/Hexify.h>
#include <Swiften/StringCodecs/SHA1.h>
#include <Swiften/Base/foreach.h>
#include "Swiften/JID/JID.h"
-#include "Swiften/Base/ByteArray.h"
#include "Swiften/Elements/VCard.h"
#include "Swiften/Serializer/PayloadSerializers/VCardSerializer.h"
#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadParserTester.h"
#include "Swiften/Parser/PayloadParsers/VCardParser.h"
-namespace Swift {
+using namespace Swift;
+
+typedef GenericPayloadPersister<VCard, VCardParser, VCardSerializer> VCardPersister;
VCardFileStorage::VCardFileStorage(boost::filesystem::path dir) : vcardsPath(dir) {
cacheFile = vcardsPath / "phashes";
@@ -48,34 +52,11 @@ VCardFileStorage::VCardFileStorage(boost::filesystem::path dir) : vcardsPath(dir
}
boost::shared_ptr<VCard> VCardFileStorage::getVCard(const JID& jid) const {
- boost::filesystem::path vcardPath(getVCardPath(jid));
- if (boost::filesystem::exists(vcardPath)) {
- ByteArray data;
- data.readFromFile(vcardPath.string());
-
- VCardParser parser;
- PayloadParserTester tester(&parser);
- tester.parse(data.toString());
- return boost::dynamic_pointer_cast<VCard>(parser.getPayload());
- }
- else {
- return boost::shared_ptr<VCard>();
- }
+ return VCardPersister().loadPayloadGeneric(getVCardPath(jid));
}
void VCardFileStorage::setVCard(const JID& jid, VCard::ref v) {
- boost::filesystem::path vcardPath(getVCardPath(jid));
- if (!boost::filesystem::exists(vcardPath.parent_path())) {
- try {
- boost::filesystem::create_directories(vcardPath.parent_path());
- }
- catch (const boost::filesystem::filesystem_error& e) {
- std::cerr << "ERROR: " << e.what() << std::endl;
- }
- }
- boost::filesystem::ofstream file(getVCardPath(jid));
- file << VCardSerializer().serializePayload(v);
- file.close();
+ VCardPersister().savePayload(v, getVCardPath(jid));
getAndUpdatePhotoHash(jid, v);
}
@@ -124,6 +105,3 @@ void VCardFileStorage::savePhotoHashes() const {
std::cerr << "Error writing vcards file" << std::endl;
}
}
-
-
-}
diff --git a/Swiften/VCards/VCardFileStorage.h b/Swift/Controllers/Storages/VCardFileStorage.h
index 26bf4b2..ba422f4 100644
--- a/Swiften/VCards/VCardFileStorage.h
+++ b/Swift/Controllers/Storages/VCardFileStorage.h
@@ -7,7 +7,7 @@
#pragma once
#include <boost/shared_ptr.hpp>
-#include <boost/filesystem.hpp>
+#include <boost/filesystem/path.hpp>
#include <string>
#include <map>
diff --git a/Swift/Controllers/UIEvents/RequestAdHocUIEvent.h b/Swift/Controllers/UIEvents/RequestAdHocUIEvent.h
new file mode 100644
index 0000000..c3b4b49
--- /dev/null
+++ b/Swift/Controllers/UIEvents/RequestAdHocUIEvent.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swift/Controllers/UIInterfaces/MainWindow.h>
+
+#include <Swift/Controllers/UIEvents/UIEvent.h>
+
+namespace Swift {
+ class RequestAdHocUIEvent : public UIEvent {
+ public:
+ RequestAdHocUIEvent(const DiscoItems::Item& command) : command_(command) {};
+ const DiscoItems::Item& getCommand() const {return command_;}
+ private:
+ DiscoItems::Item command_;
+ };
+}
diff --git a/Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h b/Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h
index dd2ff6c..2c7b105 100644
--- a/Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h
+++ b/Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h
@@ -6,18 +6,25 @@
#pragma once
-#include <boost/optional.hpp>
#include <boost/shared_ptr.hpp>
-
#include <string>
+
#include <Swift/Controllers/UIEvents/UIEvent.h>
+#include <Swiften/JID/JID.h>
namespace Swift {
class RequestJoinMUCUIEvent : public UIEvent {
public:
typedef boost::shared_ptr<RequestJoinMUCUIEvent> ref;
- RequestJoinMUCUIEvent() {
+ RequestJoinMUCUIEvent(const JID& room = JID()) : room(room) {
}
+
+ const JID& getRoom() const {
+ return room;
+ }
+
+ private:
+ JID room;
};
}
diff --git a/Swift/Controllers/UIInterfaces/AdHocCommandWindow.h b/Swift/Controllers/UIInterfaces/AdHocCommandWindow.h
new file mode 100644
index 0000000..f7a5d39
--- /dev/null
+++ b/Swift/Controllers/UIInterfaces/AdHocCommandWindow.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2010 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+namespace Swift {
+ class AdHocCommandWindow {
+ public:
+ virtual ~AdHocCommandWindow() {};
+ };
+}
diff --git a/Swift/Controllers/UIInterfaces/AdHocCommandWindowFactory.h b/Swift/Controllers/UIInterfaces/AdHocCommandWindowFactory.h
new file mode 100644
index 0000000..ae77180
--- /dev/null
+++ b/Swift/Controllers/UIInterfaces/AdHocCommandWindowFactory.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2010-2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swift/Controllers/UIInterfaces/AdHocCommandWindow.h>
+#include <Swiften/AdHoc/OutgoingAdHocCommandSession.h>
+
+namespace Swift {
+ class AdHocCommandWindowFactory {
+ public:
+ virtual ~AdHocCommandWindowFactory() {}
+ /**
+ * The UI should deal with the lifetime of this window (i.e. DeleteOnClose),
+ * so the result isn't returned.
+ */
+ virtual void createAdHocCommandWindow(boost::shared_ptr<OutgoingAdHocCommandSession> command) = 0;
+ };
+}
diff --git a/Swift/Controllers/UIInterfaces/ChatListWindow.h b/Swift/Controllers/UIInterfaces/ChatListWindow.h
index a2a0874..f717684 100644
--- a/Swift/Controllers/UIInterfaces/ChatListWindow.h
+++ b/Swift/Controllers/UIInterfaces/ChatListWindow.h
@@ -1,23 +1,35 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#pragma once
+#include <list>
#include <boost/shared_ptr.hpp>
-
-#include "Swiften/MUC/MUCBookmark.h"
+#include <Swiften/MUC/MUCBookmark.h>
namespace Swift {
class ChatListWindow {
public:
+ class Chat {
+ public:
+ Chat(const JID& jid, const std::string& chatName, const std::string& activity, bool isMUC, const std::string& nick = "") : jid(jid), chatName(chatName), activity(activity), isMUC(isMUC), nick(nick) {}
+ /** Assume that nicks aren't important for equality */
+ bool operator==(const Chat& other) const {return jid == other.jid && isMUC == other.isMUC;};
+ JID jid;
+ std::string chatName;
+ std::string activity;
+ bool isMUC;
+ std::string nick;
+ };
virtual ~ChatListWindow();
virtual void setBookmarksEnabled(bool enabled) = 0;
virtual void addMUCBookmark(const MUCBookmark& bookmark) = 0;
virtual void removeMUCBookmark(const MUCBookmark& bookmark) = 0;
- virtual void clear() = 0;
+ virtual void setRecents(const std::list<Chat>& recents) = 0;
+ virtual void clearBookmarks() = 0;
};
}
diff --git a/Swift/Controllers/UIInterfaces/ChatWindow.h b/Swift/Controllers/UIInterfaces/ChatWindow.h
index c7bcf1e..aa4416b 100644
--- a/Swift/Controllers/UIInterfaces/ChatWindow.h
+++ b/Swift/Controllers/UIInterfaces/ChatWindow.h
@@ -40,6 +40,7 @@ namespace Swift {
virtual void addSystemMessage(const std::string& message) = 0;
virtual void addPresenceMessage(const std::string& message) = 0;
virtual void addErrorMessage(const std::string& message) = 0;
+ virtual void replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time) = 0;
virtual void setContactChatState(ChatState::ChatStateType state) = 0;
virtual void setName(const std::string& name) = 0;
@@ -61,9 +62,11 @@ namespace Swift {
boost::signal<void ()> onClosed;
boost::signal<void ()> onAllMessagesRead;
- boost::signal<void (const std::string&)> onSendMessageRequest;
+ boost::signal<void (const std::string&, bool isCorrection)> onSendMessageRequest;
+ boost::signal<void ()> onSendCorrectionMessageRequest;
boost::signal<void ()> onUserTyping;
boost::signal<void ()> onUserCancelsTyping;
+ boost::signal<void (bool correction)> onSendMessageCorrection;
};
}
#endif
diff --git a/Swift/Controllers/UIInterfaces/MainWindow.h b/Swift/Controllers/UIInterfaces/MainWindow.h
index 2fd463b..93584e7 100644
--- a/Swift/Controllers/UIInterfaces/MainWindow.h
+++ b/Swift/Controllers/UIInterfaces/MainWindow.h
@@ -9,6 +9,7 @@
#include <string>
#include "Swiften/JID/JID.h"
#include "Swiften/Elements/StatusShow.h"
+#include "Swiften/Elements/DiscoItems.h"
#include "Swiften/Base/boost_bsignals.h"
#include <boost/shared_ptr.hpp>
@@ -33,6 +34,7 @@ namespace Swift {
/** Must be able to cope with NULL to clear the roster */
virtual void setRosterModel(Roster* roster) = 0;
virtual void setConnecting() = 0;
+ virtual void setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& commands) = 0;
boost::signal<void (StatusShow::Type, const std::string&)> onChangeStatusRequest;
boost::signal<void ()> onSignOutRequest;
diff --git a/Swift/Controllers/UIInterfaces/UIFactory.h b/Swift/Controllers/UIInterfaces/UIFactory.h
index 9b36ac5..57f55d0 100644
--- a/Swift/Controllers/UIInterfaces/UIFactory.h
+++ b/Swift/Controllers/UIInterfaces/UIFactory.h
@@ -17,6 +17,7 @@
#include <Swift/Controllers/UIInterfaces/XMLConsoleWidgetFactory.h>
#include <Swift/Controllers/UIInterfaces/ProfileWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/ContactEditWindowFactory.h>
+#include <Swift/Controllers/UIInterfaces/AdHocCommandWindowFactory.h>
namespace Swift {
class UIFactory :
@@ -30,7 +31,8 @@ namespace Swift {
public UserSearchWindowFactory,
public JoinMUCWindowFactory,
public ProfileWindowFactory,
- public ContactEditWindowFactory {
+ public ContactEditWindowFactory,
+ public AdHocCommandWindowFactory {
public:
virtual ~UIFactory() {}
};
diff --git a/Swift/Controllers/UnitTest/ChatMessageSummarizerTest.cpp b/Swift/Controllers/UnitTest/ChatMessageSummarizerTest.cpp
new file mode 100644
index 0000000..ee0ee9f
--- /dev/null
+++ b/Swift/Controllers/UnitTest/ChatMessageSummarizerTest.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include "Swift/Controllers/ChatMessageSummarizer.h"
+
+using namespace Swift;
+using namespace std;
+
+class ChatMessageSummarizerTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(ChatMessageSummarizerTest);
+ CPPUNIT_TEST(testEmpty);
+ CPPUNIT_TEST(testCurrentNone);
+ CPPUNIT_TEST(testCurrentCount);
+ CPPUNIT_TEST(testCurrentCountOthersNone);
+ CPPUNIT_TEST(testCurrentCountOtherCount);
+ CPPUNIT_TEST(testCurrentNoneOtherCount);
+ CPPUNIT_TEST(testCurrentCountOthersCount);
+ CPPUNIT_TEST(testCurrentNoneOthersCount);
+ CPPUNIT_TEST(testCurrentCountSomeOthersCount);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ ChatMessageSummarizerTest() {};
+
+ void setUp() {
+
+ }
+
+ void testEmpty() {
+ string current("");
+ vector<UnreadPair> unreads;
+ ChatMessageSummarizer summary;
+ CPPUNIT_ASSERT_EQUAL(current, summary.getSummary(current, unreads));
+ }
+
+ void testCurrentNone() {
+ string current("Bob");
+ vector<UnreadPair> unreads;
+ unreads.push_back(UnreadPair("Bob", 0));
+ ChatMessageSummarizer summary;
+ CPPUNIT_ASSERT_EQUAL(current, summary.getSummary(current, unreads));
+ }
+
+ void testCurrentCount() {
+ string current("Bob");
+ vector<UnreadPair> unreads;
+ unreads.push_back(UnreadPair("Bob", 3));
+ ChatMessageSummarizer summary;
+ CPPUNIT_ASSERT_EQUAL(string("Bob (3)"), summary.getSummary(current, unreads));
+ }
+
+ void testCurrentCountOthersNone() {
+ string current("Bob");
+ vector<UnreadPair> unreads;
+ unreads.push_back(UnreadPair("Bert", 0));
+ unreads.push_back(UnreadPair("Bob", 3));
+ unreads.push_back(UnreadPair("Betty", 0));
+ ChatMessageSummarizer summary;
+ CPPUNIT_ASSERT_EQUAL(string("Bob (3)"), summary.getSummary(current, unreads));
+ }
+
+ void testCurrentCountOtherCount() {
+ string current("Bob");
+ vector<UnreadPair> unreads;
+ unreads.push_back(UnreadPair("Bert", 0));
+ unreads.push_back(UnreadPair("Bob", 3));
+ unreads.push_back(UnreadPair("Betty", 7));
+ ChatMessageSummarizer summary;
+ CPPUNIT_ASSERT_EQUAL(string("Bob (3), Betty (7)"), summary.getSummary(current, unreads));
+ }
+
+ void testCurrentNoneOtherCount() {
+ string current("Bob");
+ vector<UnreadPair> unreads;
+ unreads.push_back(UnreadPair("Bert", 0));
+ unreads.push_back(UnreadPair("Bob", 0));
+ unreads.push_back(UnreadPair("Betty", 7));
+ ChatMessageSummarizer summary;
+ CPPUNIT_ASSERT_EQUAL(string("Bob, Betty (7)"), summary.getSummary(current, unreads));
+ }
+
+ void testCurrentNoneOthersCount() {
+ string current("Bob");
+ vector<UnreadPair> unreads;
+ unreads.push_back(UnreadPair("Bert", 2));
+ unreads.push_back(UnreadPair("Bob", 0));
+ unreads.push_back(UnreadPair("Betty", 7));
+ ChatMessageSummarizer summary;
+ CPPUNIT_ASSERT_EQUAL(string("Bob and 2 others (9)"), summary.getSummary(current, unreads));
+ }
+
+ void testCurrentCountOthersCount() {
+ string current("Bob");
+ vector<UnreadPair> unreads;
+ unreads.push_back(UnreadPair("Bert", 2));
+ unreads.push_back(UnreadPair("Bob", 11));
+ unreads.push_back(UnreadPair("Betty", 7));
+ ChatMessageSummarizer summary;
+ CPPUNIT_ASSERT_EQUAL(string("Bob (11) and 2 others (9)"), summary.getSummary(current, unreads));
+ }
+
+ void testCurrentCountSomeOthersCount() {
+ string current("Bob");
+ vector<UnreadPair> unreads;
+ unreads.push_back(UnreadPair("Bert", 2));
+ unreads.push_back(UnreadPair("Beverly", 0));
+ unreads.push_back(UnreadPair("Bob", 11));
+ unreads.push_back(UnreadPair("Beatrice", 0));
+ unreads.push_back(UnreadPair("Betty", 7));
+ ChatMessageSummarizer summary;
+ CPPUNIT_ASSERT_EQUAL(string("Bob (11) and 2 others (9)"), summary.getSummary(current, unreads));
+ }
+
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(ChatMessageSummarizerTest);
diff --git a/Swift/Controllers/UnitTest/MockChatWindow.h b/Swift/Controllers/UnitTest/MockChatWindow.h
index 53a90a7..82c5b52 100644
--- a/Swift/Controllers/UnitTest/MockChatWindow.h
+++ b/Swift/Controllers/UnitTest/MockChatWindow.h
@@ -34,12 +34,13 @@ namespace Swift {
virtual void setRosterModel(Roster* /*roster*/) {};
virtual void setTabComplete(TabComplete*) {};
virtual void replaceLastMessage(const std::string&) {};
+ virtual void replaceMessage(const std::string&, const std::string&, const boost::posix_time::ptime&) {};
void setAckState(const std::string& /*id*/, AckState /*state*/) {};
virtual void flash() {};
boost::signal<void ()> onClosed;
boost::signal<void ()> onAllMessagesRead;
- boost::signal<void (const std::string&)> onSendMessageRequest;
+ boost::signal<void (const std::string&, bool isCorrection)> onSendMessageRequest;
std::string name_;
std::string lastMessageBody_;
diff --git a/Swift/Controllers/UnitTest/MockMainWindow.h b/Swift/Controllers/UnitTest/MockMainWindow.h
index afa5c2a..f773062 100644
--- a/Swift/Controllers/UnitTest/MockMainWindow.h
+++ b/Swift/Controllers/UnitTest/MockMainWindow.h
@@ -20,6 +20,7 @@ namespace Swift {
virtual void setMyAvatarPath(const std::string& /*path*/) {};
virtual void setMyStatusText(const std::string& /*status*/) {};
virtual void setMyStatusType(StatusShow::Type /*type*/) {};
+ virtual void setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& /*commands*/) {};
virtual void setConnecting() {};
Roster* roster;
diff --git a/Swift/Controllers/XMPPEvents/EventController.cpp b/Swift/Controllers/XMPPEvents/EventController.cpp
index 7f8f216..98fd634 100644
--- a/Swift/Controllers/XMPPEvents/EventController.cpp
+++ b/Swift/Controllers/XMPPEvents/EventController.cpp
@@ -9,6 +9,7 @@
#include <boost/bind.hpp>
#include <algorithm>
+#include <Swiften/Base/foreach.h>
#include "Swift/Controllers/XMPPEvents/MessageEvent.h"
#include "Swift/Controllers/XMPPEvents/ErrorEvent.h"
#include "Swift/Controllers/XMPPEvents/SubscriptionRequestEvent.h"
diff --git a/Swift/Controllers/XMPPURIController.cpp b/Swift/Controllers/XMPPURIController.cpp
new file mode 100644
index 0000000..00759b8
--- /dev/null
+++ b/Swift/Controllers/XMPPURIController.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swift/Controllers/XMPPURIController.h>
+
+#include <boost/bind.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <SwifTools/URIHandler/URIHandler.h>
+#include <SwifTools/URIHandler/XMPPURI.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
+
+using namespace Swift;
+
+XMPPURIController::XMPPURIController(URIHandler* uriHandler, UIEventStream* uiEventStream) : uriHandler(uriHandler), uiEventStream(uiEventStream) {
+ uriHandler->onURI.connect(boost::bind(&XMPPURIController::handleURI, this, _1));
+}
+
+XMPPURIController::~XMPPURIController() {
+ uriHandler->onURI.disconnect(boost::bind(&XMPPURIController::handleURI, this, _1));
+}
+
+void XMPPURIController::handleURI(const std::string& s) {
+ XMPPURI uri = XMPPURI::fromString(s);
+ if (!uri.isNull()) {
+ if (uri.getQueryType() == "join") {
+ uiEventStream->send(boost::make_shared<RequestJoinMUCUIEvent>(uri.getPath()));
+ }
+ else {
+ uiEventStream->send(boost::make_shared<RequestChatUIEvent>(uri.getPath()));
+ }
+ }
+}
diff --git a/Swift/Controllers/XMPPURIController.h b/Swift/Controllers/XMPPURIController.h
new file mode 100644
index 0000000..54534d4
--- /dev/null
+++ b/Swift/Controllers/XMPPURIController.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <string>
+#include <Swiften/Base/boost_bsignals.h>
+
+namespace Swift {
+ class URIHandler;
+ class JID;
+ class UIEventStream;
+
+ class XMPPURIController {
+ public:
+ XMPPURIController(URIHandler* uriHandler, UIEventStream* uiEventStream);
+ ~XMPPURIController();
+
+ boost::signal<void (const JID&)> onStartChat;
+ boost::signal<void (const JID&)> onJoinMUC;
+
+ private:
+ void handleURI(const std::string&);
+
+ private:
+ URIHandler* uriHandler;
+ UIEventStream* uiEventStream;
+ };
+}
diff --git a/Swift/QtUI/.gitignore b/Swift/QtUI/.gitignore
index f539e86..53acb9f 100644
--- a/Swift/QtUI/.gitignore
+++ b/Swift/QtUI/.gitignore
@@ -1,3 +1,4 @@
Swift
BuildVersion.h
*.dmg
+swift-open-uri
diff --git a/Swift/QtUI/ChatList/ChatListDelegate.cpp b/Swift/QtUI/ChatList/ChatListDelegate.cpp
index 274a10a..b2bfe0a 100644
--- a/Swift/QtUI/ChatList/ChatListDelegate.cpp
+++ b/Swift/QtUI/ChatList/ChatListDelegate.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -11,6 +11,7 @@
#include "Swift/QtUI/Roster/GroupItemDelegate.h"
#include "Swift/QtUI/ChatList/ChatListItem.h"
#include "Swift/QtUI/ChatList/ChatListMUCItem.h"
+#include "Swift/QtUI/ChatList/ChatListRecentItem.h"
#include "Swift/QtUI/ChatList/ChatListGroupItem.h"
namespace Swift {
@@ -27,7 +28,11 @@ QSize ChatListDelegate::sizeHint(const QStyleOptionViewItem& option, const QMode
ChatListItem* item = static_cast<ChatListItem*>(index.internalPointer());
if (item && dynamic_cast<ChatListMUCItem*>(item)) {
return mucSizeHint(option, index);
- } else if (item && dynamic_cast<ChatListGroupItem*>(item)) {
+ }
+ else if (item && dynamic_cast<ChatListRecentItem*>(item)) {
+ return recentSizeHint(option, index);
+ }
+ else if (item && dynamic_cast<ChatListGroupItem*>(item)) {
return groupDelegate_->sizeHint(option, index);
}
return QStyledItemDelegate::sizeHint(option, index);
@@ -40,14 +45,23 @@ QSize ChatListDelegate::mucSizeHint(const QStyleOptionViewItem& /*option*/, cons
return QSize(150, sizeByText);
}
+QSize ChatListDelegate::recentSizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const {
+ return mucSizeHint(option, index);
+}
+
void ChatListDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
ChatListItem* item = static_cast<ChatListItem*>(index.internalPointer());
if (item && dynamic_cast<ChatListMUCItem*>(item)) {
paintMUC(painter, option, dynamic_cast<ChatListMUCItem*>(item));
- } else if (item && dynamic_cast<ChatListGroupItem*>(item)) {
+ }
+ else if (item && dynamic_cast<ChatListRecentItem*>(item)) {
+ paintRecent(painter, option, dynamic_cast<ChatListRecentItem*>(item));
+ }
+ else if (item && dynamic_cast<ChatListGroupItem*>(item)) {
ChatListGroupItem* group = dynamic_cast<ChatListGroupItem*>(item);
groupDelegate_->paint(painter, option, group->data(Qt::DisplayRole).toString(), group->rowCount(), option.state & QStyle::State_Open);
- } else {
+ }
+ else {
QStyledItemDelegate::paint(painter, option, index);
}
}
@@ -78,9 +92,40 @@ void ChatListDelegate::paintMUC(QPainter* painter, const QStyleOptionViewItem& o
painter->setPen(QPen(QColor(160,160,160)));
QRect detailRegion(textRegion.adjusted(0, nameHeight, 0, 0));
- DelegateCommons::drawElidedText(painter, detailRegion, item->data(DetailTextRole).toString());
+ DelegateCommons::drawElidedText(painter, detailRegion, item->data(ChatListMUCItem::DetailTextRole).toString());
painter->restore();
}
+void ChatListDelegate::paintRecent(QPainter* painter, const QStyleOptionViewItem& option, ChatListRecentItem* item) const {
+ painter->save();
+ QRect fullRegion(option.rect);
+ if ( option.state & QStyle::State_Selected ) {
+ painter->fillRect(fullRegion, option.palette.highlight());
+ painter->setPen(option.palette.highlightedText().color());
+ } else {
+ QColor nameColor = item->data(Qt::TextColorRole).value<QColor>();
+ painter->setPen(QPen(nameColor));
+ }
+
+ QFontMetrics nameMetrics(common_.nameFont);
+ painter->setFont(common_.nameFont);
+ int extraFontWidth = nameMetrics.width("H");
+ int leftOffset = common_.horizontalMargin * 2 + extraFontWidth / 2;
+ QRect textRegion(fullRegion.adjusted(leftOffset, 0, 0, 0));
+
+ int nameHeight = nameMetrics.height() + common_.verticalMargin;
+ QRect nameRegion(textRegion.adjusted(0, common_.verticalMargin, 0, 0));
+
+ DelegateCommons::drawElidedText(painter, nameRegion, item->data(Qt::DisplayRole).toString());
+
+ painter->setFont(common_.detailFont);
+ painter->setPen(QPen(QColor(160,160,160)));
+
+ QRect detailRegion(textRegion.adjusted(0, nameHeight, 0, 0));
+ DelegateCommons::drawElidedText(painter, detailRegion, item->data(ChatListRecentItem::DetailTextRole).toString());
+
+ painter->restore();
+}
+
}
diff --git a/Swift/QtUI/ChatList/ChatListDelegate.h b/Swift/QtUI/ChatList/ChatListDelegate.h
index f6c6c40..a898df4 100644
--- a/Swift/QtUI/ChatList/ChatListDelegate.h
+++ b/Swift/QtUI/ChatList/ChatListDelegate.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -12,6 +12,7 @@
namespace Swift {
class ChatListMUCItem;
+ class ChatListRecentItem;
class ChatListDelegate : public QStyledItemDelegate {
public:
ChatListDelegate();
@@ -20,7 +21,9 @@ namespace Swift {
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
private:
void paintMUC(QPainter* painter, const QStyleOptionViewItem& option, ChatListMUCItem* item) const;
+ void paintRecent(QPainter* painter, const QStyleOptionViewItem& option, ChatListRecentItem* item) const;
QSize mucSizeHint(const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/ ) const;
+ QSize recentSizeHint(const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/ ) const;
DelegateCommons common_;
GroupItemDelegate* groupDelegate_;
diff --git a/Swift/QtUI/ChatList/ChatListGroupItem.h b/Swift/QtUI/ChatList/ChatListGroupItem.h
index cc4d4af..a1e479f 100644
--- a/Swift/QtUI/ChatList/ChatListGroupItem.h
+++ b/Swift/QtUI/ChatList/ChatListGroupItem.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -13,8 +13,8 @@
namespace Swift {
class ChatListGroupItem : public ChatListItem {
public:
- ChatListGroupItem(const QString& name, ChatListGroupItem* parent) : ChatListItem(parent), name_(name) {};
- void addItem(ChatListItem* item) {items_.push_back(item); qStableSort(items_.begin(), items_.end(), pointerItemLessThan);};
+ ChatListGroupItem(const QString& name, ChatListGroupItem* parent, bool sorted = true) : ChatListItem(parent), name_(name), sorted_(sorted) {};
+ void addItem(ChatListItem* item) {items_.push_back(item); if (sorted_) {qStableSort(items_.begin(), items_.end(), pointerItemLessThan);}};
void remove(int index) {items_.removeAt(index);};
int rowCount() {return items_.size();};
ChatListItem* item(int i) {return items_[i];};
@@ -30,5 +30,6 @@ namespace Swift {
QString name_;
QList<ChatListItem*> items_;
+ bool sorted_;
};
}
diff --git a/Swift/QtUI/ChatList/ChatListMUCItem.h b/Swift/QtUI/ChatList/ChatListMUCItem.h
index 068f5d6..f26aa67 100644
--- a/Swift/QtUI/ChatList/ChatListMUCItem.h
+++ b/Swift/QtUI/ChatList/ChatListMUCItem.h
@@ -15,14 +15,14 @@
#include "Swift/QtUI/ChatList/ChatListItem.h"
namespace Swift {
- enum MUCItemRoles {
- DetailTextRole = Qt::UserRole/*,
- AvatarRole = Qt::UserRole + 1,
- PresenceIconRole = Qt::UserRole + 2,
- StatusShowTypeRole = Qt::UserRole + 3*/
- };
class ChatListMUCItem : public ChatListItem {
public:
+ enum MUCItemRoles {
+ DetailTextRole = Qt::UserRole/*,
+ AvatarRole = Qt::UserRole + 1,
+ PresenceIconRole = Qt::UserRole + 2,
+ StatusShowTypeRole = Qt::UserRole + 3*/
+ };
ChatListMUCItem(const MUCBookmark& bookmark, ChatListGroupItem* parent);
const MUCBookmark& getBookmark();
QVariant data(int role) const;
diff --git a/Swift/QtUI/ChatList/ChatListModel.cpp b/Swift/QtUI/ChatList/ChatListModel.cpp
index ba7b766..681c1c2 100644
--- a/Swift/QtUI/ChatList/ChatListModel.cpp
+++ b/Swift/QtUI/ChatList/ChatListModel.cpp
@@ -1,22 +1,25 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#include "Swift/QtUI/ChatList/ChatListModel.h"
+#include <Swift/QtUI/ChatList/ChatListModel.h>
-#include "Swift/QtUI/ChatList/ChatListMUCItem.h"
+#include <Swift/QtUI/ChatList/ChatListMUCItem.h>
+#include <Swift/QtUI/ChatList/ChatListRecentItem.h>
namespace Swift {
ChatListModel::ChatListModel() {
- root_ = new ChatListGroupItem("", NULL);
+ root_ = new ChatListGroupItem("", NULL, false);
mucBookmarks_ = new ChatListGroupItem(tr("Bookmarked Rooms"), root_);
+ recents_ = new ChatListGroupItem(tr("Recent Chats"), root_, false);
+ root_->addItem(recents_);
root_->addItem(mucBookmarks_);
}
-void ChatListModel::clear() {
+void ChatListModel::clearBookmarks() {
emit layoutAboutToBeChanged();
mucBookmarks_->clear();
emit layoutChanged();
@@ -43,6 +46,15 @@ void ChatListModel::removeMUCBookmark(const Swift::MUCBookmark& bookmark) {
}
}
+void ChatListModel::setRecents(const std::list<ChatListWindow::Chat>& recents) {
+ emit layoutAboutToBeChanged();
+ recents_->clear();
+ foreach (const ChatListWindow::Chat chat, recents) {
+ recents_->addItem(new ChatListRecentItem(chat, recents_));
+ }
+ emit layoutChanged();
+}
+
int ChatListModel::columnCount(const QModelIndex& /*parent*/) const {
return 1;
}
diff --git a/Swift/QtUI/ChatList/ChatListModel.h b/Swift/QtUI/ChatList/ChatListModel.h
index adde148..8e7828c 100644
--- a/Swift/QtUI/ChatList/ChatListModel.h
+++ b/Swift/QtUI/ChatList/ChatListModel.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -11,9 +11,10 @@
#include <QAbstractItemModel>
#include <QList>
-#include "Swiften/MUC/MUCBookmark.h"
+#include <Swiften/MUC/MUCBookmark.h>
+#include <Swift/Controllers/UIInterfaces/ChatListWindow.h>
-#include "Swift/QtUI/ChatList/ChatListGroupItem.h"
+#include <Swift/QtUI/ChatList/ChatListGroupItem.h>
namespace Swift {
class ChatListModel : public QAbstractItemModel {
@@ -28,9 +29,11 @@ namespace Swift {
QModelIndex parent(const QModelIndex& index) const;
int rowCount(const QModelIndex& parent = QModelIndex()) const;
ChatListItem* getItemForIndex(const QModelIndex& index) const;
- void clear();
+ void clearBookmarks();
+ void setRecents(const std::list<ChatListWindow::Chat>& recents);
private:
ChatListGroupItem* mucBookmarks_;
+ ChatListGroupItem* recents_;
ChatListGroupItem* root_;
};
diff --git a/Swift/QtUI/ChatList/ChatListRecentItem.cpp b/Swift/QtUI/ChatList/ChatListRecentItem.cpp
new file mode 100644
index 0000000..8b6707c
--- /dev/null
+++ b/Swift/QtUI/ChatList/ChatListRecentItem.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swift/QtUI/ChatList/ChatListRecentItem.h>
+
+#include <Swift/QtUI/QtSwiftUtil.h>
+
+namespace Swift {
+ChatListRecentItem::ChatListRecentItem(const ChatListWindow::Chat& chat, ChatListGroupItem* parent) : ChatListItem(parent), chat_(chat) {
+
+}
+
+const ChatListWindow::Chat& ChatListRecentItem::getChat() {
+ return chat_;
+}
+
+QVariant ChatListRecentItem::data(int role) const {
+ switch (role) {
+ case Qt::DisplayRole: return P2QSTRING(chat_.chatName);
+ case DetailTextRole: return P2QSTRING(chat_.activity);
+ /*case Qt::TextColorRole: return textColor_;
+ case Qt::BackgroundColorRole: return backgroundColor_;
+ case Qt::ToolTipRole: return isContact() ? toolTipString() : QVariant();
+ case StatusTextRole: return statusText_;
+ case AvatarRole: return avatar_;
+ case PresenceIconRole: return getPresenceIcon();*/
+ default: return QVariant();
+ }
+}
+
+}
diff --git a/Swift/QtUI/ChatList/ChatListRecentItem.h b/Swift/QtUI/ChatList/ChatListRecentItem.h
new file mode 100644
index 0000000..c2646cc
--- /dev/null
+++ b/Swift/QtUI/ChatList/ChatListRecentItem.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <QList>
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/MUC/MUCBookmark.h>
+#include <Swift/Controllers/UIInterfaces/ChatListWindow.h>
+
+#include <Swift/QtUI/ChatList/ChatListItem.h>
+
+namespace Swift {
+ class ChatListRecentItem : public ChatListItem {
+ public:
+ enum RecentItemRoles {
+ DetailTextRole = Qt::UserRole/*,
+ AvatarRole = Qt::UserRole + 1,
+ PresenceIconRole = Qt::UserRole + 2,
+ StatusShowTypeRole = Qt::UserRole + 3*/
+ };
+ ChatListRecentItem(const ChatListWindow::Chat& chat, ChatListGroupItem* parent);
+ const ChatListWindow::Chat& getChat();
+ QVariant data(int role) const;
+ private:
+ ChatListWindow::Chat chat_;
+ };
+}
diff --git a/Swift/QtUI/ChatList/QtChatListWindow.cpp b/Swift/QtUI/ChatList/QtChatListWindow.cpp
index b532cdb..d71563d 100644
--- a/Swift/QtUI/ChatList/QtChatListWindow.cpp
+++ b/Swift/QtUI/ChatList/QtChatListWindow.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -10,9 +10,11 @@
#include <QContextMenuEvent>
#include "Swift/QtUI/ChatList/ChatListMUCItem.h"
+#include "Swift/QtUI/ChatList/ChatListRecentItem.h"
#include "Swift/QtUI/QtAddBookmarkWindow.h"
#include "Swift/QtUI/QtEditBookmarkWindow.h"
#include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h"
+#include "Swift/Controllers/UIEvents/RequestChatUIEvent.h"
#include "Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h"
#include "Swift/Controllers/UIEvents/RemoveMUCBookmarkUIEvent.h"
#include "Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h"
@@ -68,19 +70,30 @@ void QtChatListWindow::setupContextMenus() {
}
void QtChatListWindow::handleItemActivated(const QModelIndex& index) {
- if (!bookmarksEnabled_) {
- return;
- }
ChatListItem* item = model_->getItemForIndex(index);
ChatListMUCItem* mucItem = dynamic_cast<ChatListMUCItem*>(item);
- if (mucItem) {
+ if (bookmarksEnabled_ && mucItem) {
boost::shared_ptr<UIEvent> event(new JoinMUCUIEvent(mucItem->getBookmark().getRoom(), mucItem->getBookmark().getNick()));
eventStream_->send(event);
}
+ ChatListRecentItem* recentItem = dynamic_cast<ChatListRecentItem*>(item);
+ if (recentItem) {
+ boost::shared_ptr<UIEvent> event;
+ if (recentItem->getChat().isMUC) {
+ if (!bookmarksEnabled_) {
+ return;
+ }
+ return;
+ }
+ else {
+ event = boost::shared_ptr<UIEvent>(new RequestChatUIEvent(recentItem->getChat().jid));
+ }
+ eventStream_->send(event);
+ }
}
-void QtChatListWindow::clear() {
- model_->clear();
+void QtChatListWindow::clearBookmarks() {
+ model_->clearBookmarks();
}
void QtChatListWindow::addMUCBookmark(const MUCBookmark& bookmark) {
@@ -91,6 +104,10 @@ void QtChatListWindow::removeMUCBookmark(const MUCBookmark& bookmark) {
model_->removeMUCBookmark(bookmark);
}
+void QtChatListWindow::setRecents(const std::list<ChatListWindow::Chat>& recents) {
+ model_->setRecents(recents);
+}
+
void QtChatListWindow::handleRemoveBookmark() {
ChatListMUCItem* mucItem = dynamic_cast<ChatListMUCItem*>(contextMenuItem_);
if (!mucItem) return;
diff --git a/Swift/QtUI/ChatList/QtChatListWindow.h b/Swift/QtUI/ChatList/QtChatListWindow.h
index 3a3e95f..f5c12f6 100644
--- a/Swift/QtUI/ChatList/QtChatListWindow.h
+++ b/Swift/QtUI/ChatList/QtChatListWindow.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -23,7 +23,8 @@ namespace Swift {
void addMUCBookmark(const MUCBookmark& bookmark);
void removeMUCBookmark(const MUCBookmark& bookmark);
void setBookmarksEnabled(bool enabled);
- void clear();
+ void setRecents(const std::list<ChatListWindow::Chat>& recents);
+ void clearBookmarks();
private slots:
void handleItemActivated(const QModelIndex&);
void handleAddBookmark();
diff --git a/Swift/QtUI/ChatSnippet.h b/Swift/QtUI/ChatSnippet.h
index 3aa5fcc..7cbb3b3 100644
--- a/Swift/QtUI/ChatSnippet.h
+++ b/Swift/QtUI/ChatSnippet.h
@@ -17,7 +17,7 @@ namespace Swift {
public:
ChatSnippet(bool appendToPrevious);
virtual ~ChatSnippet();
-
+
virtual const QString& getContent() const = 0;
virtual QString getContinuationElementID() const { return ""; }
@@ -26,7 +26,7 @@ namespace Swift {
bool getAppendToPrevious() const {
return appendToPrevious_;
}
-
+
static QString escape(const QString& original) {
QString result(original);
result.replace("%message%", "&#37;message&#37;");
@@ -37,11 +37,12 @@ namespace Swift {
return result;
}
+ static QString timeToEscapedString(const QDateTime& time);
+
protected:
void setContinuationFallbackSnippet(boost::shared_ptr<ChatSnippet> continuationFallback) {
continuationFallback_ = continuationFallback;
}
- static QString timeToEscapedString(const QDateTime& time);
private:
bool appendToPrevious_;
boost::shared_ptr<ChatSnippet> continuationFallback_;
diff --git a/Swift/QtUI/QtAdHocCommandWindow.cpp b/Swift/QtUI/QtAdHocCommandWindow.cpp
new file mode 100644
index 0000000..a3bb077
--- /dev/null
+++ b/Swift/QtUI/QtAdHocCommandWindow.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2010-2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swift/QtUI/QtAdHocCommandWindow.h>
+
+#include <boost/bind.hpp>
+#include <QBoxLayout>
+#include <Swift/QtUI/QtFormWidget.h>
+#include <Swiften/Elements/Command.h>
+
+namespace Swift {
+QtAdHocCommandWindow::QtAdHocCommandWindow(boost::shared_ptr<OutgoingAdHocCommandSession> command) : command_(command) {
+
+ formWidget_ = NULL;
+
+ setAttribute(Qt::WA_DeleteOnClose);
+ command->onNextStageReceived.connect(boost::bind(&QtAdHocCommandWindow::handleNextStageReceived, this, _1));
+ command->onError.connect(boost::bind(&QtAdHocCommandWindow::handleError, this, _1));
+ command->start();
+
+ QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom, this);
+ layout->setContentsMargins(0,0,0,0);
+ layout->setSpacing(2);
+ label_ = new QLabel(this);
+ layout->addWidget(label_);
+ QWidget* formContainer = new QWidget(this);
+ layout->addWidget(formContainer);
+ formLayout_ = new QBoxLayout(QBoxLayout::TopToBottom, formContainer);
+ QWidget* buttonsWidget = new QWidget(this);
+ layout->addWidget(buttonsWidget);
+
+ QBoxLayout* buttonsLayout = new QBoxLayout(QBoxLayout::LeftToRight, buttonsWidget);
+ cancelButton_ = new QPushButton(tr("Cancel"), buttonsWidget);
+ buttonsLayout->addWidget(cancelButton_);
+ connect(cancelButton_, SIGNAL(clicked()), this, SLOT(handleCancelClicked()));
+ backButton_ = new QPushButton(tr("Back"), buttonsWidget);
+ buttonsLayout->addWidget(backButton_);
+ connect(backButton_, SIGNAL(clicked()), this, SLOT(handlePrevClicked()));
+ nextButton_ = new QPushButton(tr("Next"), buttonsWidget);
+ buttonsLayout->addWidget(nextButton_);
+ connect(nextButton_, SIGNAL(clicked()), this, SLOT(handleNextClicked()));
+ completeButton_ = new QPushButton(tr("Complete"), buttonsWidget);
+ buttonsLayout->addWidget(completeButton_);
+ connect(completeButton_, SIGNAL(clicked()), this, SLOT(handleCompleteClicked()));
+ nextButton_->setEnabled(false);
+ backButton_->setEnabled(false);
+ completeButton_->setEnabled(false);
+ actions_[Command::Next] = nextButton_;
+ actions_[Command::Prev] = backButton_;
+ actions_[Command::Complete] = completeButton_;
+ actions_[Command::Cancel] = cancelButton_;
+ show();
+}
+
+QtAdHocCommandWindow::~QtAdHocCommandWindow() {
+
+}
+
+void QtAdHocCommandWindow::handleCancelClicked() {
+ command_->cancel();
+}
+
+void QtAdHocCommandWindow::handlePrevClicked() {
+ command_->goBack();
+}
+
+void QtAdHocCommandWindow::handleNextClicked() {
+ command_->goNext(formWidget_ ? formWidget_->getCompletedForm() : Form::ref());
+}
+
+void QtAdHocCommandWindow::handleCompleteClicked() {
+ command_->complete(formWidget_ ? formWidget_->getCompletedForm() : Form::ref());
+}
+
+void QtAdHocCommandWindow::handleNextStageReceived(Command::ref command) {
+ if (command->getForm()) {
+ setForm(command->getForm());
+ } else {
+ setNoForm();
+ }
+ QString notes;
+ foreach (Command::Note note, command->getNotes()) {
+ if (!notes.isEmpty()) {
+ notes += "\n";
+ QString qNote(note.note.c_str());
+ switch (note.type) {
+ case Command::Note::Error: notes += tr("Error: %1").arg(qNote); break;
+ case Command::Note::Warn: notes += tr("Warning: %1").arg(qNote); break;
+ case Command::Note::Info: notes += qNote; break;
+ }
+ }
+ }
+ label_->setText(notes);
+ setAvailableActions(command);
+}
+
+void QtAdHocCommandWindow::handleError(ErrorPayload::ref /*error*/) {
+ nextButton_->setEnabled(false);
+ backButton_->setEnabled(false);
+ completeButton_->setEnabled(false);
+ label_->setText(tr("Error executing command"));
+}
+
+void QtAdHocCommandWindow::setForm(Form::ref form) {
+ delete formWidget_;
+ formWidget_ = new QtFormWidget(form, this);
+ formLayout_->addWidget(formWidget_);
+}
+
+void QtAdHocCommandWindow::setNoForm() {
+ delete formWidget_;
+}
+
+typedef std::pair<Command::Action, QPushButton*> ActionButton;
+
+void QtAdHocCommandWindow::setAvailableActions(Command::ref /*commandResult*/) {
+ foreach (ActionButton pair, actions_) {
+ OutgoingAdHocCommandSession::ActionState state = command_->getActionState(pair.first);
+ if (state & OutgoingAdHocCommandSession::Present) {
+ pair.second->show();
+ }
+ else {
+ pair.second->hide();
+ }
+ if (state & OutgoingAdHocCommandSession::Enabled) {
+ pair.second->setEnabled(true);
+ }
+ else {
+ pair.second->setEnabled(false);
+ }
+ }
+}
+
+}
diff --git a/Swift/QtUI/QtAdHocCommandWindow.h b/Swift/QtUI/QtAdHocCommandWindow.h
new file mode 100644
index 0000000..adeb3e6
--- /dev/null
+++ b/Swift/QtUI/QtAdHocCommandWindow.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2010-2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <QWidget>
+#include <QPushButton>
+#include <QLabel>
+
+#include <Swift/Controllers/UIInterfaces/AdHocCommandWindow.h>
+#include <Swiften/AdHoc/OutgoingAdHocCommandSession.h>
+
+class QBoxLayout;
+
+namespace Swift {
+ class QtFormWidget;
+ class QtAdHocCommandWindow : public QWidget, public AdHocCommandWindow {
+ Q_OBJECT
+ public:
+ QtAdHocCommandWindow(boost::shared_ptr<OutgoingAdHocCommandSession> command);
+ virtual ~QtAdHocCommandWindow();
+ private:
+ void handleNextStageReceived(Command::ref command);
+ void handleError(ErrorPayload::ref error);
+ void setForm(Form::ref);
+ void setNoForm();
+ void setAvailableActions(Command::ref commandResult);
+ private slots:
+ void handleCancelClicked();
+ void handlePrevClicked();
+ void handleNextClicked();
+ void handleCompleteClicked();
+ private:
+ boost::shared_ptr<OutgoingAdHocCommandSession> command_;
+ QtFormWidget* formWidget_;
+ QBoxLayout* formLayout_;
+ Form::ref form_;
+ QLabel* label_;
+ QPushButton* backButton_;
+ QPushButton* nextButton_;
+ QPushButton* completeButton_;
+ QPushButton* cancelButton_;
+ std::map<Command::Action, QPushButton*> actions_;
+ };
+}
diff --git a/Swift/QtUI/QtChatTabs.cpp b/Swift/QtUI/QtChatTabs.cpp
index 25c7ca2..249080b 100644
--- a/Swift/QtUI/QtChatTabs.cpp
+++ b/Swift/QtUI/QtChatTabs.cpp
@@ -7,6 +7,10 @@
#include "QtChatTabs.h"
#include <algorithm>
+#include <vector>
+
+#include <Swift/Controllers/ChatMessageSummarizer.h>
+#include <Swift/QtUI/QtSwiftUtil.h>
#include <QCloseEvent>
#include <QDesktopWidget>
@@ -236,16 +240,18 @@ void QtChatTabs::handleTabTitleUpdated(QWidget* widget) {
default : tabTextColor = QColor();
}
tabs_->tabBar()->setTabTextColor(index, tabTextColor);
- int unread = 0;
+
+ std::vector<std::pair<std::string, int> > unreads;
for (int i = 0; i < tabs_->count(); i++) {
QtTabbable* tab = qobject_cast<QtTabbable*>(tabs_->widget(i));
if (tab) {
- unread += tab->getCount();
+ unreads.push_back(std::pair<std::string, int>(Q2PSTRING(tab->windowTitle()), tab->getCount()));
}
}
- QtTabbable* current = qobject_cast<QtTabbable*>(tabs_->currentWidget());
- setWindowTitle(unread > 0 ? QString("(%1) %2").arg(unread).arg(current->windowTitle()) : current->windowTitle());
+ std::string current(Q2PSTRING(qobject_cast<QtTabbable*>(tabs_->currentWidget())->windowTitle()));
+ ChatMessageSummarizer summary;
+ setWindowTitle(summary.getSummary(current, unreads).c_str());
}
void QtChatTabs::flash() {
diff --git a/Swift/QtUI/QtChatView.cpp b/Swift/QtUI/QtChatView.cpp
index 521b072..eab6d91 100644
--- a/Swift/QtUI/QtChatView.cpp
+++ b/Swift/QtUI/QtChatView.cpp
@@ -106,6 +106,19 @@ void QtChatView::addToDOM(boost::shared_ptr<ChatSnippet> snippet) {
//qApp->processEvents();
}
+void QtChatView::addLastSeenLine() {
+ if (lineSeparator_.isNull()) {
+ lineSeparator_ = newInsertPoint_.clone();
+ lineSeparator_.setInnerXml(QString("<hr/>"));
+ newInsertPoint_.prependOutside(lineSeparator_);
+ }
+ else {
+ QWebElement lineSeparatorC = lineSeparator_.clone();
+ lineSeparatorC.removeFromDocument();
+ }
+ newInsertPoint_.prependOutside(lineSeparator_);
+}
+
void QtChatView::replaceLastMessage(const QString& newMessage) {
assert(viewReady_);
/* FIXME: must be queued? */
@@ -125,6 +138,25 @@ void QtChatView::replaceLastMessage(const QString& newMessage, const QString& no
replace.setInnerXml(ChatSnippet::escape(note));
}
+QString QtChatView::getLastSentMessage() {
+ return lastElement_.toPlainText();
+}
+
+void QtChatView::replaceMessage(const QString& newMessage, const QString& id, const QDateTime& editTime) {
+ rememberScrolledToBottom();
+ QWebElement message = document_.findFirst("#" + id);
+ if (!message.isNull()) {
+ QWebElement replaceContent = message.findFirst("span.swift_message");
+ assert(!replaceContent.isNull());
+ QString old = replaceContent.toOuterXml();
+ replaceContent.setInnerXml(ChatSnippet::escape(newMessage));
+ QWebElement replaceTime = message.findFirst("span.swift_time");
+ assert(!replaceTime.isNull());
+ old = replaceTime.toOuterXml();
+ replaceTime.setInnerXml(ChatSnippet::escape(tr("%1 edited").arg(ChatSnippet::timeToEscapedString(editTime))));
+ }
+}
+
void QtChatView::copySelectionToClipboard() {
if (!webPage_->selectedText().isEmpty()) {
webPage_->triggerAction(QWebPage::Copy);
diff --git a/Swift/QtUI/QtChatView.h b/Swift/QtUI/QtChatView.h
index 58b33df..32741f4 100644
--- a/Swift/QtUI/QtChatView.h
+++ b/Swift/QtUI/QtChatView.h
@@ -26,12 +26,14 @@ namespace Swift {
Q_OBJECT
public:
QtChatView(QtChatTheme* theme, QWidget* parent);
-
void addMessage(boost::shared_ptr<ChatSnippet> snippet);
+ void addLastSeenLine();
void replaceLastMessage(const QString& newMessage);
void replaceLastMessage(const QString& newMessage, const QString& note);
+ void replaceMessage(const QString& newMessage, const QString& id, const QDateTime& time);
void rememberScrolledToBottom();
void setAckXML(const QString& id, const QString& xml);
+ QString getLastSentMessage();
signals:
void gotFocus();
@@ -63,6 +65,7 @@ namespace Swift {
QtChatTheme* theme_;
QWebElement newInsertPoint_;
+ QWebElement lineSeparator_;
QWebElement lastElement_;
QWebElement document_;
};
diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp
index 1a909fd..326660f 100644
--- a/Swift/QtUI/QtChatWindow.cpp
+++ b/Swift/QtUI/QtChatWindow.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -17,6 +17,7 @@
#include "SwifTools/TabComplete.h"
+#include <QLabel>
#include <QApplication>
#include <QBoxLayout>
#include <QCloseEvent>
@@ -35,12 +36,13 @@ QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventSt
inputEnabled_ = true;
completer_ = NULL;
theme_ = theme;
+ isCorrection_ = false;
updateTitleWithUnreadCount();
QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom, this);
layout->setContentsMargins(0,0,0,0);
layout->setSpacing(2);
-
+
QSplitter *logRosterSplitter = new QSplitter(this);
logRosterSplitter->setAutoFillBackground(true);
@@ -69,10 +71,18 @@ QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventSt
labelsWidget_->setSizeAdjustPolicy(QComboBox::AdjustToContents);
midBarLayout->addWidget(labelsWidget_,0);
+ QWidget* inputBar = new QWidget(this);
+ layout->addWidget(inputBar);
+ QHBoxLayout* inputBarLayout = new QHBoxLayout(inputBar);
+ inputBarLayout->setContentsMargins(0,0,0,0);
+ inputBarLayout->setSpacing(2);
input_ = new QtTextEdit(this);
input_->setAcceptRichText(false);
- layout->addWidget(input_);
-
+ inputBarLayout->addWidget(input_);
+ correctingLabel_ = new QLabel(tr("Correcting"), this);
+ inputBarLayout->addWidget(correctingLabel_);
+ correctingLabel_->hide();
+
inputClearing_ = false;
contactIsTyping_ = false;
@@ -118,11 +128,33 @@ void QtChatWindow::handleKeyPressEvent(QKeyEvent* event) {
emit requestActiveTab();
} else if (key == Qt::Key_Tab) {
tabComplete();
+ } else if ((key == Qt::Key_Up) && input_->toPlainText().isEmpty() && !(lastSentMessage_.isEmpty())) {
+ beginCorrection();
+ } else if (key == Qt::Key_Down && isCorrection_ && input_->textCursor().atBlockEnd()) {
+ cancelCorrection();
} else {
messageLog_->handleKeyPressEvent(event);
}
}
+void QtChatWindow::beginCorrection() {
+ QTextCursor cursor = input_->textCursor();
+ cursor.select(QTextCursor::Document);
+ cursor.beginEditBlock();
+ cursor.insertText(QString(lastSentMessage_));
+ cursor.endEditBlock();
+ isCorrection_ = true;
+ correctingLabel_->show();
+}
+
+void QtChatWindow::cancelCorrection() {
+ QTextCursor cursor = input_->textCursor();
+ cursor.select(QTextCursor::Document);
+ cursor.removeSelectedText();
+ isCorrection_ = false;
+ correctingLabel_->hide();
+}
+
void QtChatWindow::tabComplete() {
if (!completer_) {
return;
@@ -150,7 +182,7 @@ void QtChatWindow::tabComplete() {
}
void QtChatWindow::setRosterModel(Roster* roster) {
- treeWidget_->setRosterModel(roster);
+ treeWidget_->setRosterModel(roster);
}
void QtChatWindow::setAvailableSecurityLabels(const std::vector<SecurityLabelsCatalog::Item>& labels) {
@@ -204,10 +236,13 @@ void QtChatWindow::qAppFocusChanged(QWidget *old, QWidget *now) {
Q_UNUSED(old);
Q_UNUSED(now);
if (isWidgetSelected()) {
+ lastLineTracker_.setHasFocus(true);
input_->setFocus();
onAllMessagesRead();
}
-
+ else {
+ lastLineTracker_.setHasFocus(false);
+ }
}
void QtChatWindow::setInputEnabled(bool enabled) {
@@ -236,7 +271,7 @@ void QtChatWindow::setContactChatState(ChatState::ChatStateType state) {
QtTabbable::AlertType QtChatWindow::getWidgetAlertState() {
if (contactIsTyping_) {
return ImpendingActivity;
- }
+ }
if (unreadCount_ > 0) {
return WaitingActivity;
}
@@ -265,7 +300,6 @@ std::string QtChatWindow::addMessage(const std::string &message, const std::stri
if (isWidgetSelected()) {
onAllMessagesRead();
}
-
QString scaledAvatarPath = QtScaledAvatarCache(32).getScaledAvatarPath(avatarPath.c_str());
QString htmlString;
@@ -281,6 +315,12 @@ std::string QtChatWindow::addMessage(const std::string &message, const std::stri
htmlString += styleSpanStart + messageHTML + styleSpanEnd;
bool appendToPrevious = !previousMessageWasSystem_ && !previousMessageWasPresence_ && ((senderIsSelf && previousMessageWasSelf_) || (!senderIsSelf && !previousMessageWasSelf_ && previousSenderName_ == P2QSTRING(senderName)));
+ if (lastLineTracker_.getShouldMoveLastLine()) {
+ /* should this be queued? */
+ messageLog_->addLastSeenLine();
+ /* if the line is added we should break the snippet */
+ appendToPrevious = false;
+ }
QString qAvatarPath = scaledAvatarPath.isEmpty() ? "qrc:/icons/avatar.png" : QUrl::fromLocalFile(scaledAvatarPath).toEncoded();
std::string id = id_.generateID();
messageLog_->addMessage(boost::shared_ptr<ChatSnippet>(new MessageSnippet(htmlString, Qt::escape(P2QSTRING(senderName)), B2QDATE(time), qAvatarPath, senderIsSelf, appendToPrevious, theme_, P2QSTRING(id))));
@@ -343,6 +383,15 @@ void QtChatWindow::addSystemMessage(const std::string& message) {
previousMessageWasPresence_ = false;
}
+void QtChatWindow::replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time) {
+ if (!id.empty()) {
+ QString messageHTML(Qt::escape(P2QSTRING(message)));
+ messageHTML = P2QSTRING(Linkify::linkify(Q2PSTRING(messageHTML)));
+ messageHTML.replace("\n","<br/>");
+ messageLog_->replaceMessage(messageHTML, P2QSTRING(id), B2QDATE(time));
+ }
+}
+
void QtChatWindow::addPresenceMessage(const std::string& message) {
if (isWidgetSelected()) {
onAllMessagesRead();
@@ -364,9 +413,11 @@ void QtChatWindow::returnPressed() {
return;
}
messageLog_->scrollToBottom();
- onSendMessageRequest(Q2PSTRING(input_->toPlainText()));
+ lastSentMessage_ = QString(input_->toPlainText());
+ onSendMessageRequest(Q2PSTRING(input_->toPlainText()), isCorrection_);
inputClearing_ = true;
input_->clear();
+ cancelCorrection();
inputClearing_ = false;
}
@@ -382,7 +433,9 @@ void QtChatWindow::handleInputChanged() {
}
void QtChatWindow::show() {
- QWidget::show();
+ if (parentWidget() == NULL) {
+ QWidget::show();
+ }
emit windowOpening();
}
@@ -399,7 +452,7 @@ void QtChatWindow::resizeEvent(QResizeEvent*) {
}
void QtChatWindow::moveEvent(QMoveEvent*) {
- emit geometryChanged();
+ emit geometryChanged();
}
void QtChatWindow::replaceLastMessage(const std::string& message) {
diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h
index 910019b..a95041e 100644
--- a/Swift/QtUI/QtChatWindow.h
+++ b/Swift/QtUI/QtChatWindow.h
@@ -1,21 +1,23 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#ifndef SWIFT_QtChatWindow_H
-#define SWIFT_QtChatWindow_H
+#pragma once
#include "Swift/Controllers/UIInterfaces/ChatWindow.h"
#include "QtTabbable.h"
+#include "SwifTools/LastLineTracker.h"
+
#include "Swiften/Base/IDGenerator.h"
class QTextEdit;
class QLineEdit;
class QComboBox;
+class QLabel;
namespace Swift {
class QtChatView;
@@ -35,6 +37,7 @@ namespace Swift {
void addSystemMessage(const std::string& message);
void addPresenceMessage(const std::string& message);
void addErrorMessage(const std::string& errorMessage);
+ void replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time);
void show();
void activate();
void setUnreadMessageCount(int count);
@@ -75,18 +78,24 @@ namespace Swift {
private:
void updateTitleWithUnreadCount();
void tabComplete();
+ void beginCorrection();
+ void cancelCorrection();
std::string addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const QString& style, const boost::posix_time::ptime& time);
int unreadCount_;
bool contactIsTyping_;
+ LastLineTracker lastLineTracker_;
QString contact_;
+ QString lastSentMessage_;
QtChatView* messageLog_;
QtChatTheme* theme_;
QtTextEdit* input_;
QComboBox* labelsWidget_;
QtTreeWidget* treeWidget_;
+ QLabel* correctingLabel_;
TabComplete* completer_;
std::vector<SecurityLabelsCatalog::Item> availableLabels_;
+ bool isCorrection_;
bool previousMessageWasSelf_;
bool previousMessageWasSystem_;
bool previousMessageWasPresence_;
@@ -97,5 +106,3 @@ namespace Swift {
IDGenerator id_;
};
}
-
-#endif
diff --git a/Swift/QtUI/QtDBUSURIHandler.cpp b/Swift/QtUI/QtDBUSURIHandler.cpp
new file mode 100644
index 0000000..9b69ca6
--- /dev/null
+++ b/Swift/QtUI/QtDBUSURIHandler.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include "QtDBUSURIHandler.h"
+
+#include <QDBusAbstractAdaptor>
+#include <QDBusConnection>
+
+#include "QtSwiftUtil.h"
+
+using namespace Swift;
+
+namespace {
+ class DBUSAdaptor: public QDBusAbstractAdaptor {
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "im.swift.Swift.URIHandler");
+ public:
+ DBUSAdaptor(QtDBUSURIHandler* uriHandler) : QDBusAbstractAdaptor(uriHandler), uriHandler(uriHandler) {
+ }
+
+ public slots:
+ void openURI(const QString& uri) {
+ uriHandler->onURI(Q2PSTRING(uri));
+ }
+
+ private:
+ QtDBUSURIHandler* uriHandler;
+ };
+}
+
+QtDBUSURIHandler::QtDBUSURIHandler() {
+ new DBUSAdaptor(this);
+ QDBusConnection connection = QDBusConnection::sessionBus();
+ connection.registerService("im.swift.Swift.URIHandler");
+ connection.registerObject("/", this);
+}
+
+#include "QtDBUSURIHandler.moc"
diff --git a/Swift/QtUI/QtDBUSURIHandler.h b/Swift/QtUI/QtDBUSURIHandler.h
new file mode 100644
index 0000000..be1872e
--- /dev/null
+++ b/Swift/QtUI/QtDBUSURIHandler.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <QObject>
+#include <SwifTools/URIHandler/URIHandler.h>
+
+namespace Swift {
+ class QtDBUSURIHandler : public QObject, public URIHandler {
+ public:
+ QtDBUSURIHandler();
+ };
+}
diff --git a/Swift/QtUI/QtFormWidget.cpp b/Swift/QtUI/QtFormWidget.cpp
new file mode 100644
index 0000000..050ff27
--- /dev/null
+++ b/Swift/QtUI/QtFormWidget.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2010-2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swift/QtUI/QtFormWidget.h>
+
+#include <QGridLayout>
+#include <QLabel>
+#include <QListWidget>
+#include <QLineEdit>
+#include <QTextEdit>
+#include <QCheckBox>
+#include <QScrollArea>
+
+#include <Swift/QtUI/QtSwiftUtil.h>
+#include <Swiften/Base/foreach.h>
+
+namespace Swift {
+
+QtFormWidget::QtFormWidget(Form::ref form, QWidget* parent) : QWidget(parent), form_(form) {
+ QGridLayout* thisLayout = new QGridLayout(this);
+ int row = 0;
+ if (!form->getTitle().empty()) {
+ QLabel* instructions = new QLabel(("<b>" + form->getTitle() + "</b>").c_str(), this);
+ thisLayout->addWidget(instructions, row++, 0, 1, 2);
+ }
+ if (!form->getInstructions().empty()) {
+ QLabel* instructions = new QLabel(form->getInstructions().c_str(), this);
+ thisLayout->addWidget(instructions, row++, 0, 1, 2);
+ }
+ QScrollArea* scrollArea = new QScrollArea(this);
+ thisLayout->addWidget(scrollArea);
+ QWidget* scroll = new QWidget(this);
+ QGridLayout* layout = new QGridLayout(scroll);
+ foreach (boost::shared_ptr<FormField> field, form->getFields()) {
+ QWidget* widget = createWidget(field);
+ if (widget) {
+ layout->addWidget(new QLabel(field->getLabel().c_str(), this), row, 0);
+ layout->addWidget(widget, row++, 1);
+ }
+ }
+ scrollArea->setWidget(scroll);
+ scrollArea->setWidgetResizable(true);
+}
+
+QtFormWidget::~QtFormWidget() {
+
+}
+
+QListWidget* QtFormWidget::createList(FormField::ref field) {
+ QListWidget* listWidget = new QListWidget(this);
+ listWidget->setSortingEnabled(false);
+ listWidget->setSelectionMode(boost::dynamic_pointer_cast<ListMultiFormField>(field) ? QAbstractItemView::MultiSelection : QAbstractItemView::SingleSelection);
+ foreach (FormField::Option option, field->getOptions()) {
+ listWidget->addItem(option.label.c_str());
+ }
+ boost::shared_ptr<ListMultiFormField> listMultiField = boost::dynamic_pointer_cast<ListMultiFormField>(field);
+ boost::shared_ptr<ListSingleFormField> listSingleField = boost::dynamic_pointer_cast<ListSingleFormField>(field);
+ for (int i = 0; i < listWidget->count(); i++) {
+ QListWidgetItem* item = listWidget->item(i);
+ bool selected = false;
+ if (listSingleField) {
+ selected = (item->text() == QString(listSingleField->getValue().c_str()));
+ }
+ else if (listMultiField) {
+ std::string text = Q2PSTRING(item->text());
+ selected = (std::find(listMultiField->getValue().begin(), listMultiField->getValue().end(), text) != listMultiField->getValue().end());
+ }
+ item->setSelected(selected);
+ }
+ return listWidget;
+}
+
+QWidget* QtFormWidget::createWidget(FormField::ref field) {
+ QWidget* widget = NULL;
+ boost::shared_ptr<BooleanFormField> booleanField = boost::dynamic_pointer_cast<BooleanFormField>(field);
+ if (booleanField) {
+ QCheckBox* checkWidget = new QCheckBox(this);
+ checkWidget->setCheckState(booleanField->getValue() ? Qt::Checked : Qt::Unchecked);
+ widget = checkWidget;
+ }
+ boost::shared_ptr<FixedFormField> fixedField = boost::dynamic_pointer_cast<FixedFormField>(field);
+ if (fixedField) {
+ QString value = fixedField->getValue().c_str();
+ widget = new QLabel(value, this);
+ }
+ boost::shared_ptr<ListSingleFormField> listSingleField = boost::dynamic_pointer_cast<ListSingleFormField>(field);
+ if (listSingleField) {
+ widget = createList(field);
+ }
+ boost::shared_ptr<TextMultiFormField> textMultiField = boost::dynamic_pointer_cast<TextMultiFormField>(field);
+ if (textMultiField) {
+ QString value = textMultiField->getValue().c_str();
+ widget = new QTextEdit(value, this);
+ }
+ boost::shared_ptr<TextPrivateFormField> textPrivateField = boost::dynamic_pointer_cast<TextPrivateFormField>(field);
+ if (textPrivateField) {
+ QString value = textPrivateField->getValue().c_str();
+ QLineEdit* lineWidget = new QLineEdit(value, this);
+ lineWidget->setEchoMode(QLineEdit::Password);
+ widget = lineWidget;
+ }
+ boost::shared_ptr<TextSingleFormField> textSingleField = boost::dynamic_pointer_cast<TextSingleFormField>(field);
+ if (textSingleField) {
+ QString value = textSingleField->getValue().c_str();
+ widget = new QLineEdit(value, this);
+ }
+ boost::shared_ptr<JIDSingleFormField> jidSingleField = boost::dynamic_pointer_cast<JIDSingleFormField>(field);
+ if (jidSingleField) {
+ QString value = jidSingleField->getValue().toString().c_str();
+ widget = new QLineEdit(value, this);
+ }
+ boost::shared_ptr<JIDMultiFormField> jidMultiField = boost::dynamic_pointer_cast<JIDMultiFormField>(field);
+ if (jidMultiField) {
+ QString text;
+ bool prev = false;
+ foreach (JID line, jidMultiField->getValue()) {
+ if (prev) {
+ text += "\n";
+ }
+ prev = true;
+ text += line.toString().c_str();
+ }
+ widget = new QTextEdit(text, this);
+ }
+ boost::shared_ptr<ListMultiFormField> listMultiField = boost::dynamic_pointer_cast<ListMultiFormField>(field);
+ if (listMultiField) {
+ widget = createList(field);
+ }
+ boost::shared_ptr<HiddenFormField> hiddenField = boost::dynamic_pointer_cast<HiddenFormField>(field);
+ if (hiddenField) {
+ }
+ fields_[field->getName()] = widget;
+ return widget;
+}
+
+Form::ref QtFormWidget::getCompletedForm() {
+ Form::ref result(new Form(Form::SubmitType));
+ foreach (boost::shared_ptr<FormField> field, form_->getFields()) {
+ boost::shared_ptr<FormField> resultField;
+ boost::shared_ptr<BooleanFormField> booleanField = boost::dynamic_pointer_cast<BooleanFormField>(field);
+ if (booleanField) {
+ resultField = FormField::ref(BooleanFormField::create(qobject_cast<QCheckBox*>(fields_[field->getName()])->checkState() == Qt::Checked));
+ }
+ boost::shared_ptr<FixedFormField> fixedField = boost::dynamic_pointer_cast<FixedFormField>(field);
+ if (fixedField) {
+ resultField = FormField::ref(FixedFormField::create(fixedField->getValue()));
+ }
+ boost::shared_ptr<ListSingleFormField> listSingleField = boost::dynamic_pointer_cast<ListSingleFormField>(field);
+ if (listSingleField) {
+ QListWidget* listWidget = qobject_cast<QListWidget*>(fields_[field->getName()]);
+ if (listWidget->selectedItems().size() > 0) {
+ int i = listWidget->row(listWidget->selectedItems()[0]);
+ resultField = FormField::ref(ListSingleFormField::create(field->getOptions()[i].value));
+ }
+ else {
+ resultField = FormField::ref(ListSingleFormField::create());
+ }
+ }
+ boost::shared_ptr<TextMultiFormField> textMultiField = boost::dynamic_pointer_cast<TextMultiFormField>(field);
+ if (textMultiField) {
+ QTextEdit* widget = qobject_cast<QTextEdit*>(fields_[field->getName()]);
+ QString string = widget->toPlainText();
+ if (string.isEmpty()) {
+ resultField = FormField::ref(TextMultiFormField::create());
+ }
+ else {
+ resultField = FormField::ref(TextMultiFormField::create(Q2PSTRING(string)));
+ }
+ }
+ boost::shared_ptr<TextPrivateFormField> textPrivateField = boost::dynamic_pointer_cast<TextPrivateFormField>(field);
+ if (textPrivateField) {
+ QLineEdit* widget = qobject_cast<QLineEdit*>(fields_[field->getName()]);
+ QString string = widget->text();
+ if (string.isEmpty()) {
+ resultField = FormField::ref(TextPrivateFormField::create());
+ }
+ else {
+ resultField = FormField::ref(TextPrivateFormField::create(Q2PSTRING(string)));
+ }
+ }
+ boost::shared_ptr<TextSingleFormField> textSingleField = boost::dynamic_pointer_cast<TextSingleFormField>(field);
+ if (textSingleField) {
+ QLineEdit* widget = qobject_cast<QLineEdit*>(fields_[field->getName()]);
+ QString string = widget->text();
+ if (string.isEmpty()) {
+ resultField = FormField::ref(TextSingleFormField::create());
+ }
+ else {
+ resultField = FormField::ref(TextSingleFormField::create(Q2PSTRING(string)));
+ }
+ }
+ boost::shared_ptr<JIDSingleFormField> jidSingleField = boost::dynamic_pointer_cast<JIDSingleFormField>(field);
+ if (jidSingleField) {
+ QLineEdit* widget = qobject_cast<QLineEdit*>(fields_[field->getName()]);
+ QString string = widget->text();
+ JID jid(Q2PSTRING(string));
+ if (string.isEmpty()) {
+ resultField = FormField::ref(JIDSingleFormField::create());
+ }
+ else {
+ resultField = FormField::ref(JIDSingleFormField::create(jid));
+ }
+ }
+ boost::shared_ptr<JIDMultiFormField> jidMultiField = boost::dynamic_pointer_cast<JIDMultiFormField>(field);
+ if (jidMultiField) {
+ QTextEdit* widget = qobject_cast<QTextEdit*>(fields_[field->getName()]);
+ QString string = widget->toPlainText();
+ if (string.isEmpty()) {
+ resultField = FormField::ref(JIDMultiFormField::create());
+ }
+ else {
+ QStringList lines = string.split("\n");
+ std::vector<JID> value;
+ foreach (QString line, lines) {
+ value.push_back(JID(Q2PSTRING(line)));
+ }
+ resultField = FormField::ref(JIDMultiFormField::create(value));
+ }
+ }
+ boost::shared_ptr<ListMultiFormField> listMultiField = boost::dynamic_pointer_cast<ListMultiFormField>(field);
+ if (listMultiField) {
+ QListWidget* listWidget = qobject_cast<QListWidget*>(fields_[field->getName()]);
+ std::vector<std::string> values;
+ foreach (QListWidgetItem* item, listWidget->selectedItems()) {
+ values.push_back(field->getOptions()[listWidget->row(item)].value);
+ }
+ resultField = FormField::ref(ListMultiFormField::create(values));
+ }
+ boost::shared_ptr<HiddenFormField> hiddenField = boost::dynamic_pointer_cast<HiddenFormField>(field);
+ if (hiddenField) {
+ resultField = FormField::ref(HiddenFormField::create(hiddenField->getValue()));
+ }
+ resultField->setName(field->getName());
+ result->addField(resultField);
+ }
+ return result;
+}
+
+}
diff --git a/Swift/QtUI/QtFormWidget.h b/Swift/QtUI/QtFormWidget.h
new file mode 100644
index 0000000..2fb7b98
--- /dev/null
+++ b/Swift/QtUI/QtFormWidget.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <QWidget>
+
+#include <map>
+#include <Swiften/Elements/Form.h>
+
+class QListWidget;
+
+namespace Swift {
+
+class QtFormWidget : public QWidget {
+ Q_OBJECT
+ public:
+ QtFormWidget(Form::ref form, QWidget* parent = NULL);
+ virtual ~QtFormWidget();
+ Form::ref getCompletedForm();
+ private:
+ QWidget* createWidget(FormField::ref field);
+ QListWidget* createList(FormField::ref field);
+ std::map<std::string, QWidget*> fields_;
+ Form::ref form_;
+};
+
+}
diff --git a/Swift/QtUI/QtLoginWindow.cpp b/Swift/QtUI/QtLoginWindow.cpp
index d0ab61e..4302c10 100644
--- a/Swift/QtUI/QtLoginWindow.cpp
+++ b/Swift/QtUI/QtLoginWindow.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -56,9 +56,9 @@ QtLoginWindow::QtLoginWindow(UIEventStream* uiEventStream) : QMainWindow() {
stack_ = new QStackedWidget(centralWidget);
topLayout->addWidget(stack_);
topLayout->setMargin(0);
- QWidget *wrapperWidget = new QWidget(this);
- wrapperWidget->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
- QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom, wrapperWidget);
+ loginWidgetWrapper_ = new QWidget(this);
+ loginWidgetWrapper_->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
+ QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom, loginWidgetWrapper_);
layout->addStretch(2);
QLabel* logo = new QLabel(this);
@@ -139,7 +139,7 @@ QtLoginWindow::QtLoginWindow(UIEventStream* uiEventStream) : QMainWindow() {
layout->addWidget(loginAutomatically_);
connect(loginButton_, SIGNAL(clicked()), SLOT(loginClicked()));
- stack_->addWidget(wrapperWidget);
+ stack_->addWidget(loginWidgetWrapper_);
#ifdef SWIFTEN_PLATFORM_MACOSX
menuBar_ = new QMenuBar(NULL);
#else
@@ -284,11 +284,9 @@ void QtLoginWindow::handleUsernameTextChanged() {
}
void QtLoginWindow::loggedOut() {
- if (stack_->count() > 1) {
- QWidget* current = stack_->currentWidget();
- stack_->setCurrentIndex(0);
- stack_->removeWidget(current);
- }
+ stack_->removeWidget(stack_->currentWidget());
+ stack_->addWidget(loginWidgetWrapper_);
+ stack_->setCurrentWidget(loginWidgetWrapper_);
setInitialMenus();
setIsLoggingIn(false);
}
@@ -370,6 +368,7 @@ void QtLoginWindow::setInitialMenus() {
void QtLoginWindow::morphInto(MainWindow *mainWindow) {
QtMainWindow *qtMainWindow = dynamic_cast<QtMainWindow*>(mainWindow);
assert(qtMainWindow);
+ stack_->removeWidget(loginWidgetWrapper_);
stack_->addWidget(qtMainWindow);
stack_->setCurrentWidget(qtMainWindow);
setEnabled(true);
diff --git a/Swift/QtUI/QtLoginWindow.h b/Swift/QtUI/QtLoginWindow.h
index 3f3b5f8..b667a4b 100644
--- a/Swift/QtUI/QtLoginWindow.h
+++ b/Swift/QtUI/QtLoginWindow.h
@@ -1,11 +1,10 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#ifndef SWIFT_QtLoginWindow_H
-#define SWIFT_QtLoginWindow_H
+#pragma once
#include <QMainWindow>
#include <QPointer>
@@ -65,6 +64,7 @@ namespace Swift {
private:
void setInitialMenus();
+ QWidget* loginWidgetWrapper_;
QStringList usernames_;
QStringList passwords_;
QStringList certificateFiles_;
@@ -87,5 +87,3 @@ namespace Swift {
QPointer<QtAboutWidget> aboutDialog_;
};
}
-
-#endif
diff --git a/Swift/QtUI/QtMainWindow.cpp b/Swift/QtUI/QtMainWindow.cpp
index 6391961..0c959d6 100644
--- a/Swift/QtUI/QtMainWindow.cpp
+++ b/Swift/QtUI/QtMainWindow.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -21,20 +21,25 @@
#include <QAction>
#include <QTabWidget>
-#include "QtSwiftUtil.h"
-#include "QtTabWidget.h"
-#include "Roster/QtTreeWidget.h"
-#include "Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h"
-#include "Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h"
-#include "Swift/Controllers/UIEvents/RequestChatWithUserDialogUIEvent.h"
-#include "Swift/Controllers/UIEvents/RequestProfileEditorUIEvent.h"
-#include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h"
-#include "Swift/Controllers/UIEvents/ToggleShowOfflineUIEvent.h"
+#include <Swift/QtUI/QtSwiftUtil.h>
+#include <Swift/QtUI/QtTabWidget.h>
+#include <Swift/QtUI/QtSettingsProvider.h>
+#include <Roster/QtTreeWidget.h>
+#include <Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestChatWithUserDialogUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestProfileEditorUIEvent.h>
+#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
+#include <Swift/Controllers/UIEvents/ToggleShowOfflineUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestAdHocUIEvent.h>
namespace Swift {
+#define CURRENT_ROSTER_TAB "current_roster_tab"
+
QtMainWindow::QtMainWindow(QtSettingsProvider* settings, UIEventStream* uiEventStream) : QWidget(), MainWindow(false) {
uiEventStream_ = uiEventStream;
+ settings_ = settings;
setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
QBoxLayout *mainLayout = new QBoxLayout(QBoxLayout::TopToBottom, this);
mainLayout->setContentsMargins(0,0,0,0);
@@ -68,8 +73,12 @@ QtMainWindow::QtMainWindow(QtSettingsProvider* settings, UIEventStream* uiEventS
chatListWindow_ = new QtChatListWindow(uiEventStream_);
- tabs_->addTab(eventWindow_, tr("&Notices"));
tabs_->addTab(chatListWindow_, tr("C&hats"));
+ tabs_->addTab(eventWindow_, tr("&Notices"));
+
+ tabs_->setCurrentIndex(settings_->getIntSetting(CURRENT_ROSTER_TAB, 0));
+
+ connect(tabs_, SIGNAL(currentChanged(int)), this, SLOT(handleTabChanged(int)));
this->setLayout(mainLayout);
@@ -99,6 +108,8 @@ QtMainWindow::QtMainWindow(QtSettingsProvider* settings, UIEventStream* uiEventS
chatUserAction_ = new QAction(tr("Start &Chat"), this);
connect(chatUserAction_, SIGNAL(triggered(bool)), this, SLOT(handleChatUserActionTriggered(bool)));
actionsMenu->addAction(chatUserAction_);
+ serverAdHocMenu_ = new QMenu(tr("Run Server Command"), this);
+ actionsMenu->addMenu(serverAdHocMenu_);
actionsMenu->addSeparator();
QAction* signOutAction = new QAction(tr("&Sign Out"), this);
connect(signOutAction, SIGNAL(triggered()), SLOT(handleSignOutAction()));
@@ -106,6 +117,12 @@ QtMainWindow::QtMainWindow(QtSettingsProvider* settings, UIEventStream* uiEventS
connect(treeWidget_, SIGNAL(onSomethingSelectedChanged(bool)), editUserAction_, SLOT(setEnabled(bool)));
+ setAvailableAdHocCommands(std::vector<DiscoItems::Item>());
+ QAction* adHocAction = new QAction(tr("Collecting commands..."), this);
+ adHocAction->setEnabled(false);
+ serverAdHocMenu_->addAction(adHocAction);
+ serverAdHocCommandActions_.append(adHocAction);
+
lastOfflineState_ = false;
uiEventStream_->onUIEvent.connect(boost::bind(&QtMainWindow::handleUIEvent, this, _1));
}
@@ -114,6 +131,10 @@ QtMainWindow::~QtMainWindow() {
uiEventStream_->onUIEvent.disconnect(boost::bind(&QtMainWindow::handleUIEvent, this, _1));
}
+void QtMainWindow::handleTabChanged(int index) {
+ settings_->storeInt(CURRENT_ROSTER_TAB, index);
+}
+
QtEventWindow* QtMainWindow::getEventWindow() {
return eventWindow_;
}
@@ -132,7 +153,7 @@ void QtMainWindow::handleEditProfileRequest() {
void QtMainWindow::handleEventCountUpdated(int count) {
QColor eventTabColor = (count == 0) ? QColor() : QColor(255, 0, 0); // invalid resets to default
- int eventIndex = 1;
+ int eventIndex = 2;
tabs_->tabBar()->setTabTextColor(eventIndex, eventTabColor);
QString text = tr("&Notices");
if (count > 0) {
@@ -206,6 +227,33 @@ void QtMainWindow::setConnecting() {
meView_->setConnecting();
}
+void QtMainWindow::handleAdHocActionTriggered(bool /*checked*/) {
+ QAction* action = qobject_cast<QAction*>(sender());
+ assert(action);
+ DiscoItems::Item command = serverAdHocCommands_[serverAdHocCommandActions_.indexOf(action)];
+ uiEventStream_->send(boost::shared_ptr<UIEvent>(new RequestAdHocUIEvent(command)));
+}
+
+void QtMainWindow::setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& commands) {
+ serverAdHocCommands_ = commands;
+ foreach (QAction* action, serverAdHocCommandActions_) {
+ delete action;
+ }
+ serverAdHocMenu_->clear();
+ serverAdHocCommandActions_.clear();
+ foreach (DiscoItems::Item command, commands) {
+ QAction* action = new QAction(P2QSTRING(command.getName()), this);
+ connect(action, SIGNAL(triggered(bool)), this, SLOT(handleAdHocActionTriggered(bool)));
+ serverAdHocMenu_->addAction(action);
+ serverAdHocCommandActions_.append(action);
+ }
+ if (serverAdHocCommandActions_.isEmpty()) {
+ QAction* action = new QAction(tr("No Available Commands"), this);
+ action->setEnabled(false);
+ serverAdHocMenu_->addAction(action);
+ serverAdHocCommandActions_.append(action);
+ }
+}
}
diff --git a/Swift/QtUI/QtMainWindow.h b/Swift/QtUI/QtMainWindow.h
index 3462bb0..5c29f6d 100644
--- a/Swift/QtUI/QtMainWindow.h
+++ b/Swift/QtUI/QtMainWindow.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -8,6 +8,7 @@
#include <QWidget>
#include <QMenu>
+#include <QList>
#include "Swift/Controllers/UIInterfaces/MainWindow.h"
#include "Swift/QtUI/QtRosterHeader.h"
#include "Swift/QtUI/EventViewer/QtEventWindow.h"
@@ -20,7 +21,7 @@ class QLineEdit;
class QPushButton;
class QToolBar;
class QAction;
-
+class QMenu;
class QTabWidget;
namespace Swift {
@@ -46,6 +47,7 @@ namespace Swift {
QtEventWindow* getEventWindow();
QtChatListWindow* getChatListWindow();
void setRosterModel(Roster* roster);
+ void setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& commands);
private slots:
void handleStatusChanged(StatusShow::Type showType, const QString &statusMessage);
void handleUIEvent(boost::shared_ptr<UIEvent> event);
@@ -55,10 +57,13 @@ namespace Swift {
void handleEditProfileAction();
void handleAddUserActionTriggered(bool checked);
void handleChatUserActionTriggered(bool checked);
+ void handleAdHocActionTriggered(bool checked);
void handleEventCountUpdated(int count);
void handleEditProfileRequest();
+ void handleTabChanged(int index);
private:
+ QtSettingsProvider* settings_;
std::vector<QMenu*> menus_;
QtTreeWidget* treeWidget_;
QtRosterHeader* meView_;
@@ -66,6 +71,7 @@ namespace Swift {
QAction* editUserAction_;
QAction* chatUserAction_;
QAction* showOfflineAction_;
+ QMenu* serverAdHocMenu_;
QtTabWidget* tabs_;
QWidget* contactsTabWidget_;
QWidget* eventsTabWidget_;
@@ -73,5 +79,7 @@ namespace Swift {
QtChatListWindow* chatListWindow_;
UIEventStream* uiEventStream_;
bool lastOfflineState_;
+ std::vector<DiscoItems::Item> serverAdHocCommands_;
+ QList<QAction*> serverAdHocCommandActions_;
};
}
diff --git a/Swift/QtUI/QtSwift.cpp b/Swift/QtUI/QtSwift.cpp
index d4c306f..d7a1f78 100644
--- a/Swift/QtUI/QtSwift.cpp
+++ b/Swift/QtUI/QtSwift.cpp
@@ -18,13 +18,11 @@
#include "QtUIFactory.h"
#include "QtChatWindowFactory.h"
#include <Swiften/Base/Log.h>
-#include <Swift/Controllers/CertificateFileStorageFactory.h>
+#include <Swift/Controllers/Storages/CertificateFileStorageFactory.h>
+#include "Swift/Controllers/Storages/FileStoragesFactory.h"
#include "SwifTools/Application/PlatformApplicationPathProvider.h"
-#include "Swiften/Avatars/AvatarFileStorage.h"
-#include "Swiften/Disco/CapsFileStorage.h"
#include <string>
#include "Swiften/Base/Platform.h"
-#include "Swift/Controllers/FileStoragesFactory.h"
#include "Swiften/Elements/Presence.h"
#include "Swiften/Client/Client.h"
#include "Swift/Controllers/MainController.h"
@@ -32,20 +30,30 @@
#include "Swift/Controllers/BuildVersion.h"
#include "SwifTools/AutoUpdater/AutoUpdater.h"
#include "SwifTools/AutoUpdater/PlatformAutoUpdaterFactory.h"
+
#if defined(SWIFTEN_PLATFORM_WINDOWS)
#include "WindowsNotifier.h"
-#endif
-#if defined(HAVE_GROWL)
+#elif defined(HAVE_GROWL)
#include "SwifTools/Notifier/GrowlNotifier.h"
#elif defined(SWIFTEN_PLATFORM_LINUX)
#include "FreeDesktopNotifier.h"
#else
#include "SwifTools/Notifier/NullNotifier.h"
#endif
+
#if defined(SWIFTEN_PLATFORM_MACOSX)
#include "SwifTools/Dock/MacOSXDock.h"
-#endif
+#else
#include "SwifTools/Dock/NullDock.h"
+#endif
+
+#if defined(SWIFTEN_PLATFORM_MACOSX)
+#include "QtURIHandler.h"
+#elif defined(SWIFTEN_PLATFORM_WIN32)
+#include <SwifTools/URIHandler/NullURIHandler.h>
+#else
+#include "QtDBUSURIHandler.h"
+#endif
namespace Swift{
@@ -123,6 +131,14 @@ QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMa
dock_ = new NullDock();
#endif
+#if defined(SWIFTEN_PLATFORM_MACOSX)
+ uriHandler_ = new QtURIHandler();
+#elif defined(SWIFTEN_PLATFORM_WIN32)
+ uriHandler_ = new NullURIHandler();
+#else
+ uriHandler_ = new QtDBUSURIHandler();
+#endif
+
if (splitter_) {
splitter_->show();
}
@@ -145,6 +161,7 @@ QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMa
certificateStorageFactory_,
dock_,
notifier_,
+ uriHandler_,
options.count("latency-debug") > 0);
mainControllers_.push_back(mainController);
}
@@ -172,6 +189,7 @@ QtSwift::~QtSwift() {
}
delete tabs_;
delete splitter_;
+ delete uriHandler_;
delete dock_;
delete soundPlayer_;
delete chatWindowFactory_;
diff --git a/Swift/QtUI/QtSwift.h b/Swift/QtUI/QtSwift.h
index 978fa14..4bf5c97 100644
--- a/Swift/QtUI/QtSwift.h
+++ b/Swift/QtUI/QtSwift.h
@@ -44,6 +44,7 @@ namespace Swift {
class QtMUCSearchWindowFactory;
class QtUserSearchWindowFactory;
class EventLoop;
+ class URIHandler;
class QtSwift : public QObject {
Q_OBJECT
@@ -63,6 +64,7 @@ namespace Swift {
QSplitter* splitter_;
QtSoundPlayer* soundPlayer_;
Dock* dock_;
+ URIHandler* uriHandler_;
QtChatTabs* tabs_;
ApplicationPathProvider* applicationPathProvider_;
StoragesFactory* storagesFactory_;
diff --git a/Swift/QtUI/QtTextEdit.cpp b/Swift/QtUI/QtTextEdit.cpp
index 3668220..3a62325 100644
--- a/Swift/QtUI/QtTextEdit.cpp
+++ b/Swift/QtUI/QtTextEdit.cpp
@@ -4,7 +4,7 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#include "QtTextEdit.h"
+#include <Swift/QtUI/QtTextEdit.h>
#include <QFontMetrics>
#include <QKeyEvent>
@@ -22,19 +22,25 @@ void QtTextEdit::keyPressEvent(QKeyEvent* event) {
if ((key == Qt::Key_Enter || key == Qt::Key_Return)
&& (modifiers == Qt::NoModifier || modifiers == Qt::KeypadModifier)) {
emit returnPressed();
- } else if (((key == Qt::Key_PageUp || key == Qt::Key_PageDown) && modifiers == Qt::ShiftModifier)
+ }
+ else if (((key == Qt::Key_PageUp || key == Qt::Key_PageDown) && modifiers == Qt::ShiftModifier)
|| (key == Qt::Key_C && modifiers == Qt::ControlModifier && textCursor().selectedText().isEmpty())
|| (key == Qt::Key_W && modifiers == Qt::ControlModifier)
|| (key == Qt::Key_PageUp && modifiers == Qt::ControlModifier)
|| (key == Qt::Key_PageDown && modifiers == Qt::ControlModifier)
-// || (key == Qt::Key_Left && modifiers == (Qt::ControlModifier | Qt::ShiftModifier))
-// || (key == Qt::Key_Right && modifiers == (Qt::ControlModifier | Qt::ShiftModifier))
|| (key == Qt::Key_Tab && modifiers == Qt::ControlModifier)
|| (key == Qt::Key_A && modifiers == Qt::AltModifier)
|| (key == Qt::Key_Tab)
) {
emit unhandledKeyPressEvent(event);
- } else {
+ }
+ else if ((key == Qt::Key_Up)
+ || (key == Qt::Key_Down)
+ ){
+ emit unhandledKeyPressEvent(event);
+ QTextEdit::keyPressEvent(event);
+ }
+ else {
QTextEdit::keyPressEvent(event);
}
}
diff --git a/Swift/QtUI/QtUIFactory.cpp b/Swift/QtUI/QtUIFactory.cpp
index 35fbfcd..5c1f78d 100644
--- a/Swift/QtUI/QtUIFactory.cpp
+++ b/Swift/QtUI/QtUIFactory.cpp
@@ -23,6 +23,7 @@
#include "UserSearch/QtUserSearchWindow.h"
#include "QtProfileWindow.h"
#include "QtContactEditWindow.h"
+#include "QtAdHocCommandWindow.h"
namespace Swift {
@@ -99,5 +100,8 @@ ContactEditWindow* QtUIFactory::createContactEditWindow() {
return new QtContactEditWindow();
}
+void QtUIFactory::createAdHocCommandWindow(boost::shared_ptr<OutgoingAdHocCommandSession> command) {
+ new QtAdHocCommandWindow(command);
+}
}
diff --git a/Swift/QtUI/QtUIFactory.h b/Swift/QtUI/QtUIFactory.h
index ddaaf6e..9ef228a 100644
--- a/Swift/QtUI/QtUIFactory.h
+++ b/Swift/QtUI/QtUIFactory.h
@@ -37,6 +37,7 @@ namespace Swift {
virtual JoinMUCWindow* createJoinMUCWindow();
virtual ProfileWindow* createProfileWindow();
virtual ContactEditWindow* createContactEditWindow();
+ virtual void createAdHocCommandWindow(boost::shared_ptr<OutgoingAdHocCommandSession> command);
private slots:
void handleLoginWindowGeometryChanged();
diff --git a/Swift/QtUI/QtURIHandler.cpp b/Swift/QtUI/QtURIHandler.cpp
new file mode 100644
index 0000000..43f3ed1
--- /dev/null
+++ b/Swift/QtUI/QtURIHandler.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include "QtURIHandler.h"
+
+#include <QCoreApplication>
+#include <QFileOpenEvent>
+#include <QUrl>
+
+#include "QtSwiftUtil.h"
+#ifdef Q_WS_MAC
+#include <SwifTools/URIHandler/MacOSXURIHandlerHelpers.h>
+#endif
+
+using namespace Swift;
+
+QtURIHandler::QtURIHandler() {
+ qApp->installEventFilter(this);
+#ifdef Q_WS_MAC
+ registerAppAsDefaultXMPPURIHandler();
+#endif
+}
+
+bool QtURIHandler::eventFilter(QObject*, QEvent* event) {
+ if (event->type() == QEvent::FileOpen) {
+ QFileOpenEvent* fileOpenEvent = static_cast<QFileOpenEvent*>(event);
+ if (fileOpenEvent->url().scheme() == "xmpp") {
+ onURI(Q2PSTRING(fileOpenEvent->url().toString()));
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/Swift/QtUI/QtURIHandler.h b/Swift/QtUI/QtURIHandler.h
new file mode 100644
index 0000000..a02114a
--- /dev/null
+++ b/Swift/QtUI/QtURIHandler.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <QObject>
+#include <SwifTools/URIHandler/URIHandler.h>
+
+class QUrl;
+
+namespace Swift {
+ class QtURIHandler : public QObject, public URIHandler {
+ public:
+ QtURIHandler();
+
+ private:
+ bool eventFilter(QObject* obj, QEvent* event);
+ };
+}
diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript
index 494731c..ef4f744 100644
--- a/Swift/QtUI/SConscript
+++ b/Swift/QtUI/SConscript
@@ -77,6 +77,7 @@ sources = [
"QtStatusWidget.cpp",
"QtScaledAvatarCache.cpp",
"QtSwift.cpp",
+ "QtURIHandler.cpp",
"QtChatView.cpp",
"QtChatTheme.cpp",
"QtChatTabs.cpp",
@@ -87,6 +88,7 @@ sources = [
"QtTabWidget.cpp",
"QtTextEdit.cpp",
"QtXMLConsoleWidget.cpp",
+ "QtAdHocCommandWindow.cpp",
"QtUtilities.cpp",
"QtBookmarkDetailWindow.cpp",
"QtAddBookmarkWindow.cpp",
@@ -97,6 +99,7 @@ sources = [
"MessageSnippet.cpp",
"SystemMessageSnippet.cpp",
"QtElidingLabel.cpp",
+ "QtFormWidget.cpp",
"QtLineEdit.cpp",
"QtJoinMUCWindow.cpp",
"Roster/RosterModel.cpp",
@@ -114,6 +117,7 @@ sources = [
"ChatList/ChatListModel.cpp",
"ChatList/ChatListDelegate.cpp",
"ChatList/ChatListMUCItem.cpp",
+ "ChatList/ChatListRecentItem.cpp",
"MUCSearch/QtMUCSearchWindow.cpp",
"MUCSearch/MUCSearchModel.cpp",
"MUCSearch/MUCSearchRoomItem.cpp",
@@ -136,20 +140,31 @@ sources = [
myenv["SWIFT_VERSION"] = Version.getBuildVersion(env.Dir("#").abspath, "swift")
if env["PLATFORM"] == "win32" :
- myenv.RES("../resources/Windows/Swift.rc")
+ res = myenv.RES("../resources/Windows/Swift.rc")
+ # For some reason, SCons isn't picking up the dependency correctly
+ # Adding it explicitly until i figure out why
+ myenv.Depends(res, "../Controllers/BuildVersion.h")
sources += [
"WindowsNotifier.cpp",
"../resources/Windows/Swift.res"
]
if env["PLATFORM"] == "posix" :
- sources += ["FreeDesktopNotifier.cpp"]
+ sources += [
+ "FreeDesktopNotifier.cpp",
+ "QtDBUSURIHandler.cpp",
+ ]
if env["PLATFORM"] == "darwin" or env["PLATFORM"] == "win32" :
swiftProgram = myenv.Program("Swift", sources)
else :
swiftProgram = myenv.Program("swift", sources)
+if env["PLATFORM"] != "darwin" and env["PLATFORM"] != "win32" :
+ openURIProgram = myenv.Program("swift-open-uri", "swift-open-uri.cpp")
+else :
+ openURIProgram = []
+
myenv.Uic4("MUCSearch/QtMUCSearchWindow.ui")
myenv.Uic4("UserSearch/QtUserSearchWizard.ui")
myenv.Uic4("UserSearch/QtUserSearchFirstPage.ui")
@@ -215,12 +230,12 @@ if env["PLATFORM"] == "darwin" :
if env["HAVE_GROWL"] :
frameworks.append(env["GROWL_FRAMEWORK"])
commonResources[""] = commonResources.get("", []) + ["../resources/MacOSX/Swift.icns"]
- app = myenv.AppBundle("Swift", version = myenv["SWIFT_VERSION"], resources = commonResources, frameworks = frameworks)
+ app = myenv.AppBundle("Swift", version = myenv["SWIFT_VERSION"], resources = commonResources, frameworks = frameworks, handlesXMPPURIs = True)
if env["DIST"] :
myenv.Command(["Swift-${SWIFT_VERSION}.dmg"], [app], ["Swift/Packaging/MacOSX/package.sh " + app.path + " Swift/Packaging/MacOSX/Swift.dmg.gz $TARGET $QTDIR"])
if env.get("SWIFT_INSTALLDIR", "") :
- env.Install(os.path.join(env["SWIFT_INSTALLDIR"], "bin"), swiftProgram)
+ env.Install(os.path.join(env["SWIFT_INSTALLDIR"], "bin"), swiftProgram + openURIProgram)
env.InstallAs(os.path.join(env["SWIFT_INSTALLDIR"], "share", "pixmaps", "swift.xpm"), "../resources/logo/logo-icon-32.xpm")
icons_path = os.path.join(env["SWIFT_INSTALLDIR"], "share", "icons", "hicolor")
env.InstallAs(os.path.join(icons_path, "32x32", "apps", "swift.xpm"), "../resources/logo/logo-icon-32.xpm")
diff --git a/Swift/QtUI/swift-open-uri.cpp b/Swift/QtUI/swift-open-uri.cpp
new file mode 100644
index 0000000..2d5ef19
--- /dev/null
+++ b/Swift/QtUI/swift-open-uri.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <QCoreApplication>
+#include <QDBusConnection>
+#include <QDBusMessage>
+#include <iostream>
+
+int main(int argc, char* argv[]) {
+ QCoreApplication app(argc, argv);
+
+ QDBusConnection bus = QDBusConnection::sessionBus();
+ if (!bus.isConnected()) {
+ return -1;
+ }
+ if (argc != 2) {
+ std::cerr << "Usage: " << argv[0] << " uri" << std::endl;
+ return -1;
+ }
+
+ QDBusMessage msg = QDBusMessage::createMethodCall("im.swift.Swift.URIHandler", "/", "im.swift.Swift.URIHandler", "openURI");
+ msg << argv[1];
+
+ bus.call(msg);
+
+ return 0;
+}
diff --git a/Swift/Translations/swift_nl.ts b/Swift/Translations/swift_nl.ts
index 0683260..7e8bfbd 100644
--- a/Swift/Translations/swift_nl.ts
+++ b/Swift/Translations/swift_nl.ts
@@ -416,6 +416,22 @@
<source>There was an error publishing your profile data</source>
<translation>Er is een fout opgetreden bij het publiceren van uw profiel</translation>
</message>
+ <message>
+ <source>%1% (%2%)</source>
+ <translation>%1% (%2%)</translation>
+ </message>
+ <message>
+ <source>%1% and %2% others (%3%)</source>
+ <translation>%1% en %2% anderen (%3%)</translation>
+ </message>
+ <message>
+ <source>%1%, %2% (%3%)</source>
+ <translation>%1%, %2% (%3%)</translation>
+ </message>
+ <message>
+ <source>User address invalid. User address should be of the form &apos;alice@wonderland.lit&apos;</source>
+ <translation>Gebruikersadres ongeldig. Gebruikersadres moet van de vorm &apos;alice@wonderland.lit&apos; zijn</translation>
+ </message>
</context>
<context>
<name>CloseButton</name>
@@ -835,6 +851,10 @@
<source>Bookmarked Rooms</source>
<translation>Bladwijzers</translation>
</message>
+ <message>
+ <source>Recent Chats</source>
+ <translation>Recente conversaties</translation>
+ </message>
</context>
<context>
<name>Swift::QtAboutWidget</name>
@@ -866,6 +886,37 @@
</message>
</context>
<context>
+ <name>Swift::QtAdHocCommandWindow</name>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuleren</translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>Terug</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>Volgende</translation>
+ </message>
+ <message>
+ <source>Complete</source>
+ <translation>Voltooien</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation>Fout: %1</translation>
+ </message>
+ <message>
+ <source>Warning: %1</source>
+ <translation>Waarschuwing: %1</translation>
+ </message>
+ <message>
+ <source>Error executing command</source>
+ <translation>Fout bij het uitvoeren van de opdracht</translation>
+ </message>
+</context>
+<context>
<name>Swift::QtAvatarWidget</name>
<message>
<source>No picture</source>
@@ -1161,6 +1212,18 @@ afbeelding</translation>
<source>Enter &amp;Room</source>
<translation>&amp;Kamer betreden</translation>
</message>
+ <message>
+ <source>Run Server Command</source>
+ <translation>Voer opdracht op server uit</translation>
+ </message>
+ <message>
+ <source>Collecting commands...</source>
+ <translation>Opdrachten aan het verzamelen...</translation>
+ </message>
+ <message>
+ <source>No Available Commands</source>
+ <translation>Geen beschikbare opdrachten</translation>
+ </message>
</context>
<context>
<name>Swift::QtNameWidget</name>
diff --git a/Swiften/AdHoc/OutgoingAdHocCommandSession.cpp b/Swiften/AdHoc/OutgoingAdHocCommandSession.cpp
new file mode 100644
index 0000000..da7f042
--- /dev/null
+++ b/Swiften/AdHoc/OutgoingAdHocCommandSession.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2010-2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/AdHoc/OutgoingAdHocCommandSession.h>
+
+#include <boost/bind.hpp>
+
+#include <Swiften/Queries/GenericRequest.h>
+
+namespace Swift {
+OutgoingAdHocCommandSession::OutgoingAdHocCommandSession(const DiscoItems::Item& command, AdHocCommandWindowFactory* /*factory*/, IQRouter* iqRouter) : command_(command), iqRouter_(iqRouter), isMultiStage_(false) {
+
+}
+
+void OutgoingAdHocCommandSession::handleResponse(boost::shared_ptr<Command> payload, ErrorPayload::ref error) {
+ if (error) {
+ onError(error);
+ } else {
+ const std::vector<Command::Action> actions = payload->getAvailableActions();
+ actionStates_.clear();
+ if (payload->getStatus() == Command::Executing ) {
+ actionStates_[Command::Cancel] = EnabledAndPresent;
+ actionStates_[Command::Complete] = Present;
+ if (std::find(actions.begin(), actions.end(), Command::Complete) != actions.end()) {
+ actionStates_[Command::Complete] = EnabledAndPresent;
+ }
+
+ if (getIsMultiStage()) {
+ actionStates_[Command::Next] = Present;
+ actionStates_[Command::Prev] = Present;
+ }
+
+ if (std::find(actions.begin(), actions.end(), Command::Next) != actions.end()) {
+ actionStates_[Command::Next] = EnabledAndPresent;
+ }
+ if (std::find(actions.begin(), actions.end(), Command::Prev) != actions.end()) {
+ actionStates_[Command::Prev] = EnabledAndPresent;
+ }
+ }
+
+ sessionID_ = payload->getSessionID();
+ if (std::find(actions.begin(), actions.end(), Command::Next) != actions.end()
+ || std::find(actions.begin(), actions.end(), Command::Prev) != actions.end()) {
+ isMultiStage_ = true;
+ }
+ onNextStageReceived(payload);
+ }
+}
+
+bool OutgoingAdHocCommandSession::getIsMultiStage() {
+ return isMultiStage_;
+}
+
+void OutgoingAdHocCommandSession::start() {
+ boost::shared_ptr<Payload> commandPayload(new Command(command_.getNode()));
+ boost::shared_ptr<GenericRequest<Command> > commandRequest(new GenericRequest<Command>(IQ::Set, command_.getJID(), commandPayload, iqRouter_));
+ commandRequest->onResponse.connect(boost::bind(&OutgoingAdHocCommandSession::handleResponse, this, _1, _2));
+ commandRequest->send();
+}
+
+void OutgoingAdHocCommandSession::cancel() {
+ if (!sessionID_.empty()) {
+ boost::shared_ptr<Payload> commandPayload(new Command(command_.getNode(), sessionID_, Command::Cancel));
+ boost::shared_ptr<GenericRequest<Command> > commandRequest(new GenericRequest<Command>(IQ::Set, command_.getJID(), commandPayload, iqRouter_));
+ commandRequest->onResponse.connect(boost::bind(&OutgoingAdHocCommandSession::handleResponse, this, _1, _2));
+ commandRequest->send();
+ }
+}
+
+void OutgoingAdHocCommandSession::goBack() {
+ boost::shared_ptr<Payload> commandPayload(new Command(command_.getNode(), sessionID_, Command::Prev));
+ boost::shared_ptr<GenericRequest<Command> > commandRequest(new GenericRequest<Command>(IQ::Set, command_.getJID(), commandPayload, iqRouter_));
+ commandRequest->onResponse.connect(boost::bind(&OutgoingAdHocCommandSession::handleResponse, this, _1, _2));
+ commandRequest->send();
+}
+
+void OutgoingAdHocCommandSession::complete(Form::ref form) {
+ Command* command = new Command(command_.getNode(), sessionID_, Command::Complete);
+ boost::shared_ptr<Payload> commandPayload(command);
+ command->setForm(form);
+ boost::shared_ptr<GenericRequest<Command> > commandRequest(new GenericRequest<Command>(IQ::Set, command_.getJID(), commandPayload, iqRouter_));
+ commandRequest->onResponse.connect(boost::bind(&OutgoingAdHocCommandSession::handleResponse, this, _1, _2));
+ commandRequest->send();
+}
+
+void OutgoingAdHocCommandSession::goNext(Form::ref form) {
+ Command* command = new Command(command_.getNode(), sessionID_, Command::Next);
+ boost::shared_ptr<Payload> commandPayload(command);
+ command->setForm(form);
+ boost::shared_ptr<GenericRequest<Command> > commandRequest(new GenericRequest<Command>(IQ::Set, command_.getJID(), commandPayload, iqRouter_));
+ commandRequest->onResponse.connect(boost::bind(&OutgoingAdHocCommandSession::handleResponse, this, _1, _2));
+ commandRequest->send();
+}
+
+OutgoingAdHocCommandSession::ActionState OutgoingAdHocCommandSession::getActionState(Command::Action action) {
+ return actionStates_[action];
+}
+
+}
diff --git a/Swiften/AdHoc/OutgoingAdHocCommandSession.h b/Swiften/AdHoc/OutgoingAdHocCommandSession.h
new file mode 100644
index 0000000..f4b5242
--- /dev/null
+++ b/Swiften/AdHoc/OutgoingAdHocCommandSession.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2010-2011 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/boost_bsignals.h>
+#include <boost/shared_ptr.hpp>
+#include <Swiften/Elements/DiscoItems.h>
+#include <Swiften/Elements/Command.h>
+#include <Swiften/Elements/ErrorPayload.h>
+
+namespace Swift {
+ class IQRouter;
+ class MainWindow;
+ class UIEventStream;
+ class AdHocCommandWindowFactory;
+ class OutgoingAdHocCommandSession {
+ public:
+
+ /**
+ * Availability of action.
+ */
+ enum ActionState {
+ Absent /** Action isn't applicable to this command. */ = 0,
+ Present /** Action is applicable to this command */= 1,
+ Enabled /** Action is applicable and currently available */ = 2,
+ EnabledAndPresent = 3};
+
+ OutgoingAdHocCommandSession(const DiscoItems::Item& command, AdHocCommandWindowFactory* factory, IQRouter* iqRouter);
+ /**
+ * Send initial request to the target.
+ */
+ void start();
+ /**
+ * Cancel command session with the target.
+ */
+ void cancel();
+ /**
+ * Return to the previous stage.
+ */
+ void goBack();
+ /**
+ * Send the form to complete the command.
+ * \param form Form for submission - if missing the command will be submitted with no form.
+ */
+ void complete(Form::ref form);
+ /**
+ * Send the form to advance to the next stage of the command.
+ * \param form Form for submission - if missing the command will be submitted with no form.
+ */
+ void goNext(Form::ref form);
+
+ /**
+ * Is the form multi-stage?
+ */
+ bool getIsMultiStage();
+
+ /**
+ * Emitted when the form for the next stage is available.
+ */
+ boost::signal<void (Command::ref)> onNextStageReceived;
+
+ /**
+ * Emitted on error.
+ */
+ boost::signal<void (ErrorPayload::ref)> onError;
+
+ /**
+ * Get the state of a given action.
+ * This is useful for a UI to determine which buttons should be visible,
+ * and which enabled.
+ * Use for Next, Prev, Cancel and Complete only.
+ * If no actions are available, the command has completed.
+ */
+ ActionState getActionState(Command::Action action);
+ private:
+ void handleResponse(boost::shared_ptr<Command> payload, ErrorPayload::ref error);
+ private:
+ DiscoItems::Item command_;
+ IQRouter* iqRouter_;
+ bool isMultiStage_;
+ std::string sessionID_;
+ std::map<Command::Action, ActionState> actionStates_;
+ };
+}
diff --git a/Swiften/AdHoc/SConscript b/Swiften/AdHoc/SConscript
new file mode 100644
index 0000000..69c9083
--- /dev/null
+++ b/Swiften/AdHoc/SConscript
@@ -0,0 +1,6 @@
+Import("swiften_env")
+
+objects = swiften_env.SwiftenObject([
+ "OutgoingAdHocCommandSession.cpp",
+ ])
+swiften_env.Append(SWIFTEN_OBJECTS = [objects])
diff --git a/Swiften/Avatars/AvatarManager.h b/Swiften/Avatars/AvatarManager.h
index e1af451..3461973 100644
--- a/Swiften/Avatars/AvatarManager.h
+++ b/Swiften/Avatars/AvatarManager.h
@@ -6,7 +6,7 @@
#pragma once
-#include <boost/filesystem.hpp>
+#include <boost/filesystem/path.hpp>
#include <Swiften/Base/boost_bsignals.h>
#include <Swiften/Base/ByteArray.h>
diff --git a/Swiften/Avatars/AvatarProvider.h b/Swiften/Avatars/AvatarProvider.h
index 0f66904..d2d408e 100644
--- a/Swiften/Avatars/AvatarProvider.h
+++ b/Swiften/Avatars/AvatarProvider.h
@@ -6,9 +6,10 @@
#pragma once
-#include "Swiften/Base/boost_bsignals.h"
#include <string>
+#include <Swiften/Base/boost_bsignals.h>
+
namespace Swift {
class JID;
diff --git a/Swiften/Avatars/AvatarStorage.h b/Swiften/Avatars/AvatarStorage.h
index 48fc885..d1aff39 100644
--- a/Swiften/Avatars/AvatarStorage.h
+++ b/Swiften/Avatars/AvatarStorage.h
@@ -6,7 +6,7 @@
#pragma once
-#include <boost/filesystem.hpp>
+#include <boost/filesystem/path.hpp>
#include <string>
namespace Swift {
diff --git a/Swiften/Avatars/SConscript b/Swiften/Avatars/SConscript
index 46ae897..9c219a4 100644
--- a/Swiften/Avatars/SConscript
+++ b/Swiften/Avatars/SConscript
@@ -1,7 +1,6 @@
Import("swiften_env")
objects = swiften_env.SwiftenObject([
- "AvatarFileStorage.cpp",
"VCardUpdateAvatarManager.cpp",
"VCardAvatarManager.cpp",
"OfflineAvatarManager.cpp",
diff --git a/Swiften/Avatars/VCardAvatarManager.h b/Swiften/Avatars/VCardAvatarManager.h
index 3f99dad..6c02ace 100644
--- a/Swiften/Avatars/VCardAvatarManager.h
+++ b/Swiften/Avatars/VCardAvatarManager.h
@@ -6,11 +6,8 @@
#pragma once
-#include <map>
-
#include "Swiften/Avatars/AvatarProvider.h"
#include "Swiften/JID/JID.h"
-#include "Swiften/Elements/VCard.h"
namespace Swift {
class MUCRegistry;
diff --git a/Swiften/Base/ByteArray.cpp b/Swiften/Base/ByteArray.cpp
index 928e145..323c866 100644
--- a/Swiften/Base/ByteArray.cpp
+++ b/Swiften/Base/ByteArray.cpp
@@ -9,6 +9,10 @@
#include <fstream>
std::ostream& operator<<(std::ostream& os, const Swift::ByteArray& s) {
+ return operator<<(os, s.getDataVector());
+}
+
+std::ostream& operator<<(std::ostream& os, const std::vector<unsigned char>& s) {
std::ios::fmtflags oldFlags = os.flags();
os << std::hex;
for (Swift::ByteArray::const_iterator i = s.begin(); i != s.end(); ++i) {
@@ -37,4 +41,45 @@ void ByteArray::readFromFile(const std::string& file) {
input.close();
}
+std::vector<unsigned char> ByteArray::create(const std::string& s) {
+ return std::vector<unsigned char>(s.begin(), s.end());
+}
+
+std::vector<unsigned char> ByteArray::create(const char* c) {
+ std::vector<unsigned char> data;
+ while (*c) {
+ data.push_back(static_cast<unsigned char>(*c));
+ ++c;
+ }
+ return data;
+}
+
+std::vector<unsigned char> ByteArray::create(const char* c, size_t n) {
+ std::vector<unsigned char> data;
+ if (n > 0) {
+ data.resize(n);
+ memcpy(&data[0], c, n);
+ }
+ return data;
+}
+
+std::vector<unsigned char> ByteArray::create(const unsigned char* c, size_t n) {
+ std::vector<unsigned char> data;
+ if (n > 0) {
+ data.resize(n);
+ memcpy(&data[0], c, n);
+ }
+ return data;
+}
+
+std::string ByteArray::toString() const {
+ size_t i;
+ for (i = data_.size(); i > 0; --i) {
+ if (data_[i - 1] != 0) {
+ break;
+ }
+ }
+ return i > 0 ? std::string(reinterpret_cast<const char*>(getData()), i) : "";
+}
+
}
diff --git a/Swiften/Base/ByteArray.h b/Swiften/Base/ByteArray.h
index ad2c1e5..ebc22d8 100644
--- a/Swiften/Base/ByteArray.h
+++ b/Swiften/Base/ByteArray.h
@@ -6,11 +6,9 @@
#pragma once
-#include <cstring>
#include <vector>
-#include <iostream>
-
#include <string>
+#include <cstring> // for memcpy
namespace Swift {
class ByteArray
@@ -24,7 +22,7 @@ namespace Swift {
ByteArray(const char* c) {
while (*c) {
- data_.push_back(*c);
+ data_.push_back(static_cast<unsigned char>(*c));
++c;
}
}
@@ -75,7 +73,7 @@ namespace Swift {
}
void resize(size_t size, char c) {
- return data_.resize(size, c);
+ return data_.resize(size, static_cast<unsigned char>(c));
}
friend ByteArray operator+(const ByteArray& a, const ByteArray&b) {
@@ -87,7 +85,7 @@ namespace Swift {
friend ByteArray operator+(const ByteArray& a, char b) {
ByteArray x;
x.resize(1);
- x[0] = b;
+ x[0] = static_cast<unsigned char>(b);
return a + x;
}
@@ -97,7 +95,7 @@ namespace Swift {
}
ByteArray& operator+=(char c) {
- data_.push_back(c);
+ data_.push_back(static_cast<unsigned char>(c));
return *this;
}
@@ -122,9 +120,7 @@ namespace Swift {
return data_.end();
}
- std::string toString() const {
- return std::string(reinterpret_cast<const char*>(getData()), getSize());
- }
+ std::string toString() const;
void readFromFile(const std::string& file);
@@ -132,9 +128,27 @@ namespace Swift {
data_.clear();
}
+ const std::vector<unsigned char>& getDataVector() const {
+ return data_;
+ }
+
+ static std::vector<unsigned char> create(const std::string& s);
+ static std::vector<unsigned char> create(const char* c);
+ static std::vector<unsigned char> create(const unsigned char* c, size_t n);
+ static std::vector<unsigned char> create(const char* c, size_t n);
+
+ static const unsigned char* data(const std::vector<unsigned char>& v) {
+ return v.empty() ? NULL : &v[0];
+ }
+
+ static const char* charData(const std::vector<unsigned char>& v) {
+ return v.empty() ? NULL : reinterpret_cast<const char*>(&v[0]);
+ }
+
private:
std::vector<unsigned char> data_;
};
}
std::ostream& operator<<(std::ostream& os, const Swift::ByteArray& s);
+std::ostream& operator<<(std::ostream& os, const std::vector<unsigned char>& s);
diff --git a/Swiften/Base/IDGenerator.h b/Swiften/Base/IDGenerator.h
index 4b6289b..d536dcc 100644
--- a/Swiften/Base/IDGenerator.h
+++ b/Swiften/Base/IDGenerator.h
@@ -4,8 +4,7 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#ifndef SWIFTEN_IDGenerator_H
-#define SWIFTEN_IDGenerator_H
+#pragma once
#include <string>
@@ -20,5 +19,3 @@ namespace Swift {
std::string currentID_;
};
}
-
-#endif
diff --git a/Swiften/Base/Paths.cpp b/Swiften/Base/Paths.cpp
index 43eee57..d901ff9 100644
--- a/Swiften/Base/Paths.cpp
+++ b/Swiften/Base/Paths.cpp
@@ -25,7 +25,7 @@ boost::filesystem::path Paths::getExecutablePath() {
uint32_t size = 4096;
path.resize(size);
if (_NSGetExecutablePath(reinterpret_cast<char*>(path.getData()), &size) == 0) {
- return boost::filesystem::path(path.toString().c_str()).parent_path();
+ return boost::filesystem::path(std::string(reinterpret_cast<const char*>(path.getData()), path.getSize()).c_str()).parent_path();
}
#elif defined(SWIFTEN_PLATFORM_LINUX)
ByteArray path;
@@ -33,13 +33,13 @@ boost::filesystem::path Paths::getExecutablePath() {
size_t size = readlink("/proc/self/exe", reinterpret_cast<char*>(path.getData()), path.getSize());
if (size > 0) {
path.resize(size);
- return boost::filesystem::path(path.toString().c_str()).parent_path();
+ return boost::filesystem::path(std::string(reinterpret_cast<const char*>(path.getData()), path.getSize()).c_str()).parent_path();
}
#elif defined(SWIFTEN_PLATFORM_WINDOWS)
ByteArray data;
data.resize(2048);
GetModuleFileName(NULL, reinterpret_cast<char*>(data.getData()), data.getSize());
- return boost::filesystem::path(data.toString().c_str()).parent_path();
+ return boost::filesystem::path(std::string(reinterpret_cast<const char*>(data.getData()), data.getSize()).c_str()).parent_path();
#endif
return boost::filesystem::path();
}
diff --git a/Swiften/Base/Paths.h b/Swiften/Base/Paths.h
index 06c6aeb..8ac4640 100644
--- a/Swiften/Base/Paths.h
+++ b/Swiften/Base/Paths.h
@@ -6,7 +6,7 @@
#pragma once
-#include <boost/filesystem.hpp>
+#include <boost/filesystem/path.hpp>
namespace Swift {
class Paths {
diff --git a/Swiften/Base/Platform.h b/Swiften/Base/Platform.h
index 32e2671..395747c 100644
--- a/Swiften/Base/Platform.h
+++ b/Swiften/Base/Platform.h
@@ -4,8 +4,7 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#ifndef SWIFTEN_Platform_H
-#define SWIFTEN_Platform_H
+#pragma once
// Base platforms
#if defined(linux) || defined(__linux) || defined(__linux__)
@@ -26,6 +25,10 @@
#define SWIFTEN_PLATFORM_BEOS
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
#define SWIFTEN_PLATFORM_MACOSX
+#include <TargetConditionals.h>
+# if defined(TARGET_OS_IPHONE)
+# define SWIFTEN_PLATFORM_IPHONE
+# endif
#elif defined(__IBMCPP__) || defined(_AIX)
#define SWIFTEN_PLATFORM_AIX
#elif defined(__amigaos__)
@@ -46,5 +49,3 @@
#elif defined(BOOST_BIG_ENDIAN)
#define SWIFTEN_BIG_ENDIAN
#endif
-
-#endif
diff --git a/Swiften/Base/String.h b/Swiften/Base/String.h
index 192d53b..0de6cac 100644
--- a/Swiften/Base/String.h
+++ b/Swiften/Base/String.h
@@ -6,7 +6,6 @@
#pragma once
-#include <map>
#include <string>
#include <vector>
diff --git a/Swiften/Base/UnitTest/ByteArrayTest.cpp b/Swiften/Base/UnitTest/ByteArrayTest.cpp
index cb10dd4..069e68e 100644
--- a/Swiften/Base/UnitTest/ByteArrayTest.cpp
+++ b/Swiften/Base/UnitTest/ByteArrayTest.cpp
@@ -8,12 +8,17 @@
#include <cppunit/extensions/TestFactoryRegistry.h>
#include "Swiften/Base/ByteArray.h"
+#include <boost/lexical_cast.hpp>
using namespace Swift;
class ByteArrayTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(ByteArrayTest);
CPPUNIT_TEST(testGetData_NoData);
+ CPPUNIT_TEST(testToString);
+ CPPUNIT_TEST(testToString_NullTerminated);
+ CPPUNIT_TEST(testToString_TwoNullTerminated);
+ CPPUNIT_TEST(testToString_AllNull);
CPPUNIT_TEST_SUITE_END();
public:
@@ -22,6 +27,30 @@ class ByteArrayTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT_EQUAL(reinterpret_cast<const char*>(NULL), reinterpret_cast<const char*>(testling.getData()));
}
+
+ void testToString() {
+ ByteArray testling(ByteArray::create("abcde"));
+
+ CPPUNIT_ASSERT_EQUAL(std::string("abcde"), testling.toString());
+ }
+
+ void testToString_NullTerminated() {
+ ByteArray testling(ByteArray::create("abcde\0", 6));
+
+ CPPUNIT_ASSERT_EQUAL(std::string("abcde"), testling.toString());
+ }
+
+ void testToString_TwoNullTerminated() {
+ ByteArray testling(ByteArray::create("abcde\0\0", 7));
+
+ CPPUNIT_ASSERT_EQUAL(std::string("abcde"), testling.toString());
+ }
+
+ void testToString_AllNull() {
+ ByteArray testling(ByteArray::create("\0\0", 2));
+
+ CPPUNIT_ASSERT_EQUAL(std::string(""), testling.toString());
+ }
};
CPPUNIT_TEST_SUITE_REGISTRATION(ByteArrayTest);
diff --git a/Swiften/Base/foreach.h b/Swiften/Base/foreach.h
index 05366d6..87f6147 100644
--- a/Swiften/Base/foreach.h
+++ b/Swiften/Base/foreach.h
@@ -4,12 +4,9 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#ifndef SWIFTEN_FOREACH_H
-#define SWIFTEN_FOREACH_H
+#pragma once
#include <boost/foreach.hpp>
#undef foreach
#define foreach BOOST_FOREACH
-
-#endif
diff --git a/Swiften/Base/format.h b/Swiften/Base/format.h
index 4591827..0e49eaa 100644
--- a/Swiften/Base/format.h
+++ b/Swiften/Base/format.h
@@ -7,6 +7,7 @@
#pragma once
#include <boost/format.hpp>
+#include <iostream>
namespace Swift {
inline boost::format format(const std::string& s) {
diff --git a/Swiften/Base/sleep.h b/Swiften/Base/sleep.h
index c2bc601..a95e907 100644
--- a/Swiften/Base/sleep.h
+++ b/Swiften/Base/sleep.h
@@ -4,11 +4,8 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#ifndef SWIFTEN_sleep_H
-#define SWIFTEN_sleep_H
+#pragma once
namespace Swift {
void sleep(unsigned int msecs);
}
-
-#endif
diff --git a/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp b/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp
index 5d7961b..aa16892 100644
--- a/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp
+++ b/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp
@@ -8,6 +8,7 @@
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <boost/bind.hpp>
+#include <Swiften/Base/foreach.h>
#include "Swiften/Chat/ChatStateNotifier.h"
#include "Swiften/Client/DummyStanzaChannel.h"
#include "Swiften/Disco/DummyEntityCapsProvider.h"
diff --git a/Swiften/Client/Client.cpp b/Swiften/Client/Client.cpp
index 7918c46..5a3450c 100644
--- a/Swiften/Client/Client.cpp
+++ b/Swiften/Client/Client.cpp
@@ -25,6 +25,7 @@
#include "Swiften/Presence/SubscriptionManager.h"
#include "Swiften/TLS/BlindCertificateTrustChecker.h"
#include <Swiften/Client/NickManagerImpl.h>
+#include <Swiften/Client/ClientSession.h>
namespace Swift {
@@ -35,7 +36,7 @@ Client::Client(const JID& jid, const std::string& password, NetworkFactories* ne
softwareVersionResponder->start();
roster = new XMPPRosterImpl();
- rosterController = new XMPPRosterController(getIQRouter(), roster);
+ rosterController = new XMPPRosterController(getIQRouter(), roster, getStorages()->getRosterStorage());
subscriptionManager = new SubscriptionManager(getStanzaChannel());
@@ -98,6 +99,11 @@ void Client::setSoftwareVersion(const std::string& name, const std::string& vers
}
void Client::requestRoster() {
+ // FIXME: We should set this once when the session is finished, but there
+ // is currently no callback for this
+ if (getSession()) {
+ rosterController->setUseVersioning(getSession()->getRosterVersioningSupported());
+ }
rosterController->requestRoster();
}
diff --git a/Swiften/Client/Client.h b/Swiften/Client/Client.h
index 083b8a0..05c1e6e 100644
--- a/Swiften/Client/Client.h
+++ b/Swiften/Client/Client.h
@@ -6,7 +6,7 @@
#pragma once
-#include "Swiften/Client/CoreClient.h"
+#include <Swiften/Client/CoreClient.h>
namespace Swift {
class SoftwareVersionResponder;
@@ -85,12 +85,12 @@ namespace Swift {
/**
* Returns the last received presence for the given (full) JID.
*/
- Presence::ref getLastPresence(const JID& jid) const;
+ boost::shared_ptr<Presence> getLastPresence(const JID& jid) const;
/**
* Returns the presence with the highest priority received for the given JID.
*/
- Presence::ref getHighestPriorityPresence(const JID& bareJID) const;
+ boost::shared_ptr<Presence> getHighestPriorityPresence(const JID& bareJID) const;
PresenceOracle* getPresenceOracle() const {
return presenceOracle;
@@ -142,7 +142,7 @@ namespace Swift {
/**
* This signal is emitted when a JID changes presence.
*/
- boost::signal<void (Presence::ref)> onPresenceChange;
+ boost::signal<void (boost::shared_ptr<Presence>)> onPresenceChange;
private:
Storages* getStorages() const;
diff --git a/Swiften/Client/ClientOptions.h b/Swiften/Client/ClientOptions.h
new file mode 100644
index 0000000..1155b46
--- /dev/null
+++ b/Swiften/Client/ClientOptions.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+struct ClientOptions {
+ enum UseTLS {
+ NeverUseTLS,
+ UseTLSWhenAvailable
+ };
+
+ ClientOptions() : useStreamCompression(true), useTLS(UseTLSWhenAvailable), useStreamResumption(false) {
+ }
+
+ /**
+ * Whether ZLib stream compression should be used when available.
+ *
+ * Default: true
+ */
+ bool useStreamCompression;
+
+ /**
+ * Sets whether TLS encryption should be used.
+ *
+ * Default: UseTLSWhenAvailable
+ */
+ UseTLS useTLS;
+
+ /**
+ * Use XEP-196 stream resumption when available.
+ *
+ * Default: false
+ */
+ bool useStreamResumption;
+};
+
diff --git a/Swiften/Client/ClientSession.cpp b/Swiften/Client/ClientSession.cpp
index e1c1d8e..cadc9a4 100644
--- a/Swiften/Client/ClientSession.cpp
+++ b/Swiften/Client/ClientSession.cpp
@@ -54,6 +54,7 @@ ClientSession::ClientSession(
needSessionStart(false),
needResourceBind(false),
needAcking(false),
+ rosterVersioningSupported(false),
authenticator(NULL),
certificateTrustChecker(NULL) {
}
@@ -223,6 +224,7 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) {
}
else {
// Start the session
+ rosterVersioningSupported = streamFeatures->hasRosterVersioning();
stream->setWhitespacePingEnabled(true);
needSessionStart = streamFeatures->hasSession();
needResourceBind = streamFeatures->hasResourceBind();
diff --git a/Swiften/Client/ClientSession.h b/Swiften/Client/ClientSession.h
index 25ee694..4447f57 100644
--- a/Swiften/Client/ClientSession.h
+++ b/Swiften/Client/ClientSession.h
@@ -89,6 +89,10 @@ namespace Swift {
return stanzaAckRequester_;
}
+ bool getRosterVersioningSupported() const {
+ return rosterVersioningSupported;
+ }
+
const JID& getLocalJID() const {
return localJID;
}
@@ -153,6 +157,7 @@ namespace Swift {
bool needSessionStart;
bool needResourceBind;
bool needAcking;
+ bool rosterVersioningSupported;
ClientAuthenticator* authenticator;
boost::shared_ptr<StanzaAckRequester> stanzaAckRequester_;
boost::shared_ptr<StanzaAckResponder> stanzaAckResponder_;
diff --git a/Swiften/Client/ClientSessionStanzaChannel.cpp b/Swiften/Client/ClientSessionStanzaChannel.cpp
index 6b32b3d..85d9dec 100644
--- a/Swiften/Client/ClientSessionStanzaChannel.cpp
+++ b/Swiften/Client/ClientSessionStanzaChannel.cpp
@@ -7,6 +7,7 @@
#include "Swiften/Client/ClientSessionStanzaChannel.h"
#include <boost/bind.hpp>
+#include <iostream>
namespace Swift {
diff --git a/Swiften/Client/ClientXMLTracer.cpp b/Swiften/Client/ClientXMLTracer.cpp
new file mode 100644
index 0000000..a26ce66
--- /dev/null
+++ b/Swiften/Client/ClientXMLTracer.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Client/ClientXMLTracer.h>
+
+#include <iostream>
+#include <boost/bind.hpp>
+
+namespace Swift {
+
+ClientXMLTracer::ClientXMLTracer(CoreClient* client) {
+ client->onDataRead.connect(boost::bind(&ClientXMLTracer::printData, '<', _1));
+ client->onDataWritten.connect(boost::bind(&ClientXMLTracer::printData, '>', _1));
+}
+
+void ClientXMLTracer::printData(char direction, const std::string& data) {
+ printLine(direction);
+ std::cerr << data << std::endl;
+}
+
+void ClientXMLTracer::printLine(char c) {
+ for (unsigned int i = 0; i < 80; ++i) {
+ std::cerr << c;
+ }
+ std::cerr << std::endl;
+}
+
+}
diff --git a/Swiften/Client/ClientXMLTracer.h b/Swiften/Client/ClientXMLTracer.h
index bca2a54..617c53f 100644
--- a/Swiften/Client/ClientXMLTracer.h
+++ b/Swiften/Client/ClientXMLTracer.h
@@ -6,29 +6,15 @@
#pragma once
-#include <boost/bind.hpp>
-
#include <Swiften/Client/CoreClient.h>
namespace Swift {
class ClientXMLTracer {
public:
- ClientXMLTracer(CoreClient* client) {
- client->onDataRead.connect(boost::bind(&ClientXMLTracer::printData, '<', _1));
- client->onDataWritten.connect(boost::bind(&ClientXMLTracer::printData, '>', _1));
- }
+ ClientXMLTracer(CoreClient* client);
private:
- static void printData(char direction, const std::string& data) {
- printLine(direction);
- std::cerr << data << std::endl;
- }
-
- static void printLine(char c) {
- for (unsigned int i = 0; i < 80; ++i) {
- std::cerr << c;
- }
- std::cerr << std::endl;
- }
+ static void printData(char direction, const std::string& data);
+ static void printLine(char c);
};
}
diff --git a/Swiften/Client/CoreClient.cpp b/Swiften/Client/CoreClient.cpp
index f0c5333..de40517 100644
--- a/Swiften/Client/CoreClient.cpp
+++ b/Swiften/Client/CoreClient.cpp
@@ -7,11 +7,12 @@
#include "Swiften/Client/CoreClient.h"
#include <boost/bind.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
#include "Swiften/Client/ClientSession.h"
#include "Swiften/TLS/PlatformTLSFactories.h"
#include "Swiften/TLS/CertificateVerificationError.h"
-#include "Swiften/Network/Connector.h"
+#include <Swiften/Network/ChainedConnector.h>
#include "Swiften/Network/NetworkFactories.h"
#include "Swiften/TLS/PKCS12Certificate.h"
#include "Swiften/Session/BasicSessionStream.h"
@@ -19,10 +20,14 @@
#include "Swiften/Base/IDGenerator.h"
#include "Swiften/Client/ClientSessionStanzaChannel.h"
#include <Swiften/Base/Log.h>
+#include <Swiften/Base/foreach.h>
+#include "Swiften/Network/PlatformProxyProvider.h"
+#include "Swiften/Network/SOCKS5ProxiedConnectionFactory.h"
+#include "Swiften/Network/HTTPConnectProxiedConnectionFactory.h"
namespace Swift {
-CoreClient::CoreClient(const JID& jid, const std::string& password, NetworkFactories* networkFactories) : jid_(jid), password_(password), networkFactories(networkFactories), useStreamCompression(true), useTLS(UseTLSWhenAvailable), disconnectRequested_(false), certificateTrustChecker(NULL) {
+CoreClient::CoreClient(const JID& jid, const std::string& password, NetworkFactories* networkFactories) : jid_(jid), password_(password), networkFactories(networkFactories), disconnectRequested_(false), certificateTrustChecker(NULL) {
stanzaChannel_ = new ClientSessionStanzaChannel();
stanzaChannel_->onMessageReceived.connect(boost::bind(&CoreClient::handleMessageReceived, this, _1));
stanzaChannel_->onPresenceReceived.connect(boost::bind(&CoreClient::handlePresenceReceived, this, _1));
@@ -47,8 +52,9 @@ CoreClient::~CoreClient() {
delete stanzaChannel_;
}
-void CoreClient::connect() {
+void CoreClient::connect(const ClientOptions& o) {
SWIFT_LOG(debug) << "Connecting" << std::endl;
+ options = o;
connect(jid_.getDomain());
}
@@ -56,7 +62,19 @@ void CoreClient::connect(const std::string& host) {
SWIFT_LOG(debug) << "Connecting to host " << host << std::endl;
disconnectRequested_ = false;
assert(!connector_);
- connector_ = Connector::create(host, networkFactories->getDomainNameResolver(), networkFactories->getConnectionFactory(), networkFactories->getTimerFactory());
+
+ assert(proxyConnectionFactories.empty());
+ PlatformProxyProvider proxyProvider;
+ if(proxyProvider.getSOCKS5Proxy().isValid()) {
+ proxyConnectionFactories.push_back(new SOCKS5ProxiedConnectionFactory(networkFactories->getConnectionFactory(), proxyProvider.getSOCKS5Proxy()));
+ }
+ if(proxyProvider.getHTTPConnectProxy().isValid()) {
+ proxyConnectionFactories.push_back(new HTTPConnectProxiedConnectionFactory(networkFactories->getConnectionFactory(), proxyProvider.getHTTPConnectProxy()));
+ }
+ std::vector<ConnectionFactory*> connectionFactories(proxyConnectionFactories);
+ connectionFactories.push_back(networkFactories->getConnectionFactory());
+
+ connector_ = boost::make_shared<ChainedConnector>(host, networkFactories->getDomainNameResolver(), connectionFactories, networkFactories->getTimerFactory());
connector_->onConnectFinished.connect(boost::bind(&CoreClient::handleConnectorFinished, this, _1));
connector_->setTimeoutMilliseconds(60*1000);
connector_->start();
@@ -65,6 +83,10 @@ void CoreClient::connect(const std::string& host) {
void CoreClient::handleConnectorFinished(boost::shared_ptr<Connection> connection) {
connector_->onConnectFinished.disconnect(boost::bind(&CoreClient::handleConnectorFinished, this, _1));
connector_.reset();
+ foreach(ConnectionFactory* f, proxyConnectionFactories) {
+ delete f;
+ }
+
if (!connection) {
onDisconnected(disconnectRequested_ ? boost::optional<ClientError>() : boost::optional<ClientError>(ClientError::ConnectionError));
}
@@ -82,12 +104,12 @@ void CoreClient::handleConnectorFinished(boost::shared_ptr<Connection> connectio
session_ = ClientSession::create(jid_, sessionStream_);
session_->setCertificateTrustChecker(certificateTrustChecker);
- session_->setUseStreamCompression(useStreamCompression);
- switch(useTLS) {
- case UseTLSWhenAvailable:
+ session_->setUseStreamCompression(options.useStreamCompression);
+ switch(options.useTLS) {
+ case ClientOptions::UseTLSWhenAvailable:
session_->setUseTLS(ClientSession::UseTLSWhenAvailable);
break;
- case NeverUseTLS:
+ case ClientOptions::NeverUseTLS:
session_->setUseTLS(ClientSession::NeverUseTLS);
break;
}
@@ -275,13 +297,25 @@ void CoreClient::handleStanzaAcked(Stanza::ref stanza) {
onStanzaAcked(stanza);
}
-void CoreClient::setUseStreamCompression(bool b) {
- useStreamCompression = b;
+bool CoreClient::isAvailable() const {
+ return stanzaChannel_->isAvailable();
}
-void CoreClient::setUseTLS(UseTLS b) {
- useTLS = b;
+bool CoreClient::getStreamManagementEnabled() const {
+ return stanzaChannel_->getStreamManagementEnabled();
}
+StanzaChannel* CoreClient::getStanzaChannel() const {
+ return stanzaChannel_;
+}
+
+const JID& CoreClient::getJID() const {
+ if (session_) {
+ return session_->getLocalJID();
+ }
+ else {
+ return jid_;
+ }
+}
}
diff --git a/Swiften/Client/CoreClient.h b/Swiften/Client/CoreClient.h
index eb9c42c..7c46fe7 100644
--- a/Swiften/Client/CoreClient.h
+++ b/Swiften/Client/CoreClient.h
@@ -6,35 +6,33 @@
#pragma once
-#include "Swiften/Base/boost_bsignals.h"
+#include <string>
#include <boost/shared_ptr.hpp>
+#include <Swiften/Base/boost_bsignals.h>
-#include "Swiften/Network/PlatformDomainNameResolver.h"
-#include "Swiften/Network/Connector.h"
-#include "Swiften/Base/Error.h"
-#include "Swiften/Client/ClientSession.h"
-#include "Swiften/Client/ClientError.h"
-#include "Swiften/Elements/Presence.h"
-#include "Swiften/Elements/Message.h"
-#include "Swiften/JID/JID.h"
-#include <string>
-#include "Swiften/Client/StanzaChannel.h"
-#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h"
-#include "Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h"
#include <Swiften/Entity/Entity.h>
-
-#include "Swiften/Client/ClientSessionStanzaChannel.h"
+#include <Swiften/JID/JID.h>
+#include <Swiften/Client/ClientError.h>
+#include <Swiften/Client/ClientOptions.h>
namespace Swift {
+ class ChainedConnector;
+ class Message;
+ class Presence;
+ class Error;
class IQRouter;
class TLSContextFactory;
class ConnectionFactory;
+ class Connection;
class TimerFactory;
class ClientSession;
+ class StanzaChannel;
+ class Stanza;
class BasicSessionStream;
class PlatformTLSFactories;
class CertificateTrustChecker;
class NetworkFactories;
+ class ClientSessionStanzaChannel;
/**
* The central class for communicating with an XMPP server.
@@ -48,11 +46,6 @@ namespace Swift {
*/
class CoreClient : public Entity {
public:
- enum UseTLS {
- NeverUseTLS,
- UseTLSWhenAvailable
- };
-
/**
* Constructs a client for the given JID with the given password.
* The given eventLoop will be used to post events to.
@@ -68,7 +61,7 @@ namespace Swift {
* After the connection is established, the client will set
* initialize the stream and authenticate.
*/
- void connect();
+ void connect(const ClientOptions& = ClientOptions());
/**
* Disconnects the client from the server.
@@ -80,12 +73,12 @@ namespace Swift {
/**
* Sends a message.
*/
- void sendMessage(Message::ref);
+ void sendMessage(boost::shared_ptr<Message>);
/**
* Sends a presence stanza.
*/
- void sendPresence(Presence::ref);
+ void sendPresence(boost::shared_ptr<Presence>);
/**
* Sends raw, unchecked data.
@@ -103,9 +96,7 @@ namespace Swift {
* Checks whether the client is connected to the server,
* and stanzas can be sent.
*/
- bool isAvailable() const {
- return stanzaChannel_->isAvailable();
- }
+ bool isAvailable() const;
/**
* Checks whether the client is active.
@@ -118,14 +109,7 @@ namespace Swift {
* Returns the JID of the client.
* After the session was initialized, this returns the bound JID.
*/
- const JID& getJID() const {
- if (session_) {
- return session_->getLocalJID();
- }
- else {
- return jid_;
- }
- }
+ const JID& getJID() const;
/**
* Checks whether stream management is enabled.
@@ -135,13 +119,9 @@ namespace Swift {
*
* \see onStanzaAcked
*/
- bool getStreamManagementEnabled() const {
- return stanzaChannel_->getStreamManagementEnabled();
- }
+ bool getStreamManagementEnabled() const;
- StanzaChannel* getStanzaChannel() const {
- return stanzaChannel_;
- }
+ StanzaChannel* getStanzaChannel() const;
/**
* Sets the certificate trust checker.
@@ -153,16 +133,6 @@ namespace Swift {
*/
void setCertificateTrustChecker(CertificateTrustChecker*);
- /**
- * Sets whether ZLib stream compression should be used when available.
- */
- void setUseStreamCompression(bool b);
-
- /**
- * Sets whether TLS encryption should be used.
- */
- void setUseTLS(UseTLS useTLS);
-
public:
/**
* Emitted when the client was disconnected from the network.
@@ -197,12 +167,12 @@ namespace Swift {
/**
* Emitted when a message is received.
*/
- boost::signal<void (Message::ref)> onMessageReceived;
+ boost::signal<void (boost::shared_ptr<Message>)> onMessageReceived;
/**
* Emitted when a presence stanza is received.
*/
- boost::signal<void (Presence::ref) > onPresenceReceived;
+ boost::signal<void (boost::shared_ptr<Presence>) > onPresenceReceived;
/**
* Emitted when the server acknowledges receipt of a
@@ -210,7 +180,12 @@ namespace Swift {
*
* \see getStreamManagementEnabled()
*/
- boost::signal<void (Stanza::ref)> onStanzaAcked;
+ boost::signal<void (boost::shared_ptr<Stanza>)> onStanzaAcked;
+
+ protected:
+ boost::shared_ptr<ClientSession> getSession() const {
+ return session_;
+ }
private:
void handleConnectorFinished(boost::shared_ptr<Connection>);
@@ -219,19 +194,19 @@ namespace Swift {
void handleNeedCredentials();
void handleDataRead(const std::string&);
void handleDataWritten(const std::string&);
- void handlePresenceReceived(Presence::ref);
- void handleMessageReceived(Message::ref);
- void handleStanzaAcked(Stanza::ref);
+ void handlePresenceReceived(boost::shared_ptr<Presence>);
+ void handleMessageReceived(boost::shared_ptr<Message>);
+ void handleStanzaAcked(boost::shared_ptr<Stanza>);
private:
JID jid_;
std::string password_;
NetworkFactories* networkFactories;
- bool useStreamCompression;
- UseTLS useTLS;
ClientSessionStanzaChannel* stanzaChannel_;
IQRouter* iqRouter_;
- Connector::ref connector_;
+ ClientOptions options;
+ boost::shared_ptr<ChainedConnector> connector_;
+ std::vector<ConnectionFactory*> proxyConnectionFactories;
PlatformTLSFactories* tlsFactories;
boost::shared_ptr<Connection> connection_;
boost::shared_ptr<BasicSessionStream> sessionStream_;
diff --git a/Swiften/Client/DummyStanzaChannel.h b/Swiften/Client/DummyStanzaChannel.h
index b9f05c3..306e2b4 100644
--- a/Swiften/Client/DummyStanzaChannel.h
+++ b/Swiften/Client/DummyStanzaChannel.h
@@ -56,6 +56,22 @@ namespace Swift {
return iqStanza && iqStanza->getType() == type && iqStanza->getTo() == jid && iqStanza->getPayload<T>();
}
+ bool isResultAtIndex(size_t index, const std::string& id) {
+ if (index >= sentStanzas.size()) {
+ return false;
+ }
+ boost::shared_ptr<IQ> iqStanza = boost::dynamic_pointer_cast<IQ>(sentStanzas[index]);
+ return iqStanza && iqStanza->getType() == IQ::Result && iqStanza->getID() == id;
+ }
+
+ bool isErrorAtIndex(size_t index, const std::string& id) {
+ if (index >= sentStanzas.size()) {
+ return false;
+ }
+ boost::shared_ptr<IQ> iqStanza = boost::dynamic_pointer_cast<IQ>(sentStanzas[index]);
+ return iqStanza && iqStanza->getType() == IQ::Error && iqStanza->getID() == id;
+ }
+
template<typename T> boost::shared_ptr<T> getStanzaAtIndex(size_t index) {
if (sentStanzas.size() <= index) {
return boost::shared_ptr<T>();
diff --git a/Swiften/Client/MemoryStorages.cpp b/Swiften/Client/MemoryStorages.cpp
index 5f6371b..6941add 100644
--- a/Swiften/Client/MemoryStorages.cpp
+++ b/Swiften/Client/MemoryStorages.cpp
@@ -8,6 +8,7 @@
#include "Swiften/VCards/VCardMemoryStorage.h"
#include "Swiften/Avatars/AvatarMemoryStorage.h"
#include "Swiften/Disco/CapsMemoryStorage.h"
+#include "Swiften/Roster/RosterMemoryStorage.h"
namespace Swift {
@@ -15,9 +16,11 @@ MemoryStorages::MemoryStorages() {
vcardStorage = new VCardMemoryStorage();
capsStorage = new CapsMemoryStorage();
avatarStorage = new AvatarMemoryStorage();
+ rosterStorage = new RosterMemoryStorage();
}
MemoryStorages::~MemoryStorages() {
+ delete rosterStorage;
delete avatarStorage;
delete capsStorage;
delete vcardStorage;
@@ -35,4 +38,9 @@ AvatarStorage* MemoryStorages::getAvatarStorage() const {
return avatarStorage;
}
+RosterStorage* MemoryStorages::getRosterStorage() const {
+ return rosterStorage;
+}
+
+
}
diff --git a/Swiften/Client/MemoryStorages.h b/Swiften/Client/MemoryStorages.h
index 67025cd..1e1a596 100644
--- a/Swiften/Client/MemoryStorages.h
+++ b/Swiften/Client/MemoryStorages.h
@@ -23,10 +23,12 @@ namespace Swift {
virtual VCardStorage* getVCardStorage() const;
virtual AvatarStorage* getAvatarStorage() const;
virtual CapsStorage* getCapsStorage() const;
+ virtual RosterStorage* getRosterStorage() const;
private:
VCardMemoryStorage* vcardStorage;
AvatarStorage* avatarStorage;
CapsStorage* capsStorage;
+ RosterStorage* rosterStorage;
};
}
diff --git a/Swiften/Client/NickResolver.h b/Swiften/Client/NickResolver.h
index 881362a..bf373fa 100644
--- a/Swiften/Client/NickResolver.h
+++ b/Swiften/Client/NickResolver.h
@@ -5,9 +5,9 @@
*/
#include <map>
-#include <boost/signals.hpp>
#include <boost/shared_ptr.hpp>
+#include <Swiften/Base/boost_bsignals.h>
#include <string>
#include "Swiften/JID/JID.h"
#include "Swiften/Elements/VCard.h"
diff --git a/Swiften/Client/Storages.cpp b/Swiften/Client/Storages.cpp
new file mode 100644
index 0000000..3c2dbc5
--- /dev/null
+++ b/Swiften/Client/Storages.cpp
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Client/Storages.h>
+
+using namespace Swift;
+
+Storages::~Storages() {
+}
diff --git a/Swiften/Client/Storages.h b/Swiften/Client/Storages.h
index e62f0a9..1c5bbe9 100644
--- a/Swiften/Client/Storages.h
+++ b/Swiften/Client/Storages.h
@@ -10,6 +10,7 @@ namespace Swift {
class VCardStorage;
class AvatarStorage;
class CapsStorage;
+ class RosterStorage;
/**
* An interface to hold storage classes for different
@@ -17,10 +18,11 @@ namespace Swift {
*/
class Storages {
public:
- virtual ~Storages() {}
+ virtual ~Storages();
virtual VCardStorage* getVCardStorage() const = 0;
virtual AvatarStorage* getAvatarStorage() const = 0;
virtual CapsStorage* getCapsStorage() const = 0;
+ virtual RosterStorage* getRosterStorage() const = 0;
};
}
diff --git a/Swiften/Component/ComponentSessionStanzaChannel.cpp b/Swiften/Component/ComponentSessionStanzaChannel.cpp
index b9fecb2..b342714 100644
--- a/Swiften/Component/ComponentSessionStanzaChannel.cpp
+++ b/Swiften/Component/ComponentSessionStanzaChannel.cpp
@@ -7,6 +7,7 @@
#include "Swiften/Component/ComponentSessionStanzaChannel.h"
#include <boost/bind.hpp>
+#include <iostream>
namespace Swift {
diff --git a/Swiften/Component/ComponentXMLTracer.cpp b/Swiften/Component/ComponentXMLTracer.cpp
new file mode 100644
index 0000000..b952c29
--- /dev/null
+++ b/Swiften/Component/ComponentXMLTracer.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Component/ComponentXMLTracer.h>
+
+#include <iostream>
+#include <boost/bind.hpp>
+
+namespace Swift {
+
+ComponentXMLTracer::ComponentXMLTracer(CoreComponent* client) {
+ client->onDataRead.connect(boost::bind(&ComponentXMLTracer::printData, '<', _1));
+ client->onDataWritten.connect(boost::bind(&ComponentXMLTracer::printData, '>', _1));
+}
+
+void ComponentXMLTracer::printData(char direction, const std::string& data) {
+ printLine(direction);
+ std::cerr << data << std::endl;
+}
+
+void ComponentXMLTracer::printLine(char c) {
+ for (unsigned int i = 0; i < 80; ++i) {
+ std::cerr << c;
+ }
+ std::cerr << std::endl;
+}
+
+}
diff --git a/Swiften/Component/ComponentXMLTracer.h b/Swiften/Component/ComponentXMLTracer.h
index 70a617b..d7e2b46 100644
--- a/Swiften/Component/ComponentXMLTracer.h
+++ b/Swiften/Component/ComponentXMLTracer.h
@@ -6,29 +6,15 @@
#pragma once
-#include <boost/bind.hpp>
-
#include "Swiften/Component/Component.h"
namespace Swift {
class ComponentXMLTracer {
public:
- ComponentXMLTracer(Component* component) {
- component->onDataRead.connect(boost::bind(&ComponentXMLTracer::printData, '<', _1));
- component->onDataWritten.connect(boost::bind(&ComponentXMLTracer::printData, '>', _1));
- }
+ ComponentXMLTracer(CoreComponent* component);
private:
- static void printData(char direction, const std::string& data) {
- printLine(direction);
- std::cerr << data << std::endl;
- }
-
- static void printLine(char c) {
- for (unsigned int i = 0; i < 80; ++i) {
- std::cerr << c;
- }
- std::cerr << std::endl;
- }
+ static void printData(char direction, const std::string& data);
+ static void printLine(char c);
};
}
diff --git a/Swiften/Component/CoreComponent.cpp b/Swiften/Component/CoreComponent.cpp
index e79d735..f995ab0 100644
--- a/Swiften/Component/CoreComponent.cpp
+++ b/Swiften/Component/CoreComponent.cpp
@@ -7,6 +7,7 @@
#include "Swiften/Component/CoreComponent.h"
#include <boost/bind.hpp>
+#include <iostream>
#include "Swiften/Component/ComponentSession.h"
#include "Swiften/Network/Connector.h"
diff --git a/Swiften/Component/SConscript b/Swiften/Component/SConscript
index 0a9f250..ef5700c 100644
--- a/Swiften/Component/SConscript
+++ b/Swiften/Component/SConscript
@@ -7,6 +7,7 @@ sources = [
"ComponentSessionStanzaChannel.cpp",
"CoreComponent.cpp",
"Component.cpp",
+ "ComponentXMLTracer.cpp",
]
swiften_env.Append(SWIFTEN_OBJECTS = swiften_env.SwiftenObject(sources))
diff --git a/Swiften/Compress/ZLibCompressor.cpp b/Swiften/Compress/ZLibCompressor.cpp
index 7e3116e..b740c68 100644
--- a/Swiften/Compress/ZLibCompressor.cpp
+++ b/Swiften/Compress/ZLibCompressor.cpp
@@ -6,6 +6,8 @@
#include "Swiften/Compress/ZLibCompressor.h"
+#include <cassert>
+
#pragma GCC diagnostic ignored "-Wold-style-cast"
namespace Swift {
diff --git a/Swiften/Compress/ZLibCompressor.h b/Swiften/Compress/ZLibCompressor.h
index 7fe5387..e0b4759 100644
--- a/Swiften/Compress/ZLibCompressor.h
+++ b/Swiften/Compress/ZLibCompressor.h
@@ -6,8 +6,6 @@
#pragma once
-#include <cassert>
-
#include "Swiften/Compress/ZLibCodecompressor.h"
#include "Swiften/Base/ByteArray.h"
diff --git a/Swiften/Compress/ZLibDecompressor.cpp b/Swiften/Compress/ZLibDecompressor.cpp
index af7349b..78e9846 100644
--- a/Swiften/Compress/ZLibDecompressor.cpp
+++ b/Swiften/Compress/ZLibDecompressor.cpp
@@ -6,6 +6,8 @@
#include "Swiften/Compress/ZLibDecompressor.h"
+#include <cassert>
+
#pragma GCC diagnostic ignored "-Wold-style-cast"
namespace Swift {
diff --git a/Swiften/Compress/ZLibDecompressor.h b/Swiften/Compress/ZLibDecompressor.h
index ec08a4f..917e1b7 100644
--- a/Swiften/Compress/ZLibDecompressor.h
+++ b/Swiften/Compress/ZLibDecompressor.h
@@ -6,8 +6,6 @@
#pragma once
-#include <cassert>
-
#include "Swiften/Compress/ZLibCodecompressor.h"
#include "Swiften/Base/ByteArray.h"
diff --git a/Swiften/Config/swiften-config.cpp b/Swiften/Config/swiften-config.cpp
index b3875cb..0c46cf0 100644
--- a/Swiften/Config/swiften-config.cpp
+++ b/Swiften/Config/swiften-config.cpp
@@ -11,6 +11,7 @@
#include <boost/program_options/variables_map.hpp>
#include <boost/program_options.hpp>
#include <boost/version.hpp>
+#include <boost/filesystem.hpp>
#include <string>
#include <Swiften/Base/Platform.h>
diff --git a/Swiften/Disco/CapsFileStorage.cpp b/Swiften/Disco/CapsFileStorage.cpp
deleted file mode 100644
index 1e53854..0000000
--- a/Swiften/Disco/CapsFileStorage.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2010 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-#include "Swiften/Disco/CapsFileStorage.h"
-
-#include <iostream>
-#include <boost/filesystem/fstream.hpp>
-
-#include "Swiften/Base/ByteArray.h"
-#include "Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.h"
-#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadParserTester.h"
-#include "Swiften/Parser/PayloadParsers/DiscoInfoParser.h"
-#include "Swiften/StringCodecs/Hexify.h"
-#include "Swiften/StringCodecs/Base64.h"
-
-namespace Swift {
-
-CapsFileStorage::CapsFileStorage(const boost::filesystem::path& path) : path(path) {
-}
-
-DiscoInfo::ref CapsFileStorage::getDiscoInfo(const std::string& hash) const {
- boost::filesystem::path capsPath(getCapsPath(hash));
- if (boost::filesystem::exists(capsPath)) {
- ByteArray data;
- data.readFromFile(capsPath.string());
-
- DiscoInfoParser parser;
- PayloadParserTester tester(&parser);
- tester.parse(data.toString());
- return boost::dynamic_pointer_cast<DiscoInfo>(parser.getPayload());
- }
- else {
- return DiscoInfo::ref();
- }
-}
-
-void CapsFileStorage::setDiscoInfo(const std::string& hash, DiscoInfo::ref discoInfo) {
- boost::filesystem::path capsPath(getCapsPath(hash));
- if (!boost::filesystem::exists(capsPath.parent_path())) {
- try {
- boost::filesystem::create_directories(capsPath.parent_path());
- }
- catch (const boost::filesystem::filesystem_error& e) {
- std::cerr << "ERROR: " << e.what() << std::endl;
- }
- }
- DiscoInfo::ref bareDiscoInfo(new DiscoInfo(*discoInfo.get()));
- bareDiscoInfo->setNode("");
- boost::filesystem::ofstream file(capsPath);
- file << DiscoInfoSerializer().serializePayload(bareDiscoInfo);
- file.close();
-}
-
-boost::filesystem::path CapsFileStorage::getCapsPath(const std::string& hash) const {
- return path / (Hexify::hexify(Base64::decode(hash)) + ".xml");
-}
-
-}
diff --git a/Swiften/Disco/CapsManager.cpp b/Swiften/Disco/CapsManager.cpp
index 63166e6..6eb7c17 100644
--- a/Swiften/Disco/CapsManager.cpp
+++ b/Swiften/Disco/CapsManager.cpp
@@ -7,6 +7,7 @@
#include "Swiften/Disco/CapsManager.h"
#include <boost/bind.hpp>
+#include <iostream>
#include "Swiften/Client/StanzaChannel.h"
#include "Swiften/Disco/CapsStorage.h"
diff --git a/Swiften/Disco/DummyEntityCapsProvider.cpp b/Swiften/Disco/DummyEntityCapsProvider.cpp
new file mode 100644
index 0000000..a906652
--- /dev/null
+++ b/Swiften/Disco/DummyEntityCapsProvider.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Disco/DummyEntityCapsProvider.h>
+
+#include <iostream>
+
+namespace Swift {
+
+DiscoInfo::ref DummyEntityCapsProvider::getCaps(const JID& jid) const {
+ std::map<JID, DiscoInfo::ref>::const_iterator i = caps.find(jid);
+ if (i != caps.end()) {
+ return i->second;
+ }
+ return DiscoInfo::ref();
+}
+
+}
diff --git a/Swiften/Disco/DummyEntityCapsProvider.h b/Swiften/Disco/DummyEntityCapsProvider.h
index 68cef2f..1bd4bb9 100644
--- a/Swiften/Disco/DummyEntityCapsProvider.h
+++ b/Swiften/Disco/DummyEntityCapsProvider.h
@@ -7,7 +7,7 @@
#pragma once
#include <map>
-#include <iostream>
+
#include "Swiften/Disco/EntityCapsProvider.h"
namespace Swift {
@@ -16,13 +16,7 @@ namespace Swift {
DummyEntityCapsProvider() {
}
- DiscoInfo::ref getCaps(const JID& jid) const {
- std::map<JID, DiscoInfo::ref>::const_iterator i = caps.find(jid);
- if (i != caps.end()) {
- return i->second;
- }
- return DiscoInfo::ref();
- }
+ DiscoInfo::ref getCaps(const JID& jid) const;
std::map<JID, DiscoInfo::ref> caps;
};
diff --git a/Swiften/Disco/GetDiscoItemsRequest.h b/Swiften/Disco/GetDiscoItemsRequest.h
index 0a94402..46735ef 100644
--- a/Swiften/Disco/GetDiscoItemsRequest.h
+++ b/Swiften/Disco/GetDiscoItemsRequest.h
@@ -18,9 +18,18 @@ namespace Swift {
return ref(new GetDiscoItemsRequest(jid, router));
}
+ static ref create(const JID& jid, const std::string& node, IQRouter* router) {
+ return ref(new GetDiscoItemsRequest(jid, node, router));
+ }
+
private:
GetDiscoItemsRequest(const JID& jid, IQRouter* router) :
GenericRequest<DiscoItems>(IQ::Get, jid, boost::shared_ptr<DiscoItems>(new DiscoItems()), router) {
}
+
+ GetDiscoItemsRequest(const JID& jid, const std::string& node, IQRouter* router) :
+ GenericRequest<DiscoItems>(IQ::Get, jid, boost::shared_ptr<DiscoItems>(new DiscoItems()), router) {
+ getPayloadGeneric()->setNode(node);
+ }
};
}
diff --git a/Swiften/Disco/SConscript b/Swiften/Disco/SConscript
index 9982192..434018a 100644
--- a/Swiften/Disco/SConscript
+++ b/Swiften/Disco/SConscript
@@ -5,8 +5,8 @@ objects = swiften_env.SwiftenObject([
"CapsManager.cpp",
"EntityCapsManager.cpp",
"EntityCapsProvider.cpp",
+ "DummyEntityCapsProvider.cpp",
"CapsStorage.cpp",
- "CapsFileStorage.cpp",
"ClientDiscoManager.cpp",
"DiscoInfoResponder.cpp",
"JIDDiscoInfoResponder.cpp",
diff --git a/Swiften/Elements/Body.h b/Swiften/Elements/Body.h
index 2887390..a2497f7 100644
--- a/Swiften/Elements/Body.h
+++ b/Swiften/Elements/Body.h
@@ -6,14 +6,13 @@
#pragma once
-#include "Swiften/Elements/Payload.h"
#include <string>
+#include <Swiften/Elements/Payload.h>
+
namespace Swift {
class Body : public Payload {
public:
- typedef boost::shared_ptr<Body> ref;
-
Body(const std::string& text = "") : text_(text) {
}
diff --git a/Swiften/Elements/Bytestreams.h b/Swiften/Elements/Bytestreams.h
index b493375..211396b 100644
--- a/Swiften/Elements/Bytestreams.h
+++ b/Swiften/Elements/Bytestreams.h
@@ -9,9 +9,9 @@
#include <vector>
#include <boost/optional.hpp>
#include <boost/shared_ptr.hpp>
+#include <string>
#include "Swiften/JID/JID.h"
-#include <string>
#include "Swiften/Elements/Payload.h"
namespace Swift {
diff --git a/Swiften/Elements/CapsInfo.h b/Swiften/Elements/CapsInfo.h
index ccad278..f1e2c37 100644
--- a/Swiften/Elements/CapsInfo.h
+++ b/Swiften/Elements/CapsInfo.h
@@ -7,8 +7,8 @@
#pragma once
#include <boost/shared_ptr.hpp>
-
#include <string>
+
#include "Swiften/Elements/Payload.h"
namespace Swift {
diff --git a/Swiften/Elements/ChatState.h b/Swiften/Elements/ChatState.h
index 2896877..ddeed79 100644
--- a/Swiften/Elements/ChatState.h
+++ b/Swiften/Elements/ChatState.h
@@ -7,6 +7,7 @@
#pragma once
#include <string>
+
#include "Swiften/Elements/Payload.h"
namespace Swift {
diff --git a/Swiften/Elements/Command.h b/Swiften/Elements/Command.h
index f4059a8..4a9c2a3 100644
--- a/Swiften/Elements/Command.h
+++ b/Swiften/Elements/Command.h
@@ -7,8 +7,8 @@
#pragma once
#include <boost/shared_ptr.hpp>
-
#include <string>
+
#include "Swiften/Elements/Payload.h"
#include "Swiften/Elements/Form.h"
diff --git a/Swiften/Elements/ComponentHandshake.h b/Swiften/Elements/ComponentHandshake.h
index 6047eab..3fe0457 100644
--- a/Swiften/Elements/ComponentHandshake.h
+++ b/Swiften/Elements/ComponentHandshake.h
@@ -7,9 +7,9 @@
#pragma once
#include <boost/shared_ptr.hpp>
+#include <string>
#include "Swiften/Elements/Element.h"
-#include <string>
namespace Swift {
class ComponentHandshake : public Element {
diff --git a/Swiften/Elements/Delay.h b/Swiften/Elements/Delay.h
index 3213037..85d167b 100644
--- a/Swiften/Elements/Delay.h
+++ b/Swiften/Elements/Delay.h
@@ -6,7 +6,7 @@
#pragma once
-#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/optional.hpp>
#include "Swiften/Elements/Payload.h"
diff --git a/Swiften/Elements/DiscoInfo.cpp b/Swiften/Elements/DiscoInfo.cpp
index f0e728e..5b2bb04 100644
--- a/Swiften/Elements/DiscoInfo.cpp
+++ b/Swiften/Elements/DiscoInfo.cpp
@@ -6,12 +6,15 @@
#include "Swiften/Elements/DiscoInfo.h"
+#include <algorithm>
+
namespace Swift {
const std::string DiscoInfo::ChatStatesFeature = std::string("http://jabber.org/protocol/chatstates");
const std::string DiscoInfo::SecurityLabelsFeature = std::string("urn:xmpp:sec-label:0");
const std::string DiscoInfo::SecurityLabelsCatalogFeature = std::string("urn:xmpp:sec-label:catalog:2");
const std::string DiscoInfo::JabberSearchFeature = std::string("jabber:iq:search");
+const std::string DiscoInfo::CommandsFeature = std::string("http://jabber.org/protocol/commands");
bool DiscoInfo::Identity::operator<(const Identity& other) const {
@@ -33,4 +36,8 @@ bool DiscoInfo::Identity::operator<(const Identity& other) const {
}
}
+bool DiscoInfo::hasFeature(const std::string& feature) const {
+ return std::find(features_.begin(), features_.end(), feature) != features_.end();
+}
+
}
diff --git a/Swiften/Elements/DiscoInfo.h b/Swiften/Elements/DiscoInfo.h
index d5bf64a..cd650b9 100644
--- a/Swiften/Elements/DiscoInfo.h
+++ b/Swiften/Elements/DiscoInfo.h
@@ -7,11 +7,9 @@
#pragma once
#include <vector>
-#include <algorithm>
-
-#include "Swiften/Elements/Payload.h"
#include <string>
+#include "Swiften/Elements/Payload.h"
#include "Swiften/Elements/Form.h"
namespace Swift {
@@ -23,6 +21,7 @@ namespace Swift {
static const std::string SecurityLabelsFeature;
static const std::string SecurityLabelsCatalogFeature;
static const std::string JabberSearchFeature;
+ static const std::string CommandsFeature;
class Identity {
public:
@@ -82,9 +81,7 @@ namespace Swift {
features_.push_back(feature);
}
- bool hasFeature(const std::string& feature) const {
- return std::find(features_.begin(), features_.end(), feature) != features_.end();
- }
+ bool hasFeature(const std::string& feature) const;
void addExtension(Form::ref form) {
extensions_.push_back(form);
diff --git a/Swiften/Elements/DiscoItems.h b/Swiften/Elements/DiscoItems.h
index cc5a583..1b7063b 100644
--- a/Swiften/Elements/DiscoItems.h
+++ b/Swiften/Elements/DiscoItems.h
@@ -7,10 +7,9 @@
#pragma once
#include <vector>
-#include <algorithm>
+#include <string>
#include "Swiften/Elements/Payload.h"
-#include <string>
#include "Swiften/JID/JID.h"
namespace Swift {
diff --git a/Swiften/Elements/Element.h b/Swiften/Elements/Element.h
index aded528..1e6a9d0 100644
--- a/Swiften/Elements/Element.h
+++ b/Swiften/Elements/Element.h
@@ -4,8 +4,7 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#ifndef SWIFTEN_ELEMENT_H
-#define SWIFTEN_ELEMENT_H
+#pragma once
namespace Swift {
class Element {
@@ -13,5 +12,3 @@ namespace Swift {
virtual ~Element();
};
}
-
-#endif
diff --git a/Swiften/Elements/ErrorPayload.h b/Swiften/Elements/ErrorPayload.h
index 12ad574..cece81f 100644
--- a/Swiften/Elements/ErrorPayload.h
+++ b/Swiften/Elements/ErrorPayload.h
@@ -7,9 +7,9 @@
#pragma once
#include <boost/shared_ptr.hpp>
+#include <string>
#include "Swiften/Elements/Payload.h"
-#include <string>
namespace Swift {
class ErrorPayload : public Payload {
diff --git a/Swiften/Elements/Form.h b/Swiften/Elements/Form.h
index 1c50f0c..4e6e9f1 100644
--- a/Swiften/Elements/Form.h
+++ b/Swiften/Elements/Form.h
@@ -7,11 +7,10 @@
#pragma once
#include <vector>
+#include <string>
#include "Swiften/Elements/Payload.h"
#include "Swiften/Elements/FormField.h"
-#include <string>
-
#include "Swiften/JID/JID.h"
namespace Swift {
diff --git a/Swiften/Elements/FormField.h b/Swiften/Elements/FormField.h
index f455303..2438bb3 100644
--- a/Swiften/Elements/FormField.h
+++ b/Swiften/Elements/FormField.h
@@ -11,8 +11,8 @@
#include <vector>
#include <boost/shared_ptr.hpp>
-
#include <string>
+
#include "Swiften/JID/JID.h"
namespace Swift {
@@ -111,5 +111,4 @@ namespace Swift {
SWIFTEN_DECLARE_FORM_FIELD(JIDSingle, JID);
SWIFTEN_DECLARE_FORM_FIELD(JIDMulti, std::vector<JID>);
SWIFTEN_DECLARE_FORM_FIELD(ListMulti, std::vector<std::string>);
- SWIFTEN_DECLARE_FORM_FIELD(Untyped, std::vector<std::string>);
}
diff --git a/Swiften/Elements/IBB.h b/Swiften/Elements/IBB.h
index 55f2c4f..8138e83 100644
--- a/Swiften/Elements/IBB.h
+++ b/Swiften/Elements/IBB.h
@@ -6,11 +6,11 @@
#pragma once
+#include <string>
+#include <vector>
#include <boost/shared_ptr.hpp>
-#include <string>
-#include "Swiften/Base/ByteArray.h"
-#include "Swiften/Elements/Payload.h"
+#include <Swiften/Elements/Payload.h>
namespace Swift {
class IBB : public Payload {
@@ -36,7 +36,7 @@ namespace Swift {
return result;
}
- static IBB::ref createIBBData(const std::string& streamID, int sequenceNumber, const ByteArray& data) {
+ static IBB::ref createIBBData(const std::string& streamID, int sequenceNumber, const std::vector<unsigned char>& data) {
IBB::ref result(new IBB(Data, streamID));
result->setSequenceNumber(sequenceNumber);
result->setData(data);
@@ -71,11 +71,11 @@ namespace Swift {
return streamID;
}
- const ByteArray& getData() const {
+ const std::vector<unsigned char>& getData() const {
return data;
}
- void setData(const ByteArray& data) {
+ void setData(const std::vector<unsigned char>& data) {
this->data = data;
}
@@ -98,7 +98,7 @@ namespace Swift {
private:
Action action;
std::string streamID;
- ByteArray data;
+ std::vector<unsigned char> data;
StanzaType stanzaType;
int blockSize;
int sequenceNumber;
diff --git a/Swiften/Elements/InBandRegistrationPayload.h b/Swiften/Elements/InBandRegistrationPayload.h
index e4e1e6f..6e0f741 100644
--- a/Swiften/Elements/InBandRegistrationPayload.h
+++ b/Swiften/Elements/InBandRegistrationPayload.h
@@ -8,10 +8,10 @@
#include <boost/shared_ptr.hpp>
#include <boost/optional.hpp>
+#include <string>
#include "Swiften/Elements/Payload.h"
#include "Swiften/Elements/Form.h"
-#include <string>
namespace Swift {
class InBandRegistrationPayload : public Payload {
diff --git a/Swiften/Elements/JingleContent.h b/Swiften/Elements/JingleContentPayload.h
index 4ae908b..c44a806 100644
--- a/Swiften/Elements/JingleContent.h
+++ b/Swiften/Elements/JingleContentPayload.h
@@ -8,18 +8,17 @@
#include <vector>
#include <boost/optional.hpp>
-
#include <string>
+
#include <Swiften/JID/JID.h>
#include <Swiften/Elements/Payload.h>
#include <Swiften/Elements/JingleDescription.h>
-#include <Swiften/Elements/JingleTransport.h>
-#include <Swiften/Base/foreach.h>
+#include <Swiften/Elements/JingleTransportPayload.h>
namespace Swift {
- class JingleContent : public Payload {
+ class JingleContentPayload : public Payload {
public:
- typedef boost::shared_ptr<JingleContent> ref;
+ typedef boost::shared_ptr<JingleContentPayload> ref;
enum Creator {
InitiatorCreator,
@@ -33,10 +32,18 @@ namespace Swift {
BothSenders,
};*/
+ Creator getCreator() const {
+ return creator;
+ }
+
void setCreator(Creator creator) {
this->creator = creator;
}
+ const std::string& getName() const {
+ return name;
+ }
+
void setName(const std::string& name) {
this->name = name;
}
@@ -49,18 +56,18 @@ namespace Swift {
descriptions.push_back(description);
}
- const std::vector<JingleTransport::ref>& getTransports() const {
+ const std::vector<boost::shared_ptr<JingleTransportPayload> >& getTransports() const {
return transports;
}
- void addTransport(JingleTransport::ref transport) {
+ void addTransport(boost::shared_ptr<JingleTransportPayload> transport) {
transports.push_back(transport);
}
template<typename T>
boost::shared_ptr<T> getDescription() const {
- foreach (JingleDescription::ref i, descriptions) {
- boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(i));
+ for (size_t i = 0; i < descriptions.size(); ++i) {
+ boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(descriptions[i]));
if (result) {
return result;
}
@@ -70,8 +77,8 @@ namespace Swift {
template<typename T>
boost::shared_ptr<T> getTransport() const {
- foreach (JingleTransport::ref i, transports) {
- boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(i));
+ for (size_t i = 0; i < transports.size(); ++i) {
+ boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(transports[i]));
if (result) {
return result;
}
@@ -84,6 +91,6 @@ namespace Swift {
std::string name;
//Senders senders;
std::vector<JingleDescription::ref> descriptions;
- std::vector<JingleTransport::ref> transports;
+ std::vector<boost::shared_ptr<JingleTransportPayload> > transports;
};
}
diff --git a/Swiften/Elements/JingleIBBTransport.h b/Swiften/Elements/JingleIBBTransportPayload.h
index faa5af3..67aab09 100644
--- a/Swiften/Elements/JingleIBBTransport.h
+++ b/Swiften/Elements/JingleIBBTransportPayload.h
@@ -6,12 +6,16 @@
#pragma once
+#include <boost/shared_ptr.hpp>
#include <string>
-#include <Swiften/Elements/JingleTransport.h>
+
+#include <Swiften/Elements/JingleTransportPayload.h>
namespace Swift {
- class JingleIBBTransport : public JingleTransport {
+ class JingleIBBTransportPayload : public JingleTransportPayload {
public:
+ typedef boost::shared_ptr<JingleIBBTransportPayload> ref;
+
enum StanzaType {
IQStanza,
MessageStanza,
diff --git a/Swiften/Elements/JinglePayload.h b/Swiften/Elements/JinglePayload.h
index 59d3c99..be02543 100644
--- a/Swiften/Elements/JinglePayload.h
+++ b/Swiften/Elements/JinglePayload.h
@@ -12,7 +12,7 @@
#include <string>
#include <Swiften/JID/JID.h>
#include <Swiften/Elements/Payload.h>
-#include <Swiften/Elements/JingleContent.h>
+#include <Swiften/Elements/JingleContentPayload.h>
namespace Swift {
@@ -98,11 +98,11 @@ namespace Swift {
return sessionID;
}
- void addContent(JingleContent::ref content) {
+ void addContent(JingleContentPayload::ref content) {
this->contents.push_back(content);
}
- const std::vector<JingleContent::ref> getContents() const {
+ const std::vector<JingleContentPayload::ref> getContents() const {
return contents;
}
@@ -119,7 +119,7 @@ namespace Swift {
JID initiator;
JID responder;
std::string sessionID;
- std::vector<JingleContent::ref> contents;
+ std::vector<JingleContentPayload::ref> contents;
boost::optional<Reason> reason;
};
}
diff --git a/Swiften/Elements/JingleS5BTransport.h b/Swiften/Elements/JingleS5BTransportPayload.h
index 4522417..7b3089f 100644
--- a/Swiften/Elements/JingleS5BTransport.h
+++ b/Swiften/Elements/JingleS5BTransportPayload.h
@@ -6,11 +6,13 @@
#pragma once
-#include <Swiften/Elements/JingleTransport.h>
+#include <Swiften/Elements/JingleTransportPayload.h>
#include <Swiften/Elements/Bytestreams.h>
+// FIXME: Remove Bytestreams, and replace by our own candidate
+
namespace Swift {
- class JingleS5BTransport : public JingleTransport {
+ class JingleS5BTransportPayload : public JingleTransportPayload {
public:
const Bytestreams& getInfo() const {
return info;
diff --git a/Swiften/Elements/JingleTransportPayload.h b/Swiften/Elements/JingleTransportPayload.h
new file mode 100644
index 0000000..7a9ea29
--- /dev/null
+++ b/Swiften/Elements/JingleTransportPayload.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Elements/Payload.h>
+
+namespace Swift {
+ class JingleTransportPayload : public Payload {
+ public:
+ typedef boost::shared_ptr<JingleTransportPayload> ref;
+ };
+}
diff --git a/Swiften/Elements/MUCPayload.h b/Swiften/Elements/MUCPayload.h
index c372360..eb3baeb 100644
--- a/Swiften/Elements/MUCPayload.h
+++ b/Swiften/Elements/MUCPayload.h
@@ -7,7 +7,7 @@
#pragma once
#include <boost/optional.hpp>
-#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
#include "Swiften/JID/JID.h"
#include <string>
diff --git a/Swiften/Elements/Message.h b/Swiften/Elements/Message.h
index a553eb3..3623e73 100644
--- a/Swiften/Elements/Message.h
+++ b/Swiften/Elements/Message.h
@@ -14,6 +14,7 @@
#include "Swiften/Elements/Subject.h"
#include "Swiften/Elements/ErrorPayload.h"
#include "Swiften/Elements/Stanza.h"
+#include "Swiften/Elements/Replace.h"
namespace Swift {
class Message : public Stanza {
diff --git a/Swiften/Elements/Payload.h b/Swiften/Elements/Payload.h
index c87b899..8b6d44a 100644
--- a/Swiften/Elements/Payload.h
+++ b/Swiften/Elements/Payload.h
@@ -6,13 +6,9 @@
#pragma once
-#include <boost/shared_ptr.hpp>
-
namespace Swift {
class Payload {
public:
- typedef boost::shared_ptr<Payload> ref;
-
virtual ~Payload();
};
}
diff --git a/Swiften/Elements/Presence.cpp b/Swiften/Elements/Presence.cpp
new file mode 100644
index 0000000..6cde567
--- /dev/null
+++ b/Swiften/Elements/Presence.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Elements/Presence.h>
+
+#include <Swiften/Elements/Priority.h>
+#include <Swiften/Elements/Status.h>
+
+namespace Swift {
+
+Presence::Presence() : type_(Available) /*, showType_(Online)*/ {
+}
+
+Presence::Presence(const std::string& status) : type_(Available) {
+ setStatus(status);
+}
+
+Presence::~Presence() {
+}
+
+int Presence::getPriority() const {
+ boost::shared_ptr<Priority> priority(getPayload<Priority>());
+ return (priority ? priority->getPriority() : 0);
+}
+
+void Presence::setPriority(int priority) {
+ updatePayload(boost::shared_ptr<Priority>(new Priority(priority)));
+}
+
+std::string Presence::getStatus() const {
+ boost::shared_ptr<Status> status(getPayload<Status>());
+ if (status) {
+ return status->getText();
+ }
+ return "";
+}
+
+void Presence::setStatus(const std::string& status) {
+ updatePayload(boost::shared_ptr<Status>(new Status(status)));
+}
+
+
+}
diff --git a/Swiften/Elements/Presence.h b/Swiften/Elements/Presence.h
index 7f957ba..5ae482b 100644
--- a/Swiften/Elements/Presence.h
+++ b/Swiften/Elements/Presence.h
@@ -6,11 +6,8 @@
#pragma once
-
-#include "Swiften/Elements/Stanza.h"
-#include "Swiften/Elements/Status.h"
-#include "Swiften/Elements/StatusShow.h"
-#include "Swiften/Elements/Priority.h"
+#include <Swiften/Elements/Stanza.h>
+#include <Swiften/Elements/StatusShow.h>
namespace Swift {
class Presence : public Stanza {
@@ -19,10 +16,9 @@ namespace Swift {
enum Type { Available, Error, Probe, Subscribe, Subscribed, Unavailable, Unsubscribe, Unsubscribed };
- Presence() : type_(Available) /*, showType_(Online)*/ {}
- Presence(const std::string& status) : type_(Available) {
- setStatus(status);
- }
+ Presence();
+ Presence(const std::string& status);
+ virtual ~Presence();
static ref create() {
return ref(new Presence());
@@ -51,26 +47,11 @@ namespace Swift {
updatePayload(boost::shared_ptr<StatusShow>(new StatusShow(show)));
}
- std::string getStatus() const {
- boost::shared_ptr<Status> status(getPayload<Status>());
- if (status) {
- return status->getText();
- }
- return "";
- }
+ std::string getStatus() const;
+ void setStatus(const std::string& status);
- void setStatus(const std::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)));
- }
+ int getPriority() const;
+ void setPriority(int priority);
boost::shared_ptr<Presence> clone() const {
return boost::shared_ptr<Presence>(new Presence(*this));
diff --git a/Swiften/Elements/Priority.h b/Swiften/Elements/Priority.h
index 12181d4..2c0cb9b 100644
--- a/Swiften/Elements/Priority.h
+++ b/Swiften/Elements/Priority.h
@@ -6,13 +6,11 @@
#pragma once
-#include "Swiften/Elements/Payload.h"
+#include <Swiften/Elements/Payload.h>
namespace Swift {
class Priority : public Payload {
public:
- typedef boost::shared_ptr<Priority> ref;
-
Priority(int priority = 0) : priority_(priority) {
}
diff --git a/Swiften/Elements/Replace.h b/Swiften/Elements/Replace.h
new file mode 100644
index 0000000..dc8ff59
--- /dev/null
+++ b/Swiften/Elements/Replace.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2011 Vlad Voicu
+ * Licensed under the Simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include "Swiften/Elements/Payload.h"
+
+namespace Swift {
+ class Replace : public Payload {
+ public:
+ typedef boost::shared_ptr<Replace> ref;
+ Replace(std::string id = "") : replaceID_(id) {};
+ std::string getId() {
+ return replaceID_;
+ }
+ void setId(std::string id) {
+ replaceID_ = id;
+ }
+ private:
+ std::string replaceID_;
+ };
+}
diff --git a/Swiften/Elements/RosterItemExchangePayload.cpp b/Swiften/Elements/RosterItemExchangePayload.cpp
new file mode 100644
index 0000000..f4f3a57
--- /dev/null
+++ b/Swiften/Elements/RosterItemExchangePayload.cpp
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2011 Jan Kaluza
+ * Licensed under the Simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "Swiften/Elements/RosterItemExchangePayload.h"
+#include "Swiften/Base/foreach.h"
+
+namespace Swift {
+
+RosterItemExchangePayload::Item::Item() {
+}
+
+RosterItemExchangePayload::RosterItemExchangePayload() {
+}
+
+}
diff --git a/Swiften/Elements/RosterItemExchangePayload.h b/Swiften/Elements/RosterItemExchangePayload.h
new file mode 100644
index 0000000..d9e2912
--- /dev/null
+++ b/Swiften/Elements/RosterItemExchangePayload.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2011 Jan Kaluza
+ * Licensed under the Simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <vector>
+#include <string>
+#include <boost/shared_ptr.hpp>
+
+#include "Swiften/Elements/Payload.h"
+#include "Swiften/JID/JID.h"
+
+
+namespace Swift {
+ class RosterItemExchangePayload : public Payload {
+ public:
+ typedef boost::shared_ptr<RosterItemExchangePayload> ref;
+
+ class Item {
+ public:
+ enum Action { Add, Modify, Delete };
+
+ Item();
+
+ Action getAction() const {
+ return action;
+ }
+
+ void setAction(Action action) {
+ this->action = action;
+ }
+
+ const JID& getJID() const {
+ return jid;
+ }
+
+ void setJID(const JID& jid) {
+ this->jid = jid;
+ }
+
+ const std::string& getName() const {
+ return name;
+ }
+
+ void setName(const std::string& name) {
+ this->name = name;
+ }
+
+ const std::vector<std::string>& getGroups() const {
+ return groups;
+ }
+
+ void addGroup(const std::string& group) {
+ groups.push_back(group);
+ }
+
+ private:
+ Action action;
+ JID jid;
+ std::string name;
+ std::vector<std::string> groups;
+ };
+
+ typedef std::vector<RosterItemExchangePayload::Item> RosterItemExchangePayloadItems;
+
+ public:
+ RosterItemExchangePayload();
+
+ void addItem(const RosterItemExchangePayload::Item& item) {
+ items_.push_back(item);
+ }
+
+ const RosterItemExchangePayloadItems& getItems() const {
+ return items_;
+ }
+
+ private:
+ RosterItemExchangePayloadItems items_;
+ };
+}
diff --git a/Swiften/Elements/RosterItemPayload.h b/Swiften/Elements/RosterItemPayload.h
index b8a1b10..915ae31 100644
--- a/Swiften/Elements/RosterItemPayload.h
+++ b/Swiften/Elements/RosterItemPayload.h
@@ -4,22 +4,20 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#ifndef SWIFTEN_RosterItemPayloadPayload_H
-#define SWIFTEN_RosterItemPayloadPayload_H
+#pragma once
#include <vector>
-
-#include "Swiften/JID/JID.h"
#include <string>
+#include <Swiften/JID/JID.h>
+
namespace Swift {
- class RosterItemPayload
- {
+ class RosterItemPayload {
public:
enum Subscription { None, To, From, Both, Remove };
RosterItemPayload() : subscription_(None), ask_(false) {}
- RosterItemPayload(const JID& jid, const std::string& name, Subscription subscription) : jid_(jid), name_(name), subscription_(subscription), ask_(false) { }
+ RosterItemPayload(const JID& jid, const std::string& name, Subscription subscription, const std::vector<std::string>& groups = std::vector<std::string>()) : jid_(jid), name_(name), subscription_(subscription), groups_(groups), ask_(false) { }
void setJID(const JID& jid) { jid_ = jid; }
const JID& getJID() const { return jid_; }
@@ -51,5 +49,3 @@ namespace Swift {
std::string unknownContent_;
};
}
-
-#endif
diff --git a/Swiften/Elements/RosterPayload.h b/Swiften/Elements/RosterPayload.h
index b46b384..3102f0e 100644
--- a/Swiften/Elements/RosterPayload.h
+++ b/Swiften/Elements/RosterPayload.h
@@ -33,7 +33,16 @@ namespace Swift {
return items_;
}
+ const boost::optional<std::string>& getVersion() const {
+ return version_;
+ }
+
+ void setVersion(const std::string& version) {
+ version_ = version;
+ }
+
private:
RosterItemPayloads items_;
+ boost::optional<std::string> version_;
};
}
diff --git a/Swiften/Elements/SecurityLabelsCatalog.h b/Swiften/Elements/SecurityLabelsCatalog.h
index 10ef459..cd84b0b 100644
--- a/Swiften/Elements/SecurityLabelsCatalog.h
+++ b/Swiften/Elements/SecurityLabelsCatalog.h
@@ -4,13 +4,13 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#ifndef SWIFTEN_SecurityLabelsCatalog_H
-#define SWIFTEN_SecurityLabelsCatalog_H
+#pragma once
#include <vector>
+#include <string>
+#include <boost/shared_ptr.hpp>
#include "Swiften/JID/JID.h"
-#include <string>
#include "Swiften/Elements/Payload.h"
#include "Swiften/Elements/SecurityLabel.h"
@@ -85,5 +85,3 @@ namespace Swift {
std::vector<Item> items_;
};
}
-
-#endif
diff --git a/Swiften/Elements/SoftwareVersion.h b/Swiften/Elements/SoftwareVersion.h
index 5863b38..887c6e9 100644
--- a/Swiften/Elements/SoftwareVersion.h
+++ b/Swiften/Elements/SoftwareVersion.h
@@ -6,8 +6,10 @@
#pragma once
-#include "Swiften/Elements/Payload.h"
#include <string>
+#include <boost/shared_ptr.hpp>
+
+#include "Swiften/Elements/Payload.h"
namespace Swift {
class SoftwareVersion : public Payload {
diff --git a/Swiften/Elements/Stanza.cpp b/Swiften/Elements/Stanza.cpp
index d15d778..607dfd1 100644
--- a/Swiften/Elements/Stanza.cpp
+++ b/Swiften/Elements/Stanza.cpp
@@ -9,8 +9,13 @@
#include <typeinfo>
+#include <Swiften/Base/foreach.h>
+
namespace Swift {
+Stanza::Stanza() {
+}
+
Stanza::~Stanza() {
payloads_.clear();
}
diff --git a/Swiften/Elements/Stanza.h b/Swiften/Elements/Stanza.h
index 9b934e4..9e082cc 100644
--- a/Swiften/Elements/Stanza.h
+++ b/Swiften/Elements/Stanza.h
@@ -7,27 +7,28 @@
#pragma once
#include <vector>
+#include <string>
#include <boost/shared_ptr.hpp>
-#include <boost/optional.hpp>
-#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/optional/optional_fwd.hpp>
+#include <boost/date_time/posix_time/ptime.hpp>
-#include "Swiften/Elements/Element.h"
-#include "Swiften/Elements/Payload.h"
-#include <string>
-#include "Swiften/Base/foreach.h"
-#include "Swiften/JID/JID.h"
+#include <Swiften/Elements/Element.h>
+#include <Swiften/JID/JID.h>
namespace Swift {
+ class Payload;
+
class Stanza : public Element {
public:
typedef boost::shared_ptr<Stanza> ref;
+ Stanza();
virtual ~Stanza();
template<typename T>
boost::shared_ptr<T> getPayload() const {
- foreach (const boost::shared_ptr<Payload>& i, payloads_) {
- boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(i));
+ for (size_t i = 0; i < payloads_.size(); ++i) {
+ boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(payloads_[i]));
if (result) {
return result;
}
@@ -38,8 +39,8 @@ namespace Swift {
template<typename T>
std::vector< boost::shared_ptr<T> > getPayloads() const {
std::vector< boost::shared_ptr<T> > results;
- foreach (const boost::shared_ptr<Payload>& i, payloads_) {
- boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(i));
+ for (size_t i = 0; i < payloads_.size(); ++i) {
+ boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(payloads_[i]));
if (result) {
results.push_back(result);
}
@@ -78,8 +79,6 @@ namespace Swift {
std::string id_;
JID from_;
JID to_;
-
- typedef std::vector< boost::shared_ptr<Payload> > Payloads;
- Payloads payloads_;
+ std::vector< boost::shared_ptr<Payload> > payloads_;
};
}
diff --git a/Swiften/Elements/Status.h b/Swiften/Elements/Status.h
index 3ef6401..bb9b6e9 100644
--- a/Swiften/Elements/Status.h
+++ b/Swiften/Elements/Status.h
@@ -4,8 +4,7 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#ifndef SWIFTEN_Status_H
-#define SWIFTEN_Status_H
+#pragma once
#include "Swiften/Elements/Payload.h"
#include <string>
@@ -28,5 +27,3 @@ namespace Swift {
std::string text_;
};
}
-
-#endif
diff --git a/Swiften/Elements/StatusShow.cpp b/Swiften/Elements/StatusShow.cpp
new file mode 100644
index 0000000..656e5c4
--- /dev/null
+++ b/Swiften/Elements/StatusShow.cpp
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Elements/StatusShow.h>
+
+using namespace Swift;
+
+StatusShow::StatusShow(const Type& type) : type_(type) {
+}
diff --git a/Swiften/Elements/StatusShow.h b/Swiften/Elements/StatusShow.h
index a158239..cd3477e 100644
--- a/Swiften/Elements/StatusShow.h
+++ b/Swiften/Elements/StatusShow.h
@@ -4,19 +4,16 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#ifndef SWIFTEN_StatusShow_H
-#define SWIFTEN_StatusShow_H
+#pragma once
-#include "Swiften/Elements/Payload.h"
-#include <string>
+#include <Swiften/Elements/Payload.h>
namespace Swift {
class StatusShow : public Payload {
public:
enum Type { Online, Away, FFC, XA, DND, None };
- StatusShow(const Type& type = Online) : type_(type) {
- }
+ StatusShow(const Type& type = Online);
void setType(const Type& type) {
type_ = type;
@@ -32,19 +29,17 @@ namespace Swift {
*/
static int typeToAvailabilityOrdering(Type type) {
switch (type) {
- case Online: return 4;
- case FFC: return 5;
- case Away: return 2;
- case XA: return 1;
- case DND: return 3;
- case None: return 0;
+ case Online: return 4;
+ case FFC: return 5;
+ case Away: return 2;
+ case XA: return 1;
+ case DND: return 3;
+ case None: return 0;
}
- return -1;
+ return 0;
}
private:
Type type_;
};
}
-
-#endif
diff --git a/Swiften/Elements/StreamFeatures.cpp b/Swiften/Elements/StreamFeatures.cpp
new file mode 100644
index 0000000..c6f6c04
--- /dev/null
+++ b/Swiften/Elements/StreamFeatures.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Elements/StreamFeatures.h>
+
+#include <algorithm>
+
+namespace Swift {
+
+bool StreamFeatures::hasCompressionMethod(const std::string& mechanism) const {
+ return std::find(compressionMethods_.begin(), compressionMethods_.end(), mechanism) != compressionMethods_.end();
+}
+
+bool StreamFeatures::hasAuthenticationMechanism(const std::string& mechanism) const {
+ return std::find(authenticationMechanisms_.begin(), authenticationMechanisms_.end(), mechanism) != authenticationMechanisms_.end();
+}
+
+}
diff --git a/Swiften/Elements/StreamFeatures.h b/Swiften/Elements/StreamFeatures.h
index fbc0bb8..5dc5a26 100644
--- a/Swiften/Elements/StreamFeatures.h
+++ b/Swiften/Elements/StreamFeatures.h
@@ -7,9 +7,9 @@
#pragma once
#include <vector>
-#include <algorithm>
-
#include <string>
+#include <boost/shared_ptr.hpp>
+
#include "Swiften/Elements/Element.h"
namespace Swift {
@@ -17,7 +17,7 @@ namespace Swift {
public:
typedef boost::shared_ptr<StreamFeatures> ref;
- StreamFeatures() : hasStartTLS_(false), hasResourceBind_(false), hasSession_(false), hasStreamManagement_(false) {}
+ StreamFeatures() : hasStartTLS_(false), hasResourceBind_(false), hasSession_(false), hasStreamManagement_(false), hasRosterVersioning_(false) {}
void setHasStartTLS() {
hasStartTLS_ = true;
@@ -51,9 +51,7 @@ namespace Swift {
compressionMethods_.push_back(mechanism);
}
- bool hasCompressionMethod(const std::string& mechanism) const {
- return std::find(compressionMethods_.begin(), compressionMethods_.end(), mechanism) != compressionMethods_.end();
- }
+ bool hasCompressionMethod(const std::string& mechanism) const;
const std::vector<std::string>& getAuthenticationMechanisms() const {
return authenticationMechanisms_;
@@ -63,9 +61,7 @@ namespace Swift {
authenticationMechanisms_.push_back(mechanism);
}
- bool hasAuthenticationMechanism(const std::string& mechanism) const {
- return std::find(authenticationMechanisms_.begin(), authenticationMechanisms_.end(), mechanism) != authenticationMechanisms_.end();
- }
+ bool hasAuthenticationMechanism(const std::string& mechanism) const;
bool hasAuthenticationMechanisms() const {
return !authenticationMechanisms_.empty();
@@ -79,6 +75,14 @@ namespace Swift {
hasStreamManagement_ = true;
}
+ bool hasRosterVersioning() const {
+ return hasRosterVersioning_;
+ }
+
+ void setHasRosterVersioning() {
+ hasRosterVersioning_ = true;
+ }
+
private:
bool hasStartTLS_;
std::vector<std::string> compressionMethods_;
@@ -86,5 +90,6 @@ namespace Swift {
bool hasResourceBind_;
bool hasSession_;
bool hasStreamManagement_;
+ bool hasRosterVersioning_;
};
}
diff --git a/Swiften/Elements/StreamManagementEnabled.cpp b/Swiften/Elements/StreamManagementEnabled.cpp
new file mode 100644
index 0000000..bab7516
--- /dev/null
+++ b/Swiften/Elements/StreamManagementEnabled.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Elements/StreamManagementEnabled.h>
+
+using namespace Swift;
+
+StreamManagementEnabled::StreamManagementEnabled() {
+}
+
+StreamManagementEnabled::~StreamManagementEnabled() {
+}
diff --git a/Swiften/Elements/StreamManagementEnabled.h b/Swiften/Elements/StreamManagementEnabled.h
index 0c72b84..02e77f3 100644
--- a/Swiften/Elements/StreamManagementEnabled.h
+++ b/Swiften/Elements/StreamManagementEnabled.h
@@ -1,17 +1,39 @@
/*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2011 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#pragma once
-#include "Swiften/Elements/Element.h"
+#include <string>
+#include <Swiften/Elements/Element.h>
namespace Swift {
class StreamManagementEnabled : public Element {
public:
- StreamManagementEnabled() {}
+ StreamManagementEnabled();
+ ~StreamManagementEnabled();
+
+ void setResumeSupported() {
+ resumeSupported = true;
+ }
+
+ bool getResumeSupported() const {
+ return resumeSupported;
+ }
+
+ void setResumeID(const std::string& id) {
+ resumeID = id;
+ }
+
+ const std::string& getResumeID() const {
+ return resumeID;
+ }
+
+ private:
+ bool resumeSupported;
+ std::string resumeID;
};
}
diff --git a/Swiften/Elements/StreamResume.cpp b/Swiften/Elements/StreamResume.cpp
new file mode 100644
index 0000000..d55ef78
--- /dev/null
+++ b/Swiften/Elements/StreamResume.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Elements/StreamResume.h>
+
+using namespace Swift;
+
+StreamResume::StreamResume() {
+}
+
+StreamResume::~StreamResume() {
+}
diff --git a/Swiften/Elements/StreamResume.h b/Swiften/Elements/StreamResume.h
new file mode 100644
index 0000000..652182a
--- /dev/null
+++ b/Swiften/Elements/StreamResume.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <string>
+#include <boost/optional.hpp>
+
+#include <Swiften/Elements/Element.h>
+
+namespace Swift {
+ class StreamResume : public Element {
+ public:
+ StreamResume();
+ ~StreamResume();
+
+ void setResumeID(const std::string& id) {
+ resumeID = id;
+ }
+
+ const std::string& getResumeID() const {
+ return resumeID;
+ }
+
+ const boost::optional<int> getHandledStanzasCount() const {
+ return handledStanzasCount;
+ }
+
+ void setHandledStanzasCount(int i) {
+ handledStanzasCount = i;
+ }
+
+ private:
+ std::string resumeID;
+ boost::optional<int> handledStanzasCount;
+ };
+}
diff --git a/Swiften/Elements/StreamResumed.cpp b/Swiften/Elements/StreamResumed.cpp
new file mode 100644
index 0000000..552e654
--- /dev/null
+++ b/Swiften/Elements/StreamResumed.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Elements/StreamResumed.h>
+
+using namespace Swift;
+
+StreamResumed::StreamResumed() {
+}
+
+StreamResumed::~StreamResumed() {
+}
diff --git a/Swiften/Elements/StreamResumed.h b/Swiften/Elements/StreamResumed.h
new file mode 100644
index 0000000..cc42895
--- /dev/null
+++ b/Swiften/Elements/StreamResumed.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <string>
+#include <boost/optional.hpp>
+
+#include <Swiften/Elements/Element.h>
+
+namespace Swift {
+ class StreamResumed : public Element {
+ public:
+ StreamResumed();
+ ~StreamResumed();
+
+ void setResumeID(const std::string& id) {
+ resumeID = id;
+ }
+
+ const std::string& getResumeID() const {
+ return resumeID;
+ }
+
+ const boost::optional<int> getHandledStanzasCount() const {
+ return handledStanzasCount;
+ }
+
+ void setHandledStanzasCount(int i) {
+ handledStanzasCount = i;
+ }
+
+ private:
+ std::string resumeID;
+ boost::optional<int> handledStanzasCount;
+ };
+}
diff --git a/Swiften/Elements/UnitTest/StanzaTest.cpp b/Swiften/Elements/UnitTest/StanzaTest.cpp
index 4020f8b..4669f16 100644
--- a/Swiften/Elements/UnitTest/StanzaTest.cpp
+++ b/Swiften/Elements/UnitTest/StanzaTest.cpp
@@ -7,6 +7,7 @@
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <boost/shared_ptr.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
#include "Swiften/Elements/Stanza.h"
#include "Swiften/Elements/Payload.h"
diff --git a/Swiften/Entity/Entity.cpp b/Swiften/Entity/Entity.cpp
index da2ecaf..dea47b0 100644
--- a/Swiften/Entity/Entity.cpp
+++ b/Swiften/Entity/Entity.cpp
@@ -6,26 +6,45 @@
#include "Swiften/Entity/Entity.h"
+#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h"
+#include "Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h"
+
+
namespace Swift {
+Entity::Entity() {
+ payloadParserFactories = new FullPayloadParserFactoryCollection();
+ payloadSerializers = new FullPayloadSerializerCollection();
+}
+
Entity::~Entity() {
+ delete payloadSerializers;
+ delete payloadParserFactories;
}
void Entity::addPayloadParserFactory(PayloadParserFactory* payloadParserFactory) {
- payloadParserFactories.addFactory(payloadParserFactory);
+ payloadParserFactories->addFactory(payloadParserFactory);
}
void Entity::removePayloadParserFactory(PayloadParserFactory* payloadParserFactory) {
- payloadParserFactories.removeFactory(payloadParserFactory);
+ payloadParserFactories->removeFactory(payloadParserFactory);
}
void Entity::addPayloadSerializer(PayloadSerializer* payloadSerializer) {
- payloadSerializers.addSerializer(payloadSerializer);
+ payloadSerializers->addSerializer(payloadSerializer);
}
void Entity::removePayloadSerializer(PayloadSerializer* payloadSerializer) {
- payloadSerializers.removeSerializer(payloadSerializer);
+ payloadSerializers->removeSerializer(payloadSerializer);
+}
+
+PayloadParserFactoryCollection* Entity::getPayloadParserFactories() {
+ return payloadParserFactories;
+}
+
+PayloadSerializerCollection* Entity::getPayloadSerializers() {
+ return payloadSerializers;
}
}
diff --git a/Swiften/Entity/Entity.h b/Swiften/Entity/Entity.h
index 20d02ba..65480d0 100644
--- a/Swiften/Entity/Entity.h
+++ b/Swiften/Entity/Entity.h
@@ -6,21 +6,20 @@
#pragma once
-#include <Swiften/Base/boost_bsignals.h>
-#include <boost/shared_ptr.hpp>
-
-#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h"
-#include "Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h"
-
namespace Swift {
class PayloadParserFactory;
class PayloadSerializer;
+ class FullPayloadParserFactoryCollection;
+ class FullPayloadSerializerCollection;
+ class PayloadParserFactoryCollection;
+ class PayloadSerializerCollection;
/**
* The base class for XMPP entities (Clients, Components).
*/
class Entity {
public:
+ Entity();
virtual ~Entity();
void addPayloadParserFactory(PayloadParserFactory* payloadParserFactory);
@@ -30,16 +29,11 @@ namespace Swift {
void removePayloadSerializer(PayloadSerializer* payloadSerializer);
protected:
- PayloadParserFactoryCollection* getPayloadParserFactories() {
- return &payloadParserFactories;
- }
-
- PayloadSerializerCollection* getPayloadSerializers() {
- return &payloadSerializers;
- }
+ PayloadParserFactoryCollection* getPayloadParserFactories();
+ PayloadSerializerCollection* getPayloadSerializers();
private:
- FullPayloadParserFactoryCollection payloadParserFactories;
- FullPayloadSerializerCollection payloadSerializers;
+ FullPayloadParserFactoryCollection* payloadParserFactories;
+ FullPayloadSerializerCollection* payloadSerializers;
};
}
diff --git a/Swiften/Entity/GenericPayloadPersister.h b/Swiften/Entity/GenericPayloadPersister.h
new file mode 100644
index 0000000..63553de
--- /dev/null
+++ b/Swiften/Entity/GenericPayloadPersister.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Entity/PayloadPersister.h>
+#include <Swiften/Parser/GenericPayloadParserFactory.h>
+
+namespace Swift {
+ template<typename PAYLOAD, typename PARSER, typename SERIALIZER>
+ class GenericPayloadPersister : public PayloadPersister {
+ public:
+ GenericPayloadPersister() {
+ }
+
+ public:
+ boost::shared_ptr<PAYLOAD> loadPayloadGeneric(const boost::filesystem::path& path) {
+ return boost::dynamic_pointer_cast<PAYLOAD>(loadPayload(path));
+ }
+
+ protected:
+ virtual const PayloadSerializer* getSerializer() const {
+ return &serializer;
+ }
+
+ virtual PayloadParser* createParser() const {
+ return new PARSER();
+ }
+
+ private:
+ SERIALIZER serializer;
+ };
+}
diff --git a/Swiften/Entity/PayloadPersister.cpp b/Swiften/Entity/PayloadPersister.cpp
new file mode 100644
index 0000000..f7278cc
--- /dev/null
+++ b/Swiften/Entity/PayloadPersister.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Entity/PayloadPersister.h>
+
+#include <boost/filesystem/fstream.hpp>
+#include <boost/filesystem.hpp>
+#include <iostream>
+
+#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadParserTester.h>
+#include <Swiften/Base/ByteArray.h>
+#include <Swiften/Parser/PayloadParser.h>
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Serializer/PayloadSerializer.h>
+
+using namespace Swift;
+
+PayloadPersister::PayloadPersister() {
+}
+
+PayloadPersister::~PayloadPersister() {
+}
+
+void PayloadPersister::savePayload(boost::shared_ptr<Payload> payload, const boost::filesystem::path& path) {
+ if (!boost::filesystem::exists(path.parent_path())) {
+ try {
+ boost::filesystem::create_directories(path.parent_path());
+ }
+ catch (const boost::filesystem::filesystem_error& e) {
+ std::cerr << "ERROR: " << e.what() << std::endl;
+ }
+ }
+ boost::filesystem::ofstream file(path);
+ file << getSerializer()->serialize(payload);
+ file.close();
+}
+
+boost::shared_ptr<Payload> PayloadPersister::loadPayload(const boost::filesystem::path& path) {
+ if (boost::filesystem::exists(path)) {
+ ByteArray data;
+ data.readFromFile(path.string());
+ std::auto_ptr<PayloadParser> parser(createParser());
+ PayloadParserTester tester(parser.get());
+ tester.parse(data.toString());
+ return parser->getPayload();
+ }
+ else {
+ return boost::shared_ptr<Payload>();
+ }
+}
diff --git a/Swiften/Entity/PayloadPersister.h b/Swiften/Entity/PayloadPersister.h
new file mode 100644
index 0000000..ea7c74c
--- /dev/null
+++ b/Swiften/Entity/PayloadPersister.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+#include <boost/filesystem/path.hpp>
+
+namespace Swift {
+ class Payload;
+ class PayloadSerializer;
+ class PayloadParser;
+
+ class PayloadPersister {
+ public:
+ PayloadPersister();
+ virtual ~PayloadPersister();
+
+ void savePayload(boost::shared_ptr<Payload>, const boost::filesystem::path&);
+ boost::shared_ptr<Payload> loadPayload(const boost::filesystem::path&);
+
+ protected:
+
+ virtual const PayloadSerializer* getSerializer() const = 0;
+ virtual PayloadParser* createParser() const = 0;
+ };
+}
diff --git a/Swiften/EventLoop/DummyEventLoop.cpp b/Swiften/EventLoop/DummyEventLoop.cpp
new file mode 100644
index 0000000..3741eec
--- /dev/null
+++ b/Swiften/EventLoop/DummyEventLoop.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/EventLoop/DummyEventLoop.h>
+
+#include <iostream>
+
+namespace Swift {
+
+DummyEventLoop::DummyEventLoop() {
+}
+
+DummyEventLoop::~DummyEventLoop() {
+ if (!events_.empty()) {
+ std::cerr << "DummyEventLoop: Unhandled events at destruction time" << std::endl;
+ }
+ events_.clear();
+}
+
+
+}
diff --git a/Swiften/EventLoop/DummyEventLoop.h b/Swiften/EventLoop/DummyEventLoop.h
index b7ef516..68f9b85 100644
--- a/Swiften/EventLoop/DummyEventLoop.h
+++ b/Swiften/EventLoop/DummyEventLoop.h
@@ -7,24 +7,14 @@
#pragma once
#include <deque>
-#include <iostream>
-#include <boost/function.hpp>
#include "Swiften/EventLoop/EventLoop.h"
-#include "Swiften/Base/foreach.h"
namespace Swift {
class DummyEventLoop : public EventLoop {
public:
- DummyEventLoop() {
- }
-
- ~DummyEventLoop() {
- if (!events_.empty()) {
- std::cerr << "DummyEventLoop: Unhandled events at destruction time" << std::endl;
- }
- events_.clear();
- }
+ DummyEventLoop();
+ ~DummyEventLoop();
void processEvents() {
while (!events_.empty()) {
diff --git a/Swiften/EventLoop/EventLoop.cpp b/Swiften/EventLoop/EventLoop.cpp
index 56bb6ac..510ed63 100644
--- a/Swiften/EventLoop/EventLoop.cpp
+++ b/Swiften/EventLoop/EventLoop.cpp
@@ -9,6 +9,7 @@
#include <algorithm>
#include <boost/bind.hpp>
#include <iostream>
+#include <cassert>
#include <Swiften/Base/Log.h>
@@ -17,6 +18,7 @@ namespace Swift {
inline void invokeCallback(const Event& event) {
try {
+ assert(!event.callback.empty());
event.callback();
}
catch (const std::exception& e) {
diff --git a/Swiften/EventLoop/SConscript b/Swiften/EventLoop/SConscript
index 21ae8b9..e448f43 100644
--- a/Swiften/EventLoop/SConscript
+++ b/Swiften/EventLoop/SConscript
@@ -5,6 +5,7 @@ sources = [
"EventOwner.cpp",
"Event.cpp",
"SimpleEventLoop.cpp",
+ "DummyEventLoop.cpp",
]
objects = swiften_env.SwiftenObject(sources)
diff --git a/Swiften/Examples/BenchTool/BenchTool.cpp b/Swiften/Examples/BenchTool/BenchTool.cpp
index 9e54ed9..1fb6601 100644
--- a/Swiften/Examples/BenchTool/BenchTool.cpp
+++ b/Swiften/Examples/BenchTool/BenchTool.cpp
@@ -6,6 +6,7 @@
#include <boost/bind.hpp>
#include <boost/thread.hpp>
+#include <iostream>
#include "Swiften/Client/Client.h"
#include "Swiften/Network/TimerFactory.h"
diff --git a/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp b/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp
index fda203a..3b66d96 100644
--- a/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp
+++ b/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp
@@ -6,6 +6,7 @@
#include <boost/bind.hpp>
#include <boost/thread.hpp>
+#include <iostream>
#include "Swiften/Client/Client.h"
#include "Swiften/Network/Timer.h"
diff --git a/Swiften/Examples/SendFile/ReceiveFile.cpp b/Swiften/Examples/SendFile/ReceiveFile.cpp
index b46d790..effa1b7 100644
--- a/Swiften/Examples/SendFile/ReceiveFile.cpp
+++ b/Swiften/Examples/SendFile/ReceiveFile.cpp
@@ -7,7 +7,10 @@
#include <boost/bind.hpp>
#include <boost/filesystem.hpp>
#include <boost/smart_ptr/make_shared.hpp>
+#include <iostream>
+#include <Swiften/Elements/Presence.h>
+#include <Swiften/Base/foreach.h>
#include <Swiften/Client/Client.h>
#include <Swiften/Network/BoostNetworkFactories.h>
#include <Swiften/EventLoop/SimpleEventLoop.h>
diff --git a/Swiften/Examples/SendFile/SendFile.cpp b/Swiften/Examples/SendFile/SendFile.cpp
index 5ec00a9..d8300be 100644
--- a/Swiften/Examples/SendFile/SendFile.cpp
+++ b/Swiften/Examples/SendFile/SendFile.cpp
@@ -6,15 +6,17 @@
#include <boost/bind.hpp>
#include <boost/filesystem.hpp>
+#include <iostream>
#include "Swiften/Client/Client.h"
+#include <Swiften/Elements/Presence.h>
#include "Swiften/Network/BoostTimer.h"
#include "Swiften/Network/TimerFactory.h"
#include "Swiften/Network/BoostNetworkFactories.h"
#include "Swiften/EventLoop/EventLoop.h"
#include "Swiften/Client/ClientXMLTracer.h"
#include "Swiften/EventLoop/SimpleEventLoop.h"
-#include "Swiften/FileTransfer/OutgoingFileTransfer.h"
+#include "Swiften/FileTransfer/OutgoingSIFileTransfer.h"
#include "Swiften/FileTransfer/FileReadBytestream.h"
#include "Swiften/FileTransfer/SOCKS5BytestreamServer.h"
#include "Swiften/Network/BoostConnectionServer.h"
@@ -64,7 +66,7 @@ class FileSender {
private:
void handleConnected() {
client->sendPresence(Presence::create());
- transfer = new OutgoingFileTransfer("myid", client->getJID(), recipient, file.filename(), boost::filesystem::file_size(file), "A file", boost::shared_ptr<FileReadBytestream>(new FileReadBytestream(file)), client->getIQRouter(), socksBytestreamServer);
+ transfer = new OutgoingSIFileTransfer("myid", client->getJID(), recipient, file.filename(), boost::filesystem::file_size(file), "A file", boost::shared_ptr<FileReadBytestream>(new FileReadBytestream(file)), client->getIQRouter(), socksBytestreamServer);
transfer->onFinished.connect(boost::bind(&FileSender::handleFileTransferFinished, this, _1));
transfer->start();
}
@@ -99,7 +101,7 @@ class FileSender {
boost::filesystem::path file;
Client* client;
ClientXMLTracer* tracer;
- OutgoingFileTransfer* transfer;
+ OutgoingSIFileTransfer* transfer;
};
diff --git a/Swiften/Examples/SendMessage/SendMessage.cpp b/Swiften/Examples/SendMessage/SendMessage.cpp
index d7f7333..ad75318 100644
--- a/Swiften/Examples/SendMessage/SendMessage.cpp
+++ b/Swiften/Examples/SendMessage/SendMessage.cpp
@@ -6,8 +6,10 @@
#include <boost/bind.hpp>
#include <boost/thread.hpp>
+#include <iostream>
#include "Swiften/Client/Client.h"
+#include "Swiften/Elements/Message.h"
#include "Swiften/Network/BoostNetworkFactories.h"
#include "Swiften/Network/TimerFactory.h"
#include "Swiften/EventLoop/EventLoop.h"
diff --git a/Swiften/FileTransfer/ByteArrayReadBytestream.h b/Swiften/FileTransfer/ByteArrayReadBytestream.h
index d459658..4704db6 100644
--- a/Swiften/FileTransfer/ByteArrayReadBytestream.h
+++ b/Swiften/FileTransfer/ByteArrayReadBytestream.h
@@ -6,31 +6,32 @@
#pragma once
-#include "Swiften/FileTransfer/ReadBytestream.h"
-#include "Swiften/Base/ByteArray.h"
+#include <vector>
+
+#include <Swiften/FileTransfer/ReadBytestream.h>
namespace Swift {
class ByteArrayReadBytestream : public ReadBytestream {
public:
- ByteArrayReadBytestream(const ByteArray& data) : data(data), position(0) {
+ ByteArrayReadBytestream(const std::vector<unsigned char>& data) : data(data), position(0) {
}
- virtual ByteArray read(size_t size) {
+ virtual std::vector<unsigned char> read(size_t size) {
size_t readSize = size;
- if (position + readSize > data.getSize()) {
- readSize = data.getSize() - position;
+ if (position + readSize > data.size()) {
+ readSize = data.size() - position;
}
- ByteArray result(data.getData() + position, readSize);
+ std::vector<unsigned char> result(data.begin() + position, data.begin() + position + readSize);
position += readSize;
return result;
}
virtual bool isFinished() const {
- return position >= data.getSize();
+ return position >= data.size();
}
private:
- ByteArray data;
+ std::vector<unsigned char> data;
size_t position;
};
}
diff --git a/Swiften/FileTransfer/ByteArrayWriteBytestream.h b/Swiften/FileTransfer/ByteArrayWriteBytestream.h
new file mode 100644
index 0000000..6c360e6
--- /dev/null
+++ b/Swiften/FileTransfer/ByteArrayWriteBytestream.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/FileTransfer/WriteBytestream.h>
+
+namespace Swift {
+ class ByteArrayWriteBytestream : public WriteBytestream {
+ public:
+ ByteArrayWriteBytestream() {
+ }
+
+ virtual void write(const std::vector<unsigned char>& bytes) {
+ data.insert(data.end(), bytes.begin(), bytes.end());
+ }
+
+ const std::vector<unsigned char>& getData() const {
+ return data;
+ }
+
+ private:
+ std::vector<unsigned char> data;
+ };
+}
diff --git a/Swiften/FileTransfer/FileReadBytestream.cpp b/Swiften/FileTransfer/FileReadBytestream.cpp
index c08747b..e997366 100644
--- a/Swiften/FileTransfer/FileReadBytestream.cpp
+++ b/Swiften/FileTransfer/FileReadBytestream.cpp
@@ -21,14 +21,14 @@ FileReadBytestream::~FileReadBytestream() {
}
}
-ByteArray FileReadBytestream::read(size_t size) {
+std::vector<unsigned char> FileReadBytestream::read(size_t size) {
if (!stream) {
stream = new boost::filesystem::ifstream(file, std::ios_base::in|std::ios_base::binary);
}
- ByteArray result;
+ std::vector<unsigned char> result;
result.resize(size);
assert(stream->good());
- stream->read(reinterpret_cast<char*>(result.getData()), size);
+ stream->read(reinterpret_cast<char*>(&result[0]), size);
result.resize(stream->gcount());
return result;
}
diff --git a/Swiften/FileTransfer/FileReadBytestream.h b/Swiften/FileTransfer/FileReadBytestream.h
index 055e194..f136a68 100644
--- a/Swiften/FileTransfer/FileReadBytestream.h
+++ b/Swiften/FileTransfer/FileReadBytestream.h
@@ -6,7 +6,7 @@
#pragma once
-#include <boost/filesystem.hpp>
+#include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp>
#include "Swiften/FileTransfer/ReadBytestream.h"
@@ -17,7 +17,7 @@ namespace Swift {
FileReadBytestream(const boost::filesystem::path& file);
~FileReadBytestream();
- virtual ByteArray read(size_t size) ;
+ virtual std::vector<unsigned char> read(size_t size);
virtual bool isFinished() const;
private:
diff --git a/Swiften/FileTransfer/FileWriteBytestream.cpp b/Swiften/FileTransfer/FileWriteBytestream.cpp
index 4d29bd1..803a10b 100644
--- a/Swiften/FileTransfer/FileWriteBytestream.cpp
+++ b/Swiften/FileTransfer/FileWriteBytestream.cpp
@@ -21,12 +21,12 @@ FileWriteBytestream::~FileWriteBytestream() {
}
}
-void FileWriteBytestream::write(const ByteArray& data) {
+void FileWriteBytestream::write(const std::vector<unsigned char>& data) {
if (!stream) {
stream = new boost::filesystem::ofstream(file, std::ios_base::out|std::ios_base::binary);
}
assert(stream->good());
- stream->write(reinterpret_cast<const char*>(data.getData()), data.getSize());
+ stream->write(reinterpret_cast<const char*>(&data[0]), data.size());
}
}
diff --git a/Swiften/FileTransfer/FileWriteBytestream.h b/Swiften/FileTransfer/FileWriteBytestream.h
index c6f7b39..8cfa718 100644
--- a/Swiften/FileTransfer/FileWriteBytestream.h
+++ b/Swiften/FileTransfer/FileWriteBytestream.h
@@ -6,10 +6,10 @@
#pragma once
-#include <boost/filesystem.hpp>
+#include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp>
-#include "Swiften/FileTransfer/WriteBytestream.h"
+#include <Swiften/FileTransfer/WriteBytestream.h>
namespace Swift {
class FileWriteBytestream : public WriteBytestream {
@@ -17,7 +17,7 @@ namespace Swift {
FileWriteBytestream(const boost::filesystem::path& file);
~FileWriteBytestream();
- virtual void write(const ByteArray&);
+ virtual void write(const std::vector<unsigned char>&);
private:
boost::filesystem::path file;
diff --git a/Swiften/FileTransfer/IBBReceiveSession.cpp b/Swiften/FileTransfer/IBBReceiveSession.cpp
index 5c90757..566dcca 100644
--- a/Swiften/FileTransfer/IBBReceiveSession.cpp
+++ b/Swiften/FileTransfer/IBBReceiveSession.cpp
@@ -4,31 +4,96 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#include "Swiften/FileTransfer/IBBReceiveSession.h"
+#include <Swiften/FileTransfer/IBBReceiveSession.h>
#include <boost/bind.hpp>
-#include "Swiften/Queries/IQRouter.h"
-#include "Swiften/FileTransfer/IBBRequest.h"
-#include "Swiften/FileTransfer/BytestreamException.h"
+#include <Swiften/Base/Log.h>
+#include <Swiften/Queries/IQRouter.h>
+#include <Swiften/FileTransfer/IBBRequest.h>
+#include <Swiften/FileTransfer/BytestreamException.h>
+#include <Swiften/Queries/SetResponder.h>
namespace Swift {
-IBBReceiveSession::IBBReceiveSession(const std::string& id, const JID& from, size_t size, WriteBytestream::ref bytestream, IQRouter* router) : SetResponder<IBB>(router), id(id), from(from), size(size), bytestream(bytestream), router(router), sequenceNumber(0), active(false), receivedSize(0) {
+class IBBReceiveSession::IBBResponder : public SetResponder<IBB> {
+ public:
+ IBBResponder(IBBReceiveSession* session, IQRouter* router) : SetResponder<IBB>(router), session(session), sequenceNumber(0), receivedSize(0) {
+ }
+
+ virtual bool handleSetRequest(const JID& from, const JID&, const std::string& id, IBB::ref ibb) {
+ if (from == session->from && ibb->getStreamID() == session->id) {
+ if (ibb->getAction() == IBB::Data) {
+ if (sequenceNumber == ibb->getSequenceNumber()) {
+ session->onDataReceived(ibb->getData());
+ receivedSize += ibb->getData().size();
+ sequenceNumber++;
+ sendResponse(from, id, IBB::ref());
+ if (receivedSize >= session->size) {
+ if (receivedSize > session->size) {
+ std::cerr << "Warning: Received more data than expected" << std::endl;
+ }
+ session->finish(boost::optional<FileTransferError>());
+ }
+ }
+ else {
+ SWIFT_LOG(warning) << "Received data out of order" << std::endl;
+ sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Cancel);
+ session->finish(FileTransferError(FileTransferError::ClosedError));
+ }
+ }
+ else if (ibb->getAction() == IBB::Open) {
+ sendResponse(from, id, IBB::ref());
+ }
+ else if (ibb->getAction() == IBB::Close) {
+ sendResponse(from, id, IBB::ref());
+ session->finish(FileTransferError(FileTransferError::ClosedError));
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ IBBReceiveSession* session;
+ int sequenceNumber;
+ size_t receivedSize;
+};
+
+
+IBBReceiveSession::IBBReceiveSession(
+ const std::string& id,
+ const JID& from,
+ size_t size,
+ IQRouter* router) :
+ id(id),
+ from(from),
+ size(size),
+ router(router),
+ active(false) {
+ responder = new IBBResponder(this, router);
}
IBBReceiveSession::~IBBReceiveSession() {
+ if (active) {
+ SWIFT_LOG(warning) << "Session still active" << std::endl;
+ }
+ delete responder;
}
void IBBReceiveSession::start() {
active = true;
+ responder->start();
}
void IBBReceiveSession::stop() {
- if (active && router->isAvailable()) {
- IBBRequest::create(from, IBB::createIBBClose(id), router)->send();
+ responder->stop();
+ if (active) {
+ if (router->isAvailable()) {
+ IBBRequest::create(from, IBB::createIBBClose(id), router)->send();
+ }
+ finish(boost::optional<FileTransferError>());
}
- finish(boost::optional<FileTransferError>());
}
void IBBReceiveSession::finish(boost::optional<FileTransferError> error) {
@@ -36,34 +101,4 @@ void IBBReceiveSession::finish(boost::optional<FileTransferError> error) {
onFinished(error);
}
-bool IBBReceiveSession::handleSetRequest(const JID& from, const JID&, const std::string& id, IBB::ref ibb) {
- if (from == this->from && ibb->getStreamID() == id) {
- if (ibb->getAction() == IBB::Data) {
- if (sequenceNumber == ibb->getSequenceNumber()) {
- bytestream->write(ibb->getData());
- receivedSize += ibb->getData().getSize();
- if (receivedSize >= size) {
- if (receivedSize > size) {
- std::cerr << "Warning: Received more data than expected" << std::endl;
- }
- finish(boost::optional<FileTransferError>());
- }
- }
- else {
- sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Cancel);
- finish(FileTransferError(FileTransferError::ClosedError));
- }
- }
- else if (ibb->getAction() == IBB::Open) {
- sendResponse(from, id, IBB::ref());
- }
- else if (ibb->getAction() == IBB::Close) {
- sendResponse(from, id, IBB::ref());
- finish(FileTransferError(FileTransferError::ClosedError));
- }
- return true;
- }
- return false;
-}
-
}
diff --git a/Swiften/FileTransfer/IBBReceiveSession.h b/Swiften/FileTransfer/IBBReceiveSession.h
index 6d936de..d512025 100644
--- a/Swiften/FileTransfer/IBBReceiveSession.h
+++ b/Swiften/FileTransfer/IBBReceiveSession.h
@@ -7,27 +7,30 @@
#pragma once
#include <boost/shared_ptr.hpp>
-#include <boost/optional.hpp>
+#include <boost/optional/optional_fwd.hpp>
#include "Swiften/Base/boost_bsignals.h"
#include "Swiften/FileTransfer/WriteBytestream.h"
#include "Swiften/JID/JID.h"
#include "Swiften/Elements/IBB.h"
-#include "Swiften/Elements/ErrorPayload.h"
#include "Swiften/FileTransfer/FileTransferError.h"
-#include "Swiften/Queries/SetResponder.h"
namespace Swift {
class IQRouter;
- class IBBReceiveSession : public SetResponder<IBB> {
+ class IBBReceiveSession {
public:
- IBBReceiveSession(const std::string& id, const JID& from, size_t size, WriteBytestream::ref bytestream, IQRouter* router);
+ IBBReceiveSession(
+ const std::string& id,
+ const JID& from,
+ size_t size,
+ IQRouter* router);
~IBBReceiveSession();
void start();
void stop();
+ boost::signal<void (const std::vector<unsigned char>&)> onDataReceived;
boost::signal<void (boost::optional<FileTransferError>)> onFinished;
private:
@@ -35,13 +38,14 @@ namespace Swift {
void finish(boost::optional<FileTransferError>);
private:
+ class IBBResponder;
+ friend class IBBResponder;
+
std::string id;
JID from;
size_t size;
- WriteBytestream::ref bytestream;
IQRouter* router;
- int sequenceNumber;
+ IBBResponder* responder;
bool active;
- size_t receivedSize;
};
}
diff --git a/Swiften/FileTransfer/IBBSendSession.cpp b/Swiften/FileTransfer/IBBSendSession.cpp
index 0fb47d3..c31fe4a 100644
--- a/Swiften/FileTransfer/IBBSendSession.cpp
+++ b/Swiften/FileTransfer/IBBSendSession.cpp
@@ -38,13 +38,13 @@ void IBBSendSession::handleIBBResponse(IBB::ref, ErrorPayload::ref error) {
if (!error) {
if (!bytestream->isFinished()) {
try {
- ByteArray data = bytestream->read(blockSize);
+ std::vector<unsigned char> data = bytestream->read(blockSize);
IBBRequest::ref request = IBBRequest::create(to, IBB::createIBBData(id, sequenceNumber, data), router);
sequenceNumber++;
request->onResponse.connect(boost::bind(&IBBSendSession::handleIBBResponse, this, _1, _2));
request->send();
}
- catch (const BytestreamException& e) {
+ catch (const BytestreamException&) {
finish(FileTransferError(FileTransferError::ReadError));
}
}
diff --git a/Swiften/FileTransfer/IncomingFileTransfer.cpp b/Swiften/FileTransfer/IncomingFileTransfer.cpp
index 238ccce..7c97e4d 100644
--- a/Swiften/FileTransfer/IncomingFileTransfer.cpp
+++ b/Swiften/FileTransfer/IncomingFileTransfer.cpp
@@ -4,20 +4,11 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#include "Swiften/FileTransfer/IncomingFileTransfer.h"
+#include <Swiften/FileTransfer/IncomingFileTransfer.h>
namespace Swift {
IncomingFileTransfer::~IncomingFileTransfer() {
-
-}
-
-/*void IncomingFileTransfer::accept(WriteBytestream::ref) {
-
}
-void IncomingFileTransfer::stop() {
-
-}*/
-
}
diff --git a/Swiften/FileTransfer/IncomingFileTransferManager.cpp b/Swiften/FileTransfer/IncomingFileTransferManager.cpp
index 5535840..79d2391 100644
--- a/Swiften/FileTransfer/IncomingFileTransferManager.cpp
+++ b/Swiften/FileTransfer/IncomingFileTransferManager.cpp
@@ -10,8 +10,10 @@
#include <Swiften/Elements/JingleDescription.h>
#include <Swiften/Elements/JingleFileTransferDescription.h>
-#include <Swiften/Elements/JingleIBBTransport.h>
+#include <Swiften/Elements/JingleIBBTransportPayload.h>
+#include <Swiften/Elements/JingleS5BTransportPayload.h>
#include <Swiften/Jingle/JingleSessionManager.h>
+#include <Swiften/Jingle/Jingle.h>
#include <Swiften/FileTransfer/IncomingJingleFileTransfer.h>
namespace Swift {
@@ -24,12 +26,12 @@ IncomingFileTransferManager::~IncomingFileTransferManager() {
jingleSessionManager->removeIncomingSessionHandler(this);
}
-bool IncomingFileTransferManager::handleIncomingJingleSession(IncomingJingleSession::ref session) {
- JingleContent::ref content = session->getContentWithDescription<JingleFileTransferDescription>();
- if (content) {
- // Check for supported transports
- if (content->getTransport<JingleIBBTransport>()) {
- IncomingJingleFileTransfer::ref transfer = boost::make_shared<IncomingJingleFileTransfer>(session);
+bool IncomingFileTransferManager::handleIncomingJingleSession(JingleSession::ref session, const std::vector<JingleContentPayload::ref>& contents) {
+ if (JingleContentPayload::ref content = Jingle::getContentWithDescription<JingleFileTransferDescription>(contents)) {
+ if (content->getTransport<JingleIBBTransportPayload>() || content->getTransport<JingleS5BTransportPayload>()) {
+ RemoteJingleTransportCandidateSelectorFactory* a;
+ LocalJingleTransportCandidateGeneratorFactory* b;
+ IncomingJingleFileTransfer::ref transfer = boost::make_shared<IncomingJingleFileTransfer>(session, content, a, b, router);
onIncomingFileTransfer(transfer);
}
else {
diff --git a/Swiften/FileTransfer/IncomingFileTransferManager.h b/Swiften/FileTransfer/IncomingFileTransferManager.h
index a54b5cd..428a838 100644
--- a/Swiften/FileTransfer/IncomingFileTransferManager.h
+++ b/Swiften/FileTransfer/IncomingFileTransferManager.h
@@ -15,6 +15,8 @@
namespace Swift {
class IQRouter;
class JingleSessionManager;
+ class RemoteJingleTransportCandidateSelectorFactory;
+ class LocalJingleTransportCandidateGeneratorFactory;
class IncomingFileTransferManager : public IncomingJingleSessionHandler {
public:
@@ -24,7 +26,7 @@ namespace Swift {
boost::signal<void (IncomingFileTransfer::ref)> onIncomingFileTransfer;
private:
- bool handleIncomingJingleSession(IncomingJingleSession::ref session);
+ bool handleIncomingJingleSession(JingleSession::ref session, const std::vector<JingleContentPayload::ref>& contents);
private:
JingleSessionManager* jingleSessionManager;
diff --git a/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp b/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp
index cb2f65c..904b53e 100644
--- a/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp
+++ b/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp
@@ -6,14 +6,164 @@
#include <Swiften/FileTransfer/IncomingJingleFileTransfer.h>
+#include <boost/bind.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h>
+#include <Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h>
+#include <Swiften/FileTransfer/JingleIncomingIBBTransport.h>
+#include <Swiften/Elements/JingleIBBTransportPayload.h>
+#include <Swiften/Elements/JingleS5BTransportPayload.h>
+#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h>
+#include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h>
+
namespace Swift {
-IncomingJingleFileTransfer::IncomingJingleFileTransfer(IncomingJingleSession::ref session) : session(session) {
+IncomingJingleFileTransfer::IncomingJingleFileTransfer(
+ JingleSession::ref session,
+ JingleContentPayload::ref content,
+ RemoteJingleTransportCandidateSelectorFactory* candidateSelectorFactory,
+ LocalJingleTransportCandidateGeneratorFactory* candidateGeneratorFactory,
+ IQRouter* router) :
+ session(session),
+ router(router),
+ initialContent(content),
+ contentID(content->getName(), content->getCreator()),
+ state(Initial),
+ remoteTransportCandidateSelectFinished(false),
+ localTransportCandidateSelectFinished(false) {
+
+ candidateSelector = candidateSelectorFactory->createCandidateSelector();
+ candidateSelector->onRemoteTransportCandidateSelectFinished.connect(boost::bind(&IncomingJingleFileTransfer::handleRemoteTransportCandidateSelectFinished, this, _1));
+
+ candidateGenerator = candidateGeneratorFactory->createCandidateGenerator();
+ candidateGenerator->onLocalTransportCandidatesGenerated.connect(boost::bind(&IncomingJingleFileTransfer::handleLocalTransportCandidatesGenerated, this, _1));
+
+ session->onTransportInfoReceived.connect(boost::bind(&IncomingJingleFileTransfer::handleTransportInfoReceived, this, _1, _2));
+ session->onTransportReplaceReceived.connect(boost::bind(&IncomingJingleFileTransfer::handleTransportReplaceReceived, this, _1, _2));
+ session->onSessionTerminateReceived.connect(boost::bind(&IncomingJingleFileTransfer::handleSessionTerminateReceived, this));
+
+ description = initialContent->getDescription<JingleFileTransferDescription>();
+ assert(description);
+}
+
+IncomingJingleFileTransfer::~IncomingJingleFileTransfer() {
+ session->onSessionTerminateReceived.disconnect(boost::bind(&IncomingJingleFileTransfer::handleSessionTerminateReceived, this));
+ session->onTransportReplaceReceived.disconnect(boost::bind(&IncomingJingleFileTransfer::handleTransportReplaceReceived, this, _1, _2));
+ session->onTransportInfoReceived.disconnect(boost::bind(&IncomingJingleFileTransfer::handleTransportInfoReceived, this, _1, _2));
+
+ candidateGenerator->onLocalTransportCandidatesGenerated.disconnect(boost::bind(&IncomingJingleFileTransfer::handleLocalTransportCandidatesGenerated, this, _1));
+ delete candidateGenerator;
+ candidateSelector->onRemoteTransportCandidateSelectFinished.disconnect(boost::bind(&IncomingJingleFileTransfer::handleRemoteTransportCandidateSelectFinished, this, _1));
+ delete candidateSelector;
}
void IncomingJingleFileTransfer::accept(WriteBytestream::ref stream) {
+ assert(!stream);
this->stream = stream;
+
+ if (JingleIBBTransportPayload::ref ibbTransport = initialContent->getTransport<JingleIBBTransportPayload>()) {
+ setActiveTransport(createIBBTransport(ibbTransport));
+ session->accept();
+ }
+ else if (JingleS5BTransportPayload::ref s5bTransport = initialContent->getTransport<JingleS5BTransportPayload>()) {
+ state = CreatingInitialTransports;
+ candidateSelector->addRemoteTransportCandidates(s5bTransport);
+ candidateGenerator->generateLocalTransportCandidates();
+ }
+ else {
+ assert(false);
+ }
+}
+
+
+void IncomingJingleFileTransfer::handleLocalTransportCandidatesGenerated(JingleTransportPayload::ref candidates) {
+ if (state == CreatingInitialTransports) {
+ if (!candidates) {
+ localTransportCandidateSelectFinished = true;
+ }
+ session->accept(candidates);
+ state = NegotiatingTransport;
+ candidateSelector->selectCandidate();
+ }
+}
+
+
+void IncomingJingleFileTransfer::handleRemoteTransportCandidateSelectFinished(JingleTransportPayload::ref transport) {
+ remoteTransportCandidateSelectFinished = true;
+ selectedRemoteTransportCandidate = transport;
+ session->sendTransportInfo(contentID, transport);
+ checkCandidateSelected();
+}
+
+void IncomingJingleFileTransfer::checkCandidateSelected() {
+ if (localTransportCandidateSelectFinished && remoteTransportCandidateSelectFinished) {
+ if (candidateGenerator->isActualCandidate(selectedLocalTransportCandidate) && candidateSelector->isActualCandidate(selectedRemoteTransportCandidate)) {
+ if (candidateGenerator->getPriority(selectedLocalTransportCandidate) > candidateSelector->getPriority(selectedRemoteTransportCandidate)) {
+ setActiveTransport(candidateGenerator->selectTransport(selectedLocalTransportCandidate));
+ }
+ else {
+ setActiveTransport(candidateSelector->selectTransport(selectedRemoteTransportCandidate));
+ }
+ }
+ else if (candidateSelector->isActualCandidate(selectedRemoteTransportCandidate)) {
+ setActiveTransport(candidateSelector->selectTransport(selectedRemoteTransportCandidate));
+ }
+ else if (candidateGenerator->isActualCandidate(selectedLocalTransportCandidate)) {
+ setActiveTransport(candidateGenerator->selectTransport(selectedLocalTransportCandidate));
+ }
+ else {
+ state = WaitingForFallbackOrTerminate;
+ }
+ }
+}
+
+void IncomingJingleFileTransfer::setActiveTransport(JingleTransport::ref transport) {
+ state = Transferring;
+ activeTransport = transport;
+ activeTransport->onDataReceived.connect(boost::bind(&IncomingJingleFileTransfer::handleTransportDataReceived, this, _1));
+ activeTransport->start();
+}
+
+void IncomingJingleFileTransfer::handleSessionTerminateReceived() {
+ // TODO
+ state = Terminated;
+}
+
+void IncomingJingleFileTransfer::handleTransportDataReceived(const std::vector<unsigned char>& data) {
+ stream->write(data);
+}
+
+
+void IncomingJingleFileTransfer::handleTransportInfoReceived(const JingleContentID&, JingleTransportPayload::ref transport) {
+ localTransportCandidateSelectFinished = true;
+ selectedLocalTransportCandidate = transport;
+ if (candidateGenerator->isActualCandidate(transport)) {
+ candidateSelector->setMinimumPriority(candidateGenerator->getPriority(transport));
+ }
+ checkCandidateSelected();
+}
+
+void IncomingJingleFileTransfer::handleTransportReplaceReceived(const JingleContentID& content, JingleTransportPayload::ref transport) {
+ if (JingleIBBTransportPayload::ref ibbTransport = boost::dynamic_pointer_cast<JingleIBBTransportPayload>(transport)) {
+ setActiveTransport(createIBBTransport(ibbTransport));
+ session->acceptTransport(content, transport);
+ }
+ else {
+ session->rejectTransport(content, transport);
+ }
+}
+
+void IncomingJingleFileTransfer::stopActiveTransport() {
+ if (activeTransport) {
+ activeTransport->stop();
+ activeTransport->onDataReceived.disconnect(boost::bind(&IncomingJingleFileTransfer::handleTransportDataReceived, this, _1));
+ }
+}
+
+JingleIncomingIBBTransport::ref IncomingJingleFileTransfer::createIBBTransport(JingleIBBTransportPayload::ref ibbTransport) {
+ return boost::make_shared<JingleIncomingIBBTransport>(session->getInitiator(), ibbTransport->getSessionID(), description->getOffer()->size, router);
}
}
diff --git a/Swiften/FileTransfer/IncomingJingleFileTransfer.h b/Swiften/FileTransfer/IncomingJingleFileTransfer.h
index d69449e..164d868 100644
--- a/Swiften/FileTransfer/IncomingJingleFileTransfer.h
+++ b/Swiften/FileTransfer/IncomingJingleFileTransfer.h
@@ -8,20 +8,71 @@
#include <boost/shared_ptr.hpp>
-#include <Swiften/Jingle/IncomingJingleSession.h>
+#include <Swiften/Jingle/JingleSession.h>
+#include <Swiften/Jingle/JingleContentID.h>
#include <Swiften/FileTransfer/IncomingFileTransfer.h>
+#include <Swiften/FileTransfer/JingleTransport.h>
+#include <Swiften/FileTransfer/JingleIncomingIBBTransport.h>
+#include <Swiften/Elements/JingleContentPayload.h>
+#include <Swiften/Elements/JingleFileTransferDescription.h>
+#include <Swiften/Elements/JingleIBBTransportPayload.h>
namespace Swift {
+ class IQRouter;
+ class RemoteJingleTransportCandidateSelectorFactory;
+ class LocalJingleTransportCandidateGeneratorFactory;
+ class RemoteJingleTransportCandidateSelector;
+ class LocalJingleTransportCandidateGenerator;
+
class IncomingJingleFileTransfer : public IncomingFileTransfer {
public:
typedef boost::shared_ptr<IncomingJingleFileTransfer> ref;
+ enum State {
+ Initial,
+ CreatingInitialTransports,
+ NegotiatingTransport,
+ Transferring,
+ WaitingForFallbackOrTerminate,
+ Terminated
+ };
- IncomingJingleFileTransfer(IncomingJingleSession::ref session);
+ IncomingJingleFileTransfer(
+ JingleSession::ref,
+ JingleContentPayload::ref content,
+ RemoteJingleTransportCandidateSelectorFactory*,
+ LocalJingleTransportCandidateGeneratorFactory*,
+ IQRouter* router);
+ ~IncomingJingleFileTransfer();
virtual void accept(WriteBytestream::ref);
private:
- IncomingJingleSession::ref session;
+ void handleSessionTerminateReceived();
+ void handleTransportReplaceReceived(const JingleContentID&, JingleTransportPayload::ref);
+ void handleTransportInfoReceived(const JingleContentID&, JingleTransportPayload::ref);
+ void handleLocalTransportCandidatesGenerated(JingleTransportPayload::ref candidates);
+ void handleRemoteTransportCandidateSelectFinished(JingleTransportPayload::ref candidate);
+ void setActiveTransport(JingleTransport::ref transport);
+ void handleTransportDataReceived(const std::vector<unsigned char>& data);
+ void stopActiveTransport();
+ void checkCandidateSelected();
+ JingleIncomingIBBTransport::ref createIBBTransport(JingleIBBTransportPayload::ref ibbTransport);
+
+ private:
+ JingleSession::ref session;
+ IQRouter* router;
+ JingleContentPayload::ref initialContent;
+ JingleContentID contentID;
+ State state;
+ JingleFileTransferDescription::ref description;
WriteBytestream::ref stream;
+ RemoteJingleTransportCandidateSelector* candidateSelector;
+ LocalJingleTransportCandidateGenerator* candidateGenerator;
+ bool remoteTransportCandidateSelectFinished;
+ JingleTransportPayload::ref selectedRemoteTransportCandidate;
+ bool localTransportCandidateSelectFinished;
+ JingleTransportPayload::ref selectedLocalTransportCandidate;
+
+ JingleTransport::ref activeTransport;
};
}
diff --git a/Swiften/FileTransfer/JingleIncomingIBBTransport.cpp b/Swiften/FileTransfer/JingleIncomingIBBTransport.cpp
new file mode 100644
index 0000000..0ca899f
--- /dev/null
+++ b/Swiften/FileTransfer/JingleIncomingIBBTransport.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/FileTransfer/JingleIncomingIBBTransport.h>
+
+namespace Swift {
+
+JingleIncomingIBBTransport::JingleIncomingIBBTransport(const JID& from, const std::string& id, size_t size, IQRouter* router) : ibbSession(from, id, size, router) {
+ ibbSession.onDataReceived.connect(boost::ref(onDataReceived));
+}
+
+void JingleIncomingIBBTransport::start() {
+ ibbSession.start();
+}
+
+void JingleIncomingIBBTransport::stop() {
+ ibbSession.stop();
+}
+
+}
diff --git a/Swiften/FileTransfer/JingleIncomingIBBTransport.h b/Swiften/FileTransfer/JingleIncomingIBBTransport.h
new file mode 100644
index 0000000..e2fa485
--- /dev/null
+++ b/Swiften/FileTransfer/JingleIncomingIBBTransport.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/FileTransfer/JingleTransport.h>
+#include <Swiften/FileTransfer/IBBReceiveSession.h>
+
+namespace Swift {
+ class JingleIncomingIBBTransport : public JingleTransport {
+ public:
+ typedef boost::shared_ptr<JingleIncomingIBBTransport> ref;
+
+ JingleIncomingIBBTransport(const JID& from, const std::string& id, size_t size, IQRouter* router);
+
+ virtual void start();
+ virtual void stop();
+
+ private:
+ IBBReceiveSession ibbSession;
+ };
+}
diff --git a/Swiften/FileTransfer/JingleTransport.cpp b/Swiften/FileTransfer/JingleTransport.cpp
new file mode 100644
index 0000000..c507922
--- /dev/null
+++ b/Swiften/FileTransfer/JingleTransport.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/FileTransfer/JingleTransport.h>
+
+namespace Swift {
+
+JingleTransport::~JingleTransport() {
+
+}
+
+}
diff --git a/Swiften/FileTransfer/JingleTransport.h b/Swiften/FileTransfer/JingleTransport.h
new file mode 100644
index 0000000..1d163d0
--- /dev/null
+++ b/Swiften/FileTransfer/JingleTransport.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/boost_bsignals.h>
+
+namespace Swift {
+ class JingleTransport {
+ public:
+ typedef boost::shared_ptr<JingleTransport> ref;
+
+ virtual ~JingleTransport();
+
+ virtual void start() = 0;
+ virtual void stop() = 0;
+
+ boost::signal<void (const std::vector<unsigned char>&)> onDataReceived;
+ };
+}
diff --git a/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp
new file mode 100644
index 0000000..852902b
--- /dev/null
+++ b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h>
+
+namespace Swift {
+
+LocalJingleTransportCandidateGenerator::~LocalJingleTransportCandidateGenerator() {
+}
+
+}
diff --git a/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h
new file mode 100644
index 0000000..c111005
--- /dev/null
+++ b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/boost_bsignals.h>
+
+#include <Swiften/Elements/JingleTransportPayload.h>
+#include <Swiften/FileTransfer/JingleTransport.h>
+
+namespace Swift {
+ class LocalJingleTransportCandidateGenerator {
+ public:
+ virtual ~LocalJingleTransportCandidateGenerator();
+
+ virtual void generateLocalTransportCandidates() = 0;
+
+ virtual bool isActualCandidate(JingleTransportPayload::ref) = 0;
+ virtual int getPriority(JingleTransportPayload::ref) = 0;
+ virtual JingleTransport::ref selectTransport(JingleTransportPayload::ref) = 0;
+
+ boost::signal<void (JingleTransportPayload::ref)> onLocalTransportCandidatesGenerated;
+ };
+}
diff --git a/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.cpp b/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.cpp
new file mode 100644
index 0000000..a1e3874
--- /dev/null
+++ b/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.cpp
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h>
+
+namespace Swift {
+
+LocalJingleTransportCandidateGeneratorFactory::~LocalJingleTransportCandidateGeneratorFactory() {
+}
+
+}
diff --git a/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h b/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h
new file mode 100644
index 0000000..c969fc7
--- /dev/null
+++ b/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+namespace Swift {
+ class LocalJingleTransportCandidateGenerator;
+
+ class LocalJingleTransportCandidateGeneratorFactory {
+ public:
+ virtual ~LocalJingleTransportCandidateGeneratorFactory();
+
+ virtual LocalJingleTransportCandidateGenerator* createCandidateGenerator() = 0;
+ };
+}
diff --git a/Swiften/FileTransfer/OutgoingFileTransfer.cpp b/Swiften/FileTransfer/OutgoingFileTransfer.cpp
index 32f7e17..94d4348 100644
--- a/Swiften/FileTransfer/OutgoingFileTransfer.cpp
+++ b/Swiften/FileTransfer/OutgoingFileTransfer.cpp
@@ -4,75 +4,11 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#include "Swiften/FileTransfer/OutgoingFileTransfer.h"
-
-#include <boost/bind.hpp>
-
-#include "Swiften/FileTransfer/StreamInitiationRequest.h"
-#include "Swiften/FileTransfer/BytestreamsRequest.h"
-#include "Swiften/FileTransfer/SOCKS5BytestreamServer.h"
-#include "Swiften/FileTransfer/IBBSendSession.h"
+#include <Swiften/FileTransfer/OutgoingFileTransfer.h>
namespace Swift {
-OutgoingFileTransfer::OutgoingFileTransfer(const std::string& id, const JID& from, const JID& to, const std::string& name, int size, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* iqRouter, SOCKS5BytestreamServer* socksServer) : id(id), from(from), to(to), name(name), size(size), description(description), bytestream(bytestream), iqRouter(iqRouter), socksServer(socksServer) {
-}
-
-void OutgoingFileTransfer::start() {
- StreamInitiation::ref streamInitiation(new StreamInitiation());
- streamInitiation->setID(id);
- streamInitiation->setFileInfo(StreamInitiationFileInfo(name, description, size));
- //streamInitiation->addProvidedMethod("http://jabber.org/protocol/bytestreams");
- streamInitiation->addProvidedMethod("http://jabber.org/protocol/ibb");
- StreamInitiationRequest::ref request = StreamInitiationRequest::create(to, streamInitiation, iqRouter);
- request->onResponse.connect(boost::bind(&OutgoingFileTransfer::handleStreamInitiationRequestResponse, this, _1, _2));
- request->send();
-}
-
-void OutgoingFileTransfer::stop() {
-}
-
-void OutgoingFileTransfer::handleStreamInitiationRequestResponse(StreamInitiation::ref response, ErrorPayload::ref error) {
- if (error) {
- finish(FileTransferError());
- }
- else {
- if (response->getRequestedMethod() == "http://jabber.org/protocol/bytestreams") {
- socksServer->addBytestream(id, from, to, bytestream);
- Bytestreams::ref bytestreams(new Bytestreams());
- bytestreams->setStreamID(id);
- HostAddressPort addressPort = socksServer->getAddressPort();
- bytestreams->addStreamHost(Bytestreams::StreamHost(addressPort.getAddress().toString(), from, addressPort.getPort()));
- BytestreamsRequest::ref request = BytestreamsRequest::create(to, bytestreams, iqRouter);
- request->onResponse.connect(boost::bind(&OutgoingFileTransfer::handleBytestreamsRequestResponse, this, _1, _2));
- request->send();
- }
- else if (response->getRequestedMethod() == "http://jabber.org/protocol/ibb") {
- ibbSession = boost::shared_ptr<IBBSendSession>(new IBBSendSession(id, to, bytestream, iqRouter));
- ibbSession->onFinished.connect(boost::bind(&OutgoingFileTransfer::handleIBBSessionFinished, this, _1));
- ibbSession->start();
- }
- }
-}
-
-void OutgoingFileTransfer::handleBytestreamsRequestResponse(Bytestreams::ref, ErrorPayload::ref error) {
- if (error) {
- finish(FileTransferError());
- }
- //socksServer->onTransferFinished.connect();
-}
-
-void OutgoingFileTransfer::finish(boost::optional<FileTransferError> error) {
- if (ibbSession) {
- ibbSession->onFinished.disconnect(boost::bind(&OutgoingFileTransfer::handleIBBSessionFinished, this, _1));
- ibbSession.reset();
- }
- socksServer->removeBytestream(id, from, to);
- onFinished(error);
-}
-
-void OutgoingFileTransfer::handleIBBSessionFinished(boost::optional<FileTransferError> error) {
- finish(error);
+OutgoingFileTransfer::~OutgoingFileTransfer() {
}
}
diff --git a/Swiften/FileTransfer/OutgoingFileTransfer.h b/Swiften/FileTransfer/OutgoingFileTransfer.h
index a694c13..a8c1e81 100644
--- a/Swiften/FileTransfer/OutgoingFileTransfer.h
+++ b/Swiften/FileTransfer/OutgoingFileTransfer.h
@@ -6,47 +6,12 @@
#pragma once
-#include <boost/shared_ptr.hpp>
-
-#include "Swiften/FileTransfer/ReadBytestream.h"
-#include "Swiften/Base/boost_bsignals.h"
-#include "Swiften/FileTransfer/FileTransferError.h"
-#include "Swiften/FileTransfer/SOCKS5BytestreamServer.h"
-#include "Swiften/JID/JID.h"
-#include "Swiften/Elements/StreamInitiation.h"
-#include "Swiften/Elements/Bytestreams.h"
-#include "Swiften/Elements/ErrorPayload.h"
-#include "Swiften/FileTransfer/IBBSendSession.h"
-
namespace Swift {
- class IQRouter;
- class SOCKS5BytestreamServer;
-
class OutgoingFileTransfer {
public:
- OutgoingFileTransfer(const std::string& id, const JID& from, const JID& to, const std::string& name, int size, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* iqRouter, SOCKS5BytestreamServer* socksServer);
-
- void start();
- void stop();
-
- boost::signal<void (const boost::optional<FileTransferError>&)> onFinished;
-
- private:
- void handleStreamInitiationRequestResponse(StreamInitiation::ref, ErrorPayload::ref);
- void handleBytestreamsRequestResponse(Bytestreams::ref, ErrorPayload::ref);
- void finish(boost::optional<FileTransferError> error);
- void handleIBBSessionFinished(boost::optional<FileTransferError> error);
+ virtual ~OutgoingFileTransfer();
- private:
- std::string id;
- JID from;
- JID to;
- std::string name;
- int size;
- std::string description;
- boost::shared_ptr<ReadBytestream> bytestream;
- IQRouter* iqRouter;
- SOCKS5BytestreamServer* socksServer;
- boost::shared_ptr<IBBSendSession> ibbSession;
+ virtual void start() = 0;
+ virtual void stop() = 0;
};
}
diff --git a/Swiften/FileTransfer/OutgoingSIFileTransfer.cpp b/Swiften/FileTransfer/OutgoingSIFileTransfer.cpp
new file mode 100644
index 0000000..2ed3a9d
--- /dev/null
+++ b/Swiften/FileTransfer/OutgoingSIFileTransfer.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include "Swiften/FileTransfer/OutgoingSIFileTransfer.h"
+
+#include <boost/bind.hpp>
+
+#include "Swiften/FileTransfer/StreamInitiationRequest.h"
+#include "Swiften/FileTransfer/BytestreamsRequest.h"
+#include "Swiften/FileTransfer/SOCKS5BytestreamServer.h"
+#include "Swiften/FileTransfer/IBBSendSession.h"
+
+namespace Swift {
+
+OutgoingSIFileTransfer::OutgoingSIFileTransfer(const std::string& id, const JID& from, const JID& to, const std::string& name, int size, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* iqRouter, SOCKS5BytestreamServer* socksServer) : id(id), from(from), to(to), name(name), size(size), description(description), bytestream(bytestream), iqRouter(iqRouter), socksServer(socksServer) {
+}
+
+void OutgoingSIFileTransfer::start() {
+ StreamInitiation::ref streamInitiation(new StreamInitiation());
+ streamInitiation->setID(id);
+ streamInitiation->setFileInfo(StreamInitiationFileInfo(name, description, size));
+ //streamInitiation->addProvidedMethod("http://jabber.org/protocol/bytestreams");
+ streamInitiation->addProvidedMethod("http://jabber.org/protocol/ibb");
+ StreamInitiationRequest::ref request = StreamInitiationRequest::create(to, streamInitiation, iqRouter);
+ request->onResponse.connect(boost::bind(&OutgoingSIFileTransfer::handleStreamInitiationRequestResponse, this, _1, _2));
+ request->send();
+}
+
+void OutgoingSIFileTransfer::stop() {
+}
+
+void OutgoingSIFileTransfer::handleStreamInitiationRequestResponse(StreamInitiation::ref response, ErrorPayload::ref error) {
+ if (error) {
+ finish(FileTransferError());
+ }
+ else {
+ if (response->getRequestedMethod() == "http://jabber.org/protocol/bytestreams") {
+ socksServer->addBytestream(id, from, to, bytestream);
+ Bytestreams::ref bytestreams(new Bytestreams());
+ bytestreams->setStreamID(id);
+ HostAddressPort addressPort = socksServer->getAddressPort();
+ bytestreams->addStreamHost(Bytestreams::StreamHost(addressPort.getAddress().toString(), from, addressPort.getPort()));
+ BytestreamsRequest::ref request = BytestreamsRequest::create(to, bytestreams, iqRouter);
+ request->onResponse.connect(boost::bind(&OutgoingSIFileTransfer::handleBytestreamsRequestResponse, this, _1, _2));
+ request->send();
+ }
+ else if (response->getRequestedMethod() == "http://jabber.org/protocol/ibb") {
+ ibbSession = boost::shared_ptr<IBBSendSession>(new IBBSendSession(id, to, bytestream, iqRouter));
+ ibbSession->onFinished.connect(boost::bind(&OutgoingSIFileTransfer::handleIBBSessionFinished, this, _1));
+ ibbSession->start();
+ }
+ }
+}
+
+void OutgoingSIFileTransfer::handleBytestreamsRequestResponse(Bytestreams::ref, ErrorPayload::ref error) {
+ if (error) {
+ finish(FileTransferError());
+ }
+ //socksServer->onTransferFinished.connect();
+}
+
+void OutgoingSIFileTransfer::finish(boost::optional<FileTransferError> error) {
+ if (ibbSession) {
+ ibbSession->onFinished.disconnect(boost::bind(&OutgoingSIFileTransfer::handleIBBSessionFinished, this, _1));
+ ibbSession.reset();
+ }
+ socksServer->removeBytestream(id, from, to);
+ onFinished(error);
+}
+
+void OutgoingSIFileTransfer::handleIBBSessionFinished(boost::optional<FileTransferError> error) {
+ finish(error);
+}
+
+}
diff --git a/Swiften/FileTransfer/OutgoingSIFileTransfer.h b/Swiften/FileTransfer/OutgoingSIFileTransfer.h
new file mode 100644
index 0000000..cdf988f
--- /dev/null
+++ b/Swiften/FileTransfer/OutgoingSIFileTransfer.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/FileTransfer/OutgoingFileTransfer.h>
+#include "Swiften/FileTransfer/ReadBytestream.h"
+#include "Swiften/Base/boost_bsignals.h"
+#include "Swiften/FileTransfer/FileTransferError.h"
+#include "Swiften/FileTransfer/SOCKS5BytestreamServer.h"
+#include "Swiften/JID/JID.h"
+#include "Swiften/Elements/StreamInitiation.h"
+#include "Swiften/Elements/Bytestreams.h"
+#include "Swiften/Elements/ErrorPayload.h"
+#include "Swiften/FileTransfer/IBBSendSession.h"
+
+namespace Swift {
+ class IQRouter;
+ class SOCKS5BytestreamServer;
+
+ class OutgoingSIFileTransfer : public OutgoingFileTransfer {
+ public:
+ OutgoingSIFileTransfer(const std::string& id, const JID& from, const JID& to, const std::string& name, int size, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* iqRouter, SOCKS5BytestreamServer* socksServer);
+
+ virtual void start();
+ virtual void stop();
+
+ boost::signal<void (const boost::optional<FileTransferError>&)> onFinished;
+
+ private:
+ void handleStreamInitiationRequestResponse(StreamInitiation::ref, ErrorPayload::ref);
+ void handleBytestreamsRequestResponse(Bytestreams::ref, ErrorPayload::ref);
+ void finish(boost::optional<FileTransferError> error);
+ void handleIBBSessionFinished(boost::optional<FileTransferError> error);
+
+ private:
+ std::string id;
+ JID from;
+ JID to;
+ std::string name;
+ int size;
+ std::string description;
+ boost::shared_ptr<ReadBytestream> bytestream;
+ IQRouter* iqRouter;
+ SOCKS5BytestreamServer* socksServer;
+ boost::shared_ptr<IBBSendSession> ibbSession;
+ };
+}
diff --git a/Swiften/FileTransfer/ReadBytestream.h b/Swiften/FileTransfer/ReadBytestream.h
index 4da2bc2..2601192 100644
--- a/Swiften/FileTransfer/ReadBytestream.h
+++ b/Swiften/FileTransfer/ReadBytestream.h
@@ -6,13 +6,14 @@
#pragma once
-#include "Swiften/Base/ByteArray.h"
+#include <vector>
+#include <cstring>
namespace Swift {
class ReadBytestream {
public:
virtual ~ReadBytestream();
- virtual ByteArray read(size_t size) = 0;
+ virtual std::vector<unsigned char> read(size_t size) = 0;
virtual bool isFinished() const = 0;
};
}
diff --git a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp
new file mode 100644
index 0000000..338f221
--- /dev/null
+++ b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h>
+
+namespace Swift {
+
+RemoteJingleTransportCandidateSelector::~RemoteJingleTransportCandidateSelector() {
+}
+
+}
diff --git a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h
new file mode 100644
index 0000000..b12b06b
--- /dev/null
+++ b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/boost_bsignals.h>
+
+#include <Swiften/Elements/JingleTransportPayload.h>
+#include <Swiften/FileTransfer/JingleTransport.h>
+
+namespace Swift {
+ class RemoteJingleTransportCandidateSelector {
+ public:
+ virtual ~RemoteJingleTransportCandidateSelector();
+
+ virtual void addRemoteTransportCandidates(JingleTransportPayload::ref) = 0;
+ virtual void selectCandidate() = 0;
+ virtual void setMinimumPriority(int) = 0;
+
+ virtual bool isActualCandidate(JingleTransportPayload::ref) = 0;
+ virtual int getPriority(JingleTransportPayload::ref) = 0;
+ virtual JingleTransport::ref selectTransport(JingleTransportPayload::ref) = 0;
+
+ boost::signal<void (JingleTransportPayload::ref)> onRemoteTransportCandidateSelectFinished;
+ };
+}
diff --git a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.cpp b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.cpp
new file mode 100644
index 0000000..36b7cba
--- /dev/null
+++ b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.cpp
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h>
+
+namespace Swift {
+
+RemoteJingleTransportCandidateSelectorFactory::~RemoteJingleTransportCandidateSelectorFactory() {
+}
+
+}
diff --git a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h
new file mode 100644
index 0000000..caa3097
--- /dev/null
+++ b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+namespace Swift {
+ class RemoteJingleTransportCandidateSelector;
+
+ class RemoteJingleTransportCandidateSelectorFactory {
+ public:
+ virtual ~RemoteJingleTransportCandidateSelectorFactory();
+
+ virtual RemoteJingleTransportCandidateSelector* createCandidateSelector() = 0;
+ };
+}
diff --git a/Swiften/FileTransfer/SConscript b/Swiften/FileTransfer/SConscript
index ea9e7bb..24fc9e8 100644
--- a/Swiften/FileTransfer/SConscript
+++ b/Swiften/FileTransfer/SConscript
@@ -1,10 +1,17 @@
-Import("swiften_env")
+Import("swiften_env", "env")
sources = [
"OutgoingFileTransfer.cpp",
+ "OutgoingSIFileTransfer.cpp",
"IncomingFileTransfer.cpp",
"IncomingJingleFileTransfer.cpp",
- "IncomingFileTransferManager.cpp",
+ "IncomingFileTransferManager.cpp",
+ "RemoteJingleTransportCandidateSelector.cpp",
+ "RemoteJingleTransportCandidateSelectorFactory.cpp",
+ "LocalJingleTransportCandidateGenerator.cpp",
+ "LocalJingleTransportCandidateGeneratorFactory.cpp",
+ "JingleTransport.cpp",
+ "JingleIncomingIBBTransport.cpp",
"ReadBytestream.cpp",
"WriteBytestream.cpp",
"FileReadBytestream.cpp",
@@ -17,3 +24,9 @@ sources = [
]
swiften_env.Append(SWIFTEN_OBJECTS = swiften_env.SwiftenObject(sources))
+
+env.Append(UNITTEST_SOURCES = [
+ File("UnitTest/SOCKS5BytestreamServerSessionTest.cpp"),
+ File("UnitTest/IBBSendSessionTest.cpp"),
+ File("UnitTest/IBBReceiveSessionTest.cpp"),
+ ])
diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp b/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp
index 9951f7a..268ba4c 100644
--- a/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp
+++ b/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp
@@ -7,6 +7,7 @@
#include "Swiften/FileTransfer/SOCKS5BytestreamServerSession.h"
#include <boost/bind.hpp>
+#include <iostream>
#include "Swiften/Base/ByteArray.h"
#include "Swiften/FileTransfer/SOCKS5BytestreamRegistry.h"
@@ -98,7 +99,7 @@ void SOCKS5BytestreamServerSession::sendData() {
try {
connection->write(bytestream->read(chunkSize));
}
- catch (const BytestreamException& e) {
+ catch (const BytestreamException&) {
finish(true);
}
}
diff --git a/Swiften/FileTransfer/UnitTest/IBBReceiveSessionTest.cpp b/Swiften/FileTransfer/UnitTest/IBBReceiveSessionTest.cpp
new file mode 100644
index 0000000..590443f
--- /dev/null
+++ b/Swiften/FileTransfer/UnitTest/IBBReceiveSessionTest.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <vector>
+#include <boost/bind.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Base/ByteArray.h>
+#include "Swiften/FileTransfer/IBBReceiveSession.h"
+#include "Swiften/Queries/IQRouter.h"
+#include "Swiften/Client/DummyStanzaChannel.h"
+
+using namespace Swift;
+
+class IBBReceiveSessionTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(IBBReceiveSessionTest);
+ CPPUNIT_TEST(testOpen);
+ CPPUNIT_TEST(testReceiveData);
+ CPPUNIT_TEST(testReceiveMultipleData);
+ CPPUNIT_TEST(testReceiveDataForOtherSession);
+ CPPUNIT_TEST(testReceiveDataOutOfOrder);
+ CPPUNIT_TEST(testReceiveLastData);
+ CPPUNIT_TEST(testReceiveClose);
+ CPPUNIT_TEST(testStopWhileActive);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void setUp() {
+ stanzaChannel = new DummyStanzaChannel();
+ iqRouter = new IQRouter(stanzaChannel);
+ finished = false;
+ }
+
+ void tearDown() {
+ delete iqRouter;
+ delete stanzaChannel;
+ }
+
+ void testOpen() {
+ std::auto_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession"));
+ testling->start();
+ stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open"));
+
+ CPPUNIT_ASSERT(stanzaChannel->isResultAtIndex(0, "id-open"));
+ CPPUNIT_ASSERT(!finished);
+
+ testling->stop();
+ }
+
+ void testReceiveData() {
+ std::auto_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession"));
+ testling->start();
+ stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open"));
+
+ stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, ByteArray::create("abc")), "foo@bar.com/baz", "id-a"));
+
+ CPPUNIT_ASSERT(stanzaChannel->isResultAtIndex(1, "id-a"));
+ CPPUNIT_ASSERT(ByteArray::create("abc") == receivedData);
+ CPPUNIT_ASSERT(!finished);
+
+ testling->stop();
+ }
+
+ void testReceiveMultipleData() {
+ std::auto_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession"));
+ testling->start();
+ stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open"));
+
+ stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, ByteArray::create("abc")), "foo@bar.com/baz", "id-a"));
+ stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 1, ByteArray::create("def")), "foo@bar.com/baz", "id-b"));
+
+ CPPUNIT_ASSERT(stanzaChannel->isResultAtIndex(2, "id-b"));
+ CPPUNIT_ASSERT(ByteArray::create("abcdef") == receivedData);
+ CPPUNIT_ASSERT(!finished);
+
+ testling->stop();
+ }
+
+ void testReceiveDataForOtherSession() {
+ std::auto_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession"));
+ testling->start();
+ stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open"));
+
+ stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("othersession", 0, ByteArray::create("abc")), "foo@bar.com/baz", "id-a"));
+
+ CPPUNIT_ASSERT(stanzaChannel->isErrorAtIndex(1, "id-a"));
+
+ testling->stop();
+ }
+
+ void testReceiveDataOutOfOrder() {
+ std::auto_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession"));
+ testling->start();
+ stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open"));
+
+ stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, ByteArray::create("abc")), "foo@bar.com/baz", "id-a"));
+ stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, ByteArray::create("def")), "foo@bar.com/baz", "id-b"));
+
+ CPPUNIT_ASSERT(stanzaChannel->isErrorAtIndex(2, "id-b"));
+ CPPUNIT_ASSERT(finished);
+ CPPUNIT_ASSERT(error);
+
+ testling->stop();
+ }
+
+ void testReceiveLastData() {
+ std::auto_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession", 6));
+ testling->start();
+ stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open"));
+
+ stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, ByteArray::create("abc")), "foo@bar.com/baz", "id-a"));
+ stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 1, ByteArray::create("def")), "foo@bar.com/baz", "id-b"));
+
+ CPPUNIT_ASSERT(stanzaChannel->isResultAtIndex(2, "id-b"));
+ CPPUNIT_ASSERT(ByteArray::create("abcdef") == receivedData);
+ CPPUNIT_ASSERT(finished);
+ CPPUNIT_ASSERT(!error);
+
+ testling->stop();
+ }
+
+ void testReceiveClose() {
+ std::auto_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession"));
+ testling->start();
+ stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open"));
+
+ stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBClose("mysession"), "foo@bar.com/baz", "id-close"));
+
+ CPPUNIT_ASSERT(finished);
+ CPPUNIT_ASSERT(error);
+
+ testling->stop();
+ }
+
+ void testStopWhileActive() {
+ std::auto_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession"));
+ testling->start();
+ stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open"));
+
+ testling->stop();
+
+ CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<IBB>(1, JID("foo@bar.com/baz"), IQ::Set));
+ IBB::ref ibb = stanzaChannel->sentStanzas[1]->getPayload<IBB>();
+ CPPUNIT_ASSERT_EQUAL(IBB::Close, ibb->getAction());
+ CPPUNIT_ASSERT_EQUAL(std::string("mysession"), ibb->getStreamID());
+ CPPUNIT_ASSERT(finished);
+ CPPUNIT_ASSERT(!error);
+ }
+
+ private:
+ IQ::ref createIBBRequest(IBB::ref ibb, const JID& from, const std::string& id) {
+ IQ::ref request = IQ::createRequest(IQ::Set, JID("baz@fum.com/dum"), id, ibb);
+ request->setFrom(from);
+ return request;
+ }
+
+ IBBReceiveSession* createSession(const std::string& from, const std::string& id, size_t size = 0x1000) {
+ IBBReceiveSession* session = new IBBReceiveSession(id, JID(from), size, iqRouter);
+ session->onDataReceived.connect(boost::bind(&IBBReceiveSessionTest::handleDataReceived, this, _1));
+ session->onFinished.connect(boost::bind(&IBBReceiveSessionTest::handleFinished, this, _1));
+ return session;
+ }
+
+
+ void handleFinished(boost::optional<FileTransferError> error) {
+ finished = true;
+ this->error = error;
+ }
+
+ void handleDataReceived(const std::vector<unsigned char>& data) {
+ receivedData.insert(receivedData.end(), data.begin(), data.end());
+ }
+
+ private:
+ DummyStanzaChannel* stanzaChannel;
+ IQRouter* iqRouter;
+ bool finished;
+ boost::optional<FileTransferError> error;
+ std::vector<unsigned char> receivedData;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(IBBReceiveSessionTest);
diff --git a/Swiften/FileTransfer/UnitTest/IBBSendSessionTest.cpp b/Swiften/FileTransfer/UnitTest/IBBSendSessionTest.cpp
index 0cd273a..32df34b 100644
--- a/Swiften/FileTransfer/UnitTest/IBBSendSessionTest.cpp
+++ b/Swiften/FileTransfer/UnitTest/IBBSendSessionTest.cpp
@@ -4,13 +4,12 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
-#include "Swiften/Base/ByteArray.h"
-
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <vector>
#include <boost/bind.hpp>
+#include "Swiften/Base/ByteArray.h"
#include "Swiften/FileTransfer/IBBSendSession.h"
#include "Swiften/FileTransfer/ByteArrayReadBytestream.h"
#include "Swiften/Queries/IQRouter.h"
@@ -33,7 +32,7 @@ class IBBSendSessionTest : public CppUnit::TestFixture {
void setUp() {
stanzaChannel = new DummyStanzaChannel();
iqRouter = new IQRouter(stanzaChannel);
- bytestream = boost::shared_ptr<ByteArrayReadBytestream>(new ByteArrayReadBytestream(ByteArray("abcdefg")));
+ bytestream = boost::shared_ptr<ByteArrayReadBytestream>(new ByteArrayReadBytestream(ByteArray::create("abcdefg")));
}
void tearDown() {
@@ -66,7 +65,7 @@ class IBBSendSessionTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<IBB>(1, JID("foo@bar.com/baz"), IQ::Set));
IBB::ref ibb = stanzaChannel->sentStanzas[1]->getPayload<IBB>();
CPPUNIT_ASSERT_EQUAL(IBB::Data, ibb->getAction());
- CPPUNIT_ASSERT_EQUAL(ByteArray("abc"), ibb->getData());
+ CPPUNIT_ASSERT(ByteArray::create("abc") == ibb->getData());
CPPUNIT_ASSERT_EQUAL(0, ibb->getSequenceNumber());
CPPUNIT_ASSERT_EQUAL(std::string("myid"), ibb->getStreamID());
}
@@ -82,7 +81,7 @@ class IBBSendSessionTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<IBB>(2, JID("foo@bar.com/baz"), IQ::Set));
IBB::ref ibb = stanzaChannel->sentStanzas[2]->getPayload<IBB>();
CPPUNIT_ASSERT_EQUAL(IBB::Data, ibb->getAction());
- CPPUNIT_ASSERT_EQUAL(ByteArray("def"), ibb->getData());
+ CPPUNIT_ASSERT(ByteArray::create("def") == ibb->getData());
CPPUNIT_ASSERT_EQUAL(1, ibb->getSequenceNumber());
CPPUNIT_ASSERT_EQUAL(std::string("myid"), ibb->getStreamID());
}
diff --git a/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp b/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp
index c6d246d..1c1a246 100644
--- a/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp
+++ b/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp
@@ -35,7 +35,7 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture {
eventLoop = new DummyEventLoop();
connection = boost::shared_ptr<DummyConnection>(new DummyConnection(eventLoop));
connection->onDataSent.connect(boost::bind(&SOCKS5BytestreamServerSessionTest::handleDataWritten, this, _1));
- stream1 = boost::shared_ptr<ByteArrayReadBytestream>(new ByteArrayReadBytestream(ByteArray("abcdefg")));
+ stream1 = boost::shared_ptr<ByteArrayReadBytestream>(new ByteArrayReadBytestream(ByteArray::create("abcdefg")));
}
void tearDown() {
@@ -47,20 +47,20 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture {
std::auto_ptr<SOCKS5BytestreamServerSession> testling(createSession());
StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get());
- receive(ByteArray("\x05\x02\x01\x02"));
+ receive(ByteArray::create("\x05\x02\x01\x02"));
- CPPUNIT_ASSERT_EQUAL(ByteArray("\x05\x00", 2), receivedData);
+ CPPUNIT_ASSERT(ByteArray::create("\x05\x00", 2) == receivedData);
}
void testAuthenticate_Chunked() {
std::auto_ptr<SOCKS5BytestreamServerSession> testling(createSession());
StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get());
- receive(ByteArray("\x05\x02\x01"));
+ receive(ByteArray::create("\x05\x02\x01"));
- CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(receivedData.getSize()));
- receive(ByteArray("\x01"));
- CPPUNIT_ASSERT_EQUAL(ByteArray("\x05\x00", 2), receivedData);
+ CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(receivedData.size()));
+ receive(ByteArray::create("\x01"));
+ CPPUNIT_ASSERT(ByteArray::create("\x05\x00", 2) == receivedData);
}
void testRequest() {
@@ -70,8 +70,8 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture {
authenticate();
ByteArray hostname("abcdef");
- receive(ByteArray("\x05\x01\x00\x03", 4) + hostname.getSize() + hostname + ByteArray("\x00\x00", 2));
- CPPUNIT_ASSERT_EQUAL(ByteArray("\x05\x00\x00\x03\x06\x61\x62\x63\x64\x65\x66\x00\x00", 13), ByteArray(receivedData.getData(), 13));
+ receive(ByteArray(ByteArray::create("\x05\x01\x00\x03", 4)) + hostname.getSize() + hostname + ByteArray::create("\x00\x00", 2));
+ CPPUNIT_ASSERT(ByteArray::create("\x05\x00\x00\x03\x06\x61\x62\x63\x64\x65\x66\x00\x00", 13) == ByteArray::create(&receivedData[0], 13));
}
void testRequest_UnknownBytestream() {
@@ -80,8 +80,8 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture {
authenticate();
ByteArray hostname("abcdef");
- receive(ByteArray("\x05\x01\x00\x03", 4) + hostname.getSize() + hostname + ByteArray("\x00\x00", 2));
- CPPUNIT_ASSERT_EQUAL(ByteArray("\x05\x04\x00\x03\x06\x61\x62\x63\x64\x65\x66\x00\x00", 13), receivedData);
+ receive(ByteArray(ByteArray::create("\x05\x01\x00\x03", 4)) + hostname.getSize() + hostname + ByteArray::create("\x00\x00", 2));
+ CPPUNIT_ASSERT(ByteArray::create("\x05\x04\x00\x03\x06\x61\x62\x63\x64\x65\x66\x00\x00", 13) == receivedData);
}
void testReceiveData() {
@@ -93,7 +93,7 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture {
eventLoop->processEvents();
skipHeader("abcdef");
- CPPUNIT_ASSERT_EQUAL(ByteArray("abcdefg"), receivedData);
+ CPPUNIT_ASSERT(ByteArray::create("abcdefg") == receivedData);
CPPUNIT_ASSERT_EQUAL(2, receivedDataChunks);
}
@@ -107,7 +107,7 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture {
eventLoop->processEvents();
skipHeader("abcdef");
- CPPUNIT_ASSERT_EQUAL(ByteArray("abcdefg"), receivedData);
+ CPPUNIT_ASSERT(ByteArray::create("abcdefg") == receivedData);
CPPUNIT_ASSERT_EQUAL(4, receivedDataChunks);
}
@@ -118,23 +118,23 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture {
}
void authenticate() {
- receive(ByteArray("\x05\x02\x01\x02"));
+ receive(ByteArray::create("\x05\x02\x01\x02"));
receivedData.clear();
receivedDataChunks = 0;
}
void request(const std::string& hostname) {
- receive(ByteArray("\x05\x01\x00\x03", 4) + hostname.size() + hostname + ByteArray("\x00\x00", 2));
+ receive(ByteArray(ByteArray::create("\x05\x01\x00\x03", 4)) + hostname.size() + hostname + ByteArray::create("\x00\x00", 2));
}
void skipHeader(const std::string& hostname) {
int headerSize = 7 + hostname.size();
- receivedData = ByteArray(receivedData.getData() + headerSize, receivedData.getSize() - headerSize);
+ receivedData = ByteArray::create(&receivedData[headerSize], receivedData.size() - headerSize);
}
void handleDataWritten(const ByteArray& data) {
- receivedData += data;
+ receivedData.insert(receivedData.end(), data.begin(), data.end());
receivedDataChunks++;
}
@@ -148,7 +148,7 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture {
DummyEventLoop* eventLoop;
SOCKS5BytestreamRegistry bytestreams;
boost::shared_ptr<DummyConnection> connection;
- ByteArray receivedData;
+ std::vector<unsigned char> receivedData;
int receivedDataChunks;
boost::shared_ptr<ByteArrayReadBytestream> stream1;
};
diff --git a/Swiften/FileTransfer/WriteBytestream.h b/Swiften/FileTransfer/WriteBytestream.h
index 1dc791c..c27aeff 100644
--- a/Swiften/FileTransfer/WriteBytestream.h
+++ b/Swiften/FileTransfer/WriteBytestream.h
@@ -7,8 +7,7 @@
#pragma once
#include <boost/shared_ptr.hpp>
-
-#include "Swiften/Base/ByteArray.h"
+#include <vector>
namespace Swift {
class WriteBytestream {
@@ -17,6 +16,6 @@ namespace Swift {
virtual ~WriteBytestream();
- virtual void write(const ByteArray&) = 0;
+ virtual void write(const std::vector<unsigned char>&) = 0;
};
}
diff --git a/Swiften/JID/JID.cpp b/Swiften/JID/JID.cpp
index e4611b3..00adf34 100644
--- a/Swiften/JID/JID.cpp
+++ b/Swiften/JID/JID.cpp
@@ -7,12 +7,17 @@
#define SWIFTEN_CACHE_JID_PREP
#include <vector>
+#include <list>
#include <iostream>
#include <string>
#ifdef SWIFTEN_CACHE_JID_PREP
#include <boost/unordered_map.hpp>
#endif
+#include <boost/assign/list_of.hpp>
+#include <boost/algorithm/string/find_format.hpp>
+#include <boost/algorithm/string/finder.hpp>
+#include <sstream>
#include <stringprep.h>
#include <Swiften/Base/String.h>
@@ -27,6 +32,75 @@ static PrepCache domainPrepCache;
static PrepCache resourcePrepCache;
#endif
+static const std::list<char> escapedChars = boost::assign::list_of(' ')('"')('&')('\'')('/')('<')('>')('@')(':');
+
+bool getEscapeSequenceValue(const std::string& sequence, unsigned char& value) {
+ std::stringstream s;
+ unsigned int v;
+ s << std::hex << sequence;
+ s >> v;
+ value = static_cast<unsigned char>(v);
+ return (!s.fail() && !s.bad() && (value == 0x5C || std::find(escapedChars.begin(), escapedChars.end(), value) != escapedChars.end()));
+}
+
+struct UnescapedCharacterFinder {
+ template<typename Iterator> boost::iterator_range<Iterator> operator()(Iterator begin, Iterator end) {
+ for (; begin != end; ++begin) {
+ if (std::find(escapedChars.begin(), escapedChars.end(), *begin) != escapedChars.end()) {
+ return boost::iterator_range<Iterator>(begin, begin + 1);
+ }
+ else if (*begin == '\\') {
+ // Check if we have an escaped dissalowed character sequence
+ Iterator innerBegin = begin + 1;
+ if (innerBegin != end && innerBegin + 1 != end) {
+ Iterator innerEnd = innerBegin + 2;
+ unsigned char value;
+ if (getEscapeSequenceValue(std::string(innerBegin, innerEnd), value)) {
+ return boost::iterator_range<Iterator>(begin, begin + 1);
+ }
+ }
+ }
+ }
+ return boost::iterator_range<Iterator>(end, end);
+ }
+};
+
+struct UnescapedCharacterFormatter {
+ template<typename FindResult> std::string operator()(const FindResult& match) const {
+ std::ostringstream s;
+ s << '\\' << std::hex << static_cast<int>(*match.begin());
+ return s.str();
+ }
+};
+
+struct EscapedCharacterFinder {
+ template<typename Iterator> boost::iterator_range<Iterator> operator()(Iterator begin, Iterator end) {
+ for (; begin != end; ++begin) {
+ if (*begin == '\\') {
+ Iterator innerEnd = begin + 1;
+ for (size_t i = 0; i < 2 && innerEnd != end; ++i, ++innerEnd) {
+ }
+ unsigned char value;
+ if (getEscapeSequenceValue(std::string(begin + 1, innerEnd), value)) {
+ return boost::iterator_range<Iterator>(begin, innerEnd);
+ }
+ }
+ }
+ return boost::iterator_range<Iterator>(end, end);
+ }
+};
+
+struct EscapedCharacterFormatter {
+ template<typename FindResult> std::string operator()(const FindResult& match) const {
+ unsigned char value;
+ if (getEscapeSequenceValue(std::string(match.begin() + 1, match.end()), value)) {
+ return std::string(reinterpret_cast<const char*>(&value), 1);
+ }
+ return boost::copy_range<std::string>(match);
+ }
+};
+
+
namespace Swift {
JID::JID(const char* jid) {
@@ -126,5 +200,13 @@ int JID::compare(const Swift::JID& o, CompareType compareType) const {
return 0;
}
+std::string JID::getEscapedNode(const std::string& node) {
+ return boost::find_format_all_copy(node, UnescapedCharacterFinder(), UnescapedCharacterFormatter());
+}
+
+std::string JID::getUnescapedNode() const {
+ return boost::find_format_all_copy(node_, EscapedCharacterFinder(), EscapedCharacterFormatter());
+}
+
} // namespace Swift
diff --git a/Swiften/JID/JID.h b/Swiften/JID/JID.h
index 63e063d..98b42da 100644
--- a/Swiften/JID/JID.h
+++ b/Swiften/JID/JID.h
@@ -7,7 +7,7 @@
#pragma once
#include <string>
-#include <ostream>
+#include <iosfwd>
namespace Swift {
class JID {
@@ -38,6 +38,18 @@ namespace Swift {
return !hasResource_;
}
+ /**
+ * Returns the given node, escaped according to XEP-0106.
+ * The resulting node is a valid node for a JID, whereas the input value can contain characters
+ * that are not allowed.
+ */
+ static std::string getEscapedNode(const std::string& node);
+
+ /**
+ * Returns the node of the current JID, unescaped according to XEP-0106.
+ */
+ std::string getUnescapedNode() const;
+
JID toBare() const {
JID result(*this);
result.hasResource_ = false;
diff --git a/Swiften/JID/UnitTest/JIDTest.cpp b/Swiften/JID/UnitTest/JIDTest.cpp
index 0f22e15..5e79db2 100644
--- a/Swiften/JID/UnitTest/JIDTest.cpp
+++ b/Swiften/JID/UnitTest/JIDTest.cpp
@@ -51,6 +51,10 @@ class JIDTest : public CppUnit::TestFixture
CPPUNIT_TEST(testSmallerThan_Larger);
CPPUNIT_TEST(testHasResource);
CPPUNIT_TEST(testHasResource_NoResource);
+ CPPUNIT_TEST(testGetEscapedNode);
+ CPPUNIT_TEST(testGetEscapedNode_XEP106Examples);
+ CPPUNIT_TEST(testGetUnescapedNode);
+ CPPUNIT_TEST(testGetUnescapedNode_XEP106Examples);
CPPUNIT_TEST_SUITE_END();
public:
@@ -311,6 +315,57 @@ class JIDTest : public CppUnit::TestFixture
CPPUNIT_ASSERT(testling.isBare());
}
+
+ void testGetEscapedNode() {
+ std::string escaped = JID::getEscapedNode("alice@wonderland.lit");
+ CPPUNIT_ASSERT_EQUAL(std::string("alice\\40wonderland.lit"), escaped);
+
+ escaped = JID::getEscapedNode("\\& \" ' / <\\\\> @ :\\3a\\40");
+ CPPUNIT_ASSERT_EQUAL(std::string("\\\\26\\20\\22\\20\\27\\20\\2f\\20\\3c\\\\\\3e\\20\\40\\20\\3a\\5c3a\\5c40"), escaped);
+ }
+
+ void testGetEscapedNode_XEP106Examples() {
+ CPPUNIT_ASSERT_EQUAL(std::string("\\2plus\\2is\\4"), JID::getEscapedNode("\\2plus\\2is\\4"));
+ CPPUNIT_ASSERT_EQUAL(std::string("foo\\bar"), JID::getEscapedNode("foo\\bar"));
+ CPPUNIT_ASSERT_EQUAL(std::string("foob\\41r"), JID::getEscapedNode("foob\\41r"));
+ CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("space cadet"), std::string("space\\20cadet"));
+ CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("call me \"ishmael\""), std::string("call\\20me\\20\\22ishmael\\22"));
+ CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("at&t guy"), std::string("at\\26t\\20guy"));
+ CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("d'artagnan"), std::string("d\\27artagnan"));
+ CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("/.fanboy"), std::string("\\2f.fanboy"));
+ CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("::foo::"), std::string("\\3a\\3afoo\\3a\\3a"));
+ CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("<foo>"), std::string("\\3cfoo\\3e"));
+ CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("user@host"), std::string("user\\40host"));
+ CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("c:\\net"), std::string("c\\3a\\net"));
+ CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("c:\\\\net"), std::string("c\\3a\\\\net"));
+ CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("c:\\cool stuff"), std::string("c\\3a\\cool\\20stuff"));
+ CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("c:\\5commas"), std::string("c\\3a\\5c5commas"));
+ }
+
+ void testGetUnescapedNode() {
+ std::string input = "\\& \" ' / <\\\\> @ : \\5c\\40";
+ JID testling(JID::getEscapedNode(input) + "@y");
+ CPPUNIT_ASSERT(testling.isValid());
+ CPPUNIT_ASSERT_EQUAL(input, testling.getUnescapedNode());
+ }
+
+ void testGetUnescapedNode_XEP106Examples() {
+ CPPUNIT_ASSERT_EQUAL(std::string("\\2plus\\2is\\4"), JID("\\2plus\\2is\\4@example.com").getUnescapedNode());
+ CPPUNIT_ASSERT_EQUAL(std::string("foo\\bar"), JID("foo\\bar@example.com").getUnescapedNode());
+ CPPUNIT_ASSERT_EQUAL(std::string("foob\\41r"), JID("foob\\41r@example.com").getUnescapedNode());
+ CPPUNIT_ASSERT_EQUAL(std::string("space cadet"), JID("space\\20cadet@example.com").getUnescapedNode());
+ CPPUNIT_ASSERT_EQUAL(std::string("call me \"ishmael\""), JID("call\\20me\\20\\22ishmael\\22@example.com").getUnescapedNode());
+ CPPUNIT_ASSERT_EQUAL(std::string("at&t guy"), JID("at\\26t\\20guy@example.com").getUnescapedNode());
+ CPPUNIT_ASSERT_EQUAL(std::string("d'artagnan"), JID("d\\27artagnan@example.com").getUnescapedNode());
+ CPPUNIT_ASSERT_EQUAL(std::string("/.fanboy"), JID("\\2f.fanboy@example.com").getUnescapedNode());
+ CPPUNIT_ASSERT_EQUAL(std::string("::foo::"), JID("\\3a\\3afoo\\3a\\3a@example.com").getUnescapedNode());
+ CPPUNIT_ASSERT_EQUAL(std::string("<foo>"), JID("\\3cfoo\\3e@example.com").getUnescapedNode());
+ CPPUNIT_ASSERT_EQUAL(std::string("user@host"), JID("user\\40host@example.com").getUnescapedNode());
+ CPPUNIT_ASSERT_EQUAL(std::string("c:\\net"), JID("c\\3a\\net@example.com").getUnescapedNode());
+ CPPUNIT_ASSERT_EQUAL(std::string("c:\\\\net"), JID("c\\3a\\\\net@example.com").getUnescapedNode());
+ CPPUNIT_ASSERT_EQUAL(std::string("c:\\cool stuff"), JID("c\\3a\\cool\\20stuff@example.com").getUnescapedNode());
+ CPPUNIT_ASSERT_EQUAL(std::string("c:\\5commas"), JID("c\\3a\\5c5commas@example.com").getUnescapedNode());
+ }
};
CPPUNIT_TEST_SUITE_REGISTRATION(JIDTest);
diff --git a/Swiften/Jingle/IncomingJingleSession.cpp b/Swiften/Jingle/IncomingJingleSession.cpp
deleted file mode 100644
index b18d9d3..0000000
--- a/Swiften/Jingle/IncomingJingleSession.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copyright (c) 2010 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-#include <Swiften/Jingle/IncomingJingleSession.h>
-
-namespace Swift {
-
-IncomingJingleSession::IncomingJingleSession(const std::string& id, const std::vector<JingleContent::ref>& contents) : JingleSession(id, contents) {
-
-}
-
-}
diff --git a/Swiften/Jingle/IncomingJingleSession.h b/Swiften/Jingle/IncomingJingleSession.h
deleted file mode 100644
index 64816f6..0000000
--- a/Swiften/Jingle/IncomingJingleSession.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (c) 2011 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-#pragma once
-
-#include <boost/shared_ptr.hpp>
-
-#include <Swiften/Jingle/JingleSession.h>
-
-namespace Swift {
- class IncomingJingleSession : public JingleSession {
- public:
- IncomingJingleSession(const std::string& id, const std::vector<JingleContent::ref>& contents);
-
- typedef boost::shared_ptr<IncomingJingleSession> ref;
- };
-}
diff --git a/Swiften/Jingle/IncomingJingleSessionHandler.h b/Swiften/Jingle/IncomingJingleSessionHandler.h
index 5bf9237..4d22a4e 100644
--- a/Swiften/Jingle/IncomingJingleSessionHandler.h
+++ b/Swiften/Jingle/IncomingJingleSessionHandler.h
@@ -6,13 +6,13 @@
#pragma once
-#include <Swiften/Jingle/IncomingJingleSession.h>
+#include <Swiften/Jingle/JingleSession.h>
namespace Swift {
class IncomingJingleSessionHandler {
public:
virtual ~IncomingJingleSessionHandler();
- virtual bool handleIncomingJingleSession(IncomingJingleSession::ref) = 0;
+ virtual bool handleIncomingJingleSession(JingleSession::ref, const std::vector<JingleContentPayload::ref>& contents) = 0;
};
}
diff --git a/Swiften/Jingle/Jingle.h b/Swiften/Jingle/Jingle.h
new file mode 100644
index 0000000..ba4dfe3
--- /dev/null
+++ b/Swiften/Jingle/Jingle.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include <Swiften/Elements/JingleContentPayload.h>
+
+namespace Swift {
+ namespace Jingle {
+ template<typename T>
+ JingleContentPayload::ref getContentWithDescription(const std::vector<JingleContentPayload::ref>& contents) {
+ for (size_t i = 0; i < contents.size(); ++i) {
+ if (contents[i]->getDescription<T>()) {
+ return contents[i];
+ }
+ }
+ return JingleContentPayload::ref();
+ }
+ }
+}
diff --git a/Swiften/Jingle/JingleContentID.h b/Swiften/Jingle/JingleContentID.h
new file mode 100644
index 0000000..8d75581
--- /dev/null
+++ b/Swiften/Jingle/JingleContentID.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <Swiften/Elements/JingleContentPayload.h>
+
+namespace Swift {
+ class JingleContentID {
+ public:
+ JingleContentID(const std::string& name, JingleContentPayload::Creator creator) : name(name), creator(creator) {
+ }
+
+ private:
+ std::string name;
+ JingleContentPayload::Creator creator;
+ };
+}
diff --git a/Swiften/Jingle/JingleResponder.cpp b/Swiften/Jingle/JingleResponder.cpp
index 2397e63..198f9a2 100644
--- a/Swiften/Jingle/JingleResponder.cpp
+++ b/Swiften/Jingle/JingleResponder.cpp
@@ -9,7 +9,7 @@
#include <boost/smart_ptr/make_shared.hpp>
#include <Swiften/Jingle/JingleSessionManager.h>
-#include <Swiften/Jingle/IncomingJingleSession.h>
+#include <Swiften/Jingle/JingleSessionImpl.h>
namespace Swift {
@@ -24,12 +24,12 @@ bool JingleResponder::handleSetRequest(const JID& from, const JID&, const std::s
}
else {
sendResponse(from, id, boost::shared_ptr<JinglePayload>());
- IncomingJingleSession::ref session = boost::make_shared<IncomingJingleSession>(id, payload->getContents());
- sessionManager->handleIncomingSession(from, session);
+ JingleSessionImpl::ref session = boost::make_shared<JingleSessionImpl>(payload->getInitiator(), payload->getSessionID());
+ sessionManager->handleIncomingSession(from, session, payload->getContents());
}
}
else {
- JingleSession::ref session = sessionManager->getSession(from, payload->getSessionID());
+ JingleSessionImpl::ref session = sessionManager->getSession(from, payload->getSessionID());
if (session) {
session->handleIncomingAction(payload);
sendResponse(from, id, boost::shared_ptr<JinglePayload>());
diff --git a/Swiften/Jingle/JingleSession.cpp b/Swiften/Jingle/JingleSession.cpp
index d255abd..1366191 100644
--- a/Swiften/Jingle/JingleSession.cpp
+++ b/Swiften/Jingle/JingleSession.cpp
@@ -10,21 +10,11 @@
namespace Swift {
-JingleSession::JingleSession(const std::string& id, const std::vector<JingleContent::ref>& contents) : id(id), contents(contents) {
+JingleSession::JingleSession(const JID& initiator, const std::string& id) : initiator(initiator), id(id) {
}
JingleSession::~JingleSession() {
}
-void JingleSession::handleIncomingAction(JinglePayload::ref) {
-}
-
-void JingleSession::terminate(JinglePayload::Reason::Type reason) {
- JinglePayload::ref payload = boost::make_shared<JinglePayload>(JinglePayload::SessionTerminate, id);
- payload->setReason(JinglePayload::Reason(reason));
- //onAction(payload)
-}
-
-
}
diff --git a/Swiften/Jingle/JingleSession.h b/Swiften/Jingle/JingleSession.h
index c00492d..fa7da7e 100644
--- a/Swiften/Jingle/JingleSession.h
+++ b/Swiften/Jingle/JingleSession.h
@@ -7,47 +7,43 @@
#pragma once
#include <boost/shared_ptr.hpp>
+#include <string>
#include <Swiften/Base/boost_bsignals.h>
-#include <string>
+#include <Swiften/JID/JID.h>
#include <Swiften/Elements/JinglePayload.h>
-#include <Swiften/Elements/JingleContent.h>
-#include <Swiften/Base/foreach.h>
namespace Swift {
+ class JingleContentID;
+
class JingleSession {
- friend class JingleResponder;
public:
typedef boost::shared_ptr<JingleSession> ref;
- JingleSession(const std::string& id, const std::vector<JingleContent::ref>& contents);
+ JingleSession(const JID& initiator, const std::string& id);
virtual ~JingleSession();
- std::string getID() const {
- return id;
+ const JID& getInitiator() const {
+ return initiator;
}
- template<typename T>
- JingleContent::ref getContentWithDescription() const {
- foreach (JingleContent::ref content, contents) {
- if (content->getDescription<T>()) {
- return content;
- }
- }
- return JingleContent::ref();
- }
-
- const std::vector<JingleContent::ref> getContents() const {
- return contents;
+ std::string getID() const {
+ return id;
}
- void terminate(JinglePayload::Reason::Type reason);
+ virtual void terminate(JinglePayload::Reason::Type reason) = 0;
+ virtual void accept(JingleTransportPayload::ref = JingleTransportPayload::ref()) = 0;
+ virtual void sendTransportInfo(const JingleContentID&, JingleTransportPayload::ref) = 0;
+ virtual void acceptTransport(const JingleContentID&, JingleTransportPayload::ref) = 0;
+ virtual void rejectTransport(const JingleContentID&, JingleTransportPayload::ref) = 0;
- private:
- void handleIncomingAction(JinglePayload::ref);
+ public:
+ boost::signal<void ()> onSessionTerminateReceived;
+ boost::signal<void (const JingleContentID&, JingleTransportPayload::ref)> onTransportInfoReceived;
+ boost::signal<void (const JingleContentID&, JingleTransportPayload::ref)> onTransportReplaceReceived;
private:
+ JID initiator;
std::string id;
- std::vector<JingleContent::ref> contents;
};
}
diff --git a/Swiften/Jingle/JingleSessionImpl.cpp b/Swiften/Jingle/JingleSessionImpl.cpp
new file mode 100644
index 0000000..cbb2b42
--- /dev/null
+++ b/Swiften/Jingle/JingleSessionImpl.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Jingle/JingleSessionImpl.h>
+
+#include <boost/smart_ptr/make_shared.hpp>
+
+namespace Swift {
+
+JingleSessionImpl::JingleSessionImpl(const JID& initiator, const std::string& id) : JingleSession(initiator, id) {
+}
+
+void JingleSessionImpl::handleIncomingAction(JinglePayload::ref) {
+}
+
+void JingleSessionImpl::terminate(JinglePayload::Reason::Type reason) {
+ JinglePayload::ref payload = boost::make_shared<JinglePayload>(JinglePayload::SessionTerminate, getID());
+ payload->setReason(JinglePayload::Reason(reason));
+ //onAction(payload)
+}
+
+void JingleSessionImpl::acceptTransport(const JingleContentID&, JingleTransportPayload::ref) {
+
+}
+
+void JingleSessionImpl::rejectTransport(const JingleContentID&, JingleTransportPayload::ref) {
+
+}
+
+void JingleSessionImpl::accept(JingleTransportPayload::ref) {
+}
+
+void JingleSessionImpl::sendTransportInfo(const JingleContentID&, JingleTransportPayload::ref) {
+
+}
+
+
+
+}
diff --git a/Swiften/Jingle/JingleSessionImpl.h b/Swiften/Jingle/JingleSessionImpl.h
new file mode 100644
index 0000000..a254ead
--- /dev/null
+++ b/Swiften/Jingle/JingleSessionImpl.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Jingle/JingleSession.h>
+
+namespace Swift {
+ class JingleSessionImpl : public JingleSession {
+ friend class JingleResponder;
+ public:
+ typedef boost::shared_ptr<JingleSessionImpl> ref;
+
+ JingleSessionImpl(const JID& initiator, const std::string& id);
+
+ virtual void terminate(JinglePayload::Reason::Type reason);
+ virtual void accept(JingleTransportPayload::ref);
+ virtual void sendTransportInfo(const JingleContentID&, JingleTransportPayload::ref);
+ virtual void acceptTransport(const JingleContentID&, JingleTransportPayload::ref);
+ virtual void rejectTransport(const JingleContentID&, JingleTransportPayload::ref);
+
+ private:
+ void handleIncomingAction(JinglePayload::ref);
+ };
+}
diff --git a/Swiften/Jingle/JingleSessionManager.cpp b/Swiften/Jingle/JingleSessionManager.cpp
index e60449b..58e90c8 100644
--- a/Swiften/Jingle/JingleSessionManager.cpp
+++ b/Swiften/Jingle/JingleSessionManager.cpp
@@ -7,6 +7,7 @@
#include <Swiften/Jingle/JingleSessionManager.h>
#include <Swiften/Jingle/JingleResponder.h>
#include <Swiften/Jingle/IncomingJingleSessionHandler.h>
+#include <Swiften/Base/foreach.h>
namespace Swift {
@@ -18,9 +19,9 @@ JingleSessionManager::~JingleSessionManager() {
delete responder;
}
-JingleSession::ref JingleSessionManager::getSession(const JID& jid, const std::string& id) const {
+JingleSessionImpl::ref JingleSessionManager::getSession(const JID& jid, const std::string& id) const {
SessionMap::const_iterator i = incomingSessions.find(JIDSession(jid, id));
- return i != incomingSessions.end() ? i->second : JingleSession::ref();
+ return i != incomingSessions.end() ? i->second : JingleSessionImpl::ref();
}
void JingleSessionManager::addIncomingSessionHandler(IncomingJingleSessionHandler* handler) {
@@ -31,10 +32,10 @@ void JingleSessionManager::removeIncomingSessionHandler(IncomingJingleSessionHan
incomingSessionHandlers.erase(std::remove(incomingSessionHandlers.begin(), incomingSessionHandlers.end(), handler), incomingSessionHandlers.end());
}
-void JingleSessionManager::handleIncomingSession(const JID& from, IncomingJingleSession::ref session) {
+void JingleSessionManager::handleIncomingSession(const JID& from, JingleSessionImpl::ref session, const std::vector<JingleContentPayload::ref>& contents) {
incomingSessions.insert(std::make_pair(JIDSession(from, session->getID()), session));
foreach (IncomingJingleSessionHandler* handler, incomingSessionHandlers) {
- if (handler->handleIncomingJingleSession(session)) {
+ if (handler->handleIncomingJingleSession(session, contents)) {
return;
}
}
diff --git a/Swiften/Jingle/JingleSessionManager.h b/Swiften/Jingle/JingleSessionManager.h
index 3e99656..3b23fb0 100644
--- a/Swiften/Jingle/JingleSessionManager.h
+++ b/Swiften/Jingle/JingleSessionManager.h
@@ -10,7 +10,7 @@
#include <map>
#include <Swiften/Base/boost_bsignals.h>
-#include <Swiften/Jingle/IncomingJingleSession.h>
+#include <Swiften/Jingle/JingleSessionImpl.h>
namespace Swift {
class IQRouter;
@@ -23,13 +23,13 @@ namespace Swift {
JingleSessionManager(IQRouter* router);
~JingleSessionManager();
- JingleSession::ref getSession(const JID& jid, const std::string& id) const;
+ JingleSessionImpl::ref getSession(const JID& jid, const std::string& id) const;
void addIncomingSessionHandler(IncomingJingleSessionHandler* handler);
void removeIncomingSessionHandler(IncomingJingleSessionHandler* handler);
protected:
- void handleIncomingSession(const JID& from, IncomingJingleSession::ref);
+ void handleIncomingSession(const JID& from, JingleSessionImpl::ref, const std::vector<JingleContentPayload::ref>& contents);
private:
IQRouter* router;
@@ -43,7 +43,7 @@ namespace Swift {
JID jid;
std::string session;
};
- typedef std::map<JIDSession, JingleSession::ref> SessionMap;
+ typedef std::map<JIDSession, JingleSessionImpl::ref> SessionMap;
SessionMap incomingSessions;
};
}
diff --git a/Swiften/Jingle/SConscript b/Swiften/Jingle/SConscript
index a8890b7..6b3cfd3 100644
--- a/Swiften/Jingle/SConscript
+++ b/Swiften/Jingle/SConscript
@@ -1,11 +1,11 @@
Import("swiften_env")
sources = [
- "IncomingJingleSession.cpp",
+ "JingleSession.cpp",
+ "JingleSessionImpl.cpp",
"IncomingJingleSessionHandler.cpp",
"JingleSessionManager.cpp",
"JingleResponder.cpp",
- "JingleSession.cpp",
]
swiften_env.Append(SWIFTEN_OBJECTS = swiften_env.SwiftenObject(sources))
diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.cpp b/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.cpp
new file mode 100644
index 0000000..e31bf87
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h>
+
+#include <boost/bind.hpp>
+#include <iostream>
+
+#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h>
+
+namespace Swift {
+
+void AvahiBrowseQuery::startBrowsing() {
+ std::cout << "Start browsing" << std::endl;
+ assert(!browser);
+ avahi_threaded_poll_lock(querier->getThreadedPoll());
+ browser = avahi_service_browser_new(querier->getClient(), AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_presence._tcp", NULL, static_cast<AvahiLookupFlags>(0), &handleServiceDiscoveredStatic, this);
+ if (!browser) {
+ std::cout << "Error" << std::endl;
+ eventLoop->postEvent(boost::bind(boost::ref(onError)), shared_from_this());
+ }
+ avahi_threaded_poll_unlock(querier->getThreadedPoll());
+}
+
+void AvahiBrowseQuery::stopBrowsing() {
+ std::cout << "Stop browsing" << std::endl;
+ avahi_threaded_poll_lock(querier->getThreadedPoll());
+ avahi_service_browser_free(browser);
+ browser = NULL;
+ avahi_threaded_poll_unlock(querier->getThreadedPoll());
+}
+
+void AvahiBrowseQuery::handleServiceDiscovered(AvahiServiceBrowser *, AvahiIfIndex interfaceIndex, AvahiProtocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags) {
+ switch (event) {
+ case AVAHI_BROWSER_FAILURE:
+ std::cout << "Service browse error" << std::endl;
+ eventLoop->postEvent(boost::bind(boost::ref(onError)), shared_from_this());
+ break;
+ case AVAHI_BROWSER_NEW: {
+ DNSSDServiceID service(name, domain, type, interfaceIndex);
+ std::cout << "Service discovered " << name << " " << domain << " " << type << " " << interfaceIndex << std::endl;
+ eventLoop->postEvent(boost::bind(boost::ref(onServiceAdded), service), shared_from_this());
+ break;
+ }
+ case AVAHI_BROWSER_REMOVE: {
+ std::cout << "Service went away " << name << " " << domain << " " << type << " " << interfaceIndex << std::endl;
+ DNSSDServiceID service(name, domain, type, interfaceIndex);
+ eventLoop->postEvent(boost::bind(boost::ref(onServiceRemoved), service), shared_from_this());
+ break;
+ }
+ case AVAHI_BROWSER_ALL_FOR_NOW:
+ case AVAHI_BROWSER_CACHE_EXHAUSTED:
+ break;
+ }
+}
+
+}
diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h
index 163a5f6..7641712 100644
--- a/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h
+++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h
@@ -6,7 +6,7 @@
#pragma once
-#include <boost/bind.hpp>
+#include <avahi-client/lookup.h>
#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h"
#include "Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h"
@@ -20,54 +20,15 @@ namespace Swift {
AvahiBrowseQuery(boost::shared_ptr<AvahiQuerier> q, EventLoop* eventLoop) : AvahiQuery(q, eventLoop), browser(NULL) {
}
- void startBrowsing() {
- std::cout << "Start browsing" << std::endl;
- assert(!browser);
- avahi_threaded_poll_lock(querier->getThreadedPoll());
- browser = avahi_service_browser_new(querier->getClient(), AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_presence._tcp", NULL, static_cast<AvahiLookupFlags>(0), &handleServiceDiscoveredStatic, this);
- if (!browser) {
- std::cout << "Error" << std::endl;
- eventLoop->postEvent(boost::bind(boost::ref(onError)), shared_from_this());
- }
- avahi_threaded_poll_unlock(querier->getThreadedPoll());
- }
-
- void stopBrowsing() {
- std::cout << "Stop browsing" << std::endl;
- avahi_threaded_poll_lock(querier->getThreadedPoll());
- avahi_service_browser_free(browser);
- browser = NULL;
- avahi_threaded_poll_unlock(querier->getThreadedPoll());
- }
+ void startBrowsing();
+ void stopBrowsing();
private:
static void handleServiceDiscoveredStatic(AvahiServiceBrowser *b, AvahiIfIndex interfaceIndex, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags flags, void* context) {
static_cast<AvahiBrowseQuery*>(context)->handleServiceDiscovered(b, interfaceIndex, protocol, event, name, type, domain, flags);
}
- void handleServiceDiscovered(AvahiServiceBrowser *, AvahiIfIndex interfaceIndex, AvahiProtocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags) {
- switch (event) {
- case AVAHI_BROWSER_FAILURE:
- std::cout << "Service browse error" << std::endl;
- eventLoop->postEvent(boost::bind(boost::ref(onError)), shared_from_this());
- break;
- case AVAHI_BROWSER_NEW: {
- DNSSDServiceID service(name, domain, type, interfaceIndex);
- std::cout << "Service discovered " << name << " " << domain << " " << type << " " << interfaceIndex << std::endl;
- eventLoop->postEvent(boost::bind(boost::ref(onServiceAdded), service), shared_from_this());
- break;
- }
- case AVAHI_BROWSER_REMOVE: {
- std::cout << "Service went away " << name << " " << domain << " " << type << " " << interfaceIndex << std::endl;
- DNSSDServiceID service(name, domain, type, interfaceIndex);
- eventLoop->postEvent(boost::bind(boost::ref(onServiceRemoved), service), shared_from_this());
- break;
- }
- case AVAHI_BROWSER_ALL_FOR_NOW:
- case AVAHI_BROWSER_CACHE_EXHAUSTED:
- break;
- }
- }
+ void handleServiceDiscovered(AvahiServiceBrowser *, AvahiIfIndex interfaceIndex, AvahiProtocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags);
private:
AvahiServiceBrowser* browser;
diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.cpp b/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.cpp
new file mode 100644
index 0000000..7975e7b
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h>
+
+#include <iostream>
+#include <boost/bind.hpp>
+
+#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h>
+
+namespace Swift {
+
+void AvahiRegisterQuery::registerService() {
+ std::cout << "Registering service " << name << ":" << port << std::endl;
+ avahi_threaded_poll_lock(querier->getThreadedPoll());
+ if (!group) {
+ std::cout << "Creating entry group" << std::endl;
+ group = avahi_entry_group_new(querier->getClient(), handleEntryGroupChange, this);
+ if (!group) {
+ std::cout << "Error ceating entry group" << std::endl;
+ eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this());
+ }
+ }
+
+ doRegisterService();
+ avahi_threaded_poll_unlock(querier->getThreadedPoll());
+}
+
+void AvahiRegisterQuery::unregisterService() {
+ if (group) {
+ avahi_entry_group_free(group);
+ group = NULL;
+ }
+}
+
+void AvahiRegisterQuery::updateServiceInfo(const ByteArray& txtRecord) {
+ this->txtRecord = txtRecord;
+ avahi_threaded_poll_lock(querier->getThreadedPoll());
+ assert(group);
+ avahi_entry_group_reset(group);
+ doRegisterService();
+ avahi_threaded_poll_unlock(querier->getThreadedPoll());
+}
+
+void AvahiRegisterQuery::doRegisterService() {
+ AvahiStringList* txtList;
+ avahi_string_list_parse(txtRecord.getData(), txtRecord.getSize(), &txtList);
+
+ int result = avahi_entry_group_add_service_strlst(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, static_cast<AvahiPublishFlags>(0), name.c_str(), "_presence._tcp", NULL, NULL, port, txtList);
+ if (result < 0) {
+ std::cout << "Error registering service: " << avahi_strerror(result) << std::endl;
+ eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this());
+ }
+ result = avahi_entry_group_commit(group);
+ if (result < 0) {
+ std::cout << "Error registering service: " << avahi_strerror(result) << std::endl;
+ }
+}
+
+void AvahiRegisterQuery::handleEntryGroupChange(AvahiEntryGroup* g, AvahiEntryGroupState state) {
+ std::cout << "ENtry group callback: " << state << std::endl;
+ switch (state) {
+ case AVAHI_ENTRY_GROUP_ESTABLISHED :
+ // Domain is a hack!
+ eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>(DNSSDServiceID(name, "local", "_presence._tcp", 0))), shared_from_this());
+ std::cout << "Entry group established" << std::endl;
+ break;
+ case AVAHI_ENTRY_GROUP_COLLISION : {
+ std::cout << "Entry group collision" << std::endl;
+ /*char *n;
+ n = avahi_alternative_service_name(name);
+ avahi_free(name);
+ name = n;*/
+ break;
+ }
+
+ case AVAHI_ENTRY_GROUP_FAILURE :
+ std::cout << "Entry group failure " << avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))) << std::endl;
+ break;
+
+ case AVAHI_ENTRY_GROUP_UNCOMMITED:
+ case AVAHI_ENTRY_GROUP_REGISTERING:
+ ;
+
+ /*
+ DNSServiceErrorType result = DNSServiceRegister(
+ &sdRef, 0, 0, name.c_str(), "_presence._tcp", NULL, NULL, port,
+ txtRecord.getSize(), txtRecord.getData(),
+ &AvahiRegisterQuery::handleServiceRegisteredStatic, this);
+ if (result != kDNSServiceErr_NoError) {
+ sdRef = NULL;
+ }*/
+ //eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this());
+ }
+}
+
+
+}
diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h
index 07966af..3303f1b 100644
--- a/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h
+++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h
@@ -21,94 +21,18 @@ namespace Swift {
AvahiRegisterQuery(const std::string& name, int port, const ByteArray& txtRecord, boost::shared_ptr<AvahiQuerier> querier, EventLoop* eventLoop) : AvahiQuery(querier, eventLoop), name(name), port(port), txtRecord(txtRecord), group(0) {
}
- void registerService() {
- std::cout << "Registering service " << name << ":" << port << std::endl;
- avahi_threaded_poll_lock(querier->getThreadedPoll());
- if (!group) {
- std::cout << "Creating entry group" << std::endl;
- group = avahi_entry_group_new(querier->getClient(), handleEntryGroupChange, this);
- if (!group) {
- std::cout << "Error ceating entry group" << std::endl;
- eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this());
- }
- }
-
- doRegisterService();
- avahi_threaded_poll_unlock(querier->getThreadedPoll());
- }
-
- void unregisterService() {
- if (group) {
- avahi_entry_group_free(group);
- group = NULL;
- }
- }
-
- void updateServiceInfo(const ByteArray& txtRecord) {
- this->txtRecord = txtRecord;
- avahi_threaded_poll_lock(querier->getThreadedPoll());
- assert(group);
- avahi_entry_group_reset(group);
- doRegisterService();
- avahi_threaded_poll_unlock(querier->getThreadedPoll());
- }
+ void registerService();
+ void unregisterService();
+ void updateServiceInfo(const ByteArray& txtRecord);
private:
- void doRegisterService() {
- AvahiStringList* txtList;
- avahi_string_list_parse(txtRecord.getData(), txtRecord.getSize(), &txtList);
-
- int result = avahi_entry_group_add_service_strlst(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, static_cast<AvahiPublishFlags>(0), name.c_str(), "_presence._tcp", NULL, NULL, port, txtList);
- if (result < 0) {
- std::cout << "Error registering service: " << avahi_strerror(result) << std::endl;
- eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this());
- }
- result = avahi_entry_group_commit(group);
- if (result < 0) {
- std::cout << "Error registering service: " << avahi_strerror(result) << std::endl;
- }
- }
+ void doRegisterService();
static void handleEntryGroupChange(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata) {
static_cast<AvahiRegisterQuery*>(userdata)->handleEntryGroupChange(g, state);
}
- void handleEntryGroupChange(AvahiEntryGroup* g, AvahiEntryGroupState state) {
- std::cout << "ENtry group callback: " << state << std::endl;
- switch (state) {
- case AVAHI_ENTRY_GROUP_ESTABLISHED :
- // Domain is a hack!
- eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>(DNSSDServiceID(name, "local", "_presence._tcp", 0))), shared_from_this());
- std::cout << "Entry group established" << std::endl;
- break;
- case AVAHI_ENTRY_GROUP_COLLISION : {
- std::cout << "Entry group collision" << std::endl;
- /*char *n;
- n = avahi_alternative_service_name(name);
- avahi_free(name);
- name = n;*/
- break;
- }
-
- case AVAHI_ENTRY_GROUP_FAILURE :
- std::cout << "Entry group failure " << avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))) << std::endl;
- break;
-
- case AVAHI_ENTRY_GROUP_UNCOMMITED:
- case AVAHI_ENTRY_GROUP_REGISTERING:
- ;
-
- /*
- DNSServiceErrorType result = DNSServiceRegister(
- &sdRef, 0, 0, name.c_str(), "_presence._tcp", NULL, NULL, port,
- txtRecord.getSize(), txtRecord.getData(),
- &AvahiRegisterQuery::handleServiceRegisteredStatic, this);
- if (result != kDNSServiceErr_NoError) {
- sdRef = NULL;
- }*/
- //eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this());
- }
- }
+ void handleEntryGroupChange(AvahiEntryGroup* g, AvahiEntryGroupState state);
/*
static void handleServiceRegisteredStatic(DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, void *context) {
diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.cpp b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.cpp
new file mode 100644
index 0000000..d9a1c5c
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.cpp
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h>
+
+#include <iostream>
+#include <boost/bind.hpp>
+
+namespace Swift {
+
+AvahiResolveHostnameQuery::AvahiResolveHostnameQuery(const std::string& hostname, int, boost::shared_ptr<AvahiQuerier> querier, EventLoop* eventLoop) : AvahiQuery(querier, eventLoop), hostname(hostname) {
+ std::cout << "Resolving hostname " << hostname << std::endl;
+}
+
+void AvahiResolveHostnameQuery::run() {
+ eventLoop->postEvent(boost::bind(boost::ref(onHostnameResolved), boost::optional<HostAddress>(HostAddress(hostname))), shared_from_this());
+}
+
+}
diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h
index 00712f1..acc1897 100644
--- a/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h
+++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h
@@ -19,13 +19,9 @@ namespace Swift {
class AvahiResolveHostnameQuery : public DNSSDResolveHostnameQuery, public AvahiQuery {
public:
- AvahiResolveHostnameQuery(const std::string& hostname, int, boost::shared_ptr<AvahiQuerier> querier, EventLoop* eventLoop) : AvahiQuery(querier, eventLoop), hostname(hostname) {
- std::cout << "Resolving hostname " << hostname << std::endl;
- }
+ AvahiResolveHostnameQuery(const std::string& hostname, int, boost::shared_ptr<AvahiQuerier> querier, EventLoop* eventLoop);
- void run() {
- eventLoop->postEvent(boost::bind(boost::ref(onHostnameResolved), boost::optional<HostAddress>(HostAddress(hostname))), shared_from_this());
- }
+ void run();
void finish() {
}
diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.cpp b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.cpp
new file mode 100644
index 0000000..24fe067
--- /dev/null
+++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h>
+
+#include <boost/bind.hpp>
+#include <iostream>
+
+#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h>
+
+namespace Swift {
+
+void AvahiResolveServiceQuery::start() {
+ std::cout << "Start resolving " << service.getName() << " " << service.getType() << " " << service.getDomain() << std::endl;
+ avahi_threaded_poll_lock(querier->getThreadedPoll());
+ assert(!resolver);
+ resolver = avahi_service_resolver_new(querier->getClient(), service.getNetworkInterfaceID(), AVAHI_PROTO_UNSPEC, service.getName().c_str(), service.getType().c_str(), service.getDomain().c_str(), AVAHI_PROTO_UNSPEC, static_cast<AvahiLookupFlags>(0), handleServiceResolvedStatic, this);
+ if (!resolver) {
+ std::cout << "Error starting resolver" << std::endl;
+ eventLoop->postEvent(boost::bind(boost::ref(onServiceResolved), boost::optional<Result>()), shared_from_this());
+ }
+ avahi_threaded_poll_unlock(querier->getThreadedPoll());
+}
+
+void AvahiResolveServiceQuery::stop() {
+ std::cout << "Stop resolving" << std::endl;
+ avahi_threaded_poll_lock(querier->getThreadedPoll());
+ avahi_service_resolver_free(resolver);
+ resolver = NULL;
+ avahi_threaded_poll_unlock(querier->getThreadedPoll());
+}
+
+void AvahiResolveServiceQuery::handleServiceResolved(AvahiServiceResolver* resolver, AvahiIfIndex, AvahiProtocol, AvahiResolverEvent event, const char *name, const char * type, const char* domain, const char * /*host_name*/, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags) {
+ std::cout << "Resolve finished" << std::endl;
+ switch(event) {
+ case AVAHI_RESOLVER_FAILURE:
+ std::cout << "Resolve error " << avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(resolver))) << std::endl;
+ eventLoop->postEvent(boost::bind(boost::ref(onServiceResolved), boost::optional<Result>()), shared_from_this());
+ break;
+ case AVAHI_RESOLVER_FOUND: {
+ std::cout << "Success" << std::endl;
+ char a[AVAHI_ADDRESS_STR_MAX];
+ avahi_address_snprint(a, sizeof(a), address);
+
+ ByteArray txtRecord;
+ txtRecord.resize(1024);
+ avahi_string_list_serialize(txt, txtRecord.getData(), txtRecord.getSize());
+
+ // FIXME: Probably not accurate
+ std::string fullname = std::string(name) + "." + std::string(type) + "." + std::string(domain) + ".";
+ std::cout << "Result: " << fullname << "->" << std::string(a) << ":" << port << std::endl;
+ eventLoop->postEvent(
+ boost::bind(
+ boost::ref(onServiceResolved),
+ Result(fullname, std::string(a), port, txtRecord)),
+ shared_from_this());
+ break;
+ }
+ }
+}
+
+}
diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h
index e9c4db1..be48409 100644
--- a/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h
+++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h
@@ -6,6 +6,8 @@
#pragma once
+#include <avahi-client/lookup.h>
+
#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h"
#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h"
#include "Swiften/LinkLocal/LinkLocalServiceInfo.h"
@@ -20,59 +22,15 @@ namespace Swift {
AvahiResolveServiceQuery(const DNSSDServiceID& service, boost::shared_ptr<AvahiQuerier> querier, EventLoop* eventLoop) : AvahiQuery(querier, eventLoop), service(service), resolver(NULL) {
}
- void start() {
- std::cout << "Start resolving " << service.getName() << " " << service.getType() << " " << service.getDomain() << std::endl;
- avahi_threaded_poll_lock(querier->getThreadedPoll());
- assert(!resolver);
- resolver = avahi_service_resolver_new(querier->getClient(), service.getNetworkInterfaceID(), AVAHI_PROTO_UNSPEC, service.getName().c_str(), service.getType().c_str(), service.getDomain().c_str(), AVAHI_PROTO_UNSPEC, static_cast<AvahiLookupFlags>(0), handleServiceResolvedStatic, this);
- if (!resolver) {
- std::cout << "Error starting resolver" << std::endl;
- eventLoop->postEvent(boost::bind(boost::ref(onServiceResolved), boost::optional<Result>()), shared_from_this());
- }
- avahi_threaded_poll_unlock(querier->getThreadedPoll());
- }
-
- void stop() {
- std::cout << "Stop resolving" << std::endl;
- avahi_threaded_poll_lock(querier->getThreadedPoll());
- avahi_service_resolver_free(resolver);
- resolver = NULL;
- avahi_threaded_poll_unlock(querier->getThreadedPoll());
- }
+ void start();
+ void stop();
private:
static void handleServiceResolvedStatic(AvahiServiceResolver* resolver, AvahiIfIndex interfaceIndex, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void* context) {
static_cast<AvahiResolveServiceQuery*>(context)->handleServiceResolved(resolver, interfaceIndex, protocol, event, name, type, domain, host_name, address, port, txt, flags);
}
- void handleServiceResolved(AvahiServiceResolver* resolver, AvahiIfIndex, AvahiProtocol, AvahiResolverEvent event, const char *name, const char * type, const char* domain, const char * /*host_name*/, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags) {
- std::cout << "Resolve finished" << std::endl;
- switch(event) {
- case AVAHI_RESOLVER_FAILURE:
- std::cout << "Resolve error " << avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(resolver))) << std::endl;
- eventLoop->postEvent(boost::bind(boost::ref(onServiceResolved), boost::optional<Result>()), shared_from_this());
- break;
- case AVAHI_RESOLVER_FOUND: {
- std::cout << "Success" << std::endl;
- char a[AVAHI_ADDRESS_STR_MAX];
- avahi_address_snprint(a, sizeof(a), address);
-
- ByteArray txtRecord;
- txtRecord.resize(1024);
- avahi_string_list_serialize(txt, txtRecord.getData(), txtRecord.getSize());
-
- // FIXME: Probably not accurate
- std::string fullname = std::string(name) + "." + std::string(type) + "." + std::string(domain) + ".";
- std::cout << "Result: " << fullname << "->" << std::string(a) << ":" << port << std::endl;
- eventLoop->postEvent(
- boost::bind(
- boost::ref(onServiceResolved),
- Result(fullname, std::string(a), port, txtRecord)),
- shared_from_this());
- break;
- }
- }
- }
+ void handleServiceResolved(AvahiServiceResolver* resolver, AvahiIfIndex, AvahiProtocol, AvahiResolverEvent event, const char *name, const char * type, const char* domain, const char * /*host_name*/, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags);
private:
DNSSDServiceID service;
diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h
index edd3056..c342247 100644
--- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h
+++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h
@@ -9,7 +9,7 @@
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <list>
-#include <boost/thread.hpp>
+#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h"
diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp
index d7d0228..b13b0c4 100644
--- a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp
+++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp
@@ -7,7 +7,9 @@
#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h"
#include <boost/bind.hpp>
+#include <iostream>
+#include <Swiften/Base/foreach.h>
#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDBrowseQuery.h"
#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDRegisterQuery.h"
#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveServiceQuery.h"
diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h
index b2871c9..9aef6a5 100644
--- a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h
+++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h
@@ -11,7 +11,6 @@
#include <list>
#include <set>
-#include "Swiften/Base/foreach.h"
#include <string>
#include "Swiften/EventLoop/EventOwner.h"
#include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h"
@@ -63,8 +62,8 @@ namespace Swift {
template<typename T>
std::vector< boost::shared_ptr<T> > getAllQueriesEverRun() const {
std::vector< boost::shared_ptr<T> > result;
- foreach(const boost::shared_ptr<FakeDNSSDQuery>& query, allQueriesEverRun) {
- if (boost::shared_ptr<T> resultQuery = boost::dynamic_pointer_cast<T>(query)) {
+ for (QueryList::const_iterator i = allQueriesEverRun.begin(); i != allQueriesEverRun.end(); ++i) {
+ if (boost::shared_ptr<T> resultQuery = boost::dynamic_pointer_cast<T>(*i)) {
result.push_back(resultQuery);
}
}
@@ -75,8 +74,8 @@ namespace Swift {
template<typename T>
std::vector< boost::shared_ptr<T> > getQueries() const {
std::vector< boost::shared_ptr<T> > result;
- foreach(const boost::shared_ptr<FakeDNSSDQuery>& query, runningQueries) {
- if (boost::shared_ptr<T> resultQuery = boost::dynamic_pointer_cast<T>(query)) {
+ for (QueryList::const_iterator i = runningQueries.begin(); i != runningQueries.end(); ++i) {
+ if (boost::shared_ptr<T> resultQuery = boost::dynamic_pointer_cast<T>(*i)) {
result.push_back(resultQuery);
}
}
@@ -86,8 +85,9 @@ namespace Swift {
private:
std::string domain;
EventLoop* eventLoop;
- std::list< boost::shared_ptr<FakeDNSSDQuery> > runningQueries;
- std::list< boost::shared_ptr<FakeDNSSDQuery> > allQueriesEverRun;
+ typedef std::list< boost::shared_ptr<FakeDNSSDQuery> > QueryList;
+ QueryList runningQueries;
+ QueryList allQueriesEverRun;
std::set<DNSSDServiceID> services;
typedef std::map<DNSSDServiceID,DNSSDResolveServiceQuery::Result> ServiceInfoMap;
ServiceInfoMap serviceInfo;
diff --git a/Swiften/LinkLocal/OutgoingLinkLocalSession.cpp b/Swiften/LinkLocal/OutgoingLinkLocalSession.cpp
index 65542d2..d13032d 100644
--- a/Swiften/LinkLocal/OutgoingLinkLocalSession.cpp
+++ b/Swiften/LinkLocal/OutgoingLinkLocalSession.cpp
@@ -8,6 +8,7 @@
#include <boost/bind.hpp>
+#include <Swiften/Base/foreach.h>
#include "Swiften/StreamStack/XMPPLayer.h"
#include "Swiften/Elements/ProtocolHeader.h"
#include "Swiften/Elements/StreamFeatures.h"
diff --git a/Swiften/LinkLocal/SConscript b/Swiften/LinkLocal/SConscript
index 6edf993..29ea692 100644
--- a/Swiften/LinkLocal/SConscript
+++ b/Swiften/LinkLocal/SConscript
@@ -31,7 +31,11 @@ elif myenv.get("HAVE_AVAHI", 0) :
myenv.Append(CPPDEFINES = ["HAVE_AVAHI"])
sources += [
"DNSSD/Avahi/AvahiQuerier.cpp",
- "DNSSD/Avahi/AvahiQuery.cpp"
+ "DNSSD/Avahi/AvahiQuery.cpp",
+ "DNSSD/Avahi/AvahiResolveHostnameQuery.cpp",
+ "DNSSD/Avahi/AvahiResolveServiceQuery.cpp",
+ "DNSSD/Avahi/AvahiRegisterQuery.cpp",
+ "DNSSD/Avahi/AvahiBrowseQuery.cpp",
]
objects = myenv.SwiftenObject(sources)
diff --git a/Swiften/LinkLocal/UnitTest/LinkLocalConnectorTest.cpp b/Swiften/LinkLo