diff --git a/build/Makefile.am b/build/Makefile.am index 4bc008d..0a07e55 100644 --- a/build/Makefile.am +++ b/build/Makefile.am @@ -3,7 +3,8 @@ bin_PROGRAMS = toxic -toxic_SOURCES = $(top_srcdir)/src/main.c \ +toxic_SOURCES = $(top_srcdir)/src/toxic.c \ + $(top_srcdir)/src/toxic.h \ $(top_srcdir)/src/chat.h \ $(top_srcdir)/src/chat.c \ $(top_srcdir)/src/configdir.h \ @@ -12,8 +13,8 @@ toxic_SOURCES = $(top_srcdir)/src/main.c \ $(top_srcdir)/src/prompt.c \ $(top_srcdir)/src/friendlist.h \ $(top_srcdir)/src/friendlist.c \ - $(top_srcdir)/src/toxic_windows.h \ $(top_srcdir)/src/windows.c \ + $(top_srcdir)/src/windows.h \ $(top_srcdir)/src/groupchat.c \ $(top_srcdir)/src/groupchat.h \ $(top_srcdir)/src/global_commands.c \ @@ -35,11 +36,11 @@ toxic_SOURCES = $(top_srcdir)/src/main.c \ $(top_srcdir)/src/settings.c \ $(top_srcdir)/src/settings.h -toxic_CFLAGS = -I$(top_srcdir) \ - $(NCURSES_CFLAGS) \ - $(LIBSODIUM_CFLAGS) \ - $(LIBTOXCORE_CFLAGS) \ - $(PTHREAD_CFLAGS) +toxic_CFLAGS = -I$(top_srcdir) \ + $(NCURSES_CFLAGS) \ + $(LIBSODIUM_CFLAGS) \ + $(LIBTOXCORE_CFLAGS) \ + $(PTHREAD_CFLAGS) toxic_CPPFLAGS = '-DTOXICVER="$(TOXIC_VERSION)"' diff --git a/configure.ac b/configure.ac index de0d610..075b702 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ AC_PREREQ([2.65]) AC_INIT([toxic], [0.4.0], [https://tox.im/]) AC_CONFIG_AUX_DIR(configure_aux) -AC_CONFIG_SRCDIR([src/main.c]) +AC_CONFIG_SRCDIR([src/toxic.c]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([1.10 -Wall]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) diff --git a/src/audio_call.c b/src/audio_call.c index 106ebed..a885814 100644 --- a/src/audio_call.c +++ b/src/audio_call.c @@ -1,16 +1,34 @@ -/* - * Toxic -- Tox Curses Client +/* audio_call.c + * + * + * Copyright (C) 2014 Toxic All Rights Reserved. + * + * This file is part of Toxic. + * + * Toxic 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. + * + * Toxic 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 Toxic. If not, see . + * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include "toxic_windows.h" +#include "toxic.h" +#include "windows.h" #include "audio_call.h" #include "chat_commands.h" #include "global_commands.h" -#include "toxic_windows.h" #include "line_info.h" #include diff --git a/src/audio_call.h b/src/audio_call.h index 264e94b..7583eb4 100644 --- a/src/audio_call.h +++ b/src/audio_call.h @@ -1,5 +1,23 @@ -/* - * Toxic -- Tox Curses Client +/* audio_call.h + * + * + * Copyright (C) 2014 Toxic All Rights Reserved. + * + * This file is part of Toxic. + * + * Toxic 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. + * + * Toxic 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 Toxic. If not, see . + * */ #ifndef _audio_h @@ -7,6 +25,9 @@ #include +#include "toxic.h" +#include "windows.h" + #define MAX_DEVICES 32 typedef enum _AudioError { diff --git a/src/chat.c b/src/chat.c index d1fbc36..a348527 100644 --- a/src/chat.c +++ b/src/chat.c @@ -28,7 +28,8 @@ #include #include -#include "toxic_windows.h" +#include "toxic.h" +#include "windows.h" #include "execute.h" #include "misc_tools.h" #include "friendlist.h" diff --git a/src/chat.h b/src/chat.h index d3aeb3e..e6fc30b 100644 --- a/src/chat.h +++ b/src/chat.h @@ -23,7 +23,8 @@ #ifndef CHAT_H_6489PZ13 #define CHAT_H_6489PZ13 -#include "toxic_windows.h" +#include "windows.h" +#include "toxic.h" void kill_chat_window(ToxWindow *self); ToxWindow new_chat(Tox *m, int32_t friendnum); diff --git a/src/chat_commands.c b/src/chat_commands.c index 063d16d..9c92e8e 100644 --- a/src/chat_commands.c +++ b/src/chat_commands.c @@ -27,7 +27,8 @@ #include #include -#include "toxic_windows.h" +#include "toxic.h" +#include "windows.h" #include "misc_tools.h" #include "friendlist.h" #include "execute.h" diff --git a/src/chat_commands.h b/src/chat_commands.h index 76ecd64..0cab454 100644 --- a/src/chat_commands.h +++ b/src/chat_commands.h @@ -20,6 +20,12 @@ * */ +#ifndef _chat_commands_h +#define _chat_commands_h + +#include "windows.h" +#include "toxic.h" + void cmd_chat_help(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_groupinvite(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_join_group(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); @@ -34,3 +40,5 @@ void cmd_reject(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZ void cmd_hangup(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_cancel(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); #endif /* _SUPPORT_AUDIO */ + +#endif /* #define _chat_commands_h */ diff --git a/src/configdir.h b/src/configdir.h index ad4daf8..0a8b01d 100644 --- a/src/configdir.h +++ b/src/configdir.h @@ -20,6 +20,9 @@ * */ +#ifndef _configdir_h +#define _configdir_h + #define CONFIGDIR "/tox/" #ifndef S_ISDIR @@ -29,3 +32,5 @@ char *get_user_config_dir(void); int create_user_config_dir(char *path); + +#endif /* #define _configdir_h */ diff --git a/src/execute.c b/src/execute.c index 34e8e31..5a9fde8 100644 --- a/src/execute.c +++ b/src/execute.c @@ -28,7 +28,8 @@ #include #include -#include "toxic_windows.h" +#include "toxic.h" +#include "windows.h" #include "execute.h" #include "chat_commands.h" #include "global_commands.h" diff --git a/src/execute.h b/src/execute.h index df9072e..80a6a00 100644 --- a/src/execute.h +++ b/src/execute.h @@ -20,6 +20,12 @@ * */ +#ifndef _execute_h +#define _execute_h + +#include "toxic.h" +#include "windows.h" + #define MAX_NUM_ARGS 4 /* Includes command */ #ifdef _SUPPORT_AUDIO @@ -37,3 +43,5 @@ enum { }; void execute(WINDOW *w, ToxWindow *self, Tox *m, char *cmd, int mode); + +#endif /* #define _execute_h */ diff --git a/src/file_senders.c b/src/file_senders.c index 69aaca5..4d12a54 100644 --- a/src/file_senders.c +++ b/src/file_senders.c @@ -28,7 +28,9 @@ #include #include -#include "toxic_windows.h" +#include "toxic.h" +#include "windows.h" +#include "file_senders.h" #include "line_info.h" FileSender file_senders[MAX_FILES]; diff --git a/src/file_senders.h b/src/file_senders.h index 9ec1cdc..59cc640 100644 --- a/src/file_senders.h +++ b/src/file_senders.h @@ -20,7 +20,33 @@ * */ +#ifndef _filesenders_h +#define _filesenders_h + +#include "toxic.h" +#include "windows.h" + +#define FILE_PIECE_SIZE 2048 /* must be >= (MAX_CRYPTO_DATA_SIZE - 2) in toxcore/net_crypto.h */ +#define MAX_FILES 256 +#define TIMEOUT_FILESENDER 300 + +typedef struct { + FILE *file; + ToxWindow *toxwin; + int32_t friendnum; + bool active; + int filenum; + uint8_t nextpiece[FILE_PIECE_SIZE]; + uint16_t piecelen; + uint8_t pathname[MAX_STR_SIZE]; + uint64_t timestamp; + uint64_t size; + uint32_t line_id; +} FileSender; + /* Should only be called on exit */ void close_all_file_senders(void); void do_file_senders(Tox *m); + +#endif /* #define _filesenders_h */ diff --git a/src/friendlist.c b/src/friendlist.c index 108b772..9e602a6 100644 --- a/src/friendlist.c +++ b/src/friendlist.c @@ -31,6 +31,8 @@ #include +#include "toxic.h" +#include "windows.h" #include "chat.h" #include "friendlist.h" #include "misc_tools.h" diff --git a/src/friendlist.h b/src/friendlist.h index 363cbea..f6cc9fd 100644 --- a/src/friendlist.h +++ b/src/friendlist.h @@ -24,10 +24,21 @@ #define FRIENDLIST_H_53I41IM #include -#include "toxic_windows.h" + +#include "toxic.h" +#include "windows.h" +#include "file_senders.h" #define TIME_STR_SIZE 16 +struct FileReceiver { + uint8_t filenames[MAX_FILES][MAX_STR_SIZE]; + FILE *files[MAX_FILES]; + bool pending[MAX_FILES]; + uint64_t size[MAX_FILES]; + uint32_t line_id[MAX_FILES]; +}; + struct LastOnline { uint64_t last_on; struct tm tm; diff --git a/src/global_commands.c b/src/global_commands.c index b51adca..9221e90 100644 --- a/src/global_commands.c +++ b/src/global_commands.c @@ -27,7 +27,8 @@ #include #include -#include "toxic_windows.h" +#include "toxic.h" +#include "windows.h" #include "misc_tools.h" #include "friendlist.h" #include "log.h" diff --git a/src/global_commands.h b/src/global_commands.h index f8aec5b..5bc5e3c 100644 --- a/src/global_commands.h +++ b/src/global_commands.h @@ -20,6 +20,12 @@ * */ +#ifndef _global_commands_h +#define _global_commands_h + +#include "windows.h" +#include "toxic.h" + void cmd_accept(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_add(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_clear(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); @@ -36,4 +42,6 @@ void cmd_status(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZ #ifdef _SUPPORT_AUDIO void cmd_list_devices(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_change_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); -#endif /* _SUPPORT_AUDIO */ \ No newline at end of file +#endif /* _SUPPORT_AUDIO */ + +#endif /* #define _global_commands_h */ diff --git a/src/groupchat.c b/src/groupchat.c index 15c8448..5a42892 100644 --- a/src/groupchat.c +++ b/src/groupchat.c @@ -28,7 +28,8 @@ #include #include -#include "toxic_windows.h" +#include "windows.h" +#include "toxic.h" #include "execute.h" #include "misc_tools.h" #include "groupchat.h" diff --git a/src/groupchat.h b/src/groupchat.h index afaa311..3ef5a1e 100644 --- a/src/groupchat.h +++ b/src/groupchat.h @@ -20,6 +20,12 @@ * */ +#ifndef _groupchat_h +#define _groupchat_h + +#include "toxic.h" +#include "windows.h" + #define SIDEBAR_WIDTH 16 #define SDBAR_OFST 2 /* Offset for the peer number box at the top of the statusbar */ @@ -37,3 +43,5 @@ typedef struct { void kill_groupchat_window(ToxWindow *self); int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum); ToxWindow new_group_chat(Tox *m, int groupnum); + +#endif /* #define _groupchat_h */ diff --git a/src/line_info.c b/src/line_info.c index 94ac2b4..6c32295 100644 --- a/src/line_info.c +++ b/src/line_info.c @@ -28,7 +28,8 @@ #include #include -#include "toxic_windows.h" +#include "toxic.h" +#include "windows.h" #include "line_info.h" #include "groupchat.h" #include "settings.h" diff --git a/src/line_info.h b/src/line_info.h index 3d921e5..e9618a7 100644 --- a/src/line_info.h +++ b/src/line_info.h @@ -20,6 +20,12 @@ * */ +#ifndef _line_info_h +#define line_info_h + +#include "windows.h" +#include "toxic.h" + #define MAX_HISTORY 10000 #define MIN_HISTORY 20 @@ -84,3 +90,5 @@ void line_info_set(ToxWindow *self, uint32_t id, uint8_t *msg); void line_info_init(struct history *hst); void line_info_onKey(ToxWindow *self, wint_t key); void line_info_onDraw(ToxWindow *self); + +#endif /* #define line_info_h */ diff --git a/src/log.c b/src/log.c index 63f3d40..d965895 100644 --- a/src/log.c +++ b/src/log.c @@ -29,7 +29,8 @@ #include #include "configdir.h" -#include "toxic_windows.h" +#include "toxic.h" +#include "windows.h" #include "misc_tools.h" #include "log.h" #include "settings.h" diff --git a/src/log.h b/src/log.h index 9473eeb..0cb1ba2 100644 --- a/src/log.h +++ b/src/log.h @@ -20,6 +20,9 @@ * */ +#ifndef _log_h +#define _log_h + #define LOG_FLUSH_LIMIT 2 /* limits calls to fflush(logfile) to a max of one per LOG_FLUSH_LIMIT seconds */ struct chatlog { @@ -40,3 +43,5 @@ void log_enable(uint8_t *name, uint8_t *key, struct chatlog *log); /* disables logging for specified log and closes file */ void log_disable(struct chatlog *log); + +#endif /* #define _log_h */ diff --git a/src/misc_tools.c b/src/misc_tools.c index a1e562e..b28d814 100644 --- a/src/misc_tools.c +++ b/src/misc_tools.c @@ -29,7 +29,8 @@ #include #include -#include "toxic_windows.h" +#include "toxic.h" +#include "windows.h" #include "misc_tools.h" #include "settings.h" diff --git a/src/misc_tools.h b/src/misc_tools.h index e1e7e45..1c056cb 100644 --- a/src/misc_tools.h +++ b/src/misc_tools.h @@ -19,6 +19,11 @@ * along with Toxic. If not, see . * */ +#ifndef _misc_tools_h +#define _misc_tools_h + +#include "windows.h" +#include "toxic.h" #define MIN(x, y) (((x) < (y)) ? (x) : (y)) #define MAX(x, y) (((x) > (y)) ? (x) : (y)) @@ -75,3 +80,5 @@ void mv_curs_end(WINDOW *w, size_t len, int max_y, int max_x); /* gets base file name from path or original file name if no path is supplied */ void get_file_name(uint8_t *namebuf, uint8_t *pathname); + +#endif /* #define _misc_tools_h */ diff --git a/src/prompt.c b/src/prompt.c index 39e9ba9..a6e387d 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -27,7 +27,8 @@ #include #include -#include "toxic_windows.h" +#include "toxic.h" +#include "windows.h" #include "prompt.h" #include "execute.h" #include "misc_tools.h" diff --git a/src/prompt.h b/src/prompt.h index b120a65..405a3ec 100644 --- a/src/prompt.h +++ b/src/prompt.h @@ -23,8 +23,10 @@ #ifndef PROMPT_H_UZYGWFFL #define PROMPT_H_UZYGWFFL -#define X_OFST 2 /* offset to account for prompt char */ +#include "toxic.h" +#include "windows.h" +#define X_OFST 2 /* offset to account for prompt char */ #ifdef _SUPPORT_AUDIO #define AC_NUM_GLOB_COMMANDS 17 diff --git a/src/settings.c b/src/settings.c index 2eb860d..9e10d42 100644 --- a/src/settings.c +++ b/src/settings.c @@ -23,7 +23,8 @@ #include #include -#include "toxic_windows.h" +#include "toxic.h" +#include "windows.h" #include "configdir.h" #ifdef _SUPPORT_AUDIO diff --git a/src/settings.h b/src/settings.h index ef9e709..946d2e6 100644 --- a/src/settings.h +++ b/src/settings.h @@ -20,6 +20,11 @@ * */ +#ifndef _settings_h +#define _settings_h + +#include "toxic.h" + #ifdef _SUPPORT_AUDIO #define NUM_SETTINGS 8 #else @@ -58,3 +63,5 @@ enum { } settings_values; int settings_load(struct user_settings *s, char *path); + +#endif /* #define _settings_h */ diff --git a/src/toxic.c b/src/toxic.c new file mode 100644 index 0000000..2a54a69 --- /dev/null +++ b/src/toxic.c @@ -0,0 +1,652 @@ +/* toxic.c + * + * + * Copyright (C) 2014 Toxic All Rights Reserved. + * + * This file is part of Toxic. + * + * Toxic 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. + * + * Toxic 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 Toxic. If not, see . + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef SIGWINCH +#define SIGWINCH 28 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "configdir.h" +#include "toxic.h" +#include "windows.h" +#include "friendlist.h" +#include "prompt.h" +#include "misc_tools.h" +#include "file_senders.h" +#include "line_info.h" +#include "settings.h" + +#ifdef _SUPPORT_AUDIO +#include "audio_call.h" +#endif /* _SUPPORT_AUDIO */ + +#ifndef PACKAGE_DATADIR +#define PACKAGE_DATADIR "." +#endif + +#ifdef _SUPPORT_AUDIO +ToxAv *av; +#endif /* _SUPPORT_AUDIO */ + +/* Export for use in Callbacks */ +char *DATA_FILE = NULL; +ToxWindow *prompt = NULL; + +struct arg_opts { + int ignore_data_file; + int use_ipv4; + char config_path[MAX_STR_SIZE]; + char nodes_path[MAX_STR_SIZE]; +} arg_opts; + +struct _Winthread Winthread; +struct user_settings *user_settings = NULL; + +void on_window_resize(int sig) +{ + refresh(); + clear(); +} + +static void init_term(void) +{ + /* Setup terminal */ + signal(SIGWINCH, on_window_resize); +#if HAVE_WIDECHAR + + if (setlocale(LC_ALL, "") == NULL) { + fprintf(stderr, "Could not set your locale, plese check your locale settings or" + "disable wide char support\n"); + exit(EXIT_FAILURE); + } + +#endif + initscr(); + cbreak(); + keypad(stdscr, 1); + noecho(); + timeout(100); + + if (has_colors()) { + short bg_color = COLOR_BLACK; + start_color(); + + if (user_settings->colour_theme == NATIVE_COLS) { + if (assume_default_colors(-1, -1) == OK) + bg_color = -1; + } + + init_pair(0, COLOR_WHITE, COLOR_BLACK); + init_pair(1, COLOR_GREEN, bg_color); + init_pair(2, COLOR_CYAN, bg_color); + init_pair(3, COLOR_RED, bg_color); + init_pair(4, COLOR_BLUE, bg_color); + init_pair(5, COLOR_YELLOW, bg_color); + init_pair(6, COLOR_MAGENTA, bg_color); + init_pair(7, COLOR_BLACK, COLOR_BLACK); + init_pair(8, COLOR_BLACK, COLOR_WHITE); + } + + refresh(); +} + +static Tox *init_tox(int ipv4) +{ + /* Init core */ + int ipv6 = !ipv4; + Tox *m = tox_new(ipv6); + + /* + * TOX_ENABLE_IPV6_DEFAULT is always 1. + * Checking it is redundant, this *should* be doing ipv4 fallback + */ + if (ipv6 && m == NULL) { + fprintf(stderr, "IPv6 didn't initialize, trying IPv4\n"); + m = tox_new(0); + } + + if (ipv4) + fprintf(stderr, "Forcing IPv4 connection\n"); + + if (m == NULL) + return NULL; + + /* Callbacks */ + tox_callback_connection_status(m, on_connectionchange, NULL); + tox_callback_typing_change(m, on_typing_change, NULL); + tox_callback_friend_request(m, on_request, NULL); + tox_callback_friend_message(m, on_message, NULL); + tox_callback_name_change(m, on_nickchange, NULL); + tox_callback_user_status(m, on_statuschange, NULL); + tox_callback_status_message(m, on_statusmessagechange, NULL); + tox_callback_friend_action(m, on_action, NULL); + tox_callback_group_invite(m, on_groupinvite, NULL); + tox_callback_group_message(m, on_groupmessage, NULL); + tox_callback_group_action(m, on_groupaction, NULL); + tox_callback_group_namelist_change(m, on_group_namelistchange, NULL); + tox_callback_file_send_request(m, on_file_sendrequest, NULL); + tox_callback_file_control(m, on_file_control, NULL); + tox_callback_file_data(m, on_file_data, NULL); + +#ifdef __linux__ + tox_set_name(m, (uint8_t *) "Cool dude", strlen("Cool dude")); +#elif defined(__FreeBSD__) + tox_set_name(m, (uint8_t *) "Nerd", strlen("Nerd")); +#elif defined(__APPLE__) + tox_set_name(m, (uint8_t *) "Hipster", strlen("Hipster")); /* This used to users of other Unixes are hipsters */ +#else + tox_set_name(m, (uint8_t *) "Registered Minix user #4", strlen("Registered Minix user #4")); +#endif + + return m; +} + +#define MINLINE 50 /* IP: 7 + port: 5 + key: 38 + spaces: 2 = 70. ! (& e.g. tox.im = 6) */ +#define MAXLINE 256 /* Approx max number of chars in a sever line (name + port + key) */ +#define MAXNODES 50 +#define NODELEN (MAXLINE - TOX_CLIENT_ID_SIZE - 7) + +static int linecnt = 0; +static char nodes[MAXNODES][NODELEN]; +static uint16_t ports[MAXNODES]; +static uint8_t keys[MAXNODES][TOX_CLIENT_ID_SIZE]; + +static int nodelist_load(char *filename) +{ + if (!filename) + return 1; + + FILE *fp = fopen(filename, "r"); + + if (fp == NULL) + return 1; + + char line[MAXLINE]; + + while (fgets(line, sizeof(line), fp) && linecnt < MAXNODES) { + if (strlen(line) > MINLINE) { + char *name = strtok(line, " "); + char *port = strtok(NULL, " "); + char *key_ascii = strtok(NULL, " "); + + /* invalid line */ + if (name == NULL || port == NULL || key_ascii == NULL) + continue; + + snprintf(nodes[linecnt], sizeof(nodes[linecnt]), "%s", name); + nodes[linecnt][NODELEN - 1] = 0; + ports[linecnt] = htons(atoi(port)); + + uint8_t *key_binary = hex_string_to_bin(key_ascii); + memcpy(keys[linecnt], key_binary, TOX_CLIENT_ID_SIZE); + free(key_binary); + + linecnt++; + } + } + + if (linecnt < 1) { + fclose(fp); + return 2; + } + + fclose(fp); + return 0; +} + +int init_connection_helper(Tox *m, int line) +{ + return tox_bootstrap_from_address(m, nodes[line], TOX_ENABLE_IPV6_DEFAULT, + ports[line], keys[line]); +} + +/* Connects to a random DHT node listed in the DHTnodes file + * + * return codes: + * 1: failed to open node file + * 2: no line of sufficient length in node file + * 3: failed to resolve name to IP + * 4: nodelist file contains no acceptable line + */ +static bool srvlist_loaded = false; + +#define NUM_INIT_NODES 5 + +int init_connection(Tox *m) +{ + if (linecnt > 0) /* already loaded nodelist */ + return init_connection_helper(m, rand() % linecnt) ? 0 : 3; + + /* only once: + * - load the nodelist + * - connect to "everyone" inside + */ + if (!srvlist_loaded) { + srvlist_loaded = true; + int res; + + if (!arg_opts.nodes_path[0]) + res = nodelist_load(PACKAGE_DATADIR "/DHTnodes"); + else + res = nodelist_load(arg_opts.nodes_path); + + if (linecnt < 1) + return res; + + res = 3; + int i; + int n = MIN(NUM_INIT_NODES, linecnt); + + for (i = 0; i < n; ++i) { + if (init_connection_helper(m, rand() % linecnt)) + res = 0; + } + + return res; + } + + /* empty nodelist file */ + return 4; +} + +static void do_connection(Tox *m, ToxWindow *prompt) +{ + uint8_t msg[MAX_STR_SIZE] = {0}; + + static int conn_try = 0; + static int conn_err = 0; + static bool dht_on = false; + + bool is_connected = tox_isconnected(m); + + if (!dht_on && !is_connected && !(conn_try++ % 100)) { + if (!conn_err) { + if ((conn_err = init_connection(m))) { + snprintf(msg, sizeof(msg), "\nAuto-connect failed with error code %d", conn_err); + } + } + } else if (!dht_on && is_connected) { + dht_on = true; + prompt_update_connectionstatus(prompt, dht_on); + snprintf(msg, sizeof(msg), "DHT connected."); + } else if (dht_on && !is_connected) { + dht_on = false; + prompt_update_connectionstatus(prompt, dht_on); + snprintf(msg, sizeof(msg), "\nDHT disconnected. Attempting to reconnect."); + } + + if (msg[0]) + line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, 0); +} + +static void load_friendlist(Tox *m) +{ + uint32_t i; + uint32_t numfriends = tox_count_friendlist(m); + + for (i = 0; i < numfriends; ++i) + friendlist_onFriendAdded(NULL, m, i, false); +} + +/* + * Store Messenger to given location + * Return 0 stored successfully + * Return 1 file path is NULL + * Return 2 malloc failed + * Return 3 opening path failed + * Return 4 fwrite failed + */ +int store_data(Tox *m, char *path) +{ + if (arg_opts.ignore_data_file) + return 0; + + if (path == NULL) + return 1; + + FILE *fd; + size_t len; + uint8_t *buf; + + len = tox_size(m); + buf = malloc(len); + + if (buf == NULL) + return 2; + + tox_save(m, buf); + + fd = fopen(path, "wb"); + + if (fd == NULL) { + free(buf); + return 3; + } + + if (fwrite(buf, len, 1, fd) != 1) { + free(buf); + fclose(fd); + return 4; + } + + free(buf); + fclose(fd); + return 0; +} + +static void load_data(Tox *m, char *path) +{ + if (arg_opts.ignore_data_file) + return; + + FILE *fd; + size_t len; + uint8_t *buf; + + if ((fd = fopen(path, "rb")) != NULL) { + fseek(fd, 0, SEEK_END); + len = ftell(fd); + fseek(fd, 0, SEEK_SET); + + buf = malloc(len); + + if (buf == NULL) { + fclose(fd); + endwin(); + fprintf(stderr, "malloc() failed. Aborting...\n"); + exit(EXIT_FAILURE); + } + + if (fread(buf, len, 1, fd) != 1) { + free(buf); + fclose(fd); + endwin(); + fprintf(stderr, "fread() failed. Aborting...\n"); + exit(EXIT_FAILURE); + } + + tox_load(m, buf, len); + load_friendlist(m); + + free(buf); + fclose(fd); + } else { + int st; + + if ((st = store_data(m, path)) != 0) { + endwin(); + fprintf(stderr, "Store messenger failed with return code: %d\n", st); + exit(EXIT_FAILURE); + } + } +} + +void exit_toxic(Tox *m) +{ + store_data(m, DATA_FILE); + close_all_file_senders(); + kill_all_windows(); + log_disable(prompt->chatwin->log); + line_info_cleanup(prompt->chatwin->hst); + free(DATA_FILE); + free(prompt->stb); + free(prompt->chatwin->log); + free(prompt->chatwin->hst); + free(prompt->chatwin); + free(user_settings); +#ifdef _SUPPORT_AUDIO + terminate_audio(); +#endif /* _SUPPORT_AUDIO */ + tox_kill(m); + endwin(); + exit(EXIT_SUCCESS); +} + +static void do_toxic(Tox *m, ToxWindow *prompt) +{ + pthread_mutex_lock(&Winthread.lock); + + do_connection(m, prompt); + do_file_senders(m); + + /* main tox-core loop */ + tox_do(m); + + pthread_mutex_unlock(&Winthread.lock); +} + +void *thread_winref(void *data) +{ + Tox *m = (Tox *) data; + + while (true) { + draw_active_window(m); + refresh_inactive_windows(); + } +} + +static void print_usage(void) +{ + fprintf(stderr, "usage: toxic [OPTION] [FILE ...]\n"); + fprintf(stderr, " -f, --file Use specified data file\n"); + fprintf(stderr, " -x, --nodata Ignore data file\n"); + fprintf(stderr, " -4, --ipv4 Force IPv4 connection\n"); + fprintf(stderr, " -c, --config Use specified config file\n"); + fprintf(stderr, " -n, --nodes Use specified DHTnodes file\n"); + fprintf(stderr, " -h, --help Show this message and exit\n"); +} + +static void set_default_opts(void) +{ + arg_opts.use_ipv4 = 0; + arg_opts.ignore_data_file = 0; +} + +static void parse_args(int argc, char *argv[]) +{ + set_default_opts(); + + const char *opts_str = "4xf:c:n:h"; + int opt, indexptr; + + while (true) { + static struct option long_opts[] = { + {"file", required_argument, 0, 'f'}, + {"nodata", no_argument, 0, 'x'}, + {"ipv4", no_argument, 0, '4'}, + {"config", required_argument, 0, 'c'}, + {"nodes", required_argument, 0, 'n'}, + {"help", no_argument, 0, 'h'}, + }; + + opt = getopt_long(argc, argv, opts_str, long_opts, &indexptr); + + if (opt == -1) + break; + + switch (opt) { + case 'f': + DATA_FILE = strdup(optarg); + break; + + case 'x': + arg_opts.ignore_data_file = 1; + break; + + case '4': + arg_opts.use_ipv4 = 1; + break; + + case 'c': + snprintf(arg_opts.config_path, sizeof(arg_opts.config_path), "%s", optarg); + break; + + case 'n': + snprintf(arg_opts.nodes_path, sizeof(arg_opts.nodes_path), "%s", optarg); + break; + + case 'h': + default: + print_usage(); + exit(EXIT_FAILURE); + } + } +} + +int main(int argc, char *argv[]) +{ + char *user_config_dir = get_user_config_dir(); + int config_err = 0; + + parse_args(argc, argv); + + /* Make sure all written files are read/writeable only by the current user. */ + umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + + config_err = create_user_config_dir(user_config_dir); + + if (DATA_FILE == NULL ) { + if (config_err) { + DATA_FILE = strdup("data"); + } else { + DATA_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen("data") + 1); + + if (DATA_FILE != NULL) { + strcpy(DATA_FILE, user_config_dir); + strcat(DATA_FILE, CONFIGDIR); + strcat(DATA_FILE, "data"); + } else { + endwin(); + fprintf(stderr, "malloc() failed. Aborting...\n"); + exit(EXIT_FAILURE); + } + } + } + + free(user_config_dir); + + /* init user_settings struct and load settings from conf file */ + user_settings = malloc(sizeof(struct user_settings)); + + if (user_settings == NULL) { + endwin(); + fprintf(stderr, "malloc() failed. Aborting...\n"); + exit(EXIT_FAILURE); + } + + memset(user_settings, 0, sizeof(struct user_settings)); + + char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL; + int settings_err = settings_load(user_settings, p); + + Tox *m = init_tox(arg_opts.use_ipv4); + init_term(); + + if (m == NULL) { + endwin(); + fprintf(stderr, "Failed to initialize network. Aborting...\n"); + exit(EXIT_FAILURE); + } + + if (!arg_opts.ignore_data_file) + load_data(m, DATA_FILE); + + prompt = init_windows(m); + + /* create new thread for ncurses stuff */ + if (pthread_mutex_init(&Winthread.lock, NULL) != 0) { + endwin(); + fprintf(stderr, "Mutex init failed. Aborting...\n"); + exit(EXIT_FAILURE); + } + + if (pthread_create(&Winthread.tid, NULL, thread_winref, (void *) m) != 0) { + endwin(); + fprintf(stderr, "Thread creation failed. Aborting...\n"); + exit(EXIT_FAILURE); + } + + uint8_t *msg; + +#ifdef _SUPPORT_AUDIO + + av = init_audio(prompt, m); + + device_set(prompt, input, user_settings->audio_in_dev); + device_set(prompt, output, user_settings->audio_out_dev); + + if ( errors() == NoError ) + msg = "Audio initiated with no problems."; + else /* Get error code and stuff */ + msg = "Error initiating audio!"; + + line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, 0); + +#endif /* _SUPPORT_AUDIO */ + + if (config_err) { + msg = "Unable to determine configuration directory. Defaulting to 'data' for a keyfile..."; + line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, 0); + } + + + if (settings_err == -1) { + msg = "Failed to load user settings"; + line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, 0); + } + + + sort_friendlist_index(); + prompt_init_statusbar(prompt, m); + + while (true) { + update_unix_time(); + do_toxic(m, prompt); + // uint32_t st = MIN(tox_do_interval(m) * 1000, 20000); + usleep(10000); + } + + return 0; +} diff --git a/src/toxic.h b/src/toxic.h new file mode 100644 index 0000000..46d4588 --- /dev/null +++ b/src/toxic.h @@ -0,0 +1,84 @@ +/* toxic.h + * + * + * Copyright (C) 2014 Toxic All Rights Reserved. + * + * This file is part of Toxic. + * + * Toxic 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. + * + * Toxic 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 Toxic. If not, see . + * + */ + +#ifndef _toxic_h +#define _toxic_h + +#ifndef TOXICVER +#define TOXICVER "NOVER_" /* Use the -D flag to set this */ +#endif + +#include +#include + +#include + +#define UNKNOWN_NAME "Anonymous" + +#define MAX_FRIENDS_NUM 500 +#define MAX_STR_SIZE 256 +#define MAX_CMDNAME_SIZE 64 +#define TOXIC_MAX_NAME_LENGTH 32 /* Must be <= TOX_MAX_NAME_LENGTH */ +#define KEY_IDENT_DIGITS 2 /* number of hex digits to display for the pub-key based identifier */ +#define TIME_STR_SIZE 16 + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +/* ASCII key codes */ +#define T_KEY_KILL 0x0B /* ctrl-k */ +#define T_KEY_DISCARD 0x15 /* ctrl-u */ +#define T_KEY_NEXT 0x10 /* ctrl-p */ +#define T_KEY_PREV 0x0F /* ctrl-o */ +#define T_KEY_C_E 0x05 /* ctrl-e */ +#define T_KEY_C_A 0x01 /* ctrl-a */ +#define T_KEY_ESC 0x1B /* ESC key */ + +enum { + MOVE_UP, + MOVE_DOWN, +} KEY_DIRS; + +/* Fixes text color problem on some terminals. + Uncomment if necessary */ +/* #define URXVT_FIX */ + +void on_request(Tox *m, uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata); +void on_connectionchange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata); +void on_message(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata); +void on_action(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata); +void on_nickchange(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata); +void on_statuschange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata); +void on_statusmessagechange(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata); +void on_friendadded(Tox *m, int32_t friendnumber, bool sort); +void on_groupmessage(Tox *m, int groupnumber, int peernumber, uint8_t *message, uint16_t length, void *userdata); +void on_groupaction(Tox *m, int groupnumber, int peernumber, uint8_t *action, uint16_t length, void *userdata); +void on_groupinvite(Tox *m, int32_t friendnumber, uint8_t *group_pub_key, void *userdata); +void on_group_namelistchange(Tox *m, int groupnumber, int peernumber, uint8_t change, void *userdata); +void on_file_sendrequest(Tox *m, int32_t friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *pathname, + uint16_t pathname_length, void *userdata); +void on_file_control(Tox *m, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber, uint8_t control_type, + uint8_t *data, uint16_t length, void *userdata); +void on_file_data(Tox *m, int32_t friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata); +void on_typing_change(Tox *m, int32_t friendnumber, uint8_t is_typing, void *userdata); + +#endif /* #define _toxic_h */ diff --git a/src/toxic_strings.c b/src/toxic_strings.c index 4f7f9ae..388f9b7 100644 --- a/src/toxic_strings.c +++ b/src/toxic_strings.c @@ -27,7 +27,8 @@ #include #include -#include "toxic_windows.h" +#include "toxic.h" +#include "windows.h" #include "misc_tools.h" #include "toxic_strings.h" diff --git a/src/toxic_strings.h b/src/toxic_strings.h index 772c318..b792532 100644 --- a/src/toxic_strings.h +++ b/src/toxic_strings.h @@ -20,6 +20,11 @@ * */ +#ifndef _toxic_strings_h +#define _toxic_strings_h + +#include "windows.h" + /* Adds char to line at pos */ void add_char_to_buf(ChatContext *ctx, wint_t ch); @@ -59,3 +64,5 @@ void add_line_to_hist(ChatContext *ctx); resets line if at end of history */ void fetch_hist_item(ChatContext *ctx, int key_dir); + +#endif /* #define _toxic_strings_h */ diff --git a/src/windows.c b/src/windows.c index ce2cd06..e1f93f4 100644 --- a/src/windows.c +++ b/src/windows.c @@ -30,7 +30,8 @@ #include "friendlist.h" #include "prompt.h" -#include "toxic_windows.h" +#include "toxic.h" +#include "windows.h" #include "groupchat.h" extern char *DATA_FILE; diff --git a/src/windows.h b/src/windows.h new file mode 100644 index 0000000..99aa74f --- /dev/null +++ b/src/windows.h @@ -0,0 +1,180 @@ +/* windows.h + * + * + * Copyright (C) 2014 Toxic All Rights Reserved. + * + * This file is part of Toxic. + * + * Toxic 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. + * + * Toxic 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 Toxic. If not, see . + * + */ + +#ifndef _windows_h +#define _windows_h + +#include +#include +#include + +#include + +#ifdef _SUPPORT_AUDIO +#include +#endif /* _SUPPORT_AUDIO */ + +#include "toxic.h" + +#define MAX_WINDOWS_NUM 32 +#define CURS_Y_OFFSET 3 /* y-axis cursor offset for chat contexts */ +#define CHATBOX_HEIGHT 4 + +/* Curses foreground colours (background is black) */ +enum { + WHITE, + GREEN, + CYAN, + RED, + BLUE, + YELLOW, + MAGENTA, + BLACK, +} C_COLOURS; + +/* tab alert types: lower types take priority */ +enum { + WINDOW_ALERT_0, + WINDOW_ALERT_1, + WINDOW_ALERT_2, +} WINDOW_ALERTS; + +/* Fixes text color problem on some terminals. + Uncomment if necessary */ +/* #define URXVT_FIX */ + +struct _Winthread { + pthread_t tid; + pthread_mutex_t lock; +}; + +typedef struct ToxWindow ToxWindow; +typedef struct StatusBar StatusBar; +typedef struct PromptBuf PromptBuf; +typedef struct ChatContext ChatContext; + +struct ToxWindow { + void(*onKey)(ToxWindow *, Tox *, wint_t, bool); + void(*onDraw)(ToxWindow *, Tox *); + void(*onInit)(ToxWindow *, Tox *); + void(*onFriendRequest)(ToxWindow *, Tox *, uint8_t *, uint8_t *, uint16_t); + void(*onFriendAdded)(ToxWindow *, Tox *, int32_t, bool); + void(*onConnectionChange)(ToxWindow *, Tox *, int32_t, uint8_t); + void(*onMessage)(ToxWindow *, Tox *, int32_t, uint8_t *, uint16_t); + void(*onNickChange)(ToxWindow *, Tox *, int32_t, uint8_t *, uint16_t); + void(*onStatusChange)(ToxWindow *, Tox *, int32_t, uint8_t); + void(*onStatusMessageChange)(ToxWindow *, int32_t, uint8_t *, uint16_t); + void(*onAction)(ToxWindow *, Tox *, int32_t, uint8_t *, uint16_t); + void(*onGroupMessage)(ToxWindow *, Tox *, int, int, uint8_t *, uint16_t); + void(*onGroupAction)(ToxWindow *, Tox *, int, int, uint8_t *, uint16_t); + void(*onGroupInvite)(ToxWindow *, Tox *, int32_t, uint8_t *); + void(*onGroupNamelistChange)(ToxWindow *, Tox *, int, int, uint8_t); + void(*onFileSendRequest)(ToxWindow *, Tox *, int32_t, uint8_t, uint64_t, uint8_t *, uint16_t); + void(*onFileControl)(ToxWindow *, Tox *, int32_t, uint8_t, uint8_t, uint8_t, uint8_t *, uint16_t); + void(*onFileData)(ToxWindow *, Tox *, int32_t, uint8_t, uint8_t *, uint16_t); + void(*onTypingChange)(ToxWindow *, Tox *, int32_t, uint8_t); + +#ifdef _SUPPORT_AUDIO + + void(*onInvite)(ToxWindow *, ToxAv *, int); + void(*onRinging)(ToxWindow *, ToxAv *, int); + void(*onStarting)(ToxWindow *, ToxAv *, int); + void(*onEnding)(ToxWindow *, ToxAv *, int); + void(*onError)(ToxWindow *, ToxAv *, int); + void(*onStart)(ToxWindow *, ToxAv *, int); + void(*onCancel)(ToxWindow *, ToxAv *, int); + void(*onReject)(ToxWindow *, ToxAv *, int); + void(*onEnd)(ToxWindow *, ToxAv *, int); + void(*onRequestTimeout)(ToxWindow *, ToxAv *, int); + void(*onPeerTimeout)(ToxWindow *, ToxAv *, int); + + int call_index; /* If in a call will have this index set, otherwise it's -1. + * Don't modify outside av callbacks. */ +#endif /* _SUPPORT_AUDIO */ + + char name[TOX_MAX_NAME_LENGTH]; + int32_t num; /* corresponds to friendnumber in chat windows */ + bool active; + int x; + + /* window type identifiers */ + bool is_chat; + bool is_groupchat; + bool is_prompt; + + bool alert0; + bool alert1; + bool alert2; + + ChatContext *chatwin; + StatusBar *stb; + + WINDOW *popup; + WINDOW *window; +}; + +/* statusbar info holder */ +struct StatusBar { + WINDOW *topline; + uint8_t statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH]; + uint16_t statusmsg_len; + uint8_t nick[TOX_MAX_NAME_LENGTH]; + uint16_t nick_len; + uint8_t status; + bool is_online; +}; + +#define MAX_LINE_HIST 128 + +/* chat and groupchat window/buffer holder */ +struct ChatContext { + wchar_t line[MAX_STR_SIZE]; + size_t pos; + size_t len; + + wchar_t ln_history[MAX_LINE_HIST][MAX_STR_SIZE]; /* history for input lines/commands */ + int hst_pos; + int hst_tot; + + struct history *hst; + struct chatlog *log; + + uint8_t self_is_typing; + + WINDOW *history; + WINDOW *linewin; + WINDOW *sidebar; + + /* specific for prompt */ + bool at_bottom; /* true if line end is at bottom of window */ + int orig_y; /* y axis point of line origin */ +}; + +ToxWindow *init_windows(Tox *m); +void draw_active_window(Tox *m); +int add_window(Tox *m, ToxWindow w); +void del_window(ToxWindow *w); +void set_active_window(int ch); +int get_num_active_windows(void); +void kill_all_windows(void); /* should only be called on shutdown */ + +#endif /* #define _windows_h */