diff --git a/README.md b/README.md
index 2afa965..3318693 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,21 @@
-## Toxic - console client for [Tox](http://tox.im)
+# Toxic
-The client formerly resided in the [Tox core repository](https://github.com/irungentoo/ProjectTox-Core) and is now available as a standalone program. It looks like [this](http://wiki.tox.im/images/b/b6/Ncursesclient1.png).
+Toxic is an ncurses based instant messaging client for [Tox](http://tox.im) which formerly resided in the [Tox core repository](https://github.com/irungentoo/ProjectTox-Core) and is now available as a standalone program. It looks like [this](http://i.imgur.com/hL7WhVl.png).
+## Installation
+* Generate the configure script by running the ```autoreconf -i``` command.
-To compile, first generate the configure script by running the ```autoreconf -i``` command.
+* Execute the configure script with ```./configure``` (you may need to pass it the location of your dependency libraries, i.e.):
+```./configure --prefix=/where/to/install --with-libtoxcore-headers=/path/to/ProjectTox-Core/toxcore --with-libtoxcore-libs=/path/to/ProjectTox-Core/build/toxcore --with-libsodium-headers=/path/to/libsodium/include/ --with-libsodium-libs=/path/to/sodiumtest/lib/ ```
-Then execute the configure script with ./configure (you may need to pass it the location of your dependency libraries, i.e.):
-```
-./configure --prefix=/where/to/install --with-libtoxcore-headers=/path/to/ProjectTox-Core/core --with-libtoxcore-libs=/path/to/ProjectTox-Core/build/core --with-libsodium-headers=/path/to/libsodium/include/ --with-libsodium-libs=/path/to/sodiumtest/lib/
+* Compile and install the program with ```make && sudo make install```
-```
-*Note:* If your default prefix is /usr/local and you happen to get an error that says "error while loading shared libraries: libtoxcore.so.0: cannot open shared object file: No such file or directory", then you can try running ```sudo ldconfig```. If that doesn't fix it, run:
+#### Notes
+If your default prefix is /usr/local and you get the error: "error while loading shared libraries: libtoxcore.so.0: cannot open shared object file: No such file or directory", then you can try running ```sudo ldconfig```. If that doesn't fix it, run:
```
echo '/usr/local/lib/' | sudo tee -a /etc/ld.so.conf.d/locallib.conf
sudo ldconfig
```
+If you dont already have them, you may need to install the ncurses libraries. For Debian based systems:
+```
+sudo apt-get install libncurses5-dev libncursesw5-dev
+```
diff --git a/build/Makefile.am b/build/Makefile.am
index e8e8848..329678d 100644
--- a/build/Makefile.am
+++ b/build/Makefile.am
@@ -25,7 +25,11 @@ toxic_SOURCES = $(top_srcdir)/src/main.c \
$(top_srcdir)/src/misc_tools.c \
$(top_srcdir)/src/misc_tools.h \
$(top_srcdir)/src/toxic_strings.c \
- $(top_srcdir)/src/toxic_strings.h
+ $(top_srcdir)/src/toxic_strings.h \
+ $(top_srcdir)/src/log.c \
+ $(top_srcdir)/src/log.h \
+ $(top_srcdir)/src/file_senders.c \
+ $(top_srcdir)/src/file_senders.h
toxic_CFLAGS = -I$(top_srcdir) \
$(NCURSES_CFLAGS) \
@@ -53,4 +57,4 @@ toxic_CFLAGS += $(LIBTOXAV_CFLAGS) \
toxic_LDADD += $(LIBTOXAV_LIBS) \
$(OPENAL_LIBS)
-endif
\ No newline at end of file
+endif
diff --git a/configure.ac b/configure.ac
index a58f474..e17e4b4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.65])
-AC_INIT([toxic], [0.2.5], [https://tox.im/])
+AC_INIT([toxic], [0.2.7], [https://tox.im/])
AC_CONFIG_AUX_DIR(configure_aux)
AC_CONFIG_SRCDIR([src/main.c])
AC_CONFIG_HEADERS([config.h])
diff --git a/misc/DHTservers b/misc/DHTnodes
similarity index 100%
rename from misc/DHTservers
rename to misc/DHTnodes
diff --git a/misc/Makefile.am b/misc/Makefile.am
index c25600a..0113f9d 100644
--- a/misc/Makefile.am
+++ b/misc/Makefile.am
@@ -1 +1 @@
-dist_pkgdata_DATA = DHTservers
+dist_pkgdata_DATA = DHTnodes
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
deleted file mode 100644
index 53316af..0000000
--- a/src/CMakeLists.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-cmake_minimum_required(VERSION 2.6.0)
-project(toxic C)
-
-execute_process(COMMAND git rev-list HEAD --count OUTPUT_VARIABLE COMMIT)
-SET(GCC_COVERAGE_COMPILE_FLAGS '-DTOXICVER="0.1.1_r${COMMIT}"')
-add_definitions(${GCC_COVERAGE_COMPILE_FLAGS})
-set(exe_name toxic)
-
-add_executable(${exe_name}
- main.c
- windows.c
- prompt.c
- friendlist.c
- dhtstatus.c
- chat.c
- configdir.c)
-
-include_directories(${CURSES_INCLUDE_DIR})
-
-target_link_libraries(${exe_name}
- ${CURSES_LIBRARIES})
-
-linkCoreLibraries(${exe_name})
diff --git a/src/chat.c b/src/chat.c
index 492ada1..7e0b29f 100644
--- a/src/chat.c
+++ b/src/chat.c
@@ -1,5 +1,23 @@
-/*
- * Toxic -- Tox Curses Client
+/* chat.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
@@ -15,6 +33,7 @@
#include "misc_tools.h"
#include "friendlist.h"
#include "toxic_strings.h"
+#include "log.h"
#ifdef _SUPPORT_AUDIO
#include "audio_call.h"
@@ -26,7 +45,12 @@ extern int store_data(Tox *m, char *path);
extern FileSender file_senders[MAX_FILES];
extern ToxicFriend friends[MAX_FRIENDS_NUM];
-#define AC_NUM_CHAT_COMMANDS 21
+
+#ifdef _SUPPORT_AUDIO
+#define AC_NUM_CHAT_COMMANDS 22
+#else
+#define AC_NUM_CHAT_COMMANDS 18
+#endif /* _SUPPORT_AUDIO */
/* Array of chat command names used for tab completion. */
static const uint8_t chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
@@ -40,6 +64,7 @@ static const uint8_t chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/help" },
{ "/invite" },
{ "/join" },
+ { "/log" },
{ "/myid" },
{ "/nick" },
{ "/note" },
@@ -58,6 +83,33 @@ static const uint8_t chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
#endif /* _SUPPORT_AUDIO */
};
+static void set_typingstatus(ToxWindow *self, Tox *m, bool is_typing)
+{
+ ChatContext *ctx = self->chatwin;
+
+ tox_set_user_is_typing(m, self->num, is_typing);
+ ctx->self_is_typing = is_typing;
+}
+
+void kill_chat_window(ToxWindow *self)
+{
+ set_active_window(0);
+ ChatContext *ctx = self->chatwin;
+ StatusBar *statusbar = self->stb;
+
+ log_disable(ctx->log);
+
+ int f_num = self->num;
+ delwin(ctx->linewin);
+ delwin(statusbar->topline);
+ del_window(self);
+ disable_chatwin(f_num);
+
+ free(ctx->log);
+ free(ctx);
+ free(statusbar);
+}
+
static void chat_onMessage(ToxWindow *self, Tox *m, int num, uint8_t *msg, uint16_t len)
{
if (self->num != num)
@@ -81,6 +133,7 @@ static void chat_onMessage(ToxWindow *self, Tox *m, int num, uint8_t *msg, uint1
} else
wprintw(ctx->history, "%s\n", msg);
+ write_to_log(msg, nick, ctx->log, false);
alert_window(self, WINDOW_ALERT_1, true);
}
@@ -90,7 +143,22 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, int num, uint8_t st
return;
StatusBar *statusbar = self->stb;
- statusbar->is_online = status == 1 ? true : false;
+
+ if (status == 1) {
+ statusbar->is_online = true;
+ friends[num].is_typing = tox_get_is_typing(m, num);
+ } else {
+ statusbar->is_online = false;
+ friends[num].is_typing = false;
+ }
+}
+
+static void chat_onTypingChange(ToxWindow *self, Tox *m, int num, int is_typing)
+{
+ if (self->num != num)
+ return;
+
+ friends[num].is_typing = is_typing;
}
static void chat_onAction(ToxWindow *self, Tox *m, int num, uint8_t *action, uint16_t len)
@@ -109,6 +177,7 @@ static void chat_onAction(ToxWindow *self, Tox *m, int num, uint8_t *action, uin
wprintw(ctx->history, "* %s %s\n", nick, action);
wattroff(ctx->history, COLOR_PAIR(YELLOW));
+ write_to_log(action, nick, ctx->log, true);
alert_window(self, WINDOW_ALERT_1, true);
}
@@ -172,7 +241,7 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int num, uint8_t fil
strcat(filename, d);
filename[len + strlen(d)] = '\0';
- if (count > 999999) {
+ if (count > 999) {
wprintw(ctx->history, "Error saving file to disk.\n");
return;
}
@@ -186,6 +255,15 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int num, uint8_t fil
alert_window(self, WINDOW_ALERT_2, true);
}
+static void chat_close_file_receiver(int num, uint8_t filenum)
+{
+ friends[num].file_receiver.pending[filenum] = false;
+ FILE *file = friends[num].file_receiver.files[filenum];
+
+ if (file != NULL)
+ fclose(file);
+}
+
static void chat_onFileControl(ToxWindow *self, Tox *m, int num, uint8_t receive_send,
uint8_t filenum, uint8_t control_type, uint8_t *data, uint16_t length)
{
@@ -204,20 +282,20 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, int num, uint8_t receive
case TOX_FILECONTROL_ACCEPT:
wprintw(ctx->history, "File transfer for '%s' accepted.\n", filename);
break;
- case TOX_FILECONTROL_PAUSE:
- // wprintw(ctx->history, "File transfer for '%s' paused.\n", filename);
- break;
+ // case TOX_FILECONTROL_PAUSE:
+ // wprintw(ctx->history, "File transfer for '%s' paused.\n", filename);
+ // break;
case TOX_FILECONTROL_KILL:
wprintw(ctx->history, "File transfer for '%s' failed.\n", filename);
if (receive_send == 0)
- friends[num].file_receiver.pending[filenum] = false;
+ chat_close_file_receiver(num, filenum);
else
- close_file_sender(filenum);
-
+ chat_close_file_receiver(num, filenum);
break;
case TOX_FILECONTROL_FINISHED:
wprintw(ctx->history, "File transfer for '%s' complete.\n", filename);
+ chat_close_file_receiver(num, filenum);
break;
}
@@ -232,26 +310,12 @@ static void chat_onFileData(ToxWindow *self, Tox *m, int num, uint8_t filenum, u
ChatContext *ctx = self->chatwin;
- uint8_t *filename = friends[num].file_receiver.filenames[filenum];
- FILE *file_to_save = fopen(filename, "a");
-
- // we have a problem here, but don't let it segfault
- if (file_to_save == NULL) {
- wattron(ctx->history, COLOR_PAIR(RED));
- wprintw(ctx->history, "* Error writing to file.\n");
- wattroff(ctx->history, COLOR_PAIR(RED));
- tox_file_send_control(m, num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0);
- return;
- }
-
- if (fwrite(data, length, 1, file_to_save) != 1) {
+ if (fwrite(data, length, 1, friends[num].file_receiver.files[filenum]) != 1) {
wattron(ctx->history, COLOR_PAIR(RED));
wprintw(ctx->history, "* Error writing to file.\n");
wattroff(ctx->history, COLOR_PAIR(RED));
tox_file_send_control(m, num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0);
}
-
- fclose(file_to_save);
}
static void chat_onGroupInvite(ToxWindow *self, Tox *m, int friendnumber, uint8_t *group_pub_key)
@@ -407,6 +471,8 @@ static void send_action(ToxWindow *self, ChatContext *ctx, Tox *m, uint8_t *acti
wattron(ctx->history, COLOR_PAIR(RED));
wprintw(ctx->history, " * Failed to send action\n");
wattroff(ctx->history, COLOR_PAIR(RED));
+ } else {
+ write_to_log(action, selfname, ctx->log, true);
}
}
@@ -457,14 +523,14 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key)
beep();
}
- else if (key == KEY_HOME) { /* HOME key: Move cursor to beginning of line */
+ else if (key == KEY_HOME || key == T_KEY_C_A) { /* HOME/C-a key: Move cursor to start of line */
if (ctx->pos > 0) {
ctx->pos = 0;
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
}
}
- else if (key == KEY_END) { /* END key: move cursor to end of line */
+ else if (key == KEY_END || key == T_KEY_C_E) { /* END/C-e key: move cursor to end of line */
if (ctx->pos != ctx->len) {
ctx->pos = ctx->len;
mv_curs_end(self->window, MAX(0, wcswidth(ctx->line, (CHATBOX_HEIGHT-1)*x2)), y2, x2);
@@ -546,6 +612,9 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key)
else
wmove(self->window, y, x + MAX(1, wcwidth(key)));
}
+
+ if (!ctx->self_is_typing && ctx->line[0] != '/')
+ set_typingstatus(self, m, true);
}
/* RETURN key: Execute command or print line */
else if (key == '\n') {
@@ -557,22 +626,22 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key)
wclear(ctx->linewin);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
wclrtobot(self->window);
- bool close_win = false;
if (!string_is_empty(line))
add_line_to_hist(ctx->line, ctx->len, ctx->ln_history, &ctx->hst_tot, &ctx->hst_pos);
if (line[0] == '/') {
- if (close_win = !strcmp(line, "/close")) {
- int f_num = self->num;
- delwin(ctx->linewin);
- delwin(statusbar->topline);
- del_window(self);
- disable_chatwin(f_num);
- } else if (strncmp(line, "/me ", strlen("/me ")) == 0)
+ if (strcmp(line, "/close") == 0) {
+ if (ctx->self_is_typing)
+ set_typingstatus(self, m, false);
+
+ kill_chat_window(self);
+ return;
+ } else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
send_action(self, ctx, m, line + strlen("/me "));
- else
+ } else {
execute(ctx->history, self, m, line, CHAT_COMMAND_MODE);
+ }
} else if (!string_is_empty(line)) {
uint8_t selfname[TOX_MAX_NAME_LENGTH];
tox_get_self_name(m, selfname, TOX_MAX_NAME_LENGTH);
@@ -593,16 +662,16 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key)
wattron(ctx->history, COLOR_PAIR(RED));
wprintw(ctx->history, " * Failed to send message.\n");
wattroff(ctx->history, COLOR_PAIR(RED));
+ } else {
+ write_to_log(line, selfname, ctx->log, false);
}
}
- if (close_win) {
- free(ctx);
- free(statusbar);
- } else {
- reset_buf(ctx->line, &ctx->pos, &ctx->len);
- }
+ reset_buf(ctx->line, &ctx->pos, &ctx->len);
}
+
+ if (ctx->len <= 0 && ctx->self_is_typing)
+ set_typingstatus(self, m, false);
}
static void chat_onDraw(ToxWindow *self, Tox *m)
@@ -653,9 +722,16 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
break;
}
+ if (friends[self->num].is_typing)
+ wattron(statusbar->topline, COLOR_PAIR(YELLOW));
+
wattron(statusbar->topline, A_BOLD);
wprintw(statusbar->topline, " %s ", self->name);
wattroff(statusbar->topline, A_BOLD);
+
+ if (friends[self->num].is_typing)
+ wattroff(statusbar->topline, COLOR_PAIR(YELLOW));
+
wattron(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
wprintw(statusbar->topline, "[%s]", status_text);
wattroff(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
@@ -724,8 +800,24 @@ static void chat_onInit(ToxWindow *self, Tox *m)
ctx->history = subwin(self->window, y2-CHATBOX_HEIGHT+1, x2, 0, 0);
scrollok(ctx->history, 1);
ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2-CHATBOX_HEIGHT, 0);
+
+ ctx->log = malloc(sizeof(struct chatlog));
+
+ if (ctx->log == NULL) {
+ endwin();
+ fprintf(stderr, "malloc() failed. Aborting...\n");
+ exit(EXIT_FAILURE);
+ }
+
+ memset(ctx->log, 0, sizeof(struct chatlog));
+
+ if (friends[self->num].logging_on)
+ log_enable(self->name, friends[self->num].pub_key, ctx->log);
+
wprintw(ctx->history, "\n\n");
execute(ctx->history, self, m, "/help", CHAT_COMMAND_MODE);
+ execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
+
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
}
@@ -735,12 +827,14 @@ ToxWindow new_chat(Tox *m, int friendnum)
memset(&ret, 0, sizeof(ret));
ret.active = true;
+ ret.is_chat = true;
ret.onKey = &chat_onKey;
ret.onDraw = &chat_onDraw;
ret.onInit = &chat_onInit;
ret.onMessage = &chat_onMessage;
ret.onConnectionChange = &chat_onConnectionChange;
+ ret.onTypingChange = & chat_onTypingChange;
ret.onGroupInvite = &chat_onGroupInvite;
ret.onNickChange = &chat_onNickChange;
ret.onStatusChange = &chat_onStatusChange;
diff --git a/src/chat.h b/src/chat.h
index a7918df..fac132a 100644
--- a/src/chat.h
+++ b/src/chat.h
@@ -1,8 +1,31 @@
+/* chat.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 CHAT_H_6489PZ13
#define CHAT_H_6489PZ13
#include "toxic_windows.h"
+void kill_chat_window(ToxWindow *self);
ToxWindow new_chat(Tox *m, int friendnum);
#endif /* end of include guard: CHAT_H_6489PZ13 */
diff --git a/src/chat_commands.c b/src/chat_commands.c
index 600c07a..9bac9a3 100644
--- a/src/chat_commands.c
+++ b/src/chat_commands.c
@@ -1,5 +1,23 @@
-/*
- * Toxic -- Tox Curses Client
+/* chat_commands.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
@@ -12,6 +30,7 @@
#include "toxic_windows.h"
#include "misc_tools.h"
#include "friendlist.h"
+#include "execute.h"
extern ToxWindow *prompt;
@@ -22,23 +41,17 @@ extern uint8_t max_file_senders_index;
void cmd_chat_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
+ if (argc == 1) {
+ if (!strcmp(argv[1], "global")) {
+ execute(window, self, m, "/help", GLOBAL_COMMAND_MODE);
+ return;
+ }
+ }
+
wattron(window, COLOR_PAIR(CYAN) | A_BOLD);
wprintw(window, "Chat commands:\n");
wattroff(window, COLOR_PAIR(CYAN) | A_BOLD);
- wprintw(window, " /status : Set your status with optional note\n");
- wprintw(window, " /note : Set a personal note\n");
- wprintw(window, " /nick : Set your nickname\n");
- wprintw(window, " /invite : Invite friend to a group chat\n");
- wprintw(window, " /me : Do an action\n");
- wprintw(window, " /myid : Print your ID\n");
- wprintw(window, " /join : Join a pending group chat\n");
- wprintw(window, " /clear : Clear the screen\n");
- wprintw(window, " /close : Close the current chat window\n");
- wprintw(window, " /sendfile : Send a file\n");
- wprintw(window, " /savefile : Receive a file\n");
- wprintw(window, " /quit or /exit : Exit Toxic\n");
-
#ifdef _SUPPORT_AUDIO
wprintw(window, " /call : Audio call\n");
@@ -48,7 +61,14 @@ void cmd_chat_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
#endif /* _SUPPORT_AUDIO */
- wprintw(window, " /help : Print this message again\n");
+ wprintw(window, " /invite : Invite friend to a group chat\n");
+ wprintw(window, " /join : Join a pending group chat\n");
+ wprintw(window, " /log or : Enable/disable logging\n");
+ wprintw(window, " /sendfile : Send a file\n");
+ wprintw(window, " /savefile : Receive a file\n");
+ wprintw(window, " /close : Close the current chat window\n");
+ wprintw(window, " /help : Print this message again\n");
+ wprintw(window, " /help global : Show a list of global commands\n");
wattron(window, COLOR_PAIR(CYAN) | A_BOLD);
wprintw(window, " * Argument messages must be enclosed in quotation marks.\n\n");
@@ -128,10 +148,18 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
uint8_t *filename = friends[self->num].file_receiver.filenames[filenum];
- if (tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_ACCEPT, 0, 0) == 0)
+ if (tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_ACCEPT, 0, 0) == 0) {
wprintw(window, "Accepted file transfer %u. Saving file as: '%s'\n", filenum, filename);
- else
+
+ if ((friends[self->num].file_receiver.files[filenum] = fopen(filename, "a")) == NULL) {
+ wattron(window, COLOR_PAIR(RED));
+ wprintw(window, "* Error writing to file.\n");
+ wattroff(window, COLOR_PAIR(RED));
+ tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0);
+ }
+ } else {
wprintw(window, "File transfer failed.\n");
+ }
friends[self->num].file_receiver.pending[filenum] = false;
}
diff --git a/src/chat_commands.h b/src/chat_commands.h
index d52357b..f5caf1d 100644
--- a/src/chat_commands.h
+++ b/src/chat_commands.h
@@ -1,5 +1,23 @@
-/*
- * Toxic -- Tox Curses Client
+/* chat_commands.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 .
+ *
*/
void cmd_chat_help(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
@@ -14,4 +32,4 @@ void cmd_call(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]
void cmd_answer(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
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 */
\ No newline at end of file
+#endif /* _SUPPORT_AUDIO */
diff --git a/src/configdir.c b/src/configdir.c
index 8f43bc9..d43b08c 100644
--- a/src/configdir.c
+++ b/src/configdir.c
@@ -1,20 +1,22 @@
-/*
- * Copyright (C) 2013 Tox project All Rights Reserved.
+/* configdir.c
*
- * This file is part of Tox.
*
- * Tox is free software: you can redistribute it and/or modify
+ * 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.
*
- * Tox is distributed in the hope that it will be useful,
+ * 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 Tox. If not, see .
+ * along with Toxic. If not, see .
*
*/
diff --git a/src/configdir.h b/src/configdir.h
index e886e53..6a1a7eb 100644
--- a/src/configdir.h
+++ b/src/configdir.h
@@ -1,20 +1,22 @@
-/*
- * Copyright (C) 2013 Tox project All Rights Reserved.
+/* configdir.h
*
- * This file is part of Tox.
*
- * Tox is free software: you can redistribute it and/or modify
+ * 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.
*
- * Tox is distributed in the hope that it will be useful,
+ * 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 Tox. If not, see .
+ * along with Toxic. If not, see .
*
*/
diff --git a/src/execute.c b/src/execute.c
index 104af9a..462749d 100644
--- a/src/execute.c
+++ b/src/execute.c
@@ -1,5 +1,23 @@
-/*
- * Toxic -- Tox Curses Client
+/* execute.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 .
+ *
*/
#include
@@ -23,6 +41,7 @@ static struct cmd_func global_commands[] = {
{ "/exit", cmd_quit },
{ "/groupchat", cmd_groupchat },
{ "/help", cmd_prompt_help },
+ { "/log", cmd_log },
{ "/myid", cmd_myid },
{ "/nick", cmd_nick },
{ "/note", cmd_note },
diff --git a/src/execute.h b/src/execute.h
index 9586410..42b90b9 100644
--- a/src/execute.h
+++ b/src/execute.h
@@ -1,9 +1,27 @@
-/*
- * Toxic -- Tox Curses Client
+/* execute.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 .
+ *
*/
#define MAX_NUM_ARGS 4 /* Includes command */
-#define GLOBAL_NUM_COMMANDS 13
+#define GLOBAL_NUM_COMMANDS 14
#ifdef _SUPPORT_AUDIO
#define CHAT_NUM_COMMANDS 9
diff --git a/src/file_senders.c b/src/file_senders.c
new file mode 100644
index 0000000..d643bf4
--- /dev/null
+++ b/src/file_senders.c
@@ -0,0 +1,109 @@
+/* file_senders.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 .
+ *
+ */
+
+#include
+#include
+#include
+
+#include "toxic_windows.h"
+
+FileSender file_senders[MAX_FILES];
+uint8_t max_file_senders_index;
+
+static void close_file_sender(int i)
+{
+ fclose(file_senders[i].file);
+ memset(&file_senders[i], 0, sizeof(FileSender));
+
+ int j;
+
+ for (j = max_file_senders_index; j > 0; --j) {
+ if (file_senders[j-1].active)
+ break;
+ }
+
+ max_file_senders_index = j;
+}
+
+/* Should only be called on exit */
+void close_all_file_senders(void)
+{
+ int i;
+
+ for (i = 0; i < max_file_senders_index; ++i) {
+ if (file_senders[i].active)
+ fclose(file_senders[i].file);
+ }
+}
+
+void do_file_senders(Tox *m)
+{
+ int i;
+
+ for (i = 0; i < max_file_senders_index; ++i) {
+ if (!file_senders[i].active)
+ continue;
+
+ uint8_t *pathname = file_senders[i].pathname;
+ uint8_t filenum = file_senders[i].filenum;
+ int friendnum = file_senders[i].friendnum;
+ FILE *fp = file_senders[i].file;
+ uint64_t current_time = (uint64_t) time(NULL);
+
+ /* If file transfer has timed out kill transfer and send kill control */
+ if (timed_out(file_senders[i].timestamp, current_time, TIMEOUT_FILESENDER)) {
+ ChatContext *ctx = file_senders[i].toxwin->chatwin;
+
+ if (ctx != NULL) {
+ wprintw(ctx->history, "File transfer for '%s' timed out.\n", pathname);
+ alert_window(file_senders[i].toxwin, WINDOW_ALERT_2, true);
+ }
+
+ tox_file_send_control(m, friendnum, 0, filenum, TOX_FILECONTROL_KILL, 0, 0);
+ close_file_sender(i);
+ continue;
+ }
+
+ while (true) {
+ if (tox_file_send_data(m, friendnum, filenum, file_senders[i].nextpiece,
+ file_senders[i].piecelen) == -1)
+ break;
+
+ file_senders[i].timestamp = current_time;
+ file_senders[i].piecelen = fread(file_senders[i].nextpiece, 1,
+ tox_file_data_size(m, friendnum), fp);
+
+ if (file_senders[i].piecelen == 0) {
+ ChatContext *ctx = file_senders[i].toxwin->chatwin;
+
+ if (ctx != NULL) {
+ wprintw(ctx->history, "File '%s' successfuly sent.\n", pathname);
+ alert_window(file_senders[i].toxwin, WINDOW_ALERT_2, true);
+ }
+
+ tox_file_send_control(m, friendnum, 0, filenum, TOX_FILECONTROL_FINISHED, 0, 0);
+ close_file_sender(i);
+ break;
+ }
+ }
+ }
+}
diff --git a/src/file_senders.h b/src/file_senders.h
new file mode 100644
index 0000000..9ec1cdc
--- /dev/null
+++ b/src/file_senders.h
@@ -0,0 +1,26 @@
+/* file_senders.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 .
+ *
+ */
+
+/* Should only be called on exit */
+void close_all_file_senders(void);
+
+void do_file_senders(Tox *m);
diff --git a/src/friendlist.c b/src/friendlist.c
index c6273b5..190de5b 100644
--- a/src/friendlist.c
+++ b/src/friendlist.c
@@ -1,5 +1,23 @@
-/*
- * Toxic -- Tox Curses Client
+/* friendlist.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
@@ -116,7 +134,7 @@ static void friendlist_onStatusMessageChange(ToxWindow *self, int num, uint8_t *
friends[num].statusmsg_len = len;
}
-static void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int num, bool sort)
+void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int num, bool sort)
{
if (max_friends_index < 0 || max_friends_index >= MAX_FRIENDS_NUM)
return;
diff --git a/src/friendlist.h b/src/friendlist.h
index 029c9a6..23a3565 100644
--- a/src/friendlist.h
+++ b/src/friendlist.h
@@ -1,3 +1,25 @@
+/* friendlist.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 FRIENDLIST_H_53I41IM
#define FRIENDLIST_H_53I41IM
@@ -14,6 +36,8 @@ typedef struct {
int chatwin;
bool active;
bool online;
+ bool is_typing;
+ bool logging_on; /* saves preference for friend irrespective of chat windows */
TOX_USERSTATUS status;
struct FileReceiver file_receiver;
} ToxicFriend;
@@ -22,6 +46,8 @@ ToxWindow new_friendlist(void);
void disable_chatwin(int f_num);
int get_friendnum(uint8_t *name);
+void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int num, bool sort);
+
/* sorts friendlist_index first by connection status then alphabetically */
void sort_friendlist_index(Tox *m);
diff --git a/src/global_commands.c b/src/global_commands.c
index 29af2d6..80a2978 100644
--- a/src/global_commands.c
+++ b/src/global_commands.c
@@ -1,5 +1,23 @@
-/*
- * Toxic -- Tox Curses Client
+/* global_commands.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
@@ -202,6 +220,73 @@ void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
wprintw(window, "Group chat created as %d.\n", groupnum);
}
+void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
+{
+ if (argc == 0) {
+ bool on;
+
+ if (self->is_chat || self->is_groupchat)
+ on = self->chatwin->log->log_on;
+ else if (self->is_prompt)
+ on = self->promptbuf->log->log_on;
+
+ if (on) {
+ wprintw(window, "Logging for this window is ");
+ wattron(window, COLOR_PAIR(GREEN) | A_BOLD);
+ wprintw(window, "[on]");
+ wattroff(window, COLOR_PAIR(GREEN) | A_BOLD);
+ wprintw(window, ". Type \"/log off\" to disable.\n");
+ } else {
+ wprintw(window, "Logging for this window is ");
+ wattron(window, COLOR_PAIR(RED) | A_BOLD);
+ wprintw(window, "[off]");
+ wattroff(window, COLOR_PAIR(RED) | A_BOLD);
+ wprintw(window, ". Type \"/log on\" to enable.\n");
+ }
+
+ return;
+ }
+
+ uint8_t *swch = argv[1];
+
+ if (!strcmp(swch, "1") || !strcmp(swch, "on")) {
+
+ if (self->is_chat) {
+ friends[self->num].logging_on = true;
+ log_enable(self->name, friends[self->num].pub_key, self->chatwin->log);
+ } else if (self->is_prompt) {
+ uint8_t myid[TOX_FRIEND_ADDRESS_SIZE];
+ tox_get_address(m, myid);
+ log_enable(self->name, &myid, self->promptbuf->log);
+ } else if (self->is_groupchat) {
+ log_enable(self->name, NULL, self->chatwin->log);
+ }
+
+ wprintw(window, "Logging ");
+ wattron(window, COLOR_PAIR(GREEN) | A_BOLD);
+ wprintw(window, "[on]\n");
+ wattroff(window, COLOR_PAIR(GREEN) | A_BOLD);
+ return;
+ } else if (!strcmp(swch, "0") || !strcmp(swch, "off")) {
+ if (self->is_chat) {
+ friends[self->num].logging_on = false;
+ log_disable(self->chatwin->log);
+ } else if (self->is_prompt) {
+ log_disable(self->promptbuf->log);
+ } else if (self->is_groupchat) {
+ log_disable(self->chatwin->log);
+ }
+
+ wprintw(window, "Logging ");
+ wattron(window, COLOR_PAIR(RED) | A_BOLD);
+ wprintw(window, "[off]\n");
+ wattroff(window, COLOR_PAIR(RED) | A_BOLD);
+ return;
+ }
+
+ wprintw(window, "Invalid option. Use \"/log on\" and \"/log off\" to toggle logging.\n");
+}
+
void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
char id[TOX_FRIEND_ADDRESS_SIZE * 2 + 1] = {0};
@@ -280,17 +365,18 @@ void cmd_prompt_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
wprintw(window, "\n\nGlobal commands:\n");
wattroff(window, COLOR_PAIR(CYAN) | A_BOLD);
- wprintw(window, " /add : Add friend with optional message\n");
- wprintw(window, " /accept : Accept friend request\n");
- wprintw(window, " /connect : Manually connect to a DHT server\n");
- wprintw(window, " /status : Set your status with optional note\n");
- wprintw(window, " /note : Set a personal note\n");
- wprintw(window, " /nick : Set your nickname\n");
- wprintw(window, " /groupchat : Create a group chat\n");
- wprintw(window, " /myid : Print your ID\n");
- wprintw(window, " /quit or /exit : Exit Toxic\n");
- wprintw(window, " /help : Print this message again\n");
- wprintw(window, " /clear : Clear the window\n");
+ wprintw(window, " /add : Add friend with optional message\n");
+ wprintw(window, " /accept : Accept friend request\n");
+ wprintw(window, " /connect : Manually connect to a DHT node\n");
+ wprintw(window, " /status : Set status with optional note\n");
+ wprintw(window, " /note : Set a personal note\n");
+ wprintw(window, " /nick : Set your nickname\n");
+ wprintw(window, " /log or : Enable/disable logging\n");
+ wprintw(window, " /groupchat : Create a group chat\n");
+ wprintw(window, " /myid : Print your ID\n");
+ wprintw(window, " /help : Print this message again\n");
+ wprintw(window, " /clear : Clear the window\n");
+ wprintw(window, " /quit or /exit : Exit Toxic\n");
wattron(window, COLOR_PAIR(CYAN) | A_BOLD);
wprintw(window, " * Argument messages must be enclosed in quotation marks.\n");
diff --git a/src/global_commands.h b/src/global_commands.h
index 57f16e3..5b0a66b 100644
--- a/src/global_commands.h
+++ b/src/global_commands.h
@@ -1,5 +1,23 @@
-/*
- * Toxic -- Tox Curses Client
+/* global_commands.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 .
+ *
*/
void cmd_accept(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
@@ -7,6 +25,7 @@ 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]);
void cmd_connect(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_groupchat(WINDOW *, ToxWindow *, Tox *, 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_nick(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_note(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
diff --git a/src/groupchat.c b/src/groupchat.c
index 5b6d624..2f30ff9 100644
--- a/src/groupchat.c
+++ b/src/groupchat.c
@@ -1,5 +1,23 @@
-/*
- * Toxic -- Tox Curses Client
+/* groupchat.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
@@ -16,6 +34,7 @@
#include "groupchat.h"
#include "prompt.h"
#include "toxic_strings.h"
+#include "log.h"
extern char *DATA_FILE;
extern int store_data(Tox *m, char *path);
@@ -53,8 +72,20 @@ int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum)
return -1;
}
-static void close_groupchatwin(Tox *m, int groupnum)
+void kill_groupchat_window(ToxWindow *self)
{
+ ChatContext *ctx = self->chatwin;
+
+ log_disable(ctx->log);
+ delwin(ctx->linewin);
+ del_window(self);
+ free(ctx->log);
+ free(ctx);
+}
+
+static void close_groupchat(ToxWindow *self, Tox *m, int groupnum)
+{
+ set_active_window(0);
tox_del_groupchat(m, groupnum);
free(groupchats[groupnum].peer_names);
@@ -69,6 +100,7 @@ static void close_groupchatwin(Tox *m, int groupnum)
}
max_groupchat_index = i;
+ kill_groupchat_window(self);
}
static void print_groupchat_help(ChatContext *ctx)
@@ -77,16 +109,15 @@ static void print_groupchat_help(ChatContext *ctx)
wprintw(ctx->history, "Group chat commands:\n");
wattroff(ctx->history, COLOR_PAIR(CYAN) | A_BOLD);
- wprintw(ctx->history, " /add : Add friend with optional message\n");
- wprintw(ctx->history, " /status : Set your status with optional note\n");
- wprintw(ctx->history, " /note : Set a personal note\n");
- wprintw(ctx->history, " /nick : Set your nickname\n");
- wprintw(ctx->history, " /groupchat : Create a group chat\n");
- wprintw(ctx->history, " /myid : Print your ID\n");
- wprintw(ctx->history, " /clear : Clear the screen\n");
- wprintw(ctx->history, " /close : Close the current group chat\n");
- wprintw(ctx->history, " /quit or /exit : Exit Toxic\n");
- wprintw(ctx->history, " /help : Print this message again\n");
+ wprintw(ctx->history, " /add : Add friend with optional message\n");
+ wprintw(ctx->history, " /status : Set your status with optional note\n");
+ wprintw(ctx->history, " /note : Set a personal note\n");
+ wprintw(ctx->history, " /nick : Set your nickname\n");
+ wprintw(ctx->history, " /groupchat : Create a group chat\n");
+ wprintw(ctx->history, " /log or : Enable/disable logging\n");
+ wprintw(ctx->history, " /close : Close the current group chat\n");
+ wprintw(ctx->history, " /help : Print this message again\n");
+ wprintw(ctx->history, " /help global : Show a list of global commands\n");
wattron(ctx->history, COLOR_PAIR(CYAN) | A_BOLD);
wprintw(ctx->history, " * Argument messages must be enclosed in quotation marks.\n");
@@ -136,6 +167,8 @@ static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, int groupnum, int
} else {
wprintw(ctx->history, "%s\n", msg);
}
+
+ write_to_log(msg, nick, ctx->log, false);
}
static void groupchat_onGroupAction(ToxWindow *self, Tox *m, int groupnum, int peernum, uint8_t *action,
@@ -170,6 +203,8 @@ static void groupchat_onGroupAction(ToxWindow *self, Tox *m, int groupnum, int p
wattron(ctx->history, COLOR_PAIR(YELLOW));
wprintw(ctx->history, "* %s %s\n", nick, action);
wattroff(ctx->history, COLOR_PAIR(YELLOW));
+
+ write_to_log(action, nick, ctx->log, true);
}
/* Puts two copies of peerlist in chat instance */
@@ -234,25 +269,36 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu
ChatContext *ctx = self->chatwin;
print_time(ctx->history);
+ uint8_t *event;
+
switch (change) {
case TOX_CHAT_CHANGE_PEER_ADD:
+ event = "has joined the room";
+
wattron(ctx->history, COLOR_PAIR(GREEN));
wattron(ctx->history, A_BOLD);
wprintw(ctx->history, "* %s", peername);
wattroff(ctx->history, A_BOLD);
- wprintw(ctx->history, " has joined the room\n");
+ wprintw(ctx->history, " %s\n", event);
wattroff(ctx->history, COLOR_PAIR(GREEN));
+
+ write_to_log(event, peername, ctx->log, true);
break;
+
case TOX_CHAT_CHANGE_PEER_DEL:
+ event = "has left the room";
+
wattron(ctx->history, A_BOLD);
wprintw(ctx->history, "* %s", oldpeername);
wattroff(ctx->history, A_BOLD);
- wprintw(ctx->history, " has left the room\n");
+ wprintw(ctx->history, " %s\n", event);
if (groupchats[self->num].side_pos > 0)
--groupchats[self->num].side_pos;
+ write_to_log(event, oldpeername, ctx->log, true);
break;
+
case TOX_CHAT_CHANGE_PEER_NAME:
wattron(ctx->history, COLOR_PAIR(MAGENTA));
wattron(ctx->history, A_BOLD);
@@ -265,6 +311,10 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu
wprintw(ctx->history, "%s\n", peername);
wattroff(ctx->history, A_BOLD);
wattroff(ctx->history, COLOR_PAIR(MAGENTA));
+
+ uint8_t tmp_event[TOXIC_MAX_NAME_LENGTH + 32];
+ snprintf(tmp_event, sizeof(tmp_event), "is now known as %s", peername);
+ write_to_log(tmp_event, oldpeername, ctx->log, true);
break;
}
@@ -338,14 +388,14 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key)
beep();
}
- else if (key == KEY_HOME) { /* HOME key: Move cursor to beginning of line */
+ else if (key == KEY_HOME || key == T_KEY_C_A) { /* HOME/C-a key: Move cursor to start of line */
if (ctx->pos > 0) {
ctx->pos = 0;
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
}
}
- else if (key == KEY_END) { /* END key: move cursor to end of line */
+ else if (key == KEY_END || key == T_KEY_C_E) { /* END/C-e key: move cursor to end of line */
if (ctx->pos != ctx->len) {
ctx->pos = ctx->len;
mv_curs_end(self->window, MAX(0, wcswidth(ctx->line, (CHATBOX_HEIGHT-1)*x2)), y2, x2);
@@ -458,24 +508,25 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key)
wclear(ctx->linewin);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
wclrtobot(self->window);
- bool close_win = false;
if (!string_is_empty(line))
add_line_to_hist(ctx->line, ctx->len, ctx->ln_history, &ctx->hst_tot, &ctx->hst_pos);
if (line[0] == '/') {
- if (close_win = strcmp(line, "/close") == 0) {
- set_active_window(0);
- int groupnum = self->num;
- delwin(ctx->linewin);
- del_window(self);
- close_groupchatwin(m, groupnum);
- } else if (strcmp(line, "/help") == 0)
- print_groupchat_help(ctx);
- else if (strncmp(line, "/me ", strlen("/me ")) == 0)
+ if (strcmp(line, "/close") == 0) {
+ close_groupchat(self, m, self->num);
+ return;
+ } else if (strcmp(line, "/help") == 0) {
+ if (strcmp(line, "help global") == 0)
+ execute(ctx->history, self, m, "/help", GLOBAL_COMMAND_MODE);
+ else
+ print_groupchat_help(ctx);
+
+ } else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
send_group_action(self, ctx, m, line + strlen("/me "));
- else
+ } else {
execute(ctx->history, self, m, line, GROUPCHAT_COMMAND_MODE);
+ }
} else if (!string_is_empty(line)) {
if (tox_group_message_send(m, self->num, line, strlen(line) + 1) == -1) {
wattron(ctx->history, COLOR_PAIR(RED));
@@ -484,10 +535,7 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key)
}
}
- if (close_win)
- free(ctx);
- else
- reset_buf(ctx->line, &ctx->pos, &ctx->len);
+ reset_buf(ctx->line, &ctx->pos, &ctx->len);
}
}
@@ -555,7 +603,19 @@ static void groupchat_onInit(ToxWindow *self, Tox *m)
ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x, y-CHATBOX_HEIGHT, 0);
ctx->sidebar = subwin(self->window, y-CHATBOX_HEIGHT+1, SIDEBAR_WIDTH, 0, x-SIDEBAR_WIDTH);
+ ctx->log = malloc(sizeof(struct chatlog));
+
+ if (ctx->log == NULL) {
+ endwin();
+ fprintf(stderr, "malloc() failed. Aborting...\n");
+ exit(EXIT_FAILURE);
+ }
+
+ memset(ctx->log, 0, sizeof(struct chatlog));
+
print_groupchat_help(ctx);
+ execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
+
wmove(self->window, y-CURS_Y_OFFSET, 0);
}
@@ -565,6 +625,7 @@ ToxWindow new_group_chat(Tox *m, int groupnum)
memset(&ret, 0, sizeof(ret));
ret.active = true;
+ ret.is_groupchat = true;
ret.onKey = &groupchat_onKey;
ret.onDraw = &groupchat_onDraw;
diff --git a/src/groupchat.h b/src/groupchat.h
index a3aa0a7..5b079d5 100644
--- a/src/groupchat.h
+++ b/src/groupchat.h
@@ -1,5 +1,23 @@
-/*
- * Toxic -- Tox Curses Client
+/* groupchat.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 .
+ *
*/
#define SIDEBAR_WIDTH 16
@@ -14,5 +32,6 @@ typedef struct {
uint8_t *oldpeer_names;
} GroupChat;
+void kill_groupchat_window(ToxWindow *self);
int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum);
ToxWindow new_group_chat(Tox *m, int groupnum);
diff --git a/src/log.c b/src/log.c
new file mode 100644
index 0000000..0b41b43
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,124 @@
+/* log.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 .
+ *
+ */
+
+#include
+#include
+#include
+
+#include "configdir.h"
+#include "toxic_windows.h"
+#include "misc_tools.h"
+
+/* Creates/fetches log file by appending to the config dir the name and a pseudo-unique identity */
+void init_logging_session(uint8_t *name, uint8_t *key, struct chatlog *log)
+{
+ if (!log->log_on)
+ return;
+
+ char *user_config_dir = get_user_config_dir();
+ int path_len = strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(name);
+
+ /* use first 4 digits of key as log ident. If no key use a timestamp */
+ uint8_t ident[32];
+
+ if (key != NULL) {
+ path_len += (KEY_IDENT_DIGITS * 2 + 5);
+
+ sprintf(&ident[0], "%02X", key[0] & 0xff);
+ sprintf(&ident[2], "%02X", key[2] & 0xff);
+ ident[KEY_IDENT_DIGITS*2+1] = '\0';
+ } else {
+ struct tm *tminfo = get_time();
+ snprintf(ident, sizeof(ident),
+ "%04d-%02d-%02d[%02d:%02d:%02d]", tminfo->tm_year+1900,tminfo->tm_mon+1, tminfo->tm_mday,
+ tminfo->tm_hour, tminfo->tm_min, tminfo->tm_sec);
+ path_len += strlen(ident) + 1;
+ }
+
+ if (path_len > MAX_STR_SIZE) {
+ log->log_on = false;
+ return;
+ }
+
+ uint8_t log_path[MAX_STR_SIZE];
+
+ snprintf(log_path, MAX_STR_SIZE, "%s%s%s-%s.log",
+ user_config_dir, CONFIGDIR, name, ident);
+
+ log->file = fopen(log_path, "a");
+
+ if (log->file == NULL) {
+ log->log_on = false;
+ return;
+ }
+
+ fprintf(log->file, "\n*** NEW SESSION ***\n\n");
+ free(user_config_dir);
+}
+
+void write_to_log(uint8_t *msg, uint8_t *name, struct chatlog *log, bool event)
+{
+ if (!log->log_on)
+ return;
+
+ if (log->file == NULL) {
+ log->log_on = false;
+ return;
+ }
+
+ uint8_t name_frmt[TOXIC_MAX_NAME_LENGTH + 3];
+
+ if (event)
+ snprintf(name_frmt, sizeof(name_frmt), "* %s", name);
+ else
+ snprintf(name_frmt, sizeof(name_frmt), "%s:", name);
+
+ struct tm *tminfo = get_time();
+ fprintf(log->file,"%04d/%02d/%02d [%02d:%02d:%02d] %s %s\n", tminfo->tm_year+1900,
+ tminfo->tm_mon+1, tminfo->tm_mday, tminfo->tm_hour, tminfo->tm_min,
+ tminfo->tm_sec, name_frmt, msg);
+
+ uint64_t curtime = (uint64_t) time(NULL);
+
+ if (timed_out(log->lastwrite, curtime, LOG_FLUSH_LIMIT)) {
+ fflush(log->file);
+ log->lastwrite = curtime;
+ }
+}
+
+void log_enable(uint8_t *name, uint8_t *key, struct chatlog *log)
+{
+ log->log_on = true;
+
+ if (log->file == NULL)
+ init_logging_session(name, key, log);
+}
+
+void log_disable(struct chatlog *log)
+{
+ log->log_on = false;
+
+ if (log->file != NULL) {
+ fclose(log->file);
+ log->file = NULL;
+ }
+}
diff --git a/src/log.h b/src/log.h
new file mode 100644
index 0000000..71c9748
--- /dev/null
+++ b/src/log.h
@@ -0,0 +1,33 @@
+/* log.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 .
+ *
+ */
+
+/* Creates/fetches log file by appending to the config dir the name and a pseudo-unique identity */
+void init_logging_session(uint8_t *name, uint8_t *key, struct chatlog *log);
+
+/* formats/writes line to log file */
+void write_to_log(uint8_t *msg, uint8_t *name, struct chatlog *log, bool event);
+
+/* enables logging for specified log and creates/fetches file if necessary */
+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);
diff --git a/src/main.c b/src/main.c
index cefe2ed..57ae644 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,5 +1,23 @@
-/*
- * Toxic -- Tox Curses Client
+/* main.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
@@ -40,6 +58,7 @@
#include "friendlist.h"
#include "prompt.h"
#include "misc_tools.h"
+#include "file_senders.h"
#ifdef _SUPPORT_AUDIO
#include "audio_call.h"
@@ -51,11 +70,9 @@
/* Export for use in Callbacks */
char *DATA_FILE = NULL;
-char *SRVLIST_FILE = NULL;
ToxWindow *prompt = NULL;
-FileSender file_senders[MAX_FILES];
-uint8_t max_file_senders_index;
+static int f_loadfromfile; /* 1 if we want to load from/save the data file, 0 otherwise */
void on_window_resize(int sig)
{
@@ -103,8 +120,12 @@ static Tox *init_tox(int ipv4)
int ipv6 = !ipv4;
Tox *m = tox_new(ipv6);
- if (TOX_ENABLE_IPV6_DEFAULT && m == NULL) {
- fprintf(stderr, "IPv6 didn't initialize, trying IPv4 only\n");
+ /*
+ * 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);
}
@@ -113,6 +134,7 @@ static Tox *init_tox(int ipv4)
/* 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);
@@ -142,25 +164,26 @@ static Tox *init_tox(int ipv4)
#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 MAXSERVERS 50
-#define SERVERLEN (MAXLINE - TOX_CLIENT_ID_SIZE - 7)
+#define MAXNODES 50
+#define NODELEN (MAXLINE - TOX_CLIENT_ID_SIZE - 7)
static int linecnt = 0;
-static char servers[MAXSERVERS][SERVERLEN];
-static uint16_t ports[MAXSERVERS];
-static uint8_t keys[MAXSERVERS][TOX_CLIENT_ID_SIZE];
+static char nodes[MAXNODES][NODELEN];
+static uint16_t ports[MAXNODES];
+static uint8_t keys[MAXNODES][TOX_CLIENT_ID_SIZE];
-int serverlist_load(void)
+static int nodelist_load(char *filename)
{
- FILE *fp = NULL;
+ if (!filename)
+ return 1;
- fp = fopen(SRVLIST_FILE, "r");
+ FILE *fp = fopen(filename, "r");
if (fp == NULL)
return 1;
char line[MAXLINE];
- while (fgets(line, sizeof(line), fp) && linecnt < MAXSERVERS) {
+ while (fgets(line, sizeof(line), fp) && linecnt < MAXNODES) {
if (strlen(line) > MINLINE) {
char *name = strtok(line, " ");
char *port = strtok(NULL, " ");
@@ -169,8 +192,8 @@ int serverlist_load(void)
if (name == NULL || port == NULL || key_ascii == NULL)
continue;
- strncpy(servers[linecnt], name, SERVERLEN);
- servers[linecnt][SERVERLEN - 1] = 0;
+ strncpy(nodes[linecnt], name, NODELEN);
+ nodes[linecnt][NODELEN - 1] = 0;
ports[linecnt] = htons(atoi(port));
uint8_t *key_binary = hex_string_to_bin(key_ascii);
@@ -190,51 +213,53 @@ int serverlist_load(void)
return 0;
}
-int init_connection_helper(Tox *m, int linenumber)
+int init_connection_helper(Tox *m, int line)
{
- return tox_bootstrap_from_address(m, servers[linenumber], TOX_ENABLE_IPV6_DEFAULT,
- ports[linenumber], keys[linenumber]);
+ return tox_bootstrap_from_address(m, nodes[line], TOX_ENABLE_IPV6_DEFAULT,
+ ports[line], keys[line]);
}
-/* Connects to a random DHT server listed in the DHTservers file
+/* Connects to a random DHT node listed in the DHTnodes file
*
* return codes:
- * 1: failed to open server file
- * 2: no line of sufficient length in server file
- * 3: (old, removed) failed to split a selected line in the server file
- * 4: failed to resolve name to IP
- * 5: serverlist file contains no acceptable line
+ * 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 int init_connection_serverlist_loaded = 0;
+static bool srvlist_loaded = false;
+
+#define NUM_INIT_NODES 5
+
int init_connection(Tox *m)
{
- if (linecnt > 0) /* already loaded serverlist */
- return init_connection_helper(m, rand() % linecnt) ? 0 : 4;
+ if (linecnt > 0) /* already loaded nodelist */
+ return init_connection_helper(m, rand() % linecnt) ? 0 : 3;
/* only once:
- * - load the serverlist
+ * - load the nodelist
* - connect to "everyone" inside
*/
- if (!init_connection_serverlist_loaded) {
- init_connection_serverlist_loaded = 1;
- int res = serverlist_load();
- if (res)
+ if (!srvlist_loaded) {
+ srvlist_loaded = true;
+ int res = nodelist_load(PACKAGE_DATADIR "/DHTnodes");
+
+ if (linecnt < 1)
return res;
- if (!linecnt)
- return 4;
+ res = 3;
+ int i;
+ int n = MIN(NUM_INIT_NODES, linecnt);
- res = 6;
- int linenumber;
- for(linenumber = 0; linenumber < linecnt; linenumber++)
- if (init_connection_helper(m, linenumber))
+ for(i = 0; i < n; ++i)
+ if (init_connection_helper(m, rand() % linecnt))
res = 0;
return res;
}
- /* empty serverlist file */
- return 5;
+ /* empty nodelist file */
+ return 4;
}
static void do_connection(Tox *m, ToxWindow *prompt)
@@ -267,7 +292,14 @@ static void do_connection(Tox *m, ToxWindow *prompt)
}
}
-int f_loadfromfile;
+static void load_friendlist(Tox *m)
+{
+ int 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
@@ -347,12 +379,7 @@ static void load_data(Tox *m, char *path)
}
tox_load(m, buf, len);
-
- uint32_t i = 0;
- uint8_t name[TOX_MAX_NAME_LENGTH];
-
- while (tox_get_name(m, i, name) != -1)
- on_friendadded(m, i++, false);
+ load_friendlist(m);
free(buf);
fclose(fd);
@@ -367,88 +394,15 @@ static void load_data(Tox *m, char *path)
}
}
-void close_file_sender(int i)
-{
- fclose(file_senders[i].file);
- memset(&file_senders[i], 0, sizeof(FileSender));
-
- int j;
-
- for (j = max_file_senders_index; j > 0; --j) {
- if (file_senders[j-1].active)
- break;
- }
-
- max_file_senders_index = j;
-}
-
-static void do_file_senders(Tox *m)
-{
- int i;
-
- for (i = 0; i < max_file_senders_index; ++i) {
- if (!file_senders[i].active)
- continue;
-
- uint8_t *pathname = file_senders[i].pathname;
- uint8_t filenum = file_senders[i].filenum;
- int friendnum = file_senders[i].friendnum;
- FILE *fp = file_senders[i].file;
- uint64_t current_time = (uint64_t) time(NULL);
-
- /* If file transfer has timed out kill transfer and send kill control */
- if (timed_out(file_senders[i].timestamp, current_time, TIMEOUT_FILESENDER)) {
- ChatContext *ctx = file_senders[i].toxwin->chatwin;
-
- if (ctx != NULL) {
- wprintw(ctx->history, "File transfer for '%s' timed out.\n", pathname);
- alert_window(file_senders[i].toxwin, WINDOW_ALERT_2, true);
- }
-
- tox_file_send_control(m, friendnum, 0, filenum, TOX_FILECONTROL_KILL, 0, 0);
- close_file_sender(i);
- continue;
- }
-
- while (true) {
- if (tox_file_send_data(m, friendnum, filenum, file_senders[i].nextpiece,
- file_senders[i].piecelen) == -1)
- break;
-
- file_senders[i].timestamp = current_time;
- file_senders[i].piecelen = fread(file_senders[i].nextpiece, 1,
- tox_file_data_size(m, friendnum), fp);
-
- if (file_senders[i].piecelen == 0) {
- ChatContext *ctx = file_senders[i].toxwin->chatwin;
-
- if (ctx != NULL) {
- wprintw(ctx->history, "File '%s' successfuly sent.\n", pathname);
- alert_window(file_senders[i].toxwin, WINDOW_ALERT_2, true);
- }
-
- tox_file_send_control(m, friendnum, 0, filenum, TOX_FILECONTROL_FINISHED, 0, 0);
- close_file_sender(i);
- break;
- }
- }
- }
-}
-
void exit_toxic(Tox *m)
{
store_data(m, DATA_FILE);
-
- int i;
-
- for (i = 0; i < max_file_senders_index; ++i) {
- if (file_senders[i].active)
- fclose(file_senders[i].file);
- }
-
+ close_all_file_senders();
+ kill_all_windows();
+ log_disable(prompt->promptbuf->log);
free(DATA_FILE);
- free(SRVLIST_FILE);
free(prompt->stb);
+ free(prompt->promptbuf->log);
free(prompt->promptbuf);
tox_kill(m);
endwin();
@@ -475,7 +429,7 @@ int main(int argc, char *argv[])
int i = 0;
int f_use_ipv4 = 0;
- // Make sure all written files are read/writeable only by the current user.
+ /* Make sure all written files are read/writeable only by the current user. */
umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
for (i = 0; i < argc; ++i) {
@@ -504,7 +458,7 @@ int main(int argc, char *argv[])
if (DATA_FILE != NULL) {
strcpy(DATA_FILE, user_config_dir);
strcat(DATA_FILE, CONFIGDIR);
- strcat(DATA_FILE, "data");
+ strcat(DATA_FILE, "data");
} else {
endwin();
fprintf(stderr, "malloc() failed. Aborting...\n");
@@ -513,21 +467,6 @@ int main(int argc, char *argv[])
}
}
- if (config_err) {
- SRVLIST_FILE = strdup(PACKAGE_DATADIR "/DHTservers");
- } else {
- SRVLIST_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen("DHTservers") + 1);
- if (SRVLIST_FILE != NULL) {
- strcpy(SRVLIST_FILE, user_config_dir);
- strcat(SRVLIST_FILE, CONFIGDIR);
- strcat(SRVLIST_FILE, "DHTservers");
- } else {
- endwin();
- fprintf(stderr, "malloc() failed. Aborting...\n");
- exit(EXIT_FAILURE);
- }
- }
-
free(user_config_dir);
init_term();
@@ -577,7 +516,8 @@ int main(int argc, char *argv[])
prompt_init_statusbar(prompt, m);
sort_friendlist_index(m);
- while (true) do_toxic(m, prompt);
+ while (true)
+ do_toxic(m, prompt);
#ifdef _SUPPORT_AUDIO
terminate_audio(prompt, av);
diff --git a/src/misc_tools.c b/src/misc_tools.c
index 395a25b..be41bc1 100644
--- a/src/misc_tools.c
+++ b/src/misc_tools.c
@@ -1,5 +1,23 @@
-/*
- * Toxic -- Tox Curses Client
+/* misc_tools.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 .
+ *
*/
#include
@@ -52,8 +70,8 @@ void print_time(WINDOW *window)
wattroff(window,COLOR_PAIR(BLUE));
}
-/* Returns 1 if the string is empty, 0 otherwise */
-int string_is_empty(char *string)
+/* Returns true if the string is empty, false otherwise */
+bool string_is_empty(char *string)
{
return string[0] == '\0';
}
diff --git a/src/misc_tools.h b/src/misc_tools.h
index a3f223c..af264b9 100644
--- a/src/misc_tools.h
+++ b/src/misc_tools.h
@@ -1,9 +1,27 @@
-/*
- * Toxic -- Tox Curses Client
+/* misc_tools.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 .
+ *
*/
-// #define MIN(x, y) (((x) < (y)) ? (x) : (y))
- #define MAX(x, y) (((x) > (y)) ? (x) : (y))
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+#define MAX(x, y) (((x) > (y)) ? (x) : (y))
/* convert a hex string to binary */
unsigned char *hex_string_to_bin(char hex_string[]);
@@ -14,8 +32,8 @@ struct tm *get_time(void);
/* Prints the time to given window */
void print_time(WINDOW *window);
-/* Returns 1 if the string is empty, 0 otherwise */
-int string_is_empty(char *string);
+/* Returns true if the string is empty, false otherwise */
+bool string_is_empty(char *string);
/* convert a multibyte string to a wide character string (must provide buffer) */
int char_to_wcs_buf(wchar_t *buf, const uint8_t *string, size_t n);
diff --git a/src/prompt.c b/src/prompt.c
index 6d0a238..bda06e0 100644
--- a/src/prompt.c
+++ b/src/prompt.c
@@ -1,5 +1,23 @@
-/*
- * Toxic -- Tox Curses Client
+/* prompt.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
@@ -30,6 +48,7 @@ const uint8_t glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/groupchat" },
{ "/help" },
{ "/join" },
+ { "/log" },
{ "/myid" },
{ "/nick" },
{ "/note" },
@@ -154,12 +173,12 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key)
beep();
}
- else if (key == KEY_HOME) { /* HOME key: Move cursor to beginning of line */
+ else if (key == KEY_HOME || key == T_KEY_C_A) { /* HOME/C-a key: Move cursor to start of line */
if (prt->pos != 0)
prt->pos = 0;
}
- else if (key == KEY_END) { /* END key: move cursor to end of line */
+ else if (key == KEY_END || key == T_KEY_C_E) { /* END/C-e key: move cursor to end of line */
if (prt->pos != prt->len)
prt->pos = prt->len;
}
@@ -341,6 +360,18 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
static void prompt_onInit(ToxWindow *self, Tox *m)
{
scrollok(self->window, true);
+ PromptBuf *prt = self->promptbuf;
+
+ prt->log = malloc(sizeof(struct chatlog));
+
+ if (prt->log == NULL) {
+ endwin();
+ fprintf(stderr, "malloc() failed. Aborting...\n");
+ exit(EXIT_FAILURE);
+ }
+
+ memset(prt->log, 0, sizeof(struct chatlog));
+
execute(self->window, self, m, "/help", GLOBAL_COMMAND_MODE);
wclrtoeol(self->window);
}
@@ -350,6 +381,7 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, int friendnum , u
if (friendnum < 0)
return;
+ PromptBuf *prt = self->promptbuf;
prep_prompt_win();
uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'};
@@ -363,22 +395,29 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, int friendnum , u
wprintw(self->window, "\n");
print_time(self->window);
+ uint8_t *msg;
+
if (status == 1) {
+ msg = "has come online";
wattron(self->window, COLOR_PAIR(GREEN));
wattron(self->window, A_BOLD);
wprintw(self->window, "* %s ", nick);
wattroff(self->window, A_BOLD);
- wprintw(self->window, "has come online\n");
+ wprintw(self->window, "%s\n", msg);
wattroff(self->window, COLOR_PAIR(GREEN));
+ write_to_log(msg, nick, prt->log, true);
alert_window(self, WINDOW_ALERT_2, false);
} else {
+ msg = "has gone offline";
wattron(self->window, COLOR_PAIR(RED));
wattron(self->window, A_BOLD);
wprintw(self->window, "* %s ", nick);
wattroff(self->window, A_BOLD);
- wprintw(self->window, "has gone offline\n");
+ wprintw(self->window, "%s\n", msg);
wattroff(self->window, COLOR_PAIR(RED));
+
+ write_to_log(msg, nick, prt->log, true);
}
}
@@ -386,16 +425,23 @@ static void prompt_onFriendRequest(ToxWindow *self, uint8_t *key, uint8_t *data,
{
// make sure message data is null-terminated
data[length - 1] = 0;
-
+ PromptBuf *prt = self->promptbuf;
prep_prompt_win();
+
wprintw(self->window, "\n");
print_time(self->window);
- wprintw(self->window, "Friend request with the message: '%s'\n", data);
+
+ uint8_t msg[MAX_STR_SIZE];
+ snprintf(msg, sizeof(msg), "Friend request with the message '%s'\n", data);
+ wprintw(self->window, "%s", msg);
+ write_to_log(msg, "", prt->log, true);
int n = add_friend_request(key);
if (n == -1) {
- wprintw(self->window, "Friend request queue is full. Discarding request.\n");
+ uint8_t *errmsg = "Friend request queue is full. Discarding request.\n";
+ wprintw(self->window, "%s", errmsg);
+ write_to_log(errmsg, "", prt->log, true);
return;
}
@@ -441,6 +487,7 @@ ToxWindow new_prompt(void)
memset(&ret, 0, sizeof(ret));
ret.active = true;
+ ret.is_prompt = true;
ret.onKey = &prompt_onKey;
ret.onDraw = &prompt_onDraw;
diff --git a/src/prompt.h b/src/prompt.h
index 7652503..51acd59 100644
--- a/src/prompt.h
+++ b/src/prompt.h
@@ -1,5 +1,23 @@
-/*
- * Toxic -- Tox Curses Client
+/* prompt.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 PROMPT_H_UZYGWFFL
@@ -7,7 +25,7 @@
#define X_OFST 2 /* offset to account for prompt char */
-#define AC_NUM_GLOB_COMMANDS 14
+#define AC_NUM_GLOB_COMMANDS 15
ToxWindow new_prompt(void);
void prep_prompt_win(void);
diff --git a/src/toxic_strings.c b/src/toxic_strings.c
index 15cff71..efebc03 100644
--- a/src/toxic_strings.c
+++ b/src/toxic_strings.c
@@ -1,5 +1,23 @@
-/*
- * Toxic -- Tox Curses Client
+/* toxic_strings.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 .
+ *
*/
#include
@@ -120,19 +138,21 @@ void add_line_to_hist(const wchar_t *buf, size_t len, wchar_t (*hst)[MAX_STR_SIZ
}
/* copies history item at hst_pos to buf. Sets pos and len to the len of the history item.
- hst_pos is decremented or incremented depending on key_dir. */
+ hst_pos is decremented or incremented depending on key_dir.
+
+ resets buffer if at end of history */
void fetch_hist_item(wchar_t *buf, size_t *pos, size_t *len, wchar_t (*hst)[MAX_STR_SIZE],
int hst_tot, int *hst_pos, int key_dir)
{
if (key_dir == LN_HIST_MV_UP) {
if (--(*hst_pos) < 0) {
- ++(*hst_pos);
+ *hst_pos = 0;
beep();
}
} else {
if (++(*hst_pos) >= hst_tot) {
- --(*hst_pos);
- beep();
+ *hst_pos = hst_tot;
+ reset_buf(buf, pos, len);
return;
}
}
diff --git a/src/toxic_strings.h b/src/toxic_strings.h
index f97dd20..3e28c0f 100644
--- a/src/toxic_strings.h
+++ b/src/toxic_strings.h
@@ -1,5 +1,23 @@
-/*
- * Toxic -- Tox Curses Client
+/* toxic_strings.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 .
+ *
*/
/* Adds char to buffer at pos */
diff --git a/src/toxic_windows.h b/src/toxic_windows.h
index 58fac0f..93618c6 100644
--- a/src/toxic_windows.h
+++ b/src/toxic_windows.h
@@ -1,5 +1,23 @@
-/*
- * Toxic -- Tox Curses Client
+/* toxic_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
@@ -40,6 +58,8 @@
#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 */
/* Curses foreground colours (background is black) */
enum {
@@ -88,6 +108,7 @@ struct ToxWindow {
void(*onFileSendRequest)(ToxWindow *, Tox *, int, uint8_t, uint64_t, uint8_t *, uint16_t);
void(*onFileControl)(ToxWindow *, Tox *, int, uint8_t, uint8_t, uint8_t, uint8_t *, uint16_t);
void(*onFileData)(ToxWindow *, Tox *, int, uint8_t, uint8_t *, uint16_t);
+ void(*onTypingChange)(ToxWindow *, Tox *, int, int);
#ifdef _SUPPORT_AUDIO
@@ -109,6 +130,11 @@ struct ToxWindow {
bool active;
int x;
+ /* window type identifiers */
+ bool is_chat;
+ bool is_groupchat;
+ bool is_prompt;
+
bool alert0;
bool alert1;
bool alert2;
@@ -131,6 +157,15 @@ struct StatusBar {
bool is_online;
};
+#define LOG_FLUSH_LIMIT 2 /* limits calls to fflush(logfile) to a max of one per LOG_FLUSH_LIMIT seconds */
+
+struct chatlog {
+ FILE *file;
+ uint64_t lastwrite;
+ int pos;
+ bool log_on; /* specific to current chat window */
+};
+
#define MAX_LINE_HIST 128
/* chat and groupchat window/buffer holder */
@@ -143,6 +178,10 @@ struct ChatContext {
int hst_pos;
int hst_tot;
+ bool self_is_typing;
+
+ struct chatlog *log;
+
WINDOW *history;
WINDOW *linewin;
WINDOW *sidebar;
@@ -153,6 +192,7 @@ struct PromptBuf {
wchar_t line[MAX_STR_SIZE];
size_t pos;
size_t len;
+
bool at_bottom; /* true if line end is at bottom of window */
int orig_y; /* y axis point of line origin */
bool scroll; /* used for prompt window hack to determine when to scroll down */
@@ -161,6 +201,7 @@ struct PromptBuf {
int hst_pos;
int hst_tot;
+ struct chatlog *log;
WINDOW *linewin;
};
@@ -184,6 +225,7 @@ typedef struct {
struct FileReceiver {
uint8_t filenames[MAX_FILES][MAX_STR_SIZE];
+ FILE *files[MAX_FILES];
bool pending[MAX_FILES];
};
@@ -204,6 +246,7 @@ void on_group_namelistchange(Tox *m, int groupnumber, int peernumber, uint8_t ch
void on_file_sendrequest(Tox *m, int friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *pathname, uint16_t pathname_length, void *userdata);
void on_file_control(Tox *m, int 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, int friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata);
+void on_typing_change(Tox *m, int friendnumber, int is_typing, void *userdata);
ToxWindow *init_windows(Tox *m);
void draw_active_window(Tox *m);
@@ -211,4 +254,7 @@ int add_window(Tox *m, ToxWindow w);
void del_window(ToxWindow *w);
void set_active_window(int ch);
int num_active_windows(void);
+
+/* cleans up all chat and groupchat windows (should only be called on shutdown) */
+void kill_all_windows(void);
#endif
diff --git a/src/windows.c b/src/windows.c
index 8e068f5..e5dd40f 100644
--- a/src/windows.c
+++ b/src/windows.c
@@ -1,3 +1,25 @@
+/* windows.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
@@ -8,6 +30,7 @@
#include "friendlist.h"
#include "prompt.h"
#include "toxic_windows.h"
+#include "groupchat.h"
extern char *DATA_FILE;
@@ -37,6 +60,16 @@ void on_connectionchange(Tox *m, int friendnumber, uint8_t status, void *userdat
}
}
+void on_typing_change(Tox *m, int friendnumber, int is_typing, void *userdata)
+{
+ int i;
+
+ for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
+ if (windows[i].onTypingChange != NULL)
+ windows[i].onTypingChange(&windows[i], m, friendnumber, is_typing);
+ }
+}
+
void on_message(Tox *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata)
{
int i;
@@ -377,3 +410,16 @@ int num_active_windows(void)
return count;
}
+
+/* destroys all chat and groupchat windows (should only be called on shutdown) */
+void kill_all_windows(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
+ if (windows[i].is_chat)
+ kill_chat_window(&windows[i]);
+ else if (windows[i].is_groupchat)
+ kill_groupchat_window(&windows[i]);
+ }
+}