From 0c3fbeb0557c85cbe7c103053c869b6e3b42fab6 Mon Sep 17 00:00:00 2001 From: Sergey Bolhovskoy Date: Sat, 4 Oct 2014 12:59:00 +0000 Subject: VKontakte: Upload files support part 1 (photo) version bump git-svn-id: http://svn.miranda-ng.org/main/trunk@10683 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/VKontakte/src/misc.cpp | 10 ++ protocols/VKontakte/src/version.h | 2 +- protocols/VKontakte/src/vk.h | 6 +- protocols/VKontakte/src/vk_files.cpp | 259 ++++++++++++++++++++++++++++++ protocols/VKontakte/src/vk_proto.cpp | 41 +---- protocols/VKontakte/src/vk_proto.h | 24 +++ protocols/VKontakte/src/vk_search.cpp | 10 -- protocols/VKontakte/src/vk_thread.cpp | 4 +- protocols/VKontakte/vk_10.vcxproj | 1 + protocols/VKontakte/vk_10.vcxproj.filters | 3 + protocols/VKontakte/vk_12.vcxproj | 1 + protocols/VKontakte/vk_12.vcxproj.filters | 3 + 12 files changed, 313 insertions(+), 51 deletions(-) create mode 100644 protocols/VKontakte/src/vk_files.cpp diff --git a/protocols/VKontakte/src/misc.cpp b/protocols/VKontakte/src/misc.cpp index 2a3b930fa2..75e23daac8 100644 --- a/protocols/VKontakte/src/misc.cpp +++ b/protocols/VKontakte/src/misc.cpp @@ -479,4 +479,14 @@ void CVkProto::SetMirVer(MCONTACT hContact, int platform) if (bSetFlag) setTString(hContact, "MirVer", MirVer.GetBuffer()); +} + +bool tlstrstr(TCHAR* _s1, TCHAR* _s2) +{ + TCHAR s1[1024], s2[1024]; + mir_sntprintf(s1, SIZEOF(s1), _T("%s"), _s1); + mir_sntprintf(s2, SIZEOF(s2), _T("%s"), _s2); + CharLowerBuff(s1, SIZEOF(s1)); + CharLowerBuff(s2, SIZEOF(s2)); + return (_tcsstr(s1, s2) == NULL); } \ No newline at end of file diff --git a/protocols/VKontakte/src/version.h b/protocols/VKontakte/src/version.h index f7d72011c9..1acb8c28fb 100644 --- a/protocols/VKontakte/src/version.h +++ b/protocols/VKontakte/src/version.h @@ -1,7 +1,7 @@ #define __MAJOR_VERSION 0 #define __MINOR_VERSION 1 #define __RELEASE_NUM 0 -#define __BUILD_NUM 18 +#define __BUILD_NUM 19 #include diff --git a/protocols/VKontakte/src/vk.h b/protocols/VKontakte/src/vk.h index 1f7714961c..f85659968c 100644 --- a/protocols/VKontakte/src/vk.h +++ b/protocols/VKontakte/src/vk.h @@ -69,9 +69,7 @@ extern LIST vk_Instances; extern HINSTANCE hInst; LPCSTR findHeader(NETLIBHTTPREQUEST *hdr, LPCSTR szField); +bool tlstrstr(TCHAR* _s1, TCHAR* _s2); void InitIcons(void); -HANDLE GetIconHandle(int iCommand); - -void MyHtmlDecode(CMStringW &str); - +HANDLE GetIconHandle(int iCommand); \ No newline at end of file diff --git a/protocols/VKontakte/src/vk_files.cpp b/protocols/VKontakte/src/vk_files.cpp new file mode 100644 index 0000000000..804c612e8b --- /dev/null +++ b/protocols/VKontakte/src/vk_files.cpp @@ -0,0 +1,259 @@ +/* +Copyright (c) 2013-14 Miranda NG project (http://miranda-ng.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "stdafx.h" + +HANDLE CVkProto::FileAllow(MCONTACT hContact, HANDLE hTransfer, const PROTOCHAR *path) { return NULL; } +int CVkProto::FileCancel(MCONTACT hContact, HANDLE hTransfer) { return 1; } +int CVkProto::FileDeny(MCONTACT hContact, HANDLE hTransfer, const PROTOCHAR *reason) { return 1; } +int CVkProto::FileResume(HANDLE hTransfer, int *action, const PROTOCHAR **filename) { return 1; } +int CVkProto::RecvFile(MCONTACT hContact, PROTORECVFILET *) { return 1; } + +FileUploadParam::FileUploadParam(MCONTACT _hContact, const PROTOCHAR* _desc, PROTOCHAR** _files): +hContact(_hContact), filetype(typeInvalid), atr(NULL), fname(NULL) +{ + Desc = mir_tstrdup(_desc); + FileName = mir_tstrdup(_files[0]); +} + +FileUploadParam::~FileUploadParam() +{ + mir_free(Desc); + mir_free(FileName); + mir_free(atr); + mir_free(fname); +} + +FileUploadParam::VKFileType FileUploadParam::GetType() +{ + if (filetype != typeInvalid) + return filetype; + + TCHAR img[] = L"jpg jpeg png bmp"; + TCHAR audio[] = L"mp3"; + + TCHAR DRIVE[3], DIR[256], FNAME[256], EXT[256]; + _tsplitpath(FileName, DRIVE, DIR, FNAME, EXT); + + CMStringA fn(mir_utf8encodeT(FNAME)); + fn.AppendChar('.'); + fn.AppendFormat("%s", mir_utf8encodeT(EXT)); + + fname = mir_strdup(fn.GetBuffer()); + + if (tlstrstr(img, EXT)){ + filetype = FileUploadParam::typeImg; + atr = mir_strdup("photo"); + } + else if (tlstrstr(audio, EXT)){ + filetype = FileUploadParam::typeAudio; + atr = mir_strdup("file"); + } + else{ + filetype = FileUploadParam::typeDoc; + atr = mir_strdup("file"); + } + + return filetype; +} + + +HANDLE CVkProto::SendFile(MCONTACT hContact, const PROTOCHAR *desc, PROTOCHAR **files) +{ + debugLogA("CVkProto::SendFile"); + FileUploadParam *fup = new FileUploadParam(hContact, desc, files); + ForkThread(&CVkProto::SendFileThread, (void *)fup); + return (HANDLE)fup; +} + +void CVkProto::SendFileFiled(FileUploadParam *fup, TCHAR *reason) +{ + debugLog(L"CVkProto::SendFileFiled <%s>", reason); + ProtoBroadcastAck(fup->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)fup, 0); + delete fup; +} + +void CVkProto::SendFileThread(void *p) +{ + FileUploadParam *fup = (FileUploadParam *)p; + debugLogA("CVkProto::SendFileThread"); + if (!fup->IsAccess()){ + SendFileFiled(fup, L"FileIsNotAccess"); + return; + } + AsyncHttpRequest *pReq; + switch (fup->GetType()){ + case FileUploadParam::typeImg: + pReq = new AsyncHttpRequest(this, REQUEST_GET, "/method/photos.getMessagesUploadServer.json", true, &CVkProto::OnReciveUploadServer) + << VER_API; + pReq->pUserInfo = p; + Push(pReq); + break; + case FileUploadParam::typeAudio: + // Audio + SendFileFiled(fup, L"FileTypeIsNotSupported"); + break; + case FileUploadParam::typeDoc: + // Doc + SendFileFiled(fup, L"FileTypeIsNotSupported"); + break; + default: + SendFileFiled(fup); + } +} + +void CVkProto::OnReciveUploadServer(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) +{ + FileUploadParam *fup = (FileUploadParam *)pReq->pUserInfo; + + debugLogA("CVkProto::OnReciveUploadServer %d", reply->resultCode); + if (reply->resultCode != 200){ + SendFileFiled(fup, L"NotUploadServer"); + return; + } + + JSONROOT pRoot; + JSONNODE *pResponse = CheckJsonResponse(pReq, reply, pRoot); + if (pResponse == NULL){ + SendFileFiled(fup); + return; + } + + CMStringA uri = json_as_string(json_get(pResponse, "upload_url")); + if (uri.IsEmpty()){ + SendFileFiled(fup); + return; + } + + FILE *pFile = _tfopen(fup->FileName, _T("rb")); + if (pFile == NULL){ + SendFileFiled(fup, L"ErrorOpenFile"); + return; + } + + fseek(pFile, 0, SEEK_END); + size_t szFileLen = ftell(pFile); //FileSize + fseek(pFile, 0, SEEK_SET); + + AsyncHttpRequest *pUploadReq = new AsyncHttpRequest(this, REQUEST_POST, uri.GetBuffer(), false, &CVkProto::OnReciveUpload); + pUploadReq->m_bApiReq = false; + pUploadReq->m_szParam = ""; + CMStringA boundary, header; + CMStringA NamePart = fup->atrName(); + CMStringA FNamePart = fup->fileName(); + srand(time(NULL)); + + int iboundary = rand(); + boundary.AppendFormat("Miranda%dNG%d", iboundary, time(NULL)); + header.AppendFormat("multipart/form-data; boundary=%s", boundary.GetBuffer()); + pUploadReq->AddHeader("Content-Type", header.GetBuffer()); + + CMStringA DataBegin = "--"; + DataBegin += boundary; + DataBegin += "\r\n"; + DataBegin += "Content-Disposition: form-data; name=\""; + DataBegin += NamePart; + DataBegin += "\"; filename=\""; + DataBegin += FNamePart; + DataBegin += "\";\r\n\r\n"; + + CMStringA DataEnd = "\r\n--"; + DataEnd += boundary; + DataEnd += "--\r\n"; + + size_t dataLength = szFileLen + DataBegin.GetLength() + DataEnd.GetLength(); + + char* pData = (char *)mir_alloc(dataLength); + memcpy(pData, (void *)DataBegin.GetBuffer(), DataBegin.GetLength()); + pUploadReq->pData = pData; + pData += DataBegin.GetLength(); + fread(pData, 1, szFileLen, pFile); + pData += szFileLen; + memcpy(pData, (void *)DataEnd.GetBuffer(), DataEnd.GetLength()); + pUploadReq-> dataLength = dataLength; + pUploadReq->pUserInfo = pReq->pUserInfo; + debugLogA("CVkProto::OnReciveUploadServer \n<%d>", dataLength); + Push(pUploadReq); + fclose(pFile); +} + +void CVkProto::OnReciveUpload(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) +{ + FileUploadParam *fup = (FileUploadParam *)pReq->pUserInfo; + + debugLogA("CVkProto::OnReciveUploadServer %d", reply->resultCode); + if (reply->resultCode != 200){ + SendFileFiled(fup); + return; + } + + JSONROOT pRoot; + JSONNODE *pResponse = CheckJsonResponse(pReq, reply, pRoot); + + CMString server = json_as_string(json_get(pRoot, "server")); + CMString photo = json_as_string(json_get(pRoot, "photo")); + CMString hash = json_as_string(json_get(pRoot, "hash")); + + AsyncHttpRequest *pUploadReq = new AsyncHttpRequest(this, REQUEST_GET, "/method/photos.saveMessagesPhoto.json", true, &CVkProto::OnReciveUploadFile) + << TCHAR_PARAM("server", server) + << TCHAR_PARAM("photo", photo) + << TCHAR_PARAM("hash", hash) + << VER_API; + pUploadReq->pUserInfo = pReq->pUserInfo; + Push(pUploadReq); +} + +void CVkProto::OnReciveUploadFile(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) +{ + FileUploadParam *fup = (FileUploadParam *)pReq->pUserInfo; + + debugLogA("CVkProto::OnReciveUploadPhoto %d", reply->resultCode); + if (reply->resultCode != 200){ + SendFileFiled(fup); + return; + } + + JSONROOT pRoot; + JSONNODE *pResponse = CheckJsonResponse(pReq, reply, pRoot); + if (pResponse == NULL){ + SendFileFiled(fup); + return; + } + + int id = json_as_int(json_get(json_at(pResponse,0), "id")); + int owner_id = json_as_int(json_get(json_at(pResponse, 0), "owner_id")); + CMString Attachment; + Attachment.AppendFormat(L"photo%d_%d", owner_id, id); + + debugLog(L"CVkProto::OnReciveUploadPhoto Att %s", Attachment.GetBuffer()); + + LONG userID = getDword(fup->hContact, "ID", -1); + if (userID == -1){ + SendFileFiled(fup); + return; + } + + AsyncHttpRequest *pMsgReq = new AsyncHttpRequest(this, REQUEST_POST, "/method/messages.send.json", true, &CVkProto::OnSendMessage) + << INT_PARAM("user_id", userID) + << TCHAR_PARAM("message", fup->Desc) + << TCHAR_PARAM("attachment", Attachment.GetBuffer()) + << VER_API; + pMsgReq->AddHeader("Content-Type", "application/x-www-form-urlencoded"); + pMsgReq->pUserInfo = new CVkSendMsgParam(fup->hContact, -1, (int)pReq->pUserInfo); + + Push(pMsgReq); +} \ No newline at end of file diff --git a/protocols/VKontakte/src/vk_proto.cpp b/protocols/VKontakte/src/vk_proto.cpp index 2e437d290e..ab93108d33 100644 --- a/protocols/VKontakte/src/vk_proto.cpp +++ b/protocols/VKontakte/src/vk_proto.cpp @@ -281,7 +281,7 @@ DWORD_PTR CVkProto::GetCaps(int type, MCONTACT hContact) { switch(type) { case PFLAGNUM_1: - return PF1_IM | PF1_CHAT | PF1_SERVERCLIST | PF1_AUTHREQ | PF1_BASICSEARCH | PF1_SEARCHBYNAME | PF1_SEARCHBYEMAIL | PF1_MODEMSG; + return PF1_IM | PF1_CHAT | PF1_SERVERCLIST | PF1_AUTHREQ | PF1_BASICSEARCH | PF1_SEARCHBYNAME | PF1_SEARCHBYEMAIL | PF1_MODEMSG | PF1_FILESEND | PF1_FILERESUME; case PFLAGNUM_2: return PF2_ONLINE | PF2_INVISIBLE | PF2_ONTHEPHONE | PF2_IDLE; @@ -290,7 +290,7 @@ DWORD_PTR CVkProto::GetCaps(int type, MCONTACT hContact) return PF2_ONLINE; case PFLAGNUM_4: - return PF4_IMSENDUTF | PF4_AVATARS | PF4_SUPPORTTYPING | PF4_NOAUTHDENYREASON | PF4_IMSENDOFFLINE; + return PF4_IMSENDUTF | PF4_AVATARS | PF4_SUPPORTTYPING | PF4_NOAUTHDENYREASON | PF4_IMSENDOFFLINE | PF4_OFFLINEFILES; case PFLAGNUM_5: return PF2_ONTHEPHONE; @@ -383,7 +383,12 @@ void CVkProto::OnSendMessage(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) } } - if (m_bServerDelivery) + if (param->iMsgID == -1){ + FileUploadParam *fup = (FileUploadParam *)param->iCount; + ProtoBroadcastAck(fup->hContact, ACKTYPE_FILE, iResult, (HANDLE)fup, 0); + delete fup; + } + else if (m_bServerDelivery) ProtoBroadcastAck(param->hContact, ACKTYPE_MESSAGE, iResult, HANDLE(param->iMsgID), 0); delete param; } @@ -580,26 +585,6 @@ int CVkProto::AuthRecv(MCONTACT hContact,PROTORECVEVENT *) return 1; } -HANDLE CVkProto::FileAllow(MCONTACT hContact,HANDLE hTransfer,const PROTOCHAR *path) -{ - return NULL; -} - -int CVkProto::FileCancel(MCONTACT hContact,HANDLE hTransfer) -{ - return 1; -} - -int CVkProto::FileDeny(MCONTACT hContact,HANDLE hTransfer,const PROTOCHAR *reason) -{ - return 1; -} - -int CVkProto::FileResume(HANDLE hTransfer,int *action,const PROTOCHAR **filename) -{ - return 1; -} - int CVkProto::GetInfo(MCONTACT hContact, int infoType) { LONG userID = getDword(hContact, "ID", -1); @@ -624,11 +609,6 @@ int CVkProto::RecvContacts(MCONTACT hContact,PROTORECVEVENT *) return 1; } -int CVkProto::RecvFile(MCONTACT hContact,PROTORECVFILET *) -{ - return 1; -} - int CVkProto::RecvUrl(MCONTACT hContact,PROTORECVEVENT *) { return 1; @@ -639,11 +619,6 @@ int CVkProto::SendContacts(MCONTACT hContact, int flags, int nContacts, MCONTACT return 1; } -HANDLE CVkProto::SendFile(MCONTACT hContact,const PROTOCHAR *desc, PROTOCHAR **files) -{ - return NULL; -} - int CVkProto::SendUrl(MCONTACT hContact,int flags,const char *url) { return 1; diff --git a/protocols/VKontakte/src/vk_proto.h b/protocols/VKontakte/src/vk_proto.h index 03e18048e3..0298598752 100644 --- a/protocols/VKontakte/src/vk_proto.h +++ b/protocols/VKontakte/src/vk_proto.h @@ -131,6 +131,23 @@ struct CVkChatInfo : public MZeroedObject CVkChatUser* GetUserById(LPCTSTR); }; +struct FileUploadParam { + enum VKFileType {typeInvalid, typeImg, typeAudio, typeDoc, typeNotSupported}; + TCHAR* FileName; + TCHAR* Desc; + char* atr; + char* fname; + MCONTACT hContact; + VKFileType filetype; + + FileUploadParam(MCONTACT _hContact, const PROTOCHAR* _desc, PROTOCHAR** _files); + ~FileUploadParam(); + VKFileType GetType(); + __forceinline bool FileUploadParam::IsAccess() {return ::_taccess(FileName, 0)==0; } + __forceinline char* FileUploadParam::atrName() { return atr; } + __forceinline char* FileUploadParam::fileName() { return fname; } +}; + struct CVkProto : public PROTO { CVkProto(const char*, const TCHAR*); @@ -226,6 +243,13 @@ struct CVkProto : public PROTO void OnSearch(NETLIBHTTPREQUEST*, AsyncHttpRequest*); void OnSearchByMail(NETLIBHTTPREQUEST *, AsyncHttpRequest *); + //==== Files Upload ================================================================== + + void __cdecl SendFileThread(void *p); + void SendFileFiled(FileUploadParam *fup, TCHAR* reason=NULL); + void OnReciveUploadServer(NETLIBHTTPREQUEST*, AsyncHttpRequest*); + void OnReciveUpload(NETLIBHTTPREQUEST*, AsyncHttpRequest*); + void OnReciveUploadFile(NETLIBHTTPREQUEST*, AsyncHttpRequest*); //==== Misc ========================================================================== TCHAR* GetUserStoredPassword(void); diff --git a/protocols/VKontakte/src/vk_search.cpp b/protocols/VKontakte/src/vk_search.cpp index 5763f6d7ca..be75b5e3ff 100644 --- a/protocols/VKontakte/src/vk_search.cpp +++ b/protocols/VKontakte/src/vk_search.cpp @@ -18,16 +18,6 @@ along with this program. If not, see . #include "stdafx.h" -static bool tlstrstr(TCHAR* _s1, TCHAR* _s2) -{ - TCHAR s1[200], s2[200]; - mir_sntprintf(s1, SIZEOF(s1), _T("%s"), _s1); - mir_sntprintf(s2, SIZEOF(s2), _T("%s"), _s2); - CharLowerBuff(s1, SIZEOF(s1)); - CharLowerBuff(s2, SIZEOF(s2)); - return (_tcsstr(s1, s2)==NULL); -} - void CVkProto::SearchBasicThread(void* id) { debugLogA("CVkProto::OnSearchBasicThread"); diff --git a/protocols/VKontakte/src/vk_thread.cpp b/protocols/VKontakte/src/vk_thread.cpp index 064bd31d37..ffb9e438a7 100644 --- a/protocols/VKontakte/src/vk_thread.cpp +++ b/protocols/VKontakte/src/vk_thread.cpp @@ -252,9 +252,7 @@ MCONTACT CVkProto::SetContactInfo(JSONNODE* pItem, bool flag) hContact = NULL; else if ((hContact = FindUser(userid, flag)) == NULL) return -1; - - debugLogA("CVkProto::SetContactInfo %d %d", userid, hContact); - + CMString tszNick, tszValue; int iValue; diff --git a/protocols/VKontakte/vk_10.vcxproj b/protocols/VKontakte/vk_10.vcxproj index 8d249f393f..4d75bd6b9d 100644 --- a/protocols/VKontakte/vk_10.vcxproj +++ b/protocols/VKontakte/vk_10.vcxproj @@ -183,6 +183,7 @@ + diff --git a/protocols/VKontakte/vk_10.vcxproj.filters b/protocols/VKontakte/vk_10.vcxproj.filters index 633997a52d..218a220874 100644 --- a/protocols/VKontakte/vk_10.vcxproj.filters +++ b/protocols/VKontakte/vk_10.vcxproj.filters @@ -48,6 +48,9 @@ Source Files + + Source Files + diff --git a/protocols/VKontakte/vk_12.vcxproj b/protocols/VKontakte/vk_12.vcxproj index 460d21b6db..d3cc9a4936 100644 --- a/protocols/VKontakte/vk_12.vcxproj +++ b/protocols/VKontakte/vk_12.vcxproj @@ -186,6 +186,7 @@ + diff --git a/protocols/VKontakte/vk_12.vcxproj.filters b/protocols/VKontakte/vk_12.vcxproj.filters index 450e52b623..823b6f6102 100644 --- a/protocols/VKontakte/vk_12.vcxproj.filters +++ b/protocols/VKontakte/vk_12.vcxproj.filters @@ -48,6 +48,9 @@ Source Files + + Source Files + -- cgit v1.2.3