#include <windows.h>
#include <commctrl.h>

#include "resource.h"
#include "scc.h"
#include "scc_gvar.h"
#include "scc_gui.h"
#include "mf0xAB.h"

BOOL thread_launcher(LPTHREAD_START_ROUTINE p_thrfun)
{
    if (!hThr) TerminateThread(hThr, 0);
    hThr = CreateThread(NULL, 0, p_thrfun, NULL, 0, NULL);
    if (hThr)
    {
        SetThreadPriority(hThr, THREAD_PRIORITY_NORMAL);
        return TRUE;
    }
    else
    {
        gui_stbar(TEXT("\x03 Fatal error! Can't create thread!"));
        return FALSE;
    }
}

BOOL thr_scd2gui(BYTE scd, LPTSTR sztp, PBYTE pgui_tp)
{
    DWORD       cnt;
    BOOL        bRet = FALSE;

    if (pgui_tp)
    {
        // search for gui type
        for (cnt = 0; cnt != sizeof(scc_dsc) / sizeof(scc_dsc[0]); cnt++)
        {
            if (scc_dsc[cnt].tp == scd)
            {
                *pgui_tp = (BYTE)cnt;
                bRet = TRUE;
            }
        }
    }
    if (sztp)
    {
        if (scd == SCD_UL) lstrcpy(sztp, TEXT("UL"));
        else if (scd == SCD_CL1K) lstrcpy(sztp, TEXT("CL1K"));
        else if (scd == SCD_CL4K) lstrcpy(sztp, TEXT("CL4K"));
        else if (scd == SCD_CL1K1) lstrcpy(sztp, TEXT("CL1K1"));
        else if (scd == SCD_CL4K1) lstrcpy(sztp, TEXT("CL4K1"));
        else if (scd == SCD_PL2S1) lstrcpy(sztp, TEXT("PL2S1"));
        else if (scd == SCD_PL4S1) lstrcpy(sztp, TEXT("PL4S1"));
        else if (scd == SCD_PL2S2) lstrcpy(sztp, TEXT("PL2S2"));
        else if (scd == SCD_PL4S2) lstrcpy(sztp, TEXT("PL4S2"));
        else if (scd == SCD_PL2S3) lstrcpy(sztp, TEXT("PL2S3"));
        else if (scd == SCD_PL4S3) lstrcpy(sztp, TEXT("PL4S3"));
        else if (scd == SCD_MINI) lstrcpy(sztp, TEXT("MINI"));
        else if (scd == SCD_DF1) lstrcpy(sztp, TEXT("DF1"));
        else if (scd == SCD_DF2) lstrcpy(sztp, TEXT("DF2"));
        else if (scd == SCD_SMMX) lstrcpy(sztp, TEXT("SMMX"));
        else if (scd == SCD_SM1K) lstrcpy(sztp, TEXT("SM1K"));
        else if (scd == SCD_SM2K) lstrcpy(sztp, TEXT("SM2K"));
        else if (scd == SCD_SM4K) lstrcpy(sztp, TEXT("SM4K"));
        else lstrcpy(sztp, TEXT("???"));
    }
    return bRet;
}

void thr_verberr(DWORD err, LPTSTR szErr)
{
    if (err == LERR_SUCCESS) lstrcpy(szErr, TEXT("\2Success!"));
    else if (err == LERR_FAIL) lstrcpy(szErr, TEXT("\3Command execution error!"));
    else if (err == LERR_HARDWARE) lstrcpy(szErr, TEXT("\3Hardware error!"));
    else if (err == LERR_TIMEOUT_TX) lstrcpy(szErr, TEXT("\3Communication error: TX timeout!"));
    else if (err == LERR_TIMEOUT_RX) lstrcpy(szErr, TEXT("\3Communication error: RX timeout!"));
    else if (err == LERR_NOTSYNC) lstrcpy(szErr, TEXT("\3Communication error: synchronization lost!"));
    else if (err == LERR_NOREADER) lstrcpy(szErr, TEXT("\3Can't find reader!"));
    else if (err == LERR_NOCARD) lstrcpy(szErr, TEXT("\3Can't find card!"));
    else if (err == LERR_INVALIDCARD) lstrcpy(szErr, TEXT("\3Invalid card type!"));
    else if (err == LERR_INVALIDKEY) lstrcpy(szErr, TEXT("\3Invalid auth key or card type!"));
    else if (err == LERR_IOERR) lstrcpy(szErr, TEXT("\3I/O error!"));
    else if (err == LERR_DATAREAD) lstrcpy(szErr, TEXT("\3Can't read data from card!"));
    else if (err == LERR_DATAWRITE) lstrcpy(szErr, TEXT("\3Can't write data to card!"));
    else if (err == LERR_BUSY) lstrcpy(szErr, TEXT("\3Device busy error!"));
    else lstrcpy(szErr, TEXT("\3Unknown error!"));
}

DWORD WINAPI t_typesrch(void)
{
    CCR         ccr;
    DWORD       err = LERR_SUCCESS;
    TCHAR       szLocal[256];

    BYTE        r_model = 0, r_hw = 0;
    DWORD       r_sn = 0;

    BYTE        sc_type = SCD_UNKNOWN;
    BYTE        sc_uidlen = 0, sc_uid[SZ_UID];
    WORD        sc_atqa = 0;
    BYTE        sc_sak = 0;
    BYTE        sc_atslen, sc_ats[SZ_ATS];

    szLocal[0] = 0;
    // disable controls
    gui_disen(FALSE);
    gui_stbar(TEXT("\4Search for the type of card..."));

    memset(&ccr, 0, sizeof(ccr));
    if ((cport) && (cbr))
    {
        // open COM device; return LERR_SUCCESS, LERR_HARDWARE
        if ((err = link_comopen(cport, cbr, &ccr)) != LERR_SUCCESS) goto thr_exit;
    }
    else
    {
        // open USB device; return LERR_SUCCESS, LERR_HARDWARE
        if ((err = link_hidopen(0, NULL, &ccr)) != LERR_SUCCESS)
        {
            err = LERR_NOREADER;
            goto thr_exit;
        }
    }
    // DIR-mode initialization
    if ((err = mfInit(&ccr, &r_model, &r_hw, &r_sn)) != LERR_SUCCESS)
    {
        if ((cport) && (cbr) && (err != LERR_HARDWARE)) err = LERR_NOREADER;
        goto thr_exit;
    }
    wsprintf(szLocal, TEXT("RD-0%uAB, SN:%08X, HW:%u.%u"), r_model, r_sn, r_hw >> 4, r_hw & 15);
    SetWindowText(hMain, szLocal);

    gui_setats(0, NULL);                // rst ATS
    gui_setuid(0, NULL);                // rst UID
    gui_setatqasak(NULL, NULL, FALSE);  // rst ATQA & SAK

    // card type detection
    sc_uidlen = MFDM_RWC;
    if ((err = mfType(&ccr, 7, &sc_type, &sc_uidlen, sc_uid, &sc_atqa, &sc_sak, &sc_atslen, sc_ats)) != LERR_SUCCESS) goto thr_exit;
    // storage setup
    szLocal[0] = 2; // status ok
    if (thr_scd2gui(sc_type, &szLocal[1], &scc_set.tp))
    {
        scc_set.rw = (sc_uidlen & MFDM_RWC) ? 1 : 0;
    }
    scc_set.uidlen = sc_uidlen & 15;
    memcpy(scc_set.uid, sc_uid, SZ_UID);
    //gui out
    if ((scc_set.tp == 0) && (scc_set.blk > 15)) scc_set.blk = 0;   // correct page for UL
    if (scc_set.rw) lstrcat(szLocal, TEXT("-RW"));
    wsprintf(&szLocal[lstrlen(szLocal)], TEXT(", ATQA=%04X, SAK=%02X."), sc_atqa, sc_sak);
    gui_setparm();
    gui_setats(sc_atslen, sc_ats);
    gui_setatqasak(sc_atqa, sc_sak, TRUE);

thr_exit:
    if (err) thr_verberr(err, szLocal);
    if (lstrlen(szLocal)) gui_stbar(szLocal);

    if ((link_isopen(&ccr)) && (err != LERR_HARDWARE) && (err != LERR_NOREADER))
    {
        if (err) mfBeep(&ccr, 0x03);    // if fail
        else mfBeep(&ccr, 0x02);        // if success
    }
    link_close(&ccr);

    gui_disen(TRUE);
    return 0;
}

DWORD WINAPI t_aksrch(void)
{
    BYTE defaultKeys[][6] = {
        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // dummy key for copy from dialog control
        { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, // Default key (first key used by program if no user defined key)
        { 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5 }, // NFCForum MAD key
        { 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5 },
        { 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7 }, // NFCForum content key
        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Blank key
        { 0x4D, 0x3A, 0x99, 0xC3, 0x51, 0xDD }, // this & next keys - original mfoc | mfcuk
        { 0x1A, 0x98, 0x2C, 0x7E, 0x45, 0x9A },
        { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF },
        { 0x71, 0x4C, 0x5C, 0x88, 0x6E, 0x97 },
        { 0x58, 0x7E, 0xE5, 0xF9, 0x35, 0x0F },
        { 0xA0, 0x47, 0x8C, 0xC3, 0x90, 0x91 },
        { 0x53, 0x3C, 0xB6, 0xC7, 0x23, 0xF6 },
        { 0x8F, 0xD0, 0xA4, 0xF2, 0x56, 0xE9 } };

    CCR         ccr;
    DWORD       err = LERR_SUCCESS;
    TCHAR       szLocal[256];
    DWORD       cnt;
    BOOL        fnd = FALSE;

    BYTE        r_model = 0, r_hw = 0;
    DWORD       r_sn = 0;

    // disable controls
    gui_disen(FALSE);

    wsprintf(szLocal, TEXT("\4Search authorization key"));
    if (scc_set.tp)
    {
        wsprintf(&szLocal[lstrlen(szLocal)], TEXT(" for the %c%u:%u"),
            (scc_set.blk < 128) ? (((scc_set.blk & 3) == 3) ? 'T' : 'S') : (((scc_set.blk & 15) == 15) ? 'T' : 'S'),
            (scc_set.blk < 128) ? scc_set.blk / 4 : scc_set.blk / 16 + 24,
            (scc_set.blk < 128) ? scc_set.blk & 3 : scc_set.blk & 15);
    }
    lstrcat(szLocal, TEXT("..."));
    gui_stbar(szLocal);

    memset(&ccr, 0, sizeof(ccr));
    // open USB device; return LERR_SUCCESS, LERR_HARDWARE
    if ((err = link_hidopen(0, NULL, &ccr)) != LERR_SUCCESS)
    {
        err = LERR_NOREADER;
        goto thr_exit;
    }
    // DIR-mode initialization
    if ((err = mfInit(&ccr, &r_model, &r_hw, &r_sn)) != LERR_SUCCESS) goto thr_exit;
    wsprintf(szLocal, TEXT("RD-0%uAB, SN:%08X, HW:%u.%u"), r_model, r_sn, r_hw >> 4, r_hw & 15);
    SetWindowText(hMain, szLocal);

    memcpy(&defaultKeys[0], scc_set.ak, 6); // set key from dialog control
    // search loop
    for (cnt = 0; cnt != sizeof(defaultKeys) / sizeof(defaultKeys[0]); cnt++)
    {
        if ((cnt) && (!memcmp(defaultKeys[cnt], defaultKeys[0], 6))) continue;  // skip ak if checked

        wsprintf(szLocal, TEXT("\4Probe %u/%u, AK=%02X%02X%02X%02X%02X%02X for the %c%u:%u..."),
            cnt + 1, sizeof(defaultKeys) / sizeof(defaultKeys[0]),
            defaultKeys[cnt][0], defaultKeys[cnt][1], defaultKeys[cnt][2], defaultKeys[cnt][3], defaultKeys[cnt][4], defaultKeys[cnt][5],
            (scc_set.blk < 128) ? (((scc_set.blk & 3) == 3) ? 'T' : 'S') : (((scc_set.blk & 15) == 15) ? 'T' : 'S'),
            (scc_set.blk < 128) ? scc_set.blk / 4 : scc_set.blk / 16 + 24,
            (scc_set.blk < 128) ? scc_set.blk & 3 : scc_set.blk & 15);
        gui_stbar(szLocal);

        // set authorization key
        if ((err = mfSetAK(&ccr, 0, defaultKeys[cnt])) != LERR_SUCCESS) goto thr_exit;
        // data block authorization only then card halted
        if (((err = mfAuth(&ccr, 4, (scc_set.aktp) ? PICC_AUTHENT1B : PICC_AUTHENT1A, 0, scc_set.blk,
            &scc_set.uidlen, scc_set.uid, NULL, NULL)) != LERR_SUCCESS) && (err != LERR_INVALIDKEY)) goto thr_exit;
        if (err == LERR_SUCCESS) break;
    }
    if (err == LERR_SUCCESS)
    {
        fnd = TRUE;
        memcpy(scc_set.ak, defaultKeys[cnt], 6);
        gui_setparm();
        lstrcpy(szLocal, TEXT("\2"));
        if (scc_set.tp)
        {
            wsprintf(&szLocal[lstrlen(szLocal)], TEXT("Key for the %c%u:%u was found."),
                (scc_set.blk < 128) ? (((scc_set.blk & 3) == 3) ? 'T' : 'S') : (((scc_set.blk & 15) == 15) ? 'T' : 'S'),
                (scc_set.blk < 128) ? scc_set.blk / 4 : scc_set.blk / 16 + 24,
                (scc_set.blk < 128) ? scc_set.blk & 3 : scc_set.blk & 15);
        }
        else lstrcat(szLocal, TEXT("Key was found."));
    }
    else
    {
        lstrcpy(szLocal, TEXT("\3"));
        if (scc_set.tp)
        {
            wsprintf(&szLocal[lstrlen(szLocal)], TEXT("Can't find key for the %c%u:%u."),
                (scc_set.blk < 128) ? (((scc_set.blk & 3) == 3) ? 'T' : 'S') : (((scc_set.blk & 15) == 15) ? 'T' : 'S'),
                (scc_set.blk < 128) ? scc_set.blk / 4 : scc_set.blk / 16 + 24,
                (scc_set.blk < 128) ? scc_set.blk & 3 : scc_set.blk & 15);
        }
        else lstrcat(szLocal, TEXT("Can't find key."));
    }
    err = LERR_SUCCESS;

thr_exit:
    if (err) thr_verberr(err, szLocal);
    if (lstrlen(szLocal)) gui_stbar(szLocal);

    // final beep
    if ((link_isopen(&ccr)) && (err != LERR_HARDWARE) && (err != LERR_NOREADER))
    {
        if (fnd) mfBeep(&ccr, 0x04);    // if ak was found
        else mfBeep(&ccr, 0x03);        // if not found
    }
    link_close(&ccr);

    gui_disen(TRUE);
    return 0;
}

DWORD WINAPI t_read(void)
{
    CCR         ccr;
    DWORD       err = LERR_SUCCESS;
    TCHAR       szLocal[256];

    BYTE        r_model = 0, r_hw = 0;
    DWORD       r_sn = 0;

    BYTE        sc_acm = 0, sc_uidlen = 0;
    WORD        sc_atqa = 0;
    BYTE        sc_sak = 0;

    // disable controls
    gui_disen(FALSE);
    // status message
    if (scc_set.tp)
    {
        wsprintf(szLocal, TEXT("\4%sRead block from the %c%u:%u..."),
            (scc_set.rw) ? TEXT("RW-mode! ") : TEXT(""),
            (scc_set.blk < 128) ? (((scc_set.blk & 3) == 3) ? 'T' : 'S') : (((scc_set.blk & 15) == 15) ? 'T' : 'S'),
            (scc_set.blk < 128) ? scc_set.blk / 4 : scc_set.blk / 16 + 24,
            (scc_set.blk < 128) ? scc_set.blk & 3 : scc_set.blk & 15);
    }
    else
    {
        wsprintf(szLocal, TEXT("\4%sRead pages %u-%u..."),
            (scc_set.rw) ? TEXT("RW-mode! ") : TEXT(""),
            scc_set.blk, (scc_set.blk + 3) & 0xFF);
    }
    gui_stbar(szLocal);

    memset(&ccr, 0, sizeof(ccr));
    // open USB device; return LERR_SUCCESS, LERR_HARDWARE
    if ((err = link_hidopen(0, NULL, &ccr)) != LERR_SUCCESS)
    {
        err = LERR_NOREADER;
        goto thr_exit;
    }
    // DIR-mode initialization
    if ((err = mfInit(&ccr, &r_model, &r_hw, &r_sn)) != LERR_SUCCESS) goto thr_exit;
    wsprintf(szLocal, TEXT("RD-0%uAB, SN:%08X, HW:%u.%u"), r_model, r_sn, r_hw >> 4, r_hw & 15);
    SetWindowText(hMain, szLocal);

    // set authorization key
    if ((scc_set.tp) && ((err = mfSetAK(&ccr, 0, scc_set.ak)) != LERR_SUCCESS)) goto thr_exit;
    // setup auth command
    if (scc_set.tp) sc_acm = (scc_set.aktp) ? PICC_AUTHENT1B : PICC_AUTHENT1A;
    else sc_acm = 0;
    // data read; sc_uidlen = 0 for any uid read
    if ((err = mfDataRead(&ccr, 7, ((scc_set.rw) ? MFDM_RWC : MFDM_NMC) | ((scc_set.tp) ? MFDM_BLOCK : MFDM_PAGE),
        sc_acm, 0, scc_set.blk, (scc_set.tp) ? 1 : 4, scc_set.data, &sc_uidlen, scc_set.uid, &sc_atqa, &sc_sak)) != LERR_SUCCESS)  goto thr_exit;
    scc_set.uidlen = sc_uidlen;
    // gui out
    gui_setparm();
    gui_setatqasak(sc_atqa, sc_sak, !(scc_set.rw));

    if (scc_set.tp)
    {
        wsprintf(szLocal, TEXT("\2%sRead block from the %c%u:%u complete."),
            (scc_set.rw) ? TEXT("RW-mode! ") : TEXT(""),
            (scc_set.blk < 128) ? (((scc_set.blk & 3) == 3) ? 'T' : 'S') : (((scc_set.blk & 15) == 15) ? 'T' : 'S'),
            (scc_set.blk < 128) ? scc_set.blk / 4 : scc_set.blk / 16 + 24,
            (scc_set.blk < 128) ? scc_set.blk & 3 : scc_set.blk & 15);
    }
    else
    {
        wsprintf(szLocal, TEXT("\2%sRead pages %u-%u complete."),
            (scc_set.rw) ? TEXT("RW-mode! ") : TEXT(""),
            scc_set.blk, (scc_set.blk + 3) & 0xFF);
    }
    gui_stbar(szLocal);

thr_exit:
    if (err) thr_verberr(err, szLocal);
    if (lstrlen(szLocal)) gui_stbar(szLocal);

    // final beep
    if ((link_isopen(&ccr)) && (err != LERR_HARDWARE) && (err != LERR_NOREADER))
    {
        if (err)  mfBeep(&ccr, 0x03);   // if read fail
        else mfBeep(&ccr, 0x02);        // if read success
    }
    link_close(&ccr);

    gui_disen(TRUE);
    return 0;
}

DWORD WINAPI t_write(void)
{
    CCR         ccr;
    DWORD       err = LERR_SUCCESS;
    TCHAR       szLocal[256];

    BYTE        r_model = 0, r_hw = 0;
    DWORD       r_sn = 0;
    WORD        sc_atqa = 0;
    BYTE        sc_sak = 0;

    BYTE        sc_acm = 0, sc_uidlen = 0;
    BOOL        okf = FALSE;
    BYTE        vbuf[SZ_MFBLK];

    // disable controls
    gui_disen(FALSE);
    // status message
    if (scc_set.tp)
    {
        wsprintf(szLocal, TEXT("\4%sWrite block to the %c%u:%u..."),
            (scc_set.rw) ? TEXT("RW-mode! ") : TEXT(""),
            (scc_set.blk < 128) ? (((scc_set.blk & 3) == 3) ? 'T' : 'S') : (((scc_set.blk & 15) == 15) ? 'T' : 'S'),
            (scc_set.blk < 128) ? scc_set.blk / 4 : scc_set.blk / 16 + 24,
            (scc_set.blk < 128) ? scc_set.blk & 3 : scc_set.blk & 15);
    }
    else
    {
        wsprintf(szLocal, TEXT("\4%sWrite pages %u-%u..."),
            (scc_set.rw) ? TEXT("RW-mode! ") : TEXT(""),
            scc_set.blk, (scc_set.blk + 3) & 0xFF);
    }
    gui_stbar(szLocal);

    memset(&ccr, 0, sizeof(ccr));
    // open USB device; return LERR_SUCCESS, LERR_HARDWARE
    if ((err = link_hidopen(0, NULL, &ccr)) != LERR_SUCCESS)
    {
        err = LERR_NOREADER;
        goto thr_exit;
    }
    // DIR-mode initialization
    if ((err = mfInit(&ccr, &r_model, &r_hw, &r_sn)) != LERR_SUCCESS) goto thr_exit;
    wsprintf(szLocal, TEXT("RD-0%uAB, SN:%08X, HW:%u.%u"), r_model, r_sn, r_hw >> 4, r_hw & 15);
    SetWindowText(hMain, szLocal);

    // set authorization key
    if ((scc_set.tp) && ((err = mfSetAK(&ccr, 0, scc_set.ak)) != LERR_SUCCESS)) goto thr_exit;
    // setup auth command
    if (scc_set.tp) sc_acm = (scc_set.aktp) ? PICC_AUTHENT1B : PICC_AUTHENT1A;
    else sc_acm = 0;
    // data write; sc_uidlen = 0 for any uid write
    if ((err = mfDataWrite(&ccr, 7, ((scc_set.rw) ? MFDM_RWC : MFDM_NMC) | ((scc_set.tp) ? MFDM_BLOCK : MFDM_PAGE),
        sc_acm, 0, scc_set.blk, (scc_set.tp) ? 1 : 4, scc_set.data, &sc_uidlen, scc_set.uid, &sc_atqa, &sc_sak)) != LERR_SUCCESS)  goto thr_exit;
    scc_set.uidlen = sc_uidlen;
    // gui out
    gui_setparm();
    gui_setatqasak(sc_atqa, sc_sak, !(scc_set.rw));
    // verify for UL card
    if (scc_set.tp == 0)
    {
        if ((err = mfDataRead(&ccr, 7, ((scc_set.rw) ? MFDM_RWC : MFDM_NMC) | ((scc_set.tp) ? MFDM_BLOCK : MFDM_PAGE),
            sc_acm, 0, scc_set.blk, (scc_set.tp) ? 1 : 4, vbuf, &scc_set.uidlen, scc_set.uid, NULL, NULL)) != LERR_SUCCESS)  goto thr_exit;
        if (memcmp(scc_set.data, vbuf, SZ_MFBLK)) err = LERR_DATAWRITE;
    }
    if (err == LERR_SUCCESS)
    {
        okf = TRUE;
        if (scc_set.tp)
        {
            wsprintf(szLocal, TEXT("\2%sWrite block to the %c%u:%u complete."),
                (scc_set.rw) ? TEXT("RW-mode! ") : TEXT(""),
                (scc_set.blk < 128) ? (((scc_set.blk & 3) == 3) ? 'T' : 'S') : (((scc_set.blk & 15) == 15) ? 'T' : 'S'),
                (scc_set.blk < 128) ? scc_set.blk / 4 : scc_set.blk / 16 + 24,
                (scc_set.blk < 128) ? scc_set.blk & 3 : scc_set.blk & 15);
        }
        else
        {
            wsprintf(szLocal, TEXT("\2%sWrite pages %u-%u complete."),
                (scc_set.rw) ? TEXT("RW-mode! ") : TEXT(""),
                scc_set.blk, (scc_set.blk + 3) & 0xFF);
        }
    }
    else
    {
        if (scc_set.tp)
        {
            wsprintf(szLocal, TEXT("\3%sCan't write block to the %c%u:%u!"),
                (scc_set.rw) ? TEXT("RW-mode! ") : TEXT(""),
                (scc_set.blk < 128) ? (((scc_set.blk & 3) == 3) ? 'T' : 'S') : (((scc_set.blk & 15) == 15) ? 'T' : 'S'),
                (scc_set.blk < 128) ? scc_set.blk / 4 : scc_set.blk / 16 + 24,
                (scc_set.blk < 128) ? scc_set.blk & 3 : scc_set.blk & 15);
        }
        else
        {
            wsprintf(szLocal, TEXT("\3%sCan't write pages %u-%u!"),
                (scc_set.rw) ? TEXT("RW-mode! ") : TEXT(""),
                scc_set.blk, (scc_set.blk + 3) & 0xFF);
        }
    }
    gui_stbar(szLocal);
    err = LERR_SUCCESS;

thr_exit:
    if (err) thr_verberr(err, szLocal);
    if (lstrlen(szLocal)) gui_stbar(szLocal);

    // final beep
    if ((link_isopen(&ccr)) && (err != LERR_HARDWARE) && (err != LERR_NOREADER))
    {
        if (okf) mfBeep(&ccr, 0x02);    // if write success
        else mfBeep(&ccr, 0x03);        // if write fail
    }
    link_close(&ccr);

    gui_disen(TRUE);
    return 0;
}

DWORD WINAPI t_setuid(void)
{
    CCR         ccr;
    DWORD       err = LERR_SUCCESS;
    TCHAR       szLocal[256];

    BYTE        r_model = 0, r_hw = 0;
    DWORD       r_sn = 0;
    WORD        sc_atqa;
    BYTE        sc_sak;

    BYTE        sc_uidlen = 0;
    BYTE        sc_halt[2] = { PICC_HALT, 0 };
    BOOL        okf = FALSE;
    BYTE        ubuf[SZ_MFBLK];

    memset(&ccr, 0, sizeof(ccr));
    // disable controls
    gui_disen(FALSE);

    // check uid len for UL card
    if (scc_set.tp == 0)
    {
        if (scc_set.uidlen != 7)
        {
            MessageBeep(MB_ICONSTOP);
            lstrcpy(szLocal, TEXT("\3Length of UID must be 7 bytes!"));
            goto thr_exit;
        }
    }
    else
    {
        if (scc_set.uidlen != 4)
        {
            MessageBeep(MB_ICONSTOP);
            lstrcpy(szLocal, TEXT("\3Length of UID must be 4 bytes!"));
            goto thr_exit;
        }
        sc_atqa = scc_dsc[scc_set.tp].atqa; // ATQA by default
        sc_sak = scc_dsc[scc_set.tp].sak;       // SAK by default
        if (!gui_getatqasak(&sc_atqa, &sc_sak)) // ATQA & SAK reading
        {
            MessageBeep(MB_ICONSTOP);
            lstrcpy(szLocal, TEXT("\3Wrong ATQA or SAK!"));
            goto thr_exit;
        }
    }

    // status message
    gui_stbar(TEXT("\4Set new UID..."));

    // open USB device; return LERR_SUCCESS, LERR_HARDWARE
    if ((err = link_hidopen(0, NULL, &ccr)) != LERR_SUCCESS)
    {
        err = LERR_NOREADER;
        goto thr_exit;
    }
    // DIR-mode initialization
    if ((err = mfInit(&ccr, &r_model, &r_hw, &r_sn)) != LERR_SUCCESS) goto thr_exit;
    wsprintf(szLocal, TEXT("RD-0%uAB, SN:%08X, HW:%u.%u"), r_model, r_sn, r_hw >> 4, r_hw & 15);
    SetWindowText(hMain, szLocal);
    // read block 0 / pages 0..3 with UID
    if ((err = mfDataRead(&ccr, 7, ((scc_set.rw) ? MFDM_RWC : MFDM_NMC) | ((scc_set.tp) ? MFDM_BLOCK : MFDM_PAGE),
        0, 0, 0, (scc_set.tp) ? 1 : 4, ubuf, NULL, NULL, NULL, NULL)) != LERR_SUCCESS)  goto thr_exit;
    // set new UID to dump
    if (scc_set.tp == 0)
    {
        // construct UID for UL
        ubuf[0] = scc_set.uid[0];
        ubuf[1] = scc_set.uid[1];
        ubuf[2] = scc_set.uid[2];
        ubuf[3] = scc_set.uid[0] ^ scc_set.uid[1] ^ scc_set.uid[2] ^ 0x88;
        ubuf[4] = scc_set.uid[3];
        ubuf[5] = scc_set.uid[4];
        ubuf[6] = scc_set.uid[5];
        ubuf[7] = scc_set.uid[6];
        ubuf[8] = scc_set.uid[3] ^ scc_set.uid[4] ^ scc_set.uid[5] ^ scc_set.uid[6];
    }
    else if ((scc_set.tp >= 1) && (scc_set.tp <= 4))    // CL1...CL4
    {
        // construct UID for CL
        ubuf[0] = scc_set.uid[0];
        ubuf[1] = scc_set.uid[1];
        ubuf[2] = scc_set.uid[2];
        ubuf[3] = scc_set.uid[3];
        ubuf[4] = scc_set.uid[0] ^ scc_set.uid[1] ^ scc_set.uid[2] ^ scc_set.uid[3];
        // construct SAK for CL
        ubuf[5] = sc_sak;
        // construct ATQA for CL
        ubuf[6] = (BYTE)sc_atqa & 0xFF;
        ubuf[7] = (BYTE)(sc_atqa >> 8);
    }
    else if (scc_set.tp > 4)    // >= PL2
    {
        // construct UID for PL
        ubuf[0] = scc_set.uid[0];
        ubuf[1] = scc_set.uid[1];
        ubuf[2] = scc_set.uid[2];
        ubuf[3] = scc_set.uid[3];
        ubuf[4] = scc_set.uid[4];
        ubuf[5] = scc_set.uid[5];
        ubuf[6] = scc_set.uid[6];
        // construct SAK for CL
        ubuf[7] = sc_sak;
        // construct ATQA for CL
        ubuf[8] = (BYTE)sc_atqa & 0xFF;
        ubuf[9] = (BYTE)(sc_atqa >> 8);
    }
    // data write; sc_uidlen = 0 for any uid write
    if ((err = mfDataWrite(&ccr, 7, ((scc_set.rw) ? MFDM_RWC : MFDM_NMC) | ((scc_set.tp) ? MFDM_BLOCK : MFDM_PAGE),
        0, 0, 0, (scc_set.tp) ? 1 : 4, ubuf, NULL, NULL, NULL, NULL)) != LERR_SUCCESS)  goto thr_exit;
    Sleep(50);
    // verify UID; sc_uidlen = 0
    if ((err = mfSelect(&ccr, 7, PICC_REQALL, &sc_uidlen, ubuf, NULL, NULL)) != LERR_SUCCESS) goto thr_exit;
    if (((err = mfLong(&ccr, sc_halt, sizeof(sc_halt), NULL, NULL)) != LERR_SUCCESS) && (err != LERR_FAIL)) goto thr_exit;
    // gui out
    gui_setparm();
    // compare readen & written UID
    err = LERR_SUCCESS;
    if (memcmp(scc_set.uid, ubuf, sc_uidlen))
    {
        lstrcpy(szLocal, TEXT("\3Can't set new UID!"));
    }
    else
    {
        okf = TRUE;
        lstrcpy(szLocal, TEXT("\2Setting the new UID is complete."));
    }
thr_exit:
    if (err) thr_verberr(err, szLocal);
    if (lstrlen(szLocal)) gui_stbar(szLocal);

    // final beep
    if ((link_isopen(&ccr)) && (err != LERR_HARDWARE) && (err != LERR_NOREADER))
    {
        if (okf) mfBeep(&ccr, 0x02);    // if write success
        else mfBeep(&ccr, 0x03);        // if write fail
    }
    link_close(&ccr);

    gui_disen(TRUE);
    return 0;
}
