Esempio n. 1
0
MEVENT CSkypeProto::GetMessageFromDb(MCONTACT hContact, const char *messageId, LONGLONG timestamp)
{
	if (messageId == NULL)
		return NULL;

	timestamp -= 600; // we check events written 10 minutes ago
	size_t messageIdLength = mir_strlen(messageId);

	mir_cslock lock(messageSyncLock);
	for (MEVENT hDbEvent = db_event_last(hContact); hDbEvent; hDbEvent = db_event_prev(hContact, hDbEvent))
	{
		DBEVENTINFO dbei = { sizeof(dbei) };
		dbei.cbBlob = db_event_getBlobSize(hDbEvent);

		if (dbei.cbBlob < messageIdLength)
			continue;

		mir_ptr<BYTE> blob((PBYTE)mir_alloc(dbei.cbBlob));
		dbei.pBlob = blob;
		db_event_get(hDbEvent, &dbei);

		size_t cbLen = mir_strlen((char*)dbei.pBlob);
		if (memcmp(&dbei.pBlob[cbLen + 1], messageId, messageIdLength) == 0)
			return hDbEvent;

		if (dbei.timestamp < timestamp)
			break;
	}

	return NULL;
}
Esempio n. 2
0
DWORD INTSORT_GetLastMsgTime(MCONTACT hContact)
{
	for (MEVENT hDbEvent = db_event_last(hContact); hDbEvent; hDbEvent = db_event_prev(hContact, hDbEvent)) {
		DBEVENTINFO dbei = { sizeof(dbei) };
		db_event_get(hDbEvent, &dbei);
		if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT))
			return dbei.timestamp;
	}
	return 0;
}
Esempio n. 3
0
//************************************************************************
// updates the message count for the specified contact
//************************************************************************
void CContactList::UpdateMessageCounter(CListEntry<CContactListEntry*,CContactListGroup*> *pContactEntry)
{
	CContactListEntry *pEntry = GetContactData(pContactEntry);
	if(!pEntry) {
		return;
	}
	int iOldMessages = pEntry->iMessages;

	bool bSort = false;
	HANDLE hEvent= NULL;

	hEvent = db_event_firstUnread(pEntry->hHandle);
	if(CAppletManager::IsMessageWindowOpen(pEntry->hHandle) || (hEvent == NULL && pEntry->iMessages > 0))
	{
		pEntry->iMessages = 0;
		bSort = true;
	}
	else
	{
		pEntry->iMessages = 0;
		HANDLE hLastEvent = db_event_last(pEntry->hHandle);
		while(hLastEvent != NULL && hEvent != NULL)
		{
			pEntry->iMessages++;
			if(hLastEvent == hEvent)
				break;
			hLastEvent = db_event_prev(hLastEvent);
		}
	}
	if(pEntry->iMessages >= 100)
		pEntry->strMessages = _T(">99");
	else
	{
		char buffer[8];
		buffer[0] = 0;
		itoa(pEntry->iMessages,buffer,10);
		pEntry->strMessages = toTstring(buffer);
	}

	CListContainer<CContactListEntry*,CContactListGroup*>* pContainer = ((CListContainer<CContactListEntry*,CContactListGroup*>*)pContactEntry->GetParent());
	// Update the contacts group if it has one
	if(pContainer->GetType() != ROOT)
	{
		// Update the groups event count
		if(iOldMessages != 0 && pEntry->iMessages == 0)
			ChangeGroupObjectCounters(pContainer->GetGroupData()->strPath,0,0,-1);
		else if(iOldMessages == 0 && pEntry->iMessages != 0)
			ChangeGroupObjectCounters(pContainer->GetGroupData()->strPath,0,0,1);
		else
			return;
		
		// sort the groups parent
		((CListContainer<CContactListEntry*,CContactListGroup*>*)pContainer->GetParent())->sort(CContactList::CompareEntries);
	}
}
Esempio n. 4
0
LONGLONG GetLastSentMessageTime(MCONTACT hContact)
{
	for (MEVENT hDbEvent = db_event_last(hContact); hDbEvent; hDbEvent = db_event_prev(hContact, hDbEvent))
	{
		DBEVENTINFO dbei = { sizeof(dbei) };
		db_event_get(hDbEvent, &dbei);
		if (FLAG_CONTAINS(dbei.flags, DBEF_SENT))
			return dbei.timestamp;
	}
	return -1;
}
Esempio n. 5
0
DWORD CompareContacts2_getLMTime(MCONTACT hContact)
{
	MEVENT hDbEvent = db_event_last(hContact);
	while (hDbEvent) {
		DBEVENTINFO dbei = { sizeof(dbei) };
		db_event_get(hDbEvent, &dbei);
		if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT))
			return dbei.timestamp;
		hDbEvent = db_event_prev(hContact, hDbEvent);
	}
	return 0;
}
Esempio n. 6
0
time_t getLastInputMsg(MCONTACT hContact)
{
	MEVENT hDbEvent = db_event_last(hContact);
	while (hDbEvent) {
		DBEVENTINFO dbei = {};
		db_event_get(hDbEvent, &dbei);
		if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT))
			return dbei.timestamp;
		hDbEvent = db_event_prev(hContact, hDbEvent);
	}
	return -1;
}
Esempio n. 7
0
/**
 * calculate message frequency for a single contact
 */
static void MF_CalcFrequency(MCONTACT hContact, DWORD dwCutoffDays, int doSleep)
{
    DWORD     curTime = time(NULL);
    DWORD     frequency, eventCount;
    DBEVENTINFO dbei = {0};
    MEVENT hEvent = db_event_last(hContact);

    eventCount = 0;
    dbei.cbSize = sizeof(dbei);
    dbei.timestamp = 0;

    while(hEvent) {
        dbei.cbBlob = 0;
        dbei.pBlob = NULL;
        db_event_get(hEvent, &dbei);

        if(dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT)) { // record time of last event
            eventCount++;
        }
		/*
		 * consider the most recent 100 messages and ignore messages that are older than the cutoff days.
		 * this will prevent contacts with a high message rate in the past to keep occupying the 
		 * top positions forever.
		 */
        if(eventCount >= 100 || dbei.timestamp < curTime - (dwCutoffDays * 86400))
            break;
        hEvent = db_event_prev(hContact, hEvent);
		// check for main update thread still running (if not, application is shutting down, so terminate our work)
        if(doSleep && mf_updatethread_running == FALSE)
            return;
        if(doSleep)
            Sleep(100);
    }

    if(eventCount == 0) {
        frequency = 0x7fffffff;
        cfg::writeDword(hContact, "CList", "mf_firstEvent", curTime - (dwCutoffDays * 86400));
    }
    else {
        frequency = (curTime - dbei.timestamp) / eventCount;
        cfg::writeDword(hContact, "CList", "mf_firstEvent", dbei.timestamp);
    }

    cfg::writeDword(hContact, "CList", "mf_freq", frequency);
    cfg::writeDword(hContact, "CList", "mf_count", eventCount);
}
Esempio n. 8
0
static void FillHistoryThread(void* param)
{
	Thread_SetName("HistoryWindow::FillHistoryThread");

	THistoryThread *hInfo = (THistoryThread*)param;
	HWND hwndList = GetDlgItem(hInfo->hwnd, IDC_LIST);

	SendDlgItemMessage(hInfo->hwnd, IDC_LIST, LB_RESETCONTENT, 0, 0);
	int i = db_event_count(hInfo->hContact);
	SendDlgItemMessage(hInfo->hwnd, IDC_LIST, LB_INITSTORAGE, i, i * 40);

	DBEVENTINFO dbei = { sizeof(dbei) };
	int oldBlobSize = 0;
	MEVENT hDbEvent = db_event_last(hInfo->hContact);

	while (hDbEvent != NULL) {
		if (!IsWindow(hInfo->hwnd))
			break;
		int newBlobSize = db_event_getBlobSize(hDbEvent);
		if (newBlobSize > oldBlobSize) {
			dbei.pBlob = (PBYTE)mir_realloc(dbei.pBlob, newBlobSize);
			oldBlobSize = newBlobSize;
		}
		dbei.cbBlob = oldBlobSize;
		db_event_get(hDbEvent, &dbei);

		TCHAR str[200], eventText[256], strdatetime[64];
		GetObjectSummary(&dbei, str, _countof(str));
		if (str[0]) {
			TimeZone_PrintTimeStamp(NULL, dbei.timestamp, _T("d t"), strdatetime, _countof(strdatetime), 0);
			mir_sntprintf(eventText, _T("%s: %s"), strdatetime, str);
			i = SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)eventText);
			SendMessage(hwndList, LB_SETITEMDATA, i, (LPARAM)hDbEvent);
		}
		hDbEvent = db_event_prev(hInfo->hContact, hDbEvent);
	}
	mir_free(dbei.pBlob);

	SendDlgItemMessage(hInfo->hwnd, IDC_LIST, LB_SETCURSEL, 0, 0);
	SendMessage(hInfo->hwnd, WM_COMMAND, MAKEWPARAM(IDC_LIST, LBN_SELCHANGE), 0);
	EnableWindow(GetDlgItem(hInfo->hwnd, IDC_LIST), TRUE);
	mir_free(hInfo);
}
Esempio n. 9
0
static int lua_EventReverseIterator(lua_State *L)
{
	MCONTACT hContact = luaL_checkinteger(L, lua_upvalueindex(1));
	MEVENT hEvent = luaL_checkinteger(L, lua_upvalueindex(2));

	hEvent = hEvent == NULL
		? db_event_last(hContact)
		: db_event_prev(hContact, hEvent);

	if (hEvent)
	{
		lua_pushinteger(L, hContact);
		lua_pushvalue(L, -1);
		lua_replace(L, lua_upvalueindex(2));
	}
	else
		lua_pushnil(L);

	return 1;
}
Esempio n. 10
0
static void MF_CalcFrequency(MCONTACT hContact, DWORD dwCutoffDays, int doSleep)
{
	DWORD  curTime = time(NULL);
	DWORD  frequency, eventCount;
	MEVENT hEvent = db_event_last(hContact);

	eventCount = 0;

	DBEVENTINFO dbei = { sizeof(dbei) };
	while (hEvent) {
		db_event_get(hEvent, &dbei);

		if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT)) { // record time of last event
			eventCount++;
		}
		if (eventCount >= 100 || dbei.timestamp < curTime - (dwCutoffDays * 86400))
			break;
		hEvent = db_event_prev(hContact, hEvent);
		if (doSleep && mf_updatethread_running == FALSE)
			return;
		if (doSleep)
			Sleep(100);
	}

	if (eventCount == 0) {
		frequency = 0x7fffffff;
		cfg::writeDword(hContact, "CList", "mf_firstEvent", curTime - (dwCutoffDays * 86400));
	}
	else {
		frequency = (curTime - dbei.timestamp) / eventCount;
		cfg::writeDword(hContact, "CList", "mf_firstEvent", dbei.timestamp);
	}

	cfg::writeDword(hContact, "CList", "mf_freq", frequency);
	cfg::writeDword(hContact, "CList", "mf_count", eventCount);
}
Esempio n. 11
0
// Returns TRUE if the event already exist in the database
BOOL IsDuplicateEvent(MCONTACT hContact, DBEVENTINFO& dbei)
{
	HANDLE hExistingDbEvent;
	DWORD dwEventTimeStamp;

	// get last event
	if (!(hExistingDbEvent = db_event_last(hContact)))
		return FALSE;

	DBEVENTINFO dbeiExisting = { sizeof(dbeiExisting) };
	db_event_get(hExistingDbEvent, &dbeiExisting);
	dwEventTimeStamp = dbeiExisting.timestamp;

	// compare with last timestamp
	if (dbei.timestamp > dwEventTimeStamp) {
		// remember event
		hPreviousDbEvent = hExistingDbEvent;
		dwPreviousTimeStamp = dwEventTimeStamp;
		return FALSE;
	}

	if (hContact != hPreviousContact) {
		hPreviousContact = hContact;
		// remember event
		hPreviousDbEvent = hExistingDbEvent;
		dwPreviousTimeStamp = dwEventTimeStamp;

		// get first event
		if (!(hExistingDbEvent = db_event_first(hContact)))
			return FALSE;

		memset(&dbeiExisting, 0, sizeof(dbeiExisting));
		dbeiExisting.cbSize = sizeof(dbeiExisting);
		db_event_get(hExistingDbEvent, &dbeiExisting);
		dwEventTimeStamp = dbeiExisting.timestamp;

		// compare with first timestamp
		if (dbei.timestamp <= dwEventTimeStamp) {
			// remember event
			dwPreviousTimeStamp = dwEventTimeStamp;
			hPreviousDbEvent = hExistingDbEvent;

			if ( dbei.timestamp != dwEventTimeStamp )
				return FALSE;
		}
	}

	// check for equal timestamps
	if (dbei.timestamp == dwPreviousTimeStamp) {
		memset(&dbeiExisting, 0, sizeof(dbeiExisting));
		dbeiExisting.cbSize = sizeof(dbeiExisting);
		db_event_get(hPreviousDbEvent, &dbeiExisting);

		if ((dbei.timestamp == dbeiExisting.timestamp) &&
			(dbei.eventType == dbeiExisting.eventType) &&
			(dbei.cbBlob == dbeiExisting.cbBlob) &&
			((dbei.flags&DBEF_SENT) == (dbeiExisting.flags&DBEF_SENT)))
			return TRUE;

		// find event with another timestamp
		hExistingDbEvent = db_event_next(hContact, hPreviousDbEvent);
		while (hExistingDbEvent != NULL) {
			memset(&dbeiExisting, 0, sizeof(dbeiExisting));
			dbeiExisting.cbSize = sizeof(dbeiExisting);
			db_event_get(hExistingDbEvent, &dbeiExisting);

			if (dbeiExisting.timestamp != dwPreviousTimeStamp) {
				// use found event
				hPreviousDbEvent = hExistingDbEvent;
				dwPreviousTimeStamp = dbeiExisting.timestamp;
				break;
			}

			hPreviousDbEvent = hExistingDbEvent;
			hExistingDbEvent = db_event_next(hContact, hExistingDbEvent);
		}
	}

	hExistingDbEvent = hPreviousDbEvent;

	if (dbei.timestamp <= dwPreviousTimeStamp) {
		// look back
		while (hExistingDbEvent != NULL) {
			memset(&dbeiExisting, 0, sizeof(dbeiExisting));
			dbeiExisting.cbSize = sizeof(dbeiExisting);
			db_event_get(hExistingDbEvent, &dbeiExisting);

			if (dbei.timestamp > dbeiExisting.timestamp) {
				// remember event
				hPreviousDbEvent = hExistingDbEvent;
				dwPreviousTimeStamp = dbeiExisting.timestamp;
				return FALSE;
			}

			// Compare event with import candidate
			if ((dbei.timestamp == dbeiExisting.timestamp) &&
				(dbei.eventType == dbeiExisting.eventType) &&
				(dbei.cbBlob == dbeiExisting.cbBlob) &&
				((dbei.flags & DBEF_SENT) == (dbeiExisting.flags & DBEF_SENT)))
			{
				// remember event
				hPreviousDbEvent = hExistingDbEvent;
				dwPreviousTimeStamp = dbeiExisting.timestamp;
				return TRUE;
			}

			// Get previous event in chain
			hExistingDbEvent = db_event_prev(hContact, hExistingDbEvent);
		}
	}
	else {
		// look forward
		while (hExistingDbEvent != NULL) {
			memset(&dbeiExisting, 0, sizeof(dbeiExisting));
			dbeiExisting.cbSize = sizeof(dbeiExisting);
			db_event_get(hExistingDbEvent, &dbeiExisting);

			if (dbei.timestamp < dbeiExisting.timestamp) {
				// remember event
				hPreviousDbEvent = hExistingDbEvent;
				dwPreviousTimeStamp = dbeiExisting.timestamp;
				return FALSE;
			}

			// Compare event with import candidate
			if ((dbei.timestamp == dbeiExisting.timestamp) &&
				(dbei.eventType == dbeiExisting.eventType) &&
				(dbei.cbBlob == dbeiExisting.cbBlob) &&
				((dbei.flags&DBEF_SENT) == (dbeiExisting.flags&DBEF_SENT)))
			{
				// remember event
				hPreviousDbEvent = hExistingDbEvent;
				dwPreviousTimeStamp = dbeiExisting.timestamp;
				return TRUE;
			}

			// Get next event in chain
			hExistingDbEvent = db_event_next(hContact, hExistingDbEvent);
		}
	}
	// reset last event
	hPreviousContact = INVALID_CONTACT_ID;
	return FALSE;
}
Esempio n. 12
0
//************************************************************************
// loads the contacts history
//************************************************************************
void CChatScreen::LoadHistory()
{
	if(!m_hContact)
		return;

	char *szProto = GetContactProto(m_hContact);
	
	if(m_bIRCProtocol && db_get_b(m_hContact, szProto, "ChatRoom", 0) != 0)
	{
		if(!CAppletManager::GetInstance()->IsIRCHookEnabled())
		{
			time_t now;
			tm tm_now;
			time(&now);
			localtime_s(&tm_now,&now);

			AddIncomingMessage(CAppletManager::TranslateString(_T("IRC-Chatroom support is disabled!\nYou need to install the patched IRC.dll (see the readme) to use IRC-Chatrooms on the LCD")),&tm_now,true);
		}
		else
		{
			CIRCHistory *pHistory = CAppletManager::GetInstance()->GetIRCHistory(m_hContact);
			if(pHistory)
			{
				list<SIRCMessage>::iterator iter = pHistory->LMessages.begin();
				while(iter != pHistory->LMessages.end())
				{
					if((*iter).bIsMe)
						AddOutgoingMessage((*iter).strMessage,&((*iter).Time),true);
					else
						AddIncomingMessage((*iter).strMessage,&((*iter).Time),true);
					iter++;
				}
			}
		}
	}
	else
	{
		// Get last events from database
		CEvent Event;
		list<MEVENT> LHandles;
		MEVENT hEvent = db_event_last(m_hContact);
		MEVENT hUnread = db_event_firstUnread(m_hContact);
		
		if(CConfig::GetBoolSetting(SESSION_LOADDB))
		{
			while(hEvent != NULL && hUnread != NULL)
			{
				LHandles.push_front(hEvent);
				if(CConfig::GetBoolSetting(SESSION_LOADDB) && *(LHandles.begin()) == hUnread)
					break;
				hEvent = db_event_prev(m_hContact, hEvent);
			}
		}
		else
		{
			for (int i = CConfig::GetIntSetting(SESSION_LOGSIZE); i > 0 && hEvent!=NULL; i--)
			{
				LHandles.push_front(hEvent);
				hEvent = db_event_prev(m_hContact, hEvent);
			}
		}

		bool bRead = true;
		while(!(LHandles.empty()))
		{
			if(CAppletManager::TranslateDBEvent(&Event,(LPARAM)m_hContact,(WPARAM)*(LHandles.begin())))
			{
				if(Event.hValue == hUnread)
					bRead = false;
				if(Event.eType == EVENT_MSG_RECEIVED)
				{
					AddIncomingMessage(Event.strValue,&Event.Time);
					if(!bRead && CConfig::GetBoolSetting(SESSION_MARKREAD) && !CAppletManager::IsMessageWindowOpen(m_hContact))
						CAppletManager::MarkMessageAsRead(m_hContact,Event.hValue);
				}
				else
					AddOutgoingMessage(Event.strValue,&Event.Time);

			}		
			LHandles.pop_front();
		}
	}
}
Esempio n. 13
0
static int PrebuildContactMenu(WPARAM hContact, LPARAM)
{
	Menu_ShowItem(hContactMenu, db_event_last(hContact) != NULL);
	return 0;
}
Esempio n. 14
0
void CYahooProto::ext_got_im(const char *me, const char *who, int protocol, const char *msg, 
								long tm, int stat, int utf8, int buddy_icon, 
								const char *seqn, int sendn)
{
	char 		*umsg;
	const char	*c = msg;
	int 		oidx = 0;

	LOG(("YAHOO_GOT_IM id:%s %s: %s (len: %d) tm:%lu stat:%i utf8:%i buddy_icon: %i", me, who, msg, lstrlenA(msg), tm, stat, utf8, buddy_icon));

	if (stat == 2) {
		char z[1024];

		mir_snprintf(z, SIZEOF(z), "Error sending message to %s", who);
		LOG((z));
		ShowError( TranslateT("Yahoo Error"), _A2T(z));
		return;
	}

	if (!msg) {
		LOG(("Empty Incoming Message, exiting."));
		return;
	}

	if (getByte("IgnoreUnknown", 0)) {

		/*
		* Check our buddy list to see if we have it there. And if it's not on the list then we don't accept any IMs.
		*/
		if (getbuddyH(who) == NULL) {
			LOG(("Ignoring unknown user messages. User '%s'. Dropping Message.", who));
			return;
		}
	}

	if ( BuddyIgnored( who )) {
		LOG(("User '%s' on our Ignore List. Dropping Message.", who));
		return;
	}

	// make a bigger buffer for \n -> \r\n conversion (x2)
	umsg = (char *) alloca(lstrlenA(msg) * 2 + 1); 

	while ( *c != '\0') {
		// Strip the font tag
		if (!_strnicmp(c,"<font ",6) || !_strnicmp(c,"</font>",6) ||
			// strip the fade tag
			!_strnicmp(c, "<FADE ",6) || !_strnicmp(c,"</FADE>",7) ||
			// strip the alternate colors tag
			!_strnicmp(c, "<ALT ",5) || !_strnicmp(c, "</ALT>",6)) { 
				while ((*c++ != '>') && (*c != '\0')); 
		} else
			// strip ANSI color combination
			if ((*c == 0x1b) && (*(c+1) == '[')) { 
				while ((*c++ != 'm') && (*c != '\0')); 
			} else

				if (*c != '\0') {
					umsg[oidx++] = *c;

					/* Adding \r to \r\n conversion */
					if (*c == '\r' && *(c + 1) != '\n') 
						umsg[oidx++] = '\n';

					c++;
				}
	}

	umsg[oidx++]= '\0';

	/* Need to strip off formatting stuff first. Then do all decoding/converting */
	LOG(("%s: %s", who, umsg));

	HANDLE hContact = add_buddy(who, who, protocol, PALF_TEMPORARY);
	//setWord(hContact, "yprotoid", protocol);
	Set_Protocol(hContact, protocol);

	PROTORECVEVENT pre = { 0 };
	pre.flags = (utf8) ? PREF_UTF : 0;

	if (tm) {
		HANDLE hEvent = db_event_last(hContact);

		if (hEvent) { // contact has events
			DWORD dummy;
			DBEVENTINFO dbei = { sizeof (dbei) };
			dbei.pBlob = (BYTE*)&dummy;
			dbei.cbBlob = 2;
			if (!db_event_get(hEvent, &dbei)) 
				// got that event, if newer than ts then reset to current time
				if ((DWORD)tm < dbei.timestamp) tm = (long)time(NULL);
		}

		pre.timestamp = (DWORD)time(NULL);
		
		if ((DWORD)tm < pre.timestamp)
			pre.timestamp = tm;
		
	}
	else pre.timestamp = (DWORD)time(NULL);

	pre.szMessage = umsg;
	pre.lParam = 0;

	// Turn off typing
	CallService(MS_PROTO_CONTACTISTYPING, (WPARAM) hContact, PROTOTYPE_CONTACTTYPING_OFF);
	ProtoChainRecvMsg(hContact, &pre);

	// ack the message we just got
	if (seqn)
		yahoo_send_im_ack(m_id, me, who, seqn, sendn);

	if (buddy_icon < 0) return;

	//?? Don't generate floods!!
	setByte(hContact, "AvatarType", (BYTE)buddy_icon);
	if (buddy_icon != 2)
		reset_avatar(hContact);
	else if (getDword(hContact, "PictCK", 0) == 0) /* request the buddy image */
		request_avatar(who); 
}
Esempio n. 15
0
static MEVENT findDbEvent(MCONTACT hContact, MEVENT hDbEvent, int flags)
{
	DBEVENTINFO dbe;
	BOOL bEventOk;

	do {
		memset(&dbe, 0, sizeof(DBEVENTINFO));
		dbe.cbSize = sizeof(DBEVENTINFO);
		dbe.cbBlob = 0;
		dbe.pBlob = NULL;
		if (hContact != NULL) {
			if ((flags & DBE_FIRST) && (flags & DBE_UNREAD)) {
				hDbEvent = db_event_firstUnread(hContact);
				if (hDbEvent == NULL && (flags & DBE_READ))
					hDbEvent = db_event_first(hContact);
			}
			else if (flags & DBE_FIRST)
				hDbEvent = db_event_first(hContact);
			else if (flags & DBE_LAST)
				hDbEvent = db_event_last(hContact);
			else if (flags & DBE_NEXT)
				hDbEvent = db_event_next(hContact, hDbEvent);
			else if (flags & DBE_PREV)
				hDbEvent = db_event_prev(hContact, hDbEvent);
		}
		else {
			MEVENT hMatchEvent = NULL, hSearchEvent = NULL;
			DWORD matchTimestamp = 0, priorTimestamp = 0;

			if (flags & DBE_FIRST) {
				for (MCONTACT hSearchContact = db_find_first(); hSearchContact; hSearchContact = db_find_next(hSearchContact)) {
					hSearchEvent = findDbEvent(hSearchContact, NULL, flags);
					dbe.cbBlob = 0;
					if (!db_event_get(hSearchEvent, &dbe)) {
						if ((dbe.timestamp < matchTimestamp) || (matchTimestamp == 0)) {
							hMatchEvent = hSearchEvent;
							matchTimestamp = dbe.timestamp;
						}
					}
				}
				hDbEvent = hMatchEvent;
			}
			else if (flags & DBE_LAST) {
				for (MCONTACT hSearchContact = db_find_first(); hSearchContact; hSearchContact = db_find_next(hSearchContact)) {
					hSearchEvent = findDbEvent(hSearchContact, NULL, flags);
					dbe.cbBlob = 0;
					if (!db_event_get(hSearchEvent, &dbe)) {
						if ((dbe.timestamp > matchTimestamp) || (matchTimestamp == 0)) {
							hMatchEvent = hSearchEvent;
							matchTimestamp = dbe.timestamp;
						}
					}
				}
				hDbEvent = hMatchEvent;
			}
			else if (flags & DBE_NEXT) {
				dbe.cbBlob = 0;
				if (!db_event_get(hDbEvent, &dbe)) {
					priorTimestamp = dbe.timestamp;
					for (MCONTACT hSearchContact = db_find_first(); hSearchContact; hSearchContact = db_find_next(hSearchContact)) {
						hSearchEvent = findDbEvent(hSearchContact, hDbEvent, flags);
						dbe.cbBlob = 0;
						if (!db_event_get(hSearchEvent, &dbe)) {
							if (((dbe.timestamp < matchTimestamp) || (matchTimestamp == 0)) && (dbe.timestamp > priorTimestamp)) {
								hMatchEvent = hSearchEvent;
								matchTimestamp = dbe.timestamp;
							}
						}
					}
					hDbEvent = hMatchEvent;
				}
			}
			else if (flags & DBE_PREV) {
				if (!db_event_get(hDbEvent, &dbe)) {
					priorTimestamp = dbe.timestamp;
					for (MCONTACT hSearchContact = db_find_first(); hSearchContact; hSearchContact = db_find_next(hSearchContact)) {
						hSearchEvent = findDbEvent(hSearchContact, hDbEvent, flags);
						dbe.cbBlob = 0;
						if (!db_event_get(hSearchEvent, &dbe)) {
							if (((dbe.timestamp > matchTimestamp) || (matchTimestamp == 0)) && (dbe.timestamp < priorTimestamp)) {
								hMatchEvent = hSearchEvent;
								matchTimestamp = dbe.timestamp;
							}
						}
					}
					hDbEvent = hMatchEvent;
				}
			}
		}
		dbe.cbBlob = 0;
		if (db_event_get(hDbEvent, &dbe))
			bEventOk = FALSE;
		else
			bEventOk = isValidDbEvent(&dbe, flags);
		if (!bEventOk) {
			if (flags&DBE_FIRST) {
				flags |= DBE_NEXT;
				flags &= ~DBE_FIRST;
			}
			else if (flags&DBE_LAST) {
				flags |= DBE_PREV;
				flags &= ~DBE_LAST;
			}
		}
	}
	while ((!bEventOk) && (hDbEvent != NULL));

	return hDbEvent;
}