#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; ipszFiles)[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; itotalFiles; 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; }