STDMETHODIMP_(MEVENT) CDb3Mmap::FindLastEvent(MCONTACT contactID) { DBCachedContact *cc; DWORD ofsContact = GetContactOffset(contactID, &cc); mir_cslock lck(m_csDbAccess); DBContact *dbc = (DBContact*)DBRead(ofsContact, nullptr); if (dbc->signature != DBCONTACT_SIGNATURE) return 0; if (!cc || !cc->IsSub()) return MEVENT(dbc->ofsLastEvent); if ((cc = m_cache->GetCachedContact(cc->parentID)) == nullptr) return 0; dbc = (DBContact*)DBRead(cc->dwOfsContact, nullptr); if (dbc->signature != DBCONTACT_SIGNATURE) return 0; for (DWORD dwOffset = dbc->ofsLastEvent; dwOffset != 0;) { DBEvent *dbe = AdaptEvent(dwOffset, contactID); if (dbe->signature != DBEVENT_SIGNATURE) return 0; if (dbe->contactID == contactID) return MEVENT(dwOffset); dwOffset = dbe->ofsPrev; } return 0; }
int Meta_ContactDeleted(WPARAM hContact, LPARAM lParam) { DBCachedContact *cc = currDb->m_cache->GetCachedContact(hContact); if (cc == NULL) return 0; // is a subcontact - update meta contact if (cc->IsSub()) { DBCachedContact *ccMeta = CheckMeta(cc->parentID); if (ccMeta) { Meta_RemoveContactNumber(ccMeta, Meta_GetContactNumber(ccMeta, hContact), true); NotifyEventHooks(hSubcontactsChanged, ccMeta->contactID, 0); } return 0; } // not a subcontact - is it a metacontact? if (!cc->IsMeta()) return 0; if (cc->nSubs > 0) NotifyEventHooks(hSubcontactsChanged, hContact, 0); // remove & restore all subcontacts for (int i = 0; i < cc->nSubs; i++) { currDb->MetaDetouchSub(cc, i); // stop ignoring, if we were if (options.bSuppressStatus) CallService(MS_IGNORE_UNIGNORE, cc->pSubs[i], IGNOREEVENT_USERONLINE); } return 0; }
INT_PTR Meta_Default(WPARAM hSub, LPARAM) { DBCachedContact *cc = currDb->m_cache->GetCachedContact(db_mc_getMeta(hSub)); if (cc && cc->IsMeta()) db_mc_setDefault(cc->contactID, hSub, true); return 0; }
STDMETHODIMP_(HANDLE) CDb3Mmap::FindLastEvent(MCONTACT contactID) { DBCachedContact *cc; DWORD ofsContact = GetContactOffset(contactID, &cc); mir_cslock lck(m_csDbAccess); DBContact *dbc = (DBContact*)DBRead(ofsContact, sizeof(DBContact), NULL); if (dbc->signature != DBCONTACT_SIGNATURE) return NULL; if (!cc || !cc->IsSub()) return HANDLE(dbc->ofsLastEvent); if ((cc = m_cache->GetCachedContact(cc->parentID)) == NULL) return NULL; dbc = (DBContact*)DBRead(cc->dwDriverData, sizeof(DBContact), NULL); if (dbc->signature != DBCONTACT_SIGNATURE) return NULL; for (DWORD dwOffset = dbc->ofsLastEvent; dwOffset != 0;) { DBEvent *dbe = (DBEvent*)DBRead(dwOffset, sizeof(DBEvent), NULL); if (dbe->signature != DBEVENT_SIGNATURE) return NULL; if (dbe->contactID == contactID) return HANDLE(dwOffset); dwOffset = dbe->ofsPrev; } return NULL; }
// returns parent hContact for a subcontact or hContact itself if it's not a sub MIR_CORE_DLL(MCONTACT) db_mc_tryMeta(MCONTACT hContact) { if (currDb == NULL) return hContact; DBCachedContact *cc = currDb->m_cache->GetCachedContact(hContact); if (cc == NULL) return hContact; return (cc->IsSub()) ? cc->parentID : hContact; }
static INT_PTR MetaFilter_RecvMessage(WPARAM wParam, LPARAM lParam) { CCSDATA *ccs = (CCSDATA*)lParam; DBCachedContact *cc = currDb->m_cache->GetCachedContact(ccs->hContact); if (cc && cc->IsSub()) Meta_SetSrmmSub(cc->parentID, cc->contactID); CallService(MS_PROTO_CHAINRECV, wParam, lParam); return 0; }
STDMETHODIMP_(BOOL) CDb3Mmap::MarkEventRead(MCONTACT contactID, HANDLE hDbEvent) { DBCachedContact *cc; if (contactID) { if ((cc = m_cache->GetCachedContact(contactID)) == NULL) return -1; if (cc->IsSub()) if ((cc = m_cache->GetCachedContact(cc->parentID)) == NULL) return -1; } else cc = NULL; mir_cslockfull lck(m_csDbAccess); DWORD ofsContact = (cc) ? cc->dwDriverData : m_dbHeader.ofsUser; DBContact dbc = *(DBContact*)DBRead(ofsContact, sizeof(DBContact), NULL); DBEvent *dbe = (DBEvent*)DBRead((DWORD)hDbEvent, sizeof(DBEvent), NULL); if (dbe->signature != DBEVENT_SIGNATURE || dbc.signature != DBCONTACT_SIGNATURE) return -1; if (dbe->markedRead()) return dbe->flags; // log1("mark read @ %08x", hContact); dbe->flags |= DBEF_READ; DBWrite((DWORD)hDbEvent, dbe, sizeof(DBEvent)); BOOL ret = dbe->flags; if (dbc.ofsFirstUnread == (DWORD)hDbEvent) { for (;;) { if (dbe->ofsNext == 0) { dbc.ofsFirstUnread = 0; dbc.tsFirstUnread = 0; break; } DWORD ofsThis = dbe->ofsNext; dbe = (DBEvent*)DBRead(ofsThis, sizeof(DBEvent), NULL); if (!dbe->markedRead()) { dbc.ofsFirstUnread = ofsThis; dbc.tsFirstUnread = dbe->timestamp; break; } } } DBWrite(ofsContact, &dbc, sizeof(DBContact)); DBFlush(0); lck.unlock(); NotifyEventHooks(hEventMarkedRead, contactID, (LPARAM)hDbEvent); return ret; }
STDMETHODIMP_(HANDLE) CDb3Mmap::FindPrevEvent(MCONTACT contactID, HANDLE hDbEvent) { DBCachedContact *cc = (contactID) ? m_cache->GetCachedContact(contactID) : NULL; mir_cslock lck(m_csDbAccess); DBEvent *dbe = (DBEvent*)DBRead((DWORD)hDbEvent, sizeof(DBEvent), NULL); if (dbe->signature != DBEVENT_SIGNATURE) return NULL; if (!cc || !cc->IsSub()) return HANDLE(dbe->ofsPrev); for (DWORD dwOffset = dbe->ofsPrev; dwOffset != 0;) { dbe = (DBEvent*)DBRead(dwOffset, sizeof(DBEvent), NULL); if (dbe->signature != DBEVENT_SIGNATURE) return NULL; if (dbe->contactID == contactID) return HANDLE(dwOffset); dwOffset = dbe->ofsPrev; } return NULL; }
STDMETHODIMP_(MEVENT) CDb3Mmap::FindPrevEvent(MCONTACT contactID, MEVENT hDbEvent) { DBCachedContact *cc = (contactID) ? m_cache->GetCachedContact(contactID) : nullptr; mir_cslock lck(m_csDbAccess); DBEvent *dbe = AdaptEvent((DWORD)hDbEvent, contactID); if (dbe->signature != DBEVENT_SIGNATURE) return 0; if (!cc || !cc->IsSub()) return MEVENT(dbe->ofsPrev); for (DWORD dwOffset = dbe->ofsPrev; dwOffset != 0;) { dbe = AdaptEvent(dwOffset, contactID); if (dbe->signature != DBEVENT_SIGNATURE) return 0; if (dbe->contactID == contactID) return MEVENT(dwOffset); dwOffset = dbe->ofsPrev; } return 0; }
// record window open/close status for subs & metas static int Meta_MessageWindowEvent(WPARAM wParam, LPARAM lParam) { MessageWindowEventData *mwed = (MessageWindowEventData*)lParam; if (mwed->uType == MSG_WINDOW_EVT_OPEN) { DBCachedContact *cc = currDb->m_cache->GetCachedContact(mwed->hContact); if (cc != NULL) { Meta_UpdateSrmmIcon(cc, db_get_w(cc->contactID, META_PROTO, "Status", ID_STATUS_OFFLINE)); if (cc->IsMeta()) { MetaSrmmData *p = new MetaSrmmData; p->m_hMeta = cc->contactID; p->m_hSub = db_mc_getMostOnline(cc->contactID); p->m_hWnd = mwed->hwndWindow; arMetaWindows.insert(p); } } } else if (mwed->uType == MSG_WINDOW_EVT_CLOSING) { for (int i = 0; i < arMetaWindows.getCount(); i++) if (arMetaWindows[i].m_hWnd == mwed->hwndWindow) arMetaWindows.remove(i); } return 0; }
INT_PTR Meta_Delete(WPARAM hContact, LPARAM bSkipQuestion) { DBCachedContact *cc = currDb->m_cache->GetCachedContact(hContact); if (cc == NULL) return 1; // The wParam is a metacontact if (cc->IsMeta()) { // check from recursion - see second half of this function if (!bSkipQuestion && IDYES != MessageBox(cli.hwndContactList, TranslateT("This will remove the metacontact permanently.\n\nProceed anyway?"), TranslateT("Are you sure?"), MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2)) return 0; for (int i = cc->nSubs-1; i >= 0; i--) Meta_RemoveContactNumber(cc, i, false); NotifyEventHooks(hSubcontactsChanged, hContact, 0); CallService(MS_DB_CONTACT_DELETE, hContact, 0); } else if (cc->IsSub()) { if ((cc = currDb->m_cache->GetCachedContact(cc->parentID)) == NULL) return 2; if (cc->nSubs == 1) { if (IDYES == MessageBox(0, TranslateT(szDelMsg), TranslateT("Delete metacontact?"), MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON1)) Meta_Delete(cc->contactID, 1); return 0; } Meta_RemoveContactNumber(cc, Meta_GetContactNumber(cc, hContact), true); } return 0; }
int Meta_SettingChanged(WPARAM hContact, LPARAM lParam) { DBCONTACTWRITESETTING *dcws = (DBCONTACTWRITESETTING *)lParam; char buffer[512]; // the only global options we're interested in if (hContact == 0) return 0; DBCachedContact *cc = currDb->m_cache->GetCachedContact(hContact); if (cc == NULL || !cc->IsSub()) return 0; DBCachedContact *ccMeta = currDb->m_cache->GetCachedContact(cc->parentID); if (ccMeta == NULL || !ccMeta->IsMeta()) return 0; // This contact is attached to a MetaContact. int contact_number = Meta_GetContactNumber(ccMeta, hContact); if (contact_number == -1) return 0; // exit - db corruption if (!strcmp(dcws->szSetting, "IP")) { if (dcws->value.type == DBVT_DWORD) db_set_dw(ccMeta->contactID, META_PROTO, "IP", dcws->value.dVal); else db_unset(ccMeta->contactID, META_PROTO, "IP"); } else if (!strcmp(dcws->szSetting, "RealIP")) { if (dcws->value.type == DBVT_DWORD) db_set_dw(ccMeta->contactID, META_PROTO, "RealIP", dcws->value.dVal); else db_unset(ccMeta->contactID, META_PROTO, "RealIP"); } else if (!strcmp(dcws->szSetting, "ListeningTo")) { switch (dcws->value.type) { case DBVT_ASCIIZ: db_set_s(ccMeta->contactID, META_PROTO, "ListeningTo", dcws->value.pszVal); break; case DBVT_UTF8: db_set_utf(ccMeta->contactID, META_PROTO, "ListeningTo", dcws->value.pszVal); break; case DBVT_WCHAR: db_set_ws(ccMeta->contactID, META_PROTO, "ListeningTo", dcws->value.pwszVal); break; case DBVT_DELETED: db_unset(ccMeta->contactID, META_PROTO, "ListeningTo"); break; } } else if (!strcmp(dcws->szSetting, "Nick") && dcws->value.type != DBVT_DELETED) { // subcontact nick has changed - update metacontact mir_snprintf(buffer, SIZEOF(buffer), "Nick%d", contact_number); db_set(ccMeta->contactID, META_PROTO, buffer, &dcws->value); ptrT tszMyhandle(db_get_tsa(hContact, "CList", "MyHandle")); if (tszMyhandle == NULL) { mir_snprintf(buffer, SIZEOF(buffer), "CListName%d", contact_number); db_set(ccMeta->contactID, META_PROTO, buffer, &dcws->value); } // copy nick to metacontact, if it's the most online MCONTACT hMostOnline = Meta_GetMostOnline(ccMeta); Meta_CopyContactNick(ccMeta, hMostOnline); } else if (!strcmp(dcws->szSetting, "IdleTS")) { if (dcws->value.type == DBVT_DWORD) db_set_dw(ccMeta->contactID, META_PROTO, "IdleTS", dcws->value.dVal); else if (dcws->value.type == DBVT_DELETED) db_set_dw(ccMeta->contactID, META_PROTO, "IdleTS", 0); } else if (!strcmp(dcws->szSetting, "LogonTS")) { if (dcws->value.type == DBVT_DWORD) db_set_dw(ccMeta->contactID, META_PROTO, "LogonTS", dcws->value.dVal); else if (dcws->value.type == DBVT_DELETED) db_set_dw(ccMeta->contactID, META_PROTO, "LogonTS", 0); } else if (!strcmp(dcws->szModule, "CList") && !strcmp(dcws->szSetting, "MyHandle")) { if (dcws->value.type == DBVT_DELETED) { char *proto = GetContactProto(hContact); mir_snprintf(buffer, SIZEOF(buffer), "CListName%d", contact_number); DBVARIANT dbv; if (proto && !db_get_ts(hContact, proto, "Nick", &dbv)) { db_set_ts(ccMeta->contactID, META_PROTO, buffer, dbv.ptszVal); db_free(&dbv); } else db_unset(ccMeta->contactID, META_PROTO, buffer); } else { // subcontact clist displayname has changed - update metacontact mir_snprintf(buffer, SIZEOF(buffer), "CListName%d", contact_number); db_set(ccMeta->contactID, META_PROTO, buffer, &dcws->value); } // copy nick to metacontact, if it's the most online Meta_CopyContactNick(ccMeta, Meta_GetMostOnline(ccMeta)); } // subcontact changing status else if (!strcmp(dcws->szSetting, "Status") && dcws->value.type != DBVT_DELETED) { // update subcontact status setting mir_snprintf(buffer, SIZEOF(buffer), "Status%d", contact_number); db_set_w(ccMeta->contactID, META_PROTO, buffer, dcws->value.wVal); mir_snprintf(buffer, SIZEOF(buffer), "StatusString%d", contact_number); db_set_ts(ccMeta->contactID, META_PROTO, buffer, cli.pfnGetStatusModeDescription(dcws->value.wVal, 0)); // set status to that of most online contact MCONTACT hMostOnline = Meta_GetMostOnline(ccMeta); if (hMostOnline != db_mc_getDefault(ccMeta->contactID)) db_mc_notifyDefChange(ccMeta->contactID, hMostOnline); Meta_CopyContactNick(ccMeta, hMostOnline); Meta_FixStatus(ccMeta); // most online contact with avatar support might have changed - update avatar hMostOnline = Meta_GetMostOnlineSupporting(ccMeta, PFLAGNUM_4, PF4_AVATARS); if (hMostOnline) { PROTO_AVATAR_INFORMATIONT AI = { sizeof(AI) }; AI.hContact = ccMeta->contactID; AI.format = PA_FORMAT_UNKNOWN; _tcscpy(AI.filename, _T("X")); if (CallProtoService(META_PROTO, PS_GETAVATARINFOT, 0, (LPARAM)&AI) == GAIR_SUCCESS) db_set_ts(ccMeta->contactID, "ContactPhoto", "File", AI.filename); } } return 0; }
int Meta_ModifyMenu(WPARAM hMeta, LPARAM) { DBCachedContact *cc = currDb->m_cache->GetCachedContact(hMeta); if (cc == NULL) return 0; Menu_ShowItem(hMenuRoot, false); if (cc->IsMeta()) { // save the mouse pos in case they open a subcontact menu GetCursorPos(&menuMousePoint); // This is a MetaContact, show the edit, force default, and the delete menu, and hide the others Menu_ShowItem(hMenuEdit, true); Menu_ShowItem(hMenuAdd, false); Menu_ShowItem(hMenuConvert, false); Menu_ShowItem(hMenuDefault, false); Menu_ShowItem(hMenuDelete, false); Menu_ModifyItem(hMenuDelete, LPGENT("Remove from metacontact")); // show subcontact menu items CMString tszNick; for (int i = 0; i < MAX_CONTACTS; i++) { if (i >= cc->nSubs) { Menu_ShowItem(hMenuContact[i], false); continue; } MCONTACT hContact = Meta_GetContactHandle(cc, i); LPCTSTR ptszName; if (options.menu_contact_label == DNT_UID) { Meta_GetSubNick(hMeta, i, tszNick); ptszName = tszNick.GetBuffer(); } else ptszName = cli.pfnGetContactDisplayName(hContact, 0); int iconIndex = CallService(MS_CLIST_GETCONTACTICON, hContact, 0); HICON hIcon = ImageList_GetIcon((HIMAGELIST)CallService(MS_CLIST_GETICONSIMAGELIST, 0, 0), iconIndex, 0); Menu_ModifyItem(hMenuContact[i], ptszName, hIcon, 0); DestroyIcon(hIcon); Menu_ShowItem(hMenuRoot, true); } // show hide nudge menu item char serviceFunc[256]; mir_snprintf(serviceFunc, _countof(serviceFunc), "%s%s", GetContactProto(Meta_GetMostOnline(cc)), PS_SEND_NUDGE); CallService(MS_NUDGE_SHOWMENU, (WPARAM)META_PROTO, ServiceExists(serviceFunc)); return 0; } PROTOACCOUNT *pa = Proto_GetAccount(cc->szProto); if (!db_mc_isEnabled() || !pa || pa->bIsVirtual) { // groups disabled - all meta menu options hidden Menu_ShowItem(hMenuDefault, false); Menu_ShowItem(hMenuDelete, false); Menu_ShowItem(hMenuAdd, false); Menu_ShowItem(hMenuConvert, false); Menu_ShowItem(hMenuEdit, false); return 0; } // the contact is affected to a metacontact if (cc->IsSub()) { Menu_ShowItem(hMenuDefault, true); Menu_ModifyItem(hMenuDelete, LPGENT("Remove from metacontact")); Menu_ShowItem(hMenuDelete, true); Menu_ShowItem(hMenuAdd, false); Menu_ShowItem(hMenuConvert, false); Menu_ShowItem(hMenuEdit, false); } else { // The contact is neutral bool bHideChat = db_get_b(hMeta, cc->szProto, "ChatRoom", 0) == 0; Menu_ShowItem(hMenuAdd, bHideChat); Menu_ShowItem(hMenuConvert, bHideChat); Menu_ShowItem(hMenuEdit, false); Menu_ShowItem(hMenuDelete, false); Menu_ShowItem(hMenuDefault, false); } for (int i = 0; i < MAX_CONTACTS; i++) Menu_ShowItem(hMenuContact[i], false); return 0; }
static INT_PTR CALLBACK Meta_SelectDialogProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_INITDIALOG: TranslateDialogDefault(hwndDlg); { DBCachedContact *cc = currDb->m_cache->GetCachedContact(lParam); if (cc == NULL) { DestroyWindow(hwndDlg); return TRUE; } if (cc->IsMeta()) { MessageBox(hwndDlg, TranslateT("This contact is a metacontact.\nYou can't add a metacontact to another metacontact.\n\nPlease choose another."), TranslateT("Metacontact conflict"), MB_ICONERROR); DestroyWindow(hwndDlg); return TRUE; } if (cc->IsSub()) { MessageBox(hwndDlg, TranslateT("This contact is already associated to a metacontact.\nYou cannot add a contact to multiple metacontacts."), TranslateT("Multiple metacontacts"), MB_ICONERROR); DestroyWindow(hwndDlg); return TRUE; } } SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); // user data is contact handle SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIconEx(I_ADD)); // Initialize the graphical part CheckDlgButton(hwndDlg, IDC_ONLYAVAIL, BST_CHECKED); // Initially checked; display all metacontacts is only an option // Besides, we can check if there is at least one metacontact to add the contact to. if (BuildList(GetDlgItem(hwndDlg, IDC_METALIST), FALSE) <= 0) { if (MessageBox(hwndDlg, TranslateT(szConvMsg), TranslateT("No suitable metacontact found"), MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON1) == IDYES) Meta_Convert(lParam, 0); DestroyWindow(hwndDlg); return TRUE; } else { // get contact display name from clist TCHAR *ptszCDN = cli.pfnGetContactDisplayName(lParam, 0); if (!ptszCDN) ptszCDN = TranslateT("a contact"); // ... and set it to the Window title. TCHAR buf[256]; mir_sntprintf(buf, SIZEOF(buf), TranslateT("Adding %s..."), ptszCDN); SetWindowText(hwndDlg, buf); } ShowWindow(hwndDlg, SW_SHOWNORMAL); return TRUE; case WM_COMMAND: if (HIWORD(wParam) == LBN_DBLCLK) // emulate click ok Ok wParam = MAKEWPARAM(IDOK, BN_CLICKED); if (HIWORD(wParam) != BN_CLICKED) break; // Only clicks of buttons are relevant, let other COMMANDs through switch (LOWORD(wParam)) { case IDOK: { int item = SendDlgItemMessage(hwndDlg, IDC_METALIST, LB_GETCURSEL, 0, 0); // Get the index of the selected metacontact if (item == -1) return IDOK == MessageBox(hwndDlg, TranslateT("Please select a metacontact"), TranslateT("No metacontact selected"), MB_ICONHAND); MCONTACT hContact = (MCONTACT)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); MCONTACT hMeta = (MCONTACT)SendMessage(GetDlgItem(hwndDlg, IDC_METALIST), LB_GETITEMDATA, item, 0); if (!Meta_Assign(hContact, hMeta, FALSE)) MessageBox(hwndDlg, TranslateT("Assignment to the metacontact failed."), TranslateT("Assignment failure"), MB_ICONERROR); } // fall through case IDCANCEL: DestroyWindow(hwndDlg); break; case IDC_CHK_SRT: SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_METALIST), GWL_STYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_METALIST), GWL_STYLE) ^ LBS_SORT); if (BuildList(GetDlgItem(hwndDlg, IDC_METALIST), IsDlgButtonChecked(hwndDlg, IDC_CHK_SRT) ? TRUE : FALSE) <= 0) { if (MessageBox(hwndDlg, TranslateT(szConvMsg), TranslateT("No suitable metacontact found"), MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON1) == IDYES) Meta_Convert(lParam, 0); DestroyWindow(hwndDlg); return TRUE; } break; } break; case WM_DESTROY: // Free all allocated memory and return the focus to the CList HWND clist = GetParent(hwndDlg); Skin_ReleaseIcon((HICON)SendMessage(hwndDlg, WM_SETICON, ICON_BIG, 0)); EndDialog(hwndDlg, TRUE); SetFocus(clist); return TRUE; } return FALSE; // All other Message are not handled }
int CDb3Mmap::GetContactSettingWorker(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv, int isStatic) { if (szSetting == NULL || szModule == NULL) return 1; // the db format can't tolerate more than 255 bytes of space (incl. null) for settings+module name int settingNameLen = (int)mir_strlen(szSetting); int moduleNameLen = (int)mir_strlen(szModule); if (settingNameLen > 0xFE) { #ifdef _DEBUG OutputDebugStringA("GetContactSettingWorker() got a > 255 setting name length. \n"); #endif return 1; } if (moduleNameLen > 0xFE) { #ifdef _DEBUG OutputDebugStringA("GetContactSettingWorker() got a > 255 module name length. \n"); #endif return 1; } mir_cslock lck(m_csDbAccess); LBL_Seek: char *szCachedSettingName = m_cache->GetCachedSetting(szModule, szSetting, moduleNameLen, settingNameLen); log3("get [%08p] %s (%p)", hContact, szCachedSettingName, szCachedSettingName); DBVARIANT *pCachedValue = m_cache->GetCachedValuePtr(contactID, szCachedSettingName, 0); if (pCachedValue != NULL) { if (pCachedValue->type == DBVT_ASCIIZ || pCachedValue->type == DBVT_UTF8) { int cbOrigLen = dbv->cchVal; char *cbOrigPtr = dbv->pszVal; memcpy(dbv, pCachedValue, sizeof(DBVARIANT)); if (isStatic) { int cbLen = 0; if (pCachedValue->pszVal != NULL) cbLen = (int)mir_strlen(pCachedValue->pszVal); cbOrigLen--; dbv->pszVal = cbOrigPtr; if (cbLen < cbOrigLen) cbOrigLen = cbLen; memcpy(dbv->pszVal, pCachedValue->pszVal, cbOrigLen); dbv->pszVal[cbOrigLen] = 0; dbv->cchVal = cbLen; } else { dbv->pszVal = (char*)mir_alloc(mir_strlen(pCachedValue->pszVal) + 1); mir_strcpy(dbv->pszVal, pCachedValue->pszVal); } } else memcpy(dbv, pCachedValue, sizeof(DBVARIANT)); log2("get cached %s (%p)", printVariant(dbv), pCachedValue); return (pCachedValue->type == DBVT_DELETED) ? 1 : 0; } // never look db for the resident variable if (szCachedSettingName[-1] != 0) return 1; DBCachedContact *cc; DWORD ofsContact = GetContactOffset(contactID, &cc); DWORD ofsModuleName = GetModuleNameOfs(szModule); DBContact dbc = *(DBContact*)DBRead(ofsContact, NULL); if (dbc.signature != DBCONTACT_SIGNATURE) return 1; DWORD ofsSettingsGroup = GetSettingsGroupOfsByModuleNameOfs(&dbc, ofsModuleName); if (ofsSettingsGroup) { int bytesRemaining; unsigned varLen; DWORD ofsBlobPtr = ofsSettingsGroup + offsetof(DBContactSettings, blob); PBYTE pBlob = DBRead(ofsBlobPtr, &bytesRemaining); while (pBlob[0]) { NeedBytes(1 + settingNameLen); if (pBlob[0] == settingNameLen && !memcmp(pBlob + 1, szSetting, settingNameLen)) { MoveAlong(1 + settingNameLen); NeedBytes(5); if (isStatic && (pBlob[0] & DBVTF_VARIABLELENGTH) && VLT(dbv->type) != VLT(pBlob[0])) return 1; BYTE iType = dbv->type = pBlob[0]; switch (iType) { case DBVT_DELETED: /* this setting is deleted */ dbv->type = DBVT_DELETED; return 2; case DBVT_BYTE: dbv->bVal = pBlob[1]; break; case DBVT_WORD: memmove(&(dbv->wVal), (PWORD)(pBlob + 1), 2); break; case DBVT_DWORD: memmove(&(dbv->dVal), (PDWORD)(pBlob + 1), 4); break; case DBVT_UTF8: case DBVT_ASCIIZ: varLen = *(PWORD)(pBlob + 1); NeedBytes(int(3 + varLen)); if (isStatic) { dbv->cchVal--; if (varLen < dbv->cchVal) dbv->cchVal = varLen; memmove(dbv->pszVal, pBlob + 3, dbv->cchVal); // decode dbv->pszVal[dbv->cchVal] = 0; dbv->cchVal = varLen; } else { dbv->pszVal = (char*)mir_alloc(1 + varLen); memmove(dbv->pszVal, pBlob + 3, varLen); dbv->pszVal[varLen] = 0; } break; case DBVT_BLOB: varLen = *(PWORD)(pBlob + 1); NeedBytes(int(3 + varLen)); if (isStatic) { if (varLen < dbv->cpbVal) dbv->cpbVal = varLen; memmove(dbv->pbVal, pBlob + 3, dbv->cpbVal); } else { dbv->pbVal = (BYTE *)mir_alloc(varLen); memmove(dbv->pbVal, pBlob + 3, varLen); } dbv->cpbVal = varLen; break; case DBVT_ENCRYPTED: if (m_crypto == NULL) return 1; else { varLen = *(PWORD)(pBlob + 1); NeedBytes(int(3 + varLen)); size_t realLen; ptrA decoded(m_crypto->decodeString(pBlob + 3, varLen, &realLen)); if (decoded == NULL) return 1; varLen = (WORD)realLen; dbv->type = DBVT_UTF8; if (isStatic) { dbv->cchVal--; if (varLen < dbv->cchVal) dbv->cchVal = varLen; memmove(dbv->pszVal, decoded, dbv->cchVal); dbv->pszVal[dbv->cchVal] = 0; dbv->cchVal = varLen; } else { dbv->pszVal = (char*)mir_alloc(1 + varLen); memmove(dbv->pszVal, decoded, varLen); dbv->pszVal[varLen] = 0; } } break; } /**** add to cache **********************/ if (iType != DBVT_BLOB && iType != DBVT_ENCRYPTED) { DBVARIANT *pCachedValue = m_cache->GetCachedValuePtr(contactID, szCachedSettingName, 1); if (pCachedValue != NULL) { m_cache->SetCachedVariant(dbv, pCachedValue); log3("set cached [%08p] %s (%p)", hContact, szCachedSettingName, pCachedValue); } } return 0; } NeedBytes(1); MoveAlong(pBlob[0] + 1); NeedBytes(3); MoveAlong(1 + GetSettingValueLength(pBlob)); NeedBytes(1); } } // try to get the missing mc setting from the active sub if (cc && cc->IsMeta() && ValidLookupName(szModule, szSetting)) { if (contactID = db_mc_getDefault(contactID)) { if (szModule = GetContactProto(contactID)) { moduleNameLen = (int)mir_strlen(szModule); goto LBL_Seek; } } } logg(); return 1; }
int CDbxKV::GetContactSettingWorker(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv, int isStatic) { if (szSetting == NULL || szModule == NULL) return 1; // the db format can't tolerate more than 255 bytes of space (incl. null) for settings+module name int settingNameLen = (int)strlen(szSetting); int moduleNameLen = (int)strlen(szModule); if (settingNameLen > 0xFE) { #ifdef _DEBUG OutputDebugStringA("GetContactSettingWorker() got a > 255 setting name length. \n"); #endif return 1; } if (moduleNameLen > 0xFE) { #ifdef _DEBUG OutputDebugStringA("GetContactSettingWorker() got a > 255 module name length. \n"); #endif return 1; } mir_cslock lck(m_csDbAccess); LBL_Seek: char *szCachedSettingName = m_cache->GetCachedSetting(szModule, szSetting, moduleNameLen, settingNameLen); DBVARIANT *pCachedValue = m_cache->GetCachedValuePtr(contactID, szCachedSettingName, 0); if (pCachedValue != NULL) { if (pCachedValue->type == DBVT_ASCIIZ || pCachedValue->type == DBVT_UTF8) { int cbOrigLen = dbv->cchVal; char *cbOrigPtr = dbv->pszVal; memcpy(dbv, pCachedValue, sizeof(DBVARIANT)); if (isStatic) { int cbLen = 0; if (pCachedValue->pszVal != NULL) cbLen = (int)strlen(pCachedValue->pszVal); cbOrigLen--; dbv->pszVal = cbOrigPtr; if (cbLen < cbOrigLen) cbOrigLen = cbLen; memcpy(dbv->pszVal, pCachedValue->pszVal, cbOrigLen); dbv->pszVal[cbOrigLen] = 0; dbv->cchVal = cbLen; } else { dbv->pszVal = (char*)mir_alloc(strlen(pCachedValue->pszVal) + 1); strcpy(dbv->pszVal, pCachedValue->pszVal); } } else memcpy(dbv, pCachedValue, sizeof(DBVARIANT)); return (pCachedValue->type == DBVT_DELETED) ? 1 : 0; } // never look db for the resident variable if (szCachedSettingName[-1] != 0) return 1; DBCachedContact *cc = (contactID) ? m_cache->GetCachedContact(contactID) : NULL; DBSettingSortingKey keySearch; keySearch.dwContactID = contactID; keySearch.dwOfsModule = GetModuleNameOfs(szModule); strncpy_s(keySearch.szSettingName, szSetting, _TRUNCATE); ham_key_t key = { 2 * sizeof(DWORD) + settingNameLen, &keySearch }; ham_record_t rec = { 0 }; if (ham_db_find(m_dbSettings, NULL, &key, &rec, 0)) { // try to get the missing mc setting from the active sub if (cc && cc->IsMeta() && ValidLookupName(szModule, szSetting)) { if (contactID = db_mc_getDefault(contactID)) { if (szModule = GetContactProto(contactID)) { moduleNameLen = (int)strlen(szModule); goto LBL_Seek; } } } return 1; } BYTE *pBlob = (BYTE*)rec.data; if (isStatic && (pBlob[0] & DBVTF_VARIABLELENGTH) && VLT(dbv->type) != VLT(pBlob[0])) return 1; int varLen; BYTE iType = dbv->type = pBlob[0]; pBlob++; switch (iType) { case DBVT_DELETED: /* this setting is deleted */ dbv->type = DBVT_DELETED; return 2; case DBVT_BYTE: dbv->bVal = *pBlob; break; case DBVT_WORD: dbv->wVal = *(WORD*)pBlob; break; case DBVT_DWORD: dbv->dVal = *(DWORD*)pBlob; break; case DBVT_UTF8: case DBVT_ASCIIZ: varLen = *(WORD*)pBlob; pBlob += 2; if (isStatic) { dbv->cchVal--; if (varLen < dbv->cchVal) dbv->cchVal = varLen; memmove(dbv->pszVal, pBlob, dbv->cchVal); // decode dbv->pszVal[dbv->cchVal] = 0; dbv->cchVal = varLen; } else { dbv->pszVal = (char*)mir_alloc(1 + varLen); memmove(dbv->pszVal, pBlob, varLen); dbv->pszVal[varLen] = 0; } break; case DBVT_BLOB: varLen = *(WORD*)pBlob; pBlob += 2; if (isStatic) { if (varLen < dbv->cpbVal) dbv->cpbVal = varLen; memmove(dbv->pbVal, pBlob, dbv->cpbVal); } else { dbv->pbVal = (BYTE *)mir_alloc(varLen); memmove(dbv->pbVal, pBlob, varLen); } dbv->cpbVal = varLen; break; case DBVT_ENCRYPTED: if (m_crypto == NULL) return 1; varLen = *(WORD*)pBlob; pBlob += 2; size_t realLen; ptrA decoded(m_crypto->decodeString(pBlob, varLen, &realLen)); if (decoded == NULL) return 1; varLen = (WORD)realLen; dbv->type = DBVT_UTF8; if (isStatic) { dbv->cchVal--; if (varLen < dbv->cchVal) dbv->cchVal = varLen; memmove(dbv->pszVal, decoded, dbv->cchVal); dbv->pszVal[dbv->cchVal] = 0; dbv->cchVal = varLen; } else { dbv->pszVal = (char*)mir_alloc(1 + varLen); memmove(dbv->pszVal, decoded, varLen); dbv->pszVal[varLen] = 0; } break; } /**** add to cache **********************/ if (iType != DBVT_BLOB && iType != DBVT_ENCRYPTED) { DBVARIANT *pCachedValue = m_cache->GetCachedValuePtr(contactID, szCachedSettingName, 1); if (pCachedValue != NULL) m_cache->SetCachedVariant(dbv, pCachedValue); } return 0; }
STDMETHODIMP_(BOOL) CDb3Mmap::DeleteEvent(MCONTACT contactID, HANDLE hDbEvent) { DBCachedContact *cc; if (contactID) { if ((cc = m_cache->GetCachedContact(contactID)) == NULL) return 2; if (cc->IsSub()) if ((cc = m_cache->GetCachedContact(cc->parentID)) == NULL) return 3; } else cc = NULL; mir_cslockfull lck(m_csDbAccess); DWORD ofsContact = (cc) ? cc->dwDriverData : m_dbHeader.ofsUser; DBContact dbc = *(DBContact*)DBRead(ofsContact, sizeof(DBContact), NULL); DBEvent dbe = *(DBEvent*)DBRead((DWORD)hDbEvent, sizeof(DBEvent), NULL); if (dbc.signature != DBCONTACT_SIGNATURE || dbe.signature != DBEVENT_SIGNATURE) return 1; lck.unlock(); log1("delete event @ %08x", hContact); // call notifier while outside mutex NotifyEventHooks(hEventDeletedEvent, contactID, (LPARAM)hDbEvent); // get back in lck.lock(); dbc = *(DBContact*)DBRead(ofsContact, sizeof(DBContact), NULL); dbe = *(DBEvent*)DBRead((DWORD)hDbEvent, sizeof(DBEvent), NULL); // check if this was the first unread, if so, recalc the first unread if (dbc.ofsFirstUnread == (DWORD)hDbEvent) { for (DBEvent *dbeNext = &dbe;;) { if (dbeNext->ofsNext == 0) { dbc.ofsFirstUnread = 0; dbc.tsFirstUnread = 0; break; } DWORD ofsThis = dbeNext->ofsNext; dbeNext = (DBEvent*)DBRead(ofsThis, sizeof(DBEvent), NULL); if (!dbeNext->markedRead()) { dbc.ofsFirstUnread = ofsThis; dbc.tsFirstUnread = dbeNext->timestamp; break; } } } // get previous and next events in chain and change offsets if (dbe.ofsPrev == 0) { if (dbe.ofsNext == 0) dbc.ofsFirstEvent = dbc.ofsLastEvent = 0; else { DBEvent *dbeNext = (DBEvent*)DBRead(dbe.ofsNext, sizeof(DBEvent), NULL); dbeNext->ofsPrev = 0; DBWrite(dbe.ofsNext, dbeNext, sizeof(DBEvent)); dbc.ofsFirstEvent = dbe.ofsNext; } } else { if (dbe.ofsNext == 0) { DBEvent *dbePrev = (DBEvent*)DBRead(dbe.ofsPrev, sizeof(DBEvent), NULL); dbePrev->ofsNext = 0; DBWrite(dbe.ofsPrev, dbePrev, sizeof(DBEvent)); dbc.ofsLastEvent = dbe.ofsPrev; } else { DBEvent *dbePrev = (DBEvent*)DBRead(dbe.ofsPrev, sizeof(DBEvent), NULL); dbePrev->ofsNext = dbe.ofsNext; DBWrite(dbe.ofsPrev, dbePrev, sizeof(DBEvent)); DBEvent *dbeNext = (DBEvent*)DBRead(dbe.ofsNext, sizeof(DBEvent), NULL); dbeNext->ofsPrev = dbe.ofsPrev; DBWrite(dbe.ofsNext, dbeNext, sizeof(DBEvent)); } } // decrement event count dbc.eventCount--; DBWrite(ofsContact, &dbc, sizeof(DBContact)); // delete event DeleteSpace((DWORD)hDbEvent, offsetof(DBEvent, blob) + dbe.cbBlob); // also update a sub if (cc && dbe.contactID != cc->contactID) { DBContact *pSub = (DBContact*)DBRead(GetContactOffset(dbe.contactID), sizeof(DBContact), NULL); if (pSub->eventCount > 0) pSub->eventCount--; } DBFlush(0); return 0; }
STDMETHODIMP_(HANDLE) CDb3Mmap::AddEvent(MCONTACT contactID, DBEVENTINFO *dbei) { if (dbei == NULL || dbei->cbSize != sizeof(DBEVENTINFO)) return 0; if (dbei->timestamp == 0) return 0; DBEvent dbe; dbe.signature = DBEVENT_SIGNATURE; dbe.contactID = contactID; // store native or subcontact's id dbe.timestamp = dbei->timestamp; dbe.flags = dbei->flags; dbe.wEventType = dbei->eventType; dbe.cbBlob = dbei->cbBlob; BYTE *pBlob = dbei->pBlob; MCONTACT contactNotifyID = contactID; DBCachedContact *ccSub = NULL; if (contactID != 0) { DBCachedContact *cc = m_cache->GetCachedContact(contactID); if (cc == NULL) return NULL; if (cc->IsSub()) { ccSub = cc; // set default sub to the event's source db_mc_setDefault(cc->parentID, contactID, false); contactID = cc->parentID; // and add an event to a metahistory if (db_mc_isEnabled()) contactNotifyID = contactID; } } if (NotifyEventHooks(hEventFilterAddedEvent, contactNotifyID, (LPARAM)dbei)) return NULL; mir_ptr<BYTE> pCryptBlob; if (m_bEncrypted) { size_t len; BYTE *pResult = m_crypto->encodeBuffer(pBlob, dbe.cbBlob, &len); if (pResult != NULL) { pCryptBlob = pBlob = pResult; dbe.cbBlob = (DWORD)len; dbe.flags |= DBEF_ENCRYPTED; } } bool neednotify; mir_cslockfull lck(m_csDbAccess); DWORD ofsContact = GetContactOffset(contactID); DBContact dbc = *(DBContact*)DBRead(ofsContact, sizeof(DBContact), NULL); if (dbc.signature != DBCONTACT_SIGNATURE) return NULL; DWORD ofsNew = CreateNewSpace(offsetof(DBEvent, blob) + dbe.cbBlob); dbe.ofsModuleName = GetModuleNameOfs(dbei->szModule); // find where to put it - sort by timestamp if (dbc.eventCount == 0) { dbe.ofsPrev = dbe.ofsNext = 0; dbc.ofsFirstEvent = dbc.ofsLastEvent = ofsNew; } else { DBEvent *dbeTest = (DBEvent*)DBRead(dbc.ofsFirstEvent, sizeof(DBEvent), NULL); // Should new event be placed before first event in chain? if (dbe.timestamp < dbeTest->timestamp) { dbe.ofsPrev = 0; dbe.ofsNext = dbc.ofsFirstEvent; dbc.ofsFirstEvent = ofsNew; dbeTest = (DBEvent*)DBRead(dbe.ofsNext, sizeof(DBEvent), NULL); dbeTest->ofsPrev = ofsNew; DBWrite(dbe.ofsNext, dbeTest, sizeof(DBEvent)); } else { // Loop through the chain, starting at the end DWORD ofsThis = dbc.ofsLastEvent; dbeTest = (DBEvent*)DBRead(ofsThis, sizeof(DBEvent), NULL); for (;;) { // If the new event's timesstamp is equal to or greater than the // current dbevent, it will be inserted after. If not, continue // with the previous dbevent in chain. if (dbe.timestamp >= dbeTest->timestamp) { dbe.ofsPrev = ofsThis; dbe.ofsNext = dbeTest->ofsNext; dbeTest->ofsNext = ofsNew; DBWrite(ofsThis, dbeTest, sizeof(DBEvent)); if (dbe.ofsNext == 0) dbc.ofsLastEvent = ofsNew; else { dbeTest = (DBEvent*)DBRead(dbe.ofsNext, sizeof(DBEvent), NULL); dbeTest->ofsPrev = ofsNew; DBWrite(dbe.ofsNext, dbeTest, sizeof(DBEvent)); } break; } ofsThis = dbeTest->ofsPrev; dbeTest = (DBEvent*)DBRead(ofsThis, sizeof(DBEvent), NULL); } } } dbc.eventCount++; if (!(dbe.flags & (DBEF_READ | DBEF_SENT))) { if (dbe.timestamp < dbc.tsFirstUnread || dbc.tsFirstUnread == 0) { dbc.tsFirstUnread = dbe.timestamp; dbc.ofsFirstUnread = ofsNew; } neednotify = true; } else neednotify = m_safetyMode; if (ccSub != NULL) { DBContact *pSub = (DBContact*)DBRead(ccSub->dwDriverData, sizeof(DBContact), NULL); pSub->eventCount++; } DBWrite(ofsContact, &dbc, sizeof(DBContact)); DBWrite(ofsNew, &dbe, offsetof(DBEvent, blob)); DBWrite(ofsNew + offsetof(DBEvent, blob), pBlob, dbe.cbBlob); DBFlush(0); lck.unlock(); log1("add event @ %08x", ofsNew); // Notify only in safe mode or on really new events if (neednotify) NotifyEventHooks(hEventAddedEvent, contactNotifyID, (LPARAM)ofsNew); return (HANDLE)ofsNew; }