mirror of
https://github.com/Tha14/toxic.git
synced 2025-06-27 21:06:46 +02:00
Compare commits
236 Commits
Author | SHA1 | Date | |
---|---|---|---|
0d8e6d713e | |||
39e4ff8bd6 | |||
0434ac186a | |||
8d9d51640c | |||
c4c0c0d1f4 | |||
3f2826bd66 | |||
7b7ea0e386 | |||
d35a38735b | |||
f0c4906fdc | |||
56ba61e061 | |||
898d89e95a | |||
1fd1e27bdf | |||
8e84ac58d4 | |||
9d65997871 | |||
da2889f3ab | |||
312b38d253 | |||
0554bf0240 | |||
53a7530e8a | |||
41be04a142 | |||
31f36318a2 | |||
f882fdf608 | |||
7e1e410307 | |||
c135c812c2 | |||
6c239193ab | |||
de7db08352 | |||
ba5ded9bc2 | |||
4581dee4fc | |||
d75d6e8b60 | |||
142ce642f0 | |||
7dead5ec96 | |||
ddcf224db2 | |||
daf794c4a2 | |||
dac0124f0f | |||
15b7a30925 | |||
77ab71f26f | |||
68e1ba312d | |||
752fc6d619 | |||
16bcb27ca7 | |||
71d7d355a6 | |||
4188b392cc | |||
811fbfbb1e | |||
32eb7d3040 | |||
42763905d7 | |||
f64300d1d6 | |||
1a723f0e8e | |||
a86884c40e | |||
3f02e119f4 | |||
1bbd50aac7 | |||
e7a0c32a68 | |||
7560bc9547 | |||
2b43340c90 | |||
ff1620c923 | |||
1303053a27 | |||
91f194c821 | |||
478762f76c | |||
4d96d6a753 | |||
3cdcfbf4e5 | |||
4c302da503 | |||
26b5fe8f9d | |||
22d60232fb | |||
e428879beb | |||
3015138a5a | |||
9c06ad608b | |||
015dbd9a96 | |||
a7466c3142 | |||
f012007cc4 | |||
dcf3baf60f | |||
4bda799a4b | |||
bdeae33d48 | |||
47591d5298 | |||
b5ace27a3e | |||
b334622d36 | |||
4bfb344caa | |||
16d96d6faf | |||
0ab2bad226 | |||
68db926f9f | |||
b270c1e8b7 | |||
e7142e49fd | |||
610906d07f | |||
6f72a191ba | |||
dd5fa236ae | |||
51e1ab94b3 | |||
ddc8c53abf | |||
46513017e3 | |||
98cb7f58c0 | |||
206bf407fd | |||
0a8ac4de3b | |||
87d54acad0 | |||
45ff6d8bac | |||
437dd8baeb | |||
b080236ee5 | |||
116bff8cef | |||
ddeca171a0 | |||
127f9462e0 | |||
4b5a9abbd4 | |||
bb2257973e | |||
12b9cd2386 | |||
2cbe8fa880 | |||
2e39bee05a | |||
05eda76643 | |||
f7b73af9a7 | |||
73aaa44d12 | |||
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 | |||
b1d8ab102f | |||
0bd5b4ddee | |||
c387df35f8 | |||
351a50c214 | |||
93175314b5 | |||
b905a1a3c5 | |||
c4386b195f | |||
ed1e617380 | |||
1382adb1f6 | |||
ecf1c317b7 | |||
cf0b99f1e5 | |||
3605a296a9 | |||
9375d220f9 | |||
8f94b0a218 | |||
85a0becbf9 | |||
fec36ad9e6 | |||
ecdf6f01d2 | |||
e1bfa30769 | |||
ebcbc7497b | |||
e844ece28b | |||
8508451ba6 | |||
5cc83a7cb5 | |||
febc725763 | |||
f2c116feb3 | |||
52dd60dc86 | |||
80c0500299 | |||
ab490d28b4 | |||
a9f7f85617 | |||
1bfc1ba371 | |||
2ede39369a | |||
922c184195 | |||
56a9571509 | |||
0136f22076 | |||
c4ace288af | |||
6d3fbfee59 | |||
be5e7906da | |||
369f26932e | |||
22ea522baf | |||
4f60d546e6 | |||
76d1eafdc0 | |||
37912f2d88 | |||
09710327c5 | |||
acee4615f8 | |||
5ed26eda9b | |||
6d2b90ac9f | |||
02ea0fac44 | |||
7d3d129624 | |||
b3ed8bc35c | |||
90210daca7 | |||
0e13a1f1bc | |||
09e2690211 | |||
e65e3af274 | |||
c6c60d018e | |||
451d4ced80 | |||
7a7402ff86 | |||
600e013adc | |||
1d71e2eb18 | |||
f858714edd | |||
4df44a7274 | |||
a26ed9d28f | |||
2bd5083b8f | |||
8805f694b9 | |||
71040355fd | |||
6bc5d8c543 | |||
abb39ea6b5 | |||
15846d2b50 | |||
958df9f2e8 | |||
2fd43aebee | |||
34c29745cc | |||
da6fe41d75 | |||
e17fa89d8f | |||
f056f13329 |
1
.github/CODEOWNERS
vendored
Normal file
1
.github/CODEOWNERS
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/.github/ @TokTok/admins
|
2
.github/FUNDING.yml
vendored
Normal file
2
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
github: [JFreegman]
|
17
.github/settings.yml
vendored
Normal file
17
.github/settings.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
_extends: .github
|
||||||
|
|
||||||
|
repository:
|
||||||
|
name: toxic
|
||||||
|
description: An ncurses-based Tox client
|
||||||
|
topics: tox, console, chat
|
||||||
|
|
||||||
|
branches:
|
||||||
|
- name: "master"
|
||||||
|
protection:
|
||||||
|
required_status_checks:
|
||||||
|
contexts:
|
||||||
|
- Codacy/PR Quality Review
|
||||||
|
- CodeFactor
|
||||||
|
- Travis CI - Pull Request
|
||||||
|
- code-review/reviewable
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -16,3 +16,4 @@ stamp-h1
|
|||||||
build/toxic
|
build/toxic
|
||||||
build/*.o
|
build/*.o
|
||||||
build/*.d
|
build/*.d
|
||||||
|
apidoc/python/build
|
||||||
|
4
.restyled.yaml
Normal file
4
.restyled.yaml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
restylers:
|
||||||
|
- astyle:
|
||||||
|
arguments: ["--options=astylerc"]
|
60
.travis.yml
Normal file
60
.travis.yml
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
---
|
||||||
|
language: python
|
||||||
|
python: nightly
|
||||||
|
dist: xenial
|
||||||
|
os: linux
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
include:
|
||||||
|
- env: JOB=linux
|
||||||
|
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- 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))
|
||||||
|
|
||||||
|
script:
|
||||||
|
- make ENABLE_PYTHON=1 -j$(nproc)
|
||||||
|
|
||||||
|
- env: JOB=macos
|
||||||
|
os: macos
|
||||||
|
language: c
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- $HOME/cache
|
||||||
|
|
||||||
|
install:
|
||||||
|
- brew install
|
||||||
|
freealut
|
||||||
|
libconfig
|
||||||
|
libqrencode
|
||||||
|
libsodium
|
||||||
|
openal-soft
|
||||||
|
- export LDFLAGS="-L/usr/local/Cellar/openal-soft/1.21.0/lib"
|
||||||
|
- git clone --depth=1 https://github.com/TokTok/c-toxcore ../c-toxcore
|
||||||
|
- test -f /usr/local/lib/libtoxcore.dylib || (cd ../c-toxcore && cmake -B_build -H. && make -C_build install -j$(nproc))
|
||||||
|
|
||||||
|
script:
|
||||||
|
- make ENABLE_PYTHON=1 DISABLE_DESKTOP_NOTIFY=1 DISABLE_X11=1 DISABLE_AV=1 DISABLE_SOUND_NOTIFY=1 -j$(nproc)
|
41
BUILD.bazel
Normal file
41
BUILD.bazel
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
load("@rules_cc//cc:defs.bzl", "cc_binary")
|
||||||
|
load("//tools/project:build_defs.bzl", "project")
|
||||||
|
|
||||||
|
project()
|
||||||
|
|
||||||
|
cc_binary(
|
||||||
|
name = "toxic",
|
||||||
|
srcs = glob(
|
||||||
|
[
|
||||||
|
"src/*.c",
|
||||||
|
"src/*.h",
|
||||||
|
],
|
||||||
|
exclude = ["src/video*"],
|
||||||
|
) + select({
|
||||||
|
"//tools/config:linux": glob(["src/video*"]),
|
||||||
|
"//tools/config:osx": [],
|
||||||
|
}),
|
||||||
|
copts = [
|
||||||
|
"-std=gnu99",
|
||||||
|
"-DAUDIO",
|
||||||
|
"-DPACKAGE_DATADIR='\"data\"'",
|
||||||
|
"-DPYTHON",
|
||||||
|
"-DQRCODE",
|
||||||
|
] + select({
|
||||||
|
"//tools/config:linux": ["-DVIDEO"],
|
||||||
|
"//tools/config:osx": [],
|
||||||
|
}),
|
||||||
|
deps = [
|
||||||
|
"//c-toxcore",
|
||||||
|
"@curl",
|
||||||
|
"@libconfig",
|
||||||
|
"@libqrencode",
|
||||||
|
"@libvpx",
|
||||||
|
"@ncurses",
|
||||||
|
"@openal",
|
||||||
|
"@python3//:python",
|
||||||
|
] + select({
|
||||||
|
"//tools/config:linux": ["@x11"],
|
||||||
|
"//tools/config:osx": [],
|
||||||
|
}),
|
||||||
|
)
|
70
INSTALL.md
70
INSTALL.md
@ -1,70 +1,70 @@
|
|||||||
# Installation
|
# Installation
|
||||||
* [Dependencies](#deps)
|
* [Dependencies](#dependencies)
|
||||||
* [OS X Notes](#deps_osx)
|
* [OS X Notes](#os-x-notes)
|
||||||
* [Compiling](#compiling)
|
* [Compiling](#compiling)
|
||||||
* [Documentation](#docs)
|
* [Documentation](#documentation)
|
||||||
* [Notes](#notes)
|
* [Notes](#notes)
|
||||||
* [Compilation variables](#comp_vars)
|
* [Compilation variables](#compilation-variables)
|
||||||
* [Packaging](#packaging)
|
* [Environment variables](#environment-variables)
|
||||||
|
|
||||||
<a name="deps" />
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
| Name | Needed by | Debian package |
|
| Name | Needed by | Debian package |
|
||||||
|------------------------------------------------------|----------------------------|---------------------|
|
|------------------------------------------------------|----------------------------|---------------------|
|
||||||
| [Tox Core](https://github.com/irungentoo/toxcore) | BASE | *None* |
|
| [Tox Core](https://github.com/toktok/c-toxcore) | BASE | *None* |
|
||||||
| [NCurses](https://www.gnu.org/software/ncurses) | BASE | libncursesw5-dev |
|
| [NCurses](https://www.gnu.org/software/ncurses) | BASE | libncursesw5-dev |
|
||||||
| [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/irungentoo/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 |
|
||||||
|
| [Python 3](http://www.python.org/) | PYTHON | python3-dev |
|
||||||
| [AsciiDoc](http://asciidoc.org/index.html) | DOCUMENTATION<sup>1</sup> | asciidoc |
|
| [AsciiDoc](http://asciidoc.org/index.html) | DOCUMENTATION<sup>1</sup> | asciidoc |
|
||||||
<sup>1</sup>: see [Documentation](#docs)
|
|
||||||
|
|
||||||
<a name="deps_osx" />
|
<sup>1</sup>: see [Documentation](#documentation)
|
||||||
|
|
||||||
#### 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 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 https://raw.githubusercontent.com/Homebrew/homebrew-x11/master/libnotify.rb
|
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.
|
||||||
|
|
||||||
<a name="Compiling">
|
|
||||||
## Compiling
|
## Compiling
|
||||||
```
|
```
|
||||||
make PREFIX="/where/to/install"
|
make
|
||||||
sudo make install PREFIX="/where/to/install"
|
sudo make install
|
||||||
```
|
```
|
||||||
|
|
||||||
<a name="docs" />
|
|
||||||
#### 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.
|
||||||
|
|
||||||
<a name="notes" />
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
<a name="comp_vars" />
|
|
||||||
#### 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_QRCODE` → Disable QR exporting support
|
||||||
* `DISABLE_DESKTOP_NOTIFY=1` → build toxic without desktop notifications support
|
* `DISABLE_QRPNG` → Disable support for exporting QR as PNG
|
||||||
|
* `DISABLE_DESKTOP_NOTIFY=1` → Disable desktop notifications support
|
||||||
|
* `ENABLE_PYTHON=1` → Build toxic with Python scripting support
|
||||||
|
* `ENABLE_RELEASE=1` → Build toxic without debug symbols and with full compiler optimizations
|
||||||
|
* `ENABLE_ASAN=1` → Build toxic with LLVM Address Sanitizer enabled
|
||||||
|
|
||||||
<a name="packaging" />
|
* `DESTDIR=""` Specifies the base install directory for binaries and data files (e.g.: DESTDIR="/tmp/build/pkg")
|
||||||
#### Packaging
|
|
||||||
* For packaging purpose, you can use `DESTDIR=""` to specify a directory where to store installed files
|
|
||||||
* `DESTDIR=""` can be used in addition to `PREFIX=""`:
|
|
||||||
* `DESTDIR=""` is meant to specify a directory where to store installed files (ex: "/tmp/build/pkg")
|
|
||||||
* `PREFIX=""` is meant to specify a prefix directory for binaries and data files (ex: "/usr/local")
|
|
||||||
|
|
||||||
|
#### Environment variables
|
||||||
|
* You can use the `CFLAGS` and `LDFLAGS` environment variables to add specific flags to the Makefile
|
||||||
|
* 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.
|
||||||
|
47
Makefile
47
Makefile
@ -3,39 +3,52 @@ 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 ?= -std=c99 -pthread -Wall -Wpedantic -Wunused -fstack-protector-all -Wvla -Wno-missing-braces
|
||||||
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 conference_commands.o conference.o help.o input.o
|
||||||
OBJ += line_info.o log.o message_queue.o misc_tools.o name_lookup.o notify.o prompt.o qr_code.o settings.o
|
OBJ += line_info.o log.o message_queue.o misc_tools.o name_lookup.o notify.o prompt.o qr_code.o settings.o
|
||||||
OBJ += term_mplex.o toxic.o toxic_strings.o windows.o
|
OBJ += term_mplex.o toxic.o toxic_strings.o windows.o
|
||||||
|
|
||||||
|
# Check if debug build is enabled
|
||||||
|
RELEASE := $(shell if [ -z "$(RELEASE_ENABLED)" ] || [ "$(RELEASE_ENABLED)" = "0" ] ; then echo disabled ; else echo enabled ; fi)
|
||||||
|
ifneq ($(RELEASE), enabled)
|
||||||
|
CFLAGS += -O0 -g -DDEBUG
|
||||||
|
LDFLAGS += -O0
|
||||||
|
else
|
||||||
|
CFLAGS += -O2 -flto
|
||||||
|
LDFLAGS += -O2 -flto
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Check if LLVM Address Sanitizer is enabled
|
||||||
|
ASAN_ENABLED := $(shell if [ -z "$(ENABLE_ASAN)" ] || [ "$(ENABLE_ASAN)" = "0" ] ; then echo disabled ; else echo enabled ; fi)
|
||||||
|
ifneq ($(ASAN_ENABLED), disabled)
|
||||||
|
CFLAGS += -fsanitize=address -fno-omit-frame-pointer -mllvm -asan-use-private-alias=1 -Wno-unused-command-line-argument
|
||||||
|
endif
|
||||||
|
|
||||||
# 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
|
||||||
|
ifeq ($(UNAME_S), NetBSD)
|
||||||
|
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)
|
||||||
@ -72,7 +85,7 @@ $(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
|
|||||||
fi
|
fi
|
||||||
@echo " CC $(@:$(BUILD_DIR)/%=%)"
|
@echo " CC $(@:$(BUILD_DIR)/%=%)"
|
||||||
@$(CC) $(CFLAGS) -o $(BUILD_DIR)/$*.o -c $(SRC_DIR)/$*.c
|
@$(CC) $(CFLAGS) -o $(BUILD_DIR)/$*.o -c $(SRC_DIR)/$*.c
|
||||||
@$(CC) -MM $(CFLAGS) $(SRC_DIR)/$*.c > $(BUILD_DIR)/$*.d
|
@$(CC) -MM $(CFLAGS) $(SRC_DIR)/$*.c >$(BUILD_DIR)/$*.d
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(BUILD_DIR)/*.d $(BUILD_DIR)/*.o $(BUILD_DIR)/toxic
|
rm -f $(BUILD_DIR)/*.d $(BUILD_DIR)/*.o $(BUILD_DIR)/toxic
|
||||||
|
@ -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/irungentoo/toxcore), and is now available as a standalone application.
|
Toxic is a [Tox](https://tox.chat)-based instant messaging and video chat client.
|
||||||
|
|
||||||
[](https://i.imgur.com/san99Z2.png)
|
[](https://i.imgur.com/5S577z6.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.
|
||||||
|
20
apidoc/python/Makefile
Normal file
20
apidoc/python/Makefile
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Minimal makefile for Sphinx documentation
|
||||||
|
#
|
||||||
|
|
||||||
|
# You can set these variables from the command line.
|
||||||
|
SPHINXOPTS =
|
||||||
|
SPHINXBUILD = sphinx-build
|
||||||
|
SPHINXPROJ = toxic_api
|
||||||
|
SOURCEDIR = source
|
||||||
|
BUILDDIR = build
|
||||||
|
|
||||||
|
# Put it first so that "make" without argument is like "make help".
|
||||||
|
help:
|
||||||
|
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||||
|
|
||||||
|
.PHONY: help Makefile
|
||||||
|
|
||||||
|
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||||
|
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||||
|
%: Makefile
|
||||||
|
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
157
apidoc/python/source/conf.py
Normal file
157
apidoc/python/source/conf.py
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# toxic_api documentation build configuration file, created by
|
||||||
|
# sphinx-quickstart on Tue May 16 08:58:24 2017.
|
||||||
|
#
|
||||||
|
# This file is execfile()d with the current directory set to its
|
||||||
|
# containing dir.
|
||||||
|
#
|
||||||
|
# Note that not all possible configuration values are present in this
|
||||||
|
# autogenerated file.
|
||||||
|
#
|
||||||
|
# All configuration values have a default; values that are commented out
|
||||||
|
# serve to show the default.
|
||||||
|
|
||||||
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
|
#
|
||||||
|
# import os
|
||||||
|
# import sys
|
||||||
|
# sys.path.insert(0, os.path.abspath('.'))
|
||||||
|
|
||||||
|
|
||||||
|
# -- General configuration ------------------------------------------------
|
||||||
|
|
||||||
|
# If your documentation needs a minimal Sphinx version, state it here.
|
||||||
|
#
|
||||||
|
# needs_sphinx = '1.0'
|
||||||
|
|
||||||
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
|
# ones.
|
||||||
|
extensions = []
|
||||||
|
|
||||||
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
templates_path = ['_templates']
|
||||||
|
|
||||||
|
# The suffix(es) of source filenames.
|
||||||
|
# You can specify multiple suffix as a list of string:
|
||||||
|
#
|
||||||
|
# source_suffix = ['.rst', '.md']
|
||||||
|
source_suffix = '.rst'
|
||||||
|
|
||||||
|
# The master toctree document.
|
||||||
|
master_doc = 'index'
|
||||||
|
|
||||||
|
# General information about the project.
|
||||||
|
project = 'toxic_api'
|
||||||
|
copyright = '2017, Jakob Kreuze'
|
||||||
|
author = 'Jakob Kreuze'
|
||||||
|
|
||||||
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
|
# |version| and |release|, also used in various other places throughout the
|
||||||
|
# built documents.
|
||||||
|
#
|
||||||
|
# The short X.Y version.
|
||||||
|
version = '0.9.1'
|
||||||
|
# The full version, including alpha/beta/rc tags.
|
||||||
|
release = '0.9.1'
|
||||||
|
|
||||||
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
|
# for a list of supported languages.
|
||||||
|
#
|
||||||
|
# This is also used if you do content translation via gettext catalogs.
|
||||||
|
# Usually you set "language" from the command line for these cases.
|
||||||
|
language = None
|
||||||
|
|
||||||
|
# List of patterns, relative to source directory, that match files and
|
||||||
|
# directories to ignore when looking for source files.
|
||||||
|
# This patterns also effect to html_static_path and html_extra_path
|
||||||
|
exclude_patterns = []
|
||||||
|
|
||||||
|
# The name of the Pygments (syntax highlighting) style to use.
|
||||||
|
pygments_style = 'sphinx'
|
||||||
|
|
||||||
|
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||||
|
todo_include_todos = False
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTML output ----------------------------------------------
|
||||||
|
|
||||||
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
|
# a list of builtin themes.
|
||||||
|
#
|
||||||
|
html_theme = 'alabaster'
|
||||||
|
|
||||||
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
|
# further. For a list of options available for each theme, see the
|
||||||
|
# documentation.
|
||||||
|
#
|
||||||
|
# html_theme_options = {}
|
||||||
|
|
||||||
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
|
html_static_path = ['_static']
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTMLHelp output ------------------------------------------
|
||||||
|
|
||||||
|
# Output file base name for HTML help builder.
|
||||||
|
htmlhelp_basename = 'toxic_apidoc'
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for LaTeX output ---------------------------------------------
|
||||||
|
|
||||||
|
latex_elements = {
|
||||||
|
# The paper size ('letterpaper' or 'a4paper').
|
||||||
|
#
|
||||||
|
# 'papersize': 'letterpaper',
|
||||||
|
|
||||||
|
# The font size ('10pt', '11pt' or '12pt').
|
||||||
|
#
|
||||||
|
# 'pointsize': '10pt',
|
||||||
|
|
||||||
|
# Additional stuff for the LaTeX preamble.
|
||||||
|
#
|
||||||
|
# 'preamble': '',
|
||||||
|
|
||||||
|
# Latex figure (float) alignment
|
||||||
|
#
|
||||||
|
# 'figure_align': 'htbp',
|
||||||
|
}
|
||||||
|
|
||||||
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
|
# (source start file, target name, title,
|
||||||
|
# author, documentclass [howto, manual, or own class]).
|
||||||
|
latex_documents = [
|
||||||
|
(master_doc, 'toxic_api.tex', 'toxic\\_api Documentation',
|
||||||
|
'Jakob Kreuze', 'manual'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for manual page output ---------------------------------------
|
||||||
|
|
||||||
|
# One entry per manual page. List of tuples
|
||||||
|
# (source start file, name, description, authors, manual section).
|
||||||
|
man_pages = [
|
||||||
|
(master_doc, 'toxic_api', 'toxic_api Documentation',
|
||||||
|
[author], 1)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for Texinfo output -------------------------------------------
|
||||||
|
|
||||||
|
# Grouping the document tree into Texinfo files. List of tuples
|
||||||
|
# (source start file, target name, title, author,
|
||||||
|
# dir menu entry, description, category)
|
||||||
|
texinfo_documents = [
|
||||||
|
(master_doc, 'toxic_api', 'toxic_api Documentation',
|
||||||
|
author, 'toxic_api', 'One line description of project.',
|
||||||
|
'Miscellaneous'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
8
apidoc/python/source/examples.rst
Normal file
8
apidoc/python/source/examples.rst
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
============
|
||||||
|
API Examples
|
||||||
|
============
|
||||||
|
|
||||||
|
Fortune
|
||||||
|
=======
|
||||||
|
.. literalinclude:: fortune.py
|
||||||
|
:language: python
|
37
apidoc/python/source/fortune.py
Normal file
37
apidoc/python/source/fortune.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import toxic_api
|
||||||
|
import random
|
||||||
|
|
||||||
|
FORTUNES = [
|
||||||
|
"A bug in the code is worth two in the documentation.",
|
||||||
|
"A bug in the hand is better than one as yet undetected.",
|
||||||
|
"\"A debugged program is one for which you have not yet found the "
|
||||||
|
"conditions that make it fail.\" -- Jerry Ogdin"
|
||||||
|
]
|
||||||
|
|
||||||
|
def send_fortune(args):
|
||||||
|
"""Callback function that sends the contact of the current window a
|
||||||
|
given number of random fortunes.
|
||||||
|
"""
|
||||||
|
if len(args) != 1:
|
||||||
|
toxic_api.display("Only one argument allowed!")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
count = int(args[0])
|
||||||
|
except ValueError:
|
||||||
|
toxic_api.display("Argument must be a number!")
|
||||||
|
return
|
||||||
|
|
||||||
|
if count < 0 or count > 20:
|
||||||
|
toxic_api.display("Argument is too large!")
|
||||||
|
return
|
||||||
|
|
||||||
|
name = toxic_api.get_nick()
|
||||||
|
|
||||||
|
toxic_api.send("%s has decided to send you %d fortunes:" % (name, count))
|
||||||
|
for _ in range(count):
|
||||||
|
toxic_api.send(random.choice(FORTUNES))
|
||||||
|
|
||||||
|
|
||||||
|
toxic_api.register("/fortune", "Send a fortune to the contact of the current "
|
||||||
|
"window", send_fortune)
|
9
apidoc/python/source/index.rst
Normal file
9
apidoc/python/source/index.rst
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
Toxic Scripting Interface Documentation
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
intro
|
||||||
|
reference
|
||||||
|
examples
|
12
apidoc/python/source/intro.rst
Normal file
12
apidoc/python/source/intro.rst
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
=========================
|
||||||
|
Toxic Scripting Interface
|
||||||
|
=========================
|
||||||
|
|
||||||
|
A Python scripting interface to `Toxic <https://github.com/JFreegman/toxic>`_.
|
||||||
|
|
||||||
|
|
||||||
|
Getting Started
|
||||||
|
===============
|
||||||
|
Toxic is compiled with Python support by default. To access the scripting interface, simply import "toxic_api" in your script.
|
||||||
|
|
||||||
|
Scripts can be run by issuing "/run <path>" from toxic, or placing them in the "autorun_path" from your toxic configuration file.
|
73
apidoc/python/source/reference.rst
Normal file
73
apidoc/python/source/reference.rst
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
=============
|
||||||
|
API Reference
|
||||||
|
=============
|
||||||
|
|
||||||
|
Messages
|
||||||
|
========
|
||||||
|
.. function:: display(msg)
|
||||||
|
|
||||||
|
Display a message to the user through the current window.
|
||||||
|
|
||||||
|
:param msg: The message to display.
|
||||||
|
:type msg: string
|
||||||
|
:rtype: none
|
||||||
|
|
||||||
|
.. function:: send(msg)
|
||||||
|
|
||||||
|
Send a message to the user specified by the currently open conversation.
|
||||||
|
|
||||||
|
:param msg: The message to display.
|
||||||
|
:type msg: string
|
||||||
|
:rtype: none
|
||||||
|
|
||||||
|
|
||||||
|
State
|
||||||
|
=====
|
||||||
|
.. function:: get_nick()
|
||||||
|
|
||||||
|
Return the user's current nickname.
|
||||||
|
|
||||||
|
:rtype: string
|
||||||
|
|
||||||
|
.. function:: get_status()
|
||||||
|
|
||||||
|
Return a string representing the user's current status. Can be either "online", "away", or "busy".
|
||||||
|
|
||||||
|
:rtype: string
|
||||||
|
|
||||||
|
.. function:: get_status_message()
|
||||||
|
|
||||||
|
Return the user's current status message.
|
||||||
|
|
||||||
|
:rtype: string
|
||||||
|
|
||||||
|
.. function:: get_all_friends()
|
||||||
|
|
||||||
|
Return a list of all the user's friends.
|
||||||
|
|
||||||
|
:rtype: list of (string, string) tuples containing the nickname followed by their public key
|
||||||
|
|
||||||
|
|
||||||
|
Commands
|
||||||
|
========
|
||||||
|
.. function:: execute(command, class)
|
||||||
|
|
||||||
|
Executes the given command. The API exports three constants for the class parameter; GLOBAL_COMMAND, CHAT_COMMAND, and GROUPCHAT_COMMAND.
|
||||||
|
|
||||||
|
:param command: The command to execute.
|
||||||
|
:type command: string
|
||||||
|
:param class: The class of the command.
|
||||||
|
:type class: int
|
||||||
|
:rtype: none
|
||||||
|
|
||||||
|
.. function:: register(command, help, callback)
|
||||||
|
|
||||||
|
Register a callback to be executed whenever command is run. The callback function will be called with one argument, a list of arguments from when the user calls the command.
|
||||||
|
|
||||||
|
:param command: The command to listen for.
|
||||||
|
:type command: string
|
||||||
|
:param help: A description of the command to be shown in the help menu.
|
||||||
|
:type help: string
|
||||||
|
:param callback: The function to be called.
|
||||||
|
:type callback: callable
|
||||||
|
:rtype: none
|
26
astylerc
Normal file
26
astylerc
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# Bracket Style Options
|
||||||
|
--style=kr
|
||||||
|
|
||||||
|
# Tab Options
|
||||||
|
--indent=spaces=4
|
||||||
|
|
||||||
|
# Indentation Options
|
||||||
|
--indent-switches
|
||||||
|
|
||||||
|
# Padding Options
|
||||||
|
--pad-header
|
||||||
|
--break-blocks
|
||||||
|
--pad-oper
|
||||||
|
--unpad-paren
|
||||||
|
--align-pointer=name
|
||||||
|
--align-reference=name
|
||||||
|
|
||||||
|
# Formatting Options
|
||||||
|
--add-brackets
|
||||||
|
--convert-tabs
|
||||||
|
--max-code-length=120
|
||||||
|
|
||||||
|
# Other Options
|
||||||
|
--preserve-date
|
||||||
|
--formatted
|
||||||
|
--lineend=linux
|
@ -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
|
||||||
@ -8,13 +8,14 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
# Check if we can build audio support
|
# Check if we can build audio support
|
||||||
CHECK_AUDIO_LIBS = $(shell $(PKG_CONFIG) --exists $(AUDIO_LIBS) || echo -n "error")
|
CHECK_AUDIO_LIBS := $(shell $(PKG_CONFIG) --exists $(AUDIO_LIBS) || echo -n "error")
|
||||||
ifneq ($(CHECK_AUDIO_LIBS), error)
|
ifneq ($(CHECK_AUDIO_LIBS), error)
|
||||||
LIBS += $(AUDIO_LIBS)
|
LIBS += $(AUDIO_LIBS)
|
||||||
|
LDFLAGS += -lm
|
||||||
CFLAGS += $(AUDIO_CFLAGS)
|
CFLAGS += $(AUDIO_CFLAGS)
|
||||||
OBJ += $(AUDIO_OBJ)
|
OBJ += $(AUDIO_OBJ)
|
||||||
else ifneq ($(MAKECMDGOALS), clean)
|
else ifneq ($(MAKECMDGOALS), clean)
|
||||||
MISSING_AUDIO_LIBS = $(shell for lib in $(AUDIO_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
|
MISSING_AUDIO_LIBS := $(shell for lib in $(AUDIO_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
|
||||||
$(warning WARNING -- Toxic will be compiled without audio support)
|
$(warning WARNING -- Toxic will be compiled without audio support)
|
||||||
$(warning WARNING -- You need these libraries for audio support)
|
$(warning WARNING -- You need these libraries for audio support)
|
||||||
$(warning WARNING -- $(MISSING_AUDIO_LIBS))
|
$(warning WARNING -- $(MISSING_AUDIO_LIBS))
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
CHECKS_DIR = $(CFG_DIR)/checks
|
CHECKS_DIR = $(CFG_DIR)/checks
|
||||||
|
|
||||||
# Check if we want build X11 support
|
# Check if we want build X11 support
|
||||||
X11 = $(shell if [ -z "$(DISABLE_X11)" ] || [ "$(DISABLE_X11)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
|
X11 := $(shell if [ -z "$(DISABLE_X11)" ] || [ "$(DISABLE_X11)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
|
||||||
ifneq ($(X11), disabled)
|
ifneq ($(X11), disabled)
|
||||||
-include $(CHECKS_DIR)/x11.mk
|
-include $(CHECKS_DIR)/x11.mk
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Check if we want build audio support
|
# Check if we want build audio support
|
||||||
AUDIO = $(shell if [ -z "$(DISABLE_AV)" ] || [ "$(DISABLE_AV)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
|
AUDIO := $(shell if [ -z "$(DISABLE_AV)" ] || [ "$(DISABLE_AV)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
|
||||||
ifneq ($(AUDIO), disabled)
|
ifneq ($(AUDIO), disabled)
|
||||||
-include $(CHECKS_DIR)/audio.mk
|
-include $(CHECKS_DIR)/audio.mk
|
||||||
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)
|
||||||
@ -23,24 +23,42 @@ endif
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
# Check if we want build sound notifications support
|
# Check if we want build sound notifications support
|
||||||
SND_NOTIFY = $(shell if [ -z "$(DISABLE_SOUND_NOTIFY)" ] || [ "$(DISABLE_SOUND_NOTIFY)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
|
SND_NOTIFY := $(shell if [ -z "$(DISABLE_SOUND_NOTIFY)" ] || [ "$(DISABLE_SOUND_NOTIFY)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
|
||||||
ifneq ($(SND_NOTIFY), disabled)
|
ifneq ($(SND_NOTIFY), disabled)
|
||||||
-include $(CHECKS_DIR)/sound_notifications.mk
|
-include $(CHECKS_DIR)/sound_notifications.mk
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Check if we want build desktop notifications support
|
# Check if we want build desktop notifications support
|
||||||
DESK_NOTIFY = $(shell if [ -z "$(DISABLE_DESKTOP_NOTIFY)" ] || [ "$(DISABLE_DESKTOP_NOTIFY)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
|
DESK_NOTIFY := $(shell if [ -z "$(DISABLE_DESKTOP_NOTIFY)" ] || [ "$(DISABLE_DESKTOP_NOTIFY)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
|
||||||
ifneq ($(DESK_NOTIFY), disabled)
|
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
|
||||||
|
QR_PNG := $(shell if [ -z "$(DISABLE_QRPNG)" ] || [ "$(DISABLE_QRPNG)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
|
||||||
|
ifneq ($(QR_PNG), disabled)
|
||||||
|
-include $(CHECKS_DIR)/qr_png.mk
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Check if we want build Python scripting support
|
||||||
|
PYTHON := $(shell if [ -z "$(ENABLE_PYTHON)" ] || [ "$(ENABLE_PYTHON)" = "0" ] ; then echo disabled ; else echo enabled ; fi)
|
||||||
|
ifneq ($(PYTHON), disabled)
|
||||||
|
-include $(CHECKS_DIR)/python.mk
|
||||||
|
endif
|
||||||
|
|
||||||
# Check if we can build Toxic
|
# Check if we can build Toxic
|
||||||
CHECK_LIBS = $(shell $(PKG_CONFIG) --exists $(LIBS) || echo -n "error")
|
CHECK_LIBS := $(shell $(PKG_CONFIG) --exists $(LIBS) || echo -n "error")
|
||||||
ifneq ($(CHECK_LIBS), error)
|
ifneq ($(CHECK_LIBS), error)
|
||||||
CFLAGS += $(shell $(PKG_CONFIG) --cflags $(LIBS))
|
CFLAGS += $(shell $(PKG_CONFIG) --cflags $(LIBS))
|
||||||
LDFLAGS += $(shell $(PKG_CONFIG) --libs $(LIBS))
|
LDFLAGS += $(shell $(PKG_CONFIG) --libs $(LIBS))
|
||||||
else ifneq ($(MAKECMDGOALS), clean)
|
else ifneq ($(MAKECMDGOALS), clean)
|
||||||
MISSING_LIBS = $(shell for lib in $(LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
|
MISSING_LIBS := $(shell for lib in $(LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
|
||||||
$(warning ERROR -- Cannot compile Toxic)
|
$(warning ERROR -- Cannot compile Toxic)
|
||||||
$(warning ERROR -- You need these libraries)
|
$(warning ERROR -- You need these libraries)
|
||||||
$(warning ERROR -- $(MISSING_LIBS))
|
$(warning ERROR -- $(MISSING_LIBS))
|
||||||
|
@ -3,12 +3,12 @@ DESK_NOTIFY_LIBS = libnotify
|
|||||||
DESK_NOTIFY_CFLAGS = -DBOX_NOTIFY
|
DESK_NOTIFY_CFLAGS = -DBOX_NOTIFY
|
||||||
|
|
||||||
# Check if we can build desktop notifications support
|
# Check if we can build desktop notifications support
|
||||||
CHECK_DESK_NOTIFY_LIBS = $(shell $(PKG_CONFIG) --exists $(DESK_NOTIFY_LIBS) || echo -n "error")
|
CHECK_DESK_NOTIFY_LIBS := $(shell $(PKG_CONFIG) --exists $(DESK_NOTIFY_LIBS) || echo -n "error")
|
||||||
ifneq ($(CHECK_DESK_NOTIFY_LIBS), error)
|
ifneq ($(CHECK_DESK_NOTIFY_LIBS), error)
|
||||||
LIBS += $(DESK_NOTIFY_LIBS)
|
LIBS += $(DESK_NOTIFY_LIBS)
|
||||||
CFLAGS += $(DESK_NOTIFY_CFLAGS)
|
CFLAGS += $(DESK_NOTIFY_CFLAGS)
|
||||||
else ifneq ($(MAKECMDGOALS), clean)
|
else ifneq ($(MAKECMDGOALS), clean)
|
||||||
MISSING_DESK_NOTIFY_LIBS = $(shell for lib in $(DESK_NOTIFY_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
|
MISSING_DESK_NOTIFY_LIBS := $(shell for lib in $(DESK_NOTIFY_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
|
||||||
$(warning WARNING -- Toxic will be compiled without desktop notifications support)
|
$(warning WARNING -- Toxic will be compiled without desktop notifications support)
|
||||||
$(warning WARNING -- You need these libraries for desktop notifications support)
|
$(warning WARNING -- You need these libraries for desktop notifications support)
|
||||||
$(warning WARNING -- $(MISSING_DESK_NOTIFY_LIBS))
|
$(warning WARNING -- $(MISSING_DESK_NOTIFY_LIBS))
|
||||||
|
15
cfg/checks/python.mk
Normal file
15
cfg/checks/python.mk
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Variables for Python scripting support
|
||||||
|
PYTHON3_LIBS = python3
|
||||||
|
PYTHON_CFLAGS = -DPYTHON
|
||||||
|
PYTHON_OBJ = api.o python_api.o
|
||||||
|
|
||||||
|
# Check if we can build Python scripting support
|
||||||
|
CHECK_PYTHON3_LIBS = $(shell $(PKG_CONFIG) --exists $(PYTHON3_LIBS) || echo -n "error")
|
||||||
|
ifneq ($(CHECK_PYTHON3_LIBS), error)
|
||||||
|
LDFLAGS += $(shell python3-config --ldflags)
|
||||||
|
CFLAGS += $(PYTHON_CFLAGS) $(shell python3-config --includes)
|
||||||
|
OBJ += $(PYTHON_OBJ)
|
||||||
|
else ifneq ($(MAKECMDGOALS), clean)
|
||||||
|
$(warning WARNING -- Toxic will be compiled without Python scripting support)
|
||||||
|
$(warning WARNING -- You need python3 installed for Python scripting support)
|
||||||
|
endif
|
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
|
15
cfg/checks/qr_png.mk
Normal file
15
cfg/checks/qr_png.mk
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Variables for QR exported as PNG support
|
||||||
|
PNG_LIBS = libpng
|
||||||
|
PNG_CFLAGS = -DQRPNG
|
||||||
|
|
||||||
|
# Check if we can build QR exported as PNG support
|
||||||
|
CHECK_PNG_LIBS = $(shell pkg-config --exists $(PNG_LIBS) || echo -n "error")
|
||||||
|
ifneq ($(CHECK_PNG_LIBS), error)
|
||||||
|
LIBS += $(PNG_LIBS)
|
||||||
|
CFLAGS += $(PNG_CFLAGS)
|
||||||
|
else ifneq ($(MAKECMDGOALS), clean)
|
||||||
|
MISSING_PNG_LIBS = $(shell for lib in $(PNG_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
|
||||||
|
$(warning WARNING -- Toxic will be compiled without QR exported as PNG support)
|
||||||
|
$(warning WARNING -- You need these libraries for QR exported as PNG support)
|
||||||
|
$(warning WARNING -- $(MISSING_PNG_LIBS))
|
||||||
|
endif
|
@ -1,5 +1,5 @@
|
|||||||
# Variables for video call support
|
# Variables for video call support
|
||||||
VIDEO_LIBS = libtoxav vpx x11
|
VIDEO_LIBS = openal 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
|
||||||
@ -8,13 +8,13 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
# Check if we can build video support
|
# Check if we can build video support
|
||||||
CHECK_VIDEO_LIBS = $(shell pkg-config --exists $(VIDEO_LIBS) || echo -n "error")
|
CHECK_VIDEO_LIBS = $(shell $(PKG_CONFIG) --exists $(VIDEO_LIBS) || echo -n "error")
|
||||||
ifneq ($(CHECK_VIDEO_LIBS), error)
|
ifneq ($(CHECK_VIDEO_LIBS), error)
|
||||||
LIBS += $(VIDEO_LIBS)
|
LIBS += $(VIDEO_LIBS)
|
||||||
CFLAGS += $(VIDEO_CFLAGS)
|
CFLAGS += $(VIDEO_CFLAGS)
|
||||||
OBJ += $(VIDEO_OBJ)
|
OBJ += $(VIDEO_OBJ)
|
||||||
else ifneq ($(MAKECMDGOALS), clean)
|
else ifneq ($(MAKECMDGOALS), clean)
|
||||||
MISSING_VIDEO_LIBS = $(shell for lib in $(VIDEO_LIBS) ; do if ! pkg-config --exists $$lib ; then echo $$lib ; fi ; done)
|
MISSING_VIDEO_LIBS = $(shell for lib in $(VIDEO_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
|
||||||
$(warning WARNING -- Toxic will be compiled without video support)
|
$(warning WARNING -- Toxic will be compiled without video support)
|
||||||
$(warning WARNING -- You will need these libraries for video support)
|
$(warning WARNING -- You will need these libraries for video support)
|
||||||
$(warning WARNING -- $(MISSING_VIDEO_LIBS))
|
$(warning WARNING -- $(MISSING_VIDEO_LIBS))
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# Variables for X11 support
|
# Variables for X11 support
|
||||||
X11_LIBS = x11
|
X11_LIBS = x11
|
||||||
X11_CFLAGS = -DX11
|
X11_CFLAGS = -DX11
|
||||||
X11_OBJ = xtra.o
|
X11_OBJ = x11focus.o
|
||||||
|
|
||||||
# Check if we can build X11 support
|
# Check if we can build X11 support
|
||||||
CHECK_X11_LIBS = $(shell $(PKG_CONFIG) --exists $(X11_LIBS) || echo -n "error")
|
CHECK_X11_LIBS = $(shell $(PKG_CONFIG) --exists $(X11_LIBS) || echo -n "error")
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Version
|
# Version
|
||||||
TOXIC_VERSION = 0.7.1
|
TOXIC_VERSION = 0.9.1
|
||||||
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,9 +14,24 @@ 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 " ENABLE_PYTHON: Set to \"1\" to enable building with Python scripting support"
|
||||||
|
@echo " RELEASE_ENABLED: Set to \"1\" to build without debug symbols and with full compiler optimizations"
|
||||||
|
@echo " ASAN_ENABLED: Set to \"1\" to build with LLVM address sanitizer enabled.
|
||||||
@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 ;\
|
||||||
@ -35,7 +35,7 @@ install: $(BUILD_DIR)/toxic
|
|||||||
mv temp_file $$file ;\
|
mv temp_file $$file ;\
|
||||||
sed -e 's:__DATADIR__:'$(abspath $(DATADIR))':g' $$file > temp_file && \
|
sed -e 's:__DATADIR__:'$(abspath $(DATADIR))':g' $$file > temp_file && \
|
||||||
mv temp_file $$file ;\
|
mv temp_file $$file ;\
|
||||||
gzip -f -9 $$file ;\
|
gzip -f -n -9 $$file ;\
|
||||||
done
|
done
|
||||||
|
|
||||||
.PHONY: install
|
.PHONY: install
|
||||||
|
@ -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
|
||||||
|
11
doc/toxic.1
11
doc/toxic.1
@ -1,13 +1,13 @@
|
|||||||
'\" t
|
'\" t
|
||||||
.\" Title: toxic
|
.\" Title: toxic
|
||||||
.\" Author: [see the "AUTHORS" section]
|
.\" Author: [see the "AUTHORS" section]
|
||||||
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
|
||||||
.\" Date: 2016-09-20
|
.\" Date: 2020-05-04
|
||||||
.\" Manual: Toxic Manual
|
.\" Manual: Toxic Manual
|
||||||
.\" Source: toxic __VERSION__
|
.\" Source: toxic __VERSION__
|
||||||
.\" Language: English
|
.\" Language: English
|
||||||
.\"
|
.\"
|
||||||
.TH "TOXIC" "1" "2016\-09\-20" "toxic __VERSION__" "Toxic Manual"
|
.TH "TOXIC" "1" "2020\-05\-04" "toxic __VERSION__" "Toxic Manual"
|
||||||
.\" -----------------------------------------------------------------
|
.\" -----------------------------------------------------------------
|
||||||
.\" * Define some portability stuff
|
.\" * Define some portability stuff
|
||||||
.\" -----------------------------------------------------------------
|
.\" -----------------------------------------------------------------
|
||||||
@ -78,6 +78,11 @@ instead of
|
|||||||
Show help message
|
Show help message
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
|
\-l, \-\-logging
|
||||||
|
.RS 4
|
||||||
|
Enable toxcore logging to stderr
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
\-n, \-\-nodes nodes\-file
|
\-n, \-\-nodes nodes\-file
|
||||||
.RS 4
|
.RS 4
|
||||||
Use specified
|
Use specified
|
||||||
|
@ -40,6 +40,9 @@ OPTIONS
|
|||||||
-h, --help::
|
-h, --help::
|
||||||
Show help message
|
Show help message
|
||||||
|
|
||||||
|
-l, --logging::
|
||||||
|
Enable toxcore logging to stderr
|
||||||
|
|
||||||
-n, --nodes nodes-file::
|
-n, --nodes nodes-file::
|
||||||
Use specified 'nodes-file' for DHT bootstrap nodes instead of '~/.config/tox/DHTnodes.json'
|
Use specified 'nodes-file' for DHT bootstrap nodes instead of '~/.config/tox/DHTnodes.json'
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
'\" t
|
'\" t
|
||||||
.\" Title: toxic.conf
|
.\" Title: toxic.conf
|
||||||
.\" Author: [see the "AUTHORS" section]
|
.\" Author: [see the "AUTHORS" section]
|
||||||
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
|
||||||
.\" Date: 2016-07-21
|
.\" Date: 2020-05-07
|
||||||
.\" Manual: Toxic Manual
|
.\" Manual: Toxic Manual
|
||||||
.\" Source: toxic __VERSION__
|
.\" Source: toxic __VERSION__
|
||||||
.\" Language: English
|
.\" Language: English
|
||||||
.\"
|
.\"
|
||||||
.TH "TOXIC\&.CONF" "5" "2016\-07\-21" "toxic __VERSION__" "Toxic Manual"
|
.TH "TOXIC\&.CONF" "5" "2020\-05\-07" "toxic __VERSION__" "Toxic Manual"
|
||||||
.\" -----------------------------------------------------------------
|
.\" -----------------------------------------------------------------
|
||||||
.\" * Define some portability stuff
|
.\" * Define some portability stuff
|
||||||
.\" -----------------------------------------------------------------
|
.\" -----------------------------------------------------------------
|
||||||
@ -120,7 +120,12 @@ Enable friend connection change notifications\&. true or false
|
|||||||
.PP
|
.PP
|
||||||
\fBnodelist_update_freq\fR
|
\fBnodelist_update_freq\fR
|
||||||
.RS 4
|
.RS 4
|
||||||
How often in days to update the DHT nodes list\&. (0 to disable updates)
|
How often in days to update the DHT nodes list\&. (integer; 0 to disable)
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
\fBautosave_freq\fR
|
||||||
|
.RS 4
|
||||||
|
How often in seconds to auto\-save the Tox data file\&. (integer; 0 to disable)
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
\fBhistory_size\fR
|
\fBhistory_size\fR
|
||||||
@ -128,6 +133,11 @@ How often in days to update the DHT nodes list\&. (0 to disable updates)
|
|||||||
Maximum lines for chat window history\&. Integer value\&. (for example: 700)
|
Maximum lines for chat window history\&. Integer value\&. (for example: 700)
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
|
\fBnotification_timeout\fR
|
||||||
|
.RS 4
|
||||||
|
Time in milliseconds to display a notification\&. Integer value\&. (for example: 3000)
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
\fBline_join\fR
|
\fBline_join\fR
|
||||||
.RS 4
|
.RS 4
|
||||||
Indicator for when someone connects or joins a group\&. Three characters max for line_ settings\&.
|
Indicator for when someone connects or joins a group\&. Three characters max for line_ settings\&.
|
||||||
@ -207,9 +217,24 @@ Audio output device\&. Integer value\&. Number corresponds to
|
|||||||
/lsdev out
|
/lsdev out
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
\fBVAD_treshold\fR
|
\fBVAD_threshold\fR
|
||||||
.RS 4
|
.RS 4
|
||||||
Voice Activity Detection treshold\&. Float value\&. Recommended values are around 40\&.0
|
Voice Activity Detection threshold\&. Float value\&. Recommended values are 1\&.0\-40\&.0
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
\fBpush_to_talk\fR
|
||||||
|
.RS 4
|
||||||
|
Enable/Disable Push\-To\-Talk for conference audio chats (active key is F2)\&. true or false
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
\fBconference_audio_channels\fR
|
||||||
|
.RS 4
|
||||||
|
Number of channels for conference audio broadcast\&. Integer value\&. 1 (mono) or 2 (stereo)
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
\fBchat_audio_channels\fR
|
||||||
|
.RS 4
|
||||||
|
Number of channels for 1\-on\-1 audio broadcast\&. Integer value\&. 1 (mono) or 2 (stereo)
|
||||||
.RE
|
.RE
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
@ -227,6 +252,11 @@ Default path for downloads\&. String value\&. Absolute path for downloaded files
|
|||||||
Path for your avatar (file must be a \&.png and cannot exceed 16\&.3 KiB)
|
Path for your avatar (file must be a \&.png and cannot exceed 16\&.3 KiB)
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
|
\fBautorun_path\fR
|
||||||
|
.RS 4
|
||||||
|
Path for any scripts that should be run on startup
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
\fBchatlogs_path\fR
|
\fBchatlogs_path\fR
|
||||||
.RS 4
|
.RS 4
|
||||||
Default path for chatlogs\&. String value\&. Absolute path for chatlog files\&.
|
Default path for chatlogs\&. String value\&. Absolute path for chatlog files\&.
|
||||||
@ -336,16 +366,6 @@ Key combination to scroll half page down\&.
|
|||||||
Key combination to scroll to page bottom\&.
|
Key combination to scroll to page bottom\&.
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
\fBpeer_list_up\fR
|
|
||||||
.RS 4
|
|
||||||
Key combination to scroll contacts list up\&.
|
|
||||||
.RE
|
|
||||||
.PP
|
|
||||||
\fBpeer_list_down\fR
|
|
||||||
.RS 4
|
|
||||||
Key combination to scroll contacts list down\&.
|
|
||||||
.RE
|
|
||||||
.PP
|
|
||||||
\fBtoggle_peerlist\fR
|
\fBtoggle_peerlist\fR
|
||||||
.RS 4
|
.RS 4
|
||||||
Toggle the peer list on and off\&.
|
Toggle the peer list on and off\&.
|
||||||
|
@ -76,11 +76,17 @@ OPTIONS
|
|||||||
Enable friend connection change notifications. true or false
|
Enable friend connection change notifications. true or false
|
||||||
|
|
||||||
*nodelist_update_freq*;;
|
*nodelist_update_freq*;;
|
||||||
How often in days to update the DHT nodes list. (0 to disable updates)
|
How often in days to update the DHT nodes list. (integer; 0 to disable)
|
||||||
|
|
||||||
|
*autosave_freq*;;
|
||||||
|
How often in seconds to auto-save the Tox data file. (integer; 0 to disable)
|
||||||
|
|
||||||
*history_size*;;
|
*history_size*;;
|
||||||
Maximum lines for chat window history. Integer value. (for example: 700)
|
Maximum lines for chat window history. Integer value. (for example: 700)
|
||||||
|
|
||||||
|
*notification_timeout*;;
|
||||||
|
Time in milliseconds to display a notification. Integer value. (for example: 3000)
|
||||||
|
|
||||||
*line_join*;;
|
*line_join*;;
|
||||||
Indicator for when someone connects or joins a group.
|
Indicator for when someone connects or joins a group.
|
||||||
Three characters max for line_ settings.
|
Three characters max for line_ settings.
|
||||||
@ -129,9 +135,18 @@ OPTIONS
|
|||||||
*output_device*;;
|
*output_device*;;
|
||||||
Audio output device. Integer value. Number corresponds to `/lsdev out`
|
Audio output device. Integer value. Number corresponds to `/lsdev out`
|
||||||
|
|
||||||
*VAD_treshold*;;
|
*VAD_threshold*;;
|
||||||
Voice Activity Detection treshold. Float value. Recommended values are
|
Voice Activity Detection threshold. Float value. Recommended values are
|
||||||
around 40.0
|
1.0-40.0
|
||||||
|
|
||||||
|
*conference_audio_channels*;;
|
||||||
|
Number of channels for conference audio broadcast. Integer value. 1 (mono) or 2 (stereo)
|
||||||
|
|
||||||
|
*chat_audio_channels*;;
|
||||||
|
Number of channels for 1-on-1 audio broadcast. Integer value. 1 (mono) or 2 (stereo)
|
||||||
|
|
||||||
|
*push_to_talk*;;
|
||||||
|
Enable/Disable Push-To-Talk for conference audio chats (active key is F2). true or false
|
||||||
|
|
||||||
*tox*::
|
*tox*::
|
||||||
Configuration related to paths.
|
Configuration related to paths.
|
||||||
@ -143,6 +158,9 @@ OPTIONS
|
|||||||
*avatar_path*;;
|
*avatar_path*;;
|
||||||
Path for your avatar (file must be a .png and cannot exceed 16.3 KiB)
|
Path for your avatar (file must be a .png and cannot exceed 16.3 KiB)
|
||||||
|
|
||||||
|
*autorun_path*;;
|
||||||
|
Path for any scripts that should be run on startup
|
||||||
|
|
||||||
*chatlogs_path*;;
|
*chatlogs_path*;;
|
||||||
Default path for chatlogs. String value. Absolute path for chatlog files.
|
Default path for chatlogs. String value. Absolute path for chatlog files.
|
||||||
|
|
||||||
@ -212,12 +230,6 @@ OPTIONS
|
|||||||
*page_bottom*;;
|
*page_bottom*;;
|
||||||
Key combination to scroll to page bottom.
|
Key combination to scroll to page bottom.
|
||||||
|
|
||||||
*peer_list_up*;;
|
|
||||||
Key combination to scroll contacts list up.
|
|
||||||
|
|
||||||
*peer_list_down*;;
|
|
||||||
Key combination to scroll contacts list down.
|
|
||||||
|
|
||||||
*toggle_peerlist*;;
|
*toggle_peerlist*;;
|
||||||
Toggle the peer list on and off.
|
Toggle the peer list on and off.
|
||||||
|
|
||||||
|
@ -47,9 +47,15 @@ ui = {
|
|||||||
// How often in days to update the DHT nodes list. (0 to disable updates)
|
// How often in days to update the DHT nodes list. (0 to disable updates)
|
||||||
nodeslist_update_freq=7;
|
nodeslist_update_freq=7;
|
||||||
|
|
||||||
|
// How often in seconds to auto-save the Tox data file. (0 to disable periodic auto-saves)
|
||||||
|
autosave_freq=600;
|
||||||
|
|
||||||
// maximum lines for chat window history
|
// maximum lines for chat window history
|
||||||
history_size=700;
|
history_size=700;
|
||||||
|
|
||||||
|
// time in milliseconds to display a notification
|
||||||
|
notification_timeout=3000;
|
||||||
|
|
||||||
// Indicator for display when someone connects or joins a group.
|
// Indicator for display when someone connects or joins a group.
|
||||||
line_join="-->";
|
line_join="-->";
|
||||||
|
|
||||||
@ -76,8 +82,17 @@ audio = {
|
|||||||
// preferred audio output device; numbers correspond to /lsdev out
|
// preferred audio output device; numbers correspond to /lsdev out
|
||||||
output_device=0;
|
output_device=0;
|
||||||
|
|
||||||
// default VAD treshold; float (recommended values are around 40)
|
// default VAD threshold; float (recommended values are 1.0-40.0)
|
||||||
VAD_treshold=40.0;
|
VAD_threshold=5.0;
|
||||||
|
|
||||||
|
// Number of channels to use for conference audio broadcasts; 1 for mono, 2 for stereo.
|
||||||
|
conference_audio_channels=1;
|
||||||
|
|
||||||
|
// Number of channels to use for 1-on-1 audio broadcasts; 1 for mono, 2 for stereo.
|
||||||
|
chat_audio_channels=2;
|
||||||
|
|
||||||
|
// toggle conference push-to-talk
|
||||||
|
push_to_talk=false;
|
||||||
};
|
};
|
||||||
|
|
||||||
tox = {
|
tox = {
|
||||||
@ -87,6 +102,9 @@ tox = {
|
|||||||
// Path for your avatar (file must be a .png and cannot exceed 64 KiB)
|
// Path for your avatar (file must be a .png and cannot exceed 64 KiB)
|
||||||
// avatar_path="/home/USERNAME/Pictures/youravatar.png";
|
// avatar_path="/home/USERNAME/Pictures/youravatar.png";
|
||||||
|
|
||||||
|
// Path for scripts that should be run on startup
|
||||||
|
// autorun_path="/home/USERNAME/toxic_scripts/";
|
||||||
|
|
||||||
// Path for chatlogs
|
// Path for chatlogs
|
||||||
// chatlogs_path="/home/USERNAME/toxic_chatlogs/";
|
// chatlogs_path="/home/USERNAME/toxic_chatlogs/";
|
||||||
};
|
};
|
||||||
@ -113,9 +131,6 @@ keys = {
|
|||||||
half_page_up="Ctrl+F";
|
half_page_up="Ctrl+F";
|
||||||
half_page_down="Ctrl+V";
|
half_page_down="Ctrl+V";
|
||||||
page_bottom="Ctrl+H";
|
page_bottom="Ctrl+H";
|
||||||
peer_list_up="Ctrl+[";
|
|
||||||
peer_list_down="Ctrl+]";
|
|
||||||
toggle_peerlist="Ctrl+b";
|
toggle_peerlist="Ctrl+b";
|
||||||
toggle_paste_mode="Ctrl+T";
|
toggle_paste_mode="Ctrl+T";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
219
src/api.c
Normal file
219
src/api.c
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
/* api.c
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Jakob Kreuze <jakob@memeware.net>
|
||||||
|
*
|
||||||
|
* This file is part of Toxic.
|
||||||
|
*
|
||||||
|
* Toxic is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Toxic is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <tox/tox.h>
|
||||||
|
|
||||||
|
#include "execute.h"
|
||||||
|
#include "friendlist.h"
|
||||||
|
#include "line_info.h"
|
||||||
|
#include "message_queue.h"
|
||||||
|
#include "misc_tools.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "toxic_strings.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
|
#ifdef PYTHON
|
||||||
|
#include "python_api.h"
|
||||||
|
|
||||||
|
Tox *user_tox;
|
||||||
|
static WINDOW *cur_window;
|
||||||
|
static ToxWindow *self_window;
|
||||||
|
|
||||||
|
extern FriendsList Friends;
|
||||||
|
extern struct user_settings *user_settings;
|
||||||
|
|
||||||
|
void api_display(const char *const msg)
|
||||||
|
{
|
||||||
|
if (msg == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self_window = get_active_window();
|
||||||
|
line_info_add(self_window, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
FriendsList api_get_friendslist(void)
|
||||||
|
{
|
||||||
|
return Friends;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *api_get_nick(void)
|
||||||
|
{
|
||||||
|
size_t len = tox_self_get_name_size(user_tox);
|
||||||
|
uint8_t *name = malloc(len + 1);
|
||||||
|
|
||||||
|
if (name == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
tox_self_get_name(user_tox, name);
|
||||||
|
name[len] = '\0';
|
||||||
|
return (char *) name;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tox_User_Status api_get_status(void)
|
||||||
|
{
|
||||||
|
return tox_self_get_status(user_tox);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *api_get_status_message(void)
|
||||||
|
{
|
||||||
|
size_t len = tox_self_get_status_message_size(user_tox);
|
||||||
|
uint8_t *status = malloc(len + 1);
|
||||||
|
|
||||||
|
if (status == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
tox_self_get_status_message(user_tox, status);
|
||||||
|
status[len] = '\0';
|
||||||
|
return (char *) status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void api_send(const char *msg)
|
||||||
|
{
|
||||||
|
if (msg == NULL || self_window->chatwin->cqueue == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *name = api_get_nick();
|
||||||
|
char timefrmt[TIME_STR_SIZE];
|
||||||
|
|
||||||
|
if (name == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self_window = get_active_window();
|
||||||
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
|
|
||||||
|
strncpy((char *) self_window->chatwin->line, msg, sizeof(self_window->chatwin->line));
|
||||||
|
add_line_to_hist(self_window->chatwin);
|
||||||
|
int id = line_info_add(self_window, timefrmt, name, NULL, OUT_MSG, 0, 0, "%s", msg);
|
||||||
|
cqueue_add(self_window->chatwin->cqueue, msg, strlen(msg), OUT_MSG, id);
|
||||||
|
free(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void api_execute(const char *input, int mode)
|
||||||
|
{
|
||||||
|
self_window = get_active_window();
|
||||||
|
execute(cur_window, self_window, user_tox, input, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
int do_plugin_command(int num_args, char (*args)[MAX_STR_SIZE])
|
||||||
|
{
|
||||||
|
return do_python_command(num_args, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
int num_registered_handlers(void)
|
||||||
|
{
|
||||||
|
return python_num_registered_handlers();
|
||||||
|
}
|
||||||
|
|
||||||
|
int help_max_width(void)
|
||||||
|
{
|
||||||
|
return python_help_max_width();
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_handler_help(WINDOW *win)
|
||||||
|
{
|
||||||
|
python_draw_handler_help(win);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmd_run(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
const char *error_str;
|
||||||
|
|
||||||
|
cur_window = window;
|
||||||
|
self_window = self;
|
||||||
|
|
||||||
|
if (argc != 1) {
|
||||||
|
if (argc < 1) {
|
||||||
|
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);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp = fopen(argv[1], "r");
|
||||||
|
|
||||||
|
if (fp == NULL) {
|
||||||
|
error_str = "Path does not exist.";
|
||||||
|
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, error_str);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
run_python(fp, argv[1]);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void invoke_autoruns(WINDOW *window, ToxWindow *self)
|
||||||
|
{
|
||||||
|
char abspath_buf[PATH_MAX + 256];
|
||||||
|
char err_buf[PATH_MAX + 128];
|
||||||
|
|
||||||
|
if (user_settings->autorun_path[0] == '\0') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DIR *d = opendir(user_settings->autorun_path);
|
||||||
|
|
||||||
|
if (d == NULL) {
|
||||||
|
snprintf(err_buf, sizeof(err_buf), "Autorun path does not exist: %s", user_settings->autorun_path);
|
||||||
|
api_display(err_buf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dirent *dir = NULL;
|
||||||
|
|
||||||
|
cur_window = window;
|
||||||
|
|
||||||
|
self_window = self;
|
||||||
|
|
||||||
|
while ((dir = readdir(d)) != NULL) {
|
||||||
|
size_t path_len = strlen(dir->d_name);
|
||||||
|
|
||||||
|
if (!strcmp(dir->d_name + path_len - 3, ".py")) {
|
||||||
|
snprintf(abspath_buf, sizeof(abspath_buf), "%s%s", user_settings->autorun_path, dir->d_name);
|
||||||
|
FILE *fp = fopen(abspath_buf, "r");
|
||||||
|
|
||||||
|
if (fp == NULL) {
|
||||||
|
snprintf(err_buf, sizeof(err_buf), "Invalid path: %s", abspath_buf);
|
||||||
|
api_display(err_buf);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
run_python(fp, abspath_buf);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(d);
|
||||||
|
}
|
||||||
|
#endif /* PYTHON */
|
43
src/api.h
Normal file
43
src/api.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/* api.h
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Jakob Kreuze <jakob@memeware.net>
|
||||||
|
*
|
||||||
|
* This file is part of Toxic.
|
||||||
|
*
|
||||||
|
* Toxic is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Toxic is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef API_H
|
||||||
|
#define API_H
|
||||||
|
|
||||||
|
#include "friendlist.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
|
void api_display(const char *const msg);
|
||||||
|
FriendsList api_get_friendslist(void);
|
||||||
|
char *api_get_nick(void);
|
||||||
|
Tox_User_Status api_get_status(void);
|
||||||
|
char *api_get_status_message(void);
|
||||||
|
void api_send(const char *msg);
|
||||||
|
void api_execute(const char *input, int mode);
|
||||||
|
int do_plugin_command(int num_args, char (*args)[MAX_STR_SIZE]);
|
||||||
|
int num_registered_handlers(void);
|
||||||
|
int help_max_width(void);
|
||||||
|
void draw_handler_help(WINDOW *win);
|
||||||
|
void invoke_autoruns(WINDOW *w, ToxWindow *self);
|
||||||
|
void cmd_run(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
|
|
||||||
|
#endif /* API_H */
|
1089
src/audio_call.c
1089
src/audio_call.c
File diff suppressed because it is too large
Load Diff
@ -27,9 +27,7 @@
|
|||||||
|
|
||||||
#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,
|
||||||
ae_StartingOutputDevice = 1 << 1,
|
ae_StartingOutputDevice = 1 << 1,
|
||||||
@ -37,7 +35,7 @@ typedef enum _AudioError {
|
|||||||
} AudioError;
|
} AudioError;
|
||||||
|
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
typedef enum _VideoError {
|
typedef enum VideoError {
|
||||||
ve_None = 0,
|
ve_None = 0,
|
||||||
ve_StartingCaptureDevice = 1 << 0,
|
ve_StartingCaptureDevice = 1 << 0,
|
||||||
ve_StartingOutputDevice = 1 << 1,
|
ve_StartingOutputDevice = 1 << 1,
|
||||||
@ -46,14 +44,27 @@ typedef enum _VideoError {
|
|||||||
|
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
|
|
||||||
|
/* Status transitions:
|
||||||
|
* None -> Pending (call invitation made or received);
|
||||||
|
* Pending -> None (invitation rejected or failed);
|
||||||
|
* Pending -> Active (call starts);
|
||||||
|
* Active -> None (call ends).
|
||||||
|
*/
|
||||||
|
typedef enum CallStatus {
|
||||||
|
cs_None = 0,
|
||||||
|
cs_Pending,
|
||||||
|
cs_Active
|
||||||
|
} CallStatus;
|
||||||
|
|
||||||
typedef struct Call {
|
typedef struct Call {
|
||||||
pthread_t ttid; /* Transmission thread id */
|
CallStatus status;
|
||||||
bool ttas, has_output; /* Transmission thread active status (0 - stopped, 1- running) */
|
uint32_t state; /* ToxAV call state, valid when `status == cs_Active` */
|
||||||
uint32_t in_idx, out_idx; /* Audio Index */
|
uint32_t in_idx, out_idx; /* Audio device index, or -1 if not open */
|
||||||
#ifdef VIDEO
|
uint32_t audio_bit_rate; /* Bit rate for sending audio */
|
||||||
uint32_t vin_idx, vout_idx; /* Video Index */
|
|
||||||
#endif /* VIDEO */
|
uint32_t vin_idx, vout_idx; /* Video device index, or -1 if not open */
|
||||||
pthread_mutex_t mutex;
|
uint32_t video_width, video_height;
|
||||||
|
uint32_t video_bit_rate; /* Bit rate for sending video; 0 for no video */
|
||||||
} Call;
|
} Call;
|
||||||
|
|
||||||
struct CallControl {
|
struct CallControl {
|
||||||
@ -65,29 +76,34 @@ struct CallControl {
|
|||||||
ToxAV *av;
|
ToxAV *av;
|
||||||
ToxWindow *prompt;
|
ToxWindow *prompt;
|
||||||
|
|
||||||
Call calls[MAX_CALLS];
|
Call *calls;
|
||||||
uint32_t call_state;
|
uint32_t max_calls;
|
||||||
bool pending_call;
|
|
||||||
bool audio_enabled;
|
bool audio_enabled;
|
||||||
bool video_enabled;
|
bool video_enabled;
|
||||||
|
|
||||||
uint32_t audio_bit_rate;
|
|
||||||
int32_t audio_frame_duration;
|
int32_t audio_frame_duration;
|
||||||
uint32_t audio_sample_rate;
|
uint32_t audio_sample_rate;
|
||||||
uint8_t audio_channels;
|
uint8_t audio_channels;
|
||||||
|
uint32_t default_audio_bit_rate;
|
||||||
|
|
||||||
uint32_t video_bit_rate;
|
|
||||||
int32_t video_frame_duration;
|
int32_t video_frame_duration;
|
||||||
|
uint32_t default_video_width, default_video_height;
|
||||||
|
uint32_t default_video_bit_rate;
|
||||||
|
};
|
||||||
|
|
||||||
} CallControl;
|
extern struct CallControl CallControl;
|
||||||
|
|
||||||
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 stop_transmission(Call *call, uint32_t friend_number);
|
bool init_call(Call *call);
|
||||||
|
|
||||||
|
void place_call(ToxWindow *self);
|
||||||
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 */
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -30,8 +30,9 @@
|
|||||||
#define AUDIO_DEVICE_H
|
#define AUDIO_DEVICE_H
|
||||||
|
|
||||||
#define OPENAL_BUFS 5
|
#define OPENAL_BUFS 5
|
||||||
|
#define MAX_OPENAL_DEVICES 32
|
||||||
#define MAX_DEVICES 32
|
#define MAX_DEVICES 32
|
||||||
#include <inttypes.h>
|
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
|
|
||||||
typedef enum DeviceType {
|
typedef enum DeviceType {
|
||||||
@ -52,40 +53,45 @@ typedef enum DeviceError {
|
|||||||
de_AlError = -9,
|
de_AlError = -9,
|
||||||
} DeviceError;
|
} DeviceError;
|
||||||
|
|
||||||
typedef void (*DataHandleCallback) (const int16_t*, uint32_t size, void* data);
|
typedef void (*DataHandleCallback)(const int16_t *, uint32_t size, void *data);
|
||||||
|
|
||||||
|
|
||||||
#ifdef AUDIO
|
DeviceError init_devices(void);
|
||||||
DeviceError init_devices(ToxAV* av);
|
|
||||||
#else
|
|
||||||
DeviceError init_devices();
|
|
||||||
#endif /* AUDIO */
|
|
||||||
|
|
||||||
DeviceError terminate_devices();
|
void get_al_device_names(void);
|
||||||
|
DeviceError terminate_devices(void);
|
||||||
/* Callback handles ready data from INPUT device */
|
|
||||||
DeviceError register_device_callback(int32_t friend_number, uint32_t device_idx, DataHandleCallback callback, void* data, bool enable_VAD);
|
|
||||||
void* get_device_callback_data(uint32_t device_idx);
|
|
||||||
|
|
||||||
/* toggle device mute */
|
/* toggle device mute */
|
||||||
DeviceError device_mute(DeviceType type, uint32_t device_idx);
|
DeviceError device_mute(DeviceType type, uint32_t device_idx);
|
||||||
|
|
||||||
#ifdef AUDIO
|
bool device_is_muted(DeviceType type, uint32_t device_idx);
|
||||||
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value);
|
|
||||||
#endif
|
DeviceError device_set_VAD_threshold(uint32_t device_idx, float value);
|
||||||
|
|
||||||
|
float device_get_VAD_threshold(uint32_t device_idx);
|
||||||
|
|
||||||
|
DeviceError set_source_position(uint32_t device_idx, float x, float y, float z);
|
||||||
|
|
||||||
|
DeviceError set_al_device(DeviceType type, int32_t selection);
|
||||||
|
|
||||||
DeviceError set_primary_device(DeviceType type, int32_t selection);
|
|
||||||
DeviceError open_primary_device(DeviceType type, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels);
|
|
||||||
/* Start device */
|
/* Start device */
|
||||||
DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels);
|
DeviceError open_input_device(uint32_t *device_idx,
|
||||||
|
DataHandleCallback cb, void *cb_data, bool enable_VAD,
|
||||||
|
uint32_t sample_rate, uint32_t frame_duration, uint8_t channels);
|
||||||
|
DeviceError open_output_device(uint32_t *device_idx,
|
||||||
|
uint32_t sample_rate, uint32_t frame_duration, uint8_t channels);
|
||||||
|
|
||||||
/* Stop device */
|
/* Stop device */
|
||||||
DeviceError close_device(DeviceType type, uint32_t device_idx);
|
DeviceError close_device(DeviceType type, uint32_t device_idx);
|
||||||
|
|
||||||
/* Write data to device */
|
/* Write data to output device */
|
||||||
DeviceError write_out(uint32_t device_idx, const int16_t* data, uint32_t length, uint8_t channels, uint32_t sample_rate);
|
DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_t length, uint8_t channels,
|
||||||
|
uint32_t sample_rate);
|
||||||
|
|
||||||
void print_devices(ToxWindow* self, DeviceType type);
|
/* return current input volume as float in range 0.0-100.0 */
|
||||||
void get_primary_device_name(DeviceType type, char *buf, int size);
|
float get_input_volume(void);
|
||||||
|
|
||||||
|
void print_al_devices(ToxWindow *self, DeviceType type);
|
||||||
|
|
||||||
DeviceError selection_valid(DeviceType type, int32_t selection);
|
DeviceError selection_valid(DeviceType type, int32_t selection);
|
||||||
#endif /* AUDIO_DEVICE_H */
|
#endif /* AUDIO_DEVICE_H */
|
||||||
|
@ -20,36 +20,35 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <limits.h>
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#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 "toxic.h"
|
|
||||||
#include "misc_tools.h"
|
|
||||||
#include "line_info.h"
|
|
||||||
#include "execute.h"
|
|
||||||
#include "configdir.h"
|
#include "configdir.h"
|
||||||
|
#include "execute.h"
|
||||||
|
#include "line_info.h"
|
||||||
|
#include "misc_tools.h"
|
||||||
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
static void print_matches(ToxWindow *self, Tox *m, const void *list, int n_items, int size)
|
static void print_ac_matches(ToxWindow *self, Tox *m, char **list, size_t n_matches)
|
||||||
{
|
{
|
||||||
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;
|
for (size_t i = 0; i < n_matches; ++i) {
|
||||||
int i;
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", list[i]);
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < n_items; ++i)
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", &L[i * size]);
|
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); /* formatting */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* puts match in match buffer. if more than one match, add first n chars that are identical.
|
/* puts match in match buffer. if more than one match, add first n chars that are identical.
|
||||||
@ -57,19 +56,19 @@ static void print_matches(ToxWindow *self, Tox *m, const void *list, int n_items
|
|||||||
*
|
*
|
||||||
* Returns the length of the match.
|
* Returns the length of the match.
|
||||||
*/
|
*/
|
||||||
static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, char (*matches)[MAX_STR_SIZE], int n)
|
static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, const char **matches, size_t n_items,
|
||||||
|
size_t max_size)
|
||||||
{
|
{
|
||||||
if (n == 1) {
|
UNUSED_VAR(self);
|
||||||
|
|
||||||
|
if (n_items == 1) {
|
||||||
return snprintf(match, match_sz, "%s", matches[0]);
|
return snprintf(match, match_sz, "%s", matches[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
int i;
|
for (size_t i = 0; i < max_size; ++i) {
|
||||||
|
|
||||||
for (i = 0; i < MAX_STR_SIZE; ++i) {
|
|
||||||
char ch1 = matches[0][i];
|
char ch1 = matches[0][i];
|
||||||
int j;
|
|
||||||
|
|
||||||
for (j = 0; j < n; ++j) {
|
for (size_t j = 0; j < n_items; ++j) {
|
||||||
char ch2 = matches[j][i];
|
char ch2 = matches[j][i];
|
||||||
|
|
||||||
if (ch1 != ch2 || !ch1) {
|
if (ch1 != ch2 || !ch1) {
|
||||||
@ -83,49 +82,58 @@ 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 `n_items` strings. Each string in the list must be <= MAX_STR_SIZE.
|
||||||
|
*
|
||||||
Returns the difference between the old len and new len of line on success, -1 if error */
|
* dir_search should be true if the line being completed is a file path.
|
||||||
int complete_line(ToxWindow *self, const void *list, int n_items, int size)
|
*
|
||||||
|
* 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 char **list, const size_t n_items, 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->len >= MAX_STR_SIZE) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
const char *L = (char *) list;
|
|
||||||
const char *endchrs = " ";
|
const char *endchrs = " ";
|
||||||
char ubuf[MAX_STR_SIZE];
|
char ubuf[MAX_STR_SIZE];
|
||||||
|
|
||||||
/* 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"));
|
|
||||||
|
|
||||||
/* 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);
|
memcpy(tmp, ubuf, ctx->pos);
|
||||||
tmp[ctx->pos] = '\0';
|
tmp[ctx->pos] = 0;
|
||||||
|
|
||||||
const char *s = dir_search ? strchr(tmp, '\"') : strrchr(tmp, ' ');
|
const char *s = dir_search ? strchr(tmp, ' ') : 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]);
|
||||||
|
|
||||||
@ -133,50 +141,60 @@ 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] && !(dir_search && n_items == 1)) {
|
||||||
|
free(sub);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int s_len = strlen(sub);
|
||||||
|
size_t n_matches = 0;
|
||||||
|
|
||||||
|
char **matches = (char **) malloc_ptr_array(n_items, MAX_STR_SIZE);
|
||||||
|
|
||||||
|
if (matches == NULL) {
|
||||||
free(sub);
|
free(sub);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int s_len = strlen(sub);
|
|
||||||
int n_matches = 0;
|
|
||||||
char matches[n_items][MAX_STR_SIZE];
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
/* put all list matches in matches array */
|
/* put all list matches in matches array */
|
||||||
for (i = 0; i < n_items; ++i) {
|
for (size_t i = 0; i < n_items; ++i) {
|
||||||
char str[MAX_CMDNAME_SIZE + 1];
|
if (strncasecmp(list[i], sub, s_len) == 0) {
|
||||||
snprintf(str, sizeof(str), "%s", &L[i * size]);
|
snprintf(matches[n_matches++], MAX_STR_SIZE, "%s", list[i]);
|
||||||
|
}
|
||||||
if (strncasecmp(str, sub, s_len) == 0)
|
|
||||||
strcpy(matches[n_matches++], str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(sub);
|
free(sub);
|
||||||
|
|
||||||
if (!n_matches)
|
if (!n_matches) {
|
||||||
|
free_ptr_array((void **) 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_ac_matches(self, NULL, matches, n_matches);
|
||||||
|
}
|
||||||
|
|
||||||
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), (const char **) matches, n_matches, MAX_STR_SIZE);
|
||||||
|
|
||||||
|
free_ptr_array((void **) matches);
|
||||||
|
|
||||||
if (match_len == 0) {
|
if (match_len == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 = "";
|
||||||
}
|
}
|
||||||
@ -185,8 +203,10 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
|
|||||||
int n_endchrs = strlen(endchrs);
|
int n_endchrs = strlen(endchrs);
|
||||||
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]);
|
||||||
@ -196,6 +216,31 @@ 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) {
|
||||||
|
path_start = strchr(ubuf + 1, ' ');
|
||||||
|
|
||||||
|
if (!path_start) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(path_start) < 2) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
++path_start;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
@ -214,54 +259,82 @@ 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 char **list, size_t n_items)
|
||||||
static void complt_home_dir(ToxWindow *self, char *path, int pathsize, const char *cmd, int cmdlen)
|
{
|
||||||
|
return complete_line_helper(self, list, n_items, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int complete_path(ToxWindow *self, const char **list, const size_t n_items)
|
||||||
|
{
|
||||||
|
return complete_line_helper(self, list, n_items, 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;
|
||||||
|
|
||||||
char homedir[MAX_STR_SIZE] = {0};
|
char homedir[MAX_STR_SIZE] = {0};
|
||||||
get_home_dir(homedir, sizeof(homedir));
|
get_home_dir(homedir, sizeof(homedir));
|
||||||
|
|
||||||
char newline[MAX_STR_SIZE];
|
char newline[MAX_STR_SIZE + 1];
|
||||||
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.
|
/*
|
||||||
|
* Return true if the first `p_len` chars in `s` are equal to `p` and `s` is a valid directory name.
|
||||||
|
*/
|
||||||
|
static bool is_partial_match(const char *s, const char *p, size_t p_len)
|
||||||
|
{
|
||||||
|
if (s == NULL || p == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if only one match, auto-complete line.
|
return strncmp(s, p, p_len) == 0 && strcmp(".", s) != 0 && strcmp("..", s) != 0;
|
||||||
return diff between old len and new len of ctx->line, -1 if no matches or > 1 match */
|
}
|
||||||
#define MAX_DIRS 512
|
|
||||||
|
|
||||||
|
/* Attempts to match /command "<incomplete-dir>" line to matching directories.
|
||||||
|
* If there is only one match the line is auto-completed.
|
||||||
|
*
|
||||||
|
* 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 75
|
||||||
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 + 1];
|
||||||
char b_name[MAX_STR_SIZE];
|
char b_name[MAX_STR_SIZE + 1];
|
||||||
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) == -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) - 1, b_cmd, strlen(b_cmd) + 2);
|
||||||
|
}
|
||||||
|
|
||||||
int si = char_rfind(b_path, '/', strlen(b_path));
|
int si = char_rfind(b_path, '/', strlen(b_path));
|
||||||
|
|
||||||
@ -269,40 +342,52 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
|
|||||||
b_path[0] = '.';
|
b_path[0] = '.';
|
||||||
b_path[1] = '\0';
|
b_path[1] = '\0';
|
||||||
} else if (!si && b_path[0] != '/') { /* look for matches in pwd */
|
} else if (!si && b_path[0] != '/') { /* look for matches in pwd */
|
||||||
char tmp[MAX_STR_SIZE];
|
memmove(b_path + 1, b_path, sizeof(b_path) - 1);
|
||||||
snprintf(tmp, sizeof(tmp), ".%s", b_path);
|
b_path[0] = '.';
|
||||||
snprintf(b_path, sizeof(b_path), "%s", tmp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(b_name, sizeof(b_name), "%s", &b_path[si + 1]);
|
snprintf(b_name, sizeof(b_name), "%s", &b_path[si + 1]);
|
||||||
b_path[si + 1] = '\0';
|
b_path[si + 1] = '\0';
|
||||||
int b_name_len = strlen(b_name);
|
size_t 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 = (char **) malloc_ptr_array(MAX_DIRS, NAME_MAX + 1);
|
||||||
|
|
||||||
|
if (dirnames == NULL) {
|
||||||
|
closedir(dp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
char dirnames[MAX_DIRS][NAME_MAX];
|
|
||||||
struct dirent *entry;
|
struct dirent *entry;
|
||||||
|
|
||||||
int dircount = 0;
|
int dircount = 0;
|
||||||
|
|
||||||
while ((entry = readdir(dp)) && dircount < MAX_DIRS) {
|
while ((entry = readdir(dp)) && dircount < MAX_DIRS) {
|
||||||
if (strncmp(entry->d_name, b_name, b_name_len) == 0
|
if (is_partial_match(entry->d_name, b_name, b_name_len)) {
|
||||||
&& strcmp(".", entry->d_name) && strcmp("..", entry->d_name)) {
|
snprintf(dirnames[dircount], NAME_MAX + 1, "%s", entry->d_name);
|
||||||
snprintf(dirnames[dircount], sizeof(dirnames[dircount]), "%s", entry->d_name);
|
|
||||||
++dircount;
|
++dircount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir(dp);
|
closedir(dp);
|
||||||
|
|
||||||
if (dircount == 0)
|
if (dircount == 0) {
|
||||||
|
free_ptr_array((void **) dirnames);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (dircount > 1) {
|
|
||||||
qsort(dirnames, dircount, NAME_MAX, qsort_strcasecmp_hlpr);
|
|
||||||
print_matches(self, m, dirnames, dircount, NAME_MAX);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return complete_line(self, dirnames, dircount, NAME_MAX);
|
if (dircount > 1) {
|
||||||
|
qsort(dirnames, dircount, sizeof(char *), qsort_ptr_char_array_helper);
|
||||||
|
print_ac_matches(self, m, dirnames, dircount);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = complete_path(self, (const char **) dirnames, dircount);
|
||||||
|
|
||||||
|
free_ptr_array((void **) dirnames);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -23,20 +23,30 @@
|
|||||||
#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,
|
#include "windows.h"
|
||||||
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.
|
* 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
|
||||||
|
* with "Hello john". If multiple matches, prints out all the matches and semi-completes line.
|
||||||
|
*
|
||||||
|
* `list` is a pointer to `n_items` strings.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
int complete_line(ToxWindow *self, const char **list, size_t n_items);
|
||||||
|
|
||||||
Returns the difference between the old len and new len of line on success, -1 if error */
|
/* Attempts to match /command "<incomplete-dir>" line to matching directories.
|
||||||
int complete_line(ToxWindow *self, const void *list, int n_items, int size);
|
* If there is only one match the line is auto-completed.
|
||||||
|
*
|
||||||
/* attempts to match /command "<incomplete-dir>" line to matching directories.
|
* Returns the diff between old len and new len of ctx->line on success.
|
||||||
|
* Returns -1 if no matches or more than one match.
|
||||||
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 */
|
||||||
|
119
src/avatars.c
119
src/avatars.c
@ -20,14 +20,14 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "misc_tools.h"
|
#include "avatars.h"
|
||||||
#include "file_transfers.h"
|
#include "file_transfers.h"
|
||||||
#include "friendlist.h"
|
#include "friendlist.h"
|
||||||
#include "avatars.h"
|
#include "misc_tools.h"
|
||||||
|
|
||||||
extern FriendsList Friends;
|
extern FriendsList Friends;
|
||||||
|
|
||||||
@ -39,39 +39,76 @@ static struct Avatar {
|
|||||||
off_t size;
|
off_t size;
|
||||||
} Avatar;
|
} Avatar;
|
||||||
|
|
||||||
|
/* Compares the first size bytes of fp to signature.
|
||||||
|
*
|
||||||
|
* Returns 0 if they are the same
|
||||||
|
* Returns 1 if they differ
|
||||||
|
* Returns -1 on error.
|
||||||
|
*
|
||||||
|
* On success this function will seek back to the beginning of fp.
|
||||||
|
*/
|
||||||
|
static int check_file_signature(const unsigned char *signature, size_t size, FILE *fp)
|
||||||
|
{
|
||||||
|
char *buf = malloc(size);
|
||||||
|
|
||||||
|
if (buf == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fread(buf, size, 1, fp) != 1) {
|
||||||
|
free(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = memcmp(signature, buf, size);
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
if (fseek(fp, 0L, SEEK_SET) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret == 0 ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void avatar_clear(void)
|
static void avatar_clear(void)
|
||||||
{
|
{
|
||||||
memset(&Avatar, 0, sizeof(struct Avatar));
|
Avatar = (struct Avatar) {
|
||||||
|
0
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sends avatar to friendnum.
|
/* Sends avatar to friendnumber.
|
||||||
*
|
*
|
||||||
* Returns 0 on success.
|
* Returns 0 on success.
|
||||||
* Returns -1 on failure.
|
* Returns -1 on failure.
|
||||||
*/
|
*/
|
||||||
int avatar_send(Tox *m, uint32_t friendnum)
|
int avatar_send(Tox *m, uint32_t friendnumber)
|
||||||
{
|
{
|
||||||
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 filenumber = tox_file_send(m, friendnumber, 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 %u (error %d)\n", friendnumber, err);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FileTransfer *ft = new_file_transfer(NULL, friendnum, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_AVATAR);
|
struct FileTransfer *ft = new_file_transfer(NULL, friendnumber, filenumber, 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;
|
||||||
@ -82,11 +119,10 @@ int avatar_send(Tox *m, uint32_t friendnum)
|
|||||||
/* Sends avatar to all friends */
|
/* Sends avatar to all friends */
|
||||||
static void avatar_send_all(Tox *m)
|
static void avatar_send_all(Tox *m)
|
||||||
{
|
{
|
||||||
size_t i;
|
for (size_t i = 0; i < Friends.max_idx; ++i) {
|
||||||
|
if (Friends.list[i].connection_status != TOX_CONNECTION_NONE) {
|
||||||
for (i = 0; i < Friends.max_idx; ++i) {
|
|
||||||
if (Friends.list[i].connection_status != TOX_CONNECTION_NONE)
|
|
||||||
avatar_send(m, Friends.list[i].num);
|
avatar_send(m, Friends.list[i].num);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,15 +133,17 @@ 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};
|
unsigned char PNG_signature[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
|
||||||
|
|
||||||
if (check_file_signature(PNG_signature, sizeof(PNG_signature), fp) != 0) {
|
if (check_file_signature(PNG_signature, sizeof(PNG_signature), fp) != 0) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
@ -116,8 +154,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);
|
||||||
@ -141,7 +180,14 @@ 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_friend_connection_status(Tox *m, uint32_t friendnumber, Tox_Connection connection_status)
|
||||||
|
{
|
||||||
|
if (connection_status == TOX_CONNECTION_NONE) {
|
||||||
|
kill_avatar_file_transfers_friend(m, friendnumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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:
|
||||||
@ -150,6 +196,7 @@ void on_avatar_file_control(Tox *m, struct FileTransfer *ft, TOX_FILE_CONTROL co
|
|||||||
} else if (ft->state == FILE_TRANSFER_PAUSED) {
|
} else if (ft->state == FILE_TRANSFER_PAUSED) {
|
||||||
ft->state = FILE_TRANSFER_STARTED;
|
ft->state = FILE_TRANSFER_STARTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_FILE_CONTROL_PAUSE:
|
case TOX_FILE_CONTROL_PAUSE:
|
||||||
@ -164,8 +211,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);
|
||||||
@ -186,20 +234,29 @@ void on_avatar_chunk_request(Tox *m, struct FileTransfer *ft, uint64_t position,
|
|||||||
ft->position = position;
|
ft->position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t send_data[length];
|
uint8_t *send_data = malloc(length);
|
||||||
size_t send_length = fread(send_data, 1, sizeof(send_data), ft->file);
|
|
||||||
|
|
||||||
if (send_length != length) {
|
if (send_data == NULL) {
|
||||||
close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent);
|
close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TOX_ERR_FILE_SEND_CHUNK err;
|
size_t send_length = fread(send_data, 1, length, ft->file);
|
||||||
tox_file_send_chunk(m, ft->friendnum, ft->filenum, position, send_data, send_length, &err);
|
|
||||||
|
|
||||||
if (err != TOX_ERR_FILE_SEND_CHUNK_OK)
|
if (send_length != length) {
|
||||||
|
close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent);
|
||||||
|
free(send_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tox_Err_File_Send_Chunk err;
|
||||||
|
tox_file_send_chunk(m, ft->friendnumber, ft->filenumber, position, send_data, send_length, &err);
|
||||||
|
|
||||||
|
free(send_data);
|
||||||
|
|
||||||
|
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();
|
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
#ifndef AVATARS_H
|
#ifndef AVATARS_H
|
||||||
#define AVATARS_H
|
#define AVATARS_H
|
||||||
|
|
||||||
|
#include "file_transfers.h"
|
||||||
|
|
||||||
#define MAX_AVATAR_FILE_SIZE 65536
|
#define MAX_AVATAR_FILE_SIZE 65536
|
||||||
|
|
||||||
/* Sends avatar to friendnum.
|
/* Sends avatar to friendnum.
|
||||||
@ -47,6 +49,7 @@ 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);
|
||||||
|
void on_avatar_friend_connection_status(Tox *m, uint32_t friendnumber, Tox_Connection connection_status);
|
||||||
|
|
||||||
#endif /* AVATARS_H */
|
#endif /* AVATARS_H */
|
||||||
|
@ -20,20 +20,24 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdbool.h>
|
#include <sys/socket.h>
|
||||||
#include <limits.h>
|
|
||||||
|
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
#include <tox/tox.h>
|
#include <tox/tox.h>
|
||||||
|
|
||||||
#include "line_info.h"
|
|
||||||
#include "windows.h"
|
|
||||||
#include "misc_tools.h"
|
|
||||||
#include "configdir.h"
|
#include "configdir.h"
|
||||||
#include "curl_util.h"
|
#include "curl_util.h"
|
||||||
|
#include "line_info.h"
|
||||||
|
#include "misc_tools.h"
|
||||||
|
#include "prompt.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "windows.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;
|
||||||
@ -104,11 +108,45 @@ static struct DHT_Nodes {
|
|||||||
time_t last_updated;
|
time_t last_updated;
|
||||||
} Nodes;
|
} Nodes;
|
||||||
|
|
||||||
|
/* Return true if address appears to be a valid ipv4 address. */
|
||||||
|
static bool is_ip4_address(const char *address)
|
||||||
|
{
|
||||||
|
struct sockaddr_in s_addr;
|
||||||
|
return inet_pton(AF_INET, address, &(s_addr.sin_addr)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if address roughly appears to be a valid ipv6 address.
|
||||||
|
*
|
||||||
|
* TODO: Improve this function (inet_pton behaves strangely with ipv6).
|
||||||
|
* for now the only guarantee is that it won't return true if the
|
||||||
|
* address is a domain or ipv4 address, and should only be used if you're
|
||||||
|
* reasonably sure that the address is one of the three (ipv4, ipv6 or a domain).
|
||||||
|
*/
|
||||||
|
static bool is_ip6_address(const char *address)
|
||||||
|
{
|
||||||
|
size_t num_colons = 0;
|
||||||
|
char ch = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; (ch = address[i]); ++i) {
|
||||||
|
if (ch == '.') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch == ':') {
|
||||||
|
++num_colons;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return num_colons > 1 && num_colons < 8;
|
||||||
|
}
|
||||||
|
|
||||||
/* 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,
|
||||||
@ -237,6 +275,7 @@ on_exit:
|
|||||||
* Return -2 if http lookup failed.
|
* Return -2 if http lookup failed.
|
||||||
* Return -3 if http reponse was empty.
|
* Return -3 if http reponse was empty.
|
||||||
* Return -4 if data could not be written to disk.
|
* Return -4 if data could not be written to disk.
|
||||||
|
* Return -5 if memory allocation fails.
|
||||||
*/
|
*/
|
||||||
static int update_DHT_nodeslist(const char *nodes_path)
|
static int update_DHT_nodeslist(const char *nodes_path)
|
||||||
{
|
{
|
||||||
@ -250,25 +289,34 @@ static int update_DHT_nodeslist(const char *nodes_path)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Recv_Curl_Data recv_data;
|
struct Recv_Curl_Data *recv_data = calloc(1, sizeof(struct Recv_Curl_Data));
|
||||||
memset(&recv_data, 0, sizeof(struct Recv_Curl_Data));
|
|
||||||
|
|
||||||
if (curl_fetch_nodes_JSON(&recv_data) == -1) {
|
if (recv_data == NULL) {
|
||||||
|
fclose(fp);
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curl_fetch_nodes_JSON(recv_data) == -1) {
|
||||||
|
free(recv_data);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recv_data.length == 0) {
|
if (recv_data->length == 0) {
|
||||||
|
free(recv_data);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fwrite(recv_data.data, recv_data.length, 1, fp) != 1) {
|
if (fwrite(recv_data->data, recv_data->length, 1, fp) != 1) {
|
||||||
|
free(recv_data);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return -4;
|
return -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(recv_data);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,7 +424,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -425,6 +473,8 @@ static int extract_node(const char *line, struct Node *node)
|
|||||||
/* Loads the DHT nodeslist to memory from json encoded nodes file. */
|
/* Loads the DHT nodeslist to memory from json encoded nodes file. */
|
||||||
void *load_nodeslist_thread(void *data)
|
void *load_nodeslist_thread(void *data)
|
||||||
{
|
{
|
||||||
|
UNUSED_VAR(data);
|
||||||
|
|
||||||
char nodes_path[PATH_MAX];
|
char nodes_path[PATH_MAX];
|
||||||
get_nodeslist_path(nodes_path, sizeof(nodes_path));
|
get_nodeslist_path(nodes_path, sizeof(nodes_path));
|
||||||
|
|
||||||
@ -476,7 +526,7 @@ void *load_nodeslist_thread(void *data)
|
|||||||
/* If nodeslist does not contain any valid entries we set the last_scan value
|
/* If nodeslist does not contain any valid entries we set the last_scan value
|
||||||
* to 0 so that it will fetch a new list the next time this function is called.
|
* to 0 so that it will fetch a new list the next time this function is called.
|
||||||
*/
|
*/
|
||||||
if (idx == 0) {
|
if (Nodes.count == 0) {
|
||||||
const char *s = "{\"last_scan\":0}";
|
const char *s = "{\"last_scan\":0}";
|
||||||
rewind(fp);
|
rewind(fp);
|
||||||
fwrite(s, strlen(s), 1, fp); // Not much we can do if it fails
|
fwrite(s, strlen(s), 1, fp); // Not much we can do if it fails
|
||||||
@ -523,6 +573,7 @@ int load_DHT_nodeslist(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
thread_data.active = true;
|
thread_data.active = true;
|
||||||
|
|
||||||
if (pthread_create(&thread_data.tid, &thread_data.attr, load_nodeslist_thread, NULL) != 0) {
|
if (pthread_create(&thread_data.tid, &thread_data.attr, load_nodeslist_thread, NULL) != 0) {
|
||||||
thread_data.active = false;
|
thread_data.active = false;
|
||||||
return -5;
|
return -5;
|
||||||
@ -554,7 +605,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) {
|
||||||
@ -575,7 +626,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);
|
||||||
|
@ -39,4 +39,4 @@ void do_tox_connection(Tox *m);
|
|||||||
*/
|
*/
|
||||||
int load_DHT_nodeslist(void);
|
int load_DHT_nodeslist(void);
|
||||||
|
|
||||||
#endif /* BOOTSTRAP_H */
|
#endif /* BOOTSTRAP_H */
|
||||||
|
879
src/chat.c
879
src/chat.c
File diff suppressed because it is too large
Load Diff
@ -23,13 +23,13 @@
|
|||||||
#ifndef CHAT_H
|
#ifndef CHAT_H
|
||||||
#define CHAT_H
|
#define CHAT_H
|
||||||
|
|
||||||
#include "windows.h"
|
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
/* set CTRL to -1 if we don't want to send a control signal.
|
/* set CTRL to -1 if we don't want to send a control signal.
|
||||||
set msg to NULL if we don't want to display a message */
|
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 */
|
||||||
|
@ -23,21 +23,23 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "chat.h"
|
||||||
|
#include "conference.h"
|
||||||
|
#include "execute.h"
|
||||||
|
#include "file_transfers.h"
|
||||||
|
#include "friendlist.h"
|
||||||
|
#include "line_info.h"
|
||||||
|
#include "misc_tools.h"
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#include "misc_tools.h"
|
|
||||||
#include "friendlist.h"
|
|
||||||
#include "execute.h"
|
|
||||||
#include "line_info.h"
|
|
||||||
#include "groupchat.h"
|
|
||||||
#include "chat.h"
|
|
||||||
#include "file_transfers.h"
|
|
||||||
|
|
||||||
extern ToxWindow *prompt;
|
extern ToxWindow *prompt;
|
||||||
extern FriendsList Friends;
|
extern FriendsList Friends;
|
||||||
|
|
||||||
void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
|
UNUSED_VAR(window);
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Requires type in|out and the file ID.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Requires type in|out and the file ID.");
|
||||||
return;
|
return;
|
||||||
@ -78,69 +80,102 @@ void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
|
|||||||
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, silent);
|
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, silent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_conference_invite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
|
UNUSED_VAR(window);
|
||||||
|
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group number required.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Conference number required.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
long int groupnum = strtol(argv[1], NULL, 10);
|
long int conferencenum = strtol(argv[1], NULL, 10);
|
||||||
|
|
||||||
if ((groupnum == 0 && strcmp(argv[1], "0")) || groupnum < 0 || groupnum == LONG_MAX) {
|
if ((conferencenum == 0 && strcmp(argv[1], "0")) || conferencenum < 0 || conferencenum == LONG_MAX) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid group number.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid conference number.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tox_invite_friend(m, self->num, groupnum) == -1) {
|
Tox_Err_Conference_Invite err;
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to group.");
|
|
||||||
|
if (!tox_conference_invite(m, self->num, conferencenum, &err)) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to conference (error %d)", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invited contact to Group %d.", groupnum);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invited contact to Conference %ld.", conferencenum);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_join_group(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_conference_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
|
UNUSED_VAR(window);
|
||||||
|
UNUSED_VAR(argc);
|
||||||
|
UNUSED_VAR(argv);
|
||||||
|
|
||||||
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
|
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *groupkey = Friends.list[self->num].group_invite.key;
|
const char *conferencekey = Friends.list[self->num].conference_invite.key;
|
||||||
uint16_t length = Friends.list[self->num].group_invite.length;
|
uint16_t length = Friends.list[self->num].conference_invite.length;
|
||||||
uint8_t type = Friends.list[self->num].group_invite.type;
|
uint8_t type = Friends.list[self->num].conference_invite.type;
|
||||||
|
|
||||||
if (!Friends.list[self->num].group_invite.pending) {
|
if (!Friends.list[self->num].conference_invite.pending) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending group chat invite.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending conference invite.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int groupnum = -1;
|
uint32_t conferencenum;
|
||||||
|
|
||||||
if (type == TOX_GROUPCHAT_TYPE_TEXT)
|
if (type == TOX_CONFERENCE_TYPE_TEXT) {
|
||||||
groupnum = tox_join_groupchat(m, self->num, (uint8_t *) groupkey, length);
|
Tox_Err_Conference_Join err;
|
||||||
/*#ifdef AUDIO
|
conferencenum = tox_conference_join(m, self->num, (const uint8_t *) conferencekey, length, &err);
|
||||||
else
|
|
||||||
groupnum = toxav_join_av_groupchat(m, self->num, (uint8_t *) groupkey, length,
|
|
||||||
NULL, NULL);
|
|
||||||
#endif*/
|
|
||||||
|
|
||||||
if (groupnum == -1) {
|
if (err != TOX_ERR_CONFERENCE_JOIN_OK) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Conference instance failed to initialize (error %d)", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (type == TOX_CONFERENCE_TYPE_AV) {
|
||||||
|
#ifdef AUDIO
|
||||||
|
conferencenum = toxav_join_av_groupchat(m, self->num, (const uint8_t *) conferencekey, length,
|
||||||
|
audio_conference_callback, NULL);
|
||||||
|
|
||||||
|
if (conferencenum == (uint32_t) -1) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio conference instance failed to initialize");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio support disabled by compile-time option.");
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Unknown conference type %d", type);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (init_groupchat_win(prompt, m, groupnum, type) == -1) {
|
if (init_conference_win(m, conferencenum, type, NULL, 0) == -1) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Conference window failed to initialize.");
|
||||||
tox_del_groupchat(m, groupnum);
|
tox_conference_delete(m, conferencenum, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
|
|
||||||
|
if (type == TOX_CONFERENCE_TYPE_AV) {
|
||||||
|
if (!init_conference_audio_input(m, conferencenum)) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio capture failed; use \"/audio on\" to try again.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
|
UNUSED_VAR(window);
|
||||||
|
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File ID required.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File ID required.");
|
||||||
return;
|
return;
|
||||||
@ -166,18 +201,19 @@ 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->filenumber, 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 [%ld] as: '%s'", idx, ft->file_path);
|
||||||
|
|
||||||
/* prep progress bar line */
|
/* prep progress bar line */
|
||||||
char progline[MAX_STR_SIZE];
|
char progline[MAX_STR_SIZE];
|
||||||
@ -190,6 +226,7 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
on_recv_error:
|
on_recv_error:
|
||||||
|
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND:
|
case TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND:
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend not found.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend not found.");
|
||||||
@ -215,6 +252,8 @@ on_recv_error:
|
|||||||
|
|
||||||
void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
|
UNUSED_VAR(window);
|
||||||
|
|
||||||
const char *errmsg = NULL;
|
const char *errmsg = NULL;
|
||||||
|
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
@ -222,16 +261,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.");
|
||||||
@ -256,12 +288,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);
|
||||||
|
|
||||||
@ -282,6 +315,7 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
on_send_error:
|
on_send_error:
|
||||||
|
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND:
|
case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND:
|
||||||
errmsg = "File transfer failed: Invalid friend.";
|
errmsg = "File transfer failed: Invalid friend.";
|
||||||
|
@ -23,12 +23,12 @@
|
|||||||
#ifndef CHAT_COMMANDS_H
|
#ifndef CHAT_COMMANDS_H
|
||||||
#define CHAT_COMMANDS_H
|
#define CHAT_COMMANDS_H
|
||||||
|
|
||||||
#include "windows.h"
|
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
void cmd_groupinvite(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_conference_invite(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
void cmd_join_group(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_conference_join(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
void cmd_savefile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_savefile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
void cmd_sendfile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_sendfile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
|
|
||||||
@ -41,11 +41,13 @@ void cmd_cancel(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZ
|
|||||||
void cmd_ccur_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_ccur_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
void cmd_mute(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_mute(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
void cmd_sense(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_sense(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
|
void cmd_bitrate(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
|
void cmd_vcall(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
void cmd_video(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
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_res(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
|
|
||||||
#endif /* #define CHAT_COMMANDS_H */
|
#endif /* CHAT_COMMANDS_H */
|
||||||
|
1388
src/conference.c
Normal file
1388
src/conference.c
Normal file
File diff suppressed because it is too large
Load Diff
120
src/conference.h
Normal file
120
src/conference.h
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
/* conference.h
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Toxic All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This file is part of Toxic.
|
||||||
|
*
|
||||||
|
* Toxic is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Toxic is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CONFERENCE_H
|
||||||
|
#define CONFERENCE_H
|
||||||
|
|
||||||
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
|
#define SIDEBAR_WIDTH 16
|
||||||
|
#define MAX_CONFERENCE_NUM (MAX_WINDOWS_NUM - 2)
|
||||||
|
#define CONFERENCE_EVENT_WAIT 3
|
||||||
|
#define CONFERENCE_MAX_TITLE_LENGTH TOX_MAX_NAME_LENGTH
|
||||||
|
|
||||||
|
typedef struct ConferencePeer {
|
||||||
|
bool active;
|
||||||
|
|
||||||
|
uint8_t pubkey[TOX_PUBLIC_KEY_SIZE];
|
||||||
|
uint32_t peernum; /* index in chat->peer_list */
|
||||||
|
|
||||||
|
char name[TOX_MAX_NAME_LENGTH];
|
||||||
|
size_t name_length;
|
||||||
|
|
||||||
|
bool sending_audio;
|
||||||
|
uint32_t audio_out_idx;
|
||||||
|
time_t last_audio_time;
|
||||||
|
} ConferencePeer;
|
||||||
|
|
||||||
|
typedef struct AudioInputCallbackData {
|
||||||
|
Tox *tox;
|
||||||
|
uint32_t conferencenum;
|
||||||
|
} AudioInputCallbackData;
|
||||||
|
|
||||||
|
#define PUBKEY_STRING_SIZE (2 * TOX_PUBLIC_KEY_SIZE + 1)
|
||||||
|
typedef struct NameListEntry {
|
||||||
|
char name[TOX_MAX_NAME_LENGTH];
|
||||||
|
char pubkey_str[PUBKEY_STRING_SIZE];
|
||||||
|
uint32_t peernum;
|
||||||
|
} NameListEntry;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int chatwin;
|
||||||
|
bool active;
|
||||||
|
uint8_t type;
|
||||||
|
int side_pos; /* current position of the sidebar - used for scrolling up and down */
|
||||||
|
time_t start_time;
|
||||||
|
|
||||||
|
char title[CONFERENCE_MAX_TITLE_LENGTH + 1];
|
||||||
|
size_t title_length;
|
||||||
|
|
||||||
|
ConferencePeer *peer_list;
|
||||||
|
uint32_t max_idx;
|
||||||
|
|
||||||
|
NameListEntry *name_list;
|
||||||
|
uint32_t num_peers;
|
||||||
|
|
||||||
|
bool push_to_talk_enabled;
|
||||||
|
time_t ptt_last_pushed;
|
||||||
|
|
||||||
|
bool audio_enabled;
|
||||||
|
time_t last_sent_audio;
|
||||||
|
uint32_t audio_in_idx;
|
||||||
|
AudioInputCallbackData audio_input_callback_data;
|
||||||
|
} ConferenceChat;
|
||||||
|
|
||||||
|
/* Frees all Toxic associated data structures for a conference (does not call tox_conference_delete() ) */
|
||||||
|
void free_conference(ToxWindow *self, uint32_t conferencenum);
|
||||||
|
|
||||||
|
int init_conference_win(Tox *m, uint32_t conferencenum, uint8_t type, const char *title, size_t length);
|
||||||
|
|
||||||
|
/* destroys and re-creates conference window with or without the peerlist */
|
||||||
|
void redraw_conference_win(ToxWindow *self);
|
||||||
|
|
||||||
|
void conference_set_title(ToxWindow *self, uint32_t conferencesnum, const char *title, size_t length);
|
||||||
|
void conference_rename_log_path(Tox *m, uint32_t conferencenum, const char *new_title);
|
||||||
|
int conference_enable_logging(ToxWindow *self, Tox *m, uint32_t conferencenum, struct chatlog *log);
|
||||||
|
|
||||||
|
/* Puts `(NameListEntry *)`s in `entries` for each matched peer, up to a maximum
|
||||||
|
* of `maxpeers`.
|
||||||
|
* Maches each peer whose name or pubkey begins with `prefix`.
|
||||||
|
* If `prefix` is exactly the pubkey of a peer, matches only that peer.
|
||||||
|
* return number of entries placed in `entries`.
|
||||||
|
*/
|
||||||
|
uint32_t get_name_list_entries_by_prefix(uint32_t conferencenum, const char *prefix, NameListEntry **entries,
|
||||||
|
uint32_t maxpeers);
|
||||||
|
|
||||||
|
bool init_conference_audio_input(Tox *tox, uint32_t conferencenum);
|
||||||
|
bool enable_conference_audio(Tox *tox, uint32_t conferencenum);
|
||||||
|
bool disable_conference_audio(Tox *tox, uint32_t conferencenum);
|
||||||
|
bool toggle_conference_push_to_talk(uint32_t conferencenum, bool enabled);
|
||||||
|
void audio_conference_callback(void *tox, uint32_t conferencenum, uint32_t peernum,
|
||||||
|
const int16_t *pcm, unsigned int samples, uint8_t channels, uint32_t
|
||||||
|
sample_rate, void *userdata);
|
||||||
|
|
||||||
|
bool conference_mute_self(uint32_t conferencenum);
|
||||||
|
bool conference_mute_peer(const Tox *m, uint32_t conferencenum, uint32_t peernum);
|
||||||
|
bool conference_set_VAD_threshold(uint32_t conferencenum, float threshold);
|
||||||
|
float conference_get_VAD_threshold(uint32_t conferencenum);
|
||||||
|
|
||||||
|
#endif /* CONFERENCE_H */
|
213
src/conference_commands.c
Normal file
213
src/conference_commands.c
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
/* conference_commands.c
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Toxic All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This file is part of Toxic.
|
||||||
|
*
|
||||||
|
* Toxic is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Toxic is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "conference.h"
|
||||||
|
#include "line_info.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "misc_tools.h"
|
||||||
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
|
static void print_err(ToxWindow *self, const char *error_str)
|
||||||
|
{
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", error_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
|
{
|
||||||
|
UNUSED_VAR(window);
|
||||||
|
|
||||||
|
Tox_Err_Conference_Title err;
|
||||||
|
char title[CONFERENCE_MAX_TITLE_LENGTH + 1];
|
||||||
|
|
||||||
|
if (argc < 1) {
|
||||||
|
size_t tlen = tox_conference_get_title_size(m, self->num, &err);
|
||||||
|
|
||||||
|
if (err != TOX_ERR_CONFERENCE_TITLE_OK || tlen >= sizeof(title)) {
|
||||||
|
print_err(self, "Title is not set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tox_conference_get_title(m, self->num, (uint8_t *) title, &err)) {
|
||||||
|
print_err(self, "Title is not set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
title[tlen] = '\0';
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title is set to: %s", title);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t len = strlen(argv[1]);
|
||||||
|
|
||||||
|
if (len >= sizeof(title)) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title: max length exceeded.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(title, sizeof(title), "%s", argv[1]);
|
||||||
|
|
||||||
|
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);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
conference_rename_log_path(m, self->num, title); // must be called first
|
||||||
|
|
||||||
|
conference_set_title(self, self->num, title, len);
|
||||||
|
|
||||||
|
char timefrmt[TIME_STR_SIZE];
|
||||||
|
char selfnick[TOX_MAX_NAME_LENGTH];
|
||||||
|
|
||||||
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
|
|
||||||
|
tox_self_get_name(m, (uint8_t *) selfnick);
|
||||||
|
size_t sn_len = tox_self_get_name_size(m);
|
||||||
|
selfnick[sn_len] = '\0';
|
||||||
|
|
||||||
|
line_info_add(self, timefrmt, selfnick, NULL, NAME_CHANGE, 0, 0, " set the conference title to: %s", title);
|
||||||
|
|
||||||
|
char tmp_event[MAX_STR_SIZE + 20];
|
||||||
|
snprintf(tmp_event, sizeof(tmp_event), "set title to %s", title);
|
||||||
|
write_to_log(tmp_event, selfnick, self->chatwin->log, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
|
void cmd_enable_audio(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
|
{
|
||||||
|
UNUSED_VAR(window);
|
||||||
|
|
||||||
|
bool enable;
|
||||||
|
|
||||||
|
if (argc == 1 && !strcasecmp(argv[1], "on")) {
|
||||||
|
enable = true;
|
||||||
|
} else if (argc == 1 && !strcasecmp(argv[1], "off")) {
|
||||||
|
enable = false;
|
||||||
|
} else {
|
||||||
|
print_err(self, "Please specify: on | off");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enable ? enable_conference_audio(m, self->num) : disable_conference_audio(m, self->num)) {
|
||||||
|
print_err(self, enable ? "Enabled conference audio. Use the '/ptt' command to toggle Push-To-Talk."
|
||||||
|
: "Disabled conference audio");
|
||||||
|
} else {
|
||||||
|
print_err(self, enable ? "Failed to enable audio" : "Failed to disable audio");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmd_conference_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
|
{
|
||||||
|
UNUSED_VAR(window);
|
||||||
|
|
||||||
|
if (argc < 1) {
|
||||||
|
if (conference_mute_self(self->num)) {
|
||||||
|
print_err(self, "Toggled self audio mute status");
|
||||||
|
} else {
|
||||||
|
print_err(self, "No audio input to mute");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
NameListEntry *entries[16];
|
||||||
|
uint32_t n = get_name_list_entries_by_prefix(self->num, argv[1], entries, 16);
|
||||||
|
|
||||||
|
if (n == 0) {
|
||||||
|
print_err(self, "No such peer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n > 1) {
|
||||||
|
print_err(self, "Multiple matching peers (use /mute [public key] to disambiguate):");
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < n; ++i) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s: %s", entries[i]->pubkey_str, entries[i]->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conference_mute_peer(m, self->num, entries[0]->peernum)) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Toggled audio mute status of %s", entries[0]->name);
|
||||||
|
} else {
|
||||||
|
print_err(self, "Peer is not on the call");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmd_conference_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
|
{
|
||||||
|
UNUSED_VAR(window);
|
||||||
|
UNUSED_VAR(m);
|
||||||
|
|
||||||
|
if (argc == 0) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Current VAD threshold: %.1f",
|
||||||
|
(double) conference_get_VAD_threshold(self->num));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc > 1) {
|
||||||
|
print_err(self, "Only one argument allowed.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *end;
|
||||||
|
float value = strtof(argv[1], &end);
|
||||||
|
|
||||||
|
if (*end) {
|
||||||
|
print_err(self, "Invalid input");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conference_set_VAD_threshold(self->num, value)) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Set VAD threshold to %.1f", (double) value);
|
||||||
|
} else {
|
||||||
|
print_err(self, "Failed to set conference audio input sensitivity.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmd_conference_push_to_talk(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
|
{
|
||||||
|
UNUSED_VAR(window);
|
||||||
|
UNUSED_VAR(m);
|
||||||
|
|
||||||
|
bool enable;
|
||||||
|
|
||||||
|
if (argc == 1 && !strcasecmp(argv[1], "on")) {
|
||||||
|
enable = true;
|
||||||
|
} else if (argc == 1 && !strcasecmp(argv[1], "off")) {
|
||||||
|
enable = false;
|
||||||
|
} else {
|
||||||
|
print_err(self, "Please specify: on | off");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!toggle_conference_push_to_talk(self->num, enable)) {
|
||||||
|
print_err(self, "Failed to toggle push to talk.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_err(self, enable ? "Push-To-Talk is enabled. Push F2 to activate" : "Push-To-Talk is disabled");
|
||||||
|
}
|
||||||
|
#endif /* AUDIO */
|
35
src/conference_commands.h
Normal file
35
src/conference_commands.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/* conference_commands.h
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Toxic All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This file is part of Toxic.
|
||||||
|
*
|
||||||
|
* Toxic is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Toxic is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CONFERENCE_COMMANDS_H
|
||||||
|
#define CONFERENCE_COMMANDS_H
|
||||||
|
|
||||||
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
|
void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
|
void cmd_enable_audio(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
|
void cmd_conference_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
|
void cmd_conference_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
|
void cmd_conference_push_to_talk(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
|
|
||||||
|
#endif /* CONFERENCE_COMMANDS_H */
|
@ -20,18 +20,18 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "toxic.h"
|
|
||||||
#include "configdir.h"
|
#include "configdir.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
|
#include "toxic.h"
|
||||||
|
|
||||||
/* get the user's home directory. */
|
/* get the user's home directory. */
|
||||||
void get_home_dir(char *home, int size)
|
void get_home_dir(char *home, int size)
|
||||||
@ -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;
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
#ifndef CURL_UTIL_H
|
#ifndef CURL_UTIL_H
|
||||||
#define CURL_UTIL_H
|
#define CURL_UTIL_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
/* List based on Mozilla's recommended configurations for modern browsers */
|
/* List based on Mozilla's recommended configurations for modern browsers */
|
||||||
#define TLS_CIPHER_SUITE_LIST "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK"
|
#define TLS_CIPHER_SUITE_LIST "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK"
|
||||||
|
|
||||||
@ -52,4 +54,4 @@ int set_curl_proxy(CURL *c_handle, const char *proxy_address, uint16_t port, uin
|
|||||||
*/
|
*/
|
||||||
size_t curl_cb_write_data(void *data, size_t size, size_t nmemb, void *user_pointer);
|
size_t curl_cb_write_data(void *data, size_t size, size_t nmemb, void *user_pointer);
|
||||||
|
|
||||||
#endif /* CURL_UTIL_H */
|
#endif /* CURL_UTIL_H */
|
||||||
|
203
src/execute.c
203
src/execute.c
@ -20,19 +20,20 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#include "toxic.h"
|
#include "api.h"
|
||||||
#include "windows.h"
|
|
||||||
#include "execute.h"
|
|
||||||
#include "chat_commands.h"
|
#include "chat_commands.h"
|
||||||
|
#include "execute.h"
|
||||||
#include "global_commands.h"
|
#include "global_commands.h"
|
||||||
#include "group_commands.h"
|
#include "conference_commands.h"
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
struct cmd_func {
|
struct cmd_func {
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -47,11 +48,13 @@ static struct cmd_func global_commands[] = {
|
|||||||
{ "/connect", cmd_connect },
|
{ "/connect", cmd_connect },
|
||||||
{ "/decline", cmd_decline },
|
{ "/decline", cmd_decline },
|
||||||
{ "/exit", cmd_quit },
|
{ "/exit", cmd_quit },
|
||||||
{ "/group", cmd_groupchat },
|
{ "/conference", cmd_conference },
|
||||||
{ "/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 },
|
||||||
@ -64,88 +67,149 @@ static struct cmd_func global_commands[] = {
|
|||||||
{ "/sdev", cmd_change_device },
|
{ "/sdev", cmd_change_device },
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
{ "/lsvdev", cmd_list_video_devices },
|
{ "/lsvdev", cmd_list_video_devices },
|
||||||
{ "/svdev" , cmd_change_video_device },
|
{ "/svdev", cmd_change_video_device },
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
|
#ifdef PYTHON
|
||||||
|
{ "/run", cmd_run },
|
||||||
|
#endif /* PYTHON */
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct cmd_func chat_commands[] = {
|
static struct cmd_func chat_commands[] = {
|
||||||
{ "/cancel", cmd_cancelfile },
|
{ "/cancel", cmd_cancelfile },
|
||||||
{ "/invite", cmd_groupinvite },
|
{ "/invite", cmd_conference_invite },
|
||||||
{ "/join", cmd_join_group },
|
{ "/join", cmd_conference_join },
|
||||||
{ "/savefile", cmd_savefile },
|
{ "/savefile", cmd_savefile },
|
||||||
{ "/sendfile", cmd_sendfile },
|
{ "/sendfile", cmd_sendfile },
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
{ "/call", cmd_call },
|
{ "/call", cmd_call },
|
||||||
{ "/answer", cmd_answer },
|
{ "/answer", cmd_answer },
|
||||||
{ "/reject", cmd_reject },
|
{ "/reject", cmd_reject },
|
||||||
{ "/hangup", cmd_hangup },
|
{ "/hangup", cmd_hangup },
|
||||||
{ "/mute", cmd_mute },
|
{ "/mute", cmd_mute },
|
||||||
{ "/sense", cmd_sense },
|
{ "/sense", cmd_sense },
|
||||||
|
{ "/bitrate", cmd_bitrate },
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
{ "/video", cmd_video },
|
{ "/vcall", cmd_vcall },
|
||||||
|
{ "/video", cmd_video },
|
||||||
|
{ "/res", cmd_res },
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct cmd_func group_commands[] = {
|
static struct cmd_func conference_commands[] = {
|
||||||
{ "/title", cmd_set_title },
|
{ "/title", cmd_conference_set_title },
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
{ "/mute", cmd_mute },
|
{ "/audio", cmd_enable_audio },
|
||||||
{ "/sense", cmd_sense },
|
{ "/mute", cmd_conference_mute },
|
||||||
|
{ "/ptt", cmd_conference_push_to_talk },
|
||||||
|
{ "/sense", cmd_conference_sense },
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Parses input command and puts args into arg array.
|
|
||||||
Returns number of arguments on success, -1 on failure. */
|
#ifdef PYTHON
|
||||||
static int parse_command(WINDOW *w, ToxWindow *self, const char *input, char (*args)[MAX_STR_SIZE])
|
#define SPECIAL_COMMANDS 7
|
||||||
|
#else
|
||||||
|
#define SPECIAL_COMMANDS 6
|
||||||
|
#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 */
|
||||||
|
"/sendfile",
|
||||||
|
"/title",
|
||||||
|
"/mute",
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 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(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.
|
||||||
|
*
|
||||||
|
* Returns the number of arguments.
|
||||||
|
*/
|
||||||
|
static int parse_command(const char *input, char (*args)[MAX_STR_SIZE])
|
||||||
|
{
|
||||||
|
if (is_special_command(input)) {
|
||||||
|
return parse_special_command(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])
|
||||||
{
|
{
|
||||||
@ -163,34 +227,49 @@ 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(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 CONFERENCE_COMMAND_MODE:
|
||||||
if (do_command(w, self, m, num_args, group_commands, args) == 0)
|
if (do_command(w, self, m, num_args, conference_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
|
||||||
|
|
||||||
|
if (do_plugin_command(num_args, args) == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid command.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid command.");
|
||||||
}
|
}
|
||||||
|
@ -31,9 +31,9 @@
|
|||||||
enum {
|
enum {
|
||||||
GLOBAL_COMMAND_MODE,
|
GLOBAL_COMMAND_MODE,
|
||||||
CHAT_COMMAND_MODE,
|
CHAT_COMMAND_MODE,
|
||||||
GROUPCHAT_COMMAND_MODE,
|
CONFERENCE_COMMAND_MODE,
|
||||||
};
|
};
|
||||||
|
|
||||||
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 */
|
||||||
|
@ -20,23 +20,24 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "toxic.h"
|
|
||||||
#include "windows.h"
|
|
||||||
#include "friendlist.h"
|
|
||||||
#include "file_transfers.h"
|
#include "file_transfers.h"
|
||||||
|
#include "friendlist.h"
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
extern FriendsList Friends;
|
extern FriendsList Friends;
|
||||||
|
|
||||||
/* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */
|
/* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */
|
||||||
#define NUM_PROG_MARKS 50
|
#define NUM_PROG_MARKS 50
|
||||||
|
#define STR_BUF_SIZE 30
|
||||||
|
|
||||||
/* creates initial progress line that will be updated during file transfer.
|
/* creates initial progress line that will be updated during file transfer.
|
||||||
Assumes progline has room for at least MAX_STR_SIZE bytes */
|
Assumes progline has room for at least MAX_STR_SIZE bytes */
|
||||||
@ -45,8 +46,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,42 +56,58 @@ 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[STR_BUF_SIZE];
|
||||||
snprintf(pct_str, sizeof(pct_str), "%.1f%%", pct_done);
|
snprintf(pct_str, sizeof(pct_str), "%.1f%%", pct_done);
|
||||||
|
|
||||||
char bps_str[24];
|
char bps_str[STR_BUF_SIZE];
|
||||||
bytes_convert_str(bps_str, sizeof(bps_str), bps);
|
bytes_convert_str(bps_str, sizeof(bps_str), bps);
|
||||||
|
|
||||||
char prog_line[NUM_PROG_MARKS + 1] = {0};
|
char prog_line[NUM_PROG_MARKS + 1];
|
||||||
|
prog_line[0] = 0;
|
||||||
|
|
||||||
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];
|
size_t line_buf_size = 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);
|
char *full_line = malloc(line_buf_size);
|
||||||
|
|
||||||
|
if (full_line == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(full_line, line_buf_size, "%s [%s] %s/s", pct_str, prog_line, bps_str);
|
||||||
|
|
||||||
line_info_set(self, line_id, full_line);
|
line_info_set(self, line_id, full_line);
|
||||||
|
|
||||||
|
free(full_line);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void refresh_progress_helper(ToxWindow *self, Tox *m, struct FileTransfer *ft)
|
static void refresh_progress_helper(ToxWindow *self, 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;
|
||||||
@ -100,33 +118,38 @@ static void refresh_progress_helper(ToxWindow *self, Tox *m, struct FileTransfer
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* refreshes active file transfer status bars. */
|
/* refreshes active file transfer status bars. */
|
||||||
void refresh_file_transfer_progress(ToxWindow *self, Tox *m, uint32_t friendnum)
|
void refresh_file_transfer_progress(ToxWindow *self, uint32_t friendnumber)
|
||||||
{
|
{
|
||||||
size_t i;
|
for (size_t i = 0; i < MAX_FILES; ++i) {
|
||||||
|
refresh_progress_helper(self, &Friends.list[friendnumber].file_receiver[i]);
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
refresh_progress_helper(self, &Friends.list[friendnumber].file_sender[i]);
|
||||||
refresh_progress_helper(self, m, &Friends.list[friendnum].file_receiver[i]);
|
|
||||||
refresh_progress_helper(self, m, &Friends.list[friendnum].file_sender[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns a pointer to friendnum's FileTransfer struct associated with filenum.
|
static void clear_file_transfer(struct FileTransfer *ft)
|
||||||
* Returns NULL if filenum is invalid.
|
|
||||||
*/
|
|
||||||
struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filenum)
|
|
||||||
{
|
{
|
||||||
size_t i;
|
*ft = (struct FileTransfer) {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
/* Returns a pointer to friendnumber's FileTransfer struct associated with filenumber.
|
||||||
struct FileTransfer *ft_send = &Friends.list[friendnum].file_sender[i];
|
* Returns NULL if filenumber is invalid.
|
||||||
|
*/
|
||||||
|
struct FileTransfer *get_file_transfer_struct(uint32_t friendnumber, uint32_t filenumber)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < MAX_FILES; ++i) {
|
||||||
|
struct FileTransfer *ft_send = &Friends.list[friendnumber].file_sender[i];
|
||||||
|
|
||||||
if (ft_send->state != FILE_TRANSFER_INACTIVE && ft_send->filenum == filenum)
|
if (ft_send->state != FILE_TRANSFER_INACTIVE && ft_send->filenumber == filenumber) {
|
||||||
return ft_send;
|
return ft_send;
|
||||||
|
}
|
||||||
|
|
||||||
struct FileTransfer *ft_recv = &Friends.list[friendnum].file_receiver[i];
|
struct FileTransfer *ft_recv = &Friends.list[friendnumber].file_receiver[i];
|
||||||
|
|
||||||
if (ft_recv->state != FILE_TRANSFER_INACTIVE && ft_recv->filenum == filenum)
|
if (ft_recv->state != FILE_TRANSFER_INACTIVE && ft_recv->filenumber == filenumber) {
|
||||||
return ft_recv;
|
return ft_recv;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -135,21 +158,21 @@ struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filen
|
|||||||
/* Returns a pointer to the FileTransfer struct associated with index with the direction specified.
|
/* Returns a pointer to the FileTransfer struct associated with index with the direction specified.
|
||||||
* Returns NULL on failure.
|
* Returns NULL on failure.
|
||||||
*/
|
*/
|
||||||
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t index,
|
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnumber, 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;
|
for (size_t i = 0; i < MAX_FILES; ++i) {
|
||||||
|
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
|
||||||
struct FileTransfer *ft = direction == FILE_TRANSFER_SEND ?
|
struct FileTransfer *ft = direction == FILE_TRANSFER_SEND ?
|
||||||
&Friends.list[friendnum].file_sender[i] :
|
&Friends.list[friendnumber].file_sender[i] :
|
||||||
&Friends.list[friendnum].file_receiver[i];
|
&Friends.list[friendnumber].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;
|
||||||
@ -158,23 +181,19 @@ struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t
|
|||||||
/* Returns a pointer to an unused file sender.
|
/* Returns a pointer to an unused file sender.
|
||||||
* Returns NULL if all file senders are in use.
|
* Returns NULL if all file senders are in use.
|
||||||
*/
|
*/
|
||||||
static struct FileTransfer *new_file_sender(ToxWindow *window, uint32_t friendnum, uint32_t filenum, uint8_t type)
|
static struct FileTransfer *new_file_sender(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber, uint8_t type)
|
||||||
{
|
{
|
||||||
size_t i;
|
for (size_t i = 0; i < MAX_FILES; ++i) {
|
||||||
|
struct FileTransfer *ft = &Friends.list[friendnumber].file_sender[i];
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
|
||||||
struct FileTransfer *ft = &Friends.list[friendnum].file_sender[i];
|
|
||||||
|
|
||||||
if (ft->state == FILE_TRANSFER_INACTIVE) {
|
if (ft->state == FILE_TRANSFER_INACTIVE) {
|
||||||
memset(ft, 0, sizeof(struct FileTransfer));
|
clear_file_transfer(ft);
|
||||||
ft->window = window;
|
ft->window = window;
|
||||||
ft->index = i;
|
ft->index = i;
|
||||||
ft->friendnum = friendnum;
|
ft->friendnumber = friendnumber;
|
||||||
ft->filenum = filenum;
|
ft->filenumber = filenumber;
|
||||||
ft->file_type = type;
|
ft->file_type = type;
|
||||||
ft->last_keep_alive = get_unix_time();
|
|
||||||
ft->state = FILE_TRANSFER_PENDING;
|
ft->state = FILE_TRANSFER_PENDING;
|
||||||
ft->direction = FILE_TRANSFER_SEND;
|
|
||||||
return ft;
|
return ft;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -185,23 +204,20 @@ static struct FileTransfer *new_file_sender(ToxWindow *window, uint32_t friendnu
|
|||||||
/* Returns a pointer to an unused file receiver.
|
/* Returns a pointer to an unused file receiver.
|
||||||
* Returns NULL if all file receivers are in use.
|
* Returns NULL if all file receivers are in use.
|
||||||
*/
|
*/
|
||||||
static struct FileTransfer *new_file_receiver(ToxWindow *window, uint32_t friendnum, uint32_t filenum, uint8_t type)
|
static struct FileTransfer *new_file_receiver(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber,
|
||||||
|
uint8_t type)
|
||||||
{
|
{
|
||||||
size_t i;
|
for (size_t i = 0; i < MAX_FILES; ++i) {
|
||||||
|
struct FileTransfer *ft = &Friends.list[friendnumber].file_receiver[i];
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
|
||||||
struct FileTransfer *ft = &Friends.list[friendnum].file_receiver[i];
|
|
||||||
|
|
||||||
if (ft->state == FILE_TRANSFER_INACTIVE) {
|
if (ft->state == FILE_TRANSFER_INACTIVE) {
|
||||||
memset(ft, 0, sizeof(struct FileTransfer));
|
clear_file_transfer(ft);
|
||||||
ft->window = window;
|
ft->window = window;
|
||||||
ft->index = i;
|
ft->index = i;
|
||||||
ft->friendnum = friendnum;
|
ft->friendnumber = friendnumber;
|
||||||
ft->filenum = filenum;
|
ft->filenumber = filenumber;
|
||||||
ft->file_type = type;
|
ft->file_type = type;
|
||||||
ft->last_keep_alive = get_unix_time();
|
|
||||||
ft->state = FILE_TRANSFER_PENDING;
|
ft->state = FILE_TRANSFER_PENDING;
|
||||||
ft->direction = FILE_TRANSFER_RECV;
|
|
||||||
return ft;
|
return ft;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -212,14 +228,16 @@ static struct FileTransfer *new_file_receiver(ToxWindow *window, uint32_t friend
|
|||||||
/* Initializes an unused file transfer and returns its pointer.
|
/* Initializes an unused file transfer and returns its pointer.
|
||||||
* Returns NULL on failure.
|
* Returns NULL on failure.
|
||||||
*/
|
*/
|
||||||
struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnum, uint32_t filenum,
|
struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber,
|
||||||
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, friendnumber, filenumber, type);
|
||||||
|
}
|
||||||
|
|
||||||
if (direction == FILE_TRANSFER_SEND)
|
if (direction == FILE_TRANSFER_SEND) {
|
||||||
return new_file_sender(window, friendnum, filenum, type);
|
return new_file_sender(window, friendnumber, filenumber, type);
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -233,45 +251,59 @@ 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->friendnumber, ft->filenumber, (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);
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(ft, 0, sizeof(struct FileTransfer));
|
clear_file_transfer(ft);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Kills all active file transfers for friendnum */
|
/* Kills active outgoing avatar file transfers for friendnumber */
|
||||||
void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum)
|
void kill_avatar_file_transfers_friend(Tox *m, uint32_t friendnumber)
|
||||||
{
|
{
|
||||||
size_t i;
|
for (size_t i = 0; i < MAX_FILES; ++i) {
|
||||||
|
struct FileTransfer *ft = &Friends.list[friendnumber].file_sender[i];
|
||||||
|
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
if (ft->file_type == TOX_FILE_KIND_AVATAR) {
|
||||||
close_file_transfer(NULL, m, &Friends.list[friendnum].file_sender[i], TOX_FILE_CONTROL_CANCEL, NULL, silent);
|
close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent);
|
||||||
close_file_transfer(NULL, m, &Friends.list[friendnum].file_receiver[i], TOX_FILE_CONTROL_CANCEL, NULL, silent);
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Kills all active file transfers for friendnumber */
|
||||||
|
void kill_all_file_transfers_friend(Tox *m, uint32_t friendnumber)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < MAX_FILES; ++i) {
|
||||||
|
close_file_transfer(NULL, m, &Friends.list[friendnumber].file_sender[i], TOX_FILE_CONTROL_CANCEL, NULL, silent);
|
||||||
|
close_file_transfer(NULL, m, &Friends.list[friendnumber].file_receiver[i], TOX_FILE_CONTROL_CANCEL, NULL, silent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void kill_all_file_transfers(Tox *m)
|
void kill_all_file_transfers(Tox *m)
|
||||||
{
|
{
|
||||||
size_t i;
|
for (size_t 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,9 @@
|
|||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include "notify.h"
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#include "notify.h"
|
|
||||||
|
|
||||||
#define KiB 1024
|
#define KiB 1024
|
||||||
#define MiB 1048576 /* 1024^2 */
|
#define MiB 1048576 /* 1024^2 */
|
||||||
@ -51,18 +51,16 @@ struct FileTransfer {
|
|||||||
ToxWindow *window;
|
ToxWindow *window;
|
||||||
FILE *file;
|
FILE *file;
|
||||||
FILE_TRANSFER_STATE state;
|
FILE_TRANSFER_STATE state;
|
||||||
FILE_TRANSFER_DIRECTION direction;
|
|
||||||
uint8_t file_type;
|
uint8_t file_type;
|
||||||
char file_name[TOX_MAX_FILENAME_LENGTH + 1];
|
char file_name[TOX_MAX_FILENAME_LENGTH + 1];
|
||||||
char file_path[PATH_MAX + 1]; /* Not used by senders */
|
char file_path[PATH_MAX + 1]; /* Not used by senders */
|
||||||
double bps;
|
double bps;
|
||||||
uint32_t filenum;
|
uint32_t filenumber;
|
||||||
uint32_t friendnum;
|
uint32_t friendnumber;
|
||||||
size_t index;
|
size_t index;
|
||||||
uint64_t file_size;
|
uint64_t file_size;
|
||||||
uint64_t position;
|
uint64_t position;
|
||||||
time_t last_line_progress; /* The last time we updated the progress bar */
|
time_t last_line_progress; /* The last time we updated the progress bar */
|
||||||
time_t last_keep_alive; /* The last time we sent or received data */
|
|
||||||
uint32_t line_id;
|
uint32_t line_id;
|
||||||
uint8_t file_id[TOX_FILE_ID_LENGTH];
|
uint8_t file_id[TOX_FILE_ID_LENGTH];
|
||||||
};
|
};
|
||||||
@ -75,24 +73,24 @@ void init_progress_bar(char *progline);
|
|||||||
void print_progress_bar(ToxWindow *self, double pct_done, double bps, uint32_t line_id);
|
void print_progress_bar(ToxWindow *self, double pct_done, double bps, uint32_t line_id);
|
||||||
|
|
||||||
/* refreshes active file transfer status bars. */
|
/* refreshes active file transfer status bars. */
|
||||||
void refresh_file_transfer_progress(ToxWindow *self, Tox *m, uint32_t friendnum);
|
void refresh_file_transfer_progress(ToxWindow *self, uint32_t friendnumber);
|
||||||
|
|
||||||
/* Returns a pointer to friendnum's FileTransfer struct associated with filenum.
|
/* Returns a pointer to friendnumber's FileTransfer struct associated with filenumber.
|
||||||
* Returns NULL if filenum is invalid.
|
* Returns NULL if filenumber is invalid.
|
||||||
*/
|
*/
|
||||||
struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filenum);
|
struct FileTransfer *get_file_transfer_struct(uint32_t friendnumber, uint32_t filenumber);
|
||||||
|
|
||||||
|
|
||||||
/* Returns a pointer to the FileTransfer struct associated with index with the direction specified.
|
/* Returns a pointer to the FileTransfer struct associated with index with the direction specified.
|
||||||
* Returns NULL on failure.
|
* Returns NULL on failure.
|
||||||
*/
|
*/
|
||||||
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t index,
|
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnumber, uint32_t index,
|
||||||
FILE_TRANSFER_DIRECTION direction);
|
FILE_TRANSFER_DIRECTION direction);
|
||||||
|
|
||||||
/* Initializes an unused file transfer and returns its pointer.
|
/* Initializes an unused file transfer and returns its pointer.
|
||||||
* Returns NULL on failure.
|
* Returns NULL on failure.
|
||||||
*/
|
*/
|
||||||
struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnum, uint32_t filenum,
|
struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber,
|
||||||
FILE_TRANSFER_DIRECTION direction, uint8_t type);
|
FILE_TRANSFER_DIRECTION direction, uint8_t type);
|
||||||
|
|
||||||
/* Closes file transfer ft.
|
/* Closes file transfer ft.
|
||||||
@ -103,9 +101,12 @@ 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);
|
||||||
|
|
||||||
/* Kills all active file transfers for friendnum */
|
/* Kills active outgoing avatar file transfers for friendnumber */
|
||||||
void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum);
|
void kill_avatar_file_transfers_friend(Tox *m, uint32_t friendnumber);
|
||||||
|
|
||||||
|
/* Kills all active file transfers for friendnumber */
|
||||||
|
void kill_all_file_transfers_friend(Tox *m, uint32_t friendnumber);
|
||||||
|
|
||||||
void kill_all_file_transfers(Tox *m);
|
void kill_all_file_transfers(Tox *m);
|
||||||
|
|
||||||
#endif /* #define FILE_TRANSFERS_H */
|
#endif /* FILE_TRANSFERS_H */
|
||||||
|
583
src/friendlist.c
583
src/friendlist.c
File diff suppressed because it is too large
Load Diff
@ -25,9 +25,9 @@
|
|||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "file_transfers.h"
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#include "file_transfers.h"
|
|
||||||
|
|
||||||
struct LastOnline {
|
struct LastOnline {
|
||||||
uint64_t last_on;
|
uint64_t last_on;
|
||||||
@ -35,7 +35,7 @@ struct LastOnline {
|
|||||||
char hour_min_str[TIME_STR_SIZE]; /* holds 12/24-hour time string e.g. "10:43 PM" */
|
char hour_min_str[TIME_STR_SIZE]; /* holds 12/24-hour time string e.g. "10:43 PM" */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GroupChatInvite {
|
struct ConferenceInvite {
|
||||||
char *key;
|
char *key;
|
||||||
uint16_t length;
|
uint16_t length;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
@ -44,20 +44,20 @@ struct GroupChatInvite {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char name[TOXIC_MAX_NAME_LENGTH + 1];
|
char name[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
int namelength;
|
uint16_t namelength;
|
||||||
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
|
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
|
||||||
size_t statusmsg_len;
|
size_t statusmsg_len;
|
||||||
char pub_key[TOX_PUBLIC_KEY_SIZE];
|
char pub_key[TOX_PUBLIC_KEY_SIZE];
|
||||||
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 ConferenceInvite conference_invite;
|
||||||
|
|
||||||
struct FileTransfer file_receiver[MAX_FILES];
|
struct FileTransfer file_receiver[MAX_FILES];
|
||||||
struct FileTransfer file_sender[MAX_FILES];
|
struct FileTransfer file_sender[MAX_FILES];
|
||||||
@ -65,7 +65,7 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char name[TOXIC_MAX_NAME_LENGTH + 1];
|
char name[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
int namelength;
|
uint16_t namelength;
|
||||||
char pub_key[TOX_PUBLIC_KEY_SIZE];
|
char pub_key[TOX_PUBLIC_KEY_SIZE];
|
||||||
uint32_t num;
|
uint32_t num;
|
||||||
bool active;
|
bool active;
|
||||||
@ -81,14 +81,23 @@ 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);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns true if friend associated with `public_key` is in the block list.
|
||||||
|
*
|
||||||
|
* `public_key` must be at least TOX_PUBLIC_KEY_SIZE bytes.
|
||||||
|
*/
|
||||||
|
bool friend_is_blocked(const char *public_key);
|
||||||
|
|
||||||
#endif /* end of include guard: FRIENDLIST_H */
|
#endif /* end of include guard: FRIENDLIST_H */
|
||||||
|
@ -23,20 +23,20 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "toxic.h"
|
|
||||||
#include "windows.h"
|
|
||||||
#include "misc_tools.h"
|
|
||||||
#include "friendlist.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "line_info.h"
|
|
||||||
#include "groupchat.h"
|
|
||||||
#include "prompt.h"
|
|
||||||
#include "help.h"
|
|
||||||
#include "term_mplex.h"
|
|
||||||
#include "avatars.h"
|
#include "avatars.h"
|
||||||
|
#include "conference.h"
|
||||||
|
#include "friendlist.h"
|
||||||
|
#include "help.h"
|
||||||
|
#include "line_info.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "misc_tools.h"
|
||||||
#include "name_lookup.h"
|
#include "name_lookup.h"
|
||||||
|
#include "prompt.h"
|
||||||
#include "qr_code.h"
|
#include "qr_code.h"
|
||||||
|
#include "term_mplex.h"
|
||||||
|
#include "toxic.h"
|
||||||
#include "toxic_strings.h"
|
#include "toxic_strings.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
extern char *DATA_FILE;
|
extern char *DATA_FILE;
|
||||||
extern ToxWindow *prompt;
|
extern ToxWindow *prompt;
|
||||||
@ -46,6 +46,8 @@ 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])
|
||||||
{
|
{
|
||||||
|
UNUSED_VAR(window);
|
||||||
|
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Request ID required.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Request ID required.");
|
||||||
return;
|
return;
|
||||||
@ -63,7 +65,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,29 +73,31 @@ 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));
|
FrndRequests.request[req] = (struct friend_request) {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg)
|
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,13 +130,14 @@ 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:
|
||||||
|
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
default:
|
default:
|
||||||
errmsg = "Faile to add friend: Unknown error.";
|
errmsg = "Failed to add friend: Unknown error.";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,6 +146,8 @@ void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg
|
|||||||
|
|
||||||
void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
|
UNUSED_VAR(window);
|
||||||
|
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Tox ID or address required.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Tox ID or address required.");
|
||||||
return;
|
return;
|
||||||
@ -192,6 +199,11 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
|||||||
id_bin[i] = x;
|
id_bin[i] = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (friend_is_blocked(id_bin)) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Friend is in your block list.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
cmd_add_helper(self, m, id_bin, msg);
|
cmd_add_helper(self, m, id_bin, msg);
|
||||||
} else { /* assume id is a username@domain address and do http name server lookup */
|
} else { /* assume id is a username@domain address and do http name server lookup */
|
||||||
name_lookup(self, m, id_bin, id, msg);
|
name_lookup(self, m, id_bin, id, msg);
|
||||||
@ -200,21 +212,17 @@ 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) {
|
UNUSED_VAR(window);
|
||||||
|
|
||||||
|
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.");
|
||||||
@ -237,12 +245,18 @@ void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
|||||||
|
|
||||||
void cmd_clear(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_clear(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
|
UNUSED_VAR(m);
|
||||||
|
UNUSED_VAR(argc);
|
||||||
|
UNUSED_VAR(argv);
|
||||||
|
|
||||||
line_info_clear(self->chatwin->hst);
|
line_info_clear(self->chatwin->hst);
|
||||||
force_refresh(window);
|
force_refresh(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
|
UNUSED_VAR(window);
|
||||||
|
|
||||||
if (argc != 3) {
|
if (argc != 3) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Require: <ip> <port> <key>");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Require: <ip> <port> <key>");
|
||||||
return;
|
return;
|
||||||
@ -260,12 +274,13 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
char key_binary[TOX_PUBLIC_KEY_SIZE * 2 + 1];
|
char key_binary[TOX_PUBLIC_KEY_SIZE * 2 + 1];
|
||||||
|
|
||||||
if (hex_string_to_bin(ascii_key, strlen(ascii_key), key_binary, TOX_PUBLIC_KEY_SIZE) == -1) {
|
if (hex_string_to_bin(ascii_key, strlen(ascii_key), key_binary, TOX_PUBLIC_KEY_SIZE) == -1) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid key.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid key.");
|
||||||
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);
|
||||||
|
|
||||||
@ -281,6 +296,7 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
|
|||||||
case TOX_ERR_BOOTSTRAP_NULL:
|
case TOX_ERR_BOOTSTRAP_NULL:
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed.");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -288,6 +304,9 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
|
|||||||
|
|
||||||
void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
|
UNUSED_VAR(window);
|
||||||
|
UNUSED_VAR(m);
|
||||||
|
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Request ID required.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Request ID required.");
|
||||||
return;
|
return;
|
||||||
@ -305,75 +324,105 @@ void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&FrndRequests.request[req], 0, sizeof(struct friend_request));
|
FrndRequests.request[req] = (struct friend_request) {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_conference(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
|
UNUSED_VAR(window);
|
||||||
|
|
||||||
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
|
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Please specify group type: text | audio");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Please specify conference type: text | audio");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
|
|
||||||
if (!strcasecmp(argv[1], "audio"))
|
if (!strcasecmp(argv[1], "audio")) {
|
||||||
type = TOX_GROUPCHAT_TYPE_AV;
|
type = TOX_CONFERENCE_TYPE_AV;
|
||||||
else if (!strcasecmp(argv[1], "text"))
|
} else if (!strcasecmp(argv[1], "text")) {
|
||||||
type = TOX_GROUPCHAT_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 conference types are: text | audio");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int groupnum = -1;
|
uint32_t conferencenum = 0;
|
||||||
|
|
||||||
if (type == TOX_GROUPCHAT_TYPE_TEXT)
|
if (type == TOX_CONFERENCE_TYPE_TEXT) {
|
||||||
groupnum = tox_add_groupchat(m);
|
Tox_Err_Conference_New err;
|
||||||
/*#ifdef AUDIO
|
|
||||||
else
|
|
||||||
groupnum = toxav_add_av_groupchat(m, NULL, NULL);
|
|
||||||
#endif*/
|
|
||||||
|
|
||||||
if (groupnum == -1) {
|
conferencenum = tox_conference_new(m, &err);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize.");
|
|
||||||
|
if (err != TOX_ERR_CONFERENCE_NEW_OK) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Conference instance failed to initialize (error %d)", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (type == TOX_CONFERENCE_TYPE_AV) {
|
||||||
|
#ifdef AUDIO
|
||||||
|
conferencenum = toxav_add_av_groupchat(m, audio_conference_callback, NULL);
|
||||||
|
|
||||||
|
if (conferencenum == (uint32_t) -1) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio conference instance failed to initialize");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio support disabled by compile-time option.");
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (init_conference_win(m, conferencenum, type, NULL, 0) == -1) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Conference window failed to initialize.");
|
||||||
|
tox_conference_delete(m, conferencenum, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (init_groupchat_win(prompt, m, groupnum, type) == -1) {
|
#ifdef AUDIO
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
|
|
||||||
tox_del_groupchat(m, groupnum);
|
if (type == TOX_CONFERENCE_TYPE_AV) {
|
||||||
return;
|
if (!init_conference_audio_input(m, conferencenum)) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio capture failed; use \"/audio on\" to try again.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat [%d] created.", groupnum);
|
#endif
|
||||||
|
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Conference [%d] created.", conferencenum);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
|
UNUSED_VAR(window);
|
||||||
|
|
||||||
const char *msg;
|
const char *msg;
|
||||||
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;
|
||||||
@ -382,26 +431,13 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
|||||||
const char *swch = argv[1];
|
const char *swch = argv[1];
|
||||||
|
|
||||||
if (!strcmp(swch, "1") || !strcmp(swch, "on")) {
|
if (!strcmp(swch, "1") || !strcmp(swch, "on")) {
|
||||||
char myid[TOX_ADDRESS_SIZE];
|
msg = log_enable(log) == 0 ? "Logging enabled." : "Warning: Failed to enable log.";
|
||||||
tox_self_get_address(m, (uint8_t *) myid);
|
|
||||||
|
|
||||||
int log_ret = -1;
|
|
||||||
|
|
||||||
if (self->is_chat) {
|
|
||||||
Friends.list[self->num].logging_on = true;
|
|
||||||
log_ret = log_enable(self->name, myid, Friends.list[self->num].pub_key, log, LOG_CHAT);
|
|
||||||
} else if (self->is_prompt) {
|
|
||||||
log_ret = log_enable(self->name, myid, NULL, log, LOG_PROMPT);
|
|
||||||
} else if (self->is_groupchat) {
|
|
||||||
log_ret = log_enable(self->name, myid, NULL, log, LOG_GROUP);
|
|
||||||
}
|
|
||||||
|
|
||||||
msg = log_ret == 0 ? "Logging enabled." : "Warning: Log failed to initialize.";
|
|
||||||
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->type == WINDOW_TYPE_CHAT) {
|
||||||
Friends.list[self->num].logging_on = false;
|
Friends.list[self->num].logging_on = false;
|
||||||
|
}
|
||||||
|
|
||||||
log_disable(log);
|
log_disable(log);
|
||||||
|
|
||||||
@ -416,6 +452,10 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
|||||||
|
|
||||||
void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
|
UNUSED_VAR(window);
|
||||||
|
UNUSED_VAR(argc);
|
||||||
|
UNUSED_VAR(argv);
|
||||||
|
|
||||||
char id_string[TOX_ADDRESS_SIZE * 2 + 1];
|
char id_string[TOX_ADDRESS_SIZE * 2 + 1];
|
||||||
char bin_id[TOX_ADDRESS_SIZE];
|
char bin_id[TOX_ADDRESS_SIZE];
|
||||||
tox_self_get_address(m, (uint8_t *) bin_id);
|
tox_self_get_address(m, (uint8_t *) bin_id);
|
||||||
@ -428,8 +468,11 @@ 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])
|
||||||
{
|
{
|
||||||
|
UNUSED_VAR(window);
|
||||||
|
|
||||||
char id_string[TOX_ADDRESS_SIZE * 2 + 1];
|
char id_string[TOX_ADDRESS_SIZE * 2 + 1];
|
||||||
char bin_id[TOX_ADDRESS_SIZE];
|
char bin_id[TOX_ADDRESS_SIZE];
|
||||||
tox_self_get_address(m, (uint8_t *) bin_id);
|
tox_self_get_address(m, (uint8_t *) bin_id);
|
||||||
@ -445,48 +488,94 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
|||||||
nick[nick_len] = '\0';
|
nick[nick_len] = '\0';
|
||||||
|
|
||||||
size_t data_file_len = strlen(DATA_FILE);
|
size_t data_file_len = strlen(DATA_FILE);
|
||||||
char dir[data_file_len + 1];
|
char *dir = malloc(data_file_len + 1);
|
||||||
|
|
||||||
|
if (dir == NULL) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code: Out of memory.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
size_t dir_len = get_base_dir(DATA_FILE, data_file_len, dir);
|
size_t dir_len = get_base_dir(DATA_FILE, data_file_len, dir);
|
||||||
|
|
||||||
char qr_path[dir_len + nick_len + strlen(QRCODE_FILENAME_EXT) + 1];
|
#ifdef QRPNG
|
||||||
snprintf(qr_path, sizeof(qr_path), "%s%s%s", dir, nick, QRCODE_FILENAME_EXT);
|
|
||||||
|
|
||||||
FILE *output = fopen(qr_path, "wb");
|
if (argc == 0) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Required 'txt' or 'png'");
|
||||||
|
free(dir);
|
||||||
|
return;
|
||||||
|
} else if (!strcmp(argv[1], "txt")) {
|
||||||
|
|
||||||
if (output == NULL) {
|
#endif /* QRPNG */
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
|
size_t qr_path_buf_size = dir_len + nick_len + sizeof(QRCODE_FILENAME_EXT);
|
||||||
|
char *qr_path = malloc(qr_path_buf_size);
|
||||||
|
|
||||||
|
if (qr_path == NULL) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code: Out of memory");
|
||||||
|
free(dir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(qr_path, qr_path_buf_size, "%s%s%s", dir, nick, QRCODE_FILENAME_EXT);
|
||||||
|
|
||||||
|
if (ID_to_QRcode_txt(id_string, qr_path) == -1) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
|
||||||
|
free(dir);
|
||||||
|
free(qr_path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path);
|
||||||
|
|
||||||
|
free(qr_path);
|
||||||
|
|
||||||
|
#ifdef QRPNG
|
||||||
|
} else if (!strcmp(argv[1], "png")) {
|
||||||
|
size_t qr_path_buf_size = dir_len + nick_len + sizeof(QRCODE_FILENAME_EXT_PNG);
|
||||||
|
char *qr_path = malloc(qr_path_buf_size);
|
||||||
|
|
||||||
|
if (qr_path == NULL) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code: Out of memory");
|
||||||
|
free(dir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(qr_path, qr_path_buf_size, "%s%s%s", dir, nick, QRCODE_FILENAME_EXT_PNG);
|
||||||
|
|
||||||
|
if (ID_to_QRcode_png(id_string, qr_path) == -1) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
|
||||||
|
free(dir);
|
||||||
|
free(qr_path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path);
|
||||||
|
|
||||||
|
free(qr_path);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Unknown option '%s' -- Required 'txt' or 'png'", argv[1]);
|
||||||
|
free(dir);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ID_to_QRcode(id_string, output) == -1) {
|
#endif /* QRPNG */
|
||||||
fclose(output);
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path);
|
free(dir);
|
||||||
|
|
||||||
fclose(output);
|
|
||||||
}
|
}
|
||||||
|
#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])
|
||||||
{
|
{
|
||||||
|
UNUSED_VAR(window);
|
||||||
|
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Input required.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Input required.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char nick[MAX_STR_SIZE];
|
char nick[MAX_STR_SIZE];
|
||||||
size_t len = 0;
|
snprintf(nick, sizeof(nick), "%s", argv[1]);
|
||||||
|
size_t len = strlen(nick);
|
||||||
if (argv[1][0] == '\"') { /* remove opening and closing quotes */
|
|
||||||
snprintf(nick, sizeof(nick), "%s", &argv[1][1]);
|
|
||||||
len = strlen(nick) - 1;
|
|
||||||
nick[len] = '\0';
|
|
||||||
} else {
|
|
||||||
snprintf(nick, sizeof(nick), "%s", argv[1]);
|
|
||||||
len = strlen(nick);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!valid_nick(nick)) {
|
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.");
|
||||||
@ -504,24 +593,14 @@ void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
|||||||
|
|
||||||
void cmd_note(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_note(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
|
UNUSED_VAR(window);
|
||||||
|
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Input required.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Input required.");
|
||||||
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])
|
||||||
@ -543,22 +622,39 @@ void cmd_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
|||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Your new Tox ID is:");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Your new Tox ID is:");
|
||||||
cmd_myid(window, self, m, 0, NULL);
|
cmd_myid(window, self, m, 0, NULL);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Any services that relied on your old ID will need to be updated manually.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "If you ever want your old Tox ID back, type '/nospam %X'", old_nospam);
|
"Any services that relied on your old ID will need to be updated manually.");
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "If you ever want your old Tox ID back, type '/nospam %X'",
|
||||||
|
old_nospam);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_prompt_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_prompt_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
|
UNUSED_VAR(window);
|
||||||
|
UNUSED_VAR(m);
|
||||||
|
UNUSED_VAR(argc);
|
||||||
|
UNUSED_VAR(argv);
|
||||||
|
|
||||||
help_init_menu(self);
|
help_init_menu(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_quit(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_quit(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
|
UNUSED_VAR(window);
|
||||||
|
UNUSED_VAR(argc);
|
||||||
|
UNUSED_VAR(argv);
|
||||||
|
UNUSED_VAR(self);
|
||||||
|
|
||||||
exit_toxic_success(m);
|
exit_toxic_success(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_requests(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_requests(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
|
UNUSED_VAR(window);
|
||||||
|
UNUSED_VAR(m);
|
||||||
|
UNUSED_VAR(argc);
|
||||||
|
UNUSED_VAR(argv);
|
||||||
|
|
||||||
if (FrndRequests.num_requests == 0) {
|
if (FrndRequests.num_requests == 0) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend requests.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend requests.");
|
||||||
return;
|
return;
|
||||||
@ -568,8 +664,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};
|
||||||
|
|
||||||
@ -582,36 +679,36 @@ 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;
|
UNUSED_VAR(window);
|
||||||
|
|
||||||
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;
|
||||||
@ -619,22 +716,9 @@ 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);
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Your status has been changed to %s.", status_str);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
unlock_status ();
|
unlock_status();
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,8 @@
|
|||||||
#ifndef GLOBAL_COMMANDS_H
|
#ifndef GLOBAL_COMMANDS_H
|
||||||
#define GLOBAL_COMMANDS_H
|
#define GLOBAL_COMMANDS_H
|
||||||
|
|
||||||
#include "windows.h"
|
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
void cmd_accept(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_accept(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
void cmd_add(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_add(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
@ -32,10 +32,12 @@ void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
|||||||
void cmd_clear(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_clear(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
void cmd_connect(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_connect(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
void cmd_groupchat(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_conference(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]);
|
||||||
@ -56,4 +58,8 @@ void cmd_list_video_devices(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)
|
|||||||
void cmd_change_video_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_change_video_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
|
|
||||||
#endif /* #define GLOBAL_COMMANDS_H */
|
#ifdef PYTHON
|
||||||
|
void cmd_run(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
|
#endif /* PYTHON */
|
||||||
|
|
||||||
|
#endif /* GLOBAL_COMMANDS_H */
|
||||||
|
@ -1,79 +0,0 @@
|
|||||||
/* group_commands.c
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Copyright (C) 2014 Toxic All Rights Reserved.
|
|
||||||
*
|
|
||||||
* This file is part of Toxic.
|
|
||||||
*
|
|
||||||
* Toxic is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Toxic is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "toxic.h"
|
|
||||||
#include "windows.h"
|
|
||||||
#include "line_info.h"
|
|
||||||
#include "misc_tools.h"
|
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
void cmd_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
|
||||||
{
|
|
||||||
char title[MAX_STR_SIZE];
|
|
||||||
|
|
||||||
if (argc < 1) {
|
|
||||||
int tlen = tox_group_get_title(m, self->num, (uint8_t *) title, TOX_MAX_NAME_LENGTH);
|
|
||||||
|
|
||||||
if (tlen != -1) {
|
|
||||||
title[tlen] = '\0';
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title is set to: %s", title);
|
|
||||||
} else {
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title is not set");
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argv[1][0] != '\"') {
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title must be enclosed in quotes.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remove opening and closing quotes */
|
|
||||||
snprintf(title, sizeof(title), "%s", &argv[1][1]);
|
|
||||||
int len = strlen(title) - 1;
|
|
||||||
title[len] = '\0';
|
|
||||||
|
|
||||||
if (tox_group_set_title(m, self->num, (uint8_t *) title, len) != 0) {
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_window_title(self, title, len);
|
|
||||||
|
|
||||||
char timefrmt[TIME_STR_SIZE];
|
|
||||||
char selfnick[TOX_MAX_NAME_LENGTH];
|
|
||||||
|
|
||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
|
||||||
|
|
||||||
tox_self_get_name(m, (uint8_t *) selfnick);
|
|
||||||
size_t sn_len = tox_self_get_name_size(m);
|
|
||||||
selfnick[sn_len] = '\0';
|
|
||||||
|
|
||||||
line_info_add(self, timefrmt, selfnick, NULL, NAME_CHANGE, 0, 0, " set the group title to: %s", title);
|
|
||||||
|
|
||||||
char tmp_event[MAX_STR_SIZE];
|
|
||||||
snprintf(tmp_event, sizeof(tmp_event), "set title to %s", title);
|
|
||||||
write_to_log(tmp_event, selfnick, self->chatwin->log, true);
|
|
||||||
}
|
|
924
src/groupchat.c
924
src/groupchat.c
@ -1,924 +0,0 @@
|
|||||||
/* groupchat.c
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Copyright (C) 2014 Toxic All Rights Reserved.
|
|
||||||
*
|
|
||||||
* This file is part of Toxic.
|
|
||||||
*
|
|
||||||
* Toxic is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Toxic is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _GNU_SOURCE
|
|
||||||
#define _GNU_SOURCE /* needed for strcasestr() and wcswidth() */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <wchar.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#ifdef AUDIO
|
|
||||||
#ifdef __APPLE__
|
|
||||||
#include <OpenAL/al.h>
|
|
||||||
#include <OpenAL/alc.h>
|
|
||||||
#else
|
|
||||||
#include <AL/al.h>
|
|
||||||
#include <AL/alc.h>
|
|
||||||
/* compatibility with older versions of OpenAL */
|
|
||||||
#ifndef ALC_ALL_DEVICES_SPECIFIER
|
|
||||||
#include <AL/alext.h>
|
|
||||||
#endif /* ALC_ALL_DEVICES_SPECIFIER */
|
|
||||||
#endif /* __APPLE__ */
|
|
||||||
#endif /* AUDIO */
|
|
||||||
|
|
||||||
#include "windows.h"
|
|
||||||
#include "toxic.h"
|
|
||||||
#include "execute.h"
|
|
||||||
#include "misc_tools.h"
|
|
||||||
#include "groupchat.h"
|
|
||||||
#include "prompt.h"
|
|
||||||
#include "toxic_strings.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "line_info.h"
|
|
||||||
#include "settings.h"
|
|
||||||
#include "input.h"
|
|
||||||
#include "help.h"
|
|
||||||
#include "notify.h"
|
|
||||||
#include "autocomplete.h"
|
|
||||||
#include "audio_device.h"
|
|
||||||
|
|
||||||
extern char *DATA_FILE;
|
|
||||||
|
|
||||||
static GroupChat groupchats[MAX_GROUPCHAT_NUM];
|
|
||||||
static int max_groupchat_index = 0;
|
|
||||||
|
|
||||||
extern struct user_settings *user_settings;
|
|
||||||
extern struct Winthread Winthread;
|
|
||||||
|
|
||||||
#ifdef AUDIO
|
|
||||||
#define AC_NUM_GROUP_COMMANDS 24
|
|
||||||
#else
|
|
||||||
#define AC_NUM_GROUP_COMMANDS 20
|
|
||||||
#endif /* AUDIO */
|
|
||||||
|
|
||||||
/* Array of groupchat command names used for tab completion. */
|
|
||||||
static const char group_cmd_list[AC_NUM_GROUP_COMMANDS][MAX_CMDNAME_SIZE] = {
|
|
||||||
{ "/accept" },
|
|
||||||
{ "/add" },
|
|
||||||
{ "/avatar" },
|
|
||||||
{ "/clear" },
|
|
||||||
{ "/close" },
|
|
||||||
{ "/connect" },
|
|
||||||
{ "/decline" },
|
|
||||||
{ "/exit" },
|
|
||||||
{ "/group" },
|
|
||||||
{ "/help" },
|
|
||||||
{ "/log" },
|
|
||||||
{ "/myid" },
|
|
||||||
{ "/myqr" },
|
|
||||||
{ "/nick" },
|
|
||||||
{ "/note" },
|
|
||||||
{ "/nospam" },
|
|
||||||
{ "/quit" },
|
|
||||||
{ "/requests" },
|
|
||||||
{ "/status" },
|
|
||||||
{ "/title" },
|
|
||||||
|
|
||||||
#ifdef AUDIO
|
|
||||||
|
|
||||||
{ "/lsdev" },
|
|
||||||
{ "/sdev" },
|
|
||||||
{ "/mute" },
|
|
||||||
{ "/sense" },
|
|
||||||
|
|
||||||
#endif /* AUDIO */
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef AUDIO
|
|
||||||
static int group_audio_open_out_device(int groupnum);
|
|
||||||
static int group_audio_close_out_device(int groupnum);
|
|
||||||
#endif /* AUDIO */
|
|
||||||
|
|
||||||
int init_groupchat_win(ToxWindow *prompt, Tox *m, int 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);
|
|
||||||
|
|
||||||
#ifdef AUDIO
|
|
||||||
if (type == TOX_GROUPCHAT_TYPE_AV)
|
|
||||||
if (group_audio_open_out_device(i) == -1)
|
|
||||||
fprintf(stderr, "Group Audio failed to init\n");
|
|
||||||
#endif /* AUDIO */
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
ChatContext *ctx = self->chatwin;
|
|
||||||
|
|
||||||
log_disable(ctx->log);
|
|
||||||
line_info_cleanup(ctx->hst);
|
|
||||||
delwin(ctx->linewin);
|
|
||||||
delwin(ctx->history);
|
|
||||||
delwin(ctx->sidebar);
|
|
||||||
free(ctx->log);
|
|
||||||
free(ctx);
|
|
||||||
free(self->help);
|
|
||||||
del_window(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
void close_groupchat(ToxWindow *self, Tox *m, int groupnum)
|
|
||||||
{
|
|
||||||
tox_del_groupchat(m, groupnum);
|
|
||||||
#ifdef AUDIO
|
|
||||||
group_audio_close_out_device(groupnum);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
free(groupchats[groupnum].peer_names);
|
|
||||||
free(groupchats[groupnum].oldpeer_names);
|
|
||||||
free(groupchats[groupnum].peer_name_lengths);
|
|
||||||
free(groupchats[groupnum].oldpeer_name_lengths);
|
|
||||||
memset(&groupchats[groupnum], 0, sizeof(GroupChat));
|
|
||||||
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = max_groupchat_index; i > 0; --i) {
|
|
||||||
if (groupchats[i - 1].active)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
max_groupchat_index = i;
|
|
||||||
kill_groupchat_window(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* destroys and re-creates groupchat window with or without the peerlist */
|
|
||||||
void redraw_groupchat_win(ToxWindow *self)
|
|
||||||
{
|
|
||||||
ChatContext *ctx = self->chatwin;
|
|
||||||
|
|
||||||
endwin();
|
|
||||||
refresh();
|
|
||||||
clear();
|
|
||||||
|
|
||||||
int x2, y2;
|
|
||||||
getmaxyx(stdscr, y2, x2);
|
|
||||||
y2 -= 2;
|
|
||||||
|
|
||||||
if (y2 <= 0 || x2 <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (ctx->sidebar) {
|
|
||||||
delwin(ctx->sidebar);
|
|
||||||
ctx->sidebar = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
delwin(ctx->linewin);
|
|
||||||
delwin(ctx->history);
|
|
||||||
delwin(self->window);
|
|
||||||
|
|
||||||
self->window = newwin(y2, x2, 0, 0);
|
|
||||||
ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
|
|
||||||
|
|
||||||
if (self->show_peerlist) {
|
|
||||||
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2 - SIDEBAR_WIDTH - 1, 0, 0);
|
|
||||||
ctx->sidebar = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, SIDEBAR_WIDTH, 0, x2 - SIDEBAR_WIDTH);
|
|
||||||
} else {
|
|
||||||
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
scrollok(ctx->history, 0);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, int groupnum, int peernum,
|
|
||||||
const char *msg, uint16_t len)
|
|
||||||
{
|
|
||||||
if (self->num != groupnum)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ChatContext *ctx = self->chatwin;
|
|
||||||
|
|
||||||
char nick[TOX_MAX_NAME_LENGTH];
|
|
||||||
get_group_nick_truncate(m, nick, peernum, groupnum);
|
|
||||||
|
|
||||||
char selfnick[TOX_MAX_NAME_LENGTH];
|
|
||||||
tox_self_get_name(m, (uint8_t *) selfnick);
|
|
||||||
|
|
||||||
size_t sn_len = tox_self_get_name_size(m);
|
|
||||||
selfnick[sn_len] = '\0';
|
|
||||||
|
|
||||||
int nick_clr = strcmp(nick, selfnick) == 0 ? GREEN : CYAN;
|
|
||||||
|
|
||||||
/* Only play sound if mentioned by someone else */
|
|
||||||
if (strcasestr(msg, selfnick) && strcmp(selfnick, nick)) {
|
|
||||||
sound_notify(self, generic_message, NT_WNDALERT_0 | user_settings->bell_on_message, NULL);
|
|
||||||
|
|
||||||
if (self->active_box != -1)
|
|
||||||
box_silent_notify2(self, NT_NOFOCUS, self->active_box, "%s %s", nick, msg);
|
|
||||||
else
|
|
||||||
box_silent_notify(self, NT_NOFOCUS, &self->active_box, self->name, "%s %s", nick, msg);
|
|
||||||
|
|
||||||
nick_clr = RED;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sound_notify(self, silent, NT_WNDALERT_1, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
char timefrmt[TIME_STR_SIZE];
|
|
||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
|
||||||
|
|
||||||
line_info_add(self, timefrmt, nick, NULL, IN_MSG, 0, nick_clr, "%s", msg);
|
|
||||||
write_to_log(msg, nick, ctx->log, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void groupchat_onGroupAction(ToxWindow *self, Tox *m, int groupnum, int peernum, const char *action,
|
|
||||||
uint16_t len)
|
|
||||||
{
|
|
||||||
if (self->num != groupnum)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ChatContext *ctx = self->chatwin;
|
|
||||||
|
|
||||||
char nick[TOX_MAX_NAME_LENGTH];
|
|
||||||
get_group_nick_truncate(m, nick, peernum, groupnum);
|
|
||||||
|
|
||||||
char selfnick[TOX_MAX_NAME_LENGTH];
|
|
||||||
tox_self_get_name(m, (uint8_t *) selfnick);
|
|
||||||
|
|
||||||
size_t n_len = tox_self_get_name_size(m);
|
|
||||||
selfnick[n_len] = '\0';
|
|
||||||
|
|
||||||
if (strcasestr(action, selfnick)) {
|
|
||||||
sound_notify(self, generic_message, NT_WNDALERT_0 | user_settings->bell_on_message, NULL);
|
|
||||||
|
|
||||||
if (self->active_box != -1)
|
|
||||||
box_silent_notify2(self, NT_NOFOCUS, self->active_box, "* %s %s", nick, action );
|
|
||||||
else
|
|
||||||
box_silent_notify(self, NT_NOFOCUS, &self->active_box, self->name, "* %s %s", nick, action);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sound_notify(self, silent, NT_WNDALERT_1, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
char timefrmt[TIME_STR_SIZE];
|
|
||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
|
||||||
|
|
||||||
line_info_add(self, timefrmt, nick, NULL, IN_ACTION, 0, 0, "%s", action);
|
|
||||||
write_to_log(action, nick, ctx->log, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void groupchat_onGroupTitleChange(ToxWindow *self, Tox *m, int groupnum, int peernum, const char *title,
|
|
||||||
uint8_t length)
|
|
||||||
{
|
|
||||||
ChatContext *ctx = self->chatwin;
|
|
||||||
|
|
||||||
if (self->num != groupnum)
|
|
||||||
return;
|
|
||||||
|
|
||||||
set_window_title(self, title, length);
|
|
||||||
|
|
||||||
char timefrmt[TIME_STR_SIZE];
|
|
||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
|
||||||
|
|
||||||
/* don't announce title when we join the room */
|
|
||||||
if (!timed_out(groupchats[self->num].start_time, GROUP_EVENT_WAIT))
|
|
||||||
return;
|
|
||||||
|
|
||||||
char nick[TOX_MAX_NAME_LENGTH];
|
|
||||||
get_group_nick_truncate(m, nick, peernum, groupnum);
|
|
||||||
line_info_add(self, timefrmt, nick, NULL, NAME_CHANGE, 0, 0, " set the group title to: %s", title);
|
|
||||||
|
|
||||||
char tmp_event[MAX_STR_SIZE];
|
|
||||||
snprintf(tmp_event, sizeof(tmp_event), "set title to %s", title);
|
|
||||||
write_to_log(tmp_event, nick, ctx->log, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Puts two copies of peerlist/lengths in chat instance */
|
|
||||||
static void copy_peernames(int gnum, uint8_t peerlist[][TOX_MAX_NAME_LENGTH], uint16_t lengths[], int npeers)
|
|
||||||
{
|
|
||||||
/* Assumes these are initiated in init_groupchat_win */
|
|
||||||
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;
|
|
||||||
|
|
||||||
groupchats[gnum].peer_names = malloc(sizeof(uint8_t) * npeers * N);
|
|
||||||
groupchats[gnum].oldpeer_names = malloc(sizeof(uint8_t) * npeers * N);
|
|
||||||
groupchats[gnum].peer_name_lengths = malloc(sizeof(uint16_t) * npeers);
|
|
||||||
groupchats[gnum].oldpeer_name_lengths = malloc(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);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < npeers; ++i) {
|
|
||||||
if (!lengths[i]) {
|
|
||||||
memcpy(&groupchats[gnum].peer_names[i * N], UNKNOWN_NAME, u_len);
|
|
||||||
groupchats[gnum].peer_names[i * N + u_len] = '\0';
|
|
||||||
groupchats[gnum].peer_name_lengths[i] = u_len;
|
|
||||||
} else {
|
|
||||||
uint16_t n_len = MIN(lengths[i], TOXIC_MAX_NAME_LENGTH - 1);
|
|
||||||
memcpy(&groupchats[gnum].peer_names[i * N], peerlist[i], 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);
|
|
||||||
memcpy(groupchats[gnum].oldpeer_name_lengths, groupchats[gnum].peer_name_lengths, sizeof(uint16_t) * npeers);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct group_add_thrd {
|
|
||||||
Tox *m;
|
|
||||||
ToxWindow *self;
|
|
||||||
int peernum;
|
|
||||||
int 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 */
|
|
||||||
void *group_add_wait(void *data)
|
|
||||||
{
|
|
||||||
struct group_add_thrd *thrd = (struct group_add_thrd *) data;
|
|
||||||
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, int groupnum, int peernum, uint8_t change)
|
|
||||||
{
|
|
||||||
if (self->num != groupnum)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (groupnum > max_groupchat_index)
|
|
||||||
return;
|
|
||||||
|
|
||||||
groupchats[groupnum].num_peers = tox_group_number_peers(m, groupnum);
|
|
||||||
int num_peers = groupchats[groupnum].num_peers;
|
|
||||||
|
|
||||||
if (peernum > num_peers)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* get old peer name before updating name list */
|
|
||||||
uint8_t oldpeername[TOX_MAX_NAME_LENGTH];
|
|
||||||
|
|
||||||
if (change != TOX_CHAT_CHANGE_PEER_ADD) {
|
|
||||||
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 */
|
|
||||||
uint8_t tmp_peerlist[num_peers][TOX_MAX_NAME_LENGTH];
|
|
||||||
uint16_t tmp_peerlens[num_peers];
|
|
||||||
|
|
||||||
if (tox_group_get_names(m, groupnum, tmp_peerlist, tmp_peerlens, num_peers) == -1) {
|
|
||||||
memset(tmp_peerlist, 0, sizeof(tmp_peerlist));
|
|
||||||
memset(tmp_peerlens, 0, sizeof(tmp_peerlens));
|
|
||||||
}
|
|
||||||
|
|
||||||
copy_peernames(groupnum, tmp_peerlist, tmp_peerlens, num_peers);
|
|
||||||
|
|
||||||
/* get current peername then sort namelist */
|
|
||||||
uint8_t peername[TOX_MAX_NAME_LENGTH];
|
|
||||||
|
|
||||||
if (change != TOX_CHAT_CHANGE_PEER_DEL) {
|
|
||||||
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);
|
|
||||||
|
|
||||||
ChatContext *ctx = self->chatwin;
|
|
||||||
|
|
||||||
const char *event;
|
|
||||||
char timefrmt[TIME_STR_SIZE];
|
|
||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
|
||||||
|
|
||||||
switch (change) {
|
|
||||||
case TOX_CHAT_CHANGE_PEER_ADD:
|
|
||||||
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_CHAT_CHANGE_PEER_DEL:
|
|
||||||
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_CHAT_CHANGE_PEER_NAME:
|
|
||||||
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];
|
|
||||||
snprintf(tmp_event, sizeof(tmp_event), "is now known as %s", (char *) peername);
|
|
||||||
write_to_log(tmp_event, (char *) oldpeername, ctx->log, true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
sound_notify(self, silent, NT_WNDALERT_2, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void send_group_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
|
|
||||||
{
|
|
||||||
if (action == NULL) {
|
|
||||||
wprintw(ctx->history, "Invalid syntax.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tox_group_action_send(m, self->num, (uint8_t *) action, strlen(action)) == -1) {
|
|
||||||
const char *errmsg = " * Failed to send action.";
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, errmsg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|
||||||
{
|
|
||||||
ChatContext *ctx = self->chatwin;
|
|
||||||
|
|
||||||
int x, y, y2, x2;
|
|
||||||
getyx(self->window, y, x);
|
|
||||||
getmaxyx(self->window, y2, x2);
|
|
||||||
|
|
||||||
if (x2 <= 0 || y2 <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (self->help->active) {
|
|
||||||
help_onKey(self, key);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctx->pastemode && key == '\r')
|
|
||||||
key = '\n';
|
|
||||||
|
|
||||||
if (ltr || key == '\n') { /* char is printable */
|
|
||||||
input_new_char(self, key, x, y, x2, y2);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line_info_onKey(self, key))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (input_handle(self, key, x, y, x2, y2))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (key == '\t') { /* TAB key: auto-completes peer name or command */
|
|
||||||
if (ctx->len > 0) {
|
|
||||||
int diff;
|
|
||||||
|
|
||||||
/* TODO: make this not suck */
|
|
||||||
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,
|
|
||||||
TOX_MAX_NAME_LENGTH);
|
|
||||||
} else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) {
|
|
||||||
diff = dir_match(self, m, ctx->line, L"/avatar");
|
|
||||||
} else {
|
|
||||||
diff = complete_line(self, group_cmd_list, AC_NUM_GROUP_COMMANDS, MAX_CMDNAME_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (diff != -1) {
|
|
||||||
if (x + diff > x2 - 1) {
|
|
||||||
int wlen = MAX(0, wcswidth(ctx->line, sizeof(ctx->line) / sizeof(wchar_t)));
|
|
||||||
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sound_notify(self, notif_error, 0, NULL);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sound_notify(self, notif_error, 0, NULL);
|
|
||||||
}
|
|
||||||
} else if (key == user_settings->key_peer_list_down) { /* Scroll peerlist up and down one position */
|
|
||||||
int L = y2 - CHATBOX_HEIGHT - SDBAR_OFST;
|
|
||||||
|
|
||||||
if (groupchats[self->num].side_pos < groupchats[self->num].num_peers - L)
|
|
||||||
++groupchats[self->num].side_pos;
|
|
||||||
} else if (key == user_settings->key_peer_list_up) {
|
|
||||||
if (groupchats[self->num].side_pos > 0)
|
|
||||||
--groupchats[self->num].side_pos;
|
|
||||||
} else if (key == '\r') {
|
|
||||||
rm_trailing_spaces_buf(ctx);
|
|
||||||
|
|
||||||
if (!wstring_is_empty(ctx->line))
|
|
||||||
{
|
|
||||||
add_line_to_hist(ctx);
|
|
||||||
|
|
||||||
wstrsubst(ctx->line, L'¶', L'\n');
|
|
||||||
|
|
||||||
char line[MAX_STR_SIZE];
|
|
||||||
|
|
||||||
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
|
|
||||||
memset(&line, 0, sizeof(line));
|
|
||||||
|
|
||||||
if (line[0] == '/') {
|
|
||||||
if (strcmp(line, "/close") == 0) {
|
|
||||||
close_groupchat(self, m, self->num);
|
|
||||||
return;
|
|
||||||
} else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
|
|
||||||
send_group_action(self, ctx, m, line + strlen("/me "));
|
|
||||||
} else {
|
|
||||||
execute(ctx->history, self, m, line, GROUPCHAT_COMMAND_MODE);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (tox_group_message_send(m, self->num, (uint8_t *) line, strlen(line)) == -1) {
|
|
||||||
const char *errmsg = " * Failed to send message.";
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, errmsg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wclear(ctx->linewin);
|
|
||||||
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
|
||||||
reset_buf(ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void groupchat_onDraw(ToxWindow *self, Tox *m)
|
|
||||||
{
|
|
||||||
int x2, y2;
|
|
||||||
getmaxyx(self->window, y2, x2);
|
|
||||||
|
|
||||||
if (x2 <= 0 || y2 <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ChatContext *ctx = self->chatwin;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
|
||||||
line_info_print(self);
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
|
||||||
|
|
||||||
wclear(ctx->linewin);
|
|
||||||
|
|
||||||
curs_set(1);
|
|
||||||
|
|
||||||
if (ctx->len > 0)
|
|
||||||
mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]);
|
|
||||||
|
|
||||||
wclear(ctx->sidebar);
|
|
||||||
mvwhline(self->window, y2 - CHATBOX_HEIGHT, 0, ACS_HLINE, x2);
|
|
||||||
|
|
||||||
if (self->show_peerlist) {
|
|
||||||
mvwvline(ctx->sidebar, 0, 0, ACS_VLINE, y2 - CHATBOX_HEIGHT);
|
|
||||||
mvwaddch(ctx->sidebar, y2 - CHATBOX_HEIGHT, 0, ACS_BTEE);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
|
||||||
int num_peers = groupchats[self->num].num_peers;
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
|
||||||
|
|
||||||
wmove(ctx->sidebar, 0, 1);
|
|
||||||
wattron(ctx->sidebar, A_BOLD);
|
|
||||||
wprintw(ctx->sidebar, "Peers: %d\n", num_peers);
|
|
||||||
wattroff(ctx->sidebar, A_BOLD);
|
|
||||||
|
|
||||||
mvwaddch(ctx->sidebar, 1, 0, ACS_LTEE);
|
|
||||||
mvwhline(ctx->sidebar, 1, 1, ACS_HLINE, SIDEBAR_WIDTH - 1);
|
|
||||||
|
|
||||||
int maxlines = y2 - SDBAR_OFST - CHATBOX_HEIGHT;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < num_peers && i < maxlines; ++i) {
|
|
||||||
wmove(ctx->sidebar, i + 2, 1);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
|
||||||
int peer = i + groupchats[self->num].side_pos;
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
|
||||||
|
|
||||||
/* truncate nick to fit in side panel without modifying list */
|
|
||||||
char tmpnck[TOX_MAX_NAME_LENGTH];
|
|
||||||
int maxlen = SIDEBAR_WIDTH - 2;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
|
||||||
memcpy(tmpnck, &groupchats[self->num].peer_names[peer * TOX_MAX_NAME_LENGTH], maxlen);
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
|
||||||
|
|
||||||
tmpnck[maxlen] = '\0';
|
|
||||||
|
|
||||||
wprintw(ctx->sidebar, "%s\n", tmpnck);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int y, x;
|
|
||||||
getyx(self->window, y, x);
|
|
||||||
(void) x;
|
|
||||||
int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
|
|
||||||
wmove(self->window, y + 1, new_x);
|
|
||||||
|
|
||||||
wrefresh(self->window);
|
|
||||||
|
|
||||||
if (self->help->active)
|
|
||||||
help_onDraw(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void groupchat_onInit(ToxWindow *self, Tox *m)
|
|
||||||
{
|
|
||||||
int x2, y2;
|
|
||||||
getmaxyx(self->window, y2, x2);
|
|
||||||
|
|
||||||
if (x2 <= 0 || y2 <= 0)
|
|
||||||
exit_toxic_err("failed in groupchat_onInit", FATALERR_CURSES);
|
|
||||||
|
|
||||||
ChatContext *ctx = self->chatwin;
|
|
||||||
|
|
||||||
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2 - SIDEBAR_WIDTH - 1, 0, 0);
|
|
||||||
ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
|
|
||||||
ctx->sidebar = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, SIDEBAR_WIDTH, 0, x2 - SIDEBAR_WIDTH);
|
|
||||||
|
|
||||||
ctx->hst = calloc(1, sizeof(struct history));
|
|
||||||
ctx->log = calloc(1, sizeof(struct chatlog));
|
|
||||||
|
|
||||||
if (ctx->log == NULL || ctx->hst == NULL)
|
|
||||||
exit_toxic_err("failed in groupchat_onInit", FATALERR_MEMORY);
|
|
||||||
|
|
||||||
line_info_init(ctx->hst);
|
|
||||||
|
|
||||||
if (user_settings->autolog == AUTOLOG_ON) {
|
|
||||||
char myid[TOX_ADDRESS_SIZE];
|
|
||||||
tox_self_get_address(m, (uint8_t *) myid);
|
|
||||||
|
|
||||||
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.");
|
|
||||||
}
|
|
||||||
|
|
||||||
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
|
|
||||||
|
|
||||||
scrollok(ctx->history, 0);
|
|
||||||
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef AUDIO
|
|
||||||
static int group_audio_open_out_device(int groupnum)
|
|
||||||
{
|
|
||||||
char dname[MAX_STR_SIZE];
|
|
||||||
get_primary_device_name(output, dname, sizeof(dname));
|
|
||||||
dname[MAX_STR_SIZE - 1] = '\0';
|
|
||||||
|
|
||||||
groupchats[groupnum].audio.dvhandle = alcOpenDevice(dname);
|
|
||||||
|
|
||||||
if (groupchats[groupnum].audio.dvhandle == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
groupchats[groupnum].audio.dvctx = alcCreateContext(groupchats[groupnum].audio.dvhandle, NULL);
|
|
||||||
alcMakeContextCurrent(groupchats[groupnum].audio.dvctx);
|
|
||||||
alGenBuffers(OPENAL_BUFS, groupchats[groupnum].audio.buffers);
|
|
||||||
alGenSources((uint32_t) 1, &groupchats[groupnum].audio.source);
|
|
||||||
alSourcei(groupchats[groupnum].audio.source, AL_LOOPING, AL_FALSE);
|
|
||||||
|
|
||||||
if (alcGetError(groupchats[groupnum].audio.dvhandle) != AL_NO_ERROR) {
|
|
||||||
group_audio_close_out_device(groupnum);
|
|
||||||
groupchats[groupnum].audio.dvhandle = NULL;
|
|
||||||
groupchats[groupnum].audio.dvctx = NULL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
alSourceQueueBuffers(groupchats[groupnum].audio.source, OPENAL_BUFS, groupchats[groupnum].audio.buffers);
|
|
||||||
alSourcePlay(groupchats[groupnum].audio.source);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int group_audio_close_out_device(int groupnum)
|
|
||||||
{
|
|
||||||
if (!groupchats[groupnum].audio.dvhandle)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (!groupchats[groupnum].audio.dvctx)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (alcGetCurrentContext() != groupchats[groupnum].audio.dvctx)
|
|
||||||
alcMakeContextCurrent(groupchats[groupnum].audio.dvctx);
|
|
||||||
|
|
||||||
alDeleteSources((uint32_t) 1, &groupchats[groupnum].audio.source);
|
|
||||||
alDeleteBuffers(OPENAL_BUFS, groupchats[groupnum].audio.buffers);
|
|
||||||
|
|
||||||
alcMakeContextCurrent(NULL);
|
|
||||||
alcDestroyContext(groupchats[groupnum].audio.dvctx);
|
|
||||||
|
|
||||||
if (!alcCloseDevice(groupchats[groupnum].audio.dvhandle))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// static int group_audio_write(int peernum, int groupnum, const int16_t *pcm, unsigned int samples, uint8_t channels,
|
|
||||||
// unsigned int sample_rate)
|
|
||||||
// {
|
|
||||||
// if (!pcm)
|
|
||||||
// return -1;
|
|
||||||
|
|
||||||
// if (channels == 0 || channels > 2)
|
|
||||||
// return -2;
|
|
||||||
|
|
||||||
// ALuint bufid;
|
|
||||||
// ALint processed = 0, queued = 0;
|
|
||||||
|
|
||||||
// alGetSourcei(groupchats[groupnum].audio.source, AL_BUFFERS_PROCESSED, &processed);
|
|
||||||
// alGetSourcei(groupchats[groupnum].audio.source, AL_BUFFERS_QUEUED, &queued);
|
|
||||||
// fprintf(stderr, "source: %d, queued: %d, processed: %d\n", groupchats[groupnum].audio.source, queued, processed);
|
|
||||||
|
|
||||||
// if (processed) {
|
|
||||||
// ALuint bufids[processed];
|
|
||||||
// alSourceUnqueueBuffers(groupchats[groupnum].audio.source, processed, bufids);
|
|
||||||
// alDeleteBuffers(processed - 1, bufids + 1);
|
|
||||||
// bufid = bufids[0];
|
|
||||||
// } else if (queued < 16) {
|
|
||||||
// alGenBuffers(1, &bufid);
|
|
||||||
// } else {
|
|
||||||
// return -3;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// int length = samples * channels * sizeof(int16_t);
|
|
||||||
|
|
||||||
// alBufferData(bufid, (channels == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, pcm, length, sample_rate);
|
|
||||||
// alSourceQueueBuffers(groupchats[groupnum].audio.source, 1, &bufid);
|
|
||||||
|
|
||||||
// ALint state;
|
|
||||||
// alGetSourcei(groupchats[groupnum].audio.source, AL_SOURCE_STATE, &state);
|
|
||||||
|
|
||||||
// if (state != AL_PLAYING)
|
|
||||||
// alSourcePlay(groupchats[groupnum].audio.source);
|
|
||||||
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
static void groupchat_onWriteDevice(ToxWindow *self, Tox *m, uint32_t groupnum, int peernum, const int16_t *pcm,
|
|
||||||
unsigned int samples, uint8_t channels, unsigned int sample_rate)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
|
|
||||||
// if (groupnum != self->num)
|
|
||||||
// return;
|
|
||||||
|
|
||||||
// if (peernum < 0)
|
|
||||||
// return;
|
|
||||||
|
|
||||||
// if (groupchats[groupnum].audio.dvhandle == NULL)
|
|
||||||
// fprintf(stderr, "dvhandle is null)\n");
|
|
||||||
|
|
||||||
// if (groupchats[groupnum].audio.dvctx == NULL)
|
|
||||||
// fprintf(stderr, "ctx is null\n");
|
|
||||||
|
|
||||||
// int ret = group_audio_write(peernum, groupnum, pcm, samples, channels, sample_rate);
|
|
||||||
// fprintf(stderr, "write: %d\n", ret);
|
|
||||||
}
|
|
||||||
#endif /* AUDIO */
|
|
||||||
|
|
||||||
ToxWindow new_group_chat(Tox *m, int groupnum)
|
|
||||||
{
|
|
||||||
ToxWindow ret;
|
|
||||||
memset(&ret, 0, sizeof(ret));
|
|
||||||
|
|
||||||
ret.active = true;
|
|
||||||
ret.is_groupchat = true;
|
|
||||||
|
|
||||||
ret.onKey = &groupchat_onKey;
|
|
||||||
ret.onDraw = &groupchat_onDraw;
|
|
||||||
ret.onInit = &groupchat_onInit;
|
|
||||||
ret.onGroupMessage = &groupchat_onGroupMessage;
|
|
||||||
ret.onGroupNamelistChange = &groupchat_onGroupNamelistChange;
|
|
||||||
ret.onGroupAction = &groupchat_onGroupAction;
|
|
||||||
ret.onGroupTitleChange = &groupchat_onGroupTitleChange;
|
|
||||||
|
|
||||||
#ifdef AUDIO
|
|
||||||
ret.onWriteDevice = &groupchat_onWriteDevice;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
snprintf(ret.name, sizeof(ret.name), "Group %d", groupnum);
|
|
||||||
|
|
||||||
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
|
|
||||||
Help *help = calloc(1, sizeof(Help));
|
|
||||||
|
|
||||||
if (chatwin == NULL || help == NULL)
|
|
||||||
exit_toxic_err("failed in new_group_chat", FATALERR_MEMORY);
|
|
||||||
|
|
||||||
ret.chatwin = chatwin;
|
|
||||||
ret.help = help;
|
|
||||||
|
|
||||||
ret.num = groupnum;
|
|
||||||
ret.show_peerlist = true;
|
|
||||||
ret.active_box = -1;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
/* groupchat.h
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Copyright (C) 2014 Toxic All Rights Reserved.
|
|
||||||
*
|
|
||||||
* This file is part of Toxic.
|
|
||||||
*
|
|
||||||
* Toxic is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Toxic is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef GROUPCHAT_H
|
|
||||||
#define GROUPCHAT_H
|
|
||||||
|
|
||||||
#include "toxic.h"
|
|
||||||
#include "windows.h"
|
|
||||||
|
|
||||||
#ifdef AUDIO
|
|
||||||
#include "audio_call.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef AUDIO
|
|
||||||
#ifdef __APPLE__
|
|
||||||
#include <OpenAL/al.h>
|
|
||||||
#include <OpenAL/alc.h>
|
|
||||||
#else
|
|
||||||
#include <AL/al.h>
|
|
||||||
#include <AL/alc.h>
|
|
||||||
/* compatibility with older versions of OpenAL */
|
|
||||||
#ifndef ALC_ALL_DEVICES_SPECIFIER
|
|
||||||
#include <AL/alext.h>
|
|
||||||
#endif /* ALC_ALL_DEVICES_SPECIFIER */
|
|
||||||
#endif /* __APPLE__ */
|
|
||||||
#endif /* AUDIO */
|
|
||||||
|
|
||||||
#define SIDEBAR_WIDTH 16
|
|
||||||
#define SDBAR_OFST 2 /* Offset for the peer number box at the top of the statusbar */
|
|
||||||
#define MAX_GROUPCHAT_NUM MAX_WINDOWS_NUM - 2
|
|
||||||
#define GROUP_EVENT_WAIT 3
|
|
||||||
|
|
||||||
#ifdef AUDIO
|
|
||||||
struct GAudio {
|
|
||||||
ALCdevice *dvhandle; /* Handle of device selected/opened */
|
|
||||||
ALCcontext *dvctx;
|
|
||||||
ALuint source;
|
|
||||||
ALuint buffers[OPENAL_BUFS];
|
|
||||||
};
|
|
||||||
#endif /* AUDIO */
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int chatwin;
|
|
||||||
bool active;
|
|
||||||
uint8_t type;
|
|
||||||
int num_peers;
|
|
||||||
int side_pos; /* current position of the sidebar - used for scrolling up and down */
|
|
||||||
time_t start_time;
|
|
||||||
uint8_t *peer_names;
|
|
||||||
uint8_t *oldpeer_names;
|
|
||||||
uint16_t *peer_name_lengths;
|
|
||||||
uint16_t *oldpeer_name_lengths;
|
|
||||||
|
|
||||||
#ifdef AUDIO
|
|
||||||
struct GAudio audio;
|
|
||||||
#endif
|
|
||||||
} GroupChat;
|
|
||||||
|
|
||||||
void close_groupchat(ToxWindow *self, Tox *m, int groupnum);
|
|
||||||
int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum, uint8_t type);
|
|
||||||
|
|
||||||
/* destroys and re-creates groupchat window with or without the peerlist */
|
|
||||||
void redraw_groupchat_win(ToxWindow *self);
|
|
||||||
|
|
||||||
ToxWindow new_group_chat(Tox *m, int groupnum);
|
|
||||||
|
|
||||||
#endif /* #define GROUPCHAT_H */
|
|
186
src/help.c
186
src/help.c
@ -22,24 +22,34 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "windows.h"
|
|
||||||
#include "toxic.h"
|
|
||||||
#include "help.h"
|
#include "help.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
|
#ifdef PYTHON
|
||||||
|
#include "api.h"
|
||||||
|
#endif /* PYTHON */
|
||||||
|
|
||||||
|
#ifdef PYTHON
|
||||||
|
#define HELP_MENU_HEIGHT 10
|
||||||
|
#else
|
||||||
#define HELP_MENU_HEIGHT 9
|
#define HELP_MENU_HEIGHT 9
|
||||||
|
#endif /* PYTHON */
|
||||||
#define HELP_MENU_WIDTH 26
|
#define HELP_MENU_WIDTH 26
|
||||||
|
|
||||||
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;
|
||||||
@ -49,19 +59,24 @@ void help_init_menu(ToxWindow *self)
|
|||||||
static void help_exit(ToxWindow *self)
|
static void help_exit(ToxWindow *self)
|
||||||
{
|
{
|
||||||
delwin(self->help->win);
|
delwin(self->help->win);
|
||||||
memset(self->help, 0, sizeof(Help));
|
|
||||||
|
*(self->help) = (struct Help) {
|
||||||
|
0
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
@ -89,11 +104,18 @@ static void help_draw_menu(ToxWindow *self)
|
|||||||
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||||
wprintw(win, "hat commands\n");
|
wprintw(win, "hat commands\n");
|
||||||
|
|
||||||
wprintw(win, " g");
|
wprintw(win, " c");
|
||||||
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
|
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||||
wprintw(win, "r");
|
wprintw(win, "o");
|
||||||
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||||
wprintw(win, "oup commands\n");
|
wprintw(win, "nference commands\n");
|
||||||
|
|
||||||
|
#ifdef PYTHON
|
||||||
|
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||||
|
wprintw(win, " p");
|
||||||
|
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||||
|
wprintw(win, "lugin commands\n");
|
||||||
|
#endif /* PYTHON */
|
||||||
|
|
||||||
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
|
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||||
wprintw(win, " f");
|
wprintw(win, " f");
|
||||||
@ -112,14 +134,15 @@ static void help_draw_menu(ToxWindow *self)
|
|||||||
wprintw(win, "it menu\n");
|
wprintw(win, "it menu\n");
|
||||||
|
|
||||||
box(win, ACS_VLINE, ACS_HLINE);
|
box(win, ACS_VLINE, ACS_HLINE);
|
||||||
wrefresh(win);
|
wnoutrefresh(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void help_draw_bottom_menu(WINDOW *win)
|
static void help_draw_bottom_menu(WINDOW *win)
|
||||||
{
|
{
|
||||||
int y2, x2;
|
int y2, x2;
|
||||||
getmaxyx(win, y2, x2);
|
getmaxyx(win, y2, x2);
|
||||||
(void) x2;
|
|
||||||
|
UNUSED_VAR(x2);
|
||||||
|
|
||||||
wmove(win, y2 - 2, 1);
|
wmove(win, y2 - 2, 1);
|
||||||
|
|
||||||
@ -156,9 +179,15 @@ static void help_draw_global(ToxWindow *self)
|
|||||||
wprintw(win, " /nick <nick> : Set your nickname\n");
|
wprintw(win, " /nick <nick> : Set your nickname\n");
|
||||||
wprintw(win, " /nospam <value> : Change part of your Tox ID to stop spam\n");
|
wprintw(win, " /nospam <value> : Change part of your Tox ID to stop spam\n");
|
||||||
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, " /conference <type> : Create a conference 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
|
||||||
|
wprintw(win, " /myqr <txt> or <png> : Print your Tox ID's QR code to a file.\n");
|
||||||
|
#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 /* 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");
|
||||||
@ -181,10 +210,18 @@ static void help_draw_global(ToxWindow *self)
|
|||||||
wprintw(win, " /svdev <type> <id> : Set active video device\n");
|
wprintw(win, " /svdev <type> <id> : Set active video device\n");
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
|
|
||||||
|
#ifdef PYTHON
|
||||||
|
wattron(win, A_BOLD);
|
||||||
|
wprintw(win, "\n Scripting:\n");
|
||||||
|
wattroff(win, A_BOLD);
|
||||||
|
|
||||||
|
wprintw(win, " /run <path> : Load and run the script at path\n");
|
||||||
|
#endif /* PYTHON */
|
||||||
|
|
||||||
help_draw_bottom_menu(win);
|
help_draw_bottom_menu(win);
|
||||||
|
|
||||||
box(win, ACS_VLINE, ACS_HLINE);
|
box(win, ACS_VLINE, ACS_HLINE);
|
||||||
wrefresh(win);
|
wnoutrefresh(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void help_draw_chat(ToxWindow *self)
|
static void help_draw_chat(ToxWindow *self)
|
||||||
@ -197,8 +234,8 @@ static void help_draw_chat(ToxWindow *self)
|
|||||||
wprintw(win, "Chat Commands:\n");
|
wprintw(win, "Chat Commands:\n");
|
||||||
wattroff(win, A_BOLD | COLOR_PAIR(RED));
|
wattroff(win, A_BOLD | COLOR_PAIR(RED));
|
||||||
|
|
||||||
wprintw(win, " /invite <n> : Invite contact to a group chat\n");
|
wprintw(win, " /invite <n> : Invite contact to a conference \n");
|
||||||
wprintw(win, " /join : Join a pending group chat\n");
|
wprintw(win, " /join : Join a pending conference\n");
|
||||||
wprintw(win, " /sendfile <path> : Send a file\n");
|
wprintw(win, " /sendfile <path> : Send a file\n");
|
||||||
wprintw(win, " /savefile <id> : Receive a file\n");
|
wprintw(win, " /savefile <id> : Receive a file\n");
|
||||||
wprintw(win, " /cancel <type> <id> : Cancel file transfer where type: in|out\n");
|
wprintw(win, " /cancel <type> <id> : Cancel file transfer where type: in|out\n");
|
||||||
@ -215,19 +252,22 @@ static void help_draw_chat(ToxWindow *self)
|
|||||||
wprintw(win, " /sdev <type> <id> : Change active device\n");
|
wprintw(win, " /sdev <type> <id> : Change active device\n");
|
||||||
wprintw(win, " /mute <type> : Mute active device if in call\n");
|
wprintw(win, " /mute <type> : Mute active device if in call\n");
|
||||||
wprintw(win, " /sense <n> : VAD sensitivity threshold\n");
|
wprintw(win, " /sense <n> : VAD sensitivity threshold\n");
|
||||||
|
wprintw(win, " /bitrate <n> : Set the audio encoding bitrate\n");
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
wattron(win, A_BOLD);
|
wattron(win, A_BOLD);
|
||||||
wprintw(win, "\n Video:\n");
|
wprintw(win, "\n Video:\n");
|
||||||
wattroff(win, A_BOLD);
|
wattroff(win, A_BOLD);
|
||||||
wprintw(win, " /video : Toggle video call\n");
|
wprintw(win, " /res <width> <height> : Set video resolution\n");
|
||||||
|
wprintw(win, " /vcall : Video call\n");
|
||||||
|
wprintw(win, " /video : Toggle video in call\n");
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
|
|
||||||
help_draw_bottom_menu(win);
|
help_draw_bottom_menu(win);
|
||||||
|
|
||||||
box(win, ACS_VLINE, ACS_HLINE);
|
box(win, ACS_VLINE, ACS_HLINE);
|
||||||
wrefresh(win);
|
wnoutrefresh(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void help_draw_keys(ToxWindow *self)
|
static void help_draw_keys(ToxWindow *self)
|
||||||
@ -244,8 +284,8 @@ static void help_draw_keys(ToxWindow *self)
|
|||||||
wprintw(win, " Page Up and Page Down : Scroll window history one line\n");
|
wprintw(win, " Page Up and Page Down : Scroll window history one line\n");
|
||||||
wprintw(win, " Ctrl+F and Ctrl+V : Scroll window history half a page\n");
|
wprintw(win, " Ctrl+F and Ctrl+V : Scroll window history half a page\n");
|
||||||
wprintw(win, " Ctrl+H : Move to the bottom of window history\n");
|
wprintw(win, " Ctrl+H : Move to the bottom of window history\n");
|
||||||
wprintw(win, " Ctrl+[ and Ctrl+] : Scroll peer list in groupchats\n");
|
wprintw(win, " Ctrl+up and Ctrl+down : Scroll peer list in conference\n");
|
||||||
wprintw(win, " Ctrl+B : Toggle the groupchat peerlist\n");
|
wprintw(win, " Ctrl+B : Toggle the conference peerlist\n");
|
||||||
wprintw(win, " Ctrl+J : Insert new line\n");
|
wprintw(win, " Ctrl+J : Insert new line\n");
|
||||||
wprintw(win, " Ctrl+T : Toggle paste mode\n\n");
|
wprintw(win, " Ctrl+T : Toggle paste mode\n\n");
|
||||||
wprintw(win, " (Note: Custom keybindings override these defaults.)\n\n");
|
wprintw(win, " (Note: Custom keybindings override these defaults.)\n\n");
|
||||||
@ -253,27 +293,57 @@ static void help_draw_keys(ToxWindow *self)
|
|||||||
help_draw_bottom_menu(win);
|
help_draw_bottom_menu(win);
|
||||||
|
|
||||||
box(win, ACS_VLINE, ACS_HLINE);
|
box(win, ACS_VLINE, ACS_HLINE);
|
||||||
wrefresh(win);
|
wnoutrefresh(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void help_draw_group(ToxWindow *self)
|
static void help_draw_conference(ToxWindow *self)
|
||||||
{
|
{
|
||||||
WINDOW *win = self->help->win;
|
WINDOW *win = self->help->win;
|
||||||
|
|
||||||
wmove(win, 1, 1);
|
wmove(win, 1, 1);
|
||||||
|
|
||||||
wattron(win, A_BOLD | COLOR_PAIR(RED));
|
wattron(win, A_BOLD | COLOR_PAIR(RED));
|
||||||
wprintw(win, "Group commands:\n");
|
wprintw(win, "Conference commands:\n");
|
||||||
wattroff(win, A_BOLD | COLOR_PAIR(RED));
|
wattroff(win, A_BOLD | COLOR_PAIR(RED));
|
||||||
|
|
||||||
wprintw(win, " /title <msg> : Set group title (show current title if no msg)\n\n");
|
wprintw(win, " /title <msg> : Show/set conference title\n");
|
||||||
|
#ifdef AUDIO
|
||||||
|
wattron(win, A_BOLD);
|
||||||
|
wprintw(win, "\n Audio:\n");
|
||||||
|
wattroff(win, A_BOLD);
|
||||||
|
wprintw(win, " /audio <on> or <off> : Enable/disable audio in an audio conference\n");
|
||||||
|
wprintw(win, " /mute : Toggle self audio mute status\n");
|
||||||
|
wprintw(win, " /mute <nick> or <pubkey> : Toggle peer audio mute status\n");
|
||||||
|
wprintw(win, " /ptt <on> or <off> : Toggle audio input Push-To-Talk (F2 to activate)\n");
|
||||||
|
wprintw(win, " /sense <n> : VAD sensitivity threshold\n\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
help_draw_bottom_menu(win);
|
help_draw_bottom_menu(win);
|
||||||
|
|
||||||
box(win, ACS_VLINE, ACS_HLINE);
|
box(win, ACS_VLINE, ACS_HLINE);
|
||||||
wrefresh(win);
|
wnoutrefresh(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef PYTHON
|
||||||
|
static void help_draw_plugin(ToxWindow *self)
|
||||||
|
{
|
||||||
|
WINDOW *win = self->help->win;
|
||||||
|
|
||||||
|
wmove(win, 1, 1);
|
||||||
|
|
||||||
|
wattron(win, A_BOLD | COLOR_PAIR(RED));
|
||||||
|
wprintw(win, "Plugin commands:\n");
|
||||||
|
wattroff(win, A_BOLD | COLOR_PAIR(RED));
|
||||||
|
|
||||||
|
draw_handler_help(win);
|
||||||
|
|
||||||
|
help_draw_bottom_menu(win);
|
||||||
|
|
||||||
|
box(win, ACS_VLINE, ACS_HLINE);
|
||||||
|
wnoutrefresh(win);
|
||||||
|
}
|
||||||
|
#endif /* PYTHON */
|
||||||
|
|
||||||
static void help_draw_contacts(ToxWindow *self)
|
static void help_draw_contacts(ToxWindow *self)
|
||||||
{
|
{
|
||||||
WINDOW *win = self->help->win;
|
WINDOW *win = self->help->win;
|
||||||
@ -293,55 +363,72 @@ static void help_draw_contacts(ToxWindow *self)
|
|||||||
help_draw_bottom_menu(win);
|
help_draw_bottom_menu(win);
|
||||||
|
|
||||||
box(win, ACS_VLINE, ACS_HLINE);
|
box(win, ACS_VLINE, ACS_HLINE);
|
||||||
wrefresh(win);
|
wnoutrefresh(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
void help_onKey(ToxWindow *self, wint_t key)
|
void help_onKey(ToxWindow *self, wint_t key)
|
||||||
{
|
{
|
||||||
switch(key) {
|
int height;
|
||||||
case 'x':
|
|
||||||
|
switch (key) {
|
||||||
|
case L'x':
|
||||||
case T_KEY_ESC:
|
case T_KEY_ESC:
|
||||||
help_exit(self);
|
help_exit(self);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'c':
|
case L'c':
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
help_init_window(self, 22, 80);
|
help_init_window(self, 25, 80);
|
||||||
#elif AUDIO
|
#elif AUDIO
|
||||||
help_init_window(self, 19, 80);
|
help_init_window(self, 20, 80);
|
||||||
#else
|
#else
|
||||||
help_init_window(self, 10, 80);
|
help_init_window(self, 10, 80);
|
||||||
#endif
|
#endif
|
||||||
self->help->type = HELP_CHAT;
|
self->help->type = HELP_CHAT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'g':
|
case L'g':
|
||||||
|
height = 22;
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
help_init_window(self, 30, 80);
|
height += 8;
|
||||||
#elif AUDIO
|
#elif AUDIO
|
||||||
help_init_window(self, 26, 80);
|
height += 4;
|
||||||
#else
|
|
||||||
help_init_window(self, 22, 80);
|
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef PYTHON
|
||||||
|
height += 2;
|
||||||
|
#endif
|
||||||
|
help_init_window(self, height, 80);
|
||||||
self->help->type = HELP_GLOBAL;
|
self->help->type = HELP_GLOBAL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'r':
|
case L'o':
|
||||||
help_init_window(self, 6, 80);
|
height = 6;
|
||||||
self->help->type = HELP_GROUP;
|
#ifdef AUDIO
|
||||||
|
height += 7;
|
||||||
|
#endif
|
||||||
|
help_init_window(self, height, 80);
|
||||||
|
self->help->type = HELP_CONFERENCE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'f':
|
#ifdef PYTHON
|
||||||
|
|
||||||
|
case L'p':
|
||||||
|
help_init_window(self, 4 + num_registered_handlers(), help_max_width());
|
||||||
|
self->help->type = HELP_PLUGIN;
|
||||||
|
break;
|
||||||
|
#endif /* PYTHON */
|
||||||
|
|
||||||
|
case L'f':
|
||||||
help_init_window(self, 10, 80);
|
help_init_window(self, 10, 80);
|
||||||
self->help->type = HELP_CONTACTS;
|
self->help->type = HELP_CONTACTS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'k':
|
case L'k':
|
||||||
help_init_window(self, 15, 80);
|
help_init_window(self, 15, 80);
|
||||||
self->help->type = HELP_KEYS;
|
self->help->type = HELP_KEYS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'm':
|
case L'm':
|
||||||
help_init_menu(self);
|
help_init_menu(self);
|
||||||
self->help->type = HELP_MENU;
|
self->help->type = HELP_MENU;
|
||||||
break;
|
break;
|
||||||
@ -350,9 +437,7 @@ void help_onKey(ToxWindow *self, wint_t key)
|
|||||||
|
|
||||||
void help_onDraw(ToxWindow *self)
|
void help_onDraw(ToxWindow *self)
|
||||||
{
|
{
|
||||||
curs_set(0);
|
switch (self->help->type) {
|
||||||
|
|
||||||
switch(self->help->type) {
|
|
||||||
case HELP_MENU:
|
case HELP_MENU:
|
||||||
help_draw_menu(self);
|
help_draw_menu(self);
|
||||||
return;
|
return;
|
||||||
@ -373,8 +458,15 @@ void help_onDraw(ToxWindow *self)
|
|||||||
help_draw_contacts(self);
|
help_draw_contacts(self);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HELP_GROUP:
|
case HELP_CONFERENCE:
|
||||||
help_draw_group(self);
|
help_draw_conference(self);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
#ifdef PYTHON
|
||||||
|
|
||||||
|
case HELP_PLUGIN:
|
||||||
|
help_draw_plugin(self);
|
||||||
|
break;
|
||||||
|
#endif /* PYTHON */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,13 +30,16 @@ typedef enum {
|
|||||||
HELP_MENU,
|
HELP_MENU,
|
||||||
HELP_GLOBAL,
|
HELP_GLOBAL,
|
||||||
HELP_CHAT,
|
HELP_CHAT,
|
||||||
HELP_GROUP,
|
HELP_CONFERENCE,
|
||||||
HELP_KEYS,
|
HELP_KEYS,
|
||||||
HELP_CONTACTS,
|
HELP_CONTACTS,
|
||||||
|
#ifdef PYTHON
|
||||||
|
HELP_PLUGIN,
|
||||||
|
#endif
|
||||||
} HELP_TYPES;
|
} HELP_TYPES;
|
||||||
|
|
||||||
void help_onDraw(ToxWindow *self);
|
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 */
|
||||||
|
119
src/input.c
119
src/input.c
@ -26,25 +26,26 @@
|
|||||||
|
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
|
||||||
#include "toxic.h"
|
#include "conference.h"
|
||||||
#include "windows.h"
|
|
||||||
#include "misc_tools.h"
|
|
||||||
#include "toxic_strings.h"
|
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
|
#include "misc_tools.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
#include "groupchat.h"
|
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "toxic.h"
|
||||||
|
#include "toxic_strings.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
extern struct user_settings *user_settings;
|
extern struct user_settings *user_settings;
|
||||||
|
|
||||||
/* add a char to input field and buffer */
|
/* add a char to input field and buffer */
|
||||||
void input_new_char(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y)
|
void input_new_char(ToxWindow *self, wint_t key, int x, int mx_x)
|
||||||
{
|
{
|
||||||
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,42 +78,45 @@ 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)
|
||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
if (del_word_buf(ctx) == -1) {
|
if (del_word_buf(ctx) == -1) {
|
||||||
sound_notify(self, notif_error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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)
|
||||||
@ -134,7 +138,7 @@ static void input_yank(ToxWindow *self, int x, int mx_x)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* moves cursor/line position to end of line in input field and buffer */
|
/* moves cursor/line position to end of line in input field and buffer */
|
||||||
static void input_mv_end(ToxWindow *self, int y, int mx_x)
|
static void input_mv_end(ToxWindow *self, int mx_x)
|
||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
@ -149,8 +153,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,18 +166,44 @@ 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;
|
|
||||||
|
|
||||||
--ctx->pos;
|
--ctx->pos;
|
||||||
|
|
||||||
if (ctx->start && (x >= mx_x - cur_len))
|
if (ctx->start > 0 && (x >= mx_x - cur_len)) {
|
||||||
|
int s_len = wcwidth(ctx->line[ctx->start - 1]);
|
||||||
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 > 0) {
|
||||||
ctx->start = MAX(0, ctx->start - cur_len);
|
ctx->start = MAX(0, ctx->start - cur_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* moves the cursor to the beginning of the previous word in input field and buffer */
|
||||||
|
static void input_skip_left(ToxWindow *self, int x, int mx_x)
|
||||||
|
{
|
||||||
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
|
if (ctx->pos <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
--ctx->pos;
|
||||||
|
count += wcwidth(ctx->line[ctx->pos]);
|
||||||
|
} while (ctx->pos > 0 && (ctx->line[ctx->pos - 1] != L' ' || ctx->line[ctx->pos] == L' '));
|
||||||
|
|
||||||
|
if (ctx->start > 0 && (x >= mx_x - count)) {
|
||||||
|
int s_len = wcwidth(ctx->line[ctx->start - 1]);
|
||||||
|
ctx->start = MAX(0, ctx->start - 1 + (s_len - count));
|
||||||
|
} else if (ctx->start > 0) {
|
||||||
|
ctx->start = MAX(0, ctx->start - count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* moves cursor/line position right in input field and buffer */
|
/* moves cursor/line position right in input field and buffer */
|
||||||
@ -180,8 +211,9 @@ 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;
|
||||||
|
|
||||||
@ -193,6 +225,29 @@ static void input_mv_right(ToxWindow *self, int x, int mx_x)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* moves the cursor to the end of the next word in input field and buffer */
|
||||||
|
static void input_skip_right(ToxWindow *self, int x, int mx_x)
|
||||||
|
{
|
||||||
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
|
if (ctx->pos >= ctx->len) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
count += wcwidth(ctx->line[ctx->pos]);
|
||||||
|
++ctx->pos;
|
||||||
|
} while (ctx->pos < ctx->len && !(ctx->line[ctx->pos] == L' ' && ctx->line[ctx->pos - 1] != L' '));
|
||||||
|
|
||||||
|
int newpos = x + count;
|
||||||
|
|
||||||
|
if (newpos >= mx_x) {
|
||||||
|
ctx->start += (1 + (newpos - mx_x));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* puts a line history item in input field and buffer */
|
/* puts a line history item in input field and buffer */
|
||||||
static void input_history(ToxWindow *self, wint_t key, int mx_x)
|
static void input_history(ToxWindow *self, wint_t key, int mx_x)
|
||||||
{
|
{
|
||||||
@ -205,7 +260,7 @@ static void input_history(ToxWindow *self, wint_t key, int mx_x)
|
|||||||
|
|
||||||
/* Handles non-printable input keys that behave the same for all types of chat windows.
|
/* Handles non-printable input keys that behave the same for all types of chat windows.
|
||||||
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 mx_x)
|
||||||
{
|
{
|
||||||
bool match = true;
|
bool match = true;
|
||||||
|
|
||||||
@ -232,7 +287,7 @@ bool input_handle(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case T_KEY_C_W:
|
case T_KEY_C_W:
|
||||||
input_del_word(self, x, mx_x);
|
input_del_word(self);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KEY_HOME:
|
case KEY_HOME:
|
||||||
@ -242,7 +297,7 @@ bool input_handle(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y)
|
|||||||
|
|
||||||
case KEY_END:
|
case KEY_END:
|
||||||
case T_KEY_C_E:
|
case T_KEY_C_E:
|
||||||
input_mv_end(self, y, mx_x);
|
input_mv_end(self, mx_x);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KEY_LEFT:
|
case KEY_LEFT:
|
||||||
@ -262,6 +317,14 @@ bool input_handle(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y)
|
|||||||
force_refresh(self->chatwin->history);
|
force_refresh(self->chatwin->history);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_KEY_C_LEFT:
|
||||||
|
input_skip_left(self, x, mx_x);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_KEY_C_RIGHT:
|
||||||
|
input_skip_right(self, x, mx_x);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
match = false;
|
match = false;
|
||||||
break;
|
break;
|
||||||
@ -271,13 +334,13 @@ bool input_handle(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y)
|
|||||||
maybe convert entire function to if/else and make them all customizable keys? */
|
maybe convert entire function to if/else and make them all customizable keys? */
|
||||||
if (!match) {
|
if (!match) {
|
||||||
if (key == user_settings->key_toggle_peerlist) {
|
if (key == user_settings->key_toggle_peerlist) {
|
||||||
if (self->is_groupchat) {
|
if (self->type == WINDOW_TYPE_CONFERENCE) {
|
||||||
self->show_peerlist ^= 1;
|
self->show_peerlist ^= 1;
|
||||||
redraw_groupchat_win(self);
|
redraw_conference_win(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
match = true;
|
match = true;
|
||||||
}
|
} else if (key == user_settings->key_toggle_pastemode) {
|
||||||
else if (key == user_settings->key_toggle_pastemode) {
|
|
||||||
self->chatwin->pastemode ^= 1;
|
self->chatwin->pastemode ^= 1;
|
||||||
match = true;
|
match = true;
|
||||||
}
|
}
|
||||||
|
@ -24,10 +24,10 @@
|
|||||||
#define INPUT_H
|
#define INPUT_H
|
||||||
|
|
||||||
/* add a char to input field and buffer for given chatcontext */
|
/* add a char to input field and buffer for given chatcontext */
|
||||||
void input_new_char(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y);
|
void input_new_char(ToxWindow *self, wint_t key, int x, int mx_x);
|
||||||
|
|
||||||
/* Handles non-printable input keys that behave the same for all types of chat windows.
|
/* Handles non-printable input keys that behave the same for all types of chat windows.
|
||||||
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 mx_x);
|
||||||
|
|
||||||
#endif /* #define INPUT_H */
|
#endif /* INPUT_H */
|
||||||
|
464
src/line_info.c
464
src/line_info.c
@ -20,19 +20,19 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
#include "toxic.h"
|
#include "conference.h"
|
||||||
#include "windows.h"
|
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "groupchat.h"
|
|
||||||
#include "settings.h"
|
|
||||||
#include "notify.h"
|
|
||||||
#include "message_queue.h"
|
#include "message_queue.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
|
#include "notify.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
extern struct user_settings *user_settings;
|
extern struct user_settings *user_settings;
|
||||||
|
|
||||||
@ -40,12 +40,13 @@ 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;
|
||||||
hst->queue_sz = 0;
|
hst->queue_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* resets line_start (moves to end of chat history) */
|
/* resets line_start (moves to end of chat history) */
|
||||||
@ -53,24 +54,24 @@ 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;
|
||||||
|
int x2;
|
||||||
getmaxyx(self->window, y2, x2);
|
getmaxyx(self->window, y2, x2);
|
||||||
|
UNUSED_VAR(x2);
|
||||||
|
|
||||||
int side_offst = self->show_peerlist ? SIDEBAR_WIDTH : 0;
|
int top_offst = (self->type == WINDOW_TYPE_CHAT) || (self->type == WINDOW_TYPE_PROMPT) ? 2 : 0;
|
||||||
int top_offst = self->is_chat || self->is_prompt ? 2 : 0;
|
int max_y = y2 - CHATBOX_HEIGHT - top_offst;
|
||||||
int max_y = (y2 - CHATBOX_HEIGHT - top_offst);
|
|
||||||
|
|
||||||
int curlines = 0;
|
int curlines = 0;
|
||||||
int nxtlines = line->newlines + (line->len / (x2 - side_offst));
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
curlines += 1 + nxtlines;
|
curlines += line->format_lines;
|
||||||
line = line->prev;
|
line = line->prev;
|
||||||
nxtlines = line->newlines + (line->len / (x2 - side_offst));
|
} while (line->prev && curlines + line->format_lines <= max_y);
|
||||||
} while (line->prev && curlines + nxtlines < max_y);
|
|
||||||
|
|
||||||
hst->line_start = line;
|
hst->line_start = line;
|
||||||
}
|
}
|
||||||
@ -85,11 +86,10 @@ void line_info_cleanup(struct history *hst)
|
|||||||
tmp1 = tmp2;
|
tmp1 = tmp2;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i;
|
for (size_t i = 0; i < hst->queue_size; ++i) {
|
||||||
|
if (hst->queue[i]) {
|
||||||
for (i = 0; i < hst->queue_sz; ++i) {
|
|
||||||
if (hst->queue[i])
|
|
||||||
free(hst->queue[i]);
|
free(hst->queue[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(hst);
|
free(hst);
|
||||||
@ -114,39 +114,207 @@ 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_size == 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
struct line_info *line = hst->queue[0];
|
struct line_info *line = hst->queue[0];
|
||||||
|
|
||||||
int i;
|
for (size_t i = 0; i < hst->queue_size; ++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_size;
|
||||||
|
|
||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* creates new line_info line and puts it in the queue. */
|
/* Prints a maximum of `n` chars from `s` to `win`.
|
||||||
void 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, ...)
|
* Return true if the string contains a newline or tab byte.
|
||||||
|
*/
|
||||||
|
static bool print_n_chars(WINDOW *win, const char *s, size_t n)
|
||||||
{
|
{
|
||||||
if (!self)
|
bool newline = false;
|
||||||
|
char ch;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n && (ch = s[i]); ++i) {
|
||||||
|
if (win) {
|
||||||
|
wprintw(win, "%c", ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch == '\n') {
|
||||||
|
newline = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the index of the last space character in `s` found before `limit`.
|
||||||
|
* Returns -1 if no space is found.
|
||||||
|
*/
|
||||||
|
static int rspace_index(const char *s, int limit)
|
||||||
|
{
|
||||||
|
for (int i = limit; i >= 0; --i) {
|
||||||
|
if (s[i] == ' ') {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the first index in `s` containing a newline byte found before `limit`.
|
||||||
|
* Returns -1 if no newline is found.
|
||||||
|
*/
|
||||||
|
static int newline_index(const char *s, int limit)
|
||||||
|
{
|
||||||
|
char ch;
|
||||||
|
|
||||||
|
for (int i = 0; i < limit && (ch = s[i]); ++i) {
|
||||||
|
if (ch == '\n') {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the number of newline bytes in `s` */
|
||||||
|
static unsigned int newline_count(const char *s)
|
||||||
|
{
|
||||||
|
char ch;
|
||||||
|
unsigned int count = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; (ch = s[i]); ++i) {
|
||||||
|
if (ch == '\n') {
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prints `line` message to window, wrapping at the last word that fits on the current line.
|
||||||
|
* This function updates the `format_lines` field of `line` according to current window dimensions.
|
||||||
|
*
|
||||||
|
* If `win` is null nothing will be printed to the window. This is useful to set the
|
||||||
|
* `format_lines` field on initialization.
|
||||||
|
*/
|
||||||
|
static void print_wrap(WINDOW *win, struct line_info *line, int max_x)
|
||||||
|
{
|
||||||
|
const char *msg = line->msg;
|
||||||
|
uint16_t length = line->msg_len;
|
||||||
|
uint16_t lines = 0;
|
||||||
|
const int x_start = line->len - line->msg_len - 1; // manually keep track of x position because ncurses sucks
|
||||||
|
int x_limit = max_x - x_start;
|
||||||
|
|
||||||
|
if (x_limit <= 0) {
|
||||||
|
fprintf(stderr, "Warning: x_limit <= 0 in print_wrap(): %d\n", x_limit);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (msg) {
|
||||||
|
if (length < x_limit) {
|
||||||
|
if (print_n_chars(win, msg, length)) {
|
||||||
|
lines += newline_count(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
++lines;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int newline_idx = newline_index(msg, x_limit - 1);
|
||||||
|
|
||||||
|
if (newline_idx >= 0) {
|
||||||
|
print_n_chars(win, msg, newline_idx + 1);
|
||||||
|
msg += newline_idx + 1;
|
||||||
|
length -= (newline_idx + 1);
|
||||||
|
x_limit = max_x; // if we find a newline we stop adding column padding for rest of message
|
||||||
|
++lines;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int space_idx = rspace_index(msg, x_limit - 1);
|
||||||
|
|
||||||
|
if (space_idx >= 1) {
|
||||||
|
print_n_chars(win, msg, space_idx);
|
||||||
|
msg += space_idx + 1;
|
||||||
|
length -= (space_idx + 1);
|
||||||
|
waddch(win, '\n');
|
||||||
|
} else {
|
||||||
|
print_n_chars(win, msg, x_limit);
|
||||||
|
msg += x_limit;
|
||||||
|
length -= x_limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add padding to the start of the next line
|
||||||
|
if (win && x_limit < max_x) {
|
||||||
|
for (size_t i = 0; i < x_start; ++i) {
|
||||||
|
waddch(win, ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
++lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (win && line->noread_flag) {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
UNUSED_VAR(y);
|
||||||
|
|
||||||
|
getyx(win, y, x);
|
||||||
|
|
||||||
|
if (x >= max_x - 1 || x == x_start) {
|
||||||
|
++lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
wattron(win, COLOR_PAIR(RED));
|
||||||
|
wprintw(win, " x");
|
||||||
|
wattroff(win, COLOR_PAIR(RED));
|
||||||
|
}
|
||||||
|
|
||||||
|
line->format_lines = lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void line_info_init_line(WINDOW *win, struct line_info *line)
|
||||||
|
{
|
||||||
|
int max_y;
|
||||||
|
int max_x;
|
||||||
|
UNUSED_VAR(max_y);
|
||||||
|
|
||||||
|
getmaxyx(win, max_y, max_x);
|
||||||
|
|
||||||
|
print_wrap(NULL, line, max_x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* creates new line_info line and puts it in the queue.
|
||||||
|
*
|
||||||
|
* Returns the id of the new line.
|
||||||
|
* Returns -1 on failure.
|
||||||
|
*/
|
||||||
|
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, ...)
|
||||||
|
{
|
||||||
|
if (!self) {
|
||||||
|
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_size >= MAX_LINE_INFO_QUEUE) {
|
||||||
return;
|
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];
|
||||||
|
frmt_msg[0] = 0;
|
||||||
|
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, msg);
|
va_start(args, msg);
|
||||||
@ -158,12 +326,14 @@ void line_info_add(ToxWindow *self, const char *timestr, const char *name1, cons
|
|||||||
/* for type-specific formatting in print function */
|
/* for type-specific formatting in print function */
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case IN_ACTION:
|
case IN_ACTION:
|
||||||
|
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case OUT_ACTION:
|
case OUT_ACTION:
|
||||||
len += strlen(user_settings->line_normal) + 2;
|
len += strlen(user_settings->line_normal) + 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IN_MSG:
|
case IN_MSG:
|
||||||
|
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case OUT_MSG:
|
case OUT_MSG:
|
||||||
len += strlen(user_settings->line_normal) + 3;
|
len += strlen(user_settings->line_normal) + 3;
|
||||||
@ -193,16 +363,12 @@ void line_info_add(ToxWindow *self, const char *timestr, const char *name1, cons
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t msg_len = 0;
|
||||||
|
|
||||||
if (frmt_msg[0]) {
|
if (frmt_msg[0]) {
|
||||||
snprintf(new_line->msg, sizeof(new_line->msg), "%s", frmt_msg);
|
snprintf(new_line->msg, sizeof(new_line->msg), "%s", frmt_msg);
|
||||||
len += strlen(new_line->msg);
|
msg_len = strlen(new_line->msg);
|
||||||
|
len += msg_len;
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; frmt_msg[i]; ++i) {
|
|
||||||
if (frmt_msg[i] == '\n')
|
|
||||||
++new_line->newlines;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timestr) {
|
if (timestr) {
|
||||||
@ -220,14 +386,20 @@ void line_info_add(ToxWindow *self, const char *timestr, const char *name1, cons
|
|||||||
len += strlen(new_line->name2);
|
len += strlen(new_line->name2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_line->id = (hst->line_end->id + 1 + hst->queue_size) % INT_MAX;
|
||||||
new_line->len = len;
|
new_line->len = len;
|
||||||
|
new_line->msg_len = msg_len;
|
||||||
new_line->type = type;
|
new_line->type = type;
|
||||||
new_line->bold = bold;
|
new_line->bold = bold;
|
||||||
new_line->colour = colour;
|
new_line->colour = colour;
|
||||||
new_line->noread_flag = false;
|
new_line->noread_flag = false;
|
||||||
new_line->timestamp = get_unix_time();
|
new_line->timestamp = get_unix_time();
|
||||||
|
|
||||||
hst->queue[hst->queue_sz++] = new_line;
|
line_info_init_line(self->chatwin->history, new_line);
|
||||||
|
|
||||||
|
hst->queue[hst->queue_size++] = new_line;
|
||||||
|
|
||||||
|
return new_line->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* adds a single queue item to hst if possible. only called once per call to line_info_print() */
|
/* adds a single queue item to hst if possible. only called once per call to line_info_print() */
|
||||||
@ -236,33 +408,39 @@ 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->id = hst->line_end->id + 1;
|
|
||||||
line->prev = hst->line_end;
|
line->prev = hst->line_end;
|
||||||
hst->line_end->next = line;
|
hst->line_end->next = line;
|
||||||
hst->line_end = line;
|
hst->line_end = line;
|
||||||
|
hst->line_end->id = line->id;
|
||||||
|
|
||||||
int y, y2, x, x2;
|
int y;
|
||||||
|
int y2;
|
||||||
|
int x;
|
||||||
|
int x2;
|
||||||
getmaxyx(self->window, y2, x2);
|
getmaxyx(self->window, y2, x2);
|
||||||
getyx(self->chatwin->history, y, x);
|
getyx(self->chatwin->history, y, x);
|
||||||
(void) x;
|
|
||||||
|
|
||||||
if (x2 <= SIDEBAR_WIDTH)
|
UNUSED_VAR(x);
|
||||||
|
|
||||||
|
if (x2 <= SIDEBAR_WIDTH) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int offst = self->show_peerlist ? SIDEBAR_WIDTH : 0; /* offset width of groupchat sidebar */
|
int lines = line->format_lines;
|
||||||
int lines = 1 + line->newlines + (line->len / (x2 - offst));
|
|
||||||
int max_y = y2 - CHATBOX_HEIGHT;
|
int max_y = y2 - CHATBOX_HEIGHT;
|
||||||
|
|
||||||
/* move line_start forward proportionate to the number of new lines */
|
/* move line_start forward proportionate to the number of new lines */
|
||||||
if (y + lines - 1 >= max_y) {
|
if (y + lines > max_y) {
|
||||||
while (lines > 0 && hst->line_start->next) {
|
while (lines > 0 && hst->line_start->next) {
|
||||||
lines -= 1 + hst->line_start->next->newlines + (hst->line_start->next->len / (x2 - offst));
|
lines -= hst->line_start->next->format_lines;
|
||||||
hst->line_start = hst->line_start->next;
|
hst->line_start = hst->line_start->next;
|
||||||
++hst->start_id;
|
++hst->start_id;
|
||||||
}
|
}
|
||||||
@ -275,8 +453,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;
|
||||||
|
|
||||||
@ -284,19 +463,29 @@ 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;
|
||||||
|
|
||||||
|
int x2;
|
||||||
|
|
||||||
getmaxyx(self->window, y2, x2);
|
getmaxyx(self->window, y2, x2);
|
||||||
|
|
||||||
if (x2 <= SIDEBAR_WIDTH)
|
if (x2 - 1 <= SIDEBAR_WIDTH) { // leave room on x axis for sidebar padding
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (self->is_groupchat)
|
if (self->type == WINDOW_TYPE_CONFERENCE) {
|
||||||
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;
|
||||||
|
|
||||||
|
const int max_x = self->show_peerlist ? x2 - 1 - SIDEBAR_WIDTH : x2;
|
||||||
|
|
||||||
int numlines = 0;
|
int numlines = 0;
|
||||||
|
|
||||||
while (line && numlines++ <= y2) {
|
while (line && numlines++ <= y2) {
|
||||||
@ -304,8 +493,10 @@ void line_info_print(ToxWindow *self)
|
|||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case OUT_MSG:
|
case OUT_MSG:
|
||||||
|
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case OUT_MSG_READ:
|
case OUT_MSG_READ:
|
||||||
|
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case IN_MSG:
|
case IN_MSG:
|
||||||
wattron(win, COLOR_PAIR(BLUE));
|
wattron(win, COLOR_PAIR(BLUE));
|
||||||
@ -314,54 +505,49 @@ 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);
|
||||||
wattroff(win, COLOR_PAIR(nameclr));
|
wattroff(win, COLOR_PAIR(nameclr));
|
||||||
|
|
||||||
char* msg = line->msg;
|
if (line->msg[0] == 0) {
|
||||||
while (msg)
|
waddch(win, '\n');
|
||||||
{
|
break;
|
||||||
char* line = strsep(&msg, "\n");
|
|
||||||
|
|
||||||
if (line[0] == '>')
|
|
||||||
wattron(win, COLOR_PAIR(GREEN));
|
|
||||||
else if (line[0] == '<')
|
|
||||||
wattron(win, COLOR_PAIR(RED));
|
|
||||||
|
|
||||||
wprintw(win, "%s%c", line, msg ? '\n' : '\0');
|
|
||||||
|
|
||||||
if (line[0] == '>')
|
|
||||||
wattroff(win, COLOR_PAIR(GREEN));
|
|
||||||
else if (line[0] == '<')
|
|
||||||
wattroff(win, COLOR_PAIR(RED));
|
|
||||||
|
|
||||||
// change the \0 set by strsep back to \n
|
|
||||||
if (msg)
|
|
||||||
msg[-1] = '\n';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == OUT_MSG && timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
|
if (line->msg[0] == '>') {
|
||||||
|
wattron(win, COLOR_PAIR(GREEN));
|
||||||
|
} else if (line->msg[0] == '<') {
|
||||||
wattron(win, COLOR_PAIR(RED));
|
wattron(win, COLOR_PAIR(RED));
|
||||||
wprintw(win, " x", line->msg);
|
}
|
||||||
wattroff(win, COLOR_PAIR(RED));
|
|
||||||
|
|
||||||
if (line->noread_flag == false) {
|
print_wrap(win, line, max_x);
|
||||||
|
|
||||||
|
if (line->msg[0] == '>') {
|
||||||
|
wattroff(win, COLOR_PAIR(GREEN));
|
||||||
|
} else if (line->msg[0] == '<') {
|
||||||
|
wattroff(win, COLOR_PAIR(RED));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == OUT_MSG && !line->read_flag) {
|
||||||
|
if (timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
|
||||||
line->noread_flag = true;
|
line->noread_flag = true;
|
||||||
line->len += 2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wprintw(win, "\n", line->msg);
|
waddch(win, '\n');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OUT_ACTION_READ:
|
case OUT_ACTION_READ:
|
||||||
|
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case OUT_ACTION:
|
case OUT_ACTION:
|
||||||
|
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case IN_ACTION:
|
case IN_ACTION:
|
||||||
wattron(win, COLOR_PAIR(BLUE));
|
wattron(win, COLOR_PAIR(BLUE));
|
||||||
@ -369,21 +555,17 @@ void line_info_print(ToxWindow *self)
|
|||||||
wattroff(win, COLOR_PAIR(BLUE));
|
wattroff(win, COLOR_PAIR(BLUE));
|
||||||
|
|
||||||
wattron(win, COLOR_PAIR(YELLOW));
|
wattron(win, COLOR_PAIR(YELLOW));
|
||||||
wprintw(win, "%s %s %s", user_settings->line_normal, line->name1, line->msg);
|
wprintw(win, "%s %s ", user_settings->line_normal, line->name1);
|
||||||
|
print_wrap(win, line, max_x);
|
||||||
wattroff(win, COLOR_PAIR(YELLOW));
|
wattroff(win, COLOR_PAIR(YELLOW));
|
||||||
|
|
||||||
if (type == OUT_ACTION && timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
|
if (type == OUT_ACTION && !line->read_flag) {
|
||||||
wattron(win, COLOR_PAIR(RED));
|
if (timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
|
||||||
wprintw(win, " x", line->msg);
|
|
||||||
wattroff(win, COLOR_PAIR(RED));
|
|
||||||
|
|
||||||
if (line->noread_flag == false) {
|
|
||||||
line->noread_flag = true;
|
line->noread_flag = true;
|
||||||
line->len += 2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wprintw(win, "\n", line->msg);
|
waddch(win, '\n');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SYS_MSG:
|
case SYS_MSG:
|
||||||
@ -393,19 +575,24 @@ 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);
|
print_wrap(win, line, max_x);
|
||||||
|
waddch(win, '\n');
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
@ -414,10 +601,11 @@ 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);
|
print_wrap(win, line, max_x);
|
||||||
|
}
|
||||||
|
|
||||||
wprintw(win, "\n");
|
waddch(win, '\n');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CONNECTION:
|
case CONNECTION:
|
||||||
@ -432,7 +620,9 @@ void line_info_print(ToxWindow *self)
|
|||||||
wprintw(win, "%s ", line->name1);
|
wprintw(win, "%s ", line->name1);
|
||||||
wattroff(win, A_BOLD);
|
wattroff(win, A_BOLD);
|
||||||
|
|
||||||
wprintw(win, "%s\n", line->msg);
|
print_wrap(win, line, max_x);
|
||||||
|
waddch(win, '\n');
|
||||||
|
|
||||||
wattroff(win, COLOR_PAIR(line->colour));
|
wattroff(win, COLOR_PAIR(line->colour));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -449,7 +639,9 @@ void line_info_print(ToxWindow *self)
|
|||||||
wprintw(win, "%s ", line->name1);
|
wprintw(win, "%s ", line->name1);
|
||||||
wattroff(win, A_BOLD);
|
wattroff(win, A_BOLD);
|
||||||
|
|
||||||
wprintw(win, "%s\n", line->msg);
|
print_wrap(win, line, max_x);
|
||||||
|
waddch(win, '\n');
|
||||||
|
|
||||||
wattroff(win, COLOR_PAIR(line->colour));
|
wattroff(win, COLOR_PAIR(line->colour));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -465,7 +657,7 @@ void line_info_print(ToxWindow *self)
|
|||||||
wprintw(win, "%s", line->name1);
|
wprintw(win, "%s", line->name1);
|
||||||
wattroff(win, A_BOLD);
|
wattroff(win, A_BOLD);
|
||||||
|
|
||||||
wprintw(win, "%s", line->msg);
|
print_wrap(win, line, max_x);
|
||||||
|
|
||||||
wattron(win, A_BOLD);
|
wattron(win, A_BOLD);
|
||||||
wprintw(win, "%s\n", line->name2);
|
wprintw(win, "%s\n", line->name2);
|
||||||
@ -479,8 +671,9 @@ 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_size > 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 */
|
||||||
@ -490,6 +683,9 @@ void line_info_set(ToxWindow *self, uint32_t id, char *msg)
|
|||||||
|
|
||||||
while (line) {
|
while (line) {
|
||||||
if (line->id == id) {
|
if (line->id == id) {
|
||||||
|
size_t new_len = strlen(msg);
|
||||||
|
line->len = line->len - line->msg_len + new_len;
|
||||||
|
line->msg_len = new_len;
|
||||||
snprintf(line->msg, sizeof(line->msg), "%s", msg);
|
snprintf(line->msg, sizeof(line->msg), "%s", msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -498,47 +694,50 @@ void line_info_set(ToxWindow *self, uint32_t id, char *msg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static void line_info_goto_root(struct history *hst)
|
|
||||||
{
|
|
||||||
hst->line_start = hst->line_root;
|
|
||||||
} */
|
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
int x2, y2;
|
int x2, y2;
|
||||||
getmaxyx(self->window, y2, x2);
|
getmaxyx(self->window, y2, x2);
|
||||||
(void) x2;
|
|
||||||
int jump_dist = y2 / 2;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < jump_dist && hst->line_start->prev; ++i)
|
UNUSED_VAR(x2);
|
||||||
|
|
||||||
|
size_t jump_dist = y2 / 2;
|
||||||
|
|
||||||
|
for (size_t 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)
|
||||||
{
|
{
|
||||||
int x2, y2;
|
int x2, y2;
|
||||||
getmaxyx(self->window, y2, x2);
|
getmaxyx(self->window, y2, x2);
|
||||||
(void) x2;
|
|
||||||
int jump_dist = y2 / 2;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < jump_dist && hst->line_start->next; ++i)
|
UNUSED_VAR(x2);
|
||||||
|
|
||||||
|
size_t jump_dist = y2 / 2;
|
||||||
|
|
||||||
|
for (size_t 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)
|
||||||
@ -548,20 +747,15 @@ bool line_info_onKey(ToxWindow *self, wint_t key)
|
|||||||
|
|
||||||
if (key == user_settings->key_half_page_up) {
|
if (key == user_settings->key_half_page_up) {
|
||||||
line_info_page_up(self, hst);
|
line_info_page_up(self, hst);
|
||||||
}
|
} else if (key == user_settings->key_half_page_down) {
|
||||||
else if (key == user_settings->key_half_page_down) {
|
|
||||||
line_info_page_down(self, hst);
|
line_info_page_down(self, hst);
|
||||||
}
|
} else if (key == user_settings->key_scroll_line_up) {
|
||||||
else if (key == user_settings->key_scroll_line_up) {
|
|
||||||
line_info_scroll_up(hst);
|
line_info_scroll_up(hst);
|
||||||
}
|
} else if (key == user_settings->key_scroll_line_down) {
|
||||||
else if (key == user_settings->key_scroll_line_down) {
|
|
||||||
line_info_scroll_down(hst);
|
line_info_scroll_down(hst);
|
||||||
}
|
} else if (key == user_settings->key_page_bottom) {
|
||||||
else if (key == user_settings->key_page_bottom) {
|
|
||||||
line_info_reset_start(self, hst);
|
line_info_reset_start(self, hst);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
match = false;
|
match = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,15 +23,15 @@
|
|||||||
#ifndef LINE_INFO_H
|
#ifndef LINE_INFO_H
|
||||||
#define LINE_INFO_H
|
#define LINE_INFO_H
|
||||||
|
|
||||||
#include "windows.h"
|
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
#define MAX_HISTORY 100000
|
#define MAX_HISTORY 100000
|
||||||
#define MIN_HISTORY 40
|
#define MIN_HISTORY 40
|
||||||
#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,
|
||||||
@ -54,10 +54,12 @@ struct line_info {
|
|||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint8_t bold;
|
uint8_t bold;
|
||||||
uint8_t colour;
|
uint8_t colour;
|
||||||
uint8_t noread_flag; /* true if a line should be flagged as unread */
|
bool noread_flag; /* true if a line should be flagged as unread */
|
||||||
|
bool read_flag; /* true if a message has been flagged as read */
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
uint16_t len; /* combined len of entire line */
|
uint16_t len; /* combined length of entire line */
|
||||||
uint8_t newlines;
|
uint16_t msg_len; /* length of the message */
|
||||||
|
uint16_t format_lines; /* number of lines the combined string takes up (dynamically set) */
|
||||||
|
|
||||||
struct line_info *prev;
|
struct line_info *prev;
|
||||||
struct line_info *next;
|
struct line_info *next;
|
||||||
@ -71,12 +73,16 @@ struct history {
|
|||||||
uint32_t start_id; /* keeps track of where line_start should be when at bottom of history */
|
uint32_t start_id; /* keeps track of where line_start should be when at bottom of history */
|
||||||
|
|
||||||
struct line_info *queue[MAX_LINE_INFO_QUEUE];
|
struct line_info *queue[MAX_LINE_INFO_QUEUE];
|
||||||
int queue_sz;
|
size_t queue_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* creates new line_info line and puts it in the queue. */
|
/* creates new line_info line and puts it in the queue.
|
||||||
void 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, ...);
|
* Returns the id of the new line.
|
||||||
|
* Returns -1 on failure.
|
||||||
|
*/
|
||||||
|
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, ...);
|
||||||
|
|
||||||
/* Prints a section of history starting at line_start */
|
/* Prints a section of history starting at line_start */
|
||||||
void line_info_print(ToxWindow *self);
|
void line_info_print(ToxWindow *self);
|
||||||
@ -96,4 +102,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 */
|
||||||
|
309
src/log.c
309
src/log.c
@ -22,41 +22,46 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include "configdir.h"
|
#include "configdir.h"
|
||||||
|
#include "line_info.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "misc_tools.h"
|
||||||
|
#include "settings.h"
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#include "misc_tools.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "settings.h"
|
|
||||||
#include "line_info.h"
|
|
||||||
|
|
||||||
extern struct user_settings *user_settings;
|
extern struct user_settings *user_settings;
|
||||||
|
|
||||||
/* There are three types of logs: chat logs, groupchat logs, and prompt logs (see LOG_TYPE in log.h)
|
/* Creates a log path and puts it in `dest.
|
||||||
A prompt log is in the format: LOGDIR/selfkey-home.log
|
*
|
||||||
A chat log is in the format: LOGDIR/selfkey-friendname-otherkey.log
|
* There are two types of logs: chat logs and prompt logs (see LOG_TYPE in log.h)
|
||||||
A groupchat log is in the format: LOGDIR/selfkey-groupname-date[time].log
|
* A prompt log is in the format: LOGDIR/selfkey-home.log
|
||||||
|
* A chat log is in the format: LOGDIR/selfkey-name-otherkey.log
|
||||||
Only the first (KEY_IDENT_DIGITS * 2) numbers of the key are used.
|
*
|
||||||
|
* For friend chats `otherkey` is the first 6 bytes of the friend's Tox ID.
|
||||||
Returns 0 on success, -1 if the path is too long */
|
* For Conferences/groups `otherkey` is the first 6 bytes of the group's unique ID.
|
||||||
static int get_log_path(char *dest, int destsize, char *name, const char *selfkey, const char *otherkey, int logtype)
|
*
|
||||||
|
* Return path length on success.
|
||||||
|
* Return -1 if the path is too long.
|
||||||
|
*/
|
||||||
|
static int get_log_path(char *dest, int destsize, const char *name, const char *selfkey, const char *otherkey)
|
||||||
{
|
{
|
||||||
if (!valid_nick(name))
|
if (!valid_nick(name)) {
|
||||||
name = UNKNOWN_NAME;
|
name = UNKNOWN_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
const char *namedash = logtype == LOG_PROMPT ? "" : "-";
|
const char *namedash = otherkey ? "-" : "";
|
||||||
const char *set_path = user_settings->chatlogs_path;
|
const char *set_path = user_settings->chatlogs_path;
|
||||||
|
|
||||||
char *user_config_dir = get_user_config_dir();
|
char *user_config_dir = get_user_config_dir();
|
||||||
int path_len = strlen(name) + strlen(".log") + strlen("-") + strlen(namedash);
|
int path_len = strlen(name) + strlen(".log") + strlen("-") + strlen(namedash);
|
||||||
path_len += strlen(set_path) ? *set_path : strlen(user_config_dir) + strlen(LOGDIR);
|
path_len += strlen(set_path) ? *set_path : strlen(user_config_dir) + strlen(LOGDIR);
|
||||||
|
|
||||||
/* first 6 digits of selfkey */
|
/* first 6 bytes of selfkey */
|
||||||
char self_id[32];
|
char self_id[32] = {0};
|
||||||
path_len += KEY_IDENT_DIGITS * 2;
|
path_len += KEY_IDENT_DIGITS * 2;
|
||||||
sprintf(&self_id[0], "%02X", selfkey[0] & 0xff);
|
sprintf(&self_id[0], "%02X", selfkey[0] & 0xff);
|
||||||
sprintf(&self_id[2], "%02X", selfkey[1] & 0xff);
|
sprintf(&self_id[2], "%02X", selfkey[1] & 0xff);
|
||||||
@ -65,19 +70,13 @@ static int get_log_path(char *dest, int destsize, char *name, const char *selfke
|
|||||||
|
|
||||||
char other_id[32] = {0};
|
char other_id[32] = {0};
|
||||||
|
|
||||||
switch (logtype) {
|
if (otherkey) {
|
||||||
case LOG_CHAT:
|
/* first 6 bytes of otherkey */
|
||||||
path_len += KEY_IDENT_DIGITS * 2;
|
path_len += KEY_IDENT_DIGITS * 2;
|
||||||
sprintf(&other_id[0], "%02X", otherkey[0] & 0xff);
|
sprintf(&other_id[0], "%02X", otherkey[0] & 0xff);
|
||||||
sprintf(&other_id[2], "%02X", otherkey[1] & 0xff);
|
sprintf(&other_id[2], "%02X", otherkey[1] & 0xff);
|
||||||
sprintf(&other_id[4], "%02X", otherkey[2] & 0xff);
|
sprintf(&other_id[4], "%02X", otherkey[2] & 0xff);
|
||||||
other_id[KEY_IDENT_DIGITS * 2] = '\0';
|
other_id[KEY_IDENT_DIGITS * 2] = '\0';
|
||||||
break;
|
|
||||||
|
|
||||||
case LOG_GROUP:
|
|
||||||
strftime(other_id, sizeof(other_id), "%Y-%m-%d[%H:%M:%S]", get_time());
|
|
||||||
path_len += strlen(other_id);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path_len >= destsize) {
|
if (path_len >= destsize) {
|
||||||
@ -85,32 +84,43 @@ 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);
|
||||||
|
|
||||||
return 0;
|
return path_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Opens log file or creates a new one */
|
/* Initializes log path for `log`.
|
||||||
static int init_logging_session(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype)
|
*
|
||||||
|
* Return 0 on success.
|
||||||
|
* Return -1 on failure.
|
||||||
|
*/
|
||||||
|
static int init_logging_session(const char *name, const char *selfkey, const char *otherkey, struct chatlog *log,
|
||||||
|
LOG_TYPE type)
|
||||||
{
|
{
|
||||||
if (selfkey == NULL || (logtype == LOG_CHAT && otherkey == NULL))
|
if (log == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selfkey == NULL || (type == LOG_TYPE_CHAT && otherkey == NULL)) {
|
||||||
|
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)
|
int path_len = get_log_path(log_path, sizeof(log_path), name, selfkey, otherkey);
|
||||||
return -1;
|
|
||||||
|
|
||||||
log->file = fopen(log_path, "a+");
|
if (path_len == -1 || path_len >= sizeof(log->path)) {
|
||||||
snprintf(log->path, sizeof(log->path), "%s", log_path);
|
|
||||||
|
|
||||||
if (log->file == NULL)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(log->path, log_path, path_len);
|
||||||
|
log->path[path_len] = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -119,8 +129,13 @@ 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 == NULL) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!log->log_on) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (log->file == NULL) {
|
if (log->file == NULL) {
|
||||||
log->log_on = false;
|
log->log_on = false;
|
||||||
@ -129,10 +144,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,86 +163,162 @@ 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 == NULL) {
|
||||||
fclose(log->file);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
memset(log, 0, sizeof(struct chatlog));
|
if (log->file != NULL) {
|
||||||
|
fclose(log->file);
|
||||||
|
log->file = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
log->lastwrite = 0;
|
||||||
|
log->log_on = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int log_enable(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype)
|
int log_enable(struct chatlog *log)
|
||||||
{
|
{
|
||||||
log->log_on = true;
|
if (log == NULL) {
|
||||||
|
|
||||||
if (log->file != NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (init_logging_session(name, selfkey, otherkey, log, logtype) == -1) {
|
|
||||||
log_disable(log);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (log->log_on) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*log->path == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (log->file != NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
log->file = fopen(log->path, "a+");
|
||||||
|
|
||||||
|
if (log->file == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
log->log_on = true;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loads previous history from chat log */
|
/* Initializes a log. This function must be called before any other logging operations.
|
||||||
void load_chat_history(ToxWindow *self, struct chatlog *log)
|
*
|
||||||
|
* Return 0 on success.
|
||||||
|
* Return -1 on failure.
|
||||||
|
*/
|
||||||
|
int log_init(struct chatlog *log, const char *name, const char *selfkey, const char *otherkey, LOG_TYPE type)
|
||||||
{
|
{
|
||||||
if (log->file == NULL)
|
if (log == NULL) {
|
||||||
return;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (log->file != NULL || log->log_on) {
|
||||||
|
fprintf(stderr, "Warning: Called log_init() on an already initialized log\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (init_logging_session(name, selfkey, otherkey, log, type) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_disable(log);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loads chat log history and prints it to `self` window.
|
||||||
|
*
|
||||||
|
* Return 0 on success or if log file doesn't exist.
|
||||||
|
* Return -1 on failure.
|
||||||
|
*/
|
||||||
|
int load_chat_history(ToxWindow *self, struct chatlog *log)
|
||||||
|
{
|
||||||
|
if (log == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*log->path == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
off_t sz = file_size(log->path);
|
off_t sz = file_size(log->path);
|
||||||
|
|
||||||
if (sz <= 0)
|
if (sz <= 0) {
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
char *hstbuf = malloc(sz + 1);
|
|
||||||
|
|
||||||
if (hstbuf == NULL)
|
|
||||||
exit_toxic_err("failed in load_chat_history", FATALERR_MEMORY);
|
|
||||||
|
|
||||||
if (fseek(log->file, 0L, SEEK_SET) == -1) {
|
|
||||||
free(hstbuf);
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to read log file");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fread(hstbuf, sz, 1, log->file) != 1) {
|
FILE *fp = fopen(log->path, "r");
|
||||||
free(hstbuf);
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to read log file");
|
if (fp == NULL) {
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
hstbuf[sz] = '\0';
|
char *buf = malloc(sz + 1);
|
||||||
|
|
||||||
|
if (buf == NULL) {
|
||||||
|
fclose(fp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fseek(fp, 0L, SEEK_SET) == -1) {
|
||||||
|
free(buf);
|
||||||
|
fclose(fp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fread(buf, sz, 1, fp) != 1) {
|
||||||
|
free(buf);
|
||||||
|
fclose(fp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
buf[sz] = 0;
|
||||||
|
|
||||||
/* Number of history lines to load: must not be larger than MAX_LINE_INFO_QUEUE - 2 */
|
/* Number of history lines to load: must not be larger than MAX_LINE_INFO_QUEUE - 2 */
|
||||||
int L = MIN(MAX_LINE_INFO_QUEUE - 2, user_settings->history_size);
|
int L = MIN(MAX_LINE_INFO_QUEUE - 2, user_settings->history_size);
|
||||||
int start, count = 0;
|
|
||||||
|
int start = 0;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
/* 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 (buf[start] == '\n') {
|
||||||
++count;
|
++count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *line = strtok(&hstbuf[start + 1], "\n");
|
char *tmp = NULL;
|
||||||
|
const char *line = strtok_r(&buf[start + 1], "\n", &tmp);
|
||||||
|
|
||||||
if (line == NULL) {
|
if (line == NULL) {
|
||||||
free(hstbuf);
|
free(buf);
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (line != NULL && count--) {
|
while (line != NULL && count--) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", line);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", line);
|
||||||
line = strtok(NULL, "\n");
|
line = strtok_r(NULL, "\n", &tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
|
||||||
free(hstbuf);
|
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* renames chatlog file replacing src with dest.
|
/* Renames chatlog file `src` to `dest`.
|
||||||
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)
|
* Return 0 on success or if no log exists.
|
||||||
|
* Return -1 on failure.
|
||||||
|
*/
|
||||||
|
int rename_logfile(const char *src, const char *dest, const char *selfkey, const char *otherkey, int winnum)
|
||||||
{
|
{
|
||||||
ToxWindow *toxwin = get_window_ptr(winnum);
|
ToxWindow *toxwin = get_window_ptr(winnum);
|
||||||
struct chatlog *log = NULL;
|
struct chatlog *log = NULL;
|
||||||
@ -235,35 +327,58 @@ int rename_logfile(char *src, char *dest, const char *selfkey, const char *other
|
|||||||
/* disable log if necessary and save its state */
|
/* disable log if necessary and save its state */
|
||||||
if (toxwin != NULL) {
|
if (toxwin != NULL) {
|
||||||
log = toxwin->chatwin->log;
|
log = toxwin->chatwin->log;
|
||||||
|
|
||||||
|
if (log == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
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) == -1) {
|
||||||
goto on_error;
|
goto on_error;
|
||||||
|
}
|
||||||
|
|
||||||
if (!file_exists(oldpath))
|
if (!file_exists(oldpath)) {
|
||||||
|
init_logging_session(dest, selfkey, otherkey, log, LOG_TYPE_CHAT); // still need to rename path
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (get_log_path(newpath, sizeof(newpath), dest, selfkey, otherkey, LOG_CHAT) == -1)
|
int new_path_len = get_log_path(newpath, sizeof(newpath), dest, selfkey, otherkey);
|
||||||
|
|
||||||
|
if (new_path_len == -1 || new_path_len >= MAX_STR_SIZE) {
|
||||||
goto on_error;
|
goto on_error;
|
||||||
|
}
|
||||||
|
|
||||||
if (rename(oldpath, newpath) != 0)
|
if (file_exists(newpath)) {
|
||||||
|
remove(oldpath);
|
||||||
|
} else if (rename(oldpath, newpath) != 0) {
|
||||||
goto on_error;
|
goto on_error;
|
||||||
|
}
|
||||||
|
|
||||||
if (log_on)
|
if (log != NULL) {
|
||||||
log_enable(dest, selfkey, otherkey, log, LOG_CHAT);
|
memcpy(log->path, newpath, new_path_len);
|
||||||
|
log->path[new_path_len] = 0;
|
||||||
|
|
||||||
|
if (log_on) {
|
||||||
|
log_enable(log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
on_error:
|
on_error:
|
||||||
if (log_on)
|
|
||||||
log_enable(src, selfkey, otherkey, log, LOG_CHAT);
|
if (log_on) {
|
||||||
|
log_enable(log);
|
||||||
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
37
src/log.h
37
src/log.h
@ -30,30 +30,43 @@ struct chatlog {
|
|||||||
bool log_on; /* specific to current chat window */
|
bool log_on; /* specific to current chat window */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
typedef enum LOG_TYPE {
|
||||||
LOG_GROUP,
|
LOG_TYPE_PROMPT,
|
||||||
LOG_PROMPT,
|
LOG_TYPE_CHAT,
|
||||||
LOG_CHAT,
|
|
||||||
} LOG_TYPE;
|
} LOG_TYPE;
|
||||||
|
|
||||||
|
/* Initializes a log. This function must be called before any other logging operations.
|
||||||
|
*
|
||||||
|
* Return 0 on success.
|
||||||
|
* Return -1 on failure.
|
||||||
|
*/
|
||||||
|
int log_init(struct chatlog *log, const char *name, const char *selfkey, const char *otherkey, LOG_TYPE type);
|
||||||
|
|
||||||
/* formats/writes line to log file */
|
/* formats/writes line to log file */
|
||||||
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);
|
||||||
|
|
||||||
/* enables logging for specified log and creates/fetches file if necessary.
|
/* enables logging for specified log.
|
||||||
*
|
*
|
||||||
* Returns 0 on success.
|
* Returns 0 on success.
|
||||||
* Returns -1 on failure.
|
* Returns -1 on failure.
|
||||||
*/
|
*/
|
||||||
int log_enable(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype);
|
int log_enable(struct chatlog *log);
|
||||||
|
|
||||||
/* disables logging for specified log and closes file */
|
/* disables logging for specified log and closes file */
|
||||||
void log_disable(struct chatlog *log);
|
void log_disable(struct chatlog *log);
|
||||||
|
|
||||||
/* Loads previous history from chat log */
|
/* Loads chat log history and prints it to `self` window.
|
||||||
void load_chat_history(ToxWindow *self, struct chatlog *log);
|
*
|
||||||
|
* Return 0 on success or if log file doesn't exist.
|
||||||
|
* Return -1 on failure.
|
||||||
|
*/
|
||||||
|
int load_chat_history(ToxWindow *self, struct chatlog *log);
|
||||||
|
|
||||||
/* renames chatlog file replacing src with dest.
|
/* Renames chatlog file `src` to `dest`.
|
||||||
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);
|
* Return 0 on success or if no log exists.
|
||||||
|
* Return -1 on failure.
|
||||||
|
*/
|
||||||
|
int rename_logfile(const char *src, const char *dest, const char *selfkey, const char *otherkey, int winnum);
|
||||||
|
|
||||||
#endif /* #define LOG_H */
|
#endif /* LOG_H */
|
||||||
|
@ -22,12 +22,12 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "toxic.h"
|
|
||||||
#include "windows.h"
|
|
||||||
#include "message_queue.h"
|
|
||||||
#include "misc_tools.h"
|
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "message_queue.h"
|
||||||
|
#include "misc_tools.h"
|
||||||
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
void cqueue_cleanup(struct chat_queue *q)
|
void cqueue_cleanup(struct chat_queue *q)
|
||||||
{
|
{
|
||||||
@ -42,19 +42,24 @@ void cqueue_cleanup(struct chat_queue *q)
|
|||||||
free(q);
|
free(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, uint32_t line_id)
|
void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, int line_id)
|
||||||
{
|
{
|
||||||
|
if (line_id < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
new_m->type = type;
|
new_m->type = type;
|
||||||
new_m->line_id = line_id;
|
new_m->line_id = line_id;
|
||||||
new_m->last_send_try = 0;
|
new_m->last_send_try = 0;
|
||||||
new_m->receipt = 0;
|
new_m->receipt = -1;
|
||||||
new_m->next = NULL;
|
new_m->next = NULL;
|
||||||
|
|
||||||
if (q->root == NULL) {
|
if (q->root == NULL) {
|
||||||
@ -81,9 +86,9 @@ static void cqueue_mark_read(ToxWindow *self, struct cqueue_msg *msg)
|
|||||||
|
|
||||||
line->type = msg->type == OUT_ACTION ? OUT_ACTION_READ : OUT_MSG_READ;
|
line->type = msg->type == OUT_ACTION ? OUT_ACTION_READ : OUT_MSG_READ;
|
||||||
|
|
||||||
if (line->noread_flag == true) {
|
if (line->noread_flag) {
|
||||||
line->len -= 2;
|
|
||||||
line->noread_flag = false;
|
line->noread_flag = false;
|
||||||
|
line->read_flag = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -93,6 +98,7 @@ static void cqueue_mark_read(ToxWindow *self, struct cqueue_msg *msg)
|
|||||||
/* 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)
|
||||||
{
|
{
|
||||||
|
struct chatlog *log = self->chatwin->log;
|
||||||
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;
|
||||||
|
|
||||||
@ -102,53 +108,84 @@ void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
char selfname[TOX_MAX_NAME_LENGTH];
|
if (log->log_on) {
|
||||||
tox_self_get_name(m, (uint8_t *) selfname);
|
char selfname[TOX_MAX_NAME_LENGTH];
|
||||||
|
tox_self_get_name(m, (uint8_t *) selfname);
|
||||||
|
|
||||||
size_t len = tox_self_get_name_size(m);
|
size_t len = tox_self_get_name_size(m);
|
||||||
selfname[len] = '\0';
|
selfname[len] = 0;
|
||||||
|
|
||||||
|
write_to_log(msg->message, selfname, log, msg->type == OUT_ACTION);
|
||||||
|
}
|
||||||
|
|
||||||
write_to_log(msg->message, selfname, self->chatwin->log, msg->type == OUT_ACTION);
|
|
||||||
cqueue_mark_read(self, msg);
|
cqueue_mark_read(self, msg);
|
||||||
|
|
||||||
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);
|
|
||||||
q->root = next;
|
q->root = next;
|
||||||
} else {
|
} else {
|
||||||
struct cqueue_msg *prev = msg->prev;
|
struct cqueue_msg *prev = msg->prev;
|
||||||
free(msg);
|
|
||||||
prev->next = next;
|
prev->next = next;
|
||||||
|
next->prev = prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(msg);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CQUEUE_TRY_SEND_INTERVAL 60
|
// We use knowledge of toxcore internals (bad!) to determine that if we haven't received a read receipt for a
|
||||||
|
// sent packet after this amount of time, the connection has been severed and the packet needs to be re-sent.
|
||||||
|
#define TRY_SEND_TIMEOUT 32
|
||||||
|
|
||||||
/* Tries to send the oldest unsent message in queue. */
|
/*
|
||||||
|
* Marks all timed out messages in queue as unsent.
|
||||||
|
*/
|
||||||
|
static void cqueue_check_timeouts(struct cqueue_msg *msg)
|
||||||
|
{
|
||||||
|
while (msg) {
|
||||||
|
if (timed_out(msg->last_send_try, TRY_SEND_TIMEOUT)) {
|
||||||
|
msg->receipt = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = msg->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tries to send all messages in the send queue in sequential order.
|
||||||
|
* If a message fails to send the function will immediately return.
|
||||||
|
*/
|
||||||
void cqueue_try_send(ToxWindow *self, Tox *m)
|
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)
|
while (msg) {
|
||||||
return;
|
if (msg->receipt != -1) {
|
||||||
|
// we can no longer try to send unsent messages until we get receipts for our previous sent
|
||||||
|
// messages, but we continue to iterate the list, checking timestamps for any further
|
||||||
|
// successfully sent messages that have not yet gotten a receipt.
|
||||||
|
cqueue_check_timeouts(msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (msg->receipt != 0 && !timed_out(msg->last_send_try, CQUEUE_TRY_SEND_INTERVAL))
|
TOX_ERR_FRIEND_SEND_MESSAGE err;
|
||||||
return;
|
Tox_Message_Type type = msg->type == OUT_MSG ? TOX_MESSAGE_TYPE_NORMAL : TOX_MESSAGE_TYPE_ACTION;
|
||||||
|
uint32_t receipt = tox_friend_send_message(m, self->num, type, (uint8_t *) msg->message, msg->len, &err);
|
||||||
|
|
||||||
uint32_t receipt = 0;
|
if (err != TOX_ERR_FRIEND_SEND_MESSAGE_OK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TOX_MESSAGE_TYPE type = msg->type == OUT_MSG ? TOX_MESSAGE_TYPE_NORMAL : TOX_MESSAGE_TYPE_ACTION;
|
msg->receipt = receipt;
|
||||||
receipt = tox_friend_send_message(m, self->num, type, (uint8_t *) msg->message, msg->len, NULL);
|
msg->last_send_try = get_unix_time();
|
||||||
|
msg = msg->next;
|
||||||
msg->last_send_try = get_unix_time();
|
}
|
||||||
msg->receipt = receipt;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
@ -27,9 +27,9 @@ struct cqueue_msg {
|
|||||||
char message[MAX_STR_SIZE];
|
char message[MAX_STR_SIZE];
|
||||||
size_t len;
|
size_t len;
|
||||||
int line_id;
|
int line_id;
|
||||||
uint8_t type;
|
|
||||||
uint32_t receipt;
|
|
||||||
time_t last_send_try;
|
time_t last_send_try;
|
||||||
|
uint8_t type;
|
||||||
|
int64_t receipt;
|
||||||
struct cqueue_msg *next;
|
struct cqueue_msg *next;
|
||||||
struct cqueue_msg *prev;
|
struct cqueue_msg *prev;
|
||||||
};
|
};
|
||||||
@ -40,12 +40,15 @@ struct chat_queue {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void cqueue_cleanup(struct chat_queue *q);
|
void cqueue_cleanup(struct chat_queue *q);
|
||||||
void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, uint32_t line_id);
|
void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, int line_id);
|
||||||
|
|
||||||
/* Tries to send the oldest unsent message in queue. */
|
/*
|
||||||
|
* Tries to send all messages in the send queue in sequential order.
|
||||||
|
* If a message fails to send the function will immediately return.
|
||||||
|
*/
|
||||||
void cqueue_try_send(ToxWindow *self, Tox *m);
|
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 */
|
||||||
|
397
src/misc_tools.c
397
src/misc_tools.c
@ -20,38 +20,44 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include "toxic.h"
|
#include "file_transfers.h"
|
||||||
#include "windows.h"
|
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "file_transfers.h"
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
extern ToxWindow *prompt;
|
extern ToxWindow *prompt;
|
||||||
extern struct user_settings *user_settings;
|
extern struct user_settings *user_settings;
|
||||||
|
|
||||||
|
void clear_screen(void)
|
||||||
|
{
|
||||||
|
printf("\033[2J\033[1;1H");
|
||||||
|
}
|
||||||
|
|
||||||
void hst_to_net(uint8_t *num, uint16_t numbytes)
|
void hst_to_net(uint8_t *num, uint16_t numbytes)
|
||||||
{
|
{
|
||||||
#ifndef WORDS_BIGENDIAN
|
#ifndef WORDS_BIGENDIAN
|
||||||
uint32_t i;
|
uint8_t *buff = malloc(numbytes);
|
||||||
uint8_t buff[numbytes];
|
|
||||||
|
|
||||||
for (i = 0; i < numbytes; ++i) {
|
if (buff == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < numbytes; ++i) {
|
||||||
buff[i] = num[numbytes - i - 1];
|
buff[i] = num[numbytes - i - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(num, buff, numbytes);
|
memcpy(num, buff, numbytes);
|
||||||
|
free(buff);
|
||||||
#endif
|
#endif
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t get_unix_time(void)
|
time_t get_unix_time(void)
|
||||||
@ -65,12 +71,25 @@ int timed_out(time_t timestamp, time_t timeout)
|
|||||||
return timestamp + timeout <= get_unix_time();
|
return timestamp + timeout <= get_unix_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Sleeps the caller's thread for `usec` microseconds */
|
||||||
|
void sleep_thread(long int usec)
|
||||||
|
{
|
||||||
|
struct timespec req;
|
||||||
|
|
||||||
|
req.tv_sec = 0;
|
||||||
|
req.tv_nsec = usec * 1000L;
|
||||||
|
|
||||||
|
if (nanosleep(&req, NULL) == -1) {
|
||||||
|
fprintf(stderr, "nanosleep() returned -1\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Get the current local time */
|
/* Get the current local time */
|
||||||
struct tm *get_time(void)
|
struct tm *get_time(void)
|
||||||
{
|
{
|
||||||
struct tm *timeinfo;
|
struct tm *timeinfo;
|
||||||
time_t t = get_unix_time();
|
time_t t = get_unix_time();
|
||||||
timeinfo = localtime((const time_t*) &t);
|
timeinfo = localtime((const time_t *) &t);
|
||||||
return timeinfo;
|
return timeinfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,25 +102,30 @@ 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -113,11 +137,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,18 +151,19 @@ 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;
|
|
||||||
const char *pos = keystr;
|
const char *pos = keystr;
|
||||||
|
|
||||||
for (i = 0; i < size; ++i) {
|
for (size_t i = 0; i < size; ++i) {
|
||||||
res = sscanf(pos, "%2hhx", &buf[i]);
|
int 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;
|
||||||
@ -150,13 +176,31 @@ 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;
|
for (size_t i = 0; i < TOX_ADDRESS_SIZE; ++i) {
|
||||||
|
snprintf(&output[i * 2], output_size - (i * 2), "%02X", bin_id[i] & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < TOX_ADDRESS_SIZE; ++i)
|
return 0;
|
||||||
snprintf(&output[i*2], output_size - (i * 2), "%02X", bin_id[i] & 0xff);
|
}
|
||||||
|
|
||||||
|
/* Converts a binary representation of a Tox public key into a string.
|
||||||
|
*
|
||||||
|
* Returns 0 on success.
|
||||||
|
* Returns -1 on failure.
|
||||||
|
*/
|
||||||
|
int bin_pubkey_to_string(const uint8_t *bin_pubkey, size_t bin_pubkey_size, char *output, size_t output_size)
|
||||||
|
{
|
||||||
|
if (bin_pubkey_size != TOX_PUBLIC_KEY_SIZE || output_size < (TOX_PUBLIC_KEY_SIZE * 2 + 1)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < TOX_PUBLIC_KEY_SIZE; ++i) {
|
||||||
|
snprintf(&output[i * 2], output_size - (i * 2), "%02X", bin_pubkey[i] & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -164,8 +208,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';
|
||||||
}
|
}
|
||||||
@ -173,8 +218,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';
|
||||||
}
|
}
|
||||||
@ -184,11 +230,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;
|
||||||
}
|
}
|
||||||
@ -198,11 +246,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;
|
||||||
}
|
}
|
||||||
@ -213,41 +263,67 @@ int qsort_strcasecmp_hlpr(const void *str1, const void *str2)
|
|||||||
return strcasecmp((const char *) str1, (const char *) str2);
|
return strcasecmp((const char *) str1, (const char *) str2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns 1 if nick is valid, 0 if not. A valid toxic nick:
|
/* case-insensitive string compare function for use with qsort */
|
||||||
- cannot be empty
|
int qsort_ptr_char_array_helper(const void *str1, const void *str2)
|
||||||
- cannot start with a space
|
|
||||||
- must not contain a forward slash (for logfile naming purposes)
|
|
||||||
- must not contain contiguous spaces
|
|
||||||
- must not contain a newline or tab seqeunce */
|
|
||||||
int valid_nick(const char *nick)
|
|
||||||
{
|
{
|
||||||
if (!nick[0] || nick[0] == ' ')
|
return strcasecmp(*(char **)str1, *(char **)str2);
|
||||||
return 0;
|
}
|
||||||
|
|
||||||
int i;
|
static const char invalid_chars[] = {'/', '\n', '\t', '\v', '\r', '\0'};
|
||||||
|
|
||||||
for (i = 0; nick[i]; ++i) {
|
/*
|
||||||
if ((nick[i] == ' ' && nick[i + 1] == ' ')
|
* Helper function for `valid_nick()`.
|
||||||
|| nick[i] == '/'
|
*
|
||||||
|| nick[i] == '\n'
|
* Returns true if `ch` is not in the `invalid_chars` array.
|
||||||
|| nick[i] == '\t'
|
*/
|
||||||
|| nick[i] == '\v'
|
static bool is_valid_char(char ch)
|
||||||
|| nick[i] == '\r')
|
{
|
||||||
|
char tmp;
|
||||||
|
|
||||||
return 0;
|
for (size_t i = 0; (tmp = invalid_chars[i]); ++i) {
|
||||||
|
if (tmp == ch) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns true if nick is valid.
|
||||||
|
*
|
||||||
|
* A valid toxic nick:
|
||||||
|
* - cannot be empty
|
||||||
|
* - cannot start with a space
|
||||||
|
* - must not contain a forward slash (for logfile naming purposes)
|
||||||
|
* - must not contain contiguous spaces
|
||||||
|
* - must not contain a newline or tab seqeunce
|
||||||
|
*/
|
||||||
|
bool valid_nick(const char *nick)
|
||||||
|
{
|
||||||
|
if (!nick[0] || nick[0] == ' ') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; nick[i]; ++i) {
|
||||||
|
char ch = nick[i];
|
||||||
|
|
||||||
|
if ((ch == ' ' && nick[i + 1] == ' ') || !is_valid_char(ch)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Converts all newline/tab chars to spaces (use for strings that should be contained to a single line) */
|
/* Converts all newline/tab chars to spaces (use for strings that should be contained to a single line) */
|
||||||
void filter_str(char *str, size_t len)
|
void filter_str(char *str, size_t len)
|
||||||
{
|
{
|
||||||
size_t i;
|
for (size_t i = 0; i < len; ++i) {
|
||||||
|
char ch = str[i];
|
||||||
|
|
||||||
for (i = 0; i < len; ++i) {
|
if (!is_valid_char(ch) || str[i] == '\0') {
|
||||||
if (str[i] == '\n' || str[i] == '\r' || str[i] == '\t' || str[i] == '\v' || str[i] == '\0')
|
|
||||||
str[i] = ' ';
|
str[i] = ' ';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,22 +335,26 @@ 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);
|
||||||
@ -291,13 +371,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';
|
||||||
@ -310,8 +392,9 @@ 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.
|
||||||
@ -319,45 +402,71 @@ void str_to_lower(char *str)
|
|||||||
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)
|
||||||
{
|
{
|
||||||
size_t len = tox_friend_get_name_size(m, friendnum, NULL);
|
Tox_Err_Friend_Query err;
|
||||||
|
size_t len = tox_friend_get_name_size(m, friendnum, &err);
|
||||||
|
|
||||||
if (len == 0) {
|
if (err != TOX_ERR_FRIEND_QUERY_OK) {
|
||||||
strcpy(buf, UNKNOWN_NAME);
|
goto on_error;
|
||||||
len = strlen(UNKNOWN_NAME);
|
|
||||||
} else {
|
} else {
|
||||||
tox_friend_get_name(m, friendnum, (uint8_t *) buf, NULL);
|
if (!tox_friend_get_name(m, friendnum, (uint8_t *) buf, NULL)) {
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
|
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
|
||||||
buf[len] = '\0';
|
buf[len] = '\0';
|
||||||
filter_str(buf, len);
|
filter_str(buf, len);
|
||||||
return len;
|
return len;
|
||||||
|
|
||||||
|
on_error:
|
||||||
|
strcpy(buf, UNKNOWN_NAME);
|
||||||
|
len = strlen(UNKNOWN_NAME);
|
||||||
|
buf[len] = '\0';
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* same as get_nick_truncate but for groupchats */
|
/* same as get_nick_truncate but for conferences */
|
||||||
int get_group_nick_truncate(Tox *m, char *buf, int peernum, int groupnum)
|
int get_conference_nick_truncate(Tox *m, char *buf, uint32_t peernum, uint32_t conferencenum)
|
||||||
{
|
{
|
||||||
int len = tox_group_peername(m, groupnum, peernum, (uint8_t *) buf);
|
Tox_Err_Conference_Peer_Query err;
|
||||||
|
size_t len = tox_conference_peer_get_name_size(m, conferencenum, peernum, &err);
|
||||||
|
|
||||||
if (len == -1) {
|
if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
|
||||||
strcpy(buf, UNKNOWN_NAME);
|
goto on_error;
|
||||||
len = strlen(UNKNOWN_NAME);
|
} else {
|
||||||
|
if (!tox_conference_peer_get_name(m, conferencenum, peernum, (uint8_t *) buf, NULL)) {
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
|
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
|
||||||
buf[len] = '\0';
|
buf[len] = '\0';
|
||||||
filter_str(buf, len);
|
filter_str(buf, len);
|
||||||
return len;
|
return len;
|
||||||
|
|
||||||
|
on_error:
|
||||||
|
strcpy(buf, UNKNOWN_NAME);
|
||||||
|
len = strlen(UNKNOWN_NAME);
|
||||||
|
buf[len] = '\0';
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copies data to msg buffer.
|
/* copies data to msg buffer, removing return characters.
|
||||||
returns length of msg, which will be no larger than size-1 */
|
returns length of msg, which will be no larger than size-1 */
|
||||||
size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length)
|
size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length)
|
||||||
{
|
{
|
||||||
size_t len = MIN(length, size - 1);
|
size_t i;
|
||||||
memcpy(msg, data, len);
|
size_t j = 0;
|
||||||
msg[len] = '\0';
|
|
||||||
return len;
|
for (i = 0; (i < length) && (j < size - 1); ++i) {
|
||||||
|
if (data[i] != '\r') {
|
||||||
|
msg[j++] = data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
msg[j] = '\0';
|
||||||
|
|
||||||
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns index of the first instance of ch in s starting at idx.
|
/* returns index of the first instance of ch in s starting at idx.
|
||||||
@ -371,8 +480,9 @@ 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;
|
||||||
@ -389,8 +499,9 @@ 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;
|
||||||
@ -425,45 +536,59 @@ 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;
|
||||||
|
|
||||||
|
if (stat(path, &s) == -1) {
|
||||||
|
return FILE_TYPE_OTHER;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* compares the first size bytes of fp to signature.
|
|
||||||
Returns 0 if they are the same, 1 if they differ, and -1 on error.
|
|
||||||
|
|
||||||
On success this function will seek back to the beginning of fp */
|
|
||||||
int check_file_signature(const char *signature, size_t size, FILE *fp)
|
|
||||||
{
|
|
||||||
char buf[size];
|
|
||||||
|
|
||||||
if (fread(buf, size, 1, fp) != 1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
int ret = memcmp(signature, buf, size);
|
|
||||||
|
|
||||||
if (fseek(fp, 0L, SEEK_SET) == -1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return ret == 0 ? 0 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* sets window title in tab bar. */
|
/* sets window title in tab bar. */
|
||||||
void set_window_title(ToxWindow *self, const char *title, int len)
|
void set_window_title(ToxWindow *self, const char *title, int len)
|
||||||
{
|
{
|
||||||
|
if (len <= 0 || !title) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
char cpy[TOXIC_MAX_NAME_LENGTH + 1];
|
char cpy[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
|
|
||||||
if (self->is_groupchat) /* keep groupnumber in title */
|
if (self->type == WINDOW_TYPE_CONFERENCE) { /* keep conferencenumber in title for invites */
|
||||||
snprintf(cpy, sizeof(cpy), "%d %s", self->num, title);
|
snprintf(cpy, sizeof(cpy), "%u %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], "...");
|
||||||
@ -473,35 +598,49 @@ void set_window_title(ToxWindow *self, const char *title, int len)
|
|||||||
snprintf(self->name, sizeof(self->name), "%s", cpy);
|
snprintf(self->name, sizeof(self->name), "%s", cpy);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return true if address appears to be a valid ipv4 address. */
|
/*
|
||||||
bool is_ip4_address(const char *address)
|
* Frees all members of a pointer array plus `arr`.
|
||||||
|
*/
|
||||||
|
void free_ptr_array(void **arr)
|
||||||
{
|
{
|
||||||
struct sockaddr_in s_addr;
|
if (arr == NULL) {
|
||||||
return inet_pton(AF_INET, address, &(s_addr.sin_addr)) != 0;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void **tmp = arr;
|
||||||
|
|
||||||
|
while (*arr) {
|
||||||
|
free(*arr);
|
||||||
|
++arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return true if address roughly appears to be a valid ipv6 address.
|
/*
|
||||||
|
* Returns a null terminated array of `length` pointers. Each pointer is allocated `bytes` bytes.
|
||||||
|
* Returns NULL on failure.
|
||||||
*
|
*
|
||||||
* TODO: Improve this function (inet_pton behaves strangely with ipv6).
|
* The caller is responsible for freeing the array with `free_ptr_array`.
|
||||||
* for now the only guarantee is that it won't return true if the
|
|
||||||
* address is a domain or ipv4 address, and should only be used if you're
|
|
||||||
* reasonably sure that the address is one of the three (ipv4, ipv6 or a domain).
|
|
||||||
*/
|
*/
|
||||||
bool is_ip6_address(const char *address)
|
void **malloc_ptr_array(size_t length, size_t bytes)
|
||||||
{
|
{
|
||||||
size_t i;
|
void **arr = malloc((length + 1) * sizeof(void *));
|
||||||
size_t num_colons = 0;
|
|
||||||
char ch = 0;
|
|
||||||
|
|
||||||
for (i = 0; (ch = address[i]); ++i) {
|
if (arr == NULL) {
|
||||||
if (ch == '.') {
|
return NULL;
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (ch == ':') {
|
for (size_t i = 0; i < length; ++i) {
|
||||||
++num_colons;
|
arr[i] = malloc(bytes);
|
||||||
|
|
||||||
|
if (arr[i] == NULL) {
|
||||||
|
free_ptr_array(arr);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return num_colons > 1 && num_colons < 8;
|
arr[length] = NULL;
|
||||||
|
|
||||||
|
return arr;
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,8 @@
|
|||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include "windows.h"
|
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
#ifndef MIN
|
#ifndef MIN
|
||||||
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
||||||
@ -39,6 +39,17 @@
|
|||||||
#define net_to_host(x, y) hst_to_net(x, y)
|
#define net_to_host(x, y) hst_to_net(x, y)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define UNUSED_VAR(x) ((void) x)
|
||||||
|
|
||||||
|
typedef enum File_Type {
|
||||||
|
FILE_TYPE_REGULAR,
|
||||||
|
FILE_TYPE_DIRECTORY,
|
||||||
|
FILE_TYPE_OTHER,
|
||||||
|
} File_Type;
|
||||||
|
|
||||||
|
|
||||||
|
void clear_screen(void);
|
||||||
|
|
||||||
void hst_to_net(uint8_t *num, uint16_t numbytes);
|
void hst_to_net(uint8_t *num, uint16_t numbytes);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -60,6 +71,13 @@ 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);
|
||||||
|
|
||||||
|
/* Converts a binary representation of a Tox public key into a string.
|
||||||
|
*
|
||||||
|
* Returns 0 on success.
|
||||||
|
* Returns -1 on failure.
|
||||||
|
*/
|
||||||
|
int bin_pubkey_to_string(const uint8_t *bin_pubkey, size_t bin_pubkey_size, char *output, size_t output_size);
|
||||||
|
|
||||||
/* get the current unix time (not thread safe) */
|
/* get the current unix time (not thread safe) */
|
||||||
time_t get_unix_time(void);
|
time_t get_unix_time(void);
|
||||||
|
|
||||||
@ -78,31 +96,40 @@ 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 */
|
||||||
int timed_out(time_t timestamp, time_t timeout);
|
int timed_out(time_t timestamp, time_t timeout);
|
||||||
|
|
||||||
|
/* Sleeps the caller's thread for `usec` microseconds */
|
||||||
|
void sleep_thread(long int usec);
|
||||||
|
|
||||||
/* Colours the window tab according to type. Beeps if is_beep is true */
|
/* Colours the window tab according to type. Beeps if is_beep is true */
|
||||||
void alert_window(ToxWindow *self, int type, bool is_beep);
|
void alert_window(ToxWindow *self, int type, bool is_beep);
|
||||||
|
|
||||||
/* case-insensitive string compare function for use with qsort */
|
/* case-insensitive string compare function for use with qsort */
|
||||||
int qsort_strcasecmp_hlpr(const void *str1, const void *str2);
|
int qsort_strcasecmp_hlpr(const void *str1, const void *str2);
|
||||||
|
|
||||||
/* Returns 1 if nick is valid, 0 if not. A valid toxic nick:
|
/* case-insensitive string compare function for use with qsort */
|
||||||
- cannot be empty
|
int qsort_ptr_char_array_helper(const void *str1, const void *str2);
|
||||||
- cannot start with a space
|
|
||||||
- must not contain a forward slash (for logfile naming purposes)
|
/* Returns true if nick is valid.
|
||||||
- must not contain contiguous spaces
|
*
|
||||||
- must not contain a newline or tab seqeunce */
|
* A valid toxic nick:
|
||||||
int valid_nick(const char *nick);
|
* - cannot be empty
|
||||||
|
* - cannot start with a space
|
||||||
|
* - must not contain a forward slash (for logfile naming purposes)
|
||||||
|
* - must not contain contiguous spaces
|
||||||
|
* - must not contain a newline or tab seqeunce
|
||||||
|
*/
|
||||||
|
bool valid_nick(const char *nick);
|
||||||
|
|
||||||
/* Converts all newline/tab chars to spaces (use for strings that should be contained to a single line) */
|
/* Converts all newline/tab chars to spaces (use for strings that should be contained to a single line) */
|
||||||
void filter_str(char *str, size_t len);
|
void filter_str(char *str, size_t len);
|
||||||
@ -125,8 +152,8 @@ void str_to_lower(char *str);
|
|||||||
Returns nick len on success, -1 on failure */
|
Returns nick len on success, -1 on failure */
|
||||||
size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum);
|
size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum);
|
||||||
|
|
||||||
/* same as get_nick_truncate but for groupchats */
|
/* same as get_nick_truncate but for conferences */
|
||||||
int get_group_nick_truncate(Tox *m, char *buf, int peernum, int groupnum);
|
int get_conference_nick_truncate(Tox *m, char *buf, uint32_t peernum, uint32_t conferencenum);
|
||||||
|
|
||||||
/* copies data to msg buffer.
|
/* copies data to msg buffer.
|
||||||
returns length of msg, which will be no larger than size-1 */
|
returns length of msg, which will be no larger than size-1 */
|
||||||
@ -146,28 +173,32 @@ 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);
|
||||||
|
|
||||||
/* compares the first size bytes of fp and signature.
|
|
||||||
Returns 0 if they are the same, 1 if they differ, and -1 on error.
|
|
||||||
|
|
||||||
On success this function will seek back to the beginning of fp */
|
|
||||||
int check_file_signature(const char *signature, size_t size, FILE *fp);
|
|
||||||
|
|
||||||
/* sets window title in tab bar. */
|
/* sets window title in tab bar. */
|
||||||
void set_window_title(ToxWindow *self, const char *title, int len);
|
void set_window_title(ToxWindow *self, const char *title, int len);
|
||||||
|
|
||||||
/* Return true if address appears to be a valid ipv4 address. */
|
/*
|
||||||
bool is_ip4_address(const char *address);
|
* Frees all members of a pointer array plus `arr`.
|
||||||
|
|
||||||
/* Return true if address roughly appears to be a valid ipv6 address.
|
|
||||||
*
|
|
||||||
* TODO: Improve this function (inet_pton behaves strangely with ipv6).
|
|
||||||
* for now the only guarantee is that it won't return true if the
|
|
||||||
* address is a domain or ipv4 address, and should only be used if you're
|
|
||||||
* reasonably sure that the address is one of the three (ipv4, ipv6 or a domain).
|
|
||||||
*/
|
*/
|
||||||
bool is_ip6_address(const char *address);
|
void free_ptr_array(void **arr);
|
||||||
|
|
||||||
#endif /* #define MISC_TOOLS_H */
|
/*
|
||||||
|
* Returns a null terminated array of `length` pointers. Each pointer is allocated `bytes` bytes.
|
||||||
|
* Returns NULL on failure.
|
||||||
|
*
|
||||||
|
* The caller is responsible for freeing the array with `free_ptr_array`.
|
||||||
|
*/
|
||||||
|
void **malloc_ptr_array(size_t length, size_t bytes);
|
||||||
|
|
||||||
|
#endif /* MISC_TOOLS_H */
|
||||||
|
@ -20,17 +20,18 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <curl/curl.h>
|
|
||||||
|
|
||||||
#include "toxic.h"
|
|
||||||
#include "windows.h"
|
|
||||||
#include "line_info.h"
|
|
||||||
#include "global_commands.h"
|
|
||||||
#include "misc_tools.h"
|
|
||||||
#include "configdir.h"
|
#include "configdir.h"
|
||||||
#include "curl_util.h"
|
#include "curl_util.h"
|
||||||
|
#include "global_commands.h"
|
||||||
|
#include "line_info.h"
|
||||||
|
#include "misc_tools.h"
|
||||||
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
extern struct arg_opts arg_opts;
|
extern struct arg_opts arg_opts;
|
||||||
extern struct Winthread Winthread;
|
extern struct Winthread Winthread;
|
||||||
@ -41,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];
|
||||||
@ -62,6 +63,13 @@ static struct lookup_thread {
|
|||||||
pthread_attr_t attr;
|
pthread_attr_t attr;
|
||||||
} lookup_thread;
|
} lookup_thread;
|
||||||
|
|
||||||
|
static void clear_thread_data(void)
|
||||||
|
{
|
||||||
|
t_data = (struct thread_data) {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
static int lookup_error(ToxWindow *self, const char *errmsg, ...)
|
static int lookup_error(ToxWindow *self, const char *errmsg, ...)
|
||||||
{
|
{
|
||||||
char frmt_msg[MAX_STR_SIZE];
|
char frmt_msg[MAX_STR_SIZE];
|
||||||
@ -80,7 +88,7 @@ static int lookup_error(ToxWindow *self, const char *errmsg, ...)
|
|||||||
|
|
||||||
static void kill_lookup_thread(void)
|
static void kill_lookup_thread(void)
|
||||||
{
|
{
|
||||||
memset(&t_data, 0, sizeof(struct thread_data));
|
clear_thread_data();
|
||||||
pthread_attr_destroy(&lookup_thread.attr);
|
pthread_attr_destroy(&lookup_thread.attr);
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
@ -96,42 +104,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;
|
||||||
}
|
}
|
||||||
@ -144,8 +159,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;
|
||||||
@ -155,8 +171,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);
|
||||||
@ -196,29 +213,35 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *lookup_thread_func(void *data)
|
void *lookup_thread_func(void *data)
|
||||||
{
|
{
|
||||||
|
UNUSED_VAR(data);
|
||||||
|
|
||||||
ToxWindow *self = t_data.self;
|
ToxWindow *self = t_data.self;
|
||||||
|
|
||||||
char input_domain[MAX_STR_SIZE];
|
char input_domain[MAX_STR_SIZE];
|
||||||
@ -233,10 +256,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();
|
||||||
}
|
}
|
||||||
@ -248,28 +272,39 @@ void *lookup_thread_func(void *data)
|
|||||||
kill_lookup_thread();
|
kill_lookup_thread();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Recv_Curl_Data recv_data;
|
struct Recv_Curl_Data *recv_data = calloc(1, sizeof(struct Recv_Curl_Data));
|
||||||
memset(&recv_data, 0, sizeof(struct Recv_Curl_Data));
|
|
||||||
|
if (recv_data == NULL) {
|
||||||
|
lookup_error(self, "memory allocation error");
|
||||||
|
kill_lookup_thread();
|
||||||
|
}
|
||||||
|
|
||||||
|
char post_data[MAX_STR_SIZE + 30];
|
||||||
|
|
||||||
char post_data[MAX_STR_SIZE];
|
|
||||||
snprintf(post_data, sizeof(post_data), "{\"action\": 3, \"name\": \"%s\"}", name);
|
snprintf(post_data, sizeof(post_data), "{\"action\": 3, \"name\": \"%s\"}", name);
|
||||||
|
|
||||||
struct curl_slist *headers = NULL;
|
struct curl_slist *headers = NULL;
|
||||||
|
|
||||||
headers = curl_slist_append(headers, "Content-Type: application/json");
|
headers = curl_slist_append(headers, "Content-Type: application/json");
|
||||||
|
|
||||||
headers = curl_slist_append(headers, "charsets: utf-8");
|
headers = curl_slist_append(headers, "charsets: utf-8");
|
||||||
|
|
||||||
curl_easy_setopt(c_handle, CURLOPT_HTTPHEADER, headers);
|
curl_easy_setopt(c_handle, CURLOPT_HTTPHEADER, headers);
|
||||||
|
|
||||||
curl_easy_setopt(c_handle, CURLOPT_URL, real_domain);
|
curl_easy_setopt(c_handle, CURLOPT_URL, real_domain);
|
||||||
|
|
||||||
curl_easy_setopt(c_handle, CURLOPT_WRITEFUNCTION, curl_cb_write_data);
|
curl_easy_setopt(c_handle, CURLOPT_WRITEFUNCTION, curl_cb_write_data);
|
||||||
curl_easy_setopt(c_handle, CURLOPT_WRITEDATA, &recv_data);
|
|
||||||
|
curl_easy_setopt(c_handle, CURLOPT_WRITEDATA, recv_data);
|
||||||
|
|
||||||
curl_easy_setopt(c_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
|
curl_easy_setopt(c_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
|
||||||
|
|
||||||
curl_easy_setopt(c_handle, CURLOPT_POSTFIELDS, post_data);
|
curl_easy_setopt(c_handle, CURLOPT_POSTFIELDS, post_data);
|
||||||
|
|
||||||
int proxy_ret = set_curl_proxy(c_handle, arg_opts.proxy_address, arg_opts.proxy_port, arg_opts.proxy_type);
|
int proxy_ret = set_curl_proxy(c_handle, arg_opts.proxy_address, arg_opts.proxy_port, arg_opts.proxy_type);
|
||||||
|
|
||||||
if (proxy_ret != 0) {
|
if (proxy_ret != 0) {
|
||||||
lookup_error(self, "Failed to set proxy (error %d)\n");
|
lookup_error(self, "Failed to set proxy (error %d)\n", proxy_ret);
|
||||||
goto on_exit;
|
goto on_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,7 +344,7 @@ void *lookup_thread_func(void *data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process_response(&recv_data) == -1) {
|
if (process_response(recv_data) == -1) {
|
||||||
lookup_error(self, "Bad response.");
|
lookup_error(self, "Bad response.");
|
||||||
goto on_exit;
|
goto on_exit;
|
||||||
}
|
}
|
||||||
@ -319,6 +354,7 @@ void *lookup_thread_func(void *data)
|
|||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
on_exit:
|
on_exit:
|
||||||
|
free(recv_data);
|
||||||
curl_slist_free_all(headers);
|
curl_slist_free_all(headers);
|
||||||
curl_easy_cleanup(c_handle);
|
curl_easy_cleanup(c_handle);
|
||||||
kill_lookup_thread();
|
kill_lookup_thread();
|
||||||
@ -347,21 +383,21 @@ void name_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr,
|
|||||||
|
|
||||||
if (pthread_attr_init(&lookup_thread.attr) != 0) {
|
if (pthread_attr_init(&lookup_thread.attr) != 0) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread attr failed to init");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread attr failed to init");
|
||||||
memset(&t_data, 0, sizeof(struct thread_data));
|
clear_thread_data();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pthread_attr_setdetachstate(&lookup_thread.attr, PTHREAD_CREATE_DETACHED) != 0) {
|
if (pthread_attr_setdetachstate(&lookup_thread.attr, PTHREAD_CREATE_DETACHED) != 0) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread attr failed to set");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread attr failed to set");
|
||||||
pthread_attr_destroy(&lookup_thread.attr);
|
pthread_attr_destroy(&lookup_thread.attr);
|
||||||
memset(&t_data, 0, sizeof(struct thread_data));
|
clear_thread_data();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pthread_create(&lookup_thread.tid, &lookup_thread.attr, lookup_thread_func, NULL) != 0) {
|
if (pthread_create(&lookup_thread.tid, &lookup_thread.attr, lookup_thread_func, NULL) != 0) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread failed to init");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread failed to init");
|
||||||
pthread_attr_destroy(&lookup_thread.attr);
|
pthread_attr_destroy(&lookup_thread.attr);
|
||||||
memset(&t_data, 0, sizeof(struct thread_data));
|
clear_thread_data();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
489
src/notify.c
489
src/notify.c
@ -20,51 +20,51 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "notify.h"
|
|
||||||
#include "audio_device.h"
|
#include "audio_device.h"
|
||||||
#include "settings.h"
|
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
#include "xtra.h"
|
#include "notify.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "x11focus.h"
|
||||||
|
|
||||||
#if defined(AUDIO) || defined(SOUND_NOTIFY)
|
#if defined(AUDIO) || defined(SOUND_NOTIFY)
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <OpenAL/al.h>
|
#include <OpenAL/al.h>
|
||||||
#include <OpenAL/alc.h>
|
#include <OpenAL/alc.h>
|
||||||
#else
|
#else
|
||||||
#include <AL/al.h>
|
#include <AL/al.h>
|
||||||
#include <AL/alc.h>
|
#include <AL/alc.h>
|
||||||
/* 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>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MAX_BOX_MSG_LEN 127
|
#define MAX_BOX_MSG_LEN 127
|
||||||
#define SOUNDS_SIZE 10
|
#define SOUNDS_SIZE 10
|
||||||
#define ACTIVE_NOTIFS_MAX 50
|
#define ACTIVE_NOTIFS_MAX 10
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
@ -75,25 +75,25 @@ struct Control {
|
|||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
uint32_t device_idx; /* index of output device */
|
uint32_t device_idx; /* index of output device */
|
||||||
char* sounds[SOUNDS_SIZE];
|
char *sounds[SOUNDS_SIZE];
|
||||||
#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
|
||||||
NotifyNotification* box;
|
NotifyNotification *box;
|
||||||
char messages[MAX_BOX_MSG_LEN + 1][MAX_BOX_MSG_LEN + 1];
|
char messages[MAX_BOX_MSG_LEN + 1][MAX_BOX_MSG_LEN + 1];
|
||||||
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];
|
||||||
/**********************************************************************************/
|
/**********************************************************************************/
|
||||||
/**********************************************************************************/
|
/**********************************************************************************/
|
||||||
@ -101,24 +101,40 @@ struct _ActiveNotifications {
|
|||||||
/**********************************************************************************/
|
/**********************************************************************************/
|
||||||
/**********************************************************************************/
|
/**********************************************************************************/
|
||||||
|
|
||||||
|
static void clear_actives_index(size_t idx)
|
||||||
|
{
|
||||||
|
if (actives[idx].id_indicator) {
|
||||||
|
*actives[idx].id_indicator = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
actives[idx] = (struct _ActiveNotifications) {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
++self->pending_messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 +144,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,21 +173,25 @@ 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_output_device(&Control.device_idx, 48000, 20, 1);
|
||||||
|
|
||||||
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,32 +199,37 @@ 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();
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
for (i = 0; i < ACTIVE_NOTIFS_MAX; ++i) {
|
||||||
if (actives[i].active) {
|
if (actives[i].active) {
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
|
|
||||||
if (actives[i].box) {
|
if (actives[i].box) {
|
||||||
GError* ignore;
|
GError *ignore;
|
||||||
notify_notification_close(actives[i].box, &ignore);
|
notify_notification_close(actives[i].box, &ignore);
|
||||||
actives[i].box = NULL;
|
actives[i].box = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if(actives[i].id_indicator)
|
#endif /* BOX_NOTIFY */
|
||||||
|
|
||||||
|
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));
|
clear_actives_index(i);
|
||||||
else break;
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -215,17 +240,17 @@ void graceful_clear()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
usleep(1000);
|
sleep_thread(1000L);
|
||||||
}
|
}
|
||||||
|
|
||||||
control_unlock();
|
control_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void* do_playing(void* _p)
|
void *do_playing(void *_p)
|
||||||
{
|
{
|
||||||
(void)_p;
|
UNUSED_VAR(_p);
|
||||||
|
|
||||||
while(true) {
|
while (true) {
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
if (!Control.poll_active) {
|
if (!Control.poll_active) {
|
||||||
@ -237,63 +262,75 @@ void* do_playing(void* _p)
|
|||||||
bool test_active_notify = false;
|
bool test_active_notify = false;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
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
|
||||||
test_active_notify = test_active_notify && !actives[i].box;
|
test_active_notify = test_active_notify && !actives[i].box;
|
||||||
#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 */
|
||||||
alSourceStop(actives[i].source);
|
alSourceStop(actives[i].source);
|
||||||
alDeleteSources(1, &actives[i].source);
|
alDeleteSources(1, &actives[i].source);
|
||||||
alDeleteBuffers(1, &actives[i].buffer);
|
alDeleteBuffers(1, &actives[i].buffer);
|
||||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
clear_actives_index(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef BOX_NOTIFY
|
|
||||||
else if (actives[i].box && time(NULL) >= actives[i].n_timeout)
|
#ifdef BOX_NOTIFY
|
||||||
{
|
else if (actives[i].box && time(NULL) >= actives[i].n_timeout) {
|
||||||
GError* ignore;
|
GError *ignore;
|
||||||
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 */
|
||||||
alSourceStop(actives[i].source);
|
alSourceStop(actives[i].source);
|
||||||
alDeleteSources(1, &actives[i].source);
|
alDeleteSources(1, &actives[i].source);
|
||||||
alDeleteBuffers(1, &actives[i].buffer);
|
alDeleteBuffers(1, &actives[i].buffer);
|
||||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
clear_actives_index(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#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*/
|
||||||
if (device_opened && !has_looping &&
|
if (device_opened && !has_looping &&
|
||||||
(time(NULL) - last_opened_update) > DEVICE_COOLDOWN) {
|
(time(NULL) - last_opened_update) > DEVICE_COOLDOWN) {
|
||||||
m_close_device();
|
m_close_device();
|
||||||
}
|
}
|
||||||
|
|
||||||
has_looping = false;
|
has_looping = false;
|
||||||
|
|
||||||
control_unlock();
|
control_unlock();
|
||||||
usleep(10000);
|
sleep_thread(10000L);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int play_source(uint32_t source, uint32_t buffer, bool looping)
|
int play_source(uint32_t source, uint32_t buffer, bool looping)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (; i < ACTIVE_NOTIFS_MAX && actives[i].active; i ++);
|
|
||||||
if ( i == ACTIVE_NOTIFS_MAX ) {
|
for (; i < ACTIVE_NOTIFS_MAX && actives[i].active; ++i);
|
||||||
|
|
||||||
|
if (i == ACTIVE_NOTIFS_MAX) {
|
||||||
return -1; /* Full */
|
return -1; /* Full */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,11 +345,11 @@ int play_source(uint32_t source, uint32_t buffer, bool looping)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#elif BOX_NOTIFY
|
#elif BOX_NOTIFY
|
||||||
void* do_playing(void* _p)
|
void *do_playing(void *_p)
|
||||||
{
|
{
|
||||||
(void)_p;
|
UNUSED_VAR(_p);
|
||||||
|
|
||||||
while(true) {
|
while (true) {
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
if (!Control.poll_active) {
|
if (!Control.poll_active) {
|
||||||
@ -320,47 +357,64 @@ void* do_playing(void* _p)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i;
|
for (size_t i = 0; i < ACTIVE_NOTIFS_MAX; ++i) {
|
||||||
|
if (actives[i].box && time(NULL) >= actives[i].n_timeout) {
|
||||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
GError *ignore;
|
||||||
if (actives[i].box && time(NULL) >= actives[i].n_timeout)
|
|
||||||
{
|
|
||||||
GError* ignore;
|
|
||||||
notify_notification_close(actives[i].box, &ignore);
|
notify_notification_close(actives[i].box, &ignore);
|
||||||
actives[i].box = NULL;
|
clear_actives_index(i);
|
||||||
if(actives[i].id_indicator)
|
|
||||||
*actives[i].id_indicator = -1; /* reset indicator value */
|
|
||||||
|
|
||||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
control_unlock();
|
control_unlock();
|
||||||
usleep(10000);
|
sleep_thread(10000L);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void graceful_clear()
|
void graceful_clear(void)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
for (size_t i = 0; i < ACTIVE_NOTIFS_MAX; ++i) {
|
||||||
if (actives[i].box) {
|
if (actives[i].box) {
|
||||||
GError* ignore;
|
GError *ignore;
|
||||||
notify_notification_close(actives[i].box, &ignore);
|
notify_notification_close(actives[i].box, &ignore);
|
||||||
actives[i].box = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actives[i].id_indicator)
|
clear_actives_index(i);
|
||||||
*actives[i].id_indicator = -1; /* reset indicator value */
|
}
|
||||||
|
|
||||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
control_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* SOUND_NOTIFY */
|
||||||
|
|
||||||
|
/* Kills all notifications for `id`. This must be called before freeing a ToxWindow. */
|
||||||
|
void kill_notifs(int id)
|
||||||
|
{
|
||||||
|
control_lock();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < ACTIVE_NOTIFS_MAX; ++i) {
|
||||||
|
if (!actives[i].id_indicator) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*actives[i].id_indicator == id) {
|
||||||
|
#ifdef BOX_NOTIFY
|
||||||
|
|
||||||
|
if (actives[i].box) {
|
||||||
|
GError *ignore;
|
||||||
|
notify_notification_close(actives[i].box, &ignore);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // BOX_NOTIFY
|
||||||
|
clear_actives_index(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
control_unlock();
|
control_unlock();
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/**********************************************************************************/
|
/**********************************************************************************/
|
||||||
/**********************************************************************************/
|
/**********************************************************************************/
|
||||||
@ -378,19 +432,21 @@ int init_notify(int login_cooldown, int notification_timeout)
|
|||||||
#endif /* SOUND_NOTIFY */
|
#endif /* SOUND_NOTIFY */
|
||||||
|
|
||||||
#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;
|
||||||
|
|
||||||
if (pthread_create(&thread, NULL, do_playing, NULL) != 0 || pthread_detach(thread) != 0 ) {
|
if (pthread_create(&thread, NULL, do_playing, NULL) != 0 || pthread_detach(thread) != 0) {
|
||||||
pthread_mutex_destroy(Control.poll_mutex);
|
pthread_mutex_destroy(Control.poll_mutex);
|
||||||
Control.poll_active = 0;
|
Control.poll_active = 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif /* defined(SOUND_NOTIFY) || defined(BOX_NOTIFY) */
|
||||||
Control.cooldown = time(NULL) + login_cooldown;
|
Control.cooldown = time(NULL) + login_cooldown;
|
||||||
|
|
||||||
|
|
||||||
@ -401,12 +457,12 @@ 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();
|
||||||
|
|
||||||
if ( !Control.poll_active ) {
|
if (!Control.poll_active) {
|
||||||
control_unlock();
|
control_unlock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -415,11 +471,15 @@ 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 */
|
||||||
|
|
||||||
@ -429,9 +489,11 @@ 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]);
|
||||||
|
|
||||||
@ -457,10 +519,11 @@ int play_sound_internal(Notification what, bool loop)
|
|||||||
alSourcei(source, AL_LOOPING, loop);
|
alSourcei(source, AL_LOOPING, loop);
|
||||||
|
|
||||||
int rc = play_source(source, buffer, loop);
|
int rc = play_source(source, buffer, loop);
|
||||||
|
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
alSourceStop(source);
|
alSourceStop(source);
|
||||||
alDeleteSources(1, &source);
|
alDeleteSources(1, &source);
|
||||||
alDeleteBuffers(1,&buffer);
|
alDeleteBuffers(1, &buffer);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -471,10 +534,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);
|
||||||
}
|
}
|
||||||
@ -482,73 +549,72 @@ int play_notify_sound(Notification notif, uint64_t flags)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void stop_sound(int id)
|
void stop_sound(int id)
|
||||||
{
|
{
|
||||||
if (id >= 0 && id < ACTIVE_NOTIFS_MAX && actives[id].looping && actives[id].active ) {
|
if (id >= 0 && id < ACTIVE_NOTIFS_MAX && actives[id].looping && actives[id].active) {
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
|
|
||||||
if (actives[id].box) {
|
if (actives[id].box) {
|
||||||
GError* ignore;
|
GError *ignore;
|
||||||
notify_notification_close(actives[id].box, &ignore);
|
notify_notification_close(actives[id].box, &ignore);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
if (actives[id].id_indicator)
|
#endif /* BOX_NOTIFY */
|
||||||
*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);
|
||||||
alDeleteSources(1, &actives[id].source);
|
alDeleteSources(1, &actives[id].source);
|
||||||
alDeleteBuffers(1,&actives[id].buffer);
|
alDeleteBuffers(1, &actives[id].buffer);
|
||||||
memset(&actives[id], 0, sizeof(struct _ActiveNotifications));
|
clear_actives_index(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* SOUND_NOTIFY */
|
||||||
|
|
||||||
static int m_play_sound(Notification notif, uint64_t flags)
|
static int m_play_sound(Notification notif, uint64_t flags)
|
||||||
{
|
{
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
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
|
int sound_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indicator)
|
||||||
void m_notify_action(NotifyNotification *box, char *action, void* data)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
if (id == -1) {
|
if (id == -1) {
|
||||||
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].box; id++);
|
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].box; id++);
|
||||||
if ( id == ACTIVE_NOTIFS_MAX ) {
|
|
||||||
|
if (id == ACTIVE_NOTIFS_MAX) {
|
||||||
control_unlock();
|
control_unlock();
|
||||||
return -1; /* Full */
|
return -1; /* Full */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#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;
|
||||||
*id_indicator = id;
|
*id_indicator = id;
|
||||||
}
|
}
|
||||||
@ -558,14 +624,18 @@ int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_in
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
|
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();
|
||||||
|
|
||||||
@ -578,7 +648,7 @@ int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
|
|||||||
|
|
||||||
alSourceStop(actives[id].source);
|
alSourceStop(actives[id].source);
|
||||||
alDeleteSources(1, &actives[id].source);
|
alDeleteSources(1, &actives[id].source);
|
||||||
alDeleteBuffers(1,&actives[id].buffer);
|
alDeleteBuffers(1, &actives[id].buffer);
|
||||||
|
|
||||||
alGenSources(1, &actives[id].source);
|
alGenSources(1, &actives[id].source);
|
||||||
alGenBuffers(1, &actives[id].buffer);
|
alGenBuffers(1, &actives[id].buffer);
|
||||||
@ -592,14 +662,17 @@ 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 */
|
||||||
}
|
}
|
||||||
|
|
||||||
int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator, const char* title, const char* format, ...)
|
int box_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indicator, const char *title,
|
||||||
|
const char *format, ...)
|
||||||
{
|
{
|
||||||
if (notifications_are_disabled(flags)) {
|
if (notifications_are_disabled(flags)) {
|
||||||
tab_notify(self, flags);
|
tab_notify(self, flags);
|
||||||
@ -613,32 +686,46 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi
|
|||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
|
|
||||||
if (id == -1) { /* Could not play */
|
if (id == -1) { /* Could not play */
|
||||||
|
|
||||||
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++);
|
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++);
|
||||||
if ( id == ACTIVE_NOTIFS_MAX ) {
|
|
||||||
|
if (id == ACTIVE_NOTIFS_MAX) {
|
||||||
control_unlock();
|
control_unlock();
|
||||||
return -1; /* Full */
|
return -1; /* Full */
|
||||||
}
|
}
|
||||||
|
|
||||||
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, "...");
|
|
||||||
|
|
||||||
va_list __ARGS__; va_start (__ARGS__, format);
|
if (strlen(title) > 23) {
|
||||||
vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
|
strcpy(actives[id].title + 20, "...");
|
||||||
va_end (__ARGS__);
|
}
|
||||||
|
|
||||||
if (strlen(actives[id].messages[0]) > MAX_BOX_MSG_LEN - 3)
|
va_list __ARGS__;
|
||||||
|
va_start(__ARGS__, format);
|
||||||
|
vsnprintf(actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
|
||||||
|
va_end(__ARGS__);
|
||||||
|
|
||||||
|
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++;
|
||||||
@ -653,10 +740,10 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi
|
|||||||
return id;
|
return id;
|
||||||
#else
|
#else
|
||||||
return sound_notify(self, notif, flags, id_indicator);
|
return sound_notify(self, notif, flags, id_indicator);
|
||||||
#endif /* BOX_NOTIFY */
|
#endif /* BOX_NOTIFY */
|
||||||
}
|
}
|
||||||
|
|
||||||
int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, const char* format, ...)
|
int box_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id, const char *format, ...)
|
||||||
{
|
{
|
||||||
if (notifications_are_disabled(flags)) {
|
if (notifications_are_disabled(flags)) {
|
||||||
tab_notify(self, flags);
|
tab_notify(self, flags);
|
||||||
@ -665,8 +752,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();
|
||||||
|
|
||||||
@ -675,51 +763,55 @@ int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, con
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
va_list __ARGS__; va_start (__ARGS__, format);
|
va_list __ARGS__;
|
||||||
vsnprintf (actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __ARGS__);
|
va_start(__ARGS__, format);
|
||||||
va_end (__ARGS__);
|
vsnprintf(actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __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;
|
||||||
|
|
||||||
char formated[128 * 129] = {'\0'};
|
char *formatted = calloc(1, sizeof(char) * ((MAX_BOX_MSG_LEN + 1) * (MAX_BOX_MSG_LEN + 2)));
|
||||||
|
|
||||||
int i = 0;
|
for (size_t i = 0; i < actives[id].size; ++i) {
|
||||||
for (; i <actives[id].size; i ++) {
|
strcat(formatted, actives[id].messages[i]);
|
||||||
strcat(formated, actives[id].messages[i]);
|
strcat(formatted, "\n");
|
||||||
strcat(formated, "\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
formated[strlen(formated) - 1] = '\0';
|
notify_notification_update(actives[id].box, actives[id].title, formatted, NULL);
|
||||||
|
|
||||||
notify_notification_update(actives[id].box, actives[id].title, formated, NULL);
|
|
||||||
notify_notification_show(actives[id].box, NULL);
|
notify_notification_show(actives[id].box, NULL);
|
||||||
|
|
||||||
|
free(formatted);
|
||||||
|
|
||||||
control_unlock();
|
control_unlock();
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
int id;
|
int id;
|
||||||
|
|
||||||
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++);
|
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++);
|
||||||
if ( id == ACTIVE_NOTIFS_MAX ) {
|
|
||||||
|
if (id == ACTIVE_NOTIFS_MAX) {
|
||||||
control_unlock();
|
control_unlock();
|
||||||
return -1; /* Full */
|
return -1; /* Full */
|
||||||
}
|
}
|
||||||
@ -730,14 +822,19 @@ 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, "...");
|
|
||||||
|
|
||||||
va_list __ARGS__; va_start (__ARGS__, format);
|
if (strlen(title) > 23) {
|
||||||
vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
|
strcpy(actives[id].title + 20, "...");
|
||||||
va_end (__ARGS__);
|
}
|
||||||
|
|
||||||
if (strlen(actives[id].messages[0]) > MAX_BOX_MSG_LEN - 3)
|
va_list __ARGS__;
|
||||||
|
va_start(__ARGS__, format);
|
||||||
|
vsnprintf(actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
|
||||||
|
va_end(__ARGS__);
|
||||||
|
|
||||||
|
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);
|
||||||
@ -753,52 +850,54 @@ 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();
|
||||||
|
|
||||||
if (id < 0 || id >= ACTIVE_NOTIFS_MAX || !actives[id].box || actives[id].size >= MAX_BOX_MSG_LEN + 1 ) {
|
if (id < 0 || id >= ACTIVE_NOTIFS_MAX || !actives[id].box || actives[id].size >= MAX_BOX_MSG_LEN + 1) {
|
||||||
control_unlock();
|
control_unlock();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
va_list __ARGS__; va_start (__ARGS__, format);
|
va_list __ARGS__;
|
||||||
vsnprintf (actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __ARGS__);
|
va_start(__ARGS__, format);
|
||||||
va_end (__ARGS__);
|
vsnprintf(actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __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;
|
||||||
|
|
||||||
char formated[128 * 129] = {'\0'};
|
char *formatted = calloc(1, sizeof(char) * ((MAX_BOX_MSG_LEN + 1) * (MAX_BOX_MSG_LEN + 2)));
|
||||||
|
|
||||||
int i = 0;
|
for (size_t i = 0; i < actives[id].size; ++i) {
|
||||||
for (; i <actives[id].size; i ++) {
|
strcat(formatted, actives[id].messages[i]);
|
||||||
strcat(formated, actives[id].messages[i]);
|
strcat(formatted, "\n");
|
||||||
strcat(formated, "\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
formated[strlen(formated) - 1] = '\0';
|
notify_notification_update(actives[id].box, actives[id].title, formatted, NULL);
|
||||||
|
|
||||||
notify_notification_update(actives[id].box, actives[id].title, formated, NULL);
|
|
||||||
notify_notification_show(actives[id].box, NULL);
|
notify_notification_show(actives[id].box, NULL);
|
||||||
|
|
||||||
|
free(formatted);
|
||||||
|
|
||||||
control_unlock();
|
control_unlock();
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
#else
|
#else
|
||||||
return -1;
|
return -1;
|
||||||
#endif
|
#endif /* BOX_NOTIFY */
|
||||||
}
|
}
|
||||||
|
25
src/notify.h
25
src/notify.h
@ -23,11 +23,10 @@
|
|||||||
#ifndef NOTIFY_H
|
#ifndef NOTIFY_H
|
||||||
#define NOTIFY_H
|
#define NOTIFY_H
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <stdint.h>
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
|
|
||||||
typedef enum _Notification
|
typedef enum _Notification {
|
||||||
{
|
|
||||||
silent = -1,
|
silent = -1,
|
||||||
notif_error,
|
notif_error,
|
||||||
self_log_in,
|
self_log_in,
|
||||||
@ -61,20 +60,24 @@ 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);
|
/* Kills all notifications for `id`. This must be called before freeing a ToxWindow. */
|
||||||
int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id);
|
void kill_notifs(int id);
|
||||||
|
|
||||||
|
int sound_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indicator);
|
||||||
|
int sound_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id);
|
||||||
|
|
||||||
void stop_sound(int id);
|
void stop_sound(int id);
|
||||||
|
|
||||||
int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator, const char* title, const char* format, ...);
|
int box_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indicator, const char *title,
|
||||||
int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, const char* format, ...);
|
const char *format, ...);
|
||||||
int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const char* title, const char* format, ...);
|
int box_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id, const char *format, ...);
|
||||||
int box_silent_notify2(ToxWindow* self, uint64_t flags, int id, const char* format, ...);
|
int box_silent_notify(ToxWindow *self, uint64_t flags, int *id_indicator, const char *title, const char *format, ...);
|
||||||
|
int box_silent_notify2(ToxWindow *self, uint64_t flags, int id, const char *format, ...);
|
||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
int set_sound(Notification sound, const char* value);
|
int set_sound(Notification sound, const char *value);
|
||||||
#endif /* SOUND_NOTIFY */
|
#endif /* SOUND_NOTIFY */
|
||||||
|
|
||||||
#endif /* NOTIFY_H */
|
#endif /* NOTIFY_H */
|
||||||
|
@ -31,18 +31,21 @@
|
|||||||
#endif /* __OBJC__ */
|
#endif /* __OBJC__ */
|
||||||
|
|
||||||
#define RELEASE_CHK(func, obj) if ((obj))\
|
#define RELEASE_CHK(func, obj) if ((obj))\
|
||||||
func((obj));
|
func((obj));
|
||||||
|
|
||||||
void bgrtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *rgb, uint16_t width, uint16_t height);
|
void bgrtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *rgb, uint16_t width, uint16_t height);
|
||||||
|
|
||||||
#ifdef __OBJC__
|
#ifdef __OBJC__
|
||||||
@interface OSXVideo : NSObject <AVCaptureVideoDataOutputSampleBufferDelegate>
|
@interface OSXVideo :
|
||||||
- (instancetype)initWithDeviceNames:(char **)device_names AmtDevices:(int *)size;
|
NSObject <AVCaptureVideoDataOutputSampleBufferDelegate>
|
||||||
|
- (instancetype)initWithDeviceNames:
|
||||||
|
(char **)device_names AmtDevices:
|
||||||
|
(int *)size;
|
||||||
@end
|
@end
|
||||||
#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 */
|
||||||
|
122
src/osx_video.m
122
src/osx_video.m
@ -44,19 +44,19 @@
|
|||||||
static uint8_t rgb_to_y(int r, int g, int b)
|
static uint8_t rgb_to_y(int r, int g, int b)
|
||||||
{
|
{
|
||||||
int y = ((9798 * r + 19235 * g + 3736 * b) >> 15);
|
int y = ((9798 * r + 19235 * g + 3736 * b) >> 15);
|
||||||
return y>255? 255 : y<0 ? 0 : y;
|
return y > 255 ? 255 : y < 0 ? 0 : y;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t rgb_to_u(int r, int g, int b)
|
static uint8_t rgb_to_u(int r, int g, int b)
|
||||||
{
|
{
|
||||||
int u = ((-5538 * r + -10846 * g + 16351 * b) >> 15) + 128;
|
int u = ((-5538 * r + -10846 * g + 16351 * b) >> 15) + 128;
|
||||||
return u>255? 255 : u<0 ? 0 : u;
|
return u > 255 ? 255 : u < 0 ? 0 : u;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t rgb_to_v(int r, int g, int b)
|
static uint8_t rgb_to_v(int r, int g, int b)
|
||||||
{
|
{
|
||||||
int v = ((16351 * r + -13697 * g + -2664 * b) >> 15) + 128;
|
int v = ((16351 * r + -13697 * g + -2664 * b) >> 15) + 128;
|
||||||
return v>255? 255 : v<0 ? 0 : v;
|
return v > 255 ? 255 : v < 0 ? 0 : v;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *rgb, uint16_t width, uint16_t height)
|
void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *rgb, uint16_t width, uint16_t height)
|
||||||
@ -65,9 +65,10 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
|
|||||||
uint8_t *p;
|
uint8_t *p;
|
||||||
uint8_t r, g, b;
|
uint8_t r, g, b;
|
||||||
|
|
||||||
for(y = 0; y != height; y += 2) {
|
for (y = 0; y != height; y += 2) {
|
||||||
p = rgb;
|
p = rgb;
|
||||||
for(x = 0; x != width; x++) {
|
|
||||||
|
for (x = 0; x != width; x++) {
|
||||||
b = *rgb++;
|
b = *rgb++;
|
||||||
g = *rgb++;
|
g = *rgb++;
|
||||||
r = *rgb++;
|
r = *rgb++;
|
||||||
@ -76,7 +77,7 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
|
|||||||
*plane_y++ = rgb_to_y(r, g, b);
|
*plane_y++ = rgb_to_y(r, g, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(x = 0; x != width / 2; x++) {
|
for (x = 0; x != width / 2; x++) {
|
||||||
b = *rgb++;
|
b = *rgb++;
|
||||||
g = *rgb++;
|
g = *rgb++;
|
||||||
r = *rgb++;
|
r = *rgb++;
|
||||||
@ -91,9 +92,12 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
|
|||||||
|
|
||||||
*plane_y++ = rgb_to_y(r, g, b);
|
*plane_y++ = rgb_to_y(r, g, b);
|
||||||
|
|
||||||
b = ((int)b + (int)*(rgb - 8) + (int)*p + (int)*(p + 4) + 2) / 4; p++;
|
b = ((int)b + (int) * (rgb - 8) + (int) * p + (int) * (p + 4) + 2) / 4;
|
||||||
g = ((int)g + (int)*(rgb - 7) + (int)*p + (int)*(p + 4) + 2) / 4; p++;
|
p++;
|
||||||
r = ((int)r + (int)*(rgb - 6) + (int)*p + (int)*(p + 4) + 2) / 4; p++;
|
g = ((int)g + (int) * (rgb - 7) + (int) * p + (int) * (p + 4) + 2) / 4;
|
||||||
|
p++;
|
||||||
|
r = ((int)r + (int) * (rgb - 6) + (int) * p + (int) * (p + 4) + 2) / 4;
|
||||||
|
p++;
|
||||||
p++;
|
p++;
|
||||||
|
|
||||||
*plane_u++ = rgb_to_u(r, g, b);
|
*plane_u++ = rgb_to_u(r, g, b);
|
||||||
@ -122,28 +126,35 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
|
|||||||
BOOL _shouldMangleDimensions;
|
BOOL _shouldMangleDimensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithDeviceNames: (char **)device_names AmtDevices: (int *)size {
|
- (instancetype)initWithDeviceNames:
|
||||||
|
(char **)device_names AmtDevices:
|
||||||
|
(int *)size
|
||||||
|
{
|
||||||
_session = [[AVCaptureSession alloc] init];
|
_session = [[AVCaptureSession alloc] init];
|
||||||
|
|
||||||
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
|
NSArray *devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < [devices count]; ++i) {
|
for (i = 0; i < [devices count]; ++i) {
|
||||||
AVCaptureDevice *device = [devices objectAtIndex:i];
|
AVCaptureDevice *device = [devices objectAtIndex: i];
|
||||||
char *video_input_name;
|
char *video_input_name;
|
||||||
NSString *localizedName = [device localizedName];
|
NSString *localizedName = [device localizedName];
|
||||||
video_input_name = (char*)malloc(strlen([localizedName cStringUsingEncoding:NSUTF8StringEncoding]) + 1);
|
video_input_name = (char *)malloc(strlen([localizedName cStringUsingEncoding: NSUTF8StringEncoding]) + 1);
|
||||||
strcpy(video_input_name, (char*)[localizedName cStringUsingEncoding:NSUTF8StringEncoding]);
|
strcpy(video_input_name, (char *)[localizedName cStringUsingEncoding: NSUTF8StringEncoding]);
|
||||||
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;
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc {
|
- (void)dealloc
|
||||||
|
{
|
||||||
pthread_mutex_destroy(&_frameLock);
|
pthread_mutex_destroy(&_frameLock);
|
||||||
[_session release];
|
[_session release];
|
||||||
[_linkerVideo release];
|
[_linkerVideo release];
|
||||||
@ -151,22 +162,26 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
|
|||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int)openVideoDeviceIndex: (uint32_t)device_idx Width: (uint16_t *)width Height: (uint16_t *)height {
|
- (int)openVideoDeviceIndex:
|
||||||
|
(uint32_t)device_idx Width:
|
||||||
|
(uint16_t *)width Height:
|
||||||
|
(uint16_t *)height
|
||||||
|
{
|
||||||
pthread_mutex_init(&_frameLock, NULL);
|
pthread_mutex_init(&_frameLock, NULL);
|
||||||
pthread_mutex_lock(&_frameLock);
|
pthread_mutex_lock(&_frameLock);
|
||||||
_processingQueue = dispatch_queue_create("Toxic processing queue", DISPATCH_QUEUE_SERIAL);
|
_processingQueue = dispatch_queue_create("Toxic processing queue", DISPATCH_QUEUE_SERIAL);
|
||||||
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
|
NSArray *devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo];
|
||||||
AVCaptureDevice *device = [devices objectAtIndex:device_idx];
|
AVCaptureDevice *device = [devices objectAtIndex: device_idx];
|
||||||
NSError *error = NULL;
|
NSError *error = NULL;
|
||||||
AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error];
|
AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice: device error: &error];
|
||||||
|
|
||||||
if ( error != NULL ) {
|
if (error != NULL) {
|
||||||
[input release];
|
[input release];
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
[_session beginConfiguration];
|
[_session beginConfiguration];
|
||||||
[_session addInput:input];
|
[_session addInput: input];
|
||||||
//_session.sessionPreset = AVCaptureSessionPreset640x480;
|
//_session.sessionPreset = AVCaptureSessionPreset640x480;
|
||||||
//*width = 640;
|
//*width = 640;
|
||||||
//*height = 480;
|
//*height = 480;
|
||||||
@ -176,9 +191,10 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
|
|||||||
[device release];
|
[device release];
|
||||||
|
|
||||||
/* Obtain device resolution */
|
/* Obtain device resolution */
|
||||||
AVCaptureInputPort *port = [input.ports objectAtIndex:0];
|
AVCaptureInputPort *port = [input.ports objectAtIndex: 0];
|
||||||
CMFormatDescriptionRef format_description = port.formatDescription;
|
CMFormatDescriptionRef format_description = port.formatDescription;
|
||||||
if ( format_description ) {
|
|
||||||
|
if (format_description) {
|
||||||
CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(format_description);
|
CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(format_description);
|
||||||
*width = dimensions.width;
|
*width = dimensions.width;
|
||||||
*height = dimensions.height;
|
*height = dimensions.height;
|
||||||
@ -188,36 +204,47 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
_linkerVideo = [[AVCaptureVideoDataOutput alloc] init];
|
_linkerVideo = [[AVCaptureVideoDataOutput alloc] init];
|
||||||
[_linkerVideo setSampleBufferDelegate:self queue:_processingQueue];
|
[_linkerVideo setSampleBufferDelegate: self queue: _processingQueue];
|
||||||
|
|
||||||
// TODO possibly get a better pixel format
|
// TODO possibly get a better pixel format
|
||||||
if (_shouldMangleDimensions) {
|
if (_shouldMangleDimensions) {
|
||||||
[_linkerVideo setVideoSettings:@{(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA),
|
[_linkerVideo setVideoSettings: @ {
|
||||||
(id)kCVPixelBufferWidthKey: @640,
|
(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA),
|
||||||
(id)kCVPixelBufferHeightKey: @480}];
|
(id)kCVPixelBufferWidthKey: @640,
|
||||||
|
(id)kCVPixelBufferHeightKey: @480
|
||||||
|
}];
|
||||||
} else {
|
} else {
|
||||||
[_linkerVideo setVideoSettings:@{(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)}];
|
[_linkerVideo setVideoSettings: @ {(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)}];
|
||||||
}
|
}
|
||||||
[_session addOutput:_linkerVideo];
|
|
||||||
|
[_session addOutput: _linkerVideo];
|
||||||
[_session startRunning];
|
[_session startRunning];
|
||||||
|
|
||||||
pthread_mutex_unlock(&_frameLock);
|
pthread_mutex_unlock(&_frameLock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)closeVideoDeviceIndex: (uint32_t)device_idx {
|
- (void)closeVideoDeviceIndex:
|
||||||
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
|
(uint32_t)device_idx
|
||||||
AVCaptureDevice *device = [devices objectAtIndex:device_idx];
|
{
|
||||||
|
NSArray *devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo];
|
||||||
|
AVCaptureDevice *device = [devices objectAtIndex: device_idx];
|
||||||
NSError *error = NULL;
|
NSError *error = NULL;
|
||||||
AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error];
|
AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice: device error: &error];
|
||||||
[_session stopRunning];
|
[_session stopRunning];
|
||||||
[_session removeOutput:_linkerVideo];
|
[_session removeOutput: _linkerVideo];
|
||||||
[_session removeInput:input];
|
[_session removeInput: input];
|
||||||
[_linkerVideo release];
|
[_linkerVideo release];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
|
- (void)captureOutput:
|
||||||
|
(AVCaptureOutput *)captureOutput didOutputSampleBuffer:
|
||||||
|
(CMSampleBufferRef)sampleBuffer fromConnection:
|
||||||
|
(AVCaptureConnection *)connection
|
||||||
|
{
|
||||||
pthread_mutex_lock(&_frameLock);
|
pthread_mutex_lock(&_frameLock);
|
||||||
CVImageBufferRef img = CMSampleBufferGetImageBuffer(sampleBuffer);
|
CVImageBufferRef img = CMSampleBufferGetImageBuffer(sampleBuffer);
|
||||||
|
|
||||||
if (!img) {
|
if (!img) {
|
||||||
NSLog(@"Toxic WARNING: Bad sampleBuffer from AVfoundation!");
|
NSLog(@"Toxic WARNING: Bad sampleBuffer from AVfoundation!");
|
||||||
} else {
|
} else {
|
||||||
@ -228,10 +255,17 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
|
|||||||
// we're not going to do anything to it, so it's safe to lock it always
|
// we're not going to do anything to it, so it's safe to lock it always
|
||||||
CVPixelBufferLockBaseAddress(_currentFrame, kCVPixelBufferLock_ReadOnly);
|
CVPixelBufferLockBaseAddress(_currentFrame, kCVPixelBufferLock_ReadOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&_frameLock);
|
pthread_mutex_unlock(&_frameLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int)getVideoFrameY: (uint8_t *)y U: (uint8_t *)u V: (uint8_t *)v Width: (uint16_t *)width Height: (uint16_t *)height {
|
- (int)getVideoFrameY:
|
||||||
|
(uint8_t *)y U:
|
||||||
|
(uint8_t *)u V:
|
||||||
|
(uint8_t *)v Width:
|
||||||
|
(uint16_t *)width Height:
|
||||||
|
(uint16_t *)height
|
||||||
|
{
|
||||||
if (!_currentFrame) {
|
if (!_currentFrame) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -240,6 +274,7 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
|
|||||||
CFRetain(_currentFrame);
|
CFRetain(_currentFrame);
|
||||||
|
|
||||||
CFTypeID imageType = CFGetTypeID(_currentFrame);
|
CFTypeID imageType = CFGetTypeID(_currentFrame);
|
||||||
|
|
||||||
if (imageType == CVPixelBufferGetTypeID()) {
|
if (imageType == CVPixelBufferGetTypeID()) {
|
||||||
// TODO maybe handle other formats
|
// TODO maybe handle other formats
|
||||||
bgrxtoyuv420(y, u, v, CVPixelBufferGetBaseAddress(_currentFrame), *width, *height);
|
bgrxtoyuv420(y, u, v, CVPixelBufferGetBaseAddress(_currentFrame), *width, *height);
|
||||||
@ -263,14 +298,15 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
|
|||||||
/*
|
/*
|
||||||
* C-interface for OSXVideo
|
* C-interface for OSXVideo
|
||||||
*/
|
*/
|
||||||
static OSXVideo* _OSXVideo = nil;
|
static OSXVideo *_OSXVideo = nil;
|
||||||
|
|
||||||
int osx_video_init(char **device_names, int *size)
|
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;
|
||||||
}
|
}
|
||||||
@ -283,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];
|
||||||
}
|
}
|
||||||
@ -296,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];
|
||||||
}
|
}
|
||||||
|
333
src/prompt.c
333
src/prompt.c
@ -28,20 +28,20 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
|
||||||
#include "toxic.h"
|
|
||||||
#include "windows.h"
|
|
||||||
#include "prompt.h"
|
|
||||||
#include "friendlist.h"
|
|
||||||
#include "execute.h"
|
|
||||||
#include "misc_tools.h"
|
|
||||||
#include "toxic_strings.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "line_info.h"
|
|
||||||
#include "settings.h"
|
|
||||||
#include "input.h"
|
|
||||||
#include "help.h"
|
|
||||||
#include "notify.h"
|
|
||||||
#include "autocomplete.h"
|
#include "autocomplete.h"
|
||||||
|
#include "execute.h"
|
||||||
|
#include "friendlist.h"
|
||||||
|
#include "help.h"
|
||||||
|
#include "input.h"
|
||||||
|
#include "line_info.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "misc_tools.h"
|
||||||
|
#include "notify.h"
|
||||||
|
#include "prompt.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "toxic.h"
|
||||||
|
#include "toxic_strings.h"
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
extern ToxWindow *prompt;
|
extern ToxWindow *prompt;
|
||||||
extern struct user_settings *user_settings;
|
extern struct user_settings *user_settings;
|
||||||
@ -49,49 +49,50 @@ extern struct Winthread Winthread;
|
|||||||
|
|
||||||
extern FriendsList Friends;
|
extern FriendsList Friends;
|
||||||
FriendRequests FrndRequests;
|
FriendRequests FrndRequests;
|
||||||
#ifdef VIDEO
|
|
||||||
#define AC_NUM_GLOB_COMMANDS 22
|
|
||||||
#elif AUDIO
|
|
||||||
#define AC_NUM_GLOB_COMMANDS 20
|
|
||||||
#else
|
|
||||||
#define AC_NUM_GLOB_COMMANDS 18
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* 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[] = {
|
||||||
{ "/accept" },
|
"/accept",
|
||||||
{ "/add" },
|
"/add",
|
||||||
{ "/avatar" },
|
"/avatar",
|
||||||
{ "/clear" },
|
"/clear",
|
||||||
{ "/connect" },
|
"/connect",
|
||||||
{ "/decline" },
|
"/decline",
|
||||||
{ "/exit" },
|
"/exit",
|
||||||
{ "/group" },
|
"/conference",
|
||||||
{ "/help" },
|
"/help",
|
||||||
{ "/log" },
|
"/log",
|
||||||
{ "/myid" },
|
"/myid",
|
||||||
{ "/myqr" },
|
#ifdef QRCODE
|
||||||
{ "/nick" },
|
"/myqr",
|
||||||
{ "/note" },
|
#endif /* QRCODE */
|
||||||
{ "/nospam" },
|
"/nick",
|
||||||
{ "/quit" },
|
"/note",
|
||||||
{ "/requests" },
|
"/nospam",
|
||||||
{ "/status" },
|
"/quit",
|
||||||
|
"/requests",
|
||||||
|
"/status",
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
|
|
||||||
{ "/lsdev" },
|
"/lsdev",
|
||||||
{ "/sdev" },
|
"/sdev",
|
||||||
|
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
|
|
||||||
{ "/lsvdev" },
|
"/lsvdev",
|
||||||
{ "/svdev" },
|
"/svdev",
|
||||||
|
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
|
|
||||||
|
#ifdef PYTHON
|
||||||
|
|
||||||
|
"/run",
|
||||||
|
|
||||||
|
#endif /* PYTHON */
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void kill_prompt_window(ToxWindow *self)
|
void kill_prompt_window(ToxWindow *self)
|
||||||
@ -115,8 +116,10 @@ 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)
|
||||||
{
|
{
|
||||||
|
UNUSED_VAR(m);
|
||||||
|
UNUSED_VAR(userdata);
|
||||||
StatusBar *statusbar = prompt->stb;
|
StatusBar *statusbar = prompt->stb;
|
||||||
statusbar->connection = connection_status;
|
statusbar->connection = connection_status;
|
||||||
}
|
}
|
||||||
@ -137,26 +140,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;
|
||||||
|
|
||||||
@ -166,8 +178,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;
|
||||||
|
|
||||||
@ -178,7 +191,10 @@ static int add_friend_request(const char *public_key, const char *data)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
/*
|
||||||
|
* Return true if input is recognized by handler
|
||||||
|
*/
|
||||||
|
static bool prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
@ -186,43 +202,64 @@ 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)
|
UNUSED_VAR(y);
|
||||||
return;
|
|
||||||
|
|
||||||
if (ctx->pastemode && key == '\r')
|
if (x2 <= 0 || y2 <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
help_onKey(self, key);
|
help_onKey(self, key);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
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, x2);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (line_info_onKey(self, key))
|
if (line_info_onKey(self, key)) {
|
||||||
return;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
input_handle(self, key, x, y, x2, y2);
|
if (input_handle(self, key, x, x2)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int input_ret = false;
|
||||||
|
|
||||||
if (key == '\t') { /* TAB key: auto-completes command */
|
if (key == '\t') { /* TAB key: auto-completes command */
|
||||||
|
input_ret = true;
|
||||||
|
|
||||||
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");
|
||||||
else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0){
|
}
|
||||||
const char status_cmd_list[3][8] = {
|
|
||||||
{"online"},
|
#ifdef PYTHON
|
||||||
{"away"},
|
else if (wcsncmp(ctx->line, L"/run ", wcslen(L"/run ")) == 0) {
|
||||||
{"busy"},
|
diff = dir_match(self, m, ctx->line, L"/run");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) {
|
||||||
|
const char *status_cmd_list[] = {
|
||||||
|
"online",
|
||||||
|
"away",
|
||||||
|
"busy",
|
||||||
};
|
};
|
||||||
diff = complete_line(self, status_cmd_list, 3, 8);
|
diff = complete_line(self, status_cmd_list, sizeof(status_cmd_list) / sizeof(char *));
|
||||||
} else
|
} else {
|
||||||
diff = complete_line(self, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
|
diff = complete_line(self, glob_cmd_list, sizeof(glob_cmd_list) / sizeof(char *));
|
||||||
|
}
|
||||||
|
|
||||||
if (diff != -1) {
|
if (diff != -1) {
|
||||||
if (x + diff > x2 - 1) {
|
if (x + diff > x2 - 1) {
|
||||||
@ -236,26 +273,30 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
sound_notify(self, notif_error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
}
|
}
|
||||||
} else if (key == '\r') {
|
} else if (key == '\r') {
|
||||||
|
input_ret = true;
|
||||||
|
|
||||||
rm_trailing_spaces_buf(ctx);
|
rm_trailing_spaces_buf(ctx);
|
||||||
|
|
||||||
if (!wstring_is_empty(ctx->line))
|
if (!wstring_is_empty(ctx->line)) {
|
||||||
{
|
|
||||||
add_line_to_hist(ctx);
|
add_line_to_hist(ctx);
|
||||||
wstrsubst(ctx->line, L'¶', L'\n');
|
wstrsubst(ctx->line, L'¶', L'\n');
|
||||||
|
|
||||||
char line[MAX_STR_SIZE] = {0};
|
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));
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to parse message.");
|
||||||
|
} else {
|
||||||
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wclear(ctx->linewin);
|
wclear(ctx->linewin);
|
||||||
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
||||||
reset_buf(ctx);
|
reset_buf(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return input_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prompt_onDraw(ToxWindow *self, Tox *m)
|
static void prompt_onDraw(ToxWindow *self, Tox *m)
|
||||||
@ -263,8 +304,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;
|
||||||
|
|
||||||
@ -276,8 +318,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;
|
||||||
|
|
||||||
@ -285,7 +328,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) {
|
||||||
@ -293,7 +336,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) {
|
||||||
@ -301,10 +344,12 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
|||||||
status_text = "Online";
|
status_text = "Online";
|
||||||
colour = GREEN;
|
colour = GREEN;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_USER_STATUS_AWAY:
|
case TOX_USER_STATUS_AWAY:
|
||||||
status_text = "Away";
|
status_text = "Away";
|
||||||
colour = YELLOW;
|
colour = YELLOW;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_USER_STATUS_BUSY:
|
case TOX_USER_STATUS_BUSY:
|
||||||
status_text = "Busy";
|
status_text = "Busy";
|
||||||
colour = RED;
|
colour = RED;
|
||||||
@ -335,7 +380,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
size_t slen = tox_self_get_status_message_size(m);
|
size_t slen = 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);
|
||||||
statusmsg[slen] = '\0';
|
statusmsg[slen] = '\0';
|
||||||
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
|
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
|
||||||
statusbar->statusmsg_len = strlen(statusbar->statusmsg);
|
statusbar->statusmsg_len = strlen(statusbar->statusmsg);
|
||||||
@ -355,8 +400,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);
|
||||||
|
|
||||||
@ -364,26 +410,29 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
int y, x;
|
int y, x;
|
||||||
getyx(self->window, y, x);
|
getyx(self->window, y, x);
|
||||||
(void) x;
|
|
||||||
|
UNUSED_VAR(x);
|
||||||
|
|
||||||
int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
|
int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
|
||||||
wmove(self->window, y + 1, new_x);
|
wmove(self->window, y + 1, new_x);
|
||||||
|
|
||||||
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));
|
||||||
@ -398,29 +447,33 @@ 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)
|
||||||
{
|
{
|
||||||
|
UNUSED_VAR(m);
|
||||||
|
UNUSED_VAR(length);
|
||||||
|
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
char timefrmt[TIME_STR_SIZE];
|
char timefrmt[TIME_STR_SIZE];
|
||||||
@ -441,15 +494,16 @@ 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;
|
UNUSED_VAR(y2);
|
||||||
|
|
||||||
/* Init statusbar info */
|
/* Init statusbar info */
|
||||||
StatusBar *statusbar = self->stb;
|
StatusBar *statusbar = self->stb;
|
||||||
@ -465,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';
|
||||||
@ -493,21 +547,41 @@ static void print_welcome_msg(ToxWindow *self)
|
|||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, BLUE, " |_| \\___/_/\\_\\___\\____| v." TOXICVER);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, BLUE, " |_| \\___/_/\\_\\___\\____| v." TOXICVER);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
|
||||||
|
|
||||||
const char *msg = "Welcome to Toxic, a free, open source Tox-based instant messenging client.";
|
const char *msg = "Welcome to Toxic, a free, open source Tox-based instant messaging client.";
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, CYAN, msg);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, CYAN, msg);
|
||||||
msg = "Type \"/help\" for assistance. Further help may be found via the man page.";
|
msg = "Type \"/help\" for assistance. Further help may be found via the man page.";
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, CYAN, msg);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, CYAN, msg);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void prompt_init_log(ToxWindow *self, Tox *m, const char *self_name)
|
||||||
|
{
|
||||||
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
|
char myid[TOX_ADDRESS_SIZE];
|
||||||
|
tox_self_get_address(m, (uint8_t *) myid);
|
||||||
|
|
||||||
|
if (log_init(ctx->log, self->name, myid, NULL, LOG_TYPE_PROMPT) != 0) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user_settings->autolog == AUTOLOG_ON) {
|
||||||
|
if (log_enable(ctx->log) == -1) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Failed to enable log.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void prompt_onInit(ToxWindow *self, Tox *m)
|
static void prompt_onInit(ToxWindow *self, Tox *m)
|
||||||
{
|
{
|
||||||
curs_set(1);
|
curs_set(1);
|
||||||
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);
|
||||||
@ -516,55 +590,54 @@ 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);
|
||||||
|
|
||||||
if (user_settings->autolog == AUTOLOG_ON) {
|
prompt_init_log(self, m, self->name);
|
||||||
char myid[TOX_ADDRESS_SIZE];
|
|
||||||
tox_self_get_address(m, (uint8_t *) myid);
|
|
||||||
|
|
||||||
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.");
|
|
||||||
}
|
|
||||||
|
|
||||||
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->type = WINDOW_TYPE_PROMPT;
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
17
src/prompt.h
17
src/prompt.h
@ -26,31 +26,34 @@
|
|||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
|
|
||||||
#define MAX_FRIEND_REQUESTS 32
|
#define MAX_FRIEND_REQUESTS 20
|
||||||
|
|
||||||
struct friend_request {
|
struct friend_request {
|
||||||
bool active;
|
bool active;
|
||||||
char msg[MAX_STR_SIZE];
|
char msg[TOX_MAX_FRIEND_REQUEST_LENGTH + 1];
|
||||||
uint8_t key[TOX_PUBLIC_KEY_SIZE];
|
uint8_t key[TOX_PUBLIC_KEY_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct FriendRequests {
|
||||||
int max_idx;
|
int max_idx;
|
||||||
int num_requests;
|
int num_requests;
|
||||||
struct friend_request request[MAX_FRIEND_REQUESTS];
|
struct friend_request request[MAX_FRIEND_REQUESTS];
|
||||||
} FriendRequests;
|
} FriendRequests;
|
||||||
|
|
||||||
ToxWindow new_prompt(void);
|
ToxWindow *new_prompt(void);
|
||||||
|
|
||||||
void prep_prompt_win(void);
|
void prep_prompt_win(void);
|
||||||
void prompt_init_statusbar(ToxWindow *self, Tox *m);
|
void prompt_init_statusbar(ToxWindow *self, Tox *m, 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 */
|
||||||
|
365
src/python_api.c
Normal file
365
src/python_api.c
Normal file
@ -0,0 +1,365 @@
|
|||||||
|
/* python_api.c
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Jakob Kreuze <jakob@memeware.net>
|
||||||
|
*
|
||||||
|
* This file is part of Toxic.
|
||||||
|
*
|
||||||
|
* Toxic is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Toxic is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef PYTHON
|
||||||
|
#include <Python.h>
|
||||||
|
#include "api.h"
|
||||||
|
|
||||||
|
#include "execute.h"
|
||||||
|
|
||||||
|
extern Tox *user_tox;
|
||||||
|
|
||||||
|
static struct python_registered_func {
|
||||||
|
char *name;
|
||||||
|
char *help;
|
||||||
|
PyObject *callback;
|
||||||
|
struct python_registered_func *next;
|
||||||
|
} python_commands = {0};
|
||||||
|
|
||||||
|
static PyObject *python_api_display(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
const char *msg;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "s", &msg)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
api_display(msg);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *python_api_get_nick(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
PyObject *ret;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "")) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = api_get_nick();
|
||||||
|
|
||||||
|
if (name == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = Py_BuildValue("s", name);
|
||||||
|
free(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *python_api_get_status(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
PyObject *ret = NULL;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "")) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (api_get_status()) {
|
||||||
|
case TOX_USER_STATUS_NONE:
|
||||||
|
ret = Py_BuildValue("s", "online");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOX_USER_STATUS_AWAY:
|
||||||
|
ret = Py_BuildValue("s", "away");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOX_USER_STATUS_BUSY:
|
||||||
|
ret = Py_BuildValue("s", "busy");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *python_api_get_status_message(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
char *status;
|
||||||
|
PyObject *ret;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "")) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = api_get_status_message();
|
||||||
|
|
||||||
|
if (status == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = Py_BuildValue("s", status);
|
||||||
|
free(status);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *python_api_get_all_friends(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
FriendsList friends;
|
||||||
|
char pubkey_buf[TOX_PUBLIC_KEY_SIZE * 2 + 1];
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "")) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
friends = api_get_friendslist();
|
||||||
|
PyObject *ret = PyList_New(0);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < friends.num_friends; i++) {
|
||||||
|
for (size_t ii = 0; ii < TOX_PUBLIC_KEY_SIZE; ii++) {
|
||||||
|
snprintf(pubkey_buf + ii * 2, 3, "%02X", friends.list[i].pub_key[ii] & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
pubkey_buf[TOX_PUBLIC_KEY_SIZE * 2] = '\0';
|
||||||
|
PyObject *cur = Py_BuildValue("(s,s)", friends.list[i].name, pubkey_buf);
|
||||||
|
PyList_Append(ret, cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *python_api_send(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
const char *msg;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "s", &msg)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
api_send(msg);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *python_api_execute(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
int mode;
|
||||||
|
const char *command;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "si", &command, &mode)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
api_execute(command, mode);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *python_api_register(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
struct python_registered_func *cur;
|
||||||
|
size_t command_len, help_len;
|
||||||
|
const char *command, *help;
|
||||||
|
PyObject *callback;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "ssO:register_command", &command, &help, &callback)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PyCallable_Check(callback)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "Calback parameter must be callable");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command[0] != '/') {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "Command must be prefixed with a '/'");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (cur = &python_commands; ; cur = cur->next) {
|
||||||
|
if (cur->name != NULL && !strcmp(command, cur->name)) {
|
||||||
|
Py_XDECREF(cur->callback);
|
||||||
|
Py_XINCREF(callback);
|
||||||
|
cur->callback = callback;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur->next == NULL) {
|
||||||
|
Py_XINCREF(callback);
|
||||||
|
cur->next = malloc(sizeof(struct python_registered_func));
|
||||||
|
|
||||||
|
if (cur->next == NULL) {
|
||||||
|
return PyErr_NoMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
command_len = strlen(command);
|
||||||
|
cur->next->name = malloc(command_len + 1);
|
||||||
|
|
||||||
|
if (cur->next->name == NULL) {
|
||||||
|
return PyErr_NoMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(cur->next->name, command, command_len + 1);
|
||||||
|
help_len = strlen(help);
|
||||||
|
cur->next->help = malloc(help_len + 1);
|
||||||
|
|
||||||
|
if (cur->next->help == NULL) {
|
||||||
|
return PyErr_NoMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(cur->next->help, help, help_len + 1);
|
||||||
|
cur->next->callback = callback;
|
||||||
|
cur->next->next = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef ToxicApiMethods[] = {
|
||||||
|
{"display", python_api_display, METH_VARARGS, "Display a message to the current prompt"},
|
||||||
|
{"get_nick", python_api_get_nick, METH_VARARGS, "Return the user's current nickname"},
|
||||||
|
{"get_status", python_api_get_status, METH_VARARGS, "Returns the user's current status"},
|
||||||
|
{"get_status_message", python_api_get_status_message, METH_VARARGS, "Return the user's current status message"},
|
||||||
|
{"get_all_friends", python_api_get_all_friends, METH_VARARGS, "Return all of the user's friends"},
|
||||||
|
{"send", python_api_send, METH_VARARGS, "Send the message to the current user"},
|
||||||
|
{"execute", python_api_execute, METH_VARARGS, "Execute a command like `/nick`"},
|
||||||
|
{"register", python_api_register, METH_VARARGS, "Register a command like `/nick` to a Python function"},
|
||||||
|
{NULL, NULL, 0, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct PyModuleDef toxic_api_module = {
|
||||||
|
PyModuleDef_HEAD_INIT,
|
||||||
|
"toxic_api",
|
||||||
|
NULL,
|
||||||
|
-1,
|
||||||
|
ToxicApiMethods
|
||||||
|
};
|
||||||
|
|
||||||
|
PyMODINIT_FUNC PyInit_toxic_api(void)
|
||||||
|
{
|
||||||
|
PyObject *m = PyModule_Create(&toxic_api_module);
|
||||||
|
PyObject *global_command_const = Py_BuildValue("i", GLOBAL_COMMAND_MODE);
|
||||||
|
PyObject *chat_command_const = Py_BuildValue("i", CHAT_COMMAND_MODE);
|
||||||
|
PyObject *conference_command_const = Py_BuildValue("i", CONFERENCE_COMMAND_MODE);
|
||||||
|
PyObject_SetAttrString(m, "GLOBAL_COMMAND", global_command_const);
|
||||||
|
PyObject_SetAttrString(m, "CHAT_COMMAND", chat_command_const);
|
||||||
|
PyObject_SetAttrString(m, "CONFERENCE_COMMAND", conference_command_const);
|
||||||
|
Py_DECREF(global_command_const);
|
||||||
|
Py_DECREF(chat_command_const);
|
||||||
|
Py_DECREF(conference_command_const);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
void terminate_python(void)
|
||||||
|
{
|
||||||
|
if (python_commands.name != NULL) {
|
||||||
|
free(python_commands.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct python_registered_func *cur = NULL;
|
||||||
|
|
||||||
|
for (cur = python_commands.next; cur != NULL;) {
|
||||||
|
struct python_registered_func *old = cur;
|
||||||
|
cur = cur->next;
|
||||||
|
free(old->name);
|
||||||
|
free(old);
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_Finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_python(Tox *m)
|
||||||
|
{
|
||||||
|
user_tox = m;
|
||||||
|
PyImport_AppendInittab("toxic_api", PyInit_toxic_api);
|
||||||
|
Py_Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_python(FILE *fp, char *path)
|
||||||
|
{
|
||||||
|
PyRun_SimpleFile(fp, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
int do_python_command(int num_args, char (*args)[MAX_STR_SIZE])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
PyObject *callback_args, *args_strings;
|
||||||
|
struct python_registered_func *cur;
|
||||||
|
|
||||||
|
for (cur = &python_commands; cur != NULL; cur = cur->next) {
|
||||||
|
if (cur->name == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(args[0], cur->name)) {
|
||||||
|
args_strings = PyList_New(0);
|
||||||
|
|
||||||
|
for (i = 1; i < num_args; i++) {
|
||||||
|
PyList_Append(args_strings, Py_BuildValue("s", args[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
callback_args = PyTuple_Pack(1, args_strings);
|
||||||
|
|
||||||
|
if (PyObject_CallObject(cur->callback, callback_args) == NULL) {
|
||||||
|
api_display("Exception raised in callback function");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int python_num_registered_handlers(void)
|
||||||
|
{
|
||||||
|
int n = 0;
|
||||||
|
struct python_registered_func *cur;
|
||||||
|
|
||||||
|
for (cur = &python_commands; cur != NULL; cur = cur->next) {
|
||||||
|
if (cur->name != NULL) {
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int python_help_max_width(void)
|
||||||
|
{
|
||||||
|
size_t tmp;
|
||||||
|
int max = 0;
|
||||||
|
struct python_registered_func *cur;
|
||||||
|
|
||||||
|
for (cur = &python_commands; cur != NULL; cur = cur->next) {
|
||||||
|
if (cur->name != NULL) {
|
||||||
|
tmp = strlen(cur->help);
|
||||||
|
max = tmp > max ? tmp : max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
max = max > 50 ? 50 : max;
|
||||||
|
return 37 + max;
|
||||||
|
}
|
||||||
|
|
||||||
|
void python_draw_handler_help(WINDOW *win)
|
||||||
|
{
|
||||||
|
struct python_registered_func *cur;
|
||||||
|
|
||||||
|
for (cur = &python_commands; cur != NULL; cur = cur->next) {
|
||||||
|
if (cur->name != NULL) {
|
||||||
|
wprintw(win, " %-29s: %.50s\n", cur->name, cur->help);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* PYTHON */
|
@ -1,7 +1,7 @@
|
|||||||
/* xtra.h
|
/* python_api.h
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Toxic All Rights Reserved.
|
* Copyright (C) 2017 Jakob Kreuze <jakob@memeware.net>
|
||||||
*
|
*
|
||||||
* This file is part of Toxic.
|
* This file is part of Toxic.
|
||||||
*
|
*
|
||||||
@ -20,22 +20,20 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef XTRA_H
|
#ifndef PYTHON_API_H
|
||||||
#define XTRA_H
|
#define PYTHON_API_H
|
||||||
|
|
||||||
/* NOTE: If no xlib present don't compile */
|
#ifdef PYTHON
|
||||||
|
#include <Python.h>
|
||||||
|
#endif /* PYTHON */
|
||||||
|
|
||||||
typedef enum {
|
PyMODINIT_FUNC PyInit_toxic_api(void);
|
||||||
DT_plain,
|
void terminate_python(void);
|
||||||
DT_file_list
|
void init_python(Tox *m);
|
||||||
}
|
void run_python(FILE *fp, char *path);
|
||||||
DropType;
|
int do_python_command(int num_args, char (*args)[MAX_STR_SIZE]);
|
||||||
|
int python_num_registered_handlers(void);
|
||||||
|
int python_help_max_width(void);
|
||||||
|
void python_draw_handler_help(WINDOW *win);
|
||||||
|
|
||||||
typedef void (*drop_callback) (const char*, DropType);
|
#endif /* PYTHON_API_H */
|
||||||
|
|
||||||
int init_xtra(drop_callback d);
|
|
||||||
void terminate_xtra();
|
|
||||||
long unsigned int focused_window_id();
|
|
||||||
int is_focused(); /* returns bool */
|
|
||||||
|
|
||||||
#endif /* XTRA_H */
|
|
167
src/qr_code.c
167
src/qr_code.c
@ -20,45 +20,62 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#ifdef QRCODE
|
||||||
|
|
||||||
#include <qrencode.h>
|
#include <qrencode.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "qr_code.h"
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#include "qr_code.h"
|
|
||||||
|
#ifdef QRPNG
|
||||||
|
#include <png.h>
|
||||||
|
#define INCHES_PER_METER (100.0/2.54)
|
||||||
|
#define DPI 72
|
||||||
|
#define SQUARE_SIZE 5
|
||||||
|
#endif /* QRPNG */
|
||||||
|
|
||||||
#define BORDER_LEN 1
|
#define BORDER_LEN 1
|
||||||
#define CHAR_1 "\342\226\210"
|
#define CHAR_1 "\342\226\210"
|
||||||
#define CHAR_2 "\342\226\204"
|
#define CHAR_2 "\342\226\204"
|
||||||
#define CHAR_3 "\342\226\200"
|
#define CHAR_3 "\342\226\200"
|
||||||
|
|
||||||
/* Converts a tox ID string into a QRcode and prints it to the given file stream.
|
/* Converts a tox ID string into a QRcode and prints it into the given filename.
|
||||||
*
|
*
|
||||||
* Returns 0 on success.
|
* Returns 0 on success.
|
||||||
* Returns -1 on failure.
|
* Returns -1 on failure.
|
||||||
*/
|
*/
|
||||||
int ID_to_QRcode(const char *tox_id, FILE *fp)
|
int ID_to_QRcode_txt(const char *tox_id, const char *outfile)
|
||||||
{
|
{
|
||||||
if (fp == NULL)
|
FILE *fp = fopen(outfile, "wb");
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
if (qr_obj == NULL)
|
if (qr_obj == NULL) {
|
||||||
|
fclose(fp);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
@ -67,23 +84,147 @@ int ID_to_QRcode(const char *tox_id, FILE *fp)
|
|||||||
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
QRcode_free(qr_obj);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef QRPNG
|
||||||
|
/* Converts a tox ID string into a QRcode and prints it into the given filename as png.
|
||||||
|
*
|
||||||
|
* Returns 0 on success.
|
||||||
|
* Returns -1 on failure.
|
||||||
|
*/
|
||||||
|
int ID_to_QRcode_png(const char *tox_id, const char *outfile)
|
||||||
|
{
|
||||||
|
static FILE *fp;
|
||||||
|
unsigned char *p;
|
||||||
|
unsigned char black[4] = {0, 0, 0, 255};
|
||||||
|
size_t x, y, xx, yy, real_width;
|
||||||
|
png_structp png_ptr;
|
||||||
|
png_infop info_ptr;
|
||||||
|
|
||||||
|
fp = fopen(outfile, "wb");
|
||||||
|
|
||||||
|
if (fp == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRcode *qr_obj = QRcode_encodeString(tox_id, 0, QR_ECLEVEL_L, QR_MODE_8, 0);
|
||||||
|
|
||||||
|
if (qr_obj == NULL) {
|
||||||
|
fclose(fp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
real_width = (qr_obj->width + BORDER_LEN * 2) * SQUARE_SIZE;
|
||||||
|
size_t row_size = real_width * 4;
|
||||||
|
unsigned char *row = malloc(row_size);
|
||||||
|
|
||||||
|
if (row == NULL) {
|
||||||
|
fclose(fp);
|
||||||
|
QRcode_free(qr_obj);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
if (png_ptr == NULL) {
|
||||||
|
fclose(fp);
|
||||||
|
free(row);
|
||||||
|
QRcode_free(qr_obj);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
info_ptr = png_create_info_struct(png_ptr);
|
||||||
|
|
||||||
|
if (info_ptr == NULL) {
|
||||||
|
fclose(fp);
|
||||||
|
free(row);
|
||||||
|
QRcode_free(qr_obj);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||||
|
fclose(fp);
|
||||||
|
free(row);
|
||||||
|
QRcode_free(qr_obj);
|
||||||
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_init_io(png_ptr, fp);
|
||||||
|
png_set_IHDR(png_ptr, info_ptr, real_width, real_width, 8,
|
||||||
|
PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
|
||||||
|
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||||
|
png_set_pHYs(png_ptr, info_ptr, DPI * INCHES_PER_METER,
|
||||||
|
DPI * INCHES_PER_METER, PNG_RESOLUTION_METER);
|
||||||
|
png_write_info(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
/* top margin */
|
||||||
|
memset(row, 0xff, row_size);
|
||||||
|
|
||||||
|
for (y = 0; y < BORDER_LEN * SQUARE_SIZE; y++) {
|
||||||
|
png_write_row(png_ptr, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* data */
|
||||||
|
p = qr_obj->data;
|
||||||
|
|
||||||
|
for (y = 0; y < qr_obj->width; y++) {
|
||||||
|
memset(row, 0xff, row_size);
|
||||||
|
|
||||||
|
for (x = 0; x < qr_obj->width; x++) {
|
||||||
|
for (xx = 0; xx < SQUARE_SIZE; xx++) {
|
||||||
|
if (*p & 1) {
|
||||||
|
memcpy(&row[((BORDER_LEN + x) * SQUARE_SIZE + xx) * 4], black, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (yy = 0; yy < SQUARE_SIZE; yy++) {
|
||||||
|
png_write_row(png_ptr, row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* bottom margin */
|
||||||
|
memset(row, 0xff, row_size);
|
||||||
|
|
||||||
|
for (y = 0; y < BORDER_LEN * SQUARE_SIZE; y++) {
|
||||||
|
png_write_row(png_ptr, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(row);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
png_write_end(png_ptr, info_ptr);
|
||||||
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||||
|
|
||||||
QRcode_free(qr_obj);
|
QRcode_free(qr_obj);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif /* QRPNG */
|
||||||
|
|
||||||
|
#endif /* QRCODE */
|
||||||
|
@ -23,13 +23,27 @@
|
|||||||
#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 to the given file stream.
|
/* Converts a tox ID string into a QRcode and prints it into the given filename.
|
||||||
*
|
*
|
||||||
* Returns 0 on success.
|
* Returns 0 on success.
|
||||||
* Returns -1 on failure.
|
* Returns -1 on failure.
|
||||||
*/
|
*/
|
||||||
int ID_to_QRcode(const char *tox_id, FILE *fp);
|
int ID_to_QRcode_txt(const char *tox_id, const char *outfile);
|
||||||
|
|
||||||
|
#ifdef QRPNG
|
||||||
|
#define QRCODE_FILENAME_EXT_PNG ".QRcode.png"
|
||||||
|
/* Converts a tox ID string into a QRcode and prints it into the given filename as png.
|
||||||
|
*
|
||||||
|
* Returns 0 on success.
|
||||||
|
* Returns -1 on failure.
|
||||||
|
*/
|
||||||
|
int ID_to_QRcode_png(const char *tox_id, const char *outfile);
|
||||||
|
#endif /* QRPNG */
|
||||||
|
|
||||||
|
#endif /* QRCODE */
|
||||||
|
|
||||||
#endif /* QR_CODE */
|
#endif /* QR_CODE */
|
||||||
|
370
src/settings.c
370
src/settings.c
@ -20,57 +20,59 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <libconfig.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <libconfig.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
|
#include "configdir.h"
|
||||||
|
#include "misc_tools.h"
|
||||||
|
#include "notify.h"
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#include "configdir.h"
|
|
||||||
#include "notify.h"
|
|
||||||
#include "misc_tools.h"
|
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
#include "audio_device.h"
|
#include "audio_device.h"
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
#include "settings.h"
|
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
#ifndef PACKAGE_DATADIR
|
#ifndef PACKAGE_DATADIR
|
||||||
#define PACKAGE_DATADIR "."
|
#define PACKAGE_DATADIR "."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define NO_SOUND "silent"
|
#define NO_SOUND "silent"
|
||||||
|
|
||||||
static struct ui_strings {
|
static struct ui_strings {
|
||||||
const char* self;
|
const char *self;
|
||||||
const char* timestamps;
|
const char *timestamps;
|
||||||
const char* time_format;
|
const char *time_format;
|
||||||
const char* timestamp_format;
|
const char *timestamp_format;
|
||||||
const char* log_timestamp_format;
|
const char *log_timestamp_format;
|
||||||
const char* alerts;
|
const char *alerts;
|
||||||
const char* bell_on_message;
|
const char *bell_on_message;
|
||||||
const char* bell_on_filetrans;
|
const char *bell_on_filetrans;
|
||||||
const char* bell_on_filetrans_accept;
|
const char *bell_on_filetrans_accept;
|
||||||
const char* bell_on_invite;
|
const char *bell_on_invite;
|
||||||
const char* native_colors;
|
const char *native_colors;
|
||||||
const char* autolog;
|
const char *autolog;
|
||||||
const char* history_size;
|
const char *history_size;
|
||||||
const char* show_typing_self;
|
const char *notification_timeout;
|
||||||
const char* show_typing_other;
|
const char *show_typing_self;
|
||||||
const char* show_welcome_msg;
|
const char *show_typing_other;
|
||||||
const char* show_connection_msg;
|
const char *show_welcome_msg;
|
||||||
const char* nodeslist_update_freq;
|
const char *show_connection_msg;
|
||||||
|
const char *nodeslist_update_freq;
|
||||||
|
const char *autosave_freq;
|
||||||
|
|
||||||
const char* line_join;
|
const char *line_join;
|
||||||
const char* line_quit;
|
const char *line_quit;
|
||||||
const char* line_alert;
|
const char *line_alert;
|
||||||
const char* line_normal;
|
const char *line_normal;
|
||||||
|
|
||||||
const char* mplex_away;
|
const char *mplex_away;
|
||||||
const char* mplex_away_note;
|
const char *mplex_away_note;
|
||||||
} ui_strings = {
|
} ui_strings = {
|
||||||
"ui",
|
"ui",
|
||||||
"timestamps",
|
"timestamps",
|
||||||
@ -85,11 +87,13 @@ static struct ui_strings {
|
|||||||
"native_colors",
|
"native_colors",
|
||||||
"autolog",
|
"autolog",
|
||||||
"history_size",
|
"history_size",
|
||||||
|
"notification_timeout",
|
||||||
"show_typing_self",
|
"show_typing_self",
|
||||||
"show_typing_other",
|
"show_typing_other",
|
||||||
"show_welcome_msg",
|
"show_welcome_msg",
|
||||||
"show_connection_msg",
|
"show_connection_msg",
|
||||||
"nodeslist_update_freq",
|
"nodeslist_update_freq",
|
||||||
|
"autosave_freq",
|
||||||
"line_join",
|
"line_join",
|
||||||
"line_quit",
|
"line_quit",
|
||||||
"line_alert",
|
"line_alert",
|
||||||
@ -98,7 +102,7 @@ static struct ui_strings {
|
|||||||
"mplex_away_note",
|
"mplex_away_note",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ui_defaults(struct user_settings* settings)
|
static void ui_defaults(struct user_settings *settings)
|
||||||
{
|
{
|
||||||
settings->timestamps = TIMESTAMPS_ON;
|
settings->timestamps = TIMESTAMPS_ON;
|
||||||
snprintf(settings->timestamp_format, sizeof(settings->timestamp_format), "%s", TIMESTAMP_DEFAULT);
|
snprintf(settings->timestamp_format, sizeof(settings->timestamp_format), "%s", TIMESTAMP_DEFAULT);
|
||||||
@ -112,11 +116,13 @@ static void ui_defaults(struct user_settings* settings)
|
|||||||
settings->bell_on_invite = 0;
|
settings->bell_on_invite = 0;
|
||||||
settings->colour_theme = DFLT_COLS;
|
settings->colour_theme = DFLT_COLS;
|
||||||
settings->history_size = 700;
|
settings->history_size = 700;
|
||||||
|
settings->notification_timeout = 3000;
|
||||||
settings->show_typing_self = SHOW_TYPING_ON;
|
settings->show_typing_self = SHOW_TYPING_ON;
|
||||||
settings->show_typing_other = SHOW_TYPING_ON;
|
settings->show_typing_other = SHOW_TYPING_ON;
|
||||||
settings->show_welcome_msg = SHOW_WELCOME_MSG_ON;
|
settings->show_welcome_msg = SHOW_WELCOME_MSG_ON;
|
||||||
settings->show_connection_msg = SHOW_CONNECTION_MSG_ON;
|
settings->show_connection_msg = SHOW_CONNECTION_MSG_ON;
|
||||||
settings->nodeslist_update_freq = 7;
|
settings->nodeslist_update_freq = 7;
|
||||||
|
settings->autosave_freq = 600;
|
||||||
|
|
||||||
snprintf(settings->line_join, LINE_HINT_MAX + 1, "%s", LINE_JOIN);
|
snprintf(settings->line_join, LINE_HINT_MAX + 1, "%s", LINE_JOIN);
|
||||||
snprintf(settings->line_quit, LINE_HINT_MAX + 1, "%s", LINE_QUIT);
|
snprintf(settings->line_quit, LINE_HINT_MAX + 1, "%s", LINE_QUIT);
|
||||||
@ -124,25 +130,23 @@ static void ui_defaults(struct user_settings* settings)
|
|||||||
snprintf(settings->line_normal, LINE_HINT_MAX + 1, "%s", LINE_NORMAL);
|
snprintf(settings->line_normal, LINE_HINT_MAX + 1, "%s", LINE_NORMAL);
|
||||||
|
|
||||||
settings->mplex_away = MPLEX_ON;
|
settings->mplex_away = MPLEX_ON;
|
||||||
snprintf (settings->mplex_away_note,
|
snprintf(settings->mplex_away_note,
|
||||||
sizeof (settings->mplex_away_note),
|
sizeof(settings->mplex_away_note),
|
||||||
"%s",
|
"%s",
|
||||||
MPLEX_AWAY_NOTE);
|
MPLEX_AWAY_NOTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct keys_strings {
|
static const struct keys_strings {
|
||||||
const char* self;
|
const char *self;
|
||||||
const char* next_tab;
|
const char *next_tab;
|
||||||
const char* prev_tab;
|
const char *prev_tab;
|
||||||
const char* scroll_line_up;
|
const char *scroll_line_up;
|
||||||
const char* scroll_line_down;
|
const char *scroll_line_down;
|
||||||
const char* half_page_up;
|
const char *half_page_up;
|
||||||
const char* half_page_down;
|
const char *half_page_down;
|
||||||
const char* page_bottom;
|
const char *page_bottom;
|
||||||
const char* peer_list_up;
|
const char *toggle_peerlist;
|
||||||
const char* peer_list_down;
|
const char *toggle_pastemode;
|
||||||
const char* toggle_peerlist;
|
|
||||||
const char* toggle_pastemode;
|
|
||||||
} key_strings = {
|
} key_strings = {
|
||||||
"keys",
|
"keys",
|
||||||
"next_tab",
|
"next_tab",
|
||||||
@ -152,14 +156,12 @@ static const struct keys_strings {
|
|||||||
"half_page_up",
|
"half_page_up",
|
||||||
"half_page_down",
|
"half_page_down",
|
||||||
"page_bottom",
|
"page_bottom",
|
||||||
"peer_list_up",
|
|
||||||
"peer_list_down",
|
|
||||||
"toggle_peerlist",
|
"toggle_peerlist",
|
||||||
"toggle_paste_mode",
|
"toggle_paste_mode",
|
||||||
};
|
};
|
||||||
|
|
||||||
/* defines from toxic.h */
|
/* defines from toxic.h */
|
||||||
static void key_defaults(struct user_settings* settings)
|
static void key_defaults(struct user_settings *settings)
|
||||||
{
|
{
|
||||||
settings->key_next_tab = T_KEY_NEXT;
|
settings->key_next_tab = T_KEY_NEXT;
|
||||||
settings->key_prev_tab = T_KEY_PREV;
|
settings->key_prev_tab = T_KEY_PREV;
|
||||||
@ -168,68 +170,78 @@ static void key_defaults(struct user_settings* settings)
|
|||||||
settings->key_half_page_up = T_KEY_C_F;
|
settings->key_half_page_up = T_KEY_C_F;
|
||||||
settings->key_half_page_down = T_KEY_C_V;
|
settings->key_half_page_down = T_KEY_C_V;
|
||||||
settings->key_page_bottom = T_KEY_C_H;
|
settings->key_page_bottom = T_KEY_C_H;
|
||||||
settings->key_peer_list_up = T_KEY_C_LB;
|
|
||||||
settings->key_peer_list_down = T_KEY_C_RB;
|
|
||||||
settings->key_toggle_peerlist = T_KEY_C_B;
|
settings->key_toggle_peerlist = T_KEY_C_B;
|
||||||
settings->key_toggle_pastemode = T_KEY_C_T;
|
settings->key_toggle_pastemode = T_KEY_C_T;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct tox_strings {
|
static const struct tox_strings {
|
||||||
const char* self;
|
const char *self;
|
||||||
const char* download_path;
|
const char *download_path;
|
||||||
const char* chatlogs_path;
|
const char *chatlogs_path;
|
||||||
const char* avatar_path;
|
const char *avatar_path;
|
||||||
const char* password_eval;
|
const char *autorun_path;
|
||||||
|
const char *password_eval;
|
||||||
} tox_strings = {
|
} tox_strings = {
|
||||||
"tox",
|
"tox",
|
||||||
"download_path",
|
"download_path",
|
||||||
"chatlogs_path",
|
"chatlogs_path",
|
||||||
"avatar_path",
|
"avatar_path",
|
||||||
|
"autorun_path",
|
||||||
"password_eval",
|
"password_eval",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void tox_defaults(struct user_settings* settings)
|
static void tox_defaults(struct user_settings *settings)
|
||||||
{
|
{
|
||||||
strcpy(settings->download_path, "");
|
strcpy(settings->download_path, "");
|
||||||
strcpy(settings->chatlogs_path, "");
|
strcpy(settings->chatlogs_path, "");
|
||||||
strcpy(settings->avatar_path, "");
|
strcpy(settings->avatar_path, "");
|
||||||
|
strcpy(settings->autorun_path, "");
|
||||||
strcpy(settings->password_eval, "");
|
strcpy(settings->password_eval, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
static const struct audio_strings {
|
static const struct audio_strings {
|
||||||
const char* self;
|
const char *self;
|
||||||
const char* input_device;
|
const char *input_device;
|
||||||
const char* output_device;
|
const char *output_device;
|
||||||
const char* VAD_treshold;
|
const char *VAD_threshold;
|
||||||
|
const char *conference_audio_channels;
|
||||||
|
const char *chat_audio_channels;
|
||||||
|
const char *push_to_talk;
|
||||||
} audio_strings = {
|
} audio_strings = {
|
||||||
"audio",
|
"audio",
|
||||||
"input_device",
|
"input_device",
|
||||||
"output_device",
|
"output_device",
|
||||||
"VAD_treshold",
|
"VAD_threshold",
|
||||||
|
"conference_audio_channels",
|
||||||
|
"chat_audio_channels",
|
||||||
|
"push_to_talk",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void audio_defaults(struct user_settings* settings)
|
static void audio_defaults(struct user_settings *settings)
|
||||||
{
|
{
|
||||||
settings->audio_in_dev = 0;
|
settings->audio_in_dev = 0;
|
||||||
settings->audio_out_dev = 0;
|
settings->audio_out_dev = 0;
|
||||||
settings->VAD_treshold = 40.0;
|
settings->VAD_threshold = 5.0;
|
||||||
|
settings->conference_audio_channels = 1;
|
||||||
|
settings->chat_audio_channels = 2;
|
||||||
|
settings->push_to_talk = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
static const struct sound_strings {
|
static const struct sound_strings {
|
||||||
const char* self;
|
const char *self;
|
||||||
const char* notif_error;
|
const char *notif_error;
|
||||||
const char* self_log_in;
|
const char *self_log_in;
|
||||||
const char* self_log_out;
|
const char *self_log_out;
|
||||||
const char* user_log_in;
|
const char *user_log_in;
|
||||||
const char* user_log_out;
|
const char *user_log_out;
|
||||||
const char* call_incoming;
|
const char *call_incoming;
|
||||||
const char* call_outgoing;
|
const char *call_outgoing;
|
||||||
const char* generic_message;
|
const char *generic_message;
|
||||||
const char* transfer_pending;
|
const char *transfer_pending;
|
||||||
const char* transfer_completed;
|
const char *transfer_completed;
|
||||||
} sound_strings = {
|
} sound_strings = {
|
||||||
"sounds",
|
"sounds",
|
||||||
"notif_error",
|
"notif_error",
|
||||||
@ -245,24 +257,29 @@ static const struct sound_strings {
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int key_parse(const char **bind) {
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_key_binding(int *key, const char **bind) {
|
static void set_key_binding(int *key, const char **bind)
|
||||||
|
{
|
||||||
int code = key_parse(bind);
|
int code = key_parse(bind);
|
||||||
|
|
||||||
if (code != -1) {
|
if (code != -1) {
|
||||||
@ -299,8 +316,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);
|
||||||
}
|
}
|
||||||
@ -318,18 +336,19 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
config_setting_lookup_bool(setting, ui_strings.timestamps, &s->timestamps);
|
config_setting_lookup_bool(setting, ui_strings.timestamps, &s->timestamps);
|
||||||
|
|
||||||
int time = 24;
|
int time = 24;
|
||||||
if ( config_setting_lookup_int(setting, ui_strings.time_format, &time) ) {
|
|
||||||
|
if (config_setting_lookup_int(setting, ui_strings.time_format, &time)) {
|
||||||
if (time == 12) {
|
if (time == 12) {
|
||||||
snprintf(s->timestamp_format, sizeof(s->timestamp_format), "%s", "%I:%M:%S %p");
|
snprintf(s->timestamp_format, sizeof(s->timestamp_format), "%s", "%I:%M:%S %p");
|
||||||
snprintf(s->log_timestamp_format, sizeof(s->log_timestamp_format), "%s", "%Y/%m/%d [%I:%M:%S %p]");
|
snprintf(s->log_timestamp_format, sizeof(s->log_timestamp_format), "%s", "%Y/%m/%d [%I:%M:%S %p]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( config_setting_lookup_string(setting, ui_strings.timestamp_format, &str) ) {
|
if (config_setting_lookup_string(setting, ui_strings.timestamp_format, &str)) {
|
||||||
snprintf(s->timestamp_format, sizeof(s->timestamp_format), "%s", str);
|
snprintf(s->timestamp_format, sizeof(s->timestamp_format), "%s", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( config_setting_lookup_string(setting, ui_strings.log_timestamp_format, &str) ) {
|
if (config_setting_lookup_string(setting, ui_strings.log_timestamp_format, &str)) {
|
||||||
snprintf(s->log_timestamp_format, sizeof(s->log_timestamp_format), "%s", str);
|
snprintf(s->log_timestamp_format, sizeof(s->log_timestamp_format), "%s", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,12 +357,15 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
if (config_setting_lookup_bool(setting, ui_strings.bell_on_message, &s->bell_on_message)) {
|
if (config_setting_lookup_bool(setting, ui_strings.bell_on_message, &s->bell_on_message)) {
|
||||||
s->bell_on_message = s->bell_on_message ? NT_BEEP : 0;
|
s->bell_on_message = s->bell_on_message ? NT_BEEP : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config_setting_lookup_bool(setting, ui_strings.bell_on_filetrans, &s->bell_on_filetrans)) {
|
if (config_setting_lookup_bool(setting, ui_strings.bell_on_filetrans, &s->bell_on_filetrans)) {
|
||||||
s->bell_on_filetrans = s->bell_on_filetrans ? NT_BEEP : 0;
|
s->bell_on_filetrans = s->bell_on_filetrans ? NT_BEEP : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config_setting_lookup_bool(setting, ui_strings.bell_on_filetrans_accept, &s->bell_on_filetrans_accept)) {
|
if (config_setting_lookup_bool(setting, ui_strings.bell_on_filetrans_accept, &s->bell_on_filetrans_accept)) {
|
||||||
s->bell_on_filetrans_accept = s->bell_on_filetrans_accept ? NT_BEEP : 0;
|
s->bell_on_filetrans_accept = s->bell_on_filetrans_accept ? NT_BEEP : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config_setting_lookup_bool(setting, ui_strings.bell_on_invite, &s->bell_on_invite)) {
|
if (config_setting_lookup_bool(setting, ui_strings.bell_on_invite, &s->bell_on_invite)) {
|
||||||
s->bell_on_invite = s->bell_on_invite ? NT_BEEP : 0;
|
s->bell_on_invite = s->bell_on_invite ? NT_BEEP : 0;
|
||||||
}
|
}
|
||||||
@ -356,96 +378,135 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
config_setting_lookup_bool(setting, ui_strings.show_connection_msg, &s->show_connection_msg);
|
config_setting_lookup_bool(setting, ui_strings.show_connection_msg, &s->show_connection_msg);
|
||||||
|
|
||||||
config_setting_lookup_int(setting, ui_strings.history_size, &s->history_size);
|
config_setting_lookup_int(setting, ui_strings.history_size, &s->history_size);
|
||||||
|
config_setting_lookup_int(setting, ui_strings.notification_timeout, &s->notification_timeout);
|
||||||
config_setting_lookup_int(setting, ui_strings.nodeslist_update_freq, &s->nodeslist_update_freq);
|
config_setting_lookup_int(setting, ui_strings.nodeslist_update_freq, &s->nodeslist_update_freq);
|
||||||
|
config_setting_lookup_int(setting, ui_strings.autosave_freq, &s->autosave_freq);
|
||||||
|
|
||||||
if ( config_setting_lookup_string(setting, ui_strings.line_join, &str) ) {
|
if (config_setting_lookup_string(setting, ui_strings.line_join, &str)) {
|
||||||
snprintf(s->line_join, sizeof(s->line_join), "%s", str);
|
snprintf(s->line_join, sizeof(s->line_join), "%s", str);
|
||||||
}
|
}
|
||||||
if ( config_setting_lookup_string(setting, ui_strings.line_quit, &str) ) {
|
|
||||||
|
if (config_setting_lookup_string(setting, ui_strings.line_quit, &str)) {
|
||||||
snprintf(s->line_quit, sizeof(s->line_quit), "%s", str);
|
snprintf(s->line_quit, sizeof(s->line_quit), "%s", str);
|
||||||
}
|
}
|
||||||
if ( config_setting_lookup_string(setting, ui_strings.line_alert, &str) ) {
|
|
||||||
|
if (config_setting_lookup_string(setting, ui_strings.line_alert, &str)) {
|
||||||
snprintf(s->line_alert, sizeof(s->line_alert), "%s", str);
|
snprintf(s->line_alert, sizeof(s->line_alert), "%s", str);
|
||||||
}
|
}
|
||||||
if ( config_setting_lookup_string(setting, ui_strings.line_normal, &str) ) {
|
|
||||||
|
if (config_setting_lookup_string(setting, ui_strings.line_normal, &str)) {
|
||||||
snprintf(s->line_normal, sizeof(s->line_normal), "%s", str);
|
snprintf(s->line_normal, sizeof(s->line_normal), "%s", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
config_setting_lookup_bool (setting, ui_strings.mplex_away, &s->mplex_away);
|
config_setting_lookup_bool(setting, ui_strings.mplex_away, &s->mplex_away);
|
||||||
|
|
||||||
if (config_setting_lookup_string (setting, ui_strings.mplex_away_note, &str)) {
|
if (config_setting_lookup_string(setting, ui_strings.mplex_away_note, &str)) {
|
||||||
snprintf (s->mplex_away_note, sizeof (s->mplex_away_note), "%s", str);
|
snprintf(s->mplex_away_note, sizeof(s->mplex_away_note), "%s", str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* paths */
|
/* paths */
|
||||||
if ((setting = config_lookup(cfg, tox_strings.self)) != NULL) {
|
if ((setting = config_lookup(cfg, tox_strings.self)) != NULL) {
|
||||||
if ( config_setting_lookup_string(setting, tox_strings.download_path, &str) ) {
|
if (config_setting_lookup_string(setting, tox_strings.download_path, &str)) {
|
||||||
snprintf(s->download_path, sizeof(s->download_path), "%s", str);
|
snprintf(s->download_path, sizeof(s->download_path), "%s", str);
|
||||||
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';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( config_setting_lookup_string(setting, tox_strings.password_eval, &str) ) {
|
#ifdef PYTHON
|
||||||
|
|
||||||
|
if (config_setting_lookup_string(setting, tox_strings.autorun_path, &str)) {
|
||||||
|
snprintf(s->autorun_path, sizeof(s->autorun_path), "%s", str);
|
||||||
|
int len = strlen(str);
|
||||||
|
|
||||||
|
if (len >= sizeof(s->autorun_path) - 2) {
|
||||||
|
s->autorun_path[0] = '\0';
|
||||||
|
} else if (s->autorun_path[len - 1] != '/') {
|
||||||
|
strcat(&s->autorun_path[len - 1], "/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (config_setting_lookup_string(setting, tox_strings.password_eval, &str)) {
|
||||||
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))
|
}
|
||||||
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.toggle_peerlist, &tmp)) {
|
||||||
set_key_binding(&s->key_peer_list_down, &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
|
||||||
|
|
||||||
if ((setting = config_lookup(cfg, audio_strings.self)) != NULL) {
|
if ((setting = config_lookup(cfg, audio_strings.self)) != NULL) {
|
||||||
config_setting_lookup_int(setting, audio_strings.input_device, &s->audio_in_dev);
|
config_setting_lookup_int(setting, audio_strings.input_device, &s->audio_in_dev);
|
||||||
s->audio_in_dev = s->audio_in_dev < 0 || s->audio_in_dev > MAX_DEVICES ? 0 : s->audio_in_dev;
|
s->audio_in_dev = s->audio_in_dev < 0 || s->audio_in_dev > MAX_DEVICES ? 0 : s->audio_in_dev;
|
||||||
@ -453,61 +514,79 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
config_setting_lookup_int(setting, audio_strings.output_device, &s->audio_out_dev);
|
config_setting_lookup_int(setting, audio_strings.output_device, &s->audio_out_dev);
|
||||||
s->audio_out_dev = s->audio_out_dev < 0 || s->audio_out_dev > MAX_DEVICES ? 0 : s->audio_out_dev;
|
s->audio_out_dev = s->audio_out_dev < 0 || s->audio_out_dev > MAX_DEVICES ? 0 : s->audio_out_dev;
|
||||||
|
|
||||||
config_setting_lookup_float(setting, audio_strings.VAD_treshold, &s->VAD_treshold);
|
config_setting_lookup_float(setting, audio_strings.VAD_threshold, &s->VAD_threshold);
|
||||||
|
|
||||||
|
config_setting_lookup_int(setting, audio_strings.conference_audio_channels, &s->conference_audio_channels);
|
||||||
|
s->conference_audio_channels = s->conference_audio_channels <= 0
|
||||||
|
|| s->conference_audio_channels > 2 ? 1 : s->conference_audio_channels;
|
||||||
|
|
||||||
|
config_setting_lookup_int(setting, audio_strings.chat_audio_channels, &s->chat_audio_channels);
|
||||||
|
s->chat_audio_channels = s->chat_audio_channels <= 0 || s->chat_audio_channels > 2 ? 2 : s->chat_audio_channels;
|
||||||
|
|
||||||
|
config_setting_lookup_bool(setting, audio_strings.push_to_talk, &s->push_to_talk);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
|
|
||||||
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");
|
||||||
set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ToxicContactOffline.wav");
|
set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ToxicContactOffline.wav");
|
||||||
@ -517,6 +596,7 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
set_sound(transfer_pending, PACKAGE_DATADIR "/sounds/ToxicTransferStart.wav");
|
set_sound(transfer_pending, PACKAGE_DATADIR "/sounds/ToxicTransferStart.wav");
|
||||||
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/ToxicTransferComplete.wav");
|
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/ToxicTransferComplete.wav");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
config_destroy(cfg);
|
config_destroy(cfg);
|
||||||
|
@ -49,11 +49,13 @@ struct user_settings {
|
|||||||
|
|
||||||
int colour_theme; /* boolean (0 for default toxic colours) */
|
int colour_theme; /* boolean (0 for default toxic colours) */
|
||||||
int history_size; /* int between MIN_HISTORY and MAX_HISTORY */
|
int history_size; /* int between MIN_HISTORY and MAX_HISTORY */
|
||||||
|
int notification_timeout;
|
||||||
int show_typing_self; /* boolean */
|
int show_typing_self; /* boolean */
|
||||||
int show_typing_other; /* boolean */
|
int show_typing_other; /* boolean */
|
||||||
int show_welcome_msg; /* boolean */
|
int show_welcome_msg; /* boolean */
|
||||||
int show_connection_msg; /* boolean */
|
int show_connection_msg; /* boolean */
|
||||||
int nodeslist_update_freq; /* int (<= 0 to disable updates) */
|
int nodeslist_update_freq; /* int (<= 0 to disable updates) */
|
||||||
|
int autosave_freq; /* int (<= 0 to disable autosave) */
|
||||||
|
|
||||||
char line_join[LINE_HINT_MAX + 1];
|
char line_join[LINE_HINT_MAX + 1];
|
||||||
char line_quit[LINE_HINT_MAX + 1];
|
char line_quit[LINE_HINT_MAX + 1];
|
||||||
@ -63,6 +65,7 @@ struct user_settings {
|
|||||||
char download_path[PATH_MAX];
|
char download_path[PATH_MAX];
|
||||||
char chatlogs_path[PATH_MAX];
|
char chatlogs_path[PATH_MAX];
|
||||||
char avatar_path[PATH_MAX];
|
char avatar_path[PATH_MAX];
|
||||||
|
char autorun_path[PATH_MAX];
|
||||||
char password_eval[PASSWORD_EVAL_MAX];
|
char password_eval[PASSWORD_EVAL_MAX];
|
||||||
|
|
||||||
int key_next_tab;
|
int key_next_tab;
|
||||||
@ -72,8 +75,6 @@ struct user_settings {
|
|||||||
int key_half_page_up;
|
int key_half_page_up;
|
||||||
int key_half_page_down;
|
int key_half_page_down;
|
||||||
int key_page_bottom;
|
int key_page_bottom;
|
||||||
int key_peer_list_up;
|
|
||||||
int key_peer_list_down;
|
|
||||||
int key_toggle_peerlist;
|
int key_toggle_peerlist;
|
||||||
int key_toggle_pastemode;
|
int key_toggle_pastemode;
|
||||||
|
|
||||||
@ -83,11 +84,14 @@ struct user_settings {
|
|||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
int audio_in_dev;
|
int audio_in_dev;
|
||||||
int audio_out_dev;
|
int audio_out_dev;
|
||||||
double VAD_treshold;
|
double VAD_threshold;
|
||||||
|
int conference_audio_channels;
|
||||||
|
int chat_audio_channels;
|
||||||
|
int push_to_talk; /* boolean */
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum settings_values {
|
||||||
AUTOLOG_OFF = 0,
|
AUTOLOG_OFF = 0,
|
||||||
AUTOLOG_ON = 1,
|
AUTOLOG_ON = 1,
|
||||||
|
|
||||||
@ -113,15 +117,16 @@ 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 "<--"
|
||||||
#define LINE_ALERT "-!-"
|
#define LINE_ALERT "-!-"
|
||||||
#define LINE_NORMAL "---"
|
#define LINE_NORMAL "-"
|
||||||
#define TIMESTAMP_DEFAULT "%H:%M:%S"
|
#define TIMESTAMP_DEFAULT "%H:%M"
|
||||||
#define LOG_TIMESTAMP_DEFAULT "%Y/%m/%d [%H:%M:%S]"
|
#define LOG_TIMESTAMP_DEFAULT "%Y/%m/%d [%H:%M:%S]"
|
||||||
#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 */
|
||||||
|
347
src/term_mplex.c
347
src/term_mplex.c
@ -26,18 +26,18 @@
|
|||||||
#include <string.h> /* strlen, strcpy, strstr, strchr, strrchr, strcat, strncmp */
|
#include <string.h> /* strlen, strcpy, strstr, strchr, strrchr, strcat, strncmp */
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <tox/tox.h>
|
#include <tox/tox.h>
|
||||||
|
|
||||||
#include "global_commands.h"
|
#include "execute.h"
|
||||||
#include "windows.h"
|
#include "settings.h"
|
||||||
#include "term_mplex.h"
|
#include "term_mplex.h"
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "settings.h"
|
#include "windows.h"
|
||||||
|
|
||||||
extern struct ToxWindow *prompt;
|
extern struct ToxWindow *prompt;
|
||||||
extern struct user_settings *user_settings;
|
extern struct user_settings *user_settings;
|
||||||
@ -52,8 +52,7 @@ extern struct Winthread Winthread;
|
|||||||
#define PATH_SEP_S "/"
|
#define PATH_SEP_S "/"
|
||||||
#define PATH_SEP_C '/'
|
#define PATH_SEP_C '/'
|
||||||
|
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
|
||||||
MPLEX_NONE,
|
MPLEX_NONE,
|
||||||
MPLEX_SCREEN,
|
MPLEX_SCREEN,
|
||||||
MPLEX_TMUX,
|
MPLEX_TMUX,
|
||||||
@ -70,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:
|
||||||
@ -81,128 +80,172 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *read_into_dyn_buffer (FILE *stream)
|
static char *read_into_dyn_buffer(FILE *stream)
|
||||||
{
|
{
|
||||||
const char *input_ptr = NULL;
|
const char *input_ptr = NULL;
|
||||||
char *dyn_buffer = NULL;
|
char *dyn_buffer = NULL;
|
||||||
int dyn_buffer_size = 1; /* account for the \0 */
|
int dyn_buffer_size = 1; /* account for the \0 */
|
||||||
|
|
||||||
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);
|
char *tmp = realloc(dyn_buffer, length);
|
||||||
else
|
|
||||||
dyn_buffer = (char*) malloc (length);
|
if (tmp == NULL) {
|
||||||
strcpy (dyn_buffer + dyn_buffer_size - 1, input_ptr);
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dyn_buffer = tmp;
|
||||||
|
} else {
|
||||||
|
dyn_buffer = malloc(length);
|
||||||
|
|
||||||
|
if (dyn_buffer == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(dyn_buffer + dyn_buffer_size - 1, input_ptr);
|
||||||
dyn_buffer_size = length;
|
dyn_buffer_size = length;
|
||||||
}
|
}
|
||||||
|
|
||||||
return dyn_buffer;
|
return dyn_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *extract_socket_path (const char *info)
|
static char *extract_socket_path(const char *info)
|
||||||
{
|
{
|
||||||
const char *search_str = " Socket";
|
const char *search_str = " Socket";
|
||||||
const char *pos = strstr (info, search_str);
|
const char *pos = strstr(info, search_str);
|
||||||
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)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
end = strchr (pos, '\n');
|
if (!pos) {
|
||||||
if (!end)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
end = strchr(pos, '\n');
|
||||||
|
|
||||||
|
if (!end) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
*end = '\0';
|
*end = '\0';
|
||||||
end = strrchr (pos, '.');
|
end = strrchr(pos, '.');
|
||||||
if (!end)
|
|
||||||
return NULL;
|
if (!end) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
path = malloc(end - pos + 1);
|
||||||
|
|
||||||
|
if (path == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
char *dyn_buffer = NULL;
|
char *dyn_buffer = NULL;
|
||||||
|
|
||||||
socket_name = getenv ("STY");
|
socket_name = getenv("STY");
|
||||||
if (!socket_name)
|
|
||||||
goto nomplex;
|
|
||||||
|
|
||||||
session_info_stream = popen ("env LC_ALL=C screen -ls", "r");
|
if (!socket_name) {
|
||||||
if (!session_info_stream)
|
|
||||||
goto nomplex;
|
goto nomplex;
|
||||||
|
}
|
||||||
|
|
||||||
dyn_buffer = read_into_dyn_buffer (session_info_stream);
|
session_info_stream = popen("env LC_ALL=C screen -ls", "r");
|
||||||
if (!dyn_buffer)
|
|
||||||
|
if (!session_info_stream) {
|
||||||
goto nomplex;
|
goto nomplex;
|
||||||
|
}
|
||||||
|
|
||||||
pclose (session_info_stream);
|
dyn_buffer = read_into_dyn_buffer(session_info_stream);
|
||||||
|
|
||||||
|
if (!dyn_buffer) {
|
||||||
|
goto nomplex;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
|
||||||
goto nomplex;
|
|
||||||
|
|
||||||
free (dyn_buffer);
|
if (!socket_path) {
|
||||||
|
goto nomplex;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
strcat (mplex_data, socket_name);
|
strcat(mplex_data, socket_name);
|
||||||
free (socket_path);
|
free(socket_path);
|
||||||
socket_path = NULL;
|
socket_path = NULL;
|
||||||
|
|
||||||
mplex = MPLEX_SCREEN;
|
mplex = MPLEX_SCREEN;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
nomplex:
|
nomplex:
|
||||||
if (session_info_stream)
|
|
||||||
pclose (session_info_stream);
|
if (session_info_stream) {
|
||||||
if (dyn_buffer)
|
pclose(session_info_stream);
|
||||||
free (dyn_buffer);
|
}
|
||||||
if (socket_path)
|
|
||||||
|
if (dyn_buffer) {
|
||||||
|
free(dyn_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* store the session number string for later use */
|
if (!pos) {
|
||||||
snprintf (mplex_data, sizeof(mplex_data), "%s", pos + 1);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* store the session id for later use */
|
||||||
|
snprintf(mplex_data, sizeof(mplex_data), "$%s", pos + 1);
|
||||||
mplex = MPLEX_TMUX;
|
mplex = MPLEX_TMUX;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -215,92 +258,108 @@ 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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. An attached entry ends with "(attached)". Example:
|
current session's entry.
|
||||||
|
*/
|
||||||
$ tmux list-sessions
|
static int tmux_is_detached(void)
|
||||||
0: 1 windows (created Mon Mar 2 21:48:29 2015) [80x23] (attached)
|
|
||||||
1: 2 windows (created Mon Mar 2 21:48:43 2015) [80x23]
|
|
||||||
|
|
||||||
In this example, session 0 is attached and session 1 is detached.
|
|
||||||
*/
|
|
||||||
static int tmux_is_detached ()
|
|
||||||
{
|
{
|
||||||
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;
|
||||||
char *entry_pos, *nl_pos, *attached_pos;
|
char *entry_pos;
|
||||||
const int numstr_len = strlen (mplex_data);
|
int detached;
|
||||||
|
const int numstr_len = strlen(mplex_data);
|
||||||
|
|
||||||
session_info_stream = popen ("env LC_ALL=C tmux list-sessions", "r");
|
/* get the number of attached clients for each session */
|
||||||
if (!session_info_stream)
|
session_info_stream = popen("tmux list-sessions -F \"#{session_id} #{session_attached}\"", "r");
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
/* prepare search string, for finding the current session's entry */
|
/* prepare search string, for finding the current session's entry */
|
||||||
search_str = (char*) malloc (numstr_len + 4);
|
search_str = malloc(numstr_len + 2);
|
||||||
|
|
||||||
|
if (search_str == NULL) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
search_str[0] = '\n';
|
search_str[0] = '\n';
|
||||||
strcpy (search_str + 1, mplex_data);
|
strcpy(search_str + 1, mplex_data);
|
||||||
strcat (search_str, ": ");
|
|
||||||
|
|
||||||
/* do the search */
|
/* do the search */
|
||||||
if (strncmp (dyn_buffer, search_str + 1, numstr_len + 2) == 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;
|
||||||
|
}
|
||||||
|
|
||||||
/* find the next \n and look for the "(attached)" before it */
|
entry_pos = strchr(entry_pos, ' ') + 1;
|
||||||
nl_pos = strchr (entry_pos + 1, '\n');
|
detached = strncmp(entry_pos, "0\n", 2) == 0;
|
||||||
attached_pos = strstr (entry_pos + 1, "(attached)\n");
|
|
||||||
|
|
||||||
free (search_str);
|
free(search_str);
|
||||||
search_str = NULL;
|
search_str = NULL;
|
||||||
|
|
||||||
free (dyn_buffer);
|
free(dyn_buffer);
|
||||||
dyn_buffer = NULL;
|
dyn_buffer = NULL;
|
||||||
|
|
||||||
return attached_pos == NULL || attached_pos > nl_pos;
|
return detached;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
if (session_info_stream)
|
|
||||||
pclose (session_info_stream);
|
if (session_info_stream) {
|
||||||
if (dyn_buffer)
|
pclose(session_info_stream);
|
||||||
free (dyn_buffer);
|
}
|
||||||
if (search_str)
|
|
||||||
free (search_str);
|
if (dyn_buffer) {
|
||||||
|
free(dyn_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (search_str) {
|
||||||
|
free(search_str);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,57 +372,55 @@ 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();
|
||||||
|
|
||||||
pthread_mutex_lock (&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
current_status = tox_self_get_status (m);
|
current_status = tox_self_get_status(m);
|
||||||
pthread_mutex_unlock (&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
if (auto_away_active && current_status == TOX_USER_STATUS_AWAY && !detached)
|
if (auto_away_active && current_status == TOX_USER_STATUS_AWAY && !detached) {
|
||||||
{
|
|
||||||
auto_away_active = false;
|
auto_away_active = false;
|
||||||
new_status = prev_status;
|
new_status = prev_status;
|
||||||
new_note = prev_note;
|
new_note = prev_note;
|
||||||
}
|
} else if (current_status == TOX_USER_STATUS_NONE && detached) {
|
||||||
else
|
|
||||||
if (current_status == TOX_USER_STATUS_NONE && detached)
|
|
||||||
{
|
|
||||||
auto_away_active = true;
|
auto_away_active = true;
|
||||||
prev_status = current_status;
|
prev_status = current_status;
|
||||||
new_status = TOX_USER_STATUS_AWAY;
|
new_status = TOX_USER_STATUS_AWAY;
|
||||||
pthread_mutex_lock (&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
size_t slen = tox_self_get_status_message_size(m);
|
size_t slen = tox_self_get_status_message_size(m);
|
||||||
tox_self_get_status_message (m, (uint8_t*) prev_note);
|
tox_self_get_status_message(m, (uint8_t *) prev_note);
|
||||||
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 argv[3][MAX_STR_SIZE];
|
char status_str[MAX_STR_SIZE];
|
||||||
strcpy (argv[0], "/status");
|
char note_str[MAX_STR_SIZE];
|
||||||
strcpy (argv[1], (new_status == TOX_USER_STATUS_AWAY ? "away" :
|
const char *status = new_status == TOX_USER_STATUS_AWAY ? "away" :
|
||||||
new_status == TOX_USER_STATUS_BUSY ? "busy" : "online"));
|
new_status == TOX_USER_STATUS_BUSY ? "busy" : "online";
|
||||||
argv[2][0] = '\"';
|
snprintf(status_str, sizeof(status_str), "/status %s", status);
|
||||||
strcpy (argv[2] + 1, new_note);
|
snprintf(note_str, sizeof(status_str), "/note %s", 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);
|
||||||
pthread_mutex_unlock (&Winthread.lock);
|
execute(prompt->chatwin->history, prompt, m, note_str, GLOBAL_COMMAND_MODE);
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Time in seconds between calls to mplex_timer_handler */
|
/* Time in seconds between calls to mplex_timer_handler */
|
||||||
@ -379,20 +436,24 @@ 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;
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user