1 #include "main.h"
2 
3 #include "../filesys.h"
4 #include "../file_transfers.h"
5 #include "../flist.h"
6 #include "../friend.h"
7 #include "../debug.h"
8 #include "../tox.h"
9 #include "../macros.h"
10 
11 typedef struct {
12     IDropTarget dt;
13     LONG ref;
14 } my_IDropTarget;
15 
dnd_AddRef(IDropTarget * lpMyObj)16 ULONG __stdcall dnd_AddRef(IDropTarget *lpMyObj) {
17     my_IDropTarget *p = (void*)lpMyObj;
18     return InterlockedIncrement(&p->ref);
19 }
20 
dnd_Release(IDropTarget * lpMyObj)21 ULONG __stdcall dnd_Release(IDropTarget *lpMyObj) {
22     my_IDropTarget *p = (void*)lpMyObj;
23     LONG count = InterlockedDecrement(&p->ref);
24 
25     if (!count) {
26         free(lpMyObj->lpVtbl);
27         free(lpMyObj);
28     }
29 
30     return count;
31 }
32 
dnd_QueryInterface(IDropTarget * lpMyObj,REFIID riid,LPVOID FAR * lppvObj)33 HRESULT __stdcall dnd_QueryInterface(IDropTarget *lpMyObj, REFIID riid, LPVOID FAR *lppvObj) {
34       *lppvObj = NULL;
35 
36 //  PRINT_GUID (riid);
37   if (IsEqualIID (riid, &IID_IUnknown) || IsEqualIID (riid, &IID_IDropTarget)) {
38       dnd_AddRef (lpMyObj);
39       *lppvObj = lpMyObj;
40       return S_OK;
41     }
42 
43     return E_NOINTERFACE;
44 }
45 
dnd_DragEnter(IDropTarget * UNUSED (lpMyObj),IDataObject * UNUSED (pDataObject),DWORD UNUSED (grfKeyState),POINTL UNUSED (pt),DWORD * pdwEffect)46 HRESULT __stdcall dnd_DragEnter(IDropTarget *UNUSED(lpMyObj), IDataObject *UNUSED(pDataObject),
47                                 DWORD UNUSED(grfKeyState), POINTL UNUSED(pt), DWORD *pdwEffect) {
48     *pdwEffect = DROPEFFECT_COPY;
49     return S_OK;
50 }
51 
dnd_DragOver(IDropTarget * UNUSED (lpMyObj),DWORD UNUSED (grfKeyState),POINTL UNUSED (pt),DWORD * pdwEffect)52 HRESULT __stdcall dnd_DragOver(IDropTarget *UNUSED(lpMyObj), DWORD UNUSED(grfKeyState),
53                                POINTL UNUSED(pt), DWORD *pdwEffect) {
54     *pdwEffect = DROPEFFECT_COPY;
55     return S_OK;
56 }
57 
dnd_DragLeave(IDropTarget * UNUSED (lpMyObj))58 HRESULT __stdcall dnd_DragLeave(IDropTarget *UNUSED(lpMyObj)) {
59     return S_OK;
60 }
61 
dnd_Drop(IDropTarget * UNUSED (lpMyObj),IDataObject * pDataObject,DWORD UNUSED (grfKeyState),POINTL UNUSED (pt),DWORD * pdwEffect)62 HRESULT __stdcall dnd_Drop(IDropTarget *UNUSED(lpMyObj), IDataObject *pDataObject,
63                            DWORD UNUSED(grfKeyState), POINTL UNUSED(pt), DWORD *pdwEffect) {
64     *pdwEffect = DROPEFFECT_COPY;
65     LOG_NOTE("DnD", "Dropped!" );
66 
67     if (!flist_get_friend()) {
68         return S_OK;
69     }
70 
71     FORMATETC format = {
72         .cfFormat = CF_HDROP,
73         .dwAspect = DVASPECT_CONTENT,
74         .lindex = -1,
75         .tymed = TYMED_HGLOBAL,
76     };
77     STGMEDIUM medium;
78 
79     HRESULT r = pDataObject->lpVtbl->GetData(pDataObject, &format, &medium);
80     if (r == S_OK) {
81         HDROP h = medium.hGlobal;
82         int count = DragQueryFile(h, ~0, NULL, 0);
83         LOG_INFO("WINDND", "%u files dropped\n", count);
84 
85         for (int i = 0; i < count; i++) {
86             LOG_NOTE("WINDND", "Sending file number %i", i);
87             UTOX_MSG_FT *msg = calloc(1, sizeof(UTOX_MSG_FT));
88             if (!msg) {
89                 LOG_ERR("WINDND", "Unable to alloc for UTOX_MSG_FT");
90                 return 0;
91             }
92 
93             char *path = calloc(1, UTOX_FILE_NAME_LENGTH);
94             if (!path) {
95                 LOG_ERR("WINDND", "Unable to alloc for UTOX_MSG_FT");
96                 free(msg);
97                 return 0;
98             }
99 
100             DragQueryFile(h, i, path, UTOX_FILE_NAME_LENGTH);
101 
102             msg->file = fopen(path, "rb");
103             if (!msg->file) {
104                 LOG_ERR("WINDND", "Unable to read file %s" , path);
105                 free(msg);
106                 free(path);
107                 return 0;
108             }
109 
110             msg->name = (uint8_t *)path;
111             postmessage_toxcore(TOX_FILE_SEND_NEW, flist_get_friend()->number, 0, msg);
112             LOG_INFO("WINDND", "File number %i sent!" , i);
113         }
114 
115         ReleaseStgMedium(&medium);
116     } else {
117         LOG_ERR("WINDND", "itz failed! %lX", r);
118     }
119 
120     return S_OK;
121 }
122 
dnd_init(HWND window)123 void dnd_init(HWND window) {
124     my_IDropTarget *p;
125     p = malloc(sizeof(my_IDropTarget));
126     p->dt.lpVtbl = malloc(sizeof(*(p->dt.lpVtbl)));
127     p->ref = 0;
128 
129     p->dt.lpVtbl->QueryInterface = dnd_QueryInterface;
130     p->dt.lpVtbl->AddRef = dnd_AddRef;
131     p->dt.lpVtbl->Release = dnd_Release;
132 
133     p->dt.lpVtbl->DragEnter = dnd_DragEnter;
134     p->dt.lpVtbl->DragLeave = dnd_DragLeave;
135     p->dt.lpVtbl->DragOver = dnd_DragOver;
136     p->dt.lpVtbl->Drop = dnd_Drop;
137 
138     CoLockObjectExternal((struct IUnknown*)p, TRUE, FALSE);
139 
140     RegisterDragDrop(window, (IDropTarget*)p);
141 }
142