Login and Sign Up dialogs implemented.
This commit is contained in:
parent
5a840ab1bf
commit
7174d36eb9
21 changed files with 734 additions and 173 deletions
|
@ -72,6 +72,7 @@ HEADERS = \
|
|||
src/login.h \
|
||||
src/network.h \
|
||||
src/runtime.h \
|
||||
src/signup.h \
|
||||
src/thirdparty/minicoro/minicoro.h \
|
||||
src/system/comport.h \
|
||||
src/settings.h \
|
||||
|
@ -119,7 +120,9 @@ SOURCES = \
|
|||
src/login.c \
|
||||
src/network.c \
|
||||
src/settings.c \
|
||||
src/signup.c \
|
||||
src/system/comport.c \
|
||||
src/system/os.c \
|
||||
src/system/surface.c \
|
||||
src/system/taglist.c \
|
||||
$$SHARED/util.c \
|
||||
|
|
BIN
client/data/ddialing.png
(Stored with Git LFS)
BIN
client/data/ddialing.png
(Stored with Git LFS)
Binary file not shown.
|
@ -58,6 +58,7 @@ WidgetT *textboxInit(WidgetT *widget, char *title) {
|
|||
t->value = (char *)malloc(t->maxLength);
|
||||
t->caret = 0;
|
||||
t->offset = 0;
|
||||
t->password = 0;
|
||||
|
||||
if (!t->value) return NULL;
|
||||
t->value[0] = 0;
|
||||
|
@ -76,6 +77,7 @@ static void textboxKeyboardEvent(WidgetT *widget, uint8_t ascii, uint8_t extende
|
|||
|
||||
TextboxT *t = (TextboxT *)widget;
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
char *temp;
|
||||
|
||||
(void)scancode;
|
||||
|
@ -167,20 +169,25 @@ static void textboxKeyboardEvent(WidgetT *widget, uint8_t ascii, uint8_t extende
|
|||
|
||||
default: // Other keys
|
||||
if (ascii >= 32 && ascii <= 126) {
|
||||
// Remember length so we can zero terminate this after the edit.
|
||||
y = strlen(t->value);
|
||||
// Insert character, if room.
|
||||
if (strlen(t->value) < (size_t)t->maxLength - 1) {
|
||||
if (y < (size_t)t->maxLength - 1) {
|
||||
// Move existing characters over, if needed.
|
||||
if (t->caret + t->offset < strlen(t->value)) {
|
||||
for (x=strlen(t->value) + 1; x>t->caret + t->offset; x--) {
|
||||
if (t->caret + t->offset < y) {
|
||||
for (x=y + 1; x>t->caret + t->offset; x--) {
|
||||
t->value[x] = t->value[x-1];
|
||||
}
|
||||
}
|
||||
// Place typed character at caret.
|
||||
t->value[t->caret + t->offset] = ascii;
|
||||
y++;
|
||||
// Fix zero termination.
|
||||
t->value[y] = 0;
|
||||
// Is the caret on the right edge of the box?
|
||||
if (t->caret == t->visible - 1) {
|
||||
// Can we move the string offset?
|
||||
if (t->offset < strlen(t->value)) {
|
||||
if (t->offset < y) {
|
||||
t->offset++;
|
||||
}
|
||||
} else {
|
||||
|
@ -267,6 +274,7 @@ static void textboxPaint(WidgetT *widget, uint8_t enabled, RectT pos) {
|
|||
uint16_t textY;
|
||||
char cursor[2] = { 0xb1, 0 };
|
||||
|
||||
|
||||
if (GUI_GET_FLAG(widget, WIDGET_FLAG_DIRTY) || guiFocusGet() == widget) {
|
||||
labelWidth = (strlen(t->title) * fontWidthGet(_guiFont)) + _guiMetric[METRIC_TEXTBOX_PADDING];
|
||||
valueWidth = (t->visible * fontWidthGet(_guiFont)) + (_guiMetric[METRIC_TEXTBOX_HORIZONTAL_PADDING] * 2);
|
||||
|
@ -288,6 +296,7 @@ static void textboxPaint(WidgetT *widget, uint8_t enabled, RectT pos) {
|
|||
// Draw value.
|
||||
draw = strdup(&t->value[t->offset]);
|
||||
if (strlen(draw) > t->visible) draw[t->visible] = 0;
|
||||
if (t->password != 0) memset(draw, t->password, strlen(draw));
|
||||
fontRender(_guiFont, draw, _guiColor[COLOR_TEXTBOX_TEXT], _guiColor[COLOR_TEXTBOX_BACKGROUND], textX, textY);
|
||||
free(draw);
|
||||
|
||||
|
@ -302,6 +311,11 @@ static void textboxPaint(WidgetT *widget, uint8_t enabled, RectT pos) {
|
|||
}
|
||||
|
||||
|
||||
void textboxPasswordCharacterSet(TextboxT *textbox, char c) {
|
||||
textbox->password = c;
|
||||
}
|
||||
|
||||
|
||||
void textboxTitleSet(TextboxT *textbox, char *title) {
|
||||
if (textbox->title) free(textbox->title);
|
||||
textbox->title = strdup(title);
|
||||
|
|
|
@ -30,6 +30,7 @@ typedef struct TextboxS {
|
|||
WidgetT base; // Must be first in every widget
|
||||
char *title;
|
||||
char *value;
|
||||
char password; // Character to use to mask passwords
|
||||
uint16_t maxLength; // Maximum length of value + 1
|
||||
uint16_t caret; // Cursor position in control (caret + offset = cursor positition in value)
|
||||
uint16_t offset; // First character position to display in control
|
||||
|
@ -40,6 +41,7 @@ typedef struct TextboxS {
|
|||
WidgetT *textboxInit(WidgetT *widget, char *title);
|
||||
void textboxLengthMaxSet(TextboxT *textbox, uint16_t length);
|
||||
TextboxT *textboxNew(uint16_t x, uint16_t y, uint16_t w, char *title);
|
||||
void textboxPasswordCharacterSet(TextboxT *textbox, char c);
|
||||
void textboxTitleSet(TextboxT *textbox, char *title);
|
||||
char *textboxValueGet(TextboxT *textbox);
|
||||
void textboxValueSet(TextboxT *textbox, char *value);
|
||||
|
|
|
@ -28,6 +28,7 @@ uint8_t widgetEnableGet(WidgetT *widget) {
|
|||
|
||||
|
||||
void widgetEnableSet(WidgetT *widget, uint8_t enabled) {
|
||||
// ***TODO*** Should also set children.
|
||||
// We did "DISABLED" for the flag so that "flags = 0" (the default) would enable widgets.
|
||||
if (enabled) {
|
||||
GUI_CLEAR_FLAG(widget, WIDGET_FLAG_DISABLED);
|
||||
|
|
|
@ -18,13 +18,103 @@
|
|||
*/
|
||||
|
||||
|
||||
#include "login.h"
|
||||
#include "textbox.h"
|
||||
#include "button.h"
|
||||
#include "msgbox.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "comport.h"
|
||||
#include "network.h"
|
||||
#include "taglist.h"
|
||||
#include "timer.h"
|
||||
#include "task.h"
|
||||
|
||||
#include "login.h"
|
||||
#include "signup.h"
|
||||
#include "welcome.h"
|
||||
|
||||
|
||||
static WindowT *_winLogin = NULL;
|
||||
static TextboxT *_txtUser = NULL;
|
||||
static TextboxT *_txtPass = NULL;
|
||||
static ButtonT *_btnCancel = NULL;
|
||||
static ButtonT *_btnSignUp = NULL;
|
||||
static ButtonT *_btnLogin = NULL;
|
||||
|
||||
|
||||
static void btnCancelClick(WidgetT *widget);
|
||||
static void btnSignUpClick(WidgetT *widget);
|
||||
static void btnLoginClick(WidgetT *widget);
|
||||
static void btnMsgBoxCancel(MsgBoxButtonT button);
|
||||
static void setButtons(uint8_t enabled);
|
||||
static void taskDisconnect(void *data);
|
||||
|
||||
|
||||
static void btnCancelClick(WidgetT *widget) {
|
||||
(void)widget;
|
||||
|
||||
// ***TODO*** This should disable the entire dialog instead of just the buttons. Need to finish the Enable GUI code first.
|
||||
|
||||
setButtons(0);
|
||||
msgBoxTwo("Cancel?", MSGBOX_ICON_QUESTION, "Cancel login?\n \nThis will disconnect you from the server.", "Okay", btnMsgBoxCancel, "Cancel", btnMsgBoxCancel);
|
||||
}
|
||||
|
||||
|
||||
static void btnSignUpClick(WidgetT *widget) {
|
||||
(void)widget;
|
||||
|
||||
guiDelete(D(_winLogin));
|
||||
taskCreate(taskSignUp, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void btnLoginClick(WidgetT *widget) {
|
||||
(void)widget;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void btnMsgBoxCancel(MsgBoxButtonT button) {
|
||||
|
||||
if (button == MSGBOX_BUTTON_ONE) {
|
||||
guiDelete(D(_winLogin));
|
||||
taskCreate(taskDisconnect, taskWelcome);
|
||||
} else {
|
||||
setButtons(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void setButtons(uint8_t enabled) {
|
||||
widgetEnableSet(W(_btnCancel), enabled);
|
||||
widgetEnableSet(W(_btnSignUp), enabled);
|
||||
widgetEnableSet(W(_btnLogin), enabled);
|
||||
}
|
||||
|
||||
|
||||
static void taskDisconnect(void *nextTask) {
|
||||
PacketEncodeDataT encoded = { 0 };
|
||||
int16_t timeout = 2;
|
||||
|
||||
// Tell server we're disconnecting.
|
||||
encoded.packetType = PACKET_TYPE_CLIENT_SHUTDOWN;
|
||||
encoded.control = PACKET_CONTROL_DAT;
|
||||
encoded.channel = 0;
|
||||
encoded.encrypt = 0;
|
||||
packetEncode(__packetThreadData, &encoded, NULL, 0);
|
||||
packetSend(__packetThreadData, &encoded);
|
||||
|
||||
// Snooze a bit for the packet to send.
|
||||
while (timeout > 0) {
|
||||
taskYield();
|
||||
if (__timerQuarterSecondTick) timeout--;
|
||||
}
|
||||
|
||||
// Shut down packet processing & COM port.
|
||||
netShutdown();
|
||||
comClose(__configData.serialCom - 1);
|
||||
if (nextTask) taskCreate(taskWelcome, nextTask);
|
||||
}
|
||||
|
||||
|
||||
void taskLogin(void *data) {
|
||||
|
@ -35,7 +125,39 @@ void taskLogin(void *data) {
|
|||
T_START,
|
||||
T_WINDOW, O(_winLogin),
|
||||
T_TITLE, P("Login"),
|
||||
T_WIDTH, 500, T_HEIGHT, 225,
|
||||
T_WIDTH, 300, T_HEIGHT, 155,
|
||||
|
||||
T_TEXTBOX, O(_txtUser),
|
||||
T_TITLE, P("User Name:"),
|
||||
T_X, 42, T_Y, 10,
|
||||
T_WIDTH, 200,
|
||||
T_LENGTH, 16,
|
||||
T_TEXTBOX, T_DONE,
|
||||
|
||||
T_TEXTBOX, O(_txtPass),
|
||||
T_TITLE, P(" Password:"),
|
||||
T_X, 42, T_Y, 40,
|
||||
T_WIDTH, 200,
|
||||
T_LENGTH, 16,
|
||||
T_MASK, '*',
|
||||
T_TEXTBOX, T_DONE,
|
||||
|
||||
T_BUTTON, O(_btnCancel),
|
||||
T_TITLE, P("Cancel"),
|
||||
T_X, 25, T_Y, 85,
|
||||
T_CLICK, P(btnCancelClick),
|
||||
T_BUTTON, T_DONE,
|
||||
T_BUTTON, O(_btnSignUp),
|
||||
T_TITLE, P("Sign Up"),
|
||||
T_X, 110, T_Y, 85,
|
||||
T_CLICK, P(btnSignUpClick),
|
||||
T_BUTTON, T_DONE,
|
||||
T_BUTTON, O(_btnLogin),
|
||||
T_TITLE, P("Login"),
|
||||
T_X, 199, T_Y, 85,
|
||||
T_CLICK, P(btnLoginClick),
|
||||
T_BUTTON, T_DONE,
|
||||
|
||||
T_WINDOW, T_DONE,
|
||||
T_END
|
||||
};
|
||||
|
|
|
@ -47,138 +47,19 @@
|
|||
#include "gui.h"
|
||||
#include "config.h"
|
||||
#include "runtime.h"
|
||||
#include "comport.h"
|
||||
|
||||
#include "welcome.h"
|
||||
#include "signup.h"
|
||||
|
||||
|
||||
PacketThreadDataT *__packetThreadData = NULL; // Exported in os.h
|
||||
RuntimeDataT __runtimeData; // Exported in runtime.h
|
||||
|
||||
|
||||
static void taskComDebugLoop(void *data);
|
||||
static void taskGuiEventLoop(void *data);
|
||||
|
||||
|
||||
#include "comport.h"
|
||||
static void taskComDebugLoop(void *data) {
|
||||
int32_t r;
|
||||
int32_t x;
|
||||
char buffer[1024];
|
||||
|
||||
(void)data;
|
||||
|
||||
// Open COM port.
|
||||
logWrite("Opening COM\n");
|
||||
r = comOpen(__configData.serialCom - 1, 57600L, 8, 'n', 1, SER_HANDSHAKING_RTSCTS);
|
||||
if (r != SER_SUCCESS) {
|
||||
logWrite("Unable to open COM port! Please check settings.\n");
|
||||
guiStop();
|
||||
return;
|
||||
}
|
||||
// Send a CR to clear anything in the modem.
|
||||
logWrite("Clearing modem buffer\n");
|
||||
snprintf(buffer, 1023, "%c", 13);
|
||||
comWrite(__configData.serialCom - 1, buffer, strlen(buffer));
|
||||
// Wait roughly a second for anything.
|
||||
comWaitWithTimeout(__configData.serialCom - 1, buffer, 1023, 4, "weExpectNothing");
|
||||
// Send actual init
|
||||
logWrite("Init modem\n");
|
||||
snprintf(buffer, 1023, "%s%c", "AT+SOCK1", 13);
|
||||
comWrite(__configData.serialCom - 1, buffer, strlen(buffer));
|
||||
// Wait roughly a second for "OK".
|
||||
r = comWaitWithTimeout(__configData.serialCom - 1, buffer, 1023, 4, "OK");
|
||||
if (r <= 0) {
|
||||
comClose(__configData.serialCom - 1);
|
||||
logWrite("Modem does not support ENET! Please check settings.\n");
|
||||
guiStop();
|
||||
return;
|
||||
}
|
||||
logWrite("Modem OK\n");
|
||||
// Flush COM port.
|
||||
timerQuarterSecondsWait(4);
|
||||
comReceiveBufferFlush(__configData.serialCom - 1);
|
||||
|
||||
// Show dialing, dial service.
|
||||
logWrite("Dialing\n");
|
||||
snprintf(buffer, 1023, "ATDT%s:%d%c", __configData.serverHost, __configData.serverPort, 13);
|
||||
comWrite(__configData.serialCom - 1, buffer, strlen(buffer));
|
||||
// Wait 7 seconds for welcome banner.
|
||||
r = comWaitWithTimeout(__configData.serialCom - 1, buffer, 1023, 4 * 7, "KPMPGSMKII\r");
|
||||
if (r <= 0) {
|
||||
comClose(__configData.serialCom - 1);
|
||||
logWrite("Unable to connect to server! Please check settings or try later.\n");
|
||||
guiStop();
|
||||
return;
|
||||
}
|
||||
|
||||
// Connected! Show icon and negotiate session.
|
||||
logWrite("Connected\n");
|
||||
|
||||
packetEncryptionSetup(__packetThreadData);
|
||||
|
||||
PacketEncodeDataT encoded = { 0 };
|
||||
PacketDecodeDataT decoded = { 0 };
|
||||
|
||||
// Send it 10 times, waiting for a PONG between each.
|
||||
for (x=0; x<10; x++) {
|
||||
// Send PING.
|
||||
logWrite("Sending PING %d\n", x);
|
||||
encoded.control = PACKET_CONTROL_DAT;
|
||||
encoded.packetType = PACKET_TYPE_PING;
|
||||
encoded.channel = 1;
|
||||
encoded.encrypt = 0;
|
||||
packetEncode(__packetThreadData, &encoded, NULL, 0); // Must encode each packet - no reusing encoded data.
|
||||
packetSend(__packetThreadData, &encoded);
|
||||
// Wait for PONG.
|
||||
while (!guiHasStopped()) {
|
||||
r = comRead(__configData.serialCom - 1, buffer, 1);
|
||||
if (r == 1) {
|
||||
if (packetDecode(__packetThreadData, &decoded, buffer, 1)) {
|
||||
if (decoded.packetType == PACKET_TYPE_PONG) {
|
||||
logWrite("Received PONG\n");
|
||||
break;
|
||||
} else {
|
||||
logWrite("Unexpected packet type received %d\n", decoded.packetType);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
taskYield();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (guiHasStopped()) return;
|
||||
|
||||
// Send LOGIN.
|
||||
logWrite("Sending LOGIN\n");
|
||||
PacketTypeLoginT loginData;
|
||||
strcpy(loginData.user, "Encryption");
|
||||
strcpy(loginData.pass, "Works!");
|
||||
encoded.control = PACKET_CONTROL_DAT;
|
||||
encoded.packetType = PACKET_TYPE_LOGIN;
|
||||
encoded.channel = 1;
|
||||
encoded.encrypt = 1;
|
||||
packetEncode(__packetThreadData, &encoded, (char *)&loginData, sizeof(PacketTypeLoginT)); // Must encode each packet - no reusing encoded data.
|
||||
packetSend(__packetThreadData, &encoded);
|
||||
|
||||
// Send CLIENT_SHUTDOWN.
|
||||
logWrite("Sending CLIENT_SHUTDOWN\n");
|
||||
encoded.control = PACKET_CONTROL_DAT;
|
||||
encoded.packetType = PACKET_TYPE_CLIENT_SHUTDOWN;
|
||||
encoded.channel = 1;
|
||||
encoded.encrypt = 0;
|
||||
packetEncode(__packetThreadData, &encoded, NULL, 0);
|
||||
packetSend(__packetThreadData, &encoded);
|
||||
|
||||
logWrite("Sleeping\n");
|
||||
timerQuarterSecondsWait(8);
|
||||
|
||||
logWrite("COM closed\n");
|
||||
comClose(__configData.serialCom - 1);
|
||||
guiStop();
|
||||
}
|
||||
|
||||
|
||||
static void taskGuiEventLoop(void *data) {
|
||||
MouseT *mouse = NULL;
|
||||
ImageT *pointer = NULL;
|
||||
|
@ -211,6 +92,10 @@ static void taskGuiEventLoop(void *data) {
|
|||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
FILE *cache = NULL;
|
||||
char *line = NULL;
|
||||
char *p = NULL;
|
||||
|
||||
#ifndef __linux__
|
||||
// On DOS, display the contets of the log now that we're back in text mode.
|
||||
char *logName = NULL;
|
||||
|
@ -260,31 +145,74 @@ int main(int argc, char *argv[]) {
|
|||
sh_new_strdup(__runtimeData.integers);
|
||||
sh_new_strdup(__runtimeData.strings);
|
||||
|
||||
// ***TODO*** Load tables from disk cache
|
||||
// ***TODO*** Default initial tables
|
||||
|
||||
//taskCreate(taskComDebugLoop, NULL);
|
||||
mkdir("cache", 0777);
|
||||
line = (char *)malloc(4096);
|
||||
if (line) {
|
||||
// Load string cache.
|
||||
cache = fopen("cache/string.dat", "rt");
|
||||
if (cache) {
|
||||
while (fscanf(cache, "%s\n", line) != EOF) {
|
||||
p = strstr(line, "=");
|
||||
if (p) {
|
||||
*p = 0;
|
||||
p++;
|
||||
shput(__runtimeData.strings, line, strdup(p));
|
||||
}
|
||||
}
|
||||
fclose(cache);
|
||||
}
|
||||
// Load integer cache.
|
||||
cache = fopen("cache/integer.dat", "rt");
|
||||
if (cache) {
|
||||
while (fscanf(cache, "%s\n", line) != EOF) {
|
||||
p = strstr(line, "=");
|
||||
if (p) {
|
||||
*p = 0;
|
||||
p++;
|
||||
shput(__runtimeData.integers, line, atol(p));
|
||||
}
|
||||
}
|
||||
fclose(cache);
|
||||
}
|
||||
free(line);
|
||||
line = NULL;
|
||||
}
|
||||
|
||||
// taskCreate(taskSignUp, NULL);
|
||||
taskCreate(taskWelcome, NULL);
|
||||
taskCreate(taskGuiEventLoop, NULL);
|
||||
|
||||
taskRun();
|
||||
|
||||
// ***TODO*** Write tables from disk cache
|
||||
|
||||
// Free integer table.
|
||||
if (__runtimeData.integers) {
|
||||
while (shlen(__runtimeData.integers) > 0) {
|
||||
shdel(__runtimeData.integers, __runtimeData.integers[0].key);
|
||||
// Save & free integer table.
|
||||
cache = fopen("cache/integer.dat", "wt");
|
||||
if (cache) {
|
||||
if (__runtimeData.integers) {
|
||||
while (shlen(__runtimeData.integers) > 0) {
|
||||
//logWrite("[%s]=[%d]\n", __runtimeData.integers[0].key, __runtimeData.integers[0].value);
|
||||
fprintf(cache, "%s=%d\n", __runtimeData.integers[0].key, __runtimeData.integers[0].value);
|
||||
shdel(__runtimeData.integers, __runtimeData.integers[0].key);
|
||||
}
|
||||
shfree(__runtimeData.integers);
|
||||
}
|
||||
shfree(__runtimeData.integers);
|
||||
fclose(cache);
|
||||
}
|
||||
|
||||
// Free string table.
|
||||
if (__runtimeData.strings) {
|
||||
while (shlen(__runtimeData.strings) > 0) {
|
||||
DEL(__runtimeData.strings[0].value);
|
||||
shdel(__runtimeData.strings, __runtimeData.strings[0].key);
|
||||
// Save & free string table.
|
||||
cache = fopen("cache/string.dat", "wt");
|
||||
if (cache) {
|
||||
if (__runtimeData.strings) {
|
||||
while (shlen(__runtimeData.strings) > 0) {
|
||||
//logWrite("[%s]=[%s]\n", __runtimeData.strings[0].key, __runtimeData.strings[0].value);
|
||||
fprintf(cache, "%s=%s\n", __runtimeData.strings[0].key, __runtimeData.strings[0].value);
|
||||
DEL(__runtimeData.strings[0].value);
|
||||
shdel(__runtimeData.strings, __runtimeData.strings[0].key);
|
||||
}
|
||||
shfree(__runtimeData.strings);
|
||||
}
|
||||
shfree(__runtimeData.strings);
|
||||
fclose(cache);
|
||||
}
|
||||
|
||||
packetThreadDataDestroy(&__packetThreadData);
|
||||
|
|
|
@ -66,11 +66,16 @@ PacketDecodeDataT *netGetPacket(uint8_t channel) {
|
|||
}
|
||||
|
||||
|
||||
void netStop(void) {
|
||||
void netShutdown(void) {
|
||||
_netRunning = 0;
|
||||
}
|
||||
|
||||
|
||||
void netStartup(void) {
|
||||
taskCreate(taskNetwork, NULL);
|
||||
}
|
||||
|
||||
|
||||
void taskNetwork(void *data) {
|
||||
int32_t r = 0;
|
||||
int8_t pingTimeout = 0;
|
||||
|
|
|
@ -27,7 +27,8 @@
|
|||
|
||||
uint8_t netGetChannelFree(void);
|
||||
PacketDecodeDataT *netGetPacket(uint8_t channel);
|
||||
void netStop(void);
|
||||
void netShutdown(void);
|
||||
void netStartup(void);
|
||||
|
||||
void taskNetwork(void *data);
|
||||
|
||||
|
|
384
client/src/signup.c
Normal file
384
client/src/signup.c
Normal file
|
@ -0,0 +1,384 @@
|
|||
/*
|
||||
* Kangaroo Punch MultiPlayer Game Server Mark II
|
||||
* Copyright (C) 2020-2021 Scott Duensing
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "textbox.h"
|
||||
#include "button.h"
|
||||
#include "label.h"
|
||||
#include "msgbox.h"
|
||||
|
||||
#include "network.h"
|
||||
#include "runtime.h"
|
||||
#include "taglist.h"
|
||||
#include "timer.h"
|
||||
#include "task.h"
|
||||
|
||||
#include "signup.h"
|
||||
#include "login.h"
|
||||
|
||||
|
||||
static WindowT *_winSignUp = NULL;
|
||||
static LabelT *_lblRequired = NULL;
|
||||
static TextboxT *_txtEmail = NULL;
|
||||
static TextboxT *_txtFirst = NULL;
|
||||
static TextboxT *_txtLast = NULL;
|
||||
static TextboxT *_txtUser = NULL;
|
||||
static TextboxT *_txtPass1 = NULL;
|
||||
static TextboxT *_txtPass2 = NULL;
|
||||
static ButtonT *_btnCancel = NULL;
|
||||
static ButtonT *_btnSignUp = NULL;
|
||||
|
||||
|
||||
static void btnCancelClick(WidgetT *widget);
|
||||
static void btnMsgBoxContinue(MsgBoxButtonT button);
|
||||
static void btnMsgBoxFinish(MsgBoxButtonT button);
|
||||
static void setButtons(uint8_t enabled);
|
||||
static void taskSignUpClick(void *data);
|
||||
static uint8_t validateEmail(char *email);
|
||||
static uint8_t validateEmailLetter(char c);
|
||||
static uint8_t validateName(char *username);
|
||||
static uint8_t validatePassword(char *password);
|
||||
static uint8_t validateUser(char *username);
|
||||
|
||||
|
||||
static void btnCancelClick(WidgetT *widget) {
|
||||
(void)widget;
|
||||
|
||||
guiDelete(D(_winSignUp));
|
||||
taskCreate(taskLogin, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void btnMsgBoxContinue(MsgBoxButtonT button) {
|
||||
(void)button;
|
||||
|
||||
setButtons(1);
|
||||
}
|
||||
|
||||
|
||||
static void btnMsgBoxFinish(MsgBoxButtonT button) {
|
||||
(void)button;
|
||||
|
||||
guiDelete(D(_winSignUp));
|
||||
taskCreate(taskLogin, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void setButtons(uint8_t enabled) {
|
||||
widgetEnableSet(W(_btnCancel), enabled);
|
||||
widgetEnableSet(W(_btnSignUp), enabled);
|
||||
}
|
||||
|
||||
|
||||
void taskSignUp(void *data) {
|
||||
|
||||
(void)data;
|
||||
|
||||
TagItemT uiSignUp[] = {
|
||||
T_START,
|
||||
T_WINDOW, O(_winSignUp),
|
||||
T_TITLE, P("Create New Account"),
|
||||
T_WIDTH, 400, T_HEIGHT, 340,
|
||||
|
||||
T_LABEL, O(_lblRequired),
|
||||
T_TITLE, P("All fields are required!"),
|
||||
T_X, 100, T_Y, 25,
|
||||
T_COLOR_FOREGROUND, vbeColorMake(255, 255, 0),
|
||||
T_LABEL, T_DONE,
|
||||
|
||||
T_TEXTBOX, O(_txtUser),
|
||||
// 123456789012345678
|
||||
T_TITLE, P(" User Name:"),
|
||||
T_X, 40, T_Y, 64,
|
||||
T_WIDTH, 300,
|
||||
T_LENGTH, 16,
|
||||
T_TEXTBOX, T_DONE,
|
||||
|
||||
T_TEXTBOX, O(_txtPass1),
|
||||
// 123456789012345678
|
||||
T_TITLE, P(" Password:"),
|
||||
T_X, 40, T_Y, 94,
|
||||
T_WIDTH, 300,
|
||||
T_LENGTH, 16,
|
||||
T_MASK, '*',
|
||||
T_TEXTBOX, T_DONE,
|
||||
|
||||
T_TEXTBOX, O(_txtPass2),
|
||||
// 123456789012345678
|
||||
T_TITLE, P(" Password (again):"),
|
||||
T_X, 40, T_Y, 124,
|
||||
T_WIDTH, 300,
|
||||
T_LENGTH, 16,
|
||||
T_MASK, '*',
|
||||
T_TEXTBOX, T_DONE,
|
||||
|
||||
T_TEXTBOX, O(_txtFirst),
|
||||
// 123456789012345678
|
||||
T_TITLE, P(" REAL First Name:"),
|
||||
T_X, 40, T_Y, 154,
|
||||
T_WIDTH, 300,
|
||||
T_LENGTH, 16,
|
||||
T_MASK, '*',
|
||||
T_TEXTBOX, T_DONE,
|
||||
|
||||
T_TEXTBOX, O(_txtLast),
|
||||
// 123456789012345678
|
||||
T_TITLE, P(" REAL Last Name:"),
|
||||
T_X, 40, T_Y, 184,
|
||||
T_WIDTH, 300,
|
||||
T_LENGTH, 16,
|
||||
T_MASK, '*',
|
||||
T_TEXTBOX, T_DONE,
|
||||
|
||||
T_TEXTBOX, O(_txtEmail),
|
||||
// 123456789012345678
|
||||
T_TITLE, P(" VALID E-Mail:"),
|
||||
T_X, 40, T_Y, 214,
|
||||
T_WIDTH, 300,
|
||||
T_LENGTH, 16,
|
||||
T_MASK, '*',
|
||||
T_TEXTBOX, T_DONE,
|
||||
|
||||
T_BUTTON, O(_btnCancel),
|
||||
T_TITLE, P("Cancel"),
|
||||
T_X, 25, T_Y, 270,
|
||||
T_CLICK, P(btnCancelClick),
|
||||
T_BUTTON, T_DONE,
|
||||
T_BUTTON, O(_btnSignUp),
|
||||
T_TITLE, P("Sign Up"),
|
||||
T_X, 291, T_Y, 270,
|
||||
T_CLICK, P(taskProxy),
|
||||
T_USER_DATA, P(taskSignUpClick),
|
||||
T_BUTTON, T_DONE,
|
||||
|
||||
T_WINDOW, T_DONE,
|
||||
T_END
|
||||
};
|
||||
|
||||
tagListRun(uiSignUp);
|
||||
}
|
||||
|
||||
|
||||
static void taskSignUpClick(void *data) {
|
||||
PacketEncodeDataT encoded = { 0 };
|
||||
PacketDecodeDataT *decoded = NULL;
|
||||
PacketTypeSignUpT signup = { 0 };
|
||||
PacketTypeSignUpResultT *result = { 0 };
|
||||
int16_t timeout = 5;
|
||||
|
||||
(void)data;
|
||||
|
||||
// ***TODO*** This should disable the entire dialog instead of just the buttons. Need to finish the Enable GUI code first.
|
||||
|
||||
setButtons(0);
|
||||
|
||||
// Get the data.
|
||||
memcpy(signup.email, textboxValueGet(_txtEmail), strlen(textboxValueGet(_txtEmail)));
|
||||
memcpy(signup.first, textboxValueGet(_txtFirst), strlen(textboxValueGet(_txtFirst)));
|
||||
memcpy(signup.last, textboxValueGet(_txtLast), strlen(textboxValueGet(_txtLast)));
|
||||
memcpy(signup.pass, textboxValueGet(_txtPass1), strlen(textboxValueGet(_txtPass1)));
|
||||
memcpy(signup.user, textboxValueGet(_txtUser), strlen(textboxValueGet(_txtUser)));
|
||||
|
||||
// Validate it. ***TODO*** These messages could be a lot better.
|
||||
if (!validateEmail(signup.email)) {
|
||||
msgBoxOne("Invalid E-Mail", MSGBOX_ICON_ERROR, "Please enter a valid E-mail address.", "Okay", btnMsgBoxContinue);
|
||||
return;
|
||||
}
|
||||
if (!validateName(signup.first)) {
|
||||
msgBoxOne("Invalid First Name", MSGBOX_ICON_ERROR, "Please enter a valid first name.", "Okay", btnMsgBoxContinue);
|
||||
return;
|
||||
}
|
||||
if (!validateName(signup.last)) {
|
||||
msgBoxOne("Invalid Last Name", MSGBOX_ICON_ERROR, "Please enter a valid last name.", "Okay", btnMsgBoxContinue);
|
||||
return;
|
||||
}
|
||||
if (strcmp(textboxValueGet(_txtPass1), textboxValueGet(_txtPass2)) != 0) {
|
||||
msgBoxOne("Invalid Password", MSGBOX_ICON_ERROR, "Passwords must match.", "Okay", btnMsgBoxContinue);
|
||||
return;
|
||||
}
|
||||
if (!validatePassword(signup.pass)) {
|
||||
msgBoxOne("Invalid Password", MSGBOX_ICON_ERROR, "Please enter a valid password.", "Okay", btnMsgBoxContinue);
|
||||
return;
|
||||
}
|
||||
if (!validateUser(signup.user)) {
|
||||
msgBoxOne("Invalid User Name", MSGBOX_ICON_ERROR, "Please enter a valid user name.", "Okay", btnMsgBoxContinue);
|
||||
return;
|
||||
}
|
||||
|
||||
// Send signup request.
|
||||
encoded.packetType = PACKET_TYPE_SIGNUP;
|
||||
encoded.control = PACKET_CONTROL_DAT;
|
||||
encoded.channel = 0;
|
||||
encoded.encrypt = 0;
|
||||
packetEncode(__packetThreadData, &encoded, (char *)&signup, sizeof(PacketTypeSignUpT));
|
||||
packetSend(__packetThreadData, &encoded);
|
||||
|
||||
// Wait for response.
|
||||
do {
|
||||
decoded = netGetPacket(0);
|
||||
if (decoded) {
|
||||
switch (decoded->packetType) {
|
||||
case PACKET_TYPE_SIGNUP_RESULT:
|
||||
result = (PacketTypeSignUpResultT *)decoded->data;
|
||||
if (result->success) {
|
||||
msgBoxOne("Success!", MSGBOX_ICON_INFORMATION, result->message, "Okay", btnMsgBoxFinish);
|
||||
} else {
|
||||
msgBoxOne("Uh Oh!", MSGBOX_ICON_ERROR, result->message, "Okay", btnMsgBoxContinue);
|
||||
}
|
||||
timeout = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
logWrite("Unexpected packet received: %d\n", decoded->packetType);
|
||||
break;
|
||||
}
|
||||
packetDecodeDataDestroy(&decoded);
|
||||
}
|
||||
taskYield();
|
||||
if (__timerQuarterSecondTick) timeout--;
|
||||
} while (!guiHasStopped() && timeout > 0);
|
||||
|
||||
setButtons(1);
|
||||
}
|
||||
|
||||
|
||||
static uint8_t validateEmail(char *email) {
|
||||
|
||||
uint16_t x;
|
||||
uint16_t step = 0;
|
||||
|
||||
// This does a really terrible job of checking if a string is an email address.
|
||||
// It only has be sorta close. The server will make sure.
|
||||
|
||||
for (x=0; x<strlen(email); x++) {
|
||||
|
||||
switch (step) {
|
||||
|
||||
// Look for username
|
||||
case 0:
|
||||
if (validateEmailLetter(email[x])) step++;
|
||||
break;
|
||||
|
||||
// Look for @
|
||||
case 1:
|
||||
if (email[x] == '@') step++;
|
||||
break;
|
||||
|
||||
// Look for domain
|
||||
case 2:
|
||||
if (validateEmailLetter(email[x])) step++;
|
||||
break;
|
||||
|
||||
// Look for dot
|
||||
case 3:
|
||||
if (email[x] == '.') step++;
|
||||
break;
|
||||
|
||||
// Look for TLD
|
||||
case 4:
|
||||
if (validateEmailLetter(email[x])) return 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t validateEmailLetter(char c) {
|
||||
if ((c >= '0') && (c <= '9')) return 1;
|
||||
if ((c >= 'a') && (c <= 'z')) return 1;
|
||||
if ((c >= 'A') && (c <= 'Z')) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t validateName(char *username) {
|
||||
uint16_t x;
|
||||
char *allowed;
|
||||
char needle[2];
|
||||
|
||||
if ((int32_t)strlen(username) < shget(__runtimeData.integers, "minName")) return 0;
|
||||
if ((int32_t)strlen(username) > shget(__runtimeData.integers, "maxName")) return 0;
|
||||
|
||||
allowed = shget(__runtimeData.strings, "nameAllowed");
|
||||
needle[1] = 0;
|
||||
for (x=0; x<strlen(username); x++) {
|
||||
needle[0] = username[x];
|
||||
if (!strstr(allowed, needle)) return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t validatePassword(char *password) {
|
||||
uint16_t x;
|
||||
uint16_t lowerCount = 0;
|
||||
uint16_t upperCount = 0;
|
||||
uint16_t specialCount = 0;
|
||||
uint16_t numericCount = 0;
|
||||
char *passLower;
|
||||
char *passUpper;
|
||||
char *passSpecial;
|
||||
char *passNumeric;
|
||||
char needle[2];
|
||||
|
||||
if ((int32_t)strlen(password) < shget(__runtimeData.integers, "minPass")) return 0;
|
||||
if ((int32_t)strlen(password) > shget(__runtimeData.integers, "maxPass")) return 0;
|
||||
|
||||
passLower = shget(__runtimeData.strings, "passLower");
|
||||
passUpper = shget(__runtimeData.strings, "passUpper");
|
||||
passSpecial = shget(__runtimeData.strings, "passSpecial");
|
||||
passNumeric = shget(__runtimeData.strings, "passNumeric");
|
||||
needle[1] = 0;
|
||||
for (x=0; x<strlen(password); x++) {
|
||||
needle[0] = password[x];
|
||||
if (strstr(passLower, needle)) lowerCount++;
|
||||
if (strstr(passUpper, needle)) upperCount++;
|
||||
if (strstr(passSpecial, needle)) specialCount++;
|
||||
if (strstr(passNumeric, needle)) numericCount++;
|
||||
}
|
||||
|
||||
if (lowerCount < shget(__runtimeData.integers, "minPassLower")) return 0;
|
||||
if (upperCount < shget(__runtimeData.integers, "minPassUpper")) return 0;
|
||||
if (specialCount < shget(__runtimeData.integers, "minPassSpecial")) return 0;
|
||||
if (numericCount < shget(__runtimeData.integers, "minPassNumeric")) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t validateUser(char *username) {
|
||||
uint16_t x;
|
||||
char *allowed;
|
||||
char needle[2];
|
||||
|
||||
if ((int32_t)strlen(username) < shget(__runtimeData.integers, "minUser")) return 0;
|
||||
if ((int32_t)strlen(username) > shget(__runtimeData.integers, "maxUser")) return 0;
|
||||
|
||||
allowed = shget(__runtimeData.strings, "userAllowed");
|
||||
needle[1] = 0;
|
||||
for (x=0; x<strlen(username); x++) {
|
||||
needle[0] = username[x];
|
||||
if (!strstr(allowed, needle)) return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
31
client/src/signup.h
Normal file
31
client/src/signup.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Kangaroo Punch MultiPlayer Game Server Mark II
|
||||
* Copyright (C) 2020-2021 Scott Duensing
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SIGNUP_H
|
||||
#define SIGNUP_H
|
||||
|
||||
|
||||
#include "os.h"
|
||||
|
||||
|
||||
void taskSignUp(void *data);
|
||||
|
||||
|
||||
#endif // SIGNUP_H
|
23
client/src/system/os.c
Normal file
23
client/src/system/os.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Kangaroo Punch MultiPlayer Game Server Mark II
|
||||
* Copyright (C) 2020-2021 Scott Duensing
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "os.h"
|
||||
|
||||
|
|
@ -34,6 +34,7 @@
|
|||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
||||
#ifdef __linux__
|
||||
|
|
|
@ -106,6 +106,7 @@ static void tagListWidgetAttributeHandle(void) {
|
|||
uint8_t hasIndex;
|
||||
uint8_t enabled;
|
||||
uint8_t visible;
|
||||
char mask;
|
||||
|
||||
// Process generated lists in reverse.
|
||||
while (arrlen(_widgetList) > 0) {
|
||||
|
@ -140,6 +141,7 @@ static void tagListWidgetAttributeHandle(void) {
|
|||
hasIndex = 0;
|
||||
enabled = 1;
|
||||
visible = 1;
|
||||
mask = 0;
|
||||
|
||||
// Parse provided attributes.
|
||||
for (i=0; i<arrlen(w->tagList); i+=2) {
|
||||
|
@ -196,6 +198,10 @@ static void tagListWidgetAttributeHandle(void) {
|
|||
length = v;
|
||||
break;
|
||||
|
||||
case T_MASK:
|
||||
mask = v;
|
||||
break;
|
||||
|
||||
case T_MAXIMUM:
|
||||
maximum = v;
|
||||
break;
|
||||
|
@ -320,8 +326,9 @@ static void tagListWidgetAttributeHandle(void) {
|
|||
|
||||
case T_TEXTBOX:
|
||||
widget = W(textboxNew(pos.x, pos.y, pos.w, title));
|
||||
textboxValueSet((TextboxT *)widget, valueString);
|
||||
if (hasValue) textboxValueSet((TextboxT *)widget, valueString);
|
||||
if (length > 0) textboxLengthMaxSet((TextboxT *)widget, length);
|
||||
textboxPasswordCharacterSet((TextboxT *)widget, mask);
|
||||
break;
|
||||
|
||||
case T_UPDOWN:
|
||||
|
|
|
@ -71,6 +71,7 @@ enum TagItemsE {
|
|||
T_INDEX,
|
||||
T_ITEM,
|
||||
T_LENGTH,
|
||||
T_MASK,
|
||||
T_MAXIMUM,
|
||||
T_MINIMUM,
|
||||
T_SELECTED,
|
||||
|
|
|
@ -137,7 +137,7 @@ static void taskConnectClick(void *data) {
|
|||
}
|
||||
|
||||
// Start packet handler and negotiate encryption.
|
||||
taskCreate(taskNetwork, NULL);
|
||||
netStartup();
|
||||
packetEncryptionSetup(__packetThreadData);
|
||||
timeout = 5;
|
||||
do {
|
||||
|
@ -161,20 +161,18 @@ static void taskConnectClick(void *data) {
|
|||
switch (decoded->packetType) {
|
||||
case PACKET_TYPE_NUMBER:
|
||||
// Store in number table.
|
||||
logWrite("Added integer: [%s] = [%d]\n", &decoded->data[4], (int32_t)decoded->data[0]);
|
||||
shput(__runtimeData.integers, &decoded->data[4], (int32_t)decoded->data[0]);
|
||||
// Reset timeout.
|
||||
timeout = 10;
|
||||
break;
|
||||
|
||||
case PACKET_TYPE_PROCEED:
|
||||
logWrite("Received PACKET_TYPE_PROCEED\n");
|
||||
waiting = 0;
|
||||
break;
|
||||
|
||||
case PACKET_TYPE_STRING:
|
||||
// Store in string table.
|
||||
logWrite("Added string: [%s] = [%s]\n", decoded->data, &decoded->data[strlen(decoded->data) + 1]);
|
||||
//logWrite("Storing [%s]=[%s]\n", decoded->data, &decoded->data[strlen(decoded->data) + 1]);
|
||||
shput(__runtimeData.strings, decoded->data, strdup(&decoded->data[strlen(decoded->data) + 1]));
|
||||
// Reset timeout.
|
||||
timeout = 10;
|
||||
|
@ -219,7 +217,7 @@ static void taskConnectClick(void *data) {
|
|||
// Connected! Show icon.
|
||||
widgetVisibleSet(W(_picConnect), 1);
|
||||
timeout = 6; // Roughly 1.5 seconds.
|
||||
while (timeout > 0) {
|
||||
while (timeout > 0 && !guiHasStopped()) {
|
||||
taskYield();
|
||||
if (__timerQuarterSecondTick) timeout--;
|
||||
}
|
||||
|
@ -244,7 +242,7 @@ static void btnSettingsClick(WidgetT *widget) {
|
|||
}
|
||||
|
||||
|
||||
void setButtons(uint8_t enabled) {
|
||||
static void setButtons(uint8_t enabled) {
|
||||
widgetEnableSet(W(_btnConnect), (__configData.serialCom > 0 && strlen(__configData.serverHost) > 2) ? enabled : 0);
|
||||
widgetEnableSet(W(_btnSettings), enabled);
|
||||
widgetEnableSet(W(_btnQuit), enabled);
|
||||
|
|
|
@ -92,7 +92,10 @@ static void clientProcessPacket(ClientThreadT *client, PacketDecodeDataT *data)
|
|||
packetEncode(client->packetThreadData, &encoded, NULL, 0);
|
||||
// Send it.
|
||||
packetSend(client->packetThreadData, &encoded);
|
||||
logWrite("Got PING, sent PONG\n\r");
|
||||
break;
|
||||
|
||||
case PACKET_TYPE_SIGNUP:
|
||||
//***TODO***
|
||||
break;
|
||||
|
||||
case PACKET_TYPE_VERSION_BAD:
|
||||
|
@ -100,21 +103,19 @@ static void clientProcessPacket(ClientThreadT *client, PacketDecodeDataT *data)
|
|||
break;
|
||||
|
||||
case PACKET_TYPE_VERSION_OKAY:
|
||||
logWrite("Got VERSION_OK.\n\r");
|
||||
// Fetch string table from REST.
|
||||
response = restRequest("CONFIG_GET_STRINGS", NULL);
|
||||
if (!response) {
|
||||
logWrite("Unable to fetch strings!\n\r");
|
||||
consoleMessageQueue("%ld: Unable to fetch strings!\n", client->threadIndex);
|
||||
break;
|
||||
}
|
||||
strings = restHelperConfigStringMapGet(response);
|
||||
if (!strings) {
|
||||
logWrite("Unable to map strings!\n\r");
|
||||
consoleMessageQueue("%ld: Unable to map strings!\n", client->threadIndex);
|
||||
break;
|
||||
}
|
||||
restRelease(response);
|
||||
// Send string table to client.
|
||||
logWrite("Sending strings.\n\r");
|
||||
for (i=0; i<(unsigned)shlen(strings); i++) {
|
||||
// Strings are encoded in a single buffer as: KEY\0DATA\0
|
||||
x = strlen(strings[i].key);
|
||||
|
@ -122,11 +123,12 @@ static void clientProcessPacket(ClientThreadT *client, PacketDecodeDataT *data)
|
|||
length = x + y + 2;
|
||||
buffer = (char *)malloc(length);
|
||||
if (!buffer) {
|
||||
logWrite("Unable to allocate buffer for string packet!\n\r");
|
||||
consoleMessageQueue("%ld: Unable to allocate buffer for string packet!\n", client->threadIndex);
|
||||
break;
|
||||
}
|
||||
memcpy(buffer, strings[i].key, x + 1);
|
||||
memcpy(&buffer[x + 1], strings[i].value, y + 1);
|
||||
//consoleMessageQueue("[%s]=[%s]\n", strings[i].key, strings[i].value);
|
||||
// Build packet.
|
||||
encoded.control = PACKET_CONTROL_DAT;
|
||||
encoded.packetType = PACKET_TYPE_STRING;
|
||||
|
@ -136,23 +138,21 @@ static void clientProcessPacket(ClientThreadT *client, PacketDecodeDataT *data)
|
|||
// Send it.
|
||||
packetSend(client->packetThreadData, &encoded);
|
||||
DEL(buffer);
|
||||
//logWrite("[%s] = [%s]\r\n", strings[i].key, strings[i].value);
|
||||
}
|
||||
restHelperConfigStringMapRelease(strings);
|
||||
// Fetch number table from REST.
|
||||
response = restRequest("CONFIG_GET_NUMBERS", NULL);
|
||||
if (!response) {
|
||||
logWrite("Unable to fetch numbers!\n\r");
|
||||
consoleMessageQueue("%ld: Unable to fetch numbers!\n", client->threadIndex);
|
||||
break;
|
||||
}
|
||||
integers = restHelperConfigIntegerMapGet(response);
|
||||
if (!integers) {
|
||||
logWrite("Unable to map numbers!\n\r");
|
||||
consoleMessageQueue("%ld: Unable to map numbers!\n", client->threadIndex);
|
||||
break;
|
||||
}
|
||||
restRelease(response);
|
||||
// Send number table to client.
|
||||
logWrite("Sending numbers.\n\r");
|
||||
for (i=0; i<(unsigned)shlen(integers); i++) {
|
||||
// Integers are encoded in a single buffer as: 1234DATA\0
|
||||
// Integers are 64 bit until sent to the client when they are truncated to 32.
|
||||
|
@ -161,7 +161,7 @@ static void clientProcessPacket(ClientThreadT *client, PacketDecodeDataT *data)
|
|||
length = x + 5;
|
||||
buffer = (char *)malloc(length);
|
||||
if (!buffer) {
|
||||
logWrite("Unable to allocate buffer for number packet!\n\r");
|
||||
consoleMessageQueue("%ld: Unable to allocate buffer for number packet!\n\r", client->threadIndex);
|
||||
break;
|
||||
}
|
||||
memcpy(buffer, &y, 4);
|
||||
|
@ -186,7 +186,6 @@ static void clientProcessPacket(ClientThreadT *client, PacketDecodeDataT *data)
|
|||
packetEncode(client->packetThreadData, &encoded, NULL, 0);
|
||||
// Send it.
|
||||
packetSend(client->packetThreadData, &encoded);
|
||||
logWrite("Sending proceed.\n\r");
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "os.h"
|
||||
#include "rest.h"
|
||||
#include "array.h"
|
||||
#include "console.h"
|
||||
|
||||
|
||||
typedef struct RestResponseS {
|
||||
|
@ -147,6 +148,7 @@ RestStringMapT *restHelperConfigStringMapGet(json_object *object) {
|
|||
for (i=0; i<json_object_array_length(data); i++) {
|
||||
item = json_object_array_get_idx(data, i);
|
||||
shput(result, json_object_get_string(json_object_object_get(item, "name")), strdup(json_object_get_string(json_object_object_get(item, "data"))));
|
||||
//consoleMessageQueue("[%s]=[%s]\n", json_object_get_string(json_object_object_get(item, "name")), json_object_get_string(json_object_object_get(item, "data")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,12 +38,12 @@ void serverDisconnectClient(ClientThreadT *client) {
|
|||
void *status = NULL;
|
||||
char buffer[2048] = { 0 };
|
||||
|
||||
// Stop client processing.
|
||||
client->running = 0;
|
||||
pthread_join(client->threadHandle, &status);
|
||||
// Tell the console.
|
||||
enet_address_get_host_ip(&peer->address, buffer, 2047);
|
||||
consoleMessageQueue("%ld: [%s] disconnected.\n", client->threadIndex, buffer);
|
||||
// Stop client processing.
|
||||
client->running = 0;
|
||||
pthread_join(client->threadHandle, &status);
|
||||
// Hang up.
|
||||
enet_peer_reset(peer);
|
||||
}
|
||||
|
|
|
@ -74,6 +74,23 @@ static void *packetAesContextCreate(uint8_t *key, uint8_t *iv) {
|
|||
static uint8_t packetCRC(char *data, uint16_t length, uint8_t startAt) {
|
||||
uint16_t x = 0;
|
||||
|
||||
/*
|
||||
* ***TODO***
|
||||
*
|
||||
* Something in the data is throwing this off. CRCs fail when there are
|
||||
* "special characters" in the data, such as these string table fields:
|
||||
*
|
||||
* Storing [userAllowed]=[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890`!@#$%^&*()_-+=[]{}\/?<>.,:;"']
|
||||
* CRC failed! 192 != 60
|
||||
*
|
||||
* Storing [passSpecial]=[`!@#$%^&*()_-+=[]\{}|:;"',.<>/?]
|
||||
* CRC failed! 8 != 244
|
||||
*
|
||||
* Like the rest of the reliability code, this is only needed if we have
|
||||
* RS-232 issues to the softmodem. Documenting for later if needed.
|
||||
*
|
||||
*/
|
||||
|
||||
for (x=0; x<length; x++) {
|
||||
startAt ^= data[x] + data[x]; // Just XOR and increment.
|
||||
}
|
||||
|
@ -122,10 +139,14 @@ uint8_t packetDecode(PacketThreadDataT *threadData, PacketDecodeDataT *decodeDat
|
|||
if (c != PACKET_FRAME) {
|
||||
threadData->newPacket = 1;
|
||||
|
||||
// Check CRC.
|
||||
if ((uint8_t)threadData->decodeBuffer[threadData->length - 1] != packetCRC(threadData->decodeBuffer, threadData->length - 1, 0)) continue;
|
||||
|
||||
/*
|
||||
// Check CRC.
|
||||
x = packetCRC(threadData->decodeBuffer, threadData->length - 1, 0);
|
||||
if ((uint8_t)threadData->decodeBuffer[threadData->length - 1] != (uint8_t)x) {
|
||||
//logWrite("CRC failed! %d != %d\n", (uint8_t)threadData->decodeBuffer[threadData->length - 1], (uint8_t)x);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get sequence value.
|
||||
sequence = ((uint8_t)threadData->decodeBuffer[0]) & 0x1f;
|
||||
|
||||
|
|
|
@ -27,8 +27,11 @@
|
|||
|
||||
#define PACKET_PROTOCOL_VERSION 1
|
||||
|
||||
#define PACKET_MAX_USER 16
|
||||
#define PACKET_MAX_PASS 16
|
||||
#define PACKET_MAX_USER 16 // These need to match the configuration in the database.
|
||||
#define PACKET_MAX_PASS 16 // Or better, use the database values.
|
||||
#define PACKET_MAX_NAME 32
|
||||
#define PACKET_MAX_EMAIL 32
|
||||
#define PACKET_MAX_MESSAGE 256
|
||||
|
||||
|
||||
// This enum is treated as BYTES in the code. Do not go over 255 entries.
|
||||
|
@ -47,6 +50,8 @@ typedef enum PacketTypeE {
|
|||
PACKET_TYPE_NUMBER,
|
||||
PACKET_TYPE_PROCEED,
|
||||
PACKET_TYPE_LOGIN,
|
||||
PACKET_TYPE_SIGNUP,
|
||||
PACKET_TYPE_SIGNUP_RESULT,
|
||||
PACKET_TYPE_COUNT
|
||||
} PacketTypeT;
|
||||
|
||||
|
@ -62,6 +67,19 @@ typedef struct PacketTypeLoginS {
|
|||
char pass[PACKET_MAX_PASS];
|
||||
} PacketTypeLoginT;
|
||||
|
||||
typedef struct PacketTypeSignUpS {
|
||||
char user[PACKET_MAX_USER];
|
||||
char pass[PACKET_MAX_PASS];
|
||||
char first[PACKET_MAX_NAME];
|
||||
char last[PACKET_MAX_NAME];
|
||||
char email[PACKET_MAX_EMAIL];
|
||||
} PacketTypeSignUpT;
|
||||
|
||||
typedef struct PacketTypeSignUpResultS {
|
||||
uint8_t success;
|
||||
char message[PACKET_MAX_MESSAGE];
|
||||
} PacketTypeSignUpResultT;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue