1
0
mirror of https://github.com/Tha14/toxic.git synced 2024-06-26 20:37:46 +02:00

Added VAD, changed device i/o, mute option, dynamic device changing and more

This commit is contained in:
mannol 2014-06-22 02:18:23 +02:00
parent e06f0ffb7e
commit e47f2c05f3
40 changed files with 1828 additions and 1007 deletions

View File

@ -3,7 +3,8 @@
bin_PROGRAMS = toxic
toxic_SOURCES = $(top_srcdir)/src/main.c \
toxic_SOURCES = $(top_srcdir)/src/toxic.c \
$(top_srcdir)/src/toxic.h \
$(top_srcdir)/src/chat.h \
$(top_srcdir)/src/chat.c \
$(top_srcdir)/src/configdir.h \
@ -12,8 +13,8 @@ toxic_SOURCES = $(top_srcdir)/src/main.c \
$(top_srcdir)/src/prompt.c \
$(top_srcdir)/src/friendlist.h \
$(top_srcdir)/src/friendlist.c \
$(top_srcdir)/src/toxic_windows.h \
$(top_srcdir)/src/windows.c \
$(top_srcdir)/src/windows.h \
$(top_srcdir)/src/groupchat.c \
$(top_srcdir)/src/groupchat.h \
$(top_srcdir)/src/global_commands.c \
@ -33,13 +34,15 @@ toxic_SOURCES = $(top_srcdir)/src/main.c \
$(top_srcdir)/src/line_info.c \
$(top_srcdir)/src/line_info.h \
$(top_srcdir)/src/settings.c \
$(top_srcdir)/src/settings.h
$(top_srcdir)/src/settings.h \
$(top_srcdir)/src/dns.c \
$(top_srcdir)/src/dns.h
toxic_CFLAGS = -I$(top_srcdir) \
$(NCURSES_CFLAGS) \
$(LIBSODIUM_CFLAGS) \
$(LIBTOXCORE_CFLAGS) \
$(PTHREAD_CFLAGS)
toxic_CFLAGS = -I$(top_srcdir) \
$(NCURSES_CFLAGS) \
$(LIBSODIUM_CFLAGS) \
$(LIBTOXCORE_CFLAGS) \
$(PTHREAD_CFLAGS)
toxic_CPPFLAGS = '-DTOXICVER="$(TOXIC_VERSION)"'
@ -58,7 +61,7 @@ if BUILD_AV
toxic_SOURCES += $(top_srcdir)/src/audio_call.c \
$(top_srcdir)/src/audio_call.h \
$(top_srcdir)/src/device.c \
$(top_srcdir)/src/device.h
$(top_srcdir)/src/device.h
toxic_CFLAGS += $(LIBTOXAV_CFLAGS) \
$(OPENAL_CFLAGS)

View File

@ -2,9 +2,9 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.65])
AC_INIT([toxic], [0.3.3], [https://tox.im/])
AC_INIT([toxic], [0.4.2], [https://tox.im/])
AC_CONFIG_AUX_DIR(configure_aux)
AC_CONFIG_SRCDIR([src/main.c])
AC_CONFIG_SRCDIR([src/toxic.c])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([1.10 -Wall])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
@ -37,7 +37,9 @@ if test -n "$DEPSEARCH"; then
CFLAGS="$CFLAGS -I$DEPSEARCH/include"
CPPFLAGS="$CPPFLAGS -I$DEPSEARCH/include"
LDFLAGS="$LDFLAGS -L$DEPSEARCH/lib"
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$DEPSEARCH/lib/pkgconfig
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$DEPSEARCH/lib/pkgconfig:/usr/local/lib/pkgconfig
else
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig
fi
AC_ARG_WITH(libtoxcore-headers,
@ -77,11 +79,15 @@ AC_ARG_WITH(libsodium-libs,
)
WIN32=no
MACH=no
AC_CANONICAL_HOST
case $host_os in
*mingw*)
WIN32="yes"
;;
darwin*)
MACH=yes
;;
*freebsd*)
LDFLAGS="$LDFLAGS -L/usr/local/lib"
CFLAGS="$CFLAGS -I/usr/local/include"
@ -383,6 +389,15 @@ if test "x$LIBTOXCORE_FOUND" = "xno"; then
AC_SUBST(LIBTOXCORE_LDFLAGS)
fi
AC_CHECK_HEADER([resolv.h], [],
[
AC_MSG_ERROR([resolv.h header was not found on your system])
])
AC_CHECK_LIB(resolv, __res_init, [],
[
AC_MSG_ERROR([libresolv library was not found on your system])
])
####
#### A/V Stuff
@ -404,6 +419,8 @@ if test -n "$AV_SEARCH_DIR"; then
CPPFLAGS="$CPPFLAGS -I$AV_SEARCH_DIR/include"
LDFLAGS="$LDFLAGS -L$AV_SEARCH_DIR/lib"
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$AV_SEARCH_DIR/lib/pkgconfig
else
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig"
fi
# Check if specified enable
@ -422,29 +439,46 @@ AC_ARG_ENABLE([av],
if test "x$BUILD_AV" = "xyes"; then
PKG_CHECK_MODULES([OPENAL], [openal],
[
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig
PKG_CHECK_MODULES([LIBTOXAV], [libtoxav],
[
AC_CHECK_HEADER([tox/toxav.h],
[
# Place define for audio support
AC_DEFINE([_SUPPORT_AUDIO], [], [Is audio supported])
AC_MSG_NOTICE([Building with audio support])
],
[
AC_MSG_NOTICE([No A/V headers; disabling A/V support])
BUILD_AV="no"
],)
],
[
AC_MSG_NOTICE([No A/V library; disabling A/V support])
[],
[
if test "x$MACH" = "xyes"; then
CFLAGS="$CFLAGS -framework OpenAL"
AC_CHECK_HEADER([OpenAL/al.h],
[
OPENAL_CFLAGS="-framework OpenAL"
OPENAL_LIBS="-framework OpenAL"
AC_SUBST(OPENAL_CFLAGS)
AC_SUBST(OPENAL_LIBS)
],
[
AC_MSG_NOTICE([No openal framework; disabling A/V support])
BUILD_AV="no"
]
)
CFLAGS="$CFLAGS_SAVE"
else
AC_MSG_NOTICE([No openal library; disabling A/V support])
BUILD_AV="no"
])
fi
])
fi
if test "x$BUILD_AV" = "xyes"; then
PKG_CHECK_MODULES([LIBTOXAV], [libtoxav],
[
AC_CHECK_HEADER([tox/toxav.h],
[
# Place define for audio support
AC_DEFINE([_SUPPORT_AUDIO], [], [Is audio supported])
AC_MSG_NOTICE([Building with audio support])
],
[
AC_MSG_NOTICE([No A/V headers; disabling A/V support])
BUILD_AV="no"
],)
],
[
AC_MSG_NOTICE([No openal library; disabling A/V support])
AC_MSG_NOTICE([No A/V library; disabling A/V support])
BUILD_AV="no"
])
fi
@ -469,7 +503,7 @@ if test "x$NCURSES_WIDECHAR_SUPPORT" = "xyes"; then
AC_DEFINE([_XOPEN_SOURCE_EXTENDED], [1],
[enable X/Open Portability Guide functionality])
fi
AC_CONFIG_FILES([Makefile
misc/Makefile
build/Makefile])

View File

@ -1,22 +1,38 @@
/*
* Toxic -- Tox Curses Client
/* audio_call.c
*
*
* Copyright (C) 2014 Toxic All Rights Reserved.
*
* This file is part of Toxic.
*
* Toxic is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Toxic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "audio_call.h"
#include "device.h"
#include "chat_commands.h"
#include "global_commands.h"
#include "toxic_windows.h"
#include "line_info.h"
#include <curses.h>
#include <AL/al.h>
#include <AL/alc.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
@ -29,16 +45,6 @@
#define frame_size (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000)
typedef struct _DeviceIx {
ALCdevice *dhndl; /* Handle of device selected/opened */
ALCcontext *ctx; /* Device context */
const char *devices[MAX_DEVICES]; /* Container of available devices */
int size; /* Size of above container */
int dix; /* Index of default device */
int index; /* Current index */
} DeviceIx;
typedef struct _Call {
pthread_t ttid; /* Transmission thread id */
_Bool ttas; /* Transmission thread active status (0 - stopped, 1- running) */
@ -178,7 +184,7 @@ void *transmission(void *arg)
if ( open_primary_device(input, &this_call->in_idx) != de_None ) goto cleanup;
if ( register_device_callback(this_call->in_idx, read_device_callback, &call_index, _True) != de_None)
if ( register_device_callback(call_index, this_call->in_idx, read_device_callback, &call_index, _True) != de_None)
/* Set VAD as true for all; TODO: Make it more dynamic */
goto cleanup;
@ -582,7 +588,7 @@ on_error:
print_err (self, error_str);
}
void cmd_set_this_session_device(WINDOW * window, ToxWindow * self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
void cmd_ccur_device(WINDOW * window, ToxWindow * self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
uint8_t msg[MAX_STR_SIZE];
uint8_t *error_str;
@ -638,7 +644,7 @@ void cmd_set_this_session_device(WINDOW * window, ToxWindow * self, Tox *m, int
close_device(input, this_call->in_idx);
open_device(input, selection, &this_call->in_idx);
/* Set VAD as true for all; TODO: Make it more dynamic */
register_device_callback(this_call->in_idx, read_device_callback, &self->call_idx, _True);
register_device_callback(self->call_idx, this_call->in_idx, read_device_callback, &self->call_idx, _True);
}
}
}
@ -646,6 +652,77 @@ void cmd_set_this_session_device(WINDOW * window, ToxWindow * self, Tox *m, int
self->device_selection[type] = selection;
return;
on_error:
print_err (self, error_str);
}
void cmd_mute(WINDOW * window, ToxWindow * self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
uint8_t msg[MAX_STR_SIZE];
uint8_t *error_str;
if ( argc != 1 ) {
if ( argc < 1 ) error_str = "Type must be specified!";
else error_str = "Only two arguments allowed!";
goto on_error;
}
DeviceType type;
if ( strcmp(argv[1], "in") == 0 ) /* Input devices */
type = input;
else if ( strcmp(argv[1], "out") == 0 ) /* Output devices */
type = output;
else {
snprintf(msg, sizeof(msg), "Invalid type: %s", argv[1]);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
return;
}
/* If call is active, use this_call values */
if ( self->call_idx > -1) {
Call* this_call = &ASettins.calls[self->call_idx];
pthread_mutex_lock(&this_call->mutex);
device_mute(type, type == input ? this_call->in_idx : this_call->out_idx);
pthread_mutex_unlock(&this_call->mutex);
}
return;
on_error:
print_err (self, error_str);
}
void cmd_sense(WINDOW * window, ToxWindow * self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
uint8_t msg[MAX_STR_SIZE];
uint8_t *error_str;
if ( argc != 1 ) {
if ( argc < 1 ) error_str = "Must have value!";
else error_str = "Only two arguments allowed!";
goto on_error;
}
char *end;
float value = strtof(argv[1], &end);
if ( *end ) {
error_str = "Invalid input";
goto on_error;
}
/* Call must be active */
if ( self->call_idx > -1) device_set_VAD_treshold(ASettins.calls[self->call_idx].in_idx, value);
return;
on_error:
print_err (self, error_str);
}

View File

@ -1,5 +1,23 @@
/*
* Toxic -- Tox Curses Client
/* audio_call.h
*
*
* Copyright (C) 2014 Toxic All Rights Reserved.
*
* This file is part of Toxic.
*
* Toxic is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Toxic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef _audio_h
@ -23,8 +41,6 @@ typedef enum _AudioError {
ToxAv *init_audio(ToxWindow *self, Tox *tox);
void terminate_audio();
int clear_call_settings_per_se(ToxWindow *self);
int start_transmission(ToxWindow *self);
int stop_transmission(int call_index);
int device_set(ToxWindow* self, DeviceType type, long int selection);

View File

@ -28,7 +28,8 @@
#include <string.h>
#include <time.h>
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "execute.h"
#include "misc_tools.h"
#include "friendlist.h"
@ -51,7 +52,7 @@ extern struct _Winthread Winthread;
extern struct user_settings *user_settings;
#ifdef _SUPPORT_AUDIO
#define AC_NUM_CHAT_COMMANDS 24
#define AC_NUM_CHAT_COMMANDS 26
#else
#define AC_NUM_CHAT_COMMANDS 18
#endif /* _SUPPORT_AUDIO */
@ -85,6 +86,8 @@ static const uint8_t chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/reject" },
{ "/hangup" },
{ "/sdev" },
{ "/mute" },
{ "/sense" },
#endif /* _SUPPORT_AUDIO */
};
@ -215,8 +218,11 @@ static void chat_onStatusMessageChange(ToxWindow *self, int32_t num, uint8_t *st
return;
StatusBar *statusbar = self->stb;
status[len] = '\0';
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", status);
len = strlen(statusbar->statusmsg);
statusbar->statusmsg_len = len;
strcpy(statusbar->statusmsg, status);
statusbar->statusmsg[len] = '\0';
}
@ -226,15 +232,21 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t
if (self->num != num)
return;
uint8_t msg[MAX_STR_SIZE];
uint8_t msg[MAX_STR_SIZE * 2];
uint8_t *errmsg;
pathname[path_len] = '\0';
uint8_t filename[MAX_STR_SIZE];
get_file_name(pathname, filename);
snprintf(msg, sizeof(msg), "File transfer request for '%s' (%llu bytes).", filename,
/* holds the filename appended to the user specified path */
uint8_t filename_path[MAX_STR_SIZE] = {0};
/* holds the lone filename */
uint8_t filename_nopath[MAX_STR_SIZE];
get_file_name(filename_nopath, pathname);
int len = strlen(filename_nopath);
snprintf(msg, sizeof(msg), "File transfer request for '%s' (%llu bytes).", filename_nopath,
(long long unsigned int)filesize);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
@ -244,17 +256,42 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t
return;
}
/* use specified path in config if possible */
if (user_settings->download_path[0]) {
snprintf(filename_path, sizeof(filename_path), "%s%s", user_settings->download_path, filename_nopath);
len += strlen(user_settings->download_path);
}
if (len >= sizeof(friends[num].file_receiver.filenames[filenum])) {
errmsg = "File name too long; discarding.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
return;
}
uint8_t filename[MAX_STR_SIZE];
if (filename_path[0])
strcpy(filename, filename_path);
else
strcpy(filename, filename_nopath);
/* Append a number to duplicate file names */
FILE *filecheck = NULL;
int count = 1;
int len = strlen(filename);
while ((filecheck = fopen(filename, "r"))) {
filename[len] = '\0';
char d[9];
sprintf(d, "(%d)", count++);
int d_len = strlen(d);
if (len + d_len >= sizeof(filename)) {
len -= d_len;
filename[len] = '\0';
}
strcat(filename, d);
filename[len + strlen(d)] = '\0';
filename[len + d_len] = '\0';
if (count > 999) {
errmsg = "Error saving file to disk.";
@ -291,21 +328,28 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, int32_t num, uint8_t rec
const uint8_t *filename;
uint8_t msg[MAX_STR_SIZE] = {0};
int i; /* file_sender index */
if (receive_send == 0)
if (receive_send == 0) {
filename = friends[num].file_receiver.filenames[filenum];
else
filename = file_senders[filenum].pathname;
} else {
for (i = 0; i < MAX_FILES; ++i) {
if (file_senders[i].filenum == filenum)
break;
}
filename = file_senders[i].pathname;
}
switch (control_type) {
case TOX_FILECONTROL_ACCEPT:
snprintf(msg, sizeof(msg), "File transfer for '%s' accepted (%.1f%%)", filename, 0.0);
file_senders[filenum].line_id = self->chatwin->hst->line_end->id + 1;
if (receive_send == 1) {
snprintf(msg, sizeof(msg), "File transfer for '%s' accepted (%.1f%%)", filename, 0.0);
file_senders[i].line_id = self->chatwin->hst->line_end->id + 1;
}
break;
/*case TOX_FILECONTROL_PAUSE:
wprintw(ctx->history, "File transfer for '%s' paused.\n", filename);
break; */
case TOX_FILECONTROL_KILL:
snprintf(msg, sizeof(msg), "File transfer for '%s' failed.", filename);
@ -315,8 +359,11 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, int32_t num, uint8_t rec
break;
case TOX_FILECONTROL_FINISHED:
snprintf(msg, sizeof(msg), "File transfer for '%s' complete.", filename);
chat_close_file_receiver(num, filenum);
if (receive_send == 0) {
snprintf(msg, sizeof(msg), "File transfer for '%s' complete.", filename);
chat_close_file_receiver(num, filenum);
}
break;
}
@ -349,7 +396,7 @@ static void chat_onFileData(ToxWindow *self, Tox *m, int32_t num, uint8_t filenu
const uint8_t *name = friends[num].file_receiver.filenames[filenum];
snprintf(msg, sizeof(msg), "Saving file as: '%s' (%.1Lf%%)", name, pct_remain);
line_info_set(self, friends[num].file_receiver.line_id, msg);
line_info_set(self, friends[num].file_receiver.line_id[filenum], msg);
}
@ -365,8 +412,9 @@ static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, ui
n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH - 1);
name[n_len] = '\0';
snprintf(msg, sizeof(msg), "%s has invited you to a group chat.\n"
"Type \"/join\" to join the chat.", name);
snprintf(msg, sizeof(msg), "%s has invited you to a group chat.", name);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
snprintf(msg, sizeof(msg), "Type \"/join\" to join the chat.", name);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
memcpy(friends[friendnumber].pending_groupchat, group_pub_key, TOX_CLIENT_ID_SIZE);
@ -509,44 +557,44 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
int x, y, y2, x2;
getyx(self->window, y, x);
getmaxyx(self->window, y2, x2);
int cur_len = 0;
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);
}
/* If we're in scroll mode ignore rest of function */
if (ctx->hst->scroll_mode) {
line_info_onKey(self, key);
if (x2 <= 0)
return;
}
if (ltr) {
/* prevents buffer overflows and strange behaviour when cursor goes past the window */
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);
int cur_len = 0; /* widechar size of current char */
int x2_is_odd = x2 % 2 != 0;
if (x == x2 - 1)
wmove(self->window, y + 1, 0);
else
if (ltr) { /* char is printable */
if (ctx->len < MAX_STR_SIZE - 1) {
add_char_to_buf(ctx, key);
if (x >= x2 - 1) {
wmove(self->window, y, x2 / 2 + x2_is_odd);
ctx->start += x2 / 2;
} else {
wmove(self->window, y, x + MAX(1, wcwidth(key)));
}
}
if (!ctx->self_is_typing && ctx->line[0] != '/')
set_typingstatus(self, m, 1);
} else { /* if (!ltr) */
if (line_info_onKey(self, key))
return;
if (key == 0x107 || key == 0x8 || key == 0x7f) { /* BACKSPACE key */
if (ctx->pos > 0) {
cur_len = MAX(1, wcwidth(ctx->line[ctx->pos - 1]));
del_char_buf_bck(ctx->line, &ctx->pos, &ctx->len);
cur_len = MAX(1, wcwidth(ctx->line[ctx->pos]));
del_char_buf_bck(ctx);
if (x == 0)
wmove(self->window, y - 1, x2 - cur_len);
else
if (x == 0) {
ctx->start = ctx->start >= x2 ? ctx->start - x2 : 0;
int new_x = ctx->start == 0 ? ctx->pos : x2 - cur_len;
wmove(self->window, y, new_x);
} else {
wmove(self->window, y, x - cur_len);
}
} else {
beep();
}
@ -554,14 +602,14 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
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);
del_char_buf_frnt(ctx);
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);
discard_buf(ctx);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
} else {
beep();
@ -570,7 +618,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
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);
kill_buf(ctx);
else
beep();
}
@ -578,6 +626,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
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;
ctx->start = 0;
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
}
}
@ -585,7 +634,8 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
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);
ctx->start = x2 * (ctx->len / x2);
mv_curs_end(self->window, ctx->len, y2, x2);
}
}
@ -594,10 +644,13 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
--ctx->pos;
cur_len = MAX(1, wcwidth(ctx->line[ctx->pos]));
if (x == 0)
wmove(self->window, y - 1, x2 - cur_len);
else
if (x == 0) {
wmove(self->window, y, x2 - cur_len);
ctx->start = ctx->start >= x2 ? ctx->start - x2 : 0;
ctx->pos = ctx->start + x2 - 1;
} else {
wmove(self->window, y, x - cur_len);
}
} else {
beep();
}
@ -605,39 +658,42 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
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
if (x == x2 - 1) {
wmove(self->window, y, 0);
ctx->start += x2;
ctx->pos = ctx->start;
} else {
cur_len = MAX(1, wcwidth(ctx->line[ctx->pos]));
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);
fetch_hist_item(ctx, MOVE_UP);
ctx->start = x2 * (ctx->len / x2);
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);
fetch_hist_item(ctx, MOVE_DOWN);
ctx->start = x2 * (ctx->len / x2);
mv_curs_end(self->window, ctx->len, y2, x2);
}
else if (key == '\t') { /* TAB key: completes command */
if (ctx->len > 1 && ctx->line[0] == '/') {
int diff = complete_line(ctx->line, &ctx->pos, &ctx->len, chat_cmd_list, AC_NUM_CHAT_COMMANDS,
MAX_CMDNAME_SIZE);
int diff = complete_line(ctx, chat_cmd_list, AC_NUM_CHAT_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);
//int ofst = x + diff - x2;
wmove(self->window, y, x + diff);
ctx->start += x2 / 2;
} else {
wmove(self->window, y, x + diff);
}
@ -651,6 +707,8 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
/* RETURN key: Execute command or print line */
else if (key == '\n') {
rm_trailing_spaces_buf(ctx);
uint8_t line[MAX_STR_SIZE];
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
@ -660,7 +718,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
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);
add_line_to_hist(ctx);
if (line[0] == '/') {
if (strcmp(line, "/close") == 0) {
@ -692,7 +750,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
}
}
reset_buf(ctx->line, &ctx->pos, &ctx->len);
reset_buf(ctx);
}
}
@ -710,21 +768,16 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
line_info_print(self);
wclear(ctx->linewin);
if (ctx->hst->scroll_mode) {
line_info_onDraw(self);
} else {
curs_set(1);
scrollok(ctx->history, 1);
curs_set(1);
if (ctx->len > 0 && !ctx->hst->scroll_mode) {
uint8_t line[MAX_STR_SIZE];
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);
}
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
reset_buf(ctx);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
} else {
mvwprintw(ctx->linewin, 1, 0, "%s", &line[ctx->start]);
}
}
@ -845,17 +898,13 @@ static void chat_onInit(ToxWindow *self, Tox *m)
statusbar->topline = subwin(self->window, 2, x2, 0, 0);
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
scrollok(ctx->history, 1);
ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
ctx->hst = malloc(sizeof(struct history));
ctx->log = malloc(sizeof(struct chatlog));
if (ctx->log == NULL || ctx->hst == NULL) {
endwin();
fprintf(stderr, "malloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
if (ctx->log == NULL || ctx->hst == NULL)
exit_toxic_err("failed in chat_onInit", FATALERR_MEMORY);
memset(ctx->hst, 0, sizeof(struct history));
memset(ctx->log, 0, sizeof(struct chatlog));
@ -868,6 +917,7 @@ static void chat_onInit(ToxWindow *self, Tox *m)
execute(ctx->history, self, m, "/help", CHAT_COMMAND_MODE);
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
scrollok(ctx->history, 0);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
}
@ -929,9 +979,7 @@ ToxWindow new_chat(Tox *m, int32_t friendnum)
ret.chatwin = chatwin;
ret.stb = stb;
} else {
endwin();
fprintf(stderr, "calloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
exit_toxic_err("failed in new_chat", FATALERR_MEMORY);
}
ret.num = friendnum;

View File

@ -23,7 +23,8 @@
#ifndef CHAT_H_6489PZ13
#define CHAT_H_6489PZ13
#include "toxic_windows.h"
#include "windows.h"
#include "toxic.h"
void kill_chat_window(ToxWindow *self);
ToxWindow new_chat(Tox *m, int32_t friendnum);

View File

@ -27,7 +27,8 @@
#include <stdlib.h>
#include <string.h>
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "misc_tools.h"
#include "friendlist.h"
#include "execute.h"
@ -57,7 +58,7 @@ void cmd_chat_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
#ifdef _SUPPORT_AUDIO
#define NUMLINES 13
#define NUMLINES 16
#else
#define NUMLINES 9
#endif
@ -70,6 +71,9 @@ void cmd_chat_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
{ " /answer : Answer incomming call" },
{ " /reject : Reject incoming call" },
{ " /hangup : Hangup active call" },
{ " /sdev <type> <id> : Change active device" },
{ " /mute <type> : Mute active device if in call" },
{ " /sense <value> : VAD sensitivity treshold" },
#endif /* _SUPPORT_AUDIO */
{ " /invite <n> : Invite friend to a group chat" },
{ " /join : Join a pending group chat" },
@ -86,7 +90,7 @@ void cmd_chat_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
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";
msg = " * Use Page Up/Page Down to scroll chat history\n";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
hst->line_start = start;
@ -185,7 +189,7 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
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;
friends[self->num].file_receiver.line_id[filenum] = self->chatwin->hst->line_end->id + 1;
if ((friends[self->num].file_receiver.files[filenum] = fopen(filename, "a")) == NULL) {
errmsg = "* Error writing to file.";
@ -246,7 +250,7 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
fseek(file_to_send, 0, SEEK_SET);
uint8_t filename[MAX_STR_SIZE];
get_file_name(path, filename);
get_file_name(filename, path);
int filenum = tox_new_file_sender(m, self->num, filesize, filename, strlen(filename));
if (filenum == -1) {

View File

@ -20,6 +20,12 @@
*
*/
#ifndef _chat_commands_h
#define _chat_commands_h
#include "windows.h"
#include "toxic.h"
void cmd_chat_help(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_groupinvite(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_join_group(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
@ -33,5 +39,9 @@ void cmd_answer(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZ
void cmd_reject(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_hangup(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_cancel(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_set_this_session_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_ccur_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_mute(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_sense(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
#endif /* _SUPPORT_AUDIO */
#endif /* #define _chat_commands_h */

View File

@ -30,14 +30,8 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#ifdef _WIN32
#include <shlobj.h>
#include <direct.h>
#else /* WIN32 */
#include <unistd.h>
#include <pwd.h>
#endif /* WIN32 */
#include "configdir.h"
@ -51,25 +45,6 @@
char *get_user_config_dir(void)
{
char *user_config_dir;
#ifdef _WIN32
#warning Please fix configdir for Win32
return NULL;
#if 0
char appdata[MAX_PATH];
BOOL ok;
ok = SHGetSpecialFolderPathA(NULL, appdata, CSIDL_PROFILE, TRUE);
if (!ok) {
return NULL;
}
user_config_dir = strdup(appdata);
return user_config_dir;
#endif
#else /* WIN32 */
#ifndef NSS_BUFLEN_PASSWD
#define NSS_BUFLEN_PASSWD 4096
@ -128,7 +103,6 @@ char *get_user_config_dir(void)
return user_config_dir;
#undef NSS_BUFLEN_PASSWD
#endif /* WIN32 */
}
/*
@ -136,26 +110,6 @@ char *get_user_config_dir(void)
*/
int create_user_config_dir(char *path)
{
#ifdef _WIN32
#warning Please fix configdir for Win32
return -1;
#if 0
char *fullpath = malloc(strlen(path) + strlen(CONFIGDIR) + 1);
strcpy(fullpath, path);
strcat(fullpath, CONFIGDIR);
mkdir_err = _mkdir(fullpath);
struct __stat64 buf;
if (mkdir_err && (errno != EEXIST || _wstat64(fullpath, &buf) || !S_ISDIR(buf.st_mode))) {
free(fullpath);
return -1;
}
free(fullpath);
#endif
#else
int mkdir_err;
mkdir_err = mkdir(path, 0700);
@ -178,5 +132,4 @@ int create_user_config_dir(char *path)
free(fullpath);
return 0;
#endif
}

View File

@ -20,11 +20,10 @@
*
*/
#ifdef _win32
#define CONFIGDIR "\\tox\\"
#else
#ifndef _configdir_h
#define _configdir_h
#define CONFIGDIR "/tox/"
#endif
#ifndef S_ISDIR
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
@ -33,3 +32,5 @@
char *get_user_config_dir(void);
int create_user_config_dir(char *path);
#endif /* #define _configdir_h */

View File

@ -1,9 +1,15 @@
#include "toxic_windows.h"
#include "audio_call.h"
#include "line_info.h"
#ifdef __APPLE__
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#else
#include <AL/al.h>
#include <AL/alc.h>
#endif
#include <string.h>
#include <pthread.h>
#include <unistd.h>
@ -22,11 +28,14 @@ typedef struct _Device {
ALCcontext *ctx; /* Device context */
DataHandleCallback cb; /* Use this to handle data from input device usually */
void* cb_data; /* Data to be passed to callback */
int32_t call_idx; /* ToxAv call index */
uint32_t source, buffers[openal_bufs]; /* Playback source/buffers */
size_t ref_count;
int32_t selection;
_Bool enable_VAD;
_Bool muted;
float VAD_treshold; /* 40 is usually recommended value */
} Device;
const char *ddevice_names[2]; /* Default device */
@ -100,6 +109,42 @@ DeviceError terminate_devices()
return ae_None;
}
DeviceError device_mute(DeviceType type, uint32_t device_idx)
{
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
lock;
Device* device = running[type][device_idx];
if (!device) {
unlock;
return de_DeviceNotActive;
}
device->muted = !device->muted;
unlock;
return de_None;
}
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
{
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
lock;
Device* device = running[input][device_idx];
if (!device) {
unlock;
return de_DeviceNotActive;
}
device->VAD_treshold = value;
unlock;
return de_None;
}
DeviceError set_primary_device(DeviceType type, int32_t selection)
{
if (size[type] <= selection || selection < 0) return de_InvalidSelection;
@ -147,6 +192,7 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
if (type == input) {
device->dhndl = alcCaptureOpenDevice(devices_names[type][selection],
av_DefaultSettings.audio_sample_rate, AL_FORMAT_MONO16, frame_size * 4);
device->VAD_treshold = 40.0;
}
else {
device->dhndl = alcOpenDevice(devices_names[type][selection]);
@ -230,7 +276,7 @@ DeviceError close_device(DeviceType type, uint32_t device_idx)
return de_None;
}
DeviceError register_device_callback(uint32_t device_idx, DataHandleCallback callback, void* data, _Bool enable_VAD)
DeviceError register_device_callback( int32_t call_idx, uint32_t device_idx, DataHandleCallback callback, void* data, _Bool enable_VAD)
{
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
return de_InvalidSelection;
@ -239,6 +285,7 @@ DeviceError register_device_callback(uint32_t device_idx, DataHandleCallback cal
running[input][device_idx]->cb = callback;
running[input][device_idx]->cb_data = data;
running[input][device_idx]->enable_VAD = enable_VAD;
running[input][device_idx]->call_idx = call_idx;
unlock;
return de_None;
@ -265,7 +312,7 @@ inline__ DeviceError write_out(uint32_t device_idx, int16_t* data, uint32_t leng
Device* device = running[output][device_idx];
if (!device) return de_DeviceNotActive;
if (!device || device->muted) return de_DeviceNotActive;
alcMakeContextCurrent(device->ctx); /* TODO: Check for error */
@ -319,27 +366,27 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
{
lock;
if (running[input][i] != NULL)
// do
{
alcGetIntegerv(running[input][i]->dhndl, ALC_CAPTURE_SAMPLES, sizeof(int32_t), &sample);
if (sample < f_size) {
unlock;
continue;
}
Device* device = running[input][i];
int16_t frame[4096];
alcCaptureSamples(running[input][i]->dhndl, frame, f_size);
alcCaptureSamples(device->dhndl, frame, f_size);
if ( running[input][i]->enable_VAD && !toxav_has_activity(frame, f_size, 88.5)) { unlock; continue; } /* Skip if no voice activity */
if ( running[input][i]->cb ) running[input][i]->cb(frame, f_size, running[input][i]->cb_data);
if ( device->muted ||
(device->enable_VAD && !toxav_has_activity(av, device->call_idx, frame, f_size, device->VAD_treshold)))
{ unlock; continue; } /* Skip if no voice activity */
if ( device->cb ) device->cb(frame, f_size, device->cb_data);
}
unlock;
// while (_True);
}
// usleep(10);
usleep(5000);
}
}

View File

@ -14,7 +14,7 @@
#define MAX_DEVICES 32
#include <inttypes.h>
#include "toxic_windows.h"
#include "windows.h"
#define _True 1
#define _False 0
@ -43,9 +43,14 @@ DeviceError init_devices(ToxAv* av);
DeviceError terminate_devices();
/* Callback handles ready data from INPUT device */
DeviceError register_device_callback(uint32_t device_idx, DataHandleCallback callback, void* data, _Bool enable_VAD);
DeviceError register_device_callback(int32_t call_idx, uint32_t device_idx, DataHandleCallback callback, void* data, _Bool enable_VAD);
void* get_device_callback_data(uint32_t device_idx);
/* toggle device mute */
DeviceError device_mute(DeviceType type, uint32_t device_idx);
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value);
DeviceError set_primary_device(DeviceType type, int32_t selection);
DeviceError open_primary_device(DeviceType type, uint32_t* device_idx);
/* Start device */

305
src/dns.c Normal file
View File

@ -0,0 +1,305 @@
/* dns.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 <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <tox/toxdns.h>
#include "toxic.h"
#include "windows.h"
#include "line_info.h"
#include "dns.h"
#include "global_commands.h"
#include "misc_tools.h"
#define MAX_DNS_REQST_SIZE 256
#define NUM_DNS3_SERVERS 2 /* must correspond to number of items in dns3_servers array */
#define TOX_DNS3_TXT_PREFIX "v=tox3;id="
#define DNS3_KEY_SZ 32
/* TODO: process keys from key file instead of hard-coding like a noob */
static struct dns3_server {
uint8_t *name;
uint8_t key[DNS3_KEY_SZ];
} dns3_servers[] = {
{
"utox.org",
{
0xD3, 0x15, 0x4F, 0x65, 0xD2, 0x8A, 0x5B, 0x41, 0xA0, 0x5D, 0x4A, 0xC7, 0xE4, 0xB3, 0x9C, 0x6B,
0x1C, 0x23, 0x3C, 0xC8, 0x57, 0xFB, 0x36, 0x5C, 0x56, 0xE8, 0x39, 0x27, 0x37, 0x46, 0x2A, 0x12
}
},
{
"toxme.se",
{
0x5D, 0x72, 0xC5, 0x17, 0xDF, 0x6A, 0xEC, 0x54, 0xF1, 0xE9, 0x77, 0xA6, 0xB6, 0xF2, 0x59, 0x14,
0xEA, 0x4C, 0xF7, 0x27, 0x7A, 0x85, 0x02, 0x7C, 0xD9, 0xF5, 0x19, 0x6D, 0xF1, 0x7E, 0x0B, 0x13
}
},
};
static struct _thread_data {
ToxWindow *self;
uint8_t id_bin[TOX_FRIEND_ADDRESS_SIZE];
uint8_t addr[MAX_STR_SIZE];
uint8_t msg[MAX_STR_SIZE];
uint8_t busy;
Tox *m;
} t_data;
static struct _dns_thread {
pthread_t tid;
pthread_mutex_t lock;
} dns_thread;
static int dns_error(ToxWindow *self, uint8_t *errmsg)
{
uint8_t msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "DNS lookup failed: %s", errmsg);
pthread_mutex_lock(&dns_thread.lock);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
pthread_mutex_unlock(&dns_thread.lock);
return -1;
}
static void kill_dns_thread(void *dns_obj)
{
if (dns_obj)
tox_dns3_kill(dns_obj);
memset(&t_data, 0, sizeof(struct _thread_data));
pthread_exit(0);
}
/* puts TXT from dns response in buf. Returns length of TXT on success, -1 on fail.*/
static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, uint8_t *buf)
{
uint8_t *ans_pt = answer + sizeof(HEADER);
uint8_t *ans_end = answer + ans_len;
uint8_t exp_ans[PACKETSZ];
int len = dn_expand(answer, ans_end, ans_pt, exp_ans, sizeof(exp_ans));
if (len == -1)
return dns_error(self, "dn_expand failed.");
ans_pt += len;
if (ans_pt > ans_end - 4)
return dns_error(self, "Reply was too short.");
int type;
GETSHORT(type, ans_pt);
if (type != T_TXT)
return dns_error(self, "Broken reply.");
ans_pt += INT16SZ; /* class */
uint32_t size = 0;
/* recurse through CNAME rr's */
do {
ans_pt += size;
len = dn_expand(answer, ans_end, ans_pt, exp_ans, sizeof(exp_ans));
if (len == -1)
return dns_error(self, "Second dn_expand failed.");
ans_pt += len;
if (ans_pt > ans_end - 10)
return dns_error(self, "Reply was too short.");
GETSHORT(type, ans_pt);
ans_pt += INT16SZ;
ans_pt += 4;
GETSHORT(size, ans_pt);
if (ans_pt + size < answer || ans_pt + size > ans_end)
return dns_error(self, "RR overflow.");
} while (type == T_CNAME);
if (type != T_TXT)
return dns_error(self, "Not a TXT record.");
uint32_t txt_len = *ans_pt;
if (!size || txt_len >= size || !txt_len)
return dns_error(self, "No record found.");
ans_pt++;
ans_pt[txt_len] = '\0';
memcpy(buf, ans_pt, txt_len + 1);
return txt_len;
}
/* Takes address addr in the form "username@domain", puts the username in namebuf,
and the domain in dombuf.
return length of username on success, -1 on failure */
static int parse_addr(uint8_t *addr, uint8_t *namebuf, uint8_t *dombuf)
{
uint8_t tmpaddr[MAX_STR_SIZE];
uint8_t *tmpname, *tmpdom;
strcpy(tmpaddr, addr);
tmpname = strtok(tmpaddr, "@");
tmpdom = strtok(NULL, "");
if (tmpname == NULL || tmpdom == NULL)
return -1;
str_to_lower(tmpdom);
strcpy(namebuf, tmpname);
strcpy(dombuf, tmpdom);
return strlen(namebuf);
}
/* Does DNS lookup for addr and puts resulting tox id in id_bin. */
void *dns3_lookup_thread(void *data)
{
ToxWindow *self = t_data.self;
uint8_t domain[MAX_STR_SIZE];
uint8_t name[MAX_STR_SIZE];
int namelen = parse_addr(t_data.addr, name, domain);
if (namelen == -1) {
dns_error(self, "Must be a Tox ID or an address in the form username@domain");
kill_dns_thread(NULL);
}
/* get domain name/pub key */
uint8_t *DNS_pubkey, *domname = NULL;
int i;
for (i = 0; i < NUM_DNS3_SERVERS; ++i) {
if (strcmp(dns3_servers[i].name, domain) == 0) {
DNS_pubkey = dns3_servers[i].key;
domname = dns3_servers[i].name;
break;
}
}
if (domname == NULL) {
dns_error(self, "Domain not found.");
kill_dns_thread(NULL);
}
void *dns_obj = tox_dns3_new(DNS_pubkey);
if (dns_obj == NULL) {
dns_error(self, "Core failed to create DNS object.");
kill_dns_thread(NULL);
}
uint8_t string[MAX_DNS_REQST_SIZE];
uint32_t request_id;
int str_len = tox_generate_dns3_string(dns_obj, string, sizeof(string), &request_id, name, namelen);
if (str_len == -1) {
dns_error(self, "Core failed to generate dns3 string.");
kill_dns_thread(dns_obj);
}
string[str_len] = '\0';
u_char answer[PACKETSZ];
uint8_t d_string[MAX_DNS_REQST_SIZE];
/* format string and create dns query */
snprintf(d_string, sizeof(d_string), "_%s._tox.%s", string, domname);
int ans_len = res_query(d_string, C_IN, T_TXT, answer, sizeof(answer));
if (ans_len <= 0) {
dns_error(self, "Query failed.");
kill_dns_thread(dns_obj);
}
uint8_t ans_id[MAX_DNS_REQST_SIZE];
/* extract TXT from DNS response */
if (parse_dns_response(self, answer, ans_len, ans_id) == -1)
kill_dns_thread(dns_obj);
uint8_t encrypted_id[MAX_DNS_REQST_SIZE];
int prfx_len = strlen(TOX_DNS3_TXT_PREFIX);
/* extract the encrypted ID from TXT response */
if (strncmp(ans_id, TOX_DNS3_TXT_PREFIX, prfx_len) != 0) {
dns_error(self, "Bad dns3 TXT response.");
kill_dns_thread(dns_obj);
}
memcpy(encrypted_id, ans_id + prfx_len, ans_len - prfx_len);
if (tox_decrypt_dns3_TXT(dns_obj, t_data.id_bin, encrypted_id, strlen(encrypted_id), request_id) == -1) {
dns_error(self, "Core failed to decrypt response.");
kill_dns_thread(dns_obj);
}
pthread_mutex_lock(&dns_thread.lock);
cmd_add_helper(self, t_data.m, t_data.id_bin, t_data.msg);
pthread_mutex_unlock(&dns_thread.lock);
kill_dns_thread(dns_obj);
}
/* creates new thread for dns3 lookup. Only allows one lookup at a time. */
void dns3_lookup(ToxWindow *self, Tox *m, uint8_t *id_bin, uint8_t *addr, uint8_t *msg)
{
if (t_data.busy) {
uint8_t *err = "Please wait for previous user lookup to finish.";
line_info_add(self, NULL, NULL, NULL, err, SYS_MSG, 0, 0);
return;
}
snprintf(t_data.id_bin, sizeof(t_data.id_bin), "%s", id_bin);
snprintf(t_data.addr, sizeof(t_data.addr), "%s", addr);
snprintf(t_data.msg, sizeof(t_data.msg), "%s", msg);
t_data.self = self;
t_data.m = m;
t_data.busy = 1;
if (pthread_create(&dns_thread.tid, NULL, dns3_lookup_thread, NULL) != 0)
exit_toxic_err("failed in dns3_lookup", FATALERR_THREAD_CREATE);
if (pthread_mutex_init(&dns_thread.lock, NULL) != 0)
exit_toxic_err("failed in dns3_lookup", FATALERR_MUTEX_INIT);
}

32
src/dns.h Normal file
View File

@ -0,0 +1,32 @@
/* dns.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/>.
*
*/
/* Does DNS lookup for addr and puts resulting tox id in id_bin.
Return 0 on success, -1 on failure. */
#ifndef _dns_h
#define _dns_h
/* creates new thread for dns3 lookup. Only allows one lookup at a time. */
void dns3_lookup(ToxWindow *self, Tox *m, uint8_t *id_bin, uint8_t *addr, uint8_t *msg);
#endif /* #define _dns_h */

View File

@ -28,7 +28,8 @@
#include <string.h>
#include <assert.h>
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "execute.h"
#include "chat_commands.h"
#include "global_commands.h"
@ -54,6 +55,7 @@ static struct cmd_func global_commands[] = {
{ "/q", cmd_quit },
{ "/quit", cmd_quit },
{ "/status", cmd_status },
#ifdef _SUPPORT_AUDIO
{ "/lsdev", cmd_list_devices },
{ "/sdev", cmd_change_device },
@ -73,7 +75,9 @@ static struct cmd_func chat_commands[] = {
{ "/answer", cmd_answer },
{ "/reject", cmd_reject },
{ "/hangup", cmd_hangup },
{ "/sdev", cmd_set_this_session_device },
{ "/sdev", cmd_ccur_device },
{ "/mute", cmd_mute },
{ "/sense", cmd_sense },
#endif /* _SUPPORT_AUDIO */
};

View File

@ -20,11 +20,17 @@
*
*/
#ifndef _execute_h
#define _execute_h
#include "toxic.h"
#include "windows.h"
#define MAX_NUM_ARGS 4 /* Includes command */
#ifdef _SUPPORT_AUDIO
#define GLOBAL_NUM_COMMANDS 16
#define CHAT_NUM_COMMANDS 11
#define CHAT_NUM_COMMANDS 13
#else
#define GLOBAL_NUM_COMMANDS 14
#define CHAT_NUM_COMMANDS 5
@ -37,3 +43,5 @@ enum {
};
void execute(WINDOW *w, ToxWindow *self, Tox *m, char *cmd, int mode);
#endif /* #define _execute_h */

View File

@ -28,7 +28,9 @@
#include <stdlib.h>
#include <time.h>
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "file_senders.h"
#include "line_info.h"
FileSender file_senders[MAX_FILES];
@ -107,9 +109,9 @@ void do_file_senders(Tox *m)
if (remain)
pct_remain = (1 - (remain / size)) * 100;
const uint8_t *name = file_senders[filenum].pathname;
const uint8_t *name = file_senders[i].pathname;
snprintf(msg, sizeof(msg), "File transfer for '%s' accepted (%.1Lf%%)", name, pct_remain);
line_info_set(self, file_senders[filenum].line_id, msg);
line_info_set(self, file_senders[i].line_id, msg);
}
if (file_senders[i].piecelen == 0) {

View File

@ -20,7 +20,33 @@
*
*/
#ifndef _filesenders_h
#define _filesenders_h
#include "toxic.h"
#include "windows.h"
#define FILE_PIECE_SIZE 2048 /* must be >= (MAX_CRYPTO_DATA_SIZE - 2) in toxcore/net_crypto.h */
#define MAX_FILES 256
#define TIMEOUT_FILESENDER 300
typedef struct {
FILE *file;
ToxWindow *toxwin;
int32_t friendnum;
bool active;
int filenum;
uint8_t nextpiece[FILE_PIECE_SIZE];
uint16_t piecelen;
uint8_t pathname[MAX_STR_SIZE];
uint64_t timestamp;
uint64_t size;
uint32_t line_id;
} FileSender;
/* Should only be called on exit */
void close_all_file_senders(void);
void do_file_senders(Tox *m);
#endif /* #define _filesenders_h */

View File

@ -31,6 +31,8 @@
#include <tox/tox.h>
#include "toxic.h"
#include "windows.h"
#include "chat.h"
#include "friendlist.h"
#include "misc_tools.h"
@ -54,7 +56,7 @@ extern struct user_settings *user_settings;
ToxicFriend friends[MAX_FRIENDS_NUM];
static int friendlist_index[MAX_FRIENDS_NUM] = {0};
struct _pendingDel {
static struct _pendingDel {
int num;
bool active;
} pendingdelete;
@ -162,9 +164,11 @@ static void friendlist_onStatusMessageChange(ToxWindow *self, int32_t num, uint8
if (len > TOX_MAX_STATUSMESSAGE_LENGTH || num >= max_friends_index)
return;
strcpy(friends[num].statusmsg, str);
friends[num].statusmsg[len] = '\0';
str[len] = '\0';
snprintf(friends[num].statusmsg, sizeof(friends[num].statusmsg), "%s", str);
len = strlen(friends[num].statusmsg);
friends[num].statusmsg_len = len;
friends[num].statusmsg[len] = '\0';
}
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_t num, bool sort)

View File

@ -24,10 +24,21 @@
#define FRIENDLIST_H_53I41IM
#include <time.h>
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "file_senders.h"
#define TIME_STR_SIZE 16
struct FileReceiver {
uint8_t filenames[MAX_FILES][MAX_STR_SIZE];
FILE *files[MAX_FILES];
bool pending[MAX_FILES];
uint64_t size[MAX_FILES];
uint32_t line_id[MAX_FILES];
};
struct LastOnline {
uint64_t last_on;
struct tm tm;

View File

@ -27,11 +27,13 @@
#include <stdlib.h>
#include <string.h>
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "misc_tools.h"
#include "friendlist.h"
#include "log.h"
#include "line_info.h"
#include "dns.h"
extern char *DATA_FILE;
extern ToxWindow *prompt;
@ -88,6 +90,49 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
}
void cmd_add_helper(ToxWindow *self, Tox *m, uint8_t *id_bin, uint8_t *msg)
{
uint8_t *errmsg;
int32_t f_num = tox_add_friend(m, id_bin, msg, strlen(msg));
switch (f_num) {
case TOX_FAERR_TOOLONG:
errmsg = "Message is too long.";
break;
case TOX_FAERR_NOMESSAGE:
errmsg = "Please add a message to your request.";
break;
case TOX_FAERR_OWNKEY:
errmsg = "That appears to be your own ID.";
break;
case TOX_FAERR_ALREADYSENT:
errmsg = "Friend request has already been sent.";
break;
case TOX_FAERR_UNKNOWN:
errmsg = "Undefined error when adding friend.";
break;
case TOX_FAERR_BADCHECKSUM:
errmsg = "Bad checksum in address.";
break;
case TOX_FAERR_SETNEWNOSPAM:
errmsg = "Nospam was different.";
break;
default:
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_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
uint8_t *errmsg;
@ -119,73 +164,33 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
snprintf(msg, sizeof(msg), "Hello, my name is %s. Care to Tox?", selfname);
}
if (strlen(id) != 2 * TOX_FRIEND_ADDRESS_SIZE) {
errmsg = "Invalid ID length.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
return;
}
uint8_t id_bin[TOX_FRIEND_ADDRESS_SIZE] = {0};
uint16_t id_len = strlen(id);
size_t i;
char xx[3];
uint32_t x;
uint8_t id_bin[TOX_FRIEND_ADDRESS_SIZE];
/* try to add tox ID */
if (id_len == 2 * TOX_FRIEND_ADDRESS_SIZE) {
size_t i;
char xx[3];
uint32_t x;
for (i = 0; i < TOX_FRIEND_ADDRESS_SIZE; ++i) {
xx[0] = id[2 * i];
xx[1] = id[2 * i + 1];
xx[2] = '\0';
for (i = 0; i < TOX_FRIEND_ADDRESS_SIZE; ++i) {
xx[0] = id[2 * i];
xx[1] = id[2 * i + 1];
xx[2] = '\0';
if (sscanf(xx, "%02x", &x) != 1) {
errmsg = "Invalid ID.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
return;
if (sscanf(xx, "%02x", &x) != 1) {
errmsg = "Invalid ID.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
return;
}
id_bin[i] = x;
}
id_bin[i] = x;
cmd_add_helper(self, m, id_bin, msg);
} else { /* assume id is a username@domain address and do DNS lookup */
dns3_lookup(self, m, id_bin, id, msg);
}
for (i = 0; i < TOX_FRIEND_ADDRESS_SIZE; i++) {
id[i] = toupper(id[i]);
}
int32_t f_num = tox_add_friend(m, id_bin, msg, strlen(msg));
switch (f_num) {
case TOX_FAERR_TOOLONG:
errmsg = "Message is too long.";
break;
case TOX_FAERR_NOMESSAGE:
errmsg = "Please add a message to your request.";
break;
case TOX_FAERR_OWNKEY:
errmsg = "That appears to be your own ID.";
break;
case TOX_FAERR_ALREADYSENT:
errmsg = "Friend request has already been sent.";
break;
case TOX_FAERR_UNKNOWN:
errmsg = "Undefined error when adding friend.";
break;
case TOX_FAERR_BADCHECKSUM:
errmsg = "Bad checksum in address.";
break;
case TOX_FAERR_SETNEWNOSPAM:
errmsg = "Nospam was different (is this contact already added?";
break;
default:
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])
@ -422,16 +427,18 @@ void cmd_prompt_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
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";
msg = " * Argument messages must be enclosed in quotation marks.";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
msg = " * Use ctrl-o and ctrl-p to navigate through the tabs.";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
line_info_add(self, NULL, NULL, NULL, "", SYS_MSG, 0, 0);
hst->line_start = start;
}
void cmd_quit(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
exit_toxic(m);
exit_toxic_success(m);
}
void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
@ -454,20 +461,16 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
}
char *status = argv[1];
str_to_lower(status);
int len = strlen(status);
char l_status[len + 1];
int i;
for (i = 0; i <= len; ++i)
l_status[i] = tolower(status[i]);
TOX_USERSTATUS status_kind;
if (!strcmp(l_status, "online"))
if (!strcmp(status, "online"))
status_kind = TOX_USERSTATUS_NONE;
else if (!strcmp(l_status, "away"))
else if (!strcmp(status, "away"))
status_kind = TOX_USERSTATUS_AWAY;
else if (!strcmp(l_status, "busy"))
else if (!strcmp(status, "busy"))
status_kind = TOX_USERSTATUS_BUSY;
else {
errmsg = "Invalid status. Valid statuses are: online, busy and away.";

View File

@ -20,6 +20,12 @@
*
*/
#ifndef _global_commands_h
#define _global_commands_h
#include "windows.h"
#include "toxic.h"
void cmd_accept(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_add(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_clear(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
@ -33,7 +39,11 @@ void cmd_prompt_help(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_ST
void cmd_quit(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_status(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_add_helper(ToxWindow *self, Tox *m, uint8_t *id_bin, uint8_t *msg);
#ifdef _SUPPORT_AUDIO
void cmd_list_devices(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_change_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
#endif /* _SUPPORT_AUDIO */
#endif /* _SUPPORT_AUDIO */
#endif /* #define _global_commands_h */

View File

@ -28,7 +28,8 @@
#include <string.h>
#include <time.h>
#include "toxic_windows.h"
#include "windows.h"
#include "toxic.h"
#include "execute.h"
#include "misc_tools.h"
#include "groupchat.h"
@ -41,7 +42,7 @@
extern char *DATA_FILE;
extern int store_data(Tox *m, char *path);
static GroupChat groupchats[MAX_WINDOWS_NUM];
static GroupChat groupchats[MAX_GROUPCHAT_NUM];
static int max_groupchat_index = 0;
extern struct user_settings *user_settings;
@ -51,6 +52,9 @@ extern const uint8_t glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE];
int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum)
{
if (groupnum > MAX_GROUPCHAT_NUM)
return -1;
int i;
for (i = 0; i <= max_groupchat_index; ++i) {
@ -146,12 +150,13 @@ static void print_groupchat_help(ToxWindow *self)
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";
msg = " * Use Page Up/Page Down keys to scroll chat history";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
msg = " * Scroll peer list with the Page Up/Page Down keys.\n";
msg = " * Scroll peer list with the ctrl-] and ctrl-[ keys.";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
msg = " * Notice, some friends will be missing names while finding peers\n";
msg = " * Notice, some friends will be missing names while finding peers";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, 0);
line_info_add(self, NULL, NULL, NULL, "", SYS_MSG, 0, 0);
hst->line_start = start;
}
@ -255,16 +260,14 @@ static void copy_peernames(int gnum, uint8_t peerlist[][TOX_MAX_NAME_LENGTH], ui
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
|| groupchats[gnum].peer_name_lengths == NULL || groupchats[gnum].oldpeer_name_lengths == NULL) {
exit_toxic_err("failed in copy_peernames", FATALERR_MEMORY);
}
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;
@ -294,9 +297,15 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu
if (self->num != groupnum)
return;
if (groupnum > max_groupchat_index)
return;
groupchats[groupnum].num_peers = tox_group_number_peers(m, groupnum);
int num_peers = groupchats[groupnum].num_peers;
if (peernum >= num_peers)
return;
/* get old peer name before updating name list */
uint8_t oldpeername[TOX_MAX_NAME_LENGTH];
@ -380,40 +389,42 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
int x, y, y2, x2;
getyx(self->window, y, x);
getmaxyx(self->window, y2, x2);
int cur_len = 0;
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);
}
/* If we're in scroll mode ignore rest of function */
if (ctx->hst->scroll_mode) {
line_info_onKey(self, key);
if (x2 <= 0)
return;
}
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);
int cur_len = 0; /* widechar len of current char */
int x2_is_odd = x2 % 2 != 0;
if (x == x2 - 1)
wmove(self->window, y + 1, 0);
else
if (ltr) { /* char is printable */
if (ctx->len < MAX_STR_SIZE - 1) {
add_char_to_buf(ctx, key);
if (x >= x2 - 1) {
wmove(self->window, y, x2 / 2 + x2_is_odd);
ctx->start += x2 / 2;
} else {
wmove(self->window, y, x + MAX(1, wcwidth(key)));
}
}
} else { /* if (!ltr) */
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 (line_info_onKey(self, key))
return;
if (x == 0)
wmove(self->window, y - 1, x2 - cur_len);
else
if (key == 0x107 || key == 0x8 || key == 0x7f) { /* BACKSPACE key */
if (ctx->pos > 0) {
cur_len = MAX(1, wcwidth(ctx->line[ctx->pos]));
del_char_buf_bck(ctx);
if (x == 0) {
ctx->start = ctx->start >= x2 ? ctx->start - x2 : 0;
int new_x = ctx->start == 0 ? ctx->pos : x2 - cur_len;
wmove(self->window, y, new_x);
} else {
wmove(self->window, y, x - cur_len);
}
} else {
beep();
}
@ -421,14 +432,14 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
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);
del_char_buf_frnt(ctx);
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);
discard_buf(ctx);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
} else {
beep();
@ -437,7 +448,7 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
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);
kill_buf(ctx);
else
beep();
}
@ -445,6 +456,7 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
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;
ctx->start = 0;
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
}
}
@ -452,7 +464,8 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
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);
ctx->start = x2 * (ctx->len / x2);
mv_curs_end(self->window, ctx->len, y2, x2);
}
}
@ -461,10 +474,13 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
--ctx->pos;
cur_len = MAX(1, wcwidth(ctx->line[ctx->pos]));
if (x == 0)
wmove(self->window, y - 1, x2 - cur_len);
else
if (x == 0) {
wmove(self->window, y, x2 - cur_len);
ctx->start = ctx->start >= x2 ? ctx->start - x2 : 0;
ctx->pos = ctx->start + x2 - 1;
} else {
wmove(self->window, y, x - cur_len);
}
} else {
beep();
}
@ -472,27 +488,30 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
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
if (x == x2 - 1) {
wmove(self->window, y, 0);
ctx->start += x2;
ctx->pos = ctx->start;
} else {
cur_len = MAX(1, wcwidth(ctx->line[ctx->pos]));
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);
fetch_hist_item(ctx, MOVE_UP);
ctx->start = x2 * (ctx->len / x2);
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);
fetch_hist_item(ctx, MOVE_DOWN);
ctx->start = x2 * (ctx->len / x2);
mv_curs_end(self->window, ctx->len, y2, x2);
}
@ -501,11 +520,10 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
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,
diff = complete_line(ctx, 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);
diff = complete_line(ctx, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
if (diff != -1) {
if (x + diff > x2 - 1) {
@ -523,20 +541,22 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
}
/* Scroll peerlist up and down one position if list overflows window */
else if (key == KEY_NPAGE) {
else if (key == T_KEY_C_RB) {
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) {
else if (key == T_KEY_C_LB) {
if (groupchats[self->num].side_pos > 0)
--groupchats[self->num].side_pos;
}
/* RETURN key: Execute command or print line */
else if (key == '\n') {
rm_trailing_spaces_buf(ctx);
uint8_t line[MAX_STR_SIZE];
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
@ -547,7 +567,7 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (!string_is_empty(line))
add_line_to_hist(ctx->line, ctx->len, ctx->ln_history, &ctx->hst_tot, &ctx->hst_pos);
add_line_to_hist(ctx);
if (line[0] == '/') {
if (strcmp(line, "/close") == 0) {
@ -571,7 +591,7 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
}
}
reset_buf(ctx->line, &ctx->pos, &ctx->len);
reset_buf(ctx);
}
}
}
@ -587,21 +607,17 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
line_info_print(self);
wclear(ctx->linewin);
if (ctx->hst->scroll_mode) {
line_info_onDraw(self);
} else {
scrollok(ctx->history, 1);
curs_set(1);
scrollok(ctx->history, 0);
curs_set(1);
if (ctx->len > 0) {
uint8_t line[MAX_STR_SIZE];
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);
}
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
reset_buf(ctx);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
} else {
mvwprintw(ctx->linewin, 1, 0, "%s", &line[ctx->start]);
}
}
@ -651,11 +667,8 @@ static void groupchat_onInit(ToxWindow *self, Tox *m)
ctx->hst = malloc(sizeof(struct history));
ctx->log = malloc(sizeof(struct chatlog));
if (ctx->log == NULL || ctx->hst == NULL) {
endwin();
fprintf(stderr, "malloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
if (ctx->log == NULL || ctx->hst == NULL)
exit_toxic_err("failed in groupchat_onInit", FATALERR_MEMORY);
memset(ctx->hst, 0, sizeof(struct history));
memset(ctx->log, 0, sizeof(struct chatlog));
@ -690,14 +703,10 @@ ToxWindow new_group_chat(Tox *m, int groupnum)
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
if (chatwin != NULL)
ret.chatwin = chatwin;
else {
endwin();
fprintf(stderr, "calloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
if (chatwin == NULL)
exit_toxic_err("failed in new_group_chat", FATALERR_MEMORY);
ret.chatwin = chatwin;
ret.num = groupnum;
return ret;

View File

@ -20,8 +20,15 @@
*
*/
#ifndef _groupchat_h
#define _groupchat_h
#include "toxic.h"
#include "windows.h"
#define SIDEBAR_WIDTH 16
#define SDBAR_OFST 2 /* Offset for the peer number box at the top of the statusbar */
#define MAX_GROUPCHAT_NUM MAX_WINDOWS_NUM - 2
typedef struct {
int chatwin;
@ -37,3 +44,5 @@ typedef struct {
void kill_groupchat_window(ToxWindow *self);
int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum);
ToxWindow new_group_chat(Tox *m, int groupnum);
#endif /* #define _groupchat_h */

View File

@ -28,56 +28,46 @@
#include <string.h>
#include <stdbool.h>
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "line_info.h"
#include "groupchat.h"
#include "settings.h"
extern struct user_settings *user_settings;
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);
}
if (hst->line_root == NULL)
exit_toxic_err("failed in line_info_init", FATALERR_MEMORY);
memset(hst->line_root, 0, sizeof(struct line_info));
hst->line_start = hst->line_root;
hst->line_end = hst->line_start;
hst->queue_sz = 0;
}
/* resets line_start when scroll mode is disabled */
static void line_info_reset_start(struct history *hst)
/* resets line_start */
static void line_info_reset_start(ToxWindow *self, struct history *hst)
{
int y2, x2;
getmaxyx(self->window, y2, x2);
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;
}
uint16_t lncnt = 0;
int side_offst = self->is_groupchat ? SIDEBAR_WIDTH : 0;
int top_offst = self->is_chat ? 2 : 0;
int max_y = (y2 - CHATBOX_HEIGHT - top_offst);
while (line->prev && lncnt < max_y) {
lncnt += (1 + line->newlines) +( line->len / (x2 - side_offst));
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);
}
hst->line_start = line;
}
void line_info_cleanup(struct history *hst)
@ -107,75 +97,117 @@ static void line_info_root_fwd(struct history *hst)
hst->line_root = tmp;
}
/* adds a line_info line to queue */
static void line_info_add_queue(struct history *hst, struct line_info *line)
{
if (hst->queue_sz >= MAX_QUEUE)
return;
hst->queue[hst->queue_sz++] = line;
}
/* returns ptr to queue item 0 and removes it from queue */
static struct line_info *line_info_ret_queue(struct history *hst)
{
if (hst->queue_sz <= 0)
return NULL;
struct line_info *ret = hst->queue[0];
int i;
for (i = 0; i < hst->queue_sz; ++i)
hst->queue[i] = hst->queue[i + 1];
--hst->queue_sz;
return ret;
}
/* creates new line_info line and puts it in the queue */
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);
}
if (new_line == NULL)
exit_toxic_err("failed in line_info_add", FATALERR_MEMORY);
memset(new_line, 0, sizeof(struct line_info));
int len = 1; /* there will always be a newline */
int len = 1; /* there will always be a newline */
/* for type-specific formatting in print function */
switch (type) {
case ACTION:
case CONNECTION:
len += 3;
break;
case SYS_MSG:
break;
case PROMPT:
++len;
break;
default:
len += 2;
break;
}
if (msg) {
strcpy(new_line->msg, msg);
len += strlen(msg);
snprintf(new_line->msg, sizeof(new_line->msg), "%s", msg);
len += strlen(new_line->msg);
int i;
for (i = 0; msg[i]; ++i) {
if (msg[i] == '\n')
++new_line->newlines;
}
}
if (tmstmp) {
strcpy(new_line->timestamp, tmstmp);
len += strlen(tmstmp);
snprintf(new_line->timestamp, sizeof(new_line->timestamp), "%s", tmstmp);
len += strlen(new_line->timestamp);
}
if (name1) {
strcpy(new_line->name1, name1);
len += strlen(name1);
snprintf(new_line->name1, sizeof(new_line->name1), "%s", name1);
len += strlen(new_line->name1);
}
if (name2) {
strcpy(new_line->name2, name2);
len += strlen(name2);
snprintf(new_line->name2, sizeof(new_line->name2), "%s", name2);
len += strlen(new_line->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;
line_info_add_queue(hst, new_line);
}
if (++hst->line_items > MAX_HISTORY) {
--hst->line_items;
/* adds a single queue item to hst if possible. only called once per call to line_info_print() */
static void line_info_check_queue(ToxWindow *self)
{
struct history *hst = self->chatwin->hst;
struct line_info *line = line_info_ret_queue(hst);
if (line == NULL)
return;
if (hst->start_id > user_settings->history_size)
line_info_root_fwd(hst);
}
int newlines = 0;
int i;
for (i = 0; msg[i]; ++i) {
if (msg[i] == '\n')
++newlines;
}
line->id = hst->line_end->id + 1;
line->prev = hst->line_end;
hst->line_end->next = line;
hst->line_end = line;
int y, y2, x, x2;
getmaxyx(self->window, y2, x2);
@ -185,20 +217,15 @@ void line_info_add(ToxWindow *self, uint8_t *tmstmp, uint8_t *name1, uint8_t *na
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 lines = 1 + line->newlines + (line->len / (x2 - offst));
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) {
if (y + lines - 1 >= max_y) {
while (lines > 0 && hst->line_start->next) {
lines -= 1 + hst->line_start->next->newlines + (hst->line_start->next->len / (x2 - offst));
hst->line_start = hst->line_start->next;
++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;
}
}
}
@ -206,17 +233,22 @@ void line_info_add(ToxWindow *self, uint8_t *tmstmp, uint8_t *name1, uint8_t *na
void line_info_print(ToxWindow *self)
{
ChatContext *ctx = self->chatwin;
if (ctx == NULL)
return;
struct history *hst = ctx->hst;
/* Only allow one new item to be added to chat window per call to this function */
line_info_check_queue(self);
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 */
y2 = user_settings->history_size; /* temporary fix to make prompt scroll */
if (x2 <= SIDEBAR_WIDTH)
return;
@ -226,7 +258,7 @@ void line_info_print(ToxWindow *self)
else
wmove(win, 2, 0);
struct line_info *line = ctx->hst->line_start->next;
struct line_info *line = hst->line_start->next;
int offst = self->is_groupchat ? SIDEBAR_WIDTH : 0;
int numlines = 0;
@ -342,6 +374,10 @@ void line_info_print(ToxWindow *self)
line = line->next;
}
/* keep calling until queue is empty */
if (hst->queue_sz > 0)
line_info_print(self);
}
void line_info_set(ToxWindow *self, uint32_t id, uint8_t *msg)
@ -399,46 +435,43 @@ static void line_info_page_down(ToxWindow *self, struct history *hst)
hst->line_start = hst->line_start->next;
}
void line_info_onKey(ToxWindow *self, wint_t key)
bool line_info_onKey(ToxWindow *self, wint_t key)
{
struct history *hst = self->chatwin->hst;
bool match = true;
switch (key) {
case KEY_PPAGE:
/* TODO: Find good key bindings for all this stuff */
case T_KEY_C_F:
line_info_page_up(self, hst);
break;
case KEY_NPAGE:
case T_KEY_C_V:
line_info_page_down(self, hst);
break;
break;
case KEY_UP:
case KEY_PPAGE:
line_info_scroll_up(hst);
break;
case KEY_DOWN:
case KEY_NPAGE:
line_info_scroll_down(hst);
break;
case KEY_HOME:
/* case ?:
line_info_goto_root(hst);
break;
break; */
case KEY_END:
line_info_reset_start(hst);
case T_KEY_C_H:
line_info_reset_start(self, hst);
break;
default:
match = false;
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");
return match;
}
void line_info_clear(struct history *hst)

View File

@ -20,7 +20,15 @@
*
*/
#define MAX_HISTORY 700
#ifndef _line_info_h
#define _line_info_h
#include "windows.h"
#include "toxic.h"
#define MAX_HISTORY 10000
#define MIN_HISTORY 20
#define MAX_QUEUE 32
enum {
SYS_MSG,
@ -42,6 +50,7 @@ struct line_info {
uint8_t colour;
uint32_t id;
uint16_t len; /* combined len of all strings */
uint8_t newlines;
struct line_info *prev;
struct line_info *next;
@ -53,15 +62,12 @@ struct history {
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;
struct line_info *queue[MAX_QUEUE];
int queue_sz;
};
/* adds a line to history (also moves line_start and/or line_root forward if necessary) */
/* creates new line_info line and puts it in the queue */
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);
@ -71,9 +77,6 @@ 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);
@ -81,5 +84,6 @@ void line_info_clear(struct history *hst);
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);
bool line_info_onKey(ToxWindow *self, wint_t key); /* returns true if key is a match */
#endif /* #define _line_info_h */

View File

@ -29,7 +29,8 @@
#include <time.h>
#include "configdir.h"
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "misc_tools.h"
#include "log.h"
#include "settings.h"

View File

@ -20,6 +20,9 @@
*
*/
#ifndef _log_h
#define _log_h
#define LOG_FLUSH_LIMIT 2 /* limits calls to fflush(logfile) to a max of one per LOG_FLUSH_LIMIT seconds */
struct chatlog {
@ -40,3 +43,5 @@ void log_enable(uint8_t *name, uint8_t *key, struct chatlog *log);
/* disables logging for specified log and closes file */
void log_disable(struct chatlog *log);
#endif /* #define _log_h */

View File

@ -29,7 +29,8 @@
#include <time.h>
#include <limits.h>
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "misc_tools.h"
#include "settings.h"
@ -63,11 +64,10 @@ void get_time_str(uint8_t *buf)
strftime(buf, TIME_STR_SIZE, t, get_time());
}
/* XXX: FIX */
unsigned char *hex_string_to_bin(char hex_string[])
char *hex_string_to_bin(const char *hex_string)
{
size_t len = strlen(hex_string);
unsigned char *val = malloc(len);
char *val = malloc(len);
if (val == NULL) {
endwin();
@ -75,11 +75,10 @@ unsigned char *hex_string_to_bin(char hex_string[])
exit(EXIT_FAILURE);
}
char *pos = hex_string;
size_t i;
for (i = 0; i < len; ++i, pos += 2)
sscanf(pos, "%2hhx", &val[i]);
for (i = 0; i < len; ++i, hex_string += 2)
sscanf(hex_string, "%2hhx", &val[i]);
return val;
}
@ -227,30 +226,35 @@ int valid_nick(uint8_t *nick)
/* Moves 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)
{
int end_y = (len / max_x) + (max_y - CURS_Y_OFFSET);
int end_x = len % max_x;
wmove(w, end_y, end_x);
int new_x = len < max_x ? len : len % max_x;
wmove(w, max_y - CURS_Y_OFFSET, new_x);
}
/* gets base file name from path or original file name if no path is supplied */
void get_file_name(uint8_t *pathname, uint8_t *namebuf)
void get_file_name(uint8_t *namebuf, uint8_t *pathname)
{
int idx = strlen(pathname) - 1;
while (idx >= 0 && pathname[idx] == '/')
pathname[idx--] = '\0';
uint8_t *filename = strrchr(pathname, '/'); /* Try unix style paths */
uint8_t *filename = strrchr(pathname, '/');
if (filename != NULL) {
if (!strlen(++filename))
filename = pathname;
} else {
filename = strrchr(pathname, '\\'); /* Try windows style paths */
if (filename == NULL)
filename = pathname;
filename = pathname;
}
snprintf(namebuf, MAX_STR_SIZE, "%s", filename);
}
/* converts str to all lowercase */
void str_to_lower(uint8_t *str)
{
int i;
for (i = 0; str[i]; ++i)
str[i] = tolower(str[i]);
}

View File

@ -19,12 +19,22 @@
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef _misc_tools_h
#define _misc_tools_h
#include "windows.h"
#include "toxic.h"
#ifndef MIN
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#endif
#ifndef MAX
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#endif
/* convert a hex string to binary */
unsigned char *hex_string_to_bin(char hex_string[]);
char *hex_string_to_bin(const char *hex_string);
/* get the current unix time */
uint64_t get_unix_time(void);
@ -63,9 +73,10 @@ void alert_window(ToxWindow *self, int type, bool is_beep);
/* case-insensitive string compare function for use with qsort */
int qsort_strcasecmp_hlpr(const void *nick1, const void *nick2);
/* Returns true if nick is valid. A valid toxic nick:
/* Returns 1 if nick is valid, 0 if not. A valid toxic nick:
- cannot be empty
- cannot start with a space
- must not contain a forward slash (for logfile naming purposes)
- must not contain contiguous spaces */
int valid_nick(uint8_t *nick);
@ -73,4 +84,9 @@ int valid_nick(uint8_t *nick);
void mv_curs_end(WINDOW *w, size_t len, int max_y, int max_x);
/* gets base file name from path or original file name if no path is supplied */
void get_file_name(uint8_t *pathname, uint8_t *namebuf);
void get_file_name(uint8_t *namebuf, uint8_t *pathname);
/* converts str to all lowercase */
void str_to_lower(uint8_t *str);
#endif /* #define _misc_tools_h */

View File

@ -27,7 +27,8 @@
#include <stdlib.h>
#include <string.h>
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "prompt.h"
#include "execute.h"
#include "misc_tools.h"
@ -74,7 +75,7 @@ void prompt_update_nick(ToxWindow *prompt, uint8_t *nick, uint16_t len)
{
StatusBar *statusbar = prompt->stb;
snprintf(statusbar->nick, sizeof(statusbar->nick), "%s", nick);
statusbar->nick_len = len;
statusbar->nick_len = strlen(statusbar->nick);
}
/* Updates own statusmessage in prompt statusbar */
@ -82,7 +83,7 @@ void prompt_update_statusmessage(ToxWindow *prompt, uint8_t *statusmsg, uint16_t
{
StatusBar *statusbar = prompt->stb;
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
statusbar->statusmsg_len = len;
statusbar->statusmsg_len = strlen(statusbar->statusmsg);
}
/* Updates own status in prompt statusbar */
@ -101,7 +102,7 @@ void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected)
/* Adds friend request to pending friend requests.
Returns request number on success, -1 if queue is full or other error. */
static int add_friend_request(uint8_t *public_key)
static int add_friend_request(const uint8_t *public_key)
{
if (num_frnd_requests >= MAX_FRIENDS_NUM)
return -1;
@ -130,31 +131,16 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
getyx(ctx->history, y, x);
getmaxyx(ctx->history, y2, x2);
/* 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);
add_char_to_buf(ctx, key);
}
} else { /* if (!ltr) */
/* 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);
del_char_buf_bck(ctx);
wmove(ctx->history, y, x - 1); /* not necessary but fixes a display glitch */
} else {
beep();
@ -163,7 +149,7 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
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);
del_char_buf_frnt(ctx);
} else {
beep();
}
@ -173,7 +159,7 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (ctx->pos > 0) {
wmove(ctx->history, ctx->orig_y, X_OFST);
wclrtobot(ctx->history);
discard_buf(ctx->line, &ctx->pos, &ctx->len);
discard_buf(ctx);
} else {
beep();
}
@ -181,7 +167,7 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
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);
kill_buf(ctx);
else
beep();
}
@ -212,8 +198,7 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
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);
fetch_hist_item(ctx, MOVE_UP);
/* adjust line y origin appropriately when window scrolls down */
if (ctx->at_bottom && ctx->len >= x2 - X_OFST) {
@ -233,14 +218,12 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
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);
fetch_hist_item(ctx, 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)
if (complete_line(ctx, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE) == -1)
beep();
} else {
beep();
@ -249,6 +232,8 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
/* RETURN key: execute command */
else if (key == '\n') {
rm_trailing_spaces_buf(ctx);
wprintw(ctx->history, "\n");
uint8_t line[MAX_STR_SIZE] = {0};
@ -256,11 +241,11 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
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);
add_line_to_hist(ctx);
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);
reset_buf(ctx);
}
}
}
@ -273,10 +258,8 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
getyx(ctx->history, y, x);
getmaxyx(ctx->history, y2, x2);
if (!ctx->hst->scroll_mode) {
curs_set(1);
scrollok(ctx->history, 1);
}
curs_set(1);
scrollok(ctx->history, 1);
line_info_print(self);
@ -293,7 +276,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
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);
reset_buf(ctx);
else
mvwprintw(ctx->history, ctx->orig_y, X_OFST, line);
@ -403,10 +386,9 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, int32_t friendnum
}
}
static void prompt_onFriendRequest(ToxWindow *self, Tox *m, uint8_t *key, uint8_t *data, uint16_t length)
static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const uint8_t *key, const uint8_t *data,
uint16_t length)
{
data[length] = '\0';
ChatContext *ctx = self->chatwin;
uint8_t timefrmt[TIME_STR_SIZE];
@ -486,11 +468,8 @@ static void prompt_onInit(ToxWindow *self, Tox *m)
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);
}
if (ctx->log == NULL || ctx->hst == NULL)
exit_toxic_err("failed in prompt_onInit", FATALERR_MEMORY);
memset(ctx->log, 0, sizeof(struct chatlog));
memset(ctx->hst, 0, sizeof(struct history));
@ -526,14 +505,11 @@ ToxWindow new_prompt(void)
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
StatusBar *stb = calloc(1, sizeof(StatusBar));
if (stb != NULL && chatwin != NULL) {
ret.chatwin = chatwin;
ret.stb = stb;
} else {
endwin();
fprintf(stderr, "calloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
if (stb == NULL || chatwin == NULL)
exit_toxic_err("failed in new_prompt", FATALERR_MEMORY);
ret.chatwin = chatwin;
ret.stb = stb;
return ret;
}

View File

@ -23,8 +23,10 @@
#ifndef PROMPT_H_UZYGWFFL
#define PROMPT_H_UZYGWFFL
#define X_OFST 2 /* offset to account for prompt char */
#include "toxic.h"
#include "windows.h"
#define X_OFST 2 /* offset to account for prompt char */
#ifdef _SUPPORT_AUDIO
#define AC_NUM_GLOB_COMMANDS 17

View File

@ -20,95 +20,162 @@
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "toxic.h"
#include "windows.h"
#include "configdir.h"
#ifdef _SUPPORT_AUDIO
#include "device.h"
#endif /* _SUPPORT_AUDIO */
#include "toxic_windows.h"
#include "configdir.h"
#include "settings.h"
#include "line_info.h"
static void uset_autolog(struct user_settings *s, const char *val);
static void uset_time(struct user_settings *s, const char *val);
static void uset_alerts(struct user_settings *s, const char *val);
static void uset_colours(struct user_settings *s, const char *val);
static void uset_hst_size(struct user_settings *s, const char *val);
static void uset_dwnld_path(struct user_settings *s, const char *val);
static void uset_autolog(struct user_settings *s, int val);
static void uset_time(struct user_settings *s, int val);
static void uset_alerts(struct user_settings *s, int val);
static void uset_colours(struct user_settings *s, int val);
static void uset_ain_dev(struct user_settings *s, int val);
static void uset_aout_dev(struct user_settings *s, int val);
#ifdef _SUPPORT_AUDIO
static void uset_ain_dev(struct user_settings *s, const char *val);
static void uset_aout_dev(struct user_settings *s, const char *val);
#endif
struct {
const char *name;
void (*func)(struct user_settings *s, int val);
const char *key;
void (*func)(struct user_settings *s, const char *val);
} user_settings_list[] = {
{ "autolog", uset_autolog },
{ "time", uset_time },
{ "disable_alerts", uset_alerts },
{ "colour_theme", uset_colours },
{ "history_size", uset_hst_size },
{ "download_path", uset_dwnld_path },
#ifdef _SUPPORT_AUDIO
{ "audio_in_dev", uset_ain_dev },
{ "audio_out_dev", uset_aout_dev },
#endif
};
static void uset_autolog(struct user_settings *s, int val)
static void uset_autolog(struct user_settings *s, const char *val)
{
int n = atoi(val);
/* default off if invalid value */
s->autolog = val == AUTOLOG_ON ? AUTOLOG_ON : AUTOLOG_OFF;
s->autolog = n == AUTOLOG_ON ? AUTOLOG_ON : AUTOLOG_OFF;
}
static void uset_time(struct user_settings *s, int val)
static void uset_time(struct user_settings *s, const char *val)
{
int n = atoi(val);
/* default to 24 hour time if invalid value */
s->time = val == TIME_12 ? TIME_12 : TIME_24;
s->time = n == TIME_12 ? TIME_12 : TIME_24;
}
static void uset_alerts(struct user_settings *s, int val)
static void uset_alerts(struct user_settings *s, const char *val)
{
int n = atoi(val);
/* alerts default on if invalid value */
s->alerts = val == ALERTS_DISABLED ? ALERTS_DISABLED : ALERTS_ENABLED;
s->alerts = n == ALERTS_DISABLED ? ALERTS_DISABLED : ALERTS_ENABLED;
}
static void uset_colours(struct user_settings *s, int val)
static void uset_colours(struct user_settings *s, const char *val)
{
int n = atoi(val);
/* use default toxic colours if invalid value */
s->colour_theme = val == NATIVE_COLS ? NATIVE_COLS : DFLT_COLS;
s->colour_theme = n == NATIVE_COLS ? NATIVE_COLS : DFLT_COLS;
}
#ifdef _SUPPORT_AUDIO
static void uset_ain_dev(struct user_settings *s, int val)
static void uset_ain_dev(struct user_settings *s, const char *val)
{
if (val < 0 || val > MAX_DEVICES)
val = 0;
s->audio_in_dev = val;
int n = atoi(val);
if (n < 0 || n > MAX_DEVICES)
n = (long int) 0;
s->audio_in_dev = (long int) n;
}
static void uset_aout_dev(struct user_settings *s, int val)
static void uset_aout_dev(struct user_settings *s, const char *val)
{
if (val < 0 || val > MAX_DEVICES)
val = 0;
int n = atoi(val);
s->audio_out_dev = val;
if (n < 0 || n > MAX_DEVICES)
n = (long int) 0;
s->audio_out_dev = (long int) n;
}
#endif /* _SUPPORT_AUDIO */
static void uset_hst_size(struct user_settings *s, const char *val)
{
int n = atoi(val);
/* if val is out of range use default history size */
s->history_size = (n > MAX_HISTORY || n < MIN_HISTORY) ? DFLT_HST_SIZE : n;
}
static void uset_dwnld_path(struct user_settings *s, const char *val)
{
memset(s->download_path, 0, sizeof(s->download_path));
if (val == NULL)
return;
int len = strlen(val);
if (len >= sizeof(s->download_path) - 2) /* leave room for null and '/' */
return;
FILE *fp = fopen(val, "r");
if (fp == NULL)
return;
strcpy(s->download_path, val);
if (val[len - 1] != '/')
strcat(s->download_path, "/");
}
static void set_default_settings(struct user_settings *s)
{
/* see settings_values enum in settings.h for defaults */
uset_autolog(s, "0");
uset_time(s, "24");
uset_alerts(s, "0");
uset_colours(s, "0");
uset_hst_size(s, "700");
uset_dwnld_path(s, NULL);
#ifdef _SUPPORT_AUDIO
uset_ain_dev(s, "0");
uset_aout_dev(s, "0");
#endif
}
int settings_load(struct user_settings *s, char *path)
{
char *user_config_dir = get_user_config_dir();
FILE *fp = NULL;
char dflt_path[MAX_STR_SIZE];
if (path) {
fp = fopen(path, "r");
} else {
@ -118,34 +185,37 @@ int settings_load(struct user_settings *s, char *path)
free(user_config_dir);
set_default_settings(s);
if (fp == NULL && !path) {
if ((fp = fopen(dflt_path, "w")) == NULL)
return -1;
} else if (fp == NULL && path) {
return -1;
}
char line[MAX_STR_SIZE];
while (fgets(line, sizeof(line), fp)) {
if (line[0] == '#' || !line[0])
continue;
const char *key = strtok(line, ":");
const char *val = strtok(NULL, ";");
if (key == NULL || val == NULL)
continue;
int i;
for (i = 0; i < NUM_SETTINGS; ++i) {
if (strcmp(user_settings_list[i].name, key) == 0) {
(user_settings_list[i].func)(s, atoi(val));
if (strcmp(user_settings_list[i].key, key) == 0) {
(user_settings_list[i].func)(s, val);
break;
}
}
}
}
fclose(fp);
return 0;
}

View File

@ -20,10 +20,15 @@
*
*/
#ifndef _settings_h
#define _settings_h
#include "toxic.h"
#ifdef _SUPPORT_AUDIO
#define NUM_SETTINGS 6
#define NUM_SETTINGS 8
#else
#define NUM_SETTINGS 4
#define NUM_SETTINGS 6
#endif /* _SUPPORT_AUDIO */
/* holds user setting values */
@ -32,11 +37,13 @@ struct user_settings {
int alerts; /* boolean */
int time; /* 12 or 24 */
int colour_theme; /* boolean (0 for default toxic colours) */
int history_size; /* int between MIN_HISTORY and MAX_HISTORY */
char download_path[MAX_STR_SIZE];
#ifdef _SUPPORT_AUDIO
int audio_in_dev;
int audio_out_dev;
#endif /* _SUPPORT_AUDIO */
long int audio_in_dev;
long int audio_out_dev;
#endif
};
enum {
@ -51,6 +58,10 @@ enum {
NATIVE_COLS = 1,
DFLT_COLS = 0,
};
DFLT_HST_SIZE = 700,
} settings_values;
int settings_load(struct user_settings *s, char *path);
#endif /* #define _settings_h */

View File

@ -39,31 +39,24 @@
#include <string.h>
#include <time.h>
#include <pthread.h>
#include <assert.h>
#ifdef _WIN32
#include <direct.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <getopt.h>
#include <netdb.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#endif
#include <tox/tox.h>
#include "configdir.h"
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "friendlist.h"
#include "prompt.h"
#include "misc_tools.h"
#include "file_senders.h"
#include "line_info.h"
#include "settings.h"
#include "global_commands.h"
#ifdef _SUPPORT_AUDIO
#include "audio_call.h"
@ -81,30 +74,64 @@ ToxAv *av;
char *DATA_FILE = NULL;
ToxWindow *prompt = NULL;
static int f_loadfromfile; /* 1 if we want to load from/save the data file, 0 otherwise */
struct arg_opts {
int ignore_data_file;
int use_ipv4;
char config_path[MAX_STR_SIZE];
char nodes_path[MAX_STR_SIZE];
} arg_opts;
struct _Winthread Winthread;
struct user_settings *user_settings = NULL;
void on_window_resize(int sig)
static void ignore_SIGINT(int sig)
{
refresh();
clear();
return;
}
void exit_toxic_success(Tox *m)
{
store_data(m, DATA_FILE);
close_all_file_senders();
kill_all_windows();
log_disable(prompt->chatwin->log);
line_info_cleanup(prompt->chatwin->hst);
free(DATA_FILE);
free(prompt->stb);
free(prompt->chatwin->log);
free(prompt->chatwin->hst);
free(prompt->chatwin);
free(user_settings);
#ifdef _SUPPORT_AUDIO
terminate_audio();
#endif /* _SUPPORT_AUDIO */
tox_kill(m);
endwin();
fprintf(stderr, "Toxic session ended gracefully.\n");
exit(EXIT_SUCCESS);
}
void exit_toxic_err(const char *errmsg, int errcode)
{
if (errmsg == NULL)
errmsg = "No error message";
endwin();
fprintf(stderr, "Toxic session aborted with error code %d (%s)\n", errcode, errmsg);
exit(EXIT_FAILURE);
}
static void init_term(void)
{
/* Setup terminal */
signal(SIGWINCH, on_window_resize);
#if HAVE_WIDECHAR
if (setlocale(LC_ALL, "") == NULL) {
fprintf(stderr, "Could not set your locale, plese check your locale settings or"
"disable wide char support\n");
exit(EXIT_FAILURE);
}
if (setlocale(LC_ALL, "") == NULL)
exit_toxic_err("Could not set your locale, please check your locale settings or"
"disable wide char support", FATALERR_LOCALE_SET);
#endif
initscr();
cbreak();
keypad(stdscr, 1);
@ -149,6 +176,9 @@ static Tox *init_tox(int ipv4)
m = tox_new(0);
}
if (ipv4)
fprintf(stderr, "Forcing IPv4 connection\n");
if (m == NULL)
return NULL;
@ -170,11 +200,9 @@ 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", strlen("Cool guy"));
tox_set_name(m, (uint8_t *) "Cool dude", strlen("Cool dude"));
#elif defined(__FreeBSD__)
tox_set_name(m, (uint8_t *) "Very cool guy", strlen("Very cool guy"));
#elif defined(_WIN32)
tox_set_name(m, (uint8_t *) "I should buy a Mac", strlen("I should install buy a Mac"));
tox_set_name(m, (uint8_t *) "Nerd", strlen("Nerd"));
#elif defined(__APPLE__)
tox_set_name(m, (uint8_t *) "Hipster", strlen("Hipster")); /* This used to users of other Unixes are hipsters */
#else
@ -189,10 +217,12 @@ static Tox *init_tox(int ipv4)
#define MAXNODES 50
#define NODELEN (MAXLINE - TOX_CLIENT_ID_SIZE - 7)
static int linecnt = 0;
static char nodes[MAXNODES][NODELEN];
static uint16_t ports[MAXNODES];
static uint8_t keys[MAXNODES][TOX_CLIENT_ID_SIZE];
static struct _toxNodes {
int lines;
char nodes[MAXNODES][NODELEN];
uint16_t ports[MAXNODES];
uint8_t keys[MAXNODES][TOX_CLIENT_ID_SIZE];
} toxNodes;
static int nodelist_load(char *filename)
{
@ -206,29 +236,29 @@ static int nodelist_load(char *filename)
char line[MAXLINE];
while (fgets(line, sizeof(line), fp) && linecnt < MAXNODES) {
while (fgets(line, sizeof(line), fp) && toxNodes.lines < MAXNODES) {
if (strlen(line) > MINLINE) {
char *name = strtok(line, " ");
char *port = strtok(NULL, " ");
char *key_ascii = strtok(NULL, " ");
const char *name = strtok(line, " ");
const char *port = strtok(NULL, " ");
const char *key_ascii = strtok(NULL, " ");
/* invalid line */
if (name == NULL || port == NULL || key_ascii == NULL)
continue;
strncpy(nodes[linecnt], name, NODELEN);
nodes[linecnt][NODELEN - 1] = 0;
ports[linecnt] = htons(atoi(port));
snprintf(toxNodes.nodes[toxNodes.lines], sizeof(toxNodes.nodes[toxNodes.lines]), "%s", name);
toxNodes.nodes[toxNodes.lines][NODELEN - 1] = 0;
toxNodes.ports[toxNodes.lines] = htons(atoi(port));
uint8_t *key_binary = hex_string_to_bin(key_ascii);
memcpy(keys[linecnt], key_binary, TOX_CLIENT_ID_SIZE);
memcpy(toxNodes.keys[toxNodes.lines], key_binary, TOX_CLIENT_ID_SIZE);
free(key_binary);
linecnt++;
toxNodes.lines++;
}
}
if (linecnt < 1) {
if (toxNodes.lines < 1) {
fclose(fp);
return 2;
}
@ -239,8 +269,8 @@ static int nodelist_load(char *filename)
int init_connection_helper(Tox *m, int line)
{
return tox_bootstrap_from_address(m, nodes[line], TOX_ENABLE_IPV6_DEFAULT,
ports[line], keys[line]);
return tox_bootstrap_from_address(m, toxNodes.nodes[line], TOX_ENABLE_IPV6_DEFAULT,
toxNodes.ports[line], toxNodes.keys[line]);
}
/* Connects to a random DHT node listed in the DHTnodes file
@ -257,8 +287,8 @@ static bool srvlist_loaded = false;
int init_connection(Tox *m)
{
if (linecnt > 0) /* already loaded nodelist */
return init_connection_helper(m, rand() % linecnt) ? 0 : 3;
if (toxNodes.lines > 0) /* already loaded nodelist */
return init_connection_helper(m, rand() % toxNodes.lines) ? 0 : 3;
/* only once:
* - load the nodelist
@ -266,17 +296,22 @@ int init_connection(Tox *m)
*/
if (!srvlist_loaded) {
srvlist_loaded = true;
int res = nodelist_load(PACKAGE_DATADIR "/DHTnodes");
int res;
if (linecnt < 1)
if (!arg_opts.nodes_path[0])
res = nodelist_load(PACKAGE_DATADIR "/DHTnodes");
else
res = nodelist_load(arg_opts.nodes_path);
if (toxNodes.lines < 1)
return res;
res = 3;
int i;
int n = MIN(NUM_INIT_NODES, linecnt);
int n = MIN(NUM_INIT_NODES, toxNodes.lines);
for (i = 0; i < n; ++i) {
if (init_connection_helper(m, rand() % linecnt))
if (init_connection_helper(m, rand() % toxNodes.lines))
res = 0;
}
@ -287,30 +322,37 @@ int init_connection(Tox *m)
return 4;
}
#define TRY_CONNECT 10
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;
static bool was_connected = false;
static uint64_t last_conn_try = 0;
uint64_t curtime = get_unix_time();
bool is_connected = tox_isconnected(m);
if (!dht_on && !is_connected && !(conn_try++ % 100)) {
if (!conn_err) {
if ((conn_err = init_connection(m))) {
snprintf(msg, sizeof(msg), "\nAuto-connect failed with error code %d", conn_err);
}
}
} else if (!dht_on && is_connected) {
dht_on = true;
prompt_update_connectionstatus(prompt, dht_on);
if (was_connected && is_connected)
return;
if (!was_connected && is_connected) {
was_connected = true;
prompt_update_connectionstatus(prompt, was_connected);
snprintf(msg, sizeof(msg), "DHT connected.");
} else if (dht_on && !is_connected) {
dht_on = false;
prompt_update_connectionstatus(prompt, dht_on);
snprintf(msg, sizeof(msg), "\nDHT disconnected. Attempting to reconnect.");
} else if (was_connected && !is_connected) {
was_connected = false;
prompt_update_connectionstatus(prompt, was_connected);
snprintf(msg, sizeof(msg), "DHT disconnected. Attempting to reconnect.");
} else if (!was_connected && !is_connected && timed_out(last_conn_try, curtime, TRY_CONNECT)) {
/* if autoconnect has already failed there's no point in trying again */
if (conn_err == 0) {
last_conn_try = curtime;
if ((conn_err = init_connection(m)) != 0)
snprintf(msg, sizeof(msg), "Auto-connect failed with error code %d", conn_err);
}
}
if (msg[0])
@ -336,7 +378,7 @@ static void load_friendlist(Tox *m)
*/
int store_data(Tox *m, char *path)
{
if (f_loadfromfile == 0) /*If file loading/saving is disabled*/
if (arg_opts.ignore_data_file)
return 0;
if (path == NULL)
@ -374,7 +416,7 @@ int store_data(Tox *m, char *path)
static void load_data(Tox *m, char *path)
{
if (f_loadfromfile == 0) /*If file loading/saving is disabled*/
if (arg_opts.ignore_data_file)
return;
FILE *fd;
@ -390,17 +432,13 @@ static void load_data(Tox *m, char *path)
if (buf == NULL) {
fclose(fd);
endwin();
fprintf(stderr, "malloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
exit_toxic_err("failed in load_data", FATALERR_MEMORY);
}
if (fread(buf, len, 1, fd) != 1) {
free(buf);
fclose(fd);
endwin();
fprintf(stderr, "fread() failed. Aborting...\n");
exit(EXIT_FAILURE);
exit_toxic_err("failed in load_data", FATALERR_FREAD);
}
tox_load(m, buf, len);
@ -411,44 +449,18 @@ static void load_data(Tox *m, char *path)
} else {
int st;
if ((st = store_data(m, path)) != 0) {
endwin();
fprintf(stderr, "Store messenger failed with return code: %d\n", st);
exit(EXIT_FAILURE);
}
if ((st = store_data(m, path)) != 0)
exit_toxic_err("failed in load_data", FATALERR_STORE_DATA);
}
}
void exit_toxic(Tox *m)
{
store_data(m, DATA_FILE);
close_all_file_senders();
kill_all_windows();
log_disable(prompt->chatwin->log);
line_info_cleanup(prompt->chatwin->hst);
free(DATA_FILE);
free(prompt->stb);
free(prompt->chatwin->log);
free(prompt->chatwin->hst);
free(prompt->chatwin);
free(user_settings);
tox_kill(m);
#ifdef _SUPPORT_AUDIO
terminate_audio();
#endif /* _SUPPORT_AUDIO */
endwin();
exit(EXIT_SUCCESS);
}
static void do_toxic(Tox *m, ToxWindow *prompt)
{
pthread_mutex_lock(&Winthread.lock);
do_connection(m, prompt);
do_file_senders(m);
/* main tox-core loop */
tox_do(m);
tox_do(m); /* main tox-core loop */
pthread_mutex_unlock(&Winthread.lock);
}
@ -457,72 +469,86 @@ void *thread_winref(void *data)
{
Tox *m = (Tox *) data;
while (true)
while (true) {
draw_active_window(m);
refresh_inactive_windows();
}
}
int exit_print(char* exe_name, char* invalid_arg, char* error_str)
static void print_usage(void)
{
const char* help_str =
"usage: \n"
" -f <path> tox protocol data file path \n"
" -s <path> custom settings path \n"
" -n don't load from data file (create new profile) \n"
" -h print this help \n"
" -4 force ipv4 \n";
if (!error_str && !invalid_arg) {
printf("%s %s", exe_name, help_str);
return 0;
} else if (invalid_arg) {
fprintf(stderr, "%s invalid arg: %s", exe_name, invalid_arg);
return 1;
} else if (error_str) {
fprintf(stderr, "%s error: %s", exe_name, error_str);
return 1;
fprintf(stderr, "usage: toxic [OPTION] [FILE ...]\n");
fprintf(stderr, " -f, --file Use specified data file\n");
fprintf(stderr, " -x, --nodata Ignore data file\n");
fprintf(stderr, " -4, --ipv4 Force IPv4 connection\n");
fprintf(stderr, " -c, --config Use specified config file\n");
fprintf(stderr, " -n, --nodes Use specified DHTnodes file\n");
fprintf(stderr, " -h, --help Show this message and exit\n");
}
static void set_default_opts(void)
{
arg_opts.use_ipv4 = 0;
arg_opts.ignore_data_file = 0;
}
static void parse_args(int argc, char *argv[])
{
set_default_opts();
static struct option long_opts[] = {
{"file", required_argument, 0, 'f'},
{"nodata", no_argument, 0, 'x'},
{"ipv4", no_argument, 0, '4'},
{"config", required_argument, 0, 'c'},
{"nodes", required_argument, 0, 'n'},
{"help", no_argument, 0, 'h'},
};
const char *opts_str = "4xf:c:n:h";
int opt, indexptr;
while ((opt = getopt_long(argc, argv, opts_str, long_opts, &indexptr)) != -1) {
switch (opt) {
case 'f':
DATA_FILE = strdup(optarg);
break;
case 'x':
arg_opts.ignore_data_file = 1;
break;
case '4':
arg_opts.use_ipv4 = 1;
break;
case 'c':
snprintf(arg_opts.config_path, sizeof(arg_opts.config_path), "%s", optarg);
break;
case 'n':
snprintf(arg_opts.nodes_path, sizeof(arg_opts.nodes_path), "%s", optarg);
break;
case 'h':
default:
print_usage();
exit(EXIT_SUCCESS);
}
}
}
int main(int argc, char *argv[])
{
char *user_config_dir = get_user_config_dir(), *settings_path = NULL;
char *user_config_dir = get_user_config_dir();
int config_err = 0;
f_loadfromfile = 1;
int i = 0;
int f_use_ipv4 = 0;
parse_args(argc, argv);
/* Make sure all written files are read/writeable only by the current user. */
umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
for (i = 1; i < argc; ++i) {
if (argv[i][0] == '-') {
if (argv[i][1] == 'f') {
++i;
if (i < argc)
DATA_FILE = strdup(argv[i]);
else
return exit_print(argv[0], NULL, "argument 'f' requires value");
} else if (argv[i][1] == 'n') {
f_loadfromfile = 0;
} else if (argv[i][1] == 'h') {
return exit_print(argv[0], NULL, NULL);
} else if (argv[i][1] == '4') {
f_use_ipv4 = 1;
} else if (argv[i][1] == 's') {
++i;
if (i < argc)
settings_path = argv[i];
else
return exit_print(argv[0], NULL, "argument 's' requires value");
} else {
return exit_print(argv[0], argv[i]+1, NULL); /* Invalid arg */
}
} else {
return exit_print(argv[0], argv[i], NULL); /* Invalid value/arg */
}
}
signal(SIGINT, ignore_SIGINT);
config_err = create_user_config_dir(user_config_dir);
@ -532,15 +558,12 @@ int main(int argc, char *argv[])
} else {
DATA_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen("data") + 1);
if (DATA_FILE != NULL) {
strcpy(DATA_FILE, user_config_dir);
strcat(DATA_FILE, CONFIGDIR);
strcat(DATA_FILE, "data");
} else {
endwin();
fprintf(stderr, "malloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
if (DATA_FILE == NULL)
exit_toxic_err("failed in main", FATALERR_MEMORY);
strcpy(DATA_FILE, user_config_dir);
strcat(DATA_FILE, CONFIGDIR);
strcat(DATA_FILE, "data");
}
}
@ -549,41 +572,32 @@ int main(int argc, char *argv[])
/* init user_settings struct and load settings from conf file */
user_settings = malloc(sizeof(struct user_settings));
if (user_settings == NULL) {
endwin();
fprintf(stderr, "malloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
if (user_settings == NULL)
exit_toxic_err("failed in main", FATALERR_MEMORY);
memset(user_settings, 0, sizeof(struct user_settings));
int settings_err = settings_load(user_settings, settings_path);
Tox *m = init_tox(f_use_ipv4);
char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL;
int settings_err = settings_load(user_settings, p);
Tox *m = init_tox(arg_opts.use_ipv4);
init_term();
if (m == NULL) {
endwin();
fprintf(stderr, "Failed to initialize network. Aborting...\n");
exit(EXIT_FAILURE);
}
if (m == NULL)
exit_toxic_err("failed in main", FATALERR_NETWORKINIT);
if (f_loadfromfile)
if (!arg_opts.ignore_data_file)
load_data(m, DATA_FILE);
prompt = init_windows(m);
/* create new thread for ncurses stuff */
if (pthread_mutex_init(&Winthread.lock, NULL) != 0) {
endwin();
fprintf(stderr, "Mutex init failed. Aborting...\n");
exit(EXIT_FAILURE);
}
if (pthread_mutex_init(&Winthread.lock, NULL) != 0)
exit_toxic_err("failed in main", FATALERR_MUTEX_INIT);
if (pthread_create(&Winthread.tid, NULL, thread_winref, (void *) m) != 0) {
endwin();
fprintf(stderr, "Thread creation failed. Aborting...\n");
exit(EXIT_FAILURE);
}
if (pthread_create(&Winthread.tid, NULL, thread_winref, (void *) m) != 0)
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
uint8_t *msg;
@ -591,18 +605,10 @@ int main(int argc, char *argv[])
av = init_audio(prompt, m);
// device_set(prompt, input, user_settings->audio_in_dev);
// device_set(prompt, output, user_settings->audio_out_dev);
set_primary_device(input, user_settings->audio_in_dev);
set_primary_device(output, user_settings->audio_out_dev);
char* string = malloc(1000);
sprintf(string, "i:%d o:%d", user_settings->audio_in_dev, user_settings->audio_out_dev);
line_info_add(prompt, NULL, NULL, NULL, string, SYS_MSG, 0, 0);
cmd_myid(NULL, prompt, m, 0, NULL);
#endif /* _SUPPORT_AUDIO */
if (config_err) {

100
src/toxic.h Normal file
View File

@ -0,0 +1,100 @@
/* toxic.h
*
*
* Copyright (C) 2014 Toxic All Rights Reserved.
*
* This file is part of Toxic.
*
* Toxic is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Toxic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef _toxic_h
#define _toxic_h
#ifndef TOXICVER
#define TOXICVER "NOVER_" /* Use the -D flag to set this */
#endif
#include <stdbool.h>
#include <curses.h>
#include <tox/tox.h>
#define UNKNOWN_NAME "Anonymous"
#define MAX_FRIENDS_NUM 500
#define MAX_STR_SIZE 1024
#define MAX_CMDNAME_SIZE 64
#define TOXIC_MAX_NAME_LENGTH 32 /* Must be <= TOX_MAX_NAME_LENGTH */
#define KEY_IDENT_DIGITS 2 /* number of hex digits to display for the pub-key based identifier */
#define TIME_STR_SIZE 16
/* ASCII key codes */
#define T_KEY_KILL 0x0B /* ctrl-k */
#define T_KEY_DISCARD 0x15 /* ctrl-u */
#define T_KEY_NEXT 0x10 /* ctrl-p */
#define T_KEY_PREV 0x0F /* ctrl-o */
#define T_KEY_C_E 0x05 /* ctrl-e */
#define T_KEY_C_A 0x01 /* ctrl-a */
#define T_KEY_C_RB 0x1D /* ctrl-] */
#define T_KEY_C_LB 0x1B /* ctrl-[ */
#define T_KEY_C_V 0x16 /* ctrl-v */
#define T_KEY_C_F 0x06 /* ctrl-f */
#define T_KEY_C_H 0x08 /* ctrl-h */
enum {
MOVE_UP,
MOVE_DOWN,
} KEY_DIRS;
typedef enum _FATAL_ERRS {
FATALERR_MEMORY = -1, /* malloc() or calloc() failed */
FATALERR_FREAD = -2, /* fread() failed on critical read */
FATALERR_THREAD_CREATE = -3,
FATALERR_MUTEX_INIT = -4,
FATALERR_LOCALE_SET = -5,
FATALERR_STORE_DATA = -6,
FATALERR_NETWORKINIT = -7, /* Tox network failed to init */
FATALERR_INFLOOP = -8, /* infinite loop detected */
FATALERR_WININIT = -9, /* window init failed */
} FATAL_ERRS;
/* Fixes text color problem on some terminals.
Uncomment if necessary */
/* #define URXVT_FIX */
void exit_toxic_success(Tox *m);
void exit_toxic_err(const char *errmsg, int errcode);
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata);
void on_connectionchange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata);
void on_message(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_action(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_nickchange(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_statuschange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata);
void on_statusmessagechange(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_friendadded(Tox *m, int32_t friendnumber, bool sort);
void on_groupmessage(Tox *m, int groupnumber, int peernumber, uint8_t *message, uint16_t length, void *userdata);
void on_groupaction(Tox *m, int groupnumber, int peernumber, uint8_t *action, uint16_t length, void *userdata);
void on_groupinvite(Tox *m, int32_t friendnumber, uint8_t *group_pub_key, void *userdata);
void on_group_namelistchange(Tox *m, int groupnumber, int peernumber, uint8_t change, void *userdata);
void on_file_sendrequest(Tox *m, int32_t friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *pathname,
uint16_t pathname_length, void *userdata);
void on_file_control(Tox *m, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber, uint8_t control_type,
uint8_t *data, uint16_t length, void *userdata);
void on_file_data(Tox *m, int32_t friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata);
void on_typing_change(Tox *m, int32_t friendnumber, uint8_t is_typing, void *userdata);
#endif /* #define _toxic_h */

View File

@ -27,160 +27,181 @@
#include <stdlib.h>
#include <string.h>
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "misc_tools.h"
#include "toxic_strings.h"
/* Adds char to buffer at pos */
void add_char_to_buf(wchar_t *buf, size_t *pos, size_t *len, wint_t ch)
/* Adds char to line at pos */
void add_char_to_buf(ChatContext *ctx, wint_t ch)
{
if (*pos < 0 || *len >= MAX_STR_SIZE)
if (ctx->pos < 0 || ctx->len >= MAX_STR_SIZE)
return;
/* move all chars including null in front of pos one space forward and insert char in pos */
int i;
for (i = *len; i >= *pos && i >= 0; --i)
buf[i + 1] = buf[i];
for (i = ctx->len; i >= ctx->pos && i >= 0; --i)
ctx->line[i + 1] = ctx->line[i];
buf[(*pos)++] = ch;
++(*len);
ctx->line[ctx->pos++] = ch;
++ctx->len;
}
/* Deletes the character before pos */
void del_char_buf_bck(wchar_t *buf, size_t *pos, size_t *len)
void del_char_buf_bck(ChatContext *ctx)
{
if (*pos <= 0)
if (ctx->pos <= 0)
return;
int i;
/* similar to add_char_to_buf but deletes a char */
for (i = *pos - 1; i <= *len; ++i)
buf[i] = buf[i + 1];
for (i = ctx->pos - 1; i <= ctx->len; ++i)
ctx->line[i] = ctx->line[i + 1];
--(*pos);
--(*len);
--ctx->pos;
--ctx->len;
}
/* Deletes the character at pos */
void del_char_buf_frnt(wchar_t *buf, size_t *pos, size_t *len)
void del_char_buf_frnt(ChatContext *ctx)
{
if (*pos < 0 || *pos >= *len)
if (ctx->pos < 0 || ctx->pos >= ctx->len)
return;
int i;
for (i = *pos; i < *len; ++i)
buf[i] = buf[i + 1];
for (i = ctx->pos; i < ctx->len; ++i)
ctx->line[i] = ctx->line[i + 1];
--(*len);
--ctx->len;
}
/* Deletes the line from beginning to pos */
void discard_buf(wchar_t *buf, size_t *pos, size_t *len)
void discard_buf(ChatContext *ctx)
{
if (*pos <= 0)
if (ctx->pos <= 0)
return;
int i;
int c = 0;
for (i = *pos; i <= *len; ++i)
buf[c++] = buf[i];
for (i = ctx->pos; i <= ctx->len; ++i)
ctx->line[c++] = ctx->line[i];
*pos = 0;
*len = c - 1;
ctx->pos = 0;
ctx->start = 0;
ctx->len = c - 1;
}
/* Deletes the line from pos to len */
void kill_buf(wchar_t *buf, size_t *pos, size_t *len)
void kill_buf(ChatContext *ctx)
{
if (*len == *pos)
if (ctx->len == ctx->pos)
return;
buf[*pos] = L'\0';
*len = *pos;
ctx->line[ctx->pos] = L'\0';
ctx->len = ctx->pos;
}
/* nulls buf and sets pos and len to 0 */
void reset_buf(wchar_t *buf, size_t *pos, size_t *len)
/* nulls line and sets pos, len and start to 0 */
void reset_buf(ChatContext *ctx)
{
buf[0] = L'\0';
*pos = 0;
*len = 0;
ctx->line[0] = L'\0';
ctx->pos = 0;
ctx->len = 0;
ctx->start = 0;
}
/* Removes trailing spaces from line. */
void rm_trailing_spaces_buf(ChatContext *ctx)
{
if (ctx->len <= 0)
return;
if (ctx->line[ctx->len - 1] != ' ')
return;
int i;
for (i = ctx->len - 1; i >= 0; --i) {
if (ctx->line[i] != ' ')
break;
}
ctx->len = i + 1;
ctx->pos = MIN(ctx->pos, ctx->len);
ctx->line[ctx->len] = L'\0';
}
#define HIST_PURGE MAX_LINE_HIST / 4
/* shifts hist items back and makes room for HIST_PURGE new entries */
static void shift_hist_back(wchar_t (*hst)[MAX_STR_SIZE], int *hst_tot)
static void shift_hist_back(ChatContext *ctx)
{
int i;
int n = MAX_LINE_HIST - HIST_PURGE;
for (i = 0; i < n; ++i)
wmemcpy(hst[i], hst[i + HIST_PURGE], MAX_STR_SIZE);
wmemcpy(ctx->ln_history[i], ctx->ln_history[i + HIST_PURGE], MAX_STR_SIZE);
*hst_tot = n;
ctx->hst_tot = n;
}
/* adds a line to the ln_history buffer at hst_pos and sets hst_pos to end of history. */
void add_line_to_hist(const wchar_t *buf, size_t len, wchar_t (*hst)[MAX_STR_SIZE], int *hst_tot,
int *hst_pos)
void add_line_to_hist(ChatContext *ctx)
{
if (len > MAX_STR_SIZE)
if (ctx->len > MAX_STR_SIZE)
return;
if (*hst_tot >= MAX_LINE_HIST)
shift_hist_back(hst, hst_tot);
if (ctx->hst_tot >= MAX_LINE_HIST)
shift_hist_back(ctx);
++(*hst_tot);
*hst_pos = *hst_tot;
++ctx->hst_tot;
ctx->hst_pos = ctx->hst_tot;
wmemcpy(hst[*hst_tot - 1], buf, len + 1);
wmemcpy(ctx->ln_history[ctx->hst_tot - 1], ctx->line, ctx->len + 1);
}
/* copies history item at hst_pos to buf. Sets pos and len to the len of the history item.
/* copies history item at hst_pos to line. Sets pos and len to the len of the history item.
hst_pos is decremented or incremented depending on key_dir.
resets buffer if at end of history */
void fetch_hist_item(wchar_t *buf, size_t *pos, size_t *len, wchar_t (*hst)[MAX_STR_SIZE],
int hst_tot, int *hst_pos, int key_dir)
resets line if at end of history */
void fetch_hist_item(ChatContext *ctx, int key_dir)
{
if (key_dir == MOVE_UP) {
if (--(*hst_pos) < 0) {
*hst_pos = 0;
if (--ctx->hst_pos < 0) {
ctx->hst_pos = 0;
beep();
}
} else {
if (++(*hst_pos) >= hst_tot) {
*hst_pos = hst_tot;
reset_buf(buf, pos, len);
if (++ctx->hst_pos >= ctx->hst_tot) {
ctx->hst_pos = ctx->hst_tot;
reset_buf(ctx);
return;
}
}
const wchar_t *hst_line = hst[*hst_pos];
const wchar_t *hst_line = ctx->ln_history[ctx->hst_pos];
size_t h_len = wcslen(hst_line);
wmemcpy(buf, hst_line, h_len + 1);
*pos = h_len;
*len = h_len;
wmemcpy(ctx->line, hst_line, h_len + 1);
ctx->pos = h_len;
ctx->len = h_len;
}
/* looks for the first instance in list that begins with the last entered word in buf according to pos,
then fills buf with the complete word. e.g. "Hello jo" would complete the buffer
/* looks for the first instance in list that begins with the last entered word in line according to pos,
then fills line with the complete word. e.g. "Hello jo" would complete the line
with "Hello john".
list is a pointer to the list of strings being compared, n_items is the number of items
in the list, and size is the size of each item in the list.
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)
Returns the difference between the old len and new len of line on success, -1 if error */
int complete_line(ChatContext *ctx, const void *list, int n_items, int size)
{
if (*pos <= 0 || *len <= 0 || *len >= MAX_STR_SIZE)
if (ctx->pos <= 0 || ctx->len <= 0 || ctx->len >= MAX_STR_SIZE)
return -1;
const uint8_t *L = (uint8_t *) list;
@ -188,13 +209,13 @@ int complete_line(wchar_t *buf, size_t *pos, size_t *len, const void *list, int
uint8_t ubuf[MAX_STR_SIZE];
/* work with multibyte string copy of buf for simplicity */
if (wcs_to_mbs_buf(ubuf, buf, MAX_STR_SIZE) == -1)
if (wcs_to_mbs_buf(ubuf, ctx->line, MAX_STR_SIZE) == -1)
return -1;
/* isolate substring from space behind pos to pos */
uint8_t tmp[MAX_STR_SIZE];
snprintf(tmp, sizeof(tmp), "%s", ubuf);
tmp[*pos] = '\0';
tmp[ctx->pos] = '\0';
uint8_t *sub = strrchr(tmp, ' ');
int n_endchrs = 1; /* 1 = append space to end of match, 2 = append ": " */
@ -227,14 +248,14 @@ int complete_line(wchar_t *buf, size_t *pos, size_t *len, const void *list, int
/* put match in correct spot in buf and append endchars (space or ": ") */
const uint8_t *endchrs = n_endchrs == 1 ? " " : ": ";
int m_len = strlen(match);
int strt = (int) * pos - s_len;
int strt = ctx->pos - s_len;
int diff = m_len - s_len + n_endchrs;
if (*len + diff > MAX_STR_SIZE)
if (ctx->len + diff > MAX_STR_SIZE)
return -1;
uint8_t tmpend[MAX_STR_SIZE];
strcpy(tmpend, &ubuf[*pos]);
strcpy(tmpend, &ubuf[ctx->pos]);
strcpy(&ubuf[strt], match);
strcpy(&ubuf[strt + m_len], endchrs);
strcpy(&ubuf[strt + m_len + n_endchrs], tmpend);
@ -245,10 +266,10 @@ int complete_line(wchar_t *buf, size_t *pos, size_t *len, const void *list, int
if (mbs_to_wcs_buf(newbuf, ubuf, MAX_STR_SIZE) == -1)
return -1;
wcscpy(buf, newbuf);
wcscpy(ctx->line, newbuf);
*len += (size_t) diff;
*pos += (size_t) diff;
ctx->len += (size_t) diff;
ctx->pos += (size_t) diff;
return diff;
}

View File

@ -20,39 +20,49 @@
*
*/
/* Adds char to buffer at pos */
void add_char_to_buf(wchar_t *buf, size_t *pos, size_t *len, wint_t ch);
#ifndef _toxic_strings_h
#define _toxic_strings_h
#include "windows.h"
/* Adds char to line at pos */
void add_char_to_buf(ChatContext *ctx, wint_t ch);
/* Deletes the character before pos */
void del_char_buf_bck(wchar_t *buf, size_t *pos, size_t *len);
void del_char_buf_bck(ChatContext *ctx);
/* Deletes the character at pos */
void del_char_buf_frnt(wchar_t *buf, size_t *pos, size_t *len);
void del_char_buf_frnt(ChatContext *ctx);
/* Deletes the line from beginning to pos */
void discard_buf(wchar_t *buf, size_t *pos, size_t *len);
void discard_buf(ChatContext *ctx);
/* Deletes the line from pos to len */
void kill_buf(wchar_t *buf, size_t *pos, size_t *len);
void kill_buf(ChatContext *ctx);
/* nulls buf and sets pos and len to 0 */
void reset_buf(wchar_t *buf, size_t *pos, size_t *len);
/* nulls line and sets pos, len and start to 0 */
void reset_buf(ChatContext *ctx);
/* looks for the first instance in list that begins with the last entered word in buf according to pos,
then fills buf with the complete word. e.g. "Hello jo" would complete the buffer
/* Removes trailing spaces from line. */
void rm_trailing_spaces_buf(ChatContext *ctx);
/* looks for the first instance in list that begins with the last entered word in line according to pos,
then fills line with the complete word. e.g. "Hello jo" would complete the line
with "Hello john".
list is a pointer to the list of strings being compared, n_items is the number of items
in the list, and size is the size of each item in the list.
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);
Returns the difference between the old len and new len of line on success, -1 if error */
int complete_line(ChatContext *ctx, const void *list, int n_items, int size);
/* 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);
void add_line_to_hist(ChatContext *ctx);
/* copies history item at hst_pos to buf. Sets pos and len to the len of the history item.
hst_pos is decremented or incremented depending on key_dir. */
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);
/* copies history item at hst_pos to line. Sets pos and len to the len of the history item.
hst_pos is decremented or incremented depending on key_dir.
resets line if at end of history */
void fetch_hist_item(ChatContext *ctx, int key_dir);
#endif /* #define _toxic_strings_h */

View File

@ -30,7 +30,8 @@
#include "friendlist.h"
#include "prompt.h"
#include "toxic_windows.h"
#include "toxic.h"
#include "windows.h"
#include "groupchat.h"
extern char *DATA_FILE;
@ -43,7 +44,7 @@ extern ToxWindow *prompt;
static int num_active_windows;
/* CALLBACKS START */
void on_request(Tox *m, uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata)
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata)
{
int i;
@ -283,11 +284,8 @@ void set_next_window(int ch)
if (active_window->window)
return;
if (active_window == inf) { /* infinite loop check */
endwin();
fprintf(stderr, "set_next_window() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
if (active_window == inf) /* infinite loop check */
exit_toxic_err("failed in set_next_window", FATALERR_INFLOOP);
}
}
@ -303,11 +301,8 @@ ToxWindow *init_windows(Tox *m)
{
int n_prompt = add_window(m, new_prompt());
if (n_prompt == -1 || add_window(m, new_friendlist()) == -1) {
endwin();
fprintf(stderr, "add_window() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
if (n_prompt == -1 || add_window(m, new_friendlist()) == -1)
exit_toxic_err("failed in init_windows", FATALERR_WININIT);
prompt = &windows[n_prompt];
active_window = prompt;
@ -315,6 +310,12 @@ ToxWindow *init_windows(Tox *m)
return prompt;
}
void on_window_resize(int sig)
{
refresh();
clear();
}
static void draw_window_tab(ToxWindow toxwin)
{
/* alert0 takes priority */
@ -351,25 +352,28 @@ static void draw_bar(void)
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].active) {
if (windows + i == active_window) {
#ifdef URXVT_FIX
attron(A_BOLD | COLOR_PAIR(GREEN));
} else {
#endif
attron(A_BOLD);
}
if (!windows[i].active)
continue;
draw_window_tab(windows[i]);
if (windows + i == active_window)
if (windows + i == active_window) {
#ifdef URXVT_FIX
attroff(A_BOLD | COLOR_PAIR(GREEN));
} else {
attron(A_BOLD | COLOR_PAIR(GREEN));
else
#endif
attroff(A_BOLD);
}
}
attron(A_BOLD);
draw_window_tab(windows[i]);
if (windows + i == active_window)
#ifdef URXVT_FIX
attroff(A_BOLD | COLOR_PAIR(GREEN));
else
#endif
attroff(A_BOLD);
}
refresh();
@ -417,7 +421,7 @@ void draw_active_window(Tox *m)
ltr = isprint(ch);
#endif
if (!ltr && (ch == T_KEY_NEXT || ch == T_KEY_PREV) ) {
if (!ltr && (ch == T_KEY_NEXT || ch == T_KEY_PREV)) {
set_next_window((int) ch);
} else {
pthread_mutex_lock(&Winthread.lock);
@ -426,6 +430,20 @@ void draw_active_window(Tox *m)
}
}
/* refresh inactive windows to prevent scrolling bugs.
call at least once per second */
void refresh_inactive_windows(void)
{
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
ToxWindow *a = &windows[i];
if (a->active && a != active_window && (a->is_chat || a->is_groupchat))
line_info_print(a);
}
}
int get_num_active_windows(void)
{
return num_active_windows;

View File

@ -1,4 +1,4 @@
/* toxic_windows.h
/* windows.h
*
*
* Copyright (C) 2014 Toxic All Rights Reserved.
@ -23,11 +23,6 @@
#ifndef _windows_h
#define _windows_h
#ifndef TOXICVER
#define TOXICVER "NOVER_" /* Use the -D flag to set this */
#endif
#include <curses.h>
#include <pthread.h>
#include <wctype.h>
#include <wchar.h>
@ -38,31 +33,11 @@
#include <tox/toxav.h>
#endif /* _SUPPORT_AUDIO */
#define UNKNOWN_NAME "Anonymous"
#include "toxic.h"
#define MAX_WINDOWS_NUM 32
#define MAX_FRIENDS_NUM 100
#define MAX_STR_SIZE 256
#define MAX_CMDNAME_SIZE 64
#define KEY_SIZE_BYTES 32
#define TOXIC_MAX_NAME_LENGTH 32 /* Must be <= TOX_MAX_NAME_LENGTH */
#define N_DEFAULT_WINS 2 /* number of permanent default windows */
#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
/* ASCII key codes */
#define T_KEY_KILL 0xB /* ctrl-k */
#define T_KEY_DISCARD 0x15 /* ctrl-u */
#define T_KEY_NEXT 0x10 /* ctrl-p */
#define T_KEY_PREV 0x0F /* ctrl-o */
#define T_KEY_C_E 0x05 /* ctrl-e */
#define T_KEY_C_A 0x01 /* ctrl-a */
#define T_KEY_ESC 0x1B /* ESC key */
#define CURS_Y_OFFSET 1 /* y-axis cursor offset for chat contexts */
#define CHATBOX_HEIGHT 2
/* Curses foreground colours (background is black) */
enum {
@ -74,24 +49,24 @@ enum {
YELLOW,
MAGENTA,
BLACK,
};
} C_COLOURS;
/* tab alert types: lower types take priority */
enum {
WINDOW_ALERT_0,
WINDOW_ALERT_1,
WINDOW_ALERT_2,
};
enum {
MOVE_UP,
MOVE_DOWN,
};
} WINDOW_ALERTS;
/* Fixes text color problem on some terminals.
Uncomment if necessary */
/* #define URXVT_FIX */
struct _Winthread {
pthread_t tid;
pthread_mutex_t lock;
};
typedef struct ToxWindow ToxWindow;
typedef struct StatusBar StatusBar;
typedef struct PromptBuf PromptBuf;
@ -101,7 +76,7 @@ struct ToxWindow {
void(*onKey)(ToxWindow *, Tox *, wint_t, bool);
void(*onDraw)(ToxWindow *, Tox *);
void(*onInit)(ToxWindow *, Tox *);
void(*onFriendRequest)(ToxWindow *, Tox *, uint8_t *, uint8_t *, uint16_t);
void(*onFriendRequest)(ToxWindow *, Tox *, const uint8_t *, const 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);
@ -176,6 +151,7 @@ struct ChatContext {
wchar_t line[MAX_STR_SIZE];
size_t pos;
size_t len;
size_t start; /* the position to start printing line at */
wchar_t ln_history[MAX_LINE_HIST][MAX_STR_SIZE]; /* history for input lines/commands */
int hst_pos;
@ -195,67 +171,13 @@ struct ChatContext {
int orig_y; /* y axis point of line origin */
};
/* Start file transfer code */
#define MAX_FILES 256
#define FILE_PIECE_SIZE 1024
#define TIMEOUT_FILESENDER 300
typedef struct {
FILE *file;
ToxWindow *toxwin;
int32_t friendnum;
bool active;
int filenum;
uint8_t nextpiece[FILE_PIECE_SIZE];
uint16_t piecelen;
uint8_t pathname[MAX_STR_SIZE];
uint64_t timestamp;
uint64_t size;
uint32_t line_id;
} FileSender;
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 */
struct _Winthread {
pthread_t tid;
pthread_mutex_t lock;
};
void on_request(Tox *m, uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata);
void on_connectionchange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata);
void on_message(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_action(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_nickchange(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_statuschange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata);
void on_statusmessagechange(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_friendadded(Tox *m, int32_t friendnumber, bool sort);
void on_groupmessage(Tox *m, int groupnumber, int peernumber, uint8_t *message, uint16_t length, void *userdata);
void on_groupaction(Tox *m, int groupnumber, int peernumber, uint8_t *action, uint16_t length, void *userdata);
void on_groupinvite(Tox *m, int32_t friendnumber, uint8_t *group_pub_key, void *userdata);
void on_group_namelistchange(Tox *m, int groupnumber, int peernumber, uint8_t change, void *userdata);
void on_file_sendrequest(Tox *m, int32_t friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *pathname,
uint16_t pathname_length, void *userdata);
void on_file_control(Tox *m, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber, uint8_t control_type,
uint8_t *data, uint16_t length, void *userdata);
void on_file_data(Tox *m, int32_t friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata);
void on_typing_change(Tox *m, int32_t friendnumber, uint8_t is_typing, void *userdata);
ToxWindow *init_windows(Tox *m);
void draw_active_window(Tox *m);
int add_window(Tox *m, ToxWindow w);
void del_window(ToxWindow *w);
void set_active_window(int ch);
int get_num_active_windows(void);
void kill_all_windows(void); /* should only be called on shutdown */
void on_window_resize(int sig);
/* cleans up all chat and groupchat windows (should only be called on shutdown) */
void kill_all_windows(void);
#endif
#endif /* #define _windows_h */