summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Bolhovskoy <elzorfox@ya.ru>2014-10-04 12:59:00 +0000
committerSergey Bolhovskoy <elzorfox@ya.ru>2014-10-04 12:59:00 +0000
commit0c3fbeb0557c85cbe7c103053c869b6e3b42fab6 (patch)
treeae1193794d135f2a6e08a2a36c6ec741a156ee08
parent73c4eeff66a56dc1df1c19dd1841c77e6458f4a7 (diff)
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
-rw-r--r--protocols/VKontakte/src/misc.cpp10
-rw-r--r--protocols/VKontakte/src/version.h2
-rw-r--r--protocols/VKontakte/src/vk.h6
-rw-r--r--protocols/VKontakte/src/vk_files.cpp259
-rw-r--r--protocols/VKontakte/src/vk_proto.cpp41
-rw-r--r--protocols/VKontakte/src/vk_proto.h24
-rw-r--r--protocols/VKontakte/src/vk_search.cpp10
-rw-r--r--protocols/VKontakte/src/vk_thread.cpp4
-rw-r--r--protocols/VKontakte/vk_10.vcxproj1
-rw-r--r--protocols/VKontakte/vk_10.vcxproj.filters3
-rw-r--r--protocols/VKontakte/vk_12.vcxproj1
-rw-r--r--protocols/VKontakte/vk_12.vcxproj.filters3
12 files changed, 313 insertions, 51 deletions
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 <stdver.h>
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<CVkProto> 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 <http://www.gnu.org/licenses/>.
+*/
+
+#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>
{
CVkProto(const char*, const TCHAR*);
@@ -226,6 +243,13 @@ struct CVkProto : public PROTO<CVkProto>
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 <http://www.gnu.org/licenses/>.
#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 @@
<ClCompile Include="src\vk_avatars.cpp" />
<ClCompile Include="src\vk_captcha.cpp" />
<ClCompile Include="src\vk_chats.cpp" />
+ <ClCompile Include="src\vk_files.cpp" />
<ClCompile Include="src\vk_options.cpp" />
<ClCompile Include="src\vk_proto.cpp" />
<ClCompile Include="src\vk_queue.cpp" />
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 @@
<ClCompile Include="src\vk_search.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="src\vk_files.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\version.h">
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 @@
<ClCompile Include="src\vk_avatars.cpp" />
<ClCompile Include="src\vk_captcha.cpp" />
<ClCompile Include="src\vk_chats.cpp" />
+ <ClCompile Include="src\vk_files.cpp" />
<ClCompile Include="src\vk_options.cpp" />
<ClCompile Include="src\vk_proto.cpp" />
<ClCompile Include="src\vk_queue.cpp" />
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 @@
<ClCompile Include="src\vk_search.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="src\vk_files.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\version.h">