1
0
mirror of https://github.com/Tha14/toxic.git synced 2024-11-26 23:53:28 +01:00

Updated with latest core

This commit is contained in:
mannol 2014-08-02 02:10:21 +02:00
commit 46975bf38b
54 changed files with 1368 additions and 437 deletions

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 [![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 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/ueK1Tdj.png "Home Screen"). ![Toxic Screenshot](https://i.imgur.com/ryaEmQZ.png "Home Screen").
## Installation ## Installation
@ -12,13 +12,16 @@ Toxic is a [Tox](https://tox.im)-based instant messenging client which formerly
* [libconfig](http://www.hyperrealm.com/libconfig) (for Debian based systems, 'libconfig-dev') * [libconfig](http://www.hyperrealm.com/libconfig) (for Debian based systems, 'libconfig-dev')
##### Audio ##### Audio
* libtoxav (libtoxcore compiled with audio support) * libtoxav ([libtoxcore](https://github.com/irungentoo/toxcore) compiled with audio support)
* [openal](http://openal.org) (for Debian based systems, 'libopenal-dev') * [openal](http://openal.org) (for Debian based systems, 'libopenal-dev')
##### Sound notifications ##### Sound notifications
* [openal](http://openal.org) * [openal](http://openal.org) (for Debian based systems, 'libopenal-dev')
* [openalut](http://openal.org) (for Debian based systems, 'libalut-dev') * [openalut](http://openal.org) (for Debian based systems, 'libalut-dev')
##### Desktop notifications
* [libnotify](https://developer.gnome.org/libnotify) (for Debian based systems, 'libnotify-dev')
### Compiling ### Compiling
1. `cd build/` 1. `cd build/`
2. `make PREFIX="/where/to/install"` 2. `make PREFIX="/where/to/install"`
@ -27,10 +30,10 @@ Toxic is a [Tox](https://tox.im)-based instant messenging client which formerly
### Compilation Notes ### Compilation Notes
* You can add specific flags to the Makefile with `USER_CFLAGS=""` and/or `USER_LDFLAGS=""` * You can add specific flags to the Makefile with `USER_CFLAGS=""` and/or `USER_LDFLAGS=""`
* You can pass your own flags to the Makefile with `CFLAGS=""` and/or `LDFLAGS=""` (this will supersede the default ones) * 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 * Additional features are automatically enabled if all dependencies are found, but you can disable them by using special variables:
* If you want to build toxic without audio call support, you can use `make DISABLE_AV=1` * `DISABLE_AV=1` → build toxic without audio call support
* Sound notifications support is automatically enabled if all dependencies are found * `DISABLE_SOUND_NOTIFY=1` → build toxic without sound notifications support
* If you want to build toxic without sound notifications support, you can use `make DISABLE_NOTIFY=1` * `DISABLE_DESKTOP_NOTIFY=1` → build toxic without desktop notifications support
### Packaging ### Packaging
* For packaging purpose, you can use `DESTDIR=""` to specify a directory where to store installed files * For packaging purpose, you can use `DESTDIR=""` to specify a directory where to store installed files

View File

@ -4,18 +4,10 @@ VERSION = $(TOXIC_VERSION)_r$(REV)
CFG_DIR = ../cfg CFG_DIR = ../cfg
SRC_DIR = ../src SRC_DIR = ../src
MISC_DIR = ../misc
DOC_DIR = ../doc
SND_DIR = ../sounds
PREFIX = /usr/local PREFIX = /usr/local
BINDIR = $(PREFIX)/bin BINDIR = $(PREFIX)/bin
DATADIR = $(PREFIX)/share/toxic DATADIR = $(PREFIX)/share/toxic
MANDIR = $(PREFIX)/man MANDIR = $(PREFIX)/share/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 libconfig LIBS = libtoxcore ncursesw libconfig
@ -29,104 +21,35 @@ 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 += 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 OBJ += log.o misc_tools.o prompt.o settings.o toxic.o toxic_strings.o windows.o
# Variables for audio call support
AUDIO_LIBS = libtoxav openal
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 # Check on wich system we are running
UNAME_S = $(shell uname -s) UNAME_S = $(shell uname -s)
ifeq ($(UNAME_S), Linux) ifeq ($(UNAME_S), Linux)
-include $(CFG_DIR)/Linux.mk -include $(CFG_DIR)/systems/Linux.mk
endif endif
ifeq ($(UNAME_S), FreeBSD) ifeq ($(UNAME_S), FreeBSD)
-include $(CFG_DIR)/FreeBSD.mk -include $(CFG_DIR)/systems/FreeBSD.mk
endif endif
ifeq ($(UNAME_S), Darwin) ifeq ($(UNAME_S), Darwin)
-include $(CFG_DIR)/Darwin.mk -include $(CFG_DIR)/systems/Darwin.mk
endif endif
ifeq ($(UNAME_S), Solaris) ifeq ($(UNAME_S), Solaris)
-include $(CFG_DIR)/Solaris.mk -include $(CFG_DIR)/systems/Solaris.mk
endif endif
# Check on which platform we are running # Check on which platform we are running
UNAME_M = $(shell uname -m) UNAME_M = $(shell uname -m)
ifeq ($(UNAME_M), x86_64) ifeq ($(UNAME_M), x86_64)
-include $(CFG_DIR)/x86_64.mk -include $(CFG_DIR)/platforms/x86_64.mk
endif endif
ifneq ($(filter %86, $(UNAME_M)),) ifneq ($(filter %86, $(UNAME_M)),)
-include $(CFG_DIR)/x86.mk -include $(CFG_DIR)/platforms/x86.mk
endif endif
ifneq ($(filter arm%, $(UNAME_M)),) ifneq ($(filter arm%, $(UNAME_M)),)
-include $(CFG_DIR)/arm.mk -include $(CFG_DIR)/platforms/arm.mk
endif endif
# Check if we can use X11 # Include all needed checks
CHECK_X11_LIBS = $(shell pkg-config x11 || echo -n "error") -include $(CFG_DIR)/check_features.mk
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")
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)
$(warning WARNING -- Toxic will be compiled without audio support)
$(warning WARNING -- You need these libraries for audio support)
$(warning WARNING -- $(MISSING_AUDIO_LIBS))
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)
CFLAGS += $(shell pkg-config --cflags $(LIBS))
LDFLAGS += $(shell pkg-config --libs $(LIBS))
else
ifneq ($(MAKECMDGOALS), clean)
MISSING_LIBS = $(shell for lib in $(LIBS) ; do if ! pkg-config $$lib ; then echo $$lib ; fi ; done)
$(warning ERROR -- Cannot compile Toxic)
$(warning ERROR -- You need these libraries)
$(warning ERROR -- $(MISSING_LIBS))
$(error ERROR)
endif
endif
# Targets # Targets
all: toxic all: toxic
@ -135,33 +58,6 @@ toxic: $(OBJ)
@echo " LD $@" @echo " LD $@"
@$(CC) $(CFLAGS) -o toxic $(OBJ) $(LDFLAGS) @$(CC) $(CFLAGS) -o toxic $(OBJ) $(LDFLAGS)
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 \
section=$(abspath $(DESTDIR)/$(MANDIR))/man`echo $$f | rev | cut -d "." -f 1` ;\
file=$$section/$$f ;\
mkdir -p $$section ;\
install -m 0644 $(DOC_DIR)/$$f $$file ;\
sed -i'' -e 's:__VERSION__:'$(VERSION)':g' $$file ;\
sed -i'' -e 's:__DATADIR__:'$(abspath $(DATADIR))':g' $$file ;\
gzip -f -9 $$file ;\
done
%.o: $(SRC_DIR)/%.c %.o: $(SRC_DIR)/%.c
@echo " CC $@" @echo " CC $@"
@$(CC) $(CFLAGS) -o $*.o -c $(SRC_DIR)/$*.c @$(CC) $(CFLAGS) -o $*.o -c $(SRC_DIR)/$*.c
@ -170,8 +66,9 @@ install: toxic
clean: clean:
rm -rf *.d *.o toxic rm -rf *.d *.o toxic
-include $(CFG_DIR)/help.mk
-include $(OBJ:.o=.d) -include $(OBJ:.o=.d)
.PHONY: clean all install -include $(CFG_DIR)/install.mk
-include $(CFG_DIR)/help.mk
.PHONY: clean all

23
cfg/av.mk Normal file
View File

@ -0,0 +1,23 @@
# Variables for audio call support
AUDIO_LIBS = libtoxav openal
AUDIO_CFLAGS = -D_AUDIO
ifneq (, $(findstring device.o, $(OBJ)))
AUDIO_OBJ = audio_call.o
else
AUDIO_OBJ = audio_call.o device.o
endif
# Check if we can build audio support
CHECK_AUDIO_LIBS = $(shell pkg-config $(AUDIO_LIBS) || echo -n "error")
ifneq ($(CHECK_AUDIO_LIBS), error)
LIBS += $(AUDIO_LIBS)
CFLAGS += $(AUDIO_CFLAGS)
OBJ += $(AUDIO_OBJ)
else
ifneq ($(MAKECMDGOALS), clean)
MISSING_AUDIO_LIBS = $(shell for lib in $(AUDIO_LIBS) ; do if ! pkg-config $$lib ; then echo $$lib ; fi ; done)
$(warning WARNING -- Toxic will be compiled without audio support)
$(warning WARNING -- You need these libraries for audio support)
$(warning WARNING -- $(MISSING_AUDIO_LIBS))
endif
endif

39
cfg/check_features.mk Normal file
View File

@ -0,0 +1,39 @@
# 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 build audio support
AUDIO = $(shell if [ -z "$(DISABLE_AV)" ] || [ "$(DISABLE_AV)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
ifneq ($(AUDIO), disabled)
-include $(CFG_DIR)/av.mk
endif
# Check if we want build sound notifications support
SND_NOTIFY = $(shell if [ -z "$(DISABLE_SOUND_NOTIFY)" ] || [ "$(DISABLE_SOUND_NOTIFY)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
ifneq ($(SND_NOTIFY), disabled)
-include $(CFG_DIR)/sound_notifications.mk
endif
# Check if we want build desktop notifications support
DESK_NOTIFY = $(shell if [ -z "$(DISABLE_DESKTOP_NOTIFY)" ] || [ "$(DISABLE_DESKTOP_NOTIFY)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
ifneq ($(DESK_NOTIFY), disabled)
-include $(CFG_DIR)/desktop_notifications.mk
endif
# Check if we can build Toxic
CHECK_LIBS = $(shell pkg-config $(LIBS) || echo -n "error")
ifneq ($(CHECK_LIBS), error)
CFLAGS += $(shell pkg-config --cflags $(LIBS))
LDFLAGS += $(shell pkg-config --libs $(LIBS))
else
ifneq ($(MAKECMDGOALS), clean)
MISSING_LIBS = $(shell for lib in $(LIBS) ; do if ! pkg-config $$lib ; then echo $$lib ; fi ; done)
$(warning ERROR -- Cannot compile Toxic)
$(warning ERROR -- You need these libraries)
$(warning ERROR -- $(MISSING_LIBS))
$(error ERROR)
endif
endif

View File

@ -0,0 +1,17 @@
# Variables for desktop notifications support
DESK_NOTIFY_LIBS = libnotify
DESK_NOTIFY_CFLAGS = -D_BOX_NOTIFY
# Check if we can build desktop notifications support
CHECK_DESK_NOTIFY_LIBS = $(shell pkg-config $(DESK_NOTIFY_LIBS) || echo -n "error")
ifneq ($(CHECK_DESK_NOTIFY_LIBS), error)
LIBS += $(DESK_NOTIFY_LIBS)
CFLAGS += $(DESK_NOTIFY_CFLAGS)
else
ifneq ($(MAKECMDGOALS), clean)
MISSING_DESK_NOTIFY_LIBS = $(shell for lib in $(DESK_NOTIFY_LIBS) ; do if ! pkg-config $$lib ; then echo $$lib ; fi ; done)
$(warning WARNING -- Toxic will be compiled without desktop notifications support)
$(warning WARNING -- You need these libraries for desktop notifications support)
$(warning WARNING -- $(MISSING_DESK_NOTIFY_LIBS))
endif
endif

View File

@ -8,11 +8,12 @@ help:
@echo " help: This help" @echo " help: This help"
@echo @echo
@echo "-- Variables --" @echo "-- Variables --"
@echo " DISABLE_AV: Set to \"1\" to force building without audio call support" @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 " DISABLE_SOUND_NOTIFY: Set to \"1\" to force building without sound notification support"
@echo " USER_CFLAGS: Add custom flags to default CFLAGS" @echo " DISABLE_DESKTOP_NOTIFY: Set to \"1\" to force building without desktop notifications support"
@echo " USER_LDFLAGS: Add custom flags to default LDFLAGS" @echo " USER_CFLAGS: Add custom flags to default CFLAGS"
@echo " PREFIX: Specify a prefix directory for binaries, data files,... (default is \"$(abspath $(PREFIX))\")" @echo " USER_LDFLAGS: Add custom flags to default LDFLAGS"
@echo " DESTDIR: Specify a directory where to store installed files (mainly for packaging purpose)" @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 .PHONY: help

37
cfg/install.mk Normal file
View File

@ -0,0 +1,37 @@
MISC_DIR = ../misc
DOC_DIR = ../doc
SND_DIR = ../sounds
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
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 \
section=$(abspath $(DESTDIR)/$(MANDIR))/man`echo $$f | rev | cut -d "." -f 1` ;\
file=$$section/$$f ;\
mkdir -p $$section ;\
install -m 0644 $(DOC_DIR)/$$f $$file ;\
sed -i'' -e 's:__VERSION__:'$(VERSION)':g' $$file ;\
sed -i'' -e 's:__DATADIR__:'$(abspath $(DATADIR))':g' $$file ;\
gzip -f -9 $$file ;\
done
.PHONY: install

4
cfg/platforms/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

View File

@ -0,0 +1,23 @@
# Variables for sound notifications support
SND_NOTIFY_LIBS = openal freealut
SND_NOTIFY_CFLAGS = -D_SOUND_NOTIFY
ifneq (, $(findstring device.o, $(OBJ)))
SND_NOTIFY_OBJ =
else
SND_NOTIFY_OBJ = device.o
endif
# Check if we can build sound notifications support
CHECK_SND_NOTIFY_LIBS = $(shell pkg-config $(SND_NOTIFY_LIBS) || echo -n "error")
ifneq ($(CHECK_SND_NOTIFY_LIBS), error)
LIBS += $(SND_NOTIFY_LIBS)
CFLAGS += $(SND_NOTIFY_CFLAGS)
OBJ += $(SND_NOTIFY_OBJ)
else
ifneq ($(MAKECMDGOALS), clean)
MISSING_SND_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 notifications support)
$(warning WARNING -- You need these libraries for sound notifications support)
$(warning WARNING -- $(MISSING_SND_NOTIFY_LIBS))
endif
endif

View File

@ -11,9 +11,9 @@ client.
.I <SECTION> .I <SECTION>
.B = { .B = {
.PP .PP
.IB <KEY1> : <BOOL_VALUE> ; .IB <KEY1> = <VALUE1> ;
.br .br
.IB <KEY2> = <NOT_BOOL_VALUE> ; .IB <KEY2> = <VALUE2> ;
.br .br
... ...
.PP .PP
@ -27,7 +27,7 @@ Sections:
.PP .PP
.B ui .B ui
.RS .RS
Configurations related to user interface. Configurations related to user interface elements.
.PP .PP
Keys: Keys:
.br .br
@ -66,6 +66,20 @@ Select between 24 and 12 hour time.
Values: 24, 12 Values: 24, 12
.RE .RE
.PP .PP
.B show_typing_other
.RS
Show you when others are typing in a 1-on-1 chat
.br
Values: 'true' to enable, 'false' to disable
.RE
.PP
.B show_typing_self
.RS
Show others when you're typing in a 1-on-1 chat
.br
Values: 'true' to enable, 'false' to disable
.RE
.PP
.B history_size .B history_size
.RS .RS
Maximum lines for chat window history. Maximum lines for chat window history.
@ -119,6 +133,8 @@ Values: <STRING> (absolute path where to store downloaded files)
.B sounds .B sounds
.RS .RS
Configurations related to notification sounds. Configurations related to notification sounds.
.br
(Special value "silent" can be used to disable a specific notification)
.PP .PP
Keys: Keys:
.br .br
@ -192,6 +208,78 @@ Sound to play when a file transfer is completed.
Values: <STRING> (sound file absolute path) Values: <STRING> (sound file absolute path)
.RE .RE
.RE .RE
.PP
.B keys
.RS
Configurations related to user interface interaction.
.br
(Currently supported: Ctrl modified keys, Tab, PAGEUP and PAGEDOWN (case insensitive))
.PP
Keys:
.br
.B next_tab
.RS
Key combination to switch next tab.
.br
Values: <STRING> (key combination)
.RE
.PP
.B prev_tab
.RS
Key combination to switch previous tab.
.br
Values: <STRING> (key combination)
.RE
.PP
.B scroll_line_up
.RS
Key combination to scroll one line up.
.br
Values: <STRING> (key combination)
.RE
.PP
.B scroll_line_down
.RS
Key combination to scroll one line down.
.br
Values: <STRING> (key combination)
.RE
.PP
.B half_page_up
.RS
Key combination to scroll half page up.
.br
Values: <STRING> (key combination)
.RE
.PP
.B half_page_down
.RS
Key combination to scroll half page down.
.br
Values: <STRING> (key combination)
.RE
.PP
.B page_bottom
.RS
Key combination to scroll to page bottom.
.br
Values: <STRING> (key combination)
.RE
.PP
.B peer_list_up
.RS
Key combination to scroll contacts list up.
.br
Values: <STRING> (key combination)
.RE
.PP
.B peer_list_down
.RS
Key combination to scroll contacts list down.
.br
Values: <STRING> (key combination)
.RE
.RE
.SH EXAMPLES .SH EXAMPLES
Default settings from __DATADIR__/toxic.conf.exmaple: Default settings from __DATADIR__/toxic.conf.exmaple:
.PP .PP
@ -200,36 +288,43 @@ Default settings from __DATADIR__/toxic.conf.exmaple:
// USES LIBCONFIG-ACCEPTED SYNTAX // USES LIBCONFIG-ACCEPTED SYNTAX
.br .br
ui = { ui = {
.br .RS
// true to enable timestamps, false to disable // true to enable timestamps, false to disable
.br .br
timestamps:true; timestamps=true;
.br
.br .br
// true to enable terminal alerts on messages, false to disable // true to enable terminal alerts on messages, false to disable
.br .br
alerts:true; alerts=true;
.br .br
// true to use native terminal colours, false to use toxic default colour theme // true to use native terminal colours, false to use toxic default colour theme
.br .br
native_colors:false; native_colors=false;
.br .br
// true to enable autologging, false to disable // true to enable autologging, false to disable
.br .br
autolog:false; autolog=false;
.br .br
// 24 or 12 hour time // 24 or 12 hour time
.br .br
time_format=24; time_format=24;
.br
// true to show you when others are typing a message in 1-on-1 chats
.br
show_typing_other=true;
.br
// true to show others when you're typing a message in 1-on-1 chats
.br
show_typing_self=true;
.br .br
// maximum lines for chat window history // maximum lines for chat window history
.br .br
history_size=700; history_size=700;
.br .RE
}; };
.br .PP
audio = { audio = {
.br .RS
// preferred audio input device; numbers correspond to /lsdev in // preferred audio input device; numbers correspond to /lsdev in
.br .br
input_device=2; input_device=2;
@ -241,21 +336,21 @@ audio = {
// default VAD treshold; float (recommended values are around 40) // default VAD treshold; float (recommended values are around 40)
.br .br
VAD_treshold=40.0; VAD_treshold=40.0;
.br .RE
}; };
.br .PP
tox = { tox = {
.br .RS
// where to store received files // where to store received files
.br .br
// download_path="/home/USERNAME/Downloads/"; //download_path="/home/USERNAME/Downloads/";
.br .RE
}; };
.br .PP
// To disable a sound set the path to "silent" // To disable a sound set the path to "silent"
.br .br
sounds = { sounds = {
.br .RS
error="__DATADIR__/sounds/Error.wav"; error="__DATADIR__/sounds/Error.wav";
.br .br
self_log_in="__DATADIR__/sounds/LogIn.wav"; self_log_in="__DATADIR__/sounds/LogIn.wav";
@ -275,7 +370,33 @@ sounds = {
transfer_pending="__DATADIR__/sounds/TransferPending.wav"; transfer_pending="__DATADIR__/sounds/TransferPending.wav";
.br .br
transfer_completed="__DATADIR__/sounds/TransferComplete.wav"; transfer_completed="__DATADIR__/sounds/TransferComplete.wav";
.RE
};
.PP
// Currently supported: Ctrl modified keys, Tab, PAGEUP and PAGEDOWN (case insensitive)
.br .br
// Note: All printable keys register as input
.br
keys = {
.RS
next_tab="Ctrl+P";
.br
prev_tab="Ctrl+O";
.br
scroll_line_up="PAGEUP";
.br
scroll_line_down="PAGEDOWN";
.br
half_page_up="Ctrl+F";
.br
half_page_down="Ctrl+V";
.br
page_bottom="Ctrl+H";
.br
peer_list_up="Ctrl+[";
.br
peer_list_down="Ctrl+]";
.RE
}; };
.SH FILES .SH FILES
.IP ~/.config/tox/toxic.conf .IP ~/.config/tox/toxic.conf

View File

@ -3,20 +3,26 @@
ui = { ui = {
// true to enable timestamps, false to disable // true to enable timestamps, false to disable
timestamps:true; timestamps=true;
// true to enable terminal alerts on messages, false to disable // true to enable terminal alerts on messages, false to disable
alerts:true; alerts=true;
// true to use native terminal colours, false to use toxic default colour theme // true to use native terminal colours, false to use toxic default colour theme
native_colors:false; native_colors=false;
// true to enable autologging, false to disable // true to enable autologging, false to disable
autolog:false; autolog=false;
// 24 or 12 hour time // 24 or 12 hour time
time_format=24; time_format=24;
// true to show you when others are typing a message in 1-on-1 chats
show_typing_other=true;
// true to show others when you're typing a message in 1-on-1 chats
show_typing_self=true;
// maximum lines for chat window history // maximum lines for chat window history
history_size=700; history_size=700;
}; };
@ -34,7 +40,7 @@ audio = {
tox = { tox = {
// where to store received files // where to store received files
// download_path="/home/USERNAME/Downloads/"; //download_path="/home/USERNAME/Downloads/";
}; };
// To disable a sound set the path to "silent" // To disable a sound set the path to "silent"
@ -50,3 +56,18 @@ sounds = {
transfer_pending="__DATADIR__/sounds/TransferPending.wav"; transfer_pending="__DATADIR__/sounds/TransferPending.wav";
transfer_completed="__DATADIR__/sounds/TransferComplete.wav"; transfer_completed="__DATADIR__/sounds/TransferComplete.wav";
}; };
// Currently supported: Ctrl modified keys, Tab, PAGEUP and PAGEDOWN (case insensitive)
// Note: All printable keys register as input
keys = {
next_tab="Ctrl+P";
prev_tab="Ctrl+O";
scroll_line_up="PAGEUP";
scroll_line_down="PAGEDOWN";
half_page_up="Ctrl+F";
half_page_down="Ctrl+V";
page_bottom="Ctrl+H";
peer_list_up="Ctrl+[";
peer_list_down="Ctrl+]";
};

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -42,6 +42,10 @@
#else #else
#include <AL/al.h> #include <AL/al.h>
#include <AL/alc.h> #include <AL/alc.h>
/* compatibility with older versions of OpenAL */
#ifndef ALC_ALL_DEVICES_SPECIFIER
#include <AL/alext.h>
#endif
#endif #endif
#define _cbend pthread_exit(NULL) #define _cbend pthread_exit(NULL)
@ -96,7 +100,7 @@ void callback_peer_timeout ( void* av, int32_t call_index, void *arg );
void callback_media_change ( 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); int stop_transmission(int call_index);
void write_device_callback(ToxAv* av, int32_t call_index, int16_t* data, int size); void write_device_callback(ToxAv* av, int32_t call_index, int16_t* data, int size, void* userdata);
static void print_err (ToxWindow *self, const char *error_str) static void print_err (ToxWindow *self, const char *error_str)
{ {
@ -142,7 +146,7 @@ ToxAv *init_audio(ToxWindow *self, Tox *tox)
toxav_register_callstate_callback(ASettins.av, callback_peer_timeout, av_OnPeerTimeout, 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_callstate_callback(ASettins.av, callback_media_change, av_OnMediaChange, self);
toxav_register_audio_recv_callback(ASettins.av, write_device_callback); toxav_register_audio_recv_callback(ASettins.av, write_device_callback, NULL);
return ASettins.av; return ASettins.av;
} }
@ -171,8 +175,9 @@ void read_device_callback (const int16_t* captured, uint32_t size, void* data)
} }
void write_device_callback(ToxAv* av, int32_t call_index, int16_t* data, int size) void write_device_callback(ToxAv* av, int32_t call_index, int16_t* data, int size, void* userdata)
{ {
(void)userdata;
if (call_index >= 0 && ASettins.calls[call_index].ttas) { if (call_index >= 0 && ASettins.calls[call_index].ttas) {
ToxAvCSettings csettings = ASettins.cs; ToxAvCSettings csettings = ASettins.cs;
toxav_get_peer_csettings(av, call_index, 0, &csettings); toxav_get_peer_csettings(av, call_index, 0, &csettings);
@ -575,7 +580,7 @@ on_error:
print_err (self, error_str); print_err (self, error_str);
} }
void cmd_ccur_device(WINDOW * window, ToxWindow * self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{ {
const char *msg; const char *msg;
const char *error_str; const char *error_str;
@ -650,7 +655,7 @@ void cmd_ccur_device(WINDOW * window, ToxWindow * self, Tox *m, int argc, char (
print_err (self, error_str); print_err (self, error_str);
} }
void cmd_mute(WINDOW * window, ToxWindow * self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{ {
const char *msg; const char *msg;
const char *error_str; const char *error_str;
@ -698,7 +703,7 @@ void cmd_mute(WINDOW * window, ToxWindow * self, Tox *m, int argc, char (*argv)[
print_err (self, error_str); print_err (self, error_str);
} }
void cmd_sense(WINDOW * window, ToxWindow * self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{ {
const char *error_str; const char *error_str;

View File

@ -26,6 +26,7 @@
#ifdef __APPLE__ #ifdef __APPLE__
#include <sys/types.h> #include <sys/types.h>
#include <sys/dir.h> #include <sys/dir.h>
#include <sys/syslimits.h>
#else #else
#include <dirent.h> #include <dirent.h>
#endif /* ifdef __APPLE__ */ #endif /* ifdef __APPLE__ */
@ -202,7 +203,7 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
} }
/* transforms a sendfile tab complete contaning the shorthand "~/" into the full home directory.*/ /* transforms a sendfile tab complete contaning the shorthand "~/" into the full home directory.*/
static void complt_home_dir(ToxWindow *self, char *path) static void complt_home_dir(ToxWindow *self, char *path, int pathsize)
{ {
ChatContext *ctx = self->chatwin; ChatContext *ctx = self->chatwin;
@ -210,8 +211,8 @@ static void complt_home_dir(ToxWindow *self, char *path)
get_home_dir(homedir, sizeof(homedir)); get_home_dir(homedir, sizeof(homedir));
char newline[MAX_STR_SIZE]; char newline[MAX_STR_SIZE];
const char *isqt = !strchr(path, '\"') ? "\"" : ""; snprintf(newline, sizeof(newline), "/sendfile \"%s%s", homedir, path + 1);
snprintf(newline, sizeof(newline), "/sendfile %s%s/", isqt, homedir); snprintf(path, pathsize, "%s", &newline[11]);
wchar_t wline[MAX_STR_SIZE]; wchar_t wline[MAX_STR_SIZE];
@ -231,22 +232,20 @@ static void complt_home_dir(ToxWindow *self, char *path)
/* attempts to match /sendfile "<incomplete-dir>" line to matching directories. /* attempts to match /sendfile "<incomplete-dir>" line to matching directories.
if only one match, auto-complete line. if only one match, auto-complete line.
return diff between old len and new len of ctx->line, -1 if no matches return diff between old len and new len of ctx->line, -1 if no matches or > 1 match */
*/ #define MAX_DIRS 512
#define MAX_DIRS 256
int dir_match(ToxWindow *self, Tox *m, wchar_t *line) int dir_match(ToxWindow *self, Tox *m, const wchar_t *line)
{ {
char b_path[MAX_STR_SIZE]; char b_path[MAX_STR_SIZE];
char b_name[MAX_STR_SIZE]; char b_name[MAX_STR_SIZE];
const wchar_t *tmpline = &line[11]; /* start after "/sendfile \"" */
if (wcs_to_mbs_buf(b_path, line, sizeof(b_path)) == -1) if (wcs_to_mbs_buf(b_path, tmpline, sizeof(b_path)) == -1)
return -1; return -1;
if (!strncmp(b_path, "\"~/", 3) || !strncmp(b_path, "~/", 2)) { if (!strncmp(b_path, "~/", 2))
complt_home_dir(self, b_path); complt_home_dir(self, b_path, sizeof(b_path));
return -1;
}
int si = char_rfind(b_path, '/', strlen(b_path)); int si = char_rfind(b_path, '/', strlen(b_path));

View File

@ -33,11 +33,10 @@
Returns the difference between the old len and new len of line on success, -1 if error */ 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); int complete_line(ToxWindow *self, const void *list, int n_items, int size);
/* matches /sendfile "<incomplete-dir>" line to matching directories. /* attempts to match /sendfile "<incomplete-dir>" line to matching directories.
if only one match, auto-complete line. if only one match, auto-complete line.
return diff between old len and new len of ctx->line, or -1 if no matches return diff between old len and new len of ctx->line, -1 if no matches or > 1 match */
*/
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line); int dir_match(ToxWindow *self, Tox *m, const wchar_t *line);
#endif /* #define _autocomplete_h */ #endif /* #define _autocomplete_h */

View File

@ -103,8 +103,11 @@ static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
#endif /* _AUDIO */ #endif /* _AUDIO */
}; };
static void set_typingstatus(ToxWindow *self, Tox *m, uint8_t is_typing) static void set_self_typingstatus(ToxWindow *self, Tox *m, uint8_t is_typing)
{ {
if (user_settings_->show_typing_self == SHOW_TYPING_OFF)
return;
ChatContext *ctx = self->chatwin; ChatContext *ctx = self->chatwin;
tox_set_user_is_typing(m, self->num, is_typing); tox_set_user_is_typing(m, self->num, is_typing);
@ -177,13 +180,17 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, int32_t num, uint8_
StatusBar *statusbar = self->stb; StatusBar *statusbar = self->stb;
if (status == 1) { /* Friend shows online */ if (status == 1) { /* Friend goes online */
statusbar->is_online = true; statusbar->is_online = true;
friends[num].is_typing = tox_get_is_typing(m, num); friends[num].is_typing = user_settings_->show_typing_other == SHOW_TYPING_ON
? tox_get_is_typing(m, num) : 0;
} else { /* Friend goes offline */ } else { /* Friend goes offline */
statusbar->is_online = false; statusbar->is_online = false;
friends[num].is_typing = 0; friends[num].is_typing = 0;
if (self->chatwin->self_is_typing)
set_self_typingstatus(self, m, 0);
} }
} }
@ -375,8 +382,14 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, int32_t num, uint8_t rec
switch (control_type) { switch (control_type) {
case TOX_FILECONTROL_ACCEPT: case TOX_FILECONTROL_ACCEPT:
if (receive_send == 1) { if (receive_send == 1) {
snprintf(msg, sizeof(msg), "File transfer for '%s' accepted (%.1f%%)", filename, 0.0); const char *r_msg = "File transfer for '%s' accepted.";
file_senders[i].line_id = self->chatwin->hst->line_end->id + 1; line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, r_msg, filename);
/* prep progress bar line */
char progline[MAX_STR_SIZE];
prep_prog_line(progline);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, progline);
file_senders[i].line_id = self->chatwin->hst->line_end->id + 2;
sound_notify(self, silent, NT_NOFOCUS | NT_BEEP | NT_WNDALERT_2, NULL); sound_notify(self, silent, NT_NOFOCUS | NT_BEEP | NT_WNDALERT_2, NULL);
} }
@ -413,7 +426,8 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, int32_t num, uint8_t rec
break; break;
} }
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg); if (msg[0])
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
} }
static void chat_onFileData(ToxWindow *self, Tox *m, int32_t num, uint8_t filenum, const char *data, static void chat_onFileData(ToxWindow *self, Tox *m, int32_t num, uint8_t filenum, const char *data,
@ -432,19 +446,17 @@ static void chat_onFileData(ToxWindow *self, Tox *m, int32_t num, uint8_t filenu
} }
} }
long double remain = (long double) tox_file_data_remaining(m, num, filenum, 1); friends[num].file_receiver.bps[filenum] += length;
double remain = (double) tox_file_data_remaining(m, num, filenum, 1);
uint64_t curtime = get_unix_time(); uint64_t curtime = get_unix_time();
/* refresh line with percentage complete */ /* refresh line with percentage complete and transfer speed (must be called once per second) */
if (!remain || timed_out(friends[num].file_receiver.last_progress[filenum], curtime, 1)) { if (!remain || timed_out(friends[num].file_receiver.last_progress[filenum], curtime, 1)) {
friends[num].file_receiver.last_progress[filenum] = curtime; friends[num].file_receiver.last_progress[filenum] = curtime;
uint64_t size = friends[num].file_receiver.size[filenum]; uint64_t size = friends[num].file_receiver.size[filenum];
long double pct_remain = remain ? (1 - (remain / size)) * 100 : 100; double pct_remain = remain > 0 ? (1 - (remain / size)) * 100 : 100;
print_progress_bar(self, filenum, num, pct_remain);
char msg[MAX_STR_SIZE]; friends[num].file_receiver.bps[filenum] = 0;
const char *name = friends[num].file_receiver.filenames[filenum];
snprintf(msg, sizeof(msg), "Saving file as: '%s' (%.1Lf%%)", name, pct_remain);
line_info_set(self, friends[num].file_receiver.line_id[filenum], msg);
} }
} }
@ -757,8 +769,8 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (ltr) { /* char is printable */ if (ltr) { /* char is printable */
input_new_char(self, key, x, y, x2, y2); input_new_char(self, key, x, y, x2, y2);
if (ctx->line[0] != '/') if (ctx->line[0] != '/' && !ctx->self_is_typing && statusbar->is_online)
set_typingstatus(self, m, 1); set_self_typingstatus(self, m, 1);
return; return;
} }
@ -770,10 +782,9 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (key == '\t' && ctx->len > 1 && ctx->line[0] == '/') { /* TAB key: auto-complete */ if (key == '\t' && ctx->len > 1 && ctx->line[0] == '/') { /* TAB key: auto-complete */
int diff = -1; int diff = -1;
int sf_len = 11;
if (wcsncmp(ctx->line, L"/sendfile \"", sf_len) == 0) { if (wcsncmp(ctx->line, L"/sendfile \"", wcslen(L"/sendfile \"")) == 0) {
diff = dir_match(self, m, &ctx->line[sf_len]); diff = dir_match(self, m, ctx->line);
} else { } else {
diff = complete_line(self, chat_cmd_list, AC_NUM_CHAT_COMMANDS, MAX_CMDNAME_SIZE); diff = complete_line(self, chat_cmd_list, AC_NUM_CHAT_COMMANDS, MAX_CMDNAME_SIZE);
} }
@ -830,7 +841,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
} }
if (ctx->len <= 0 && ctx->self_is_typing) if (ctx->len <= 0 && ctx->self_is_typing)
set_typingstatus(self, m, 0); set_self_typingstatus(self, m, 0);
} }
static void chat_onDraw(ToxWindow *self, Tox *m) static void chat_onDraw(ToxWindow *self, Tox *m)

View File

@ -37,6 +37,7 @@ extern ToxicFriend friends[MAX_FRIENDS_NUM];
extern FileSender file_senders[MAX_FILES]; extern FileSender file_senders[MAX_FILES];
extern uint8_t max_file_senders_index; extern uint8_t max_file_senders_index;
extern uint8_t num_active_file_senders;
void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{ {
@ -127,9 +128,14 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
const char *filename = friends[self->num].file_receiver.filenames[filenum]; const char *filename = friends[self->num].file_receiver.filenames[filenum];
if (tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_ACCEPT, 0, 0) == 0) { if (tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_ACCEPT, 0, 0) == 0) {
const char *msg = "Saving file as: '%s' (%.1f%%)"; const char *msg = "Saving file as: '%s'";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg, filename, 0.0); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg, filename);
friends[self->num].file_receiver.line_id[filenum] = self->chatwin->hst->line_end->id + 1;
/* prep progress bar line */
char progline[MAX_STR_SIZE];
prep_prog_line(progline);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, progline);
friends[self->num].file_receiver.line_id[filenum] = self->chatwin->hst->line_end->id + 2;
if ((friends[self->num].file_receiver.files[filenum] = fopen(filename, "a")) == NULL) { if ((friends[self->num].file_receiver.files[filenum] = fopen(filename, "a")) == NULL) {
errmsg = "* Error writing to file."; errmsg = "* Error writing to file.";
@ -160,15 +166,15 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
return; return;
} }
char *path = argv[1]; if (argv[1][0] != '\"') {
if (path[0] != '\"') {
errmsg = "File path must be enclosed in quotes."; errmsg = "File path must be enclosed in quotes.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
return; return;
} }
++path; /* remove opening and closing quotes */
char path[MAX_STR_SIZE];
snprintf(path, sizeof(path), "%s", &argv[1][1]);
int path_len = strlen(path) - 1; int path_len = strlen(path) - 1;
path[path_len] = '\0'; path[path_len] = '\0';
@ -204,6 +210,7 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
for (i = 0; i < MAX_FILES; ++i) { for (i = 0; i < MAX_FILES; ++i) {
if (!file_senders[i].active) { if (!file_senders[i].active) {
file_senders[i].queue_pos = num_active_file_senders;
memcpy(file_senders[i].pathname, path, path_len + 1); memcpy(file_senders[i].pathname, path, path_len + 1);
file_senders[i].active = true; file_senders[i].active = true;
file_senders[i].toxwin = self; file_senders[i].toxwin = self;
@ -218,6 +225,8 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
const char *msg = "Sending file: '%s'"; const char *msg = "Sending file: '%s'";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg, path); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg, path);
++num_active_file_senders;
if (i == max_file_senders_index) if (i == max_file_senders_index)
++max_file_senders_index; ++max_file_senders_index;

View File

@ -35,6 +35,10 @@
#else #else
#include <AL/al.h> #include <AL/al.h>
#include <AL/alc.h> #include <AL/alc.h>
/* compatibility with older versions of OpenAL */
#ifndef ALC_ALL_DEVICES_SPECIFIER
#include <AL/alext.h>
#endif
#endif #endif
#include <string.h> #include <string.h>

View File

@ -289,7 +289,7 @@ void *dns3_lookup_thread(void *data)
} }
/* creates new thread for dns3 lookup. Only allows one lookup at a time. */ /* creates new thread for dns3 lookup. Only allows one lookup at a time. */
void dns3_lookup(ToxWindow *self, Tox *m, char *id_bin, char *addr, char *msg) void dns3_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr, const char *msg)
{ {
if (t_data.busy) { if (t_data.busy) {
const char *err = "Please wait for previous user lookup to finish."; const char *err = "Please wait for previous user lookup to finish.";

View File

@ -27,6 +27,6 @@
#define _dns_h #define _dns_h
/* creates new thread for dns3 lookup. Only allows one lookup at a time. */ /* creates new thread for dns3 lookup. Only allows one lookup at a time. */
void dns3_lookup(ToxWindow *self, Tox *m, char *id_bin, char *addr, char *msg); void dns3_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr, const char *msg);
#endif /* #define _dns_h */ #endif /* #define _dns_h */

View File

@ -27,6 +27,7 @@
#include "toxic.h" #include "toxic.h"
#include "windows.h" #include "windows.h"
#include "friendlist.h"
#include "file_senders.h" #include "file_senders.h"
#include "line_info.h" #include "line_info.h"
#include "misc_tools.h" #include "misc_tools.h"
@ -34,6 +35,77 @@
FileSender file_senders[MAX_FILES]; FileSender file_senders[MAX_FILES];
uint8_t max_file_senders_index; uint8_t max_file_senders_index;
uint8_t num_active_file_senders;
extern ToxicFriend friends[MAX_FRIENDS_NUM];
#define KiB 1024
#define MiB 1048576 /* 1024 ^ 2 */
#define GiB 1073741824 /* 1024 ^ 3 */
/* creates initial progress line that will be updated during file transfer.
Assumes progline is of size MAX_STR_SIZE */
void prep_prog_line(char *progline)
{
strcpy(progline, "0.0 B/s [");
int i;
for (i = 0; i < NUM_PROG_MARKS; ++i)
strcat(progline, "-");
strcat(progline, "] 0%%");
}
/* prints a progress bar for file transfers.
if friendnum is -1 we're sending the file, otherwise we're receiving. */
void print_progress_bar(ToxWindow *self, int idx, int friendnum, double pct_remain)
{
double bps;
uint32_t line_id;
if (friendnum < 0) {
bps = file_senders[idx].bps;
line_id = file_senders[idx].line_id;
} else {
bps = friends[friendnum].file_receiver.bps[idx];
line_id = friends[friendnum].file_receiver.line_id[idx];
}
const char *unit;
if (bps < KiB) {
unit = "B/s";
} else if (bps < MiB) {
unit = "KiB/s";
bps /= (double) KiB;
} else if (bps < GiB) {
unit = "MiB/s";
bps /= (double) MiB;
} else {
unit = "GiB/s";
bps /= (double) GiB;
}
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "%.1f %s [", bps, unit);
int n = pct_remain / (100 / NUM_PROG_MARKS);
int i;
for (i = 0; i < n; ++i)
strcat(msg, "#");
int j;
for (j = i; j < NUM_PROG_MARKS; ++j)
strcat(msg, "-");
strcat(msg, "] ");
char pctstr[16];
snprintf(pctstr, sizeof(pctstr), "%.2f%%", pct_remain);
strcat(msg, pctstr);
line_info_set(self, line_id, msg);
}
static void set_max_file_senders_index(void) static void set_max_file_senders_index(void)
{ {
@ -57,6 +129,7 @@ static void close_file_sender(ToxWindow *self, Tox *m, int i, char *msg, int CTR
fclose(file_senders[i].file); fclose(file_senders[i].file);
memset(&file_senders[i], 0, sizeof(FileSender)); memset(&file_senders[i], 0, sizeof(FileSender));
set_max_file_senders_index(); set_max_file_senders_index();
--num_active_file_senders;
} }
void close_all_file_senders(Tox *m) void close_all_file_senders(Tox *m)
@ -75,23 +148,68 @@ void close_all_file_senders(Tox *m)
} }
} }
static void send_file_data(ToxWindow *self, Tox *m, int i, int32_t friendnum, int filenum, const char *pathname)
{
FILE *fp = file_senders[i].file;
while (true) {
if (tox_file_send_data(m, friendnum, filenum, (uint8_t *) file_senders[i].nextpiece,
file_senders[i].piecelen) == -1)
return;
uint64_t curtime = get_unix_time();
file_senders[i].timestamp = curtime;
file_senders[i].bps += file_senders[i].piecelen;
file_senders[i].piecelen = fread(file_senders[i].nextpiece, 1,
tox_file_data_size(m, friendnum), fp);
double remain = (double) tox_file_data_remaining(m, friendnum, filenum, 0);
/* refresh line with percentage complete and transfer speed (must be called once per second) */
if ((self->chatwin != NULL && timed_out(file_senders[i].last_progress, curtime, 1)) || !remain) {
file_senders[i].last_progress = curtime;
double pct_remain = remain > 0 ? (1 - (remain / file_senders[i].size)) * 100 : 100;
print_progress_bar(self, i, -1, pct_remain);
file_senders[i].bps = 0;
}
if (file_senders[i].piecelen == 0) {
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "File '%s' successfuly sent.", pathname);
close_file_sender(self, m, i, msg, TOX_FILECONTROL_FINISHED, filenum, friendnum);
if (self->active_box != -1)
box_notify2(self, transfer_completed, NT_NOFOCUS | NT_WNDALERT_2,
self->active_box, "File '%s' successfuly sent!", pathname );
else
box_notify(self, transfer_completed, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box,
self->name, "File '%s' successfuly sent!", pathname );
return;
}
}
}
void do_file_senders(Tox *m) void do_file_senders(Tox *m)
{ {
char msg[MAX_STR_SIZE];
int i; int i;
for (i = 0; i < max_file_senders_index; ++i) { for (i = 0; i < max_file_senders_index; ++i) {
if (!file_senders[i].active) if (!file_senders[i].active)
continue; continue;
if (file_senders[i].queue_pos > 0) {
--file_senders[i].queue_pos;
continue;
}
ToxWindow *self = file_senders[i].toxwin; ToxWindow *self = file_senders[i].toxwin;
char *pathname = file_senders[i].pathname; char *pathname = file_senders[i].pathname;
int filenum = file_senders[i].filenum; int filenum = file_senders[i].filenum;
int32_t friendnum = file_senders[i].friendnum; int32_t friendnum = file_senders[i].friendnum;
FILE *fp = file_senders[i].file;
/* If file transfer has timed out kill transfer and send kill control */ /* If file transfer has timed out kill transfer and send kill control */
if (timed_out(file_senders[i].timestamp, get_unix_time(), TIMEOUT_FILESENDER)) { if (timed_out(file_senders[i].timestamp, get_unix_time(), TIMEOUT_FILESENDER)) {
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "File transfer for '%s' timed out.", pathname); snprintf(msg, sizeof(msg), "File transfer for '%s' timed out.", pathname);
close_file_sender(self, m, i, msg, TOX_FILECONTROL_KILL, filenum, friendnum); close_file_sender(self, m, i, msg, TOX_FILECONTROL_KILL, filenum, friendnum);
sound_notify(self, error, NT_NOFOCUS | NT_WNDALERT_2, NULL); sound_notify(self, error, NT_NOFOCUS | NT_WNDALERT_2, NULL);
@ -105,41 +223,7 @@ void do_file_senders(Tox *m)
continue; continue;
} }
while (true) { file_senders[i].queue_pos = num_active_file_senders - 1;
if (tox_file_send_data(m, friendnum, filenum, (uint8_t *) file_senders[i].nextpiece, send_file_data(self, m, i, friendnum, filenum, pathname);
file_senders[i].piecelen) == -1)
break;
uint64_t curtime = get_unix_time();
file_senders[i].timestamp = curtime;
file_senders[i].piecelen = fread(file_senders[i].nextpiece, 1,
tox_file_data_size(m, friendnum), fp);
long double remain = (long double) tox_file_data_remaining(m, friendnum, filenum, 0);
/* refresh line with percentage complete */
if ((self->chatwin != NULL && timed_out(file_senders[i].last_progress, curtime, 1)) || !remain) {
file_senders[i].last_progress = curtime;
uint64_t size = file_senders[i].size;
long double pct_remain = remain ? (1 - (remain / size)) * 100 : 100;
snprintf(msg, sizeof(msg), "File transfer for '%s' accepted (%.1Lf%%)", pathname, pct_remain);
line_info_set(self, file_senders[i].line_id, msg);
}
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);
if (self->active_box != -1)
box_notify2(self, transfer_completed, NT_NOFOCUS | NT_WNDALERT_2,
self->active_box, "File '%s' successfuly sent!", pathname );
else
box_notify(self, transfer_completed, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box,
self->name, "File '%s' successfuly sent!", pathname );
break;
}
}
} }
} }

View File

@ -29,6 +29,7 @@
#define FILE_PIECE_SIZE 2048 /* must be >= (MAX_CRYPTO_DATA_SIZE - 2) in toxcore/net_crypto.h */ #define FILE_PIECE_SIZE 2048 /* must be >= (MAX_CRYPTO_DATA_SIZE - 2) in toxcore/net_crypto.h */
#define MAX_FILES 255 #define MAX_FILES 255
#define TIMEOUT_FILESENDER 120 #define TIMEOUT_FILESENDER 120
#define NUM_PROG_MARKS 50 /* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */
typedef struct { typedef struct {
FILE *file; FILE *file;
@ -41,10 +42,20 @@ typedef struct {
char pathname[MAX_STR_SIZE]; char pathname[MAX_STR_SIZE];
uint64_t timestamp; uint64_t timestamp;
uint64_t last_progress; uint64_t last_progress;
double bps;
uint64_t size; uint64_t size;
uint32_t line_id; uint32_t line_id;
uint8_t queue_pos;
} FileSender; } FileSender;
/* creates initial progress line that will be updated during file transfer.
Assumes progline is of size MAX_STR_SIZE */
void prep_prog_line(char *progline);
/* prints a progress bar for file transfers.
if friendnum is -1 we're sending the file, otherwise we're receiving. */
void print_progress_bar(ToxWindow *self, int idx, int friendnum, double pct_remain);
void close_all_file_senders(Tox *m); void close_all_file_senders(Tox *m);
void do_file_senders(Tox *m); void do_file_senders(Tox *m);

View File

@ -24,6 +24,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
#include <arpa/inet.h>
#include <tox/tox.h> #include <tox/tox.h>
@ -35,6 +36,7 @@
#include "line_info.h" #include "line_info.h"
#include "settings.h" #include "settings.h"
#include "notify.h" #include "notify.h"
#include "help.h"
#ifdef _AUDIO #ifdef _AUDIO
#include "audio_call.h" #include "audio_call.h"
@ -42,26 +44,154 @@
extern char *DATA_FILE; extern char *DATA_FILE;
extern char *BLOCK_FILE;
extern ToxWindow *prompt; extern ToxWindow *prompt;
static int max_friends_index = 0; /* marks the index of the last friend in friends array */
static int num_selected = 0;
static int num_friends = 0;
extern struct _Winthread Winthread; extern struct _Winthread Winthread;
extern struct user_settings *user_settings_; extern struct user_settings *user_settings_;
extern struct arg_opts arg_opts;
static uint8_t blocklist_view = 0; /* 0 if we're in friendlist view, 1 if we're in blocklist view */
static int num_selected = 0;
static int max_friends_index = 0; /* 1 + the index of the last friend in friends array */
static int num_friends = 0;
ToxicFriend friends[MAX_FRIENDS_NUM]; ToxicFriend friends[MAX_FRIENDS_NUM];
static int friendlist_index[MAX_FRIENDS_NUM] = {0}; static int friendlist_index[MAX_FRIENDS_NUM] = {0};
static struct _Blocked_Contacts {
int num_selected;
int max_index;
int num_blocked;
BlockedFriend list[MAX_FRIENDS_NUM];
int index[MAX_FRIENDS_NUM];
} Blocked_Contacts;
static struct _pendingDel { static struct _pendingDel {
int num; int num;
bool active; bool active;
WINDOW *popup; WINDOW *popup;
} pendingdelete; } pendingdelete;
#define S_WEIGHT 100000 static int save_blocklist(char *path)
{
if (arg_opts.ignore_data_file)
return 0;
if (path == NULL)
return -1;
int len = sizeof(BlockedFriend) * Blocked_Contacts.num_blocked;
char *data = malloc(len);
if (data == NULL)
exit_toxic_err("Failed in save_blocklist", FATALERR_MEMORY);
int i;
int count = 0;
for (i = 0; i < Blocked_Contacts.max_index; ++i) {
if (count > Blocked_Contacts.num_blocked)
return -1;
if (Blocked_Contacts.list[i].active) {
BlockedFriend tmp;
memset(&tmp, 0, sizeof(BlockedFriend));
tmp.namelength = htons(Blocked_Contacts.list[i].namelength);
memcpy(tmp.name, Blocked_Contacts.list[i].name, Blocked_Contacts.list[i].namelength + 1);
memcpy(tmp.pub_key, Blocked_Contacts.list[i].pub_key, TOX_CLIENT_ID_SIZE);
uint8_t lastonline[sizeof(uint64_t)];
memcpy(lastonline, &Blocked_Contacts.list[i].last_on, sizeof(uint64_t));
host_to_net(lastonline, sizeof(uint64_t));
memcpy(&tmp.last_on, lastonline, sizeof(uint64_t));
memcpy(data + count * sizeof(BlockedFriend), &tmp, sizeof(BlockedFriend));
++count;
}
}
FILE *fp = fopen(path, "wb");
if (fp == NULL) {
free(data);
return -1;
}
int ret = 0;
if (fwrite(data, len, 1, fp) != 1)
ret = -1;
fclose(fp);
free(data);
return ret;
}
static void sort_blocklist_index(void);
int load_blocklist(char *path)
{
if (path == NULL)
return -1;
FILE *fp = fopen(path, "rb");
if (fp == NULL)
return -1;
fseek(fp, 0, SEEK_END);
int len = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *data = malloc(len);
if (data == NULL) {
fclose(fp);
exit_toxic_err("Failed in load_blocklist", FATALERR_MEMORY);
}
if (fread(data, len, 1, fp) != 1) {
fclose(fp);
free(data);
return -1;
}
if (len % sizeof(BlockedFriend) != 0) {
fclose(fp);
free(data);
return -1;
}
int num = len / sizeof(BlockedFriend);
int i;
for (i = 0; i < num; ++i) {
BlockedFriend tmp;
memcpy(&tmp, data + i * sizeof(BlockedFriend), sizeof(BlockedFriend));
Blocked_Contacts.list[i].active = true;
Blocked_Contacts.list[i].num = i;
Blocked_Contacts.list[i].namelength = ntohs(tmp.namelength);
memcpy(Blocked_Contacts.list[i].name, tmp.name, Blocked_Contacts.list[i].namelength + 1);
memcpy(Blocked_Contacts.list[i].pub_key, tmp.pub_key, TOX_CLIENT_ID_SIZE);
uint8_t lastonline[sizeof(uint64_t)];
memcpy(lastonline, &tmp.last_on, sizeof(uint64_t));
net_to_host(lastonline, sizeof(uint64_t));
memcpy(&Blocked_Contacts.list[i].last_on, lastonline, sizeof(uint64_t));
++Blocked_Contacts.num_blocked;
}
Blocked_Contacts.max_index = i + 1;
free(data);
fclose(fp);
sort_blocklist_index();
return 0;
}
#define S_WEIGHT 100000
static int index_name_cmp(const void *n1, const void *n2) static int index_name_cmp(const void *n1, const void *n2)
{ {
int res = qsort_strcasecmp_hlpr(friends[*(int *) n1].name, friends[*(int *) n2].name); int res = qsort_strcasecmp_hlpr(friends[*(int *) n1].name, friends[*(int *) n2].name);
@ -87,6 +217,24 @@ void sort_friendlist_index(void)
qsort(friendlist_index, num_friends, sizeof(int), index_name_cmp); qsort(friendlist_index, num_friends, sizeof(int), index_name_cmp);
} }
static int index_name_cmp_block(const void *n1, const void *n2)
{
return qsort_strcasecmp_hlpr(Blocked_Contacts.list[*(int *) n1].name, Blocked_Contacts.list[*(int *) n2].name);
}
static void sort_blocklist_index(void)
{
int i;
int n = 0;
for (i = 0; i < Blocked_Contacts.max_index; ++i) {
if (Blocked_Contacts.list[i].active)
Blocked_Contacts.index[n++] = Blocked_Contacts.list[i].num;
}
qsort(Blocked_Contacts.index, Blocked_Contacts.num_blocked, sizeof(int), index_name_cmp_block);
}
static void update_friend_last_online(int32_t num, uint64_t timestamp) static void update_friend_last_online(int32_t num, uint64_t timestamp)
{ {
friends[num].last_online.last_on = timestamp; friends[num].last_online.last_on = timestamp;
@ -206,6 +354,39 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_t num, bool sort)
} }
} }
/* puts blocked friend back in friendlist. fnum is new friend number, bnum is blocked number */
static void friendlist_add_blocked(Tox *m, int32_t fnum, int32_t bnum)
{
if (max_friends_index >= MAX_FRIENDS_NUM)
return;
int i;
for (i = 0; i <= max_friends_index; ++i) {
if (friends[i].active)
continue;
friends[i].num = fnum;
friends[i].active = true;
friends[i].chatwin = -1;
friends[i].status = TOX_USERSTATUS_NONE;
friends[i].logging_on = (bool) user_settings_->autolog == AUTOLOG_ON;
friends[i].namelength = Blocked_Contacts.list[bnum].namelength;
update_friend_last_online(i, Blocked_Contacts.list[bnum].last_on);
memcpy(friends[i].name, Blocked_Contacts.list[bnum].name, friends[i].namelength + 1);
memcpy(friends[i].pub_key, Blocked_Contacts.list[bnum].pub_key, TOX_CLIENT_ID_SIZE);
num_friends = tox_count_friendlist(m);
if (i == max_friends_index)
++max_friends_index;
sort_blocklist_index();
sort_friendlist_index();
return;
}
}
static void friendlist_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t filenum, static void friendlist_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t filenum,
uint64_t filesize, const char *filename, uint16_t filename_len) uint64_t filesize, const char *filename, uint16_t filename_len)
{ {
@ -265,18 +446,31 @@ static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, const
} }
} }
static void select_friend(ToxWindow *self, Tox *m, wint_t key) /* move friendlist/blocklist cursor up and down */
static void select_friend(ToxWindow *self, wint_t key, int *selected, int num)
{ {
if (num <= 0)
return;
if (key == KEY_UP) { if (key == KEY_UP) {
if (--num_selected < 0) if (--(*selected) < 0)
num_selected = num_friends - 1; *selected = num - 1;
} else if (key == KEY_DOWN) { } else if (key == KEY_DOWN) {
num_selected = (num_selected + 1) % num_friends; *selected = (*selected + 1) % num;
} }
} }
static void delete_friend(Tox *m, int32_t f_num) static void delete_friend(Tox *m, int32_t f_num)
{ {
if (friends[f_num].chatwin >= 0) {
ToxWindow *toxwin = get_window_ptr(friends[f_num].chatwin);
if (toxwin != NULL) {
kill_chat_window(toxwin);
set_active_window(1); /* keep friendlist focused */
}
}
tox_del_friend(m, f_num); tox_del_friend(m, f_num);
memset(&friends[f_num], 0, sizeof(ToxicFriend)); memset(&friends[f_num], 0, sizeof(ToxicFriend));
@ -294,7 +488,6 @@ static void delete_friend(Tox *m, int32_t f_num)
if (num_friends && num_selected == num_friends) if (num_friends && num_selected == num_friends)
--num_selected; --num_selected;
sort_friendlist_index();
store_data(m, DATA_FILE); store_data(m, DATA_FILE);
} }
@ -306,11 +499,20 @@ static void del_friend_activate(ToxWindow *self, Tox *m, int32_t f_num)
pendingdelete.num = f_num; pendingdelete.num = f_num;
} }
static void delete_blocked_friend(int32_t bnum);
/* deactivates delete friend popup and deletes friend if instructed */ /* deactivates delete friend popup and deletes friend if instructed */
static void del_friend_deactivate(ToxWindow *self, Tox *m, wint_t key) static void del_friend_deactivate(ToxWindow *self, Tox *m, wint_t key)
{ {
if (key == 'y') if (key == 'y') {
delete_friend(m, pendingdelete.num); if (blocklist_view == 0) {
delete_friend(m, pendingdelete.num);
sort_friendlist_index();
} else {
delete_blocked_friend(pendingdelete.num);
sort_blocklist_index();
}
}
delwin(pendingdelete.popup); delwin(pendingdelete.popup);
memset(&pendingdelete, 0, sizeof(pendingdelete)); memset(&pendingdelete, 0, sizeof(pendingdelete));
@ -318,7 +520,7 @@ static void del_friend_deactivate(ToxWindow *self, Tox *m, wint_t key)
refresh(); refresh();
} }
static void draw_popup(void) static void draw_del_popup(void)
{ {
if (!pendingdelete.active) if (!pendingdelete.active)
return; return;
@ -330,19 +532,111 @@ static void draw_popup(void)
wmove(pendingdelete.popup, 1, 1); wmove(pendingdelete.popup, 1, 1);
wprintw(pendingdelete.popup, "Delete contact "); wprintw(pendingdelete.popup, "Delete contact ");
wattron(pendingdelete.popup, A_BOLD); wattron(pendingdelete.popup, A_BOLD);
wprintw(pendingdelete.popup, "%s", friends[pendingdelete.num].name);
if (blocklist_view == 0)
wprintw(pendingdelete.popup, "%s", friends[pendingdelete.num].name);
else
wprintw(pendingdelete.popup, "%s", Blocked_Contacts.list[pendingdelete.num].name);
wattroff(pendingdelete.popup, A_BOLD); wattroff(pendingdelete.popup, A_BOLD);
wprintw(pendingdelete.popup, "? y/n"); wprintw(pendingdelete.popup, "? y/n");
wrefresh(pendingdelete.popup); wrefresh(pendingdelete.popup);
} }
static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) /* deletes contact from blocked list */
static void delete_blocked_friend(int32_t bnum)
{ {
if (num_friends == 0) memset(&Blocked_Contacts.list[bnum], 0, sizeof(BlockedFriend));
int i;
for (i = Blocked_Contacts.max_index; i > 0; --i) {
if (Blocked_Contacts.list[i - 1].active)
break;
}
--Blocked_Contacts.num_blocked;
Blocked_Contacts.max_index = i;
save_blocklist(BLOCK_FILE);
if (Blocked_Contacts.num_blocked && Blocked_Contacts.num_selected == Blocked_Contacts.num_blocked)
--Blocked_Contacts.num_selected;
}
/* deletes contact from friendlist and puts in blocklist */
void block_friend(Tox *m, int32_t fnum)
{
if (Blocked_Contacts.max_index >= MAX_FRIENDS_NUM || num_friends <= 0)
return; return;
int f = friendlist_index[num_selected]; int i;
for (i = 0; i <= Blocked_Contacts.max_index; ++i) {
if (Blocked_Contacts.list[i].active)
continue;
Blocked_Contacts.list[i].active = true;
Blocked_Contacts.list[i].num = i;
Blocked_Contacts.list[i].namelength = friends[fnum].namelength;
Blocked_Contacts.list[i].last_on = friends[fnum].last_online.last_on;
memcpy(Blocked_Contacts.list[i].pub_key, friends[fnum].pub_key, TOX_CLIENT_ID_SIZE);
memcpy(Blocked_Contacts.list[i].name, friends[fnum].name, friends[fnum].namelength + 1);
++Blocked_Contacts.num_blocked;
if (i == Blocked_Contacts.max_index)
++Blocked_Contacts.max_index;
delete_friend(m, fnum);
save_blocklist(BLOCK_FILE);
sort_blocklist_index();
sort_friendlist_index();
return;
}
}
/* removes friend from blocklist, puts back in friendlist */
static void unblock_friend(Tox *m, int32_t bnum)
{
if (Blocked_Contacts.num_blocked <= 0)
return;
int32_t friendnum = tox_add_friend_norequest(m, (uint8_t *) Blocked_Contacts.list[bnum].pub_key);
if (friendnum == -1) {
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to unblock friend");
return;
}
friendlist_add_blocked(m, friendnum, bnum);
delete_blocked_friend(bnum);
sort_blocklist_index();
sort_friendlist_index();
}
static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
{
if (self->help->active) {
help_onKey(self, key);
return;
}
if (key == 'h') {
help_init_menu(self);
return;
}
if (!blocklist_view && !num_friends && (key != KEY_RIGHT && key != KEY_LEFT))
return;
if (blocklist_view && !Blocked_Contacts.num_blocked && (key != KEY_RIGHT && key != KEY_LEFT))
return;
int f = blocklist_view == 1 ? Blocked_Contacts.index[Blocked_Contacts.num_selected]
: friendlist_index[num_selected];
/* lock screen and force decision on deletion popup */ /* lock screen and force decision on deletion popup */
if (pendingdelete.active) { if (pendingdelete.active) {
@ -352,8 +646,14 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
return; return;
} }
if (key != ltr) { if (key == ltr)
if (key == '\n') { return;
switch (key) {
case '\n':
if (blocklist_view)
break;
/* Jump to chat window if already open */ /* Jump to chat window if already open */
if (friends[f].chatwin != -1) { if (friends[f].chatwin != -1) {
set_active_window(friends[f].chatwin); set_active_window(friends[f].chatwin);
@ -363,19 +663,109 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
} else { } else {
const char *msg = "* Warning: Too many windows are open."; const char *msg = "* Warning: Too many windows are open.";
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, msg); line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, msg);
sound_notify(prompt, error, NT_WNDALERT_1, NULL); sound_notify(prompt, error, NT_WNDALERT_1, NULL);
} }
} else if (key == KEY_DC) {
break;
case KEY_DC:
del_friend_activate(self, m, f); del_friend_activate(self, m, f);
} else { break;
select_friend(self, m, key);
} case 'b':
if (!blocklist_view)
block_friend(m, f);
else
unblock_friend(m, f);
break;
case KEY_RIGHT:
case KEY_LEFT:
blocklist_view ^= 1;
break;
default:
if (blocklist_view == 0)
select_friend(self, key, &num_selected, num_friends);
else
select_friend(self, key, &Blocked_Contacts.num_selected, Blocked_Contacts.num_blocked);
break;
} }
} }
#define FLIST_OFST 6 /* Accounts for space at top and bottom */ #define FLIST_OFST 6 /* Accounts for space at top and bottom */
static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2)
{
wattron(self->window, A_BOLD);
wprintw(self->window, " Blocked: ");
wattroff(self->window, A_BOLD);
wprintw(self->window, "%d\n\n", Blocked_Contacts.num_blocked);
if ((y2 - FLIST_OFST) <= 0)
return;
int selected_num = 0;
/* Determine which portion of friendlist to draw based on current position */
int page = Blocked_Contacts.num_selected / (y2 - FLIST_OFST);
int start = (y2 - FLIST_OFST) * page;
int end = y2 - FLIST_OFST + start;
int i;
for (i = start; i < Blocked_Contacts.num_blocked && i < end; ++i) {
int f = Blocked_Contacts.index[i];
bool f_selected = false;
if (i == Blocked_Contacts.num_selected) {
wattron(self->window, A_BOLD);
wprintw(self->window, " > ");
wattroff(self->window, A_BOLD);
selected_num = f;
f_selected = true;
} else {
wprintw(self->window, " ");
}
wattron(self->window, COLOR_PAIR(RED));
wprintw(self->window, "x");
wattroff(self->window, COLOR_PAIR(RED));
if (f_selected)
wattron(self->window, COLOR_PAIR(BLUE));
wattron(self->window, A_BOLD);
wprintw(self->window, " %s\n", Blocked_Contacts.list[f].name);
wattroff(self->window, A_BOLD);
if (f_selected)
wattroff(self->window, COLOR_PAIR(BLUE));
}
wprintw(self->window, "\n");
self->x = x2;
if (Blocked_Contacts.num_blocked) {
wmove(self->window, y2 - 1, 1);
wattron(self->window, A_BOLD);
wprintw(self->window, "ID: ");
wattroff(self->window, A_BOLD);
int i;
for (i = 0; i < TOX_CLIENT_ID_SIZE; ++i)
wprintw(self->window, "%02X", Blocked_Contacts.list[selected_num].pub_key[i] & 0xff);
}
wrefresh(self->window);
draw_del_popup();
if (self->help->active)
help_onDraw(self);
}
static void friendlist_onDraw(ToxWindow *self, Tox *m) static void friendlist_onDraw(ToxWindow *self, Tox *m)
{ {
curs_set(0); curs_set(0);
@ -383,23 +773,24 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
int x2, y2; int x2, y2;
getmaxyx(self->window, y2, x2); getmaxyx(self->window, y2, x2);
uint64_t cur_time = get_unix_time();
struct tm cur_loc_tm = *localtime((const time_t*)&cur_time);
bool fix_statuses = x2 != self->x; /* true if window max x value has changed */ bool fix_statuses = x2 != self->x; /* true if window max x value has changed */
wattron(self->window, COLOR_PAIR(CYAN)); wattron(self->window, COLOR_PAIR(CYAN));
wprintw(self->window, " Open a chat window with the"); wprintw(self->window, " Press the");
wattron(self->window, A_BOLD); wattron(self->window, A_BOLD);
wprintw(self->window, " Enter "); wprintw(self->window, " H ");
wattroff(self->window, A_BOLD); wattroff(self->window, A_BOLD);
wprintw(self->window, "key. Delete a contact with the"); wprintw(self->window, "key for help\n\n");
wattron(self->window, A_BOLD);
wprintw(self->window, " Delete ");
wattroff(self->window, A_BOLD);
wprintw(self->window, "key.\n\n");
wattroff(self->window, COLOR_PAIR(CYAN)); wattroff(self->window, COLOR_PAIR(CYAN));
if (blocklist_view == 1) {
blocklist_onDraw(self, m, y2, x2);
return;
}
uint64_t cur_time = get_unix_time();
struct tm cur_loc_tm = *localtime((const time_t *) &cur_time);
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
int nf = tox_get_num_online_friends(m); int nf = tox_get_num_online_friends(m);
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
@ -553,7 +944,10 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
} }
wrefresh(self->window); wrefresh(self->window);
draw_popup(); draw_del_popup();
if (self->help->active)
help_onDraw(self);
} }
void disable_chatwin(int32_t f_num) void disable_chatwin(int32_t f_num)
@ -632,6 +1026,12 @@ ToxWindow new_friendlist(void)
ret.active_box = -1; ret.active_box = -1;
Help *help = calloc(1, sizeof(Help));
if (help == NULL)
exit_toxic_err("failed in new_friendlist", FATALERR_MEMORY);
ret.help = help;
strcpy(ret.name, "contacts"); strcpy(ret.name, "contacts");
return ret; return ret;
} }

View File

@ -34,6 +34,7 @@ struct FileReceiver {
FILE *files[MAX_FILES]; FILE *files[MAX_FILES];
bool pending[MAX_FILES]; bool pending[MAX_FILES];
uint64_t size[MAX_FILES]; uint64_t size[MAX_FILES];
double bps[MAX_FILES];
uint64_t last_progress[MAX_FILES]; uint64_t last_progress[MAX_FILES];
uint32_t line_id[MAX_FILES]; uint32_t line_id[MAX_FILES];
}; };
@ -63,9 +64,19 @@ typedef struct {
struct FileReceiver file_receiver; struct FileReceiver file_receiver;
} ToxicFriend; } ToxicFriend;
typedef struct {
char name[TOXIC_MAX_NAME_LENGTH];
int namelength;
char pub_key[TOX_CLIENT_ID_SIZE];
int32_t num;
bool active;
uint64_t last_on;
} BlockedFriend;
ToxWindow new_friendlist(void); ToxWindow new_friendlist(void);
void disable_chatwin(int32_t f_num); void disable_chatwin(int32_t f_num);
int get_friendnum(uint8_t *name); int get_friendnum(uint8_t *name);
int load_blocklist(char *data);
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_t num, bool sort); void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_t num, bool sort);

View File

@ -92,7 +92,7 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
void cmd_add_helper(ToxWindow *self, Tox *m, char *id_bin, char *msg) void cmd_add_helper(ToxWindow *self, Tox *m, char *id_bin, char *msg)
{ {
char *errmsg; const char *errmsg;
int32_t f_num = tox_add_friend(m, (uint8_t *) id_bin, (uint8_t *) msg, (uint16_t) strlen(msg)); int32_t f_num = tox_add_friend(m, (uint8_t *) id_bin, (uint8_t *) msg, (uint16_t) strlen(msg));
switch (f_num) { switch (f_num) {
@ -135,7 +135,7 @@ void cmd_add_helper(ToxWindow *self, Tox *m, char *id_bin, char *msg)
void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{ {
char *errmsg; const char *errmsg;
if (argc < 1) { if (argc < 1) {
errmsg = "Invalid syntax."; errmsg = "Invalid syntax.";
@ -143,21 +143,22 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
return; return;
} }
char *id = argv[1]; const char *id = argv[1];
char msg[MAX_STR_SIZE]; char msg[MAX_STR_SIZE];
if (argc > 1) { if (argc > 1) {
char *temp = argv[2]; if (argv[2][0] != '\"') {
if (temp[0] != '\"') {
errmsg = "Message must be enclosed in quotes."; errmsg = "Message must be enclosed in quotes.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
return; return;
} }
++temp; /* remove opening and closing quotes */
temp[strlen(temp) - 1] = '\0'; char tmp[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "%s", temp); snprintf(tmp, sizeof(tmp), "%s", &argv[2][1]);
int len = strlen(tmp) - 1;
tmp[len] = '\0';
snprintf(msg, sizeof(msg), "%s", tmp);
} else { } else {
char selfname[TOX_MAX_NAME_LENGTH]; char selfname[TOX_MAX_NAME_LENGTH];
uint16_t n_len = tox_get_self_name(m, (uint8_t *) selfname); uint16_t n_len = tox_get_self_name(m, (uint8_t *) selfname);
@ -204,7 +205,7 @@ void cmd_clear(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[M
void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{ {
char *errmsg; const char *errmsg;
/* check arguments */ /* check arguments */
if (argc != 3) { if (argc != 3) {
@ -230,7 +231,7 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{ {
char *errmsg; const char *errmsg;
if (get_num_active_windows() >= MAX_WINDOWS_NUM) { if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
errmsg = " * Warning: Too many windows are open."; errmsg = " * Warning: Too many windows are open.";
@ -259,7 +260,7 @@ void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{ {
char *msg; const char *msg;
struct chatlog *log = self->chatwin->log; struct chatlog *log = self->chatwin->log;
if (argc == 0) { if (argc == 0) {
@ -272,7 +273,7 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
return; return;
} }
char *swch = argv[1]; const char *swch = argv[1];
if (!strcmp(swch, "1") || !strcmp(swch, "on")) { if (!strcmp(swch, "1") || !strcmp(swch, "on")) {
@ -324,7 +325,7 @@ void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{ {
char *errmsg; const char *errmsg;
/* check arguments */ /* check arguments */
if (argc < 1) { if (argc < 1) {
@ -333,13 +334,16 @@ void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
return; return;
} }
char *nick = argv[1]; char nick[MAX_STR_SIZE];
int len = strlen(nick); int len = 0;
if (nick[0] == '\"') { if (argv[1][0] == '\"') { /* remove opening and closing quotes */
++nick; snprintf(nick, sizeof(nick), "%s", &argv[1][1]);
len -= 2; len = strlen(nick) - 1;
nick[len] = '\0'; nick[len] = '\0';
} else {
snprintf(nick, sizeof(nick), "%s", argv[1]);
len = strlen(nick);
} }
if (!valid_nick(nick)) { if (!valid_nick(nick)) {
@ -359,7 +363,7 @@ void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
void cmd_note(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_note(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{ {
char *errmsg; const char *errmsg;
if (argc < 1) { if (argc < 1) {
errmsg = "Wrong number of arguments."; errmsg = "Wrong number of arguments.";
@ -367,17 +371,18 @@ void cmd_note(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
return; return;
} }
char *msg = argv[1]; if (argv[1][0] != '\"') {
if (msg[0] != '\"') {
errmsg = "Note must be enclosed in quotes."; errmsg = "Note must be enclosed in quotes.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
return; return;
} }
++msg; /* remove opening and closing quotes */
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "%s", &argv[1][1]);
int len = strlen(msg) - 1; int len = strlen(msg) - 1;
msg[len] = '\0'; msg[len] = '\0';
tox_set_status_message(m, (uint8_t *) msg, (uint16_t) len); tox_set_status_message(m, (uint8_t *) msg, (uint16_t) len);
prompt_update_statusmessage(prompt, msg); prompt_update_statusmessage(prompt, msg);
} }
@ -394,24 +399,19 @@ void cmd_quit(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{ {
char *msg = NULL; bool have_note = false;
char *errmsg; const char *errmsg;
if (argc >= 2) { if (argc >= 2) {
msg = argv[2]; have_note = true;
if (msg[0] != '\"') {
errmsg = "Note must be enclosed in quotes.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
return;
}
} else if (argc != 1) { } else if (argc != 1) {
errmsg = "Wrong number of arguments."; errmsg = "Wrong number of arguments.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
return; return;
} }
char *status = argv[1]; char status[MAX_STR_SIZE];
snprintf(status, sizeof(status), "%s", argv[1]);
str_to_lower(status); str_to_lower(status);
TOX_USERSTATUS status_kind; TOX_USERSTATUS status_kind;
@ -431,10 +431,19 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
tox_set_user_status(m, status_kind); tox_set_user_status(m, status_kind);
prompt_update_status(prompt, status_kind); prompt_update_status(prompt, status_kind);
if (msg != NULL) { if (have_note) {
++msg; if (argv[2][0] != '\"') {
errmsg = "Note must be enclosed in quotes.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
return;
}
/* remove opening and closing quotes */
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "%s", &argv[2][1]);
int len = strlen(msg) - 1; int len = strlen(msg) - 1;
msg[len] = '\0'; /* remove opening and closing quotes */ msg[len] = '\0';
tox_set_status_message(m, (uint8_t *) msg, (uint16_t) len); tox_set_status_message(m, (uint8_t *) msg, (uint16_t) len);
prompt_update_statusmessage(prompt, msg); prompt_update_statusmessage(prompt, msg);
} }

View File

@ -290,7 +290,7 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu
ChatContext *ctx = self->chatwin; ChatContext *ctx = self->chatwin;
char *event; const char *event;
char timefrmt[TIME_STR_SIZE]; char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt)); get_time_str(timefrmt, sizeof(timefrmt));
@ -332,7 +332,7 @@ static void send_group_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *a
} }
if (tox_group_action_send(m, self->num, (uint8_t *) action, strlen(action)) == -1) { if (tox_group_action_send(m, self->num, (uint8_t *) action, strlen(action)) == -1) {
char *errmsg = " * Failed to send action."; const char *errmsg = " * Failed to send action.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, errmsg); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, errmsg);
} }
} }
@ -385,12 +385,12 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
} else { } else {
sound_notify(self, error, 0, NULL); sound_notify(self, error, 0, NULL);
} }
} else if (key == T_KEY_C_RB) { /* Scroll peerlist up and down one position */ } else if (key == user_settings_->key_peer_list_down) { /* Scroll peerlist up and down one position */
int L = y2 - CHATBOX_HEIGHT - SDBAR_OFST; int L = y2 - CHATBOX_HEIGHT - SDBAR_OFST;
if (groupchats[self->num].side_pos < groupchats[self->num].num_peers - L) if (groupchats[self->num].side_pos < groupchats[self->num].num_peers - L)
++groupchats[self->num].side_pos; ++groupchats[self->num].side_pos;
} else if (key == T_KEY_C_LB) { } else if (key == user_settings_->key_peer_list_up) {
if (groupchats[self->num].side_pos > 0) if (groupchats[self->num].side_pos > 0)
--groupchats[self->num].side_pos; --groupchats[self->num].side_pos;
} else if (key == '\n') { } else if (key == '\n') {
@ -415,7 +415,7 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
} }
} else if (!string_is_empty(line)) { } else if (!string_is_empty(line)) {
if (tox_group_message_send(m, self->num, (uint8_t *) line, strlen(line)) == -1) { if (tox_group_message_send(m, self->num, (uint8_t *) line, strlen(line)) == -1) {
char *errmsg = " * Failed to send message."; const char *errmsg = " * Failed to send message.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, errmsg); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, errmsg);
} }
} }

View File

@ -27,7 +27,7 @@
#include "help.h" #include "help.h"
#include "misc_tools.h" #include "misc_tools.h"
#define HELP_MENU_HEIGHT 7 #define HELP_MENU_HEIGHT 8
#define HELP_MENU_WIDTH 26 #define HELP_MENU_WIDTH 26
void help_init_menu(ToxWindow *self) void help_init_menu(ToxWindow *self)
@ -86,6 +86,11 @@ static void help_draw_menu(ToxWindow *self)
wattroff(win, A_BOLD | COLOR_PAIR(BLUE)); wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, "hat commands\n"); wprintw(win, "hat commands\n");
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, " F");
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, "riendlist controls\n");
wattron(win, A_BOLD | COLOR_PAIR(BLUE)); wattron(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, " K"); wprintw(win, " K");
wattroff(win, A_BOLD | COLOR_PAIR(BLUE)); wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
@ -209,7 +214,30 @@ static void help_draw_keys(ToxWindow *self)
wprintw(win, " Page Up and Page Down : Scroll window history one line\n"); wprintw(win, " Page Up and Page Down : Scroll window history one line\n");
wprintw(win, " Ctrl+F and Ctrl+V : Scroll window history half a page\n"); wprintw(win, " Ctrl+F and Ctrl+V : Scroll window history half a page\n");
wprintw(win, " Ctrl+H : Move to the bottom of window history\n"); wprintw(win, " Ctrl+H : Move to the bottom of window history\n");
wprintw(win, " Ctrl+[ and Ctrl+] : Scroll peer list in groupchats\n"); wprintw(win, " Ctrl+[ and Ctrl+] : Scroll peer list in groupchats\n\n");
wprintw(win, " (Note: Custom keybindings override these defaults.)\n\n");
help_draw_bottom_menu(win);
box(win, ACS_VLINE, ACS_HLINE);
wrefresh(win);
}
static void help_draw_contacts(ToxWindow *self)
{
WINDOW *win = self->help->win;
wmove(win, 1, 1);
wattron(win, A_BOLD | COLOR_PAIR(RED));
wprintw(win, "Friendlist controls:\n");
wattroff(win, A_BOLD | COLOR_PAIR(RED));
wprintw(win, " Up and Down arrows : Scroll through list\n");
wprintw(win, " Right and Left arrows : Switch between friendlist and blocked list\n");
wprintw(win, " Enter : Open a chat window with selected contact\n");
wprintw(win, " Delete : Permanently delete a contact\n");
wprintw(win, " B : Block or unblock a contact\n");
help_draw_bottom_menu(win); help_draw_bottom_menu(win);
@ -243,8 +271,13 @@ void help_onKey(ToxWindow *self, wint_t key)
self->help->type = HELP_GLOBAL; self->help->type = HELP_GLOBAL;
break; break;
case 'k': case 'f':
help_init_window(self, 10, 80); help_init_window(self, 10, 80);
self->help->type = HELP_CONTACTS;
break;
case 'k':
help_init_window(self, 12, 80);
self->help->type = HELP_KEYS; self->help->type = HELP_KEYS;
break; break;
@ -276,6 +309,10 @@ void help_onDraw(ToxWindow *self)
help_draw_keys(self); help_draw_keys(self);
break; break;
case HELP_CONTACTS:
help_draw_contacts(self);
break;
case HELP_GROUP: case HELP_GROUP:
break; break;
} }

View File

@ -32,6 +32,7 @@ typedef enum {
HELP_CHAT, HELP_CHAT,
HELP_GROUP, HELP_GROUP,
HELP_KEYS, HELP_KEYS,
HELP_CONTACTS,
} HELP_TYPES; } HELP_TYPES;
void help_onDraw(ToxWindow *self); void help_onDraw(ToxWindow *self);

View File

@ -134,7 +134,8 @@ static struct line_info *line_info_ret_queue(struct history *hst)
return ret; return ret;
} }
/* creates new line_info line and puts it in the queue */ /* creates new line_info line and puts it in the queue.
SYS_MSG lines may contain an arbitrary number of arguments for string formatting */
void line_info_add(ToxWindow *self, char *tmstmp, char *name1, char *name2, uint8_t type, uint8_t bold, void line_info_add(ToxWindow *self, char *tmstmp, char *name1, char *name2, uint8_t type, uint8_t bold,
uint8_t colour, const char *msg, ...) uint8_t colour, const char *msg, ...)
{ {
@ -145,11 +146,16 @@ void line_info_add(ToxWindow *self, char *tmstmp, char *name1, char *name2, uint
exit_toxic_err("failed in line_info_add", FATALERR_MEMORY); exit_toxic_err("failed in line_info_add", FATALERR_MEMORY);
char frmt_msg[MAX_STR_SIZE] = {0}; char frmt_msg[MAX_STR_SIZE] = {0};
va_list args;
va_start(args, msg); /* WARNING: SYS_MSG lines must not contain untrusted input */
vsnprintf(frmt_msg, sizeof(frmt_msg), msg, args); if (type == SYS_MSG) {
va_end(args); va_list args;
va_start(args, msg);
vsnprintf(frmt_msg, sizeof(frmt_msg), msg, args);
va_end(args);
} else {
snprintf(frmt_msg, sizeof(frmt_msg), "%s", msg);
}
int len = 1; /* there will always be a newline */ int len = 1; /* there will always be a newline */
@ -454,36 +460,24 @@ bool line_info_onKey(ToxWindow *self, wint_t key)
struct history *hst = self->chatwin->hst; struct history *hst = self->chatwin->hst;
bool match = true; bool match = true;
switch (key) { if (key == user_settings_->key_half_page_up) {
/* TODO: Find good key bindings for all this stuff */ line_info_page_up(self, hst);
case T_KEY_C_F: }
line_info_page_up(self, hst); else if (key == user_settings_->key_half_page_down) {
break; line_info_page_down(self, hst);
}
case T_KEY_C_V: else if (key == user_settings_->key_scroll_line_up) {
line_info_page_down(self, hst); line_info_scroll_up(hst);
break; }
else if (key == user_settings_->key_scroll_line_down) {
case KEY_PPAGE: line_info_scroll_down(hst);
line_info_scroll_up(hst); }
break; else if (key == user_settings_->key_page_bottom) {
line_info_reset_start(self, hst);
case KEY_NPAGE: }
line_info_scroll_down(hst); else {
break; match = false;
}
/* case ?:
line_info_goto_root(hst);
break; */
case T_KEY_C_H:
line_info_reset_start(self, hst);
break;
default:
match = false;
break;
}
return match; return match;
} }

View File

@ -67,7 +67,8 @@ struct history {
int queue_sz; int queue_sz;
}; };
/* creates new line_info line and puts it in the queue */ /* creates new line_info line and puts it in the queue.
SYS_MSG lines may contain an arbitrary number of arguments for string formatting */
void line_info_add(ToxWindow *self, char *tmstmp, char *name1, char *name2, uint8_t type, uint8_t bold, void line_info_add(ToxWindow *self, char *tmstmp, char *name1, char *name2, uint8_t type, uint8_t bold,
uint8_t colour, const char *msg, ...); uint8_t colour, const char *msg, ...);

View File

@ -34,7 +34,7 @@
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 */ /* 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) void init_logging_session(char *name, const char *key, struct chatlog *log)
{ {
if (!log->log_on) if (!log->log_on)
return; return;
@ -80,7 +80,7 @@ void init_logging_session(char *name, char *key, struct chatlog *log)
fprintf(log->file, "\n*** NEW SESSION ***\n\n"); fprintf(log->file, "\n*** NEW SESSION ***\n\n");
} }
void write_to_log(const char *msg, char *name, struct chatlog *log, bool event) void write_to_log(const char *msg, const char *name, struct chatlog *log, bool event)
{ {
if (!log->log_on) if (!log->log_on)
return; return;
@ -110,7 +110,7 @@ void write_to_log(const char *msg, char *name, struct chatlog *log, bool event)
} }
} }
void log_enable(char *name, char *key, struct chatlog *log) void log_enable(char *name, const char *key, struct chatlog *log)
{ {
log->log_on = true; log->log_on = true;

View File

@ -33,13 +33,13 @@ struct chatlog {
}; };
/* Creates/fetches log file by appending to the config dir the name and a pseudo-unique identity */ /* 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); void init_logging_session(char *name, const char *key, struct chatlog *log);
/* formats/writes line to log file */ /* formats/writes line to log file */
void write_to_log(const char *msg, char *name, struct chatlog *log, bool event); void write_to_log(const char *msg, const char *name, struct chatlog *log, bool event);
/* enables logging for specified log and creates/fetches file if necessary */ /* enables logging for specified log and creates/fetches file if necessary */
void log_enable(char *name, char *key, struct chatlog *log); void log_enable(char *name, const char *key, struct chatlog *log);
/* disables logging for specified log and closes file */ /* disables logging for specified log and closes file */
void log_disable(struct chatlog *log); void log_disable(struct chatlog *log);

View File

@ -37,6 +37,21 @@ extern struct user_settings *user_settings_;
static uint64_t current_unix_time; static uint64_t current_unix_time;
void host_to_net(uint8_t *num, uint16_t numbytes)
{
#ifndef WORDS_BIGENDIAN
uint32_t i;
uint8_t buff[numbytes];
for (i = 0; i < numbytes; ++i) {
buff[i] = num[numbytes - i - 1];
}
memcpy(num, buff, numbytes);
#endif
return;
}
void update_unix_time(void) void update_unix_time(void)
{ {
current_unix_time = (uint64_t) time(NULL); current_unix_time = (uint64_t) time(NULL);

View File

@ -33,6 +33,12 @@
#define MAX(x, y) (((x) > (y)) ? (x) : (y)) #define MAX(x, y) (((x) > (y)) ? (x) : (y))
#endif #endif
#ifndef net_to_host
#define net_to_host(x, y) host_to_net(x, y)
#endif
void host_to_net(uint8_t *num, uint16_t numbytes);
/* convert a hex string to binary */ /* convert a hex string to binary */
char *hex_string_to_bin(const char *hex_string); char *hex_string_to_bin(const char *hex_string);

View File

@ -38,16 +38,17 @@
#ifdef __APPLE__ #ifdef __APPLE__
#include <OpenAL/al.h> #include <OpenAL/al.h>
#include <OpenAL/alc.h> #include <OpenAL/alc.h>
#ifdef _SOUND_NOTIFY
#include <OpenAL/alut.h> /* Is this good? */
#endif
#else #else
#include <AL/al.h> #include <AL/al.h>
#include <AL/alc.h> #include <AL/alc.h>
#ifdef _SOUND_NOTIFY /* compatibility with older versions of OpenAL */
#include <AL/alut.h> /* freealut packet */ #ifndef ALC_ALL_DEVICES_SPECIFIER
#include <AL/alext.h>
#endif #endif
#endif #endif
#ifdef _SOUND_NOTIFY
#include <AL/alut.h> /* freealut packet */
#endif
#endif /* _AUDIO */ #endif /* _AUDIO */
#ifdef _X11 #ifdef _X11

View File

@ -96,7 +96,7 @@ void kill_prompt_window(ToxWindow *self)
} }
/* Updates own nick in prompt statusbar */ /* Updates own nick in prompt statusbar */
void prompt_update_nick(ToxWindow *prompt, char *nick) void prompt_update_nick(ToxWindow *prompt, const char *nick)
{ {
StatusBar *statusbar = prompt->stb; StatusBar *statusbar = prompt->stb;
snprintf(statusbar->nick, sizeof(statusbar->nick), "%s", nick); snprintf(statusbar->nick, sizeof(statusbar->nick), "%s", nick);
@ -104,7 +104,7 @@ void prompt_update_nick(ToxWindow *prompt, char *nick)
} }
/* Updates own statusmessage in prompt statusbar */ /* Updates own statusmessage in prompt statusbar */
void prompt_update_statusmessage(ToxWindow *prompt, char *statusmsg) void prompt_update_statusmessage(ToxWindow *prompt, const char *statusmsg)
{ {
StatusBar *statusbar = prompt->stb; StatusBar *statusbar = prompt->stb;
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg); snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
@ -344,7 +344,7 @@ static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, con
int n = add_friend_request(key); int n = add_friend_request(key);
if (n == -1) { if (n == -1) {
char *errmsg = "Friend request queue is full. Discarding request."; const char *errmsg = "Friend request queue is full. Discarding request.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
write_to_log(errmsg, "", ctx->log, true); write_to_log(errmsg, "", ctx->log, true);
return; return;
@ -404,7 +404,7 @@ static void print_welcome_msg(ToxWindow *self)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, BLUE, " |_| \\___/_/\\_\\___\\____|"); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, BLUE, " |_| \\___/_/\\_\\___\\____|");
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
char *msg = "Welcome to Toxic, a free, open source Tox-based instant messenging client."; const char *msg = "Welcome to Toxic, a free, open source Tox-based instant messenging client.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, CYAN, msg); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, CYAN, msg);
msg = "Type \"/help\" for assistance. Further help may be found via the man page."; msg = "Type \"/help\" for assistance. Further help may be found via the man page.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, CYAN, msg); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, CYAN, msg);

View File

@ -35,8 +35,8 @@
ToxWindow new_prompt(void); ToxWindow new_prompt(void);
void prep_prompt_win(void); void prep_prompt_win(void);
void prompt_init_statusbar(ToxWindow *self, Tox *m); void prompt_init_statusbar(ToxWindow *self, Tox *m);
void prompt_update_nick(ToxWindow *prompt, char *nick); void prompt_update_nick(ToxWindow *prompt, const char *nick);
void prompt_update_statusmessage(ToxWindow *prompt, char *statusmsg); void prompt_update_statusmessage(ToxWindow *prompt, const char *statusmsg);
void prompt_update_status(ToxWindow *prompt, uint8_t status); void prompt_update_status(ToxWindow *prompt, uint8_t status);
void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected); void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected);
void kill_prompt_window(ToxWindow *self); void kill_prompt_window(ToxWindow *self);

View File

@ -23,6 +23,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <libconfig.h> #include <libconfig.h>
#include <ctype.h>
#include "toxic.h" #include "toxic.h"
#include "windows.h" #include "windows.h"
@ -50,6 +51,8 @@ const struct _ui_strings {
const char* autolog; const char* autolog;
const char* time_format; const char* time_format;
const char* history_size; const char* history_size;
const char* show_typing_self;
const char* show_typing_other;
} ui_strings = { } ui_strings = {
"ui", "ui",
"timestamps", "timestamps",
@ -57,8 +60,11 @@ const struct _ui_strings {
"native_colors", "native_colors",
"autolog", "autolog",
"time_format", "time_format",
"history_size" "history_size",
"show_typing_self",
"show_typing_other",
}; };
static void ui_defaults(struct user_settings* settings) static void ui_defaults(struct user_settings* settings)
{ {
settings->timestamps = TIMESTAMPS_ON; settings->timestamps = TIMESTAMPS_ON;
@ -67,6 +73,46 @@ static void ui_defaults(struct user_settings* settings)
settings->alerts = ALERTS_ENABLED; settings->alerts = ALERTS_ENABLED;
settings->colour_theme = DFLT_COLS; settings->colour_theme = DFLT_COLS;
settings->history_size = 700; settings->history_size = 700;
settings->show_typing_self = SHOW_TYPING_ON;
settings->show_typing_other = SHOW_TYPING_ON;
}
const struct _keys_strings {
const char* self;
const char* next_tab;
const char* prev_tab;
const char* scroll_line_up;
const char* scroll_line_down;
const char* half_page_up;
const char* half_page_down;
const char* page_bottom;
const char* peer_list_up;
const char* peer_list_down;
} key_strings = {
"keys",
"next_tab",
"prev_tab",
"scroll_line_up",
"scroll_line_down",
"half_page_up",
"half_page_down",
"page_bottom",
"peer_list_up",
"peer_list_down"
};
/* defines from toxic.h */
static void key_defaults(struct user_settings* settings)
{
settings->key_next_tab = T_KEY_NEXT;
settings->key_prev_tab = T_KEY_PREV;
settings->key_scroll_line_up = KEY_PPAGE;
settings->key_scroll_line_down = KEY_NPAGE;
settings->key_half_page_up = T_KEY_C_F;
settings->key_half_page_down = T_KEY_C_V;
settings->key_page_bottom = T_KEY_C_H;
settings->key_peer_list_up = T_KEY_C_LB;
settings->key_peer_list_down = T_KEY_C_RB;
} }
const struct _tox_strings { const struct _tox_strings {
@ -94,6 +140,7 @@ const struct _audio_strings {
"output_device", "output_device",
"VAD_treshold", "VAD_treshold",
}; };
static void audio_defaults(struct user_settings* settings) static void audio_defaults(struct user_settings* settings)
{ {
settings->audio_in_dev = 0; settings->audio_in_dev = 0;
@ -130,6 +177,23 @@ const struct _sound_strings {
}; };
#endif #endif
static int key_parse(const char** bind){
int len = strlen(*bind);
if (len > 5) {
if(strncasecmp(*bind, "ctrl+", 5) == 0)
return toupper(bind[0][5]) - 'A' + 1;
}
if (strncasecmp(*bind, "tab", 3) == 0)
return T_KEY_TAB;
if (strncasecmp(*bind, "page", 4) == 0)
return len == 6 ? KEY_PPAGE : KEY_NPAGE;
return -1;
}
int settings_load(struct user_settings *s, const char *patharg) int settings_load(struct user_settings *s, const char *patharg)
{ {
config_t cfg[1]; config_t cfg[1];
@ -139,6 +203,7 @@ int settings_load(struct user_settings *s, const char *patharg)
/* Load default settings */ /* Load default settings */
ui_defaults(s); ui_defaults(s);
tox_defaults(s); tox_defaults(s);
key_defaults(s);
#ifdef _AUDIO #ifdef _AUDIO
audio_defaults(s); audio_defaults(s);
#endif #endif
@ -155,7 +220,6 @@ int settings_load(struct user_settings *s, const char *patharg)
/* make sure path exists or is created on first time running */ /* make sure path exists or is created on first time running */
FILE *fp = fopen(path, "r"); FILE *fp = fopen(path, "r");
if (fp == NULL) { if (fp == NULL) {
if ((fp = fopen(path, "w")) == NULL) if ((fp = fopen(path, "w")) == NULL)
return -1; return -1;
@ -177,8 +241,9 @@ int settings_load(struct user_settings *s, const char *patharg)
config_setting_lookup_bool(setting, ui_strings.alerts, &s->alerts); 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.autolog, &s->autolog);
config_setting_lookup_bool(setting, ui_strings.native_colors, &s->colour_theme); 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.history_size, &s->history_size);
config_setting_lookup_bool(setting, ui_strings.show_typing_self, &s->show_typing_self);
config_setting_lookup_bool(setting, ui_strings.show_typing_other, &s->show_typing_other);
config_setting_lookup_int(setting, ui_strings.time_format, &s->time); 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 */ s->time = s->time == TIME_24 || s->time == TIME_12 ? s->time : TIME_24; /* Check defaults */
} }
@ -189,6 +254,20 @@ int settings_load(struct user_settings *s, const char *patharg)
} }
} }
/* keys */
if((setting = config_lookup(cfg, key_strings.self)) != NULL) {
const char* tmp = NULL;
if(config_setting_lookup_string(setting, key_strings.next_tab, &tmp)) s->key_next_tab = key_parse(&tmp);
if(config_setting_lookup_string(setting, key_strings.prev_tab, &tmp)) s->key_prev_tab = key_parse(&tmp);
if(config_setting_lookup_string(setting, key_strings.scroll_line_up, &tmp)) s->key_scroll_line_up = key_parse(&tmp);
if(config_setting_lookup_string(setting, key_strings.scroll_line_down, &tmp)) s->key_scroll_line_down= key_parse(&tmp);
if(config_setting_lookup_string(setting, key_strings.half_page_up, &tmp)) s->key_half_page_up = key_parse(&tmp);
if(config_setting_lookup_string(setting, key_strings.half_page_down, &tmp)) s->key_half_page_down = key_parse(&tmp);
if(config_setting_lookup_string(setting, key_strings.page_bottom, &tmp)) s->key_page_bottom = key_parse(&tmp);
if(config_setting_lookup_string(setting, key_strings.peer_list_up, &tmp)) s->key_peer_list_up = key_parse(&tmp);
if(config_setting_lookup_string(setting, key_strings.peer_list_down, &tmp)) s->key_peer_list_down = key_parse(&tmp);
}
#ifdef _AUDIO #ifdef _AUDIO
if ((setting = config_lookup(cfg, audio_strings.self)) != NULL) { if ((setting = config_lookup(cfg, audio_strings.self)) != NULL) {
config_setting_lookup_int(setting, audio_strings.input_device, &s->audio_in_dev); config_setting_lookup_int(setting, audio_strings.input_device, &s->audio_in_dev);

View File

@ -31,8 +31,20 @@ struct user_settings {
int timestamps; /* boolean */ int timestamps; /* boolean */
int colour_theme; /* boolean (0 for default toxic colours) */ int colour_theme; /* boolean (0 for default toxic colours) */
int history_size; /* int between MIN_HISTORY and MAX_HISTORY */ int history_size; /* int between MIN_HISTORY and MAX_HISTORY */
int show_typing_self; /* boolean */
int show_typing_other; /* boolean */
char download_path[MAX_STR_SIZE]; char download_path[MAX_STR_SIZE];
int key_next_tab; /* character code */
int key_prev_tab; /* character code */
int key_scroll_line_up;
int key_scroll_line_down;
int key_half_page_up;
int key_half_page_down;
int key_page_bottom;
int key_peer_list_up;
int key_peer_list_down;
#ifdef _AUDIO #ifdef _AUDIO
int audio_in_dev; int audio_in_dev;
int audio_out_dev; int audio_out_dev;
@ -53,12 +65,14 @@ enum {
ALERTS_DISABLED = 0, ALERTS_DISABLED = 0,
ALERTS_ENABLED = 1, ALERTS_ENABLED = 1,
NATIVE_COLS = 1,
DFLT_COLS = 0, DFLT_COLS = 0,
NATIVE_COLS = 1,
SHOW_TYPING_OFF = 0,
SHOW_TYPING_ON = 1,
DFLT_HST_SIZE = 700, DFLT_HST_SIZE = 700,
} settings_values; } settings_values;
int settings_load(struct user_settings *s, const char *patharg); int settings_load(struct user_settings *s, const char *patharg);
#endif /* #define _settings_h */ #endif /* #define _settings_h */

View File

@ -67,19 +67,13 @@ ToxAv *av;
/* Export for use in Callbacks */ /* Export for use in Callbacks */
char *DATA_FILE = NULL; char *DATA_FILE = NULL;
char *BLOCK_FILE = NULL;
ToxWindow *prompt = NULL; ToxWindow *prompt = NULL;
#define AUTOSAVE_FREQ 60 #define AUTOSAVE_FREQ 60
struct arg_opts {
int ignore_data_file;
int use_ipv4;
int default_locale;
char config_path[MAX_STR_SIZE];
char nodes_path[MAX_STR_SIZE];
} arg_opts;
struct _Winthread Winthread; struct _Winthread Winthread;
struct arg_opts arg_opts;
struct user_settings *user_settings_ = NULL; struct user_settings *user_settings_ = NULL;
static void catch_SIGINT(int sig) static void catch_SIGINT(int sig)
@ -371,15 +365,17 @@ static void load_friendlist(Tox *m)
for (i = 0; i < numfriends; ++i) for (i = 0; i < numfriends; ++i)
friendlist_onFriendAdded(NULL, m, i, false); friendlist_onFriendAdded(NULL, m, i, false);
sort_friendlist_index();
} }
/* /*
* Store Messenger to given location * Store Messenger to given location
* Return 0 stored successfully or ignoring data file * Return 0 stored successfully or ignoring data file
* Return 1 file path is NULL * Return -1 file path is NULL
* Return 2 malloc failed * Return -2 malloc failed
* Return 3 opening path failed * Return -3 opening path failed
* Return 4 fwrite failed * Return -4 fwrite failed
*/ */
int store_data(Tox *m, char *path) int store_data(Tox *m, char *path)
{ {
@ -387,13 +383,13 @@ int store_data(Tox *m, char *path)
return 0; return 0;
if (path == NULL) if (path == NULL)
return 1; return -1;
int len = tox_size(m); int len = tox_size(m);
char *buf = malloc(len); char *buf = malloc(len);
if (buf == NULL) if (buf == NULL)
return 2; return -2;
tox_save(m, (uint8_t *) buf); tox_save(m, (uint8_t *) buf);
@ -401,13 +397,13 @@ int store_data(Tox *m, char *path)
if (fd == NULL) { if (fd == NULL) {
free(buf); free(buf);
return 3; return -3;
} }
if (fwrite(buf, len, 1, fd) != 1) { if (fwrite(buf, len, 1, fd) != 1) {
free(buf); free(buf);
fclose(fd); fclose(fd);
return 4; return -4;
} }
free(buf); free(buf);
@ -442,6 +438,7 @@ static void load_data(Tox *m, char *path)
tox_load(m, (uint8_t *) buf, len); tox_load(m, (uint8_t *) buf, len);
load_friendlist(m); load_friendlist(m);
load_blocklist(BLOCK_FILE);
free(buf); free(buf);
fclose(fd); fclose(fd);
@ -526,10 +523,12 @@ static void parse_args(int argc, char *argv[])
switch (opt) { switch (opt) {
case 'f': case 'f':
DATA_FILE = strdup(optarg); DATA_FILE = strdup(optarg);
BLOCK_FILE = strdup(optarg);
if (DATA_FILE == NULL) if (DATA_FILE == NULL || BLOCK_FILE == NULL)
exit_toxic_err("failed in parse_args", FATALERR_MEMORY); exit_toxic_err("failed in parse_args", FATALERR_MEMORY);
strcat(BLOCK_FILE, "-blocklist");
break; break;
case 'x': case 'x':
@ -560,39 +559,67 @@ static void parse_args(int argc, char *argv[])
} }
} }
int main(int argc, char *argv[]) #define DATANAME "data"
#define BLOCKNAME "data-blocklist"
static int init_data_files(void)
{ {
char *user_config_dir = get_user_config_dir(); char *user_config_dir = get_user_config_dir();
int config_err = 0; int config_err = create_user_config_dir(user_config_dir);
parse_args(argc, argv);
/* Make sure all written files are read/writeable only by the current user. */
umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
signal(SIGINT, catch_SIGINT);
config_err = create_user_config_dir(user_config_dir);
if (DATA_FILE == NULL ) { if (DATA_FILE == NULL ) {
if (config_err) { if (config_err) {
DATA_FILE = strdup("data"); DATA_FILE = strdup(DATANAME);
BLOCK_FILE = strdup(BLOCKNAME);
if (DATA_FILE == NULL) if (DATA_FILE == NULL || BLOCK_FILE == NULL)
exit_toxic_err("failed in main", FATALERR_MEMORY); exit_toxic_err("failed in load_data_structures", FATALERR_MEMORY);
} else { } else {
DATA_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen("data") + 1); DATA_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(DATANAME) + 1);
BLOCK_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(BLOCKNAME) + 1);
if (DATA_FILE == NULL) if (DATA_FILE == NULL || BLOCK_FILE == NULL)
exit_toxic_err("failed in main", FATALERR_MEMORY); exit_toxic_err("failed in load_data_structures", FATALERR_MEMORY);
strcpy(DATA_FILE, user_config_dir); strcpy(DATA_FILE, user_config_dir);
strcat(DATA_FILE, CONFIGDIR); strcat(DATA_FILE, CONFIGDIR);
strcat(DATA_FILE, "data"); strcat(DATA_FILE, DATANAME);
strcpy(BLOCK_FILE, user_config_dir);
strcat(BLOCK_FILE, CONFIGDIR);
strcat(BLOCK_FILE, BLOCKNAME);
} }
} }
free(user_config_dir); free(user_config_dir);
return config_err;
}
#define REC_TOX_DO_LOOPS_PER_SEC 25
/* Adjusts usleep value so that tox_do runs close to the recommended number of times per second */
static useconds_t optimal_msleepval(uint64_t *looptimer, uint64_t *loopcount, uint64_t cur_time, useconds_t msleepval)
{
useconds_t new_sleep = msleepval;
++(*loopcount);
if (*looptimer == cur_time)
return new_sleep;
if (*loopcount != REC_TOX_DO_LOOPS_PER_SEC)
new_sleep *= (double) *loopcount / REC_TOX_DO_LOOPS_PER_SEC;
*looptimer = cur_time;
*loopcount = 0;
return new_sleep;
}
int main(int argc, char *argv[])
{
parse_args(argc, argv);
/* Make sure all written files are read/writeable only by the current user. */
umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
signal(SIGINT, catch_SIGINT);
int config_err = init_data_files();
/* init user_settings struct and load settings from conf file */ /* init user_settings struct and load settings from conf file */
user_settings_ = calloc(1, sizeof(struct user_settings)); user_settings_ = calloc(1, sizeof(struct user_settings));
@ -644,7 +671,7 @@ int main(int argc, char *argv[])
const char *msg; const char *msg;
if (config_err) { if (config_err) {
msg = "Unable to determine configuration directory. Defaulting to 'data' for a keyfile..."; msg = "Unable to determine configuration directory. Defaulting to 'data' for data file...";
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, msg); line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
} }
@ -653,9 +680,10 @@ int main(int argc, char *argv[])
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, msg); line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
} }
sort_friendlist_index();
uint64_t last_save = (uint64_t) time(NULL); uint64_t last_save = (uint64_t) time(NULL);
uint64_t looptimer = last_save;
useconds_t msleepval = 40000;
uint64_t loopcount = 0;
/* Redirect stdout to /dev/null /* Redirect stdout to /dev/null
@ -676,7 +704,8 @@ int main(int argc, char *argv[])
last_save = cur_time; last_save = cur_time;
} }
usleep(40000); msleepval = optimal_msleepval(&looptimer, &loopcount, cur_time, msleepval);
usleep(msleepval);
} }
return 0; return 0;

View File

@ -50,7 +50,7 @@
#define TIME_STR_SIZE 16 #define TIME_STR_SIZE 16
/* ASCII key codes */ /* ASCII key codes */
#define T_KEY_ESC 0X1B /* esc key */ #define T_KEY_ESC 0x1B /* ESC key */
#define T_KEY_KILL 0x0B /* ctrl-k */ #define T_KEY_KILL 0x0B /* ctrl-k */
#define T_KEY_DISCARD 0x15 /* ctrl-u */ #define T_KEY_DISCARD 0x15 /* ctrl-u */
#define T_KEY_NEXT 0x10 /* ctrl-p */ #define T_KEY_NEXT 0x10 /* ctrl-p */
@ -63,12 +63,13 @@
#define T_KEY_C_F 0x06 /* ctrl-f */ #define T_KEY_C_F 0x06 /* ctrl-f */
#define T_KEY_C_H 0x08 /* ctrl-h */ #define T_KEY_C_H 0x08 /* ctrl-h */
#define T_KEY_C_Y 0x19 /* ctrl-y */ #define T_KEY_C_Y 0x19 /* ctrl-y */
#define T_KEY_TAB 0x09 /* TAB key */
#define ONLINE_CHAR "*" #define ONLINE_CHAR "*"
#define OFFLINE_CHAR "*" #define OFFLINE_CHAR "o"
typedef enum _FATAL_ERRS { typedef enum _FATAL_ERRS {
FATALERR_MEMORY = -1, /* malloc() or calloc() failed */ FATALERR_MEMORY = -1, /* heap memory allocation failed */
FATALERR_FREAD = -2, /* fread() failed on critical read */ FATALERR_FREAD = -2, /* fread() failed on critical read */
FATALERR_THREAD_CREATE = -3, /* thread creation failed */ FATALERR_THREAD_CREATE = -3, /* thread creation failed */
FATALERR_MUTEX_INIT = -4, /* mutex init failed */ FATALERR_MUTEX_INIT = -4, /* mutex init failed */

View File

@ -33,12 +33,14 @@
#include "chat.h" #include "chat.h"
#include "line_info.h" #include "line_info.h"
#include "settings.h"
extern char *DATA_FILE; extern char *DATA_FILE;
extern struct _Winthread Winthread; extern struct _Winthread Winthread;
static ToxWindow windows[MAX_WINDOWS_NUM]; static ToxWindow windows[MAX_WINDOWS_NUM];
static ToxWindow *active_window; static ToxWindow *active_window;
extern ToxWindow *prompt; extern ToxWindow *prompt;
extern struct user_settings *user_settings_;
static int num_active_windows; static int num_active_windows;
@ -65,6 +67,9 @@ void on_connectionchange(Tox *m, int32_t friendnumber, uint8_t status, void *use
void on_typing_change(Tox *m, int32_t friendnumber, uint8_t is_typing, void *userdata) void on_typing_change(Tox *m, int32_t friendnumber, uint8_t is_typing, void *userdata)
{ {
if (user_settings_->show_typing_other == SHOW_TYPING_OFF)
return;
int i; int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) { for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
@ -267,7 +272,7 @@ void set_next_window(int ch)
ToxWindow *inf = active_window; ToxWindow *inf = active_window;
while (true) { while (true) {
if (ch == T_KEY_NEXT) { if (ch == user_settings_->key_next_tab) {
if (++active_window > end) if (++active_window > end)
active_window = windows; active_window = windows;
} else if (--active_window < windows) } else if (--active_window < windows)
@ -452,7 +457,7 @@ void draw_active_window(Tox *m)
ltr = isprint(ch); ltr = isprint(ch);
#endif /* HAVE_WIDECHAR */ #endif /* HAVE_WIDECHAR */
if (!ltr && (ch == T_KEY_NEXT || ch == T_KEY_PREV)) { if (!ltr && (ch == user_settings_->key_next_tab || ch == user_settings_->key_prev_tab)) {
set_next_window((int) ch); set_next_window((int) ch);
} else { } else {
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
@ -475,6 +480,17 @@ void refresh_inactive_windows(void)
} }
} }
/* returns a pointer to the ToxWindow in the ith index. Returns NULL if no ToxWindow exists */
ToxWindow *get_window_ptr(int i)
{
ToxWindow *toxwin = NULL;
if (windows[i].active)
toxwin = &windows[i];
return toxwin;
}
int get_num_active_windows(void) int get_num_active_windows(void)
{ {
return num_active_windows; return num_active_windows;

View File

@ -71,6 +71,14 @@ struct _Winthread {
bool flag_resize; bool flag_resize;
}; };
struct arg_opts {
int ignore_data_file;
int use_ipv4;
int default_locale;
char config_path[MAX_STR_SIZE];
char nodes_path[MAX_STR_SIZE];
};
typedef struct ToxWindow ToxWindow; typedef struct ToxWindow ToxWindow;
typedef struct StatusBar StatusBar; typedef struct StatusBar StatusBar;
typedef struct PromptBuf PromptBuf; typedef struct PromptBuf PromptBuf;
@ -216,6 +224,7 @@ void set_active_window(int ch);
int get_num_active_windows(void); int get_num_active_windows(void);
void kill_all_windows(void); /* should only be called on shutdown */ void kill_all_windows(void); /* should only be called on shutdown */
void on_window_resize(void); void on_window_resize(void);
ToxWindow *get_window_ptr(int i);
/* refresh inactive windows to prevent scrolling bugs. /* refresh inactive windows to prevent scrolling bugs.
call at least once per second */ call at least once per second */