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

Compare commits

...

149 Commits

Author SHA1 Message Date
2ce42ab057 bump version to 0.5.0 2014-09-01 18:56:20 -04:00
934459dea8 show connection change message in chat windows 2014-08-31 14:17:33 -04:00
52bc874675 Merge pull request #234 from Ansa89/trivial-fix
Cosmetic fixes
2014-08-31 11:26:48 +02:00
511907fbc5 better way to check if files exist 2014-08-27 22:51:46 -04:00
155e194174 fix segfault on unknown long option 2014-08-27 14:30:06 -04:00
b1c7e21ca9 fix possible segfaults 2014-08-27 13:54:02 -04:00
7edcf6cb45 add setting to set path for chatlogs 2014-08-26 23:56:37 -04:00
9581940cfa Cosmetic fixes 2014-08-26 10:39:43 +02:00
f2aa57c4fa additional messages for startup options 2014-08-26 02:28:05 -04:00
8bf4405fd0 fix error code 2014-08-25 19:55:00 -04:00
21ef1788ca print init messages to prompt window intead of stderr 2014-08-25 19:26:41 -04:00
68f1dffba7 add command to decline friend requests 2014-08-25 14:08:01 -04:00
092df2c0e4 Merge pull request #231 from Ansa89/trivial-fix
Reworked manpage build system
2014-08-25 14:12:12 +02:00
691f94c75c README.md: second try 2014-08-25 12:59:34 +02:00
d6d4476e85 README.md: better look 2014-08-25 12:56:14 +02:00
924e8e0860 Reworked manpage build system 2014-08-25 12:54:44 +02:00
53193e933f Merge pull request #230 from louipc/manpage
Manpage
2014-08-25 00:49:31 -04:00
328587ad9c doc: Make asciidoc extra optional.
Completely separate man page generation from the main build to satisfy
travis-ci behaviour.

Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-24 17:00:25 -04:00
1a8fdb1b99 Make asciidoc 'optional'
Run `make doc` in the build directory after editing the asciidoc to
regenerate the manpages. Changes to asciidoc source and generated man
pages will need to be commited together.

Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-24 16:34:16 -04:00
690f0221b5 Add generated man pages.
Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-24 00:16:55 -04:00
e117bd3985 Add Asciidoc to README and travis
Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-21 05:00:15 -04:00
15cc87bffd Remove old man pages.
Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-21 04:40:10 -04:00
97d4c97c52 Generate man pages from asciidoc
Working directly with g/roff is a pain.
Also changed the formatting of toxic.conf.5 a bit.

Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-21 04:39:24 -04:00
c8b22d7e8a Merge pull request #229 from Ansa89/trivial-fix
toxic.conf.example: better formatting
2014-08-20 13:12:41 -04:00
f48ec4f49b array bounds fix 2014-08-20 13:10:21 -04:00
d4ce697bd9 toxic.conf.example: better formatting 2014-08-20 12:40:32 +02:00
bd20513493 a few fixes 2014-08-19 23:41:43 -04:00
fd3f4eb724 Merge branch 'master' of https://github.com/Tox/toxic 2014-08-19 20:55:38 -04:00
75e8486061 add command to list pending friend requests, a few related fixes 2014-08-19 20:52:17 -04:00
bd216709fc Merge pull request #226 from Ansa89/freebsd-man
Fix Tox/toxic#222 and reorganize cfg dir
2014-08-19 13:04:52 -04:00
a3a8f7608a Fix Tox/toxic#222 and reorganize cfg dir 2014-08-19 18:22:57 +02:00
affc88d0a8 error checking for file senders, fixes 2014-08-17 15:32:38 -04:00
eca4882ce2 transfer progress bar fix 2014-08-17 13:50:22 -04:00
58b0a04019 separate file transfer updates from callbacks 2014-08-17 00:11:49 -04:00
b870679f2c allow resuming of broken file transfers (needs testing) 2014-08-16 17:20:53 -04:00
ae83725cb6 Merge pull request #223 from louipc/master
Add debug flag and update man page.
2014-08-16 02:59:55 -04:00
595e42b587 Clarify function of -b switch.
Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-16 02:35:21 -04:00
f5401df2c7 doc/toxic: Add missing flags and sort alphabetically.
Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-15 19:26:06 -04:00
3e79a5ca8b Add -b flag for debugging
For now this just prints messages to stderr, so the user should manually
redirect stderr to avoid breaking the ui. This can be later expanded
upon to provide debugging messages in the command window.

Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-15 19:06:16 -04:00
327081945e update DHTnodes 2014-08-15 18:17:03 -04:00
68ec484a58 don't allow DNS lookups when using a proxy + forced TCP & fix arg parsing 2014-08-15 15:13:35 -04:00
1d6ccf56a8 name conflict with core function might cause linking error 2014-08-15 12:22:39 -04:00
67f637a1e1 redirect stderr before audio init to prevent error spam 2014-08-14 21:31:28 -04:00
5e175d5319 Merge pull request #220 from louipc/master
new tox_bootstrap_from_address() behaviour and a minor ui change
2014-08-14 20:47:17 -04:00
778db0fece core change: ports no longer in network byte order 2014-08-14 20:38:33 -04:00
72010dd2e1 allow connections through proxies 2014-08-14 20:31:52 -04:00
39556b36f3 port is no longer passed in network byte order to tox_bootstrap_from_address()
Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-14 20:10:14 -04:00
dc9ffa6e56 ipv6enabled parameter was removed in toxcore.
Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-14 19:51:52 -04:00
1e92bb3c2b help: lowercase keybinding hints for clarity.
Seeing the uppercase character I expected it to be the actual key.

Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-14 19:22:59 -04:00
edbdf2966a toxcore API update, add option to force TCP connection 2014-08-14 18:45:41 -04:00
3f6fd734d3 Merge pull request #218 from louipc/louipc
toxic.conf.5: Remove default config from man page
2014-08-14 12:05:33 -04:00
919a06d282 toxic.conf.5: Remove default config from man page
The reference to the config example in the FILES section should be sufficient.

Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2014-08-14 01:13:27 -04:00
35cc815cdb add option to specify DNSservers path 2014-08-12 22:32:36 -04:00
a318bdb034 add option to not connect to the DHT network 2014-08-12 18:59:27 -04:00
d6aaa95b25 ignore invalid file data callbacks 2014-08-12 15:27:42 -04:00
5718ad52db a few fixes 2014-08-12 03:01:18 -04:00
0f4cffbacc a few dns fixes 2014-08-11 01:59:01 -04:00
d9a861331f Use DNS server list instead of hard coding domains/keys 2014-08-10 21:40:19 -04:00
2f12a8d429 prevent statusmessage from wrapping on prompt screen 2014-08-10 00:37:26 -04:00
e75cf4f3ad fix bug where tab alert colours weren't being properly prioritized 2014-08-08 13:39:05 -04:00
bb85f31bb2 convert bytes for file transfer message, general fixes 2014-08-07 19:31:36 -04:00
396d08f0d2 refactor friend/blocklist, dynamically allocate memory 2014-08-07 13:24:29 -04:00
6ab184e7ce file transfer improvements and bug fixes 2014-08-05 17:38:33 -04:00
fd65fbfd0c temporarily disabling clang in travis script due to weird errors unrelated to toxic 2014-08-05 00:27:55 -04:00
637ea0ed55 attempt to fix travis with clang 2014-08-05 00:16:01 -04:00
dc2d20f4c4 bump version to 0.4.7 2014-08-04 22:28:12 -04:00
d712ccc17e Merge pull request #215 from mannol1/master
Fix ringing sounds
2014-08-05 01:41:21 +02:00
147030e06f Fix ringing sounds 2014-08-05 01:41:06 +02:00
09fd5cb69f small fix 2014-08-04 18:04:54 -04:00
64db9f73a2 update file transfers for core changes 2014-08-04 16:47:45 -04:00
28633be2dd a few fixes and improve error messages 2014-08-04 14:35:34 -04:00
6fdafceda8 add ability to cancel file transfers 2014-08-04 02:03:23 -04:00
38ed0c86ad use hangup cmd to cancel outgoing call requests 2014-08-03 23:11:19 -04:00
ad23816096 fix filetransfer bug 2014-08-03 16:44:21 -04:00
bc4a730e76 re-adding until better solution found 2014-08-03 15:42:14 -04:00
79372cc80d don't show full path when sending files 2014-08-03 15:12:55 -04:00
c9e4246ac5 Merge branch 'master' of https://github.com/Tox/toxic 2014-08-03 11:54:49 -04:00
dcd6a238b6 Merge pull request #213 from doughdemon/master
Add missing includes
2014-08-03 11:48:03 -04:00
c49de7733c Add missing includes
Fixes compilation with musl libc
2014-08-03 09:44:48 +02:00
3fc7c90630 stderr redirect doesn't work as intended, add invalid command message when no sound 2014-08-03 01:31:33 -04:00
53663a7832 try to end curses session gracefully on SIGSEGV 2014-08-03 00:26:44 -04:00
c14f2a3fcd put chatlogs in their own directory 2014-08-02 21:03:59 -04:00
3cbe61e111 fix a few formatting bugs and simplify code a bit 2014-08-02 15:35:57 -04:00
fa023c6a99 Merge pull request #211 from mannol1/master
Fix bug
2014-08-02 19:22:45 +02:00
f98e6bdcb4 Fix bug 2014-08-02 19:21:40 +02:00
0884954c84 fix data file init bug 2014-08-02 13:04:29 -04:00
43727c6730 Merge pull request #210 from mannol1/master
Fresh pack of backdoors
2014-08-02 17:31:36 +02:00
618b731d5a fix possible buffer overflow 2014-08-01 23:00:52 -04:00
46975bf38b Updated with latest core 2014-08-02 02:10:21 +02:00
8f3989000d Box notifications are like ready 2014-08-02 00:37:02 +02:00
9fe75fbc47 fix 2014-08-01 15:05:10 -04:00
c455e79604 dynamically adjust main loop sleep time according to recommended value 2014-08-01 13:56:49 -04:00
a223545853 close chatwindow if its associated contact is blocked/deleted 2014-07-31 22:05:09 -04:00
b243f7aa62 Merge branch 'master' of https://github.com/Tox/toxic 2014-07-31 15:13:10 -04:00
899452d7cd Merge branch 'block' 2014-07-31 15:04:05 -04:00
af68fa7ee0 endian correctness 2014-07-31 15:02:19 -04:00
5da789cc37 save last online data in blocked list 2014-07-31 14:53:02 -04:00
7e5b41c8e0 another apple include: <sys/syslimits.h>
for NAME_MAX
2014-07-31 10:52:36 -07:00
0254596c73 add help menu for friendlist 2014-07-31 13:49:15 -04:00
67c02404b7 alut is not part of OpenAL.framework on OS X
therefore the linux include path works fine
2014-07-31 10:38:04 -07:00
0b5ee7e2c7 Merge pull request #208 from Ansa89/makefile-update
Makefile: refactoring and adding desktop notifications support
2014-07-31 12:51:44 -04:00
fba0732faa implement contact blocking 2014-07-31 12:48:49 -04:00
d06086a656 Try to support older versions of OpenAL 2014-07-31 13:14:33 +02:00
e74b678739 check_features.mk: modify string comparison 2014-07-31 11:54:22 +02:00
b62787ce47 Makefile: refactoring and adding desktop notifications support 2014-07-30 14:14:13 +02:00
75708f7600 couple small fixes 2014-07-30 02:46:08 -04:00
476dec46b6 add settings to toggle typing notifications for self and others 2014-07-29 20:14:44 -04:00
973f6206ee enforce const correctess, fix undefined behaviour with string literals 2014-07-29 14:54:34 -04:00
cbe47b3660 Merge pull request #207 from Ansa89/manpage-update
Update toxic.conf manpage
2014-07-29 11:51:58 -04:00
1c58c339bb Update toxic.conf manpage 2014-07-29 12:07:24 +02:00
15e91cfa99 formatting, use case-insensitive string compare, use defines for keycodes 2014-07-28 21:47:35 -04:00
f4fb6ea4fc Merge branch 'gracchus163-master' 2014-07-28 20:45:52 -04:00
0d2ff2c0a8 Fixed toxic.conf.example mistakes 2014-07-29 01:28:10 +01:00
5275da5a6b Merge branch 'keybinds'
configurable keybinds finished and working, merging with master branch
2014-07-29 00:55:39 +01:00
e891b1281b Configurable keybinds implemented and example conf updated 2014-07-29 00:53:44 +01:00
ca7110b37c small visual adjustment to progress bar 2014-07-28 19:36:30 -04:00
8960eb98f4 Example conf updated 2014-07-28 22:47:33 +01:00
18610668b8 Human readable config parsing complete, few tests left to confirm 2014-07-28 22:44:12 +01:00
efe61e32e2 Merge pull request #204 from zetok/symbol
Fix ONLINE_CHAR being identical to OFFLINE_CHAR
2014-07-28 13:39:40 -04:00
7a7e4f573a Fix ONLINE_CHAR being identical to OFFLINE_CHAR 2014-07-28 18:38:15 +01:00
a7e6ab7758 reads correctly from config file now, need to go through and check each one and then look at usability 2014-07-28 15:19:50 +01:00
a0cde4ae8c Merge remote-tracking branch 'origin/master' into keybinds 2014-07-28 14:06:54 +01:00
7566aa9d26 Merge pull request #205 from loadedice/master
Lowered volume of sounds
2014-07-28 03:14:29 -04:00
d2332a5b77 Lowered volume of sounds 2014-07-28 16:42:57 +10:00
94a8ce5aa8 fix buggy path autocomplete behaviour 2014-07-28 01:33:12 -04:00
b18a67d656 put file senders in a round-robin queue so multiple transfers upload at a uniform pace 2014-07-27 22:27:27 -04:00
02708534c0 Merge pull request #200 from mannol1/master
Core adjustments
2014-07-28 01:35:58 +02:00
d5710d80e0 Upstream adaption 2014-07-28 01:35:40 +02:00
8dcba3219d Merge remote-tracking branch 'origin/master' into keybinds 2014-07-28 00:32:05 +01:00
9f01a45b1f Keybind defaults moved to settings.c; conf keybinds not reading correctly yet 2014-07-28 00:06:25 +01:00
dd2cb93ecc Merge pull request #203 from zetok/manpages
Put man pages in right place by default (#202)
2014-07-27 18:15:32 -04:00
49538a986c improve file transfer progress line 2014-07-27 18:00:33 -04:00
26c2331d0f Put man pages in right place by default (#202) 2014-07-27 21:06:37 +01:00
a0758643c2 fix blurry screenshot? 2014-07-27 03:36:06 -04:00
77e152ad36 fix security flaw where untrusted input wasn't being sanitized 2014-07-26 21:22:55 -04:00
4834642b80 Merge remote-tracking branch 'upstream/master' 2014-07-27 01:50:06 +02:00
18a6f621f0 Started adding support for popup notifications and adjustments to new core 2014-07-27 01:49:59 +02:00
3cae1d92cd change online/offline symbols 2014-07-26 19:16:07 -04:00
02b192d6ee fix bug and typo 2014-07-25 20:17:22 -04:00
f630a3e604 fix possible buffer overflows and undefined behaviour 2014-07-25 17:55:21 -04:00
fb5a9bc043 fix backspace bug, simplify a bit 2014-07-25 15:51:29 -04:00
26ad5a00a3 Fixed out of bounds read. 2014-07-25 15:17:46 -04:00
18e1f08e31 Merge branch 'master' of https://github.com/Tox/toxic 2014-07-24 23:04:07 -04:00
b68deef6db allow line_info_add to take formatted strings with variable # of args 2014-07-24 23:03:55 -04:00
30ec7debba Merge pull request #199 from mannol1/master
Fixed sounds not playing
2014-07-25 02:13:24 +02:00
3a1e23a3ff Fixed sounds not playing 2014-07-25 02:12:32 +02:00
0887bb7662 Merge pull request #198 from Ansa89/master
README.md: add precompiled binaries
2014-07-24 13:24:51 +02:00
5a55f738a9 README.md: add precompiled binaries 2014-07-24 13:05:56 +02:00
8d8df585ad sort directories and skip special symbols for path autocomplete 2014-07-23 18:34:32 -04:00
74 changed files with 4017 additions and 1674 deletions

View File

@ -1,7 +1,7 @@
language: c
compiler:
- gcc
- clang
# - clang # Fix me
before_script:
# Installing yasm (needed for compiling vpx) and openal

View File

@ -1,7 +1,7 @@
# Toxic [![Build Status](https://travis-ci.org/Tox/toxic.png?branch=master)](https://travis-ci.org/Tox/toxic)
Toxic is a [Tox](https://tox.im)-based instant messenging client which formerly resided in the [Tox core repository](https://github.com/irungentoo/toxcore), and is now available as a standalone application.
![Toxic Screenshot](https://i.imgur.com/ueK1Tdj.png "Home Screen").
![Toxic Screenshot](https://i.imgur.com/ryaEmQZ.png "Home Screen")
## Installation
@ -12,13 +12,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).

View File

@ -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
View File

@ -0,0 +1,23 @@
# Variables for audio call support
AUDIO_LIBS = libtoxav openal
AUDIO_CFLAGS = -D_AUDIO
ifneq (, $(findstring device.o, $(OBJ)))
AUDIO_OBJ = audio_call.o
else
AUDIO_OBJ = audio_call.o device.o
endif
# Check if we can build audio support
CHECK_AUDIO_LIBS = $(shell pkg-config --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

View 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

View File

@ -0,0 +1,17 @@
# Variables for desktop notifications support
DESK_NOTIFY_LIBS = libnotify
DESK_NOTIFY_CFLAGS = -D_BOX_NOTIFY
# Check if we can build desktop notifications support
CHECK_DESK_NOTIFY_LIBS = $(shell pkg-config --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

View File

@ -0,0 +1,23 @@
# Variables for sound notifications support
SND_NOTIFY_LIBS = openal freealut
SND_NOTIFY_CFLAGS = -D_SOUND_NOTIFY
ifneq (, $(findstring device.o, $(OBJ)))
SND_NOTIFY_OBJ =
else
SND_NOTIFY_OBJ = device.o
endif
# Check if we can build sound notifications support
CHECK_SND_NOTIFY_LIBS = $(shell pkg-config --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
View 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

View File

@ -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
View File

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

View File

@ -1,3 +1,4 @@
# Specials options for freebsd systems
LIBS := $(filter-out ncursesw, $(LIBS))
LDFLAGS += -lncursesw
MANDIR = $(PREFIX)/man

View File

@ -1,3 +1,4 @@
# Specials options for linux systems
CFLAGS +=
LDFLAGS += -ldl -lresolv
MANDIR = $(PREFIX)/share/man

10
cfg/targets/doc.mk Normal file
View 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
View 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
View 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

View File

@ -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
View 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

View File

@ -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
View 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>

View File

@ -2,7 +2,9 @@
37.187.46.132 33445 A9D98212B3F972BD11DA52BEB0658C326FCCC1BFD49F347F9C2D3D8B61E1B927
144.76.60.215 33445 04119E835DF3E78BACF0F84235B300546AF8B936F035185E2A8E9E0A67C8924F
23.226.230.47 33445 A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074
37.187.20.216 33445 4FD54CFD426A338399767E56FD0F44F5E35FA8C38C8E87C8DC3FEAC0160F8E17
54.199.139.199 33445 7F9C31FE850E97CEFD4C4591DF93FC757C7C12549DDD55F8EEAECC34FE76C029
109.169.46.133 33445 7F31BFC93B8E4016A902144D0B110C3EA97CB7D43F1C4D21BCAE998A7C838821
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
View File

@ -0,0 +1,2 @@
utox.org d3154f65d28a5b41a05d4ac7e4b39c6b1c233cc857fb365c56e8392737462a12
toxme.se 5d72c517df6aec54f1e977a6b6f25914ea4cf7277a85027cd9f5196df17e0b13

View File

@ -3,20 +3,26 @@
ui = {
// true to enable timestamps, false to disable
timestamps:true;
timestamps=true;
// true to enable terminal alerts on messages, false to disable
alerts:true;
alerts=true;
// true to use native terminal colours, false to use toxic default colour theme
native_colors:false;
native_colors=false;
// true to enable autologging, false to disable
autolog:false;
autolog=false;
// 24 or 12 hour time
time_format=24;
// true to show you when others are typing a message in 1-on-1 chats
show_typing_other=true;
// true to show others when you're typing a message in 1-on-1 chats
show_typing_self=true;
// maximum lines for chat window history
history_size=700;
};
@ -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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

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

View File

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

View File

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

View File

@ -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);

View File

@ -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 */

View File

@ -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;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

176
src/dns.c
View File

@ -22,6 +22,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/types.h> /* for u_char */
#include <netinet/in.h>
#include <resolv.h>
@ -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);

View File

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

View File

@ -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.");
}

View File

@ -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 {

View File

@ -27,6 +27,7 @@
#include "toxic.h"
#include "windows.h"
#include "friendlist.h"
#include "file_senders.h"
#include "line_info.h"
#include "misc_tools.h"
@ -34,6 +35,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);
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);
/* kill file transfer if chatwindow is closed */
if (self->chatwin == NULL) {
close_file_sender(self, m, i, NULL, TOX_FILECONTROL_KILL, filenum, friendnum);
continue;
}
if (file_senders[i].piecelen == 0) {
snprintf(msg, sizeof(msg), "File '%s' successfuly sent.", pathname);
close_file_sender(self, m, i, msg, TOX_FILECONTROL_FINISHED, filenum, friendnum);
notify(self, transfer_completed, NT_NOFOCUS | NT_WNDALERT_2);
break;
}
/* If file transfer has timed out kill transfer and send kill control */
if (timed_out(file_senders[i].timestamp, get_unix_time(), TIMEOUT_FILESENDER)) {
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "File transfer for '%s' timed out.", filename);
close_file_sender(self, m, i, msg, TOX_FILECONTROL_KILL, filenum, friendnum);
sound_notify(self, error, NT_NOFOCUS | NT_WNDALERT_2, NULL);
if (self->active_box != -1)
box_notify2(self, error, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%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);
}

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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 */

View File

@ -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_requests(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (FriendRequests.num_requests == 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend requests.");
return;
}
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])
{
char *msg = NULL;
char *errmsg;
bool have_note = false;
const char *errmsg;
if (argc >= 2) {
msg = argv[2];
if (msg[0] != '\"') {
errmsg = "Note must be enclosed in quotes.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
return;
}
} else if (argc != 1) {
errmsg = "Wrong number of arguments.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
have_note = true;
} else if (argc < 1) {
errmsg = "Require a status. Statuses are: online, busy and away.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
return;
}
char *status = argv[1];
char status[MAX_STR_SIZE];
snprintf(status, sizeof(status), "%s", argv[1]);
str_to_lower(status);
TOX_USERSTATUS status_kind;
@ -425,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);
}
}

View File

@ -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);

View File

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

View File

@ -27,7 +27,7 @@
#include "help.h"
#include "misc_tools.h"
#define HELP_MENU_HEIGHT 7
#define HELP_MENU_HEIGHT 8
#define HELP_MENU_WIDTH 26
void help_init_menu(ToxWindow *self)
@ -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;
}

View File

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

View File

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

View File

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

View File

@ -26,7 +26,7 @@
#include "windows.h"
#include "toxic.h"
#define MAX_HISTORY 10000
#define MAX_HISTORY 100000
#define MIN_HISTORY 40
#define MAX_QUEUE 128
@ -67,9 +67,10 @@ struct history {
int queue_sz;
};
/* creates new line_info line and puts it in the queue */
void line_info_add(ToxWindow *self, char *tmstmp, char *name1, char *name2, const char *msg,
uint8_t type, uint8_t bold, uint8_t colour);
/* creates new line_info line and puts it in the queue.
SYS_MSG lines may contain an arbitrary number of arguments for string formatting */
void line_info_add(ToxWindow *self, char *tmstmp, char *name1, char *name2, uint8_t type, uint8_t bold,
uint8_t colour, const char *msg, ...);
/* Prints a section of history starting at line_start */
void line_info_print(ToxWindow *self);

View File

@ -34,7 +34,7 @@
extern struct user_settings *user_settings_;
/* Creates/fetches log file by appending to the config dir the name and a pseudo-unique identity */
void init_logging_session(char *name, char *key, struct chatlog *log)
void init_logging_session(char *name, const char *key, struct chatlog *log)
{
if (!log->log_on)
return;
@ -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;

View File

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

View File

@ -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:
@ -246,3 +282,32 @@ 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;
}

View File

@ -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 */

View File

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

View File

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

View File

@ -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;
}

View File

@ -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);

View File

@ -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,15 +181,34 @@ 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
@ -154,14 +224,14 @@ 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);
}
} else {
snprintf(path, sizeof(path), "%s", patharg);
}
@ -177,16 +247,49 @@ int settings_load(struct user_settings *s, const char *patharg)
config_setting_lookup_bool(setting, ui_strings.alerts, &s->alerts);
config_setting_lookup_bool(setting, ui_strings.autolog, &s->autolog);
config_setting_lookup_bool(setting, ui_strings.native_colors, &s->colour_theme);
config_setting_lookup_int(setting, ui_strings.history_size, &s->history_size);
config_setting_lookup_bool(setting, ui_strings.show_typing_self, &s->show_typing_self);
config_setting_lookup_bool(setting, ui_strings.show_typing_other, &s->show_typing_other);
config_setting_lookup_int(setting, ui_strings.time_format, &s->time);
s->time = s->time == TIME_24 || s->time == TIME_12 ? s->time : TIME_24; /* Check defaults */
}
/* 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
@ -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");
}
}

View File

@ -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 */

View File

@ -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);
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)
@ -628,34 +818,36 @@ int main(int argc, char *argv[])
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;

View File

@ -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.

View File

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

View File

@ -33,12 +33,14 @@
#include "chat.h"
#include "line_info.h"
#include "settings.h"
extern char *DATA_FILE;
extern struct _Winthread Winthread;
static ToxWindow windows[MAX_WINDOWS_NUM];
static ToxWindow *active_window;
extern ToxWindow *prompt;
extern struct user_settings *user_settings_;
static int num_active_windows;
@ -65,6 +67,9 @@ void on_connectionchange(Tox *m, int32_t friendnumber, uint8_t status, void *use
void on_typing_change(Tox *m, int32_t friendnumber, uint8_t is_typing, void *userdata)
{
if (user_settings_->show_typing_other == SHOW_TYPING_OFF)
return;
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
@ -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();
}

View File

@ -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,11 +134,10 @@ struct ToxWindow {
* Don't modify outside av callbacks. */
int device_selection[2]; /* -1 if not set, if set uses these selections instead of primary device */
int ringing_sound;
#endif /* _AUDIO */
#ifdef _SOUND_NOTIFY
int active_sound;
#endif
int active_box; /* For box notify */
char name[TOXIC_MAX_NAME_LENGTH];
int32_t num; /* corresponds to friendnumber in chat windows */
@ -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 */