mirror of
https://github.com/Tha14/toxic.git
synced 2025-06-28 00:06:45 +02:00
Compare commits
63 Commits
Author | SHA1 | Date | |
---|---|---|---|
e4abd8b36b | |||
9e3d4f3889 | |||
b7d67c1d86 | |||
c4a11f8dc7 | |||
d18cc8cbc2 | |||
ce6d4861fb | |||
8f0e6026f0 | |||
258736995d | |||
56e03a3f8b | |||
b6c746b5f5 | |||
03673cbced | |||
0fea930c24 | |||
94d22a8853 | |||
63cc23401a | |||
f90a774470 | |||
e7c5fbc873 | |||
d62902ffb3 | |||
bebff3be0e | |||
2be4847b53 | |||
4557614443 | |||
5b30ecf2e4 | |||
2413ad2b59 | |||
52855b805a | |||
20b5e46850 | |||
f2b796940e | |||
a37bf300f9 | |||
cb524dcbc3 | |||
4144b868ce | |||
af11f16bef | |||
1d27a496ef | |||
32bd9dc1a7 | |||
3cd2bc7e3c | |||
43ca840658 | |||
685837357b | |||
812a13b0fb | |||
641fa471d2 | |||
8d5755f2d8 | |||
af510b6666 | |||
46f646afcf | |||
68ce17a57f | |||
a69fad15c1 | |||
7621fe9a62 | |||
f6d9bc3a74 | |||
29aea0b42c | |||
815c29ee31 | |||
3917f664bf | |||
a223329815 | |||
3fec11d5f9 | |||
221edb0012 | |||
2710ab6034 | |||
bc3ffac0ba | |||
29f55c5277 | |||
a290f0f7f8 | |||
5cd196a769 | |||
b14d983a8c | |||
51f1daeec8 | |||
b799c6a8d7 | |||
b9f9546e2b | |||
846bc4613e | |||
a5a1f6015d | |||
fe6a7074ea | |||
db7c9fe426 | |||
0bd5b4ddee |
37
.travis.yml
Normal file
37
.travis.yml
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
---
|
||||||
|
language: python
|
||||||
|
python: nightly
|
||||||
|
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- astyle
|
||||||
|
- libalut-dev
|
||||||
|
- libconfig-dev
|
||||||
|
- libnotify-dev
|
||||||
|
- libopenal-dev
|
||||||
|
- libopus-dev
|
||||||
|
- libqrencode-dev
|
||||||
|
- libvpx-dev
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- $HOME/cache
|
||||||
|
|
||||||
|
install:
|
||||||
|
# Where to find libraries.
|
||||||
|
- export LD_LIBRARY_PATH=$HOME/cache/usr/lib
|
||||||
|
- export PKG_CONFIG_PATH=$HOME/cache/usr/lib/pkgconfig
|
||||||
|
# c-sodium
|
||||||
|
- git clone --depth=1 --branch=stable https://github.com/jedisct1/libsodium ../libsodium
|
||||||
|
- test -f $HOME/cache/usr/lib/libsodium.so || (cd ../libsodium && ./configure --prefix=$HOME/cache/usr && make install -j$(nproc))
|
||||||
|
# c-toxcore
|
||||||
|
- git clone --depth=1 https://github.com/TokTok/c-toxcore ../c-toxcore
|
||||||
|
- test -f $HOME/cache/usr/lib/libtoxcore.so || (cd ../c-toxcore && cmake -B_build -H. -DCMAKE_INSTALL_PREFIX:PATH=$HOME/cache/usr && make -C_build install -j$(nproc))
|
||||||
|
# astyle
|
||||||
|
- wget -O ../astyle.tar.gz https://deb.debian.org/debian/pool/main/a/astyle/astyle_2.06.orig.tar.gz
|
||||||
|
- test -f $HOME/cache/astyle/build/gcc/bin/astyle || (tar -xf ../astyle.tar.gz -C "$HOME/cache" && make -C "$HOME/cache/astyle/build/gcc" -j2)
|
||||||
|
|
||||||
|
script:
|
||||||
|
- $HOME/cache/astyle/build/gcc/bin/astyle --options=astylerc $(find . -name "*.[ch]")
|
||||||
|
- make ENABLE_PYTHON=1 -j2
|
30
BUILD.bazel
Normal file
30
BUILD.bazel
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
load("//tools/project:build_defs.bzl", "project")
|
||||||
|
|
||||||
|
project()
|
||||||
|
|
||||||
|
cc_binary(
|
||||||
|
name = "toxic",
|
||||||
|
srcs = glob([
|
||||||
|
"src/*.c",
|
||||||
|
"src/*.h",
|
||||||
|
]),
|
||||||
|
copts = [
|
||||||
|
"-DAUDIO",
|
||||||
|
"-DPACKAGE_DATADIR='\"data\"'",
|
||||||
|
"-DPYTHON",
|
||||||
|
"-DQRCODE",
|
||||||
|
"-DVIDEO",
|
||||||
|
"-Wno-error=unused-result",
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
"//c-toxcore",
|
||||||
|
"@curl",
|
||||||
|
"@libconfig",
|
||||||
|
"@libqrencode",
|
||||||
|
"@libvpx",
|
||||||
|
"@ncurses",
|
||||||
|
"@openal",
|
||||||
|
"@python3//:python",
|
||||||
|
"@x11",
|
||||||
|
],
|
||||||
|
)
|
44
INSTALL.md
44
INSTALL.md
@ -5,7 +5,7 @@
|
|||||||
* [Documentation](#documentation)
|
* [Documentation](#documentation)
|
||||||
* [Notes](#notes)
|
* [Notes](#notes)
|
||||||
* [Compilation variables](#compilation-variables)
|
* [Compilation variables](#compilation-variables)
|
||||||
* [Packaging](#packaging)
|
* [Environment variables](#environment-variables)
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
| Name | Needed by | Debian package |
|
| Name | Needed by | Debian package |
|
||||||
@ -15,8 +15,7 @@
|
|||||||
| [LibConfig](http://www.hyperrealm.com/libconfig) | BASE | libconfig-dev |
|
| [LibConfig](http://www.hyperrealm.com/libconfig) | BASE | libconfig-dev |
|
||||||
| [GNUmake](https://www.gnu.org/software/make) | BASE | make |
|
| [GNUmake](https://www.gnu.org/software/make) | BASE | make |
|
||||||
| [libcurl](http://curl.haxx.se/) | BASE | libcurl4-openssl-dev|
|
| [libcurl](http://curl.haxx.se/) | BASE | libcurl4-openssl-dev|
|
||||||
| [libqrencode](https://fukuchi.org/works/qrencode/) | BASE | libqrencode-dev |
|
| [libqrencode](https://fukuchi.org/works/qrencode/) | QRCODE | libqrencode-dev |
|
||||||
| [Tox Core AV](https://github.com/toktok/c-toxcore) | AUDIO | *None* |
|
|
||||||
| [OpenAL](http://openal.org) | AUDIO, SOUND NOTIFICATIONS | libopenal-dev |
|
| [OpenAL](http://openal.org) | AUDIO, SOUND NOTIFICATIONS | libopenal-dev |
|
||||||
| [OpenALUT](http://openal.org) | SOUND NOTIFICATIONS | libalut-dev |
|
| [OpenALUT](http://openal.org) | SOUND NOTIFICATIONS | libalut-dev |
|
||||||
| [LibNotify](https://developer.gnome.org/libnotify) | DESKTOP NOTIFICATIONS | libnotify-dev |
|
| [LibNotify](https://developer.gnome.org/libnotify) | DESKTOP NOTIFICATIONS | libnotify-dev |
|
||||||
@ -28,39 +27,40 @@
|
|||||||
#### OS X Notes
|
#### OS X Notes
|
||||||
Using [Homebrew](http://brew.sh):
|
Using [Homebrew](http://brew.sh):
|
||||||
```
|
```
|
||||||
brew install openal-soft freealut libconfig
|
brew install curl qrencode openal-soft freealut libconfig libpng
|
||||||
brew install --HEAD https://raw.githubusercontent.com/Tox/homebrew-tox/master/Formula/libtoxcore.rb
|
brew install --HEAD https://raw.githubusercontent.com/Tox/homebrew-tox/master/Formula/libtoxcore.rb
|
||||||
brew install libnotify
|
brew install libnotify
|
||||||
|
export PKG_CONFIG_PATH=/usr/local/opt/openal-soft/lib/pkgconfig
|
||||||
|
make
|
||||||
```
|
```
|
||||||
|
|
||||||
You can omit `libnotify` if you intend to build without desktop notifications enabled.
|
You can omit `libnotify` if you intend to build without desktop notifications enabled.
|
||||||
|
|
||||||
## Compiling
|
## Compiling
|
||||||
```
|
```
|
||||||
make PREFIX="/where/to/install"
|
make
|
||||||
sudo make install PREFIX="/where/to/install"
|
sudo make install
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Documentation
|
#### Documentation
|
||||||
Run `make doc` in the build directory after editing the asciidoc files to regenerate the manpages.<br />
|
Run `make doc` in the build directory after editing the asciidoc files to regenerate the manpages.<br />
|
||||||
**NOTE FOR DEVELOPERS**: asciidoc files and generated manpages will need to be commited together.<br />
|
**Note for developers**: asciidoc files and generated manpages will need to be committed together.<br />
|
||||||
**NOTE FOR EVERYONE**: [asciidoc](http://asciidoc.org/index.html) (and this step) is only required for regenerating manpages when you modify them.
|
**Note for everyone**: [asciidoc](http://asciidoc.org/index.html) (and this step) is only required for regenerating manpages when you modify them.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
#### Compilation variables
|
#### Compilation variables
|
||||||
* You can add specific flags to the Makefile with `USER_CFLAGS=""` and/or `USER_LDFLAGS=""`
|
* You can add specific flags to the Makefile with `USER_CFLAGS=""` and `USER_LDFLAGS=""` passed as arguments to make, or as environment variables
|
||||||
* You can pass your own flags to the Makefile with `CFLAGS=""` and/or `LDFLAGS=""` (this will supersede the default ones)
|
* Default compile options can be overridden by using special variables:
|
||||||
* Additional features are automatically enabled if all dependencies are found, but you can disable them by using special variables:
|
* `DISABLE_X11=1` → Disable X11 support (needed for focus tracking)
|
||||||
* `DISABLE_X11=1` → build toxic without X11 support (needed for focus tracking)
|
* `DISABLE_AV=1` → Disable audio call support
|
||||||
* `DISABLE_AV=1` → build toxic without audio call support
|
* `DISABLE_SOUND_NOTIFY=1` → Disable sound notifications support
|
||||||
* `DISABLE_SOUND_NOTIFY=1` → build toxic without sound notifications support
|
* `DISABLE_DESKTOP_NOTIFY=1` → Disable desktop notifications support
|
||||||
* `DISABLE_DESKTOP_NOTIFY=1` → build toxic without desktop notifications support
|
* `ENABLE_PYTHON=1` → Build toxic with Python scripting support
|
||||||
* Features excluded from the default build must be explicitly enabled using special variables:
|
|
||||||
* `ENABLE_PYTHON=1` → build toxic with Python scripting support
|
|
||||||
|
|
||||||
#### Packaging
|
* `DESTDIR=""` Specifies the base install directory for binaries and data files (e.g.: DESTDIR="/tmp/build/pkg")
|
||||||
* For packaging purpose, you can use `DESTDIR=""` to specify a directory where to store installed files
|
|
||||||
* `DESTDIR=""` can be used in addition to `PREFIX=""`:
|
#### Environment variables
|
||||||
* `DESTDIR=""` is meant to specify a directory where to store installed files (ex: "/tmp/build/pkg")
|
* You can use the `CFLAGS` and `LDFLAGS` environment variables to add specific flags to the Makefile
|
||||||
* `PREFIX=""` is meant to specify a prefix directory for binaries and data files (ex: "/usr/local")
|
* The `PREFIX` environment variable specifies a base install directory for binaries and data files. This is interchangeable with the `DESTDIR` variable, and is generally used by systems that have the `PREFIX` environment variable set by default.<br />
|
||||||
|
**Note**: `sudo` does not preserve user environment variables by default on some systems. See the `sudoers` manual for more information.
|
||||||
|
27
Makefile
27
Makefile
@ -3,13 +3,15 @@ CFG_DIR = $(BASE_DIR)/cfg
|
|||||||
|
|
||||||
-include $(CFG_DIR)/global_vars.mk
|
-include $(CFG_DIR)/global_vars.mk
|
||||||
|
|
||||||
LIBS = libtoxcore ncursesw libconfig libqrencode
|
LIBS = toxcore ncursesw libconfig libcurl
|
||||||
|
|
||||||
CFLAGS = -std=gnu99 -pthread -Wall -g -fstack-protector-all
|
CFLAGS ?= -g
|
||||||
|
CFLAGS += -std=gnu99 -pthread -Wall -fstack-protector-all
|
||||||
CFLAGS += '-DTOXICVER="$(VERSION)"' -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED -D_FILE_OFFSET_BITS=64
|
CFLAGS += '-DTOXICVER="$(VERSION)"' -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED -D_FILE_OFFSET_BITS=64
|
||||||
CFLAGS += '-DPACKAGE_DATADIR="$(abspath $(DATADIR))"'
|
CFLAGS += '-DPACKAGE_DATADIR="$(abspath $(DATADIR))"'
|
||||||
CFLAGS += $(USER_CFLAGS)
|
CFLAGS += ${USER_CFLAGS}
|
||||||
LDFLAGS = $(USER_LDFLAGS)
|
LDFLAGS ?=
|
||||||
|
LDFLAGS += ${USER_LDFLAGS}
|
||||||
|
|
||||||
OBJ = autocomplete.o avatars.o bootstrap.o chat.o chat_commands.o configdir.o curl_util.o execute.o
|
OBJ = autocomplete.o avatars.o bootstrap.o chat.o chat_commands.o configdir.o curl_util.o execute.o
|
||||||
OBJ += file_transfers.o friendlist.o global_commands.o group_commands.o groupchat.o help.o input.o
|
OBJ += file_transfers.o friendlist.o global_commands.o group_commands.o groupchat.o help.o input.o
|
||||||
@ -19,26 +21,19 @@ OBJ += term_mplex.o toxic.o toxic_strings.o windows.o
|
|||||||
# Check on wich system we are running
|
# Check on wich system we are running
|
||||||
UNAME_S = $(shell uname -s)
|
UNAME_S = $(shell uname -s)
|
||||||
ifeq ($(UNAME_S), Linux)
|
ifeq ($(UNAME_S), Linux)
|
||||||
-include $(CFG_DIR)/systems/Linux.mk
|
LDFLAGS += -ldl -lrt
|
||||||
endif
|
|
||||||
ifeq ($(UNAME_S), FreeBSD)
|
|
||||||
-include $(CFG_DIR)/systems/FreeBSD.mk
|
|
||||||
endif
|
|
||||||
ifeq ($(UNAME_S), DragonFly)
|
|
||||||
-include $(CFG_DIR)/systems/FreeBSD.mk
|
|
||||||
endif
|
endif
|
||||||
ifeq ($(UNAME_S), OpenBSD)
|
ifeq ($(UNAME_S), OpenBSD)
|
||||||
-include $(CFG_DIR)/systems/FreeBSD.mk
|
LIBS := $(filter-out ncursesw, $(LIBS))
|
||||||
|
LDFLAGS += -lncursesw
|
||||||
endif
|
endif
|
||||||
ifeq ($(UNAME_S), NetBSD)
|
ifeq ($(UNAME_S), NetBSD)
|
||||||
-include $(CFG_DIR)/systems/FreeBSD.mk
|
LIBS := $(filter-out ncursesw, $(LIBS))
|
||||||
|
LDFLAGS += -lncursesw
|
||||||
endif
|
endif
|
||||||
ifeq ($(UNAME_S), Darwin)
|
ifeq ($(UNAME_S), Darwin)
|
||||||
-include $(CFG_DIR)/systems/Darwin.mk
|
-include $(CFG_DIR)/systems/Darwin.mk
|
||||||
endif
|
endif
|
||||||
ifeq ($(UNAME_S), Solaris)
|
|
||||||
-include $(CFG_DIR)/systems/Solaris.mk
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Check on which platform we are running
|
# Check on which platform we are running
|
||||||
UNAME_M = $(shell uname -m)
|
UNAME_M = $(shell uname -m)
|
||||||
|
@ -3,13 +3,12 @@
|
|||||||
src="https://scan.coverity.com/projects/4975/badge.svg"/>
|
src="https://scan.coverity.com/projects/4975/badge.svg"/>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
Toxic is a [Tox](https://tox.chat)-based instant messenging client which formerly resided in the [Tox core repository](https://github.com/toktok/c-toxcore), and is now available as a standalone application.
|
Toxic is a [Tox](https://tox.chat)-based instant messenging and video chat client.
|
||||||
|
|
||||||
[](https://i.imgur.com/san99Z2.png)
|
[](https://i.imgur.com/san99Z2.png)
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
[Use our repositories](https://wiki.tox.chat/binaries#other_linux)<br />
|
[See the install instructions](/INSTALL.md)
|
||||||
[Compile it yourself](/INSTALL.md)
|
|
||||||
|
|
||||||
## Settings
|
## 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.
|
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.
|
||||||
|
@ -55,9 +55,9 @@ author = 'Jakob Kreuze'
|
|||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '0.8.1'
|
version = '0.8.3'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '0.8.1'
|
release = '0.8.3'
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
23
astylerc
23
astylerc
@ -1,11 +1,26 @@
|
|||||||
|
# Bracket Style Options
|
||||||
--style=kr
|
--style=kr
|
||||||
--pad-header
|
|
||||||
--max-code-length=120
|
# Tab Options
|
||||||
--convert-tabs
|
--indent=spaces=4
|
||||||
|
|
||||||
|
# Indentation Options
|
||||||
--indent-switches
|
--indent-switches
|
||||||
|
|
||||||
|
# Padding Options
|
||||||
|
--pad-header
|
||||||
|
--break-blocks
|
||||||
--pad-oper
|
--pad-oper
|
||||||
|
--unpad-paren
|
||||||
--align-pointer=name
|
--align-pointer=name
|
||||||
--align-reference=name
|
--align-reference=name
|
||||||
|
|
||||||
|
# Formatting Options
|
||||||
|
--add-brackets
|
||||||
|
--convert-tabs
|
||||||
|
--max-code-length=120
|
||||||
|
|
||||||
|
# Other Options
|
||||||
--preserve-date
|
--preserve-date
|
||||||
|
--formatted
|
||||||
--lineend=linux
|
--lineend=linux
|
||||||
--break-blocks
|
|
@ -1,5 +1,5 @@
|
|||||||
# Variables for audio call support
|
# Variables for audio call support
|
||||||
AUDIO_LIBS = libtoxav openal
|
AUDIO_LIBS = openal
|
||||||
AUDIO_CFLAGS = -DAUDIO
|
AUDIO_CFLAGS = -DAUDIO
|
||||||
ifneq (, $(findstring audio_device.o, $(OBJ)))
|
ifneq (, $(findstring audio_device.o, $(OBJ)))
|
||||||
AUDIO_OBJ = audio_call.o
|
AUDIO_OBJ = audio_call.o
|
||||||
|
@ -13,7 +13,7 @@ ifneq ($(AUDIO), disabled)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
# Check if we want build video support
|
# Check if we want build video support
|
||||||
VIDEO = $(shell if [ -z "$(DISABLE_AV)" ] || [ "$(DISABLE_AV)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
|
VIDEO = $(shell if [ -z "$(DISABLE_VI)" ] || [ "$(DISABLE_VI)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
|
||||||
ifneq ($(X11), disabled)
|
ifneq ($(X11), disabled)
|
||||||
ifneq ($(AUDIO), disabled)
|
ifneq ($(AUDIO), disabled)
|
||||||
ifneq ($(VIDEO), disabled)
|
ifneq ($(VIDEO), disabled)
|
||||||
@ -34,6 +34,12 @@ ifneq ($(DESK_NOTIFY), disabled)
|
|||||||
-include $(CHECKS_DIR)/desktop_notifications.mk
|
-include $(CHECKS_DIR)/desktop_notifications.mk
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# Check if we want build QR export support
|
||||||
|
QR_CODE = $(shell if [ -z "$(DISABLE_QRCODE)" ] || [ "$(DISABLE_QRCODE)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
|
||||||
|
ifneq ($(QR_CODE), disabled)
|
||||||
|
-include $(CHECKS_DIR)/qr.mk
|
||||||
|
endif
|
||||||
|
|
||||||
# Check if we want build QR exported as PNG support
|
# Check if we want build QR exported as PNG support
|
||||||
QR_PNG = $(shell if [ -z "$(DISABLE_QRPNG)" ] || [ "$(DISABLE_QRPNG)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
|
QR_PNG = $(shell if [ -z "$(DISABLE_QRPNG)" ] || [ "$(DISABLE_QRPNG)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
|
||||||
ifneq ($(QR_PNG), disabled)
|
ifneq ($(QR_PNG), disabled)
|
||||||
|
15
cfg/checks/qr.mk
Normal file
15
cfg/checks/qr.mk
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Variables for QR export support
|
||||||
|
QR_LIBS = libqrencode
|
||||||
|
QR_CFLAGS = -DQRCODE
|
||||||
|
|
||||||
|
# Check if we can build QR export support
|
||||||
|
CHECK_QR_LIBS = $(shell pkg-config --exists $(QR_LIBS) || echo -n "error")
|
||||||
|
ifneq ($(CHECK_QR_LIBS), error)
|
||||||
|
LIBS += $(QR_LIBS)
|
||||||
|
CFLAGS += $(QR_CFLAGS)
|
||||||
|
else ifneq ($(MAKECMDGOALS), clean)
|
||||||
|
MISSING_QR_LIBS = $(shell for lib in $(QR_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
|
||||||
|
$(warning WARNING -- Toxic will be compiled without QR export support)
|
||||||
|
$(warning WARNING -- You need these libraries for QR export support)
|
||||||
|
$(warning WARNING -- $(MISSING_QR_LIBS))
|
||||||
|
endif
|
@ -1,5 +1,5 @@
|
|||||||
# Variables for video call support
|
# Variables for video call support
|
||||||
VIDEO_LIBS = libtoxav vpx x11
|
VIDEO_LIBS = vpx x11
|
||||||
VIDEO_CFLAGS = -DVIDEO
|
VIDEO_CFLAGS = -DVIDEO
|
||||||
ifneq (, $(findstring video_device.o, $(OBJ)))
|
ifneq (, $(findstring video_device.o, $(OBJ)))
|
||||||
VIDEO_OBJ = video_call.o
|
VIDEO_OBJ = video_call.o
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Version
|
# Version
|
||||||
TOXIC_VERSION = 0.8.1
|
TOXIC_VERSION = 0.8.3
|
||||||
REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error")
|
REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error")
|
||||||
ifneq (, $(findstring error, $(REV)))
|
ifneq (, $(findstring error, $(REV)))
|
||||||
VERSION = $(TOXIC_VERSION)
|
VERSION = $(TOXIC_VERSION)
|
||||||
@ -23,10 +23,10 @@ SNDFILES += ToxicRecvMessage.wav ToxicOutgoingCall.wav ToxicIncomingCall.wav
|
|||||||
SNDFILES += ToxicTransferComplete.wav ToxicTransferStart.wav
|
SNDFILES += ToxicTransferComplete.wav ToxicTransferStart.wav
|
||||||
|
|
||||||
# Install directories
|
# Install directories
|
||||||
PREFIX = /usr/local
|
PREFIX ?= /usr/local
|
||||||
BINDIR = $(PREFIX)/bin
|
BINDIR = $(PREFIX)/bin
|
||||||
DATADIR = $(PREFIX)/share/toxic
|
DATADIR = $(PREFIX)/share/toxic
|
||||||
MANDIR = $(PREFIX)/share/man
|
MANDIR ?= $(PREFIX)/share/man
|
||||||
APPDIR = $(PREFIX)/share/applications
|
APPDIR = $(PREFIX)/share/applications
|
||||||
|
|
||||||
# Platform tools
|
# Platform tools
|
||||||
|
@ -6,7 +6,7 @@ PKG_CONFIG_PATH = $(shell export PKG_CONFIG_PATH=/usr/lib/pkgconfig:/usr/local/o
|
|||||||
LIBS := $(filter-out ncursesw, $(LIBS))
|
LIBS := $(filter-out ncursesw, $(LIBS))
|
||||||
|
|
||||||
# OS X ships a usable, recent version of ncurses, but calls it ncurses not ncursesw.
|
# OS X ships a usable, recent version of ncurses, but calls it ncurses not ncursesw.
|
||||||
LDFLAGS += -lncurses -lalut -ltoxav -ltoxcore -lcurl -lconfig -ltoxencryptsave -g
|
LDFLAGS += -lncurses -lalut -ltoxcore -lcurl -lconfig -lqrencode -lpng -lopenal -g
|
||||||
CFLAGS += -I/usr/local/opt/freealut/include/AL -I/usr/local/opt/glib/include/glib-2.0 -g
|
CFLAGS += -I/usr/local/opt/freealut/include/AL -I/usr/local/opt/glib/include/glib-2.0 -g
|
||||||
|
|
||||||
OSX_LIBRARIES = -lobjc -lresolv
|
OSX_LIBRARIES = -lobjc -lresolv
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
# Specials options for freebsd systems
|
|
||||||
LIBS := $(filter-out ncursesw, $(LIBS))
|
|
||||||
LDFLAGS += -lncursesw -lcurl
|
|
||||||
MANDIR = $(PREFIX)/man
|
|
@ -1,4 +0,0 @@
|
|||||||
# Specials options for linux systems
|
|
||||||
CFLAGS +=
|
|
||||||
LDFLAGS += -ldl -lrt -lcurl
|
|
||||||
MANDIR = $(PREFIX)/share/man
|
|
@ -14,11 +14,22 @@ help:
|
|||||||
@echo " DISABLE_AV: Set to \"1\" to force building without audio call support"
|
@echo " DISABLE_AV: Set to \"1\" to force building without audio call support"
|
||||||
@echo " DISABLE_SOUND_NOTIFY: Set to \"1\" to force building without sound notification 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 " DISABLE_DESKTOP_NOTIFY: Set to \"1\" to force building without desktop notifications support"
|
||||||
|
@echo " DISABLE_QRCODE: Set to \"1\" to force building without QR export support"
|
||||||
@echo " DISABLE_QRPNG: Set to \"1\" to force building without QR exported as PNG support"
|
@echo " DISABLE_QRPNG: Set to \"1\" to force building without QR exported as PNG support"
|
||||||
@echo " ENABLE_PYTHON: Set to \"1\" to enable building with Python scripting support"
|
@echo " ENABLE_PYTHON: Set to \"1\" to enable building with Python scripting support"
|
||||||
@echo " USER_CFLAGS: Add custom flags to default CFLAGS"
|
@echo " USER_CFLAGS: Add custom flags to default CFLAGS"
|
||||||
@echo " USER_LDFLAGS: Add custom flags to default LDFLAGS"
|
@echo " USER_LDFLAGS: Add custom flags to default LDFLAGS"
|
||||||
@echo " PREFIX: Specify a prefix directory for binaries, data files,... (default is \"$(abspath $(PREFIX))\")"
|
@echo " PREFIX: Specify a prefix directory for binaries, data files,... (default is \"$(abspath $(PREFIX))\")"
|
||||||
@echo " DESTDIR: Specify a directory where to store installed files (mainly for packaging purpose)"
|
@echo " DESTDIR: Specify a directory where to store installed files (mainly for packaging purpose)"
|
||||||
|
@echo " MANDIR: Specify a directory where to store man pages (default is \"$(abspath $(PREFIX)/share/man)\")"
|
||||||
|
@echo
|
||||||
|
@echo "-- Environment Variables --"
|
||||||
|
@echo " CFLAGS: Add custom flags to default CFLAGS"
|
||||||
|
@echo " LDFLAGS: Add custom flags to default LDFLAGS"
|
||||||
|
@echo " USER_CFLAGS: Add custom flags to default CFLAGS"
|
||||||
|
@echo " USER_LDFLAGS: Add custom flags to default LDFLAGS"
|
||||||
|
@echo " PREFIX: Specify a prefix directory for binaries, data files,... (default is \"$(abspath $(PREFIX))\")"
|
||||||
|
@echo " DESTDIR: Specify a directory where to store installed files (mainly for packaging purpose)"
|
||||||
|
@echo " MANDIR: Specify a directory where to store man pages (default is \"$(abspath $(PREFIX)/share/man)\")"
|
||||||
|
|
||||||
.PHONY: help
|
.PHONY: help
|
||||||
|
@ -27,7 +27,7 @@ install: $(BUILD_DIR)/toxic
|
|||||||
if [ ! -e "$(DOC_DIR)/$$f" ]; then \
|
if [ ! -e "$(DOC_DIR)/$$f" ]; then \
|
||||||
continue ;\
|
continue ;\
|
||||||
fi ;\
|
fi ;\
|
||||||
section=$(abspath $(DESTDIR)/$(MANDIR))/man`echo $$f | rev | cut -d "." -f 1` ;\
|
section=$(abspath $(DESTDIR)/$(MANDIR))/man`echo $${f##*.}` ;\
|
||||||
file=$$section/$$f ;\
|
file=$$section/$$f ;\
|
||||||
mkdir -p $$section ;\
|
mkdir -p $$section ;\
|
||||||
install -m 0644 $(DOC_DIR)/$$f $$file ;\
|
install -m 0644 $(DOC_DIR)/$$f $$file ;\
|
||||||
|
@ -16,7 +16,7 @@ uninstall:
|
|||||||
|
|
||||||
@echo "Removing man pages"
|
@echo "Removing man pages"
|
||||||
@for f in $(MANFILES) ; do \
|
@for f in $(MANFILES) ; do \
|
||||||
section=$(abspath $(DESTDIR)/$(MANDIR))/man`echo $$f | rev | cut -d "." -f 1` ;\
|
section=$(abspath $(DESTDIR)/$(MANDIR))/man`echo $${f##*.}` ;\
|
||||||
file=$$section/$$f ;\
|
file=$$section/$$f ;\
|
||||||
rm -f $$file $$file.gz ;\
|
rm -f $$file $$file.gz ;\
|
||||||
done
|
done
|
||||||
|
31
src/api.c
31
src/api.c
@ -36,7 +36,6 @@
|
|||||||
|
|
||||||
#ifdef PYTHON
|
#ifdef PYTHON
|
||||||
#include "python_api.h"
|
#include "python_api.h"
|
||||||
#endif /* PYTHON */
|
|
||||||
|
|
||||||
Tox *user_tox;
|
Tox *user_tox;
|
||||||
static WINDOW *cur_window;
|
static WINDOW *cur_window;
|
||||||
@ -47,8 +46,9 @@ extern struct user_settings *user_settings;
|
|||||||
|
|
||||||
void api_display(const char *const msg)
|
void api_display(const char *const msg)
|
||||||
{
|
{
|
||||||
if (msg == NULL)
|
if (msg == NULL) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self_window = get_active_window();
|
self_window = get_active_window();
|
||||||
line_info_add(self_window, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
|
line_info_add(self_window, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
|
||||||
@ -64,15 +64,16 @@ char *api_get_nick(void)
|
|||||||
size_t len = tox_self_get_name_size(user_tox);
|
size_t len = tox_self_get_name_size(user_tox);
|
||||||
uint8_t *name = malloc(len + 1);
|
uint8_t *name = malloc(len + 1);
|
||||||
|
|
||||||
if (name == NULL)
|
if (name == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
tox_self_get_name(user_tox, name);
|
tox_self_get_name(user_tox, name);
|
||||||
name[len] = '\0';
|
name[len] = '\0';
|
||||||
return (char *) name;
|
return (char *) name;
|
||||||
}
|
}
|
||||||
|
|
||||||
TOX_USER_STATUS api_get_status(void)
|
Tox_User_Status api_get_status(void)
|
||||||
{
|
{
|
||||||
return tox_self_get_status(user_tox);
|
return tox_self_get_status(user_tox);
|
||||||
}
|
}
|
||||||
@ -82,8 +83,9 @@ char *api_get_status_message(void)
|
|||||||
size_t len = tox_self_get_status_message_size(user_tox);
|
size_t len = tox_self_get_status_message_size(user_tox);
|
||||||
uint8_t *status = malloc(len + 1);
|
uint8_t *status = malloc(len + 1);
|
||||||
|
|
||||||
if (status == NULL)
|
if (status == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
tox_self_get_status_message(user_tox, status);
|
tox_self_get_status_message(user_tox, status);
|
||||||
status[len] = '\0';
|
status[len] = '\0';
|
||||||
@ -92,14 +94,16 @@ char *api_get_status_message(void)
|
|||||||
|
|
||||||
void api_send(const char *msg)
|
void api_send(const char *msg)
|
||||||
{
|
{
|
||||||
if (msg == NULL || self_window->chatwin->cqueue == NULL)
|
if (msg == NULL || self_window->chatwin->cqueue == NULL) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
char *name = api_get_nick();
|
char *name = api_get_nick();
|
||||||
char timefrmt[TIME_STR_SIZE];
|
char timefrmt[TIME_STR_SIZE];
|
||||||
|
|
||||||
if (name == NULL)
|
if (name == NULL) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self_window = get_active_window();
|
self_window = get_active_window();
|
||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
@ -146,8 +150,11 @@ void cmd_run(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
|||||||
self_window = self;
|
self_window = self;
|
||||||
|
|
||||||
if (argc != 1) {
|
if (argc != 1) {
|
||||||
if ( argc < 1 ) error_str = "Path must be specified!";
|
if (argc < 1) {
|
||||||
else error_str = "Only one argument allowed!";
|
error_str = "Path must be specified.";
|
||||||
|
} else {
|
||||||
|
error_str = "Only one argument allowed.";
|
||||||
|
}
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, error_str);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, error_str);
|
||||||
return;
|
return;
|
||||||
@ -156,7 +163,7 @@ void cmd_run(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
|||||||
fp = fopen(argv[1], "r");
|
fp = fopen(argv[1], "r");
|
||||||
|
|
||||||
if (fp == NULL) {
|
if (fp == NULL) {
|
||||||
error_str = "Path does not exist!";
|
error_str = "Path does not exist.";
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, error_str);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, error_str);
|
||||||
return;
|
return;
|
||||||
@ -174,8 +181,9 @@ void invoke_autoruns(WINDOW *window, ToxWindow *self)
|
|||||||
DIR *d;
|
DIR *d;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
if (user_settings->autorun_path[0] == '\0')
|
if (user_settings->autorun_path[0] == '\0') {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
d = opendir(user_settings->autorun_path);
|
d = opendir(user_settings->autorun_path);
|
||||||
|
|
||||||
@ -208,3 +216,4 @@ void invoke_autoruns(WINDOW *window, ToxWindow *self)
|
|||||||
|
|
||||||
closedir(d);
|
closedir(d);
|
||||||
}
|
}
|
||||||
|
#endif /* PYTHON */
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
void api_display(const char *const msg);
|
void api_display(const char *const msg);
|
||||||
FriendsList api_get_friendslist(void);
|
FriendsList api_get_friendslist(void);
|
||||||
char *api_get_nick(void);
|
char *api_get_nick(void);
|
||||||
TOX_USER_STATUS api_get_status(void);
|
Tox_User_Status api_get_status(void);
|
||||||
char *api_get_status_message(void);
|
char *api_get_status_message(void);
|
||||||
void api_send(const char *msg);
|
void api_send(const char *msg);
|
||||||
void api_execute(const char *input, int mode);
|
void api_execute(const char *input, int mode);
|
||||||
@ -38,5 +38,6 @@ int num_registered_handlers(void);
|
|||||||
int help_max_width(void);
|
int help_max_width(void);
|
||||||
void draw_handler_help(WINDOW *win);
|
void draw_handler_help(WINDOW *win);
|
||||||
void invoke_autoruns(WINDOW *w, ToxWindow *self);
|
void invoke_autoruns(WINDOW *w, ToxWindow *self);
|
||||||
|
void cmd_run(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
|
|
||||||
#endif /* #define API_H */
|
#endif /* API_H */
|
||||||
|
337
src/audio_call.c
337
src/audio_call.c
@ -31,6 +31,8 @@
|
|||||||
#include "friendlist.h"
|
#include "friendlist.h"
|
||||||
#include "chat.h"
|
#include "chat.h"
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
|
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
#include "video_call.h"
|
#include "video_call.h"
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
@ -52,10 +54,13 @@
|
|||||||
/* compatibility with older versions of OpenAL */
|
/* compatibility with older versions of OpenAL */
|
||||||
#ifndef ALC_ALL_DEVICES_SPECIFIER
|
#ifndef ALC_ALL_DEVICES_SPECIFIER
|
||||||
#include <AL/alext.h>
|
#include <AL/alext.h>
|
||||||
#endif
|
#endif /* ALC_ALL_DEVICES_SPECIFIER */
|
||||||
#endif
|
#endif /* __APPLE__ */
|
||||||
|
|
||||||
extern FriendsList Friends;
|
extern FriendsList Friends;
|
||||||
|
extern ToxWindow *windows[MAX_WINDOWS_NUM];
|
||||||
|
|
||||||
|
struct CallControl CallControl;
|
||||||
|
|
||||||
#define cbend pthread_exit(NULL)
|
#define cbend pthread_exit(NULL)
|
||||||
|
|
||||||
@ -73,27 +78,25 @@ static int set_call(Call *call, bool start)
|
|||||||
if (start) {
|
if (start) {
|
||||||
call->ttas = true;
|
call->ttas = true;
|
||||||
|
|
||||||
if ( pthread_mutex_init(&call->mutex, NULL) != 0 )
|
if (pthread_mutex_init(&call->mutex, NULL) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
call->ttid = 0;
|
call->ttid = 0;
|
||||||
|
|
||||||
if ( pthread_mutex_destroy(&call->mutex) != 0 )
|
if (pthread_mutex_destroy(&call->mutex) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void call_cb ( ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled,
|
void on_call(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled,
|
||||||
void *user_data);
|
void *user_data);
|
||||||
void callstate_cb ( ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data );
|
void on_call_state(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data);
|
||||||
void receive_audio_frame_cb ( ToxAV *av, uint32_t friend_number, int16_t const *pcm, size_t sample_count,
|
void on_audio_receive_frame(ToxAV *av, uint32_t friend_number, int16_t const *pcm, size_t sample_count,
|
||||||
uint8_t channels, uint32_t sampling_rate, void *user_data);
|
uint8_t channels, uint32_t sampling_rate, void *user_data);
|
||||||
void receive_video_frame_cb ( ToxAV *av, uint32_t friend_number,
|
|
||||||
uint16_t width, uint16_t height,
|
|
||||||
uint8_t const *y, uint8_t const *u, uint8_t const *v, uint8_t const *a,
|
|
||||||
int32_t ystride, int32_t ustride, int32_t vstride, int32_t astride, void *user_data );
|
|
||||||
|
|
||||||
void callback_recv_invite(Tox *m, uint32_t friend_number);
|
void callback_recv_invite(Tox *m, uint32_t friend_number);
|
||||||
void callback_recv_ringing(uint32_t friend_number);
|
void callback_recv_ringing(uint32_t friend_number);
|
||||||
@ -114,7 +117,7 @@ static void print_err (ToxWindow *self, const char *error_str)
|
|||||||
|
|
||||||
ToxAV *init_audio(ToxWindow *self, Tox *tox)
|
ToxAV *init_audio(ToxWindow *self, Tox *tox)
|
||||||
{
|
{
|
||||||
TOXAV_ERR_NEW error;
|
Toxav_Err_New error;
|
||||||
CallControl.audio_errors = ae_None;
|
CallControl.audio_errors = ae_None;
|
||||||
CallControl.prompt = self;
|
CallControl.prompt = self;
|
||||||
CallControl.pending_call = false;
|
CallControl.pending_call = false;
|
||||||
@ -133,8 +136,6 @@ ToxAV *init_audio(ToxWindow *self, Tox *tox)
|
|||||||
CallControl.video_frame_duration = 0;
|
CallControl.video_frame_duration = 0;
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
|
|
||||||
memset(CallControl.calls, 0, sizeof(CallControl.calls));
|
|
||||||
|
|
||||||
if (!CallControl.av) {
|
if (!CallControl.av) {
|
||||||
CallControl.audio_errors |= ae_StartingCoreAudio;
|
CallControl.audio_errors |= ae_StartingCoreAudio;
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init ToxAV");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init ToxAV");
|
||||||
@ -149,29 +150,31 @@ ToxAV *init_audio(ToxWindow *self, Tox *tox)
|
|||||||
return CallControl.av = NULL;
|
return CallControl.av = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
toxav_callback_call(CallControl.av, call_cb, tox);
|
toxav_callback_call(CallControl.av, on_call, tox);
|
||||||
toxav_callback_call_state(CallControl.av, callstate_cb, NULL);
|
toxav_callback_call_state(CallControl.av, on_call_state, NULL);
|
||||||
toxav_callback_audio_receive_frame(CallControl.av, receive_audio_frame_cb, NULL);
|
toxav_callback_audio_receive_frame(CallControl.av, on_audio_receive_frame, NULL);
|
||||||
|
|
||||||
return CallControl.av;
|
return CallControl.av;
|
||||||
}
|
}
|
||||||
|
|
||||||
void terminate_audio()
|
void terminate_audio(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_CALLS; ++i)
|
for (i = 0; i < CallControl.max_calls; ++i) {
|
||||||
stop_transmission(&CallControl.calls[i], i);
|
stop_transmission(&CallControl.calls[i], i);
|
||||||
|
}
|
||||||
|
|
||||||
if ( CallControl.av )
|
if (CallControl.av) {
|
||||||
toxav_kill(CallControl.av);
|
toxav_kill(CallControl.av);
|
||||||
|
}
|
||||||
|
|
||||||
terminate_devices();
|
terminate_devices();
|
||||||
}
|
}
|
||||||
|
|
||||||
void read_device_callback(const int16_t *captured, uint32_t size, void *data)
|
void read_device_callback(const int16_t *captured, uint32_t size, void *data)
|
||||||
{
|
{
|
||||||
TOXAV_ERR_SEND_FRAME error;
|
Toxav_Err_Send_Frame error;
|
||||||
uint32_t friend_number = *((uint32_t *)data); /* TODO: Or pass an array of call_idx's */
|
uint32_t friend_number = *((uint32_t *)data); /* TODO: Or pass an array of call_idx's */
|
||||||
int64_t sample_count = ((int64_t) CallControl.audio_sample_rate) * \
|
int64_t sample_count = ((int64_t) CallControl.audio_sample_rate) * \
|
||||||
((int64_t) CallControl.audio_frame_duration) / 1000;
|
((int64_t) CallControl.audio_frame_duration) / 1000;
|
||||||
@ -186,9 +189,10 @@ void read_device_callback(const int16_t *captured, uint32_t size, void *data)
|
|||||||
void write_device_callback(uint32_t friend_number, const int16_t *PCM, uint16_t sample_count, uint8_t channels,
|
void write_device_callback(uint32_t friend_number, const int16_t *PCM, uint16_t sample_count, uint8_t channels,
|
||||||
uint32_t sample_rate)
|
uint32_t sample_rate)
|
||||||
{
|
{
|
||||||
if ( CallControl.calls[friend_number].ttas )
|
if (CallControl.calls[friend_number].ttas) {
|
||||||
write_out(CallControl.calls[friend_number].out_idx, PCM, sample_count, channels, sample_rate);
|
write_out(CallControl.calls[friend_number].out_idx, PCM, sample_count, channels, sample_rate);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int start_transmission(ToxWindow *self, Call *call)
|
int start_transmission(ToxWindow *self, Call *call)
|
||||||
{
|
{
|
||||||
@ -197,24 +201,29 @@ int start_transmission(ToxWindow *self, Call *call)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (set_call(call, true) == -1)
|
if (set_call(call, true) == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
DeviceError error = open_primary_device(input, &call->in_idx,
|
DeviceError error = open_primary_device(input, &call->in_idx,
|
||||||
CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels);
|
CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels);
|
||||||
|
|
||||||
if (error != de_None) {
|
if (error != de_None) {
|
||||||
if ( error == de_FailedStart)
|
if (error == de_FailedStart) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to start input device");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to start input device");
|
||||||
|
}
|
||||||
|
|
||||||
if ( error == de_InternalError )
|
if (error == de_InternalError) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Internal error with opening input device");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Internal error with opening input device");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (register_device_callback(self->num, call->in_idx,
|
if (register_device_callback(self->num, call->in_idx,
|
||||||
read_device_callback, &self->num, true) != de_None)
|
read_device_callback, &self->num, true) != de_None)
|
||||||
/* Set VAD as true for all; TODO: Make it more dynamic */
|
/* Set VAD as true for all; TODO: Make it more dynamic */
|
||||||
|
{
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to register input handler!");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to register input handler!");
|
||||||
|
}
|
||||||
|
|
||||||
if (open_primary_device(output, &call->out_idx,
|
if (open_primary_device(output, &call->out_idx,
|
||||||
CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels) != de_None) {
|
CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels) != de_None) {
|
||||||
@ -228,22 +237,26 @@ int start_transmission(ToxWindow *self, Call *call)
|
|||||||
int stop_transmission(Call *call, uint32_t friend_number)
|
int stop_transmission(Call *call, uint32_t friend_number)
|
||||||
{
|
{
|
||||||
if (call->ttas) {
|
if (call->ttas) {
|
||||||
TOXAV_ERR_CALL_CONTROL error = TOXAV_ERR_CALL_CONTROL_OK;
|
Toxav_Err_Call_Control error = TOXAV_ERR_CALL_CONTROL_OK;
|
||||||
|
|
||||||
if ( CallControl.call_state > TOXAV_FRIEND_CALL_STATE_FINISHED )
|
if (CallControl.call_state > TOXAV_FRIEND_CALL_STATE_FINISHED) {
|
||||||
toxav_call_control(CallControl.av, friend_number, TOXAV_CALL_CONTROL_CANCEL, &error);
|
toxav_call_control(CallControl.av, friend_number, TOXAV_CALL_CONTROL_CANCEL, &error);
|
||||||
|
}
|
||||||
|
|
||||||
if (error == TOXAV_ERR_CALL_CONTROL_OK) {
|
if (error == TOXAV_ERR_CALL_CONTROL_OK) {
|
||||||
call->ttas = false;
|
call->ttas = false;
|
||||||
|
|
||||||
if ( call->in_idx != -1 )
|
if (call->in_idx != -1) {
|
||||||
close_device(input, call->in_idx);
|
close_device(input, call->in_idx);
|
||||||
|
}
|
||||||
|
|
||||||
if ( call->out_idx != -1 )
|
if (call->out_idx != -1) {
|
||||||
close_device(output, call->out_idx);
|
close_device(output, call->out_idx);
|
||||||
|
}
|
||||||
|
|
||||||
if ( set_call(call, false) == -1 )
|
if (set_call(call, false) == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
@ -265,14 +278,14 @@ int stop_transmission(Call *call, uint32_t friend_number)
|
|||||||
/*
|
/*
|
||||||
* Callbacks
|
* Callbacks
|
||||||
*/
|
*/
|
||||||
void call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data)
|
void on_call(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data)
|
||||||
{
|
{
|
||||||
Tox *m = (Tox *) user_data;
|
Tox *m = (Tox *) user_data;
|
||||||
CallControl.pending_call = true;
|
CallControl.pending_call = true;
|
||||||
callback_recv_invite(m, friend_number);
|
callback_recv_invite(m, friend_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data)
|
void on_call_state(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data)
|
||||||
{
|
{
|
||||||
CallControl.call_state = state;
|
CallControl.call_state = state;
|
||||||
|
|
||||||
@ -291,10 +304,11 @@ void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case (TOXAV_FRIEND_CALL_STATE_FINISHED):
|
case (TOXAV_FRIEND_CALL_STATE_FINISHED):
|
||||||
if ( CallControl.pending_call )
|
if (CallControl.pending_call) {
|
||||||
callback_call_rejected(friend_number);
|
callback_call_rejected(friend_number);
|
||||||
else
|
} else {
|
||||||
callback_call_ended(friend_number);
|
callback_call_ended(friend_number);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
callback_recv_video_end(friend_number);
|
callback_recv_video_end(friend_number);
|
||||||
@ -319,10 +333,11 @@ void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_
|
|||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
|
|
||||||
/* Handle receiving client video call states */
|
/* Handle receiving client video call states */
|
||||||
if ( state & TOXAV_FRIEND_CALL_STATE_SENDING_V )
|
if (state & TOXAV_FRIEND_CALL_STATE_SENDING_V) {
|
||||||
callback_recv_video_starting(friend_number);
|
callback_recv_video_starting(friend_number);
|
||||||
else if ( state & ~TOXAV_FRIEND_CALL_STATE_SENDING_V )
|
} else if (state & ~TOXAV_FRIEND_CALL_STATE_SENDING_V) {
|
||||||
callback_recv_video_end(friend_number);
|
callback_recv_video_end(friend_number);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
}
|
}
|
||||||
@ -331,64 +346,56 @@ void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void receive_audio_frame_cb(ToxAV *av, uint32_t friend_number,
|
void on_audio_receive_frame(ToxAV *av, uint32_t friend_number,
|
||||||
int16_t const *pcm, size_t sample_count,
|
int16_t const *pcm, size_t sample_count,
|
||||||
uint8_t channels, uint32_t sampling_rate, void *user_data)
|
uint8_t channels, uint32_t sampling_rate, void *user_data)
|
||||||
{
|
{
|
||||||
write_device_callback(friend_number, pcm, sample_count, channels, sampling_rate);
|
write_device_callback(friend_number, pcm, sample_count, channels, sampling_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate,
|
void audio_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, void *user_data)
|
||||||
uint32_t video_bit_rate, void *user_data)
|
|
||||||
{
|
{
|
||||||
CallControl.audio_bit_rate = audio_bit_rate;
|
CallControl.audio_bit_rate = audio_bit_rate;
|
||||||
toxav_bit_rate_set(av, friend_number, audio_bit_rate, video_bit_rate, user_data);
|
toxav_audio_set_bit_rate(av, friend_number, audio_bit_rate, user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void callback_recv_invite(Tox *m, uint32_t friend_number)
|
void callback_recv_invite(Tox *m, uint32_t friend_number)
|
||||||
{
|
{
|
||||||
if (friend_number >= Friends.max_idx)
|
if (friend_number >= Friends.max_idx) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (Friends.list[friend_number].chatwin == -1) {
|
if (Friends.list[friend_number].chatwin == -1) {
|
||||||
if (get_num_active_windows() >= MAX_WINDOWS_NUM)
|
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Friends.list[friend_number].chatwin = add_window(m, new_chat(m, Friends.list[friend_number].num));
|
Friends.list[friend_number].chatwin = add_window(m, new_chat(m, Friends.list[friend_number].num));
|
||||||
}
|
}
|
||||||
|
|
||||||
ToxWindow *windows = CallControl.prompt;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
int i;
|
if (windows[i] != NULL && windows[i]->onInvite != NULL && windows[i]->num == friend_number) {
|
||||||
|
windows[i]->onInvite(windows[i], CallControl.av, friend_number, CallControl.call_state);
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
|
||||||
if (windows[i].onInvite != NULL && windows[i].num == friend_number) {
|
|
||||||
windows[i].onInvite(&windows[i], CallControl.av, friend_number, CallControl.call_state);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void callback_recv_ringing(uint32_t friend_number)
|
void callback_recv_ringing(uint32_t friend_number)
|
||||||
{
|
{
|
||||||
ToxWindow *windows = CallControl.prompt;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
int i;
|
if (windows[i] != NULL && windows[i]->onRinging != NULL && windows[i]->num == friend_number) {
|
||||||
|
windows[i]->onRinging(windows[i], CallControl.av, friend_number, CallControl.call_state);
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
|
||||||
if (windows[i].onRinging != NULL && windows[i].num == friend_number) {
|
|
||||||
windows[i].onRinging(&windows[i], CallControl.av, friend_number, CallControl.call_state);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void callback_recv_starting(uint32_t friend_number)
|
void callback_recv_starting(uint32_t friend_number)
|
||||||
{
|
{
|
||||||
ToxWindow *windows = CallControl.prompt;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i] != NULL && windows[i]->onStarting != NULL && windows[i]->num == friend_number) {
|
||||||
|
windows[i]->onStarting(windows[i], CallControl.av, friend_number, CallControl.call_state);
|
||||||
|
|
||||||
int i;
|
if (0 != start_transmission(windows[i], &CallControl.calls[friend_number])) { /* YEAH! */
|
||||||
|
line_info_add(windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!");
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
}
|
||||||
if ( windows[i].onStarting != NULL && windows[i].num == friend_number ) {
|
|
||||||
windows[i].onStarting(&windows[i], CallControl.av, friend_number, CallControl.call_state);
|
|
||||||
|
|
||||||
if ( 0 != start_transmission(&windows[i], &CallControl.calls[friend_number]) ) /* YEAH! */
|
|
||||||
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!");
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -396,61 +403,46 @@ void callback_recv_starting(uint32_t friend_number)
|
|||||||
}
|
}
|
||||||
void callback_recv_ending(uint32_t friend_number)
|
void callback_recv_ending(uint32_t friend_number)
|
||||||
{
|
{
|
||||||
ToxWindow *windows = CallControl.prompt;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
int i;
|
if (windows[i] != NULL && windows[i]->onEnding != NULL && windows[i]->num == friend_number) {
|
||||||
|
windows[i]->onEnding(windows[i], CallControl.av, friend_number, CallControl.call_state);
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
|
||||||
if (windows[i].onEnding != NULL && windows[i].num == friend_number) {
|
|
||||||
windows[i].onEnding(&windows[i], CallControl.av, friend_number, CallControl.call_state);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void callback_call_started(uint32_t friend_number)
|
void callback_call_started(uint32_t friend_number)
|
||||||
{
|
{
|
||||||
ToxWindow *windows = CallControl.prompt;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i] != NULL && windows[i]->onStart != NULL && windows[i]->num == friend_number) {
|
||||||
|
windows[i]->onStart(windows[i], CallControl.av, friend_number, CallControl.call_state);
|
||||||
|
|
||||||
int i;
|
if (0 != start_transmission(windows[i], &CallControl.calls[friend_number])) { /* YEAH! */
|
||||||
|
line_info_add(windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!");
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i)
|
|
||||||
if ( windows[i].onStart != NULL && windows[i].num == friend_number ) {
|
|
||||||
windows[i].onStart(&windows[i], CallControl.av, friend_number, CallControl.call_state);
|
|
||||||
|
|
||||||
if ( 0 != start_transmission(&windows[i], &CallControl.calls[friend_number]) ) {/* YEAH! */
|
|
||||||
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
void callback_call_canceled(uint32_t friend_number)
|
void callback_call_canceled(uint32_t friend_number)
|
||||||
{
|
{
|
||||||
ToxWindow *windows = CallControl.prompt;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
int i;
|
if (windows[i] != NULL && windows[i]->onCancel != NULL && windows[i]->num == friend_number) {
|
||||||
|
windows[i]->onCancel(windows[i], CallControl.av, friend_number, CallControl.call_state);
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
|
||||||
if (windows[i].onCancel != NULL && windows[i].num == friend_number) {
|
|
||||||
windows[i].onCancel(&windows[i], CallControl.av, friend_number, CallControl.call_state);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void callback_call_rejected(uint32_t friend_number)
|
void callback_call_rejected(uint32_t friend_number)
|
||||||
{
|
{
|
||||||
ToxWindow *windows = CallControl.prompt;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
int i;
|
if (windows[i] != NULL && windows[i]->onReject != NULL && windows[i]->num == friend_number) {
|
||||||
|
windows[i]->onReject(windows[i], CallControl.av, friend_number, CallControl.call_state);
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
|
||||||
if (windows[i].onReject != NULL && windows[i].num == friend_number) {
|
|
||||||
windows[i].onReject(&windows[i], CallControl.av, friend_number, CallControl.call_state);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void callback_call_ended(uint32_t friend_number)
|
void callback_call_ended(uint32_t friend_number)
|
||||||
{
|
{
|
||||||
ToxWindow *windows = CallControl.prompt;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
int i;
|
if (windows[i] != NULL && windows[i]->onEnd != NULL && windows[i]->num == friend_number) {
|
||||||
|
windows[i]->onEnd(windows[i], CallControl.av, friend_number, CallControl.call_state);
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
|
||||||
if (windows[i].onEnd != NULL && windows[i].num == friend_number) {
|
|
||||||
windows[i].onEnd(&windows[i], CallControl.av, friend_number, CallControl.call_state);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -465,7 +457,7 @@ void callback_call_ended(uint32_t friend_number)
|
|||||||
*/
|
*/
|
||||||
void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
TOXAV_ERR_CALL error;
|
Toxav_Err_Call error;
|
||||||
const char *error_str;
|
const char *error_str;
|
||||||
|
|
||||||
if (argc != 0) {
|
if (argc != 0) {
|
||||||
@ -491,11 +483,17 @@ void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
|||||||
toxav_call(CallControl.av, self->num, CallControl.audio_bit_rate, CallControl.video_bit_rate, &error);
|
toxav_call(CallControl.av, self->num, CallControl.audio_bit_rate, CallControl.video_bit_rate, &error);
|
||||||
|
|
||||||
if (error != TOXAV_ERR_CALL_OK) {
|
if (error != TOXAV_ERR_CALL_OK) {
|
||||||
if ( error == TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL ) error_str = "Already in a call!";
|
if (error == TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL) {
|
||||||
else if ( error == TOXAV_ERR_CALL_MALLOC ) error_str = "Memory allocation issue";
|
error_str = "Already in a call!";
|
||||||
else if ( error == TOXAV_ERR_CALL_FRIEND_NOT_FOUND ) error_str = "Friend number invalid";
|
} else if (error == TOXAV_ERR_CALL_MALLOC) {
|
||||||
else if ( error == TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED ) error_str = "Friend is valid but not currently connected";
|
error_str = "Memory allocation issue";
|
||||||
else error_str = "Internal error!";
|
} else if (error == TOXAV_ERR_CALL_FRIEND_NOT_FOUND) {
|
||||||
|
error_str = "Friend number invalid";
|
||||||
|
} else if (error == TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED) {
|
||||||
|
error_str = "Friend is valid but not currently connected";
|
||||||
|
} else {
|
||||||
|
error_str = "Internal error!";
|
||||||
|
}
|
||||||
|
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
@ -510,7 +508,7 @@ on_error:
|
|||||||
|
|
||||||
void cmd_answer(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_answer(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
TOXAV_ERR_ANSWER error;
|
Toxav_Err_Answer error;
|
||||||
const char *error_str;
|
const char *error_str;
|
||||||
|
|
||||||
if (argc != 0) {
|
if (argc != 0) {
|
||||||
@ -531,11 +529,17 @@ void cmd_answer(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
|||||||
toxav_answer(CallControl.av, self->num, CallControl.audio_bit_rate, CallControl.video_bit_rate, &error);
|
toxav_answer(CallControl.av, self->num, CallControl.audio_bit_rate, CallControl.video_bit_rate, &error);
|
||||||
|
|
||||||
if (error != TOXAV_ERR_ANSWER_OK) {
|
if (error != TOXAV_ERR_ANSWER_OK) {
|
||||||
if ( error == TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING ) error_str = "No incoming call!";
|
if (error == TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING) {
|
||||||
else if ( error == TOXAV_ERR_ANSWER_CODEC_INITIALIZATION ) error_str = "Failed to initialize codecs!";
|
error_str = "No incoming call!";
|
||||||
else if ( error == TOXAV_ERR_ANSWER_FRIEND_NOT_FOUND ) error_str = "Friend not found!";
|
} else if (error == TOXAV_ERR_ANSWER_CODEC_INITIALIZATION) {
|
||||||
else if ( error == TOXAV_ERR_ANSWER_INVALID_BIT_RATE ) error_str = "Invalid bit rate!";
|
error_str = "Failed to initialize codecs!";
|
||||||
else error_str = "Internal error!";
|
} else if (error == TOXAV_ERR_ANSWER_FRIEND_NOT_FOUND) {
|
||||||
|
error_str = "Friend not found!";
|
||||||
|
} else if (error == TOXAV_ERR_ANSWER_INVALID_BIT_RATE) {
|
||||||
|
error_str = "Invalid bit rate!";
|
||||||
|
} else {
|
||||||
|
error_str = "Internal error!";
|
||||||
|
}
|
||||||
|
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
@ -614,19 +618,24 @@ void cmd_list_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*
|
|||||||
const char *error_str;
|
const char *error_str;
|
||||||
|
|
||||||
if (argc != 1) {
|
if (argc != 1) {
|
||||||
if ( argc < 1 ) error_str = "Type must be specified!";
|
if (argc < 1) {
|
||||||
else error_str = "Only one argument allowed!";
|
error_str = "Type must be specified!";
|
||||||
|
} else {
|
||||||
|
error_str = "Only one argument allowed!";
|
||||||
|
}
|
||||||
|
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceType type;
|
DeviceType type;
|
||||||
|
|
||||||
if ( strcasecmp(argv[1], "in") == 0 ) /* Input devices */
|
if (strcasecmp(argv[1], "in") == 0) { /* Input devices */
|
||||||
type = input;
|
type = input;
|
||||||
|
}
|
||||||
|
|
||||||
else if ( strcasecmp(argv[1], "out") == 0 ) /* Output devices */
|
else if (strcasecmp(argv[1], "out") == 0) { /* Output devices */
|
||||||
type = output;
|
type = output;
|
||||||
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
||||||
@ -649,20 +658,26 @@ void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (
|
|||||||
const char *error_str;
|
const char *error_str;
|
||||||
|
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
if ( argc < 1 ) error_str = "Type must be specified!";
|
if (argc < 1) {
|
||||||
else if ( argc < 2 ) error_str = "Must have id!";
|
error_str = "Type must be specified!";
|
||||||
else error_str = "Only two arguments allowed!";
|
} else if (argc < 2) {
|
||||||
|
error_str = "Must have id!";
|
||||||
|
} else {
|
||||||
|
error_str = "Only two arguments allowed!";
|
||||||
|
}
|
||||||
|
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceType type;
|
DeviceType type;
|
||||||
|
|
||||||
if ( strcmp(argv[1], "in") == 0 ) /* Input devices */
|
if (strcmp(argv[1], "in") == 0) { /* Input devices */
|
||||||
type = input;
|
type = input;
|
||||||
|
}
|
||||||
|
|
||||||
else if ( strcmp(argv[1], "out") == 0 ) /* Output devices */
|
else if (strcmp(argv[1], "out") == 0) { /* Output devices */
|
||||||
type = output;
|
type = output;
|
||||||
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
||||||
@ -693,20 +708,26 @@ void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
|
|||||||
const char *error_str;
|
const char *error_str;
|
||||||
|
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
if ( argc < 1 ) error_str = "Type must be specified!";
|
if (argc < 1) {
|
||||||
else if ( argc < 2 ) error_str = "Must have id!";
|
error_str = "Type must be specified!";
|
||||||
else error_str = "Only two arguments allowed!";
|
} else if (argc < 2) {
|
||||||
|
error_str = "Must have id!";
|
||||||
|
} else {
|
||||||
|
error_str = "Only two arguments allowed!";
|
||||||
|
}
|
||||||
|
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceType type;
|
DeviceType type;
|
||||||
|
|
||||||
if ( strcmp(argv[1], "in") == 0 ) /* Input devices */
|
if (strcmp(argv[1], "in") == 0) { /* Input devices */
|
||||||
type = input;
|
type = input;
|
||||||
|
}
|
||||||
|
|
||||||
else if ( strcmp(argv[1], "out") == 0 ) /* Output devices */
|
else if (strcmp(argv[1], "out") == 0) { /* Output devices */
|
||||||
type = output;
|
type = output;
|
||||||
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
||||||
@ -764,19 +785,24 @@ void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
|||||||
const char *error_str;
|
const char *error_str;
|
||||||
|
|
||||||
if (argc != 1) {
|
if (argc != 1) {
|
||||||
if ( argc < 1 ) error_str = "Type must be specified!";
|
if (argc < 1) {
|
||||||
else error_str = "Only two arguments allowed!";
|
error_str = "Type must be specified!";
|
||||||
|
} else {
|
||||||
|
error_str = "Only two arguments allowed!";
|
||||||
|
}
|
||||||
|
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceType type;
|
DeviceType type;
|
||||||
|
|
||||||
if ( strcasecmp(argv[1], "in") == 0 ) /* Input devices */
|
if (strcasecmp(argv[1], "in") == 0) { /* Input devices */
|
||||||
type = input;
|
type = input;
|
||||||
|
}
|
||||||
|
|
||||||
else if ( strcasecmp(argv[1], "out") == 0 ) /* Output devices */
|
else if (strcasecmp(argv[1], "out") == 0) { /* Output devices */
|
||||||
type = output;
|
type = output;
|
||||||
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
||||||
@ -812,8 +838,11 @@ void cmd_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[M
|
|||||||
const char *error_str;
|
const char *error_str;
|
||||||
|
|
||||||
if (argc != 1) {
|
if (argc != 1) {
|
||||||
if ( argc < 1 ) error_str = "Must have value!";
|
if (argc < 1) {
|
||||||
else error_str = "Only two arguments allowed!";
|
error_str = "Must have value!";
|
||||||
|
} else {
|
||||||
|
error_str = "Only two arguments allowed!";
|
||||||
|
}
|
||||||
|
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
@ -854,8 +883,8 @@ void cmd_bitrate(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
|
|||||||
|
|
||||||
const uint32_t bitrate = strtol(argv[1], NULL, 10);
|
const uint32_t bitrate = strtol(argv[1], NULL, 10);
|
||||||
|
|
||||||
TOXAV_ERR_BIT_RATE_SET error;
|
Toxav_Err_Bit_Rate_Set error;
|
||||||
audio_bit_rate_status_cb(CallControl.av, self->num, bitrate, -1, &error);
|
audio_bit_rate_status_cb(CallControl.av, self->num, bitrate, &error);
|
||||||
|
|
||||||
if (error != TOXAV_ERR_BIT_RATE_SET_OK) {
|
if (error != TOXAV_ERR_BIT_RATE_SET_OK) {
|
||||||
switch (error) {
|
switch (error) {
|
||||||
@ -863,7 +892,7 @@ void cmd_bitrate(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
|
|||||||
error_str = "Syncronization error occured";
|
error_str = "Syncronization error occured";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOXAV_ERR_BIT_RATE_SET_INVALID_AUDIO_BIT_RATE:
|
case TOXAV_ERR_BIT_RATE_SET_INVALID_BIT_RATE:
|
||||||
error_str = "Invalid audio bit rate value (valid is 6-510)";
|
error_str = "Invalid audio bit rate value (valid is 6-510)";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -900,3 +929,49 @@ void stop_current_call(ToxWindow *self)
|
|||||||
|
|
||||||
CallControl.pending_call = false;
|
CallControl.pending_call = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reallocates the Calls list according to n.
|
||||||
|
*/
|
||||||
|
static void realloc_calls(uint32_t n)
|
||||||
|
{
|
||||||
|
if (n <= 0) {
|
||||||
|
free(CallControl.calls);
|
||||||
|
CallControl.calls = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Call *temp = realloc(CallControl.calls, n * sizeof(Call));
|
||||||
|
|
||||||
|
if (temp == NULL) {
|
||||||
|
exit_toxic_err("failed in realloc_calls", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
CallControl.calls = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inits the call structure for a given friend. Called when a friend is added to the friends list.
|
||||||
|
* Index must be equivalent to the friend's friendlist index.
|
||||||
|
*/
|
||||||
|
void init_friend_AV(uint32_t index)
|
||||||
|
{
|
||||||
|
realloc_calls(CallControl.max_calls + 1);
|
||||||
|
memset(&CallControl.calls[CallControl.max_calls], 0, sizeof(Call));
|
||||||
|
|
||||||
|
if (index == CallControl.max_calls) {
|
||||||
|
++CallControl.max_calls;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a call structure from the Calls list. Called when a friend is deleted from the friends list.
|
||||||
|
* Index must be equivalent to the size of the Calls list.
|
||||||
|
*/
|
||||||
|
void del_friend_AV(uint32_t index)
|
||||||
|
{
|
||||||
|
realloc_calls(index);
|
||||||
|
CallControl.max_calls = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* AUDIO */
|
||||||
|
@ -27,8 +27,6 @@
|
|||||||
|
|
||||||
#include "audio_device.h"
|
#include "audio_device.h"
|
||||||
|
|
||||||
#define MAX_CALLS 10
|
|
||||||
|
|
||||||
typedef enum _AudioError {
|
typedef enum _AudioError {
|
||||||
ae_None = 0,
|
ae_None = 0,
|
||||||
ae_StartingCaptureDevice = 1 << 0,
|
ae_StartingCaptureDevice = 1 << 0,
|
||||||
@ -65,7 +63,9 @@ struct CallControl {
|
|||||||
ToxAV *av;
|
ToxAV *av;
|
||||||
ToxWindow *prompt;
|
ToxWindow *prompt;
|
||||||
|
|
||||||
Call calls[MAX_CALLS];
|
Call *calls;
|
||||||
|
uint32_t max_calls;
|
||||||
|
|
||||||
uint32_t call_state;
|
uint32_t call_state;
|
||||||
bool pending_call;
|
bool pending_call;
|
||||||
bool audio_enabled;
|
bool audio_enabled;
|
||||||
@ -79,15 +79,17 @@ struct CallControl {
|
|||||||
uint32_t video_bit_rate;
|
uint32_t video_bit_rate;
|
||||||
int32_t video_frame_duration;
|
int32_t video_frame_duration;
|
||||||
|
|
||||||
} CallControl;
|
};
|
||||||
|
|
||||||
struct CallControl CallControl;
|
extern struct CallControl CallControl;
|
||||||
|
|
||||||
/* You will have to pass pointer to first member of 'windows' declared in windows.c */
|
/* You will have to pass pointer to first member of 'windows' declared in windows.c */
|
||||||
ToxAV *init_audio(ToxWindow *self, Tox *tox);
|
ToxAV *init_audio(ToxWindow *self, Tox *tox);
|
||||||
void terminate_audio();
|
void terminate_audio(void);
|
||||||
int start_transmission(ToxWindow *self, Call *call);
|
int start_transmission(ToxWindow *self, Call *call);
|
||||||
int stop_transmission(Call *call, uint32_t friend_number);
|
int stop_transmission(Call *call, uint32_t friend_number);
|
||||||
void stop_current_call(ToxWindow *self);
|
void stop_current_call(ToxWindow *self);
|
||||||
|
void init_friend_AV(uint32_t index);
|
||||||
|
void del_friend_AV(uint32_t index);
|
||||||
|
|
||||||
#endif /* AUDIO_CALL_H */
|
#endif /* AUDIO_CALL_H */
|
||||||
|
@ -97,19 +97,21 @@ void *thread_poll(void *);
|
|||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
DeviceError init_devices(ToxAV *av_)
|
DeviceError init_devices(ToxAV *av_)
|
||||||
#else
|
#else
|
||||||
DeviceError init_devices()
|
DeviceError init_devices(void)
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
{
|
{
|
||||||
get_devices_names();
|
get_devices_names();
|
||||||
|
|
||||||
// Start poll thread
|
// Start poll thread
|
||||||
if (pthread_mutex_init(&mutex, NULL) != 0)
|
if (pthread_mutex_init(&mutex, NULL) != 0) {
|
||||||
return de_InternalError;
|
return de_InternalError;
|
||||||
|
}
|
||||||
|
|
||||||
pthread_t thread_id;
|
pthread_t thread_id;
|
||||||
|
|
||||||
if ( pthread_create(&thread_id, NULL, thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0)
|
if (pthread_create(&thread_id, NULL, thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0) {
|
||||||
return de_InternalError;
|
return de_InternalError;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
av = av_;
|
av = av_;
|
||||||
@ -118,7 +120,7 @@ DeviceError init_devices()
|
|||||||
return (DeviceError) de_None;
|
return (DeviceError) de_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceError terminate_devices()
|
DeviceError terminate_devices(void)
|
||||||
{
|
{
|
||||||
/* Cleanup if needed */
|
/* Cleanup if needed */
|
||||||
lock;
|
lock;
|
||||||
@ -127,13 +129,15 @@ DeviceError terminate_devices()
|
|||||||
|
|
||||||
usleep(20000);
|
usleep(20000);
|
||||||
|
|
||||||
if (pthread_mutex_destroy(&mutex) != 0)
|
if (pthread_mutex_destroy(&mutex) != 0) {
|
||||||
return (DeviceError) de_InternalError;
|
return (DeviceError) de_InternalError;
|
||||||
|
}
|
||||||
|
|
||||||
return (DeviceError) de_None;
|
return (DeviceError) de_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_devices_names() {
|
void get_devices_names(void)
|
||||||
|
{
|
||||||
|
|
||||||
const char *stringed_device_list;
|
const char *stringed_device_list;
|
||||||
|
|
||||||
@ -150,10 +154,11 @@ void get_devices_names() {
|
|||||||
|
|
||||||
size[output] = 0;
|
size[output] = 0;
|
||||||
|
|
||||||
if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE)
|
if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE) {
|
||||||
stringed_device_list = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
|
stringed_device_list = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
|
||||||
else
|
} else {
|
||||||
stringed_device_list = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
|
stringed_device_list = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
|
||||||
|
}
|
||||||
|
|
||||||
if (stringed_device_list) {
|
if (stringed_device_list) {
|
||||||
ddevice_names[output] = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
|
ddevice_names[output] = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
|
||||||
@ -167,7 +172,9 @@ void get_devices_names() {
|
|||||||
|
|
||||||
DeviceError device_mute(DeviceType type, uint32_t device_idx)
|
DeviceError device_mute(DeviceType type, uint32_t device_idx)
|
||||||
{
|
{
|
||||||
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
|
if (device_idx >= MAX_DEVICES) {
|
||||||
|
return de_InvalidSelection;
|
||||||
|
}
|
||||||
|
|
||||||
lock;
|
lock;
|
||||||
|
|
||||||
@ -187,7 +194,9 @@ DeviceError device_mute(DeviceType type, uint32_t device_idx)
|
|||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
|
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
|
||||||
{
|
{
|
||||||
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
|
if (device_idx >= MAX_DEVICES) {
|
||||||
|
return de_InvalidSelection;
|
||||||
|
}
|
||||||
|
|
||||||
lock;
|
lock;
|
||||||
|
|
||||||
@ -208,7 +217,9 @@ DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
|
|||||||
|
|
||||||
DeviceError set_primary_device(DeviceType type, int32_t selection)
|
DeviceError set_primary_device(DeviceType type, int32_t selection)
|
||||||
{
|
{
|
||||||
if (size[type] <= selection || selection < 0) return de_InvalidSelection;
|
if (size[type] <= selection || selection < 0) {
|
||||||
|
return de_InvalidSelection;
|
||||||
|
}
|
||||||
|
|
||||||
primary_device[type] = selection;
|
primary_device[type] = selection;
|
||||||
|
|
||||||
@ -230,9 +241,13 @@ void get_primary_device_name(DeviceType type, char *buf, int size)
|
|||||||
DeviceError open_device(DeviceType type, int32_t selection, uint32_t *device_idx, uint32_t sample_rate,
|
DeviceError open_device(DeviceType type, int32_t selection, uint32_t *device_idx, uint32_t sample_rate,
|
||||||
uint32_t frame_duration, uint8_t channels)
|
uint32_t frame_duration, uint8_t channels)
|
||||||
{
|
{
|
||||||
if (size[type] <= selection || selection < 0) return de_InvalidSelection;
|
if (size[type] <= selection || selection < 0) {
|
||||||
|
return de_InvalidSelection;
|
||||||
|
}
|
||||||
|
|
||||||
if (channels != 1 && channels != 2) return de_UnsupportedMode;
|
if (channels != 1 && channels != 2) {
|
||||||
|
return de_UnsupportedMode;
|
||||||
|
}
|
||||||
|
|
||||||
lock;
|
lock;
|
||||||
|
|
||||||
@ -245,7 +260,9 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t *device_idx
|
|||||||
if (i == MAX_DEVICES) {
|
if (i == MAX_DEVICES) {
|
||||||
unlock;
|
unlock;
|
||||||
return de_AllDevicesBusy;
|
return de_AllDevicesBusy;
|
||||||
} else *device_idx = i;
|
} else {
|
||||||
|
*device_idx = i;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < MAX_DEVICES; i ++) { /* Check if any device has the same selection */
|
for (i = 0; i < MAX_DEVICES; i ++) { /* Check if any device has the same selection */
|
||||||
if (running[type][i] && running[type][i]->selection == selection) {
|
if (running[type][i] && running[type][i]->selection == selection) {
|
||||||
@ -324,7 +341,9 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t *device_idx
|
|||||||
|
|
||||||
DeviceError close_device(DeviceType type, uint32_t device_idx)
|
DeviceError close_device(DeviceType type, uint32_t device_idx)
|
||||||
{
|
{
|
||||||
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
|
if (device_idx >= MAX_DEVICES) {
|
||||||
|
return de_InvalidSelection;
|
||||||
|
}
|
||||||
|
|
||||||
lock;
|
lock;
|
||||||
Device *device = running[type][device_idx];
|
Device *device = running[type][device_idx];
|
||||||
@ -339,22 +358,32 @@ DeviceError close_device(DeviceType type, uint32_t device_idx)
|
|||||||
|
|
||||||
if (!device->ref_count) {
|
if (!device->ref_count) {
|
||||||
if (type == input) {
|
if (type == input) {
|
||||||
if ( !alcCaptureCloseDevice(device->dhndl) ) rc = de_AlError;
|
if (!alcCaptureCloseDevice(device->dhndl)) {
|
||||||
|
rc = de_AlError;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (alcGetCurrentContext() != device->ctx) alcMakeContextCurrent(device->ctx);
|
if (alcGetCurrentContext() != device->ctx) {
|
||||||
|
alcMakeContextCurrent(device->ctx);
|
||||||
|
}
|
||||||
|
|
||||||
alDeleteSources(1, &device->source);
|
alDeleteSources(1, &device->source);
|
||||||
alDeleteBuffers(OPENAL_BUFS, device->buffers);
|
alDeleteBuffers(OPENAL_BUFS, device->buffers);
|
||||||
|
|
||||||
alcMakeContextCurrent(NULL);
|
alcMakeContextCurrent(NULL);
|
||||||
|
|
||||||
if ( device->ctx ) alcDestroyContext(device->ctx);
|
if (device->ctx) {
|
||||||
|
alcDestroyContext(device->ctx);
|
||||||
|
}
|
||||||
|
|
||||||
if ( !alcCloseDevice(device->dhndl) ) rc = de_AlError;
|
if (!alcCloseDevice(device->dhndl)) {
|
||||||
|
rc = de_AlError;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(device);
|
free(device);
|
||||||
} else device->ref_count--;
|
} else {
|
||||||
|
device->ref_count--;
|
||||||
|
}
|
||||||
|
|
||||||
unlock;
|
unlock;
|
||||||
return rc;
|
return rc;
|
||||||
@ -363,8 +392,9 @@ DeviceError close_device(DeviceType type, uint32_t device_idx)
|
|||||||
DeviceError register_device_callback(int32_t friend_number, uint32_t device_idx, DataHandleCallback callback,
|
DeviceError register_device_callback(int32_t friend_number, uint32_t device_idx, DataHandleCallback callback,
|
||||||
void *data, bool enable_VAD)
|
void *data, bool enable_VAD)
|
||||||
{
|
{
|
||||||
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
|
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL) {
|
||||||
return de_InvalidSelection;
|
return de_InvalidSelection;
|
||||||
|
}
|
||||||
|
|
||||||
lock;
|
lock;
|
||||||
running[input][device_idx]->cb = callback;
|
running[input][device_idx]->cb = callback;
|
||||||
@ -379,11 +409,15 @@ DeviceError register_device_callback( int32_t friend_number, uint32_t device_idx
|
|||||||
inline__ DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_t sample_count, uint8_t channels,
|
inline__ DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_t sample_count, uint8_t channels,
|
||||||
uint32_t sample_rate)
|
uint32_t sample_rate)
|
||||||
{
|
{
|
||||||
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
|
if (device_idx >= MAX_DEVICES) {
|
||||||
|
return de_InvalidSelection;
|
||||||
|
}
|
||||||
|
|
||||||
Device *device = running[output][device_idx];
|
Device *device = running[output][device_idx];
|
||||||
|
|
||||||
if (!device || device->muted) return de_DeviceNotActive;
|
if (!device || device->muted) {
|
||||||
|
return de_DeviceNotActive;
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(device->mutex);
|
pthread_mutex_lock(device->mutex);
|
||||||
|
|
||||||
@ -398,8 +432,9 @@ inline__ DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_
|
|||||||
alSourceUnqueueBuffers(device->source, processed, bufids);
|
alSourceUnqueueBuffers(device->source, processed, bufids);
|
||||||
alDeleteBuffers(processed - 1, bufids + 1);
|
alDeleteBuffers(processed - 1, bufids + 1);
|
||||||
bufid = bufids[0];
|
bufid = bufids[0];
|
||||||
} else if (queued < 16) alGenBuffers(1, &bufid);
|
} else if (queued < 16) {
|
||||||
else {
|
alGenBuffers(1, &bufid);
|
||||||
|
} else {
|
||||||
pthread_mutex_unlock(device->mutex);
|
pthread_mutex_unlock(device->mutex);
|
||||||
return de_Busy;
|
return de_Busy;
|
||||||
}
|
}
|
||||||
@ -412,7 +447,9 @@ inline__ DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_
|
|||||||
ALint state;
|
ALint state;
|
||||||
alGetSourcei(device->source, AL_SOURCE_STATE, &state);
|
alGetSourcei(device->source, AL_SOURCE_STATE, &state);
|
||||||
|
|
||||||
if (state != AL_PLAYING) alSourcePlay(device->source);
|
if (state != AL_PLAYING) {
|
||||||
|
alSourcePlay(device->source);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pthread_mutex_unlock(device->mutex);
|
pthread_mutex_unlock(device->mutex);
|
||||||
@ -469,7 +506,9 @@ void *thread_poll (void *arg) // TODO: maybe use thread for every input source
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( device->cb ) device->cb(frame, f_size, device->cb_data);
|
if (device->cb) {
|
||||||
|
device->cb(frame, f_size, device->cb_data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock;
|
unlock;
|
||||||
@ -487,7 +526,8 @@ void print_devices(ToxWindow *self, DeviceType type)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < size[type]; ++i) {
|
for (i = 0; i < size[type]; ++i) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, i == primary_device[type] ? 1 : 0, 0, "%d: %s", i, devices_names[type][i]);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, i == primary_device[type] ? 1 : 0, 0, "%d: %s", i,
|
||||||
|
devices_names[type][i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -500,8 +540,9 @@ DeviceError selection_valid(DeviceType type, int32_t selection)
|
|||||||
|
|
||||||
void *get_device_callback_data(uint32_t device_idx)
|
void *get_device_callback_data(uint32_t device_idx)
|
||||||
{
|
{
|
||||||
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
|
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return running[input][device_idx]->cb_data;
|
return running[input][device_idx]->cb_data;
|
||||||
}
|
}
|
||||||
|
@ -58,11 +58,11 @@ typedef void (*DataHandleCallback) (const int16_t *, uint32_t size, void *data);
|
|||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
DeviceError init_devices(ToxAV *av);
|
DeviceError init_devices(ToxAV *av);
|
||||||
#else
|
#else
|
||||||
DeviceError init_devices();
|
DeviceError init_devices(void);
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
void get_devices_names();
|
void get_devices_names(void);
|
||||||
DeviceError terminate_devices();
|
DeviceError terminate_devices(void);
|
||||||
|
|
||||||
/* Callback handles ready data from INPUT device */
|
/* Callback handles ready data from INPUT device */
|
||||||
DeviceError register_device_callback(int32_t friend_number, uint32_t device_idx, DataHandleCallback callback,
|
DeviceError register_device_callback(int32_t friend_number, uint32_t device_idx, DataHandleCallback callback,
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
#include <sys/dir.h>
|
#include <sys/dir.h>
|
||||||
#else
|
#else
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#endif /* ifdef __APPLE__ */
|
#endif /* __APPLE__ */
|
||||||
|
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
@ -38,16 +38,18 @@
|
|||||||
#include "execute.h"
|
#include "execute.h"
|
||||||
#include "configdir.h"
|
#include "configdir.h"
|
||||||
|
|
||||||
static void print_matches(ToxWindow *self, Tox *m, const void *list, int n_items, int size)
|
static void print_matches(ToxWindow *self, Tox *m, const void *list, size_t n_items, size_t size)
|
||||||
{
|
{
|
||||||
if (m)
|
if (m) {
|
||||||
execute(self->chatwin->history, self, m, "/clear", GLOBAL_COMMAND_MODE);
|
execute(self->chatwin->history, self, m, "/clear", GLOBAL_COMMAND_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
const char *L = (char *) list;
|
const char *L = (char *) list;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < n_items; ++i)
|
for (i = 0; i < n_items; ++i) {
|
||||||
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, "%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 */
|
||||||
}
|
}
|
||||||
@ -83,53 +85,60 @@ static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, char
|
|||||||
return snprintf(match, match_sz, "%s", matches[0]);
|
return snprintf(match, match_sz, "%s", matches[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* looks for all instances in list that begin with the last entered word in line according to pos,
|
/*
|
||||||
then fills line with the complete word. e.g. "Hello jo" would complete the line
|
* Looks for all instances in list that begin with the last entered word in line according to pos,
|
||||||
with "Hello john". If multiple matches, prints out all the matches and semi-completes line.
|
* then fills line with the complete word. e.g. "Hello jo" would complete the line
|
||||||
|
* with "Hello john". If multiple matches, prints out all the matches and semi-completes line.
|
||||||
list is a pointer to the list of strings being compared, n_items is the number of items
|
*
|
||||||
in the list, and size is the size of each item in the list.
|
* list is a pointer to the list of strings being compared, n_items is the number of items
|
||||||
|
* in the list, and size is the size of each item in the list.
|
||||||
Returns the difference between the old len and new len of line on success, -1 if error */
|
*
|
||||||
int complete_line(ToxWindow *self, const void *list, int n_items, int size)
|
* dir_search should be true if the line being completed is a file path.
|
||||||
|
*
|
||||||
|
* Returns the difference between the old len and new len of line on success.
|
||||||
|
* Returns -1 on error.
|
||||||
|
*
|
||||||
|
* Note: This function should not be called directly. Use complete_line() and complete_path() instead.
|
||||||
|
*/
|
||||||
|
static int complete_line_helper(ToxWindow *self, const void *list, size_t n_items, size_t size, bool dir_search)
|
||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
if (ctx->pos <= 0 || ctx->len <= 0 || ctx->pos > ctx->len || ctx->len >= MAX_STR_SIZE || size > MAX_STR_SIZE)
|
if (ctx->pos <= 0 || ctx->len <= 0 || ctx->pos > ctx->len) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
const char *L = (char *) list;
|
if (ctx->len >= MAX_STR_SIZE || size > MAX_STR_SIZE) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *L = (const char *) list;
|
||||||
const char *endchrs = " ";
|
const char *endchrs = " ";
|
||||||
char ubuf[MAX_STR_SIZE];
|
char ubuf[MAX_STR_SIZE] = {0};
|
||||||
|
|
||||||
/* work with multibyte string copy of buf for simplicity */
|
/* work with multibyte string copy of buf for simplicity */
|
||||||
if (wcs_to_mbs_buf(ubuf, ctx->line, sizeof(ubuf)) == -1)
|
if (wcs_to_mbs_buf(ubuf, ctx->line, sizeof(ubuf)) == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
/* TODO: generalize this */
|
|
||||||
bool dir_search = !strncmp(ubuf, "/sendfile", strlen("/sendfile"))
|
|
||||||
|| !strncmp(ubuf, "/avatar", strlen("/avatar"));
|
|
||||||
|
|
||||||
#ifdef PYTHON
|
|
||||||
dir_search = dir_search || !strncmp(ubuf, "/run", strlen("/run"));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* isolate substring from space behind pos to pos */
|
/* isolate substring from space behind pos to pos */
|
||||||
char tmp[MAX_STR_SIZE];
|
char tmp[MAX_STR_SIZE];
|
||||||
snprintf(tmp, sizeof(tmp), "%s", ubuf);
|
snprintf(tmp, sizeof(tmp), "%s", ubuf);
|
||||||
tmp[ctx->pos] = '\0';
|
tmp[ctx->pos] = '\0';
|
||||||
|
|
||||||
const char *s = dir_search ? strchr(tmp, '\"') : strrchr(tmp, ' ');
|
const char *s = strrchr(tmp, ' ');
|
||||||
char *sub = calloc(1, strlen(ubuf) + 1);
|
char *sub = calloc(1, strlen(ubuf) + 1);
|
||||||
|
|
||||||
if (sub == NULL)
|
if (sub == NULL) {
|
||||||
exit_toxic_err("failed in complete_line", FATALERR_MEMORY);
|
exit_toxic_err("failed in complete_line_helper", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
if (!s && !dir_search) {
|
if (!s && !dir_search) {
|
||||||
strcpy(sub, tmp);
|
strcpy(sub, tmp);
|
||||||
|
|
||||||
if (sub[0] != '/')
|
if (sub[0] != '/') {
|
||||||
endchrs = ": ";
|
endchrs = ": ";
|
||||||
|
}
|
||||||
} else if (s) {
|
} else if (s) {
|
||||||
strcpy(sub, &s[1]);
|
strcpy(sub, &s[1]);
|
||||||
|
|
||||||
@ -137,18 +146,19 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
|
|||||||
int sub_len = strlen(sub);
|
int sub_len = strlen(sub);
|
||||||
int si = char_rfind(sub, '/', sub_len);
|
int si = char_rfind(sub, '/', sub_len);
|
||||||
|
|
||||||
if (si || *sub == '/')
|
if (si || *sub == '/') {
|
||||||
memmove(sub, &sub[si + 1], sub_len - si);
|
memmove(sub, &sub[si + 1], sub_len - si);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!sub[0]) {
|
if (!sub[0]) {
|
||||||
free(sub);
|
free(sub);
|
||||||
return -1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int s_len = strlen(sub);
|
int s_len = strlen(sub);
|
||||||
int n_matches = 0;
|
size_t n_matches = 0;
|
||||||
char matches[n_items][MAX_STR_SIZE];
|
char matches[n_items][MAX_STR_SIZE];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
@ -157,17 +167,20 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
|
|||||||
char str[MAX_CMDNAME_SIZE + 1];
|
char str[MAX_CMDNAME_SIZE + 1];
|
||||||
snprintf(str, sizeof(str), "%s", &L[i * size]);
|
snprintf(str, sizeof(str), "%s", &L[i * size]);
|
||||||
|
|
||||||
if (strncasecmp(str, sub, s_len) == 0)
|
if (strncasecmp(str, sub, s_len) == 0) {
|
||||||
strcpy(matches[n_matches++], str);
|
strcpy(matches[n_matches++], str);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
free(sub);
|
free(sub);
|
||||||
|
|
||||||
if (!n_matches)
|
if (!n_matches) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!dir_search && n_matches > 1)
|
if (!dir_search && n_matches > 1) {
|
||||||
print_matches(self, NULL, matches, n_matches, MAX_STR_SIZE);
|
print_matches(self, NULL, matches, n_matches, MAX_STR_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
char match[MAX_STR_SIZE];
|
char match[MAX_STR_SIZE];
|
||||||
size_t match_len = get_str_match(self, match, sizeof(match), matches, n_matches);
|
size_t match_len = get_str_match(self, match, sizeof(match), matches, n_matches);
|
||||||
@ -177,10 +190,11 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dir_search) {
|
if (dir_search) {
|
||||||
if (n_matches == 1)
|
if (n_matches == 1) {
|
||||||
endchrs = char_rfind(match, '.', match_len) ? "\"" : "/";
|
endchrs = char_rfind(match, '.', match_len) ? "" : "/";
|
||||||
else
|
} else {
|
||||||
endchrs = "";
|
endchrs = "";
|
||||||
|
}
|
||||||
} else if (n_matches > 1) {
|
} else if (n_matches > 1) {
|
||||||
endchrs = "";
|
endchrs = "";
|
||||||
}
|
}
|
||||||
@ -190,8 +204,9 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
|
|||||||
int strt = ctx->pos - s_len;
|
int strt = ctx->pos - s_len;
|
||||||
int diff = match_len - s_len + n_endchrs;
|
int diff = match_len - s_len + n_endchrs;
|
||||||
|
|
||||||
if (ctx->len + diff >= MAX_STR_SIZE)
|
if (ctx->len + diff >= MAX_STR_SIZE) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
char tmpend[MAX_STR_SIZE];
|
char tmpend[MAX_STR_SIZE];
|
||||||
snprintf(tmpend, sizeof(tmpend), "%s", &ubuf[ctx->pos]);
|
snprintf(tmpend, sizeof(tmpend), "%s", &ubuf[ctx->pos]);
|
||||||
@ -201,6 +216,21 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
strcpy(&ubuf[strt], match);
|
strcpy(&ubuf[strt], match);
|
||||||
|
|
||||||
|
/* If path points to a file with no extension don't append a forward slash */
|
||||||
|
if (dir_search && *endchrs == '/') {
|
||||||
|
const char *path_start = strchr(ubuf+1, '/');
|
||||||
|
|
||||||
|
if (!path_start) { // should never happen
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_type(path_start) == FILE_TYPE_REGULAR) {
|
||||||
|
endchrs = "";
|
||||||
|
diff -= n_endchrs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
strcpy(&ubuf[strt + match_len], endchrs);
|
strcpy(&ubuf[strt + match_len], endchrs);
|
||||||
strcpy(&ubuf[strt + match_len + n_endchrs], tmpend);
|
strcpy(&ubuf[strt + match_len + n_endchrs], tmpend);
|
||||||
|
|
||||||
@ -219,8 +249,18 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
|
|||||||
return diff;
|
return diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* transforms a tab complete starting with the shorthand "~" into the full home directory.*/
|
int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size)
|
||||||
static void complt_home_dir(ToxWindow *self, char *path, int pathsize, const char *cmd, int cmdlen)
|
{
|
||||||
|
return complete_line_helper(self, list, n_items, size, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int complete_path(ToxWindow *self, const void *list, size_t n_items, size_t size)
|
||||||
|
{
|
||||||
|
return complete_line_helper(self, list, n_items, size, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Transforms a tab complete starting with the shorthand "~" into the full home directory. */
|
||||||
|
static void complete_home_dir(ToxWindow *self, char *path, int pathsize, const char *cmd, int cmdlen)
|
||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
@ -228,45 +268,51 @@ static void complt_home_dir(ToxWindow *self, char *path, int pathsize, const cha
|
|||||||
get_home_dir(homedir, sizeof(homedir));
|
get_home_dir(homedir, sizeof(homedir));
|
||||||
|
|
||||||
char newline[MAX_STR_SIZE];
|
char newline[MAX_STR_SIZE];
|
||||||
snprintf(newline, sizeof(newline), "%s \"%s%s", cmd, homedir, path + 1);
|
snprintf(newline, sizeof(newline), "%s %s%s", cmd, homedir, path + 1);
|
||||||
snprintf(path, pathsize, "%s", &newline[cmdlen]);
|
snprintf(path, pathsize, "%s", &newline[cmdlen-1]);
|
||||||
|
|
||||||
wchar_t wline[MAX_STR_SIZE];
|
wchar_t wline[MAX_STR_SIZE];
|
||||||
|
|
||||||
if (mbs_to_wcs_buf(wline, newline, sizeof(wline) / sizeof(wchar_t)) == -1)
|
if (mbs_to_wcs_buf(wline, newline, sizeof(wline) / sizeof(wchar_t)) == -1) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int newlen = wcslen(wline);
|
int newlen = wcslen(wline);
|
||||||
|
|
||||||
if (ctx->len + newlen >= MAX_STR_SIZE)
|
if (ctx->len + newlen >= MAX_STR_SIZE) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
wmemcpy(ctx->line, wline, newlen + 1);
|
wmemcpy(ctx->line, wline, newlen + 1);
|
||||||
ctx->pos = newlen;
|
ctx->pos = newlen;
|
||||||
ctx->len = ctx->pos;
|
ctx->len = ctx->pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* attempts to match /command "<incomplete-dir>" line to matching directories.
|
/* Attempts to match /command "<incomplete-dir>" line to matching directories.
|
||||||
|
* If there is only one match the line is auto-completed.
|
||||||
if only one match, auto-complete line.
|
*
|
||||||
return diff between old len and new len of ctx->line, -1 if no matches or > 1 match */
|
* Returns the diff between old len and new len of ctx->line on success.
|
||||||
|
* Returns -1 if no matches or more than one match.
|
||||||
|
*/
|
||||||
#define MAX_DIRS 512
|
#define MAX_DIRS 512
|
||||||
|
|
||||||
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
|
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
|
||||||
{
|
{
|
||||||
char b_path[MAX_STR_SIZE];
|
char b_path[MAX_STR_SIZE];
|
||||||
char b_name[MAX_STR_SIZE];
|
char b_name[MAX_STR_SIZE];
|
||||||
char b_cmd[MAX_STR_SIZE];
|
char b_cmd[MAX_STR_SIZE];
|
||||||
const wchar_t *tmpline = &line[wcslen(cmd) + 2]; /* start after "/command \"" */
|
const wchar_t *tmpline = &line[wcslen(cmd) + 1]; /* start after "/command " */
|
||||||
|
|
||||||
if (wcs_to_mbs_buf(b_path, tmpline, sizeof(b_path)) == -1)
|
if (wcs_to_mbs_buf(b_path, tmpline, sizeof(b_path)) == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (wcs_to_mbs_buf(b_cmd, cmd, sizeof(b_cmd)) == -1)
|
if (wcs_to_mbs_buf(b_cmd, cmd, sizeof(b_cmd)) == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (b_path[0] == '~')
|
if (b_path[0] == '~') {
|
||||||
complt_home_dir(self, b_path, sizeof(b_path), b_cmd, strlen(b_cmd) + 2);
|
complete_home_dir(self, b_path, sizeof(b_path), b_cmd, strlen(b_cmd) + 2);
|
||||||
|
}
|
||||||
|
|
||||||
int si = char_rfind(b_path, '/', strlen(b_path));
|
int si = char_rfind(b_path, '/', strlen(b_path));
|
||||||
|
|
||||||
@ -284,8 +330,9 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
|
|||||||
int b_name_len = strlen(b_name);
|
int b_name_len = strlen(b_name);
|
||||||
DIR *dp = opendir(b_path);
|
DIR *dp = opendir(b_path);
|
||||||
|
|
||||||
if (dp == NULL)
|
if (dp == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
char dirnames[MAX_DIRS][NAME_MAX + 1];
|
char dirnames[MAX_DIRS][NAME_MAX + 1];
|
||||||
struct dirent *entry;
|
struct dirent *entry;
|
||||||
@ -301,13 +348,14 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
|
|||||||
|
|
||||||
closedir(dp);
|
closedir(dp);
|
||||||
|
|
||||||
if (dircount == 0)
|
if (dircount == 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (dircount > 1) {
|
if (dircount > 1) {
|
||||||
qsort(dirnames, dircount, NAME_MAX, qsort_strcasecmp_hlpr);
|
qsort(dirnames, dircount, NAME_MAX + 1, qsort_strcasecmp_hlpr);
|
||||||
print_matches(self, m, dirnames, dircount, NAME_MAX);
|
print_matches(self, m, dirnames, dircount, NAME_MAX + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return complete_line(self, dirnames, dircount, NAME_MAX);
|
return complete_path(self, dirnames, dircount, NAME_MAX + 1);
|
||||||
}
|
}
|
||||||
|
@ -23,20 +23,25 @@
|
|||||||
#ifndef AUTOCOMPLETE_H
|
#ifndef AUTOCOMPLETE_H
|
||||||
#define AUTOCOMPLETE_H
|
#define AUTOCOMPLETE_H
|
||||||
|
|
||||||
/* looks for all instances in list that begin with the last entered word in line according to pos,
|
/*
|
||||||
then fills line with the complete word. e.g. "Hello jo" would complete the line
|
* Looks for all instances in list that begin with the last entered word in line according to pos,
|
||||||
with "Hello john". If multiple matches, prints out all the matches and semi-completes line.
|
* then fills line with the complete word. e.g. "Hello jo" would complete the line
|
||||||
|
* with "Hello john". If multiple matches, prints out all the matches and semi-completes line.
|
||||||
|
*
|
||||||
|
* list is a pointer to the list of strings being compared, n_items is the number of items
|
||||||
|
* in the list, and size is the size of each item in the list.
|
||||||
|
*
|
||||||
|
* Returns the difference between the old len and new len of line on success.
|
||||||
|
* Returns -1 on error.
|
||||||
|
*/
|
||||||
|
int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size);
|
||||||
|
|
||||||
list is a pointer to the list of strings being compared, n_items is the number of items
|
/* Attempts to match /command "<incomplete-dir>" line to matching directories.
|
||||||
in the list, and size is the size of each item in the list.
|
* If there is only one match the line is auto-completed.
|
||||||
|
*
|
||||||
Returns the difference between the old len and new len of line on success, -1 if error */
|
* Returns the diff between old len and new len of ctx->line on success.
|
||||||
int complete_line(ToxWindow *self, const void *list, int n_items, int size);
|
* Returns -1 if no matches or more than one match.
|
||||||
|
*/
|
||||||
/* attempts to match /command "<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 or > 1 match */
|
|
||||||
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd);
|
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd);
|
||||||
|
|
||||||
#endif /* #define AUTOCOMPLETE_H */
|
#endif /* AUTOCOMPLETE_H */
|
||||||
|
@ -52,12 +52,13 @@ static void avatar_clear(void)
|
|||||||
*/
|
*/
|
||||||
int avatar_send(Tox *m, uint32_t friendnum)
|
int avatar_send(Tox *m, uint32_t friendnum)
|
||||||
{
|
{
|
||||||
TOX_ERR_FILE_SEND err;
|
Tox_Err_File_Send err;
|
||||||
uint32_t filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_AVATAR, (size_t) Avatar.size,
|
uint32_t filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_AVATAR, (size_t) Avatar.size,
|
||||||
NULL, (uint8_t *) Avatar.name, Avatar.name_len, &err);
|
NULL, (uint8_t *) Avatar.name, Avatar.name_len, &err);
|
||||||
|
|
||||||
if (Avatar.size == 0)
|
if (Avatar.size == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (err != TOX_ERR_FILE_SEND_OK) {
|
if (err != TOX_ERR_FILE_SEND_OK) {
|
||||||
fprintf(stderr, "tox_file_send failed for friendnumber %d (error %d)\n", friendnum, err);
|
fprintf(stderr, "tox_file_send failed for friendnumber %d (error %d)\n", friendnum, err);
|
||||||
@ -66,13 +67,15 @@ int avatar_send(Tox *m, uint32_t friendnum)
|
|||||||
|
|
||||||
struct FileTransfer *ft = new_file_transfer(NULL, friendnum, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_AVATAR);
|
struct FileTransfer *ft = new_file_transfer(NULL, friendnum, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_AVATAR);
|
||||||
|
|
||||||
if (!ft)
|
if (!ft) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
ft->file = fopen(Avatar.path, "r");
|
ft->file = fopen(Avatar.path, "r");
|
||||||
|
|
||||||
if (ft->file == NULL)
|
if (ft->file == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(ft->file_name, sizeof(ft->file_name), "%s", Avatar.name);
|
snprintf(ft->file_name, sizeof(ft->file_name), "%s", Avatar.name);
|
||||||
ft->file_size = Avatar.size;
|
ft->file_size = Avatar.size;
|
||||||
@ -86,10 +89,11 @@ static void avatar_send_all(Tox *m)
|
|||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < Friends.max_idx; ++i) {
|
for (i = 0; i < Friends.max_idx; ++i) {
|
||||||
if (Friends.list[i].connection_status != TOX_CONNECTION_NONE)
|
if (Friends.list[i].connection_status != TOX_CONNECTION_NONE) {
|
||||||
avatar_send(m, Friends.list[i].num);
|
avatar_send(m, Friends.list[i].num);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Sets avatar to path and sends it to all online contacts.
|
/* Sets avatar to path and sends it to all online contacts.
|
||||||
*
|
*
|
||||||
@ -98,13 +102,15 @@ static void avatar_send_all(Tox *m)
|
|||||||
*/
|
*/
|
||||||
int avatar_set(Tox *m, const char *path, size_t path_len)
|
int avatar_set(Tox *m, const char *path, size_t path_len)
|
||||||
{
|
{
|
||||||
if (path_len == 0 || path_len >= sizeof(Avatar.path))
|
if (path_len == 0 || path_len >= sizeof(Avatar.path)) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
FILE *fp = fopen(path, "rb");
|
FILE *fp = fopen(path, "rb");
|
||||||
|
|
||||||
if (fp == NULL)
|
if (fp == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
char PNG_signature[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
|
char PNG_signature[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
|
||||||
|
|
||||||
@ -117,8 +123,9 @@ int avatar_set(Tox *m, const char *path, size_t path_len)
|
|||||||
|
|
||||||
off_t size = file_size(path);
|
off_t size = file_size(path);
|
||||||
|
|
||||||
if (size == 0 || size > MAX_AVATAR_FILE_SIZE)
|
if (size == 0 || size > MAX_AVATAR_FILE_SIZE) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
get_file_name(Avatar.name, sizeof(Avatar.name), path);
|
get_file_name(Avatar.name, sizeof(Avatar.name), path);
|
||||||
Avatar.name_len = strlen(Avatar.name);
|
Avatar.name_len = strlen(Avatar.name);
|
||||||
@ -142,7 +149,7 @@ void avatar_unset(Tox *m)
|
|||||||
avatar_send_all(m);
|
avatar_send_all(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_avatar_file_control(Tox *m, struct FileTransfer *ft, TOX_FILE_CONTROL control)
|
void on_avatar_file_control(Tox *m, struct FileTransfer *ft, Tox_File_Control control)
|
||||||
{
|
{
|
||||||
switch (control) {
|
switch (control) {
|
||||||
case TOX_FILE_CONTROL_RESUME:
|
case TOX_FILE_CONTROL_RESUME:
|
||||||
@ -166,8 +173,9 @@ void on_avatar_file_control(Tox *m, struct FileTransfer *ft, TOX_FILE_CONTROL co
|
|||||||
|
|
||||||
void on_avatar_chunk_request(Tox *m, struct FileTransfer *ft, uint64_t position, size_t length)
|
void on_avatar_chunk_request(Tox *m, struct FileTransfer *ft, uint64_t position, size_t length)
|
||||||
{
|
{
|
||||||
if (ft->state != FILE_TRANSFER_STARTED)
|
if (ft->state != FILE_TRANSFER_STARTED) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (length == 0) {
|
if (length == 0) {
|
||||||
close_file_transfer(NULL, m, ft, -1, NULL, silent);
|
close_file_transfer(NULL, m, ft, -1, NULL, silent);
|
||||||
@ -196,11 +204,12 @@ void on_avatar_chunk_request(Tox *m, struct FileTransfer *ft, uint64_t position,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TOX_ERR_FILE_SEND_CHUNK err;
|
Tox_Err_File_Send_Chunk err;
|
||||||
tox_file_send_chunk(m, ft->friendnum, ft->filenum, position, send_data, send_length, &err);
|
tox_file_send_chunk(m, ft->friendnum, ft->filenum, position, send_data, send_length, &err);
|
||||||
|
|
||||||
if (err != TOX_ERR_FILE_SEND_CHUNK_OK)
|
if (err != TOX_ERR_FILE_SEND_CHUNK_OK) {
|
||||||
fprintf(stderr, "tox_file_send_chunk failed in avatar callback (error %d)\n", err);
|
fprintf(stderr, "tox_file_send_chunk failed in avatar callback (error %d)\n", err);
|
||||||
|
}
|
||||||
|
|
||||||
ft->position += send_length;
|
ft->position += send_length;
|
||||||
ft->last_keep_alive = get_unix_time();
|
ft->last_keep_alive = get_unix_time();
|
||||||
|
@ -47,6 +47,6 @@ int avatar_set(Tox *m, const char *path, size_t length);
|
|||||||
void avatar_unset(Tox *m);
|
void avatar_unset(Tox *m);
|
||||||
|
|
||||||
void on_avatar_chunk_request(Tox *m, struct FileTransfer *ft, uint64_t position, size_t length);
|
void on_avatar_chunk_request(Tox *m, struct FileTransfer *ft, uint64_t position, size_t length);
|
||||||
void on_avatar_file_control(Tox *m, struct FileTransfer *ft, TOX_FILE_CONTROL control);
|
void on_avatar_file_control(Tox *m, struct FileTransfer *ft, Tox_File_Control control);
|
||||||
|
|
||||||
#endif /* AVATARS_H */
|
#endif /* AVATARS_H */
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include "configdir.h"
|
#include "configdir.h"
|
||||||
#include "curl_util.h"
|
#include "curl_util.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "prompt.h"
|
||||||
|
|
||||||
extern struct arg_opts arg_opts;
|
extern struct arg_opts arg_opts;
|
||||||
extern struct user_settings *user_settings;
|
extern struct user_settings *user_settings;
|
||||||
@ -108,7 +109,10 @@ static struct DHT_Nodes {
|
|||||||
/* Determine if a node is offline by comparing the age of the nodeslist
|
/* Determine if a node is offline by comparing the age of the nodeslist
|
||||||
* to the last time the node was successfully pinged.
|
* to the last time the node was successfully pinged.
|
||||||
*/
|
*/
|
||||||
#define NODE_IS_OFFLINE(last_scan, last_ping) ((last_ping + NODE_OFFLINE_TIMOUT) <= (last_ping))
|
static bool node_is_offline(unsigned long long int last_ping)
|
||||||
|
{
|
||||||
|
return last_ping + NODE_OFFLINE_TIMOUT <= last_ping;
|
||||||
|
}
|
||||||
|
|
||||||
/* Return true if nodeslist pointed to by fp needs to be updated.
|
/* Return true if nodeslist pointed to by fp needs to be updated.
|
||||||
* This will be the case if the file is empty, has an invalid format,
|
* This will be the case if the file is empty, has an invalid format,
|
||||||
@ -377,7 +381,7 @@ static int extract_node(const char *line, struct Node *node)
|
|||||||
|
|
||||||
long long int last_pinged = extract_val_last_pinged(last_pinged_str + LAST_PING_JSON_KEY_LEN);
|
long long int last_pinged = extract_val_last_pinged(last_pinged_str + LAST_PING_JSON_KEY_LEN);
|
||||||
|
|
||||||
if (last_pinged <= 0 || NODE_IS_OFFLINE(Nodes.last_scan, last_pinged)) {
|
if (last_pinged <= 0 || node_is_offline(last_pinged)) {
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -556,7 +560,7 @@ static void DHT_bootstrap(Tox *m)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
TOX_ERR_BOOTSTRAP err;
|
Tox_Err_Bootstrap err;
|
||||||
tox_bootstrap(m, addr, node->port, (uint8_t *) node->key, &err);
|
tox_bootstrap(m, addr, node->port, (uint8_t *) node->key, &err);
|
||||||
|
|
||||||
if (err != TOX_ERR_BOOTSTRAP_OK) {
|
if (err != TOX_ERR_BOOTSTRAP_OK) {
|
||||||
@ -577,7 +581,7 @@ static void DHT_bootstrap(Tox *m)
|
|||||||
void do_tox_connection(Tox *m)
|
void do_tox_connection(Tox *m)
|
||||||
{
|
{
|
||||||
static time_t last_bootstrap_time = 0;
|
static time_t last_bootstrap_time = 0;
|
||||||
bool connected = tox_self_get_connection_status(m) != TOX_CONNECTION_NONE;
|
bool connected = prompt_selfConnectionStatus() != TOX_CONNECTION_NONE;
|
||||||
|
|
||||||
if (!connected && timed_out(last_bootstrap_time, TRY_BOOTSTRAP_INTERVAL)) {
|
if (!connected && timed_out(last_bootstrap_time, TRY_BOOTSTRAP_INTERVAL)) {
|
||||||
DHT_bootstrap(m);
|
DHT_bootstrap(m);
|
||||||
|
363
src/chat.c
363
src/chat.c
@ -65,15 +65,22 @@ static void init_infobox(ToxWindow *self);
|
|||||||
static void kill_infobox(ToxWindow *self);
|
static void kill_infobox(ToxWindow *self);
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
#if defined(AUDIO) && defined(PYTHON)
|
#ifdef AUDIO
|
||||||
#define AC_NUM_CHAT_COMMANDS 32
|
#define AC_NUM_CHAT_COMMANDS_AUDIO 9
|
||||||
#elif AUDIO
|
|
||||||
#define AC_NUM_CHAT_COMMANDS 31
|
|
||||||
#elif PYTHON
|
|
||||||
#define AC_NUM_CHAT_COMMANDS 23
|
|
||||||
#else
|
#else
|
||||||
#define AC_NUM_CHAT_COMMANDS 22
|
#define AC_NUM_CHAT_COMMANDS_AUDIO 0
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
#ifdef PYTHON
|
||||||
|
#define AC_NUM_CHAT_COMMANDS_PYTHON 1
|
||||||
|
#else
|
||||||
|
#define AC_NUM_CHAT_COMMANDS_PYTHON 0
|
||||||
|
#endif /* PYTHON */
|
||||||
|
#ifdef QRCODE
|
||||||
|
#define AC_NUM_CHAT_COMMANDS_QRCODE 1
|
||||||
|
#else
|
||||||
|
#define AC_NUM_CHAT_COMMANDS_QRCODE 0
|
||||||
|
#endif /* QRCODE */
|
||||||
|
#define AC_NUM_CHAT_COMMANDS (21 + AC_NUM_CHAT_COMMANDS_AUDIO + AC_NUM_CHAT_COMMANDS_PYTHON + AC_NUM_CHAT_COMMANDS_QRCODE)
|
||||||
|
|
||||||
/* Array of chat command names used for tab completion. */
|
/* Array of chat command names used for tab completion. */
|
||||||
static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
|
static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
|
||||||
@ -91,7 +98,9 @@ static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
|
|||||||
{ "/join" },
|
{ "/join" },
|
||||||
{ "/log" },
|
{ "/log" },
|
||||||
{ "/myid" },
|
{ "/myid" },
|
||||||
|
#ifdef QRCODE
|
||||||
{ "/myqr" },
|
{ "/myqr" },
|
||||||
|
#endif /* QRCODE */
|
||||||
{ "/nick" },
|
{ "/nick" },
|
||||||
{ "/note" },
|
{ "/note" },
|
||||||
{ "/nospam" },
|
{ "/nospam" },
|
||||||
@ -123,8 +132,9 @@ static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
|
|||||||
|
|
||||||
static void set_self_typingstatus(ToxWindow *self, Tox *m, bool is_typing)
|
static void set_self_typingstatus(ToxWindow *self, Tox *m, bool is_typing)
|
||||||
{
|
{
|
||||||
if (user_settings->show_typing_self == SHOW_TYPING_OFF)
|
if (user_settings->show_typing_self == SHOW_TYPING_OFF) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
@ -170,13 +180,14 @@ static void recv_message_helper(ToxWindow *self, Tox *m, uint32_t num, const cha
|
|||||||
line_info_add(self, timefrmt, nick, NULL, IN_MSG, 0, 0, "%s", msg);
|
line_info_add(self, timefrmt, nick, NULL, IN_MSG, 0, 0, "%s", msg);
|
||||||
write_to_log(msg, nick, ctx->log, false);
|
write_to_log(msg, nick, ctx->log, false);
|
||||||
|
|
||||||
if (self->active_box != -1)
|
if (self->active_box != -1) {
|
||||||
box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
|
box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
|
||||||
self->active_box, "%s", msg);
|
self->active_box, "%s", msg);
|
||||||
else
|
} else {
|
||||||
box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
|
box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
|
||||||
&self->active_box, nick, "%s", msg);
|
&self->active_box, nick, "%s", msg);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void recv_action_helper(ToxWindow *self, Tox *m, uint32_t num, const char *action, size_t len,
|
static void recv_action_helper(ToxWindow *self, Tox *m, uint32_t num, const char *action, size_t len,
|
||||||
const char *nick, const char *timefrmt)
|
const char *nick, const char *timefrmt)
|
||||||
@ -186,18 +197,20 @@ static void recv_action_helper(ToxWindow *self, Tox *m, uint32_t num, const char
|
|||||||
line_info_add(self, timefrmt, nick, NULL, IN_ACTION, 0, 0, "%s", action);
|
line_info_add(self, timefrmt, nick, NULL, IN_ACTION, 0, 0, "%s", action);
|
||||||
write_to_log(action, nick, ctx->log, true);
|
write_to_log(action, nick, ctx->log, true);
|
||||||
|
|
||||||
if (self->active_box != -1)
|
if (self->active_box != -1) {
|
||||||
box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
|
box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
|
||||||
self->active_box, "* %s %s", nick, action);
|
self->active_box, "* %s %s", nick, action);
|
||||||
else
|
} else {
|
||||||
box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
|
box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
|
||||||
&self->active_box, self->name, "* %s %s", nick, action);
|
&self->active_box, self->name, "* %s %s", nick, action);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void chat_onMessage(ToxWindow *self, Tox *m, uint32_t num, TOX_MESSAGE_TYPE type, const char *msg, size_t len)
|
static void chat_onMessage(ToxWindow *self, Tox *m, uint32_t num, Tox_Message_Type type, const char *msg, size_t len)
|
||||||
{
|
{
|
||||||
if (self->num != num)
|
if (self->num != num) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
char nick[TOX_MAX_NAME_LENGTH];
|
char nick[TOX_MAX_NAME_LENGTH];
|
||||||
get_nick_truncate(m, nick, num);
|
get_nick_truncate(m, nick, num);
|
||||||
@ -205,20 +218,25 @@ static void chat_onMessage(ToxWindow *self, Tox *m, uint32_t num, TOX_MESSAGE_TY
|
|||||||
char timefrmt[TIME_STR_SIZE];
|
char timefrmt[TIME_STR_SIZE];
|
||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
|
|
||||||
if (type == TOX_MESSAGE_TYPE_NORMAL)
|
if (type == TOX_MESSAGE_TYPE_NORMAL) {
|
||||||
return recv_message_helper(self, m, num, msg, len, nick, timefrmt);
|
recv_message_helper(self, m, num, msg, len, nick, timefrmt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (type == TOX_MESSAGE_TYPE_ACTION)
|
if (type == TOX_MESSAGE_TYPE_ACTION) {
|
||||||
return recv_action_helper(self, m, num, msg, len, nick, timefrmt);
|
recv_action_helper(self, m, num, msg, len, nick, timefrmt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chat_pause_file_transfers(Tox *m, uint32_t friendnum);
|
static void chat_pause_file_transfers(Tox *m, uint32_t friendnum);
|
||||||
static void chat_resume_file_senders(ToxWindow *self, Tox *m, uint32_t fnum);
|
static void chat_resume_file_senders(ToxWindow *self, Tox *m, uint32_t fnum);
|
||||||
|
|
||||||
static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_CONNECTION connection_status)
|
static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, Tox_Connection connection_status)
|
||||||
{
|
{
|
||||||
if (self->num != num)
|
if (self->num != num) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
StatusBar *statusbar = self->stb;
|
StatusBar *statusbar = self->stb;
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
@ -230,7 +248,7 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_C
|
|||||||
char nick[TOX_MAX_NAME_LENGTH];
|
char nick[TOX_MAX_NAME_LENGTH];
|
||||||
get_nick_truncate(m, nick, num);
|
get_nick_truncate(m, nick, num);
|
||||||
|
|
||||||
TOX_CONNECTION prev_status = statusbar->connection;
|
Tox_Connection prev_status = statusbar->connection;
|
||||||
statusbar->connection = connection_status;
|
statusbar->connection = connection_status;
|
||||||
|
|
||||||
if (user_settings->show_connection_msg == SHOW_WELCOME_MSG_OFF) {
|
if (user_settings->show_connection_msg == SHOW_WELCOME_MSG_OFF) {
|
||||||
@ -238,8 +256,6 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_C
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (prev_status == TOX_CONNECTION_NONE) {
|
if (prev_status == TOX_CONNECTION_NONE) {
|
||||||
Friends.list[num].is_typing = user_settings->show_typing_other == SHOW_TYPING_ON
|
|
||||||
? tox_friend_get_typing(m, num, NULL) : false;
|
|
||||||
chat_resume_file_senders(self, m, num);
|
chat_resume_file_senders(self, m, num);
|
||||||
|
|
||||||
msg = "has come online";
|
msg = "has come online";
|
||||||
@ -248,8 +264,9 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_C
|
|||||||
} else if (connection_status == TOX_CONNECTION_NONE) {
|
} else if (connection_status == TOX_CONNECTION_NONE) {
|
||||||
Friends.list[num].is_typing = false;
|
Friends.list[num].is_typing = false;
|
||||||
|
|
||||||
if (self->chatwin->self_is_typing)
|
if (self->chatwin->self_is_typing) {
|
||||||
set_self_typingstatus(self, m, 0);
|
set_self_typingstatus(self, m, 0);
|
||||||
|
}
|
||||||
|
|
||||||
chat_pause_file_transfers(m, num);
|
chat_pause_file_transfers(m, num);
|
||||||
|
|
||||||
@ -261,16 +278,18 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_C
|
|||||||
|
|
||||||
static void chat_onTypingChange(ToxWindow *self, Tox *m, uint32_t num, bool is_typing)
|
static void chat_onTypingChange(ToxWindow *self, Tox *m, uint32_t num, bool is_typing)
|
||||||
{
|
{
|
||||||
if (self->num != num)
|
if (self->num != num) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Friends.list[num].is_typing = is_typing;
|
Friends.list[num].is_typing = is_typing;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chat_onNickChange(ToxWindow *self, Tox *m, uint32_t num, const char *nick, size_t length)
|
static void chat_onNickChange(ToxWindow *self, Tox *m, uint32_t num, const char *nick, size_t length)
|
||||||
{
|
{
|
||||||
if (self->num != num)
|
if (self->num != num) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
StatusBar *statusbar = self->stb;
|
StatusBar *statusbar = self->stb;
|
||||||
|
|
||||||
@ -281,10 +300,11 @@ static void chat_onNickChange(ToxWindow *self, Tox *m, uint32_t num, const char
|
|||||||
set_window_title(self, statusbar->nick, length);
|
set_window_title(self, statusbar->nick, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chat_onStatusChange(ToxWindow *self, Tox *m, uint32_t num, TOX_USER_STATUS status)
|
static void chat_onStatusChange(ToxWindow *self, Tox *m, uint32_t num, Tox_User_Status status)
|
||||||
{
|
{
|
||||||
if (self->num != num)
|
if (self->num != num) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
StatusBar *statusbar = self->stb;
|
StatusBar *statusbar = self->stb;
|
||||||
statusbar->status = status;
|
statusbar->status = status;
|
||||||
@ -292,8 +312,9 @@ static void chat_onStatusChange(ToxWindow *self, Tox *m, uint32_t num, TOX_USER_
|
|||||||
|
|
||||||
static void chat_onStatusMessageChange(ToxWindow *self, uint32_t num, const char *status, size_t length)
|
static void chat_onStatusMessageChange(ToxWindow *self, uint32_t num, const char *status, size_t length)
|
||||||
{
|
{
|
||||||
if (self->num != num)
|
if (self->num != num) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
StatusBar *statusbar = self->stb;
|
StatusBar *statusbar = self->stb;
|
||||||
|
|
||||||
@ -314,13 +335,15 @@ static void chat_pause_file_transfers(Tox *m, uint32_t friendnum)
|
|||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
for (i = 0; i < MAX_FILES; ++i) {
|
||||||
if (friend->file_sender[i].state >= FILE_TRANSFER_STARTED)
|
if (friend->file_sender[i].state >= FILE_TRANSFER_STARTED) {
|
||||||
friend->file_sender[i].state = FILE_TRANSFER_PAUSED;
|
friend->file_sender[i].state = FILE_TRANSFER_PAUSED;
|
||||||
|
}
|
||||||
|
|
||||||
if (friend->file_receiver[i].state >= FILE_TRANSFER_STARTED)
|
if (friend->file_receiver[i].state >= FILE_TRANSFER_STARTED) {
|
||||||
friend->file_receiver[i].state = FILE_TRANSFER_PAUSED;
|
friend->file_receiver[i].state = FILE_TRANSFER_PAUSED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Tries to resume broken file senders. Called when a friend comes online */
|
/* Tries to resume broken file senders. Called when a friend comes online */
|
||||||
static void chat_resume_file_senders(ToxWindow *self, Tox *m, uint32_t friendnum)
|
static void chat_resume_file_senders(ToxWindow *self, Tox *m, uint32_t friendnum)
|
||||||
@ -330,10 +353,11 @@ static void chat_resume_file_senders(ToxWindow *self, Tox *m, uint32_t friendnum
|
|||||||
for (i = 0; i < MAX_FILES; ++i) {
|
for (i = 0; i < MAX_FILES; ++i) {
|
||||||
struct FileTransfer *ft = &Friends.list[friendnum].file_sender[i];
|
struct FileTransfer *ft = &Friends.list[friendnum].file_sender[i];
|
||||||
|
|
||||||
if (ft->state != FILE_TRANSFER_PAUSED)
|
if (ft->state != FILE_TRANSFER_PAUSED) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
TOX_ERR_FILE_SEND err;
|
Tox_Err_File_Send err;
|
||||||
ft->filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_DATA, ft->file_size, ft->file_id,
|
ft->filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_DATA, ft->file_size, ft->file_id,
|
||||||
(uint8_t *) ft->file_name, strlen(ft->file_name), &err);
|
(uint8_t *) ft->file_name, strlen(ft->file_name), &err);
|
||||||
|
|
||||||
@ -349,16 +373,19 @@ static void chat_resume_file_senders(ToxWindow *self, Tox *m, uint32_t friendnum
|
|||||||
static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t position,
|
static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t position,
|
||||||
size_t length)
|
size_t length)
|
||||||
{
|
{
|
||||||
if (friendnum != self->num)
|
if (friendnum != self->num) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
|
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
|
||||||
|
|
||||||
if (!ft)
|
if (!ft) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (ft->state != FILE_TRANSFER_STARTED)
|
if (ft->state != FILE_TRANSFER_STARTED) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
char msg[MAX_STR_SIZE];
|
char msg[MAX_STR_SIZE];
|
||||||
|
|
||||||
@ -394,11 +421,12 @@ static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t friendnum,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TOX_ERR_FILE_SEND_CHUNK err;
|
Tox_Err_File_Send_Chunk err;
|
||||||
tox_file_send_chunk(m, ft->friendnum, ft->filenum, position, send_data, send_length, &err);
|
tox_file_send_chunk(m, ft->friendnum, ft->filenum, position, send_data, send_length, &err);
|
||||||
|
|
||||||
if (err != TOX_ERR_FILE_SEND_CHUNK_OK)
|
if (err != TOX_ERR_FILE_SEND_CHUNK_OK) {
|
||||||
fprintf(stderr, "tox_file_send_chunk failed in chat callback (error %d)\n", err);
|
fprintf(stderr, "tox_file_send_chunk failed in chat callback (error %d)\n", err);
|
||||||
|
}
|
||||||
|
|
||||||
ft->position += send_length;
|
ft->position += send_length;
|
||||||
ft->bps += send_length;
|
ft->bps += send_length;
|
||||||
@ -408,16 +436,19 @@ static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t friendnum,
|
|||||||
static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t position,
|
static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t position,
|
||||||
const char *data, size_t length)
|
const char *data, size_t length)
|
||||||
{
|
{
|
||||||
if (friendnum != self->num)
|
if (friendnum != self->num) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
|
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
|
||||||
|
|
||||||
if (!ft)
|
if (!ft) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (ft->state != FILE_TRANSFER_STARTED)
|
if (ft->state != FILE_TRANSFER_STARTED) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
char msg[MAX_STR_SIZE];
|
char msg[MAX_STR_SIZE];
|
||||||
|
|
||||||
@ -445,15 +476,17 @@ static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t friendnum, ui
|
|||||||
ft->last_keep_alive = get_unix_time();
|
ft->last_keep_alive = get_unix_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, TOX_FILE_CONTROL control)
|
static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, Tox_File_Control control)
|
||||||
{
|
{
|
||||||
if (friendnum != self->num)
|
if (friendnum != self->num) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
|
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
|
||||||
|
|
||||||
if (!ft)
|
if (!ft) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
char msg[MAX_STR_SIZE];
|
char msg[MAX_STR_SIZE];
|
||||||
|
|
||||||
@ -500,8 +533,9 @@ static bool chat_resume_broken_ft(ToxWindow *self, Tox *m, uint32_t friendnum, u
|
|||||||
char msg[MAX_STR_SIZE];
|
char msg[MAX_STR_SIZE];
|
||||||
uint8_t file_id[TOX_FILE_ID_LENGTH];
|
uint8_t file_id[TOX_FILE_ID_LENGTH];
|
||||||
|
|
||||||
if (!tox_file_get_file_id(m, friendnum, filenum, file_id, NULL))
|
if (!tox_file_get_file_id(m, friendnum, filenum, file_id, NULL)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool resuming = false;
|
bool resuming = false;
|
||||||
struct FileTransfer *ft = NULL;
|
struct FileTransfer *ft = NULL;
|
||||||
@ -510,8 +544,9 @@ static bool chat_resume_broken_ft(ToxWindow *self, Tox *m, uint32_t friendnum, u
|
|||||||
for (i = 0; i < MAX_FILES; ++i) {
|
for (i = 0; i < MAX_FILES; ++i) {
|
||||||
ft = &Friends.list[friendnum].file_receiver[i];
|
ft = &Friends.list[friendnum].file_receiver[i];
|
||||||
|
|
||||||
if (ft->state == FILE_TRANSFER_INACTIVE)
|
if (ft->state == FILE_TRANSFER_INACTIVE) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (memcmp(ft->file_id, file_id, TOX_FILE_ID_LENGTH) == 0) {
|
if (memcmp(ft->file_id, file_id, TOX_FILE_ID_LENGTH) == 0) {
|
||||||
ft->filenum = filenum;
|
ft->filenum = filenum;
|
||||||
@ -522,14 +557,17 @@ static bool chat_resume_broken_ft(ToxWindow *self, Tox *m, uint32_t friendnum, u
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!resuming || !ft)
|
if (!resuming || !ft) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!tox_file_seek(m, ft->friendnum, ft->filenum, ft->position, NULL))
|
if (!tox_file_seek(m, ft->friendnum, ft->filenum, ft->position, NULL)) {
|
||||||
goto on_error;
|
goto on_error;
|
||||||
|
}
|
||||||
|
|
||||||
if (!tox_file_control(m, ft->friendnum, ft->filenum, TOX_FILE_CONTROL_RESUME, NULL))
|
if (!tox_file_control(m, ft->friendnum, ft->filenum, TOX_FILE_CONTROL_RESUME, NULL)) {
|
||||||
goto on_error;
|
goto on_error;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -542,12 +580,14 @@ on_error:
|
|||||||
static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t file_size,
|
static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t file_size,
|
||||||
const char *filename, size_t name_length)
|
const char *filename, size_t name_length)
|
||||||
{
|
{
|
||||||
if (self->num != friendnum)
|
if (self->num != friendnum) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* first check if we need to resume a broken transfer */
|
/* first check if we need to resume a broken transfer */
|
||||||
if (chat_resume_broken_ft(self, m, friendnum, filenum))
|
if (chat_resume_broken_ft(self, m, friendnum, filenum)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
struct FileTransfer *ft = new_file_transfer(self, friendnum, filenum, FILE_TRANSFER_RECV, TOX_FILE_KIND_DATA);
|
struct FileTransfer *ft = new_file_transfer(self, friendnum, filenum, FILE_TRANSFER_RECV, TOX_FILE_KIND_DATA);
|
||||||
|
|
||||||
@ -612,27 +652,31 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_
|
|||||||
snprintf(ft->file_name, sizeof(ft->file_name), "%s", filename);
|
snprintf(ft->file_name, sizeof(ft->file_name), "%s", filename);
|
||||||
tox_file_get_file_id(m, friendnum, filenum, ft->file_id, NULL);
|
tox_file_get_file_id(m, friendnum, filenum, ft->file_id, NULL);
|
||||||
|
|
||||||
if (self->active_box != -1)
|
if (self->active_box != -1) {
|
||||||
box_notify2(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS | user_settings->bell_on_filetrans,
|
box_notify2(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS | user_settings->bell_on_filetrans,
|
||||||
self->active_box, "Incoming file: %s", filename);
|
self->active_box, "Incoming file: %s", filename);
|
||||||
else
|
} else {
|
||||||
box_notify(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS | user_settings->bell_on_filetrans,
|
box_notify(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS | user_settings->bell_on_filetrans,
|
||||||
&self->active_box, self->name, "Incoming file: %s", filename);
|
&self->active_box, self->name, "Incoming file: %s", filename);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, uint8_t type, const char *group_pub_key,
|
static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, uint8_t type, const char *group_pub_key,
|
||||||
uint16_t length)
|
uint16_t length)
|
||||||
{
|
{
|
||||||
if (self->num != friendnumber)
|
if (self->num != friendnumber) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (Friends.list[friendnumber].group_invite.key != NULL)
|
if (Friends.list[friendnumber].group_invite.key != NULL) {
|
||||||
free(Friends.list[friendnumber].group_invite.key);
|
free(Friends.list[friendnumber].group_invite.key);
|
||||||
|
}
|
||||||
|
|
||||||
char *k = malloc(length);
|
char *k = malloc(length);
|
||||||
|
|
||||||
if (k == NULL)
|
if (k == NULL) {
|
||||||
exit_toxic_err("Failed in chat_onGroupInvite", FATALERR_MEMORY);
|
exit_toxic_err("Failed in chat_onGroupInvite", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(k, group_pub_key, length);
|
memcpy(k, group_pub_key, length);
|
||||||
Friends.list[friendnumber].group_invite.key = k;
|
Friends.list[friendnumber].group_invite.key = k;
|
||||||
@ -645,10 +689,11 @@ static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, ui
|
|||||||
char name[TOX_MAX_NAME_LENGTH];
|
char name[TOX_MAX_NAME_LENGTH];
|
||||||
get_nick_truncate(m, name, friendnumber);
|
get_nick_truncate(m, name, friendnumber);
|
||||||
|
|
||||||
if (self->active_box != -1)
|
if (self->active_box != -1) {
|
||||||
box_silent_notify2(self, NT_WNDALERT_2 | NT_NOFOCUS, self->active_box, "invites you to join group chat");
|
box_silent_notify2(self, NT_WNDALERT_2 | NT_NOFOCUS, self->active_box, "invites you to join group chat");
|
||||||
else
|
} else {
|
||||||
box_silent_notify(self, NT_WNDALERT_2 | NT_NOFOCUS, &self->active_box, name, "invites you to join group chat");
|
box_silent_notify(self, NT_WNDALERT_2 | NT_NOFOCUS, &self->active_box, name, "invites you to join group chat");
|
||||||
|
}
|
||||||
|
|
||||||
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, "%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.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type \"/join\" to join the chat.");
|
||||||
@ -659,42 +704,48 @@ static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, ui
|
|||||||
|
|
||||||
void chat_onInvite(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
|
void chat_onInvite(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
|
||||||
{
|
{
|
||||||
if (!self || self->num != friend_number)
|
if (!self || self->num != friend_number) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* call is flagged active here */
|
/* call is flagged active here */
|
||||||
self->is_call = true;
|
self->is_call = true;
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Incoming audio call! Type: \"/answer\" or \"/reject\"");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Incoming audio call! Type: \"/answer\" or \"/reject\"");
|
||||||
|
|
||||||
if (self->ringing_sound == -1)
|
if (self->ringing_sound == -1) {
|
||||||
sound_notify(self, call_incoming, NT_LOOP | user_settings->bell_on_invite, &self->ringing_sound);
|
sound_notify(self, call_incoming, NT_LOOP | user_settings->bell_on_invite, &self->ringing_sound);
|
||||||
|
}
|
||||||
|
|
||||||
if (self->active_box != -1)
|
if (self->active_box != -1) {
|
||||||
box_silent_notify2(self, NT_NOFOCUS | NT_WNDALERT_0, self->active_box, "Incoming audio call!");
|
box_silent_notify2(self, NT_NOFOCUS | NT_WNDALERT_0, self->active_box, "Incoming audio call!");
|
||||||
else
|
} else {
|
||||||
box_silent_notify(self, NT_NOFOCUS | NT_WNDALERT_0, &self->active_box, self->name, "Incoming audio call!");
|
box_silent_notify(self, NT_NOFOCUS | NT_WNDALERT_0, &self->active_box, self->name, "Incoming audio call!");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void chat_onRinging(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
|
void chat_onRinging(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
|
||||||
{
|
{
|
||||||
if (!self || self->num != friend_number)
|
if (!self || self->num != friend_number) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ringing...type \"/hangup\" to cancel it.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ringing...type \"/hangup\" to cancel it.");
|
||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
|
|
||||||
if (self->ringing_sound == -1)
|
if (self->ringing_sound == -1) {
|
||||||
sound_notify(self, call_outgoing, NT_LOOP, &self->ringing_sound);
|
sound_notify(self, call_outgoing, NT_LOOP, &self->ringing_sound);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* SOUND_NOTIFY */
|
#endif /* SOUND_NOTIFY */
|
||||||
}
|
}
|
||||||
|
|
||||||
void chat_onStarting(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
|
void chat_onStarting(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
|
||||||
{
|
{
|
||||||
if (!self || self->num != friend_number)
|
if (!self || self->num != friend_number) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
init_infobox(self);
|
init_infobox(self);
|
||||||
|
|
||||||
@ -710,8 +761,9 @@ void chat_onStarting (ToxWindow *self, ToxAV *av, uint32_t friend_number, int st
|
|||||||
|
|
||||||
void chat_onEnding(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
|
void chat_onEnding(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
|
||||||
{
|
{
|
||||||
if (!self || self->num != friend_number)
|
if (!self || self->num != friend_number) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
kill_infobox(self);
|
kill_infobox(self);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call ended!");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call ended!");
|
||||||
@ -725,8 +777,9 @@ void chat_onEnding (ToxWindow *self, ToxAV *av, uint32_t friend_number, int stat
|
|||||||
|
|
||||||
void chat_onError(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
|
void chat_onError(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
|
||||||
{
|
{
|
||||||
if (!self || self->num != friend_number)
|
if (!self || self->num != friend_number) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self->is_call = false;
|
self->is_call = false;
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error!");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error!");
|
||||||
@ -738,8 +791,9 @@ void chat_onError (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state
|
|||||||
|
|
||||||
void chat_onStart(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
|
void chat_onStart(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
|
||||||
{
|
{
|
||||||
if (!self || self->num != friend_number)
|
if (!self || self->num != friend_number) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* call is flagged active here */
|
/* call is flagged active here */
|
||||||
self->is_call = true;
|
self->is_call = true;
|
||||||
@ -755,8 +809,9 @@ void chat_onStart (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state
|
|||||||
|
|
||||||
void chat_onCancel(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
|
void chat_onCancel(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
|
||||||
{
|
{
|
||||||
if (!self || self->num != friend_number)
|
if (!self || self->num != friend_number) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self->is_call = false;
|
self->is_call = false;
|
||||||
kill_infobox(self);
|
kill_infobox(self);
|
||||||
@ -769,8 +824,9 @@ void chat_onCancel (ToxWindow *self, ToxAV *av, uint32_t friend_number, int stat
|
|||||||
|
|
||||||
void chat_onReject(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
|
void chat_onReject(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
|
||||||
{
|
{
|
||||||
if (!self || self->num != friend_number)
|
if (!self || self->num != friend_number) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Rejected!");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Rejected!");
|
||||||
self->is_call = false;
|
self->is_call = false;
|
||||||
@ -782,8 +838,9 @@ void chat_onReject (ToxWindow *self, ToxAV *av, uint32_t friend_number, int stat
|
|||||||
|
|
||||||
void chat_onEnd(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
|
void chat_onEnd(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
|
||||||
{
|
{
|
||||||
if (!self || self->num != friend_number)
|
if (!self || self->num != friend_number) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
kill_infobox(self);
|
kill_infobox(self);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call ended!");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call ended!");
|
||||||
@ -801,8 +858,9 @@ static void init_infobox(ToxWindow *self)
|
|||||||
int x2, y2;
|
int x2, y2;
|
||||||
getmaxyx(self->window, y2, x2);
|
getmaxyx(self->window, y2, x2);
|
||||||
|
|
||||||
if (y2 <= 0 || x2 <= 0)
|
if (y2 <= 0 || x2 <= 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
(void) y2;
|
(void) y2;
|
||||||
|
|
||||||
@ -819,8 +877,9 @@ static void kill_infobox(ToxWindow *self)
|
|||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
if (!ctx->infobox.win)
|
if (!ctx->infobox.win) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
delwin(ctx->infobox.win);
|
delwin(ctx->infobox.win);
|
||||||
memset(&ctx->infobox, 0, sizeof(struct infobox));
|
memset(&ctx->infobox, 0, sizeof(struct infobox));
|
||||||
@ -831,20 +890,23 @@ static void draw_infobox(ToxWindow *self)
|
|||||||
{
|
{
|
||||||
struct infobox *infobox = &self->chatwin->infobox;
|
struct infobox *infobox = &self->chatwin->infobox;
|
||||||
|
|
||||||
if (infobox->win == NULL)
|
if (infobox->win == NULL) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int x2, y2;
|
int x2, y2;
|
||||||
getmaxyx(self->window, y2, x2);
|
getmaxyx(self->window, y2, x2);
|
||||||
|
|
||||||
if (x2 < INFOBOX_WIDTH || y2 < INFOBOX_HEIGHT)
|
if (x2 < INFOBOX_WIDTH || y2 < INFOBOX_HEIGHT) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
time_t curtime = get_unix_time();
|
time_t curtime = get_unix_time();
|
||||||
|
|
||||||
/* update elapsed time string once per second */
|
/* update elapsed time string once per second */
|
||||||
if (curtime > infobox->lastupdate)
|
if (curtime > infobox->lastupdate) {
|
||||||
get_elapsed_time_str(infobox->timestr, sizeof(infobox->timestr), curtime - infobox->starttime);
|
get_elapsed_time_str(infobox->timestr, sizeof(infobox->timestr), curtime - infobox->starttime);
|
||||||
|
}
|
||||||
|
|
||||||
infobox->lastupdate = curtime;
|
infobox->lastupdate = curtime;
|
||||||
|
|
||||||
@ -874,7 +936,7 @@ static void draw_infobox(ToxWindow *self)
|
|||||||
wattron(infobox->win, A_BOLD);
|
wattron(infobox->win, A_BOLD);
|
||||||
wprintw(infobox->win, " VAD level: ");
|
wprintw(infobox->win, " VAD level: ");
|
||||||
wattroff(infobox->win, A_BOLD);
|
wattroff(infobox->win, A_BOLD);
|
||||||
wprintw(infobox->win, "%.2f\n", infobox->vad_lvl);
|
wprintw(infobox->win, "%.2f\n", (double) infobox->vad_lvl);
|
||||||
|
|
||||||
wborder(infobox->win, ACS_VLINE, ' ', ACS_HLINE, ACS_HLINE, ACS_TTEE, ' ', ACS_LLCORNER, ' ');
|
wborder(infobox->win, ACS_VLINE, ' ', ACS_HLINE, ACS_HLINE, ACS_TTEE, ' ', ACS_LLCORNER, ' ');
|
||||||
wnoutrefresh(infobox->win);
|
wnoutrefresh(infobox->win);
|
||||||
@ -884,8 +946,9 @@ static void draw_infobox(ToxWindow *self)
|
|||||||
|
|
||||||
static void send_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
|
static void send_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
|
||||||
{
|
{
|
||||||
if (action == NULL)
|
if (action == NULL) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
char selfname[TOX_MAX_NAME_LENGTH];
|
char selfname[TOX_MAX_NAME_LENGTH];
|
||||||
tox_self_get_name(m, (uint8_t *) selfname);
|
tox_self_get_name(m, (uint8_t *) selfname);
|
||||||
@ -909,11 +972,13 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
getyx(self->window, y, x);
|
getyx(self->window, y, x);
|
||||||
getmaxyx(self->window, y2, x2);
|
getmaxyx(self->window, y2, x2);
|
||||||
|
|
||||||
if (y2 <= 0 || x2 <= 0)
|
if (y2 <= 0 || x2 <= 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (ctx->pastemode && key == '\r')
|
if (ctx->pastemode && key == '\r') {
|
||||||
key = '\n';
|
key = '\n';
|
||||||
|
}
|
||||||
|
|
||||||
if (self->help->active) {
|
if (self->help->active) {
|
||||||
help_onKey(self, key);
|
help_onKey(self, key);
|
||||||
@ -923,14 +988,16 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
if (ltr || key == '\n') { /* char is printable */
|
if (ltr || key == '\n') { /* char is printable */
|
||||||
input_new_char(self, key, x, y, x2, y2);
|
input_new_char(self, key, x, y, x2, y2);
|
||||||
|
|
||||||
if (ctx->line[0] != '/' && !ctx->self_is_typing && statusbar->connection != TOX_CONNECTION_NONE)
|
if (ctx->line[0] != '/' && !ctx->self_is_typing && statusbar->connection != TOX_CONNECTION_NONE) {
|
||||||
set_self_typingstatus(self, m, 1);
|
set_self_typingstatus(self, m, 1);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (line_info_onKey(self, key))
|
if (line_info_onKey(self, key)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
input_handle(self, key, x, y, x2, y2);
|
input_handle(self, key, x, y, x2, y2);
|
||||||
|
|
||||||
@ -938,14 +1005,14 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
int diff = -1;
|
int diff = -1;
|
||||||
|
|
||||||
/* TODO: make this not suck */
|
/* TODO: make this not suck */
|
||||||
if (wcsncmp(ctx->line, L"/sendfile \"", wcslen(L"/sendfile \"")) == 0) {
|
if (wcsncmp(ctx->line, L"/sendfile ", wcslen(L"/sendfile ")) == 0) {
|
||||||
diff = dir_match(self, m, ctx->line, L"/sendfile");
|
diff = dir_match(self, m, ctx->line, L"/sendfile");
|
||||||
} else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) {
|
} else if (wcsncmp(ctx->line, L"/avatar ", wcslen(L"/avatar ")) == 0) {
|
||||||
diff = dir_match(self, m, ctx->line, L"/avatar");
|
diff = dir_match(self, m, ctx->line, L"/avatar");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef PYTHON
|
#ifdef PYTHON
|
||||||
else if (wcsncmp(ctx->line, L"/run \"", wcslen(L"/run \"")) == 0) {
|
else if (wcsncmp(ctx->line, L"/run ", wcslen(L"/run ")) == 0) {
|
||||||
diff = dir_match(self, m, ctx->line, L"/run");
|
diff = dir_match(self, m, ctx->line, L"/run");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -981,8 +1048,9 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
|
|
||||||
char line[MAX_STR_SIZE] = {0};
|
char line[MAX_STR_SIZE] = {0};
|
||||||
|
|
||||||
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
|
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
|
||||||
memset(&line, 0, sizeof(line));
|
memset(&line, 0, sizeof(line));
|
||||||
|
}
|
||||||
|
|
||||||
if (line[0] == '/') {
|
if (line[0] == '/') {
|
||||||
if (strcmp(line, "/close") == 0) {
|
if (strcmp(line, "/close") == 0) {
|
||||||
@ -1013,17 +1081,19 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
reset_buf(ctx);
|
reset_buf(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->len <= 0 && ctx->self_is_typing)
|
if (ctx->len <= 0 && ctx->self_is_typing) {
|
||||||
set_self_typingstatus(self, m, 0);
|
set_self_typingstatus(self, m, 0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void chat_onDraw(ToxWindow *self, Tox *m)
|
static void chat_onDraw(ToxWindow *self, Tox *m)
|
||||||
{
|
{
|
||||||
int x2, y2;
|
int x2, y2;
|
||||||
getmaxyx(self->window, y2, x2);
|
getmaxyx(self->window, y2, x2);
|
||||||
|
|
||||||
if (y2 <= 0 || x2 <= 0)
|
if (y2 <= 0 || x2 <= 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
@ -1035,8 +1105,9 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
curs_set(1);
|
curs_set(1);
|
||||||
|
|
||||||
if (ctx->len > 0)
|
if (ctx->len > 0) {
|
||||||
mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]);
|
mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]);
|
||||||
|
}
|
||||||
|
|
||||||
/* Draw status bar */
|
/* Draw status bar */
|
||||||
StatusBar *statusbar = self->stb;
|
StatusBar *statusbar = self->stb;
|
||||||
@ -1046,7 +1117,7 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
/* Draw name, status and note in statusbar */
|
/* Draw name, status and note in statusbar */
|
||||||
if (statusbar->connection != TOX_CONNECTION_NONE) {
|
if (statusbar->connection != TOX_CONNECTION_NONE) {
|
||||||
int colour = MAGENTA;
|
int colour = MAGENTA;
|
||||||
TOX_USER_STATUS status = statusbar->status;
|
Tox_User_Status status = statusbar->status;
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case TOX_USER_STATUS_NONE:
|
case TOX_USER_STATUS_NONE:
|
||||||
@ -1066,15 +1137,17 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
wprintw(statusbar->topline, " %s", ONLINE_CHAR);
|
wprintw(statusbar->topline, " %s", ONLINE_CHAR);
|
||||||
wattroff(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
|
wattroff(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
|
||||||
|
|
||||||
if (Friends.list[self->num].is_typing)
|
if (Friends.list[self->num].is_typing) {
|
||||||
wattron(statusbar->topline, COLOR_PAIR(YELLOW));
|
wattron(statusbar->topline, COLOR_PAIR(YELLOW));
|
||||||
|
}
|
||||||
|
|
||||||
wattron(statusbar->topline, A_BOLD);
|
wattron(statusbar->topline, A_BOLD);
|
||||||
wprintw(statusbar->topline, " %s ", statusbar->nick);
|
wprintw(statusbar->topline, " %s ", statusbar->nick);
|
||||||
wattroff(statusbar->topline, A_BOLD);
|
wattroff(statusbar->topline, A_BOLD);
|
||||||
|
|
||||||
if (Friends.list[self->num].is_typing)
|
if (Friends.list[self->num].is_typing) {
|
||||||
wattroff(statusbar->topline, COLOR_PAIR(YELLOW));
|
wattroff(statusbar->topline, COLOR_PAIR(YELLOW));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
wprintw(statusbar->topline, " %s", OFFLINE_CHAR);
|
wprintw(statusbar->topline, " %s", OFFLINE_CHAR);
|
||||||
wattron(statusbar->topline, A_BOLD);
|
wattron(statusbar->topline, A_BOLD);
|
||||||
@ -1107,8 +1180,9 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
statusbar->statusmsg_len = maxlen;
|
statusbar->statusmsg_len = maxlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (statusbar->statusmsg[0])
|
if (statusbar->statusmsg[0]) {
|
||||||
wprintw(statusbar->topline, ": %s ", statusbar->statusmsg);
|
wprintw(statusbar->topline, ": %s ", statusbar->statusmsg);
|
||||||
|
}
|
||||||
|
|
||||||
wclrtoeol(statusbar->topline);
|
wclrtoeol(statusbar->topline);
|
||||||
wmove(statusbar->topline, 0, x2 - (KEY_IDENT_DIGITS * 2) - 3);
|
wmove(statusbar->topline, 0, x2 - (KEY_IDENT_DIGITS * 2) - 3);
|
||||||
@ -1116,8 +1190,9 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < KEY_IDENT_DIGITS; ++i)
|
for (i = 0; i < KEY_IDENT_DIGITS; ++i) {
|
||||||
wprintw(statusbar->topline, "%02X", Friends.list[self->num].pub_key[i] & 0xff);
|
wprintw(statusbar->topline, "%02X", Friends.list[self->num].pub_key[i] & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
wprintw(statusbar->topline, "}\n");
|
wprintw(statusbar->topline, "}\n");
|
||||||
|
|
||||||
@ -1139,8 +1214,9 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (self->help->active)
|
if (self->help->active) {
|
||||||
help_onDraw(self);
|
help_onDraw(self);
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
refresh_file_transfer_progress(self, m, self->num);
|
refresh_file_transfer_progress(self, m, self->num);
|
||||||
@ -1153,16 +1229,16 @@ static void chat_onInit(ToxWindow *self, Tox *m)
|
|||||||
int x2, y2;
|
int x2, y2;
|
||||||
getmaxyx(self->window, y2, x2);
|
getmaxyx(self->window, y2, x2);
|
||||||
|
|
||||||
if (y2 <= 0 || x2 <= 0)
|
if (y2 <= 0 || x2 <= 0) {
|
||||||
exit_toxic_err("failed in chat_onInit", FATALERR_CURSES);
|
exit_toxic_err("failed in chat_onInit", FATALERR_CURSES);
|
||||||
|
}
|
||||||
|
|
||||||
self->x = x2;
|
self->x = x2;
|
||||||
|
|
||||||
/* Init statusbar info */
|
/* Init statusbar info */
|
||||||
StatusBar *statusbar = self->stb;
|
StatusBar *statusbar = self->stb;
|
||||||
|
statusbar->status = get_friend_status(self->num);
|
||||||
statusbar->status = tox_friend_get_status(m, self->num, NULL);
|
statusbar->connection = get_friend_connection_status(self->num);
|
||||||
statusbar->connection = tox_friend_get_connection_status(m, self->num, NULL);
|
|
||||||
|
|
||||||
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH];
|
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH];
|
||||||
tox_friend_get_status_message(m, self->num, (uint8_t *) statusmsg, NULL);
|
tox_friend_get_status_message(m, self->num, (uint8_t *) statusmsg, NULL);
|
||||||
@ -1190,8 +1266,9 @@ static void chat_onInit(ToxWindow *self, Tox *m)
|
|||||||
ctx->log = calloc(1, sizeof(struct chatlog));
|
ctx->log = calloc(1, sizeof(struct chatlog));
|
||||||
ctx->cqueue = calloc(1, sizeof(struct chat_queue));
|
ctx->cqueue = calloc(1, sizeof(struct chat_queue));
|
||||||
|
|
||||||
if (ctx->log == NULL || ctx->hst == NULL || ctx->cqueue == NULL)
|
if (ctx->log == NULL || ctx->hst == NULL || ctx->cqueue == NULL) {
|
||||||
exit_toxic_err("failed in chat_onInit", FATALERR_MEMORY);
|
exit_toxic_err("failed in chat_onInit", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
line_info_init(ctx->hst);
|
line_info_init(ctx->hst);
|
||||||
|
|
||||||
@ -1201,10 +1278,11 @@ static void chat_onInit(ToxWindow *self, Tox *m)
|
|||||||
int log_ret = log_enable(nick, myid, Friends.list[self->num].pub_key, ctx->log, LOG_CHAT);
|
int log_ret = log_enable(nick, myid, Friends.list[self->num].pub_key, ctx->log, LOG_CHAT);
|
||||||
load_chat_history(self, ctx->log);
|
load_chat_history(self, ctx->log);
|
||||||
|
|
||||||
if (!Friends.list[self->num].logging_on)
|
if (!Friends.list[self->num].logging_on) {
|
||||||
log_disable(ctx->log);
|
log_disable(ctx->log);
|
||||||
else if (log_ret == -1)
|
} else if (log_ret == -1) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
|
||||||
|
}
|
||||||
|
|
||||||
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
|
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
|
||||||
|
|
||||||
@ -1212,64 +1290,67 @@ static void chat_onInit(ToxWindow *self, Tox *m)
|
|||||||
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ToxWindow new_chat(Tox *m, uint32_t friendnum)
|
ToxWindow *new_chat(Tox *m, uint32_t friendnum)
|
||||||
{
|
{
|
||||||
ToxWindow ret;
|
ToxWindow *ret = calloc(1, sizeof(ToxWindow));
|
||||||
memset(&ret, 0, sizeof(ret));
|
|
||||||
|
|
||||||
ret.active = true;
|
if (ret == NULL) {
|
||||||
ret.is_chat = true;
|
exit_toxic_err("failed in new_chat", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
ret.onKey = &chat_onKey;
|
ret->is_chat = true;
|
||||||
ret.onDraw = &chat_onDraw;
|
|
||||||
ret.onInit = &chat_onInit;
|
ret->onKey = &chat_onKey;
|
||||||
ret.onMessage = &chat_onMessage;
|
ret->onDraw = &chat_onDraw;
|
||||||
ret.onConnectionChange = &chat_onConnectionChange;
|
ret->onInit = &chat_onInit;
|
||||||
ret.onTypingChange = & chat_onTypingChange;
|
ret->onMessage = &chat_onMessage;
|
||||||
ret.onGroupInvite = &chat_onGroupInvite;
|
ret->onConnectionChange = &chat_onConnectionChange;
|
||||||
ret.onNickChange = &chat_onNickChange;
|
ret->onTypingChange = & chat_onTypingChange;
|
||||||
ret.onStatusChange = &chat_onStatusChange;
|
ret->onGroupInvite = &chat_onGroupInvite;
|
||||||
ret.onStatusMessageChange = &chat_onStatusMessageChange;
|
ret->onNickChange = &chat_onNickChange;
|
||||||
ret.onFileChunkRequest = &chat_onFileChunkRequest;
|
ret->onStatusChange = &chat_onStatusChange;
|
||||||
ret.onFileRecvChunk = &chat_onFileRecvChunk;
|
ret->onStatusMessageChange = &chat_onStatusMessageChange;
|
||||||
ret.onFileControl = &chat_onFileControl;
|
ret->onFileChunkRequest = &chat_onFileChunkRequest;
|
||||||
ret.onFileRecv = &chat_onFileRecv;
|
ret->onFileRecvChunk = &chat_onFileRecvChunk;
|
||||||
ret.onReadReceipt = &chat_onReadReceipt;
|
ret->onFileControl = &chat_onFileControl;
|
||||||
|
ret->onFileRecv = &chat_onFileRecv;
|
||||||
|
ret->onReadReceipt = &chat_onReadReceipt;
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
ret.onInvite = &chat_onInvite;
|
ret->onInvite = &chat_onInvite;
|
||||||
ret.onRinging = &chat_onRinging;
|
ret->onRinging = &chat_onRinging;
|
||||||
ret.onStarting = &chat_onStarting;
|
ret->onStarting = &chat_onStarting;
|
||||||
ret.onEnding = &chat_onEnding;
|
ret->onEnding = &chat_onEnding;
|
||||||
ret.onError = &chat_onError;
|
ret->onError = &chat_onError;
|
||||||
ret.onStart = &chat_onStart;
|
ret->onStart = &chat_onStart;
|
||||||
ret.onCancel = &chat_onCancel;
|
ret->onCancel = &chat_onCancel;
|
||||||
ret.onReject = &chat_onReject;
|
ret->onReject = &chat_onReject;
|
||||||
ret.onEnd = &chat_onEnd;
|
ret->onEnd = &chat_onEnd;
|
||||||
|
|
||||||
ret.is_call = false;
|
ret->is_call = false;
|
||||||
ret.device_selection[0] = ret.device_selection[1] = -1;
|
ret->device_selection[0] = ret->device_selection[1] = -1;
|
||||||
ret.ringing_sound = -1;
|
ret->ringing_sound = -1;
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
ret.active_box = -1;
|
ret->active_box = -1;
|
||||||
|
|
||||||
char nick[TOX_MAX_NAME_LENGTH];
|
char nick[TOX_MAX_NAME_LENGTH];
|
||||||
size_t n_len = get_nick_truncate(m, nick, friendnum);
|
size_t n_len = get_nick_truncate(m, nick, friendnum);
|
||||||
set_window_title(&ret, nick, n_len);
|
set_window_title(ret, nick, n_len);
|
||||||
|
|
||||||
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
|
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
|
||||||
StatusBar *stb = calloc(1, sizeof(StatusBar));
|
StatusBar *stb = calloc(1, sizeof(StatusBar));
|
||||||
Help *help = calloc(1, sizeof(Help));
|
Help *help = calloc(1, sizeof(Help));
|
||||||
|
|
||||||
if (stb == NULL || chatwin == NULL || help == NULL)
|
if (stb == NULL || chatwin == NULL || help == NULL) {
|
||||||
exit_toxic_err("failed in new_chat", FATALERR_MEMORY);
|
exit_toxic_err("failed in new_chat", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
ret.chatwin = chatwin;
|
ret->chatwin = chatwin;
|
||||||
ret.stb = stb;
|
ret->stb = stb;
|
||||||
ret.help = help;
|
ret->help = help;
|
||||||
|
|
||||||
ret.num = friendnum;
|
ret->num = friendnum;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,6 @@
|
|||||||
set msg to NULL if we don't want to display a message */
|
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 chat_close_file_receiver(Tox *m, int filenum, int friendnum, int CTRL);
|
||||||
void kill_chat_window(ToxWindow *self, Tox *m);
|
void kill_chat_window(ToxWindow *self, Tox *m);
|
||||||
ToxWindow new_chat(Tox *m, int32_t friendnum);
|
ToxWindow *new_chat(Tox *m, int32_t friendnum);
|
||||||
|
|
||||||
#endif /* end of include guard: CHAT_H */
|
#endif /* end of include guard: CHAT_H */
|
||||||
|
@ -92,7 +92,7 @@ void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TOX_ERR_CONFERENCE_INVITE err;
|
Tox_Err_Conference_Invite err;
|
||||||
|
|
||||||
if (!tox_conference_invite(m, self->num, groupnum, &err)) {
|
if (!tox_conference_invite(m, self->num, groupnum, &err)) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to group (error %d)", err);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to group (error %d)", err);
|
||||||
@ -123,9 +123,9 @@ void cmd_join_group(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TOX_ERR_CONFERENCE_JOIN err;
|
Tox_Err_Conference_Join err;
|
||||||
|
|
||||||
uint32_t groupnum = tox_conference_join(m, self->num, (uint8_t *) groupkey, length, &err);
|
uint32_t groupnum = tox_conference_join(m, self->num, (const uint8_t *) groupkey, length, &err);
|
||||||
|
|
||||||
if (err != TOX_ERR_CONFERENCE_JOIN_OK) {
|
if (err != TOX_ERR_CONFERENCE_JOIN_OK) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize (error %d)", err);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize (error %d)", err);
|
||||||
@ -167,16 +167,17 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((ft->file = fopen(ft->file_path, "a")) == NULL) {
|
if ((ft->file = fopen(ft->file_path, "a")) == NULL) {
|
||||||
const char *msg = "File transfer failed: Invalid file path.";
|
const char *msg = "File transfer failed: Invalid download path.";
|
||||||
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TOX_ERR_FILE_CONTROL err;
|
Tox_Err_File_Control err;
|
||||||
tox_file_control(m, self->num, ft->filenum, TOX_FILE_CONTROL_RESUME, &err);
|
tox_file_control(m, self->num, ft->filenum, TOX_FILE_CONTROL_RESUME, &err);
|
||||||
|
|
||||||
if (err != TOX_ERR_FILE_CONTROL_OK)
|
if (err != TOX_ERR_FILE_CONTROL_OK) {
|
||||||
goto on_recv_error;
|
goto on_recv_error;
|
||||||
|
}
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%d] as: '%s'", idx, ft->file_path);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%d] as: '%s'", idx, ft->file_path);
|
||||||
|
|
||||||
@ -224,16 +225,9 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argv[1][0] != '\"') {
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path must be enclosed in quotes.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remove opening and closing quotes */
|
|
||||||
char path[MAX_STR_SIZE];
|
char path[MAX_STR_SIZE];
|
||||||
snprintf(path, sizeof(path), "%s", &argv[1][1]);
|
snprintf(path, sizeof(path), "%s", argv[1]);
|
||||||
int path_len = strlen(path) - 1;
|
int path_len = strlen(path);
|
||||||
path[path_len] = '\0';
|
|
||||||
|
|
||||||
if (path_len >= MAX_STR_SIZE) {
|
if (path_len >= MAX_STR_SIZE) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path exceeds character limit.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path exceeds character limit.");
|
||||||
@ -258,12 +252,13 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
|||||||
char file_name[TOX_MAX_FILENAME_LENGTH];
|
char file_name[TOX_MAX_FILENAME_LENGTH];
|
||||||
size_t namelen = get_file_name(file_name, sizeof(file_name), path);
|
size_t namelen = get_file_name(file_name, sizeof(file_name), path);
|
||||||
|
|
||||||
TOX_ERR_FILE_SEND err;
|
Tox_Err_File_Send err;
|
||||||
uint32_t filenum = tox_file_send(m, self->num, TOX_FILE_KIND_DATA, (uint64_t) filesize, NULL,
|
uint32_t filenum = tox_file_send(m, self->num, TOX_FILE_KIND_DATA, (uint64_t) filesize, NULL,
|
||||||
(uint8_t *) file_name, namelen, &err);
|
(uint8_t *) file_name, namelen, &err);
|
||||||
|
|
||||||
if (err != TOX_ERR_FILE_SEND_OK)
|
if (err != TOX_ERR_FILE_SEND_OK) {
|
||||||
goto on_send_error;
|
goto on_send_error;
|
||||||
|
}
|
||||||
|
|
||||||
struct FileTransfer *ft = new_file_transfer(self, self->num, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_DATA);
|
struct FileTransfer *ft = new_file_transfer(self, self->num, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_DATA);
|
||||||
|
|
||||||
|
@ -49,4 +49,4 @@ void cmd_video(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE
|
|||||||
void cmd_ccur_video_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_ccur_video_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
|
|
||||||
#endif /* #define CHAT_COMMANDS_H */
|
#endif /* CHAT_COMMANDS_H */
|
||||||
|
@ -48,8 +48,9 @@ void get_home_dir(char *home, int size)
|
|||||||
} else {
|
} else {
|
||||||
hmstr = getenv("HOME");
|
hmstr = getenv("HOME");
|
||||||
|
|
||||||
if (hmstr == NULL)
|
if (hmstr == NULL) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "%s", hmstr);
|
snprintf(buf, sizeof(buf), "%s", hmstr);
|
||||||
hmstr = buf;
|
hmstr = buf;
|
||||||
@ -77,8 +78,9 @@ char *get_user_config_dir(void)
|
|||||||
len = strlen(home) + strlen("/Library/Application Support") + 1;
|
len = strlen(home) + strlen("/Library/Application Support") + 1;
|
||||||
user_config_dir = malloc(len);
|
user_config_dir = malloc(len);
|
||||||
|
|
||||||
if (user_config_dir == NULL)
|
if (user_config_dir == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(user_config_dir, len, "%s/Library/Application Support", home);
|
snprintf(user_config_dir, len, "%s/Library/Application Support", home);
|
||||||
# else /* __APPLE__ */
|
# else /* __APPLE__ */
|
||||||
@ -89,8 +91,9 @@ char *get_user_config_dir(void)
|
|||||||
len = strlen(home) + strlen("/.config") + 1;
|
len = strlen(home) + strlen("/.config") + 1;
|
||||||
user_config_dir = malloc(len);
|
user_config_dir = malloc(len);
|
||||||
|
|
||||||
if (user_config_dir == NULL)
|
if (user_config_dir == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(user_config_dir, len, "%s/.config", home);
|
snprintf(user_config_dir, len, "%s/.config", home);
|
||||||
} else {
|
} else {
|
||||||
@ -112,14 +115,16 @@ int create_user_config_dirs(char *path)
|
|||||||
struct stat buf;
|
struct stat buf;
|
||||||
int mkdir_err = mkdir(path, 0700);
|
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;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
char *fullpath = malloc(strlen(path) + strlen(CONFIGDIR) + 1);
|
char *fullpath = malloc(strlen(path) + strlen(CONFIGDIR) + 1);
|
||||||
char *logpath = malloc(strlen(path) + strlen(LOGDIR) + 1);
|
char *logpath = malloc(strlen(path) + strlen(LOGDIR) + 1);
|
||||||
|
|
||||||
if (fullpath == NULL || logpath == NULL)
|
if (fullpath == NULL || logpath == NULL) {
|
||||||
exit_toxic_err("failed in load_data_structures", FATALERR_MEMORY);
|
exit_toxic_err("failed in load_data_structures", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
strcpy(fullpath, path);
|
strcpy(fullpath, path);
|
||||||
strcat(fullpath, CONFIGDIR);
|
strcat(fullpath, CONFIGDIR);
|
||||||
|
@ -53,4 +53,4 @@ void get_home_dir(char *home, int size);
|
|||||||
*/
|
*/
|
||||||
int create_user_config_dirs(char *path);
|
int create_user_config_dirs(char *path);
|
||||||
|
|
||||||
#endif /* #define CONFIGDIR_H */
|
#endif /* CONFIGDIR_H */
|
||||||
|
@ -36,8 +36,9 @@
|
|||||||
*/
|
*/
|
||||||
int set_curl_proxy(CURL *c_handle, const char *proxy_address, uint16_t port, uint8_t proxy_type)
|
int set_curl_proxy(CURL *c_handle, const char *proxy_address, uint16_t port, uint8_t proxy_type)
|
||||||
{
|
{
|
||||||
if (proxy_type == TOX_PROXY_TYPE_NONE)
|
if (proxy_type == TOX_PROXY_TYPE_NONE) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (proxy_address == NULL || port == 0) {
|
if (proxy_address == NULL || port == 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
127
src/execute.c
127
src/execute.c
@ -52,7 +52,9 @@ static struct cmd_func global_commands[] = {
|
|||||||
{ "/help", cmd_prompt_help },
|
{ "/help", cmd_prompt_help },
|
||||||
{ "/log", cmd_log },
|
{ "/log", cmd_log },
|
||||||
{ "/myid", cmd_myid },
|
{ "/myid", cmd_myid },
|
||||||
|
#ifdef QRCODE
|
||||||
{ "/myqr", cmd_myqr },
|
{ "/myqr", cmd_myqr },
|
||||||
|
#endif /* QRCODE */
|
||||||
{ "/nick", cmd_nick },
|
{ "/nick", cmd_nick },
|
||||||
{ "/note", cmd_note },
|
{ "/note", cmd_note },
|
||||||
{ "/nospam", cmd_nospam },
|
{ "/nospam", cmd_nospam },
|
||||||
@ -105,52 +107,104 @@ static struct cmd_func group_commands[] = {
|
|||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef PYTHON
|
||||||
|
#define SPECIAL_COMMANDS 6
|
||||||
|
#else
|
||||||
|
#define SPECIAL_COMMANDS 5
|
||||||
|
#endif /* PYTHON */
|
||||||
|
|
||||||
|
/* Special commands are commands that only take one argument even if it contains spaces */
|
||||||
|
static const char special_commands[SPECIAL_COMMANDS][MAX_CMDNAME_SIZE] = {
|
||||||
|
"/avatar",
|
||||||
|
"/nick",
|
||||||
|
"/note",
|
||||||
|
#ifdef PYTHON
|
||||||
|
"/run",
|
||||||
|
#endif /* PYTHON */
|
||||||
|
"/title",
|
||||||
|
"/sendfile",
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Returns true if input command is in the special_commands array. */
|
||||||
|
static bool is_special_command(const char *input)
|
||||||
|
{
|
||||||
|
const int s = char_find(0, input, ' ');
|
||||||
|
|
||||||
|
for (int i = 0; i < SPECIAL_COMMANDS; ++i) {
|
||||||
|
if (strncmp(input, special_commands[i], s) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parses commands in the special_commands array. Unlike parse_command, this function
|
||||||
|
* does not split the input string at spaces.
|
||||||
|
*
|
||||||
|
* Returns the number of arguments.
|
||||||
|
*/
|
||||||
|
static int parse_special_command(WINDOW *w, ToxWindow *self, const char *input, char (*args)[MAX_STR_SIZE])
|
||||||
|
{
|
||||||
|
int len = strlen(input);
|
||||||
|
int s = char_find(0, input, ' ');
|
||||||
|
|
||||||
|
memcpy(args[0], input, s);
|
||||||
|
args[0][s++] = '\0'; // increment to remove space after "/command "
|
||||||
|
|
||||||
|
if (s >= len) {
|
||||||
|
return 1; // No additional args
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(args[1], input + s, len - s);
|
||||||
|
args[1][len - s] = '\0';
|
||||||
|
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
/* Parses input command and puts args into arg array.
|
/* Parses input command and puts args into arg array.
|
||||||
Returns number of arguments on success, -1 on failure. */
|
*
|
||||||
|
* Returns the number of arguments.
|
||||||
|
*/
|
||||||
static int parse_command(WINDOW *w, ToxWindow *self, const char *input, char (*args)[MAX_STR_SIZE])
|
static int parse_command(WINDOW *w, ToxWindow *self, const char *input, char (*args)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
|
if (is_special_command(input)) {
|
||||||
|
return parse_special_command(w, self, input, args);
|
||||||
|
}
|
||||||
|
|
||||||
char *cmd = strdup(input);
|
char *cmd = strdup(input);
|
||||||
|
|
||||||
if (cmd == NULL)
|
if (cmd == NULL) {
|
||||||
exit_toxic_err("failed in parse_command", FATALERR_MEMORY);
|
exit_toxic_err("failed in parse_command", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
int num_args = 0;
|
int num_args = 0;
|
||||||
int i = 0; /* index of last char in an argument */
|
|
||||||
|
|
||||||
/* characters wrapped in double quotes count as one arg */
|
/* characters wrapped in double quotes count as one arg */
|
||||||
while (num_args < MAX_NUM_ARGS) {
|
while (num_args < MAX_NUM_ARGS) {
|
||||||
int qt_ofst = 0; /* set to 1 to offset index for quote char at end of arg */
|
int i = char_find(0, cmd, ' '); // index of last char in an argument
|
||||||
|
memcpy(args[num_args], cmd, i);
|
||||||
|
args[num_args++][i] = '\0';
|
||||||
|
|
||||||
if (*cmd == '\"') {
|
if (cmd[i] == '\0') { // no more args
|
||||||
qt_ofst = 1;
|
|
||||||
i = char_find(1, cmd, '\"');
|
|
||||||
|
|
||||||
if (cmd[i] == '\0') {
|
|
||||||
const char *errmsg = "Invalid argument. Did you forget a closing \"?";
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
|
||||||
free(cmd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
i = char_find(0, cmd, ' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(args[num_args], cmd, i + qt_ofst);
|
|
||||||
args[num_args++][i + qt_ofst] = '\0';
|
|
||||||
|
|
||||||
if (cmd[i] == '\0') /* no more args */
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
char tmp[MAX_STR_SIZE];
|
char tmp[MAX_STR_SIZE];
|
||||||
snprintf(tmp, sizeof(tmp), "%s", &cmd[i + 1]);
|
snprintf(tmp, sizeof(tmp), "%s", &cmd[i + 1]);
|
||||||
strcpy(cmd, tmp); /* tmp will always fit inside cmd */
|
strcpy(cmd, tmp); // tmp will always fit inside cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
free(cmd);
|
free(cmd);
|
||||||
return num_args;
|
return num_args;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Matches command to respective function. Returns 0 on match, 1 on no match */
|
/* Matches command to respective function.
|
||||||
|
*
|
||||||
|
* Returns 0 on match.
|
||||||
|
* Returns 1 on no match
|
||||||
|
*/
|
||||||
static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, struct cmd_func *commands,
|
static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, struct cmd_func *commands,
|
||||||
char (*args)[MAX_STR_SIZE])
|
char (*args)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
@ -168,40 +222,47 @@ static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, struct c
|
|||||||
|
|
||||||
void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode)
|
void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode)
|
||||||
{
|
{
|
||||||
if (string_is_empty(input))
|
if (string_is_empty(input)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
char args[MAX_NUM_ARGS][MAX_STR_SIZE];
|
char args[MAX_NUM_ARGS][MAX_STR_SIZE];
|
||||||
int num_args = parse_command(w, self, input, args);
|
int num_args = parse_command(w, self, input, args);
|
||||||
|
|
||||||
if (num_args == -1)
|
if (num_args <= 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Try to match input command to command functions. If non-global command mode is specified,
|
/* Try to match input command to command functions. If non-global command mode is specified,
|
||||||
try specified mode's commands first, then upon failure try global commands.
|
* try specified mode's commands first, then upon failure try global commands.
|
||||||
|
*
|
||||||
Note: Global commands must come last in case of duplicate command names */
|
* Note: Global commands must come last in case of duplicate command names
|
||||||
|
*/
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case CHAT_COMMAND_MODE:
|
case CHAT_COMMAND_MODE:
|
||||||
if (do_command(w, self, m, num_args, chat_commands, args) == 0)
|
if (do_command(w, self, m, num_args, chat_commands, args) == 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GROUPCHAT_COMMAND_MODE:
|
case GROUPCHAT_COMMAND_MODE:
|
||||||
if (do_command(w, self, m, num_args, group_commands, args) == 0)
|
if (do_command(w, self, m, num_args, group_commands, args) == 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (do_command(w, self, m, num_args, global_commands, args) == 0)
|
if (do_command(w, self, m, num_args, global_commands, args) == 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef PYTHON
|
#ifdef PYTHON
|
||||||
|
|
||||||
if (do_plugin_command(num_args, args) == 0)
|
if (do_plugin_command(num_args, args) == 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -36,4 +36,4 @@ enum {
|
|||||||
|
|
||||||
void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode);
|
void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode);
|
||||||
|
|
||||||
#endif /* #define EXECUTE_H */
|
#endif /* EXECUTE_H */
|
||||||
|
@ -45,8 +45,9 @@ void init_progress_bar(char *progline)
|
|||||||
strcpy(progline, "0% [");
|
strcpy(progline, "0% [");
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < NUM_PROG_MARKS; ++i)
|
for (i = 0; i < NUM_PROG_MARKS; ++i) {
|
||||||
strcat(progline, "-");
|
strcat(progline, "-");
|
||||||
|
}
|
||||||
|
|
||||||
strcat(progline, "] 0.0 B/s");
|
strcat(progline, "] 0.0 B/s");
|
||||||
}
|
}
|
||||||
@ -54,8 +55,9 @@ void init_progress_bar(char *progline)
|
|||||||
/* prints a progress bar for file transfers. */
|
/* prints a progress bar for file transfers. */
|
||||||
void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t line_id)
|
void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t line_id)
|
||||||
{
|
{
|
||||||
if (bps < 0 || pct_done < 0 || pct_done > 100)
|
if (bps < 0 || pct_done < 0 || pct_done > 100) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
char pct_str[24];
|
char pct_str[24];
|
||||||
snprintf(pct_str, sizeof(pct_str), "%.1f%%", pct_done);
|
snprintf(pct_str, sizeof(pct_str), "%.1f%%", pct_done);
|
||||||
@ -67,14 +69,17 @@ void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t l
|
|||||||
int n = pct_done / (100 / NUM_PROG_MARKS);
|
int n = pct_done / (100 / NUM_PROG_MARKS);
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
for (i = 0; i < n; ++i)
|
for (i = 0; i < n; ++i) {
|
||||||
strcat(prog_line, "=");
|
strcat(prog_line, "=");
|
||||||
|
}
|
||||||
|
|
||||||
if (pct_done < 100)
|
if (pct_done < 100) {
|
||||||
strcpy(prog_line + n, ">");
|
strcpy(prog_line + n, ">");
|
||||||
|
}
|
||||||
|
|
||||||
for (j = i; j < NUM_PROG_MARKS - 1; ++j)
|
for (j = i; j < NUM_PROG_MARKS - 1; ++j) {
|
||||||
strcat(prog_line, "-");
|
strcat(prog_line, "-");
|
||||||
|
}
|
||||||
|
|
||||||
char full_line[strlen(pct_str) + NUM_PROG_MARKS + strlen(bps_str) + 7];
|
char full_line[strlen(pct_str) + NUM_PROG_MARKS + strlen(bps_str) + 7];
|
||||||
snprintf(full_line, sizeof(full_line), "%s [%s] %s/s", pct_str, prog_line, bps_str);
|
snprintf(full_line, sizeof(full_line), "%s [%s] %s/s", pct_str, prog_line, bps_str);
|
||||||
@ -84,12 +89,14 @@ void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t l
|
|||||||
|
|
||||||
static void refresh_progress_helper(ToxWindow *self, Tox *m, struct FileTransfer *ft)
|
static void refresh_progress_helper(ToxWindow *self, Tox *m, struct FileTransfer *ft)
|
||||||
{
|
{
|
||||||
if (ft->state == FILE_TRANSFER_INACTIVE)
|
if (ft->state == FILE_TRANSFER_INACTIVE) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Timeout must be set to 1 second to show correct bytes per second */
|
/* Timeout must be set to 1 second to show correct bytes per second */
|
||||||
if (!timed_out(ft->last_line_progress, 1))
|
if (!timed_out(ft->last_line_progress, 1)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
double remain = ft->file_size - ft->position;
|
double remain = ft->file_size - ft->position;
|
||||||
double pct_done = remain > 0 ? (1 - (remain / ft->file_size)) * 100 : 100;
|
double pct_done = remain > 0 ? (1 - (remain / ft->file_size)) * 100 : 100;
|
||||||
@ -120,14 +127,16 @@ struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filen
|
|||||||
for (i = 0; i < MAX_FILES; ++i) {
|
for (i = 0; i < MAX_FILES; ++i) {
|
||||||
struct FileTransfer *ft_send = &Friends.list[friendnum].file_sender[i];
|
struct FileTransfer *ft_send = &Friends.list[friendnum].file_sender[i];
|
||||||
|
|
||||||
if (ft_send->state != FILE_TRANSFER_INACTIVE && ft_send->filenum == filenum)
|
if (ft_send->state != FILE_TRANSFER_INACTIVE && ft_send->filenum == filenum) {
|
||||||
return ft_send;
|
return ft_send;
|
||||||
|
}
|
||||||
|
|
||||||
struct FileTransfer *ft_recv = &Friends.list[friendnum].file_receiver[i];
|
struct FileTransfer *ft_recv = &Friends.list[friendnum].file_receiver[i];
|
||||||
|
|
||||||
if (ft_recv->state != FILE_TRANSFER_INACTIVE && ft_recv->filenum == filenum)
|
if (ft_recv->state != FILE_TRANSFER_INACTIVE && ft_recv->filenum == filenum) {
|
||||||
return ft_recv;
|
return ft_recv;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -138,8 +147,9 @@ struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filen
|
|||||||
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t index,
|
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t index,
|
||||||
FILE_TRANSFER_DIRECTION direction)
|
FILE_TRANSFER_DIRECTION direction)
|
||||||
{
|
{
|
||||||
if (direction != FILE_TRANSFER_RECV && direction != FILE_TRANSFER_SEND)
|
if (direction != FILE_TRANSFER_RECV && direction != FILE_TRANSFER_SEND) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
@ -148,9 +158,10 @@ struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t
|
|||||||
&Friends.list[friendnum].file_sender[i] :
|
&Friends.list[friendnum].file_sender[i] :
|
||||||
&Friends.list[friendnum].file_receiver[i];
|
&Friends.list[friendnum].file_receiver[i];
|
||||||
|
|
||||||
if (ft->state != FILE_TRANSFER_INACTIVE && ft->index == index)
|
if (ft->state != FILE_TRANSFER_INACTIVE && ft->index == index) {
|
||||||
return ft;
|
return ft;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -215,11 +226,13 @@ static struct FileTransfer *new_file_receiver(ToxWindow *window, uint32_t friend
|
|||||||
struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnum, uint32_t filenum,
|
struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnum, uint32_t filenum,
|
||||||
FILE_TRANSFER_DIRECTION direction, uint8_t type)
|
FILE_TRANSFER_DIRECTION direction, uint8_t type)
|
||||||
{
|
{
|
||||||
if (direction == FILE_TRANSFER_RECV)
|
if (direction == FILE_TRANSFER_RECV) {
|
||||||
return new_file_receiver(window, friendnum, filenum, type);
|
return new_file_receiver(window, friendnum, filenum, type);
|
||||||
|
}
|
||||||
|
|
||||||
if (direction == FILE_TRANSFER_SEND)
|
if (direction == FILE_TRANSFER_SEND) {
|
||||||
return new_file_sender(window, friendnum, filenum, type);
|
return new_file_sender(window, friendnum, filenum, type);
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -233,23 +246,28 @@ struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnum, ui
|
|||||||
void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int CTRL, const char *message,
|
void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int CTRL, const char *message,
|
||||||
Notification sound_type)
|
Notification sound_type)
|
||||||
{
|
{
|
||||||
if (!ft)
|
if (!ft) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (ft->state == FILE_TRANSFER_INACTIVE)
|
if (ft->state == FILE_TRANSFER_INACTIVE) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (ft->file)
|
if (ft->file) {
|
||||||
fclose(ft->file);
|
fclose(ft->file);
|
||||||
|
}
|
||||||
|
|
||||||
if (CTRL >= 0)
|
if (CTRL >= 0) {
|
||||||
tox_file_control(m, ft->friendnum, ft->filenum, (TOX_FILE_CONTROL) CTRL, NULL);
|
tox_file_control(m, ft->friendnum, ft->filenum, (Tox_File_Control) CTRL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
if (message && self) {
|
if (message && self) {
|
||||||
if (self->active_box != -1 && sound_type != silent)
|
if (self->active_box != -1 && sound_type != silent) {
|
||||||
box_notify2(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", message);
|
box_notify2(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", message);
|
||||||
else
|
} else {
|
||||||
box_notify(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", message);
|
box_notify(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", message);
|
||||||
|
}
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", message);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", message);
|
||||||
}
|
}
|
||||||
@ -272,6 +290,7 @@ void kill_all_file_transfers(Tox *m)
|
|||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < Friends.max_idx; ++i)
|
for (i = 0; i < Friends.max_idx; ++i) {
|
||||||
kill_all_file_transfers_friend(m, Friends.list[i].num);
|
kill_all_file_transfers_friend(m, Friends.list[i].num);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -108,4 +108,4 @@ void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum);
|
|||||||
|
|
||||||
void kill_all_file_transfers(Tox *m);
|
void kill_all_file_transfers(Tox *m);
|
||||||
|
|
||||||
#endif /* #define FILE_TRANSFERS_H */
|
#endif /* FILE_TRANSFERS_H */
|
||||||
|
318
src/friendlist.c
318
src/friendlist.c
@ -84,8 +84,9 @@ static void realloc_friends(int n)
|
|||||||
ToxicFriend *f = realloc(Friends.list, n * sizeof(ToxicFriend));
|
ToxicFriend *f = realloc(Friends.list, n * sizeof(ToxicFriend));
|
||||||
uint32_t *f_idx = realloc(Friends.index, n * sizeof(uint32_t));
|
uint32_t *f_idx = realloc(Friends.index, n * sizeof(uint32_t));
|
||||||
|
|
||||||
if (f == NULL || f_idx == NULL)
|
if (f == NULL || f_idx == NULL) {
|
||||||
exit_toxic_err("failed in realloc_friends", FATALERR_MEMORY);
|
exit_toxic_err("failed in realloc_friends", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
Friends.list = f;
|
Friends.list = f;
|
||||||
Friends.index = f_idx;
|
Friends.index = f_idx;
|
||||||
@ -104,24 +105,26 @@ static void realloc_blocklist(int n)
|
|||||||
BlockedFriend *b = realloc(Blocked.list, n * sizeof(BlockedFriend));
|
BlockedFriend *b = realloc(Blocked.list, n * sizeof(BlockedFriend));
|
||||||
uint32_t *b_idx = realloc(Blocked.index, n * sizeof(uint32_t));
|
uint32_t *b_idx = realloc(Blocked.index, n * sizeof(uint32_t));
|
||||||
|
|
||||||
if (b == NULL || b_idx == NULL)
|
if (b == NULL || b_idx == NULL) {
|
||||||
exit_toxic_err("failed in realloc_blocklist", FATALERR_MEMORY);
|
exit_toxic_err("failed in realloc_blocklist", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
Blocked.list = b;
|
Blocked.list = b;
|
||||||
Blocked.index = b_idx;
|
Blocked.index = b_idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void kill_friendlist(void)
|
void kill_friendlist(ToxWindow *self)
|
||||||
{
|
{
|
||||||
int i;
|
for (size_t i = 0; i < Friends.max_idx; ++i) {
|
||||||
|
if (Friends.list[i].active && Friends.list[i].group_invite.key != NULL) {
|
||||||
for (i = 0; i < Friends.max_idx; ++i) {
|
|
||||||
if (Friends.list[i].active && Friends.list[i].group_invite.key != NULL)
|
|
||||||
free(Friends.list[i].group_invite.key);
|
free(Friends.list[i].group_invite.key);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
realloc_blocklist(0);
|
realloc_blocklist(0);
|
||||||
realloc_friends(0);
|
realloc_friends(0);
|
||||||
|
free(self->help);
|
||||||
|
del_window(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Saves the blocklist to path. If there are no items in the blocklist the
|
/* Saves the blocklist to path. If there are no items in the blocklist the
|
||||||
@ -215,13 +218,15 @@ static void sort_blocklist_index(void);
|
|||||||
|
|
||||||
int load_blocklist(char *path)
|
int load_blocklist(char *path)
|
||||||
{
|
{
|
||||||
if (path == NULL)
|
if (path == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
FILE *fp = fopen(path, "rb");
|
FILE *fp = fopen(path, "rb");
|
||||||
|
|
||||||
if (fp == NULL)
|
if (fp == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
off_t len = file_size(path);
|
off_t len = file_size(path);
|
||||||
|
|
||||||
@ -298,9 +303,10 @@ void sort_friendlist_index(void)
|
|||||||
uint32_t n = 0;
|
uint32_t n = 0;
|
||||||
|
|
||||||
for (i = 0; i < Friends.max_idx; ++i) {
|
for (i = 0; i < Friends.max_idx; ++i) {
|
||||||
if (Friends.list[i].active)
|
if (Friends.list[i].active) {
|
||||||
Friends.index[n++] = Friends.list[i].num;
|
Friends.index[n++] = Friends.list[i].num;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
qsort(Friends.index, Friends.num_friends, sizeof(uint32_t), index_name_cmp);
|
qsort(Friends.index, Friends.num_friends, sizeof(uint32_t), index_name_cmp);
|
||||||
}
|
}
|
||||||
@ -316,9 +322,10 @@ static void sort_blocklist_index(void)
|
|||||||
uint32_t n = 0;
|
uint32_t n = 0;
|
||||||
|
|
||||||
for (i = 0; i < Blocked.max_idx; ++i) {
|
for (i = 0; i < Blocked.max_idx; ++i) {
|
||||||
if (Blocked.list[i].active)
|
if (Blocked.list[i].active) {
|
||||||
Blocked.index[n++] = Blocked.list[i].num;
|
Blocked.index[n++] = Blocked.list[i].num;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
qsort(Blocked.index, Blocked.num_blocked, sizeof(uint32_t), index_name_cmp_block);
|
qsort(Blocked.index, Blocked.num_blocked, sizeof(uint32_t), index_name_cmp_block);
|
||||||
}
|
}
|
||||||
@ -334,14 +341,16 @@ static void update_friend_last_online(uint32_t num, time_t timestamp)
|
|||||||
&Friends.list[num].last_online.tm);
|
&Friends.list[num].last_online.tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void friendlist_onMessage(ToxWindow *self, Tox *m, uint32_t num, TOX_MESSAGE_TYPE type, const char *str,
|
static void friendlist_onMessage(ToxWindow *self, Tox *m, uint32_t num, Tox_Message_Type type, const char *str,
|
||||||
size_t length)
|
size_t length)
|
||||||
{
|
{
|
||||||
if (num >= Friends.max_idx)
|
if (num >= Friends.max_idx) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (Friends.list[num].chatwin != -1)
|
if (Friends.list[num].chatwin != -1) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
||||||
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
|
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
|
||||||
@ -359,19 +368,21 @@ static void friendlist_onMessage(ToxWindow *self, Tox *m, uint32_t num, TOX_MESS
|
|||||||
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
|
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_CONNECTION connection_status)
|
static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, Tox_Connection connection_status)
|
||||||
{
|
{
|
||||||
if (num >= Friends.max_idx)
|
if (num >= Friends.max_idx) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (connection_status == TOX_CONNECTION_NONE) {
|
if (connection_status == TOX_CONNECTION_NONE) {
|
||||||
--Friends.num_online;
|
--Friends.num_online;
|
||||||
} else if (Friends.list[num].connection_status == TOX_CONNECTION_NONE) {
|
} else if (Friends.list[num].connection_status == TOX_CONNECTION_NONE) {
|
||||||
++Friends.num_online;
|
++Friends.num_online;
|
||||||
|
|
||||||
if (avatar_send(m, num) == -1)
|
if (avatar_send(m, num) == -1) {
|
||||||
fprintf(stderr, "avatar_send failed for friend %d\n", num);
|
fprintf(stderr, "avatar_send failed for friend %d\n", num);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Friends.list[num].connection_status = connection_status;
|
Friends.list[num].connection_status = connection_status;
|
||||||
update_friend_last_online(num, get_unix_time());
|
update_friend_last_online(num, get_unix_time());
|
||||||
@ -381,8 +392,9 @@ static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num,
|
|||||||
|
|
||||||
static void friendlist_onNickChange(ToxWindow *self, Tox *m, uint32_t num, const char *nick, size_t length)
|
static void friendlist_onNickChange(ToxWindow *self, Tox *m, uint32_t num, const char *nick, size_t length)
|
||||||
{
|
{
|
||||||
if (num >= Friends.max_idx)
|
if (num >= Friends.max_idx) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* save old name for log renaming */
|
/* save old name for log renaming */
|
||||||
char oldname[TOXIC_MAX_NAME_LENGTH + 1];
|
char oldname[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
@ -398,24 +410,27 @@ static void friendlist_onNickChange(ToxWindow *self, Tox *m, uint32_t num, const
|
|||||||
strcpy(newnamecpy, Friends.list[num].name);
|
strcpy(newnamecpy, Friends.list[num].name);
|
||||||
tox_self_get_address(m, (uint8_t *) myid);
|
tox_self_get_address(m, (uint8_t *) myid);
|
||||||
|
|
||||||
if (strcmp(oldname, newnamecpy) != 0)
|
if (strcmp(oldname, newnamecpy) != 0) {
|
||||||
rename_logfile(oldname, newnamecpy, myid, Friends.list[num].pub_key, Friends.list[num].chatwin);
|
rename_logfile(oldname, newnamecpy, myid, Friends.list[num].pub_key, Friends.list[num].chatwin);
|
||||||
|
}
|
||||||
|
|
||||||
sort_friendlist_index();
|
sort_friendlist_index();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void friendlist_onStatusChange(ToxWindow *self, Tox *m, uint32_t num, TOX_USER_STATUS status)
|
static void friendlist_onStatusChange(ToxWindow *self, Tox *m, uint32_t num, Tox_User_Status status)
|
||||||
{
|
{
|
||||||
if (num >= Friends.max_idx)
|
if (num >= Friends.max_idx) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Friends.list[num].status = status;
|
Friends.list[num].status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void friendlist_onStatusMessageChange(ToxWindow *self, uint32_t num, const char *note, size_t length)
|
static void friendlist_onStatusMessageChange(ToxWindow *self, uint32_t num, const char *note, size_t length)
|
||||||
{
|
{
|
||||||
if (length > TOX_MAX_STATUS_MESSAGE_LENGTH || num >= Friends.max_idx)
|
if (length > TOX_MAX_STATUS_MESSAGE_LENGTH || num >= Friends.max_idx) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(Friends.list[num].statusmsg, sizeof(Friends.list[num].statusmsg), "%s", note);
|
snprintf(Friends.list[num].statusmsg, sizeof(Friends.list[num].statusmsg), "%s", note);
|
||||||
Friends.list[num].statusmsg_len = strlen(Friends.list[num].statusmsg);
|
Friends.list[num].statusmsg_len = strlen(Friends.list[num].statusmsg);
|
||||||
@ -429,8 +444,9 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort)
|
|||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
|
||||||
for (i = 0; i <= Friends.max_idx; ++i) {
|
for (i = 0; i <= Friends.max_idx; ++i) {
|
||||||
if (Friends.list[i].active)
|
if (Friends.list[i].active) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
++Friends.num_friends;
|
++Friends.num_friends;
|
||||||
|
|
||||||
@ -441,17 +457,19 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort)
|
|||||||
Friends.list[i].status = TOX_USER_STATUS_NONE;
|
Friends.list[i].status = TOX_USER_STATUS_NONE;
|
||||||
Friends.list[i].logging_on = (bool) user_settings->autolog == AUTOLOG_ON;
|
Friends.list[i].logging_on = (bool) user_settings->autolog == AUTOLOG_ON;
|
||||||
|
|
||||||
TOX_ERR_FRIEND_GET_PUBLIC_KEY pkerr;
|
Tox_Err_Friend_Get_Public_Key pkerr;
|
||||||
tox_friend_get_public_key(m, num, (uint8_t *) Friends.list[i].pub_key, &pkerr);
|
tox_friend_get_public_key(m, num, (uint8_t *) Friends.list[i].pub_key, &pkerr);
|
||||||
|
|
||||||
if (pkerr != TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK)
|
if (pkerr != TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK) {
|
||||||
fprintf(stderr, "tox_friend_get_public_key failed (error %d)\n", pkerr);
|
fprintf(stderr, "tox_friend_get_public_key failed (error %d)\n", pkerr);
|
||||||
|
}
|
||||||
|
|
||||||
TOX_ERR_FRIEND_GET_LAST_ONLINE loerr;
|
Tox_Err_Friend_Get_Last_Online loerr;
|
||||||
time_t t = tox_friend_get_last_online(m, num, &loerr);
|
time_t t = tox_friend_get_last_online(m, num, &loerr);
|
||||||
|
|
||||||
if (loerr != TOX_ERR_FRIEND_GET_LAST_ONLINE_OK)
|
if (loerr != TOX_ERR_FRIEND_GET_LAST_ONLINE_OK) {
|
||||||
t = 0;
|
t = 0;
|
||||||
|
}
|
||||||
|
|
||||||
update_friend_last_online(i, t);
|
update_friend_last_online(i, t);
|
||||||
|
|
||||||
@ -460,17 +478,23 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort)
|
|||||||
snprintf(Friends.list[i].name, sizeof(Friends.list[i].name), "%s", tempname);
|
snprintf(Friends.list[i].name, sizeof(Friends.list[i].name), "%s", tempname);
|
||||||
Friends.list[i].namelength = strlen(Friends.list[i].name);
|
Friends.list[i].namelength = strlen(Friends.list[i].name);
|
||||||
|
|
||||||
if (i == Friends.max_idx)
|
if (i == Friends.max_idx) {
|
||||||
++Friends.max_idx;
|
++Friends.max_idx;
|
||||||
|
}
|
||||||
|
|
||||||
if (sort)
|
if (sort) {
|
||||||
sort_friendlist_index();
|
sort_friendlist_index();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
|
init_friend_AV(i);
|
||||||
|
#endif
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* puts blocked friend back in friendlist. fnum is new friend number, bnum is blocked number */
|
/* Puts blocked friend back in friendlist. fnum is new friend number, bnum is blocked number. */
|
||||||
static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum)
|
static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum)
|
||||||
{
|
{
|
||||||
realloc_friends(Friends.max_idx + 1);
|
realloc_friends(Friends.max_idx + 1);
|
||||||
@ -479,8 +503,9 @@ static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i <= Friends.max_idx; ++i) {
|
for (i = 0; i <= Friends.max_idx; ++i) {
|
||||||
if (Friends.list[i].active)
|
if (Friends.list[i].active) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
++Friends.num_friends;
|
++Friends.num_friends;
|
||||||
|
|
||||||
@ -494,12 +519,16 @@ static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum)
|
|||||||
memcpy(Friends.list[i].name, Blocked.list[bnum].name, Friends.list[i].namelength + 1);
|
memcpy(Friends.list[i].name, Blocked.list[bnum].name, Friends.list[i].namelength + 1);
|
||||||
memcpy(Friends.list[i].pub_key, Blocked.list[bnum].pub_key, TOX_PUBLIC_KEY_SIZE);
|
memcpy(Friends.list[i].pub_key, Blocked.list[bnum].pub_key, TOX_PUBLIC_KEY_SIZE);
|
||||||
|
|
||||||
if (i == Friends.max_idx)
|
if (i == Friends.max_idx) {
|
||||||
++Friends.max_idx;
|
++Friends.max_idx;
|
||||||
|
}
|
||||||
|
|
||||||
sort_blocklist_index();
|
sort_blocklist_index();
|
||||||
sort_friendlist_index();
|
sort_friendlist_index();
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
|
init_friend_AV(i);
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -507,11 +536,13 @@ static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum)
|
|||||||
static void friendlist_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum,
|
static void friendlist_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum,
|
||||||
uint64_t file_size, const char *filename, size_t name_length)
|
uint64_t file_size, const char *filename, size_t name_length)
|
||||||
{
|
{
|
||||||
if (num >= Friends.max_idx)
|
if (num >= Friends.max_idx) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (Friends.list[num].chatwin != -1)
|
if (Friends.list[num].chatwin != -1) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
||||||
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
|
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
|
||||||
@ -532,11 +563,13 @@ static void friendlist_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_
|
|||||||
static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, uint8_t type, const char *group_pub_key,
|
static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, uint8_t type, const char *group_pub_key,
|
||||||
uint16_t length)
|
uint16_t length)
|
||||||
{
|
{
|
||||||
if (num >= Friends.max_idx)
|
if (num >= Friends.max_idx) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (Friends.list[num].chatwin != -1)
|
if (Friends.list[num].chatwin != -1) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
||||||
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
|
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
|
||||||
@ -555,12 +588,14 @@ static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, uint8
|
|||||||
/* move friendlist/blocklist cursor up and down */
|
/* move friendlist/blocklist cursor up and down */
|
||||||
static void select_friend(ToxWindow *self, wint_t key, int *selected, int num)
|
static void select_friend(ToxWindow *self, wint_t key, int *selected, int num)
|
||||||
{
|
{
|
||||||
if (num <= 0)
|
if (num <= 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (key == KEY_UP) {
|
if (key == KEY_UP) {
|
||||||
if (--(*selected) < 0)
|
if (--(*selected) < 0) {
|
||||||
*selected = num - 1;
|
*selected = num - 1;
|
||||||
|
}
|
||||||
} else if (key == KEY_DOWN) {
|
} else if (key == KEY_DOWN) {
|
||||||
*selected = (*selected + 1) % num;
|
*selected = (*selected + 1) % num;
|
||||||
}
|
}
|
||||||
@ -568,7 +603,7 @@ static void select_friend(ToxWindow *self, wint_t key, int *selected, int num)
|
|||||||
|
|
||||||
static void delete_friend(Tox *m, uint32_t f_num)
|
static void delete_friend(Tox *m, uint32_t f_num)
|
||||||
{
|
{
|
||||||
TOX_ERR_FRIEND_DELETE err;
|
Tox_Err_Friend_Delete err;
|
||||||
|
|
||||||
if (tox_friend_delete(m, f_num, &err) != true) {
|
if (tox_friend_delete(m, f_num, &err) != true) {
|
||||||
fprintf(stderr, "tox_friend_delete failed with error %d\n", err);
|
fprintf(stderr, "tox_friend_delete failed with error %d\n", err);
|
||||||
@ -577,8 +612,9 @@ static void delete_friend(Tox *m, uint32_t f_num)
|
|||||||
|
|
||||||
--Friends.num_friends;
|
--Friends.num_friends;
|
||||||
|
|
||||||
if (Friends.list[f_num].connection_status != TOX_CONNECTION_NONE)
|
if (Friends.list[f_num].connection_status != TOX_CONNECTION_NONE) {
|
||||||
--Friends.num_online;
|
--Friends.num_online;
|
||||||
|
}
|
||||||
|
|
||||||
/* close friend's chatwindow if it's currently open */
|
/* close friend's chatwindow if it's currently open */
|
||||||
if (Friends.list[f_num].chatwin >= 0) {
|
if (Friends.list[f_num].chatwin >= 0) {
|
||||||
@ -586,28 +622,35 @@ static void delete_friend(Tox *m, uint32_t f_num)
|
|||||||
|
|
||||||
if (toxwin != NULL) {
|
if (toxwin != NULL) {
|
||||||
kill_chat_window(toxwin, m);
|
kill_chat_window(toxwin, m);
|
||||||
set_active_window(1); /* keep friendlist focused */
|
set_active_window_index(1); /* keep friendlist focused */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Friends.list[f_num].group_invite.key != NULL)
|
if (Friends.list[f_num].group_invite.key != NULL) {
|
||||||
free(Friends.list[f_num].group_invite.key);
|
free(Friends.list[f_num].group_invite.key);
|
||||||
|
}
|
||||||
|
|
||||||
memset(&Friends.list[f_num], 0, sizeof(ToxicFriend));
|
memset(&Friends.list[f_num], 0, sizeof(ToxicFriend));
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = Friends.max_idx; i > 0; --i) {
|
for (i = Friends.max_idx; i > 0; --i) {
|
||||||
if (Friends.list[i - 1].active)
|
if (Friends.list[i - 1].active) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Friends.max_idx = i;
|
Friends.max_idx = i;
|
||||||
realloc_friends(i);
|
realloc_friends(i);
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
|
del_friend_AV(i);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* make sure num_selected stays within Friends.num_friends range */
|
/* make sure num_selected stays within Friends.num_friends range */
|
||||||
if (Friends.num_friends && Friends.num_selected == Friends.num_friends)
|
if (Friends.num_friends && Friends.num_selected == Friends.num_friends) {
|
||||||
--Friends.num_selected;
|
--Friends.num_selected;
|
||||||
|
}
|
||||||
|
|
||||||
store_data(m, DATA_FILE);
|
store_data(m, DATA_FILE);
|
||||||
}
|
}
|
||||||
@ -643,8 +686,9 @@ static void del_friend_deactivate(ToxWindow *self, Tox *m, wint_t key)
|
|||||||
|
|
||||||
static void draw_del_popup(void)
|
static void draw_del_popup(void)
|
||||||
{
|
{
|
||||||
if (!PendingDelete.active)
|
if (!PendingDelete.active) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
wattron(PendingDelete.popup, A_BOLD);
|
wattron(PendingDelete.popup, A_BOLD);
|
||||||
box(PendingDelete.popup, ACS_VLINE, ACS_HLINE);
|
box(PendingDelete.popup, ACS_VLINE, ACS_HLINE);
|
||||||
@ -656,10 +700,11 @@ static void draw_del_popup(void)
|
|||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
|
|
||||||
if (blocklist_view == 0)
|
if (blocklist_view == 0) {
|
||||||
wprintw(PendingDelete.popup, "%s", Friends.list[PendingDelete.num].name);
|
wprintw(PendingDelete.popup, "%s", Friends.list[PendingDelete.num].name);
|
||||||
else
|
} else {
|
||||||
wprintw(PendingDelete.popup, "%s", Blocked.list[PendingDelete.num].name);
|
wprintw(PendingDelete.popup, "%s", Blocked.list[PendingDelete.num].name);
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
@ -677,24 +722,27 @@ static void delete_blocked_friend(uint32_t bnum)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = Blocked.max_idx; i > 0; --i) {
|
for (i = Blocked.max_idx; i > 0; --i) {
|
||||||
if (Blocked.list[i - 1].active)
|
if (Blocked.list[i - 1].active) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
--Blocked.num_blocked;
|
--Blocked.num_blocked;
|
||||||
Blocked.max_idx = i;
|
Blocked.max_idx = i;
|
||||||
realloc_blocklist(i);
|
realloc_blocklist(i);
|
||||||
save_blocklist(BLOCK_FILE);
|
save_blocklist(BLOCK_FILE);
|
||||||
|
|
||||||
if (Blocked.num_blocked && Blocked.num_selected == Blocked.num_blocked)
|
if (Blocked.num_blocked && Blocked.num_selected == Blocked.num_blocked) {
|
||||||
--Blocked.num_selected;
|
--Blocked.num_selected;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* deletes contact from friendlist and puts in blocklist */
|
/* deletes contact from friendlist and puts in blocklist */
|
||||||
void block_friend(Tox *m, uint32_t fnum)
|
void block_friend(Tox *m, uint32_t fnum)
|
||||||
{
|
{
|
||||||
if (Friends.num_friends <= 0)
|
if (Friends.num_friends <= 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
realloc_blocklist(Blocked.max_idx + 1);
|
realloc_blocklist(Blocked.max_idx + 1);
|
||||||
memset(&Blocked.list[Blocked.max_idx], 0, sizeof(BlockedFriend));
|
memset(&Blocked.list[Blocked.max_idx], 0, sizeof(BlockedFriend));
|
||||||
@ -702,8 +750,9 @@ void block_friend(Tox *m, uint32_t fnum)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i <= Blocked.max_idx; ++i) {
|
for (i = 0; i <= Blocked.max_idx; ++i) {
|
||||||
if (Blocked.list[i].active)
|
if (Blocked.list[i].active) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Blocked.list[i].active = true;
|
Blocked.list[i].active = true;
|
||||||
Blocked.list[i].num = i;
|
Blocked.list[i].num = i;
|
||||||
@ -714,8 +763,9 @@ void block_friend(Tox *m, uint32_t fnum)
|
|||||||
|
|
||||||
++Blocked.num_blocked;
|
++Blocked.num_blocked;
|
||||||
|
|
||||||
if (i == Blocked.max_idx)
|
if (i == Blocked.max_idx) {
|
||||||
++Blocked.max_idx;
|
++Blocked.max_idx;
|
||||||
|
}
|
||||||
|
|
||||||
delete_friend(m, fnum);
|
delete_friend(m, fnum);
|
||||||
save_blocklist(BLOCK_FILE);
|
save_blocklist(BLOCK_FILE);
|
||||||
@ -729,10 +779,11 @@ void block_friend(Tox *m, uint32_t fnum)
|
|||||||
/* removes friend from blocklist, puts back in friendlist */
|
/* removes friend from blocklist, puts back in friendlist */
|
||||||
static void unblock_friend(Tox *m, uint32_t bnum)
|
static void unblock_friend(Tox *m, uint32_t bnum)
|
||||||
{
|
{
|
||||||
if (Blocked.num_blocked <= 0)
|
if (Blocked.num_blocked <= 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TOX_ERR_FRIEND_ADD err;
|
Tox_Err_Friend_Add err;
|
||||||
uint32_t friendnum = tox_friend_add_norequest(m, (uint8_t *) Blocked.list[bnum].pub_key, &err);
|
uint32_t friendnum = tox_friend_add_norequest(m, (uint8_t *) Blocked.list[bnum].pub_key, &err);
|
||||||
|
|
||||||
if (err != TOX_ERR_FRIEND_ADD_OK) {
|
if (err != TOX_ERR_FRIEND_ADD_OK) {
|
||||||
@ -759,41 +810,47 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!blocklist_view && !Friends.num_friends && (key != KEY_RIGHT && key != KEY_LEFT))
|
if (!blocklist_view && !Friends.num_friends && (key != KEY_RIGHT && key != KEY_LEFT)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (blocklist_view && !Blocked.num_blocked && (key != KEY_RIGHT && key != KEY_LEFT))
|
if (blocklist_view && !Blocked.num_blocked && (key != KEY_RIGHT && key != KEY_LEFT)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int f = 0;
|
int f = 0;
|
||||||
|
|
||||||
if (blocklist_view == 1 && Blocked.num_blocked)
|
if (blocklist_view == 1 && Blocked.num_blocked) {
|
||||||
f = Blocked.index[Blocked.num_selected];
|
f = Blocked.index[Blocked.num_selected];
|
||||||
else if (Friends.num_friends)
|
} else if (Friends.num_friends) {
|
||||||
f = Friends.index[Friends.num_selected];
|
f = Friends.index[Friends.num_selected];
|
||||||
|
}
|
||||||
|
|
||||||
/* lock screen and force decision on deletion popup */
|
/* lock screen and force decision on deletion popup */
|
||||||
if (PendingDelete.active) {
|
if (PendingDelete.active) {
|
||||||
if (key == 'y' || key == 'n')
|
if (key == 'y' || key == 'n') {
|
||||||
del_friend_deactivate(self, m, key);
|
del_friend_deactivate(self, m, key);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key == ltr)
|
if (key == ltr) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case '\r':
|
case '\r':
|
||||||
if (blocklist_view)
|
if (blocklist_view) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Jump to chat window if already open */
|
/* Jump to chat window if already open */
|
||||||
if (Friends.list[f].chatwin != -1) {
|
if (Friends.list[f].chatwin != -1) {
|
||||||
set_active_window(Friends.list[f].chatwin);
|
set_active_window_index(Friends.list[f].chatwin);
|
||||||
} else if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
} else if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
||||||
Friends.list[f].chatwin = add_window(m, new_chat(m, Friends.list[f].num));
|
Friends.list[f].chatwin = add_window(m, new_chat(m, Friends.list[f].num));
|
||||||
set_active_window(Friends.list[f].chatwin);
|
set_active_window_index(Friends.list[f].chatwin);
|
||||||
} else {
|
} else {
|
||||||
const char *msg = "* Warning: Too many windows are open.";
|
const char *msg = "* Warning: Too many windows are open.";
|
||||||
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, msg);
|
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, msg);
|
||||||
@ -807,10 +864,11 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'b':
|
case 'b':
|
||||||
if (!blocklist_view)
|
if (!blocklist_view) {
|
||||||
block_friend(m, f);
|
block_friend(m, f);
|
||||||
else
|
} else {
|
||||||
unblock_friend(m, f);
|
unblock_friend(m, f);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -820,10 +878,11 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (blocklist_view == 0)
|
if (blocklist_view == 0) {
|
||||||
select_friend(self, key, &Friends.num_selected, Friends.num_friends);
|
select_friend(self, key, &Friends.num_selected, Friends.num_friends);
|
||||||
else
|
} else {
|
||||||
select_friend(self, key, &Blocked.num_selected, Blocked.num_blocked);
|
select_friend(self, key, &Blocked.num_selected, Blocked.num_blocked);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -838,8 +897,9 @@ static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2)
|
|||||||
wattroff(self->window, A_BOLD);
|
wattroff(self->window, A_BOLD);
|
||||||
wprintw(self->window, "%d\n\n", Blocked.num_blocked);
|
wprintw(self->window, "%d\n\n", Blocked.num_blocked);
|
||||||
|
|
||||||
if ((y2 - FLIST_OFST) <= 0)
|
if ((y2 - FLIST_OFST) <= 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t selected_num = 0;
|
uint32_t selected_num = 0;
|
||||||
|
|
||||||
@ -868,16 +928,18 @@ static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2)
|
|||||||
wprintw(self->window, "x");
|
wprintw(self->window, "x");
|
||||||
wattroff(self->window, COLOR_PAIR(RED));
|
wattroff(self->window, COLOR_PAIR(RED));
|
||||||
|
|
||||||
if (f_selected)
|
if (f_selected) {
|
||||||
wattron(self->window, COLOR_PAIR(BLUE));
|
wattron(self->window, COLOR_PAIR(BLUE));
|
||||||
|
}
|
||||||
|
|
||||||
wattron(self->window, A_BOLD);
|
wattron(self->window, A_BOLD);
|
||||||
wprintw(self->window, " %s\n", Blocked.list[f].name);
|
wprintw(self->window, " %s\n", Blocked.list[f].name);
|
||||||
wattroff(self->window, A_BOLD);
|
wattroff(self->window, A_BOLD);
|
||||||
|
|
||||||
if (f_selected)
|
if (f_selected) {
|
||||||
wattroff(self->window, COLOR_PAIR(BLUE));
|
wattroff(self->window, COLOR_PAIR(BLUE));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
wprintw(self->window, "\n");
|
wprintw(self->window, "\n");
|
||||||
self->x = x2;
|
self->x = x2;
|
||||||
@ -891,16 +953,18 @@ static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2)
|
|||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < TOX_PUBLIC_KEY_SIZE; ++i)
|
for (i = 0; i < TOX_PUBLIC_KEY_SIZE; ++i) {
|
||||||
wprintw(self->window, "%02X", Blocked.list[selected_num].pub_key[i] & 0xff);
|
wprintw(self->window, "%02X", Blocked.list[selected_num].pub_key[i] & 0xff);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
wnoutrefresh(self->window);
|
wnoutrefresh(self->window);
|
||||||
draw_del_popup();
|
draw_del_popup();
|
||||||
|
|
||||||
if (self->help->active)
|
if (self->help->active) {
|
||||||
help_onDraw(self);
|
help_onDraw(self);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
||||||
{
|
{
|
||||||
@ -933,8 +997,9 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
wprintw(self->window, "%d/%d \n\n", Friends.num_online, Friends.num_friends);
|
wprintw(self->window, "%d/%d \n\n", Friends.num_online, Friends.num_friends);
|
||||||
|
|
||||||
if ((y2 - FLIST_OFST) <= 0)
|
if ((y2 - FLIST_OFST) <= 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t selected_num = 0;
|
uint32_t selected_num = 0;
|
||||||
|
|
||||||
@ -973,8 +1038,8 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
TOX_CONNECTION connection_status = Friends.list[f].connection_status;
|
Tox_Connection connection_status = Friends.list[f].connection_status;
|
||||||
TOX_USER_STATUS status = Friends.list[f].status;
|
Tox_User_Status status = Friends.list[f].status;
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
if (connection_status != TOX_CONNECTION_NONE) {
|
if (connection_status != TOX_CONNECTION_NONE) {
|
||||||
@ -998,8 +1063,9 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
wprintw(self->window, "%s ", ONLINE_CHAR);
|
wprintw(self->window, "%s ", ONLINE_CHAR);
|
||||||
wattroff(self->window, COLOR_PAIR(colour) | A_BOLD);
|
wattroff(self->window, COLOR_PAIR(colour) | A_BOLD);
|
||||||
|
|
||||||
if (f_selected)
|
if (f_selected) {
|
||||||
wattron(self->window, COLOR_PAIR(BLUE));
|
wattron(self->window, COLOR_PAIR(BLUE));
|
||||||
|
}
|
||||||
|
|
||||||
wattron(self->window, A_BOLD);
|
wattron(self->window, A_BOLD);
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
@ -1007,8 +1073,9 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
wattroff(self->window, A_BOLD);
|
wattroff(self->window, A_BOLD);
|
||||||
|
|
||||||
if (f_selected)
|
if (f_selected) {
|
||||||
wattroff(self->window, COLOR_PAIR(BLUE));
|
wattroff(self->window, COLOR_PAIR(BLUE));
|
||||||
|
}
|
||||||
|
|
||||||
/* Reset Friends.list[f].statusmsg on window resize */
|
/* Reset Friends.list[f].statusmsg on window resize */
|
||||||
if (fix_statuses) {
|
if (fix_statuses) {
|
||||||
@ -1041,8 +1108,9 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
Friends.list[f].statusmsg_len = maxlen;
|
Friends.list[f].statusmsg_len = maxlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Friends.list[f].statusmsg_len > 0)
|
if (Friends.list[f].statusmsg_len > 0) {
|
||||||
wprintw(self->window, " %s", Friends.list[f].statusmsg);
|
wprintw(self->window, " %s", Friends.list[f].statusmsg);
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
@ -1050,8 +1118,9 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
} else {
|
} else {
|
||||||
wprintw(self->window, "%s ", OFFLINE_CHAR);
|
wprintw(self->window, "%s ", OFFLINE_CHAR);
|
||||||
|
|
||||||
if (f_selected)
|
if (f_selected) {
|
||||||
wattron(self->window, COLOR_PAIR(BLUE));
|
wattron(self->window, COLOR_PAIR(BLUE));
|
||||||
|
}
|
||||||
|
|
||||||
wattron(self->window, A_BOLD);
|
wattron(self->window, A_BOLD);
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
@ -1059,8 +1128,9 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
wattroff(self->window, A_BOLD);
|
wattroff(self->window, A_BOLD);
|
||||||
|
|
||||||
if (f_selected)
|
if (f_selected) {
|
||||||
wattroff(self->window, COLOR_PAIR(BLUE));
|
wattroff(self->window, COLOR_PAIR(BLUE));
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
time_t last_seen = Friends.list[f].last_online.last_on;
|
time_t last_seen = Friends.list[f].last_online.last_on;
|
||||||
@ -1108,16 +1178,18 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < TOX_PUBLIC_KEY_SIZE; ++i)
|
for (i = 0; i < TOX_PUBLIC_KEY_SIZE; ++i) {
|
||||||
wprintw(self->window, "%02X", Friends.list[selected_num].pub_key[i] & 0xff);
|
wprintw(self->window, "%02X", Friends.list[selected_num].pub_key[i] & 0xff);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
wnoutrefresh(self->window);
|
wnoutrefresh(self->window);
|
||||||
draw_del_popup();
|
draw_del_popup();
|
||||||
|
|
||||||
if (self->help->active)
|
if (self->help->active) {
|
||||||
help_onDraw(self);
|
help_onDraw(self);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void disable_chatwin(uint32_t f_num)
|
void disable_chatwin(uint32_t f_num)
|
||||||
{
|
{
|
||||||
@ -1129,8 +1201,9 @@ static void friendlist_onAV(ToxWindow *self, ToxAV *av, uint32_t friend_number,
|
|||||||
{
|
{
|
||||||
assert(0);
|
assert(0);
|
||||||
|
|
||||||
if ( friend_number >= Friends.max_idx)
|
if (friend_number >= Friends.max_idx) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
assert(0);
|
assert(0);
|
||||||
Tox *m = toxav_get_tox(av);
|
Tox *m = toxav_get_tox(av);
|
||||||
@ -1139,7 +1212,7 @@ static void friendlist_onAV(ToxWindow *self, ToxAV *av, uint32_t friend_number,
|
|||||||
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
||||||
if (state != TOXAV_FRIEND_CALL_STATE_FINISHED) {
|
if (state != TOXAV_FRIEND_CALL_STATE_FINISHED) {
|
||||||
Friends.list[friend_number].chatwin = add_window(m, new_chat(m, Friends.list[friend_number].num));
|
Friends.list[friend_number].chatwin = add_window(m, new_chat(m, Friends.list[friend_number].num));
|
||||||
set_active_window(Friends.list[friend_number].chatwin);
|
set_active_window_index(Friends.list[friend_number].chatwin);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
char nick[TOX_MAX_NAME_LENGTH];
|
char nick[TOX_MAX_NAME_LENGTH];
|
||||||
@ -1155,49 +1228,64 @@ static void friendlist_onAV(ToxWindow *self, ToxAV *av, uint32_t friend_number,
|
|||||||
}
|
}
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
ToxWindow new_friendlist(void)
|
/* Returns a friend's status */
|
||||||
|
Tox_User_Status get_friend_status(uint32_t friendnumber)
|
||||||
{
|
{
|
||||||
ToxWindow ret;
|
return Friends.list[friendnumber].status;
|
||||||
memset(&ret, 0, sizeof(ret));
|
}
|
||||||
|
|
||||||
ret.active = true;
|
/* Returns a friend's connection status */
|
||||||
ret.is_friendlist = true;
|
Tox_Connection get_friend_connection_status(uint32_t friendnumber)
|
||||||
|
{
|
||||||
|
return Friends.list[friendnumber].connection_status;
|
||||||
|
}
|
||||||
|
|
||||||
ret.onKey = &friendlist_onKey;
|
ToxWindow *new_friendlist(void)
|
||||||
ret.onDraw = &friendlist_onDraw;
|
{
|
||||||
ret.onFriendAdded = &friendlist_onFriendAdded;
|
ToxWindow *ret = calloc(1, sizeof(ToxWindow));
|
||||||
ret.onMessage = &friendlist_onMessage;
|
|
||||||
ret.onConnectionChange = &friendlist_onConnectionChange;
|
if (ret == NULL) {
|
||||||
ret.onNickChange = &friendlist_onNickChange;
|
exit_toxic_err("failed in new_friendlist", FATALERR_MEMORY);
|
||||||
ret.onStatusChange = &friendlist_onStatusChange;
|
}
|
||||||
ret.onStatusMessageChange = &friendlist_onStatusMessageChange;
|
|
||||||
ret.onFileRecv = &friendlist_onFileRecv;
|
ret->is_friendlist = true;
|
||||||
ret.onGroupInvite = &friendlist_onGroupInvite;
|
|
||||||
|
ret->onKey = &friendlist_onKey;
|
||||||
|
ret->onDraw = &friendlist_onDraw;
|
||||||
|
ret->onFriendAdded = &friendlist_onFriendAdded;
|
||||||
|
ret->onMessage = &friendlist_onMessage;
|
||||||
|
ret->onConnectionChange = &friendlist_onConnectionChange;
|
||||||
|
ret->onNickChange = &friendlist_onNickChange;
|
||||||
|
ret->onStatusChange = &friendlist_onStatusChange;
|
||||||
|
ret->onStatusMessageChange = &friendlist_onStatusMessageChange;
|
||||||
|
ret->onFileRecv = &friendlist_onFileRecv;
|
||||||
|
ret->onGroupInvite = &friendlist_onGroupInvite;
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
ret.onInvite = &friendlist_onAV;
|
ret->onInvite = &friendlist_onAV;
|
||||||
ret.onRinging = &friendlist_onAV;
|
ret->onRinging = &friendlist_onAV;
|
||||||
ret.onStarting = &friendlist_onAV;
|
ret->onStarting = &friendlist_onAV;
|
||||||
ret.onEnding = &friendlist_onAV;
|
ret->onEnding = &friendlist_onAV;
|
||||||
ret.onError = &friendlist_onAV;
|
ret->onError = &friendlist_onAV;
|
||||||
ret.onStart = &friendlist_onAV;
|
ret->onStart = &friendlist_onAV;
|
||||||
ret.onCancel = &friendlist_onAV;
|
ret->onCancel = &friendlist_onAV;
|
||||||
ret.onReject = &friendlist_onAV;
|
ret->onReject = &friendlist_onAV;
|
||||||
ret.onEnd = &friendlist_onAV;
|
ret->onEnd = &friendlist_onAV;
|
||||||
|
|
||||||
ret.is_call = false;
|
ret->is_call = false;
|
||||||
ret.device_selection[0] = ret.device_selection[1] = -1;
|
ret->device_selection[0] = ret->device_selection[1] = -1;
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
ret.num = -1;
|
ret->num = -1;
|
||||||
ret.active_box = -1;
|
ret->active_box = -1;
|
||||||
|
|
||||||
Help *help = calloc(1, sizeof(Help));
|
Help *help = calloc(1, sizeof(Help));
|
||||||
|
|
||||||
if (help == NULL)
|
if (help == NULL) {
|
||||||
exit_toxic_err("failed in new_friendlist", FATALERR_MEMORY);
|
exit_toxic_err("failed in new_friendlist", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
ret.help = help;
|
ret->help = help;
|
||||||
strcpy(ret.name, "contacts");
|
strcpy(ret->name, "contacts");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -51,10 +51,10 @@ typedef struct {
|
|||||||
uint32_t num;
|
uint32_t num;
|
||||||
int chatwin;
|
int chatwin;
|
||||||
bool active;
|
bool active;
|
||||||
TOX_CONNECTION connection_status;
|
Tox_Connection connection_status;
|
||||||
bool is_typing;
|
bool is_typing;
|
||||||
bool logging_on; /* saves preference for friend irrespective of global settings */
|
bool logging_on; /* saves preference for friend irrespective of global settings */
|
||||||
uint8_t status;
|
Tox_User_Status status;
|
||||||
|
|
||||||
struct LastOnline last_online;
|
struct LastOnline last_online;
|
||||||
struct GroupChatInvite group_invite;
|
struct GroupChatInvite group_invite;
|
||||||
@ -81,12 +81,14 @@ typedef struct {
|
|||||||
ToxicFriend *list;
|
ToxicFriend *list;
|
||||||
} FriendsList;
|
} FriendsList;
|
||||||
|
|
||||||
ToxWindow new_friendlist(void);
|
ToxWindow *new_friendlist(void);
|
||||||
void disable_chatwin(uint32_t f_num);
|
void disable_chatwin(uint32_t f_num);
|
||||||
int get_friendnum(uint8_t *name);
|
int get_friendnum(uint8_t *name);
|
||||||
int load_blocklist(char *data);
|
int load_blocklist(char *data);
|
||||||
void kill_friendlist(void);
|
void kill_friendlist(ToxWindow *self);
|
||||||
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort);
|
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort);
|
||||||
|
Tox_User_Status get_friend_status(uint32_t friendnumber);
|
||||||
|
Tox_Connection get_friend_connection_status(uint32_t friendnumber);
|
||||||
|
|
||||||
/* sorts friendlist_index first by connection status then alphabetically */
|
/* sorts friendlist_index first by connection status then alphabetically */
|
||||||
void sort_friendlist_index(void);
|
void sort_friendlist_index(void);
|
||||||
|
@ -41,7 +41,6 @@
|
|||||||
extern char *DATA_FILE;
|
extern char *DATA_FILE;
|
||||||
extern ToxWindow *prompt;
|
extern ToxWindow *prompt;
|
||||||
extern FriendsList Friends;
|
extern FriendsList Friends;
|
||||||
extern FriendRequests FrndRequests;
|
|
||||||
|
|
||||||
/* command functions */
|
/* command functions */
|
||||||
void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
@ -63,7 +62,7 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TOX_ERR_FRIEND_ADD err;
|
Tox_Err_Friend_Add err;
|
||||||
uint32_t friendnum = tox_friend_add_norequest(m, FrndRequests.request[req].key, &err);
|
uint32_t friendnum = tox_friend_add_norequest(m, FrndRequests.request[req].key, &err);
|
||||||
|
|
||||||
if (err != TOX_ERR_FRIEND_ADD_OK) {
|
if (err != TOX_ERR_FRIEND_ADD_OK) {
|
||||||
@ -71,7 +70,7 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
|||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Friend request accepted.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Friend request accepted.");
|
||||||
on_friendadded(m, friendnum, true);
|
on_friend_added(m, friendnum, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&FrndRequests.request[req], 0, sizeof(struct friend_request));
|
memset(&FrndRequests.request[req], 0, sizeof(struct friend_request));
|
||||||
@ -79,9 +78,10 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = FrndRequests.max_idx; i > 0; --i) {
|
for (i = FrndRequests.max_idx; i > 0; --i) {
|
||||||
if (FrndRequests.request[i - 1].active)
|
if (FrndRequests.request[i - 1].active) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FrndRequests.max_idx = i;
|
FrndRequests.max_idx = i;
|
||||||
--FrndRequests.num_requests;
|
--FrndRequests.num_requests;
|
||||||
@ -92,8 +92,8 @@ void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg
|
|||||||
{
|
{
|
||||||
const char *errmsg;
|
const char *errmsg;
|
||||||
|
|
||||||
TOX_ERR_FRIEND_ADD err;
|
Tox_Err_Friend_Add err;
|
||||||
uint32_t f_num = tox_friend_add(m, (uint8_t *) id_bin, (uint8_t *) msg, strlen(msg), &err);
|
uint32_t f_num = tox_friend_add(m, (const uint8_t *) id_bin, (const uint8_t *) msg, strlen(msg), &err);
|
||||||
|
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case TOX_ERR_FRIEND_ADD_TOO_LONG:
|
case TOX_ERR_FRIEND_ADD_TOO_LONG:
|
||||||
@ -126,7 +126,7 @@ void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg
|
|||||||
|
|
||||||
case TOX_ERR_FRIEND_ADD_OK:
|
case TOX_ERR_FRIEND_ADD_OK:
|
||||||
errmsg = "Friend request sent.";
|
errmsg = "Friend request sent.";
|
||||||
on_friendadded(m, f_num, true);
|
on_friend_added(m, f_num, true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_ERR_FRIEND_ADD_NULL:
|
case TOX_ERR_FRIEND_ADD_NULL:
|
||||||
@ -201,21 +201,15 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
|||||||
|
|
||||||
void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
if (argc < 2 || strlen(argv[1]) < 3) {
|
if (argc != 1 || strlen(argv[1]) < 3) {
|
||||||
avatar_unset(m);
|
avatar_unset(m);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Avatar is not set.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Avatar has been unset.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argv[1][0] != '\"') {
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Path must be enclosed in quotes.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remove opening and closing quotes */
|
|
||||||
char path[MAX_STR_SIZE];
|
char path[MAX_STR_SIZE];
|
||||||
snprintf(path, sizeof(path), "%s", &argv[1][1]);
|
snprintf(path, sizeof(path), "%s", argv[1]);
|
||||||
int len = strlen(path) - 1;
|
int len = strlen(path);
|
||||||
|
|
||||||
if (len <= 0) {
|
if (len <= 0) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid path.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid path.");
|
||||||
@ -267,7 +261,7 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TOX_ERR_BOOTSTRAP err;
|
Tox_Err_Bootstrap err;
|
||||||
tox_bootstrap(m, ip, port, (uint8_t *) key_binary, &err);
|
tox_bootstrap(m, ip, port, (uint8_t *) key_binary, &err);
|
||||||
tox_add_tcp_relay(m, ip, port, (uint8_t *) key_binary, &err);
|
tox_add_tcp_relay(m, ip, port, (uint8_t *) key_binary, &err);
|
||||||
|
|
||||||
@ -313,9 +307,10 @@ void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = FrndRequests.max_idx; i > 0; --i) {
|
for (i = FrndRequests.max_idx; i > 0; --i) {
|
||||||
if (FrndRequests.request[i - 1].active)
|
if (FrndRequests.request[i - 1].active) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FrndRequests.max_idx = i;
|
FrndRequests.max_idx = i;
|
||||||
--FrndRequests.num_requests;
|
--FrndRequests.num_requests;
|
||||||
@ -335,11 +330,11 @@ void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
|
|||||||
|
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
|
|
||||||
if (!strcasecmp(argv[1], "audio"))
|
if (!strcasecmp(argv[1], "audio")) {
|
||||||
type = TOX_CONFERENCE_TYPE_AV;
|
type = TOX_CONFERENCE_TYPE_AV;
|
||||||
else if (!strcasecmp(argv[1], "text"))
|
} else if (!strcasecmp(argv[1], "text")) {
|
||||||
type = TOX_CONFERENCE_TYPE_TEXT;
|
type = TOX_CONFERENCE_TYPE_TEXT;
|
||||||
else {
|
} else {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Valid group types are: text | audio");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Valid group types are: text | audio");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -349,7 +344,7 @@ void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TOX_ERR_CONFERENCE_NEW err;
|
Tox_Err_Conference_New err;
|
||||||
|
|
||||||
uint32_t groupnum = tox_conference_new(m, &err);
|
uint32_t groupnum = tox_conference_new(m, &err);
|
||||||
|
|
||||||
@ -373,10 +368,11 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
|||||||
struct chatlog *log = self->chatwin->log;
|
struct chatlog *log = self->chatwin->log;
|
||||||
|
|
||||||
if (argc == 0) {
|
if (argc == 0) {
|
||||||
if (log->log_on)
|
if (log->log_on) {
|
||||||
msg = "Logging for this window is ON; type \"/log off\" to disable. (Logs are not encrypted)";
|
msg = "Logging for this window is ON; type \"/log off\" to disable. (Logs are not encrypted)";
|
||||||
else
|
} else {
|
||||||
msg = "Logging for this window is OFF; type \"/log on\" to enable.";
|
msg = "Logging for this window is OFF; type \"/log on\" to enable.";
|
||||||
|
}
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
|
||||||
return;
|
return;
|
||||||
@ -403,8 +399,9 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
|||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
|
||||||
return;
|
return;
|
||||||
} else if (!strcmp(swch, "0") || !strcmp(swch, "off")) {
|
} else if (!strcmp(swch, "0") || !strcmp(swch, "off")) {
|
||||||
if (self->is_chat)
|
if (self->is_chat) {
|
||||||
Friends.list[self->num].logging_on = false;
|
Friends.list[self->num].logging_on = false;
|
||||||
|
}
|
||||||
|
|
||||||
log_disable(log);
|
log_disable(log);
|
||||||
|
|
||||||
@ -431,6 +428,7 @@ void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
|||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", id_string);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", id_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef QRCODE
|
||||||
void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
char id_string[TOX_ADDRESS_SIZE * 2 + 1];
|
char id_string[TOX_ADDRESS_SIZE * 2 + 1];
|
||||||
@ -488,6 +486,7 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
|||||||
|
|
||||||
#endif /* QRPNG */
|
#endif /* QRPNG */
|
||||||
}
|
}
|
||||||
|
#endif /* QRCODE */
|
||||||
|
|
||||||
void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
@ -497,16 +496,8 @@ void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
|||||||
}
|
}
|
||||||
|
|
||||||
char nick[MAX_STR_SIZE];
|
char nick[MAX_STR_SIZE];
|
||||||
size_t len = 0;
|
|
||||||
|
|
||||||
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]);
|
snprintf(nick, sizeof(nick), "%s", argv[1]);
|
||||||
len = strlen(nick);
|
size_t len = strlen(nick);
|
||||||
}
|
|
||||||
|
|
||||||
if (!valid_nick(nick)) {
|
if (!valid_nick(nick)) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid name.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid name.");
|
||||||
@ -529,19 +520,7 @@ void cmd_note(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argv[1][0] != '\"') {
|
prompt_update_statusmessage(prompt, m, argv[1]);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Note must be enclosed in quotes.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remove opening and closing quotes and replace linebreaks with spaces */
|
|
||||||
char msg[MAX_STR_SIZE];
|
|
||||||
snprintf(msg, sizeof(msg), "%s", &argv[1][1]);
|
|
||||||
int len = strlen(msg) - 1;
|
|
||||||
msg[len] = '\0';
|
|
||||||
strsubst(msg, '\n', ' ');
|
|
||||||
|
|
||||||
prompt_update_statusmessage(prompt, m, msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
@ -590,8 +569,9 @@ void cmd_requests(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
for (i = 0; i < FrndRequests.max_idx; ++i) {
|
for (i = 0; i < FrndRequests.max_idx; ++i) {
|
||||||
if (!FrndRequests.request[i].active)
|
if (!FrndRequests.request[i].active) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
char id[TOX_PUBLIC_KEY_SIZE * 2 + 1] = {0};
|
char id[TOX_PUBLIC_KEY_SIZE * 2 + 1] = {0};
|
||||||
|
|
||||||
@ -604,36 +584,34 @@ void cmd_requests(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
|||||||
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, "%d : %s", i, id);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", FrndRequests.request[i].msg);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", FrndRequests.request[i].msg);
|
||||||
|
|
||||||
if (++count < FrndRequests.num_requests)
|
if (++count < FrndRequests.num_requests) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
|
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])
|
void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
bool have_note = false;
|
|
||||||
const char *errmsg;
|
const char *errmsg;
|
||||||
|
|
||||||
lock_status();
|
lock_status();
|
||||||
|
|
||||||
if (argc >= 2) {
|
if (argc < 1) {
|
||||||
have_note = true;
|
|
||||||
} else if (argc < 1) {
|
|
||||||
errmsg = "Require a status. Statuses are: online, busy and away.";
|
errmsg = "Require a status. Statuses are: online, busy and away.";
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *status_str = argv[1];
|
const char *status_str = argv[1];
|
||||||
TOX_USER_STATUS status;
|
Tox_User_Status status;
|
||||||
|
|
||||||
if (!strcasecmp(status_str, "online"))
|
if (!strcasecmp(status_str, "online")) {
|
||||||
status = TOX_USER_STATUS_NONE;
|
status = TOX_USER_STATUS_NONE;
|
||||||
else if (!strcasecmp(status_str, "away"))
|
} else if (!strcasecmp(status_str, "away")) {
|
||||||
status = TOX_USER_STATUS_AWAY;
|
status = TOX_USER_STATUS_AWAY;
|
||||||
else if (!strcasecmp(status_str, "busy"))
|
} else if (!strcasecmp(status_str, "busy")) {
|
||||||
status = TOX_USER_STATUS_BUSY;
|
status = TOX_USER_STATUS_BUSY;
|
||||||
else {
|
} else {
|
||||||
errmsg = "Invalid status. Valid statuses are: online, busy and away.";
|
errmsg = "Invalid status. Valid statuses are: online, busy and away.";
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
||||||
goto finish;
|
goto finish;
|
||||||
@ -641,24 +619,8 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
|||||||
|
|
||||||
tox_self_set_status(m, status);
|
tox_self_set_status(m, status);
|
||||||
prompt_update_status(prompt, status);
|
prompt_update_status(prompt, status);
|
||||||
|
|
||||||
if (have_note) {
|
|
||||||
if (argv[2][0] != '\"') {
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Note must be enclosed in quotes.");
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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';
|
|
||||||
|
|
||||||
prompt_update_statusmessage(prompt, m, msg);
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Your status has been changed to %s: \"%s\".", status_str, msg);
|
|
||||||
} else {
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Your status has been changed to %s.", status_str);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Your status has been changed to %s.", status_str);
|
||||||
}
|
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
unlock_status();
|
unlock_status();
|
||||||
|
@ -35,7 +35,9 @@ void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
|
|||||||
void cmd_groupchat(WINDOW *, ToxWindow *, Tox *, 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_log(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
void cmd_myid(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_myid(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
|
#ifdef QRCODE
|
||||||
void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
|
#endif /* QRCODE */
|
||||||
void cmd_nick(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
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_note(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
void cmd_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
@ -58,6 +60,6 @@ void cmd_change_video_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv
|
|||||||
|
|
||||||
#ifdef PYTHON
|
#ifdef PYTHON
|
||||||
void cmd_run(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_run(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
#endif
|
#endif /* PYTHON */
|
||||||
|
|
||||||
#endif /* #define GLOBAL_COMMANDS_H */
|
#endif /* GLOBAL_COMMANDS_H */
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
void cmd_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
TOX_ERR_CONFERENCE_TITLE err;
|
Tox_Err_Conference_Title err;
|
||||||
char title[MAX_STR_SIZE];
|
char title[MAX_STR_SIZE];
|
||||||
|
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
@ -52,15 +52,8 @@ void cmd_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argv[1][0] != '\"') {
|
snprintf(title, sizeof(title), "%s", argv[1]);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title must be enclosed in quotes.");
|
int len = strlen(title);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remove opening and closing quotes */
|
|
||||||
snprintf(title, sizeof(title), "%s", &argv[1][1]);
|
|
||||||
int len = strlen(title) - 1;
|
|
||||||
title[len] = '\0';
|
|
||||||
|
|
||||||
if (!tox_conference_set_title(m, self->num, (uint8_t *) title, len, &err)) {
|
if (!tox_conference_set_title(m, self->num, (uint8_t *) title, len, &err)) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title (error %d)", err);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title (error %d)", err);
|
||||||
|
501
src/groupchat.c
501
src/groupchat.c
@ -69,15 +69,17 @@ static int max_groupchat_index = 0;
|
|||||||
extern struct user_settings *user_settings;
|
extern struct user_settings *user_settings;
|
||||||
extern struct Winthread Winthread;
|
extern struct Winthread Winthread;
|
||||||
|
|
||||||
#if defined(AUDIO) && defined(PYTHON)
|
#ifdef PYTHON
|
||||||
#define AC_NUM_GROUP_COMMANDS 25
|
#define AC_NUM_GROUP_COMMANDS_PYTHON 1
|
||||||
#elif AUDIO
|
|
||||||
#define AC_NUM_GROUP_COMMANDS 24
|
|
||||||
#elif PYTHON
|
|
||||||
#define AC_NUM_GROUP_COMMANDS 21
|
|
||||||
#else
|
#else
|
||||||
#define AC_NUM_GROUP_COMMANDS 20
|
#define AC_NUM_GROUP_COMMANDS_PYTHON 0
|
||||||
#endif /* AUDIO */
|
#endif /* PYTHON */
|
||||||
|
#ifdef QRCODE
|
||||||
|
#define AC_NUM_GROUP_COMMANDS_QRCODE 1
|
||||||
|
#else
|
||||||
|
#define AC_NUM_GROUP_COMMANDS_QRCODE 0
|
||||||
|
#endif /* QRCODE */
|
||||||
|
#define AC_NUM_GROUP_COMMANDS (19 + AC_NUM_GROUP_COMMANDS_PYTHON + AC_NUM_GROUP_COMMANDS_QRCODE)
|
||||||
|
|
||||||
/* Array of groupchat command names used for tab completion. */
|
/* Array of groupchat command names used for tab completion. */
|
||||||
static const char group_cmd_list[AC_NUM_GROUP_COMMANDS][MAX_CMDNAME_SIZE] = {
|
static const char group_cmd_list[AC_NUM_GROUP_COMMANDS][MAX_CMDNAME_SIZE] = {
|
||||||
@ -93,7 +95,9 @@ static const char group_cmd_list[AC_NUM_GROUP_COMMANDS][MAX_CMDNAME_SIZE] = {
|
|||||||
{ "/help" },
|
{ "/help" },
|
||||||
{ "/log" },
|
{ "/log" },
|
||||||
{ "/myid" },
|
{ "/myid" },
|
||||||
|
#ifdef QRCODE
|
||||||
{ "/myqr" },
|
{ "/myqr" },
|
||||||
|
#endif /* QRCODE */
|
||||||
{ "/nick" },
|
{ "/nick" },
|
||||||
{ "/note" },
|
{ "/note" },
|
||||||
{ "/nospam" },
|
{ "/nospam" },
|
||||||
@ -109,47 +113,6 @@ static const char group_cmd_list[AC_NUM_GROUP_COMMANDS][MAX_CMDNAME_SIZE] = {
|
|||||||
#endif /* PYTHON */
|
#endif /* PYTHON */
|
||||||
};
|
};
|
||||||
|
|
||||||
int init_groupchat_win(ToxWindow *prompt, Tox *m, uint32_t groupnum, uint8_t type)
|
|
||||||
{
|
|
||||||
if (groupnum > MAX_GROUPCHAT_NUM) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ToxWindow self = new_group_chat(m, groupnum);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i <= max_groupchat_index; ++i) {
|
|
||||||
if (!groupchats[i].active) {
|
|
||||||
groupchats[i].chatwin = add_window(m, self);
|
|
||||||
groupchats[i].active = true;
|
|
||||||
groupchats[i].num_peers = 0;
|
|
||||||
groupchats[i].type = type;
|
|
||||||
groupchats[i].start_time = get_unix_time();
|
|
||||||
|
|
||||||
groupchats[i].peer_names = malloc(sizeof(uint8_t) * TOX_MAX_NAME_LENGTH);
|
|
||||||
groupchats[i].oldpeer_names = malloc(sizeof(uint8_t) * TOX_MAX_NAME_LENGTH);
|
|
||||||
groupchats[i].peer_name_lengths = malloc(sizeof(uint16_t));
|
|
||||||
groupchats[i].oldpeer_name_lengths = malloc(sizeof(uint16_t));
|
|
||||||
|
|
||||||
if (groupchats[i].peer_names == NULL || groupchats[i].oldpeer_names == NULL
|
|
||||||
|| groupchats[i].peer_name_lengths == NULL || groupchats[i].oldpeer_name_lengths == NULL)
|
|
||||||
exit_toxic_err("failed in init_groupchat_win", FATALERR_MEMORY);
|
|
||||||
|
|
||||||
memcpy(&groupchats[i].oldpeer_names[0], UNKNOWN_NAME, sizeof(UNKNOWN_NAME));
|
|
||||||
groupchats[i].oldpeer_name_lengths[0] = (uint16_t) strlen(UNKNOWN_NAME);
|
|
||||||
|
|
||||||
set_active_window(groupchats[i].chatwin);
|
|
||||||
|
|
||||||
if (i == max_groupchat_index)
|
|
||||||
++max_groupchat_index;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void kill_groupchat_window(ToxWindow *self)
|
static void kill_groupchat_window(ToxWindow *self)
|
||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
@ -165,27 +128,61 @@ static void kill_groupchat_window(ToxWindow *self)
|
|||||||
del_window(self);
|
del_window(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void close_groupchat(ToxWindow *self, Tox *m, uint32_t groupnum)
|
int init_groupchat_win(ToxWindow *prompt, Tox *m, uint32_t groupnum, uint8_t type)
|
||||||
{
|
{
|
||||||
tox_conference_delete(m, groupnum, NULL);
|
if (groupnum > MAX_GROUPCHAT_NUM) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
free(groupchats[groupnum].peer_names);
|
ToxWindow *self = new_group_chat(m, groupnum);
|
||||||
free(groupchats[groupnum].oldpeer_names);
|
|
||||||
free(groupchats[groupnum].peer_name_lengths);
|
for (int i = 0; i <= max_groupchat_index; ++i) {
|
||||||
free(groupchats[groupnum].oldpeer_name_lengths);
|
if (!groupchats[i].active) {
|
||||||
|
groupchats[i].chatwin = add_window(m, self);
|
||||||
|
groupchats[i].active = true;
|
||||||
|
groupchats[i].num_peers = 0;
|
||||||
|
groupchats[i].type = type;
|
||||||
|
groupchats[i].start_time = get_unix_time();
|
||||||
|
|
||||||
|
set_active_window_index(groupchats[i].chatwin);
|
||||||
|
|
||||||
|
if (i == max_groupchat_index) {
|
||||||
|
++max_groupchat_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kill_groupchat_window(self);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_groupchat(ToxWindow *self, Tox *m, uint32_t groupnum)
|
||||||
|
{
|
||||||
|
free(groupchats[groupnum].name_list);
|
||||||
|
free(groupchats[groupnum].peer_list);
|
||||||
memset(&groupchats[groupnum], 0, sizeof(GroupChat));
|
memset(&groupchats[groupnum], 0, sizeof(GroupChat));
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = max_groupchat_index; i > 0; --i) {
|
for (i = max_groupchat_index; i > 0; --i) {
|
||||||
if (groupchats[i - 1].active)
|
if (groupchats[i - 1].active) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
max_groupchat_index = i;
|
max_groupchat_index = i;
|
||||||
kill_groupchat_window(self);
|
kill_groupchat_window(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void delete_groupchat(ToxWindow *self, Tox *m, uint32_t groupnum)
|
||||||
|
{
|
||||||
|
tox_conference_delete(m, groupnum, NULL);
|
||||||
|
free_groupchat(self, m, groupnum);
|
||||||
|
}
|
||||||
|
|
||||||
/* destroys and re-creates groupchat window with or without the peerlist */
|
/* destroys and re-creates groupchat window with or without the peerlist */
|
||||||
void redraw_groupchat_win(ToxWindow *self)
|
void redraw_groupchat_win(ToxWindow *self)
|
||||||
{
|
{
|
||||||
@ -199,8 +196,9 @@ void redraw_groupchat_win(ToxWindow *self)
|
|||||||
getmaxyx(stdscr, y2, x2);
|
getmaxyx(stdscr, y2, x2);
|
||||||
y2 -= 2;
|
y2 -= 2;
|
||||||
|
|
||||||
if (y2 <= 0 || x2 <= 0)
|
if (y2 <= 0 || x2 <= 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (ctx->sidebar) {
|
if (ctx->sidebar) {
|
||||||
delwin(ctx->sidebar);
|
delwin(ctx->sidebar);
|
||||||
@ -226,10 +224,11 @@ void redraw_groupchat_win(ToxWindow *self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, uint32_t groupnum, uint32_t peernum,
|
static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, uint32_t groupnum, uint32_t peernum,
|
||||||
TOX_MESSAGE_TYPE type, const char *msg, size_t len)
|
Tox_Message_Type type, const char *msg, size_t len)
|
||||||
{
|
{
|
||||||
if (self->num != groupnum)
|
if (self->num != groupnum) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
@ -248,10 +247,11 @@ static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, uint32_t groupnum,
|
|||||||
if (strcasestr(msg, selfnick) && strcmp(selfnick, nick)) {
|
if (strcasestr(msg, selfnick) && strcmp(selfnick, nick)) {
|
||||||
sound_notify(self, generic_message, NT_WNDALERT_0 | user_settings->bell_on_message, NULL);
|
sound_notify(self, generic_message, NT_WNDALERT_0 | user_settings->bell_on_message, NULL);
|
||||||
|
|
||||||
if (self->active_box != -1)
|
if (self->active_box != -1) {
|
||||||
box_silent_notify2(self, NT_NOFOCUS, self->active_box, "%s %s", nick, msg);
|
box_silent_notify2(self, NT_NOFOCUS, self->active_box, "%s %s", nick, msg);
|
||||||
else
|
} else {
|
||||||
box_silent_notify(self, NT_NOFOCUS, &self->active_box, self->name, "%s %s", nick, msg);
|
box_silent_notify(self, NT_NOFOCUS, &self->active_box, self->name, "%s %s", nick, msg);
|
||||||
|
}
|
||||||
|
|
||||||
nick_clr = RED;
|
nick_clr = RED;
|
||||||
} else {
|
} else {
|
||||||
@ -271,8 +271,9 @@ static void groupchat_onGroupTitleChange(ToxWindow *self, Tox *m, uint32_t group
|
|||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
if (self->num != groupnum)
|
if (self->num != groupnum) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
set_window_title(self, title, length);
|
set_window_title(self, title, length);
|
||||||
|
|
||||||
@ -280,8 +281,9 @@ static void groupchat_onGroupTitleChange(ToxWindow *self, Tox *m, uint32_t group
|
|||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
|
|
||||||
/* don't announce title when we join the room */
|
/* don't announce title when we join the room */
|
||||||
if (!timed_out(groupchats[self->num].start_time, GROUP_EVENT_WAIT))
|
if (!timed_out(groupchats[self->num].start_time, GROUP_EVENT_WAIT)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
char nick[TOX_MAX_NAME_LENGTH];
|
char nick[TOX_MAX_NAME_LENGTH];
|
||||||
get_group_nick_truncate(m, nick, peernum, groupnum);
|
get_group_nick_truncate(m, nick, peernum, groupnum);
|
||||||
@ -292,212 +294,162 @@ static void groupchat_onGroupTitleChange(ToxWindow *self, Tox *m, uint32_t group
|
|||||||
write_to_log(tmp_event, nick, ctx->log, true);
|
write_to_log(tmp_event, nick, ctx->log, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Puts two copies of peerlist/lengths in chat instance */
|
static void group_update_name_list(uint32_t groupnum)
|
||||||
static void copy_peernames(Tox *m, uint32_t gnum, size_t npeers)
|
|
||||||
{
|
{
|
||||||
/* Assumes these are initiated in init_groupchat_win */
|
GroupChat *chat = &groupchats[groupnum];
|
||||||
free(groupchats[gnum].peer_names);
|
|
||||||
free(groupchats[gnum].oldpeer_names);
|
|
||||||
free(groupchats[gnum].peer_name_lengths);
|
|
||||||
free(groupchats[gnum].oldpeer_name_lengths);
|
|
||||||
|
|
||||||
int N = TOX_MAX_NAME_LENGTH;
|
if (!chat) {
|
||||||
|
return;
|
||||||
groupchats[gnum].peer_names = calloc(1, sizeof(uint8_t) * npeers * N);
|
|
||||||
groupchats[gnum].oldpeer_names = calloc(1, sizeof(uint8_t) * npeers * N);
|
|
||||||
groupchats[gnum].peer_name_lengths = calloc(1, sizeof(uint16_t) * npeers);
|
|
||||||
groupchats[gnum].oldpeer_name_lengths = calloc(1, sizeof(uint16_t) * npeers);
|
|
||||||
|
|
||||||
if (groupchats[gnum].peer_names == NULL || groupchats[gnum].oldpeer_names == NULL
|
|
||||||
|| groupchats[gnum].peer_name_lengths == NULL || groupchats[gnum].oldpeer_name_lengths == NULL) {
|
|
||||||
exit_toxic_err("failed in copy_peernames()", FATALERR_MEMORY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t u_len = strlen(UNKNOWN_NAME);
|
if (chat->name_list) {
|
||||||
|
free(chat->name_list);
|
||||||
|
}
|
||||||
|
|
||||||
int i;
|
chat->name_list = malloc(sizeof(char *) * chat->num_peers * TOX_MAX_NAME_LENGTH);
|
||||||
|
|
||||||
for (i = 0; i < npeers; ++i) {
|
if (chat->name_list == NULL) {
|
||||||
uint8_t name[TOX_MAX_NAME_LENGTH];
|
exit_toxic_err("failed in group_update_name_list", FATALERR_MEMORY);
|
||||||
TOX_ERR_CONFERENCE_PEER_QUERY err;
|
}
|
||||||
|
|
||||||
size_t n_len = tox_conference_peer_get_name_size(m, gnum, i, &err);
|
uint32_t i, count = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < chat->max_idx; ++i) {
|
||||||
|
if (chat->peer_list[i].active) {
|
||||||
|
memcpy(&chat->name_list[count * TOX_MAX_NAME_LENGTH], chat->peer_list[i].name, chat->peer_list[i].name_length + 1);
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort(chat->name_list, count, TOX_MAX_NAME_LENGTH, qsort_strcasecmp_hlpr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reallocates groupnum's peer list. Increase is true if the list needs to grow.
|
||||||
|
*
|
||||||
|
* Returns 0 on success.
|
||||||
|
* Returns -1 on failure.
|
||||||
|
*/
|
||||||
|
static int realloc_peer_list(GroupChat *chat, uint32_t num_peers)
|
||||||
|
{
|
||||||
|
if (!chat) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_peers == 0) {
|
||||||
|
free(chat->peer_list);
|
||||||
|
chat->peer_list = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GroupPeer *tmp_list = realloc(chat->peer_list, num_peers * sizeof(struct GroupPeer));
|
||||||
|
|
||||||
|
if (!tmp_list) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
chat->peer_list = tmp_list;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_peer_list(Tox *m, uint32_t groupnum, uint32_t num_peers)
|
||||||
|
{
|
||||||
|
GroupChat *chat = &groupchats[groupnum];
|
||||||
|
|
||||||
|
if (!chat) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
realloc_peer_list(chat, num_peers);
|
||||||
|
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < num_peers; ++i) {
|
||||||
|
GroupPeer *peer = &chat->peer_list[i];
|
||||||
|
|
||||||
|
Tox_Err_Conference_Peer_Query err;
|
||||||
|
size_t length = tox_conference_peer_get_name_size(m, groupnum, i, &err);
|
||||||
|
|
||||||
|
if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK || length >= TOX_MAX_NAME_LENGTH) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tox_conference_peer_get_name(m, groupnum, i, (uint8_t *) peer->name, &err);
|
||||||
|
peer->name[length] = 0;
|
||||||
|
|
||||||
if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
|
if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
|
||||||
memcpy(&groupchats[gnum].peer_names[i * N], UNKNOWN_NAME, u_len);
|
continue;
|
||||||
groupchats[gnum].peer_names[i * N + u_len] = '\0';
|
|
||||||
groupchats[gnum].peer_name_lengths[i] = u_len;
|
|
||||||
} else {
|
|
||||||
tox_conference_peer_get_name(m, gnum, i, name, NULL);
|
|
||||||
n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH - 1);
|
|
||||||
memcpy(&groupchats[gnum].peer_names[i * N], name, n_len);
|
|
||||||
groupchats[gnum].peer_names[i * N + n_len] = '\0';
|
|
||||||
groupchats[gnum].peer_name_lengths[i] = n_len;
|
|
||||||
filter_str((char *) &groupchats[gnum].peer_names[i * N], n_len);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(groupchats[gnum].oldpeer_names, groupchats[gnum].peer_names, N * npeers);
|
peer->active = true;
|
||||||
memcpy(groupchats[gnum].oldpeer_name_lengths, groupchats[gnum].peer_name_lengths, sizeof(uint16_t) * npeers);
|
peer->name_length = length;
|
||||||
|
peer->peernumber = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct group_add_thrd {
|
group_update_name_list(groupnum);
|
||||||
Tox *m;
|
}
|
||||||
ToxWindow *self;
|
|
||||||
uint32_t peernum;
|
|
||||||
uint32_t groupnum;
|
|
||||||
time_t timestamp;
|
|
||||||
pthread_t tid;
|
|
||||||
pthread_attr_t attr;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Waits GROUP_EVENT_WAIT seconds for a new peer to set their name before announcing them */
|
static void groupchat_onGroupNameListChange(ToxWindow *self, Tox *m, uint32_t groupnum)
|
||||||
void *group_add_wait(void *data)
|
|
||||||
{
|
{
|
||||||
struct group_add_thrd *thrd = (struct group_add_thrd *) data;
|
if (self->num != groupnum) {
|
||||||
ToxWindow *self = thrd->self;
|
|
||||||
Tox *m = thrd->m;
|
|
||||||
char peername[TOX_MAX_NAME_LENGTH];
|
|
||||||
|
|
||||||
/* keep polling for a name that differs from the default until we run out of time */
|
|
||||||
while (true) {
|
|
||||||
usleep(100000);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
|
||||||
get_group_nick_truncate(m, peername, thrd->peernum, thrd->groupnum);
|
|
||||||
|
|
||||||
if (strcmp(peername, DEFAULT_TOX_NAME) || timed_out(thrd->timestamp, GROUP_EVENT_WAIT)) {
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *event = "has joined the room";
|
|
||||||
char timefrmt[TIME_STR_SIZE];
|
|
||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
|
||||||
line_info_add(self, timefrmt, (char *) peername, NULL, CONNECTION, 0, GREEN, event);
|
|
||||||
write_to_log(event, (char *) peername, self->chatwin->log, true);
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
|
||||||
|
|
||||||
pthread_attr_destroy(&thrd->attr);
|
|
||||||
free(thrd);
|
|
||||||
pthread_exit(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, uint32_t groupnum, uint32_t peernum,
|
|
||||||
TOX_CONFERENCE_STATE_CHANGE change)
|
|
||||||
{
|
|
||||||
if (self->num != groupnum)
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (groupnum > max_groupchat_index)
|
if (groupnum > max_groupchat_index) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TOX_ERR_CONFERENCE_PEER_QUERY err;
|
GroupChat *chat = &groupchats[groupnum];
|
||||||
|
Tox_Err_Conference_Peer_Query err;
|
||||||
|
|
||||||
uint32_t num_peers = tox_conference_peer_count(m, groupnum, &err);
|
uint32_t num_peers = tox_conference_peer_count(m, groupnum, &err);
|
||||||
|
uint32_t old_num = chat->num_peers;
|
||||||
|
|
||||||
if (err == TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
|
if (err == TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
|
||||||
groupchats[groupnum].num_peers = num_peers;
|
chat->num_peers = num_peers;
|
||||||
} else {
|
} else {
|
||||||
num_peers = groupchats[groupnum].num_peers;
|
num_peers = old_num;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (peernum > num_peers)
|
chat->max_idx = num_peers;
|
||||||
|
update_peer_list(m, groupnum, num_peers);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void groupchat_onGroupPeerNameChange(ToxWindow *self, Tox *m, uint32_t groupnum, uint32_t peernum,
|
||||||
|
const char *name, size_t length)
|
||||||
|
{
|
||||||
|
if (self->num != groupnum) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* get old peer name before updating name list */
|
|
||||||
uint8_t oldpeername[TOX_MAX_NAME_LENGTH];
|
|
||||||
|
|
||||||
if (change != TOX_CONFERENCE_STATE_CHANGE_PEER_JOIN) {
|
|
||||||
memcpy(oldpeername, &groupchats[groupnum].oldpeer_names[peernum * TOX_MAX_NAME_LENGTH], sizeof(oldpeername));
|
|
||||||
uint16_t old_n_len = groupchats[groupnum].oldpeer_name_lengths[peernum];
|
|
||||||
oldpeername[old_n_len] = '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update name/len lists */
|
GroupChat *chat = &groupchats[groupnum];
|
||||||
copy_peernames(m, groupnum, num_peers);
|
|
||||||
|
|
||||||
/* get current peername then sort namelist */
|
if (!chat) {
|
||||||
uint8_t peername[TOX_MAX_NAME_LENGTH];
|
return;
|
||||||
|
|
||||||
if (change != TOX_CONFERENCE_STATE_CHANGE_PEER_EXIT) {
|
|
||||||
uint16_t n_len = groupchats[groupnum].peer_name_lengths[peernum];
|
|
||||||
memcpy(peername, &groupchats[groupnum].peer_names[peernum * TOX_MAX_NAME_LENGTH], sizeof(peername));
|
|
||||||
peername[n_len] = '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qsort(groupchats[groupnum].peer_names, groupchats[groupnum].num_peers, TOX_MAX_NAME_LENGTH, qsort_strcasecmp_hlpr);
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < chat->max_idx; ++i) {
|
||||||
|
GroupPeer *peer = &chat->peer_list[i];
|
||||||
|
|
||||||
|
// Test against default tox name to prevent nick change spam on initial join (TODO: this is disgusting)
|
||||||
|
if (peer->active && peer->peernumber == peernum && peer->name_length > 0) {
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
const char *event;
|
|
||||||
char timefrmt[TIME_STR_SIZE];
|
char timefrmt[TIME_STR_SIZE];
|
||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
|
|
||||||
switch (change) {
|
|
||||||
case TOX_CONFERENCE_STATE_CHANGE_PEER_JOIN:
|
|
||||||
if (!timed_out(groupchats[groupnum].start_time, GROUP_EVENT_WAIT))
|
|
||||||
break;
|
|
||||||
|
|
||||||
struct group_add_thrd *thrd = malloc(sizeof(struct group_add_thrd));
|
|
||||||
thrd->m = m;
|
|
||||||
thrd->peernum = peernum;
|
|
||||||
thrd->groupnum = groupnum;
|
|
||||||
thrd->self = self;
|
|
||||||
thrd->timestamp = get_unix_time();
|
|
||||||
|
|
||||||
if (pthread_attr_init(&thrd->attr) != 0) {
|
|
||||||
free(thrd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pthread_attr_setdetachstate(&thrd->attr, PTHREAD_CREATE_DETACHED) != 0) {
|
|
||||||
pthread_attr_destroy(&thrd->attr);
|
|
||||||
free(thrd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pthread_create(&thrd->tid, &thrd->attr, group_add_wait, (void *) thrd) != 0) {
|
|
||||||
pthread_attr_destroy(&thrd->attr);
|
|
||||||
free(thrd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TOX_CONFERENCE_STATE_CHANGE_PEER_EXIT:
|
|
||||||
event = "has left the room";
|
|
||||||
line_info_add(self, timefrmt, (char *) oldpeername, NULL, DISCONNECTION, 0, RED, event);
|
|
||||||
|
|
||||||
if (groupchats[self->num].side_pos > 0)
|
|
||||||
--groupchats[self->num].side_pos;
|
|
||||||
|
|
||||||
write_to_log(event, (char *) oldpeername, ctx->log, true);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TOX_CONFERENCE_STATE_CHANGE_PEER_NAME_CHANGE:
|
|
||||||
if (!timed_out(groupchats[self->num].start_time, GROUP_EVENT_WAIT))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* ignore initial name change (TODO: this is a bad way to do this) */
|
|
||||||
if (strcmp((char *) oldpeername, DEFAULT_TOX_NAME) == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
event = " is now known as ";
|
|
||||||
line_info_add(self, timefrmt, (char *) oldpeername, (char *) peername, NAME_CHANGE, 0, 0, event);
|
|
||||||
|
|
||||||
char tmp_event[TOXIC_MAX_NAME_LENGTH * 2 + 32];
|
char tmp_event[TOXIC_MAX_NAME_LENGTH * 2 + 32];
|
||||||
snprintf(tmp_event, sizeof(tmp_event), "is now known as %s", (char *) peername);
|
snprintf(tmp_event, sizeof(tmp_event), "is now known as %s", (const char *) name);
|
||||||
write_to_log(tmp_event, (char *) oldpeername, ctx->log, true);
|
|
||||||
|
write_to_log(tmp_event, peer->name, ctx->log, true);
|
||||||
|
line_info_add(self, timefrmt, peer->name, (const char *) name, NAME_CHANGE, 0, 0, " is now known as ");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sound_notify(self, silent, NT_WNDALERT_2, NULL);
|
groupchat_onGroupNameListChange(self, m, groupnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void send_group_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
|
static void send_group_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
|
||||||
@ -507,7 +459,7 @@ static void send_group_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *a
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TOX_ERR_CONFERENCE_SEND_MESSAGE err;
|
Tox_Err_Conference_Send_Message err;
|
||||||
|
|
||||||
if (!tox_conference_send_message(m, self->num, TOX_MESSAGE_TYPE_ACTION, (uint8_t *) action, strlen(action), &err)) {
|
if (!tox_conference_send_message(m, self->num, TOX_MESSAGE_TYPE_ACTION, (uint8_t *) action, strlen(action), &err)) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send action (error %d)", err);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send action (error %d)", err);
|
||||||
@ -522,27 +474,31 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
getyx(self->window, y, x);
|
getyx(self->window, y, x);
|
||||||
getmaxyx(self->window, y2, x2);
|
getmaxyx(self->window, y2, x2);
|
||||||
|
|
||||||
if (x2 <= 0 || y2 <= 0)
|
if (x2 <= 0 || y2 <= 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (self->help->active) {
|
if (self->help->active) {
|
||||||
help_onKey(self, key);
|
help_onKey(self, key);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->pastemode && key == '\r')
|
if (ctx->pastemode && key == '\r') {
|
||||||
key = '\n';
|
key = '\n';
|
||||||
|
}
|
||||||
|
|
||||||
if (ltr || key == '\n') { /* char is printable */
|
if (ltr || key == '\n') { /* char is printable */
|
||||||
input_new_char(self, key, x, y, x2, y2);
|
input_new_char(self, key, x, y, x2, y2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (line_info_onKey(self, key))
|
if (line_info_onKey(self, key)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (input_handle(self, key, x, y, x2, y2))
|
if (input_handle(self, key, x, y, x2, y2)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (key == '\t') { /* TAB key: auto-completes peer name or command */
|
if (key == '\t') { /* TAB key: auto-completes peer name or command */
|
||||||
if (ctx->len > 0) {
|
if (ctx->len > 0) {
|
||||||
@ -550,14 +506,14 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
|
|
||||||
/* TODO: make this not suck */
|
/* TODO: make this not suck */
|
||||||
if (ctx->line[0] != L'/' || wcscmp(ctx->line, L"/me") == 0) {
|
if (ctx->line[0] != L'/' || wcscmp(ctx->line, L"/me") == 0) {
|
||||||
diff = complete_line(self, groupchats[self->num].peer_names, groupchats[self->num].num_peers,
|
diff = complete_line(self, groupchats[self->num].name_list, groupchats[self->num].num_peers,
|
||||||
TOX_MAX_NAME_LENGTH);
|
TOX_MAX_NAME_LENGTH);
|
||||||
} else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) {
|
} else if (wcsncmp(ctx->line, L"/avatar ", wcslen(L"/avatar ")) == 0) {
|
||||||
diff = dir_match(self, m, ctx->line, L"/avatar");
|
diff = dir_match(self, m, ctx->line, L"/avatar");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef PYTHON
|
#ifdef PYTHON
|
||||||
else if (wcsncmp(ctx->line, L"/run \"", wcslen(L"/run \"")) == 0) {
|
else if (wcsncmp(ctx->line, L"/run ", wcslen(L"/run ")) == 0) {
|
||||||
diff = dir_match(self, m, ctx->line, L"/run");
|
diff = dir_match(self, m, ctx->line, L"/run");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -581,11 +537,13 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
} else if (key == user_settings->key_peer_list_down) { /* Scroll peerlist up and down one position */
|
} else if (key == user_settings->key_peer_list_down) { /* Scroll peerlist up and down one position */
|
||||||
int L = y2 - CHATBOX_HEIGHT - SDBAR_OFST;
|
int L = y2 - CHATBOX_HEIGHT - SDBAR_OFST;
|
||||||
|
|
||||||
if (groupchats[self->num].side_pos < groupchats[self->num].num_peers - L)
|
if (groupchats[self->num].side_pos < groupchats[self->num].num_peers - L) {
|
||||||
++groupchats[self->num].side_pos;
|
++groupchats[self->num].side_pos;
|
||||||
|
}
|
||||||
} else if (key == user_settings->key_peer_list_up) {
|
} else if (key == user_settings->key_peer_list_up) {
|
||||||
if (groupchats[self->num].side_pos > 0)
|
if (groupchats[self->num].side_pos > 0) {
|
||||||
--groupchats[self->num].side_pos;
|
--groupchats[self->num].side_pos;
|
||||||
|
}
|
||||||
} else if (key == '\r') {
|
} else if (key == '\r') {
|
||||||
rm_trailing_spaces_buf(ctx);
|
rm_trailing_spaces_buf(ctx);
|
||||||
|
|
||||||
@ -596,12 +554,13 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
|
|
||||||
char line[MAX_STR_SIZE];
|
char line[MAX_STR_SIZE];
|
||||||
|
|
||||||
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
|
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
|
||||||
memset(&line, 0, sizeof(line));
|
memset(&line, 0, sizeof(line));
|
||||||
|
}
|
||||||
|
|
||||||
if (line[0] == '/') {
|
if (line[0] == '/') {
|
||||||
if (strcmp(line, "/close") == 0) {
|
if (strcmp(line, "/close") == 0) {
|
||||||
close_groupchat(self, m, self->num);
|
delete_groupchat(self, m, self->num);
|
||||||
return;
|
return;
|
||||||
} else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
|
} else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
|
||||||
send_group_action(self, ctx, m, line + strlen("/me "));
|
send_group_action(self, ctx, m, line + strlen("/me "));
|
||||||
@ -609,7 +568,7 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
execute(ctx->history, self, m, line, GROUPCHAT_COMMAND_MODE);
|
execute(ctx->history, self, m, line, GROUPCHAT_COMMAND_MODE);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TOX_ERR_CONFERENCE_SEND_MESSAGE err;
|
Tox_Err_Conference_Send_Message err;
|
||||||
|
|
||||||
if (!tox_conference_send_message(m, self->num, TOX_MESSAGE_TYPE_NORMAL, (uint8_t *) line, strlen(line), &err)) {
|
if (!tox_conference_send_message(m, self->num, TOX_MESSAGE_TYPE_NORMAL, (uint8_t *) line, strlen(line), &err)) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send message (error %d)", err);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send message (error %d)", err);
|
||||||
@ -628,8 +587,9 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
int x2, y2;
|
int x2, y2;
|
||||||
getmaxyx(self->window, y2, x2);
|
getmaxyx(self->window, y2, x2);
|
||||||
|
|
||||||
if (x2 <= 0 || y2 <= 0)
|
if (x2 <= 0 || y2 <= 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
@ -641,8 +601,9 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
curs_set(1);
|
curs_set(1);
|
||||||
|
|
||||||
if (ctx->len > 0)
|
if (ctx->len > 0) {
|
||||||
mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]);
|
mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]);
|
||||||
|
}
|
||||||
|
|
||||||
wclear(ctx->sidebar);
|
wclear(ctx->sidebar);
|
||||||
mvwhline(self->window, y2 - CHATBOX_HEIGHT, 0, ACS_HLINE, x2);
|
mvwhline(self->window, y2 - CHATBOX_HEIGHT, 0, ACS_HLINE, x2);
|
||||||
@ -678,7 +639,7 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
int maxlen = SIDEBAR_WIDTH - 2;
|
int maxlen = SIDEBAR_WIDTH - 2;
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
memcpy(tmpnck, &groupchats[self->num].peer_names[peer * TOX_MAX_NAME_LENGTH], maxlen);
|
memcpy(tmpnck, &groupchats[self->num].name_list[peer * TOX_MAX_NAME_LENGTH], maxlen);
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
tmpnck[maxlen] = '\0';
|
tmpnck[maxlen] = '\0';
|
||||||
@ -695,17 +656,19 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
wnoutrefresh(self->window);
|
wnoutrefresh(self->window);
|
||||||
|
|
||||||
if (self->help->active)
|
if (self->help->active) {
|
||||||
help_onDraw(self);
|
help_onDraw(self);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void groupchat_onInit(ToxWindow *self, Tox *m)
|
static void groupchat_onInit(ToxWindow *self, Tox *m)
|
||||||
{
|
{
|
||||||
int x2, y2;
|
int x2, y2;
|
||||||
getmaxyx(self->window, y2, x2);
|
getmaxyx(self->window, y2, x2);
|
||||||
|
|
||||||
if (x2 <= 0 || y2 <= 0)
|
if (x2 <= 0 || y2 <= 0) {
|
||||||
exit_toxic_err("failed in groupchat_onInit", FATALERR_CURSES);
|
exit_toxic_err("failed in groupchat_onInit", FATALERR_CURSES);
|
||||||
|
}
|
||||||
|
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
@ -716,8 +679,9 @@ static void groupchat_onInit(ToxWindow *self, Tox *m)
|
|||||||
ctx->hst = calloc(1, sizeof(struct history));
|
ctx->hst = calloc(1, sizeof(struct history));
|
||||||
ctx->log = calloc(1, sizeof(struct chatlog));
|
ctx->log = calloc(1, sizeof(struct chatlog));
|
||||||
|
|
||||||
if (ctx->log == NULL || ctx->hst == NULL)
|
if (ctx->log == NULL || ctx->hst == NULL) {
|
||||||
exit_toxic_err("failed in groupchat_onInit", FATALERR_MEMORY);
|
exit_toxic_err("failed in groupchat_onInit", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
line_info_init(ctx->hst);
|
line_info_init(ctx->hst);
|
||||||
|
|
||||||
@ -725,9 +689,10 @@ static void groupchat_onInit(ToxWindow *self, Tox *m)
|
|||||||
char myid[TOX_ADDRESS_SIZE];
|
char myid[TOX_ADDRESS_SIZE];
|
||||||
tox_self_get_address(m, (uint8_t *) myid);
|
tox_self_get_address(m, (uint8_t *) myid);
|
||||||
|
|
||||||
if (log_enable(self->name, myid, NULL, ctx->log, LOG_GROUP) == -1)
|
if (log_enable(self->name, myid, NULL, ctx->log, LOG_GROUP) == -1) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
|
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
|
||||||
|
|
||||||
@ -735,35 +700,39 @@ static void groupchat_onInit(ToxWindow *self, Tox *m)
|
|||||||
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ToxWindow new_group_chat(Tox *m, uint32_t groupnum)
|
ToxWindow *new_group_chat(Tox *m, uint32_t groupnum)
|
||||||
{
|
{
|
||||||
ToxWindow ret;
|
ToxWindow *ret = calloc(1, sizeof(ToxWindow));
|
||||||
memset(&ret, 0, sizeof(ret));
|
|
||||||
|
|
||||||
ret.active = true;
|
if (ret == NULL) {
|
||||||
ret.is_groupchat = true;
|
exit_toxic_err("failed in new_group_chat", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
ret.onKey = &groupchat_onKey;
|
ret->is_groupchat = true;
|
||||||
ret.onDraw = &groupchat_onDraw;
|
|
||||||
ret.onInit = &groupchat_onInit;
|
|
||||||
ret.onGroupMessage = &groupchat_onGroupMessage;
|
|
||||||
ret.onGroupNamelistChange = &groupchat_onGroupNamelistChange;
|
|
||||||
ret.onGroupTitleChange = &groupchat_onGroupTitleChange;
|
|
||||||
|
|
||||||
snprintf(ret.name, sizeof(ret.name), "Group %d", groupnum);
|
ret->onKey = &groupchat_onKey;
|
||||||
|
ret->onDraw = &groupchat_onDraw;
|
||||||
|
ret->onInit = &groupchat_onInit;
|
||||||
|
ret->onGroupMessage = &groupchat_onGroupMessage;
|
||||||
|
ret->onGroupNameListChange = &groupchat_onGroupNameListChange;
|
||||||
|
ret->onGroupPeerNameChange = &groupchat_onGroupPeerNameChange;
|
||||||
|
ret->onGroupTitleChange = &groupchat_onGroupTitleChange;
|
||||||
|
|
||||||
|
snprintf(ret->name, sizeof(ret->name), "Group %u", groupnum);
|
||||||
|
|
||||||
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
|
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
|
||||||
Help *help = calloc(1, sizeof(Help));
|
Help *help = calloc(1, sizeof(Help));
|
||||||
|
|
||||||
if (chatwin == NULL || help == NULL)
|
if (chatwin == NULL || help == NULL) {
|
||||||
exit_toxic_err("failed in new_group_chat", FATALERR_MEMORY);
|
exit_toxic_err("failed in new_group_chat", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
ret.chatwin = chatwin;
|
ret->chatwin = chatwin;
|
||||||
ret.help = help;
|
ret->help = help;
|
||||||
|
|
||||||
ret.num = groupnum;
|
ret->num = groupnum;
|
||||||
ret.show_peerlist = true;
|
ret->show_peerlist = true;
|
||||||
ret.active_box = -1;
|
ret->active_box = -1;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -31,25 +31,36 @@
|
|||||||
#define MAX_GROUPCHAT_NUM MAX_WINDOWS_NUM - 2
|
#define MAX_GROUPCHAT_NUM MAX_WINDOWS_NUM - 2
|
||||||
#define GROUP_EVENT_WAIT 3
|
#define GROUP_EVENT_WAIT 3
|
||||||
|
|
||||||
|
typedef struct GroupPeer {
|
||||||
|
bool active;
|
||||||
|
char name[TOX_MAX_NAME_LENGTH];
|
||||||
|
size_t name_length;
|
||||||
|
uint32_t peernumber;
|
||||||
|
} GroupPeer;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int chatwin;
|
int chatwin;
|
||||||
bool active;
|
bool active;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint32_t num_peers;
|
|
||||||
int side_pos; /* current position of the sidebar - used for scrolling up and down */
|
int side_pos; /* current position of the sidebar - used for scrolling up and down */
|
||||||
time_t start_time;
|
time_t start_time;
|
||||||
uint8_t *peer_names;
|
|
||||||
uint8_t *oldpeer_names;
|
GroupPeer *peer_list;
|
||||||
uint16_t *peer_name_lengths;
|
size_t max_idx;
|
||||||
uint16_t *oldpeer_name_lengths;
|
|
||||||
|
char *name_list;
|
||||||
|
size_t num_peers;
|
||||||
|
|
||||||
} GroupChat;
|
} GroupChat;
|
||||||
|
|
||||||
void close_groupchat(ToxWindow *self, Tox *m, uint32_t groupnum);
|
/* Frees all Toxic associated data structures for a groupchat (does not call tox_conference_delete() ) */
|
||||||
|
void free_groupchat(ToxWindow *self, Tox *m, uint32_t groupnum);
|
||||||
|
|
||||||
int init_groupchat_win(ToxWindow *prompt, Tox *m, uint32_t groupnum, uint8_t type);
|
int init_groupchat_win(ToxWindow *prompt, Tox *m, uint32_t groupnum, uint8_t type);
|
||||||
|
|
||||||
/* destroys and re-creates groupchat window with or without the peerlist */
|
/* destroys and re-creates groupchat window with or without the peerlist */
|
||||||
void redraw_groupchat_win(ToxWindow *self);
|
void redraw_groupchat_win(ToxWindow *self);
|
||||||
|
|
||||||
ToxWindow new_group_chat(Tox *m, uint32_t groupnum);
|
ToxWindow *new_group_chat(Tox *m, uint32_t groupnum);
|
||||||
|
|
||||||
#endif /* #define GROUPCHAT_H */
|
#endif /* GROUPCHAT_H */
|
||||||
|
18
src/help.c
18
src/help.c
@ -40,14 +40,16 @@
|
|||||||
|
|
||||||
void help_init_menu(ToxWindow *self)
|
void help_init_menu(ToxWindow *self)
|
||||||
{
|
{
|
||||||
if (self->help->win)
|
if (self->help->win) {
|
||||||
delwin(self->help->win);
|
delwin(self->help->win);
|
||||||
|
}
|
||||||
|
|
||||||
int y2, x2;
|
int y2, x2;
|
||||||
getmaxyx(self->window, y2, x2);
|
getmaxyx(self->window, y2, x2);
|
||||||
|
|
||||||
if (y2 < HELP_MENU_HEIGHT || x2 < HELP_MENU_WIDTH)
|
if (y2 < HELP_MENU_HEIGHT || x2 < HELP_MENU_WIDTH) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self->help->win = newwin(HELP_MENU_HEIGHT, HELP_MENU_WIDTH, 3, 3);
|
self->help->win = newwin(HELP_MENU_HEIGHT, HELP_MENU_WIDTH, 3, 3);
|
||||||
self->help->active = true;
|
self->help->active = true;
|
||||||
@ -62,14 +64,16 @@ static void help_exit(ToxWindow *self)
|
|||||||
|
|
||||||
static void help_init_window(ToxWindow *self, int height, int width)
|
static void help_init_window(ToxWindow *self, int height, int width)
|
||||||
{
|
{
|
||||||
if (self->help->win)
|
if (self->help->win) {
|
||||||
delwin(self->help->win);
|
delwin(self->help->win);
|
||||||
|
}
|
||||||
|
|
||||||
int y2, x2;
|
int y2, x2;
|
||||||
getmaxyx(stdscr, y2, x2);
|
getmaxyx(stdscr, y2, x2);
|
||||||
|
|
||||||
if (y2 <= 0 || x2 <= 0)
|
if (y2 <= 0 || x2 <= 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
height = MIN(height, y2);
|
height = MIN(height, y2);
|
||||||
width = MIN(width, x2);
|
width = MIN(width, x2);
|
||||||
@ -173,11 +177,13 @@ static void help_draw_global(ToxWindow *self)
|
|||||||
wprintw(win, " /log <on> or <off> : Enable/disable logging\n");
|
wprintw(win, " /log <on> or <off> : Enable/disable logging\n");
|
||||||
wprintw(win, " /group <type> : Create a group chat where type: text | audio\n");
|
wprintw(win, " /group <type> : Create a group chat where type: text | audio\n");
|
||||||
wprintw(win, " /myid : Print your Tox ID\n");
|
wprintw(win, " /myid : Print your Tox ID\n");
|
||||||
|
#ifdef QRCODE
|
||||||
#ifdef QRPNG
|
#ifdef QRPNG
|
||||||
wprintw(win, " /myqr <txt> or <png> : Print your Tox ID's QR code to a file.\n");
|
wprintw(win, " /myqr <txt> or <png> : Print your Tox ID's QR code to a file.\n");
|
||||||
#else
|
#else
|
||||||
wprintw(win, " /myqr : Print your Tox ID's QR code to a file.\n");
|
wprintw(win, " /myqr : Print your Tox ID's QR code to a file.\n");
|
||||||
#endif /* QRPNG */
|
#endif /* QRPNG */
|
||||||
|
#endif /* QRCODE */
|
||||||
wprintw(win, " /clear : Clear window history\n");
|
wprintw(win, " /clear : Clear window history\n");
|
||||||
wprintw(win, " /close : Close the current chat window\n");
|
wprintw(win, " /close : Close the current chat window\n");
|
||||||
wprintw(win, " /quit or /exit : Exit Toxic\n");
|
wprintw(win, " /quit or /exit : Exit Toxic\n");
|
||||||
@ -320,7 +326,7 @@ static void help_draw_plugin(ToxWindow *self)
|
|||||||
box(win, ACS_VLINE, ACS_HLINE);
|
box(win, ACS_VLINE, ACS_HLINE);
|
||||||
wnoutrefresh(win);
|
wnoutrefresh(win);
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* PYTHON */
|
||||||
|
|
||||||
static void help_draw_contacts(ToxWindow *self)
|
static void help_draw_contacts(ToxWindow *self)
|
||||||
{
|
{
|
||||||
@ -390,7 +396,7 @@ void help_onKey(ToxWindow *self, wint_t key)
|
|||||||
help_init_window(self, 4 + num_registered_handlers(), help_max_width());
|
help_init_window(self, 4 + num_registered_handlers(), help_max_width());
|
||||||
self->help->type = HELP_PLUGIN;
|
self->help->type = HELP_PLUGIN;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif /* PYTHON */
|
||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
help_init_window(self, 10, 80);
|
help_init_window(self, 10, 80);
|
||||||
|
@ -42,4 +42,4 @@ void help_onDraw(ToxWindow *self);
|
|||||||
void help_init_menu(ToxWindow *self);
|
void help_init_menu(ToxWindow *self);
|
||||||
void help_onKey(ToxWindow *self, wint_t key);
|
void help_onKey(ToxWindow *self, wint_t key);
|
||||||
|
|
||||||
#endif /* #define HELP_H */
|
#endif /* HELP_H */
|
||||||
|
31
src/input.c
31
src/input.c
@ -43,8 +43,9 @@ void input_new_char(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_
|
|||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
/* this is the only place we need to do this check */
|
/* this is the only place we need to do this check */
|
||||||
if (key == '\n')
|
if (key == '\n') {
|
||||||
key = L'¶';
|
key = L'¶';
|
||||||
|
}
|
||||||
|
|
||||||
int cur_len = wcwidth(key);
|
int cur_len = wcwidth(key);
|
||||||
|
|
||||||
@ -77,18 +78,20 @@ static void input_backspace(ToxWindow *self, int x, int mx_x)
|
|||||||
int cur_len = ctx->pos > 0 ? wcwidth(ctx->line[ctx->pos - 1]) : 0;
|
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;
|
int s_len = ctx->start > 0 ? wcwidth(ctx->line[ctx->start - 1]) : 0;
|
||||||
|
|
||||||
if (ctx->start && (x >= mx_x - cur_len))
|
if (ctx->start && (x >= mx_x - cur_len)) {
|
||||||
ctx->start = MAX(0, ctx->start - 1 + (s_len - cur_len));
|
ctx->start = MAX(0, ctx->start - 1 + (s_len - cur_len));
|
||||||
else if (ctx->start)
|
} else if (ctx->start) {
|
||||||
ctx->start = MAX(0, ctx->start - cur_len);
|
ctx->start = MAX(0, ctx->start - cur_len);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* delete a char via delete key from input field and buffer */
|
/* delete a char via delete key from input field and buffer */
|
||||||
static void input_delete(ToxWindow *self)
|
static void input_delete(ToxWindow *self)
|
||||||
{
|
{
|
||||||
if (del_char_buf_frnt(self->chatwin) == -1)
|
if (del_char_buf_frnt(self->chatwin) == -1) {
|
||||||
sound_notify(self, notif_error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* delete last typed word */
|
/* delete last typed word */
|
||||||
static void input_del_word(ToxWindow *self, int x, int mx_x)
|
static void input_del_word(ToxWindow *self, int x, int mx_x)
|
||||||
@ -104,16 +107,18 @@ static void input_del_word(ToxWindow *self, int x, int mx_x)
|
|||||||
/* deletes entire line before cursor from input field and buffer */
|
/* deletes entire line before cursor from input field and buffer */
|
||||||
static void input_discard(ToxWindow *self)
|
static void input_discard(ToxWindow *self)
|
||||||
{
|
{
|
||||||
if (discard_buf(self->chatwin) == -1)
|
if (discard_buf(self->chatwin) == -1) {
|
||||||
sound_notify(self, notif_error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* deletes entire line after cursor from input field and buffer */
|
/* deletes entire line after cursor from input field and buffer */
|
||||||
static void input_kill(ChatContext *ctx)
|
static void input_kill(ChatContext *ctx)
|
||||||
{
|
{
|
||||||
if (kill_buf(ctx) == -1)
|
if (kill_buf(ctx) == -1) {
|
||||||
sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
|
sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void input_yank(ToxWindow *self, int x, int mx_x)
|
static void input_yank(ToxWindow *self, int x, int mx_x)
|
||||||
{
|
{
|
||||||
@ -149,8 +154,9 @@ static void input_mv_home(ToxWindow *self)
|
|||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
if (ctx->pos <= 0)
|
if (ctx->pos <= 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ctx->pos = 0;
|
ctx->pos = 0;
|
||||||
ctx->start = 0;
|
ctx->start = 0;
|
||||||
@ -161,27 +167,30 @@ static void input_mv_left(ToxWindow *self, int x, int mx_x)
|
|||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
if (ctx->pos <= 0)
|
if (ctx->pos <= 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int cur_len = ctx->pos > 0 ? wcwidth(ctx->line[ctx->pos - 1]) : 0;
|
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;
|
int s_len = ctx->start > 0 ? wcwidth(ctx->line[ctx->start - 1]) : 0;
|
||||||
|
|
||||||
--ctx->pos;
|
--ctx->pos;
|
||||||
|
|
||||||
if (ctx->start && (x >= mx_x - cur_len))
|
if (ctx->start && (x >= mx_x - cur_len)) {
|
||||||
ctx->start = MAX(0, ctx->start - 1 + (s_len - cur_len));
|
ctx->start = MAX(0, ctx->start - 1 + (s_len - cur_len));
|
||||||
else if (ctx->start)
|
} else if (ctx->start) {
|
||||||
ctx->start = MAX(0, ctx->start - cur_len);
|
ctx->start = MAX(0, ctx->start - cur_len);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* moves cursor/line position right in input field and buffer */
|
/* moves cursor/line position right in input field and buffer */
|
||||||
static void input_mv_right(ToxWindow *self, int x, int mx_x)
|
static void input_mv_right(ToxWindow *self, int x, int mx_x)
|
||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
if (ctx->pos >= ctx->len)
|
if (ctx->pos >= ctx->len) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
++ctx->pos;
|
++ctx->pos;
|
||||||
|
|
||||||
|
@ -30,4 +30,4 @@ void input_new_char(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_
|
|||||||
return true if key matches a function, false otherwise */
|
return true if key matches a function, false otherwise */
|
||||||
bool input_handle(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y);
|
bool input_handle(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y);
|
||||||
|
|
||||||
#endif /* #define INPUT_H */
|
#endif /* INPUT_H */
|
||||||
|
105
src/line_info.c
105
src/line_info.c
@ -40,8 +40,9 @@ void line_info_init(struct history *hst)
|
|||||||
{
|
{
|
||||||
hst->line_root = calloc(1, sizeof(struct line_info));
|
hst->line_root = calloc(1, sizeof(struct line_info));
|
||||||
|
|
||||||
if (hst->line_root == NULL)
|
if (hst->line_root == NULL) {
|
||||||
exit_toxic_err("failed in line_info_init", FATALERR_MEMORY);
|
exit_toxic_err("failed in line_info_init", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
hst->line_start = hst->line_root;
|
hst->line_start = hst->line_root;
|
||||||
hst->line_end = hst->line_start;
|
hst->line_end = hst->line_start;
|
||||||
@ -53,8 +54,9 @@ void line_info_reset_start(ToxWindow *self, struct history *hst)
|
|||||||
{
|
{
|
||||||
struct line_info *line = hst->line_end;
|
struct line_info *line = hst->line_end;
|
||||||
|
|
||||||
if (line->prev == NULL)
|
if (line->prev == NULL) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int y2, x2;
|
int y2, x2;
|
||||||
getmaxyx(self->window, y2, x2);
|
getmaxyx(self->window, y2, x2);
|
||||||
@ -88,9 +90,10 @@ void line_info_cleanup(struct history *hst)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < hst->queue_sz; ++i) {
|
for (i = 0; i < hst->queue_sz; ++i) {
|
||||||
if (hst->queue[i])
|
if (hst->queue[i]) {
|
||||||
free(hst->queue[i]);
|
free(hst->queue[i]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
free(hst);
|
free(hst);
|
||||||
}
|
}
|
||||||
@ -114,15 +117,17 @@ static void line_info_root_fwd(struct history *hst)
|
|||||||
/* returns ptr to queue item 0 and removes it from queue. Returns NULL if queue is empty. */
|
/* returns ptr to queue item 0 and removes it from queue. Returns NULL if queue is empty. */
|
||||||
static struct line_info *line_info_ret_queue(struct history *hst)
|
static struct line_info *line_info_ret_queue(struct history *hst)
|
||||||
{
|
{
|
||||||
if (hst->queue_sz <= 0)
|
if (hst->queue_sz <= 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
struct line_info *line = hst->queue[0];
|
struct line_info *line = hst->queue[0];
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < hst->queue_sz; ++i)
|
for (i = 0; i < hst->queue_sz; ++i) {
|
||||||
hst->queue[i] = hst->queue[i + 1];
|
hst->queue[i] = hst->queue[i + 1];
|
||||||
|
}
|
||||||
|
|
||||||
--hst->queue_sz;
|
--hst->queue_sz;
|
||||||
|
|
||||||
@ -137,18 +142,21 @@ static struct line_info *line_info_ret_queue(struct history *hst)
|
|||||||
int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const char *name2, uint8_t type,
|
int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const char *name2, uint8_t type,
|
||||||
uint8_t bold, uint8_t colour, const char *msg, ...)
|
uint8_t bold, uint8_t colour, const char *msg, ...)
|
||||||
{
|
{
|
||||||
if (!self)
|
if (!self) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
struct history *hst = self->chatwin->hst;
|
struct history *hst = self->chatwin->hst;
|
||||||
|
|
||||||
if (hst->queue_sz >= MAX_LINE_INFO_QUEUE)
|
if (hst->queue_sz >= MAX_LINE_INFO_QUEUE) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
struct line_info *new_line = calloc(1, sizeof(struct line_info));
|
struct line_info *new_line = calloc(1, sizeof(struct line_info));
|
||||||
|
|
||||||
if (new_line == NULL)
|
if (new_line == NULL) {
|
||||||
exit_toxic_err("failed in line_info_add", FATALERR_MEMORY);
|
exit_toxic_err("failed in line_info_add", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
char frmt_msg[MAX_LINE_INFO_MSG_SIZE] = {0};
|
char frmt_msg[MAX_LINE_INFO_MSG_SIZE] = {0};
|
||||||
|
|
||||||
@ -206,10 +214,11 @@ int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; frmt_msg[i]; ++i) {
|
for (i = 0; frmt_msg[i]; ++i) {
|
||||||
if (frmt_msg[i] == '\n')
|
if (frmt_msg[i] == '\n') {
|
||||||
++new_line->newlines;
|
++new_line->newlines;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (timestr) {
|
if (timestr) {
|
||||||
snprintf(new_line->timestr, sizeof(new_line->timestr), "%s", timestr);
|
snprintf(new_line->timestr, sizeof(new_line->timestr), "%s", timestr);
|
||||||
@ -245,11 +254,13 @@ static void line_info_check_queue(ToxWindow *self)
|
|||||||
struct history *hst = self->chatwin->hst;
|
struct history *hst = self->chatwin->hst;
|
||||||
struct line_info *line = line_info_ret_queue(hst);
|
struct line_info *line = line_info_ret_queue(hst);
|
||||||
|
|
||||||
if (line == NULL)
|
if (line == NULL) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (hst->start_id > user_settings->history_size)
|
if (hst->start_id > user_settings->history_size) {
|
||||||
line_info_root_fwd(hst);
|
line_info_root_fwd(hst);
|
||||||
|
}
|
||||||
|
|
||||||
line->prev = hst->line_end;
|
line->prev = hst->line_end;
|
||||||
hst->line_end->next = line;
|
hst->line_end->next = line;
|
||||||
@ -261,8 +272,9 @@ static void line_info_check_queue(ToxWindow *self)
|
|||||||
getyx(self->chatwin->history, y, x);
|
getyx(self->chatwin->history, y, x);
|
||||||
(void) x;
|
(void) x;
|
||||||
|
|
||||||
if (x2 <= SIDEBAR_WIDTH)
|
if (x2 <= SIDEBAR_WIDTH) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int offst = self->show_peerlist ? SIDEBAR_WIDTH : 0; /* offset width of groupchat sidebar */
|
int offst = self->show_peerlist ? SIDEBAR_WIDTH : 0; /* offset width of groupchat sidebar */
|
||||||
int lines = 1 + line->newlines + (line->len / (x2 - offst));
|
int lines = 1 + line->newlines + (line->len / (x2 - offst));
|
||||||
@ -284,8 +296,9 @@ void line_info_print(ToxWindow *self)
|
|||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
if (ctx == NULL)
|
if (ctx == NULL) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
struct history *hst = ctx->hst;
|
struct history *hst = ctx->hst;
|
||||||
|
|
||||||
@ -293,19 +306,25 @@ void line_info_print(ToxWindow *self)
|
|||||||
line_info_check_queue(self);
|
line_info_check_queue(self);
|
||||||
|
|
||||||
WINDOW *win = ctx->history;
|
WINDOW *win = ctx->history;
|
||||||
|
|
||||||
wclear(win);
|
wclear(win);
|
||||||
|
|
||||||
int y2, x2;
|
int y2, x2;
|
||||||
|
|
||||||
getmaxyx(self->window, y2, x2);
|
getmaxyx(self->window, y2, x2);
|
||||||
|
|
||||||
if (x2 <= SIDEBAR_WIDTH)
|
if (x2 <= SIDEBAR_WIDTH) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (self->is_groupchat)
|
if (self->is_groupchat) {
|
||||||
wmove(win, 0, 0);
|
wmove(win, 0, 0);
|
||||||
else
|
} else {
|
||||||
wmove(win, 2, 0);
|
wmove(win, 2, 0);
|
||||||
|
}
|
||||||
|
|
||||||
struct line_info *line = hst->line_start->next;
|
struct line_info *line = hst->line_start->next;
|
||||||
|
|
||||||
int numlines = 0;
|
int numlines = 0;
|
||||||
|
|
||||||
while (line && numlines++ <= y2) {
|
while (line && numlines++ <= y2) {
|
||||||
@ -325,10 +344,11 @@ void line_info_print(ToxWindow *self)
|
|||||||
|
|
||||||
int nameclr = GREEN;
|
int nameclr = GREEN;
|
||||||
|
|
||||||
if (line->colour)
|
if (line->colour) {
|
||||||
nameclr = line->colour;
|
nameclr = line->colour;
|
||||||
else if (type == IN_MSG)
|
} else if (type == IN_MSG) {
|
||||||
nameclr = CYAN;
|
nameclr = CYAN;
|
||||||
|
}
|
||||||
|
|
||||||
wattron(win, COLOR_PAIR(nameclr));
|
wattron(win, COLOR_PAIR(nameclr));
|
||||||
wprintw(win, "%s %s: ", user_settings->line_normal, line->name1);
|
wprintw(win, "%s %s: ", user_settings->line_normal, line->name1);
|
||||||
@ -339,22 +359,25 @@ void line_info_print(ToxWindow *self)
|
|||||||
while (msg) {
|
while (msg) {
|
||||||
char *line = strsep(&msg, "\n");
|
char *line = strsep(&msg, "\n");
|
||||||
|
|
||||||
if (line[0] == '>')
|
if (line[0] == '>') {
|
||||||
wattron(win, COLOR_PAIR(GREEN));
|
wattron(win, COLOR_PAIR(GREEN));
|
||||||
else if (line[0] == '<')
|
} else if (line[0] == '<') {
|
||||||
wattron(win, COLOR_PAIR(RED));
|
wattron(win, COLOR_PAIR(RED));
|
||||||
|
}
|
||||||
|
|
||||||
wprintw(win, "%s%c", line, msg ? '\n' : '\0');
|
wprintw(win, "%s%c", line, msg ? '\n' : '\0');
|
||||||
|
|
||||||
if (line[0] == '>')
|
if (line[0] == '>') {
|
||||||
wattroff(win, COLOR_PAIR(GREEN));
|
wattroff(win, COLOR_PAIR(GREEN));
|
||||||
else if (line[0] == '<')
|
} else if (line[0] == '<') {
|
||||||
wattroff(win, COLOR_PAIR(RED));
|
wattroff(win, COLOR_PAIR(RED));
|
||||||
|
}
|
||||||
|
|
||||||
// change the \0 set by strsep back to \n
|
// change the \0 set by strsep back to \n
|
||||||
if (msg)
|
if (msg) {
|
||||||
msg[-1] = '\n';
|
msg[-1] = '\n';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (type == OUT_MSG && timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
|
if (type == OUT_MSG && timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
|
||||||
wattron(win, COLOR_PAIR(RED));
|
wattron(win, COLOR_PAIR(RED));
|
||||||
@ -406,19 +429,23 @@ void line_info_print(ToxWindow *self)
|
|||||||
wattroff(win, COLOR_PAIR(BLUE));
|
wattroff(win, COLOR_PAIR(BLUE));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (line->bold)
|
if (line->bold) {
|
||||||
wattron(win, A_BOLD);
|
wattron(win, A_BOLD);
|
||||||
|
}
|
||||||
|
|
||||||
if (line->colour)
|
if (line->colour) {
|
||||||
wattron(win, COLOR_PAIR(line->colour));
|
wattron(win, COLOR_PAIR(line->colour));
|
||||||
|
}
|
||||||
|
|
||||||
wprintw(win, "%s\n", line->msg);
|
wprintw(win, "%s\n", line->msg);
|
||||||
|
|
||||||
if (line->bold)
|
if (line->bold) {
|
||||||
wattroff(win, A_BOLD);
|
wattroff(win, A_BOLD);
|
||||||
|
}
|
||||||
|
|
||||||
if (line->colour)
|
if (line->colour) {
|
||||||
wattroff(win, COLOR_PAIR(line->colour));
|
wattroff(win, COLOR_PAIR(line->colour));
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -427,8 +454,9 @@ void line_info_print(ToxWindow *self)
|
|||||||
wprintw(win, "$ ");
|
wprintw(win, "$ ");
|
||||||
wattroff(win, COLOR_PAIR(GREEN));
|
wattroff(win, COLOR_PAIR(GREEN));
|
||||||
|
|
||||||
if (line->msg[0])
|
if (line->msg[0]) {
|
||||||
wprintw(win, "%s", line->msg);
|
wprintw(win, "%s", line->msg);
|
||||||
|
}
|
||||||
|
|
||||||
wprintw(win, "\n");
|
wprintw(win, "\n");
|
||||||
break;
|
break;
|
||||||
@ -492,9 +520,10 @@ void line_info_print(ToxWindow *self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* keep calling until queue is empty */
|
/* keep calling until queue is empty */
|
||||||
if (hst->queue_sz > 0)
|
if (hst->queue_sz > 0) {
|
||||||
line_info_print(self);
|
line_info_print(self);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* puts msg in specified line_info msg buffer */
|
/* puts msg in specified line_info msg buffer */
|
||||||
void line_info_set(ToxWindow *self, uint32_t id, char *msg)
|
void line_info_set(ToxWindow *self, uint32_t id, char *msg)
|
||||||
@ -518,16 +547,20 @@ void line_info_set(ToxWindow *self, uint32_t id, char *msg)
|
|||||||
|
|
||||||
static void line_info_scroll_up(struct history *hst)
|
static void line_info_scroll_up(struct history *hst)
|
||||||
{
|
{
|
||||||
if (hst->line_start->prev)
|
if (hst->line_start->prev) {
|
||||||
hst->line_start = hst->line_start->prev;
|
hst->line_start = hst->line_start->prev;
|
||||||
else sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
|
} else {
|
||||||
|
sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void line_info_scroll_down(struct history *hst)
|
static void line_info_scroll_down(struct history *hst)
|
||||||
{
|
{
|
||||||
if (hst->line_start->next)
|
if (hst->line_start->next) {
|
||||||
hst->line_start = hst->line_start->next;
|
hst->line_start = hst->line_start->next;
|
||||||
else sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
|
} else {
|
||||||
|
sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void line_info_page_up(ToxWindow *self, struct history *hst)
|
static void line_info_page_up(ToxWindow *self, struct history *hst)
|
||||||
@ -538,9 +571,10 @@ static void line_info_page_up(ToxWindow *self, struct history *hst)
|
|||||||
int jump_dist = y2 / 2;
|
int jump_dist = y2 / 2;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < jump_dist && hst->line_start->prev; ++i)
|
for (i = 0; i < jump_dist && hst->line_start->prev; ++i) {
|
||||||
hst->line_start = hst->line_start->prev;
|
hst->line_start = hst->line_start->prev;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void line_info_page_down(ToxWindow *self, struct history *hst)
|
static void line_info_page_down(ToxWindow *self, struct history *hst)
|
||||||
{
|
{
|
||||||
@ -550,9 +584,10 @@ static void line_info_page_down(ToxWindow *self, struct history *hst)
|
|||||||
int jump_dist = y2 / 2;
|
int jump_dist = y2 / 2;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < jump_dist && hst->line_start->next; ++i)
|
for (i = 0; i < jump_dist && hst->line_start->next; ++i) {
|
||||||
hst->line_start = hst->line_start->next;
|
hst->line_start = hst->line_start->next;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool line_info_onKey(ToxWindow *self, wint_t key)
|
bool line_info_onKey(ToxWindow *self, wint_t key)
|
||||||
{
|
{
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
#define MAX_LINE_INFO_QUEUE 1024
|
#define MAX_LINE_INFO_QUEUE 1024
|
||||||
#define MAX_LINE_INFO_MSG_SIZE MAX_STR_SIZE + TOXIC_MAX_NAME_LENGTH + 32 /* needs extra room for log loading */
|
#define MAX_LINE_INFO_MSG_SIZE MAX_STR_SIZE + TOXIC_MAX_NAME_LENGTH + 32 /* needs extra room for log loading */
|
||||||
|
|
||||||
enum {
|
typedef enum {
|
||||||
SYS_MSG,
|
SYS_MSG,
|
||||||
IN_MSG,
|
IN_MSG,
|
||||||
OUT_MSG,
|
OUT_MSG,
|
||||||
@ -100,4 +100,4 @@ void line_info_reset_start(ToxWindow *self, struct history *hst);
|
|||||||
void line_info_init(struct history *hst);
|
void line_info_init(struct history *hst);
|
||||||
bool line_info_onKey(ToxWindow *self, wint_t key); /* returns true if key is a match */
|
bool line_info_onKey(ToxWindow *self, wint_t key); /* returns true if key is a match */
|
||||||
|
|
||||||
#endif /* #define LINE_INFO_H */
|
#endif /* LINE_INFO_H */
|
||||||
|
64
src/log.c
64
src/log.c
@ -45,8 +45,9 @@ extern struct user_settings *user_settings;
|
|||||||
Returns 0 on success, -1 if the path is too long */
|
Returns 0 on success, -1 if the path is too long */
|
||||||
static int get_log_path(char *dest, int destsize, char *name, const char *selfkey, const char *otherkey, int logtype)
|
static int get_log_path(char *dest, int destsize, char *name, const char *selfkey, const char *otherkey, int logtype)
|
||||||
{
|
{
|
||||||
if (!valid_nick(name))
|
if (!valid_nick(name)) {
|
||||||
name = UNKNOWN_NAME;
|
name = UNKNOWN_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
const char *namedash = logtype == LOG_PROMPT ? "" : "-";
|
const char *namedash = logtype == LOG_PROMPT ? "" : "-";
|
||||||
const char *set_path = user_settings->chatlogs_path;
|
const char *set_path = user_settings->chatlogs_path;
|
||||||
@ -85,10 +86,11 @@ static int get_log_path(char *dest, int destsize, char *name, const char *selfke
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string_is_empty(set_path))
|
if (!string_is_empty(set_path)) {
|
||||||
snprintf(dest, destsize, "%s%s-%s%s%s.log", set_path, self_id, name, namedash, other_id);
|
snprintf(dest, destsize, "%s%s-%s%s%s.log", set_path, self_id, name, namedash, other_id);
|
||||||
else
|
} else {
|
||||||
snprintf(dest, destsize, "%s%s%s-%s%s%s.log", user_config_dir, LOGDIR, self_id, name, namedash, other_id);
|
snprintf(dest, destsize, "%s%s%s-%s%s%s.log", user_config_dir, LOGDIR, self_id, name, namedash, other_id);
|
||||||
|
}
|
||||||
|
|
||||||
free(user_config_dir);
|
free(user_config_dir);
|
||||||
|
|
||||||
@ -98,19 +100,22 @@ static int get_log_path(char *dest, int destsize, char *name, const char *selfke
|
|||||||
/* Opens log file or creates a new one */
|
/* Opens log file or creates a new one */
|
||||||
static int init_logging_session(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype)
|
static int init_logging_session(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype)
|
||||||
{
|
{
|
||||||
if (selfkey == NULL || (logtype == LOG_CHAT && otherkey == NULL))
|
if (selfkey == NULL || (logtype == LOG_CHAT && otherkey == NULL)) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
char log_path[MAX_STR_SIZE];
|
char log_path[MAX_STR_SIZE];
|
||||||
|
|
||||||
if (get_log_path(log_path, sizeof(log_path), name, selfkey, otherkey, logtype) == -1)
|
if (get_log_path(log_path, sizeof(log_path), name, selfkey, otherkey, logtype) == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
log->file = fopen(log_path, "a+");
|
log->file = fopen(log_path, "a+");
|
||||||
snprintf(log->path, sizeof(log->path), "%s", log_path);
|
snprintf(log->path, sizeof(log->path), "%s", log_path);
|
||||||
|
|
||||||
if (log->file == NULL)
|
if (log->file == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -119,8 +124,9 @@ static int init_logging_session(char *name, const char *selfkey, const char *oth
|
|||||||
|
|
||||||
void write_to_log(const char *msg, const char *name, struct chatlog *log, bool event)
|
void write_to_log(const char *msg, const char *name, struct chatlog *log, bool event)
|
||||||
{
|
{
|
||||||
if (!log->log_on)
|
if (!log->log_on) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (log->file == NULL) {
|
if (log->file == NULL) {
|
||||||
log->log_on = false;
|
log->log_on = false;
|
||||||
@ -129,10 +135,11 @@ void write_to_log(const char *msg, const char *name, struct chatlog *log, bool e
|
|||||||
|
|
||||||
char name_frmt[TOXIC_MAX_NAME_LENGTH + 3];
|
char name_frmt[TOXIC_MAX_NAME_LENGTH + 3];
|
||||||
|
|
||||||
if (event)
|
if (event) {
|
||||||
snprintf(name_frmt, sizeof(name_frmt), "* %s", name);
|
snprintf(name_frmt, sizeof(name_frmt), "* %s", name);
|
||||||
else
|
} else {
|
||||||
snprintf(name_frmt, sizeof(name_frmt), "%s:", name);
|
snprintf(name_frmt, sizeof(name_frmt), "%s:", name);
|
||||||
|
}
|
||||||
|
|
||||||
const char *t = user_settings->log_timestamp_format;
|
const char *t = user_settings->log_timestamp_format;
|
||||||
char s[MAX_STR_SIZE];
|
char s[MAX_STR_SIZE];
|
||||||
@ -147,8 +154,9 @@ void write_to_log(const char *msg, const char *name, struct chatlog *log, bool e
|
|||||||
|
|
||||||
void log_disable(struct chatlog *log)
|
void log_disable(struct chatlog *log)
|
||||||
{
|
{
|
||||||
if (log->file != NULL)
|
if (log->file != NULL) {
|
||||||
fclose(log->file);
|
fclose(log->file);
|
||||||
|
}
|
||||||
|
|
||||||
memset(log, 0, sizeof(struct chatlog));
|
memset(log, 0, sizeof(struct chatlog));
|
||||||
}
|
}
|
||||||
@ -157,8 +165,9 @@ int log_enable(char *name, const char *selfkey, const char *otherkey, struct cha
|
|||||||
{
|
{
|
||||||
log->log_on = true;
|
log->log_on = true;
|
||||||
|
|
||||||
if (log->file != NULL)
|
if (log->file != NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (init_logging_session(name, selfkey, otherkey, log, logtype) == -1) {
|
if (init_logging_session(name, selfkey, otherkey, log, logtype) == -1) {
|
||||||
log_disable(log);
|
log_disable(log);
|
||||||
@ -171,18 +180,21 @@ int log_enable(char *name, const char *selfkey, const char *otherkey, struct cha
|
|||||||
/* Loads previous history from chat log */
|
/* Loads previous history from chat log */
|
||||||
void load_chat_history(ToxWindow *self, struct chatlog *log)
|
void load_chat_history(ToxWindow *self, struct chatlog *log)
|
||||||
{
|
{
|
||||||
if (log->file == NULL)
|
if (log->file == NULL) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
off_t sz = file_size(log->path);
|
off_t sz = file_size(log->path);
|
||||||
|
|
||||||
if (sz <= 0)
|
if (sz <= 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
char *hstbuf = malloc(sz + 1);
|
char *hstbuf = malloc(sz + 1);
|
||||||
|
|
||||||
if (hstbuf == NULL)
|
if (hstbuf == NULL) {
|
||||||
exit_toxic_err("failed in load_chat_history", FATALERR_MEMORY);
|
exit_toxic_err("failed in load_chat_history", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
if (fseek(log->file, 0L, SEEK_SET) == -1) {
|
if (fseek(log->file, 0L, SEEK_SET) == -1) {
|
||||||
free(hstbuf);
|
free(hstbuf);
|
||||||
@ -204,9 +216,10 @@ void load_chat_history(ToxWindow *self, struct chatlog *log)
|
|||||||
|
|
||||||
/* start at end and backtrace L lines or to the beginning of buffer */
|
/* start at end and backtrace L lines or to the beginning of buffer */
|
||||||
for (start = sz - 1; start >= 0 && count < L; --start) {
|
for (start = sz - 1; start >= 0 && count < L; --start) {
|
||||||
if (hstbuf[start] == '\n')
|
if (hstbuf[start] == '\n') {
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const char *line = strtok(&hstbuf[start + 1], "\n");
|
const char *line = strtok(&hstbuf[start + 1], "\n");
|
||||||
|
|
||||||
@ -238,33 +251,40 @@ int rename_logfile(char *src, char *dest, const char *selfkey, const char *other
|
|||||||
log_on = log->log_on;
|
log_on = log->log_on;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (log_on)
|
if (log_on) {
|
||||||
log_disable(log);
|
log_disable(log);
|
||||||
|
}
|
||||||
|
|
||||||
char newpath[MAX_STR_SIZE];
|
char newpath[MAX_STR_SIZE];
|
||||||
char oldpath[MAX_STR_SIZE];
|
char oldpath[MAX_STR_SIZE];
|
||||||
|
|
||||||
if (get_log_path(oldpath, sizeof(oldpath), src, selfkey, otherkey, LOG_CHAT) == -1)
|
if (get_log_path(oldpath, sizeof(oldpath), src, selfkey, otherkey, LOG_CHAT) == -1) {
|
||||||
goto on_error;
|
goto on_error;
|
||||||
|
}
|
||||||
|
|
||||||
if (!file_exists(oldpath))
|
if (!file_exists(oldpath)) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (get_log_path(newpath, sizeof(newpath), dest, selfkey, otherkey, LOG_CHAT) == -1)
|
if (get_log_path(newpath, sizeof(newpath), dest, selfkey, otherkey, LOG_CHAT) == -1) {
|
||||||
goto on_error;
|
goto on_error;
|
||||||
|
}
|
||||||
|
|
||||||
if (rename(oldpath, newpath) != 0)
|
if (rename(oldpath, newpath) != 0) {
|
||||||
goto on_error;
|
goto on_error;
|
||||||
|
}
|
||||||
|
|
||||||
if (log_on)
|
if (log_on) {
|
||||||
log_enable(dest, selfkey, otherkey, log, LOG_CHAT);
|
log_enable(dest, selfkey, otherkey, log, LOG_CHAT);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
on_error:
|
on_error:
|
||||||
|
|
||||||
if (log_on)
|
if (log_on) {
|
||||||
log_enable(src, selfkey, otherkey, log, LOG_CHAT);
|
log_enable(src, selfkey, otherkey, log, LOG_CHAT);
|
||||||
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ struct chatlog {
|
|||||||
bool log_on; /* specific to current chat window */
|
bool log_on; /* specific to current chat window */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
typedef enum {
|
||||||
LOG_GROUP,
|
LOG_GROUP,
|
||||||
LOG_PROMPT,
|
LOG_PROMPT,
|
||||||
LOG_CHAT,
|
LOG_CHAT,
|
||||||
@ -56,4 +56,4 @@ void load_chat_history(ToxWindow *self, struct chatlog *log);
|
|||||||
Returns 0 on success or if no log exists, -1 on failure. */
|
Returns 0 on success or if no log exists, -1 on failure. */
|
||||||
int rename_logfile(char *src, char *dest, const char *selfkey, const char *otherkey, int winnum);
|
int rename_logfile(char *src, char *dest, const char *selfkey, const char *otherkey, int winnum);
|
||||||
|
|
||||||
#endif /* #define LOG_H */
|
#endif /* LOG_H */
|
||||||
|
@ -50,8 +50,9 @@ void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type,
|
|||||||
|
|
||||||
struct cqueue_msg *new_m = malloc(sizeof(struct cqueue_msg));
|
struct cqueue_msg *new_m = malloc(sizeof(struct cqueue_msg));
|
||||||
|
|
||||||
if (new_m == NULL)
|
if (new_m == NULL) {
|
||||||
exit_toxic_err("failed in cqueue_message", FATALERR_MEMORY);
|
exit_toxic_err("failed in cqueue_message", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(new_m->message, sizeof(new_m->message), "%s", msg);
|
snprintf(new_m->message, sizeof(new_m->message), "%s", msg);
|
||||||
new_m->len = len;
|
new_m->len = len;
|
||||||
@ -118,8 +119,9 @@ void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt)
|
|||||||
struct cqueue_msg *next = msg->next;
|
struct cqueue_msg *next = msg->next;
|
||||||
|
|
||||||
if (msg->prev == NULL) { /* root */
|
if (msg->prev == NULL) { /* root */
|
||||||
if (next)
|
if (next) {
|
||||||
next->prev = NULL;
|
next->prev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
free(msg);
|
free(msg);
|
||||||
q->root = next;
|
q->root = next;
|
||||||
@ -133,7 +135,7 @@ void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CQUEUE_TRY_SEND_INTERVAL 60
|
#define CQUEUE_TRY_SEND_INTERVAL 10
|
||||||
|
|
||||||
/* Tries to send the oldest unsent message in queue. */
|
/* Tries to send the oldest unsent message in queue. */
|
||||||
void cqueue_try_send(ToxWindow *self, Tox *m)
|
void cqueue_try_send(ToxWindow *self, Tox *m)
|
||||||
@ -141,18 +143,15 @@ void cqueue_try_send(ToxWindow *self, Tox *m)
|
|||||||
struct chat_queue *q = self->chatwin->cqueue;
|
struct chat_queue *q = self->chatwin->cqueue;
|
||||||
struct cqueue_msg *msg = q->root;
|
struct cqueue_msg *msg = q->root;
|
||||||
|
|
||||||
if (!msg)
|
if (!msg) {
|
||||||
return;
|
|
||||||
|
|
||||||
if (msg->receipt != 0 && !timed_out(msg->last_send_try, CQUEUE_TRY_SEND_INTERVAL))
|
|
||||||
return;
|
|
||||||
|
|
||||||
uint32_t receipt = 0;
|
|
||||||
|
|
||||||
TOX_MESSAGE_TYPE type = msg->type == OUT_MSG ? TOX_MESSAGE_TYPE_NORMAL : TOX_MESSAGE_TYPE_ACTION;
|
|
||||||
receipt = tox_friend_send_message(m, self->num, type, (uint8_t *) msg->message, msg->len, NULL);
|
|
||||||
|
|
||||||
msg->last_send_try = get_unix_time();
|
|
||||||
msg->receipt = receipt;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (msg->receipt != 0 && !timed_out(msg->last_send_try, CQUEUE_TRY_SEND_INTERVAL)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tox_Message_Type type = msg->type == OUT_MSG ? TOX_MESSAGE_TYPE_NORMAL : TOX_MESSAGE_TYPE_ACTION;
|
||||||
|
msg->receipt = tox_friend_send_message(m, self->num, type, (uint8_t *) msg->message, msg->len, NULL);
|
||||||
|
msg->last_send_try = get_unix_time();
|
||||||
|
}
|
||||||
|
@ -48,4 +48,4 @@ void cqueue_try_send(ToxWindow *self, Tox *m);
|
|||||||
/* removes message with matching receipt from queue, writes to log and updates line to show the message was received. */
|
/* removes message with matching receipt from queue, writes to log and updates line to show the message was received. */
|
||||||
void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt);
|
void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt);
|
||||||
|
|
||||||
#endif /* #define MESSAGE_QUEUE_H */
|
#endif /* MESSAGE_QUEUE_H */
|
||||||
|
129
src/misc_tools.c
129
src/misc_tools.c
@ -26,10 +26,8 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#if SYSTEM == BSD
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#endif /* BSD! */
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
@ -86,26 +84,31 @@ void get_time_str(char *buf, int bufsize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char *t = user_settings->timestamp_format;
|
const char *t = user_settings->timestamp_format;
|
||||||
strftime(buf, bufsize, t, get_time());
|
|
||||||
|
if (strftime(buf, bufsize, t, get_time()) == 0) {
|
||||||
|
strftime(buf, bufsize, TIMESTAMP_DEFAULT, get_time());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Converts seconds to string in format HH:mm:ss; truncates hours and minutes when necessary */
|
/* Converts seconds to string in format HH:mm:ss; truncates hours and minutes when necessary */
|
||||||
void get_elapsed_time_str(char *buf, int bufsize, time_t secs)
|
void get_elapsed_time_str(char *buf, int bufsize, time_t secs)
|
||||||
{
|
{
|
||||||
if (!secs)
|
if (!secs) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
long int seconds = secs % 60;
|
long int seconds = secs % 60;
|
||||||
long int minutes = (secs % 3600) / 60;
|
long int minutes = (secs % 3600) / 60;
|
||||||
long int hours = secs / 3600;
|
long int hours = secs / 3600;
|
||||||
|
|
||||||
if (!minutes && !hours)
|
if (!minutes && !hours) {
|
||||||
snprintf(buf, bufsize, "%.2ld", seconds);
|
snprintf(buf, bufsize, "%.2ld", seconds);
|
||||||
else if (!hours)
|
} else if (!hours) {
|
||||||
snprintf(buf, bufsize, "%ld:%.2ld", minutes, seconds);
|
snprintf(buf, bufsize, "%ld:%.2ld", minutes, seconds);
|
||||||
else
|
} else {
|
||||||
snprintf(buf, bufsize, "%ld:%.2ld:%.2ld", hours, minutes, seconds);
|
snprintf(buf, bufsize, "%ld:%.2ld:%.2ld", hours, minutes, seconds);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Converts a hexidecimal string of length hex_len to binary format and puts the result in output.
|
* Converts a hexidecimal string of length hex_len to binary format and puts the result in output.
|
||||||
@ -116,11 +119,12 @@ void get_elapsed_time_str(char *buf, int bufsize, time_t secs)
|
|||||||
*/
|
*/
|
||||||
int hex_string_to_bin(const char *hex_string, size_t hex_len, char *output, size_t output_size)
|
int hex_string_to_bin(const char *hex_string, size_t hex_len, char *output, size_t output_size)
|
||||||
{
|
{
|
||||||
if (output_size == 0 || hex_len != output_size * 2)
|
if (output_size == 0 || hex_len != output_size * 2) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < output_size; ++i) {
|
for (size_t i = 0; i < output_size; ++i) {
|
||||||
sscanf(hex_string, "%2hhx", &output[i]);
|
sscanf(hex_string, "%2hhx", (unsigned char *)&output[i]);
|
||||||
hex_string += 2;
|
hex_string += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,19 +133,21 @@ int hex_string_to_bin(const char *hex_string, size_t hex_len, char *output, size
|
|||||||
|
|
||||||
int hex_string_to_bytes(char *buf, int size, const char *keystr)
|
int hex_string_to_bytes(char *buf, int size, const char *keystr)
|
||||||
{
|
{
|
||||||
if (size % 2 != 0)
|
if (size % 2 != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int i, res;
|
int i, res;
|
||||||
const char *pos = keystr;
|
const char *pos = keystr;
|
||||||
|
|
||||||
for (i = 0; i < size; ++i) {
|
for (i = 0; i < size; ++i) {
|
||||||
res = sscanf(pos, "%2hhx", &buf[i]);
|
res = sscanf(pos, "%2hhx", (unsigned char *)&buf[i]);
|
||||||
pos += 2;
|
pos += 2;
|
||||||
|
|
||||||
if (res == EOF || res < 1)
|
if (res == EOF || res < 1) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -153,13 +159,15 @@ int hex_string_to_bytes(char *buf, int size, const char *keystr)
|
|||||||
*/
|
*/
|
||||||
int bin_id_to_string(const char *bin_id, size_t bin_id_size, char *output, size_t output_size)
|
int bin_id_to_string(const char *bin_id, size_t bin_id_size, char *output, size_t output_size)
|
||||||
{
|
{
|
||||||
if (bin_id_size != TOX_ADDRESS_SIZE || output_size < (TOX_ADDRESS_SIZE * 2 + 1))
|
if (bin_id_size != TOX_ADDRESS_SIZE || output_size < (TOX_ADDRESS_SIZE * 2 + 1)) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < TOX_ADDRESS_SIZE; ++i)
|
for (i = 0; i < TOX_ADDRESS_SIZE; ++i) {
|
||||||
snprintf(&output[i * 2], output_size - (i * 2), "%02X", bin_id[i] & 0xff);
|
snprintf(&output[i * 2], output_size - (i * 2), "%02X", bin_id[i] & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -167,8 +175,9 @@ int bin_id_to_string(const char *bin_id, size_t bin_id_size, char *output, size_
|
|||||||
/* Returns 1 if the string is empty, 0 otherwise */
|
/* Returns 1 if the string is empty, 0 otherwise */
|
||||||
int string_is_empty(const char *string)
|
int string_is_empty(const char *string)
|
||||||
{
|
{
|
||||||
if (!string)
|
if (!string) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return string[0] == '\0';
|
return string[0] == '\0';
|
||||||
}
|
}
|
||||||
@ -176,8 +185,9 @@ int string_is_empty(const char *string)
|
|||||||
/* Returns 1 if the string is empty, 0 otherwise */
|
/* Returns 1 if the string is empty, 0 otherwise */
|
||||||
int wstring_is_empty(const wchar_t *string)
|
int wstring_is_empty(const wchar_t *string)
|
||||||
{
|
{
|
||||||
if (!string)
|
if (!string) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return string[0] == L'\0';
|
return string[0] == L'\0';
|
||||||
}
|
}
|
||||||
@ -187,11 +197,13 @@ int mbs_to_wcs_buf(wchar_t *buf, const char *string, size_t n)
|
|||||||
{
|
{
|
||||||
size_t len = mbstowcs(NULL, string, 0) + 1;
|
size_t len = mbstowcs(NULL, string, 0) + 1;
|
||||||
|
|
||||||
if (n < len)
|
if (n < len) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if ((len = mbstowcs(buf, string, n)) == (size_t) - 1)
|
if ((len = mbstowcs(buf, string, n)) == (size_t) - 1) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
@ -201,11 +213,13 @@ int wcs_to_mbs_buf(char *buf, const wchar_t *string, size_t n)
|
|||||||
{
|
{
|
||||||
size_t len = wcstombs(NULL, string, 0) + 1;
|
size_t len = wcstombs(NULL, string, 0) + 1;
|
||||||
|
|
||||||
if (n < len)
|
if (n < len) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if ((len = wcstombs(buf, string, n)) == (size_t) - 1)
|
if ((len = wcstombs(buf, string, n)) == (size_t) - 1) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
@ -224,8 +238,9 @@ int qsort_strcasecmp_hlpr(const void *str1, const void *str2)
|
|||||||
- must not contain a newline or tab seqeunce */
|
- must not contain a newline or tab seqeunce */
|
||||||
int valid_nick(const char *nick)
|
int valid_nick(const char *nick)
|
||||||
{
|
{
|
||||||
if (!nick[0] || nick[0] == ' ')
|
if (!nick[0] || nick[0] == ' ') {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -237,8 +252,10 @@ int valid_nick(const char *nick)
|
|||||||
|| nick[i] == '\v'
|
|| nick[i] == '\v'
|
||||||
|| nick[i] == '\r')
|
|| nick[i] == '\r')
|
||||||
|
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -249,10 +266,11 @@ void filter_str(char *str, size_t len)
|
|||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < len; ++i) {
|
for (i = 0; i < len; ++i) {
|
||||||
if (str[i] == '\n' || str[i] == '\r' || str[i] == '\t' || str[i] == '\v' || str[i] == '\0')
|
if (str[i] == '\n' || str[i] == '\r' || str[i] == '\t' || str[i] == '\v' || str[i] == '\0') {
|
||||||
str[i] = ' ';
|
str[i] = ' ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* gets base file name from path or original file name if no path is supplied.
|
/* gets base file name from path or original file name if no path is supplied.
|
||||||
* Returns the file name length
|
* Returns the file name length
|
||||||
@ -262,23 +280,27 @@ size_t get_file_name(char *namebuf, size_t bufsize, const char *pathname)
|
|||||||
int len = strlen(pathname) - 1;
|
int len = strlen(pathname) - 1;
|
||||||
char *path = strdup(pathname);
|
char *path = strdup(pathname);
|
||||||
|
|
||||||
if (path == NULL)
|
if (path == NULL) {
|
||||||
exit_toxic_err("failed in get_file_name", FATALERR_MEMORY);
|
exit_toxic_err("failed in get_file_name", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
while (len >= 0 && pathname[len] == '/')
|
while (len >= 0 && pathname[len] == '/') {
|
||||||
path[len--] = '\0';
|
path[len--] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
char *finalname = strdup(path);
|
char *finalname = strdup(path);
|
||||||
|
|
||||||
if (finalname == NULL)
|
if (finalname == NULL) {
|
||||||
exit_toxic_err("failed in get_file_name", FATALERR_MEMORY);
|
exit_toxic_err("failed in get_file_name", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
const char *basenm = strrchr(path, '/');
|
const char *basenm = strrchr(path, '/');
|
||||||
|
|
||||||
if (basenm != NULL) {
|
if (basenm != NULL) {
|
||||||
if (basenm[1])
|
if (basenm[1]) {
|
||||||
strcpy(finalname, &basenm[1]);
|
strcpy(finalname, &basenm[1]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(namebuf, bufsize, "%s", finalname);
|
snprintf(namebuf, bufsize, "%s", finalname);
|
||||||
free(finalname);
|
free(finalname);
|
||||||
@ -294,13 +316,15 @@ size_t get_file_name(char *namebuf, size_t bufsize, const char *pathname)
|
|||||||
*/
|
*/
|
||||||
size_t get_base_dir(const char *path, size_t path_len, char *dir)
|
size_t get_base_dir(const char *path, size_t path_len, char *dir)
|
||||||
{
|
{
|
||||||
if (path_len == 0 || path == NULL)
|
if (path_len == 0 || path == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
size_t dir_len = char_rfind(path, '/', path_len);
|
size_t dir_len = char_rfind(path, '/', path_len);
|
||||||
|
|
||||||
if (dir_len != 0 && dir_len < path_len)
|
if (dir_len != 0 && dir_len < path_len) {
|
||||||
++dir_len; /* Leave trailing slash */
|
++dir_len; /* Leave trailing slash */
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(dir, path, dir_len);
|
memcpy(dir, path, dir_len);
|
||||||
dir[dir_len] = '\0';
|
dir[dir_len] = '\0';
|
||||||
@ -313,16 +337,17 @@ void str_to_lower(char *str)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; str[i]; ++i)
|
for (i = 0; str[i]; ++i) {
|
||||||
str[i] = tolower(str[i]);
|
str[i] = tolower(str[i]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* puts friendnum's nick in buf, truncating at TOXIC_MAX_NAME_LENGTH if necessary.
|
/* puts friendnum's nick in buf, truncating at TOXIC_MAX_NAME_LENGTH if necessary.
|
||||||
if toxcore API call fails, put UNKNOWN_NAME in buf
|
if toxcore API call fails, put UNKNOWN_NAME in buf
|
||||||
Returns nick len */
|
Returns nick len */
|
||||||
size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum)
|
size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum)
|
||||||
{
|
{
|
||||||
TOX_ERR_FRIEND_QUERY err;
|
Tox_Err_Friend_Query err;
|
||||||
size_t len = tox_friend_get_name_size(m, friendnum, &err);
|
size_t len = tox_friend_get_name_size(m, friendnum, &err);
|
||||||
|
|
||||||
if (err != TOX_ERR_FRIEND_QUERY_OK) {
|
if (err != TOX_ERR_FRIEND_QUERY_OK) {
|
||||||
@ -348,7 +373,7 @@ on_error:
|
|||||||
/* same as get_nick_truncate but for groupchats */
|
/* same as get_nick_truncate but for groupchats */
|
||||||
int get_group_nick_truncate(Tox *m, char *buf, uint32_t peernum, uint32_t groupnum)
|
int get_group_nick_truncate(Tox *m, char *buf, uint32_t peernum, uint32_t groupnum)
|
||||||
{
|
{
|
||||||
TOX_ERR_CONFERENCE_PEER_QUERY err;
|
Tox_Err_Conference_Peer_Query err;
|
||||||
size_t len = tox_conference_peer_get_name_size(m, groupnum, peernum, &err);
|
size_t len = tox_conference_peer_get_name_size(m, groupnum, peernum, &err);
|
||||||
|
|
||||||
if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
|
if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
|
||||||
@ -400,9 +425,10 @@ int char_find(int idx, const char *s, char ch)
|
|||||||
int i = idx;
|
int i = idx;
|
||||||
|
|
||||||
for (i = idx; s[i]; ++i) {
|
for (i = idx; s[i]; ++i) {
|
||||||
if (s[i] == ch)
|
if (s[i] == ch) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
@ -418,9 +444,10 @@ int char_rfind(const char *s, char ch, int len)
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
for (i = len; i > 0; --i) {
|
for (i = len; i > 0; --i) {
|
||||||
if (s[i] == ch)
|
if (s[i] == ch) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
@ -454,13 +481,36 @@ bool file_exists(const char *path)
|
|||||||
return stat(path, &s) == 0;
|
return stat(path, &s) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checks the file type path points to and returns a File_Type enum value.
|
||||||
|
*
|
||||||
|
* Returns FILE_TYPE_DIRECTORY if path points to a directory.
|
||||||
|
* Returns FILE_TYPE_REGULAR if path points to a regular file.
|
||||||
|
* Returns FILE_TYPE_OTHER on any other result, including an invalid path.
|
||||||
|
*/
|
||||||
|
File_Type file_type(const char *path)
|
||||||
|
{
|
||||||
|
struct stat s;
|
||||||
|
stat(path, &s);
|
||||||
|
|
||||||
|
switch (s.st_mode & S_IFMT) {
|
||||||
|
case S_IFDIR:
|
||||||
|
return FILE_TYPE_DIRECTORY;
|
||||||
|
case S_IFREG:
|
||||||
|
return FILE_TYPE_REGULAR;
|
||||||
|
default:
|
||||||
|
return FILE_TYPE_OTHER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* returns file size. If file doesn't exist returns 0. */
|
/* returns file size. If file doesn't exist returns 0. */
|
||||||
off_t file_size(const char *path)
|
off_t file_size(const char *path)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if (stat(path, &st) == -1)
|
if (stat(path, &st) == -1) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return st.st_size;
|
return st.st_size;
|
||||||
}
|
}
|
||||||
@ -473,13 +523,15 @@ int check_file_signature(const char *signature, size_t size, FILE *fp)
|
|||||||
{
|
{
|
||||||
char buf[size];
|
char buf[size];
|
||||||
|
|
||||||
if (fread(buf, size, 1, fp) != 1)
|
if (fread(buf, size, 1, fp) != 1) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int ret = memcmp(signature, buf, size);
|
int ret = memcmp(signature, buf, size);
|
||||||
|
|
||||||
if (fseek(fp, 0L, SEEK_SET) == -1)
|
if (fseek(fp, 0L, SEEK_SET) == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return ret == 0 ? 0 : 1;
|
return ret == 0 ? 0 : 1;
|
||||||
}
|
}
|
||||||
@ -489,10 +541,11 @@ void set_window_title(ToxWindow *self, const char *title, int len)
|
|||||||
{
|
{
|
||||||
char cpy[TOXIC_MAX_NAME_LENGTH + 1];
|
char cpy[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
|
|
||||||
if (self->is_groupchat) /* keep groupnumber in title */
|
if (self->is_groupchat) { /* keep groupnumber in title */
|
||||||
snprintf(cpy, sizeof(cpy), "%d %s", self->num, title);
|
snprintf(cpy, sizeof(cpy), "%d %s", self->num, title);
|
||||||
else
|
} else {
|
||||||
snprintf(cpy, sizeof(cpy), "%s", title);
|
snprintf(cpy, sizeof(cpy), "%s", title);
|
||||||
|
}
|
||||||
|
|
||||||
if (len > MAX_WINDOW_NAME_LENGTH) {
|
if (len > MAX_WINDOW_NAME_LENGTH) {
|
||||||
strcpy(&cpy[MAX_WINDOW_NAME_LENGTH - 3], "...");
|
strcpy(&cpy[MAX_WINDOW_NAME_LENGTH - 3], "...");
|
||||||
|
@ -39,6 +39,14 @@
|
|||||||
#define net_to_host(x, y) hst_to_net(x, y)
|
#define net_to_host(x, y) hst_to_net(x, y)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef enum File_Type
|
||||||
|
{
|
||||||
|
FILE_TYPE_REGULAR,
|
||||||
|
FILE_TYPE_DIRECTORY,
|
||||||
|
FILE_TYPE_OTHER,
|
||||||
|
} File_Type;
|
||||||
|
|
||||||
|
|
||||||
void hst_to_net(uint8_t *num, uint16_t numbytes);
|
void hst_to_net(uint8_t *num, uint16_t numbytes);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -78,13 +86,13 @@ int string_is_empty(const char *string);
|
|||||||
/* Same as above but for wide character strings */
|
/* Same as above but for wide character strings */
|
||||||
int wstring_is_empty(const wchar_t *string);
|
int wstring_is_empty(const wchar_t *string);
|
||||||
|
|
||||||
/* convert a multibyte string to a wide character string (must provide buffer) */
|
/* converts a multibyte string to a wide character string (must provide buffer) */
|
||||||
int char_to_wcs_buf(wchar_t *buf, const char *string, size_t n);
|
int char_to_wcs_buf(wchar_t *buf, const char *string, size_t n);
|
||||||
|
|
||||||
/* converts wide character string into a multibyte string and puts in buf. */
|
/* converts wide character string into a multibyte string and puts in buf. */
|
||||||
int wcs_to_mbs_buf(char *buf, const wchar_t *string, size_t n);
|
int wcs_to_mbs_buf(char *buf, const wchar_t *string, size_t n);
|
||||||
|
|
||||||
/* convert a multibyte string to a wide character string and puts in buf) */
|
/* converts a multibyte string to a wide character string and puts in buf) */
|
||||||
int mbs_to_wcs_buf(wchar_t *buf, const char *string, size_t n);
|
int mbs_to_wcs_buf(wchar_t *buf, const char *string, size_t n);
|
||||||
|
|
||||||
/* Returns 1 if connection has timed out, 0 otherwise */
|
/* Returns 1 if connection has timed out, 0 otherwise */
|
||||||
@ -146,6 +154,15 @@ void bytes_convert_str(char *buf, int size, uint64_t bytes);
|
|||||||
/* checks if a file exists. Returns true or false */
|
/* checks if a file exists. Returns true or false */
|
||||||
bool file_exists(const char *path);
|
bool file_exists(const char *path);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checks the file type path points to and returns a File_Type enum value.
|
||||||
|
*
|
||||||
|
* Returns FILE_TYPE_DIRECTORY if path points to a directory.
|
||||||
|
* Returns FILE_TYPE_REGULAR if path points to a regular file.
|
||||||
|
* Returns FILE_TYPE_OTHER on any other result, including an invalid path.
|
||||||
|
*/
|
||||||
|
File_Type file_type(const char *path);
|
||||||
|
|
||||||
/* returns file size. If file doesn't exist returns 0. */
|
/* returns file size. If file doesn't exist returns 0. */
|
||||||
off_t file_size(const char *path);
|
off_t file_size(const char *path);
|
||||||
|
|
||||||
@ -170,4 +187,4 @@ bool is_ip4_address(const char *address);
|
|||||||
*/
|
*/
|
||||||
bool is_ip6_address(const char *address);
|
bool is_ip6_address(const char *address);
|
||||||
|
|
||||||
#endif /* #define MISC_TOOLS_H */
|
#endif /* MISC_TOOLS_H */
|
||||||
|
@ -42,7 +42,7 @@ extern struct Winthread Winthread;
|
|||||||
#define MAX_DOMAIN_SIZE 32
|
#define MAX_DOMAIN_SIZE 32
|
||||||
#define MAX_SERVER_LINE MAX_DOMAIN_SIZE + (SERVER_KEY_SIZE * 2) + 3
|
#define MAX_SERVER_LINE MAX_DOMAIN_SIZE + (SERVER_KEY_SIZE * 2) + 3
|
||||||
|
|
||||||
struct Nameservers {
|
static struct Nameservers {
|
||||||
int lines;
|
int lines;
|
||||||
char names[MAX_SERVERS][MAX_DOMAIN_SIZE];
|
char names[MAX_SERVERS][MAX_DOMAIN_SIZE];
|
||||||
char keys[MAX_SERVERS][SERVER_KEY_SIZE];
|
char keys[MAX_SERVERS][SERVER_KEY_SIZE];
|
||||||
@ -97,42 +97,49 @@ static int load_nameserver_list(const char *path)
|
|||||||
{
|
{
|
||||||
FILE *fp = fopen(path, "r");
|
FILE *fp = fopen(path, "r");
|
||||||
|
|
||||||
if (fp == NULL)
|
if (fp == NULL) {
|
||||||
return -2;
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
char line[MAX_SERVER_LINE];
|
char line[MAX_SERVER_LINE];
|
||||||
|
|
||||||
while (fgets(line, sizeof(line), fp) && Nameservers.lines < MAX_SERVERS) {
|
while (fgets(line, sizeof(line), fp) && Nameservers.lines < MAX_SERVERS) {
|
||||||
int linelen = strlen(line);
|
int linelen = strlen(line);
|
||||||
|
|
||||||
if (linelen < SERVER_KEY_SIZE * 2 + 5)
|
if (linelen < SERVER_KEY_SIZE * 2 + 5) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (line[linelen - 1] == '\n')
|
if (line[linelen - 1] == '\n') {
|
||||||
line[--linelen] = '\0';
|
line[--linelen] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
const char *name = strtok(line, " ");
|
const char *name = strtok(line, " ");
|
||||||
const char *keystr = strtok(NULL, " ");
|
const char *keystr = strtok(NULL, " ");
|
||||||
|
|
||||||
if (name == NULL || keystr == NULL)
|
if (name == NULL || keystr == NULL) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (strlen(keystr) != SERVER_KEY_SIZE * 2)
|
if (strlen(keystr) != SERVER_KEY_SIZE * 2) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(Nameservers.names[Nameservers.lines], sizeof(Nameservers.names[Nameservers.lines]), "%s", name);
|
snprintf(Nameservers.names[Nameservers.lines], sizeof(Nameservers.names[Nameservers.lines]), "%s", name);
|
||||||
int res = hex_string_to_bytes(Nameservers.keys[Nameservers.lines], SERVER_KEY_SIZE, keystr);
|
int res = hex_string_to_bytes(Nameservers.keys[Nameservers.lines], SERVER_KEY_SIZE, keystr);
|
||||||
|
|
||||||
if (res == -1)
|
if (res == -1) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
++Nameservers.lines;
|
++Nameservers.lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
if (Nameservers.lines < 1)
|
if (Nameservers.lines < 1) {
|
||||||
return -3;
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -145,8 +152,9 @@ static int load_nameserver_list(const char *path)
|
|||||||
*/
|
*/
|
||||||
static int parse_addr(const char *addr, char *namebuf, size_t namebuf_sz, char *dombuf, size_t dombuf_sz)
|
static int parse_addr(const char *addr, char *namebuf, size_t namebuf_sz, char *dombuf, size_t dombuf_sz)
|
||||||
{
|
{
|
||||||
if (strlen(addr) >= (MAX_STR_SIZE - strlen(NAMESERVER_API_PATH)))
|
if (strlen(addr) >= (MAX_STR_SIZE - strlen(NAMESERVER_API_PATH))) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
char tmpaddr[MAX_STR_SIZE];
|
char tmpaddr[MAX_STR_SIZE];
|
||||||
char *tmpname = NULL;
|
char *tmpname = NULL;
|
||||||
@ -156,8 +164,9 @@ static int parse_addr(const char *addr, char *namebuf, size_t namebuf_sz, char *
|
|||||||
tmpname = strtok(tmpaddr, "@");
|
tmpname = strtok(tmpaddr, "@");
|
||||||
tmpdom = strtok(NULL, "");
|
tmpdom = strtok(NULL, "");
|
||||||
|
|
||||||
if (tmpname == NULL || tmpdom == NULL)
|
if (tmpname == NULL || tmpdom == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
str_to_lower(tmpdom);
|
str_to_lower(tmpdom);
|
||||||
snprintf(namebuf, namebuf_sz, "%s", tmpname);
|
snprintf(namebuf, namebuf_sz, "%s", tmpname);
|
||||||
@ -197,23 +206,27 @@ static int process_response(struct Recv_Curl_Data *recv_data)
|
|||||||
{
|
{
|
||||||
size_t prefix_size = strlen(ID_PREFIX);
|
size_t prefix_size = strlen(ID_PREFIX);
|
||||||
|
|
||||||
if (recv_data->length < TOX_ADDRESS_SIZE * 2 + prefix_size)
|
if (recv_data->length < TOX_ADDRESS_SIZE * 2 + prefix_size) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
const char *IDstart = strstr(recv_data->data, ID_PREFIX);
|
const char *IDstart = strstr(recv_data->data, ID_PREFIX);
|
||||||
|
|
||||||
if (IDstart == NULL)
|
if (IDstart == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (strlen(IDstart) < TOX_ADDRESS_SIZE * 2 + prefix_size)
|
if (strlen(IDstart) < TOX_ADDRESS_SIZE * 2 + prefix_size) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
char ID_string[TOX_ADDRESS_SIZE * 2 + 1];
|
char ID_string[TOX_ADDRESS_SIZE * 2 + 1];
|
||||||
memcpy(ID_string, IDstart + prefix_size, TOX_ADDRESS_SIZE * 2);
|
memcpy(ID_string, IDstart + prefix_size, TOX_ADDRESS_SIZE * 2);
|
||||||
ID_string[TOX_ADDRESS_SIZE * 2] = 0;
|
ID_string[TOX_ADDRESS_SIZE * 2] = 0;
|
||||||
|
|
||||||
if (hex_string_to_bin(ID_string, strlen(ID_string), t_data.id_bin, sizeof(t_data.id_bin)) == -1)
|
if (hex_string_to_bin(ID_string, strlen(ID_string), t_data.id_bin, sizeof(t_data.id_bin)) == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -234,10 +247,11 @@ void *lookup_thread_func(void *data)
|
|||||||
char real_domain[MAX_DOMAIN_SIZE];
|
char real_domain[MAX_DOMAIN_SIZE];
|
||||||
|
|
||||||
if (!get_domain_match(nameserver_key, real_domain, sizeof(real_domain), input_domain)) {
|
if (!get_domain_match(nameserver_key, real_domain, sizeof(real_domain), input_domain)) {
|
||||||
if (!strcasecmp(input_domain, "utox.org"))
|
if (!strcasecmp(input_domain, "utox.org")) {
|
||||||
lookup_error(self, "utox.org uses deprecated DNS-based lookups and is no longer supported by Toxic.");
|
lookup_error(self, "utox.org uses deprecated DNS-based lookups and is no longer supported by Toxic.");
|
||||||
else
|
} else {
|
||||||
lookup_error(self, "Name server domain not found.");
|
lookup_error(self, "Name server domain not found.");
|
||||||
|
}
|
||||||
|
|
||||||
kill_lookup_thread();
|
kill_lookup_thread();
|
||||||
}
|
}
|
||||||
|
182
src/notify.c
182
src/notify.c
@ -47,12 +47,12 @@
|
|||||||
/* compatibility with older versions of OpenAL */
|
/* compatibility with older versions of OpenAL */
|
||||||
#ifndef ALC_ALL_DEVICES_SPECIFIER
|
#ifndef ALC_ALL_DEVICES_SPECIFIER
|
||||||
#include <AL/alext.h>
|
#include <AL/alext.h>
|
||||||
#endif
|
#endif /* ALC_ALL_DEVICES_SPECIFIER */
|
||||||
#endif
|
#endif /* __APPLE__ */
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
#include <AL/alut.h> /* freealut packet */
|
#include <AL/alut.h> /* freealut packet */
|
||||||
#endif
|
#endif /* SOUND_NOTIFY */
|
||||||
#endif /* AUDIO */
|
#endif /* defined(AUDIO) || defined(SOUND_NOTIFY) */
|
||||||
|
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
#include <libnotify/notify.h>
|
#include <libnotify/notify.h>
|
||||||
@ -64,7 +64,7 @@
|
|||||||
|
|
||||||
extern struct user_settings *user_settings;
|
extern struct user_settings *user_settings;
|
||||||
|
|
||||||
struct Control {
|
static struct Control {
|
||||||
time_t cooldown;
|
time_t cooldown;
|
||||||
time_t notif_timeout;
|
time_t notif_timeout;
|
||||||
|
|
||||||
@ -79,12 +79,12 @@ struct Control {
|
|||||||
#endif /* SOUND_NOTIFY */
|
#endif /* SOUND_NOTIFY */
|
||||||
} Control = {0};
|
} Control = {0};
|
||||||
|
|
||||||
struct _ActiveNotifications {
|
static struct _ActiveNotifications {
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
uint32_t source;
|
uint32_t source;
|
||||||
uint32_t buffer;
|
uint32_t buffer;
|
||||||
bool looping;
|
bool looping;
|
||||||
#endif
|
#endif /* SOUND_NOTIFY */
|
||||||
bool active;
|
bool active;
|
||||||
int *id_indicator;
|
int *id_indicator;
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
@ -93,7 +93,7 @@ struct _ActiveNotifications {
|
|||||||
char title[64];
|
char title[64];
|
||||||
size_t size;
|
size_t size;
|
||||||
time_t n_timeout;
|
time_t n_timeout;
|
||||||
#endif
|
#endif /* BOX_NOTIFY */
|
||||||
} actives[ACTIVE_NOTIFS_MAX];
|
} actives[ACTIVE_NOTIFS_MAX];
|
||||||
/**********************************************************************************/
|
/**********************************************************************************/
|
||||||
/**********************************************************************************/
|
/**********************************************************************************/
|
||||||
@ -104,21 +104,24 @@ struct _ActiveNotifications {
|
|||||||
/* coloured tab notifications: primary notification type */
|
/* coloured tab notifications: primary notification type */
|
||||||
static void tab_notify(ToxWindow *self, uint64_t flags)
|
static void tab_notify(ToxWindow *self, uint64_t flags)
|
||||||
{
|
{
|
||||||
if (self == NULL)
|
if (self == NULL) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (flags & NT_WNDALERT_0)
|
if (flags & NT_WNDALERT_0) {
|
||||||
self->alert = WINDOW_ALERT_0;
|
self->alert = WINDOW_ALERT_0;
|
||||||
else if ( (flags & NT_WNDALERT_1) && (!self->alert || self->alert > WINDOW_ALERT_0) )
|
} else if ((flags & NT_WNDALERT_1) && (!self->alert || self->alert > WINDOW_ALERT_0)) {
|
||||||
self->alert = WINDOW_ALERT_1;
|
self->alert = WINDOW_ALERT_1;
|
||||||
else if ( (flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1) )
|
} else if ((flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1)) {
|
||||||
self->alert = WINDOW_ALERT_2;
|
self->alert = WINDOW_ALERT_2;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool notifications_are_disabled(uint64_t flags)
|
static bool notifications_are_disabled(uint64_t flags)
|
||||||
{
|
{
|
||||||
if (user_settings->alerts != ALERTS_ENABLED)
|
if (user_settings->alerts != ALERTS_ENABLED) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool res = (flags & NT_RESTOL) && (Control.cooldown > get_unix_time());
|
bool res = (flags & NT_RESTOL) && (Control.cooldown > get_unix_time());
|
||||||
#ifdef X11
|
#ifdef X11
|
||||||
@ -128,14 +131,14 @@ static bool notifications_are_disabled(uint64_t flags)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void control_lock()
|
static void control_lock(void)
|
||||||
{
|
{
|
||||||
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
||||||
pthread_mutex_lock(Control.poll_mutex);
|
pthread_mutex_lock(Control.poll_mutex);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void control_unlock()
|
static void control_unlock(void)
|
||||||
{
|
{
|
||||||
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
||||||
pthread_mutex_unlock(Control.poll_mutex);
|
pthread_mutex_unlock(Control.poll_mutex);
|
||||||
@ -157,11 +160,13 @@ static bool device_opened = false;
|
|||||||
time_t last_opened_update = 0;
|
time_t last_opened_update = 0;
|
||||||
|
|
||||||
/* Opens primary device. Returns true on succe*/
|
/* Opens primary device. Returns true on succe*/
|
||||||
void m_open_device()
|
void m_open_device(void)
|
||||||
{
|
{
|
||||||
last_opened_update = get_unix_time();
|
last_opened_update = get_unix_time();
|
||||||
|
|
||||||
if (device_opened) return;
|
if (device_opened) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Blah error check */
|
/* Blah error check */
|
||||||
open_primary_device(output, &Control.device_idx, 48000, 20, 1);
|
open_primary_device(output, &Control.device_idx, 48000, 20, 1);
|
||||||
@ -169,9 +174,11 @@ void m_open_device()
|
|||||||
device_opened = true;
|
device_opened = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void m_close_device()
|
void m_close_device(void)
|
||||||
{
|
{
|
||||||
if (!device_opened) return;
|
if (!device_opened) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
close_device(output, Control.device_idx);
|
close_device(output, Control.device_idx);
|
||||||
|
|
||||||
@ -179,7 +186,7 @@ void m_close_device()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Terminate all sounds but wait for them to finish first */
|
/* Terminate all sounds but wait for them to finish first */
|
||||||
void graceful_clear()
|
void graceful_clear(void)
|
||||||
{
|
{
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
@ -196,17 +203,20 @@ void graceful_clear()
|
|||||||
actives[i].box = NULL;
|
actives[i].box = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif /* BOX_NOTIFY */
|
||||||
|
|
||||||
if (actives[i].id_indicator)
|
if (actives[i].id_indicator) {
|
||||||
*actives[i].id_indicator = -1; /* reset indicator value */
|
*actives[i].id_indicator = -1; /* reset indicator value */
|
||||||
|
}
|
||||||
|
|
||||||
if (actives[i].looping) {
|
if (actives[i].looping) {
|
||||||
stop_sound(i);
|
stop_sound(i);
|
||||||
} else {
|
} else {
|
||||||
if (!is_playing(actives[i].source))
|
if (!is_playing(actives[i].source)) {
|
||||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
||||||
else break;
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -241,7 +251,9 @@ void *do_playing(void *_p)
|
|||||||
|
|
||||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
||||||
|
|
||||||
if (actives[i].looping) has_looping = true;
|
if (actives[i].looping) {
|
||||||
|
has_looping = true;
|
||||||
|
}
|
||||||
|
|
||||||
test_active_notify = actives[i].active && !actives[i].looping;
|
test_active_notify = actives[i].active && !actives[i].looping;
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
@ -249,8 +261,9 @@ void *do_playing(void *_p)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (test_active_notify) {
|
if (test_active_notify) {
|
||||||
if (actives[i].id_indicator)
|
if (actives[i].id_indicator) {
|
||||||
*actives[i].id_indicator = -1; /* reset indicator value */
|
*actives[i].id_indicator = -1; /* reset indicator value */
|
||||||
|
}
|
||||||
|
|
||||||
if (!is_playing(actives[i].source)) {
|
if (!is_playing(actives[i].source)) {
|
||||||
/* Close */
|
/* Close */
|
||||||
@ -267,8 +280,9 @@ void *do_playing(void *_p)
|
|||||||
notify_notification_close(actives[i].box, &ignore);
|
notify_notification_close(actives[i].box, &ignore);
|
||||||
actives[i].box = NULL;
|
actives[i].box = NULL;
|
||||||
|
|
||||||
if (actives[i].id_indicator)
|
if (actives[i].id_indicator) {
|
||||||
*actives[i].id_indicator = -1; /* reset indicator value */
|
*actives[i].id_indicator = -1; /* reset indicator value */
|
||||||
|
}
|
||||||
|
|
||||||
if (!actives[i].looping && !is_playing(actives[i].source)) {
|
if (!actives[i].looping && !is_playing(actives[i].source)) {
|
||||||
/* stop source if not looping or playing, just terminate box */
|
/* stop source if not looping or playing, just terminate box */
|
||||||
@ -279,7 +293,7 @@ void *do_playing(void *_p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif /* BOX_NOTIFY */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* device is opened and no activity in under DEVICE_COOLDOWN time, close device*/
|
/* device is opened and no activity in under DEVICE_COOLDOWN time, close device*/
|
||||||
@ -338,8 +352,9 @@ void *do_playing(void *_p)
|
|||||||
notify_notification_close(actives[i].box, &ignore);
|
notify_notification_close(actives[i].box, &ignore);
|
||||||
actives[i].box = NULL;
|
actives[i].box = NULL;
|
||||||
|
|
||||||
if (actives[i].id_indicator)
|
if (actives[i].id_indicator) {
|
||||||
*actives[i].id_indicator = -1; /* reset indicator value */
|
*actives[i].id_indicator = -1; /* reset indicator value */
|
||||||
|
}
|
||||||
|
|
||||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
||||||
}
|
}
|
||||||
@ -352,7 +367,7 @@ void *do_playing(void *_p)
|
|||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void graceful_clear()
|
void graceful_clear(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
control_lock();
|
control_lock();
|
||||||
@ -364,15 +379,16 @@ void graceful_clear()
|
|||||||
actives[i].box = NULL;
|
actives[i].box = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actives[i].id_indicator)
|
if (actives[i].id_indicator) {
|
||||||
*actives[i].id_indicator = -1; /* reset indicator value */
|
*actives[i].id_indicator = -1; /* reset indicator value */
|
||||||
|
}
|
||||||
|
|
||||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
||||||
}
|
}
|
||||||
|
|
||||||
control_unlock();
|
control_unlock();
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* SOUND_NOTIFY */
|
||||||
|
|
||||||
/**********************************************************************************/
|
/**********************************************************************************/
|
||||||
/**********************************************************************************/
|
/**********************************************************************************/
|
||||||
@ -391,8 +407,9 @@ int init_notify(int login_cooldown, int notification_timeout)
|
|||||||
|
|
||||||
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
||||||
|
|
||||||
if (pthread_mutex_init(Control.poll_mutex, NULL) != 0)
|
if (pthread_mutex_init(Control.poll_mutex, NULL) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
Control.poll_active = 1;
|
Control.poll_active = 1;
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
@ -403,7 +420,7 @@ int init_notify(int login_cooldown, int notification_timeout)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif /* defined(SOUND_NOTIFY) || defined(BOX_NOTIFY) */
|
||||||
Control.cooldown = time(NULL) + login_cooldown;
|
Control.cooldown = time(NULL) + login_cooldown;
|
||||||
|
|
||||||
|
|
||||||
@ -414,7 +431,7 @@ int init_notify(int login_cooldown, int notification_timeout)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void terminate_notify()
|
void terminate_notify(void)
|
||||||
{
|
{
|
||||||
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
||||||
control_lock();
|
control_lock();
|
||||||
@ -428,12 +445,14 @@ void terminate_notify()
|
|||||||
control_unlock();
|
control_unlock();
|
||||||
|
|
||||||
graceful_clear();
|
graceful_clear();
|
||||||
#endif
|
#endif /* defined(SOUND_NOTIFY) || defined(BOX_NOTIFY) */
|
||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
for (; i < SOUNDS_SIZE; i ++) free(Control.sounds[i]);
|
for (; i < SOUNDS_SIZE; i ++) {
|
||||||
|
free(Control.sounds[i]);
|
||||||
|
}
|
||||||
|
|
||||||
alutExit();
|
alutExit();
|
||||||
#endif /* SOUND_NOTIFY */
|
#endif /* SOUND_NOTIFY */
|
||||||
@ -446,7 +465,9 @@ void terminate_notify()
|
|||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
int set_sound(Notification sound, const char *value)
|
int set_sound(Notification sound, const char *value)
|
||||||
{
|
{
|
||||||
if (sound == silent) return 0;
|
if (sound == silent) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
free(Control.sounds[sound]);
|
free(Control.sounds[sound]);
|
||||||
|
|
||||||
@ -487,11 +508,14 @@ int play_notify_sound(Notification notif, uint64_t flags)
|
|||||||
{
|
{
|
||||||
int rc = -1;
|
int rc = -1;
|
||||||
|
|
||||||
if (flags & NT_BEEP) beep();
|
if (flags & NT_BEEP) {
|
||||||
|
beep();
|
||||||
|
}
|
||||||
|
|
||||||
if (notif != silent) {
|
if (notif != silent) {
|
||||||
if ( !Control.poll_active || !Control.sounds[notif] )
|
if (!Control.poll_active || !Control.sounds[notif]) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
rc = play_sound_internal(notif, flags & NT_LOOP ? 1 : 0);
|
rc = play_sound_internal(notif, flags & NT_LOOP ? 1 : 0);
|
||||||
}
|
}
|
||||||
@ -510,10 +534,11 @@ void stop_sound(int id)
|
|||||||
notify_notification_close(actives[id].box, &ignore);
|
notify_notification_close(actives[id].box, &ignore);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif /* BOX_NOTIFY */
|
||||||
|
|
||||||
if (actives[id].id_indicator)
|
if (actives[id].id_indicator) {
|
||||||
*actives[id].id_indicator = -1;
|
*actives[id].id_indicator = -1;
|
||||||
|
}
|
||||||
|
|
||||||
// alSourcei(actives[id].source, AL_LOOPING, false);
|
// alSourcei(actives[id].source, AL_LOOPING, false);
|
||||||
alSourceStop(actives[id].source);
|
alSourceStop(actives[id].source);
|
||||||
@ -522,7 +547,7 @@ void stop_sound(int id)
|
|||||||
memset(&actives[id], 0, sizeof(struct _ActiveNotifications));
|
memset(&actives[id], 0, sizeof(struct _ActiveNotifications));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* SOUND_NOTIFY */
|
||||||
|
|
||||||
static int m_play_sound(Notification notif, uint64_t flags)
|
static int m_play_sound(Notification notif, uint64_t flags)
|
||||||
{
|
{
|
||||||
@ -530,33 +555,30 @@ static int m_play_sound(Notification notif, uint64_t flags)
|
|||||||
return play_notify_sound(notif, flags);
|
return play_notify_sound(notif, flags);
|
||||||
#else
|
#else
|
||||||
|
|
||||||
if (notif != silent)
|
if (notif != silent) {
|
||||||
beep();
|
beep();
|
||||||
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
#endif /* SOUND_NOTIFY */
|
#endif /* SOUND_NOTIFY */
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef BOX_NOTIFY
|
|
||||||
void m_notify_action(NotifyNotification *box, char *action, void *data)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int sound_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indicator)
|
int sound_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indicator)
|
||||||
{
|
{
|
||||||
tab_notify(self, flags);
|
tab_notify(self, flags);
|
||||||
|
|
||||||
if (notifications_are_disabled(flags))
|
if (notifications_are_disabled(flags)) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int id = -1;
|
int id = -1;
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
if (self && (!self->stb || self->stb->status != TOX_USER_STATUS_BUSY))
|
if (self && (!self->stb || self->stb->status != TOX_USER_STATUS_BUSY)) {
|
||||||
id = m_play_sound(notif, flags);
|
id = m_play_sound(notif, flags);
|
||||||
else if (flags & NT_ALWAYS)
|
} else if (flags & NT_ALWAYS) {
|
||||||
id = m_play_sound(notif, flags);
|
id = m_play_sound(notif, flags);
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(BOX_NOTIFY) && !defined(SOUND_NOTIFY)
|
#if defined(BOX_NOTIFY) && !defined(SOUND_NOTIFY)
|
||||||
|
|
||||||
@ -569,7 +591,7 @@ int sound_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_in
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif /* defined(BOX_NOTIFY) && !defined(SOUND_NOTIFY) */
|
||||||
|
|
||||||
if (id_indicator && id != -1) {
|
if (id_indicator && id != -1) {
|
||||||
actives[id].id_indicator = id_indicator;
|
actives[id].id_indicator = id_indicator;
|
||||||
@ -585,10 +607,13 @@ int sound_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id)
|
|||||||
{
|
{
|
||||||
tab_notify(self, flags);
|
tab_notify(self, flags);
|
||||||
|
|
||||||
if (notifications_are_disabled(flags))
|
if (notifications_are_disabled(flags)) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (id < 0 || id >= ACTIVE_NOTIFS_MAX) return -1;
|
if (id < 0 || id >= ACTIVE_NOTIFS_MAX) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
control_lock();
|
control_lock();
|
||||||
@ -617,8 +642,9 @@ int sound_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id)
|
|||||||
return id;
|
return id;
|
||||||
#else
|
#else
|
||||||
|
|
||||||
if (notif != silent)
|
if (notif != silent) {
|
||||||
beep();
|
beep();
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
#endif /* SOUND_NOTIFY */
|
#endif /* SOUND_NOTIFY */
|
||||||
@ -652,27 +678,33 @@ int box_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indi
|
|||||||
actives[id].active = 1;
|
actives[id].active = 1;
|
||||||
actives[id].id_indicator = id_indicator;
|
actives[id].id_indicator = id_indicator;
|
||||||
|
|
||||||
if (id_indicator) *id_indicator = id;
|
if (id_indicator) {
|
||||||
|
*id_indicator = id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
if (id == -1)
|
if (id == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* SOUND_NOTIFY */
|
#endif /* SOUND_NOTIFY */
|
||||||
|
|
||||||
snprintf(actives[id].title, sizeof(actives[id].title), "%s", title);
|
snprintf(actives[id].title, sizeof(actives[id].title), "%s", title);
|
||||||
|
|
||||||
if (strlen(title) > 23) strcpy(actives[id].title + 20, "...");
|
if (strlen(title) > 23) {
|
||||||
|
strcpy(actives[id].title + 20, "...");
|
||||||
|
}
|
||||||
|
|
||||||
va_list __ARGS__;
|
va_list __ARGS__;
|
||||||
va_start(__ARGS__, format);
|
va_start(__ARGS__, format);
|
||||||
vsnprintf(actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
|
vsnprintf(actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
|
||||||
va_end(__ARGS__);
|
va_end(__ARGS__);
|
||||||
|
|
||||||
if (strlen(actives[id].messages[0]) > MAX_BOX_MSG_LEN - 3)
|
if (strlen(actives[id].messages[0]) > MAX_BOX_MSG_LEN - 3) {
|
||||||
strcpy(actives[id].messages[0] + MAX_BOX_MSG_LEN - 3, "...");
|
strcpy(actives[id].messages[0] + MAX_BOX_MSG_LEN - 3, "...");
|
||||||
|
}
|
||||||
|
|
||||||
actives[id].box = notify_notification_new(actives[id].title, actives[id].messages[0], NULL);
|
actives[id].box = notify_notification_new(actives[id].title, actives[id].messages[0], NULL);
|
||||||
actives[id].size++;
|
actives[id].size++;
|
||||||
@ -699,8 +731,9 @@ int box_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id, con
|
|||||||
|
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
|
|
||||||
if (sound_notify2(self, notif, flags, id) == -1)
|
if (sound_notify2(self, notif, flags, id) == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
@ -714,8 +747,9 @@ int box_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id, con
|
|||||||
vsnprintf(actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __ARGS__);
|
vsnprintf(actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __ARGS__);
|
||||||
va_end(__ARGS__);
|
va_end(__ARGS__);
|
||||||
|
|
||||||
if (strlen(actives[id].messages[actives[id].size]) > MAX_BOX_MSG_LEN - 3)
|
if (strlen(actives[id].messages[actives[id].size]) > MAX_BOX_MSG_LEN - 3) {
|
||||||
strcpy(actives[id].messages[actives[id].size] + MAX_BOX_MSG_LEN - 3, "...");
|
strcpy(actives[id].messages[actives[id].size] + MAX_BOX_MSG_LEN - 3, "...");
|
||||||
|
}
|
||||||
|
|
||||||
actives[id].size++;
|
actives[id].size++;
|
||||||
actives[id].n_timeout = get_unix_time() + Control.notif_timeout / 1000;
|
actives[id].n_timeout = get_unix_time() + Control.notif_timeout / 1000;
|
||||||
@ -739,15 +773,16 @@ int box_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id, con
|
|||||||
return id;
|
return id;
|
||||||
#else
|
#else
|
||||||
return sound_notify2(self, notif, flags, id);
|
return sound_notify2(self, notif, flags, id);
|
||||||
#endif
|
#endif /* BOX_NOTIFY */
|
||||||
}
|
}
|
||||||
|
|
||||||
int box_silent_notify(ToxWindow *self, uint64_t flags, int *id_indicator, const char *title, const char *format, ...)
|
int box_silent_notify(ToxWindow *self, uint64_t flags, int *id_indicator, const char *title, const char *format, ...)
|
||||||
{
|
{
|
||||||
tab_notify(self, flags);
|
tab_notify(self, flags);
|
||||||
|
|
||||||
if (notifications_are_disabled(flags))
|
if (notifications_are_disabled(flags)) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
|
|
||||||
@ -769,15 +804,18 @@ int box_silent_notify(ToxWindow *self, uint64_t flags, int *id_indicator, const
|
|||||||
|
|
||||||
snprintf(actives[id].title, sizeof(actives[id].title), "%s", title);
|
snprintf(actives[id].title, sizeof(actives[id].title), "%s", title);
|
||||||
|
|
||||||
if (strlen(title) > 23) strcpy(actives[id].title + 20, "...");
|
if (strlen(title) > 23) {
|
||||||
|
strcpy(actives[id].title + 20, "...");
|
||||||
|
}
|
||||||
|
|
||||||
va_list __ARGS__;
|
va_list __ARGS__;
|
||||||
va_start(__ARGS__, format);
|
va_start(__ARGS__, format);
|
||||||
vsnprintf(actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
|
vsnprintf(actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
|
||||||
va_end(__ARGS__);
|
va_end(__ARGS__);
|
||||||
|
|
||||||
if (strlen(actives[id].messages[0]) > MAX_BOX_MSG_LEN - 3)
|
if (strlen(actives[id].messages[0]) > MAX_BOX_MSG_LEN - 3) {
|
||||||
strcpy(actives[id].messages[0] + MAX_BOX_MSG_LEN - 3, "...");
|
strcpy(actives[id].messages[0] + MAX_BOX_MSG_LEN - 3, "...");
|
||||||
|
}
|
||||||
|
|
||||||
actives[id].active = 1;
|
actives[id].active = 1;
|
||||||
actives[id].box = notify_notification_new(actives[id].title, actives[id].messages[0], NULL);
|
actives[id].box = notify_notification_new(actives[id].title, actives[id].messages[0], NULL);
|
||||||
@ -793,15 +831,16 @@ int box_silent_notify(ToxWindow *self, uint64_t flags, int *id_indicator, const
|
|||||||
return id;
|
return id;
|
||||||
#else
|
#else
|
||||||
return -1;
|
return -1;
|
||||||
#endif
|
#endif /* BOX_NOTIFY */
|
||||||
}
|
}
|
||||||
|
|
||||||
int box_silent_notify2(ToxWindow *self, uint64_t flags, int id, const char *format, ...)
|
int box_silent_notify2(ToxWindow *self, uint64_t flags, int id, const char *format, ...)
|
||||||
{
|
{
|
||||||
tab_notify(self, flags);
|
tab_notify(self, flags);
|
||||||
|
|
||||||
if (notifications_are_disabled(flags))
|
if (notifications_are_disabled(flags)) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
control_lock();
|
control_lock();
|
||||||
@ -817,8 +856,9 @@ int box_silent_notify2(ToxWindow *self, uint64_t flags, int id, const char *form
|
|||||||
vsnprintf(actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __ARGS__);
|
vsnprintf(actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __ARGS__);
|
||||||
va_end(__ARGS__);
|
va_end(__ARGS__);
|
||||||
|
|
||||||
if (strlen(actives[id].messages[actives[id].size]) > MAX_BOX_MSG_LEN - 3)
|
if (strlen(actives[id].messages[actives[id].size]) > MAX_BOX_MSG_LEN - 3) {
|
||||||
strcpy(actives[id].messages[actives[id].size] + MAX_BOX_MSG_LEN - 3, "...");
|
strcpy(actives[id].messages[actives[id].size] + MAX_BOX_MSG_LEN - 3, "...");
|
||||||
|
}
|
||||||
|
|
||||||
actives[id].size ++;
|
actives[id].size ++;
|
||||||
actives[id].n_timeout = get_unix_time() + Control.notif_timeout / 1000;
|
actives[id].n_timeout = get_unix_time() + Control.notif_timeout / 1000;
|
||||||
@ -842,5 +882,5 @@ int box_silent_notify2(ToxWindow *self, uint64_t flags, int id, const char *form
|
|||||||
return id;
|
return id;
|
||||||
#else
|
#else
|
||||||
return -1;
|
return -1;
|
||||||
#endif
|
#endif /* BOX_NOTIFY */
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ typedef enum _Flags {
|
|||||||
} Flags;
|
} Flags;
|
||||||
|
|
||||||
int init_notify(int login_cooldown, int notification_timeout);
|
int init_notify(int login_cooldown, int notification_timeout);
|
||||||
void terminate_notify();
|
void terminate_notify(void);
|
||||||
|
|
||||||
int sound_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indicator);
|
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);
|
int sound_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id);
|
||||||
|
@ -45,7 +45,7 @@ void bgrtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *
|
|||||||
#endif /* __OBJC__ */
|
#endif /* __OBJC__ */
|
||||||
|
|
||||||
int osx_video_init(char **device_names, int *size);
|
int osx_video_init(char **device_names, int *size);
|
||||||
void osx_video_release();
|
void osx_video_release(void);
|
||||||
/* Start device */
|
/* Start device */
|
||||||
int osx_video_open_device(uint32_t selection, uint16_t *width, uint16_t *height);
|
int osx_video_open_device(uint32_t selection, uint16_t *width, uint16_t *height);
|
||||||
/* Stop device */
|
/* Stop device */
|
||||||
|
@ -144,8 +144,9 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
|
|||||||
device_names[i] = video_input_name;
|
device_names[i] = video_input_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( i <= 0 )
|
if (i <= 0) {
|
||||||
return nil;
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
*size = i;
|
*size = i;
|
||||||
|
|
||||||
@ -303,8 +304,9 @@ int osx_video_init(char **device_names, int *size)
|
|||||||
{
|
{
|
||||||
_OSXVideo = [[OSXVideo alloc] initWithDeviceNames: device_names AmtDevices: size];
|
_OSXVideo = [[OSXVideo alloc] initWithDeviceNames: device_names AmtDevices: size];
|
||||||
|
|
||||||
if ( _OSXVideo == nil )
|
if (_OSXVideo == nil) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -317,8 +319,9 @@ void osx_video_release()
|
|||||||
|
|
||||||
int osx_video_open_device(uint32_t selection, uint16_t *width, uint16_t *height)
|
int osx_video_open_device(uint32_t selection, uint16_t *width, uint16_t *height)
|
||||||
{
|
{
|
||||||
if ( _OSXVideo == nil )
|
if (_OSXVideo == nil) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return [_OSXVideo openVideoDeviceIndex: selection Width: width Height: height];
|
return [_OSXVideo openVideoDeviceIndex: selection Width: width Height: height];
|
||||||
}
|
}
|
||||||
@ -330,8 +333,9 @@ void osx_video_close_device(uint32_t device_idx)
|
|||||||
|
|
||||||
int osx_video_read_device(uint8_t *y, uint8_t *u, uint8_t *v, uint16_t *width, uint16_t *height)
|
int osx_video_read_device(uint8_t *y, uint8_t *u, uint8_t *v, uint16_t *width, uint16_t *height)
|
||||||
{
|
{
|
||||||
if ( _OSXVideo == nil )
|
if (_OSXVideo == nil) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return [_OSXVideo getVideoFrameY: y U: u V: v Width: width Height: height];
|
return [_OSXVideo getVideoFrameY: y U: u V: v Width: width Height: height];
|
||||||
}
|
}
|
||||||
|
168
src/prompt.c
168
src/prompt.c
@ -49,19 +49,27 @@ extern struct Winthread Winthread;
|
|||||||
|
|
||||||
extern FriendsList Friends;
|
extern FriendsList Friends;
|
||||||
FriendRequests FrndRequests;
|
FriendRequests FrndRequests;
|
||||||
#if defined(PYTHON) && defined(VIDEO)
|
#ifdef AUDIO
|
||||||
#define AC_NUM_GLOB_COMMANDS 23
|
#define AC_NUM_GLOB_COMMANDS_AUDIO 2
|
||||||
#elif defined(PYTHON) && defined(AUDIO)
|
|
||||||
#define AC_NUM_GLOB_COMMANDS 21
|
|
||||||
#elif VIDEO
|
|
||||||
#define AC_NUM_GLOB_COMMANDS 22
|
|
||||||
#elif AUDIO
|
|
||||||
#define AC_NUM_GLOB_COMMANDS 20
|
|
||||||
#elif PYTHON
|
|
||||||
#define AC_NUM_GLOB_COMMANDS 19
|
|
||||||
#else
|
#else
|
||||||
#define AC_NUM_GLOB_COMMANDS 18
|
#define AC_NUM_GLOB_COMMANDS_AUDIO 0
|
||||||
#endif
|
#endif /* AUDIO */
|
||||||
|
#ifdef VIDEO
|
||||||
|
#define AC_NUM_GLOB_COMMANDS_VIDEO 2
|
||||||
|
#else
|
||||||
|
#define AC_NUM_GLOB_COMMANDS_VIDEO 0
|
||||||
|
#endif /* VIDEO */
|
||||||
|
#ifdef PYTHON
|
||||||
|
#define AC_NUM_GLOB_COMMANDS_PYTHON 1
|
||||||
|
#else
|
||||||
|
#define AC_NUM_GLOB_COMMANDS_PYTHON 0
|
||||||
|
#endif /* PYTHON */
|
||||||
|
#ifdef QRCODE
|
||||||
|
#define AC_NUM_GLOB_COMMANDS_QRCODE 1
|
||||||
|
#else
|
||||||
|
#define AC_NUM_GLOB_COMMANDS_QRCODE 0
|
||||||
|
#endif /* QRCODE */
|
||||||
|
#define AC_NUM_GLOB_COMMANDS (17 + AC_NUM_GLOB_COMMANDS_AUDIO + AC_NUM_GLOB_COMMANDS_VIDEO + AC_NUM_GLOB_COMMANDS_PYTHON + AC_NUM_GLOB_COMMANDS_QRCODE)
|
||||||
|
|
||||||
/* Array of global command names used for tab completion. */
|
/* Array of global command names used for tab completion. */
|
||||||
static const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
|
static const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
|
||||||
@ -76,7 +84,9 @@ static const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
|
|||||||
{ "/help" },
|
{ "/help" },
|
||||||
{ "/log" },
|
{ "/log" },
|
||||||
{ "/myid" },
|
{ "/myid" },
|
||||||
|
#ifdef QRCODE
|
||||||
{ "/myqr" },
|
{ "/myqr" },
|
||||||
|
#endif /* QRCODE */
|
||||||
{ "/nick" },
|
{ "/nick" },
|
||||||
{ "/note" },
|
{ "/note" },
|
||||||
{ "/nospam" },
|
{ "/nospam" },
|
||||||
@ -127,7 +137,7 @@ void kill_prompt_window(ToxWindow *self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* callback: Updates own connection status in prompt statusbar */
|
/* callback: Updates own connection status in prompt statusbar */
|
||||||
void prompt_onSelfConnectionChange(Tox *m, TOX_CONNECTION connection_status, void *userdata)
|
void on_self_connection_status(Tox *m, Tox_Connection connection_status, void *userdata)
|
||||||
{
|
{
|
||||||
StatusBar *statusbar = prompt->stb;
|
StatusBar *statusbar = prompt->stb;
|
||||||
statusbar->connection = connection_status;
|
statusbar->connection = connection_status;
|
||||||
@ -149,26 +159,35 @@ void prompt_update_statusmessage(ToxWindow *prompt, Tox *m, const char *statusms
|
|||||||
size_t len = strlen(statusbar->statusmsg);
|
size_t len = strlen(statusbar->statusmsg);
|
||||||
statusbar->statusmsg_len = len;
|
statusbar->statusmsg_len = len;
|
||||||
|
|
||||||
TOX_ERR_SET_INFO err;
|
Tox_Err_Set_Info err;
|
||||||
tox_self_set_status_message(m, (uint8_t *) statusmsg, len, &err);
|
tox_self_set_status_message(m, (const uint8_t *) statusmsg, len, &err);
|
||||||
|
|
||||||
if (err != TOX_ERR_SET_INFO_OK)
|
if (err != TOX_ERR_SET_INFO_OK) {
|
||||||
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set note (error %d)\n", err);
|
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set note (error %d)\n", err);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Updates own status in prompt statusbar */
|
/* Updates own status in prompt statusbar */
|
||||||
void prompt_update_status(ToxWindow *prompt, TOX_USER_STATUS status)
|
void prompt_update_status(ToxWindow *prompt, Tox_User_Status status)
|
||||||
{
|
{
|
||||||
StatusBar *statusbar = prompt->stb;
|
StatusBar *statusbar = prompt->stb;
|
||||||
statusbar->status = status;
|
statusbar->status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns our own connection status */
|
||||||
|
Tox_Connection prompt_selfConnectionStatus(void)
|
||||||
|
{
|
||||||
|
StatusBar *statusbar = prompt->stb;
|
||||||
|
return statusbar->connection;
|
||||||
|
}
|
||||||
|
|
||||||
/* Adds friend request to pending friend requests.
|
/* Adds friend request to pending friend requests.
|
||||||
Returns request number on success, -1 if queue is full. */
|
Returns request number on success, -1 if queue is full. */
|
||||||
static int add_friend_request(const char *public_key, const char *data)
|
static int add_friend_request(const char *public_key, const char *data)
|
||||||
{
|
{
|
||||||
if (FrndRequests.max_idx >= MAX_FRIEND_REQUESTS)
|
if (FrndRequests.max_idx >= MAX_FRIEND_REQUESTS) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -178,8 +197,9 @@ static int add_friend_request(const char *public_key, const char *data)
|
|||||||
memcpy(FrndRequests.request[i].key, public_key, TOX_PUBLIC_KEY_SIZE);
|
memcpy(FrndRequests.request[i].key, public_key, TOX_PUBLIC_KEY_SIZE);
|
||||||
snprintf(FrndRequests.request[i].msg, sizeof(FrndRequests.request[i].msg), "%s", data);
|
snprintf(FrndRequests.request[i].msg, sizeof(FrndRequests.request[i].msg), "%s", data);
|
||||||
|
|
||||||
if (i == FrndRequests.max_idx)
|
if (i == FrndRequests.max_idx) {
|
||||||
++FrndRequests.max_idx;
|
++FrndRequests.max_idx;
|
||||||
|
}
|
||||||
|
|
||||||
++FrndRequests.num_requests;
|
++FrndRequests.num_requests;
|
||||||
|
|
||||||
@ -198,11 +218,13 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
getyx(self->window, y, x);
|
getyx(self->window, y, x);
|
||||||
getmaxyx(self->window, y2, x2);
|
getmaxyx(self->window, y2, x2);
|
||||||
|
|
||||||
if (x2 <= 0 || y2 <= 0)
|
if (x2 <= 0 || y2 <= 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (ctx->pastemode && key == '\r')
|
if (ctx->pastemode && key == '\r') {
|
||||||
key = '\n';
|
key = '\n';
|
||||||
|
}
|
||||||
|
|
||||||
/* ignore non-menu related input if active */
|
/* ignore non-menu related input if active */
|
||||||
if (self->help->active) {
|
if (self->help->active) {
|
||||||
@ -215,8 +237,9 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (line_info_onKey(self, key))
|
if (line_info_onKey(self, key)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
input_handle(self, key, x, y, x2, y2);
|
input_handle(self, key, x, y, x2, y2);
|
||||||
|
|
||||||
@ -224,12 +247,14 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
if (ctx->len > 1 && ctx->line[0] == '/') {
|
if (ctx->len > 1 && ctx->line[0] == '/') {
|
||||||
int diff = -1;
|
int diff = -1;
|
||||||
|
|
||||||
if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0)
|
if (wcsncmp(ctx->line, L"/avatar ", wcslen(L"/avatar ")) == 0) {
|
||||||
diff = dir_match(self, m, ctx->line, L"/avatar");
|
diff = dir_match(self, m, ctx->line, L"/avatar");
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef PYTHON
|
#ifdef PYTHON
|
||||||
else if (wcsncmp(ctx->line, L"/run \"", wcslen(L"/run \"")) == 0)
|
else if (wcsncmp(ctx->line, L"/run ", wcslen(L"/run ")) == 0) {
|
||||||
diff = dir_match(self, m, ctx->line, L"/run");
|
diff = dir_match(self, m, ctx->line, L"/run");
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -240,8 +265,9 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
{"busy"},
|
{"busy"},
|
||||||
};
|
};
|
||||||
diff = complete_line(self, status_cmd_list, 3, 8);
|
diff = complete_line(self, status_cmd_list, 3, 8);
|
||||||
} else
|
} else {
|
||||||
diff = complete_line(self, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
|
diff = complete_line(self, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
if (diff != -1) {
|
if (diff != -1) {
|
||||||
if (x + diff > x2 - 1) {
|
if (x + diff > x2 - 1) {
|
||||||
@ -263,8 +289,9 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
|
|
||||||
char line[MAX_STR_SIZE] = {0};
|
char line[MAX_STR_SIZE] = {0};
|
||||||
|
|
||||||
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
|
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
|
||||||
memset(&line, 0, sizeof(line));
|
memset(&line, 0, sizeof(line));
|
||||||
|
}
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, PROMPT, 0, 0, "%s", line);
|
line_info_add(self, NULL, NULL, NULL, PROMPT, 0, 0, "%s", line);
|
||||||
execute(ctx->history, self, m, line, GLOBAL_COMMAND_MODE);
|
execute(ctx->history, self, m, line, GLOBAL_COMMAND_MODE);
|
||||||
@ -281,8 +308,9 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
|||||||
int x2, y2;
|
int x2, y2;
|
||||||
getmaxyx(self->window, y2, x2);
|
getmaxyx(self->window, y2, x2);
|
||||||
|
|
||||||
if (y2 <= 0 || x2 <= 0)
|
if (y2 <= 0 || x2 <= 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
@ -294,8 +322,9 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
curs_set(1);
|
curs_set(1);
|
||||||
|
|
||||||
if (ctx->len > 0)
|
if (ctx->len > 0) {
|
||||||
mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]);
|
mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]);
|
||||||
|
}
|
||||||
|
|
||||||
StatusBar *statusbar = self->stb;
|
StatusBar *statusbar = self->stb;
|
||||||
|
|
||||||
@ -303,7 +332,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
|||||||
wmove(statusbar->topline, 0, 0);
|
wmove(statusbar->topline, 0, 0);
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
TOX_CONNECTION connection = statusbar->connection;
|
Tox_Connection connection = statusbar->connection;
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
if (connection != TOX_CONNECTION_NONE) {
|
if (connection != TOX_CONNECTION_NONE) {
|
||||||
@ -311,7 +340,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
|||||||
const char *status_text = "ERROR";
|
const char *status_text = "ERROR";
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
TOX_USER_STATUS status = statusbar->status;
|
Tox_User_Status status = statusbar->status;
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
@ -375,8 +404,9 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
|||||||
statusbar->statusmsg_len = maxlen;
|
statusbar->statusmsg_len = maxlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (statusbar->statusmsg[0])
|
if (statusbar->statusmsg[0]) {
|
||||||
wprintw(statusbar->topline, " : %s", statusbar->statusmsg);
|
wprintw(statusbar->topline, " : %s", statusbar->statusmsg);
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
@ -391,19 +421,21 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
wnoutrefresh(self->window);
|
wnoutrefresh(self->window);
|
||||||
|
|
||||||
if (self->help->active)
|
if (self->help->active) {
|
||||||
help_onDraw(self);
|
help_onDraw(self);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnum, TOX_CONNECTION connection_status)
|
static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnum, Tox_Connection connection_status)
|
||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
char nick[TOX_MAX_NAME_LENGTH] = {0}; /* stop removing this initiation */
|
char nick[TOX_MAX_NAME_LENGTH] = {0}; /* stop removing this initiation */
|
||||||
get_nick_truncate(m, nick, friendnum);
|
get_nick_truncate(m, nick, friendnum);
|
||||||
|
|
||||||
if (!nick[0])
|
if (!nick[0]) {
|
||||||
snprintf(nick, sizeof(nick), "%s", UNKNOWN_NAME);
|
snprintf(nick, sizeof(nick), "%s", UNKNOWN_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
char timefrmt[TIME_STR_SIZE];
|
char timefrmt[TIME_STR_SIZE];
|
||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
@ -418,25 +450,27 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnu
|
|||||||
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg);
|
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg);
|
||||||
write_to_log(msg, nick, ctx->log, true);
|
write_to_log(msg, nick, ctx->log, true);
|
||||||
|
|
||||||
if (self->active_box != -1)
|
if (self->active_box != -1) {
|
||||||
box_notify2(self, user_log_in, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, self->active_box,
|
box_notify2(self, user_log_in, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, self->active_box,
|
||||||
"%s has come online", nick);
|
"%s has come online", nick);
|
||||||
else
|
} else {
|
||||||
box_notify(self, user_log_in, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, &self->active_box,
|
box_notify(self, user_log_in, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, &self->active_box,
|
||||||
"Toxic", "%s has come online", nick);
|
"Toxic", "%s has come online", nick);
|
||||||
|
}
|
||||||
} else if (connection_status == TOX_CONNECTION_NONE) {
|
} else if (connection_status == TOX_CONNECTION_NONE) {
|
||||||
msg = "has gone offline";
|
msg = "has gone offline";
|
||||||
line_info_add(self, timefrmt, nick, NULL, DISCONNECTION, 0, RED, msg);
|
line_info_add(self, timefrmt, nick, NULL, DISCONNECTION, 0, RED, msg);
|
||||||
write_to_log(msg, nick, ctx->log, true);
|
write_to_log(msg, nick, ctx->log, true);
|
||||||
|
|
||||||
if (self->active_box != -1)
|
if (self->active_box != -1) {
|
||||||
box_notify2(self, user_log_out, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, self->active_box,
|
box_notify2(self, user_log_out, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, self->active_box,
|
||||||
"%s has gone offline", nick);
|
"%s has gone offline", nick);
|
||||||
else
|
} else {
|
||||||
box_notify(self, user_log_out, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, &self->active_box,
|
box_notify(self, user_log_out, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, &self->active_box,
|
||||||
"Toxic", "%s has gone offline", nick);
|
"Toxic", "%s has gone offline", nick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, const char *data, size_t length)
|
static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, const char *data, size_t length)
|
||||||
{
|
{
|
||||||
@ -460,13 +494,14 @@ static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, con
|
|||||||
sound_notify(self, generic_message, NT_WNDALERT_1 | NT_NOTIFWND, NULL);
|
sound_notify(self, generic_message, NT_WNDALERT_1 | NT_NOTIFWND, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void prompt_init_statusbar(ToxWindow *self, Tox *m)
|
void prompt_init_statusbar(ToxWindow *self, Tox *m, bool first_time_run)
|
||||||
{
|
{
|
||||||
int x2, y2;
|
int x2, y2;
|
||||||
getmaxyx(self->window, y2, x2);
|
getmaxyx(self->window, y2, x2);
|
||||||
|
|
||||||
if (y2 <= 0 || x2 <= 0)
|
if (y2 <= 0 || x2 <= 0) {
|
||||||
exit_toxic_err("failed in prompt_init_statusbar", FATALERR_CURSES);
|
exit_toxic_err("failed in prompt_init_statusbar", FATALERR_CURSES);
|
||||||
|
}
|
||||||
|
|
||||||
(void) y2;
|
(void) y2;
|
||||||
|
|
||||||
@ -484,12 +519,12 @@ void prompt_init_statusbar(ToxWindow *self, Tox *m)
|
|||||||
size_t s_len = tox_self_get_status_message_size(m);
|
size_t s_len = tox_self_get_status_message_size(m);
|
||||||
tox_self_get_status_message(m, (uint8_t *) statusmsg);
|
tox_self_get_status_message(m, (uint8_t *) statusmsg);
|
||||||
|
|
||||||
TOX_USER_STATUS status = tox_self_get_status(m);
|
Tox_User_Status status = tox_self_get_status(m);
|
||||||
|
|
||||||
nick[n_len] = '\0';
|
nick[n_len] = '\0';
|
||||||
statusmsg[s_len] = '\0';
|
statusmsg[s_len] = '\0';
|
||||||
|
|
||||||
if (s_len == 0 || !strncmp(statusmsg, "Toxing on Toxic", strlen("Toxing on Toxic"))) {
|
if (first_time_run) {
|
||||||
snprintf(statusmsg, sizeof(statusmsg), "Toxing on Toxic");
|
snprintf(statusmsg, sizeof(statusmsg), "Toxing on Toxic");
|
||||||
s_len = strlen(statusmsg);
|
s_len = strlen(statusmsg);
|
||||||
statusmsg[s_len] = '\0';
|
statusmsg[s_len] = '\0';
|
||||||
@ -525,8 +560,9 @@ static void prompt_onInit(ToxWindow *self, Tox *m)
|
|||||||
int y2, x2;
|
int y2, x2;
|
||||||
getmaxyx(self->window, y2, x2);
|
getmaxyx(self->window, y2, x2);
|
||||||
|
|
||||||
if (y2 <= 0 || x2 <= 0)
|
if (y2 <= 0 || x2 <= 0) {
|
||||||
exit_toxic_err("failed in prompt_onInit", FATALERR_CURSES);
|
exit_toxic_err("failed in prompt_onInit", FATALERR_CURSES);
|
||||||
|
}
|
||||||
|
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
|
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
|
||||||
@ -535,8 +571,9 @@ static void prompt_onInit(ToxWindow *self, Tox *m)
|
|||||||
ctx->log = calloc(1, sizeof(struct chatlog));
|
ctx->log = calloc(1, sizeof(struct chatlog));
|
||||||
ctx->hst = calloc(1, sizeof(struct history));
|
ctx->hst = calloc(1, sizeof(struct history));
|
||||||
|
|
||||||
if (ctx->log == NULL || ctx->hst == NULL)
|
if (ctx->log == NULL || ctx->hst == NULL) {
|
||||||
exit_toxic_err("failed in prompt_onInit", FATALERR_MEMORY);
|
exit_toxic_err("failed in prompt_onInit", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
line_info_init(ctx->hst);
|
line_info_init(ctx->hst);
|
||||||
|
|
||||||
@ -544,46 +581,51 @@ static void prompt_onInit(ToxWindow *self, Tox *m)
|
|||||||
char myid[TOX_ADDRESS_SIZE];
|
char myid[TOX_ADDRESS_SIZE];
|
||||||
tox_self_get_address(m, (uint8_t *) myid);
|
tox_self_get_address(m, (uint8_t *) myid);
|
||||||
|
|
||||||
if (log_enable(self->name, myid, NULL, ctx->log, LOG_PROMPT) == -1)
|
if (log_enable(self->name, myid, NULL, ctx->log, LOG_PROMPT) == -1) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
scrollok(ctx->history, 0);
|
scrollok(ctx->history, 0);
|
||||||
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
||||||
|
|
||||||
if (user_settings->show_welcome_msg == SHOW_WELCOME_MSG_ON)
|
if (user_settings->show_welcome_msg == SHOW_WELCOME_MSG_ON) {
|
||||||
print_welcome_msg(self);
|
print_welcome_msg(self);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ToxWindow new_prompt(void)
|
ToxWindow *new_prompt(void)
|
||||||
{
|
{
|
||||||
ToxWindow ret;
|
ToxWindow *ret = calloc(1, sizeof(ToxWindow));
|
||||||
memset(&ret, 0, sizeof(ret));
|
|
||||||
|
|
||||||
ret.num = -1;
|
if (ret == NULL) {
|
||||||
ret.active = true;
|
exit_toxic_err("failed in new_prompt", FATALERR_MEMORY);
|
||||||
ret.is_prompt = true;
|
}
|
||||||
|
|
||||||
ret.onKey = &prompt_onKey;
|
ret->num = -1;
|
||||||
ret.onDraw = &prompt_onDraw;
|
ret->is_prompt = true;
|
||||||
ret.onInit = &prompt_onInit;
|
|
||||||
ret.onConnectionChange = &prompt_onConnectionChange;
|
|
||||||
ret.onFriendRequest = &prompt_onFriendRequest;
|
|
||||||
|
|
||||||
strcpy(ret.name, "home");
|
ret->onKey = &prompt_onKey;
|
||||||
|
ret->onDraw = &prompt_onDraw;
|
||||||
|
ret->onInit = &prompt_onInit;
|
||||||
|
ret->onConnectionChange = &prompt_onConnectionChange;
|
||||||
|
ret->onFriendRequest = &prompt_onFriendRequest;
|
||||||
|
|
||||||
|
strcpy(ret->name, "home");
|
||||||
|
|
||||||
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
|
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
|
||||||
StatusBar *stb = calloc(1, sizeof(StatusBar));
|
StatusBar *stb = calloc(1, sizeof(StatusBar));
|
||||||
Help *help = calloc(1, sizeof(Help));
|
Help *help = calloc(1, sizeof(Help));
|
||||||
|
|
||||||
if (stb == NULL || chatwin == NULL || help == NULL)
|
if (stb == NULL || chatwin == NULL || help == NULL) {
|
||||||
exit_toxic_err("failed in new_prompt", FATALERR_MEMORY);
|
exit_toxic_err("failed in new_prompt", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
ret.chatwin = chatwin;
|
ret->chatwin = chatwin;
|
||||||
ret.stb = stb;
|
ret->stb = stb;
|
||||||
ret.help = help;
|
ret->help = help;
|
||||||
|
|
||||||
ret.active_box = -1;
|
ret->active_box = -1;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
13
src/prompt.h
13
src/prompt.h
@ -40,17 +40,22 @@ typedef struct {
|
|||||||
struct friend_request request[MAX_FRIEND_REQUESTS];
|
struct friend_request request[MAX_FRIEND_REQUESTS];
|
||||||
} FriendRequests;
|
} FriendRequests;
|
||||||
|
|
||||||
ToxWindow new_prompt(void);
|
extern FriendRequests FrndRequests;
|
||||||
|
|
||||||
|
ToxWindow *new_prompt(void);
|
||||||
|
|
||||||
void prep_prompt_win(void);
|
void prep_prompt_win(void);
|
||||||
void prompt_init_statusbar(ToxWindow *self, Tox *m);
|
void prompt_init_statusbar(ToxWindow *self, Tox *m, bool first_time_run);
|
||||||
void prompt_update_nick(ToxWindow *prompt, const char *nick);
|
void prompt_update_nick(ToxWindow *prompt, const char *nick);
|
||||||
void prompt_update_statusmessage(ToxWindow *prompt, Tox *m, const char *statusmsg);
|
void prompt_update_statusmessage(ToxWindow *prompt, Tox *m, const char *statusmsg);
|
||||||
void prompt_update_status(ToxWindow *prompt, TOX_USER_STATUS status);
|
void prompt_update_status(ToxWindow *prompt, Tox_User_Status status);
|
||||||
void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected);
|
void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected);
|
||||||
void kill_prompt_window(ToxWindow *self);
|
void kill_prompt_window(ToxWindow *self);
|
||||||
|
|
||||||
/* callback: Updates own connection status in prompt statusbar */
|
/* callback: Updates own connection status in prompt statusbar */
|
||||||
void prompt_onSelfConnectionChange(Tox *m, TOX_CONNECTION connection_status, void *userdata);
|
void on_self_connection_status(Tox *m, Tox_Connection connection_status, void *userdata);
|
||||||
|
|
||||||
|
/* Returns our own connection status */
|
||||||
|
Tox_Connection prompt_selfConnectionStatus(void);
|
||||||
|
|
||||||
#endif /* end of include guard: PROMPT_H */
|
#endif /* end of include guard: PROMPT_H */
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#ifdef PYTHON
|
#ifdef PYTHON
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
#include "api.h"
|
#include "api.h"
|
||||||
#endif /* PYTHON */
|
|
||||||
|
|
||||||
#include "execute.h"
|
#include "execute.h"
|
||||||
|
|
||||||
@ -40,8 +39,9 @@ static PyObject *python_api_display(PyObject *self, PyObject *args)
|
|||||||
{
|
{
|
||||||
const char *msg;
|
const char *msg;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "s", &msg))
|
if (!PyArg_ParseTuple(args, "s", &msg)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
api_display(msg);
|
api_display(msg);
|
||||||
return Py_None;
|
return Py_None;
|
||||||
@ -52,13 +52,15 @@ static PyObject *python_api_get_nick(PyObject *self, PyObject *args)
|
|||||||
char *name;
|
char *name;
|
||||||
PyObject *ret;
|
PyObject *ret;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, ""))
|
if (!PyArg_ParseTuple(args, "")) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
name = api_get_nick();
|
name = api_get_nick();
|
||||||
|
|
||||||
if (name == NULL)
|
if (name == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
ret = Py_BuildValue("s", name);
|
ret = Py_BuildValue("s", name);
|
||||||
free(name);
|
free(name);
|
||||||
@ -67,10 +69,11 @@ static PyObject *python_api_get_nick(PyObject *self, PyObject *args)
|
|||||||
|
|
||||||
static PyObject *python_api_get_status(PyObject *self, PyObject *args)
|
static PyObject *python_api_get_status(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
PyObject *ret;
|
PyObject *ret = NULL;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, ""))
|
if (!PyArg_ParseTuple(args, "")) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
switch (api_get_status()) {
|
switch (api_get_status()) {
|
||||||
case TOX_USER_STATUS_NONE:
|
case TOX_USER_STATUS_NONE:
|
||||||
@ -94,13 +97,15 @@ static PyObject *python_api_get_status_message(PyObject *self, PyObject *args)
|
|||||||
char *status;
|
char *status;
|
||||||
PyObject *ret;
|
PyObject *ret;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, ""))
|
if (!PyArg_ParseTuple(args, "")) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
status = api_get_status_message();
|
status = api_get_status_message();
|
||||||
|
|
||||||
if (status == NULL)
|
if (status == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
ret = Py_BuildValue("s", status);
|
ret = Py_BuildValue("s", status);
|
||||||
free(status);
|
free(status);
|
||||||
@ -114,15 +119,17 @@ static PyObject *python_api_get_all_friends(PyObject *self, PyObject *args)
|
|||||||
PyObject *cur, *ret;
|
PyObject *cur, *ret;
|
||||||
char pubkey_buf[TOX_PUBLIC_KEY_SIZE * 2 + 1];
|
char pubkey_buf[TOX_PUBLIC_KEY_SIZE * 2 + 1];
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, ""))
|
if (!PyArg_ParseTuple(args, "")) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
friends = api_get_friendslist();
|
friends = api_get_friendslist();
|
||||||
ret = PyList_New(0);
|
ret = PyList_New(0);
|
||||||
|
|
||||||
for (i = 0; i < friends.num_friends; i++) {
|
for (i = 0; i < friends.num_friends; i++) {
|
||||||
for (ii = 0; ii < TOX_PUBLIC_KEY_SIZE; ii++)
|
for (ii = 0; ii < TOX_PUBLIC_KEY_SIZE; ii++) {
|
||||||
snprintf(pubkey_buf + ii * 2, 3, "%02X", friends.list[i].pub_key[ii] & 0xff);
|
snprintf(pubkey_buf + ii * 2, 3, "%02X", friends.list[i].pub_key[ii] & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
pubkey_buf[TOX_PUBLIC_KEY_SIZE * 2] = '\0';
|
pubkey_buf[TOX_PUBLIC_KEY_SIZE * 2] = '\0';
|
||||||
cur = Py_BuildValue("(s,s)", friends.list[i].name, pubkey_buf);
|
cur = Py_BuildValue("(s,s)", friends.list[i].name, pubkey_buf);
|
||||||
@ -136,8 +143,9 @@ static PyObject *python_api_send(PyObject *self, PyObject *args)
|
|||||||
{
|
{
|
||||||
const char *msg;
|
const char *msg;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "s", &msg))
|
if (!PyArg_ParseTuple(args, "s", &msg)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
api_send(msg);
|
api_send(msg);
|
||||||
return Py_None;
|
return Py_None;
|
||||||
@ -148,8 +156,9 @@ static PyObject *python_api_execute(PyObject *self, PyObject *args)
|
|||||||
int mode;
|
int mode;
|
||||||
const char *command;
|
const char *command;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "si", &command, &mode))
|
if (!PyArg_ParseTuple(args, "si", &command, &mode)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
api_execute(command, mode);
|
api_execute(command, mode);
|
||||||
return Py_None;
|
return Py_None;
|
||||||
@ -162,8 +171,9 @@ static PyObject *python_api_register(PyObject *self, PyObject *args)
|
|||||||
const char *command, *help;
|
const char *command, *help;
|
||||||
PyObject *callback;
|
PyObject *callback;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "ssO:register_command", &command, &help, &callback))
|
if (!PyArg_ParseTuple(args, "ssO:register_command", &command, &help, &callback)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (!PyCallable_Check(callback)) {
|
if (!PyCallable_Check(callback)) {
|
||||||
PyErr_SetString(PyExc_TypeError, "Calback parameter must be callable");
|
PyErr_SetString(PyExc_TypeError, "Calback parameter must be callable");
|
||||||
@ -187,21 +197,24 @@ static PyObject *python_api_register(PyObject *self, PyObject *args)
|
|||||||
Py_XINCREF(callback);
|
Py_XINCREF(callback);
|
||||||
cur->next = malloc(sizeof(struct python_registered_func));
|
cur->next = malloc(sizeof(struct python_registered_func));
|
||||||
|
|
||||||
if (cur->next == NULL)
|
if (cur->next == NULL) {
|
||||||
return PyErr_NoMemory();
|
return PyErr_NoMemory();
|
||||||
|
}
|
||||||
|
|
||||||
command_len = strlen(command);
|
command_len = strlen(command);
|
||||||
cur->next->name = malloc(command_len + 1);
|
cur->next->name = malloc(command_len + 1);
|
||||||
|
|
||||||
if (cur->next->name == NULL)
|
if (cur->next->name == NULL) {
|
||||||
return PyErr_NoMemory();
|
return PyErr_NoMemory();
|
||||||
|
}
|
||||||
|
|
||||||
strncpy(cur->next->name, command, command_len + 1);
|
strncpy(cur->next->name, command, command_len + 1);
|
||||||
help_len = strlen(help);
|
help_len = strlen(help);
|
||||||
cur->next->help = malloc(help_len + 1);
|
cur->next->help = malloc(help_len + 1);
|
||||||
|
|
||||||
if (cur->next->help == NULL)
|
if (cur->next->help == NULL) {
|
||||||
return PyErr_NoMemory();
|
return PyErr_NoMemory();
|
||||||
|
}
|
||||||
|
|
||||||
strncpy(cur->next->help, help, help_len + 1);
|
strncpy(cur->next->help, help, help_len + 1);
|
||||||
cur->next->callback = callback;
|
cur->next->callback = callback;
|
||||||
@ -253,8 +266,9 @@ void terminate_python(void)
|
|||||||
{
|
{
|
||||||
struct python_registered_func *cur, *old;
|
struct python_registered_func *cur, *old;
|
||||||
|
|
||||||
if (python_commands.name != NULL)
|
if (python_commands.name != NULL) {
|
||||||
free(python_commands.name);
|
free(python_commands.name);
|
||||||
|
}
|
||||||
|
|
||||||
for (cur = python_commands.next; cur != NULL;) {
|
for (cur = python_commands.next; cur != NULL;) {
|
||||||
old = cur;
|
old = cur;
|
||||||
@ -285,19 +299,22 @@ int do_python_command(int num_args, char (*args)[MAX_STR_SIZE])
|
|||||||
struct python_registered_func *cur;
|
struct python_registered_func *cur;
|
||||||
|
|
||||||
for (cur = &python_commands; cur != NULL; cur = cur->next) {
|
for (cur = &python_commands; cur != NULL; cur = cur->next) {
|
||||||
if (cur->name == NULL)
|
if (cur->name == NULL) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!strcmp(args[0], cur->name)) {
|
if (!strcmp(args[0], cur->name)) {
|
||||||
args_strings = PyList_New(0);
|
args_strings = PyList_New(0);
|
||||||
|
|
||||||
for (i = 1; i < num_args; i++)
|
for (i = 1; i < num_args; i++) {
|
||||||
PyList_Append(args_strings, Py_BuildValue("s", args[i]));
|
PyList_Append(args_strings, Py_BuildValue("s", args[i]));
|
||||||
|
}
|
||||||
|
|
||||||
callback_args = PyTuple_Pack(1, args_strings);
|
callback_args = PyTuple_Pack(1, args_strings);
|
||||||
|
|
||||||
if (PyObject_CallObject(cur->callback, callback_args) == NULL)
|
if (PyObject_CallObject(cur->callback, callback_args) == NULL) {
|
||||||
api_display("Exception raised in callback function");
|
api_display("Exception raised in callback function");
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -312,9 +329,10 @@ int python_num_registered_handlers(void)
|
|||||||
struct python_registered_func *cur;
|
struct python_registered_func *cur;
|
||||||
|
|
||||||
for (cur = &python_commands; cur != NULL; cur = cur->next) {
|
for (cur = &python_commands; cur != NULL; cur = cur->next) {
|
||||||
if (cur->name != NULL)
|
if (cur->name != NULL) {
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
@ -341,7 +359,9 @@ void python_draw_handler_help(WINDOW *win)
|
|||||||
struct python_registered_func *cur;
|
struct python_registered_func *cur;
|
||||||
|
|
||||||
for (cur = &python_commands; cur != NULL; cur = cur->next) {
|
for (cur = &python_commands; cur != NULL; cur = cur->next) {
|
||||||
if (cur->name != NULL)
|
if (cur->name != NULL) {
|
||||||
wprintw(win, " %-29s: %.50s\n", cur->name, cur->help);
|
wprintw(win, " %-29s: %.50s\n", cur->name, cur->help);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
#endif /* PYTHON */
|
||||||
|
@ -36,4 +36,4 @@ int python_num_registered_handlers(void);
|
|||||||
int python_help_max_width(void);
|
int python_help_max_width(void);
|
||||||
void python_draw_handler_help(WINDOW *win);
|
void python_draw_handler_help(WINDOW *win);
|
||||||
|
|
||||||
#endif /* #define PYTHON_API_H */
|
#endif /* PYTHON_API_H */
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifdef QRCODE
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <qrencode.h>
|
#include <qrencode.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@ -50,8 +52,9 @@ int ID_to_QRcode_txt(const char *tox_id, const char *outfile)
|
|||||||
{
|
{
|
||||||
FILE *fp = fopen(outfile, "wb");
|
FILE *fp = fopen(outfile, "wb");
|
||||||
|
|
||||||
if (fp == NULL)
|
if (fp == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
QRcode *qr_obj = QRcode_encodeString(tox_id, 0, QR_ECLEVEL_L, QR_MODE_8, 0);
|
QRcode *qr_obj = QRcode_encodeString(tox_id, 0, QR_ECLEVEL_L, QR_MODE_8, 0);
|
||||||
|
|
||||||
@ -63,14 +66,16 @@ int ID_to_QRcode_txt(const char *tox_id, const char *outfile)
|
|||||||
size_t width = qr_obj->width;
|
size_t width = qr_obj->width;
|
||||||
size_t i, j;
|
size_t i, j;
|
||||||
|
|
||||||
for (i = 0; i < width + BORDER_LEN * 2; ++i)
|
for (i = 0; i < width + BORDER_LEN * 2; ++i) {
|
||||||
fprintf(fp, "%s", CHAR_1);
|
fprintf(fp, "%s", CHAR_1);
|
||||||
|
}
|
||||||
|
|
||||||
fprintf(fp, "\n");
|
fprintf(fp, "\n");
|
||||||
|
|
||||||
for (i = 0; i < width; i += 2) {
|
for (i = 0; i < width; i += 2) {
|
||||||
for (j = 0; j < BORDER_LEN; ++j)
|
for (j = 0; j < BORDER_LEN; ++j) {
|
||||||
fprintf(fp, "%s", CHAR_1);
|
fprintf(fp, "%s", CHAR_1);
|
||||||
|
}
|
||||||
|
|
||||||
const unsigned char *row_1 = qr_obj->data + width * i;
|
const unsigned char *row_1 = qr_obj->data + width * i;
|
||||||
const unsigned char *row_2 = row_1 + width;
|
const unsigned char *row_2 = row_1 + width;
|
||||||
@ -79,18 +84,20 @@ int ID_to_QRcode_txt(const char *tox_id, const char *outfile)
|
|||||||
bool x = row_1[j] & 1;
|
bool x = row_1[j] & 1;
|
||||||
bool y = (i + 1) < width ? (row_2[j] & 1) : false;
|
bool y = (i + 1) < width ? (row_2[j] & 1) : false;
|
||||||
|
|
||||||
if (x && y)
|
if (x && y) {
|
||||||
fprintf(fp, " ");
|
fprintf(fp, " ");
|
||||||
else if (x)
|
} else if (x) {
|
||||||
fprintf(fp, "%s", CHAR_2);
|
fprintf(fp, "%s", CHAR_2);
|
||||||
else if (y)
|
} else if (y) {
|
||||||
fprintf(fp, "%s", CHAR_3);
|
fprintf(fp, "%s", CHAR_3);
|
||||||
else
|
} else {
|
||||||
fprintf(fp, "%s", CHAR_1);
|
fprintf(fp, "%s", CHAR_1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (j = 0; j < BORDER_LEN; ++j)
|
for (j = 0; j < BORDER_LEN; ++j) {
|
||||||
fprintf(fp, "%s", CHAR_1);
|
fprintf(fp, "%s", CHAR_1);
|
||||||
|
}
|
||||||
|
|
||||||
fprintf(fp, "\n");
|
fprintf(fp, "\n");
|
||||||
}
|
}
|
||||||
@ -208,3 +215,5 @@ int ID_to_QRcode_png(const char *tox_id, const char *outfile)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* QRPNG */
|
#endif /* QRPNG */
|
||||||
|
|
||||||
|
#endif /* QRCODE */
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
#ifndef QR_CODE
|
#ifndef QR_CODE
|
||||||
#define QR_CODE
|
#define QR_CODE
|
||||||
|
|
||||||
|
#ifdef QRCODE
|
||||||
|
|
||||||
#define QRCODE_FILENAME_EXT ".QRcode"
|
#define QRCODE_FILENAME_EXT ".QRcode"
|
||||||
|
|
||||||
/* Converts a tox ID string into a QRcode and prints it into the given filename.
|
/* Converts a tox ID string into a QRcode and prints it into the given filename.
|
||||||
@ -42,4 +44,6 @@ int ID_to_QRcode_txt(const char *tox_id, const char *outfile);
|
|||||||
int ID_to_QRcode_png(const char *tox_id, const char *outfile);
|
int ID_to_QRcode_png(const char *tox_id, const char *outfile);
|
||||||
#endif /* QRPNG */
|
#endif /* QRPNG */
|
||||||
|
|
||||||
|
#endif /* QRCODE */
|
||||||
|
|
||||||
#endif /* QR_CODE */
|
#endif /* QR_CODE */
|
||||||
|
@ -253,15 +253,18 @@ static int key_parse(const char **bind)
|
|||||||
int len = strlen(*bind);
|
int len = strlen(*bind);
|
||||||
|
|
||||||
if (len > 5) {
|
if (len > 5) {
|
||||||
if (strncasecmp(*bind, "ctrl+", 5) == 0 && toupper(bind[0][5]) != 'M') /* ctrl+m cannot be used */
|
if (strncasecmp(*bind, "ctrl+", 5) == 0 && toupper(bind[0][5]) != 'M') { /* ctrl+m cannot be used */
|
||||||
return toupper(bind[0][5]) - 'A' + 1;
|
return toupper(bind[0][5]) - 'A' + 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (strncasecmp(*bind, "tab", 3) == 0)
|
if (strncasecmp(*bind, "tab", 3) == 0) {
|
||||||
return T_KEY_TAB;
|
return T_KEY_TAB;
|
||||||
|
}
|
||||||
|
|
||||||
if (strncasecmp(*bind, "page", 4) == 0)
|
if (strncasecmp(*bind, "page", 4) == 0) {
|
||||||
return len == 6 ? KEY_PPAGE : KEY_NPAGE;
|
return len == 6 ? KEY_PPAGE : KEY_NPAGE;
|
||||||
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -304,8 +307,9 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
if (!file_exists(path)) {
|
if (!file_exists(path)) {
|
||||||
FILE *fp = fopen(path, "w");
|
FILE *fp = fopen(path, "w");
|
||||||
|
|
||||||
if (fp == NULL)
|
if (fp == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
@ -397,29 +401,32 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
int len = strlen(s->download_path);
|
int len = strlen(s->download_path);
|
||||||
|
|
||||||
/* make sure path ends with a '/' */
|
/* make sure path ends with a '/' */
|
||||||
if (len >= sizeof(s->download_path) - 2)
|
if (len >= sizeof(s->download_path) - 2) {
|
||||||
s->download_path[0] = '\0';
|
s->download_path[0] = '\0';
|
||||||
else if (s->download_path[len - 1] != '/')
|
} else if (s->download_path[len - 1] != '/') {
|
||||||
strcat(&s->download_path[len - 1], "/");
|
strcat(&s->download_path[len - 1], "/");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (config_setting_lookup_string(setting, tox_strings.chatlogs_path, &str)) {
|
if (config_setting_lookup_string(setting, tox_strings.chatlogs_path, &str)) {
|
||||||
snprintf(s->chatlogs_path, sizeof(s->chatlogs_path), "%s", str);
|
snprintf(s->chatlogs_path, sizeof(s->chatlogs_path), "%s", str);
|
||||||
int len = strlen(s->chatlogs_path);
|
int len = strlen(s->chatlogs_path);
|
||||||
|
|
||||||
if (len >= sizeof(s->chatlogs_path) - 2)
|
if (len >= sizeof(s->chatlogs_path) - 2) {
|
||||||
s->chatlogs_path[0] = '\0';
|
s->chatlogs_path[0] = '\0';
|
||||||
else if (s->chatlogs_path[len - 1] != '/')
|
} else if (s->chatlogs_path[len - 1] != '/') {
|
||||||
strcat(&s->chatlogs_path[len - 1], "/");
|
strcat(&s->chatlogs_path[len - 1], "/");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (config_setting_lookup_string(setting, tox_strings.avatar_path, &str)) {
|
if (config_setting_lookup_string(setting, tox_strings.avatar_path, &str)) {
|
||||||
snprintf(s->avatar_path, sizeof(s->avatar_path), "%s", str);
|
snprintf(s->avatar_path, sizeof(s->avatar_path), "%s", str);
|
||||||
int len = strlen(str);
|
int len = strlen(str);
|
||||||
|
|
||||||
if (len >= sizeof(s->avatar_path))
|
if (len >= sizeof(s->avatar_path)) {
|
||||||
s->avatar_path[0] = '\0';
|
s->avatar_path[0] = '\0';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef PYTHON
|
#ifdef PYTHON
|
||||||
|
|
||||||
@ -427,11 +434,12 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
snprintf(s->autorun_path, sizeof(s->autorun_path), "%s", str);
|
snprintf(s->autorun_path, sizeof(s->autorun_path), "%s", str);
|
||||||
int len = strlen(str);
|
int len = strlen(str);
|
||||||
|
|
||||||
if (len >= sizeof(s->autorun_path) - 2)
|
if (len >= sizeof(s->autorun_path) - 2) {
|
||||||
s->autorun_path[0] = '\0';
|
s->autorun_path[0] = '\0';
|
||||||
else if (s->autorun_path[len - 1] != '/')
|
} else if (s->autorun_path[len - 1] != '/') {
|
||||||
strcat(&s->autorun_path[len - 1], "/");
|
strcat(&s->autorun_path[len - 1], "/");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -439,48 +447,60 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
snprintf(s->password_eval, sizeof(s->password_eval), "%s", str);
|
snprintf(s->password_eval, sizeof(s->password_eval), "%s", str);
|
||||||
int len = strlen(str);
|
int len = strlen(str);
|
||||||
|
|
||||||
if (len >= sizeof(s->password_eval))
|
if (len >= sizeof(s->password_eval)) {
|
||||||
s->password_eval[0] = '\0';
|
s->password_eval[0] = '\0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* keys */
|
/* keys */
|
||||||
if ((setting = config_lookup(cfg, key_strings.self)) != NULL) {
|
if ((setting = config_lookup(cfg, key_strings.self)) != NULL) {
|
||||||
const char *tmp = NULL;
|
const char *tmp = NULL;
|
||||||
|
|
||||||
if (config_setting_lookup_string(setting, key_strings.next_tab, &tmp))
|
if (config_setting_lookup_string(setting, key_strings.next_tab, &tmp)) {
|
||||||
set_key_binding(&s->key_next_tab, &tmp);
|
set_key_binding(&s->key_next_tab, &tmp);
|
||||||
|
}
|
||||||
|
|
||||||
if (config_setting_lookup_string(setting, key_strings.prev_tab, &tmp))
|
if (config_setting_lookup_string(setting, key_strings.prev_tab, &tmp)) {
|
||||||
set_key_binding(&s->key_prev_tab, &tmp);
|
set_key_binding(&s->key_prev_tab, &tmp);
|
||||||
|
}
|
||||||
|
|
||||||
if (config_setting_lookup_string(setting, key_strings.scroll_line_up, &tmp))
|
if (config_setting_lookup_string(setting, key_strings.scroll_line_up, &tmp)) {
|
||||||
set_key_binding(&s->key_scroll_line_up, &tmp);
|
set_key_binding(&s->key_scroll_line_up, &tmp);
|
||||||
|
}
|
||||||
|
|
||||||
if (config_setting_lookup_string(setting, key_strings.scroll_line_down, &tmp))
|
if (config_setting_lookup_string(setting, key_strings.scroll_line_down, &tmp)) {
|
||||||
set_key_binding(&s->key_scroll_line_down, &tmp);
|
set_key_binding(&s->key_scroll_line_down, &tmp);
|
||||||
|
}
|
||||||
|
|
||||||
if (config_setting_lookup_string(setting, key_strings.half_page_up, &tmp))
|
if (config_setting_lookup_string(setting, key_strings.half_page_up, &tmp)) {
|
||||||
set_key_binding(&s->key_half_page_up, &tmp);
|
set_key_binding(&s->key_half_page_up, &tmp);
|
||||||
|
}
|
||||||
|
|
||||||
if (config_setting_lookup_string(setting, key_strings.half_page_down, &tmp))
|
if (config_setting_lookup_string(setting, key_strings.half_page_down, &tmp)) {
|
||||||
set_key_binding(&s->key_half_page_down, &tmp);
|
set_key_binding(&s->key_half_page_down, &tmp);
|
||||||
|
}
|
||||||
|
|
||||||
if (config_setting_lookup_string(setting, key_strings.page_bottom, &tmp))
|
if (config_setting_lookup_string(setting, key_strings.page_bottom, &tmp)) {
|
||||||
set_key_binding(&s->key_page_bottom, &tmp);
|
set_key_binding(&s->key_page_bottom, &tmp);
|
||||||
|
}
|
||||||
|
|
||||||
if (config_setting_lookup_string(setting, key_strings.peer_list_up, &tmp))
|
if (config_setting_lookup_string(setting, key_strings.peer_list_up, &tmp)) {
|
||||||
set_key_binding(&s->key_peer_list_up, &tmp);
|
set_key_binding(&s->key_peer_list_up, &tmp);
|
||||||
|
}
|
||||||
|
|
||||||
if (config_setting_lookup_string(setting, key_strings.peer_list_down, &tmp))
|
if (config_setting_lookup_string(setting, key_strings.peer_list_down, &tmp)) {
|
||||||
set_key_binding(&s->key_peer_list_down, &tmp);
|
set_key_binding(&s->key_peer_list_down, &tmp);
|
||||||
|
}
|
||||||
|
|
||||||
if (config_setting_lookup_string(setting, key_strings.toggle_peerlist, &tmp))
|
if (config_setting_lookup_string(setting, key_strings.toggle_peerlist, &tmp)) {
|
||||||
set_key_binding(&s->key_toggle_peerlist, &tmp);
|
set_key_binding(&s->key_toggle_peerlist, &tmp);
|
||||||
|
}
|
||||||
|
|
||||||
if (config_setting_lookup_string(setting, key_strings.toggle_pastemode, &tmp))
|
if (config_setting_lookup_string(setting, key_strings.toggle_pastemode, &tmp)) {
|
||||||
set_key_binding(&s->key_toggle_pastemode, &tmp);
|
set_key_binding(&s->key_toggle_pastemode, &tmp);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
|
|
||||||
@ -501,51 +521,59 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
if ((setting = config_lookup(cfg, sound_strings.self)) != NULL) {
|
if ((setting = config_lookup(cfg, sound_strings.self)) != NULL) {
|
||||||
if ((config_setting_lookup_string(setting, sound_strings.notif_error, &str) != CONFIG_TRUE) ||
|
if ((config_setting_lookup_string(setting, sound_strings.notif_error, &str) != CONFIG_TRUE) ||
|
||||||
!set_sound(notif_error, str)) {
|
!set_sound(notif_error, str)) {
|
||||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
if (str && strcasecmp(str, NO_SOUND) != 0) {
|
||||||
set_sound(notif_error, PACKAGE_DATADIR "/sounds/ToxicError.wav");
|
set_sound(notif_error, PACKAGE_DATADIR "/sounds/ToxicError.wav");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!config_setting_lookup_string(setting, sound_strings.user_log_in, &str) ||
|
if (!config_setting_lookup_string(setting, sound_strings.user_log_in, &str) ||
|
||||||
!set_sound(user_log_in, str)) {
|
!set_sound(user_log_in, str)) {
|
||||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
if (str && strcasecmp(str, NO_SOUND) != 0) {
|
||||||
set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ToxicContactOnline.wav");
|
set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ToxicContactOnline.wav");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!config_setting_lookup_string(setting, sound_strings.user_log_out, &str) ||
|
if (!config_setting_lookup_string(setting, sound_strings.user_log_out, &str) ||
|
||||||
!set_sound(user_log_out, str)) {
|
!set_sound(user_log_out, str)) {
|
||||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
if (str && strcasecmp(str, NO_SOUND) != 0) {
|
||||||
set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ToxicContactOffline.wav");
|
set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ToxicContactOffline.wav");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!config_setting_lookup_string(setting, sound_strings.call_incoming, &str) ||
|
if (!config_setting_lookup_string(setting, sound_strings.call_incoming, &str) ||
|
||||||
!set_sound(call_incoming, str)) {
|
!set_sound(call_incoming, str)) {
|
||||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
if (str && strcasecmp(str, NO_SOUND) != 0) {
|
||||||
set_sound(call_incoming, PACKAGE_DATADIR "/sounds/ToxicIncomingCall.wav");
|
set_sound(call_incoming, PACKAGE_DATADIR "/sounds/ToxicIncomingCall.wav");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!config_setting_lookup_string(setting, sound_strings.call_outgoing, &str) ||
|
if (!config_setting_lookup_string(setting, sound_strings.call_outgoing, &str) ||
|
||||||
!set_sound(call_outgoing, str)) {
|
!set_sound(call_outgoing, str)) {
|
||||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
if (str && strcasecmp(str, NO_SOUND) != 0) {
|
||||||
set_sound(call_outgoing, PACKAGE_DATADIR "/sounds/ToxicOutgoingCall.wav");
|
set_sound(call_outgoing, PACKAGE_DATADIR "/sounds/ToxicOutgoingCall.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)) {
|
!set_sound(generic_message, str)) {
|
||||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
if (str && strcasecmp(str, NO_SOUND) != 0) {
|
||||||
set_sound(generic_message, PACKAGE_DATADIR "/sounds/ToxicRecvMessage.wav");
|
set_sound(generic_message, PACKAGE_DATADIR "/sounds/ToxicRecvMessage.wav");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!config_setting_lookup_string(setting, sound_strings.transfer_pending, &str) ||
|
if (!config_setting_lookup_string(setting, sound_strings.transfer_pending, &str) ||
|
||||||
!set_sound(transfer_pending, str)) {
|
!set_sound(transfer_pending, str)) {
|
||||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
if (str && strcasecmp(str, NO_SOUND) != 0) {
|
||||||
set_sound(transfer_pending, PACKAGE_DATADIR "/sounds/ToxicTransferStart.wav");
|
set_sound(transfer_pending, PACKAGE_DATADIR "/sounds/ToxicTransferStart.wav");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!config_setting_lookup_string(setting, sound_strings.transfer_completed, &str) ||
|
if (!config_setting_lookup_string(setting, sound_strings.transfer_completed, &str) ||
|
||||||
!set_sound(transfer_completed, str)) {
|
!set_sound(transfer_completed, str)) {
|
||||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
if (str && strcasecmp(str, NO_SOUND) != 0) {
|
||||||
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/ToxicTransferComplete.wav");
|
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/ToxicTransferComplete.wav");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
set_sound(notif_error, PACKAGE_DATADIR "/sounds/ToxicError.wav");
|
set_sound(notif_error, PACKAGE_DATADIR "/sounds/ToxicError.wav");
|
||||||
set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ToxicContactOnline.wav");
|
set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ToxicContactOnline.wav");
|
||||||
|
@ -88,7 +88,7 @@ struct user_settings {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum settings_values {
|
||||||
AUTOLOG_OFF = 0,
|
AUTOLOG_OFF = 0,
|
||||||
AUTOLOG_ON = 1,
|
AUTOLOG_ON = 1,
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ enum {
|
|||||||
|
|
||||||
MPLEX_OFF = 0,
|
MPLEX_OFF = 0,
|
||||||
MPLEX_ON = 1,
|
MPLEX_ON = 1,
|
||||||
} settings_values;
|
};
|
||||||
|
|
||||||
#define LINE_JOIN "-->"
|
#define LINE_JOIN "-->"
|
||||||
#define LINE_QUIT "<--"
|
#define LINE_QUIT "<--"
|
||||||
@ -125,4 +125,5 @@ enum {
|
|||||||
#define MPLEX_AWAY_NOTE "Detached from screen"
|
#define MPLEX_AWAY_NOTE "Detached from screen"
|
||||||
|
|
||||||
int settings_load(struct user_settings *s, const char *patharg);
|
int settings_load(struct user_settings *s, const char *patharg);
|
||||||
#endif /* #define SETTINGS_H */
|
|
||||||
|
#endif /* SETTINGS_H */
|
||||||
|
136
src/term_mplex.c
136
src/term_mplex.c
@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
#include <tox/tox.h>
|
#include <tox/tox.h>
|
||||||
|
|
||||||
#include "global_commands.h"
|
#include "execute.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#include "term_mplex.h"
|
#include "term_mplex.h"
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
@ -69,7 +69,7 @@ static char buffer [BUFFER_SIZE];
|
|||||||
static bool auto_away_active = false;
|
static bool auto_away_active = false;
|
||||||
|
|
||||||
static mplex_status mplex = MPLEX_NONE;
|
static mplex_status mplex = MPLEX_NONE;
|
||||||
static TOX_USER_STATUS prev_status = TOX_USER_STATUS_NONE;
|
static Tox_User_Status prev_status = TOX_USER_STATUS_NONE;
|
||||||
static char prev_note [TOX_MAX_STATUS_MESSAGE_LENGTH] = "";
|
static char prev_note [TOX_MAX_STATUS_MESSAGE_LENGTH] = "";
|
||||||
|
|
||||||
/* mutex for access to status data, for sync between:
|
/* mutex for access to status data, for sync between:
|
||||||
@ -80,12 +80,12 @@ static char prev_note [TOX_MAX_STATUS_MESSAGE_LENGTH] = "";
|
|||||||
static pthread_mutex_t status_lock;
|
static pthread_mutex_t status_lock;
|
||||||
static pthread_t mplex_tid;
|
static pthread_t mplex_tid;
|
||||||
|
|
||||||
void lock_status ()
|
void lock_status(void)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&status_lock);
|
pthread_mutex_lock(&status_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void unlock_status ()
|
void unlock_status(void)
|
||||||
{
|
{
|
||||||
pthread_mutex_unlock(&status_lock);
|
pthread_mutex_unlock(&status_lock);
|
||||||
}
|
}
|
||||||
@ -99,10 +99,11 @@ static char *read_into_dyn_buffer (FILE *stream)
|
|||||||
while ((input_ptr = fgets(buffer, BUFFER_SIZE, stream)) != NULL) {
|
while ((input_ptr = fgets(buffer, BUFFER_SIZE, stream)) != NULL) {
|
||||||
int length = dyn_buffer_size + strlen(input_ptr);
|
int length = dyn_buffer_size + strlen(input_ptr);
|
||||||
|
|
||||||
if (dyn_buffer)
|
if (dyn_buffer) {
|
||||||
dyn_buffer = (char *) realloc(dyn_buffer, length);
|
dyn_buffer = (char *) realloc(dyn_buffer, length);
|
||||||
else
|
} else {
|
||||||
dyn_buffer = (char *) malloc(length);
|
dyn_buffer = (char *) malloc(length);
|
||||||
|
}
|
||||||
|
|
||||||
strcpy(dyn_buffer + dyn_buffer_size - 1, input_ptr);
|
strcpy(dyn_buffer + dyn_buffer_size - 1, input_ptr);
|
||||||
dyn_buffer_size = length;
|
dyn_buffer_size = length;
|
||||||
@ -118,32 +119,36 @@ static char *extract_socket_path (const char *info)
|
|||||||
char *end = NULL;
|
char *end = NULL;
|
||||||
char *path = NULL;
|
char *path = NULL;
|
||||||
|
|
||||||
if (!pos)
|
if (!pos) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
pos += strlen(search_str);
|
pos += strlen(search_str);
|
||||||
pos = strchr(pos, PATH_SEP_C);
|
pos = strchr(pos, PATH_SEP_C);
|
||||||
|
|
||||||
if (!pos)
|
if (!pos) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
end = strchr(pos, '\n');
|
end = strchr(pos, '\n');
|
||||||
|
|
||||||
if (!end)
|
if (!end) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
*end = '\0';
|
*end = '\0';
|
||||||
end = strrchr(pos, '.');
|
end = strrchr(pos, '.');
|
||||||
|
|
||||||
if (!end)
|
if (!end) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
path = (char *) malloc(end - pos + 1);
|
path = (char *) malloc(end - pos + 1);
|
||||||
*end = '\0';
|
*end = '\0';
|
||||||
return strcpy(path, pos);
|
return strcpy(path, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int detect_gnu_screen ()
|
static int detect_gnu_screen(void)
|
||||||
{
|
{
|
||||||
FILE *session_info_stream = NULL;
|
FILE *session_info_stream = NULL;
|
||||||
char *socket_name = NULL, *socket_path = NULL;
|
char *socket_name = NULL, *socket_path = NULL;
|
||||||
@ -151,32 +156,37 @@ static int detect_gnu_screen ()
|
|||||||
|
|
||||||
socket_name = getenv("STY");
|
socket_name = getenv("STY");
|
||||||
|
|
||||||
if (!socket_name)
|
if (!socket_name) {
|
||||||
goto nomplex;
|
goto nomplex;
|
||||||
|
}
|
||||||
|
|
||||||
session_info_stream = popen("env LC_ALL=C screen -ls", "r");
|
session_info_stream = popen("env LC_ALL=C screen -ls", "r");
|
||||||
|
|
||||||
if (!session_info_stream)
|
if (!session_info_stream) {
|
||||||
goto nomplex;
|
goto nomplex;
|
||||||
|
}
|
||||||
|
|
||||||
dyn_buffer = read_into_dyn_buffer(session_info_stream);
|
dyn_buffer = read_into_dyn_buffer(session_info_stream);
|
||||||
|
|
||||||
if (!dyn_buffer)
|
if (!dyn_buffer) {
|
||||||
goto nomplex;
|
goto nomplex;
|
||||||
|
}
|
||||||
|
|
||||||
pclose(session_info_stream);
|
pclose(session_info_stream);
|
||||||
session_info_stream = NULL;
|
session_info_stream = NULL;
|
||||||
|
|
||||||
socket_path = extract_socket_path(dyn_buffer);
|
socket_path = extract_socket_path(dyn_buffer);
|
||||||
|
|
||||||
if (!socket_path)
|
if (!socket_path) {
|
||||||
goto nomplex;
|
goto nomplex;
|
||||||
|
}
|
||||||
|
|
||||||
free(dyn_buffer);
|
free(dyn_buffer);
|
||||||
dyn_buffer = NULL;
|
dyn_buffer = NULL;
|
||||||
|
|
||||||
if (strlen(socket_path) + strlen(PATH_SEP_S) + strlen(socket_name) >= sizeof(mplex_data))
|
if (strlen(socket_path) + strlen(PATH_SEP_S) + strlen(socket_name) >= sizeof(mplex_data)) {
|
||||||
goto nomplex;
|
goto nomplex;
|
||||||
|
}
|
||||||
|
|
||||||
strcpy(mplex_data, socket_path);
|
strcpy(mplex_data, socket_path);
|
||||||
strcat(mplex_data, PATH_SEP_S);
|
strcat(mplex_data, PATH_SEP_S);
|
||||||
@ -189,30 +199,35 @@ static int detect_gnu_screen ()
|
|||||||
|
|
||||||
nomplex:
|
nomplex:
|
||||||
|
|
||||||
if (session_info_stream)
|
if (session_info_stream) {
|
||||||
pclose(session_info_stream);
|
pclose(session_info_stream);
|
||||||
|
}
|
||||||
|
|
||||||
if (dyn_buffer)
|
if (dyn_buffer) {
|
||||||
free(dyn_buffer);
|
free(dyn_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
if (socket_path)
|
if (socket_path) {
|
||||||
free(socket_path);
|
free(socket_path);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int detect_tmux ()
|
static int detect_tmux(void)
|
||||||
{
|
{
|
||||||
char *tmux_env = getenv("TMUX"), *pos;
|
char *tmux_env = getenv("TMUX"), *pos;
|
||||||
|
|
||||||
if (!tmux_env)
|
if (!tmux_env) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* find second separator */
|
/* find second separator */
|
||||||
pos = strrchr(tmux_env, ',');
|
pos = strrchr(tmux_env, ',');
|
||||||
|
|
||||||
if (!pos)
|
if (!pos) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* store the session id for later use */
|
/* store the session id for later use */
|
||||||
snprintf(mplex_data, sizeof(mplex_data), "$%s", pos + 1);
|
snprintf(mplex_data, sizeof(mplex_data), "$%s", pos + 1);
|
||||||
@ -228,7 +243,7 @@ static int detect_tmux ()
|
|||||||
Returns 1 if present, 0 otherwise. This value can be used to determine
|
Returns 1 if present, 0 otherwise. This value can be used to determine
|
||||||
whether an auto-away detection timer is needed.
|
whether an auto-away detection timer is needed.
|
||||||
*/
|
*/
|
||||||
static int detect_mplex ()
|
static int detect_mplex(void)
|
||||||
{
|
{
|
||||||
/* try screen, and if fails try tmux */
|
/* try screen, and if fails try tmux */
|
||||||
return detect_gnu_screen() || detect_tmux();
|
return detect_gnu_screen() || detect_tmux();
|
||||||
@ -237,15 +252,17 @@ static int detect_mplex ()
|
|||||||
/* Detects gnu screen session attached/detached by examining permissions of
|
/* Detects gnu screen session attached/detached by examining permissions of
|
||||||
the session's unix socket.
|
the session's unix socket.
|
||||||
*/
|
*/
|
||||||
static int gnu_screen_is_detached ()
|
static int gnu_screen_is_detached(void)
|
||||||
{
|
{
|
||||||
if (mplex != MPLEX_SCREEN)
|
if (mplex != MPLEX_SCREEN) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
|
|
||||||
if (stat (mplex_data, &sb) != 0)
|
if (stat(mplex_data, &sb) != 0) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* execution permission (x) means attached */
|
/* execution permission (x) means attached */
|
||||||
return !(sb.st_mode & S_IXUSR);
|
return !(sb.st_mode & S_IXUSR);
|
||||||
@ -254,10 +271,11 @@ static int gnu_screen_is_detached ()
|
|||||||
/* Detects tmux attached/detached by getting session data and finding the
|
/* Detects tmux attached/detached by getting session data and finding the
|
||||||
current session's entry.
|
current session's entry.
|
||||||
*/
|
*/
|
||||||
static int tmux_is_detached ()
|
static int tmux_is_detached(void)
|
||||||
{
|
{
|
||||||
if (mplex != MPLEX_TMUX)
|
if (mplex != MPLEX_TMUX) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
FILE *session_info_stream = NULL;
|
FILE *session_info_stream = NULL;
|
||||||
char *dyn_buffer = NULL, *search_str = NULL;
|
char *dyn_buffer = NULL, *search_str = NULL;
|
||||||
@ -268,13 +286,15 @@ static int tmux_is_detached ()
|
|||||||
/* get the number of attached clients for each session */
|
/* get the number of attached clients for each session */
|
||||||
session_info_stream = popen("tmux list-sessions -F \"#{session_id} #{session_attached}\"", "r");
|
session_info_stream = popen("tmux list-sessions -F \"#{session_id} #{session_attached}\"", "r");
|
||||||
|
|
||||||
if (!session_info_stream)
|
if (!session_info_stream) {
|
||||||
goto fail;
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
dyn_buffer = read_into_dyn_buffer(session_info_stream);
|
dyn_buffer = read_into_dyn_buffer(session_info_stream);
|
||||||
|
|
||||||
if (!dyn_buffer)
|
if (!dyn_buffer) {
|
||||||
goto fail;
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
pclose(session_info_stream);
|
pclose(session_info_stream);
|
||||||
session_info_stream = NULL;
|
session_info_stream = NULL;
|
||||||
@ -285,13 +305,15 @@ static int tmux_is_detached ()
|
|||||||
strcpy(search_str + 1, mplex_data);
|
strcpy(search_str + 1, mplex_data);
|
||||||
|
|
||||||
/* do the search */
|
/* do the search */
|
||||||
if (strncmp (dyn_buffer, search_str + 1, numstr_len) == 0)
|
if (strncmp(dyn_buffer, search_str + 1, numstr_len) == 0) {
|
||||||
entry_pos = dyn_buffer;
|
entry_pos = dyn_buffer;
|
||||||
else
|
} else {
|
||||||
entry_pos = strstr(dyn_buffer, search_str);
|
entry_pos = strstr(dyn_buffer, search_str);
|
||||||
|
}
|
||||||
|
|
||||||
if (! entry_pos)
|
if (! entry_pos) {
|
||||||
goto fail;
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
entry_pos = strchr(entry_pos, ' ') + 1;
|
entry_pos = strchr(entry_pos, ' ') + 1;
|
||||||
detached = strncmp(entry_pos, "0\n", 2) == 0;
|
detached = strncmp(entry_pos, "0\n", 2) == 0;
|
||||||
@ -306,14 +328,17 @@ static int tmux_is_detached ()
|
|||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
|
||||||
if (session_info_stream)
|
if (session_info_stream) {
|
||||||
pclose(session_info_stream);
|
pclose(session_info_stream);
|
||||||
|
}
|
||||||
|
|
||||||
if (dyn_buffer)
|
if (dyn_buffer) {
|
||||||
free(dyn_buffer);
|
free(dyn_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
if (search_str)
|
if (search_str) {
|
||||||
free(search_str);
|
free(search_str);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -327,18 +352,19 @@ fail:
|
|||||||
sample its state and update away status according to attached/detached state
|
sample its state and update away status according to attached/detached state
|
||||||
of the mplex.
|
of the mplex.
|
||||||
*/
|
*/
|
||||||
static int mplex_is_detached ()
|
static int mplex_is_detached(void)
|
||||||
{
|
{
|
||||||
return gnu_screen_is_detached() || tmux_is_detached();
|
return gnu_screen_is_detached() || tmux_is_detached();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mplex_timer_handler(Tox *m)
|
static void mplex_timer_handler(Tox *m)
|
||||||
{
|
{
|
||||||
TOX_USER_STATUS current_status, new_status;
|
Tox_User_Status current_status, new_status;
|
||||||
const char *new_note;
|
const char *new_note;
|
||||||
|
|
||||||
if (mplex == MPLEX_NONE)
|
if (mplex == MPLEX_NONE) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int detached = mplex_is_detached();
|
int detached = mplex_is_detached();
|
||||||
|
|
||||||
@ -360,18 +386,20 @@ static void mplex_timer_handler (Tox *m)
|
|||||||
prev_note[slen] = '\0';
|
prev_note[slen] = '\0';
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
new_note = user_settings->mplex_away_note;
|
new_note = user_settings->mplex_away_note;
|
||||||
} else
|
} else {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char status_str[MAX_STR_SIZE];
|
||||||
|
char note_str[MAX_STR_SIZE];
|
||||||
|
const char *status = new_status == TOX_USER_STATUS_AWAY ? "away" :
|
||||||
|
new_status == TOX_USER_STATUS_BUSY ? "busy" : "online";
|
||||||
|
snprintf(status_str, sizeof(status_str), "/status %s", status);
|
||||||
|
snprintf(note_str, sizeof(status_str), "/note %s", new_note);
|
||||||
|
|
||||||
char argv[3][MAX_STR_SIZE];
|
|
||||||
strcpy (argv[0], "/status");
|
|
||||||
strcpy (argv[1], (new_status == TOX_USER_STATUS_AWAY ? "away" :
|
|
||||||
new_status == TOX_USER_STATUS_BUSY ? "busy" : "online"));
|
|
||||||
argv[2][0] = '\"';
|
|
||||||
strcpy (argv[2] + 1, new_note);
|
|
||||||
strcat (argv[2], "\"");
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
cmd_status (prompt->chatwin->history, prompt, m, 2, argv);
|
execute(prompt->chatwin->history, prompt, m, status_str, GLOBAL_COMMAND_MODE);
|
||||||
|
execute(prompt->chatwin->history, prompt, m, note_str, GLOBAL_COMMAND_MODE);
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,18 +418,22 @@ void *mplex_timer_thread(void *data)
|
|||||||
|
|
||||||
int init_mplex_away_timer(Tox *m)
|
int init_mplex_away_timer(Tox *m)
|
||||||
{
|
{
|
||||||
if (! detect_mplex ())
|
if (! detect_mplex()) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (! user_settings->mplex_away)
|
if (! user_settings->mplex_away) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* status access mutex */
|
/* status access mutex */
|
||||||
if (pthread_mutex_init (&status_lock, NULL) != 0)
|
if (pthread_mutex_init(&status_lock, NULL) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (pthread_create(&mplex_tid, NULL, mplex_timer_thread, (void *) m) != 0)
|
if (pthread_create(&mplex_tid, NULL, mplex_timer_thread, (void *) m) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -24,12 +24,12 @@
|
|||||||
#define TERM_MPLEX_H
|
#define TERM_MPLEX_H
|
||||||
|
|
||||||
/* Checks if Toxic runs inside a terminal multiplexer (GNU screen or tmux). If
|
/* Checks if Toxic runs inside a terminal multiplexer (GNU screen or tmux). If
|
||||||
yes, it initializes a timer which periodically checks the attached/detached
|
* yes, it initializes a timer which periodically checks the attached/detached
|
||||||
state of the terminal and updates away status accordingly.
|
* state of the terminal and updates away status accordingly.
|
||||||
*/
|
*/
|
||||||
int init_mplex_away_timer(Tox *m);
|
int init_mplex_away_timer(Tox *m);
|
||||||
|
|
||||||
void lock_status ();
|
void lock_status(void);
|
||||||
void unlock_status ();
|
void unlock_status(void);
|
||||||
|
|
||||||
#endif /* #define TERM_MPLEX_H */
|
#endif /* TERM_MPLEX_H */
|
||||||
|
313
src/toxic.c
313
src/toxic.c
@ -52,6 +52,7 @@
|
|||||||
#include "friendlist.h"
|
#include "friendlist.h"
|
||||||
#include "prompt.h"
|
#include "prompt.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
|
#include "groupchat.h"
|
||||||
#include "file_transfers.h"
|
#include "file_transfers.h"
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
@ -228,9 +229,10 @@ static void init_term(void)
|
|||||||
start_color();
|
start_color();
|
||||||
|
|
||||||
if (user_settings->colour_theme == NATIVE_COLS) {
|
if (user_settings->colour_theme == NATIVE_COLS) {
|
||||||
if (assume_default_colors(-1, -1) == OK)
|
if (assume_default_colors(-1, -1) == OK) {
|
||||||
bg_color = -1;
|
bg_color = -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
init_pair(0, COLOR_WHITE, COLOR_BLACK);
|
init_pair(0, COLOR_WHITE, COLOR_BLACK);
|
||||||
init_pair(1, COLOR_GREEN, bg_color);
|
init_pair(1, COLOR_GREEN, bg_color);
|
||||||
@ -266,13 +268,15 @@ static void queue_init_message(const char *msg, ...)
|
|||||||
|
|
||||||
char **new_msgs = realloc(init_messages.msgs, sizeof(char *) * init_messages.num);
|
char **new_msgs = realloc(init_messages.msgs, sizeof(char *) * init_messages.num);
|
||||||
|
|
||||||
if (new_msgs == NULL)
|
if (new_msgs == NULL) {
|
||||||
exit_toxic_err("Failed in queue_init_message", FATALERR_MEMORY);
|
exit_toxic_err("Failed in queue_init_message", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
new_msgs[i] = malloc(MAX_STR_SIZE);
|
new_msgs[i] = malloc(MAX_STR_SIZE);
|
||||||
|
|
||||||
if (new_msgs[i] == NULL)
|
if (new_msgs[i] == NULL) {
|
||||||
exit_toxic_err("Failed in queue_init_message", FATALERR_MEMORY);
|
exit_toxic_err("Failed in queue_init_message", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(new_msgs[i], MAX_STR_SIZE, "%s", frmt_msg);
|
snprintf(new_msgs[i], MAX_STR_SIZE, "%s", frmt_msg);
|
||||||
init_messages.msgs = new_msgs;
|
init_messages.msgs = new_msgs;
|
||||||
@ -281,13 +285,15 @@ static void queue_init_message(const char *msg, ...)
|
|||||||
/* called after messages have been printed to prompt and are no longer needed */
|
/* called after messages have been printed to prompt and are no longer needed */
|
||||||
static void cleanup_init_messages(void)
|
static void cleanup_init_messages(void)
|
||||||
{
|
{
|
||||||
if (init_messages.num <= 0)
|
if (init_messages.num <= 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < init_messages.num; ++i)
|
for (i = 0; i < init_messages.num; ++i) {
|
||||||
free(init_messages.msgs[i]);
|
free(init_messages.msgs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
free(init_messages.msgs);
|
free(init_messages.msgs);
|
||||||
}
|
}
|
||||||
@ -296,21 +302,56 @@ static void print_init_messages(ToxWindow *toxwin)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < init_messages.num; ++i)
|
for (i = 0; i < init_messages.num; ++i) {
|
||||||
line_info_add(toxwin, NULL, NULL, NULL, SYS_MSG, 0, 0, init_messages.msgs[i]);
|
line_info_add(toxwin, NULL, NULL, NULL, SYS_MSG, 0, 0, init_messages.msgs[i]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void load_friendlist(Tox *m)
|
static void load_friendlist(Tox *m)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
size_t numfriends = tox_self_get_friend_list_size(m);
|
size_t numfriends = tox_self_get_friend_list_size(m);
|
||||||
|
|
||||||
for (i = 0; i < numfriends; ++i)
|
for (i = 0; i < numfriends; ++i) {
|
||||||
friendlist_onFriendAdded(NULL, m, i, false);
|
friendlist_onFriendAdded(NULL, m, i, false);
|
||||||
|
}
|
||||||
|
|
||||||
sort_friendlist_index();
|
sort_friendlist_index();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void load_groups(ToxWindow *prompt, Tox *m)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
size_t num_chats = tox_conference_get_chatlist_size(m);
|
||||||
|
uint32_t chatlist[num_chats];
|
||||||
|
|
||||||
|
if (num_chats) {
|
||||||
|
tox_conference_get_chatlist(m, chatlist);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < num_chats; ++i) {
|
||||||
|
uint32_t groupnum = chatlist[i];
|
||||||
|
|
||||||
|
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
|
||||||
|
tox_conference_delete(m, groupnum, NULL);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tox_Err_Conference_Get_Type err;
|
||||||
|
Tox_Conference_Type type = tox_conference_get_type(m, groupnum, &err);
|
||||||
|
|
||||||
|
if (err != TOX_ERR_CONFERENCE_GET_TYPE_OK) {
|
||||||
|
tox_conference_delete(m, groupnum, NULL);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (init_groupchat_win(prompt, m, groupnum, type) == -1) {
|
||||||
|
tox_conference_delete(m, groupnum, NULL);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* return length of password on success, 0 on failure */
|
/* return length of password on success, 0 on failure */
|
||||||
static int password_prompt(char *buf, int size)
|
static int password_prompt(char *buf, int size)
|
||||||
{
|
{
|
||||||
@ -323,8 +364,9 @@ static int password_prompt(char *buf, int size)
|
|||||||
nflags.c_lflag &= ~ECHO;
|
nflags.c_lflag &= ~ECHO;
|
||||||
nflags.c_lflag |= ECHONL;
|
nflags.c_lflag |= ECHONL;
|
||||||
|
|
||||||
if (tcsetattr(fileno(stdin), TCSANOW, &nflags) != 0)
|
if (tcsetattr(fileno(stdin), TCSANOW, &nflags) != 0) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const char *p = fgets(buf, size, stdin);
|
const char *p = fgets(buf, size, stdin);
|
||||||
int len = strlen(buf);
|
int len = strlen(buf);
|
||||||
@ -332,15 +374,16 @@ static int password_prompt(char *buf, int size)
|
|||||||
/* re-enable terminal echo */
|
/* re-enable terminal echo */
|
||||||
tcsetattr(fileno(stdin), TCSANOW, &oflags);
|
tcsetattr(fileno(stdin), TCSANOW, &oflags);
|
||||||
|
|
||||||
if (p == NULL || len <= 1)
|
if (p == NULL || len <= 1) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* eat overflowed stdin and return error */
|
/* eat overflowed stdin and return error */
|
||||||
if (buf[--len] != '\n') {
|
if (buf[--len] != '\n') {
|
||||||
int ch;
|
int ch;
|
||||||
|
|
||||||
while ((ch = getchar()) != '\n' && ch > 0)
|
while ((ch = getchar()) != '\n' && ch > 0) {
|
||||||
;
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -403,15 +446,17 @@ static void first_time_encrypt(const char *msg)
|
|||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
||||||
if (!strcasecmp(ch, "y\n") || !strcasecmp(ch, "n\n") || !strcasecmp(ch, "yes\n")
|
if (!strcasecmp(ch, "y\n") || !strcasecmp(ch, "n\n") || !strcasecmp(ch, "yes\n")
|
||||||
|| !strcasecmp(ch, "no\n") || !strcasecmp(ch, "q\n"))
|
|| !strcasecmp(ch, "no\n") || !strcasecmp(ch, "q\n")) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
} while (fgets(ch, sizeof(ch), stdin));
|
} while (fgets(ch, sizeof(ch), stdin));
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
if (ch[0] == 'q' || ch[0] == 'Q')
|
if (ch[0] == 'q' || ch[0] == 'Q') {
|
||||||
exit(0);
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
if (ch[0] == 'y' || ch[0] == 'Y') {
|
if (ch[0] == 'y' || ch[0] == 'Y') {
|
||||||
int len = 0;
|
int len = 0;
|
||||||
@ -425,8 +470,9 @@ static void first_time_encrypt(const char *msg)
|
|||||||
len = password_prompt(user_password.pass, sizeof(user_password.pass));
|
len = password_prompt(user_password.pass, sizeof(user_password.pass));
|
||||||
user_password.len = len;
|
user_password.len = len;
|
||||||
|
|
||||||
if (strcasecmp(user_password.pass, "q") == 0)
|
if (strcasecmp(user_password.pass, "q") == 0) {
|
||||||
exit(0);
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
if (string_is_empty(passconfirm) && (len < MIN_PASSWORD_LEN || len > MAX_PASSWORD_LEN)) {
|
if (string_is_empty(passconfirm) && (len < MIN_PASSWORD_LEN || len > MAX_PASSWORD_LEN)) {
|
||||||
printf("Password must be between %d and %d characters long. ", MIN_PASSWORD_LEN, MAX_PASSWORD_LEN);
|
printf("Password must be between %d and %d characters long. ", MIN_PASSWORD_LEN, MAX_PASSWORD_LEN);
|
||||||
@ -540,22 +586,23 @@ int store_data(Tox *m, const char *path)
|
|||||||
|
|
||||||
static void init_tox_callbacks(Tox *m)
|
static void init_tox_callbacks(Tox *m)
|
||||||
{
|
{
|
||||||
tox_callback_self_connection_status(m, prompt_onSelfConnectionChange);
|
tox_callback_self_connection_status(m, on_self_connection_status);
|
||||||
tox_callback_friend_connection_status(m, on_connectionchange);
|
tox_callback_friend_connection_status(m, on_friend_connection_status);
|
||||||
tox_callback_friend_typing(m, on_typing_change);
|
tox_callback_friend_typing(m, on_friend_typing);
|
||||||
tox_callback_friend_request(m, on_request);
|
tox_callback_friend_request(m, on_friend_request);
|
||||||
tox_callback_friend_message(m, on_message);
|
tox_callback_friend_message(m, on_friend_message);
|
||||||
tox_callback_friend_name(m, on_nickchange);
|
tox_callback_friend_name(m, on_friend_name);
|
||||||
tox_callback_friend_status(m, on_statuschange);
|
tox_callback_friend_status(m, on_friend_status);
|
||||||
tox_callback_friend_status_message(m, on_statusmessagechange);
|
tox_callback_friend_status_message(m, on_friend_status_message);
|
||||||
tox_callback_friend_read_receipt(m, on_read_receipt);
|
tox_callback_friend_read_receipt(m, on_friend_read_receipt);
|
||||||
tox_callback_conference_invite(m, on_groupinvite);
|
tox_callback_conference_invite(m, on_conference_invite);
|
||||||
tox_callback_conference_message(m, on_groupmessage);
|
tox_callback_conference_message(m, on_conference_message);
|
||||||
tox_callback_conference_namelist_change(m, on_group_namelistchange);
|
tox_callback_conference_peer_list_changed(m, on_conference_peer_list_changed);
|
||||||
tox_callback_conference_title(m, on_group_titlechange);
|
tox_callback_conference_peer_name(m, on_conference_peer_name);
|
||||||
|
tox_callback_conference_title(m, on_conference_title);
|
||||||
tox_callback_file_recv(m, on_file_recv);
|
tox_callback_file_recv(m, on_file_recv);
|
||||||
tox_callback_file_chunk_request(m, on_file_chunk_request);
|
tox_callback_file_chunk_request(m, on_file_chunk_request);
|
||||||
tox_callback_file_recv_control(m, on_file_control);
|
tox_callback_file_recv_control(m, on_file_recv_control);
|
||||||
tox_callback_file_recv_chunk(m, on_file_recv_chunk);
|
tox_callback_file_recv_chunk(m, on_file_recv_chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -563,30 +610,32 @@ static void init_tox_options(struct Tox_Options *tox_opts)
|
|||||||
{
|
{
|
||||||
tox_options_default(tox_opts);
|
tox_options_default(tox_opts);
|
||||||
|
|
||||||
tox_opts->ipv6_enabled = !arg_opts.use_ipv4;
|
tox_options_set_ipv6_enabled(tox_opts, !arg_opts.use_ipv4);
|
||||||
tox_opts->udp_enabled = !arg_opts.force_tcp;
|
tox_options_set_udp_enabled(tox_opts, !arg_opts.force_tcp);
|
||||||
tox_opts->proxy_type = arg_opts.proxy_type;
|
tox_options_set_proxy_type(tox_opts, arg_opts.proxy_type);
|
||||||
tox_opts->tcp_port = arg_opts.tcp_port;
|
tox_options_set_tcp_port(tox_opts, arg_opts.tcp_port);
|
||||||
|
|
||||||
if (!tox_opts->ipv6_enabled)
|
if (!tox_options_get_ipv6_enabled(tox_opts)) {
|
||||||
queue_init_message("Forcing IPv4 connection");
|
queue_init_message("Forcing IPv4 connection");
|
||||||
|
}
|
||||||
|
|
||||||
if (tox_opts->tcp_port)
|
if (tox_options_get_tcp_port(tox_opts)) {
|
||||||
queue_init_message("TCP relaying enabled on port %d", tox_opts->tcp_port);
|
queue_init_message("TCP relaying enabled on port %d", tox_options_get_tcp_port(tox_opts));
|
||||||
|
}
|
||||||
|
|
||||||
if (tox_opts->proxy_type != TOX_PROXY_TYPE_NONE) {
|
if (tox_options_get_proxy_type(tox_opts) != TOX_PROXY_TYPE_NONE) {
|
||||||
tox_opts->proxy_port = arg_opts.proxy_port;
|
tox_options_set_proxy_port(tox_opts, arg_opts.proxy_port);
|
||||||
tox_opts->proxy_host = arg_opts.proxy_address;
|
tox_options_set_proxy_host(tox_opts, arg_opts.proxy_address);
|
||||||
const char *ps = tox_opts->proxy_type == TOX_PROXY_TYPE_SOCKS5 ? "SOCKS5" : "HTTP";
|
const char *ps = tox_options_get_proxy_type(tox_opts) == TOX_PROXY_TYPE_SOCKS5 ? "SOCKS5" : "HTTP";
|
||||||
|
|
||||||
char tmp[sizeof(arg_opts.proxy_address) + MAX_STR_SIZE];
|
char tmp[sizeof(arg_opts.proxy_address) + MAX_STR_SIZE];
|
||||||
snprintf(tmp, sizeof(tmp), "Using %s proxy %s : %d", ps, arg_opts.proxy_address, arg_opts.proxy_port);
|
snprintf(tmp, sizeof(tmp), "Using %s proxy %s : %d", ps, arg_opts.proxy_address, arg_opts.proxy_port);
|
||||||
queue_init_message("%s", tmp);
|
queue_init_message("%s", tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tox_opts->udp_enabled) {
|
if (!tox_options_get_udp_enabled(tox_opts)) {
|
||||||
queue_init_message("UDP disabled");
|
queue_init_message("UDP disabled");
|
||||||
} else if (tox_opts->proxy_type != TOX_PROXY_TYPE_NONE) {
|
} else if (tox_options_get_proxy_type(tox_opts) != TOX_PROXY_TYPE_NONE) {
|
||||||
const char *msg = "WARNING: Using a proxy without disabling UDP may leak your real IP address.";
|
const char *msg = "WARNING: Using a proxy without disabling UDP may leak your real IP address.";
|
||||||
queue_init_message("%s", msg);
|
queue_init_message("%s", msg);
|
||||||
msg = "Use the -t option to disable UDP.";
|
msg = "Use the -t option to disable UDP.";
|
||||||
@ -597,7 +646,7 @@ static void init_tox_options(struct Tox_Options *tox_opts)
|
|||||||
/* Returns a new Tox object on success.
|
/* Returns a new Tox object on success.
|
||||||
* If object fails to initialize the toxic process will terminate.
|
* If object fails to initialize the toxic process will terminate.
|
||||||
*/
|
*/
|
||||||
static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW *new_err)
|
static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New *new_err)
|
||||||
{
|
{
|
||||||
Tox *m = NULL;
|
Tox *m = NULL;
|
||||||
|
|
||||||
@ -626,14 +675,16 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
|
|||||||
exit_toxic_err("failed in load_tox", FATALERR_ENCRYPT);
|
exit_toxic_err("failed in load_tox", FATALERR_ENCRYPT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg_opts.unencrypt_data && is_encrypted)
|
if (arg_opts.unencrypt_data && is_encrypted) {
|
||||||
queue_init_message("Data file '%s' has been unencrypted", data_path);
|
queue_init_message("Data file '%s' has been unencrypted", data_path);
|
||||||
else if (arg_opts.unencrypt_data)
|
} else if (arg_opts.unencrypt_data) {
|
||||||
queue_init_message("Warning: passed --unencrypt-data option with unencrypted data file '%s'", data_path);
|
queue_init_message("Warning: passed --unencrypt-data option with unencrypted data file '%s'", data_path);
|
||||||
|
}
|
||||||
|
|
||||||
if (is_encrypted) {
|
if (is_encrypted) {
|
||||||
if (!arg_opts.unencrypt_data)
|
if (!arg_opts.unencrypt_data) {
|
||||||
user_password.data_is_encrypted = true;
|
user_password.data_is_encrypted = true;
|
||||||
|
}
|
||||||
|
|
||||||
size_t pwlen = 0;
|
size_t pwlen = 0;
|
||||||
int pweval = user_settings->password_eval[0];
|
int pweval = user_settings->password_eval[0];
|
||||||
@ -675,9 +726,8 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
|
|||||||
(uint8_t *) plain, &pwerr);
|
(uint8_t *) plain, &pwerr);
|
||||||
|
|
||||||
if (pwerr == TOX_ERR_DECRYPTION_OK) {
|
if (pwerr == TOX_ERR_DECRYPTION_OK) {
|
||||||
tox_opts->savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE;
|
tox_options_set_savedata_type(tox_opts, TOX_SAVEDATA_TYPE_TOX_SAVE);
|
||||||
tox_opts->savedata_data = (uint8_t *) plain;
|
tox_options_set_savedata_data(tox_opts, (uint8_t *) plain, plain_len);
|
||||||
tox_opts->savedata_length = plain_len;
|
|
||||||
|
|
||||||
m = tox_new(tox_opts, new_err);
|
m = tox_new(tox_opts, new_err);
|
||||||
|
|
||||||
@ -698,9 +748,8 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { /* data is not encrypted */
|
} else { /* data is not encrypted */
|
||||||
tox_opts->savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE;
|
tox_options_set_savedata_type(tox_opts, TOX_SAVEDATA_TYPE_TOX_SAVE);
|
||||||
tox_opts->savedata_data = (uint8_t *) data;
|
tox_options_set_savedata_data(tox_opts, (uint8_t *) data, len);
|
||||||
tox_opts->savedata_length = len;
|
|
||||||
|
|
||||||
m = tox_new(tox_opts, new_err);
|
m = tox_new(tox_opts, new_err);
|
||||||
|
|
||||||
@ -712,50 +761,63 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
|
|||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
} else { /* Data file does not/should not exist */
|
} else { /* Data file does not/should not exist */
|
||||||
if (file_exists(data_path))
|
if (file_exists(data_path)) {
|
||||||
exit_toxic_err("failed in load_tox", FATALERR_FILEOP);
|
exit_toxic_err("failed in load_tox", FATALERR_FILEOP);
|
||||||
|
}
|
||||||
|
|
||||||
tox_opts->savedata_type = TOX_SAVEDATA_TYPE_NONE;
|
tox_options_set_savedata_type(tox_opts, TOX_SAVEDATA_TYPE_NONE);
|
||||||
|
|
||||||
m = tox_new(tox_opts, new_err);
|
m = tox_new(tox_opts, new_err);
|
||||||
|
|
||||||
if (m == NULL)
|
if (m == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (store_data(m, data_path) == -1)
|
if (store_data(m, data_path) == -1) {
|
||||||
exit_toxic_err("failed in load_tox", FATALERR_FILEOP);
|
exit_toxic_err("failed in load_tox", FATALERR_FILEOP);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Tox *load_toxic(char *data_path)
|
static Tox *load_toxic(char *data_path)
|
||||||
{
|
{
|
||||||
struct Tox_Options tox_opts;
|
Tox_Err_Options_New options_new_err;
|
||||||
init_tox_options(&tox_opts);
|
struct Tox_Options *tox_opts = tox_options_new(&options_new_err);
|
||||||
|
|
||||||
TOX_ERR_NEW new_err;
|
if (!tox_opts) {
|
||||||
Tox *m = load_tox(data_path, &tox_opts, &new_err);
|
exit_toxic_err("tox_options_new returned fatal error", options_new_err);
|
||||||
|
|
||||||
if (new_err == TOX_ERR_NEW_PORT_ALLOC && tox_opts.ipv6_enabled) {
|
|
||||||
queue_init_message("Falling back to ipv4");
|
|
||||||
tox_opts.ipv6_enabled = false;
|
|
||||||
m = load_tox(data_path, &tox_opts, &new_err);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m)
|
init_tox_options(tox_opts);
|
||||||
exit_toxic_err("tox_new returned fatal error", new_err);
|
|
||||||
|
|
||||||
if (new_err != TOX_ERR_NEW_OK)
|
Tox_Err_New new_err;
|
||||||
|
Tox *m = load_tox(data_path, tox_opts, &new_err);
|
||||||
|
|
||||||
|
if (new_err == TOX_ERR_NEW_PORT_ALLOC && tox_options_get_ipv6_enabled(tox_opts)) {
|
||||||
|
queue_init_message("Falling back to ipv4");
|
||||||
|
tox_options_set_ipv6_enabled(tox_opts, false);
|
||||||
|
m = load_tox(data_path, tox_opts, &new_err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m) {
|
||||||
|
exit_toxic_err("tox_new returned fatal error", new_err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_err != TOX_ERR_NEW_OK) {
|
||||||
queue_init_message("tox_new returned non-fatal error %d", new_err);
|
queue_init_message("tox_new returned non-fatal error %d", new_err);
|
||||||
|
}
|
||||||
|
|
||||||
init_tox_callbacks(m);
|
init_tox_callbacks(m);
|
||||||
load_friendlist(m);
|
load_friendlist(m);
|
||||||
load_blocklist(BLOCK_FILE);
|
load_blocklist(BLOCK_FILE);
|
||||||
|
|
||||||
if (tox_self_get_name_size(m) == 0)
|
if (tox_self_get_name_size(m) == 0) {
|
||||||
tox_self_set_name(m, (uint8_t *) "Toxic User", strlen("Toxic User"), NULL);
|
tox_self_set_name(m, (uint8_t *) "Toxic User", strlen("Toxic User"), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
tox_options_free(tox_opts);
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -814,9 +876,10 @@ void *thread_cqueue(void *data)
|
|||||||
ToxWindow *toxwin = get_window_ptr(i);
|
ToxWindow *toxwin = get_window_ptr(i);
|
||||||
|
|
||||||
if (toxwin != NULL && toxwin->is_chat
|
if (toxwin != NULL && toxwin->is_chat
|
||||||
&& tox_friend_get_connection_status(m, toxwin->num, NULL) != TOX_CONNECTION_NONE)
|
&& get_friend_connection_status(toxwin->num) != TOX_CONNECTION_NONE) {
|
||||||
cqueue_try_send(toxwin, m);
|
cqueue_try_send(toxwin, m);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
@ -916,8 +979,9 @@ static void parse_args(int argc, char *argv[])
|
|||||||
case 'c':
|
case 'c':
|
||||||
snprintf(arg_opts.config_path, sizeof(arg_opts.config_path), "%s", optarg);
|
snprintf(arg_opts.config_path, sizeof(arg_opts.config_path), "%s", optarg);
|
||||||
|
|
||||||
if (!file_exists(arg_opts.config_path))
|
if (!file_exists(arg_opts.config_path)) {
|
||||||
queue_init_message("Config file not found");
|
queue_init_message("Config file not found");
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -933,22 +997,26 @@ static void parse_args(int argc, char *argv[])
|
|||||||
case 'f':
|
case 'f':
|
||||||
arg_opts.use_custom_data = 1;
|
arg_opts.use_custom_data = 1;
|
||||||
|
|
||||||
if (DATA_FILE)
|
if (DATA_FILE) {
|
||||||
free(DATA_FILE);
|
free(DATA_FILE);
|
||||||
|
}
|
||||||
|
|
||||||
if (BLOCK_FILE)
|
if (BLOCK_FILE) {
|
||||||
free(BLOCK_FILE);
|
free(BLOCK_FILE);
|
||||||
|
}
|
||||||
|
|
||||||
DATA_FILE = malloc(strlen(optarg) + 1);
|
DATA_FILE = malloc(strlen(optarg) + 1);
|
||||||
strcpy(DATA_FILE, optarg);
|
strcpy(DATA_FILE, optarg);
|
||||||
|
|
||||||
if (DATA_FILE == NULL)
|
if (DATA_FILE == NULL) {
|
||||||
exit_toxic_err("failed in parse_args", FATALERR_MEMORY);
|
exit_toxic_err("failed in parse_args", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
BLOCK_FILE = malloc(strlen(optarg) + strlen("-blocklist") + 1);
|
BLOCK_FILE = malloc(strlen(optarg) + strlen("-blocklist") + 1);
|
||||||
|
|
||||||
if (BLOCK_FILE == NULL)
|
if (BLOCK_FILE == NULL) {
|
||||||
exit_toxic_err("failed in parse_args", FATALERR_MEMORY);
|
exit_toxic_err("failed in parse_args", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
strcpy(BLOCK_FILE, optarg);
|
strcpy(BLOCK_FILE, optarg);
|
||||||
strcat(BLOCK_FILE, "-blocklist");
|
strcat(BLOCK_FILE, "-blocklist");
|
||||||
@ -970,13 +1038,15 @@ static void parse_args(int argc, char *argv[])
|
|||||||
arg_opts.proxy_type = TOX_PROXY_TYPE_SOCKS5;
|
arg_opts.proxy_type = TOX_PROXY_TYPE_SOCKS5;
|
||||||
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
|
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
|
||||||
|
|
||||||
if (++optind > argc || argv[optind - 1][0] == '-')
|
if (++optind > argc || argv[optind - 1][0] == '-') {
|
||||||
exit_toxic_err("Proxy error", FATALERR_PROXY);
|
exit_toxic_err("Proxy error", FATALERR_PROXY);
|
||||||
|
}
|
||||||
|
|
||||||
port = strtol(argv[optind - 1], NULL, 10);
|
port = strtol(argv[optind - 1], NULL, 10);
|
||||||
|
|
||||||
if (port <= 0 || port > MAX_PORT_RANGE)
|
if (port <= 0 || port > MAX_PORT_RANGE) {
|
||||||
exit_toxic_err("Proxy error", FATALERR_PROXY);
|
exit_toxic_err("Proxy error", FATALERR_PROXY);
|
||||||
|
}
|
||||||
|
|
||||||
arg_opts.proxy_port = port;
|
arg_opts.proxy_port = port;
|
||||||
break;
|
break;
|
||||||
@ -985,13 +1055,15 @@ static void parse_args(int argc, char *argv[])
|
|||||||
arg_opts.proxy_type = TOX_PROXY_TYPE_HTTP;
|
arg_opts.proxy_type = TOX_PROXY_TYPE_HTTP;
|
||||||
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
|
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
|
||||||
|
|
||||||
if (++optind > argc || argv[optind - 1][0] == '-')
|
if (++optind > argc || argv[optind - 1][0] == '-') {
|
||||||
exit_toxic_err("Proxy error", FATALERR_PROXY);
|
exit_toxic_err("Proxy error", FATALERR_PROXY);
|
||||||
|
}
|
||||||
|
|
||||||
port = strtol(argv[optind - 1], NULL, 10);
|
port = strtol(argv[optind - 1], NULL, 10);
|
||||||
|
|
||||||
if (port <= 0 || port > MAX_PORT_RANGE)
|
if (port <= 0 || port > MAX_PORT_RANGE) {
|
||||||
exit_toxic_err("Proxy error", FATALERR_PROXY);
|
exit_toxic_err("Proxy error", FATALERR_PROXY);
|
||||||
|
}
|
||||||
|
|
||||||
arg_opts.proxy_port = port;
|
arg_opts.proxy_port = port;
|
||||||
break;
|
break;
|
||||||
@ -999,8 +1071,9 @@ static void parse_args(int argc, char *argv[])
|
|||||||
case 'r':
|
case 'r':
|
||||||
snprintf(arg_opts.nameserver_path, sizeof(arg_opts.nameserver_path), "%s", optarg);
|
snprintf(arg_opts.nameserver_path, sizeof(arg_opts.nameserver_path), "%s", optarg);
|
||||||
|
|
||||||
if (!file_exists(arg_opts.nameserver_path))
|
if (!file_exists(arg_opts.nameserver_path)) {
|
||||||
queue_init_message("nameserver list not found");
|
queue_init_message("nameserver list not found");
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1011,8 +1084,9 @@ static void parse_args(int argc, char *argv[])
|
|||||||
case 'T':
|
case 'T':
|
||||||
port = strtol(optarg, NULL, 10);
|
port = strtol(optarg, NULL, 10);
|
||||||
|
|
||||||
if (port <= 0 || port > MAX_PORT_RANGE)
|
if (port <= 0 || port > MAX_PORT_RANGE) {
|
||||||
port = 14191;
|
port = 14191;
|
||||||
|
}
|
||||||
|
|
||||||
arg_opts.tcp_port = port;
|
arg_opts.tcp_port = port;
|
||||||
break;
|
break;
|
||||||
@ -1045,28 +1119,34 @@ static int rename_old_profile(const char *user_config_dir)
|
|||||||
char old_data_file[strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(OLD_DATA_NAME) + 1];
|
char old_data_file[strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(OLD_DATA_NAME) + 1];
|
||||||
snprintf(old_data_file, sizeof(old_data_file), "%s%s%s", user_config_dir, CONFIGDIR, OLD_DATA_NAME);
|
snprintf(old_data_file, sizeof(old_data_file), "%s%s%s", user_config_dir, CONFIGDIR, OLD_DATA_NAME);
|
||||||
|
|
||||||
if (!file_exists(old_data_file))
|
if (!file_exists(old_data_file)) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (file_exists(DATA_FILE))
|
if (file_exists(DATA_FILE)) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (rename(old_data_file, DATA_FILE) != 0)
|
if (rename(old_data_file, DATA_FILE) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
queue_init_message("Data file has been moved to %s", DATA_FILE);
|
queue_init_message("Data file has been moved to %s", DATA_FILE);
|
||||||
|
|
||||||
char old_data_blocklist[strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(OLD_DATA_BLOCKLIST_NAME) + 1];
|
char old_data_blocklist[strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(OLD_DATA_BLOCKLIST_NAME) + 1];
|
||||||
snprintf(old_data_blocklist, sizeof(old_data_blocklist), "%s%s%s", user_config_dir, CONFIGDIR, OLD_DATA_BLOCKLIST_NAME);
|
snprintf(old_data_blocklist, sizeof(old_data_blocklist), "%s%s%s", user_config_dir, CONFIGDIR, OLD_DATA_BLOCKLIST_NAME);
|
||||||
|
|
||||||
if (!file_exists(old_data_blocklist))
|
if (!file_exists(old_data_blocklist)) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (file_exists(BLOCK_FILE))
|
if (file_exists(BLOCK_FILE)) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (rename(old_data_blocklist, BLOCK_FILE) != 0)
|
if (rename(old_data_blocklist, BLOCK_FILE) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1077,13 +1157,15 @@ static int rename_old_profile(const char *user_config_dir)
|
|||||||
*/
|
*/
|
||||||
static void init_default_data_files(void)
|
static void init_default_data_files(void)
|
||||||
{
|
{
|
||||||
if (arg_opts.use_custom_data)
|
if (arg_opts.use_custom_data) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
char *user_config_dir = get_user_config_dir();
|
char *user_config_dir = get_user_config_dir();
|
||||||
|
|
||||||
if (user_config_dir == NULL)
|
if (user_config_dir == NULL) {
|
||||||
exit_toxic_err("failed in init_default_data_files()", FATALERR_FILEOP);
|
exit_toxic_err("failed in init_default_data_files()", FATALERR_FILEOP);
|
||||||
|
}
|
||||||
|
|
||||||
int config_err = create_user_config_dirs(user_config_dir);
|
int config_err = create_user_config_dirs(user_config_dir);
|
||||||
|
|
||||||
@ -1091,14 +1173,16 @@ static void init_default_data_files(void)
|
|||||||
DATA_FILE = strdup(DATANAME);
|
DATA_FILE = strdup(DATANAME);
|
||||||
BLOCK_FILE = strdup(BLOCKNAME);
|
BLOCK_FILE = strdup(BLOCKNAME);
|
||||||
|
|
||||||
if (DATA_FILE == NULL || BLOCK_FILE == NULL)
|
if (DATA_FILE == NULL || BLOCK_FILE == NULL) {
|
||||||
exit_toxic_err("failed in init_default_data_files()", FATALERR_MEMORY);
|
exit_toxic_err("failed in init_default_data_files()", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
DATA_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(DATANAME) + 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);
|
BLOCK_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(BLOCKNAME) + 1);
|
||||||
|
|
||||||
if (DATA_FILE == NULL || BLOCK_FILE == NULL)
|
if (DATA_FILE == NULL || BLOCK_FILE == NULL) {
|
||||||
exit_toxic_err("failed in init_default_data_files()", FATALERR_MEMORY);
|
exit_toxic_err("failed in init_default_data_files()", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
strcpy(DATA_FILE, user_config_dir);
|
strcpy(DATA_FILE, user_config_dir);
|
||||||
strcat(DATA_FILE, CONFIGDIR);
|
strcat(DATA_FILE, CONFIGDIR);
|
||||||
@ -1110,8 +1194,9 @@ static void init_default_data_files(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* For backwards compatibility with old toxic profile names. TODO: remove this some day */
|
/* For backwards compatibility with old toxic profile names. TODO: remove this some day */
|
||||||
if (rename_old_profile(user_config_dir) == -1)
|
if (rename_old_profile(user_config_dir) == -1) {
|
||||||
queue_init_message("Warning: Profile backwards compatibility failed.");
|
queue_init_message("Warning: Profile backwards compatibility failed.");
|
||||||
|
}
|
||||||
|
|
||||||
free(user_config_dir);
|
free(user_config_dir);
|
||||||
}
|
}
|
||||||
@ -1134,8 +1219,9 @@ int main(int argc, char **argv)
|
|||||||
parse_args(argc, argv);
|
parse_args(argc, argv);
|
||||||
|
|
||||||
/* Use the -b flag to enable stderr */
|
/* Use the -b flag to enable stderr */
|
||||||
if (!arg_opts.debug)
|
if (!arg_opts.debug) {
|
||||||
freopen("/dev/null", "w", stderr);
|
freopen("/dev/null", "w", stderr);
|
||||||
|
}
|
||||||
|
|
||||||
if (arg_opts.encrypt_data && arg_opts.unencrypt_data) {
|
if (arg_opts.encrypt_data && arg_opts.unencrypt_data) {
|
||||||
arg_opts.encrypt_data = 0;
|
arg_opts.encrypt_data = 0;
|
||||||
@ -1150,17 +1236,19 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
bool datafile_exists = file_exists(DATA_FILE);
|
bool datafile_exists = file_exists(DATA_FILE);
|
||||||
|
|
||||||
if (!datafile_exists && !arg_opts.unencrypt_data)
|
if (!datafile_exists && !arg_opts.unencrypt_data) {
|
||||||
first_time_encrypt("Creating new data file. Would you like to encrypt it? Y/n (q to quit)");
|
first_time_encrypt("Creating new data file. Would you like to encrypt it? Y/n (q to quit)");
|
||||||
else if (arg_opts.encrypt_data)
|
} else if (arg_opts.encrypt_data) {
|
||||||
first_time_encrypt("Encrypt existing data file? Y/n (q to quit)");
|
first_time_encrypt("Encrypt existing data file? Y/n (q to quit)");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* init user_settings struct and load settings from conf file */
|
/* init user_settings struct and load settings from conf file */
|
||||||
user_settings = calloc(1, sizeof(struct user_settings));
|
user_settings = calloc(1, sizeof(struct user_settings));
|
||||||
|
|
||||||
if (user_settings == NULL)
|
if (user_settings == NULL) {
|
||||||
exit_toxic_err("failed in main", FATALERR_MEMORY);
|
exit_toxic_err("failed in main", FATALERR_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
const char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL;
|
const char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL;
|
||||||
|
|
||||||
@ -1181,32 +1269,37 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
#ifdef X11
|
#ifdef X11
|
||||||
|
|
||||||
if (init_xtra(DnD_callback) == -1)
|
if (init_xtra(DnD_callback) == -1) {
|
||||||
queue_init_message("X failed to initialize");
|
queue_init_message("X failed to initialize");
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif /* X11 */
|
||||||
|
|
||||||
Tox *m = load_toxic(DATA_FILE);
|
Tox *m = load_toxic(DATA_FILE);
|
||||||
|
|
||||||
if (arg_opts.encrypt_data && !datafile_exists)
|
if (arg_opts.encrypt_data && !datafile_exists) {
|
||||||
arg_opts.encrypt_data = 0;
|
arg_opts.encrypt_data = 0;
|
||||||
|
}
|
||||||
|
|
||||||
init_term();
|
init_term();
|
||||||
|
|
||||||
prompt = init_windows(m);
|
prompt = init_windows(m);
|
||||||
prompt_init_statusbar(prompt, m);
|
prompt_init_statusbar(prompt, m, !datafile_exists);
|
||||||
|
load_groups(prompt, m);
|
||||||
|
|
||||||
/* thread for ncurses stuff */
|
/* thread for ncurses stuff */
|
||||||
if (pthread_mutex_init(&Winthread.lock, NULL) != 0)
|
if (pthread_mutex_init(&Winthread.lock, NULL) != 0) {
|
||||||
exit_toxic_err("failed in main", FATALERR_MUTEX_INIT);
|
exit_toxic_err("failed in main", FATALERR_MUTEX_INIT);
|
||||||
|
}
|
||||||
|
|
||||||
if (pthread_create(&Winthread.tid, NULL, thread_winref, (void *) m) != 0)
|
if (pthread_create(&Winthread.tid, NULL, thread_winref, (void *) m) != 0) {
|
||||||
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
|
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
|
||||||
|
}
|
||||||
|
|
||||||
/* thread for message queue */
|
/* thread for message queue */
|
||||||
if (pthread_create(&cqueue_thread.tid, NULL, thread_cqueue, (void *) m) != 0)
|
if (pthread_create(&cqueue_thread.tid, NULL, thread_cqueue, (void *) m) != 0) {
|
||||||
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
|
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
|
|
||||||
@ -1218,16 +1311,18 @@ int main(int argc, char **argv)
|
|||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
|
|
||||||
/* AV thread */
|
/* AV thread */
|
||||||
if (pthread_create(&av_thread.tid, NULL, thread_av, (void *) av) != 0)
|
if (pthread_create(&av_thread.tid, NULL, thread_av, (void *) av) != 0) {
|
||||||
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
|
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
|
||||||
|
}
|
||||||
|
|
||||||
set_primary_device(input, user_settings->audio_in_dev);
|
set_primary_device(input, user_settings->audio_in_dev);
|
||||||
set_primary_device(output, user_settings->audio_out_dev);
|
set_primary_device(output, user_settings->audio_out_dev);
|
||||||
|
|
||||||
#elif SOUND_NOTIFY
|
#elif SOUND_NOTIFY
|
||||||
|
|
||||||
if ( init_devices() == de_InternalError )
|
if (init_devices() == de_InternalError) {
|
||||||
queue_init_message("Failed to init audio devices");
|
queue_init_message("Failed to init audio devices");
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
@ -1241,8 +1336,9 @@ int main(int argc, char **argv)
|
|||||||
init_notify(60, 3000);
|
init_notify(60, 3000);
|
||||||
|
|
||||||
/* screen/tmux auto-away timer */
|
/* screen/tmux auto-away timer */
|
||||||
if (init_mplex_away_timer(m) == -1)
|
if (init_mplex_away_timer(m) == -1) {
|
||||||
queue_init_message("Failed to init mplex auto-away.");
|
queue_init_message("Failed to init mplex auto-away.");
|
||||||
|
}
|
||||||
|
|
||||||
int nodeslist_ret = load_DHT_nodeslist();
|
int nodeslist_ret = load_DHT_nodeslist();
|
||||||
|
|
||||||
@ -1258,7 +1354,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
/* set user avatar from config file. if no path is supplied tox_unset_avatar is called */
|
/* set user avatar from config file. if no path is supplied tox_unset_avatar is called */
|
||||||
char avatarstr[PATH_MAX + 11];
|
char avatarstr[PATH_MAX + 11];
|
||||||
snprintf(avatarstr, sizeof(avatarstr), "/avatar \"%s\"", user_settings->avatar_path);
|
snprintf(avatarstr, sizeof(avatarstr), "/avatar %s", user_settings->avatar_path);
|
||||||
execute(prompt->chatwin->history, prompt, m, avatarstr, GLOBAL_COMMAND_MODE);
|
execute(prompt->chatwin->history, prompt, m, avatarstr, GLOBAL_COMMAND_MODE);
|
||||||
|
|
||||||
time_t last_save = get_unix_time();
|
time_t last_save = get_unix_time();
|
||||||
@ -1271,8 +1367,9 @@ int main(int argc, char **argv)
|
|||||||
if (timed_out(last_save, AUTOSAVE_FREQ)) {
|
if (timed_out(last_save, AUTOSAVE_FREQ)) {
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
|
|
||||||
if (store_data(m, DATA_FILE) != 0)
|
if (store_data(m, DATA_FILE) != 0) {
|
||||||
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, "WARNING: Failed to save to data file");
|
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, "WARNING: Failed to save to data file");
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
|
39
src/toxic.h
39
src/toxic.h
@ -96,8 +96,8 @@ typedef enum _FATAL_ERRS {
|
|||||||
Uncomment if necessary */
|
Uncomment if necessary */
|
||||||
/* #define URXVT_FIX */
|
/* #define URXVT_FIX */
|
||||||
|
|
||||||
void lock_status ();
|
void lock_status(void);
|
||||||
void unlock_status ();
|
void unlock_status(void);
|
||||||
|
|
||||||
void exit_toxic_success(Tox *m);
|
void exit_toxic_success(Tox *m);
|
||||||
void exit_toxic_err(const char *errmsg, int errcode);
|
void exit_toxic_err(const char *errmsg, int errcode);
|
||||||
@ -105,31 +105,32 @@ void exit_toxic_err(const char *errmsg, int errcode);
|
|||||||
int store_data(Tox *m, const char *path);
|
int store_data(Tox *m, const char *path);
|
||||||
|
|
||||||
/* callbacks */
|
/* callbacks */
|
||||||
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata);
|
void on_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata);
|
||||||
void on_connectionchange(Tox *m, uint32_t friendnumber, TOX_CONNECTION status, void *userdata);
|
void on_friend_connection_status(Tox *m, uint32_t friendnumber, Tox_Connection status, void *userdata);
|
||||||
void on_message(Tox *m, uint32_t friendnumber, TOX_MESSAGE_TYPE type, const uint8_t *string, size_t length,
|
void on_friend_message(Tox *m, uint32_t friendnumber, Tox_Message_Type type, const uint8_t *string, size_t length,
|
||||||
void *userdata);
|
void *userdata);
|
||||||
void on_action(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
|
void on_friend_name(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
|
||||||
void on_nickchange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
|
void on_friend_status(Tox *m, uint32_t friendnumber, Tox_User_Status status, void *userdata);
|
||||||
void on_statuschange(Tox *m, uint32_t friendnumber, TOX_USER_STATUS status, void *userdata);
|
void on_friend_status_message(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
|
||||||
void on_statusmessagechange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
|
void on_friend_added(Tox *m, uint32_t friendnumber, bool sort);
|
||||||
void on_friendadded(Tox *m, uint32_t friendnumber, bool sort);
|
void on_conference_message(Tox *m, uint32_t groupnumber, uint32_t peernumber, Tox_Message_Type type,
|
||||||
void on_groupmessage(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_MESSAGE_TYPE type,
|
|
||||||
const uint8_t *message, size_t length, void *userdata);
|
const uint8_t *message, size_t length, void *userdata);
|
||||||
void on_groupinvite(Tox *m, uint32_t friendnumber, TOX_CONFERENCE_TYPE type, const uint8_t *group_pub_key,
|
void on_conference_invite(Tox *m, uint32_t friendnumber, Tox_Conference_Type type, const uint8_t *group_pub_key,
|
||||||
size_t length, void *userdata);
|
size_t length, void *userdata);
|
||||||
void on_group_namelistchange(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_CONFERENCE_STATE_CHANGE change,
|
void on_conference_peer_list_changed(Tox *m, uint32_t groupnumber, void *userdata);
|
||||||
void *userdata);
|
void on_conference_peer_name(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *name,
|
||||||
void on_group_titlechange(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *title, size_t length,
|
size_t length, void *userdata);
|
||||||
|
void on_conference_title(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *title, size_t length,
|
||||||
void *userdata);
|
void *userdata);
|
||||||
void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length,
|
void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length,
|
||||||
void *userdata);
|
void *userdata);
|
||||||
void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data,
|
void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data,
|
||||||
size_t length, void *userdata);
|
size_t length, void *userdata);
|
||||||
void on_file_control (Tox *m, uint32_t friendnumber, uint32_t filenumber, TOX_FILE_CONTROL control, void *userdata);
|
void on_file_recv_control(Tox *m, uint32_t friendnumber, uint32_t filenumber, Tox_File_Control control,
|
||||||
|
void *userdata);
|
||||||
void on_file_recv(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint32_t kind, uint64_t file_size,
|
void on_file_recv(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint32_t kind, uint64_t file_size,
|
||||||
const uint8_t *filename, size_t filename_length, void *userdata);
|
const uint8_t *filename, size_t filename_length, void *userdata);
|
||||||
void on_typing_change(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata);
|
void on_friend_typing(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata);
|
||||||
void on_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata);
|
void on_friend_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata);
|
||||||
|
|
||||||
#endif /* #define TOXIC_H */
|
#endif /* TOXIC_H */
|
||||||
|
@ -33,8 +33,9 @@
|
|||||||
/* Adds char to line at pos. Return 0 on success, -1 if line buffer is full */
|
/* 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)
|
int add_char_to_buf(ChatContext *ctx, wint_t ch)
|
||||||
{
|
{
|
||||||
if (ctx->len >= MAX_STR_SIZE - 1)
|
if (ctx->len >= MAX_STR_SIZE - 1) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
wmemmove(&ctx->line[ctx->pos + 1], &ctx->line[ctx->pos], ctx->len - ctx->pos);
|
wmemmove(&ctx->line[ctx->pos + 1], &ctx->line[ctx->pos], ctx->len - ctx->pos);
|
||||||
ctx->line[ctx->pos++] = ch;
|
ctx->line[ctx->pos++] = ch;
|
||||||
@ -46,8 +47,9 @@ int add_char_to_buf(ChatContext *ctx, wint_t ch)
|
|||||||
/* Deletes the character before pos. Return 0 on success, -1 if nothing to delete */
|
/* Deletes the character before pos. Return 0 on success, -1 if nothing to delete */
|
||||||
int del_char_buf_bck(ChatContext *ctx)
|
int del_char_buf_bck(ChatContext *ctx)
|
||||||
{
|
{
|
||||||
if (ctx->pos <= 0)
|
if (ctx->pos <= 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
wmemmove(&ctx->line[ctx->pos - 1], &ctx->line[ctx->pos], ctx->len - ctx->pos);
|
wmemmove(&ctx->line[ctx->pos - 1], &ctx->line[ctx->pos], ctx->len - ctx->pos);
|
||||||
--ctx->pos;
|
--ctx->pos;
|
||||||
@ -59,8 +61,9 @@ int del_char_buf_bck(ChatContext *ctx)
|
|||||||
/* Deletes the character at pos. Return 0 on success, -1 if nothing to delete. */
|
/* Deletes the character at pos. Return 0 on success, -1 if nothing to delete. */
|
||||||
int del_char_buf_frnt(ChatContext *ctx)
|
int del_char_buf_frnt(ChatContext *ctx)
|
||||||
{
|
{
|
||||||
if (ctx->pos >= ctx->len)
|
if (ctx->pos >= ctx->len) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
wmemmove(&ctx->line[ctx->pos], &ctx->line[ctx->pos + 1], ctx->len - ctx->pos - 1);
|
wmemmove(&ctx->line[ctx->pos], &ctx->line[ctx->pos + 1], ctx->len - ctx->pos - 1);
|
||||||
ctx->line[--ctx->len] = L'\0';
|
ctx->line[--ctx->len] = L'\0';
|
||||||
@ -72,8 +75,9 @@ int del_char_buf_frnt(ChatContext *ctx)
|
|||||||
Return 0 on success, -1 if noting to discard. */
|
Return 0 on success, -1 if noting to discard. */
|
||||||
int discard_buf(ChatContext *ctx)
|
int discard_buf(ChatContext *ctx)
|
||||||
{
|
{
|
||||||
if (ctx->pos <= 0)
|
if (ctx->pos <= 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
ctx->yank_len = ctx->pos;
|
ctx->yank_len = ctx->pos;
|
||||||
wmemcpy(ctx->yank, ctx->line, ctx->yank_len);
|
wmemcpy(ctx->yank, ctx->line, ctx->yank_len);
|
||||||
@ -92,8 +96,9 @@ int discard_buf(ChatContext *ctx)
|
|||||||
Return 0 on success, -1 if nothing to kill. */
|
Return 0 on success, -1 if nothing to kill. */
|
||||||
int kill_buf(ChatContext *ctx)
|
int kill_buf(ChatContext *ctx)
|
||||||
{
|
{
|
||||||
if (ctx->len <= ctx->pos)
|
if (ctx->len <= ctx->pos) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
ctx->yank_len = ctx->len - ctx->pos;
|
ctx->yank_len = ctx->len - ctx->pos;
|
||||||
wmemcpy(ctx->yank, &ctx->line[ctx->pos], ctx->yank_len);
|
wmemcpy(ctx->yank, &ctx->line[ctx->pos], ctx->yank_len);
|
||||||
@ -109,11 +114,13 @@ int kill_buf(ChatContext *ctx)
|
|||||||
Return 0 on success, -1 if yank buffer is empty or too long */
|
Return 0 on success, -1 if yank buffer is empty or too long */
|
||||||
int yank_buf(ChatContext *ctx)
|
int yank_buf(ChatContext *ctx)
|
||||||
{
|
{
|
||||||
if (!ctx->yank[0])
|
if (!ctx->yank[0]) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (ctx->yank_len + ctx->len >= MAX_STR_SIZE)
|
if (ctx->yank_len + ctx->len >= MAX_STR_SIZE) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
wmemmove(&ctx->line[ctx->pos + ctx->yank_len], &ctx->line[ctx->pos], ctx->len - ctx->pos);
|
wmemmove(&ctx->line[ctx->pos + ctx->yank_len], &ctx->line[ctx->pos], ctx->len - ctx->pos);
|
||||||
wmemcpy(&ctx->line[ctx->pos], ctx->yank, ctx->yank_len);
|
wmemcpy(&ctx->line[ctx->pos], ctx->yank, ctx->yank_len);
|
||||||
@ -130,8 +137,9 @@ int yank_buf(ChatContext *ctx)
|
|||||||
Return 0 on success, -1 if nothing to delete */
|
Return 0 on success, -1 if nothing to delete */
|
||||||
int del_word_buf(ChatContext *ctx)
|
int del_word_buf(ChatContext *ctx)
|
||||||
{
|
{
|
||||||
if (ctx->len == 0 || ctx->pos == 0)
|
if (ctx->len == 0 || ctx->pos == 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int i = ctx->pos, count = 0;
|
int i = ctx->pos, count = 0;
|
||||||
|
|
||||||
@ -169,18 +177,21 @@ void reset_buf(ChatContext *ctx)
|
|||||||
/* Removes trailing spaces and newlines from line. */
|
/* Removes trailing spaces and newlines from line. */
|
||||||
void rm_trailing_spaces_buf(ChatContext *ctx)
|
void rm_trailing_spaces_buf(ChatContext *ctx)
|
||||||
{
|
{
|
||||||
if (ctx->len <= 0)
|
if (ctx->len <= 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (ctx->line[ctx->len - 1] != ' ' && ctx->line[ctx->len - 1] != L'¶')
|
if (ctx->line[ctx->len - 1] != ' ' && ctx->line[ctx->len - 1] != L'¶') {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = ctx->len - 1; i >= 0; --i) {
|
for (i = ctx->len - 1; i >= 0; --i) {
|
||||||
if (ctx->line[i] != ' ' && ctx->line[i] != L'¶')
|
if (ctx->line[i] != ' ' && ctx->line[i] != L'¶') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ctx->len = i + 1;
|
ctx->len = i + 1;
|
||||||
ctx->pos = MIN(ctx->pos, ctx->len);
|
ctx->pos = MIN(ctx->pos, ctx->len);
|
||||||
@ -195,8 +206,9 @@ static void shift_hist_back(ChatContext *ctx)
|
|||||||
int i;
|
int i;
|
||||||
int n = MAX_LINE_HIST - HIST_PURGE;
|
int n = MAX_LINE_HIST - HIST_PURGE;
|
||||||
|
|
||||||
for (i = 0; i < n; ++i)
|
for (i = 0; i < n; ++i) {
|
||||||
wmemcpy(ctx->ln_history[i], ctx->ln_history[i + HIST_PURGE], MAX_STR_SIZE);
|
wmemcpy(ctx->ln_history[i], ctx->ln_history[i + HIST_PURGE], MAX_STR_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
ctx->hst_tot = n;
|
ctx->hst_tot = n;
|
||||||
}
|
}
|
||||||
@ -204,11 +216,13 @@ 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. */
|
/* 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)
|
void add_line_to_hist(ChatContext *ctx)
|
||||||
{
|
{
|
||||||
if (ctx->len >= MAX_STR_SIZE)
|
if (ctx->len >= MAX_STR_SIZE) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (ctx->hst_tot >= MAX_LINE_HIST)
|
if (ctx->hst_tot >= MAX_LINE_HIST) {
|
||||||
shift_hist_back(ctx);
|
shift_hist_back(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
++ctx->hst_tot;
|
++ctx->hst_tot;
|
||||||
ctx->hst_pos = ctx->hst_tot;
|
ctx->hst_pos = ctx->hst_tot;
|
||||||
@ -247,16 +261,20 @@ void strsubst(char *str, char old, char new)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; str[i] != '\0'; ++i)
|
for (i = 0; str[i] != '\0'; ++i) {
|
||||||
if (str[i] == old)
|
if (str[i] == old) {
|
||||||
str[i] = new;
|
str[i] = new;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void wstrsubst(wchar_t *str, wchar_t old, wchar_t new)
|
void wstrsubst(wchar_t *str, wchar_t old, wchar_t new)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; str[i] != L'\0'; ++i)
|
for (i = 0; str[i] != L'\0'; ++i) {
|
||||||
if (str[i] == old)
|
if (str[i] == old) {
|
||||||
str[i] = new;
|
str[i] = new;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -70,4 +70,4 @@ void fetch_hist_item(ChatContext *ctx, int key_dir);
|
|||||||
void strsubst(char *str, char old, char new);
|
void strsubst(char *str, char old, char new);
|
||||||
void wstrsubst(wchar_t *str, wchar_t old, wchar_t new);
|
void wstrsubst(wchar_t *str, wchar_t old, wchar_t new);
|
||||||
|
|
||||||
#endif /* #define TOXIC_STRINGS_H */
|
#endif /* TOXIC_STRINGS_H */
|
||||||
|
@ -37,16 +37,17 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#ifdef VIDEO
|
||||||
|
|
||||||
#define default_video_bit_rate 5000
|
#define default_video_bit_rate 5000
|
||||||
|
|
||||||
void receive_video_frame_cb( ToxAV *av, uint32_t friend_number,
|
void on_video_receive_frame(ToxAV *av, uint32_t friend_number,
|
||||||
uint16_t width, uint16_t height,
|
uint16_t width, uint16_t height,
|
||||||
uint8_t const *y, uint8_t const *u, uint8_t const *v,
|
uint8_t const *y, uint8_t const *u, uint8_t const *v,
|
||||||
int32_t ystride, int32_t ustride, int32_t vstride,
|
int32_t ystride, int32_t ustride, int32_t vstride,
|
||||||
void *user_data);
|
void *user_data);
|
||||||
|
|
||||||
void video_bit_rate_status_cb( ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate,
|
void on_video_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t video_bit_rate, void *user_data);
|
||||||
uint32_t video_bit_rate, void *user_data);
|
|
||||||
|
|
||||||
static void print_err(ToxWindow *self, const char *error_str)
|
static void print_err(ToxWindow *self, const char *error_str)
|
||||||
{
|
{
|
||||||
@ -73,24 +74,25 @@ ToxAV *init_video(ToxWindow *self, Tox *tox)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
toxav_callback_video_receive_frame(CallControl.av, receive_video_frame_cb, &CallControl);
|
toxav_callback_video_receive_frame(CallControl.av, on_video_receive_frame, &CallControl);
|
||||||
toxav_callback_bit_rate_status(CallControl.av, video_bit_rate_status_cb, &CallControl);
|
toxav_callback_video_bit_rate(CallControl.av, on_video_bit_rate, &CallControl);
|
||||||
|
|
||||||
return CallControl.av;
|
return CallControl.av;
|
||||||
}
|
}
|
||||||
|
|
||||||
void terminate_video()
|
void terminate_video(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_CALLS; ++i) {
|
for (i = 0; i < CallControl.max_calls; ++i) {
|
||||||
Call *this_call = &CallControl.calls[i];
|
Call *this_call = &CallControl.calls[i];
|
||||||
|
|
||||||
stop_video_transmission(this_call, i);
|
stop_video_transmission(this_call, i);
|
||||||
|
|
||||||
if ( this_call->vout_idx != -1 )
|
if (this_call->vout_idx != -1) {
|
||||||
close_video_device(vdt_output, this_call->vout_idx);
|
close_video_device(vdt_output, this_call->vout_idx);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
terminate_video_devices();
|
terminate_video_devices();
|
||||||
}
|
}
|
||||||
@ -100,7 +102,7 @@ void read_video_device_callback(int16_t width, int16_t height, const uint8_t *y,
|
|||||||
{
|
{
|
||||||
uint32_t friend_number = *((uint32_t *)data); /* TODO: Or pass an array of call_idx's */
|
uint32_t friend_number = *((uint32_t *)data); /* TODO: Or pass an array of call_idx's */
|
||||||
Call *this_call = &CallControl.calls[friend_number];
|
Call *this_call = &CallControl.calls[friend_number];
|
||||||
TOXAV_ERR_SEND_FRAME error;
|
Toxav_Err_Send_Frame error;
|
||||||
|
|
||||||
/* Drop frame if video sending is disabled */
|
/* Drop frame if video sending is disabled */
|
||||||
if (CallControl.video_bit_rate == 0 || this_call->vin_idx == -1) {
|
if (CallControl.video_bit_rate == 0 || this_call->vin_idx == -1) {
|
||||||
@ -111,12 +113,13 @@ void read_video_device_callback(int16_t width, int16_t height, const uint8_t *y,
|
|||||||
if (toxav_video_send_frame(CallControl.av, friend_number, width, height, y, u, v, &error) == false) {
|
if (toxav_video_send_frame(CallControl.av, friend_number, width, height, y, u, v, &error) == false) {
|
||||||
line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to send video frame");
|
line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to send video frame");
|
||||||
|
|
||||||
if ( error == TOXAV_ERR_SEND_FRAME_NULL )
|
if (error == TOXAV_ERR_SEND_FRAME_NULL) {
|
||||||
line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to capture video frame");
|
line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to capture video frame");
|
||||||
else if ( error == TOXAV_ERR_SEND_FRAME_INVALID )
|
} else if (error == TOXAV_ERR_SEND_FRAME_INVALID) {
|
||||||
line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to prepare video frame");
|
line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to prepare video frame");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void write_video_device_callback(uint32_t friend_number, uint16_t width, uint16_t height,
|
void write_video_device_callback(uint32_t friend_number, uint16_t width, uint16_t height,
|
||||||
uint8_t const *y, uint8_t const *u, uint8_t const *v,
|
uint8_t const *y, uint8_t const *u, uint8_t const *v,
|
||||||
@ -135,7 +138,7 @@ int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call)
|
|||||||
|
|
||||||
CallControl.video_bit_rate = default_video_bit_rate;
|
CallControl.video_bit_rate = default_video_bit_rate;
|
||||||
|
|
||||||
if ( toxav_bit_rate_set(CallControl.av, self->num, -1, CallControl.video_bit_rate, NULL) == false ) {
|
if (toxav_video_set_bit_rate(CallControl.av, self->num, CallControl.video_bit_rate, NULL) == false) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set video bit rate");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set video bit rate");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -156,7 +159,7 @@ int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call)
|
|||||||
int stop_video_transmission(Call *call, int friend_number)
|
int stop_video_transmission(Call *call, int friend_number)
|
||||||
{
|
{
|
||||||
CallControl.video_bit_rate = 0;
|
CallControl.video_bit_rate = 0;
|
||||||
toxav_bit_rate_set(CallControl.av, friend_number, -1, CallControl.video_bit_rate, NULL);
|
toxav_video_set_bit_rate(CallControl.av, friend_number, CallControl.video_bit_rate, NULL);
|
||||||
|
|
||||||
if (call->vin_idx != -1) {
|
if (call->vin_idx != -1) {
|
||||||
close_video_device(vdt_input, call->vin_idx);
|
close_video_device(vdt_input, call->vin_idx);
|
||||||
@ -176,7 +179,7 @@ int stop_video_transmission(Call *call, int friend_number)
|
|||||||
/*
|
/*
|
||||||
* Callbacks
|
* Callbacks
|
||||||
*/
|
*/
|
||||||
void receive_video_frame_cb(ToxAV *av, uint32_t friend_number,
|
void on_video_receive_frame(ToxAV *av, uint32_t friend_number,
|
||||||
uint16_t width, uint16_t height,
|
uint16_t width, uint16_t height,
|
||||||
uint8_t const *y, uint8_t const *u, uint8_t const *v,
|
uint8_t const *y, uint8_t const *u, uint8_t const *v,
|
||||||
int32_t ystride, int32_t ustride, int32_t vstride,
|
int32_t ystride, int32_t ustride, int32_t vstride,
|
||||||
@ -185,19 +188,19 @@ void receive_video_frame_cb(ToxAV *av, uint32_t friend_number,
|
|||||||
write_video_device_callback(friend_number, width, height, y, u, v, ystride, ustride, vstride, user_data);
|
write_video_device_callback(friend_number, width, height, y, u, v, ystride, ustride, vstride, user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void video_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate,
|
void on_video_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t video_bit_rate, void *user_data)
|
||||||
uint32_t video_bit_rate, void *user_data)
|
|
||||||
{
|
{
|
||||||
CallControl.video_bit_rate = video_bit_rate;
|
CallControl.video_bit_rate = video_bit_rate;
|
||||||
toxav_bit_rate_set(CallControl.av, friend_number, -1, CallControl.video_bit_rate, NULL);
|
toxav_video_set_bit_rate(CallControl.av, friend_number, CallControl.video_bit_rate, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void callback_recv_video_starting(uint32_t friend_number)
|
void callback_recv_video_starting(uint32_t friend_number)
|
||||||
{
|
{
|
||||||
Call *this_call = &CallControl.calls[friend_number];
|
Call *this_call = &CallControl.calls[friend_number];
|
||||||
|
|
||||||
if ( this_call->vout_idx != -1 )
|
if (this_call->vout_idx != -1) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
open_primary_video_device(vdt_output, &this_call->vout_idx);
|
open_primary_video_device(vdt_output, &this_call->vout_idx);
|
||||||
}
|
}
|
||||||
@ -213,7 +216,7 @@ void callback_video_starting(uint32_t friend_number)
|
|||||||
ToxWindow *windows = CallControl.prompt;
|
ToxWindow *windows = CallControl.prompt;
|
||||||
Call *this_call = &CallControl.calls[friend_number];
|
Call *this_call = &CallControl.calls[friend_number];
|
||||||
|
|
||||||
TOXAV_ERR_CALL_CONTROL error = TOXAV_ERR_CALL_CONTROL_OK;
|
Toxav_Err_Call_Control error = TOXAV_ERR_CALL_CONTROL_OK;
|
||||||
toxav_call_control(CallControl.av, friend_number, TOXAV_CALL_CONTROL_SHOW_VIDEO, &error);
|
toxav_call_control(CallControl.av, friend_number, TOXAV_CALL_CONTROL_SHOW_VIDEO, &error);
|
||||||
|
|
||||||
if (error == TOXAV_ERR_CALL_CONTROL_OK) {
|
if (error == TOXAV_ERR_CALL_CONTROL_OK) {
|
||||||
@ -269,10 +272,11 @@ void cmd_video(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[M
|
|||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( this_call->vin_idx == -1 )
|
if (this_call->vin_idx == -1) {
|
||||||
callback_video_starting(self->num);
|
callback_video_starting(self->num);
|
||||||
else
|
} else {
|
||||||
callback_video_end(self->num);
|
callback_video_end(self->num);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
on_error:
|
on_error:
|
||||||
@ -284,19 +288,24 @@ void cmd_list_video_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, c
|
|||||||
const char *error_str;
|
const char *error_str;
|
||||||
|
|
||||||
if (argc != 1) {
|
if (argc != 1) {
|
||||||
if ( argc < 1 ) error_str = "Type must be specified!";
|
if (argc < 1) {
|
||||||
else error_str = "Only one argument allowed!";
|
error_str = "Type must be specified!";
|
||||||
|
} else {
|
||||||
|
error_str = "Only one argument allowed!";
|
||||||
|
}
|
||||||
|
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoDeviceType type;
|
VideoDeviceType type;
|
||||||
|
|
||||||
if ( strcasecmp(argv[1], "in") == 0 ) /* Input devices */
|
if (strcasecmp(argv[1], "in") == 0) { /* Input devices */
|
||||||
type = vdt_input;
|
type = vdt_input;
|
||||||
|
}
|
||||||
|
|
||||||
else if ( strcasecmp(argv[1], "out") == 0 ) /* Output devices */
|
else if (strcasecmp(argv[1], "out") == 0) { /* Output devices */
|
||||||
type = vdt_output;
|
type = vdt_output;
|
||||||
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
||||||
@ -316,20 +325,26 @@ void cmd_change_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc,
|
|||||||
const char *error_str;
|
const char *error_str;
|
||||||
|
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
if ( argc < 1 ) error_str = "Type must be specified!";
|
if (argc < 1) {
|
||||||
else if ( argc < 2 ) error_str = "Must have id!";
|
error_str = "Type must be specified!";
|
||||||
else error_str = "Only two arguments allowed!";
|
} else if (argc < 2) {
|
||||||
|
error_str = "Must have id!";
|
||||||
|
} else {
|
||||||
|
error_str = "Only two arguments allowed!";
|
||||||
|
}
|
||||||
|
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoDeviceType type;
|
VideoDeviceType type;
|
||||||
|
|
||||||
if ( strcmp(argv[1], "in") == 0 ) /* Input devices */
|
if (strcmp(argv[1], "in") == 0) { /* Input devices */
|
||||||
type = vdt_input;
|
type = vdt_input;
|
||||||
|
}
|
||||||
|
|
||||||
else if ( strcmp(argv[1], "out") == 0 ) /* Output devices */
|
else if (strcmp(argv[1], "out") == 0) { /* Output devices */
|
||||||
type = vdt_output;
|
type = vdt_output;
|
||||||
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
||||||
@ -360,20 +375,26 @@ void cmd_ccur_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, ch
|
|||||||
const char *error_str;
|
const char *error_str;
|
||||||
|
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
if ( argc < 1 ) error_str = "Type must be specified!";
|
if (argc < 1) {
|
||||||
else if ( argc < 2 ) error_str = "Must have id!";
|
error_str = "Type must be specified!";
|
||||||
else error_str = "Only two arguments allowed!";
|
} else if (argc < 2) {
|
||||||
|
error_str = "Must have id!";
|
||||||
|
} else {
|
||||||
|
error_str = "Only two arguments allowed!";
|
||||||
|
}
|
||||||
|
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoDeviceType type;
|
VideoDeviceType type;
|
||||||
|
|
||||||
if ( strcmp(argv[1], "in") == 0 ) /* Input devices */
|
if (strcmp(argv[1], "in") == 0) { /* Input devices */
|
||||||
type = vdt_input;
|
type = vdt_input;
|
||||||
|
}
|
||||||
|
|
||||||
else if ( strcmp(argv[1], "out") == 0 ) /* Output devices */
|
else if (strcmp(argv[1], "out") == 0) { /* Output devices */
|
||||||
type = vdt_output;
|
type = vdt_output;
|
||||||
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
||||||
@ -421,6 +442,9 @@ void stop_video_stream(ToxWindow *self)
|
|||||||
{
|
{
|
||||||
Call *this_call = &CallControl.calls[self->num];
|
Call *this_call = &CallControl.calls[self->num];
|
||||||
|
|
||||||
if (this_call && this_call->vin_idx != -1)
|
if (this_call && this_call->vin_idx != -1) {
|
||||||
stop_video_transmission(this_call, self->num);
|
stop_video_transmission(this_call, self->num);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* VIDEO */
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
/* You will have to pass pointer to first member of 'windows' declared in windows.c */
|
/* You will have to pass pointer to first member of 'windows' declared in windows.c */
|
||||||
ToxAV *init_video(ToxWindow *self, Tox *tox);
|
ToxAV *init_video(ToxWindow *self, Tox *tox);
|
||||||
void terminate_video();
|
void terminate_video(void);
|
||||||
int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call);
|
int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call);
|
||||||
int stop_video_transmission(Call *call, int friend_number);
|
int stop_video_transmission(Call *call, int friend_number);
|
||||||
void stop_video_stream(ToxWindow *self);
|
void stop_video_stream(ToxWindow *self);
|
||||||
|
@ -37,12 +37,12 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#if defined(__linux__)
|
#if defined(__OpenBSD__) || defined(__NetBSD__)
|
||||||
#include <linux/videodev2.h>
|
|
||||||
#else
|
|
||||||
#include <sys/videoio.h>
|
#include <sys/videoio.h>
|
||||||
#endif
|
#else
|
||||||
#endif
|
#include <linux/videodev2.h>
|
||||||
|
#endif /* defined(__OpenBSD__) || defined(__NetBSD__) */
|
||||||
|
#endif /* __OSX__ */
|
||||||
|
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
@ -55,6 +55,8 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef VIDEO
|
||||||
|
|
||||||
#define inline__ inline __attribute__((always_inline))
|
#define inline__ inline __attribute__((always_inline))
|
||||||
|
|
||||||
extern struct user_settings *user_settings;
|
extern struct user_settings *user_settings;
|
||||||
@ -69,7 +71,7 @@ typedef struct VideoDevice {
|
|||||||
void *cb_data; /* Data to be passed to callback */
|
void *cb_data; /* Data to be passed to callback */
|
||||||
int32_t friend_number; /* ToxAV friend number */
|
int32_t friend_number; /* ToxAV friend number */
|
||||||
|
|
||||||
#if defined(__linux__) || SYSTEM == BSD
|
#if !defined(__OSX__)
|
||||||
int fd; /* File descriptor of video device selected/opened */
|
int fd; /* File descriptor of video device selected/opened */
|
||||||
struct v4l2_format fmt;
|
struct v4l2_format fmt;
|
||||||
struct VideoBuffer *buffers;
|
struct VideoBuffer *buffers;
|
||||||
@ -96,9 +98,7 @@ static int size[2]; /* Size of above containers */
|
|||||||
VideoDevice *video_devices_running[2][MAX_DEVICES] = {{NULL}}; /* Running devices */
|
VideoDevice *video_devices_running[2][MAX_DEVICES] = {{NULL}}; /* Running devices */
|
||||||
uint32_t primary_video_device[2]; /* Primary device */
|
uint32_t primary_video_device[2]; /* Primary device */
|
||||||
|
|
||||||
#ifdef VIDEO
|
|
||||||
static ToxAV *av = NULL;
|
static ToxAV *av = NULL;
|
||||||
#endif /* VIDEO */
|
|
||||||
|
|
||||||
/* q_mutex */
|
/* q_mutex */
|
||||||
#define lock pthread_mutex_lock(&video_mutex);
|
#define lock pthread_mutex_lock(&video_mutex);
|
||||||
@ -136,7 +136,7 @@ static void yuv420tobgr(uint16_t width, uint16_t height, const uint8_t *y,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__linux__) || SYSTEM == BSD
|
#if !defined(__OSX__)
|
||||||
static void yuv422to420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v,
|
static void yuv422to420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v,
|
||||||
uint8_t *input, uint16_t width, uint16_t height)
|
uint8_t *input, uint16_t width, uint16_t height)
|
||||||
{
|
{
|
||||||
@ -186,8 +186,11 @@ VideoDeviceError init_video_devices()
|
|||||||
size[vdt_input] = 0;
|
size[vdt_input] = 0;
|
||||||
|
|
||||||
#if defined(__OSX__)
|
#if defined(__OSX__)
|
||||||
if( osx_video_init((char**)video_devices_names[vdt_input], &size[vdt_input]) != 0 )
|
|
||||||
|
if (osx_video_init((char **)video_devices_names[vdt_input], &size[vdt_input]) != 0) {
|
||||||
return vde_InternalError;
|
return vde_InternalError;
|
||||||
|
}
|
||||||
|
|
||||||
#else /* not __OSX__*/
|
#else /* not __OSX__*/
|
||||||
|
|
||||||
for (; size[vdt_input] <= MAX_DEVICES; ++size[vdt_input]) {
|
for (; size[vdt_input] <= MAX_DEVICES; ++size[vdt_input]) {
|
||||||
@ -230,13 +233,15 @@ VideoDeviceError init_video_devices()
|
|||||||
video_devices_names[vdt_output][0] = video_output_name;
|
video_devices_names[vdt_output][0] = video_output_name;
|
||||||
|
|
||||||
// Start poll thread
|
// Start poll thread
|
||||||
if ( pthread_mutex_init(&video_mutex, NULL) != 0 )
|
if (pthread_mutex_init(&video_mutex, NULL) != 0) {
|
||||||
return vde_InternalError;
|
return vde_InternalError;
|
||||||
|
}
|
||||||
|
|
||||||
pthread_t thread_id;
|
pthread_t thread_id;
|
||||||
|
|
||||||
if ( pthread_create(&thread_id, NULL, video_thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0 )
|
if (pthread_create(&thread_id, NULL, video_thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0) {
|
||||||
return vde_InternalError;
|
return vde_InternalError;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
av = av_;
|
av = av_;
|
||||||
@ -245,7 +250,7 @@ VideoDeviceError init_video_devices()
|
|||||||
return (VideoDeviceError) vde_None;
|
return (VideoDeviceError) vde_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoDeviceError terminate_video_devices()
|
VideoDeviceError terminate_video_devices(void)
|
||||||
{
|
{
|
||||||
/* Cleanup if needed */
|
/* Cleanup if needed */
|
||||||
lock;
|
lock;
|
||||||
@ -260,8 +265,9 @@ VideoDeviceError terminate_video_devices()
|
|||||||
free((void *)video_devices_names[vdt_input][i]);
|
free((void *)video_devices_names[vdt_input][i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( pthread_mutex_destroy(&video_mutex) != 0 )
|
if (pthread_mutex_destroy(&video_mutex) != 0) {
|
||||||
return (VideoDeviceError) vde_InternalError;
|
return (VideoDeviceError) vde_InternalError;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __OSX__
|
#ifdef __OSX__
|
||||||
osx_video_release();
|
osx_video_release();
|
||||||
@ -275,14 +281,16 @@ VideoDeviceError register_video_device_callback(int32_t friend_number, uint32_t
|
|||||||
{
|
{
|
||||||
#if defined(__OSX__)
|
#if defined(__OSX__)
|
||||||
|
|
||||||
if ( size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx] )
|
if (size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx]) {
|
||||||
return vde_InvalidSelection;
|
return vde_InvalidSelection;
|
||||||
|
}
|
||||||
|
|
||||||
#else /* not __OSX__ */
|
#else /* not __OSX__ */
|
||||||
|
|
||||||
if (size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx]
|
if (size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx]
|
||||||
|| !video_devices_running[vdt_input][device_idx]->fd )
|
|| !video_devices_running[vdt_input][device_idx]->fd) {
|
||||||
return vde_InvalidSelection;
|
return vde_InvalidSelection;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -297,7 +305,9 @@ VideoDeviceError register_video_device_callback(int32_t friend_number, uint32_t
|
|||||||
|
|
||||||
VideoDeviceError set_primary_video_device(VideoDeviceType type, int32_t selection)
|
VideoDeviceError set_primary_video_device(VideoDeviceType type, int32_t selection)
|
||||||
{
|
{
|
||||||
if ( size[type] <= selection || selection < 0 ) return vde_InvalidSelection;
|
if (size[type] <= selection || selection < 0) {
|
||||||
|
return vde_InvalidSelection;
|
||||||
|
}
|
||||||
|
|
||||||
primary_video_device[type] = selection;
|
primary_video_device[type] = selection;
|
||||||
|
|
||||||
@ -316,7 +326,9 @@ void get_primary_video_device_name(VideoDeviceType type, char *buf, int size)
|
|||||||
|
|
||||||
VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint32_t *device_idx)
|
VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint32_t *device_idx)
|
||||||
{
|
{
|
||||||
if ( size[type] <= selection || selection < 0 ) return vde_InvalidSelection;
|
if (size[type] <= selection || selection < 0) {
|
||||||
|
return vde_InvalidSelection;
|
||||||
|
}
|
||||||
|
|
||||||
lock;
|
lock;
|
||||||
|
|
||||||
@ -358,11 +370,13 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
|||||||
video_thread_paused = true;
|
video_thread_paused = true;
|
||||||
|
|
||||||
#if defined(__OSX__)
|
#if defined(__OSX__)
|
||||||
|
|
||||||
if (osx_video_open_device(selection, &device->video_width, &device->video_height) != 0) {
|
if (osx_video_open_device(selection, &device->video_width, &device->video_height) != 0) {
|
||||||
free(device);
|
free(device);
|
||||||
unlock;
|
unlock;
|
||||||
return vde_FailedStart;
|
return vde_FailedStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* not __OSX__*/
|
#else /* not __OSX__*/
|
||||||
/* Open selected device */
|
/* Open selected device */
|
||||||
char device_address[] = "/dev/videoXX";
|
char device_address[] = "/dev/videoXX";
|
||||||
@ -448,8 +462,9 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
|||||||
device->fd, buf.m.offset);
|
device->fd, buf.m.offset);
|
||||||
|
|
||||||
if (MAP_FAILED == device->buffers[i].start) {
|
if (MAP_FAILED == device->buffers[i].start) {
|
||||||
for (i = 0; i < buf.index; ++i)
|
for (i = 0; i < buf.index; ++i) {
|
||||||
munmap(device->buffers[i].start, device->buffers[i].length);
|
munmap(device->buffers[i].start, device->buffers[i].length);
|
||||||
|
}
|
||||||
|
|
||||||
close(device->fd);
|
close(device->fd);
|
||||||
free(device);
|
free(device);
|
||||||
@ -471,8 +486,9 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
|||||||
buf.index = i;
|
buf.index = i;
|
||||||
|
|
||||||
if (-1 == xioctl(device->fd, VIDIOC_QBUF, &buf)) {
|
if (-1 == xioctl(device->fd, VIDIOC_QBUF, &buf)) {
|
||||||
for (i = 0; i < device->n_buffers; ++i)
|
for (i = 0; i < device->n_buffers; ++i) {
|
||||||
munmap(device->buffers[i].start, device->buffers[i].length);
|
munmap(device->buffers[i].start, device->buffers[i].length);
|
||||||
|
}
|
||||||
|
|
||||||
close(device->fd);
|
close(device->fd);
|
||||||
free(device);
|
free(device);
|
||||||
@ -575,16 +591,20 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
|||||||
return vde_None;
|
return vde_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
__inline VideoDeviceError write_video_out(uint16_t width, uint16_t height,
|
VideoDeviceError write_video_out(uint16_t width, uint16_t height,
|
||||||
uint8_t const *y, uint8_t const *u, uint8_t const *v,
|
uint8_t const *y, uint8_t const *u, uint8_t const *v,
|
||||||
int32_t ystride, int32_t ustride, int32_t vstride,
|
int32_t ystride, int32_t ustride, int32_t vstride,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
VideoDevice *device = video_devices_running[vdt_output][0];
|
VideoDevice *device = video_devices_running[vdt_output][0];
|
||||||
|
|
||||||
if ( !device ) return vde_DeviceNotActive;
|
if (!device) {
|
||||||
|
return vde_DeviceNotActive;
|
||||||
|
}
|
||||||
|
|
||||||
if ( !device->x_window ) return vde_DeviceNotActive;
|
if (!device->x_window) {
|
||||||
|
return vde_DeviceNotActive;
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(device->mutex);
|
pthread_mutex_lock(device->mutex);
|
||||||
|
|
||||||
@ -652,8 +672,9 @@ void *video_thread_poll (void *arg) // TODO: maybe use thread for every input so
|
|||||||
|
|
||||||
unlock;
|
unlock;
|
||||||
|
|
||||||
if ( video_thread_paused ) usleep(10000); /* Wait for unpause. */
|
if (video_thread_paused) {
|
||||||
else {
|
usleep(10000); /* Wait for unpause. */
|
||||||
|
} else {
|
||||||
for (i = 0; i < size[vdt_input]; ++i) {
|
for (i = 0; i < size[vdt_input]; ++i) {
|
||||||
lock;
|
lock;
|
||||||
|
|
||||||
@ -667,10 +688,12 @@ void *video_thread_poll (void *arg) // TODO: maybe use thread for every input so
|
|||||||
uint8_t *v = device->input.planes[2];
|
uint8_t *v = device->input.planes[2];
|
||||||
|
|
||||||
#if defined(__OSX__)
|
#if defined(__OSX__)
|
||||||
|
|
||||||
if (osx_video_read_device(y, u, v, &video_width, &video_height) != 0) {
|
if (osx_video_read_device(y, u, v, &video_width, &video_height) != 0) {
|
||||||
unlock;
|
unlock;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* not __OSX__*/
|
#else /* not __OSX__*/
|
||||||
struct v4l2_buffer buf;
|
struct v4l2_buffer buf;
|
||||||
memset(&(buf), 0, sizeof(buf));
|
memset(&(buf), 0, sizeof(buf));
|
||||||
@ -691,8 +714,9 @@ void *video_thread_poll (void *arg) // TODO: maybe use thread for every input so
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Send frame data to friend through ToxAV */
|
/* Send frame data to friend through ToxAV */
|
||||||
if ( device->cb )
|
if (device->cb) {
|
||||||
device->cb(video_width, video_height, y, u, v, device->cb_data);
|
device->cb(video_width, video_height, y, u, v, device->cb_data);
|
||||||
|
}
|
||||||
|
|
||||||
/* Convert YUV420 data to BGR */
|
/* Convert YUV420 data to BGR */
|
||||||
uint8_t *img_data = malloc(video_width * video_height * 4);
|
uint8_t *img_data = malloc(video_width * video_height * 4);
|
||||||
@ -724,14 +748,14 @@ void *video_thread_poll (void *arg) // TODO: maybe use thread for every input so
|
|||||||
XFlush(device->x_display);
|
XFlush(device->x_display);
|
||||||
free(img_data);
|
free(img_data);
|
||||||
|
|
||||||
#if defined(__linux__) || SYSTEM == BSD
|
#if !defined(__OSX__)
|
||||||
|
|
||||||
if (-1 == xioctl(device->fd, VIDIOC_QBUF, &buf)) {
|
if (-1 == xioctl(device->fd, VIDIOC_QBUF, &buf)) {
|
||||||
unlock;
|
unlock;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* __linux__ / BSD */
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -747,7 +771,9 @@ void *video_thread_poll (void *arg) // TODO: maybe use thread for every input so
|
|||||||
|
|
||||||
VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
|
VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
|
||||||
{
|
{
|
||||||
if ( device_idx >= MAX_DEVICES ) return vde_InvalidSelection;
|
if (device_idx >= MAX_DEVICES) {
|
||||||
|
return vde_InvalidSelection;
|
||||||
|
}
|
||||||
|
|
||||||
lock;
|
lock;
|
||||||
VideoDevice *device = video_devices_running[type][device_idx];
|
VideoDevice *device = video_devices_running[type][device_idx];
|
||||||
@ -787,9 +813,9 @@ VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
|
|||||||
XCloseDisplay(device->x_display);
|
XCloseDisplay(device->x_display);
|
||||||
pthread_mutex_destroy(device->mutex);
|
pthread_mutex_destroy(device->mutex);
|
||||||
|
|
||||||
#if defined(__linux__) || SYSTEM == BSD
|
#if !defined(__OSX__)
|
||||||
free(device->buffers);
|
free(device->buffers);
|
||||||
#endif /* __linux__ / BSD */
|
#endif /* not __OSX__ */
|
||||||
|
|
||||||
free(device);
|
free(device);
|
||||||
} else {
|
} else {
|
||||||
@ -801,7 +827,9 @@ VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
|
|||||||
free(device);
|
free(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else device->ref_count--;
|
} else {
|
||||||
|
device->ref_count--;
|
||||||
|
}
|
||||||
|
|
||||||
unlock;
|
unlock;
|
||||||
return rc;
|
return rc;
|
||||||
@ -811,8 +839,9 @@ void print_video_devices(ToxWindow *self, VideoDeviceType type)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < size[type]; ++i)
|
for (i = 0; i < size[type]; ++i) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%d: %s", i, video_devices_names[type][i]);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%d: %s", i, video_devices_names[type][i]);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -821,3 +850,5 @@ VideoDeviceError video_selection_valid(VideoDeviceType type, int32_t selection)
|
|||||||
{
|
{
|
||||||
return (size[type] <= selection || selection < 0) ? vde_InvalidSelection : vde_None;
|
return (size[type] <= selection || selection < 0) ? vde_InvalidSelection : vde_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* VIDEO */
|
||||||
|
@ -51,10 +51,10 @@ typedef void (*VideoDataHandleCallback) (int16_t width, int16_t height, const ui
|
|||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
VideoDeviceError init_video_devices(ToxAV *av);
|
VideoDeviceError init_video_devices(ToxAV *av);
|
||||||
#else
|
#else
|
||||||
VideoDeviceError init_video_devices();
|
VideoDeviceError init_video_devices(void);
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
|
|
||||||
VideoDeviceError terminate_video_devices();
|
VideoDeviceError terminate_video_devices(void);
|
||||||
|
|
||||||
/* Callback handles ready data from INPUT device */
|
/* Callback handles ready data from INPUT device */
|
||||||
VideoDeviceError register_video_device_callback(int32_t call_idx, uint32_t device_idx, VideoDataHandleCallback callback,
|
VideoDeviceError register_video_device_callback(int32_t call_idx, uint32_t device_idx, VideoDataHandleCallback callback,
|
||||||
|
426
src/windows.c
426
src/windows.c
@ -39,165 +39,166 @@
|
|||||||
|
|
||||||
extern char *DATA_FILE;
|
extern char *DATA_FILE;
|
||||||
extern struct Winthread Winthread;
|
extern struct Winthread Winthread;
|
||||||
static ToxWindow windows[MAX_WINDOWS_NUM];
|
|
||||||
static ToxWindow *active_window;
|
ToxWindow *windows[MAX_WINDOWS_NUM];
|
||||||
|
static uint8_t active_window_index;
|
||||||
|
static int num_active_windows;
|
||||||
|
|
||||||
extern ToxWindow *prompt;
|
extern ToxWindow *prompt;
|
||||||
extern struct user_settings *user_settings;
|
extern struct user_settings *user_settings;
|
||||||
|
|
||||||
static int num_active_windows;
|
|
||||||
|
|
||||||
/* CALLBACKS START */
|
/* CALLBACKS START */
|
||||||
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
|
void on_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
|
||||||
{
|
{
|
||||||
char msg[MAX_STR_SIZE + 1];
|
char msg[MAX_STR_SIZE + 1];
|
||||||
length = copy_tox_str(msg, sizeof(msg), (const char *) data, length);
|
length = copy_tox_str(msg, sizeof(msg), (const char *) data, length);
|
||||||
|
|
||||||
size_t i;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i] != NULL && windows[i]->onFriendRequest != NULL) {
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
windows[i]->onFriendRequest(windows[i], m, (const char *) public_key, msg, length);
|
||||||
if (windows[i].onFriendRequest != NULL) {
|
|
||||||
windows[i].onFriendRequest(&windows[i], m, (const char *) public_key, msg, length);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_connectionchange(Tox *m, uint32_t friendnumber, TOX_CONNECTION connection_status, void *userdata)
|
void on_friend_connection_status(Tox *m, uint32_t friendnumber, Tox_Connection connection_status, void *userdata)
|
||||||
{
|
{
|
||||||
size_t i;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i] != NULL && windows[i]->onConnectionChange != NULL) {
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
windows[i]->onConnectionChange(windows[i], m, friendnumber, connection_status);
|
||||||
if (windows[i].onConnectionChange != NULL)
|
}
|
||||||
windows[i].onConnectionChange(&windows[i], m, friendnumber, connection_status);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_typing_change(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata)
|
void on_friend_typing(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata)
|
||||||
{
|
{
|
||||||
if (user_settings->show_typing_other == SHOW_TYPING_OFF)
|
if (user_settings->show_typing_other == SHOW_TYPING_OFF) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
size_t i;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i] != NULL && windows[i]->onTypingChange != NULL) {
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
windows[i]->onTypingChange(windows[i], m, friendnumber, is_typing);
|
||||||
if (windows[i].onTypingChange != NULL)
|
}
|
||||||
windows[i].onTypingChange(&windows[i], m, friendnumber, is_typing);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_message(Tox *m, uint32_t friendnumber, TOX_MESSAGE_TYPE type, const uint8_t *string, size_t length,
|
void on_friend_message(Tox *m, uint32_t friendnumber, Tox_Message_Type type, const uint8_t *string, size_t length,
|
||||||
void *userdata)
|
void *userdata)
|
||||||
{
|
{
|
||||||
char msg[MAX_STR_SIZE + 1];
|
char msg[MAX_STR_SIZE + 1];
|
||||||
length = copy_tox_str(msg, sizeof(msg), (const char *) string, length);
|
length = copy_tox_str(msg, sizeof(msg), (const char *) string, length);
|
||||||
|
|
||||||
size_t i;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i] != NULL && windows[i]->onMessage != NULL) {
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
windows[i]->onMessage(windows[i], m, friendnumber, type, msg, length);
|
||||||
if (windows[i].onMessage != NULL)
|
}
|
||||||
windows[i].onMessage(&windows[i], m, friendnumber, type, msg, length);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_nickchange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata)
|
void on_friend_name(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata)
|
||||||
{
|
{
|
||||||
char nick[TOXIC_MAX_NAME_LENGTH + 1];
|
char nick[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
length = copy_tox_str(nick, sizeof(nick), (const char *) string, length);
|
length = copy_tox_str(nick, sizeof(nick), (const char *) string, length);
|
||||||
filter_str(nick, length);
|
filter_str(nick, length);
|
||||||
|
|
||||||
size_t i;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i] != NULL && windows[i]->onNickChange != NULL) {
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
windows[i]->onNickChange(windows[i], m, friendnumber, nick, length);
|
||||||
if (windows[i].onNickChange != NULL)
|
}
|
||||||
windows[i].onNickChange(&windows[i], m, friendnumber, nick, length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
store_data(m, DATA_FILE);
|
store_data(m, DATA_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_statusmessagechange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata)
|
void on_friend_status_message(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata)
|
||||||
{
|
{
|
||||||
char msg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
|
char msg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
|
||||||
length = copy_tox_str(msg, sizeof(msg), (const char *) string, length);
|
length = copy_tox_str(msg, sizeof(msg), (const char *) string, length);
|
||||||
filter_str(msg, length);
|
filter_str(msg, length);
|
||||||
|
|
||||||
size_t i;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i] != NULL && windows[i]->onStatusMessageChange != NULL) {
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
windows[i]->onStatusMessageChange(windows[i], friendnumber, msg, length);
|
||||||
if (windows[i].onStatusMessageChange != NULL)
|
}
|
||||||
windows[i].onStatusMessageChange(&windows[i], friendnumber, msg, length);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_statuschange(Tox *m, uint32_t friendnumber, TOX_USER_STATUS status, void *userdata)
|
void on_friend_status(Tox *m, uint32_t friendnumber, Tox_User_Status status, void *userdata)
|
||||||
{
|
{
|
||||||
size_t i;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i] != NULL && windows[i]->onStatusChange != NULL) {
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
windows[i]->onStatusChange(windows[i], m, friendnumber, status);
|
||||||
if (windows[i].onStatusChange != NULL)
|
}
|
||||||
windows[i].onStatusChange(&windows[i], m, friendnumber, status);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_friendadded(Tox *m, uint32_t friendnumber, bool sort)
|
void on_friend_added(Tox *m, uint32_t friendnumber, bool sort)
|
||||||
{
|
{
|
||||||
size_t i;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i] != NULL && windows[i]->onFriendAdded != NULL) {
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
windows[i]->onFriendAdded(windows[i], m, friendnumber, sort);
|
||||||
if (windows[i].onFriendAdded != NULL)
|
}
|
||||||
windows[i].onFriendAdded(&windows[i], m, friendnumber, sort);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
store_data(m, DATA_FILE);
|
store_data(m, DATA_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_groupmessage(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_MESSAGE_TYPE type,
|
void on_conference_message(Tox *m, uint32_t groupnumber, uint32_t peernumber, Tox_Message_Type type,
|
||||||
const uint8_t *message, size_t length, void *userdata)
|
const uint8_t *message, size_t length, void *userdata)
|
||||||
{
|
{
|
||||||
char msg[MAX_STR_SIZE + 1];
|
char msg[MAX_STR_SIZE + 1];
|
||||||
length = copy_tox_str(msg, sizeof(msg), (const char *) message, length);
|
length = copy_tox_str(msg, sizeof(msg), (const char *) message, length);
|
||||||
|
|
||||||
size_t i;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i] != NULL && windows[i]->onGroupMessage != NULL) {
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
windows[i]->onGroupMessage(windows[i], m, groupnumber, peernumber, type, msg, length);
|
||||||
if (windows[i].onGroupMessage != NULL)
|
}
|
||||||
windows[i].onGroupMessage(&windows[i], m, groupnumber, peernumber, type, msg, length);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_groupinvite(Tox *m, uint32_t friendnumber, TOX_CONFERENCE_TYPE type, const uint8_t *group_pub_key,
|
void on_conference_invite(Tox *m, uint32_t friendnumber, Tox_Conference_Type type, const uint8_t *group_pub_key,
|
||||||
size_t length, void *userdata)
|
size_t length, void *userdata)
|
||||||
{
|
{
|
||||||
size_t i;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i] != NULL && windows[i]->onGroupInvite != NULL) {
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
windows[i]->onGroupInvite(windows[i], m, friendnumber, type, (char *) group_pub_key, length);
|
||||||
if (windows[i].onGroupInvite != NULL)
|
}
|
||||||
windows[i].onGroupInvite(&windows[i], m, friendnumber, type, (char *) group_pub_key, length);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_group_namelistchange(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_CONFERENCE_STATE_CHANGE change,
|
void on_conference_peer_list_changed(Tox *m, uint32_t groupnumber, void *userdata)
|
||||||
void *userdata)
|
|
||||||
{
|
{
|
||||||
size_t i;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i] != NULL && windows[i]->onGroupNameListChange != NULL) {
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
windows[i]->onGroupNameListChange(windows[i], m, groupnumber);
|
||||||
if (windows[i].onGroupNamelistChange != NULL)
|
}
|
||||||
windows[i].onGroupNamelistChange(&windows[i], m, groupnumber, peernumber, change);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_group_titlechange(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *title, size_t length,
|
void on_conference_peer_name(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *name,
|
||||||
|
size_t length, void *userdata)
|
||||||
|
{
|
||||||
|
char nick[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
|
length = copy_tox_str(nick, sizeof(nick), (const char *) name, length);
|
||||||
|
filter_str(nick, length);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i] != NULL && windows[i]->onGroupPeerNameChange != NULL) {
|
||||||
|
windows[i]->onGroupPeerNameChange(windows[i], m, groupnumber, peernumber, nick, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_conference_title(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *title, size_t length,
|
||||||
void *userdata)
|
void *userdata)
|
||||||
{
|
{
|
||||||
char data[MAX_STR_SIZE + 1];
|
char data[MAX_STR_SIZE + 1];
|
||||||
length = copy_tox_str(data, sizeof(data), (const char *) title, length);
|
length = copy_tox_str(data, sizeof(data), (const char *) title, length);
|
||||||
|
|
||||||
size_t i;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i] != NULL && windows[i]->onGroupTitleChange != NULL) {
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
windows[i]->onGroupTitleChange(windows[i], m, groupnumber, peernumber, data, length);
|
||||||
if (windows[i].onGroupTitleChange != NULL)
|
}
|
||||||
windows[i].onGroupTitleChange(&windows[i], m, groupnumber, peernumber, data, length);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,19 +207,19 @@ void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, u
|
|||||||
{
|
{
|
||||||
struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
|
struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
|
||||||
|
|
||||||
if (!ft)
|
if (!ft) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (ft->file_type == TOX_FILE_KIND_AVATAR) {
|
if (ft->file_type == TOX_FILE_KIND_AVATAR) {
|
||||||
on_avatar_chunk_request(m, ft, position, length);
|
on_avatar_chunk_request(m, ft, position, length);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t i;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i] != NULL && windows[i]->onFileChunkRequest != NULL) {
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
windows[i]->onFileChunkRequest(windows[i], m, friendnumber, filenumber, position, length);
|
||||||
if (windows[i].onFileChunkRequest != NULL)
|
}
|
||||||
windows[i].onFileChunkRequest(&windows[i], m, friendnumber, filenumber, position, length);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,35 +228,35 @@ void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint
|
|||||||
{
|
{
|
||||||
struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
|
struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
|
||||||
|
|
||||||
if (!ft)
|
if (!ft) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
size_t i;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i] != NULL && windows[i]->onFileRecvChunk != NULL) {
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
windows[i]->onFileRecvChunk(windows[i], m, friendnumber, filenumber, position, (char *) data, length);
|
||||||
if (windows[i].onFileRecvChunk != NULL)
|
}
|
||||||
windows[i].onFileRecvChunk(&windows[i], m, friendnumber, filenumber, position, (char *) data, length);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_file_control(Tox *m, uint32_t friendnumber, uint32_t filenumber, TOX_FILE_CONTROL control,
|
void on_file_recv_control(Tox *m, uint32_t friendnumber, uint32_t filenumber, Tox_File_Control control,
|
||||||
void *userdata)
|
void *userdata)
|
||||||
{
|
{
|
||||||
struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
|
struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
|
||||||
|
|
||||||
if (!ft)
|
if (!ft) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (ft->file_type == TOX_FILE_KIND_AVATAR) {
|
if (ft->file_type == TOX_FILE_KIND_AVATAR) {
|
||||||
on_avatar_file_control(m, ft, control);
|
on_avatar_file_control(m, ft, control);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t i;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i] != NULL && windows[i]->onFileControl != NULL) {
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
windows[i]->onFileControl(windows[i], m, friendnumber, filenumber, control);
|
||||||
if (windows[i].onFileControl != NULL)
|
}
|
||||||
windows[i].onFileControl(&windows[i], m, friendnumber, filenumber, control);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,50 +269,51 @@ void on_file_recv(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint32_t k
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t i;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i] != NULL && windows[i]->onFileRecv != NULL) {
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
windows[i]->onFileRecv(windows[i], m, friendnumber, filenumber, file_size, (char *) filename,
|
||||||
if (windows[i].onFileRecv != NULL)
|
|
||||||
windows[i].onFileRecv(&windows[i], m, friendnumber, filenumber, file_size, (char *) filename,
|
|
||||||
filename_length);
|
filename_length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void on_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata)
|
void on_friend_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata)
|
||||||
{
|
{
|
||||||
size_t i;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i] != NULL && windows[i]->onReadReceipt != NULL) {
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
windows[i]->onReadReceipt(windows[i], m, friendnumber, receipt);
|
||||||
if (windows[i].onReadReceipt != NULL)
|
}
|
||||||
windows[i].onReadReceipt(&windows[i], m, friendnumber, receipt);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* CALLBACKS END */
|
/* CALLBACKS END */
|
||||||
|
|
||||||
int add_window(Tox *m, ToxWindow w)
|
int add_window(Tox *m, ToxWindow *w)
|
||||||
{
|
{
|
||||||
if (LINES < 2)
|
if (LINES < 2) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
size_t i;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; i++) {
|
||||||
|
if (windows[i] != NULL) {
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; i++) {
|
|
||||||
if (windows[i].active)
|
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
w.window = newwin(LINES - 2, COLS, 0, 0);
|
w->index = i;
|
||||||
|
w->window = newwin(LINES - 2, COLS, 0, 0);
|
||||||
|
|
||||||
if (w.window == NULL)
|
if (w->window == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef URXVT_FIX
|
#ifdef URXVT_FIX
|
||||||
/* Fixes text color problem on some terminals. */
|
/* Fixes text color problem on some terminals. */
|
||||||
wbkgd(w.window, COLOR_PAIR(6));
|
wbkgd(w->window, COLOR_PAIR(6));
|
||||||
#endif
|
#endif
|
||||||
windows[i] = w;
|
windows[i] = w;
|
||||||
|
|
||||||
if (w.onInit)
|
if (w->onInit) {
|
||||||
w.onInit(&w, m);
|
w->onInit(w, m);
|
||||||
|
}
|
||||||
|
|
||||||
++num_active_windows;
|
++num_active_windows;
|
||||||
|
|
||||||
@ -321,42 +323,46 @@ int add_window(Tox *m, ToxWindow w)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_active_window(int index)
|
void set_active_window_index(uint8_t index)
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= MAX_WINDOWS_NUM)
|
if (index < MAX_WINDOWS_NUM) {
|
||||||
return;
|
active_window_index = index;
|
||||||
|
}
|
||||||
active_window = windows + index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Shows next window when tab or back-tab is pressed */
|
/* Shows next window when tab or back-tab is pressed */
|
||||||
void set_next_window(int ch)
|
void set_next_window(int ch)
|
||||||
{
|
{
|
||||||
ToxWindow *end = windows + MAX_WINDOWS_NUM - 1;
|
|
||||||
ToxWindow *inf = active_window;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (ch == user_settings->key_next_tab) {
|
if (ch == user_settings->key_next_tab) {
|
||||||
if (++active_window > end)
|
for (uint8_t i = active_window_index + 1; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
active_window = windows;
|
if (windows[i] != NULL) {
|
||||||
} else if (--active_window < windows)
|
set_active_window_index(i);
|
||||||
active_window = end;
|
|
||||||
|
|
||||||
if (active_window->window)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (active_window == inf) /* infinite loop check */
|
|
||||||
exit_toxic_err("failed in set_next_window", FATALERR_INFLOOP);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
uint8_t start = active_window_index == 0 ? MAX_WINDOWS_NUM - 1 : active_window_index - 1;
|
||||||
|
|
||||||
|
for (uint8_t i = start; i > 0; --i) {
|
||||||
|
if (windows[i] != NULL) {
|
||||||
|
set_active_window_index(i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set_active_window_index(0);
|
||||||
|
}
|
||||||
|
|
||||||
/* Deletes window w and cleans up */
|
/* Deletes window w and cleans up */
|
||||||
void del_window(ToxWindow *w)
|
void del_window(ToxWindow *w)
|
||||||
{
|
{
|
||||||
set_active_window(0); /* Go to prompt screen */
|
set_active_window_index(0);
|
||||||
|
|
||||||
|
uint8_t idx = w->index;
|
||||||
delwin(w->window);
|
delwin(w->window);
|
||||||
memset(w, 0, sizeof(ToxWindow));
|
free(windows[idx]);
|
||||||
|
windows[idx] = NULL;
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
refresh();
|
refresh();
|
||||||
@ -365,13 +371,18 @@ void del_window(ToxWindow *w)
|
|||||||
|
|
||||||
ToxWindow *init_windows(Tox *m)
|
ToxWindow *init_windows(Tox *m)
|
||||||
{
|
{
|
||||||
int n_prompt = add_window(m, new_prompt());
|
prompt = new_prompt();
|
||||||
|
int n_prompt = add_window(m, prompt);
|
||||||
|
|
||||||
if (n_prompt == -1 || add_window(m, new_friendlist()) == -1)
|
if (n_prompt < 0) {
|
||||||
exit_toxic_err("failed in init_windows", FATALERR_WININIT);
|
exit_toxic_err("add_window() for prompt failed in init_windows", FATALERR_WININIT);
|
||||||
|
}
|
||||||
|
|
||||||
prompt = &windows[n_prompt];
|
if (add_window(m, new_friendlist()) == -1) {
|
||||||
active_window = prompt;
|
exit_toxic_err("add_window() for friendlist failed in init_windows", FATALERR_WININIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_active_window_index(n_prompt);
|
||||||
|
|
||||||
return prompt;
|
return prompt;
|
||||||
}
|
}
|
||||||
@ -387,25 +398,26 @@ void on_window_resize(void)
|
|||||||
getmaxyx(stdscr, y2, x2);
|
getmaxyx(stdscr, y2, x2);
|
||||||
y2 -= 2;
|
y2 -= 2;
|
||||||
|
|
||||||
if (y2 <= 0 || x2 <= 0)
|
if (y2 <= 0 || x2 <= 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
size_t i;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i] == NULL) {
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
|
||||||
if (!windows[i].active)
|
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
ToxWindow *w = &windows[i];
|
ToxWindow *w = windows[i];
|
||||||
|
|
||||||
if (windows[i].is_friendlist) {
|
if (windows[i]->is_friendlist) {
|
||||||
delwin(w->window);
|
delwin(w->window);
|
||||||
w->window = newwin(y2, x2, 0, 0);
|
w->window = newwin(y2, x2, 0, 0);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (w->help->active)
|
if (w->help->active) {
|
||||||
wclear(w->help->win);
|
wclear(w->help->win);
|
||||||
|
}
|
||||||
|
|
||||||
if (w->is_groupchat) {
|
if (w->is_groupchat) {
|
||||||
delwin(w->chatwin->sidebar);
|
delwin(w->chatwin->sidebar);
|
||||||
@ -427,9 +439,10 @@ void on_window_resize(void)
|
|||||||
} else {
|
} else {
|
||||||
w->chatwin->history = subwin(w->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
|
w->chatwin->history = subwin(w->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
|
||||||
|
|
||||||
if (!w->is_groupchat)
|
if (!w->is_groupchat) {
|
||||||
w->stb->topline = subwin(w->window, 2, x2, 0, 0);
|
w->stb->topline = subwin(w->window, 2, x2, 0, 0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
|
|
||||||
@ -448,7 +461,9 @@ static void draw_window_tab(ToxWindow *toxwin)
|
|||||||
{
|
{
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
|
|
||||||
if (toxwin->alert != WINDOW_ALERT_NONE) attron(COLOR_PAIR(toxwin->alert));
|
if (toxwin->alert != WINDOW_ALERT_NONE) {
|
||||||
|
attron(COLOR_PAIR(toxwin->alert));
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
@ -457,7 +472,9 @@ static void draw_window_tab(ToxWindow *toxwin)
|
|||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
|
|
||||||
if (toxwin->alert != WINDOW_ALERT_NONE) attroff(COLOR_PAIR(toxwin->alert));
|
if (toxwin->alert != WINDOW_ALERT_NONE) {
|
||||||
|
attroff(COLOR_PAIR(toxwin->alert));
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
}
|
}
|
||||||
@ -466,8 +483,14 @@ static void draw_bar(void)
|
|||||||
{
|
{
|
||||||
int y, x;
|
int y, x;
|
||||||
|
|
||||||
|
ToxWindow *w = windows[active_window_index];
|
||||||
|
|
||||||
|
if (w == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// save current cursor position
|
// save current cursor position
|
||||||
getyx(active_window->window, y, x);
|
getyx(w->window, y, x);
|
||||||
|
|
||||||
attron(COLOR_PAIR(BLUE));
|
attron(COLOR_PAIR(BLUE));
|
||||||
mvhline(LINES - 2, 0, '_', COLS);
|
mvhline(LINES - 2, 0, '_', COLS);
|
||||||
@ -475,32 +498,33 @@ static void draw_bar(void)
|
|||||||
|
|
||||||
move(LINES - 1, 0);
|
move(LINES - 1, 0);
|
||||||
|
|
||||||
size_t i;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i] == NULL) {
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
|
||||||
if (!windows[i].active)
|
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (windows + i == active_window)
|
if (i == active_window_index) {
|
||||||
|
|
||||||
#ifdef URXVT_FIX
|
#ifdef URXVT_FIX
|
||||||
attron(A_BOLD | COLOR_PAIR(GREEN));
|
attron(A_BOLD | COLOR_PAIR(GREEN));
|
||||||
else
|
} else {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
attron(A_BOLD);
|
attron(A_BOLD);
|
||||||
|
}
|
||||||
|
|
||||||
draw_window_tab(&windows[i]);
|
draw_window_tab(windows[i]);
|
||||||
|
|
||||||
if (windows + i == active_window)
|
if (i == active_window_index) {
|
||||||
|
|
||||||
#ifdef URXVT_FIX
|
#ifdef URXVT_FIX
|
||||||
attroff(A_BOLD | COLOR_PAIR(GREEN));
|
attroff(A_BOLD | COLOR_PAIR(GREEN));
|
||||||
else
|
} else {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
attroff(A_BOLD);
|
attroff(A_BOLD);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// restore cursor position after drawing
|
// restore cursor position after drawing
|
||||||
move(y, x);
|
move(y, x);
|
||||||
@ -510,7 +534,11 @@ static void draw_bar(void)
|
|||||||
|
|
||||||
void draw_active_window(Tox *m)
|
void draw_active_window(Tox *m)
|
||||||
{
|
{
|
||||||
ToxWindow *a = active_window;
|
ToxWindow *a = windows[active_window_index];
|
||||||
|
|
||||||
|
if (a == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
a->alert = WINDOW_ALERT_NONE;
|
a->alert = WINDOW_ALERT_NONE;
|
||||||
@ -529,19 +557,22 @@ void draw_active_window(Tox *m)
|
|||||||
#ifdef HAVE_WIDECHAR
|
#ifdef HAVE_WIDECHAR
|
||||||
int status = wget_wch(stdscr, &ch);
|
int status = wget_wch(stdscr, &ch);
|
||||||
|
|
||||||
if (status == ERR)
|
if (status == ERR) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (status == OK)
|
if (status == OK) {
|
||||||
ltr = iswprint(ch);
|
ltr = iswprint(ch);
|
||||||
else /* if (status == KEY_CODE_YES) */
|
} else { /* if (status == KEY_CODE_YES) */
|
||||||
ltr = false;
|
ltr = false;
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
ch = getch();
|
ch = getch();
|
||||||
|
|
||||||
if (ch == ERR)
|
if (ch == ERR) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* TODO verify if this works */
|
/* TODO verify if this works */
|
||||||
ltr = isprint(ch);
|
ltr = isprint(ch);
|
||||||
@ -560,34 +591,37 @@ void draw_active_window(Tox *m)
|
|||||||
call at least once per second */
|
call at least once per second */
|
||||||
void refresh_inactive_windows(void)
|
void refresh_inactive_windows(void)
|
||||||
{
|
{
|
||||||
size_t i;
|
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
ToxWindow *toxwin = windows[i];
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
if (toxwin == NULL) {
|
||||||
ToxWindow *a = &windows[i];
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (a->active && a != active_window && !a->is_friendlist) {
|
if (i != active_window_index && !toxwin->is_friendlist) {
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
line_info_print(a);
|
line_info_print(toxwin);
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns a pointer to the ToxWindow in the ith index. Returns NULL if no ToxWindow exists */
|
/* Returns a pointer to the ToxWindow in the ith index.
|
||||||
ToxWindow *get_window_ptr(int i)
|
* Returns NULL if no ToxWindow exists.
|
||||||
|
*/
|
||||||
|
ToxWindow *get_window_ptr(size_t index)
|
||||||
{
|
{
|
||||||
ToxWindow *toxwin = NULL;
|
if (index >= MAX_WINDOWS_NUM) {
|
||||||
|
return NULL;
|
||||||
if (i >= 0 && i < MAX_WINDOWS_NUM && windows[i].active)
|
|
||||||
toxwin = &windows[i];
|
|
||||||
|
|
||||||
return toxwin;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns a pointer to the currently open ToxWindow. */
|
return windows[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns a pointer to the currently active ToxWindow. */
|
||||||
ToxWindow *get_active_window(void)
|
ToxWindow *get_active_window(void)
|
||||||
{
|
{
|
||||||
return active_window;
|
return windows[active_window_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
void force_refresh(WINDOW *w)
|
void force_refresh(WINDOW *w)
|
||||||
@ -605,15 +639,19 @@ int get_num_active_windows(void)
|
|||||||
/* destroys all chat and groupchat windows (should only be called on shutdown) */
|
/* destroys all chat and groupchat windows (should only be called on shutdown) */
|
||||||
void kill_all_windows(Tox *m)
|
void kill_all_windows(Tox *m)
|
||||||
{
|
{
|
||||||
size_t i;
|
for (uint8_t i = 2; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i] == NULL) {
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
continue;
|
||||||
if (windows[i].is_chat)
|
|
||||||
kill_chat_window(&windows[i], m);
|
|
||||||
else if (windows[i].is_groupchat)
|
|
||||||
close_groupchat(&windows[i], m, windows[i].num);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kill_prompt_window(prompt);
|
if (windows[i]->is_chat) {
|
||||||
kill_friendlist();
|
kill_chat_window(windows[i], m);
|
||||||
|
} else if (windows[i]->is_groupchat) {
|
||||||
|
free_groupchat(windows[i], m, windows[i]->num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: use enum instead of magic indices */
|
||||||
|
kill_friendlist(windows[1]);
|
||||||
|
kill_prompt_window(windows[0]);
|
||||||
}
|
}
|
||||||
|
@ -36,13 +36,13 @@
|
|||||||
|
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
|
|
||||||
#define MAX_WINDOWS_NUM 32
|
#define MAX_WINDOWS_NUM 16
|
||||||
#define MAX_WINDOW_NAME_LENGTH 22
|
#define MAX_WINDOW_NAME_LENGTH 22
|
||||||
#define CURS_Y_OFFSET 1 /* y-axis cursor offset for chat contexts */
|
#define CURS_Y_OFFSET 1 /* y-axis cursor offset for chat contexts */
|
||||||
#define CHATBOX_HEIGHT 2
|
#define CHATBOX_HEIGHT 2
|
||||||
|
|
||||||
/* Curses foreground colours (background is black) */
|
/* Curses foreground colours (background is black) */
|
||||||
enum {
|
typedef enum {
|
||||||
WHITE,
|
WHITE,
|
||||||
GREEN,
|
GREEN,
|
||||||
CYAN,
|
CYAN,
|
||||||
@ -116,18 +116,19 @@ struct ToxWindow {
|
|||||||
/* toxcore */
|
/* toxcore */
|
||||||
void(*onFriendRequest)(ToxWindow *, Tox *, const char *, const char *, size_t);
|
void(*onFriendRequest)(ToxWindow *, Tox *, const char *, const char *, size_t);
|
||||||
void(*onFriendAdded)(ToxWindow *, Tox *, uint32_t, bool);
|
void(*onFriendAdded)(ToxWindow *, Tox *, uint32_t, bool);
|
||||||
void(*onConnectionChange)(ToxWindow *, Tox *, uint32_t, TOX_CONNECTION);
|
void(*onConnectionChange)(ToxWindow *, Tox *, uint32_t, Tox_Connection);
|
||||||
void(*onMessage)(ToxWindow *, Tox *, uint32_t, TOX_MESSAGE_TYPE, const char *, size_t);
|
void(*onMessage)(ToxWindow *, Tox *, uint32_t, Tox_Message_Type, const char *, size_t);
|
||||||
void(*onNickChange)(ToxWindow *, Tox *, uint32_t, const char *, size_t);
|
void(*onNickChange)(ToxWindow *, Tox *, uint32_t, const char *, size_t);
|
||||||
void(*onStatusChange)(ToxWindow *, Tox *, uint32_t, TOX_USER_STATUS);
|
void(*onStatusChange)(ToxWindow *, Tox *, uint32_t, Tox_User_Status);
|
||||||
void(*onStatusMessageChange)(ToxWindow *, uint32_t, const char *, size_t);
|
void(*onStatusMessageChange)(ToxWindow *, uint32_t, const char *, size_t);
|
||||||
void(*onGroupMessage)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_MESSAGE_TYPE, const char *, size_t);
|
void(*onGroupMessage)(ToxWindow *, Tox *, uint32_t, uint32_t, Tox_Message_Type, const char *, size_t);
|
||||||
void(*onGroupInvite)(ToxWindow *, Tox *, int32_t, uint8_t, const char *, uint16_t);
|
void(*onGroupInvite)(ToxWindow *, Tox *, int32_t, uint8_t, const char *, uint16_t);
|
||||||
void(*onGroupNamelistChange)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_CONFERENCE_STATE_CHANGE);
|
void(*onGroupNameListChange)(ToxWindow *, Tox *, uint32_t);
|
||||||
|
void(*onGroupPeerNameChange)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t);
|
||||||
void(*onGroupTitleChange)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t);
|
void(*onGroupTitleChange)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t);
|
||||||
void(*onFileChunkRequest)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, size_t);
|
void(*onFileChunkRequest)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, size_t);
|
||||||
void(*onFileRecvChunk)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, const char *, size_t);
|
void(*onFileRecvChunk)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, const char *, size_t);
|
||||||
void(*onFileControl)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_FILE_CONTROL);
|
void(*onFileControl)(ToxWindow *, Tox *, uint32_t, uint32_t, Tox_File_Control);
|
||||||
void(*onFileRecv)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, const char *, size_t);
|
void(*onFileRecv)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, const char *, size_t);
|
||||||
void(*onTypingChange)(ToxWindow *, Tox *, uint32_t, bool);
|
void(*onTypingChange)(ToxWindow *, Tox *, uint32_t, bool);
|
||||||
void(*onReadReceipt)(ToxWindow *, Tox *, uint32_t, uint32_t);
|
void(*onReadReceipt)(ToxWindow *, Tox *, uint32_t, uint32_t);
|
||||||
@ -161,7 +162,7 @@ struct ToxWindow {
|
|||||||
|
|
||||||
char name[TOXIC_MAX_NAME_LENGTH + 1];
|
char name[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
uint32_t num; /* corresponds to friendnumber in chat windows */
|
uint32_t num; /* corresponds to friendnumber in chat windows */
|
||||||
bool active;
|
uint8_t index; /* This window's index in the windows array */
|
||||||
int x;
|
int x;
|
||||||
|
|
||||||
bool is_chat;
|
bool is_chat;
|
||||||
@ -186,8 +187,8 @@ struct StatusBar {
|
|||||||
size_t statusmsg_len;
|
size_t statusmsg_len;
|
||||||
char nick[TOXIC_MAX_NAME_LENGTH + 1];
|
char nick[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
size_t nick_len;
|
size_t nick_len;
|
||||||
TOX_USER_STATUS status;
|
Tox_User_Status status;
|
||||||
TOX_CONNECTION connection;
|
Tox_Connection connection;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
@ -251,18 +252,18 @@ struct Help {
|
|||||||
|
|
||||||
ToxWindow *init_windows(Tox *m);
|
ToxWindow *init_windows(Tox *m);
|
||||||
void draw_active_window(Tox *m);
|
void draw_active_window(Tox *m);
|
||||||
int add_window(Tox *m, ToxWindow w);
|
int add_window(Tox *m, ToxWindow *w);
|
||||||
void del_window(ToxWindow *w);
|
void del_window(ToxWindow *w);
|
||||||
void set_active_window(int ch);
|
void set_active_window_index(uint8_t index);
|
||||||
int get_num_active_windows(void);
|
int get_num_active_windows(void);
|
||||||
void kill_all_windows(Tox *m); /* should only be called on shutdown */
|
void kill_all_windows(Tox *m); /* should only be called on shutdown */
|
||||||
void on_window_resize(void);
|
void on_window_resize(void);
|
||||||
void force_refresh(WINDOW *w);
|
void force_refresh(WINDOW *w);
|
||||||
ToxWindow *get_window_ptr(int i);
|
ToxWindow *get_window_ptr(size_t i);
|
||||||
ToxWindow *get_active_window(void);
|
ToxWindow *get_active_window(void);
|
||||||
|
|
||||||
/* refresh inactive windows to prevent scrolling bugs.
|
/* refresh inactive windows to prevent scrolling bugs.
|
||||||
call at least once per second */
|
call at least once per second */
|
||||||
void refresh_inactive_windows(void);
|
void refresh_inactive_windows(void);
|
||||||
|
|
||||||
#endif /* #define WINDOWS_H */
|
#endif /* WINDOWS_H */
|
||||||
|
127
src/xtra.c
127
src/xtra.c
@ -47,7 +47,7 @@ static Atom XdndTypeList;
|
|||||||
static Atom XdndActionCopy;
|
static Atom XdndActionCopy;
|
||||||
static Atom XdndFinished;
|
static Atom XdndFinished;
|
||||||
|
|
||||||
struct _Xtra {
|
struct Xtra {
|
||||||
drop_callback on_drop;
|
drop_callback on_drop;
|
||||||
Display *display;
|
Display *display;
|
||||||
Window terminal_window;
|
Window terminal_window;
|
||||||
@ -57,14 +57,14 @@ struct _Xtra {
|
|||||||
Atom expecting_type;
|
Atom expecting_type;
|
||||||
} Xtra;
|
} Xtra;
|
||||||
|
|
||||||
typedef struct _Property {
|
typedef struct Property {
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
int read_format;
|
int read_format;
|
||||||
unsigned long read_num;
|
unsigned long read_num;
|
||||||
Atom read_type;
|
Atom read_type;
|
||||||
} Property;
|
} Property;
|
||||||
|
|
||||||
Property read_property(Window s, Atom p)
|
static Property read_property(Window s, Atom p)
|
||||||
{
|
{
|
||||||
Atom read_type;
|
Atom read_type;
|
||||||
int read_format;
|
int read_format;
|
||||||
@ -76,7 +76,9 @@ Property read_property(Window s, Atom p)
|
|||||||
|
|
||||||
/* Keep trying to read the property until there are no bytes unread */
|
/* Keep trying to read the property until there are no bytes unread */
|
||||||
do {
|
do {
|
||||||
if (data) XFree(data);
|
if (data) {
|
||||||
|
XFree(data);
|
||||||
|
}
|
||||||
|
|
||||||
XGetWindowProperty(Xtra.display, s,
|
XGetWindowProperty(Xtra.display, s,
|
||||||
p, 0,
|
p, 0,
|
||||||
@ -93,12 +95,14 @@ Property read_property(Window s, Atom p)
|
|||||||
return property;
|
return property;
|
||||||
}
|
}
|
||||||
|
|
||||||
Atom get_dnd_type(long *a, int l)
|
static Atom get_dnd_type(long *a, int l)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
for (; i < l; i ++) {
|
for (; i < l; i ++) {
|
||||||
if (a[i] != XtraNil) return a[i]; /* Get first valid */
|
if (a[i] != XtraNil) {
|
||||||
|
return a[i]; /* Get first valid */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return XtraNil;
|
return XtraNil;
|
||||||
@ -193,10 +197,11 @@ static void handle_xdnd_selection(XSelectionEvent *e)
|
|||||||
Property p = read_property(Xtra.proxy_window, XdndSelection);
|
Property p = read_property(Xtra.proxy_window, XdndSelection);
|
||||||
DropType dt;
|
DropType dt;
|
||||||
|
|
||||||
if (strcmp(XGetAtomName(Xtra.display, p.read_type), "text/uri-list") == 0)
|
if (strcmp(XGetAtomName(Xtra.display, p.read_type), "text/uri-list") == 0) {
|
||||||
dt = DT_file_list;
|
dt = DT_file_list;
|
||||||
else /* text/uri-list */
|
} else { /* text/uri-list */
|
||||||
dt = DT_plain;
|
dt = DT_plain;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Call callback for every entry */
|
/* Call callback for every entry */
|
||||||
@ -204,13 +209,18 @@ static void handle_xdnd_selection(XSelectionEvent *e)
|
|||||||
char *sptr;
|
char *sptr;
|
||||||
char *str = strtok_r((char *) p.data, "\n\r", &sptr);
|
char *str = strtok_r((char *) p.data, "\n\r", &sptr);
|
||||||
|
|
||||||
if (str) Xtra.on_drop(str, dt);
|
if (str) {
|
||||||
|
|
||||||
while ((str = strtok_r(NULL, "\n\r", &sptr)))
|
|
||||||
Xtra.on_drop(str, dt);
|
Xtra.on_drop(str, dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p.data) XFree(p.data);
|
while ((str = strtok_r(NULL, "\n\r", &sptr))) {
|
||||||
|
Xtra.on_drop(str, dt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p.data) {
|
||||||
|
XFree(p.data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void *event_loop(void *p)
|
void *event_loop(void *p)
|
||||||
@ -227,7 +237,9 @@ void *event_loop(void *p)
|
|||||||
|
|
||||||
XLockDisplay(Xtra.display);
|
XLockDisplay(Xtra.display);
|
||||||
|
|
||||||
if ((pending = XPending(Xtra.display))) XNextEvent(Xtra.display, &event);
|
if ((pending = XPending(Xtra.display))) {
|
||||||
|
XNextEvent(Xtra.display, &event);
|
||||||
|
}
|
||||||
|
|
||||||
if (!pending) {
|
if (!pending) {
|
||||||
XUnlockDisplay(Xtra.display);
|
XUnlockDisplay(Xtra.display);
|
||||||
@ -238,13 +250,22 @@ void *event_loop(void *p)
|
|||||||
if (event.type == ClientMessage) {
|
if (event.type == ClientMessage) {
|
||||||
Atom type = event.xclient.message_type;
|
Atom type = event.xclient.message_type;
|
||||||
|
|
||||||
if (type == XdndEnter) handle_xdnd_enter(&event.xclient);
|
if (type == XdndEnter) {
|
||||||
else if (type == XdndPosition) handle_xdnd_position(&event.xclient);
|
handle_xdnd_enter(&event.xclient);
|
||||||
else if (type == XdndDrop) handle_xdnd_drop(&event.xclient);
|
} else if (type == XdndPosition) {
|
||||||
else if (type == XtraTerminate) break;
|
handle_xdnd_position(&event.xclient);
|
||||||
} else if (event.type == SelectionNotify) handle_xdnd_selection(&event.xselection);
|
} else if (type == XdndDrop) {
|
||||||
|
handle_xdnd_drop(&event.xclient);
|
||||||
|
} else if (type == XtraTerminate) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (event.type == SelectionNotify) {
|
||||||
|
handle_xdnd_selection(&event.xselection);
|
||||||
|
}
|
||||||
/* AINNOBODYCANHANDLEDEMEVENTS*/
|
/* AINNOBODYCANHANDLEDEMEVENTS*/
|
||||||
else XSendEvent(Xtra.display, Xtra.terminal_window, 0, 0, &event);
|
else {
|
||||||
|
XSendEvent(Xtra.display, Xtra.terminal_window, 0, 0, &event);
|
||||||
|
}
|
||||||
|
|
||||||
XUnlockDisplay(Xtra.display);
|
XUnlockDisplay(Xtra.display);
|
||||||
}
|
}
|
||||||
@ -253,28 +274,53 @@ void *event_loop(void *p)
|
|||||||
* Please call xtra_terminate() at exit
|
* Please call xtra_terminate() at exit
|
||||||
* otherwise HEWUSAGUDBOI happens
|
* otherwise HEWUSAGUDBOI happens
|
||||||
*/
|
*/
|
||||||
if (Xtra.display) XCloseDisplay(Xtra.display);
|
if (Xtra.display) {
|
||||||
|
XCloseDisplay(Xtra.display);
|
||||||
|
}
|
||||||
|
|
||||||
return (Xtra.display = NULL);
|
return (Xtra.display = NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static long unsigned int focused_window_id(void)
|
||||||
|
{
|
||||||
|
if (!Xtra.display) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Window focus;
|
||||||
|
int revert;
|
||||||
|
XLockDisplay(Xtra.display);
|
||||||
|
XGetInputFocus(Xtra.display, &focus, &revert);
|
||||||
|
XUnlockDisplay(Xtra.display);
|
||||||
|
return focus;
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_focused(void)
|
||||||
|
{
|
||||||
|
return Xtra.proxy_window == focused_window_id() || Xtra.terminal_window == focused_window_id();
|
||||||
|
}
|
||||||
|
|
||||||
int init_xtra(drop_callback d)
|
int init_xtra(drop_callback d)
|
||||||
{
|
{
|
||||||
memset(&Xtra, 0, sizeof(Xtra));
|
if (!d) {
|
||||||
|
return -1;
|
||||||
if (!d) return -1;
|
} else {
|
||||||
else Xtra.on_drop = d;
|
Xtra.on_drop = d;
|
||||||
|
}
|
||||||
|
|
||||||
XInitThreads();
|
XInitThreads();
|
||||||
|
|
||||||
if ( !(Xtra.display = XOpenDisplay(NULL))) return -1;
|
if (!(Xtra.display = XOpenDisplay(NULL))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
Xtra.terminal_window = focused_window_id();
|
Xtra.terminal_window = focused_window_id();
|
||||||
|
|
||||||
/* OSX: if focused window is 0, it means toxic is ran from
|
/* OSX: if focused window is 0, it means toxic is ran from
|
||||||
* native terminal and not X11 terminal window, silently exit */
|
* native terminal and not X11 terminal window, silently exit */
|
||||||
if (!Xtra.terminal_window)
|
if (!Xtra.terminal_window) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
/* Create an invisible window which will act as proxy for the DnD operation. */
|
/* Create an invisible window which will act as proxy for the DnD operation. */
|
||||||
@ -308,9 +354,10 @@ int init_xtra(drop_callback d)
|
|||||||
InputOnly, /* Class */
|
InputOnly, /* Class */
|
||||||
CopyFromParent, /* Visual */
|
CopyFromParent, /* Visual */
|
||||||
CWEventMask | CWCursor, /* Value mask */
|
CWEventMask | CWCursor, /* Value mask */
|
||||||
&attr)) ) /* Attributes for value mask */
|
&attr))) { /* Attributes for value mask */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
XMapWindow(Xtra.display, Xtra.proxy_window); /* Show window (sandwich) */
|
XMapWindow(Xtra.display, Xtra.proxy_window); /* Show window (sandwich) */
|
||||||
XLowerWindow(Xtra.display, Xtra.proxy_window); /* Don't interfere with parent lmao */
|
XLowerWindow(Xtra.display, Xtra.proxy_window); /* Don't interfere with parent lmao */
|
||||||
@ -339,17 +386,20 @@ int init_xtra(drop_callback d)
|
|||||||
|
|
||||||
pthread_t id;
|
pthread_t id;
|
||||||
|
|
||||||
if (pthread_create(&id, NULL, event_loop, NULL) != 0)
|
if (pthread_create(&id, NULL, event_loop, NULL) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
pthread_detach(id);
|
pthread_detach(id);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void terminate_xtra()
|
void terminate_xtra(void)
|
||||||
{
|
{
|
||||||
if (!Xtra.display || !Xtra.terminal_window) return;
|
if (!Xtra.display || !Xtra.terminal_window) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
XEvent terminate = {
|
XEvent terminate = {
|
||||||
.xclient = {
|
.xclient = {
|
||||||
@ -366,20 +416,3 @@ void terminate_xtra()
|
|||||||
|
|
||||||
while (Xtra.display); /* Wait for termination */
|
while (Xtra.display); /* Wait for termination */
|
||||||
}
|
}
|
||||||
|
|
||||||
long unsigned int focused_window_id()
|
|
||||||
{
|
|
||||||
if (!Xtra.display) return 0;
|
|
||||||
|
|
||||||
Window focus;
|
|
||||||
int revert;
|
|
||||||
XLockDisplay(Xtra.display);
|
|
||||||
XGetInputFocus(Xtra.display, &focus, &revert);
|
|
||||||
XUnlockDisplay(Xtra.display);
|
|
||||||
return focus;
|
|
||||||
}
|
|
||||||
|
|
||||||
int is_focused()
|
|
||||||
{
|
|
||||||
return Xtra.proxy_window == focused_window_id() || Xtra.terminal_window == focused_window_id();
|
|
||||||
}
|
|
||||||
|
@ -34,8 +34,7 @@ DropType;
|
|||||||
typedef void (*drop_callback)(const char *, DropType);
|
typedef void (*drop_callback)(const char *, DropType);
|
||||||
|
|
||||||
int init_xtra(drop_callback d);
|
int init_xtra(drop_callback d);
|
||||||
void terminate_xtra();
|
void terminate_xtra(void);
|
||||||
long unsigned int focused_window_id();
|
int is_focused(void); /* returns bool */
|
||||||
int is_focused(); /* returns bool */
|
|
||||||
|
|
||||||
#endif /* XTRA_H */
|
#endif /* XTRA_H */
|
Reference in New Issue
Block a user