1
0
mirror of https://github.com/Tha14/toxic.git synced 2025-06-27 02:06:45 +02:00

Compare commits

...

29 Commits

Author SHA1 Message Date
8660047ec1 fix small bug, update readme, bump version 2014-07-23 15:15:14 -04:00
9476db02a9 allow disabling of individual sounds 2014-07-23 14:59:36 -04:00
04fbf5f724 Merge pull request #195 from Ansa89/notify-fix
Add hardcoded path for sound notifications
2014-07-23 11:56:20 +02:00
3cc629cbc1 Add hardcoded path for sound notifications 2014-07-23 11:25:38 +02:00
50fca4cddf Merge pull request #193 from Ansa89/makefile-fix
Makefile: little refactoring
2014-07-23 03:51:52 +02:00
a047cead05 fix a few notification issues 2014-07-22 14:38:32 -04:00
1131b73299 Update toxic.conf.5 manpage 2014-07-22 16:38:20 +02:00
196af10d01 Move init and exit in right place 2014-07-22 12:30:35 +02:00
1e0e93e5c6 Makefile: little refactoring 2014-07-22 09:59:44 +02:00
ac01d6d316 fix config file loading, fix makefile compile errors 2014-07-21 18:57:16 -04:00
654e404e0e Merge pull request #190 from mannol1/master
Fixed some build errors
2014-07-21 23:49:08 +02:00
f0f1138c54 Fixed some build errors 2014-07-21 23:48:39 +02:00
bc94e08970 sendfile tab-complete for ~/ shortcut 2014-07-21 15:11:30 -04:00
42c3ede963 Merge pull request #188 from Ansa89/makefile-fix
Makefile fix
2014-07-21 13:02:25 -04:00
174568d769 README.md: add dependencies for sound notifications 2014-07-21 14:19:01 +02:00
4587d8ebbd Forgot libalut-dev dependency 2014-07-21 12:50:29 +02:00
98aae242fb Makefile fix 2014-07-21 12:33:19 +02:00
7abd8d5ee5 Merge pull request #187 from mannol1/master
Added sound notifications, libconfig support, and more...
2014-07-21 12:08:19 +02:00
98ac4d7983 Added sound notifications and prepared for later system notifications. Also, now using libconfig for configuration loading. 2014-07-21 03:25:21 +02:00
933d46553f Added sounds 2014-07-21 01:12:13 +02:00
7e667a8028 print multiple matches for all tab-complete operations, fix bug when tab-completing at end of line 2014-07-18 13:48:21 -04:00
d4e41d6053 autocomplete pathnames with spaces 2014-07-18 03:20:40 -04:00
f30dccf726 return correct value, fix comment 2014-07-18 01:52:33 -04:00
ea3fcd5b79 auto-completion for paths when sending file & improved auto-complete algorithm to do partial matches 2014-07-18 01:37:33 -04:00
e61d070def cleanup/error checks 2014-07-17 03:35:18 -04:00
b5f34f42a8 small fix 2014-07-16 21:34:50 -04:00
4426eaddd9 increase max friends 2014-07-16 15:59:54 -04:00
83f0720a39 another UB fix 2014-07-16 15:55:04 -04:00
ce4f293574 fix undefined behaviour with string literals 2014-07-16 12:51:07 -04:00
52 changed files with 1817 additions and 700 deletions

View File

@ -5,7 +5,7 @@ compiler:
before_script:
# Installing yasm (needed for compiling vpx) and openal
- sudo apt-get -yq install yasm libopenal-dev
- sudo apt-get -yq install yasm libopenal-dev libconfig-dev libalut-dev
# Installing libsodium, needed for toxcore
- git clone https://github.com/jedisct1/libsodium.git libsodium
- cd libsodium

View File

@ -1,7 +1,7 @@
# Toxic [![Build Status](https://travis-ci.org/Tox/toxic.png?branch=master)](https://travis-ci.org/Tox/toxic)
Toxic is a [Tox](https://tox.im)-based instant messenging client which formerly resided in the [Tox core repository](https://github.com/irungentoo/toxcore), and is now available as a standalone application.
![Toxic Screenshot](https://i.imgur.com/YOZ5NIB.png "Main Screen").
![Toxic Screenshot](https://i.imgur.com/ueK1Tdj.png "Home Screen").
## Installation
@ -9,10 +9,15 @@ Toxic is a [Tox](https://tox.im)-based instant messenging client which formerly
##### Base
* [libtoxcore](https://github.com/irungentoo/toxcore)
* [ncurses](https://www.gnu.org/software/ncurses) (for Debian based systems, 'libncursesw5-dev')
* [libconfig](http://www.hyperrealm.com/libconfig) (for Debian based systems, 'libconfig-dev')
##### Audio
* libtoxav (libtoxcore compiled with audio support)
* [openal](http://openal.org) (for Debian based systems, 'libopenal-dev')
##### Sound notifications
* [openal](http://openal.org)
* [openalut](http://openal.org) (for Debian based systems, 'libalut-dev')
### Compiling
1. `cd build/`
@ -24,6 +29,8 @@ Toxic is a [Tox](https://tox.im)-based instant messenging client which formerly
* You can pass your own flags to the Makefile with `CFLAGS=""` and/or `LDFLAGS=""` (this will supersede the default ones)
* Audio call support is automatically enabled if all dependencies are found
* If you want to build toxic without audio call support, you can use `make DISABLE_AV=1`
* Sound notifications support is automatically enabled if all dependencies are found
* If you want to build toxic without sound notifications support, you can use `make DISABLE_NOTIFY=1`
### Packaging
* For packaging purpose, you can use `DESTDIR=""` to specify a directory where to store installed files

View File

@ -1,4 +1,4 @@
TOXIC_VERSION = 0.4.5
TOXIC_VERSION = 0.4.6
REV = $(shell git rev-list HEAD --count)
VERSION = $(TOXIC_VERSION)_r$(REV)
@ -6,14 +6,18 @@ CFG_DIR = ../cfg
SRC_DIR = ../src
MISC_DIR = ../misc
DOC_DIR = ../doc
SND_DIR = ../sounds
PREFIX = /usr/local
BINDIR = $(PREFIX)/bin
DATADIR = $(PREFIX)/share/toxic
MANDIR = $(PREFIX)/man
DATAFILES = DHTnodes toxic.conf.example
MANFILES = toxic.1 toxic.conf.5
SNDFILES = ContactLogsIn.wav ContactLogsOut.wav Error.wav IncomingCall.wav
SNDFILES += LogIn.wav LogOut.wav NewMessage.wav OutgoingCall.wav
SNDFILES += TransferComplete.wav TransferPending.wav
LIBS = libtoxcore ncursesw
LIBS = libtoxcore ncursesw libconfig
CFLAGS = -std=gnu99 -pthread -Wall -g
CFLAGS += -DTOXICVER="\"$(VERSION)\"" -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED
@ -21,14 +25,18 @@ CFLAGS += -DPACKAGE_DATADIR="\"$(abspath $(DATADIR))\""
CFLAGS += $(USER_CFLAGS)
LDFLAGS = $(USER_LDFLAGS)
OBJ = chat.o chat_commands.o configdir.o dns.o execute.o file_senders.o
OBJ += friendlist.o global_commands.o groupchat.o line_info.o input.o help.o
OBJ = chat.o chat_commands.o configdir.o dns.o execute.o file_senders.o notify.o
OBJ += friendlist.o global_commands.o groupchat.o line_info.o input.o help.o autocomplete.o
OBJ += log.o misc_tools.o prompt.o settings.o toxic.o toxic_strings.o windows.o
# Variables for audio support
# Variables for audio call support
AUDIO_LIBS = libtoxav openal
AUDIO_CFLAGS = -D_SUPPORT_AUDIO
AUDIO_OBJ = device.o audio_call.o
AUDIO_CFLAGS = -D_AUDIO
AUDIO_OBJ = audio_call.o
# Variables for sound notify support
SND_NOTIFY_LIBS = openal freealut
SND_NOTIFY_CFLAGS = -D_SOUND_NOTIFY
# Check on wich system we are running
UNAME_S = $(shell uname -s)
@ -57,6 +65,13 @@ ifneq ($(filter arm%, $(UNAME_M)),)
-include $(CFG_DIR)/arm.mk
endif
# Check if we can use X11
CHECK_X11_LIBS = $(shell pkg-config x11 || echo -n "error")
ifneq ($(CHECK_X11_LIBS), error)
LIBS += x11
CFLAGS += -D_X11
endif
# Check if we want/can build audio
ifneq ($(DISABLE_AV), 1)
CHECK_AUDIO_LIBS = $(shell pkg-config $(AUDIO_LIBS) || echo -n "error")
@ -64,6 +79,7 @@ ifneq ($(CHECK_AUDIO_LIBS), error)
LIBS += $(AUDIO_LIBS)
CFLAGS += $(AUDIO_CFLAGS)
OBJ += $(AUDIO_OBJ)
NEED_AV = 1
else
ifneq ($(MAKECMDGOALS), clean)
MISSING_AUDIO_LIBS = $(shell for lib in $(AUDIO_LIBS) ; do if ! pkg-config $$lib ; then echo $$lib ; fi ; done)
@ -74,6 +90,29 @@ endif
endif
endif
# Check if we want/can build sound notify support
ifneq ($(DISABLE_NOTIFY), 1)
CHECK_NOTIFY_LIBS = $(shell pkg-config $(SND_NOTIFY_LIBS) || echo -n "error")
ifneq ($(CHECK_NOTIFY_LIBS), error)
LIBS += $(SND_NOTIFY_LIBS)
CFLAGS += $(SND_NOTIFY_CFLAGS)
NEED_AV = 1
else
ifneq ($(MAKECMDGOALS), clean)
MISSING_NOTIFY_LIBS = $(shell for lib in $(SND_NOTIFY_LIBS) ; do if ! pkg-config $$lib ; then echo $$lib ; fi ; done)
$(warning WARNING -- Toxic will be compiled without sound notify support)
$(warning WARNING -- You need these libraries for sound notify support)
$(warning WARNING -- $(MISSING_NOTIFY_LIBS))
endif
endif
endif
# device.o is needed for both audio calls and notifications but should only be loaded once
ifeq ($(NEED_AV), 1)
OBJ += device.o
endif
# Check if we can build Toxic
CHECK_LIBS = $(shell pkg-config $(LIBS) || echo -n "error")
ifneq ($(CHECK_LIBS), error)
@ -99,12 +138,18 @@ toxic: $(OBJ)
install: toxic
mkdir -p $(abspath $(DESTDIR)/$(BINDIR))
mkdir -p $(abspath $(DESTDIR)/$(DATADIR))
mkdir -p $(abspath $(DESTDIR)/$(DATADIR))/sounds
mkdir -p $(abspath $(DESTDIR)/$(MANDIR))
@echo "Installing toxic executable"
@install -m 0755 toxic $(abspath $(DESTDIR)/$(BINDIR))
@echo "Installing data files"
@for f in $(DATAFILES) ; do \
install -m 0644 $(MISC_DIR)/$$f $(abspath $(DESTDIR)/$(DATADIR)) ;\
file=$(abspath $(DESTDIR)/$(DATADIR))/$$f ;\
sed -i'' -e 's:__DATADIR__:'$(abspath $(DATADIR))':g' $$file ;\
done
@for f in $(SNDFILES) ; do \
install -m 0644 $(SND_DIR)/$$f $(abspath $(DESTDIR)/$(DATADIR))/sounds ;\
done
@echo "Installing man pages"
@for f in $(MANFILES) ; do \

View File

@ -8,10 +8,11 @@ help:
@echo " help: This help"
@echo
@echo "-- Variables --"
@echo " DISABLE_AV: Set to \"1\" to force building without audio call support"
@echo " USER_CFLAGS: Add custom flags to default CFLAGS"
@echo " USER_LDFLAGS: Add custom flags to default LDFLAGS"
@echo " PREFIX: Specify a prefix directory for binaries, data files,... (default is \"$(abspath $(PREFIX))\")"
@echo " DESTDIR: Specify a directory where to store installed files (mainly for packaging purpose)"
@echo " DISABLE_AV: Set to \"1\" to force building without audio call support"
@echo " DISABLE_NOTIFY: Set to \"1\" to force building without sound notify support"
@echo " USER_CFLAGS: Add custom flags to default CFLAGS"
@echo " USER_LDFLAGS: Add custom flags to default LDFLAGS"
@echo " PREFIX: Specify a prefix directory for binaries, data files,... (default is \"$(abspath $(PREFIX))\")"
@echo " DESTDIR: Specify a directory where to store installed files (mainly for packaging purpose)"
.PHONY: help

View File

@ -8,38 +8,62 @@ file is the main configuration file for
.BR toxic (1)
client.
.SH SYNTAX
.IB <KEY> : <VALUE> ;
.I <SECTION>
.B = {
.PP
Lines starting with "#" are comments and will be ignored.
.IB <KEY1> : <BOOL_VALUE> ;
.br
.IB <KEY2> = <NOT_BOOL_VALUE> ;
.br
...
.PP
.B };
.PP
Uses syntax accepted by libconfig.
.br
Lines starting with "//" are comments and will be ignored.
.PP
Sections:
.PP
.B ui
.RS
Configurations related to user interface.
.PP
Keys:
.PP
.B time
.RS
Select between 24 and 12 hour time.
.br
Values: 24, 12
.RE
.PP
.B timestamps
.RS
Enable or disable timestamps.
.br
Values: 1 to enable, 0 to disable
.RE
.PP
.B autolog
.RS
Enable or disable autologging.
.br
Values: 1 to enable, 0 to disable
Values: 'true' to enable, 'false' to disable
.RE
.PP
.B alerts
.RS
Enable or disable terminal alerts on events.
.br
Values: 1 to enable, 0 to disable
Values: 'true' to enable, 'false' to disable
.RE
.PP
.B native_colors
.RS
Select between native terminal colors and toxic color theme.
.br
Values: 'true' for terminal colours, 'false' for toxic colours
.RE
.PP
.B autolog
.RS
Enable or disable autologging.
.br
Values: 'true' to enable, 'false' to disable
.RE
.PP
.B time_format
.RS
Select between 24 and 12 hour time.
.br
Values: 24, 12
.RE
.PP
.B history_size
@ -48,54 +72,211 @@ Maximum lines for chat window history.
.br
Values: <INTEGER> (for example: 700)
.RE
.PP
.B colour_theme
.RS
Select between toxic colour theme and native terminal colours.
.br
Values: 0 for toxic colours, 1 for terminal colours
.RE
.PP
.B audio_in_dev
.B audio
.RS
Configurations related to audio devices.
.PP
Keys:
.br
.B input_device
.RS
Audio input device.
.br
Values: <INTEGER> (number correspond to "/lsdev in")
.RE
.PP
.B audio_out_dev
.B output_device
.RS
Audio output device.
.br
Values: <INTEGER> (number correspond to "/lsdev out")
.RE
.PP
.B VAD_treshold
.RS
Voice Activity Detection treshold.
.br
Values: <FLOAT> (recommended values are around 40.0)
.RE
.RE
.PP
.B tox
.RS
Configurations related to file transfer.
.PP
Keys:
.br
.B download_path
.RS
Default path for downloads.
.br
Values: <STRING> (absolute path where to store downloaded files)
.RE
.RE
.PP
.B sounds
.RS
Configurations related to notification sounds.
.PP
Keys:
.br
.B error
.RS
Sound to play when an error occurs.
.br
Values: <STRING> (sound file absolute path)
.RE
.PP
.B self_log_in
.RS
Sound to play when you log in.
.br
Values: <STRING> (sound file absolute path)
.RE
.PP
.B self_log_out
.RS
Sound to play when you log out.
.br
Values: <STRING> (sound file absolute path)
.RE
.PP
.B user_log_in
.RS
Sound to play when a contact become online.
.br
Values: <STRING> (sound file absolute path)
.RE
.PP
.B user_log_out
.RS
Sound to play when a contact become offline.
.br
Values: <STRING> (sound file absolute path)
.RE
.PP
.B call_incoming
.RS
Sound to play when you receive an incoming call.
.br
Values: <STRING> (sound file absolute path)
.RE
.PP
.B call_outgoing
.RS
Sound to play when you start a call.
.br
Values: <STRING> (sound file absolute path)
.RE
.PP
.B generic_message
.RS
Sound to play when an event occurs.
.br
Values: <STRING> (sound file absolute path)
.RE
.PP
.B transfer_pending
.RS
Sound to play when you receive a file transfer request.
.br
Values: <STRING> (sound file absolute path)
.RE
.PP
.B transfer_completed
.RS
Sound to play when a file transfer is completed.
.br
Values: <STRING> (sound file absolute path)
.RE
.RE
.SH EXAMPLES
Default settings from __DATADIR__/toxic.conf.exmaple:
.PP
time:24;
// SAMPLE TOXIC CONFIGURATION
.br
timestamps:1;
// USES LIBCONFIG-ACCEPTED SYNTAX
.br
autolog:0;
ui = {
.br
alerts:1;
// true to enable timestamps, false to disable
.br
history_size:700;
timestamps:true;
.br
colour_theme:0;
.br
audio_in_dev:0;
// true to enable terminal alerts on messages, false to disable
.br
audio_out_dev:0;
alerts:true;
.br
download_path:/home/USERNAME/Downloads/;
// true to use native terminal colours, false to use toxic default colour theme
.br
native_colors:false;
.br
// true to enable autologging, false to disable
.br
autolog:false;
.br
// 24 or 12 hour time
.br
time_format=24;
.br
// maximum lines for chat window history
.br
history_size=700;
.br
};
.br
audio = {
.br
// preferred audio input device; numbers correspond to /lsdev in
.br
input_device=2;
.br
// preferred audio output device; numbers correspond to /lsdev out
.br
output_device=0;
.br
// default VAD treshold; float (recommended values are around 40)
.br
VAD_treshold=40.0;
.br
};
.br
tox = {
.br
// where to store received files
.br
// download_path="/home/USERNAME/Downloads/";
.br
};
.br
// To disable a sound set the path to "silent"
.br
sounds = {
.br
error="__DATADIR__/sounds/Error.wav";
.br
self_log_in="__DATADIR__/sounds/LogIn.wav";
.br
self_log_out="__DATADIR__/sounds/LogOut.wav";
.br
user_log_in="__DATADIR__/sounds/ContactLogsIn.wav";
.br
user_log_out="__DATADIR__/sounds/ContactLogsOut.wav";
.br
call_incoming="__DATADIR__/sounds/IncomingCall.wav";
.br
call_outgoing="__DATADIR__/sounds/OutgoingCall.wav";
.br
generic_message="__DATADIR__/sounds/NewMessage.wav";
.br
transfer_pending="__DATADIR__/sounds/TransferPending.wav";
.br
transfer_completed="__DATADIR__/sounds/TransferComplete.wav";
.br
};
.SH FILES
.IP ~/.config/tox/toxic.conf
Main configuration file.

View File

@ -1,26 +1,52 @@
# 24 or 12 hour time
time:24;
// SAMPLE TOXIC CONFIGURATION
// USES LIBCONFIG-ACCEPTED SYNTAX
# 1 to enable timestamps, 0 to disable
timestamps:1;
ui = {
// true to enable timestamps, false to disable
timestamps:true;
# 1 to enable autologging, 0 to disable
autolog:0;
// true to enable terminal alerts on messages, false to disable
alerts:true;
# 1 to disbale terminal alerts on messages, 0 to enable
alerts:1;
// true to use native terminal colours, false to use toxic default colour theme
native_colors:false;
# maximum lines for chat window history
history_size:700;
// true to enable autologging, false to disable
autolog:false;
// 24 or 12 hour time
time_format=24;
# 1 to use native terminal colours, 0 to use toxic default colour theme
colour_theme:0;
// maximum lines for chat window history
history_size=700;
};
# preferred audio input device; numbers correspond to /lsdev in
audio_in_dev:0;
audio = {
// preferred audio input device; numbers correspond to /lsdev in
input_device=2;
# preferred audio output device; numbers correspond to /lsdev out
audio_out_dev:0;
// preferred audio output device; numbers correspond to /lsdev out
output_device=0;
// default VAD treshold; float (recommended values are around 40)
VAD_treshold=40.0;
};
# preferred path for downloads
download_path:/home/USERNAME/Downloads/;
tox = {
// where to store received files
// download_path="/home/USERNAME/Downloads/";
};
// To disable a sound set the path to "silent"
sounds = {
error="__DATADIR__/sounds/Error.wav";
self_log_in="__DATADIR__/sounds/LogIn.wav";
self_log_out="__DATADIR__/sounds/LogOut.wav";
user_log_in="__DATADIR__/sounds/ContactLogsIn.wav";
user_log_out="__DATADIR__/sounds/ContactLogsOut.wav";
call_incoming="__DATADIR__/sounds/IncomingCall.wav";
call_outgoing="__DATADIR__/sounds/OutgoingCall.wav";
generic_message="__DATADIR__/sounds/NewMessage.wav";
transfer_pending="__DATADIR__/sounds/TransferPending.wav";
transfer_completed="__DATADIR__/sounds/TransferComplete.wav";
};

BIN
sounds/ContactLogsIn.wav Normal file

Binary file not shown.

BIN
sounds/ContactLogsOut.wav Normal file

Binary file not shown.

BIN
sounds/Error.wav Normal file

Binary file not shown.

BIN
sounds/IncomingCall.wav Normal file

Binary file not shown.

BIN
sounds/LogIn.wav Normal file

Binary file not shown.

BIN
sounds/LogOut.wav Normal file

Binary file not shown.

BIN
sounds/NewMessage.wav Normal file

Binary file not shown.

BIN
sounds/OutgoingCall.wav Normal file

Binary file not shown.

BIN
sounds/TransferComplete.wav Normal file

Binary file not shown.

BIN
sounds/TransferPending.wav Normal file

Binary file not shown.

1
sounds/license Normal file
View File

@ -0,0 +1 @@
Tox's sounds are licensed under the "Creative Commons Attribution 3.0 Unported", all credit attributed to Adam Reid.

View File

@ -27,6 +27,7 @@
#include "chat_commands.h"
#include "global_commands.h"
#include "line_info.h"
#include "notify.h"
#include <curses.h>
#include <string.h>
@ -82,17 +83,17 @@ struct _ASettings {
Call calls[MAX_CALLS];
} ASettins;
void callback_recv_invite ( int32_t call_index, void *arg );
void callback_recv_ringing ( int32_t call_index, void *arg );
void callback_recv_starting ( int32_t call_index, void *arg );
void callback_recv_ending ( int32_t call_index, void *arg );
void callback_recv_error ( int32_t call_index, void *arg );
void callback_call_started ( int32_t call_index, void *arg );
void callback_call_canceled ( int32_t call_index, void *arg );
void callback_call_rejected ( int32_t call_index, void *arg );
void callback_call_ended ( int32_t call_index, void *arg );
void callback_requ_timeout ( int32_t call_index, void *arg );
void callback_peer_timeout ( int32_t call_index, void *arg );
void callback_recv_invite ( void* av, int32_t call_index, void *arg );
void callback_recv_ringing ( void* av, int32_t call_index, void *arg );
void callback_recv_starting ( void* av, int32_t call_index, void *arg );
void callback_recv_ending ( void* av, int32_t call_index, void *arg );
void callback_call_started ( void* av, int32_t call_index, void *arg );
void callback_call_canceled ( void* av, int32_t call_index, void *arg );
void callback_call_rejected ( void* av, int32_t call_index, void *arg );
void callback_call_ended ( void* av, int32_t call_index, void *arg );
void callback_requ_timeout ( void* av, int32_t call_index, void *arg );
void callback_peer_timeout ( void* av, int32_t call_index, void *arg );
void callback_media_change ( void* av, int32_t call_index, void *arg );
int stop_transmission(int call_index);
void write_device_callback(ToxAv* av, int32_t call_index, int16_t* data, int size);
@ -127,19 +128,19 @@ ToxAv *init_audio(ToxWindow *self, Tox *tox)
return ASettins.av = NULL;
}
toxav_register_callstate_callback(callback_call_started, av_OnStart, self);
toxav_register_callstate_callback(callback_call_canceled, av_OnCancel, self);
toxav_register_callstate_callback(callback_call_rejected, av_OnReject, self);
toxav_register_callstate_callback(callback_call_ended, av_OnEnd, self);
toxav_register_callstate_callback(callback_recv_invite, av_OnInvite, self);
toxav_register_callstate_callback(ASettins.av, callback_call_started, av_OnStart, self);
toxav_register_callstate_callback(ASettins.av, callback_call_canceled, av_OnCancel, self);
toxav_register_callstate_callback(ASettins.av, callback_call_rejected, av_OnReject, self);
toxav_register_callstate_callback(ASettins.av, callback_call_ended, av_OnEnd, self);
toxav_register_callstate_callback(ASettins.av, callback_recv_invite, av_OnInvite, self);
toxav_register_callstate_callback(callback_recv_ringing, av_OnRinging, self);
toxav_register_callstate_callback(callback_recv_starting, av_OnStarting, self);
toxav_register_callstate_callback(callback_recv_ending, av_OnEnding, self);
toxav_register_callstate_callback(ASettins.av, callback_recv_ringing, av_OnRinging, self);
toxav_register_callstate_callback(ASettins.av, callback_recv_starting, av_OnStarting, self);
toxav_register_callstate_callback(ASettins.av, callback_recv_ending, av_OnEnding, self);
toxav_register_callstate_callback(callback_recv_error, av_OnError, self);
toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout, self);
toxav_register_callstate_callback(callback_peer_timeout, av_OnPeerTimeout, self);
toxav_register_callstate_callback(ASettins.av, callback_requ_timeout, av_OnRequestTimeout, self);
toxav_register_callstate_callback(ASettins.av, callback_peer_timeout, av_OnPeerTimeout, self);
toxav_register_callstate_callback(ASettins.av, callback_media_change, av_OnMediaChange, self);
toxav_register_audio_recv_callback(ASettins.av, write_device_callback);
@ -191,7 +192,8 @@ int start_transmission(ToxWindow *self)
set_call(&ASettins.calls[self->call_idx], _True);
if ( open_primary_device(input, &ASettins.calls[self->call_idx].in_idx) != de_None )
if ( open_primary_device(input, &ASettins.calls[self->call_idx].in_idx,
av_DefaultSettings.audio_sample_rate, av_DefaultSettings.audio_frame_duration) != de_None )
line_info_add(self, NULL, NULL, NULL, "Failed to open input device!", SYS_MSG, 0, 0);
if ( register_device_callback(self->call_idx, ASettins.calls[self->call_idx].in_idx,
@ -199,7 +201,8 @@ int start_transmission(ToxWindow *self)
/* Set VAD as true for all; TODO: Make it more dynamic */
line_info_add(self, NULL, NULL, NULL, "Failed to register input handler!", SYS_MSG, 0, 0);
if ( open_primary_device(output, &ASettins.calls[self->call_idx].out_idx) != de_None ) {
if ( open_primary_device(output, &ASettins.calls[self->call_idx].out_idx,
av_DefaultSettings.audio_sample_rate, av_DefaultSettings.audio_frame_duration) != de_None ) {
line_info_add(self, NULL, NULL, NULL, "Failed to open output device!", SYS_MSG, 0, 0);
ASettins.calls[self->call_idx].has_output = 0;
}
@ -240,15 +243,15 @@ int stop_transmission(int call_index)
#define CB_BODY(call_idx, Arg, onFunc) do { ToxWindow* windows = (Arg); int i;\
for (i = 0; i < MAX_WINDOWS_NUM; ++i) if (windows[i].onFunc != NULL) windows[i].onFunc(&windows[i], ASettins.av, call_idx); } while (0)
void callback_recv_invite ( int32_t call_index, void* arg )
void callback_recv_invite ( void* av, int32_t call_index, void* arg )
{
CB_BODY(call_index, arg, onInvite);
}
void callback_recv_ringing ( int32_t call_index, void* arg )
void callback_recv_ringing ( void* av, int32_t call_index, void* arg )
{
CB_BODY(call_index, arg, onRinging);
}
void callback_recv_starting ( int32_t call_index, void* arg )
void callback_recv_starting ( void* av, int32_t call_index, void* arg )
{
ToxWindow* windows = arg;
int i;
@ -261,17 +264,13 @@ void callback_recv_starting ( int32_t call_index, void* arg )
return;
}
}
void callback_recv_ending ( int32_t call_index, void* arg )
void callback_recv_ending ( void* av, int32_t call_index, void* arg )
{
CB_BODY(call_index, arg, onEnding);
stop_transmission(call_index);
}
void callback_recv_error ( int32_t call_index, void* arg )
{
CB_BODY(call_index, arg, onError);
stop_transmission(call_index);
}
void callback_call_started ( int32_t call_index, void* arg )
void callback_call_started ( void* av, int32_t call_index, void* arg )
{
ToxWindow* windows = arg;
int i;
@ -284,28 +283,28 @@ void callback_call_started ( int32_t call_index, void* arg )
}
}
}
void callback_call_canceled ( int32_t call_index, void* arg )
void callback_call_canceled ( void* av, int32_t call_index, void* arg )
{
CB_BODY(call_index, arg, onCancel);
/* In case call is active */
stop_transmission(call_index);
}
void callback_call_rejected ( int32_t call_index, void* arg )
void callback_call_rejected ( void* av, int32_t call_index, void* arg )
{
CB_BODY(call_index, arg, onReject);
}
void callback_call_ended ( int32_t call_index, void* arg )
void callback_call_ended ( void* av, int32_t call_index, void* arg )
{
CB_BODY(call_index, arg, onEnd);
stop_transmission(call_index);
}
void callback_requ_timeout ( int32_t call_index, void* arg )
void callback_requ_timeout ( void* av, int32_t call_index, void* arg )
{
CB_BODY(call_index, arg, onRequestTimeout);
}
void callback_peer_timeout ( int32_t call_index, void* arg )
void callback_peer_timeout ( void* av, int32_t call_index, void* arg )
{
CB_BODY(call_index, arg, onPeerTimeout);
stop_transmission(call_index);
@ -314,6 +313,10 @@ void callback_peer_timeout ( int32_t call_index, void* arg )
*/
toxav_stop_call(ASettins.av, call_index);
}
void callback_media_change(void* av, int32_t call_index, void* arg)
{
/*... TODO cancel all media change requests */
}
/*
* End of Callbacks
*/
@ -476,6 +479,10 @@ void cmd_cancel(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
goto on_error;
}
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
#endif /* _SOUND_NOTIFY */
/* Callback will print status... */
return;
@ -612,14 +619,16 @@ void cmd_ccur_device(WINDOW * window, ToxWindow * self, Tox *m, int argc, char (
if (type == output) {
pthread_mutex_lock(&this_call->mutex);
close_device(output, this_call->out_idx);
this_call->has_output = open_device(output, selection, &this_call->out_idx)
this_call->has_output = open_device(output, selection, &this_call->out_idx,
av_DefaultSettings.audio_sample_rate, av_DefaultSettings.audio_frame_duration)
== de_None ? 1 : 0;
pthread_mutex_unlock(&this_call->mutex);
}
else {
/* TODO: check for failure */
close_device(input, this_call->in_idx);
open_device(input, selection, &this_call->in_idx);
open_device(input, selection, &this_call->in_idx,
av_DefaultSettings.audio_sample_rate, av_DefaultSettings.audio_frame_duration);
/* Set VAD as true for all; TODO: Make it more dynamic */
register_device_callback(self->call_idx, this_call->in_idx, read_device_callback, &self->call_idx, _True);
}

View File

@ -27,8 +27,6 @@
#include "device.h"
#define VAD_THRESHOLD_DEFAULT 40.0
typedef enum _AudioError {
ae_None = 0,
ae_StartingCaptureDevice = 1 << 0,

289
src/autocomplete.c Normal file
View File

@ -0,0 +1,289 @@
/* autocomplete.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/>.
*
*/
#include <stdlib.h>
#include <string.h>
#ifdef __APPLE__
#include <sys/types.h>
#include <sys/dir.h>
#else
#include <dirent.h>
#endif /* ifdef __APPLE__ */
#include "windows.h"
#include "toxic.h"
#include "misc_tools.h"
#include "line_info.h"
#include "execute.h"
#include "configdir.h"
static void print_matches(ToxWindow *self, Tox *m, const void *list, int n_items, int size)
{
if (m)
execute(self->chatwin->history, self, m, "/clear", GLOBAL_COMMAND_MODE);
const char *L = (char *) list;
int i;
for (i = 0; i < n_items; ++i)
line_info_add(self, NULL, NULL, NULL, &L[i * size], SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, "", SYS_MSG, 0, 0); /* formatting */
}
/* puts match in match buffer. if more than one match, add first n chars that are identical.
e.g. if matches contains: [foo, foobar, foe] we put fo in matches. */
static void get_str_match(ToxWindow *self, char *match, char (*matches)[MAX_STR_SIZE], int n)
{
if (n == 1) {
strcpy(match, matches[0]);
return;
}
int i;
for (i = 0; i < MAX_STR_SIZE; ++i) {
char ch1 = matches[0][i];
int j;
for (j = 0; j < n; ++j) {
char ch2 = matches[j][i];
if (ch1 != ch2 || !ch1) {
strcpy(match, matches[0]);
match[i] = '\0';
return;
}
}
}
strcpy(match, matches[0]);
}
/* looks for all instances in list that begin 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". If multiple matches, prints out all the matches and semi-completes line.
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 line on success, -1 if error */
int complete_line(ToxWindow *self, const void *list, int n_items, int size)
{
ChatContext *ctx = self->chatwin;
if (ctx->pos <= 0 || ctx->len <= 0 || ctx->len >= MAX_STR_SIZE || size > MAX_STR_SIZE)
return -1;
const char *L = (char *) list;
const char *endchrs = " ";
char ubuf[MAX_STR_SIZE];
/* work with multibyte string copy of buf for simplicity */
if (wcs_to_mbs_buf(ubuf, ctx->line, sizeof(ubuf)) == -1)
return -1;
bool dir_search = strncmp(ubuf, "/sendfile", strlen("/sendfile")) == 0;
/* isolate substring from space behind pos to pos */
char tmp[MAX_STR_SIZE];
snprintf(tmp, sizeof(tmp), "%s", ubuf);
tmp[ctx->pos] = '\0';
const char *s = dir_search ? strchr(tmp, '\"') : strrchr(tmp, ' ');
char *sub = malloc(strlen(ubuf) + 1);
if (sub == NULL)
exit_toxic_err("failed in complete_line", FATALERR_MEMORY);
if (!s && !dir_search) {
strcpy(sub, tmp);
if (sub[0] != '/')
endchrs = ": ";
} else if (s) {
strcpy(sub, &s[1]);
if (dir_search) {
int sub_len = strlen(sub);
int si = char_rfind(sub, '/', sub_len);
if (si || *sub == '/')
memmove(sub, &sub[si + 1], sub_len - si);
}
}
if (string_is_empty(sub)) {
free(sub);
return -1;
}
int s_len = strlen(sub);
const char *str;
int n_matches = 0;
char matches[n_items][MAX_STR_SIZE];
int i = 0;
/* put all list matches in matches array */
for (i = 0; i < n_items; ++i) {
str = &L[i * size];
if (strncasecmp(str, sub, s_len) == 0)
strcpy(matches[n_matches++], str);
}
free(sub);
if (!n_matches)
return -1;
if (!dir_search && n_matches > 1)
print_matches(self, NULL, matches, n_matches, MAX_STR_SIZE);
char match[MAX_STR_SIZE];
get_str_match(self, match, matches, n_matches);
if (dir_search) {
if (n_matches == 1)
endchrs = char_rfind(match, '.', strlen(match)) ? "\"" : "/";
else
endchrs = "";
} else if (n_matches > 1) {
endchrs = "";
}
/* put match in correct spot in buf and append endchars */
int n_endchrs = strlen(endchrs);
int m_len = strlen(match);
int strt = ctx->pos - s_len;
int diff = m_len - s_len + n_endchrs;
if (ctx->len + diff > MAX_STR_SIZE)
return -1;
char tmpend[MAX_STR_SIZE];
strcpy(tmpend, &ubuf[ctx->pos]);
strcpy(&ubuf[strt], match);
strcpy(&ubuf[strt + m_len], endchrs);
strcpy(&ubuf[strt + m_len + n_endchrs], tmpend);
/* convert to widechar and copy back to original buf */
wchar_t newbuf[MAX_STR_SIZE];
if (mbs_to_wcs_buf(newbuf, ubuf, MAX_STR_SIZE) == -1)
return -1;
wcscpy(ctx->line, newbuf);
ctx->len += diff;
ctx->pos += diff;
return diff;
}
/* transforms a sendfile tab complete contaning the shorthand "~/" into the full home directory.*/
static void complt_home_dir(ToxWindow *self, char *path)
{
ChatContext *ctx = self->chatwin;
char homedir[MAX_STR_SIZE];
get_home_dir(homedir, sizeof(homedir));
char newline[MAX_STR_SIZE];
const char *isqt = !strchr(path, '\"') ? "\"" : "";
snprintf(newline, sizeof(newline), "/sendfile %s%s/", isqt, homedir);
wchar_t wline[MAX_STR_SIZE];
if (mbs_to_wcs_buf(wline, newline, sizeof(wline)) == -1)
return;
int newlen = wcslen(wline);
if (ctx->len + newlen > MAX_STR_SIZE)
return;
wmemcpy(ctx->line, wline, newlen + 1);
ctx->pos = newlen;
ctx->len = ctx->pos;
}
/* attempts to match /sendfile "<incomplete-dir>" line to matching directories.
if only one match, auto-complete line.
return diff between old len and new len of ctx->line, -1 if no matches
*/
#define MAX_DIRS 256
int dir_match(ToxWindow *self, Tox *m, wchar_t *line)
{
char b_path[MAX_STR_SIZE];
char b_name[MAX_STR_SIZE];
if (wcs_to_mbs_buf(b_path, line, sizeof(b_path)) == -1)
return -1;
if (!strncmp(b_path, "\"~/", 3) || !strncmp(b_path, "~/", 2)) {
complt_home_dir(self, b_path);
return -1;
}
int si = char_rfind(b_path, '/', strlen(b_path));
if (!b_path[0]) { /* list everything in pwd */
b_path[0] = '.';
b_path[1] = '\0';
} else if (!si && b_path[0] != '/') { /* look for matches in pwd */
char tmp[MAX_STR_SIZE];
snprintf(tmp, sizeof(tmp), ".%s", b_path);
strcpy(b_path, tmp);
}
strcpy(b_name, &b_path[si + 1]);
b_path[si + 1] = '\0';
int b_name_len = strlen(b_name);
DIR *dp = opendir(b_path);
if (dp == NULL)
return -1;
char dirnames[MAX_DIRS][NAME_MAX];
struct dirent *entry;
int dircount = 0;
while ((entry = readdir(dp)) && dircount < MAX_DIRS) {
if (strncmp(entry->d_name, b_name, b_name_len) == 0) {
snprintf(dirnames[dircount], sizeof(dirnames[dircount]), "%s", entry->d_name);
++dircount;
}
}
if (dircount == 0)
return -1;
if (dircount > 1)
print_matches(self, m, dirnames, dircount, NAME_MAX);
return complete_line(self, dirnames, dircount, NAME_MAX);
}

43
src/autocomplete.h Normal file
View File

@ -0,0 +1,43 @@
/* autocomplete.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 _autocomplete_h
#define _autocomplete_h
/* looks for all instances in list that begin 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". If multiple matches, prints out all the matches and semi-completes line.
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 line on success, -1 if error */
int complete_line(ToxWindow *self, const void *list, int n_items, int size);
/* matches /sendfile "<incomplete-dir>" line to matching directories.
if only one match, auto-complete line.
return diff between old len and new len of ctx->line, or -1 if no matches
*/
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line);
#endif /* #define _autocomplete_h */

View File

@ -41,10 +41,13 @@
#include "settings.h"
#include "input.h"
#include "help.h"
#include "autocomplete.h"
#include "notify.h"
#ifdef _AUDIO
#include "audio_call.h"
#endif /* _AUDIO */
#ifdef _SUPPORT_AUDIO
#include "audio_call.h"
#endif /* _SUPPORT_AUDIO */
extern char *DATA_FILE;
@ -52,18 +55,18 @@ extern FileSender file_senders[MAX_FILES];
extern ToxicFriend friends[MAX_FRIENDS_NUM];
extern struct _Winthread Winthread;
extern struct user_settings *user_settings;
extern struct user_settings *user_settings_;
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
static void init_infobox(ToxWindow *self);
static void kill_infobox(ToxWindow *self);
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
#define AC_NUM_CHAT_COMMANDS 26
#else
#define AC_NUM_CHAT_COMMANDS 18
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
/* Array of chat command names used for tab completion. */
static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
@ -86,7 +89,7 @@ static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/sendfile" },
{ "/status" },
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
{ "/call" },
{ "/cancel" },
@ -97,7 +100,7 @@ static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/mute" },
{ "/sense" },
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
};
static void set_typingstatus(ToxWindow *self, Tox *m, uint8_t is_typing)
@ -126,7 +129,7 @@ void kill_chat_window(ToxWindow *self)
log_disable(ctx->log);
line_info_cleanup(ctx->hst);
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
stop_current_call(self);
#endif
@ -159,7 +162,8 @@ static void chat_onMessage(ToxWindow *self, Tox *m, int32_t num, const char *msg
line_info_add(self, timefrmt, nick, NULL, msg, IN_MSG, 0, 0);
write_to_log(msg, nick, ctx->log, false);
alert_window(self, WINDOW_ALERT_1, true);
notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS);
}
static void chat_onConnectionChange(ToxWindow *self, Tox *m, int32_t num, uint8_t status)
@ -169,12 +173,14 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, int32_t num, uint8_
StatusBar *statusbar = self->stb;
if (status == 1) {
if (status == 1) { /* Friend shows online */
statusbar->is_online = true;
friends[num].is_typing = tox_get_is_typing(m, num);
} else {
notify(self, user_log_in, NT_NOFOCUS);
} else { /* Friend goes offline */
statusbar->is_online = false;
friends[num].is_typing = 0;
notify(self, user_log_out, NT_NOFOCUS);
}
}
@ -201,7 +207,7 @@ static void chat_onAction(ToxWindow *self, Tox *m, int32_t num, const char *acti
line_info_add(self, timefrmt, nick, NULL, action, ACTION, 0, 0);
write_to_log(action, nick, ctx->log, true);
alert_window(self, WINDOW_ALERT_1, true);
notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS);
}
static void chat_onNickChange(ToxWindow *self, Tox *m, int32_t num, const char *nick, uint16_t len)
@ -271,9 +277,9 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t
}
/* 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 (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])) {
@ -321,7 +327,7 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t
friends[num].file_receiver.size[filenum] = filesize;
strcpy(friends[num].file_receiver.filenames[filenum], filename);
alert_window(self, WINDOW_ALERT_2, true);
notify(self, transfer_pending, NT_WNDALERT_2 | NT_NOFOCUS);
}
static void chat_close_file_receiver(int32_t num, uint8_t filenum)
@ -360,6 +366,7 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, int32_t num, uint8_t rec
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;
notify(self, silent, NT_NOFOCUS | NT_BEEP | NT_WNDALERT_2);
}
break;
@ -370,19 +377,20 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, int32_t num, uint8_t rec
if (receive_send == 0)
chat_close_file_receiver(num, filenum);
notify(self, error, NT_NOFOCUS | NT_WNDALERT_2);
break;
case TOX_FILECONTROL_FINISHED:
if (receive_send == 0) {
snprintf(msg, sizeof(msg), "File transfer for '%s' complete.", filename);
chat_close_file_receiver(num, filenum);
notify(self, transfer_completed, NT_NOFOCUS | NT_WNDALERT_2);
}
break;
}
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
alert_window(self, WINDOW_ALERT_2, true);
}
static void chat_onFileData(ToxWindow *self, Tox *m, int32_t num, uint8_t filenum, const char *data,
@ -435,11 +443,12 @@ static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, co
sizeof(friends[friendnumber].groupchat_key));
friends[friendnumber].groupchat_pending = true;
alert_window(self, WINDOW_ALERT_2, true);
notify(self, generic_message, NT_WNDALERT_2);
}
/* Av Stuff */
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
void chat_onInvite (ToxWindow *self, ToxAv *av, int call_index)
{
@ -450,7 +459,11 @@ void chat_onInvite (ToxWindow *self, ToxAv *av, int call_index)
self->call_idx = call_index;
line_info_add(self, NULL, NULL, NULL, "Incoming audio call! Type: \"/answer\" or \"/reject\"", SYS_MSG, 0, 0);
alert_window(self, WINDOW_ALERT_0, true);
#ifdef _SOUND_NOTIFY
if (self->active_sound == -1)
self->active_sound = notify(self, call_incoming, NT_LOOP | NT_WNDALERT_0);
#endif /* _SOUND_NOTIFY */
}
void chat_onRinging (ToxWindow *self, ToxAv *av, int call_index)
@ -459,6 +472,11 @@ void chat_onRinging (ToxWindow *self, ToxAv *av, int call_index)
return;
line_info_add(self, NULL, NULL, NULL, "Ringing...\"cancel\" ?", SYS_MSG, 0, 0);
#ifdef _SOUND_NOTIFY
if (self->active_sound == -1)
self->active_sound = notify(self, call_outgoing, NT_LOOP);
#endif /* _SOUND_NOTIFY */
}
void chat_onStarting (ToxWindow *self, ToxAv *av, int call_index)
@ -469,6 +487,11 @@ void chat_onStarting (ToxWindow *self, ToxAv *av, int call_index)
init_infobox(self);
line_info_add(self, NULL, NULL, NULL, "Call started! Type: \"/hangup\" to end it.", SYS_MSG, 0, 0);
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
#endif /* _SOUND_NOTIFY */
}
void chat_onEnding (ToxWindow *self, ToxAv *av, int call_index)
@ -479,6 +502,11 @@ void chat_onEnding (ToxWindow *self, ToxAv *av, int call_index)
kill_infobox(self);
self->call_idx = -1;
line_info_add(self, NULL, NULL, NULL, "Call ended!", SYS_MSG, 0, 0);
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
#endif /* _SOUND_NOTIFY */
}
void chat_onError (ToxWindow *self, ToxAv *av, int call_index)
@ -488,6 +516,11 @@ void chat_onError (ToxWindow *self, ToxAv *av, int call_index)
self->call_idx = -1;
line_info_add(self, NULL, NULL, NULL, "Error!", SYS_MSG, 0, 0);
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
#endif /* _SOUND_NOTIFY */
}
void chat_onStart (ToxWindow *self, ToxAv *av, int call_index)
@ -498,6 +531,11 @@ void chat_onStart (ToxWindow *self, ToxAv *av, int call_index)
init_infobox(self);
line_info_add(self, NULL, NULL, NULL, "Call started! Type: \"/hangup\" to end it.", SYS_MSG, 0, 0);
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
#endif /* _SOUND_NOTIFY */
}
void chat_onCancel (ToxWindow *self, ToxAv *av, int call_index)
@ -508,6 +546,11 @@ void chat_onCancel (ToxWindow *self, ToxAv *av, int call_index)
kill_infobox(self);
self->call_idx = -1;
line_info_add(self, NULL, NULL, NULL, "Call canceled!", SYS_MSG, 0, 0);
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
#endif /* _SOUND_NOTIFY */
}
void chat_onReject (ToxWindow *self, ToxAv *av, int call_index)
@ -517,6 +560,11 @@ void chat_onReject (ToxWindow *self, ToxAv *av, int call_index)
self->call_idx = -1;
line_info_add(self, NULL, NULL, NULL, "Rejected!", SYS_MSG, 0, 0);
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
#endif /* _SOUND_NOTIFY */
}
void chat_onEnd (ToxWindow *self, ToxAv *av, int call_index)
@ -527,6 +575,11 @@ void chat_onEnd (ToxWindow *self, ToxAv *av, int call_index)
kill_infobox(self);
self->call_idx = -1;
line_info_add(self, NULL, NULL, NULL, "Call ended!", SYS_MSG, 0, 0);
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
#endif /* _SOUND_NOTIFY */
}
void chat_onRequestTimeout (ToxWindow *self, ToxAv *av, int call_index)
@ -536,6 +589,11 @@ void chat_onRequestTimeout (ToxWindow *self, ToxAv *av, int call_index)
self->call_idx = -1;
line_info_add(self, NULL, NULL, NULL, "No answer!", SYS_MSG, 0, 0);
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
#endif /* _SOUND_NOTIFY */
}
void chat_onPeerTimeout (ToxWindow *self, ToxAv *av, int call_index)
@ -546,8 +604,14 @@ void chat_onPeerTimeout (ToxWindow *self, ToxAv *av, int call_index)
kill_infobox(self);
self->call_idx = -1;
line_info_add(self, NULL, NULL, NULL, "Peer disconnected; call ended!", SYS_MSG, 0, 0);
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
#endif /* _SOUND_NOTIFY */
}
#ifdef _AUDIO
static void init_infobox(ToxWindow *self)
{
ChatContext *ctx = self->chatwin;
@ -560,10 +624,11 @@ static void init_infobox(ToxWindow *self)
ctx->infobox.win = newwin(INFOBOX_HEIGHT, INFOBOX_WIDTH + 1, 1, x2 - INFOBOX_WIDTH);
ctx->infobox.starttime = get_unix_time();
ctx->infobox.vad_lvl = VAD_THRESHOLD_DEFAULT;
ctx->infobox.vad_lvl = user_settings_->VAD_treshold;
ctx->infobox.active = true;
strcpy(ctx->infobox.timestr, "00");
}
#endif
static void kill_infobox(ToxWindow *self)
{
@ -630,7 +695,7 @@ static void draw_infobox(ToxWindow *self)
wrefresh(infobox->win);
}
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
static void send_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
{
@ -685,21 +750,24 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
input_handle(self, key, x, y, x2, y2);
if (key == '\t') { /* TAB key: auto-completes command */
if (ctx->len > 1 && ctx->line[0] == '/') {
int diff = complete_line(ctx, chat_cmd_list, AC_NUM_CHAT_COMMANDS, MAX_CMDNAME_SIZE);
if (key == '\t' && ctx->len > 1 && ctx->line[0] == '/') { /* TAB key: auto-complete */
int diff = -1;
int sf_len = 11;
if (diff != -1) {
if (x + diff > x2 - 1) {
wmove(self->window, y, x + diff);
ctx->start += diff;
} else {
wmove(self->window, y, x + diff);
}
} else
beep();
} else
if (wcsncmp(ctx->line, L"/sendfile \"", sf_len) == 0) {
diff = dir_match(self, m, &ctx->line[sf_len]);
} else {
diff = complete_line(self, chat_cmd_list, AC_NUM_CHAT_COMMANDS, MAX_CMDNAME_SIZE);
}
if (diff != -1) {
if (x + diff > x2 - 1) {
int wlen = wcswidth(ctx->line, sizeof(ctx->line));
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
}
} else {
beep();
}
} else if (key == '\n') {
rm_trailing_spaces_buf(ctx);
@ -856,7 +924,7 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
wrefresh(self->window);
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
if (ctx->infobox.active) {
draw_infobox(self);
wrefresh(self->window);
@ -938,7 +1006,7 @@ ToxWindow new_chat(Tox *m, int32_t friendnum)
ret.onFileControl = &chat_onFileControl;
ret.onFileData = &chat_onFileData;
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
ret.onInvite = &chat_onInvite;
ret.onRinging = &chat_onRinging;
ret.onStarting = &chat_onStarting;
@ -953,8 +1021,12 @@ ToxWindow new_chat(Tox *m, int32_t friendnum)
ret.call_idx = -1;
ret.device_selection[0] = ret.device_selection[1] = -1;
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
#ifdef _SOUND_NOTIFY
ret.active_sound = -1;
#endif /* _SOUND_NOTIFY */
char nick[TOX_MAX_NAME_LENGTH];
int n_len = get_nick_truncate(m, nick, friendnum);
chat_set_window_name(&ret, nick, n_len);

View File

@ -31,7 +31,7 @@ void cmd_join_group(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR
void cmd_savefile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_sendfile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
void cmd_call(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_answer(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_reject(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
@ -40,6 +40,6 @@ void cmd_cancel(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZ
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 /* _AUDIO */
#endif /* #define _chat_commands_h */

View File

@ -31,51 +31,53 @@
#include "configdir.h"
/**
* @brief Get the users config directory.
*
* This is without a trailing slash.
*
* @return The users config dir or NULL on error.
*/
char *get_user_config_dir(void)
/* get the user's home directory */
void get_home_dir(char *home, int size)
{
char *user_config_dir;
#ifndef NSS_BUFLEN_PASSWD
#define NSS_BUFLEN_PASSWD 4096
#endif /* NSS_BUFLEN_PASSWD */
struct passwd pwd;
struct passwd *pwdbuf;
const char *home;
const char *hmstr;
char buf[NSS_BUFLEN_PASSWD];
size_t len;
int rc;
rc = getpwuid_r(getuid(), &pwd, buf, NSS_BUFLEN_PASSWD, &pwdbuf);
if (rc == 0) {
home = pwd.pw_dir;
hmstr = pwd.pw_dir;
} else {
home = getenv("HOME");
hmstr = getenv("HOME");
if (home == NULL) {
return NULL;
}
if (hmstr == NULL)
return;
/* env variables can be tainted */
snprintf(buf, sizeof(buf), "%s", home);
home = buf;
snprintf(buf, sizeof(buf), "%s", hmstr);
hmstr = buf;
}
snprintf(home, size, "%s", hmstr);
}
/**
* @brief Get the user's config directory.
*
* This is without a trailing slash. Resulting string must be freed.
*
* @return The users config dir or NULL on error.
*/
char *get_user_config_dir(void)
{
char home[NSS_BUFLEN_PASSWD];
get_home_dir(home, sizeof(home));
char *user_config_dir;
size_t len;
# if defined(__APPLE__)
len = strlen(home) + strlen("/Library/Application Support") + 1;
user_config_dir = malloc(len);
if (user_config_dir == NULL) {
if (user_config_dir == NULL)
return NULL;
}
snprintf(user_config_dir, len, "%s/Library/Application Support", home);
# else /* __APPLE__ */
@ -86,9 +88,8 @@ char *get_user_config_dir(void)
len = strlen(home) + strlen("/.config") + 1;
user_config_dir = malloc(len);
if (user_config_dir == NULL) {
if (user_config_dir == NULL)
return NULL;
}
snprintf(user_config_dir, len, "%s/.config", home);
} else {
@ -98,7 +99,6 @@ char *get_user_config_dir(void)
# endif /* __APPLE__ */
return user_config_dir;
#undef NSS_BUFLEN_PASSWD
}
/*

View File

@ -23,6 +23,10 @@
#ifndef _configdir_h
#define _configdir_h
#ifndef NSS_BUFLEN_PASSWD
#define NSS_BUFLEN_PASSWD 4096
#endif
#define CONFIGDIR "/tox/"
#ifndef S_ISDIR
@ -30,7 +34,7 @@
#endif
char *get_user_config_dir(void);
void get_home_dir(char *home, int size);
int create_user_config_dir(char *path);
#endif /* #define _configdir_h */

View File

@ -20,8 +20,14 @@
*
*/
#include "device.h"
#ifdef _AUDIO
#include "audio_call.h"
#endif
#include "line_info.h"
#include "settings.h"
#ifdef __APPLE__
#include <OpenAL/al.h>
@ -37,12 +43,10 @@
#include <stdlib.h>
#include <assert.h>
#include <tox/toxav.h>
#define openal_bufs 5
#define sample_rate 48000
#define OPENAL_BUFS 5
#define inline__ inline __attribute__((always_inline))
#define frame_size (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000)
extern struct user_settings *user_settings_;
typedef struct _Device {
ALCdevice *dhndl; /* Handle of device selected/opened */
@ -51,13 +55,17 @@ typedef struct _Device {
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 */
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 */
pthread_mutex_t mutex[1];
uint32_t sample_rate;
uint32_t frame_duration;
#ifdef _AUDIO
float VAD_treshold; /* 40 is usually recommended value */
#endif
} Device;
const char *ddevice_names[2]; /* Default device */
@ -66,7 +74,9 @@ static int size[2]; /* Size of above containers */
Device *running[2][MAX_DEVICES]; /* Running devices */
uint32_t primary_device[2]; /* Primary device */
#ifdef _AUDIO
static ToxAv* av = NULL;
#endif /* _AUDIO */
/* q_mutex */
#define lock pthread_mutex_lock(&mutex)
@ -79,7 +89,11 @@ _Bool thread_running = _True,
void* thread_poll(void*);
/* Meet devices */
#ifdef _AUDIO
DeviceError init_devices(ToxAv* av_)
#else
DeviceError init_devices()
#endif /* _AUDIO */
{
const char *stringed_device_list;
@ -115,9 +129,11 @@ DeviceError init_devices(ToxAv* av_)
if ( pthread_create(&thread_id, NULL, thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0)
return de_InternalError;
#ifdef _AUDIO
av = av_;
#endif /* _AUDIO */
return (DeviceError) ae_None;
return (DeviceError) de_None;
}
DeviceError terminate_devices()
@ -128,7 +144,7 @@ DeviceError terminate_devices()
pthread_mutex_destroy(&mutex);
return (DeviceError) ae_None;
return (DeviceError) de_None;
}
DeviceError device_mute(DeviceType type, uint32_t device_idx)
@ -149,6 +165,7 @@ DeviceError device_mute(DeviceType type, uint32_t device_idx)
return de_None;
}
#ifdef _AUDIO
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
{
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
@ -166,6 +183,8 @@ DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
unlock;
return de_None;
}
#endif
DeviceError set_primary_device(DeviceType type, int32_t selection)
{
@ -175,28 +194,33 @@ DeviceError set_primary_device(DeviceType type, int32_t selection)
return de_None;
}
DeviceError open_primary_device(DeviceType type, uint32_t* device_idx)
DeviceError open_primary_device(DeviceType type, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration)
{
return open_device(type, primary_device[type], device_idx);
return open_device(type, primary_device[type], device_idx, sample_rate, frame_duration);
}
// TODO: generate buffers separately
DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx)
DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration)
{
if (size[type] <= selection || selection < 0) return de_InvalidSelection;
lock;
const uint32_t frame_size = (sample_rate * frame_duration / 1000);
uint32_t i;
for (i = 0; i < MAX_DEVICES && running[type][i] != NULL; i ++);
if (i == MAX_DEVICES) { unlock; return de_AllDevicesBusy; }
else *device_idx = i;
Device* device = running[type][*device_idx] = calloc(1, sizeof(Device));;
Device* device = running[type][*device_idx] = calloc(1, sizeof(Device));
device->selection = selection;
device->sample_rate = sample_rate;
device->frame_duration = frame_duration;
for (i = 0; i < *device_idx; i ++) { /* Check if any previous has the same selection */
if ( running[type][i]->selection == selection ) {
device->dhndl = running[type][i]->dhndl;
@ -214,8 +238,10 @@ 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 * 2);
device->VAD_treshold = VAD_THRESHOLD_DEFAULT;
sample_rate, AL_FORMAT_MONO16, frame_size * 2);
#ifdef _AUDIO
device->VAD_treshold = user_settings_->VAD_treshold;
#endif
}
else {
device->dhndl = alcOpenDevice(devices_names[type][selection]);
@ -229,18 +255,18 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
device->ctx = alcCreateContext(device->dhndl, NULL);
alcMakeContextCurrent(device->ctx);
alGenBuffers(openal_bufs, device->buffers);
alGenBuffers(OPENAL_BUFS, device->buffers);
alGenSources((uint32_t)1, &device->source);
alSourcei(device->source, AL_LOOPING, AL_FALSE);
uint16_t zeros[frame_size];
memset(zeros, 0, frame_size*2);
for ( i =0; i < openal_bufs; ++i) {
for ( i =0; i < OPENAL_BUFS; ++i) {
alBufferData(device->buffers[i], AL_FORMAT_MONO16, zeros, frame_size*2, sample_rate);
}
alSourceQueueBuffers(device->source, openal_bufs, device->buffers);
alSourceQueueBuffers(device->source, OPENAL_BUFS, device->buffers);
alSourcePlay(device->source);
}
@ -286,7 +312,7 @@ DeviceError close_device(DeviceType type, uint32_t device_idx)
if (alcGetCurrentContext() != device->ctx) alcMakeContextCurrent(device->ctx);
alDeleteSources(1, &device->source);
alDeleteBuffers(openal_bufs, device->buffers);
alDeleteBuffers(OPENAL_BUFS, device->buffers);
if ( !alcCloseDevice(device->dhndl) ) rc = de_AlError;
alcMakeContextCurrent(NULL);
@ -346,7 +372,7 @@ inline__ DeviceError write_out(uint32_t device_idx, int16_t* data, uint32_t leng
}
alBufferData(bufid, AL_FORMAT_MONO16, data, lenght * 2 * channels, av_DefaultSettings.audio_sample_rate);
alBufferData(bufid, AL_FORMAT_MONO16, data, lenght * 2 * channels, device->sample_rate);
alSourceQueueBuffers(device->source, 1, &bufid);
ALint state;
@ -368,7 +394,6 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
uint32_t i;
int32_t sample = 0;
int f_size = frame_size;
while (thread_running)
{
@ -382,6 +407,8 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
{
alcGetIntegerv(running[input][i]->dhndl, ALC_CAPTURE_SAMPLES, sizeof(int32_t), &sample);
int f_size = (running[input][i]->sample_rate * running[input][i]->frame_duration / 1000);
if (sample < f_size) {
unlock;
continue;
@ -391,8 +418,11 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
int16_t frame[4096];
alcCaptureSamples(device->dhndl, frame, f_size);
if ( device->muted ||
(device->enable_VAD && !toxav_has_activity(av, device->call_idx, frame, f_size, device->VAD_treshold)))
if ( device->muted
#ifdef _AUDIO
|| (device->enable_VAD && !toxav_has_activity(av, device->call_idx, frame, f_size, device->VAD_treshold))
#endif /* _AUDIO */
)
{ unlock; continue; } /* Skip if no voice activity */
if ( device->cb ) device->cb(frame, f_size, device->cb_data);

View File

@ -56,7 +56,12 @@ typedef enum DeviceError {
typedef void (*DataHandleCallback) (const int16_t*, uint32_t size, void* data);
#ifdef _AUDIO
DeviceError init_devices(ToxAv* av);
#else
DeviceError init_devices();
#endif /* _AUDIO */
DeviceError terminate_devices();
/* Callback handles ready data from INPUT device */
@ -66,12 +71,14 @@ void* get_device_callback_data(uint32_t device_idx);
/* toggle device mute */
DeviceError device_mute(DeviceType type, uint32_t device_idx);
#ifdef _AUDIO
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value);
#endif
DeviceError set_primary_device(DeviceType type, int32_t selection);
DeviceError open_primary_device(DeviceType type, uint32_t* device_idx);
DeviceError open_primary_device(DeviceType type, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration);
/* Start device */
DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx);
DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration);
/* Stop device */
DeviceError close_device(DeviceType type, uint32_t device_idx);

View File

@ -26,9 +26,9 @@
#include <resolv.h>
#ifdef __APPLE__
#include <arpa/nameser_compat.h>
#include <arpa/nameser_compat.h>
#else
#include <arpa/nameser.h>
#include <arpa/nameser.h>
#endif /* ifdef __APPLE__ */
#include <tox/toxdns.h>

View File

@ -31,6 +31,7 @@
#include "global_commands.h"
#include "line_info.h"
#include "misc_tools.h"
#include "notify.h"
struct cmd_func {
const char *name;
@ -53,10 +54,10 @@ static struct cmd_func global_commands[] = {
{ "/quit", cmd_quit },
{ "/status", cmd_status },
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
{ "/lsdev", cmd_list_devices },
{ "/sdev", cmd_change_device },
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
};
static struct cmd_func chat_commands[] = {
@ -65,7 +66,7 @@ static struct cmd_func chat_commands[] = {
{ "/savefile", cmd_savefile },
{ "/sendfile", cmd_sendfile },
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
{ "/call", cmd_call },
{ "/cancel", cmd_cancel },
{ "/answer", cmd_answer },
@ -74,42 +75,49 @@ static struct cmd_func chat_commands[] = {
{ "/sdev", cmd_ccur_device },
{ "/mute", cmd_mute },
{ "/sense", cmd_sense },
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
};
/* Parses input command and puts args into arg array.
Returns number of arguments on success, -1 on failure. */
static int parse_command(WINDOW *w, ToxWindow *self, char *cmd, char (*args)[MAX_STR_SIZE])
static int parse_command(WINDOW *w, ToxWindow *self, const char *input, char (*args)[MAX_STR_SIZE])
{
char *cmd = strdup(input);
if (cmd == NULL)
exit_toxic_err("failed in parse_command", FATALERR_MEMORY);
int num_args = 0;
bool cmd_end = false; /* flags when we get to the end of cmd */
char *end; /* points to the end of the current arg */
int i = 0; /* index of last char in an argument */
/* characters wrapped in double quotes count as one arg */
while (!cmd_end && num_args < MAX_NUM_ARGS) {
if (*cmd == '\"') {
end = strchr(cmd + 1, '\"');
while (num_args < MAX_NUM_ARGS) {
int qt_ofst = 0; /* set to 1 to offset index for quote char at end of arg */
if (end++ == NULL) { /* Increment past the end quote */
if (*cmd == '\"') {
qt_ofst = 1;
i = char_find(1, cmd, '\"');
if (cmd[i] == '\0') {
char *errmsg = "Invalid argument. Did you forget a closing \"?";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
free(cmd);
return -1;
}
cmd_end = *end == '\0';
} else {
end = strchr(cmd, ' ');
cmd_end = end == NULL;
i = char_find(0, cmd, ' ');
}
if (!cmd_end)
*end++ = '\0'; /* mark end of current argument */
memcpy(args[num_args], cmd, i + qt_ofst);
args[num_args++][i + qt_ofst] = '\0';
/* Copy from start of current arg to where we just inserted the null byte */
strcpy(args[num_args++], cmd);
cmd = end;
if (cmd[i] == '\0') /* no more args */
break;
strcpy(cmd, &cmd[i + 1]);
}
free(cmd);
return num_args;
}
@ -129,13 +137,13 @@ static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, int num_
return 1;
}
void execute(WINDOW *w, ToxWindow *self, Tox *m, char *cmd, int mode)
void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode)
{
if (string_is_empty(cmd))
if (string_is_empty(input))
return;
char args[MAX_NUM_ARGS][MAX_STR_SIZE];
int num_args = parse_command(w, self, cmd, args);
int num_args = parse_command(w, self, input, args);
if (num_args == -1)
return;
@ -158,5 +166,7 @@ void execute(WINDOW *w, ToxWindow *self, Tox *m, char *cmd, int mode)
if (do_command(w, self, m, num_args, GLOBAL_NUM_COMMANDS, global_commands, args) == 0)
return;
line_info_add(self, NULL, NULL, NULL, "Invalid command.", SYS_MSG, 0, 0);
/* Just play sound instead */
/*line_info_add(self, NULL, NULL, NULL, "Invalid command.", SYS_MSG, 0, 0);*/
notify(self, error, 0);
}

View File

@ -28,13 +28,13 @@
#define MAX_NUM_ARGS 4 /* Includes command */
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
#define GLOBAL_NUM_COMMANDS 16
#define CHAT_NUM_COMMANDS 12
#else
#define GLOBAL_NUM_COMMANDS 14
#define CHAT_NUM_COMMANDS 4
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
enum {
GLOBAL_COMMAND_MODE,
@ -42,6 +42,6 @@ enum {
GROUPCHAT_COMMAND_MODE,
};
void execute(WINDOW *w, ToxWindow *self, Tox *m, char *cmd, int mode);
void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode);
#endif /* #define _execute_h */

View File

@ -30,6 +30,7 @@
#include "file_senders.h"
#include "line_info.h"
#include "misc_tools.h"
#include "notify.h"
FileSender file_senders[MAX_FILES];
uint8_t max_file_senders_index;
@ -48,10 +49,9 @@ static void set_max_file_senders_index(void)
static void close_file_sender(ToxWindow *self, Tox *m, int i, char *msg, int CTRL, int filenum, int32_t friendnum)
{
if (self->chatwin != NULL) {
if (self->chatwin != NULL)
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
alert_window(file_senders[i].toxwin, WINDOW_ALERT_2, true);
}
tox_file_send_control(m, friendnum, 0, filenum, CTRL, 0, 0);
fclose(file_senders[i].file);
@ -94,6 +94,7 @@ void do_file_senders(Tox *m)
if (timed_out(file_senders[i].timestamp, get_unix_time(), TIMEOUT_FILESENDER)) {
snprintf(msg, sizeof(msg), "File transfer for '%s' timed out.", pathname);
close_file_sender(self, m, i, msg, TOX_FILECONTROL_KILL, filenum, friendnum);
notify(self, error, NT_NOFOCUS | NT_WNDALERT_2);
continue;
}
@ -122,6 +123,7 @@ void do_file_senders(Tox *m)
if (file_senders[i].piecelen == 0) {
snprintf(msg, sizeof(msg), "File '%s' successfuly sent.", pathname);
close_file_sender(self, m, i, msg, TOX_FILECONTROL_FINISHED, filenum, friendnum);
notify(self, transfer_completed, NT_NOFOCUS | NT_WNDALERT_2);
break;
}
}

View File

@ -34,11 +34,13 @@
#include "misc_tools.h"
#include "line_info.h"
#include "settings.h"
#include "notify.h"
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
#include "audio_call.h"
#endif
extern char *DATA_FILE;
extern ToxWindow *prompt;
@ -47,7 +49,7 @@ static int num_selected = 0;
static int num_friends = 0;
extern struct _Winthread Winthread;
extern struct user_settings *user_settings;
extern struct user_settings *user_settings_;
ToxicFriend friends[MAX_FRIENDS_NUM];
static int friendlist_index[MAX_FRIENDS_NUM] = {0};
@ -91,7 +93,7 @@ static void update_friend_last_online(int32_t num, uint64_t timestamp)
friends[num].last_online.tm = *localtime((const time_t*)&timestamp);
/* if the format changes make sure TIME_STR_SIZE is the correct size */
const char *t = user_settings->time == TIME_12 ? "%I:%M %p" : "%H:%M";
const char *t = user_settings_->time == TIME_12 ? "%I:%M %p" : "%H:%M";
strftime(friends[num].last_online.hour_min_str, TIME_STR_SIZE, t,
&friends[num].last_online.tm);
}
@ -104,6 +106,7 @@ static void friendlist_onMessage(ToxWindow *self, Tox *m, int32_t num, const cha
if (friends[num].chatwin == -1) {
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
friends[num].chatwin = add_window(m, new_chat(m, friends[num].num));
notify(self, generic_message, NT_NOFOCUS);
} else {
char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, num);
@ -115,7 +118,7 @@ static void friendlist_onMessage(ToxWindow *self, Tox *m, int32_t num, const cha
char *msg = "* Warning: Too many windows are open.";
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, RED);
alert_window(prompt, WINDOW_ALERT_1, true);
notify(prompt, error, NT_WNDALERT_1);
}
}
}
@ -176,7 +179,7 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_t num, bool sort)
friends[i].chatwin = -1;
friends[i].online = false;
friends[i].status = TOX_USERSTATUS_NONE;
friends[i].logging_on = (bool) user_settings->autolog == AUTOLOG_ON;
friends[i].logging_on = (bool) user_settings_->autolog == AUTOLOG_ON;
tox_get_client_id(m, num, (uint8_t *) friends[i].pub_key);
update_friend_last_online(i, tox_get_last_online(m, i));
@ -213,6 +216,7 @@ static void friendlist_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, u
if (friends[num].chatwin == -1) {
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
friends[num].chatwin = add_window(m, new_chat(m, friends[num].num));
notify(self, transfer_pending, NT_NOFOCUS);
} else {
tox_file_send_control(m, num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0);
@ -222,8 +226,8 @@ static void friendlist_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, u
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "* File transfer from %s failed: too many windows are open.", nick);
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, RED);
alert_window(prompt, WINDOW_ALERT_1, true);
notify(prompt, error, NT_WNDALERT_1);
}
}
}
@ -236,6 +240,8 @@ static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, const
if (friends[num].chatwin == -1) {
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
friends[num].chatwin = add_window(m, new_chat(m, friends[num].num));
notify(self, generic_message, NT_NOFOCUS);
} else {
char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, num);
@ -243,8 +249,8 @@ static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, const
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "* Group chat invite from %s failed: too many windows are open.", nick);
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, RED);
alert_window(prompt, WINDOW_ALERT_1, true);
notify(prompt, error, NT_WNDALERT_1);
}
}
}
@ -348,7 +354,7 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
char *msg = "* Warning: Too many windows are open.";
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, RED);
alert_window(prompt, WINDOW_ALERT_1, true);
notify(prompt, error, NT_WNDALERT_1);
}
} else if (key == KEY_DC) {
del_friend_activate(self, m, f);
@ -545,7 +551,7 @@ void disable_chatwin(int32_t f_num)
friends[f_num].chatwin = -1;
}
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
static void friendlist_onAv(ToxWindow *self, ToxAv *av, int call_index)
{
int id = toxav_get_peer_id(av, call_index, 0);
@ -558,8 +564,9 @@ static void friendlist_onAv(ToxWindow *self, ToxAv *av, int call_index)
if (friends[id].chatwin == -1) {
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
if (toxav_get_call_state(av, call_index) == av_CallStarting) /* Only open windows when call is incoming */
if (toxav_get_call_state(av, call_index) == av_CallStarting) { /* Only open windows when call is incoming */
friends[id].chatwin = add_window(m, new_chat(m, friends[id].num));
}
} else {
char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, friends[id].num);
@ -570,12 +577,12 @@ static void friendlist_onAv(ToxWindow *self, ToxAv *av, int call_index)
char *errmsg = "* Warning: Too many windows are open.";
line_info_add(prompt, NULL, NULL, NULL, errmsg, SYS_MSG, 0, RED);
alert_window(prompt, WINDOW_ALERT_0, true);
notify(prompt, error, NT_WNDALERT_1);
}
}
}
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
ToxWindow new_friendlist(void)
{
@ -597,7 +604,7 @@ ToxWindow new_friendlist(void)
ret.onFileSendRequest = &friendlist_onFileSendRequest;
ret.onGroupInvite = &friendlist_onGroupInvite;
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
ret.onInvite = &friendlist_onAv;
ret.onRinging = &friendlist_onAv;
ret.onStarting = &friendlist_onAv;
@ -612,8 +619,12 @@ ToxWindow new_friendlist(void)
ret.call_idx = -1;
ret.device_selection[0] = ret.device_selection[1] = -1;
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
#ifdef _SOUND_NOTIFY
ret.active_sound = -1;
#endif /* _SOUND_NOTIFY */
strcpy(ret.name, "contacts");
return ret;
}

View File

@ -41,9 +41,9 @@ void cmd_status(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZ
void cmd_add_helper(ToxWindow *self, Tox *m, char *id_bin, char *msg);
#ifdef _SUPPORT_AUDIO
#ifdef _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 /* _AUDIO */
#endif /* #define _global_commands_h */

View File

@ -41,13 +41,15 @@
#include "settings.h"
#include "input.h"
#include "help.h"
#include "notify.h"
#include "autocomplete.h"
extern char *DATA_FILE;
static GroupChat groupchats[MAX_GROUPCHAT_NUM];
static int max_groupchat_index = 0;
extern struct user_settings *user_settings;
extern struct user_settings *user_settings_;
/* temporary until group chats have unique commands */
extern const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE];
@ -134,25 +136,18 @@ static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, int groupnum, int
n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH - 1); /* enforce client max name length */
nick[n_len] = '\0';
/* check if message contains own name and alert appropriately */
int alert_type = WINDOW_ALERT_1;
bool beep = false;
char selfnick[TOX_MAX_NAME_LENGTH];
uint16_t sn_len = tox_get_self_name(m, (uint8_t *) selfnick);
selfnick[sn_len] = '\0';
int nick_clr = strcmp(nick, selfnick) == 0 ? GREEN : CYAN;
bool nick_match = strcasestr(msg, selfnick) && strncmp(selfnick, nick, TOXIC_MAX_NAME_LENGTH - 1);
if (nick_match) {
alert_type = WINDOW_ALERT_0;
beep = true;
/* Only play sound if mentioned */
if (strcasestr(msg, selfnick) && strncmp(selfnick, nick, TOXIC_MAX_NAME_LENGTH - 1)) {
notify(self, generic_message, NT_WNDALERT_0);
nick_clr = RED;
}
alert_window(self, alert_type, beep);
else notify(self, silent, NT_WNDALERT_1);
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
@ -169,22 +164,14 @@ static void groupchat_onGroupAction(ToxWindow *self, Tox *m, int groupnum, int p
ChatContext *ctx = self->chatwin;
/* check if message contains own name and alert appropriately */
int alert_type = WINDOW_ALERT_1;
bool beep = false;
char selfnick[TOX_MAX_NAME_LENGTH];
uint16_t n_len = tox_get_self_name(m, (uint8_t *) selfnick);
selfnick[n_len] = '\0';
bool nick_match = strcasestr(action, selfnick);
if (nick_match) {
alert_type = WINDOW_ALERT_0;
beep = true;
if (strcasestr(action, selfnick)) {
notify(self, generic_message, NT_WNDALERT_0);
}
alert_window(self, alert_type, beep);
else notify(self, silent, NT_WNDALERT_1);
char nick[TOX_MAX_NAME_LENGTH];
n_len = tox_group_peername(m, groupnum, peernum, (uint8_t *) nick);
@ -317,7 +304,7 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu
break;
}
alert_window(self, WINDOW_ALERT_2, false);
notify(self, silent, NT_WNDALERT_2);
}
static void send_group_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
@ -365,17 +352,15 @@ 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, groupchats[self->num].peer_names,
diff = complete_line(self, groupchats[self->num].peer_names,
groupchats[self->num].num_peers, TOX_MAX_NAME_LENGTH);
else
diff = complete_line(ctx, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
diff = complete_line(self, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
if (diff != -1) {
if (x + diff > x2 - 1) {
wmove(self->window, y, x + diff);
ctx->start += diff;
} else {
wmove(self->window, y, x + diff);
int wlen = wcswidth(ctx->line, sizeof(ctx->line));
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
}
} else {
beep();
@ -502,7 +487,7 @@ static void groupchat_onInit(ToxWindow *self, Tox *m)
line_info_init(ctx->hst);
if (user_settings->autolog == AUTOLOG_ON)
if (user_settings_->autolog == AUTOLOG_ON)
log_enable(self->name, NULL, ctx->log);
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);

View File

@ -144,14 +144,14 @@ static void help_draw_global(ToxWindow *self)
wprintw(win, " /close : Close the current chat window\n");
wprintw(win, " /quit or /exit : Exit Toxic\n");
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
wattron(win, A_BOLD);
wprintw(win, "\n Audio:\n");
wattroff(win, A_BOLD);
wprintw(win, " /lsdev <type> : List devices where type: in|out\n");
wprintw(win, " /sdev <type> <id> : Set active device\n");
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
help_draw_bottom_menu(win);
@ -174,7 +174,7 @@ static void help_draw_chat(ToxWindow *self)
wprintw(win, " /sendfile <path> : Send a file\n");
wprintw(win, " /savefile <n> : Receive a file\n");
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
wattron(win, A_BOLD);
wprintw(win, "\n Audio:\n");
wattroff(win, A_BOLD);
@ -187,7 +187,7 @@ static void help_draw_chat(ToxWindow *self)
wprintw(win, " /sdev <type> <id> : Change active device\n");
wprintw(win, " /mute <type> : Mute active device if in call\n");
wprintw(win, " /sense <n> : VAD sensitivity treshold\n");
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
help_draw_bottom_menu(win);
@ -226,7 +226,7 @@ void help_onKey(ToxWindow *self, wint_t key)
break;
case 'c':
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
help_init_window(self, 19, 80);
#else
help_init_window(self, 9, 80);
@ -235,7 +235,7 @@ void help_onKey(ToxWindow *self, wint_t key)
break;
case 'g':
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
help_init_window(self, 21, 80);
#else
help_init_window(self, 17, 80);

View File

@ -185,7 +185,8 @@ static void input_history(ToxWindow *self, wint_t key, int mx_x)
ChatContext *ctx = self->chatwin;
fetch_hist_item(ctx, key);
ctx->start = mx_x * (ctx->len / mx_x);
int wlen = wcswidth(ctx->line, sizeof(ctx->line));
ctx->start = wlen < mx_x ? 0 : wlen - mx_x + 1;
}
/* Handles non-printable input keys that behave the same for all types of chat windows.

View File

@ -30,7 +30,7 @@
#include "groupchat.h"
#include "settings.h"
extern struct user_settings *user_settings;
extern struct user_settings *user_settings_;
void line_info_init(struct history *hst)
{
@ -207,7 +207,7 @@ static void line_info_check_queue(ToxWindow *self)
if (line == NULL)
return;
if (hst->start_id > user_settings->history_size)
if (hst->start_id > user_settings_->history_size)
line_info_root_fwd(hst);
line->id = hst->line_end->id + 1;

View File

@ -31,7 +31,7 @@
#include "log.h"
#include "settings.h"
extern struct user_settings *user_settings;
extern struct user_settings *user_settings_;
/* Creates/fetches log file by appending to the config dir the name and a pseudo-unique identity */
void init_logging_session(char *name, char *key, struct chatlog *log)
@ -99,7 +99,7 @@ void write_to_log(const char *msg, char *name, struct chatlog *log, bool event)
else
snprintf(name_frmt, sizeof(name_frmt), "%s:", name);
const char *t = user_settings->time == TIME_12 ? "%Y/%m/%d [%I:%M:%S %p]" : "%Y/%m/%d [%H:%M:%S]";
const char *t = user_settings_->time == TIME_12 ? "%Y/%m/%d [%I:%M:%S %p]" : "%Y/%m/%d [%H:%M:%S]";
char s[MAX_STR_SIZE];
strftime(s, MAX_STR_SIZE, t, get_time());
fprintf(log->file, "%s %s %s\n", s, name_frmt, msg);

View File

@ -25,6 +25,7 @@
#include <string.h>
#include <time.h>
#include <limits.h>
#include <dirent.h>
#include "toxic.h"
#include "windows.h"
@ -32,7 +33,7 @@
#include "settings.h"
extern ToxWindow *prompt;
extern struct user_settings *user_settings;
extern struct user_settings *user_settings_;
static uint64_t current_unix_time;
@ -64,12 +65,12 @@ struct tm *get_time(void)
/*Puts the current time in buf in the format of [HH:mm:ss] */
void get_time_str(char *buf, int bufsize)
{
if (user_settings->timestamps == TIMESTAMPS_OFF) {
if (user_settings_->timestamps == TIMESTAMPS_OFF) {
buf[0] = '\0';
return;
}
const char *t = user_settings->time == TIME_12 ? "[%-I:%M:%S] " : "[%H:%M:%S] ";
const char *t = user_settings_->time == TIME_12 ? "[%-I:%M:%S] " : "[%H:%M:%S] ";
strftime(buf, bufsize, t, get_time());
}
@ -108,7 +109,7 @@ char *hex_string_to_bin(const char *hex_string)
}
/* Returns 1 if the string is empty, 0 otherwise */
int string_is_empty(char *string)
int string_is_empty(const char *string)
{
return string[0] == '\0';
}
@ -141,29 +142,6 @@ int wcs_to_mbs_buf(char *buf, const wchar_t *string, size_t n)
return len;
}
/* Colours the window tab according to type. Beeps if is_beep is true */
void alert_window(ToxWindow *self, int type, bool is_beep)
{
switch (type) {
case WINDOW_ALERT_0:
self->alert0 = true;
break;
case WINDOW_ALERT_1:
self->alert1 = true;
break;
case WINDOW_ALERT_2:
self->alert2 = true;
break;
}
StatusBar *stb = prompt->stb;
if (is_beep && stb->status != TOX_USERSTATUS_BUSY && user_settings->alerts == ALERTS_ENABLED)
beep();
}
/* case-insensitive string compare function for use with qsort */
int qsort_strcasecmp_hlpr(const void *nick1, const void *nick2)
{
@ -197,23 +175,29 @@ int valid_nick(char *nick)
void get_file_name(char *namebuf, int bufsize, const char *pathname)
{
int idx = strlen(pathname) - 1;
char *path = strdup(pathname);
char tmpname[MAX_STR_SIZE];
snprintf(tmpname, sizeof(tmpname), "%s", pathname);
if (path == NULL)
exit_toxic_err("failed in get_file_name", FATALERR_MEMORY);
while (idx >= 0 && pathname[idx] == '/')
tmpname[idx--] = '\0';
path[idx--] = '\0';
char *filename = strrchr(tmpname, '/');
char *finalname = strdup(path);
if (filename != NULL) {
if (!strlen(++filename))
filename = tmpname;
} else {
filename = tmpname;
if (finalname == NULL)
exit_toxic_err("failed in get_file_name", FATALERR_MEMORY);
const char *basenm = strrchr(path, '/');
if (basenm != NULL) {
if (basenm[1])
strcpy(finalname, &basenm[1]);
}
snprintf(namebuf, bufsize, "%s", filename);
snprintf(namebuf, bufsize, "%s", finalname);
free(finalname);
free(path);
}
/* converts str to all lowercase */
@ -234,3 +218,31 @@ int get_nick_truncate(Tox *m, char *buf, int friendnum)
buf[len] = '\0';
return len;
}
/* returns index of the first instance of ch in s starting at idx.
returns length of s if char not found */
int char_find(int idx, const char *s, char ch)
{
int i = idx;
for (i = idx; s[i]; ++i) {
if (s[i] == ch)
break;
}
return i;
}
/* returns index of the last instance of ch in s starting at len
returns 0 if char not found (skips 0th index) */
int char_rfind(const char *s, char ch, int len)
{
int i = 0;
for (i = len; i > 0; --i) {
if (s[i] == ch)
break;
}
return i;
}

View File

@ -52,7 +52,7 @@ struct tm *get_time(void);
void update_unix_time(void);
/* Returns 1 if the string is empty, 0 otherwise */
int string_is_empty(char *string);
int string_is_empty(const char *string);
/* convert a multibyte string to a wide character string (must provide buffer) */
int char_to_wcs_buf(wchar_t *buf, const char *string, size_t n);
@ -89,4 +89,12 @@ void str_to_lower(char *str);
Returns nick len on success, -1 on failure */
int get_nick_truncate(Tox *m, char *buf, int friendnum);
/* returns index of the first instance of ch in s starting at idx.
returns length of s if char not found */
int char_find(int idx, const char *s, char ch);
/* returns index of the last instance of ch in s
returns 0 if char not found */
int char_rfind(const char *s, char ch, int len);
#endif /* #define _misc_tools_h */

335
src/notify.c Normal file
View File

@ -0,0 +1,335 @@
/* notify.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/>.
*
*/
#include "notify.h"
#include "device.h"
#include "settings.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <sys/stat.h>
#ifdef __APPLE__
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#ifdef _SOUND_NOTIFY
#include <OpenAL/alut.h> /* Is this good? */
#endif
#else
#include <AL/al.h>
#include <AL/alc.h>
#ifdef _SOUND_NOTIFY
#include <AL/alut.h> /* freealut packet */
#endif
#endif
#ifdef _X11
#include <X11/Xlib.h>
#endif /* _X11 */
#define SOUNDS_SIZE 10
#define ACTIVE_SOUNDS_MAX 50
extern struct user_settings *user_settings_;
struct _Control {
time_t cooldown;
unsigned long this_window;
#ifdef _X11
Display *display;
#endif /* _X11 */
#ifdef _SOUND_NOTIFY
pthread_mutex_t poll_mutex[1];
uint32_t device_idx; /* index of output device */
_Bool poll_active;
char* sounds[SOUNDS_SIZE];
#endif /* _SOUND_NOTIFY */
} Control = {0};
#ifdef _SOUND_NOTIFY
struct _ActiveSounds {
uint32_t source;
uint32_t buffer;
_Bool active;
_Bool looping;
} actives[ACTIVE_SOUNDS_MAX] = {{0}};
#endif
/**********************************************************************************/
/**********************************************************************************/
/**********************************************************************************/
/**********************************************************************************/
/**********************************************************************************/
long unsigned int get_focused_window_id()
{
#ifdef _X11
if (!Control.display) return 0;
Window focus;
int revert;
XGetInputFocus(Control.display, &focus, &revert);
return focus;
#else
return 0;
#endif /* _X11 */
}
#ifdef _SOUND_NOTIFY
_Bool is_playing(int source)
{
int ready;
alGetSourcei(source, AL_SOURCE_STATE, &ready);
return ready == AL_PLAYING;
}
/* Terminate all sounds but wait them to finish first */
void graceful_clear()
{
int i;
pthread_mutex_lock(Control.poll_mutex);
while (1) {
for (i = 0; i < ACTIVE_SOUNDS_MAX; i ++) {
if (actives[i].active) {
if ( actives[i].looping ) {
stop_sound(i);
} else {
if (!is_playing(actives[i].source))
memset(&actives[i], 0, sizeof(struct _ActiveSounds));
else break;
}
}
}
if (i == ACTIVE_SOUNDS_MAX) {
pthread_mutex_unlock(Control.poll_mutex);
return;
}
usleep(1000);
}
}
void* do_playing(void* _p)
{
(void)_p;
int i;
while(Control.poll_active) {
pthread_mutex_lock(Control.poll_mutex);
for (i = 0; i < ACTIVE_SOUNDS_MAX; i ++) {
if (actives[i].active && !actives[i].looping) {
if (!is_playing(actives[i].source)) {
/* Close */
alSourceStop(actives[i].source);
alDeleteSources(1, &actives[i].source);
alDeleteBuffers(1,&actives[i].buffer);
memset(&actives[i], 0, sizeof(struct _ActiveSounds));
}
}
}
pthread_mutex_unlock(Control.poll_mutex);
usleep(10000);
}
pthread_exit(NULL);
}
int play_source(uint32_t source, uint32_t buffer, _Bool looping)
{
pthread_mutex_lock(Control.poll_mutex);
int i = 0;
for (; i < ACTIVE_SOUNDS_MAX && actives[i].active; i ++);
if ( i == ACTIVE_SOUNDS_MAX ) {
pthread_mutex_unlock(Control.poll_mutex);
return -1; /* Full */
}
alSourcePlay(source);
actives[i].active = 1;
actives[i].source = source;
actives[i].buffer = buffer;
actives[i].looping = looping;
pthread_mutex_unlock(Control.poll_mutex);
return i;
}
#endif
/**********************************************************************************/
/**********************************************************************************/
/**********************************************************************************/
/**********************************************************************************/
/**********************************************************************************/
/* Opens primary device */
int init_notify(int login_cooldown)
{
#ifdef _SOUND_NOTIFY
alutInitWithoutContext(NULL, NULL);
if (open_primary_device(output, &Control.device_idx, 48000, 20) != de_None)
return -1;
pthread_mutex_init(Control.poll_mutex, NULL);
pthread_t thread;
if (pthread_create(&thread, NULL, do_playing, NULL) != 0 || pthread_detach(thread) != 0 ) {
pthread_mutex_destroy(Control.poll_mutex);
return -1;
}
Control.poll_active = 1;
#endif /* _SOUND_NOTIFY */
Control.cooldown = time(NULL) + login_cooldown;
#ifdef _X11
Control.display = XOpenDisplay(NULL);
Control.this_window = get_focused_window_id();
#else
Control.this_window = 1;
#endif /* _X11 */
return 1;
}
void terminate_notify()
{
#ifdef _SOUND_NOTIFY
if ( !Control.poll_active ) return;
Control.poll_active = 0;
int i = 0;
for (; i < SOUNDS_SIZE; i ++) free(Control.sounds[i]);
graceful_clear();
close_device(output, Control.device_idx);
alutExit();
#endif /* _SOUND_NOTIFY */
}
#ifdef _SOUND_NOTIFY
int set_sound(Notification sound, const char* value)
{
free(Control.sounds[sound]);
size_t len = strlen(value) + 1;
Control.sounds[sound] = calloc(1, len);
memcpy(Control.sounds[sound], value, len);
struct stat buf;
return stat(value, &buf) == 0;
}
int play_sound_internal(Notification what, _Bool loop)
{
uint32_t source;
uint32_t buffer;
alGenSources(1, &source);
alGenBuffers(1, &buffer);
buffer = alutCreateBufferFromFile((const char*)Control.sounds[what]);
alSourcei(source, AL_BUFFER, buffer);
alSourcei(source, AL_LOOPING, loop);
int rc = play_source(source, buffer, loop);
if (rc < 0) {
alSourceStop(source);
alDeleteSources(1, &source);
alDeleteBuffers(1,&buffer);
return -1;
}
return rc;
}
int play_notify_sound(Notification notif, uint64_t flags)
{
int rc = 0;
if (flags & NT_BEEP) beep();
else if (notif != silent) {
if ( !Control.poll_active || (flags & NT_RESTOL && Control.cooldown > time(NULL)) || !Control.sounds[notif] )
return -1;
rc = play_sound_internal(notif, flags & NT_LOOP ? 1 : 0);
}
return rc;
}
void stop_sound(int sound)
{
if (sound >= 0 && sound < ACTIVE_SOUNDS_MAX && actives[sound].looping && actives[sound].active) {
alSourcei(actives[sound].source, AL_LOOPING, false);
alSourceStop(actives[sound].source);
alDeleteSources(1, &actives[sound].source);
alDeleteBuffers(1,&actives[sound].buffer);
memset(&actives[sound], 0, sizeof(struct _ActiveSounds));
}
}
#endif
static int m_play_sound(Notification notif, uint64_t flags)
{
#ifdef _SOUND_NOTIFY
return play_notify_sound(notif, flags);
#else
if (notif != silent)
beep();
return -1;
#endif /* _SOUND_NOTIFY */
}
int notify(ToxWindow* self, Notification notif, uint64_t flags)
{
if (flags & NT_NOFOCUS && Control.this_window == get_focused_window_id())
return -1;
int rc = -1;
if (self && (!self->stb || self->stb->status != TOX_USERSTATUS_BUSY) && user_settings_->alerts == ALERTS_ENABLED)
rc = m_play_sound(notif, flags);
else if (flags & NT_ALWAYS)
rc = m_play_sound(notif, flags);
if (flags & NT_NOTIFWND) {
/* TODO: pop notify window */
}
if (self && self->alert == WINDOW_ALERT_NONE) {
if (flags & NT_WNDALERT_0) self->alert = WINDOW_ALERT_0;
else if (flags & NT_WNDALERT_1) self->alert = WINDOW_ALERT_1;
else if (flags & NT_WNDALERT_2) self->alert = WINDOW_ALERT_2;
}
return rc;
}

73
src/notify.h Normal file
View File

@ -0,0 +1,73 @@
/* notify.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 _notify_h
#define _notify_h
#include <inttypes.h>
#include "windows.h"
typedef enum _Notification
{
silent = -1,
error,
self_log_in,
self_log_out,
user_log_in,
user_log_out,
call_incoming,
call_outgoing,
generic_message,
transfer_pending,
transfer_completed,
} Notification;
typedef enum _Flags {
NT_NOFOCUS = 1 << 0, /* Notify when focus is not on this terminal. NOTE: only works with x11,
* if no x11 present this flag is ignored
*/
NT_BEEP = 1 << 1, /* Play native sound instead: \a */
NT_LOOP = 1 << 2, /* Loop sound. If this setting active, notify() will return id of the sound
* so it could be stopped. It will return 0 if error or NT_NATIVE flag is set and play \a instead
*/
NT_RESTOL = 1 << 3, /* Respect tolerance. Usually used to stop flood at toxic startup
* Only works if login_cooldown is true when calling init_notify()
*/
NT_NOTIFWND = 1 << 4, /* Pop notify window. NOTE: only works(/WILL WORK) if libnotify is present */
NT_WNDALERT_0 = 1 << 5, /* Alert toxic */
NT_WNDALERT_1 = 1 << 6, /* Alert toxic */
NT_WNDALERT_2 = 1 << 7, /* Alert toxic */
NT_ALWAYS = 1 << 8, /* Force sound to play */
} Flags;
int init_notify(int login_cooldown);
void terminate_notify();
int notify(ToxWindow* self, Notification notif, uint64_t flags);
#ifdef _SOUND_NOTIFY
int set_sound(Notification sound, const char* value);
void stop_sound(int sound);
#endif /* _SOUND_NOTIFY */
#endif /* _notify_h */

View File

@ -39,13 +39,15 @@
#include "settings.h"
#include "input.h"
#include "help.h"
#include "notify.h"
#include "autocomplete.h"
char pending_frnd_requests[MAX_FRIENDS_NUM][TOX_CLIENT_ID_SIZE];
uint16_t num_frnd_requests = 0;
extern ToxWindow *prompt;
struct _Winthread Winthread;
extern struct user_settings *user_settings;
extern struct user_settings *user_settings_;
/* Array of global command names used for tab completion. */
const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
@ -57,7 +59,6 @@ const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/exit" },
{ "/groupchat" },
{ "/help" },
{ "/join" },
{ "/log" },
{ "/myid" },
{ "/nick" },
@ -65,12 +66,12 @@ const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/quit" },
{ "/status" },
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
{ "/lsdev" },
{ "/sdev" },
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
};
void kill_prompt_window(ToxWindow *self)
@ -176,14 +177,12 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (key == '\t') { /* TAB key: auto-completes command */
if (ctx->len > 1 && ctx->line[0] == '/') {
int diff = complete_line(ctx, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
int diff = complete_line(self, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
if (diff != -1) {
if (x + diff > x2 - 1) {
wmove(self->window, y, x + diff);
ctx->start += diff;
} else {
wmove(self->window, y, x + diff);
int wlen = wcswidth(ctx->line, sizeof(ctx->line));
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
}
} else {
beep();
@ -309,11 +308,22 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, int32_t friendnum
msg = "has come online";
line_info_add(self, timefrmt, nick, NULL, msg, CONNECTION, 0, GREEN);
write_to_log(msg, nick, ctx->log, true);
alert_window(self, WINDOW_ALERT_2, false);
#ifdef _SOUND_NOTIFY
notify(self, user_log_in, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL);
#else
notify(self, silent, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL);
#endif /* _SOUND_NOTIFY */
} else {
msg = "has gone offline";
line_info_add(self, timefrmt, nick, NULL, msg, CONNECTION, 0, RED);
write_to_log(msg, nick, ctx->log, true);
#ifdef _SOUND_NOTIFY
notify(self, user_log_out, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL);
#else
notify(self, silent, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL);
#endif /* _SOUND_NOTIFY */
}
}
@ -341,7 +351,7 @@ static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, con
snprintf(msg, sizeof(msg), "Type \"/accept %d\" to accept it.", n);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
alert_window(self, WINDOW_ALERT_1, true);
notify(self, generic_message, NT_WNDALERT_1 | NT_NOTIFWND);
}
void prompt_init_statusbar(ToxWindow *self, Tox *m)
@ -372,7 +382,7 @@ void prompt_init_statusbar(ToxWindow *self, Tox *m)
strcpy(ver, TOXICVER);
const char *toxic_ver = strtok(ver, "_");
if ( (!strcmp("Online", statusmsg) || !strncmp("Toxing on Toxic", statusmsg, 15)) && toxic_ver != NULL) {
if ( (!statusmsg[0] || !strncmp("Toxing on Toxic", statusmsg, 15)) && toxic_ver != NULL) {
snprintf(statusmsg, MAX_STR_SIZE, "Toxing on Toxic v.%s", toxic_ver);
s_len = strlen(statusmsg);
statusmsg[s_len] = '\0';
@ -420,7 +430,7 @@ static void prompt_onInit(ToxWindow *self, Tox *m)
line_info_init(ctx->hst);
if (user_settings->autolog == AUTOLOG_ON) {
if (user_settings_->autolog == AUTOLOG_ON) {
char myid[TOX_FRIEND_ADDRESS_SIZE];
tox_get_address(m, (uint8_t *) myid);
log_enable(self->name, myid, ctx->log);

View File

@ -26,11 +26,11 @@
#include "toxic.h"
#include "windows.h"
#ifdef _SUPPORT_AUDIO
#define AC_NUM_GLOB_COMMANDS 17
#ifdef _AUDIO
#define AC_NUM_GLOB_COMMANDS 16
#else
#define AC_NUM_GLOB_COMMANDS 15
#endif /* _SUPPORT_AUDIO */
#define AC_NUM_GLOB_COMMANDS 14
#endif /* _AUDIO */
ToxWindow new_prompt(void);
void prep_prompt_win(void);

View File

@ -22,207 +22,261 @@
#include <stdlib.h>
#include <string.h>
#include <libconfig.h>
#include "toxic.h"
#include "windows.h"
#include "configdir.h"
#include "notify.h"
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
#include "device.h"
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
#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_timestamps(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);
#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);
#ifndef PACKAGE_DATADIR
#define PACKAGE_DATADIR "."
#endif
struct {
const char *key;
void (*func)(struct user_settings *s, const char *val);
} user_settings_list[] = {
{ "autolog", uset_autolog },
{ "time", uset_time },
{ "timestamps", uset_timestamps },
{ "alerts", uset_alerts },
{ "colour_theme", uset_colours },
{ "history_size", uset_hst_size },
{ "download_path", uset_dwnld_path },
#define NO_SOUND "silent"
#ifdef _SUPPORT_AUDIO
{ "audio_in_dev", uset_ain_dev },
{ "audio_out_dev", uset_aout_dev },
#endif
const struct _ui_strings {
const char* self;
const char* timestamps;
const char* alerts;
const char* native_colors;
const char* autolog;
const char* time_format;
const char* history_size;
} ui_strings = {
"ui",
"timestamps",
"alerts",
"native_colors",
"autolog",
"time_format",
"history_size"
};
static void ui_defaults(struct user_settings* settings)
{
settings->timestamps = TIMESTAMPS_ON;
settings->time = TIME_24;
settings->autolog = AUTOLOG_OFF;
settings->alerts = ALERTS_ENABLED;
settings->colour_theme = DFLT_COLS;
settings->history_size = 700;
}
const struct _tox_strings {
const char* self;
const char* download_path;
} tox_strings = {
"tox",
"download_path",
};
static void uset_autolog(struct user_settings *s, const char *val)
static void tox_defaults(struct user_settings* settings)
{
int n = atoi(val);
/* default off if invalid value */
s->autolog = n == AUTOLOG_ON ? AUTOLOG_ON : AUTOLOG_OFF;
strcpy(settings->download_path, ""); /* explicitly set default to pwd */
}
static void uset_time(struct user_settings *s, const char *val)
#ifdef _AUDIO
const struct _audio_strings {
const char* self;
const char* input_device;
const char* output_device;
const char* VAD_treshold;
} audio_strings = {
"audio",
"input_device",
"output_device",
"VAD_treshold",
};
static void audio_defaults(struct user_settings* settings)
{
int n = atoi(val);
/* default to 24 hour time if invalid value */
s->time = n == TIME_12 ? TIME_12 : TIME_24;
settings->audio_in_dev = 0;
settings->audio_out_dev = 0;
settings->VAD_treshold = 40.0;
}
static void uset_timestamps(struct user_settings *s, const char *val)
{
int n = atoi(val);
/* default on if invalid value */
s->timestamps = n == TIMESTAMPS_OFF ? TIMESTAMPS_OFF : TIMESTAMPS_ON;
}
static void uset_alerts(struct user_settings *s, const char *val)
{
int n = atoi(val);
/* alerts default on if invalid value */
s->alerts = n == ALERTS_DISABLED ? ALERTS_DISABLED : ALERTS_ENABLED;
}
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 = n == NATIVE_COLS ? NATIVE_COLS : DFLT_COLS;
}
#ifdef _SUPPORT_AUDIO
static void uset_ain_dev(struct user_settings *s, const char *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, const char *val)
{
int n = atoi(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_timestamps(s, "1");
uset_alerts(s, "1");
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)
#ifdef _SOUND_NOTIFY
const struct _sound_strings {
const char* self;
const char* error;
const char* self_log_in;
const char* self_log_out;
const char* user_log_in;
const char* user_log_out;
const char* call_incoming;
const char* call_outgoing;
const char* generic_message;
const char* transfer_pending;
const char* transfer_completed;
} sound_strings = {
"sounds",
"error",
"self_log_in",
"self_log_out",
"user_log_in",
"user_log_out",
"call_incoming",
"call_outgoing",
"generic_message",
"transfer_pending",
"transfer_completed",
};
#endif
int settings_load(struct user_settings *s, const char *patharg)
{
char *user_config_dir = get_user_config_dir();
FILE *fp = NULL;
char dflt_path[MAX_STR_SIZE];
config_t cfg[1];
config_setting_t *setting;
const char *str;
/* Load default settings */
ui_defaults(s);
tox_defaults(s);
#ifdef _AUDIO
audio_defaults(s);
#endif
config_init(cfg);
if (path) {
fp = fopen(path, "r");
char path[MAX_STR_SIZE];
/* use default config file path */
if (patharg == NULL) {
char *user_config_dir = get_user_config_dir();
snprintf(path, sizeof(path), "%s%stoxic.conf", user_config_dir, CONFIGDIR);
free(user_config_dir);
/* make sure path exists or is created on first time running */
FILE *fp = fopen(path, "r");
if (fp == NULL) {
if ((fp = fopen(path, "w")) == NULL)
return -1;
}
fclose(fp);
} else {
snprintf(dflt_path, sizeof(dflt_path), "%s%stoxic.conf", user_config_dir, CONFIGDIR);
fp = fopen(dflt_path, "r");
snprintf(path, sizeof(path), "%s", patharg);
}
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) {
if (!config_read_file(cfg, path)) {
config_destroy(cfg);
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].key, key) == 0) {
(user_settings_list[i].func)(s, val);
break;
}
/* ui */
if ((setting = config_lookup(cfg, ui_strings.self)) != NULL) {
config_setting_lookup_bool(setting, ui_strings.timestamps, &s->timestamps);
config_setting_lookup_bool(setting, ui_strings.alerts, &s->alerts);
config_setting_lookup_bool(setting, ui_strings.autolog, &s->autolog);
config_setting_lookup_bool(setting, ui_strings.native_colors, &s->colour_theme);
config_setting_lookup_int(setting, ui_strings.history_size, &s->history_size);
config_setting_lookup_int(setting, ui_strings.time_format, &s->time);
s->time = s->time == TIME_24 || s->time == TIME_12 ? s->time : TIME_24; /* Check defaults */
}
if ((setting = config_lookup(cfg, tox_strings.self)) != NULL) {
if ( config_setting_lookup_string(setting, tox_strings.download_path, &str) ) {
strcpy(s->download_path, str);
}
}
#ifdef _AUDIO
if ((setting = config_lookup(cfg, audio_strings.self)) != NULL) {
config_setting_lookup_int(setting, audio_strings.input_device, &s->audio_in_dev);
s->audio_in_dev = s->audio_in_dev < 0 || s->audio_in_dev > MAX_DEVICES ? 0 : s->audio_in_dev;
config_setting_lookup_int(setting, audio_strings.output_device, &s->audio_out_dev);
s->audio_out_dev = s->audio_out_dev < 0 || s->audio_out_dev > MAX_DEVICES ? 0 : s->audio_out_dev;
config_setting_lookup_float(setting, audio_strings.VAD_treshold, &s->VAD_treshold);
}
#endif
fclose(fp);
#ifdef _SOUND_NOTIFY
if ((setting = config_lookup(cfg, sound_strings.self)) != NULL) {
if ( (config_setting_lookup_string(setting, sound_strings.error, &str) != CONFIG_TRUE) ||
!set_sound(error, str) ) {
if (strcasecmp(str, NO_SOUND))
set_sound(error, PACKAGE_DATADIR "/sounds/Error.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.user_log_in, &str) ||
!set_sound(user_log_in, str) ) {
if (strcasecmp(str, NO_SOUND))
set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ContactLogsIn.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.self_log_in, &str) ||
!set_sound(self_log_in, str) ) {
if (strcasecmp(str, NO_SOUND))
set_sound(self_log_in, PACKAGE_DATADIR "/sounds/LogIn.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.user_log_out, &str) ||
!set_sound(user_log_out, str) ) {
if (strcasecmp(str, NO_SOUND))
set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ContactLogsOut.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.self_log_out, &str) ||
!set_sound(self_log_out, str) ) {
if (strcasecmp(str, NO_SOUND))
set_sound(self_log_out, PACKAGE_DATADIR "/sounds/LogOut.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.call_incoming, &str) ||
!set_sound(call_incoming, str) ) {
if (strcasecmp(str, NO_SOUND))
set_sound(call_incoming, PACKAGE_DATADIR "/sounds/IncomingCall.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.call_outgoing, &str) ||
!set_sound(call_outgoing, str) ) {
if (strcasecmp(str, NO_SOUND))
set_sound(call_outgoing, PACKAGE_DATADIR "/sounds/OutgoingCall.wav");
}
if ( config_setting_lookup_string(setting, sound_strings.generic_message, &str) ||
!set_sound(generic_message, str) ) {
if (strcasecmp(str, NO_SOUND))
set_sound(generic_message, PACKAGE_DATADIR "/sounds/NewMessage.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.transfer_pending, &str) ||
!set_sound(transfer_pending, str) ) {
if (strcasecmp(str, NO_SOUND))
set_sound(transfer_pending, PACKAGE_DATADIR "/sounds/TransferPending.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.transfer_completed, &str) ||
!set_sound(transfer_completed, str) ) {
if (strcasecmp(str, NO_SOUND))
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/TransferComplete.wav");
}
}
else {
set_sound(error, PACKAGE_DATADIR "/sounds/Error.wav");
set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ContactLogsIn.wav");
set_sound(self_log_in, PACKAGE_DATADIR "/sounds/LogIn.wav");
set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ContactLogsOut.wav");
set_sound(self_log_out, PACKAGE_DATADIR "/sounds/LogOut.wav");
set_sound(call_incoming, PACKAGE_DATADIR "/sounds/IncomingCall.wav");
set_sound(call_outgoing, PACKAGE_DATADIR "/sounds/OutgoingCall.wav");
set_sound(generic_message, PACKAGE_DATADIR "/sounds/NewMessage.wav");
set_sound(transfer_pending, PACKAGE_DATADIR "/sounds/TransferPending.wav");
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/TransferComplete.wav");
}
#endif
config_destroy(cfg);
return 0;
}

View File

@ -23,14 +23,6 @@
#ifndef _settings_h
#define _settings_h
#include "toxic.h"
#ifdef _SUPPORT_AUDIO
#define NUM_SETTINGS 9
#else
#define NUM_SETTINGS 7
#endif /* _SUPPORT_AUDIO */
/* holds user setting values */
struct user_settings {
int autolog; /* boolean */
@ -41,9 +33,10 @@ struct user_settings {
int history_size; /* int between MIN_HISTORY and MAX_HISTORY */
char download_path[MAX_STR_SIZE];
#ifdef _SUPPORT_AUDIO
long int audio_in_dev;
long int audio_out_dev;
#ifdef _AUDIO
int audio_in_dev;
int audio_out_dev;
double VAD_treshold;
#endif
};
@ -66,6 +59,6 @@ enum {
DFLT_HST_SIZE = 700,
} settings_values;
int settings_load(struct user_settings *s, char *path);
int settings_load(struct user_settings *s, const char *patharg);
#endif /* #define _settings_h */

View File

@ -50,18 +50,20 @@
#include "line_info.h"
#include "settings.h"
#include "log.h"
#include "notify.h"
#include "device.h"
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
#include "audio_call.h"
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
#ifndef PACKAGE_DATADIR
#define PACKAGE_DATADIR "."
#endif
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
ToxAv *av;
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
/* Export for use in Callbacks */
char *DATA_FILE = NULL;
@ -78,7 +80,7 @@ struct arg_opts {
} arg_opts;
struct _Winthread Winthread;
struct user_settings *user_settings = NULL;
struct user_settings *user_settings_ = NULL;
static void catch_SIGINT(int sig)
{
@ -97,11 +99,15 @@ void exit_toxic_success(Tox *m)
kill_all_windows();
free(DATA_FILE);
free(user_settings);
free(user_settings_);
#ifdef _SUPPORT_AUDIO
#ifdef _SOUND_NOTIFY
notify(NULL, self_log_out, NT_ALWAYS);
#endif /* _SOUND_NOTIFY */
terminate_notify();
#ifdef _AUDIO
terminate_audio();
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
tox_kill(m);
endwin();
exit(EXIT_SUCCESS);
@ -141,7 +147,7 @@ static void init_term(void)
short bg_color = COLOR_BLACK;
start_color();
if (user_settings->colour_theme == NATIVE_COLS) {
if (user_settings_->colour_theme == NATIVE_COLS) {
if (assume_default_colors(-1, -1) == OK)
bg_color = -1;
}
@ -369,7 +375,7 @@ static void load_friendlist(Tox *m)
/*
* Store Messenger to given location
* Return 0 stored successfully
* Return 0 stored successfully or ignoring data file
* Return 1 file path is NULL
* Return 2 malloc failed
* Return 3 opening path failed
@ -383,19 +389,15 @@ int store_data(Tox *m, char *path)
if (path == NULL)
return 1;
FILE *fd;
int len;
char *buf;
len = tox_size(m);
buf = malloc(len);
int len = tox_size(m);
char *buf = malloc(len);
if (buf == NULL)
return 2;
tox_save(m, (uint8_t *) buf);
fd = fopen(path, "wb");
FILE *fd = fopen(path, "wb");
if (fd == NULL) {
free(buf);
@ -419,15 +421,13 @@ static void load_data(Tox *m, char *path)
return;
FILE *fd;
int len;
char *buf;
if ((fd = fopen(path, "rb")) != NULL) {
fseek(fd, 0, SEEK_END);
len = ftell(fd);
int len = ftell(fd);
fseek(fd, 0, SEEK_SET);
buf = malloc(len);
char *buf = malloc(len);
if (buf == NULL) {
fclose(fd);
@ -526,6 +526,10 @@ static void parse_args(int argc, char *argv[])
switch (opt) {
case 'f':
DATA_FILE = strdup(optarg);
if (DATA_FILE == NULL)
exit_toxic_err("failed in parse_args", FATALERR_MEMORY);
break;
case 'x':
@ -573,6 +577,9 @@ int main(int argc, char *argv[])
if (DATA_FILE == NULL ) {
if (config_err) {
DATA_FILE = strdup("data");
if (DATA_FILE == NULL)
exit_toxic_err("failed in main", FATALERR_MEMORY);
} else {
DATA_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen("data") + 1);
@ -588,15 +595,13 @@ int main(int argc, char *argv[])
free(user_config_dir);
/* init user_settings struct and load settings from conf file */
user_settings = malloc(sizeof(struct user_settings));
user_settings_ = calloc(1, sizeof(struct user_settings));
if (user_settings == NULL)
if (user_settings_ == NULL)
exit_toxic_err("failed in main", FATALERR_MEMORY);
memset(user_settings, 0, sizeof(struct user_settings));
char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL;
int settings_err = settings_load(user_settings, p);
int settings_err = settings_load(user_settings_, p);
Tox *m = init_tox(arg_opts.use_ipv4);
init_term();
@ -616,17 +621,26 @@ int main(int argc, char *argv[])
if (pthread_create(&Winthread.tid, NULL, thread_winref, (void *) m) != 0)
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
char *msg;
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
av = init_audio(prompt, m);
set_primary_device(input, user_settings->audio_in_dev);
set_primary_device(output, user_settings->audio_out_dev);
set_primary_device(input, user_settings_->audio_in_dev);
set_primary_device(output, user_settings_->audio_out_dev);
#elif _SOUND_NOTIFY
if ( init_devices() == de_InternalError )
line_info_add(prompt, NULL, NULL, NULL, "Failed to init devices", SYS_MSG, 0, 0);
#endif /* _AUDIO */
#endif /* _SUPPORT_AUDIO */
init_notify(60);
#ifdef _SOUND_NOTIFY
notify(prompt, self_log_in, 0);
#endif /* _SOUND_NOTIFY */
char *msg;
if (config_err) {
msg = "Unable to determine configuration directory. Defaulting to 'data' for a keyfile...";
@ -641,7 +655,7 @@ int main(int argc, char *argv[])
sort_friendlist_index();
prompt_init_statusbar(prompt, m);
uint64_t last_save = get_unix_time();
uint64_t last_save = (uint64_t) time(NULL);
while (true) {
update_unix_time();

View File

@ -42,7 +42,7 @@
#define UNKNOWN_NAME "Anonymous"
#define MAX_FRIENDS_NUM 500
#define MAX_FRIENDS_NUM 999
#define MAX_STR_SIZE TOX_MAX_MESSAGE_LENGTH
#define MAX_CMDNAME_SIZE 64
#define TOXIC_MAX_NAME_LENGTH 32 /* Must be <= TOX_MAX_NAME_LENGTH */

View File

@ -208,86 +208,3 @@ void fetch_hist_item(ChatContext *ctx, int key_dir)
ctx->pos = h_len;
ctx->len = h_len;
}
/* 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 line on success, -1 if error */
int complete_line(ChatContext *ctx, const void *list, int n_items, int size)
{
if (ctx->pos <= 0 || ctx->len <= 0 || ctx->len >= MAX_STR_SIZE)
return -1;
const char *L = (char *) list;
char ubuf[MAX_STR_SIZE];
/* work with multibyte string copy of buf for simplicity */
if (wcs_to_mbs_buf(ubuf, ctx->line, sizeof(ubuf)) == -1)
return -1;
/* isolate substring from space behind pos to pos */
char tmp[MAX_STR_SIZE];
snprintf(tmp, sizeof(tmp), "%s", ubuf);
tmp[ctx->pos] = '\0';
char *sub = strrchr(tmp, ' ');
int n_endchrs = 1; /* 1 = append space to end of match, 2 = append ": " */
if (!sub++) {
sub = tmp;
if (sub[0] != '/') /* make sure it's not a command */
n_endchrs = 2;
}
if (string_is_empty(sub))
return -1;
int s_len = strlen(sub);
const char *match;
bool is_match = false;
int i;
/* look for a match in list */
for (i = 0; i < n_items; ++i) {
match = &L[i * size];
if ((is_match = strncasecmp(match, sub, s_len) == 0))
break;
}
if (!is_match)
return -1;
/* put match in correct spot in buf and append endchars (space or ": ") */
const char *endchrs = n_endchrs == 1 ? " " : ": ";
int m_len = strlen(match);
int strt = ctx->pos - s_len;
int diff = m_len - s_len + n_endchrs;
if (ctx->len + diff > MAX_STR_SIZE)
return -1;
char tmpend[MAX_STR_SIZE];
strcpy(tmpend, &ubuf[ctx->pos]);
strcpy(&ubuf[strt], match);
strcpy(&ubuf[strt + m_len], endchrs);
strcpy(&ubuf[strt + m_len + n_endchrs], tmpend);
/* convert to widechar and copy back to original buf */
wchar_t newbuf[MAX_STR_SIZE];
if (mbs_to_wcs_buf(newbuf, ubuf, MAX_STR_SIZE) == -1)
return -1;
wcscpy(ctx->line, newbuf);
ctx->len += diff;
ctx->pos += diff;
return diff;
}

View File

@ -52,16 +52,6 @@ int yank_buf(ChatContext *ctx);
/* 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 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(ChatContext *ctx);

View File

@ -355,12 +355,12 @@ void on_window_resize(void)
w->stb->topline = subwin(w->window, 2, x2, 0, 0);
}
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
if (w->chatwin->infobox.active) {
delwin(w->chatwin->infobox.win);
w->chatwin->infobox.win = newwin(INFOBOX_HEIGHT, INFOBOX_WIDTH + 1, 1, x2 - INFOBOX_WIDTH);
}
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
scrollok(w->chatwin->history, 0);
}
@ -368,23 +368,11 @@ void on_window_resize(void)
static void draw_window_tab(ToxWindow toxwin)
{
/* alert0 takes priority */
if (toxwin.alert0)
attron(COLOR_PAIR(GREEN));
else if (toxwin.alert1)
attron(COLOR_PAIR(RED));
else if (toxwin.alert2)
attron(COLOR_PAIR(MAGENTA));
if (toxwin.alert) attron(COLOR_PAIR(toxwin.alert));
clrtoeol();
printw(" [%s]", toxwin.name);
if (toxwin.alert0)
attroff(COLOR_PAIR(GREEN));
else if (toxwin.alert1)
attroff(COLOR_PAIR(RED));
else if (toxwin.alert2)
attroff(COLOR_PAIR(MAGENTA));
if (toxwin.alert) attroff(COLOR_PAIR(toxwin.alert));
}
static void draw_bar(void)
@ -432,9 +420,7 @@ static void draw_bar(void)
void draw_active_window(Tox *m)
{
ToxWindow *a = active_window;
a->alert0 = false;
a->alert1 = false;
a->alert2 = false;
a->alert = WINDOW_ALERT_NONE;
wint_t ch = 0;

View File

@ -29,9 +29,9 @@
#include <tox/tox.h>
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
#include <tox/toxav.h>
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
#include "toxic.h"
@ -53,10 +53,11 @@ enum {
} C_COLOURS;
/* tab alert types: lower types take priority */
enum {
WINDOW_ALERT_0,
WINDOW_ALERT_1,
WINDOW_ALERT_2,
typedef enum {
WINDOW_ALERT_NONE = 0,
WINDOW_ALERT_0 = GREEN,
WINDOW_ALERT_1 = RED,
WINDOW_ALERT_2 = MAGENTA,
} WINDOW_ALERTS;
/* Fixes text color problem on some terminals.
@ -97,7 +98,7 @@ struct ToxWindow {
void(*onFileData)(ToxWindow *, Tox *, int32_t, uint8_t, const char *, uint16_t);
void(*onTypingChange)(ToxWindow *, Tox *, int32_t, uint8_t);
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
void(*onInvite)(ToxWindow *, ToxAv *, int);
void(*onRinging)(ToxWindow *, ToxAv *, int);
@ -115,7 +116,11 @@ struct ToxWindow {
* Don't modify outside av callbacks. */
int device_selection[2]; /* -1 if not set, if set uses these selections instead of primary device */
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
#ifdef _SOUND_NOTIFY
int active_sound;
#endif
char name[TOXIC_MAX_NAME_LENGTH];
int32_t num; /* corresponds to friendnumber in chat windows */
@ -127,9 +132,7 @@ struct ToxWindow {
bool is_prompt;
bool is_friendlist;
bool alert0;
bool alert1;
bool alert2;
WINDOW_ALERTS alert;
ChatContext *chatwin;
StatusBar *stb;
@ -149,7 +152,7 @@ struct StatusBar {
bool is_online;
};
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
#define INFOBOX_HEIGHT 7
@ -168,7 +171,7 @@ struct infobox {
WINDOW *win;
};
#endif /* _SUPPORT_AUDIO */
#endif /* _AUDIO */
#define MAX_LINE_HIST 128
@ -189,7 +192,7 @@ struct ChatContext {
struct history *hst;
struct chatlog *log;
#ifdef _SUPPORT_AUDIO
#ifdef _AUDIO
struct infobox infobox;
#endif