mirror of
https://github.com/Tha14/toxic.git
synced 2024-11-13 01:03:03 +01:00
Added VAD, changed device i/o, mute option, dynamic device changing and more
This commit is contained in:
parent
e06f0ffb7e
commit
e47f2c05f3
@ -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)
|
||||
|
82
configure.ac
82
configure.ac
@ -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])
|
||||
|
115
src/audio_call.c
115
src/audio_call.c
@ -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);
|
||||
}
|
@ -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);
|
||||
|
222
src/chat.c
222
src/chat.c
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 */
|
||||
|
67
src/device.c
67
src/device.c
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
305
src/dns.c
Normal 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
32
src/dns.h
Normal 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 */
|
@ -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 */
|
||||
};
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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) {
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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.";
|
||||
|
@ -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 */
|
||||
|
173
src/groupchat.c
173
src/groupchat.c
@ -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;
|
||||
|
@ -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 */
|
||||
|
221
src/line_info.c
221
src/line_info.c
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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"
|
||||
|
@ -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 */
|
||||
|
@ -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]);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
82
src/prompt.c
82
src/prompt.c
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
146
src/settings.c
146
src/settings.c
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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
100
src/toxic.h
Normal 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 */
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
Loading…
Reference in New Issue
Block a user