diff --git a/backends/libpurple/main.cpp b/backends/libpurple/main.cpp index 9c3c9b08..e3d9f975 100644 --- a/backends/libpurple/main.cpp +++ b/backends/libpurple/main.cpp @@ -811,10 +811,20 @@ class SpectrumNetworkPlugin : public NetworkPlugin { } } + void handleFTStartRequest(const std::string &user, const std::string &buddyName, const std::string &fileName, unsigned long size, unsigned long ftID) { + PurpleXfer *xfer = m_xfers[user + fileName + buddyName]; + if (xfer) { + xfer->ui_data = (void *) ftID; + purple_xfer_request_accepted(xfer, fileName.c_str()); + purple_xfer_ui_ready(xfer); + } + } + std::map m_sessions; std::map m_accounts; std::map m_vcards; std::map m_authRequests; + std::map m_xfers; Config *config; }; @@ -1275,13 +1285,109 @@ static PurpleAccountUiOps accountUiOps = NULL }; +static void XferCreated(PurpleXfer *xfer) { + if (!xfer) { + return; + } + +// PurpleAccount *account = purple_xfer_get_account(xfer); +// np->handleFTStart(np->m_accounts[account], xfer->who, xfer, "", xhtml_); +} + +static void XferDestroyed(PurpleXfer *xfer) { +} + +static void xferCanceled(PurpleXfer *xfer) { +// FiletransferRepeater *repeater = (FiletransferRepeater *) xfer->ui_data; +// if (!repeater) +// return; +// GlooxMessageHandler::instance()->ftManager->removeSID(repeater->getSID()); +// repeater->handleXferCanceled(); + purple_xfer_unref(xfer); +} + +static void fileSendStart(PurpleXfer *xfer) { +// FiletransferRepeater *repeater = (FiletransferRepeater *) xfer->ui_data; +// repeater->fileSendStart(); +} + +static gboolean ft_ui_ready(void *data) { + purple_xfer_ui_ready((PurpleXfer *) data); + return FALSE; +} + +static void fileRecvStart(PurpleXfer *xfer) { +// FiletransferRepeater *repeater = (FiletransferRepeater *) xfer->ui_data; +// repeater->fileRecvStart(); + purple_timeout_add(1, ft_ui_ready, xfer); +} + +static void newXfer(PurpleXfer *xfer) { +// GlooxMessageHandler::instance()->ftManager->handleXferFileReceiveRequest(xfer); + PurpleAccount *account = purple_xfer_get_account(xfer); + std::string filename(xfer ? purple_xfer_get_filename(xfer) : ""); + purple_xfer_ref(xfer); + np->m_xfers[np->m_accounts[account] + filename + xfer->who] = xfer; + np->handleFTStart(np->m_accounts[account], xfer->who, filename, purple_xfer_get_size(xfer)); +} + +static void XferReceiveComplete(PurpleXfer *xfer) { +// FiletransferRepeater *repeater = (FiletransferRepeater *) xfer->ui_data; +// repeater->_tryToDeleteMe(); +// GlooxMessageHandler::instance()->ftManager->handleXferFileReceiveComplete(xfer); + purple_xfer_unref(xfer); +} + +static void XferSendComplete(PurpleXfer *xfer) { +// FiletransferRepeater *repeater = (FiletransferRepeater *) xfer->ui_data; +// repeater->_tryToDeleteMe(); + purple_xfer_unref(xfer); +} + +static gssize XferWrite(PurpleXfer *xfer, const guchar *buffer, gssize size) { +// FiletransferRepeater *repeater = (FiletransferRepeater *) xfer->ui_data; +// return repeater->handleLibpurpleData(buffer, size); + std::cout << "DATA " << std::string((const char *) buffer, (size_t) size) << "\n"; + purple_xfer_ui_ready(xfer); + return size; +} + +static void XferNotSent(PurpleXfer *xfer, const guchar *buffer, gsize size) { +// FiletransferRepeater *repeater = (FiletransferRepeater *) xfer->ui_data; +// repeater->handleDataNotSent(buffer, size); +} + +static gssize XferRead(PurpleXfer *xfer, guchar **buffer, gssize size) { +// FiletransferRepeater *repeater = (FiletransferRepeater *) xfer->ui_data; +// int data_size = repeater->getDataToSend(buffer, size); +// if (data_size == 0) +// return 0; +// +// return data_size; + return 0; +} + +static PurpleXferUiOps xferUiOps = +{ + XferCreated, + XferDestroyed, + NULL, + NULL, + xferCanceled, + xferCanceled, + XferWrite, + XferRead, + XferNotSent, + NULL +}; + static void transport_core_ui_init(void) { purple_blist_set_ui_ops(&blistUiOps); purple_accounts_set_ui_ops(&accountUiOps); purple_notify_set_ui_ops(¬ifyUiOps); purple_request_set_ui_ops(&requestUiOps); -// purple_xfers_set_ui_ops(getXferUiOps()); + purple_xfers_set_ui_ops(&xferUiOps); purple_connections_set_ui_ops(&conn_ui_ops); purple_conversations_set_ui_ops(&conversation_ui_ops); // #ifndef WIN32 @@ -1423,6 +1529,12 @@ static bool initPurple(Config &cfg) { // purple_signal_connect(purple_blist_get_handle(), "buddy-status-changed", &blist_handle,PURPLE_CALLBACK(buddyStatusChanged), NULL); purple_signal_connect(purple_blist_get_handle(), "blist-node-removed", &blist_handle,PURPLE_CALLBACK(NodeRemoved), NULL); // purple_signal_connect(purple_conversations_get_handle(), "chat-topic-changed", &conversation_handle, PURPLE_CALLBACK(conv_chat_topic_changed), NULL); + static int xfer_handle; + purple_signal_connect(purple_xfers_get_handle(), "file-send-start", &xfer_handle, PURPLE_CALLBACK(fileSendStart), NULL); + purple_signal_connect(purple_xfers_get_handle(), "file-recv-start", &xfer_handle, PURPLE_CALLBACK(fileRecvStart), NULL); + purple_signal_connect(purple_xfers_get_handle(), "file-recv-request", &xfer_handle, PURPLE_CALLBACK(newXfer), NULL); + purple_signal_connect(purple_xfers_get_handle(), "file-recv-complete", &xfer_handle, PURPLE_CALLBACK(XferReceiveComplete), NULL); + purple_signal_connect(purple_xfers_get_handle(), "file-send-complete", &xfer_handle, PURPLE_CALLBACK(XferSendComplete), NULL); // // purple_commands_init(); diff --git a/include/transport/networkplugin.h b/include/transport/networkplugin.h index 1c8adf36..acac95af 100644 --- a/include/transport/networkplugin.h +++ b/include/transport/networkplugin.h @@ -142,6 +142,8 @@ class NetworkPlugin { /// \param message Message. void handleAttention(const std::string &user, const std::string &buddyName, const std::string &message); + void handleFTStart(const std::string &user, const std::string &buddyName, const std::string fileName, unsigned long size); + /// Called when XMPP user wants to connect legacy network. /// You should connect him to legacy network and call handleConnected or handleDisconnected function later. /// \param user XMPP JID of user for which this event occurs. @@ -209,6 +211,8 @@ class NetworkPlugin { virtual void handleStoppedTypingRequest(const std::string &/*user*/, const std::string &/*buddyName*/) {} virtual void handleAttentionRequest(const std::string &/*user*/, const std::string &/*buddyName*/, const std::string &/*message*/) {} + virtual void handleFTStartRequest(const std::string &/*user*/, const std::string &/*buddyName*/, const std::string &/*fileName*/, unsigned long size, unsigned long ftID) {} + virtual void handleExit() { std::cout << "EXITING\n"; exit(1); } @@ -225,6 +229,7 @@ class NetworkPlugin { void handleBuddyRemovedPayload(const std::string &payload); void handleChatStatePayload(const std::string &payload, Swift::ChatState::ChatStateType type); void handleAttentionPayload(const std::string &payload); + void handleFTStartPayload(const std::string &payload); void handleDataRead(const Swift::SafeByteArray&); void _handleConnected(bool error); void handleDisconnected(); diff --git a/include/transport/networkpluginserver.h b/include/transport/networkpluginserver.h index 4c40b091..25c7e8b6 100644 --- a/include/transport/networkpluginserver.h +++ b/include/transport/networkpluginserver.h @@ -89,6 +89,7 @@ class NetworkPluginServer { void handleAuthorizationPayload(const std::string &payload); void handleAttentionPayload(const std::string &payload); void handleStatsPayload(Backend *c, const std::string &payload); + void handleFTStartPayload(const std::string &payload); void handleUserCreated(User *user); void handleRoomJoined(User *user, const std::string &room, const std::string &nickname, const std::string &password); @@ -106,6 +107,9 @@ class NetworkPluginServer { void handleVCardUpdated(User *user, boost::shared_ptr vcard); void handleVCardRequired(User *user, const std::string &name, unsigned int id); + void handleFTAccepted(User *user, const std::string &buddyName, const std::string &fileName, unsigned long size, unsigned long ftID); + void handleFTRejected(User *user, const std::string &buddyName, const std::string &fileName, unsigned long size, unsigned long ftID); + void send(boost::shared_ptr &, const std::string &data); void pingTimeout(); diff --git a/src/networkplugin.cpp b/src/networkplugin.cpp index eb18a86d..117895f3 100644 --- a/src/networkplugin.cpp +++ b/src/networkplugin.cpp @@ -263,6 +263,21 @@ void NetworkPlugin::handleRoomNicknameChanged(const std::string &user, const std send(message); } +void NetworkPlugin::handleFTStart(const std::string &user, const std::string &buddyName, const std::string fileName, unsigned long size) { + pbnetwork::File room; + room.set_username(user); + room.set_buddyname(buddyName); + room.set_filename(fileName); + room.set_size(size); + + std::string message; + room.SerializeToString(&message); + + WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_FT_START); + + send(message); +} + void NetworkPlugin::_handleConnected(bool error) { if (error) { // LOG4CXX_ERROR(logger, "Connecting error. Exiting"); @@ -334,6 +349,16 @@ void NetworkPlugin::handleAttentionPayload(const std::string &data) { handleAttentionRequest(payload.username(), payload.buddyname(), payload.message()); } +void NetworkPlugin::handleFTStartPayload(const std::string &data) { + pbnetwork::File payload; + if (payload.ParseFromString(data) == false) { + // TODO: ERROR + return; + } + + handleFTStartRequest(payload.username(), payload.buddyname(), payload.filename(), payload.size(), payload.ftid()); +} + void NetworkPlugin::handleJoinRoomPayload(const std::string &data) { pbnetwork::Room payload; if (payload.ParseFromString(data) == false) { @@ -481,6 +506,9 @@ void NetworkPlugin::handleDataRead(const Swift::SafeByteArray &data) { case pbnetwork::WrapperMessage_Type_TYPE_ATTENTION: handleAttentionPayload(wrapper.payload()); break; + case pbnetwork::WrapperMessage_Type_TYPE_FT_START: + handleFTStartPayload(wrapper.payload()); + break; default: return; } diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 939c67e0..d1b8406e 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -572,6 +572,21 @@ void NetworkPluginServer::handleStatsPayload(Backend *c, const std::string &data c->shared = payload.shared(); } +void NetworkPluginServer::handleFTStartPayload(const std::string &data) { + pbnetwork::File payload; + if (payload.ParseFromString(data) == false) { + // TODO: ERROR + return; + } + + User *user = m_userManager->getUser(payload.username()); + if (!user) + return; + + LOG4CXX_INFO(logger, "handleFTStartPayload " << payload.filename()); + handleFTAccepted(user, payload.buddyname(), payload.filename(), payload.size(), 255); +} + void NetworkPluginServer::handleDataRead(Backend *c, const Swift::SafeByteArray &data) { // Append data to buffer c->data.insert(c->data.end(), data.begin(), data.end()); @@ -651,6 +666,9 @@ void NetworkPluginServer::handleDataRead(Backend *c, const Swift::SafeByteArray case pbnetwork::WrapperMessage_Type_TYPE_STATS: handleStatsPayload(c, wrapper.payload()); break; + case pbnetwork::WrapperMessage_Type_TYPE_FT_START: + handleFTStartPayload(wrapper.payload()); + break; default: return; } @@ -1135,6 +1153,46 @@ void NetworkPluginServer::handleVCardRequired(User *user, const std::string &nam send(c->connection, message); } +void NetworkPluginServer::handleFTAccepted(User *user, const std::string &buddyName, const std::string &fileName, unsigned long size, unsigned long ftID) { + pbnetwork::File f; + f.set_username(user->getJID().toBare()); + f.set_buddyname(buddyName); + f.set_filename(fileName); + f.set_size(size); + f.set_ftid(ftID); + + std::string message; + f.SerializeToString(&message); + + WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_FT_START); + + Backend *c = (Backend *) user->getData(); + if (!c) { + return; + } + send(c->connection, message); +} + +void NetworkPluginServer::handleFTRejected(User *user, const std::string &buddyName, const std::string &fileName, unsigned long size, unsigned long ftID) { + pbnetwork::File f; + f.set_username(user->getJID().toBare()); + f.set_buddyname(buddyName); + f.set_filename(fileName); + f.set_size(size); + f.set_ftid(ftID); + + std::string message; + f.SerializeToString(&message); + + WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_FT_FINISH); + + Backend *c = (Backend *) user->getData(); + if (!c) { + return; + } + send(c->connection, message); +} + void NetworkPluginServer::sendPing(Backend *c) { std::string message; diff --git a/src/pbnetwork.proto b/src/pbnetwork.proto index b478bb15..1bfaad37 100644 --- a/src/pbnetwork.proto +++ b/src/pbnetwork.proto @@ -88,6 +88,19 @@ message Stats { required int32 shared = 3; } +message File { + required string userName = 1; + required string buddyName = 2; + required string fileName = 3; + required int32 size = 4; + optional int32 ftID = 5; +} + +message FileTransferData { + required int32 ftID = 1; + required bytes data = 2; +} + message WrapperMessage { enum Type { TYPE_CONNECTED = 1; @@ -110,8 +123,11 @@ message WrapperMessage { TYPE_BUDDY_STOPPED_TYPING = 19; TYPE_BUDDY_TYPED = 20; TYPE_AUTH_REQUEST = 21; - TYPE_ATTENTION = 22; + TYPE_ATTENTION = 22; TYPE_STATS = 23; + TYPE_FT_START = 24; + TYPE_FT_FINISH = 25; + TYPE_FT_DATA = 26; } required Type type = 1; optional bytes payload = 2;