mirror of
https://github.com/Tha14/toxic.git
synced 2025-06-27 02:16:45 +02:00
Compare commits
149 Commits
Author | SHA1 | Date | |
---|---|---|---|
2ce42ab057 | |||
934459dea8 | |||
52bc874675 | |||
511907fbc5 | |||
155e194174 | |||
b1c7e21ca9 | |||
7edcf6cb45 | |||
9581940cfa | |||
f2aa57c4fa | |||
8bf4405fd0 | |||
21ef1788ca | |||
68f1dffba7 | |||
092df2c0e4 | |||
691f94c75c | |||
d6d4476e85 | |||
924e8e0860 | |||
53193e933f | |||
328587ad9c | |||
1a8fdb1b99 | |||
690f0221b5 | |||
e117bd3985 | |||
15cc87bffd | |||
97d4c97c52 | |||
c8b22d7e8a | |||
f48ec4f49b | |||
d4ce697bd9 | |||
bd20513493 | |||
fd3f4eb724 | |||
75e8486061 | |||
bd216709fc | |||
a3a8f7608a | |||
affc88d0a8 | |||
eca4882ce2 | |||
58b0a04019 | |||
b870679f2c | |||
ae83725cb6 | |||
595e42b587 | |||
f5401df2c7 | |||
3e79a5ca8b | |||
327081945e | |||
68ec484a58 | |||
1d6ccf56a8 | |||
67f637a1e1 | |||
5e175d5319 | |||
778db0fece | |||
72010dd2e1 | |||
39556b36f3 | |||
dc9ffa6e56 | |||
1e92bb3c2b | |||
edbdf2966a | |||
3f6fd734d3 | |||
919a06d282 | |||
35cc815cdb | |||
a318bdb034 | |||
d6aaa95b25 | |||
5718ad52db | |||
0f4cffbacc | |||
d9a861331f | |||
2f12a8d429 | |||
e75cf4f3ad | |||
bb85f31bb2 | |||
396d08f0d2 | |||
6ab184e7ce | |||
fd65fbfd0c | |||
637ea0ed55 | |||
dc2d20f4c4 | |||
d712ccc17e | |||
147030e06f | |||
09fd5cb69f | |||
64db9f73a2 | |||
28633be2dd | |||
6fdafceda8 | |||
38ed0c86ad | |||
ad23816096 | |||
bc4a730e76 | |||
79372cc80d | |||
c9e4246ac5 | |||
dcd6a238b6 | |||
c49de7733c | |||
3fc7c90630 | |||
53663a7832 | |||
c14f2a3fcd | |||
3cbe61e111 | |||
fa023c6a99 | |||
f98e6bdcb4 | |||
0884954c84 | |||
43727c6730 | |||
618b731d5a | |||
46975bf38b | |||
8f3989000d | |||
9fe75fbc47 | |||
c455e79604 | |||
a223545853 | |||
b243f7aa62 | |||
899452d7cd | |||
af68fa7ee0 | |||
5da789cc37 | |||
7e5b41c8e0 | |||
0254596c73 | |||
67c02404b7 | |||
0b5ee7e2c7 | |||
fba0732faa | |||
d06086a656 | |||
e74b678739 | |||
b62787ce47 | |||
75708f7600 | |||
476dec46b6 | |||
973f6206ee | |||
cbe47b3660 | |||
1c58c339bb | |||
15e91cfa99 | |||
f4fb6ea4fc | |||
0d2ff2c0a8 | |||
5275da5a6b | |||
e891b1281b | |||
ca7110b37c | |||
8960eb98f4 | |||
18610668b8 | |||
efe61e32e2 | |||
7a7e4f573a | |||
a7e6ab7758 | |||
a0cde4ae8c | |||
7566aa9d26 | |||
d2332a5b77 | |||
94a8ce5aa8 | |||
b18a67d656 | |||
02708534c0 | |||
d5710d80e0 | |||
8dcba3219d | |||
9f01a45b1f | |||
dd2cb93ecc | |||
49538a986c | |||
26c2331d0f | |||
a0758643c2 | |||
77e152ad36 | |||
4834642b80 | |||
18a6f621f0 | |||
3cae1d92cd | |||
02b192d6ee | |||
f630a3e604 | |||
fb5a9bc043 | |||
26ad5a00a3 | |||
18e1f08e31 | |||
b68deef6db | |||
30ec7debba | |||
3a1e23a3ff | |||
0887bb7662 | |||
5a55f738a9 | |||
8d8df585ad |
@ -1,7 +1,7 @@
|
||||
language: c
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
# - clang # Fix me
|
||||
|
||||
before_script:
|
||||
# Installing yasm (needed for compiling vpx) and openal
|
||||
|
27
README.md
27
README.md
@ -1,7 +1,7 @@
|
||||
# Toxic [](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.
|
||||
|
||||
.
|
||||

|
||||
|
||||
## Installation
|
||||
|
||||
@ -12,13 +12,21 @@ 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')
|
||||
|
||||
##### Documentation
|
||||
* [Asciidoc](http://asciidoc.org/index.html) (only required for regenerating manpages)
|
||||
* Run `make doc` after editing the asciidoc files to regenerate the manpages.
|
||||
* **NOTE FOR DEVELOPERS**: asciidoc files and generated manpages will need to be commited together.
|
||||
|
||||
### Compiling
|
||||
1. `cd build/`
|
||||
2. `make PREFIX="/where/to/install"`
|
||||
@ -27,10 +35,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 +57,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).
|
||||
|
142
build/Makefile
142
build/Makefile
@ -1,21 +1,7 @@
|
||||
TOXIC_VERSION = 0.4.6
|
||||
REV = $(shell git rev-list HEAD --count)
|
||||
VERSION = $(TOXIC_VERSION)_r$(REV)
|
||||
BASE_DIR = $(shell cd .. && pwd -P)
|
||||
CFG_DIR = $(BASE_DIR)/cfg
|
||||
|
||||
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
|
||||
-include $(CFG_DIR)/global_vars.mk
|
||||
|
||||
LIBS = libtoxcore ncursesw libconfig
|
||||
|
||||
@ -29,139 +15,43 @@ 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)/checks/check_features.mk
|
||||
|
||||
# Targets
|
||||
all: toxic
|
||||
all: toxic doc
|
||||
|
||||
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 +60,8 @@ install: toxic
|
||||
clean:
|
||||
rm -rf *.d *.o toxic
|
||||
|
||||
-include $(CFG_DIR)/help.mk
|
||||
|
||||
-include $(OBJ:.o=.d)
|
||||
|
||||
.PHONY: clean all install
|
||||
-include $(CFG_DIR)/targets/*.mk
|
||||
|
||||
.PHONY: clean all
|
||||
|
23
cfg/checks/av.mk
Normal file
23
cfg/checks/av.mk
Normal 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 --exists $(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 --exists $$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
|
41
cfg/checks/check_features.mk
Normal file
41
cfg/checks/check_features.mk
Normal file
@ -0,0 +1,41 @@
|
||||
CHECKS_DIR = $(CFG_DIR)/checks
|
||||
|
||||
# Check if we can use X11
|
||||
CHECK_X11_LIBS = $(shell pkg-config --exists 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 $(CHECKS_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 $(CHECKS_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 $(CHECKS_DIR)/desktop_notifications.mk
|
||||
endif
|
||||
|
||||
# Check if we can build Toxic
|
||||
CHECK_LIBS = $(shell pkg-config --exists $(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 --exists $$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
|
17
cfg/checks/desktop_notifications.mk
Normal file
17
cfg/checks/desktop_notifications.mk
Normal 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 --exists $(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 --exists $$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
|
23
cfg/checks/sound_notifications.mk
Normal file
23
cfg/checks/sound_notifications.mk
Normal 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 --exists $(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 --exists $$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
|
23
cfg/global_vars.mk
Normal file
23
cfg/global_vars.mk
Normal file
@ -0,0 +1,23 @@
|
||||
# Version
|
||||
TOXIC_VERSION = 0.5.0
|
||||
REV = $(shell git rev-list HEAD --count)
|
||||
VERSION = $(TOXIC_VERSION)_r$(REV)
|
||||
|
||||
# Project directories
|
||||
DOC_DIR = $(BASE_DIR)/doc
|
||||
SRC_DIR = $(BASE_DIR)/src
|
||||
SND_DIR = $(BASE_DIR)/sounds
|
||||
MISC_DIR = $(BASE_DIR)/misc
|
||||
|
||||
# Project files
|
||||
MANFILES = toxic.1 toxic.conf.5
|
||||
DATAFILES = DHTnodes DNSservers toxic.conf.example
|
||||
SNDFILES = ContactLogsIn.wav ContactLogsOut.wav Error.wav IncomingCall.wav
|
||||
SNDFILES += LogIn.wav LogOut.wav NewMessage.wav OutgoingCall.wav
|
||||
SNDFILES += TransferComplete.wav TransferPending.wav
|
||||
|
||||
# Install directories
|
||||
PREFIX = /usr/local
|
||||
BINDIR = $(PREFIX)/bin
|
||||
DATADIR = $(PREFIX)/share/toxic
|
||||
MANDIR = $(PREFIX)/share/man
|
18
cfg/help.mk
18
cfg/help.mk
@ -1,18 +0,0 @@
|
||||
# Help target
|
||||
help:
|
||||
@echo "-- Targets --"
|
||||
@echo " all: Build toxic [DEFAULT]"
|
||||
@echo " toxic: Build toxic"
|
||||
@echo " install: Build toxic and install it in PREFIX (default PREFIX is \"$(abspath $(PREFIX))\")"
|
||||
@echo " clean: Remove built files"
|
||||
@echo " help: This 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 " USER_CFLAGS: Add custom flags to default CFLAGS"
|
||||
@echo " USER_LDFLAGS: Add custom flags to default LDFLAGS"
|
||||
@echo " PREFIX: Specify a prefix directory for binaries, data files,... (default is \"$(abspath $(PREFIX))\")"
|
||||
@echo " DESTDIR: Specify a directory where to store installed files (mainly for packaging purpose)"
|
||||
|
||||
.PHONY: help
|
4
cfg/platforms/.gitignore
vendored
Normal file
4
cfg/platforms/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
@ -1,3 +1,4 @@
|
||||
# Specials options for freebsd systems
|
||||
LIBS := $(filter-out ncursesw, $(LIBS))
|
||||
LDFLAGS += -lncursesw
|
||||
MANDIR = $(PREFIX)/man
|
@ -1,3 +1,4 @@
|
||||
# Specials options for linux systems
|
||||
CFLAGS +=
|
||||
LDFLAGS += -ldl -lresolv
|
||||
MANDIR = $(PREFIX)/share/man
|
10
cfg/targets/doc.mk
Normal file
10
cfg/targets/doc.mk
Normal file
@ -0,0 +1,10 @@
|
||||
# Doc target
|
||||
doc: $(MANFILES:%=$(DOC_DIR)/%)
|
||||
|
||||
$(DOC_DIR)/%: $(DOC_DIR)/%.asc
|
||||
@echo " MAN $(@F)"
|
||||
@a2x -f manpage -a revdate=$(shell git log -1 --date=short --format="%ad" $<) \
|
||||
-a manmanual="Toxic Manual" -a mansource=toxic \
|
||||
-a manversion=__VERSION__ -a datadir=__DATADIR__ $<
|
||||
|
||||
.PHONY: doc
|
20
cfg/targets/help.mk
Normal file
20
cfg/targets/help.mk
Normal file
@ -0,0 +1,20 @@
|
||||
# Help target
|
||||
help:
|
||||
@echo "-- Targets --"
|
||||
@echo " all: Build toxic and documentation [DEFAULT]"
|
||||
@echo " toxic: Build toxic"
|
||||
@echo " doc: Build documentation"
|
||||
@echo " install: Build toxic and install it in PREFIX (default PREFIX is \"$(abspath $(PREFIX))\")"
|
||||
@echo " clean: Remove built files"
|
||||
@echo " help: This help"
|
||||
@echo
|
||||
@echo "-- Variables --"
|
||||
@echo " DISABLE_AV: Set to \"1\" to force building without audio call 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))\")"
|
||||
@echo " DESTDIR: Specify a directory where to store installed files (mainly for packaging purpose)"
|
||||
|
||||
.PHONY: help
|
32
cfg/targets/install.mk
Normal file
32
cfg/targets/install.mk
Normal file
@ -0,0 +1,32 @@
|
||||
# Install target
|
||||
install: toxic doc
|
||||
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
|
196
doc/toxic.1
196
doc/toxic.1
@ -1,63 +1,143 @@
|
||||
.TH TOXIC 1 "June 2014" "Toxic v__VERSION__" "User Manual"
|
||||
.SH NAME
|
||||
Toxic \- CLI client for Tox
|
||||
.SH SYNOPSYS
|
||||
.B toxic [\-f
|
||||
.I data\-file
|
||||
.B ] [\-x] [\-4] [\-c
|
||||
.I config\-file
|
||||
.B ] [\-n
|
||||
.I nodes\-file
|
||||
.B ] [\-h]
|
||||
.SH DESCRIPTION
|
||||
Toxic is an ncurses-based instant messaging client for Tox which formerly
|
||||
resided in the Tox core repository, and is now available as a standalone
|
||||
application.
|
||||
.SH OPTIONS
|
||||
.IP "\-f, \-\-file data\-file"
|
||||
Use specified
|
||||
.I data\-file
|
||||
instead of
|
||||
.IR ~/.config/tox/data
|
||||
.IP "\-x, \-\-nodata"
|
||||
Ignore data file
|
||||
.IP "\-4, \-\-ipv4"
|
||||
'\" t
|
||||
.\" Title: toxic
|
||||
.\" Author: [see the "AUTHORS" section]
|
||||
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
||||
.\" Date: 2014-08-21
|
||||
.\" Manual: Toxic Manual
|
||||
.\" Source: toxic __VERSION__
|
||||
.\" Language: English
|
||||
.\"
|
||||
.TH "TOXIC" "1" "2014\-08\-21" "toxic __VERSION__" "Toxic Manual"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * Define some portability stuff
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" http://bugs.debian.org/507673
|
||||
.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * set default formatting
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" disable hyphenation
|
||||
.nh
|
||||
.\" disable justification (adjust text to left margin only)
|
||||
.ad l
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * MAIN CONTENT STARTS HERE *
|
||||
.\" -----------------------------------------------------------------
|
||||
.SH "NAME"
|
||||
toxic \- CLI client for Tox
|
||||
.SH "SYNOPSIS"
|
||||
.sp
|
||||
\fBtoxic\fR [\-f \fIdata\-file\fR] [\-x] [\-4] [\-c \fIconfig\-file\fR] [\-n \fInodes\-file\fR] [\-h]
|
||||
.SH "DESCRIPTION"
|
||||
.sp
|
||||
toxic is an ncurses\-based instant messaging client for Tox which formerly resided in the Tox core repository, and is now available as a standalone application\&.
|
||||
.SH "OPTIONS"
|
||||
.PP
|
||||
\-4, \-\-ipv4
|
||||
.RS 4
|
||||
Force IPv4 connection
|
||||
.IP "\-d, \-\-default_locale
|
||||
Use default locale
|
||||
.IP "\-c, \-\-config config\-file"
|
||||
.RE
|
||||
.PP
|
||||
\-b, \-\-debug
|
||||
.RS 4
|
||||
Enable stderr for debugging\&. Redirect output to avoid breaking the curses interface and better capture messages\&.
|
||||
.RE
|
||||
.PP
|
||||
\-c, \-\-config config\-file
|
||||
.RS 4
|
||||
Use specified
|
||||
.I config\-file
|
||||
\fIconfig\-file\fR
|
||||
instead of
|
||||
.IR ~/.config/tox/toxic.conf
|
||||
.IP "\-n, \-\-nodes nodes\-file"
|
||||
\fI~/\&.config/tox/toxic\&.conf\fR
|
||||
.RE
|
||||
.PP
|
||||
\-d, \-\-default_locale
|
||||
.RS 4
|
||||
Use default locale
|
||||
.RE
|
||||
.PP
|
||||
\-f, \-\-file data\-file
|
||||
.RS 4
|
||||
Use specified
|
||||
.I nodes\-file
|
||||
for DHT bootstrap nodes, instead of
|
||||
.IR __DATADIR__/DHTnodes
|
||||
.IP "\-h, \-\-help"
|
||||
\fIdata\-file\fR
|
||||
instead of
|
||||
\fI~/\&.config/tox/data\fR
|
||||
.RE
|
||||
.PP
|
||||
\-h, \-\-help
|
||||
.RS 4
|
||||
Show help message
|
||||
.SH FILES
|
||||
.IP __DATADIR__/DHTnodes
|
||||
Default list of DHT bootstrap nodes.
|
||||
.IP ~/.config/tox/data
|
||||
Savestate which contains your personal info (nickname, Tox ID,...) and
|
||||
your contacts list.
|
||||
.IP ~/.config/tox/toxic.conf
|
||||
Configuration file. See
|
||||
.BR toxic.conf (5)
|
||||
for more details.
|
||||
.IP __DATADIR__/toxic.conf.example
|
||||
Configuration example.
|
||||
.SH BUGS
|
||||
Unicode characters with a width larger than 1 column may cause
|
||||
strange behaviour. Expect more bugs and bad
|
||||
behaviour: this software is in a pre\-alpha stage.
|
||||
.SH AUTHORS
|
||||
JFreegman <JFreegman@gmail.com>
|
||||
.SH SEE ALSO
|
||||
.BR toxic.conf (5)
|
||||
.SH LINKS
|
||||
Project page on github: https://github.com/Tox/toxic
|
||||
.br
|
||||
IRC channel on Freenode: chat.freenode.net#tox
|
||||
.RE
|
||||
.PP
|
||||
\-n, \-\-nodes nodes\-file
|
||||
.RS 4
|
||||
Use specified
|
||||
\fInodes\-file\fR
|
||||
for DHT bootstrap nodes, instead of
|
||||
\fI__DATADIR__/DHTnodes\fR
|
||||
.RE
|
||||
.PP
|
||||
\-o, \-\-noconnect
|
||||
.RS 4
|
||||
Do not connect to the DHT network
|
||||
.RE
|
||||
.PP
|
||||
\-p, \-\-proxy
|
||||
.RS 4
|
||||
Use proxy: Requires [IP] [port]
|
||||
.RE
|
||||
.PP
|
||||
\-r, \-\-dnslist
|
||||
.RS 4
|
||||
Use specified DNSservers file
|
||||
.RE
|
||||
.PP
|
||||
\-t, \-\-force\-tcp
|
||||
.RS 4
|
||||
Force TCP connection (use this with proxies)
|
||||
.RE
|
||||
.PP
|
||||
\-x, \-\-nodata
|
||||
.RS 4
|
||||
Ignore data file
|
||||
.RE
|
||||
.SH "FILES"
|
||||
.PP
|
||||
__DATADIR__/DHTnodes
|
||||
.RS 4
|
||||
Default list of DHT bootstrap nodes\&.
|
||||
.RE
|
||||
.PP
|
||||
~/\&.config/tox/data
|
||||
.RS 4
|
||||
Savestate which contains your personal info (nickname, Tox ID, contacts, etc)
|
||||
.RE
|
||||
.PP
|
||||
~/\&.config/tox/toxic\&.conf
|
||||
.RS 4
|
||||
Configuration file\&. See
|
||||
\fBtoxic\&.conf\fR(5) for more details\&.
|
||||
.RE
|
||||
.PP
|
||||
__DATADIR__/toxic\&.conf\&.example
|
||||
.RS 4
|
||||
Configuration example\&.
|
||||
.RE
|
||||
.SH "BUGS"
|
||||
.sp
|
||||
Unicode characters with a width larger than 1 column may cause strange behaviour\&. Expect more bugs and bad behaviour: this software is in a pre\-alpha stage\&.
|
||||
.SH "AUTHORS"
|
||||
.sp
|
||||
JFreegman <JFreegman@gmail\&.com>
|
||||
.SH "SEE ALSO"
|
||||
.sp
|
||||
\fBtoxic\&.conf\fR(5)
|
||||
.SH "LINKS"
|
||||
.sp
|
||||
Project page: https://github\&.com/Tox/toxic
|
||||
.sp
|
||||
IRC channel: chat\&.freenode\&.net#tox
|
||||
|
91
doc/toxic.1.asc
Normal file
91
doc/toxic.1.asc
Normal file
@ -0,0 +1,91 @@
|
||||
toxic(1)
|
||||
========
|
||||
|
||||
NAME
|
||||
----
|
||||
toxic - CLI client for Tox
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
*toxic* [-f 'data-file'] [-x] [-4] [-c 'config-file'] [-n 'nodes-file'] [-h]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
toxic is an ncurses-based instant messaging client for Tox which formerly
|
||||
resided in the Tox core repository, and is now available as a standalone
|
||||
application.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
-4, --ipv4::
|
||||
Force IPv4 connection
|
||||
|
||||
-b, --debug::
|
||||
Enable stderr for debugging. Redirect output to
|
||||
avoid breaking the curses interface and better capture messages.
|
||||
|
||||
-c, --config config-file::
|
||||
Use specified 'config-file' instead of '~/.config/tox/toxic.conf'
|
||||
|
||||
-d, --default_locale::
|
||||
Use default locale
|
||||
|
||||
-f, --file data-file::
|
||||
Use specified 'data-file' instead of '~/.config/tox/data'
|
||||
|
||||
-h, --help::
|
||||
Show help message
|
||||
|
||||
-n, --nodes nodes-file::
|
||||
Use specified 'nodes-file' for DHT bootstrap nodes, instead of
|
||||
'{datadir}/DHTnodes'
|
||||
|
||||
-o, --noconnect::
|
||||
Do not connect to the DHT network
|
||||
|
||||
-p, --proxy::
|
||||
Use proxy: Requires [IP] [port]
|
||||
|
||||
-r, --dnslist::
|
||||
Use specified DNSservers file
|
||||
|
||||
-t, --force-tcp::
|
||||
Force TCP connection (use this with proxies)
|
||||
|
||||
-x, --nodata::
|
||||
Ignore data file
|
||||
|
||||
FILES
|
||||
-----
|
||||
{datadir}/DHTnodes::
|
||||
Default list of DHT bootstrap nodes.
|
||||
|
||||
~/.config/tox/data::
|
||||
Savestate which contains your personal info (nickname, Tox ID, contacts,
|
||||
etc)
|
||||
|
||||
~/.config/tox/toxic.conf::
|
||||
Configuration file. See *toxic.conf*(5) for more details.
|
||||
|
||||
{datadir}/toxic.conf.example::
|
||||
Configuration example.
|
||||
|
||||
BUGS
|
||||
----
|
||||
Unicode characters with a width larger than 1 column may cause strange
|
||||
behaviour. Expect more bugs and bad behaviour: this software is in a
|
||||
pre-alpha stage.
|
||||
|
||||
AUTHORS
|
||||
-------
|
||||
JFreegman <JFreegman@gmail.com>
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
*toxic.conf*(5)
|
||||
|
||||
LINKS
|
||||
-----
|
||||
Project page: <https://github.com/Tox/toxic>
|
||||
|
||||
IRC channel: chat.freenode.net#tox
|
555
doc/toxic.conf.5
555
doc/toxic.conf.5
@ -1,292 +1,271 @@
|
||||
.TH TOXIC.CONF 5 "June 2014" "Toxic v__VERSION__" "User Manual"
|
||||
.SH NAME
|
||||
toxic.conf \- Configuration file for toxic(1)
|
||||
.SH DESCRIPTION
|
||||
The
|
||||
.I toxic.conf
|
||||
file is the main configuration file for
|
||||
.BR toxic (1)
|
||||
client.
|
||||
.SH SYNTAX
|
||||
.I <SECTION>
|
||||
.B = {
|
||||
.PP
|
||||
.IB <KEY1> : <BOOL_VALUE> ;
|
||||
.br
|
||||
.IB <KEY2> = <NOT_BOOL_VALUE> ;
|
||||
.br
|
||||
...
|
||||
.PP
|
||||
.B };
|
||||
.PP
|
||||
Uses syntax accepted by libconfig.
|
||||
.br
|
||||
Lines starting with "//" are comments and will be ignored.
|
||||
.PP
|
||||
Sections:
|
||||
.PP
|
||||
.B ui
|
||||
.RS
|
||||
Configurations related to user interface.
|
||||
.PP
|
||||
Keys:
|
||||
.br
|
||||
.B timestamps
|
||||
.RS
|
||||
Enable or disable timestamps.
|
||||
.br
|
||||
Values: 'true' to enable, 'false' to disable
|
||||
.RE
|
||||
.PP
|
||||
.B alerts
|
||||
.RS
|
||||
Enable or disable terminal alerts on events.
|
||||
.br
|
||||
Values: 'true' to enable, 'false' to disable
|
||||
.RE
|
||||
.PP
|
||||
.B native_colors
|
||||
.RS
|
||||
Select between native terminal colors and toxic color theme.
|
||||
.br
|
||||
Values: 'true' for terminal colours, 'false' for toxic colours
|
||||
.RE
|
||||
.PP
|
||||
.B autolog
|
||||
.RS
|
||||
Enable or disable autologging.
|
||||
.br
|
||||
Values: 'true' to enable, 'false' to disable
|
||||
.RE
|
||||
.PP
|
||||
.B time_format
|
||||
.RS
|
||||
Select between 24 and 12 hour time.
|
||||
.br
|
||||
Values: 24, 12
|
||||
.RE
|
||||
.PP
|
||||
.B history_size
|
||||
.RS
|
||||
Maximum lines for chat window history.
|
||||
.br
|
||||
Values: <INTEGER> (for example: 700)
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
.B audio
|
||||
.RS
|
||||
Configurations related to audio devices.
|
||||
.PP
|
||||
Keys:
|
||||
.br
|
||||
.B input_device
|
||||
.RS
|
||||
Audio input device.
|
||||
.br
|
||||
Values: <INTEGER> (number correspond to "/lsdev in")
|
||||
.RE
|
||||
.PP
|
||||
.B output_device
|
||||
.RS
|
||||
Audio output device.
|
||||
.br
|
||||
Values: <INTEGER> (number correspond to "/lsdev out")
|
||||
.RE
|
||||
.PP
|
||||
.B VAD_treshold
|
||||
.RS
|
||||
Voice Activity Detection treshold.
|
||||
.br
|
||||
Values: <FLOAT> (recommended values are around 40.0)
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
.B tox
|
||||
.RS
|
||||
Configurations related to file transfer.
|
||||
.PP
|
||||
Keys:
|
||||
.br
|
||||
.B download_path
|
||||
.RS
|
||||
Default path for downloads.
|
||||
.br
|
||||
Values: <STRING> (absolute path where to store downloaded files)
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
.B sounds
|
||||
.RS
|
||||
Configurations related to notification sounds.
|
||||
.PP
|
||||
Keys:
|
||||
.br
|
||||
.B error
|
||||
.RS
|
||||
Sound to play when an error occurs.
|
||||
.br
|
||||
Values: <STRING> (sound file absolute path)
|
||||
.RE
|
||||
.PP
|
||||
.B self_log_in
|
||||
.RS
|
||||
Sound to play when you log in.
|
||||
.br
|
||||
Values: <STRING> (sound file absolute path)
|
||||
.RE
|
||||
.PP
|
||||
.B self_log_out
|
||||
.RS
|
||||
Sound to play when you log out.
|
||||
.br
|
||||
Values: <STRING> (sound file absolute path)
|
||||
.RE
|
||||
.PP
|
||||
.B user_log_in
|
||||
.RS
|
||||
Sound to play when a contact become online.
|
||||
.br
|
||||
Values: <STRING> (sound file absolute path)
|
||||
.RE
|
||||
.PP
|
||||
.B user_log_out
|
||||
.RS
|
||||
Sound to play when a contact become offline.
|
||||
.br
|
||||
Values: <STRING> (sound file absolute path)
|
||||
.RE
|
||||
.PP
|
||||
.B call_incoming
|
||||
.RS
|
||||
Sound to play when you receive an incoming call.
|
||||
.br
|
||||
Values: <STRING> (sound file absolute path)
|
||||
.RE
|
||||
.PP
|
||||
.B call_outgoing
|
||||
.RS
|
||||
Sound to play when you start a call.
|
||||
.br
|
||||
Values: <STRING> (sound file absolute path)
|
||||
.RE
|
||||
.PP
|
||||
.B generic_message
|
||||
.RS
|
||||
Sound to play when an event occurs.
|
||||
.br
|
||||
Values: <STRING> (sound file absolute path)
|
||||
.RE
|
||||
.PP
|
||||
.B transfer_pending
|
||||
.RS
|
||||
Sound to play when you receive a file transfer request.
|
||||
.br
|
||||
Values: <STRING> (sound file absolute path)
|
||||
.RE
|
||||
.PP
|
||||
.B transfer_completed
|
||||
.RS
|
||||
Sound to play when a file transfer is completed.
|
||||
.br
|
||||
Values: <STRING> (sound file absolute path)
|
||||
.RE
|
||||
.RE
|
||||
.SH EXAMPLES
|
||||
Default settings from __DATADIR__/toxic.conf.exmaple:
|
||||
.PP
|
||||
// SAMPLE TOXIC CONFIGURATION
|
||||
.br
|
||||
// USES LIBCONFIG-ACCEPTED SYNTAX
|
||||
.br
|
||||
'\" t
|
||||
.\" Title: toxic.conf
|
||||
.\" Author: [see the "AUTHORS" section]
|
||||
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
||||
.\" Date: 2014-08-21
|
||||
.\" Manual: Toxic Manual
|
||||
.\" Source: toxic __VERSION__
|
||||
.\" Language: English
|
||||
.\"
|
||||
.TH "TOXIC\&.CONF" "5" "2014\-08\-21" "toxic __VERSION__" "Toxic Manual"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * Define some portability stuff
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" http://bugs.debian.org/507673
|
||||
.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * set default formatting
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" disable hyphenation
|
||||
.nh
|
||||
.\" disable justification (adjust text to left margin only)
|
||||
.ad l
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * MAIN CONTENT STARTS HERE *
|
||||
.\" -----------------------------------------------------------------
|
||||
.SH "NAME"
|
||||
toxic.conf \- Configuration file for toxic
|
||||
.SH "SYNOPSIS"
|
||||
.sp
|
||||
~/\&.config/tox/toxic\&.conf
|
||||
.SH "DESCRIPTION"
|
||||
.sp
|
||||
The \fItoxic\&.conf\fR file is the main configuration file for \fBtoxic\fR(1) client\&. It uses syntax accepted by \fBlibconfig\fR\&. Lines starting with "//" are comments and will be ignored\&.
|
||||
.SH "EXAMPLE"
|
||||
.sp
|
||||
.if n \{\
|
||||
.RS 4
|
||||
.\}
|
||||
.nf
|
||||
// Configuration for interface
|
||||
ui = {
|
||||
.br
|
||||
// true to enable timestamps, false to disable
|
||||
.br
|
||||
timestamps:true;
|
||||
.br
|
||||
.br
|
||||
// true to enable terminal alerts on messages, false to disable
|
||||
.br
|
||||
alerts:true;
|
||||
.br
|
||||
// true to use native terminal colours, false to use toxic default colour theme
|
||||
.br
|
||||
native_colors:false;
|
||||
.br
|
||||
// true to enable autologging, false to disable
|
||||
.br
|
||||
autolog:false;
|
||||
.br
|
||||
// 24 or 12 hour time
|
||||
.br
|
||||
time_format=24;
|
||||
.br
|
||||
// maximum lines for chat window history
|
||||
.br
|
||||
history_size=700;
|
||||
.br
|
||||
timestamps = true;
|
||||
alerts = false;
|
||||
};
|
||||
.br
|
||||
|
||||
// Configuration for audio
|
||||
audio = {
|
||||
.br
|
||||
// preferred audio input device; numbers correspond to /lsdev in
|
||||
.br
|
||||
input_device=2;
|
||||
.br
|
||||
// preferred audio output device; numbers correspond to /lsdev out
|
||||
.br
|
||||
output_device=0;
|
||||
.br
|
||||
// default VAD treshold; float (recommended values are around 40)
|
||||
.br
|
||||
VAD_treshold=40.0;
|
||||
.br
|
||||
input_device = 1;
|
||||
};
|
||||
.br
|
||||
tox = {
|
||||
.br
|
||||
// where to store received files
|
||||
.br
|
||||
// download_path="/home/USERNAME/Downloads/";
|
||||
.br
|
||||
};
|
||||
.br
|
||||
// To disable a sound set the path to "silent"
|
||||
.br
|
||||
sounds = {
|
||||
.br
|
||||
error="__DATADIR__/sounds/Error.wav";
|
||||
.br
|
||||
self_log_in="__DATADIR__/sounds/LogIn.wav";
|
||||
.br
|
||||
self_log_out="__DATADIR__/sounds/LogOut.wav";
|
||||
.br
|
||||
user_log_in="__DATADIR__/sounds/ContactLogsIn.wav";
|
||||
.br
|
||||
user_log_out="__DATADIR__/sounds/ContactLogsOut.wav";
|
||||
.br
|
||||
call_incoming="__DATADIR__/sounds/IncomingCall.wav";
|
||||
.br
|
||||
call_outgoing="__DATADIR__/sounds/OutgoingCall.wav";
|
||||
.br
|
||||
generic_message="__DATADIR__/sounds/NewMessage.wav";
|
||||
.br
|
||||
transfer_pending="__DATADIR__/sounds/TransferPending.wav";
|
||||
.br
|
||||
transfer_completed="__DATADIR__/sounds/TransferComplete.wav";
|
||||
.br
|
||||
};
|
||||
.SH FILES
|
||||
.IP ~/.config/tox/toxic.conf
|
||||
Main configuration file.
|
||||
.IP __DATADIR__/toxic.conf.example
|
||||
Configuration example.
|
||||
.SH AUTHORS
|
||||
JFreegman <JFreegman@gmail.com>
|
||||
.SH SEE ALSO
|
||||
.BR toxic (1)
|
||||
.SH LINKS
|
||||
Project page on github: https://github.com/Tox/toxic
|
||||
.br
|
||||
IRC channel on Freenode: chat.freenode.net#tox
|
||||
.fi
|
||||
.if n \{\
|
||||
.RE
|
||||
.\}
|
||||
.SH "OPTIONS"
|
||||
.PP
|
||||
\fBui\fR
|
||||
.RS 4
|
||||
Configuration related to interface elements\&.
|
||||
.PP
|
||||
\fBtimestamps\fR
|
||||
.RS 4
|
||||
Enable or disable timestamps\&. true or false
|
||||
.RE
|
||||
.PP
|
||||
\fBalerts\fR
|
||||
.RS 4
|
||||
Enable or disable terminal alerts on events\&. true or false
|
||||
.RE
|
||||
.PP
|
||||
\fBnative_colors\fR
|
||||
.RS 4
|
||||
Select between native terminal colors and toxic color theme\&. true or false
|
||||
.RE
|
||||
.PP
|
||||
\fBautolog\fR
|
||||
.RS 4
|
||||
Enable or disable autologging\&. true or false
|
||||
.RE
|
||||
.PP
|
||||
\fBtime_format\fR
|
||||
.RS 4
|
||||
Select between 24 and 12 hour time\&. Specify 24 or 12
|
||||
.RE
|
||||
.PP
|
||||
\fBshow_typing_other\fR
|
||||
.RS 4
|
||||
Show when others are typing in a 1\-on\-1 chat\&. true or false
|
||||
.RE
|
||||
.PP
|
||||
\fBshow_typing_self\fR
|
||||
.RS 4
|
||||
Show others when you\(cqre typing in a 1\-on\-1 chat\&. true or false
|
||||
.RE
|
||||
.PP
|
||||
\fBhistory_size\fR
|
||||
.RS 4
|
||||
Maximum lines for chat window history\&. Integer value\&. (for example: 700)
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\fBaudio\fR
|
||||
.RS 4
|
||||
Configuration related to audio devices\&.
|
||||
.PP
|
||||
\fBinput_device\fR
|
||||
.RS 4
|
||||
Audio input device\&. Integer value\&. Number corresponds to
|
||||
/lsdev in
|
||||
.RE
|
||||
.PP
|
||||
\fBoutput_device\fR
|
||||
.RS 4
|
||||
Audio output device\&. Integer value\&. Number corresponds to
|
||||
/lsdev out
|
||||
.RE
|
||||
.PP
|
||||
\fBVAD_treshold\fR
|
||||
.RS 4
|
||||
Voice Activity Detection treshold\&. Float value\&. Recommended values are around 40\&.0
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\fBtox\fR
|
||||
.RS 4
|
||||
Configuration related to paths\&.
|
||||
.PP
|
||||
\fBdownload_path\fR
|
||||
.RS 4
|
||||
Default path for downloads\&. String value\&. Absolute path for downloaded files\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBchatlogs_path\fR
|
||||
.RS 4
|
||||
Default path for chatlogs\&. String value\&. Absolute path for chatlog files\&.
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\fBsounds\fR
|
||||
.RS 4
|
||||
Configuration related to notification sounds\&. Special value "silent" can be used to disable a specific notification\&.
|
||||
|
||||
Each value is a string which corresponds to the absolute path of a wav sound file\&.
|
||||
.PP
|
||||
\fBerror\fR
|
||||
.RS 4
|
||||
Sound to play when an error occurs\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBself_log_in\fR
|
||||
.RS 4
|
||||
Sound to play when you log in\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBself_log_out\fR
|
||||
.RS 4
|
||||
Sound to play when you log out\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBuser_log_in\fR
|
||||
.RS 4
|
||||
Sound to play when a contact become online\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBuser_log_out\fR
|
||||
.RS 4
|
||||
Sound to play when a contact become offline\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBcall_incoming\fR
|
||||
.RS 4
|
||||
Sound to play when you receive an incoming call\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBcall_outgoing\fR
|
||||
.RS 4
|
||||
Sound to play when you start a call\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBgeneric_message\fR
|
||||
.RS 4
|
||||
Sound to play when an event occurs\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBtransfer_pending\fR
|
||||
.RS 4
|
||||
Sound to play when you receive a file transfer request\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBtransfer_completed\fR
|
||||
.RS 4
|
||||
Sound to play when a file transfer is completed\&.
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\fBkeys\fR
|
||||
.RS 4
|
||||
Configuration related to user interface interaction\&. Currently supported: Ctrl modified keys, Tab, PAGEUP and PAGEDOWN\&.
|
||||
|
||||
Each value is a string which corresponds to a key combination\&.
|
||||
.PP
|
||||
\fBnext_tab\fR
|
||||
.RS 4
|
||||
Key combination to switch next tab\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBprev_tab\fR
|
||||
.RS 4
|
||||
Key combination to switch previous tab\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBscroll_line_up\fR
|
||||
.RS 4
|
||||
Key combination to scroll one line up\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBscroll_line_down\fR
|
||||
.RS 4
|
||||
Key combination to scroll one line down\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBhalf_page_up\fR
|
||||
.RS 4
|
||||
Key combination to scroll half page up\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBhalf_page_down\fR
|
||||
.RS 4
|
||||
Key combination to scroll half page down\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBpage_bottom\fR
|
||||
.RS 4
|
||||
Key combination to scroll to page bottom\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBpeer_list_up\fR
|
||||
.RS 4
|
||||
Key combination to scroll contacts list up\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBpeer_list_down\fR
|
||||
.RS 4
|
||||
Key combination to scroll contacts list down\&.
|
||||
.RE
|
||||
.RE
|
||||
.SH "FILES"
|
||||
.PP
|
||||
~/\&.config/tox/toxic\&.conf
|
||||
.RS 4
|
||||
Main configuration file\&.
|
||||
.RE
|
||||
.PP
|
||||
__DATADIR__/toxic\&.conf\&.example
|
||||
.RS 4
|
||||
Configuration example\&.
|
||||
.RE
|
||||
.SH "SEE ALSO"
|
||||
.sp
|
||||
\fBtoxic\fR(1)
|
||||
.SH "RESOURCES"
|
||||
.sp
|
||||
Project page: https://github\&.com/Tox/toxic
|
||||
.sp
|
||||
IRC channel: chat\&.freenode\&.net#tox
|
||||
.SH "AUTHORS"
|
||||
.sp
|
||||
JFreegman <JFreegman@gmail\&.com>
|
||||
|
182
doc/toxic.conf.5.asc
Normal file
182
doc/toxic.conf.5.asc
Normal file
@ -0,0 +1,182 @@
|
||||
toxic.conf(5)
|
||||
=============
|
||||
|
||||
NAME
|
||||
----
|
||||
toxic.conf - Configuration file for toxic
|
||||
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
~/.config/tox/toxic.conf
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
The 'toxic.conf' file is the main configuration file for *toxic*(1) client.
|
||||
It uses syntax accepted by *libconfig*.
|
||||
Lines starting with "//" are comments and will be ignored.
|
||||
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
----
|
||||
// Configuration for interface
|
||||
ui = {
|
||||
timestamps = true;
|
||||
alerts = false;
|
||||
};
|
||||
|
||||
// Configuration for audio
|
||||
audio = {
|
||||
input_device = 1;
|
||||
};
|
||||
----
|
||||
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
*ui*::
|
||||
Configuration related to interface elements.
|
||||
|
||||
*timestamps*;;
|
||||
Enable or disable timestamps. true or false
|
||||
|
||||
*alerts*;;
|
||||
Enable or disable terminal alerts on events. true or false
|
||||
|
||||
*native_colors*;;
|
||||
Select between native terminal colors and toxic color theme. true or false
|
||||
|
||||
*autolog*;;
|
||||
Enable or disable autologging. true or false
|
||||
|
||||
*time_format*;;
|
||||
Select between 24 and 12 hour time. Specify 24 or 12
|
||||
|
||||
*show_typing_other*;;
|
||||
Show when others are typing in a 1-on-1 chat. true or false
|
||||
|
||||
*show_typing_self*;;
|
||||
Show others when you're typing in a 1-on-1 chat. true or false
|
||||
|
||||
*history_size*;;
|
||||
Maximum lines for chat window history. Integer value. (for example: 700)
|
||||
|
||||
|
||||
*audio*::
|
||||
Configuration related to audio devices.
|
||||
|
||||
*input_device*;;
|
||||
Audio input device. Integer value. Number corresponds to `/lsdev in`
|
||||
|
||||
*output_device*;;
|
||||
Audio output device. Integer value. Number corresponds to `/lsdev out`
|
||||
|
||||
*VAD_treshold*;;
|
||||
Voice Activity Detection treshold. Float value. Recommended values are
|
||||
around 40.0
|
||||
|
||||
*tox*::
|
||||
Configuration related to paths.
|
||||
|
||||
*download_path*;;
|
||||
Default path for downloads. String value. Absolute path for downloaded
|
||||
files.
|
||||
|
||||
*chatlogs_path*;;
|
||||
Default path for chatlogs. String value. Absolute path for chatlog files.
|
||||
|
||||
*sounds*::
|
||||
Configuration related to notification sounds.
|
||||
Special value "silent" can be used to disable a specific notification. +
|
||||
Each value is a string which corresponds to the absolute path of a wav
|
||||
sound file.
|
||||
|
||||
*error*;;
|
||||
Sound to play when an error occurs.
|
||||
|
||||
*self_log_in*;;
|
||||
Sound to play when you log in.
|
||||
|
||||
*self_log_out*;;
|
||||
Sound to play when you log out.
|
||||
|
||||
*user_log_in*;;
|
||||
Sound to play when a contact become online.
|
||||
|
||||
*user_log_out*;;
|
||||
Sound to play when a contact become offline.
|
||||
|
||||
*call_incoming*;;
|
||||
Sound to play when you receive an incoming call.
|
||||
|
||||
*call_outgoing*;;
|
||||
Sound to play when you start a call.
|
||||
|
||||
*generic_message*;;
|
||||
Sound to play when an event occurs.
|
||||
|
||||
*transfer_pending*;;
|
||||
Sound to play when you receive a file transfer request.
|
||||
|
||||
*transfer_completed*;;
|
||||
Sound to play when a file transfer is completed.
|
||||
|
||||
*keys*::
|
||||
Configuration related to user interface interaction.
|
||||
Currently supported: Ctrl modified keys, Tab, PAGEUP and PAGEDOWN. +
|
||||
Each value is a string which corresponds to a key combination.
|
||||
|
||||
*next_tab*;;
|
||||
Key combination to switch next tab.
|
||||
|
||||
*prev_tab*;;
|
||||
Key combination to switch previous tab.
|
||||
|
||||
*scroll_line_up*;;
|
||||
Key combination to scroll one line up.
|
||||
|
||||
*scroll_line_down*;;
|
||||
Key combination to scroll one line down.
|
||||
|
||||
*half_page_up*;;
|
||||
Key combination to scroll half page up.
|
||||
|
||||
*half_page_down*;;
|
||||
Key combination to scroll half page down.
|
||||
|
||||
*page_bottom*;;
|
||||
Key combination to scroll to page bottom.
|
||||
|
||||
*peer_list_up*;;
|
||||
Key combination to scroll contacts list up.
|
||||
|
||||
*peer_list_down*;;
|
||||
Key combination to scroll contacts list down.
|
||||
|
||||
|
||||
FILES
|
||||
-----
|
||||
~/.config/tox/toxic.conf::
|
||||
Main configuration file.
|
||||
|
||||
{datadir}/toxic.conf.example::
|
||||
Configuration example.
|
||||
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
*toxic*(1)
|
||||
|
||||
|
||||
RESOURCES
|
||||
---------
|
||||
Project page: <https://github.com/Tox/toxic>
|
||||
|
||||
IRC channel: chat.freenode.net#tox
|
||||
|
||||
|
||||
AUTHORS
|
||||
-------
|
||||
JFreegman <JFreegman@gmail.com>
|
@ -1,8 +1,10 @@
|
||||
192.254.75.98 33445 951C88B7E75C867418ACDB5D273821372BB5BD652740BCDF623A4FA293E75D2F
|
||||
37.187.46.132 33445 A9D98212B3F972BD11DA52BEB0658C326FCCC1BFD49F347F9C2D3D8B61E1B927
|
||||
144.76.60.215 33445 04119E835DF3E78BACF0F84235B300546AF8B936F035185E2A8E9E0A67C8924F
|
||||
23.226.230.47 33445 A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074
|
||||
37.187.20.216 33445 4FD54CFD426A338399767E56FD0F44F5E35FA8C38C8E87C8DC3FEAC0160F8E17
|
||||
23.226.230.47 33445 A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074
|
||||
54.199.139.199 33445 7F9C31FE850E97CEFD4C4591DF93FC757C7C12549DDD55F8EEAECC34FE76C029
|
||||
109.169.46.133 33445 7F31BFC93B8E4016A902144D0B110C3EA97CB7D43F1C4D21BCAE998A7C838821
|
||||
192.210.149.121 33445 F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67
|
||||
192.210.149.121 33445 F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67
|
||||
37.59.102.176 33445 B98A2CEAA6C6A2FADC2C3632D284318B60FE5375CCB41EFA081AB67F500C1B0B
|
||||
95.85.13.245 33445 7187969BB10B54C98538BAE94C069CE5C84E650D54F7E596543D8FB1ECF4CF23
|
||||
178.21.112.187 33445 4B2C19E924972CB9B57732FB172F8A8604DE13EEDA2A6234E348983344B23057
|
||||
76.191.23.96 33445 4BA57660DE3E854C530EED601BF8D54B7EFAE960523B6CFC10210CC08E2CB808
|
||||
|
2
misc/DNSservers
Normal file
2
misc/DNSservers
Normal file
@ -0,0 +1,2 @@
|
||||
utox.org d3154f65d28a5b41a05d4ac7e4b39c6b1c233cc857fb365c56e8392737462a12
|
||||
toxme.se 5d72c517df6aec54f1e977a6b6f25914ea4cf7277a85027cd9f5196df17e0b13
|
@ -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;
|
||||
};
|
||||
@ -33,8 +39,11 @@ audio = {
|
||||
};
|
||||
|
||||
tox = {
|
||||
// where to store received files
|
||||
// Path for downloaded files
|
||||
// download_path="/home/USERNAME/Downloads/";
|
||||
|
||||
// Path for chatlogs
|
||||
// chatlogs_path="/home/USERNAME/toxic_chatlogs/";
|
||||
};
|
||||
|
||||
// To disable a sound set the path to "silent"
|
||||
@ -50,3 +59,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.
BIN
sounds/Error.wav
BIN
sounds/Error.wav
Binary file not shown.
Binary file not shown.
BIN
sounds/LogIn.wav
BIN
sounds/LogIn.wav
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
176
src/audio_call.c
176
src/audio_call.c
@ -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);
|
||||
|
||||
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);
|
||||
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,
|
||||
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])
|
||||
{
|
||||
char msg[MAX_STR_SIZE];
|
||||
char *error_str;
|
||||
void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
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])
|
||||
{
|
||||
char msg[MAX_STR_SIZE];
|
||||
char *error_str;
|
||||
void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
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!";
|
||||
|
@ -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 (b_path[0] == '~')
|
||||
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);
|
||||
}
|
||||
|
@ -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
|
||||
*/
|
||||
if only one match, auto-complete line.
|
||||
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 */
|
395
src/chat.c
395
src/chat.c
@ -52,7 +52,7 @@
|
||||
extern char *DATA_FILE;
|
||||
|
||||
extern FileSender file_senders[MAX_FILES];
|
||||
extern ToxicFriend friends[MAX_FRIENDS_NUM];
|
||||
extern _Friends Friends;
|
||||
|
||||
extern struct _Winthread Winthread;
|
||||
extern struct user_settings *user_settings_;
|
||||
@ -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);
|
||||
@ -121,11 +124,14 @@ static void chat_set_window_name(ToxWindow *self, char *nick, int len)
|
||||
snprintf(self->name, sizeof(self->name), "%s", nick);
|
||||
}
|
||||
|
||||
void kill_chat_window(ToxWindow *self)
|
||||
static void close_all_file_receivers(Tox *m, int friendnum);
|
||||
|
||||
void kill_chat_window(ToxWindow *self, Tox *m)
|
||||
{
|
||||
ChatContext *ctx = self->chatwin;
|
||||
StatusBar *statusbar = self->stb;
|
||||
|
||||
close_all_file_receivers(m, self->num);
|
||||
log_disable(ctx->log);
|
||||
line_info_cleanup(ctx->hst);
|
||||
|
||||
@ -160,27 +166,55 @@ 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_resume_file_transfers(Tox *m, int fnum);
|
||||
static void chat_stop_file_senders(int fnum);
|
||||
|
||||
static void chat_onConnectionChange(ToxWindow *self, Tox *m, int32_t num, uint8_t status)
|
||||
{
|
||||
if (self->num != num)
|
||||
return;
|
||||
|
||||
StatusBar *statusbar = self->stb;
|
||||
ChatContext *ctx = self->chatwin;
|
||||
const char *msg;
|
||||
|
||||
if (status == 1) { /* Friend shows online */
|
||||
char timefrmt[TIME_STR_SIZE];
|
||||
get_time_str(timefrmt, sizeof(timefrmt));
|
||||
|
||||
char nick[TOX_MAX_NAME_LENGTH];
|
||||
get_nick_truncate(m, nick, num);
|
||||
|
||||
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.list[num].is_typing = user_settings_->show_typing_other == SHOW_TYPING_ON
|
||||
? tox_get_is_typing(m, num) : 0;
|
||||
chat_resume_file_transfers(m, num);
|
||||
|
||||
msg = "has come online";
|
||||
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg);
|
||||
write_to_log(msg, nick, ctx->log, true);
|
||||
} else { /* Friend goes offline */
|
||||
statusbar->is_online = false;
|
||||
friends[num].is_typing = 0;
|
||||
notify(self, user_log_out, NT_NOFOCUS);
|
||||
Friends.list[num].is_typing = 0;
|
||||
|
||||
if (self->chatwin->self_is_typing)
|
||||
set_self_typingstatus(self, m, 0);
|
||||
|
||||
chat_stop_file_senders(num);
|
||||
|
||||
msg = "has gone offline";
|
||||
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, RED, msg);
|
||||
write_to_log(msg, nick, ctx->log, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,7 +223,7 @@ static void chat_onTypingChange(ToxWindow *self, Tox *m, int32_t num, uint8_t is
|
||||
if (self->num != num)
|
||||
return;
|
||||
|
||||
friends[num].is_typing = is_typing;
|
||||
Friends.list[num].is_typing = is_typing;
|
||||
}
|
||||
|
||||
static void chat_onAction(ToxWindow *self, Tox *m, int32_t num, const char *action, uint16_t len)
|
||||
@ -205,9 +239,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_1 | NT_NOFOCUS, self->active_box, "* %s %s", nick, action );
|
||||
else
|
||||
box_notify(self, generic_message, NT_WNDALERT_1 | 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 +293,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};
|
||||
@ -264,15 +301,15 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t
|
||||
/* holds the lone filename */
|
||||
char filename_nopath[MAX_STR_SIZE];
|
||||
get_file_name(filename_nopath, sizeof(filename_nopath), pathname);
|
||||
char sizestr[32];
|
||||
bytes_convert_str(sizestr, sizeof(sizestr), filesize);
|
||||
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' (%s)",
|
||||
filename_nopath, sizestr);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -282,9 +319,9 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t
|
||||
len += strlen(user_settings_->download_path);
|
||||
}
|
||||
|
||||
if (len >= sizeof(friends[num].file_receiver.filenames[filenum])) {
|
||||
if (len >= sizeof(Friends.list[num].file_receiver[filenum].filename)) {
|
||||
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 +352,79 @@ 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);
|
||||
Friends.list[num].file_receiver[filenum].pending = true;
|
||||
Friends.list[num].file_receiver[filenum].size = filesize;
|
||||
Friends.list[num].file_receiver[filenum].filenum = filenum;
|
||||
strcpy(Friends.list[num].file_receiver[filenum].filename, filename);
|
||||
|
||||
notify(self, transfer_pending, NT_WNDALERT_2 | NT_NOFOCUS);
|
||||
if (self->active_box != -1)
|
||||
box_notify2(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS, self->active_box,
|
||||
"Incoming file: %s", filename );
|
||||
else
|
||||
box_notify(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS, &self->active_box, self->name,
|
||||
"Incoming file: %s", filename );
|
||||
}
|
||||
|
||||
static void chat_close_file_receiver(int32_t num, uint8_t filenum)
|
||||
/* Stops active file senders for this friend. Call when a friend goes offline */
|
||||
static void chat_stop_file_senders(int fnum)
|
||||
{
|
||||
FILE *file = friends[num].file_receiver.files[filenum];
|
||||
int i;
|
||||
|
||||
if (file != NULL) {
|
||||
for (i = 0; i < MAX_FILES; ++i) {
|
||||
if (file_senders[i].active && file_senders[i].friendnum == fnum)
|
||||
file_senders[i].noconnection = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Tries to resume broken file transfers. Call when a friend comes online */
|
||||
static void chat_resume_file_transfers(Tox *m, int fnum)
|
||||
{
|
||||
if (Friends.list[fnum].active_file_receivers == 0)
|
||||
return;
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_FILES; ++i) {
|
||||
if (Friends.list[fnum].file_receiver[i].active) {
|
||||
uint8_t bytes_recv[sizeof(uint64_t)];
|
||||
memcpy(bytes_recv, &Friends.list[fnum].file_receiver[i].bytes_recv, sizeof(uint64_t));
|
||||
net_to_host(bytes_recv, sizeof(uint64_t));
|
||||
int filenum = Friends.list[fnum].file_receiver[i].filenum;
|
||||
tox_file_send_control(m, fnum, 1, filenum, TOX_FILECONTROL_RESUME_BROKEN, bytes_recv, sizeof(uint64_t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
if (CTRL > 0)
|
||||
tox_file_send_control(m, friendnum, 1, filenum, CTRL, 0, 0);
|
||||
|
||||
FILE *file = Friends.list[friendnum].file_receiver[filenum].file;
|
||||
|
||||
if (file != NULL)
|
||||
fclose(file);
|
||||
friends[num].file_receiver.files[filenum] = NULL;
|
||||
|
||||
memset(&Friends.list[friendnum].file_receiver[filenum], 0, sizeof(struct FileReceiver));
|
||||
--Friends.list[friendnum].active_file_receivers;
|
||||
}
|
||||
|
||||
static void close_all_file_receivers(Tox *m, int friendnum)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_FILES; ++i) {
|
||||
if (Friends.list[friendnum].file_receiver[i].active)
|
||||
chat_close_file_receiver(m, i, friendnum, TOX_FILECONTROL_KILL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -348,25 +436,40 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, int32_t num, uint8_t rec
|
||||
|
||||
const char *filename;
|
||||
char msg[MAX_STR_SIZE] = {0};
|
||||
int i = 0; /* file_sender index */
|
||||
int send_idx = 0; /* file sender index */
|
||||
|
||||
if (receive_send == 0) {
|
||||
filename = friends[num].file_receiver.filenames[filenum];
|
||||
if (!Friends.list[num].file_receiver[filenum].active)
|
||||
return;
|
||||
|
||||
filename = Friends.list[num].file_receiver[filenum].filename;
|
||||
} else {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_FILES; ++i) {
|
||||
if (file_senders[i].filenum == filenum)
|
||||
send_idx = i;
|
||||
|
||||
if (file_senders[i].active && file_senders[i].filenum == filenum)
|
||||
break;
|
||||
}
|
||||
|
||||
filename = file_senders[i].pathname;
|
||||
if (!file_senders[send_idx].active)
|
||||
return;
|
||||
|
||||
filename = file_senders[send_idx].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[send_idx].line_id = self->chatwin->hst->line_end->id + 2;
|
||||
sound_notify(self, silent, NT_NOFOCUS | NT_BEEP | NT_WNDALERT_2, NULL);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -374,23 +477,61 @@ 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, send_idx, NULL, -1, filenum, num);
|
||||
|
||||
notify(self, error, NT_NOFOCUS | NT_WNDALERT_2);
|
||||
break;
|
||||
|
||||
case TOX_FILECONTROL_FINISHED:
|
||||
if (receive_send == 0) {
|
||||
print_progress_bar(self, filenum, num, 100.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 {
|
||||
snprintf(msg, sizeof(msg), "File '%s' successfuly sent.", filename);
|
||||
close_file_sender(self, m, send_idx, NULL, TOX_FILECONTROL_FINISHED, filenum, num);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
case TOX_FILECONTROL_RESUME_BROKEN:
|
||||
if (receive_send == 0)
|
||||
break;
|
||||
|
||||
FILE *fp = file_senders[send_idx].file;
|
||||
|
||||
if (fp == NULL)
|
||||
break;
|
||||
|
||||
uint8_t tmp[sizeof(uint64_t)];
|
||||
memcpy(tmp, &data, sizeof(uint64_t));
|
||||
net_to_host(tmp, sizeof(uint64_t));
|
||||
uint64_t datapos;
|
||||
memcpy(&datapos, tmp, sizeof(uint64_t));
|
||||
|
||||
fseek(fp, datapos, SEEK_SET);
|
||||
tox_file_send_control(m, num, 0, filenum, TOX_FILECONTROL_ACCEPT, 0, 0);
|
||||
file_senders[send_idx].noconnection = false;
|
||||
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,
|
||||
@ -399,30 +540,17 @@ static void chat_onFileData(ToxWindow *self, Tox *m, int32_t num, uint8_t filenu
|
||||
if (self->num != num)
|
||||
return;
|
||||
|
||||
FILE *fp = friends[num].file_receiver.files[filenum];
|
||||
FILE *fp = Friends.list[num].file_receiver[filenum].file;
|
||||
|
||||
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);
|
||||
uint64_t curtime = get_unix_time();
|
||||
|
||||
/* refresh line with percentage complete */
|
||||
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);
|
||||
}
|
||||
Friends.list[num].file_receiver[filenum].bps += length;
|
||||
Friends.list[num].file_receiver[filenum].bytes_recv += length;
|
||||
}
|
||||
|
||||
static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, const char *group_pub_key)
|
||||
@ -430,21 +558,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;
|
||||
memcpy(Friends.list[friendnumber].groupchat_key, group_pub_key,
|
||||
sizeof(Friends.list[friendnumber].groupchat_key));
|
||||
Friends.list[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 +588,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 +605,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 +620,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 +634,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 +647,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 +661,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 +675,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 +688,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 +702,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 +715,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 +729,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 +752,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 +832,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 +861,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 +874,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 +887,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') {
|
||||
@ -782,7 +903,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
|
||||
if (line[0] == '/') {
|
||||
if (strcmp(line, "/close") == 0) {
|
||||
kill_chat_window(self);
|
||||
kill_chat_window(self, m);
|
||||
return;
|
||||
} else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
|
||||
send_action(self, ctx, m, line + strlen("/me "));
|
||||
@ -797,10 +918,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 +933,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,20 +980,20 @@ 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)
|
||||
if (Friends.list[self->num].is_typing)
|
||||
wattron(statusbar->topline, COLOR_PAIR(YELLOW));
|
||||
|
||||
wattron(statusbar->topline, A_BOLD);
|
||||
wprintw(statusbar->topline, " %s ", statusbar->nick);
|
||||
wattroff(statusbar->topline, A_BOLD);
|
||||
|
||||
if (friends[self->num].is_typing)
|
||||
if (Friends.list[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);
|
||||
@ -893,10 +1014,11 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
|
||||
self->x = x2;
|
||||
|
||||
/* Truncate note if it doesn't fit in statusbar */
|
||||
uint16_t maxlen = x2 - getcurx(statusbar->topline) - (KEY_IDENT_DIGITS * 2) - 7;
|
||||
uint16_t maxlen = x2 - getcurx(statusbar->topline) - (KEY_IDENT_DIGITS * 2) - 6;
|
||||
|
||||
if (statusbar->statusmsg_len > maxlen) {
|
||||
statusbar->statusmsg[maxlen] = '\0';
|
||||
statusbar->statusmsg[maxlen - 3] = '\0';
|
||||
strcat(statusbar->statusmsg, "...");
|
||||
statusbar->statusmsg_len = maxlen;
|
||||
}
|
||||
|
||||
@ -910,7 +1032,7 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < KEY_IDENT_DIGITS; ++i)
|
||||
wprintw(statusbar->topline, "%02X", friends[self->num].pub_key[i] & 0xff);
|
||||
wprintw(statusbar->topline, "%02X", Friends.list[self->num].pub_key[i] & 0xff);
|
||||
|
||||
wprintw(statusbar->topline, "}\n");
|
||||
|
||||
@ -974,8 +1096,8 @@ static void chat_onInit(ToxWindow *self, Tox *m)
|
||||
|
||||
line_info_init(ctx->hst);
|
||||
|
||||
if (friends[self->num].logging_on)
|
||||
log_enable(nick, friends[self->num].pub_key, ctx->log);
|
||||
if (Friends.list[self->num].logging_on)
|
||||
log_enable(nick, Friends.list[self->num].pub_key, ctx->log);
|
||||
|
||||
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
|
||||
|
||||
@ -1021,11 +1143,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);
|
||||
|
@ -26,7 +26,10 @@
|
||||
#include "windows.h"
|
||||
#include "toxic.h"
|
||||
|
||||
void kill_chat_window(ToxWindow *self);
|
||||
/* 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, Tox *m);
|
||||
ToxWindow new_chat(Tox *m, int32_t friendnum);
|
||||
|
||||
#endif /* end of include guard: CHAT_H_6489PZ13 */
|
||||
|
@ -30,72 +30,115 @@
|
||||
#include "execute.h"
|
||||
#include "line_info.h"
|
||||
#include "groupchat.h"
|
||||
#include "chat.h"
|
||||
#include "file_senders.h"
|
||||
|
||||
extern ToxWindow *prompt;
|
||||
|
||||
extern ToxicFriend friends[MAX_FRIENDS_NUM];
|
||||
extern _Friends Friends;
|
||||
|
||||
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.list[self->num].file_receiver[filenum].active) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
|
||||
return;
|
||||
}
|
||||
|
||||
const char *filepath = Friends.list[self->num].file_receiver[filenum].filename;
|
||||
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.list[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);
|
||||
if (!Friends.list[self->num].groupchat_pending) {
|
||||
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 +146,81 @@ 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);
|
||||
if (!Friends.list[self->num].file_receiver[filenum].pending) {
|
||||
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.list[self->num].file_receiver[filenum].filename;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
/* 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.list[self->num].file_receiver[filenum].line_id = self->chatwin->hst->line_end->id + 2;
|
||||
|
||||
if ((Friends.list[self->num].file_receiver[filenum].file = fopen(filename, "a")) == NULL) {
|
||||
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 {
|
||||
Friends.list[self->num].file_receiver[filenum].active = true;
|
||||
++Friends.list[self->num].active_file_receivers;
|
||||
}
|
||||
} 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.list[self->num].file_receiver[filenum].pending = false;
|
||||
}
|
||||
|
||||
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 +228,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 +242,7 @@ 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);
|
||||
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,13 +253,17 @@ 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);
|
||||
char sizestr[32];
|
||||
bytes_convert_str(sizestr, sizeof(sizestr), filesize);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
|
||||
"Sending file [%d]: '%s' (%s)", filenum, filename, sizestr);
|
||||
|
||||
++num_active_file_senders;
|
||||
|
||||
if (i == max_file_senders_index)
|
||||
++max_file_senders_index;
|
||||
|
||||
reset_file_sender_queue();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -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]);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
33
src/device.c
33
src/device.c
@ -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,19 +199,21 @@ 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);
|
||||
|
||||
uint32_t i;
|
||||
@ -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,12 +447,9 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
176
src/dns.c
176
src/dns.c
@ -22,6 +22,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h> /* for u_char */
|
||||
#include <netinet/in.h>
|
||||
#include <resolv.h>
|
||||
|
||||
@ -39,19 +40,23 @@
|
||||
#include "dns.h"
|
||||
#include "global_commands.h"
|
||||
#include "misc_tools.h"
|
||||
#include "configdir.h"
|
||||
|
||||
#define MAX_DNS_REQST_SIZE 256
|
||||
#define NUM_DNS3_SERVERS 2 /* must correspond to number of items in dns3_servers array */
|
||||
#define DNS3_KEY_SIZE 32
|
||||
#define MAX_DNS_REQST_SIZE 255
|
||||
#define TOX_DNS3_TXT_PREFIX "v=tox3;id="
|
||||
#define DNS3_KEY_SZ 32
|
||||
|
||||
extern struct _Winthread Winthread;
|
||||
extern struct _dns3_servers dns3_servers;
|
||||
extern struct arg_opts arg_opts;
|
||||
|
||||
/* TODO: process keys from key file instead of hard-coding like a noob */
|
||||
static struct dns3_server {
|
||||
char *name;
|
||||
char key[DNS3_KEY_SZ];
|
||||
} dns3_servers[] = {
|
||||
#define NUM_DNS3_BACKUP_SERVERS 2
|
||||
|
||||
/* Hardcoded backup in case domain list is not loaded */
|
||||
static struct dns3_server_backup {
|
||||
const char *name;
|
||||
char key[DNS3_KEY_SIZE];
|
||||
} dns3_servers_backup[] = {
|
||||
{
|
||||
"utox.org",
|
||||
{
|
||||
@ -83,13 +88,65 @@ static struct _dns_thread {
|
||||
} dns_thread;
|
||||
|
||||
|
||||
static int dns_error(ToxWindow *self, char *errmsg)
|
||||
{
|
||||
char msg[MAX_STR_SIZE];
|
||||
snprintf(msg, sizeof(msg), "User lookup failed: %s", errmsg);
|
||||
#define MAX_DNS_SERVERS 50
|
||||
#define MAX_DOMAIN_SIZE 32
|
||||
#define MAX_DNS_LINE MAX_DOMAIN_SIZE + (DNS3_KEY_SIZE * 2) + 3
|
||||
|
||||
struct _dns3_servers {
|
||||
bool loaded;
|
||||
int lines;
|
||||
char names[MAX_DNS_SERVERS][MAX_DOMAIN_SIZE];
|
||||
char keys[MAX_DNS_SERVERS][DNS3_KEY_SIZE];
|
||||
} dns3_servers;
|
||||
|
||||
static int load_dns_domainlist(const char *path)
|
||||
{
|
||||
FILE *fp = fopen(path, "r");
|
||||
|
||||
if (fp == NULL)
|
||||
return -1;
|
||||
|
||||
char line[MAX_DNS_LINE];
|
||||
|
||||
while (fgets(line, sizeof(line), fp) && dns3_servers.lines < MAX_DNS_SERVERS) {
|
||||
int linelen = strlen(line);
|
||||
|
||||
if (linelen < DNS3_KEY_SIZE * 2 + 5)
|
||||
continue;
|
||||
|
||||
if (line[linelen - 1] == '\n')
|
||||
line[--linelen] = '\0';
|
||||
|
||||
const char *name = strtok(line, " ");
|
||||
const char *keystr = strtok(NULL, " ");
|
||||
|
||||
if (name == NULL || keystr == NULL)
|
||||
continue;
|
||||
|
||||
if (strlen(keystr) != DNS3_KEY_SIZE * 2)
|
||||
continue;
|
||||
|
||||
snprintf(dns3_servers.names[dns3_servers.lines], sizeof(dns3_servers.names[dns3_servers.lines]), "%s", name);
|
||||
int res = hex_string_to_bytes(dns3_servers.keys[dns3_servers.lines], DNS3_KEY_SIZE, keystr);
|
||||
|
||||
if (res == -1)
|
||||
continue;
|
||||
|
||||
++dns3_servers.lines;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if (dns3_servers.lines < 1)
|
||||
return -2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dns_error(ToxWindow *self, const char *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;
|
||||
@ -163,6 +220,9 @@ static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, char
|
||||
if (!size || txt_len >= size || !txt_len)
|
||||
return dns_error(self, "No record found.");
|
||||
|
||||
if (txt_len > MAX_DNS_REQST_SIZE)
|
||||
return dns_error(self, "Invalid DNS response.");
|
||||
|
||||
ans_pt++;
|
||||
ans_pt[txt_len] = '\0';
|
||||
memcpy(buf, ans_pt, txt_len + 1);
|
||||
@ -174,7 +234,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;
|
||||
@ -193,35 +253,61 @@ static int parse_addr(char *addr, char *namebuf, char *dombuf)
|
||||
return strlen(namebuf);
|
||||
}
|
||||
|
||||
/* matches input domain name with domains in list and obtains key. Return 0 on success, -1 on failure */
|
||||
static int get_domain_match(char *pubkey, char *domain, const char *inputdomain)
|
||||
{
|
||||
/* check server list first */
|
||||
int i;
|
||||
bool match = false;
|
||||
|
||||
for (i = 0; i < dns3_servers.lines; ++i) {
|
||||
if (strcmp(dns3_servers.names[i], inputdomain) == 0) {
|
||||
memcpy(pubkey, dns3_servers.keys[i], DNS3_KEY_SIZE);
|
||||
snprintf(domain, MAX_DOMAIN_SIZE, "%s", dns3_servers.names[i]);
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* fall back to hard-coded domains on server list failure */
|
||||
if (!match) {
|
||||
for (i = 0; i < NUM_DNS3_BACKUP_SERVERS; ++i) {
|
||||
if (strcmp(dns3_servers_backup[i].name, inputdomain) == 0) {
|
||||
memcpy(pubkey, dns3_servers_backup[i].key, DNS3_KEY_SIZE);
|
||||
snprintf(domain, MAX_DOMAIN_SIZE, "%s", dns3_servers_backup[i].name);
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!match)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Does DNS lookup for addr and puts resulting tox id in id_bin. */
|
||||
void *dns3_lookup_thread(void *data)
|
||||
{
|
||||
ToxWindow *self = t_data.self;
|
||||
|
||||
char domain[MAX_STR_SIZE];
|
||||
char inputdomain[MAX_STR_SIZE];
|
||||
char name[MAX_STR_SIZE];
|
||||
|
||||
int namelen = parse_addr(t_data.addr, name, domain);
|
||||
int namelen = parse_addr(t_data.addr, name, inputdomain);
|
||||
|
||||
if (namelen == -1) {
|
||||
dns_error(self, "Must be a Tox ID or an address in the form username@domain");
|
||||
kill_dns_thread(NULL);
|
||||
}
|
||||
|
||||
/* get domain name/pub key */
|
||||
char *DNS_pubkey = NULL;
|
||||
char *domname = NULL;
|
||||
int i;
|
||||
char DNS_pubkey[DNS3_KEY_SIZE];
|
||||
char domain[MAX_DOMAIN_SIZE];
|
||||
|
||||
for (i = 0; i < NUM_DNS3_SERVERS; ++i) {
|
||||
if (strcmp(dns3_servers[i].name, domain) == 0) {
|
||||
DNS_pubkey = dns3_servers[i].key;
|
||||
domname = dns3_servers[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int match = get_domain_match(DNS_pubkey, domain, inputdomain);
|
||||
|
||||
if (domname == NULL) {
|
||||
if (match == -1) {
|
||||
dns_error(self, "Domain not found.");
|
||||
kill_dns_thread(NULL);
|
||||
}
|
||||
@ -233,7 +319,7 @@ void *dns3_lookup_thread(void *data)
|
||||
kill_dns_thread(NULL);
|
||||
}
|
||||
|
||||
char string[MAX_DNS_REQST_SIZE];
|
||||
char string[MAX_DNS_REQST_SIZE + 1];
|
||||
uint32_t request_id;
|
||||
|
||||
int str_len = tox_generate_dns3_string(dns_obj, (uint8_t *) string, sizeof(string), &request_id,
|
||||
@ -247,10 +333,10 @@ void *dns3_lookup_thread(void *data)
|
||||
string[str_len] = '\0';
|
||||
|
||||
u_char answer[PACKETSZ];
|
||||
char d_string[MAX_DNS_REQST_SIZE];
|
||||
char d_string[MAX_DOMAIN_SIZE + MAX_DNS_REQST_SIZE + 10];
|
||||
|
||||
/* format string and create dns query */
|
||||
snprintf(d_string, sizeof(d_string), "_%s._tox.%s", string, domname);
|
||||
snprintf(d_string, sizeof(d_string), "_%s._tox.%s", string, domain);
|
||||
int ans_len = res_query(d_string, C_IN, T_TXT, answer, sizeof(answer));
|
||||
|
||||
if (ans_len <= 0) {
|
||||
@ -258,13 +344,13 @@ void *dns3_lookup_thread(void *data)
|
||||
kill_dns_thread(dns_obj);
|
||||
}
|
||||
|
||||
char ans_id[MAX_DNS_REQST_SIZE];
|
||||
char ans_id[MAX_DNS_REQST_SIZE + 1];
|
||||
|
||||
/* extract TXT from DNS response */
|
||||
if (parse_dns_response(self, answer, ans_len, ans_id) == -1)
|
||||
kill_dns_thread(dns_obj);
|
||||
|
||||
char encrypted_id[MAX_DNS_REQST_SIZE];
|
||||
char encrypted_id[MAX_DNS_REQST_SIZE + 1];
|
||||
int prfx_len = strlen(TOX_DNS3_TXT_PREFIX);
|
||||
|
||||
/* extract the encrypted ID from TXT response */
|
||||
@ -290,14 +376,30 @@ 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);
|
||||
if (arg_opts.use_proxy && arg_opts.force_tcp) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "DNS lookups are disabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (t_data.busy) {
|
||||
const char *err = "Please wait for previous user lookup to finish.";
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dns3_servers.loaded) {
|
||||
const char *path = arg_opts.dns_path[0] ? arg_opts.dns_path : PACKAGE_DATADIR "/DNSservers";
|
||||
dns3_servers.loaded = true;
|
||||
int ret = load_dns_domainlist(path);
|
||||
|
||||
if (ret < 0) {
|
||||
const char *errmsg = "DNS server list failed to load with error code %d. Falling back to hard-coded list.";
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg, ret);
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(t_data.id_bin, sizeof(t_data.id_bin), "%s", id_bin);
|
||||
snprintf(t_data.addr, sizeof(t_data.addr), "%s", addr);
|
||||
snprintf(t_data.msg, sizeof(t_data.msg), "%s", msg);
|
||||
|
@ -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 */
|
||||
|
@ -43,6 +43,7 @@ static struct cmd_func global_commands[] = {
|
||||
{ "/add", cmd_add },
|
||||
{ "/clear", cmd_clear },
|
||||
{ "/connect", cmd_connect },
|
||||
{ "/decline", cmd_decline },
|
||||
{ "/exit", cmd_quit },
|
||||
{ "/groupchat", cmd_groupchat },
|
||||
{ "/help", cmd_prompt_help },
|
||||
@ -52,6 +53,7 @@ static struct cmd_func global_commands[] = {
|
||||
{ "/note", cmd_note },
|
||||
{ "/q", cmd_quit },
|
||||
{ "/quit", cmd_quit },
|
||||
{ "/requests", cmd_requests },
|
||||
{ "/status", cmd_status },
|
||||
|
||||
#ifdef _AUDIO
|
||||
@ -61,6 +63,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 +71,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 +102,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 +116,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 +170,5 @@ 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);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid command.");
|
||||
}
|
||||
|
@ -29,11 +29,11 @@
|
||||
#define MAX_NUM_ARGS 4 /* Includes command */
|
||||
|
||||
#ifdef _AUDIO
|
||||
#define GLOBAL_NUM_COMMANDS 16
|
||||
#define GLOBAL_NUM_COMMANDS 18
|
||||
#define CHAT_NUM_COMMANDS 12
|
||||
#else
|
||||
#define GLOBAL_NUM_COMMANDS 14
|
||||
#define CHAT_NUM_COMMANDS 4
|
||||
#define GLOBAL_NUM_COMMANDS 16
|
||||
#define CHAT_NUM_COMMANDS 5
|
||||
#endif /* _AUDIO */
|
||||
|
||||
enum {
|
||||
|
@ -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,117 @@
|
||||
|
||||
FileSender file_senders[MAX_FILES];
|
||||
uint8_t max_file_senders_index;
|
||||
uint8_t num_active_file_senders;
|
||||
extern _Friends Friends;
|
||||
|
||||
/* 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.list[friendnum].file_receiver[idx].bps;
|
||||
line_id = Friends.list[friendnum].file_receiver[idx].line_id;
|
||||
}
|
||||
|
||||
char msg[MAX_STR_SIZE];
|
||||
bytes_convert_str(msg, sizeof(msg), bps);
|
||||
strcat(msg, "/s [");
|
||||
|
||||
int n = pct_done / (100 / NUM_PROG_MARKS);
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < n; ++i)
|
||||
strcat(msg, "#");
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* refreshes active file receiver status bars */
|
||||
static void refresh_recv_prog(Tox *m)
|
||||
{
|
||||
int i;
|
||||
uint64_t curtime = get_unix_time();
|
||||
|
||||
for (i = 2; i < MAX_WINDOWS_NUM; ++i) {
|
||||
ToxWindow *toxwin = get_window_ptr(i);
|
||||
|
||||
if (toxwin == NULL || !toxwin->is_chat)
|
||||
continue;
|
||||
|
||||
int fnum = toxwin->num;
|
||||
int j;
|
||||
|
||||
for (j = 0; j < MAX_FILES; ++j) {
|
||||
if (!Friends.list[fnum].file_receiver[j].active)
|
||||
continue;
|
||||
|
||||
int filenum = Friends.list[fnum].file_receiver[j].filenum;
|
||||
double remain = (double) tox_file_data_remaining(m, fnum, filenum, 1);
|
||||
|
||||
/* must be called once per second */
|
||||
if (timed_out(Friends.list[fnum].file_receiver[filenum].last_progress, curtime, 1)) {
|
||||
Friends.list[fnum].file_receiver[filenum].last_progress = curtime;
|
||||
uint64_t size = Friends.list[fnum].file_receiver[filenum].size;
|
||||
double pct_done = remain > 0 ? (1 - (remain / size)) * 100 : 100;
|
||||
print_progress_bar(toxwin, filenum, fnum, pct_done);
|
||||
Friends.list[fnum].file_receiver[filenum].bps = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* refreshes active file sender status bars */
|
||||
static void refresh_sender_prog(Tox *m)
|
||||
{
|
||||
int i;
|
||||
uint64_t curtime = get_unix_time();
|
||||
|
||||
for (i = 0; i < max_file_senders_index; ++i) {
|
||||
if (!file_senders[i].active || file_senders[i].finished)
|
||||
continue;
|
||||
|
||||
int filenum = file_senders[i].filenum;
|
||||
int32_t friendnum = file_senders[i].friendnum;
|
||||
double remain = (double) tox_file_data_remaining(m, friendnum, filenum, 0);
|
||||
|
||||
/* must be called once per second */
|
||||
if (timed_out(file_senders[i].last_progress, curtime, 1)) {
|
||||
file_senders[i].last_progress = curtime;
|
||||
double pct_done = remain > 0 ? (1 - (remain / file_senders[i].size)) * 100 : 100;
|
||||
print_progress_bar(file_senders[i].toxwin, i, -1, pct_done);
|
||||
file_senders[i].bps = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void set_max_file_senders_index(void)
|
||||
{
|
||||
@ -47,16 +159,33 @@ 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)
|
||||
/* called whenever a file sender is opened or closed */
|
||||
void reset_file_sender_queue(void)
|
||||
{
|
||||
if (self->chatwin != NULL)
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
|
||||
int i;
|
||||
int pos = 0;
|
||||
|
||||
for (i = 0; i < max_file_senders_index; ++i) {
|
||||
if (file_senders[i].active)
|
||||
file_senders[i].queue_pos = pos++;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 (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);
|
||||
|
||||
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();
|
||||
reset_file_sender_queue();
|
||||
--num_active_file_senders;
|
||||
}
|
||||
|
||||
void close_all_file_senders(Tox *m)
|
||||
@ -75,57 +204,87 @@ 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;
|
||||
|
||||
file_senders[i].timestamp = get_unix_time();
|
||||
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);
|
||||
|
||||
/* note: file sender is closed in chat_onFileControl callback after receiving reply */
|
||||
if (file_senders[i].piecelen == 0) {
|
||||
if (feof(fp) != 0) { /* make sure we're really at eof */
|
||||
print_progress_bar(self, i, -1, 100.0);
|
||||
tox_file_send_control(m, friendnum, 0, filenum, TOX_FILECONTROL_FINISHED, 0, 0);
|
||||
file_senders[i].finished = true;
|
||||
} else {
|
||||
char msg[MAX_STR_SIZE];
|
||||
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Read error.", file_senders[i].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, "%s", msg);
|
||||
else
|
||||
box_notify(self, error, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", msg);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
/* 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 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, "%s", msg);
|
||||
else
|
||||
box_notify(self, error, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", msg);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!file_senders[i].noconnection && !file_senders[i].finished)
|
||||
send_file_data(self, m, i, friendnum, filenum, filename);
|
||||
|
||||
file_senders[i].queue_pos = num_active_file_senders - 1;
|
||||
}
|
||||
|
||||
refresh_sender_prog(m);
|
||||
refresh_recv_prog(m);
|
||||
}
|
||||
|
@ -26,25 +26,49 @@
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
|
||||
#define KiB 1024
|
||||
#define MiB 1048576 /* 1024 ^ 2 */
|
||||
#define GiB 1073741824 /* 1024 ^ 3 */
|
||||
|
||||
#define FILE_PIECE_SIZE 2048 /* must be >= (MAX_CRYPTO_DATA_SIZE - 2) in toxcore/net_crypto.h */
|
||||
#define MAX_FILES 255
|
||||
#define MAX_FILES 32
|
||||
#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 noconnection;
|
||||
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);
|
||||
|
||||
/* called whenever a file sender is opened or closed */
|
||||
void reset_file_sender_queue(void);
|
||||
|
||||
void close_all_file_senders(Tox *m);
|
||||
void do_file_senders(Tox *m);
|
||||
|
||||
|
802
src/friendlist.c
802
src/friendlist.c
File diff suppressed because it is too large
Load Diff
@ -30,12 +30,16 @@
|
||||
#include "file_senders.h"
|
||||
|
||||
struct FileReceiver {
|
||||
char filenames[MAX_FILES][MAX_STR_SIZE];
|
||||
FILE *files[MAX_FILES];
|
||||
bool pending[MAX_FILES];
|
||||
uint64_t size[MAX_FILES];
|
||||
uint64_t last_progress[MAX_FILES];
|
||||
uint32_t line_id[MAX_FILES];
|
||||
char filename[MAX_STR_SIZE];
|
||||
int filenum;
|
||||
FILE *file;
|
||||
bool pending;
|
||||
bool active;
|
||||
uint64_t size;
|
||||
uint64_t bytes_recv;
|
||||
double bps;
|
||||
uint64_t last_progress; /* unix-time when we last updated progress */
|
||||
uint32_t line_id;
|
||||
};
|
||||
|
||||
struct LastOnline {
|
||||
@ -57,16 +61,35 @@ typedef struct {
|
||||
bool active;
|
||||
bool online;
|
||||
uint8_t is_typing;
|
||||
bool logging_on; /* saves preference for friend irrespective of chat windows */
|
||||
bool logging_on; /* saves preference for friend irrespective of global settings */
|
||||
uint8_t status;
|
||||
struct LastOnline last_online;
|
||||
struct FileReceiver file_receiver;
|
||||
struct FileReceiver file_receiver[MAX_FILES];
|
||||
uint8_t active_file_receivers;
|
||||
} 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;
|
||||
|
||||
typedef struct {
|
||||
int num_selected;
|
||||
int max_idx; /* 1 + the index of the last friend in list */
|
||||
int num_friends;
|
||||
int *index;
|
||||
ToxicFriend *list;
|
||||
} _Friends;
|
||||
|
||||
ToxWindow new_friendlist(void);
|
||||
void disable_chatwin(int32_t f_num);
|
||||
int get_friendnum(uint8_t *name);
|
||||
|
||||
int load_blocklist(char *data);
|
||||
void kill_friendlist(void);
|
||||
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_t num, bool sort);
|
||||
|
||||
/* sorts friendlist_index first by connection status then alphabetically */
|
||||
|
@ -37,38 +37,31 @@
|
||||
|
||||
extern char *DATA_FILE;
|
||||
extern ToxWindow *prompt;
|
||||
|
||||
extern ToxicFriend friends[MAX_FRIENDS_NUM];
|
||||
|
||||
extern char pending_frnd_requests[MAX_FRIENDS_NUM][TOX_CLIENT_ID_SIZE];
|
||||
extern uint8_t num_frnd_requests;
|
||||
extern _Friends Friends;
|
||||
extern _FriendRequests FriendRequests;
|
||||
|
||||
/* 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);
|
||||
if ((req == 0 && strcmp(argv[1], "0")) || req < 0 || req > MAX_FRIEND_REQUESTS) {
|
||||
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);
|
||||
if (!FriendRequests.request[req].active) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t friendnum = tox_add_friend_norequest(m, (uint8_t *) pending_frnd_requests[req]);
|
||||
const char *msg;
|
||||
int32_t friendnum = tox_add_friend_norequest(m, FriendRequests.request[req].key);
|
||||
|
||||
if (friendnum == -1)
|
||||
msg = "Failed to add friend.";
|
||||
@ -77,22 +70,23 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
||||
on_friendadded(m, friendnum, true);
|
||||
}
|
||||
|
||||
memset(&pending_frnd_requests[req], 0, TOX_CLIENT_ID_SIZE);
|
||||
memset(&FriendRequests.request[req], 0, sizeof(struct _friend_request));
|
||||
|
||||
int i;
|
||||
|
||||
for (i = num_frnd_requests; i > 0; --i) {
|
||||
if (!strlen(pending_frnd_requests[i - 1]))
|
||||
for (i = FriendRequests.max_idx; i > 0; --i) {
|
||||
if (FriendRequests.request[i - 1].active)
|
||||
break;
|
||||
}
|
||||
|
||||
num_frnd_requests = i;
|
||||
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
FriendRequests.max_idx = i;
|
||||
--FriendRequests.num_requests;
|
||||
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 +124,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 +171,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 +194,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,49 +204,73 @@ 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;
|
||||
}
|
||||
|
||||
char *binary_string = hex_string_to_bin(key);
|
||||
tox_bootstrap_from_address(m, ip, TOX_ENABLE_IPV6_DEFAULT, htons(atoi(port)), (uint8_t *) binary_string);
|
||||
tox_bootstrap_from_address(m, ip, atoi(port), (uint8_t *) binary_string);
|
||||
free(binary_string);
|
||||
}
|
||||
|
||||
void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
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 < 0 || req > MAX_FRIEND_REQUESTS) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!FriendRequests.request[req].active) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&FriendRequests.request[req], 0, sizeof(struct _friend_request));
|
||||
|
||||
int i;
|
||||
|
||||
for (i = FriendRequests.max_idx; i > 0; --i) {
|
||||
if (FriendRequests.request[i - 1].active)
|
||||
break;
|
||||
}
|
||||
|
||||
FriendRequests.max_idx = i;
|
||||
--FriendRequests.num_requests;
|
||||
}
|
||||
|
||||
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,17 +279,17 @@ 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")) {
|
||||
|
||||
if (self->is_chat) {
|
||||
friends[self->num].logging_on = true;
|
||||
log_enable(self->name, friends[self->num].pub_key, log);
|
||||
Friends.list[self->num].logging_on = true;
|
||||
log_enable(self->name, Friends.list[self->num].pub_key, log);
|
||||
} else if (self->is_prompt) {
|
||||
char myid[TOX_FRIEND_ADDRESS_SIZE];
|
||||
tox_get_address(m, (uint8_t *) myid);
|
||||
@ -289,21 +299,21 @@ 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)
|
||||
friends[self->num].logging_on = false;
|
||||
Friends.list[self->num].logging_on = false;
|
||||
|
||||
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 +330,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,27 +368,23 @@ 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);
|
||||
|
||||
prompt_update_statusmessage(prompt, m, msg);
|
||||
}
|
||||
|
||||
void cmd_prompt_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
@ -393,26 +397,51 @@ void cmd_quit(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
||||
exit_toxic_success(m);
|
||||
}
|
||||
|
||||
void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
void cmd_requests(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
char *msg = NULL;
|
||||
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);
|
||||
if (FriendRequests.num_requests == 0) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend requests.");
|
||||
return;
|
||||
}
|
||||
|
||||
char *status = argv[1];
|
||||
int i, j;
|
||||
int count = 0;
|
||||
|
||||
for (i = 0; i < FriendRequests.max_idx; ++i) {
|
||||
if (!FriendRequests.request[i].active)
|
||||
continue;
|
||||
|
||||
char id[TOX_CLIENT_ID_SIZE * 2 + 1] = {0};
|
||||
|
||||
for (j = 0; j < TOX_CLIENT_ID_SIZE; ++j) {
|
||||
char d[3];
|
||||
snprintf(d, sizeof(d), "%02X", FriendRequests.request[i].key[j] & 0xff);
|
||||
strcat(id, d);
|
||||
}
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%d : %s", i, id);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", FriendRequests.request[i].msg);
|
||||
|
||||
if (++count < FriendRequests.num_requests)
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
|
||||
}
|
||||
}
|
||||
|
||||
void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
bool have_note = false;
|
||||
const char *errmsg;
|
||||
|
||||
if (argc >= 2) {
|
||||
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[MAX_STR_SIZE];
|
||||
snprintf(status, sizeof(status), "%s", argv[1]);
|
||||
str_to_lower(status);
|
||||
|
||||
TOX_USERSTATUS status_kind;
|
||||
@ -425,18 +454,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 */
|
||||
tox_set_status_message(m, (uint8_t *) msg, (uint16_t) len);
|
||||
prompt_update_statusmessage(prompt, msg);
|
||||
msg[len] = '\0';
|
||||
|
||||
prompt_update_statusmessage(prompt, m, msg);
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ void cmd_accept(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZ
|
||||
void cmd_add(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_clear(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_connect(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_groupchat(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_log(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_myid(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
@ -37,6 +38,7 @@ void cmd_nick(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]
|
||||
void cmd_note(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_prompt_help(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_quit(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_requests(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_status(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
|
||||
void cmd_add_helper(ToxWindow *self, Tox *m, char *id_bin, char *msg);
|
||||
|
@ -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;
|
||||
}
|
||||
|
73
src/help.c
73
src/help.c
@ -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)
|
||||
@ -77,21 +77,26 @@ static void help_draw_menu(ToxWindow *self)
|
||||
wattroff(win, A_BOLD | COLOR_PAIR(RED));
|
||||
|
||||
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||
wprintw(win, " G");
|
||||
wprintw(win, " g");
|
||||
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||
wprintw(win, "lobal commands\n");
|
||||
|
||||
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||
wprintw(win, " C");
|
||||
wprintw(win, " c");
|
||||
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||
wprintw(win, "hat commands\n");
|
||||
|
||||
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||
wprintw(win, " K");
|
||||
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));
|
||||
wprintw(win, "ey bindings\n");
|
||||
|
||||
wprintw(win, " E");
|
||||
wprintw(win, " e");
|
||||
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||
wprintw(win, "x");
|
||||
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||
@ -110,11 +115,11 @@ static void help_draw_bottom_menu(WINDOW *win)
|
||||
wmove(win, y2 - 2, 1);
|
||||
|
||||
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||
wprintw(win, " M");
|
||||
wprintw(win, " m");
|
||||
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||
wprintw(win, "ain menu |");
|
||||
|
||||
wprintw(win, " E");
|
||||
wprintw(win, " e");
|
||||
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||
wprintw(win, "x");
|
||||
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||
@ -131,15 +136,17 @@ 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, " /decline <id> : Decline friend request\n");
|
||||
wprintw(win, " /requests : List pending friend requests\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 +179,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 +188,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 +216,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);
|
||||
|
||||
@ -236,15 +266,20 @@ void help_onKey(ToxWindow *self, wint_t key)
|
||||
|
||||
case 'g':
|
||||
#ifdef _AUDIO
|
||||
help_init_window(self, 21, 80);
|
||||
help_init_window(self, 23, 80);
|
||||
#else
|
||||
help_init_window(self, 17, 80);
|
||||
help_init_window(self, 19, 80);
|
||||
#endif
|
||||
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 +311,10 @@ void help_onDraw(ToxWindow *self)
|
||||
help_draw_keys(self);
|
||||
break;
|
||||
|
||||
case HELP_CONTACTS:
|
||||
help_draw_contacts(self);
|
||||
break;
|
||||
|
||||
case HELP_GROUP:
|
||||
break;
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ typedef enum {
|
||||
HELP_CHAT,
|
||||
HELP_GROUP,
|
||||
HELP_KEYS,
|
||||
HELP_CONTACTS,
|
||||
} HELP_TYPES;
|
||||
|
||||
void help_onDraw(ToxWindow *self);
|
||||
|
28
src/input.c
28
src/input.c
@ -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);
|
||||
}
|
||||
|
@ -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,36 +455,24 @@ 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:
|
||||
line_info_page_up(self, hst);
|
||||
break;
|
||||
|
||||
case T_KEY_C_V:
|
||||
line_info_page_down(self, hst);
|
||||
break;
|
||||
|
||||
case KEY_PPAGE:
|
||||
line_info_scroll_up(hst);
|
||||
break;
|
||||
|
||||
case KEY_NPAGE:
|
||||
line_info_scroll_down(hst);
|
||||
break;
|
||||
|
||||
/* case ?:
|
||||
line_info_goto_root(hst);
|
||||
break; */
|
||||
|
||||
case T_KEY_C_H:
|
||||
line_info_reset_start(self, hst);
|
||||
break;
|
||||
|
||||
default:
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
if (key == user_settings_->key_half_page_up) {
|
||||
line_info_page_up(self, hst);
|
||||
}
|
||||
else if (key == user_settings_->key_half_page_down) {
|
||||
line_info_page_down(self, hst);
|
||||
}
|
||||
else if (key == user_settings_->key_scroll_line_up) {
|
||||
line_info_scroll_up(hst);
|
||||
}
|
||||
else if (key == user_settings_->key_scroll_line_down) {
|
||||
line_info_scroll_down(hst);
|
||||
}
|
||||
else if (key == user_settings_->key_page_bottom) {
|
||||
line_info_reset_start(self, hst);
|
||||
}
|
||||
else {
|
||||
match = false;
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
@ -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);
|
||||
|
20
src/log.c
20
src/log.c
@ -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;
|
||||
@ -42,15 +42,17 @@ void init_logging_session(char *name, char *key, struct chatlog *log)
|
||||
if (!valid_nick(name))
|
||||
name = UNKNOWN_NAME;
|
||||
|
||||
const char *set_path = user_settings_->chatlogs_path;
|
||||
|
||||
char *user_config_dir = get_user_config_dir();
|
||||
int path_len = strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(name);
|
||||
int path_len = strlen(set_path) + strlen(name) ? *set_path
|
||||
: 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];
|
||||
|
||||
if (key != NULL) {
|
||||
path_len += (KEY_IDENT_DIGITS * 2 + 5);
|
||||
|
||||
sprintf(&ident[0], "%02X", key[0] & 0xff);
|
||||
sprintf(&ident[2], "%02X", key[1] & 0xff);
|
||||
ident[KEY_IDENT_DIGITS * 2 + 1] = '\0';
|
||||
@ -59,7 +61,7 @@ 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;
|
||||
@ -67,8 +69,10 @@ void init_logging_session(char *name, char *key, struct chatlog *log)
|
||||
|
||||
char log_path[MAX_STR_SIZE];
|
||||
|
||||
snprintf(log_path, MAX_STR_SIZE, "%s%s%s-%s.log",
|
||||
user_config_dir, CONFIGDIR, name, ident);
|
||||
if (*set_path)
|
||||
snprintf(log_path, sizeof(log_path), "%s%s-%s.log", set_path, name, ident);
|
||||
else
|
||||
snprintf(log_path, sizeof(log_path), "%s%s%s-%s.log", user_config_dir, LOGDIR, name, ident);
|
||||
|
||||
free(user_config_dir);
|
||||
|
||||
@ -82,7 +86,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 +116,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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -26,17 +26,34 @@
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "misc_tools.h"
|
||||
#include "settings.h"
|
||||
#include "file_senders.h"
|
||||
|
||||
extern ToxWindow *prompt;
|
||||
extern struct user_settings *user_settings_;
|
||||
|
||||
static uint64_t current_unix_time;
|
||||
|
||||
void hst_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);
|
||||
@ -108,6 +125,25 @@ char *hex_string_to_bin(const char *hex_string)
|
||||
return val;
|
||||
}
|
||||
|
||||
int hex_string_to_bytes(char *buf, int size, const char *keystr)
|
||||
{
|
||||
if (size % 2 != 0)
|
||||
return -1;
|
||||
|
||||
int i, res;
|
||||
const char *pos = keystr;
|
||||
|
||||
for (i = 0; i < size; ++i) {
|
||||
res = sscanf(pos, "%2hhx", &buf[i]);
|
||||
pos += 2;
|
||||
|
||||
if (res == EOF || res < 1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns 1 if the string is empty, 0 otherwise */
|
||||
int string_is_empty(const char *string)
|
||||
{
|
||||
@ -143,9 +179,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:
|
||||
@ -245,4 +281,33 @@ int char_rfind(const char *s, char ch, int len)
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Converts bytes to appropriate unit and puts in buf as a string */
|
||||
void bytes_convert_str(char *buf, int size, uint64_t bytes)
|
||||
{
|
||||
double conv = bytes;
|
||||
const char *unit;
|
||||
|
||||
if (conv < KiB) {
|
||||
unit = "Bytes";
|
||||
} else if (conv < MiB) {
|
||||
unit = "KiB";
|
||||
conv /= (double) KiB;
|
||||
} else if (conv < GiB) {
|
||||
unit = "MiB";
|
||||
conv /= (double) MiB;
|
||||
} else {
|
||||
unit = "GiB";
|
||||
conv /= (double) GiB;
|
||||
}
|
||||
|
||||
snprintf(buf, size, "%.1f %s", conv, unit);
|
||||
}
|
||||
|
||||
/* checks if a file exists. Returns true or false */
|
||||
bool file_exists(const char *fp)
|
||||
{
|
||||
struct stat s;
|
||||
return stat(fp, &s) == 0;
|
||||
}
|
||||
|
@ -33,13 +33,22 @@
|
||||
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
||||
#endif
|
||||
|
||||
#ifndef net_to_host
|
||||
#define net_to_host(x, y) hst_to_net(x, y)
|
||||
#endif
|
||||
|
||||
void hst_to_net(uint8_t *num, uint16_t numbytes);
|
||||
|
||||
/* convert a hex string to binary */
|
||||
char *hex_string_to_bin(const char *hex_string);
|
||||
|
||||
/* convert a hex string to bytes. returns 0 on success, -1 on failure */
|
||||
int hex_string_to_bytes(char *buf, int size, const char *keystr);
|
||||
|
||||
/* get the current unix time */
|
||||
uint64_t get_unix_time(void);
|
||||
|
||||
/*Puts the current time in buf in the format of [HH:mm:ss] */
|
||||
/* Puts the current time in buf in the format of [HH:mm:ss] */
|
||||
void get_time_str(char *buf, int bufsize);
|
||||
|
||||
/* Converts seconds to string in format HH:mm:ss; truncates hours and minutes when necessary */
|
||||
@ -70,7 +79,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
|
||||
@ -97,4 +106,10 @@ int char_find(int idx, const char *s, char ch);
|
||||
returns 0 if char not found */
|
||||
int char_rfind(const char *s, char ch, int len);
|
||||
|
||||
/* Converts bytes to appropriate unit and puts in buf as a string */
|
||||
void bytes_convert_str(char *buf, int size, uint64_t bytes);
|
||||
|
||||
/* checks if a file exists. Returns true or false */
|
||||
bool file_exists(const char *fp);
|
||||
|
||||
#endif /* #define _misc_tools_h */
|
||||
|
542
src/notify.c
542
src/notify.c
@ -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__
|
||||
#include <OpenAL/al.h>
|
||||
#include <OpenAL/alc.h>
|
||||
#ifdef _SOUND_NOTIFY
|
||||
#include <OpenAL/alut.h> /* Is this good? */
|
||||
#if defined(_AUDIO) || defined(_SOUND_NOTIFY)
|
||||
#ifdef __APPLE__
|
||||
#include <OpenAL/al.h>
|
||||
#include <OpenAL/alc.h>
|
||||
#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
|
||||
#else
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
#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 */
|
||||
|
||||
/* 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));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
pthread_mutex_unlock(Control.poll_mutex);
|
||||
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 */
|
||||
#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
|
||||
@ -304,32 +431,313 @@ static int m_play_sound(Notification notif, uint64_t flags)
|
||||
beep();
|
||||
|
||||
return -1;
|
||||
#endif /* _SOUND_NOTIFY */
|
||||
|
||||
#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())
|
||||
}
|
||||
#endif
|
||||
|
||||
int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator)
|
||||
{
|
||||
/* Consider colored notify as primary */
|
||||
if (self) {
|
||||
if (flags & NT_WNDALERT_0) self->alert = WINDOW_ALERT_0;
|
||||
else if ( (flags & NT_WNDALERT_1) && (!self->alert || self->alert > WINDOW_ALERT_0) ) self->alert = WINDOW_ALERT_1;
|
||||
else if ( (flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1) ) 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;
|
||||
|
||||
int rc = -1;
|
||||
int id = -1;
|
||||
control_lock();
|
||||
|
||||
if (self && (!self->stb || self->stb->status != TOX_USERSTATUS_BUSY) && user_settings_->alerts == ALERTS_ENABLED)
|
||||
rc = m_play_sound(notif, flags);
|
||||
id = m_play_sound(notif, flags);
|
||||
|
||||
else if (flags & NT_ALWAYS)
|
||||
rc = m_play_sound(notif, flags);
|
||||
id = m_play_sound(notif, flags);
|
||||
|
||||
if (flags & NT_NOTIFWND) {
|
||||
/* TODO: pop notify window */
|
||||
#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 */
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
#endif
|
||||
|
||||
if ( id_indicator && id != -1 ) {
|
||||
actives[id].id_indicator = id_indicator;
|
||||
*id_indicator = id;
|
||||
}
|
||||
|
||||
return rc;
|
||||
control_unlock();
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
|
||||
{
|
||||
/* Consider colored notify as primary */
|
||||
if (self) {
|
||||
if (flags & NT_WNDALERT_0) self->alert = WINDOW_ALERT_0;
|
||||
else if ( (flags & NT_WNDALERT_1) && (!self->alert || self->alert > WINDOW_ALERT_0) ) self->alert = WINDOW_ALERT_1;
|
||||
else if ( (flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1) ) 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) {
|
||||
if (flags & NT_WNDALERT_0) self->alert = WINDOW_ALERT_0;
|
||||
else if ( (flags & NT_WNDALERT_1) && (!self->alert || self->alert > WINDOW_ALERT_0) ) self->alert = WINDOW_ALERT_1;
|
||||
else if ( (flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1) ) 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) {
|
||||
if (flags & NT_WNDALERT_0) self->alert = WINDOW_ALERT_0;
|
||||
else if ( (flags & NT_WNDALERT_1) && (!self->alert || self->alert > WINDOW_ALERT_0) ) self->alert = WINDOW_ALERT_1;
|
||||
else if ( (flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1) ) 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
|
||||
}
|
||||
|
13
src/notify.h
13
src/notify.h
@ -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 */
|
||||
|
144
src/prompt.c
144
src/prompt.c
@ -42,12 +42,11 @@
|
||||
#include "notify.h"
|
||||
#include "autocomplete.h"
|
||||
|
||||
char pending_frnd_requests[MAX_FRIENDS_NUM][TOX_CLIENT_ID_SIZE];
|
||||
uint16_t num_frnd_requests = 0;
|
||||
extern ToxWindow *prompt;
|
||||
struct _Winthread Winthread;
|
||||
|
||||
extern struct user_settings *user_settings_;
|
||||
extern struct _Winthread Winthread;
|
||||
|
||||
_FriendRequests FriendRequests;
|
||||
|
||||
/* Array of global command names used for tab completion. */
|
||||
const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
|
||||
@ -56,6 +55,7 @@ const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
|
||||
{ "/clear" },
|
||||
{ "/close" }, /* rm /close when groupchats gets its own list */
|
||||
{ "/connect" },
|
||||
{ "/decline" },
|
||||
{ "/exit" },
|
||||
{ "/groupchat" },
|
||||
{ "/help" },
|
||||
@ -64,6 +64,7 @@ const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
|
||||
{ "/nick" },
|
||||
{ "/note" },
|
||||
{ "/quit" },
|
||||
{ "/requests" },
|
||||
{ "/status" },
|
||||
|
||||
#ifdef _AUDIO
|
||||
@ -96,19 +97,21 @@ 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);
|
||||
statusbar->nick_len = strlen(statusbar->nick);
|
||||
}
|
||||
|
||||
/* Updates own statusmessage in prompt statusbar */
|
||||
void prompt_update_statusmessage(ToxWindow *prompt, char *statusmsg)
|
||||
/* Updates own statusmessage */
|
||||
void prompt_update_statusmessage(ToxWindow *prompt, Tox *m, const char *statusmsg)
|
||||
{
|
||||
StatusBar *statusbar = prompt->stb;
|
||||
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
|
||||
statusbar->statusmsg_len = strlen(statusbar->statusmsg);
|
||||
int len = strlen(statusbar->statusmsg);
|
||||
statusbar->statusmsg_len = len;
|
||||
tox_set_status_message(m, (uint8_t *) statusmsg, (uint64_t) len);
|
||||
}
|
||||
|
||||
/* Updates own status in prompt statusbar */
|
||||
@ -126,20 +129,24 @@ void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected)
|
||||
}
|
||||
|
||||
/* Adds friend request to pending friend requests.
|
||||
Returns request number on success, -1 if queue is full or other error. */
|
||||
static int add_friend_request(const char *public_key)
|
||||
Returns request number on success, -1 if queue is full. */
|
||||
static int add_friend_request(const char *public_key, const char *data)
|
||||
{
|
||||
if (num_frnd_requests >= MAX_FRIENDS_NUM)
|
||||
if (FriendRequests.max_idx >= MAX_FRIEND_REQUESTS)
|
||||
return -1;
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= num_frnd_requests; ++i) {
|
||||
if (!strlen(pending_frnd_requests[i])) {
|
||||
memcpy(pending_frnd_requests[i], public_key, TOX_CLIENT_ID_SIZE);
|
||||
for (i = 0; i <= FriendRequests.max_idx; ++i) {
|
||||
if (!FriendRequests.request[i].active) {
|
||||
FriendRequests.request[i].active = true;
|
||||
memcpy(FriendRequests.request[i].key, public_key, TOX_CLIENT_ID_SIZE);
|
||||
snprintf(FriendRequests.request[i].msg, sizeof(FriendRequests.request[i].msg), "%s", data);
|
||||
|
||||
if (i == num_frnd_requests)
|
||||
++num_frnd_requests;
|
||||
if (i == FriendRequests.max_idx)
|
||||
++FriendRequests.max_idx;
|
||||
|
||||
++FriendRequests.num_requests;
|
||||
|
||||
return i;
|
||||
}
|
||||
@ -185,10 +192,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 +208,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);
|
||||
@ -269,6 +276,29 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
||||
wattroff(statusbar->topline, A_BOLD);
|
||||
}
|
||||
|
||||
/* Reset statusbar->statusmsg on window resize */
|
||||
if (x2 != self->x) {
|
||||
char statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH] = {0};
|
||||
|
||||
pthread_mutex_lock(&Winthread.lock);
|
||||
tox_get_self_status_message(m, (uint8_t *) statusmsg, TOX_MAX_STATUSMESSAGE_LENGTH);
|
||||
pthread_mutex_unlock(&Winthread.lock);
|
||||
|
||||
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
|
||||
statusbar->statusmsg_len = strlen(statusbar->statusmsg);
|
||||
}
|
||||
|
||||
self->x = x2;
|
||||
|
||||
/* Truncate note if it doesn't fit in statusbar */
|
||||
uint16_t maxlen = x2 - getcurx(statusbar->topline) - 3;
|
||||
|
||||
if (statusbar->statusmsg_len > maxlen) {
|
||||
statusbar->statusmsg[maxlen - 3] = '\0';
|
||||
strcat(statusbar->statusmsg, "...");
|
||||
statusbar->statusmsg_len = maxlen;
|
||||
}
|
||||
|
||||
if (statusbar->statusmsg[0])
|
||||
wprintw(statusbar->topline, " - %s", statusbar->statusmsg);
|
||||
|
||||
@ -302,28 +332,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 +367,19 @@ 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);
|
||||
int n = add_friend_request(key, data);
|
||||
|
||||
if (n == -1) {
|
||||
char *errmsg = "Friend request queue is full. Discarding request.";
|
||||
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
|
||||
write_to_log(errmsg, "", ctx->log, true);
|
||||
const char *errmsg = "Friend request queue is full. Discarding request.";
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
||||
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\" or \"/decline %d\"", n, n);
|
||||
sound_notify(self, generic_message, NT_WNDALERT_1 | NT_NOTIFWND, NULL);
|
||||
}
|
||||
|
||||
void prompt_init_statusbar(ToxWindow *self, Tox *m)
|
||||
@ -368,11 +396,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';
|
||||
@ -382,13 +408,13 @@ void prompt_init_statusbar(ToxWindow *self, Tox *m)
|
||||
strcpy(ver, TOXICVER);
|
||||
const char *toxic_ver = strtok(ver, "_");
|
||||
|
||||
if ( (!statusmsg[0] || !strncmp("Toxing on Toxic", statusmsg, 15)) && toxic_ver != NULL) {
|
||||
snprintf(statusmsg, MAX_STR_SIZE, "Toxing on Toxic v.%s", toxic_ver);
|
||||
if ( (s_len <= 0 || !strncmp("Toxing on Toxic", statusmsg, strlen("Toxing on Toxic"))) && toxic_ver != NULL) {
|
||||
snprintf(statusmsg, sizeof(statusmsg), "Toxing on Toxic v.%s", toxic_ver);
|
||||
s_len = strlen(statusmsg);
|
||||
statusmsg[s_len] = '\0';
|
||||
}
|
||||
|
||||
prompt_update_statusmessage(prompt, statusmsg);
|
||||
prompt_update_statusmessage(prompt, m, statusmsg);
|
||||
prompt_update_status(prompt, status);
|
||||
prompt_update_nick(prompt, nick);
|
||||
|
||||
@ -398,18 +424,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 +495,7 @@ ToxWindow new_prompt(void)
|
||||
ret.stb = stb;
|
||||
ret.help = help;
|
||||
|
||||
ret.active_box = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
22
src/prompt.h
22
src/prompt.h
@ -27,16 +27,30 @@
|
||||
#include "windows.h"
|
||||
|
||||
#ifdef _AUDIO
|
||||
#define AC_NUM_GLOB_COMMANDS 16
|
||||
#define AC_NUM_GLOB_COMMANDS 18
|
||||
#else
|
||||
#define AC_NUM_GLOB_COMMANDS 14
|
||||
#define AC_NUM_GLOB_COMMANDS 16
|
||||
#endif /* _AUDIO */
|
||||
|
||||
#define MAX_FRIEND_REQUESTS 32
|
||||
|
||||
struct _friend_request {
|
||||
bool active;
|
||||
char msg[MAX_STR_SIZE];
|
||||
uint8_t key[TOX_CLIENT_ID_SIZE];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int max_idx;
|
||||
int num_requests;
|
||||
struct _friend_request request[MAX_FRIEND_REQUESTS];
|
||||
} _FriendRequests;
|
||||
|
||||
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, Tox *m, 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);
|
||||
|
163
src/settings.c
163
src/settings.c
@ -23,11 +23,13 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libconfig.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "configdir.h"
|
||||
#include "notify.h"
|
||||
#include "misc_tools.h"
|
||||
|
||||
#ifdef _AUDIO
|
||||
#include "device.h"
|
||||
@ -42,7 +44,7 @@
|
||||
|
||||
#define NO_SOUND "silent"
|
||||
|
||||
const struct _ui_strings {
|
||||
static struct _ui_strings {
|
||||
const char* self;
|
||||
const char* timestamps;
|
||||
const char* alerts;
|
||||
@ -50,6 +52,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 +61,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,23 +74,66 @@ 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 _tox_strings {
|
||||
static 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;
|
||||
}
|
||||
|
||||
static const struct _tox_strings {
|
||||
const char* self;
|
||||
const char* download_path;
|
||||
const char* chatlogs_path;
|
||||
} tox_strings = {
|
||||
"tox",
|
||||
"download_path",
|
||||
"chatlogs_path",
|
||||
};
|
||||
|
||||
static void tox_defaults(struct user_settings* settings)
|
||||
{
|
||||
strcpy(settings->download_path, ""); /* explicitly set default to pwd */
|
||||
strcpy(settings->download_path, "");
|
||||
strcpy(settings->chatlogs_path, "");
|
||||
}
|
||||
|
||||
#ifdef _AUDIO
|
||||
const struct _audio_strings {
|
||||
static const struct _audio_strings {
|
||||
const char* self;
|
||||
const char* input_device;
|
||||
const char* output_device;
|
||||
@ -94,6 +144,7 @@ const struct _audio_strings {
|
||||
"output_device",
|
||||
"VAD_treshold",
|
||||
};
|
||||
|
||||
static void audio_defaults(struct user_settings* settings)
|
||||
{
|
||||
settings->audio_in_dev = 0;
|
||||
@ -103,7 +154,7 @@ static void audio_defaults(struct user_settings* settings)
|
||||
#endif
|
||||
|
||||
#ifdef _SOUND_NOTIFY
|
||||
const struct _sound_strings {
|
||||
static const struct _sound_strings {
|
||||
const char* self;
|
||||
const char* error;
|
||||
const char* self_log_in;
|
||||
@ -130,19 +181,38 @@ 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];
|
||||
config_setting_t *setting;
|
||||
const char *str;
|
||||
const char *str = NULL;
|
||||
|
||||
/* Load default settings */
|
||||
ui_defaults(s);
|
||||
tox_defaults(s);
|
||||
key_defaults(s);
|
||||
|
||||
#ifdef _AUDIO
|
||||
audio_defaults(s);
|
||||
#endif
|
||||
|
||||
|
||||
config_init(cfg);
|
||||
|
||||
char path[MAX_STR_SIZE];
|
||||
@ -154,41 +224,74 @@ int settings_load(struct user_settings *s, const char *patharg)
|
||||
free(user_config_dir);
|
||||
|
||||
/* make sure path exists or is created on first time running */
|
||||
FILE *fp = fopen(path, "r");
|
||||
if (!file_exists(path)) {
|
||||
FILE *fp = fopen(path, "w");
|
||||
|
||||
if (fp == NULL) {
|
||||
if ((fp = fopen(path, "w")) == NULL)
|
||||
if (fp == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
fclose(fp);
|
||||
}
|
||||
} else {
|
||||
snprintf(path, sizeof(path), "%s", patharg);
|
||||
}
|
||||
|
||||
|
||||
if (!config_read_file(cfg, path)) {
|
||||
config_destroy(cfg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* ui */
|
||||
if ((setting = config_lookup(cfg, ui_strings.self)) != NULL) {
|
||||
config_setting_lookup_bool(setting, ui_strings.timestamps, &s->timestamps);
|
||||
config_setting_lookup_bool(setting, ui_strings.alerts, &s->alerts);
|
||||
config_setting_lookup_bool(setting, ui_strings.autolog, &s->autolog);
|
||||
config_setting_lookup_bool(setting, ui_strings.native_colors, &s->colour_theme);
|
||||
|
||||
config_setting_lookup_int(setting, ui_strings.history_size, &s->history_size);
|
||||
config_setting_lookup_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 */
|
||||
}
|
||||
|
||||
|
||||
/* paths */
|
||||
if ((setting = config_lookup(cfg, tox_strings.self)) != NULL) {
|
||||
if ( config_setting_lookup_string(setting, tox_strings.download_path, &str) ) {
|
||||
strcpy(s->download_path, str);
|
||||
snprintf(s->download_path, sizeof(s->download_path), "%s", str);
|
||||
int len = strlen(s->download_path);
|
||||
|
||||
/* make sure path ends with a '/' */
|
||||
if (len >= sizeof(s->download_path) - 2)
|
||||
s->download_path[0] = '\0';
|
||||
else if (s->download_path[len - 1] != '/')
|
||||
strcat(&s->download_path[len - 1], "/");
|
||||
}
|
||||
|
||||
if ( config_setting_lookup_string(setting, tox_strings.chatlogs_path, &str) ) {
|
||||
snprintf(s->chatlogs_path, sizeof(s->chatlogs_path), "%s", str);
|
||||
int len = strlen(s->chatlogs_path);
|
||||
|
||||
if (len >= sizeof(s->chatlogs_path) - 2)
|
||||
s->chatlogs_path[0] = '\0';
|
||||
else if (s->chatlogs_path[len - 1] != '/')
|
||||
strcat(&s->chatlogs_path[len - 1], "/");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* 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 +308,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 (str && 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 (str && 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 (str && 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 (str && 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 (str && 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 (str && 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 (str && 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 (str && 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 (str && 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 (str && strcasecmp(str, NO_SOUND) != 0)
|
||||
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/TransferComplete.wav");
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,8 @@
|
||||
#ifndef _settings_h
|
||||
#define _settings_h
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
/* holds user setting values */
|
||||
struct user_settings {
|
||||
int autolog; /* boolean */
|
||||
@ -31,8 +33,21 @@ 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 */
|
||||
char download_path[MAX_STR_SIZE];
|
||||
int show_typing_self; /* boolean */
|
||||
int show_typing_other; /* boolean */
|
||||
|
||||
char download_path[PATH_MAX];
|
||||
char chatlogs_path[PATH_MAX];
|
||||
|
||||
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 +68,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 */
|
||||
|
417
src/toxic.c
417
src/toxic.c
@ -37,6 +37,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <tox/tox.h>
|
||||
|
||||
@ -67,19 +68,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,22 +82,38 @@ 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);
|
||||
close_all_file_senders(m);
|
||||
kill_all_windows();
|
||||
kill_all_windows(m);
|
||||
|
||||
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 +129,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 +137,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) {
|
||||
@ -166,23 +176,93 @@ static void init_term(void)
|
||||
refresh();
|
||||
}
|
||||
|
||||
static Tox *init_tox(int ipv4)
|
||||
{
|
||||
/* Init core */
|
||||
int ipv6 = !ipv4;
|
||||
Tox *m = tox_new(ipv6);
|
||||
static struct _init_messages {
|
||||
char **msgs;
|
||||
int num;
|
||||
} init_messages;
|
||||
|
||||
/*
|
||||
* TOX_ENABLE_IPV6_DEFAULT is always 1.
|
||||
* Checking it is redundant, this *should* be doing ipv4 fallback
|
||||
*/
|
||||
if (ipv6 && m == NULL) {
|
||||
fprintf(stderr, "IPv6 didn't initialize, trying IPv4\n");
|
||||
m = tox_new(0);
|
||||
/* One-time queue for messages created during init. Do not use after program init. */
|
||||
static void queue_init_message(const char *msg)
|
||||
{
|
||||
int i = init_messages.num;
|
||||
++init_messages.num;
|
||||
|
||||
char **new_msgs = realloc(init_messages.msgs, sizeof(char *) * init_messages.num);
|
||||
|
||||
if (new_msgs == NULL)
|
||||
exit_toxic_err("Failed in queue_init_message", FATALERR_MEMORY);
|
||||
|
||||
new_msgs[i] = malloc(MAX_STR_SIZE);
|
||||
|
||||
if (new_msgs[i] == NULL)
|
||||
exit_toxic_err("Failed in queue_init_message", FATALERR_MEMORY);
|
||||
|
||||
snprintf(new_msgs[i], MAX_STR_SIZE, "%s", msg);
|
||||
init_messages.msgs = new_msgs;
|
||||
}
|
||||
|
||||
/* called after messages have been printed to console and are no longer needed */
|
||||
static void cleanup_init_messages(void)
|
||||
{
|
||||
if (init_messages.num <= 0)
|
||||
return;
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < init_messages.num; ++i)
|
||||
free(init_messages.msgs[i]);
|
||||
|
||||
free(init_messages.msgs);
|
||||
}
|
||||
|
||||
static void print_init_messages(ToxWindow *toxwin)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < init_messages.num; ++i)
|
||||
line_info_add(toxwin, NULL, NULL, NULL, SYS_MSG, 0, 0, init_messages.msgs[i]);
|
||||
}
|
||||
|
||||
static Tox *init_tox(void)
|
||||
{
|
||||
Tox_Options tox_opts;
|
||||
tox_opts.ipv6enabled = !arg_opts.use_ipv4;
|
||||
tox_opts.udp_disabled = arg_opts.force_tcp;
|
||||
tox_opts.proxy_enabled = arg_opts.use_proxy;
|
||||
|
||||
if (tox_opts.proxy_enabled) {
|
||||
tox_opts.proxy_port = arg_opts.proxy_port;
|
||||
snprintf(tox_opts.proxy_address, sizeof(tox_opts.proxy_address), "%s", arg_opts.proxy_address);
|
||||
|
||||
char tmp[48];
|
||||
snprintf(tmp, sizeof(tmp), "Using proxy %s : %d",
|
||||
arg_opts.proxy_address, arg_opts.proxy_port);
|
||||
queue_init_message(tmp);
|
||||
}
|
||||
|
||||
if (ipv4)
|
||||
fprintf(stderr, "Forcing IPv4 connection\n");
|
||||
if (tox_opts.udp_disabled) {
|
||||
queue_init_message("UDP disabled");
|
||||
} else if (tox_opts.proxy_enabled) {
|
||||
const char *msg = "WARNING: Using a proxy without disabling UDP may leak your real IP address.";
|
||||
queue_init_message(msg);
|
||||
msg = "Use the -t option to disable UDP.";
|
||||
queue_init_message(msg);
|
||||
}
|
||||
|
||||
/* Init core */
|
||||
Tox *m = tox_new(&tox_opts);
|
||||
|
||||
if (tox_opts.ipv6enabled && m == NULL) {
|
||||
queue_init_message("IPv6 failed to initialize");
|
||||
tox_opts.ipv6enabled = 0;
|
||||
m = tox_new(&tox_opts);
|
||||
}
|
||||
|
||||
if (!tox_opts.ipv6enabled)
|
||||
queue_init_message("Forcing IPv4 connection");
|
||||
|
||||
if (tox_opts.proxy_enabled && m == NULL)
|
||||
exit_toxic_err("Proxy error", FATALERR_PROXY);
|
||||
|
||||
if (m == NULL)
|
||||
return NULL;
|
||||
@ -217,10 +297,10 @@ static Tox *init_tox(int ipv4)
|
||||
return m;
|
||||
}
|
||||
|
||||
#define MINLINE 50 /* IP: 7 + port: 5 + key: 38 + spaces: 2 = 70. ! (& e.g. tox.im = 6) */
|
||||
#define MAXLINE 256 /* Approx max number of chars in a sever line (name + port + key) */
|
||||
#define MIN_NODE_LINE 50 /* IP: 7 + port: 5 + key: 38 + spaces: 2 = 70. ! (& e.g. tox.im = 6) */
|
||||
#define MAX_NODE_LINE 256 /* Approx max number of chars in a sever line (name + port + key) */
|
||||
#define MAXNODES 50
|
||||
#define NODELEN (MAXLINE - TOX_CLIENT_ID_SIZE - 7)
|
||||
#define NODELEN (MAX_NODE_LINE - TOX_CLIENT_ID_SIZE - 7)
|
||||
|
||||
static struct _toxNodes {
|
||||
int lines;
|
||||
@ -229,7 +309,7 @@ static struct _toxNodes {
|
||||
char keys[MAXNODES][TOX_CLIENT_ID_SIZE];
|
||||
} toxNodes;
|
||||
|
||||
static int nodelist_load(const char *filename)
|
||||
static int load_nodelist(const char *filename)
|
||||
{
|
||||
if (!filename)
|
||||
return 1;
|
||||
@ -239,10 +319,10 @@ static int nodelist_load(const char *filename)
|
||||
if (fp == NULL)
|
||||
return 1;
|
||||
|
||||
char line[MAXLINE];
|
||||
char line[MAX_NODE_LINE];
|
||||
|
||||
while (fgets(line, sizeof(line), fp) && toxNodes.lines < MAXNODES) {
|
||||
if (strlen(line) > MINLINE) {
|
||||
if (strlen(line) > MIN_NODE_LINE) {
|
||||
const char *name = strtok(line, " ");
|
||||
const char *port = strtok(NULL, " ");
|
||||
const char *key_ascii = strtok(NULL, " ");
|
||||
@ -253,7 +333,7 @@ static int nodelist_load(const char *filename)
|
||||
|
||||
snprintf(toxNodes.nodes[toxNodes.lines], sizeof(toxNodes.nodes[toxNodes.lines]), "%s", name);
|
||||
toxNodes.nodes[toxNodes.lines][NODELEN - 1] = 0;
|
||||
toxNodes.ports[toxNodes.lines] = htons(atoi(port));
|
||||
toxNodes.ports[toxNodes.lines] = atoi(port);
|
||||
|
||||
char *key_binary = hex_string_to_bin(key_ascii);
|
||||
memcpy(toxNodes.keys[toxNodes.lines], key_binary, TOX_CLIENT_ID_SIZE);
|
||||
@ -263,19 +343,17 @@ static int nodelist_load(const char *filename)
|
||||
}
|
||||
}
|
||||
|
||||
if (toxNodes.lines < 1) {
|
||||
fclose(fp);
|
||||
return 2;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if (toxNodes.lines < 1)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int init_connection_helper(Tox *m, int line)
|
||||
{
|
||||
return tox_bootstrap_from_address(m, toxNodes.nodes[line], TOX_ENABLE_IPV6_DEFAULT,
|
||||
toxNodes.ports[line], (uint8_t *) toxNodes.keys[line]);
|
||||
return tox_bootstrap_from_address(m, toxNodes.nodes[line], toxNodes.ports[line], (uint8_t *) toxNodes.keys[line]);
|
||||
}
|
||||
|
||||
/* Connects to a random DHT node listed in the DHTnodes file
|
||||
@ -304,11 +382,11 @@ int init_connection(Tox *m)
|
||||
int res;
|
||||
|
||||
if (!arg_opts.nodes_path[0])
|
||||
res = nodelist_load(PACKAGE_DATADIR "/DHTnodes");
|
||||
res = load_nodelist(PACKAGE_DATADIR "/DHTnodes");
|
||||
else
|
||||
res = nodelist_load(arg_opts.nodes_path);
|
||||
res = load_nodelist(arg_opts.nodes_path);
|
||||
|
||||
if (toxNodes.lines < 1)
|
||||
if (res != 0)
|
||||
return res;
|
||||
|
||||
res = 3;
|
||||
@ -331,6 +409,9 @@ int init_connection(Tox *m)
|
||||
|
||||
static void do_connection(Tox *m, ToxWindow *prompt)
|
||||
{
|
||||
if (arg_opts.no_connect == 1)
|
||||
return;
|
||||
|
||||
char msg[MAX_STR_SIZE] = {0};
|
||||
|
||||
static int conn_err = 0;
|
||||
@ -345,7 +426,7 @@ static void do_connection(Tox *m, ToxWindow *prompt)
|
||||
if (!was_connected && is_connected) {
|
||||
was_connected = true;
|
||||
prompt_update_connectionstatus(prompt, was_connected);
|
||||
snprintf(msg, sizeof(msg), "DHT connected.");
|
||||
snprintf(msg, sizeof(msg), "DHT connected");
|
||||
} else if (was_connected && !is_connected) {
|
||||
was_connected = false;
|
||||
prompt_update_connectionstatus(prompt, was_connected);
|
||||
@ -361,7 +442,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 +452,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 +470,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 +484,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 +525,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);
|
||||
@ -456,7 +540,10 @@ static void do_toxic(Tox *m, ToxWindow *prompt)
|
||||
pthread_mutex_lock(&Winthread.lock);
|
||||
do_connection(m, prompt);
|
||||
do_file_senders(m);
|
||||
tox_do(m); /* main tox-core loop */
|
||||
|
||||
if (arg_opts.no_connect == 0)
|
||||
tox_do(m); /* main tox-core loop */
|
||||
|
||||
pthread_mutex_unlock(&Winthread.lock);
|
||||
}
|
||||
|
||||
@ -489,20 +576,30 @@ void *thread_winref(void *data)
|
||||
static void print_usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: toxic [OPTION] [FILE ...]\n");
|
||||
fprintf(stderr, " -f, --file Use specified data file\n");
|
||||
fprintf(stderr, " -x, --nodata Ignore data file\n");
|
||||
fprintf(stderr, " -4, --ipv4 Force IPv4 connection\n");
|
||||
fprintf(stderr, " -d, --default_locale Use default locale\n");
|
||||
fprintf(stderr, " -b --debug Enable stderr for debugging\n");
|
||||
fprintf(stderr, " -c, --config Use specified config file\n");
|
||||
fprintf(stderr, " -n, --nodes Use specified DHTnodes file\n");
|
||||
fprintf(stderr, " -d, --default-locale Use default POSIX locale\n");
|
||||
fprintf(stderr, " -f, --file Use specified data file\n");
|
||||
fprintf(stderr, " -h, --help Show this message and exit\n");
|
||||
fprintf(stderr, " -n, --nodes Use specified DHTnodes file\n");
|
||||
fprintf(stderr, " -o, --noconnect Do not connect to the DHT network\n");
|
||||
fprintf(stderr, " -p, --proxy Use proxy: Requires [IP] [port]\n");
|
||||
fprintf(stderr, " -r, --dnslist Use specified DNSservers file\n");
|
||||
fprintf(stderr, " -t, --force-tcp Force TCP connection (use this with proxies)\n");
|
||||
fprintf(stderr, " -x, --nodata Ignore data file\n");
|
||||
}
|
||||
|
||||
static void set_default_opts(void)
|
||||
{
|
||||
arg_opts.use_ipv4 = 0;
|
||||
arg_opts.ignore_data_file = 0;
|
||||
arg_opts.debug = 0;
|
||||
arg_opts.default_locale = 0;
|
||||
arg_opts.use_custom_data = 0;
|
||||
arg_opts.no_connect = 0;
|
||||
arg_opts.force_tcp = 0;
|
||||
arg_opts.use_proxy = 0;
|
||||
}
|
||||
|
||||
static void parse_args(int argc, char *argv[])
|
||||
@ -513,43 +610,99 @@ static void parse_args(int argc, char *argv[])
|
||||
{"file", required_argument, 0, 'f'},
|
||||
{"nodata", no_argument, 0, 'x'},
|
||||
{"ipv4", no_argument, 0, '4'},
|
||||
{"default_locale", no_argument, 0, 'd'},
|
||||
{"debug", no_argument, 0, 'b'},
|
||||
{"default-locale", no_argument, 0, 'd'},
|
||||
{"config", required_argument, 0, 'c'},
|
||||
{"nodes", required_argument, 0, 'n'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"noconnect", no_argument, 0, 'o'},
|
||||
{"dnslist", required_argument, 0, 'r'},
|
||||
{"force-tcp", no_argument, 0, 't'},
|
||||
{"proxy", required_argument, 0, 'p'},
|
||||
{NULL, no_argument, NULL, 0},
|
||||
};
|
||||
|
||||
const char *opts_str = "4xdf:c:n:h";
|
||||
const char *opts_str = "4bdhotxc:f:n:r:p:";
|
||||
int opt, indexptr;
|
||||
|
||||
while ((opt = getopt_long(argc, argv, opts_str, long_opts, &indexptr)) != -1) {
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
DATA_FILE = strdup(optarg);
|
||||
|
||||
if (DATA_FILE == NULL)
|
||||
exit_toxic_err("failed in parse_args", FATALERR_MEMORY);
|
||||
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
arg_opts.ignore_data_file = 1;
|
||||
break;
|
||||
|
||||
case '4':
|
||||
arg_opts.use_ipv4 = 1;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
snprintf(arg_opts.config_path, sizeof(arg_opts.config_path), "%s", optarg);
|
||||
case 'b':
|
||||
arg_opts.debug = 1;
|
||||
queue_init_message("stderr enabled");
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
snprintf(arg_opts.nodes_path, sizeof(arg_opts.nodes_path), "%s", optarg);
|
||||
case 'c':
|
||||
snprintf(arg_opts.config_path, sizeof(arg_opts.config_path), "%s", optarg);
|
||||
|
||||
if (!file_exists(arg_opts.config_path))
|
||||
queue_init_message("Config file not found");
|
||||
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
arg_opts.default_locale = 1;
|
||||
queue_init_message("Using default POSIX locale");
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
arg_opts.use_custom_data = 1;
|
||||
DATA_FILE = strdup(optarg);
|
||||
BLOCK_FILE = malloc(strlen(optarg) + strlen("-blocklist") + 1);
|
||||
|
||||
if (DATA_FILE == NULL || BLOCK_FILE == NULL)
|
||||
exit_toxic_err("failed in parse_args", FATALERR_MEMORY);
|
||||
|
||||
strcpy(BLOCK_FILE, optarg);
|
||||
strcat(BLOCK_FILE, "-blocklist");
|
||||
|
||||
char tmp[PATH_MAX];
|
||||
snprintf(tmp, sizeof(tmp), "Using '%s' data file", DATA_FILE);
|
||||
queue_init_message(tmp);
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
snprintf(arg_opts.nodes_path, sizeof(arg_opts.nodes_path), "%s", optarg);
|
||||
|
||||
if (!file_exists(arg_opts.nodes_path))
|
||||
queue_init_message("DHTnodes file not found");
|
||||
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
arg_opts.no_connect = 1;
|
||||
queue_init_message("DHT disabled");
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
arg_opts.use_proxy = 1;
|
||||
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
|
||||
|
||||
if (++optind > argc || argv[optind-1][0] == '-')
|
||||
exit_toxic_err("Proxy error", FATALERR_PROXY);
|
||||
|
||||
arg_opts.proxy_port = (uint16_t) atoi(argv[optind-1]);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
snprintf(arg_opts.dns_path, sizeof(arg_opts.dns_path), "%s", optarg);
|
||||
|
||||
if (!file_exists(arg_opts.dns_path))
|
||||
queue_init_message("DNSservers file not found");
|
||||
|
||||
break;
|
||||
|
||||
case 't':
|
||||
arg_opts.force_tcp = 1;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
arg_opts.ignore_data_file = 1;
|
||||
queue_init_message("Ignoring data file");
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
@ -560,39 +713,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));
|
||||
@ -603,9 +788,13 @@ int main(int argc, char *argv[])
|
||||
char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL;
|
||||
int settings_err = settings_load(user_settings_, p);
|
||||
|
||||
Tox *m = init_tox(arg_opts.use_ipv4);
|
||||
Tox *m = init_tox();
|
||||
init_term();
|
||||
|
||||
/* enable stderr for debugging */
|
||||
if (!arg_opts.debug)
|
||||
freopen("/dev/null", "w", stderr);
|
||||
|
||||
if (m == NULL)
|
||||
exit_toxic_err("failed in main", FATALERR_NETWORKINIT);
|
||||
|
||||
@ -613,6 +802,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)
|
||||
@ -624,38 +814,40 @@ int main(int argc, char *argv[])
|
||||
#ifdef _AUDIO
|
||||
|
||||
av = init_audio(prompt, m);
|
||||
|
||||
|
||||
|
||||
|
||||
set_primary_device(input, user_settings_->audio_in_dev);
|
||||
set_primary_device(output, user_settings_->audio_out_dev);
|
||||
|
||||
#elif _SOUND_NOTIFY
|
||||
if ( init_devices() == de_InternalError )
|
||||
line_info_add(prompt, NULL, NULL, NULL, "Failed to init devices", SYS_MSG, 0, 0);
|
||||
queue_init_message("Failed to init audio 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...";
|
||||
queue_init_message(msg);
|
||||
}
|
||||
|
||||
if (settings_err == -1) {
|
||||
msg = "Failed to load user settings";
|
||||
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
|
||||
}
|
||||
if (settings_err == -1)
|
||||
queue_init_message("Failed to load user settings");
|
||||
|
||||
sort_friendlist_index();
|
||||
prompt_init_statusbar(prompt, m);
|
||||
print_init_messages(prompt);
|
||||
cleanup_init_messages();
|
||||
|
||||
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 +862,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;
|
||||
|
10
src/toxic.h
10
src/toxic.h
@ -42,7 +42,6 @@
|
||||
|
||||
#define UNKNOWN_NAME "Anonymous"
|
||||
|
||||
#define MAX_FRIENDS_NUM 999
|
||||
#define MAX_STR_SIZE TOX_MAX_MESSAGE_LENGTH
|
||||
#define MAX_CMDNAME_SIZE 64
|
||||
#define TOXIC_MAX_NAME_LENGTH 32 /* Must be <= TOX_MAX_NAME_LENGTH */
|
||||
@ -50,7 +49,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 +62,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 */
|
||||
@ -75,6 +78,7 @@ typedef enum _FATAL_ERRS {
|
||||
FATALERR_NETWORKINIT = -8, /* Tox network failed to init */
|
||||
FATALERR_INFLOOP = -9, /* infinite loop detected */
|
||||
FATALERR_WININIT = -10, /* window init failed */
|
||||
FATALERR_PROXY = -11, /* Tox network failed to init using a proxy */
|
||||
} FATAL_ERRS;
|
||||
|
||||
/* Fixes text color problem on some terminals.
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
@ -95,9 +100,6 @@ void on_action(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t len
|
||||
|
||||
void on_nickchange(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata)
|
||||
{
|
||||
if (friendnumber < 0 || friendnumber > MAX_FRIENDS_NUM)
|
||||
return;
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
@ -267,7 +269,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)
|
||||
@ -366,13 +368,12 @@ void on_window_resize(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_window_tab(ToxWindow toxwin)
|
||||
static void draw_window_tab(ToxWindow *toxwin)
|
||||
{
|
||||
if (toxwin.alert) attron(COLOR_PAIR(toxwin.alert));
|
||||
if (toxwin->alert != WINDOW_ALERT_NONE) attron(COLOR_PAIR(toxwin->alert));
|
||||
clrtoeol();
|
||||
printw(" [%s]", toxwin.name);
|
||||
|
||||
if (toxwin.alert) attroff(COLOR_PAIR(toxwin.alert));
|
||||
printw(" [%s]", toxwin->name);
|
||||
if (toxwin->alert != WINDOW_ALERT_NONE) attroff(COLOR_PAIR(toxwin->alert));
|
||||
}
|
||||
|
||||
static void draw_bar(void)
|
||||
@ -402,7 +403,7 @@ static void draw_bar(void)
|
||||
|
||||
attron(A_BOLD);
|
||||
|
||||
draw_window_tab(windows[i]);
|
||||
draw_window_tab(&windows[i]);
|
||||
|
||||
if (windows + i == active_window)
|
||||
|
||||
@ -452,7 +453,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,22 +476,34 @@ 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 (i >= 0 && i <= MAX_WINDOWS_NUM && windows[i].active)
|
||||
toxwin = &windows[i];
|
||||
|
||||
return toxwin;
|
||||
}
|
||||
|
||||
int get_num_active_windows(void)
|
||||
{
|
||||
return num_active_windows;
|
||||
}
|
||||
|
||||
/* destroys all chat and groupchat windows (should only be called on shutdown) */
|
||||
void kill_all_windows(void)
|
||||
void kill_all_windows(Tox *m)
|
||||
{
|
||||
kill_prompt_window(prompt);
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i].is_chat)
|
||||
kill_chat_window(&windows[i]);
|
||||
kill_chat_window(&windows[i], m);
|
||||
else if (windows[i].is_groupchat)
|
||||
kill_groupchat_window(&windows[i]);
|
||||
}
|
||||
|
||||
kill_prompt_window(prompt);
|
||||
kill_friendlist();
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ enum {
|
||||
BLACK,
|
||||
} C_COLOURS;
|
||||
|
||||
/* tab alert types: lower types take priority */
|
||||
/* tab alert types: lower types take priority (this relies on the order of C_COLOURS) */
|
||||
typedef enum {
|
||||
WINDOW_ALERT_NONE = 0,
|
||||
WINDOW_ALERT_0 = GREEN,
|
||||
@ -71,6 +71,24 @@ struct _Winthread {
|
||||
bool flag_resize;
|
||||
};
|
||||
|
||||
struct arg_opts {
|
||||
int ignore_data_file;
|
||||
int use_ipv4;
|
||||
int force_tcp;
|
||||
int debug;
|
||||
int default_locale;
|
||||
int use_custom_data;
|
||||
int no_connect;
|
||||
|
||||
char dns_path[MAX_STR_SIZE];
|
||||
char config_path[MAX_STR_SIZE];
|
||||
char nodes_path[MAX_STR_SIZE];
|
||||
|
||||
int use_proxy;
|
||||
char proxy_address[256];
|
||||
uint16_t proxy_port;
|
||||
};
|
||||
|
||||
typedef struct ToxWindow ToxWindow;
|
||||
typedef struct StatusBar StatusBar;
|
||||
typedef struct PromptBuf PromptBuf;
|
||||
@ -116,12 +134,11 @@ struct ToxWindow {
|
||||
* Don't modify outside av callbacks. */
|
||||
int device_selection[2]; /* -1 if not set, if set uses these selections instead of primary device */
|
||||
|
||||
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 */
|
||||
bool active;
|
||||
@ -215,8 +232,9 @@ int add_window(Tox *m, ToxWindow w);
|
||||
void del_window(ToxWindow *w);
|
||||
void set_active_window(int ch);
|
||||
int get_num_active_windows(void);
|
||||
void kill_all_windows(void); /* should only be called on shutdown */
|
||||
void kill_all_windows(Tox *m); /* 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 */
|
||||
|
Reference in New Issue
Block a user