diff --git a/.gitignore b/.gitignore index 72723e5..1325667 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,10 @@ *pyc + +CMakeCache.txt +CMakeFiles +Makefile +cmake_install.cmake +install_manifest.txt + +*.o +hf-terminal diff --git a/lib/config.py b/mainframe/config.py similarity index 100% rename from lib/config.py rename to mainframe/config.py diff --git a/lib/console.py b/mainframe/console.py similarity index 100% rename from lib/console.py rename to mainframe/console.py diff --git a/lib/logic.py b/mainframe/logic.py similarity index 100% rename from lib/logic.py rename to mainframe/logic.py diff --git a/terminal/CMakeLists.txt b/terminal/CMakeLists.txt new file mode 100644 index 0000000..ddb366e --- /dev/null +++ b/terminal/CMakeLists.txt @@ -0,0 +1,6 @@ +project(hf-terminal) + +add_executable(hf-terminal main.c tts.c base64.c ldap.c) +set(CMAKE_C_FLAGS "-std=c99") + +target_link_libraries(hf-terminal nfc m curl) diff --git a/terminal/base64.c b/terminal/base64.c new file mode 100644 index 0000000..d5055bc --- /dev/null +++ b/terminal/base64.c @@ -0,0 +1,150 @@ +#include +#include +#include + +/* +static char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/'}; +static char *decoding_table = NULL; +static int mod_table[] = {0, 2, 1}; + + +char *base64_encode(const char *data, + size_t input_length, + size_t *output_length) { + + printf("%04x\n", *(int *)(data + 3)); + + *output_length = (size_t) (4.0 * ceil((double) input_length / 3.0)); + + char *encoded_data = malloc(*output_length + 1); + if (encoded_data == NULL) return NULL; + + for (int i = 0, j = 0; i < input_length;) { + + uint32_t octet_a = i < input_length ? data[i++] : 0; + uint32_t octet_b = i < input_length ? data[i++] : 0; + uint32_t octet_c = i < input_length ? data[i++] : 0; + + uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; + + encoded_data[j++] = encoding_table[(triple >> (3 * 6)) & 0x3F]; + encoded_data[j++] = encoding_table[(triple >> (2 * 6)) & 0x3F]; + encoded_data[j++] = encoding_table[(triple >> (1 * 6)) & 0x3F]; + encoded_data[j++] = encoding_table[(triple >> (0 * 6)) & 0x3F]; + } + + for (int i = 0; i < mod_table[input_length % 3]; i++) + encoded_data[*output_length - 1 - i] = '='; + + encoded_data[*output_length] = 0; + + return encoded_data; +} + +void build_decoding_table(); + +char *base64_decode(const char *data, + size_t input_length, + size_t *output_length) { + + if (decoding_table == NULL) build_decoding_table(); + + if (input_length % 4 != 0) return NULL; + + *output_length = input_length / 4 * 3; + if (data[input_length - 1] == '=') (*output_length)--; + if (data[input_length - 2] == '=') (*output_length)--; + + char *decoded_data = malloc(*output_length); + if (decoded_data == NULL) return NULL; + + for (int i = 0, j = 0; i < input_length;) { + + uint32_t sextet_a = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; + uint32_t sextet_b = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; + uint32_t sextet_c = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; + uint32_t sextet_d = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; + + uint32_t triple = (sextet_a << 3 * 6) + + (sextet_b << 2 * 6) + + (sextet_c << 1 * 6) + + (sextet_d << 0 * 6); + + if (j < *output_length) decoded_data[j++] = (triple >> 2 * 8) & 0xFF; + if (j < *output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF; + if (j < *output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF; + } + + return decoded_data; +} + + +void build_decoding_table() { + + decoding_table = malloc(256); + + for (int i = 0; i < 0x40; i++) + decoding_table[encoding_table[i]] = i; +} + + +void base64_cleanup() { + free(decoding_table); +} + +*/ + +static char *b64_lut = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +void bin_to_b64(char *out, char* in, unsigned int in_length) +{ + unsigned int complete_quads = in_length / 3; + unsigned int additional = in_length - complete_quads * 3; + + for (unsigned int i = 0; i < complete_quads; i++) + { + char a, b, c; + a = in[i * 3]; b = in[i * 3 + 1]; c = in[i * 3 + 2]; + + out[i * 4 ] = b64_lut[ (a & 0b11111100) >> 2 ]; + out[i * 4 + 1] = b64_lut[((a & 0b00000011) << 4 ) | ((b & 0b11110000) >> 4)]; + out[i * 4 + 2] = b64_lut[((b & 0b00001111) << 2) | ((c & 0b11000000) >> 6)]; + out[i * 4 + 3] = b64_lut[ c & 0b00111111 ]; + } + + unsigned int final_length = complete_quads * 4; + + switch (additional) + { + case 1: + { + char a = in[complete_quads * 3]; + out[complete_quads * 4 ] = b64_lut[(a & 0b11111100) >> 2]; + out[complete_quads * 4 + 1] = b64_lut[(a & 0b00000011) << 4]; + out[complete_quads * 4 + 2] = '='; + out[complete_quads * 4 + 3] = '='; + final_length += 4; + break; + } + case 2: + { + char a, b; + a = in[complete_quads * 3]; b = in[complete_quads * 3 + 1]; + out[complete_quads * 4 ] = b64_lut[ (a & 0b11111100) >> 2 ]; + out[complete_quads * 4 + 1] = b64_lut[((a & 0b00000011) << 4) | ((b & 0b11110000) >> 4)]; + out[complete_quads * 4 + 2] = b64_lut[((b & 0b00001111) << 2) ]; + out[complete_quads * 4 + 3] = '='; + final_length += 4; + break; + } + } + out[final_length] = 0; +} + diff --git a/terminal/base64.h b/terminal/base64.h new file mode 100644 index 0000000..082960e --- /dev/null +++ b/terminal/base64.h @@ -0,0 +1,7 @@ +#ifndef __BASE64_H__ +#define __BASE64_H__ + +//char *base64_encode(const char *data, size_t input_length, size_t *output_length); +void bin_to_b64(char *out, char* in, unsigned int in_length); + +#endif diff --git a/terminal/ldap.c b/terminal/ldap.c new file mode 100644 index 0000000..8ad13d5 --- /dev/null +++ b/terminal/ldap.c @@ -0,0 +1,9 @@ +int ldap_dn_by_mifare(char *MifareID, char *DNOut, int *DNLength) +{ + // TODO: actually implement thid. tkd? + + strncpy(DNOut, "q3k", *DNLength); + *DNLength = strlen("q3k"); + + return 1; +} diff --git a/terminal/ldap.h b/terminal/ldap.h new file mode 100644 index 0000000..24808ad --- /dev/null +++ b/terminal/ldap.h @@ -0,0 +1,6 @@ +#ifndef __LDAP_H__ +#define __LDAP_H__ + +int ldap_dn_by_mifare(char *MifareID, char *DNOut, int *DNLength); + +#endif diff --git a/terminal/main.c b/terminal/main.c new file mode 100644 index 0000000..624f1bd --- /dev/null +++ b/terminal/main.c @@ -0,0 +1,104 @@ +#include +#include + +#include +#include + +#include "tts.h" +#include "ldap.h" + +static nfc_device_t *g_NFCDevice = NULL; + +const nfc_modulation_t g_NFCModulations[5] = { + { .nmt = NMT_ISO14443A, .nbr = NBR_106 }, + { .nmt = NMT_ISO14443B, .nbr = NBR_106 }, + { .nmt = NMT_FELICA, .nbr = NBR_212 }, + { .nmt = NMT_FELICA, .nbr = NBR_424 }, + { .nmt = NMT_JEWEL, .nbr = NBR_106 }, +}; +const size_t g_NFCModulationCount = 5; + +void poll_nfc(void) +{ + nfc_target_t Target; + bool Result = nfc_initiator_poll_target(g_NFCDevice, g_NFCModulations, g_NFCModulationCount, 20, 2, &Target); + + if (Result) + { + if (Target.nm.nmt != NMT_ISO14443A) + return; + + if (Target.nti.nai.szUidLen != 4) + return; + + printf("Scanned Mifare %x.\n", *(int *)Target.nti.nai.abtUid); + + char MifareID[5]; + sprintf(MifareID, "%04x", *(int *)Target.nti.nai.abtUid); + + char DN[128]; + int DNLength = 128; + int LDAPResult = ldap_dn_by_mifare(MifareID, DN, &DNLength); + + if (LDAPResult > 0) + { + if (LDAPResult == 1) + { + tts_speak("Nieznana karta."); + return; + } + else + { + tts_speak("Nieznany błąd."); + return; + } + } + printf("This appears to be %s.\n", DN); + + char WelcomeMessage[200]; + sprintf(WelcomeMessage, "Cześć %s.", DN); + tts_speak(WelcomeMessage); + } +} + +int main(int argc, char **argv) +{ + nfc_device_desc_t *Devices; + + size_t NumDevices; + Devices = (nfc_device_desc_t *) malloc(10 * sizeof(*Devices)); + nfc_list_devices(Devices, 10, &NumDevices); + + if (NumDevices == 0) + { + fprintf(stderr, "Error: No NFC device found.\n"); + return 1; + } + + if (NumDevices > 1) + { + fprintf(stderr, "Error: More than one NFC device found.\n"); + return 1; + } + + g_NFCDevice = nfc_connect(&Devices[0]); + + if (g_NFCDevice == NULL) + { + fprintf(stderr, "Error: Could not connect to NFC device.\n"); + return 1; + } + + nfc_initiator_init(g_NFCDevice); + printf("Connected to NFC device.\n"); + + //tts_speak("Lodówka zainicjalizowana."); + tts_speak("Zażółć gęślą jaźń."); + + while (1) + { + poll_nfc(); + } + + return 0; +} diff --git a/terminal/tts.c b/terminal/tts.c new file mode 100644 index 0000000..8a1fe4c --- /dev/null +++ b/terminal/tts.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include + +#include "base64.h" + +static char *g_IvonaURL = "http://www.ivona.com/online/fileSentence.php?l=en&e=0&v=1&t=%s"; + +size_t tts_write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) +{ + int written = fwrite(ptr, size, nmemb, stream); + return written; +} + +void tts_speak(char *Text) +{ + int B64OutputLength; + char *B64Output = (char *)malloc(strlen(Text) * 2); + bin_to_b64(B64Output, Text, strlen(Text)); + + char *URL = (char *)malloc(strlen(B64Output) + strlen(g_IvonaURL)); + sprintf(URL, g_IvonaURL, B64Output); + printf("URL: %s\n", URL); + + CURL *Curl; + CURLcode Result; + FILE *File; + + File = fopen("/tmp/hf-tts.mp3", "w"); + + Curl = curl_easy_init(); + curl_easy_setopt(Curl, CURLOPT_URL, URL); + curl_easy_setopt(Curl, CURLOPT_WRITEFUNCTION, tts_write_data); + curl_easy_setopt(Curl, CURLOPT_WRITEDATA, File); + curl_easy_setopt(Curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS); + curl_easy_setopt(Curl, CURLOPT_FOLLOWLOCATION, 1); + Result = curl_easy_perform(Curl); + curl_easy_cleanup(Curl); + + fclose(File); + + system("mpg123 -q -2 /tmp/hf-tts.mp3"); + + free((void *)URL); + free((void *)B64Output); +} diff --git a/terminal/tts.h b/terminal/tts.h new file mode 100644 index 0000000..6cdcac0 --- /dev/null +++ b/terminal/tts.h @@ -0,0 +1,6 @@ +#ifndef __TTS_H__ +#define __TTS_H__ + +void tts_speak(char *Text); + +#endif