void ipcGetSkinIcons(THeaderIPC *ipch) { TSlotProtoIcons spi; char szTmp[64]; int protoCount; PROTOACCOUNT **pp; if ( CallService(MS_PROTO_ENUMACCOUNTS, WPARAM(&protoCount), LPARAM(&pp)) == 0 && protoCount != 0) { spi.pid = GetCurrentProcessId(); while (protoCount > 0) { PROTOACCOUNT *pa = *pp; lstrcpyA(szTmp, pa->szModuleName); lstrcatA(szTmp, PS_GETCAPS); DWORD dwCaps = CallService(szTmp, PFLAGNUM_1, 0); if (dwCaps & PF1_FILESEND) { TSlotIPC *pct = ipcAlloc(ipch, sizeof(TSlotProtoIcons)); if (pct != NULL) { // capture all the icons! spi.hProto = murmur_hash(pa->szModuleName); for (int j = 0; j <= 10; j++) spi.hIcons[j] = LoadSkinnedProtoIcon(pa->szModuleName, ID_STATUS_OFFLINE + j); pct->fType = REQUEST_NEWICONS; memcpy(LPSTR(pct) + sizeof(TSlotIPC), &spi, sizeof(TSlotProtoIcons)); if (ipch->NewIconsBegin == NULL) ipch->NewIconsBegin = pct; } } pp++; protoCount--; } } // add Miranda icon TSlotIPC *pct = ipcAlloc(ipch, sizeof(TSlotProtoIcons)); if (pct != NULL) { ZeroMemory(&spi.hIcons, sizeof(spi.hIcons)); spi.hProto = 0; // no protocol spi.hIcons[0] = LoadSkinnedIcon(SKINICON_OTHER_MIRANDA); pct->fType = REQUEST_NEWICONS; memcpy(LPSTR(pct) + sizeof(TSlotIPC), &spi, sizeof(TSlotProtoIcons)); if (ipch->NewIconsBegin == NULL) ipch->NewIconsBegin = pct; } }
HRESULT ipcGetFiles(THeaderIPC *pipch, IDataObject* pDataObject, MCONTACT hContact) { FORMATETC fet; fet.cfFormat = CF_HDROP; fet.ptd = NULL; fet.dwAspect = DVASPECT_CONTENT; fet.lindex = -1; fet.tymed = TYMED_HGLOBAL; STGMEDIUM stgm; HRESULT hr = pDataObject->GetData(&fet, &stgm); if (hr == S_OK) { // FIX, actually lock the global object and get a pointer HANDLE hDrop = GlobalLock(stgm.hGlobal); if (hDrop != 0) { // get the maximum number of files UINT iFile, iFileMax = DragQueryFileA((HDROP)stgm.hGlobal, -1, NULL, 0); for (iFile = 0; iFile < iFileMax; iFile++) { // get the size of the file path int cbSize = DragQueryFileA((HDROP)stgm.hGlobal, iFile, NULL, 0); // get the buffer TSlotIPC *pct = ipcAlloc(pipch, cbSize + 1); // including null term // allocated? if (pct == NULL) break; // store the hContact pct->hContact = hContact; // copy it to the buffer DragQueryFileA((HDROP)stgm.hGlobal, iFile, LPSTR(pct) + sizeof(TSlotIPC), pct->cbStrSection); } // store the number of files pipch->Slots = iFile; GlobalUnlock(stgm.hGlobal); } // if hDrop check // release the mediumn the lock may of failed ReleaseStgMedium(&stgm); } return hr; }
// this function is called from an APC into the main thread void __stdcall ipcService(ULONG_PTR dwParam) { HANDLE hSignal; TSlotIPC *pct; LPSTR szBuf; char szGroupStr[32]; DBVARIANT dbv; LPSTR szMiranda; // try to open the file mapping object the caller must make sure no other // running instance is using this file HANDLE hMap = OpenFileMappingA(FILE_MAP_ALL_ACCESS, false, IPC_PACKET_NAME); if (hMap == 0) return; // map the file to this process THeaderIPC *pMMT = (THeaderIPC*)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0); // if it fails the caller should of had some timeout in wait if (pMMT != NULL && pMMT->cbSize == sizeof(THeaderIPC) && pMMT->dwVersion == PLUGIN_MAKE_VERSION(2, 0, 1, 2)) { // toggle the right bits int *bits = &pMMT->fRequests; // jump right to a worker thread for file processing? if (*bits & REQUEST_XFRFILES) { THeaderIPC *cloned = (THeaderIPC*)mir_alloc(IPC_PACKET_SIZE); // translate from client space to cloned heap memory pMMT->pServerBaseAddress = pMMT->pClientBaseAddress; pMMT->pClientBaseAddress = cloned; CopyMemory(cloned, pMMT, IPC_PACKET_SIZE); ipcFixupAddresses(true, cloned); DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &cloned->Param, THREAD_SET_CONTEXT, false, 0); mir_forkthread(&IssueTransferThread, cloned); goto Reply; } // the request was to clear the MRU entries, we have no return data if (*bits & REQUEST_CLEARMRU) { mir_forkthread(&ClearMRUThread, NULL); goto Reply; } // the IPC header may have pointers that need to be translated // in either case the supplied data area pointers has to be // translated to this address space. // the server base address is always removed to get an offset // to which the client base is added, this is what ipcFixupAddresses() does pMMT->pServerBaseAddress = pMMT->pClientBaseAddress; pMMT->pClientBaseAddress = pMMT; // translate to the server space map ipcFixupAddresses(true, pMMT); // store the address map offset so the caller can retranslate pMMT->pServerBaseAddress = pMMT; // return some options to the client if (db_get_b(0, SHLExt_Name, SHLExt_ShowNoIcons, 0) != 0) pMMT->dwFlags = HIPC_NOICONS; // see if we have a custom string for 'Miranda' szMiranda = "Miranda"; lstrcpynA(pMMT->MirandaName, szMiranda, sizeof(pMMT->MirandaName) - 1); // for the MRU menu szBuf = Translate("Recently"); lstrcpynA(pMMT->MRUMenuName, szBuf, sizeof(pMMT->MRUMenuName) - 1); // and a custom string for "clear entries" szBuf = Translate("Clear entries"); lstrcpynA(pMMT->ClearEntries, szBuf, sizeof(pMMT->ClearEntries) - 1); // if the group mode is on, check if they want the CList setting bool bGroupMode = (BST_CHECKED == db_get_b(0, SHLExt_Name, SHLExt_UseGroups, BST_UNCHECKED)); if (bGroupMode && BST_CHECKED == db_get_b(0, SHLExt_Name, SHLExt_UseCListSetting, BST_UNCHECKED)) bGroupMode = db_get_b(0, "CList", "UseGroups", true) != 0; int iSlot = 0; // return profile if set if (BST_UNCHECKED == db_get_b(0, SHLExt_Name, SHLExt_ShowNoProfile, BST_UNCHECKED)) { pct = ipcAlloc(pMMT, 50); if (pct != NULL) { // will actually return with .dat if there's space for it, not what the docs say pct->Status = STATUS_PROFILENAME; CallService(MS_DB_GETPROFILENAME, 49, UINT_PTR(pct) + sizeof(TSlotIPC)); } } if (*bits & REQUEST_NEWICONS) ipcGetSkinIcons(pMMT); if (*bits & REQUEST_GROUPS) { // return contact's grouping if it's present while (bGroupMode) { _itoa(iSlot, szGroupStr, 10); if ( db_get_s(0, "CListGroups", szGroupStr, &dbv) != 0) break; pct = ipcAlloc(pMMT, lstrlenA(dbv.pszVal + 1) + 1); // first byte has flags, need null term if (pct != NULL) { if (pMMT->GroupsBegin == NULL) pMMT->GroupsBegin = pct; pct->fType = REQUEST_GROUPS; pct->hContact = 0; szBuf = LPSTR(pct) + sizeof(TSlotIPC); // get the end of the slot lstrcpyA(szBuf, dbv.pszVal + 1); pct->hGroup = 0; db_free(&dbv); // free the string } else { // outta space db_free(&dbv); break; } iSlot++; } // if there was no space left, it'll } on null if (pct == NULL) *bits = (*bits | GROUPS_NOTIMPL) & ~REQUEST_GROUPS; } // SHOULD check slot space. if (*bits & REQUEST_CONTACTS) { if (!ipcGetSortedContacts(pMMT, &iSlot, bGroupMode)) // fail if there were no contacts AT ALL *bits = (*bits | CONTACTS_NOTIMPL) & ~REQUEST_CONTACTS; } // store the number of slots allocated pMMT->Slots = iSlot; Reply: // get the handle the caller wants to be signalled on hSignal = OpenEventA(EVENT_ALL_ACCESS, false, pMMT->SignalEventName); if (hSignal != 0) { SetEvent(hSignal); CloseHandle(hSignal); } UnmapViewOfFile(pMMT); } CloseHandle(hMap); }
bool ipcGetSortedContacts(THeaderIPC *ipch, int *pSlot, bool bGroupMode) { DBVARIANT dbv; int n, rc; bool Result = false; // hide offliners? bool bHideOffline = db_get_b(0, "CList", "HideOffline", 0) == 1; // do they wanna hide the offline people anyway? if (db_get_b(0, SHLExt_Name, SHLExt_ShowNoOffline, 0) == 1) // hide offline people bHideOffline = true; // get the number of contacts int dwContacts = (int)CallService(MS_DB_CONTACT_GETCOUNT, 0, 0); if (dwContacts == 0) return false; // get the contacts in the array to be sorted by status, trim out anyone // who doesn't wanna be seen. TSlotInfo *pContacts = (TSlotInfo*)mir_alloc((dwContacts + 2) * sizeof(TSlotInfo)); int i = 0; int dwOnline = 0; for (MCONTACT hContact = db_find_first(); hContact != 0; hContact = db_find_next(hContact)) { if (i >= dwContacts) break; // do they have a running protocol? char *szProto = GetContactProto(hContact); if (szProto != NULL) { // does it support file sends? DWORD dwCaps = ProtoCallService(szProto, PS_GETCAPS, PFLAGNUM_1, 0); if ((dwCaps & PF1_FILESEND) == 0) continue; int dwStatus = db_get_w(hContact, szProto, "Status", ID_STATUS_OFFLINE); if (dwStatus != ID_STATUS_OFFLINE) dwOnline++; else if (bHideOffline) continue; // is HIT on? if (BST_UNCHECKED == db_get_b(0, SHLExt_Name, SHLExt_UseHITContacts, BST_UNCHECKED)) { // don't show people who are "Hidden" "NotOnList" or Ignored if (db_get_b(hContact, "CList", "Hidden", 0) == 1 || db_get_b(hContact, "CList", "NotOnList", 0) == 1 || CallService(MS_IGNORE_ISIGNORED, hContact, IGNOREEVENT_MESSAGE | IGNOREEVENT_URL | IGNOREEVENT_FILE) != 0) continue; } // is HIT2 off? if (BST_UNCHECKED == db_get_b(0, SHLExt_Name, SHLExt_UseHIT2Contacts, BST_UNCHECKED)) if (db_get_w(hContact, szProto, "ApparentMode", 0) == ID_STATUS_OFFLINE) continue; // store pContacts[i].hContact = hContact; pContacts[i].dwStatus = dwStatus; pContacts[i].hProto = murmur_hash(szProto); i++; } } // if no one is online and the CList isn't showing offliners, quit if (dwOnline == 0 && bHideOffline) { mir_free(pContacts); return false; } dwContacts = i; qsort(pContacts, dwContacts, sizeof(TSlotInfo), SortContact); // create an IPC slot for each contact and store display name, etc for (i=0; i < dwContacts; i++) { char *szContact = (char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)pContacts[i].hContact, 0); if (szContact != NULL) { n = 0; rc = 1; if (bGroupMode) { rc = db_get_s(pContacts[i].hContact, "CList", "Group", &dbv); if (!rc) n = lstrlenA(dbv.pszVal) + 1; } int cch = lstrlenA(szContact) + 1; TSlotIPC *pct = ipcAlloc(ipch, cch + 1 + n); if (pct == NULL) { db_free(&dbv); break; } // lie about the actual size of the TSlotIPC pct->cbStrSection = cch; LPSTR szSlot = LPSTR(pct) + sizeof(TSlotIPC); lstrcpyA(szSlot, szContact); pct->fType = REQUEST_CONTACTS; pct->hContact = pContacts[i].hContact; pct->Status = pContacts[i].dwStatus; pct->hProto = pContacts[i].hProto; pct->MRU = db_get_b(pct->hContact, SHLExt_Name, SHLExt_MRU, 0); if (ipch->ContactsBegin == NULL) ipch->ContactsBegin = pct; szSlot += cch + 1; if (rc == 0) { pct->hGroup = murmur_hash(dbv.pszVal); lstrcpyA(szSlot, dbv.pszVal); db_free(&dbv); } else { pct->hGroup = 0; *szSlot = 0; } pSlot[0]++; } } mir_free(pContacts); return true; }