Login and Sign Up dialogs implemented.

This commit is contained in:
Scott Duensing 2022-01-14 19:06:01 -06:00
parent 5a840ab1bf
commit 7174d36eb9
21 changed files with 734 additions and 173 deletions

View file

@ -72,6 +72,7 @@ HEADERS = \
src/login.h \ src/login.h \
src/network.h \ src/network.h \
src/runtime.h \ src/runtime.h \
src/signup.h \
src/thirdparty/minicoro/minicoro.h \ src/thirdparty/minicoro/minicoro.h \
src/system/comport.h \ src/system/comport.h \
src/settings.h \ src/settings.h \
@ -119,7 +120,9 @@ SOURCES = \
src/login.c \ src/login.c \
src/network.c \ src/network.c \
src/settings.c \ src/settings.c \
src/signup.c \
src/system/comport.c \ src/system/comport.c \
src/system/os.c \
src/system/surface.c \ src/system/surface.c \
src/system/taglist.c \ src/system/taglist.c \
$$SHARED/util.c \ $$SHARED/util.c \

BIN
client/data/ddialing.png (Stored with Git LFS)

Binary file not shown.

View file

@ -58,6 +58,7 @@ WidgetT *textboxInit(WidgetT *widget, char *title) {
t->value = (char *)malloc(t->maxLength); t->value = (char *)malloc(t->maxLength);
t->caret = 0; t->caret = 0;
t->offset = 0; t->offset = 0;
t->password = 0;
if (!t->value) return NULL; if (!t->value) return NULL;
t->value[0] = 0; t->value[0] = 0;
@ -76,6 +77,7 @@ static void textboxKeyboardEvent(WidgetT *widget, uint8_t ascii, uint8_t extende
TextboxT *t = (TextboxT *)widget; TextboxT *t = (TextboxT *)widget;
uint16_t x; uint16_t x;
uint16_t y;
char *temp; char *temp;
(void)scancode; (void)scancode;
@ -167,20 +169,25 @@ static void textboxKeyboardEvent(WidgetT *widget, uint8_t ascii, uint8_t extende
default: // Other keys default: // Other keys
if (ascii >= 32 && ascii <= 126) { if (ascii >= 32 && ascii <= 126) {
// Remember length so we can zero terminate this after the edit.
y = strlen(t->value);
// Insert character, if room. // 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. // Move existing characters over, if needed.
if (t->caret + t->offset < strlen(t->value)) { if (t->caret + t->offset < y) {
for (x=strlen(t->value) + 1; x>t->caret + t->offset; x--) { for (x=y + 1; x>t->caret + t->offset; x--) {
t->value[x] = t->value[x-1]; t->value[x] = t->value[x-1];
} }
} }
// Place typed character at caret. // Place typed character at caret.
t->value[t->caret + t->offset] = ascii; 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? // Is the caret on the right edge of the box?
if (t->caret == t->visible - 1) { if (t->caret == t->visible - 1) {
// Can we move the string offset? // Can we move the string offset?
if (t->offset < strlen(t->value)) { if (t->offset < y) {
t->offset++; t->offset++;
} }
} else { } else {
@ -267,6 +274,7 @@ static void textboxPaint(WidgetT *widget, uint8_t enabled, RectT pos) {
uint16_t textY; uint16_t textY;
char cursor[2] = { 0xb1, 0 }; char cursor[2] = { 0xb1, 0 };
if (GUI_GET_FLAG(widget, WIDGET_FLAG_DIRTY) || guiFocusGet() == widget) { if (GUI_GET_FLAG(widget, WIDGET_FLAG_DIRTY) || guiFocusGet() == widget) {
labelWidth = (strlen(t->title) * fontWidthGet(_guiFont)) + _guiMetric[METRIC_TEXTBOX_PADDING]; labelWidth = (strlen(t->title) * fontWidthGet(_guiFont)) + _guiMetric[METRIC_TEXTBOX_PADDING];
valueWidth = (t->visible * fontWidthGet(_guiFont)) + (_guiMetric[METRIC_TEXTBOX_HORIZONTAL_PADDING] * 2); 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 value.
draw = strdup(&t->value[t->offset]); draw = strdup(&t->value[t->offset]);
if (strlen(draw) > t->visible) draw[t->visible] = 0; 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); fontRender(_guiFont, draw, _guiColor[COLOR_TEXTBOX_TEXT], _guiColor[COLOR_TEXTBOX_BACKGROUND], textX, textY);
free(draw); 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) { void textboxTitleSet(TextboxT *textbox, char *title) {
if (textbox->title) free(textbox->title); if (textbox->title) free(textbox->title);
textbox->title = strdup(title); textbox->title = strdup(title);

View file

@ -30,6 +30,7 @@ typedef struct TextboxS {
WidgetT base; // Must be first in every widget WidgetT base; // Must be first in every widget
char *title; char *title;
char *value; char *value;
char password; // Character to use to mask passwords
uint16_t maxLength; // Maximum length of value + 1 uint16_t maxLength; // Maximum length of value + 1
uint16_t caret; // Cursor position in control (caret + offset = cursor positition in value) uint16_t caret; // Cursor position in control (caret + offset = cursor positition in value)
uint16_t offset; // First character position to display in control uint16_t offset; // First character position to display in control
@ -40,6 +41,7 @@ typedef struct TextboxS {
WidgetT *textboxInit(WidgetT *widget, char *title); WidgetT *textboxInit(WidgetT *widget, char *title);
void textboxLengthMaxSet(TextboxT *textbox, uint16_t length); void textboxLengthMaxSet(TextboxT *textbox, uint16_t length);
TextboxT *textboxNew(uint16_t x, uint16_t y, uint16_t w, char *title); 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); void textboxTitleSet(TextboxT *textbox, char *title);
char *textboxValueGet(TextboxT *textbox); char *textboxValueGet(TextboxT *textbox);
void textboxValueSet(TextboxT *textbox, char *value); void textboxValueSet(TextboxT *textbox, char *value);

View file

@ -28,6 +28,7 @@ uint8_t widgetEnableGet(WidgetT *widget) {
void widgetEnableSet(WidgetT *widget, uint8_t enabled) { 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. // We did "DISABLED" for the flag so that "flags = 0" (the default) would enable widgets.
if (enabled) { if (enabled) {
GUI_CLEAR_FLAG(widget, WIDGET_FLAG_DISABLED); GUI_CLEAR_FLAG(widget, WIDGET_FLAG_DISABLED);

View file

@ -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 "taglist.h"
#include "timer.h"
#include "task.h" #include "task.h"
#include "login.h"
#include "signup.h"
#include "welcome.h"
static WindowT *_winLogin = NULL; 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) { void taskLogin(void *data) {
@ -35,7 +125,39 @@ void taskLogin(void *data) {
T_START, T_START,
T_WINDOW, O(_winLogin), T_WINDOW, O(_winLogin),
T_TITLE, P("Login"), 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_WINDOW, T_DONE,
T_END T_END
}; };

View file

@ -47,138 +47,19 @@
#include "gui.h" #include "gui.h"
#include "config.h" #include "config.h"
#include "runtime.h" #include "runtime.h"
#include "comport.h"
#include "welcome.h" #include "welcome.h"
#include "signup.h"
PacketThreadDataT *__packetThreadData = NULL; // Exported in os.h PacketThreadDataT *__packetThreadData = NULL; // Exported in os.h
RuntimeDataT __runtimeData; // Exported in runtime.h RuntimeDataT __runtimeData; // Exported in runtime.h
static void taskComDebugLoop(void *data);
static void taskGuiEventLoop(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) { static void taskGuiEventLoop(void *data) {
MouseT *mouse = NULL; MouseT *mouse = NULL;
ImageT *pointer = NULL; ImageT *pointer = NULL;
@ -211,6 +92,10 @@ static void taskGuiEventLoop(void *data) {
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
FILE *cache = NULL;
char *line = NULL;
char *p = NULL;
#ifndef __linux__ #ifndef __linux__
// On DOS, display the contets of the log now that we're back in text mode. // On DOS, display the contets of the log now that we're back in text mode.
char *logName = NULL; char *logName = NULL;
@ -260,31 +145,74 @@ int main(int argc, char *argv[]) {
sh_new_strdup(__runtimeData.integers); sh_new_strdup(__runtimeData.integers);
sh_new_strdup(__runtimeData.strings); 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(taskWelcome, NULL);
taskCreate(taskGuiEventLoop, NULL); taskCreate(taskGuiEventLoop, NULL);
taskRun(); taskRun();
// ***TODO*** Write tables from disk cache // Save & free integer table.
cache = fopen("cache/integer.dat", "wt");
// Free integer table. if (cache) {
if (__runtimeData.integers) { if (__runtimeData.integers) {
while (shlen(__runtimeData.integers) > 0) { while (shlen(__runtimeData.integers) > 0) {
shdel(__runtimeData.integers, __runtimeData.integers[0].key); //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. // Save & free string table.
if (__runtimeData.strings) { cache = fopen("cache/string.dat", "wt");
while (shlen(__runtimeData.strings) > 0) { if (cache) {
DEL(__runtimeData.strings[0].value); if (__runtimeData.strings) {
shdel(__runtimeData.strings, __runtimeData.strings[0].key); 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); packetThreadDataDestroy(&__packetThreadData);

View file

@ -66,11 +66,16 @@ PacketDecodeDataT *netGetPacket(uint8_t channel) {
} }
void netStop(void) { void netShutdown(void) {
_netRunning = 0; _netRunning = 0;
} }
void netStartup(void) {
taskCreate(taskNetwork, NULL);
}
void taskNetwork(void *data) { void taskNetwork(void *data) {
int32_t r = 0; int32_t r = 0;
int8_t pingTimeout = 0; int8_t pingTimeout = 0;

View file

@ -27,7 +27,8 @@
uint8_t netGetChannelFree(void); uint8_t netGetChannelFree(void);
PacketDecodeDataT *netGetPacket(uint8_t channel); PacketDecodeDataT *netGetPacket(uint8_t channel);
void netStop(void); void netShutdown(void);
void netStartup(void);
void taskNetwork(void *data); void taskNetwork(void *data);

384
client/src/signup.c Normal file
View 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
View 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
View 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"

View file

@ -34,6 +34,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdarg.h> #include <stdarg.h>
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h>
#ifdef __linux__ #ifdef __linux__

View file

@ -106,6 +106,7 @@ static void tagListWidgetAttributeHandle(void) {
uint8_t hasIndex; uint8_t hasIndex;
uint8_t enabled; uint8_t enabled;
uint8_t visible; uint8_t visible;
char mask;
// Process generated lists in reverse. // Process generated lists in reverse.
while (arrlen(_widgetList) > 0) { while (arrlen(_widgetList) > 0) {
@ -140,6 +141,7 @@ static void tagListWidgetAttributeHandle(void) {
hasIndex = 0; hasIndex = 0;
enabled = 1; enabled = 1;
visible = 1; visible = 1;
mask = 0;
// Parse provided attributes. // Parse provided attributes.
for (i=0; i<arrlen(w->tagList); i+=2) { for (i=0; i<arrlen(w->tagList); i+=2) {
@ -196,6 +198,10 @@ static void tagListWidgetAttributeHandle(void) {
length = v; length = v;
break; break;
case T_MASK:
mask = v;
break;
case T_MAXIMUM: case T_MAXIMUM:
maximum = v; maximum = v;
break; break;
@ -320,8 +326,9 @@ static void tagListWidgetAttributeHandle(void) {
case T_TEXTBOX: case T_TEXTBOX:
widget = W(textboxNew(pos.x, pos.y, pos.w, title)); 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); if (length > 0) textboxLengthMaxSet((TextboxT *)widget, length);
textboxPasswordCharacterSet((TextboxT *)widget, mask);
break; break;
case T_UPDOWN: case T_UPDOWN:

View file

@ -71,6 +71,7 @@ enum TagItemsE {
T_INDEX, T_INDEX,
T_ITEM, T_ITEM,
T_LENGTH, T_LENGTH,
T_MASK,
T_MAXIMUM, T_MAXIMUM,
T_MINIMUM, T_MINIMUM,
T_SELECTED, T_SELECTED,

View file

@ -137,7 +137,7 @@ static void taskConnectClick(void *data) {
} }
// Start packet handler and negotiate encryption. // Start packet handler and negotiate encryption.
taskCreate(taskNetwork, NULL); netStartup();
packetEncryptionSetup(__packetThreadData); packetEncryptionSetup(__packetThreadData);
timeout = 5; timeout = 5;
do { do {
@ -161,20 +161,18 @@ static void taskConnectClick(void *data) {
switch (decoded->packetType) { switch (decoded->packetType) {
case PACKET_TYPE_NUMBER: case PACKET_TYPE_NUMBER:
// Store in number table. // 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]); shput(__runtimeData.integers, &decoded->data[4], (int32_t)decoded->data[0]);
// Reset timeout. // Reset timeout.
timeout = 10; timeout = 10;
break; break;
case PACKET_TYPE_PROCEED: case PACKET_TYPE_PROCEED:
logWrite("Received PACKET_TYPE_PROCEED\n");
waiting = 0; waiting = 0;
break; break;
case PACKET_TYPE_STRING: case PACKET_TYPE_STRING:
// Store in string table. // 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])); shput(__runtimeData.strings, decoded->data, strdup(&decoded->data[strlen(decoded->data) + 1]));
// Reset timeout. // Reset timeout.
timeout = 10; timeout = 10;
@ -219,7 +217,7 @@ static void taskConnectClick(void *data) {
// Connected! Show icon. // Connected! Show icon.
widgetVisibleSet(W(_picConnect), 1); widgetVisibleSet(W(_picConnect), 1);
timeout = 6; // Roughly 1.5 seconds. timeout = 6; // Roughly 1.5 seconds.
while (timeout > 0) { while (timeout > 0 && !guiHasStopped()) {
taskYield(); taskYield();
if (__timerQuarterSecondTick) timeout--; 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(_btnConnect), (__configData.serialCom > 0 && strlen(__configData.serverHost) > 2) ? enabled : 0);
widgetEnableSet(W(_btnSettings), enabled); widgetEnableSet(W(_btnSettings), enabled);
widgetEnableSet(W(_btnQuit), enabled); widgetEnableSet(W(_btnQuit), enabled);

View file

@ -92,7 +92,10 @@ static void clientProcessPacket(ClientThreadT *client, PacketDecodeDataT *data)
packetEncode(client->packetThreadData, &encoded, NULL, 0); packetEncode(client->packetThreadData, &encoded, NULL, 0);
// Send it. // Send it.
packetSend(client->packetThreadData, &encoded); packetSend(client->packetThreadData, &encoded);
logWrite("Got PING, sent PONG\n\r"); break;
case PACKET_TYPE_SIGNUP:
//***TODO***
break; break;
case PACKET_TYPE_VERSION_BAD: case PACKET_TYPE_VERSION_BAD:
@ -100,21 +103,19 @@ static void clientProcessPacket(ClientThreadT *client, PacketDecodeDataT *data)
break; break;
case PACKET_TYPE_VERSION_OKAY: case PACKET_TYPE_VERSION_OKAY:
logWrite("Got VERSION_OK.\n\r");
// Fetch string table from REST. // Fetch string table from REST.
response = restRequest("CONFIG_GET_STRINGS", NULL); response = restRequest("CONFIG_GET_STRINGS", NULL);
if (!response) { if (!response) {
logWrite("Unable to fetch strings!\n\r"); consoleMessageQueue("%ld: Unable to fetch strings!\n", client->threadIndex);
break; break;
} }
strings = restHelperConfigStringMapGet(response); strings = restHelperConfigStringMapGet(response);
if (!strings) { if (!strings) {
logWrite("Unable to map strings!\n\r"); consoleMessageQueue("%ld: Unable to map strings!\n", client->threadIndex);
break; break;
} }
restRelease(response); restRelease(response);
// Send string table to client. // Send string table to client.
logWrite("Sending strings.\n\r");
for (i=0; i<(unsigned)shlen(strings); i++) { for (i=0; i<(unsigned)shlen(strings); i++) {
// Strings are encoded in a single buffer as: KEY\0DATA\0 // Strings are encoded in a single buffer as: KEY\0DATA\0
x = strlen(strings[i].key); x = strlen(strings[i].key);
@ -122,11 +123,12 @@ static void clientProcessPacket(ClientThreadT *client, PacketDecodeDataT *data)
length = x + y + 2; length = x + y + 2;
buffer = (char *)malloc(length); buffer = (char *)malloc(length);
if (!buffer) { 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; break;
} }
memcpy(buffer, strings[i].key, x + 1); memcpy(buffer, strings[i].key, x + 1);
memcpy(&buffer[x + 1], strings[i].value, y + 1); memcpy(&buffer[x + 1], strings[i].value, y + 1);
//consoleMessageQueue("[%s]=[%s]\n", strings[i].key, strings[i].value);
// Build packet. // Build packet.
encoded.control = PACKET_CONTROL_DAT; encoded.control = PACKET_CONTROL_DAT;
encoded.packetType = PACKET_TYPE_STRING; encoded.packetType = PACKET_TYPE_STRING;
@ -136,23 +138,21 @@ static void clientProcessPacket(ClientThreadT *client, PacketDecodeDataT *data)
// Send it. // Send it.
packetSend(client->packetThreadData, &encoded); packetSend(client->packetThreadData, &encoded);
DEL(buffer); DEL(buffer);
//logWrite("[%s] = [%s]\r\n", strings[i].key, strings[i].value);
} }
restHelperConfigStringMapRelease(strings); restHelperConfigStringMapRelease(strings);
// Fetch number table from REST. // Fetch number table from REST.
response = restRequest("CONFIG_GET_NUMBERS", NULL); response = restRequest("CONFIG_GET_NUMBERS", NULL);
if (!response) { if (!response) {
logWrite("Unable to fetch numbers!\n\r"); consoleMessageQueue("%ld: Unable to fetch numbers!\n", client->threadIndex);
break; break;
} }
integers = restHelperConfigIntegerMapGet(response); integers = restHelperConfigIntegerMapGet(response);
if (!integers) { if (!integers) {
logWrite("Unable to map numbers!\n\r"); consoleMessageQueue("%ld: Unable to map numbers!\n", client->threadIndex);
break; break;
} }
restRelease(response); restRelease(response);
// Send number table to client. // Send number table to client.
logWrite("Sending numbers.\n\r");
for (i=0; i<(unsigned)shlen(integers); i++) { for (i=0; i<(unsigned)shlen(integers); i++) {
// Integers are encoded in a single buffer as: 1234DATA\0 // 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. // 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; length = x + 5;
buffer = (char *)malloc(length); buffer = (char *)malloc(length);
if (!buffer) { 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; break;
} }
memcpy(buffer, &y, 4); memcpy(buffer, &y, 4);
@ -186,7 +186,6 @@ static void clientProcessPacket(ClientThreadT *client, PacketDecodeDataT *data)
packetEncode(client->packetThreadData, &encoded, NULL, 0); packetEncode(client->packetThreadData, &encoded, NULL, 0);
// Send it. // Send it.
packetSend(client->packetThreadData, &encoded); packetSend(client->packetThreadData, &encoded);
logWrite("Sending proceed.\n\r");
break; break;
default: default:

View file

@ -25,6 +25,7 @@
#include "os.h" #include "os.h"
#include "rest.h" #include "rest.h"
#include "array.h" #include "array.h"
#include "console.h"
typedef struct RestResponseS { typedef struct RestResponseS {
@ -147,6 +148,7 @@ RestStringMapT *restHelperConfigStringMapGet(json_object *object) {
for (i=0; i<json_object_array_length(data); i++) { for (i=0; i<json_object_array_length(data); i++) {
item = json_object_array_get_idx(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")))); 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")));
} }
} }
} }

View file

@ -38,12 +38,12 @@ void serverDisconnectClient(ClientThreadT *client) {
void *status = NULL; void *status = NULL;
char buffer[2048] = { 0 }; char buffer[2048] = { 0 };
// Stop client processing.
client->running = 0;
pthread_join(client->threadHandle, &status);
// Tell the console. // Tell the console.
enet_address_get_host_ip(&peer->address, buffer, 2047); enet_address_get_host_ip(&peer->address, buffer, 2047);
consoleMessageQueue("%ld: [%s] disconnected.\n", client->threadIndex, buffer); consoleMessageQueue("%ld: [%s] disconnected.\n", client->threadIndex, buffer);
// Stop client processing.
client->running = 0;
pthread_join(client->threadHandle, &status);
// Hang up. // Hang up.
enet_peer_reset(peer); enet_peer_reset(peer);
} }

View file

@ -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) { static uint8_t packetCRC(char *data, uint16_t length, uint8_t startAt) {
uint16_t x = 0; 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++) { for (x=0; x<length; x++) {
startAt ^= data[x] + data[x]; // Just XOR and increment. startAt ^= data[x] + data[x]; // Just XOR and increment.
} }
@ -122,10 +139,14 @@ uint8_t packetDecode(PacketThreadDataT *threadData, PacketDecodeDataT *decodeDat
if (c != PACKET_FRAME) { if (c != PACKET_FRAME) {
threadData->newPacket = 1; 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. // Get sequence value.
sequence = ((uint8_t)threadData->decodeBuffer[0]) & 0x1f; sequence = ((uint8_t)threadData->decodeBuffer[0]) & 0x1f;

View file

@ -27,8 +27,11 @@
#define PACKET_PROTOCOL_VERSION 1 #define PACKET_PROTOCOL_VERSION 1
#define PACKET_MAX_USER 16 #define PACKET_MAX_USER 16 // These need to match the configuration in the database.
#define PACKET_MAX_PASS 16 #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. // 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_NUMBER,
PACKET_TYPE_PROCEED, PACKET_TYPE_PROCEED,
PACKET_TYPE_LOGIN, PACKET_TYPE_LOGIN,
PACKET_TYPE_SIGNUP,
PACKET_TYPE_SIGNUP_RESULT,
PACKET_TYPE_COUNT PACKET_TYPE_COUNT
} PacketTypeT; } PacketTypeT;
@ -62,6 +67,19 @@ typedef struct PacketTypeLoginS {
char pass[PACKET_MAX_PASS]; char pass[PACKET_MAX_PASS];
} PacketTypeLoginT; } 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) #pragma pack(pop)