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

Compare commits

...

84 Commits

Author SHA1 Message Date
dc2d20f4c4 bump version to 0.4.7 2014-08-04 22:28:12 -04:00
d712ccc17e Merge pull request #215 from mannol1/master
Fix ringing sounds
2014-08-05 01:41:21 +02:00
147030e06f Fix ringing sounds 2014-08-05 01:41:06 +02:00
09fd5cb69f small fix 2014-08-04 18:04:54 -04:00
64db9f73a2 update file transfers for core changes 2014-08-04 16:47:45 -04:00
28633be2dd a few fixes and improve error messages 2014-08-04 14:35:34 -04:00
6fdafceda8 add ability to cancel file transfers 2014-08-04 02:03:23 -04:00
38ed0c86ad use hangup cmd to cancel outgoing call requests 2014-08-03 23:11:19 -04:00
ad23816096 fix filetransfer bug 2014-08-03 16:44:21 -04:00
bc4a730e76 re-adding until better solution found 2014-08-03 15:42:14 -04:00
79372cc80d don't show full path when sending files 2014-08-03 15:12:55 -04:00
c9e4246ac5 Merge branch 'master' of https://github.com/Tox/toxic 2014-08-03 11:54:49 -04:00
dcd6a238b6 Merge pull request #213 from doughdemon/master
Add missing includes
2014-08-03 11:48:03 -04:00
c49de7733c Add missing includes
Fixes compilation with musl libc
2014-08-03 09:44:48 +02:00
3fc7c90630 stderr redirect doesn't work as intended, add invalid command message when no sound 2014-08-03 01:31:33 -04:00
53663a7832 try to end curses session gracefully on SIGSEGV 2014-08-03 00:26:44 -04:00
c14f2a3fcd put chatlogs in their own directory 2014-08-02 21:03:59 -04:00
3cbe61e111 fix a few formatting bugs and simplify code a bit 2014-08-02 15:35:57 -04:00
fa023c6a99 Merge pull request #211 from mannol1/master
Fix bug
2014-08-02 19:22:45 +02:00
f98e6bdcb4 Fix bug 2014-08-02 19:21:40 +02:00
0884954c84 fix data file init bug 2014-08-02 13:04:29 -04:00
43727c6730 Merge pull request #210 from mannol1/master
Fresh pack of backdoors
2014-08-02 17:31:36 +02:00
618b731d5a fix possible buffer overflow 2014-08-01 23:00:52 -04:00
46975bf38b Updated with latest core 2014-08-02 02:10:21 +02:00
8f3989000d Box notifications are like ready 2014-08-02 00:37:02 +02:00
9fe75fbc47 fix 2014-08-01 15:05:10 -04:00
c455e79604 dynamically adjust main loop sleep time according to recommended value 2014-08-01 13:56:49 -04:00
a223545853 close chatwindow if its associated contact is blocked/deleted 2014-07-31 22:05:09 -04:00
b243f7aa62 Merge branch 'master' of https://github.com/Tox/toxic 2014-07-31 15:13:10 -04:00
899452d7cd Merge branch 'block' 2014-07-31 15:04:05 -04:00
af68fa7ee0 endian correctness 2014-07-31 15:02:19 -04:00
5da789cc37 save last online data in blocked list 2014-07-31 14:53:02 -04:00
7e5b41c8e0 another apple include: <sys/syslimits.h>
for NAME_MAX
2014-07-31 10:52:36 -07:00
0254596c73 add help menu for friendlist 2014-07-31 13:49:15 -04:00
67c02404b7 alut is not part of OpenAL.framework on OS X
therefore the linux include path works fine
2014-07-31 10:38:04 -07:00
0b5ee7e2c7 Merge pull request #208 from Ansa89/makefile-update
Makefile: refactoring and adding desktop notifications support
2014-07-31 12:51:44 -04:00
fba0732faa implement contact blocking 2014-07-31 12:48:49 -04:00
d06086a656 Try to support older versions of OpenAL 2014-07-31 13:14:33 +02:00
e74b678739 check_features.mk: modify string comparison 2014-07-31 11:54:22 +02:00
b62787ce47 Makefile: refactoring and adding desktop notifications support 2014-07-30 14:14:13 +02:00
75708f7600 couple small fixes 2014-07-30 02:46:08 -04:00
476dec46b6 add settings to toggle typing notifications for self and others 2014-07-29 20:14:44 -04:00
973f6206ee enforce const correctess, fix undefined behaviour with string literals 2014-07-29 14:54:34 -04:00
cbe47b3660 Merge pull request #207 from Ansa89/manpage-update
Update toxic.conf manpage
2014-07-29 11:51:58 -04:00
1c58c339bb Update toxic.conf manpage 2014-07-29 12:07:24 +02:00
15e91cfa99 formatting, use case-insensitive string compare, use defines for keycodes 2014-07-28 21:47:35 -04:00
f4fb6ea4fc Merge branch 'gracchus163-master' 2014-07-28 20:45:52 -04:00
0d2ff2c0a8 Fixed toxic.conf.example mistakes 2014-07-29 01:28:10 +01:00
5275da5a6b Merge branch 'keybinds'
configurable keybinds finished and working, merging with master branch
2014-07-29 00:55:39 +01:00
e891b1281b Configurable keybinds implemented and example conf updated 2014-07-29 00:53:44 +01:00
ca7110b37c small visual adjustment to progress bar 2014-07-28 19:36:30 -04:00
8960eb98f4 Example conf updated 2014-07-28 22:47:33 +01:00
18610668b8 Human readable config parsing complete, few tests left to confirm 2014-07-28 22:44:12 +01:00
efe61e32e2 Merge pull request #204 from zetok/symbol
Fix ONLINE_CHAR being identical to OFFLINE_CHAR
2014-07-28 13:39:40 -04:00
7a7e4f573a Fix ONLINE_CHAR being identical to OFFLINE_CHAR 2014-07-28 18:38:15 +01:00
a7e6ab7758 reads correctly from config file now, need to go through and check each one and then look at usability 2014-07-28 15:19:50 +01:00
a0cde4ae8c Merge remote-tracking branch 'origin/master' into keybinds 2014-07-28 14:06:54 +01:00
7566aa9d26 Merge pull request #205 from loadedice/master
Lowered volume of sounds
2014-07-28 03:14:29 -04:00
d2332a5b77 Lowered volume of sounds 2014-07-28 16:42:57 +10:00
94a8ce5aa8 fix buggy path autocomplete behaviour 2014-07-28 01:33:12 -04:00
b18a67d656 put file senders in a round-robin queue so multiple transfers upload at a uniform pace 2014-07-27 22:27:27 -04:00
02708534c0 Merge pull request #200 from mannol1/master
Core adjustments
2014-07-28 01:35:58 +02:00
d5710d80e0 Upstream adaption 2014-07-28 01:35:40 +02:00
8dcba3219d Merge remote-tracking branch 'origin/master' into keybinds 2014-07-28 00:32:05 +01:00
9f01a45b1f Keybind defaults moved to settings.c; conf keybinds not reading correctly yet 2014-07-28 00:06:25 +01:00
dd2cb93ecc Merge pull request #203 from zetok/manpages
Put man pages in right place by default (#202)
2014-07-27 18:15:32 -04:00
49538a986c improve file transfer progress line 2014-07-27 18:00:33 -04:00
26c2331d0f Put man pages in right place by default (#202) 2014-07-27 21:06:37 +01:00
a0758643c2 fix blurry screenshot? 2014-07-27 03:36:06 -04:00
77e152ad36 fix security flaw where untrusted input wasn't being sanitized 2014-07-26 21:22:55 -04:00
4834642b80 Merge remote-tracking branch 'upstream/master' 2014-07-27 01:50:06 +02:00
18a6f621f0 Started adding support for popup notifications and adjustments to new core 2014-07-27 01:49:59 +02:00
3cae1d92cd change online/offline symbols 2014-07-26 19:16:07 -04:00
02b192d6ee fix bug and typo 2014-07-25 20:17:22 -04:00
f630a3e604 fix possible buffer overflows and undefined behaviour 2014-07-25 17:55:21 -04:00
fb5a9bc043 fix backspace bug, simplify a bit 2014-07-25 15:51:29 -04:00
26ad5a00a3 Fixed out of bounds read. 2014-07-25 15:17:46 -04:00
18e1f08e31 Merge branch 'master' of https://github.com/Tox/toxic 2014-07-24 23:04:07 -04:00
b68deef6db allow line_info_add to take formatted strings with variable # of args 2014-07-24 23:03:55 -04:00
30ec7debba Merge pull request #199 from mannol1/master
Fixed sounds not playing
2014-07-25 02:13:24 +02:00
3a1e23a3ff Fixed sounds not playing 2014-07-25 02:12:32 +02:00
0887bb7662 Merge pull request #198 from Ansa89/master
README.md: add precompiled binaries
2014-07-24 13:24:51 +02:00
5a55f738a9 README.md: add precompiled binaries 2014-07-24 13:05:56 +02:00
8d8df585ad sort directories and skip special symbols for path autocomplete 2014-07-23 18:34:32 -04:00
64 changed files with 2443 additions and 1008 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 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
@ -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')
##### 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')
##### 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')
##### Desktop notifications
* [libnotify](https://developer.gnome.org/libnotify) (for Debian based systems, 'libnotify-dev')
### Compiling
1. `cd build/`
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
* 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)
* Audio call support is automatically enabled if all dependencies are found
* If you want to build toxic without audio call support, you can use `make DISABLE_AV=1`
* Sound notifications support is automatically enabled if all dependencies are found
* If you want to build toxic without sound notifications support, you can use `make DISABLE_NOTIFY=1`
* Additional features are automatically enabled if all dependencies are found, but you can disable them by using special variables:
* `DISABLE_AV=1` build toxic without audio call support
* `DISABLE_SOUND_NOTIFY=1` → build toxic without sound notifications support
* `DISABLE_DESKTOP_NOTIFY=1` build toxic without desktop notifications support
### Packaging
* For packaging purpose, you can use `DESTDIR=""` to specify a directory where to store installed files
@ -49,6 +52,11 @@ echo '/usr/local/lib/' | sudo tee -a /etc/ld.so.conf.d/locallib.conf
sudo ldconfig
```
## Precompiled binaries
You can download precompiled binaries from [jenkins](https://jenkins.libtoxcore.so):
* [Linux 32 bit](https://jenkins.libtoxcore.so/job/toxic_linux_i386/lastSuccessfulBuild/artifact/toxic_linux_i386.tar.xz)
* [Linux 64 bit](https://jenkins.libtoxcore.so/job/toxic_linux_amd64/lastSuccessfulBuild/artifact/toxic_linux_amd64.tar.xz)
## Settings
Running Toxic for the first time creates an empty file called toxic.conf in your home configuration directory ("~/.config/tox" for Linux users). Adding options to this file allows you to enable auto-logging, change the time format (12/24 hour), and much more.
You can view our example config file [here](misc/toxic.conf.example).

View File

@ -1,21 +1,13 @@
TOXIC_VERSION = 0.4.6
TOXIC_VERSION = 0.4.7
REV = $(shell git rev-list HEAD --count)
VERSION = $(TOXIC_VERSION)_r$(REV)
CFG_DIR = ../cfg
SRC_DIR = ../src
MISC_DIR = ../misc
DOC_DIR = ../doc
SND_DIR = ../sounds
PREFIX = /usr/local
BINDIR = $(PREFIX)/bin
DATADIR = $(PREFIX)/share/toxic
MANDIR = $(PREFIX)/man
DATAFILES = DHTnodes toxic.conf.example
MANFILES = toxic.1 toxic.conf.5
SNDFILES = ContactLogsIn.wav ContactLogsOut.wav Error.wav IncomingCall.wav
SNDFILES += LogIn.wav LogOut.wav NewMessage.wav OutgoingCall.wav
SNDFILES += TransferComplete.wav TransferPending.wav
MANDIR = $(PREFIX)/share/man
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 += 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
UNAME_S = $(shell uname -s)
ifeq ($(UNAME_S), Linux)
-include $(CFG_DIR)/Linux.mk
-include $(CFG_DIR)/systems/Linux.mk
endif
ifeq ($(UNAME_S), FreeBSD)
-include $(CFG_DIR)/FreeBSD.mk
-include $(CFG_DIR)/systems/FreeBSD.mk
endif
ifeq ($(UNAME_S), Darwin)
-include $(CFG_DIR)/Darwin.mk
-include $(CFG_DIR)/systems/Darwin.mk
endif
ifeq ($(UNAME_S), Solaris)
-include $(CFG_DIR)/Solaris.mk
-include $(CFG_DIR)/systems/Solaris.mk
endif
# Check on which platform we are running
UNAME_M = $(shell uname -m)
ifeq ($(UNAME_M), x86_64)
-include $(CFG_DIR)/x86_64.mk
-include $(CFG_DIR)/platforms/x86_64.mk
endif
ifneq ($(filter %86, $(UNAME_M)),)
-include $(CFG_DIR)/x86.mk
-include $(CFG_DIR)/platforms/x86.mk
endif
ifneq ($(filter arm%, $(UNAME_M)),)
-include $(CFG_DIR)/arm.mk
-include $(CFG_DIR)/platforms/arm.mk
endif
# Check if we can use X11
CHECK_X11_LIBS = $(shell pkg-config x11 || echo -n "error")
ifneq ($(CHECK_X11_LIBS), error)
LIBS += x11
CFLAGS += -D_X11
endif
# Check if we want/can build audio
ifneq ($(DISABLE_AV), 1)
CHECK_AUDIO_LIBS = $(shell pkg-config $(AUDIO_LIBS) || echo -n "error")
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
# Include all needed checks
-include $(CFG_DIR)/check_features.mk
# Targets
all: toxic
@ -135,33 +58,6 @@ toxic: $(OBJ)
@echo " LD $@"
@$(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
@echo " CC $@"
@$(CC) $(CFLAGS) -o $*.o -c $(SRC_DIR)/$*.c
@ -170,8 +66,9 @@ install: toxic
clean:
rm -rf *.d *.o toxic
-include $(CFG_DIR)/help.mk
-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

@ -9,7 +9,8 @@ help:
@echo
@echo "-- Variables --"
@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 " DISABLE_DESKTOP_NOTIFY: Set to \"1\" to force building without desktop notifications support"
@echo " USER_CFLAGS: Add custom flags to default CFLAGS"
@echo " USER_LDFLAGS: Add custom flags to default LDFLAGS"
@echo " PREFIX: Specify a prefix directory for binaries, data files,... (default is \"$(abspath $(PREFIX))\")"

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>
.B = {
.PP
.IB <KEY1> : <BOOL_VALUE> ;
.IB <KEY1> = <VALUE1> ;
.br
.IB <KEY2> = <NOT_BOOL_VALUE> ;
.IB <KEY2> = <VALUE2> ;
.br
...
.PP
@ -27,7 +27,7 @@ Sections:
.PP
.B ui
.RS
Configurations related to user interface.
Configurations related to user interface elements.
.PP
Keys:
.br
@ -66,6 +66,20 @@ Select between 24 and 12 hour time.
Values: 24, 12
.RE
.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
.RS
Maximum lines for chat window history.
@ -119,6 +133,8 @@ Values: <STRING> (absolute path where to store downloaded files)
.B sounds
.RS
Configurations related to notification sounds.
.br
(Special value "silent" can be used to disable a specific notification)
.PP
Keys:
.br
@ -192,6 +208,78 @@ Sound to play when a file transfer is completed.
Values: <STRING> (sound file absolute path)
.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
Default settings from __DATADIR__/toxic.conf.exmaple:
.PP
@ -200,36 +288,43 @@ Default settings from __DATADIR__/toxic.conf.exmaple:
// USES LIBCONFIG-ACCEPTED SYNTAX
.br
ui = {
.br
.RS
// true to enable timestamps, false to disable
.br
timestamps:true;
.br
timestamps=true;
.br
// true to enable terminal alerts on messages, false to disable
.br
alerts:true;
alerts=true;
.br
// true to use native terminal colours, false to use toxic default colour theme
.br
native_colors:false;
native_colors=false;
.br
// true to enable autologging, false to disable
.br
autolog:false;
autolog=false;
.br
// 24 or 12 hour time
.br
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
// maximum lines for chat window history
.br
history_size=700;
.br
.RE
};
.br
.PP
audio = {
.br
.RS
// preferred audio input device; numbers correspond to /lsdev in
.br
input_device=2;
@ -241,21 +336,21 @@ audio = {
// default VAD treshold; float (recommended values are around 40)
.br
VAD_treshold=40.0;
.br
.RE
};
.br
.PP
tox = {
.br
.RS
// where to store received files
.br
// download_path="/home/USERNAME/Downloads/";
.br
//download_path="/home/USERNAME/Downloads/";
.RE
};
.br
.PP
// To disable a sound set the path to "silent"
.br
sounds = {
.br
.RS
error="__DATADIR__/sounds/Error.wav";
.br
self_log_in="__DATADIR__/sounds/LogIn.wav";
@ -275,7 +370,33 @@ sounds = {
transfer_pending="__DATADIR__/sounds/TransferPending.wav";
.br
transfer_completed="__DATADIR__/sounds/TransferComplete.wav";
.RE
};
.PP
// Currently supported: Ctrl modified keys, Tab, PAGEUP and PAGEDOWN (case insensitive)
.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
.IP ~/.config/tox/toxic.conf

View File

@ -3,20 +3,26 @@
ui = {
// true to enable timestamps, false to disable
timestamps:true;
timestamps=true;
// 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
native_colors:false;
native_colors=false;
// true to enable autologging, false to disable
autolog:false;
autolog=false;
// 24 or 12 hour time
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
history_size=700;
};
@ -34,7 +40,7 @@ audio = {
tox = {
// where to store received files
// download_path="/home/USERNAME/Downloads/";
//download_path="/home/USERNAME/Downloads/";
};
// To disable a sound set the path to "silent"
@ -50,3 +56,18 @@ sounds = {
transfer_pending="__DATADIR__/sounds/TransferPending.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
#include <AL/al.h>
#include <AL/alc.h>
/* compatibility with older versions of OpenAL */
#ifndef ALC_ALL_DEVICES_SPECIFIER
#include <AL/alext.h>
#endif
#endif
#define _cbend pthread_exit(NULL)
@ -78,7 +82,7 @@ struct _ASettings {
ToxAv *av;
ToxAvCodecSettings cs;
ToxAvCSettings cs;
Call calls[MAX_CALLS];
} ASettins;
@ -96,11 +100,11 @@ void callback_peer_timeout ( void* av, int32_t call_index, void *arg );
void callback_media_change ( void* av, int32_t call_index, void *arg );
int stop_transmission(int call_index);
void write_device_callback(ToxAv* av, int32_t call_index, int16_t* data, int size);
void write_device_callback(ToxAv* av, int32_t call_index, int16_t* data, int size, void* userdata);
static void print_err (ToxWindow *self, char *error_str)
static void print_err (ToxWindow *self, const char *error_str)
{
line_info_add(self, NULL, NULL, NULL, error_str, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", error_str);
}
ToxAv *init_audio(ToxWindow *self, Tox *tox)
@ -123,7 +127,7 @@ ToxAv *init_audio(ToxWindow *self, Tox *tox)
}
if ( init_devices(ASettins.av) == de_InternalError ) {
line_info_add(self, NULL, NULL, NULL, "Failed to init devices", SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init devices");
toxav_kill(ASettins.av);
return ASettins.av = NULL;
}
@ -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_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;
}
@ -171,10 +175,14 @@ 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)
{
if (ASettins.calls[call_index].ttas)
write_out(ASettins.calls[call_index].out_idx, data, size, 1);
(void)userdata;
if (call_index >= 0 && ASettins.calls[call_index].ttas) {
ToxAvCSettings csettings = ASettins.cs;
toxav_get_peer_csettings(av, call_index, 0, &csettings);
write_out(ASettins.calls[call_index].out_idx, data, size, csettings.audio_channels);
}
}
int start_transmission(ToxWindow *self)
@ -182,8 +190,8 @@ int start_transmission(ToxWindow *self)
if ( !ASettins.av || self->call_idx == -1 ) return -1;
/* Don't provide support for video */
if ( 0 != toxav_prepare_transmission(ASettins.av, self->call_idx, &ASettins.cs, 0) ) {
line_info_add(self, NULL, NULL, NULL, "Could not prepare transmission", SYS_MSG, 0, 0);
if ( 0 != toxav_prepare_transmission(ASettins.av, self->call_idx, av_jbufdc * 2, av_VADd, 0) ) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Could not prepare transmission");
}
if ( !toxav_capability_supported(ASettins.av, self->call_idx, AudioDecoding) ||
@ -192,18 +200,21 @@ int start_transmission(ToxWindow *self)
set_call(&ASettins.calls[self->call_idx], _True);
ToxAvCSettings csettings;
toxav_get_peer_csettings(ASettins.av, self->call_idx, 0, &csettings);
if ( open_primary_device(input, &ASettins.calls[self->call_idx].in_idx,
av_DefaultSettings.audio_sample_rate, av_DefaultSettings.audio_frame_duration) != de_None )
line_info_add(self, NULL, NULL, NULL, "Failed to open input device!", SYS_MSG, 0, 0);
csettings.audio_sample_rate, csettings.audio_frame_duration, csettings.audio_channels) != de_None )
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open input device!");
if ( register_device_callback(self->call_idx, ASettins.calls[self->call_idx].in_idx,
read_device_callback, &self->call_idx, _True) != de_None)
/* Set VAD as true for all; TODO: Make it more dynamic */
line_info_add(self, NULL, NULL, NULL, "Failed to register input handler!", SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to register input handler!");
if ( open_primary_device(output, &ASettins.calls[self->call_idx].out_idx,
av_DefaultSettings.audio_sample_rate, av_DefaultSettings.audio_frame_duration) != de_None ) {
line_info_add(self, NULL, NULL, NULL, "Failed to open output device!", SYS_MSG, 0, 0);
csettings.audio_sample_rate, csettings.audio_frame_duration, csettings.audio_channels) != de_None ) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open output device!");
ASettins.calls[self->call_idx].has_output = 0;
}
@ -259,7 +270,7 @@ void callback_recv_starting ( void* av, int32_t call_index, void* arg )
if (windows[i].onStarting != NULL && windows[i].call_idx == call_index) {
windows[i].onStarting(&windows[i], ASettins.av, call_index);
if ( 0 != start_transmission(&windows[i]) ) {/* YEAH! */
line_info_add(&windows[i], NULL, NULL, NULL, "Error starting transmission!", SYS_MSG, 0, 0);
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0 , "Error starting transmission!");
}
return;
}
@ -278,7 +289,7 @@ void callback_call_started ( void* av, int32_t call_index, void* arg )
if (windows[i].onStart != NULL && windows[i].call_idx == call_index) {
windows[i].onStart(&windows[i], ASettins.av, call_index);
if ( 0 != start_transmission(&windows[i]) ) {/* YEAH! */
line_info_add(&windows[i], NULL, NULL, NULL, "Error starting transmission!", SYS_MSG, 0, 0);
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!");
return;
}
}
@ -327,11 +338,10 @@ void callback_media_change(void* av, int32_t call_index, void* arg)
*/
void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
char msg[MAX_STR_SIZE];
char *error_str;
const char *error_str;
if (argc != 0) {
error_str = "Invalid syntax!";
error_str = "Unknown arguments.";
goto on_error;
}
@ -345,7 +355,7 @@ void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
goto on_error;
}
ToxAvError error = toxav_call(ASettins.av, &self->call_idx, self->num, TypeAudio, 30);
ToxAvError error = toxav_call(ASettins.av, &self->call_idx, self->num, &ASettins.cs, 30);
if ( error != ErrorNone ) {
if ( error == ErrorAlreadyInCall ) error_str = "Already in a call!";
@ -354,21 +364,19 @@ void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
goto on_error;
}
snprintf(msg, sizeof(msg), "Calling... idx: %d", self->call_idx);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Calling... idx: %d", self->call_idx);
return;
on_error:
snprintf(msg, sizeof(msg), "%s", error_str);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
print_err(self, error_str);
}
void cmd_answer(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
char *error_str;
const char *error_str;
if (argc != 0) {
error_str = "Invalid syntax!";
error_str = "Unknown arguments.";
goto on_error;
}
@ -377,7 +385,7 @@ void cmd_answer(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
goto on_error;
}
ToxAvError error = toxav_answer(ASettins.av, self->call_idx, TypeAudio);
ToxAvError error = toxav_answer(ASettins.av, self->call_idx, &ASettins.cs);
if ( error != ErrorNone ) {
if ( error == ErrorInvalidState ) error_str = "Cannot answer in invalid state!";
@ -396,10 +404,10 @@ on_error:
void cmd_reject(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
char *error_str;
const char *error_str;
if (argc != 0) {
error_str = "Invalid syntax!";
error_str = "Unknown arguments.";
goto on_error;
}
@ -427,10 +435,10 @@ on_error:
void cmd_hangup(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
char *error_str;
const char *error_str;
if (argc != 0) {
error_str = "Invalid syntax!";
error_str = "Unknown arguments.";
goto on_error;
}
@ -439,7 +447,18 @@ void cmd_hangup(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
goto on_error;
}
ToxAvError error = toxav_hangup(ASettins.av, self->call_idx);
ToxAvError error;
if (toxav_get_call_state(ASettins.av, self->call_idx) == av_CallInviting) {
error = toxav_cancel(ASettins.av, self->call_idx, self->num,
"Only those who appreciate small things know the beauty that is life");
#ifdef _SOUND_NOTIFY
stop_sound(self->ringing_sound);
#endif
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call canceled!");
} else {
error = toxav_hangup(ASettins.av, self->call_idx);
}
if ( error != ErrorNone ) {
if ( error == ErrorInvalidState ) error_str = "Cannot hangup in invalid state!";
@ -454,47 +473,9 @@ on_error:
print_err (self, error_str);
}
void cmd_cancel(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
char *error_str;
if (argc != 0) {
error_str = "Invalid syntax!";
goto on_error;
}
if ( !ASettins.av ) {
error_str = "Audio not supported!";
goto on_error;
}
ToxAvError error = toxav_cancel(ASettins.av, self->call_idx, self->num,
"Only those who appreciate small things know the beauty that is life");
if ( error != ErrorNone ) {
if ( error == ErrorNoCall ) error_str = "No call!";
else if ( error == ErrorInvalidState ) error_str = "Cannot cancel in invalid state!";
else error_str = "Internal error!";
goto on_error;
}
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
#endif /* _SOUND_NOTIFY */
/* Callback will print status... */
return;
on_error:
print_err (self, error_str);
}
void cmd_list_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
char msg[MAX_STR_SIZE];
char *error_str;
const char *error_str;
if ( argc != 1 ) {
if ( argc < 1 ) error_str = "Type must be specified!";
@ -512,8 +493,7 @@ void cmd_list_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*
type = output;
else {
snprintf(msg, sizeof(msg), "Invalid type: %s", argv[1]);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
return;
}
@ -527,8 +507,7 @@ on_error:
/* This changes primary device only */
void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
char msg[MAX_STR_SIZE];
char *error_str;
const char *error_str;
if ( argc != 2 ) {
if ( argc < 1 ) error_str = "Type must be specified!";
@ -547,8 +526,7 @@ void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (
type = output;
else {
snprintf(msg, sizeof(msg), "Invalid type: %s", argv[1]);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
return;
}
@ -571,10 +549,9 @@ on_error:
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])
{
char msg[MAX_STR_SIZE];
char *error_str;
const char *error_str;
if ( argc != 2 ) {
if ( argc < 1 ) error_str = "Type must be specified!";
@ -593,8 +570,7 @@ void cmd_ccur_device(WINDOW * window, ToxWindow * self, Tox *m, int argc, char (
type = output;
else {
snprintf(msg, sizeof(msg), "Invalid type: %s", argv[1]);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
return;
}
@ -616,19 +592,23 @@ void cmd_ccur_device(WINDOW * window, ToxWindow * self, Tox *m, int argc, char (
if ( self->call_idx > -1) {
Call* this_call = &ASettins.calls[self->call_idx];
if (this_call->ttas) {
ToxAvCSettings csettings;
toxav_get_peer_csettings(ASettins.av, self->call_idx, 0, &csettings);
if (type == output) {
pthread_mutex_lock(&this_call->mutex);
close_device(output, this_call->out_idx);
this_call->has_output = open_device(output, selection, &this_call->out_idx,
av_DefaultSettings.audio_sample_rate, av_DefaultSettings.audio_frame_duration)
csettings.audio_sample_rate, csettings.audio_frame_duration, csettings.audio_channels)
== de_None ? 1 : 0;
pthread_mutex_unlock(&this_call->mutex);
}
else {
/* TODO: check for failure */
close_device(input, this_call->in_idx);
open_device(input, selection, &this_call->in_idx,
av_DefaultSettings.audio_sample_rate, av_DefaultSettings.audio_frame_duration);
open_device(input, selection, &this_call->in_idx, csettings.audio_sample_rate,
csettings.audio_frame_duration, csettings.audio_channels);
/* Set VAD as true for all; TODO: Make it more dynamic */
register_device_callback(self->call_idx, this_call->in_idx, read_device_callback, &self->call_idx, _True);
}
@ -642,10 +622,9 @@ void cmd_ccur_device(WINDOW * window, ToxWindow * self, Tox *m, int argc, char (
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])
{
char msg[MAX_STR_SIZE];
char *error_str;
const char *error_str;
if ( argc != 1 ) {
if ( argc < 1 ) error_str = "Type must be specified!";
@ -656,15 +635,14 @@ void cmd_mute(WINDOW * window, ToxWindow * self, Tox *m, int argc, char (*argv)[
DeviceType type;
if ( strcmp(argv[1], "in") == 0 ) /* Input devices */
if ( strcasecmp(argv[1], "in") == 0 ) /* Input devices */
type = input;
else if ( strcmp(argv[1], "out") == 0 ) /* Output devices */
else if ( strcasecmp(argv[1], "out") == 0 ) /* Output devices */
type = output;
else {
snprintf(msg, sizeof(msg), "Invalid type: %s", argv[1]);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
return;
}
@ -690,9 +668,9 @@ void cmd_mute(WINDOW * window, ToxWindow * self, Tox *m, int argc, char (*argv)[
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])
{
char *error_str;
const char *error_str;
if ( argc != 1 ) {
if ( argc < 1 ) error_str = "Must have value!";

View File

@ -22,6 +22,7 @@
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#ifdef __APPLE__
#include <sys/types.h>
@ -46,9 +47,9 @@ static void print_matches(ToxWindow *self, Tox *m, const void *list, int n_items
int i;
for (i = 0; i < n_items; ++i)
line_info_add(self, NULL, NULL, NULL, &L[i * size], SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", &L[i * size]);
line_info_add(self, NULL, NULL, NULL, "", SYS_MSG, 0, 0); /* formatting */
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); /* formatting */
}
/* puts match in match buffer. if more than one match, add first n chars that are identical.
@ -178,7 +179,7 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
int strt = ctx->pos - s_len;
int diff = m_len - s_len + n_endchrs;
if (ctx->len + diff > MAX_STR_SIZE)
if (ctx->len + diff >= MAX_STR_SIZE)
return -1;
char tmpend[MAX_STR_SIZE];
@ -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.*/
static void complt_home_dir(ToxWindow *self, char *path)
static void complt_home_dir(ToxWindow *self, char *path, int pathsize)
{
ChatContext *ctx = self->chatwin;
@ -210,8 +211,8 @@ static void complt_home_dir(ToxWindow *self, char *path)
get_home_dir(homedir, sizeof(homedir));
char newline[MAX_STR_SIZE];
const char *isqt = !strchr(path, '\"') ? "\"" : "";
snprintf(newline, sizeof(newline), "/sendfile %s%s/", isqt, homedir);
snprintf(newline, sizeof(newline), "/sendfile \"%s%s", homedir, path + 1);
snprintf(path, pathsize, "%s", &newline[11]);
wchar_t wline[MAX_STR_SIZE];
@ -220,7 +221,7 @@ static void complt_home_dir(ToxWindow *self, char *path)
int newlen = wcslen(wline);
if (ctx->len + newlen > MAX_STR_SIZE)
if (ctx->len + newlen >= MAX_STR_SIZE)
return;
wmemcpy(ctx->line, wline, newlen + 1);
@ -231,22 +232,20 @@ static void complt_home_dir(ToxWindow *self, char *path)
/* attempts to match /sendfile "<incomplete-dir>" line to matching directories.
if only one match, auto-complete line.
return diff between old len and new len of ctx->line, -1 if no matches
*/
#define MAX_DIRS 256
return diff between old len and new len of ctx->line, -1 if no matches or > 1 match */
#define MAX_DIRS 512
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_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;
if (!strncmp(b_path, "\"~/", 3) || !strncmp(b_path, "~/", 2)) {
complt_home_dir(self, b_path);
return -1;
}
if (!strncmp(b_path, "~/", 2))
complt_home_dir(self, b_path, sizeof(b_path));
int si = char_rfind(b_path, '/', strlen(b_path));
@ -273,7 +272,8 @@ int dir_match(ToxWindow *self, Tox *m, wchar_t *line)
int dircount = 0;
while ((entry = readdir(dp)) && dircount < MAX_DIRS) {
if (strncmp(entry->d_name, b_name, b_name_len) == 0) {
if (strncmp(entry->d_name, b_name, b_name_len) == 0
&& strcmp(".", entry->d_name) && strcmp("..", entry->d_name)) {
snprintf(dirnames[dircount], sizeof(dirnames[dircount]), "%s", entry->d_name);
++dircount;
}
@ -282,8 +282,10 @@ int dir_match(ToxWindow *self, Tox *m, wchar_t *line)
if (dircount == 0)
return -1;
if (dircount > 1)
if (dircount > 1) {
qsort(dirnames, dircount, NAME_MAX, qsort_strcasecmp_hlpr);
print_matches(self, m, dirnames, dircount, NAME_MAX);
}
return complete_line(self, dirnames, dircount, NAME_MAX);
}

View File

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

View File

@ -65,13 +65,14 @@ static void kill_infobox(ToxWindow *self);
#ifdef _AUDIO
#define AC_NUM_CHAT_COMMANDS 26
#else
#define AC_NUM_CHAT_COMMANDS 18
#define AC_NUM_CHAT_COMMANDS 19
#endif /* _AUDIO */
/* Array of chat command names used for tab completion. */
static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/accept" },
{ "/add" },
{ "/cancel" },
{ "/clear" },
{ "/close" },
{ "/connect" },
@ -92,7 +93,6 @@ static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
#ifdef _AUDIO
{ "/call" },
{ "/cancel" },
{ "/answer" },
{ "/reject" },
{ "/hangup" },
@ -103,8 +103,11 @@ static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
#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;
tox_set_user_is_typing(m, self->num, is_typing);
@ -160,10 +163,14 @@ static void chat_onMessage(ToxWindow *self, Tox *m, int32_t num, const char *msg
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
line_info_add(self, timefrmt, nick, NULL, msg, IN_MSG, 0, 0);
line_info_add(self, timefrmt, nick, NULL, IN_MSG, 0, 0, "%s", msg);
write_to_log(msg, nick, ctx->log, false);
notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS);
if (self->active_box != -1)
box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS, self->active_box, "%s", msg);
else
box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS, &self->active_box, nick, "%s", msg);
}
static void chat_onConnectionChange(ToxWindow *self, Tox *m, int32_t num, uint8_t status)
@ -173,14 +180,17 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, int32_t num, uint8_
StatusBar *statusbar = self->stb;
if (status == 1) { /* Friend shows online */
if (status == 1) { /* Friend goes online */
statusbar->is_online = true;
friends[num].is_typing = tox_get_is_typing(m, num);
notify(self, user_log_in, NT_NOFOCUS);
friends[num].is_typing = user_settings_->show_typing_other == SHOW_TYPING_ON
? tox_get_is_typing(m, num) : 0;
} else { /* Friend goes offline */
statusbar->is_online = false;
friends[num].is_typing = 0;
notify(self, user_log_out, NT_NOFOCUS);
if (self->chatwin->self_is_typing)
set_self_typingstatus(self, m, 0);
}
}
@ -205,9 +215,13 @@ static void chat_onAction(ToxWindow *self, Tox *m, int32_t num, const char *acti
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
line_info_add(self, timefrmt, nick, NULL, action, ACTION, 0, 0);
line_info_add(self, timefrmt, nick, NULL, ACTION, 0, 0, "%s", action);
write_to_log(action, nick, ctx->log, true);
notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS);
if (self->active_box != -1)
box_notify2(self, generic_message, NT_WNDALERT_0 | NT_NOFOCUS, self->active_box, "* %s %s", nick, action );
else
box_notify(self, generic_message, NT_WNDALERT_0 | NT_NOFOCUS, &self->active_box, self->name, "* %s %s", nick, action );
}
static void chat_onNickChange(ToxWindow *self, Tox *m, int32_t num, const char *nick, uint16_t len)
@ -255,8 +269,7 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t
if (self->num != num)
return;
char msg[MAX_STR_SIZE * 2];
char *errmsg;
const char *errmsg;
/* holds the filename appended to the user specified path */
char filename_path[MAX_STR_SIZE] = {0};
@ -265,14 +278,12 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t
char filename_nopath[MAX_STR_SIZE];
get_file_name(filename_nopath, sizeof(filename_nopath), pathname);
int len = strlen(filename_nopath);
snprintf(msg, sizeof(msg), "File transfer request for '%s' (%llu bytes).", filename_nopath,
(long long unsigned int)filesize);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer request for '%s' (%llu bytes).",
filename_nopath, (long long unsigned int) filesize);
if (filenum >= MAX_FILES) {
errmsg = "Too many pending file requests; discarding.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
return;
}
@ -284,7 +295,7 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t
if (len >= sizeof(friends[num].file_receiver.filenames[filenum])) {
errmsg = "File name too long; discarding.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
return;
}
@ -315,28 +326,39 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t
if (count > 999) {
errmsg = "Error saving file to disk.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
return;
}
}
snprintf(msg, sizeof(msg), "Type '/savefile %d' to accept the file transfer.", filenum);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type '/savefile %d' to accept the file transfer.", filenum);
friends[num].file_receiver.pending[filenum] = true;
friends[num].file_receiver.size[filenum] = filesize;
strcpy(friends[num].file_receiver.filenames[filenum], filename);
notify(self, transfer_pending, NT_WNDALERT_2 | NT_NOFOCUS);
if (self->active_box != -1)
box_notify2(self, transfer_pending, NT_WNDALERT_2 | NT_NOFOCUS, self->active_box,
"Incoming file: %s", filename );
else
box_notify(self, transfer_pending, NT_WNDALERT_2 | NT_NOFOCUS, &self->active_box, self->name,
"Incoming file: %s", filename );
}
static void chat_close_file_receiver(int32_t num, uint8_t filenum)
/* set CTRL to -1 if we don't want to send a control signal.
set msg to NULL if we don't want to display a message */
void chat_close_file_receiver(Tox *m, int filenum, int friendnum, int CTRL)
{
FILE *file = friends[num].file_receiver.files[filenum];
if (CTRL > 0)
tox_file_send_control(m, friendnum, 1, filenum, CTRL, 0, 0);
friends[friendnum].file_receiver.active[filenum] = false;
friends[friendnum].file_receiver.pending[filenum] = false;
FILE *file = friends[friendnum].file_receiver.files[filenum];
if (file != NULL) {
fclose(file);
friends[num].file_receiver.files[filenum] = NULL;
friends[friendnum].file_receiver.files[filenum] = NULL;
}
}
@ -354,19 +376,24 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, int32_t num, uint8_t rec
filename = friends[num].file_receiver.filenames[filenum];
} else {
for (i = 0; i < MAX_FILES; ++i) {
if (file_senders[i].filenum == filenum)
if (file_senders[i].active && file_senders[i].filenum == filenum)
break;
}
filename = file_senders[i].pathname;
filename = file_senders[i].filename;
}
switch (control_type) {
case TOX_FILECONTROL_ACCEPT:
if (receive_send == 1) {
snprintf(msg, sizeof(msg), "File transfer for '%s' accepted (%.1f%%)", filename, 0.0);
file_senders[i].line_id = self->chatwin->hst->line_end->id + 1;
notify(self, silent, NT_NOFOCUS | NT_BEEP | NT_WNDALERT_2);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer [%d] for '%s' accepted.",
filenum, 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, "%s", 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);
}
break;
@ -374,23 +401,43 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, int32_t num, uint8_t rec
case TOX_FILECONTROL_KILL:
snprintf(msg, sizeof(msg), "File transfer for '%s' failed.", filename);
if (receive_send == 0)
chat_close_file_receiver(num, filenum);
if (self->active_box != -1)
box_notify2(self, error, NT_NOFOCUS | NT_WNDALERT_2,
self->active_box, "File transfer for '%s' failed!", filename );
else
box_notify(self, error, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box,
self->name, "File transfer for '%s' failed!", filename );
if (receive_send == 0)
chat_close_file_receiver(m, filenum, num, -1);
else
close_file_sender(self, m, i, NULL, -1, filenum, num);
notify(self, error, NT_NOFOCUS | NT_WNDALERT_2);
break;
case TOX_FILECONTROL_FINISHED:
if (receive_send == 0) {
snprintf(msg, sizeof(msg), "File transfer for '%s' complete.", filename);
chat_close_file_receiver(num, filenum);
notify(self, transfer_completed, NT_NOFOCUS | NT_WNDALERT_2);
chat_close_file_receiver(m, filenum, num, TOX_FILECONTROL_FINISHED);
} else {
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "File '%s' successfuly sent.", filename);
close_file_sender(self, m, i, msg, TOX_FILECONTROL_FINISHED, filenum, num);
return;
}
if (self->active_box != -1)
box_notify2(self, transfer_completed, NT_NOFOCUS | NT_WNDALERT_2,
self->active_box, "%s", msg);
else
box_notify(self, transfer_completed, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box,
self->name, "%s", msg);
break;
}
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
if (msg[0])
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", msg);
}
static void chat_onFileData(ToxWindow *self, Tox *m, int32_t num, uint8_t filenum, const char *data,
@ -403,25 +450,22 @@ static void chat_onFileData(ToxWindow *self, Tox *m, int32_t num, uint8_t filenu
if (fp) {
if (fwrite(data, length, 1, fp) != 1) {
line_info_add(self, NULL, NULL, NULL, " * Error writing to file.", SYS_MSG, 0, RED);
tox_file_send_control(m, num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0);
chat_close_file_receiver(num, filenum);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Error writing to file.");
chat_close_file_receiver(m, filenum, num, TOX_FILECONTROL_KILL);
}
}
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();
/* 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)) {
friends[num].file_receiver.last_progress[filenum] = curtime;
uint64_t size = friends[num].file_receiver.size[filenum];
long double pct_remain = remain ? (1 - (remain / size)) * 100 : 100;
char msg[MAX_STR_SIZE];
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);
double pct_done = remain > 0 ? (1 - (remain / size)) * 100 : 100;
print_progress_bar(self, filenum, num, pct_done);
friends[num].file_receiver.bps[filenum] = 0;
}
}
@ -430,21 +474,23 @@ static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, co
if (self->num != friendnumber)
return;
char msg[MAX_STR_SIZE + TOX_MAX_NAME_LENGTH];
char name[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, name, friendnumber);
snprintf(msg, sizeof(msg), "%s has invited you to a group chat.", name);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, "Type \"/join\" to join the chat.", SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s has invited you to a group chat.", name);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type \"/join\" to join the chat.");
memcpy(friends[friendnumber].groupchat_key, group_pub_key,
sizeof(friends[friendnumber].groupchat_key));
friends[friendnumber].groupchat_pending = true;
notify(self, generic_message, NT_WNDALERT_2);
sound_notify(self, generic_message, NT_WNDALERT_2, NULL);
if (self->active_box != -1)
box_silent_notify2(self, NT_WNDALERT_2 | NT_NOFOCUS, self->active_box, "invites you to join group chat");
else
box_silent_notify(self, NT_WNDALERT_2 | NT_NOFOCUS, &self->active_box, name, "invites you to join group chat");
}
/* Av Stuff */
@ -458,12 +504,16 @@ void chat_onInvite (ToxWindow *self, ToxAv *av, int call_index)
/* call_index is set here and reset on call end */
self->call_idx = call_index;
line_info_add(self, NULL, NULL, NULL, "Incoming audio call! Type: \"/answer\" or \"/reject\"", SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Incoming audio call! Type: \"/answer\" or \"/reject\"");
#ifdef _SOUND_NOTIFY
if (self->active_sound == -1)
self->active_sound = notify(self, call_incoming, NT_LOOP | NT_WNDALERT_0);
#endif /* _SOUND_NOTIFY */
if (self->ringing_sound == -1)
sound_notify(self, call_incoming, NT_LOOP, &self->ringing_sound);
if (self->active_box != -1)
box_silent_notify2(self, NT_NOFOCUS | NT_WNDALERT_0, self->active_box, "Incoming audio call!");
else
box_silent_notify(self, NT_NOFOCUS | NT_WNDALERT_0, &self->active_box, self->name, "Incoming audio call!");
}
void chat_onRinging (ToxWindow *self, ToxAv *av, int call_index)
@ -471,11 +521,11 @@ void chat_onRinging (ToxWindow *self, ToxAv *av, int call_index)
if ( !self || self->call_idx != call_index || self->num != toxav_get_peer_id(av, call_index, 0))
return;
line_info_add(self, NULL, NULL, NULL, "Ringing...\"cancel\" ?", SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ringing...type \"/hangup\" to cancel it.");
#ifdef _SOUND_NOTIFY
if (self->active_sound == -1)
self->active_sound = notify(self, call_outgoing, NT_LOOP);
if (self->ringing_sound == -1)
sound_notify(self, call_outgoing, NT_LOOP, &self->ringing_sound);
#endif /* _SOUND_NOTIFY */
}
@ -486,11 +536,10 @@ void chat_onStarting (ToxWindow *self, ToxAv *av, int call_index)
init_infobox(self);
line_info_add(self, NULL, NULL, NULL, "Call started! Type: \"/hangup\" to end it.", SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call started! Type: \"/hangup\" to end it.");
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
stop_sound(self->ringing_sound);
#endif /* _SOUND_NOTIFY */
}
@ -501,11 +550,10 @@ void chat_onEnding (ToxWindow *self, ToxAv *av, int call_index)
kill_infobox(self);
self->call_idx = -1;
line_info_add(self, NULL, NULL, NULL, "Call ended!", SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call ended!");
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
stop_sound(self->ringing_sound);
#endif /* _SOUND_NOTIFY */
}
@ -515,11 +563,10 @@ void chat_onError (ToxWindow *self, ToxAv *av, int call_index)
return;
self->call_idx = -1;
line_info_add(self, NULL, NULL, NULL, "Error!", SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error!");
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
stop_sound(self->ringing_sound);
#endif /* _SOUND_NOTIFY */
}
@ -530,11 +577,10 @@ void chat_onStart (ToxWindow *self, ToxAv *av, int call_index)
init_infobox(self);
line_info_add(self, NULL, NULL, NULL, "Call started! Type: \"/hangup\" to end it.", SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call started! Type: \"/hangup\" to end it.");
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
stop_sound(self->ringing_sound);
#endif /* _SOUND_NOTIFY */
}
@ -545,11 +591,10 @@ void chat_onCancel (ToxWindow *self, ToxAv *av, int call_index)
kill_infobox(self);
self->call_idx = -1;
line_info_add(self, NULL, NULL, NULL, "Call canceled!", SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call canceled!");
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
stop_sound(self->ringing_sound);
#endif /* _SOUND_NOTIFY */
}
@ -559,11 +604,10 @@ void chat_onReject (ToxWindow *self, ToxAv *av, int call_index)
return;
self->call_idx = -1;
line_info_add(self, NULL, NULL, NULL, "Rejected!", SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Rejected!");
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
stop_sound(self->ringing_sound);
#endif /* _SOUND_NOTIFY */
}
@ -574,11 +618,10 @@ void chat_onEnd (ToxWindow *self, ToxAv *av, int call_index)
kill_infobox(self);
self->call_idx = -1;
line_info_add(self, NULL, NULL, NULL, "Call ended!", SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call ended!");
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
stop_sound(self->ringing_sound);
#endif /* _SOUND_NOTIFY */
}
@ -588,11 +631,10 @@ void chat_onRequestTimeout (ToxWindow *self, ToxAv *av, int call_index)
return;
self->call_idx = -1;
line_info_add(self, NULL, NULL, NULL, "No answer!", SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No answer!");
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
stop_sound(self->ringing_sound);
#endif /* _SOUND_NOTIFY */
}
@ -603,15 +645,13 @@ void chat_onPeerTimeout (ToxWindow *self, ToxAv *av, int call_index)
kill_infobox(self);
self->call_idx = -1;
line_info_add(self, NULL, NULL, NULL, "Peer disconnected; call ended!", SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer disconnected; call ended!");
#ifdef _SOUND_NOTIFY
stop_sound(self->active_sound);
self->active_sound = -1;
stop_sound(self->ringing_sound);
#endif /* _SOUND_NOTIFY */
}
#ifdef _AUDIO
static void init_infobox(ToxWindow *self)
{
ChatContext *ctx = self->chatwin;
@ -628,7 +668,6 @@ static void init_infobox(ToxWindow *self)
ctx->infobox.active = true;
strcpy(ctx->infobox.timestr, "00");
}
#endif
static void kill_infobox(ToxWindow *self)
{
@ -709,11 +748,10 @@ static void send_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
line_info_add(self, timefrmt, selfname, NULL, action, ACTION, 0, 0);
line_info_add(self, timefrmt, selfname, NULL, ACTION, 0, 0, "%s", action);
if (tox_send_action(m, self->num, (uint8_t *) action, strlen(action)) == 0) {
char *errmsg = " * Failed to send action.";
line_info_add(self, NULL, selfname, NULL, errmsg, SYS_MSG, 0, RED);
line_info_add(self, NULL, selfname, NULL, SYS_MSG, 0, RED, " * Failed to send action.");
} else {
write_to_log(action, selfname, ctx->log, true);
}
@ -739,8 +777,8 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (ltr) { /* char is printable */
input_new_char(self, key, x, y, x2, y2);
if (ctx->line[0] != '/')
set_typingstatus(self, m, 1);
if (ctx->line[0] != '/' && !ctx->self_is_typing && statusbar->is_online)
set_self_typingstatus(self, m, 1);
return;
}
@ -752,10 +790,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 */
int diff = -1;
int sf_len = 11;
if (wcsncmp(ctx->line, L"/sendfile \"", sf_len) == 0) {
diff = dir_match(self, m, &ctx->line[sf_len]);
if (wcsncmp(ctx->line, L"/sendfile \"", wcslen(L"/sendfile \"")) == 0) {
diff = dir_match(self, m, ctx->line);
} else {
diff = complete_line(self, chat_cmd_list, AC_NUM_CHAT_COMMANDS, MAX_CMDNAME_SIZE);
}
@ -766,7 +803,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
}
} else {
beep();
sound_notify(self, error, 0, NULL);
}
} else if (key == '\n') {
@ -797,10 +834,10 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
line_info_add(self, timefrmt, selfname, NULL, line, OUT_MSG, 0, 0);
line_info_add(self, timefrmt, selfname, NULL, OUT_MSG, 0, 0, "%s", line);
if (!statusbar->is_online || tox_send_message(m, self->num, (uint8_t *) line, strlen(line)) == 0) {
line_info_add(self, NULL, NULL, NULL, " * Failed to send message.", SYS_MSG, 0, RED);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send message.");
} else {
write_to_log(line, selfname, ctx->log, false);
}
@ -812,7 +849,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
}
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)
@ -859,7 +896,7 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
}
wattron(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
wprintw(statusbar->topline, " O");
wprintw(statusbar->topline, " %s", ONLINE_CHAR);
wattroff(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
if (friends[self->num].is_typing)
@ -872,7 +909,7 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
if (friends[self->num].is_typing)
wattroff(statusbar->topline, COLOR_PAIR(YELLOW));
} else {
wprintw(statusbar->topline, " o");
wprintw(statusbar->topline, " %s", OFFLINE_CHAR);
wattron(statusbar->topline, A_BOLD);
wprintw(statusbar->topline, " %s ", statusbar->nick);
wattroff(statusbar->topline, A_BOLD);
@ -1021,11 +1058,10 @@ ToxWindow new_chat(Tox *m, int32_t friendnum)
ret.call_idx = -1;
ret.device_selection[0] = ret.device_selection[1] = -1;
ret.ringing_sound = -1;
#endif /* _AUDIO */
#ifdef _SOUND_NOTIFY
ret.active_sound = -1;
#endif /* _SOUND_NOTIFY */
ret.active_box = -1;
char nick[TOX_MAX_NAME_LENGTH];
int n_len = get_nick_truncate(m, nick, friendnum);

View File

@ -26,6 +26,9 @@
#include "windows.h"
#include "toxic.h"
/* set CTRL to -1 if we don't want to send a control signal.
set msg to NULL if we don't want to display a message */
void chat_close_file_receiver(Tox *m, int filenum, int friendnum, int CTRL);
void kill_chat_window(ToxWindow *self);
ToxWindow new_chat(Tox *m, int32_t friendnum);

View File

@ -30,6 +30,8 @@
#include "execute.h"
#include "line_info.h"
#include "groupchat.h"
#include "chat.h"
#include "file_senders.h"
extern ToxWindow *prompt;
@ -37,65 +39,107 @@ extern ToxicFriend friends[MAX_FRIENDS_NUM];
extern FileSender file_senders[MAX_FILES];
extern uint8_t max_file_senders_index;
extern uint8_t num_active_file_senders;
void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 2) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Requires type in|out and the file ID.");
return;
}
const char *inoutstr = argv[1];
int filenum = atoi(argv[2]);
if (filenum >= MAX_FILES || filenum < 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
return;
}
if (strcasecmp(inoutstr, "in") == 0) { /* cancel an incoming file transfer */
if (!friends[self->num].file_receiver.active[filenum]) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
return;
}
const char *filepath = friends[self->num].file_receiver.filenames[filenum];
char name[MAX_STR_SIZE];
get_file_name(name, sizeof(name), filepath);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer for '%s' canceled.", name);
chat_close_file_receiver(m, filenum, self->num, TOX_FILECONTROL_KILL);
return;
} else if (strcasecmp(inoutstr, "out") == 0) { /* cancel an outgoing file transfer */
int i;
bool match = false;
for (i = 0; i < MAX_FILES; ++i) {
if (file_senders[i].active && file_senders[i].filenum == filenum) {
match = true;
break;
}
}
if (!match) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
return;
}
const char *filename = file_senders[i].filename;
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "File transfer for '%s' canceled.", filename);
close_file_sender(self, m, i, msg, TOX_FILECONTROL_KILL, filenum, self->num);
return;
} else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type must be 'in' or 'out'.");
return;
}
}
void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
char *errmsg;
if (argc < 1) {
errmsg = "Invalid syntax";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group number required.");
return;
}
int groupnum = atoi(argv[1]);
if (groupnum == 0 && strcmp(argv[1], "0")) { /* atoi returns 0 value on invalid input */
errmsg = "Invalid syntax.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid group number.");
return;
}
if (tox_invite_friend(m, self->num, groupnum) == -1) {
errmsg = "Failed to invite contact to group.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to group.");
return;
}
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "Invited contact to Group %d.", groupnum);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invited contact to Group %d.", groupnum);
}
void cmd_join_group(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
char *errmsg;
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
errmsg = " * Warning: Too many windows are open.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, RED);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open.");
return;
}
char *groupkey = friends[self->num].groupchat_key;
const char *groupkey = friends[self->num].groupchat_key;
if (!friends[self->num].groupchat_pending) {
errmsg = "No pending group chat invite.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending group chat invite.");
return;
}
int groupnum = tox_join_groupchat(m, self->num, (uint8_t *) groupkey);
if (groupnum == -1) {
errmsg = "Group chat instance failed to initialize.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize.");
return;
}
if (init_groupchat_win(prompt, m, groupnum) == -1) {
errmsg = "Group chat window failed to initialize.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
tox_del_groupchat(m, groupnum);
return;
}
@ -103,88 +147,79 @@ void cmd_join_group(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
char *errmsg;
if (argc != 1) {
errmsg = "Invalid syntax.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File ID required.");
return;
}
uint8_t filenum = atoi(argv[1]);
if ((filenum == 0 && strcmp(argv[1], "0")) || filenum >= MAX_FILES) {
errmsg = "No pending file transfers with that number.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
return;
}
if (!friends[self->num].file_receiver.pending[filenum]) {
errmsg = "No pending file transfers with that number.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
return;
}
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) {
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "Saving file as: '%s' (%.1f%%)", filename, 0.0);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
friends[self->num].file_receiver.line_id[filenum] = self->chatwin->hst->line_end->id + 1;
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%d] as: '%s'", filenum, 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, "%s", 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) {
errmsg = "* Error writing to file.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, RED);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "* Error writing to file.");
tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0);
}
} else {
errmsg = "File transfer failed.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed.");
}
friends[self->num].file_receiver.pending[filenum] = false;
friends[self->num].file_receiver.active[filenum] = true;
}
void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
char *errmsg;
if (max_file_senders_index >= (MAX_FILES - 1)) {
errmsg = "Please wait for some of your outgoing file transfers to complete.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
const char *errmsg = "Please wait for some of your outgoing file transfers to complete.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
return;
}
if (argc < 1) {
errmsg = "Invalid syntax.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path required.");
return;
}
char *path = argv[1];
if (path[0] != '\"') {
errmsg = "File path must be enclosed in quotes.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
if (argv[1][0] != '\"') {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path must be enclosed in quotes.");
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;
path[path_len] = '\0';
if (path_len > MAX_STR_SIZE) {
errmsg = "File path exceeds character limit.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
if (path_len >= MAX_STR_SIZE) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path exceeds character limit.");
return;
}
FILE *file_to_send = fopen(path, "r");
if (file_to_send == NULL) {
errmsg = "File not found.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File not found.");
return;
}
@ -192,13 +227,13 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
uint64_t filesize = ftell(file_to_send);
fseek(file_to_send, 0, SEEK_SET);
char filename[MAX_STR_SIZE];
char filename[MAX_STR_SIZE] = {0};
get_file_name(filename, sizeof(filename), path);
int filenum = tox_new_file_sender(m, self->num, filesize, (const uint8_t *) filename, strlen(filename));
int namelen = strlen(filename);
int filenum = tox_new_file_sender(m, self->num, filesize, (const uint8_t *) filename, namelen);
if (filenum == -1) {
errmsg = "Error sending file.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error sending file.");
return;
}
@ -206,7 +241,8 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
for (i = 0; i < MAX_FILES; ++i) {
if (!file_senders[i].active) {
memcpy(file_senders[i].pathname, path, path_len + 1);
file_senders[i].queue_pos = num_active_file_senders;
memcpy(file_senders[i].filename, filename, namelen + 1);
file_senders[i].active = true;
file_senders[i].toxwin = self;
file_senders[i].file = file_to_send;
@ -217,9 +253,9 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
file_senders[i].piecelen = fread(file_senders[i].nextpiece, 1,
tox_file_data_size(m, self->num), file_to_send);
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "Sending file: '%s'", path);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Sending file [%d]: '%s'", filenum, filename);
++num_active_file_senders;
if (i == max_file_senders_index)
++max_file_senders_index;

View File

@ -26,6 +26,7 @@
#include "windows.h"
#include "toxic.h"
void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_groupinvite(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_join_group(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_savefile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);

View File

@ -29,6 +29,7 @@
#include <unistd.h>
#include <pwd.h>
#include "toxic.h"
#include "configdir.h"
/* get the user's home directory */
@ -38,9 +39,8 @@ void get_home_dir(char *home, int size)
struct passwd *pwdbuf;
const char *hmstr;
char buf[NSS_BUFLEN_PASSWD];
int rc;
rc = getpwuid_r(getuid(), &pwd, buf, NSS_BUFLEN_PASSWD, &pwdbuf);
int rc = getpwuid_r(getuid(), &pwd, buf, NSS_BUFLEN_PASSWD, &pwdbuf);
if (rc == 0) {
hmstr = pwd.pw_dir;
@ -102,30 +102,45 @@ char *get_user_config_dir(void)
}
/*
* Creates the config directory.
* Creates the config and chatlog directories.
*/
int create_user_config_dir(char *path)
int create_user_config_dirs(char *path)
{
int mkdir_err;
mkdir_err = mkdir(path, 0700);
struct stat buf;
int mkdir_err = mkdir(path, 0700);
if (mkdir_err && (errno != EEXIST || stat(path, &buf) || !S_ISDIR(buf.st_mode))) {
if (mkdir_err && (errno != EEXIST || stat(path, &buf) || !S_ISDIR(buf.st_mode)))
return -1;
}
char *fullpath = malloc(strlen(path) + strlen(CONFIGDIR) + 1);
char *logpath = malloc(strlen(path) + strlen(LOGDIR) + 1);
if (fullpath == NULL || logpath == NULL)
exit_toxic_err("failed in load_data_structures", FATALERR_MEMORY);
strcpy(fullpath, path);
strcat(fullpath, CONFIGDIR);
strcpy(logpath, path);
strcat(logpath, LOGDIR);
mkdir_err = mkdir(fullpath, 0700);
if (mkdir_err && (errno != EEXIST || stat(fullpath, &buf) || !S_ISDIR(buf.st_mode))) {
free(fullpath);
free(logpath);
return -1;
}
mkdir_err = mkdir(logpath, 0700);
if (mkdir_err && (errno != EEXIST || stat(logpath, &buf) || !S_ISDIR(buf.st_mode))) {
free(fullpath);
free(logpath);
return -1;
}
free(logpath);
free(fullpath);
return 0;
}

View File

@ -28,6 +28,7 @@
#endif
#define CONFIGDIR "/tox/"
#define LOGDIR "/tox/chatlogs/"
#ifndef S_ISDIR
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
@ -35,6 +36,6 @@
char *get_user_config_dir(void);
void get_home_dir(char *home, int size);
int create_user_config_dir(char *path);
int create_user_config_dirs(char *path);
#endif /* #define _configdir_h */

View File

@ -35,6 +35,10 @@
#else
#include <AL/al.h>
#include <AL/alc.h>
/* compatibility with older versions of OpenAL */
#ifndef ALC_ALL_DEVICES_SPECIFIER
#include <AL/alext.h>
#endif
#endif
#include <string.h>
@ -63,6 +67,7 @@ typedef struct _Device {
pthread_mutex_t mutex[1];
uint32_t sample_rate;
uint32_t frame_duration;
int32_t sound_mode;
#ifdef _AUDIO
float VAD_treshold; /* 40 is usually recommended value */
#endif
@ -194,17 +199,19 @@ DeviceError set_primary_device(DeviceType type, int32_t selection)
return de_None;
}
DeviceError open_primary_device(DeviceType type, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration)
DeviceError open_primary_device(DeviceType type, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels)
{
return open_device(type, primary_device[type], device_idx, sample_rate, frame_duration);
return open_device(type, primary_device[type], device_idx, sample_rate, frame_duration, channels);
}
// TODO: generate buffers separately
DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration)
DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels)
{
if (size[type] <= selection || selection < 0) return de_InvalidSelection;
if (channels != 1 && channels != 2) return de_UnsupportedMode;
lock;
const uint32_t frame_size = (sample_rate * frame_duration / 1000);
@ -220,6 +227,7 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
device->sample_rate = sample_rate;
device->frame_duration = frame_duration;
device->sound_mode = channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
for (i = 0; i < *device_idx; i ++) { /* Check if any previous has the same selection */
if ( running[type][i]->selection == selection ) {
@ -238,7 +246,7 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
if (type == input) {
device->dhndl = alcCaptureOpenDevice(devices_names[type][selection],
sample_rate, AL_FORMAT_MONO16, frame_size * 2);
sample_rate, device->sound_mode, frame_size * 2);
#ifdef _AUDIO
device->VAD_treshold = user_settings_->VAD_treshold;
#endif
@ -263,7 +271,7 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
memset(zeros, 0, frame_size*2);
for ( i =0; i < OPENAL_BUFS; ++i) {
alBufferData(device->buffers[i], AL_FORMAT_MONO16, zeros, frame_size*2, sample_rate);
alBufferData(device->buffers[i], device->sound_mode, zeros, frame_size*2, sample_rate);
}
alSourceQueueBuffers(device->source, OPENAL_BUFS, device->buffers);
@ -372,7 +380,7 @@ inline__ DeviceError write_out(uint32_t device_idx, int16_t* data, uint32_t leng
}
alBufferData(bufid, AL_FORMAT_MONO16, data, lenght * 2 * channels, device->sample_rate);
alBufferData(bufid, device->sound_mode, data, lenght * 2 * channels, device->sample_rate);
alSourceQueueBuffers(device->source, 1, &bufid);
ALint state;
@ -415,7 +423,7 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
}
Device* device = running[input][i];
int16_t frame[4096];
int16_t frame[16000];
alcCaptureSamples(device->dhndl, frame, f_size);
if ( device->muted
@ -439,11 +447,8 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
void print_devices(ToxWindow* self, DeviceType type)
{
int i = 0;
for ( ; i < size[type]; i ++) {
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "%d: %s", i, devices_names[type][i]);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
}
for ( ; i < size[type]; i ++)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%d: %s", i, devices_names[type][i]);
return;
}

View File

@ -50,7 +50,8 @@ typedef enum DeviceError {
de_AllDevicesBusy = -5,
de_DeviceNotActive = -6,
de_BufferError = -7,
de_AlError = -8,
de_UnsupportedMode = -8,
de_AlError = -9,
} DeviceError;
typedef void (*DataHandleCallback) (const int16_t*, uint32_t size, void* data);
@ -76,9 +77,9 @@ DeviceError device_set_VAD_treshold(uint32_t device_idx, float value);
#endif
DeviceError set_primary_device(DeviceType type, int32_t selection);
DeviceError open_primary_device(DeviceType type, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration);
DeviceError open_primary_device(DeviceType type, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels);
/* Start device */
DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration);
DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels);
/* Stop device */
DeviceError close_device(DeviceType type, uint32_t device_idx);

View File

@ -22,6 +22,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/types.h> /* for u_char */
#include <netinet/in.h>
#include <resolv.h>
@ -49,7 +50,7 @@ extern struct _Winthread Winthread;
/* TODO: process keys from key file instead of hard-coding like a noob */
static struct dns3_server {
char *name;
const char *name;
char key[DNS3_KEY_SZ];
} dns3_servers[] = {
{
@ -83,13 +84,10 @@ static struct _dns_thread {
} dns_thread;
static int dns_error(ToxWindow *self, char *errmsg)
static int dns_error(ToxWindow *self, const char *errmsg)
{
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "User lookup failed: %s", errmsg);
pthread_mutex_lock(&Winthread.lock);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "User lookup failed: %s", errmsg);
pthread_mutex_unlock(&Winthread.lock);
return -1;
@ -174,7 +172,7 @@ static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, char
and the domain in dombuf.
return length of username on success, -1 on failure */
static int parse_addr(char *addr, char *namebuf, char *dombuf)
static int parse_addr(const char *addr, char *namebuf, char *dombuf)
{
char tmpaddr[MAX_STR_SIZE];
char *tmpname, *tmpdom;
@ -209,8 +207,8 @@ void *dns3_lookup_thread(void *data)
}
/* get domain name/pub key */
char *DNS_pubkey = NULL;
char *domname = NULL;
const char *DNS_pubkey = NULL;
const char *domname = NULL;
int i;
for (i = 0; i < NUM_DNS3_SERVERS; ++i) {
@ -290,11 +288,11 @@ void *dns3_lookup_thread(void *data)
}
/* 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) {
char *err = "Please wait for previous user lookup to finish.";
line_info_add(self, NULL, NULL, NULL, err, SYS_MSG, 0, 0);
const char *err = "Please wait for previous user lookup to finish.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, err);
return;
}

View File

@ -27,6 +27,6 @@
#define _dns_h
/* 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 */

View File

@ -61,6 +61,7 @@ static struct cmd_func global_commands[] = {
};
static struct cmd_func chat_commands[] = {
{ "/cancel", cmd_cancelfile },
{ "/invite", cmd_groupinvite },
{ "/join", cmd_join_group },
{ "/savefile", cmd_savefile },
@ -68,7 +69,6 @@ static struct cmd_func chat_commands[] = {
#ifdef _AUDIO
{ "/call", cmd_call },
{ "/cancel", cmd_cancel },
{ "/answer", cmd_answer },
{ "/reject", cmd_reject },
{ "/hangup", cmd_hangup },
@ -100,7 +100,7 @@ static int parse_command(WINDOW *w, ToxWindow *self, const char *input, char (*a
if (cmd[i] == '\0') {
char *errmsg = "Invalid argument. Did you forget a closing \"?";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
free(cmd);
return -1;
}
@ -114,7 +114,9 @@ static int parse_command(WINDOW *w, ToxWindow *self, const char *input, char (*a
if (cmd[i] == '\0') /* no more args */
break;
strcpy(cmd, &cmd[i + 1]);
char tmp[MAX_STR_SIZE];
snprintf(tmp, sizeof(tmp), "%s", &cmd[i + 1]);
strcpy(cmd, tmp);
}
free(cmd);
@ -166,7 +168,9 @@ void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode)
if (do_command(w, self, m, num_args, GLOBAL_NUM_COMMANDS, global_commands, args) == 0)
return;
/* Just play sound instead */
/*line_info_add(self, NULL, NULL, NULL, "Invalid command.", SYS_MSG, 0, 0);*/
notify(self, error, 0);
#ifdef _SOUND_NOTIFY
sound_notify(self, error, 0, NULL);
#else
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid command.");
#endif
}

View File

@ -33,7 +33,7 @@
#define CHAT_NUM_COMMANDS 12
#else
#define GLOBAL_NUM_COMMANDS 14
#define CHAT_NUM_COMMANDS 4
#define CHAT_NUM_COMMANDS 5
#endif /* _AUDIO */
enum {

View File

@ -27,6 +27,7 @@
#include "toxic.h"
#include "windows.h"
#include "friendlist.h"
#include "file_senders.h"
#include "line_info.h"
#include "misc_tools.h"
@ -34,6 +35,78 @@
FileSender file_senders[MAX_FILES];
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_done)
{
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_done / (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];
const char *frmt = pct_done == 100 ? "%.f%%" : "%.1f%%";
snprintf(pctstr, sizeof(pctstr), frmt, pct_done);
strcat(msg, pctstr);
line_info_set(self, line_id, msg);
}
static void set_max_file_senders_index(void)
{
@ -47,16 +120,20 @@ static void set_max_file_senders_index(void)
max_file_senders_index = j;
}
static void close_file_sender(ToxWindow *self, Tox *m, int i, char *msg, int CTRL, int filenum, int32_t friendnum)
/* set CTRL to -1 if we don't want to send a control signal.
set msg to NULL if we don't want to display a message */
void close_file_sender(ToxWindow *self, Tox *m, int i, const char *msg, int CTRL, int filenum, int32_t friendnum)
{
if (self->chatwin != NULL)
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
if (msg != NULL)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", msg);
if (CTRL > 0)
tox_file_send_control(m, friendnum, 0, filenum, CTRL, 0, 0);
fclose(file_senders[i].file);
memset(&file_senders[i], 0, sizeof(FileSender));
set_max_file_senders_index();
--num_active_file_senders;
}
void close_all_file_senders(Tox *m)
@ -75,57 +152,81 @@ 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 *filename)
{
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].finished) ) {
file_senders[i].last_progress = curtime;
double pct_done = remain > 0 ? (1 - (remain / file_senders[i].size)) * 100 : 100;
print_progress_bar(self, i, -1, pct_done);
file_senders[i].bps = 0;
}
/* file sender is closed in chat_onFileControl callback after receiving reply */
if (file_senders[i].piecelen == 0 && !file_senders[i].finished) {
tox_file_send_control(m, friendnum, 0, filenum, TOX_FILECONTROL_FINISHED, 0, 0);
file_senders[i].finished = true;
}
}
}
void do_file_senders(Tox *m)
{
char msg[MAX_STR_SIZE];
int i;
for (i = 0; i < max_file_senders_index; ++i) {
if (!file_senders[i].active)
continue;
ToxWindow *self = file_senders[i].toxwin;
char *pathname = file_senders[i].pathname;
int filenum = file_senders[i].filenum;
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 (timed_out(file_senders[i].timestamp, get_unix_time(), TIMEOUT_FILESENDER)) {
snprintf(msg, sizeof(msg), "File transfer for '%s' timed out.", pathname);
close_file_sender(self, m, i, msg, TOX_FILECONTROL_KILL, filenum, friendnum);
notify(self, error, NT_NOFOCUS | NT_WNDALERT_2);
if (file_senders[i].queue_pos > 0) {
--file_senders[i].queue_pos;
continue;
}
while (true) {
if (tox_file_send_data(m, friendnum, filenum, (uint8_t *) file_senders[i].nextpiece,
file_senders[i].piecelen) == -1)
break;
ToxWindow *self = file_senders[i].toxwin;
char *filename = file_senders[i].filename;
int filenum = file_senders[i].filenum;
int32_t friendnum = file_senders[i].friendnum;
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);
/* kill file transfer if chatwindow is closed */
if (self->chatwin == NULL) {
close_file_sender(self, m, i, NULL, TOX_FILECONTROL_KILL, filenum, friendnum);
continue;
}
if (file_senders[i].piecelen == 0) {
snprintf(msg, sizeof(msg), "File '%s' successfuly sent.", pathname);
close_file_sender(self, m, i, msg, TOX_FILECONTROL_FINISHED, filenum, friendnum);
notify(self, transfer_completed, NT_NOFOCUS | NT_WNDALERT_2);
break;
}
/* If file transfer has timed out kill transfer and send kill control */
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.", filename);
close_file_sender(self, m, i, msg, TOX_FILECONTROL_KILL, filenum, friendnum);
sound_notify(self, error, NT_NOFOCUS | NT_WNDALERT_2, NULL);
if (self->active_box != -1)
box_notify2(self, error, NT_NOFOCUS | NT_WNDALERT_2,
self->active_box, "File transfer for '%s' timed out.", filename );
else
box_notify(self, error, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box,
self->name, "File transfer for '%s' timed out.", filename );
continue;
}
file_senders[i].queue_pos = num_active_file_senders - 1;
send_file_data(self, m, i, friendnum, filenum, filename);
}
}

View File

@ -29,22 +29,38 @@
#define FILE_PIECE_SIZE 2048 /* must be >= (MAX_CRYPTO_DATA_SIZE - 2) in toxcore/net_crypto.h */
#define MAX_FILES 255
#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 {
FILE *file;
ToxWindow *toxwin;
int32_t friendnum;
bool active;
bool finished;
int filenum;
char nextpiece[FILE_PIECE_SIZE];
uint16_t piecelen;
char pathname[MAX_STR_SIZE];
char filename[MAX_STR_SIZE];
uint64_t timestamp;
uint64_t last_progress;
double bps;
uint64_t size;
uint32_t line_id;
uint8_t queue_pos;
} 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);
/* set CTRL to -1 if we don't want to send a control signal.
set msg to NULL if we don't want to display a message */
void close_file_sender(ToxWindow *self, Tox *m, int i, const char *msg, int CTRL, int filenum, int32_t friendnum);
void close_all_file_senders(Tox *m);
void do_file_senders(Tox *m);

View File

@ -24,6 +24,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
#include <arpa/inet.h>
#include <tox/tox.h>
@ -35,6 +36,7 @@
#include "line_info.h"
#include "settings.h"
#include "notify.h"
#include "help.h"
#ifdef _AUDIO
#include "audio_call.h"
@ -42,26 +44,154 @@
extern char *DATA_FILE;
extern char *BLOCK_FILE;
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 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];
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 {
int num;
bool active;
WINDOW *popup;
} 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)
{
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);
}
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)
{
friends[num].last_online.last_on = timestamp;
@ -106,7 +254,6 @@ static void friendlist_onMessage(ToxWindow *self, Tox *m, int32_t num, const cha
if (friends[num].chatwin == -1) {
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
friends[num].chatwin = add_window(m, new_chat(m, friends[num].num));
notify(self, generic_message, NT_NOFOCUS);
} else {
char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, num);
@ -114,11 +261,11 @@ static void friendlist_onMessage(ToxWindow *self, Tox *m, int32_t num, const cha
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
line_info_add(prompt, timefrmt, nick, NULL, str, IN_MSG, 0, 0);
line_info_add(prompt, timefrmt, nick, NULL, IN_MSG, 0, 0, "%s", str);
char *msg = "* Warning: Too many windows are open.";
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, RED);
notify(prompt, error, NT_WNDALERT_1);
const char *msg = "* Warning: Too many windows are open.";
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, msg);
sound_notify(prompt, error, NT_WNDALERT_1, NULL);
}
}
}
@ -207,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,
uint64_t filesize, const char *filename, uint16_t filename_len)
{
@ -216,18 +396,16 @@ static void friendlist_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, u
if (friends[num].chatwin == -1) {
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
friends[num].chatwin = add_window(m, new_chat(m, friends[num].num));
notify(self, transfer_pending, NT_NOFOCUS);
} else {
tox_file_send_control(m, num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0);
char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, num);
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "* File transfer from %s failed: too many windows are open.", nick);
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, RED);
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED,
"* File transfer from %s failed: too many windows are open.", nick);
notify(prompt, error, NT_WNDALERT_1);
sound_notify(prompt, error, NT_WNDALERT_1, NULL);
}
}
}
@ -240,33 +418,49 @@ static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, const
if (friends[num].chatwin == -1) {
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
friends[num].chatwin = add_window(m, new_chat(m, friends[num].num));
notify(self, generic_message, NT_NOFOCUS);
if (self->active_box != -1)
box_notify2(self, generic_message, NT_WNDALERT_0 | NT_NOFOCUS, self->active_box,
"You are invited to join group" );
else
box_notify(self, generic_message, NT_WNDALERT_0 | NT_NOFOCUS, &self->active_box, self->name,
"You are invited to join group" );
} else {
char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, num);
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "* Group chat invite from %s failed: too many windows are open.", nick);
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, RED);
notify(prompt, error, NT_WNDALERT_1);
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED,
"* Group chat invite from %s failed: too many windows are open.", nick);
sound_notify(prompt, error, NT_WNDALERT_1, NULL);
}
}
}
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 (--num_selected < 0)
num_selected = num_friends - 1;
if (--(*selected) < 0)
*selected = num - 1;
} 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)
{
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);
memset(&friends[f_num], 0, sizeof(ToxicFriend));
@ -284,7 +478,6 @@ static void delete_friend(Tox *m, int32_t f_num)
if (num_friends && num_selected == num_friends)
--num_selected;
sort_friendlist_index();
store_data(m, DATA_FILE);
}
@ -296,11 +489,20 @@ static void del_friend_activate(ToxWindow *self, Tox *m, int32_t f_num)
pendingdelete.num = f_num;
}
static void delete_blocked_friend(int32_t bnum);
/* deactivates delete friend popup and deletes friend if instructed */
static void del_friend_deactivate(ToxWindow *self, Tox *m, wint_t key)
{
if (key == 'y')
if (key == 'y') {
if (blocklist_view == 0) {
delete_friend(m, pendingdelete.num);
sort_friendlist_index();
} else {
delete_blocked_friend(pendingdelete.num);
sort_blocklist_index();
}
}
delwin(pendingdelete.popup);
memset(&pendingdelete, 0, sizeof(pendingdelete));
@ -308,7 +510,7 @@ static void del_friend_deactivate(ToxWindow *self, Tox *m, wint_t key)
refresh();
}
static void draw_popup(void)
static void draw_del_popup(void)
{
if (!pendingdelete.active)
return;
@ -320,19 +522,111 @@ static void draw_popup(void)
wmove(pendingdelete.popup, 1, 1);
wprintw(pendingdelete.popup, "Delete contact ");
wattron(pendingdelete.popup, A_BOLD);
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);
wprintw(pendingdelete.popup, "? y/n");
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;
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 */
if (pendingdelete.active) {
@ -342,8 +636,14 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
return;
}
if (key != ltr) {
if (key == '\n') {
if (key == ltr)
return;
switch (key) {
case '\n':
if (blocklist_view)
break;
/* Jump to chat window if already open */
if (friends[f].chatwin != -1) {
set_active_window(friends[f].chatwin);
@ -351,21 +651,111 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
friends[f].chatwin = add_window(m, new_chat(m, friends[f].num));
set_active_window(friends[f].chatwin);
} else {
char *msg = "* Warning: Too many windows are open.";
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, RED);
const char *msg = "* Warning: Too many windows are open.";
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, msg);
sound_notify(prompt, error, NT_WNDALERT_1, NULL);
}
notify(prompt, error, NT_WNDALERT_1);
}
} else if (key == KEY_DC) {
break;
case KEY_DC:
del_friend_activate(self, m, f);
} else {
select_friend(self, m, key);
}
break;
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 */
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)
{
curs_set(0);
@ -373,23 +763,24 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
int x2, y2;
getmaxyx(self->window, y2, x2);
uint64_t cur_time = get_unix_time();
struct tm cur_loc_tm = *localtime((const time_t*)&cur_time);
bool fix_statuses = x2 != self->x; /* true if window max x value has changed */
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);
wprintw(self->window, " Enter ");
wprintw(self->window, " H ");
wattroff(self->window, A_BOLD);
wprintw(self->window, "key. Delete a contact with the");
wattron(self->window, A_BOLD);
wprintw(self->window, " Delete ");
wattroff(self->window, A_BOLD);
wprintw(self->window, "key.\n\n");
wprintw(self->window, "key for help\n\n");
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);
int nf = tox_get_num_online_friends(m);
pthread_mutex_unlock(&Winthread.lock);
@ -449,7 +840,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
}
wattron(self->window, COLOR_PAIR(colour) | A_BOLD);
wprintw(self->window, "O ");
wprintw(self->window, "%s ", ONLINE_CHAR);
wattroff(self->window, COLOR_PAIR(colour) | A_BOLD);
if (f_selected)
@ -489,7 +880,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
wprintw(self->window, "\n");
} else {
wprintw(self->window, "o ");
wprintw(self->window, "%s ", OFFLINE_CHAR);
if (f_selected)
wattron(self->window, COLOR_PAIR(BLUE));
@ -543,7 +934,10 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
}
wrefresh(self->window);
draw_popup();
draw_del_popup();
if (self->help->active)
help_onDraw(self);
}
void disable_chatwin(int32_t f_num)
@ -570,15 +964,12 @@ static void friendlist_onAv(ToxWindow *self, ToxAv *av, int call_index)
} else {
char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, friends[id].num);
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio action from: %s!", nick);
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "Audio action from: %s!", nick);
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
const char *errmsg = "* Warning: Too many windows are open.";
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, errmsg);
char *errmsg = "* Warning: Too many windows are open.";
line_info_add(prompt, NULL, NULL, NULL, errmsg, SYS_MSG, 0, RED);
notify(prompt, error, NT_WNDALERT_1);
sound_notify(prompt, error, NT_WNDALERT_1, NULL);
}
}
}
@ -621,10 +1012,14 @@ ToxWindow new_friendlist(void)
ret.device_selection[0] = ret.device_selection[1] = -1;
#endif /* _AUDIO */
#ifdef _SOUND_NOTIFY
ret.active_sound = -1;
#endif /* _SOUND_NOTIFY */
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");
return ret;
}

View File

@ -33,9 +33,12 @@ struct FileReceiver {
char filenames[MAX_FILES][MAX_STR_SIZE];
FILE *files[MAX_FILES];
bool pending[MAX_FILES];
bool active[MAX_FILES];
uint64_t size[MAX_FILES];
double bps[MAX_FILES];
uint64_t last_progress[MAX_FILES];
uint32_t line_id[MAX_FILES];
int filenums[MAX_FILES];
};
struct LastOnline {
@ -63,9 +66,19 @@ typedef struct {
struct FileReceiver file_receiver;
} 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);
void disable_chatwin(int32_t f_num);
int get_friendnum(uint8_t *name);
int load_blocklist(char *data);
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_t num, bool sort);

View File

@ -46,28 +46,24 @@ extern uint8_t num_frnd_requests;
/* command functions */
void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
char *msg;
if (argc != 1) {
msg = "Invalid syntax.";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Request ID required.");
return;
}
int req = atoi(argv[1]);
if ((req == 0 && strcmp(argv[1], "0")) || req >= MAX_FRIENDS_NUM) {
msg = "No pending friend request with that number.";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
return;
}
if (!strlen(pending_frnd_requests[req])) {
msg = "No pending friend request with that number.";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
return;
}
const char *msg;
int32_t friendnum = tox_add_friend_norequest(m, (uint8_t *) pending_frnd_requests[req]);
if (friendnum == -1)
@ -87,12 +83,12 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
}
num_frnd_requests = i;
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", 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));
switch (f_num) {
@ -130,34 +126,31 @@ void cmd_add_helper(ToxWindow *self, Tox *m, char *id_bin, char *msg)
break;
}
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
}
void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
char *errmsg;
if (argc < 1) {
errmsg = "Invalid syntax.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Tox ID or address required.");
return;
}
char *id = argv[1];
const char *id = argv[1];
char msg[MAX_STR_SIZE];
if (argc > 1) {
char *temp = argv[2];
if (temp[0] != '\"') {
errmsg = "Message must be enclosed in quotes.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
if (argv[2][0] != '\"') {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Message must be enclosed in quotes.");
return;
}
++temp;
temp[strlen(temp) - 1] = '\0';
snprintf(msg, sizeof(msg), "%s", temp);
/* remove opening and closing quotes */
char tmp[MAX_STR_SIZE];
snprintf(tmp, sizeof(tmp), "%s", &argv[2][1]);
int len = strlen(tmp) - 1;
tmp[len] = '\0';
snprintf(msg, sizeof(msg), "%s", tmp);
} else {
char selfname[TOX_MAX_NAME_LENGTH];
uint16_t n_len = tox_get_self_name(m, (uint8_t *) selfname);
@ -180,8 +173,7 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
xx[2] = '\0';
if (sscanf(xx, "%02x", &x) != 1) {
errmsg = "Invalid ID.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid Tox ID.");
return;
}
@ -204,12 +196,8 @@ 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])
{
char *errmsg;
/* check arguments */
if (argc != 3) {
errmsg = "Invalid syntax.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Require: <ip> <port> <key>");
return;
}
@ -218,8 +206,7 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
const char *key = argv[3];
if (atoi(port) == 0) {
errmsg = "Invalid syntax.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid port.");
return;
}
@ -230,37 +217,30 @@ 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])
{
char *errmsg;
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
errmsg = " * Warning: Too many windows are open.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, RED);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open.");
return;
}
int groupnum = tox_add_groupchat(m);
if (groupnum == -1) {
errmsg = "Group chat instance failed to initialize.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize.");
return;
}
if (init_groupchat_win(prompt, m, groupnum) == -1) {
errmsg = "Group chat window failed to initialize.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
tox_del_groupchat(m, groupnum);
return;
}
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "Group chat created as %d.", groupnum);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat [%d] created.", groupnum);
}
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;
if (argc == 0) {
@ -269,11 +249,11 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
else
msg = "Logging for this window is OFF. Type \"/log on\" to enable.";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
return;
}
char *swch = argv[1];
const char *swch = argv[1];
if (!strcmp(swch, "1") || !strcmp(swch, "on")) {
@ -289,7 +269,7 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
}
msg = "Logging enabled";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
return;
} else if (!strcmp(swch, "0") || !strcmp(swch, "off")) {
if (self->is_chat)
@ -298,12 +278,12 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
log_disable(log);
msg = "Logging disabled";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
return;
}
msg = "Invalid option. Use \"/log on\" and \"/log off\" to toggle logging.";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
}
void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
@ -320,32 +300,30 @@ void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
strcat(id, xx);
}
line_info_add(self, NULL, NULL, NULL, id, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", id);
}
void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
char *errmsg;
/* check arguments */
if (argc < 1) {
errmsg = "Invalid name.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Input required.");
return;
}
char *nick = argv[1];
int len = strlen(nick);
char nick[MAX_STR_SIZE];
int len = 0;
if (nick[0] == '\"') {
++nick;
len -= 2;
if (argv[1][0] == '\"') { /* remove opening and closing quotes */
snprintf(nick, sizeof(nick), "%s", &argv[1][1]);
len = strlen(nick) - 1;
nick[len] = '\0';
} else {
snprintf(nick, sizeof(nick), "%s", argv[1]);
len = strlen(nick);
}
if (!valid_nick(nick)) {
errmsg = "Invalid name.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid name.");
return;
}
@ -360,25 +338,22 @@ 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])
{
char *errmsg;
if (argc < 1) {
errmsg = "Wrong number of arguments.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Input required.");
return;
}
char *msg = argv[1];
if (msg[0] != '\"') {
errmsg = "Note must be enclosed in quotes.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
if (argv[1][0] != '\"') {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Note must be enclosed in quotes.");
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;
msg[len] = '\0';
tox_set_status_message(m, (uint8_t *) msg, (uint16_t) len);
prompt_update_statusmessage(prompt, msg);
}
@ -395,24 +370,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])
{
char *msg = NULL;
char *errmsg;
bool have_note = false;
const char *errmsg;
if (argc >= 2) {
msg = argv[2];
if (msg[0] != '\"') {
errmsg = "Note must be enclosed in quotes.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
return;
}
} else if (argc != 1) {
errmsg = "Wrong number of arguments.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
have_note = true;
} else if (argc < 1) {
errmsg = "Require a status. Statuses are: online, busy and away.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
return;
}
char *status = argv[1];
char status[MAX_STR_SIZE];
snprintf(status, sizeof(status), "%s", argv[1]);
str_to_lower(status);
TOX_USERSTATUS status_kind;
@ -425,17 +395,25 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
status_kind = TOX_USERSTATUS_BUSY;
else {
errmsg = "Invalid status. Valid statuses are: online, busy and away.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
return;
}
tox_set_user_status(m, status_kind);
prompt_update_status(prompt, status_kind);
if (msg != NULL) {
++msg;
if (have_note) {
if (argv[2][0] != '\"') {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Note must be enclosed in quotes.");
return;
}
/* remove opening and closing quotes */
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "%s", &argv[2][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);
prompt_update_statusmessage(prompt, msg);
}

View File

@ -26,6 +26,7 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <time.h>
#include <wchar.h>
@ -144,15 +145,21 @@ static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, int groupnum, int
/* Only play sound if mentioned */
if (strcasestr(msg, selfnick) && strncmp(selfnick, nick, TOXIC_MAX_NAME_LENGTH - 1)) {
notify(self, generic_message, NT_WNDALERT_0);
sound_notify(self, generic_message, NT_WNDALERT_0, NULL);
if (self->active_box != -1)
box_silent_notify2(self, NT_NOFOCUS, self->active_box, "%s %s", nick, msg);
else
box_silent_notify(self, NT_NOFOCUS, &self->active_box, self->name, "%s %s", nick, msg);
nick_clr = RED;
}
else notify(self, silent, NT_WNDALERT_1);
else sound_notify(self, silent, NT_WNDALERT_1, NULL);
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
line_info_add(self, timefrmt, nick, NULL, msg, IN_MSG, 0, nick_clr);
line_info_add(self, timefrmt, nick, NULL, IN_MSG, 0, nick_clr, "%s", msg);
write_to_log(msg, nick, ctx->log, false);
}
@ -169,9 +176,19 @@ static void groupchat_onGroupAction(ToxWindow *self, Tox *m, int groupnum, int p
selfnick[n_len] = '\0';
if (strcasestr(action, selfnick)) {
notify(self, generic_message, NT_WNDALERT_0);
sound_notify(self, generic_message, NT_WNDALERT_0, NULL);
char nick[TOX_MAX_NAME_LENGTH];
int n_len = tox_group_peername(m, groupnum, peernum, (uint8_t *) nick);
n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH - 1); /* enforce client max name length */
nick[n_len] = '\0';
if (self->active_box != -1)
box_silent_notify2(self, NT_NOFOCUS, self->active_box, "* %s %s", nick, action );
else
box_silent_notify(self, NT_NOFOCUS, &self->active_box, self->name, "* %s %s", nick, action);
}
else notify(self, silent, NT_WNDALERT_1);
else sound_notify(self, silent, NT_WNDALERT_1, NULL);
char nick[TOX_MAX_NAME_LENGTH];
n_len = tox_group_peername(m, groupnum, peernum, (uint8_t *) nick);
@ -181,7 +198,7 @@ static void groupchat_onGroupAction(ToxWindow *self, Tox *m, int groupnum, int p
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
line_info_add(self, timefrmt, nick, NULL, action, ACTION, 0, 0);
line_info_add(self, timefrmt, nick, NULL, ACTION, 0, 0, "%s", action);
write_to_log(action, nick, ctx->log, true);
}
@ -273,20 +290,20 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu
ChatContext *ctx = self->chatwin;
char *event;
const char *event;
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
switch (change) {
case TOX_CHAT_CHANGE_PEER_ADD:
event = "has joined the room";
line_info_add(self, timefrmt, (char *) peername, NULL, event, CONNECTION, 0, GREEN);
line_info_add(self, timefrmt, (char *) peername, NULL, CONNECTION, 0, GREEN, event);
write_to_log(event, (char *) peername, ctx->log, true);
break;
case TOX_CHAT_CHANGE_PEER_DEL:
event = "has left the room";
line_info_add(self, timefrmt, (char *) oldpeername, NULL, event, CONNECTION, 0, 0);
line_info_add(self, timefrmt, (char *) oldpeername, NULL, CONNECTION, 0, 0, event);
if (groupchats[self->num].side_pos > 0)
--groupchats[self->num].side_pos;
@ -296,7 +313,7 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu
case TOX_CHAT_CHANGE_PEER_NAME:
event = " is now known as ";
line_info_add(self, timefrmt, (char *) oldpeername, (char *) peername, event, NAME_CHANGE, 0, 0);
line_info_add(self, timefrmt, (char *) oldpeername, (char *) peername, NAME_CHANGE, 0, 0, event);
char tmp_event[TOXIC_MAX_NAME_LENGTH * 2 + 32];
snprintf(tmp_event, sizeof(tmp_event), "is now known as %s", (char *) peername);
@ -304,7 +321,7 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu
break;
}
notify(self, silent, NT_WNDALERT_2);
sound_notify(self, silent, NT_WNDALERT_2, NULL);
}
static void send_group_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
@ -315,8 +332,8 @@ 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) {
char *errmsg = " * Failed to send action.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, RED);
const char *errmsg = " * Failed to send action.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, errmsg);
}
}
@ -363,17 +380,17 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
}
} else {
beep();
sound_notify(self, error, 0, NULL);
}
} else {
beep();
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;
if (groupchats[self->num].side_pos < groupchats[self->num].num_peers - L)
++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)
--groupchats[self->num].side_pos;
} else if (key == '\n') {
@ -398,8 +415,8 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
}
} else if (!string_is_empty(line)) {
if (tox_group_message_send(m, self->num, (uint8_t *) line, strlen(line)) == -1) {
char *errmsg = " * Failed to send message.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, RED);
const char *errmsg = " * Failed to send message.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, errmsg);
}
}
@ -523,6 +540,7 @@ ToxWindow new_group_chat(Tox *m, int groupnum)
ret.help = help;
ret.num = groupnum;
ret.active_box = -1;
return ret;
}

View File

@ -27,7 +27,7 @@
#include "help.h"
#include "misc_tools.h"
#define HELP_MENU_HEIGHT 7
#define HELP_MENU_HEIGHT 8
#define HELP_MENU_WIDTH 26
void help_init_menu(ToxWindow *self)
@ -86,6 +86,11 @@ static void help_draw_menu(ToxWindow *self)
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
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));
wprintw(win, " K");
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
@ -131,15 +136,15 @@ static void help_draw_global(ToxWindow *self)
wprintw(win, "Global Commands:\n");
wattroff(win, A_BOLD | COLOR_PAIR(RED));
wprintw(win, " /add <id> <msg> : Add contact with optional message\n");
wprintw(win, " /accept <n> : Accept friend request\n");
wprintw(win, " /add <addr> <msg> : Add contact with optional message\n");
wprintw(win, " /accept <id> : Accept friend request\n");
wprintw(win, " /connect <ip> <port> <key> : Manually connect to a DHT node\n");
wprintw(win, " /status <type> <msg> : Set status with optional note\n");
wprintw(win, " /note <msg> : Set a personal note\n");
wprintw(win, " /nick <nick> : Set your nickname\n");
wprintw(win, " /log <on> or <off> : Enable/disable logging\n");
wprintw(win, " /groupchat : Create a group chat\n");
wprintw(win, " /myid : Print your ID\n");
wprintw(win, " /myid : Print your Tox ID\n");
wprintw(win, " /clear : Clear window history\n");
wprintw(win, " /close : Close the current chat window\n");
wprintw(win, " /quit or /exit : Exit Toxic\n");
@ -172,7 +177,8 @@ static void help_draw_chat(ToxWindow *self)
wprintw(win, " /invite <n> : Invite contact to a group chat\n");
wprintw(win, " /join : Join a pending group chat\n");
wprintw(win, " /sendfile <path> : Send a file\n");
wprintw(win, " /savefile <n> : Receive a file\n");
wprintw(win, " /savefile <id> : Receive a file\n");
wprintw(win, " /cancel <type> <id> : Cancel file transfer where type: in|out\n");
#ifdef _AUDIO
wattron(win, A_BOLD);
@ -180,8 +186,7 @@ static void help_draw_chat(ToxWindow *self)
wattroff(win, A_BOLD);
wprintw(win, " /call : Audio call\n");
wprintw(win, " /cancel : Cancel call\n");
wprintw(win, " /answer : Answer incomming call\n");
wprintw(win, " /answer : Answer incoming call\n");
wprintw(win, " /reject : Reject incoming call\n");
wprintw(win, " /hangup : Hangup active call\n");
wprintw(win, " /sdev <type> <id> : Change active device\n");
@ -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, " 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+[ 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);
@ -243,8 +271,13 @@ void help_onKey(ToxWindow *self, wint_t key)
self->help->type = HELP_GLOBAL;
break;
case 'k':
case 'f':
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;
break;
@ -276,6 +309,10 @@ void help_onDraw(ToxWindow *self)
help_draw_keys(self);
break;
case HELP_CONTACTS:
help_draw_contacts(self);
break;
case HELP_GROUP:
break;
}

View File

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

View File

@ -31,6 +31,7 @@
#include "misc_tools.h"
#include "toxic_strings.h"
#include "line_info.h"
#include "notify.h"
/* add a char to input field and buffer */
void input_new_char(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y)
@ -41,12 +42,12 @@ void input_new_char(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_
/* this is the only place we need to do this check */
if (cur_len == -1) {
beep();
sound_notify(self, error, 0, NULL);
return;
}
if (add_char_to_buf(ctx, key) == -1) {
beep();
sound_notify(self, error, 0, NULL);
return;
}
@ -62,17 +63,15 @@ static void input_backspace(ToxWindow *self, int x, int mx_x)
ChatContext *ctx = self->chatwin;
if (del_char_buf_bck(ctx) == -1) {
beep();
sound_notify(self, error, 0, NULL);
return;
}
int cur_len = wcwidth(ctx->line[ctx->pos - 1]);
int s_len = wcwidth(ctx->line[ctx->start - 1]);
int cur_len = ctx->pos > 0 ? wcwidth(ctx->line[ctx->pos - 1]) : 0;
int s_len = ctx->start > 0 ? wcwidth(ctx->line[ctx->start - 1]) : 0;
if (ctx->start && (x >= mx_x - cur_len))
ctx->start = MAX(0, ctx->start - 1 + (s_len - cur_len));
else if (ctx->start && (ctx->pos == ctx->len))
ctx->start = MAX(0, ctx->start - cur_len);
else if (ctx->start)
ctx->start = MAX(0, ctx->start - cur_len);
}
@ -81,21 +80,21 @@ static void input_backspace(ToxWindow *self, int x, int mx_x)
static void input_delete(ToxWindow *self)
{
if (del_char_buf_frnt(self->chatwin) == -1)
beep();
sound_notify(self, error, 0, NULL);
}
/* deletes entire line before cursor from input field and buffer */
static void input_discard(ToxWindow *self)
{
if (discard_buf(self->chatwin) == -1)
beep();
sound_notify(self, error, 0, NULL);
}
/* deletes entire line after cursor from input field and buffer */
static void input_kill(ChatContext *ctx)
{
if (kill_buf(ctx) == -1)
beep();
sound_notify(NULL, error, NT_ALWAYS, NULL);
}
static void input_yank(ToxWindow *self, int x, int mx_x)
@ -103,7 +102,7 @@ static void input_yank(ToxWindow *self, int x, int mx_x)
ChatContext *ctx = self->chatwin;
if (yank_buf(ctx) == -1) {
beep();
sound_notify(self, error, 0, NULL);
return;
}
@ -147,16 +146,13 @@ static void input_mv_left(ToxWindow *self, int x, int mx_x)
if (ctx->pos <= 0)
return;
int cur_len = wcwidth(ctx->line[ctx->pos - 1]);
int cur_len = ctx->pos > 0 ? wcwidth(ctx->line[ctx->pos - 1]) : 0;
int s_len = ctx->start > 0 ? wcwidth(ctx->line[ctx->start - 1]) : 0;
--ctx->pos;
int s_len = wcwidth(ctx->line[ctx->start - 1]);
if (ctx->start && (x >= mx_x - cur_len))
ctx->start = MAX(0, ctx->start - 1 + (s_len - cur_len));
else if (ctx->start && (ctx->pos == ctx->len))
ctx->start = MAX(0, ctx->start - cur_len);
else if (ctx->start)
ctx->start = MAX(0, ctx->start - cur_len);
}

View File

@ -23,12 +23,14 @@
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdarg.h>
#include "toxic.h"
#include "windows.h"
#include "line_info.h"
#include "groupchat.h"
#include "settings.h"
#include "notify.h"
extern struct user_settings *user_settings_;
@ -132,9 +134,10 @@ static struct line_info *line_info_ret_queue(struct history *hst)
return ret;
}
/* creates new line_info line and puts it in the queue */
void line_info_add(ToxWindow *self, char *tmstmp, char *name1, char *name2, const char *msg, uint8_t type,
uint8_t bold, uint8_t colour)
/* 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,
uint8_t colour, const char *msg, ...)
{
struct history *hst = self->chatwin->hst;
struct line_info *new_line = calloc(1, sizeof(struct line_info));
@ -142,6 +145,13 @@ void line_info_add(ToxWindow *self, char *tmstmp, char *name1, char *name2, cons
if (new_line == NULL)
exit_toxic_err("failed in line_info_add", FATALERR_MEMORY);
char frmt_msg[MAX_STR_SIZE] = {0};
va_list args;
va_start(args, msg);
vsnprintf(frmt_msg, sizeof(frmt_msg), msg, args);
va_end(args);
int len = 1; /* there will always be a newline */
/* for type-specific formatting in print function */
@ -163,14 +173,14 @@ void line_info_add(ToxWindow *self, char *tmstmp, char *name1, char *name2, cons
break;
}
if (msg) {
snprintf(new_line->msg, sizeof(new_line->msg), "%s", msg);
if (frmt_msg[0]) {
snprintf(new_line->msg, sizeof(new_line->msg), "%s", frmt_msg);
len += strlen(new_line->msg);
int i;
for (i = 0; msg[i]; ++i) {
if (msg[i] == '\n')
for (i = 0; frmt_msg[i]; ++i) {
if (frmt_msg[i] == '\n')
++new_line->newlines;
}
}
@ -406,14 +416,14 @@ static void line_info_scroll_up(struct history *hst)
{
if (hst->line_start->prev)
hst->line_start = hst->line_start->prev;
else beep();
else sound_notify(NULL, error, NT_ALWAYS, NULL);
}
static void line_info_scroll_down(struct history *hst)
{
if (hst->line_start->next)
hst->line_start = hst->line_start->next;
else beep();
else sound_notify(NULL, error, NT_ALWAYS, NULL);
}
static void line_info_page_up(ToxWindow *self, struct history *hst)
@ -445,35 +455,23 @@ bool line_info_onKey(ToxWindow *self, wint_t key)
struct history *hst = self->chatwin->hst;
bool match = true;
switch (key) {
/* TODO: Find good key bindings for all this stuff */
case T_KEY_C_F:
if (key == user_settings_->key_half_page_up) {
line_info_page_up(self, hst);
break;
case T_KEY_C_V:
}
else if (key == user_settings_->key_half_page_down) {
line_info_page_down(self, hst);
break;
case KEY_PPAGE:
}
else if (key == user_settings_->key_scroll_line_up) {
line_info_scroll_up(hst);
break;
case KEY_NPAGE:
}
else if (key == user_settings_->key_scroll_line_down) {
line_info_scroll_down(hst);
break;
/* case ?:
line_info_goto_root(hst);
break; */
case T_KEY_C_H:
}
else if (key == user_settings_->key_page_bottom) {
line_info_reset_start(self, hst);
break;
default:
}
else {
match = false;
break;
}
return match;

View File

@ -26,7 +26,7 @@
#include "windows.h"
#include "toxic.h"
#define MAX_HISTORY 10000
#define MAX_HISTORY 100000
#define MIN_HISTORY 40
#define MAX_QUEUE 128
@ -67,9 +67,10 @@ struct history {
int queue_sz;
};
/* creates new line_info line and puts it in the queue */
void line_info_add(ToxWindow *self, char *tmstmp, char *name1, char *name2, const char *msg,
uint8_t type, uint8_t bold, uint8_t colour);
/* 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,
uint8_t colour, const char *msg, ...);
/* Prints a section of history starting at line_start */
void line_info_print(ToxWindow *self);

View File

@ -34,7 +34,7 @@
extern struct user_settings *user_settings_;
/* Creates/fetches log file by appending to the config dir the name and a pseudo-unique identity */
void init_logging_session(char *name, char *key, struct chatlog *log)
void init_logging_session(char *name, const char *key, struct chatlog *log)
{
if (!log->log_on)
return;
@ -43,7 +43,7 @@ void init_logging_session(char *name, char *key, struct chatlog *log)
name = UNKNOWN_NAME;
char *user_config_dir = get_user_config_dir();
int path_len = strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(name);
int path_len = strlen(user_config_dir) + strlen(LOGDIR) + strlen(name);
/* use first 4 digits of key as log ident. If no key use a timestamp */
char ident[32];
@ -59,16 +59,14 @@ void init_logging_session(char *name, char *key, struct chatlog *log)
path_len += strlen(ident) + 1;
}
if (path_len > MAX_STR_SIZE) {
if (path_len >= MAX_STR_SIZE) {
log->log_on = false;
free(user_config_dir);
return;
}
char log_path[MAX_STR_SIZE];
snprintf(log_path, MAX_STR_SIZE, "%s%s%s-%s.log",
user_config_dir, CONFIGDIR, name, ident);
snprintf(log_path, MAX_STR_SIZE, "%s%s%s-%s.log", user_config_dir, LOGDIR, name, ident);
free(user_config_dir);
@ -82,7 +80,7 @@ void init_logging_session(char *name, char *key, struct chatlog *log)
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)
return;
@ -112,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;

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 */
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 */
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 */
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 */
void log_disable(struct chatlog *log);

View File

@ -37,6 +37,21 @@ extern struct user_settings *user_settings_;
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)
{
current_unix_time = (uint64_t) time(NULL);
@ -143,9 +158,9 @@ int wcs_to_mbs_buf(char *buf, const wchar_t *string, size_t n)
}
/* case-insensitive string compare function for use with qsort */
int qsort_strcasecmp_hlpr(const void *nick1, const void *nick2)
int qsort_strcasecmp_hlpr(const void *str1, const void *str2)
{
return strcasecmp((const char *) nick1, (const char *) nick2);
return strcasecmp((const char *) str1, (const char *) str2);
}
/* Returns 1 if nick is valid, 0 if not. A valid toxic nick:

View File

@ -33,6 +33,12 @@
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#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 */
char *hex_string_to_bin(const char *hex_string);
@ -70,7 +76,7 @@ int timed_out(uint64_t timestamp, uint64_t timeout, uint64_t curtime);
void alert_window(ToxWindow *self, int type, bool is_beep);
/* case-insensitive string compare function for use with qsort */
int qsort_strcasecmp_hlpr(const void *nick1, const void *nick2);
int qsort_strcasecmp_hlpr(const void *str1, const void *str2);
/* Returns 1 if nick is valid, 0 if not. A valid toxic nick:
- cannot be empty

View File

@ -23,60 +23,82 @@
#include "notify.h"
#include "device.h"
#include "settings.h"
#include "line_info.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdarg.h>
#include <time.h>
#include <assert.h>
#include <sys/stat.h>
#ifdef __APPLE__
#if defined(_AUDIO) || defined(_SOUND_NOTIFY)
#ifdef __APPLE__
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#ifdef _SOUND_NOTIFY
#include <OpenAL/alut.h> /* Is this good? */
#endif
#else
#else
#include <AL/al.h>
#include <AL/alc.h>
/* compatibility with older versions of OpenAL */
#ifndef ALC_ALL_DEVICES_SPECIFIER
#include <AL/alext.h>
#endif
#endif
#ifdef _SOUND_NOTIFY
#include <AL/alut.h> /* freealut packet */
#endif
#endif
#endif /* _AUDIO */
#ifdef _X11
#include <X11/Xlib.h>
#endif /* _X11 */
#ifdef _BOX_NOTIFY
#include <libnotify/notify.h>
#endif
#define SOUNDS_SIZE 10
#define ACTIVE_SOUNDS_MAX 50
#define ACTIVE_NOTIFS_MAX 50
extern struct user_settings *user_settings_;
struct _Control {
time_t cooldown;
time_t notif_timeout;
unsigned long this_window;
#ifdef _X11
Display *display;
#endif /* _X11 */
#ifdef _SOUND_NOTIFY
#if defined(_SOUND_NOTIFY) || defined(_BOX_NOTIFY)
pthread_mutex_t poll_mutex[1];
uint32_t device_idx; /* index of output device */
_Bool poll_active;
#endif
#ifdef _SOUND_NOTIFY
uint32_t device_idx; /* index of output device */
char* sounds[SOUNDS_SIZE];
#endif /* _SOUND_NOTIFY */
} Control = {0};
struct _ActiveNotifications {
#ifdef _SOUND_NOTIFY
struct _ActiveSounds {
uint32_t source;
uint32_t buffer;
_Bool active;
_Bool looping;
} actives[ACTIVE_SOUNDS_MAX] = {{0}};
#endif
_Bool active;
int *id_indicator;
#ifdef _BOX_NOTIFY
NotifyNotification* box;
char messages[128][128];
char title[24];
size_t size;
time_t n_timeout;
#endif
} actives[ACTIVE_NOTIFS_MAX] = {{0}};
/**********************************************************************************/
/**********************************************************************************/
/**********************************************************************************/
@ -97,8 +119,21 @@ long unsigned int get_focused_window_id()
#endif /* _X11 */
}
#ifdef _SOUND_NOTIFY
static void control_lock()
{
#if defined(_SOUND_NOTIFY) || defined(_BOX_NOTIFY)
pthread_mutex_lock(Control.poll_mutex);
#endif
}
static void control_unlock()
{
#if defined(_SOUND_NOTIFY) || defined(_BOX_NOTIFY)
pthread_mutex_unlock(Control.poll_mutex);
#endif
}
#ifdef _SOUND_NOTIFY
_Bool is_playing(int source)
{
int ready;
@ -110,23 +145,33 @@ _Bool is_playing(int source)
void graceful_clear()
{
int i;
pthread_mutex_lock(Control.poll_mutex);
control_lock();
while (1) {
for (i = 0; i < ACTIVE_SOUNDS_MAX; i ++) {
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
if (actives[i].active) {
#ifdef _BOX_NOTIFY
if (actives[i].box) {
GError* ignore;
notify_notification_close(actives[i].box, &ignore);
actives[i].box = NULL;
}
#endif
if(actives[i].id_indicator) *actives[i].id_indicator = -1; // reset indicator value
if ( actives[i].looping ) {
stop_sound(i);
} else {
if (!is_playing(actives[i].source))
memset(&actives[i], 0, sizeof(struct _ActiveSounds));
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
else break;
}
}
}
if (i == ACTIVE_SOUNDS_MAX) {
pthread_mutex_unlock(Control.poll_mutex);
if (i == ACTIVE_NOTIFS_MAX) {
control_unlock();
return;
}
@ -139,33 +184,51 @@ void* do_playing(void* _p)
(void)_p;
int i;
while(Control.poll_active) {
pthread_mutex_lock(Control.poll_mutex);
for (i = 0; i < ACTIVE_SOUNDS_MAX; i ++) {
if (actives[i].active && !actives[i].looping) {
control_lock();
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
if (actives[i].active && !actives[i].looping
#ifdef _BOX_NOTIFY
&& !actives[i].box
#endif
) {
if (!is_playing(actives[i].source)) {
/* Close */
alSourceStop(actives[i].source);
alDeleteSources(1, &actives[i].source);
alDeleteBuffers(1,&actives[i].buffer);
memset(&actives[i], 0, sizeof(struct _ActiveSounds));
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
}
}
#ifdef _BOX_NOTIFY
else if (actives[i].box && time(NULL) >= actives[i].n_timeout)
{
GError* ignore;
notify_notification_close(actives[i].box, &ignore);
actives[i].box = NULL;
if(actives[i].id_indicator) *actives[i].id_indicator = -1; // reset indicator value
if (!actives[i].looping && !is_playing(actives[i].source)) {
/* stop source if not looping or playing, just terminate box */
alSourceStop(actives[i].source);
alDeleteSources(1, &actives[i].source);
alDeleteBuffers(1,&actives[i].buffer);
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
}
pthread_mutex_unlock(Control.poll_mutex);
}
#endif
}
control_unlock();
usleep(10000);
}
pthread_exit(NULL);
}
int play_source(uint32_t source, uint32_t buffer, _Bool looping)
{
pthread_mutex_lock(Control.poll_mutex);
int i = 0;
for (; i < ACTIVE_SOUNDS_MAX && actives[i].active; i ++);
if ( i == ACTIVE_SOUNDS_MAX ) {
pthread_mutex_unlock(Control.poll_mutex);
for (; i < ACTIVE_NOTIFS_MAX && actives[i].active; i ++);
if ( i == ACTIVE_NOTIFS_MAX ) {
return -1; /* Full */
}
@ -176,10 +239,53 @@ int play_source(uint32_t source, uint32_t buffer, _Bool looping)
actives[i].buffer = buffer;
actives[i].looping = looping;
pthread_mutex_unlock(Control.poll_mutex);
return i;
}
#elif _BOX_NOTIFY
void* do_playing(void* _p)
{
(void)_p;
int i;
while(Control.poll_active) {
control_lock();
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
if (actives[i].box && time(NULL) >= actives[i].n_timeout)
{
GError* ignore;
notify_notification_close(actives[i].box, &ignore);
actives[i].box = NULL;
if(actives[i].id_indicator) *actives[i].id_indicator = -1; // reset indicator value
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
}
}
control_unlock();
usleep(10000);
}
pthread_exit(NULL);
}
void graceful_clear()
{
int i;
control_lock();
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
if (actives[i].box) {
GError* ignore;
notify_notification_close(actives[i].box, &ignore);
actives[i].box = NULL;
}
if(actives[i].id_indicator) *actives[i].id_indicator = -1; // reset indicator value
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
}
control_unlock();
}
#endif
/**********************************************************************************/
/**********************************************************************************/
/**********************************************************************************/
@ -189,13 +295,15 @@ int play_source(uint32_t source, uint32_t buffer, _Bool looping)
/* Opens primary device */
int init_notify(int login_cooldown)
int init_notify(int login_cooldown, int notification_timeout)
{
#ifdef _SOUND_NOTIFY
alutInitWithoutContext(NULL, NULL);
if (open_primary_device(output, &Control.device_idx, 48000, 20) != de_None)
if (open_primary_device(output, &Control.device_idx, 48000, 20, 1) != de_None)
return -1;
#endif /* _SOUND_NOTIFY */
#if defined(_SOUND_NOTIFY) || defined(_BOX_NOTIFY)
pthread_mutex_init(Control.poll_mutex, NULL);
pthread_t thread;
if (pthread_create(&thread, NULL, do_playing, NULL) != 0 || pthread_detach(thread) != 0 ) {
@ -203,7 +311,7 @@ int init_notify(int login_cooldown)
return -1;
}
Control.poll_active = 1;
#endif /* _SOUND_NOTIFY */
#endif
Control.cooldown = time(NULL) + login_cooldown;
#ifdef _X11
@ -214,31 +322,43 @@ int init_notify(int login_cooldown)
#endif /* _X11 */
#ifdef _BOX_NOTIFY
notify_init("toxic");
#endif
Control.notif_timeout = notification_timeout;
return 1;
}
void terminate_notify()
{
#ifdef _SOUND_NOTIFY
#if defined(_SOUND_NOTIFY) || defined(_BOX_NOTIFY)
if ( !Control.poll_active ) return;
Control.poll_active = 0;
graceful_clear();
#endif
#ifdef _SOUND_NOTIFY
int i = 0;
for (; i < SOUNDS_SIZE; i ++) free(Control.sounds[i]);
graceful_clear();
close_device(output, Control.device_idx);
alutExit();
#endif /* _SOUND_NOTIFY */
#ifdef _BOX_NOTIFY
notify_uninit();
#endif
}
#ifdef _SOUND_NOTIFY
int set_sound(Notification sound, const char* value)
{
if (sound == silent) return 0;
free(Control.sounds[sound]);
size_t len = strlen(value) + 1;
Control.sounds[sound] = calloc(1, len);
Control.sounds[sound] = calloc(len, 1);
memcpy(Control.sounds[sound], value, len);
struct stat buf;
@ -252,7 +372,7 @@ int play_sound_internal(Notification what, _Bool loop)
alGenSources(1, &source);
alGenBuffers(1, &buffer);
buffer = alutCreateBufferFromFile((const char*)Control.sounds[what]);
buffer = alutCreateBufferFromFile(Control.sounds[what]);
alSourcei(source, AL_BUFFER, buffer);
alSourcei(source, AL_LOOPING, loop);
@ -269,11 +389,11 @@ int play_sound_internal(Notification what, _Bool loop)
int play_notify_sound(Notification notif, uint64_t flags)
{
int rc = 0;
int rc = -1;
if (flags & NT_BEEP) beep();
else if (notif != silent) {
if ( !Control.poll_active || (flags & NT_RESTOL && Control.cooldown > time(NULL)) || !Control.sounds[notif] )
if ( !Control.poll_active || !Control.sounds[notif] )
return -1;
rc = play_sound_internal(notif, flags & NT_LOOP ? 1 : 0);
@ -283,14 +403,21 @@ int play_notify_sound(Notification notif, uint64_t flags)
}
void stop_sound(int sound)
void stop_sound(int id)
{
if (sound >= 0 && sound < ACTIVE_SOUNDS_MAX && actives[sound].looping && actives[sound].active) {
alSourcei(actives[sound].source, AL_LOOPING, false);
alSourceStop(actives[sound].source);
alDeleteSources(1, &actives[sound].source);
alDeleteBuffers(1,&actives[sound].buffer);
memset(&actives[sound], 0, sizeof(struct _ActiveSounds));
if (id >= 0 && id < ACTIVE_NOTIFS_MAX && actives[id].looping && actives[id].active ) {
#ifdef _BOX_NOTIFY
if (actives[id].box) {
GError* ignore;
notify_notification_close(actives[id].box, &ignore);
}
#endif
*actives[id].id_indicator = -1;
// alSourcei(actives[id].source, AL_LOOPING, false);
alSourceStop(actives[id].source);
alDeleteSources(1, &actives[id].source);
alDeleteBuffers(1,&actives[id].buffer);
memset(&actives[id], 0, sizeof(struct _ActiveNotifications));
}
}
#endif
@ -305,31 +432,312 @@ static int m_play_sound(Notification notif, uint64_t flags)
return -1;
#endif /* _SOUND_NOTIFY */
}
int notify(ToxWindow* self, Notification notif, uint64_t flags)
#ifdef _BOX_NOTIFY
void m_notify_action(NotifyNotification *box, char *action, void* data)
{
if (flags & NT_NOFOCUS && Control.this_window == get_focused_window_id())
return -1;
int rc = -1;
if (self && (!self->stb || self->stb->status != TOX_USERSTATUS_BUSY) && user_settings_->alerts == ALERTS_ENABLED)
rc = m_play_sound(notif, flags);
else if (flags & NT_ALWAYS)
rc = m_play_sound(notif, flags);
if (flags & NT_NOTIFWND) {
/* TODO: pop notify window */
}
}
#endif
int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator)
{
/* Consider colored notify as primary */
if (self && self->alert == WINDOW_ALERT_NONE) {
if (flags & NT_WNDALERT_0) self->alert = WINDOW_ALERT_0;
else if (flags & NT_WNDALERT_1) self->alert = WINDOW_ALERT_1;
else if (flags & NT_WNDALERT_2) self->alert = WINDOW_ALERT_2;
}
return rc;
if ((flags & NT_RESTOL && Control.cooldown > time(NULL)) ||
((flags & NT_NOFOCUS && Control.this_window == get_focused_window_id()) ))
return -1;
int id = -1;
control_lock();
if (self && (!self->stb || self->stb->status != TOX_USERSTATUS_BUSY) && user_settings_->alerts == ALERTS_ENABLED)
id = m_play_sound(notif, flags);
else if (flags & NT_ALWAYS)
id = m_play_sound(notif, flags);
#if defined(_BOX_NOTIFY) && !defined(_SOUND_NOTIFY)
if (id == -1) {
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].box; id ++);
if ( id == ACTIVE_NOTIFS_MAX ) {
control_unlock();
return -1; /* Full */
}
}
#endif
if ( id_indicator && id != -1 ) {
actives[id].id_indicator = id_indicator;
*id_indicator = id;
}
control_unlock();
return id;
}
int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
{
/* Consider colored notify as primary */
if (self && self->alert == WINDOW_ALERT_NONE) {
if (flags & NT_WNDALERT_0) self->alert = WINDOW_ALERT_0;
else if (flags & NT_WNDALERT_1) self->alert = WINDOW_ALERT_1;
else if (flags & NT_WNDALERT_2) self->alert = WINDOW_ALERT_2;
}
if ((flags & NT_RESTOL && Control.cooldown > time(NULL)) ||
((flags & NT_NOFOCUS && Control.this_window == get_focused_window_id()) ))
return -1;
if (id < 0 || id >= ACTIVE_NOTIFS_MAX) return -1;
#ifdef _SOUND_NOTIFY
control_lock();
if (!actives[id].active || !Control.sounds[notif]) {
control_unlock();
return -1;
}
alSourceStop(actives[id].source);
alDeleteSources(1, &actives[id].source);
alDeleteBuffers(1,&actives[id].buffer);
alGenSources(1, &actives[id].source);
alGenBuffers(1, &actives[id].buffer);
actives[id].buffer = alutCreateBufferFromFile(Control.sounds[notif]);
alSourcei(actives[id].source, AL_BUFFER, actives[id].buffer);
alSourcei(actives[id].source, AL_LOOPING, flags & NT_LOOP);
alSourcePlay(actives[id].source);
control_unlock();
return id;
#else
if (notif != silent)
beep();
return 0;
#endif /* _SOUND_NOTIFY */
}
int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator, char* title, const char* format, ...)
{
if ((flags & NT_RESTOL && Control.cooldown > time(NULL)) ||
((flags & NT_NOFOCUS && Control.this_window == get_focused_window_id()) ))
return -1;
#ifdef _BOX_NOTIFY
int id = sound_notify(self, notif, flags, id_indicator);
control_lock();
#ifdef _SOUND_NOTIFY
if (id == -1) { /* Could not play */
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++);
if ( id == ACTIVE_NOTIFS_MAX ) {
control_unlock();
return -1; /* Full */
}
actives[id].active = 1;
actives[id].id_indicator = id_indicator;
if (id_indicator) *id_indicator = id;
}
#endif
strncpy(actives[id].title, title, 24);
if (strlen(title) > 23) strcpy(actives[id].title + 20, "...");
va_list __ARGS__; va_start (__ARGS__, format);
vsnprintf (actives[id].messages[0], 127, format, __ARGS__);
va_end (__ARGS__);
if (strlen(actives[id].messages[0]) > 124)
strcpy(actives[id].messages[0] + 124, "...");
actives[id].box = notify_notification_new(actives[id].title, actives[id].messages[0], NULL);
actives[id].size ++;
actives[id].n_timeout = time(NULL) + Control.notif_timeout / 1000;
notify_notification_set_timeout(actives[id].box, Control.notif_timeout);
notify_notification_set_app_name(actives[id].box, "toxic");
/*notify_notification_add_action(actives[id].box, "lel", "default", m_notify_action, self, NULL);*/
notify_notification_show(actives[id].box, NULL);
control_unlock();
return id;
#else
return sound_notify(self, notif, flags, id_indicator);
#endif
}
int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, const char* format, ...)
{
if ((flags & NT_RESTOL && Control.cooldown > time(NULL)) ||
((flags & NT_NOFOCUS && Control.this_window == get_focused_window_id()) ))
return -1;
#ifdef _BOX_NOTIFY
if (sound_notify2(self, notif, flags, id) == -1)
return -1;
control_lock();
if (!actives[id].box || actives[id].size >= 128 ) {
control_unlock();
return -1;
}
va_list __ARGS__; va_start (__ARGS__, format);
vsnprintf (actives[id].messages[actives[id].size], 127, format, __ARGS__);
va_end (__ARGS__);
if (strlen(actives[id].messages[actives[id].size]) > 124)
strcpy(actives[id].messages[actives[id].size] + 124, "...");
actives[id].size ++;
actives[id].n_timeout = time(NULL) + Control.notif_timeout / 1000;
char formated[128 * 129] = {'\0'};
int i = 0;
for (; i <actives[id].size; i ++) {
strcat(formated, actives[id].messages[i]);
strcat(formated, "\n");
}
formated[strlen(formated) - 1] = '\0';
notify_notification_update(actives[id].box, actives[id].title, formated, NULL);
notify_notification_show(actives[id].box, NULL);
control_unlock();
return id;
#else
return sound_notify2(self, notif, flags, id);
#endif
}
int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const char* title, const char* format, ...)
{
/* Always do colored notify */
if (self && self->alert == WINDOW_ALERT_NONE) {
if (flags & NT_WNDALERT_0) self->alert = WINDOW_ALERT_0;
else if (flags & NT_WNDALERT_1) self->alert = WINDOW_ALERT_1;
else if (flags & NT_WNDALERT_2) self->alert = WINDOW_ALERT_2;
}
if ((flags & NT_RESTOL && Control.cooldown > time(NULL)) ||
((flags & NT_NOFOCUS && Control.this_window == get_focused_window_id()) ))
return -1;
#ifdef _BOX_NOTIFY
control_lock();
int id;
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++);
if ( id == ACTIVE_NOTIFS_MAX ) {
control_unlock();
return -1; /* Full */
}
if (id_indicator) {
actives[id].id_indicator = id_indicator;
*id_indicator = id;
}
strncpy(actives[id].title, title, 24);
if (strlen(title) > 23) strcpy(actives[id].title + 20, "...");
va_list __ARGS__; va_start (__ARGS__, format);
vsnprintf (actives[id].messages[0], 127, format, __ARGS__);
va_end (__ARGS__);
if (strlen(actives[id].messages[0]) > 124)
strcpy(actives[id].messages[0] + 124, "...");
actives[id].active = 1;
actives[id].box = notify_notification_new(actives[id].title, actives[id].messages[0], NULL);
actives[id].size ++;
actives[id].n_timeout = time(NULL) + Control.notif_timeout / 1000;
notify_notification_set_timeout(actives[id].box, Control.notif_timeout);
notify_notification_set_app_name(actives[id].box, "toxic");
/*notify_notification_add_action(actives[id].box, "lel", "default", m_notify_action, self, NULL);*/
notify_notification_show(actives[id].box, NULL);
control_unlock();
return id;
#else
return -1;
#endif
}
int box_silent_notify2(ToxWindow* self, uint64_t flags, int id, const char* format, ...)
{
/* Always do colored notify */
if (self && self->alert == WINDOW_ALERT_NONE) {
if (flags & NT_WNDALERT_0) self->alert = WINDOW_ALERT_0;
else if (flags & NT_WNDALERT_1) self->alert = WINDOW_ALERT_1;
else if (flags & NT_WNDALERT_2) self->alert = WINDOW_ALERT_2;
}
if ((flags & NT_RESTOL && Control.cooldown > time(NULL)) ||
((flags & NT_NOFOCUS && Control.this_window == get_focused_window_id()) ))
return -1;
#ifdef _BOX_NOTIFY
control_lock();
if (id < 0 || id >= ACTIVE_NOTIFS_MAX || !actives[id].box || actives[id].size >= 128 ) {
control_unlock();
return -1;
}
va_list __ARGS__; va_start (__ARGS__, format);
vsnprintf (actives[id].messages[actives[id].size], 127, format, __ARGS__);
va_end (__ARGS__);
if (strlen(actives[id].messages[actives[id].size]) > 124)
strcpy(actives[id].messages[actives[id].size] + 124, "...");
actives[id].size ++;
actives[id].n_timeout = time(NULL) + Control.notif_timeout / 1000;
char formated[128 * 129] = {'\0'};
int i = 0;
for (; i <actives[id].size; i ++) {
strcat(formated, actives[id].messages[i]);
strcat(formated, "\n");
}
formated[strlen(formated) - 1] = '\0';
notify_notification_update(actives[id].box, actives[id].title, formated, NULL);
notify_notification_show(actives[id].box, NULL);
control_unlock();
return id;
#else
return -1;
#endif
}

View File

@ -60,14 +60,21 @@ typedef enum _Flags {
NT_ALWAYS = 1 << 8, /* Force sound to play */
} Flags;
int init_notify(int login_cooldown);
int init_notify(int login_cooldown, int notification_timeout);
void terminate_notify();
int notify(ToxWindow* self, Notification notif, uint64_t flags);
int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator);
int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id);
void stop_sound(int id);
int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator, char* title, const char* format, ...);
int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, const char* format, ...);
int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const char* title, const char* format, ...);
int box_silent_notify2(ToxWindow* self, uint64_t flags, int id, const char* format, ...);
#ifdef _SOUND_NOTIFY
int set_sound(Notification sound, const char* value);
void stop_sound(int sound);
#endif /* _SOUND_NOTIFY */
#endif /* _notify_h */

View File

@ -96,7 +96,7 @@ void kill_prompt_window(ToxWindow *self)
}
/* 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;
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 */
void prompt_update_statusmessage(ToxWindow *prompt, char *statusmsg)
void prompt_update_statusmessage(ToxWindow *prompt, const char *statusmsg)
{
StatusBar *statusbar = prompt->stb;
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
@ -185,10 +185,10 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
}
} else {
beep();
sound_notify(self, error, 0, NULL);
}
} else {
beep();
sound_notify(self, error, 0, NULL);
}
} else if (key == '\n') {
rm_trailing_spaces_buf(ctx);
@ -201,7 +201,7 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (!string_is_empty(line))
add_line_to_hist(ctx);
line_info_add(self, NULL, NULL, NULL, line, PROMPT, 0, 0);
line_info_add(self, NULL, NULL, NULL, PROMPT, 0, 0, "%s", line);
execute(ctx->history, self, m, line, GLOBAL_COMMAND_MODE);
wclear(ctx->linewin);
@ -302,28 +302,30 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, int32_t friendnum
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
char *msg;
const char *msg;
if (status == 1) {
msg = "has come online";
line_info_add(self, timefrmt, nick, NULL, msg, CONNECTION, 0, GREEN);
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg);
write_to_log(msg, nick, ctx->log, true);
#ifdef _SOUND_NOTIFY
notify(self, user_log_in, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL);
#else
notify(self, silent, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL);
#endif /* _SOUND_NOTIFY */
if (self->active_box != -1)
box_notify2(self, user_log_in, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, self->active_box,
"%s has come online", nick );
else
box_notify(self, user_log_in, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, &self->active_box,
"Toxic", "%s has come online", nick );
} else {
msg = "has gone offline";
line_info_add(self, timefrmt, nick, NULL, msg, CONNECTION, 0, RED);
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, RED, msg);
write_to_log(msg, nick, ctx->log, true);
#ifdef _SOUND_NOTIFY
notify(self, user_log_out, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL);
#else
notify(self, silent, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL);
#endif /* _SOUND_NOTIFY */
if (self->active_box != -1)
box_notify2(self, user_log_out, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, self->active_box,
"%s has gone offline", nick );
else
box_notify(self, user_log_out, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, &self->active_box,
"Toxic", "%s has gone offline", nick );
}
}
@ -335,23 +337,20 @@ static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, con
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "Friend request with the message '%s'", data);
line_info_add(self, timefrmt, NULL, NULL, msg, SYS_MSG, 0, 0);
write_to_log(msg, "", ctx->log, true);
line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 0, 0, "Friend request with the message '%s'", data);
write_to_log("Friend request with the message '%s'", "", ctx->log, true);
int n = add_friend_request(key);
if (n == -1) {
char *errmsg = "Friend request queue is full. Discarding request.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
const char *errmsg = "Friend request queue is full. Discarding request.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
write_to_log(errmsg, "", ctx->log, true);
return;
}
snprintf(msg, sizeof(msg), "Type \"/accept %d\" to accept it.", n);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
notify(self, generic_message, NT_WNDALERT_1 | NT_NOTIFWND);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type \"/accept %d\" to accept it.", n);
sound_notify(self, generic_message, NT_WNDALERT_1 | NT_NOTIFWND, NULL);
}
void prompt_init_statusbar(ToxWindow *self, Tox *m)
@ -368,11 +367,9 @@ void prompt_init_statusbar(ToxWindow *self, Tox *m)
char nick[TOX_MAX_NAME_LENGTH];
char statusmsg[MAX_STR_SIZE];
pthread_mutex_lock(&Winthread.lock);
uint16_t n_len = tox_get_self_name(m, (uint8_t *) nick);
uint16_t s_len = tox_get_self_status_message(m, (uint8_t *) statusmsg, MAX_STR_SIZE);
uint8_t status = tox_get_self_user_status(m);
pthread_mutex_unlock(&Winthread.lock);
nick[n_len] = '\0';
statusmsg[s_len] = '\0';
@ -398,18 +395,18 @@ void prompt_init_statusbar(ToxWindow *self, Tox *m)
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, 1, BLUE);
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, 1, BLUE, " _____ _____ _____ ____ ");
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, 1, BLUE, " | || |_| / \\ | | |___ ");
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, BLUE, " |_| \\___/_/\\_\\___\\____|");
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.";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
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);
msg = "Type \"/help\" for assistance. Further help may be found via the man page.";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
line_info_add(self, NULL, NULL, NULL, "", SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, CYAN, msg);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
}
static void prompt_onInit(ToxWindow *self, Tox *m)
@ -469,5 +466,7 @@ ToxWindow new_prompt(void)
ret.stb = stb;
ret.help = help;
ret.active_box = -1;
return ret;
}

View File

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

View File

@ -23,6 +23,7 @@
#include <stdlib.h>
#include <string.h>
#include <libconfig.h>
#include <ctype.h>
#include "toxic.h"
#include "windows.h"
@ -40,8 +41,6 @@
#define PACKAGE_DATADIR "."
#endif
#define NO_SOUND "silent"
const struct _ui_strings {
const char* self;
const char* timestamps;
@ -50,6 +49,8 @@ const struct _ui_strings {
const char* autolog;
const char* time_format;
const char* history_size;
const char* show_typing_self;
const char* show_typing_other;
} ui_strings = {
"ui",
"timestamps",
@ -57,8 +58,11 @@ const struct _ui_strings {
"native_colors",
"autolog",
"time_format",
"history_size"
"history_size",
"show_typing_self",
"show_typing_other",
};
static void ui_defaults(struct user_settings* settings)
{
settings->timestamps = TIMESTAMPS_ON;
@ -67,6 +71,46 @@ static void ui_defaults(struct user_settings* settings)
settings->alerts = ALERTS_ENABLED;
settings->colour_theme = DFLT_COLS;
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 {
@ -94,6 +138,7 @@ const struct _audio_strings {
"output_device",
"VAD_treshold",
};
static void audio_defaults(struct user_settings* settings)
{
settings->audio_in_dev = 0;
@ -130,6 +175,23 @@ const struct _sound_strings {
};
#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)
{
config_t cfg[1];
@ -139,6 +201,7 @@ int settings_load(struct user_settings *s, const char *patharg)
/* Load default settings */
ui_defaults(s);
tox_defaults(s);
key_defaults(s);
#ifdef _AUDIO
audio_defaults(s);
#endif
@ -155,7 +218,6 @@ int settings_load(struct user_settings *s, const char *patharg)
/* make sure path exists or is created on first time running */
FILE *fp = fopen(path, "r");
if (fp == NULL) {
if ((fp = fopen(path, "w")) == NULL)
return -1;
@ -177,8 +239,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.autolog, &s->autolog);
config_setting_lookup_bool(setting, ui_strings.native_colors, &s->colour_theme);
config_setting_lookup_int(setting, ui_strings.history_size, &s->history_size);
config_setting_lookup_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);
s->time = s->time == TIME_24 || s->time == TIME_12 ? s->time : TIME_24; /* Check defaults */
}
@ -189,6 +252,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
if ((setting = config_lookup(cfg, audio_strings.self)) != NULL) {
config_setting_lookup_int(setting, audio_strings.input_device, &s->audio_in_dev);
@ -205,61 +282,61 @@ int settings_load(struct user_settings *s, const char *patharg)
if ((setting = config_lookup(cfg, sound_strings.self)) != NULL) {
if ( (config_setting_lookup_string(setting, sound_strings.error, &str) != CONFIG_TRUE) ||
!set_sound(error, str) ) {
if (strcasecmp(str, NO_SOUND))
if (strcasecmp(str, NO_SOUND) != 0)
set_sound(error, PACKAGE_DATADIR "/sounds/Error.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.user_log_in, &str) ||
!set_sound(user_log_in, str) ) {
if (strcasecmp(str, NO_SOUND))
if (strcasecmp(str, NO_SOUND) != 0)
set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ContactLogsIn.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.self_log_in, &str) ||
!set_sound(self_log_in, str) ) {
if (strcasecmp(str, NO_SOUND))
if (strcasecmp(str, NO_SOUND) != 0)
set_sound(self_log_in, PACKAGE_DATADIR "/sounds/LogIn.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.user_log_out, &str) ||
!set_sound(user_log_out, str) ) {
if (strcasecmp(str, NO_SOUND))
if (strcasecmp(str, NO_SOUND) != 0)
set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ContactLogsOut.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.self_log_out, &str) ||
!set_sound(self_log_out, str) ) {
if (strcasecmp(str, NO_SOUND))
if (strcasecmp(str, NO_SOUND) != 0)
set_sound(self_log_out, PACKAGE_DATADIR "/sounds/LogOut.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.call_incoming, &str) ||
!set_sound(call_incoming, str) ) {
if (strcasecmp(str, NO_SOUND))
if (strcasecmp(str, NO_SOUND) != 0)
set_sound(call_incoming, PACKAGE_DATADIR "/sounds/IncomingCall.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.call_outgoing, &str) ||
!set_sound(call_outgoing, str) ) {
if (strcasecmp(str, NO_SOUND))
if (strcasecmp(str, NO_SOUND) != 0)
set_sound(call_outgoing, PACKAGE_DATADIR "/sounds/OutgoingCall.wav");
}
if ( config_setting_lookup_string(setting, sound_strings.generic_message, &str) ||
if ( !config_setting_lookup_string(setting, sound_strings.generic_message, &str) ||
!set_sound(generic_message, str) ) {
if (strcasecmp(str, NO_SOUND))
if (strcasecmp(str, NO_SOUND) != 0)
set_sound(generic_message, PACKAGE_DATADIR "/sounds/NewMessage.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.transfer_pending, &str) ||
!set_sound(transfer_pending, str) ) {
if (strcasecmp(str, NO_SOUND))
if (strcasecmp(str, NO_SOUND) != 0)
set_sound(transfer_pending, PACKAGE_DATADIR "/sounds/TransferPending.wav");
}
if ( !config_setting_lookup_string(setting, sound_strings.transfer_completed, &str) ||
!set_sound(transfer_completed, str) ) {
if (strcasecmp(str, NO_SOUND))
if (strcasecmp(str, NO_SOUND) != 0)
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/TransferComplete.wav");
}
}

View File

@ -23,6 +23,8 @@
#ifndef _settings_h
#define _settings_h
#define NO_SOUND "silent"
/* holds user setting values */
struct user_settings {
int autolog; /* boolean */
@ -31,8 +33,20 @@ struct user_settings {
int timestamps; /* boolean */
int colour_theme; /* boolean (0 for default toxic colours) */
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];
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
int audio_in_dev;
int audio_out_dev;
@ -53,12 +67,14 @@ enum {
ALERTS_DISABLED = 0,
ALERTS_ENABLED = 1,
NATIVE_COLS = 1,
DFLT_COLS = 0,
NATIVE_COLS = 1,
SHOW_TYPING_OFF = 0,
SHOW_TYPING_ON = 1,
DFLT_HST_SIZE = 700,
} settings_values;
int settings_load(struct user_settings *s, const char *patharg);
#endif /* #define _settings_h */

View File

@ -67,19 +67,13 @@ ToxAv *av;
/* Export for use in Callbacks */
char *DATA_FILE = NULL;
char *BLOCK_FILE = NULL;
ToxWindow *prompt = NULL;
#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 arg_opts arg_opts;
struct user_settings *user_settings_ = NULL;
static void catch_SIGINT(int sig)
@ -87,11 +81,26 @@ static void catch_SIGINT(int sig)
Winthread.sig_exit_toxic = true;
}
static void catch_SIGSEGV(int sig)
{
freopen("/dev/tty", "w", stderr);
endwin();
fprintf(stderr, "Caught SIGSEGV: Aborting toxic session.\n");
exit(EXIT_FAILURE);
}
static void flag_window_resize(int sig)
{
Winthread.flag_resize = true;
}
static void init_signal_catchers(void)
{
signal(SIGWINCH, flag_window_resize);
signal(SIGINT, catch_SIGINT);
signal(SIGSEGV, catch_SIGSEGV);
}
void exit_toxic_success(Tox *m)
{
store_data(m, DATA_FILE);
@ -99,10 +108,11 @@ void exit_toxic_success(Tox *m)
kill_all_windows();
free(DATA_FILE);
free(BLOCK_FILE);
free(user_settings_);
#ifdef _SOUND_NOTIFY
notify(NULL, self_log_out, NT_ALWAYS);
// sound_notify(NULL, self_log_out, NT_ALWAYS, NULL);
#endif /* _SOUND_NOTIFY */
terminate_notify();
#ifdef _AUDIO
@ -118,6 +128,7 @@ void exit_toxic_err(const char *errmsg, int errcode)
if (errmsg == NULL)
errmsg = "No error message";
freopen("/dev/tty", "w", stderr);
endwin();
fprintf(stderr, "Toxic session aborted with error code %d (%s)\n", errcode, errmsg);
exit(EXIT_FAILURE);
@ -125,8 +136,6 @@ void exit_toxic_err(const char *errmsg, int errcode)
static void init_term(void)
{
signal(SIGWINCH, flag_window_resize);
#if HAVE_WIDECHAR
if (!arg_opts.default_locale) {
@ -361,7 +370,7 @@ static void do_connection(Tox *m, ToxWindow *prompt)
}
if (msg[0])
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
}
static void load_friendlist(Tox *m)
@ -371,15 +380,17 @@ static void load_friendlist(Tox *m)
for (i = 0; i < numfriends; ++i)
friendlist_onFriendAdded(NULL, m, i, false);
sort_friendlist_index();
}
/*
* Store Messenger to given location
* Return 0 stored successfully or ignoring data file
* Return 1 file path is NULL
* Return 2 malloc failed
* Return 3 opening path failed
* Return 4 fwrite failed
* Return -1 file path is NULL
* Return -2 malloc failed
* Return -3 opening path failed
* Return -4 fwrite failed
*/
int store_data(Tox *m, char *path)
{
@ -387,13 +398,13 @@ int store_data(Tox *m, char *path)
return 0;
if (path == NULL)
return 1;
return -1;
int len = tox_size(m);
char *buf = malloc(len);
if (buf == NULL)
return 2;
return -2;
tox_save(m, (uint8_t *) buf);
@ -401,13 +412,13 @@ int store_data(Tox *m, char *path)
if (fd == NULL) {
free(buf);
return 3;
return -3;
}
if (fwrite(buf, len, 1, fd) != 1) {
free(buf);
fclose(fd);
return 4;
return -4;
}
free(buf);
@ -442,6 +453,7 @@ static void load_data(Tox *m, char *path)
tox_load(m, (uint8_t *) buf, len);
load_friendlist(m);
load_blocklist(BLOCK_FILE);
free(buf);
fclose(fd);
@ -503,6 +515,7 @@ static void set_default_opts(void)
arg_opts.use_ipv4 = 0;
arg_opts.ignore_data_file = 0;
arg_opts.default_locale = 0;
arg_opts.use_custom_data = 0;
}
static void parse_args(int argc, char *argv[])
@ -525,11 +538,15 @@ static void parse_args(int argc, char *argv[])
while ((opt = getopt_long(argc, argv, opts_str, long_opts, &indexptr)) != -1) {
switch (opt) {
case 'f':
arg_opts.use_custom_data = 1;
DATA_FILE = strdup(optarg);
BLOCK_FILE = malloc(strlen(optarg) + strlen("-blocklist") + 1);
if (DATA_FILE == NULL)
if (DATA_FILE == NULL || BLOCK_FILE == NULL)
exit_toxic_err("failed in parse_args", FATALERR_MEMORY);
strcpy(BLOCK_FILE, optarg);
strcat(BLOCK_FILE, "-blocklist");
break;
case 'x':
@ -560,39 +577,71 @@ 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)
{
if (arg_opts.use_custom_data)
return 0;
char *user_config_dir = get_user_config_dir();
int config_err = 0;
parse_args(argc, argv);
/* Make sure all written files are read/writeable only by the current user. */
umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
signal(SIGINT, catch_SIGINT);
config_err = create_user_config_dir(user_config_dir);
int config_err = create_user_config_dirs(user_config_dir);
if (DATA_FILE == NULL ) {
if (config_err) {
DATA_FILE = strdup("data");
DATA_FILE = strdup(DATANAME);
BLOCK_FILE = strdup(BLOCKNAME);
if (DATA_FILE == NULL)
exit_toxic_err("failed in main", FATALERR_MEMORY);
if (DATA_FILE == NULL || BLOCK_FILE == NULL)
exit_toxic_err("failed in load_data_structures", FATALERR_MEMORY);
} 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)
exit_toxic_err("failed in main", FATALERR_MEMORY);
if (DATA_FILE == NULL || BLOCK_FILE == NULL)
exit_toxic_err("failed in load_data_structures", FATALERR_MEMORY);
strcpy(DATA_FILE, user_config_dir);
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);
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[])
{
init_signal_catchers();
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);
int config_err = init_data_files();
/* init user_settings struct and load settings from conf file */
user_settings_ = calloc(1, sizeof(struct user_settings));
@ -613,6 +662,7 @@ int main(int argc, char *argv[])
load_data(m, DATA_FILE);
prompt = init_windows(m);
prompt_init_statusbar(prompt, m);
/* thread for ncurses stuff */
if (pthread_mutex_init(&Winthread.lock, NULL) != 0)
@ -630,32 +680,36 @@ int main(int argc, char *argv[])
set_primary_device(output, user_settings_->audio_out_dev);
#elif _SOUND_NOTIFY
if ( init_devices() == de_InternalError )
line_info_add(prompt, NULL, NULL, NULL, "Failed to init devices", SYS_MSG, 0, 0);
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init devices");
#endif /* _AUDIO */
init_notify(60);
init_notify(60, 3000);
#ifdef _SOUND_NOTIFY
notify(prompt, self_log_in, 0);
// sound_notify(prompt, self_log_in, 0, NULL);
#endif /* _SOUND_NOTIFY */
char *msg;
const char *msg;
if (config_err) {
msg = "Unable to determine configuration directory. Defaulting to 'data' for a keyfile...";
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
msg = "Unable to determine configuration directory. Defaulting to 'data' for data file...";
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
}
if (settings_err == -1) {
msg = "Failed to load user settings";
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
}
sort_friendlist_index();
prompt_init_statusbar(prompt, m);
/* Redirect stderr to /dev/null
NOTE: Might not be best solution. Comment out for debugging. */
freopen("/dev/null", "w", stderr);
uint64_t last_save = (uint64_t) time(NULL);
uint64_t looptimer = last_save;
useconds_t msleepval = 40000;
uint64_t loopcount = 0;
while (true) {
update_unix_time();
@ -670,7 +724,8 @@ int main(int argc, char *argv[])
last_save = cur_time;
}
usleep(40000);
msleepval = optimal_msleepval(&looptimer, &loopcount, cur_time, msleepval);
usleep(msleepval);
}
return 0;

View File

@ -50,7 +50,7 @@
#define TIME_STR_SIZE 16
/* 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_DISCARD 0x15 /* ctrl-u */
#define T_KEY_NEXT 0x10 /* ctrl-p */
@ -63,9 +63,13 @@
#define T_KEY_C_F 0x06 /* ctrl-f */
#define T_KEY_C_H 0x08 /* ctrl-h */
#define T_KEY_C_Y 0x19 /* ctrl-y */
#define T_KEY_TAB 0x09 /* TAB key */
#define ONLINE_CHAR "*"
#define OFFLINE_CHAR "o"
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_THREAD_CREATE = -3, /* thread creation failed */
FATALERR_MUTEX_INIT = -4, /* mutex init failed */

View File

@ -28,6 +28,7 @@
#include "windows.h"
#include "misc_tools.h"
#include "toxic_strings.h"
#include "notify.h"
/* Adds char to line at pos. Return 0 on success, -1 if line buffer is full */
int add_char_to_buf(ChatContext *ctx, wint_t ch)
@ -111,7 +112,7 @@ int yank_buf(ChatContext *ctx)
if (!ctx->yank[0])
return -1;
if (ctx->yank_len + ctx->len >= MAX_STR_SIZE - 1)
if (ctx->yank_len + ctx->len >= MAX_STR_SIZE)
return -1;
wmemmove(&ctx->line[ctx->pos + ctx->yank_len], &ctx->line[ctx->pos], ctx->len - ctx->pos);
@ -170,7 +171,7 @@ static void shift_hist_back(ChatContext *ctx)
/* adds a line to the ln_history buffer at hst_pos and sets hst_pos to end of history. */
void add_line_to_hist(ChatContext *ctx)
{
if (ctx->len > MAX_STR_SIZE)
if (ctx->len >= MAX_STR_SIZE)
return;
if (ctx->hst_tot >= MAX_LINE_HIST)
@ -191,7 +192,7 @@ void fetch_hist_item(ChatContext *ctx, int key_dir)
if (key_dir == KEY_UP) {
if (--ctx->hst_pos < 0) {
ctx->hst_pos = 0;
beep();
sound_notify(NULL, error, NT_ALWAYS, NULL);
}
} else {
if (++ctx->hst_pos >= ctx->hst_tot) {

View File

@ -33,12 +33,14 @@
#include "chat.h"
#include "line_info.h"
#include "settings.h"
extern char *DATA_FILE;
extern struct _Winthread Winthread;
static ToxWindow windows[MAX_WINDOWS_NUM];
static ToxWindow *active_window;
extern ToxWindow *prompt;
extern struct user_settings *user_settings_;
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)
{
if (user_settings_->show_typing_other == SHOW_TYPING_OFF)
return;
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
@ -267,7 +272,7 @@ void set_next_window(int ch)
ToxWindow *inf = active_window;
while (true) {
if (ch == T_KEY_NEXT) {
if (ch == user_settings_->key_next_tab) {
if (++active_window > end)
active_window = windows;
} else if (--active_window < windows)
@ -452,7 +457,7 @@ void draw_active_window(Tox *m)
ltr = isprint(ch);
#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);
} else {
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)
{
return num_active_windows;

View File

@ -71,6 +71,15 @@ struct _Winthread {
bool flag_resize;
};
struct arg_opts {
int ignore_data_file;
int use_ipv4;
int default_locale;
int use_custom_data;
char config_path[MAX_STR_SIZE];
char nodes_path[MAX_STR_SIZE];
};
typedef struct ToxWindow ToxWindow;
typedef struct StatusBar StatusBar;
typedef struct PromptBuf PromptBuf;
@ -116,11 +125,10 @@ struct ToxWindow {
* Don't modify outside av callbacks. */
int device_selection[2]; /* -1 if not set, if set uses these selections instead of primary device */
int ringing_sound;
#endif /* _AUDIO */
#ifdef _SOUND_NOTIFY
int active_sound;
#endif
int active_box; /* For box notify */
char name[TOXIC_MAX_NAME_LENGTH];
int32_t num; /* corresponds to friendnumber in chat windows */
@ -217,6 +225,7 @@ void set_active_window(int ch);
int get_num_active_windows(void);
void kill_all_windows(void); /* should only be called on shutdown */
void on_window_resize(void);
ToxWindow *get_window_ptr(int i);
/* refresh inactive windows to prevent scrolling bugs.
call at least once per second */