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

Compare commits

...

89 Commits

Author SHA1 Message Date
22d60232fb Bump to version 0.8.4 2020-10-22 22:14:33 -04:00
e428879beb Fix clashing key bindings
Scrolling the groupchat peer list now uses ctrl+up and down
2020-10-13 19:52:43 -04:00
3015138a5a Manually attempt to decode input char sequences
This is currently a fallback method for when the terminal doesn't
detect ctrl arrow sequences, but it is generalized for future additions
2020-10-13 16:12:55 -04:00
9c06ad608b Add ability to skip words in input field with ctrl-left/right arrow 2020-10-10 11:21:15 -04:00
015dbd9a96 fix: Fix non-working bell notifications
The problem with the bell notifications only happens when Toxic is
compiled with X11 support, but does not run under X. This commit changes
toxic's behavior such that it behaves identically when not running under an
X session, no matter if it has been compiled with X11 support or not.
2020-08-24 16:36:52 +02:00
a7466c3142 Add option to disable LAN 2020-08-10 21:56:45 -04:00
f012007cc4 A couple small fixes 2020-05-19 21:44:35 -04:00
dcf3baf60f Make sure logger file is closed after tox_kill 2020-05-18 13:58:55 -04:00
4bda799a4b Add the ability to log to file (#84) 2020-05-16 23:12:54 -04:00
bdeae33d48 Add macOS build.
Lots of features disabled, because I can't get it to work yet. We'll
enable features one by one as we get them to work.
2020-05-05 00:47:08 +01:00
47591d5298 chore: Use global release-drafter config. 2020-05-05 00:25:10 +01:00
b5ace27a3e chore: Remove astyle from travis build.
The astyle check is now done by restyled.
2020-05-04 23:50:31 +01:00
b334622d36 Add release-drafter config. 2020-05-04 22:01:33 +01:00
4bfb344caa Add option for toxcore logging in stderr 2020-05-04 16:15:28 -04:00
16d96d6faf Add restyled config for toxic. 2020-05-04 20:54:58 +01:00
0ab2bad226 Add CODEOWNERS and settings.yml files. 2020-04-25 03:40:02 +00:00
68db926f9f Check that files are formatted correctly.
Fail the CI build if they are not.
2020-04-23 01:16:57 +00:00
b270c1e8b7 Remove extra semicolon in lock/unlock macros.
lock/unlock are always expanded in a context followed by a semicolon.
2020-04-23 01:12:34 +00:00
e7142e49fd Terminate notify before windows
This fixes a use after free bug
2020-04-22 20:54:53 -04:00
610906d07f fix segfault on starting video 2020-04-17 00:00:00 +00:00
6f72a191ba Revert "Add feature flags and missing #includes."
This reverts commit dd5fa236ae.

Also, set `-std=gnu99` in Bazel build.
2020-04-17 19:37:22 +00:00
dd5fa236ae Add feature flags and missing #includes.
These are needed to compile on some strict Linuxes.
2020-04-15 21:34:30 +00:00
51e1ab94b3 Add QR disabling options to INSTALL.md 2020-04-04 23:20:52 -03:00
ddc8c53abf Fix unused variable warnings and change all (void)s to UNUSED macro 2020-03-30 16:02:27 -04:00
46513017e3 Half-hearted attempt at making toxic work on osx.
Video has no chance without X11 for now.
2020-03-30 18:14:43 +00:00
98cb7f58c0 Fix unused parameter and unused result warnings 2020-03-15 14:57:00 -04:00
206bf407fd Use rules_cc instead of native cc_binary rules. 2020-03-12 12:23:57 +00:00
0a8ac4de3b Fix yamllint warning about missing document start marker.
YAML apparently likes to have this marker, so let's have it.
2020-03-10 14:57:12 +00:00
87d54acad0 Add sponsorship button 2020-03-07 13:19:10 -05:00
45ff6d8bac Migrate to Camel_Case enum types.
UPPER_CASE enum types are deprecated and will be removed in 0.3.0.
2020-03-07 18:11:41 +00:00
437dd8baeb Some misc fixes 2020-02-29 14:14:56 -05:00
b080236ee5 Fix typo 2020-02-10 17:16:56 -05:00
116bff8cef format fixes 2019-12-07 23:17:02 -05:00
ddeca171a0 Add input line text to history on UP and DOWN 2019-12-07 18:29:33 -03:00
127f9462e0 make friend add fail if friend is in the block list 2019-11-16 01:55:47 -05:00
4b5a9abbd4 Fix A/V bug preventing the caller from being properly informed of call termination 2019-07-12 11:51:08 -04:00
bb2257973e Load conference titles on startup for saved conferences (#43) 2019-06-30 14:51:13 -04:00
12b9cd2386 Fix header issues 2019-03-27 01:38:15 -04:00
2cbe8fa880 Use correct integer types to fix groupchat peer scrolling bug 2019-03-26 23:05:24 -04:00
2e39bee05a Check for openal lib before attempting to build with video support 2019-03-15 16:05:54 -04:00
05eda76643 Partially fix autocomplete behaviour for input with spaces 2019-02-17 17:25:34 -05:00
f7b73af9a7 Add config option for the notification timeout duration 2018-11-10 08:54:59 -05:00
73aaa44d12 Add config option to set data file auto-save frequency 2018-10-30 18:22:30 -04:00
e4abd8b36b Bump version to 0.8.3 2018-10-30 18:03:44 -04:00
9e3d4f3889 Check if pointer is null before accessing 2018-10-28 07:09:37 -04:00
b7d67c1d86 re-init AV for unblocked contacts 2018-10-20 02:56:37 -04:00
c4a11f8dc7 Refactor ToxWindows
ToxWindow constructor functions now return pointers instead of structs
ToxWindow windows array now holds pointers instead of structs
Refactor some logic in windows.c pertaining to keeping track of active windows
Use uint8_t for window array indexing
2018-10-19 17:43:06 -04:00
d18cc8cbc2 Fix two memory leaks and properly clean up friendlist window 2018-10-19 17:43:03 -04:00
ce6d4861fb Fix bug where autocomplete added a forward slash to files with no extension
Also slightly refactored the line complete functions
2018-10-17 18:00:09 -04:00
8f0e6026f0 Add enum for file_type() and a little cleanup 2018-10-17 18:00:08 -04:00
258736995d Remove ability to set note with status command 2018-10-17 18:00:08 -04:00
56e03a3f8b No longer require quotes to enclose paths 2018-10-17 18:00:08 -04:00
b6c746b5f5 No longer require quotes for commands that take strings as arguments 2018-10-17 18:00:07 -04:00
03673cbced Improve readability of INSTALL.md 2018-10-11 14:22:37 -04:00
0fea930c24 Convert deprecated uppercase enums to camelcase 2018-10-10 13:34:17 -04:00
94d22a8853 Allow empty status messages 2018-10-09 18:21:05 -04:00
63cc23401a Improve readability of defines 2018-10-08 13:39:04 -04:00
f90a774470 Make Toxic easier to port 2018-10-03 22:00:43 +00:00
e7c5fbc873 Cleanup xtra.c
Privatise some functions that don't need to be public
Fix struct names starting with _ char
Remove unnecessary memset of Xtra struct in init_xtra()
2018-09-27 03:41:58 -04:00
d62902ffb3 Use (void) in prototypes instead of ().
Also, removed `__inline` from an extern function (why was it there?).
Also, moved one extern declaration to a header file. There are lots of
these that need to be moved, but one thing at a time.
2018-09-13 23:47:47 +00:00
bebff3be0e Use (void) for empty parameter list in C. 2018-09-08 17:23:07 +00:00
2be4847b53 Ignore warning about unused result.
These should be fixed, but for now we leave it as warning, not error.
2018-09-06 13:46:24 +00:00
4557614443 Enable .travis.yml check and use non-markdown license. 2018-08-17 23:49:01 +00:00
5b30ecf2e4 Use @x11 instead of the longer @x11//:X11 to link against xlib. 2018-08-14 09:55:54 +00:00
2413ad2b59 Use bazel import libs instead of global -l flags.
Import libs currently also point to the global system installed versions,
but at least we have the freedom to import them properly later.
2018-08-05 19:17:57 +00:00
52855b805a Add astyle check to travis. 2018-07-18 17:19:43 +00:00
20b5e46850 Rename callback implementations to be of the form on_$event.
So it's easy to map from implementation to the event without looking at
the `tox_callback_*` calls.
2018-07-18 17:06:28 +00:00
f2b796940e Add missing braces to if/for/while blocks.
Astyle doesn't quite catch all of them.
2018-07-18 15:56:21 +00:00
a37bf300f9 Update astylerc to match toxcore & reformat all source files 2018-07-18 11:33:16 -04:00
cb524dcbc3 Merge branch 'iphydf-local-libconfig' 2018-07-16 10:18:44 -04:00
4144b868ce Use libconfig built in the WORKSPACE rather than system installed.
Improves hermeticity and reproducibility.
2018-07-15 15:34:19 +00:00
af11f16bef fix merge mistake take 2 2018-07-07 10:29:12 -04:00
1d27a496ef fix merge mistake 2018-07-06 15:43:32 -04:00
32bd9dc1a7 Merge branch 'TokTok-master' 2018-07-06 12:35:46 -04:00
3cd2bc7e3c Don't compile A/V code if AUDIO/VIDEO are not #defined. 2018-07-06 15:46:12 +00:00
43ca840658 Conditionally compile api.c and python_api.c contents.
Based on `-DPYTHON`, instead of based on which files are listed in the
source list. This simplifies people's lives when compiling from the
command line with `cc *.c`.
2018-07-06 14:42:33 +00:00
685837357b Add bazel build file for toxic. 2018-07-06 14:41:16 +00:00
812a13b0fb Merge branch 'fx-carton-master' 2018-06-17 20:27:57 -04:00
641fa471d2 Merge branch 'master' of https://github.com/fx-carton/toxic into fx-carton-master 2018-06-17 20:23:12 -04:00
8d5755f2d8 Merge branch 'nieldk-master' 2018-06-17 20:21:05 -04:00
af510b6666 Merge branch 'master' of https://github.com/nieldk/toxic into nieldk-master 2018-06-17 20:09:14 -04:00
46f646afcf Add an option to disable qr codes 2018-06-16 05:07:16 +02:00
68ce17a57f Temp fix for nick change spam on group join 2018-04-19 22:23:49 -04:00
a69fad15c1 Use default timestamp format if provided one is invalid 2018-04-10 17:47:21 -04:00
7621fe9a62 fix macOS build (#494) 2018-03-31 21:10:17 -04:00
f6d9bc3a74 Update check_features.mk
Changed cfg/checks/check_features.mk to enable individual Audio/Video checks by adding proper DISABLE_VI option which takes "0" or "1" for disable/enable video checks/building.
2018-03-19 22:31:31 +01:00
29aea0b42c Remove libtoxav from install instructions as it's now part of the toxcore lib 2018-03-03 23:55:54 -05:00
815c29ee31 Significantly reduce time before trying to re-send a message with no read receipt
(also some formatting cleanup)
2018-03-03 23:54:12 -05:00
3917f664bf Bump to v0.8.2 2018-03-01 19:14:14 -05:00
101 changed files with 3961 additions and 2313 deletions

1
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1 @@
/.github/ @TokTok/admins

2
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,2 @@
---
github: [JFreegman]

17
.github/settings.yml vendored Normal file
View 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

4
.restyled.yaml Normal file
View File

@ -0,0 +1,4 @@
---
restylers:
- astyle:
arguments: ["--options=astylerc"]

View File

@ -1,31 +1,60 @@
---
language: python
python: nightly
dist: xenial
os: linux
addons:
apt:
packages:
- libalut-dev
- libconfig-dev
- libnotify-dev
- libopenal-dev
- libopus-dev
- libqrencode-dev
- libvpx-dev
jobs:
include:
- env: JOB=linux
cache:
directories:
- $HOME/cache
addons:
apt:
packages:
- libalut-dev
- libconfig-dev
- libnotify-dev
- libopenal-dev
- libopus-dev
- libqrencode-dev
- libvpx-dev
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
- 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
- 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))
cache:
directories:
- $HOME/cache
script:
- make ENABLE_PYTHON=1
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.20.1/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
View 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": [],
}),
)

View File

@ -5,7 +5,7 @@
* [Documentation](#documentation)
* [Notes](#notes)
* [Compilation variables](#compilation-variables)
* [Packaging](#packaging)
* [Environment variables](#environment-variables)
## Dependencies
| Name | Needed by | Debian package |
@ -15,8 +15,7 @@
| [LibConfig](http://www.hyperrealm.com/libconfig) | BASE | libconfig-dev |
| [GNUmake](https://www.gnu.org/software/make) | BASE | make |
| [libcurl](http://curl.haxx.se/) | BASE | libcurl4-openssl-dev|
| [libqrencode](https://fukuchi.org/works/qrencode/) | BASE | libqrencode-dev |
| [Tox Core AV](https://github.com/toktok/c-toxcore) | AUDIO | *None* |
| [libqrencode](https://fukuchi.org/works/qrencode/) | QRCODE | libqrencode-dev |
| [OpenAL](http://openal.org) | AUDIO, SOUND NOTIFICATIONS | libopenal-dev |
| [OpenALUT](http://openal.org) | SOUND NOTIFICATIONS | libalut-dev |
| [LibNotify](https://developer.gnome.org/libnotify) | DESKTOP NOTIFICATIONS | libnotify-dev |
@ -28,39 +27,42 @@
#### OS X Notes
Using [Homebrew](http://brew.sh):
```
brew install openal-soft freealut libconfig
brew install curl qrencode openal-soft freealut libconfig libpng
brew install --HEAD https://raw.githubusercontent.com/Tox/homebrew-tox/master/Formula/libtoxcore.rb
brew install 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.
## Compiling
```
make PREFIX="/where/to/install"
sudo make install PREFIX="/where/to/install"
make
sudo make install
```
#### Documentation
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 EVERYONE**: [asciidoc](http://asciidoc.org/index.html) (and this step) is only required for regenerating manpages when you modify them.
**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.
## Notes
#### Compilation variables
* You can add specific flags to the Makefile with `USER_CFLAGS=""` and/or `USER_LDFLAGS=""`
* You can pass your own flags to the Makefile with `CFLAGS=""` and/or `LDFLAGS=""` (this will supersede the default ones)
* Additional features are automatically enabled if all dependencies are found, but you can disable them by using special variables:
* `DISABLE_X11=1`build toxic without X11 support (needed for focus tracking)
* `DISABLE_AV=1` → build toxic without audio call support
* `DISABLE_SOUND_NOTIFY=1` → build toxic without sound notifications support
* `DISABLE_DESKTOP_NOTIFY=1` → build toxic without desktop notifications support
* Features excluded from the default build must be explicitly enabled using special variables:
* `ENABLE_PYTHON=1`build toxic with Python scripting support
* You can add specific flags to the Makefile with `USER_CFLAGS=""` and `USER_LDFLAGS=""` passed as arguments to make, or as environment variables
* Default compile options can be overridden by using special variables:
* `DISABLE_X11=1` → Disable X11 support (needed for focus tracking)
* `DISABLE_AV=1`Disable audio call support
* `DISABLE_SOUND_NOTIFY=1` → Disable sound notifications support
* `DISABLE_QRCODE` → Disable QR exporting 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
#### 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")
* `DESTDIR=""` Specifies the base install directory for binaries and data files (e.g.: DESTDIR="/tmp/build/pkg")
#### 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.

View File

View File

@ -3,13 +3,15 @@ CFG_DIR = $(BASE_DIR)/cfg
-include $(CFG_DIR)/global_vars.mk
LIBS = toxcore ncursesw libconfig libqrencode
LIBS = toxcore ncursesw libconfig libcurl
CFLAGS = -std=gnu99 -pthread -Wall -g -fstack-protector-all
CFLAGS ?= -g
CFLAGS += -std=gnu99 -pthread -Wall -Wpedantic -Wunused -fstack-protector-all
CFLAGS += '-DTOXICVER="$(VERSION)"' -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED -D_FILE_OFFSET_BITS=64
CFLAGS += '-DPACKAGE_DATADIR="$(abspath $(DATADIR))"'
CFLAGS += $(USER_CFLAGS)
LDFLAGS = $(USER_LDFLAGS)
CFLAGS += ${USER_CFLAGS}
LDFLAGS ?=
LDFLAGS += ${USER_LDFLAGS}
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
@ -19,26 +21,19 @@ OBJ += term_mplex.o toxic.o toxic_strings.o windows.o
# Check on wich system we are running
UNAME_S = $(shell uname -s)
ifeq ($(UNAME_S), Linux)
-include $(CFG_DIR)/systems/Linux.mk
endif
ifeq ($(UNAME_S), FreeBSD)
-include $(CFG_DIR)/systems/FreeBSD.mk
endif
ifeq ($(UNAME_S), DragonFly)
-include $(CFG_DIR)/systems/FreeBSD.mk
LDFLAGS += -ldl -lrt
endif
ifeq ($(UNAME_S), OpenBSD)
-include $(CFG_DIR)/systems/FreeBSD.mk
LIBS := $(filter-out ncursesw, $(LIBS))
LDFLAGS += -lncursesw
endif
ifeq ($(UNAME_S), NetBSD)
-include $(CFG_DIR)/systems/FreeBSD.mk
LIBS := $(filter-out ncursesw, $(LIBS))
LDFLAGS += -lncursesw
endif
ifeq ($(UNAME_S), Darwin)
-include $(CFG_DIR)/systems/Darwin.mk
endif
ifeq ($(UNAME_S), Solaris)
-include $(CFG_DIR)/systems/Solaris.mk
endif
# Check on which platform we are running
UNAME_M = $(shell uname -m)

View File

@ -3,7 +3,7 @@
src="https://scan.coverity.com/projects/4975/badge.svg"/>
</a>
Toxic is a [Tox](https://tox.chat)-based instant messenging and video chat client.
Toxic is a [Tox](https://tox.chat)-based instant messaging and video chat client.
[![Toxic Screenshot](https://i.imgur.com/san99Z2.png "Home Screen")](https://i.imgur.com/san99Z2.png)

View File

@ -55,9 +55,9 @@ author = 'Jakob Kreuze'
# built documents.
#
# The short X.Y version.
version = '0.8.1'
version = '0.8.4'
# The full version, including alpha/beta/rc tags.
release = '0.8.1'
release = '0.8.4'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

View File

@ -1,11 +1,26 @@
# Bracket Style Options
--style=kr
--pad-header
--max-code-length=120
--convert-tabs
--indent-switches
--pad-oper
--align-pointer=name
--align-reference=name
--preserve-date
--lineend=linux
--break-blocks
# 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

View File

@ -8,13 +8,13 @@ else
endif
# 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)
LIBS += $(AUDIO_LIBS)
CFLAGS += $(AUDIO_CFLAGS)
OBJ += $(AUDIO_OBJ)
else ifneq ($(MAKECMDGOALS), clean)
MISSING_AUDIO_LIBS = $(shell for lib in $(AUDIO_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
MISSING_AUDIO_LIBS := $(shell for lib in $(AUDIO_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
$(warning WARNING -- Toxic will be compiled without audio support)
$(warning WARNING -- You need these libraries for audio support)
$(warning WARNING -- $(MISSING_AUDIO_LIBS))

View File

@ -1,19 +1,19 @@
CHECKS_DIR = $(CFG_DIR)/checks
# 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)
-include $(CHECKS_DIR)/x11.mk
endif
# 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)
-include $(CHECKS_DIR)/audio.mk
endif
# 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 ($(AUDIO), disabled)
ifneq ($(VIDEO), disabled)
@ -23,36 +23,42 @@ endif
endif
# Check if we want build sound notifications support
SND_NOTIFY = $(shell if [ -z "$(DISABLE_SOUND_NOTIFY)" ] || [ "$(DISABLE_SOUND_NOTIFY)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
SND_NOTIFY := $(shell if [ -z "$(DISABLE_SOUND_NOTIFY)" ] || [ "$(DISABLE_SOUND_NOTIFY)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
ifneq ($(SND_NOTIFY), disabled)
-include $(CHECKS_DIR)/sound_notifications.mk
endif
# Check if we want build desktop notifications support
DESK_NOTIFY = $(shell if [ -z "$(DISABLE_DESKTOP_NOTIFY)" ] || [ "$(DISABLE_DESKTOP_NOTIFY)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
DESK_NOTIFY := $(shell if [ -z "$(DISABLE_DESKTOP_NOTIFY)" ] || [ "$(DISABLE_DESKTOP_NOTIFY)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
ifneq ($(DESK_NOTIFY), disabled)
-include $(CHECKS_DIR)/desktop_notifications.mk
endif
# Check if we 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)
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)
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_LIBS = $(shell $(PKG_CONFIG) --exists $(LIBS) || echo -n "error")
CHECK_LIBS := $(shell $(PKG_CONFIG) --exists $(LIBS) || echo -n "error")
ifneq ($(CHECK_LIBS), error)
CFLAGS += $(shell $(PKG_CONFIG) --cflags $(LIBS))
LDFLAGS += $(shell $(PKG_CONFIG) --libs $(LIBS))
else ifneq ($(MAKECMDGOALS), clean)
MISSING_LIBS = $(shell for lib in $(LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
MISSING_LIBS := $(shell for lib in $(LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
$(warning ERROR -- Cannot compile Toxic)
$(warning ERROR -- You need these libraries)
$(warning ERROR -- $(MISSING_LIBS))

View File

@ -3,12 +3,12 @@ DESK_NOTIFY_LIBS = libnotify
DESK_NOTIFY_CFLAGS = -DBOX_NOTIFY
# 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)
LIBS += $(DESK_NOTIFY_LIBS)
CFLAGS += $(DESK_NOTIFY_CFLAGS)
else ifneq ($(MAKECMDGOALS), clean)
MISSING_DESK_NOTIFY_LIBS = $(shell for lib in $(DESK_NOTIFY_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
MISSING_DESK_NOTIFY_LIBS := $(shell for lib in $(DESK_NOTIFY_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
$(warning WARNING -- Toxic will be compiled without desktop notifications support)
$(warning WARNING -- You need these libraries for desktop notifications support)
$(warning WARNING -- $(MISSING_DESK_NOTIFY_LIBS))

15
cfg/checks/qr.mk Normal file
View 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

View File

@ -1,5 +1,5 @@
# Variables for video call support
VIDEO_LIBS = vpx x11
VIDEO_LIBS = openal vpx x11
VIDEO_CFLAGS = -DVIDEO
ifneq (, $(findstring video_device.o, $(OBJ)))
VIDEO_OBJ = video_call.o

View File

@ -1,5 +1,5 @@
# Version
TOXIC_VERSION = 0.8.1
TOXIC_VERSION = 0.8.4
REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error")
ifneq (, $(findstring error, $(REV)))
VERSION = $(TOXIC_VERSION)
@ -23,10 +23,10 @@ SNDFILES += ToxicRecvMessage.wav ToxicOutgoingCall.wav ToxicIncomingCall.wav
SNDFILES += ToxicTransferComplete.wav ToxicTransferStart.wav
# Install directories
PREFIX = /usr/local
PREFIX ?= /usr/local
BINDIR = $(PREFIX)/bin
DATADIR = $(PREFIX)/share/toxic
MANDIR = $(PREFIX)/share/man
MANDIR ?= $(PREFIX)/share/man
APPDIR = $(PREFIX)/share/applications
# Platform tools

View File

@ -6,7 +6,7 @@ PKG_CONFIG_PATH = $(shell export PKG_CONFIG_PATH=/usr/lib/pkgconfig:/usr/local/o
LIBS := $(filter-out ncursesw, $(LIBS))
# 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
OSX_LIBRARIES = -lobjc -lresolv

View File

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

View File

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

View File

@ -1,10 +1,10 @@
# Doc target
doc: $(MANFILES:%=$(DOC_DIR)/%)
$(DOC_DIR)/%: $(DOC_DIR)/%.asc
@echo " MAN $(@F)"
@a2x -f manpage -a revdate=$(shell git log -1 --date=short --format="%ad" $<) \
-a manmanual="Toxic Manual" -a mansource=toxic \
-a manversion=__VERSION__ -a datadir=__DATADIR__ $<
.PHONY: doc

View File

@ -14,11 +14,22 @@ help:
@echo " DISABLE_AV: Set to \"1\" to force building without audio call support"
@echo " DISABLE_SOUND_NOTIFY: Set to \"1\" to force building without sound notification support"
@echo " DISABLE_DESKTOP_NOTIFY: Set to \"1\" to force building without desktop notifications support"
@echo " 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 " 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)\")"
@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

View File

@ -27,7 +27,7 @@ install: $(BUILD_DIR)/toxic
if [ ! -e "$(DOC_DIR)/$$f" ]; then \
continue ;\
fi ;\
section=$(abspath $(DESTDIR)/$(MANDIR))/man`echo $$f | rev | cut -d "." -f 1` ;\
section=$(abspath $(DESTDIR)/$(MANDIR))/man`echo $${f##*.}` ;\
file=$$section/$$f ;\
mkdir -p $$section ;\
install -m 0644 $(DOC_DIR)/$$f $$file ;\

View File

@ -16,7 +16,7 @@ uninstall:
@echo "Removing man pages"
@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 ;\
rm -f $$file $$file.gz ;\
done

View File

@ -78,6 +78,11 @@ instead of
Show help message
.RE
.PP
\-l, \-\-logging
.RS 4
Enable toxcore logging to stderr
.RE
.PP
\-n, \-\-nodes nodes\-file
.RS 4
Use specified

View File

@ -40,6 +40,9 @@ OPTIONS
-h, --help::
Show help message
-l, --logging::
Enable toxcore logging to stderr
-n, --nodes nodes-file::
Use specified 'nodes-file' for DHT bootstrap nodes instead of '~/.config/tox/DHTnodes.json'

View File

@ -2,12 +2,12 @@
.\" Title: toxic.conf
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
.\" Date: 2016-09-20
.\" Date: 2018-10-27
.\" Manual: Toxic Manual
.\" Source: toxic __VERSION__
.\" Language: English
.\"
.TH "TOXIC\&.CONF" "5" "2016\-09\-20" "toxic __VERSION__" "Toxic Manual"
.TH "TOXIC\&.CONF" "5" "2018\-10\-27" "toxic __VERSION__" "Toxic Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@ -120,7 +120,12 @@ Enable friend connection change notifications\&. true or false
.PP
\fBnodelist_update_freq\fR
.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
.PP
\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)
.RE
.PP
\fBnotification_timeout\fR
.RS 4
Time in milliseconds to display a notification\&. (for example: 3000)
.RE
.PP
\fBline_join\fR
.RS 4
Indicator for when someone connects or joins a group\&. Three characters max for line_ settings\&.
@ -341,16 +351,6 @@ Key combination to scroll half page down\&.
Key combination to scroll to page bottom\&.
.RE
.PP
\fBpeer_list_up\fR
.RS 4
Key combination to scroll contacts list up\&.
.RE
.PP
\fBpeer_list_down\fR
.RS 4
Key combination to scroll contacts list down\&.
.RE
.PP
\fBtoggle_peerlist\fR
.RS 4
Toggle the peer list on and off\&.

View File

@ -76,11 +76,17 @@ OPTIONS
Enable friend connection change notifications. true or false
*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*;;
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*;;
Indicator for when someone connects or joins a group.
Three characters max for line_ settings.
@ -215,12 +221,6 @@ OPTIONS
*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 the peer list on and off.

View File

@ -47,9 +47,15 @@ ui = {
// How often in days to update the DHT nodes list. (0 to disable updates)
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
history_size=700;
// time in milliseconds to display a notification
notification_timeout=3000;
// Indicator for display when someone connects or joins a group.
line_join="-->";
@ -116,8 +122,6 @@ keys = {
half_page_up="Ctrl+F";
half_page_down="Ctrl+V";
page_bottom="Ctrl+H";
peer_list_up="Ctrl+[";
peer_list_down="Ctrl+]";
toggle_peerlist="Ctrl+b";
toggle_paste_mode="Ctrl+T";
};

View File

@ -46,8 +46,9 @@ extern struct user_settings *user_settings;
void api_display(const char *const msg)
{
if (msg == NULL)
if (msg == NULL) {
return;
}
self_window = get_active_window();
line_info_add(self_window, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
@ -63,15 +64,16 @@ char *api_get_nick(void)
size_t len = tox_self_get_name_size(user_tox);
uint8_t *name = malloc(len + 1);
if (name == NULL)
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)
Tox_User_Status api_get_status(void)
{
return tox_self_get_status(user_tox);
}
@ -81,8 +83,9 @@ 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)
if (status == NULL) {
return NULL;
}
tox_self_get_status_message(user_tox, status);
status[len] = '\0';
@ -91,14 +94,16 @@ char *api_get_status_message(void)
void api_send(const char *msg)
{
if (msg == NULL || self_window->chatwin->cqueue == NULL)
if (msg == NULL || self_window->chatwin->cqueue == NULL) {
return;
}
char *name = api_get_nick();
char timefrmt[TIME_STR_SIZE];
if (name == NULL)
if (name == NULL) {
return;
}
self_window = get_active_window();
get_time_str(timefrmt, sizeof(timefrmt));
@ -144,9 +149,12 @@ void cmd_run(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
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!";
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;
@ -154,8 +162,8 @@ void cmd_run(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
fp = fopen(argv[1], "r");
if ( fp == NULL ) {
error_str = "Path does not exist!";
if (fp == NULL) {
error_str = "Path does not exist.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, error_str);
return;
@ -173,8 +181,9 @@ void invoke_autoruns(WINDOW *window, ToxWindow *self)
DIR *d;
FILE *fp;
if (user_settings->autorun_path[0] == '\0')
if (user_settings->autorun_path[0] == '\0') {
return;
}
d = opendir(user_settings->autorun_path);

View File

@ -29,7 +29,7 @@
void api_display(const char *const msg);
FriendsList api_get_friendslist(void);
char *api_get_nick(void);
TOX_USER_STATUS api_get_status(void);
Tox_User_Status api_get_status(void);
char *api_get_status_message(void);
void api_send(const char *msg);
void api_execute(const char *input, int mode);
@ -38,5 +38,6 @@ 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 /* #define API_H */
#endif /* API_H */

View File

@ -30,6 +30,9 @@
#include "notify.h"
#include "friendlist.h"
#include "chat.h"
#include "misc_tools.h"
#ifdef AUDIO
#ifdef VIDEO
#include "video_call.h"
@ -52,10 +55,12 @@
/* compatibility with older versions of OpenAL */
#ifndef ALC_ALL_DEVICES_SPECIFIER
#include <AL/alext.h>
#endif
#endif
#endif /* ALC_ALL_DEVICES_SPECIFIER */
#endif /* __APPLE__ */
extern FriendsList Friends;
extern ToxWindow *windows[MAX_WINDOWS_NUM];
struct CallControl CallControl;
#define cbend pthread_exit(NULL)
@ -71,51 +76,49 @@ static int set_call(Call *call, bool start)
call->vout_idx = -1;
#endif /* VIDEO */
if ( start ) {
if (start) {
call->ttas = true;
if ( pthread_mutex_init(&call->mutex, NULL) != 0 )
if (pthread_mutex_init(&call->mutex, NULL) != 0) {
return -1;
}
} else {
call->ttid = 0;
if ( pthread_mutex_destroy(&call->mutex) != 0 )
if (pthread_mutex_destroy(&call->mutex) != 0) {
return -1;
}
}
return 0;
}
void call_cb ( ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled,
void *user_data );
void callstate_cb ( ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data );
void receive_audio_frame_cb ( ToxAV *av, uint32_t friend_number, int16_t const *pcm, size_t sample_count,
uint8_t channels, uint32_t sampling_rate, void *user_data );
void receive_video_frame_cb ( ToxAV *av, uint32_t friend_number,
uint16_t width, uint16_t height,
uint8_t const *y, uint8_t const *u, uint8_t const *v, uint8_t const *a,
int32_t ystride, int32_t ustride, int32_t vstride, int32_t astride, void *user_data );
void on_call(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled,
void *user_data);
void on_call_state(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data);
void on_audio_receive_frame(ToxAV *av, uint32_t friend_number, int16_t const *pcm, size_t sample_count,
uint8_t channels, uint32_t sampling_rate, void *user_data);
void callback_recv_invite ( Tox *m, uint32_t friend_number );
void callback_recv_ringing ( uint32_t friend_number );
void callback_recv_starting ( uint32_t friend_number );
void callback_recv_ending ( uint32_t friend_number );
void callback_call_started ( uint32_t friend_number );
void callback_call_canceled ( uint32_t friend_number );
void callback_call_rejected ( uint32_t friend_number );
void callback_call_ended ( uint32_t friend_number );
void callback_recv_invite(Tox *m, uint32_t friend_number);
void callback_recv_ringing(uint32_t friend_number);
void callback_recv_starting(uint32_t friend_number);
void callback_recv_ending(uint32_t friend_number);
void callback_call_started(uint32_t friend_number);
void callback_call_canceled(uint32_t friend_number);
void callback_call_rejected(uint32_t friend_number);
void callback_call_ended(uint32_t friend_number);
void write_device_callback( uint32_t friend_number, const int16_t *PCM, uint16_t sample_count, uint8_t channels,
uint32_t sample_rate );
void write_device_callback(uint32_t friend_number, const int16_t *PCM, uint16_t sample_count, uint8_t channels,
uint32_t sample_rate);
static void print_err (ToxWindow *self, const char *error_str)
static void print_err(ToxWindow *self, const char *error_str)
{
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", error_str);
}
ToxAV *init_audio(ToxWindow *self, Tox *tox)
{
TOXAV_ERR_NEW error;
Toxav_Err_New error;
CallControl.audio_errors = ae_None;
CallControl.prompt = self;
CallControl.pending_call = false;
@ -134,89 +137,99 @@ ToxAV *init_audio(ToxWindow *self, Tox *tox)
CallControl.video_frame_duration = 0;
#endif /* VIDEO */
if ( !CallControl.av ) {
if (!CallControl.av) {
CallControl.audio_errors |= ae_StartingCoreAudio;
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init ToxAV");
return NULL;
}
if ( init_devices(CallControl.av) == de_InternalError ) {
if (init_devices(CallControl.av) == de_InternalError) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init devices");
toxav_kill(CallControl.av);
return CallControl.av = NULL;
}
toxav_callback_call(CallControl.av, call_cb, tox);
toxav_callback_call_state(CallControl.av, callstate_cb, NULL);
toxav_callback_audio_receive_frame(CallControl.av, receive_audio_frame_cb, NULL);
toxav_callback_call(CallControl.av, on_call, tox);
toxav_callback_call_state(CallControl.av, on_call_state, NULL);
toxav_callback_audio_receive_frame(CallControl.av, on_audio_receive_frame, NULL);
return CallControl.av;
}
void terminate_audio()
void terminate_audio(void)
{
int i;
for (i = 0; i < CallControl.max_calls; ++i)
for (i = 0; i < CallControl.max_calls; ++i) {
stop_transmission(&CallControl.calls[i], i);
}
if ( CallControl.av )
if (CallControl.av) {
toxav_kill(CallControl.av);
}
terminate_devices();
}
void read_device_callback(const int16_t *captured, uint32_t size, void *data)
{
TOXAV_ERR_SEND_FRAME error;
UNUSED_VAR(size);
Toxav_Err_Send_Frame error;
uint32_t friend_number = *((uint32_t *)data); /* TODO: Or pass an array of call_idx's */
int64_t sample_count = ((int64_t) CallControl.audio_sample_rate) * \
((int64_t) CallControl.audio_frame_duration) / 1000;
if ( sample_count <= 0 || toxav_audio_send_frame(CallControl.av, friend_number,
if (sample_count <= 0 || toxav_audio_send_frame(CallControl.av, friend_number,
captured, sample_count,
CallControl.audio_channels,
CallControl.audio_sample_rate, &error) == false ) {
CallControl.audio_sample_rate, &error) == false) {
}
}
void write_device_callback(uint32_t friend_number, const int16_t *PCM, uint16_t sample_count, uint8_t channels,
uint32_t sample_rate)
{
if ( CallControl.calls[friend_number].ttas )
if (CallControl.calls[friend_number].ttas) {
write_out(CallControl.calls[friend_number].out_idx, PCM, sample_count, channels, sample_rate);
}
}
int start_transmission(ToxWindow *self, Call *call)
{
if ( !self || !CallControl.av ) {
if (!self || !CallControl.av) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to prepare transmission");
return -1;
}
if (set_call(call, true) == -1)
if (set_call(call, true) == -1) {
return -1;
}
DeviceError error = open_primary_device(input, &call->in_idx,
CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels);
if ( error != de_None ) {
if ( error == de_FailedStart)
if (error != de_None) {
if (error == de_FailedStart) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to start input device");
}
if ( error == de_InternalError )
if (error == de_InternalError) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Internal error with opening input device");
}
}
if ( register_device_callback(self->num, call->in_idx,
read_device_callback, &self->num, true) != de_None)
if (register_device_callback(self->num, call->in_idx,
read_device_callback, &self->num, true) != de_None)
/* Set VAD as true for all; TODO: Make it more dynamic */
{
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to register input handler!");
}
if ( open_primary_device(output, &call->out_idx,
CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels) != de_None ) {
if (open_primary_device(output, &call->out_idx,
CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels) != de_None) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open output device!");
call->has_output = 0;
}
@ -226,23 +239,27 @@ int start_transmission(ToxWindow *self, Call *call)
int stop_transmission(Call *call, uint32_t friend_number)
{
if ( call->ttas ) {
TOXAV_ERR_CALL_CONTROL error = TOXAV_ERR_CALL_CONTROL_OK;
if (call->ttas) {
Toxav_Err_Call_Control error = TOXAV_ERR_CALL_CONTROL_OK;
if ( CallControl.call_state > TOXAV_FRIEND_CALL_STATE_FINISHED )
if (CallControl.call_state > TOXAV_FRIEND_CALL_STATE_FINISHED) {
toxav_call_control(CallControl.av, friend_number, TOXAV_CALL_CONTROL_CANCEL, &error);
}
if ( error == TOXAV_ERR_CALL_CONTROL_OK ) {
if (error == TOXAV_ERR_CALL_CONTROL_OK) {
call->ttas = false;
if ( call->in_idx != -1 )
if (call->in_idx != -1) {
close_device(input, call->in_idx);
}
if ( call->out_idx != -1 )
if (call->out_idx != -1) {
close_device(output, call->out_idx);
}
if ( set_call(call, false) == -1 )
if (set_call(call, false) == -1) {
return -1;
}
return 0;
} else {
@ -264,19 +281,26 @@ int stop_transmission(Call *call, uint32_t friend_number)
/*
* Callbacks
*/
void call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data)
void on_call(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data)
{
UNUSED_VAR(av);
UNUSED_VAR(audio_enabled);
UNUSED_VAR(video_enabled);
Tox *m = (Tox *) user_data;
CallControl.pending_call = true;
callback_recv_invite(m, friend_number);
}
void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data)
void on_call_state(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data)
{
UNUSED_VAR(av);
UNUSED_VAR(user_data);
CallControl.call_state = state;
switch ( state ) {
case ( TOXAV_FRIEND_CALL_STATE_ERROR ):
switch (state) {
case (TOXAV_FRIEND_CALL_STATE_ERROR):
line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "ToxAV callstate error!");
#ifdef VIDEO
@ -289,11 +313,12 @@ void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_
break;
case ( TOXAV_FRIEND_CALL_STATE_FINISHED ):
if ( CallControl.pending_call )
case (TOXAV_FRIEND_CALL_STATE_FINISHED):
if (CallControl.pending_call) {
callback_call_rejected(friend_number);
else
} else {
callback_call_ended(friend_number);
}
#ifdef VIDEO
callback_recv_video_end(friend_number);
@ -309,7 +334,7 @@ void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_
break;
default:
if ( CallControl.pending_call ) {
if (CallControl.pending_call) {
/* Start answered call */
callback_call_started(friend_number);
CallControl.pending_call = false;
@ -318,10 +343,11 @@ void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_
#ifdef VIDEO
/* Handle receiving client video call states */
if ( state & TOXAV_FRIEND_CALL_STATE_SENDING_V )
if (state & TOXAV_FRIEND_CALL_STATE_SENDING_V) {
callback_recv_video_starting(friend_number);
else if ( state & ~TOXAV_FRIEND_CALL_STATE_SENDING_V )
} else if (state & ~TOXAV_FRIEND_CALL_STATE_SENDING_V) {
callback_recv_video_end(friend_number);
}
#endif /* VIDEO */
}
@ -330,10 +356,13 @@ void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_
}
}
void receive_audio_frame_cb(ToxAV *av, uint32_t friend_number,
void on_audio_receive_frame(ToxAV *av, uint32_t friend_number,
int16_t const *pcm, size_t sample_count,
uint8_t channels, uint32_t sampling_rate, void *user_data)
{
UNUSED_VAR(av);
UNUSED_VAR(user_data);
write_device_callback(friend_number, pcm, sample_count, channels, sampling_rate);
}
@ -345,48 +374,41 @@ void audio_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_
void callback_recv_invite(Tox *m, uint32_t friend_number)
{
if (friend_number >= Friends.max_idx)
if (friend_number >= Friends.max_idx) {
return;
}
if (Friends.list[friend_number].chatwin == -1) {
if (get_num_active_windows() >= MAX_WINDOWS_NUM)
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
return;
}
Friends.list[friend_number].chatwin = add_window(m, new_chat(m, Friends.list[friend_number].num));
}
ToxWindow *windows = CallControl.prompt;
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onInvite != NULL && windows[i].num == friend_number) {
windows[i].onInvite(&windows[i], CallControl.av, friend_number, CallControl.call_state);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onInvite != NULL && windows[i]->num == friend_number) {
windows[i]->onInvite(windows[i], CallControl.av, friend_number, CallControl.call_state);
}
}
}
void callback_recv_ringing(uint32_t friend_number)
{
ToxWindow *windows = CallControl.prompt;
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onRinging != NULL && windows[i].num == friend_number) {
windows[i].onRinging(&windows[i], CallControl.av, friend_number, CallControl.call_state);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onRinging != NULL && windows[i]->num == friend_number) {
windows[i]->onRinging(windows[i], CallControl.av, friend_number, CallControl.call_state);
}
}
}
void callback_recv_starting(uint32_t friend_number)
{
ToxWindow *windows = CallControl.prompt;
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onStarting != NULL && windows[i]->num == friend_number) {
windows[i]->onStarting(windows[i], CallControl.av, friend_number, CallControl.call_state);
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if ( windows[i].onStarting != NULL && windows[i].num == friend_number ) {
windows[i].onStarting(&windows[i], CallControl.av, friend_number, CallControl.call_state);
if ( 0 != start_transmission(&windows[i], &CallControl.calls[friend_number]) ) /* YEAH! */
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!");
if (0 != start_transmission(windows[i], &CallControl.calls[friend_number])) { /* YEAH! */
line_info_add(windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!");
}
return;
}
@ -394,61 +416,46 @@ void callback_recv_starting(uint32_t friend_number)
}
void callback_recv_ending(uint32_t friend_number)
{
ToxWindow *windows = CallControl.prompt;
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onEnding != NULL && windows[i].num == friend_number) {
windows[i].onEnding(&windows[i], CallControl.av, friend_number, CallControl.call_state);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onEnding != NULL && windows[i]->num == friend_number) {
windows[i]->onEnding(windows[i], CallControl.av, friend_number, CallControl.call_state);
}
}
}
void callback_call_started(uint32_t friend_number)
{
ToxWindow *windows = CallControl.prompt;
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onStart != NULL && windows[i]->num == friend_number) {
windows[i]->onStart(windows[i], CallControl.av, friend_number, CallControl.call_state);
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i)
if ( windows[i].onStart != NULL && windows[i].num == friend_number ) {
windows[i].onStart(&windows[i], CallControl.av, friend_number, CallControl.call_state);
if ( 0 != start_transmission(&windows[i], &CallControl.calls[friend_number]) ) {/* YEAH! */
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!");
if (0 != start_transmission(windows[i], &CallControl.calls[friend_number])) { /* YEAH! */
line_info_add(windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!");
return;
}
}
}
}
void callback_call_canceled(uint32_t friend_number)
{
ToxWindow *windows = CallControl.prompt;
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onCancel != NULL && windows[i].num == friend_number) {
windows[i].onCancel(&windows[i], CallControl.av, friend_number, CallControl.call_state);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onCancel != NULL && windows[i]->num == friend_number) {
windows[i]->onCancel(windows[i], CallControl.av, friend_number, CallControl.call_state);
}
}
}
void callback_call_rejected(uint32_t friend_number)
{
ToxWindow *windows = CallControl.prompt;
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onReject != NULL && windows[i].num == friend_number) {
windows[i].onReject(&windows[i], CallControl.av, friend_number, CallControl.call_state);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onReject != NULL && windows[i]->num == friend_number) {
windows[i]->onReject(windows[i], CallControl.av, friend_number, CallControl.call_state);
}
}
}
void callback_call_ended(uint32_t friend_number)
{
ToxWindow *windows = CallControl.prompt;
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onEnd != NULL && windows[i].num == friend_number) {
windows[i].onEnd(&windows[i], CallControl.av, friend_number, CallControl.call_state);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onEnd != NULL && windows[i]->num == friend_number) {
windows[i]->onEnd(windows[i], CallControl.av, friend_number, CallControl.call_state);
}
}
}
@ -463,37 +470,47 @@ void callback_call_ended(uint32_t friend_number)
*/
void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
TOXAV_ERR_CALL error;
UNUSED_VAR(window);
UNUSED_VAR(m);
UNUSED_VAR(argv);
Toxav_Err_Call error;
const char *error_str;
if ( argc != 0 ) {
if (argc != 0) {
error_str = "Unknown arguments.";
goto on_error;
}
if ( !CallControl.av ) {
if (!CallControl.av) {
error_str = "ToxAV not supported!";
goto on_error;
}
if ( !self->stb->connection ) {
if (!self->stb->connection) {
error_str = "Friend is offline.";
goto on_error;
}
if ( CallControl.pending_call ) {
if (CallControl.pending_call) {
error_str = "Already a pending call!";
goto on_error;
}
toxav_call(CallControl.av, self->num, CallControl.audio_bit_rate, CallControl.video_bit_rate, &error);
if ( error != TOXAV_ERR_CALL_OK ) {
if ( error == TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL ) error_str = "Already in a call!";
else if ( error == TOXAV_ERR_CALL_MALLOC ) error_str = "Memory allocation issue";
else if ( error == TOXAV_ERR_CALL_FRIEND_NOT_FOUND ) error_str = "Friend number invalid";
else if ( error == TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED ) error_str = "Friend is valid but not currently connected";
else error_str = "Internal error!";
if (error != TOXAV_ERR_CALL_OK) {
if (error == TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL) {
error_str = "Already in a call!";
} else if (error == TOXAV_ERR_CALL_MALLOC) {
error_str = "Memory allocation issue";
} else if (error == TOXAV_ERR_CALL_FRIEND_NOT_FOUND) {
error_str = "Friend number invalid";
} else if (error == TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED) {
error_str = "Friend is valid but not currently connected";
} else {
error_str = "Internal error!";
}
goto on_error;
}
@ -508,32 +525,42 @@ on_error:
void cmd_answer(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
TOXAV_ERR_ANSWER error;
UNUSED_VAR(window);
UNUSED_VAR(m);
UNUSED_VAR(argv);
Toxav_Err_Answer error;
const char *error_str;
if ( argc != 0 ) {
if (argc != 0) {
error_str = "Unknown arguments.";
goto on_error;
}
if ( !CallControl.av ) {
if (!CallControl.av) {
error_str = "Audio not supported!";
goto on_error;
}
if ( !CallControl.pending_call ) {
if (!CallControl.pending_call) {
error_str = "No incoming call!";
goto on_error;
}
toxav_answer(CallControl.av, self->num, CallControl.audio_bit_rate, CallControl.video_bit_rate, &error);
if ( error != TOXAV_ERR_ANSWER_OK ) {
if ( error == TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING ) error_str = "No incoming call!";
else if ( error == TOXAV_ERR_ANSWER_CODEC_INITIALIZATION ) error_str = "Failed to initialize codecs!";
else if ( error == TOXAV_ERR_ANSWER_FRIEND_NOT_FOUND ) error_str = "Friend not found!";
else if ( error == TOXAV_ERR_ANSWER_INVALID_BIT_RATE ) error_str = "Invalid bit rate!";
else error_str = "Internal error!";
if (error != TOXAV_ERR_ANSWER_OK) {
if (error == TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING) {
error_str = "No incoming call!";
} else if (error == TOXAV_ERR_ANSWER_CODEC_INITIALIZATION) {
error_str = "Failed to initialize codecs!";
} else if (error == TOXAV_ERR_ANSWER_FRIEND_NOT_FOUND) {
error_str = "Friend not found!";
} else if (error == TOXAV_ERR_ANSWER_INVALID_BIT_RATE) {
error_str = "Invalid bit rate!";
} else {
error_str = "Internal error!";
}
goto on_error;
}
@ -544,24 +571,28 @@ void cmd_answer(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
return;
on_error:
print_err (self, error_str);
print_err(self, error_str);
}
void cmd_reject(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
UNUSED_VAR(m);
UNUSED_VAR(argv);
const char *error_str;
if ( argc != 0 ) {
if (argc != 0) {
error_str = "Unknown arguments.";
goto on_error;
}
if ( !CallControl.av ) {
if (!CallControl.av) {
error_str = "Audio not supported!";
goto on_error;
}
if ( !CallControl.pending_call ) {
if (!CallControl.pending_call) {
error_str = "No incoming call!";
goto on_error;
}
@ -575,24 +606,28 @@ void cmd_reject(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
return;
on_error:
print_err (self, error_str);
print_err(self, error_str);
}
void cmd_hangup(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
UNUSED_VAR(m);
UNUSED_VAR(argv);
const char *error_str = NULL;
if ( !CallControl.av ) {
if (!CallControl.av) {
error_str = "Audio not supported!";
goto on_error;
}
if ( argc != 0 ) {
if (argc != 0) {
error_str = "Unknown arguments.";
goto on_error;
}
if ( !self->is_call && !CallControl.pending_call ) {
if (!self->is_call && !CallControl.pending_call) {
error_str = "Not in a call.";
goto on_error;
}
@ -604,27 +639,35 @@ void cmd_hangup(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
stop_current_call(self);
return;
on_error:
print_err (self, error_str);
print_err(self, error_str);
}
void cmd_list_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
UNUSED_VAR(m);
const char *error_str;
if ( argc != 1 ) {
if ( argc < 1 ) error_str = "Type must be specified!";
else error_str = "Only one argument allowed!";
if (argc != 1) {
if (argc < 1) {
error_str = "Type must be specified!";
} else {
error_str = "Only one argument allowed!";
}
goto on_error;
}
DeviceType type;
if ( strcasecmp(argv[1], "in") == 0 ) /* Input devices */
if (strcasecmp(argv[1], "in") == 0) { /* Input devices */
type = input;
}
else if ( strcasecmp(argv[1], "out") == 0 ) /* Output devices */
else if (strcasecmp(argv[1], "out") == 0) { /* Output devices */
type = output;
}
else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
@ -638,29 +681,38 @@ void cmd_list_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*
return;
on_error:
print_err (self, error_str);
print_err(self, error_str);
}
/* This changes primary device only */
void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
UNUSED_VAR(m);
const char *error_str;
if ( argc != 2 ) {
if ( argc < 1 ) error_str = "Type must be specified!";
else if ( argc < 2 ) error_str = "Must have id!";
else error_str = "Only two arguments allowed!";
if (argc != 2) {
if (argc < 1) {
error_str = "Type must be specified!";
} else if (argc < 2) {
error_str = "Must have id!";
} else {
error_str = "Only two arguments allowed!";
}
goto on_error;
}
DeviceType type;
if ( strcmp(argv[1], "in") == 0 ) /* Input devices */
if (strcmp(argv[1], "in") == 0) { /* Input devices */
type = input;
}
else if ( strcmp(argv[1], "out") == 0 ) /* Output devices */
else if (strcmp(argv[1], "out") == 0) { /* Output devices */
type = output;
}
else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
@ -671,40 +723,49 @@ void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (
char *end;
long int selection = strtol(argv[2], &end, 10);
if ( *end ) {
if (*end) {
error_str = "Invalid input";
goto on_error;
}
if ( set_primary_device(type, selection) == de_InvalidSelection ) {
if (set_primary_device(type, selection) == de_InvalidSelection) {
error_str = "Invalid selection!";
goto on_error;
}
return;
on_error:
print_err (self, error_str);
print_err(self, error_str);
}
void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
UNUSED_VAR(m);
const char *error_str;
if ( argc != 2 ) {
if ( argc < 1 ) error_str = "Type must be specified!";
else if ( argc < 2 ) error_str = "Must have id!";
else error_str = "Only two arguments allowed!";
if (argc != 2) {
if (argc < 1) {
error_str = "Type must be specified!";
} else if (argc < 2) {
error_str = "Must have id!";
} else {
error_str = "Only two arguments allowed!";
}
goto on_error;
}
DeviceType type;
if ( strcmp(argv[1], "in") == 0 ) /* Input devices */
if (strcmp(argv[1], "in") == 0) { /* Input devices */
type = input;
}
else if ( strcmp(argv[1], "out") == 0 ) /* Output devices */
else if (strcmp(argv[1], "out") == 0) { /* Output devices */
type = output;
}
else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
@ -715,24 +776,24 @@ void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
char *end;
long int selection = strtol(argv[2], &end, 10);
if ( *end ) {
if (*end) {
error_str = "Invalid input";
goto on_error;
}
if ( selection_valid(type, selection) == de_InvalidSelection ) {
if (selection_valid(type, selection) == de_InvalidSelection) {
error_str = "Invalid selection!";
goto on_error;
}
/* If call is active, change device */
if ( self->is_call ) {
if (self->is_call) {
Call *this_call = &CallControl.calls[self->num];
if ( this_call->ttas ) {
if (this_call->ttas) {
if ( type == output ) {
if (type == output) {
pthread_mutex_lock(&this_call->mutex);
close_device(output, this_call->out_idx);
this_call->has_output = open_device(output, selection, &this_call->out_idx,
@ -754,27 +815,35 @@ void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
return;
on_error:
print_err (self, error_str);
print_err(self, error_str);
}
void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
UNUSED_VAR(m);
const char *error_str;
if ( argc != 1 ) {
if ( argc < 1 ) error_str = "Type must be specified!";
else error_str = "Only two arguments allowed!";
if (argc != 1) {
if (argc < 1) {
error_str = "Type must be specified!";
} else {
error_str = "Only two arguments allowed!";
}
goto on_error;
}
DeviceType type;
if ( strcasecmp(argv[1], "in") == 0 ) /* Input devices */
if (strcasecmp(argv[1], "in") == 0) { /* Input devices */
type = input;
}
else if ( strcasecmp(argv[1], "out") == 0 ) /* Output devices */
else if (strcasecmp(argv[1], "out") == 0) { /* Output devices */
type = output;
}
else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
@ -783,12 +852,12 @@ void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
/* If call is active, use this_call values */
if ( self->is_call ) {
if (self->is_call) {
Call *this_call = &CallControl.calls[self->num];
pthread_mutex_lock(&this_call->mutex);
if ( type == input ) {
if (type == input) {
device_mute(type, this_call->in_idx);
self->chatwin->infobox.in_is_muted ^= 1;
} else {
@ -802,16 +871,22 @@ void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
return;
on_error:
print_err (self, error_str);
print_err(self, error_str);
}
void cmd_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
UNUSED_VAR(m);
const char *error_str;
if ( argc != 1 ) {
if ( argc < 1 ) error_str = "Must have value!";
else error_str = "Only two arguments allowed!";
if (argc != 1) {
if (argc < 1) {
error_str = "Must have value!";
} else {
error_str = "Only two arguments allowed!";
}
goto on_error;
}
@ -819,13 +894,13 @@ void cmd_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[M
char *end;
float value = strtof(argv[1], &end);
if ( *end ) {
if (*end) {
error_str = "Invalid input";
goto on_error;
}
/* Call must be active */
if ( self->is_call ) {
if (self->is_call) {
device_set_VAD_treshold(CallControl.calls[self->num].in_idx, value);
self->chatwin->infobox.vad_lvl = value;
}
@ -833,26 +908,29 @@ void cmd_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[M
return;
on_error:
print_err (self, error_str);
print_err(self, error_str);
}
void cmd_bitrate(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
UNUSED_VAR(m);
char *error_str;
if ( argc != 1 ) {
if (argc != 1) {
error_str = "Must have value!";
goto on_error;
}
if ( self->is_call == false ) {
if (self->is_call == false) {
error_str = "Must be in a call";
goto on_error;
}
const uint32_t bitrate = strtol(argv[1], NULL, 10);
TOXAV_ERR_BIT_RATE_SET error;
Toxav_Err_Bit_Rate_Set error;
audio_bit_rate_status_cb(CallControl.av, self->num, bitrate, &error);
if (error != TOXAV_ERR_BIT_RATE_SET_OK) {
@ -862,7 +940,7 @@ void cmd_bitrate(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
break;
case TOXAV_ERR_BIT_RATE_SET_INVALID_BIT_RATE:
error_str = "Invalid AV bit rate value (valid is 6-510)";
error_str = "Invalid audio bit rate value (valid is 6-510)";
break;
case TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_FOUND:
@ -883,13 +961,14 @@ void cmd_bitrate(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
return;
on_error:
print_err (self, error_str);
print_err(self, error_str);
}
void stop_current_call(ToxWindow *self)
{
if ( CallControl.pending_call ) {
toxav_call_control(CallControl.av, self->num, TOXAV_CALL_CONTROL_CANCEL, NULL);
toxav_call_control(CallControl.av, self->num, TOXAV_CALL_CONTROL_CANCEL, NULL);
if (CallControl.pending_call) {
callback_call_canceled(self->num);
} else {
stop_transmission(&CallControl.calls[self->num], self->num);
@ -942,3 +1021,5 @@ void del_friend_AV(uint32_t index)
realloc_calls(index);
CallControl.max_calls = index;
}
#endif /* AUDIO */

View File

@ -85,7 +85,7 @@ extern struct CallControl CallControl;
/* You will have to pass pointer to first member of 'windows' declared in windows.c */
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);
void stop_current_call(ToxWindow *self);

View File

@ -28,18 +28,14 @@
#include "line_info.h"
#include "settings.h"
#include "misc_tools.h"
#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 /* ALC_ALL_DEVICES_SPECIFIER */
#include <stdbool.h>
#include <string.h>
@ -97,19 +93,21 @@ void *thread_poll(void *);
#ifdef AUDIO
DeviceError init_devices(ToxAV *av_)
#else
DeviceError init_devices()
DeviceError init_devices(void)
#endif /* AUDIO */
{
get_devices_names();
// Start poll thread
if (pthread_mutex_init(&mutex, NULL) != 0)
if (pthread_mutex_init(&mutex, NULL) != 0) {
return de_InternalError;
}
pthread_t thread_id;
if ( pthread_create(&thread_id, NULL, thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0)
if (pthread_create(&thread_id, NULL, thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0) {
return de_InternalError;
}
#ifdef AUDIO
av = av_;
@ -118,7 +116,7 @@ DeviceError init_devices()
return (DeviceError) de_None;
}
DeviceError terminate_devices()
DeviceError terminate_devices(void)
{
/* Cleanup if needed */
lock;
@ -127,47 +125,52 @@ DeviceError terminate_devices()
usleep(20000);
if (pthread_mutex_destroy(&mutex) != 0)
if (pthread_mutex_destroy(&mutex) != 0) {
return (DeviceError) de_InternalError;
}
return (DeviceError) de_None;
}
void get_devices_names() {
void get_devices_names(void)
{
const char *stringed_device_list;
size[input] = 0;
if ( (stringed_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER)) ) {
if ((stringed_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER))) {
ddevice_names[input] = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
for ( ; *stringed_device_list && size[input] < MAX_DEVICES; ++size[input] ) {
for (; *stringed_device_list && size[input] < MAX_DEVICES; ++size[input]) {
devices_names[input][size[input]] = stringed_device_list;
stringed_device_list += strlen( stringed_device_list ) + 1;
stringed_device_list += strlen(stringed_device_list) + 1;
}
}
size[output] = 0;
if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE)
if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE) {
stringed_device_list = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
else
} else {
stringed_device_list = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
}
if (stringed_device_list) {
ddevice_names[output] = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
for ( ; *stringed_device_list && size[output] < MAX_DEVICES; ++size[output] ) {
for (; *stringed_device_list && size[output] < MAX_DEVICES; ++size[output]) {
devices_names[output][size[output]] = stringed_device_list;
stringed_device_list += strlen( stringed_device_list ) + 1;
stringed_device_list += strlen(stringed_device_list) + 1;
}
}
}
DeviceError device_mute(DeviceType type, uint32_t device_idx)
{
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
if (device_idx >= MAX_DEVICES) {
return de_InvalidSelection;
}
lock;
@ -187,7 +190,9 @@ DeviceError device_mute(DeviceType type, uint32_t device_idx)
#ifdef AUDIO
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
{
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
if (device_idx >= MAX_DEVICES) {
return de_InvalidSelection;
}
lock;
@ -208,7 +213,9 @@ DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
DeviceError set_primary_device(DeviceType type, int32_t selection)
{
if (size[type] <= selection || selection < 0) return de_InvalidSelection;
if (size[type] <= selection || selection < 0) {
return de_InvalidSelection;
}
primary_device[type] = selection;
@ -230,9 +237,13 @@ void get_primary_device_name(DeviceType type, char *buf, int size)
DeviceError open_device(DeviceType type, int32_t selection, uint32_t *device_idx, uint32_t sample_rate,
uint32_t frame_duration, uint8_t channels)
{
if (size[type] <= selection || selection < 0) return de_InvalidSelection;
if (size[type] <= selection || selection < 0) {
return de_InvalidSelection;
}
if (channels != 1 && channels != 2) return de_UnsupportedMode;
if (channels != 1 && channels != 2) {
return de_UnsupportedMode;
}
lock;
@ -245,10 +256,12 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t *device_idx
if (i == MAX_DEVICES) {
unlock;
return de_AllDevicesBusy;
} else *device_idx = i;
} else {
*device_idx = i;
}
for (i = 0; i < MAX_DEVICES; i ++) { /* Check if any device has the same selection */
if ( running[type][i] && running[type][i]->selection == selection ) {
if (running[type][i] && running[type][i]->selection == selection) {
// printf("a%d-%d:%p ", selection, i, running[type][i]->dhndl);
running[type][*device_idx] = running[type][i];
@ -281,7 +294,7 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t *device_idx
} else {
device->dhndl = alcOpenDevice(devices_names[type][selection]);
if ( !device->dhndl ) {
if (!device->dhndl) {
free(device);
running[type][*device_idx] = NULL;
unlock;
@ -298,7 +311,7 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t *device_idx
uint16_t zeros[frame_size];
memset(zeros, 0, frame_size * 2);
for ( i = 0; i < OPENAL_BUFS; ++i ) {
for (i = 0; i < OPENAL_BUFS; ++i) {
alBufferData(device->buffers[i], device->sound_mode, zeros, frame_size * 2, sample_rate);
}
@ -324,7 +337,9 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t *device_idx
DeviceError close_device(DeviceType type, uint32_t device_idx)
{
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
if (device_idx >= MAX_DEVICES) {
return de_InvalidSelection;
}
lock;
Device *device = running[type][device_idx];
@ -337,34 +352,45 @@ DeviceError close_device(DeviceType type, uint32_t device_idx)
running[type][device_idx] = NULL;
if ( !device->ref_count ) {
if (!device->ref_count) {
if (type == input) {
if ( !alcCaptureCloseDevice(device->dhndl) ) rc = de_AlError;
if (!alcCaptureCloseDevice(device->dhndl)) {
rc = de_AlError;
}
} else {
if (alcGetCurrentContext() != device->ctx) alcMakeContextCurrent(device->ctx);
if (alcGetCurrentContext() != device->ctx) {
alcMakeContextCurrent(device->ctx);
}
alDeleteSources(1, &device->source);
alDeleteBuffers(OPENAL_BUFS, device->buffers);
alcMakeContextCurrent(NULL);
if ( device->ctx ) alcDestroyContext(device->ctx);
if (device->ctx) {
alcDestroyContext(device->ctx);
}
if ( !alcCloseDevice(device->dhndl) ) rc = de_AlError;
if (!alcCloseDevice(device->dhndl)) {
rc = de_AlError;
}
}
free(device);
} else device->ref_count--;
} else {
device->ref_count--;
}
unlock;
return rc;
}
DeviceError register_device_callback( int32_t friend_number, uint32_t device_idx, DataHandleCallback callback,
void *data, bool enable_VAD)
DeviceError register_device_callback(int32_t friend_number, uint32_t device_idx, DataHandleCallback callback,
void *data, bool enable_VAD)
{
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL) {
return de_InvalidSelection;
}
lock;
running[input][device_idx]->cb = callback;
@ -379,11 +405,15 @@ DeviceError register_device_callback( int32_t friend_number, uint32_t device_idx
inline__ DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_t sample_count, uint8_t channels,
uint32_t sample_rate)
{
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
if (device_idx >= MAX_DEVICES) {
return de_InvalidSelection;
}
Device *device = running[output][device_idx];
if (!device || device->muted) return de_DeviceNotActive;
if (!device || device->muted) {
return de_DeviceNotActive;
}
pthread_mutex_lock(device->mutex);
@ -398,8 +428,9 @@ inline__ DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_
alSourceUnqueueBuffers(device->source, processed, bufids);
alDeleteBuffers(processed - 1, bufids + 1);
bufid = bufids[0];
} else if (queued < 16) alGenBuffers(1, &bufid);
else {
} else if (queued < 16) {
alGenBuffers(1, &bufid);
} else {
pthread_mutex_unlock(device->mutex);
return de_Busy;
}
@ -412,19 +443,21 @@ inline__ DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_
ALint state;
alGetSourcei(device->source, AL_SOURCE_STATE, &state);
if (state != AL_PLAYING) alSourcePlay(device->source);
if (state != AL_PLAYING) {
alSourcePlay(device->source);
}
pthread_mutex_unlock(device->mutex);
return de_None;
}
void *thread_poll (void *arg) // TODO: maybe use thread for every input source
void *thread_poll(void *arg) // TODO: maybe use thread for every input source
{
/*
* NOTE: We only need to poll input devices for data.
*/
(void)arg;
UNUSED_VAR(arg);
uint32_t i;
int32_t sample = 0;
@ -469,7 +502,9 @@ void *thread_poll (void *arg) // TODO: maybe use thread for every input source
continue;
}
if ( device->cb ) device->cb(frame, f_size, device->cb_data);
if (device->cb) {
device->cb(frame, f_size, device->cb_data);
}
}
unlock;
@ -487,7 +522,8 @@ void print_devices(ToxWindow *self, DeviceType type)
int i;
for (i = 0; i < size[type]; ++i) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, i == primary_device[type] ? 1 : 0, 0, "%d: %s", i, devices_names[type][i]);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, i == primary_device[type] ? 1 : 0, 0, "%d: %s", i,
devices_names[type][i]);
}
return;
@ -500,8 +536,9 @@ DeviceError selection_valid(DeviceType type, int32_t selection)
void *get_device_callback_data(uint32_t device_idx)
{
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL) {
return NULL;
}
return running[input][device_idx]->cb_data;
}

View File

@ -31,7 +31,7 @@
#define OPENAL_BUFS 5
#define MAX_DEVICES 32
#include <inttypes.h>
#include "windows.h"
typedef enum DeviceType {
@ -52,17 +52,17 @@ typedef enum DeviceError {
de_AlError = -9,
} 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(ToxAV *av);
#else
DeviceError init_devices();
DeviceError init_devices(void);
#endif /* AUDIO */
void get_devices_names();
DeviceError terminate_devices();
void get_devices_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,

View File

@ -29,7 +29,7 @@
#include <sys/dir.h>
#else
#include <dirent.h>
#endif /* ifdef __APPLE__ */
#endif /* __APPLE__ */
#include "windows.h"
#include "toxic.h"
@ -61,6 +61,8 @@ static void print_matches(ToxWindow *self, Tox *m, const void *list, size_t n_it
*/
static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, char (*matches)[MAX_STR_SIZE], int n)
{
UNUSED_VAR(self);
if (n == 1) {
return snprintf(match, match_sz, "%s", matches[0]);
}
@ -85,53 +87,60 @@ static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, char
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
with "Hello john". If multiple matches, prints out all the matches and semi-completes line.
list is a pointer to the list of strings being compared, n_items is the number of items
in the list, and size is the size of each item in the list.
Returns the difference between the old len and new len of line on success, -1 if error */
int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size)
/*
* 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 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.
*
* dir_search should be true if the line being completed is a file path.
*
* Returns the difference between the old len and new len of line on success.
* Returns -1 on error.
*
* Note: This function should not be called directly. Use complete_line() and complete_path() instead.
*/
static int complete_line_helper(ToxWindow *self, const void *list, size_t n_items, size_t size, bool dir_search)
{
ChatContext *ctx = self->chatwin;
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;
}
const char *L = (char *) list;
if (ctx->len >= MAX_STR_SIZE || size > MAX_STR_SIZE) {
return -1;
}
const char *L = (const char *) list;
const char *endchrs = " ";
char ubuf[MAX_STR_SIZE];
char ubuf[MAX_STR_SIZE] = {0};
/* 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;
/* TODO: generalize this */
bool dir_search = !strncmp(ubuf, "/sendfile", strlen("/sendfile"))
|| !strncmp(ubuf, "/avatar", strlen("/avatar"));
#ifdef PYTHON
dir_search = dir_search || !strncmp(ubuf, "/run", strlen("/run"));
#endif
}
/* isolate substring from space behind pos to pos */
char tmp[MAX_STR_SIZE];
snprintf(tmp, sizeof(tmp), "%s", ubuf);
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);
if (sub == NULL)
exit_toxic_err("failed in complete_line", FATALERR_MEMORY);
if (sub == NULL) {
exit_toxic_err("failed in complete_line_helper", FATALERR_MEMORY);
}
if (!s && !dir_search) {
strcpy(sub, tmp);
if (sub[0] != '/')
if (sub[0] != '/') {
endchrs = ": ";
}
} else if (s) {
strcpy(sub, &s[1]);
@ -139,14 +148,15 @@ int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size
int sub_len = strlen(sub);
int si = char_rfind(sub, '/', sub_len);
if (si || *sub == '/')
if (si || *sub == '/') {
memmove(sub, &sub[si + 1], sub_len - si);
}
}
}
if (!sub[0]) {
free(sub);
return -1;
return 0;
}
int s_len = strlen(sub);
@ -159,17 +169,20 @@ int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size
char str[MAX_CMDNAME_SIZE + 1];
snprintf(str, sizeof(str), "%s", &L[i * size]);
if (strncasecmp(str, sub, s_len) == 0)
if (strncasecmp(str, sub, s_len) == 0) {
strcpy(matches[n_matches++], str);
}
}
free(sub);
if (!n_matches)
if (!n_matches) {
return -1;
}
if (!dir_search && n_matches > 1)
if (!dir_search && n_matches > 1) {
print_matches(self, NULL, matches, n_matches, MAX_STR_SIZE);
}
char match[MAX_STR_SIZE];
size_t match_len = get_str_match(self, match, sizeof(match), matches, n_matches);
@ -179,10 +192,11 @@ int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size
}
if (dir_search) {
if (n_matches == 1)
endchrs = char_rfind(match, '.', match_len) ? "\"" : "/";
else
if (n_matches == 1) {
endchrs = char_rfind(match, '.', match_len) ? "" : "/";
} else {
endchrs = "";
}
} else if (n_matches > 1) {
endchrs = "";
}
@ -192,8 +206,9 @@ int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size
int strt = ctx->pos - s_len;
int diff = match_len - s_len + n_endchrs;
if (ctx->len + diff >= MAX_STR_SIZE)
if (ctx->len + diff >= MAX_STR_SIZE) {
return -1;
}
char tmpend[MAX_STR_SIZE];
snprintf(tmpend, sizeof(tmpend), "%s", &ubuf[ctx->pos]);
@ -203,6 +218,31 @@ int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size
}
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 + n_endchrs], tmpend);
@ -221,8 +261,18 @@ int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size
return diff;
}
/* transforms a tab complete starting with the shorthand "~" into the full home directory.*/
static void complt_home_dir(ToxWindow *self, char *path, int pathsize, const char *cmd, int cmdlen)
int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size)
{
return complete_line_helper(self, list, n_items, size, false);
}
static int complete_path(ToxWindow *self, const void *list, size_t n_items, size_t size)
{
return complete_line_helper(self, list, n_items, size, true);
}
/* Transforms a tab complete starting with the shorthand "~" into the full home directory. */
static void complete_home_dir(ToxWindow *self, char *path, int pathsize, const char *cmd, int cmdlen)
{
ChatContext *ctx = self->chatwin;
@ -230,45 +280,51 @@ static void complt_home_dir(ToxWindow *self, char *path, int pathsize, const cha
get_home_dir(homedir, sizeof(homedir));
char newline[MAX_STR_SIZE];
snprintf(newline, sizeof(newline), "%s \"%s%s", cmd, homedir, path + 1);
snprintf(path, pathsize, "%s", &newline[cmdlen]);
snprintf(newline, sizeof(newline), "%s %s%s", cmd, homedir, path + 1);
snprintf(path, pathsize, "%s", &newline[cmdlen - 1]);
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;
}
int newlen = wcslen(wline);
if (ctx->len + newlen >= MAX_STR_SIZE)
if (ctx->len + newlen >= MAX_STR_SIZE) {
return;
}
wmemcpy(ctx->line, wline, newlen + 1);
ctx->pos = newlen;
ctx->len = ctx->pos;
}
/* attempts to match /command "<incomplete-dir>" line to matching directories.
if only one match, auto-complete line.
return diff between old len and new len of ctx->line, -1 if no matches or > 1 match */
/* 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 512
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
{
char b_path[MAX_STR_SIZE];
char b_name[MAX_STR_SIZE];
char b_cmd[MAX_STR_SIZE];
const wchar_t *tmpline = &line[wcslen(cmd) + 2]; /* start after "/command \"" */
const wchar_t *tmpline = &line[wcslen(cmd) + 1]; /* start after "/command " */
if (wcs_to_mbs_buf(b_path, tmpline, sizeof(b_path)) == -1)
if (wcs_to_mbs_buf(b_path, tmpline, sizeof(b_path)) == -1) {
return -1;
}
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;
}
if (b_path[0] == '~')
complt_home_dir(self, b_path, sizeof(b_path), b_cmd, strlen(b_cmd) + 2);
if (b_path[0] == '~') {
complete_home_dir(self, b_path, sizeof(b_path), b_cmd, strlen(b_cmd) + 2);
}
int si = char_rfind(b_path, '/', strlen(b_path));
@ -286,10 +342,11 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
int b_name_len = strlen(b_name);
DIR *dp = opendir(b_path);
if (dp == NULL)
if (dp == NULL) {
return -1;
}
char dirnames[MAX_DIRS][NAME_MAX+1];
char dirnames[MAX_DIRS][NAME_MAX + 1];
struct dirent *entry;
int dircount = 0;
@ -303,13 +360,14 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
closedir(dp);
if (dircount == 0)
if (dircount == 0) {
return -1;
}
if (dircount > 1) {
qsort(dirnames, dircount, NAME_MAX + 1, qsort_strcasecmp_hlpr);
print_matches(self, m, dirnames, dircount, NAME_MAX + 1);
}
return complete_line(self, dirnames, dircount, NAME_MAX + 1);
return complete_path(self, dirnames, dircount, NAME_MAX + 1);
}

View File

@ -23,20 +23,25 @@
#ifndef AUTOCOMPLETE_H
#define AUTOCOMPLETE_H
/* looks for all instances in list that begin with the last entered word in line according to pos,
then fills line with the complete word. e.g. "Hello jo" would complete the line
with "Hello john". If multiple matches, prints out all the matches and semi-completes line.
list is a pointer to the list of strings being compared, n_items is the number of items
in the list, and size is the size of each item in the list.
Returns the difference between the old len and new len of line on success, -1 if error */
/*
* 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 the list of strings being compared, n_items is the number of items
* in the list, and size is the size of each item in the list.
*
* Returns the difference between the old len and new len of line on success.
* Returns -1 on error.
*/
int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size);
/* attempts to match /command "<incomplete-dir>" line to matching directories.
if only one match, auto-complete line.
return diff between old len and new len of ctx->line, -1 if no matches or > 1 match */
/* 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.
*/
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd);
#endif /* #define AUTOCOMPLETE_H */
#endif /* AUTOCOMPLETE_H */

View File

@ -52,12 +52,13 @@ static void avatar_clear(void)
*/
int avatar_send(Tox *m, uint32_t friendnum)
{
TOX_ERR_FILE_SEND err;
Tox_Err_File_Send err;
uint32_t filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_AVATAR, (size_t) Avatar.size,
NULL, (uint8_t *) Avatar.name, Avatar.name_len, &err);
if (Avatar.size == 0)
if (Avatar.size == 0) {
return 0;
}
if (err != TOX_ERR_FILE_SEND_OK) {
fprintf(stderr, "tox_file_send failed for friendnumber %d (error %d)\n", friendnum, err);
@ -66,13 +67,15 @@ int avatar_send(Tox *m, uint32_t friendnum)
struct FileTransfer *ft = new_file_transfer(NULL, friendnum, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_AVATAR);
if (!ft)
if (!ft) {
return -1;
}
ft->file = fopen(Avatar.path, "r");
if (ft->file == NULL)
if (ft->file == NULL) {
return -1;
}
snprintf(ft->file_name, sizeof(ft->file_name), "%s", Avatar.name);
ft->file_size = Avatar.size;
@ -86,8 +89,9 @@ static void avatar_send_all(Tox *m)
size_t i;
for (i = 0; i < Friends.max_idx; ++i) {
if (Friends.list[i].connection_status != TOX_CONNECTION_NONE)
if (Friends.list[i].connection_status != TOX_CONNECTION_NONE) {
avatar_send(m, Friends.list[i].num);
}
}
}
@ -98,15 +102,17 @@ static void avatar_send_all(Tox *m)
*/
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;
}
FILE *fp = fopen(path, "rb");
if (fp == NULL)
if (fp == NULL) {
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) {
fclose(fp);
@ -117,8 +123,9 @@ int avatar_set(Tox *m, const char *path, size_t path_len)
off_t size = file_size(path);
if (size == 0 || size > MAX_AVATAR_FILE_SIZE)
if (size == 0 || size > MAX_AVATAR_FILE_SIZE) {
return -1;
}
get_file_name(Avatar.name, sizeof(Avatar.name), path);
Avatar.name_len = strlen(Avatar.name);
@ -142,7 +149,7 @@ void avatar_unset(Tox *m)
avatar_send_all(m);
}
void on_avatar_file_control(Tox *m, struct FileTransfer *ft, TOX_FILE_CONTROL control)
void on_avatar_file_control(Tox *m, struct FileTransfer *ft, Tox_File_Control control)
{
switch (control) {
case TOX_FILE_CONTROL_RESUME:
@ -166,8 +173,9 @@ void on_avatar_file_control(Tox *m, struct FileTransfer *ft, TOX_FILE_CONTROL co
void on_avatar_chunk_request(Tox *m, struct FileTransfer *ft, uint64_t position, size_t length)
{
if (ft->state != FILE_TRANSFER_STARTED)
if (ft->state != FILE_TRANSFER_STARTED) {
return;
}
if (length == 0) {
close_file_transfer(NULL, m, ft, -1, NULL, silent);
@ -196,11 +204,12 @@ void on_avatar_chunk_request(Tox *m, struct FileTransfer *ft, uint64_t position,
return;
}
TOX_ERR_FILE_SEND_CHUNK err;
Tox_Err_File_Send_Chunk err;
tox_file_send_chunk(m, ft->friendnum, ft->filenum, position, send_data, send_length, &err);
if (err != TOX_ERR_FILE_SEND_CHUNK_OK)
if (err != TOX_ERR_FILE_SEND_CHUNK_OK) {
fprintf(stderr, "tox_file_send_chunk failed in avatar callback (error %d)\n", err);
}
ft->position += send_length;
ft->last_keep_alive = get_unix_time();

View File

@ -47,6 +47,6 @@ int avatar_set(Tox *m, const char *path, size_t length);
void avatar_unset(Tox *m);
void on_avatar_chunk_request(Tox *m, struct FileTransfer *ft, uint64_t position, size_t length);
void on_avatar_file_control(Tox *m, struct FileTransfer *ft, TOX_FILE_CONTROL control);
void on_avatar_file_control(Tox *m, struct FileTransfer *ft, Tox_File_Control control);
#endif /* AVATARS_H */

View File

@ -430,6 +430,8 @@ static int extract_node(const char *line, struct Node *node)
/* Loads the DHT nodeslist to memory from json encoded nodes file. */
void *load_nodeslist_thread(void *data)
{
UNUSED_VAR(data);
char nodes_path[PATH_MAX];
get_nodeslist_path(nodes_path, sizeof(nodes_path));
@ -560,7 +562,7 @@ static void DHT_bootstrap(Tox *m)
continue;
}
TOX_ERR_BOOTSTRAP err;
Tox_Err_Bootstrap err;
tox_bootstrap(m, addr, node->port, (uint8_t *) node->key, &err);
if (err != TOX_ERR_BOOTSTRAP_OK) {

View File

@ -39,4 +39,4 @@ void do_tox_connection(Tox *m);
*/
int load_DHT_nodeslist(void);
#endif /* BOOTSTRAP_H */
#endif /* BOOTSTRAP_H */

File diff suppressed because it is too large Load Diff

View File

@ -30,6 +30,6 @@
set msg to NULL if we don't want to display a message */
void chat_close_file_receiver(Tox *m, int filenum, int friendnum, int CTRL);
void kill_chat_window(ToxWindow *self, Tox *m);
ToxWindow new_chat(Tox *m, int32_t friendnum);
ToxWindow *new_chat(Tox *m, int32_t friendnum);
#endif /* end of include guard: CHAT_H */

View File

@ -38,6 +38,8 @@ extern FriendsList Friends;
void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
if (argc < 2) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Requires type in|out and the file ID.");
return;
@ -80,6 +82,8 @@ void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group number required.");
return;
@ -92,7 +96,7 @@ void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
return;
}
TOX_ERR_CONFERENCE_INVITE err;
Tox_Err_Conference_Invite err;
if (!tox_conference_invite(m, self->num, groupnum, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to group (error %d)", err);
@ -104,6 +108,10 @@ void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
void cmd_join_group(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) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open.");
return;
@ -123,16 +131,16 @@ void cmd_join_group(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
return;
}
TOX_ERR_CONFERENCE_JOIN err;
Tox_Err_Conference_Join err;
uint32_t groupnum = tox_conference_join(m, self->num, (uint8_t *) groupkey, length, &err);
uint32_t groupnum = tox_conference_join(m, self->num, (const uint8_t *) groupkey, length, &err);
if (err != TOX_ERR_CONFERENCE_JOIN_OK) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize (error %d)", err);
return;
}
if (init_groupchat_win(prompt, m, groupnum, type) == -1) {
if (init_groupchat_win(m, groupnum, type, NULL, 0) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
tox_conference_delete(m, groupnum, NULL);
return;
@ -142,6 +150,8 @@ void cmd_join_group(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File ID required.");
return;
@ -167,16 +177,17 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
}
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);
return;
}
TOX_ERR_FILE_CONTROL err;
Tox_Err_File_Control err;
tox_file_control(m, self->num, ft->filenum, TOX_FILE_CONTROL_RESUME, &err);
if (err != TOX_ERR_FILE_CONTROL_OK)
if (err != TOX_ERR_FILE_CONTROL_OK) {
goto on_recv_error;
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%d] as: '%s'", idx, ft->file_path);
@ -217,6 +228,8 @@ on_recv_error:
void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
const char *errmsg = NULL;
if (argc < 1) {
@ -224,16 +237,9 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
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];
snprintf(path, sizeof(path), "%s", &argv[1][1]);
int path_len = strlen(path) - 1;
path[path_len] = '\0';
snprintf(path, sizeof(path), "%s", argv[1]);
int path_len = strlen(path);
if (path_len >= MAX_STR_SIZE) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path exceeds character limit.");
@ -258,12 +264,13 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
char file_name[TOX_MAX_FILENAME_LENGTH];
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,
(uint8_t *) file_name, namelen, &err);
if (err != TOX_ERR_FILE_SEND_OK)
if (err != TOX_ERR_FILE_SEND_OK) {
goto on_send_error;
}
struct FileTransfer *ft = new_file_transfer(self, self->num, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_DATA);

View File

@ -49,4 +49,4 @@ void cmd_video(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE
void cmd_ccur_video_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
#endif /* VIDEO */
#endif /* #define CHAT_COMMANDS_H */
#endif /* CHAT_COMMANDS_H */

View File

@ -48,8 +48,9 @@ void get_home_dir(char *home, int size)
} else {
hmstr = getenv("HOME");
if (hmstr == NULL)
if (hmstr == NULL) {
return;
}
snprintf(buf, sizeof(buf), "%s", hmstr);
hmstr = buf;
@ -77,8 +78,9 @@ char *get_user_config_dir(void)
len = strlen(home) + strlen("/Library/Application Support") + 1;
user_config_dir = malloc(len);
if (user_config_dir == NULL)
if (user_config_dir == NULL) {
return NULL;
}
snprintf(user_config_dir, len, "%s/Library/Application Support", home);
# else /* __APPLE__ */
@ -89,8 +91,9 @@ char *get_user_config_dir(void)
len = strlen(home) + strlen("/.config") + 1;
user_config_dir = malloc(len);
if (user_config_dir == NULL)
if (user_config_dir == NULL) {
return NULL;
}
snprintf(user_config_dir, len, "%s/.config", home);
} else {
@ -112,14 +115,16 @@ int create_user_config_dirs(char *path)
struct stat buf;
int mkdir_err = mkdir(path, 0700);
if (mkdir_err && (errno != EEXIST || stat(path, &buf) || !S_ISDIR(buf.st_mode)))
if (mkdir_err && (errno != EEXIST || stat(path, &buf) || !S_ISDIR(buf.st_mode))) {
return -1;
}
char *fullpath = malloc(strlen(path) + strlen(CONFIGDIR) + 1);
char *logpath = malloc(strlen(path) + strlen(LOGDIR) + 1);
if (fullpath == NULL || logpath == NULL)
if (fullpath == NULL || logpath == NULL) {
exit_toxic_err("failed in load_data_structures", FATALERR_MEMORY);
}
strcpy(fullpath, path);
strcat(fullpath, CONFIGDIR);

View File

@ -53,4 +53,4 @@ void get_home_dir(char *home, int size);
*/
int create_user_config_dirs(char *path);
#endif /* #define CONFIGDIR_H */
#endif /* CONFIGDIR_H */

View File

@ -36,8 +36,9 @@
*/
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;
}
if (proxy_address == NULL || port == 0) {
return -1;

View File

@ -52,4 +52,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);
#endif /* CURL_UTIL_H */
#endif /* CURL_UTIL_H */

View File

@ -52,7 +52,9 @@ static struct cmd_func global_commands[] = {
{ "/help", cmd_prompt_help },
{ "/log", cmd_log },
{ "/myid", cmd_myid },
#ifdef QRCODE
{ "/myqr", cmd_myqr },
#endif /* QRCODE */
{ "/nick", cmd_nick },
{ "/note", cmd_note },
{ "/nospam", cmd_nospam },
@ -105,52 +107,104 @@ static struct cmd_func group_commands[] = {
{ NULL, NULL },
};
/* Parses input command and puts args into arg array.
Returns number of arguments on success, -1 on failure. */
static int parse_command(WINDOW *w, ToxWindow *self, const char *input, char (*args)[MAX_STR_SIZE])
#ifdef PYTHON
#define SPECIAL_COMMANDS 6
#else
#define SPECIAL_COMMANDS 5
#endif /* PYTHON */
/* Special commands are commands that only take one argument even if it contains spaces */
static const char special_commands[SPECIAL_COMMANDS][MAX_CMDNAME_SIZE] = {
"/avatar",
"/nick",
"/note",
#ifdef PYTHON
"/run",
#endif /* PYTHON */
"/sendfile",
"/title",
};
/* 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);
if (cmd == NULL)
if (cmd == NULL) {
exit_toxic_err("failed in parse_command", FATALERR_MEMORY);
}
int num_args = 0;
int i = 0; /* index of last char in an argument */
/* characters wrapped in double quotes count as one arg */
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 == '\"') {
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 */
if (cmd[i] == '\0') { // no more args
break;
}
char tmp[MAX_STR_SIZE];
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);
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,
char (*args)[MAX_STR_SIZE])
{
@ -168,40 +222,47 @@ static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, struct c
void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode)
{
if (string_is_empty(input))
if (string_is_empty(input)) {
return;
}
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;
}
/* 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.
Note: Global commands must come last in case of duplicate command names */
* try specified mode's commands first, then upon failure try global commands.
*
* Note: Global commands must come last in case of duplicate command names
*/
switch (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;
}
break;
case GROUPCHAT_COMMAND_MODE:
if (do_command(w, self, m, num_args, group_commands, args) == 0)
if (do_command(w, self, m, num_args, group_commands, args) == 0) {
return;
}
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;
}
#ifdef PYTHON
if (do_plugin_command(num_args, args) == 0)
if (do_plugin_command(num_args, args) == 0) {
return;
}
#endif

View File

@ -36,4 +36,4 @@ enum {
void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode);
#endif /* #define EXECUTE_H */
#endif /* EXECUTE_H */

View File

@ -45,8 +45,9 @@ void init_progress_bar(char *progline)
strcpy(progline, "0% [");
int i;
for (i = 0; i < NUM_PROG_MARKS; ++i)
for (i = 0; i < NUM_PROG_MARKS; ++i) {
strcat(progline, "-");
}
strcat(progline, "] 0.0 B/s");
}
@ -54,8 +55,9 @@ void init_progress_bar(char *progline)
/* prints a progress bar for file transfers. */
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;
}
char pct_str[24];
snprintf(pct_str, sizeof(pct_str), "%.1f%%", pct_done);
@ -67,14 +69,17 @@ void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t l
int n = pct_done / (100 / NUM_PROG_MARKS);
int i, j;
for (i = 0; i < n; ++i)
for (i = 0; i < n; ++i) {
strcat(prog_line, "=");
}
if (pct_done < 100)
if (pct_done < 100) {
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, "-");
}
char full_line[strlen(pct_str) + NUM_PROG_MARKS + strlen(bps_str) + 7];
snprintf(full_line, sizeof(full_line), "%s [%s] %s/s", pct_str, prog_line, bps_str);
@ -82,14 +87,16 @@ void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t l
line_info_set(self, line_id, 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;
}
/* 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;
}
double remain = ft->file_size - ft->position;
double pct_done = remain > 0 ? (1 - (remain / ft->file_size)) * 100 : 100;
@ -100,13 +107,13 @@ static void refresh_progress_helper(ToxWindow *self, Tox *m, struct FileTransfer
}
/* 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 friendnum)
{
size_t i;
for (i = 0; i < MAX_FILES; ++i) {
refresh_progress_helper(self, m, &Friends.list[friendnum].file_receiver[i]);
refresh_progress_helper(self, m, &Friends.list[friendnum].file_sender[i]);
refresh_progress_helper(self, &Friends.list[friendnum].file_receiver[i]);
refresh_progress_helper(self, &Friends.list[friendnum].file_sender[i]);
}
}
@ -120,13 +127,15 @@ struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filen
for (i = 0; i < MAX_FILES; ++i) {
struct FileTransfer *ft_send = &Friends.list[friendnum].file_sender[i];
if (ft_send->state != FILE_TRANSFER_INACTIVE && ft_send->filenum == filenum)
if (ft_send->state != FILE_TRANSFER_INACTIVE && ft_send->filenum == filenum) {
return ft_send;
}
struct FileTransfer *ft_recv = &Friends.list[friendnum].file_receiver[i];
if (ft_recv->state != FILE_TRANSFER_INACTIVE && ft_recv->filenum == filenum)
if (ft_recv->state != FILE_TRANSFER_INACTIVE && ft_recv->filenum == filenum) {
return ft_recv;
}
}
return NULL;
@ -138,8 +147,9 @@ struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filen
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t index,
FILE_TRANSFER_DIRECTION direction)
{
if (direction != FILE_TRANSFER_RECV && direction != FILE_TRANSFER_SEND)
if (direction != FILE_TRANSFER_RECV && direction != FILE_TRANSFER_SEND) {
return NULL;
}
size_t i;
@ -148,8 +158,9 @@ struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t
&Friends.list[friendnum].file_sender[i] :
&Friends.list[friendnum].file_receiver[i];
if (ft->state != FILE_TRANSFER_INACTIVE && ft->index == index)
if (ft->state != FILE_TRANSFER_INACTIVE && ft->index == index) {
return ft;
}
}
return NULL;
@ -215,11 +226,13 @@ static struct FileTransfer *new_file_receiver(ToxWindow *window, uint32_t friend
struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnum, uint32_t filenum,
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);
}
if (direction == FILE_TRANSFER_SEND)
if (direction == FILE_TRANSFER_SEND) {
return new_file_sender(window, friendnum, filenum, type);
}
return NULL;
}
@ -233,23 +246,28 @@ struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnum, ui
void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int CTRL, const char *message,
Notification sound_type)
{
if (!ft)
if (!ft) {
return;
}
if (ft->state == FILE_TRANSFER_INACTIVE)
if (ft->state == FILE_TRANSFER_INACTIVE) {
return;
}
if (ft->file)
if (ft->file) {
fclose(ft->file);
}
if (CTRL >= 0)
tox_file_control(m, ft->friendnum, ft->filenum, (TOX_FILE_CONTROL) CTRL, NULL);
if (CTRL >= 0) {
tox_file_control(m, ft->friendnum, ft->filenum, (Tox_File_Control) CTRL, NULL);
}
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);
else
} else {
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);
}
@ -272,6 +290,7 @@ void kill_all_file_transfers(Tox *m)
{
size_t i;
for (i = 0; i < Friends.max_idx; ++i)
for (i = 0; i < Friends.max_idx; ++i) {
kill_all_file_transfers_friend(m, Friends.list[i].num);
}
}

View File

@ -75,7 +75,7 @@ void init_progress_bar(char *progline);
void print_progress_bar(ToxWindow *self, double pct_done, double bps, uint32_t line_id);
/* 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 friendnum);
/* Returns a pointer to friendnum's FileTransfer struct associated with filenum.
* Returns NULL if filenum is invalid.
@ -108,4 +108,4 @@ void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum);
void kill_all_file_transfers(Tox *m);
#endif /* #define FILE_TRANSFERS_H */
#endif /* FILE_TRANSFERS_H */

View File

@ -84,8 +84,9 @@ static void realloc_friends(int n)
ToxicFriend *f = realloc(Friends.list, n * sizeof(ToxicFriend));
uint32_t *f_idx = realloc(Friends.index, n * sizeof(uint32_t));
if (f == NULL || f_idx == NULL)
if (f == NULL || f_idx == NULL) {
exit_toxic_err("failed in realloc_friends", FATALERR_MEMORY);
}
Friends.list = f;
Friends.index = f_idx;
@ -104,24 +105,26 @@ static void realloc_blocklist(int n)
BlockedFriend *b = realloc(Blocked.list, n * sizeof(BlockedFriend));
uint32_t *b_idx = realloc(Blocked.index, n * sizeof(uint32_t));
if (b == NULL || b_idx == NULL)
if (b == NULL || b_idx == NULL) {
exit_toxic_err("failed in realloc_blocklist", FATALERR_MEMORY);
}
Blocked.list = b;
Blocked.index = b_idx;
}
void kill_friendlist(void)
void kill_friendlist(ToxWindow *self)
{
int i;
for (i = 0; i < Friends.max_idx; ++i) {
if (Friends.list[i].active && Friends.list[i].group_invite.key != NULL)
for (size_t i = 0; i < Friends.max_idx; ++i) {
if (Friends.list[i].active && Friends.list[i].group_invite.key != NULL) {
free(Friends.list[i].group_invite.key);
}
}
realloc_blocklist(0);
realloc_friends(0);
free(self->help);
del_window(self);
}
/* Saves the blocklist to path. If there are no items in the blocklist the
@ -215,13 +218,15 @@ static void sort_blocklist_index(void);
int load_blocklist(char *path)
{
if (path == NULL)
if (path == NULL) {
return -1;
}
FILE *fp = fopen(path, "rb");
if (fp == NULL)
if (fp == NULL) {
return -1;
}
off_t len = file_size(path);
@ -298,11 +303,14 @@ void sort_friendlist_index(void)
uint32_t n = 0;
for (i = 0; i < Friends.max_idx; ++i) {
if (Friends.list[i].active)
if (Friends.list[i].active) {
Friends.index[n++] = Friends.list[i].num;
}
}
qsort(Friends.index, Friends.num_friends, sizeof(uint32_t), index_name_cmp);
if (Friends.num_friends > 0) {
qsort(Friends.index, Friends.num_friends, sizeof(uint32_t), index_name_cmp);
}
}
static int index_name_cmp_block(const void *n1, const void *n2)
@ -316,8 +324,9 @@ static void sort_blocklist_index(void)
uint32_t n = 0;
for (i = 0; i < Blocked.max_idx; ++i) {
if (Blocked.list[i].active)
if (Blocked.list[i].active) {
Blocked.index[n++] = Blocked.list[i].num;
}
}
qsort(Blocked.index, Blocked.num_blocked, sizeof(uint32_t), index_name_cmp_block);
@ -334,14 +343,20 @@ static void update_friend_last_online(uint32_t num, time_t timestamp)
&Friends.list[num].last_online.tm);
}
static void friendlist_onMessage(ToxWindow *self, Tox *m, uint32_t num, TOX_MESSAGE_TYPE type, const char *str,
static void friendlist_onMessage(ToxWindow *self, Tox *m, uint32_t num, Tox_Message_Type type, const char *str,
size_t length)
{
if (num >= Friends.max_idx)
return;
UNUSED_VAR(self);
UNUSED_VAR(type);
UNUSED_VAR(length);
if (Friends.list[num].chatwin != -1)
if (num >= Friends.max_idx) {
return;
}
if (Friends.list[num].chatwin != -1) {
return;
}
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
@ -359,18 +374,22 @@ static void friendlist_onMessage(ToxWindow *self, Tox *m, uint32_t num, TOX_MESS
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
}
static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_CONNECTION connection_status)
static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, Tox_Connection connection_status)
{
if (num >= Friends.max_idx)
UNUSED_VAR(self);
if (num >= Friends.max_idx) {
return;
}
if (connection_status == TOX_CONNECTION_NONE) {
--Friends.num_online;
} else if (Friends.list[num].connection_status == TOX_CONNECTION_NONE) {
++Friends.num_online;
if (avatar_send(m, num) == -1)
if (avatar_send(m, num) == -1) {
fprintf(stderr, "avatar_send failed for friend %d\n", num);
}
}
Friends.list[num].connection_status = connection_status;
@ -381,8 +400,12 @@ static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num,
static void friendlist_onNickChange(ToxWindow *self, Tox *m, uint32_t num, const char *nick, size_t length)
{
if (num >= Friends.max_idx)
UNUSED_VAR(self);
UNUSED_VAR(length);
if (num >= Friends.max_idx) {
return;
}
/* save old name for log renaming */
char oldname[TOXIC_MAX_NAME_LENGTH + 1];
@ -398,24 +421,32 @@ static void friendlist_onNickChange(ToxWindow *self, Tox *m, uint32_t num, const
strcpy(newnamecpy, Friends.list[num].name);
tox_self_get_address(m, (uint8_t *) myid);
if (strcmp(oldname, newnamecpy) != 0)
if (strcmp(oldname, newnamecpy) != 0) {
rename_logfile(oldname, newnamecpy, myid, Friends.list[num].pub_key, Friends.list[num].chatwin);
}
sort_friendlist_index();
}
static void friendlist_onStatusChange(ToxWindow *self, Tox *m, uint32_t num, TOX_USER_STATUS status)
static void friendlist_onStatusChange(ToxWindow *self, Tox *m, uint32_t num, Tox_User_Status status)
{
if (num >= Friends.max_idx)
UNUSED_VAR(self);
UNUSED_VAR(m);
if (num >= Friends.max_idx) {
return;
}
Friends.list[num].status = status;
}
static void friendlist_onStatusMessageChange(ToxWindow *self, uint32_t num, const char *note, size_t length)
{
if (length > TOX_MAX_STATUS_MESSAGE_LENGTH || num >= Friends.max_idx)
UNUSED_VAR(self);
if (length > TOX_MAX_STATUS_MESSAGE_LENGTH || num >= Friends.max_idx) {
return;
}
snprintf(Friends.list[num].statusmsg, sizeof(Friends.list[num].statusmsg), "%s", note);
Friends.list[num].statusmsg_len = strlen(Friends.list[num].statusmsg);
@ -423,14 +454,17 @@ static void friendlist_onStatusMessageChange(ToxWindow *self, uint32_t num, cons
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort)
{
UNUSED_VAR(self);
realloc_friends(Friends.max_idx + 1);
memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend));
uint32_t i;
for (i = 0; i <= Friends.max_idx; ++i) {
if (Friends.list[i].active)
if (Friends.list[i].active) {
continue;
}
++Friends.num_friends;
@ -441,17 +475,19 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort)
Friends.list[i].status = TOX_USER_STATUS_NONE;
Friends.list[i].logging_on = (bool) user_settings->autolog == AUTOLOG_ON;
TOX_ERR_FRIEND_GET_PUBLIC_KEY pkerr;
Tox_Err_Friend_Get_Public_Key pkerr;
tox_friend_get_public_key(m, num, (uint8_t *) Friends.list[i].pub_key, &pkerr);
if (pkerr != TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK)
if (pkerr != TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK) {
fprintf(stderr, "tox_friend_get_public_key failed (error %d)\n", pkerr);
}
TOX_ERR_FRIEND_GET_LAST_ONLINE loerr;
Tox_Err_Friend_Get_Last_Online loerr;
time_t t = tox_friend_get_last_online(m, num, &loerr);
if (loerr != TOX_ERR_FRIEND_GET_LAST_ONLINE_OK)
if (loerr != TOX_ERR_FRIEND_GET_LAST_ONLINE_OK) {
t = 0;
}
update_friend_last_online(i, t);
@ -460,11 +496,13 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort)
snprintf(Friends.list[i].name, sizeof(Friends.list[i].name), "%s", tempname);
Friends.list[i].namelength = strlen(Friends.list[i].name);
if (i == Friends.max_idx)
if (i == Friends.max_idx) {
++Friends.max_idx;
}
if (sort)
if (sort) {
sort_friendlist_index();
}
#ifdef AUDIO
init_friend_AV(i);
@ -474,8 +512,8 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort)
}
}
/* puts blocked friend back in friendlist. fnum is new friend number, bnum is blocked number */
static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum)
/* Puts blocked friend back in friendlist. fnum is new friend number, bnum is blocked number. */
static void friendlist_add_blocked(uint32_t fnum, uint32_t bnum)
{
realloc_friends(Friends.max_idx + 1);
memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend));
@ -483,8 +521,9 @@ static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum)
int i;
for (i = 0; i <= Friends.max_idx; ++i) {
if (Friends.list[i].active)
if (Friends.list[i].active) {
continue;
}
++Friends.num_friends;
@ -498,12 +537,16 @@ static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum)
memcpy(Friends.list[i].name, Blocked.list[bnum].name, Friends.list[i].namelength + 1);
memcpy(Friends.list[i].pub_key, Blocked.list[bnum].pub_key, TOX_PUBLIC_KEY_SIZE);
if (i == Friends.max_idx)
if (i == Friends.max_idx) {
++Friends.max_idx;
}
sort_blocklist_index();
sort_friendlist_index();
#ifdef AUDIO
init_friend_AV(i);
#endif
return;
}
}
@ -511,11 +554,18 @@ static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum)
static void friendlist_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum,
uint64_t file_size, const char *filename, size_t name_length)
{
if (num >= Friends.max_idx)
return;
UNUSED_VAR(self);
UNUSED_VAR(file_size);
UNUSED_VAR(filename);
UNUSED_VAR(name_length);
if (Friends.list[num].chatwin != -1)
if (num >= Friends.max_idx) {
return;
}
if (Friends.list[num].chatwin != -1) {
return;
}
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
@ -536,11 +586,18 @@ static void friendlist_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_
static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, uint8_t type, const char *group_pub_key,
uint16_t length)
{
if (num >= Friends.max_idx)
return;
UNUSED_VAR(self);
UNUSED_VAR(type);
UNUSED_VAR(group_pub_key);
UNUSED_VAR(length);
if (Friends.list[num].chatwin != -1)
if (num >= Friends.max_idx) {
return;
}
if (Friends.list[num].chatwin != -1) {
return;
}
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
@ -557,14 +614,16 @@ static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, uint8
}
/* move friendlist/blocklist cursor up and down */
static void select_friend(ToxWindow *self, wint_t key, int *selected, int num)
static void select_friend(wint_t key, int *selected, int num)
{
if (num <= 0)
if (num <= 0) {
return;
}
if (key == KEY_UP) {
if (--(*selected) < 0)
if (--(*selected) < 0) {
*selected = num - 1;
}
} else if (key == KEY_DOWN) {
*selected = (*selected + 1) % num;
}
@ -572,7 +631,7 @@ static void select_friend(ToxWindow *self, wint_t key, int *selected, int num)
static void delete_friend(Tox *m, uint32_t f_num)
{
TOX_ERR_FRIEND_DELETE err;
Tox_Err_Friend_Delete err;
if (tox_friend_delete(m, f_num, &err) != true) {
fprintf(stderr, "tox_friend_delete failed with error %d\n", err);
@ -581,8 +640,9 @@ static void delete_friend(Tox *m, uint32_t f_num)
--Friends.num_friends;
if (Friends.list[f_num].connection_status != TOX_CONNECTION_NONE)
if (Friends.list[f_num].connection_status != TOX_CONNECTION_NONE) {
--Friends.num_online;
}
/* close friend's chatwindow if it's currently open */
if (Friends.list[f_num].chatwin >= 0) {
@ -590,20 +650,22 @@ static void delete_friend(Tox *m, uint32_t f_num)
if (toxwin != NULL) {
kill_chat_window(toxwin, m);
set_active_window(1); /* keep friendlist focused */
set_active_window_index(1); /* keep friendlist focused */
}
}
if (Friends.list[f_num].group_invite.key != NULL)
if (Friends.list[f_num].group_invite.key != NULL) {
free(Friends.list[f_num].group_invite.key);
}
memset(&Friends.list[f_num], 0, sizeof(ToxicFriend));
int i;
for (i = Friends.max_idx; i > 0; --i) {
if (Friends.list[i - 1].active)
if (Friends.list[i - 1].active) {
break;
}
}
Friends.max_idx = i;
@ -614,14 +676,15 @@ static void delete_friend(Tox *m, uint32_t f_num)
#endif
/* make sure num_selected stays within Friends.num_friends range */
if (Friends.num_friends && Friends.num_selected == Friends.num_friends)
if (Friends.num_friends && Friends.num_selected == Friends.num_friends) {
--Friends.num_selected;
}
store_data(m, DATA_FILE);
}
/* activates delete friend popup */
static void del_friend_activate(ToxWindow *self, Tox *m, uint32_t f_num)
static void del_friend_activate(uint32_t f_num)
{
PendingDelete.popup = newwin(3, 22 + TOXIC_MAX_NAME_LENGTH, 8, 8);
PendingDelete.active = true;
@ -631,7 +694,7 @@ static void del_friend_activate(ToxWindow *self, Tox *m, uint32_t f_num)
static void delete_blocked_friend(uint32_t bnum);
/* deactivates delete friend popup and deletes friend if instructed */
static void del_friend_deactivate(ToxWindow *self, Tox *m, wint_t key)
static void del_friend_deactivate(Tox *m, wint_t key)
{
if (key == 'y') {
if (blocklist_view == 0) {
@ -651,8 +714,9 @@ static void del_friend_deactivate(ToxWindow *self, Tox *m, wint_t key)
static void draw_del_popup(void)
{
if (!PendingDelete.active)
if (!PendingDelete.active) {
return;
}
wattron(PendingDelete.popup, A_BOLD);
box(PendingDelete.popup, ACS_VLINE, ACS_HLINE);
@ -664,10 +728,11 @@ static void draw_del_popup(void)
pthread_mutex_lock(&Winthread.lock);
if (blocklist_view == 0)
if (blocklist_view == 0) {
wprintw(PendingDelete.popup, "%s", Friends.list[PendingDelete.num].name);
else
} else {
wprintw(PendingDelete.popup, "%s", Blocked.list[PendingDelete.num].name);
}
pthread_mutex_unlock(&Winthread.lock);
@ -685,8 +750,9 @@ static void delete_blocked_friend(uint32_t bnum)
int i;
for (i = Blocked.max_idx; i > 0; --i) {
if (Blocked.list[i - 1].active)
if (Blocked.list[i - 1].active) {
break;
}
}
--Blocked.num_blocked;
@ -694,15 +760,17 @@ static void delete_blocked_friend(uint32_t bnum)
realloc_blocklist(i);
save_blocklist(BLOCK_FILE);
if (Blocked.num_blocked && Blocked.num_selected == Blocked.num_blocked)
if (Blocked.num_blocked && Blocked.num_selected == Blocked.num_blocked) {
--Blocked.num_selected;
}
}
/* deletes contact from friendlist and puts in blocklist */
void block_friend(Tox *m, uint32_t fnum)
{
if (Friends.num_friends <= 0)
if (Friends.num_friends <= 0) {
return;
}
realloc_blocklist(Blocked.max_idx + 1);
memset(&Blocked.list[Blocked.max_idx], 0, sizeof(BlockedFriend));
@ -710,8 +778,9 @@ void block_friend(Tox *m, uint32_t fnum)
int i;
for (i = 0; i <= Blocked.max_idx; ++i) {
if (Blocked.list[i].active)
if (Blocked.list[i].active) {
continue;
}
Blocked.list[i].active = true;
Blocked.list[i].num = i;
@ -722,8 +791,9 @@ void block_friend(Tox *m, uint32_t fnum)
++Blocked.num_blocked;
if (i == Blocked.max_idx)
if (i == Blocked.max_idx) {
++Blocked.max_idx;
}
delete_friend(m, fnum);
save_blocklist(BLOCK_FILE);
@ -737,10 +807,11 @@ void block_friend(Tox *m, uint32_t fnum)
/* removes friend from blocklist, puts back in friendlist */
static void unblock_friend(Tox *m, uint32_t bnum)
{
if (Blocked.num_blocked <= 0)
if (Blocked.num_blocked <= 0) {
return;
}
TOX_ERR_FRIEND_ADD err;
Tox_Err_Friend_Add err;
uint32_t friendnum = tox_friend_add_norequest(m, (uint8_t *) Blocked.list[bnum].pub_key, &err);
if (err != TOX_ERR_FRIEND_ADD_OK) {
@ -748,60 +819,69 @@ static void unblock_friend(Tox *m, uint32_t bnum)
return;
}
friendlist_add_blocked(m, friendnum, bnum);
friendlist_add_blocked(friendnum, bnum);
delete_blocked_friend(bnum);
sort_blocklist_index();
sort_friendlist_index();
}
static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
/*
* Return true if input is recognized by handler
*/
static bool friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
{
if (self->help->active) {
help_onKey(self, key);
return;
return true;
}
if (key == 'h') {
help_init_menu(self);
return;
return true;
}
if (!blocklist_view && !Friends.num_friends && (key != KEY_RIGHT && key != KEY_LEFT))
return;
if (!blocklist_view && !Friends.num_friends && (key != KEY_RIGHT && key != KEY_LEFT)) {
return true;
}
if (blocklist_view && !Blocked.num_blocked && (key != KEY_RIGHT && key != KEY_LEFT))
return;
if (blocklist_view && !Blocked.num_blocked && (key != KEY_RIGHT && key != KEY_LEFT)) {
return true;
}
int f = 0;
if (blocklist_view == 1 && Blocked.num_blocked)
if (blocklist_view == 1 && Blocked.num_blocked) {
f = Blocked.index[Blocked.num_selected];
else if (Friends.num_friends)
} else if (Friends.num_friends) {
f = Friends.index[Friends.num_selected];
}
/* lock screen and force decision on deletion popup */
if (PendingDelete.active) {
if (key == 'y' || key == 'n')
del_friend_deactivate(self, m, key);
if (key == 'y' || key == 'n') {
del_friend_deactivate(m, key);
}
return;
return true;
}
if (key == ltr)
return;
if (key == ltr) {
return true;
}
switch (key) {
case '\r':
if (blocklist_view)
if (blocklist_view) {
break;
}
/* Jump to chat window if already open */
if (Friends.list[f].chatwin != -1) {
set_active_window(Friends.list[f].chatwin);
set_active_window_index(Friends.list[f].chatwin);
} else if (get_num_active_windows() < MAX_WINDOWS_NUM) {
Friends.list[f].chatwin = add_window(m, new_chat(m, Friends.list[f].num));
set_active_window(Friends.list[f].chatwin);
set_active_window_index(Friends.list[f].chatwin);
} else {
const char *msg = "* Warning: Too many windows are open.";
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, msg);
@ -811,14 +891,15 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
break;
case KEY_DC:
del_friend_activate(self, m, f);
del_friend_activate(f);
break;
case 'b':
if (!blocklist_view)
if (!blocklist_view) {
block_friend(m, f);
else
} else {
unblock_friend(m, f);
}
break;
@ -828,26 +909,32 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
break;
default:
if (blocklist_view == 0)
select_friend(self, key, &Friends.num_selected, Friends.num_friends);
else
select_friend(self, key, &Blocked.num_selected, Blocked.num_blocked);
if (blocklist_view == 0) {
select_friend(key, &Friends.num_selected, Friends.num_friends);
} else {
select_friend(key, &Blocked.num_selected, Blocked.num_blocked);
}
break;
}
return true;
}
#define FLIST_OFST 6 /* Accounts for space at top and bottom */
static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2)
{
UNUSED_VAR(m);
wattron(self->window, A_BOLD);
wprintw(self->window, " Blocked: ");
wattroff(self->window, A_BOLD);
wprintw(self->window, "%d\n\n", Blocked.num_blocked);
if ((y2 - FLIST_OFST) <= 0)
if ((y2 - FLIST_OFST) <= 0) {
return;
}
uint32_t selected_num = 0;
@ -876,15 +963,17 @@ static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2)
wprintw(self->window, "x");
wattroff(self->window, COLOR_PAIR(RED));
if (f_selected)
if (f_selected) {
wattron(self->window, COLOR_PAIR(BLUE));
}
wattron(self->window, A_BOLD);
wprintw(self->window, " %s\n", Blocked.list[f].name);
wattroff(self->window, A_BOLD);
if (f_selected)
if (f_selected) {
wattroff(self->window, COLOR_PAIR(BLUE));
}
}
wprintw(self->window, "\n");
@ -899,15 +988,17 @@ static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2)
int i;
for (i = 0; i < TOX_PUBLIC_KEY_SIZE; ++i)
for (i = 0; i < TOX_PUBLIC_KEY_SIZE; ++i) {
wprintw(self->window, "%02X", Blocked.list[selected_num].pub_key[i] & 0xff);
}
}
wnoutrefresh(self->window);
draw_del_popup();
if (self->help->active)
if (self->help->active) {
help_onDraw(self);
}
}
static void friendlist_onDraw(ToxWindow *self, Tox *m)
@ -941,8 +1032,9 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
wprintw(self->window, "%d/%d \n\n", Friends.num_online, Friends.num_friends);
if ((y2 - FLIST_OFST) <= 0)
if ((y2 - FLIST_OFST) <= 0) {
return;
}
uint32_t selected_num = 0;
@ -981,8 +1073,8 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
}
pthread_mutex_lock(&Winthread.lock);
TOX_CONNECTION connection_status = Friends.list[f].connection_status;
TOX_USER_STATUS status = Friends.list[f].status;
Tox_Connection connection_status = Friends.list[f].connection_status;
Tox_User_Status status = Friends.list[f].status;
pthread_mutex_unlock(&Winthread.lock);
if (connection_status != TOX_CONNECTION_NONE) {
@ -1006,8 +1098,9 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
wprintw(self->window, "%s ", ONLINE_CHAR);
wattroff(self->window, COLOR_PAIR(colour) | A_BOLD);
if (f_selected)
if (f_selected) {
wattron(self->window, COLOR_PAIR(BLUE));
}
wattron(self->window, A_BOLD);
pthread_mutex_lock(&Winthread.lock);
@ -1015,8 +1108,9 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
pthread_mutex_unlock(&Winthread.lock);
wattroff(self->window, A_BOLD);
if (f_selected)
if (f_selected) {
wattroff(self->window, COLOR_PAIR(BLUE));
}
/* Reset Friends.list[f].statusmsg on window resize */
if (fix_statuses) {
@ -1049,8 +1143,9 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
Friends.list[f].statusmsg_len = maxlen;
}
if (Friends.list[f].statusmsg_len > 0)
if (Friends.list[f].statusmsg_len > 0) {
wprintw(self->window, " %s", Friends.list[f].statusmsg);
}
pthread_mutex_unlock(&Winthread.lock);
@ -1058,8 +1153,9 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
} else {
wprintw(self->window, "%s ", OFFLINE_CHAR);
if (f_selected)
if (f_selected) {
wattron(self->window, COLOR_PAIR(BLUE));
}
wattron(self->window, A_BOLD);
pthread_mutex_lock(&Winthread.lock);
@ -1067,8 +1163,9 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
pthread_mutex_unlock(&Winthread.lock);
wattroff(self->window, A_BOLD);
if (f_selected)
if (f_selected) {
wattroff(self->window, COLOR_PAIR(BLUE));
}
pthread_mutex_lock(&Winthread.lock);
time_t last_seen = Friends.list[f].last_online.last_on;
@ -1116,15 +1213,17 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
int i;
for (i = 0; i < TOX_PUBLIC_KEY_SIZE; ++i)
for (i = 0; i < TOX_PUBLIC_KEY_SIZE; ++i) {
wprintw(self->window, "%02X", Friends.list[selected_num].pub_key[i] & 0xff);
}
}
wnoutrefresh(self->window);
draw_del_popup();
if (self->help->active)
if (self->help->active) {
help_onDraw(self);
}
}
void disable_chatwin(uint32_t f_num)
@ -1135,19 +1234,19 @@ void disable_chatwin(uint32_t f_num)
#ifdef AUDIO
static void friendlist_onAV(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
{
assert(0);
UNUSED_VAR(self);
if ( friend_number >= Friends.max_idx)
if (friend_number >= Friends.max_idx) {
return;
}
assert(0);
Tox *m = toxav_get_tox(av);
if (Friends.list[friend_number].chatwin == -1) {
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
if (state != TOXAV_FRIEND_CALL_STATE_FINISHED) {
Friends.list[friend_number].chatwin = add_window(m, new_chat(m, Friends.list[friend_number].num));
set_active_window(Friends.list[friend_number].chatwin);
set_active_window_index(Friends.list[friend_number].chatwin);
}
} else {
char nick[TOX_MAX_NAME_LENGTH];
@ -1164,60 +1263,83 @@ static void friendlist_onAV(ToxWindow *self, ToxAV *av, uint32_t friend_number,
#endif /* AUDIO */
/* Returns a friend's status */
TOX_USER_STATUS get_friend_status(uint32_t friendnumber)
Tox_User_Status get_friend_status(uint32_t friendnumber)
{
return Friends.list[friendnumber].status;
}
/* Returns a friend's connection status */
TOX_CONNECTION get_friend_connection_status(uint32_t friendnumber)
Tox_Connection get_friend_connection_status(uint32_t friendnumber)
{
return Friends.list[friendnumber].connection_status;
}
ToxWindow new_friendlist(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)
{
ToxWindow ret;
memset(&ret, 0, sizeof(ret));
for (size_t i = 0; i < Blocked.max_idx; ++i) {
if (!Blocked.list[i].active) {
continue;
}
ret.active = true;
ret.is_friendlist = true;
if (memcmp(public_key, Blocked.list[i].pub_key, TOX_PUBLIC_KEY_SIZE) == 0) {
return true;
}
}
ret.onKey = &friendlist_onKey;
ret.onDraw = &friendlist_onDraw;
ret.onFriendAdded = &friendlist_onFriendAdded;
ret.onMessage = &friendlist_onMessage;
ret.onConnectionChange = &friendlist_onConnectionChange;
ret.onNickChange = &friendlist_onNickChange;
ret.onStatusChange = &friendlist_onStatusChange;
ret.onStatusMessageChange = &friendlist_onStatusMessageChange;
ret.onFileRecv = &friendlist_onFileRecv;
ret.onGroupInvite = &friendlist_onGroupInvite;
return false;
}
ToxWindow *new_friendlist(void)
{
ToxWindow *ret = calloc(1, sizeof(ToxWindow));
if (ret == NULL) {
exit_toxic_err("failed in new_friendlist", FATALERR_MEMORY);
}
ret->is_friendlist = true;
ret->onKey = &friendlist_onKey;
ret->onDraw = &friendlist_onDraw;
ret->onFriendAdded = &friendlist_onFriendAdded;
ret->onMessage = &friendlist_onMessage;
ret->onConnectionChange = &friendlist_onConnectionChange;
ret->onNickChange = &friendlist_onNickChange;
ret->onStatusChange = &friendlist_onStatusChange;
ret->onStatusMessageChange = &friendlist_onStatusMessageChange;
ret->onFileRecv = &friendlist_onFileRecv;
ret->onGroupInvite = &friendlist_onGroupInvite;
#ifdef AUDIO
ret.onInvite = &friendlist_onAV;
ret.onRinging = &friendlist_onAV;
ret.onStarting = &friendlist_onAV;
ret.onEnding = &friendlist_onAV;
ret.onError = &friendlist_onAV;
ret.onStart = &friendlist_onAV;
ret.onCancel = &friendlist_onAV;
ret.onReject = &friendlist_onAV;
ret.onEnd = &friendlist_onAV;
ret->onInvite = &friendlist_onAV;
ret->onRinging = &friendlist_onAV;
ret->onStarting = &friendlist_onAV;
ret->onEnding = &friendlist_onAV;
ret->onError = &friendlist_onAV;
ret->onStart = &friendlist_onAV;
ret->onCancel = &friendlist_onAV;
ret->onReject = &friendlist_onAV;
ret->onEnd = &friendlist_onAV;
ret.is_call = false;
ret.device_selection[0] = ret.device_selection[1] = -1;
ret->is_call = false;
ret->device_selection[0] = ret->device_selection[1] = -1;
#endif /* AUDIO */
ret.num = -1;
ret.active_box = -1;
ret->num = -1;
ret->active_box = -1;
Help *help = calloc(1, sizeof(Help));
if (help == NULL)
if (help == NULL) {
exit_toxic_err("failed in new_friendlist", FATALERR_MEMORY);
}
ret.help = help;
strcpy(ret.name, "contacts");
ret->help = help;
strcpy(ret->name, "contacts");
return ret;
}

View File

@ -51,10 +51,10 @@ typedef struct {
uint32_t num;
int chatwin;
bool active;
TOX_CONNECTION connection_status;
Tox_Connection connection_status;
bool is_typing;
bool logging_on; /* saves preference for friend irrespective of global settings */
TOX_USER_STATUS status;
Tox_User_Status status;
struct LastOnline last_online;
struct GroupChatInvite group_invite;
@ -81,16 +81,23 @@ typedef struct {
ToxicFriend *list;
} FriendsList;
ToxWindow new_friendlist(void);
ToxWindow *new_friendlist(void);
void disable_chatwin(uint32_t f_num);
int get_friendnum(uint8_t *name);
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);
TOX_USER_STATUS get_friend_status(uint32_t friendnumber);
TOX_CONNECTION get_friend_connection_status(uint32_t friendnumber);
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 */
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 */

View File

@ -41,11 +41,12 @@
extern char *DATA_FILE;
extern ToxWindow *prompt;
extern FriendsList Friends;
extern FriendRequests FrndRequests;
/* command functions */
void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Request ID required.");
return;
@ -63,7 +64,7 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
return;
}
TOX_ERR_FRIEND_ADD err;
Tox_Err_Friend_Add err;
uint32_t friendnum = tox_friend_add_norequest(m, FrndRequests.request[req].key, &err);
if (err != TOX_ERR_FRIEND_ADD_OK) {
@ -71,7 +72,7 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
return;
} else {
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));
@ -79,8 +80,9 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
int i;
for (i = FrndRequests.max_idx; i > 0; --i) {
if (FrndRequests.request[i - 1].active)
if (FrndRequests.request[i - 1].active) {
break;
}
}
FrndRequests.max_idx = i;
@ -92,8 +94,8 @@ void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg
{
const char *errmsg;
TOX_ERR_FRIEND_ADD err;
uint32_t f_num = tox_friend_add(m, (uint8_t *) id_bin, (uint8_t *) msg, strlen(msg), &err);
Tox_Err_Friend_Add err;
uint32_t f_num = tox_friend_add(m, (const uint8_t *) id_bin, (const uint8_t *) msg, strlen(msg), &err);
switch (err) {
case TOX_ERR_FRIEND_ADD_TOO_LONG:
@ -126,14 +128,14 @@ void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg
case TOX_ERR_FRIEND_ADD_OK:
errmsg = "Friend request sent.";
on_friendadded(m, f_num, true);
on_friend_added(m, f_num, true);
break;
case TOX_ERR_FRIEND_ADD_NULL:
/* fallthrough */
default:
errmsg = "Faile to add friend: Unknown error.";
errmsg = "Failed to add friend: Unknown error.";
break;
}
@ -142,6 +144,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])
{
UNUSED_VAR(window);
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Tox ID or address required.");
return;
@ -193,6 +197,11 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
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);
} else { /* assume id is a username@domain address and do http name server lookup */
name_lookup(self, m, id_bin, id, msg);
@ -201,21 +210,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])
{
if (argc < 2 || strlen(argv[1]) < 3) {
UNUSED_VAR(window);
if (argc != 1 || strlen(argv[1]) < 3) {
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;
}
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];
snprintf(path, sizeof(path), "%s", &argv[1][1]);
int len = strlen(path) - 1;
snprintf(path, sizeof(path), "%s", argv[1]);
int len = strlen(path);
if (len <= 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid path.");
@ -238,12 +243,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])
{
UNUSED_VAR(m);
UNUSED_VAR(argc);
UNUSED_VAR(argv);
line_info_clear(self->chatwin->hst);
force_refresh(window);
}
void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
if (argc != 3) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Require: <ip> <port> <key>");
return;
@ -267,7 +278,7 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
return;
}
TOX_ERR_BOOTSTRAP err;
Tox_Err_Bootstrap err;
tox_bootstrap(m, ip, port, (uint8_t *) key_binary, &err);
tox_add_tcp_relay(m, ip, port, (uint8_t *) key_binary, &err);
@ -291,6 +302,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])
{
UNUSED_VAR(window);
UNUSED_VAR(m);
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Request ID required.");
return;
@ -313,8 +327,9 @@ void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
int i;
for (i = FrndRequests.max_idx; i > 0; --i) {
if (FrndRequests.request[i - 1].active)
if (FrndRequests.request[i - 1].active) {
break;
}
}
FrndRequests.max_idx = i;
@ -323,6 +338,8 @@ void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
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.");
return;
@ -335,11 +352,11 @@ void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
uint8_t type;
if (!strcasecmp(argv[1], "audio"))
if (!strcasecmp(argv[1], "audio")) {
type = TOX_CONFERENCE_TYPE_AV;
else if (!strcasecmp(argv[1], "text"))
} else if (!strcasecmp(argv[1], "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");
return;
}
@ -349,7 +366,7 @@ void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
return;
}
TOX_ERR_CONFERENCE_NEW err;
Tox_Err_Conference_New err;
uint32_t groupnum = tox_conference_new(m, &err);
@ -358,7 +375,7 @@ void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
return;
}
if (init_groupchat_win(prompt, m, groupnum, type) == -1) {
if (init_groupchat_win(m, groupnum, type, NULL, 0) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
tox_conference_delete(m, groupnum, NULL);
return;
@ -369,14 +386,17 @@ void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
const char *msg;
struct chatlog *log = self->chatwin->log;
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)";
else
} else {
msg = "Logging for this window is OFF; type \"/log on\" to enable.";
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
return;
@ -403,8 +423,9 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
return;
} else if (!strcmp(swch, "0") || !strcmp(swch, "off")) {
if (self->is_chat)
if (self->is_chat) {
Friends.list[self->num].logging_on = false;
}
log_disable(log);
@ -419,6 +440,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])
{
UNUSED_VAR(window);
UNUSED_VAR(argc);
UNUSED_VAR(argv);
char id_string[TOX_ADDRESS_SIZE * 2 + 1];
char bin_id[TOX_ADDRESS_SIZE];
tox_self_get_address(m, (uint8_t *) bin_id);
@ -431,8 +456,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);
}
#ifdef QRCODE
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 bin_id[TOX_ADDRESS_SIZE];
tox_self_get_address(m, (uint8_t *) bin_id);
@ -488,25 +516,20 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
#endif /* QRPNG */
}
#endif /* QRCODE */
void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Input required.");
return;
}
char nick[MAX_STR_SIZE];
size_t len = 0;
if (argv[1][0] == '\"') { /* remove opening and closing quotes */
snprintf(nick, sizeof(nick), "%s", &argv[1][1]);
len = strlen(nick) - 1;
nick[len] = '\0';
} else {
snprintf(nick, sizeof(nick), "%s", argv[1]);
len = strlen(nick);
}
snprintf(nick, sizeof(nick), "%s", argv[1]);
size_t len = strlen(nick);
if (!valid_nick(nick)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid name.");
@ -524,24 +547,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])
{
UNUSED_VAR(window);
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Input required.");
return;
}
if (argv[1][0] != '\"') {
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);
prompt_update_statusmessage(prompt, m, argv[1]);
}
void cmd_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
@ -571,16 +584,31 @@ void cmd_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
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);
}
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);
}
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) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend requests.");
return;
@ -590,8 +618,9 @@ void cmd_requests(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
int count = 0;
for (i = 0; i < FrndRequests.max_idx; ++i) {
if (!FrndRequests.request[i].active)
if (!FrndRequests.request[i].active) {
continue;
}
char id[TOX_PUBLIC_KEY_SIZE * 2 + 1] = {0};
@ -604,36 +633,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, "%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, "");
}
}
}
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;
lock_status ();
lock_status();
if (argc >= 2) {
have_note = true;
} else if (argc < 1) {
if (argc < 1) {
errmsg = "Require a status. Statuses are: online, busy and away.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
goto finish;
}
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;
else if (!strcasecmp(status_str, "away"))
} else if (!strcasecmp(status_str, "away")) {
status = TOX_USER_STATUS_AWAY;
else if (!strcasecmp(status_str, "busy"))
} else if (!strcasecmp(status_str, "busy")) {
status = TOX_USER_STATUS_BUSY;
else {
} else {
errmsg = "Invalid status. Valid statuses are: online, busy and away.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
goto finish;
@ -641,25 +670,9 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
tox_self_set_status(m, 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);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Your status has been changed to %s: \"%s\".", status_str, msg);
} else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Your status has been changed to %s.", status_str);
}
finish:
unlock_status ();
unlock_status();
}

View File

@ -35,7 +35,9 @@ void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
void cmd_groupchat(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_log(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]);
#endif /* QRCODE */
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_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
@ -58,6 +60,6 @@ void cmd_change_video_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv
#ifdef PYTHON
void cmd_run(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
#endif
#endif /* PYTHON */
#endif /* #define GLOBAL_COMMANDS_H */
#endif /* GLOBAL_COMMANDS_H */

View File

@ -30,13 +30,15 @@
void cmd_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
TOX_ERR_CONFERENCE_TITLE err;
UNUSED_VAR(window);
Tox_Err_Conference_Title err;
char title[MAX_STR_SIZE];
if (argc < 1) {
size_t tlen = tox_conference_get_title_size(m, self->num, &err);
if (err != TOX_ERR_CONFERENCE_TITLE_OK) {
if (err != TOX_ERR_CONFERENCE_TITLE_OK || tlen >= sizeof(title)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title is not set");
return;
}
@ -52,15 +54,8 @@ void cmd_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
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';
snprintf(title, sizeof(title), "%s", argv[1]);
int len = strlen(title);
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);

View File

@ -28,4 +28,4 @@
void cmd_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
#endif /* GROUP_COMMANDS_H */
#endif /* GROUP_COMMANDS_H */

View File

@ -30,6 +30,7 @@
#include <time.h>
#include <wchar.h>
#include <unistd.h>
#include <inttypes.h>
#ifdef AUDIO
#ifdef __APPLE__
@ -41,9 +42,9 @@
/* compatibility with older versions of OpenAL */
#ifndef ALC_ALL_DEVICES_SPECIFIER
#include <AL/alext.h>
#endif /* ALC_ALL_DEVICES_SPECIFIER */
#endif /* __APPLE__ */
#endif /* AUDIO */
#endif /* ALC_ALL_DEVICES_SPECIFIER */
#endif /* __APPLE__ */
#endif /* AUDIO */
#include "windows.h"
#include "toxic.h"
@ -69,15 +70,17 @@ static int max_groupchat_index = 0;
extern struct user_settings *user_settings;
extern struct Winthread Winthread;
#if defined(AUDIO) && defined(PYTHON)
#define AC_NUM_GROUP_COMMANDS 25
#elif AUDIO
#define AC_NUM_GROUP_COMMANDS 24
#elif PYTHON
#define AC_NUM_GROUP_COMMANDS 21
#ifdef PYTHON
#define AC_NUM_GROUP_COMMANDS_PYTHON 1
#else
#define AC_NUM_GROUP_COMMANDS 20
#endif /* AUDIO */
#define AC_NUM_GROUP_COMMANDS_PYTHON 0
#endif /* PYTHON */
#ifdef QRCODE
#define AC_NUM_GROUP_COMMANDS_QRCODE 1
#else
#define AC_NUM_GROUP_COMMANDS_QRCODE 0
#endif /* QRCODE */
#define AC_NUM_GROUP_COMMANDS (19 + AC_NUM_GROUP_COMMANDS_PYTHON + AC_NUM_GROUP_COMMANDS_QRCODE)
/* Array of groupchat command names used for tab completion. */
static const char group_cmd_list[AC_NUM_GROUP_COMMANDS][MAX_CMDNAME_SIZE] = {
@ -93,7 +96,9 @@ static const char group_cmd_list[AC_NUM_GROUP_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/help" },
{ "/log" },
{ "/myid" },
#ifdef QRCODE
{ "/myqr" },
#endif /* QRCODE */
{ "/nick" },
{ "/note" },
{ "/nospam" },
@ -109,34 +114,7 @@ static const char group_cmd_list[AC_NUM_GROUP_COMMANDS][MAX_CMDNAME_SIZE] = {
#endif /* PYTHON */
};
int init_groupchat_win(ToxWindow *prompt, Tox *m, uint32_t groupnum, uint8_t type)
{
if (groupnum > MAX_GROUPCHAT_NUM) {
return -1;
}
ToxWindow self = new_group_chat(m, groupnum);
int i;
for (i = 0; i <= max_groupchat_index; ++i) {
if (!groupchats[i].active) {
groupchats[i].chatwin = add_window(m, self);
groupchats[i].active = true;
groupchats[i].num_peers = 0;
groupchats[i].type = type;
groupchats[i].start_time = get_unix_time();
set_active_window(groupchats[i].chatwin);
if (i == max_groupchat_index)
++max_groupchat_index;
return 0;
}
}
return -1;
}
static ToxWindow *new_group_chat(uint32_t groupnum);
static void kill_groupchat_window(ToxWindow *self)
{
@ -153,7 +131,40 @@ static void kill_groupchat_window(ToxWindow *self)
del_window(self);
}
void free_groupchat(ToxWindow *self, Tox *m, uint32_t groupnum)
int init_groupchat_win(Tox *m, uint32_t groupnum, uint8_t type, const char *title,
size_t title_length)
{
if (groupnum > MAX_GROUPCHAT_NUM) {
return -1;
}
ToxWindow *self = new_group_chat(groupnum);
for (int 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();
set_active_window_index(groupchats[i].chatwin);
set_window_title(self, title, title_length);
if (i == max_groupchat_index) {
++max_groupchat_index;
}
return 0;
}
}
kill_groupchat_window(self);
return -1;
}
void free_groupchat(ToxWindow *self, uint32_t groupnum)
{
free(groupchats[groupnum].name_list);
free(groupchats[groupnum].peer_list);
@ -162,8 +173,9 @@ void free_groupchat(ToxWindow *self, Tox *m, uint32_t groupnum)
int i;
for (i = max_groupchat_index; i > 0; --i) {
if (groupchats[i - 1].active)
if (groupchats[i - 1].active) {
break;
}
}
max_groupchat_index = i;
@ -173,7 +185,7 @@ void free_groupchat(ToxWindow *self, Tox *m, uint32_t groupnum)
static void delete_groupchat(ToxWindow *self, Tox *m, uint32_t groupnum)
{
tox_conference_delete(m, groupnum, NULL);
free_groupchat(self, m, groupnum);
free_groupchat(self, groupnum);
}
/* destroys and re-creates groupchat window with or without the peerlist */
@ -189,8 +201,9 @@ void redraw_groupchat_win(ToxWindow *self)
getmaxyx(stdscr, y2, x2);
y2 -= 2;
if (y2 <= 0 || x2 <= 0)
if (y2 <= 0 || x2 <= 0) {
return;
}
if (ctx->sidebar) {
delwin(ctx->sidebar);
@ -216,10 +229,13 @@ void redraw_groupchat_win(ToxWindow *self)
}
static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, uint32_t groupnum, uint32_t peernum,
TOX_MESSAGE_TYPE type, const char *msg, size_t len)
Tox_Message_Type type, const char *msg, size_t len)
{
if (self->num != groupnum)
UNUSED_VAR(len);
if (self->num != groupnum) {
return;
}
ChatContext *ctx = self->chatwin;
@ -238,10 +254,11 @@ static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, uint32_t groupnum,
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)
if (self->active_box != -1) {
box_silent_notify2(self, NT_NOFOCUS, self->active_box, "%s %s", nick, msg);
else
} else {
box_silent_notify(self, NT_NOFOCUS, &self->active_box, self->name, "%s %s", nick, msg);
}
nick_clr = RED;
} else {
@ -261,8 +278,9 @@ static void groupchat_onGroupTitleChange(ToxWindow *self, Tox *m, uint32_t group
{
ChatContext *ctx = self->chatwin;
if (self->num != groupnum)
if (self->num != groupnum) {
return;
}
set_window_title(self, title, length);
@ -270,8 +288,9 @@ static void groupchat_onGroupTitleChange(ToxWindow *self, Tox *m, uint32_t group
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))
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);
@ -286,7 +305,7 @@ static void group_update_name_list(uint32_t groupnum)
{
GroupChat *chat = &groupchats[groupnum];
if (!chat) {
if (!chat->active) {
return;
}
@ -344,7 +363,7 @@ static void update_peer_list(Tox *m, uint32_t groupnum, uint32_t num_peers)
{
GroupChat *chat = &groupchats[groupnum];
if (!chat) {
if (!chat->active) {
return;
}
@ -355,7 +374,7 @@ static void update_peer_list(Tox *m, uint32_t groupnum, uint32_t num_peers)
for (i = 0; i < num_peers; ++i) {
GroupPeer *peer = &chat->peer_list[i];
TOX_ERR_CONFERENCE_PEER_QUERY err;
Tox_Err_Conference_Peer_Query err;
size_t length = tox_conference_peer_get_name_size(m, groupnum, i, &err);
if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK || length >= TOX_MAX_NAME_LENGTH) {
@ -379,14 +398,21 @@ static void update_peer_list(Tox *m, uint32_t groupnum, uint32_t num_peers)
static void groupchat_onGroupNameListChange(ToxWindow *self, Tox *m, uint32_t groupnum)
{
if (self->num != groupnum)
if (self->num != groupnum) {
return;
}
if (groupnum > max_groupchat_index)
if (groupnum > max_groupchat_index) {
return;
}
GroupChat *chat = &groupchats[groupnum];
TOX_ERR_CONFERENCE_PEER_QUERY err;
if (!chat->active) {
return;
}
Tox_Err_Conference_Peer_Query err;
uint32_t num_peers = tox_conference_peer_count(m, groupnum, &err);
uint32_t old_num = chat->num_peers;
@ -402,34 +428,36 @@ static void groupchat_onGroupNameListChange(ToxWindow *self, Tox *m, uint32_t gr
}
static void groupchat_onGroupPeerNameChange(ToxWindow *self, Tox *m, uint32_t groupnum, uint32_t peernum,
const char *name, size_t length)
const char *name, size_t length)
{
UNUSED_VAR(length);
if (self->num != groupnum) {
return;
}
GroupChat *chat = &groupchats[groupnum];
if (!chat) {
if (!chat->active) {
return;
}
size_t i;
uint32_t i;
for (i = 0; i < chat->max_idx; ++i) {
GroupPeer *peer = &chat->peer_list[i];
// Test against default tox name to prevent nick change spam on initial join (TODO: this is disgusting)
if (peer->active && peer->peernumber == peernum && strcmp(peer->name, "Tox User")) {
if (peer->active && peer->peernumber == peernum && peer->name_length > 0) {
ChatContext *ctx = self->chatwin;
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
char tmp_event[TOXIC_MAX_NAME_LENGTH * 2 + 32];
snprintf(tmp_event, sizeof(tmp_event), "is now known as %s", (char *) name);
snprintf(tmp_event, sizeof(tmp_event), "is now known as %s", (const char *) name);
write_to_log(tmp_event, peer->name, ctx->log, true);
line_info_add(self, timefrmt, peer->name, (char *) name, NAME_CHANGE, 0, 0, " is now known as ");
line_info_add(self, timefrmt, peer->name, (const char *) name, NAME_CHANGE, 0, 0, " is now known as ");
break;
}
@ -445,14 +473,17 @@ static void send_group_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *a
return;
}
TOX_ERR_CONFERENCE_SEND_MESSAGE err;
Tox_Err_Conference_Send_Message err;
if (!tox_conference_send_message(m, self->num, TOX_MESSAGE_TYPE_ACTION, (uint8_t *) action, strlen(action), &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send action (error %d)", err);
}
}
static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
/*
* Return true if input is recognized by handler
*/
static bool groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
{
ChatContext *ctx = self->chatwin;
@ -460,29 +491,39 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
getyx(self->window, y, x);
getmaxyx(self->window, y2, x2);
if (x2 <= 0 || y2 <= 0)
return;
UNUSED_VAR(y);
if (x2 <= 0 || y2 <= 0) {
return false;
}
if (self->help->active) {
help_onKey(self, key);
return;
return true;
}
if (ctx->pastemode && key == '\r')
if (ctx->pastemode && key == '\r') {
key = '\n';
}
if (ltr || key == '\n') { /* char is printable */
input_new_char(self, key, x, y, x2, y2);
return;
input_new_char(self, key, x, x2);
return true;
}
if (line_info_onKey(self, key))
return;
if (line_info_onKey(self, key)) {
return true;
}
if (input_handle(self, key, x, y, x2, y2))
return;
if (input_handle(self, key, x, x2)) {
return true;
}
bool input_ret = false;
if (key == '\t') { /* TAB key: auto-completes peer name or command */
input_ret = true;
if (ctx->len > 0) {
int diff;
@ -490,17 +531,16 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (ctx->line[0] != L'/' || wcscmp(ctx->line, L"/me") == 0) {
diff = complete_line(self, groupchats[self->num].name_list, groupchats[self->num].num_peers,
TOX_MAX_NAME_LENGTH);
} else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) {
} else if (wcsncmp(ctx->line, L"/avatar ", wcslen(L"/avatar ")) == 0) {
diff = dir_match(self, m, ctx->line, L"/avatar");
}
#ifdef PYTHON
else if (wcsncmp(ctx->line, L"/run \"", wcslen(L"/run \"")) == 0) {
else if (wcsncmp(ctx->line, L"/run ", wcslen(L"/run ")) == 0) {
diff = dir_match(self, m, ctx->line, L"/run");
}
#endif
else {
diff = complete_line(self, group_cmd_list, AC_NUM_GROUP_COMMANDS, MAX_CMDNAME_SIZE);
}
@ -516,15 +556,21 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
} 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;
} else if (key == T_KEY_C_DOWN) { /* Scroll peerlist up and down one position */
input_ret = true;
const int L = y2 - CHATBOX_HEIGHT - SDBAR_OFST;
if (groupchats[self->num].side_pos < groupchats[self->num].num_peers - L)
if (groupchats[self->num].side_pos < (int64_t) 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)
}
} else if (key == T_KEY_C_UP) {
input_ret = true;
if (groupchats[self->num].side_pos > 0) {
--groupchats[self->num].side_pos;
}
} else if (key == '\r') {
input_ret = true;
rm_trailing_spaces_buf(ctx);
if (!wstring_is_empty(ctx->line)) {
@ -534,20 +580,21 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
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));
}
if (line[0] == '/') {
if (strcmp(line, "/close") == 0) {
delete_groupchat(self, m, self->num);
return;
return true;
} 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 {
TOX_ERR_CONFERENCE_SEND_MESSAGE err;
Tox_Err_Conference_Send_Message err;
if (!tox_conference_send_message(m, self->num, TOX_MESSAGE_TYPE_NORMAL, (uint8_t *) line, strlen(line), &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send message (error %d)", err);
@ -559,15 +606,20 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
reset_buf(ctx);
}
return input_ret;
}
static void groupchat_onDraw(ToxWindow *self, Tox *m)
{
UNUSED_VAR(m);
int x2, y2;
getmaxyx(self->window, y2, x2);
if (x2 <= 0 || y2 <= 0)
if (x2 <= 0 || y2 <= 0) {
return;
}
ChatContext *ctx = self->chatwin;
@ -579,8 +631,9 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
curs_set(1);
if (ctx->len > 0)
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);
@ -590,19 +643,19 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
mvwaddch(ctx->sidebar, y2 - CHATBOX_HEIGHT, 0, ACS_BTEE);
pthread_mutex_lock(&Winthread.lock);
int num_peers = groupchats[self->num].num_peers;
uint32_t 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);
wprintw(ctx->sidebar, "Peers: %"PRIu32"\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;
uint32_t i;
for (i = 0; i < num_peers && i < maxlines; ++i) {
wmove(ctx->sidebar, i + 2, 1);
@ -627,14 +680,17 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
int 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));
wmove(self->window, y + 1, new_x);
wnoutrefresh(self->window);
if (self->help->active)
if (self->help->active) {
help_onDraw(self);
}
}
static void groupchat_onInit(ToxWindow *self, Tox *m)
@ -642,8 +698,9 @@ static void groupchat_onInit(ToxWindow *self, Tox *m)
int x2, y2;
getmaxyx(self->window, y2, x2);
if (x2 <= 0 || y2 <= 0)
if (x2 <= 0 || y2 <= 0) {
exit_toxic_err("failed in groupchat_onInit", FATALERR_CURSES);
}
ChatContext *ctx = self->chatwin;
@ -654,8 +711,9 @@ static void groupchat_onInit(ToxWindow *self, Tox *m)
ctx->hst = calloc(1, sizeof(struct history));
ctx->log = calloc(1, sizeof(struct chatlog));
if (ctx->log == NULL || ctx->hst == NULL)
if (ctx->log == NULL || ctx->hst == NULL) {
exit_toxic_err("failed in groupchat_onInit", FATALERR_MEMORY);
}
line_info_init(ctx->hst);
@ -663,8 +721,9 @@ static void groupchat_onInit(ToxWindow *self, Tox *m)
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)
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);
@ -673,36 +732,39 @@ static void groupchat_onInit(ToxWindow *self, Tox *m)
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
}
ToxWindow new_group_chat(Tox *m, uint32_t groupnum)
static ToxWindow *new_group_chat(uint32_t groupnum)
{
ToxWindow ret;
memset(&ret, 0, sizeof(ret));
ToxWindow *ret = calloc(1, sizeof(ToxWindow));
ret.active = true;
ret.is_groupchat = true;
if (ret == NULL) {
exit_toxic_err("failed in new_group_chat", FATALERR_MEMORY);
}
ret.onKey = &groupchat_onKey;
ret.onDraw = &groupchat_onDraw;
ret.onInit = &groupchat_onInit;
ret.onGroupMessage = &groupchat_onGroupMessage;
ret.onGroupNameListChange = &groupchat_onGroupNameListChange;
ret.onGroupPeerNameChange = &groupchat_onGroupPeerNameChange;
ret.onGroupTitleChange = &groupchat_onGroupTitleChange;
ret->is_groupchat = true;
snprintf(ret.name, sizeof(ret.name), "Group %d", groupnum);
ret->onKey = &groupchat_onKey;
ret->onDraw = &groupchat_onDraw;
ret->onInit = &groupchat_onInit;
ret->onGroupMessage = &groupchat_onGroupMessage;
ret->onGroupNameListChange = &groupchat_onGroupNameListChange;
ret->onGroupPeerNameChange = &groupchat_onGroupPeerNameChange;
ret->onGroupTitleChange = &groupchat_onGroupTitleChange;
snprintf(ret->name, sizeof(ret->name), "Group %u", groupnum);
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
Help *help = calloc(1, sizeof(Help));
if (chatwin == NULL || help == NULL)
if (chatwin == NULL || help == NULL) {
exit_toxic_err("failed in new_group_chat", FATALERR_MEMORY);
}
ret.chatwin = chatwin;
ret.help = help;
ret->chatwin = chatwin;
ret->help = help;
ret.num = groupnum;
ret.show_peerlist = true;
ret.active_box = -1;
ret->num = groupnum;
ret->show_peerlist = true;
ret->active_box = -1;
return ret;
}

View File

@ -46,21 +46,19 @@ typedef struct {
time_t start_time;
GroupPeer *peer_list;
size_t max_idx;
uint32_t max_idx;
char *name_list;
size_t num_peers;
uint32_t num_peers;
} GroupChat;
/* Frees all Toxic associated data structures for a groupchat (does not call tox_conference_delete() ) */
void free_groupchat(ToxWindow *self, Tox *m, uint32_t groupnum);
void free_groupchat(ToxWindow *self, uint32_t groupnum);
int init_groupchat_win(ToxWindow *prompt, Tox *m, uint32_t groupnum, uint8_t type);
int init_groupchat_win(Tox *m, uint32_t groupnum, uint8_t type, const char *title, size_t title_length);
/* destroys and re-creates groupchat window with or without the peerlist */
void redraw_groupchat_win(ToxWindow *self);
ToxWindow new_group_chat(Tox *m, uint32_t groupnum);
#endif /* #define GROUPCHAT_H */
#endif /* GROUPCHAT_H */

View File

@ -40,14 +40,16 @@
void help_init_menu(ToxWindow *self)
{
if (self->help->win)
if (self->help->win) {
delwin(self->help->win);
}
int 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;
}
self->help->win = newwin(HELP_MENU_HEIGHT, HELP_MENU_WIDTH, 3, 3);
self->help->active = true;
@ -62,14 +64,16 @@ static void help_exit(ToxWindow *self)
static void help_init_window(ToxWindow *self, int height, int width)
{
if (self->help->win)
if (self->help->win) {
delwin(self->help->win);
}
int y2, x2;
getmaxyx(stdscr, y2, x2);
if (y2 <= 0 || x2 <= 0)
if (y2 <= 0 || x2 <= 0) {
return;
}
height = MIN(height, y2);
width = MIN(width, x2);
@ -134,7 +138,8 @@ static void help_draw_bottom_menu(WINDOW *win)
{
int y2, x2;
getmaxyx(win, y2, x2);
(void) x2;
UNUSED_VAR(x2);
wmove(win, y2 - 2, 1);
@ -173,11 +178,13 @@ static void help_draw_global(ToxWindow *self)
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, " /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");
#endif /* QRPNG */
#endif /* QRCODE */
wprintw(win, " /clear : Clear window history\n");
wprintw(win, " /close : Close the current chat window\n");
wprintw(win, " /quit or /exit : Exit Toxic\n");
@ -272,7 +279,7 @@ static void help_draw_keys(ToxWindow *self)
wprintw(win, " Page Up and Page Down : Scroll window history one line\n");
wprintw(win, " Ctrl+F and Ctrl+V : Scroll window history half a page\n");
wprintw(win, " Ctrl+H : Move to the bottom of window history\n");
wprintw(win, " Ctrl+[ and Ctrl+] : Scroll peer list in groupchats\n");
wprintw(win, " Ctrl+up and Ctrl+down : Scroll peer list in groupchats\n");
wprintw(win, " Ctrl+B : Toggle the groupchat peerlist\n");
wprintw(win, " Ctrl+J : Insert new line\n");
wprintw(win, " Ctrl+T : Toggle paste mode\n\n");
@ -320,7 +327,7 @@ static void help_draw_plugin(ToxWindow *self)
box(win, ACS_VLINE, ACS_HLINE);
wnoutrefresh(win);
}
#endif
#endif /* PYTHON */
static void help_draw_contacts(ToxWindow *self)
{
@ -390,7 +397,7 @@ void help_onKey(ToxWindow *self, wint_t key)
help_init_window(self, 4 + num_registered_handlers(), help_max_width());
self->help->type = HELP_PLUGIN;
break;
#endif
#endif /* PYTHON */
case 'f':
help_init_window(self, 10, 80);

View File

@ -42,4 +42,4 @@ void help_onDraw(ToxWindow *self);
void help_init_menu(ToxWindow *self);
void help_onKey(ToxWindow *self, wint_t key);
#endif /* #define HELP_H */
#endif /* HELP_H */

View File

@ -38,13 +38,14 @@
extern struct user_settings *user_settings;
/* 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;
/* this is the only place we need to do this check */
if (key == '\n')
if (key == '\n') {
key = L'';
}
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 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));
else if (ctx->start)
} else if (ctx->start) {
ctx->start = MAX(0, ctx->start - cur_len);
}
}
/* delete a char via delete key from input field and buffer */
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);
}
}
/* 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;
if (del_word_buf(ctx) == -1) {
sound_notify(self, notif_error, 0, NULL);
return;
}
}
/* deletes entire line before cursor from input field and buffer */
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);
}
}
/* deletes entire line after cursor from input field and buffer */
static void input_kill(ChatContext *ctx)
{
if (kill_buf(ctx) == -1)
if (kill_buf(ctx) == -1) {
sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
}
}
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 */
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;
@ -149,8 +153,9 @@ static void input_mv_home(ToxWindow *self)
{
ChatContext *ctx = self->chatwin;
if (ctx->pos <= 0)
if (ctx->pos <= 0) {
return;
}
ctx->pos = 0;
ctx->start = 0;
@ -161,18 +166,44 @@ static void input_mv_left(ToxWindow *self, int x, int mx_x)
{
ChatContext *ctx = self->chatwin;
if (ctx->pos <= 0)
if (ctx->pos <= 0) {
return;
}
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;
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));
else if (ctx->start)
} else if (ctx->start > 0) {
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 */
@ -180,8 +211,9 @@ static void input_mv_right(ToxWindow *self, int x, int mx_x)
{
ChatContext *ctx = self->chatwin;
if (ctx->pos >= ctx->len)
if (ctx->pos >= ctx->len) {
return;
}
++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 */
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.
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;
@ -232,7 +287,7 @@ bool input_handle(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y)
break;
case T_KEY_C_W:
input_del_word(self, x, mx_x);
input_del_word(self);
break;
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 T_KEY_C_E:
input_mv_end(self, y, mx_x);
input_mv_end(self, mx_x);
break;
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);
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:
match = false;
break;

View File

@ -24,10 +24,10 @@
#define INPUT_H
/* 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.
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 */

View File

@ -40,8 +40,9 @@ void line_info_init(struct history *hst)
{
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);
}
hst->line_start = hst->line_root;
hst->line_end = hst->line_start;
@ -53,8 +54,9 @@ void line_info_reset_start(ToxWindow *self, struct history *hst)
{
struct line_info *line = hst->line_end;
if (line->prev == NULL)
if (line->prev == NULL) {
return;
}
int y2, x2;
getmaxyx(self->window, y2, x2);
@ -88,8 +90,9 @@ void line_info_cleanup(struct history *hst)
int i;
for (i = 0; i < hst->queue_sz; ++i) {
if (hst->queue[i])
if (hst->queue[i]) {
free(hst->queue[i]);
}
}
free(hst);
@ -114,15 +117,17 @@ static void line_info_root_fwd(struct history *hst)
/* returns ptr to queue item 0 and removes it from queue. Returns NULL if queue is empty. */
static struct line_info *line_info_ret_queue(struct history *hst)
{
if (hst->queue_sz <= 0)
if (hst->queue_sz <= 0) {
return NULL;
}
struct line_info *line = hst->queue[0];
int i;
for (i = 0; i < hst->queue_sz; ++i)
for (i = 0; i < hst->queue_sz; ++i) {
hst->queue[i] = hst->queue[i + 1];
}
--hst->queue_sz;
@ -137,18 +142,21 @@ static struct line_info *line_info_ret_queue(struct history *hst)
int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const char *name2, uint8_t type,
uint8_t bold, uint8_t colour, const char *msg, ...)
{
if (!self)
if (!self) {
return -1;
}
struct history *hst = self->chatwin->hst;
if (hst->queue_sz >= MAX_LINE_INFO_QUEUE)
if (hst->queue_sz >= MAX_LINE_INFO_QUEUE) {
return -1;
}
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);
}
char frmt_msg[MAX_LINE_INFO_MSG_SIZE] = {0};
@ -206,8 +214,9 @@ int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const
int i;
for (i = 0; frmt_msg[i]; ++i) {
if (frmt_msg[i] == '\n')
if (frmt_msg[i] == '\n') {
++new_line->newlines;
}
}
}
@ -245,11 +254,13 @@ static void line_info_check_queue(ToxWindow *self)
struct history *hst = self->chatwin->hst;
struct line_info *line = line_info_ret_queue(hst);
if (line == NULL)
if (line == NULL) {
return;
}
if (hst->start_id > user_settings->history_size)
if (hst->start_id > user_settings->history_size) {
line_info_root_fwd(hst);
}
line->prev = hst->line_end;
hst->line_end->next = line;
@ -259,10 +270,12 @@ static void line_info_check_queue(ToxWindow *self)
int y, y2, x, x2;
getmaxyx(self->window, y2, x2);
getyx(self->chatwin->history, y, x);
(void) x;
if (x2 <= SIDEBAR_WIDTH)
UNUSED_VAR(x);
if (x2 <= SIDEBAR_WIDTH) {
return;
}
int offst = self->show_peerlist ? SIDEBAR_WIDTH : 0; /* offset width of groupchat sidebar */
int lines = 1 + line->newlines + (line->len / (x2 - offst));
@ -284,8 +297,9 @@ void line_info_print(ToxWindow *self)
{
ChatContext *ctx = self->chatwin;
if (ctx == NULL)
if (ctx == NULL) {
return;
}
struct history *hst = ctx->hst;
@ -293,19 +307,25 @@ void line_info_print(ToxWindow *self)
line_info_check_queue(self);
WINDOW *win = ctx->history;
wclear(win);
int y2, x2;
getmaxyx(self->window, y2, x2);
if (x2 <= SIDEBAR_WIDTH)
if (x2 <= SIDEBAR_WIDTH) {
return;
}
if (self->is_groupchat)
if (self->is_groupchat) {
wmove(win, 0, 0);
else
} else {
wmove(win, 2, 0);
}
struct line_info *line = hst->line_start->next;
int numlines = 0;
while (line && numlines++ <= y2) {
@ -325,10 +345,11 @@ void line_info_print(ToxWindow *self)
int nameclr = GREEN;
if (line->colour)
if (line->colour) {
nameclr = line->colour;
else if (type == IN_MSG)
} else if (type == IN_MSG) {
nameclr = CYAN;
}
wattron(win, COLOR_PAIR(nameclr));
wprintw(win, "%s %s: ", user_settings->line_normal, line->name1);
@ -339,26 +360,29 @@ void line_info_print(ToxWindow *self)
while (msg) {
char *line = strsep(&msg, "\n");
if (line[0] == '>')
if (line[0] == '>') {
wattron(win, COLOR_PAIR(GREEN));
else if (line[0] == '<')
} else if (line[0] == '<') {
wattron(win, COLOR_PAIR(RED));
}
wprintw(win, "%s%c", line, msg ? '\n' : '\0');
if (line[0] == '>')
if (line[0] == '>') {
wattroff(win, COLOR_PAIR(GREEN));
else if (line[0] == '<')
} else if (line[0] == '<') {
wattroff(win, COLOR_PAIR(RED));
}
// change the \0 set by strsep back to \n
if (msg)
if (msg) {
msg[-1] = '\n';
}
}
if (type == OUT_MSG && timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
wattron(win, COLOR_PAIR(RED));
wprintw(win, " x", line->msg);
wprintw(win, " x");
wattroff(win, COLOR_PAIR(RED));
if (line->noread_flag == false) {
@ -406,19 +430,23 @@ void line_info_print(ToxWindow *self)
wattroff(win, COLOR_PAIR(BLUE));
}
if (line->bold)
if (line->bold) {
wattron(win, A_BOLD);
}
if (line->colour)
if (line->colour) {
wattron(win, COLOR_PAIR(line->colour));
}
wprintw(win, "%s\n", line->msg);
if (line->bold)
if (line->bold) {
wattroff(win, A_BOLD);
}
if (line->colour)
if (line->colour) {
wattroff(win, COLOR_PAIR(line->colour));
}
break;
@ -427,8 +455,9 @@ void line_info_print(ToxWindow *self)
wprintw(win, "$ ");
wattroff(win, COLOR_PAIR(GREEN));
if (line->msg[0])
if (line->msg[0]) {
wprintw(win, "%s", line->msg);
}
wprintw(win, "\n");
break;
@ -492,8 +521,9 @@ void line_info_print(ToxWindow *self)
}
/* keep calling until queue is empty */
if (hst->queue_sz > 0)
if (hst->queue_sz > 0) {
line_info_print(self);
}
}
/* puts msg in specified line_info msg buffer */
@ -518,40 +548,50 @@ void line_info_set(ToxWindow *self, uint32_t id, char *msg)
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;
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)
{
if (hst->line_start->next)
if (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)
{
int x2, y2;
getmaxyx(self->window, y2, x2);
(void) x2;
UNUSED_VAR(x2);
int jump_dist = y2 / 2;
int i;
for (i = 0; i < jump_dist && hst->line_start->prev; ++i)
for (i = 0; i < jump_dist && hst->line_start->prev; ++i) {
hst->line_start = hst->line_start->prev;
}
}
static void line_info_page_down(ToxWindow *self, struct history *hst)
{
int x2, y2;
getmaxyx(self->window, y2, x2);
(void) x2;
UNUSED_VAR(x2);
int jump_dist = y2 / 2;
int i;
for (i = 0; i < jump_dist && hst->line_start->next; ++i)
for (i = 0; i < jump_dist && hst->line_start->next; ++i) {
hst->line_start = hst->line_start->next;
}
}
bool line_info_onKey(ToxWindow *self, wint_t key)

View File

@ -100,4 +100,4 @@ void line_info_reset_start(ToxWindow *self, 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 */
#endif /* #define LINE_INFO_H */
#endif /* LINE_INFO_H */

View File

@ -45,8 +45,9 @@ extern struct user_settings *user_settings;
Returns 0 on success, -1 if the path is too long */
static int get_log_path(char *dest, int destsize, char *name, const char *selfkey, const char *otherkey, int logtype)
{
if (!valid_nick(name))
if (!valid_nick(name)) {
name = UNKNOWN_NAME;
}
const char *namedash = logtype == LOG_PROMPT ? "" : "-";
const char *set_path = user_settings->chatlogs_path;
@ -85,10 +86,11 @@ static int get_log_path(char *dest, int destsize, char *name, const char *selfke
return -1;
}
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);
else
} else {
snprintf(dest, destsize, "%s%s%s-%s%s%s.log", user_config_dir, LOGDIR, self_id, name, namedash, other_id);
}
free(user_config_dir);
@ -98,19 +100,22 @@ static int get_log_path(char *dest, int destsize, char *name, const char *selfke
/* Opens log file or creates a new one */
static int init_logging_session(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype)
{
if (selfkey == NULL || (logtype == LOG_CHAT && otherkey == NULL))
if (selfkey == NULL || (logtype == LOG_CHAT && otherkey == NULL)) {
return -1;
}
char log_path[MAX_STR_SIZE];
if (get_log_path(log_path, sizeof(log_path), name, selfkey, otherkey, logtype) == -1)
if (get_log_path(log_path, sizeof(log_path), name, selfkey, otherkey, logtype) == -1) {
return -1;
}
log->file = fopen(log_path, "a+");
snprintf(log->path, sizeof(log->path), "%s", log_path);
if (log->file == NULL)
if (log->file == NULL) {
return -1;
}
return 0;
}
@ -119,8 +124,9 @@ static int init_logging_session(char *name, const char *selfkey, const char *oth
void write_to_log(const char *msg, const char *name, struct chatlog *log, bool event)
{
if (!log->log_on)
if (!log->log_on) {
return;
}
if (log->file == NULL) {
log->log_on = false;
@ -129,10 +135,11 @@ void write_to_log(const char *msg, const char *name, struct chatlog *log, bool e
char name_frmt[TOXIC_MAX_NAME_LENGTH + 3];
if (event)
if (event) {
snprintf(name_frmt, sizeof(name_frmt), "* %s", name);
else
} else {
snprintf(name_frmt, sizeof(name_frmt), "%s:", name);
}
const char *t = user_settings->log_timestamp_format;
char s[MAX_STR_SIZE];
@ -147,8 +154,9 @@ void write_to_log(const char *msg, const char *name, struct chatlog *log, bool e
void log_disable(struct chatlog *log)
{
if (log->file != NULL)
if (log->file != NULL) {
fclose(log->file);
}
memset(log, 0, sizeof(struct chatlog));
}
@ -157,8 +165,9 @@ int log_enable(char *name, const char *selfkey, const char *otherkey, struct cha
{
log->log_on = true;
if (log->file != NULL)
if (log->file != NULL) {
return 0;
}
if (init_logging_session(name, selfkey, otherkey, log, logtype) == -1) {
log_disable(log);
@ -171,18 +180,21 @@ int log_enable(char *name, const char *selfkey, const char *otherkey, struct cha
/* Loads previous history from chat log */
void load_chat_history(ToxWindow *self, struct chatlog *log)
{
if (log->file == NULL)
if (log->file == NULL) {
return;
}
off_t sz = file_size(log->path);
if (sz <= 0)
if (sz <= 0) {
return;
}
char *hstbuf = malloc(sz + 1);
if (hstbuf == NULL)
if (hstbuf == NULL) {
exit_toxic_err("failed in load_chat_history", FATALERR_MEMORY);
}
if (fseek(log->file, 0L, SEEK_SET) == -1) {
free(hstbuf);
@ -204,8 +216,9 @@ void load_chat_history(ToxWindow *self, struct chatlog *log)
/* start at end and backtrace L lines or to the beginning of buffer */
for (start = sz - 1; start >= 0 && count < L; --start) {
if (hstbuf[start] == '\n')
if (hstbuf[start] == '\n') {
++count;
}
}
const char *line = strtok(&hstbuf[start + 1], "\n");
@ -238,33 +251,40 @@ int rename_logfile(char *src, char *dest, const char *selfkey, const char *other
log_on = log->log_on;
}
if (log_on)
if (log_on) {
log_disable(log);
}
char newpath[MAX_STR_SIZE];
char oldpath[MAX_STR_SIZE];
if (get_log_path(oldpath, sizeof(oldpath), src, selfkey, otherkey, LOG_CHAT) == -1)
if (get_log_path(oldpath, sizeof(oldpath), src, selfkey, otherkey, LOG_CHAT) == -1) {
goto on_error;
}
if (!file_exists(oldpath))
if (!file_exists(oldpath)) {
return 0;
}
if (get_log_path(newpath, sizeof(newpath), dest, selfkey, otherkey, LOG_CHAT) == -1)
if (get_log_path(newpath, sizeof(newpath), dest, selfkey, otherkey, LOG_CHAT) == -1) {
goto on_error;
}
if (rename(oldpath, newpath) != 0)
if (rename(oldpath, newpath) != 0) {
goto on_error;
}
if (log_on)
if (log_on) {
log_enable(dest, selfkey, otherkey, log, LOG_CHAT);
}
return 0;
on_error:
if (log_on)
if (log_on) {
log_enable(src, selfkey, otherkey, log, LOG_CHAT);
}
return -1;
}

View File

@ -56,4 +56,4 @@ void load_chat_history(ToxWindow *self, struct chatlog *log);
Returns 0 on success or if no log exists, -1 on failure. */
int rename_logfile(char *src, char *dest, const char *selfkey, const char *otherkey, int winnum);
#endif /* #define LOG_H */
#endif /* LOG_H */

View File

@ -50,8 +50,9 @@ void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type,
struct cqueue_msg *new_m = malloc(sizeof(struct cqueue_msg));
if (new_m == NULL)
if (new_m == NULL) {
exit_toxic_err("failed in cqueue_message", FATALERR_MEMORY);
}
snprintf(new_m->message, sizeof(new_m->message), "%s", msg);
new_m->len = len;
@ -118,8 +119,9 @@ void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt)
struct cqueue_msg *next = msg->next;
if (msg->prev == NULL) { /* root */
if (next)
if (next) {
next->prev = NULL;
}
free(msg);
q->root = next;
@ -133,7 +135,7 @@ void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt)
}
}
#define CQUEUE_TRY_SEND_INTERVAL 60
#define CQUEUE_TRY_SEND_INTERVAL 10
/* Tries to send the oldest unsent message in queue. */
void cqueue_try_send(ToxWindow *self, Tox *m)
@ -141,18 +143,15 @@ void cqueue_try_send(ToxWindow *self, Tox *m)
struct chat_queue *q = self->chatwin->cqueue;
struct cqueue_msg *msg = q->root;
if (!msg)
if (!msg) {
return;
}
if (msg->receipt != 0 && !timed_out(msg->last_send_try, CQUEUE_TRY_SEND_INTERVAL))
if (msg->receipt != 0 && !timed_out(msg->last_send_try, CQUEUE_TRY_SEND_INTERVAL)) {
return;
}
uint32_t receipt = 0;
TOX_MESSAGE_TYPE type = msg->type == OUT_MSG ? TOX_MESSAGE_TYPE_NORMAL : TOX_MESSAGE_TYPE_ACTION;
receipt = tox_friend_send_message(m, self->num, type, (uint8_t *) msg->message, msg->len, NULL);
Tox_Message_Type type = msg->type == OUT_MSG ? TOX_MESSAGE_TYPE_NORMAL : TOX_MESSAGE_TYPE_ACTION;
msg->receipt = tox_friend_send_message(m, self->num, type, (uint8_t *) msg->message, msg->len, NULL);
msg->last_send_try = get_unix_time();
msg->receipt = receipt;
return;
}

View File

@ -48,4 +48,4 @@ void cqueue_try_send(ToxWindow *self, Tox *m);
/* removes message with matching receipt from queue, writes to log and updates line to show the message was received. */
void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt);
#endif /* #define MESSAGE_QUEUE_H */
#endif /* MESSAGE_QUEUE_H */

View File

@ -40,6 +40,13 @@
extern ToxWindow *prompt;
extern struct user_settings *user_settings;
void clear_screen(void)
{
if (system("clear") != 0) {
fprintf(stderr, "Warning: system() failed to clear screen\n");
}
}
void hst_to_net(uint8_t *num, uint16_t numbytes)
{
#ifndef WORDS_BIGENDIAN
@ -84,25 +91,30 @@ void get_time_str(char *buf, int bufsize)
}
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 */
void get_elapsed_time_str(char *buf, int bufsize, time_t secs)
{
if (!secs)
if (!secs) {
return;
}
long int seconds = secs % 60;
long int minutes = (secs % 3600) / 60;
long int hours = secs / 3600;
if (!minutes && !hours)
if (!minutes && !hours) {
snprintf(buf, bufsize, "%.2ld", seconds);
else if (!hours)
} else if (!hours) {
snprintf(buf, bufsize, "%ld:%.2ld", minutes, seconds);
else
} else {
snprintf(buf, bufsize, "%ld:%.2ld:%.2ld", hours, minutes, seconds);
}
}
/*
@ -114,11 +126,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)
{
if (output_size == 0 || hex_len != output_size * 2)
if (output_size == 0 || hex_len != output_size * 2) {
return -1;
}
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;
}
@ -127,18 +140,20 @@ 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)
{
if (size % 2 != 0)
if (size % 2 != 0) {
return -1;
}
int i, res;
const char *pos = keystr;
for (i = 0; i < size; ++i) {
res = sscanf(pos, "%2hhx", &buf[i]);
res = sscanf(pos, "%2hhx", (unsigned char *)&buf[i]);
pos += 2;
if (res == EOF || res < 1)
if (res == EOF || res < 1) {
return -1;
}
}
return 0;
@ -151,13 +166,15 @@ int hex_string_to_bytes(char *buf, int size, const char *keystr)
*/
int bin_id_to_string(const char *bin_id, size_t bin_id_size, char *output, size_t output_size)
{
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;
}
size_t i;
for (i = 0; i < TOX_ADDRESS_SIZE; ++i)
for (i = 0; i < TOX_ADDRESS_SIZE; ++i) {
snprintf(&output[i * 2], output_size - (i * 2), "%02X", bin_id[i] & 0xff);
}
return 0;
}
@ -165,8 +182,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 */
int string_is_empty(const char *string)
{
if (!string)
if (!string) {
return true;
}
return string[0] == '\0';
}
@ -174,8 +192,9 @@ int string_is_empty(const char *string)
/* Returns 1 if the string is empty, 0 otherwise */
int wstring_is_empty(const wchar_t *string)
{
if (!string)
if (!string) {
return true;
}
return string[0] == L'\0';
}
@ -185,11 +204,13 @@ int mbs_to_wcs_buf(wchar_t *buf, const char *string, size_t n)
{
size_t len = mbstowcs(NULL, string, 0) + 1;
if (n < len)
if (n < len) {
return -1;
}
if ((len = mbstowcs(buf, string, n)) == (size_t) - 1)
if ((len = mbstowcs(buf, string, n)) == (size_t) - 1) {
return -1;
}
return len;
}
@ -199,11 +220,13 @@ int wcs_to_mbs_buf(char *buf, const wchar_t *string, size_t n)
{
size_t len = wcstombs(NULL, string, 0) + 1;
if (n < len)
if (n < len) {
return -1;
}
if ((len = wcstombs(buf, string, n)) == (size_t) - 1)
if ((len = wcstombs(buf, string, n)) == (size_t) - 1) {
return -1;
}
return len;
}
@ -222,8 +245,9 @@ int qsort_strcasecmp_hlpr(const void *str1, const void *str2)
- must not contain a newline or tab seqeunce */
int valid_nick(const char *nick)
{
if (!nick[0] || nick[0] == ' ')
if (!nick[0] || nick[0] == ' ') {
return 0;
}
int i;
@ -235,7 +259,9 @@ int valid_nick(const char *nick)
|| nick[i] == '\v'
|| nick[i] == '\r')
{
return 0;
}
}
return 1;
@ -247,8 +273,9 @@ void filter_str(char *str, size_t len)
size_t i;
for (i = 0; i < len; ++i) {
if (str[i] == '\n' || str[i] == '\r' || str[i] == '\t' || str[i] == '\v' || str[i] == '\0')
if (str[i] == '\n' || str[i] == '\r' || str[i] == '\t' || str[i] == '\v' || str[i] == '\0') {
str[i] = ' ';
}
}
}
@ -260,22 +287,26 @@ size_t get_file_name(char *namebuf, size_t bufsize, const char *pathname)
int len = strlen(pathname) - 1;
char *path = strdup(pathname);
if (path == NULL)
if (path == NULL) {
exit_toxic_err("failed in get_file_name", FATALERR_MEMORY);
}
while (len >= 0 && pathname[len] == '/')
while (len >= 0 && pathname[len] == '/') {
path[len--] = '\0';
}
char *finalname = strdup(path);
if (finalname == NULL)
if (finalname == NULL) {
exit_toxic_err("failed in get_file_name", FATALERR_MEMORY);
}
const char *basenm = strrchr(path, '/');
if (basenm != NULL) {
if (basenm[1])
if (basenm[1]) {
strcpy(finalname, &basenm[1]);
}
}
snprintf(namebuf, bufsize, "%s", finalname);
@ -292,13 +323,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)
{
if (path_len == 0 || path == NULL)
if (path_len == 0 || path == NULL) {
return 0;
}
size_t dir_len = char_rfind(path, '/', path_len);
if (dir_len != 0 && dir_len < path_len)
++dir_len; /* Leave trailing slash */
if (dir_len != 0 && dir_len < path_len) {
++dir_len; /* Leave trailing slash */
}
memcpy(dir, path, dir_len);
dir[dir_len] = '\0';
@ -311,8 +344,9 @@ void str_to_lower(char *str)
{
int i;
for (i = 0; str[i]; ++i)
for (i = 0; str[i]; ++i) {
str[i] = tolower(str[i]);
}
}
/* puts friendnum's nick in buf, truncating at TOXIC_MAX_NAME_LENGTH if necessary.
@ -320,7 +354,7 @@ void str_to_lower(char *str)
Returns nick len */
size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum)
{
TOX_ERR_FRIEND_QUERY err;
Tox_Err_Friend_Query err;
size_t len = tox_friend_get_name_size(m, friendnum, &err);
if (err != TOX_ERR_FRIEND_QUERY_OK) {
@ -346,7 +380,7 @@ on_error:
/* same as get_nick_truncate but for groupchats */
int get_group_nick_truncate(Tox *m, char *buf, uint32_t peernum, uint32_t groupnum)
{
TOX_ERR_CONFERENCE_PEER_QUERY err;
Tox_Err_Conference_Peer_Query err;
size_t len = tox_conference_peer_get_name_size(m, groupnum, peernum, &err);
if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
@ -398,8 +432,9 @@ int char_find(int idx, const char *s, char ch)
int i = idx;
for (i = idx; s[i]; ++i) {
if (s[i] == ch)
if (s[i] == ch) {
break;
}
}
return i;
@ -416,8 +451,9 @@ int char_rfind(const char *s, char ch, int len)
int i = 0;
for (i = len; i > 0; --i) {
if (s[i] == ch)
if (s[i] == ch) {
break;
}
}
return i;
@ -452,13 +488,41 @@ bool file_exists(const char *path)
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. */
off_t file_size(const char *path)
{
struct stat st;
if (stat(path, &st) == -1)
if (stat(path, &st) == -1) {
return 0;
}
return st.st_size;
}
@ -467,17 +531,19 @@ off_t file_size(const char *path)
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)
int check_file_signature(const unsigned char *signature, size_t size, FILE *fp)
{
char buf[size];
if (fread(buf, size, 1, fp) != 1)
if (fread(buf, size, 1, fp) != 1) {
return -1;
}
int ret = memcmp(signature, buf, size);
if (fseek(fp, 0L, SEEK_SET) == -1)
if (fseek(fp, 0L, SEEK_SET) == -1) {
return -1;
}
return ret == 0 ? 0 : 1;
}
@ -485,12 +551,17 @@ int check_file_signature(const char *signature, size_t size, FILE *fp)
/* sets window title in tab bar. */
void set_window_title(ToxWindow *self, const char *title, int len)
{
if (len <= 0 || !title) {
return;
}
char cpy[TOXIC_MAX_NAME_LENGTH + 1];
if (self->is_groupchat) /* keep groupnumber in title */
if (self->is_groupchat) { /* keep groupnumber in title */
snprintf(cpy, sizeof(cpy), "%d %s", self->num, title);
else
} else {
snprintf(cpy, sizeof(cpy), "%s", title);
}
if (len > MAX_WINDOW_NAME_LENGTH) {
strcpy(&cpy[MAX_WINDOW_NAME_LENGTH - 3], "...");

View File

@ -39,6 +39,17 @@
#define net_to_host(x, y) hst_to_net(x, y)
#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);
/*
@ -78,13 +89,13 @@ int string_is_empty(const char *string);
/* Same as above but for wide character strings */
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);
/* 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);
/* 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);
/* Returns 1 if connection has timed out, 0 otherwise */
@ -146,6 +157,15 @@ void bytes_convert_str(char *buf, int size, uint64_t bytes);
/* checks if a file exists. Returns true or false */
bool file_exists(const char *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. */
off_t file_size(const char *path);
@ -153,7 +173,7 @@ off_t file_size(const char *path);
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);
int check_file_signature(const unsigned char *signature, size_t size, FILE *fp);
/* sets window title in tab bar. */
void set_window_title(ToxWindow *self, const char *title, int len);
@ -170,4 +190,4 @@ bool is_ip4_address(const char *address);
*/
bool is_ip6_address(const char *address);
#endif /* #define MISC_TOOLS_H */
#endif /* MISC_TOOLS_H */

View File

@ -42,7 +42,7 @@ extern struct Winthread Winthread;
#define MAX_DOMAIN_SIZE 32
#define MAX_SERVER_LINE MAX_DOMAIN_SIZE + (SERVER_KEY_SIZE * 2) + 3
struct Nameservers {
static struct Nameservers {
int lines;
char names[MAX_SERVERS][MAX_DOMAIN_SIZE];
char keys[MAX_SERVERS][SERVER_KEY_SIZE];
@ -97,42 +97,49 @@ static int load_nameserver_list(const char *path)
{
FILE *fp = fopen(path, "r");
if (fp == NULL)
if (fp == NULL) {
return -2;
}
char line[MAX_SERVER_LINE];
while (fgets(line, sizeof(line), fp) && Nameservers.lines < MAX_SERVERS) {
int linelen = strlen(line);
if (linelen < SERVER_KEY_SIZE * 2 + 5)
if (linelen < SERVER_KEY_SIZE * 2 + 5) {
continue;
}
if (line[linelen - 1] == '\n')
if (line[linelen - 1] == '\n') {
line[--linelen] = '\0';
}
const char *name = strtok(line, " ");
const char *keystr = strtok(NULL, " ");
if (name == NULL || keystr == NULL)
if (name == NULL || keystr == NULL) {
continue;
}
if (strlen(keystr) != SERVER_KEY_SIZE * 2)
if (strlen(keystr) != SERVER_KEY_SIZE * 2) {
continue;
}
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);
if (res == -1)
if (res == -1) {
continue;
}
++Nameservers.lines;
}
fclose(fp);
if (Nameservers.lines < 1)
if (Nameservers.lines < 1) {
return -3;
}
return 0;
}
@ -145,8 +152,9 @@ static int load_nameserver_list(const char *path)
*/
static int parse_addr(const char *addr, char *namebuf, size_t namebuf_sz, char *dombuf, size_t dombuf_sz)
{
if (strlen(addr) >= (MAX_STR_SIZE - strlen(NAMESERVER_API_PATH)))
if (strlen(addr) >= (MAX_STR_SIZE - strlen(NAMESERVER_API_PATH))) {
return -1;
}
char tmpaddr[MAX_STR_SIZE];
char *tmpname = NULL;
@ -156,8 +164,9 @@ static int parse_addr(const char *addr, char *namebuf, size_t namebuf_sz, char *
tmpname = strtok(tmpaddr, "@");
tmpdom = strtok(NULL, "");
if (tmpname == NULL || tmpdom == NULL)
if (tmpname == NULL || tmpdom == NULL) {
return -1;
}
str_to_lower(tmpdom);
snprintf(namebuf, namebuf_sz, "%s", tmpname);
@ -197,29 +206,35 @@ static int process_response(struct Recv_Curl_Data *recv_data)
{
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;
}
const char *IDstart = strstr(recv_data->data, ID_PREFIX);
if (IDstart == NULL)
if (IDstart == NULL) {
return -1;
}
if (strlen(IDstart) < TOX_ADDRESS_SIZE * 2 + prefix_size)
if (strlen(IDstart) < TOX_ADDRESS_SIZE * 2 + prefix_size) {
return -1;
}
char ID_string[TOX_ADDRESS_SIZE * 2 + 1];
memcpy(ID_string, IDstart + prefix_size, TOX_ADDRESS_SIZE * 2);
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 0;
}
void *lookup_thread_func(void *data)
{
UNUSED_VAR(data);
ToxWindow *self = t_data.self;
char input_domain[MAX_STR_SIZE];
@ -234,10 +249,11 @@ void *lookup_thread_func(void *data)
char real_domain[MAX_DOMAIN_SIZE];
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.");
else
} else {
lookup_error(self, "Name server domain not found.");
}
kill_lookup_thread();
}
@ -278,7 +294,7 @@ void *lookup_thread_func(void *data)
int proxy_ret = set_curl_proxy(c_handle, arg_opts.proxy_address, arg_opts.proxy_port, arg_opts.proxy_type);
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;
}

View File

@ -47,12 +47,12 @@
/* compatibility with older versions of OpenAL */
#ifndef ALC_ALL_DEVICES_SPECIFIER
#include <AL/alext.h>
#endif
#endif
#endif /* ALC_ALL_DEVICES_SPECIFIER */
#endif /* __APPLE__ */
#ifdef SOUND_NOTIFY
#include <AL/alut.h> /* freealut packet */
#endif
#endif /* AUDIO */
#endif /* SOUND_NOTIFY */
#endif /* defined(AUDIO) || defined(SOUND_NOTIFY) */
#ifdef BOX_NOTIFY
#include <libnotify/notify.h>
@ -64,7 +64,7 @@
extern struct user_settings *user_settings;
struct Control {
static struct Control {
time_t cooldown;
time_t notif_timeout;
@ -79,12 +79,12 @@ struct Control {
#endif /* SOUND_NOTIFY */
} Control = {0};
struct _ActiveNotifications {
static struct _ActiveNotifications {
#ifdef SOUND_NOTIFY
uint32_t source;
uint32_t buffer;
bool looping;
#endif
#endif /* SOUND_NOTIFY */
bool active;
int *id_indicator;
#ifdef BOX_NOTIFY
@ -93,7 +93,7 @@ struct _ActiveNotifications {
char title[64];
size_t size;
time_t n_timeout;
#endif
#endif /* BOX_NOTIFY */
} actives[ACTIVE_NOTIFS_MAX];
/**********************************************************************************/
/**********************************************************************************/
@ -104,21 +104,24 @@ struct _ActiveNotifications {
/* coloured tab notifications: primary notification type */
static void tab_notify(ToxWindow *self, uint64_t flags)
{
if (self == NULL)
if (self == NULL) {
return;
}
if (flags & NT_WNDALERT_0)
if (flags & NT_WNDALERT_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;
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;
}
}
static bool notifications_are_disabled(uint64_t flags)
{
if (user_settings->alerts != ALERTS_ENABLED)
if (user_settings->alerts != ALERTS_ENABLED) {
return true;
}
bool res = (flags & NT_RESTOL) && (Control.cooldown > get_unix_time());
#ifdef X11
@ -128,14 +131,14 @@ static bool notifications_are_disabled(uint64_t flags)
#endif
}
static void control_lock()
static void control_lock(void)
{
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
pthread_mutex_lock(Control.poll_mutex);
#endif
}
static void control_unlock()
static void control_unlock(void)
{
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
pthread_mutex_unlock(Control.poll_mutex);
@ -157,11 +160,13 @@ static bool device_opened = false;
time_t last_opened_update = 0;
/* Opens primary device. Returns true on succe*/
void m_open_device()
void m_open_device(void)
{
last_opened_update = get_unix_time();
if (device_opened) return;
if (device_opened) {
return;
}
/* Blah error check */
open_primary_device(output, &Control.device_idx, 48000, 20, 1);
@ -169,9 +174,11 @@ void m_open_device()
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);
@ -179,7 +186,7 @@ void m_close_device()
}
/* Terminate all sounds but wait for them to finish first */
void graceful_clear()
void graceful_clear(void)
{
control_lock();
@ -196,17 +203,20 @@ void graceful_clear()
actives[i].box = NULL;
}
#endif
#endif /* BOX_NOTIFY */
if (actives[i].id_indicator)
if (actives[i].id_indicator) {
*actives[i].id_indicator = -1; /* reset indicator value */
}
if ( actives[i].looping ) {
if (actives[i].looping) {
stop_sound(i);
} else {
if (!is_playing(actives[i].source))
if (!is_playing(actives[i].source)) {
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
else break;
} else {
break;
}
}
}
}
@ -225,7 +235,7 @@ void graceful_clear()
void *do_playing(void *_p)
{
(void)_p;
UNUSED_VAR(_p);
while (true) {
control_lock();
@ -241,7 +251,9 @@ void *do_playing(void *_p)
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;
#ifdef BOX_NOTIFY
@ -249,8 +261,9 @@ void *do_playing(void *_p)
#endif
if (test_active_notify) {
if (actives[i].id_indicator)
if (actives[i].id_indicator) {
*actives[i].id_indicator = -1; /* reset indicator value */
}
if (!is_playing(actives[i].source)) {
/* Close */
@ -267,8 +280,9 @@ void *do_playing(void *_p)
notify_notification_close(actives[i].box, &ignore);
actives[i].box = NULL;
if (actives[i].id_indicator)
if (actives[i].id_indicator) {
*actives[i].id_indicator = -1; /* reset indicator value */
}
if (!actives[i].looping && !is_playing(actives[i].source)) {
/* stop source if not looping or playing, just terminate box */
@ -279,7 +293,7 @@ void *do_playing(void *_p)
}
}
#endif
#endif /* BOX_NOTIFY */
}
/* device is opened and no activity in under DEVICE_COOLDOWN time, close device*/
@ -303,7 +317,7 @@ int play_source(uint32_t source, uint32_t buffer, bool looping)
for (; i < ACTIVE_NOTIFS_MAX && actives[i].active; i ++);
if ( i == ACTIVE_NOTIFS_MAX ) {
if (i == ACTIVE_NOTIFS_MAX) {
return -1; /* Full */
}
@ -320,7 +334,7 @@ int play_source(uint32_t source, uint32_t buffer, bool looping)
#elif BOX_NOTIFY
void *do_playing(void *_p)
{
(void)_p;
UNUSED_VAR(_p);
while (true) {
control_lock();
@ -338,8 +352,9 @@ void *do_playing(void *_p)
notify_notification_close(actives[i].box, &ignore);
actives[i].box = NULL;
if (actives[i].id_indicator)
if (actives[i].id_indicator) {
*actives[i].id_indicator = -1; /* reset indicator value */
}
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
}
@ -352,7 +367,7 @@ void *do_playing(void *_p)
pthread_exit(NULL);
}
void graceful_clear()
void graceful_clear(void)
{
int i;
control_lock();
@ -364,15 +379,16 @@ void graceful_clear()
actives[i].box = NULL;
}
if (actives[i].id_indicator)
if (actives[i].id_indicator) {
*actives[i].id_indicator = -1; /* reset indicator value */
}
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
}
control_unlock();
}
#endif
#endif /* SOUND_NOTIFY */
/**********************************************************************************/
/**********************************************************************************/
@ -391,19 +407,20 @@ int init_notify(int login_cooldown, int notification_timeout)
#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;
}
Control.poll_active = 1;
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);
Control.poll_active = 0;
return -1;
}
#endif
#endif /* defined(SOUND_NOTIFY) || defined(BOX_NOTIFY) */
Control.cooldown = time(NULL) + login_cooldown;
@ -414,12 +431,12 @@ int init_notify(int login_cooldown, int notification_timeout)
return 1;
}
void terminate_notify()
void terminate_notify(void)
{
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
control_lock();
if ( !Control.poll_active ) {
if (!Control.poll_active) {
control_unlock();
return;
}
@ -428,12 +445,14 @@ void terminate_notify()
control_unlock();
graceful_clear();
#endif
#endif /* defined(SOUND_NOTIFY) || defined(BOX_NOTIFY) */
#ifdef SOUND_NOTIFY
int i = 0;
for (; i < SOUNDS_SIZE; i ++) free(Control.sounds[i]);
for (; i < SOUNDS_SIZE; i ++) {
free(Control.sounds[i]);
}
alutExit();
#endif /* SOUND_NOTIFY */
@ -446,7 +465,9 @@ void terminate_notify()
#ifdef SOUND_NOTIFY
int set_sound(Notification sound, const char *value)
{
if (sound == silent) return 0;
if (sound == silent) {
return 0;
}
free(Control.sounds[sound]);
@ -487,11 +508,14 @@ int play_notify_sound(Notification notif, uint64_t flags)
{
int rc = -1;
if (flags & NT_BEEP) beep();
if (flags & NT_BEEP) {
beep();
}
if (notif != silent) {
if ( !Control.poll_active || !Control.sounds[notif] )
if (!Control.poll_active || !Control.sounds[notif]) {
return -1;
}
rc = play_sound_internal(notif, flags & NT_LOOP ? 1 : 0);
}
@ -502,7 +526,7 @@ int play_notify_sound(Notification notif, uint64_t flags)
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
if (actives[id].box) {
@ -510,19 +534,20 @@ void stop_sound(int id)
notify_notification_close(actives[id].box, &ignore);
}
#endif
#endif /* BOX_NOTIFY */
if (actives[id].id_indicator)
if (actives[id].id_indicator) {
*actives[id].id_indicator = -1;
}
// alSourcei(actives[id].source, AL_LOOPING, false);
// alSourcei(actives[id].source, AL_LOOPING, false);
alSourceStop(actives[id].source);
alDeleteSources(1, &actives[id].source);
alDeleteBuffers(1, &actives[id].buffer);
memset(&actives[id], 0, sizeof(struct _ActiveNotifications));
}
}
#endif
#endif /* SOUND_NOTIFY */
static int m_play_sound(Notification notif, uint64_t flags)
{
@ -530,48 +555,45 @@ static int m_play_sound(Notification notif, uint64_t flags)
return play_notify_sound(notif, flags);
#else
if (notif != silent)
if (notif != silent) {
beep();
}
return -1;
#endif /* SOUND_NOTIFY */
}
#ifdef BOX_NOTIFY
void m_notify_action(NotifyNotification *box, char *action, void *data)
{
}
#endif
int sound_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indicator)
{
tab_notify(self, flags);
if (notifications_are_disabled(flags))
if (notifications_are_disabled(flags)) {
return -1;
}
int id = -1;
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);
else if (flags & NT_ALWAYS)
} else if (flags & NT_ALWAYS) {
id = m_play_sound(notif, flags);
}
#if defined(BOX_NOTIFY) && !defined(SOUND_NOTIFY)
if (id == -1) {
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].box; id++);
if ( id == ACTIVE_NOTIFS_MAX ) {
if (id == ACTIVE_NOTIFS_MAX) {
control_unlock();
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;
*id_indicator = id;
}
@ -585,10 +607,13 @@ int sound_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id)
{
tab_notify(self, flags);
if (notifications_are_disabled(flags))
if (notifications_are_disabled(flags)) {
return -1;
}
if (id < 0 || id >= ACTIVE_NOTIFS_MAX) return -1;
if (id < 0 || id >= ACTIVE_NOTIFS_MAX) {
return -1;
}
#ifdef SOUND_NOTIFY
control_lock();
@ -617,8 +642,9 @@ int sound_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id)
return id;
#else
if (notif != silent)
if (notif != silent) {
beep();
}
return 0;
#endif /* SOUND_NOTIFY */
@ -644,7 +670,7 @@ int box_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indi
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++);
if ( id == ACTIVE_NOTIFS_MAX ) {
if (id == ACTIVE_NOTIFS_MAX) {
control_unlock();
return -1; /* Full */
}
@ -652,27 +678,33 @@ int box_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indi
actives[id].active = 1;
actives[id].id_indicator = id_indicator;
if (id_indicator) *id_indicator = id;
if (id_indicator) {
*id_indicator = id;
}
}
#else
if (id == -1)
if (id == -1) {
return -1;
}
#endif /* SOUND_NOTIFY */
#endif /* SOUND_NOTIFY */
snprintf(actives[id].title, sizeof(actives[id].title), "%s", title);
if (strlen(title) > 23) strcpy(actives[id].title + 20, "...");
if (strlen(title) > 23) {
strcpy(actives[id].title + 20, "...");
}
va_list __ARGS__;
va_start (__ARGS__, format);
vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
va_end (__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)
if (strlen(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].size++;
@ -687,7 +719,7 @@ int box_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indi
return id;
#else
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, ...)
@ -699,8 +731,9 @@ int box_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id, con
#ifdef BOX_NOTIFY
if (sound_notify2(self, notif, flags, id) == -1)
if (sound_notify2(self, notif, flags, id) == -1) {
return -1;
}
control_lock();
@ -710,12 +743,13 @@ int box_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id, con
}
va_list __ARGS__;
va_start (__ARGS__, format);
vsnprintf (actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __ARGS__);
va_end (__ARGS__);
va_start(__ARGS__, format);
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, "...");
}
actives[id].size++;
actives[id].n_timeout = get_unix_time() + Control.notif_timeout / 1000;
@ -739,15 +773,16 @@ int box_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id, con
return id;
#else
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, ...)
{
tab_notify(self, flags);
if (notifications_are_disabled(flags))
if (notifications_are_disabled(flags)) {
return -1;
}
#ifdef BOX_NOTIFY
@ -757,7 +792,7 @@ int box_silent_notify(ToxWindow *self, uint64_t flags, int *id_indicator, const
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++);
if ( id == ACTIVE_NOTIFS_MAX ) {
if (id == ACTIVE_NOTIFS_MAX) {
control_unlock();
return -1; /* Full */
}
@ -769,15 +804,18 @@ int box_silent_notify(ToxWindow *self, uint64_t flags, int *id_indicator, const
snprintf(actives[id].title, sizeof(actives[id].title), "%s", title);
if (strlen(title) > 23) strcpy(actives[id].title + 20, "...");
if (strlen(title) > 23) {
strcpy(actives[id].title + 20, "...");
}
va_list __ARGS__;
va_start (__ARGS__, format);
vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
va_end (__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)
if (strlen(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].box = notify_notification_new(actives[id].title, actives[id].messages[0], NULL);
@ -793,32 +831,34 @@ int box_silent_notify(ToxWindow *self, uint64_t flags, int *id_indicator, const
return id;
#else
return -1;
#endif
#endif /* BOX_NOTIFY */
}
int box_silent_notify2(ToxWindow *self, uint64_t flags, int id, const char *format, ...)
{
tab_notify(self, flags);
if (notifications_are_disabled(flags))
if (notifications_are_disabled(flags)) {
return -1;
}
#ifdef BOX_NOTIFY
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();
return -1;
}
va_list __ARGS__;
va_start (__ARGS__, format);
vsnprintf (actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __ARGS__);
va_end (__ARGS__);
va_start(__ARGS__, format);
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, "...");
}
actives[id].size ++;
actives[id].n_timeout = get_unix_time() + Control.notif_timeout / 1000;
@ -842,5 +882,5 @@ int box_silent_notify2(ToxWindow *self, uint64_t flags, int id, const char *form
return id;
#else
return -1;
#endif
#endif /* BOX_NOTIFY */
}

View File

@ -23,7 +23,7 @@
#ifndef NOTIFY_H
#define NOTIFY_H
#include <inttypes.h>
#include <stdint.h>
#include "windows.h"
typedef enum _Notification {
@ -60,7 +60,7 @@ typedef enum _Flags {
} Flags;
int init_notify(int login_cooldown, int notification_timeout);
void terminate_notify();
void terminate_notify(void);
int sound_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indicator);
int sound_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id);

View File

@ -45,7 +45,7 @@ void bgrtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *
#endif /* __OBJC__ */
int osx_video_init(char **device_names, int *size);
void osx_video_release();
void osx_video_release(void);
/* Start device */
int osx_video_open_device(uint32_t selection, uint16_t *width, uint16_t *height);
/* Stop device */
@ -54,4 +54,4 @@ 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);
#endif /* OSX_VIDEO_H */
#endif /* OSX_VIDEO_H */

View File

@ -144,8 +144,9 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
device_names[i] = video_input_name;
}
if ( i <= 0 )
if (i <= 0) {
return nil;
}
*size = i;
@ -174,7 +175,7 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
NSError *error = NULL;
AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice: device error: &error];
if ( error != NULL ) {
if (error != NULL) {
[input release];
return -1;
}
@ -193,7 +194,7 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
AVCaptureInputPort *port = [input.ports objectAtIndex: 0];
CMFormatDescriptionRef format_description = port.formatDescription;
if ( format_description ) {
if (format_description) {
CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(format_description);
*width = dimensions.width;
*height = dimensions.height;
@ -303,8 +304,9 @@ int osx_video_init(char **device_names, int *size)
{
_OSXVideo = [[OSXVideo alloc] initWithDeviceNames: device_names AmtDevices: size];
if ( _OSXVideo == nil )
if (_OSXVideo == nil) {
return -1;
}
return 0;
}
@ -317,8 +319,9 @@ void osx_video_release()
int osx_video_open_device(uint32_t selection, uint16_t *width, uint16_t *height)
{
if ( _OSXVideo == nil )
if (_OSXVideo == nil) {
return -1;
}
return [_OSXVideo openVideoDeviceIndex: selection Width: width Height: height];
}
@ -330,8 +333,9 @@ void osx_video_close_device(uint32_t device_idx)
int osx_video_read_device(uint8_t *y, uint8_t *u, uint8_t *v, uint16_t *width, uint16_t *height)
{
if ( _OSXVideo == nil )
if (_OSXVideo == nil) {
return -1;
}
return [_OSXVideo getVideoFrameY: y U: u V: v Width: width Height: height];
}
@ -339,4 +343,4 @@ int osx_video_read_device(uint8_t *y, uint8_t *u, uint8_t *v, uint16_t *width, u
* End of C-interface for OSXVideo
*/
#endif /* __OBJC__ */
#endif /* __OBJC__ */

View File

@ -49,19 +49,27 @@ extern struct Winthread Winthread;
extern FriendsList Friends;
FriendRequests FrndRequests;
#if defined(PYTHON) && defined(VIDEO)
#define AC_NUM_GLOB_COMMANDS 23
#elif defined(PYTHON) && defined(AUDIO)
#define AC_NUM_GLOB_COMMANDS 21
#elif VIDEO
#define AC_NUM_GLOB_COMMANDS 22
#elif AUDIO
#define AC_NUM_GLOB_COMMANDS 20
#elif PYTHON
#define AC_NUM_GLOB_COMMANDS 19
#ifdef AUDIO
#define AC_NUM_GLOB_COMMANDS_AUDIO 2
#else
#define AC_NUM_GLOB_COMMANDS 18
#endif
#define AC_NUM_GLOB_COMMANDS_AUDIO 0
#endif /* AUDIO */
#ifdef VIDEO
#define AC_NUM_GLOB_COMMANDS_VIDEO 2
#else
#define AC_NUM_GLOB_COMMANDS_VIDEO 0
#endif /* VIDEO */
#ifdef PYTHON
#define AC_NUM_GLOB_COMMANDS_PYTHON 1
#else
#define AC_NUM_GLOB_COMMANDS_PYTHON 0
#endif /* PYTHON */
#ifdef QRCODE
#define AC_NUM_GLOB_COMMANDS_QRCODE 1
#else
#define AC_NUM_GLOB_COMMANDS_QRCODE 0
#endif /* QRCODE */
#define AC_NUM_GLOB_COMMANDS (17 + AC_NUM_GLOB_COMMANDS_AUDIO + AC_NUM_GLOB_COMMANDS_VIDEO + AC_NUM_GLOB_COMMANDS_PYTHON + AC_NUM_GLOB_COMMANDS_QRCODE)
/* Array of global command names used for tab completion. */
static const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
@ -76,7 +84,9 @@ static const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/help" },
{ "/log" },
{ "/myid" },
#ifdef QRCODE
{ "/myqr" },
#endif /* QRCODE */
{ "/nick" },
{ "/note" },
{ "/nospam" },
@ -127,8 +137,10 @@ void kill_prompt_window(ToxWindow *self)
}
/* 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->connection = connection_status;
}
@ -149,22 +161,23 @@ void prompt_update_statusmessage(ToxWindow *prompt, Tox *m, const char *statusms
size_t len = strlen(statusbar->statusmsg);
statusbar->statusmsg_len = len;
TOX_ERR_SET_INFO err;
tox_self_set_status_message(m, (uint8_t *) statusmsg, len, &err);
Tox_Err_Set_Info 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);
}
}
/* 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->status = status;
}
/* Returns our own connection status */
TOX_CONNECTION prompt_selfConnectionStatus(void)
Tox_Connection prompt_selfConnectionStatus(void)
{
StatusBar *statusbar = prompt->stb;
return statusbar->connection;
@ -174,8 +187,9 @@ TOX_CONNECTION prompt_selfConnectionStatus(void)
Returns request number on success, -1 if queue is full. */
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;
}
int i;
@ -185,8 +199,9 @@ static int add_friend_request(const char *public_key, const char *data)
memcpy(FrndRequests.request[i].key, public_key, TOX_PUBLIC_KEY_SIZE);
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.num_requests;
@ -197,7 +212,10 @@ static int add_friend_request(const char *public_key, const char *data)
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;
@ -205,38 +223,51 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
getyx(self->window, y, x);
getmaxyx(self->window, y2, x2);
if (x2 <= 0 || y2 <= 0)
return;
UNUSED_VAR(y);
if (ctx->pastemode && key == '\r')
if (x2 <= 0 || y2 <= 0) {
return false;
}
if (ctx->pastemode && key == '\r') {
key = '\n';
}
/* ignore non-menu related input if active */
if (self->help->active) {
help_onKey(self, key);
return;
return true;
}
if (ltr || key == '\n') { /* char is printable */
input_new_char(self, key, x, y, x2, y2);
return;
input_new_char(self, key, x, x2);
return true;
}
if (line_info_onKey(self, key))
return;
if (line_info_onKey(self, key)) {
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 */
input_ret = true;
if (ctx->len > 1 && ctx->line[0] == '/') {
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");
}
#ifdef PYTHON
else if (wcsncmp(ctx->line, L"/run \"", wcslen(L"/run \"")) == 0)
else if (wcsncmp(ctx->line, L"/run ", wcslen(L"/run ")) == 0) {
diff = dir_match(self, m, ctx->line, L"/run");
}
#endif
@ -247,8 +278,9 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
{"busy"},
};
diff = complete_line(self, status_cmd_list, 3, 8);
} else
} else {
diff = complete_line(self, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
}
if (diff != -1) {
if (x + diff > x2 - 1) {
@ -262,6 +294,8 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
sound_notify(self, notif_error, 0, NULL);
}
} else if (key == '\r') {
input_ret = true;
rm_trailing_spaces_buf(ctx);
if (!wstring_is_empty(ctx->line)) {
@ -270,8 +304,9 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
char line[MAX_STR_SIZE] = {0};
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
memset(&line, 0, sizeof(line));
}
line_info_add(self, NULL, NULL, NULL, PROMPT, 0, 0, "%s", line);
execute(ctx->history, self, m, line, GLOBAL_COMMAND_MODE);
@ -281,6 +316,8 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
reset_buf(ctx);
}
return input_ret;
}
static void prompt_onDraw(ToxWindow *self, Tox *m)
@ -288,8 +325,9 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
int x2, y2;
getmaxyx(self->window, y2, x2);
if (y2 <= 0 || x2 <= 0)
if (y2 <= 0 || x2 <= 0) {
return;
}
ChatContext *ctx = self->chatwin;
@ -301,8 +339,9 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
curs_set(1);
if (ctx->len > 0)
if (ctx->len > 0) {
mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]);
}
StatusBar *statusbar = self->stb;
@ -310,7 +349,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
wmove(statusbar->topline, 0, 0);
pthread_mutex_lock(&Winthread.lock);
TOX_CONNECTION connection = statusbar->connection;
Tox_Connection connection = statusbar->connection;
pthread_mutex_unlock(&Winthread.lock);
if (connection != TOX_CONNECTION_NONE) {
@ -318,7 +357,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
const char *status_text = "ERROR";
pthread_mutex_lock(&Winthread.lock);
TOX_USER_STATUS status = statusbar->status;
Tox_User_Status status = statusbar->status;
pthread_mutex_unlock(&Winthread.lock);
switch (status) {
@ -362,7 +401,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
pthread_mutex_lock(&Winthread.lock);
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';
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
statusbar->statusmsg_len = strlen(statusbar->statusmsg);
@ -382,8 +421,9 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
statusbar->statusmsg_len = maxlen;
}
if (statusbar->statusmsg[0])
if (statusbar->statusmsg[0]) {
wprintw(statusbar->topline, " : %s", statusbar->statusmsg);
}
pthread_mutex_unlock(&Winthread.lock);
@ -391,26 +431,29 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
int 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));
wmove(self->window, y + 1, new_x);
wnoutrefresh(self->window);
if (self->help->active)
if (self->help->active) {
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;
char nick[TOX_MAX_NAME_LENGTH] = {0}; /* stop removing this initiation */
get_nick_truncate(m, nick, friendnum);
if (!nick[0])
if (!nick[0]) {
snprintf(nick, sizeof(nick), "%s", UNKNOWN_NAME);
}
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
@ -425,28 +468,33 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnu
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg);
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,
"%s has come online", nick );
else
"%s has come online", nick);
} else {
box_notify(self, user_log_in, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, &self->active_box,
"Toxic", "%s has come online", nick );
"Toxic", "%s has come online", nick);
}
} else if (connection_status == TOX_CONNECTION_NONE) {
msg = "has gone offline";
line_info_add(self, timefrmt, nick, NULL, DISCONNECTION, 0, RED, msg);
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,
"%s has gone offline", nick );
else
"%s has gone offline", nick);
} else {
box_notify(self, user_log_out, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, &self->active_box,
"Toxic", "%s has gone offline", nick );
"Toxic", "%s has gone offline", nick);
}
}
}
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;
char timefrmt[TIME_STR_SIZE];
@ -467,15 +515,16 @@ static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, con
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;
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);
}
(void) y2;
UNUSED_VAR(y2);
/* Init statusbar info */
StatusBar *statusbar = self->stb;
@ -491,12 +540,12 @@ void prompt_init_statusbar(ToxWindow *self, Tox *m)
size_t s_len = tox_self_get_status_message_size(m);
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';
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");
s_len = strlen(statusmsg);
statusmsg[s_len] = '\0';
@ -519,7 +568,7 @@ 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, 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);
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);
@ -532,8 +581,9 @@ static void prompt_onInit(ToxWindow *self, Tox *m)
int 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);
}
ChatContext *ctx = self->chatwin;
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
@ -542,8 +592,9 @@ static void prompt_onInit(ToxWindow *self, Tox *m)
ctx->log = calloc(1, sizeof(struct chatlog));
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);
}
line_info_init(ctx->hst);
@ -551,46 +602,51 @@ static void prompt_onInit(ToxWindow *self, Tox *m)
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)
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);
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);
}
}
ToxWindow new_prompt(void)
ToxWindow *new_prompt(void)
{
ToxWindow ret;
memset(&ret, 0, sizeof(ret));
ToxWindow *ret = calloc(1, sizeof(ToxWindow));
ret.num = -1;
ret.active = true;
ret.is_prompt = true;
if (ret == NULL) {
exit_toxic_err("failed in new_prompt", FATALERR_MEMORY);
}
ret.onKey = &prompt_onKey;
ret.onDraw = &prompt_onDraw;
ret.onInit = &prompt_onInit;
ret.onConnectionChange = &prompt_onConnectionChange;
ret.onFriendRequest = &prompt_onFriendRequest;
ret->num = -1;
ret->is_prompt = true;
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));
StatusBar *stb = calloc(1, sizeof(StatusBar));
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);
}
ret.chatwin = chatwin;
ret.stb = stb;
ret.help = help;
ret->chatwin = chatwin;
ret->stb = stb;
ret->help = help;
ret.active_box = -1;
ret->active_box = -1;
return ret;
}

View File

@ -40,20 +40,22 @@ typedef struct {
struct friend_request request[MAX_FRIEND_REQUESTS];
} FriendRequests;
ToxWindow new_prompt(void);
extern FriendRequests FrndRequests;
ToxWindow *new_prompt(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_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 kill_prompt_window(ToxWindow *self);
/* 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);
Tox_Connection prompt_selfConnectionStatus(void);
#endif /* end of include guard: PROMPT_H */

View File

@ -39,8 +39,9 @@ static PyObject *python_api_display(PyObject *self, PyObject *args)
{
const char *msg;
if (!PyArg_ParseTuple(args, "s", &msg))
if (!PyArg_ParseTuple(args, "s", &msg)) {
return NULL;
}
api_display(msg);
return Py_None;
@ -51,13 +52,15 @@ static PyObject *python_api_get_nick(PyObject *self, PyObject *args)
char *name;
PyObject *ret;
if (!PyArg_ParseTuple(args, ""))
if (!PyArg_ParseTuple(args, "")) {
return NULL;
}
name = api_get_nick();
if (name == NULL)
if (name == NULL) {
return NULL;
}
ret = Py_BuildValue("s", name);
free(name);
@ -68,8 +71,9 @@ static PyObject *python_api_get_status(PyObject *self, PyObject *args)
{
PyObject *ret = NULL;
if (!PyArg_ParseTuple(args, ""))
if (!PyArg_ParseTuple(args, "")) {
return NULL;
}
switch (api_get_status()) {
case TOX_USER_STATUS_NONE:
@ -93,13 +97,15 @@ static PyObject *python_api_get_status_message(PyObject *self, PyObject *args)
char *status;
PyObject *ret;
if (!PyArg_ParseTuple(args, ""))
if (!PyArg_ParseTuple(args, "")) {
return NULL;
}
status = api_get_status_message();
if (status == NULL)
if (status == NULL) {
return NULL;
}
ret = Py_BuildValue("s", status);
free(status);
@ -113,15 +119,17 @@ static PyObject *python_api_get_all_friends(PyObject *self, PyObject *args)
PyObject *cur, *ret;
char pubkey_buf[TOX_PUBLIC_KEY_SIZE * 2 + 1];
if (!PyArg_ParseTuple(args, ""))
if (!PyArg_ParseTuple(args, "")) {
return NULL;
}
friends = api_get_friendslist();
ret = PyList_New(0);
for (i = 0; i < friends.num_friends; i++) {
for (ii = 0; ii < TOX_PUBLIC_KEY_SIZE; ii++)
for (ii = 0; ii < TOX_PUBLIC_KEY_SIZE; ii++) {
snprintf(pubkey_buf + ii * 2, 3, "%02X", friends.list[i].pub_key[ii] & 0xff);
}
pubkey_buf[TOX_PUBLIC_KEY_SIZE * 2] = '\0';
cur = Py_BuildValue("(s,s)", friends.list[i].name, pubkey_buf);
@ -135,8 +143,9 @@ static PyObject *python_api_send(PyObject *self, PyObject *args)
{
const char *msg;
if (!PyArg_ParseTuple(args, "s", &msg))
if (!PyArg_ParseTuple(args, "s", &msg)) {
return NULL;
}
api_send(msg);
return Py_None;
@ -147,8 +156,9 @@ static PyObject *python_api_execute(PyObject *self, PyObject *args)
int mode;
const char *command;
if (!PyArg_ParseTuple(args, "si", &command, &mode))
if (!PyArg_ParseTuple(args, "si", &command, &mode)) {
return NULL;
}
api_execute(command, mode);
return Py_None;
@ -161,8 +171,9 @@ static PyObject *python_api_register(PyObject *self, PyObject *args)
const char *command, *help;
PyObject *callback;
if (!PyArg_ParseTuple(args, "ssO:register_command", &command, &help, &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");
@ -186,21 +197,24 @@ static PyObject *python_api_register(PyObject *self, PyObject *args)
Py_XINCREF(callback);
cur->next = malloc(sizeof(struct python_registered_func));
if (cur->next == NULL)
if (cur->next == NULL) {
return PyErr_NoMemory();
}
command_len = strlen(command);
cur->next->name = malloc(command_len + 1);
if (cur->next->name == NULL)
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)
if (cur->next->help == NULL) {
return PyErr_NoMemory();
}
strncpy(cur->next->help, help, help_len + 1);
cur->next->callback = callback;
@ -252,8 +266,9 @@ void terminate_python(void)
{
struct python_registered_func *cur, *old;
if (python_commands.name != NULL)
if (python_commands.name != NULL) {
free(python_commands.name);
}
for (cur = python_commands.next; cur != NULL;) {
old = cur;
@ -284,19 +299,22 @@ int do_python_command(int num_args, char (*args)[MAX_STR_SIZE])
struct python_registered_func *cur;
for (cur = &python_commands; cur != NULL; cur = cur->next) {
if (cur->name == NULL)
if (cur->name == NULL) {
continue;
}
if (!strcmp(args[0], cur->name)) {
args_strings = PyList_New(0);
for (i = 1; i < num_args; i++)
for (i = 1; i < num_args; i++) {
PyList_Append(args_strings, Py_BuildValue("s", args[i]));
}
callback_args = PyTuple_Pack(1, args_strings);
if (PyObject_CallObject(cur->callback, callback_args) == NULL)
if (PyObject_CallObject(cur->callback, callback_args) == NULL) {
api_display("Exception raised in callback function");
}
return 0;
}
@ -311,8 +329,9 @@ int python_num_registered_handlers(void)
struct python_registered_func *cur;
for (cur = &python_commands; cur != NULL; cur = cur->next) {
if (cur->name != NULL)
if (cur->name != NULL) {
n++;
}
}
return n;
@ -340,8 +359,9 @@ 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)
if (cur->name != NULL) {
wprintw(win, " %-29s: %.50s\n", cur->name, cur->help);
}
}
}
#endif /* PYTHON */

View File

@ -36,4 +36,4 @@ int python_num_registered_handlers(void);
int python_help_max_width(void);
void python_draw_handler_help(WINDOW *win);
#endif /* #define PYTHON_API_H */
#endif /* PYTHON_API_H */

View File

@ -20,6 +20,8 @@
*
*/
#ifdef QRCODE
#include <stdlib.h>
#include <qrencode.h>
#include <stdbool.h>
@ -50,8 +52,9 @@ int ID_to_QRcode_txt(const char *tox_id, const char *outfile)
{
FILE *fp = fopen(outfile, "wb");
if (fp == NULL)
if (fp == NULL) {
return -1;
}
QRcode *qr_obj = QRcode_encodeString(tox_id, 0, QR_ECLEVEL_L, QR_MODE_8, 0);
@ -63,14 +66,16 @@ int ID_to_QRcode_txt(const char *tox_id, const char *outfile)
size_t width = qr_obj->width;
size_t 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, "\n");
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);
}
const unsigned char *row_1 = qr_obj->data + width * i;
const unsigned char *row_2 = row_1 + width;
@ -79,18 +84,20 @@ int ID_to_QRcode_txt(const char *tox_id, const char *outfile)
bool x = row_1[j] & 1;
bool y = (i + 1) < width ? (row_2[j] & 1) : false;
if (x && y)
if (x && y) {
fprintf(fp, " ");
else if (x)
} else if (x) {
fprintf(fp, "%s", CHAR_2);
else if (y)
} else if (y) {
fprintf(fp, "%s", CHAR_3);
else
} else {
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, "\n");
}
@ -208,3 +215,5 @@ int ID_to_QRcode_png(const char *tox_id, const char *outfile)
return 0;
}
#endif /* QRPNG */
#endif /* QRCODE */

View File

@ -23,6 +23,8 @@
#ifndef QR_CODE
#define QR_CODE
#ifdef QRCODE
#define QRCODE_FILENAME_EXT ".QRcode"
/* Converts a tox ID string into a QRcode and prints it into the given filename.
@ -42,4 +44,6 @@ int ID_to_QRcode_txt(const char *tox_id, const char *outfile);
int ID_to_QRcode_png(const char *tox_id, const char *outfile);
#endif /* QRPNG */
#endif /* QRCODE */
#endif /* QR_CODE */

View File

@ -58,11 +58,13 @@ static struct ui_strings {
const char *native_colors;
const char *autolog;
const char *history_size;
const char *notification_timeout;
const char *show_typing_self;
const char *show_typing_other;
const char *show_welcome_msg;
const char *show_connection_msg;
const char *nodeslist_update_freq;
const char *autosave_freq;
const char *line_join;
const char *line_quit;
@ -85,11 +87,13 @@ static struct ui_strings {
"native_colors",
"autolog",
"history_size",
"notification_timeout",
"show_typing_self",
"show_typing_other",
"show_welcome_msg",
"show_connection_msg",
"nodeslist_update_freq",
"autosave_freq",
"line_join",
"line_quit",
"line_alert",
@ -112,11 +116,13 @@ static void ui_defaults(struct user_settings *settings)
settings->bell_on_invite = 0;
settings->colour_theme = DFLT_COLS;
settings->history_size = 700;
settings->notification_timeout = 3000;
settings->show_typing_self = SHOW_TYPING_ON;
settings->show_typing_other = SHOW_TYPING_ON;
settings->show_welcome_msg = SHOW_WELCOME_MSG_ON;
settings->show_connection_msg = SHOW_CONNECTION_MSG_ON;
settings->nodeslist_update_freq = 7;
settings->autosave_freq = 600;
snprintf(settings->line_join, LINE_HINT_MAX + 1, "%s", LINE_JOIN);
snprintf(settings->line_quit, LINE_HINT_MAX + 1, "%s", LINE_QUIT);
@ -124,10 +130,10 @@ static void ui_defaults(struct user_settings *settings)
snprintf(settings->line_normal, LINE_HINT_MAX + 1, "%s", LINE_NORMAL);
settings->mplex_away = MPLEX_ON;
snprintf (settings->mplex_away_note,
sizeof (settings->mplex_away_note),
"%s",
MPLEX_AWAY_NOTE);
snprintf(settings->mplex_away_note,
sizeof(settings->mplex_away_note),
"%s",
MPLEX_AWAY_NOTE);
}
static const struct keys_strings {
@ -139,8 +145,6 @@ static const struct keys_strings {
const char *half_page_up;
const char *half_page_down;
const char *page_bottom;
const char *peer_list_up;
const char *peer_list_down;
const char *toggle_peerlist;
const char *toggle_pastemode;
} key_strings = {
@ -152,8 +156,6 @@ static const struct keys_strings {
"half_page_up",
"half_page_down",
"page_bottom",
"peer_list_up",
"peer_list_down",
"toggle_peerlist",
"toggle_paste_mode",
};
@ -168,8 +170,6 @@ static void key_defaults(struct user_settings *settings)
settings->key_half_page_up = T_KEY_C_F;
settings->key_half_page_down = T_KEY_C_V;
settings->key_page_bottom = T_KEY_C_H;
settings->key_peer_list_up = T_KEY_C_LB;
settings->key_peer_list_down = T_KEY_C_RB;
settings->key_toggle_peerlist = T_KEY_C_B;
settings->key_toggle_pastemode = T_KEY_C_T;
}
@ -253,15 +253,18 @@ static int key_parse(const char **bind)
int len = strlen(*bind);
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;
}
}
if (strncasecmp(*bind, "tab", 3) == 0)
if (strncasecmp(*bind, "tab", 3) == 0) {
return T_KEY_TAB;
}
if (strncasecmp(*bind, "page", 4) == 0)
if (strncasecmp(*bind, "page", 4) == 0) {
return len == 6 ? KEY_PPAGE : KEY_NPAGE;
}
return -1;
}
@ -304,8 +307,9 @@ int settings_load(struct user_settings *s, const char *patharg)
if (!file_exists(path)) {
FILE *fp = fopen(path, "w");
if (fp == NULL)
if (fp == NULL) {
return -1;
}
fclose(fp);
}
@ -324,18 +328,18 @@ int settings_load(struct user_settings *s, const char *patharg)
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) {
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]");
}
}
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);
}
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);
}
@ -365,82 +369,89 @@ 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_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.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);
}
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);
}
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);
}
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);
}
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)) {
snprintf (s->mplex_away_note, sizeof (s->mplex_away_note), "%s", 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);
}
}
/* paths */
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);
int len = strlen(s->download_path);
/* 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';
else if (s->download_path[len - 1] != '/')
} else if (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);
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';
else if (s->chatlogs_path[len - 1] != '/')
} else if (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);
int len = strlen(str);
if (len >= sizeof(s->avatar_path))
if (len >= sizeof(s->avatar_path)) {
s->avatar_path[0] = '\0';
}
}
#ifdef PYTHON
if ( config_setting_lookup_string(setting, tox_strings.autorun_path, &str) ) {
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)
if (len >= sizeof(s->autorun_path) - 2) {
s->autorun_path[0] = '\0';
else if (s->autorun_path[len - 1] != '/')
} else if (s->autorun_path[len - 1] != '/') {
strcat(&s->autorun_path[len - 1], "/");
}
}
#endif
if ( config_setting_lookup_string(setting, tox_strings.password_eval, &str) ) {
if (config_setting_lookup_string(setting, tox_strings.password_eval, &str)) {
snprintf(s->password_eval, sizeof(s->password_eval), "%s", str);
int len = strlen(str);
if (len >= sizeof(s->password_eval))
if (len >= sizeof(s->password_eval)) {
s->password_eval[0] = '\0';
}
}
}
@ -448,38 +459,41 @@ int settings_load(struct user_settings *s, const char *patharg)
if ((setting = config_lookup(cfg, key_strings.self)) != 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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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))
set_key_binding(&s->key_peer_list_down, &tmp);
if (config_setting_lookup_string(setting, key_strings.toggle_peerlist, &tmp))
if (config_setting_lookup_string(setting, key_strings.toggle_peerlist, &tmp)) {
set_key_binding(&s->key_toggle_peerlist, &tmp);
}
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);
}
}
#ifdef AUDIO
@ -499,52 +513,60 @@ int settings_load(struct user_settings *s, const char *patharg)
#ifdef SOUND_NOTIFY
if ((setting = config_lookup(cfg, sound_strings.self)) != NULL) {
if ( (config_setting_lookup_string(setting, sound_strings.notif_error, &str) != CONFIG_TRUE) ||
!set_sound(notif_error, str) ) {
if (str && strcasecmp(str, NO_SOUND) != 0)
if ((config_setting_lookup_string(setting, sound_strings.notif_error, &str) != CONFIG_TRUE) ||
!set_sound(notif_error, str)) {
if (str && strcasecmp(str, NO_SOUND) != 0) {
set_sound(notif_error, PACKAGE_DATADIR "/sounds/ToxicError.wav");
}
}
if ( !config_setting_lookup_string(setting, sound_strings.user_log_in, &str) ||
!set_sound(user_log_in, str) ) {
if (str && strcasecmp(str, NO_SOUND) != 0)
if (!config_setting_lookup_string(setting, sound_strings.user_log_in, &str) ||
!set_sound(user_log_in, str)) {
if (str && strcasecmp(str, NO_SOUND) != 0) {
set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ToxicContactOnline.wav");
}
}
if ( !config_setting_lookup_string(setting, sound_strings.user_log_out, &str) ||
!set_sound(user_log_out, str) ) {
if (str && strcasecmp(str, NO_SOUND) != 0)
if (!config_setting_lookup_string(setting, sound_strings.user_log_out, &str) ||
!set_sound(user_log_out, str)) {
if (str && strcasecmp(str, NO_SOUND) != 0) {
set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ToxicContactOffline.wav");
}
}
if ( !config_setting_lookup_string(setting, sound_strings.call_incoming, &str) ||
!set_sound(call_incoming, str) ) {
if (str && strcasecmp(str, NO_SOUND) != 0)
if (!config_setting_lookup_string(setting, sound_strings.call_incoming, &str) ||
!set_sound(call_incoming, str)) {
if (str && strcasecmp(str, NO_SOUND) != 0) {
set_sound(call_incoming, PACKAGE_DATADIR "/sounds/ToxicIncomingCall.wav");
}
}
if ( !config_setting_lookup_string(setting, sound_strings.call_outgoing, &str) ||
!set_sound(call_outgoing, str) ) {
if (str && strcasecmp(str, NO_SOUND) != 0)
if (!config_setting_lookup_string(setting, sound_strings.call_outgoing, &str) ||
!set_sound(call_outgoing, str)) {
if (str && strcasecmp(str, NO_SOUND) != 0) {
set_sound(call_outgoing, PACKAGE_DATADIR "/sounds/ToxicOutgoingCall.wav");
}
}
if ( !config_setting_lookup_string(setting, sound_strings.generic_message, &str) ||
!set_sound(generic_message, str) ) {
if (str && strcasecmp(str, NO_SOUND) != 0)
if (!config_setting_lookup_string(setting, sound_strings.generic_message, &str) ||
!set_sound(generic_message, str)) {
if (str && strcasecmp(str, NO_SOUND) != 0) {
set_sound(generic_message, PACKAGE_DATADIR "/sounds/ToxicRecvMessage.wav");
}
}
if ( !config_setting_lookup_string(setting, sound_strings.transfer_pending, &str) ||
!set_sound(transfer_pending, str) ) {
if (str && strcasecmp(str, NO_SOUND) != 0)
if (!config_setting_lookup_string(setting, sound_strings.transfer_pending, &str) ||
!set_sound(transfer_pending, str)) {
if (str && strcasecmp(str, NO_SOUND) != 0) {
set_sound(transfer_pending, PACKAGE_DATADIR "/sounds/ToxicTransferStart.wav");
}
}
if ( !config_setting_lookup_string(setting, sound_strings.transfer_completed, &str) ||
!set_sound(transfer_completed, str) ) {
if (str && strcasecmp(str, NO_SOUND) != 0)
if (!config_setting_lookup_string(setting, sound_strings.transfer_completed, &str) ||
!set_sound(transfer_completed, str)) {
if (str && strcasecmp(str, NO_SOUND) != 0) {
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/ToxicTransferComplete.wav");
}
}
} else {
set_sound(notif_error, PACKAGE_DATADIR "/sounds/ToxicError.wav");

View File

@ -49,11 +49,13 @@ struct user_settings {
int colour_theme; /* boolean (0 for default toxic colours) */
int history_size; /* int between MIN_HISTORY and MAX_HISTORY */
int notification_timeout;
int show_typing_self; /* boolean */
int show_typing_other; /* boolean */
int show_welcome_msg; /* boolean */
int show_connection_msg; /* boolean */
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_quit[LINE_HINT_MAX + 1];
@ -73,8 +75,6 @@ struct user_settings {
int key_half_page_up;
int key_half_page_down;
int key_page_bottom;
int key_peer_list_up;
int key_peer_list_down;
int key_toggle_peerlist;
int key_toggle_pastemode;
@ -125,4 +125,5 @@ enum settings_values {
#define MPLEX_AWAY_NOTE "Detached from screen"
int settings_load(struct user_settings *s, const char *patharg);
#endif /* #define SETTINGS_H */
#endif /* SETTINGS_H */

View File

@ -33,7 +33,7 @@
#include <tox/tox.h>
#include "global_commands.h"
#include "execute.h"
#include "windows.h"
#include "term_mplex.h"
#include "toxic.h"
@ -69,7 +69,7 @@ static char buffer [BUFFER_SIZE];
static bool auto_away_active = false;
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] = "";
/* mutex for access to status data, for sync between:
@ -80,108 +80,118 @@ static char prev_note [TOX_MAX_STATUS_MESSAGE_LENGTH] = "";
static pthread_mutex_t status_lock;
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;
char *dyn_buffer = NULL;
int dyn_buffer_size = 1; /* account for the \0 */
while ((input_ptr = fgets (buffer, BUFFER_SIZE, stream)) != NULL) {
int length = dyn_buffer_size + strlen (input_ptr);
while ((input_ptr = fgets(buffer, BUFFER_SIZE, stream)) != NULL) {
int length = dyn_buffer_size + strlen(input_ptr);
if (dyn_buffer)
dyn_buffer = (char *) realloc (dyn_buffer, length);
else
dyn_buffer = (char *) malloc (length);
if (dyn_buffer) {
dyn_buffer = (char *) realloc(dyn_buffer, length);
} else {
dyn_buffer = (char *) malloc(length);
}
strcpy (dyn_buffer + dyn_buffer_size - 1, input_ptr);
strcpy(dyn_buffer + dyn_buffer_size - 1, input_ptr);
dyn_buffer_size = length;
}
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 *pos = strstr (info, search_str);
const char *pos = strstr(info, search_str);
char *end = NULL;
char *path = NULL;
if (!pos)
if (!pos) {
return NULL;
}
pos += strlen (search_str);
pos = strchr (pos, PATH_SEP_C);
pos += strlen(search_str);
pos = strchr(pos, PATH_SEP_C);
if (!pos)
if (!pos) {
return NULL;
}
end = strchr (pos, '\n');
end = strchr(pos, '\n');
if (!end)
if (!end) {
return NULL;
}
*end = '\0';
end = strrchr (pos, '.');
end = strrchr(pos, '.');
if (!end)
if (!end) {
return NULL;
}
path = (char *) malloc (end - pos + 1);
path = (char *) malloc(end - pos + 1);
*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;
char *socket_name = NULL, *socket_path = NULL;
char *dyn_buffer = NULL;
socket_name = getenv ("STY");
socket_name = getenv("STY");
if (!socket_name)
if (!socket_name) {
goto nomplex;
}
session_info_stream = popen ("env LC_ALL=C screen -ls", "r");
session_info_stream = popen("env LC_ALL=C screen -ls", "r");
if (!session_info_stream)
if (!session_info_stream) {
goto nomplex;
}
dyn_buffer = read_into_dyn_buffer (session_info_stream);
dyn_buffer = read_into_dyn_buffer(session_info_stream);
if (!dyn_buffer)
if (!dyn_buffer) {
goto nomplex;
}
pclose (session_info_stream);
pclose(session_info_stream);
session_info_stream = NULL;
socket_path = extract_socket_path (dyn_buffer);
socket_path = extract_socket_path(dyn_buffer);
if (!socket_path)
if (!socket_path) {
goto nomplex;
}
free (dyn_buffer);
free(dyn_buffer);
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;
}
strcpy (mplex_data, socket_path);
strcat (mplex_data, PATH_SEP_S);
strcat (mplex_data, socket_name);
free (socket_path);
strcpy(mplex_data, socket_path);
strcat(mplex_data, PATH_SEP_S);
strcat(mplex_data, socket_name);
free(socket_path);
socket_path = NULL;
mplex = MPLEX_SCREEN;
@ -189,33 +199,38 @@ static int detect_gnu_screen ()
nomplex:
if (session_info_stream)
pclose (session_info_stream);
if (session_info_stream) {
pclose(session_info_stream);
}
if (dyn_buffer)
free (dyn_buffer);
if (dyn_buffer) {
free(dyn_buffer);
}
if (socket_path)
if (socket_path) {
free(socket_path);
}
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;
}
/* find second separator */
pos = strrchr (tmux_env, ',');
pos = strrchr(tmux_env, ',');
if (!pos)
if (!pos) {
return 0;
}
/* store the session id for later use */
snprintf (mplex_data, sizeof(mplex_data), "$%s", pos + 1);
snprintf(mplex_data, sizeof(mplex_data), "$%s", pos + 1);
mplex = MPLEX_TMUX;
return 1;
}
@ -228,92 +243,102 @@ static int detect_tmux ()
Returns 1 if present, 0 otherwise. This value can be used to determine
whether an auto-away detection timer is needed.
*/
static int detect_mplex ()
static int detect_mplex(void)
{
/* 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
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;
}
struct stat sb;
if (stat (mplex_data, &sb) != 0)
if (stat(mplex_data, &sb) != 0) {
return 0;
}
/* 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
current session's entry.
*/
static int tmux_is_detached ()
static int tmux_is_detached(void)
{
if (mplex != MPLEX_TMUX)
if (mplex != MPLEX_TMUX) {
return 0;
}
FILE *session_info_stream = NULL;
char *dyn_buffer = NULL, *search_str = NULL;
char *entry_pos;
int detached;
const int numstr_len = strlen (mplex_data);
const int numstr_len = strlen(mplex_data);
/* get the number of attached clients for each session */
session_info_stream = popen ("tmux list-sessions -F \"#{session_id} #{session_attached}\"", "r");
session_info_stream = popen("tmux list-sessions -F \"#{session_id} #{session_attached}\"", "r");
if (!session_info_stream)
if (!session_info_stream) {
goto fail;
}
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;
}
pclose (session_info_stream);
pclose(session_info_stream);
session_info_stream = NULL;
/* prepare search string, for finding the current session's entry */
search_str = (char *) malloc (numstr_len + 2);
search_str = (char *) malloc(numstr_len + 2);
search_str[0] = '\n';
strcpy (search_str + 1, mplex_data);
strcpy(search_str + 1, mplex_data);
/* do the search */
if (strncmp (dyn_buffer, search_str + 1, numstr_len) == 0)
if (strncmp(dyn_buffer, search_str + 1, numstr_len) == 0) {
entry_pos = dyn_buffer;
else
entry_pos = strstr (dyn_buffer, search_str);
} else {
entry_pos = strstr(dyn_buffer, search_str);
}
if (! entry_pos)
if (! entry_pos) {
goto fail;
}
entry_pos = strchr (entry_pos, ' ') + 1;
detached = strncmp (entry_pos, "0\n", 2) == 0;
entry_pos = strchr(entry_pos, ' ') + 1;
detached = strncmp(entry_pos, "0\n", 2) == 0;
free (search_str);
free(search_str);
search_str = NULL;
free (dyn_buffer);
free(dyn_buffer);
dyn_buffer = NULL;
return detached;
fail:
if (session_info_stream)
pclose (session_info_stream);
if (session_info_stream) {
pclose(session_info_stream);
}
if (dyn_buffer)
free (dyn_buffer);
if (dyn_buffer) {
free(dyn_buffer);
}
if (search_str)
free (search_str);
if (search_str) {
free(search_str);
}
return 0;
}
@ -327,24 +352,25 @@ fail:
sample its state and update away status according to attached/detached state
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;
if (mplex == MPLEX_NONE)
if (mplex == MPLEX_NONE) {
return;
}
int detached = mplex_is_detached ();
int detached = mplex_is_detached();
pthread_mutex_lock (&Winthread.lock);
current_status = tox_self_get_status (m);
pthread_mutex_unlock (&Winthread.lock);
pthread_mutex_lock(&Winthread.lock);
current_status = tox_self_get_status(m);
pthread_mutex_unlock(&Winthread.lock);
if (auto_away_active && current_status == TOX_USER_STATUS_AWAY && !detached) {
auto_away_active = false;
@ -354,25 +380,27 @@ static void mplex_timer_handler (Tox *m)
auto_away_active = true;
prev_status = current_status;
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);
tox_self_get_status_message (m, (uint8_t *) prev_note);
tox_self_get_status_message(m, (uint8_t *) prev_note);
prev_note[slen] = '\0';
pthread_mutex_unlock (&Winthread.lock);
pthread_mutex_unlock(&Winthread.lock);
new_note = user_settings->mplex_away_note;
} else
} else {
return;
}
char argv[3][MAX_STR_SIZE];
strcpy (argv[0], "/status");
strcpy (argv[1], (new_status == TOX_USER_STATUS_AWAY ? "away" :
new_status == TOX_USER_STATUS_BUSY ? "busy" : "online"));
argv[2][0] = '\"';
strcpy (argv[2] + 1, new_note);
strcat (argv[2], "\"");
pthread_mutex_lock (&Winthread.lock);
cmd_status (prompt->chatwin->history, prompt, m, 2, argv);
pthread_mutex_unlock (&Winthread.lock);
char status_str[MAX_STR_SIZE];
char note_str[MAX_STR_SIZE];
const char *status = new_status == TOX_USER_STATUS_AWAY ? "away" :
new_status == TOX_USER_STATUS_BUSY ? "busy" : "online";
snprintf(status_str, sizeof(status_str), "/status %s", status);
snprintf(note_str, sizeof(status_str), "/note %s", new_note);
pthread_mutex_lock(&Winthread.lock);
execute(prompt->chatwin->history, prompt, m, status_str, GLOBAL_COMMAND_MODE);
execute(prompt->chatwin->history, prompt, m, note_str, GLOBAL_COMMAND_MODE);
pthread_mutex_unlock(&Winthread.lock);
}
/* Time in seconds between calls to mplex_timer_handler */
@ -388,20 +416,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;
}
if (! user_settings->mplex_away)
if (! user_settings->mplex_away) {
return 0;
}
/* status access mutex */
if (pthread_mutex_init (&status_lock, NULL) != 0)
if (pthread_mutex_init(&status_lock, NULL) != 0) {
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 0;
}

View File

@ -24,12 +24,12 @@
#define TERM_MPLEX_H
/* Checks if Toxic runs inside a terminal multiplexer (GNU screen or tmux). If
yes, it initializes a timer which periodically checks the attached/detached
state of the terminal and updates away status accordingly.
* yes, it initializes a timer which periodically checks the attached/detached
* state of the terminal and updates away status accordingly.
*/
int init_mplex_away_timer (Tox *m);
int init_mplex_away_timer(Tox *m);
void lock_status ();
void unlock_status ();
void lock_status(void);
void unlock_status(void);
#endif /* #define TERM_MPLEX_H */
#endif /* TERM_MPLEX_H */

View File

@ -94,7 +94,6 @@ ToxWindow *prompt = NULL;
#define DATANAME "toxic_profile.tox"
#define BLOCKNAME "toxic_blocklist"
#define AUTOSAVE_FREQ 600
#define MIN_PASSWORD_LEN 6
#define MAX_PASSWORD_LEN 64
@ -115,6 +114,8 @@ static time_t last_signal_time;
static void catch_SIGINT(int sig)
{
UNUSED_VAR(sig);
time_t cur_time = get_unix_time();
if (difftime(cur_time, last_signal_time) <= 1) {
@ -126,7 +127,12 @@ static void catch_SIGINT(int sig)
static void catch_SIGSEGV(int sig)
{
freopen("/dev/tty", "w", stderr); // make sure stderr is enabled since we may have disabled it
UNUSED_VAR(sig);
if (!freopen("/dev/tty", "w", stderr)) { // make sure stderr is enabled since we may have disabled it
fprintf(stderr, "Warning: Failed to enable stderr\n");
}
endwin();
fprintf(stderr, "Caught SIGSEGV: Aborting toxic session.\n");
exit(EXIT_FAILURE);
@ -134,6 +140,8 @@ static void catch_SIGSEGV(int sig)
static void flag_window_resize(int sig)
{
UNUSED_VAR(sig);
Winthread.flag_resize = 1;
}
@ -166,9 +174,11 @@ void exit_toxic_success(Tox *m)
{
store_data(m, DATA_FILE);
memset(&user_password, 0, sizeof(struct user_password));
terminate_notify();
kill_all_file_transfers(m);
kill_all_windows(m);
terminate_notify();
#ifdef AUDIO
#ifdef VIDEO
@ -183,6 +193,12 @@ void exit_toxic_success(Tox *m)
free_global_data();
tox_kill(m);
if (arg_opts.log_fp != NULL) {
fclose(arg_opts.log_fp);
arg_opts.log_fp = NULL;
}
endwin();
curl_global_cleanup();
@ -199,12 +215,32 @@ void exit_toxic_success(Tox *m)
void exit_toxic_err(const char *errmsg, int errcode)
{
free_global_data();
freopen("/dev/tty", "w", stderr);
if (!freopen("/dev/tty", "w", stderr)) {
fprintf(stderr, "Warning: Failed to open stderr\n");
}
endwin();
fprintf(stderr, "Toxic session aborted with error code %d (%s)\n", errcode, errmsg);
exit(EXIT_FAILURE);
}
void cb_toxcore_logger(Tox *m, TOX_LOG_LEVEL level, const char *file, uint32_t line, const char *func,
const char *message, void *user_data)
{
UNUSED_VAR(user_data);
UNUSED_VAR(file);
UNUSED_VAR(m);
if (user_data) {
FILE *fp = (FILE *)user_data;
fprintf(fp, "[%d] %u:%s() - %s\n", level, line, func, message);
fflush(fp);
} else {
fprintf(stderr, "[%d] %u:%s() - %s\n", level, line, func, message);
}
}
static void init_term(void)
{
#if HAVE_WIDECHAR
@ -229,8 +265,9 @@ static void init_term(void)
start_color();
if (user_settings->colour_theme == NATIVE_COLS) {
if (assume_default_colors(-1, -1) == OK)
if (assume_default_colors(-1, -1) == OK) {
bg_color = -1;
}
}
init_pair(0, COLOR_WHITE, COLOR_BLACK);
@ -267,13 +304,15 @@ static void queue_init_message(const char *msg, ...)
char **new_msgs = realloc(init_messages.msgs, sizeof(char *) * init_messages.num);
if (new_msgs == NULL)
if (new_msgs == NULL) {
exit_toxic_err("Failed in queue_init_message", FATALERR_MEMORY);
}
new_msgs[i] = malloc(MAX_STR_SIZE);
if (new_msgs[i] == NULL)
if (new_msgs[i] == NULL) {
exit_toxic_err("Failed in queue_init_message", FATALERR_MEMORY);
}
snprintf(new_msgs[i], MAX_STR_SIZE, "%s", frmt_msg);
init_messages.msgs = new_msgs;
@ -282,13 +321,15 @@ static void queue_init_message(const char *msg, ...)
/* called after messages have been printed to prompt and are no longer needed */
static void cleanup_init_messages(void)
{
if (init_messages.num <= 0)
if (init_messages.num <= 0) {
return;
}
int i;
for (i = 0; i < init_messages.num; ++i)
for (i = 0; i < init_messages.num; ++i) {
free(init_messages.msgs[i]);
}
free(init_messages.msgs);
}
@ -297,8 +338,9 @@ static void print_init_messages(ToxWindow *toxwin)
{
int i;
for (i = 0; i < init_messages.num; ++i)
for (i = 0; i < init_messages.num; ++i) {
line_info_add(toxwin, NULL, NULL, NULL, SYS_MSG, 0, 0, init_messages.msgs[i]);
}
}
static void load_friendlist(Tox *m)
@ -313,17 +355,18 @@ static void load_friendlist(Tox *m)
sort_friendlist_index();
}
static void load_groups(ToxWindow *prompt, Tox *m)
static void load_conferences(Tox *m)
{
size_t i;
size_t num_chats = tox_conference_get_chatlist_size(m);
uint32_t chatlist[num_chats];
if (num_chats) {
tox_conference_get_chatlist(m, chatlist);
if (num_chats == 0) {
return;
}
for (i = 0; i < num_chats; ++i) {
uint32_t chatlist[num_chats];
tox_conference_get_chatlist(m, chatlist);
for (size_t i = 0; i < num_chats; ++i) {
uint32_t groupnum = chatlist[i];
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
@ -331,15 +374,31 @@ static void load_groups(ToxWindow *prompt, Tox *m)
continue;
}
TOX_ERR_CONFERENCE_GET_TYPE err;
TOX_CONFERENCE_TYPE type = tox_conference_get_type(m, groupnum, &err);
Tox_Err_Conference_Get_Type err;
Tox_Conference_Type type = tox_conference_get_type(m, groupnum, &err);
if (err != TOX_ERR_CONFERENCE_GET_TYPE_OK) {
tox_conference_delete(m, groupnum, NULL);
continue;
}
if (init_groupchat_win(prompt, m, groupnum, type) == -1) {
Tox_Err_Conference_Title t_err;
size_t length = tox_conference_get_title_size(m, groupnum, &t_err);
uint8_t title[MAX_STR_SIZE];
if (t_err != TOX_ERR_CONFERENCE_TITLE_OK || length >= sizeof(title)) {
length = 0;
} else {
tox_conference_get_title(m, groupnum, title, &t_err);
if (t_err != TOX_ERR_CONFERENCE_TITLE_OK) {
length = 0;
}
}
title[length] = 0;
if (init_groupchat_win(m, groupnum, type, (const char *) title, length) == -1) {
tox_conference_delete(m, groupnum, NULL);
continue;
}
@ -358,8 +417,9 @@ static int password_prompt(char *buf, int size)
nflags.c_lflag &= ~ECHO;
nflags.c_lflag |= ECHONL;
if (tcsetattr(fileno(stdin), TCSANOW, &nflags) != 0)
if (tcsetattr(fileno(stdin), TCSANOW, &nflags) != 0) {
return 0;
}
const char *p = fgets(buf, size, stdin);
int len = strlen(buf);
@ -367,15 +427,16 @@ static int password_prompt(char *buf, int size)
/* re-enable terminal echo */
tcsetattr(fileno(stdin), TCSANOW, &oflags);
if (p == NULL || len <= 1)
if (p == NULL || len <= 1) {
return 0;
}
/* eat overflowed stdin and return error */
if (buf[--len] != '\n') {
int ch;
while ((ch = getchar()) != '\n' && ch > 0)
;
while ((ch = getchar()) != '\n' && ch > 0) {
}
return 0;
}
@ -433,20 +494,22 @@ static void first_time_encrypt(const char *msg)
char ch[256] = {0};
do {
system("clear");
clear_screen();
printf("%s ", msg);
fflush(stdout);
if (!strcasecmp(ch, "y\n") || !strcasecmp(ch, "n\n") || !strcasecmp(ch, "yes\n")
|| !strcasecmp(ch, "no\n") || !strcasecmp(ch, "q\n"))
|| !strcasecmp(ch, "no\n") || !strcasecmp(ch, "q\n")) {
break;
}
} while (fgets(ch, sizeof(ch), stdin));
printf("\n");
if (ch[0] == 'q' || ch[0] == 'Q')
if (ch[0] == 'q' || ch[0] == 'Q') {
exit(0);
}
if (ch[0] == 'y' || ch[0] == 'Y') {
int len = 0;
@ -460,8 +523,9 @@ static void first_time_encrypt(const char *msg)
len = password_prompt(user_password.pass, sizeof(user_password.pass));
user_password.len = len;
if (strcasecmp(user_password.pass, "q") == 0)
if (strcasecmp(user_password.pass, "q") == 0) {
exit(0);
}
if (string_is_empty(passconfirm) && (len < MIN_PASSWORD_LEN || len > MAX_PASSWORD_LEN)) {
printf("Password must be between %d and %d characters long. ", MIN_PASSWORD_LEN, MAX_PASSWORD_LEN);
@ -489,7 +553,7 @@ static void first_time_encrypt(const char *msg)
user_password.data_is_encrypted = true;
}
system("clear");
clear_screen();
}
/* Store Tox profile data to path.
@ -533,7 +597,7 @@ int store_data(Tox *m, const char *path)
return -1;
}
TOX_ERR_ENCRYPTION err;
Tox_Err_Encryption err;
tox_pass_encrypt((uint8_t *) data, data_len, (uint8_t *) user_password.pass, user_password.len,
(uint8_t *) enc_data, &err);
@ -575,23 +639,23 @@ int store_data(Tox *m, const char *path)
static void init_tox_callbacks(Tox *m)
{
tox_callback_self_connection_status(m, prompt_onSelfConnectionChange);
tox_callback_friend_connection_status(m, on_connectionchange);
tox_callback_friend_typing(m, on_typing_change);
tox_callback_friend_request(m, on_request);
tox_callback_friend_message(m, on_message);
tox_callback_friend_name(m, on_nickchange);
tox_callback_friend_status(m, on_statuschange);
tox_callback_friend_status_message(m, on_statusmessagechange);
tox_callback_friend_read_receipt(m, on_read_receipt);
tox_callback_conference_invite(m, on_groupinvite);
tox_callback_conference_message(m, on_groupmessage);
tox_callback_conference_peer_list_changed(m, on_group_namelistchange);
tox_callback_conference_peer_name(m, on_group_peernamechange);
tox_callback_conference_title(m, on_group_titlechange);
tox_callback_self_connection_status(m, on_self_connection_status);
tox_callback_friend_connection_status(m, on_friend_connection_status);
tox_callback_friend_typing(m, on_friend_typing);
tox_callback_friend_request(m, on_friend_request);
tox_callback_friend_message(m, on_friend_message);
tox_callback_friend_name(m, on_friend_name);
tox_callback_friend_status(m, on_friend_status);
tox_callback_friend_status_message(m, on_friend_status_message);
tox_callback_friend_read_receipt(m, on_friend_read_receipt);
tox_callback_conference_invite(m, on_conference_invite);
tox_callback_conference_message(m, on_conference_message);
tox_callback_conference_peer_list_changed(m, on_conference_peer_list_changed);
tox_callback_conference_peer_name(m, on_conference_peer_name);
tox_callback_conference_title(m, on_conference_title);
tox_callback_file_recv(m, on_file_recv);
tox_callback_file_chunk_request(m, on_file_chunk_request);
tox_callback_file_recv_control(m, on_file_control);
tox_callback_file_recv_control(m, on_file_recv_control);
tox_callback_file_recv_chunk(m, on_file_recv_chunk);
}
@ -603,12 +667,23 @@ static void init_tox_options(struct Tox_Options *tox_opts)
tox_options_set_udp_enabled(tox_opts, !arg_opts.force_tcp);
tox_options_set_proxy_type(tox_opts, arg_opts.proxy_type);
tox_options_set_tcp_port(tox_opts, arg_opts.tcp_port);
tox_options_set_local_discovery_enabled(tox_opts, !arg_opts.disable_local_discovery);
if (!tox_options_get_ipv6_enabled(tox_opts))
if (arg_opts.logging) {
tox_options_set_log_callback(tox_opts, cb_toxcore_logger);
if (arg_opts.log_fp != NULL) {
tox_options_set_log_user_data(tox_opts, arg_opts.log_fp);
}
}
if (!tox_options_get_ipv6_enabled(tox_opts)) {
queue_init_message("Forcing IPv4 connection");
}
if (tox_options_get_tcp_port(tox_opts))
if (tox_options_get_tcp_port(tox_opts)) {
queue_init_message("TCP relaying enabled on port %d", tox_options_get_tcp_port(tox_opts));
}
if (tox_options_get_proxy_type(tox_opts) != TOX_PROXY_TYPE_NONE) {
tox_options_set_proxy_port(tox_opts, arg_opts.proxy_port);
@ -633,7 +708,7 @@ static void init_tox_options(struct Tox_Options *tox_opts)
/* Returns a new Tox object on success.
* If object fails to initialize the toxic process will terminate.
*/
static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW *new_err)
static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New *new_err)
{
Tox *m = NULL;
@ -662,20 +737,22 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
exit_toxic_err("failed in load_tox", FATALERR_ENCRYPT);
}
if (arg_opts.unencrypt_data && is_encrypted)
if (arg_opts.unencrypt_data && is_encrypted) {
queue_init_message("Data file '%s' has been unencrypted", data_path);
else if (arg_opts.unencrypt_data)
} else if (arg_opts.unencrypt_data) {
queue_init_message("Warning: passed --unencrypt-data option with unencrypted data file '%s'", data_path);
}
if (is_encrypted) {
if (!arg_opts.unencrypt_data)
if (!arg_opts.unencrypt_data) {
user_password.data_is_encrypted = true;
}
size_t pwlen = 0;
int pweval = user_settings->password_eval[0];
if (!pweval) {
system("clear"); // TODO: is this portable?
clear_screen();
printf("Enter password (q to quit) ");
}
@ -699,14 +776,14 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
}
if (pwlen < MIN_PASSWORD_LEN) {
system("clear");
clear_screen();
sleep(1);
printf("Invalid password. Try again. ");
pweval = 0;
continue;
}
TOX_ERR_DECRYPTION pwerr;
Tox_Err_Decryption pwerr;
tox_pass_decrypt((uint8_t *) data, len, (uint8_t *) user_password.pass, pwlen,
(uint8_t *) plain, &pwerr);
@ -723,7 +800,7 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
break;
} else if (pwerr == TOX_ERR_DECRYPTION_FAILED) {
system("clear");
clear_screen();
sleep(1);
printf("Invalid password. Try again. ");
pweval = 0;
@ -746,18 +823,21 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
fclose(fp);
} else { /* Data file does not/should not exist */
if (file_exists(data_path))
if (file_exists(data_path)) {
exit_toxic_err("failed in load_tox", FATALERR_FILEOP);
}
tox_options_set_savedata_type(tox_opts, TOX_SAVEDATA_TYPE_NONE);
m = tox_new(tox_opts, new_err);
if (m == NULL)
if (m == NULL) {
return NULL;
}
if (store_data(m, data_path) == -1)
if (store_data(m, data_path) == -1) {
exit_toxic_err("failed in load_tox", FATALERR_FILEOP);
}
}
return m;
@ -765,13 +845,16 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
static Tox *load_toxic(char *data_path)
{
TOX_ERR_OPTIONS_NEW options_new_err;
Tox_Err_Options_New options_new_err;
struct Tox_Options *tox_opts = tox_options_new(&options_new_err);
if (!tox_opts)
if (!tox_opts) {
exit_toxic_err("tox_options_new returned fatal error", options_new_err);
}
init_tox_options(tox_opts);
TOX_ERR_NEW new_err;
Tox_Err_New new_err;
Tox *m = load_tox(data_path, tox_opts, &new_err);
if (new_err == TOX_ERR_NEW_PORT_ALLOC && tox_options_get_ipv6_enabled(tox_opts)) {
@ -780,18 +863,21 @@ static Tox *load_toxic(char *data_path)
m = load_tox(data_path, tox_opts, &new_err);
}
if (!m)
if (!m) {
exit_toxic_err("tox_new returned fatal error", new_err);
}
if (new_err != TOX_ERR_NEW_OK)
if (new_err != TOX_ERR_NEW_OK) {
queue_init_message("tox_new returned non-fatal error %d", new_err);
}
init_tox_callbacks(m);
load_friendlist(m);
load_blocklist(BLOCK_FILE);
if (tox_self_get_name_size(m) == 0)
if (tox_self_get_name_size(m) == 0) {
tox_self_set_name(m, (uint8_t *) "Toxic User", strlen("Toxic User"), NULL);
}
tox_options_free(tox_opts);
return m;
@ -852,8 +938,9 @@ void *thread_cqueue(void *data)
ToxWindow *toxwin = get_window_ptr(i);
if (toxwin != NULL && toxwin->is_chat
&& get_friend_connection_status(toxwin->num) != TOX_CONNECTION_NONE)
&& get_friend_connection_status(toxwin->num) != TOX_CONNECTION_NONE) {
cqueue_try_send(toxwin, m);
}
}
pthread_mutex_unlock(&Winthread.lock);
@ -875,7 +962,7 @@ void *thread_av(void *data)
usleep(toxav_iteration_interval(av) * 1000);
}
}
#endif /* AUDIO */
#endif /* AUDIO */
static void print_usage(void)
{
@ -887,6 +974,8 @@ static void print_usage(void)
fprintf(stderr, " -e, --encrypt-data Encrypt an unencrypted data file\n");
fprintf(stderr, " -f, --file Use specified data file\n");
fprintf(stderr, " -h, --help Show this message and exit\n");
fprintf(stderr, " -l, --logging Enable toxcore logging: Requires [log_path | stderr]\n");
fprintf(stderr, " -L, --no-lan Disable local discovery\n");
fprintf(stderr, " -n, --nodes Use specified DHTnodes file\n");
fprintf(stderr, " -o, --noconnect Do not connect to the DHT network\n");
fprintf(stderr, " -p, --SOCKS5-proxy Use SOCKS5 proxy: Requires [IP] [port]\n");
@ -917,12 +1006,14 @@ static void parse_args(int argc, char *argv[])
set_default_opts();
static struct option long_opts[] = {
{"file", required_argument, 0, 'f'},
{"ipv4", no_argument, 0, '4'},
{"debug", no_argument, 0, 'b'},
{"default-locale", no_argument, 0, 'd'},
{"config", required_argument, 0, 'c'},
{"encrypt-data", no_argument, 0, 'e'},
{"file", required_argument, 0, 'f'},
{"logging", required_argument, 0, 'l'},
{"no-lan", no_argument, 0, 'L'},
{"nodes", required_argument, 0, 'n'},
{"help", no_argument, 0, 'h'},
{"noconnect", no_argument, 0, 'o'},
@ -936,7 +1027,7 @@ static void parse_args(int argc, char *argv[])
{NULL, no_argument, NULL, 0},
};
const char *opts_str = "4bdehotuxvc:f:n:r:p:P:T:";
const char *opts_str = "4bdehLotuxvc:f:l:n:r:p:P:T:";
int opt, indexptr;
long int port = 0;
@ -954,8 +1045,9 @@ static void parse_args(int argc, char *argv[])
case 'c':
snprintf(arg_opts.config_path, sizeof(arg_opts.config_path), "%s", optarg);
if (!file_exists(arg_opts.config_path))
if (!file_exists(arg_opts.config_path)) {
queue_init_message("Config file not found");
}
break;
@ -971,22 +1063,26 @@ static void parse_args(int argc, char *argv[])
case 'f':
arg_opts.use_custom_data = 1;
if (DATA_FILE)
if (DATA_FILE) {
free(DATA_FILE);
}
if (BLOCK_FILE)
if (BLOCK_FILE) {
free(BLOCK_FILE);
}
DATA_FILE = malloc(strlen(optarg) + 1);
strcpy(DATA_FILE, optarg);
if (DATA_FILE == NULL)
if (DATA_FILE == NULL) {
exit_toxic_err("failed in parse_args", FATALERR_MEMORY);
}
BLOCK_FILE = malloc(strlen(optarg) + strlen("-blocklist") + 1);
if (BLOCK_FILE == NULL)
if (BLOCK_FILE == NULL) {
exit_toxic_err("failed in parse_args", FATALERR_MEMORY);
}
strcpy(BLOCK_FILE, optarg);
strcat(BLOCK_FILE, "-blocklist");
@ -995,6 +1091,32 @@ static void parse_args(int argc, char *argv[])
break;
case 'l':
if (optarg) {
arg_opts.logging = true;
if (strcmp(optarg, "stderr") != 0) {
arg_opts.log_fp = fopen(optarg, "w");
if (arg_opts.log_fp != NULL) {
queue_init_message("Toxcore logging enabled to %s", optarg);
} else {
arg_opts.debug = true;
queue_init_message("Failed to open log file %s. Falling back to stderr.", optarg);
}
} else {
arg_opts.debug = true;
queue_init_message("Toxcore logging enabled to stderr");
}
}
break;
case 'L':
arg_opts.disable_local_discovery = 1;
queue_init_message("Local discovery disabled");
break;
case 'n':
snprintf(arg_opts.nodes_path, sizeof(arg_opts.nodes_path), "%s", optarg);
break;
@ -1008,13 +1130,15 @@ static void parse_args(int argc, char *argv[])
arg_opts.proxy_type = TOX_PROXY_TYPE_SOCKS5;
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
if (++optind > argc || argv[optind - 1][0] == '-')
if (++optind > argc || argv[optind - 1][0] == '-') {
exit_toxic_err("Proxy error", FATALERR_PROXY);
}
port = strtol(argv[optind - 1], NULL, 10);
if (port <= 0 || port > MAX_PORT_RANGE)
if (port <= 0 || port > MAX_PORT_RANGE) {
exit_toxic_err("Proxy error", FATALERR_PROXY);
}
arg_opts.proxy_port = port;
break;
@ -1023,13 +1147,15 @@ static void parse_args(int argc, char *argv[])
arg_opts.proxy_type = TOX_PROXY_TYPE_HTTP;
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
if (++optind > argc || argv[optind - 1][0] == '-')
if (++optind > argc || argv[optind - 1][0] == '-') {
exit_toxic_err("Proxy error", FATALERR_PROXY);
}
port = strtol(argv[optind - 1], NULL, 10);
if (port <= 0 || port > MAX_PORT_RANGE)
if (port <= 0 || port > MAX_PORT_RANGE) {
exit_toxic_err("Proxy error", FATALERR_PROXY);
}
arg_opts.proxy_port = port;
break;
@ -1037,8 +1163,9 @@ static void parse_args(int argc, char *argv[])
case 'r':
snprintf(arg_opts.nameserver_path, sizeof(arg_opts.nameserver_path), "%s", optarg);
if (!file_exists(arg_opts.nameserver_path))
if (!file_exists(arg_opts.nameserver_path)) {
queue_init_message("nameserver list not found");
}
break;
@ -1049,8 +1176,9 @@ static void parse_args(int argc, char *argv[])
case 'T':
port = strtol(optarg, NULL, 10);
if (port <= 0 || port > MAX_PORT_RANGE)
if (port <= 0 || port > MAX_PORT_RANGE) {
port = 14191;
}
arg_opts.tcp_port = port;
break;
@ -1083,28 +1211,34 @@ static int rename_old_profile(const char *user_config_dir)
char old_data_file[strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(OLD_DATA_NAME) + 1];
snprintf(old_data_file, sizeof(old_data_file), "%s%s%s", user_config_dir, CONFIGDIR, OLD_DATA_NAME);
if (!file_exists(old_data_file))
if (!file_exists(old_data_file)) {
return 0;
}
if (file_exists(DATA_FILE))
if (file_exists(DATA_FILE)) {
return 0;
}
if (rename(old_data_file, DATA_FILE) != 0)
if (rename(old_data_file, DATA_FILE) != 0) {
return -1;
}
queue_init_message("Data file has been moved to %s", DATA_FILE);
char old_data_blocklist[strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(OLD_DATA_BLOCKLIST_NAME) + 1];
snprintf(old_data_blocklist, sizeof(old_data_blocklist), "%s%s%s", user_config_dir, CONFIGDIR, OLD_DATA_BLOCKLIST_NAME);
if (!file_exists(old_data_blocklist))
if (!file_exists(old_data_blocklist)) {
return 0;
}
if (file_exists(BLOCK_FILE))
if (file_exists(BLOCK_FILE)) {
return 0;
}
if (rename(old_data_blocklist, BLOCK_FILE) != 0)
if (rename(old_data_blocklist, BLOCK_FILE) != 0) {
return -1;
}
return 0;
}
@ -1115,13 +1249,15 @@ static int rename_old_profile(const char *user_config_dir)
*/
static void init_default_data_files(void)
{
if (arg_opts.use_custom_data)
if (arg_opts.use_custom_data) {
return;
}
char *user_config_dir = get_user_config_dir();
if (user_config_dir == NULL)
if (user_config_dir == NULL) {
exit_toxic_err("failed in init_default_data_files()", FATALERR_FILEOP);
}
int config_err = create_user_config_dirs(user_config_dir);
@ -1129,14 +1265,16 @@ static void init_default_data_files(void)
DATA_FILE = strdup(DATANAME);
BLOCK_FILE = strdup(BLOCKNAME);
if (DATA_FILE == NULL || BLOCK_FILE == NULL)
if (DATA_FILE == NULL || BLOCK_FILE == NULL) {
exit_toxic_err("failed in init_default_data_files()", FATALERR_MEMORY);
}
} else {
DATA_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(DATANAME) + 1);
BLOCK_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(BLOCKNAME) + 1);
if (DATA_FILE == NULL || BLOCK_FILE == NULL)
if (DATA_FILE == NULL || BLOCK_FILE == NULL) {
exit_toxic_err("failed in init_default_data_files()", FATALERR_MEMORY);
}
strcpy(DATA_FILE, user_config_dir);
strcat(DATA_FILE, CONFIGDIR);
@ -1148,8 +1286,9 @@ static void init_default_data_files(void)
}
/* For backwards compatibility with old toxic profile names. TODO: remove this some day */
if (rename_old_profile(user_config_dir) == -1)
if (rename_old_profile(user_config_dir) == -1) {
queue_init_message("Warning: Profile backwards compatibility failed.");
}
free(user_config_dir);
}
@ -1158,6 +1297,8 @@ static void init_default_data_files(void)
#ifdef X11
void DnD_callback(const char *asdv, DropType dt)
{
UNUSED_VAR(asdv);
UNUSED_VAR(dt);
// if (dt != DT_plain)
// return;
@ -1169,11 +1310,17 @@ void DnD_callback(const char *asdv, DropType dt)
int main(int argc, char **argv)
{
/* Make sure all written files are read/writeable only by the current user. */
umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
parse_args(argc, argv);
/* Use the -b flag to enable stderr */
if (!arg_opts.debug)
freopen("/dev/null", "w", stderr);
if (!arg_opts.debug) {
if (!freopen("/dev/null", "w", stderr)) {
fprintf(stderr, "Warning: failed to enable stderr\n");
}
}
if (arg_opts.encrypt_data && arg_opts.unencrypt_data) {
arg_opts.encrypt_data = 0;
@ -1181,24 +1328,23 @@ int main(int argc, char **argv)
queue_init_message("Warning: Using --unencrypt-data and --encrypt-data simultaneously has no effect");
}
/* Make sure all written files are read/writeable only by the current user. */
umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
init_default_data_files();
bool datafile_exists = file_exists(DATA_FILE);
if (!datafile_exists && !arg_opts.unencrypt_data)
if (!datafile_exists && !arg_opts.unencrypt_data) {
first_time_encrypt("Creating new data file. Would you like to encrypt it? Y/n (q to quit)");
else if (arg_opts.encrypt_data)
} else if (arg_opts.encrypt_data) {
first_time_encrypt("Encrypt existing data file? Y/n (q to quit)");
}
/* init user_settings struct and load settings from conf file */
user_settings = calloc(1, sizeof(struct user_settings));
if (user_settings == NULL)
if (user_settings == NULL) {
exit_toxic_err("failed in main", FATALERR_MEMORY);
}
const char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL;
@ -1219,33 +1365,37 @@ int main(int argc, char **argv)
#ifdef X11
if (init_xtra(DnD_callback) == -1)
if (init_xtra(DnD_callback) == -1) {
queue_init_message("X failed to initialize");
}
#endif
#endif /* X11 */
Tox *m = load_toxic(DATA_FILE);
if (arg_opts.encrypt_data && !datafile_exists)
if (arg_opts.encrypt_data && !datafile_exists) {
arg_opts.encrypt_data = 0;
}
init_term();
prompt = init_windows(m);
prompt_init_statusbar(prompt, m);
load_groups(prompt, m);
prompt_init_statusbar(prompt, m, !datafile_exists);
load_conferences(m);
/* thread for ncurses stuff */
if (pthread_mutex_init(&Winthread.lock, NULL) != 0)
if (pthread_mutex_init(&Winthread.lock, NULL) != 0) {
exit_toxic_err("failed in main", FATALERR_MUTEX_INIT);
}
if (pthread_create(&Winthread.tid, NULL, thread_winref, (void *) m) != 0)
if (pthread_create(&Winthread.tid, NULL, thread_winref, (void *) m) != 0) {
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
}
/* thread for message queue */
if (pthread_create(&cqueue_thread.tid, NULL, thread_cqueue, (void *) m) != 0)
if (pthread_create(&cqueue_thread.tid, NULL, thread_cqueue, (void *) m) != 0) {
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
}
#ifdef AUDIO
@ -1257,16 +1407,18 @@ int main(int argc, char **argv)
#endif /* VIDEO */
/* AV thread */
if (pthread_create(&av_thread.tid, NULL, thread_av, (void *) av) != 0)
if (pthread_create(&av_thread.tid, NULL, thread_av, (void *) av) != 0) {
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
}
set_primary_device(input, user_settings->audio_in_dev);
set_primary_device(output, user_settings->audio_out_dev);
#elif SOUND_NOTIFY
if ( init_devices() == de_InternalError )
if (init_devices() == de_InternalError) {
queue_init_message("Failed to init audio devices");
}
#endif /* AUDIO */
@ -1277,11 +1429,12 @@ int main(int argc, char **argv)
#endif /* PYTHON */
init_notify(60, 3000);
init_notify(60, user_settings->notification_timeout);
/* screen/tmux auto-away timer */
if (init_mplex_away_timer(m) == -1)
if (init_mplex_away_timer(m) == -1) {
queue_init_message("Failed to init mplex auto-away.");
}
int nodeslist_ret = load_DHT_nodeslist();
@ -1297,7 +1450,7 @@ int main(int argc, char **argv)
/* set user avatar from config file. if no path is supplied tox_unset_avatar is called */
char avatarstr[PATH_MAX + 11];
snprintf(avatarstr, sizeof(avatarstr), "/avatar \"%s\"", user_settings->avatar_path);
snprintf(avatarstr, sizeof(avatarstr), "/avatar %s", user_settings->avatar_path);
execute(prompt->chatwin->history, prompt, m, avatarstr, GLOBAL_COMMAND_MODE);
time_t last_save = get_unix_time();
@ -1307,11 +1460,12 @@ int main(int argc, char **argv)
time_t cur_time = get_unix_time();
if (timed_out(last_save, AUTOSAVE_FREQ)) {
if (user_settings->autosave_freq > 0 && timed_out(last_save, user_settings->autosave_freq)) {
pthread_mutex_lock(&Winthread.lock);
if (store_data(m, DATA_FILE) != 0)
if (store_data(m, DATA_FILE) != 0) {
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, "WARNING: Failed to save to data file");
}
pthread_mutex_unlock(&Winthread.lock);

View File

@ -61,8 +61,6 @@
#define T_KEY_PREV 0x0F /* ctrl-o */
#define T_KEY_C_E 0x05 /* ctrl-e */
#define T_KEY_C_A 0x01 /* ctrl-a */
#define T_KEY_C_RB 0x1D /* ctrl-] */
#define T_KEY_C_LB 0x1B /* ctrl-[ */
#define T_KEY_C_V 0x16 /* ctrl-v */
#define T_KEY_C_F 0x06 /* ctrl-f */
#define T_KEY_C_H 0x08 /* ctrl-h */
@ -71,6 +69,10 @@
#define T_KEY_C_W 0x17 /* ctrl-w */
#define T_KEY_C_B 0x02 /* ctrl-b */
#define T_KEY_C_T 0x14 /* ctrl-t */
#define T_KEY_C_LEFT 0x221 /* ctrl-left arrow */
#define T_KEY_C_RIGHT 0x230 /* ctrl-right arrow */
#define T_KEY_C_UP 0x236 /* ctrl-up arrow */
#define T_KEY_C_DOWN 0x20D /* ctrl-down arrow */
#define T_KEY_TAB 0x09 /* TAB key */
#define ONLINE_CHAR "*"
@ -96,8 +98,8 @@ typedef enum _FATAL_ERRS {
Uncomment if necessary */
/* #define URXVT_FIX */
void lock_status ();
void unlock_status ();
void lock_status(void);
void unlock_status(void);
void exit_toxic_success(Tox *m);
void exit_toxic_err(const char *errmsg, int errcode);
@ -105,32 +107,32 @@ void exit_toxic_err(const char *errmsg, int errcode);
int store_data(Tox *m, const char *path);
/* callbacks */
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata);
void on_connectionchange(Tox *m, uint32_t friendnumber, TOX_CONNECTION status, void *userdata);
void on_message(Tox *m, uint32_t friendnumber, TOX_MESSAGE_TYPE type, const uint8_t *string, size_t length,
void *userdata);
void on_action(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
void on_nickchange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
void on_statuschange(Tox *m, uint32_t friendnumber, TOX_USER_STATUS status, void *userdata);
void on_statusmessagechange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
void on_friendadded(Tox *m, uint32_t friendnumber, bool sort);
void on_groupmessage(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_MESSAGE_TYPE type,
const uint8_t *message, size_t length, void *userdata);
void on_groupinvite(Tox *m, uint32_t friendnumber, TOX_CONFERENCE_TYPE type, const uint8_t *group_pub_key,
size_t length, void *userdata);
void on_group_namelistchange(Tox *m, uint32_t groupnumber, void *userdata);
void on_group_peernamechange(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *name,
void on_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata);
void on_friend_connection_status(Tox *m, uint32_t friendnumber, Tox_Connection status, void *userdata);
void on_friend_message(Tox *m, uint32_t friendnumber, Tox_Message_Type type, const uint8_t *string, size_t length,
void *userdata);
void on_friend_name(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
void on_friend_status(Tox *m, uint32_t friendnumber, Tox_User_Status status, void *userdata);
void on_friend_status_message(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
void on_friend_added(Tox *m, uint32_t friendnumber, bool sort);
void on_conference_message(Tox *m, uint32_t groupnumber, uint32_t peernumber, Tox_Message_Type type,
const uint8_t *message, size_t length, void *userdata);
void on_conference_invite(Tox *m, uint32_t friendnumber, Tox_Conference_Type type, const uint8_t *group_pub_key,
size_t length, void *userdata);
void on_conference_peer_list_changed(Tox *m, uint32_t groupnumber, void *userdata);
void on_conference_peer_name(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *name,
size_t length, void *userdata);
void on_group_titlechange(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *title, size_t length,
void *userdata);
void on_conference_title(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *title, size_t length,
void *userdata);
void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length,
void *userdata);
void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data,
size_t length, void *userdata);
void on_file_control (Tox *m, uint32_t friendnumber, uint32_t filenumber, TOX_FILE_CONTROL control, void *userdata);
void on_file_recv_control(Tox *m, uint32_t friendnumber, uint32_t filenumber, Tox_File_Control control,
void *userdata);
void on_file_recv(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint32_t kind, uint64_t file_size,
const uint8_t *filename, size_t filename_length, void *userdata);
void on_typing_change(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata);
void on_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata);
void on_friend_typing(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata);
void on_friend_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata);
#endif /* #define TOXIC_H */
#endif /* TOXIC_H */

View File

@ -33,8 +33,9 @@
/* Adds char to line at pos. Return 0 on success, -1 if line buffer is full */
int add_char_to_buf(ChatContext *ctx, wint_t ch)
{
if (ctx->len >= MAX_STR_SIZE - 1)
if (ctx->len >= MAX_STR_SIZE - 1) {
return -1;
}
wmemmove(&ctx->line[ctx->pos + 1], &ctx->line[ctx->pos], ctx->len - ctx->pos);
ctx->line[ctx->pos++] = ch;
@ -46,8 +47,9 @@ int add_char_to_buf(ChatContext *ctx, wint_t ch)
/* Deletes the character before pos. Return 0 on success, -1 if nothing to delete */
int del_char_buf_bck(ChatContext *ctx)
{
if (ctx->pos <= 0)
if (ctx->pos <= 0) {
return -1;
}
wmemmove(&ctx->line[ctx->pos - 1], &ctx->line[ctx->pos], ctx->len - ctx->pos);
--ctx->pos;
@ -59,8 +61,9 @@ int del_char_buf_bck(ChatContext *ctx)
/* Deletes the character at pos. Return 0 on success, -1 if nothing to delete. */
int del_char_buf_frnt(ChatContext *ctx)
{
if (ctx->pos >= ctx->len)
if (ctx->pos >= ctx->len) {
return -1;
}
wmemmove(&ctx->line[ctx->pos], &ctx->line[ctx->pos + 1], ctx->len - ctx->pos - 1);
ctx->line[--ctx->len] = L'\0';
@ -72,8 +75,9 @@ int del_char_buf_frnt(ChatContext *ctx)
Return 0 on success, -1 if noting to discard. */
int discard_buf(ChatContext *ctx)
{
if (ctx->pos <= 0)
if (ctx->pos <= 0) {
return -1;
}
ctx->yank_len = ctx->pos;
wmemcpy(ctx->yank, ctx->line, ctx->yank_len);
@ -92,8 +96,9 @@ int discard_buf(ChatContext *ctx)
Return 0 on success, -1 if nothing to kill. */
int kill_buf(ChatContext *ctx)
{
if (ctx->len <= ctx->pos)
if (ctx->len <= ctx->pos) {
return -1;
}
ctx->yank_len = ctx->len - ctx->pos;
wmemcpy(ctx->yank, &ctx->line[ctx->pos], ctx->yank_len);
@ -109,11 +114,13 @@ int kill_buf(ChatContext *ctx)
Return 0 on success, -1 if yank buffer is empty or too long */
int yank_buf(ChatContext *ctx)
{
if (!ctx->yank[0])
if (!ctx->yank[0]) {
return -1;
}
if (ctx->yank_len + ctx->len >= MAX_STR_SIZE)
if (ctx->yank_len + ctx->len >= MAX_STR_SIZE) {
return -1;
}
wmemmove(&ctx->line[ctx->pos + ctx->yank_len], &ctx->line[ctx->pos], ctx->len - ctx->pos);
wmemcpy(&ctx->line[ctx->pos], ctx->yank, ctx->yank_len);
@ -130,8 +137,9 @@ int yank_buf(ChatContext *ctx)
Return 0 on success, -1 if nothing to delete */
int del_word_buf(ChatContext *ctx)
{
if (ctx->len == 0 || ctx->pos == 0)
if (ctx->len == 0 || ctx->pos == 0) {
return -1;
}
int i = ctx->pos, count = 0;
@ -169,17 +177,20 @@ void reset_buf(ChatContext *ctx)
/* Removes trailing spaces and newlines from line. */
void rm_trailing_spaces_buf(ChatContext *ctx)
{
if (ctx->len <= 0)
if (ctx->len <= 0) {
return;
}
if (ctx->line[ctx->len - 1] != ' ' && ctx->line[ctx->len - 1] != L'')
if (ctx->line[ctx->len - 1] != ' ' && ctx->line[ctx->len - 1] != L'') {
return;
}
int i;
for (i = ctx->len - 1; i >= 0; --i) {
if (ctx->line[i] != ' ' && ctx->line[i] != L'')
if (ctx->line[i] != ' ' && ctx->line[i] != L'') {
break;
}
}
ctx->len = i + 1;
@ -195,8 +206,9 @@ static void shift_hist_back(ChatContext *ctx)
int i;
int n = MAX_LINE_HIST - HIST_PURGE;
for (i = 0; i < n; ++i)
for (i = 0; i < n; ++i) {
wmemcpy(ctx->ln_history[i], ctx->ln_history[i + HIST_PURGE], MAX_STR_SIZE);
}
ctx->hst_tot = n;
}
@ -204,11 +216,13 @@ static void shift_hist_back(ChatContext *ctx)
/* adds a line to the ln_history buffer at hst_pos and sets hst_pos to end of history. */
void add_line_to_hist(ChatContext *ctx)
{
if (ctx->len >= MAX_STR_SIZE)
if (ctx->len >= MAX_STR_SIZE) {
return;
}
if (ctx->hst_tot >= MAX_LINE_HIST)
if (ctx->hst_tot >= MAX_LINE_HIST) {
shift_hist_back(ctx);
}
++ctx->hst_tot;
ctx->hst_pos = ctx->hst_tot;
@ -222,6 +236,12 @@ void add_line_to_hist(ChatContext *ctx)
resets line if at end of history */
void fetch_hist_item(ChatContext *ctx, int key_dir)
{
if (wcscmp(ctx->line, L"\0") != 0
&& ctx->hst_pos == ctx->hst_tot) {
add_line_to_hist(ctx);
ctx->hst_pos--;
}
if (key_dir == KEY_UP) {
if (--ctx->hst_pos < 0) {
ctx->hst_pos = 0;
@ -247,16 +267,20 @@ void strsubst(char *str, char old, char new)
{
int i;
for (i = 0; str[i] != '\0'; ++i)
if (str[i] == old)
for (i = 0; str[i] != '\0'; ++i) {
if (str[i] == old) {
str[i] = new;
}
}
}
void wstrsubst(wchar_t *str, wchar_t old, wchar_t new)
{
int i;
for (i = 0; str[i] != L'\0'; ++i)
if (str[i] == old)
for (i = 0; str[i] != L'\0'; ++i) {
if (str[i] == old) {
str[i] = new;
}
}
}

View File

@ -70,4 +70,4 @@ void fetch_hist_item(ChatContext *ctx, int key_dir);
void strsubst(char *str, char old, char new);
void wstrsubst(wchar_t *str, wchar_t old, wchar_t new);
#endif /* #define TOXIC_STRINGS_H */
#endif /* TOXIC_STRINGS_H */

View File

@ -28,6 +28,7 @@
#include "global_commands.h"
#include "line_info.h"
#include "notify.h"
#include "misc_tools.h"
#include <stdbool.h>
#include <curses.h>
@ -37,48 +38,52 @@
#include <stdlib.h>
#include <assert.h>
#ifdef VIDEO
#define default_video_bit_rate 5000
void receive_video_frame_cb( ToxAV *av, uint32_t friend_number,
uint16_t width, uint16_t height,
uint8_t const *y, uint8_t const *u, uint8_t const *v,
int32_t ystride, int32_t ustride, int32_t vstride,
void *user_data );
void on_video_receive_frame(ToxAV *av, uint32_t friend_number,
uint16_t width, uint16_t height,
uint8_t const *y, uint8_t const *u, uint8_t const *v,
int32_t ystride, int32_t ustride, int32_t vstride,
void *user_data);
void video_bit_rate_status_cb( ToxAV *av, uint32_t friend_number, uint32_t video_bit_rate, void *user_data);
void on_video_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t video_bit_rate, void *user_data);
static void print_err (ToxWindow *self, const char *error_str)
static void print_err(ToxWindow *self, const char *error_str)
{
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", error_str);
}
ToxAV *init_video(ToxWindow *self, Tox *tox)
{
UNUSED_VAR(tox);
CallControl.video_errors = ve_None;
CallControl.video_enabled = true;
CallControl.video_bit_rate = 0;
CallControl.video_frame_duration = 10;
if ( !CallControl.av ) {
if (!CallControl.av) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Video failed to init with ToxAV instance");
return NULL;
}
if ( init_video_devices(CallControl.av) == vde_InternalError ) {
if (init_video_devices(CallControl.av) == vde_InternalError) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init video devices");
return NULL;
}
toxav_callback_video_receive_frame(CallControl.av, receive_video_frame_cb, &CallControl);
toxav_callback_video_bit_rate(CallControl.av, video_bit_rate_status_cb, &CallControl);
toxav_callback_video_receive_frame(CallControl.av, on_video_receive_frame, &CallControl);
toxav_callback_video_bit_rate(CallControl.av, on_video_bit_rate, &CallControl);
return CallControl.av;
}
void terminate_video()
void terminate_video(void)
{
int i;
@ -87,8 +92,9 @@ void terminate_video()
stop_video_transmission(this_call, i);
if ( this_call->vout_idx != -1 )
if (this_call->vout_idx != -1) {
close_video_device(vdt_output, this_call->vout_idx);
}
}
terminate_video_devices();
@ -99,21 +105,22 @@ void read_video_device_callback(int16_t width, int16_t height, const uint8_t *y,
{
uint32_t friend_number = *((uint32_t *)data); /* TODO: Or pass an array of call_idx's */
Call *this_call = &CallControl.calls[friend_number];
TOXAV_ERR_SEND_FRAME error;
Toxav_Err_Send_Frame error;
/* Drop frame if video sending is disabled */
if ( CallControl.video_bit_rate == 0 || this_call->vin_idx == -1 ) {
if (CallControl.video_bit_rate == 0 || this_call->vin_idx == -1) {
line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Video frame dropped.");
return;
}
if ( toxav_video_send_frame(CallControl.av, friend_number, width, height, y, u, v, &error ) == false ) {
if (toxav_video_send_frame(CallControl.av, friend_number, width, height, y, u, v, &error) == false) {
line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to send video frame");
if ( error == TOXAV_ERR_SEND_FRAME_NULL )
if (error == TOXAV_ERR_SEND_FRAME_NULL) {
line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to capture video frame");
else if ( error == TOXAV_ERR_SEND_FRAME_INVALID )
} else if (error == TOXAV_ERR_SEND_FRAME_INVALID) {
line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to prepare video frame");
}
}
}
@ -122,29 +129,31 @@ void write_video_device_callback(uint32_t friend_number, uint16_t width, uint16_
int32_t ystride, int32_t ustride, int32_t vstride,
void *user_data)
{
UNUSED_VAR(friend_number);
write_video_out(width, height, y, u, v, ystride, ustride, vstride, user_data);
}
int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call)
{
if ( !self || !av) {
if (!self || !av) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to prepare transmission");
return -1;
}
CallControl.video_bit_rate = default_video_bit_rate;
if ( toxav_video_set_bit_rate(CallControl.av, self->num, CallControl.video_bit_rate, NULL) == false ) {
if (toxav_video_set_bit_rate(CallControl.av, self->num, CallControl.video_bit_rate, NULL) == false) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set video bit rate");
return -1;
}
if ( open_primary_video_device(vdt_input, &call->vin_idx) != vde_None ) {
if (open_primary_video_device(vdt_input, &call->vin_idx) != vde_None) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open input video device!");
return -1;
}
if ( register_video_device_callback(self->num, call->vin_idx, read_video_device_callback, &self->num) != vde_None ) {
if (register_video_device_callback(self->num, call->vin_idx, read_video_device_callback, &self->num) != vde_None) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to register input video handler!");
return -1;
}
@ -157,7 +166,7 @@ int stop_video_transmission(Call *call, int friend_number)
CallControl.video_bit_rate = 0;
toxav_video_set_bit_rate(CallControl.av, friend_number, CallControl.video_bit_rate, NULL);
if ( call->vin_idx != -1 ) {
if (call->vin_idx != -1) {
close_video_device(vdt_input, call->vin_idx);
call->vin_idx = -1;
}
@ -175,17 +184,22 @@ int stop_video_transmission(Call *call, int friend_number)
/*
* Callbacks
*/
void receive_video_frame_cb(ToxAV *av, uint32_t friend_number,
void on_video_receive_frame(ToxAV *av, uint32_t friend_number,
uint16_t width, uint16_t height,
uint8_t const *y, uint8_t const *u, uint8_t const *v,
int32_t ystride, int32_t ustride, int32_t vstride,
void *user_data)
{
UNUSED_VAR(av);
write_video_device_callback(friend_number, width, height, y, u, v, ystride, ustride, vstride, user_data);
}
void video_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t video_bit_rate, void *user_data)
void on_video_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t video_bit_rate, void *user_data)
{
UNUSED_VAR(av);
UNUSED_VAR(user_data);
CallControl.video_bit_rate = video_bit_rate;
toxav_video_set_bit_rate(CallControl.av, friend_number, CallControl.video_bit_rate, NULL);
}
@ -194,8 +208,9 @@ void callback_recv_video_starting(uint32_t friend_number)
{
Call *this_call = &CallControl.calls[friend_number];
if ( this_call->vout_idx != -1 )
if (this_call->vout_idx != -1) {
return;
}
open_primary_video_device(vdt_output, &this_call->vout_idx);
}
@ -208,23 +223,24 @@ void callback_recv_video_end(uint32_t friend_number)
}
void callback_video_starting(uint32_t friend_number)
{
ToxWindow *windows = CallControl.prompt;
Call *this_call = &CallControl.calls[friend_number];
TOXAV_ERR_CALL_CONTROL error = TOXAV_ERR_CALL_CONTROL_OK;
Toxav_Err_Call_Control error = TOXAV_ERR_CALL_CONTROL_OK;
toxav_call_control(CallControl.av, friend_number, TOXAV_CALL_CONTROL_SHOW_VIDEO, &error);
if (error == TOXAV_ERR_CALL_CONTROL_OK) {
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if ( windows[i].is_call && windows[i].num == friend_number ) {
if ( 0 != start_video_transmission(&windows[i], CallControl.av, this_call) ) {
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!");
ToxWindow *window = get_window_ptr(i);
if (window != NULL && window->is_call && window->num == friend_number) {
if (0 != start_video_transmission(window, CallControl.av, this_call)) {
line_info_add(window, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!");
return;
}
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Video capture starting.");
line_info_add(window, NULL, NULL, NULL, SYS_MSG, 0, 0, "Video capture starting.");
}
}
}
@ -244,57 +260,70 @@ void callback_video_end(uint32_t friend_number)
*/
void cmd_video(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
UNUSED_VAR(m);
UNUSED_VAR(argv);
const char *error_str;
Call *this_call = &CallControl.calls[self->num];
if ( argc != 0 ) {
if (argc != 0) {
error_str = "Unknown arguments.";
goto on_error;
}
if ( !CallControl.av ) {
if (!CallControl.av) {
error_str = "ToxAV not supported!";
goto on_error;
}
if ( !self->stb->connection ) {
if (!self->stb->connection) {
error_str = "Friend is offline.";
goto on_error;
}
if ( !self->is_call ) {
if (!self->is_call) {
error_str = "Not in call!";
goto on_error;
}
if ( this_call->vin_idx == -1 )
if (this_call->vin_idx == -1) {
callback_video_starting(self->num);
else
} else {
callback_video_end(self->num);
}
return;
on_error:
print_err (self, error_str);
print_err(self, error_str);
}
void cmd_list_video_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
UNUSED_VAR(m);
const char *error_str;
if ( argc != 1 ) {
if ( argc < 1 ) error_str = "Type must be specified!";
else error_str = "Only one argument allowed!";
if (argc != 1) {
if (argc < 1) {
error_str = "Type must be specified!";
} else {
error_str = "Only one argument allowed!";
}
goto on_error;
}
VideoDeviceType type;
if ( strcasecmp(argv[1], "in") == 0 ) /* Input devices */
if (strcasecmp(argv[1], "in") == 0) { /* Input devices */
type = vdt_input;
}
else if ( strcasecmp(argv[1], "out") == 0 ) /* Output devices */
else if (strcasecmp(argv[1], "out") == 0) { /* Output devices */
type = vdt_output;
}
else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
@ -305,29 +334,38 @@ void cmd_list_video_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, c
return;
on_error:
print_err (self, error_str);
print_err(self, error_str);
}
/* This changes primary video device only */
void cmd_change_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
UNUSED_VAR(m);
const char *error_str;
if ( argc != 2 ) {
if ( argc < 1 ) error_str = "Type must be specified!";
else if ( argc < 2 ) error_str = "Must have id!";
else error_str = "Only two arguments allowed!";
if (argc != 2) {
if (argc < 1) {
error_str = "Type must be specified!";
} else if (argc < 2) {
error_str = "Must have id!";
} else {
error_str = "Only two arguments allowed!";
}
goto on_error;
}
VideoDeviceType type;
if ( strcmp(argv[1], "in") == 0 ) /* Input devices */
if (strcmp(argv[1], "in") == 0) { /* Input devices */
type = vdt_input;
}
else if ( strcmp(argv[1], "out") == 0 ) /* Output devices */
else if (strcmp(argv[1], "out") == 0) { /* Output devices */
type = vdt_output;
}
else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
@ -338,40 +376,49 @@ void cmd_change_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc,
char *end;
long int selection = strtol(argv[2], &end, 10);
if ( *end ) {
if (*end) {
error_str = "Invalid input";
goto on_error;
}
if ( set_primary_video_device(type, selection) == vde_InvalidSelection ) {
if (set_primary_video_device(type, selection) == vde_InvalidSelection) {
error_str = "Invalid selection!";
goto on_error;
}
return;
on_error:
print_err (self, error_str);
print_err(self, error_str);
}
void cmd_ccur_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
UNUSED_VAR(window);
UNUSED_VAR(m);
const char *error_str;
if ( argc != 2 ) {
if ( argc < 1 ) error_str = "Type must be specified!";
else if ( argc < 2 ) error_str = "Must have id!";
else error_str = "Only two arguments allowed!";
if (argc != 2) {
if (argc < 1) {
error_str = "Type must be specified!";
} else if (argc < 2) {
error_str = "Must have id!";
} else {
error_str = "Only two arguments allowed!";
}
goto on_error;
}
VideoDeviceType type;
if ( strcmp(argv[1], "in") == 0 ) /* Input devices */
if (strcmp(argv[1], "in") == 0) { /* Input devices */
type = vdt_input;
}
else if ( strcmp(argv[1], "out") == 0 ) /* Output devices */
else if (strcmp(argv[1], "out") == 0) { /* Output devices */
type = vdt_output;
}
else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
@ -382,23 +429,23 @@ void cmd_ccur_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, ch
char *end;
long int selection = strtol(argv[2], &end, 10);
if ( *end ) {
if (*end) {
error_str = "Invalid input";
goto on_error;
}
if ( video_selection_valid(type, selection) == vde_InvalidSelection ) {
if (video_selection_valid(type, selection) == vde_InvalidSelection) {
error_str = "Invalid selection!";
goto on_error;
}
/* If call is active, change device */
if ( self->is_call ) {
if (self->is_call) {
Call *this_call = &CallControl.calls[self->num];
if ( this_call->ttas ) {
if (this_call->ttas) {
if ( type == vdt_output ) {
if (type == vdt_output) {
} else {
/* TODO: check for failure */
close_video_device(vdt_input, this_call->vin_idx);
@ -412,13 +459,16 @@ void cmd_ccur_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, ch
return;
on_error:
print_err (self, error_str);
print_err(self, error_str);
}
void stop_video_stream(ToxWindow *self)
{
Call *this_call = &CallControl.calls[self->num];
if (this_call && this_call->vin_idx != -1)
if (this_call && this_call->vin_idx != -1) {
stop_video_transmission(this_call, self->num);
}
}
#endif /* VIDEO */

View File

@ -31,7 +31,7 @@
/* You will have to pass pointer to first member of 'windows' declared in windows.c */
ToxAV *init_video(ToxWindow *self, Tox *tox);
void terminate_video();
void terminate_video(void);
int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call);
int stop_video_transmission(Call *call, int friend_number);
void stop_video_stream(ToxWindow *self);

View File

@ -24,28 +24,29 @@
#include "video_call.h"
#include <sys/ioctl.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <vpx/vpx_image.h>
#if defined(__OSX__)
#if defined(__OSX__) || defined(__APPLE__)
#import "osx_video.h"
#else
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#if defined(__linux__)
#include <linux/videodev2.h>
#else
#if defined(__OpenBSD__) || defined(__NetBSD__)
#include <sys/videoio.h>
#endif
#endif
#else
#include <linux/videodev2.h>
#endif /* defined(__OpenBSD__) || defined(__NetBSD__) */
#endif /* __OSX__ || __APPLE__ */
#include "line_info.h"
#include "settings.h"
#include "misc_tools.h"
#include <errno.h>
@ -55,6 +56,8 @@
#include <unistd.h>
#include <stdlib.h>
#ifdef VIDEO
#define inline__ inline __attribute__((always_inline))
extern struct user_settings *user_settings;
@ -69,7 +72,7 @@ typedef struct VideoDevice {
void *cb_data; /* Data to be passed to callback */
int32_t friend_number; /* ToxAV friend number */
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#if !(defined(__OSX__) || defined(__APPLE__))
int fd; /* File descriptor of video device selected/opened */
struct v4l2_format fmt;
struct VideoBuffer *buffers;
@ -96,13 +99,11 @@ static int size[2]; /* Size of above containers */
VideoDevice *video_devices_running[2][MAX_DEVICES] = {{NULL}}; /* Running devices */
uint32_t primary_video_device[2]; /* Primary device */
#ifdef VIDEO
static ToxAV *av = NULL;
#endif /* VIDEO */
/* q_mutex */
#define lock pthread_mutex_lock(&video_mutex);
#define unlock pthread_mutex_unlock(&video_mutex);
#define lock pthread_mutex_lock(&video_mutex)
#define unlock pthread_mutex_unlock(&video_mutex)
pthread_mutex_t video_mutex;
bool video_thread_running = true,
@ -136,7 +137,7 @@ static void yuv420tobgr(uint16_t width, uint16_t height, const uint8_t *y,
}
}
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#if !(defined(__OSX__) || defined(__APPLE__))
static void yuv422to420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v,
uint8_t *input, uint16_t width, uint16_t height)
{
@ -185,10 +186,13 @@ VideoDeviceError init_video_devices()
{
size[vdt_input] = 0;
#if defined(__OSX__)
if( osx_video_init((char**)video_devices_names[vdt_input], &size[vdt_input]) != 0 )
#if defined(__OSX__) || defined(__APPLE__)
if (osx_video_init((char **)video_devices_names[vdt_input], &size[vdt_input]) != 0) {
return vde_InternalError;
#else /* not __OSX__*/
}
#else /* not __OSX__ || __APPLE__ */
for (; size[vdt_input] <= MAX_DEVICES; ++size[vdt_input]) {
int fd;
@ -197,14 +201,14 @@ VideoDeviceError init_video_devices()
fd = open(device_address, O_RDWR | O_NONBLOCK, 0);
if ( fd == -1 ) {
if (fd == -1) {
break;
} else {
struct v4l2_capability cap;
char *video_input_name;
/* Query V4L for capture capabilities */
if ( -1 != ioctl(fd, VIDIOC_QUERYCAP, &cap) ) {
if (-1 != ioctl(fd, VIDIOC_QUERYCAP, &cap)) {
video_input_name = (char *)malloc(strlen((const char *)cap.card) + strlen(device_address) + 4);
strcpy(video_input_name, (char *)cap.card);
strcat(video_input_name, " (");
@ -230,13 +234,15 @@ VideoDeviceError init_video_devices()
video_devices_names[vdt_output][0] = video_output_name;
// Start poll thread
if ( pthread_mutex_init(&video_mutex, NULL) != 0 )
if (pthread_mutex_init(&video_mutex, NULL) != 0) {
return vde_InternalError;
}
pthread_t thread_id;
if ( pthread_create(&thread_id, NULL, video_thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0 )
if (pthread_create(&thread_id, NULL, video_thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0) {
return vde_InternalError;
}
#ifdef VIDEO
av = av_;
@ -245,7 +251,7 @@ VideoDeviceError init_video_devices()
return (VideoDeviceError) vde_None;
}
VideoDeviceError terminate_video_devices()
VideoDeviceError terminate_video_devices(void)
{
/* Cleanup if needed */
lock;
@ -260,12 +266,13 @@ VideoDeviceError terminate_video_devices()
free((void *)video_devices_names[vdt_input][i]);
}
if ( pthread_mutex_destroy(&video_mutex) != 0 )
if (pthread_mutex_destroy(&video_mutex) != 0) {
return (VideoDeviceError) vde_InternalError;
}
#ifdef __OSX__
#if defined(__OSX__) || defined(__APPLE__)
osx_video_release();
#endif /* __OSX__ */
#endif /* __OSX__ || __APPLE__ */
return (VideoDeviceError) vde_None;
}
@ -273,16 +280,18 @@ VideoDeviceError terminate_video_devices()
VideoDeviceError register_video_device_callback(int32_t friend_number, uint32_t device_idx,
VideoDataHandleCallback callback, void *data)
{
#if defined(__OSX__)
#if defined(__OSX__) || defined(__APPLE__)
if ( size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx] )
if (size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx]) {
return vde_InvalidSelection;
}
#else /* not __OSX__ */
#else /* not __OSX__ || __APPLE__ */
if ( size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx]
|| !video_devices_running[vdt_input][device_idx]->fd )
if (size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx]
|| !video_devices_running[vdt_input][device_idx]->fd) {
return vde_InvalidSelection;
}
#endif
@ -297,7 +306,9 @@ VideoDeviceError register_video_device_callback(int32_t friend_number, uint32_t
VideoDeviceError set_primary_video_device(VideoDeviceType type, int32_t selection)
{
if ( size[type] <= selection || selection < 0 ) return vde_InvalidSelection;
if (size[type] <= selection || selection < 0) {
return vde_InvalidSelection;
}
primary_video_device[type] = selection;
@ -316,14 +327,16 @@ void get_primary_video_device_name(VideoDeviceType type, char *buf, int size)
VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint32_t *device_idx)
{
if ( size[type] <= selection || selection < 0 ) return vde_InvalidSelection;
if (size[type] <= selection || selection < 0) {
return vde_InvalidSelection;
}
lock;
uint32_t i, temp_idx = -1;
for (i = 0; i < MAX_DEVICES; ++i) {
if ( !video_devices_running[type][i] ) {
if (!video_devices_running[type][i]) {
temp_idx = i;
break;
}
@ -335,7 +348,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
}
for (i = 0; i < MAX_DEVICES; i ++) { /* Check if any device has the same selection */
if ( video_devices_running[type][i] && video_devices_running[type][i]->selection == selection ) {
if (video_devices_running[type][i] && video_devices_running[type][i]->selection == selection) {
video_devices_running[type][temp_idx] = video_devices_running[type][i];
video_devices_running[type][i]->ref_count++;
@ -348,29 +361,31 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
VideoDevice *device = video_devices_running[type][temp_idx] = calloc(1, sizeof(VideoDevice));
device->selection = selection;
if ( pthread_mutex_init(device->mutex, NULL) != 0 ) {
if (pthread_mutex_init(device->mutex, NULL) != 0) {
free(device);
unlock;
return vde_InternalError;
}
if ( type == vdt_input ) {
if (type == vdt_input) {
video_thread_paused = true;
#if defined(__OSX__)
if ( osx_video_open_device(selection, &device->video_width, &device->video_height) != 0 ) {
#if defined(__OSX__) || defined(__APPLE__)
if (osx_video_open_device(selection, &device->video_width, &device->video_height) != 0) {
free(device);
unlock;
return vde_FailedStart;
}
#else /* not __OSX__*/
#else /* not __OSX__ || __APPLE__ */
/* Open selected device */
char device_address[] = "/dev/videoXX";
snprintf(device_address + 10, sizeof(device_address) - 10, "%i", selection);
device->fd = open(device_address, O_RDWR);
if ( device->fd == -1 ) {
if (device->fd == -1) {
unlock;
return vde_FailedStart;
}
@ -378,7 +393,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
/* Obtain video device capabilities */
struct v4l2_capability cap;
if ( -1 == xioctl(device->fd, VIDIOC_QUERYCAP, &cap) ) {
if (-1 == xioctl(device->fd, VIDIOC_QUERYCAP, &cap)) {
close(device->fd);
free(device);
unlock;
@ -392,7 +407,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
if ( -1 == xioctl(device->fd, VIDIOC_S_FMT, &fmt) ) {
if (-1 == xioctl(device->fd, VIDIOC_S_FMT, &fmt)) {
close(device->fd);
free(device);
unlock;
@ -409,14 +424,14 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if ( -1 == xioctl(device->fd, VIDIOC_REQBUFS, &req) ) {
if (-1 == xioctl(device->fd, VIDIOC_REQBUFS, &req)) {
close(device->fd);
free(device);
unlock;
return vde_FailedStart;
}
if ( req.count < 2 ) {
if (req.count < 2) {
close(device->fd);
free(device);
unlock;
@ -433,7 +448,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if ( -1 == xioctl(device->fd, VIDIOC_QUERYBUF, &buf) ) {
if (-1 == xioctl(device->fd, VIDIOC_QUERYBUF, &buf)) {
close(device->fd);
free(device);
unlock;
@ -447,9 +462,10 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
MAP_SHARED /* recommended */,
device->fd, buf.m.offset);
if ( MAP_FAILED == device->buffers[i].start ) {
for (i = 0; i < buf.index; ++i)
if (MAP_FAILED == device->buffers[i].start) {
for (i = 0; i < buf.index; ++i) {
munmap(device->buffers[i].start, device->buffers[i].length);
}
close(device->fd);
free(device);
@ -470,9 +486,10 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if ( -1 == xioctl(device->fd, VIDIOC_QBUF, &buf) ) {
for (i = 0; i < device->n_buffers; ++i)
if (-1 == xioctl(device->fd, VIDIOC_QBUF, &buf)) {
for (i = 0; i < device->n_buffers; ++i) {
munmap(device->buffers[i].start, device->buffers[i].length);
}
close(device->fd);
free(device);
@ -484,7 +501,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
/* Turn on video stream */
if ( -1 == xioctl(device->fd, VIDIOC_STREAMON, &type) ) {
if (-1 == xioctl(device->fd, VIDIOC_STREAMON, &type)) {
close_video_device(vdt_input, temp_idx);
unlock;
return vde_FailedStart;
@ -493,7 +510,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
#endif
/* Create X11 window associated to device */
if ( (device->x_display = XOpenDisplay(NULL)) == NULL ) {
if ((device->x_display = XOpenDisplay(NULL)) == NULL) {
close_video_device(vdt_input, temp_idx);
unlock;
return vde_FailedStart;
@ -501,9 +518,9 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
int screen = DefaultScreen(device->x_display);
if ( !(device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen), 0, 0,
device->video_width, device->video_height, 0, BlackPixel(device->x_display, screen),
BlackPixel(device->x_display, screen))) ) {
if (!(device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen), 0, 0,
device->video_width, device->video_height, 0, BlackPixel(device->x_display, screen),
BlackPixel(device->x_display, screen)))) {
close_video_device(vdt_input, temp_idx);
unlock;
return vde_FailedStart;
@ -512,7 +529,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
XStoreName(device->x_display, device->x_window, "Video Preview");
XSelectInput(device->x_display, device->x_window, ExposureMask | ButtonPressMask | KeyPressMask);
if ( (device->x_gc = DefaultGC(device->x_display, screen)) == NULL ) {
if ((device->x_gc = DefaultGC(device->x_display, screen)) == NULL) {
close_video_device(vdt_input, temp_idx);
unlock;
return vde_FailedStart;
@ -533,7 +550,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
} else { /* vdt_output */
/* Create X11 window associated to device */
if ( (device->x_display = XOpenDisplay(NULL)) == NULL ) {
if ((device->x_display = XOpenDisplay(NULL)) == NULL) {
close_video_device(vdt_output, temp_idx);
unlock;
return vde_FailedStart;
@ -541,8 +558,8 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
int screen = DefaultScreen(device->x_display);
if ( !(device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen), 0, 0,
100, 100, 0, BlackPixel(device->x_display, screen), BlackPixel(device->x_display, screen))) ) {
if (!(device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen), 0, 0,
100, 100, 0, BlackPixel(device->x_display, screen), BlackPixel(device->x_display, screen)))) {
close_video_device(vdt_output, temp_idx);
unlock;
return vde_FailedStart;
@ -551,7 +568,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
XStoreName(device->x_display, device->x_window, "Video Receive");
XSelectInput(device->x_display, device->x_window, ExposureMask | ButtonPressMask | KeyPressMask);
if ( (device->x_gc = DefaultGC(device->x_display, screen)) == NULL ) {
if ((device->x_gc = DefaultGC(device->x_display, screen)) == NULL) {
close_video_device(vdt_output, temp_idx);
unlock;
return vde_FailedStart;
@ -575,21 +592,27 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
return vde_None;
}
__inline VideoDeviceError write_video_out(uint16_t width, uint16_t height,
uint8_t const *y, uint8_t const *u, uint8_t const *v,
int32_t ystride, int32_t ustride, int32_t vstride,
void *user_data)
VideoDeviceError write_video_out(uint16_t width, uint16_t height,
uint8_t const *y, uint8_t const *u, uint8_t const *v,
int32_t ystride, int32_t ustride, int32_t vstride,
void *user_data)
{
UNUSED_VAR(user_data);
VideoDevice *device = video_devices_running[vdt_output][0];
if ( !device ) return vde_DeviceNotActive;
if (!device) {
return vde_DeviceNotActive;
}
if ( !device->x_window ) return vde_DeviceNotActive;
if (!device->x_window) {
return vde_DeviceNotActive;
}
pthread_mutex_lock(device->mutex);
/* Resize X11 window to correct size */
if ( device->video_width != width || device->video_height != height ) {
if (device->video_width != width || device->video_height != height) {
device->video_width = width;
device->video_height = height;
XResizeWindow(device->x_display, device->x_window, width, height);
@ -634,12 +657,12 @@ __inline VideoDeviceError write_video_out(uint16_t width, uint16_t height,
return vde_None;
}
void *video_thread_poll (void *arg) // TODO: maybe use thread for every input source
void *video_thread_poll(void *arg) // TODO: maybe use thread for every input source
{
/*
* NOTE: We only need to poll input devices for data.
*/
(void)arg;
UNUSED_VAR(arg);
uint32_t i;
while (1) {
@ -652,12 +675,13 @@ void *video_thread_poll (void *arg) // TODO: maybe use thread for every input so
unlock;
if ( video_thread_paused ) usleep(10000); /* Wait for unpause. */
else {
if (video_thread_paused) {
usleep(10000); /* Wait for unpause. */
} else {
for (i = 0; i < size[vdt_input]; ++i) {
lock;
if ( video_devices_running[vdt_input][i] != NULL ) {
if (video_devices_running[vdt_input][i] != NULL) {
/* Obtain frame image data from device buffers */
VideoDevice *device = video_devices_running[vdt_input][i];
uint16_t video_width = device->video_width;
@ -666,19 +690,21 @@ void *video_thread_poll (void *arg) // TODO: maybe use thread for every input so
uint8_t *u = device->input.planes[1];
uint8_t *v = device->input.planes[2];
#if defined(__OSX__)
if ( osx_video_read_device(y, u, v, &video_width, &video_height) != 0 ) {
#if defined(__OSX__) || defined(__APPLE__)
if (osx_video_read_device(y, u, v, &video_width, &video_height) != 0) {
unlock;
continue;
}
#else /* not __OSX__*/
#else /* not __OSX__ || __APPLE__ */
struct v4l2_buffer buf;
memset(&(buf), 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if ( -1 == ioctl(device->fd, VIDIOC_DQBUF, &buf) ) {
if (-1 == ioctl(device->fd, VIDIOC_DQBUF, &buf)) {
unlock;
continue;
}
@ -691,8 +717,9 @@ void *video_thread_poll (void *arg) // TODO: maybe use thread for every input so
#endif
/* Send frame data to friend through ToxAV */
if ( device->cb )
if (device->cb) {
device->cb(video_width, video_height, y, u, v, device->cb_data);
}
/* Convert YUV420 data to BGR */
uint8_t *img_data = malloc(video_width * video_height * 4);
@ -724,9 +751,9 @@ void *video_thread_poll (void *arg) // TODO: maybe use thread for every input so
XFlush(device->x_display);
free(img_data);
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#if !(defined(__OSX__) || defined(__APPLE__))
if ( -1 == xioctl(device->fd, VIDIOC_QBUF, &buf) ) {
if (-1 == xioctl(device->fd, VIDIOC_QBUF, &buf)) {
unlock;
continue;
}
@ -747,34 +774,36 @@ void *video_thread_poll (void *arg) // TODO: maybe use thread for every input so
VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
{
if ( device_idx >= MAX_DEVICES ) return vde_InvalidSelection;
if (device_idx >= MAX_DEVICES) {
return vde_InvalidSelection;
}
lock;
VideoDevice *device = video_devices_running[type][device_idx];
VideoDeviceError rc = vde_None;
if ( !device ) {
if (!device) {
unlock;
return vde_DeviceNotActive;
}
video_devices_running[type][device_idx] = NULL;
if ( !device->ref_count ) {
if (!device->ref_count) {
if ( type == vdt_input ) {
#if defined(__OSX__)
if (type == vdt_input) {
#if defined(__OSX__) || defined(__APPLE__)
osx_video_close_device(device_idx);
#else /* not __OSX__ */
#else /* not __OSX__ || __APPLE__ */
enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if ( -1 == xioctl(device->fd, VIDIOC_STREAMOFF, &buf_type) ) {}
if (-1 == xioctl(device->fd, VIDIOC_STREAMOFF, &buf_type)) {}
int i;
for (i = 0; i < device->n_buffers; ++i) {
if ( -1 == munmap(device->buffers[i].start, device->buffers[i].length) ) {
if (-1 == munmap(device->buffers[i].start, device->buffers[i].length)) {
}
}
@ -787,9 +816,9 @@ VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
XCloseDisplay(device->x_display);
pthread_mutex_destroy(device->mutex);
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#if !(defined(__OSX__) || defined(__APPLE__))
free(device->buffers);
#endif /* __linux__ / BSD */
#endif /* not __OSX__ || __APPLE__ */
free(device);
} else {
@ -801,7 +830,9 @@ VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
free(device);
}
} else device->ref_count--;
} else {
device->ref_count--;
}
unlock;
return rc;
@ -811,8 +842,9 @@ void print_video_devices(ToxWindow *self, VideoDeviceType type)
{
int i;
for (i = 0; i < size[type]; ++i)
for (i = 0; i < size[type]; ++i) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%d: %s", i, video_devices_names[type][i]);
}
return;
}
@ -821,3 +853,5 @@ VideoDeviceError video_selection_valid(VideoDeviceType type, int32_t selection)
{
return (size[type] <= selection || selection < 0) ? vde_InvalidSelection : vde_None;
}
#endif /* VIDEO */

View File

@ -45,16 +45,16 @@ typedef enum VideoDeviceError {
vde_CaptureError = -9,
} VideoDeviceError;
typedef void (*VideoDataHandleCallback) (int16_t width, int16_t height, const uint8_t *y, const uint8_t *u,
const uint8_t *v, void *data);
typedef void (*VideoDataHandleCallback)(int16_t width, int16_t height, const uint8_t *y, const uint8_t *u,
const uint8_t *v, void *data);
#ifdef VIDEO
VideoDeviceError init_video_devices(ToxAV *av);
#else
VideoDeviceError init_video_devices();
VideoDeviceError init_video_devices(void);
#endif /* VIDEO */
VideoDeviceError terminate_video_devices();
VideoDeviceError terminate_video_devices(void);
/* Callback handles ready data from INPUT device */
VideoDeviceError register_video_device_callback(int32_t call_idx, uint32_t device_idx, VideoDataHandleCallback callback,
@ -76,4 +76,4 @@ void print_video_devices(ToxWindow *self, VideoDeviceType type);
void get_primary_video_device_name(VideoDeviceType type, char *buf, int size);
VideoDeviceError video_selection_valid(VideoDeviceType type, int32_t selection);
#endif /* VIDEO_DEVICE_H */
#endif /* VIDEO_DEVICE_H */

View File

@ -39,293 +39,316 @@
extern char *DATA_FILE;
extern struct Winthread Winthread;
static ToxWindow windows[MAX_WINDOWS_NUM];
static ToxWindow *active_window;
ToxWindow *windows[MAX_WINDOWS_NUM];
static uint8_t active_window_index;
static int num_active_windows;
extern ToxWindow *prompt;
extern struct user_settings *user_settings;
static int num_active_windows;
/* CALLBACKS START */
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
void on_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
{
UNUSED_VAR(userdata);
char msg[MAX_STR_SIZE + 1];
length = copy_tox_str(msg, sizeof(msg), (const char *) data, length);
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onFriendRequest != NULL) {
windows[i].onFriendRequest(&windows[i], m, (const char *) public_key, msg, length);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onFriendRequest != NULL) {
windows[i]->onFriendRequest(windows[i], m, (const char *) public_key, msg, length);
}
}
}
void on_connectionchange(Tox *m, uint32_t friendnumber, TOX_CONNECTION connection_status, void *userdata)
void on_friend_connection_status(Tox *m, uint32_t friendnumber, Tox_Connection connection_status, void *userdata)
{
size_t i;
UNUSED_VAR(userdata);
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onConnectionChange != NULL)
windows[i].onConnectionChange(&windows[i], m, friendnumber, connection_status);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onConnectionChange != NULL) {
windows[i]->onConnectionChange(windows[i], m, friendnumber, connection_status);
}
}
}
void on_typing_change(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata)
void on_friend_typing(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata)
{
if (user_settings->show_typing_other == SHOW_TYPING_OFF)
UNUSED_VAR(userdata);
if (user_settings->show_typing_other == SHOW_TYPING_OFF) {
return;
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onTypingChange != NULL)
windows[i].onTypingChange(&windows[i], m, friendnumber, is_typing);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onTypingChange != NULL) {
windows[i]->onTypingChange(windows[i], m, friendnumber, is_typing);
}
}
}
void on_message(Tox *m, uint32_t friendnumber, TOX_MESSAGE_TYPE type, const uint8_t *string, size_t length,
void *userdata)
void on_friend_message(Tox *m, uint32_t friendnumber, Tox_Message_Type type, const uint8_t *string, size_t length,
void *userdata)
{
UNUSED_VAR(userdata);
char msg[MAX_STR_SIZE + 1];
length = copy_tox_str(msg, sizeof(msg), (const char *) string, length);
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onMessage != NULL)
windows[i].onMessage(&windows[i], m, friendnumber, type, msg, length);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onMessage != NULL) {
windows[i]->onMessage(windows[i], m, friendnumber, type, msg, length);
}
}
}
void on_nickchange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata)
void on_friend_name(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata)
{
UNUSED_VAR(userdata);
char nick[TOXIC_MAX_NAME_LENGTH + 1];
length = copy_tox_str(nick, sizeof(nick), (const char *) string, length);
filter_str(nick, length);
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onNickChange != NULL)
windows[i].onNickChange(&windows[i], m, friendnumber, nick, length);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onNickChange != NULL) {
windows[i]->onNickChange(windows[i], m, friendnumber, nick, length);
}
}
store_data(m, DATA_FILE);
}
void on_statusmessagechange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata)
void on_friend_status_message(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata)
{
UNUSED_VAR(userdata);
UNUSED_VAR(m);
char msg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
length = copy_tox_str(msg, sizeof(msg), (const char *) string, length);
filter_str(msg, length);
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onStatusMessageChange != NULL)
windows[i].onStatusMessageChange(&windows[i], friendnumber, msg, length);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onStatusMessageChange != NULL) {
windows[i]->onStatusMessageChange(windows[i], friendnumber, msg, length);
}
}
}
void on_statuschange(Tox *m, uint32_t friendnumber, TOX_USER_STATUS status, void *userdata)
void on_friend_status(Tox *m, uint32_t friendnumber, Tox_User_Status status, void *userdata)
{
size_t i;
UNUSED_VAR(userdata);
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onStatusChange != NULL)
windows[i].onStatusChange(&windows[i], m, friendnumber, status);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onStatusChange != NULL) {
windows[i]->onStatusChange(windows[i], m, friendnumber, status);
}
}
}
void on_friendadded(Tox *m, uint32_t friendnumber, bool sort)
void on_friend_added(Tox *m, uint32_t friendnumber, bool sort)
{
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onFriendAdded != NULL)
windows[i].onFriendAdded(&windows[i], m, friendnumber, sort);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onFriendAdded != NULL) {
windows[i]->onFriendAdded(windows[i], m, friendnumber, sort);
}
}
store_data(m, DATA_FILE);
}
void on_groupmessage(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_MESSAGE_TYPE type,
const uint8_t *message, size_t length, void *userdata)
void on_conference_message(Tox *m, uint32_t groupnumber, uint32_t peernumber, Tox_Message_Type type,
const uint8_t *message, size_t length, void *userdata)
{
UNUSED_VAR(userdata);
char msg[MAX_STR_SIZE + 1];
length = copy_tox_str(msg, sizeof(msg), (const char *) message, length);
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupMessage != NULL)
windows[i].onGroupMessage(&windows[i], m, groupnumber, peernumber, type, msg, length);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onGroupMessage != NULL) {
windows[i]->onGroupMessage(windows[i], m, groupnumber, peernumber, type, msg, length);
}
}
}
void on_groupinvite(Tox *m, uint32_t friendnumber, TOX_CONFERENCE_TYPE type, const uint8_t *group_pub_key,
size_t length, void *userdata)
void on_conference_invite(Tox *m, uint32_t friendnumber, Tox_Conference_Type type, const uint8_t *group_pub_key,
size_t length, void *userdata)
{
size_t i;
UNUSED_VAR(userdata);
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupInvite != NULL)
windows[i].onGroupInvite(&windows[i], m, friendnumber, type, (char *) group_pub_key, length);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onGroupInvite != NULL) {
windows[i]->onGroupInvite(windows[i], m, friendnumber, type, (char *) group_pub_key, length);
}
}
}
void on_group_namelistchange(Tox *m, uint32_t groupnumber, void *userdata)
void on_conference_peer_list_changed(Tox *m, uint32_t groupnumber, void *userdata)
{
size_t i;
UNUSED_VAR(userdata);
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupNameListChange != NULL)
windows[i].onGroupNameListChange(&windows[i], m, groupnumber);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onGroupNameListChange != NULL) {
windows[i]->onGroupNameListChange(windows[i], m, groupnumber);
}
}
}
void on_group_peernamechange(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *name,
void on_conference_peer_name(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *name,
size_t length, void *userdata)
{
UNUSED_VAR(userdata);
char nick[TOXIC_MAX_NAME_LENGTH + 1];
length = copy_tox_str(nick, sizeof(nick), (const char *) name, length);
filter_str(nick, length);
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupPeerNameChange != NULL)
windows[i].onGroupPeerNameChange(&windows[i], m, groupnumber, peernumber, nick, length);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onGroupPeerNameChange != NULL) {
windows[i]->onGroupPeerNameChange(windows[i], m, groupnumber, peernumber, nick, length);
}
}
}
void on_group_titlechange(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *title, size_t length,
void *userdata)
void on_conference_title(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *title, size_t length,
void *userdata)
{
UNUSED_VAR(userdata);
char data[MAX_STR_SIZE + 1];
length = copy_tox_str(data, sizeof(data), (const char *) title, length);
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupTitleChange != NULL)
windows[i].onGroupTitleChange(&windows[i], m, groupnumber, peernumber, data, length);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onGroupTitleChange != NULL) {
windows[i]->onGroupTitleChange(windows[i], m, groupnumber, peernumber, data, length);
}
}
}
void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position,
size_t length, void *userdata)
{
UNUSED_VAR(userdata);
struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
if (!ft)
if (!ft) {
return;
}
if (ft->file_type == TOX_FILE_KIND_AVATAR) {
on_avatar_chunk_request(m, ft, position, length);
return;
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onFileChunkRequest != NULL)
windows[i].onFileChunkRequest(&windows[i], m, friendnumber, filenumber, position, length);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onFileChunkRequest != NULL) {
windows[i]->onFileChunkRequest(windows[i], m, friendnumber, filenumber, position, length);
}
}
}
void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position,
const uint8_t *data, size_t length, void *user_data)
const uint8_t *data, size_t length, void *userdata)
{
UNUSED_VAR(userdata);
struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
if (!ft)
if (!ft) {
return;
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onFileRecvChunk != NULL)
windows[i].onFileRecvChunk(&windows[i], m, friendnumber, filenumber, position, (char *) data, length);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onFileRecvChunk != NULL) {
windows[i]->onFileRecvChunk(windows[i], m, friendnumber, filenumber, position, (char *) data, length);
}
}
}
void on_file_control(Tox *m, uint32_t friendnumber, uint32_t filenumber, TOX_FILE_CONTROL control,
void *userdata)
void on_file_recv_control(Tox *m, uint32_t friendnumber, uint32_t filenumber, Tox_File_Control control,
void *userdata)
{
UNUSED_VAR(userdata);
struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
if (!ft)
if (!ft) {
return;
}
if (ft->file_type == TOX_FILE_KIND_AVATAR) {
on_avatar_file_control(m, ft, control);
return;
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onFileControl != NULL)
windows[i].onFileControl(&windows[i], m, friendnumber, filenumber, control);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onFileControl != NULL) {
windows[i]->onFileControl(windows[i], m, friendnumber, filenumber, control);
}
}
}
void on_file_recv(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint32_t kind, uint64_t file_size,
const uint8_t *filename, size_t filename_length, void *userdata)
{
UNUSED_VAR(userdata);
/* We don't care about receiving avatars */
if (kind != TOX_FILE_KIND_DATA) {
tox_file_control(m, friendnumber, filenumber, TOX_FILE_CONTROL_CANCEL, NULL);
return;
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onFileRecv != NULL)
windows[i].onFileRecv(&windows[i], m, friendnumber, filenumber, file_size, (char *) filename,
filename_length);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onFileRecv != NULL) {
windows[i]->onFileRecv(windows[i], m, friendnumber, filenumber, file_size, (char *) filename,
filename_length);
}
}
}
void on_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata)
void on_friend_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata)
{
size_t i;
UNUSED_VAR(userdata);
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onReadReceipt != NULL)
windows[i].onReadReceipt(&windows[i], m, friendnumber, receipt);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onReadReceipt != NULL) {
windows[i]->onReadReceipt(windows[i], m, friendnumber, receipt);
}
}
}
/* CALLBACKS END */
int add_window(Tox *m, ToxWindow w)
int add_window(Tox *m, ToxWindow *w)
{
if (LINES < 2)
if (LINES < 2) {
return -1;
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; i++) {
if (windows[i].active)
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; i++) {
if (windows[i] != NULL) {
continue;
}
w.window = newwin(LINES - 2, COLS, 0, 0);
w->index = i;
w->window = newwin(LINES - 2, COLS, 0, 0);
if (w.window == NULL)
if (w->window == NULL) {
return -1;
}
#ifdef URXVT_FIX
/* Fixes text color problem on some terminals. */
wbkgd(w.window, COLOR_PAIR(6));
wbkgd(w->window, COLOR_PAIR(6));
#endif
windows[i] = w;
if (w.onInit)
w.onInit(&w, m);
if (w->onInit) {
w->onInit(w, m);
}
++num_active_windows;
@ -335,42 +358,46 @@ int add_window(Tox *m, ToxWindow w)
return -1;
}
void set_active_window(int index)
void set_active_window_index(uint8_t index)
{
if (index < 0 || index >= MAX_WINDOWS_NUM)
return;
active_window = windows + index;
if (index < MAX_WINDOWS_NUM) {
active_window_index = index;
}
}
/* Shows next window when tab or back-tab is pressed */
void set_next_window(int ch)
{
ToxWindow *end = windows + MAX_WINDOWS_NUM - 1;
ToxWindow *inf = active_window;
if (ch == user_settings->key_next_tab) {
for (uint8_t i = active_window_index + 1; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL) {
set_active_window_index(i);
return;
}
}
} else {
uint8_t start = active_window_index == 0 ? MAX_WINDOWS_NUM - 1 : active_window_index - 1;
while (true) {
if (ch == user_settings->key_next_tab) {
if (++active_window > end)
active_window = windows;
} else if (--active_window < windows)
active_window = end;
if (active_window->window)
return;
if (active_window == inf) /* infinite loop check */
exit_toxic_err("failed in set_next_window", FATALERR_INFLOOP);
for (uint8_t i = start; i > 0; --i) {
if (windows[i] != NULL) {
set_active_window_index(i);
return;
}
}
}
set_active_window_index(0);
}
/* Deletes window w and cleans up */
void del_window(ToxWindow *w)
{
set_active_window(0); /* Go to prompt screen */
set_active_window_index(0);
uint8_t idx = w->index;
delwin(w->window);
memset(w, 0, sizeof(ToxWindow));
free(windows[idx]);
windows[idx] = NULL;
clear();
refresh();
@ -379,13 +406,18 @@ void del_window(ToxWindow *w)
ToxWindow *init_windows(Tox *m)
{
int n_prompt = add_window(m, new_prompt());
prompt = new_prompt();
int n_prompt = add_window(m, prompt);
if (n_prompt == -1 || add_window(m, new_friendlist()) == -1)
exit_toxic_err("failed in init_windows", FATALERR_WININIT);
if (n_prompt < 0) {
exit_toxic_err("add_window() for prompt failed in init_windows", FATALERR_WININIT);
}
prompt = &windows[n_prompt];
active_window = prompt;
if (add_window(m, new_friendlist()) == -1) {
exit_toxic_err("add_window() for friendlist failed in init_windows", FATALERR_WININIT);
}
set_active_window_index(n_prompt);
return prompt;
}
@ -401,25 +433,26 @@ void on_window_resize(void)
getmaxyx(stdscr, y2, x2);
y2 -= 2;
if (y2 <= 0 || x2 <= 0)
if (y2 <= 0 || x2 <= 0) {
return;
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (!windows[i].active)
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] == NULL) {
continue;
}
ToxWindow *w = &windows[i];
ToxWindow *w = windows[i];
if (windows[i].is_friendlist) {
if (windows[i]->is_friendlist) {
delwin(w->window);
w->window = newwin(y2, x2, 0, 0);
continue;
}
if (w->help->active)
if (w->help->active) {
wclear(w->help->win);
}
if (w->is_groupchat) {
delwin(w->chatwin->sidebar);
@ -441,8 +474,9 @@ void on_window_resize(void)
} else {
w->chatwin->history = subwin(w->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
if (!w->is_groupchat)
if (!w->is_groupchat) {
w->stb->topline = subwin(w->window, 2, x2, 0, 0);
}
}
#ifdef AUDIO
@ -452,7 +486,7 @@ void on_window_resize(void)
w->chatwin->infobox.win = newwin(INFOBOX_HEIGHT, INFOBOX_WIDTH + 1, 1, x2 - INFOBOX_WIDTH);
}
#endif /* AUDIO */
#endif /* AUDIO */
scrollok(w->chatwin->history, 0);
}
@ -462,7 +496,9 @@ static void draw_window_tab(ToxWindow *toxwin)
{
pthread_mutex_lock(&Winthread.lock);
if (toxwin->alert != WINDOW_ALERT_NONE) attron(COLOR_PAIR(toxwin->alert));
if (toxwin->alert != WINDOW_ALERT_NONE) {
attron(COLOR_PAIR(toxwin->alert));
}
pthread_mutex_unlock(&Winthread.lock);
@ -471,7 +507,9 @@ static void draw_window_tab(ToxWindow *toxwin)
pthread_mutex_lock(&Winthread.lock);
if (toxwin->alert != WINDOW_ALERT_NONE) attroff(COLOR_PAIR(toxwin->alert));
if (toxwin->alert != WINDOW_ALERT_NONE) {
attroff(COLOR_PAIR(toxwin->alert));
}
pthread_mutex_unlock(&Winthread.lock);
}
@ -480,8 +518,14 @@ static void draw_bar(void)
{
int y, x;
ToxWindow *w = windows[active_window_index];
if (w == NULL) {
return;
}
// save current cursor position
getyx(active_window->window, y, x);
getyx(w->window, y, x);
attron(COLOR_PAIR(BLUE));
mvhline(LINES - 2, 0, '_', COLS);
@ -489,31 +533,32 @@ static void draw_bar(void)
move(LINES - 1, 0);
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (!windows[i].active)
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] == NULL) {
continue;
}
if (windows + i == active_window)
if (i == active_window_index) {
#ifdef URXVT_FIX
attron(A_BOLD | COLOR_PAIR(GREEN));
else
} else {
#endif
attron(A_BOLD);
}
draw_window_tab(&windows[i]);
draw_window_tab(windows[i]);
if (windows + i == active_window)
if (i == active_window_index) {
#ifdef URXVT_FIX
attroff(A_BOLD | COLOR_PAIR(GREEN));
else
} else {
#endif
attroff(A_BOLD);
}
}
// restore cursor position after drawing
@ -522,86 +567,179 @@ static void draw_bar(void)
refresh();
}
/*
* Gets current char from stdscr and puts it in ch.
*
* Return 1 if char is printable.
* Return 0 if char is not printable.
* Return -1 on error.
*/
static int get_current_char(wint_t *ch)
{
wint_t tmpchar = 0;
bool is_printable = false;
#ifdef HAVE_WIDECHAR
int status = wget_wch(stdscr, &tmpchar);
if (status == ERR) {
return -1;
}
if (status == OK) {
is_printable = iswprint(tmpchar);
}
#else
tmpchar = getch();
if (tmpchar == ERR) {
return -1;
}
is_printable = isprint(tmpchar);
#endif /* HAVE_WIDECHAR */
*ch = tmpchar;
return (int) is_printable;
}
static struct key_sequence_codes {
wchar_t *code;
wint_t key;
} Keys[] = {
{ L"[1;5A", T_KEY_C_UP },
{ L"[1;5B", T_KEY_C_DOWN },
{ L"[1;5C", T_KEY_C_RIGHT },
{ L"[1;5D", T_KEY_C_LEFT },
{ NULL, 0 }
};
/*
* Return key code corresponding to character sequence queued in stdscr.
* Return -1 if sequence is unknown.
*/
#define MAX_SEQUENCE_SIZE 5
static wint_t get_input_sequence_code(void)
{
wchar_t code[MAX_SEQUENCE_SIZE + 1];
size_t length = 0;
wint_t ch = 0;
for (size_t i = 0; i < MAX_SEQUENCE_SIZE; ++i) {
int res = get_current_char(&ch);
if (res < 0) {
break;
}
++length;
code[i] = (wchar_t) ch;
}
if (length == 0) {
return -1;
}
code[length] = L'\0';
for (size_t i = 0; Keys[i].key != 0; ++i) {
if (wcscmp(code, Keys[i].code) == 0) {
return Keys[i].key;
}
}
return -1;
}
void draw_active_window(Tox *m)
{
ToxWindow *a = active_window;
ToxWindow *a = windows[active_window_index];
if (a == NULL) {
return;
}
pthread_mutex_lock(&Winthread.lock);
a->alert = WINDOW_ALERT_NONE;
pthread_mutex_unlock(&Winthread.lock);
wint_t ch = 0;
draw_bar();
touchwin(a->window);
a->onDraw(a, m);
wrefresh(a->window);
/* Handle input */
bool ltr;
#ifdef HAVE_WIDECHAR
int status = wget_wch(stdscr, &ch);
wint_t ch = 0;
int printable = get_current_char(&ch);
if (status == ERR)
if (printable < 0) {
return;
if (status == OK)
ltr = iswprint(ch);
else /* if (status == KEY_CODE_YES) */
ltr = false;
#else
ch = getch();
if (ch == ERR)
return;
/* TODO verify if this works */
ltr = isprint(ch);
#endif /* HAVE_WIDECHAR */
if (!ltr && (ch == user_settings->key_next_tab || ch == user_settings->key_prev_tab)) {
set_next_window((int) ch);
} else {
pthread_mutex_lock(&Winthread.lock);
a->onKey(a, m, ch, ltr);
pthread_mutex_unlock(&Winthread.lock);
}
if (printable == 0 && (ch == user_settings->key_next_tab || ch == user_settings->key_prev_tab)) {
set_next_window((int) ch);
return;
} else if (printable == 0 && !a->is_friendlist) {
pthread_mutex_lock(&Winthread.lock);
bool input_ret = a->onKey(a, m, ch, (bool) printable);
pthread_mutex_unlock(&Winthread.lock);
if (input_ret) {
return;
}
// if an unprintable key code is unrecognized by input handler we attempt to manually decode char sequence
wint_t tmp = get_input_sequence_code();
if (tmp != (wint_t) -1) {
ch = tmp;
}
}
pthread_mutex_lock(&Winthread.lock);
a->onKey(a, m, ch, (bool) printable);
pthread_mutex_unlock(&Winthread.lock);
}
/* refresh inactive windows to prevent scrolling bugs.
call at least once per second */
/* Refresh inactive windows to prevent scrolling bugs.
* Call at least once per second.
*/
void refresh_inactive_windows(void)
{
size_t i;
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
ToxWindow *toxwin = windows[i];
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
ToxWindow *a = &windows[i];
if (toxwin == NULL) {
continue;
}
if (a->active && a != active_window && !a->is_friendlist) {
if (i != active_window_index && !toxwin->is_friendlist) {
pthread_mutex_lock(&Winthread.lock);
line_info_print(a);
line_info_print(toxwin);
pthread_mutex_unlock(&Winthread.lock);
}
}
}
/* returns a pointer to the ToxWindow in the ith index. Returns NULL if no ToxWindow exists */
ToxWindow *get_window_ptr(int i)
/* Returns a pointer to the ToxWindow in the ith index.
* Returns NULL if no ToxWindow exists.
*/
ToxWindow *get_window_ptr(size_t index)
{
ToxWindow *toxwin = NULL;
if (index >= MAX_WINDOWS_NUM) {
return NULL;
}
if (i >= 0 && i < MAX_WINDOWS_NUM && windows[i].active)
toxwin = &windows[i];
return toxwin;
return windows[index];
}
/* returns a pointer to the currently open ToxWindow. */
/* Returns a pointer to the currently active ToxWindow. */
ToxWindow *get_active_window(void)
{
return active_window;
return windows[active_window_index];
}
void force_refresh(WINDOW *w)
@ -619,16 +757,19 @@ int get_num_active_windows(void)
/* destroys all chat and groupchat windows (should only be called on shutdown) */
void kill_all_windows(Tox *m)
{
size_t i;
for (uint8_t i = 2; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] == NULL) {
continue;
}
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].is_chat) {
kill_chat_window(&windows[i], m);
} else if (windows[i].is_groupchat) {
free_groupchat(&windows[i], m, windows[i].num);
if (windows[i]->is_chat) {
kill_chat_window(windows[i], m);
} else if (windows[i]->is_groupchat) {
free_groupchat(windows[i], windows[i]->num);
}
}
kill_prompt_window(prompt);
kill_friendlist();
/* TODO: use enum instead of magic indices */
kill_friendlist(windows[1]);
kill_prompt_window(windows[0]);
}

View File

@ -36,7 +36,7 @@
#include "toxic.h"
#define MAX_WINDOWS_NUM 32
#define MAX_WINDOWS_NUM 16
#define MAX_WINDOW_NAME_LENGTH 22
#define CURS_Y_OFFSET 1 /* y-axis cursor offset for chat contexts */
#define CHATBOX_HEIGHT 2
@ -83,6 +83,7 @@ struct av_thread {
struct arg_opts {
bool use_ipv4;
bool force_tcp;
bool disable_local_discovery;
bool debug;
bool default_locale;
bool use_custom_data;
@ -94,6 +95,9 @@ struct arg_opts {
char config_path[MAX_STR_SIZE];
char nodes_path[MAX_STR_SIZE];
bool logging;
FILE *log_fp;
char proxy_address[256];
uint8_t proxy_type;
uint16_t proxy_port;
@ -109,26 +113,26 @@ typedef struct Help Help;
struct ToxWindow {
/* ncurses */
void(*onKey)(ToxWindow *, Tox *, wint_t, bool);
bool(*onKey)(ToxWindow *, Tox *, wint_t, bool);
void(*onDraw)(ToxWindow *, Tox *);
void(*onInit)(ToxWindow *, Tox *);
/* toxcore */
void(*onFriendRequest)(ToxWindow *, Tox *, const char *, const char *, size_t);
void(*onFriendAdded)(ToxWindow *, Tox *, uint32_t, bool);
void(*onConnectionChange)(ToxWindow *, Tox *, uint32_t, TOX_CONNECTION);
void(*onMessage)(ToxWindow *, Tox *, uint32_t, TOX_MESSAGE_TYPE, const char *, size_t);
void(*onConnectionChange)(ToxWindow *, Tox *, uint32_t, Tox_Connection);
void(*onMessage)(ToxWindow *, Tox *, uint32_t, Tox_Message_Type, const char *, size_t);
void(*onNickChange)(ToxWindow *, Tox *, uint32_t, const char *, size_t);
void(*onStatusChange)(ToxWindow *, Tox *, uint32_t, TOX_USER_STATUS);
void(*onStatusChange)(ToxWindow *, Tox *, uint32_t, Tox_User_Status);
void(*onStatusMessageChange)(ToxWindow *, uint32_t, const char *, size_t);
void(*onGroupMessage)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_MESSAGE_TYPE, const char *, size_t);
void(*onGroupMessage)(ToxWindow *, Tox *, uint32_t, uint32_t, Tox_Message_Type, const char *, size_t);
void(*onGroupInvite)(ToxWindow *, Tox *, int32_t, uint8_t, const char *, uint16_t);
void(*onGroupNameListChange)(ToxWindow *, Tox *, uint32_t);
void(*onGroupPeerNameChange)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t);
void(*onGroupTitleChange)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t);
void(*onFileChunkRequest)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, size_t);
void(*onFileRecvChunk)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, const char *, size_t);
void(*onFileControl)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_FILE_CONTROL);
void(*onFileControl)(ToxWindow *, Tox *, uint32_t, uint32_t, Tox_File_Control);
void(*onFileRecv)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, const char *, size_t);
void(*onTypingChange)(ToxWindow *, Tox *, uint32_t, bool);
void(*onReadReceipt)(ToxWindow *, Tox *, uint32_t, uint32_t);
@ -162,7 +166,7 @@ struct ToxWindow {
char name[TOXIC_MAX_NAME_LENGTH + 1];
uint32_t num; /* corresponds to friendnumber in chat windows */
bool active;
uint8_t index; /* This window's index in the windows array */
int x;
bool is_chat;
@ -187,8 +191,8 @@ struct StatusBar {
size_t statusmsg_len;
char nick[TOXIC_MAX_NAME_LENGTH + 1];
size_t nick_len;
TOX_USER_STATUS status;
TOX_CONNECTION connection;
Tox_User_Status status;
Tox_Connection connection;
};
#ifdef AUDIO
@ -252,18 +256,18 @@ struct Help {
ToxWindow *init_windows(Tox *m);
void draw_active_window(Tox *m);
int add_window(Tox *m, ToxWindow w);
int add_window(Tox *m, ToxWindow *w);
void del_window(ToxWindow *w);
void set_active_window(int ch);
void set_active_window_index(uint8_t index);
int get_num_active_windows(void);
void kill_all_windows(Tox *m); /* should only be called on shutdown */
void on_window_resize(void);
void force_refresh(WINDOW *w);
ToxWindow *get_window_ptr(int i);
ToxWindow *get_window_ptr(size_t i);
ToxWindow *get_active_window(void);
/* refresh inactive windows to prevent scrolling bugs.
call at least once per second */
void refresh_inactive_windows(void);
#endif /* #define WINDOWS_H */
#endif /* WINDOWS_H */

View File

@ -21,6 +21,9 @@
*/
#include "xtra.h"
#include "misc_tools.h"
#ifndef __APPLE__
#include <X11/Xlib.h>
#include <X11/Xatom.h>
@ -47,7 +50,7 @@ static Atom XdndTypeList;
static Atom XdndActionCopy;
static Atom XdndFinished;
struct _Xtra {
struct Xtra {
drop_callback on_drop;
Display *display;
Window terminal_window;
@ -57,14 +60,14 @@ struct _Xtra {
Atom expecting_type;
} Xtra;
typedef struct _Property {
typedef struct Property {
unsigned char *data;
int read_format;
unsigned long read_num;
Atom read_type;
} Property;
Property read_property(Window s, Atom p)
static Property read_property(Window s, Atom p)
{
Atom read_type;
int read_format;
@ -76,7 +79,9 @@ Property read_property(Window s, Atom p)
/* Keep trying to read the property until there are no bytes unread */
do {
if (data) XFree(data);
if (data) {
XFree(data);
}
XGetWindowProperty(Xtra.display, s,
p, 0,
@ -93,12 +98,14 @@ Property read_property(Window s, Atom p)
return property;
}
Atom get_dnd_type(long *a, int l)
static Atom get_dnd_type(long *a, int l)
{
int i = 0;
for (; i < l; i ++) {
if (a[i] != XtraNil) return a[i]; /* Get first valid */
if (a[i] != XtraNil) {
return a[i]; /* Get first valid */
}
}
return XtraNil;
@ -175,6 +182,8 @@ static void handle_xdnd_drop(XClientMessageEvent *e)
static void handle_xdnd_selection(XSelectionEvent *e)
{
UNUSED_VAR(e);
/* DnD succesfully finished, send finished and call callback */
XEvent ev = {
.xclient = {
@ -193,10 +202,11 @@ static void handle_xdnd_selection(XSelectionEvent *e)
Property p = read_property(Xtra.proxy_window, XdndSelection);
DropType dt;
if (strcmp(XGetAtomName(Xtra.display, p.read_type), "text/uri-list") == 0)
if (strcmp(XGetAtomName(Xtra.display, p.read_type), "text/uri-list") == 0) {
dt = DT_file_list;
else /* text/uri-list */
} else { /* text/uri-list */
dt = DT_plain;
}
/* Call callback for every entry */
@ -204,20 +214,25 @@ static void handle_xdnd_selection(XSelectionEvent *e)
char *sptr;
char *str = strtok_r((char *) p.data, "\n\r", &sptr);
if (str) Xtra.on_drop(str, dt);
while ((str = strtok_r(NULL, "\n\r", &sptr)))
if (str) {
Xtra.on_drop(str, dt);
}
while ((str = strtok_r(NULL, "\n\r", &sptr))) {
Xtra.on_drop(str, dt);
}
}
if (p.data) XFree(p.data);
if (p.data) {
XFree(p.data);
}
}
void *event_loop(void *p)
{
/* Handle events like a real nigga */
(void) p; /* DINDUNOTHIN */
UNUSED_VAR(p); /* DINDUNOTHIN */
XEvent event;
int pending;
@ -227,7 +242,9 @@ void *event_loop(void *p)
XLockDisplay(Xtra.display);
if ((pending = XPending(Xtra.display))) XNextEvent(Xtra.display, &event);
if ((pending = XPending(Xtra.display))) {
XNextEvent(Xtra.display, &event);
}
if (!pending) {
XUnlockDisplay(Xtra.display);
@ -238,13 +255,22 @@ void *event_loop(void *p)
if (event.type == ClientMessage) {
Atom type = event.xclient.message_type;
if (type == XdndEnter) handle_xdnd_enter(&event.xclient);
else if (type == XdndPosition) handle_xdnd_position(&event.xclient);
else if (type == XdndDrop) handle_xdnd_drop(&event.xclient);
else if (type == XtraTerminate) break;
} else if (event.type == SelectionNotify) handle_xdnd_selection(&event.xselection);
if (type == XdndEnter) {
handle_xdnd_enter(&event.xclient);
} else if (type == XdndPosition) {
handle_xdnd_position(&event.xclient);
} else if (type == XdndDrop) {
handle_xdnd_drop(&event.xclient);
} else if (type == XtraTerminate) {
break;
}
} else if (event.type == SelectionNotify) {
handle_xdnd_selection(&event.xselection);
}
/* AINNOBODYCANHANDLEDEMEVENTS*/
else XSendEvent(Xtra.display, Xtra.terminal_window, 0, 0, &event);
else {
XSendEvent(Xtra.display, Xtra.terminal_window, 0, 0, &event);
}
XUnlockDisplay(Xtra.display);
}
@ -253,28 +279,53 @@ void *event_loop(void *p)
* Please call xtra_terminate() at exit
* otherwise HEWUSAGUDBOI happens
*/
if (Xtra.display) XCloseDisplay(Xtra.display);
if (Xtra.display) {
XCloseDisplay(Xtra.display);
}
return (Xtra.display = NULL);
}
static long unsigned int focused_window_id(void)
{
if (!Xtra.display) {
return 0;
}
Window focus;
int revert;
XLockDisplay(Xtra.display);
XGetInputFocus(Xtra.display, &focus, &revert);
XUnlockDisplay(Xtra.display);
return focus;
}
int is_focused(void)
{
return Xtra.display && (Xtra.proxy_window == focused_window_id() || Xtra.terminal_window == focused_window_id());
}
int init_xtra(drop_callback d)
{
memset(&Xtra, 0, sizeof(Xtra));
if (!d) return -1;
else Xtra.on_drop = d;
if (!d) {
return -1;
} else {
Xtra.on_drop = d;
}
XInitThreads();
if ( !(Xtra.display = XOpenDisplay(NULL))) return -1;
if (!(Xtra.display = XOpenDisplay(NULL))) {
return -1;
}
Xtra.terminal_window = focused_window_id();
/* OSX: if focused window is 0, it means toxic is ran from
* native terminal and not X11 terminal window, silently exit */
if (!Xtra.terminal_window)
if (!Xtra.terminal_window) {
return 0;
}
{
/* Create an invisible window which will act as proxy for the DnD operation. */
@ -299,17 +350,18 @@ int init_xtra(drop_callback d)
XDefaultRootWindow(Xtra.display),
&root, &x, &y, &wht, &hht, &b, &d);
if (! (Xtra.proxy_window = XCreateWindow
(Xtra.display, Xtra.terminal_window, /* Parent */
0, 0, /* Position */
wht, hht, /* Width + height */
0, /* Border width */
CopyFromParent, /* Depth */
InputOnly, /* Class */
CopyFromParent, /* Visual */
CWEventMask | CWCursor, /* Value mask */
&attr)) ) /* Attributes for value mask */
if (!(Xtra.proxy_window = XCreateWindow
(Xtra.display, Xtra.terminal_window, /* Parent */
0, 0, /* Position */
wht, hht, /* Width + height */
0, /* Border width */
CopyFromParent, /* Depth */
InputOnly, /* Class */
CopyFromParent, /* Visual */
CWEventMask | CWCursor, /* Value mask */
&attr))) { /* Attributes for value mask */
return -1;
}
}
XMapWindow(Xtra.display, Xtra.proxy_window); /* Show window (sandwich) */
@ -339,17 +391,20 @@ int init_xtra(drop_callback d)
pthread_t id;
if (pthread_create(&id, NULL, event_loop, NULL) != 0)
if (pthread_create(&id, NULL, event_loop, NULL) != 0) {
return -1;
}
pthread_detach(id);
return 0;
}
void terminate_xtra()
void terminate_xtra(void)
{
if (!Xtra.display || !Xtra.terminal_window) return;
if (!Xtra.display || !Xtra.terminal_window) {
return;
}
XEvent terminate = {
.xclient = {
@ -367,19 +422,4 @@ void terminate_xtra()
while (Xtra.display); /* Wait for termination */
}
long unsigned int focused_window_id()
{
if (!Xtra.display) return 0;
Window focus;
int revert;
XLockDisplay(Xtra.display);
XGetInputFocus(Xtra.display, &focus, &revert);
XUnlockDisplay(Xtra.display);
return focus;
}
int is_focused()
{
return Xtra.proxy_window == focused_window_id() || Xtra.terminal_window == focused_window_id();
}
#endif /* !__APPLE__ */

Some files were not shown because too many files have changed in this diff Show More