#ifndef TALK_APP_WIN32_FILESHARE_H__ #define TALK_APP_WIN32_FILESHARE_H__ #include "talk/base/messagequeue.h" #include "talk/base/socketpool.h" #include "talk/base/stringutils.h" #include "talk/base/sigslot.h" #include "talk/p2p/base/session.h" #include "talk/p2p/base/sessiondescription.h" #include "talk/xmpp/jid.h" class StreamCounter; class StreamRelay; namespace talk_base { class HttpClient; class HttpServer; class HttpTransaction; } extern const std::string NS_GOOGLE_SHARE; namespace cricket { /////////////////////////////////////////////////////////////////////////////// // FileShareManifest /////////////////////////////////////////////////////////////////////////////// class FileShareManifest { public: enum Type { T_FILE, T_IMAGE, T_FOLDER }; enum { SIZE_UNKNOWN = talk_base::SIZE_UNKNOWN }; struct Item { Type type; std::string name; size_t size, width, height; }; typedef std::vector ItemList; inline bool empty() const { return items_.empty(); } inline size_t size() const { return items_.size(); } inline const Item& item(size_t index) const { return items_[index]; } void AddFile(const std::string& name, size_t size); void AddImage(const std::string& name, size_t size, size_t width, size_t height); void AddFolder(const std::string& name, size_t size); size_t GetItemCount(Type t) const; inline size_t GetFileCount() const { return GetItemCount(T_FILE); } inline size_t GetImageCount() const { return GetItemCount(T_IMAGE); } inline size_t GetFolderCount() const { return GetItemCount(T_FOLDER); } private: ItemList items_; }; enum FileShareState { FS_NONE, // Initialization FS_OFFER, // Offer extended FS_TRANSFER, // In progress FS_COMPLETE, // Completed successfully FS_LOCAL_CANCEL, // Local side cancelled FS_REMOTE_CANCEL, // Remote side cancelled FS_FAILURE // An error occurred during transfer }; class FileShareSession : public talk_base::StreamPool, public talk_base::MessageHandler, public sigslot::has_slots<> { public: struct FileShareDescription : public cricket::SessionDescription { FileShareManifest manifest; bool supports_http; std::string source_path; std::string preview_path; FileShareDescription() : supports_http(false) { } }; FileShareSession(cricket::Session* session, const std::string &user_agent); virtual ~FileShareSession(); bool IsComplete() const; bool IsClosed() const; FileShareState state() const; sigslot::signal1 SignalState; sigslot::signal1 SignalNextFile; sigslot::signal1 SignalUpdateProgress; sigslot::signal4 SignalResampleImage; void ResampleComplete(talk_base::StreamInterface *si, talk_base::HttpTransaction *trans, bool success); bool is_sender() const; const buzz::Jid& jid() const; const FileShareManifest* manifest() const; const std::string& local_folder() const; void SetLocalFolder(const std::string& folder) { local_folder_ = folder; } void Share(const buzz::Jid& jid, FileShareManifest* manifest); void Accept(); void Decline(); void Cancel(); bool GetItemUrl(size_t index, std::string* url); bool GetImagePreviewUrl(size_t index, size_t width, size_t height, std::string* url); // Returns true if the transferring item size is known bool GetProgress(size_t& bytes) const; // Returns true if the total size is known bool GetTotalSize(size_t& bytes) const; // Returns true if currently transferring item name is known bool GetCurrentItemName(std::string* name); // TODO: Eliminate this eventually? cricket::Session* session() { return session_; } // StreamPool Interface virtual talk_base::StreamInterface* RequestConnectedStream(const talk_base::SocketAddress& remote, int* err); virtual void ReturnConnectedStream(talk_base::StreamInterface* stream); // MessageHandler Interface virtual void OnMessage(talk_base::Message* msg); void GetItemNetworkPath(size_t index, bool preview, std::string* path); private: typedef std::list ProxyList; typedef std::list TransactionList; // Session Signals void OnSessionState(cricket::Session* session, cricket::Session::State state); void OnSessionInfoMessage(cricket::Session* session, const cricket::Session::XmlElements& els); void OnSessionChannelGone(cricket::Session* session, const std::string& name); // HttpClient Signals void OnHttpClientComplete(talk_base::HttpClient* http, int err); void OnHttpClientClosed(talk_base::HttpClient* http, int err); // HttpServer Signals void OnHttpRequest(talk_base::HttpServer* server, talk_base::HttpTransaction* transaction); void OnHttpRequestComplete(talk_base::HttpServer* server, talk_base::HttpTransaction* transaction, int err); void OnHttpConnectionClosed(talk_base::HttpServer* server, int err, talk_base::StreamInterface* stream); // TarStream Signals void OnNextEntry(const std::string& name, size_t size); // Socket Signals void OnProxyAccept(talk_base::AsyncSocket* socket); void OnProxyClosed(StreamRelay* proxy, int error); // StreamCounterSignals void OnUpdateBytes(size_t count); // Internal Helpers void GenerateTemporaryPrefix(std::string* prefix); bool GetItemBaseUrl(size_t index, bool preview, std::string* url); bool GetProxyAddress(talk_base::SocketAddress& address, bool is_remote); talk_base::StreamInterface* CreateChannel(const std::string& channel_name); void SetState(FileShareState state, bool prevent_close); void OnInitiate(); void NextDownload(); const FileShareDescription* description() const; void DoClose(bool terminate); cricket::Session* session_; FileShareState state_; bool is_closed_; bool is_sender_; buzz::Jid jid_; FileShareManifest* manifest_; std::string source_path_; std::string preview_path_; std::string local_folder_; // The currently active p2p streams to our peer talk_base::StreamCache pool_; // The http client state (client only) talk_base::HttpClient* http_client_; // The http server state (server only) talk_base::HttpServer* http_server_; // The connection id of the currently transferring file (server) int transfer_connection_id_; // The counter for the currently transferring file const StreamCounter* counter_; // The number of manifest items that have successfully transferred size_t item_transferring_; // The byte count of successfully transferred items size_t bytes_transferred_; // Where the currently transferring item is being (temporarily) saved (client) std::string transfer_path_; // The name of the currently transferring item std::string transfer_name_; // Where the files are saved after transfer (client) std::vector stored_location_; // Was it a local cancel? Or a remote cancel? bool local_cancel_; // Proxy socket for local IE http requests talk_base::AsyncSocket* local_listener_; // Proxy socket for remote IE http requests talk_base::AsyncSocket* remote_listener_; // Cached address of remote_listener_ talk_base::SocketAddress remote_listener_address_; // Uniqueness for channel names size_t next_channel_id_; // Proxy relays ProxyList proxies_; std::string user_agent_; TransactionList transactions_; }; class FileShareSessionClient : public SessionClient { public: FileShareSessionClient(SessionManager *sm, buzz::Jid jid, const std::string &user_agent) : sm_(sm), jid_(jid), user_agent_(user_agent) {} virtual void OnSessionCreate(cricket::Session* session, bool received_initiate); virtual void OnSessionDestroy(cricket::Session* session); virtual const cricket::SessionDescription* CreateSessionDescription(const buzz::XmlElement* element); virtual buzz::XmlElement* TranslateSessionDescription(const cricket::SessionDescription* description); FileShareSession *CreateFileShareSession(); sigslot::signal1 SignalFileShareSessionCreate; sigslot::signal1 SignalFileShareSessionDestroy; private: SessionManager *sm_; buzz::Jid jid_; friend class FileShareSession; typedef std::set SessionSet; SessionSet sessions_; std::string user_agent_; }; } // namespace cricket #endif // TALK_APP_WIN32_FILESHARE_H__