diff --git a/INSTALL.md b/INSTALL.md index 12d9749..15f96cc 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -16,6 +16,7 @@ | [LibConfig](http://www.hyperrealm.com/libconfig) | BASE | libconfig-dev | | [GNUmake](https://www.gnu.org/software/make) | BASE | make | | [libcurl](http://curl.haxx.se/) | BASE | libcurl4-openssl-dev| +| [libqrencode](https://fukuchi.org/works/qrencode/) | BASE | libqrencode-dev | | [Tox Core AV](https://github.com/irungentoo/toxcore) | AUDIO | *None* | | [OpenAL](http://openal.org) | AUDIO, SOUND NOTIFICATIONS | libopenal-dev | | [OpenALUT](http://openal.org) | SOUND NOTIFICATIONS | libalut-dev | diff --git a/Makefile b/Makefile index 3f73cdb..6781c60 100644 --- a/Makefile +++ b/Makefile @@ -3,9 +3,9 @@ CFG_DIR = $(BASE_DIR)/cfg -include $(CFG_DIR)/global_vars.mk -LIBS = libtoxcore ncursesw libconfig +LIBS = libtoxcore ncursesw libconfig libqrencode -CFLAGS = -std=gnu99 -pthread -Wall -g +CFLAGS = -std=gnu99 -pthread -Wall -g -fstack-protector-all CFLAGS += '-DTOXICVER="$(VERSION)"' -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED -D_FILE_OFFSET_BITS=64 CFLAGS += '-DPACKAGE_DATADIR="$(abspath $(DATADIR))"' CFLAGS += $(USER_CFLAGS) @@ -14,7 +14,7 @@ LDFLAGS = $(USER_LDFLAGS) OBJ = chat.o chat_commands.o configdir.o execute.o file_transfers.o notify.o OBJ += friendlist.o global_commands.o groupchat.o line_info.o input.o help.o autocomplete.o OBJ += log.o misc_tools.o prompt.o settings.o toxic.o toxic_strings.o windows.o message_queue.o -OBJ += group_commands.o term_mplex.o avatars.o name_lookup.o +OBJ += group_commands.o term_mplex.o avatars.o name_lookup.o qr_code.o # Check on wich system we are running UNAME_S = $(shell uname -s) @@ -24,6 +24,9 @@ endif ifeq ($(UNAME_S), FreeBSD) -include $(CFG_DIR)/systems/FreeBSD.mk endif +ifeq ($(UNAME_S), DragonFly) + -include $(CFG_DIR)/systems/FreeBSD.mk +endif ifeq ($(UNAME_S), OpenBSD) -include $(CFG_DIR)/systems/FreeBSD.mk endif diff --git a/README.md b/README.md index fa8c703..252716d 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ + + Coverity Scan Build Status + + Toxic is a [Tox](https://tox.im)-based instant messenging client which formerly resided in the [Tox core repository](https://github.com/irungentoo/toxcore), and is now available as a standalone application. [![Toxic Screenshot](https://i.imgur.com/san99Z2.png "Home Screen")](https://i.imgur.com/san99Z2.png) diff --git a/src/audio_call.c b/src/audio_call.c index 5dc72d5..0b7ce4b 100644 --- a/src/audio_call.c +++ b/src/audio_call.c @@ -169,8 +169,9 @@ void terminate_audio() void read_device_callback(const int16_t* captured, uint32_t size, void* data) { TOXAV_ERR_SEND_FRAME error; - uint32_t friend_number = *((uint32_t*)data); /* TODO: Or pass an array of call_idx's */ - int64_t sample_count = CallControl.audio_sample_rate * CallControl.audio_frame_duration / 1000; + uint32_t friend_number = *((uint32_t *)data); /* TODO: Or pass an array of call_idx's */ + int64_t sample_count = ((int64_t) CallControl.audio_sample_rate) * \ + ((int64_t) CallControl.audio_frame_duration) / 1000; if ( sample_count <= 0 || toxav_audio_send_frame(CallControl.av, friend_number, captured, sample_count, diff --git a/src/autocomplete.c b/src/autocomplete.c index 6bc3c6a..d3ea7a4 100644 --- a/src/autocomplete.c +++ b/src/autocomplete.c @@ -114,7 +114,7 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size) tmp[ctx->pos] = '\0'; const char *s = dir_search ? strchr(tmp, '\"') : strrchr(tmp, ' '); - char *sub = malloc(strlen(ubuf) + 1); + char *sub = calloc(1, strlen(ubuf) + 1); if (sub == NULL) exit_toxic_err("failed in complete_line", FATALERR_MEMORY); @@ -142,14 +142,14 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size) } int s_len = strlen(sub); - const char *str; int n_matches = 0; char matches[n_items][MAX_STR_SIZE]; int i = 0; /* put all list matches in matches array */ for (i = 0; i < n_items; ++i) { - str = &L[i * size]; + char str[MAX_CMDNAME_SIZE + 1]; + snprintf(str, sizeof(str), "%s", &L[i * size]); if (strncasecmp(str, sub, s_len) == 0) strcpy(matches[n_matches++], str); @@ -165,10 +165,11 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size) char match[MAX_STR_SIZE]; get_str_match(self, match, matches, n_matches); + size_t match_len = strlen(match); if (dir_search) { if (n_matches == 1) - endchrs = char_rfind(match, '.', strlen(match)) ? "\"" : "/"; + endchrs = char_rfind(match, '.', match_len) ? "\"" : "/"; else endchrs = ""; } else if (n_matches > 1) { @@ -177,18 +178,21 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size) /* put match in correct spot in buf and append endchars */ int n_endchrs = strlen(endchrs); - int m_len = strlen(match); int strt = ctx->pos - s_len; - int diff = m_len - s_len + n_endchrs; + int diff = match_len - s_len + n_endchrs; if (ctx->len + diff >= MAX_STR_SIZE) return -1; char tmpend[MAX_STR_SIZE]; snprintf(tmpend, sizeof(tmpend), "%s", &ubuf[ctx->pos]); + + if (match_len + n_endchrs + strlen(tmpend) >= sizeof(ubuf)) + return -1; + strcpy(&ubuf[strt], match); - strcpy(&ubuf[strt + m_len], endchrs); - strcpy(&ubuf[strt + m_len + n_endchrs], tmpend); + strcpy(&ubuf[strt + match_len], endchrs); + strcpy(&ubuf[strt + match_len + n_endchrs], tmpend); /* convert to widechar and copy back to original buf */ wchar_t newbuf[MAX_STR_SIZE]; diff --git a/src/chat.c b/src/chat.c index 194faaf..863e828 100644 --- a/src/chat.c +++ b/src/chat.c @@ -63,9 +63,9 @@ static void kill_infobox(ToxWindow *self); #endif /* AUDIO */ #ifdef AUDIO -#define AC_NUM_CHAT_COMMANDS 29 +#define AC_NUM_CHAT_COMMANDS 30 #else -#define AC_NUM_CHAT_COMMANDS 22 +#define AC_NUM_CHAT_COMMANDS 23 #endif /* AUDIO */ /* Array of chat command names used for tab completion. */ @@ -85,6 +85,7 @@ static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = { { "/join" }, { "/log" }, { "/myid" }, + { "/myqr" }, { "/nick" }, { "/note" }, { "/nospam" }, @@ -789,6 +790,10 @@ static void init_infobox(ToxWindow *self) int x2, y2; getmaxyx(self->window, y2, x2); + + if (y2 <= 0 || x2 <= 0) + return; + (void) y2; memset(&ctx->infobox, 0, sizeof(struct infobox)); @@ -895,7 +900,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) getyx(self->window, y, x); getmaxyx(self->window, y2, x2); - if (x2 <= 0) + if (y2 <= 0 || x2 <= 0) return; if (self->help->active) { @@ -993,6 +998,9 @@ static void chat_onDraw(ToxWindow *self, Tox *m) int x2, y2; getmaxyx(self->window, y2, x2); + if (y2 <= 0 || x2 <= 0) + return; + ChatContext *ctx = self->chatwin; pthread_mutex_lock(&Winthread.lock); @@ -1117,6 +1125,10 @@ static void chat_onInit(ToxWindow *self, Tox *m) curs_set(1); int x2, y2; getmaxyx(self->window, y2, x2); + + if (y2 <= 0 || x2 <= 0) + exit_toxic_err("failed in chat_onInit", FATALERR_CURSES); + self->x = x2; /* Init statusbar info */ diff --git a/src/configdir.c b/src/configdir.c index 8a9f60c..db63b6f 100644 --- a/src/configdir.c +++ b/src/configdir.c @@ -31,6 +31,7 @@ #include "toxic.h" #include "configdir.h" +#include "misc_tools.h" /* get the user's home directory */ void get_home_dir(char *home, int size) @@ -69,8 +70,8 @@ char *get_user_config_dir(void) char home[NSS_BUFLEN_PASSWD] = {0}; get_home_dir(home, sizeof(home)); - char *user_config_dir; - size_t len; + char *user_config_dir = NULL; + size_t len = 0; # if defined(__APPLE__) len = strlen(home) + strlen("/Library/Application Support") + 1; @@ -82,9 +83,9 @@ char *get_user_config_dir(void) snprintf(user_config_dir, len, "%s/Library/Application Support", home); # else /* __APPLE__ */ - const char *tmp; + const char *tmp = getenv("XDG_CONFIG_HOME"); - if (!(tmp = getenv("XDG_CONFIG_HOME"))) { + if (tmp == NULL) { len = strlen(home) + strlen("/.config") + 1; user_config_dir = malloc(len); @@ -98,6 +99,11 @@ char *get_user_config_dir(void) # endif /* __APPLE__ */ + if (!file_exists(user_config_dir)) { + free(user_config_dir); + return NULL; + } + return user_config_dir; } diff --git a/src/execute.c b/src/execute.c index 86c6ddd..64481ca 100644 --- a/src/execute.c +++ b/src/execute.c @@ -54,6 +54,7 @@ static struct cmd_func global_commands[] = { { "/join", cmd_join }, { "/log", cmd_log }, { "/myid", cmd_myid }, + { "/myqr", cmd_myqr }, { "/nick", cmd_nick }, { "/note", cmd_note }, { "/nospam", cmd_nospam }, diff --git a/src/friendlist.c b/src/friendlist.c index 84268ef..85411b9 100644 --- a/src/friendlist.c +++ b/src/friendlist.c @@ -26,7 +26,6 @@ #include #include #include -#include #include @@ -125,7 +124,13 @@ void kill_friendlist(void) realloc_friends(0); } -#define TEMP_BLOCKLIST_SAVE_NAME "toxic_blocklist.tmp" +/* Saves the blocklist to path. If there are no items in the blocklist the + * empty file will be removed. + * + * Returns 0 if stored successfully. + * Returns -1 on failure. + */ +#define TEMP_BLOCKLIST_EXT ".tmp" static int save_blocklist(char *path) { if (path == NULL) @@ -165,19 +170,23 @@ static int save_blocklist(char *path) return 0; } - FILE *fp = fopen(TEMP_BLOCKLIST_SAVE_NAME, "wb"); + char temp_path[strlen(path) + strlen(TEMP_BLOCKLIST_EXT) + 1]; + snprintf(temp_path, sizeof(temp_path), "%s%s", path, TEMP_BLOCKLIST_EXT); + + FILE *fp = fopen(temp_path, "wb"); if (fp == NULL) return -1; if (fwrite(data, len, 1, fp) != 1) { + fprintf(stderr, "Failed to write blocklist data.\n"); fclose(fp); return -1; } fclose(fp); - if (rename(TEMP_BLOCKLIST_SAVE_NAME, path) != 0) + if (rename(temp_path, path) != 0) return -1; return 0; @@ -228,7 +237,7 @@ int load_blocklist(char *path) memcpy(&tmp, data + i * sizeof(BlockedFriend), sizeof(BlockedFriend)); Blocked.list[i].active = true; Blocked.list[i].num = i; - Blocked.list[i].namelength = ntohs(tmp.namelength); + Blocked.list[i].namelength = MIN(TOXIC_MAX_NAME_LENGTH, ntohs(tmp.namelength)); memcpy(Blocked.list[i].name, tmp.name, Blocked.list[i].namelength + 1); memcpy(Blocked.list[i].pub_key, tmp.pub_key, TOX_PUBLIC_KEY_SIZE); diff --git a/src/global_commands.c b/src/global_commands.c index be6510f..5a8b91c 100644 --- a/src/global_commands.c +++ b/src/global_commands.c @@ -22,7 +22,6 @@ #include #include -#include #include "toxic.h" #include "windows.h" @@ -36,6 +35,7 @@ #include "term_mplex.h" #include "avatars.h" #include "name_lookup.h" +#include "qr_code.h" extern char *DATA_FILE; extern ToxWindow *prompt; @@ -493,19 +493,57 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) { - char id[TOX_ADDRESS_SIZE * 2 + 1] = {0}; - char address[TOX_ADDRESS_SIZE]; - tox_self_get_address(m, (uint8_t *) address); + char id_string[TOX_ADDRESS_SIZE * 2 + 1]; + char bin_id[TOX_ADDRESS_SIZE]; + tox_self_get_address(m, (uint8_t *) bin_id); - size_t i; - - for (i = 0; i < TOX_ADDRESS_SIZE; ++i) { - char d[3]; - snprintf(d, sizeof(d), "%02X", address[i] & 0xff); - strcat(id, d); + if (bin_id_to_string(bin_id, sizeof(bin_id), id_string, sizeof(id_string)) == -1) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to print ID."); + return; } - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", id); + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", id_string); +} + +void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) +{ + char id_string[TOX_ADDRESS_SIZE * 2 + 1]; + char bin_id[TOX_ADDRESS_SIZE]; + tox_self_get_address(m, (uint8_t *) bin_id); + + if (bin_id_to_string(bin_id, sizeof(bin_id), id_string, sizeof(id_string)) == -1) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code."); + return; + } + + char nick[TOX_MAX_NAME_LENGTH]; + tox_self_get_name(m, (uint8_t *) nick); + size_t nick_len = tox_self_get_name_size(m); + nick[nick_len] = '\0'; + + size_t data_file_len = strlen(DATA_FILE); + char dir[data_file_len]; + size_t dir_len = get_base_dir(DATA_FILE, data_file_len, dir); + + char qr_path[dir_len + nick_len + strlen(QRCODE_FILENAME_EXT) + 1]; + snprintf(qr_path, sizeof(qr_path), "%s%s%s", dir, nick, QRCODE_FILENAME_EXT); + + FILE *output = fopen(qr_path, "wb"); + + if (output == NULL) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code."); + return; + } + + if (ID_to_QRcode(id_string, output) == -1) { + fclose(output); + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code."); + return; + } + + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path); + + fclose(output); } void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) diff --git a/src/global_commands.h b/src/global_commands.h index 89236e9..94fe6e2 100644 --- a/src/global_commands.h +++ b/src/global_commands.h @@ -36,6 +36,7 @@ void cmd_groupchat(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_ void cmd_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_log(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_myid(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); +void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_nick(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_note(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]); void cmd_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); diff --git a/src/groupchat.c b/src/groupchat.c index d4233de..9036cc6 100644 --- a/src/groupchat.c +++ b/src/groupchat.c @@ -70,9 +70,9 @@ extern struct user_settings *user_settings; extern struct Winthread Winthread; #ifdef AUDIO -#define AC_NUM_GROUP_COMMANDS 41 +#define AC_NUM_GROUP_COMMANDS 42 #else -#define AC_NUM_GROUP_COMMANDS 37 +#define AC_NUM_GROUP_COMMANDS 38 #endif /* AUDIO */ /* groupchat command names used for tab completion. */ @@ -96,6 +96,7 @@ static const char group_cmd_list[AC_NUM_GROUP_COMMANDS][MAX_CMDNAME_SIZE] = { { "/mod" }, { "/myid" }, { "/mykey" }, + { "/myqr" }, { "/nick" }, { "/note" }, { "/passwd" }, @@ -402,6 +403,9 @@ void redraw_groupchat_win(ToxWindow *self) getmaxyx(stdscr, y2, x2); y2 -= 2; + if (y2 <= 0 || x2 <= 0) + return; + if (ctx->sidebar) { delwin(ctx->sidebar); ctx->sidebar = NULL; @@ -1055,7 +1059,7 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) getyx(self->window, y, x); getmaxyx(self->window, y2, x2); - if (x2 <= 0) + if (x2 <= 0 || y2 <= 0) return; if (self->help->active) { @@ -1148,6 +1152,9 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m) int x2, y2; getmaxyx(self->window, y2, x2); + if (x2 <= 0 || y2 <= 0) + return; + ChatContext *ctx = self->chatwin; GroupChat *chat = &groupchats[self->num]; @@ -1250,6 +1257,9 @@ static void groupchat_onInit(ToxWindow *self, Tox *m) int x2, y2; getmaxyx(self->window, y2, x2); + if (x2 <= 0 || y2 <= 0) + exit_toxic_err("failed in groupchat_onInit", FATALERR_CURSES); + ChatContext *ctx = self->chatwin; ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2 - SIDEBAR_WIDTH - 1, 0, 0); diff --git a/src/help.c b/src/help.c index eaffe6b..bd392cd 100644 --- a/src/help.c +++ b/src/help.c @@ -60,6 +60,9 @@ static void help_init_window(ToxWindow *self, int height, int width) int y2, x2; getmaxyx(stdscr, y2, x2); + if (y2 <= 0 || x2 <= 0) + return; + height = MIN(height, y2); width = MIN(width, x2); @@ -156,6 +159,7 @@ static void help_draw_global(ToxWindow *self) wprintw(win, " /nospam : Change part of your Tox ID to stop spam\n"); wprintw(win, " /log or : Enable/disable logging\n"); wprintw(win, " /myid : Print your Tox ID\n"); + wprintw(win, " /myqr : Print your Tox ID's QR code to a file.\n"); wprintw(win, " /clear : Clear window history\n"); wprintw(win, " /close : Close the current chat window\n"); wprintw(win, " /quit or /exit : Exit Toxic\n"); @@ -329,7 +333,7 @@ void help_onKey(ToxWindow *self, wint_t key) #elif AUDIO help_init_window(self, 18, 80); #else - help_init_window(self, 9, 80); + help_init_window(self, 10, 80); #endif self->help->type = HELP_CHAT; break; diff --git a/src/misc_tools.c b/src/misc_tools.c index c0bb248..9610057 100644 --- a/src/misc_tools.c +++ b/src/misc_tools.c @@ -167,6 +167,24 @@ int hex_string_to_bytes(char *buf, int size, const char *keystr) return 0; } +/* Converts a binary representation of a Tox ID into a string. + * + * Returns 0 on success. + * Returns -1 on failure. + */ +int bin_id_to_string(const char *bin_id, size_t bin_id_size, char *output, size_t output_size) +{ + if (bin_id_size != TOX_ADDRESS_SIZE || output_size < (TOX_ADDRESS_SIZE * 2 + 1)) + return -1; + + size_t i; + + for (i = 0; i < TOX_ADDRESS_SIZE; ++i) + snprintf(&output[i*2], output_size - (i * 2), "%02X", bin_id[i] & 0xff); + + return 0; +} + /* Returns 1 if the string is empty, 0 otherwise */ int string_is_empty(const char *string) { @@ -281,6 +299,24 @@ size_t get_file_name(char *namebuf, size_t bufsize, const char *pathname) return strlen(namebuf); } +/* Gets the base directory of path and puts it in dir. + * dir must have at least as much space as path_len. + * + * Returns the length of the base directory. + */ +size_t get_base_dir(const char *path, size_t path_len, char *dir) +{ + size_t dir_len = char_rfind(path, '/', path_len); + + if (dir_len != 0 && dir_len < path_len) + ++dir_len; /* Leave trailing slash */ + + memcpy(dir, path, dir_len); + dir[dir_len] = '\0'; + + return dir_len; +} + /* converts str to all lowercase */ void str_to_lower(char *str) { @@ -363,8 +399,8 @@ int char_find(int idx, const char *s, char ch) return i; } -/* returns index of the last instance of ch in s starting at len - returns 0 if char not found (skips 0th index) */ +/* returns index of the last instance of ch in s starting at len. + returns 0 if char not found (skips 0th index). */ int char_rfind(const char *s, char ch, int len) { int i = 0; diff --git a/src/misc_tools.h b/src/misc_tools.h index 312dc1b..d4c22f7 100644 --- a/src/misc_tools.h +++ b/src/misc_tools.h @@ -53,6 +53,13 @@ int hex_string_to_bin(const char *hex_string, size_t hex_len, char *output, size /* convert a hex string to bytes. returns 0 on success, -1 on failure */ int hex_string_to_bytes(char *buf, int size, const char *keystr); +/* Converts a binary representation of a Tox ID into a string. + * + * Returns 0 on success. + * Returns -1 on failure. + */ +int bin_id_to_string(const char *bin_id, size_t bin_id_size, char *output, size_t output_size); + /* get the current unix time (not thread safe) */ uint64_t get_unix_time(void); @@ -106,6 +113,14 @@ void filter_str(char *str, size_t len); /* gets base file name from path or original file name if no path is supplied */ size_t get_file_name(char *namebuf, size_t bufsize, const char *pathname); +/* Gets the base directory of path and puts it in dir. + * dir must have at least as much space as path_len. + * + * Returns the length of the base directory on success. + * Returns -1 on failure. + */ +size_t get_base_dir(const char *path, size_t path_len, char *dir); + /* converts str to all lowercase */ void str_to_lower(char *str); diff --git a/src/name_lookup.c b/src/name_lookup.c index 464e206..fad4c9e 100644 --- a/src/name_lookup.c +++ b/src/name_lookup.c @@ -202,12 +202,12 @@ size_t write_lookup_data(void *data, size_t size, size_t nmemb, void *user_point struct Recv_Data *recv_data = (struct Recv_Data *) user_pointer; size_t real_size = size * nmemb; - if (real_size > MAX_RECV_LOOKUP_DATA_SIZE) + if (real_size >= MAX_RECV_LOOKUP_DATA_SIZE) return 0; memcpy(&recv_data->data, data, real_size); recv_data->size = real_size; - recv_data->data[real_size] = 0; + recv_data->data[real_size] = '\0'; return real_size; } diff --git a/src/prompt.c b/src/prompt.c index e22eddc..b349143 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -50,11 +50,11 @@ extern struct Winthread Winthread; extern FriendsList Friends; FriendRequests FrndRequests; #ifdef VIDEO -#define AC_NUM_GLOB_COMMANDS 22 +#define AC_NUM_GLOB_COMMANDS 23 #elif AUDIO -#define AC_NUM_GLOB_COMMANDS 20 +#define AC_NUM_GLOB_COMMANDS 21 #else -#define AC_NUM_GLOB_COMMANDS 18 +#define AC_NUM_GLOB_COMMANDS 19 #endif /* Array of global command names used for tab completion. */ @@ -71,6 +71,7 @@ static const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = { { "/join" }, { "/log" }, { "/myid" }, + { "/myqr" }, { "/nick" }, { "/note" }, { "/nospam" }, @@ -186,7 +187,7 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) getyx(self->window, y, x); getmaxyx(self->window, y2, x2); - if (x2 <= 0) + if (x2 <= 0 || y2 <= 0) return; /* ignore non-menu related input if active */ @@ -257,6 +258,9 @@ static void prompt_onDraw(ToxWindow *self, Tox *m) int x2, y2; getmaxyx(self->window, y2, x2); + if (y2 <= 0 || x2 <= 0) + return; + ChatContext *ctx = self->chatwin; pthread_mutex_lock(&Winthread.lock); @@ -432,6 +436,10 @@ void prompt_init_statusbar(ToxWindow *self, Tox *m) { int x2, y2; getmaxyx(self->window, y2, x2); + + if (y2 <= 0 || x2 <= 0) + exit_toxic_err("failed in prompt_init_statusbar", FATALERR_CURSES); + (void) y2; /* Init statusbar info */ @@ -489,6 +497,9 @@ static void prompt_onInit(ToxWindow *self, Tox *m) int y2, x2; getmaxyx(self->window, y2, x2); + if (y2 <= 0 || x2 <= 0) + exit_toxic_err("failed in prompt_onInit", FATALERR_CURSES); + ChatContext *ctx = self->chatwin; ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0); ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0); diff --git a/src/qr_code.c b/src/qr_code.c new file mode 100644 index 0000000..1341126 --- /dev/null +++ b/src/qr_code.c @@ -0,0 +1,89 @@ +/* qr_obj_code.c + * + * + * Copyright (C) 2015 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 . + * + */ + +#include +#include +#include + +#include "toxic.h" +#include "windows.h" +#include "qr_code.h" + +#define BORDER_LEN 1 +#define CHAR_1 "\342\226\210" +#define CHAR_2 "\342\226\204" +#define CHAR_3 "\342\226\200" + +/* Converts a tox ID string into a QRcode and prints it to the given file stream. + * + * Returns 0 on success. + * Returns -1 on failure. + */ +int ID_to_QRcode(const char *tox_id, FILE *fp) +{ + if (fp == NULL) + return -1; + + QRcode *qr_obj = QRcode_encodeString(tox_id, 0, QR_ECLEVEL_L, QR_MODE_8, 0); + + if (qr_obj == NULL) + return -1; + + size_t width = qr_obj->width; + size_t i, j; + + for (i = 0; i < width + BORDER_LEN * 2; ++i) + fprintf(fp, "%s", CHAR_1); + + fprintf(fp, "\n"); + + for (i = 0; i < width; i += 2) { + for (j = 0; j < BORDER_LEN; ++j) + fprintf(fp, "%s", CHAR_1); + + const unsigned char *row_1 = qr_obj->data + width * i; + const unsigned char *row_2 = row_1 + width; + + for (j = 0; j < width; ++j) { + bool x = row_1[j] & 1; + bool y = (i + 1) < width ? (row_2[j] & 1) : false; + + if (x && y) + fprintf(fp, " "); + else if (x) + fprintf(fp, "%s", CHAR_2); + else if (y) + fprintf(fp, "%s", CHAR_3); + else + fprintf(fp, "%s", CHAR_1); + } + + for (j = 0; j < BORDER_LEN; ++j) + fprintf(fp, "%s", CHAR_1); + + fprintf(fp, "\n"); + } + + QRcode_free(qr_obj); + + return 0; +} diff --git a/src/qr_code.h b/src/qr_code.h new file mode 100644 index 0000000..eb94ddf --- /dev/null +++ b/src/qr_code.h @@ -0,0 +1,35 @@ +/* qr_code.h + * + * + * Copyright (C) 2015 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 QR_CODE +#define QR_CODE + +#define QRCODE_FILENAME_EXT ".QRcode" + +/* Converts a tox ID string into a QRcode and prints it to the given file stream. + * + * Returns 0 on success. + * Returns -1 on failure. + */ +int ID_to_QRcode(const char *tox_id, FILE *fp); + +#endif /* QR_CODE */ diff --git a/src/toxic.c b/src/toxic.c index cb42c28..29c1b31 100644 --- a/src/toxic.c +++ b/src/toxic.c @@ -549,18 +549,21 @@ static void first_time_encrypt(const char *msg) system("clear"); } -/* Store Tox profile data to given location +/* Store Tox profile data to path. * * Return 0 if stored successfully. * Return -1 on error. */ -#define TEMP_PROFILE_SAVE_NAME "toxic_profile.tmp" +#define TEMP_PROFILE_EXT ".tmp" int store_data(Tox *m, const char *path) { if (path == NULL) return -1; - FILE *fp = fopen(TEMP_PROFILE_SAVE_NAME, "wb"); + char temp_path[strlen(path) + strlen(TEMP_PROFILE_EXT) + 1]; + snprintf(temp_path, sizeof(temp_path), "%s%s", path, TEMP_PROFILE_EXT); + + FILE *fp = fopen(temp_path, "wb"); if (fp == NULL) return -1; @@ -585,11 +588,13 @@ int store_data(Tox *m, const char *path) } if (fwrite(enc_data, enc_len, 1, fp) != 1) { + fprintf(stderr, "Failed to write profile data.\n"); fclose(fp); return -1; } } else { /* data will not be encrypted */ if (fwrite(data, data_len, 1, fp) != 1) { + fprintf(stderr, "Failed to write profile data.\n"); fclose(fp); return -1; } @@ -597,7 +602,7 @@ int store_data(Tox *m, const char *path) fclose(fp); - if (rename(TEMP_PROFILE_SAVE_NAME, path) != 0) + if (rename(temp_path, path) != 0) return -1; return 0; diff --git a/src/toxic.h b/src/toxic.h index ee61197..1111aae 100644 --- a/src/toxic.h +++ b/src/toxic.h @@ -88,6 +88,7 @@ typedef enum _FATAL_ERRS { FATALERR_PROXY = -10, /* Tox network failed to init using a proxy */ FATALERR_ENCRYPT = -11, /* Data file encryption failure */ FATALERR_TOX_INIT = -12, /* Tox instance failed to initialize */ + FATALERR_CURSES = -13, /* Unrecoverable Ncurses error */ } FATAL_ERRS; /* Fixes text color problem on some terminals. diff --git a/src/video_call.c b/src/video_call.c index 950cf55..95da741 100644 --- a/src/video_call.c +++ b/src/video_call.c @@ -153,9 +153,10 @@ int stop_video_transmission(Call *call, int friend_number) CallControl.video_bit_rate = 0; toxav_bit_rate_set(CallControl.av, friend_number, -1, CallControl.video_bit_rate, NULL); - if ( call->vin_idx != -1 ) + if ( call->vin_idx != -1 ) { close_video_device(vdt_input, call->vin_idx); call->vin_idx = -1; + } return 0; } @@ -190,12 +191,12 @@ void callback_recv_video_starting(uint32_t friend_number) { return; - Call* this_call = &CallControl.calls[friend_number]; + // Call* this_call = &CallControl.calls[friend_number]; - if ( this_call->vout_idx != -1 ) - return; + // if ( this_call->vout_idx != -1 ) + // return; - open_primary_video_device(vdt_output, &this_call->vout_idx); + // open_primary_video_device(vdt_output, &this_call->vout_idx); } void callback_recv_video_end(uint32_t friend_number) { @@ -243,37 +244,37 @@ void cmd_video(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[M { return; // TODO: Fix video - const char *error_str; - Call* this_call = &CallControl.calls[self->num]; +// const char *error_str; +// Call* this_call = &CallControl.calls[self->num]; - if ( argc != 0 ) { - error_str = "Unknown arguments."; - goto on_error; - } +// if ( argc != 0 ) { +// error_str = "Unknown arguments."; +// goto on_error; +// } - if ( !CallControl.av ) { - error_str = "ToxAV not supported!"; - goto on_error; - } +// if ( !CallControl.av ) { +// error_str = "ToxAV not supported!"; +// goto on_error; +// } - if ( !self->stb->connection ) { - error_str = "Friend is offline."; - goto on_error; - } +// if ( !self->stb->connection ) { +// error_str = "Friend is offline."; +// goto on_error; +// } - if ( !self->is_call ) { - error_str = "Not in call!"; - goto on_error; - } +// if ( !self->is_call ) { +// error_str = "Not in call!"; +// goto on_error; +// } - if ( this_call->vin_idx == -1 ) - callback_video_starting(self->num); - else - callback_video_end(self->num); +// if ( this_call->vin_idx == -1 ) +// callback_video_starting(self->num); +// else +// callback_video_end(self->num); - return; -on_error: - print_err (self, error_str); +// return; +// on_error: +// print_err (self, error_str); } void cmd_list_video_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) diff --git a/src/windows.c b/src/windows.c index 2eacf8e..69994db 100644 --- a/src/windows.c +++ b/src/windows.c @@ -505,6 +505,9 @@ void on_window_resize(void) getmaxyx(stdscr, y2, x2); y2 -= 2; + if (y2 <= 0 || x2 <= 0) + return; + size_t i; for (i = 0; i < MAX_WINDOWS_NUM; ++i) {