From 297626e55974e9082f0fd76b98050fc291b1e3f3 Mon Sep 17 00:00:00 2001 From: Alexander Lantsev Date: Fri, 5 Apr 2013 16:08:13 +0000 Subject: - first approach of file transferring git-svn-id: http://svn.miranda-ng.org/main/trunk@4317 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/Skype/src/skype_database.cpp | 20 ++++ protocols/Skype/src/skype_events.cpp | 149 ++++++++++++++++++++++++++++++ protocols/Skype/src/skype_proto.cpp | 126 +++++++++++++++++++++++-- protocols/Skype/src/skype_proto.h | 38 +++++++- protocols/Skype/src/skype_subclassing.cpp | 27 +++++- protocols/Skype/src/skype_subclassing.h | 21 ++++- protocols/Skype/src/skype_transfer.cpp | 29 ++++++ protocols/Skype/src/skype_utils.cpp | 5 +- 8 files changed, 401 insertions(+), 14 deletions(-) create mode 100644 protocols/Skype/src/skype_transfer.cpp (limited to 'protocols/Skype/src') diff --git a/protocols/Skype/src/skype_database.cpp b/protocols/Skype/src/skype_database.cpp index 9d87b9b2c7..50fac3651f 100644 --- a/protocols/Skype/src/skype_database.cpp +++ b/protocols/Skype/src/skype_database.cpp @@ -92,4 +92,24 @@ void CSkypeProto::RaiseMessageSendedEvent( pre.szMessage = (char *)message; ::CallService(MS_PROTO_CHAINSEND, 0, (LPARAM)&ccs); +} + +void CSkypeProto::RaiseFileReceivedEvent( + DWORD timestamp, + const char* sid, + const char* nick, + const char* message) +{ + PROTORECVFILET pre = {0}; + + CCSDATA ccs = {0}; + ccs.szProtoService = PSR_FILE; + ccs.hContact = this->AddContactBySid(sid, nick); + ccs.wParam = 0; + ccs.lParam = (LPARAM)⪯ + pre.flags = PREF_UTF; + pre.timestamp = timestamp; + //pre.szMessage = (char *)message; + + ::CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); } \ No newline at end of file diff --git a/protocols/Skype/src/skype_events.cpp b/protocols/Skype/src/skype_events.cpp index fcacb7117f..ac29ab59e9 100644 --- a/protocols/Skype/src/skype_events.cpp +++ b/protocols/Skype/src/skype_events.cpp @@ -148,6 +148,146 @@ void CSkypeProto::OnMessageReceived(CConversation::Ref conversation, CMessage::R HXML hXml = xi.parseString(xml, &bytesProcessed, NULL);*/ } +void CSkypeProto::OnTransferChanged(int prop, CTransfer::Ref transfer) +{ + if (prop == Transfer::P_STATUS) + { + Transfer::STATUS status; + transfer->GetPropStatus(status); + + /*CConversation::Ref conversation; + transfer->GetPropConvoId(conversation); + + SEBinary guid; + transfer->GetPropChatmsgGuid(guid); + auto ft = this->FindTransfer(guid);*/ + auto ft = this->FindFileTransfer(transfer); + + SEString sid; + transfer->GetPropPartnerHandle(sid); + //CParticipant::Refs participants; + //conversation->GetParticipants(participants, CConversation::OTHER_CONSUMERS); + ////for (uint i = 0; i < participants.size(); i++) + //participants[0]->GetPropIdentity(sid); + + HANDLE hContact = this->GetContactBySid(sid); + + switch(status) + { + /*case CTransfer::NEW: + break;*/ + /*case CTransfer::WAITING_FOR_ACCEPT: + break;*/ + case CTransfer::CONNECTING: + this->SendBroadcast(hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, (HANDLE)ft, 0); + break; + case CTransfer::TRANSFERRING: + case CTransfer::TRANSFERRING_OVER_RELAY: + this->SendBroadcast(hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, (HANDLE)ft, 0); + break; + case CTransfer::FAILED: + this->SendBroadcast(hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)ft, 0); + break; + case CTransfer::COMPLETED: + this->SendBroadcast(hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, (HANDLE)ft, 0); + break; + case CTransfer::CANCELLED: + case CTransfer::CANCELLED_BY_REMOTE: + this->SendBroadcast(hContact, ACKTYPE_FILE, ACKRESULT_DENIED, (HANDLE)ft, 0); + break; + } + } + if (prop == Transfer::P_BYTESTRANSFERRED) + { + //PROTOFILETRANSFERSTATUS + //this->SendBroadcast(hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)ccid, 0); + //SEString transferProgressStr; + //transfer->GetPropBytestransferred(transferProgressStr); + //uint transferProgress = transferProgressStr.toUInt(); + + //SEString fileSizeStr; + //transfer->GetPropFilesize(fileSizeStr); + + //// fileSize is float here, to avoid trouble with + //// files lessthan 100 bytes in size. + //float fileSize = (float)fileSizeStr.toUInt(); + //float progress = (100 * transferProgress) / fileSize; + + //uint transferRate; + //transfer->GetPropBytespersecond(transferRate); + //float transferRateInKb = (float)transferRate / 1024; + + //PROTOFILETRANSFERSTATUS pfts = {0}; + //pfts.cbSize = sizeof(pfts); + ////pfts.szCurrentFile + //pfts.currentFileProgress = progress; + //pfts. + + //this->SendBroadcast(hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)ccid, 0); + // printf("Progress: %3.0f%% (%1.0f KB/s)\n", progress, transferRateInKb); + } +} + +void CSkypeProto::OnFileReceived(CConversation::Ref conversation, CMessage::Ref message) +{ + CTransfer::Refs transferList; + message->GetTransfers(transferList); + Sid::fetch(transferList); + + Transfer::TYPE transferType; + Transfer::STATUS transferStatus; + + for (uint i = 0; i < transferList.size(); i++) + { + auto transfer = transferList[i]; + transfer.fetch(); + transfer->SetOnTransferCallback( + (CTransfer::OnTransfer)&CSkypeProto::OnTransferChanged, + this); + //this->transferList.append(transfer); + + // For incomings, we need to check for transfer status, just to be sure. + // In some cases, a transfer can appear with STATUS == PLACEHOLDER + // As such transfers cannot be accepted, we will need to just store + // the reference to Transfer Object and then check for further + // status changes in Transfer::OnChange + transfer->GetPropType(transferType); + transfer->GetPropStatus(transferStatus); + if ((transferType == Transfer::INCOMING) && (transferStatus == Transfer::NEW)) + { + //transferList[i]->AutoAccept(); + SEString name; + transfer->GetPropFilename(name); + + wchar_t *path = ::mir_utf8decodeW(name); + + SEString sid; + transfer->GetPropPartnerHandle(sid); + HANDLE hContact = this->GetContactBySid(sid); + + auto ft = new FileTransfer(this); + ft->transfers.append(transfer); + transfer->GetPropChatmsgGuid(ft->guid); + this->fileTransferList.insert(ft); + + PROTORECVFILET pre = {0}; + pre.flags = PREF_TCHAR; + pre.fileCount = 1; + pre.timestamp = time(NULL); + pre.tszDescription = L" "; + pre.ptszFiles = &path; + pre.lParam = (LPARAM)ft; + ::ProtoChainRecvFile(hContact, &pre); + + ::mir_free(path); + } + } + + //SEString bodyXml; + //message->GetPropBodyXml(bodyXml); + //printf("File transfer msg BodyXML:\n%s\n", (const char*)bodyXml); +} + void CSkypeProto::OnMessage(CConversation::Ref conversation, CMessage::Ref message) { CMessage::TYPE messageType; @@ -156,6 +296,12 @@ void CSkypeProto::OnMessage(CConversation::Ref conversation, CMessage::Ref messa CMessage::SENDING_STATUS sendingStatus; message->GetPropSendingStatus(sendingStatus); + if (messageType == CMessage::POSTED_FILES) + { + this->OnFileReceived(conversation, message); + return; + } + CMessage::CONSUMPTION_STATUS status; message->GetPropConsumptionStatus(status); @@ -179,6 +325,9 @@ void CSkypeProto::OnMessage(CConversation::Ref conversation, CMessage::Ref messa } break; + case CMessage::POSTED_FILES: + break; + case CMessage::ADDED_CONSUMERS: { SEString data; diff --git a/protocols/Skype/src/skype_proto.cpp b/protocols/Skype/src/skype_proto.cpp index c5014171b4..6b31760df7 100644 --- a/protocols/Skype/src/skype_proto.cpp +++ b/protocols/Skype/src/skype_proto.cpp @@ -1,9 +1,11 @@ -#include "skype_proto.h" +#include "skype_proto.h" -CSkypeProto::CSkypeProto(const char* protoName, const TCHAR* userName) +CSkypeProto::CSkypeProto(const char* protoName, const TCHAR* userName) : fileTransferList(1) { ProtoConstructor(this, protoName, userName); + //this->fileTransferList = new LIST(1); + //this->login = NULL; //this->password = NULL; this->rememberPassword = false; @@ -133,17 +135,66 @@ int __cdecl CSkypeProto::AuthRequest(HANDLE hContact, const TCHAR* szMessage) HANDLE __cdecl CSkypeProto::ChangeInfo( int iInfoType, void* pInfoData ) { return 0; } -HANDLE __cdecl CSkypeProto::FileAllow( HANDLE hContact, HANDLE hTransfer, const TCHAR* szPath ) { return 0; } -int __cdecl CSkypeProto::FileCancel( HANDLE hContact, HANDLE hTransfer ) { return 0; } -int __cdecl CSkypeProto::FileDeny( HANDLE hContact, HANDLE hTransfer, const TCHAR* szReason ) { return 0; } -int __cdecl CSkypeProto::FileResume( HANDLE hTransfer, int* action, const TCHAR** szFilename ) { return 0; } +HANDLE __cdecl CSkypeProto::FileAllow( HANDLE hContact, HANDLE hTransfer, const TCHAR* szPath ) +{ + auto ft = (FileTransfer*)hTransfer; + + for (uint i = 0; i < ft->transfers.size(); i++) + { + bool success; + SEString name; + wchar_t fullPath[MAX_PATH] = {0}; + ft->transfers[i]->GetPropFilename(name); + ::mir_sntprintf(fullPath, MAX_PATH, L"%s%s", szPath, ::mir_utf8decodeW(name)); + if (ft->transfers[i]->Accept(::mir_u2a(fullPath), success) && success) + { + return 0; + } + } + + return hTransfer; +} + +int __cdecl CSkypeProto::FileCancel( HANDLE hContact, HANDLE hTransfer ) +{ + auto ft = (FileTransfer*)hTransfer; + + for (uint i = 0; i < ft->transfers.size(); i++) + { + if (ft->transfers[i]->Cancel()) + { + return 1; + } + } + + return 0; +} + +int __cdecl CSkypeProto::FileDeny( HANDLE hContact, HANDLE hTransfer, const TCHAR* szReason ) +{ + auto ft = (FileTransfer*)hTransfer; + + for (uint i = 0; i < ft->transfers.size(); i++) + { + if (ft->transfers[i]->Cancel()) + { + return 1; + } + } + + return 0; +} +int __cdecl CSkypeProto::FileResume( HANDLE hTransfer, int* action, const TCHAR** szFilename ) +{ + return 0; +} DWORD_PTR __cdecl CSkypeProto:: GetCaps(int type, HANDLE hContact) { switch(type) { case PFLAGNUM_1: - return PF1_IM | PF1_BASICSEARCH | PF1_ADDSEARCHRES | PF1_SEARCHBYEMAIL/* | PF1_SEARCHBYNAME*/; + return PF1_IM | PF1_FILE | PF1_BASICSEARCH | PF1_ADDSEARCHRES | PF1_SEARCHBYEMAIL/* | PF1_SEARCHBYNAME*/; case PFLAGNUM_2: case PFLAGNUM_3: return PF2_ONLINE | PF2_SHORTAWAY | PF2_HEAVYDND | PF2_INVISIBLE; @@ -202,7 +253,11 @@ HWND __cdecl CSkypeProto::SearchAdvanced( HWND owner ) { return 0; } HWND __cdecl CSkypeProto::CreateExtendedSearchUI( HWND owner ){ return 0; } int __cdecl CSkypeProto::RecvContacts( HANDLE hContact, PROTORECVEVENT* ) { return 0; } -int __cdecl CSkypeProto::RecvFile( HANDLE hContact, PROTORECVFILET* ) { return 0; } +int __cdecl CSkypeProto::RecvFile( HANDLE hContact, PROTORECVFILET* evt) +{ + //db_unset(hContact, "CList", "Hidden"); + return Proto_RecvFile(hContact, evt); +} int __cdecl CSkypeProto::RecvMsg( HANDLE hContact, PROTORECVEVENT* pre) { @@ -213,7 +268,60 @@ int __cdecl CSkypeProto::RecvMsg( HANDLE hContact, PROTORECVEVENT* pre) int __cdecl CSkypeProto::RecvUrl( HANDLE hContact, PROTORECVEVENT* ) { return 0; } int __cdecl CSkypeProto::SendContacts( HANDLE hContact, int flags, int nContacts, HANDLE* hContactsList ) { return 0; } -HANDLE __cdecl CSkypeProto::SendFile( HANDLE hContact, const TCHAR* szDescription, TCHAR** ppszFiles ) { return 0; } + +HANDLE __cdecl CSkypeProto::SendFile( HANDLE hContact, const TCHAR* szDescription, TCHAR** ppszFiles ) +{ + if (this->IsOnline() && hContact && ppszFiles) + { + SEStringList targets; + char* sid = ::DBGetString(hContact, this->m_szModuleName, "sid"); + targets.append(sid); + + CConversation::Ref conversation = CConversation::FindBySid( + this->skype, + ::DBGetString(hContact, this->m_szModuleName, "sid")); + conversation.fetch(); + + SEFilenameList fileList; + for (int i = 0; ppszFiles[i]; i++) + { + char* file = ::mir_u2a(ppszFiles[i]); + fileList.append(file); + } + + auto error = TRANSFER_OPEN_SUCCESS; + SEFilename errFile; MessageRef msgRef; + if ( !conversation->PostFiles(fileList, ::mir_u2a(szDescription), error, errFile, msgRef) || error) + { + // todo: despair + //this->SendBroadcast(hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)ccid, 0); + return 0; + } + + FileTransfer *ft = new FileTransfer(this); + if (msgRef->GetTransfers(ft->transfers)) + { + Sid::fetch(ft->transfers); + for (uint i = 0; i < ft->transfers.size(); i++) + { + auto transfer = ft->transfers[i]; + transfer.fetch(); + transfer->SetOnTransferCallback( + (CTransfer::OnTransfer)&CSkypeProto::OnTransferChanged, + this); + //this->transferList.append(transfer); + } + } + + //auto ft = new FileTransfer(this); + msgRef->GetPropGuid(ft->guid); + this->fileTransferList.insert(ft); + + return ft; + } + + return 0; +} int __cdecl CSkypeProto::SendMsg(HANDLE hContact, int flags, const char* msg) { diff --git a/protocols/Skype/src/skype_proto.h b/protocols/Skype/src/skype_proto.h index 18c18dfeb4..5e38e73c2a 100644 --- a/protocols/Skype/src/skype_proto.h +++ b/protocols/Skype/src/skype_proto.h @@ -115,6 +115,7 @@ const SettingItem setting[]={ {LPGENT("About"), "About", DBVT_WCHAR, LI_STRING} }; + struct HtmlEntity { const char *entity; @@ -179,6 +180,27 @@ struct PasswordChangeBoxParam } }; +struct FileTransfer +{ + CSkypeProto* ppro; + SEBinary guid; + CTransfer::Refs transfers; + //char *who; + //char *msg; + //char *ftoken; + //char *relay; + //HANDLE hContact; + //int cancel; + //char *url; + //HANDLE hWaitEvent; + //DWORD action; + //int y7; + ////YList *files; + //PROTOFILETRANSFERSTATUS pfts; + + FileTransfer(CSkypeProto* ppro) { this->ppro = ppro; } +}; + struct CSkypeProto : public PROTO_INTERFACE { public: @@ -273,8 +295,9 @@ protected: CSkype *skype; CAccount::Ref account; CContact::Refs contactList; +// CTransfer::Refs transferList; CContactGroup::Ref commonList; - CContactGroup::Ref authWaitList; + CContactGroup::Ref authWaitList; // account void OnAccountChanged(int prop); @@ -299,6 +322,14 @@ protected: void OnMessageSended(CConversation::Ref conversation, CMessage::Ref message); void OnMessageReceived(CConversation::Ref conversation, CMessage::Ref message); + // file transfer + LIST fileTransferList; + FileTransfer *FindTransfer(SEBinary guid); + FileTransfer *FindFileTransfer(CTransfer::Ref transfer); + + void OnFileReceived(CConversation::Ref conversation, CMessage::Ref message); + void OnTransferChanged(int prop, CTransfer::Ref transfer); + // chat static char* Groups[]; @@ -460,6 +491,11 @@ protected: const char* sid, const char* nick, const char* message = ""); + void RaiseFileReceivedEvent( + DWORD timestamp, + const char* sid, + const char* nick, + const char* message = ""); void RaiseAuthRequestEvent( DWORD timestamp, const char* sid, diff --git a/protocols/Skype/src/skype_subclassing.cpp b/protocols/Skype/src/skype_subclassing.cpp index 10bdecf9d5..2c24252fa7 100644 --- a/protocols/Skype/src/skype_subclassing.cpp +++ b/protocols/Skype/src/skype_subclassing.cpp @@ -44,6 +44,11 @@ CMessage* CSkype::newMessage(int oid) return new CMessage(oid, this); } +CTransfer* CSkype::newTransfer(int oid) +{ + return new CTransfer(oid, this); +} + CContactSearch* CSkype::newContactSearch(int oid) { return new CContactSearch(oid, this); @@ -479,4 +484,24 @@ void CConversation::SetOnMessageReceivedCallback(OnMessageReceived callback, CSk // CMessage -CMessage::CMessage(unsigned int oid, SERootObject* root) : Message(oid, root) { } \ No newline at end of file +CMessage::CMessage(unsigned int oid, SERootObject* root) : Message(oid, root) { } + +// CTransfer + +CTransfer::CTransfer(unsigned int oid, SERootObject* root) : Transfer(oid, root) +{ + this->proto = NULL; + this->transferCallback = NULL; +} + +void CTransfer::SetOnTransferCallback(OnTransfer callback, CSkypeProto* proto) +{ + this->proto = proto; + this->transferCallback = callback; +} + +void CTransfer::OnChange(int prop) +{ + if (this->proto) + (proto->*transferCallback)(prop, this->ref()); +} \ No newline at end of file diff --git a/protocols/Skype/src/skype_subclassing.h b/protocols/Skype/src/skype_subclassing.h index 694fce2c56..b16f7d7e66 100644 --- a/protocols/Skype/src/skype_subclassing.h +++ b/protocols/Skype/src/skype_subclassing.h @@ -12,13 +12,31 @@ class CSkype; class CMessage : public Message { public: - typedef DRef Ref; typedef DRefs Refs; CMessage(unsigned int oid, SERootObject* root); }; +class CTransfer : public Transfer +{ +public: + typedef void (CSkypeProto::* OnTransfer)(int prop, CTransfer::Ref transfer); + + typedef DRef Ref; + typedef DRefs Refs; + + CTransfer(unsigned int oid, SERootObject* p_root); + + void SetOnTransferCallback(OnTransfer callback, CSkypeProto* proto); + +private: + CSkypeProto* proto; + OnTransfer transferCallback; + + void OnChange(int prop); +}; + class CParticipant : public Participant { public: @@ -149,6 +167,7 @@ public: CParticipant* newParticipant(int oid); CContact* newContact(int oid); CMessage* newMessage(int oid); + CTransfer* newTransfer(int oid); CConversation::Refs inbox; diff --git a/protocols/Skype/src/skype_transfer.cpp b/protocols/Skype/src/skype_transfer.cpp new file mode 100644 index 0000000000..437d016b6d --- /dev/null +++ b/protocols/Skype/src/skype_transfer.cpp @@ -0,0 +1,29 @@ +#include "skype_proto.h" + +//LIST CSkypeProto::fileTransferList(1); + +FileTransfer *CSkypeProto::FindTransfer(SEBinary guid) +{ + for (int i = 0; i < this->fileTransferList.getCount(); i++) + { + if (this->fileTransferList[i]->guid == guid) + { + return this->fileTransferList[i]; + } + } + + return NULL; +} + +FileTransfer *CSkypeProto::FindFileTransfer(CTransfer::Ref transfer) +{ + for (int i = 0; i < this->fileTransferList.getCount(); i++) + { + if (this->fileTransferList[i]->transfers.contains(transfer)) + { + return this->fileTransferList[i]; + } + } + + return NULL; +} \ No newline at end of file diff --git a/protocols/Skype/src/skype_utils.cpp b/protocols/Skype/src/skype_utils.cpp index 7b66b00386..66e334fbdd 100644 --- a/protocols/Skype/src/skype_utils.cpp +++ b/protocols/Skype/src/skype_utils.cpp @@ -396,7 +396,7 @@ void CSkypeProto::HookEvent(const char* szEvent, SkypeEventFunc handler) int CSkypeProto::SendBroadcast(HANDLE hContact, int type, int result, HANDLE hProcess, LPARAM lParam) { - ACKDATA ack = { sizeof(ACKDATA) }; + /*ACKDATA ack = { sizeof(ACKDATA) }; ack.szModule = this->m_szModuleName; ack.hContact = hContact; ack.type = type; @@ -404,7 +404,8 @@ int CSkypeProto::SendBroadcast(HANDLE hContact, int type, int result, HANDLE hPr ack.hProcess = hProcess; ack.lParam = lParam; - return ::CallService(MS_PROTO_BROADCASTACK, 0, (LPARAM)&ack); + return ::CallService(MS_PROTO_BROADCASTACK, 0, (LPARAM)&ack);*/ + return ::ProtoBroadcastAck(this->m_szModuleName, hContact, type, result, hProcess, lParam); } DWORD CSkypeProto::SendBroadcastAsync(HANDLE hContact, int type, int hResult, HANDLE hProcess, LPARAM lParam, size_t paramSize) -- cgit v1.2.3