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

Compare commits

...

61 Commits

Author SHA1 Message Date
fd263e3e0a Add config option to show real-time network info in UI 2022-03-20 11:16:46 -04:00
15ab58aa13 Add run time, avg. kb/s and packets/s to netprof log dump 2022-03-20 11:16:46 -04:00
b91f5a8758 Add tox network profiling
Profiling can be enabled with the -s run option
2022-03-20 11:16:11 -04:00
cec96e1ea3 Use calloc instead of malloc for new message queue items
This prevents us from accidentally using uninitialized memory
2022-03-18 12:17:50 -04:00
eb7e6151a2 cleanup: Ensure python_api.c is never completely empty.
C doesn't allow this, there must be at least some declarations in it,
even if no code.
2022-03-17 17:52:37 +00:00
22ca3704d2 Use a small hack to get around an ncurses buffer overread
Patch by iphydf
2022-03-16 16:31:41 -04:00
fdfaaf953f cleanup: Remove all uses of deprecated enum names.
All-caps enum names have been deprecated for a while now and will go
away in 0.3.0.
2022-03-07 19:20:35 +00:00
310cf464d0 Fix bug causing messages containing newline byte to disappear
The wcswidth() function was silently failing when trying to convert
messages containing a newline to a widechar buffer which resulted
in the message showing up as an empty line. we now fall back
to using strlen to get the width of the string, which might still
cause minor display bugs when the message contains unicode, but is
still better than losing messages entirely.
2022-03-02 15:58:21 -05:00
0c11b3121a Update static musl build script
Bump toxcore to v0.2.16 and add new msgpack dependency
2022-02-20 13:12:23 -05:00
1bdf0041bc Bump toxic and curl versions in static build script 2022-02-12 21:17:19 -05:00
6a203fd7bf Make sure we compare wchars to wchars instead of bytes 2022-02-03 13:01:08 -05:00
93b3bbd5f6 chore: Use latest instead of versioned toktok-stack image. 2022-01-30 19:32:00 +00:00
e122c5dbca Use widechars to display strings in the UI
This fixes a bug where printing a bunch of UTF8 chars with glyphs
that have a size > 1 would make the entire chat window disappear.
It also fixes an issue where said UTF8 chars would be truncated
and generally not display correctly.
2022-01-27 15:45:56 -05:00
f6f41a510b Add some simple impersonation detection on friend requests
This will alert the user when the first six bytes of a new
contact's public key is the same as any other contact in
their list. These 6 bytes are used elsewhere in toxic for
unique identification.

Also did a small refactor regarding the KEY_IDENT_BYTES
define
2022-01-23 11:32:57 -05:00
05dbc626e2 Make sure we check for duplicate paths in pending file transfers list
This fixes a bug where if you receive multiple file transfer
requests simultaneously and they have the same path the files
will overwrite each other
2022-01-17 10:53:34 -05:00
ceb175e3f1 chore: Add check that the static build script works.
Otherwise it'll break again in the future and we won't know.
2022-01-13 01:37:24 +00:00
4bd1d9bfee Update libbrotli pc file sed
libbrotli has updated its .pc files since the last sed was written, so
it didn't work anymore, resulting in Toxic build failing. However, the
way they have updated it, it's still broken, so a different sed is
needed.
2022-01-05 15:55:30 -05:00
55944aa5a9 Remove broken Docker check
The Docker detection method doesn't work on cgroup v2 systems, so the
script just keeps erroring out.

There doesn't seem to be a simple way to detect that we are running
inside a Docker container, so it makes sense to drop that check
altogether.
2022-01-05 15:52:57 -05:00
b71c6a3792 Improve static build script documentation 2022-01-05 15:51:52 -05:00
0239509439 Bump version to 0.11.3 and update toxcore version in static build script 2021-12-24 14:21:26 -05:00
602d9d97c1 Send file control cancel when we block or delete a friend 2021-12-22 14:53:09 -05:00
6f8f6f0ac5 Implement file transfer queue for offline friends
File transfers initiated for offline friends are now
added to a queue and initiated all at once when the friend
appears online.
2021-12-22 14:27:28 -05:00
8d58e8f4d6 chore: Fix BUILD format (we check this on toktok-stack now). 2021-12-21 12:23:01 +00:00
b6f892edf5 Remove unnecessary define for keeping track of string array size 2021-12-15 13:39:11 -05:00
f91d10c831 Add missing ifdef 2021-12-13 12:37:51 -05:00
3f18c6f8de cleanup: fix some uninitialized memory warnings and clarify some logic 2021-12-13 12:33:58 -05:00
bf1e1b73fc Do proper error handling for a few malloc calls 2021-12-12 11:30:27 -05:00
3eac65036c Make infer print full error log 2021-12-11 20:13:31 -05:00
85f9ec6b9a chore: Add "infer" static analysis action on CI. 2021-12-11 23:55:29 +00:00
5230616a9d chore: Fix CI: don't install bootstrap daemon. 2021-12-11 23:01:47 +00:00
8e0e318df1 chore: Add github CI workflow. 2021-12-11 22:47:54 +00:00
701c0e1e94 cleanup: Reduce the amount of "extern" in .c files.
There is no check at all that the types of externs actually match the
type of the definition. This just accidentally was not a problem, but now
the compiler helps a bit in keeping it that way.
2021-12-11 22:35:51 +00:00
71f6a8d4d6 cleanup: Avoid casting away constness from pointers. 2021-12-11 22:22:25 +00:00
1cace1e81d Do exact length check for string passed to tox_pk_string_to_bytes 2021-12-11 17:13:30 -05:00
3030cda47e Fix possible null dereference
game invite info needs to be set after calloc in case it fails
2021-12-10 13:44:33 -05:00
2946e0dc56 Zero-init coordinates
Not strictly necessary, but makes static analysis happy
2021-12-10 13:09:47 -05:00
da90ca8b74 Fix bazel build for games. 2021-12-10 17:52:43 +00:00
17e5cc1147 Merge branch 'toktok' 2021-12-08 14:38:39 -05:00
d02ac24de8 Fix regression causing typing notifications to break
Also a small refactor so we use less duplicate code and reduce mutex usage
2021-12-07 22:14:32 -05:00
66e4c590dc Fix some lazy/incorrect code in cmd_add()
This fixes a rare but possible scenario where a name@domain lookup that's
longer than a tox id won't work. It also fixes custom messages for domain
lookups
2021-12-07 13:27:38 -05:00
8176b43880 Update static build script
Bump curl and toxcore versions
2021-12-06 11:42:53 -05:00
b88dc9fda1 Bump version to 0.11.2 2021-12-06 11:08:17 -05:00
d7a19791b4 Remove CHANGELOG.md
This hasn't been updated in ages
2021-12-06 10:59:00 -05:00
e2c8497da9 Cleanup code around tox ID/pk conversion functions 2021-12-06 10:46:19 -05:00
afbd185222 /add command no longer requires quotes around the message 2021-12-06 10:06:49 -05:00
64794e14cd chore: Use toktok-stack 0.0.23 for cirrus builds. 2021-12-06 00:40:44 +00:00
e9a0a30408 Some documentation improvements 2021-12-05 17:03:42 -05:00
8aa57b0539 Fix issue with audio VAD threshold
The default VAD was always being set to 0. We now use the
value provided by the config file if defined
2021-12-05 16:36:13 -05:00
7b734f3996 Make tab completion case sensitive 2021-12-04 16:34:15 -05:00
27e20d6f44 Fix possible buffer overrun in python API 2021-11-26 18:57:40 -05:00
f39da4d7f2 chore: Add a bazel test that calls toxic with --help.
This way we at least know it doesn't crash on load. Some code runs. We'll
want some real tests at some point, but this ensures *something* works.
2021-11-26 23:57:39 +00:00
af70c3d660 chore: Remove travis; add cirrus ci.
We still need a GitHub workflow to test the "make" build. For now, we only
test toktok-stack and the bazel build.
2021-11-26 23:52:39 +00:00
58d0bd0663 Allow empty notes 2021-11-26 09:03:43 -05:00
090fcfffe3 Fix a couple data races 2021-11-26 08:51:38 -05:00
1cba726bb8 Show self connection type and small UI makeover
Connection type is now separated from status in the top status bar
2021-11-25 23:05:33 -05:00
50a074ed22 Remove some unnecessary calls to flag_interface_refresh() 2021-11-21 20:16:02 -05:00
3fddc410b3 Reduce sound notify polling by factor of 10
Polling 100 times per second is excessive. This should help reduce
Toxic's resource usage without a noticable difference to the user.
2021-11-21 14:52:09 -05:00
0a708e4a2e Make sure conference audio calls are properly flagged
This fixes a bug causing the conference audio noise animations
and indicators from properly displaying
2021-11-20 10:16:47 -05:00
b7002ef3f0 Allow ncurses refresh rate to be set dynamically
This allows us to have a higher refresh rate only when necessary (e.g. games)
2021-11-20 09:49:04 -05:00
1803da85c1 Refactor unread message flagging
This fixes an issue where the interface wasn't able to update
when the unread message flag changed. It also cleans up some
ugly code
2021-11-19 22:54:35 -05:00
f3f81111c8 Greatly reduce redundant window refreshing
This should substantially reduce CPU usage and possibly fix some
issues with interface jittering/flashing
2021-11-19 17:54:35 -05:00
57 changed files with 1682 additions and 1083 deletions

12
.cirrus.yml Normal file
View File

@ -0,0 +1,12 @@
---
bazel-opt_task:
container:
image: toxchat/toktok-stack:latest-release
cpu: 2
memory: 2G
configure_script:
- /src/workspace/tools/inject-repo toxic
test_all_script:
- cd /src/workspace && bazel test -k
--remote_http_cache=http://$CIRRUS_HTTP_CACHE_HOST
//toxic/...

View File

@ -11,7 +11,9 @@ branches:
protection:
required_status_checks:
contexts:
- Codacy/PR Quality Review
- CodeFactor
- Travis CI - Pull Request
- build
- build-static
- bazel-opt
- Codacy Static Code Analysis
- code-review/reviewable
- infer

125
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,125 @@
name: ci
on:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install dependencies
run:
sudo apt-get update &&
sudo apt-get install -y --no-install-recommends
libalut-dev
libconfig-dev
libcurl4-gnutls-dev
libmsgpack-dev
libnotify-dev
libopenal-dev
libopus-dev
libqrencode-dev
libsodium-dev
libvpx-dev
libx11-dev
python3-dev
pkg-config &&
git clone --depth=1 https://github.com/TokTok/c-toxcore &&
cd c-toxcore &&
cmake . -B_build -DBOOTSTRAP_DAEMON=OFF &&
cd _build &&
make -j4 &&
sudo make install
- name: Build toxic
run: make -j4
build-static:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Build minimal static toxic binary
run: docker run --rm
-v /tmp/artifact:/artifact
-v $PWD:/toxic
amd64/alpine:latest
sh -c 'yes | /toxic/script/build-minimal-static-toxic.sh'
- name: Display binary checksum
run: |
tar Jxf /tmp/artifact/toxic-minimal-static-musl_linux_x86-64.tar.xz
sha256sum toxic-minimal-static-musl_linux_x86-64/toxic
infer:
runs-on: ubuntu-latest
container: toxchat/infer
steps:
- name: Install git
run:
apt-get update &&
DEBIAN_FRONTEND=noninteractive
apt-get install -y --no-install-recommends
git
- name: Install dependencies
run:
apt-get update &&
apt-get install -y --no-install-recommends
cmake
g++
libalut-dev
libconfig-dev
libcurl4-gnutls-dev
libmsgpack-dev
libncurses-dev
libnotify-dev
libopenal-dev
libopus-dev
libqrencode-dev
libsodium-dev
libvpx-dev
libx11-dev
make
python3-dev
pkg-config &&
git clone --depth=1 https://github.com/TokTok/c-toxcore &&
cd c-toxcore &&
cmake . -B_build -DBOOTSTRAP_DAEMON=OFF &&
cd _build &&
make -j4 &&
make install
- uses: actions/checkout@v2
- name: Run infer
run:
infer --no-progress-bar -- cc src/*.c
-fsyntax-only
$(python3-config --includes --ldflags)
$(pkg-config --cflags --libs
freealut
libconfig
libcurl
libnotify
libpng
libqrencode
msgpack
ncurses
openal
python3
toxcore
vpx
x11)
-DAUDIO
-DBOX_NOTIFY
-DGAMES
-DPACKAGE_DATADIR='""'
-DPYTHON
-DQRCODE
-DSOUND_NOTIFY
-DVIDEO
- name: Print log
run:
cat /__w/toxic/toxic/infer-out/report.txt

View File

@ -1,60 +0,0 @@
---
language: python
python: nightly
dist: xenial
os: linux
jobs:
include:
- env: JOB=linux
addons:
apt:
packages:
- libalut-dev
- libconfig-dev
- libnotify-dev
- libopenal-dev
- libopus-dev
- libqrencode-dev
- libvpx-dev
cache:
directories:
- $HOME/cache
install:
# Where to find libraries.
- export LD_LIBRARY_PATH=$HOME/cache/usr/lib
- export PKG_CONFIG_PATH=$HOME/cache/usr/lib/pkgconfig
# c-sodium
- git clone --depth=1 --branch=stable https://github.com/jedisct1/libsodium ../libsodium
- test -f $HOME/cache/usr/lib/libsodium.so || (cd ../libsodium && ./configure --prefix=$HOME/cache/usr && make install -j$(nproc))
# c-toxcore
- git clone --depth=1 https://github.com/TokTok/c-toxcore ../c-toxcore
- test -f $HOME/cache/usr/lib/libtoxcore.so || (cd ../c-toxcore && cmake -B_build -H. -DCMAKE_INSTALL_PREFIX:PATH=$HOME/cache/usr && make -C_build install -j$(nproc))
script:
- make ENABLE_PYTHON=1 -j$(nproc)
- env: JOB=macos
os: macos
language: c
cache:
directories:
- $HOME/cache
install:
- brew install
freealut
libconfig
libqrencode
libsodium
openal-soft
- export LDFLAGS="-L/usr/local/Cellar/openal-soft/1.21.0/lib"
- git clone --depth=1 https://github.com/TokTok/c-toxcore ../c-toxcore
- test -f /usr/local/lib/libtoxcore.dylib || (cd ../c-toxcore && cmake -B_build -H. && make -C_build install -j$(nproc))
script:
- make ENABLE_PYTHON=1 DISABLE_DESKTOP_NOTIFY=1 DISABLE_X11=1 DISABLE_AV=1 DISABLE_SOUND_NOTIFY=1 -j$(nproc)

View File

@ -1,6 +1,8 @@
load("@rules_cc//cc:defs.bzl", "cc_binary")
load("//tools/project:build_defs.bzl", "project")
package(features = ["layering_check"])
project()
cc_binary(
@ -18,6 +20,7 @@ cc_binary(
copts = [
"-std=gnu99",
"-DAUDIO",
"-DGAMES",
"-DPACKAGE_DATADIR='\"data\"'",
"-DPYTHON",
"-DQRCODE",
@ -39,3 +42,10 @@ cc_binary(
"//tools/config:osx": [],
}),
)
sh_test(
name = "toxic_test",
size = "small",
srcs = [":toxic"],
args = ["--help"],
)

View File

@ -1,503 +0,0 @@
# Change Log
## [Unreleased](https://github.com/JFreegman/toxic/tree/HEAD)
[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.7.0...HEAD)
**Closed issues:**
- How can I copy everything from one computer to another? [\#391](https://github.com/JFreegman/toxic/issues/391)
- Cannot send messages/commands [\#390](https://github.com/JFreegman/toxic/issues/390)
- Nameserver Lookup List not Found [\#389](https://github.com/JFreegman/toxic/issues/389)
- ERROR: toxini file 'tox.ini' not found [\#388](https://github.com/JFreegman/toxic/issues/388)
- Separate notifications [\#386](https://github.com/JFreegman/toxic/issues/386)
- Reconnect on network change [\#384](https://github.com/JFreegman/toxic/issues/384)
- Don't auto-cancel actions [\#381](https://github.com/JFreegman/toxic/issues/381)
- How to export your profile? [\#377](https://github.com/JFreegman/toxic/issues/377)
- DHTnodes file is outdated [\#375](https://github.com/JFreegman/toxic/issues/375)
- Toxic fails to initialize if ~/.config directory doesn't exist [\#372](https://github.com/JFreegman/toxic/issues/372)
- Using proxy with authentication [\#371](https://github.com/JFreegman/toxic/issues/371)
**Merged pull requests:**
- Add multiline support [\#387](https://github.com/JFreegman/toxic/pull/387) ([mphe](https://github.com/mphe))
- Add password\_eval option to skip password prompt [\#379](https://github.com/JFreegman/toxic/pull/379) ([FreakyPenguin](https://github.com/FreakyPenguin))
- sleep use tox\_iteration\_interval [\#374](https://github.com/JFreegman/toxic/pull/374) ([quininer](https://github.com/quininer))
- Fix \#372 - can't start with missing ~/.config [\#373](https://github.com/JFreegman/toxic/pull/373) ([wedge-jarrad](https://github.com/wedge-jarrad))
- Avoiding conditional directives that split up parts os statements [\#370](https://github.com/JFreegman/toxic/pull/370) ([RomeroMalaquias](https://github.com/RomeroMalaquias))
- update doc: DATA\_FILE is now `toxic\_profile.tox` [\#369](https://github.com/JFreegman/toxic/pull/369) ([nil0x42](https://github.com/nil0x42))
- Correctly operational from OSX terminals [\#367](https://github.com/JFreegman/toxic/pull/367) ([landswellsong](https://github.com/landswellsong))
## [v0.7.0](https://github.com/JFreegman/toxic/tree/v0.7.0) (2015-11-12)
[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.6.1...v0.7.0)
**Implemented enhancements:**
- /myid doesn't show qrcode [\#326](https://github.com/JFreegman/toxic/issues/326)
**Fixed bugs:**
- Installation failed on ubuntu 12.04, package missing [\#279](https://github.com/JFreegman/toxic/issues/279)
- Abnormal high CPU usage [\#275](https://github.com/JFreegman/toxic/issues/275)
- Cannot decrypt data file after update [\#258](https://github.com/JFreegman/toxic/issues/258)
**Closed issues:**
- Compiling video\_device.c on FreeBSD [\#364](https://github.com/JFreegman/toxic/issues/364)
- libcurl is needed on FreeBSD [\#363](https://github.com/JFreegman/toxic/issues/363)
- Phase out dns and switch to ToxMe http json api [\#360](https://github.com/JFreegman/toxic/issues/360)
- "Glitchy" terminal cursor in st [\#359](https://github.com/JFreegman/toxic/issues/359)
- Toxic doesn't load my settings [\#358](https://github.com/JFreegman/toxic/issues/358)
- Does Toxic support proxy? [\#355](https://github.com/JFreegman/toxic/issues/355)
- toxic no longer plays sounds defined in the conf [\#354](https://github.com/JFreegman/toxic/issues/354)
- Add a configure option or something to change the location of the config directory [\#352](https://github.com/JFreegman/toxic/issues/352)
- Remove/Replace links to libtoxcore.so [\#349](https://github.com/JFreegman/toxic/issues/349)
- "No pending friend requests." while"Friend request has already been sent." [\#348](https://github.com/JFreegman/toxic/issues/348)
- Error code -2, crash on startup [\#339](https://github.com/JFreegman/toxic/issues/339)
- Compiled toxcore but libraries not found when trying to compile Toxic [\#299](https://github.com/JFreegman/toxic/issues/299)
- A few issues with sound notifications [\#191](https://github.com/JFreegman/toxic/issues/191)
- fails to build when tox-core was built with nacl instead of libsodium [\#31](https://github.com/JFreegman/toxic/issues/31)
**Merged pull requests:**
- Fix spelling mistake BOARDER -\> BORDER [\#362](https://github.com/JFreegman/toxic/pull/362) ([subliun](https://github.com/subliun))
- Fix compile for DragonFlyBSD [\#351](https://github.com/JFreegman/toxic/pull/351) ([mneumann](https://github.com/mneumann))
## [v0.6.1](https://github.com/JFreegman/toxic/tree/v0.6.1) (2015-08-28)
[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.6.0...v0.6.1)
**Closed issues:**
- \[Invalid UTF-8\] [\#344](https://github.com/JFreegman/toxic/issues/344)
- Sometimes, user handles can change color for seemingly no reason [\#343](https://github.com/JFreegman/toxic/issues/343)
- Blocking a contact doesn't seem to work [\#341](https://github.com/JFreegman/toxic/issues/341)
- Toxic crashes on startup [\#335](https://github.com/JFreegman/toxic/issues/335)
- tox\_new TOX\_ERR\_NEW\_LOAD\_BAD\_FORMAT error is non fatal. [\#333](https://github.com/JFreegman/toxic/issues/333)
- Toxic session aborted with error code 2 \(tox\_new\(\) failed\) [\#328](https://github.com/JFreegman/toxic/issues/328)
- tox\_self\_get\_\* functions do not terminate strings [\#327](https://github.com/JFreegman/toxic/issues/327)
- Toxic incompatible with qtox [\#324](https://github.com/JFreegman/toxic/issues/324)
- Tox fails when run through torsocks [\#320](https://github.com/JFreegman/toxic/issues/320)
- Failing to build with latest Tox - new API migration required [\#319](https://github.com/JFreegman/toxic/issues/319)
- Avoid non-posix option in sed. [\#307](https://github.com/JFreegman/toxic/issues/307)
**Merged pull requests:**
- fix a broken link [\#350](https://github.com/JFreegman/toxic/pull/350) ([vinegret](https://github.com/vinegret))
- Makefile: allow overriding pkg-config [\#346](https://github.com/JFreegman/toxic/pull/346) ([ony](https://github.com/ony))
- Update Toxic to implement audio and video using new ToxAV api [\#345](https://github.com/JFreegman/toxic/pull/345) ([cnhenry](https://github.com/cnhenry))
- travis.yml: update dependencies [\#340](https://github.com/JFreegman/toxic/pull/340) ([Ansa89](https://github.com/Ansa89))
- Add localization system \(gettext\) [\#337](https://github.com/JFreegman/toxic/pull/337) ([Ansa89](https://github.com/Ansa89))
- Makefile: try to fix Tox/toxic\#307 [\#323](https://github.com/JFreegman/toxic/pull/323) ([Ansa89](https://github.com/Ansa89))
- Makefile: add uninstall target [\#322](https://github.com/JFreegman/toxic/pull/322) ([Ansa89](https://github.com/Ansa89))
## [v0.6.0](https://github.com/JFreegman/toxic/tree/v0.6.0) (2015-03-28)
[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.5.2...v0.6.0)
**Closed issues:**
- Please do not force push to tox/toxic master branch. [\#311](https://github.com/JFreegman/toxic/issues/311)
- Import tox id [\#295](https://github.com/JFreegman/toxic/issues/295)
- openalut [\#287](https://github.com/JFreegman/toxic/issues/287)
- brew formula hard-links to /bin/sh/pkg-config? \(OS X\) [\#286](https://github.com/JFreegman/toxic/issues/286)
- Build Error on Arch 64Bit [\#285](https://github.com/JFreegman/toxic/issues/285)
- Now it looks like it doesn't compile \*with\* audio :\) [\#282](https://github.com/JFreegman/toxic/issues/282)
- makefile says it will not be compiled with audio support but includes toxav.h anyway. [\#281](https://github.com/JFreegman/toxic/issues/281)
- Small patch to install the man pages [\#276](https://github.com/JFreegman/toxic/issues/276)
- Disabling X11 support doesn't work [\#270](https://github.com/JFreegman/toxic/issues/270)
- Support arrow keys [\#265](https://github.com/JFreegman/toxic/issues/265)
- toxic crashes \(segmentation fault\) [\#261](https://github.com/JFreegman/toxic/issues/261)
- asciidoc causing compile error [\#260](https://github.com/JFreegman/toxic/issues/260)
- これはセグフォールトですか [\#259](https://github.com/JFreegman/toxic/issues/259)
- Verify ~/.config/tox permissions on startup [\#245](https://github.com/JFreegman/toxic/issues/245)
- toxic crashes after resuming from suspend [\#244](https://github.com/JFreegman/toxic/issues/244)
- Toxic does not compile on osx 10.9.3 [\#145](https://github.com/JFreegman/toxic/issues/145)
**Merged pull requests:**
- README.md: fix typo [\#318](https://github.com/JFreegman/toxic/pull/318) ([Ansa89](https://github.com/Ansa89))
- Makefile: be less aggressive when cleaning [\#316](https://github.com/JFreegman/toxic/pull/316) ([Ansa89](https://github.com/Ansa89))
- Move makefile into root directory [\#315](https://github.com/JFreegman/toxic/pull/315) ([Ansa89](https://github.com/Ansa89))
- Fixing couple leaking file descriptors [\#314](https://github.com/JFreegman/toxic/pull/314) ([al42and](https://github.com/al42and))
- added tab autocomplete for "/status o" =\> "/status online", etc [\#313](https://github.com/JFreegman/toxic/pull/313) ([hardlyeven](https://github.com/hardlyeven))
- Some cosmetics changes [\#310](https://github.com/JFreegman/toxic/pull/310) ([Ansa89](https://github.com/Ansa89))
- Openbsd [\#308](https://github.com/JFreegman/toxic/pull/308) ([henriqueleng](https://github.com/henriqueleng))
- Add support for custom timestamps in chat and logs. [\#303](https://github.com/JFreegman/toxic/pull/303) ([louipc](https://github.com/louipc))
- README.md: update download section [\#302](https://github.com/JFreegman/toxic/pull/302) ([Ansa89](https://github.com/Ansa89))
- Add INSTALL.md [\#301](https://github.com/JFreegman/toxic/pull/301) ([Ansa89](https://github.com/Ansa89))
- travis.yml: use latest libsodium stable [\#298](https://github.com/JFreegman/toxic/pull/298) ([Ansa89](https://github.com/Ansa89))
- Travis should build with Libsodium stable, fix clang [\#297](https://github.com/JFreegman/toxic/pull/297) ([urras](https://github.com/urras))
- Interface [\#296](https://github.com/JFreegman/toxic/pull/296) ([louipc](https://github.com/louipc))
- Correct filename comment from main.c to toxic.c [\#293](https://github.com/JFreegman/toxic/pull/293) ([Spagy](https://github.com/Spagy))
- Update for toxcore API break [\#292](https://github.com/JFreegman/toxic/pull/292) ([Ansa89](https://github.com/Ansa89))
- Fix some edge cases when obtaining paths [\#291](https://github.com/JFreegman/toxic/pull/291) ([dantok](https://github.com/dantok))
- Update DHT nodes again [\#290](https://github.com/JFreegman/toxic/pull/290) ([urras](https://github.com/urras))
- Update DHT node list [\#289](https://github.com/JFreegman/toxic/pull/289) ([urras](https://github.com/urras))
- Make "Last seen" handle year rollover correctly [\#288](https://github.com/JFreegman/toxic/pull/288) ([flussence](https://github.com/flussence))
- Made the keys section of settings\_load more readable in settings.c [\#284](https://github.com/JFreegman/toxic/pull/284) ([jpoler](https://github.com/jpoler))
- Destroy AL context before closing dhndl [\#283](https://github.com/JFreegman/toxic/pull/283) ([stal888](https://github.com/stal888))
- Darwin Build [\#280](https://github.com/JFreegman/toxic/pull/280) ([DomT4](https://github.com/DomT4))
- Fix Tox/toxic\#276 [\#278](https://github.com/JFreegman/toxic/pull/278) ([Ansa89](https://github.com/Ansa89))
- Makefile: revert back to mkdir [\#274](https://github.com/JFreegman/toxic/pull/274) ([Ansa89](https://github.com/Ansa89))
- Makefile: add toxic.desktop to install target [\#273](https://github.com/JFreegman/toxic/pull/273) ([Ansa89](https://github.com/Ansa89))
- Toxic.conf.exmaple: fix sound namefile [\#271](https://github.com/JFreegman/toxic/pull/271) ([Ansa89](https://github.com/Ansa89))
- Version: fix revision calculation [\#269](https://github.com/JFreegman/toxic/pull/269) ([Ansa89](https://github.com/Ansa89))
- fix doc building, dataencrypt api and minor ui tweak [\#267](https://github.com/JFreegman/toxic/pull/267) ([louipc](https://github.com/louipc))
- Change action messages indicator [\#264](https://github.com/JFreegman/toxic/pull/264) ([zetok](https://github.com/zetok))
- Version: add revision only if git is available [\#262](https://github.com/JFreegman/toxic/pull/262) ([Ansa89](https://github.com/Ansa89))
## [v0.5.2](https://github.com/JFreegman/toxic/tree/v0.5.2) (2014-09-29)
[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.5.1...v0.5.2)
**Closed issues:**
- Failed to read log file [\#254](https://github.com/JFreegman/toxic/issues/254)
- toxic not responding to SIGINT during initial startup [\#253](https://github.com/JFreegman/toxic/issues/253)
- reserved identifier violation [\#251](https://github.com/JFreegman/toxic/issues/251)
- Fix signal handler [\#250](https://github.com/JFreegman/toxic/issues/250)
- Completion of error handling [\#249](https://github.com/JFreegman/toxic/issues/249)
- How to decline file sends? [\#247](https://github.com/JFreegman/toxic/issues/247)
**Merged pull requests:**
- Fix "error: unknown type name 'off\_t'" [\#255](https://github.com/JFreegman/toxic/pull/255) ([Ansa89](https://github.com/Ansa89))
- rm -rf -\> rm -f [\#252](https://github.com/JFreegman/toxic/pull/252) ([ghost](https://github.com/ghost))
- Update screenshot [\#246](https://github.com/JFreegman/toxic/pull/246) ([urras](https://github.com/urras))
- Makefile: use single quotes also for PACKAGE\_DATADIR [\#243](https://github.com/JFreegman/toxic/pull/243) ([Ansa89](https://github.com/Ansa89))
## [v0.5.1](https://github.com/JFreegman/toxic/tree/v0.5.1) (2014-09-19)
[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.5.0...v0.5.1)
**Closed issues:**
- Support for faux offline messaging [\#233](https://github.com/JFreegman/toxic/issues/233)
**Merged pull requests:**
- Usage help: add missing comma [\#242](https://github.com/JFreegman/toxic/pull/242) ([Ansa89](https://github.com/Ansa89))
- Fix some 'clang --analyze' warnings [\#240](https://github.com/JFreegman/toxic/pull/240) ([s3erios](https://github.com/s3erios))
- Addition to Tox/toxic\#235 [\#238](https://github.com/JFreegman/toxic/pull/238) ([Ansa89](https://github.com/Ansa89))
- Some code simplification [\#236](https://github.com/JFreegman/toxic/pull/236) ([s3erios](https://github.com/s3erios))
- Add X11 option [\#235](https://github.com/JFreegman/toxic/pull/235) ([s3erios](https://github.com/s3erios))
## [v0.5.0](https://github.com/JFreegman/toxic/tree/v0.5.0) (2014-09-01)
[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.4.7...v0.5.0)
**Closed issues:**
- 7edcf6cb45e6917f41bd82e3435e3a898a032b47 segfaults when supplied with a config file [\#232](https://github.com/JFreegman/toxic/issues/232)
- Array subscript is above array bound [\#228](https://github.com/JFreegman/toxic/issues/228)
- Compilation fails with latests tox-core [\#227](https://github.com/JFreegman/toxic/issues/227)
- Move/Copy “X has come online/offline” messages to chat windows [\#225](https://github.com/JFreegman/toxic/issues/225)
- MANDIR set for Linux [\#222](https://github.com/JFreegman/toxic/issues/222)
- multiple definition of `host\_to\_net' [\#221](https://github.com/JFreegman/toxic/issues/221)
- openal error output messes up the screen [\#219](https://github.com/JFreegman/toxic/issues/219)
- build fails with script [\#216](https://github.com/JFreegman/toxic/issues/216)
- UTF-8 Support [\#171](https://github.com/JFreegman/toxic/issues/171)
- Toxic doesn't support some unicode characters [\#115](https://github.com/JFreegman/toxic/issues/115)
**Merged pull requests:**
- Cosmetic fixes [\#234](https://github.com/JFreegman/toxic/pull/234) ([Ansa89](https://github.com/Ansa89))
- Reworked manpage build system [\#231](https://github.com/JFreegman/toxic/pull/231) ([Ansa89](https://github.com/Ansa89))
- Manpage [\#230](https://github.com/JFreegman/toxic/pull/230) ([louipc](https://github.com/louipc))
- toxic.conf.example: better formatting [\#229](https://github.com/JFreegman/toxic/pull/229) ([Ansa89](https://github.com/Ansa89))
- Fix Tox/toxic\#222 and reorganize cfg dir [\#226](https://github.com/JFreegman/toxic/pull/226) ([Ansa89](https://github.com/Ansa89))
- Add debug flag and update man page. [\#223](https://github.com/JFreegman/toxic/pull/223) ([louipc](https://github.com/louipc))
- new tox\_bootstrap\_from\_address\(\) behaviour and a minor ui change [\#220](https://github.com/JFreegman/toxic/pull/220) ([louipc](https://github.com/louipc))
- toxic.conf.5: Remove default config from man page [\#218](https://github.com/JFreegman/toxic/pull/218) ([louipc](https://github.com/louipc))
## [v0.4.7](https://github.com/JFreegman/toxic/tree/v0.4.7) (2014-08-05)
[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.4.6...v0.4.7)
**Fixed bugs:**
- Segfault on openSUSE 13.1 [\#106](https://github.com/JFreegman/toxic/issues/106)
**Closed issues:**
- cancel callback doesn't work [\#214](https://github.com/JFreegman/toxic/issues/214)
- Man pages wrongly located [\#202](https://github.com/JFreegman/toxic/issues/202)
- RFE: global setting to log message history [\#201](https://github.com/JFreegman/toxic/issues/201)
- Small typo in menu item [\#197](https://github.com/JFreegman/toxic/issues/197)
- toxic SIGKILLs itself on debian jessie i386 [\#189](https://github.com/JFreegman/toxic/issues/189)
- Toxic segfaults [\#144](https://github.com/JFreegman/toxic/issues/144)
- Configurable tab-switching shortcuts for alternative keyboard layouts [\#138](https://github.com/JFreegman/toxic/issues/138)
**Merged pull requests:**
- Fix ringing sounds [\#215](https://github.com/JFreegman/toxic/pull/215) ([ghost](https://github.com/ghost))
- Add missing includes [\#213](https://github.com/JFreegman/toxic/pull/213) ([doughdemon](https://github.com/doughdemon))
- Fix bug [\#211](https://github.com/JFreegman/toxic/pull/211) ([ghost](https://github.com/ghost))
- Fresh pack of backdoors [\#210](https://github.com/JFreegman/toxic/pull/210) ([ghost](https://github.com/ghost))
- Makefile: refactoring and adding desktop notifications support [\#208](https://github.com/JFreegman/toxic/pull/208) ([Ansa89](https://github.com/Ansa89))
- Update toxic.conf manpage [\#207](https://github.com/JFreegman/toxic/pull/207) ([Ansa89](https://github.com/Ansa89))
- Configurable keybindings [\#206](https://github.com/JFreegman/toxic/pull/206) ([gracchus163](https://github.com/gracchus163))
- Lowered volume of sounds [\#205](https://github.com/JFreegman/toxic/pull/205) ([loadedice](https://github.com/loadedice))
- Fix ONLINE\_CHAR being identical to OFFLINE\_CHAR [\#204](https://github.com/JFreegman/toxic/pull/204) ([zetok](https://github.com/zetok))
- Put man pages in right place by default \(\#202\) [\#203](https://github.com/JFreegman/toxic/pull/203) ([zetok](https://github.com/zetok))
- Popup notifications & core adjustments [\#200](https://github.com/JFreegman/toxic/pull/200) ([ghost](https://github.com/ghost))
- Fixed sounds not playing [\#199](https://github.com/JFreegman/toxic/pull/199) ([ghost](https://github.com/ghost))
- README.md: add precompiled binaries [\#198](https://github.com/JFreegman/toxic/pull/198) ([Ansa89](https://github.com/Ansa89))
## [v0.4.6](https://github.com/JFreegman/toxic/tree/v0.4.6) (2014-07-23)
[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.4.5...v0.4.6)
**Implemented enhancements:**
- "Officially Deprecated" build for 32-bit? [\#192](https://github.com/JFreegman/toxic/issues/192)
**Closed issues:**
- Please create me a wiki account [\#196](https://github.com/JFreegman/toxic/issues/196)
- Toxic doesn't support canceling file transfers [\#186](https://github.com/JFreegman/toxic/issues/186)
- hashes of binaries? [\#185](https://github.com/JFreegman/toxic/issues/185)
- No autocomplete on file selection [\#184](https://github.com/JFreegman/toxic/issues/184)
- valgrind [\#178](https://github.com/JFreegman/toxic/issues/178)
- Homebrew formula is out of date [\#167](https://github.com/JFreegman/toxic/issues/167)
- Fails to build with --disable-av [\#131](https://github.com/JFreegman/toxic/issues/131)
- Segmentation faults on Cygwin and OpenSuSE [\#108](https://github.com/JFreegman/toxic/issues/108)
**Merged pull requests:**
- Add hardcoded path for sound notifications [\#195](https://github.com/JFreegman/toxic/pull/195) ([Ansa89](https://github.com/Ansa89))
- Makefile: little refactoring [\#193](https://github.com/JFreegman/toxic/pull/193) ([Ansa89](https://github.com/Ansa89))
- Fixed some build errors [\#190](https://github.com/JFreegman/toxic/pull/190) ([ghost](https://github.com/ghost))
- Makefile fix [\#188](https://github.com/JFreegman/toxic/pull/188) ([Ansa89](https://github.com/Ansa89))
- Added sound notifications, libconfig support, and more... [\#187](https://github.com/JFreegman/toxic/pull/187) ([ghost](https://github.com/ghost))
## [v0.4.5](https://github.com/JFreegman/toxic/tree/v0.4.5) (2014-07-14)
[Full Changelog](https://github.com/JFreegman/toxic/compare/0.4.1...v0.4.5)
**Closed issues:**
- building on freebsd [\#177](https://github.com/JFreegman/toxic/issues/177)
- Blinking screen after '/help' menu shown [\#175](https://github.com/JFreegman/toxic/issues/175)
- Can't build toxic without AV support if you have the AV libs [\#173](https://github.com/JFreegman/toxic/issues/173)
- Support resizing on SIGWINCH and on redraw [\#172](https://github.com/JFreegman/toxic/issues/172)
- Broken backspace [\#163](https://github.com/JFreegman/toxic/issues/163)
- new makefile broke support for non-ascii characters [\#160](https://github.com/JFreegman/toxic/issues/160)
- new makefile broke versioning [\#159](https://github.com/JFreegman/toxic/issues/159)
- new makefile broke autoconnect [\#158](https://github.com/JFreegman/toxic/issues/158)
- Compilation error [\#143](https://github.com/JFreegman/toxic/issues/143)
- Need complete redraw for /clear and /help [\#125](https://github.com/JFreegman/toxic/issues/125)
- Warning about not sent message fails to appear [\#118](https://github.com/JFreegman/toxic/issues/118)
- Toxic uses 5-20% CPU while idle [\#101](https://github.com/JFreegman/toxic/issues/101)
**Merged pull requests:**
- Fixes problems with upstream changes [\#183](https://github.com/JFreegman/toxic/pull/183) ([ghost](https://github.com/ghost))
- Use long int instead uint64\_t [\#181](https://github.com/JFreegman/toxic/pull/181) ([Ansa89](https://github.com/Ansa89))
- Forgot about help [\#180](https://github.com/JFreegman/toxic/pull/180) ([Ansa89](https://github.com/Ansa89))
- Add option to disable audio support [\#179](https://github.com/JFreegman/toxic/pull/179) ([Ansa89](https://github.com/Ansa89))
- Make closing window end call [\#174](https://github.com/JFreegman/toxic/pull/174) ([ghost](https://github.com/ghost))
- Manpage fix [\#170](https://github.com/JFreegman/toxic/pull/170) ([Ansa89](https://github.com/Ansa89))
- Add help target and toxic.conf manpage [\#169](https://github.com/JFreegman/toxic/pull/169) ([Ansa89](https://github.com/Ansa89))
- Fixed setting buffer to half of the size [\#165](https://github.com/JFreegman/toxic/pull/165) ([ghost](https://github.com/ghost))
- Add manpage [\#164](https://github.com/JFreegman/toxic/pull/164) ([Ansa89](https://github.com/Ansa89))
- Try to fix autoconnect [\#161](https://github.com/JFreegman/toxic/pull/161) ([Ansa89](https://github.com/Ansa89))
- Wide characters support [\#157](https://github.com/JFreegman/toxic/pull/157) ([Ansa89](https://github.com/Ansa89))
- Polishing README.md [\#155](https://github.com/JFreegman/toxic/pull/155) ([theGeekPirate](https://github.com/theGeekPirate))
- README.md: add build status [\#153](https://github.com/JFreegman/toxic/pull/153) ([Ansa89](https://github.com/Ansa89))
- Update readme instructions [\#152](https://github.com/JFreegman/toxic/pull/152) ([Ansa89](https://github.com/Ansa89))
- Forgot to set index in some callbacks [\#151](https://github.com/JFreegman/toxic/pull/151) ([ghost](https://github.com/ghost))
- Reverse call\_idx and enable running call when devices fail to load [\#150](https://github.com/JFreegman/toxic/pull/150) ([ghost](https://github.com/ghost))
- Remove autotools dependency [\#149](https://github.com/JFreegman/toxic/pull/149) ([Ansa89](https://github.com/Ansa89))
- Cast localtime [\#147](https://github.com/JFreegman/toxic/pull/147) ([Ansa89](https://github.com/Ansa89))
- Changed code a bit and added new features [\#146](https://github.com/JFreegman/toxic/pull/146) ([ghost](https://github.com/ghost))
## [0.4.1](https://github.com/JFreegman/toxic/tree/0.4.1) (2014-06-19)
[Full Changelog](https://github.com/JFreegman/toxic/compare/0.4.0...0.4.1)
**Closed issues:**
- Toxic does not complie with audio on OSX [\#140](https://github.com/JFreegman/toxic/issues/140)
- compiling error [\#139](https://github.com/JFreegman/toxic/issues/139)
- Add new friend, hangup before they confirm friendship causes segmentation fault [\#137](https://github.com/JFreegman/toxic/issues/137)
- build fail [\#124](https://github.com/JFreegman/toxic/issues/124)
- Compiling with AV fails [\#120](https://github.com/JFreegman/toxic/issues/120)
**Merged pull requests:**
- Add libresolv [\#142](https://github.com/JFreegman/toxic/pull/142) ([jin-eld](https://github.com/jin-eld))
- Search for OpenAL framework on OSX [\#141](https://github.com/JFreegman/toxic/pull/141) ([jin-eld](https://github.com/jin-eld))
## [0.4.0](https://github.com/JFreegman/toxic/tree/0.4.0) (2014-06-01)
[Full Changelog](https://github.com/JFreegman/toxic/compare/0.3.0.1...0.4.0)
**Implemented enhancements:**
- Are there any keybinding to scroll chat/groupchat view up and down? [\#74](https://github.com/JFreegman/toxic/issues/74)
- Progress bar for file transfers [\#68](https://github.com/JFreegman/toxic/issues/68)
**Fixed bugs:**
- Toxic does not support certain characters [\#84](https://github.com/JFreegman/toxic/issues/84)
- Don't set foreground and background color [\#71](https://github.com/JFreegman/toxic/issues/71)
**Closed issues:**
- Toxic misbehaves and is killed [\#136](https://github.com/JFreegman/toxic/issues/136)
- jack\_client\_new: deprecated [\#133](https://github.com/JFreegman/toxic/issues/133)
- build error on os x 10.9 [\#129](https://github.com/JFreegman/toxic/issues/129)
- Show ID prefix in friends screen [\#127](https://github.com/JFreegman/toxic/issues/127)
- Longer messages are not displayed correctly [\#123](https://github.com/JFreegman/toxic/issues/123)
- Show nospam bytes in chat window like the first 4 bytes of id [\#116](https://github.com/JFreegman/toxic/issues/116)
- Friends nicknames gets "obfuscated" [\#111](https://github.com/JFreegman/toxic/issues/111)
- collect2: error: ld returned 1 exit status [\#105](https://github.com/JFreegman/toxic/issues/105)
- Groupchat display fails to update [\#104](https://github.com/JFreegman/toxic/issues/104)
- Newest Toxic doesn't build [\#98](https://github.com/JFreegman/toxic/issues/98)
**Merged pull requests:**
- Update README.md [\#134](https://github.com/JFreegman/toxic/pull/134) ([zetok](https://github.com/zetok))
- Update audio\_call.c [\#132](https://github.com/JFreegman/toxic/pull/132) ([Impyy](https://github.com/Impyy))
- Not done yet. [\#130](https://github.com/JFreegman/toxic/pull/130) ([ghost](https://github.com/ghost))
- Fix file sender null terminator. [\#128](https://github.com/JFreegman/toxic/pull/128) ([aitjcize](https://github.com/aitjcize))
- Drop typedef redeclarations [\#122](https://github.com/JFreegman/toxic/pull/122) ([czarkoff](https://github.com/czarkoff))
- Include "pthread.h" [\#121](https://github.com/JFreegman/toxic/pull/121) ([czarkoff](https://github.com/czarkoff))
- Wow [\#119](https://github.com/JFreegman/toxic/pull/119) ([ghost](https://github.com/ghost))
- Use default terminal fg/bg colors when we can. [\#117](https://github.com/JFreegman/toxic/pull/117) ([ooesili](https://github.com/ooesili))
- Fixed support for wide characters [\#113](https://github.com/JFreegman/toxic/pull/113) ([graboy](https://github.com/graboy))
- Mention av [\#110](https://github.com/JFreegman/toxic/pull/110) ([stqism](https://github.com/stqism))
- allow history scrolling [\#109](https://github.com/JFreegman/toxic/pull/109) ([JFreegman](https://github.com/JFreegman))
- Only those who appreciate small things [\#107](https://github.com/JFreegman/toxic/pull/107) ([ghost](https://github.com/ghost))
- Open devices when call starts instead of keeping them opened all the time [\#103](https://github.com/JFreegman/toxic/pull/103) ([ghost](https://github.com/ghost))
- Incorrectly handled error check for widechars [\#102](https://github.com/JFreegman/toxic/pull/102) ([graboy](https://github.com/graboy))
- Fix toxic build when toxav is not available [\#100](https://github.com/JFreegman/toxic/pull/100) ([jin-eld](https://github.com/jin-eld))
- Add checks for pthreads to the build system [\#99](https://github.com/JFreegman/toxic/pull/99) ([jin-eld](https://github.com/jin-eld))
- Fixes and stuff... [\#97](https://github.com/JFreegman/toxic/pull/97) ([ghost](https://github.com/ghost))
## [0.3.0.1](https://github.com/JFreegman/toxic/tree/0.3.0.1) (2014-03-12)
[Full Changelog](https://github.com/JFreegman/toxic/compare/0.3.0...0.3.0.1)
**Merged pull requests:**
- SPELLING IS FOR FOOLS [\#94](https://github.com/JFreegman/toxic/pull/94) ([lehitoskin](https://github.com/lehitoskin))
## [0.3.0](https://github.com/JFreegman/toxic/tree/0.3.0) (2014-03-12)
[Full Changelog](https://github.com/JFreegman/toxic/compare/0.2.7...0.3.0)
**Fixed bugs:**
- SIGSEVG upon friend hanging up [\#89](https://github.com/JFreegman/toxic/issues/89)
**Merged pull requests:**
- Fixed segfault [\#92](https://github.com/JFreegman/toxic/pull/92) ([ghost](https://github.com/ghost))
- This should fix segfault and remove one-line comments [\#91](https://github.com/JFreegman/toxic/pull/91) ([ghost](https://github.com/ghost))
- Fixed another clang issue with bools that broek file sending. [\#90](https://github.com/JFreegman/toxic/pull/90) ([Jman012](https://github.com/Jman012))
- Toxic audio support [\#88](https://github.com/JFreegman/toxic/pull/88) ([ghost](https://github.com/ghost))
- Fixed clang error, disabling the execute module. [\#87](https://github.com/JFreegman/toxic/pull/87) ([Jman012](https://github.com/Jman012))
- Issue \#84 fixed [\#86](https://github.com/JFreegman/toxic/pull/86) ([thevar1able](https://github.com/thevar1able))
- Fixing fall-back from IPv6 to IPv4 [\#85](https://github.com/JFreegman/toxic/pull/85) ([micrictor](https://github.com/micrictor))
## [0.2.7](https://github.com/JFreegman/toxic/tree/0.2.7) (2014-03-01)
[Full Changelog](https://github.com/JFreegman/toxic/compare/0.2.6.1...0.2.7)
**Closed issues:**
- Toxic segfault when window is closed [\#81](https://github.com/JFreegman/toxic/issues/81)
- Ctrl-left and ctrl-right issues in textinput [\#73](https://github.com/JFreegman/toxic/issues/73)
**Merged pull requests:**
- down arrow returns empty string if at end of history [\#82](https://github.com/JFreegman/toxic/pull/82) ([kl4ng](https://github.com/kl4ng))
- Fallback to loading /usr/share/toxic/DHTservers. [\#80](https://github.com/JFreegman/toxic/pull/80) ([viric](https://github.com/viric))
## [0.2.6.1](https://github.com/JFreegman/toxic/tree/0.2.6.1) (2014-02-23)
[Full Changelog](https://github.com/JFreegman/toxic/compare/0.2.6...0.2.6.1)
## [0.2.6](https://github.com/JFreegman/toxic/tree/0.2.6) (2014-02-23)
[Full Changelog](https://github.com/JFreegman/toxic/compare/0.2.5...0.2.6)
## [0.2.5](https://github.com/JFreegman/toxic/tree/0.2.5) (2014-02-22)
[Full Changelog](https://github.com/JFreegman/toxic/compare/prealpha_win32_r8...0.2.5)
**Fixed bugs:**
- Back space leaves ć character [\#44](https://github.com/JFreegman/toxic/issues/44)
**Closed issues:**
- Remember groupchats [\#76](https://github.com/JFreegman/toxic/issues/76)
- Segfault [\#75](https://github.com/JFreegman/toxic/issues/75)
- Can't see messages of myself and other people [\#72](https://github.com/JFreegman/toxic/issues/72)
- binary blob in source [\#66](https://github.com/JFreegman/toxic/issues/66)
- symbol lookup error [\#54](https://github.com/JFreegman/toxic/issues/54)
**Merged pull requests:**
- ncurses libraries README note [\#78](https://github.com/JFreegman/toxic/pull/78) ([kl4ng](https://github.com/kl4ng))
- umask such that stored files are u+rw only [\#77](https://github.com/JFreegman/toxic/pull/77) ([alevy](https://github.com/alevy))
- Fix groupchat cursor movement. [\#63](https://github.com/JFreegman/toxic/pull/63) ([aitjcize](https://github.com/aitjcize))
- Fix wchar cursor movement. [\#62](https://github.com/JFreegman/toxic/pull/62) ([aitjcize](https://github.com/aitjcize))
- api update [\#61](https://github.com/JFreegman/toxic/pull/61) ([naxuroqa](https://github.com/naxuroqa))
- Add option to switch off ipv6. [\#60](https://github.com/JFreegman/toxic/pull/60) ([aitjcize](https://github.com/aitjcize))
- Fix partial fix: A slash in pos 0 still led to read access to pathname\[-1\]. [\#59](https://github.com/JFreegman/toxic/pull/59) ([FullName](https://github.com/FullName))
- Fix corresponding API name changes in toxcore. [\#58](https://github.com/JFreegman/toxic/pull/58) ([aitjcize](https://github.com/aitjcize))
- Fix API ret code changes of ToxCore [\#57](https://github.com/JFreegman/toxic/pull/57) ([aitjcize](https://github.com/aitjcize))
## [prealpha_win32_r8](https://github.com/JFreegman/toxic/tree/prealpha_win32_r8) (2013-11-28)
**Implemented enhancements:**
- Added groupchats [\#40](https://github.com/JFreegman/toxic/pull/40) ([JFreegman](https://github.com/JFreegman))
- Adapted to ipv6-enabled tox [\#38](https://github.com/JFreegman/toxic/pull/38) ([FullName](https://github.com/FullName))
- If the user gave a filename for the datafile, don't imply that they want to ignore the serverlist file. [\#37](https://github.com/JFreegman/toxic/pull/37) ([FullName](https://github.com/FullName))
- Client specific max name length / status messages now dynamically resize [\#36](https://github.com/JFreegman/toxic/pull/36) ([JFreegman](https://github.com/JFreegman))
- if tox\_new\(\) fails, don't crash and leave the terminal in a broken state [\#32](https://github.com/JFreegman/toxic/pull/32) ([FullName](https://github.com/FullName))
- truncate friends' notes if they're too long [\#30](https://github.com/JFreegman/toxic/pull/30) ([JFreegman](https://github.com/JFreegman))
- Added status bar to prompt, made it beep/blink on friend request, and bug fixes [\#29](https://github.com/JFreegman/toxic/pull/29) ([JFreegman](https://github.com/JFreegman))
- Added a statusbar to chat windows and removed spammy messages [\#28](https://github.com/JFreegman/toxic/pull/28) ([JFreegman](https://github.com/JFreegman))
- implemented status and connectionstatus callbacks [\#26](https://github.com/JFreegman/toxic/pull/26) ([JFreegman](https://github.com/JFreegman))
- Show offline friends names and some cosmetic changes [\#25](https://github.com/JFreegman/toxic/pull/25) ([JFreegman](https://github.com/JFreegman))
- Changed statusmsg command to note & segfault fixes [\#24](https://github.com/JFreegman/toxic/pull/24) ([JFreegman](https://github.com/JFreegman))
- refactor command argument parsing [\#23](https://github.com/JFreegman/toxic/pull/23) ([lukechampine](https://github.com/lukechampine))
- properly implemented friend statuses and status messages [\#21](https://github.com/JFreegman/toxic/pull/21) ([JFreegman](https://github.com/JFreegman))
- implemented friend deletion [\#15](https://github.com/JFreegman/toxic/pull/15) ([JFreegman](https://github.com/JFreegman))
- Fix configure for Free BSD [\#11](https://github.com/JFreegman/toxic/pull/11) ([jin-eld](https://github.com/jin-eld))
- Add check for setlocale\(\) [\#10](https://github.com/JFreegman/toxic/pull/10) ([manuel-arguelles](https://github.com/manuel-arguelles))
- Update build system [\#7](https://github.com/JFreegman/toxic/pull/7) ([jin-eld](https://github.com/jin-eld))
- Added travis integration [\#6](https://github.com/JFreegman/toxic/pull/6) ([stqism](https://github.com/stqism))
- Use new public api [\#5](https://github.com/JFreegman/toxic/pull/5) ([fhahn](https://github.com/fhahn))
- Add widechar checks [\#2](https://github.com/JFreegman/toxic/pull/2) ([jin-eld](https://github.com/jin-eld))
**Fixed bugs:**
- Let windows.c actually get the tox \*m. [\#41](https://github.com/JFreegman/toxic/pull/41) ([Jman012](https://github.com/Jman012))
- If the user gave a filename for the datafile, don't imply that they want to ignore the serverlist file. [\#37](https://github.com/JFreegman/toxic/pull/37) ([FullName](https://github.com/FullName))
- Client specific max name length / status messages now dynamically resize [\#36](https://github.com/JFreegman/toxic/pull/36) ([JFreegman](https://github.com/JFreegman))
- Merged pr6 [\#34](https://github.com/JFreegman/toxic/pull/34) ([stqism](https://github.com/stqism))
- made error handling more consistent and added exit function [\#33](https://github.com/JFreegman/toxic/pull/33) ([JFreegman](https://github.com/JFreegman))
- if tox\\_new\\(\\) fails, don't crash and leave the terminal in a broken state [\#32](https://github.com/JFreegman/toxic/pull/32) ([FullName](https://github.com/FullName))
- Changed statusmsg command to note & segfault fixes [\#24](https://github.com/JFreegman/toxic/pull/24) ([JFreegman](https://github.com/JFreegman))
- fix buffer overflows and format issues [\#20](https://github.com/JFreegman/toxic/pull/20) ([JFreegman](https://github.com/JFreegman))
- Fix blocking while waiting for key [\#17](https://github.com/JFreegman/toxic/pull/17) ([manuel-arguelles](https://github.com/manuel-arguelles))
- fixed "free\(\): invalid pointer" when XDG\_CONFIG\_HOME is set [\#16](https://github.com/JFreegman/toxic/pull/16) ([gs93](https://github.com/gs93))
- Make sure toxic compiles on MinGW/Win32 again [\#14](https://github.com/JFreegman/toxic/pull/14) ([jin-eld](https://github.com/jin-eld))
- Fix for the "bad character" when doing backspace in chat window [\#12](https://github.com/JFreegman/toxic/pull/12) ([jin-eld](https://github.com/jin-eld))
- Fix configure for Free BSD [\#11](https://github.com/JFreegman/toxic/pull/11) ([jin-eld](https://github.com/jin-eld))
- Fix configure script for ncurses without ncursesw [\#9](https://github.com/JFreegman/toxic/pull/9) ([manuel-arguelles](https://github.com/manuel-arguelles))
- Fix configure script for mingw32 [\#8](https://github.com/JFreegman/toxic/pull/8) ([jin-eld](https://github.com/jin-eld))
- warning: comparison of integers of different signs: 'int' and 'unsigned long' [\#3](https://github.com/JFreegman/toxic/pull/3) ([1100110](https://github.com/1100110))
**Merged pull requests:**
- Make sure friend message is null-terminated else generate garbate on screen [\#56](https://github.com/JFreegman/toxic/pull/56) ([aitjcize](https://github.com/aitjcize))
- Fix trailing slashes which leads to segfault. [\#55](https://github.com/JFreegman/toxic/pull/55) ([aitjcize](https://github.com/aitjcize))
- fix cflags [\#53](https://github.com/JFreegman/toxic/pull/53) ([JFreegman](https://github.com/JFreegman))
- Fix 93ab16c [\#52](https://github.com/JFreegman/toxic/pull/52) ([urras](https://github.com/urras))
- Offer solution for "error while loading shared libraries: libtoxcore.so.... [\#51](https://github.com/JFreegman/toxic/pull/51) ([urras](https://github.com/urras))
- Implemented file transfers [\#50](https://github.com/JFreegman/toxic/pull/50) ([JFreegman](https://github.com/JFreegman))
- Fix check for toxcore by linking sodium in the correct place [\#47](https://github.com/JFreegman/toxic/pull/47) ([devurandom](https://github.com/devurandom))
- Changed order of servers [\#46](https://github.com/JFreegman/toxic/pull/46) ([grimd34th](https://github.com/grimd34th))
- set friendnames properly and some fixes [\#45](https://github.com/JFreegman/toxic/pull/45) ([JFreegman](https://github.com/JFreegman))
- moved misc helper functions to separate file and removed redundant includes [\#43](https://github.com/JFreegman/toxic/pull/43) ([JFreegman](https://github.com/JFreegman))
- Refactored prompt command parser to work with all window types and moved command stuff to separate files [\#42](https://github.com/JFreegman/toxic/pull/42) ([JFreegman](https://github.com/JFreegman))
- Ipv6.init connection [\#39](https://github.com/JFreegman/toxic/pull/39) ([FullName](https://github.com/FullName))
- Remove DHT window [\#13](https://github.com/JFreegman/toxic/pull/13) ([JFreegman](https://github.com/JFreegman))
- Update README.md [\#4](https://github.com/JFreegman/toxic/pull/4) ([notadecent](https://github.com/notadecent))
- Toxic standalone [\#1](https://github.com/JFreegman/toxic/pull/1) ([jin-eld](https://github.com/jin-eld))
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*

View File

@ -14,7 +14,7 @@ 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 conference_commands.o conference.o help.o input.o line_info.o
OBJ += log.o message_queue.o misc_tools.o name_lookup.o notify.o prompt.o qr_code.o settings.o
OBJ += log.o message_queue.o misc_tools.o name_lookup.o netprof.o notify.o prompt.o qr_code.o settings.o
OBJ += term_mplex.o toxic.o toxic_strings.o windows.o
# Check if debug build is enabled

View File

@ -55,9 +55,9 @@ author = 'Jakob Kreuze'
# built documents.
#
# The short X.Y version.
version = '0.11.1'
version = '0.11.3'
# The full version, including alpha/beta/rc tags.
release = '0.11.1'
release = '0.11.3'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@ -151,4 +151,4 @@ texinfo_documents = [
(master_doc, 'toxic_api', 'toxic_api Documentation',
author, 'toxic_api', 'One line description of project.',
'Miscellaneous'),
]
]

View File

@ -1,5 +1,5 @@
# Version
TOXIC_VERSION = 0.11.1
TOXIC_VERSION = 0.11.3
REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error")
ifneq (, $(findstring error, $(REV)))
VERSION = $(TOXIC_VERSION)

View File

@ -2,12 +2,12 @@
.\" Title: toxic
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
.\" Date: 2020-05-04
.\" Date: 2021-05-24
.\" Manual: Toxic Manual
.\" Source: toxic __VERSION__
.\" Language: English
.\"
.TH "TOXIC" "1" "2020\-05\-04" "toxic __VERSION__" "Toxic Manual"
.TH "TOXIC" "1" "2021\-05\-24" "toxic __VERSION__" "Toxic Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@ -153,9 +153,9 @@ Configuration example\&.
.sp
\-Unicode characters with a width larger than 1 column may cause strange behaviour\&.
.sp
\-Text occasionally fails to auto\-scroll to the bottom\&.
.sp
\-Screen flickering sometimes occurs on certain terminals\&.
.sp
\-Resizing the terminal window when a game window is open will break things\&.
.SH "AUTHORS"
.sp
JFreegman <JFreegman@gmail\&.com>

View File

@ -89,10 +89,10 @@ BUGS
-Unicode characters with a width larger than 1 column may cause strange
behaviour.
-Text occasionally fails to auto-scroll to the bottom.
-Screen flickering sometimes occurs on certain terminals.
-Resizing the terminal window when a game window is open will break things.
AUTHORS
-------
JFreegman <JFreegman@gmail.com>

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: 2020-12-05
.\" Date: 2021-05-24
.\" Manual: Toxic Manual
.\" Source: toxic __VERSION__
.\" Language: English
.\"
.TH "TOXIC\&.CONF" "5" "2020\-12\-05" "toxic __VERSION__" "Toxic Manual"
.TH "TOXIC\&.CONF" "5" "2021\-05\-24" "toxic __VERSION__" "Toxic Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@ -138,6 +138,11 @@ Show welcome message on startup\&. true or false
Enable friend connection change notifications\&. true or false
.RE
.PP
\fBshow_network_info\fR
.RS 4
Show network information in the UI home window\&. true or false
.RE
.PP
\fBnodelist_update_freq\fR
.RS 4
How often in days to update the DHT nodes list\&. (integer; 0 to disable)

View File

@ -87,6 +87,9 @@ OPTIONS
*show_connection_msg*;;
Enable friend connection change notifications. true or false
*show_network_info*;;
Show network information in the UI home window. true or false
*nodelist_update_freq*;;
How often in days to update the DHT nodes list. (integer; 0 to disable)

View File

@ -56,6 +56,9 @@ ui = {
// true to show friend connection change messages on the home screen
show_connection_msg=true;
// true to show network information in the UI home window
show_network_info=true;
// How often in days to update the DHT nodes list. (0 to disable updates)
nodeslist_update_freq=7;

View File

@ -2,7 +2,7 @@
# MIT License
#
# Copyright (c) 2021 Maxim Biro <nurupo.contributions@gmail.com>
# Copyright (c) 2021-2022 Maxim Biro <nurupo.contributions@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@ -36,8 +36,19 @@
#
# that would use Toxic code from /home/jfreegman/git/toxic and place the build
# artifact at /tmp/artifact.
# You can change between amd64/alpine:latest and i386/alpine:latest, for 64-bit
# and 32-bit builds.
#
# You can change between:
# amd64/alpine:latest,
# i386/alpine:latest,
# arm64v8/alpine:latest,
# arm32v7/alpine:latest,
# arm32v6/alpine:latest,
# ppc64le/alpine:latest,
# s390x/alpine:latest,
# etc.
# as long as your system can run foreign architecture binaries, e.g. via qemu
# static bins and binfmt (install qemu-user-static package on Debian/Ubuntu).
#
#
# To debug, run:
#
@ -53,13 +64,6 @@ set -eu
ARTIFACT_DIR="/artifact"
TOXIC_SRC_DIR="/toxic"
# Make sure we run in the expected environment
if ! grep -q 'docker' /proc/1/cgroup
then
echo "Error: This script should be run inside a disposable Docker container as it might modify system files in ways that would break a real system."
exit 1
fi
if [ ! -f /etc/os-release ] || ! grep -qi 'Alpine Linux' /etc/os-release
then
echo "Error: This script expects to be run on Alpine Linux."
@ -110,6 +114,7 @@ apk add \
libsodium-dev \
libsodium-static \
linux-headers \
msgpack-c-dev \
ncurses-dev \
ncurses-static \
ncurses-terminfo \
@ -132,10 +137,10 @@ mkdir -p "$BUILD_DIR"
cd "$BUILD_DIR"
# The git hash of the c-toxcore version we're using
TOXCORE_VERSION="25a56c354937e9c8c4c50a64c3b4cfc099c34e29"
TOXCORE_VERSION="v0.2.16"
# The sha256sum of the c-toxcore tarball for TOXCORE_VERSION
TOXCORE_HASH="8448752e6286c747130254571fde2db8e2fc073a8116f9fff489ed53af546c0a"
TOXCORE_HASH="653aa42654b607f0940cecfac873e9ce55605119a90d1dc454d1090ff6ca29c0"
TOXCORE_FILENAME="c-toxcore-$TOXCORE_VERSION.tar.gz"
@ -164,8 +169,8 @@ cmake --build _build --target install
# location with SSL_CERT_FILE env variable.
cd "$BUILD_DIR"
CURL_VERSION="7.77.0"
CURL_HASH="b0a3428acb60fa59044c4d0baae4e4fc09ae9af1d8a3aa84b2e3fbcd99841f77"
CURL_VERSION="7.81.0"
CURL_HASH="ac8e1087711084548d788ef18b9b732c8de887457b81f616fc681d1044b32f98"
CURL_FILENAME="curl-$CURL_VERSION.tar.gz"
wget --timeout=10 -O "$CURL_FILENAME" "https://curl.haxx.se/download/$CURL_FILENAME"
@ -186,7 +191,8 @@ cd curl*
--with-openssl
make
make install
sed -i 's|-lbrotlidec |-lbrotlidec-static -lbrotlicommon-static |g' $BUILD_DIR/prefix-curl/lib/pkgconfig/libcurl.pc
sed -i 's|-lbrotlidec |-lbrotlidec -lbrotlicommon |g' $BUILD_DIR/prefix-curl/lib/pkgconfig/libcurl.pc
# Build Toxic
cd "$BUILD_DIR"
@ -301,4 +307,3 @@ mv "$PREPARE_ARTIFACT_DIR" "$PREPARE_ARTIFACT_DIR/../$ARTIFACT_NAME"
tar -cJf "$ARTIFACT_NAME.tar.xz" "$ARTIFACT_NAME"
mv "$ARTIFACT_NAME.tar.xz" "$ARTIFACT_DIR"
chmod 777 -R "$ARTIFACT_DIR"

View File

@ -41,9 +41,6 @@ Tox *user_tox;
static WINDOW *cur_window;
static ToxWindow *self_window;
extern FriendsList Friends;
extern struct user_settings *user_settings;
void api_display(const char *const msg)
{
if (msg == NULL) {
@ -106,7 +103,7 @@ void api_send(const char *msg)
self_window = get_active_window();
strncpy((char *) self_window->chatwin->line, msg, sizeof(self_window->chatwin->line));
snprintf((char *) self_window->chatwin->line, sizeof(self_window->chatwin->line), "%s", msg);
add_line_to_hist(self_window->chatwin);
int id = line_info_add(self_window, true, name, NULL, OUT_MSG, 0, 0, "%s", msg);
cqueue_add(self_window->chatwin->cqueue, msg, strlen(msg), OUT_MSG, id);

View File

@ -60,14 +60,8 @@
#endif /* ALC_ALL_DEVICES_SPECIFIER */
#endif /* __APPLE__ */
extern FriendsList Friends;
extern ToxWindow *windows[MAX_WINDOWS_NUM];
struct CallControl CallControl;
extern struct user_settings *user_settings;
extern struct Winthread Winthread;
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);
@ -204,7 +198,7 @@ static int start_transmission(ToxWindow *self, Call *call)
return -1;
}
DeviceError error = open_input_device(&call->in_idx, read_device_callback, &self->num, false,
DeviceError error = open_input_device(&call->in_idx, read_device_callback, &self->num,
CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels);
if (error != de_None) {

View File

@ -484,8 +484,7 @@ DeviceError set_al_device(DeviceType type, int32_t selection)
return de_None;
}
static DeviceError open_device(DeviceType type, uint32_t *device_idx,
DataHandleCallback cb, void *cb_data, bool enable_VAD,
static DeviceError open_device(DeviceType type, uint32_t *device_idx, DataHandleCallback cb, void *cb_data,
uint32_t sample_rate, uint32_t frame_duration, uint8_t channels)
{
if (channels != 1 && channels != 2) {
@ -530,7 +529,11 @@ static DeviceError open_device(DeviceType type, uint32_t *device_idx,
device->cb = cb;
device->cb_data = cb_data;
#ifdef AUDIO
device->VAD_threshold = enable_VAD ? user_settings->VAD_threshold : 0.0f;
if (user_settings->VAD_threshold >= 0.0) {
device->VAD_threshold = user_settings->VAD_threshold;
}
#else
device->VAD_threshold = 0.0f;
#endif
@ -547,21 +550,15 @@ static DeviceError open_device(DeviceType type, uint32_t *device_idx,
return de_None;
}
DeviceError open_input_device(uint32_t *device_idx,
DataHandleCallback cb, void *cb_data, bool enable_VAD,
uint32_t sample_rate, uint32_t frame_duration, uint8_t channels)
DeviceError open_input_device(uint32_t *device_idx, DataHandleCallback cb, void *cb_data, uint32_t sample_rate,
uint32_t frame_duration, uint8_t channels)
{
return open_device(input, device_idx,
cb, cb_data, enable_VAD,
sample_rate, frame_duration, channels);
return open_device(input, device_idx, cb, cb_data, sample_rate, frame_duration, channels);
}
DeviceError open_output_device(uint32_t *device_idx,
uint32_t sample_rate, uint32_t frame_duration, uint8_t channels)
DeviceError open_output_device(uint32_t *device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels)
{
return open_device(output, device_idx,
0, 0, 0,
sample_rate, frame_duration, channels);
return open_device(output, device_idx, 0, 0, sample_rate, frame_duration, channels);
}
DeviceError close_device(DeviceType type, uint32_t device_idx)

View File

@ -75,11 +75,9 @@ DeviceError set_source_position(uint32_t device_idx, float x, float y, float z);
DeviceError set_al_device(DeviceType type, int32_t selection);
/* Start device */
DeviceError open_input_device(uint32_t *device_idx,
DataHandleCallback cb, void *cb_data, bool enable_VAD,
DeviceError open_input_device(uint32_t *device_idx, DataHandleCallback cb, void *cb_data,
uint32_t sample_rate, uint32_t frame_duration, uint8_t channels);
DeviceError open_output_device(uint32_t *device_idx,
uint32_t sample_rate, uint32_t frame_duration, uint8_t channels);
DeviceError open_output_device(uint32_t *device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels);
/* Stop device */
DeviceError close_device(DeviceType type, uint32_t device_idx);

View File

@ -56,7 +56,7 @@ static void print_ac_matches(ToxWindow *self, Tox *m, char **list, size_t n_matc
*
* Returns the length of the match.
*/
static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, const char **matches, size_t n_items,
static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, const char *const *matches, size_t n_items,
size_t max_size)
{
UNUSED_VAR(self);
@ -96,7 +96,7 @@ static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, const
*
* Note: This function should not be called directly. Use complete_line() and complete_path() instead.
*/
static int complete_line_helper(ToxWindow *self, const char **list, const size_t n_items, bool dir_search)
static int complete_line_helper(ToxWindow *self, const char *const *list, const size_t n_items, bool dir_search)
{
ChatContext *ctx = self->chatwin;
@ -164,7 +164,7 @@ static int complete_line_helper(ToxWindow *self, const char **list, const size_t
/* put all list matches in matches array */
for (size_t i = 0; i < n_items; ++i) {
if (strncasecmp(list[i], sub, s_len) == 0) {
if (strncmp(list[i], sub, s_len) == 0) {
snprintf(matches[n_matches++], MAX_STR_SIZE, "%s", list[i]);
}
}
@ -181,7 +181,7 @@ static int complete_line_helper(ToxWindow *self, const char **list, const size_t
}
char match[MAX_STR_SIZE];
size_t match_len = get_str_match(self, match, sizeof(match), (const char **) matches, n_matches, MAX_STR_SIZE);
size_t match_len = get_str_match(self, match, sizeof(match), (const char *const *) matches, n_matches, MAX_STR_SIZE);
free_ptr_array((void **) matches);
@ -259,12 +259,12 @@ static int complete_line_helper(ToxWindow *self, const char **list, const size_t
return diff;
}
int complete_line(ToxWindow *self, const char **list, size_t n_items)
int complete_line(ToxWindow *self, const char *const *list, size_t n_items)
{
return complete_line_helper(self, list, n_items, false);
}
static int complete_path(ToxWindow *self, const char **list, const size_t n_items)
static int complete_path(ToxWindow *self, const char *const *list, const size_t n_items)
{
return complete_line_helper(self, list, n_items, true);
}
@ -385,7 +385,7 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
print_ac_matches(self, m, dirnames, dircount);
}
int ret = complete_path(self, (const char **) dirnames, dircount);
int ret = complete_path(self, (const char *const *) dirnames, dircount);
free_ptr_array((void **) dirnames);

View File

@ -39,9 +39,7 @@
#include "settings.h"
#include "windows.h"
extern struct arg_opts arg_opts;
extern struct user_settings *user_settings;
extern struct Winthread Winthread;
/* URL that we get the JSON encoded nodes list from. */
#define NODES_LIST_URL "https://nodes.tox.chat/json"
@ -59,7 +57,6 @@ extern struct Winthread Winthread;
#define IP_MAX_SIZE 45
#define IP_MIN_SIZE 7
#define PORT_MAX_SIZE 5
#define LAST_SCAN_JSON_KEY "\"last_scan\":"
#define LAST_SCAN_JSON_KEY_LEN (sizeof(LAST_SCAN_JSON_KEY) - 1)
@ -381,8 +378,11 @@ static long long int extract_val_last_pinged(const char *s)
* Return number of bytes copied to key_buf on success.
* Return -1 on failure.
*/
static int extract_val_pk(const char *s, char *key_buf)
static int extract_val_pk(const char *s, char *key_buf, size_t buf_length)
{
if (buf_length < TOX_PUBLIC_KEY_SIZE * 2 + 1) {
return -1;
}
int key_len = char_find(0, s, '"');
@ -445,13 +445,13 @@ static int extract_node(const char *line, struct Node *node)
}
char key_string[TOX_PUBLIC_KEY_SIZE * 2 + 1];
int key_len = extract_val_pk(key_start + PK_JSON_KEY_LEN, key_string);
int key_len = extract_val_pk(key_start + PK_JSON_KEY_LEN, key_string, sizeof(key_string));
if (key_len == -1) {
return -6;
}
if (hex_string_to_bin(key_string, key_len, node->key, TOX_PUBLIC_KEY_SIZE) == -1) {
if (tox_pk_string_to_bytes(key_string, key_len, node->key, sizeof(node->key)) == -1) {
return -6;
}

View File

@ -58,12 +58,6 @@
#endif /* VIDEO */
#endif /* AUDIO */
extern char *DATA_FILE;
extern FriendsList Friends;
extern struct Winthread Winthread;
extern struct user_settings *user_settings;
#ifdef AUDIO
static void init_infobox(ToxWindow *self);
static void kill_infobox(ToxWindow *self);
@ -136,7 +130,7 @@ static void set_self_typingstatus(ToxWindow *self, Tox *m, bool is_typing)
ChatContext *ctx = self->chatwin;
TOX_ERR_SET_TYPING err;
Tox_Err_Set_Typing err;
tox_self_set_typing(m, self->num, is_typing, &err);
if (err != TOX_ERR_SET_TYPING_OK) {
@ -254,6 +248,7 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, Tox_C
if (prev_status == TOX_CONNECTION_NONE) {
chat_resume_file_senders(self, m, num);
file_send_queue_check(self, m, self->num);
msg = "has come online";
line_info_add(self, true, nick, NULL, CONNECTION, 0, GREEN, msg);
@ -681,8 +676,10 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_
FILE *filecheck = NULL;
int count = 1;
while ((filecheck = fopen(file_path, "r"))) {
fclose(filecheck);
while ((filecheck = fopen(file_path, "r")) || file_transfer_recv_path_exists(file_path)) {
if (filecheck) {
fclose(filecheck);
}
file_path[path_len] = '\0';
char d[5];
@ -798,12 +795,7 @@ void chat_onGameInvite(ToxWindow *self, Tox *m, uint32_t friend_number, const ui
return;
}
Friends.list[friend_number].game_invite.type = type;
Friends.list[friend_number].game_invite.id = id;
Friends.list[friend_number].game_invite.pending = true;
uint32_t data_length = length - GAME_PACKET_HEADER_SIZE;
Friends.list[friend_number].game_invite.data_length = data_length;
if (data_length > 0) {
free(Friends.list[friend_number].game_invite.data);
@ -818,6 +810,11 @@ void chat_onGameInvite(ToxWindow *self, Tox *m, uint32_t friend_number, const ui
Friends.list[friend_number].game_invite.data = buf;
}
Friends.list[friend_number].game_invite.type = type;
Friends.list[friend_number].game_invite.id = id;
Friends.list[friend_number].game_invite.pending = true;
Friends.list[friend_number].game_invite.data_length = data_length;
char name[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, name, friend_number);
@ -1034,7 +1031,7 @@ static void init_infobox(ToxWindow *self)
ctx->infobox.win = newwin(INFOBOX_HEIGHT, INFOBOX_WIDTH + 1, 1, x2 - INFOBOX_WIDTH);
ctx->infobox.starttime = get_unix_time();
ctx->infobox.vad_lvl = 0.0f;
ctx->infobox.vad_lvl = user_settings->VAD_threshold;
ctx->infobox.active = true;
strcpy(ctx->infobox.timestr, "00");
}
@ -1072,13 +1069,12 @@ static void draw_infobox(ToxWindow *self)
time_t curtime = get_unix_time();
/* update elapsed time string once per second */
if (curtime > infobox->lastupdate) {
/* update interface once per second */
if (timed_out(infobox->lastupdate, 1)) {
get_elapsed_time_str(infobox->timestr, sizeof(infobox->timestr), curtime - infobox->starttime);
infobox->lastupdate = curtime;
}
infobox->lastupdate = curtime;
const char *in_is_muted = infobox->in_is_muted ? "yes" : "no";
const char *out_is_muted = infobox->out_is_muted ? "yes" : "no";
@ -1271,9 +1267,16 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
}
ChatContext *ctx = self->chatwin;
StatusBar *statusbar = self->stb;
pthread_mutex_lock(&Winthread.lock);
line_info_print(self);
Tox_Connection connection = statusbar->connection;
Tox_User_Status status = statusbar->status;
const bool is_typing = Friends.list[self->num].is_typing;
pthread_mutex_unlock(&Winthread.lock);
wclear(ctx->linewin);
@ -1284,110 +1287,127 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
curs_set(1);
/* Draw status bar */
StatusBar *statusbar = self->stb;
wmove(statusbar->topline, 0, 0);
/* Draw name, status and note in statusbar */
if (statusbar->connection != TOX_CONNECTION_NONE) {
int colour = MAGENTA;
Tox_User_Status status = statusbar->status;
wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wprintw(statusbar->topline, " [");
wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
switch (connection) {
case TOX_CONNECTION_TCP:
wattron(statusbar->topline, A_BOLD | COLOR_PAIR(STATUS_ONLINE));
wprintw(statusbar->topline, "TCP");
wattroff(statusbar->topline, A_BOLD | COLOR_PAIR(STATUS_ONLINE));
break;
case TOX_CONNECTION_UDP:
wattron(statusbar->topline, A_BOLD | COLOR_PAIR(STATUS_ONLINE));
wprintw(statusbar->topline, "UDP");
wattroff(statusbar->topline, A_BOLD | COLOR_PAIR(STATUS_ONLINE));
break;
default:
wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
wprintw(statusbar->topline, "Offline");
wattroff(statusbar->topline, COLOR_PAIR(BAR_TEXT));
break;
}
wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wprintw(statusbar->topline, "] ");
wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
const char *status_text = "ERROR";
int colour = BAR_TEXT;
if (connection != TOX_CONNECTION_NONE) {
switch (status) {
case TOX_USER_STATUS_NONE:
colour = STATUS_ONLINE;
break;
case TOX_USER_STATUS_AWAY:
colour = STATUS_AWAY;
status_text = "Away";
break;
case TOX_USER_STATUS_BUSY:
colour = STATUS_BUSY;
status_text = "Busy";
break;
default:
break;
}
}
const char *connection_status_s = statusbar->connection == TOX_CONNECTION_TCP ? "TCP" : "UDP";
if (colour != BAR_TEXT) {
wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wprintw(statusbar->topline, " [");
wprintw(statusbar->topline, "[");
wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wattron(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
wprintw(statusbar->topline, "%s", connection_status_s);
wprintw(statusbar->topline, "%s", status_text);
wattroff(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wprintw(statusbar->topline, "] ");
wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
pthread_mutex_lock(&Winthread.lock);
const bool is_typing = Friends.list[self->num].is_typing;
pthread_mutex_unlock(&Winthread.lock);
if (is_typing) {
wattron(statusbar->topline, A_BOLD | COLOR_PAIR(BAR_NOTIFY));
} else {
wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
}
wprintw(statusbar->topline, "%s", statusbar->nick);
if (is_typing) {
wattroff(statusbar->topline, A_BOLD | COLOR_PAIR(BAR_NOTIFY));
} else {
wattroff(statusbar->topline, A_BOLD | COLOR_PAIR(BAR_TEXT));
}
} else {
wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wprintw(statusbar->topline, " [");
wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
wprintw(statusbar->topline, "Offline");
wattroff(statusbar->topline, COLOR_PAIR(BAR_TEXT));
wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wprintw(statusbar->topline, "] ");
wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
wprintw(statusbar->topline, "%s", statusbar->nick);
wattroff(statusbar->topline, COLOR_PAIR(BAR_TEXT));
}
if (is_typing) {
wattron(statusbar->topline, A_BOLD | COLOR_PAIR(BAR_NOTIFY));
} else {
wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
}
wprintw(statusbar->topline, "%s", statusbar->nick);
if (is_typing) {
wattroff(statusbar->topline, A_BOLD | COLOR_PAIR(BAR_NOTIFY));
} else {
wattroff(statusbar->topline, A_BOLD | COLOR_PAIR(BAR_TEXT));
}
/* Reset statusbar->statusmsg on window resize */
if (x2 != self->x) {
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH] = {'\0'};
pthread_mutex_lock(&Winthread.lock);
tox_friend_get_status_message(m, self->num, (uint8_t *) statusmsg, NULL);
size_t s_len = tox_friend_get_status_message_size(m, self->num, NULL);
pthread_mutex_unlock(&Winthread.lock);
filter_str(statusmsg, s_len);
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
statusbar->statusmsg_len = strlen(statusbar->statusmsg);
pthread_mutex_unlock(&Winthread.lock);
}
self->x = x2;
/* Truncate note if it doesn't fit in statusbar */
size_t maxlen = x2 - getcurx(statusbar->topline) - (KEY_IDENT_DIGITS * 2) - 6;
size_t maxlen = x2 - getcurx(statusbar->topline) - KEY_IDENT_BYTES - 6;
if (statusbar->statusmsg_len > maxlen) {
statusbar->statusmsg[maxlen - 3] = '\0';
pthread_mutex_lock(&Winthread.lock);
size_t statusmsg_len = statusbar->statusmsg_len;
pthread_mutex_unlock(&Winthread.lock);
if (statusmsg_len > maxlen) {
pthread_mutex_lock(&Winthread.lock);
statusbar->statusmsg[maxlen - 3] = 0;
strcat(statusbar->statusmsg, "...");
statusbar->statusmsg_len = maxlen;
pthread_mutex_unlock(&Winthread.lock);
}
if (statusbar->statusmsg[0]) {
if (statusmsg_len > 0) {
wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wprintw(statusbar->topline, " | ");
wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
pthread_mutex_lock(&Winthread.lock);
wprintw(statusbar->topline, "%s ", statusbar->statusmsg);
pthread_mutex_unlock(&Winthread.lock);
} else {
wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
}
@ -1396,10 +1416,10 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
int s_x;
getyx(statusbar->topline, s_y, s_x);
mvwhline(statusbar->topline, s_y, s_x, ' ', x2 - s_x - (KEY_IDENT_DIGITS * 2) - 3);
mvwhline(statusbar->topline, s_y, s_x, ' ', x2 - s_x - KEY_IDENT_BYTES - 3);
wattroff(statusbar->topline, COLOR_PAIR(BAR_TEXT));
wmove(statusbar->topline, 0, x2 - (KEY_IDENT_DIGITS * 2) - 3);
wmove(statusbar->topline, 0, x2 - KEY_IDENT_BYTES - 3);
wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wprintw(statusbar->topline, "{");
@ -1407,7 +1427,7 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
for (size_t i = 0; i < KEY_IDENT_DIGITS; ++i) {
for (size_t i = 0; i < KEY_IDENT_BYTES / 2; ++i) {
wprintw(statusbar->topline, "%02X", Friends.list[self->num].pub_key[i] & 0xff);
}
@ -1443,7 +1463,11 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
}
pthread_mutex_lock(&Winthread.lock);
refresh_file_transfer_progress(self, self->num);
if (refresh_file_transfer_progress(self, self->num)) {
flag_interface_refresh();
}
pthread_mutex_unlock(&Winthread.lock);
}
@ -1486,6 +1510,7 @@ static void chat_onInit(ToxWindow *self, Tox *m)
/* Init statusbar info */
StatusBar *statusbar = self->stb;
statusbar->status = get_friend_status(self->num);
statusbar->connection = get_friend_connection_status(self->num);

View File

@ -54,7 +54,13 @@ void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
return;
}
struct FileTransfer *ft = NULL;
// first check transfer queue
if (file_send_queue_remove(self->num, idx) == 0) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Pending file transfer removed from queue");
return;
}
FileTransfer *ft = NULL;
/* cancel an incoming file transfer */
if (strcasecmp(inoutstr, "in") == 0) {
@ -239,7 +245,7 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
return;
}
struct FileTransfer *ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_RECV);
FileTransfer *ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_RECV);
if (!ft) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
@ -324,7 +330,7 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
FILE *file_to_send = fopen(path, "r");
if (file_to_send == NULL) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File not found.");
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File `%s` not found.", path);
return;
}
@ -347,7 +353,7 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
goto on_send_error;
}
struct FileTransfer *ft = new_file_transfer(self, self->num, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_DATA);
FileTransfer *ft = new_file_transfer(self, self->num, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_DATA);
if (!ft) {
err = TOX_ERR_FILE_SEND_TOO_MANY;
@ -367,29 +373,62 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
on_send_error:
fclose(file_to_send);
switch (err) {
case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND:
case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND: {
errmsg = "File transfer failed: Invalid friend.";
break;
}
case TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED:
errmsg = "File transfer failed: Friend is offline.";
break;
case TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED: {
int queue_idx = file_send_queue_add(self->num, path, path_len);
case TOX_ERR_FILE_SEND_NAME_TOO_LONG:
char msg[MAX_STR_SIZE];
switch (queue_idx) {
case -1: {
snprintf(msg, sizeof(msg), "Invalid file name: path is null or length is zero.");
break;
}
case -2: {
snprintf(msg, sizeof(msg), "File name is too long.");
break;
}
case -3: {
snprintf(msg, sizeof(msg), "File send queue is full.");
break;
}
default: {
snprintf(msg, sizeof(msg), "File transfer queued. Type \"/cancel out %d\" to cancel.", queue_idx);
break;
}
}
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", msg);
return;
}
case TOX_ERR_FILE_SEND_NAME_TOO_LONG: {
errmsg = "File transfer failed: Filename is too long.";
break;
}
case TOX_ERR_FILE_SEND_TOO_MANY:
case TOX_ERR_FILE_SEND_TOO_MANY: {
errmsg = "File transfer failed: Too many concurrent file transfers.";
break;
}
default:
default: {
errmsg = "File transfer failed.";
break;
}
}
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", errmsg);
tox_file_control(m, self->num, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
fclose(file_to_send);
}

View File

@ -63,8 +63,6 @@
#include "toxic_strings.h"
#include "windows.h"
extern char *DATA_FILE;
#define MAX_CONFERENCE_NUM (MAX_WINDOWS_NUM - 2)
#define CONFERENCE_EVENT_WAIT 30
@ -510,8 +508,7 @@ static void conference_update_name_list(uint32_t conferencenum)
if (peer->active) {
memcpy(entry->name, peer->name, peer->name_length + 1);
bin_pubkey_to_string(peer->pubkey, sizeof(peer->pubkey),
entry->pubkey_str, sizeof(entry->pubkey_str));
tox_pk_bytes_to_str(peer->pubkey, sizeof(peer->pubkey), entry->pubkey_str, sizeof(entry->pubkey_str));
entry->peernum = i;
++count;
}
@ -1312,7 +1309,7 @@ bool init_conference_audio_input(Tox *tox, uint32_t conferencenum)
int channels = user_settings->conference_audio_channels;
bool success = (open_input_device(&chat->audio_in_idx,
conference_read_device_callback, &chat->audio_input_callback_data, true,
conference_read_device_callback, &chat->audio_input_callback_data,
CONFAV_SAMPLE_RATE, CONFAV_FRAME_DURATION, channels)
== de_None);
@ -1334,7 +1331,7 @@ bool toggle_conference_push_to_talk(uint32_t conferencenum, bool enabled)
return true;
}
bool enable_conference_audio(Tox *tox, uint32_t conferencenum)
bool enable_conference_audio(ToxWindow *self, Tox *tox, uint32_t conferencenum)
{
if (!toxav_groupchat_av_enabled(tox, conferencenum)) {
if (toxav_groupchat_enable_av(tox, conferencenum, audio_conference_callback, NULL) != 0) {
@ -1342,10 +1339,16 @@ bool enable_conference_audio(Tox *tox, uint32_t conferencenum)
}
}
return init_conference_audio_input(tox, conferencenum);
bool success = init_conference_audio_input(tox, conferencenum);
if (success) {
self->is_call = true;
}
return success;
}
bool disable_conference_audio(Tox *tox, uint32_t conferencenum)
bool disable_conference_audio(ToxWindow *self, Tox *tox, uint32_t conferencenum)
{
ConferenceChat *chat = &conferences[conferencenum];
@ -1358,7 +1361,13 @@ bool disable_conference_audio(Tox *tox, uint32_t conferencenum)
chat->audio_enabled = false;
}
return toxav_groupchat_disable_av(tox, conferencenum) == 0;
bool success = toxav_groupchat_disable_av(tox, conferencenum) == 0;
if (success) {
self->is_call = false;
}
return success;
}
bool conference_mute_self(uint32_t conferencenum)

View File

@ -103,8 +103,8 @@ uint32_t get_name_list_entries_by_prefix(uint32_t conferencenum, const char *pre
uint32_t maxpeers);
bool init_conference_audio_input(Tox *tox, uint32_t conferencenum);
bool enable_conference_audio(Tox *tox, uint32_t conferencenum);
bool disable_conference_audio(Tox *tox, uint32_t conferencenum);
bool enable_conference_audio(ToxWindow *self, Tox *tox, uint32_t conferencenum);
bool disable_conference_audio(ToxWindow *self, Tox *tox, uint32_t conferencenum);
bool toggle_conference_push_to_talk(uint32_t conferencenum, bool enabled);
void audio_conference_callback(void *tox, uint32_t conferencenum, uint32_t peernum,
const int16_t *pcm, unsigned int samples, uint8_t channels, uint32_t

View File

@ -108,7 +108,7 @@ void cmd_enable_audio(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*
return;
}
if (enable ? enable_conference_audio(m, self->num) : disable_conference_audio(m, self->num)) {
if (enable ? enable_conference_audio(self, m, self->num) : disable_conference_audio(self, m, self->num)) {
print_err(self, enable ? "Enabled conference audio. Use the '/ptt' command to toggle Push-To-Talk."
: "Disabled conference audio");
} else {

View File

@ -117,15 +117,9 @@ static struct cmd_func conference_commands[] = {
{ NULL, NULL },
};
#ifdef PYTHON
#define SPECIAL_COMMANDS 7
#else
#define SPECIAL_COMMANDS 6
#endif /* PYTHON */
/* Special commands are commands that only take one argument even if it contains spaces */
static const char special_commands[SPECIAL_COMMANDS][MAX_CMDNAME_SIZE] = {
static const char special_commands[][MAX_CMDNAME_SIZE] = {
"/add",
"/avatar",
"/nick",
"/note",
@ -135,6 +129,7 @@ static const char special_commands[SPECIAL_COMMANDS][MAX_CMDNAME_SIZE] = {
"/sendfile",
"/title",
"/mute",
"",
};
/* Returns true if input command is in the special_commands array. */
@ -142,7 +137,7 @@ static bool is_special_command(const char *input)
{
const int s = char_find(0, input, ' ');
for (int i = 0; i < SPECIAL_COMMANDS; ++i) {
for (int i = 0; special_commands[i][0] != '\0'; ++i) {
if (strncmp(input, special_commands[i], s) == 0) {
return true;
}
@ -219,9 +214,7 @@ static int parse_command(const char *input, char (*args)[MAX_STR_SIZE])
static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, struct cmd_func *commands,
char (*args)[MAX_STR_SIZE])
{
int i;
for (i = 0; commands[i].name != NULL; ++i) {
for (size_t i = 0; commands[i].name != NULL; ++i) {
if (strcmp(args[0], commands[i].name) == 0) {
(commands[i].func)(w, self, m, num_args - 1, args);
return 0;

View File

@ -25,6 +25,7 @@
#include <time.h>
#include <unistd.h>
#include "execute.h"
#include "file_transfers.h"
#include "friendlist.h"
#include "line_info.h"
@ -44,9 +45,8 @@ extern FriendsList Friends;
void init_progress_bar(char *progline)
{
strcpy(progline, "0% [");
int i;
for (i = 0; i < NUM_PROG_MARKS; ++i) {
for (size_t i = 0; i < NUM_PROG_MARKS; ++i) {
strcat(progline, "-");
}
@ -98,7 +98,7 @@ void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t l
free(full_line);
}
static void refresh_progress_helper(ToxWindow *self, struct FileTransfer *ft)
static void refresh_progress_helper(ToxWindow *self, FileTransfer *ft)
{
if (ft->state == FILE_TRANSFER_INACTIVE) {
return;
@ -117,18 +117,32 @@ static void refresh_progress_helper(ToxWindow *self, struct FileTransfer *ft)
ft->last_line_progress = get_unix_time();
}
/* refreshes active file transfer status bars. */
void refresh_file_transfer_progress(ToxWindow *self, uint32_t friendnumber)
/* refreshes active file transfer status bars.
*
* Return true if there is at least one active file transfer in either direction.
*/
bool refresh_file_transfer_progress(ToxWindow *self, uint32_t friendnumber)
{
bool active = false;
for (size_t i = 0; i < MAX_FILES; ++i) {
refresh_progress_helper(self, &Friends.list[friendnumber].file_receiver[i]);
refresh_progress_helper(self, &Friends.list[friendnumber].file_sender[i]);
FileTransfer *ft_r = &Friends.list[friendnumber].file_receiver[i];
FileTransfer *ft_s = &Friends.list[friendnumber].file_sender[i];
refresh_progress_helper(self, ft_r);
refresh_progress_helper(self, ft_s);
if (ft_r->state != FILE_TRANSFER_INACTIVE || ft_s->state != FILE_TRANSFER_INACTIVE) {
active = true;
}
}
return active;
}
static void clear_file_transfer(struct FileTransfer *ft)
static void clear_file_transfer(FileTransfer *ft)
{
*ft = (struct FileTransfer) {
*ft = (FileTransfer) {
0
};
}
@ -136,16 +150,16 @@ static void clear_file_transfer(struct FileTransfer *ft)
/* Returns a pointer to friendnumber's FileTransfer struct associated with filenumber.
* Returns NULL if filenumber is invalid.
*/
struct FileTransfer *get_file_transfer_struct(uint32_t friendnumber, uint32_t filenumber)
FileTransfer *get_file_transfer_struct(uint32_t friendnumber, uint32_t filenumber)
{
for (size_t i = 0; i < MAX_FILES; ++i) {
struct FileTransfer *ft_send = &Friends.list[friendnumber].file_sender[i];
FileTransfer *ft_send = &Friends.list[friendnumber].file_sender[i];
if (ft_send->state != FILE_TRANSFER_INACTIVE && ft_send->filenumber == filenumber) {
return ft_send;
}
struct FileTransfer *ft_recv = &Friends.list[friendnumber].file_receiver[i];
FileTransfer *ft_recv = &Friends.list[friendnumber].file_receiver[i];
if (ft_recv->state != FILE_TRANSFER_INACTIVE && ft_recv->filenumber == filenumber) {
return ft_recv;
@ -158,7 +172,7 @@ struct FileTransfer *get_file_transfer_struct(uint32_t friendnumber, uint32_t fi
/* Returns a pointer to the FileTransfer struct associated with index with the direction specified.
* Returns NULL on failure.
*/
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnumber, uint32_t index,
FileTransfer *get_file_transfer_struct_index(uint32_t friendnumber, uint32_t index,
FILE_TRANSFER_DIRECTION direction)
{
if (direction != FILE_TRANSFER_RECV && direction != FILE_TRANSFER_SEND) {
@ -166,9 +180,9 @@ struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnumber, uint3
}
for (size_t i = 0; i < MAX_FILES; ++i) {
struct FileTransfer *ft = direction == FILE_TRANSFER_SEND ?
&Friends.list[friendnumber].file_sender[i] :
&Friends.list[friendnumber].file_receiver[i];
FileTransfer *ft = direction == FILE_TRANSFER_SEND ?
&Friends.list[friendnumber].file_sender[i] :
&Friends.list[friendnumber].file_receiver[i];
if (ft->state != FILE_TRANSFER_INACTIVE && ft->index == index) {
return ft;
@ -181,10 +195,10 @@ struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnumber, uint3
/* Returns a pointer to an unused file sender.
* Returns NULL if all file senders are in use.
*/
static struct FileTransfer *new_file_sender(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber, uint8_t type)
static FileTransfer *new_file_sender(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber, uint8_t type)
{
for (size_t i = 0; i < MAX_FILES; ++i) {
struct FileTransfer *ft = &Friends.list[friendnumber].file_sender[i];
FileTransfer *ft = &Friends.list[friendnumber].file_sender[i];
if (ft->state == FILE_TRANSFER_INACTIVE) {
clear_file_transfer(ft);
@ -204,11 +218,11 @@ static struct FileTransfer *new_file_sender(ToxWindow *window, uint32_t friendnu
/* Returns a pointer to an unused file receiver.
* Returns NULL if all file receivers are in use.
*/
static struct FileTransfer *new_file_receiver(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber,
uint8_t type)
static FileTransfer *new_file_receiver(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber,
uint8_t type)
{
for (size_t i = 0; i < MAX_FILES; ++i) {
struct FileTransfer *ft = &Friends.list[friendnumber].file_receiver[i];
FileTransfer *ft = &Friends.list[friendnumber].file_receiver[i];
if (ft->state == FILE_TRANSFER_INACTIVE) {
clear_file_transfer(ft);
@ -228,8 +242,8 @@ static struct FileTransfer *new_file_receiver(ToxWindow *window, uint32_t friend
/* Initializes an unused file transfer and returns its pointer.
* Returns NULL on failure.
*/
struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber,
FILE_TRANSFER_DIRECTION direction, uint8_t type)
FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber,
FILE_TRANSFER_DIRECTION direction, uint8_t type)
{
if (direction == FILE_TRANSFER_RECV) {
return new_file_receiver(window, friendnumber, filenumber, type);
@ -242,13 +256,83 @@ struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnumber,
return NULL;
}
int file_send_queue_add(uint32_t friendnumber, const char *file_path, size_t length)
{
if (length == 0 || file_path == NULL) {
return -1;
}
if (length > TOX_MAX_FILENAME_LENGTH) {
return -2;
}
for (size_t i = 0; i < MAX_FILES; ++i) {
PendingFileTransfer *pending_slot = &Friends.list[friendnumber].file_send_queue[i];
if (pending_slot->pending) {
continue;
}
pending_slot->pending = true;
memcpy(pending_slot->file_path, file_path, length);
pending_slot->file_path[length] = 0;
pending_slot->length = length;
return i;
}
return -3;
}
#define FILE_TRANSFER_SEND_CMD "/sendfile "
#define FILE_TRANSFER_SEND_LEN (sizeof(FILE_TRANSFER_SEND_CMD) - 1)
void file_send_queue_check(ToxWindow *self, Tox *m, uint32_t friendnumber)
{
for (size_t i = 0; i < MAX_FILES; ++i) {
PendingFileTransfer *pending_slot = &Friends.list[friendnumber].file_send_queue[i];
if (!pending_slot->pending) {
continue;
}
char command[TOX_MAX_FILENAME_LENGTH + FILE_TRANSFER_SEND_LEN + 1];
snprintf(command, sizeof(command), "%s%s", FILE_TRANSFER_SEND_CMD, pending_slot->file_path);
execute(self->window, self, m, command, CHAT_COMMAND_MODE);
*pending_slot = (PendingFileTransfer) {
0,
};
}
}
int file_send_queue_remove(uint32_t friendnumber, size_t index)
{
if (index >= MAX_FILES) {
return -1;
}
PendingFileTransfer *pending_slot = &Friends.list[friendnumber].file_send_queue[index];
if (!pending_slot->pending) {
return -1;
}
*pending_slot = (PendingFileTransfer) {
0,
};
return 0;
}
/* Closes file transfer ft.
*
* Set CTRL to -1 if we don't want to send a control signal.
* Set message or self to NULL if we don't want to display a message.
*/
void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int CTRL, const char *message,
void close_file_transfer(ToxWindow *self, Tox *m, FileTransfer *ft, int CTRL, const char *message,
Notification sound_type)
{
if (!ft) {
@ -264,7 +348,11 @@ void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int C
}
if (CTRL >= 0) {
tox_file_control(m, ft->friendnumber, ft->filenumber, (Tox_File_Control) CTRL, NULL);
Tox_Err_File_Control err;
if (!tox_file_control(m, ft->friendnumber, ft->filenumber, (Tox_File_Control) CTRL, &err)) {
fprintf(stderr, "Failed to cancel file transfer: %d\n", err);
}
}
if (message && self) {
@ -284,7 +372,7 @@ void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int C
void kill_avatar_file_transfers_friend(Tox *m, uint32_t friendnumber)
{
for (size_t i = 0; i < MAX_FILES; ++i) {
struct FileTransfer *ft = &Friends.list[friendnumber].file_sender[i];
FileTransfer *ft = &Friends.list[friendnumber].file_sender[i];
if (ft->file_type == TOX_FILE_KIND_AVATAR) {
close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent);
@ -298,6 +386,7 @@ void kill_all_file_transfers_friend(Tox *m, uint32_t friendnumber)
for (size_t i = 0; i < MAX_FILES; ++i) {
close_file_transfer(NULL, m, &Friends.list[friendnumber].file_sender[i], TOX_FILE_CONTROL_CANCEL, NULL, silent);
close_file_transfer(NULL, m, &Friends.list[friendnumber].file_receiver[i], TOX_FILE_CONTROL_CANCEL, NULL, silent);
file_send_queue_remove(friendnumber, i);
}
}
@ -307,3 +396,26 @@ void kill_all_file_transfers(Tox *m)
kill_all_file_transfers_friend(m, Friends.list[i].num);
}
}
bool file_transfer_recv_path_exists(const char *path)
{
for (size_t friendnumber = 0; friendnumber < Friends.max_idx; ++friendnumber) {
if (!Friends.list[friendnumber].active) {
continue;
}
for (size_t i = 0; i < MAX_FILES; ++i) {
FileTransfer *ft = &Friends.list[friendnumber].file_receiver[i];
if (ft->state == FILE_TRANSFER_INACTIVE) {
continue;
}
if (strcmp(path, ft->file_path) == 0) {
return true;
}
}
}
return false;
}

View File

@ -29,9 +29,9 @@
#include "toxic.h"
#include "windows.h"
#define KiB 1024
#define MiB 1048576 /* 1024^2 */
#define GiB 1073741824 /* 1024^3 */
#define KiB (uint32_t) 1024
#define MiB (uint32_t) (1024 << 10) /* 1024^2 */
#define GiB (uint32_t) (1024 << 20) /* 1024^3 */
#define MAX_FILES 32
@ -47,7 +47,7 @@ typedef enum FILE_TRANSFER_DIRECTION {
FILE_TRANSFER_RECV
} FILE_TRANSFER_DIRECTION;
struct FileTransfer {
typedef struct FileTransfer {
ToxWindow *window;
FILE *file;
FILE_TRANSFER_STATE state;
@ -63,7 +63,15 @@ struct FileTransfer {
time_t last_line_progress; /* The last time we updated the progress bar */
uint32_t line_id;
uint8_t file_id[TOX_FILE_ID_LENGTH];
};
} FileTransfer;
typedef struct PendingFileTransfer {
char file_path[TOX_MAX_FILENAME_LENGTH + 1];
size_t length;
uint32_t friendnumber;
bool pending;
} PendingFileTransfer;
/* creates initial progress line that will be updated during file transfer.
progline must be at lesat MAX_STR_SIZE bytes */
@ -72,8 +80,11 @@ void init_progress_bar(char *progline);
/* prints a progress bar for file transfers */
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, uint32_t friendnumber);
/* refreshes active file transfer status bars.
*
* Return true if there is at least one active file transfer in either direction.
*/
bool refresh_file_transfer_progress(ToxWindow *self, uint32_t friendnumber);
/* Returns a pointer to friendnumber's FileTransfer struct associated with filenumber.
* Returns NULL if filenumber is invalid.
@ -93,6 +104,31 @@ struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnumber, uint3
struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber,
FILE_TRANSFER_DIRECTION direction, uint8_t type);
/* Adds a file designated by `file_path` of length `length` to the file transfer queue.
*
* Items in this queue will be automatically sent to the contact designated by `friendnumber`
* as soon as they appear online. The item will then be removed from the queue whether
* or not the transfer successfully initiates.
*
* If the ToxWindow associated with this friend is closed, all queued items will be
* discarded.
*
* Return the queue index on success.
* Return -1 if the length is invalid.
* Return -2 if the send queue is full.
*/
int file_send_queue_add(uint32_t friendnumber, const char *file_path, size_t length);
/* Initiates all file transfers from the file send queue for friend designated by `friendnumber`. */
void file_send_queue_check(ToxWindow *self, Tox *m, uint32_t friendnumber);
/* Removes the `index`-th item from the file send queue for `friendnumber`.
*
* Return 0 if a pending transfer was successfully removed
* Return -1 if index does not designate a pending file transfer.
*/
int file_send_queue_remove(uint32_t friendnumber, size_t index);
/* Closes file transfer ft.
*
* Set CTRL to -1 if we don't want to send a control signal.
@ -109,4 +145,7 @@ void kill_all_file_transfers_friend(Tox *m, uint32_t friendnumber);
void kill_all_file_transfers(Tox *m);
/* Return true if any pending or active file receiver has the path `path`. */
bool file_transfer_recv_path_exists(const char *path);
#endif /* FILE_TRANSFERS_H */

View File

@ -37,6 +37,7 @@
#include "log.h"
#include "misc_tools.h"
#include "notify.h"
#include "prompt.h"
#include "settings.h"
#include "toxic.h"
#include "windows.h"
@ -46,13 +47,6 @@
#endif
extern char *DATA_FILE;
extern char *BLOCK_FILE;
extern ToxWindow *prompt;
extern struct Winthread Winthread;
extern struct user_settings *user_settings;
extern struct arg_opts arg_opts;
static uint8_t blocklist_view = 0; /* 0 if we're in friendlist view, 1 if we're in blocklist view */
FriendsList Friends;
@ -321,11 +315,11 @@ int load_blocklist(char *path)
#define S_WEIGHT 100000
static int index_name_cmp(const void *n1, const void *n2)
{
int res = qsort_strcasecmp_hlpr(Friends.list[*(int *) n1].name, Friends.list[*(int *) n2].name);
int res = qsort_strcasecmp_hlpr(Friends.list[*(const int *) n1].name, Friends.list[*(const int *) n2].name);
/* Use weight to make qsort always put online friends before offline */
res = Friends.list[*(int *) n1].connection_status ? (res - S_WEIGHT) : (res + S_WEIGHT);
res = Friends.list[*(int *) n2].connection_status ? (res + S_WEIGHT) : (res - S_WEIGHT);
res = Friends.list[*(const int *) n1].connection_status ? (res - S_WEIGHT) : (res + S_WEIGHT);
res = Friends.list[*(const int *) n2].connection_status ? (res + S_WEIGHT) : (res - S_WEIGHT);
return res;
}
@ -349,7 +343,7 @@ void sort_friendlist_index(void)
static int index_name_cmp_block(const void *n1, const void *n2)
{
return qsort_strcasecmp_hlpr(Blocked.list[*(int *) n1].name, Blocked.list[*(int *) n2].name);
return qsort_strcasecmp_hlpr(Blocked.list[*(const int *) n1].name, Blocked.list[*(const int *) n2].name);
}
static void sort_blocklist_index(void)
@ -698,6 +692,9 @@ static void select_friend(wint_t key, int *selected, int num)
static void delete_friend(Tox *m, uint32_t f_num)
{
kill_all_file_transfers_friend(m, f_num);
kill_avatar_file_transfers_friend(m, f_num);
Tox_Err_Friend_Delete err;
if (tox_friend_delete(m, f_num, &err) != true) {
@ -846,9 +843,7 @@ void block_friend(Tox *m, uint32_t fnum)
realloc_blocklist(Blocked.max_idx + 1);
clear_blocklist_index(Blocked.max_idx);
int i;
for (i = 0; i <= Blocked.max_idx; ++i) {
for (int i = 0; i <= Blocked.max_idx; ++i) {
if (Blocked.list[i].active) {
continue;
}
@ -1113,14 +1108,14 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
/* Determine which portion of friendlist to draw based on current position */
pthread_mutex_lock(&Winthread.lock);
int page = Friends.num_selected / (y2 - FLIST_OFST);
const int page = Friends.num_selected / (y2 - FLIST_OFST);
pthread_mutex_unlock(&Winthread.lock);
int start = (y2 - FLIST_OFST) * page;
int end = y2 - FLIST_OFST + start;
const int start = (y2 - FLIST_OFST) * page;
const int end = y2 - FLIST_OFST + start;
pthread_mutex_lock(&Winthread.lock);
size_t num_friends = Friends.num_friends;
const size_t num_friends = Friends.num_friends;
pthread_mutex_unlock(&Winthread.lock);
int i;

View File

@ -79,8 +79,9 @@ typedef struct {
struct GameInvite game_invite;
#endif
struct FileTransfer file_receiver[MAX_FILES];
struct FileTransfer file_sender[MAX_FILES];
FileTransfer file_receiver[MAX_FILES];
FileTransfer file_sender[MAX_FILES];
PendingFileTransfer file_send_queue[MAX_FILES];
} ToxicFriend;
typedef struct {
@ -101,6 +102,8 @@ typedef struct {
ToxicFriend *list;
} FriendsList;
extern FriendsList Friends;
ToxWindow *new_friendlist(void);
void friendlist_onInit(ToxWindow *self, Tox *m);
void disable_chatwin(uint32_t f_num);

View File

@ -174,6 +174,10 @@ void game_kill(ToxWindow *self)
kill_notifs(self->active_box);
del_window(self);
if (get_num_active_windows_type(WINDOW_TYPE_GAME) == 0) {
set_window_refresh_rate(NCURSES_DEFAULT_REFRESH_RATE);
}
}
static void game_init_abort(const ToxWindow *parent, ToxWindow *self)
@ -300,6 +304,8 @@ int game_initialize(const ToxWindow *parent, Tox *m, GameType type, uint32_t id,
set_active_window_index(window_id);
set_window_refresh_rate(NCURSES_GAME_REFRESH_RATE);
return 0;
}
@ -511,10 +517,10 @@ static void game_draw_help_bar(const GameData *game, WINDOW *win)
{
int max_x;
int max_y;
UNUSED_VAR(max_x);
getmaxyx(win, max_y, max_x);
UNUSED_VAR(max_x);
wmove(win, max_y - 1, 1);
if (!game->is_multiplayer) {
@ -931,10 +937,10 @@ int game_y_bottom_bound(const GameData *game)
{
int max_x;
int max_y;
UNUSED_VAR(max_x);
getmaxyx(game->window, max_y, max_x);
UNUSED_VAR(max_x);
return ((max_y + game->game_max_y) / 2) - 1;
}
@ -942,10 +948,10 @@ int game_y_top_bound(const GameData *game)
{
int max_x;
int max_y;
UNUSED_VAR(max_x);
getmaxyx(game->window, max_y, max_x);
UNUSED_VAR(max_x);
return ((max_y - game->game_max_y) / 2) + 1;
}
@ -953,10 +959,10 @@ int game_x_right_bound(const GameData *game)
{
int max_x;
int max_y;
UNUSED_VAR(max_y);
getmaxyx(game->window, max_y, max_x);
UNUSED_VAR(max_y);
return ((max_x + game->game_max_x) / 2) - 1;
}
@ -964,10 +970,10 @@ int game_x_left_bound(const GameData *game)
{
int max_x;
int max_y;
UNUSED_VAR(max_y);
getmaxyx(game->window, max_y, max_x);
UNUSED_VAR(max_y);
return ((max_x - game->game_max_x) / 2) + 1;
}
@ -1123,7 +1129,7 @@ int game_packet_send(const GameData *game, const uint8_t *data, size_t length, G
memcpy(packet + 1 + GAME_PACKET_HEADER_SIZE, data, length);
packet_length += length;
TOX_ERR_FRIEND_CUSTOM_PACKET err;
Tox_Err_Friend_Custom_Packet err;
if (!tox_friend_send_lossless_packet(game->tox, game->friend_number, packet, packet_length, &err)) {
fprintf(stderr, "failed to send game packet: error %d\n", err);

View File

@ -436,7 +436,11 @@ static bool chess_path_line_clear(Board *board, const Tile *from, const Tile *to
return false;
}
ChessCoords chess_coords;
ChessCoords chess_coords = (ChessCoords) {
0,
0
};
size_t start;
size_t end;
@ -800,11 +804,13 @@ static bool chess_mock_move_valid(ChessState *state, const Player *player, Tile
{
Board *board = &state->board;
const bool en_passant = player->en_passant_move_number == -1;
bool in_check = false;
Tile *ep_tile = NULL;
Piece ep_piece;
memset(&ep_piece, 0, sizeof(ep_piece));
if (player->en_passant_move_number == -1) { // remove piece that was captured via en passant
if (en_passant) { // remove piece that was captured via en passant
ChessCoords ep_coords;
ep_coords.N = player->colour == White ? to->chess_coords.N - 1 : to->chess_coords.N + 1;
ep_coords.L = to->chess_coords.L;
@ -815,7 +821,7 @@ static bool chess_mock_move_valid(ChessState *state, const Player *player, Tile
}
chess_copy_piece(&ep_piece, &ep_tile->piece);
ep_tile->piece.type = NoPiece;
ep_tile->piece.type = NoPiece; // temporarily remove piece
}
Piece from_piece;
@ -831,8 +837,8 @@ static bool chess_mock_move_valid(ChessState *state, const Player *player, Tile
from->piece.type = from_piece.type;
chess_copy_piece(&to->piece, &to_piece);
if (player->en_passant_move_number == -1) {
ep_tile->piece.type = ep_piece.type;
if (en_passant) {
ep_tile->piece.type = ep_piece.type; // reset piece to original state
}
return !in_check;

View File

@ -42,11 +42,6 @@
#include "game_base.h"
#endif
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])
{
@ -157,21 +152,15 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
return;
}
char msg[MAX_STR_SIZE] = {0};
const char *id = argv[1];
char msg[MAX_STR_SIZE];
const size_t arg_length = strlen(id);
const int space_idx = char_find(0, id, ' ');
if (argc > 1) {
if (argv[2][0] != '\"') {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Message must be enclosed in quotes.");
return;
}
/* remove opening and closing quotes */
char tmp[MAX_STR_SIZE];
snprintf(tmp, sizeof(tmp), "%s", &argv[2][1]);
int len = strlen(tmp) - 1;
tmp[len] = '\0';
snprintf(msg, sizeof(msg), "%s", tmp);
// we have to manually parse the message due to this command being a special case
if (space_idx > 0 && space_idx < arg_length - 1) {
snprintf(msg, sizeof(msg), "%s", &id[space_idx + 1]);
} else {
char selfname[TOX_MAX_NAME_LENGTH];
tox_self_get_name(m, (uint8_t *) selfname);
@ -182,36 +171,35 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
}
char id_bin[TOX_ADDRESS_SIZE] = {0};
uint16_t id_len = (uint16_t) strlen(id);
/* try to add tox ID */
if (id_len == 2 * TOX_ADDRESS_SIZE) {
size_t i;
char xx[3];
uint32_t x;
const bool is_tox_id = (char_find(0, id, '@') == arg_length) && (arg_length >= TOX_ADDRESS_SIZE * 2);
for (i = 0; i < TOX_ADDRESS_SIZE; ++i) {
xx[0] = id[2 * i];
xx[1] = id[2 * i + 1];
xx[2] = '\0';
if (!is_tox_id) {
name_lookup(self, m, id_bin, id, msg);
}
if (sscanf(xx, "%02x", &x) != 1) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid Tox ID.");
return;
}
char xx[3];
uint32_t x = 0;
id_bin[i] = x;
}
for (size_t i = 0; i < TOX_ADDRESS_SIZE; ++i) {
xx[0] = id[2 * i];
xx[1] = id[2 * i + 1];
xx[2] = 0;
if (friend_is_blocked(id_bin)) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Friend is in your block list.");
if (sscanf(xx, "%02x", &x) != 1) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid Tox ID.");
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);
id_bin[i] = x;
}
if (friend_is_blocked(id_bin)) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Friend is in your block list.");
return;
}
cmd_add_helper(self, m, id_bin, msg);
}
void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
@ -277,9 +265,9 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
return;
}
char key_binary[TOX_PUBLIC_KEY_SIZE * 2 + 1];
char key_binary[TOX_PUBLIC_KEY_SIZE];
if (hex_string_to_bin(ascii_key, strlen(ascii_key), key_binary, TOX_PUBLIC_KEY_SIZE) == -1) {
if (tox_pk_string_to_bytes(ascii_key, strlen(ascii_key), key_binary, sizeof(key_binary)) == -1) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid key.");
return;
}
@ -521,7 +509,7 @@ void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
char bin_id[TOX_ADDRESS_SIZE];
tox_self_get_address(m, (uint8_t *) bin_id);
if (bin_id_to_string(bin_id, sizeof(bin_id), id_string, sizeof(id_string)) == -1) {
if (tox_id_bytes_to_str(bin_id, sizeof(bin_id), id_string, sizeof(id_string)) == -1) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to print ID.");
return;
}
@ -538,7 +526,7 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
char bin_id[TOX_ADDRESS_SIZE];
tox_self_get_address(m, (uint8_t *) bin_id);
if (bin_id_to_string(bin_id, sizeof(bin_id), id_string, sizeof(id_string)) == -1) {
if (tox_id_bytes_to_str(bin_id, sizeof(bin_id), id_string, sizeof(id_string)) == -1) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
return;
}
@ -656,12 +644,9 @@ void cmd_note(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
{
UNUSED_VAR(window);
if (argc < 1) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Input required.");
return;
}
const char *note = argc >= 1 ? argv[1] : "";
prompt_update_statusmessage(prompt, m, argv[1]);
prompt_update_statusmessage(prompt, m, note);
}
void cmd_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])

View File

@ -346,5 +346,9 @@ bool input_handle(ToxWindow *self, wint_t key, int x, int mx_x)
}
}
if (match) {
flag_interface_refresh();
}
return match;
}

View File

@ -20,6 +20,10 @@
*
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* needed for wcswidth() */
#endif
#include <stdarg.h>
#include <stdbool.h>
#include <stdlib.h>
@ -137,20 +141,24 @@ static struct line_info *line_info_ret_queue(struct history *hst)
* Return 0 if string does not contain a newline byte.
* Return -1 if printing was aborted.
*/
static int print_n_chars(WINDOW *win, const char *s, size_t n, int max_y)
static int print_n_chars(WINDOW *win, const wchar_t *s, size_t n, int max_y)
{
// we use an array to represent a single wchar in order to get around an ncurses
// bug with waddnwstr() that overreads the memory address by one byte when
// supplied with a single wchar.
wchar_t ch[2] = {0};
bool newline = false;
char ch;
for (size_t i = 0; i < n && (ch = s[i]); ++i) {
if (ch == '\n') {
for (size_t i = 0; i < n && (ch[0] = s[i]); ++i) {
if (ch[0] == L'\n') {
newline = true;
int x;
int y;
UNUSED_VAR(x);
getyx(win, y, x);
UNUSED_VAR(x);
// make sure cursor will wrap correctly after newline to prevent display bugs
if (y + 1 >= max_y) {
return -1;
@ -158,7 +166,17 @@ static int print_n_chars(WINDOW *win, const char *s, size_t n, int max_y)
}
if (win) {
wprintw(win, "%c", ch);
#ifdef HAVE_WIDECHAR
waddnwstr(win, ch, 1);
#else
char b;
if (wcstombs(&b, ch, sizeof(char)) != 1) {
continue;
}
wprintw(win, "%c", b);
#endif // HAVE_WIDECHAR
}
}
@ -168,10 +186,10 @@ static int print_n_chars(WINDOW *win, const char *s, size_t n, int max_y)
/* Returns the index of the last space character in `s` found before `limit`.
* Returns -1 if no space is found.
*/
static int rspace_index(const char *s, int limit)
static int rspace_index(const wchar_t *s, int limit)
{
for (int i = limit; i >= 0; --i) {
if (s[i] == ' ') {
if (s[i] == L' ') {
return i;
}
}
@ -182,12 +200,12 @@ static int rspace_index(const char *s, int limit)
/* Returns the first index in `s` containing a newline byte found before `limit`.
* Returns -1 if no newline is found.
*/
static int newline_index(const char *s, int limit)
static int newline_index(const wchar_t *s, int limit)
{
char ch;
wchar_t ch;
for (int i = 0; i < limit && (ch = s[i]); ++i) {
if (ch == '\n') {
if (ch == L'\n') {
return i;
}
}
@ -196,13 +214,13 @@ static int newline_index(const char *s, int limit)
}
/* Returns the number of newline bytes in `s` */
static unsigned int newline_count(const char *s)
static unsigned int newline_count(const wchar_t *s)
{
char ch;
wchar_t ch;
unsigned int count = 0;
for (size_t i = 0; (ch = s[i]); ++i) {
if (ch == '\n') {
if (ch == L'\n') {
++count;
}
}
@ -225,10 +243,10 @@ static int print_wrap(WINDOW *win, struct line_info *line, int max_x, int max_y)
int y;
UNUSED_VAR(y);
const char *msg = line->msg;
uint16_t length = line->msg_len;
const wchar_t *msg = line->msg;
uint16_t length = line->msg_width;
uint16_t lines = 0;
const int x_start = line->len - line->msg_len - 1; // manually keep track of x position because ncurses sucks
const int x_start = line->len - line->msg_width - 1; // manually keep track of x position because ncurses sucks
int x_limit = max_x - x_start;
if (x_limit <= 1) {
@ -245,7 +263,7 @@ static int print_wrap(WINDOW *win, struct line_info *line, int max_x, int max_y)
}
if (length < x_limit) {
int p_ret = print_n_chars(win, msg, length, max_y);
const int p_ret = print_n_chars(win, msg, length, max_y);
if (p_ret == 1) {
lines += newline_count(msg);
@ -257,7 +275,7 @@ static int print_wrap(WINDOW *win, struct line_info *line, int max_x, int max_y)
break;
}
int newline_idx = newline_index(msg, x_limit - 1);
const int newline_idx = newline_index(msg, x_limit - 1);
if (newline_idx >= 0) {
if (print_n_chars(win, msg, newline_idx + 1, max_y) == -1) {
@ -271,7 +289,7 @@ static int print_wrap(WINDOW *win, struct line_info *line, int max_x, int max_y)
continue;
}
int space_idx = rspace_index(msg, x_limit - 1);
const int space_idx = rspace_index(msg, x_limit - 1);
if (space_idx >= 1) {
if (print_n_chars(win, msg, space_idx, max_y) == -1) {
@ -320,14 +338,45 @@ static int print_wrap(WINDOW *win, struct line_info *line, int max_x, int max_y)
return 0;
}
/* Converts `msg` into a widechar string and puts the result in `buf`.
*
* Returns the widechar width of the string.
*/
static uint16_t line_info_add_msg(wchar_t *buf, size_t buf_size, const char *msg)
{
if (msg == NULL || msg[0] == '\0') {
return 0;
}
const wint_t wc_msg_len = mbs_to_wcs_buf(buf, msg, buf_size);
if (wc_msg_len > 0 && wc_msg_len < buf_size) {
buf[wc_msg_len] = L'\0';
int width = wcswidth(buf, wc_msg_len);
if (width == -1) { // the best we can do on failure is to fall back to strlen
width = strlen(msg);
}
return (uint16_t)width;
} else {
fprintf(stderr, "Failed to convert string '%s' to widechar\n", msg);
const wchar_t *err = L"Failed to parse message";
uint16_t width = (uint16_t)wcslen(err);
wmemcpy(buf, err, width);
buf[width] = L'\0';
return width;
}
}
static void line_info_init_line(ToxWindow *self, struct line_info *line)
{
int y2;
int x2;
UNUSED_VAR(y2);
getmaxyx(self->window, y2, x2);
UNUSED_VAR(y2);
const int max_y = y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT;
const int max_x = self->show_peerlist ? x2 - 1 - SIDEBAR_WIDTH : x2;
@ -408,13 +457,8 @@ int line_info_add(ToxWindow *self, bool show_timestamp, const char *name1, const
break;
}
uint16_t msg_len = 0;
if (frmt_msg[0]) {
snprintf(new_line->msg, sizeof(new_line->msg), "%s", frmt_msg);
msg_len = strlen(new_line->msg);
len += msg_len;
}
const uint16_t msg_width = line_info_add_msg(new_line->msg, sizeof(new_line->msg), frmt_msg);
len += msg_width;
if (show_timestamp) {
get_time_str(new_line->timestr, sizeof(new_line->timestr));
@ -433,13 +477,17 @@ int line_info_add(ToxWindow *self, bool show_timestamp, const char *name1, const
new_line->id = (hst->line_end->id + 1 + hst->queue_size) % INT_MAX;
new_line->len = len;
new_line->msg_len = msg_len;
new_line->msg_width = msg_width;
new_line->type = type;
new_line->bold = bold;
new_line->colour = colour;
new_line->noread_flag = false;
new_line->timestamp = get_unix_time();
if (type == OUT_MSG || type == OUT_ACTION) {
new_line->noread_flag = self->stb->connection == TOX_CONNECTION_NONE;
}
line_info_init_line(self, new_line);
hst->queue[hst->queue_size++] = new_line;
@ -471,8 +519,6 @@ static void line_info_check_queue(ToxWindow *self)
}
}
#define NOREAD_FLAG_TIMEOUT 5 /* seconds before a sent message with no read receipt is flagged as unread */
void line_info_print(ToxWindow *self)
{
ChatContext *ctx = self->chatwin;
@ -515,15 +561,14 @@ void line_info_print(ToxWindow *self)
const int max_y = y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT;
const int max_x = self->show_peerlist ? x2 - 1 - SIDEBAR_WIDTH : x2;
uint16_t numlines = line->format_lines;
int print_ret = 0;
while (line && numlines++ <= max_y && print_ret == 0) {
while (line && numlines++ <= max_y) {
int y;
int x;
UNUSED_VAR(y);
getyx(win, y, x);
UNUSED_VAR(y);
if (x > 0) { // Prevents us from printing off the screen
break;
}
@ -554,31 +599,25 @@ void line_info_print(ToxWindow *self)
wprintw(win, "%s %s: ", user_settings->line_normal, line->name1);
wattroff(win, COLOR_PAIR(nameclr));
if (line->msg[0] == 0) {
if (line->msg[0] == L'\0') {
waddch(win, '\n');
break;
}
if (line->msg[0] == '>') {
if (line->msg[0] == L'>') {
wattron(win, COLOR_PAIR(GREEN));
} else if (line->msg[0] == '<') {
} else if (line->msg[0] == L'<') {
wattron(win, COLOR_PAIR(RED));
}
print_ret = print_wrap(win, line, max_x, max_y);
print_wrap(win, line, max_x, max_y);
if (line->msg[0] == '>') {
if (line->msg[0] == L'>') {
wattroff(win, COLOR_PAIR(GREEN));
} else if (line->msg[0] == '<') {
} else if (line->msg[0] == L'<') {
wattroff(win, COLOR_PAIR(RED));
}
if (type == OUT_MSG && !line->read_flag) {
if (timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
line->noread_flag = true;
}
}
waddch(win, '\n');
break;
@ -595,15 +634,9 @@ void line_info_print(ToxWindow *self)
wattron(win, COLOR_PAIR(YELLOW));
wprintw(win, "%s %s ", user_settings->line_normal, line->name1);
print_ret = print_wrap(win, line, max_x, max_y);
print_wrap(win, line, max_x, max_y);
wattroff(win, COLOR_PAIR(YELLOW));
if (type == OUT_ACTION && !line->read_flag) {
if (timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
line->noread_flag = true;
}
}
waddch(win, '\n');
break;
@ -622,7 +655,7 @@ void line_info_print(ToxWindow *self)
wattron(win, COLOR_PAIR(line->colour));
}
print_ret = print_wrap(win, line, max_x, max_y);
print_wrap(win, line, max_x, max_y);
waddch(win, '\n');
if (line->bold) {
@ -640,8 +673,8 @@ void line_info_print(ToxWindow *self)
wprintw(win, "$ ");
wattroff(win, COLOR_PAIR(GREEN));
if (line->msg[0]) {
print_ret = print_wrap(win, line, max_x, max_y);
if (line->msg[0] != L'\0') {
print_wrap(win, line, max_x, max_y);
}
waddch(win, '\n');
@ -659,7 +692,7 @@ void line_info_print(ToxWindow *self)
wprintw(win, "%s ", line->name1);
wattroff(win, A_BOLD);
print_ret = print_wrap(win, line, max_x, max_y);
print_wrap(win, line, max_x, max_y);
waddch(win, '\n');
wattroff(win, COLOR_PAIR(line->colour));
@ -678,7 +711,7 @@ void line_info_print(ToxWindow *self)
wprintw(win, "%s ", line->name1);
wattroff(win, A_BOLD);
print_ret = print_wrap(win, line, max_x, max_y);
print_wrap(win, line, max_x, max_y);
waddch(win, '\n');
wattroff(win, COLOR_PAIR(line->colour));
@ -696,7 +729,7 @@ void line_info_print(ToxWindow *self)
wprintw(win, "%s", line->name1);
wattroff(win, A_BOLD);
print_ret = print_wrap(win, line, max_x, max_y);
print_wrap(win, line, max_x, max_y);
wattron(win, A_BOLD);
wprintw(win, "%s\n", line->name2);
@ -709,6 +742,8 @@ void line_info_print(ToxWindow *self)
line = line->next;
}
flag_interface_refresh();
/* keep calling until queue is empty */
if (hst->queue_size > 0) {
line_info_print(self);
@ -750,14 +785,15 @@ static bool line_info_screen_fit(ToxWindow *self, struct line_info *line)
/* puts msg in specified line_info msg buffer */
void line_info_set(ToxWindow *self, uint32_t id, char *msg)
{
flag_interface_refresh();
struct line_info *line = self->chatwin->hst->line_end;
while (line) {
if (line->id == id) {
size_t new_len = strlen(msg);
line->len = line->len - line->msg_len + new_len;
line->msg_len = new_len;
snprintf(line->msg, sizeof(line->msg), "%s", msg);
const uint16_t new_width = line_info_add_msg(line->msg, sizeof(line->msg), msg);
line->len = line->len - line->msg_width + new_width;
line->msg_width = new_width;
return;
}
@ -765,6 +801,24 @@ void line_info_set(ToxWindow *self, uint32_t id, char *msg)
}
}
/* Return the line_info object associated with `id`.
* Return NULL if id cannot be found
*/
struct line_info *line_info_get(ToxWindow *self, uint32_t id)
{
struct line_info *line = self->chatwin->hst->line_end;
while (line) {
if (line->id == id) {
return line;
}
line = line->prev;
}
return NULL;
}
static void line_info_scroll_up(ToxWindow *self, struct history *hst)
{
if (hst->line_start->prev) {
@ -855,6 +909,10 @@ bool line_info_onKey(ToxWindow *self, wint_t key)
match = false;
}
if (match) {
flag_interface_refresh();
}
return match;
}

View File

@ -46,11 +46,11 @@ typedef enum LINE_TYPE {
} LINE_TYPE;
struct line_info {
char timestr[TIME_STR_SIZE];
char name1[TOXIC_MAX_NAME_LENGTH + 1];
char name2[TOXIC_MAX_NAME_LENGTH + 1];
char msg[MAX_LINE_INFO_MSG_SIZE];
time_t timestamp;
char timestr[TIME_STR_SIZE];
char name1[TOXIC_MAX_NAME_LENGTH + 1];
char name2[TOXIC_MAX_NAME_LENGTH + 1];
wchar_t msg[MAX_LINE_INFO_MSG_SIZE];
time_t timestamp;
uint8_t type;
uint8_t bold;
uint8_t colour;
@ -58,7 +58,7 @@ struct line_info {
bool read_flag; /* true if a message has been flagged as read */
uint32_t id;
uint16_t len; /* combined length of entire line */
uint16_t msg_len; /* length of the message */
uint16_t msg_width; /* width of the message */
uint16_t format_lines; /* number of lines the combined string takes up (dynamically set) */
struct line_info *prev;
@ -96,6 +96,11 @@ void line_info_clear(struct history *hst);
/* puts msg in specified line_info msg buffer */
void line_info_set(ToxWindow *self, uint32_t id, char *msg);
/* Return the line_info object associated with `id`.
* Return NULL if id cannot be found
*/
struct line_info *line_info_get(ToxWindow *self, uint32_t id);
/* resets line_start (moves to end of chat history) */
void line_info_reset_start(ToxWindow *self, struct history *hst);

View File

@ -62,21 +62,21 @@ static int get_log_path(char *dest, int destsize, const char *name, const char *
/* first 6 bytes of selfkey */
char self_id[32] = {0};
path_len += KEY_IDENT_DIGITS * 2;
path_len += KEY_IDENT_BYTES;
sprintf(&self_id[0], "%02X", selfkey[0] & 0xff);
sprintf(&self_id[2], "%02X", selfkey[1] & 0xff);
sprintf(&self_id[4], "%02X", selfkey[2] & 0xff);
self_id[KEY_IDENT_DIGITS * 2] = '\0';
self_id[KEY_IDENT_BYTES] = '\0';
char other_id[32] = {0};
if (otherkey) {
/* first 6 bytes of otherkey */
path_len += KEY_IDENT_DIGITS * 2;
path_len += KEY_IDENT_BYTES;
sprintf(&other_id[0], "%02X", otherkey[0] & 0xff);
sprintf(&other_id[2], "%02X", otherkey[1] & 0xff);
sprintf(&other_id[4], "%02X", otherkey[2] & 0xff);
other_id[KEY_IDENT_DIGITS * 2] = '\0';
other_id[KEY_IDENT_BYTES] = '\0';
}
if (path_len >= destsize) {

View File

@ -48,7 +48,7 @@ void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type,
return;
}
struct cqueue_msg *new_m = malloc(sizeof(struct cqueue_msg));
struct cqueue_msg *new_m = calloc(1, sizeof(struct cqueue_msg));
if (new_m == NULL) {
exit_toxic_err("failed in cqueue_message", FATALERR_MEMORY);
@ -59,8 +59,10 @@ void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type,
new_m->type = type;
new_m->line_id = line_id;
new_m->last_send_try = 0;
new_m->time_added = get_unix_time();
new_m->receipt = -1;
new_m->next = NULL;
new_m->noread_flag = false;
if (q->root == NULL) {
new_m->prev = NULL;
@ -76,23 +78,19 @@ void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type,
/* update line to show receipt was received after queue removal */
static void cqueue_mark_read(ToxWindow *self, struct cqueue_msg *msg)
{
struct line_info *line = self->chatwin->hst->line_end;
while (line) {
if (line->id != msg->line_id) {
line = line->prev;
continue;
}
line->type = msg->type == OUT_ACTION ? OUT_ACTION_READ : OUT_MSG_READ;
if (line->noread_flag) {
line->noread_flag = false;
line->read_flag = true;
}
struct line_info *line = line_info_get(self, msg->line_id);
if (line == NULL) {
return;
}
line->type = msg->type == OUT_ACTION ? OUT_ACTION_READ : OUT_MSG_READ;
if (line->noread_flag) {
line->noread_flag = false;
line->read_flag = true;
flag_interface_refresh();
}
}
/* removes message with matching receipt from queue, writes to log and updates line to show the message was received. */
@ -158,6 +156,36 @@ static void cqueue_check_timeouts(struct cqueue_msg *msg)
}
}
/*
* Sets the noread flag for messages sent to the peer associated with `self` which have not
* received a receipt after a period of time.
*/
#define NOREAD_TIMEOUT 5
void cqueue_check_unread(ToxWindow *self)
{
struct chat_queue *q = self->chatwin->cqueue;
struct cqueue_msg *msg = q->root;
while (msg) {
if (msg->noread_flag) {
msg = msg->next;
continue;
}
struct line_info *line = line_info_get(self, msg->line_id);
if (line != NULL) {
if (timed_out(msg->time_added, NOREAD_TIMEOUT)) {
line->noread_flag = true;
msg->noread_flag = true;
flag_interface_refresh();
}
}
msg = msg->next;
}
}
/*
* Tries to send all messages in the send queue in sequential order.
* If a message fails to send the function will immediately return.
@ -176,7 +204,7 @@ void cqueue_try_send(ToxWindow *self, Tox *m)
return;
}
TOX_ERR_FRIEND_SEND_MESSAGE err;
Tox_Err_Friend_Send_Message err;
Tox_Message_Type type = msg->type == OUT_MSG ? TOX_MESSAGE_TYPE_NORMAL : TOX_MESSAGE_TYPE_ACTION;
uint32_t receipt = tox_friend_send_message(m, self->num, type, (uint8_t *) msg->message, msg->len, &err);

View File

@ -28,8 +28,10 @@ struct cqueue_msg {
size_t len;
int line_id;
time_t last_send_try;
time_t time_added;
uint8_t type;
int64_t receipt;
bool noread_flag;
struct cqueue_msg *next;
struct cqueue_msg *prev;
};
@ -48,6 +50,12 @@ void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type,
*/
void cqueue_try_send(ToxWindow *self, Tox *m);
/*
* Sets the noread flag for messages sent to the peer associated with `self` which have not
* received a receipt after a period of time.
*/
void cqueue_check_unread(ToxWindow *self);
/* 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);

View File

@ -137,15 +137,18 @@ void get_elapsed_time_str(char *buf, int bufsize, time_t secs)
}
/*
* Converts a hexidecimal string of length hex_len to binary format and puts the result in output.
* output_size must be exactly half of hex_len.
* Converts a hexidecimal string representation of a Tox public key to binary format and puts
* the result in output.
*
* `hex_len` must be exactly TOX_PUBLIC_KEY_SIZE * 2, and `output_size` must have room
* for TOX_PUBLIC_KEY_SIZE bytes.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
int hex_string_to_bin(const char *hex_string, size_t hex_len, char *output, size_t output_size)
int tox_pk_string_to_bytes(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 != TOX_PUBLIC_KEY_SIZE || hex_len != output_size * 2) {
return -1;
}
@ -157,6 +160,11 @@ int hex_string_to_bin(const char *hex_string, size_t hex_len, char *output, size
return 0;
}
/* Convert a hexadecimcal string of length `size` to bytes and puts the result in `keystr`.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
int hex_string_to_bytes(char *buf, int size, const char *keystr)
{
if (size % 2 != 0) {
@ -178,11 +186,14 @@ int hex_string_to_bytes(char *buf, int size, const char *keystr)
}
/* Converts a binary representation of a Tox ID into a string.
*
* `bin_id_size` must be exactly TOX_ADDRESS_SIZE bytes in length, and
* `output_size` must be at least TOX_ADDRESS_SIZE * 2 + 1.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
int bin_id_to_string(const char *bin_id, size_t bin_id_size, char *output, size_t output_size)
int tox_id_bytes_to_str(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)) {
return -1;
@ -196,11 +207,14 @@ int bin_id_to_string(const char *bin_id, size_t bin_id_size, char *output, size_
}
/* Converts a binary representation of a Tox public key into a string.
*
* `bin_pubkey_size` must be exactly TOX_PUBLIC_KEY_SIZE bytes in size, and
* `output_size` must be at least TOX_PUBLIC_KEY_SIZE * 2 + 1.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
int bin_pubkey_to_string(const uint8_t *bin_pubkey, size_t bin_pubkey_size, char *output, size_t output_size)
int tox_pk_bytes_to_str(const uint8_t *bin_pubkey, size_t bin_pubkey_size, char *output, size_t output_size)
{
if (bin_pubkey_size != TOX_PUBLIC_KEY_SIZE || output_size < (TOX_PUBLIC_KEY_SIZE * 2 + 1)) {
return -1;
@ -274,7 +288,7 @@ int qsort_strcasecmp_hlpr(const void *str1, const void *str2)
/* case-insensitive string compare function for use with qsort */
int qsort_ptr_char_array_helper(const void *str1, const void *str2)
{
return strcasecmp(*(char **)str1, *(char **)str2);
return strcasecmp(*(const char *const *)str1, *(const char *const *)str2);
}
static const char invalid_chars[] = {'/', '\n', '\t', '\v', '\r', '\0'};
@ -463,10 +477,9 @@ on_error:
returns length of msg, which will be no larger than size-1 */
size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length)
{
size_t i;
size_t j = 0;
for (i = 0; (i < length) && (j < size - 1); ++i) {
for (size_t i = 0; (i < length) && (j < size - 1); ++i) {
if (data[i] != '\r') {
msg[j++] = data[i];
}

View File

@ -53,30 +53,43 @@ void clear_screen(void);
void hst_to_net(uint8_t *num, uint16_t numbytes);
/*
* Converts a hexidecimal string of length hex_len to binary format and puts the result in output.
* output_size must be exactly half of hex_len.
* Converts a hexidecimal string representation of a Tox public key to binary format and puts
* the result in output.
*
* `hex_len` must be exactly TOX_PUBLIC_KEY_SIZE * 2, and `output_size` must have room
* for TOX_PUBLIC_KEY_SIZE bytes.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
int hex_string_to_bin(const char *hex_string, size_t hex_len, char *output, size_t output_size);
int tox_pk_string_to_bytes(const char *hex_string, size_t hex_len, char *output, size_t output_size);
/* convert a hex string to bytes. returns 0 on success, -1 on failure */
/* Converts a binary representation of a Tox public key into a string.
*
* `bin_pubkey_size` must be exactly TOX_PUBLIC_KEY_SIZE bytes in size, and
* `output_size` must be at least TOX_PUBLIC_KEY_SIZE * 2 + 1.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
int tox_pk_bytes_to_str(const uint8_t *bin_pubkey, size_t bin_pubkey_size, char *output, size_t output_size);
/* Convert a hexadecimcal string of length `size` to bytes and puts the result in `keystr`.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
int hex_string_to_bytes(char *buf, int size, const char *keystr);
/* Converts a binary representation of a Tox ID into a string.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
int bin_id_to_string(const char *bin_id, size_t bin_id_size, char *output, size_t output_size);
/* Converts a binary representation of a Tox public key into a string.
* `bin_id_size` must be exactly TOX_ADDRESS_SIZE bytes in length, and
* `output_size` must be at least TOX_ADDRESS_SIZE * 2 + 1.
*
* Returns 0 on success.
* Returns -1 on failure.
*/
int bin_pubkey_to_string(const uint8_t *bin_pubkey, size_t bin_pubkey_size, char *output, size_t output_size);
int tox_id_bytes_to_str(const char *bin_id, size_t bin_id_size, char *output, size_t output_size);
/* get the current unix time (not thread safe) */
time_t get_unix_time(void);

View File

@ -33,9 +33,6 @@
#include "toxic.h"
#include "windows.h"
extern struct arg_opts arg_opts;
extern struct Winthread Winthread;
#define NAMESERVER_API_PATH "api"
#define SERVER_KEY_SIZE 32
#define MAX_SERVERS 50
@ -111,14 +108,15 @@ static int load_nameserver_list(const char *path)
char line[MAX_SERVER_LINE];
while (fgets(line, sizeof(line), fp) && Nameservers.lines < MAX_SERVERS) {
int linelen = strlen(line);
size_t linelen = strlen(line);
if (linelen < SERVER_KEY_SIZE * 2 + 5) {
continue;
}
if (line[linelen - 1] == '\n') {
line[--linelen] = '\0';
--linelen;
line[linelen] = '\0';
}
const char *name = strtok(line, " ");
@ -132,8 +130,10 @@ static int load_nameserver_list(const char *path)
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);
const size_t idx = Nameservers.lines;
snprintf(Nameservers.names[idx], sizeof(Nameservers.names[idx]), "%s", name);
int res = hex_string_to_bytes(Nameservers.keys[idx], SERVER_KEY_SIZE, keystr);
if (res == -1) {
continue;
@ -231,7 +231,7 @@ static int process_response(struct Recv_Curl_Data *recv_data)
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 (tox_pk_string_to_bytes(ID_string, strlen(ID_string), t_data.id_bin, sizeof(t_data.id_bin)) == -1) {
return -1;
}

299
src/netprof.c Normal file
View File

@ -0,0 +1,299 @@
/* netprof.c
*
*
* Copyright (C) 2022 Toxic All Rights Reserved.
*
* This file is part of Toxic.
*
* Toxic is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Toxic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <stdio.h>
#include "netprof.h"
#include "../../toxcore/toxcore/tox_private.h" // set this to your local toxcore source directory
static void log_tcp_packet_id(FILE *fp, unsigned int id, uint64_t total, uint64_t TCP_id_sent, uint64_t TCP_id_recv)
{
switch (id) {
case TOX_NETPROF_PACKET_ID_ZERO:
case TOX_NETPROF_PACKET_ID_ONE:
case TOX_NETPROF_PACKET_ID_TWO:
case TOX_NETPROF_PACKET_ID_TCP_DISCONNECT:
case TOX_NETPROF_PACKET_ID_FOUR:
case TOX_NETPROF_PACKET_ID_TCP_PONG:
case TOX_NETPROF_PACKET_ID_TCP_OOB_SEND:
case TOX_NETPROF_PACKET_ID_TCP_OOB_RECV:
case TOX_NETPROF_PACKET_ID_TCP_ONION_REQUEST:
case TOX_NETPROF_PACKET_ID_TCP_ONION_RESPONSE:
case TOX_NETPROF_PACKET_ID_TCP_DATA: {
if (TCP_id_recv || TCP_id_sent) {
fprintf(fp, "0x%02x (total): %lu (%.2f%%)\n", id, TCP_id_sent + TCP_id_recv,
((float)TCP_id_recv + TCP_id_sent) / total * 100.0);
}
if (TCP_id_sent) {
fprintf(fp, "0x%02x (sent): %lu (%.2f%%)\n", id, TCP_id_sent, (float)TCP_id_sent / total * 100.0);
}
if (TCP_id_recv) {
fprintf(fp, "0x%02x (recv): %lu (%.2f%%)\n", id, TCP_id_recv, (float)TCP_id_recv / total * 100.0);
}
break;
}
default:
return;
}
}
static void log_udp_packet_id(FILE *fp, unsigned int id, uint64_t total, uint64_t UDP_id_sent, uint64_t UDP_id_recv)
{
switch (id) {
case TOX_NETPROF_PACKET_ID_ZERO:
case TOX_NETPROF_PACKET_ID_ONE:
case TOX_NETPROF_PACKET_ID_TWO:
case TOX_NETPROF_PACKET_ID_FOUR:
case TOX_NETPROF_PACKET_ID_COOKIE_REQUEST:
case TOX_NETPROF_PACKET_ID_COOKIE_RESPONSE:
case TOX_NETPROF_PACKET_ID_CRYPTO_HS:
case TOX_NETPROF_PACKET_ID_CRYPTO_DATA:
case TOX_NETPROF_PACKET_ID_CRYPTO:
case TOX_NETPROF_PACKET_ID_LAN_DISCOVERY:
case TOX_NETPROF_PACKET_ID_ONION_SEND_INITIAL:
case TOX_NETPROF_PACKET_ID_ONION_SEND_1:
case TOX_NETPROF_PACKET_ID_ONION_SEND_2:
case TOX_NETPROF_PACKET_ID_ANNOUNCE_REQUEST:
case TOX_NETPROF_PACKET_ID_ANNOUNCE_RESPONSE:
case TOX_NETPROF_PACKET_ID_ONION_DATA_REQUEST:
case TOX_NETPROF_PACKET_ID_ONION_DATA_RESPONSE:
case TOX_NETPROF_PACKET_ID_ONION_RECV_3:
case TOX_NETPROF_PACKET_ID_ONION_RECV_2:
case TOX_NETPROF_PACKET_ID_ONION_RECV_1:
case TOX_NETPROF_PACKET_ID_BOOTSTRAP_INFO: {
if (UDP_id_recv || UDP_id_sent) {
fprintf(fp, "0x%02x (total): %lu (%.2f%%)\n", id, UDP_id_sent + UDP_id_recv,
((float)UDP_id_recv + UDP_id_sent) / total * 100.0);
}
if (UDP_id_sent) {
fprintf(fp, "0x%02x (sent): %lu (%.2f%%)\n", id, UDP_id_sent, (float)UDP_id_sent / total * 100.0);
}
if (UDP_id_recv) {
fprintf(fp, "0x%02x (recv): %lu (%.2f%%)\n", id, UDP_id_recv, (float)UDP_id_recv / total * 100.0);
}
break;
}
default:
return;
}
}
static void dump_packet_id_counts(const Tox *m, FILE *fp, uint64_t total_count, Tox_Netprof_Packet_Type packet_type)
{
if (packet_type == TOX_NETPROF_PACKET_TYPE_TCP) {
fprintf(fp, "--- TCP packet counts by packet ID --- \n");
} else {
fprintf(fp, "--- UDP packet counts by packet ID --- \n");
}
for (unsigned long i = TOX_NETPROF_PACKET_ID_ZERO; i <= TOX_NETPROF_PACKET_ID_BOOTSTRAP_INFO; ++i) {
const uint64_t id_count_sent = tox_netprof_get_packet_id_count(m, packet_type, i, TOX_NETPROF_DIRECTION_SENT);
const uint64_t id_count_recv = tox_netprof_get_packet_id_count(m, packet_type, i, TOX_NETPROF_DIRECTION_RECV);
if (packet_type == TOX_NETPROF_PACKET_TYPE_TCP) {
log_tcp_packet_id(fp, i, total_count, id_count_sent, id_count_recv);
} else {
log_udp_packet_id(fp, i, total_count, id_count_sent, id_count_recv);
}
}
fprintf(fp, "\n\n");
}
static void dump_packet_id_bytes(const Tox *m, FILE *fp, uint64_t total_bytes, Tox_Netprof_Packet_Type packet_type)
{
if (packet_type == TOX_NETPROF_PACKET_TYPE_TCP) {
fprintf(fp, "--- TCP byte counts by packet ID --- \n");
} else {
fprintf(fp, "--- UDP byte counts by packet ID --- \n");
}
for (unsigned long i = TOX_NETPROF_PACKET_ID_ZERO; i <= TOX_NETPROF_PACKET_ID_BOOTSTRAP_INFO; ++i) {
const uint64_t id_bytes_sent = tox_netprof_get_packet_id_bytes(m, packet_type, i, TOX_NETPROF_DIRECTION_SENT);
const uint64_t id_bytes_recv = tox_netprof_get_packet_id_bytes(m, packet_type, i, TOX_NETPROF_DIRECTION_RECV);
if (packet_type == TOX_NETPROF_PACKET_TYPE_TCP) {
log_tcp_packet_id(fp, i, total_bytes, id_bytes_sent, id_bytes_recv);
} else {
log_udp_packet_id(fp, i, total_bytes, id_bytes_sent, id_bytes_recv);
}
}
fprintf(fp, "\n\n");
}
static void dump_packet_count_totals(const Tox *m, FILE *fp, uint64_t total_packet_count,
uint64_t UDP_count_sent, uint64_t UDP_count_recv,
uint64_t TCP_count_sent, uint64_t TCP_count_recv)
{
const uint64_t total_UDP_count = UDP_count_sent + UDP_count_recv;
const uint64_t total_TCP_count = TCP_count_sent + TCP_count_recv;
const uint64_t total_packet_count_sent = UDP_count_sent + TCP_count_sent;
const uint64_t total_packet_count_recv = UDP_count_recv + TCP_count_recv;
fprintf(fp, "--- Total packet counts --- \n");
fprintf(fp, "Total packets: %lu\n", total_packet_count);
fprintf(fp, "Total packets sent: %lu (%.2f%%)\n", total_packet_count_sent,
(float)total_packet_count_sent / total_packet_count * 100.0);
fprintf(fp, "Total packets recv: %lu (%.2f%%)\n", total_packet_count_recv,
(float)total_packet_count_recv / total_packet_count * 100.0);
fprintf(fp, "total UDP packets: %lu (%.2f%%)\n", total_UDP_count,
(float)total_UDP_count / total_packet_count * 100.0);
fprintf(fp, "UDP packets sent: %lu (%.2f%%)\n", UDP_count_sent,
(float)UDP_count_sent / total_packet_count * 100.0);
fprintf(fp, "UDP packets recv: %lu (%.2f%%)\n", UDP_count_recv,
(float)UDP_count_recv / total_packet_count * 100.0);
fprintf(fp, "Total TCP packets: %lu (%.2f%%)\n", total_TCP_count,
(float)total_TCP_count / total_packet_count * 100.0);
fprintf(fp, "TCP packets sent: %lu (%.2f%%)\n", TCP_count_sent,
(float)TCP_count_sent / total_packet_count * 100.0);
fprintf(fp, "TCP packets recv: %lu (%.2f%%)\n", TCP_count_recv,
(float)TCP_count_recv / total_packet_count * 100.0);
fprintf(fp, "\n\n");
}
void dump_packet_bytes_totals(const Tox *m, FILE *fp, const uint64_t total_bytes,
const uint64_t UDP_bytes_sent, const uint64_t UDP_bytes_recv,
const uint64_t TCP_bytes_sent, const uint64_t TCP_bytes_recv)
{
const uint64_t total_UDP_bytes = UDP_bytes_sent + UDP_bytes_recv;
const uint64_t total_TCP_bytes = TCP_bytes_sent + TCP_bytes_recv;
const uint64_t total_bytes_sent = UDP_bytes_sent + TCP_bytes_sent;
const uint64_t total_bytes_recv = UDP_bytes_recv + TCP_bytes_recv;
fprintf(fp, "--- Total byte counts --- \n");
fprintf(fp, "Total bytes: %lu\n", total_bytes);
fprintf(fp, "Total bytes sent: %lu (%.2f%%)\n", total_bytes_sent,
(float)total_bytes_sent / total_bytes * 100.0);
fprintf(fp, "Total bytes recv: %lu (%.2f%%)\n", total_bytes_recv,
(float)total_bytes_recv / total_bytes * 100.0);
fprintf(fp, "Total UDP bytes: %lu (%.2f%%)\n", total_UDP_bytes,
(float)total_UDP_bytes / total_bytes * 100.0);
fprintf(fp, "UDP bytes sent: %lu (%.2f%%)\n", UDP_bytes_sent,
(float)UDP_bytes_sent / total_bytes * 100.0);
fprintf(fp, "UDP bytes recv: %lu (%.2f%%)\n", UDP_bytes_recv,
(float)UDP_bytes_recv / total_bytes * 100.0);
fprintf(fp, "Total TCP bytes: %lu (%.2f%%)\n", total_TCP_bytes,
(float)total_TCP_bytes / total_bytes * 100.0);
fprintf(fp, "TCP bytes sent: %lu (%.2f%%)\n", TCP_bytes_sent,
(float)TCP_bytes_sent / total_bytes * 100.0);
fprintf(fp, "TCP bytes recv: %lu (%.2f%%)\n", TCP_bytes_recv,
(float)TCP_bytes_recv / total_bytes * 100.0);
fprintf(fp, "\n\n");
}
void netprof_log_dump(const Tox *m, FILE *fp, time_t run_time)
{
if (fp == NULL) {
fprintf(stderr, "Failed to dump network statistics: null file pointer\n");
return;
}
const uint64_t UDP_count_sent = tox_netprof_get_packet_total_count(m, TOX_NETPROF_PACKET_TYPE_UDP,
TOX_NETPROF_DIRECTION_SENT);
const uint64_t UDP_count_recv = tox_netprof_get_packet_total_count(m, TOX_NETPROF_PACKET_TYPE_UDP,
TOX_NETPROF_DIRECTION_RECV);
const uint64_t TCP_count_sent = tox_netprof_get_packet_total_count(m, TOX_NETPROF_PACKET_TYPE_TCP,
TOX_NETPROF_DIRECTION_SENT);
const uint64_t TCP_count_recv = tox_netprof_get_packet_total_count(m, TOX_NETPROF_PACKET_TYPE_TCP,
TOX_NETPROF_DIRECTION_RECV);
const uint64_t UDP_bytes_sent = tox_netprof_get_packet_total_bytes(m, TOX_NETPROF_PACKET_TYPE_UDP,
TOX_NETPROF_DIRECTION_SENT);
const uint64_t UDP_bytes_recv = tox_netprof_get_packet_total_bytes(m, TOX_NETPROF_PACKET_TYPE_UDP,
TOX_NETPROF_DIRECTION_RECV);
const uint64_t TCP_bytes_sent = tox_netprof_get_packet_total_bytes(m, TOX_NETPROF_PACKET_TYPE_TCP,
TOX_NETPROF_DIRECTION_SENT);
const uint64_t TCP_bytes_recv = tox_netprof_get_packet_total_bytes(m, TOX_NETPROF_PACKET_TYPE_TCP,
TOX_NETPROF_DIRECTION_RECV);
const uint64_t total_count = UDP_count_sent + UDP_count_recv + TCP_count_sent + TCP_count_recv;
const uint64_t total_bytes = UDP_bytes_sent + UDP_bytes_recv + TCP_bytes_sent + TCP_bytes_recv;
fprintf(fp, "--- Tox network profile log dump ---\n");
fprintf(fp, "Run time: %lu seconds\n", run_time);
if (run_time && total_count && total_bytes) {
fprintf(fp, "Average kilobytes per second: %.2f\n", ((float)total_bytes / run_time) / 1000.0);
fprintf(fp, "Average packets per second: %lu\n", total_count / run_time);
fprintf(fp, "Average packet size: %lu bytes\n", total_bytes / total_count);
fprintf(fp, "\n");
}
dump_packet_count_totals(m, fp, total_count, UDP_count_sent, UDP_count_recv, TCP_count_sent, TCP_count_recv);
dump_packet_bytes_totals(m, fp, total_bytes, UDP_bytes_sent, UDP_bytes_recv, TCP_bytes_sent, TCP_bytes_recv);
dump_packet_id_counts(m, fp, total_count, TOX_NETPROF_PACKET_TYPE_TCP);
dump_packet_id_counts(m, fp, total_count, TOX_NETPROF_PACKET_TYPE_UDP);
dump_packet_id_bytes(m, fp, total_bytes, TOX_NETPROF_PACKET_TYPE_TCP);
dump_packet_id_bytes(m, fp, total_bytes, TOX_NETPROF_PACKET_TYPE_UDP);
fflush(fp);
}
uint64_t netprof_get_bytes_up(const Tox *m)
{
const uint64_t UDP_bytes_sent = tox_netprof_get_packet_total_bytes(m, TOX_NETPROF_PACKET_TYPE_UDP,
TOX_NETPROF_DIRECTION_SENT);
const uint64_t TCP_bytes_sent = tox_netprof_get_packet_total_bytes(m, TOX_NETPROF_PACKET_TYPE_TCP,
TOX_NETPROF_DIRECTION_SENT);
return UDP_bytes_sent + TCP_bytes_sent;
}
uint64_t netprof_get_bytes_down(const Tox *m)
{
const uint64_t UDP_bytes_recv = tox_netprof_get_packet_total_bytes(m, TOX_NETPROF_PACKET_TYPE_UDP,
TOX_NETPROF_DIRECTION_RECV);
const uint64_t TCP_bytes_recv = tox_netprof_get_packet_total_bytes(m, TOX_NETPROF_PACKET_TYPE_TCP,
TOX_NETPROF_DIRECTION_RECV);
return UDP_bytes_recv + TCP_bytes_recv;
}

35
src/netprof.h Normal file
View File

@ -0,0 +1,35 @@
/* netprof.h
*
*
* Copyright (C) 2022 Toxic All Rights Reserved.
*
* This file is part of Toxic.
*
* Toxic is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Toxic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TOXIC_NETPROF
#define TOXIC_NETPROF
#include <stdio.h>
#include <time.h>
#include <tox/tox.h>
void netprof_log_dump(const Tox *m, FILE *fp, time_t run_time);
uint64_t netprof_get_bytes_down(const Tox *m);
uint64_t netprof_get_bytes_up(const Tox *m);
#endif // TOXIC_NETPROF

View File

@ -318,7 +318,7 @@ void *do_playing(void *_p)
has_looping = false;
control_unlock();
sleep_thread(10000L);
sleep_thread(100000L);
}
pthread_exit(NULL);
@ -489,16 +489,27 @@ void terminate_notify(void)
}
#ifdef SOUND_NOTIFY
int set_sound(Notification sound, const char *value)
/*
* Sets notification sound designated by `sound` to file path `value`.
*
* Return true if the sound is successfully set.
*/
bool set_sound(Notification sound, const char *value)
{
if (sound == silent) {
return 0;
return false;
}
free(Control.sounds[sound]);
size_t len = strlen(value) + 1;
Control.sounds[sound] = calloc(len, 1);
if (Control.sounds[sound] == NULL) {
return false;
}
memcpy(Control.sounds[sound], value, len);
struct stat buf;

View File

@ -77,7 +77,7 @@ int box_silent_notify(ToxWindow *self, uint64_t flags, int *id_indicator, const
int box_silent_notify2(ToxWindow *self, uint64_t flags, int id, const char *format, ...);
#ifdef SOUND_NOTIFY
int set_sound(Notification sound, const char *value);
bool set_sound(Notification sound, const char *value);
#endif /* SOUND_NOTIFY */
#endif /* NOTIFY_H */

View File

@ -36,6 +36,7 @@
#include "line_info.h"
#include "log.h"
#include "misc_tools.h"
#include "netprof.h"
#include "notify.h"
#include "prompt.h"
#include "settings.h"
@ -125,6 +126,8 @@ void on_self_connection_status(Tox *m, Tox_Connection connection_status, void *u
UNUSED_VAR(userdata);
StatusBar *statusbar = prompt->stb;
statusbar->connection = connection_status;
flag_interface_refresh();
}
/* Updates own nick in prompt statusbar */
@ -173,9 +176,7 @@ static int add_friend_request(const char *public_key, const char *data)
return -1;
}
int i;
for (i = 0; i <= FrndRequests.max_idx; ++i) {
for (int i = 0; i <= FrndRequests.max_idx; ++i) {
if (!FrndRequests.request[i].active) {
FrndRequests.request[i].active = true;
memcpy(FrndRequests.request[i].key, public_key, TOX_PUBLIC_KEY_SIZE);
@ -305,6 +306,77 @@ static bool prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
return input_ret;
}
#define NET_INFO_REFRESH_INTERVAL 1
static void draw_network_info(const Tox *m, StatusBar *stb)
{
WINDOW *win = stb->topline;
wattron(win, COLOR_PAIR(BAR_TEXT));
wprintw(win, "%s", stb->network_info);
wattroff(win, COLOR_PAIR(BAR_TEXT));
if (!timed_out(stb->time_last_refreshed, NET_INFO_REFRESH_INTERVAL)) {
return;
}
stb->time_last_refreshed = get_unix_time();
const uint64_t up_bytes = netprof_get_bytes_up(m);
const uint64_t down_bytes = netprof_get_bytes_down(m);
const uint64_t up_delta = (up_bytes - stb->up_bytes) / NET_INFO_REFRESH_INTERVAL;
const uint64_t down_delta = (down_bytes - stb->down_bytes) / NET_INFO_REFRESH_INTERVAL;
stb->up_bytes = up_bytes;
stb->down_bytes = down_bytes;
float up = up_bytes;
float down = down_bytes;
const char *up_unit = "bytes";
const char *down_unit = "bytes";
if (up_bytes > MiB) {
up /= (float)MiB;
up_unit = "MiB";
} else if (up_bytes > KiB) {
up /= (float)KiB;
up_unit = "KiB";
}
if (down_bytes > MiB) {
down /= (float)MiB;
down_unit = "MiB";
} else if (down_bytes > KiB) {
down /= (float)KiB;
down_unit = "KiB";
}
float up_bps = up_delta;
float down_bps = down_delta;
const char *up_bps_unit = "b/s";
const char *down_bps_unit = "b/s";
if (up_bps > MiB) {
up_bps /= (float)MiB;
up_bps_unit = "MiB/s";
} else if (up_bps > KiB) {
up_bps /= (float)KiB;
up_bps_unit = "KiB/s";
}
if (down_bps > MiB) {
down_bps /= (float)MiB;
down_bps_unit = "MiB/s";
} else if (down_bps > KiB) {
down_bps /= (float)KiB;
down_bps_unit = "KiB/s";
}
snprintf(stb->network_info, sizeof(stb->network_info),
" | [Up: %.1f%s (%.1f%s) | Down: %.1f%s (%.1f%s)]", up, up_unit, up_bps, up_bps_unit,
down, down_unit, down_bps, down_bps_unit);
}
static void prompt_onDraw(ToxWindow *self, Tox *m)
{
int x2;
@ -338,24 +410,50 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
Tox_User_Status status = statusbar->status;
pthread_mutex_unlock(&Winthread.lock);
if (connection != TOX_CONNECTION_NONE) {
wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wprintw(statusbar->topline, " [");
wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
switch (connection) {
case TOX_CONNECTION_TCP:
wattron(statusbar->topline, A_BOLD | COLOR_PAIR(STATUS_ONLINE));
wprintw(statusbar->topline, "TCP");
wattroff(statusbar->topline, A_BOLD | COLOR_PAIR(STATUS_ONLINE));
break;
case TOX_CONNECTION_UDP:
wattron(statusbar->topline, A_BOLD | COLOR_PAIR(STATUS_ONLINE));
wprintw(statusbar->topline, "UDP");
wattroff(statusbar->topline, A_BOLD | COLOR_PAIR(STATUS_ONLINE));
break;
default:
wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
wprintw(statusbar->topline, "Offline");
wattroff(statusbar->topline, COLOR_PAIR(BAR_TEXT));
break;
}
wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wprintw(statusbar->topline, "]");
wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
if (status != TOX_USER_STATUS_NONE) {
int colour = MAGENTA;
const char *status_text = "ERROR";
switch (status) {
case TOX_USER_STATUS_NONE:
status_text = "Online";
colour = STATUS_ONLINE;
break;
case TOX_USER_STATUS_AWAY:
status_text = "Away";
colour = STATUS_AWAY;
status_text = "Away";
break;
case TOX_USER_STATUS_BUSY:
status_text = "Busy";
colour = STATUS_BUSY;
status_text = "Busy";
break;
default:
break;
}
@ -377,18 +475,6 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
wprintw(statusbar->topline, " %s", statusbar->nick);
pthread_mutex_unlock(&Winthread.lock);
} else {
wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wprintw(statusbar->topline, " [");
wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
wprintw(statusbar->topline, "Offline");
wattroff(statusbar->topline, COLOR_PAIR(BAR_TEXT));
wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wprintw(statusbar->topline, "]");
wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
pthread_mutex_lock(&Winthread.lock);
@ -408,11 +494,14 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH];
pthread_mutex_lock(&Winthread.lock);
size_t slen = tox_self_get_status_message_size(m);
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);
pthread_mutex_unlock(&Winthread.lock);
}
@ -422,24 +511,32 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
uint16_t maxlen = x2 - getcurx(statusbar->topline) - 3;
pthread_mutex_lock(&Winthread.lock);
size_t statusmsg_len = statusbar->statusmsg_len;
pthread_mutex_unlock(&Winthread.lock);
if (statusbar->statusmsg_len > maxlen) {
statusbar->statusmsg[maxlen - 3] = '\0';
if (statusmsg_len > maxlen) {
pthread_mutex_lock(&Winthread.lock);
statusbar->statusmsg[maxlen - 3] = 0;
strcat(statusbar->statusmsg, "...");
statusbar->statusmsg_len = maxlen;
pthread_mutex_unlock(&Winthread.lock);
}
if (statusbar->statusmsg[0]) {
if (statusmsg_len) {
wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wprintw(statusbar->topline, " | ");
wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
pthread_mutex_lock(&Winthread.lock);
wprintw(statusbar->topline, "%s", statusbar->statusmsg);
pthread_mutex_unlock(&Winthread.lock);
wattroff(statusbar->topline, COLOR_PAIR(BAR_TEXT));
}
pthread_mutex_unlock(&Winthread.lock);
if (user_settings->show_network_info) {
draw_network_info(m, statusbar);
}
int y;
int x;
@ -503,6 +600,26 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnu
}
}
/**
* Return true is the first 3 bytes of `key` are identical to any other contact in the contact list.
*/
static bool key_is_similar(const char *key)
{
for (size_t i = 0; i < Friends.max_idx; ++i) {
const ToxicFriend *friend = &Friends.list[i];
if (!friend->active) {
continue;
}
if (memcmp(friend->pub_key, key, KEY_IDENT_BYTES / 2) == 0) {
return true;
}
}
return false;
}
static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, const char *data, size_t length)
{
UNUSED_VAR(m);
@ -513,6 +630,13 @@ static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, con
line_info_add(self, true, NULL, NULL, SYS_MSG, 0, 0, "Friend request with the message '%s'", data);
write_to_log("Friend request with the message '%s'", "", ctx->log, true);
if (key_is_similar(key)) {
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED,
"WARNING: This contact's public key is suspiciously similar to that of another contact ");
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED,
"in your list. This may be an impersonation attempt, or it may have occurred by chance.");
}
int n = add_friend_request(key, data);
if (n == -1) {

View File

@ -40,6 +40,9 @@ typedef struct FriendRequests {
struct friend_request request[MAX_FRIEND_REQUESTS];
} FriendRequests;
extern ToxWindow *prompt;
extern FriendRequests FrndRequests;
ToxWindow *new_prompt(void);
void prep_prompt_win(void);

View File

@ -20,9 +20,10 @@
*
*/
#include "api.h"
#ifdef PYTHON
#include <Python.h>
#include "api.h"
#include "execute.h"

View File

@ -63,6 +63,7 @@ static struct ui_strings {
const char *show_typing_other;
const char *show_welcome_msg;
const char *show_connection_msg;
const char *show_network_info;
const char *nodeslist_update_freq;
const char *autosave_freq;
@ -97,6 +98,7 @@ static struct ui_strings {
"show_typing_other",
"show_welcome_msg",
"show_connection_msg",
"show_network_info",
"nodeslist_update_freq",
"autosave_freq",
"line_join",
@ -130,6 +132,7 @@ static void ui_defaults(struct user_settings *settings)
settings->show_typing_other = SHOW_TYPING_ON;
settings->show_welcome_msg = SHOW_WELCOME_MSG_ON;
settings->show_connection_msg = SHOW_CONNECTION_MSG_ON;
settings->show_network_info = SHOW_NETWORK_INFO_OFF;
settings->nodeslist_update_freq = 7;
settings->autosave_freq = 600;
@ -398,6 +401,7 @@ int settings_load(struct user_settings *s, const char *patharg)
config_setting_lookup_bool(setting, ui_strings.show_typing_other, &s->show_typing_other);
config_setting_lookup_bool(setting, ui_strings.show_welcome_msg, &s->show_welcome_msg);
config_setting_lookup_bool(setting, ui_strings.show_connection_msg, &s->show_connection_msg);
config_setting_lookup_bool(setting, ui_strings.show_network_info, &s->show_network_info);
config_setting_lookup_int(setting, ui_strings.history_size, &s->history_size);
config_setting_lookup_int(setting, ui_strings.notification_timeout, &s->notification_timeout);

View File

@ -32,7 +32,7 @@
#define PASSWORD_EVAL_MAX 512
/* holds user setting values */
/* Holds user setting values defined in the toxic config file. */
struct user_settings {
int autolog; /* boolean */
int alerts; /* boolean */
@ -54,6 +54,7 @@ struct user_settings {
int show_typing_other; /* boolean */
int show_welcome_msg; /* boolean */
int show_connection_msg; /* boolean */
int show_network_info; /* boolean */
int nodeslist_update_freq; /* int (<= 0 to disable updates) */
int autosave_freq; /* int (<= 0 to disable autosave) */
@ -96,6 +97,8 @@ struct user_settings {
#endif
};
extern struct user_settings *user_settings;
enum settings_values {
AUTOLOG_OFF = 0,
AUTOLOG_ON = 1,
@ -118,6 +121,9 @@ enum settings_values {
SHOW_CONNECTION_MSG_OFF = 0,
SHOW_CONNECTION_MSG_ON = 1,
SHOW_NETWORK_INFO_OFF = 0,
SHOW_NETWORK_INFO_ON = 1,
DFLT_HST_SIZE = 700,
MPLEX_OFF = 0,

View File

@ -58,6 +58,7 @@
#include "message_queue.h"
#include "misc_tools.h"
#include "name_lookup.h"
#include "netprof.h"
#include "notify.h"
#include "prompt.h"
#include "settings.h"
@ -74,7 +75,7 @@
#ifdef VIDEO
#include "video_call.h"
#endif /* VIDEO */
ToxAV *av;
static ToxAV *av;
#endif /* AUDIO */
#ifdef PYTHON
@ -98,9 +99,15 @@ ToxWindow *prompt = NULL;
#define MAX_PASSWORD_LEN 64
struct Winthread Winthread;
struct cqueue_thread cqueue_thread;
struct av_thread av_thread;
static struct cqueue_thread cqueue_thread;
struct arg_opts arg_opts;
#ifdef AUDIO
static struct av_thread av_thread;
#endif
// This struct is not thread safe. It should only ever be written to from the main thread
// before any other thread that uses it is initialized.
struct user_settings *user_settings = NULL;
static struct user_password {
@ -137,6 +144,22 @@ static void catch_SIGSEGV(int sig)
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 flag_window_resize(int sig)
{
UNUSED_VAR(sig);
@ -171,6 +194,10 @@ void free_global_data(void)
void exit_toxic_success(Tox *m)
{
if (arg_opts.netprof_log_dump) {
netprof_log_dump(m, arg_opts.netprof_fp, get_unix_time() - arg_opts.netprof_start_time);
}
store_data(m, DATA_FILE);
user_password = (struct user_password) {
@ -201,6 +228,11 @@ void exit_toxic_success(Tox *m)
arg_opts.log_fp = NULL;
}
if (arg_opts.netprof_fp != NULL) {
fclose(arg_opts.netprof_fp);
arg_opts.netprof_fp = NULL;
}
endwin();
curl_global_cleanup();
@ -223,20 +255,10 @@ void exit_toxic_err(const char *errmsg, int errcode)
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)
/* Sets ncurses refresh rate. Lower values make it refresh more often. */
void set_window_refresh_rate(size_t refresh_rate)
{
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);
}
timeout(refresh_rate);
}
static void init_term(void)
@ -256,7 +278,7 @@ static void init_term(void)
keypad(stdscr, 1);
noecho();
nonl();
timeout(30);
set_window_refresh_rate(NCURSES_DEFAULT_REFRESH_RATE);
if (has_colors()) {
short bg_color = COLOR_BLACK;
@ -435,9 +457,7 @@ static void cleanup_init_messages(void)
return;
}
int i;
for (i = 0; i < init_messages.num; ++i) {
for (int i = 0; i < init_messages.num; ++i) {
free(init_messages.msgs[i]);
}
@ -446,19 +466,16 @@ static void cleanup_init_messages(void)
static void print_init_messages(ToxWindow *toxwin)
{
int i;
for (i = 0; i < init_messages.num; ++i) {
for (int 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)
{
size_t i;
size_t numfriends = tox_self_get_friend_list_size(m);
for (i = 0; i < numfriends; ++i) {
for (size_t i = 0; i < numfriends; ++i) {
friendlist_onFriendAdded(NULL, m, i, false);
}
@ -1072,6 +1089,37 @@ static void do_toxic(Tox *m)
pthread_mutex_unlock(&Winthread.lock);
}
/* Set interface refresh flag. This should be called whenever the interface changes.
*
* This function is not thread safe.
*/
void flag_interface_refresh(void)
{
Winthread.flag_refresh = 1;
Winthread.last_refresh_flag = get_unix_time();
}
/* How long we wait to idle interface refreshing after last flag set. Should be no less than 2. */
#define ACTIVE_WIN_REFRESH_TIMEOUT 2
static void poll_interface_refresh_flag(void)
{
pthread_mutex_lock(&Winthread.lock);
bool flag = Winthread.flag_refresh;
time_t t = Winthread.last_refresh_flag;
pthread_mutex_unlock(&Winthread.lock);
if (flag == 1 && timed_out(t, ACTIVE_WIN_REFRESH_TIMEOUT)) {
pthread_mutex_lock(&Winthread.lock);
Winthread.flag_refresh = 0;
pthread_mutex_unlock(&Winthread.lock);
}
}
/* How often we refresh windows that aren't focused */
#define INACTIVE_WIN_REFRESH_RATE 10
void *thread_winref(void *data)
@ -1079,11 +1127,12 @@ void *thread_winref(void *data)
Tox *m = (Tox *) data;
uint8_t draw_count = 0;
init_signal_catchers();
while (true) {
draw_active_window(m);
draw_count++;
draw_active_window(m);
if (Winthread.flag_resize) {
on_window_resize();
@ -1097,6 +1146,8 @@ void *thread_winref(void *data)
pthread_mutex_lock(&Winthread.lock);
exit_toxic_success(m);
}
poll_interface_refresh_flag();
}
}
@ -1110,9 +1161,12 @@ void *thread_cqueue(void *data)
for (size_t i = 2; i < MAX_WINDOWS_NUM; ++i) {
ToxWindow *toxwin = get_window_ptr(i);
if ((toxwin != NULL) && (toxwin->type == WINDOW_TYPE_CHAT)
&& (get_friend_connection_status(toxwin->num) != TOX_CONNECTION_NONE)) {
cqueue_try_send(toxwin, m);
if ((toxwin != NULL) && (toxwin->type == WINDOW_TYPE_CHAT)) {
cqueue_check_unread(toxwin);
if (get_friend_connection_status(toxwin->num) != TOX_CONNECTION_NONE) {
cqueue_try_send(toxwin, m);
}
}
}
@ -1155,6 +1209,7 @@ static void print_usage(void)
fprintf(stderr, " -p, --SOCKS5-proxy Use SOCKS5 proxy: Requires [IP] [port]\n");
fprintf(stderr, " -P, --HTTP-proxy Use HTTP proxy: Requires [IP] [port]\n");
fprintf(stderr, " -r, --namelist Use specified name lookup server list\n");
fprintf(stderr, " -s, --netstats Dump network statistic to log on exit: Requires [path]\n");
fprintf(stderr, " -t, --force-tcp Force toxic to use a TCP connection (use with proxies)\n");
fprintf(stderr, " -T, --tcp-server Act as a TCP relay server: Requires [port]\n");
fprintf(stderr, " -u, --unencrypt-data Unencrypt an encrypted data file\n");
@ -1194,6 +1249,7 @@ static void parse_args(int argc, char *argv[])
{"help", no_argument, 0, 'h'},
{"noconnect", no_argument, 0, 'o'},
{"namelist", required_argument, 0, 'r'},
{"netstats", required_argument, 0, 's'},
{"force-tcp", no_argument, 0, 't'},
{"tcp-server", required_argument, 0, 'T'},
{"SOCKS5-proxy", required_argument, 0, 'p'},
@ -1203,7 +1259,7 @@ static void parse_args(int argc, char *argv[])
{NULL, no_argument, NULL, 0},
};
const char *opts_str = "4bdehLotuxvc:f:l:n:r:p:P:T:";
const char *opts_str = "4bdehLotuxvc:f:l:n:r:s:p:P:T:";
int opt = 0;
int indexptr = 0;
@ -1399,6 +1455,25 @@ static void parse_args(int argc, char *argv[])
break;
}
case 's': {
if (optarg == NULL) {
queue_init_message("Invalid argument for option: %d", opt);
break;
}
arg_opts.netprof_fp = fopen(optarg, "w");
if (arg_opts.netprof_fp != NULL) {
queue_init_message("Network profile logging enabled. Logging to file: '%s'", optarg);
arg_opts.netprof_log_dump = true;
arg_opts.netprof_start_time = time(NULL);
} else {
queue_init_message("Failed to open file '%s' for network profile logging.", optarg);
}
break;
}
case 'u': {
arg_opts.unencrypt_data = 1;
break;
@ -1604,6 +1679,7 @@ int main(int argc, char **argv)
pthread_mutex_lock(&Winthread.lock);
print_init_messages(prompt);
flag_interface_refresh();
pthread_mutex_unlock(&Winthread.lock);
cleanup_init_messages();

View File

@ -23,6 +23,10 @@
#ifndef TOXIC_H
#define TOXIC_H
#ifndef NCURSES_WIDECHAR
#define NCURSES_WIDECHAR 1
#endif
#ifndef TOXICVER
#define TOXICVER "NOVERS" /* Use the -D flag to set this */
#endif
@ -46,10 +50,13 @@
#define MAX_STR_SIZE TOX_MAX_MESSAGE_LENGTH /* must be >= TOX_MAX_MESSAGE_LENGTH */
#define MAX_CMDNAME_SIZE 64
#define TOXIC_MAX_NAME_LENGTH 32 /* Must be <= TOX_MAX_NAME_LENGTH */
#define KEY_IDENT_DIGITS 3 /* number of hex digits to display for the pub-key based identifier */
#define KEY_IDENT_BYTES 6 /* number of hex digits to display for the public key identifier */
#define TIME_STR_SIZE 32
#define COLOR_STR_SIZE 10 /* should fit every color option */
#define NCURSES_DEFAULT_REFRESH_RATE 100
#define NCURSES_GAME_REFRESH_RATE 25
#ifndef MAX_PORT_RANGE
#define MAX_PORT_RANGE 65535
#endif
@ -102,6 +109,11 @@ typedef enum _FATAL_ERRS {
void lock_status(void);
void unlock_status(void);
void flag_interface_refresh(void);
/* Sets ncurses refresh rate. Lower values make it refresh more often. */
void set_window_refresh_rate(size_t refresh_rate);
void exit_toxic_success(Tox *m);
void exit_toxic_err(const char *errmsg, int errcode);
@ -137,5 +149,7 @@ void on_friend_typing(Tox *m, uint32_t friendnumber, bool is_typing, void *userd
void on_friend_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata);
void on_lossless_custom_packet(Tox *m, uint32_t friendnumber, const uint8_t *data, size_t length, void *userdata);
extern char *DATA_FILE;
extern char *BLOCK_FILE;
#endif /* TOXIC_H */

View File

@ -92,21 +92,21 @@ typedef struct VideoDevice {
} VideoDevice;
const char *dvideo_device_names[2]; /* Default device */
const char *video_devices_names[2][MAX_DEVICES]; /* Container of available devices */
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 */
static const char *dvideo_device_names[2]; /* Default device */
static char *video_devices_names[2][MAX_DEVICES]; /* Container of available devices */
static int size[2]; /* Size of above containers */
static VideoDevice *video_devices_running[2][MAX_DEVICES] = {{NULL}}; /* Running devices */
static uint32_t primary_video_device[2]; /* Primary device */
static ToxAV *av = NULL;
/* q_mutex */
#define lock pthread_mutex_lock(&video_mutex)
#define unlock pthread_mutex_unlock(&video_mutex)
pthread_mutex_t video_mutex;
static pthread_mutex_t video_mutex;
bool video_thread_running = true,
video_thread_paused = true; /* Thread control */
static bool video_thread_running = true;
static bool video_thread_paused = true; /* Thread control */
void *video_thread_poll(void *);
@ -187,7 +187,7 @@ VideoDeviceError init_video_devices(void)
#if defined(__OSX__) || defined(__APPLE__)
if (osx_video_init((char **)video_devices_names[vdt_input], &size[vdt_input]) != 0) {
if (osx_video_init(&video_devices_names[vdt_input][0], &size[vdt_input]) != 0) {
return vde_InternalError;
}
@ -209,12 +209,24 @@ VideoDeviceError init_video_devices(void)
/* Query V4L for capture capabilities */
if (-1 != ioctl(fd, VIDIOC_QUERYCAP, &cap)) {
video_input_name = (char *)malloc(strlen((const char *)cap.card) + strlen(device_address) + 4);
if (video_input_name == NULL) {
close(fd);
return vde_InternalError;
}
strcpy(video_input_name, (char *)cap.card);
strcat(video_input_name, " (");
strcat(video_input_name, (char *)device_address);
strcat(video_input_name, ")");
} else {
video_input_name = (char *)malloc(strlen(device_address) + 3);
if (video_input_name == NULL) {
close(fd);
return vde_InternalError;
}
strcpy(video_input_name, "(");
strcat(video_input_name, device_address);
strcat(video_input_name, ")");
@ -229,6 +241,9 @@ VideoDeviceError init_video_devices(void)
#endif
size[vdt_output] = 1;
// TODO(iphydf): String literals are const char *. This may need to be
// copied, or if we're not owning any output device names, it should be
// const and video_devices_names needs to be split.
char *video_output_name = "Toxic Video Receiver";
video_devices_names[vdt_output][0] = video_output_name;
@ -262,7 +277,7 @@ VideoDeviceError terminate_video_devices(void)
int i;
for (i = 0; i < size[vdt_input]; ++i) {
free((void *)video_devices_names[vdt_input][i]);
free(video_devices_names[vdt_input][i]);
}
if (pthread_mutex_destroy(&video_mutex) != 0) {

View File

@ -41,16 +41,10 @@
#include "game_base.h"
#endif
extern char *DATA_FILE;
extern struct Winthread Winthread;
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;
/* CALLBACKS START */
void on_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
{
@ -77,6 +71,8 @@ void on_friend_connection_status(Tox *m, uint32_t friendnumber, Tox_Connection c
windows[i]->onConnectionChange(windows[i], m, friendnumber, connection_status);
}
}
flag_interface_refresh();
}
void on_friend_typing(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata)
@ -92,6 +88,8 @@ void on_friend_typing(Tox *m, uint32_t friendnumber, bool is_typing, void *userd
windows[i]->onTypingChange(windows[i], m, friendnumber, is_typing);
}
}
flag_interface_refresh();
}
void on_friend_message(Tox *m, uint32_t friendnumber, Tox_Message_Type type, const uint8_t *string, size_t length,
@ -123,6 +121,8 @@ void on_friend_name(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t
}
}
flag_interface_refresh();
store_data(m, DATA_FILE);
}
@ -140,6 +140,8 @@ void on_friend_status_message(Tox *m, uint32_t friendnumber, const uint8_t *stri
windows[i]->onStatusMessageChange(windows[i], friendnumber, msg, length);
}
}
flag_interface_refresh();
}
void on_friend_status(Tox *m, uint32_t friendnumber, Tox_User_Status status, void *userdata)
@ -151,6 +153,8 @@ void on_friend_status(Tox *m, uint32_t friendnumber, Tox_User_Status status, voi
windows[i]->onStatusChange(windows[i], m, friendnumber, status);
}
}
flag_interface_refresh();
}
void on_friend_added(Tox *m, uint32_t friendnumber, bool sort)
@ -186,7 +190,7 @@ void on_conference_invite(Tox *m, uint32_t friendnumber, Tox_Conference_Type typ
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onConferenceInvite != NULL) {
windows[i]->onConferenceInvite(windows[i], m, friendnumber, type, (char *) conference_pub_key, length);
windows[i]->onConferenceInvite(windows[i], m, friendnumber, type, (const char *) conference_pub_key, length);
}
}
}
@ -200,6 +204,8 @@ void on_conference_peer_list_changed(Tox *m, uint32_t conferencenumber, void *us
windows[i]->onConferenceNameListChange(windows[i], m, conferencenumber);
}
}
flag_interface_refresh();
}
void on_conference_peer_name(Tox *m, uint32_t conferencenumber, uint32_t peernumber, const uint8_t *name,
@ -238,7 +244,7 @@ void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, u
{
UNUSED_VAR(userdata);
struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
if (!ft) {
return;
@ -261,7 +267,7 @@ void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint
{
UNUSED_VAR(userdata);
struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
if (!ft) {
return;
@ -269,7 +275,7 @@ void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint
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);
windows[i]->onFileRecvChunk(windows[i], m, friendnumber, filenumber, position, (const char *) data, length);
}
}
}
@ -279,7 +285,7 @@ void on_file_recv_control(Tox *m, uint32_t friendnumber, uint32_t filenumber, To
{
UNUSED_VAR(userdata);
struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
if (!ft) {
return;
@ -310,7 +316,7 @@ void on_file_recv(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint32_t k
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,
windows[i]->onFileRecv(windows[i], m, friendnumber, filenumber, file_size, (const char *) filename,
filename_length);
}
}
@ -421,13 +427,15 @@ void set_active_window_index(uint8_t index)
/* Displays the next window if `ch` is equal to the next window key binding.
* Otherwise displays the previous window.
*/
void set_next_window(int ch)
static void set_next_window(int ch)
{
uint8_t index = 0;
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;
index = i;
break;
}
}
} else {
@ -435,13 +443,13 @@ void set_next_window(int ch)
for (uint8_t i = start; i > 0; --i) {
if (windows[i] != NULL) {
set_active_window_index(i);
return;
index = i;
break;
}
}
}
set_active_window_index(0);
set_active_window_index(index);
}
/* Deletes window w and cleans up */
@ -677,10 +685,10 @@ void draw_window_bar(ToxWindow *self)
int cur_x;
int cur_y;
UNUSED_VAR(cur_y);
getyx(win, cur_y, cur_x);
UNUSED_VAR(cur_y);
wattron(win, COLOR_PAIR(BAR_TEXT));
mvwhline(win, 0, cur_x, ' ', COLS - cur_x);
wattroff(win, COLOR_PAIR(BAR_TEXT));
@ -784,21 +792,43 @@ void draw_active_window(Tox *m)
pthread_mutex_lock(&Winthread.lock);
a->alert = WINDOW_ALERT_NONE;
a->pending_messages = 0;
bool flag_refresh = Winthread.flag_refresh;
pthread_mutex_unlock(&Winthread.lock);
touchwin(a->window);
a->onDraw(a, m);
wrefresh(a->window);
if (flag_refresh) {
touchwin(a->window);
a->onDraw(a, m);
wrefresh(a->window);
}
#ifdef AUDIO
else if (a->is_call && timed_out(a->chatwin->infobox.lastupdate, 1)) {
touchwin(a->window);
a->onDraw(a, m);
wrefresh(a->window);
}
#endif // AUDIO
#ifdef GAMES
if (a->type == WINDOW_TYPE_GAME) {
if (!flag_refresh) { // we always want to be continously refreshing game windows
touchwin(a->window);
a->onDraw(a, m);
wrefresh(a->window);
}
int ch = getch();
if (ch == ERR) {
return;
}
pthread_mutex_lock(&Winthread.lock);
flag_interface_refresh();
pthread_mutex_unlock(&Winthread.lock);
if (ch == user_settings->key_next_tab || ch == user_settings->key_prev_tab) {
set_next_window(ch);
}
@ -817,6 +847,10 @@ void draw_active_window(Tox *m)
return;
}
pthread_mutex_lock(&Winthread.lock);
flag_interface_refresh();
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;
@ -892,10 +926,30 @@ int get_num_active_windows(void)
return num_active_windows;
}
/* Returns the number of active windows of given type. */
size_t get_num_active_windows_type(WINDOW_TYPE type)
{
size_t count = 0;
for (size_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
ToxWindow *w = windows[i];
if (w == NULL) {
continue;
}
if (w->type == type) {
++count;
}
}
return count;
}
/* destroys all chat and conference windows (should only be called on shutdown) */
void kill_all_windows(Tox *m)
{
for (uint8_t i = 2; i < MAX_WINDOWS_NUM; ++i) {
for (size_t i = 2; i < MAX_WINDOWS_NUM; ++i) {
ToxWindow *w = windows[i];
if (w == NULL) {

View File

@ -98,13 +98,24 @@ typedef enum {
Uncomment if necessary */
/* #define URXVT_FIX */
/*
* Used to control access to global variables via a mutex, as well as to handle signals.
* Any file, variable or data structure that is used by the UI/Window thread and any other thread
* must be guarded by `lock`.
*
* There should only ever be one instance of this struct.
*/
struct Winthread {
pthread_t tid;
pthread_mutex_t lock;
volatile sig_atomic_t sig_exit_toxic;
volatile sig_atomic_t flag_resize;
volatile sig_atomic_t flag_refresh;
volatile sig_atomic_t last_refresh_flag;
};
extern struct Winthread Winthread;
struct cqueue_thread {
pthread_t tid;
};
@ -131,6 +142,10 @@ struct arg_opts {
bool logging;
FILE *log_fp;
bool netprof_log_dump;
time_t netprof_start_time;
FILE *netprof_fp;
char proxy_address[256];
uint8_t proxy_type;
uint16_t proxy_port;
@ -138,6 +153,8 @@ struct arg_opts {
uint16_t tcp_port;
};
extern struct arg_opts arg_opts;
typedef struct ToxWindow ToxWindow;
typedef struct StatusBar StatusBar;
typedef struct PromptBuf PromptBuf;
@ -224,6 +241,8 @@ struct ToxWindow {
WINDOW *window_bar;
};
extern ToxWindow *windows[MAX_WINDOWS_NUM];
/* statusbar info holder */
struct StatusBar {
WINDOW *topline;
@ -233,6 +252,12 @@ struct StatusBar {
size_t nick_len;
Tox_User_Status status;
Tox_Connection connection;
/* network info */
uint64_t up_bytes;
uint64_t down_bytes;
uint64_t time_last_refreshed;
char network_info[MAX_STR_SIZE];
};
#ifdef AUDIO
@ -307,6 +332,9 @@ ToxWindow *get_window_ptr(size_t i);
ToxWindow *get_active_window(void);
void draw_window_bar(ToxWindow *self);
/* Returns the number of active windows of given type. */
size_t get_num_active_windows_type(WINDOW_TYPE type);
/* refresh inactive windows to prevent scrolling bugs.
call at least once per second */
void refresh_inactive_windows(void);