diff options
author | Tobias Weimer <wishmaster51@googlemail.com> | 2015-01-09 19:38:12 +0000 |
---|---|---|
committer | Tobias Weimer <wishmaster51@googlemail.com> | 2015-01-09 19:38:12 +0000 |
commit | 8e2a004d967dd3faea172fbed655b0b45c826d54 (patch) | |
tree | d9927aa8060439235584bd0b4bbd27df86c577fe /protocols/SkypeClassic/src/filexfer.cpp | |
parent | 7feae2a81f7c4784805329e1d1c1682e689a4008 (diff) |
SkypeClassic:
Upmerge with leecher's repo:
-Implemented Filetransfer extensions for receiving files and avatars via SkypeProxy (sending via SkypeProxy not working yet).
-Added option to disable the check for SENT messages as newer Skype versions don't send this notification anymore.
-Various little code fixes.
Other changes:
- Fixed memory leak
- Fixed crash in x64 builds
- Translation fixes
git-svn-id: http://svn.miranda-ng.org/main/trunk@11805 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'protocols/SkypeClassic/src/filexfer.cpp')
-rw-r--r-- | protocols/SkypeClassic/src/filexfer.cpp | 400 |
1 files changed, 400 insertions, 0 deletions
diff --git a/protocols/SkypeClassic/src/filexfer.cpp b/protocols/SkypeClassic/src/filexfer.cpp new file mode 100644 index 0000000000..e27afa9f42 --- /dev/null +++ b/protocols/SkypeClassic/src/filexfer.cpp @@ -0,0 +1,400 @@ +#include "skype.h"
+#include "skypeapi.h"
+#include "utf8.h"
+#include "msglist.h"
+#include "pthread.h"
+
+extern char g_szProtoName[];
+
+/* Services */
+INT_PTR SkypeRecvFile(WPARAM, LPARAM lParam)
+{
+ DBEVENTINFO dbei = { 0 };
+ CCSDATA *ccs = (CCSDATA *)lParam;
+ PROTORECVEVENT *pre = (PROTORECVEVENT *)ccs->lParam;
+ size_t cbFilename, nFiles;
+ INT_PTR ret = 0;
+
+ db_unset(ccs->hContact, "CList", "Hidden");
+ dbei.cbSize = sizeof(dbei);
+ dbei.szModule = SKYPE_PROTONAME;
+ dbei.timestamp = pre->timestamp;
+ if (pre->flags & PREF_CREATEREAD) dbei.flags |= DBEF_READ;
+ if (pre->flags & PREF_UTF) dbei.flags |= DBEF_UTF;
+ dbei.eventType = EVENTTYPE_FILE;
+ dbei.cbBlob=sizeof(DWORD);
+ if (pre->flags & PREF_UNICODE) {
+ for(nFiles=0;cbFilename=wcslen((wchar_t*)&pre->szMessage[dbei.cbBlob])*sizeof(wchar_t);nFiles++)
+ dbei.cbBlob+=cbFilename+sizeof(wchar_t);
+ dbei.cbBlob+=sizeof(wchar_t);
+ } else {
+ for(nFiles=0;cbFilename=strlen(&pre->szMessage[dbei.cbBlob]);nFiles++)
+ dbei.cbBlob+=cbFilename+1;
+ dbei.cbBlob++;
+ }
+ dbei.pBlob = (PBYTE)pre->szMessage;
+
+ TYP_MSGLENTRY *pEntry = MsgList_Add(pre->lParam, db_event_add(ccs->hContact, &dbei));
+ if (pEntry) {
+ DWORD cbSize = sizeof(PROTOFILETRANSFERSTATUS);
+ /* Allocate basic entry and fill some stuff we already know */
+ if (pEntry->pfts = calloc(1, cbSize)) {
+ PROTOFILETRANSFERSTATUS *pfts = (PROTOFILETRANSFERSTATUS*)pEntry->pfts;
+ size_t iOffs=sizeof(DWORD);
+
+ pfts->cbSize = cbSize;
+ pfts->hContact = ccs->hContact;
+ pfts->totalFiles = nFiles;
+ if (pfts->pszFiles=(char**)calloc(nFiles+1, sizeof(char*))) {
+ if (pre->flags & PREF_UNICODE) {
+ wchar_t *pFN;
+ for (size_t i=0; cbFilename=wcslen(pFN=(wchar_t*)&pre->szMessage[iOffs])*sizeof(wchar_t); i++) {
+ pfts->pszFiles[i]=(char*)wcsdup(pFN);
+ iOffs+=cbFilename+sizeof(wchar_t);
+ }
+ } else {
+ char *pFN;
+ for(size_t i=0;cbFilename=strlen(pFN=&pre->szMessage[iOffs]);i++) {
+ pfts->pszFiles[i]=strdup(pFN);
+ iOffs+=cbFilename+1;
+ }
+ if (pre->flags & PREF_UTF) pfts->flags |= PFTS_UTF;
+ }
+ ret = pre->lParam;
+ }
+ }
+ }
+ return ret;
+}
+
+INT_PTR SkypeSendFile(WPARAM, LPARAM lParam)
+{
+ CCSDATA *ccs = (CCSDATA *)lParam;
+ DBVARIANT dbv;
+ char *mymsgcmd, *utfmsg = NULL, *pszFile=NULL;
+ TCHAR **files = (TCHAR**)ccs->lParam;
+ int nFiles, iLen = 0, ret=0;
+ BYTE bIsChatroom = 0 != db_get_b(ccs->hContact, SKYPE_PROTONAME, "ChatRoom", 0);
+
+ if (bIsChatroom) {
+ if (db_get_s(ccs->hContact, SKYPE_PROTONAME, "ChatRoomID", &dbv))
+ return 0;
+ mymsgcmd = "CHATFILE";
+ } else {
+ if (db_get_s(ccs->hContact, SKYPE_PROTONAME, SKYPE_NAME, &dbv))
+ return 0;
+ mymsgcmd = "FILE";
+ }
+ for (nFiles=0; files[nFiles]; nFiles++) {
+ utfmsg=(char*)make_utf8_string(files[nFiles]);
+ iLen+=strlen(utfmsg)+3;
+ if (pszFile=pszFile?(char*)realloc(pszFile, iLen):(char*)calloc(1,iLen)) {
+ if (nFiles>0) strcat(pszFile, ",");
+ strcat(pszFile, "\"");
+ strcat(pszFile, utfmsg);
+ strcat(pszFile, "\"");
+ }
+ free(utfmsg);
+ }
+ if (pszFile) {
+ if (SkypeSend("%s %s %s", mymsgcmd, dbv.pszVal, pszFile) == 0) {
+ /* No chatmessage IDs available for filetransfers, there is no possibility
+ * in SkypeKit to check if incoming filetransfer SENT message belongs to
+ * the last file sent :( */
+ char *str = SkypeRcvTime("CHATFILE", SkypeTime(NULL), INFINITE);
+ if (str) {
+ if (strncmp(str, "ERROR", 5)) {
+ char *pTok=strtok(str+9, " ");
+
+ if (pTok) {
+ ret=strtoul(pTok, NULL, 10);
+ TYP_MSGLENTRY *pEntry = MsgList_Add(ret, INVALID_HANDLE_VALUE);
+ if (pEntry) {
+ DWORD cbSize = sizeof(PROTOFILETRANSFERSTATUS);
+ /* Allocate basic entry and fill some stuff we already know */
+ if (pEntry->pfts = calloc(1, cbSize)) {
+ PROTOFILETRANSFERSTATUS *pfts = (PROTOFILETRANSFERSTATUS*)pEntry->pfts;
+
+ pfts->cbSize = cbSize;
+ pfts->hContact = ccs->hContact;
+ pfts->totalFiles = nFiles;
+ pfts->flags = PFTS_SENDING;
+ if (pfts->pszFiles=(char**)calloc(nFiles+1, sizeof(char*))) {
+ for (int i=0; i<nFiles; i++)
+ ((TCHAR**)pfts->pszFiles)[i]=_tcsdup(files[i]);
+ }
+ }
+
+ }
+ }
+ }
+ free(str);
+ }
+ }
+ free(pszFile);
+ }
+ db_free(&dbv);
+ return ret;
+}
+
+INT_PTR SkypeFileAllow(WPARAM, LPARAM lParam)
+{
+ CCSDATA *ccs = (CCSDATA *)lParam;
+ if (!ccs || !ccs->lParam || !ccs->wParam)
+ return 0;
+
+ TYP_MSGLENTRY *pEntry = MsgList_FindMessage(ccs->wParam);
+ if(!pEntry)
+ return 0;
+
+ char *pszMsgNum, szMsgNum[16];
+ sprintf(szMsgNum, "%d", ccs->wParam);
+ char *pszXferIDs = SkypeGetErr("CHATMESSAGE", szMsgNum, "FILETRANSFERS");
+ if (!pszXferIDs)
+ return 0;
+
+ INT_PTR ret = 0;
+ char *pszDir = (char*)make_utf8_string((wchar_t*)ccs->lParam);
+ if (pszDir) {
+ for (pszMsgNum = strtok(pszXferIDs, ", "); pszMsgNum; pszMsgNum = strtok(NULL, ", ")) {
+ if (SkypeSend("ALTER FILETRANSFER %s ACCEPT %s", pszMsgNum, pszDir)!=-1) {
+ char *ptr = SkypeRcv("ALTER FILETRANSFER ACCEPT", 2000);
+ if (ptr) {
+ if (strncmp(ptr, "ERROR", 5))
+ ret = ccs->wParam;
+ free(ptr);
+ }
+ }
+ }
+
+ /* Now we know the save directory in pfts */
+ PROTOFILETRANSFERSTATUS *pfts = (PROTOFILETRANSFERSTATUS*)pEntry->pfts;
+ pfts->szWorkingDir = pszDir;
+ }
+ free(pszXferIDs);
+ return ret;
+}
+
+INT_PTR SkypeFileCancel(WPARAM, LPARAM lParam)
+{
+ CCSDATA *ccs = (CCSDATA *)lParam;
+ if (!ccs || !ccs->wParam)
+ return 0;
+
+ char *pszMsgNum, szMsgNum[16], *ptr;
+ sprintf(szMsgNum, "%d", ccs->wParam);
+ char *pszXferIDs = SkypeGetErr("CHATMESSAGE", szMsgNum, "FILETRANSFERS");
+ if (!pszXferIDs)
+ return 0;
+ INT_PTR ret = 1;
+ for (pszMsgNum = strtok(pszXferIDs, ", "); pszMsgNum; pszMsgNum = strtok(NULL, ", ")) {
+ if (SkypeSend ("ALTER FILETRANSFER %s CANCEL", pszMsgNum)!=-1) {
+ if (ptr=SkypeRcv("ALTER FILETRANSFER CANCEL", 2000)) {
+ if (strncmp(ptr, "ERROR", 5))
+ ret=0;
+ free(ptr);
+ }
+ }
+ }
+ free(pszXferIDs);
+ return ret;
+}
+
+void FXFreePFTS(void *Ppfts)
+{
+ PROTOFILETRANSFERSTATUS *pfts = (PROTOFILETRANSFERSTATUS*)Ppfts;
+
+ if (pfts->pszFiles)
+ {
+ for (int i=0; i<pfts->totalFiles; i++)
+ free(pfts->pszFiles[i]);
+ free(pfts->pszFiles);
+ free(pfts->szWorkingDir);
+ }
+ free(pfts);
+}
+
+BOOL FXHandleRecv(PROTORECVEVENT *pre, MCONTACT hContact)
+{
+ // Our custom Skypekit FILETRANSFER extension
+ size_t cbMsg = sizeof(DWORD), cbNewSize;
+
+ char szMsgNum[16];
+ sprintf (szMsgNum, "%d", pre->lParam);
+ char *pszXferIDs = SkypeGetErr("CHATMESSAGE", szMsgNum, "FILETRANSFERS");
+ if (!pszXferIDs)
+ return FALSE;
+ for (char *pszMsgNum = strtok(pszXferIDs, ", "); pszMsgNum; pszMsgNum = strtok(NULL, ", "))
+ {
+ char *pszStatus = SkypeGetErrID("FILETRANSFER", pszMsgNum, "STATUS");
+ if (pszStatus)
+ {
+ if (!strcmp(pszStatus, "NEW") || !strcmp(pszStatus, "PLACEHOLDER"))
+ {
+ char *pszType = SkypeGetErr("FILETRANSFER", pszMsgNum, "TYPE");
+ if (pszType)
+ {
+ if (!strcmp(pszType, "INCOMING"))
+ {
+ char *pszFN = SkypeGetErr("FILETRANSFER", pszMsgNum, "FILENAME");
+ if (pszFN)
+ {
+ cbNewSize = cbMsg+strlen(pszFN)+2;
+ if ((pre->szMessage = (char*)realloc(pre->szMessage, cbNewSize)))
+ {
+ memcpy(pre->szMessage+cbMsg, pszFN, cbNewSize-cbMsg-1);
+ cbMsg=cbNewSize-1;
+ } else pszMsgNum=NULL;
+ pre->flags |= PREF_UTF;
+ free(pszFN);
+ }
+ }
+ free (pszType);
+ }
+ }
+ free(pszStatus);
+ }
+ }
+ free(pszXferIDs);
+ if (pre->szMessage)
+ {
+ CCSDATA ccs = {0};
+
+ *((TCHAR*)&pre->szMessage[cbMsg])=0;
+ *((DWORD*)pre->szMessage)=pre->lParam;
+ ccs.szProtoService = PSR_FILE;
+ ccs.hContact = hContact;
+ ccs.wParam = 0;
+ ccs.lParam = (LPARAM)pre;
+ CallServiceSync(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs);
+ free(pre->szMessage);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+typedef struct {
+ BOOL bStatus;
+ char szNum[16];
+ char szArg[32];
+} ft_args;
+
+void FXHandleMessageThread(ft_args *pargs)
+{
+ char *pszChat = SkypeGetErr("FILETRANSFER", pargs->szNum, "CHATMESSAGE");
+ if (!pszChat) {
+ free(pargs);
+ return;
+ }
+
+ DWORD dwChat = strtoul(pszChat, NULL, 10);
+ TYP_MSGLENTRY *pEntry = MsgList_FindMessage(dwChat);
+ if(!pEntry) {
+ free(pargs);
+ free(pszChat);
+ return;
+ }
+
+ MCONTACT hContact = ((PROTOFILETRANSFERSTATUS*)pEntry->pfts)->hContact;
+ if(!hContact) {
+ free(pargs);
+ free(pszChat);
+ return;
+ }
+
+ if (pargs->bStatus) {
+ if (!strcmp(pargs->szArg, "CONNECTING"))
+ ProtoBroadcastAck(SKYPE_PROTONAME, hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, (HANDLE)dwChat, 0);
+ else if (!strncmp(pargs->szArg, "TRANSFERRING", 12))
+ ProtoBroadcastAck(SKYPE_PROTONAME, hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, (HANDLE)dwChat, 0);
+ else if (!strcmp(pargs->szArg, "FAILED"))
+ ProtoBroadcastAck(SKYPE_PROTONAME, hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)dwChat, 0);
+ else if (!strcmp(pargs->szArg, "CANCELLED"))
+ ProtoBroadcastAck(SKYPE_PROTONAME, hContact, ACKTYPE_FILE, ACKRESULT_DENIED, (HANDLE)dwChat, 0);
+ else if (!strcmp(pargs->szArg, "COMPLETED")) {
+ // Check if all transfers from this message are completed.
+ char *pszMsgNum, *pszStatus;
+ BOOL bAllComplete=TRUE;
+ char *pszXferIDs = SkypeGetErr("CHATMESSAGE", pszChat, "FILETRANSFERS");
+ if (pszXferIDs) {
+ for (pszMsgNum = strtok(pszXferIDs, ", "); pszMsgNum; pszMsgNum = strtok(NULL, ", ")) {
+ if (pszStatus=SkypeGetErrID("FILETRANSFER", pszMsgNum, "STATUS")) {
+ if (strcmp(pszStatus, "COMPLETED")) bAllComplete=FALSE;
+ free(pszStatus);
+ if (!bAllComplete) break;
+ }
+ }
+ free(pszXferIDs);
+ if (bAllComplete) {
+ ProtoBroadcastAck(SKYPE_PROTONAME, hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, (HANDLE)dwChat, 0);
+ // We could free pEntry at this point, but Garbage Collector will take care of it anyway
+ }
+ }
+ }
+ } else {
+ // BYTESTRANSFERRED
+ PROTOFILETRANSFERSTATUS pfts={0};
+ char *pszMsgNum;
+ int i;
+
+ // This always needs some fetching to fill PFTS :/
+ char *pszXferIDs = SkypeGetErr("CHATMESSAGE", pszChat, "FILETRANSFERS");
+ if (pszXferIDs) {
+ for (pszMsgNum = strtok(pszXferIDs, ", "),i=0; pszMsgNum; pszMsgNum = strtok(NULL, ", "),i++) {
+ DWORD dwTransferred;
+ BOOL bIsCurFil = strcmp(pargs->szNum,pszMsgNum)==0;
+
+ if (bIsCurFil)
+ pfts.currentFileNumber = i;
+ char *pszcbFile = SkypeGetErr("FILETRANSFER", pszMsgNum, "FILESIZE");
+ if (pszcbFile) {
+ dwTransferred = strtoul(pszcbFile, NULL, 10);
+ pfts.totalBytes+=dwTransferred;
+ if (bIsCurFil) pfts.currentFileSize=dwTransferred;
+ free(pszcbFile);
+ }
+ if (pszcbFile = SkypeGetErrID("FILETRANSFER", pszMsgNum, "BYTESTRANSFERRED")) {
+ dwTransferred = strtoul(pszcbFile, NULL, 10);
+ pfts.totalProgress+=dwTransferred;
+ if (bIsCurFil) pfts.currentFileProgress=dwTransferred;
+ free(pszcbFile);
+ }
+ }
+ free(pszXferIDs);
+ PROTOFILETRANSFERSTATUS *pftsv2 = (PROTOFILETRANSFERSTATUS*)pEntry->pfts;
+
+ pftsv2->currentFileNumber = pfts.currentFileNumber;
+ pftsv2->totalBytes = pfts.totalBytes;
+ pftsv2->totalProgress = pfts.totalProgress;
+ pftsv2->currentFileSize = pfts.currentFileSize;
+ pftsv2->currentFileProgress = pfts.currentFileProgress;
+ pftsv2->szCurrentFile = pftsv2->pszFiles[pftsv2->currentFileNumber];
+ ProtoBroadcastAck(SKYPE_PROTONAME, hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)dwChat, (LPARAM)pEntry->pfts);
+ }
+ }
+ free(pszChat);
+ free(pargs);
+}
+
+BOOL FXHandleMessage(const char *pszMsg)
+{
+ ft_args args={0};
+
+ const char *pTok=strchr(pszMsg, ' ');
+ if (!pTok)
+ return FALSE;
+
+ strncpy(args.szNum, pszMsg, pTok-pszMsg);
+ pszMsg=pTok+1;
+ if (!(pTok=strchr(pszMsg, ' '))) return FALSE;
+ pTok++;
+ if (!(args.bStatus=!strncmp(pszMsg, "STATUS", 6)) && strncmp(pszMsg, "BYTESTRANSFERRED", 16))
+ return FALSE;
+ ft_args *pargs=(ft_args*)malloc(sizeof(args));
+ if (!pargs) return TRUE;
+ strncpy(args.szArg, pTok, sizeof(args.szArg));
+ memcpy(pargs, &args, sizeof(args));
+ pthread_create((pThreadFunc)FXHandleMessageThread, pargs);
+ return TRUE;
+}
+
|