UI drawing and input, and move encryption to ui.c
This commit is contained in:
parent
0be02f3954
commit
fa729a8a45
5 changed files with 270 additions and 81 deletions
|
@ -3,9 +3,23 @@
|
||||||
|
|
||||||
#include <ncurses.h>
|
#include <ncurses.h>
|
||||||
|
|
||||||
|
#define USERS_WINDOW 0
|
||||||
|
#define CHAT_WINDOW 1
|
||||||
|
|
||||||
|
/* Keybindings */
|
||||||
|
#define CTRLA 0x01
|
||||||
|
#define CTRLD 0x04
|
||||||
|
#define CTRLE 0x05
|
||||||
|
#define DOWN 0x102
|
||||||
|
#define UP 0x103
|
||||||
|
#define LEFT 0x104
|
||||||
|
#define RIGHT 0x105
|
||||||
|
|
||||||
void ncurses_init();
|
void ncurses_init();
|
||||||
void windows_init();
|
void windows_init();
|
||||||
void draw_border(WINDOW *window, bool active);
|
void draw_border(WINDOW *window, bool active);
|
||||||
|
void add_message(uint8_t *author, uint8_t *recipient, uint8_t *content, uint32_t length, time_t creation);
|
||||||
|
void show_chat(uint8_t *recipient);
|
||||||
void add_username(char *username);
|
void add_username(char *username);
|
||||||
void ui();
|
void ui();
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
typedef struct user {
|
typedef struct user {
|
||||||
char *name;
|
uint8_t *name;
|
||||||
wchar_t *icon;
|
wchar_t *icon;
|
||||||
int color;
|
int color;
|
||||||
} user;
|
} user;
|
||||||
|
@ -19,9 +19,9 @@ typedef struct ArrayList {
|
||||||
|
|
||||||
ArrayList *arraylist_init(size_t capacity);
|
ArrayList *arraylist_init(size_t capacity);
|
||||||
void arraylist_free(ArrayList *list);
|
void arraylist_free(ArrayList *list);
|
||||||
long arraylist_search(ArrayList *list, char *username);
|
long arraylist_search(ArrayList *list, uint8_t *username);
|
||||||
void arraylist_remove(ArrayList *list, long index);
|
void arraylist_remove(ArrayList *list, long index);
|
||||||
void arraylist_add(ArrayList *list, char *name, wchar_t *icon, int color, bool marked, bool force);
|
void arraylist_add(ArrayList *list, uint8_t *username, wchar_t *icon, int color, bool marked, bool force);
|
||||||
char *get_line(ArrayList *list, long index, bool icons);
|
char *get_line(ArrayList *list, long index, bool icons);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
|
#include "notification.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "client/ui.h"
|
#include "client/ui.h"
|
||||||
#include "client/db.h"
|
#include "client/db.h"
|
||||||
|
#include "server/server.h"
|
||||||
|
|
||||||
int sockfd;
|
int sockfd;
|
||||||
|
|
||||||
|
@ -12,7 +14,7 @@ int sockfd;
|
||||||
*/
|
*/
|
||||||
int authenticate_server(key_pair *kp)
|
int authenticate_server(key_pair *kp)
|
||||||
{
|
{
|
||||||
packet server_auth_pkt;
|
packet_t server_auth_pkt;
|
||||||
int status;
|
int status;
|
||||||
if ((status = recv_packet(&server_auth_pkt, sockfd, ZSM_TYP_AUTH) != ZSM_STA_SUCCESS)) {
|
if ((status = recv_packet(&server_auth_pkt, sockfd, ZSM_TYP_AUTH) != ZSM_STA_SUCCESS)) {
|
||||||
return status;
|
return status;
|
||||||
|
@ -28,7 +30,7 @@ int authenticate_server(key_pair *kp)
|
||||||
memcpy(pk_content + PK_BIN_SIZE + MAX_NAME, &kp->pk.creation, TIME_SIZE);
|
memcpy(pk_content + PK_BIN_SIZE + MAX_NAME, &kp->pk.creation, TIME_SIZE);
|
||||||
memcpy(pk_content + PK_BIN_SIZE + METADATA_SIZE, kp->pk.signature, SIGN_SIZE);
|
memcpy(pk_content + PK_BIN_SIZE + METADATA_SIZE, kp->pk.signature, SIGN_SIZE);
|
||||||
|
|
||||||
packet *auth_pkt = create_packet(1, ZSM_TYP_AUTH, SIGN_SIZE, pk_content, sig);
|
packet_t *auth_pkt = create_packet(1, ZSM_TYP_AUTH, SIGN_SIZE, pk_content, sig);
|
||||||
if (send_packet(auth_pkt, sockfd) != ZSM_STA_SUCCESS) {
|
if (send_packet(auth_pkt, sockfd) != ZSM_STA_SUCCESS) {
|
||||||
/* fd already closed */
|
/* fd already closed */
|
||||||
error(0, "Could not authenticate with server");
|
error(0, "Could not authenticate with server");
|
||||||
|
@ -38,43 +40,74 @@ int authenticate_server(key_pair *kp)
|
||||||
}
|
}
|
||||||
|
|
||||||
free_packet(auth_pkt);
|
free_packet(auth_pkt);
|
||||||
packet response;
|
packet_t response;
|
||||||
status = recv_packet(&response, sockfd, ZSM_TYP_INFO);
|
status = recv_packet(&response, sockfd, ZSM_TYP_INFO);
|
||||||
return (response.status == ZSM_STA_AUTHORISED ? ZSM_STA_SUCCESS : ZSM_STA_ERROR_AUTHENTICATE);
|
return (response.status == ZSM_STA_AUTHORISED ? ZSM_STA_SUCCESS : ZSM_STA_ERROR_AUTHENTICATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For sending packets to server
|
* Starting ui
|
||||||
*/
|
*/
|
||||||
void *send_message(void *arg)
|
void *ui_worker(void *arg)
|
||||||
{
|
{
|
||||||
key_pair *kp = (key_pair *) arg;
|
ui(sockfd);
|
||||||
|
|
||||||
while (1) {
|
|
||||||
int status = encrypt_packet(sockfd, kp);
|
|
||||||
if (status != ZSM_STA_SUCCESS) {
|
|
||||||
error(1, "Error encrypting packet %x", status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For receiving packets from server
|
* For receiving packets from server
|
||||||
*/
|
*/
|
||||||
void *receive_message(void *arg)
|
void *receive_worker(void *arg)
|
||||||
{
|
{
|
||||||
key_pair *kp = (key_pair *) arg;
|
key_pair *kp = (key_pair *) arg;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
packet pkt;
|
packet_t pkt;
|
||||||
|
|
||||||
if (verify_packet(&pkt, sockfd) == 0) {
|
if (verify_packet(&pkt, sockfd) == 0) {
|
||||||
error(0, "Error verifying packet");
|
error(0, "Error verifying packet");
|
||||||
}
|
}
|
||||||
uint8_t *decrypted = decrypt_data(&pkt);
|
size_t cipher_len = pkt.length - NONCE_SIZE - MAX_NAME * 2;
|
||||||
|
size_t data_len = cipher_len - ADDITIONAL_SIZE;
|
||||||
|
|
||||||
|
uint8_t nonce[NONCE_SIZE], encrypted[cipher_len];
|
||||||
|
|
||||||
|
uint8_t *from = memalloc(MAX_NAME);
|
||||||
|
uint8_t *to = memalloc(MAX_NAME);
|
||||||
|
uint8_t *decrypted = memalloc(data_len + 1);
|
||||||
|
|
||||||
|
/* Deconstruct data */
|
||||||
|
memcpy(from, pkt.data, MAX_NAME);
|
||||||
|
memcpy(to, pkt.data + MAX_NAME, MAX_NAME);
|
||||||
|
memcpy(nonce, pkt.data + MAX_NAME * 2, NONCE_SIZE);
|
||||||
|
memcpy(encrypted, pkt.data + MAX_NAME * 2 + NONCE_SIZE, cipher_len);
|
||||||
|
|
||||||
|
key_pair *kp_from = get_key_pair(from);
|
||||||
|
key_pair *kp_to = get_key_pair(to);
|
||||||
|
|
||||||
|
uint8_t shared_key[SHARED_SIZE];
|
||||||
|
if (crypto_kx_client_session_keys(shared_key, NULL, kp_from->pk.bin,
|
||||||
|
kp_from->sk.bin, kp_to->pk.bin) != 0) {
|
||||||
|
/* Suspicious server public key, bail out */
|
||||||
|
error(0, "Error performing key exchange");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We don't need it anymore */
|
||||||
|
free(pkt.data);
|
||||||
|
if (crypto_aead_xchacha20poly1305_ietf_decrypt(decrypted, NULL,
|
||||||
|
NULL, encrypted,
|
||||||
|
cipher_len,
|
||||||
|
NULL, 0,
|
||||||
|
nonce, shared_key) != 0) {
|
||||||
free(decrypted);
|
free(decrypted);
|
||||||
|
error(0, "Cannot decrypt data");
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
/* Terminate decrypted data so we don't print random bytes */
|
||||||
|
decrypted[data_len] = '\0';
|
||||||
|
add_message(from, to, decrypted, data_len, time(NULL));
|
||||||
|
show_chat(from);
|
||||||
|
send_notification(from, decrypted);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -85,7 +118,11 @@ int main()
|
||||||
if (sodium_init() < 0) {
|
if (sodium_init() < 0) {
|
||||||
write_log(LOG_ERROR, "Error initializing libsodium\n");
|
write_log(LOG_ERROR, "Error initializing libsodium\n");
|
||||||
}
|
}
|
||||||
//ui();
|
|
||||||
|
/* Init libnotify with app name */
|
||||||
|
if (notify_init("zen") < 0) {
|
||||||
|
error(1, "Error initializing libnotify");
|
||||||
|
}
|
||||||
|
|
||||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
if (sockfd < 0) {
|
if (sockfd < 0) {
|
||||||
|
@ -106,47 +143,42 @@ int main()
|
||||||
/* free(server); Can't be freed seems */
|
/* free(server); Can't be freed seems */
|
||||||
if (connect(sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr)
|
if (connect(sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr)
|
||||||
) < 0) {
|
) < 0) {
|
||||||
if (errno != EINPROGRESS) {
|
|
||||||
/* Connection is in progress, shouldn't be treated as error */
|
|
||||||
error(1, "Error on connect");
|
error(1, "Error on connect");
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
write_log(LOG_INFO, "Connected to server at %s\n", DOMAIN);
|
write_log(LOG_INFO, "Connected to server at %s\n", DOMAIN);
|
||||||
|
|
||||||
/* set_nonblocking(sockfd); */
|
|
||||||
/*
|
/*
|
||||||
key_pair *kpp = create_key_pair("palanix");
|
key_pair *kpp = create_key_pair("palanix");
|
||||||
key_pair *kpn = create_key_pair("night");
|
key_pair *kpn = create_key_pair("night");
|
||||||
*/
|
*/
|
||||||
key_pair *kpp = get_key_pair("palanix");
|
key_pair *kp = get_key_pair(USERNAME);
|
||||||
key_pair *kpn = get_key_pair("night");
|
|
||||||
|
|
||||||
if (authenticate_server(kpp) != ZSM_STA_SUCCESS) {
|
if (authenticate_server(kp) != ZSM_STA_SUCCESS) {
|
||||||
/* Fatal */
|
/* Fatal */
|
||||||
error(1, "Error authenticating with server");
|
error(1, "Error authenticating with server");
|
||||||
} else {
|
} else {
|
||||||
write_log(LOG_INFO, "Authenticated with server\n");
|
write_log(LOG_INFO, "Authenticated with server\n");
|
||||||
printf("Authenticated as palanix\n");
|
printf("Authenticated as %s\n", USERNAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create threads for sending and receiving messages */
|
/* Create threads for sending and receiving messages */
|
||||||
pthread_t send_thread, receive_thread;
|
pthread_t ui_thread, receive_thread;
|
||||||
|
|
||||||
if (pthread_create(&send_thread, NULL, send_message, kpp) != 0) {
|
if (pthread_create(&ui_thread, NULL, ui_worker, NULL) != 0) {
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
error(1, "Failed to create send thread");
|
error(1, "Failed to create send thread");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pthread_create(&receive_thread, NULL, receive_message, kpp) != 0) {
|
if (pthread_create(&receive_thread, NULL, receive_worker, kp) != 0) {
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
error(1, "Failed to create receive thread");
|
error(1, "Failed to create receive thread");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wait for threads to finish */
|
/* Wait for threads to finish */
|
||||||
pthread_join(send_thread, NULL);
|
pthread_join(ui_thread, NULL);
|
||||||
pthread_join(receive_thread, NULL);
|
pthread_join(receive_thread, NULL);
|
||||||
|
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
|
|
211
src/client/ui.c
211
src/client/ui.c
|
@ -5,27 +5,41 @@
|
||||||
#include "client/db.h"
|
#include "client/db.h"
|
||||||
#include "client/user.h"
|
#include "client/user.h"
|
||||||
|
|
||||||
typedef struct windows {
|
|
||||||
WINDOW *users_border;
|
|
||||||
WINDOW *users_content;
|
|
||||||
WINDOW *chat_border;
|
|
||||||
WINDOW *chat_content;
|
|
||||||
} windows;
|
|
||||||
|
|
||||||
WINDOW *panel;
|
WINDOW *panel;
|
||||||
WINDOW *users_border;
|
WINDOW *users_border;
|
||||||
WINDOW *chat_border;
|
WINDOW *chat_border;
|
||||||
|
|
||||||
WINDOW *users_content;
|
WINDOW *users_content;
|
||||||
|
WINDOW *textbox;
|
||||||
WINDOW *chat_content;
|
WINDOW *chat_content;
|
||||||
|
|
||||||
ArrayList *users;
|
ArrayList *users;
|
||||||
ArrayList *marked;
|
ArrayList *marked;
|
||||||
|
message_t messages[100];
|
||||||
|
int num_messages = 0;
|
||||||
long current_selection = 0;
|
long current_selection = 0;
|
||||||
|
int current_window = 0;
|
||||||
|
int sockfd;
|
||||||
bool show_icons;
|
bool show_icons;
|
||||||
|
static char content[MAX_MESSAGE_LENGTH];
|
||||||
|
|
||||||
void show_chat();
|
void send_message();
|
||||||
|
|
||||||
|
void signal_handler(int signal)
|
||||||
|
{
|
||||||
|
switch (signal) {
|
||||||
|
case SIGPIPE:
|
||||||
|
error(0, "SIGPIPE received");
|
||||||
|
break;
|
||||||
|
case SIGABRT:
|
||||||
|
case SIGINT:
|
||||||
|
case SIGTERM:
|
||||||
|
shutdown(sockfd, SHUT_WR);
|
||||||
|
endwin();
|
||||||
|
close(sockfd);
|
||||||
|
error(1, "Shutdown signal received");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ncurses_init()
|
void ncurses_init()
|
||||||
{
|
{
|
||||||
|
@ -70,13 +84,13 @@ void windows_init()
|
||||||
int chat_width = COLS - 32;
|
int chat_width = COLS - 32;
|
||||||
|
|
||||||
/*------------------------------+
|
/*------------------------------+
|
||||||
|----border(0)--||--border(2)--||
|
|-----border----||---border----||
|
||||||
|| || ||
|
|| || ||
|
||||||
|| content (1) || content (3) ||
|
|| content || content ||
|
||||||
|| (users) || (chat) ||
|
|| (users) || (chat) ||
|
||||||
|| || ||
|
|| || ||
|
||||||
|---------------||-------------||
|
|---------------||-textbox-----||
|
||||||
+==========panel (4)===========*/
|
+==========panel===============*/
|
||||||
|
|
||||||
/* lines, cols, y, x */
|
/* lines, cols, y, x */
|
||||||
panel = newwin(PANEL_HEIGHT, COLS, LINES - PANEL_HEIGHT, 0 );
|
panel = newwin(PANEL_HEIGHT, COLS, LINES - PANEL_HEIGHT, 0 );
|
||||||
|
@ -85,6 +99,7 @@ void windows_init()
|
||||||
chat_border = newwin(LINES - PANEL_HEIGHT, chat_width - 2, 0, users_width + 2);
|
chat_border = newwin(LINES - PANEL_HEIGHT, chat_width - 2, 0, users_width + 2);
|
||||||
|
|
||||||
users_content = newwin(LINES - PANEL_HEIGHT - 2, users_width, 1, 1 );
|
users_content = newwin(LINES - PANEL_HEIGHT - 2, users_width, 1, 1 );
|
||||||
|
textbox = newwin(1, users_width, LINES - PANEL_HEIGHT - 2, users_width + 3);
|
||||||
chat_content = newwin(LINES - PANEL_HEIGHT - 2, chat_width - 4, 1, users_width + 3);
|
chat_content = newwin(LINES - PANEL_HEIGHT - 2, chat_width - 4, 1, users_width + 3);
|
||||||
|
|
||||||
refresh();
|
refresh();
|
||||||
|
@ -231,23 +246,30 @@ void highlight_current_line()
|
||||||
wrefresh(users_content);
|
wrefresh(users_content);
|
||||||
wrefresh(panel);
|
wrefresh(panel);
|
||||||
/* show chat conversation every time cursor changes */
|
/* show chat conversation every time cursor changes */
|
||||||
#if DRAW_PREVIEW
|
show_chat(users->items[current_selection].name);
|
||||||
show_chat();
|
|
||||||
#endif
|
|
||||||
#if DRAW_BORDERS
|
#if DRAW_BORDERS
|
||||||
draw_border_title(preview_border, true);
|
draw_border_title(preview_border, true);
|
||||||
#endif
|
#endif
|
||||||
wrefresh(chat_content);
|
wrefresh(chat_content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add_message(uint8_t *author, uint8_t *recipient, uint8_t *content, uint32_t length, time_t creation)
|
||||||
|
{
|
||||||
|
message_t *msg = &messages[num_messages];
|
||||||
|
strcpy(msg->author, author);
|
||||||
|
strcpy(msg->recipient, recipient);
|
||||||
|
msg->content = memalloc(length);
|
||||||
|
strcpy(msg->content, content);
|
||||||
|
msg->creation = creation;
|
||||||
|
num_messages++;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Add message to chat window
|
* Add message to chat window
|
||||||
* user_color is the color defined above at ncurses_init
|
* user_color is the color defined above at ncurses_init
|
||||||
*/
|
*/
|
||||||
|
void print_message(message_t *msg, int user_color)
|
||||||
void add_message(time_t rawtime, char *username, int user_color, char *content)
|
|
||||||
{
|
{
|
||||||
struct tm *timeinfo = localtime(&rawtime);
|
struct tm *timeinfo = localtime(&msg->creation);
|
||||||
char buffer[21];
|
char buffer[21];
|
||||||
strftime(buffer, sizeof(buffer), "%b %d %Y %H:%M:%S", timeinfo);
|
strftime(buffer, sizeof(buffer), "%b %d %Y %H:%M:%S", timeinfo);
|
||||||
|
|
||||||
|
@ -255,25 +277,37 @@ void add_message(time_t rawtime, char *username, int user_color, char *content)
|
||||||
wattron(chat_content, A_BOLD);
|
wattron(chat_content, A_BOLD);
|
||||||
wattron(chat_content, COLOR_PAIR(user_color));
|
wattron(chat_content, COLOR_PAIR(user_color));
|
||||||
|
|
||||||
wprintw(chat_content, "<%s> ", username);
|
wprintw(chat_content, "<%s> ", msg->author);
|
||||||
|
|
||||||
wattroff(chat_content, A_BOLD);
|
wattroff(chat_content, A_BOLD);
|
||||||
wattroff(chat_content, COLOR_PAIR(user_color));
|
wattroff(chat_content, COLOR_PAIR(user_color));
|
||||||
wprintw(chat_content, "%s", content);
|
wprintw(chat_content, "%s", msg->content);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get chat conversation into buffer and show it to chat window
|
* Get chat conversation into buffer and show it to chat window
|
||||||
*/
|
*/
|
||||||
void show_chat()
|
void show_chat(uint8_t *recipient)
|
||||||
{
|
{
|
||||||
add_message(1725932011, "night", 1, "I go to school by bus.\n");
|
wclear(chat_content);
|
||||||
add_message(1725933011, "night", 2, "I go to school by tram.\n");
|
for (int i = 0; i < 100; i++) {
|
||||||
add_message(1725934011, "night", 3, "I go to school by train.\n");
|
message_t message = messages[i];
|
||||||
add_message(1725935011, "night", 4, "I go to school by car.\n");
|
if (message.content == NULL) continue;
|
||||||
add_message(1725936011, "night", 5, "I go to school by run.\n");
|
/* Find messages from recipient to client or vice versa */
|
||||||
add_message(1725937011, "night", 6, "I go to school by bike.\n");
|
/* outgoing = 1, incoming = 2 */
|
||||||
add_message(1725938011, "night", 7, "I go to school by plane.\n");
|
if (strncmp(message.author, USERNAME, MAX_NAME) == 0 &&
|
||||||
|
strncmp(message.recipient, recipient, MAX_NAME) == 0) {
|
||||||
|
print_message(&message, 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(message.author, recipient, MAX_NAME) == 0 &&
|
||||||
|
strncmp(message.recipient, USERNAME, MAX_NAME) == 0) {
|
||||||
|
print_message(&message, 2);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wrefresh(chat_content);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Require heap allocated username
|
* Require heap allocated username
|
||||||
|
@ -286,11 +320,95 @@ void add_username(char *username)
|
||||||
arraylist_add(users, username, icon_str, 7, false, false);
|
arraylist_add(users, username, icon_str, 7, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void get_chatbox_content(int ch)
|
||||||
|
{
|
||||||
|
/* For tracking position in content */
|
||||||
|
static int pos = 0;
|
||||||
|
|
||||||
|
if (ch == KEY_BACKSPACE || ch == 127) {
|
||||||
|
if (pos > 0) {
|
||||||
|
pos--;
|
||||||
|
content[pos] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Input done */
|
||||||
|
else if (ch == '\n') {
|
||||||
|
content[pos++] = ch;
|
||||||
|
content[pos++] = '\0';
|
||||||
|
send_message();
|
||||||
|
/* Reset for new input */
|
||||||
|
pos = 0;
|
||||||
|
}
|
||||||
|
/* Append it to the content if it is normal character */
|
||||||
|
else if (pos < MAX_MESSAGE_LENGTH - 1) {
|
||||||
|
content[pos++] = ch;
|
||||||
|
content[pos] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Display the current content */
|
||||||
|
mvwprintw(textbox, 0, 0, "%s", content);
|
||||||
|
wrefresh(textbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_message()
|
||||||
|
{
|
||||||
|
uint8_t *recipient = users->items[current_selection].name;
|
||||||
|
|
||||||
|
key_pair *kp_from = get_key_pair(USERNAME);
|
||||||
|
key_pair *kp_to = get_key_pair(recipient);
|
||||||
|
|
||||||
|
int status = ZSM_STA_SUCCESS;
|
||||||
|
|
||||||
|
uint8_t shared_key[SHARED_SIZE];
|
||||||
|
if (crypto_kx_client_session_keys(shared_key, NULL, kp_from->pk.bin,
|
||||||
|
kp_from->sk.bin, kp_to->pk.bin) != 0) {
|
||||||
|
/* Recipient public key is suspicious */
|
||||||
|
error(0, "Error performing key exchange");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t content_len = strlen(content);
|
||||||
|
|
||||||
|
uint32_t cipher_len = content_len + ADDITIONAL_SIZE;
|
||||||
|
uint8_t nonce[NONCE_SIZE], encrypted[cipher_len];
|
||||||
|
|
||||||
|
/* Generate random nonce(number used once) */
|
||||||
|
randombytes_buf(nonce, sizeof(nonce));
|
||||||
|
|
||||||
|
/* Encrypt the content and store it to encrypted, should be cipher_len */
|
||||||
|
crypto_aead_xchacha20poly1305_ietf_encrypt(encrypted, NULL, content,
|
||||||
|
content_len, NULL, 0, NULL, nonce, shared_key);
|
||||||
|
|
||||||
|
size_t data_len = MAX_NAME * 2 + NONCE_SIZE + cipher_len;
|
||||||
|
uint8_t *data = memalloc(data_len);
|
||||||
|
|
||||||
|
/* Construct data */
|
||||||
|
memcpy(data, kp_from->sk.username, MAX_NAME);
|
||||||
|
memcpy(data + MAX_NAME, kp_to->sk.username, MAX_NAME);
|
||||||
|
memcpy(data + MAX_NAME * 2, nonce, NONCE_SIZE);
|
||||||
|
memcpy(data + MAX_NAME * 2 + NONCE_SIZE, encrypted, cipher_len);
|
||||||
|
|
||||||
|
uint8_t *signature = create_signature(data, data_len, &kp_from->sk);
|
||||||
|
packet_t *pkt = create_packet(1, ZSM_TYP_MESSAGE, data_len, data, signature);
|
||||||
|
|
||||||
|
if (send_packet(pkt, sockfd) != ZSM_STA_SUCCESS) {
|
||||||
|
close(sockfd);
|
||||||
|
write_log(LOG_ERROR, "Failed to send message");
|
||||||
|
}
|
||||||
|
add_message(USERNAME, recipient, content, content_len, time(NULL));
|
||||||
|
free_packet(pkt);
|
||||||
|
highlight_current_line();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Main loop of user interface
|
* Main loop of user interface
|
||||||
*/
|
*/
|
||||||
void ui()
|
void ui(int fd)
|
||||||
{
|
{
|
||||||
|
signal(SIGPIPE, signal_handler);
|
||||||
|
signal(SIGABRT, signal_handler);
|
||||||
|
signal(SIGINT, signal_handler);
|
||||||
|
signal(SIGTERM, signal_handler);
|
||||||
|
sockfd = fd;
|
||||||
ncurses_init();
|
ncurses_init();
|
||||||
windows_init();
|
windows_init();
|
||||||
users = arraylist_init(LINES);
|
users = arraylist_init(LINES);
|
||||||
|
@ -301,32 +419,57 @@ void ui()
|
||||||
refresh();
|
refresh();
|
||||||
int ch;
|
int ch;
|
||||||
while (1) {
|
while (1) {
|
||||||
|
/*
|
||||||
if (COLS < 80 || LINES < 24) {
|
if (COLS < 80 || LINES < 24) {
|
||||||
endwin();
|
endwin();
|
||||||
error(1, "Terminal size needs to be at least 80x24");
|
error(1, "Terminal size needs to be at least 80x24");
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
ch = getch();
|
ch = getch();
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 'q':
|
case CTRLD:
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
/* go up by k or up arrow */
|
/* go up by k or up arrow */
|
||||||
case UP:
|
case UP:
|
||||||
case 'k':
|
if (current_window == USERS_WINDOW) {
|
||||||
if (current_selection > 0)
|
if (current_selection > 0)
|
||||||
current_selection--;
|
current_selection--;
|
||||||
|
|
||||||
highlight_current_line();
|
highlight_current_line();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* go down by j or down arrow */
|
/* go down by j or down arrow */
|
||||||
case DOWN:
|
case DOWN:
|
||||||
case 'j':
|
if (current_window == USERS_WINDOW) {
|
||||||
if (current_selection < (users->length - 1))
|
if (current_selection < (users->length - 1))
|
||||||
current_selection++;
|
current_selection++;
|
||||||
|
|
||||||
highlight_current_line();
|
highlight_current_line();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* A is normally for left and E for right */
|
||||||
|
case CTRLA:
|
||||||
|
case CTRLE:
|
||||||
|
current_window ^= 1;
|
||||||
|
if (current_window == USERS_WINDOW) {
|
||||||
|
draw_border(users_border, true);
|
||||||
|
draw_border(chat_border, false);
|
||||||
|
} else {
|
||||||
|
draw_border(chat_border, true);
|
||||||
|
draw_border(users_border, false);
|
||||||
|
}
|
||||||
|
/* Need to reprint everything after drawing border */
|
||||||
|
highlight_current_line();
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (current_window == CHAT_WINDOW)
|
||||||
|
get_chatbox_content(ch);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cleanup:
|
cleanup:
|
||||||
|
|
|
@ -28,7 +28,7 @@ void arraylist_free(ArrayList *list)
|
||||||
/*
|
/*
|
||||||
* Check if the user is in the arraylist
|
* Check if the user is in the arraylist
|
||||||
*/
|
*/
|
||||||
long arraylist_search(ArrayList *list, char *username)
|
long arraylist_search(ArrayList *list, uint8_t *username)
|
||||||
{
|
{
|
||||||
for (long i = 0; i < list->length; i++) {
|
for (long i = 0; i < list->length; i++) {
|
||||||
if (strcmp(list->items[i].name, username) == 0) {
|
if (strcmp(list->items[i].name, username) == 0) {
|
||||||
|
@ -55,9 +55,9 @@ void arraylist_remove(ArrayList *list, long index)
|
||||||
/*
|
/*
|
||||||
* Force will not remove duplicate marked users, instead it just skip adding
|
* Force will not remove duplicate marked users, instead it just skip adding
|
||||||
*/
|
*/
|
||||||
void arraylist_add(ArrayList *list, char *name, wchar_t *icon, int color, bool marked, bool force)
|
void arraylist_add(ArrayList *list, uint8_t *username, wchar_t *icon, int color, bool marked, bool force)
|
||||||
{
|
{
|
||||||
user new_user = { name, icon, color };
|
user new_user = { username, icon, color };
|
||||||
|
|
||||||
if (list->capacity != list->length) {
|
if (list->capacity != list->length) {
|
||||||
if (marked) {
|
if (marked) {
|
||||||
|
|
Loading…
Reference in a new issue