1
0
mirror of https://github.com/CPunch/Laika.git synced 2024-11-21 20:40:05 +00:00

Added panel!

- minor refactoring
- TODO: panel & cnc should really use unique keys. maybe add config file?
This commit is contained in:
CPunch 2022-02-14 00:22:36 -06:00
parent e7265ad15b
commit fb71dfb3c3
13 changed files with 1003 additions and 6 deletions

10
.vscode/settings.json vendored
View File

@ -24,18 +24,24 @@
"stdio.h": "c", "stdio.h": "c",
"bit": "c", "bit": "c",
"limits": "c", "limits": "c",
"*.in": "cpp" "*.in": "cpp",
"lerror.h": "c"
}, },
"cSpell.words": [ "cSpell.words": [
"cnc's",
"CWARN", "CWARN",
"epollfd", "epollfd",
"EPOLLIN", "EPOLLIN",
"evnt",
"EWOULD", "EWOULD",
"ISPROTECTED", "ISPROTECTED",
"Laika", "Laika",
"LAIKAMAGIC", "LAIKAMAGIC",
"LAIKAMAGICLEN", "LAIKAMAGICLEN",
"LAIKAPKT",
"NOMINMAX", "NOMINMAX",
"rmvarray" "PCLIENT",
"rmvarray",
"wmain"
] ]
} }

View File

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.10) cmake_minimum_required(VERSION 3.10)
project(Laika) project(Laika)
set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_STANDARD_REQUIRED ON)
# Set the project as the default startup project for VS # Set the project as the default startup project for VS
@ -37,3 +37,4 @@ add_subdirectory(lib)
add_subdirectory(tools) add_subdirectory(tools)
add_subdirectory(cnc) add_subdirectory(cnc)
add_subdirectory(bot) add_subdirectory(bot)
add_subdirectory(panel)

View File

@ -41,6 +41,9 @@ void laikaC_handleHandshakeRequest(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, v
laikaS_writeByte(&peer->sock, laikaS_isBigEndian()); laikaS_writeByte(&peer->sock, laikaS_isBigEndian());
laikaS_endOutPacket(peer); laikaS_endOutPacket(peer);
/* handshake (mostly) complete */
laikaC_onAddPeer(cnc, peer);
LAIKA_DEBUG("accepted handshake from peer %lx\n", peer); LAIKA_DEBUG("accepted handshake from peer %lx\n", peer);
} }
@ -98,6 +101,7 @@ void laikaC_onAddPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer) {
/* notify connected panels of the newly connected peer */ /* notify connected panels of the newly connected peer */
for (i = 0; i < cnc->panelCount; i++) { for (i = 0; i < cnc->panelCount; i++) {
LAIKA_DEBUG("sending new peer to %lx\n", peer);
laikaC_sendNewPeer(cnc->panels[i], peer); laikaC_sendNewPeer(cnc->panels[i], peer);
} }
} }
@ -118,7 +122,7 @@ void laikaC_rmvPanel(struct sLaika_cnc *cnc, struct sLaika_peer *panel) {
for (i = 0; i < cnc->panelCount; i++) { for (i = 0; i < cnc->panelCount; i++) {
if (cnc->panels[i] == panel) { /* we found the index for our panel! */ if (cnc->panels[i] == panel) { /* we found the index for our panel! */
laikaM_rmvarray(cnc->panels, cnc->panelCount, i, 1); laikaM_rmvarray(cnc->panels, cnc->panelCount, i, 1);
break; return;
} }
} }
} }
@ -129,6 +133,8 @@ void laikaC_addPanel(struct sLaika_cnc *cnc, struct sLaika_peer *panel) {
/* insert into authenticated panel table */ /* insert into authenticated panel table */
cnc->panels[cnc->panelCount++] = panel; cnc->panels[cnc->panelCount++] = panel;
LAIKA_DEBUG("added panel %lx!\n", panel);
} }
void laikaC_killPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer) { void laikaC_killPeer(struct sLaika_cnc *cnc, struct sLaika_peer *peer) {
@ -173,8 +179,6 @@ bool laikaC_pollPeers(struct sLaika_cnc *cnc, int timeout) {
/* add to our pollList */ /* add to our pollList */
laikaP_addSock(&cnc->pList, &peer->sock); laikaP_addSock(&cnc->pList, &peer->sock);
laikaC_onAddPeer(cnc, peer);
LAIKA_DEBUG("new peer %lx!\n", peer); LAIKA_DEBUG("new peer %lx!\n", peer);
continue; continue;
} }
@ -200,6 +204,7 @@ bool laikaC_pollPeers(struct sLaika_cnc *cnc, int timeout) {
/* flush pList's outQueue */ /* flush pList's outQueue */
for (i = 0; i < cnc->pList.outCount; i++) { for (i = 0; i < cnc->pList.outCount; i++) {
peer = cnc->pList.outQueue[i]; peer = cnc->pList.outQueue[i];
LAIKA_DEBUG("sending OUT to %lx\n", peer);
if (!laikaS_handlePeerOut(peer)) if (!laikaS_handlePeerOut(peer))
laikaC_killPeer(cnc, peer); laikaC_killPeer(cnc, peer);
} }

View File

@ -58,6 +58,10 @@ void laikaC_handleAuthenticatedHandshake(struct sLaika_peer *panel, LAIKAPKT_SIZ
/* they passed! send list of our peers */ /* they passed! send list of our peers */
laikaP_iterList(&cnc->pList, sendPanelPeerIter, (void*)panel); laikaP_iterList(&cnc->pList, sendPanelPeerIter, (void*)panel);
/* notify other peers */
laikaC_onRmvPeer(cnc, panel);
laikaC_onAddPeer(cnc, panel);
break; break;
default: default:
LAIKA_ERROR("unknown peerType [%d]!\n", panel->type); LAIKA_ERROR("unknown peerType [%d]!\n", panel->type);

View File

@ -77,9 +77,18 @@ void laikaP_addSock(struct sLaika_pollList *pList, struct sLaika_socket *sock) {
} }
void laikaP_rmvSock(struct sLaika_pollList *pList, struct sLaika_socket *sock) { void laikaP_rmvSock(struct sLaika_pollList *pList, struct sLaika_socket *sock) {
int i;
/* remove socket from hashmap */ /* remove socket from hashmap */
hashmap_delete(pList->sockets, &(tLaika_hashMapElem){.fd = sock->sock, .sock = sock}); hashmap_delete(pList->sockets, &(tLaika_hashMapElem){.fd = sock->sock, .sock = sock});
/* make sure peer isn't in outQueue */
for (i = 0; i < pList->outCount; i++) {
if ((void*)pList->outQueue[i] == (void*)sock) {
laikaM_rmvarray(pList->outQueue, pList->outCount, i, 1);
}
}
#ifdef LAIKA_USE_EPOLL #ifdef LAIKA_USE_EPOLL
/* epoll_event* isn't needed with EPOLL_CTL_DEL, however we still need to pass a NON-NULL pointer. [see: https://man7.org/linux/man-pages/man2/epoll_ctl.2.html#BUGS] */ /* epoll_event* isn't needed with EPOLL_CTL_DEL, however we still need to pass a NON-NULL pointer. [see: https://man7.org/linux/man-pages/man2/epoll_ctl.2.html#BUGS] */
if (epoll_ctl(pList->epollfd, EPOLL_CTL_DEL, sock->sock, &pList->ev) == -1) { if (epoll_ctl(pList->epollfd, EPOLL_CTL_DEL, sock->sock, &pList->ev) == -1) {

22
panel/CMakeLists.txt Normal file
View File

@ -0,0 +1,22 @@
cmake_minimum_required(VERSION 3.10)
set(PANEL_INCLUDEDIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
set(CURSES_NEED_NCURSES TRUE)
project(LaikaPanel VERSION 1.0)
# Put CMake targets (ALL_BUILD/ZERO_CHECK) into a folder
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
find_package(Curses)
# compile LaikaPanel
file(GLOB_RECURSE PANELSOURCE ${CMAKE_CURRENT_SOURCE_DIR}/src/**.c)
add_executable(LaikaPanel ${PANELSOURCE})
target_link_libraries(LaikaPanel PUBLIC LaikaLib ${CURSES_LIBRARIES})
# add the 'DEBUG' preprocessor definition if we're compiling as Debug
target_compile_definitions(LaikaPanel PUBLIC "$<$<CONFIG:Debug>:DEBUG>")
# add include directory
target_include_directories(LaikaPanel PUBLIC ${PANEL_INCLUDEDIR})

93
panel/include/panel.h Normal file
View File

@ -0,0 +1,93 @@
#ifndef PANELMENU_H
#define PANELMENU_H
#include <ncurses.h>
#include <stdbool.h>
#define PANEL_CURSES_TIMEOUT 100
#define COMMONPANELLIST tPanel_list list;
typedef void (*panelCallback)(void *uData);
typedef enum {
LIST_LIST,
LIST_TABS,
LIST_MENU,
LIST_NONE
} LISTTYPE;
struct sPanel_list;
typedef struct sPanel_listItem {
panelCallback callback;
struct sPanel_list *child;
void *uData;
char *name;
struct sPanel_listItem *next;
struct sPanel_listItem *last;
int x, y, width, height;
} tPanel_listItem;
typedef struct sPanel_list {
tPanel_listItem *itemHead, *selectedItem;
WINDOW *win;
int x, y, width, height;
LISTTYPE type;
bool hidden;
} tPanel_list;
typedef struct sPanel_tabs {
COMMONPANELLIST;
char *title;
} tPanel_tabs;
typedef struct sPanel_menu {
COMMONPANELLIST;
char *title;
} tPanel_menu;
extern WINDOW *wmain;
extern tPanel_list *panel_botList;
extern tPanel_tabs *panel_tabList;
void panel_init(void);
void panel_cleanUp(void);
tPanel_list *panel_getActiveList(void);
int panel_getChar(void);
void panel_pushActiveList(tPanel_list *list);
void panel_popActiveList(void); /* also free's the item */
void panel_draw(void);
bool panel_tick(int input); /* ticks activeList list, returns true if input was accepted/valid */
void panel_setTimeout(int timeout);
tPanel_listItem *panelL_newListItem(tPanel_list *list, tPanel_list *child, char *name, panelCallback callback, void *uData);
void panelL_freeListItem(tPanel_list *list, tPanel_listItem *item);
/* call *after* adding listItems with panelL_newListItem */
void panelL_init(tPanel_list *list);
void panelL_draw(tPanel_list *list);
void panelL_free(tPanel_list *list);
bool panelL_tick(tPanel_list *list, int ch);
void panelL_setHidden(tPanel_list *list, bool hidden);
void panelL_setTimeout(tPanel_list *list, int timeout);
/* handles selection */
void panelL_nextItem(tPanel_list *list);
void panelL_prevItem(tPanel_list *list);
void panelL_selectItem(tPanel_list *list); /* calls select item's callback */
/* center list */
tPanel_list *panelL_newList(void);
void panelL_freeList(tPanel_list *list);
/* top tabs */
tPanel_tabs *panelL_newTabs(char *title);
void panelL_freeTabs(tPanel_tabs *tabs);
/* menu popup */
tPanel_menu *panelL_newMenu(char *title);
void panelL_freeMenu(tPanel_menu *menu);
#undef COMMONPANELLIST
#endif

24
panel/include/pbot.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef PBOT_H
#define PBOT_H
#include "laika.h"
#include "lpeer.h"
#include "lrsa.h"
#include "panel.h"
typedef struct sPanel_bot {
uint8_t pub[crypto_kx_PUBLICKEYBYTES];
PEERTYPE type;
tPanel_listItem *item;
char *name; /* heap allocated string */
} tPanel_bot;
tPanel_bot *panelB_newBot(uint8_t *pubKey);
void panelB_freeBot(tPanel_bot *bot);
/* search connected bots by public key */
tPanel_bot *panelB_getBot(uint8_t *pubKey);
void panelB_setItem(tPanel_bot *bot, tPanel_listItem *item);
#endif

24
panel/include/pclient.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef PCLIENT_H
#define PCLIENT_H
#include "laika.h"
#include "lpeer.h"
#include "lpolllist.h"
#include "pbot.h"
typedef struct sPanel_client {
uint8_t priv[crypto_kx_SECRETKEYBYTES], pub[crypto_kx_PUBLICKEYBYTES];
struct sLaika_pollList pList;
struct sLaika_peer *peer;
} tPanel_client;
tPanel_client *panelC_newClient();
void panelC_freeClient(tPanel_client *client);
void panelC_connectToCNC(tPanel_client *client, char *ip, char *port); /* can throw a LAIKA_ERROR */
bool panelC_poll(tPanel_client *client, int timeout);
void panelC_addBot(tPanel_bot *bot);
void panelC_rmvBot(tPanel_bot *bot);
#endif

99
panel/src/main.c Normal file
View File

@ -0,0 +1,99 @@
#include "laika.h"
#include "lerror.h"
#include "panel.h"
#include "pclient.h"
#define STRING(x) #x
#define MACROLITSTR(x) STRING(x)
tPanel_client *client;
tPanel_tabs *panel_tabList;
tPanel_list *panel_botList;
void connectToCNC(void *uData) {
tPanel_listItem *curr;
int ch;
/* hide main menu */
panelL_setHidden(panel_getActiveList(), true);
/* init global lists */
panel_tabList = panelL_newTabs("Laika CNC Panel");
panel_botList = panelL_newList();
/* init tabs */
panelL_newListItem(&panel_tabList->list, panel_botList, "Bot List", NULL, NULL);
panelL_init(&panel_tabList->list);
panelL_init(panel_botList);
addstr("Connecting to CNC with pubkey [" LAIKA_PUBKEY "]...");
refresh();
client = panelC_newClient();
panelC_connectToCNC(client, "127.0.0.1", "13337");
/* main panel loop */
panel_pushActiveList(&panel_tabList->list);
while ((ch = panel_getChar()) != 'q' && laikaS_isAlive((&client->peer->sock))) {
if (!panel_tick(ch)) {
/* if we got an event to handle, we *probably* have more events to handle so temporarily make ncurses non-blocking */
if (panelC_poll(client, 0)) {
panel_setTimeout(0); /* makes ncurses non-blocking */
panel_draw();
} else {
/* wait to poll if we didn't receive any new messages */
panel_setTimeout(PANEL_CURSES_TIMEOUT);
}
} else {
/* we got input, redraw screen */
panel_draw();
}
}
/* free bots in botList */
curr = panel_botList->itemHead;
while (curr != NULL) {
panelB_freeBot(curr->uData);
curr = curr->next;
}
/* since panel_botList is a child of one of panel_tabList's items, it
gets free'd with panel_tabList. so popping it frees both */
panel_popActiveList();
panelC_freeClient(client);
/* re-show main menu */
panelL_setHidden(panel_getActiveList(), false);
}
void quitLaika(void *uData) {
LAIKA_ERROR("quit!\n")
}
int main(int argv, char **argc) {
tPanel_menu *menu;
int ch;
/* init ncurses */
panel_init();
menu = panelL_newMenu("Laika v" MACROLITSTR(LAIKA_VERSION_MAJOR) "." MACROLITSTR(LAIKA_VERSION_MINOR));
panelL_newListItem(&menu->list, NULL, "Quit", quitLaika, NULL);
panelL_newListItem(&menu->list, NULL, "- Connect to CNC", connectToCNC, NULL);
/* start main menu */
panelL_init(&menu->list);
panel_pushActiveList(&menu->list);
LAIKA_TRY
while ((ch = panel_getChar()) != 'q') {
if (panel_tick(ch))
panel_draw();
}
LAIKA_TRYEND
panel_popActiveList();
/* cleanup */
panel_cleanUp();
return 0;
}

472
panel/src/panel.c Normal file
View File

@ -0,0 +1,472 @@
#include <string.h>
#include <ncurses.h>
#include "lmem.h"
#include "lerror.h"
#include "panel.h"
#include "pbot.h"
/* i don't expect to ever be 16 layers deep of menus */
#define ACTIVESIZE 16
WINDOW *wmain;
tPanel_list *activeList[ACTIVESIZE] = { NULL };
int activeListSize = -1;
void printTitle(WINDOW *win, char *text, int width, int x, int y) {
int pad = (width - (strlen(text) + 4)) / 2;
mvwprintw(win, y, x+pad, "| %s |", text);
}
void printCenter(WINDOW *win, char *text, int width, int x, int y) {
int strLength = strlen(text);
int pad = (width - strLength) / 2;
mvwprintw(win, y, x, "%*s%s%*s", pad, "", text, (width-pad-strLength), "");
}
void printLine(WINDOW *win, char *text, int width, int x, int y) {
int strLength = strlen(text);
int pad = (width - strLength);
mvwprintw(win, y, x, "%s%*s\n", text, pad, "");
}
void panel_init() {
if ((wmain = initscr()) == NULL)
LAIKA_ERROR("Failed to init ncurses!")
activeListSize = -1;
/* setup ncurses */
cbreak();
noecho();
timeout(1);
keypad(stdscr, true);
curs_set(0); /* hide the default screen cursor. */
refresh();
}
void panel_cleanUp() {
/* clean up ncurses */
delwin(wmain);
endwin();
}
tPanel_list *panel_newBaseList(size_t sz, LISTTYPE type) {
tPanel_list *list = laikaM_malloc(sz);
list->itemHead = NULL;
list->selectedItem = NULL;
list->win = NULL;
list->x = 1;
list->y = 0;
list->height = 0;
list->type = type;
list->hidden = false;
return list;
}
void panel_freeBaseList(tPanel_list *list) {
/* free linked list */
tPanel_listItem *curr = list->itemHead, *last = NULL;
while(curr != NULL) {
last = curr;
curr = curr->next;
if (last != NULL)
panelL_freeListItem(list, last);
}
/* remove ncurses window */
wclear(list->win);
delwin(list->win);
/* free list */
laikaM_free(list);
}
tPanel_list *panel_getActiveList() {
return activeList[activeListSize];
}
int panel_getChar() {
/* if we have an activeList panel, grab the input from that otherwise return -1 */
if (activeList)
return wgetch(panel_getActiveList()->win);
return -1;
}
void panel_pushActiveList(tPanel_list *list) {
/* set activeList window & draw */
activeList[++activeListSize] = list;
panelL_draw(panel_getActiveList());
}
void panel_popActiveList() {
panelL_freeList(activeList[activeListSize--]);
if (activeListSize >= 0)
panelL_init(panel_getActiveList());
}
void panel_draw(void) {
int i;
/* draw active panels from bottom most (pushed first) to top most (pushed last)
this way, new-er windows will be drawn on-top of older ones */
clear();
for (i = 0; i <= activeListSize; i++) {
panelL_draw(activeList[i]);
}
}
bool panel_tick(int ch) {
int i;
/* tick each panel from top most (pushed last) to bottom most (pushed first)
this way, the top-most windows/lists will be the most interactive */
for (i = activeListSize; i >= 0; i--) {
if (panelL_tick(activeList[i], ch))
return true;
}
/* no ticks returned any results */
return false;
}
void panel_setTimeout(int timeout) {
panelL_setTimeout(panel_getActiveList(), timeout);
}
/* ==================================================[[ List ]]================================================== */
tPanel_list *panelL_newList(void) {
return (tPanel_list*)panel_newBaseList(sizeof(tPanel_list), LIST_LIST);
}
void panelL_freeList(tPanel_list *list) {
panel_freeBaseList(list);
}
void panelL_initList(tPanel_list *list) {
tPanel_listItem *curr = list->itemHead;
int numLines = 0;
/* count # of lines */
while (curr != NULL) {
numLines++;
curr = curr->next;
}
/* create ncurses window */
list->x = 0;
list->y = 2;
list->width = COLS;
list->height = numLines;
list->win = newwin(list->height, list->width, list->y, list->x);
keypad(list->win, TRUE); /* setup keyboard input */
wtimeout(list->win, 0);
}
void panelL_drawList(tPanel_list *list) {
tPanel_listItem *curr = list->itemHead;
int i = 0;
/* write each line */
while (curr != NULL) {
/* highlight selected option */
if (curr == list->selectedItem)
wattron(list->win, A_STANDOUT);
printLine(list->win, curr->name, list->width, 0, i++);
wattroff(list->win, A_STANDOUT);
curr = curr->next;
}
/* push to screen */
wrefresh(list->win);
}
bool panelL_tickList(tPanel_list *list, int ch) {
switch (ch) {
case KEY_DOWN: panelL_nextItem(list); break;
case KEY_UP: panelL_prevItem(list); break;
default: return false;
}
return true;
}
/* ==================================================[[ Tabs ]]================================================== */
tPanel_tabs *panelL_newTabs(char *title) {
tPanel_tabs *tabs = (tPanel_tabs*)panel_newBaseList(sizeof(tPanel_tabs), LIST_TABS);
tabs->title = title;
tabs->list.width = strlen(title) + 4;
return tabs;
}
void panelL_freeTabs(tPanel_tabs *tabs) {
panel_freeBaseList((tPanel_list*)tabs);
}
void panelL_initTabs(tPanel_list *tabs) {
tPanel_listItem *curr = tabs->itemHead;
int numTabs = 0;
if (tabs->win)
delwin(tabs->win);
/* get tab count */
while (curr != NULL) {
curr = curr->next;
numTabs++;
}
tabs->x = 0;
tabs->y = 0;
if (numTabs <= 1)
tabs->width = COLS;
else
tabs->width = COLS/numTabs;
tabs->height = 2;
tabs->win = newwin(tabs->height, COLS, tabs->y, tabs->x);
keypad(tabs->win, true);
wtimeout(tabs->win, 0);
}
void panelL_drawTabs(tPanel_tabs *tabs) {
tPanel_listItem *curr = tabs->list.itemHead;
int i = 0;
/* write title */
printCenter(tabs->list.win, tabs->title, COLS, 0, 0);
/* write each tab */
while (curr != NULL) {
/* highlight selected option */
if (curr == tabs->list.selectedItem)
wattron(tabs->list.win, A_STANDOUT);
printCenter(tabs->list.win, curr->name, tabs->list.width, (i++)*tabs->list.width, 1);
curr = curr->next;
wattroff(tabs->list.win, A_STANDOUT);
}
/* draw tab */
refresh();
if (tabs->list.selectedItem && tabs->list.selectedItem->child)
panelL_draw(tabs->list.selectedItem->child);
wrefresh(tabs->list.win);
}
bool panelL_tickTabs(tPanel_tabs *tabs, int ch) {
switch (ch) {
case KEY_RIGHT: panelL_nextItem(&tabs->list); break;
case KEY_LEFT: panelL_prevItem(&tabs->list); break;
/* tick child */
default: return (tabs->list.selectedItem && tabs->list.selectedItem->child) ? panelL_tick(tabs->list.selectedItem->child, ch) : false;
}
return true;
}
/* ==================================================[[ Menu ]]================================================== */
tPanel_menu *panelL_newMenu(char *title) {
tPanel_menu *menu = (tPanel_menu*)panel_newBaseList(sizeof(tPanel_menu), LIST_MENU);
menu->title = title;
menu->list.width = strlen(title) + 4;
return menu;
}
void panelL_freeMenu(tPanel_menu *menu) {
panel_freeBaseList((tPanel_list*)menu);
}
void panelL_initMenu(tPanel_list *menu) {
tPanel_listItem *curr = menu->itemHead;
if (menu->win)
delwin(menu->win);
/* get max line length & menu height */
menu->height = 2;
while (curr != NULL) {
if (curr->width+6 > menu->width)
menu->width = curr->width+6;
curr = curr->next;
menu->height++;
}
menu->y = (LINES-menu->height)/2;
menu->x = (COLS-menu->width)/2;
menu->win = newwin(menu->height, menu->width, menu->y, menu->x);
keypad(menu->win, true);
wtimeout(menu->win, 0);
}
void panelL_drawMenu(tPanel_menu *menu) {
tPanel_listItem *curr = menu->list.itemHead;
int i = 1;
/* write each line */
while (curr != NULL) {
/* highlight selected option */
if (curr == menu->list.selectedItem)
wattron(menu->list.win, A_STANDOUT);
printLine(menu->list.win, curr->name, menu->list.width-4, 2, i++);
wattroff(menu->list.win, A_STANDOUT);
curr = curr->next;
}
/* write the title & border */
box(menu->list.win, 0, 0);
printTitle(menu->list.win, menu->title, menu->list.width, 0, 0);
/* push to screen */
wrefresh(menu->list.win);
}
bool panelL_tickMenu(tPanel_menu *menu, int ch) {
switch (ch) {
case KEY_UP: panelL_prevItem(&menu->list); break;
case KEY_DOWN: panelL_nextItem(&menu->list); break;
case '\n': case KEY_ENTER: panelL_selectItem(&menu->list); break;
default: return false;
}
panelL_drawMenu(menu);
return true;
}
/* ==================================================[[ Panel Direct ]]================================================== */
tPanel_listItem *panelL_newListItem(tPanel_list *list, tPanel_list *child, char *name, panelCallback callback, void *uData) {
tPanel_listItem *item = laikaM_malloc(sizeof(tPanel_listItem));
item->child = child;
item->callback = callback;
item->uData = uData;
item->name = name;
item->last = NULL;
item->next = NULL;
item->width = strlen(name);
item->height = 1;
item->x = 0;
item->y = 0;
/* add to list */
if (list->itemHead)
list->itemHead->last = item;
item->next = list->itemHead;
list->itemHead = item;
list->selectedItem = item;
return item;
}
void panelL_freeListItem(tPanel_list *list, tPanel_listItem *item) {
if (list->itemHead == item) {
if (item->next)
item->next->last = NULL;
list->itemHead = item->next;
} else {
/* unlink from list */
if (item->last)
item->last->next = item->next;
if (item->next)
item->next->last = item->last;
}
/* free child */
if (item->child)
panelL_freeList(item->child);
/* update selected item */
if (list->selectedItem == item)
list->selectedItem = list->itemHead;
laikaM_free(item);
}
void panelL_nextItem(tPanel_list *list) {
if (!list->selectedItem || !list->selectedItem->next) /* sanity check */
return;
list->selectedItem = list->selectedItem->next;
}
void panelL_prevItem(tPanel_list *list) {
if (!list->selectedItem || !list->selectedItem->last) /* sanity check */
return;
list->selectedItem = list->selectedItem->last;
}
void panelL_selectItem(tPanel_list *list) {
if (!list->selectedItem || !list->selectedItem->callback) /* sanity check */
return;
list->selectedItem->callback(list->selectedItem->uData);
}
void panelL_init(tPanel_list *list) {
switch (list->type) {
case LIST_LIST: panelL_initList(list); break;
case LIST_TABS: panelL_initTabs(list); break;
case LIST_MENU: panelL_initMenu(list); break;
default: LAIKA_ERROR("Malformed tPanel_list!\n"); break;
}
}
void panelL_free(tPanel_list *list) {
switch (list->type) {
case LIST_LIST: panelL_freeList(list); break;
case LIST_TABS: panelL_freeTabs((tPanel_tabs*)list); break;
case LIST_MENU: panelL_freeMenu((tPanel_menu*)list); break;
default: LAIKA_ERROR("Malformed tPanel_list!\n"); break;
}
}
void panelL_draw(tPanel_list *list) {
if (list->hidden) /* don't draw a hidden list */
return;
switch (list->type) {
case LIST_LIST: panelL_drawList(list); break;
case LIST_TABS: panelL_drawTabs((tPanel_tabs*)list); break;
case LIST_MENU: panelL_drawMenu((tPanel_menu*)list); break;
default: LAIKA_ERROR("Malformed tPanel_list!\n"); break;
}
}
bool panelL_tick(tPanel_list *list, int ch) {
if (list->hidden) /* don't tick a hidden list */
return false;
switch (list->type) {
case LIST_LIST: return panelL_tickList(list, ch);
case LIST_TABS: return panelL_tickTabs((tPanel_tabs*)list, ch);
case LIST_MENU: return panelL_tickMenu((tPanel_menu*)list, ch);
return false;
}
}
void panelL_setHidden(tPanel_list *list, bool hidden) {
list->hidden = hidden;
}
void panelL_setTimeout(tPanel_list *list, int timeout) {
wtimeout(list->win, timeout);
}

45
panel/src/pbot.c Normal file
View File

@ -0,0 +1,45 @@
#include "lmem.h"
#include "lerror.h"
#include "pbot.h"
#include "panel.h"
tPanel_bot *panelB_newBot(uint8_t *pubKey) {
tPanel_bot *bot = laikaM_malloc(sizeof(tPanel_bot));
bot->name = laikaM_malloc(256);
sodium_bin2hex(bot->name, 256, pubKey, crypto_kx_PUBLICKEYBYTES);
/* copy pubKey to bot's pubKey */
memcpy(bot->pub, pubKey, crypto_kx_PUBLICKEYBYTES);
return bot;
}
void panelB_freeBot(tPanel_bot *bot) {
laikaM_free(bot->name);
laikaM_free(bot);
}
/* search connected bots by public key */
tPanel_bot *panelB_getBot(uint8_t *pubKey) {
tPanel_listItem *curr = panel_botList->itemHead;
tPanel_bot *bot;
while (curr != NULL) {
bot = (tPanel_bot*)curr->uData;
/* check pubKeys */
if (memcmp(pubKey, bot->pub, crypto_kx_PUBLICKEYBYTES) == 0)
return bot; /* they match! */
curr = curr->next;
}
/* no match found :( */
return NULL;
}
void panelB_setItem(tPanel_bot *bot, tPanel_listItem *item) {
bot->item = item;
}

193
panel/src/pclient.c Normal file
View File

@ -0,0 +1,193 @@
#include "lmem.h"
#include "lerror.h"
#include "pclient.h"
#include "panel.h"
void handleHandshakeResponse(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) {
tPanel_client *client = (tPanel_client*)uData;
uint8_t endianness = laikaS_readByte(&peer->sock);
peer->sock.flipEndian = endianness != laikaS_isBigEndian();
}
void handleAddPeer(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) {
uint8_t pubKey[crypto_kx_PUBLICKEYBYTES];
uint8_t type;
/* read newly connected peer's pubKey */
laikaS_read(&peer->sock, pubKey, crypto_kx_PUBLICKEYBYTES);
/* read peer's peerType */
type = laikaS_readByte(&peer->sock);
/* add peer */
switch (type) {
case PEER_BOT: {
tPanel_bot *bot = panelB_newBot(pubKey);
panelC_addBot(bot);
break;
}
default:
LAIKA_WARN("unknown peer type? [%d]\n", type);
}
}
void handleRmvPeer(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uData) {
uint8_t pubKey[crypto_kx_PUBLICKEYBYTES];
uint8_t type;
/* read newly connected peer's pubKey */
laikaS_read(&peer->sock, pubKey, crypto_kx_PUBLICKEYBYTES);
/* read peer's peerType */
type = laikaS_readByte(&peer->sock);
/* find peer by pubkey & rmv it */
switch (type) {
case PEER_BOT: {
tPanel_bot *bot = panelB_getBot(pubKey);
if (bot != NULL)
panelC_rmvBot(bot);
break;
}
default:
LAIKA_WARN("unknown peer type? [%d]\n", type);
}
}
LAIKAPKT_SIZE panelC_pktSizeTbl[LAIKAPKT_MAXNONE] = {
[LAIKAPKT_HANDSHAKE_RES] = sizeof(uint8_t),
[LAIKAPKT_AUTHENTICATED_ADD_PEER] = crypto_kx_PUBLICKEYBYTES + sizeof(uint8_t), /* pubkey + peerType */
[LAIKAPKT_AUTHENTICATED_RMV_PEER] = crypto_kx_PUBLICKEYBYTES + sizeof(uint8_t), /* pubkey + peerType */
};
PeerPktHandler panelC_handlerTbl[LAIKAPKT_MAXNONE] = {
[LAIKAPKT_HANDSHAKE_RES] = handleHandshakeResponse,
[LAIKAPKT_AUTHENTICATED_ADD_PEER] = handleAddPeer,
[LAIKAPKT_AUTHENTICATED_RMV_PEER] = handleRmvPeer,
};
tPanel_client *panelC_newClient() {
tPanel_client *client = laikaM_malloc(sizeof(tPanel_client));
size_t _unused;
laikaP_initPList(&client->pList);
client->peer = laikaS_newPeer(
panelC_handlerTbl,
panelC_pktSizeTbl,
&client->pList,
(void*)client
);
/* load authenticated keypair */
if (sodium_init() < 0) {
panelC_freeClient(client);
LAIKA_ERROR("LibSodium failed to initialize!\n");
}
if (sodium_hex2bin(client->pub, crypto_kx_PUBLICKEYBYTES, LAIKA_PUBKEY, strlen(LAIKA_PUBKEY), NULL, &_unused, NULL) != 0) {
panelC_freeClient(client);
LAIKA_ERROR("Failed to init public key!\n");
}
if (sodium_hex2bin(client->priv, crypto_kx_SECRETKEYBYTES, LAIKA_PRIVKEY, strlen(LAIKA_PRIVKEY), NULL, &_unused, NULL) != 0) {
panelC_freeClient(client);
LAIKA_ERROR("Failed to init private key!\n");
}
/* read cnc's public key into peerPub */
if (sodium_hex2bin(client->peer->peerPub, crypto_kx_PUBLICKEYBYTES, LAIKA_PUBKEY, strlen(LAIKA_PUBKEY), NULL, &_unused, NULL) != 0) {
panelC_freeClient(client);
LAIKA_ERROR("Failed to init cnc public key!\n");
}
return client;
}
void panelC_freeClient(tPanel_client *client) {
laikaS_freePeer(client->peer);
laikaP_cleanPList(&client->pList);
laikaM_free(client);
}
void panelC_connectToCNC(tPanel_client *client, char *ip, char *port) {
struct sLaika_socket *sock = &client->peer->sock;
/* setup socket */
laikaS_connect(sock, ip, port);
laikaS_setNonBlock(sock);
laikaP_addSock(&client->pList, sock);
/* queue handshake request */
laikaS_startOutPacket(client->peer, LAIKAPKT_HANDSHAKE_REQ);
laikaS_write(sock, LAIKA_MAGIC, LAIKA_MAGICLEN);
laikaS_writeByte(sock, LAIKA_VERSION_MAJOR);
laikaS_writeByte(sock, LAIKA_VERSION_MINOR);
laikaS_write(sock, client->pub, sizeof(client->pub)); /* write public key */
laikaS_endOutPacket(client->peer);
laikaS_setSecure(client->peer, true);
if (crypto_kx_client_session_keys(client->peer->inKey, client->peer->outKey, client->pub, client->priv, client->peer->peerPub) != 0)
LAIKA_ERROR("failed to gen session key!\n")
/* queue authenticated handshake request */
laikaS_startOutPacket(client->peer, LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ);
laikaS_writeByte(sock, PEER_PANEL);
laikaS_endOutPacket(client->peer);
if (!laikaS_handlePeerOut(client->peer))
LAIKA_ERROR("failed to send handshake request!\n")
}
bool panelC_poll(tPanel_client *client, int timeout) {
struct sLaika_pollEvent *evnt;
int numEvents;
evnt = laikaP_poll(&client->pList, timeout, &numEvents);
if (numEvents == 0) /* no events? timeout was reached */
return false;
LAIKA_TRY
if (evnt->pollIn && !laikaS_handlePeerIn(client->peer))
goto _CLIENTKILL;
if (evnt->pollOut && !laikaS_handlePeerOut(client->peer))
goto _CLIENTKILL;
if (!evnt->pollIn && !evnt->pollOut)
goto _CLIENTKILL;
LAIKA_CATCH
_CLIENTKILL:
laikaS_kill(&client->peer->sock);
LAIKA_TRYEND
/* flush pList's outQueue */
if (client->pList.outCount > 0) {
if (!laikaS_handlePeerOut(client->peer))
laikaS_kill(&client->peer->sock);
laikaP_resetOutQueue(&client->pList);
}
return true;
}
void panelC_addBot(tPanel_bot *bot) {
tPanel_listItem *bItem;
/* add to botList tab */
bItem = panelL_newListItem(panel_botList, NULL, bot->name, NULL, (void*)bot);
/* link bot with listItem */
panelB_setItem(bot, bItem);
}
void panelC_rmvBot(tPanel_bot *bot) {
tPanel_listItem *bItem = bot->item;
/* free from bot list & then free the bot */
panelL_freeListItem(panel_botList, bItem);
panelB_freeBot(bot);
}