mirror of
https://github.com/Tha14/toxic.git
synced 2024-11-13 01:53:01 +01:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
cb9622136c
@ -7,6 +7,7 @@ Toxic is an ncurses based instant messaging client for [Tox](http://tox.im) whic
|
||||
* 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/ ```
|
||||
|
||||
* Compile with --disable-av to build without audio call support
|
||||
* Compile and install the program with ```make && sudo make install```
|
||||
|
||||
#### Notes
|
||||
|
@ -29,7 +29,9 @@ toxic_SOURCES = $(top_srcdir)/src/main.c \
|
||||
$(top_srcdir)/src/log.c \
|
||||
$(top_srcdir)/src/log.h \
|
||||
$(top_srcdir)/src/file_senders.c \
|
||||
$(top_srcdir)/src/file_senders.h
|
||||
$(top_srcdir)/src/file_senders.h \
|
||||
$(top_srcdir)/src/line_info.c \
|
||||
$(top_srcdir)/src/line_info.h
|
||||
|
||||
toxic_CFLAGS = -I$(top_srcdir) \
|
||||
$(NCURSES_CFLAGS) \
|
||||
|
@ -2,7 +2,7 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ([2.65])
|
||||
AC_INIT([toxic], [0.3.0], [https://tox.im/])
|
||||
AC_INIT([toxic], [0.3.2], [https://tox.im/])
|
||||
AC_CONFIG_AUX_DIR(configure_aux)
|
||||
AC_CONFIG_SRCDIR([src/main.c])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
@ -1,2 +1,8 @@
|
||||
192.254.75.98 33445 FE3914F4616E227F29B2103450D6B55A836AD4BD23F97144E2C4ABE8D504FE1B
|
||||
2607:5600:284::2 33445 FE3914F4616E227F29B2103450D6B55A836AD4BD23F97144E2C4ABE8D504FE1B
|
||||
23.226.230.47 33445 A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074
|
||||
173.255.223.85 33445 92E0CE88651FC89D54D6A3110FD08854ECD487613E69BFB1002380D35FD4F947
|
||||
144.76.60.215 33445 04119E835DF3E78BACF0F84235B300546AF8B936F035185E2A8E9E0A67C8924F
|
||||
109.169.46.133 33445 4086B340BF2C2C3CC5412BCF673080EF10CF5E75A06AC960497BD85B9DEA2E64
|
||||
54.199.139.199 33445 7F9C31FE850E97CEFD4C4591DF93FC757C7C12549DDD55F8EEAECC34FE76C029
|
||||
66.175.223.88 33445 B24E2FB924AE66D023FE1E42A2EE3B432010206F751A2FFD3E297383ACF1572E
|
||||
|
135
src/audio_call.c
135
src/audio_call.c
@ -11,6 +11,7 @@
|
||||
#include "chat_commands.h"
|
||||
#include "global_commands.h"
|
||||
#include "toxic_windows.h"
|
||||
#include "line_info.h"
|
||||
|
||||
#include <curses.h>
|
||||
#include <AL/al.h>
|
||||
@ -51,7 +52,6 @@ struct _ASettings {
|
||||
int ttas; /* Transmission thread active status (0 - stopped, 1- running) */
|
||||
} ASettins;
|
||||
|
||||
|
||||
void callback_recv_invite ( void *arg );
|
||||
void callback_recv_ringing ( void *arg );
|
||||
void callback_recv_starting ( void *arg );
|
||||
@ -65,16 +65,24 @@ void callback_requ_timeout ( void *arg );
|
||||
void callback_peer_timeout ( void* arg );
|
||||
|
||||
|
||||
static void print_err (ToxWindow *self, uint8_t *error_str)
|
||||
{
|
||||
line_info_add(self, NULL, NULL, NULL, error_str, SYS_MSG, 0, 0);
|
||||
}
|
||||
|
||||
/* Opens device under current index
|
||||
*/
|
||||
int device_open (WINDOW *window, _Devices type)
|
||||
int device_open (ToxWindow *self, _Devices type)
|
||||
{
|
||||
WINDOW *window = self->chatwin->history;
|
||||
|
||||
/* Do not error if no device */
|
||||
if ( !ASettins.device[type].size ) return 0;
|
||||
|
||||
ALCdevice* prev_device = ASettins.device[type].dhndl;
|
||||
|
||||
const char* error = NULL;
|
||||
uint8_t msg[MAX_STR_SIZE];
|
||||
uint8_t* error = NULL;
|
||||
|
||||
if ( type == input ) {
|
||||
ASettins.device[type].dhndl = alcCaptureOpenDevice(
|
||||
@ -101,7 +109,10 @@ int device_open (WINDOW *window, _Devices type)
|
||||
if ( prev_device )
|
||||
alcCaptureCloseDevice(prev_device);
|
||||
|
||||
if ( window ) wprintw(window, "Input device: %s\n", ASettins.device[type].devices[ASettins.device[type].index]);
|
||||
if ( window ) {
|
||||
snprintf(msg, sizeof(msg), "Input device: %s", ASettins.device[type].devices[ASettins.device[type].index]);
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
ASettins.device[type].ctx = NULL;
|
||||
@ -136,20 +147,27 @@ int device_open (WINDOW *window, _Devices type)
|
||||
|
||||
ASettins.device[type].ctx = alcCreateContext(ASettins.device[type].dhndl, NULL);
|
||||
|
||||
if ( window ) wprintw(window, "Output device: %s\n", ASettins.device[type].devices[ASettins.device[type].index]);
|
||||
if ( window ) {
|
||||
snprintf(msg, sizeof(msg), "Output device: %s", ASettins.device[type].devices[ASettins.device[type].index]);
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( error ) {
|
||||
if ( window ) wprintw(window, "Error: %s\n", error);
|
||||
if ( window ) {
|
||||
snprintf(msg, sizeof(msg), "Error: %s", error);
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
|
||||
int device_close (WINDOW *window, _Devices type)
|
||||
int device_close (ToxWindow *self, _Devices type)
|
||||
{
|
||||
const char* device = NULL;
|
||||
uint8_t* device = NULL;
|
||||
|
||||
if ( ASettins.device[type].dhndl ) {
|
||||
if (type == input) {
|
||||
@ -169,11 +187,14 @@ int device_close (WINDOW *window, _Devices type)
|
||||
ASettins.device[type].index = ASettins.device[type].dix;
|
||||
}
|
||||
|
||||
if ( window && device ) wprintw(window, "Closed %s device\n", device);
|
||||
if ( self && device ) {
|
||||
uint8_t msg[MAX_STR_SIZE];
|
||||
snprintf(msg, sizeof(msg), "Closed %s device", device);
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ToxAv* init_audio(ToxWindow* window, Tox* tox)
|
||||
ToxAv* init_audio(ToxWindow* self, Tox* tox)
|
||||
{
|
||||
ASettins.errors = NoError;
|
||||
ASettins.ttas = 0; /* Not running */
|
||||
@ -214,7 +235,8 @@ ToxAv* init_audio(ToxWindow* window, Tox* tox)
|
||||
}
|
||||
|
||||
if (!ASettins.device[input].size && !ASettins.device[output].size) {
|
||||
wprintw(window->window, "No devices: disabling audio!\n");
|
||||
uint8_t *msg = "No devices: disabling audio!";
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
ASettins.av = NULL;
|
||||
}
|
||||
else {
|
||||
@ -230,19 +252,19 @@ ToxAv* init_audio(ToxWindow* window, Tox* tox)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
toxav_register_callstate_callback(callback_call_started, av_OnStart, window);
|
||||
toxav_register_callstate_callback(callback_call_canceled, av_OnCancel, window);
|
||||
toxav_register_callstate_callback(callback_call_rejected, av_OnReject, window);
|
||||
toxav_register_callstate_callback(callback_call_ended, av_OnEnd, window);
|
||||
toxav_register_callstate_callback(callback_recv_invite, av_OnInvite, window);
|
||||
toxav_register_callstate_callback(callback_call_started, av_OnStart, self);
|
||||
toxav_register_callstate_callback(callback_call_canceled, av_OnCancel, self);
|
||||
toxav_register_callstate_callback(callback_call_rejected, av_OnReject, self);
|
||||
toxav_register_callstate_callback(callback_call_ended, av_OnEnd, self);
|
||||
toxav_register_callstate_callback(callback_recv_invite, av_OnInvite, self);
|
||||
|
||||
toxav_register_callstate_callback(callback_recv_ringing, av_OnRinging, window);
|
||||
toxav_register_callstate_callback(callback_recv_starting, av_OnStarting, window);
|
||||
toxav_register_callstate_callback(callback_recv_ending, av_OnEnding, window);
|
||||
toxav_register_callstate_callback(callback_recv_ringing, av_OnRinging, self);
|
||||
toxav_register_callstate_callback(callback_recv_starting, av_OnStarting, self);
|
||||
toxav_register_callstate_callback(callback_recv_ending, av_OnEnding, self);
|
||||
|
||||
toxav_register_callstate_callback(callback_recv_error, av_OnError, window);
|
||||
toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout, window);
|
||||
toxav_register_callstate_callback(callback_peer_timeout, av_OnPeerTimeout, window);
|
||||
toxav_register_callstate_callback(callback_recv_error, av_OnError, self);
|
||||
toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout, self);
|
||||
toxav_register_callstate_callback(callback_peer_timeout, av_OnPeerTimeout, self);
|
||||
}
|
||||
|
||||
return ASettins.av;
|
||||
@ -256,7 +278,6 @@ void terminate_audio()
|
||||
toxav_kill(ASettins.av);
|
||||
}
|
||||
|
||||
|
||||
int errors()
|
||||
{
|
||||
return ASettins.errors;
|
||||
@ -376,7 +397,7 @@ cleanup:
|
||||
_cbend;
|
||||
}
|
||||
|
||||
int start_transmission()
|
||||
int start_transmission(ToxWindow *self)
|
||||
{
|
||||
if ( !ASettins.av ) return -1;
|
||||
|
||||
@ -385,9 +406,9 @@ int start_transmission()
|
||||
return -1;
|
||||
|
||||
/* Now open our devices */
|
||||
if ( -1 == device_open(NULL, input) )
|
||||
if ( -1 == device_open(self, input) )
|
||||
return -1;
|
||||
if ( -1 == device_open(NULL, output))
|
||||
if ( -1 == device_open(self, output))
|
||||
return -1;
|
||||
|
||||
/* Don't provide support for video */
|
||||
@ -483,7 +504,8 @@ void callback_peer_timeout ( void* arg )
|
||||
*/
|
||||
void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
const char* error_str;
|
||||
uint8_t msg[MAX_STR_SIZE];
|
||||
uint8_t* error_str;
|
||||
|
||||
if (argc != 0) { error_str = "Invalid syntax!"; goto on_error; }
|
||||
|
||||
@ -497,17 +519,19 @@ void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
||||
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
wprintw(window, "Calling...\n");
|
||||
|
||||
|
||||
error_str = "Calling...";
|
||||
line_info_add(self, NULL, NULL, NULL, error_str, SYS_MSG, 0, 0);
|
||||
|
||||
return;
|
||||
on_error:
|
||||
wprintw(window, "%s\n", error_str);
|
||||
on_error:
|
||||
snprintf(msg, sizeof(msg), "%s", error_str);
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
}
|
||||
|
||||
void cmd_answer(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
const char* error_str;
|
||||
uint8_t* error_str;
|
||||
|
||||
if (argc != 0) { error_str = "Invalid syntax!"; goto on_error; }
|
||||
|
||||
@ -527,12 +551,12 @@ void cmd_answer(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
||||
|
||||
return;
|
||||
on_error:
|
||||
wprintw(window, "%s\n", error_str);
|
||||
print_err (self, error_str);
|
||||
}
|
||||
|
||||
void cmd_reject(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
const char* error_str;
|
||||
uint8_t* error_str;
|
||||
|
||||
if (argc != 0) { error_str = "Invalid syntax!"; goto on_error; }
|
||||
|
||||
@ -552,12 +576,12 @@ void cmd_reject(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
||||
|
||||
return;
|
||||
on_error:
|
||||
wprintw(window, "%s\n", error_str);
|
||||
print_err (self, error_str);
|
||||
}
|
||||
|
||||
void cmd_hangup(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
const char* error_str;
|
||||
uint8_t* error_str;
|
||||
|
||||
if (argc != 0) { error_str = "Invalid syntax!"; goto on_error; }
|
||||
|
||||
@ -575,12 +599,12 @@ void cmd_hangup(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
||||
|
||||
return;
|
||||
on_error:
|
||||
wprintw(window, "%s\n", error_str);
|
||||
print_err (self, error_str);
|
||||
}
|
||||
|
||||
void cmd_cancel(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
const char* error_str;
|
||||
uint8_t* error_str;
|
||||
|
||||
if (argc != 0) { error_str = "Invalid syntax!"; goto on_error; }
|
||||
|
||||
@ -599,13 +623,14 @@ void cmd_cancel(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
||||
|
||||
return;
|
||||
on_error:
|
||||
wprintw(window, "%s\n", error_str);
|
||||
print_err (self, error_str);
|
||||
}
|
||||
|
||||
|
||||
void cmd_list_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
const char* error_str;
|
||||
uint8_t msg[MAX_STR_SIZE];
|
||||
uint8_t* error_str;
|
||||
|
||||
if ( argc != 1 ) {
|
||||
if ( argc < 1 ) error_str = "Type must be specified!";
|
||||
@ -623,22 +648,26 @@ void cmd_list_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*
|
||||
type = output;
|
||||
|
||||
else {
|
||||
wprintw(window, "Invalid type: %s\n", argv[1]);
|
||||
snprintf(msg, sizeof(msg), "Invalid type: %s", argv[1]);
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for ( ; i < ASettins.device[type].size; i ++)
|
||||
wprintw(window, "%d: %s\n", i, ASettins.device[type].devices[i]);
|
||||
|
||||
for ( ; i < ASettins.device[type].size; i ++) {
|
||||
snprintf(msg, sizeof(msg), "%d: %s", i, ASettins.device[type].devices[i]);
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
}
|
||||
|
||||
return;
|
||||
on_error:
|
||||
wprintw(window, "%s\n", error_str);
|
||||
print_err (self, error_str);
|
||||
}
|
||||
|
||||
void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
const char* error_str;
|
||||
uint8_t msg[MAX_STR_SIZE];
|
||||
uint8_t* error_str;
|
||||
|
||||
if ( argc != 2 ) {
|
||||
if ( argc < 1 ) error_str = "Type must be specified!";
|
||||
@ -662,7 +691,8 @@ void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (
|
||||
type = output;
|
||||
|
||||
else {
|
||||
wprintw(window, "Invalid type: %s\n", argv[1]);
|
||||
snprintf(msg, sizeof(msg), "Invalid type: %s", argv[1]);
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -681,9 +711,10 @@ void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (
|
||||
}
|
||||
|
||||
ASettins.device[type].index = selection;
|
||||
wprintw(window, "Selected: %s\n", ASettins.device[type].devices[selection]);
|
||||
snprintf(msg, sizeof(msg), "Selected: %s", ASettins.device[type].devices[selection]);
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
|
||||
return;
|
||||
on_error:
|
||||
wprintw(window, "%s\n", error_str);
|
||||
}
|
||||
print_err (self, error_str);
|
||||
}
|
||||
|
@ -20,11 +20,11 @@ typedef enum _AudioError
|
||||
/* You will have to pass pointer to first member of 'windows'
|
||||
* declared in windows.c otherwise undefined behaviour will
|
||||
*/
|
||||
ToxAv* init_audio(ToxWindow* window, Tox* tox);
|
||||
ToxAv* init_audio(ToxWindow* self, Tox* tox);
|
||||
void terminate_audio();
|
||||
|
||||
int errors();
|
||||
|
||||
int start_transmission();
|
||||
int start_transmission(ToxWindow *self);
|
||||
|
||||
#endif /* _audio_h */
|
695
src/chat.c
695
src/chat.c
File diff suppressed because it is too large
Load Diff
@ -26,6 +26,6 @@
|
||||
#include "toxic_windows.h"
|
||||
|
||||
void kill_chat_window(ToxWindow *self);
|
||||
ToxWindow new_chat(Tox *m, int friendnum);
|
||||
ToxWindow new_chat(Tox *m, int32_t friendnum);
|
||||
|
||||
#endif /* end of include guard: CHAT_H_6489PZ13 */
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "misc_tools.h"
|
||||
#include "friendlist.h"
|
||||
#include "execute.h"
|
||||
#include "line_info.h"
|
||||
|
||||
extern ToxWindow *prompt;
|
||||
|
||||
@ -41,6 +42,10 @@ extern uint8_t max_file_senders_index;
|
||||
|
||||
void cmd_chat_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
struct history *hst = self->chatwin->hst;
|
||||
line_info_clear(hst);
|
||||
struct line_info *start = hst->line_start;
|
||||
|
||||
if (argc == 1) {
|
||||
if (!strcmp(argv[1], "global")) {
|
||||
execute(window, self, m, "/help", GLOBAL_COMMAND_MODE);
|
||||
@ -48,81 +53,103 @@ void cmd_chat_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
|
||||
}
|
||||
}
|
||||
|
||||
wattron(window, COLOR_PAIR(CYAN) | A_BOLD);
|
||||
wprintw(window, "Chat commands:\n");
|
||||
wattroff(window, COLOR_PAIR(CYAN) | A_BOLD);
|
||||
uint8_t *msg = "Chat commands:";
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
|
||||
|
||||
#ifdef _SUPPORT_AUDIO
|
||||
#define NUMLINES 13
|
||||
#else
|
||||
#define NUMLINES 9
|
||||
#endif
|
||||
|
||||
wprintw(window, " /call : Audio call\n");
|
||||
wprintw(window, " /cancel : Cancel call\n");
|
||||
wprintw(window, " /answer : Answer incomming call\n");
|
||||
wprintw(window, " /reject : Reject incomming call\n");
|
||||
wprintw(window, " /hangup : Hangup active call\n");
|
||||
uint8_t lines[NUMLINES][MAX_STR_SIZE] = {
|
||||
|
||||
#ifdef _SUPPORT_AUDIO
|
||||
{ " /call : Audio call" },
|
||||
{ " /cancel : Cancel call" },
|
||||
{ " /answer : Answer incomming call" },
|
||||
{ " /reject : Reject incoming call" },
|
||||
{ " /hangup : Hangup active call" },
|
||||
#endif /* _SUPPORT_AUDIO */
|
||||
|
||||
wprintw(window, " /invite <n> : Invite friend to a group chat\n");
|
||||
wprintw(window, " /join : Join a pending group chat\n");
|
||||
wprintw(window, " /log <on> or <off> : Enable/disable logging\n");
|
||||
wprintw(window, " /sendfile <filepath> : Send a file\n");
|
||||
wprintw(window, " /savefile <n> : 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");
|
||||
wattroff(window, COLOR_PAIR(CYAN) | A_BOLD);
|
||||
{ " /invite <n> : Invite friend to a group chat" },
|
||||
{ " /join : Join a pending group chat" },
|
||||
{ " /log <on> or <off> : Enable/disable logging" },
|
||||
{ " /sendfile <filepath> : Send a file" },
|
||||
{ " /savefile <n> : Receive a file" },
|
||||
{ " /close : Close the current chat window" },
|
||||
{ " /help : Print this message again" },
|
||||
{ " /help global : Show a list of global commands" },
|
||||
};
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUMLINES; ++i)
|
||||
line_info_add(self, NULL, NULL, NULL, lines[i], SYS_MSG, 0, 0);
|
||||
|
||||
msg = " * Use ESC key to toggle history scroll mode\n";
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
|
||||
|
||||
hst->line_start = start;
|
||||
}
|
||||
|
||||
void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
uint8_t *errmsg;
|
||||
|
||||
if (argc < 1) {
|
||||
wprintw(window, "Invalid syntax.\n");
|
||||
return;
|
||||
errmsg = "Invalid syntax";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
int groupnum = atoi(argv[1]);
|
||||
|
||||
if (groupnum == 0 && strcmp(argv[1], "0")) { /* atoi returns 0 value on invalid input */
|
||||
wprintw(window, "Invalid syntax.\n");
|
||||
errmsg = "Invalid syntax.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tox_invite_friend(m, self->num, groupnum) == -1) {
|
||||
wprintw(window, "Failed to invite friend.\n");
|
||||
errmsg = "Failed to invite friend.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
wprintw(window, "Invited friend to group chat %d.\n", groupnum);
|
||||
uint8_t msg[MAX_STR_SIZE];
|
||||
snprintf(msg, sizeof(msg), "Invited friend to Room #%d.", groupnum);
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
}
|
||||
|
||||
void cmd_join_group(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
uint8_t *errmsg;
|
||||
|
||||
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
|
||||
wattron(window, COLOR_PAIR(RED));
|
||||
wprintw(window, " * Warning: Too many windows are open.\n");
|
||||
wattron(window, COLOR_PAIR(RED));
|
||||
errmsg = " * Warning: Too many windows are open.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, RED);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *groupkey = friends[self->num].pending_groupchat;
|
||||
|
||||
if (groupkey[0] == '\0') {
|
||||
wprintw(window, "No pending group chat invite.\n");
|
||||
errmsg = "No pending group chat invite.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
int groupnum = tox_join_groupchat(m, self->num, groupkey);
|
||||
|
||||
if (groupnum == -1) {
|
||||
wprintw(window, "Group chat instance failed to initialize.\n");
|
||||
errmsg = "Group chat instance failed to initialize.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (init_groupchat_win(prompt, m, groupnum) == -1) {
|
||||
wprintw(window, "Group chat window failed to initialize.\n");
|
||||
errmsg = "Group chat window failed to initialize.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
tox_del_groupchat(m, groupnum);
|
||||
return;
|
||||
}
|
||||
@ -130,36 +157,44 @@ void cmd_join_group(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
|
||||
|
||||
void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
uint8_t *errmsg;
|
||||
|
||||
if (argc != 1) {
|
||||
wprintw(window, "Invalid syntax.\n");
|
||||
errmsg = "Invalid syntax.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t filenum = atoi(argv[1]);
|
||||
|
||||
if ((filenum == 0 && strcmp(argv[1], "0")) || filenum >= MAX_FILES) {
|
||||
wprintw(window, "No pending file transfers with that number.\n");
|
||||
errmsg = "No pending file transfers with that number.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!friends[self->num].file_receiver.pending[filenum]) {
|
||||
wprintw(window, "No pending file transfers with that number.\n");
|
||||
errmsg = "No pending file transfers with that number.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
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) {
|
||||
wprintw(window, "Accepted file transfer %u. Saving file as: '%s'\n", filenum, filename);
|
||||
uint8_t msg[MAX_STR_SIZE];
|
||||
snprintf(msg, sizeof(msg), "Saving file as: '%s' (%.1f%%)", filename, 0.0);
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
friends[self->num].file_receiver.line_id = self->chatwin->hst->line_end->id;
|
||||
|
||||
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));
|
||||
errmsg = "* Error writing to file.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, RED);
|
||||
tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0);
|
||||
}
|
||||
} else {
|
||||
wprintw(window, "File transfer failed.\n");
|
||||
errmsg = "File transfer failed.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
}
|
||||
|
||||
friends[self->num].file_receiver.pending[filenum] = false;
|
||||
@ -167,20 +202,25 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
||||
|
||||
void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
uint8_t *errmsg;
|
||||
|
||||
if (max_file_senders_index >= (MAX_FILES-1)) {
|
||||
wprintw(window,"Please wait for some of your outgoing file transfers to complete.\n");
|
||||
errmsg = "Please wait for some of your outgoing file transfers to complete.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (argc < 1) {
|
||||
wprintw(window, "Invalid syntax.\n");
|
||||
errmsg = "Invalid syntax.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *path = argv[1];
|
||||
|
||||
if (path[0] != '\"') {
|
||||
wprintw(window, "File path must be enclosed in quotes.\n");
|
||||
errmsg = "File path must be enclosed in quotes.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -188,14 +228,16 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
||||
int path_len = strlen(path);
|
||||
|
||||
if (path_len > MAX_STR_SIZE) {
|
||||
wprintw(window, "File path exceeds character limit.\n");
|
||||
errmsg = "File path exceeds character limit.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
FILE *file_to_send = fopen(path, "r");
|
||||
|
||||
if (file_to_send == NULL) {
|
||||
wprintw(window, "File '%s' not found.\n", path);
|
||||
errmsg = "File not found.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -208,7 +250,8 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
||||
int filenum = tox_new_file_sender(m, self->num, filesize, filename, strlen(filename) + 1);
|
||||
|
||||
if (filenum == -1) {
|
||||
wprintw(window, "Error sending file.\n");
|
||||
errmsg = "Error sending file.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -220,13 +263,16 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
||||
file_senders[i].active = true;
|
||||
file_senders[i].toxwin = self;
|
||||
file_senders[i].file = file_to_send;
|
||||
file_senders[i].filenum = (uint8_t) filenum;
|
||||
file_senders[i].filenum = filenum;
|
||||
file_senders[i].friendnum = self->num;
|
||||
file_senders[i].timestamp = (uint64_t) time(NULL);
|
||||
file_senders[i].timestamp = get_unix_time();
|
||||
file_senders[i].size = filesize;
|
||||
file_senders[i].piecelen = fread(file_senders[i].nextpiece, 1,
|
||||
tox_file_data_size(m, self->num), file_to_send);
|
||||
|
||||
wprintw(window, "Sending file: '%s'\n", path);
|
||||
uint8_t msg[MAX_STR_SIZE];
|
||||
snprintf(msg, sizeof(msg), "Sending file: '%s'", path);
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
|
||||
if (i == max_file_senders_index)
|
||||
++max_file_senders_index;
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "execute.h"
|
||||
#include "chat_commands.h"
|
||||
#include "global_commands.h"
|
||||
#include "line_info.h"
|
||||
|
||||
struct cmd_func {
|
||||
const char *name;
|
||||
@ -77,7 +78,7 @@ static struct cmd_func chat_commands[] = {
|
||||
|
||||
/* Parses input command and puts args into arg array.
|
||||
Returns number of arguments on success, -1 on failure. */
|
||||
static int parse_command(WINDOW *w, char *cmd, char (*args)[MAX_STR_SIZE])
|
||||
static int parse_command(WINDOW *w, ToxWindow *self, char *cmd, char (*args)[MAX_STR_SIZE])
|
||||
{
|
||||
int num_args = 0;
|
||||
bool cmd_end = false; /* flags when we get to the end of cmd */
|
||||
@ -89,7 +90,8 @@ static int parse_command(WINDOW *w, char *cmd, char (*args)[MAX_STR_SIZE])
|
||||
end = strchr(cmd+1, '\"');
|
||||
|
||||
if (end++ == NULL) { /* Increment past the end quote */
|
||||
wprintw(w, "Invalid argument. Did you forget a closing \"?\n");
|
||||
uint8_t *errmsg = "Invalid argument. Did you forget a closing \"?";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -132,7 +134,7 @@ void execute(WINDOW* w, ToxWindow *self, Tox *m, char *cmd, int mode)
|
||||
return;
|
||||
|
||||
char args[MAX_NUM_ARGS][MAX_STR_SIZE] = {0};
|
||||
int num_args = parse_command(w, cmd, args);
|
||||
int num_args = parse_command(w, self, cmd, args);
|
||||
|
||||
if (num_args == -1)
|
||||
return;
|
||||
@ -154,5 +156,6 @@ void execute(WINDOW* w, ToxWindow *self, Tox *m, char *cmd, int mode)
|
||||
if (do_command(w, self, m, num_args, GLOBAL_NUM_COMMANDS, global_commands, args) == 0)
|
||||
return;
|
||||
|
||||
wprintw(w, "Invalid command.\n");
|
||||
uint8_t *errmsg = "Invalid command.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
#ifdef _SUPPORT_AUDIO
|
||||
#define GLOBAL_NUM_COMMANDS 16
|
||||
#define CHAT_NUM_COMMANDS 9
|
||||
#define CHAT_NUM_COMMANDS 10
|
||||
#else
|
||||
#define GLOBAL_NUM_COMMANDS 14
|
||||
#define CHAT_NUM_COMMANDS 5
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <time.h>
|
||||
|
||||
#include "toxic_windows.h"
|
||||
#include "line_info.h"
|
||||
|
||||
FileSender file_senders[MAX_FILES];
|
||||
uint8_t max_file_senders_index;
|
||||
@ -61,24 +62,25 @@ void close_all_file_senders(void)
|
||||
|
||||
void do_file_senders(Tox *m)
|
||||
{
|
||||
uint8_t msg[MAX_STR_SIZE];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < max_file_senders_index; ++i) {
|
||||
if (!file_senders[i].active)
|
||||
continue;
|
||||
|
||||
ToxWindow *self = file_senders[i].toxwin;
|
||||
uint8_t *pathname = file_senders[i].pathname;
|
||||
uint8_t filenum = file_senders[i].filenum;
|
||||
int friendnum = file_senders[i].friendnum;
|
||||
int filenum = file_senders[i].filenum;
|
||||
int32_t friendnum = file_senders[i].friendnum;
|
||||
FILE *fp = file_senders[i].file;
|
||||
uint64_t current_time = (uint64_t) time(NULL);
|
||||
uint64_t current_time = get_unix_time();
|
||||
|
||||
/* 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);
|
||||
if (self->chatwin != NULL) {
|
||||
snprintf(msg, sizeof(msg), "File transfer for '%s' timed out.", pathname);
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
alert_window(file_senders[i].toxwin, WINDOW_ALERT_2, true);
|
||||
}
|
||||
|
||||
@ -96,11 +98,24 @@ void do_file_senders(Tox *m)
|
||||
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;
|
||||
/* refresh line with percentage complete */
|
||||
if (self->chatwin != NULL) {
|
||||
uint64_t size = file_senders[i].size;
|
||||
long double remain = (long double) tox_file_data_remaining(m, friendnum, filenum, 0);
|
||||
long double pct_remain = 100;
|
||||
|
||||
if (ctx != NULL) {
|
||||
wprintw(ctx->history, "File '%s' successfuly sent.\n", pathname);
|
||||
if (remain)
|
||||
pct_remain = (1 - (remain / size)) * 100;
|
||||
|
||||
const uint8_t *name = file_senders[filenum].pathname;
|
||||
snprintf(msg, sizeof(msg), "File transfer for '%s' accepted (%.1Lf%%)", name, pct_remain);
|
||||
line_info_set(self, file_senders[filenum].line_id, msg);
|
||||
}
|
||||
|
||||
if (file_senders[i].piecelen == 0) {
|
||||
if (self->chatwin != NULL) {
|
||||
snprintf(msg, sizeof(msg), "File '%s' successfuly sent.", pathname);
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
alert_window(file_senders[i].toxwin, WINDOW_ALERT_2, true);
|
||||
}
|
||||
|
||||
|
248
src/friendlist.c
248
src/friendlist.c
@ -27,12 +27,14 @@
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <tox/tox.h>
|
||||
|
||||
#include "chat.h"
|
||||
#include "friendlist.h"
|
||||
#include "misc_tools.h"
|
||||
#include "line_info.h"
|
||||
|
||||
#ifdef _SUPPORT_AUDIO
|
||||
#include "audio_call.h"
|
||||
@ -49,7 +51,10 @@ extern struct _Winthread Winthread;
|
||||
ToxicFriend friends[MAX_FRIENDS_NUM];
|
||||
static int friendlist_index[MAX_FRIENDS_NUM] = {0};
|
||||
|
||||
static PendingDel pendingdelete;
|
||||
struct _pendingDel {
|
||||
int num;
|
||||
bool active;
|
||||
} pendingdelete;
|
||||
|
||||
#define S_WEIGHT 100
|
||||
|
||||
@ -65,7 +70,7 @@ static int index_name_cmp(const void *n1, const void *n2)
|
||||
}
|
||||
|
||||
/* sorts friendlist_index first by connection status then alphabetically */
|
||||
void sort_friendlist_index(Tox *m)
|
||||
void sort_friendlist_index(void)
|
||||
{
|
||||
int i;
|
||||
int n = 0;
|
||||
@ -78,7 +83,17 @@ void sort_friendlist_index(Tox *m)
|
||||
qsort(friendlist_index, num_friends, sizeof(int), index_name_cmp);
|
||||
}
|
||||
|
||||
static void friendlist_onMessage(ToxWindow *self, Tox *m, int num, uint8_t *str, uint16_t len)
|
||||
static void update_friend_last_online(int32_t num, uint64_t timestamp)
|
||||
{
|
||||
friends[num].last_online.last_on = timestamp;
|
||||
friends[num].last_online.tm = *localtime(×tamp);
|
||||
|
||||
/* if the format changes make sure TIME_STR_SIZE is the correct size */
|
||||
strftime(friends[num].last_online.hour_min_str, TIME_STR_SIZE, "%I:%M %p",
|
||||
&friends[num].last_online.tm);
|
||||
}
|
||||
|
||||
static void friendlist_onMessage(ToxWindow *self, Tox *m, int32_t num, uint8_t *str, uint16_t len)
|
||||
{
|
||||
if (num >= max_friends_index)
|
||||
return;
|
||||
@ -87,43 +102,50 @@ static void friendlist_onMessage(ToxWindow *self, Tox *m, int num, uint8_t *str,
|
||||
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
||||
friends[num].chatwin = add_window(m, new_chat(m, friends[num].num));
|
||||
} else {
|
||||
str[len] = '\0';
|
||||
|
||||
uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'};
|
||||
tox_get_name(m, num, nick);
|
||||
nick[TOXIC_MAX_NAME_LENGTH] = '\0';
|
||||
wprintw(prompt->window, "%s: %s\n", nick, str);
|
||||
int n_len = tox_get_name(m, num, nick);
|
||||
n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH-1);
|
||||
nick[n_len] = '\0';
|
||||
|
||||
prep_prompt_win();
|
||||
wattron(prompt->window, COLOR_PAIR(RED));
|
||||
wprintw(prompt->window, "* Warning: Too many windows are open.\n");
|
||||
wattron(prompt->window, COLOR_PAIR(RED));
|
||||
uint8_t timefrmt[TIME_STR_SIZE];
|
||||
get_time_str(timefrmt);
|
||||
|
||||
line_info_add(prompt, timefrmt, nick, NULL, str, IN_MSG, 0, 0);
|
||||
|
||||
uint8_t *msg = "* Warning: Too many windows are open.";
|
||||
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, RED);
|
||||
alert_window(prompt, WINDOW_ALERT_1, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, int num, uint8_t status)
|
||||
static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, int32_t num, uint8_t status)
|
||||
{
|
||||
if (num >= max_friends_index)
|
||||
return;
|
||||
|
||||
friends[num].online = status == 1 ? true : false;
|
||||
sort_friendlist_index(m);
|
||||
friends[num].online = status;
|
||||
update_friend_last_online(num, get_unix_time());
|
||||
store_data(m, DATA_FILE);
|
||||
sort_friendlist_index();
|
||||
}
|
||||
|
||||
static void friendlist_onNickChange(ToxWindow *self, Tox *m, int num, uint8_t *str, uint16_t len)
|
||||
static void friendlist_onNickChange(ToxWindow *self, Tox *m, int32_t num, uint8_t *str, uint16_t len)
|
||||
{
|
||||
if (len > TOX_MAX_NAME_LENGTH || num >= max_friends_index)
|
||||
return;
|
||||
|
||||
str[TOXIC_MAX_NAME_LENGTH] = '\0';
|
||||
len = strlen(str) + 1;
|
||||
memcpy(friends[num].name, str, len);
|
||||
len = MIN(len, TOXIC_MAX_NAME_LENGTH-1);
|
||||
|
||||
str[len] = '\0';
|
||||
strcpy(friends[num].name, str);
|
||||
friends[num].namelength = len;
|
||||
sort_friendlist_index(m);
|
||||
sort_friendlist_index();
|
||||
}
|
||||
|
||||
static void friendlist_onStatusChange(ToxWindow *self, Tox *m, int num, TOX_USERSTATUS status)
|
||||
static void friendlist_onStatusChange(ToxWindow *self, Tox *m, int32_t num, uint8_t status)
|
||||
{
|
||||
if (num >= max_friends_index)
|
||||
return;
|
||||
@ -131,16 +153,17 @@ static void friendlist_onStatusChange(ToxWindow *self, Tox *m, int num, TOX_USER
|
||||
friends[num].status = status;
|
||||
}
|
||||
|
||||
static void friendlist_onStatusMessageChange(ToxWindow *self, int num, uint8_t *str, uint16_t len)
|
||||
static void friendlist_onStatusMessageChange(ToxWindow *self, int32_t num, uint8_t *str, uint16_t len)
|
||||
{
|
||||
if (len > TOX_MAX_STATUSMESSAGE_LENGTH || num >= max_friends_index)
|
||||
return;
|
||||
|
||||
memcpy(friends[num].statusmsg, str, len);
|
||||
strcpy(friends[num].statusmsg, str);
|
||||
friends[num].statusmsg[len] = '\0';
|
||||
friends[num].statusmsg_len = len;
|
||||
}
|
||||
|
||||
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int num, bool sort)
|
||||
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_t num, bool sort)
|
||||
{
|
||||
if (max_friends_index < 0 || max_friends_index >= MAX_FRIENDS_NUM)
|
||||
return;
|
||||
@ -156,13 +179,14 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int num, bool sort)
|
||||
friends[i].status = TOX_USERSTATUS_NONE;
|
||||
friends[i].namelength = tox_get_name(m, num, friends[i].name);
|
||||
tox_get_client_id(m, num, friends[i].pub_key);
|
||||
update_friend_last_online(i, tox_get_last_online(m, i));
|
||||
|
||||
if (friends[i].namelength == -1 || friends[i].name[0] == '\0') {
|
||||
strcpy(friends[i].name, (uint8_t *) UNKNOWN_NAME);
|
||||
friends[i].namelength = strlen(UNKNOWN_NAME) + 1;
|
||||
friends[i].namelength = strlen(UNKNOWN_NAME);
|
||||
} else { /* Enforce toxic's maximum name length */
|
||||
friends[i].name[TOXIC_MAX_NAME_LENGTH] = '\0';
|
||||
friends[i].namelength = strlen(friends[i].name) + 1;
|
||||
friends[i].namelength = MIN(friends[i].namelength, TOXIC_MAX_NAME_LENGTH);
|
||||
friends[i].name[friends[i].namelength] = '\0';
|
||||
}
|
||||
|
||||
num_friends = tox_count_friendlist(m);
|
||||
@ -171,14 +195,14 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int num, bool sort)
|
||||
++max_friends_index;
|
||||
|
||||
if (sort)
|
||||
sort_friendlist_index(m);
|
||||
sort_friendlist_index();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void friendlist_onFileSendRequest(ToxWindow *self, Tox *m, int num, uint8_t filenum,
|
||||
static void friendlist_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t filenum,
|
||||
uint64_t filesize, uint8_t *filename, uint16_t filename_len)
|
||||
{
|
||||
if (num >= max_friends_index)
|
||||
@ -190,21 +214,21 @@ static void friendlist_onFileSendRequest(ToxWindow *self, Tox *m, int num, uint8
|
||||
} else {
|
||||
tox_file_send_control(m, num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0);
|
||||
|
||||
uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'};
|
||||
tox_get_name(m, num, nick);
|
||||
nick[TOXIC_MAX_NAME_LENGTH] = '\0';
|
||||
uint8_t nick[TOX_MAX_NAME_LENGTH];
|
||||
int n_len = tox_get_name(m, num, nick);
|
||||
n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH-1);
|
||||
nick[n_len] = '\0';
|
||||
|
||||
prep_prompt_win();
|
||||
wattron(prompt->window, COLOR_PAIR(RED));
|
||||
wprintw(prompt->window, "* File transfer from %s failed: too many windows are open.\n", nick);
|
||||
wattron(prompt->window, COLOR_PAIR(RED));
|
||||
uint8_t msg[MAX_STR_SIZE];
|
||||
snprintf(msg, sizeof(msg), "* File transfer from %s failed: too many windows are open.", nick);
|
||||
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, RED);
|
||||
|
||||
alert_window(prompt, WINDOW_ALERT_1, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int num, uint8_t *group_pub_key)
|
||||
static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, uint8_t *group_pub_key)
|
||||
{
|
||||
if (num >= max_friends_index)
|
||||
return;
|
||||
@ -213,14 +237,14 @@ static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int num, uint8_t *
|
||||
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
||||
friends[num].chatwin = add_window(m, new_chat(m, friends[num].num));
|
||||
} else {
|
||||
uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'};
|
||||
tox_get_name(m, num, nick);
|
||||
nick[TOXIC_MAX_NAME_LENGTH] = '\0';
|
||||
uint8_t nick[TOX_MAX_NAME_LENGTH];
|
||||
int n_len = tox_get_name(m, num, nick);
|
||||
n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH-1);
|
||||
nick[n_len] = '\0';
|
||||
|
||||
prep_prompt_win();
|
||||
wattron(prompt->window, COLOR_PAIR(RED));
|
||||
wprintw(prompt->window, "* Group chat invite from %s failed: too many windows are open.\n", nick);
|
||||
wattron(prompt->window, COLOR_PAIR(RED));
|
||||
uint8_t msg[MAX_STR_SIZE];
|
||||
snprintf(msg, sizeof(msg), "* Group chat invite from %s failed: too many windows are open.", nick);
|
||||
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, RED);
|
||||
|
||||
alert_window(prompt, WINDOW_ALERT_1, true);
|
||||
}
|
||||
@ -237,7 +261,7 @@ static void select_friend(ToxWindow *self, Tox *m, wint_t key)
|
||||
}
|
||||
}
|
||||
|
||||
static void delete_friend(Tox *m, int f_num)
|
||||
static void delete_friend(Tox *m, int32_t f_num)
|
||||
{
|
||||
tox_del_friend(m, f_num);
|
||||
memset(&friends[f_num], 0, sizeof(ToxicFriend));
|
||||
@ -256,12 +280,12 @@ static void delete_friend(Tox *m, int f_num)
|
||||
if (num_friends && num_selected == num_friends)
|
||||
--num_selected;
|
||||
|
||||
sort_friendlist_index(m);
|
||||
sort_friendlist_index();
|
||||
store_data(m, DATA_FILE);
|
||||
}
|
||||
|
||||
/* activates delete friend popup */
|
||||
static void del_friend_activate(ToxWindow *self, Tox *m, int f_num)
|
||||
static void del_friend_activate(ToxWindow *self, Tox *m, int32_t f_num)
|
||||
{
|
||||
int x2, y2;
|
||||
getmaxyx(self->window, y2, x2);
|
||||
@ -277,7 +301,7 @@ static void del_friend_deactivate(ToxWindow *self, Tox *m, wint_t key)
|
||||
if (key == 'y')
|
||||
delete_friend(m, pendingdelete.num);
|
||||
|
||||
memset(&pendingdelete, 0, sizeof(PendingDel));
|
||||
memset(&pendingdelete, 0, sizeof(pendingdelete));
|
||||
delwin(self->popup);
|
||||
self->popup = NULL;
|
||||
clear();
|
||||
@ -303,7 +327,7 @@ static void draw_popup(ToxWindow *self, Tox *m)
|
||||
wrefresh(self->popup);
|
||||
}
|
||||
|
||||
static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key)
|
||||
static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
{
|
||||
if (num_friends == 0)
|
||||
return;
|
||||
@ -318,25 +342,25 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key)
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == '\n') {
|
||||
/* Jump to chat window if already open */
|
||||
if (friends[f].chatwin != -1) {
|
||||
set_active_window(friends[f].chatwin);
|
||||
} else if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
||||
friends[f].chatwin = add_window(m, new_chat(m, friends[f].num));
|
||||
set_active_window(friends[f].chatwin);
|
||||
} else {
|
||||
prep_prompt_win();
|
||||
wattron(prompt->window, COLOR_PAIR(RED));
|
||||
wprintw(prompt->window, "* Warning: Too many windows are open.\n");
|
||||
wattron(prompt->window, COLOR_PAIR(RED));
|
||||
if (key != ltr) {
|
||||
if (key == '\n') {
|
||||
/* Jump to chat window if already open */
|
||||
if (friends[f].chatwin != -1) {
|
||||
set_active_window(friends[f].chatwin);
|
||||
} else if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
||||
friends[f].chatwin = add_window(m, new_chat(m, friends[f].num));
|
||||
set_active_window(friends[f].chatwin);
|
||||
} else {
|
||||
uint8_t *msg = "* Warning: Too many windows are open.";
|
||||
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, RED);
|
||||
|
||||
alert_window(prompt, WINDOW_ALERT_1, true);
|
||||
alert_window(prompt, WINDOW_ALERT_1, true);
|
||||
}
|
||||
} else if (key == KEY_DC) {
|
||||
del_friend_activate(self, m, f);
|
||||
} else {
|
||||
select_friend(self, m, key);
|
||||
}
|
||||
} else if (key == KEY_DC) {
|
||||
del_friend_activate(self, m, f);
|
||||
} else {
|
||||
select_friend(self, m, key);
|
||||
}
|
||||
}
|
||||
|
||||
@ -349,6 +373,9 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
||||
int x2, y2;
|
||||
getmaxyx(self->window, y2, x2);
|
||||
|
||||
uint64_t cur_time = get_unix_time();
|
||||
struct tm cur_loc_tm = *localtime(&cur_time);
|
||||
|
||||
bool fix_statuses = x2 != self->x; /* true if window x axis has changed */
|
||||
|
||||
wattron(self->window, COLOR_PAIR(CYAN));
|
||||
@ -368,8 +395,9 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
||||
pthread_mutex_unlock(&Winthread.lock);
|
||||
|
||||
wattron(self->window, A_BOLD);
|
||||
wprintw(self->window, " Online: %d/%d \n\n", nf, num_friends);
|
||||
wprintw(self->window, " Online: ");
|
||||
wattroff(self->window, A_BOLD);
|
||||
wprintw(self->window, "%d/%d \n\n", nf, num_friends);
|
||||
|
||||
if ((y2 - FLIST_OFST) <= 0) /* don't allow division by zero */
|
||||
return;
|
||||
@ -396,7 +424,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
||||
}
|
||||
|
||||
if (friends[f].online) {
|
||||
TOX_USERSTATUS status = friends[f].status;
|
||||
uint8_t status = friends[f].status;
|
||||
int colour = WHITE;
|
||||
|
||||
switch (status) {
|
||||
@ -409,34 +437,41 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
||||
case TOX_USERSTATUS_BUSY:
|
||||
colour = RED;
|
||||
break;
|
||||
case TOX_USERSTATUS_INVALID:
|
||||
colour = MAGENTA;
|
||||
break;
|
||||
}
|
||||
|
||||
wprintw(self->window, "[");
|
||||
wattron(self->window, COLOR_PAIR(colour) | A_BOLD);
|
||||
wprintw(self->window, "O");
|
||||
wprintw(self->window, "O ");
|
||||
wattroff(self->window, COLOR_PAIR(colour) | A_BOLD);
|
||||
wprintw(self->window, "]");
|
||||
|
||||
if (f_selected)
|
||||
wattron(self->window, A_BOLD);
|
||||
wattron(self->window, COLOR_PAIR(BLUE));
|
||||
|
||||
wattron(self->window, A_BOLD);
|
||||
wprintw(self->window, "%s", friends[f].name);
|
||||
wattroff(self->window, A_BOLD);
|
||||
|
||||
if (f_selected)
|
||||
wattroff(self->window, A_BOLD);
|
||||
wattroff(self->window, COLOR_PAIR(BLUE));
|
||||
|
||||
/* Reset friends[f].statusmsg on window resize */
|
||||
if (fix_statuses) {
|
||||
uint8_t statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH] = {'\0'};
|
||||
|
||||
pthread_mutex_lock(&Winthread.lock);
|
||||
tox_get_status_message(m, friends[f].num, statusmsg, TOX_MAX_STATUSMESSAGE_LENGTH);
|
||||
friends[f].statusmsg_len = tox_get_status_message_size(m, f);
|
||||
uint16_t s_len = tox_get_status_message(m, friends[f].num, statusmsg,
|
||||
TOX_MAX_STATUSMESSAGE_LENGTH);
|
||||
pthread_mutex_unlock(&Winthread.lock);
|
||||
|
||||
friends[f].statusmsg_len = s_len;
|
||||
friends[f].statusmsg[s_len] = '\0';
|
||||
snprintf(friends[f].statusmsg, sizeof(friends[f].statusmsg), "%s", statusmsg);
|
||||
}
|
||||
|
||||
/* Truncate note if it doesn't fit on one line */
|
||||
uint16_t maxlen = x2 - getcurx(self->window) - 4;
|
||||
uint16_t maxlen = x2 - getcurx(self->window) - 2;
|
||||
if (friends[f].statusmsg_len > maxlen) {
|
||||
friends[f].statusmsg[maxlen-3] = '\0';
|
||||
strcat(friends[f].statusmsg, "...");
|
||||
@ -444,21 +479,43 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
||||
friends[f].statusmsg_len = maxlen;
|
||||
}
|
||||
|
||||
wprintw(self->window, " (%s)\n", friends[f].statusmsg);
|
||||
if (friends[f].statusmsg[0])
|
||||
wprintw(self->window, " %s", friends[f].statusmsg);
|
||||
|
||||
wprintw(self->window, "\n");
|
||||
} else {
|
||||
wprintw(self->window, "[");
|
||||
wprintw(self->window, "o ");
|
||||
|
||||
if (f_selected)
|
||||
wattron(self->window, COLOR_PAIR(BLUE));
|
||||
|
||||
wattron(self->window, A_BOLD);
|
||||
wprintw(self->window, "O");
|
||||
wprintw(self->window, "%s", friends[f].name);
|
||||
wattroff(self->window, A_BOLD);
|
||||
wprintw(self->window, "]");
|
||||
|
||||
if (f_selected)
|
||||
wattron(self->window, A_BOLD);
|
||||
wattroff(self->window, COLOR_PAIR(YELLOW));
|
||||
|
||||
uint64_t last_seen = friends[f].last_online.last_on;
|
||||
|
||||
wprintw(self->window, "%s\n", friends[f].name);
|
||||
if (last_seen != 0) {
|
||||
int day_dist = (cur_loc_tm.tm_yday - friends[f].last_online.tm.tm_yday) % 365;
|
||||
const uint8_t *hourmin = friends[f].last_online.hour_min_str;
|
||||
|
||||
if (f_selected)
|
||||
wattroff(self->window, A_BOLD);
|
||||
switch (day_dist) {
|
||||
case 0:
|
||||
wprintw(self->window, " Last seen: Today %s\n", hourmin);
|
||||
break;
|
||||
case 1:
|
||||
wprintw(self->window, " Last seen: Yesterday %s\n", hourmin);
|
||||
break;
|
||||
default:
|
||||
wprintw(self->window, " Last seen: %d days ago\n", day_dist);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
wprintw(self->window, " Last seen: Never\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -468,16 +525,11 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
||||
draw_popup(self, m);
|
||||
}
|
||||
|
||||
void disable_chatwin(int f_num)
|
||||
void disable_chatwin(int32_t f_num)
|
||||
{
|
||||
friends[f_num].chatwin = -1;
|
||||
}
|
||||
|
||||
static void friendlist_onInit(ToxWindow *self, Tox *m)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#ifdef _SUPPORT_AUDIO
|
||||
static void friendlist_onAv(ToxWindow *self, ToxAv *av)
|
||||
{
|
||||
@ -493,14 +545,17 @@ static void friendlist_onAv(ToxWindow *self, ToxAv *av)
|
||||
friends[id].chatwin = add_window(m, new_chat(m, friends[id].num));
|
||||
} else {
|
||||
uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'};
|
||||
tox_get_name(m, id, nick);
|
||||
nick[TOXIC_MAX_NAME_LENGTH] = '\0';
|
||||
wprintw(prompt->window, "Audio action from: %s!\n", nick);
|
||||
|
||||
prep_prompt_win();
|
||||
wattron(prompt->window, COLOR_PAIR(RED));
|
||||
wprintw(prompt->window, "* Warning: Too many windows are open.\n");
|
||||
wattron(prompt->window, COLOR_PAIR(RED));
|
||||
int n_len = tox_get_name(m, id, nick);
|
||||
|
||||
n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH-1);
|
||||
nick[n_len] = '\0';
|
||||
|
||||
uint8_t msg[MAX_STR_SIZE];
|
||||
snprintf(msg, sizeof(msg), "Audio action from: %s!", nick);
|
||||
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
|
||||
uint8_t *errmsg = "* Warning: Too many windows are open.";
|
||||
line_info_add(prompt, NULL, NULL, NULL, errmsg, SYS_MSG, 0, RED);
|
||||
|
||||
alert_window(prompt, WINDOW_ALERT_0, true);
|
||||
}
|
||||
@ -517,7 +572,6 @@ ToxWindow new_friendlist(void)
|
||||
|
||||
ret.onKey = &friendlist_onKey;
|
||||
ret.onDraw = &friendlist_onDraw;
|
||||
ret.onInit = &friendlist_onInit;
|
||||
ret.onFriendAdded = &friendlist_onFriendAdded;
|
||||
ret.onMessage = &friendlist_onMessage;
|
||||
ret.onConnectionChange = &friendlist_onConnectionChange;
|
||||
|
@ -23,8 +23,17 @@
|
||||
#ifndef FRIENDLIST_H_53I41IM
|
||||
#define FRIENDLIST_H_53I41IM
|
||||
|
||||
#include <time.h>
|
||||
#include "toxic_windows.h"
|
||||
|
||||
#define TIME_STR_SIZE 16
|
||||
|
||||
struct LastOnline {
|
||||
uint64_t last_on;
|
||||
struct tm tm;
|
||||
uint8_t hour_min_str[TIME_STR_SIZE]; /* holds 12-hour time string e.g. "10:43 PM" */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t name[TOX_MAX_NAME_LENGTH];
|
||||
uint16_t namelength;
|
||||
@ -32,28 +41,24 @@ typedef struct {
|
||||
uint16_t statusmsg_len;
|
||||
uint8_t pending_groupchat[TOX_CLIENT_ID_SIZE];
|
||||
uint8_t pub_key[TOX_CLIENT_ID_SIZE];
|
||||
int num;
|
||||
int32_t num;
|
||||
int chatwin;
|
||||
bool active;
|
||||
bool online;
|
||||
bool is_typing;
|
||||
uint8_t is_typing;
|
||||
bool logging_on; /* saves preference for friend irrespective of chat windows */
|
||||
TOX_USERSTATUS status;
|
||||
uint8_t status;
|
||||
struct LastOnline last_online;
|
||||
struct FileReceiver file_receiver;
|
||||
} ToxicFriend;
|
||||
|
||||
typedef struct {
|
||||
int num;
|
||||
bool active;
|
||||
} PendingDel;
|
||||
|
||||
ToxWindow new_friendlist(void);
|
||||
void disable_chatwin(int f_num);
|
||||
void disable_chatwin(int32_t f_num);
|
||||
int get_friendnum(uint8_t *name);
|
||||
|
||||
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int num, bool sort);
|
||||
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_t num, bool sort);
|
||||
|
||||
/* sorts friendlist_index first by connection status then alphabetically */
|
||||
void sort_friendlist_index(Tox *m);
|
||||
void sort_friendlist_index(void);
|
||||
|
||||
#endif /* end of include guard: FRIENDLIST_H_53I41IM */
|
||||
|
@ -30,6 +30,8 @@
|
||||
#include "toxic_windows.h"
|
||||
#include "misc_tools.h"
|
||||
#include "friendlist.h"
|
||||
#include "log.h"
|
||||
#include "line_info.h"
|
||||
|
||||
extern char *DATA_FILE;
|
||||
extern ToxWindow *prompt;
|
||||
@ -42,30 +44,34 @@ extern uint8_t num_frnd_requests;
|
||||
/* command functions */
|
||||
void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
/* check arguments */
|
||||
uint8_t *msg;
|
||||
|
||||
if (argc != 1) {
|
||||
wprintw(window, "Invalid syntax.\n");
|
||||
return;
|
||||
msg = "Invalid syntax.";
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
int req = atoi(argv[1]);
|
||||
|
||||
if ((req == 0 && strcmp(argv[1], "0"))|| req >= MAX_FRIENDS_NUM) {
|
||||
wprintw(window, "No pending friend request with that number.\n");
|
||||
msg = "No pending friend request with that number.";
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strlen(pending_frnd_requests[req])) {
|
||||
wprintw(window, "No pending friend request with that number.\n");
|
||||
msg = "No pending friend request with that number.";
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
int friendnum = tox_add_friend_norequest(m, pending_frnd_requests[req]);
|
||||
int32_t friendnum = tox_add_friend_norequest(m, pending_frnd_requests[req]);
|
||||
|
||||
if (friendnum == -1)
|
||||
wprintw(window, "Failed to add friend.\n");
|
||||
msg = "Failed to add friend.";
|
||||
else {
|
||||
wprintw(window, "Friend request accepted.\n");
|
||||
msg = "Friend request accepted.";
|
||||
on_friendadded(m, friendnum, true);
|
||||
}
|
||||
|
||||
@ -79,12 +85,16 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
||||
}
|
||||
|
||||
num_frnd_requests = i;
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
}
|
||||
|
||||
void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
uint8_t *errmsg;
|
||||
|
||||
if (argc < 1) {
|
||||
wprintw(window, "Invalid syntax.\n");
|
||||
errmsg = "Invalid syntax.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -95,7 +105,8 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
||||
uint8_t *temp = argv[2];
|
||||
|
||||
if (temp[0] != '\"') {
|
||||
wprintw(window, "Message must be enclosed in quotes.\n");
|
||||
errmsg = "Message must be enclosed in quotes.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -103,12 +114,14 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
||||
snprintf(msg, sizeof(msg), "%s", temp);
|
||||
} else {
|
||||
uint8_t selfname[TOX_MAX_NAME_LENGTH];
|
||||
tox_get_self_name(m, selfname, TOX_MAX_NAME_LENGTH);
|
||||
uint16_t n_len = tox_get_self_name(m, selfname);
|
||||
selfname[n_len] = '\0';
|
||||
snprintf(msg, sizeof(msg), "Hello, my name is %s. Care to Tox?", selfname);
|
||||
}
|
||||
|
||||
if (strlen(id) != 2 * TOX_FRIEND_ADDRESS_SIZE) {
|
||||
wprintw(window, "Invalid ID length.\n");
|
||||
errmsg = "Invalid ID length.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -123,7 +136,8 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
||||
xx[2] = '\0';
|
||||
|
||||
if (sscanf(xx, "%02x", &x) != 1) {
|
||||
wprintw(window, "Invalid ID.\n");
|
||||
errmsg = "Invalid ID.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -134,48 +148,52 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
||||
id[i] = toupper(id[i]);
|
||||
}
|
||||
|
||||
int f_num = tox_add_friend(m, id_bin, msg, strlen(msg) + 1);
|
||||
int32_t f_num = tox_add_friend(m, id_bin, msg, strlen(msg));
|
||||
|
||||
switch (f_num) {
|
||||
case TOX_FAERR_TOOLONG:
|
||||
wprintw(window, "Message is too long.\n");
|
||||
errmsg = "Message is too long.";
|
||||
break;
|
||||
case TOX_FAERR_NOMESSAGE:
|
||||
wprintw(window, "Please add a message to your request.\n");
|
||||
errmsg = "Please add a message to your request.";
|
||||
break;
|
||||
case TOX_FAERR_OWNKEY:
|
||||
wprintw(window, "That appears to be your own ID.\n");
|
||||
errmsg = "That appears to be your own ID.";
|
||||
break;
|
||||
case TOX_FAERR_ALREADYSENT:
|
||||
wprintw(window, "Friend request has already been sent.\n");
|
||||
errmsg = "Friend request has already been sent.";
|
||||
break;
|
||||
case TOX_FAERR_UNKNOWN:
|
||||
wprintw(window, "Undefined error when adding friend.\n");
|
||||
errmsg = "Undefined error when adding friend.";
|
||||
break;
|
||||
case TOX_FAERR_BADCHECKSUM:
|
||||
wprintw(window, "Bad checksum in address.\n");
|
||||
errmsg = "Bad checksum in address.";
|
||||
break;
|
||||
case TOX_FAERR_SETNEWNOSPAM:
|
||||
wprintw(window, "Nospam was different (is this contact already added?)\n");
|
||||
errmsg = "Nospam was different (is this contact already added?";
|
||||
break;
|
||||
default:
|
||||
wprintw(window, "Friend request sent.\n");
|
||||
errmsg = "Friend request sent.";
|
||||
on_friendadded(m, f_num, true);
|
||||
break;
|
||||
}
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
}
|
||||
|
||||
void cmd_clear(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
wclear(window);
|
||||
wprintw(window, "\n\n");
|
||||
line_info_clear(self->chatwin->hst);
|
||||
}
|
||||
|
||||
void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
uint8_t *errmsg;
|
||||
|
||||
/* check arguments */
|
||||
if (argc != 3) {
|
||||
wprintw(window, "Invalid syntax.\n");
|
||||
errmsg = "Invalid syntax.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -185,7 +203,8 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
|
||||
char *key = argv[3];
|
||||
|
||||
if (atoi(port) == 0) {
|
||||
wprintw(window, "Invalid syntax.\n");
|
||||
errmsg = "Invalid syntax.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -197,53 +216,46 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
|
||||
|
||||
void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
uint8_t *errmsg;
|
||||
|
||||
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
|
||||
wattron(window, COLOR_PAIR(RED));
|
||||
wprintw(window, " * Warning: Too many windows are open.\n");
|
||||
wattron(window, COLOR_PAIR(RED));
|
||||
errmsg = " * Warning: Too many windows are open.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, RED);
|
||||
return;
|
||||
}
|
||||
|
||||
int groupnum = tox_add_groupchat(m);
|
||||
|
||||
if (groupnum == -1) {
|
||||
wprintw(window, "Group chat instance failed to initialize.\n");
|
||||
errmsg = "Group chat instance failed to initialize.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (init_groupchat_win(prompt, m, groupnum) == -1) {
|
||||
wprintw(window, "Group chat window failed to initialize.\n");
|
||||
errmsg = "Group chat window failed to initialize.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
tox_del_groupchat(m, groupnum);
|
||||
return;
|
||||
}
|
||||
|
||||
wprintw(window, "Group chat created as %d.\n", groupnum);
|
||||
uint8_t msg[MAX_STR_SIZE];
|
||||
snprintf(msg, sizeof(msg), "Group chat created as %d.", groupnum);
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
}
|
||||
|
||||
void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
uint8_t *msg;
|
||||
struct chatlog *log = self->chatwin->log;
|
||||
|
||||
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");
|
||||
}
|
||||
if (log->log_on)
|
||||
msg = "Logging for this window is ON. Type \"/log off\" to disable.";
|
||||
else
|
||||
msg = "Logging for this window is OFF. Type \"/log on\" to enable.";
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -253,38 +265,31 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
||||
|
||||
if (self->is_chat) {
|
||||
friends[self->num].logging_on = true;
|
||||
log_enable(self->name, friends[self->num].pub_key, self->chatwin->log);
|
||||
log_enable(self->name, friends[self->num].pub_key, 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);
|
||||
log_enable(self->name, myid, log);
|
||||
} else if (self->is_groupchat) {
|
||||
log_enable(self->name, NULL, self->chatwin->log);
|
||||
log_enable(self->name, NULL, log);
|
||||
}
|
||||
|
||||
wprintw(window, "Logging ");
|
||||
wattron(window, COLOR_PAIR(GREEN) | A_BOLD);
|
||||
wprintw(window, "[on]\n");
|
||||
wattroff(window, COLOR_PAIR(GREEN) | A_BOLD);
|
||||
msg = "Logging enabled";
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
} else if (!strcmp(swch, "0") || !strcmp(swch, "off")) {
|
||||
if (self->is_chat) {
|
||||
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);
|
||||
log_disable(log);
|
||||
|
||||
msg = "Logging disabled";
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
wprintw(window, "Invalid option. Use \"/log on\" and \"/log off\" to toggle logging.\n");
|
||||
msg = "Invalid option. Use \"/log on\" and \"/log off\" to toggle logging.";
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
}
|
||||
|
||||
void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
@ -301,14 +306,17 @@ void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
||||
strcat(id, xx);
|
||||
}
|
||||
|
||||
wprintw(window, "%s\n", id);
|
||||
line_info_add(self, NULL, NULL, NULL, id, SYS_MSG, 0, 0);
|
||||
}
|
||||
|
||||
void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
uint8_t *errmsg;
|
||||
|
||||
/* check arguments */
|
||||
if (argc < 1) {
|
||||
wprintw(window, "Invalid name.\n");
|
||||
errmsg = "Invalid name.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -322,71 +330,90 @@ void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
||||
}
|
||||
|
||||
if (!valid_nick(nick)) {
|
||||
wprintw(window, "Invalid name.\n");
|
||||
errmsg = "Invalid name.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (len > TOXIC_MAX_NAME_LENGTH) {
|
||||
nick[TOXIC_MAX_NAME_LENGTH] = L'\0';
|
||||
len = TOXIC_MAX_NAME_LENGTH;
|
||||
}
|
||||
len = MIN(len, TOXIC_MAX_NAME_LENGTH-1);
|
||||
|
||||
tox_set_name(m, nick, len+1);
|
||||
prompt_update_nick(prompt, nick, len+1);
|
||||
nick[len] = L'\0';
|
||||
|
||||
tox_set_name(m, nick, len);
|
||||
prompt_update_nick(prompt, nick, len);
|
||||
|
||||
store_data(m, DATA_FILE);
|
||||
}
|
||||
|
||||
void cmd_note(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
uint8_t *errmsg;
|
||||
|
||||
if (argc < 1) {
|
||||
wprintw(window, "Wrong number of arguments.\n");
|
||||
errmsg = "Wrong number of arguments.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *msg = argv[1];
|
||||
|
||||
if (msg[0] != '\"') {
|
||||
wprintw(window, "Note must be enclosed in quotes.\n");
|
||||
errmsg = "Note must be enclosed in quotes.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
msg[strlen(++msg)-1] = L'\0';
|
||||
uint16_t len = strlen(msg) + 1;
|
||||
uint16_t len = strlen(msg);
|
||||
tox_set_status_message(m, msg, len);
|
||||
|
||||
prompt_update_statusmessage(prompt, msg, len);
|
||||
}
|
||||
|
||||
void cmd_prompt_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
wclear(window);
|
||||
wattron(window, COLOR_PAIR(CYAN) | A_BOLD);
|
||||
wprintw(window, "\n\nGlobal commands:\n");
|
||||
wattroff(window, COLOR_PAIR(CYAN) | A_BOLD);
|
||||
struct history *hst = self->chatwin->hst;
|
||||
line_info_clear(hst);
|
||||
struct line_info *start = hst->line_start;
|
||||
|
||||
uint8_t *msg = "Global commands:";
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
|
||||
|
||||
wprintw(window, " /add <id> <msg> : Add friend with optional message\n");
|
||||
wprintw(window, " /accept <n> : Accept friend request\n");
|
||||
wprintw(window, " /connect <ip> <port> <key> : Manually connect to a DHT node\n");
|
||||
wprintw(window, " /status <type> <msg> : Set status with optional note\n");
|
||||
wprintw(window, " /note <msg> : Set a personal note\n");
|
||||
wprintw(window, " /nick <nick> : Set your nickname\n");
|
||||
wprintw(window, " /log <on> or <off> : 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");
|
||||
|
||||
#ifdef _SUPPORT_AUDIO
|
||||
wprintw(window, " /lsdev <type> : List devices where type: in|out\n");
|
||||
wprintw(window, " /sdev <type> <id> : Set active device\n");
|
||||
#define NUMLINES 14
|
||||
#else
|
||||
#define NUMLINES 12
|
||||
#endif
|
||||
|
||||
uint8_t lines[NUMLINES][MAX_STR_SIZE] = {
|
||||
|
||||
{ " /add <id> <msg> : Add friend with optional message" },
|
||||
{ " /accept <n> : Accept friend request" },
|
||||
{ " /connect <ip> <port> <key> : Manually connect to a DHT node" },
|
||||
{ " /status <type> <msg> : Set status with optional note" },
|
||||
{ " /note <msg> : Set a personal note" },
|
||||
{ " /nick <nick> : Set your nickname" },
|
||||
{ " /log <on> or <off> : Enable/disable logging" },
|
||||
{ " /groupchat : Create a group chat" },
|
||||
{ " /myid : Print your ID" },
|
||||
{ " /help : Print this message again" },
|
||||
{ " /clear : Clear window history" },
|
||||
{ " /quit or /exit : Exit Toxic" },
|
||||
#ifdef _SUPPORT_AUDIO
|
||||
{ " /lsdev <type> : List devices where type: in|out" },
|
||||
{ " /sdev <type> <id> : Set active device" },
|
||||
#endif /* _SUPPORT_AUDIO */
|
||||
|
||||
wattron(window, COLOR_PAIR(CYAN) | A_BOLD);
|
||||
wprintw(window, " * Argument messages must be enclosed in quotation marks.\n");
|
||||
wprintw(window, " * Use ctrl-o and ctrl-p to navigate through the tabs.\n\n");
|
||||
wattroff(window, COLOR_PAIR(CYAN) | A_BOLD);
|
||||
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUMLINES; ++i)
|
||||
line_info_add(self, NULL, NULL, NULL, lines[i], SYS_MSG, 0, 0);
|
||||
|
||||
msg = " * Argument messages must be enclosed in quotation marks.\n"
|
||||
" * Use ctrl-o and ctrl-p to navigate through the tabs.\n";
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
|
||||
|
||||
hst->line_start = start;
|
||||
}
|
||||
|
||||
void cmd_quit(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
@ -397,16 +424,19 @@ void cmd_quit(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
||||
void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
uint8_t *msg = NULL;
|
||||
uint8_t *errmsg;
|
||||
|
||||
if (argc >= 2) {
|
||||
msg = argv[2];
|
||||
|
||||
if (msg[0] != '\"') {
|
||||
wprintw(window, "Note must be enclosed in quotes.\n");
|
||||
errmsg = "Note must be enclosed in quotes.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
} else if (argc != 1) {
|
||||
wprintw(window, "Wrong number of arguments.\n");
|
||||
errmsg = "Wrong number of arguments.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -427,7 +457,8 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
||||
else if (!strcmp(l_status, "busy"))
|
||||
status_kind = TOX_USERSTATUS_BUSY;
|
||||
else {
|
||||
wprintw(window, "Invalid status. Valid statuses are: online, busy and away.\n");
|
||||
errmsg = "Invalid status. Valid statuses are: online, busy and away.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -436,7 +467,7 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
||||
|
||||
if (msg != NULL) {
|
||||
msg[strlen(++msg)-1] = L'\0'; /* remove opening and closing quotes */
|
||||
uint16_t len = strlen(msg) + 1;
|
||||
uint16_t len = strlen(msg);
|
||||
tox_set_status_message(m, msg, len);
|
||||
prompt_update_statusmessage(prompt, msg, len);
|
||||
}
|
||||
|
590
src/groupchat.c
590
src/groupchat.c
@ -35,6 +35,7 @@
|
||||
#include "prompt.h"
|
||||
#include "toxic_strings.h"
|
||||
#include "log.h"
|
||||
#include "line_info.h"
|
||||
|
||||
extern char *DATA_FILE;
|
||||
extern int store_data(Tox *m, char *path);
|
||||
@ -56,9 +57,14 @@ int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum)
|
||||
groupchats[i].num_peers = 0;
|
||||
groupchats[i].peer_names = malloc(sizeof(uint8_t) * TOX_MAX_NAME_LENGTH);
|
||||
groupchats[i].oldpeer_names = malloc(sizeof(uint8_t) * TOX_MAX_NAME_LENGTH);
|
||||
groupchats[i].peer_name_lengths = malloc(sizeof(uint16_t));
|
||||
groupchats[i].oldpeer_name_lengths = malloc(sizeof(uint16_t));
|
||||
|
||||
memset(groupchats[i].peer_names, 0, sizeof(uint8_t) * TOX_MAX_NAME_LENGTH);
|
||||
memset(groupchats[i].peer_name_lengths, 0, sizeof(uint16_t));
|
||||
|
||||
/* temp fix */
|
||||
memcpy(&groupchats[i].oldpeer_names[0], UNKNOWN_NAME, sizeof(UNKNOWN_NAME));
|
||||
groupchats[i].oldpeer_name_lengths[0] = (uint16_t) strlen(UNKNOWN_NAME);
|
||||
|
||||
set_active_window(groupchats[i].chatwin);
|
||||
|
||||
@ -77,9 +83,11 @@ void kill_groupchat_window(ToxWindow *self)
|
||||
ChatContext *ctx = self->chatwin;
|
||||
|
||||
log_disable(ctx->log);
|
||||
line_info_cleanup(ctx->hst);
|
||||
delwin(ctx->linewin);
|
||||
del_window(self);
|
||||
free(ctx->log);
|
||||
free(ctx->hst);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
@ -90,6 +98,8 @@ static void close_groupchat(ToxWindow *self, Tox *m, int groupnum)
|
||||
|
||||
free(groupchats[groupnum].peer_names);
|
||||
free(groupchats[groupnum].oldpeer_names);
|
||||
free(groupchats[groupnum].peer_name_lengths);
|
||||
free(groupchats[groupnum].oldpeer_name_lengths);
|
||||
memset(&groupchats[groupnum], 0, sizeof(GroupChat));
|
||||
|
||||
int i;
|
||||
@ -103,29 +113,44 @@ static void close_groupchat(ToxWindow *self, Tox *m, int groupnum)
|
||||
kill_groupchat_window(self);
|
||||
}
|
||||
|
||||
static void print_groupchat_help(ChatContext *ctx)
|
||||
static void print_groupchat_help(ToxWindow *self)
|
||||
{
|
||||
wattron(ctx->history, COLOR_PAIR(CYAN) | A_BOLD);
|
||||
wprintw(ctx->history, "Group chat commands:\n");
|
||||
wattroff(ctx->history, COLOR_PAIR(CYAN) | A_BOLD);
|
||||
struct history *hst = self->chatwin->hst;
|
||||
line_info_clear(hst);
|
||||
struct line_info *start = hst->line_start;
|
||||
|
||||
wprintw(ctx->history, " /add <id> <msg> : Add friend with optional message\n");
|
||||
wprintw(ctx->history, " /status <type> <msg>: Set your status with optional note\n");
|
||||
wprintw(ctx->history, " /note <msg> : Set a personal note\n");
|
||||
wprintw(ctx->history, " /nick <nick> : Set your nickname\n");
|
||||
wprintw(ctx->history, " /groupchat : Create a group chat\n");
|
||||
wprintw(ctx->history, " /log <on> or <off> : 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");
|
||||
wprintw(ctx->history, " * Scroll peer list with the Page Up/Page Down keys.\n\n");
|
||||
wattroff(ctx->history, COLOR_PAIR(CYAN) | A_BOLD);
|
||||
wattron(ctx->history, COLOR_PAIR(WHITE) | A_BOLD);
|
||||
wprintw(ctx->history, " Notice, some friends will be missing names while finding peers\n\n");
|
||||
wattroff(ctx->history, COLOR_PAIR(WHITE) | A_BOLD);
|
||||
uint8_t *msg = "Group chat commands:";
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
|
||||
|
||||
#define NUMLINES 9
|
||||
|
||||
uint8_t lines[NUMLINES][MAX_STR_SIZE] = {
|
||||
|
||||
{ " /add <id> <msg> : Add friend with optional message" },
|
||||
{ " /status <type> <msg>: Set your status with optional note" },
|
||||
{ " /note <msg> : Set a personal note" },
|
||||
{ " /nick <nick> : Set your nickname" },
|
||||
{ " /groupchat : Create a group chat" },
|
||||
{ " /log <on> or <off> : Enable/disable logging" },
|
||||
{ " /close : Close the current group chat" },
|
||||
{ " /help : Print this message again" },
|
||||
{ " /help global : Show a list of global commands" },
|
||||
|
||||
};
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUMLINES; ++i)
|
||||
line_info_add(self, NULL, NULL, NULL, lines[i], SYS_MSG, 0, 0);
|
||||
|
||||
msg = " * Use ESC key to toggle history scroll mode";
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
|
||||
msg = " * Scroll peer list with the Page Up/Page Down keys.\n";
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
|
||||
msg = " * Notice, some friends will be missing names while finding peers\n";
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, 0);
|
||||
|
||||
hst->line_start = start;
|
||||
}
|
||||
|
||||
static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, int groupnum, int peernum,
|
||||
@ -134,18 +159,24 @@ static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, int groupnum, int
|
||||
if (self->num != groupnum)
|
||||
return;
|
||||
|
||||
msg[len] = '\0';
|
||||
|
||||
ChatContext *ctx = self->chatwin;
|
||||
|
||||
uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'};
|
||||
tox_group_peername(m, groupnum, peernum, nick);
|
||||
nick[TOXIC_MAX_NAME_LENGTH] = '\0'; /* enforce client max name length */
|
||||
int n_len = tox_group_peername(m, groupnum, peernum, nick);
|
||||
|
||||
n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH-1); /* enforce client max name length */
|
||||
nick[n_len] = '\0';
|
||||
|
||||
/* check if message contains own name and alert appropriately */
|
||||
int alert_type = WINDOW_ALERT_1;
|
||||
bool beep = false;
|
||||
|
||||
uint8_t selfnick[TOX_MAX_NAME_LENGTH] = {'\0'};
|
||||
tox_get_self_name(m, selfnick, TOX_MAX_NAME_LENGTH);
|
||||
uint8_t selfnick[TOX_MAX_NAME_LENGTH];
|
||||
uint16_t sn_len = tox_get_self_name(m, selfnick);
|
||||
selfnick[sn_len] = '\0';
|
||||
|
||||
int nick_clr = strcmp(nick, selfnick) == 0 ? GREEN : CYAN;
|
||||
|
||||
bool nick_match = strcasestr(msg, selfnick) && strncmp(selfnick, nick, TOXIC_MAX_NAME_LENGTH);
|
||||
@ -158,19 +189,10 @@ static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, int groupnum, int
|
||||
|
||||
alert_window(self, alert_type, beep);
|
||||
|
||||
print_time(ctx->history);
|
||||
wattron(ctx->history, COLOR_PAIR(nick_clr));
|
||||
wprintw(ctx->history, "%s: ", nick);
|
||||
wattroff(ctx->history, COLOR_PAIR(nick_clr));
|
||||
|
||||
if (msg[0] == '>') {
|
||||
wattron(ctx->history, COLOR_PAIR(GREEN));
|
||||
wprintw(ctx->history, "%s\n", msg);
|
||||
wattroff(ctx->history, COLOR_PAIR(GREEN));
|
||||
} else {
|
||||
wprintw(ctx->history, "%s\n", msg);
|
||||
}
|
||||
uint8_t timefrmt[TIME_STR_SIZE];
|
||||
get_time_str(timefrmt);
|
||||
|
||||
line_info_add(self, timefrmt, nick, NULL, msg, IN_MSG, 0, nick_clr);
|
||||
write_to_log(msg, nick, ctx->log, false);
|
||||
}
|
||||
|
||||
@ -180,14 +202,17 @@ static void groupchat_onGroupAction(ToxWindow *self, Tox *m, int groupnum, int p
|
||||
if (self->num != groupnum)
|
||||
return;
|
||||
|
||||
action[len] = '\0';
|
||||
|
||||
ChatContext *ctx = self->chatwin;
|
||||
|
||||
/* check if message contains own name and alert appropriately */
|
||||
int alert_type = WINDOW_ALERT_1;
|
||||
bool beep = false;
|
||||
|
||||
uint8_t selfnick[TOX_MAX_NAME_LENGTH] = {'\0'};
|
||||
tox_get_self_name(m, selfnick, TOX_MAX_NAME_LENGTH);
|
||||
uint8_t selfnick[TOX_MAX_NAME_LENGTH];
|
||||
uint16_t n_len = tox_get_self_name(m, selfnick);
|
||||
selfnick[n_len] = '\0';
|
||||
|
||||
bool nick_match = strcasestr(action, selfnick);
|
||||
|
||||
@ -199,47 +224,65 @@ static void groupchat_onGroupAction(ToxWindow *self, Tox *m, int groupnum, int p
|
||||
alert_window(self, alert_type, beep);
|
||||
|
||||
uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'};
|
||||
tox_group_peername(m, groupnum, peernum, nick);
|
||||
nick[TOXIC_MAX_NAME_LENGTH] = '\0'; /* enforce client max name length */
|
||||
n_len = tox_group_peername(m, groupnum, peernum, nick);
|
||||
|
||||
print_time(ctx->history);
|
||||
wattron(ctx->history, COLOR_PAIR(YELLOW));
|
||||
wprintw(ctx->history, "* %s %s\n", nick, action);
|
||||
wattroff(ctx->history, COLOR_PAIR(YELLOW));
|
||||
n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH-1);
|
||||
nick[n_len] = '\0';
|
||||
|
||||
uint8_t timefrmt[TIME_STR_SIZE];
|
||||
get_time_str(timefrmt);
|
||||
|
||||
line_info_add(self, timefrmt, nick, NULL, action, ACTION, 0, 0);
|
||||
write_to_log(action, nick, ctx->log, true);
|
||||
}
|
||||
|
||||
/* Puts two copies of peerlist in chat instance */
|
||||
static void copy_peernames(int gnum, int npeers, uint8_t tmp_peerlist[][TOX_MAX_NAME_LENGTH])
|
||||
/* Puts two copies of peerlist/lengths in chat instance */
|
||||
static void copy_peernames(int gnum, uint8_t peerlist[][TOX_MAX_NAME_LENGTH], uint16_t lengths[], int npeers)
|
||||
{
|
||||
/* Assumes these are initiated in init_groupchat_win */
|
||||
free(groupchats[gnum].peer_names);
|
||||
free(groupchats[gnum].oldpeer_names);
|
||||
free(groupchats[gnum].peer_name_lengths);
|
||||
free(groupchats[gnum].oldpeer_name_lengths);
|
||||
|
||||
int N = TOX_MAX_NAME_LENGTH;
|
||||
|
||||
groupchats[gnum].peer_names = malloc(sizeof(uint8_t) * npeers * N);
|
||||
groupchats[gnum].oldpeer_names = malloc(sizeof(uint8_t) * npeers * N);
|
||||
groupchats[gnum].peer_name_lengths = malloc(sizeof(uint16_t) * npeers);
|
||||
groupchats[gnum].oldpeer_name_lengths = malloc(sizeof(uint16_t) * npeers);
|
||||
|
||||
if (groupchats[gnum].peer_names == NULL || groupchats[gnum].oldpeer_names == NULL) {
|
||||
memset(groupchats[gnum].peer_names, 0, sizeof(uint8_t) * npeers * N);
|
||||
memset(groupchats[gnum].peer_name_lengths, 0, sizeof(uint16_t) * npeers);
|
||||
|
||||
if (groupchats[gnum].peer_names == NULL || groupchats[gnum].oldpeer_names == NULL
|
||||
|| groupchats[gnum].peer_name_lengths == NULL || groupchats[gnum].oldpeer_name_lengths == NULL) {
|
||||
endwin();
|
||||
fprintf(stderr, "malloc() failed. Aborting...\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
uint16_t unknown_len = strlen(UNKNOWN_NAME);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < npeers; ++i) {
|
||||
if (string_is_empty(tmp_peerlist[i])) {
|
||||
if (string_is_empty(peerlist[i])) {
|
||||
memcpy(&groupchats[gnum].peer_names[i*N], UNKNOWN_NAME, sizeof(UNKNOWN_NAME));
|
||||
groupchats[gnum].peer_name_lengths[i] = unknown_len;
|
||||
} else {
|
||||
memcpy(&groupchats[gnum].peer_names[i*N], tmp_peerlist[i], N);
|
||||
groupchats[gnum].peer_names[i*N+TOXIC_MAX_NAME_LENGTH] = '\0';
|
||||
memcpy(&groupchats[gnum].peer_names[i*N], peerlist[i], N);
|
||||
uint16_t n_len = lengths[i];
|
||||
|
||||
n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH-1);
|
||||
|
||||
groupchats[gnum].peer_names[i*N+n_len] = '\0';
|
||||
groupchats[gnum].peer_name_lengths[i] = n_len;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(groupchats[gnum].oldpeer_names, groupchats[gnum].peer_names, N*npeers);
|
||||
memcpy(groupchats[gnum].oldpeer_name_lengths, groupchats[gnum].peer_name_lengths,
|
||||
sizeof(uint16_t) * npeers);
|
||||
}
|
||||
|
||||
static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnum, int peernum,
|
||||
@ -252,49 +295,48 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu
|
||||
int num_peers = groupchats[groupnum].num_peers;
|
||||
|
||||
/* get old peer name before updating name list */
|
||||
uint8_t oldpeername[TOX_MAX_NAME_LENGTH] = {0};
|
||||
uint8_t oldpeername[TOX_MAX_NAME_LENGTH];
|
||||
|
||||
if (change != TOX_CHAT_CHANGE_PEER_ADD)
|
||||
if (change != TOX_CHAT_CHANGE_PEER_ADD) {
|
||||
memcpy(oldpeername, &groupchats[groupnum].oldpeer_names[peernum*TOX_MAX_NAME_LENGTH],
|
||||
sizeof(oldpeername));
|
||||
uint16_t old_n_len = groupchats[groupnum].oldpeer_name_lengths[peernum];
|
||||
oldpeername[old_n_len] = '\0';
|
||||
}
|
||||
|
||||
/* Update name lists */
|
||||
/* Update name/len lists */
|
||||
uint8_t tmp_peerlist[num_peers][TOX_MAX_NAME_LENGTH];
|
||||
tox_group_get_names(m, groupnum, tmp_peerlist, num_peers);
|
||||
copy_peernames(groupnum, num_peers, tmp_peerlist);
|
||||
uint16_t tmp_peerlens[num_peers];
|
||||
tox_group_get_names(m, groupnum, tmp_peerlist, tmp_peerlens, num_peers);
|
||||
copy_peernames(groupnum, tmp_peerlist, tmp_peerlens, num_peers);
|
||||
|
||||
/* get current peername then sort namelist */
|
||||
uint8_t peername[TOX_MAX_NAME_LENGTH] = {0};
|
||||
memcpy(peername, &groupchats[groupnum].peer_names[peernum*TOX_MAX_NAME_LENGTH], sizeof(peername));
|
||||
uint8_t peername[TOX_MAX_NAME_LENGTH];
|
||||
|
||||
if (change != TOX_CHAT_CHANGE_PEER_DEL) {
|
||||
uint16_t n_len = groupchats[groupnum].peer_name_lengths[peernum];
|
||||
memcpy(peername, &groupchats[groupnum].peer_names[peernum*TOX_MAX_NAME_LENGTH], sizeof(peername));
|
||||
peername[n_len] = '\0';
|
||||
}
|
||||
|
||||
qsort(groupchats[groupnum].peer_names, groupchats[groupnum].num_peers, TOX_MAX_NAME_LENGTH, qsort_strcasecmp_hlpr);
|
||||
|
||||
ChatContext *ctx = self->chatwin;
|
||||
print_time(ctx->history);
|
||||
|
||||
uint8_t *event;
|
||||
uint8_t timefrmt[TIME_STR_SIZE];
|
||||
get_time_str(timefrmt);
|
||||
|
||||
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, " %s\n", event);
|
||||
wattroff(ctx->history, COLOR_PAIR(GREEN));
|
||||
|
||||
line_info_add(self, timefrmt, peername, NULL, event, CONNECTION, 0, 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, " %s\n", event);
|
||||
line_info_add(self, timefrmt, oldpeername, NULL, event, CONNECTION, 0, 0);
|
||||
|
||||
if (groupchats[self->num].side_pos > 0)
|
||||
--groupchats[self->num].side_pos;
|
||||
@ -303,19 +345,10 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu
|
||||
break;
|
||||
|
||||
case TOX_CHAT_CHANGE_PEER_NAME:
|
||||
wattron(ctx->history, COLOR_PAIR(MAGENTA));
|
||||
wattron(ctx->history, A_BOLD);
|
||||
wprintw(ctx->history, "* %s", oldpeername);
|
||||
wattroff(ctx->history, A_BOLD);
|
||||
event = " is now known as ";
|
||||
line_info_add(self, timefrmt, oldpeername, peername, event, NAME_CHANGE, 0, 0);
|
||||
|
||||
wprintw(ctx->history, " is now known as ");
|
||||
|
||||
wattron(ctx->history, A_BOLD);
|
||||
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];
|
||||
uint8_t tmp_event[TOXIC_MAX_NAME_LENGTH * 2 + 32];
|
||||
snprintf(tmp_event, sizeof(tmp_event), "is now known as %s", peername);
|
||||
write_to_log(tmp_event, oldpeername, ctx->log, true);
|
||||
break;
|
||||
@ -330,22 +363,13 @@ static void send_group_action(ToxWindow *self, ChatContext *ctx, Tox *m, uint8_t
|
||||
return;
|
||||
}
|
||||
|
||||
/* uint8_t selfname[TOX_MAX_NAME_LENGTH];
|
||||
tox_get_self_name(m, selfname, TOX_MAX_NAME_LENGTH);
|
||||
|
||||
print_time(ctx->history);
|
||||
wattron(ctx->history, COLOR_PAIR(YELLOW));
|
||||
wprintw(ctx->history, "* %s %s\n", selfname, action);
|
||||
wattroff(ctx->history, COLOR_PAIR(YELLOW)); */
|
||||
|
||||
if (tox_group_action_send(m, self->num, action, strlen(action) + 1) == -1) {
|
||||
wattron(ctx->history, COLOR_PAIR(RED));
|
||||
wprintw(ctx->history, " * Failed to send action\n");
|
||||
wattroff(ctx->history, COLOR_PAIR(RED));
|
||||
if (tox_group_action_send(m, self->num, action, strlen(action)) == -1) {
|
||||
uint8_t *errmsg = " * Failed to send action.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, RED);
|
||||
}
|
||||
}
|
||||
|
||||
static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key)
|
||||
static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
{
|
||||
ChatContext *ctx = self->chatwin;
|
||||
|
||||
@ -354,143 +378,18 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key)
|
||||
getmaxyx(self->window, y2, x2);
|
||||
int cur_len = 0;
|
||||
|
||||
if (key == 0x107 || key == 0x8 || key == 0x7f) { /* BACKSPACE key: Remove character behind pos */
|
||||
if (ctx->pos > 0) {
|
||||
cur_len = MAX(1, wcwidth(ctx->line[ctx->pos - 1]));
|
||||
del_char_buf_bck(ctx->line, &ctx->pos, &ctx->len);
|
||||
|
||||
if (x == 0)
|
||||
wmove(self->window, y-1, x2 - cur_len);
|
||||
else
|
||||
wmove(self->window, y, x - cur_len);
|
||||
} else {
|
||||
beep();
|
||||
}
|
||||
}
|
||||
|
||||
else if (key == KEY_DC) { /* DEL key: Remove character at pos */
|
||||
if (ctx->pos != ctx->len)
|
||||
del_char_buf_frnt(ctx->line, &ctx->pos, &ctx->len);
|
||||
else
|
||||
beep();
|
||||
if (!ltr && (key == T_KEY_ESC) ) { /* ESC key: Toggle history scroll mode */
|
||||
bool scroll = ctx->hst->scroll_mode ? false : true;
|
||||
line_info_toggle_scroll(self, scroll);
|
||||
}
|
||||
|
||||
else if (key == T_KEY_DISCARD) { /* CTRL-U: Delete entire line behind pos */
|
||||
if (ctx->pos > 0) {
|
||||
discard_buf(ctx->line, &ctx->pos, &ctx->len);
|
||||
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
||||
} else {
|
||||
beep();
|
||||
}
|
||||
/* If we're in scroll mode ignore rest of function */
|
||||
if (ctx->hst->scroll_mode) {
|
||||
line_info_onKey(self, key);
|
||||
return;
|
||||
}
|
||||
|
||||
else if (key == T_KEY_KILL) { /* CTRL-K: Delete entire line in front of pos */
|
||||
if (ctx->pos != ctx->len)
|
||||
kill_buf(ctx->line, &ctx->pos, &ctx->len);
|
||||
else
|
||||
beep();
|
||||
}
|
||||
|
||||
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 || 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);
|
||||
}
|
||||
}
|
||||
|
||||
else if (key == KEY_LEFT) {
|
||||
if (ctx->pos > 0) {
|
||||
--ctx->pos;
|
||||
cur_len = MAX(1, wcwidth(ctx->line[ctx->pos]));
|
||||
|
||||
if (x == 0)
|
||||
wmove(self->window, y-1, x2 - cur_len);
|
||||
else
|
||||
wmove(self->window, y, x - cur_len);
|
||||
} else {
|
||||
beep();
|
||||
}
|
||||
}
|
||||
|
||||
else if (key == KEY_RIGHT) {
|
||||
if (ctx->pos < ctx->len) {
|
||||
cur_len = MAX(1, wcwidth(ctx->line[ctx->pos]));
|
||||
++ctx->pos;
|
||||
|
||||
if (x == x2-1)
|
||||
wmove(self->window, y+1, 0);
|
||||
else
|
||||
wmove(self->window, y, x + cur_len);
|
||||
} else {
|
||||
beep();
|
||||
}
|
||||
}
|
||||
|
||||
else if (key == KEY_UP) { /* fetches previous item in history */
|
||||
fetch_hist_item(ctx->line, &ctx->pos, &ctx->len, ctx->ln_history, ctx->hst_tot,
|
||||
&ctx->hst_pos, LN_HIST_MV_UP);
|
||||
mv_curs_end(self->window, ctx->len, y2, x2);
|
||||
}
|
||||
|
||||
else if (key == KEY_DOWN) { /* fetches next item in history */
|
||||
fetch_hist_item(ctx->line, &ctx->pos, &ctx->len, ctx->ln_history, ctx->hst_tot,
|
||||
&ctx->hst_pos, LN_HIST_MV_DWN);
|
||||
mv_curs_end(self->window, ctx->len, y2, x2);
|
||||
}
|
||||
|
||||
else if (key == '\t') { /* TAB key: completes peer name */
|
||||
if (ctx->len > 0) {
|
||||
int diff;
|
||||
|
||||
if ((ctx->line[0] != '/') || (ctx->line[1] == 'm' && ctx->line[2] == 'e'))
|
||||
diff = complete_line(ctx->line, &ctx->pos, &ctx->len, groupchats[self->num].peer_names,
|
||||
groupchats[self->num].num_peers, TOX_MAX_NAME_LENGTH);
|
||||
else
|
||||
diff = complete_line(ctx->line, &ctx->pos, &ctx->len, glob_cmd_list, AC_NUM_GLOB_COMMANDS,
|
||||
MAX_CMDNAME_SIZE);
|
||||
|
||||
if (diff != -1) {
|
||||
if (x + diff > x2 - 1) {
|
||||
int ofst = (x + diff - 1) - (x2 - 1);
|
||||
wmove(self->window, y+1, ofst);
|
||||
} else {
|
||||
wmove(self->window, y, x+diff);
|
||||
}
|
||||
} else {
|
||||
beep();
|
||||
}
|
||||
} else {
|
||||
beep();
|
||||
}
|
||||
}
|
||||
|
||||
/* Scroll peerlist up and down one position if list overflows window */
|
||||
else if (key == KEY_NPAGE) {
|
||||
int L = y2 - CHATBOX_HEIGHT - SDBAR_OFST;
|
||||
|
||||
if (groupchats[self->num].side_pos < groupchats[self->num].num_peers - L)
|
||||
++groupchats[self->num].side_pos;
|
||||
}
|
||||
|
||||
else if (key == KEY_PPAGE) {
|
||||
if (groupchats[self->num].side_pos > 0)
|
||||
--groupchats[self->num].side_pos;
|
||||
}
|
||||
|
||||
else
|
||||
#if HAVE_WIDECHAR
|
||||
if (iswprint(key))
|
||||
#else
|
||||
if (isprint(key))
|
||||
#endif
|
||||
{ /* prevents buffer overflows and strange behaviour when cursor goes past the window */
|
||||
if (ltr) {
|
||||
if ( (ctx->len < MAX_STR_SIZE-1) && (ctx->len < (x2 * (CHATBOX_HEIGHT - 1)-1)) ) {
|
||||
add_char_to_buf(ctx->line, &ctx->pos, &ctx->len, key);
|
||||
|
||||
@ -499,67 +398,206 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key)
|
||||
else
|
||||
wmove(self->window, y, x + MAX(1, wcwidth(key)));
|
||||
}
|
||||
}
|
||||
|
||||
/* RETURN key: Execute command or print line */
|
||||
else if (key == '\n') {
|
||||
uint8_t line[MAX_STR_SIZE];
|
||||
} else { /* if (!ltr) */
|
||||
|
||||
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
|
||||
memset(&line, 0, sizeof(line));
|
||||
if (key == 0x107 || key == 0x8 || key == 0x7f) { /* BACKSPACE key: Remove character behind pos */
|
||||
if (ctx->pos > 0) {
|
||||
cur_len = MAX(1, wcwidth(ctx->line[ctx->pos - 1]));
|
||||
del_char_buf_bck(ctx->line, &ctx->pos, &ctx->len);
|
||||
|
||||
wclear(ctx->linewin);
|
||||
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
||||
wclrtobot(self->window);
|
||||
|
||||
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 (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);
|
||||
if (x == 0)
|
||||
wmove(self->window, y-1, x2 - cur_len);
|
||||
else
|
||||
print_groupchat_help(ctx);
|
||||
|
||||
} else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
|
||||
send_group_action(self, ctx, m, line + strlen("/me "));
|
||||
wmove(self->window, y, x - cur_len);
|
||||
} 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));
|
||||
wprintw(ctx->history, " * Failed to send message.\n");
|
||||
wattroff(ctx->history, COLOR_PAIR(RED));
|
||||
beep();
|
||||
}
|
||||
}
|
||||
|
||||
reset_buf(ctx->line, &ctx->pos, &ctx->len);
|
||||
else if (key == KEY_DC) { /* DEL key: Remove character at pos */
|
||||
if (ctx->pos != ctx->len)
|
||||
del_char_buf_frnt(ctx->line, &ctx->pos, &ctx->len);
|
||||
else
|
||||
beep();
|
||||
}
|
||||
|
||||
else if (key == T_KEY_DISCARD) { /* CTRL-U: Delete entire line behind pos */
|
||||
if (ctx->pos > 0) {
|
||||
discard_buf(ctx->line, &ctx->pos, &ctx->len);
|
||||
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
||||
} else {
|
||||
beep();
|
||||
}
|
||||
}
|
||||
|
||||
else if (key == T_KEY_KILL) { /* CTRL-K: Delete entire line in front of pos */
|
||||
if (ctx->pos != ctx->len)
|
||||
kill_buf(ctx->line, &ctx->pos, &ctx->len);
|
||||
else
|
||||
beep();
|
||||
}
|
||||
|
||||
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 || 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);
|
||||
}
|
||||
}
|
||||
|
||||
else if (key == KEY_LEFT) {
|
||||
if (ctx->pos > 0) {
|
||||
--ctx->pos;
|
||||
cur_len = MAX(1, wcwidth(ctx->line[ctx->pos]));
|
||||
|
||||
if (x == 0)
|
||||
wmove(self->window, y-1, x2 - cur_len);
|
||||
else
|
||||
wmove(self->window, y, x - cur_len);
|
||||
} else {
|
||||
beep();
|
||||
}
|
||||
}
|
||||
|
||||
else if (key == KEY_RIGHT) {
|
||||
if (ctx->pos < ctx->len) {
|
||||
cur_len = MAX(1, wcwidth(ctx->line[ctx->pos]));
|
||||
++ctx->pos;
|
||||
|
||||
if (x == x2-1)
|
||||
wmove(self->window, y+1, 0);
|
||||
else
|
||||
wmove(self->window, y, x + cur_len);
|
||||
} else {
|
||||
beep();
|
||||
}
|
||||
}
|
||||
|
||||
else if (key == KEY_UP) { /* fetches previous item in history */
|
||||
fetch_hist_item(ctx->line, &ctx->pos, &ctx->len, ctx->ln_history, ctx->hst_tot,
|
||||
&ctx->hst_pos, MOVE_UP);
|
||||
mv_curs_end(self->window, ctx->len, y2, x2);
|
||||
}
|
||||
|
||||
else if (key == KEY_DOWN) { /* fetches next item in history */
|
||||
fetch_hist_item(ctx->line, &ctx->pos, &ctx->len, ctx->ln_history, ctx->hst_tot,
|
||||
&ctx->hst_pos, MOVE_DOWN);
|
||||
mv_curs_end(self->window, ctx->len, y2, x2);
|
||||
}
|
||||
|
||||
else if (key == '\t') { /* TAB key: completes peer name */
|
||||
if (ctx->len > 0) {
|
||||
int diff;
|
||||
|
||||
if ((ctx->line[0] != '/') || (ctx->line[1] == 'm' && ctx->line[2] == 'e'))
|
||||
diff = complete_line(ctx->line, &ctx->pos, &ctx->len, groupchats[self->num].peer_names,
|
||||
groupchats[self->num].num_peers, TOX_MAX_NAME_LENGTH);
|
||||
else
|
||||
diff = complete_line(ctx->line, &ctx->pos, &ctx->len, glob_cmd_list, AC_NUM_GLOB_COMMANDS,
|
||||
MAX_CMDNAME_SIZE);
|
||||
|
||||
if (diff != -1) {
|
||||
if (x + diff > x2 - 1) {
|
||||
int ofst = (x + diff - 1) - (x2 - 1);
|
||||
wmove(self->window, y+1, ofst);
|
||||
} else {
|
||||
wmove(self->window, y, x+diff);
|
||||
}
|
||||
} else {
|
||||
beep();
|
||||
}
|
||||
} else {
|
||||
beep();
|
||||
}
|
||||
}
|
||||
|
||||
/* Scroll peerlist up and down one position if list overflows window */
|
||||
else if (key == KEY_NPAGE) {
|
||||
int L = y2 - CHATBOX_HEIGHT - SDBAR_OFST;
|
||||
|
||||
if (groupchats[self->num].side_pos < groupchats[self->num].num_peers - L)
|
||||
++groupchats[self->num].side_pos;
|
||||
}
|
||||
|
||||
else if (key == KEY_PPAGE) {
|
||||
if (groupchats[self->num].side_pos > 0)
|
||||
--groupchats[self->num].side_pos;
|
||||
}
|
||||
|
||||
/* RETURN key: Execute command or print line */
|
||||
else if (key == '\n') {
|
||||
uint8_t line[MAX_STR_SIZE];
|
||||
|
||||
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
|
||||
memset(&line, 0, sizeof(line));
|
||||
|
||||
wclear(ctx->linewin);
|
||||
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
||||
|
||||
|
||||
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 (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(self);
|
||||
|
||||
} else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
|
||||
send_group_action(self, ctx, m, line + strlen("/me "));
|
||||
} 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) {
|
||||
uint8_t *errmsg = " * Failed to send message.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, RED);
|
||||
}
|
||||
}
|
||||
|
||||
reset_buf(ctx->line, &ctx->pos, &ctx->len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void groupchat_onDraw(ToxWindow *self, Tox *m)
|
||||
{
|
||||
curs_set(1);
|
||||
|
||||
int x2, y2;
|
||||
getmaxyx(self->window, y2, x2);
|
||||
|
||||
ChatContext *ctx = self->chatwin;
|
||||
|
||||
line_info_print(self);
|
||||
wclear(ctx->linewin);
|
||||
|
||||
if (ctx->len > 0) {
|
||||
uint8_t line[MAX_STR_SIZE];
|
||||
if (ctx->hst->scroll_mode) {
|
||||
line_info_onDraw(self);
|
||||
} else {
|
||||
scrollok(ctx->history, 1);
|
||||
curs_set(1);
|
||||
|
||||
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
|
||||
reset_buf(ctx->line, &ctx->pos, &ctx->len);
|
||||
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
||||
} else {
|
||||
mvwprintw(ctx->linewin, 1, 0, "%s", line);
|
||||
if (ctx->len > 0) {
|
||||
uint8_t line[MAX_STR_SIZE];
|
||||
|
||||
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
|
||||
reset_buf(ctx->line, &ctx->pos, &ctx->len);
|
||||
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
||||
} else {
|
||||
mvwprintw(ctx->linewin, 1, 0, "%s", line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -601,22 +639,26 @@ static void groupchat_onInit(ToxWindow *self, Tox *m)
|
||||
getmaxyx(self->window, y, x);
|
||||
|
||||
ChatContext *ctx = self->chatwin;
|
||||
|
||||
ctx->history = subwin(self->window, y-CHATBOX_HEIGHT+1, x-SIDEBAR_WIDTH-1, 0, 0);
|
||||
scrollok(ctx->history, 1);
|
||||
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->hst = malloc(sizeof(struct history));
|
||||
ctx->log = malloc(sizeof(struct chatlog));
|
||||
|
||||
if (ctx->log == NULL) {
|
||||
if (ctx->log == NULL || ctx->hst == NULL) {
|
||||
endwin();
|
||||
fprintf(stderr, "malloc() failed. Aborting...\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memset(ctx->hst, 0, sizeof(struct history));
|
||||
memset(ctx->log, 0, sizeof(struct chatlog));
|
||||
|
||||
print_groupchat_help(ctx);
|
||||
line_info_init(ctx->hst);
|
||||
|
||||
print_groupchat_help(self);
|
||||
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
|
||||
|
||||
wmove(self->window, y-CURS_Y_OFFSET, 0);
|
||||
|
@ -28,8 +28,10 @@ typedef struct {
|
||||
bool active;
|
||||
int num_peers;
|
||||
int side_pos; /* current position of the sidebar - used for scrolling up and down */
|
||||
uint8_t *peer_names;
|
||||
uint8_t *oldpeer_names;
|
||||
uint8_t *peer_names;
|
||||
uint8_t *oldpeer_names;
|
||||
uint16_t *peer_name_lengths;
|
||||
uint16_t *oldpeer_name_lengths;
|
||||
} GroupChat;
|
||||
|
||||
void kill_groupchat_window(ToxWindow *self);
|
||||
|
434
src/line_info.c
Normal file
434
src/line_info.c
Normal file
@ -0,0 +1,434 @@
|
||||
/* line_info.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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "toxic_windows.h"
|
||||
#include "line_info.h"
|
||||
#include "groupchat.h"
|
||||
|
||||
void line_info_init(struct history *hst)
|
||||
{
|
||||
hst->line_root = malloc(sizeof(struct line_info));
|
||||
|
||||
if (hst->line_root == NULL) {
|
||||
endwin();
|
||||
fprintf(stderr, "malloc() failed. Aborting...\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memset(hst->line_root, 0, sizeof(struct line_info));
|
||||
hst->line_start = hst->line_root;
|
||||
hst->line_end = hst->line_start;
|
||||
}
|
||||
|
||||
/* resets line_start when scroll mode is disabled */
|
||||
static void line_info_reset_start(struct history *hst)
|
||||
{
|
||||
struct line_info *line = hst->line_end;
|
||||
uint32_t start_id = hst->start_id;
|
||||
|
||||
while (line) {
|
||||
if (line->id == start_id) {
|
||||
hst->line_start = line;
|
||||
break;
|
||||
}
|
||||
|
||||
line = line->prev;
|
||||
}
|
||||
}
|
||||
|
||||
void line_info_toggle_scroll(ToxWindow *self, bool scroll)
|
||||
{
|
||||
WINDOW *win = self->chatwin->history;
|
||||
struct history *hst = self->chatwin->hst;
|
||||
|
||||
if (scroll) {
|
||||
hst->scroll_mode = true;
|
||||
scrollok(win, 0);
|
||||
curs_set(0);
|
||||
} else {
|
||||
hst->scroll_mode = false;
|
||||
scrollok(win, 1);
|
||||
curs_set(1);
|
||||
line_info_reset_start(hst);
|
||||
}
|
||||
}
|
||||
|
||||
void line_info_cleanup(struct history *hst)
|
||||
{
|
||||
struct line_info *tmp1 = hst->line_root;
|
||||
|
||||
while (tmp1) {
|
||||
struct line_info *tmp2 = tmp1->next;
|
||||
free(tmp1);
|
||||
tmp1 = tmp2;
|
||||
}
|
||||
}
|
||||
|
||||
/* moves root forward and frees previous root */
|
||||
static void line_info_root_fwd(struct history *hst)
|
||||
{
|
||||
struct line_info *tmp = hst->line_root->next;
|
||||
tmp->prev = NULL;
|
||||
|
||||
if (hst->line_start->prev == NULL) { /* if line_start is root move it forward as well */
|
||||
hst->line_start = hst->line_start->next;
|
||||
hst->line_start->prev = NULL;
|
||||
++hst->start_id;
|
||||
}
|
||||
|
||||
free(hst->line_root);
|
||||
hst->line_root = tmp;
|
||||
}
|
||||
|
||||
void line_info_add(ToxWindow *self, uint8_t *tmstmp, uint8_t *name1, uint8_t *name2, uint8_t *msg,
|
||||
uint8_t type, uint8_t bold, uint8_t colour)
|
||||
{
|
||||
struct history *hst = self->chatwin->hst;
|
||||
struct line_info *new_line = malloc(sizeof(struct line_info));
|
||||
|
||||
if (new_line == NULL) {
|
||||
endwin();
|
||||
fprintf(stderr, "malloc() failed. Aborting...\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memset(new_line, 0, sizeof(struct line_info));
|
||||
|
||||
int len = 1; /* there will always be a newline */
|
||||
|
||||
/* for type-specific formatting in print function */
|
||||
switch (type) {
|
||||
case ACTION:
|
||||
len += 3;
|
||||
break;
|
||||
default:
|
||||
len += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (msg) {
|
||||
memcpy(new_line->msg, msg, sizeof(new_line->msg));
|
||||
len += strlen(msg);
|
||||
} if (tmstmp) {
|
||||
memcpy(new_line->timestamp, tmstmp, sizeof(new_line->timestamp));
|
||||
len += strlen(tmstmp);
|
||||
} if (name1) {
|
||||
memcpy(new_line->name1, name1, sizeof(new_line->name1));
|
||||
len += strlen(name1);
|
||||
} if (name2) {
|
||||
memcpy(new_line->name2, name2, sizeof(new_line->name2));
|
||||
len += strlen(name2);
|
||||
}
|
||||
|
||||
new_line->len = len;
|
||||
new_line->type = type;
|
||||
new_line->bold = bold;
|
||||
new_line->colour = colour;
|
||||
new_line->id = hst->line_end->id + 1;
|
||||
|
||||
new_line->prev = hst->line_end;
|
||||
hst->line_end->next = new_line;
|
||||
hst->line_end = new_line;
|
||||
|
||||
if (++hst->line_items > MAX_HISTORY) {
|
||||
--hst->line_items;
|
||||
line_info_root_fwd(hst);
|
||||
}
|
||||
|
||||
int newlines = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; msg[i]; ++i) {
|
||||
if (msg[i] == '\n')
|
||||
++newlines;
|
||||
}
|
||||
|
||||
int y, y2, x, x2;
|
||||
getmaxyx(self->window, y2, x2);
|
||||
getyx(self->chatwin->history, y, x);
|
||||
|
||||
if (x2 <= SIDEBAR_WIDTH)
|
||||
return;
|
||||
|
||||
int offst = self->is_groupchat ? SIDEBAR_WIDTH : 0; /* offset width of groupchat sidebar */
|
||||
int lines = (1 + newlines + (len / (x2 - offst)));
|
||||
hst->queue_lns += lines;
|
||||
++hst->queue;
|
||||
|
||||
int max_y = self->is_prompt ? y2 : y2 - CHATBOX_HEIGHT;
|
||||
|
||||
/* move line_start forward proportionate to the number of new lines */
|
||||
if (y + hst->queue_lns - hst->queue >= max_y) {
|
||||
while (lines > 0) {
|
||||
++hst->start_id;
|
||||
lines -= (1 + hst->line_start->len / (x2 - offst));
|
||||
|
||||
if (!hst->scroll_mode && hst->line_start->next)
|
||||
hst->line_start = hst->line_start->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void line_info_print(ToxWindow *self)
|
||||
{
|
||||
ChatContext *ctx = self->chatwin;
|
||||
WINDOW *win = ctx->history;
|
||||
|
||||
ctx->hst->queue = 0;
|
||||
ctx->hst->queue_lns = 0;
|
||||
|
||||
wclear(win);
|
||||
int y2, x2;
|
||||
getmaxyx(self->window, y2, x2);
|
||||
|
||||
if (self->is_prompt)
|
||||
y2 = MAX_HISTORY; /* temporary fix to make prompt scroll */
|
||||
|
||||
if (x2 <= SIDEBAR_WIDTH)
|
||||
return;
|
||||
|
||||
if (self->is_groupchat)
|
||||
wmove(win, 0, 0);
|
||||
else
|
||||
wmove(win, 2, 0);
|
||||
|
||||
struct line_info *line = ctx->hst->line_start->next;
|
||||
int offst = self->is_groupchat ? SIDEBAR_WIDTH : 0;
|
||||
int numlines = 0;
|
||||
|
||||
while(line && numlines++ <= y2) {
|
||||
uint8_t type = line->type;
|
||||
|
||||
switch (type) {
|
||||
case OUT_MSG:
|
||||
case IN_MSG:
|
||||
wattron(win, COLOR_PAIR(BLUE));
|
||||
wprintw(win, "%s", line->timestamp);
|
||||
wattroff(win, COLOR_PAIR(BLUE));
|
||||
|
||||
int nameclr = GREEN;
|
||||
|
||||
if (line->colour)
|
||||
nameclr = line->colour;
|
||||
else if (type == IN_MSG)
|
||||
nameclr = CYAN;
|
||||
|
||||
wattron(win, COLOR_PAIR(nameclr));
|
||||
wprintw(win, "%s: ", line->name1);
|
||||
wattroff(win, COLOR_PAIR(nameclr));
|
||||
|
||||
if (line->msg[0] == '>')
|
||||
wattron(win, COLOR_PAIR(GREEN));
|
||||
|
||||
wprintw(win, "%s\n", line->msg);
|
||||
|
||||
if (line->msg[0] == '>')
|
||||
wattroff(win, COLOR_PAIR(GREEN));
|
||||
|
||||
break;
|
||||
|
||||
case ACTION:
|
||||
wattron(win, COLOR_PAIR(BLUE));
|
||||
wprintw(win, "%s", line->timestamp);
|
||||
wattroff(win, COLOR_PAIR(BLUE));
|
||||
|
||||
wattron(win, COLOR_PAIR(YELLOW));
|
||||
wprintw(win, "* %s %s\n", line->name1, line->msg);
|
||||
wattroff(win, COLOR_PAIR(YELLOW));
|
||||
|
||||
break;
|
||||
|
||||
case SYS_MSG:
|
||||
if (line->timestamp[0]) {
|
||||
wattron(win, COLOR_PAIR(BLUE));
|
||||
wprintw(win, "%s", line->timestamp);
|
||||
wattroff(win, COLOR_PAIR(BLUE));
|
||||
}
|
||||
|
||||
if (line->bold)
|
||||
wattron(win, A_BOLD);
|
||||
if (line->colour)
|
||||
wattron(win, COLOR_PAIR(line->colour));
|
||||
|
||||
wprintw(win, "%s\n", line->msg);
|
||||
|
||||
if (line->bold)
|
||||
wattroff(win, A_BOLD);
|
||||
if (line->colour)
|
||||
wattroff(win, COLOR_PAIR(line->colour));
|
||||
|
||||
break;
|
||||
|
||||
case PROMPT:
|
||||
wattron(win, COLOR_PAIR(GREEN));
|
||||
wprintw(win, "$ ");
|
||||
wattroff(win, COLOR_PAIR(GREEN));
|
||||
|
||||
if (line->msg[0])
|
||||
wprintw(win, "%s", line->msg);
|
||||
|
||||
wprintw(win, "\n");
|
||||
break;
|
||||
|
||||
case CONNECTION:
|
||||
wattron(win, COLOR_PAIR(BLUE));
|
||||
wprintw(win, "%s", line->timestamp);
|
||||
wattroff(win, COLOR_PAIR(BLUE));
|
||||
|
||||
wattron(win, COLOR_PAIR(line->colour));
|
||||
wattron(win, A_BOLD);
|
||||
wprintw(win, "* %s ", line->name1);
|
||||
wattroff(win, A_BOLD);
|
||||
wprintw(win, "%s\n", line->msg);
|
||||
wattroff(win, COLOR_PAIR(line->colour));
|
||||
|
||||
break;
|
||||
|
||||
case NAME_CHANGE:
|
||||
wattron(win, COLOR_PAIR(BLUE));
|
||||
wprintw(win, "%s", line->timestamp);
|
||||
wattroff(win, COLOR_PAIR(BLUE));
|
||||
|
||||
wattron(win, COLOR_PAIR(MAGENTA));
|
||||
wattron(win, A_BOLD);
|
||||
wprintw(win, "* %s", line->name1);
|
||||
wattroff(win, A_BOLD);
|
||||
|
||||
wprintw(win, "%s", line->msg);
|
||||
|
||||
wattron(win, A_BOLD);
|
||||
wprintw(win, "%s\n", line->name2);
|
||||
wattroff(win, A_BOLD);
|
||||
wattroff(win, COLOR_PAIR(MAGENTA));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
line = line->next;
|
||||
}
|
||||
}
|
||||
|
||||
void line_info_set(ToxWindow *self, uint32_t id, uint8_t *msg)
|
||||
{
|
||||
struct line_info *line = self->chatwin->hst->line_end;
|
||||
|
||||
while (line) {
|
||||
if (line->id == id) {
|
||||
snprintf(line->msg, sizeof(line->msg), "%s", msg);
|
||||
return;
|
||||
}
|
||||
|
||||
line = line->prev;
|
||||
}
|
||||
}
|
||||
|
||||
static void line_info_goto_root(struct history *hst)
|
||||
{
|
||||
hst->line_start = hst->line_root;
|
||||
}
|
||||
|
||||
static void line_info_scroll_up(struct history *hst)
|
||||
{
|
||||
if (hst->line_start->prev)
|
||||
hst->line_start = hst->line_start->prev;
|
||||
else beep();
|
||||
}
|
||||
|
||||
static void line_info_scroll_down(struct history *hst)
|
||||
{
|
||||
if (hst->line_start->next)
|
||||
hst->line_start = hst->line_start->next;
|
||||
else beep();
|
||||
}
|
||||
|
||||
static void line_info_page_up(ToxWindow *self, struct history *hst)
|
||||
{
|
||||
int x2, y2;
|
||||
getmaxyx(self->window, y2, x2);
|
||||
int jump_dist = y2 / 2;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < jump_dist && hst->line_start->prev; ++i)
|
||||
hst->line_start = hst->line_start->prev;
|
||||
}
|
||||
|
||||
static void line_info_page_down(ToxWindow *self, struct history *hst)
|
||||
{
|
||||
int x2, y2;
|
||||
getmaxyx(self->window, y2, x2);
|
||||
int jump_dist = y2 / 2;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < jump_dist && hst->line_start->next; ++i)
|
||||
hst->line_start = hst->line_start->next;
|
||||
}
|
||||
|
||||
void line_info_onKey(ToxWindow *self, wint_t key)
|
||||
{
|
||||
struct history *hst = self->chatwin->hst;
|
||||
|
||||
switch (key) {
|
||||
case KEY_PPAGE:
|
||||
line_info_page_up(self, hst);
|
||||
break;
|
||||
case KEY_NPAGE:
|
||||
line_info_page_down(self, hst);
|
||||
break;
|
||||
case KEY_UP:
|
||||
line_info_scroll_up(hst);
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
line_info_scroll_down(hst);
|
||||
break;
|
||||
case KEY_HOME:
|
||||
line_info_goto_root(hst);
|
||||
break;
|
||||
case KEY_END:
|
||||
line_info_reset_start(hst);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void line_info_onDraw(ToxWindow *self)
|
||||
{
|
||||
ChatContext *ctx = self->chatwin;
|
||||
|
||||
wattron(ctx->linewin, A_BOLD | COLOR_PAIR(BLUE));
|
||||
mvwprintw(ctx->linewin, 1, 0, "Scroll mode:\n");
|
||||
wattroff(ctx->linewin, A_BOLD | COLOR_PAIR(BLUE));
|
||||
mvwprintw(ctx->linewin, 1, 13, "Use up/down arrows, page up/page down, and home/end to navigate.\n"
|
||||
" ESC to exit.\n");
|
||||
}
|
||||
|
||||
void line_info_clear(struct history *hst)
|
||||
{
|
||||
hst->line_start = hst->line_end;
|
||||
hst->start_id = hst->line_start->id;
|
||||
}
|
85
src/line_info.h
Normal file
85
src/line_info.h
Normal file
@ -0,0 +1,85 @@
|
||||
/* line_info.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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#define MAX_HISTORY 700
|
||||
|
||||
enum {
|
||||
SYS_MSG,
|
||||
IN_MSG,
|
||||
OUT_MSG,
|
||||
PROMPT,
|
||||
ACTION,
|
||||
CONNECTION,
|
||||
NAME_CHANGE,
|
||||
} LINE_TYPE;
|
||||
|
||||
struct line_info {
|
||||
uint8_t timestamp[TIME_STR_SIZE];
|
||||
uint8_t name1[TOXIC_MAX_NAME_LENGTH];
|
||||
uint8_t name2[TOXIC_MAX_NAME_LENGTH];
|
||||
uint8_t msg[MAX_STR_SIZE];
|
||||
uint8_t type;
|
||||
uint8_t bold;
|
||||
uint8_t colour;
|
||||
uint32_t id;
|
||||
uint16_t len; /* combined len of all strings */
|
||||
|
||||
struct line_info *prev;
|
||||
struct line_info *next;
|
||||
};
|
||||
|
||||
/* Linked list containing chat history lines */
|
||||
struct history {
|
||||
struct line_info *line_root;
|
||||
struct line_info *line_start; /* the first line we want to start printing at */
|
||||
struct line_info *line_end;
|
||||
uint32_t start_id; /* keeps track of where line_start should be when at bottom of history */
|
||||
uint32_t line_items;
|
||||
bool scroll_mode;
|
||||
|
||||
/* keeps track of lines added between window refreshes */
|
||||
uint32_t queue;
|
||||
uint32_t queue_lns;
|
||||
};
|
||||
|
||||
/* adds a line to history (also moves line_start and/or line_root forward if necessary) */
|
||||
void line_info_add(ToxWindow *self, uint8_t *tmstmp, uint8_t *name1, uint8_t *name2, uint8_t *msg,
|
||||
uint8_t type, uint8_t bold, uint8_t colour);
|
||||
|
||||
/* Prints a section of history starting at line_start */
|
||||
void line_info_print(ToxWindow *self);
|
||||
|
||||
/* frees all history lines */
|
||||
void line_info_cleanup(struct history *hst);
|
||||
|
||||
/* Toggles scroll mode for current window */
|
||||
void line_info_toggle_scroll(ToxWindow *self, bool scroll);
|
||||
|
||||
/* clears the screen (does not delete anything) */
|
||||
void line_info_clear(struct history *hst);
|
||||
|
||||
/* puts msg in specified line_info msg buffer */
|
||||
void line_info_set(ToxWindow *self, uint32_t id, uint8_t *msg);
|
||||
|
||||
void line_info_init(struct history *hst);
|
||||
void line_info_onKey(ToxWindow *self, wint_t key);
|
||||
void line_info_onDraw(ToxWindow *self);
|
15
src/log.c
15
src/log.c
@ -31,6 +31,7 @@
|
||||
#include "configdir.h"
|
||||
#include "toxic_windows.h"
|
||||
#include "misc_tools.h"
|
||||
#include "log.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)
|
||||
@ -48,17 +49,16 @@ void init_logging_session(uint8_t *name, uint8_t *key, struct chatlog *log)
|
||||
path_len += (KEY_IDENT_DIGITS * 2 + 5);
|
||||
|
||||
sprintf(&ident[0], "%02X", key[0] & 0xff);
|
||||
sprintf(&ident[2], "%02X", key[2] & 0xff);
|
||||
sprintf(&ident[2], "%02X", key[1] & 0xff);
|
||||
ident[KEY_IDENT_DIGITS*2+1] = '\0';
|
||||
} else {
|
||||
uint8_t s[MAX_STR_SIZE];
|
||||
strftime(s, MAX_STR_SIZE, "%Y-%m-%d[%H:%M:%S]", get_time());
|
||||
snprintf(ident, sizeof(ident), "%s", s);
|
||||
strftime(ident, sizeof(ident), "%Y-%m-%d[%H:%M:%S]", get_time());
|
||||
path_len += strlen(ident) + 1;
|
||||
}
|
||||
|
||||
if (path_len > MAX_STR_SIZE) {
|
||||
log->log_on = false;
|
||||
free(user_config_dir);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -67,6 +67,8 @@ void init_logging_session(uint8_t *name, uint8_t *key, struct chatlog *log)
|
||||
snprintf(log_path, MAX_STR_SIZE, "%s%s%s-%s.log",
|
||||
user_config_dir, CONFIGDIR, name, ident);
|
||||
|
||||
free(user_config_dir);
|
||||
|
||||
log->file = fopen(log_path, "a");
|
||||
|
||||
if (log->file == NULL) {
|
||||
@ -75,10 +77,9 @@ void init_logging_session(uint8_t *name, uint8_t *key, struct chatlog *log)
|
||||
}
|
||||
|
||||
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)
|
||||
void write_to_log(const uint8_t *msg, uint8_t *name, struct chatlog *log, bool event)
|
||||
{
|
||||
if (!log->log_on)
|
||||
return;
|
||||
@ -99,7 +100,7 @@ void write_to_log(uint8_t *msg, uint8_t *name, struct chatlog *log, bool event)
|
||||
strftime(s, MAX_STR_SIZE, "%Y/%m/%d [%H:%M:%S]", get_time());
|
||||
fprintf(log->file,"%s %s %s\n", s, name_frmt, msg);
|
||||
|
||||
uint64_t curtime = (uint64_t) time(NULL);
|
||||
uint64_t curtime = get_unix_time();
|
||||
|
||||
if (timed_out(log->lastwrite, curtime, LOG_FLUSH_LIMIT)) {
|
||||
fflush(log->file);
|
||||
|
11
src/log.h
11
src/log.h
@ -20,11 +20,20 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#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 */
|
||||
};
|
||||
|
||||
/* 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);
|
||||
void write_to_log(const 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);
|
||||
|
79
src/main.c
79
src/main.c
@ -60,6 +60,7 @@
|
||||
#include "prompt.h"
|
||||
#include "misc_tools.h"
|
||||
#include "file_senders.h"
|
||||
#include "line_info.h"
|
||||
|
||||
#ifdef _SUPPORT_AUDIO
|
||||
#include "audio_call.h"
|
||||
@ -83,7 +84,6 @@ struct _Winthread Winthread;
|
||||
|
||||
void on_window_resize(int sig)
|
||||
{
|
||||
endwin();
|
||||
refresh();
|
||||
clear();
|
||||
}
|
||||
@ -157,20 +157,20 @@ static Tox *init_tox(int ipv4)
|
||||
tox_callback_file_data(m, on_file_data, NULL);
|
||||
|
||||
#ifdef __linux__
|
||||
tox_set_name(m, (uint8_t *) "Cool guy", sizeof("Cool guy"));
|
||||
tox_set_name(m, (uint8_t *) "Cool guy", strlen("Cool guy"));
|
||||
#elif defined(_WIN32)
|
||||
tox_set_name(m, (uint8_t *) "I should install GNU/Linux", sizeof("I should install GNU/Linux"));
|
||||
tox_set_name(m, (uint8_t *) "I should install GNU/Linux", strlen("I should install GNU/Linux"));
|
||||
#elif defined(__APPLE__)
|
||||
tox_set_name(m, (uint8_t *) "Hipster", sizeof("Hipster")); /* This used to users of other Unixes are hipsters */
|
||||
tox_set_name(m, (uint8_t *) "Hipster", strlen("Hipster")); /* This used to users of other Unixes are hipsters */
|
||||
#else
|
||||
tox_set_name(m, (uint8_t *) "Registered Minix user #4", sizeof("Registered Minix user #4"));
|
||||
tox_set_name(m, (uint8_t *) "Registered Minix user #4", strlen("Registered Minix user #4"));
|
||||
#endif
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
#define MINLINE 50 /* IP: 7 + port: 5 + key: 38 + spaces: 2 = 70. ! (& e.g. tox.im = 6) */
|
||||
#define MAXLINE 256 /* Approx max number of chars in a sever line (name + port + key) */
|
||||
#define MINLINE 50 /* IP: 7 + port: 5 + key: 38 + spaces: 2 = 70. ! (& e.g. tox.im = 6) */
|
||||
#define MAXLINE 256 /* Approx max number of chars in a sever line (name + port + key) */
|
||||
#define MAXNODES 50
|
||||
#define NODELEN (MAXLINE - TOX_CLIENT_ID_SIZE - 7)
|
||||
|
||||
@ -272,6 +272,8 @@ int init_connection(Tox *m)
|
||||
|
||||
static void do_connection(Tox *m, ToxWindow *prompt)
|
||||
{
|
||||
uint8_t msg[MAX_STR_SIZE] = {0};
|
||||
|
||||
static int conn_try = 0;
|
||||
static int conn_err = 0;
|
||||
static bool dht_on = false;
|
||||
@ -281,26 +283,26 @@ static void do_connection(Tox *m, ToxWindow *prompt)
|
||||
if (!dht_on && !is_connected && !(conn_try++ % 100)) {
|
||||
if (!conn_err) {
|
||||
if ((conn_err = init_connection(m))) {
|
||||
prep_prompt_win();
|
||||
wprintw(prompt->window, "\nAuto-connect failed with error code %d\n", conn_err);
|
||||
snprintf(msg, sizeof(msg), "\nAuto-connect failed with error code %d", conn_err);
|
||||
}
|
||||
}
|
||||
} else if (!dht_on && is_connected) {
|
||||
dht_on = true;
|
||||
prompt_update_connectionstatus(prompt, dht_on);
|
||||
prep_prompt_win();
|
||||
wprintw(prompt->window, "DHT connected.\n");
|
||||
snprintf(msg, sizeof(msg), "DHT connected.");
|
||||
} else if (dht_on && !is_connected) {
|
||||
dht_on = false;
|
||||
prompt_update_connectionstatus(prompt, dht_on);
|
||||
prep_prompt_win();
|
||||
wprintw(prompt->window, "\nDHT disconnected. Attempting to reconnect.\n");
|
||||
snprintf(msg, sizeof(msg), "\nDHT disconnected. Attempting to reconnect.");
|
||||
}
|
||||
|
||||
if (msg[0])
|
||||
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
}
|
||||
|
||||
static void load_friendlist(Tox *m)
|
||||
{
|
||||
int i;
|
||||
int32_t i;
|
||||
uint32_t numfriends = tox_count_friendlist(m);
|
||||
|
||||
for (i = 0; i < numfriends; ++i)
|
||||
@ -405,11 +407,13 @@ void exit_toxic(Tox *m)
|
||||
store_data(m, DATA_FILE);
|
||||
close_all_file_senders();
|
||||
kill_all_windows();
|
||||
log_disable(prompt->promptbuf->log);
|
||||
log_disable(prompt->chatwin->log);
|
||||
line_info_cleanup(prompt->chatwin->hst);
|
||||
free(DATA_FILE);
|
||||
free(prompt->stb);
|
||||
free(prompt->promptbuf->log);
|
||||
free(prompt->promptbuf);
|
||||
free(prompt->chatwin->log);
|
||||
free(prompt->chatwin->hst);
|
||||
free(prompt->chatwin);
|
||||
tox_kill(m);
|
||||
#ifdef _SUPPORT_AUDIO
|
||||
terminate_audio();
|
||||
@ -501,8 +505,7 @@ int main(int argc, char *argv[])
|
||||
prompt = init_windows(m);
|
||||
|
||||
/* create new thread for ncurses stuff */
|
||||
if (pthread_mutex_init(&Winthread.lock, NULL) != 0)
|
||||
{
|
||||
if (pthread_mutex_init(&Winthread.lock, NULL) != 0) {
|
||||
endwin();
|
||||
fprintf(stderr, "Mutex init failed. Aborting...\n");
|
||||
exit(EXIT_FAILURE);
|
||||
@ -514,43 +517,39 @@ int main(int argc, char *argv[])
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#ifdef _SUPPORT_AUDIO
|
||||
|
||||
attron(COLOR_PAIR(RED) | A_BOLD);
|
||||
wprintw(prompt->window, "Starting audio...\n");
|
||||
attroff(COLOR_PAIR(RED) | A_BOLD);
|
||||
|
||||
uint8_t *msg;
|
||||
|
||||
#ifdef _SUPPORT_AUDIO
|
||||
|
||||
av = init_audio(prompt, m);
|
||||
|
||||
|
||||
if ( errors() == NoError )
|
||||
wprintw(prompt->window, "Audio started with no problems.\n");
|
||||
msg = "Audio started with no problems.";
|
||||
else /* Get error code and stuff */
|
||||
wprintw(prompt->window, "Error starting audio!\n");
|
||||
|
||||
|
||||
msg = "Error starting audio!";
|
||||
|
||||
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
|
||||
#endif /* _SUPPORT_AUDIO */
|
||||
|
||||
|
||||
if (f_loadfromfile)
|
||||
load_data(m, DATA_FILE);
|
||||
|
||||
if (f_flag == -1) {
|
||||
attron(COLOR_PAIR(RED) | A_BOLD);
|
||||
wprintw(prompt->window, "You passed '-f' without giving an argument.\n"
|
||||
"defaulting to 'data' for a keyfile...\n");
|
||||
attroff(COLOR_PAIR(RED) | A_BOLD);
|
||||
msg = "You passed '-f' without giving an argument. Defaulting to 'data' for a keyfile...";
|
||||
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
}
|
||||
|
||||
if (config_err) {
|
||||
attron(COLOR_PAIR(RED) | A_BOLD);
|
||||
wprintw(prompt->window, "Unable to determine configuration directory.\n"
|
||||
"defaulting to 'data' for a keyfile...\n");
|
||||
attroff(COLOR_PAIR(RED) | A_BOLD);
|
||||
msg = "Unable to determine configuration directory. Defaulting to 'data' for a keyfile...";
|
||||
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
}
|
||||
|
||||
sort_friendlist_index(m);
|
||||
sort_friendlist_index();
|
||||
prompt_init_statusbar(prompt, m);
|
||||
|
||||
while (true) {
|
||||
update_unix_time();
|
||||
do_toxic(m, prompt);
|
||||
usleep(10000);
|
||||
}
|
||||
|
@ -30,9 +30,36 @@
|
||||
#include <limits.h>
|
||||
|
||||
#include "toxic_windows.h"
|
||||
#include "misc_tools.h"
|
||||
|
||||
extern ToxWindow *prompt;
|
||||
|
||||
static uint64_t current_unix_time;
|
||||
|
||||
void update_unix_time(void)
|
||||
{
|
||||
current_unix_time = (uint64_t) time(NULL);
|
||||
}
|
||||
|
||||
uint64_t get_unix_time(void)
|
||||
{
|
||||
return current_unix_time;
|
||||
}
|
||||
|
||||
/* Get the current local time */
|
||||
struct tm *get_time(void)
|
||||
{
|
||||
struct tm *timeinfo;
|
||||
uint64_t t = get_unix_time();
|
||||
timeinfo = localtime(&t);
|
||||
return timeinfo;
|
||||
}
|
||||
|
||||
void get_time_str(uint8_t *buf)
|
||||
{
|
||||
strftime(buf, TIME_STR_SIZE, "[%H:%M:%S] ", get_time());
|
||||
}
|
||||
|
||||
/* XXX: FIX */
|
||||
unsigned char *hex_string_to_bin(char hex_string[])
|
||||
{
|
||||
@ -54,27 +81,6 @@ unsigned char *hex_string_to_bin(char hex_string[])
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Get the current local time */
|
||||
struct tm *get_time(void)
|
||||
{
|
||||
struct tm *timeinfo;
|
||||
time_t now;
|
||||
time(&now);
|
||||
timeinfo = localtime(&now);
|
||||
return timeinfo;
|
||||
}
|
||||
|
||||
/* Prints the time to given window */
|
||||
void print_time(WINDOW *window)
|
||||
{
|
||||
uint8_t s[MAX_STR_SIZE];
|
||||
strftime(s, MAX_STR_SIZE, "[%H:%M:%S] ", get_time());
|
||||
|
||||
wattron(window, COLOR_PAIR(BLUE));
|
||||
wprintw(window, "%s", s);
|
||||
wattroff(window,COLOR_PAIR(BLUE));
|
||||
}
|
||||
|
||||
/* Returns 1 if the string is empty, 0 otherwise */
|
||||
int string_is_empty(char *string)
|
||||
{
|
||||
|
@ -26,11 +26,17 @@
|
||||
/* convert a hex string to binary */
|
||||
unsigned char *hex_string_to_bin(char hex_string[]);
|
||||
|
||||
/* get the current unix time */
|
||||
uint64_t get_unix_time(void);
|
||||
|
||||
/*Puts the current time in buf in the format of [Hour:Min:Sec] */
|
||||
void get_time_str(uint8_t *buf);
|
||||
|
||||
/* get the current local time */
|
||||
struct tm *get_time(void);
|
||||
|
||||
/* Prints the time to given window */
|
||||
void print_time(WINDOW *window);
|
||||
/* updates current unix time (should be run once per do_toxic loop) */
|
||||
void update_unix_time(void);
|
||||
|
||||
/* Returns 1 if the string is empty, 0 otherwise */
|
||||
int string_is_empty(char *string);
|
||||
@ -61,7 +67,7 @@ int qsort_strcasecmp_hlpr(const void *nick1, const void *nick2);
|
||||
- cannot be empty
|
||||
- cannot start with a space
|
||||
- must not contain contiguous spaces */
|
||||
bool valid_nick(uint8_t *nick);
|
||||
int valid_nick(uint8_t *nick);
|
||||
|
||||
/* Moves the cursor to the end of the line in given window */
|
||||
void mv_curs_end(WINDOW *w, size_t len, int max_y, int max_x);
|
||||
|
491
src/prompt.c
491
src/prompt.c
@ -32,6 +32,8 @@
|
||||
#include "execute.h"
|
||||
#include "misc_tools.h"
|
||||
#include "toxic_strings.h"
|
||||
#include "log.h"
|
||||
#include "line_info.h"
|
||||
|
||||
uint8_t pending_frnd_requests[MAX_FRIENDS_NUM][TOX_CLIENT_ID_SIZE] = {0};
|
||||
uint8_t num_frnd_requests = 0;
|
||||
@ -64,25 +66,6 @@ const uint8_t glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
|
||||
#endif /* _SUPPORT_AUDIO */
|
||||
};
|
||||
|
||||
/* prevents input string from eating system messages: call this prior to printing a prompt message
|
||||
TODO: This is only a partial fix */
|
||||
void prep_prompt_win(void)
|
||||
{
|
||||
PromptBuf *prt = prompt->promptbuf;
|
||||
|
||||
if (prt->len <= 0)
|
||||
return;
|
||||
|
||||
wprintw(prompt->window, "\n");
|
||||
|
||||
if (!prt->at_bottom) {
|
||||
wmove(prompt->window, prt->orig_y - 1, X_OFST);
|
||||
++prt->orig_y;
|
||||
} else {
|
||||
wmove(prompt->window, prt->orig_y - 2, X_OFST);
|
||||
}
|
||||
}
|
||||
|
||||
/* Updates own nick in prompt statusbar */
|
||||
void prompt_update_nick(ToxWindow *prompt, uint8_t *nick, uint16_t len)
|
||||
{
|
||||
@ -100,7 +83,7 @@ void prompt_update_statusmessage(ToxWindow *prompt, uint8_t *statusmsg, uint16_t
|
||||
}
|
||||
|
||||
/* Updates own status in prompt statusbar */
|
||||
void prompt_update_status(ToxWindow *prompt, TOX_USERSTATUS status)
|
||||
void prompt_update_status(ToxWindow *prompt, uint8_t status)
|
||||
{
|
||||
StatusBar *statusbar = prompt->stb;
|
||||
statusbar->status = status;
|
||||
@ -136,153 +119,166 @@ static int add_friend_request(uint8_t *public_key)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key)
|
||||
static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
{
|
||||
PromptBuf *prt = self->promptbuf;
|
||||
ChatContext *ctx = self->chatwin;
|
||||
|
||||
int x, y, y2, x2;
|
||||
getyx(self->window, y, x);
|
||||
getmaxyx(self->window, y2, x2);
|
||||
getyx(ctx->history, y, x);
|
||||
getmaxyx(ctx->history, y2, x2);
|
||||
|
||||
/* BACKSPACE key: Remove one character from line */
|
||||
if (key == 0x107 || key == 0x8 || key == 0x7f) {
|
||||
if (prt->pos > 0) {
|
||||
del_char_buf_bck(prt->line, &prt->pos, &prt->len);
|
||||
wmove(self->window, y, x-1); /* not necessary but fixes a display glitch */
|
||||
prt->scroll = false;
|
||||
} else {
|
||||
beep();
|
||||
/* TODO this is buggy */
|
||||
/* ESC key: Toggle history scroll mode */
|
||||
/*
|
||||
if (key == T_KEY_ESC) {
|
||||
bool scroll = ctx->hst->scroll_mode ? false : true;
|
||||
line_info_toggle_scroll(self, scroll);
|
||||
}
|
||||
*/
|
||||
|
||||
/* If we're in scroll mode ignore rest of function */
|
||||
if (ctx->hst->scroll_mode) {
|
||||
line_info_onKey(self, key);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ltr) {
|
||||
if (ctx->len < (MAX_STR_SIZE-1)) {
|
||||
add_char_to_buf(ctx->line, &ctx->pos, &ctx->len, key);
|
||||
}
|
||||
}
|
||||
} else { /* if (!ltr) */
|
||||
|
||||
else if (key == KEY_DC) { /* DEL key: Remove character at pos */
|
||||
if (prt->pos != prt->len) {
|
||||
del_char_buf_frnt(prt->line, &prt->pos, &prt->len);
|
||||
prt->scroll = false;
|
||||
} else {
|
||||
beep();
|
||||
}
|
||||
}
|
||||
|
||||
else if (key == T_KEY_DISCARD) { /* CTRL-U: Delete entire line behind pos */
|
||||
if (prt->pos > 0) {
|
||||
wmove(self->window, prt->orig_y, X_OFST);
|
||||
wclrtobot(self->window);
|
||||
discard_buf(prt->line, &prt->pos, &prt->len);
|
||||
} else {
|
||||
beep();
|
||||
}
|
||||
}
|
||||
|
||||
else if (key == T_KEY_KILL) { /* CTRL-K: Delete entire line in front of pos */
|
||||
if (prt->len != prt->pos)
|
||||
kill_buf(prt->line, &prt->pos, &prt->len);
|
||||
else
|
||||
beep();
|
||||
}
|
||||
|
||||
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 || key == T_KEY_C_E) { /* END/C-e key: move cursor to end of line */
|
||||
if (prt->pos != prt->len)
|
||||
prt->pos = prt->len;
|
||||
}
|
||||
|
||||
else if (key == KEY_LEFT) {
|
||||
if (prt->pos > 0)
|
||||
--prt->pos;
|
||||
else
|
||||
beep();
|
||||
}
|
||||
|
||||
else if (key == KEY_RIGHT) {
|
||||
if (prt->pos < prt->len)
|
||||
++prt->pos;
|
||||
else
|
||||
beep();
|
||||
}
|
||||
|
||||
else if (key == KEY_UP) { /* fetches previous item in history */
|
||||
wmove(self->window, prt->orig_y, X_OFST);
|
||||
fetch_hist_item(prt->line, &prt->pos, &prt->len, prt->ln_history, prt->hst_tot,
|
||||
&prt->hst_pos, LN_HIST_MV_UP);
|
||||
|
||||
/* adjust line y origin appropriately when window scrolls down */
|
||||
if (prt->at_bottom && prt->len >= x2 - X_OFST) {
|
||||
int px2 = prt->len >= x2 ? x2 : x2 - X_OFST;
|
||||
int p_ofst = px2 != x2 ? 0 : X_OFST;
|
||||
|
||||
if (px2 <= 0)
|
||||
return;
|
||||
|
||||
int k = prt->orig_y + ((prt->len + p_ofst) / px2);
|
||||
|
||||
if (k >= y2) {
|
||||
wprintw(self->window, "\n");
|
||||
--prt->orig_y;
|
||||
/* BACKSPACE key: Remove one character from line */
|
||||
if (key == 0x107 || key == 0x8 || key == 0x7f) {
|
||||
if (ctx->pos > 0) {
|
||||
del_char_buf_bck(ctx->line, &ctx->pos, &ctx->len);
|
||||
wmove(ctx->history, y, x-1); /* not necessary but fixes a display glitch */
|
||||
} else {
|
||||
beep();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (key == KEY_DOWN) { /* fetches next item in history */
|
||||
wmove(self->window, prt->orig_y, X_OFST);
|
||||
fetch_hist_item(prt->line, &prt->pos, &prt->len, prt->ln_history, prt->hst_tot,
|
||||
&prt->hst_pos, LN_HIST_MV_DWN);
|
||||
}
|
||||
|
||||
else if (key == '\t') { /* TAB key: completes command */
|
||||
if (prt->len > 1 && prt->line[0] == '/') {
|
||||
if (complete_line(prt->line, &prt->pos, &prt->len, glob_cmd_list, AC_NUM_GLOB_COMMANDS,
|
||||
MAX_CMDNAME_SIZE) == -1)
|
||||
else if (key == KEY_DC) { /* DEL key: Remove character at pos */
|
||||
if (ctx->pos != ctx->len) {
|
||||
del_char_buf_frnt(ctx->line, &ctx->pos, &ctx->len);
|
||||
} else {
|
||||
beep();
|
||||
} else {
|
||||
beep();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
#if HAVE_WIDECHAR
|
||||
if (iswprint(key))
|
||||
#else
|
||||
if (isprint(key))
|
||||
#endif
|
||||
{
|
||||
if (prt->len < (MAX_STR_SIZE-1)) {
|
||||
add_char_to_buf(prt->line, &prt->pos, &prt->len, key);
|
||||
prt->scroll = true;
|
||||
else if (key == T_KEY_DISCARD) { /* CTRL-U: Delete entire line behind pos */
|
||||
if (ctx->pos > 0) {
|
||||
wmove(ctx->history, ctx->orig_y, X_OFST);
|
||||
wclrtobot(ctx->history);
|
||||
discard_buf(ctx->line, &ctx->pos, &ctx->len);
|
||||
} else {
|
||||
beep();
|
||||
}
|
||||
}
|
||||
}
|
||||
/* RETURN key: execute command */
|
||||
else if (key == '\n') {
|
||||
wprintw(self->window, "\n");
|
||||
uint8_t line[MAX_STR_SIZE];
|
||||
|
||||
if (wcs_to_mbs_buf(line, prt->line, MAX_STR_SIZE) == -1)
|
||||
memset(&line, 0, sizeof(line));
|
||||
else if (key == T_KEY_KILL) { /* CTRL-K: Delete entire line in front of pos */
|
||||
if (ctx->len != ctx->pos)
|
||||
kill_buf(ctx->line, &ctx->pos, &ctx->len);
|
||||
else
|
||||
beep();
|
||||
}
|
||||
|
||||
if (!string_is_empty(line))
|
||||
add_line_to_hist(prt->line, prt->len, prt->ln_history, &prt->hst_tot, &prt->hst_pos);
|
||||
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;
|
||||
}
|
||||
|
||||
execute(self->window, self, m, line, GLOBAL_COMMAND_MODE);
|
||||
reset_buf(prt->line, &prt->pos, &prt->len);
|
||||
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;
|
||||
}
|
||||
|
||||
else if (key == KEY_LEFT) {
|
||||
if (ctx->pos > 0)
|
||||
--ctx->pos;
|
||||
else
|
||||
beep();
|
||||
}
|
||||
|
||||
else if (key == KEY_RIGHT) {
|
||||
if (ctx->pos < ctx->len)
|
||||
++ctx->pos;
|
||||
else
|
||||
beep();
|
||||
}
|
||||
|
||||
else if (key == KEY_UP) { /* fetches previous item in history */
|
||||
wmove(ctx->history, ctx->orig_y, X_OFST);
|
||||
fetch_hist_item(ctx->line, &ctx->pos, &ctx->len, ctx->ln_history, ctx->hst_tot,
|
||||
&ctx->hst_pos, MOVE_UP);
|
||||
|
||||
/* adjust line y origin appropriately when window scrolls down */
|
||||
if (ctx->at_bottom && ctx->len >= x2 - X_OFST) {
|
||||
int px2 = ctx->len >= x2 ? x2 : x2 - X_OFST;
|
||||
int p_ofst = px2 != x2 ? 0 : X_OFST;
|
||||
|
||||
if (px2 <= 0)
|
||||
return;
|
||||
|
||||
int k = ctx->orig_y + ((ctx->len + p_ofst) / px2);
|
||||
|
||||
if (k >= y2) {
|
||||
--ctx->orig_y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (key == KEY_DOWN) { /* fetches next item in history */
|
||||
wmove(ctx->history, ctx->orig_y, X_OFST);
|
||||
fetch_hist_item(ctx->line, &ctx->pos, &ctx->len, ctx->ln_history, ctx->hst_tot,
|
||||
&ctx->hst_pos, MOVE_DOWN);
|
||||
}
|
||||
|
||||
else if (key == '\t') { /* TAB key: completes command */
|
||||
if (ctx->len > 1 && ctx->line[0] == '/') {
|
||||
if (complete_line(ctx->line, &ctx->pos, &ctx->len, glob_cmd_list, AC_NUM_GLOB_COMMANDS,
|
||||
MAX_CMDNAME_SIZE) == -1)
|
||||
beep();
|
||||
} else {
|
||||
beep();
|
||||
}
|
||||
}
|
||||
|
||||
/* RETURN key: execute command */
|
||||
else if (key == '\n') {
|
||||
wprintw(ctx->history, "\n");
|
||||
uint8_t line[MAX_STR_SIZE] = {0};
|
||||
|
||||
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
|
||||
memset(&line, 0, sizeof(line));
|
||||
|
||||
if (!string_is_empty(line))
|
||||
add_line_to_hist(ctx->line, ctx->len, ctx->ln_history, &ctx->hst_tot, &ctx->hst_pos);
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, line, PROMPT, 0, 0);
|
||||
execute(ctx->history, self, m, line, GLOBAL_COMMAND_MODE);
|
||||
reset_buf(ctx->line, &ctx->pos, &ctx->len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void prompt_onDraw(ToxWindow *self, Tox *m)
|
||||
{
|
||||
PromptBuf *prt = self->promptbuf;
|
||||
ChatContext *ctx = self->chatwin;
|
||||
|
||||
curs_set(1);
|
||||
int x, y, x2, y2;
|
||||
getyx(self->window, y, x);
|
||||
getmaxyx(self->window, y2, x2);
|
||||
wclrtobot(self->window);
|
||||
getyx(ctx->history, y, x);
|
||||
getmaxyx(ctx->history, y2, x2);
|
||||
|
||||
if (!ctx->hst->scroll_mode) {
|
||||
curs_set(1);
|
||||
scrollok(ctx->history, 1);
|
||||
}
|
||||
|
||||
line_info_print(self);
|
||||
|
||||
/* if len is >= screen width offset max x by X_OFST to account for prompt char */
|
||||
int px2 = prt->len >= x2 ? x2 : x2 - X_OFST;
|
||||
int px2 = ctx->len >= x2 ? x2 : x2 - X_OFST;
|
||||
|
||||
if (px2 <= 0)
|
||||
return;
|
||||
@ -290,33 +286,31 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
||||
/* len offset to account for prompt char (0 if len is < width of screen) */
|
||||
int p_ofst = px2 != x2 ? 0 : X_OFST;
|
||||
|
||||
if (prt->len > 0) {
|
||||
if (ctx->len > 0) {
|
||||
uint8_t line[MAX_STR_SIZE];
|
||||
|
||||
if (wcs_to_mbs_buf(line, prt->line, MAX_STR_SIZE) == -1)
|
||||
reset_buf(prt->line, &prt->pos, &prt->len);
|
||||
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
|
||||
reset_buf(ctx->line, &ctx->pos, &ctx->len);
|
||||
else
|
||||
mvwprintw(self->window, prt->orig_y, X_OFST, line);
|
||||
mvwprintw(ctx->history, ctx->orig_y, X_OFST, line);
|
||||
|
||||
int k = prt->orig_y + ((prt->len + p_ofst) / px2);
|
||||
int k = ctx->orig_y + ((ctx->len + p_ofst) / px2);
|
||||
|
||||
prt->at_bottom = k == y2 - 1;
|
||||
ctx->at_bottom = k == y2 - 1;
|
||||
bool botm = k == y2;
|
||||
bool edge = (prt->len + p_ofst) % px2 == 0;
|
||||
bool edge = (ctx->len + p_ofst) % px2 == 0;
|
||||
|
||||
/* move point of line origin up when input scrolls screen down */
|
||||
if (prt->scroll && edge && botm) {
|
||||
--prt->orig_y;
|
||||
prt->scroll = false;
|
||||
}
|
||||
if (edge && botm)
|
||||
--ctx->orig_y;
|
||||
|
||||
} else { /* Mark point of origin for new line */
|
||||
prt->orig_y = y;
|
||||
ctx->orig_y = y;
|
||||
}
|
||||
|
||||
wattron(self->window, COLOR_PAIR(GREEN));
|
||||
mvwprintw(self->window, prt->orig_y, 0, "$ ");
|
||||
wattroff(self->window, COLOR_PAIR(GREEN));
|
||||
wattron(ctx->history, COLOR_PAIR(GREEN));
|
||||
mvwprintw(ctx->history, ctx->orig_y, 0, "$ ");
|
||||
wattroff(ctx->history, COLOR_PAIR(GREEN));
|
||||
|
||||
StatusBar *statusbar = self->stb;
|
||||
werase(statusbar->topline);
|
||||
@ -325,7 +319,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
||||
|
||||
if (statusbar->is_online) {
|
||||
int colour = WHITE;
|
||||
char *status_text = "Unknown";
|
||||
const uint8_t *status_text = "Unknown";
|
||||
|
||||
switch (statusbar->status) {
|
||||
case TOX_USERSTATUS_NONE:
|
||||
@ -340,159 +334,164 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
||||
status_text = "Busy";
|
||||
colour = RED;
|
||||
break;
|
||||
case TOX_USERSTATUS_INVALID:
|
||||
status_text = "ERROR";
|
||||
colour = MAGENTA;
|
||||
break;
|
||||
}
|
||||
wattron(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
|
||||
wprintw(statusbar->topline, " [%s]", status_text);
|
||||
wattroff(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
|
||||
|
||||
wattron(statusbar->topline, A_BOLD);
|
||||
wprintw(statusbar->topline, " %s ", statusbar->nick);
|
||||
wattron(statusbar->topline, A_BOLD);
|
||||
wattron(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
|
||||
wprintw(statusbar->topline, "[%s]", status_text);
|
||||
wattroff(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
|
||||
wprintw(statusbar->topline, " %s", statusbar->nick);
|
||||
wattroff(statusbar->topline, A_BOLD);
|
||||
} else {
|
||||
wprintw(statusbar->topline, "[Offline]");
|
||||
wattron(statusbar->topline, A_BOLD);
|
||||
wprintw(statusbar->topline, " %s ", statusbar->nick);
|
||||
wattroff(statusbar->topline, A_BOLD);
|
||||
wprintw(statusbar->topline, "[Offline]");
|
||||
}
|
||||
|
||||
wattron(statusbar->topline, A_BOLD);
|
||||
wprintw(statusbar->topline, " - %s", statusbar->statusmsg);
|
||||
wattroff(statusbar->topline, A_BOLD);
|
||||
if (statusbar->statusmsg[0])
|
||||
wprintw(statusbar->topline, " - %s", statusbar->statusmsg);
|
||||
|
||||
/* put cursor back in correct spot */
|
||||
int y_m = prt->orig_y + ((prt->pos + p_ofst) / px2);
|
||||
int x_m = (prt->pos + X_OFST) % x2;
|
||||
int y_m = ctx->orig_y + ((ctx->pos + p_ofst) / px2);
|
||||
int x_m = (ctx->pos + X_OFST) % x2;
|
||||
wmove(self->window, y_m, x_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);
|
||||
}
|
||||
|
||||
static void prompt_onConnectionChange(ToxWindow *self, Tox *m, int friendnum , uint8_t status)
|
||||
static void prompt_onConnectionChange(ToxWindow *self, Tox *m, int32_t friendnum , uint8_t status)
|
||||
{
|
||||
if (friendnum < 0)
|
||||
return;
|
||||
|
||||
PromptBuf *prt = self->promptbuf;
|
||||
prep_prompt_win();
|
||||
ChatContext *ctx = self->chatwin;
|
||||
|
||||
uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'};
|
||||
uint8_t nick[TOX_MAX_NAME_LENGTH] = {0};
|
||||
int n_len = tox_get_name(m, friendnum, nick);
|
||||
n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH-1);
|
||||
|
||||
if (tox_get_name(m, friendnum, nick) == -1)
|
||||
return;
|
||||
|
||||
if (!nick[0])
|
||||
if (!nick[0]) {
|
||||
snprintf(nick, sizeof(nick), "%s", UNKNOWN_NAME);
|
||||
n_len = strlen(UNKNOWN_NAME);
|
||||
}
|
||||
|
||||
wprintw(self->window, "\n");
|
||||
print_time(self->window);
|
||||
nick[n_len] = '\0';
|
||||
|
||||
uint8_t timefrmt[TIME_STR_SIZE];
|
||||
get_time_str(timefrmt);
|
||||
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, "%s\n", msg);
|
||||
wattroff(self->window, COLOR_PAIR(GREEN));
|
||||
|
||||
write_to_log(msg, nick, prt->log, true);
|
||||
line_info_add(self, timefrmt, nick, NULL, msg, CONNECTION, 0, GREEN);
|
||||
write_to_log(msg, nick, ctx->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, "%s\n", msg);
|
||||
wattroff(self->window, COLOR_PAIR(RED));
|
||||
|
||||
write_to_log(msg, nick, prt->log, true);
|
||||
line_info_add(self, timefrmt, nick, NULL, msg, CONNECTION, 0, RED);
|
||||
write_to_log(msg, nick, ctx->log, true);
|
||||
}
|
||||
}
|
||||
|
||||
static void prompt_onFriendRequest(ToxWindow *self, uint8_t *key, uint8_t *data, uint16_t length)
|
||||
static void prompt_onFriendRequest(ToxWindow *self, Tox *m, uint8_t *key, uint8_t *data, uint16_t length)
|
||||
{
|
||||
/* make sure message data is null-terminated */
|
||||
data[length - 1] = 0;
|
||||
PromptBuf *prt = self->promptbuf;
|
||||
prep_prompt_win();
|
||||
data[length] = '\0';
|
||||
|
||||
wprintw(self->window, "\n");
|
||||
print_time(self->window);
|
||||
ChatContext *ctx = self->chatwin;
|
||||
|
||||
uint8_t timefrmt[TIME_STR_SIZE];
|
||||
get_time_str(timefrmt);
|
||||
|
||||
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);
|
||||
snprintf(msg, sizeof(msg), "Friend request with the message '%s'", data);
|
||||
line_info_add(self, timefrmt, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
write_to_log(msg, "", ctx->log, true);
|
||||
|
||||
int n = add_friend_request(key);
|
||||
|
||||
if (n == -1) {
|
||||
uint8_t *errmsg = "Friend request queue is full. Discarding request.\n";
|
||||
wprintw(self->window, "%s", errmsg);
|
||||
write_to_log(errmsg, "", prt->log, true);
|
||||
uint8_t *errmsg = "Friend request queue is full. Discarding request.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
write_to_log(errmsg, "", ctx->log, true);
|
||||
return;
|
||||
}
|
||||
|
||||
wprintw(self->window, "Type \"/accept %d\" to accept it.\n", n);
|
||||
snprintf(msg, sizeof(msg), "Type \"/accept %d\" to accept it.", n);
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
alert_window(self, WINDOW_ALERT_1, true);
|
||||
}
|
||||
|
||||
void prompt_init_statusbar(ToxWindow *self, Tox *m)
|
||||
{
|
||||
int x, y;
|
||||
getmaxyx(self->window, y, x);
|
||||
int x2, y2;
|
||||
getmaxyx(self->window, y2, x2);
|
||||
|
||||
/* Init statusbar info */
|
||||
StatusBar *statusbar = self->stb;
|
||||
statusbar->status = TOX_USERSTATUS_NONE;
|
||||
statusbar->is_online = false;
|
||||
|
||||
uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'};
|
||||
uint8_t nick[TOX_MAX_NAME_LENGTH];
|
||||
uint8_t statusmsg[MAX_STR_SIZE];
|
||||
|
||||
pthread_mutex_lock(&Winthread.lock);
|
||||
tox_get_self_name(m, nick, TOX_MAX_NAME_LENGTH);
|
||||
tox_get_self_status_message(m, statusmsg, MAX_STR_SIZE);
|
||||
uint16_t n_len = tox_get_self_name(m, nick);
|
||||
uint16_t s_len = tox_get_self_status_message(m, statusmsg, MAX_STR_SIZE);
|
||||
uint8_t status = tox_get_self_user_status(m);
|
||||
pthread_mutex_unlock(&Winthread.lock);
|
||||
|
||||
snprintf(statusbar->nick, sizeof(statusbar->nick), "%s", nick);
|
||||
nick[n_len] = '\0';
|
||||
statusmsg[s_len] = '\0';
|
||||
|
||||
/* temporary until statusmessage saving works */
|
||||
/* load prev status message or show toxic version if it has never been set */
|
||||
uint8_t ver[strlen(TOXICVER) + 1];
|
||||
strcpy(ver, TOXICVER);
|
||||
uint8_t *toxic_ver = strtok(ver, "_");
|
||||
const uint8_t *toxic_ver = strtok(ver, "_");
|
||||
|
||||
if (!strcmp("Online", statusmsg))
|
||||
if ( (!strcmp("Online", statusmsg) || !strncmp("Toxing on Toxic", statusmsg, 15)) && toxic_ver != NULL) {
|
||||
snprintf(statusmsg, MAX_STR_SIZE, "Toxing on Toxic v.%s", toxic_ver);
|
||||
s_len = strlen(statusmsg);
|
||||
statusmsg[s_len] = '\0';
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&Winthread.lock);
|
||||
tox_set_status_message(m, statusmsg, strlen(statusmsg) + 1);
|
||||
pthread_mutex_unlock(&Winthread.lock);
|
||||
|
||||
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
|
||||
prompt_update_statusmessage(prompt, statusmsg, s_len);
|
||||
prompt_update_status(prompt, status);
|
||||
prompt_update_nick(prompt, nick, n_len);
|
||||
|
||||
/* Init statusbar subwindow */
|
||||
statusbar->topline = subwin(self->window, 2, x, 0, 0);
|
||||
statusbar->topline = subwin(self->window, 2, x2, 0, 0);
|
||||
}
|
||||
|
||||
static void prompt_onInit(ToxWindow *self, Tox *m)
|
||||
{
|
||||
ChatContext *ctx = self->chatwin;
|
||||
|
||||
curs_set(1);
|
||||
int y2, x2;
|
||||
getmaxyx(self->window, y2, x2);
|
||||
|
||||
ctx->history = subwin(self->window, y2, x2, 0, 0);
|
||||
scrollok(ctx->history, 1);
|
||||
|
||||
ctx->log = malloc(sizeof(struct chatlog));
|
||||
ctx->hst = malloc(sizeof(struct history));
|
||||
|
||||
if (ctx->log == NULL || ctx->hst == NULL) {
|
||||
endwin();
|
||||
fprintf(stderr, "malloc() failed. Aborting...\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memset(ctx->log, 0, sizeof(struct chatlog));
|
||||
memset(ctx->hst, 0, sizeof(struct history));
|
||||
|
||||
line_info_init(ctx->hst);
|
||||
execute(ctx->history, self, m, "/help", GLOBAL_COMMAND_MODE);
|
||||
|
||||
wmove(ctx->history, y2-1, 2);
|
||||
}
|
||||
|
||||
ToxWindow new_prompt(void)
|
||||
@ -511,11 +510,11 @@ ToxWindow new_prompt(void)
|
||||
|
||||
strcpy(ret.name, "prompt");
|
||||
|
||||
PromptBuf *promptbuf = calloc(1, sizeof(PromptBuf));
|
||||
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
|
||||
StatusBar *stb = calloc(1, sizeof(StatusBar));
|
||||
|
||||
if (stb != NULL && promptbuf != NULL) {
|
||||
ret.promptbuf = promptbuf;
|
||||
if (stb != NULL && chatwin != NULL) {
|
||||
ret.chatwin = chatwin;
|
||||
ret.stb = stb;
|
||||
} else {
|
||||
endwin();
|
||||
|
@ -37,7 +37,7 @@ void prep_prompt_win(void);
|
||||
void prompt_init_statusbar(ToxWindow *self, Tox *m);
|
||||
void prompt_update_nick(ToxWindow *prompt, uint8_t *nick, uint16_t len);
|
||||
void prompt_update_statusmessage(ToxWindow *prompt, uint8_t *statusmsg, uint16_t len);
|
||||
void prompt_update_status(ToxWindow *prompt, TOX_USERSTATUS status);
|
||||
void prompt_update_status(ToxWindow *prompt, uint8_t status);
|
||||
void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected);
|
||||
|
||||
#endif /* end of include guard: PROMPT_H_UZYGWFFL */
|
||||
|
@ -148,7 +148,7 @@ void add_line_to_hist(const wchar_t *buf, size_t len, wchar_t (*hst)[MAX_STR_SIZ
|
||||
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 (key_dir == MOVE_UP) {
|
||||
if (--(*hst_pos) < 0) {
|
||||
*hst_pos = 0;
|
||||
beep();
|
||||
|
@ -48,11 +48,6 @@ void reset_buf(wchar_t *buf, size_t *pos, size_t *len);
|
||||
Returns the difference between the old len and new len of buf on success, -1 if error */
|
||||
int complete_line(wchar_t *buf, size_t *pos, size_t *len, const void *list, int n_items, int size);
|
||||
|
||||
enum {
|
||||
LN_HIST_MV_UP,
|
||||
LN_HIST_MV_DWN,
|
||||
};
|
||||
|
||||
/* adds a line to the ln_history buffer at hst_pos and sets hst_pos to last history item. */
|
||||
void add_line_to_hist(const wchar_t *buf, size_t len, wchar_t (*hst)[MAX_STR_SIZE], int *hst_tot,
|
||||
int *hst_pos);
|
||||
|
@ -49,6 +49,7 @@
|
||||
#define CURS_Y_OFFSET 3 /* y-axis cursor offset for chat contexts */
|
||||
#define CHATBOX_HEIGHT 4
|
||||
#define KEY_IDENT_DIGITS 2 /* number of hex digits to display for the pub-key based identifier */
|
||||
#define TIME_STR_SIZE 16
|
||||
|
||||
#define EXIT_SUCCESS 0
|
||||
#define EXIT_FAILURE 1
|
||||
@ -60,6 +61,7 @@
|
||||
#define T_KEY_PREV 0x0F /* ctrl-o */
|
||||
#define T_KEY_C_E 0x05 /* ctrl-e */
|
||||
#define T_KEY_C_A 0x01 /* ctrl-a */
|
||||
#define T_KEY_ESC 0x1B /* ESC key */
|
||||
|
||||
/* Curses foreground colours (background is black) */
|
||||
enum {
|
||||
@ -80,7 +82,12 @@ enum {
|
||||
WINDOW_ALERT_2,
|
||||
};
|
||||
|
||||
/* Fixes text color problem on some terminals.
|
||||
enum {
|
||||
MOVE_UP,
|
||||
MOVE_DOWN,
|
||||
};
|
||||
|
||||
/* Fixes text color problem on some terminals.
|
||||
Uncomment if necessary */
|
||||
/* #define URXVT_FIX */
|
||||
|
||||
@ -90,25 +97,25 @@ typedef struct PromptBuf PromptBuf;
|
||||
typedef struct ChatContext ChatContext;
|
||||
|
||||
struct ToxWindow {
|
||||
void(*onKey)(ToxWindow *, Tox *, wint_t);
|
||||
void(*onKey)(ToxWindow *, Tox *, wint_t, bool);
|
||||
void(*onDraw)(ToxWindow *, Tox *);
|
||||
void(*onInit)(ToxWindow *, Tox *);
|
||||
void(*onFriendRequest)(ToxWindow *, uint8_t *, uint8_t *, uint16_t);
|
||||
void(*onFriendAdded)(ToxWindow *, Tox *, int, bool);
|
||||
void(*onConnectionChange)(ToxWindow *, Tox *, int, uint8_t);
|
||||
void(*onMessage)(ToxWindow *, Tox *, int, uint8_t *, uint16_t);
|
||||
void(*onNickChange)(ToxWindow *, Tox *, int, uint8_t *, uint16_t);
|
||||
void(*onStatusChange)(ToxWindow *, Tox *, int, TOX_USERSTATUS);
|
||||
void(*onStatusMessageChange)(ToxWindow *, int, uint8_t *, uint16_t);
|
||||
void(*onAction)(ToxWindow *, Tox *, int, uint8_t *, uint16_t);
|
||||
void(*onFriendRequest)(ToxWindow *, Tox *, uint8_t *, uint8_t *, uint16_t);
|
||||
void(*onFriendAdded)(ToxWindow *, Tox *, int32_t, bool);
|
||||
void(*onConnectionChange)(ToxWindow *, Tox *, int32_t, uint8_t);
|
||||
void(*onMessage)(ToxWindow *, Tox *, int32_t, uint8_t *, uint16_t);
|
||||
void(*onNickChange)(ToxWindow *, Tox *, int32_t, uint8_t *, uint16_t);
|
||||
void(*onStatusChange)(ToxWindow *, Tox *, int32_t, uint8_t);
|
||||
void(*onStatusMessageChange)(ToxWindow *, int32_t, uint8_t *, uint16_t);
|
||||
void(*onAction)(ToxWindow *, Tox *, int32_t, uint8_t *, uint16_t);
|
||||
void(*onGroupMessage)(ToxWindow *, Tox *, int, int, uint8_t *, uint16_t);
|
||||
void(*onGroupAction)(ToxWindow *, Tox *, int, int, uint8_t *, uint16_t);
|
||||
void(*onGroupInvite)(ToxWindow *, Tox *, int, uint8_t *);
|
||||
void(*onGroupInvite)(ToxWindow *, Tox *, int32_t, uint8_t *);
|
||||
void(*onGroupNamelistChange)(ToxWindow *, Tox*, int, int, uint8_t);
|
||||
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);
|
||||
void(*onFileSendRequest)(ToxWindow *, Tox *, int32_t, uint8_t, uint64_t, uint8_t *, uint16_t);
|
||||
void(*onFileControl)(ToxWindow *, Tox *, int32_t, uint8_t, uint8_t, uint8_t, uint8_t *, uint16_t);
|
||||
void(*onFileData)(ToxWindow *, Tox *, int32_t, uint8_t, uint8_t *, uint16_t);
|
||||
void(*onTypingChange)(ToxWindow *, Tox *, int32_t, uint8_t);
|
||||
|
||||
#ifdef _SUPPORT_AUDIO
|
||||
|
||||
@ -123,11 +130,11 @@ struct ToxWindow {
|
||||
void(*onEnd)(ToxWindow *, ToxAv *);
|
||||
void(*onRequestTimeout)(ToxWindow *, ToxAv *);
|
||||
void(*onPeerTimeout)(ToxWindow *, ToxAv *);
|
||||
|
||||
|
||||
#endif /* _SUPPORT_AUDIO */
|
||||
|
||||
|
||||
char name[TOX_MAX_NAME_LENGTH];
|
||||
int num;
|
||||
int32_t num; /* corresponds to friendnumber in chat windows */
|
||||
bool active;
|
||||
int x;
|
||||
|
||||
@ -141,7 +148,6 @@ struct ToxWindow {
|
||||
bool alert2;
|
||||
|
||||
ChatContext *chatwin;
|
||||
PromptBuf *promptbuf;
|
||||
StatusBar *stb;
|
||||
|
||||
WINDOW *popup;
|
||||
@ -150,24 +156,15 @@ struct ToxWindow {
|
||||
|
||||
/* statusbar info holder */
|
||||
struct StatusBar {
|
||||
WINDOW *topline;
|
||||
WINDOW *topline;
|
||||
uint8_t statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH];
|
||||
uint16_t statusmsg_len;
|
||||
uint8_t nick[TOX_MAX_NAME_LENGTH];
|
||||
uint16_t nick_len;
|
||||
TOX_USERSTATUS status;
|
||||
uint8_t status;
|
||||
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 */
|
||||
@ -176,35 +173,22 @@ struct ChatContext {
|
||||
size_t pos;
|
||||
size_t len;
|
||||
|
||||
wchar_t ln_history[MAX_LINE_HIST][MAX_STR_SIZE];
|
||||
wchar_t ln_history[MAX_LINE_HIST][MAX_STR_SIZE]; /* history for input lines/commands */
|
||||
int hst_pos;
|
||||
int hst_tot;
|
||||
|
||||
bool self_is_typing;
|
||||
|
||||
struct history *hst;
|
||||
struct chatlog *log;
|
||||
|
||||
uint8_t self_is_typing;
|
||||
|
||||
WINDOW *history;
|
||||
WINDOW *linewin;
|
||||
WINDOW *sidebar;
|
||||
};
|
||||
|
||||
/* prompt window/buffer holder */
|
||||
struct PromptBuf {
|
||||
wchar_t line[MAX_STR_SIZE];
|
||||
size_t pos;
|
||||
size_t len;
|
||||
|
||||
/* specific for prompt */
|
||||
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 */
|
||||
|
||||
wchar_t ln_history[MAX_LINE_HIST][MAX_STR_SIZE];
|
||||
int hst_pos;
|
||||
int hst_tot;
|
||||
|
||||
struct chatlog *log;
|
||||
WINDOW *linewin;
|
||||
};
|
||||
|
||||
/* Start file transfer code */
|
||||
@ -216,19 +200,23 @@ struct PromptBuf {
|
||||
typedef struct {
|
||||
FILE *file;
|
||||
ToxWindow *toxwin;
|
||||
int friendnum;
|
||||
int32_t friendnum;
|
||||
bool active;
|
||||
uint8_t filenum;
|
||||
int filenum;
|
||||
uint8_t nextpiece[FILE_PIECE_SIZE];
|
||||
uint16_t piecelen;
|
||||
uint8_t pathname[MAX_STR_SIZE];
|
||||
uint64_t timestamp;
|
||||
uint64_t size;
|
||||
uint32_t line_id;
|
||||
} FileSender;
|
||||
|
||||
struct FileReceiver {
|
||||
uint8_t filenames[MAX_FILES][MAX_STR_SIZE];
|
||||
FILE *files[MAX_FILES];
|
||||
bool pending[MAX_FILES];
|
||||
uint64_t size[MAX_FILES];
|
||||
uint32_t line_id;
|
||||
};
|
||||
|
||||
/* End file transfer code */
|
||||
@ -238,22 +226,22 @@ struct _Winthread {
|
||||
pthread_mutex_t lock;
|
||||
};
|
||||
|
||||
void on_request(uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata);
|
||||
void on_connectionchange(Tox *m, int friendnumber, uint8_t status, void *userdata);
|
||||
void on_message(Tox *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata);
|
||||
void on_action(Tox *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata);
|
||||
void on_nickchange(Tox *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata);
|
||||
void on_statuschange(Tox *m, int friendnumber, TOX_USERSTATUS status, void *userdata);
|
||||
void on_statusmessagechange(Tox *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata);
|
||||
void on_friendadded(Tox *m, int friendnumber, bool sort);
|
||||
void on_request(Tox *m, uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata);
|
||||
void on_connectionchange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata);
|
||||
void on_message(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata);
|
||||
void on_action(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata);
|
||||
void on_nickchange(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata);
|
||||
void on_statuschange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata);
|
||||
void on_statusmessagechange(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata);
|
||||
void on_friendadded(Tox *m, int32_t friendnumber, bool sort);
|
||||
void on_groupmessage(Tox *m, int groupnumber, int peernumber, uint8_t *message, uint16_t length, void *userdata);
|
||||
void on_groupaction(Tox *m, int groupnumber, int peernumber, uint8_t *action, uint16_t length, void *userdata);
|
||||
void on_groupinvite(Tox *m, int friendnumber, uint8_t *group_pub_key, void *userdata);
|
||||
void on_groupinvite(Tox *m, int32_t friendnumber, uint8_t *group_pub_key, void *userdata);
|
||||
void on_group_namelistchange(Tox *m, int groupnumber, int peernumber, uint8_t change, void *userdata);
|
||||
void on_file_sendrequest(Tox *m, 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);
|
||||
void on_file_sendrequest(Tox *m, int32_t friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *pathname, uint16_t pathname_length, void *userdata);
|
||||
void on_file_control(Tox *m, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber, uint8_t control_type, uint8_t *data, uint16_t length, void *userdata);
|
||||
void on_file_data(Tox *m, int32_t friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata);
|
||||
void on_typing_change(Tox *m, int32_t friendnumber, uint8_t is_typing, void *userdata);
|
||||
|
||||
ToxWindow *init_windows(Tox *m);
|
||||
void draw_active_window(Tox *m);
|
||||
|
@ -43,64 +43,64 @@ extern ToxWindow *prompt;
|
||||
static int num_active_windows;
|
||||
|
||||
/* CALLBACKS START */
|
||||
void on_request(uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata)
|
||||
void on_request(Tox *m, uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_active_windows; ++i) {
|
||||
|
||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i].onFriendRequest != NULL)
|
||||
windows[i].onFriendRequest(&windows[i], public_key, data, length);
|
||||
windows[i].onFriendRequest(&windows[i], m, public_key, data, length);
|
||||
}
|
||||
}
|
||||
|
||||
void on_connectionchange(Tox *m, int friendnumber, uint8_t status, void *userdata)
|
||||
void on_connectionchange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_active_windows; ++i) {
|
||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i].onConnectionChange != NULL)
|
||||
windows[i].onConnectionChange(&windows[i], m, friendnumber, status);
|
||||
}
|
||||
}
|
||||
|
||||
void on_typing_change(Tox *m, int friendnumber, int is_typing, void *userdata)
|
||||
void on_typing_change(Tox *m, int32_t friendnumber, uint8_t is_typing, void *userdata)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_active_windows; ++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)
|
||||
void on_message(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_active_windows; ++i) {
|
||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i].onMessage != NULL)
|
||||
windows[i].onMessage(&windows[i], m, friendnumber, string, length);
|
||||
}
|
||||
}
|
||||
|
||||
void on_action(Tox *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata)
|
||||
void on_action(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_active_windows; ++i) {
|
||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i].onAction != NULL)
|
||||
windows[i].onAction(&windows[i], m, friendnumber, string, length);
|
||||
}
|
||||
}
|
||||
|
||||
void on_nickchange(Tox *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata)
|
||||
void on_nickchange(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata)
|
||||
{
|
||||
if (friendnumber < 0 || friendnumber > MAX_FRIENDS_NUM)
|
||||
return;
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_active_windows; ++i) {
|
||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i].onNickChange != NULL)
|
||||
windows[i].onNickChange(&windows[i], m, friendnumber, string, length);
|
||||
}
|
||||
@ -109,31 +109,31 @@ void on_nickchange(Tox *m, int friendnumber, uint8_t *string, uint16_t length, v
|
||||
wprintw(prompt->window, "\nCould not store Tox data\n");
|
||||
}
|
||||
|
||||
void on_statusmessagechange(Tox *m, int friendnumber, uint8_t *string, uint16_t length, void *userdata)
|
||||
void on_statusmessagechange(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_active_windows; ++i) {
|
||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i].onStatusMessageChange != NULL)
|
||||
windows[i].onStatusMessageChange(&windows[i], friendnumber, string, length);
|
||||
}
|
||||
}
|
||||
|
||||
void on_statuschange(Tox *m, int friendnumber, TOX_USERSTATUS status, void *userdata)
|
||||
void on_statuschange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_active_windows; ++i) {
|
||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i].onStatusChange != NULL)
|
||||
windows[i].onStatusChange(&windows[i], m, friendnumber, status);
|
||||
}
|
||||
}
|
||||
|
||||
void on_friendadded(Tox *m, int friendnumber, bool sort)
|
||||
void on_friendadded(Tox *m, int32_t friendnumber, bool sort)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_active_windows; ++i) {
|
||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i].onFriendAdded != NULL)
|
||||
windows[i].onFriendAdded(&windows[i], m, friendnumber, sort);
|
||||
}
|
||||
@ -147,7 +147,7 @@ void on_groupmessage(Tox *m, int groupnumber, int peernumber, uint8_t *message,
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_active_windows; ++i) {
|
||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i].onGroupMessage != NULL)
|
||||
windows[i].onGroupMessage(&windows[i], m, groupnumber, peernumber, message, length);
|
||||
}
|
||||
@ -158,17 +158,17 @@ void on_groupaction(Tox *m, int groupnumber, int peernumber, uint8_t *action, ui
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_active_windows; ++i) {
|
||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i].onGroupAction != NULL)
|
||||
windows[i].onGroupAction(&windows[i], m, groupnumber, peernumber, action, length);
|
||||
}
|
||||
}
|
||||
|
||||
void on_groupinvite(Tox *m, int friendnumber, uint8_t *group_pub_key, void *userdata)
|
||||
void on_groupinvite(Tox *m, int32_t friendnumber, uint8_t *group_pub_key, void *userdata)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_active_windows; ++i) {
|
||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i].onGroupInvite != NULL)
|
||||
windows[i].onGroupInvite(&windows[i], m, friendnumber, group_pub_key);
|
||||
}
|
||||
@ -178,42 +178,42 @@ void on_group_namelistchange(Tox *m, int groupnumber, int peernumber, uint8_t ch
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_active_windows; ++i) {
|
||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i].onGroupNamelistChange != NULL)
|
||||
windows[i].onGroupNamelistChange(&windows[i], m, groupnumber, peernumber, change);
|
||||
}
|
||||
}
|
||||
|
||||
void on_file_sendrequest(Tox *m, int friendnumber, uint8_t filenumber, uint64_t filesize,
|
||||
void on_file_sendrequest(Tox *m, int32_t friendnumber, uint8_t filenumber, uint64_t filesize,
|
||||
uint8_t *filename, uint16_t filename_length, void *userdata)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_active_windows; ++i) {
|
||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i].onFileSendRequest != NULL)
|
||||
windows[i].onFileSendRequest(&windows[i], m, friendnumber, filenumber, filesize,
|
||||
filename, filename_length);
|
||||
}
|
||||
}
|
||||
|
||||
void on_file_control (Tox *m, int friendnumber, uint8_t receive_send, uint8_t filenumber,
|
||||
void on_file_control (Tox *m, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber,
|
||||
uint8_t control_type, uint8_t *data, uint16_t length, void *userdata)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_active_windows; ++i) {
|
||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i].onFileControl != NULL)
|
||||
windows[i].onFileControl(&windows[i], m, friendnumber, receive_send, filenumber,
|
||||
control_type, data, length);
|
||||
}
|
||||
}
|
||||
|
||||
void on_file_data(Tox *m, int friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length,
|
||||
void on_file_data(Tox *m, int32_t friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length,
|
||||
void *userdata)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_active_windows; ++i) {
|
||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i].onFileData != NULL)
|
||||
windows[i].onFileData(&windows[i], m, friendnumber, filenumber, data, length);
|
||||
}
|
||||
@ -241,7 +241,9 @@ int add_window(Tox *m, ToxWindow w)
|
||||
wbkgd(w.window, COLOR_PAIR(6));
|
||||
#endif
|
||||
windows[i] = w;
|
||||
w.onInit(&w, m);
|
||||
|
||||
if (w.onInit)
|
||||
w.onInit(&w, m);
|
||||
|
||||
++num_active_windows;
|
||||
|
||||
@ -392,18 +394,32 @@ void draw_active_window(Tox *m)
|
||||
wrefresh(a->window);
|
||||
|
||||
/* Handle input */
|
||||
bool ltr;
|
||||
#ifdef HAVE_WIDECHAR
|
||||
if (wget_wch(stdscr, &ch) == ERR)
|
||||
#else
|
||||
if ((ch = getch()) == ERR)
|
||||
#endif
|
||||
int status = wget_wch(stdscr, &ch);
|
||||
|
||||
if (status == ERR)
|
||||
return;
|
||||
|
||||
if (ch == T_KEY_NEXT || ch == T_KEY_PREV) {
|
||||
if (status == OK)
|
||||
ltr = iswprint(ch);
|
||||
else /* if (status == KEY_CODE_YES) */
|
||||
ltr = false;
|
||||
#else
|
||||
ch = getch();
|
||||
|
||||
if (ch == ERR)
|
||||
return;
|
||||
|
||||
/* TODO verify if this works */
|
||||
ltr = isprint(ch);
|
||||
#endif
|
||||
|
||||
if (!ltr && (ch == T_KEY_NEXT || ch == T_KEY_PREV) ) {
|
||||
set_next_window((int) ch);
|
||||
} else {
|
||||
pthread_mutex_lock(&Winthread.lock);
|
||||
a->onKey(a, m, ch);
|
||||
a->onKey(a, m, ch, ltr);
|
||||
pthread_mutex_unlock(&Winthread.lock);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user