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

Compare commits

..

94 Commits

Author SHA1 Message Date
9dfa455561 Merge branch 'master' into new_groupchats 2016-10-06 12:53:57 -04:00
372fcb0a67 Fix merge problems 2016-09-27 16:35:25 -04:00
c760ffc563 Merge with master branch 2016-09-24 23:34:29 -04:00
c6f2a9cb59 Merge with master branch 2016-09-24 23:31:20 -04:00
76bfa34c45 Merge branch 'master' into new_groupchats 2016-06-29 21:54:30 -04:00
43d9623877 Fix merge conflicts 2016-06-12 18:27:54 -04:00
60b431459c Add another bootstrap node 2015-12-07 23:56:29 -05:00
6e7b0a5430 Fix groupchat creation bug
Users can no longer create new groupchat windows if they have been kicked from a group and haven't closed the window
2015-12-07 02:33:54 -05:00
86b36d7a13 Add working bootstrap server to DHTnodes 2015-12-06 23:09:15 -05:00
7e122ceec6 Merge branch 'master' into new_groupchats 2015-12-06 22:12:02 -05:00
fe0eba9107 Fix merge conflict 2015-12-01 18:01:02 -05:00
1d1c051a44 Merge branch 'master' into new_groupchats 2015-12-01 17:57:45 -05:00
fbd22003a8 Merge with upstream master 2015-11-10 23:52:54 -05:00
3cfda32b5e Fix help menu 2015-11-07 01:17:06 -05:00
9b1592b335 Merge new_av from upstream 2015-11-07 00:21:42 -05:00
fbf50ecc8c Merge branch 'master' of https://github.com/JFreegman/toxic into new_groupchats 2015-11-02 14:49:48 -05:00
7025a33097 Merge with upstream 2015-11-01 21:07:22 -05:00
171024428b Merge with master branch 2015-10-16 21:01:49 -04:00
2e4c86be4b Add last seen and public key fields for group peers and add whois command 2015-09-13 23:15:58 -04:00
97d5fb84fc Add command to print your own group public key 2015-09-13 19:38:49 -04:00
b2c512687a Sort group peerlist by role/name 2015-09-01 17:27:17 -04:00
8526d4d77e Refactor group peerlist to match API refactor
Peerlists are now similar to the friendlist, which makes managing them much easier, and
improves efficiency
2015-09-01 02:29:25 -04:00
ed1429afa1 Merge with upstream 2015-08-27 21:36:20 -04:00
1270f34596 group API type change 2015-08-23 19:15:44 -04:00
6eef188d3c fix travis 2015-08-08 16:45:48 -04:00
8e23ce1b83 Group API changes 2015-07-22 14:55:52 -04:00
15ef50e46c Refactor groupchats 2015-07-16 17:10:04 -04:00
0597152352 merge with master 2015-07-14 02:19:10 -04:00
23bb980173 Add group callbacks for password, peerlimit and privacy state changes 2015-07-14 02:07:52 -04:00
a846c38695 Port to new group API 2015-07-13 22:12:13 -04:00
1f7f4490b2 merge with master 2015-07-08 21:09:58 -04:00
40b220c821 Revert "Merge branch 'Ansa89-add_translation'"
This reverts commit 312d0c3f42, reversing
changes made to 409e4ddd96.
2015-07-08 21:08:55 -04:00
cb4a631df0 strcasecmp should be strcmp 2015-06-12 23:16:00 -04:00
35718db46f fix ban command bug 2015-06-10 19:30:44 -04:00
1ba0891f71 fix ban API calls 2015-06-08 21:56:32 -04:00
b36ada0f5b remove obsolete prune command 2015-06-04 16:46:30 -04:00
9cd2158c72 add group silencing and improve group help menu 2015-06-04 04:08:11 -04:00
928134da7a implement banning/unbanning 2015-06-03 04:32:59 -04:00
52a3367b5e small API fix 2015-06-01 03:12:12 -04:00
7e7087e94e add mod-list prune command 2015-05-30 23:57:30 -04:00
9cd8afe90a add mod and unmod commands 2015-05-29 02:00:18 -04:00
526bd02189 Add group peer kicking && update related callback 2015-05-26 01:23:09 -04:00
3826fd793d Merge branch 'master' into new_groupchats 2015-05-24 18:13:15 -04:00
a6d7e9b839 add ability for founder to set group peer limit 2015-05-24 03:27:50 -04:00
29d0384a90 add ability for founder to set group privacy state 2015-05-22 21:41:32 -04:00
0481f43746 Update .travis.yml 2015-05-20 21:00:28 -04:00
f021908f8b implement group passwords 2015-05-20 19:07:25 -04:00
f82d58bbfc Merge branch 'master' of https://github.com/Tox/toxic into new_groupchats 2015-05-19 04:26:38 -04:00
9385f1145f update group api call 2015-05-05 22:32:42 -04:00
2acd99b04c show self in group when it's first created 2015-04-14 01:59:39 -04:00
6cd7fb9e5b Merge branch 'master' into new_groupchats 2015-04-13 00:55:05 -04:00
540bf4a5c4 not clear which error message is given for ipv6 failure 2015-04-13 00:45:15 -04:00
a360afe08a remove group self-timeout callback 2015-04-12 21:56:42 -04:00
b66a1f6ba1 merge branch 'master' into new_groupchats 2015-04-10 00:22:07 -04:00
b66932fcec Merge branch 'master' into new_groupchats 2015-04-09 02:14:50 -04:00
de38df32c2 merge with upstream 2015-04-07 17:28:12 -04:00
bdfbda7cda merge with upstream 2015-04-04 03:36:09 -04:00
0c49ab392d Merge branch 'master' into new_groupchats 2015-04-02 22:45:06 -04:00
b2c0753fdf Update .travis.yml 2015-04-02 22:31:20 -04:00
c97095be68 Merge branch 'master' into new_groupchats 2015-03-31 21:59:26 -04:00
c2b9967691 merge with master 2015-03-31 19:34:33 -04:00
ee074f334e merge with master (new api) 2015-03-30 21:46:25 -04:00
23429d8da4 Merge pull request #5 from stqism/patch-2
I'm not allowed to do this correctly on the first try.
2015-03-26 03:16:29 -04:00
e34ac70a72 I'm not allowed to do this correctly on the first try. 2015-03-26 00:12:30 -07:00
77d45334ac Merge pull request #4 from stqism/patch-1
Build on commit
2015-03-26 03:00:08 -04:00
88719c4ccc Update .travis.yml 2015-03-25 23:56:40 -07:00
386c5a8fa5 sound/desktop alert on private group message 2015-03-22 17:07:33 -04:00
5caa9bed51 fix nick parsing bug for private messages 2015-03-22 17:01:46 -04:00
59b90b1328 better format for private messages 2015-03-22 01:37:07 -04:00
05c05868c6 implement group private messaging 2015-03-22 01:07:56 -04:00
88d6d907d8 Merge branch 'master' into new_groupchats 2015-03-21 15:15:48 -04:00
6cc8fdf215 don't delete groups on client exit 2015-03-19 17:39:11 -04:00
02a0cac85a . 2015-03-13 20:38:44 -04:00
0976804fdf Merge branch 'master' into new_groupchats 2015-03-13 20:34:49 -04:00
f8ff5df2f3 fix race conditions 2015-03-13 16:32:35 -04:00
22acba5aa8 merge wit upstream 2015-03-11 18:52:28 -04:00
2bcce234a8 add group rejoin command 2015-03-07 00:05:54 -05:00
5859763f04 load saved group names 2015-03-04 00:08:30 -05:00
4cc0805036 fix small bug 2015-02-28 14:37:28 -05:00
830ddb21b5 add support for group persistence 2015-02-28 02:44:41 -05:00
b31bd93e7d api function name change 2015-02-26 19:59:55 -05:00
a89e6b2cdc merge mistake 2015-02-19 21:36:21 -05:00
dd3ea3dab5 merge with upstream 2015-02-19 21:33:46 -05:00
c3179b3b22 fix memory leak 2015-02-19 21:24:52 -05:00
5c98c1c51e group invite API change 2015-01-27 18:00:25 -05:00
ff69cdd253 add friend group invites 2015-01-23 00:52:09 -05:00
38e55d55b3 fix formatting bug 2015-01-20 18:06:26 -05:00
6f45085d86 update DHTnodes for new test network 2015-01-20 00:52:00 -05:00
0348f81ba8 remove old group audio code 2015-01-18 22:32:59 -05:00
7ee858110c improve command parsing so you don't need quotes & add group ignoring 2015-01-12 20:56:32 -05:00
89637e7d2f implement group join rejection callback 2015-01-12 01:09:56 -05:00
ff3da5f657 implement group status/nick changes, various fixes 2015-01-11 16:48:40 -05:00
b3ab0bde05 a couple fixes 2015-01-04 17:22:24 -05:00
26dda8dbf9 implement new groupchats 2015-01-04 01:56:37 -05:00
101 changed files with 4205 additions and 4831 deletions

1
.gitignore vendored
View File

@ -16,4 +16,3 @@ stamp-h1
build/toxic
build/*.o
build/*.d
apidoc/python/build

View File

@ -1,37 +0,0 @@
---
language: python
python: nightly
addons:
apt:
packages:
- astyle
- libalut-dev
- libconfig-dev
- libnotify-dev
- libopenal-dev
- libopus-dev
- libqrencode-dev
- libvpx-dev
cache:
directories:
- $HOME/cache
install:
# Where to find libraries.
- export LD_LIBRARY_PATH=$HOME/cache/usr/lib
- export PKG_CONFIG_PATH=$HOME/cache/usr/lib/pkgconfig
# c-sodium
- git clone --depth=1 --branch=stable https://github.com/jedisct1/libsodium ../libsodium
- test -f $HOME/cache/usr/lib/libsodium.so || (cd ../libsodium && ./configure --prefix=$HOME/cache/usr && make install -j$(nproc))
# c-toxcore
- git clone --depth=1 https://github.com/TokTok/c-toxcore ../c-toxcore
- test -f $HOME/cache/usr/lib/libtoxcore.so || (cd ../c-toxcore && cmake -B_build -H. -DCMAKE_INSTALL_PREFIX:PATH=$HOME/cache/usr && make -C_build install -j$(nproc))
# astyle
- wget -O ../astyle.tar.gz https://deb.debian.org/debian/pool/main/a/astyle/astyle_2.06.orig.tar.gz
- test -f $HOME/cache/astyle/build/gcc/bin/astyle || (tar -xf ../astyle.tar.gz -C "$HOME/cache" && make -C "$HOME/cache/astyle/build/gcc" -j2)
script:
- $HOME/cache/astyle/build/gcc/bin/astyle --options=astylerc $(find . -name "*.[ch]")
- make ENABLE_PYTHON=1 -j2

View File

@ -1,30 +0,0 @@
load("//tools/project:build_defs.bzl", "project")
project()
cc_binary(
name = "toxic",
srcs = glob([
"src/*.c",
"src/*.h",
]),
copts = [
"-DAUDIO",
"-DPACKAGE_DATADIR='\"data\"'",
"-DPYTHON",
"-DQRCODE",
"-DVIDEO",
"-Wno-error=unused-result",
],
deps = [
"//c-toxcore",
"@curl",
"@libconfig",
"@libqrencode",
"@libvpx",
"@ncurses",
"@openal",
"@python3//:python",
"@x11",
],
)

View File

View File

@ -1,66 +1,70 @@
# Installation
* [Dependencies](#dependencies)
* [OS X Notes](#os-x-notes)
* [Dependencies](#deps)
* [OS X Notes](#deps_osx)
* [Compiling](#compiling)
* [Documentation](#documentation)
* [Documentation](#docs)
* [Notes](#notes)
* [Compilation variables](#compilation-variables)
* [Environment variables](#environment-variables)
* [Compilation variables](#comp_vars)
* [Packaging](#packaging)
<a name="deps" />
## Dependencies
| Name | Needed by | Debian package |
|------------------------------------------------------|----------------------------|---------------------|
| [Tox Core](https://github.com/toktok/c-toxcore) | BASE | *None* |
| [Tox Core](https://github.com/irungentoo/toxcore) | BASE | *None* |
| [NCurses](https://www.gnu.org/software/ncurses) | BASE | libncursesw5-dev |
| [LibConfig](http://www.hyperrealm.com/libconfig) | BASE | libconfig-dev |
| [GNUmake](https://www.gnu.org/software/make) | BASE | make |
| [libcurl](http://curl.haxx.se/) | BASE | libcurl4-openssl-dev|
| [libqrencode](https://fukuchi.org/works/qrencode/) | QRCODE | libqrencode-dev |
| [libqrencode](https://fukuchi.org/works/qrencode/) | BASE | libqrencode-dev |
| [Tox Core AV](https://github.com/irungentoo/toxcore) | AUDIO | *None* |
| [OpenAL](http://openal.org) | AUDIO, SOUND NOTIFICATIONS | libopenal-dev |
| [OpenALUT](http://openal.org) | SOUND NOTIFICATIONS | libalut-dev |
| [LibNotify](https://developer.gnome.org/libnotify) | DESKTOP NOTIFICATIONS | libnotify-dev |
| [Python 3](http://www.python.org/) | PYTHON | python3-dev |
| [AsciiDoc](http://asciidoc.org/index.html) | DOCUMENTATION<sup>1</sup> | asciidoc |
<sup>1</sup>: see [Documentation](#docs)
<sup>1</sup>: see [Documentation](#documentation)
<a name="deps_osx" />
#### OS X Notes
Using [Homebrew](http://brew.sh):
```
brew install curl qrencode openal-soft freealut libconfig libpng
brew install --HEAD https://raw.githubusercontent.com/Tox/homebrew-tox/master/Formula/libtoxcore.rb
brew install libnotify
export PKG_CONFIG_PATH=/usr/local/opt/openal-soft/lib/pkgconfig
make
brew install openal-soft freealut libconfig
brew install https://raw.githubusercontent.com/Tox/homebrew-tox/master/Formula/libtoxcore.rb
brew install https://raw.githubusercontent.com/Homebrew/homebrew-x11/master/libnotify.rb
```
You can omit `libnotify` if you intend to build without desktop notifications enabled.
<a name="Compiling">
## Compiling
```
make
sudo make install
make PREFIX="/where/to/install"
sudo make install PREFIX="/where/to/install"
```
<a name="docs" />
#### Documentation
Run `make doc` in the build directory after editing the asciidoc files to regenerate the manpages.<br />
**Note for developers**: asciidoc files and generated manpages will need to be committed together.<br />
**Note for everyone**: [asciidoc](http://asciidoc.org/index.html) (and this step) is only required for regenerating manpages when you modify them.
**NOTE FOR DEVELOPERS**: asciidoc files and generated manpages will need to be commited together.<br />
**NOTE FOR EVERYONE**: [asciidoc](http://asciidoc.org/index.html) (and this step) is only required for regenerating manpages when you modify them.
<a name="notes" />
## Notes
<a name="comp_vars" />
#### Compilation variables
* You can add specific flags to the Makefile with `USER_CFLAGS=""` and `USER_LDFLAGS=""` passed as arguments to make, or as environment variables
* Default compile options can be overridden by using special variables:
* `DISABLE_X11=1` → Disable X11 support (needed for focus tracking)
* `DISABLE_AV=1`Disable audio call support
* `DISABLE_SOUND_NOTIFY=1` → Disable sound notifications support
* `DISABLE_DESKTOP_NOTIFY=1`Disable desktop notifications support
* `ENABLE_PYTHON=1`Build toxic with Python scripting support
* You can add specific flags to the Makefile with `USER_CFLAGS=""` and/or `USER_LDFLAGS=""`
* You can pass your own flags to the Makefile with `CFLAGS=""` and/or `LDFLAGS=""` (this will supersede the default ones)
* Additional features are automatically enabled if all dependencies are found, but you can disable them by using special variables:
* `DISABLE_X11=1`build toxic without X11 support (needed for focus tracking)
* `DISABLE_AV=1` → build toxic without audio call support
* `DISABLE_SOUND_NOTIFY=1`build toxic without sound notifications support
* `DISABLE_DESKTOP_NOTIFY=1`build toxic without desktop notifications support
* `DESTDIR=""` Specifies the base install directory for binaries and data files (e.g.: DESTDIR="/tmp/build/pkg")
<a name="packaging" />
#### Packaging
* For packaging purpose, you can use `DESTDIR=""` to specify a directory where to store installed files
* `DESTDIR=""` can be used in addition to `PREFIX=""`:
* `DESTDIR=""` is meant to specify a directory where to store installed files (ex: "/tmp/build/pkg")
* `PREFIX=""` is meant to specify a prefix directory for binaries and data files (ex: "/usr/local")
#### Environment variables
* You can use the `CFLAGS` and `LDFLAGS` environment variables to add specific flags to the Makefile
* The `PREFIX` environment variable specifies a base install directory for binaries and data files. This is interchangeable with the `DESTDIR` variable, and is generally used by systems that have the `PREFIX` environment variable set by default.<br />
**Note**: `sudo` does not preserve user environment variables by default on some systems. See the `sudoers` manual for more information.

View File

@ -3,15 +3,13 @@ CFG_DIR = $(BASE_DIR)/cfg
-include $(CFG_DIR)/global_vars.mk
LIBS = toxcore ncursesw libconfig libcurl
LIBS = libtoxcore ncursesw libconfig libqrencode
CFLAGS ?= -g
CFLAGS += -std=gnu99 -pthread -Wall -fstack-protector-all
CFLAGS = -std=gnu99 -pthread -Wall -g -fstack-protector-all
CFLAGS += '-DTOXICVER="$(VERSION)"' -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED -D_FILE_OFFSET_BITS=64
CFLAGS += '-DPACKAGE_DATADIR="$(abspath $(DATADIR))"'
CFLAGS += ${USER_CFLAGS}
LDFLAGS ?=
LDFLAGS += ${USER_LDFLAGS}
CFLAGS += $(USER_CFLAGS)
LDFLAGS = $(USER_LDFLAGS)
OBJ = autocomplete.o avatars.o bootstrap.o chat.o chat_commands.o configdir.o curl_util.o execute.o
OBJ += file_transfers.o friendlist.o global_commands.o group_commands.o groupchat.o help.o input.o
@ -21,19 +19,23 @@ OBJ += term_mplex.o toxic.o toxic_strings.o windows.o
# Check on wich system we are running
UNAME_S = $(shell uname -s)
ifeq ($(UNAME_S), Linux)
LDFLAGS += -ldl -lrt
-include $(CFG_DIR)/systems/Linux.mk
endif
ifeq ($(UNAME_S), FreeBSD)
-include $(CFG_DIR)/systems/FreeBSD.mk
endif
ifeq ($(UNAME_S), DragonFly)
-include $(CFG_DIR)/systems/FreeBSD.mk
endif
ifeq ($(UNAME_S), OpenBSD)
LIBS := $(filter-out ncursesw, $(LIBS))
LDFLAGS += -lncursesw
endif
ifeq ($(UNAME_S), NetBSD)
LIBS := $(filter-out ncursesw, $(LIBS))
LDFLAGS += -lncursesw
-include $(CFG_DIR)/systems/FreeBSD.mk
endif
ifeq ($(UNAME_S), Darwin)
-include $(CFG_DIR)/systems/Darwin.mk
endif
ifeq ($(UNAME_S), Solaris)
-include $(CFG_DIR)/systems/Solaris.mk
endif
# Check on which platform we are running
UNAME_M = $(shell uname -m)

View File

@ -3,12 +3,13 @@
src="https://scan.coverity.com/projects/4975/badge.svg"/>
</a>
Toxic is a [Tox](https://tox.chat)-based instant messenging and video chat client.
Toxic is a [Tox](https://tox.im)-based instant messenging client which formerly resided in the [Tox core repository](https://github.com/irungentoo/toxcore), and is now available as a standalone application.
[![Toxic Screenshot](https://i.imgur.com/san99Z2.png "Home Screen")](https://i.imgur.com/san99Z2.png)
## Installation
[See the install instructions](/INSTALL.md)
[Use our repositories](https://wiki.tox.chat/binaries#other_linux)<br />
[Compile it yourself](/INSTALL.md)
## Settings
Running Toxic for the first time creates an empty file called toxic.conf in your home configuration directory ("~/.config/tox" for Linux users). Adding options to this file allows you to enable auto-logging, change the time format (12/24 hour), and much more.

View File

@ -1,20 +0,0 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SPHINXPROJ = toxic_api
SOURCEDIR = source
BUILDDIR = build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

View File

@ -1,157 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# toxic_api documentation build configuration file, created by
# sphinx-quickstart on Tue May 16 08:58:24 2017.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = []
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = 'toxic_api'
copyright = '2017, Jakob Kreuze'
author = 'Jakob Kreuze'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.8.3'
# The full version, including alpha/beta/rc tags.
release = '0.8.3'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = []
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'alabaster'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# -- Options for HTMLHelp output ------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'toxic_apidoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'toxic_api.tex', 'toxic\\_api Documentation',
'Jakob Kreuze', 'manual'),
]
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'toxic_api', 'toxic_api Documentation',
[author], 1)
]
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'toxic_api', 'toxic_api Documentation',
author, 'toxic_api', 'One line description of project.',
'Miscellaneous'),
]

View File

@ -1,8 +0,0 @@
============
API Examples
============
Fortune
=======
.. literalinclude:: fortune.py
:language: python

View File

@ -1,37 +0,0 @@
import toxic_api
import random
FORTUNES = [
"A bug in the code is worth two in the documentation.",
"A bug in the hand is better than one as yet undetected.",
"\"A debugged program is one for which you have not yet found the "
"conditions that make it fail.\" -- Jerry Ogdin"
]
def send_fortune(args):
"""Callback function that sends the contact of the current window a
given number of random fortunes.
"""
if len(args) != 1:
toxic_api.display("Only one argument allowed!")
return
try:
count = int(args[0])
except ValueError:
toxic_api.display("Argument must be a number!")
return
if count < 0 or count > 20:
toxic_api.display("Argument is too large!")
return
name = toxic_api.get_nick()
toxic_api.send("%s has decided to send you %d fortunes:" % (name, count))
for _ in range(count):
toxic_api.send(random.choice(FORTUNES))
toxic_api.register("/fortune", "Send a fortune to the contact of the current "
"window", send_fortune)

View File

@ -1,9 +0,0 @@
Toxic Scripting Interface Documentation
=======================================
.. toctree::
:maxdepth: 2
intro
reference
examples

View File

@ -1,12 +0,0 @@
=========================
Toxic Scripting Interface
=========================
A Python scripting interface to `Toxic <https://github.com/JFreegman/toxic>`_.
Getting Started
===============
Toxic is compiled with Python support by default. To access the scripting interface, simply import "toxic_api" in your script.
Scripts can be run by issuing "/run <path>" from toxic, or placing them in the "autorun_path" from your toxic configuration file.

View File

@ -1,73 +0,0 @@
=============
API Reference
=============
Messages
========
.. function:: display(msg)
Display a message to the user through the current window.
:param msg: The message to display.
:type msg: string
:rtype: none
.. function:: send(msg)
Send a message to the user specified by the currently open conversation.
:param msg: The message to display.
:type msg: string
:rtype: none
State
=====
.. function:: get_nick()
Return the user's current nickname.
:rtype: string
.. function:: get_status()
Return a string representing the user's current status. Can be either "online", "away", or "busy".
:rtype: string
.. function:: get_status_message()
Return the user's current status message.
:rtype: string
.. function:: get_all_friends()
Return a list of all the user's friends.
:rtype: list of (string, string) tuples containing the nickname followed by their public key
Commands
========
.. function:: execute(command, class)
Executes the given command. The API exports three constants for the class parameter; GLOBAL_COMMAND, CHAT_COMMAND, and GROUPCHAT_COMMAND.
:param command: The command to execute.
:type command: string
:param class: The class of the command.
:type class: int
:rtype: none
.. function:: register(command, help, callback)
Register a callback to be executed whenever command is run. The callback function will be called with one argument, a list of arguments from when the user calls the command.
:param command: The command to listen for.
:type command: string
:param help: A description of the command to be shown in the help menu.
:type help: string
:param callback: The function to be called.
:type callback: callable
:rtype: none

View File

@ -1,26 +1,11 @@
# Bracket Style Options
--style=kr
# Tab Options
--indent=spaces=4
# Indentation Options
--indent-switches
# Padding Options
--pad-header
--break-blocks
--pad-oper
--unpad-paren
--align-pointer=name
--align-reference=name
# Formatting Options
--add-brackets
--convert-tabs
--max-code-length=120
# Other Options
--preserve-date
--formatted
--lineend=linux
--pad-header
--max-code-length=120
--convert-tabs
--indent-switches
--pad-oper
--align-pointer=name
--align-reference=name
--preserve-date
--lineend=linux
--break-blocks

View File

@ -1,5 +1,5 @@
# Variables for audio call support
AUDIO_LIBS = openal
AUDIO_LIBS = libtoxav openal
AUDIO_CFLAGS = -DAUDIO
ifneq (, $(findstring audio_device.o, $(OBJ)))
AUDIO_OBJ = audio_call.o
@ -18,4 +18,4 @@ else ifneq ($(MAKECMDGOALS), clean)
$(warning WARNING -- Toxic will be compiled without audio support)
$(warning WARNING -- You need these libraries for audio support)
$(warning WARNING -- $(MISSING_AUDIO_LIBS))
endif
endif

View File

@ -13,7 +13,7 @@ ifneq ($(AUDIO), disabled)
endif
# Check if we want build video support
VIDEO = $(shell if [ -z "$(DISABLE_VI)" ] || [ "$(DISABLE_VI)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
VIDEO = $(shell if [ -z "$(DISABLE_AV)" ] || [ "$(DISABLE_AV)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
ifneq ($(X11), disabled)
ifneq ($(AUDIO), disabled)
ifneq ($(VIDEO), disabled)
@ -34,24 +34,12 @@ ifneq ($(DESK_NOTIFY), disabled)
-include $(CHECKS_DIR)/desktop_notifications.mk
endif
# Check if we want build QR export support
QR_CODE = $(shell if [ -z "$(DISABLE_QRCODE)" ] || [ "$(DISABLE_QRCODE)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
ifneq ($(QR_CODE), disabled)
-include $(CHECKS_DIR)/qr.mk
endif
# Check if we want build QR exported as PNG support
QR_PNG = $(shell if [ -z "$(DISABLE_QRPNG)" ] || [ "$(DISABLE_QRPNG)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
ifneq ($(QR_PNG), disabled)
-include $(CHECKS_DIR)/qr_png.mk
endif
# Check if we want build Python scripting support
PYTHON = $(shell if [ -z "$(ENABLE_PYTHON)" ] || [ "$(ENABLE_PYTHON)" = "0" ] ; then echo disabled ; else echo enabled ; fi)
ifneq ($(PYTHON), disabled)
-include $(CHECKS_DIR)/python.mk
endif
# Check if we can build Toxic
CHECK_LIBS = $(shell $(PKG_CONFIG) --exists $(LIBS) || echo -n "error")
ifneq ($(CHECK_LIBS), error)

View File

@ -1,15 +0,0 @@
# Variables for Python scripting support
PYTHON3_LIBS = python3
PYTHON_CFLAGS = -DPYTHON
PYTHON_OBJ = api.o python_api.o
# Check if we can build Python scripting support
CHECK_PYTHON3_LIBS = $(shell $(PKG_CONFIG) --exists $(PYTHON3_LIBS) || echo -n "error")
ifneq ($(CHECK_PYTHON3_LIBS), error)
LDFLAGS += $(shell python3-config --ldflags)
CFLAGS += $(PYTHON_CFLAGS) $(shell python3-config --includes)
OBJ += $(PYTHON_OBJ)
else ifneq ($(MAKECMDGOALS), clean)
$(warning WARNING -- Toxic will be compiled without Python scripting support)
$(warning WARNING -- You need python3 installed for Python scripting support)
endif

View File

@ -1,15 +0,0 @@
# Variables for QR export support
QR_LIBS = libqrencode
QR_CFLAGS = -DQRCODE
# Check if we can build QR export support
CHECK_QR_LIBS = $(shell pkg-config --exists $(QR_LIBS) || echo -n "error")
ifneq ($(CHECK_QR_LIBS), error)
LIBS += $(QR_LIBS)
CFLAGS += $(QR_CFLAGS)
else ifneq ($(MAKECMDGOALS), clean)
MISSING_QR_LIBS = $(shell for lib in $(QR_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
$(warning WARNING -- Toxic will be compiled without QR export support)
$(warning WARNING -- You need these libraries for QR export support)
$(warning WARNING -- $(MISSING_QR_LIBS))
endif

View File

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

View File

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

View File

@ -6,7 +6,7 @@ PKG_CONFIG_PATH = $(shell export PKG_CONFIG_PATH=/usr/lib/pkgconfig:/usr/local/o
LIBS := $(filter-out ncursesw, $(LIBS))
# OS X ships a usable, recent version of ncurses, but calls it ncurses not ncursesw.
LDFLAGS += -lncurses -lalut -ltoxcore -lcurl -lconfig -lqrencode -lpng -lopenal -g
LDFLAGS += -lncurses -lalut -ltoxav -ltoxcore -lcurl -lconfig -ltoxencryptsave -g
CFLAGS += -I/usr/local/opt/freealut/include/AL -I/usr/local/opt/glib/include/glib-2.0 -g
OSX_LIBRARIES = -lobjc -lresolv

4
cfg/systems/FreeBSD.mk Normal file
View File

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

4
cfg/systems/Linux.mk Normal file
View File

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

View File

@ -14,22 +14,10 @@ help:
@echo " DISABLE_AV: Set to \"1\" to force building without audio call support"
@echo " DISABLE_SOUND_NOTIFY: Set to \"1\" to force building without sound notification support"
@echo " DISABLE_DESKTOP_NOTIFY: Set to \"1\" to force building without desktop notifications support"
@echo " DISABLE_QRCODE: Set to \"1\" to force building without QR export support"
@echo " DISABLE_QRPNG: Set to \"1\" to force building without QR exported as PNG support"
@echo " ENABLE_PYTHON: Set to \"1\" to enable building with Python scripting support"
@echo " USER_CFLAGS: Add custom flags to default CFLAGS"
@echo " USER_LDFLAGS: Add custom flags to default LDFLAGS"
@echo " PREFIX: Specify a prefix directory for binaries, data files,... (default is \"$(abspath $(PREFIX))\")"
@echo " DESTDIR: Specify a directory where to store installed files (mainly for packaging purpose)"
@echo " MANDIR: Specify a directory where to store man pages (default is \"$(abspath $(PREFIX)/share/man)\")"
@echo
@echo "-- Environment Variables --"
@echo " CFLAGS: Add custom flags to default CFLAGS"
@echo " LDFLAGS: Add custom flags to default LDFLAGS"
@echo " USER_CFLAGS: Add custom flags to default CFLAGS"
@echo " USER_LDFLAGS: Add custom flags to default LDFLAGS"
@echo " PREFIX: Specify a prefix directory for binaries, data files,... (default is \"$(abspath $(PREFIX))\")"
@echo " DESTDIR: Specify a directory where to store installed files (mainly for packaging purpose)"
@echo " MANDIR: Specify a directory where to store man pages (default is \"$(abspath $(PREFIX)/share/man)\")"
.PHONY: help

View File

@ -27,7 +27,7 @@ install: $(BUILD_DIR)/toxic
if [ ! -e "$(DOC_DIR)/$$f" ]; then \
continue ;\
fi ;\
section=$(abspath $(DESTDIR)/$(MANDIR))/man`echo $${f##*.}` ;\
section=$(abspath $(DESTDIR)/$(MANDIR))/man`echo $$f | rev | cut -d "." -f 1` ;\
file=$$section/$$f ;\
mkdir -p $$section ;\
install -m 0644 $(DOC_DIR)/$$f $$file ;\
@ -35,7 +35,7 @@ install: $(BUILD_DIR)/toxic
mv temp_file $$file ;\
sed -e 's:__DATADIR__:'$(abspath $(DATADIR))':g' $$file > temp_file && \
mv temp_file $$file ;\
gzip -f -n -9 $$file ;\
gzip -f -9 $$file ;\
done
.PHONY: install

View File

@ -16,7 +16,7 @@ uninstall:
@echo "Removing man pages"
@for f in $(MANFILES) ; do \
section=$(abspath $(DESTDIR)/$(MANDIR))/man`echo $${f##*.}` ;\
section=$(abspath $(DESTDIR)/$(MANDIR))/man`echo $$f | rev | cut -d "." -f 1` ;\
file=$$section/$$f ;\
rm -f $$file $$file.gz ;\
done

View File

@ -1,13 +1,13 @@
'\" t
.\" Title: toxic.conf
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
.\" Date: 2016-09-20
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
.\" Date: 2016-07-21
.\" Manual: Toxic Manual
.\" Source: toxic __VERSION__
.\" Language: English
.\"
.TH "TOXIC\&.CONF" "5" "2016\-09\-20" "toxic __VERSION__" "Toxic Manual"
.TH "TOXIC\&.CONF" "5" "2016\-07\-21" "toxic __VERSION__" "Toxic Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@ -148,6 +148,11 @@ Indicator for alert messages\&.
Indicator for normal messages\&.
.RE
.PP
\fBline_special\fR
.RS 4
Indicator for special messages\&.
.RE
.PP
\fBmplex_away\fR
.RS 4
Set user status when attaching and detaching from GNU screen or tmux\&. true or false
@ -227,11 +232,6 @@ Default path for downloads\&. String value\&. Absolute path for downloaded files
Path for your avatar (file must be a \&.png and cannot exceed 16\&.3 KiB)
.RE
.PP
\fBautorun_path\fR
.RS 4
Path for any scripts that should be run on startup
.RE
.PP
\fBchatlogs_path\fR
.RS 4
Default path for chatlogs\&. String value\&. Absolute path for chatlog files\&.

View File

@ -94,6 +94,9 @@ OPTIONS
*line_normal*;;
Indicator for normal messages.
*line_special*;;
Indicator for special messages.
*mplex_away*;;
Set user status when attaching and detaching from GNU screen or tmux.
true or false
@ -143,9 +146,6 @@ OPTIONS
*avatar_path*;;
Path for your avatar (file must be a .png and cannot exceed 16.3 KiB)
*autorun_path*;;
Path for any scripts that should be run on startup
*chatlogs_path*;;
Default path for chatlogs. String value. Absolute path for chatlog files.

View File

@ -62,6 +62,9 @@ ui = {
// Indicator for normal messages.
line_normal="---";
// Indicator for special messages (currently only used for private group messages)
line_special=">>>";
// true to change status based on screen/tmux attach/detach, false to disable
mplex_away=true;
@ -87,9 +90,6 @@ tox = {
// Path for your avatar (file must be a .png and cannot exceed 64 KiB)
// avatar_path="/home/USERNAME/Pictures/youravatar.png";
// Path for scripts that should be run on startup
// autorun_path="/home/USERNAME/toxic_scripts/";
// Path for chatlogs
// chatlogs_path="/home/USERNAME/toxic_chatlogs/";
};
@ -121,3 +121,4 @@ keys = {
toggle_peerlist="Ctrl+b";
toggle_paste_mode="Ctrl+T";
};

219
src/api.c
View File

@ -1,219 +0,0 @@
/* api.c
*
*
* Copyright (C) 2017 Jakob Kreuze <jakob@memeware.net>
*
* This file is part of Toxic.
*
* Toxic is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Toxic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <dirent.h>
#include <stdint.h>
#include <tox/tox.h>
#include "execute.h"
#include "friendlist.h"
#include "line_info.h"
#include "message_queue.h"
#include "misc_tools.h"
#include "settings.h"
#include "toxic_strings.h"
#include "windows.h"
#ifdef PYTHON
#include "python_api.h"
Tox *user_tox;
static WINDOW *cur_window;
static ToxWindow *self_window;
extern FriendsList Friends;
extern struct user_settings *user_settings;
void api_display(const char *const msg)
{
if (msg == NULL) {
return;
}
self_window = get_active_window();
line_info_add(self_window, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
}
FriendsList api_get_friendslist(void)
{
return Friends;
}
char *api_get_nick(void)
{
size_t len = tox_self_get_name_size(user_tox);
uint8_t *name = malloc(len + 1);
if (name == NULL) {
return NULL;
}
tox_self_get_name(user_tox, name);
name[len] = '\0';
return (char *) name;
}
Tox_User_Status api_get_status(void)
{
return tox_self_get_status(user_tox);
}
char *api_get_status_message(void)
{
size_t len = tox_self_get_status_message_size(user_tox);
uint8_t *status = malloc(len + 1);
if (status == NULL) {
return NULL;
}
tox_self_get_status_message(user_tox, status);
status[len] = '\0';
return (char *) status;
}
void api_send(const char *msg)
{
if (msg == NULL || self_window->chatwin->cqueue == NULL) {
return;
}
char *name = api_get_nick();
char timefrmt[TIME_STR_SIZE];
if (name == NULL) {
return;
}
self_window = get_active_window();
get_time_str(timefrmt, sizeof(timefrmt));
strncpy((char *) self_window->chatwin->line, msg, sizeof(self_window->chatwin->line));
add_line_to_hist(self_window->chatwin);
int id = line_info_add(self_window, timefrmt, name, NULL, OUT_MSG, 0, 0, "%s", msg);
cqueue_add(self_window->chatwin->cqueue, msg, strlen(msg), OUT_MSG, id);
free(name);
}
void api_execute(const char *input, int mode)
{
self_window = get_active_window();
execute(cur_window, self_window, user_tox, input, mode);
}
int do_plugin_command(int num_args, char (*args)[MAX_STR_SIZE])
{
return do_python_command(num_args, args);
}
int num_registered_handlers(void)
{
return python_num_registered_handlers();
}
int help_max_width(void)
{
return python_help_max_width();
}
void draw_handler_help(WINDOW *win)
{
python_draw_handler_help(win);
}
void cmd_run(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
FILE *fp;
const char *error_str;
cur_window = window;
self_window = self;
if (argc != 1) {
if (argc < 1) {
error_str = "Path must be specified.";
} else {
error_str = "Only one argument allowed.";
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, error_str);
return;
}
fp = fopen(argv[1], "r");
if (fp == NULL) {
error_str = "Path does not exist.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, error_str);
return;
}
run_python(fp, argv[1]);
fclose(fp);
}
void invoke_autoruns(WINDOW *window, ToxWindow *self)
{
struct dirent *dir;
char abspath_buf[PATH_MAX + 1], err_buf[PATH_MAX + 1];
size_t path_len;
DIR *d;
FILE *fp;
if (user_settings->autorun_path[0] == '\0') {
return;
}
d = opendir(user_settings->autorun_path);
if (d == NULL) {
snprintf(err_buf, PATH_MAX + 1, "Autorun path does not exist: %s", user_settings->autorun_path);
api_display(err_buf);
return;
}
cur_window = window;
self_window = self;
while ((dir = readdir(d)) != NULL) {
path_len = strlen(dir->d_name);
if (!strcmp(dir->d_name + path_len - 3, ".py")) {
snprintf(abspath_buf, PATH_MAX + 1, "%s%s", user_settings->autorun_path, dir->d_name);
fp = fopen(abspath_buf, "r");
if (fp == NULL) {
snprintf(err_buf, PATH_MAX + 1, "Invalid path: %s", abspath_buf);
api_display(err_buf);
continue;
}
run_python(fp, abspath_buf);
fclose(fp);
}
}
closedir(d);
}
#endif /* PYTHON */

View File

@ -1,43 +0,0 @@
/* api.h
*
*
* Copyright (C) 2017 Jakob Kreuze <jakob@memeware.net>
*
* This file is part of Toxic.
*
* Toxic is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Toxic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef API_H
#define API_H
#include "friendlist.h"
#include "windows.h"
void api_display(const char *const msg);
FriendsList api_get_friendslist(void);
char *api_get_nick(void);
Tox_User_Status api_get_status(void);
char *api_get_status_message(void);
void api_send(const char *msg);
void api_execute(const char *input, int mode);
int do_plugin_command(int num_args, char (*args)[MAX_STR_SIZE]);
int num_registered_handlers(void);
int help_max_width(void);
void draw_handler_help(WINDOW *win);
void invoke_autoruns(WINDOW *w, ToxWindow *self);
void cmd_run(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
#endif /* API_H */

File diff suppressed because it is too large Load Diff

View File

@ -27,6 +27,8 @@
#include "audio_device.h"
#define MAX_CALLS 10
typedef enum _AudioError {
ae_None = 0,
ae_StartingCaptureDevice = 1 << 0,
@ -63,9 +65,7 @@ struct CallControl {
ToxAV *av;
ToxWindow *prompt;
Call *calls;
uint32_t max_calls;
Call calls[MAX_CALLS];
uint32_t call_state;
bool pending_call;
bool audio_enabled;
@ -79,17 +79,15 @@ struct CallControl {
uint32_t video_bit_rate;
int32_t video_frame_duration;
};
} CallControl;
extern struct CallControl CallControl;
struct CallControl CallControl;
/* You will have to pass pointer to first member of 'windows' declared in windows.c */
ToxAV *init_audio(ToxWindow *self, Tox *tox);
void terminate_audio(void);
void terminate_audio();
int start_transmission(ToxWindow *self, Call *call);
int stop_transmission(Call *call, uint32_t friend_number);
void stop_current_call(ToxWindow *self);
void init_friend_AV(uint32_t index);
void del_friend_AV(uint32_t index);
#endif /* AUDIO_CALL_H */

View File

@ -38,8 +38,8 @@
/* compatibility with older versions of OpenAL */
#ifndef ALC_ALL_DEVICES_SPECIFIER
#include <AL/alext.h>
#endif /* ALC_ALL_DEVICES_SPECIFIER */
#endif /* __APPLE__ */
#endif /* ALC_ALL_DEVICES_SPECIFIER */
#endif /* __APPLE__ */
#include <stdbool.h>
#include <string.h>
@ -97,21 +97,46 @@ void *thread_poll(void *);
#ifdef AUDIO
DeviceError init_devices(ToxAV *av_)
#else
DeviceError init_devices(void)
DeviceError init_devices()
#endif /* AUDIO */
{
get_devices_names();
const char *stringed_device_list;
size[input] = 0;
if ( (stringed_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER)) ) {
ddevice_names[input] = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
for ( ; *stringed_device_list && size[input] < MAX_DEVICES; ++size[input] ) {
devices_names[input][size[input]] = stringed_device_list;
stringed_device_list += strlen( stringed_device_list ) + 1;
}
}
size[output] = 0;
if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE)
stringed_device_list = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
else
stringed_device_list = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
if (stringed_device_list) {
ddevice_names[output] = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
for ( ; *stringed_device_list && size[output] < MAX_DEVICES; ++size[output] ) {
devices_names[output][size[output]] = stringed_device_list;
stringed_device_list += strlen( stringed_device_list ) + 1;
}
}
// Start poll thread
if (pthread_mutex_init(&mutex, NULL) != 0) {
if (pthread_mutex_init(&mutex, NULL) != 0)
return de_InternalError;
}
pthread_t thread_id;
if (pthread_create(&thread_id, NULL, thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0) {
if ( pthread_create(&thread_id, NULL, thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0)
return de_InternalError;
}
#ifdef AUDIO
av = av_;
@ -120,7 +145,7 @@ DeviceError init_devices(void)
return (DeviceError) de_None;
}
DeviceError terminate_devices(void)
DeviceError terminate_devices()
{
/* Cleanup if needed */
lock;
@ -129,52 +154,15 @@ DeviceError terminate_devices(void)
usleep(20000);
if (pthread_mutex_destroy(&mutex) != 0) {
if (pthread_mutex_destroy(&mutex) != 0)
return (DeviceError) de_InternalError;
}
return (DeviceError) de_None;
}
void get_devices_names(void)
{
const char *stringed_device_list;
size[input] = 0;
if ((stringed_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER))) {
ddevice_names[input] = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
for (; *stringed_device_list && size[input] < MAX_DEVICES; ++size[input]) {
devices_names[input][size[input]] = stringed_device_list;
stringed_device_list += strlen(stringed_device_list) + 1;
}
}
size[output] = 0;
if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE) {
stringed_device_list = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
} else {
stringed_device_list = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
}
if (stringed_device_list) {
ddevice_names[output] = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
for (; *stringed_device_list && size[output] < MAX_DEVICES; ++size[output]) {
devices_names[output][size[output]] = stringed_device_list;
stringed_device_list += strlen(stringed_device_list) + 1;
}
}
}
DeviceError device_mute(DeviceType type, uint32_t device_idx)
{
if (device_idx >= MAX_DEVICES) {
return de_InvalidSelection;
}
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
lock;
@ -194,9 +182,7 @@ DeviceError device_mute(DeviceType type, uint32_t device_idx)
#ifdef AUDIO
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
{
if (device_idx >= MAX_DEVICES) {
return de_InvalidSelection;
}
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
lock;
@ -217,9 +203,7 @@ DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
DeviceError set_primary_device(DeviceType type, int32_t selection)
{
if (size[type] <= selection || selection < 0) {
return de_InvalidSelection;
}
if (size[type] <= selection || selection < 0) return de_InvalidSelection;
primary_device[type] = selection;
@ -241,13 +225,9 @@ void get_primary_device_name(DeviceType type, char *buf, int size)
DeviceError open_device(DeviceType type, int32_t selection, uint32_t *device_idx, uint32_t sample_rate,
uint32_t frame_duration, uint8_t channels)
{
if (size[type] <= selection || selection < 0) {
return de_InvalidSelection;
}
if (size[type] <= selection || selection < 0) return de_InvalidSelection;
if (channels != 1 && channels != 2) {
return de_UnsupportedMode;
}
if (channels != 1 && channels != 2) return de_UnsupportedMode;
lock;
@ -260,12 +240,10 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t *device_idx
if (i == MAX_DEVICES) {
unlock;
return de_AllDevicesBusy;
} else {
*device_idx = i;
}
} else *device_idx = i;
for (i = 0; i < MAX_DEVICES; i ++) { /* Check if any device has the same selection */
if (running[type][i] && running[type][i]->selection == selection) {
if ( running[type][i] && running[type][i]->selection == selection ) {
// printf("a%d-%d:%p ", selection, i, running[type][i]->dhndl);
running[type][*device_idx] = running[type][i];
@ -298,7 +276,7 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t *device_idx
} else {
device->dhndl = alcOpenDevice(devices_names[type][selection]);
if (!device->dhndl) {
if ( !device->dhndl ) {
free(device);
running[type][*device_idx] = NULL;
unlock;
@ -315,7 +293,7 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t *device_idx
uint16_t zeros[frame_size];
memset(zeros, 0, frame_size * 2);
for (i = 0; i < OPENAL_BUFS; ++i) {
for ( i = 0; i < OPENAL_BUFS; ++i ) {
alBufferData(device->buffers[i], device->sound_mode, zeros, frame_size * 2, sample_rate);
}
@ -341,9 +319,7 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t *device_idx
DeviceError close_device(DeviceType type, uint32_t device_idx)
{
if (device_idx >= MAX_DEVICES) {
return de_InvalidSelection;
}
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
lock;
Device *device = running[type][device_idx];
@ -356,45 +332,34 @@ DeviceError close_device(DeviceType type, uint32_t device_idx)
running[type][device_idx] = NULL;
if (!device->ref_count) {
if ( !device->ref_count ) {
if (type == input) {
if (!alcCaptureCloseDevice(device->dhndl)) {
rc = de_AlError;
}
if ( !alcCaptureCloseDevice(device->dhndl) ) rc = de_AlError;
} else {
if (alcGetCurrentContext() != device->ctx) {
alcMakeContextCurrent(device->ctx);
}
if (alcGetCurrentContext() != device->ctx) alcMakeContextCurrent(device->ctx);
alDeleteSources(1, &device->source);
alDeleteBuffers(OPENAL_BUFS, device->buffers);
alcMakeContextCurrent(NULL);
if (device->ctx) {
alcDestroyContext(device->ctx);
}
if ( device->ctx ) alcDestroyContext(device->ctx);
if (!alcCloseDevice(device->dhndl)) {
rc = de_AlError;
}
if ( !alcCloseDevice(device->dhndl) ) rc = de_AlError;
}
free(device);
} else {
device->ref_count--;
}
} else device->ref_count--;
unlock;
return rc;
}
DeviceError register_device_callback(int32_t friend_number, uint32_t device_idx, DataHandleCallback callback,
void *data, bool enable_VAD)
DeviceError register_device_callback( int32_t friend_number, uint32_t device_idx, DataHandleCallback callback,
void *data, bool enable_VAD)
{
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL) {
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
return de_InvalidSelection;
}
lock;
running[input][device_idx]->cb = callback;
@ -409,15 +374,11 @@ DeviceError register_device_callback(int32_t friend_number, uint32_t device_idx,
inline__ DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_t sample_count, uint8_t channels,
uint32_t sample_rate)
{
if (device_idx >= MAX_DEVICES) {
return de_InvalidSelection;
}
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
Device *device = running[output][device_idx];
if (!device || device->muted) {
return de_DeviceNotActive;
}
if (!device || device->muted) return de_DeviceNotActive;
pthread_mutex_lock(device->mutex);
@ -432,9 +393,8 @@ inline__ DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_
alSourceUnqueueBuffers(device->source, processed, bufids);
alDeleteBuffers(processed - 1, bufids + 1);
bufid = bufids[0];
} else if (queued < 16) {
alGenBuffers(1, &bufid);
} else {
} else if (queued < 16) alGenBuffers(1, &bufid);
else {
pthread_mutex_unlock(device->mutex);
return de_Busy;
}
@ -447,16 +407,14 @@ inline__ DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_
ALint state;
alGetSourcei(device->source, AL_SOURCE_STATE, &state);
if (state != AL_PLAYING) {
alSourcePlay(device->source);
}
if (state != AL_PLAYING) alSourcePlay(device->source);
pthread_mutex_unlock(device->mutex);
return de_None;
}
void *thread_poll(void *arg) // TODO: maybe use thread for every input source
void *thread_poll (void *arg) // TODO: maybe use thread for every input source
{
/*
* NOTE: We only need to poll input devices for data.
@ -506,9 +464,7 @@ void *thread_poll(void *arg) // TODO: maybe use thread for every input source
continue;
}
if (device->cb) {
device->cb(frame, f_size, device->cb_data);
}
if ( device->cb ) device->cb(frame, f_size, device->cb_data);
}
unlock;
@ -525,10 +481,8 @@ void print_devices(ToxWindow *self, DeviceType type)
{
int i;
for (i = 0; i < size[type]; ++i) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, i == primary_device[type] ? 1 : 0, 0, "%d: %s", i,
devices_names[type][i]);
}
for (i = 0; i < size[type]; ++i)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%d: %s", i, devices_names[type][i]);
return;
}
@ -540,9 +494,8 @@ DeviceError selection_valid(DeviceType type, int32_t selection)
void *get_device_callback_data(uint32_t device_idx)
{
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL) {
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
return NULL;
}
return running[input][device_idx]->cb_data;
}

View File

@ -52,17 +52,16 @@ typedef enum DeviceError {
de_AlError = -9,
} DeviceError;
typedef void (*DataHandleCallback)(const int16_t *, uint32_t size, void *data);
typedef void (*DataHandleCallback) (const int16_t *, uint32_t size, void *data);
#ifdef AUDIO
DeviceError init_devices(ToxAV *av);
#else
DeviceError init_devices(void);
DeviceError init_devices();
#endif /* AUDIO */
void get_devices_names(void);
DeviceError terminate_devices(void);
DeviceError terminate_devices();
/* Callback handles ready data from INPUT device */
DeviceError register_device_callback(int32_t friend_number, uint32_t device_idx, DataHandleCallback callback,

View File

@ -29,7 +29,7 @@
#include <sys/dir.h>
#else
#include <dirent.h>
#endif /* __APPLE__ */
#endif /* ifdef __APPLE__ */
#include "windows.h"
#include "toxic.h"
@ -38,18 +38,16 @@
#include "execute.h"
#include "configdir.h"
static void print_matches(ToxWindow *self, Tox *m, const void *list, size_t n_items, size_t size)
static void print_matches(ToxWindow *self, Tox *m, const void *list, int n_items, int size)
{
if (m) {
if (m)
execute(self->chatwin->history, self, m, "/clear", GLOBAL_COMMAND_MODE);
}
const char *L = (char *) list;
int i;
for (i = 0; i < n_items; ++i) {
for (i = 0; i < n_items; ++i)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", &L[i * size]);
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); /* formatting */
}
@ -85,60 +83,49 @@ static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, char
return snprintf(match, match_sz, "%s", matches[0]);
}
/*
* Looks for all instances in list that begin with the last entered word in line according to pos,
* then fills line with the complete word. e.g. "Hello jo" would complete the line
* with "Hello john". If multiple matches, prints out all the matches and semi-completes line.
*
* list is a pointer to the list of strings being compared, n_items is the number of items
* in the list, and size is the size of each item in the list.
*
* dir_search should be true if the line being completed is a file path.
*
* Returns the difference between the old len and new len of line on success.
* Returns -1 on error.
*
* Note: This function should not be called directly. Use complete_line() and complete_path() instead.
*/
static int complete_line_helper(ToxWindow *self, const void *list, size_t n_items, size_t size, bool dir_search)
/* looks for all instances in list that begin with the last entered word in line according to pos,
then fills line with the complete word. e.g. "Hello jo" would complete the line
with "Hello john". If multiple matches, prints out all the matches and semi-completes line.
list is a pointer to the list of strings being compared, n_items is the number of items
in the list, and size is the size of each item in the list.
Returns the difference between the old len and new len of line on success, -1 if error */
int complete_line(ToxWindow *self, const void *list, int n_items, int size)
{
ChatContext *ctx = self->chatwin;
if (ctx->pos <= 0 || ctx->len <= 0 || ctx->pos > ctx->len) {
if (ctx->pos <= 0 || ctx->len <= 0 || ctx->pos > ctx->len || ctx->len >= MAX_STR_SIZE || size > MAX_STR_SIZE)
return -1;
}
if (ctx->len >= MAX_STR_SIZE || size > MAX_STR_SIZE) {
return -1;
}
const char *L = (const char *) list;
const char *L = (char *) list;
const char *endchrs = " ";
char ubuf[MAX_STR_SIZE] = {0};
char ubuf[MAX_STR_SIZE];
/* work with multibyte string copy of buf for simplicity */
if (wcs_to_mbs_buf(ubuf, ctx->line, sizeof(ubuf)) == -1) {
if (wcs_to_mbs_buf(ubuf, ctx->line, sizeof(ubuf)) == -1)
return -1;
}
/* TODO: generalize this */
bool dir_search = !strncmp(ubuf, "/sendfile", strlen("/sendfile"))
|| !strncmp(ubuf, "/avatar", strlen("/avatar"));
/* isolate substring from space behind pos to pos */
char tmp[MAX_STR_SIZE];
snprintf(tmp, sizeof(tmp), "%s", ubuf);
tmp[ctx->pos] = '\0';
const char *s = strrchr(tmp, ' ');
const char *s = dir_search ? strchr(tmp, '\"') : strrchr(tmp, ' ');
char *sub = calloc(1, strlen(ubuf) + 1);
if (sub == NULL) {
exit_toxic_err("failed in complete_line_helper", FATALERR_MEMORY);
}
if (sub == NULL)
exit_toxic_err("failed in complete_line", FATALERR_MEMORY);
if (!s && !dir_search) {
strcpy(sub, tmp);
if (sub[0] != '/') {
if (sub[0] != '/')
endchrs = ": ";
}
} else if (s) {
strcpy(sub, &s[1]);
@ -146,19 +133,18 @@ static int complete_line_helper(ToxWindow *self, const void *list, size_t n_item
int sub_len = strlen(sub);
int si = char_rfind(sub, '/', sub_len);
if (si || *sub == '/') {
if (si || *sub == '/')
memmove(sub, &sub[si + 1], sub_len - si);
}
}
}
if (!sub[0]) {
free(sub);
return 0;
return -1;
}
int s_len = strlen(sub);
size_t n_matches = 0;
int n_matches = 0;
char matches[n_items][MAX_STR_SIZE];
int i = 0;
@ -167,20 +153,17 @@ static int complete_line_helper(ToxWindow *self, const void *list, size_t n_item
char str[MAX_CMDNAME_SIZE + 1];
snprintf(str, sizeof(str), "%s", &L[i * size]);
if (strncasecmp(str, sub, s_len) == 0) {
if (strncasecmp(str, sub, s_len) == 0)
strcpy(matches[n_matches++], str);
}
}
free(sub);
if (!n_matches) {
if (!n_matches)
return -1;
}
if (!dir_search && n_matches > 1) {
if (!dir_search && n_matches > 1)
print_matches(self, NULL, matches, n_matches, MAX_STR_SIZE);
}
char match[MAX_STR_SIZE];
size_t match_len = get_str_match(self, match, sizeof(match), matches, n_matches);
@ -190,11 +173,10 @@ static int complete_line_helper(ToxWindow *self, const void *list, size_t n_item
}
if (dir_search) {
if (n_matches == 1) {
endchrs = char_rfind(match, '.', match_len) ? "" : "/";
} else {
if (n_matches == 1)
endchrs = char_rfind(match, '.', match_len) ? "\"" : "/";
else
endchrs = "";
}
} else if (n_matches > 1) {
endchrs = "";
}
@ -204,9 +186,8 @@ static int complete_line_helper(ToxWindow *self, const void *list, size_t n_item
int strt = ctx->pos - s_len;
int diff = match_len - s_len + n_endchrs;
if (ctx->len + diff >= MAX_STR_SIZE) {
if (ctx->len + diff >= MAX_STR_SIZE)
return -1;
}
char tmpend[MAX_STR_SIZE];
snprintf(tmpend, sizeof(tmpend), "%s", &ubuf[ctx->pos]);
@ -216,21 +197,6 @@ static int complete_line_helper(ToxWindow *self, const void *list, size_t n_item
}
strcpy(&ubuf[strt], match);
/* If path points to a file with no extension don't append a forward slash */
if (dir_search && *endchrs == '/') {
const char *path_start = strchr(ubuf+1, '/');
if (!path_start) { // should never happen
return -1;
}
if (file_type(path_start) == FILE_TYPE_REGULAR) {
endchrs = "";
diff -= n_endchrs;
}
}
strcpy(&ubuf[strt + match_len], endchrs);
strcpy(&ubuf[strt + match_len + n_endchrs], tmpend);
@ -249,18 +215,8 @@ static int complete_line_helper(ToxWindow *self, const void *list, size_t n_item
return diff;
}
int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size)
{
return complete_line_helper(self, list, n_items, size, false);
}
static int complete_path(ToxWindow *self, const void *list, size_t n_items, size_t size)
{
return complete_line_helper(self, list, n_items, size, true);
}
/* Transforms a tab complete starting with the shorthand "~" into the full home directory. */
static void complete_home_dir(ToxWindow *self, char *path, int pathsize, const char *cmd, int cmdlen)
/* transforms a tab complete starting with the shorthand "~" into the full home directory.*/
static void complt_home_dir(ToxWindow *self, char *path, int pathsize, const char *cmd, int cmdlen)
{
ChatContext *ctx = self->chatwin;
@ -268,51 +224,45 @@ static void complete_home_dir(ToxWindow *self, char *path, int pathsize, const c
get_home_dir(homedir, sizeof(homedir));
char newline[MAX_STR_SIZE];
snprintf(newline, sizeof(newline), "%s %s%s", cmd, homedir, path + 1);
snprintf(path, pathsize, "%s", &newline[cmdlen-1]);
snprintf(newline, sizeof(newline), "%s \"%s%s", cmd, homedir, path + 1);
snprintf(path, pathsize, "%s", &newline[cmdlen]);
wchar_t wline[MAX_STR_SIZE];
if (mbs_to_wcs_buf(wline, newline, sizeof(wline) / sizeof(wchar_t)) == -1) {
if (mbs_to_wcs_buf(wline, newline, sizeof(wline) / sizeof(wchar_t)) == -1)
return;
}
int newlen = wcslen(wline);
if (ctx->len + newlen >= MAX_STR_SIZE) {
if (ctx->len + newlen >= MAX_STR_SIZE)
return;
}
wmemcpy(ctx->line, wline, newlen + 1);
ctx->pos = newlen;
ctx->len = ctx->pos;
}
/* Attempts to match /command "<incomplete-dir>" line to matching directories.
* If there is only one match the line is auto-completed.
*
* Returns the diff between old len and new len of ctx->line on success.
* Returns -1 if no matches or more than one match.
*/
/* attempts to match /command "<incomplete-dir>" line to matching directories.
if only one match, auto-complete line.
return diff between old len and new len of ctx->line, -1 if no matches or > 1 match */
#define MAX_DIRS 512
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
{
char b_path[MAX_STR_SIZE];
char b_name[MAX_STR_SIZE];
char b_cmd[MAX_STR_SIZE];
const wchar_t *tmpline = &line[wcslen(cmd) + 1]; /* start after "/command " */
const wchar_t *tmpline = &line[wcslen(cmd) + 2]; /* start after "/command \"" */
if (wcs_to_mbs_buf(b_path, tmpline, sizeof(b_path)) == -1) {
if (wcs_to_mbs_buf(b_path, tmpline, sizeof(b_path)) == -1)
return -1;
}
if (wcs_to_mbs_buf(b_cmd, cmd, sizeof(b_cmd)) == -1) {
if (wcs_to_mbs_buf(b_cmd, cmd, sizeof(b_cmd)) == -1)
return -1;
}
if (b_path[0] == '~') {
complete_home_dir(self, b_path, sizeof(b_path), b_cmd, strlen(b_cmd) + 2);
}
if (b_path[0] == '~')
complt_home_dir(self, b_path, sizeof(b_path), b_cmd, strlen(b_cmd) + 2);
int si = char_rfind(b_path, '/', strlen(b_path));
@ -330,11 +280,10 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
int b_name_len = strlen(b_name);
DIR *dp = opendir(b_path);
if (dp == NULL) {
if (dp == NULL)
return -1;
}
char dirnames[MAX_DIRS][NAME_MAX + 1];
char dirnames[MAX_DIRS][NAME_MAX];
struct dirent *entry;
int dircount = 0;
@ -348,14 +297,13 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
closedir(dp);
if (dircount == 0) {
if (dircount == 0)
return -1;
}
if (dircount > 1) {
qsort(dirnames, dircount, NAME_MAX + 1, qsort_strcasecmp_hlpr);
print_matches(self, m, dirnames, dircount, NAME_MAX + 1);
qsort(dirnames, dircount, NAME_MAX, qsort_strcasecmp_hlpr);
print_matches(self, m, dirnames, dircount, NAME_MAX);
}
return complete_path(self, dirnames, dircount, NAME_MAX + 1);
return complete_line(self, dirnames, dircount, NAME_MAX);
}

View File

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

View File

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

View File

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

View File

@ -34,7 +34,6 @@
#include "configdir.h"
#include "curl_util.h"
#include "settings.h"
#include "prompt.h"
extern struct arg_opts arg_opts;
extern struct user_settings *user_settings;
@ -109,10 +108,7 @@ static struct DHT_Nodes {
/* Determine if a node is offline by comparing the age of the nodeslist
* to the last time the node was successfully pinged.
*/
static bool node_is_offline(unsigned long long int last_ping)
{
return last_ping + NODE_OFFLINE_TIMOUT <= last_ping;
}
#define NODE_IS_OFFLINE(last_scan, last_ping) ((last_ping + NODE_OFFLINE_TIMOUT) <= (last_ping))
/* Return true if nodeslist pointed to by fp needs to be updated.
* This will be the case if the file is empty, has an invalid format,
@ -381,7 +377,7 @@ static int extract_node(const char *line, struct Node *node)
long long int last_pinged = extract_val_last_pinged(last_pinged_str + LAST_PING_JSON_KEY_LEN);
if (last_pinged <= 0 || node_is_offline(last_pinged)) {
if (last_pinged <= 0 || NODE_IS_OFFLINE(Nodes.last_scan, last_pinged)) {
return -3;
}
@ -481,7 +477,7 @@ void *load_nodeslist_thread(void *data)
/* If nodeslist does not contain any valid entries we set the last_scan value
* to 0 so that it will fetch a new list the next time this function is called.
*/
if (Nodes.count == 0) {
if (idx == 0) {
const char *s = "{\"last_scan\":0}";
rewind(fp);
fwrite(s, strlen(s), 1, fp); // Not much we can do if it fails
@ -560,7 +556,7 @@ static void DHT_bootstrap(Tox *m)
continue;
}
Tox_Err_Bootstrap err;
TOX_ERR_BOOTSTRAP err;
tox_bootstrap(m, addr, node->port, (uint8_t *) node->key, &err);
if (err != TOX_ERR_BOOTSTRAP_OK) {
@ -581,7 +577,7 @@ static void DHT_bootstrap(Tox *m)
void do_tox_connection(Tox *m)
{
static time_t last_bootstrap_time = 0;
bool connected = prompt_selfConnectionStatus() != TOX_CONNECTION_NONE;
bool connected = tox_self_get_connection_status(m) != TOX_CONNECTION_NONE;
if (!connected && timed_out(last_bootstrap_time, TRY_BOOTSTRAP_INTERVAL)) {
DHT_bootstrap(m);

View File

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

View File

@ -51,8 +51,8 @@
#include "audio_call.h"
#ifdef VIDEO
#include "video_call.h"
#endif /* VIDEO */
#endif /* AUDIO */
#endif /* VIDEO */
#endif /* AUDIO */
extern char *DATA_FILE;
extern FriendsList Friends;
@ -63,24 +63,13 @@ extern struct user_settings *user_settings;
#ifdef AUDIO
static void init_infobox(ToxWindow *self);
static void kill_infobox(ToxWindow *self);
#endif /* AUDIO */
#endif /* AUDIO */
#ifdef AUDIO
#define AC_NUM_CHAT_COMMANDS_AUDIO 9
#define AC_NUM_CHAT_COMMANDS 31
#else
#define AC_NUM_CHAT_COMMANDS_AUDIO 0
#define AC_NUM_CHAT_COMMANDS 23
#endif /* AUDIO */
#ifdef PYTHON
#define AC_NUM_CHAT_COMMANDS_PYTHON 1
#else
#define AC_NUM_CHAT_COMMANDS_PYTHON 0
#endif /* PYTHON */
#ifdef QRCODE
#define AC_NUM_CHAT_COMMANDS_QRCODE 1
#else
#define AC_NUM_CHAT_COMMANDS_QRCODE 0
#endif /* QRCODE */
#define AC_NUM_CHAT_COMMANDS (21 + AC_NUM_CHAT_COMMANDS_AUDIO + AC_NUM_CHAT_COMMANDS_PYTHON + AC_NUM_CHAT_COMMANDS_QRCODE)
/* Array of chat command names used for tab completion. */
static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
@ -92,15 +81,14 @@ static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/close" },
{ "/connect" },
{ "/exit" },
{ "/gaccept" },
{ "/group" },
{ "/help" },
{ "/invite" },
{ "/join" },
{ "/log" },
{ "/myid" },
#ifdef QRCODE
{ "/myqr" },
#endif /* QRCODE */
{ "/nick" },
{ "/note" },
{ "/nospam" },
@ -119,22 +107,14 @@ static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/mute" },
{ "/sense" },
{ "/video" },
{ "/bitrate" },
#endif /* AUDIO */
#ifdef PYTHON
{ "/run" },
#endif /* PYTHON */
};
static void set_self_typingstatus(ToxWindow *self, Tox *m, bool is_typing)
{
if (user_settings->show_typing_self == SHOW_TYPING_OFF) {
if (user_settings->show_typing_self == SHOW_TYPING_OFF)
return;
}
ChatContext *ctx = self->chatwin;
@ -150,9 +130,9 @@ void kill_chat_window(ToxWindow *self, Tox *m)
#ifdef AUDIO
#ifdef VIDEO
stop_video_stream(self);
#endif /* VIDEO */
#endif /* VIDEO */
stop_current_call(self);
#endif /* AUDIO */
#endif /* AUDIO */
kill_all_file_transfers_friend(m, self->num);
log_disable(ctx->log);
@ -180,13 +160,12 @@ static void recv_message_helper(ToxWindow *self, Tox *m, uint32_t num, const cha
line_info_add(self, timefrmt, nick, NULL, IN_MSG, 0, 0, "%s", msg);
write_to_log(msg, nick, ctx->log, false);
if (self->active_box != -1) {
if (self->active_box != -1)
box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
self->active_box, "%s", msg);
} else {
else
box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
&self->active_box, nick, "%s", msg);
}
}
static void recv_action_helper(ToxWindow *self, Tox *m, uint32_t num, const char *action, size_t len,
@ -197,20 +176,18 @@ static void recv_action_helper(ToxWindow *self, Tox *m, uint32_t num, const char
line_info_add(self, timefrmt, nick, NULL, IN_ACTION, 0, 0, "%s", action);
write_to_log(action, nick, ctx->log, true);
if (self->active_box != -1) {
if (self->active_box != -1)
box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
self->active_box, "* %s %s", nick, action);
} else {
self->active_box, "* %s %s", nick, action );
else
box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
&self->active_box, self->name, "* %s %s", nick, action);
}
&self->active_box, self->name, "* %s %s", nick, action );
}
static void chat_onMessage(ToxWindow *self, Tox *m, uint32_t num, Tox_Message_Type type, const char *msg, size_t len)
static void chat_onMessage(ToxWindow *self, Tox *m, uint32_t num, TOX_MESSAGE_TYPE type, const char *msg, size_t len)
{
if (self->num != num) {
if (self->num != num)
return;
}
char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, num);
@ -218,25 +195,20 @@ static void chat_onMessage(ToxWindow *self, Tox *m, uint32_t num, Tox_Message_Ty
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
if (type == TOX_MESSAGE_TYPE_NORMAL) {
recv_message_helper(self, m, num, msg, len, nick, timefrmt);
return;
}
if (type == TOX_MESSAGE_TYPE_NORMAL)
return recv_message_helper(self, m, num, msg, len, nick, timefrmt);
if (type == TOX_MESSAGE_TYPE_ACTION) {
recv_action_helper(self, m, num, msg, len, nick, timefrmt);
return;
}
if (type == TOX_MESSAGE_TYPE_ACTION)
return recv_action_helper(self, m, num, msg, len, nick, timefrmt);
}
static void chat_pause_file_transfers(Tox *m, uint32_t friendnum);
static void chat_resume_file_senders(ToxWindow *self, Tox *m, uint32_t fnum);
static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, Tox_Connection connection_status)
static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_CONNECTION connection_status)
{
if (self->num != num) {
if (self->num != num)
return;
}
StatusBar *statusbar = self->stb;
ChatContext *ctx = self->chatwin;
@ -248,7 +220,7 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, Tox_C
char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, num);
Tox_Connection prev_status = statusbar->connection;
TOX_CONNECTION prev_status = statusbar->connection;
statusbar->connection = connection_status;
if (user_settings->show_connection_msg == SHOW_WELCOME_MSG_OFF) {
@ -256,6 +228,8 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, Tox_C
}
if (prev_status == TOX_CONNECTION_NONE) {
Friends.list[num].is_typing = user_settings->show_typing_other == SHOW_TYPING_ON
? tox_friend_get_typing(m, num, NULL) : false;
chat_resume_file_senders(self, m, num);
msg = "has come online";
@ -264,9 +238,8 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, Tox_C
} else if (connection_status == TOX_CONNECTION_NONE) {
Friends.list[num].is_typing = false;
if (self->chatwin->self_is_typing) {
if (self->chatwin->self_is_typing)
set_self_typingstatus(self, m, 0);
}
chat_pause_file_transfers(m, num);
@ -278,18 +251,16 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, Tox_C
static void chat_onTypingChange(ToxWindow *self, Tox *m, uint32_t num, bool is_typing)
{
if (self->num != num) {
if (self->num != num)
return;
}
Friends.list[num].is_typing = is_typing;
}
static void chat_onNickChange(ToxWindow *self, Tox *m, uint32_t num, const char *nick, size_t length)
{
if (self->num != num) {
if (self->num != num)
return;
}
StatusBar *statusbar = self->stb;
@ -300,11 +271,10 @@ static void chat_onNickChange(ToxWindow *self, Tox *m, uint32_t num, const char
set_window_title(self, statusbar->nick, length);
}
static void chat_onStatusChange(ToxWindow *self, Tox *m, uint32_t num, Tox_User_Status status)
static void chat_onStatusChange(ToxWindow *self, Tox *m, uint32_t num, TOX_USER_STATUS status)
{
if (self->num != num) {
if (self->num != num)
return;
}
StatusBar *statusbar = self->stb;
statusbar->status = status;
@ -312,9 +282,8 @@ static void chat_onStatusChange(ToxWindow *self, Tox *m, uint32_t num, Tox_User_
static void chat_onStatusMessageChange(ToxWindow *self, uint32_t num, const char *status, size_t length)
{
if (self->num != num) {
if (self->num != num)
return;
}
StatusBar *statusbar = self->stb;
@ -335,13 +304,11 @@ static void chat_pause_file_transfers(Tox *m, uint32_t friendnum)
size_t i;
for (i = 0; i < MAX_FILES; ++i) {
if (friend->file_sender[i].state >= FILE_TRANSFER_STARTED) {
if (friend->file_sender[i].state >= FILE_TRANSFER_STARTED)
friend->file_sender[i].state = FILE_TRANSFER_PAUSED;
}
if (friend->file_receiver[i].state >= FILE_TRANSFER_STARTED) {
if (friend->file_receiver[i].state >= FILE_TRANSFER_STARTED)
friend->file_receiver[i].state = FILE_TRANSFER_PAUSED;
}
}
}
@ -353,11 +320,10 @@ static void chat_resume_file_senders(ToxWindow *self, Tox *m, uint32_t friendnum
for (i = 0; i < MAX_FILES; ++i) {
struct FileTransfer *ft = &Friends.list[friendnum].file_sender[i];
if (ft->state != FILE_TRANSFER_PAUSED) {
if (ft->state != FILE_TRANSFER_PAUSED)
continue;
}
Tox_Err_File_Send err;
TOX_ERR_FILE_SEND err;
ft->filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_DATA, ft->file_size, ft->file_id,
(uint8_t *) ft->file_name, strlen(ft->file_name), &err);
@ -373,19 +339,16 @@ static void chat_resume_file_senders(ToxWindow *self, Tox *m, uint32_t friendnum
static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t position,
size_t length)
{
if (friendnum != self->num) {
if (friendnum != self->num)
return;
}
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
if (!ft) {
if (!ft)
return;
}
if (ft->state != FILE_TRANSFER_STARTED) {
if (ft->state != FILE_TRANSFER_STARTED)
return;
}
char msg[MAX_STR_SIZE];
@ -421,12 +384,11 @@ static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t friendnum,
return;
}
Tox_Err_File_Send_Chunk err;
TOX_ERR_FILE_SEND_CHUNK err;
tox_file_send_chunk(m, ft->friendnum, ft->filenum, position, send_data, send_length, &err);
if (err != TOX_ERR_FILE_SEND_CHUNK_OK) {
if (err != TOX_ERR_FILE_SEND_CHUNK_OK)
fprintf(stderr, "tox_file_send_chunk failed in chat callback (error %d)\n", err);
}
ft->position += send_length;
ft->bps += send_length;
@ -436,19 +398,16 @@ static void chat_onFileChunkRequest(ToxWindow *self, Tox *m, uint32_t friendnum,
static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t position,
const char *data, size_t length)
{
if (friendnum != self->num) {
if (friendnum != self->num)
return;
}
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
if (!ft) {
if (!ft)
return;
}
if (ft->state != FILE_TRANSFER_STARTED) {
if (ft->state != FILE_TRANSFER_STARTED)
return;
}
char msg[MAX_STR_SIZE];
@ -476,17 +435,15 @@ static void chat_onFileRecvChunk(ToxWindow *self, Tox *m, uint32_t friendnum, ui
ft->last_keep_alive = get_unix_time();
}
static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, Tox_File_Control control)
static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, TOX_FILE_CONTROL control)
{
if (friendnum != self->num) {
if (friendnum != self->num)
return;
}
struct FileTransfer *ft = get_file_transfer_struct(friendnum, filenum);
if (!ft) {
if (!ft)
return;
}
char msg[MAX_STR_SIZE];
@ -533,9 +490,8 @@ static bool chat_resume_broken_ft(ToxWindow *self, Tox *m, uint32_t friendnum, u
char msg[MAX_STR_SIZE];
uint8_t file_id[TOX_FILE_ID_LENGTH];
if (!tox_file_get_file_id(m, friendnum, filenum, file_id, NULL)) {
if (!tox_file_get_file_id(m, friendnum, filenum, file_id, NULL))
return false;
}
bool resuming = false;
struct FileTransfer *ft = NULL;
@ -544,9 +500,8 @@ static bool chat_resume_broken_ft(ToxWindow *self, Tox *m, uint32_t friendnum, u
for (i = 0; i < MAX_FILES; ++i) {
ft = &Friends.list[friendnum].file_receiver[i];
if (ft->state == FILE_TRANSFER_INACTIVE) {
if (ft->state == FILE_TRANSFER_INACTIVE)
continue;
}
if (memcmp(ft->file_id, file_id, TOX_FILE_ID_LENGTH) == 0) {
ft->filenum = filenum;
@ -557,17 +512,14 @@ static bool chat_resume_broken_ft(ToxWindow *self, Tox *m, uint32_t friendnum, u
}
}
if (!resuming || !ft) {
if (!resuming || !ft)
return false;
}
if (!tox_file_seek(m, ft->friendnum, ft->filenum, ft->position, NULL)) {
if (!tox_file_seek(m, ft->friendnum, ft->filenum, ft->position, NULL))
goto on_error;
}
if (!tox_file_control(m, ft->friendnum, ft->filenum, TOX_FILE_CONTROL_RESUME, NULL)) {
if (!tox_file_control(m, ft->friendnum, ft->filenum, TOX_FILE_CONTROL_RESUME, NULL))
goto on_error;
}
return true;
@ -580,14 +532,12 @@ on_error:
static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_t filenum, uint64_t file_size,
const char *filename, size_t name_length)
{
if (self->num != friendnum) {
if (self->num != friendnum)
return;
}
/* first check if we need to resume a broken transfer */
if (chat_resume_broken_ft(self, m, friendnum, filenum)) {
if (chat_resume_broken_ft(self, m, friendnum, filenum))
return;
}
struct FileTransfer *ft = new_file_transfer(self, friendnum, filenum, FILE_TRANSFER_RECV, TOX_FILE_KIND_DATA);
@ -601,7 +551,7 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_
bytes_convert_str(sizestr, sizeof(sizestr), file_size);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer request for '%s' (%s)", filename, sizestr);
char file_path[PATH_MAX + name_length + 1];
char file_path[MAX_STR_SIZE];
size_t path_len = name_length;
/* use specified download path in config if possible */
@ -652,100 +602,82 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_
snprintf(ft->file_name, sizeof(ft->file_name), "%s", filename);
tox_file_get_file_id(m, friendnum, filenum, ft->file_id, NULL);
if (self->active_box != -1) {
if (self->active_box != -1)
box_notify2(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS | user_settings->bell_on_filetrans,
self->active_box, "Incoming file: %s", filename);
} else {
self->active_box, "Incoming file: %s", filename );
else
box_notify(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS | user_settings->bell_on_filetrans,
&self->active_box, self->name, "Incoming file: %s", filename);
}
&self->active_box, self->name, "Incoming file: %s", filename );
}
static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, uint8_t type, const char *group_pub_key,
uint16_t length)
static void chat_onGroupInvite(ToxWindow *self, Tox *m, uint32_t friendnumber, const char *invite_data,
size_t length)
{
if (self->num != friendnumber) {
if (self->num != friendnumber)
return;
}
if (Friends.list[friendnumber].group_invite.key != NULL) {
free(Friends.list[friendnumber].group_invite.key);
}
if (Friends.list[friendnumber].group_invite.data)
free(Friends.list[friendnumber].group_invite.data);
char *k = malloc(length);
if (k == NULL) {
exit_toxic_err("Failed in chat_onGroupInvite", FATALERR_MEMORY);
}
memcpy(k, group_pub_key, length);
Friends.list[friendnumber].group_invite.key = k;
Friends.list[friendnumber].group_invite.pending = true;
Friends.list[friendnumber].group_invite.data = malloc(length * sizeof(uint8_t));
memcpy(Friends.list[friendnumber].group_invite.data, invite_data, length);
Friends.list[friendnumber].group_invite.length = length;
Friends.list[friendnumber].group_invite.type = type;
sound_notify(self, generic_message, NT_WNDALERT_2 | user_settings->bell_on_invite, NULL);
char name[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, name, friendnumber);
if (self->active_box != -1) {
if (self->active_box != -1)
box_silent_notify2(self, NT_WNDALERT_2 | NT_NOFOCUS, self->active_box, "invites you to join group chat");
} else {
else
box_silent_notify(self, NT_WNDALERT_2 | NT_NOFOCUS, &self->active_box, name, "invites you to join group chat");
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s has invited you to a group chat.", name);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type \"/join\" to join the chat.");
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type \"/gaccept\" to join the chat.");
}
/* AV Stuff */
#ifdef AUDIO
void chat_onInvite(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
void chat_onInvite (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
{
if (!self || self->num != friend_number) {
if (!self || self->num != friend_number)
return;
}
/* call is flagged active here */
self->is_call = true;
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Incoming audio call! Type: \"/answer\" or \"/reject\"");
if (self->ringing_sound == -1) {
if (self->ringing_sound == -1)
sound_notify(self, call_incoming, NT_LOOP | user_settings->bell_on_invite, &self->ringing_sound);
}
if (self->active_box != -1) {
if (self->active_box != -1)
box_silent_notify2(self, NT_NOFOCUS | NT_WNDALERT_0, self->active_box, "Incoming audio call!");
} else {
else
box_silent_notify(self, NT_NOFOCUS | NT_WNDALERT_0, &self->active_box, self->name, "Incoming audio call!");
}
}
void chat_onRinging(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
void chat_onRinging (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
{
if (!self || self->num != friend_number) {
if (!self || self->num != friend_number)
return;
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ringing...type \"/hangup\" to cancel it.");
#ifdef SOUND_NOTIFY
if (self->ringing_sound == -1) {
if (self->ringing_sound == -1)
sound_notify(self, call_outgoing, NT_LOOP, &self->ringing_sound);
}
#endif /* SOUND_NOTIFY */
}
void chat_onStarting(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
void chat_onStarting (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
{
if (!self || self->num != friend_number) {
if (!self || self->num != friend_number)
return;
}
init_infobox(self);
@ -759,11 +691,10 @@ void chat_onStarting(ToxWindow *self, ToxAV *av, uint32_t friend_number, int sta
#endif /* SOUND_NOTIFY */
}
void chat_onEnding(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
void chat_onEnding (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
{
if (!self || self->num != friend_number) {
if (!self || self->num != friend_number)
return;
}
kill_infobox(self);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call ended!");
@ -775,11 +706,10 @@ void chat_onEnding(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state
#endif /* SOUND_NOTIFY */
}
void chat_onError(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
void chat_onError (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
{
if (!self || self->num != friend_number) {
if (!self || self->num != friend_number)
return;
}
self->is_call = false;
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error!");
@ -789,11 +719,10 @@ void chat_onError(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
#endif /* SOUND_NOTIFY */
}
void chat_onStart(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
void chat_onStart (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
{
if (!self || self->num != friend_number) {
if (!self || self->num != friend_number)
return;
}
/* call is flagged active here */
self->is_call = true;
@ -807,11 +736,10 @@ void chat_onStart(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
#endif /* SOUND_NOTIFY */
}
void chat_onCancel(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
void chat_onCancel (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
{
if (!self || self->num != friend_number) {
if (!self || self->num != friend_number)
return;
}
self->is_call = false;
kill_infobox(self);
@ -822,11 +750,10 @@ void chat_onCancel(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state
#endif /* SOUND_NOTIFY */
}
void chat_onReject(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
void chat_onReject (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
{
if (!self || self->num != friend_number) {
if (!self || self->num != friend_number)
return;
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Rejected!");
self->is_call = false;
@ -836,11 +763,10 @@ void chat_onReject(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state
#endif /* SOUND_NOTIFY */
}
void chat_onEnd(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
void chat_onEnd (ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
{
if (!self || self->num != friend_number) {
if (!self || self->num != friend_number)
return;
}
kill_infobox(self);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call ended!");
@ -858,9 +784,8 @@ static void init_infobox(ToxWindow *self)
int x2, y2;
getmaxyx(self->window, y2, x2);
if (y2 <= 0 || x2 <= 0) {
if (y2 <= 0 || x2 <= 0)
return;
}
(void) y2;
@ -877,9 +802,8 @@ static void kill_infobox(ToxWindow *self)
{
ChatContext *ctx = self->chatwin;
if (!ctx->infobox.win) {
if (!ctx->infobox.win)
return;
}
delwin(ctx->infobox.win);
memset(&ctx->infobox, 0, sizeof(struct infobox));
@ -890,23 +814,20 @@ static void draw_infobox(ToxWindow *self)
{
struct infobox *infobox = &self->chatwin->infobox;
if (infobox->win == NULL) {
if (infobox->win == NULL)
return;
}
int x2, y2;
getmaxyx(self->window, y2, x2);
if (x2 < INFOBOX_WIDTH || y2 < INFOBOX_HEIGHT) {
if (x2 < INFOBOX_WIDTH || y2 < INFOBOX_HEIGHT)
return;
}
time_t curtime = get_unix_time();
/* update elapsed time string once per second */
if (curtime > infobox->lastupdate) {
if (curtime > infobox->lastupdate)
get_elapsed_time_str(infobox->timestr, sizeof(infobox->timestr), curtime - infobox->starttime);
}
infobox->lastupdate = curtime;
@ -936,7 +857,7 @@ static void draw_infobox(ToxWindow *self)
wattron(infobox->win, A_BOLD);
wprintw(infobox->win, " VAD level: ");
wattroff(infobox->win, A_BOLD);
wprintw(infobox->win, "%.2f\n", (double) infobox->vad_lvl);
wprintw(infobox->win, "%.2f\n", infobox->vad_lvl);
wborder(infobox->win, ACS_VLINE, ' ', ACS_HLINE, ACS_HLINE, ACS_TTEE, ' ', ACS_LLCORNER, ' ');
wnoutrefresh(infobox->win);
@ -946,9 +867,8 @@ static void draw_infobox(ToxWindow *self)
static void send_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
{
if (action == NULL) {
if (action == NULL)
return;
}
char selfname[TOX_MAX_NAME_LENGTH];
tox_self_get_name(m, (uint8_t *) selfname);
@ -959,8 +879,8 @@ static void send_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
int id = line_info_add(self, timefrmt, selfname, NULL, OUT_ACTION, 0, 0, "%s", action);
cqueue_add(ctx->cqueue, action, strlen(action), OUT_ACTION, id);
line_info_add(self, timefrmt, selfname, NULL, OUT_ACTION, 0, 0, "%s", action);
cqueue_add(ctx->cqueue, action, strlen(action), OUT_ACTION, ctx->hst->line_end->id + 1);
}
static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
@ -972,13 +892,11 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
getyx(self->window, y, x);
getmaxyx(self->window, y2, x2);
if (y2 <= 0 || x2 <= 0) {
if (y2 <= 0 || x2 <= 0)
return;
}
if (ctx->pastemode && key == '\r') {
if (ctx->pastemode && key == '\r')
key = '\n';
}
if (self->help->active) {
help_onKey(self, key);
@ -988,16 +906,14 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (ltr || key == '\n') { /* char is printable */
input_new_char(self, key, x, y, x2, y2);
if (ctx->line[0] != '/' && !ctx->self_is_typing && statusbar->connection != TOX_CONNECTION_NONE) {
if (ctx->line[0] != '/' && !ctx->self_is_typing && statusbar->connection != TOX_CONNECTION_NONE)
set_self_typingstatus(self, m, 1);
}
return;
}
if (line_info_onKey(self, key)) {
if (line_info_onKey(self, key))
return;
}
input_handle(self, key, x, y, x2, y2);
@ -1005,20 +921,11 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
int diff = -1;
/* TODO: make this not suck */
if (wcsncmp(ctx->line, L"/sendfile ", wcslen(L"/sendfile ")) == 0) {
if (wcsncmp(ctx->line, L"/sendfile \"", wcslen(L"/sendfile \"")) == 0) {
diff = dir_match(self, m, ctx->line, L"/sendfile");
} else if (wcsncmp(ctx->line, L"/avatar ", wcslen(L"/avatar ")) == 0) {
} else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) {
diff = dir_match(self, m, ctx->line, L"/avatar");
}
#ifdef PYTHON
else if (wcsncmp(ctx->line, L"/run ", wcslen(L"/run ")) == 0) {
diff = dir_match(self, m, ctx->line, L"/run");
}
#endif
else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) {
} else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) {
const char status_cmd_list[3][8] = {
{"online"},
{"away"},
@ -1048,9 +955,8 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
char line[MAX_STR_SIZE] = {0};
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
memset(&line, 0, sizeof(line));
}
if (line[0] == '/') {
if (strcmp(line, "/close") == 0) {
@ -1071,8 +977,8 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
int id = line_info_add(self, timefrmt, selfname, NULL, OUT_MSG, 0, 0, "%s", line);
cqueue_add(ctx->cqueue, line, strlen(line), OUT_MSG, id);
line_info_add(self, timefrmt, selfname, NULL, OUT_MSG, 0, 0, "%s", line);
cqueue_add(ctx->cqueue, line, strlen(line), OUT_MSG, ctx->hst->line_end->id + 1);
}
}
@ -1081,9 +987,8 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
reset_buf(ctx);
}
if (ctx->len <= 0 && ctx->self_is_typing) {
if (ctx->len <= 0 && ctx->self_is_typing)
set_self_typingstatus(self, m, 0);
}
}
static void chat_onDraw(ToxWindow *self, Tox *m)
@ -1091,9 +996,8 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
int x2, y2;
getmaxyx(self->window, y2, x2);
if (y2 <= 0 || x2 <= 0) {
if (y2 <= 0 || x2 <= 0)
return;
}
ChatContext *ctx = self->chatwin;
@ -1105,9 +1009,8 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
curs_set(1);
if (ctx->len > 0) {
if (ctx->len > 0)
mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]);
}
/* Draw status bar */
StatusBar *statusbar = self->stb;
@ -1117,7 +1020,7 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
/* Draw name, status and note in statusbar */
if (statusbar->connection != TOX_CONNECTION_NONE) {
int colour = MAGENTA;
Tox_User_Status status = statusbar->status;
TOX_USER_STATUS status = statusbar->status;
switch (status) {
case TOX_USER_STATUS_NONE:
@ -1137,17 +1040,15 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
wprintw(statusbar->topline, " %s", ONLINE_CHAR);
wattroff(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
if (Friends.list[self->num].is_typing) {
if (Friends.list[self->num].is_typing)
wattron(statusbar->topline, COLOR_PAIR(YELLOW));
}
wattron(statusbar->topline, A_BOLD);
wprintw(statusbar->topline, " %s ", statusbar->nick);
wattroff(statusbar->topline, A_BOLD);
if (Friends.list[self->num].is_typing) {
if (Friends.list[self->num].is_typing)
wattroff(statusbar->topline, COLOR_PAIR(YELLOW));
}
} else {
wprintw(statusbar->topline, " %s", OFFLINE_CHAR);
wattron(statusbar->topline, A_BOLD);
@ -1180,9 +1081,8 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
statusbar->statusmsg_len = maxlen;
}
if (statusbar->statusmsg[0]) {
if (statusbar->statusmsg[0])
wprintw(statusbar->topline, ": %s ", statusbar->statusmsg);
}
wclrtoeol(statusbar->topline);
wmove(statusbar->topline, 0, x2 - (KEY_IDENT_DIGITS * 2) - 3);
@ -1190,9 +1090,8 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
size_t i;
for (i = 0; i < KEY_IDENT_DIGITS; ++i) {
for (i = 0; i < KEY_IDENT_DIGITS; ++i)
wprintw(statusbar->topline, "%02X", Friends.list[self->num].pub_key[i] & 0xff);
}
wprintw(statusbar->topline, "}\n");
@ -1214,9 +1113,8 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
#endif
if (self->help->active) {
if (self->help->active)
help_onDraw(self);
}
pthread_mutex_lock(&Winthread.lock);
refresh_file_transfer_progress(self, m, self->num);
@ -1229,16 +1127,16 @@ static void chat_onInit(ToxWindow *self, Tox *m)
int x2, y2;
getmaxyx(self->window, y2, x2);
if (y2 <= 0 || x2 <= 0) {
if (y2 <= 0 || x2 <= 0)
exit_toxic_err("failed in chat_onInit", FATALERR_CURSES);
}
self->x = x2;
/* Init statusbar info */
StatusBar *statusbar = self->stb;
statusbar->status = get_friend_status(self->num);
statusbar->connection = get_friend_connection_status(self->num);
statusbar->status = tox_friend_get_status(m, self->num, NULL);
statusbar->connection = tox_friend_get_connection_status(m, self->num, NULL);
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH];
tox_friend_get_status_message(m, self->num, (uint8_t *) statusmsg, NULL);
@ -1266,9 +1164,8 @@ static void chat_onInit(ToxWindow *self, Tox *m)
ctx->log = calloc(1, sizeof(struct chatlog));
ctx->cqueue = calloc(1, sizeof(struct chat_queue));
if (ctx->log == NULL || ctx->hst == NULL || ctx->cqueue == NULL) {
if (ctx->log == NULL || ctx->hst == NULL || ctx->cqueue == NULL)
exit_toxic_err("failed in chat_onInit", FATALERR_MEMORY);
}
line_info_init(ctx->hst);
@ -1278,11 +1175,10 @@ static void chat_onInit(ToxWindow *self, Tox *m)
int log_ret = log_enable(nick, myid, Friends.list[self->num].pub_key, ctx->log, LOG_CHAT);
load_chat_history(self, ctx->log);
if (!Friends.list[self->num].logging_on) {
if (!Friends.list[self->num].logging_on)
log_disable(ctx->log);
} else if (log_ret == -1) {
else if (log_ret == -1)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
}
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
@ -1290,67 +1186,64 @@ static void chat_onInit(ToxWindow *self, Tox *m)
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
}
ToxWindow *new_chat(Tox *m, uint32_t friendnum)
ToxWindow new_chat(Tox *m, uint32_t friendnum)
{
ToxWindow *ret = calloc(1, sizeof(ToxWindow));
ToxWindow ret;
memset(&ret, 0, sizeof(ret));
if (ret == NULL) {
exit_toxic_err("failed in new_chat", FATALERR_MEMORY);
}
ret.active = true;
ret.is_chat = true;
ret->is_chat = true;
ret->onKey = &chat_onKey;
ret->onDraw = &chat_onDraw;
ret->onInit = &chat_onInit;
ret->onMessage = &chat_onMessage;
ret->onConnectionChange = &chat_onConnectionChange;
ret->onTypingChange = & chat_onTypingChange;
ret->onGroupInvite = &chat_onGroupInvite;
ret->onNickChange = &chat_onNickChange;
ret->onStatusChange = &chat_onStatusChange;
ret->onStatusMessageChange = &chat_onStatusMessageChange;
ret->onFileChunkRequest = &chat_onFileChunkRequest;
ret->onFileRecvChunk = &chat_onFileRecvChunk;
ret->onFileControl = &chat_onFileControl;
ret->onFileRecv = &chat_onFileRecv;
ret->onReadReceipt = &chat_onReadReceipt;
ret.onKey = &chat_onKey;
ret.onDraw = &chat_onDraw;
ret.onInit = &chat_onInit;
ret.onMessage = &chat_onMessage;
ret.onConnectionChange = &chat_onConnectionChange;
ret.onTypingChange = & chat_onTypingChange;
ret.onNickChange = &chat_onNickChange;
ret.onStatusChange = &chat_onStatusChange;
ret.onStatusMessageChange = &chat_onStatusMessageChange;
ret.onFileChunkRequest = &chat_onFileChunkRequest;
ret.onFileRecvChunk = &chat_onFileRecvChunk;
ret.onFileControl = &chat_onFileControl;
ret.onFileRecv = &chat_onFileRecv;
ret.onReadReceipt = &chat_onReadReceipt;
ret.onGroupInvite = &chat_onGroupInvite;
#ifdef AUDIO
ret->onInvite = &chat_onInvite;
ret->onRinging = &chat_onRinging;
ret->onStarting = &chat_onStarting;
ret->onEnding = &chat_onEnding;
ret->onError = &chat_onError;
ret->onStart = &chat_onStart;
ret->onCancel = &chat_onCancel;
ret->onReject = &chat_onReject;
ret->onEnd = &chat_onEnd;
ret.onInvite = &chat_onInvite;
ret.onRinging = &chat_onRinging;
ret.onStarting = &chat_onStarting;
ret.onEnding = &chat_onEnding;
ret.onError = &chat_onError;
ret.onStart = &chat_onStart;
ret.onCancel = &chat_onCancel;
ret.onReject = &chat_onReject;
ret.onEnd = &chat_onEnd;
ret->is_call = false;
ret->device_selection[0] = ret->device_selection[1] = -1;
ret->ringing_sound = -1;
ret.is_call = false;
ret.device_selection[0] = ret.device_selection[1] = -1;
ret.ringing_sound = -1;
#endif /* AUDIO */
ret->active_box = -1;
ret.active_box = -1;
char nick[TOX_MAX_NAME_LENGTH];
size_t n_len = get_nick_truncate(m, nick, friendnum);
set_window_title(ret, nick, n_len);
set_window_title(&ret, nick, n_len);
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
StatusBar *stb = calloc(1, sizeof(StatusBar));
Help *help = calloc(1, sizeof(Help));
if (stb == NULL || chatwin == NULL || help == NULL) {
if (stb == NULL || chatwin == NULL || help == NULL)
exit_toxic_err("failed in new_chat", FATALERR_MEMORY);
}
ret->chatwin = chatwin;
ret->stb = stb;
ret->help = help;
ret.chatwin = chatwin;
ret.stb = stb;
ret.help = help;
ret->num = friendnum;
ret.num = friendnum;
return ret;
}

View File

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

View File

@ -78,6 +78,47 @@ void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, silent);
}
void cmd_groupaccept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open.");
return;
}
if (Friends.list[self->num].group_invite.length == 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending group invite");
return;
}
const char *passwd = NULL;
uint16_t passwd_len = 0;
if (argc > 0) {
passwd = argv[1];
passwd_len = strlen(passwd);
}
TOX_ERR_GROUP_INVITE_ACCEPT err;
uint32_t groupnumber = tox_group_invite_accept(m, Friends.list[self->num].group_invite.data,
Friends.list[self->num].group_invite.length,
(uint8_t *) passwd, passwd_len, &err);
if (err != TOX_ERR_GROUP_INVITE_ACCEPT_OK) {
if (err == TOX_ERR_GROUP_INVITE_ACCEPT_TOO_LONG)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to joing group: Password too long.");
else
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to joing group (error %d).", err);
return;
}
if (init_groupchat_win(m, groupnumber, NULL, 0) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
tox_group_leave(m, groupnumber, NULL, 0, NULL);
return;
}
}
void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 1) {
@ -85,61 +126,24 @@ void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
return;
}
long int groupnum = strtol(argv[1], NULL, 10);
int groupnum = atoi(argv[1]);
if ((groupnum == 0 && strcmp(argv[1], "0")) || groupnum < 0 || groupnum == LONG_MAX) {
if (groupnum == 0 && strcmp(argv[1], "0")) { /* atoi returns 0 value on invalid input */
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid group number.");
return;
}
Tox_Err_Conference_Invite err;
TOX_ERR_GROUP_INVITE_FRIEND err;
if (!tox_conference_invite(m, self->num, groupnum, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to group (error %d)", err);
if (!tox_group_invite_friend(m, groupnum, self->num, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to group (error %d).", err);
return;
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invited contact to Group %d.", groupnum);
}
void cmd_join_group(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open.");
return;
}
const char *groupkey = Friends.list[self->num].group_invite.key;
uint16_t length = Friends.list[self->num].group_invite.length;
uint8_t type = Friends.list[self->num].group_invite.type;
if (!Friends.list[self->num].group_invite.pending) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending group chat invite.");
return;
}
if (type != TOX_CONFERENCE_TYPE_TEXT) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Toxic does not support audio groups.");
return;
}
Tox_Err_Conference_Join err;
uint32_t groupnum = tox_conference_join(m, self->num, (const uint8_t *) groupkey, length, &err);
if (err != TOX_ERR_CONFERENCE_JOIN_OK) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize (error %d)", err);
return;
}
if (init_groupchat_win(prompt, m, groupnum, type) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
tox_conference_delete(m, groupnum, NULL);
return;
}
}
void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 1) {
@ -167,17 +171,16 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
}
if ((ft->file = fopen(ft->file_path, "a")) == NULL) {
const char *msg = "File transfer failed: Invalid download path.";
const char *msg = "File transfer failed: Invalid file path.";
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
return;
}
Tox_Err_File_Control err;
TOX_ERR_FILE_CONTROL err;
tox_file_control(m, self->num, ft->filenum, TOX_FILE_CONTROL_RESUME, &err);
if (err != TOX_ERR_FILE_CONTROL_OK) {
if (err != TOX_ERR_FILE_CONTROL_OK)
goto on_recv_error;
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%d] as: '%s'", idx, ft->file_path);
@ -225,9 +228,16 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
return;
}
if (argv[1][0] != '\"') {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path must be enclosed in quotes.");
return;
}
/* remove opening and closing quotes */
char path[MAX_STR_SIZE];
snprintf(path, sizeof(path), "%s", argv[1]);
int path_len = strlen(path);
snprintf(path, sizeof(path), "%s", &argv[1][1]);
int path_len = strlen(path) - 1;
path[path_len] = '\0';
if (path_len >= MAX_STR_SIZE) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path exceeds character limit.");
@ -252,13 +262,12 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
char file_name[TOX_MAX_FILENAME_LENGTH];
size_t namelen = get_file_name(file_name, sizeof(file_name), path);
Tox_Err_File_Send err;
TOX_ERR_FILE_SEND err;
uint32_t filenum = tox_file_send(m, self->num, TOX_FILE_KIND_DATA, (uint64_t) filesize, NULL,
(uint8_t *) file_name, namelen, &err);
if (err != TOX_ERR_FILE_SEND_OK) {
if (err != TOX_ERR_FILE_SEND_OK)
goto on_send_error;
}
struct FileTransfer *ft = new_file_transfer(self, self->num, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_DATA);

View File

@ -26,9 +26,9 @@
#include "windows.h"
#include "toxic.h"
void cmd_groupaccept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_groupinvite(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_join_group(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_savefile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_sendfile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
@ -41,7 +41,6 @@ void cmd_cancel(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZ
void cmd_ccur_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_mute(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_sense(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_bitrate(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
#endif /* AUDIO */
#ifdef VIDEO
@ -49,4 +48,4 @@ void cmd_video(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE
void cmd_ccur_video_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
#endif /* VIDEO */
#endif /* CHAT_COMMANDS_H */
#endif /* #define CHAT_COMMANDS_H */

View File

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

View File

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

View File

@ -36,9 +36,8 @@
*/
int set_curl_proxy(CURL *c_handle, const char *proxy_address, uint16_t port, uint8_t proxy_type)
{
if (proxy_type == TOX_PROXY_TYPE_NONE) {
if (proxy_type == TOX_PROXY_TYPE_NONE)
return 0;
}
if (proxy_address == NULL || port == 0) {
return -1;

View File

@ -52,4 +52,4 @@ int set_curl_proxy(CURL *c_handle, const char *proxy_address, uint16_t port, uin
*/
size_t curl_cb_write_data(void *data, size_t size, size_t nmemb, void *user_pointer);
#endif /* CURL_UTIL_H */
#endif /* CURL_UTIL_H */

View File

@ -33,7 +33,8 @@
#include "line_info.h"
#include "misc_tools.h"
#include "notify.h"
#include "api.h"
#define MAX_NUM_ARGS 10 /* Includes command */
struct cmd_func {
const char *name;
@ -50,11 +51,10 @@ static struct cmd_func global_commands[] = {
{ "/exit", cmd_quit },
{ "/group", cmd_groupchat },
{ "/help", cmd_prompt_help },
{ "/join", cmd_join },
{ "/log", cmd_log },
{ "/myid", cmd_myid },
#ifdef QRCODE
{ "/myqr", cmd_myqr },
#endif /* QRCODE */
{ "/nick", cmd_nick },
{ "/note", cmd_note },
{ "/nospam", cmd_nospam },
@ -68,18 +68,15 @@ static struct cmd_func global_commands[] = {
#endif /* AUDIO */
#ifdef VIDEO
{ "/lsvdev", cmd_list_video_devices },
{ "/svdev", cmd_change_video_device },
{ "/svdev" , cmd_change_video_device },
#endif /* VIDEO */
#ifdef PYTHON
{ "/run", cmd_run },
#endif /* PYTHON */
{ NULL, NULL },
};
static struct cmd_func chat_commands[] = {
{ "/cancel", cmd_cancelfile },
{ "/gaccept", cmd_groupaccept },
{ "/invite", cmd_groupinvite },
{ "/join", cmd_join_group },
{ "/savefile", cmd_savefile },
{ "/sendfile", cmd_sendfile },
#ifdef AUDIO
@ -89,7 +86,6 @@ static struct cmd_func chat_commands[] = {
{ "/hangup", cmd_hangup },
{ "/mute", cmd_mute },
{ "/sense", cmd_sense },
{ "/bitrate", cmd_bitrate },
#endif /* AUDIO */
#ifdef VIDEO
{ "/video", cmd_video },
@ -98,112 +94,148 @@ static struct cmd_func chat_commands[] = {
};
static struct cmd_func group_commands[] = {
{ "/title", cmd_set_title },
{ "/ban", cmd_ban },
{ "/chatid", cmd_chatid },
{ "/ignore", cmd_ignore },
{ "/kick", cmd_kick },
{ "/mod", cmd_mod },
{ "/mykey", cmd_mykey },
{ "/passwd", cmd_set_passwd },
{ "/peerlimit", cmd_set_peerlimit },
{ "/privacy", cmd_set_privacy },
{ "/rejoin", cmd_rejoin },
{ "/silence", cmd_silence },
{ "/topic", cmd_set_topic },
{ "/unban", cmd_unban },
{ "/unignore", cmd_unignore },
{ "/unmod", cmd_unmod },
{ "/unsilence", cmd_unsilence },
{ "/whois", cmd_whois },
#ifdef AUDIO
{ "/mute", cmd_mute },
{ "/sense", cmd_sense },
{ "/mute", cmd_mute },
{ "/sense", cmd_sense },
#endif /* AUDIO */
{ NULL, NULL },
{ NULL, NULL },
};
#ifdef PYTHON
#define SPECIAL_COMMANDS 6
#else
#define SPECIAL_COMMANDS 5
#endif /* PYTHON */
/* Special commands are commands that only take one argument even if it contains spaces */
static const char special_commands[SPECIAL_COMMANDS][MAX_CMDNAME_SIZE] = {
"/avatar",
#define NUM_SPECIAL_COMMANDS 15
static const char special_commands[NUM_SPECIAL_COMMANDS][MAX_CMDNAME_SIZE] = {
"/ban",
"/gaccept",
"/group",
"/ignore",
"/kick",
"/mod",
"/nick",
"/note",
#ifdef PYTHON
"/run",
#endif /* PYTHON */
"/title",
"/sendfile",
"/passwd",
"/silence",
"/topic",
"/unignore",
"/unmod",
"/unsilence",
"/whois",
};
/* Returns true if input command is in the special_commands array. */
/* return true if input command is in the special_commands array. False otherwise.*/
static bool is_special_command(const char *input)
{
const int s = char_find(0, input, ' ');
int s = char_find(0, input, ' ');
for (int i = 0; i < SPECIAL_COMMANDS; ++i) {
if (strncmp(input, special_commands[i], s) == 0) {
if (s == strlen(input))
return false;
int i;
for (i = 0; i < NUM_SPECIAL_COMMANDS; ++i) {
if (strncmp(input, special_commands[i], s) == 0)
return true;
}
}
return false;
}
/* Parses commands in the special_commands array. Unlike parse_command, this function
* does not split the input string at spaces.
/* Parses commands in the special_commands array which take exactly one argument that may contain spaces.
* Unlike parse_command, this function does not split the input string at spaces.
*
* Returns the number of arguments.
* Returns number of arguments on success
* Returns -1 on failure
*/
static int parse_special_command(WINDOW *w, ToxWindow *self, const char *input, char (*args)[MAX_STR_SIZE])
{
int len = strlen(input);
int s = char_find(0, input, ' ');
if (s + 1 >= len)
return -1;
memcpy(args[0], input, s);
args[0][s++] = '\0'; // increment to remove space after "/command "
if (s >= len) {
return 1; // No additional args
}
args[0][s++] = '\0'; /* increment to remove space after /command */
memcpy(args[1], input + s, len - s);
args[1][len - s] = '\0';
return 2;
}
/* Parses input command and puts args into arg array.
/* Parses input command and puts args (split by spaces) into args array.
*
* Returns the number of arguments.
* Returns number of arguments on success
* Returns -1 on failure.
*/
static int parse_command(WINDOW *w, ToxWindow *self, const char *input, char (*args)[MAX_STR_SIZE])
{
if (is_special_command(input)) {
if (is_special_command(input))
return parse_special_command(w, self, input, args);
}
char *cmd = strdup(input);
if (cmd == NULL) {
if (cmd == NULL)
exit_toxic_err("failed in parse_command", FATALERR_MEMORY);
}
int num_args = 0;
int i = 0; /* index of last char in an argument */
/* characters wrapped in double quotes count as one arg */
while (num_args < MAX_NUM_ARGS) {
int i = char_find(0, cmd, ' '); // index of last char in an argument
memcpy(args[num_args], cmd, i);
args[num_args++][i] = '\0';
int qt_ofst = 0; /* set to 1 to offset index for quote char at end of arg */
if (cmd[i] == '\0') { // no more args
break;
if (*cmd == '\"') {
qt_ofst = 1;
i = char_find(1, cmd, '\"');
if (cmd[i] == '\0') {
const char *errmsg = "Invalid argument. Did you forget a closing \"?";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
free(cmd);
return -1;
}
} else {
i = char_find(0, cmd, ' ');
}
memcpy(args[num_args], cmd, i + qt_ofst);
args[num_args++][i + qt_ofst] = '\0';
if (cmd[i] == '\0') /* no more args */
break;
char tmp[MAX_STR_SIZE];
snprintf(tmp, sizeof(tmp), "%s", &cmd[i + 1]);
strcpy(cmd, tmp); // tmp will always fit inside cmd
strcpy(cmd, tmp); /* tmp will always fit inside cmd */
}
/* Ugly special case concatinates all args after arg1 for multi-word group passwords */
if (num_args > 2 && strcmp(args[0], "/join") == 0)
strcpy(args[2], input + strlen(args[0]) + 1 + strlen(args[1]) + 1);
free(cmd);
return num_args;
}
/* Matches command to respective function.
*
* Returns 0 on match.
* Returns 1 on no match
* Returns 0 on match,
* Returns -1 on no match
*/
static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, struct cmd_func *commands,
char (*args)[MAX_STR_SIZE])
@ -217,54 +249,40 @@ static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, struct c
}
}
return 1;
return -1;
}
void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode)
{
if (string_is_empty(input)) {
if (string_is_empty(input))
return;
}
char args[MAX_NUM_ARGS][MAX_STR_SIZE];
int num_args = parse_command(w, self, input, args);
if (num_args <= 0) {
if (num_args == -1)
return;
}
/* Try to match input command to command functions. If non-global command mode is specified,
* try specified mode's commands first, then upon failure try global commands.
*
* Note: Global commands must come last in case of duplicate command names
*/
try specified mode's commands first, then upon failure try global commands.
Note: Global commands must come last in case of duplicate command names */
switch (mode) {
case CHAT_COMMAND_MODE:
if (do_command(w, self, m, num_args, chat_commands, args) == 0) {
if (do_command(w, self, m, num_args, chat_commands, args) == 0)
return;
}
break;
case GROUPCHAT_COMMAND_MODE:
if (do_command(w, self, m, num_args, group_commands, args) == 0) {
if (do_command(w, self, m, num_args, group_commands, args) == 0)
return;
}
break;
}
if (do_command(w, self, m, num_args, global_commands, args) == 0) {
if (do_command(w, self, m, num_args, global_commands, args) == 0)
return;
}
#ifdef PYTHON
if (do_plugin_command(num_args, args) == 0) {
return;
}
#endif
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid command.");
}

View File

@ -26,14 +26,12 @@
#include "toxic.h"
#include "windows.h"
#define MAX_NUM_ARGS 4 /* Includes command */
enum {
GLOBAL_COMMAND_MODE,
CHAT_COMMAND_MODE,
GROUPCHAT_COMMAND_MODE,
};
} COMMAND_MODE;
void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode);
#endif /* EXECUTE_H */
#endif /* #define EXECUTE_H */

View File

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

View File

@ -108,4 +108,4 @@ void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum);
void kill_all_file_transfers(Tox *m);
#endif /* FILE_TRANSFERS_H */
#endif /* #define FILE_TRANSFERS_H */

View File

@ -84,9 +84,8 @@ static void realloc_friends(int n)
ToxicFriend *f = realloc(Friends.list, n * sizeof(ToxicFriend));
uint32_t *f_idx = realloc(Friends.index, n * sizeof(uint32_t));
if (f == NULL || f_idx == NULL) {
if (f == NULL || f_idx == NULL)
exit_toxic_err("failed in realloc_friends", FATALERR_MEMORY);
}
Friends.list = f;
Friends.index = f_idx;
@ -105,26 +104,24 @@ static void realloc_blocklist(int n)
BlockedFriend *b = realloc(Blocked.list, n * sizeof(BlockedFriend));
uint32_t *b_idx = realloc(Blocked.index, n * sizeof(uint32_t));
if (b == NULL || b_idx == NULL) {
if (b == NULL || b_idx == NULL)
exit_toxic_err("failed in realloc_blocklist", FATALERR_MEMORY);
}
Blocked.list = b;
Blocked.index = b_idx;
}
void kill_friendlist(ToxWindow *self)
void kill_friendlist(void)
{
for (size_t i = 0; i < Friends.max_idx; ++i) {
if (Friends.list[i].active && Friends.list[i].group_invite.key != NULL) {
free(Friends.list[i].group_invite.key);
}
size_t i;
for (i = 0; i < Friends.max_idx; ++i) {
if (Friends.list[i].group_invite.data != NULL)
free(Friends.list[i].group_invite.data);
}
realloc_blocklist(0);
realloc_friends(0);
free(self->help);
del_window(self);
}
/* Saves the blocklist to path. If there are no items in the blocklist the
@ -156,14 +153,10 @@ static int save_blocklist(char *path)
}
if (Blocked.list[i].active) {
if (Blocked.list[i].namelength > TOXIC_MAX_NAME_LENGTH) {
continue;
}
BlockedFriend tmp;
memset(&tmp, 0, sizeof(BlockedFriend));
tmp.namelength = htons(Blocked.list[i].namelength);
memcpy(tmp.name, Blocked.list[i].name, Blocked.list[i].namelength + 1); // Include null byte
memcpy(tmp.name, Blocked.list[i].name, Blocked.list[i].namelength + 1);
memcpy(tmp.pub_key, Blocked.list[i].pub_key, TOX_PUBLIC_KEY_SIZE);
uint8_t lastonline[sizeof(uint64_t)];
@ -218,15 +211,13 @@ static void sort_blocklist_index(void);
int load_blocklist(char *path)
{
if (path == NULL) {
if (path == NULL)
return -1;
}
FILE *fp = fopen(path, "rb");
if (fp == NULL) {
if (fp == NULL)
return -1;
}
off_t len = file_size(path);
@ -259,15 +250,10 @@ int load_blocklist(char *path)
memset(&Blocked.list[i], 0, sizeof(BlockedFriend));
memcpy(&tmp, data + i * sizeof(BlockedFriend), sizeof(BlockedFriend));
Blocked.list[i].namelength = ntohs(tmp.namelength);
if (Blocked.list[i].namelength > TOXIC_MAX_NAME_LENGTH) {
continue;
}
Blocked.list[i].active = true;
Blocked.list[i].num = i;
memcpy(Blocked.list[i].name, tmp.name, Blocked.list[i].namelength + 1); // copy null byte
Blocked.list[i].namelength = MIN(TOXIC_MAX_NAME_LENGTH, ntohs(tmp.namelength));
memcpy(Blocked.list[i].name, tmp.name, Blocked.list[i].namelength + 1);
memcpy(Blocked.list[i].pub_key, tmp.pub_key, TOX_PUBLIC_KEY_SIZE);
uint8_t lastonline[sizeof(uint64_t)];
@ -303,9 +289,8 @@ void sort_friendlist_index(void)
uint32_t n = 0;
for (i = 0; i < Friends.max_idx; ++i) {
if (Friends.list[i].active) {
if (Friends.list[i].active)
Friends.index[n++] = Friends.list[i].num;
}
}
qsort(Friends.index, Friends.num_friends, sizeof(uint32_t), index_name_cmp);
@ -322,9 +307,8 @@ static void sort_blocklist_index(void)
uint32_t n = 0;
for (i = 0; i < Blocked.max_idx; ++i) {
if (Blocked.list[i].active) {
if (Blocked.list[i].active)
Blocked.index[n++] = Blocked.list[i].num;
}
}
qsort(Blocked.index, Blocked.num_blocked, sizeof(uint32_t), index_name_cmp_block);
@ -341,16 +325,14 @@ static void update_friend_last_online(uint32_t num, time_t timestamp)
&Friends.list[num].last_online.tm);
}
static void friendlist_onMessage(ToxWindow *self, Tox *m, uint32_t num, Tox_Message_Type type, const char *str,
static void friendlist_onMessage(ToxWindow *self, Tox *m, uint32_t num, TOX_MESSAGE_TYPE type, const char *str,
size_t length)
{
if (num >= Friends.max_idx) {
if (num >= Friends.max_idx)
return;
}
if (Friends.list[num].chatwin != -1) {
if (Friends.list[num].chatwin != -1)
return;
}
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
@ -368,20 +350,18 @@ static void friendlist_onMessage(ToxWindow *self, Tox *m, uint32_t num, Tox_Mess
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
}
static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, Tox_Connection connection_status)
static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_CONNECTION connection_status)
{
if (num >= Friends.max_idx) {
if (num >= Friends.max_idx)
return;
}
if (connection_status == TOX_CONNECTION_NONE) {
--Friends.num_online;
} else if (Friends.list[num].connection_status == TOX_CONNECTION_NONE) {
++Friends.num_online;
if (avatar_send(m, num) == -1) {
if (avatar_send(m, num) == -1)
fprintf(stderr, "avatar_send failed for friend %d\n", num);
}
}
Friends.list[num].connection_status = connection_status;
@ -392,9 +372,8 @@ static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num,
static void friendlist_onNickChange(ToxWindow *self, Tox *m, uint32_t num, const char *nick, size_t length)
{
if (num >= Friends.max_idx) {
if (num >= Friends.max_idx)
return;
}
/* save old name for log renaming */
char oldname[TOXIC_MAX_NAME_LENGTH + 1];
@ -410,27 +389,24 @@ static void friendlist_onNickChange(ToxWindow *self, Tox *m, uint32_t num, const
strcpy(newnamecpy, Friends.list[num].name);
tox_self_get_address(m, (uint8_t *) myid);
if (strcmp(oldname, newnamecpy) != 0) {
if (strcmp(oldname, newnamecpy) != 0)
rename_logfile(oldname, newnamecpy, myid, Friends.list[num].pub_key, Friends.list[num].chatwin);
}
sort_friendlist_index();
}
static void friendlist_onStatusChange(ToxWindow *self, Tox *m, uint32_t num, Tox_User_Status status)
static void friendlist_onStatusChange(ToxWindow *self, Tox *m, uint32_t num, TOX_USER_STATUS status)
{
if (num >= Friends.max_idx) {
if (num >= Friends.max_idx)
return;
}
Friends.list[num].status = status;
}
static void friendlist_onStatusMessageChange(ToxWindow *self, uint32_t num, const char *note, size_t length)
{
if (length > TOX_MAX_STATUS_MESSAGE_LENGTH || num >= Friends.max_idx) {
if (length > TOX_MAX_STATUS_MESSAGE_LENGTH || num >= Friends.max_idx)
return;
}
snprintf(Friends.list[num].statusmsg, sizeof(Friends.list[num].statusmsg), "%s", note);
Friends.list[num].statusmsg_len = strlen(Friends.list[num].statusmsg);
@ -444,9 +420,8 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort)
uint32_t i;
for (i = 0; i <= Friends.max_idx; ++i) {
if (Friends.list[i].active) {
if (Friends.list[i].active)
continue;
}
++Friends.num_friends;
@ -457,19 +432,17 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort)
Friends.list[i].status = TOX_USER_STATUS_NONE;
Friends.list[i].logging_on = (bool) user_settings->autolog == AUTOLOG_ON;
Tox_Err_Friend_Get_Public_Key pkerr;
TOX_ERR_FRIEND_GET_PUBLIC_KEY pkerr;
tox_friend_get_public_key(m, num, (uint8_t *) Friends.list[i].pub_key, &pkerr);
if (pkerr != TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK) {
if (pkerr != TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK)
fprintf(stderr, "tox_friend_get_public_key failed (error %d)\n", pkerr);
}
Tox_Err_Friend_Get_Last_Online loerr;
TOX_ERR_FRIEND_GET_LAST_ONLINE loerr;
time_t t = tox_friend_get_last_online(m, num, &loerr);
if (loerr != TOX_ERR_FRIEND_GET_LAST_ONLINE_OK) {
if (loerr != TOX_ERR_FRIEND_GET_LAST_ONLINE_OK)
t = 0;
}
update_friend_last_online(i, t);
@ -478,23 +451,17 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort)
snprintf(Friends.list[i].name, sizeof(Friends.list[i].name), "%s", tempname);
Friends.list[i].namelength = strlen(Friends.list[i].name);
if (i == Friends.max_idx) {
if (i == Friends.max_idx)
++Friends.max_idx;
}
if (sort) {
if (sort)
sort_friendlist_index();
}
#ifdef AUDIO
init_friend_AV(i);
#endif
return;
}
}
/* Puts blocked friend back in friendlist. fnum is new friend number, bnum is blocked number. */
/* puts blocked friend back in friendlist. fnum is new friend number, bnum is blocked number */
static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum)
{
realloc_friends(Friends.max_idx + 1);
@ -503,9 +470,8 @@ static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum)
int i;
for (i = 0; i <= Friends.max_idx; ++i) {
if (Friends.list[i].active) {
if (Friends.list[i].active)
continue;
}
++Friends.num_friends;
@ -519,16 +485,12 @@ static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum)
memcpy(Friends.list[i].name, Blocked.list[bnum].name, Friends.list[i].namelength + 1);
memcpy(Friends.list[i].pub_key, Blocked.list[bnum].pub_key, TOX_PUBLIC_KEY_SIZE);
if (i == Friends.max_idx) {
if (i == Friends.max_idx)
++Friends.max_idx;
}
sort_blocklist_index();
sort_friendlist_index();
#ifdef AUDIO
init_friend_AV(i);
#endif
return;
}
}
@ -536,13 +498,11 @@ static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum)
static void friendlist_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum,
uint64_t file_size, const char *filename, size_t name_length)
{
if (num >= Friends.max_idx) {
if (num >= Friends.max_idx)
return;
}
if (Friends.list[num].chatwin != -1) {
if (Friends.list[num].chatwin != -1)
return;
}
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
@ -560,16 +520,13 @@ static void friendlist_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
}
static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, uint8_t type, const char *group_pub_key,
uint16_t length)
static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, uint32_t num, const char *data, size_t length)
{
if (num >= Friends.max_idx) {
if (num >= Friends.max_idx)
return;
}
if (Friends.list[num].chatwin != -1) {
if (Friends.list[num].chatwin != -1)
return;
}
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
@ -588,14 +545,12 @@ static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, uint8
/* move friendlist/blocklist cursor up and down */
static void select_friend(ToxWindow *self, wint_t key, int *selected, int num)
{
if (num <= 0) {
if (num <= 0)
return;
}
if (key == KEY_UP) {
if (--(*selected) < 0) {
if (--(*selected) < 0)
*selected = num - 1;
}
} else if (key == KEY_DOWN) {
*selected = (*selected + 1) % num;
}
@ -603,7 +558,7 @@ static void select_friend(ToxWindow *self, wint_t key, int *selected, int num)
static void delete_friend(Tox *m, uint32_t f_num)
{
Tox_Err_Friend_Delete err;
TOX_ERR_FRIEND_DELETE err;
if (tox_friend_delete(m, f_num, &err) != true) {
fprintf(stderr, "tox_friend_delete failed with error %d\n", err);
@ -612,9 +567,8 @@ static void delete_friend(Tox *m, uint32_t f_num)
--Friends.num_friends;
if (Friends.list[f_num].connection_status != TOX_CONNECTION_NONE) {
if (Friends.list[f_num].connection_status != TOX_CONNECTION_NONE)
--Friends.num_online;
}
/* close friend's chatwindow if it's currently open */
if (Friends.list[f_num].chatwin >= 0) {
@ -622,35 +576,25 @@ static void delete_friend(Tox *m, uint32_t f_num)
if (toxwin != NULL) {
kill_chat_window(toxwin, m);
set_active_window_index(1); /* keep friendlist focused */
set_active_window(1); /* keep friendlist focused */
}
}
if (Friends.list[f_num].group_invite.key != NULL) {
free(Friends.list[f_num].group_invite.key);
}
memset(&Friends.list[f_num], 0, sizeof(ToxicFriend));
int i;
for (i = Friends.max_idx; i > 0; --i) {
if (Friends.list[i - 1].active) {
if (Friends.list[i - 1].active)
break;
}
}
Friends.max_idx = i;
realloc_friends(i);
#ifdef AUDIO
del_friend_AV(i);
#endif
/* make sure num_selected stays within Friends.num_friends range */
if (Friends.num_friends && Friends.num_selected == Friends.num_friends) {
if (Friends.num_friends && Friends.num_selected == Friends.num_friends)
--Friends.num_selected;
}
store_data(m, DATA_FILE);
}
@ -686,9 +630,8 @@ static void del_friend_deactivate(ToxWindow *self, Tox *m, wint_t key)
static void draw_del_popup(void)
{
if (!PendingDelete.active) {
if (!PendingDelete.active)
return;
}
wattron(PendingDelete.popup, A_BOLD);
box(PendingDelete.popup, ACS_VLINE, ACS_HLINE);
@ -700,18 +643,17 @@ static void draw_del_popup(void)
pthread_mutex_lock(&Winthread.lock);
if (blocklist_view == 0) {
if (blocklist_view == 0)
wprintw(PendingDelete.popup, "%s", Friends.list[PendingDelete.num].name);
} else {
else
wprintw(PendingDelete.popup, "%s", Blocked.list[PendingDelete.num].name);
}
pthread_mutex_unlock(&Winthread.lock);
wattroff(PendingDelete.popup, A_BOLD);
wprintw(PendingDelete.popup, "? y/n");
wnoutrefresh(PendingDelete.popup);
wrefresh(PendingDelete.popup);
}
/* deletes contact from blocked list */
@ -722,9 +664,8 @@ static void delete_blocked_friend(uint32_t bnum)
int i;
for (i = Blocked.max_idx; i > 0; --i) {
if (Blocked.list[i - 1].active) {
if (Blocked.list[i - 1].active)
break;
}
}
--Blocked.num_blocked;
@ -732,17 +673,15 @@ static void delete_blocked_friend(uint32_t bnum)
realloc_blocklist(i);
save_blocklist(BLOCK_FILE);
if (Blocked.num_blocked && Blocked.num_selected == Blocked.num_blocked) {
if (Blocked.num_blocked && Blocked.num_selected == Blocked.num_blocked)
--Blocked.num_selected;
}
}
/* deletes contact from friendlist and puts in blocklist */
void block_friend(Tox *m, uint32_t fnum)
{
if (Friends.num_friends <= 0) {
if (Friends.num_friends <= 0)
return;
}
realloc_blocklist(Blocked.max_idx + 1);
memset(&Blocked.list[Blocked.max_idx], 0, sizeof(BlockedFriend));
@ -750,9 +689,8 @@ void block_friend(Tox *m, uint32_t fnum)
int i;
for (i = 0; i <= Blocked.max_idx; ++i) {
if (Blocked.list[i].active) {
if (Blocked.list[i].active)
continue;
}
Blocked.list[i].active = true;
Blocked.list[i].num = i;
@ -763,9 +701,8 @@ void block_friend(Tox *m, uint32_t fnum)
++Blocked.num_blocked;
if (i == Blocked.max_idx) {
if (i == Blocked.max_idx)
++Blocked.max_idx;
}
delete_friend(m, fnum);
save_blocklist(BLOCK_FILE);
@ -779,11 +716,10 @@ void block_friend(Tox *m, uint32_t fnum)
/* removes friend from blocklist, puts back in friendlist */
static void unblock_friend(Tox *m, uint32_t bnum)
{
if (Blocked.num_blocked <= 0) {
if (Blocked.num_blocked <= 0)
return;
}
Tox_Err_Friend_Add err;
TOX_ERR_FRIEND_ADD err;
uint32_t friendnum = tox_friend_add_norequest(m, (uint8_t *) Blocked.list[bnum].pub_key, &err);
if (err != TOX_ERR_FRIEND_ADD_OK) {
@ -810,47 +746,41 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
return;
}
if (!blocklist_view && !Friends.num_friends && (key != KEY_RIGHT && key != KEY_LEFT)) {
if (!blocklist_view && !Friends.num_friends && (key != KEY_RIGHT && key != KEY_LEFT))
return;
}
if (blocklist_view && !Blocked.num_blocked && (key != KEY_RIGHT && key != KEY_LEFT)) {
if (blocklist_view && !Blocked.num_blocked && (key != KEY_RIGHT && key != KEY_LEFT))
return;
}
int f = 0;
if (blocklist_view == 1 && Blocked.num_blocked) {
if (blocklist_view == 1 && Blocked.num_blocked)
f = Blocked.index[Blocked.num_selected];
} else if (Friends.num_friends) {
else if (Friends.num_friends)
f = Friends.index[Friends.num_selected];
}
/* lock screen and force decision on deletion popup */
if (PendingDelete.active) {
if (key == 'y' || key == 'n') {
if (key == 'y' || key == 'n')
del_friend_deactivate(self, m, key);
}
return;
}
if (key == ltr) {
if (key == ltr)
return;
}
switch (key) {
case '\r':
if (blocklist_view) {
if (blocklist_view)
break;
}
/* Jump to chat window if already open */
if (Friends.list[f].chatwin != -1) {
set_active_window_index(Friends.list[f].chatwin);
set_active_window(Friends.list[f].chatwin);
} else if (get_num_active_windows() < MAX_WINDOWS_NUM) {
Friends.list[f].chatwin = add_window(m, new_chat(m, Friends.list[f].num));
set_active_window_index(Friends.list[f].chatwin);
set_active_window(Friends.list[f].chatwin);
} else {
const char *msg = "* Warning: Too many windows are open.";
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, msg);
@ -864,11 +794,10 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
break;
case 'b':
if (!blocklist_view) {
if (!blocklist_view)
block_friend(m, f);
} else {
else
unblock_friend(m, f);
}
break;
@ -878,11 +807,10 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
break;
default:
if (blocklist_view == 0) {
if (blocklist_view == 0)
select_friend(self, key, &Friends.num_selected, Friends.num_friends);
} else {
else
select_friend(self, key, &Blocked.num_selected, Blocked.num_blocked);
}
break;
}
@ -897,9 +825,8 @@ static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2)
wattroff(self->window, A_BOLD);
wprintw(self->window, "%d\n\n", Blocked.num_blocked);
if ((y2 - FLIST_OFST) <= 0) {
if ((y2 - FLIST_OFST) <= 0)
return;
}
uint32_t selected_num = 0;
@ -928,17 +855,15 @@ static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2)
wprintw(self->window, "x");
wattroff(self->window, COLOR_PAIR(RED));
if (f_selected) {
if (f_selected)
wattron(self->window, COLOR_PAIR(BLUE));
}
wattron(self->window, A_BOLD);
wprintw(self->window, " %s\n", Blocked.list[f].name);
wattroff(self->window, A_BOLD);
if (f_selected) {
if (f_selected)
wattroff(self->window, COLOR_PAIR(BLUE));
}
}
wprintw(self->window, "\n");
@ -953,17 +878,15 @@ static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2)
int i;
for (i = 0; i < TOX_PUBLIC_KEY_SIZE; ++i) {
for (i = 0; i < TOX_PUBLIC_KEY_SIZE; ++i)
wprintw(self->window, "%02X", Blocked.list[selected_num].pub_key[i] & 0xff);
}
}
wnoutrefresh(self->window);
wrefresh(self->window);
draw_del_popup();
if (self->help->active) {
if (self->help->active)
help_onDraw(self);
}
}
static void friendlist_onDraw(ToxWindow *self, Tox *m)
@ -997,9 +920,8 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
wprintw(self->window, "%d/%d \n\n", Friends.num_online, Friends.num_friends);
if ((y2 - FLIST_OFST) <= 0) {
if ((y2 - FLIST_OFST) <= 0)
return;
}
uint32_t selected_num = 0;
@ -1038,8 +960,8 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
}
pthread_mutex_lock(&Winthread.lock);
Tox_Connection connection_status = Friends.list[f].connection_status;
Tox_User_Status status = Friends.list[f].status;
TOX_CONNECTION connection_status = Friends.list[f].connection_status;
TOX_USER_STATUS status = Friends.list[f].status;
pthread_mutex_unlock(&Winthread.lock);
if (connection_status != TOX_CONNECTION_NONE) {
@ -1063,9 +985,8 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
wprintw(self->window, "%s ", ONLINE_CHAR);
wattroff(self->window, COLOR_PAIR(colour) | A_BOLD);
if (f_selected) {
if (f_selected)
wattron(self->window, COLOR_PAIR(BLUE));
}
wattron(self->window, A_BOLD);
pthread_mutex_lock(&Winthread.lock);
@ -1073,9 +994,8 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
pthread_mutex_unlock(&Winthread.lock);
wattroff(self->window, A_BOLD);
if (f_selected) {
if (f_selected)
wattroff(self->window, COLOR_PAIR(BLUE));
}
/* Reset Friends.list[f].statusmsg on window resize */
if (fix_statuses) {
@ -1108,9 +1028,8 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
Friends.list[f].statusmsg_len = maxlen;
}
if (Friends.list[f].statusmsg_len > 0) {
if (Friends.list[f].statusmsg_len > 0)
wprintw(self->window, " %s", Friends.list[f].statusmsg);
}
pthread_mutex_unlock(&Winthread.lock);
@ -1118,9 +1037,8 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
} else {
wprintw(self->window, "%s ", OFFLINE_CHAR);
if (f_selected) {
if (f_selected)
wattron(self->window, COLOR_PAIR(BLUE));
}
wattron(self->window, A_BOLD);
pthread_mutex_lock(&Winthread.lock);
@ -1128,9 +1046,8 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
pthread_mutex_unlock(&Winthread.lock);
wattroff(self->window, A_BOLD);
if (f_selected) {
if (f_selected)
wattroff(self->window, COLOR_PAIR(BLUE));
}
pthread_mutex_lock(&Winthread.lock);
time_t last_seen = Friends.list[f].last_online.last_on;
@ -1178,17 +1095,15 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
int i;
for (i = 0; i < TOX_PUBLIC_KEY_SIZE; ++i) {
for (i = 0; i < TOX_PUBLIC_KEY_SIZE; ++i)
wprintw(self->window, "%02X", Friends.list[selected_num].pub_key[i] & 0xff);
}
}
wnoutrefresh(self->window);
wrefresh(self->window);
draw_del_popup();
if (self->help->active) {
if (self->help->active)
help_onDraw(self);
}
}
void disable_chatwin(uint32_t f_num)
@ -1201,9 +1116,8 @@ static void friendlist_onAV(ToxWindow *self, ToxAV *av, uint32_t friend_number,
{
assert(0);
if (friend_number >= Friends.max_idx) {
if ( friend_number >= Friends.max_idx)
return;
}
assert(0);
Tox *m = toxav_get_tox(av);
@ -1212,7 +1126,7 @@ static void friendlist_onAV(ToxWindow *self, ToxAV *av, uint32_t friend_number,
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
if (state != TOXAV_FRIEND_CALL_STATE_FINISHED) {
Friends.list[friend_number].chatwin = add_window(m, new_chat(m, Friends.list[friend_number].num));
set_active_window_index(Friends.list[friend_number].chatwin);
set_active_window(Friends.list[friend_number].chatwin);
}
} else {
char nick[TOX_MAX_NAME_LENGTH];
@ -1228,64 +1142,49 @@ static void friendlist_onAV(ToxWindow *self, ToxAV *av, uint32_t friend_number,
}
#endif /* AUDIO */
/* Returns a friend's status */
Tox_User_Status get_friend_status(uint32_t friendnumber)
ToxWindow new_friendlist(void)
{
return Friends.list[friendnumber].status;
}
ToxWindow ret;
memset(&ret, 0, sizeof(ret));
/* Returns a friend's connection status */
Tox_Connection get_friend_connection_status(uint32_t friendnumber)
{
return Friends.list[friendnumber].connection_status;
}
ret.active = true;
ret.is_friendlist = true;
ToxWindow *new_friendlist(void)
{
ToxWindow *ret = calloc(1, sizeof(ToxWindow));
if (ret == NULL) {
exit_toxic_err("failed in new_friendlist", FATALERR_MEMORY);
}
ret->is_friendlist = true;
ret->onKey = &friendlist_onKey;
ret->onDraw = &friendlist_onDraw;
ret->onFriendAdded = &friendlist_onFriendAdded;
ret->onMessage = &friendlist_onMessage;
ret->onConnectionChange = &friendlist_onConnectionChange;
ret->onNickChange = &friendlist_onNickChange;
ret->onStatusChange = &friendlist_onStatusChange;
ret->onStatusMessageChange = &friendlist_onStatusMessageChange;
ret->onFileRecv = &friendlist_onFileRecv;
ret->onGroupInvite = &friendlist_onGroupInvite;
ret.onKey = &friendlist_onKey;
ret.onDraw = &friendlist_onDraw;
ret.onFriendAdded = &friendlist_onFriendAdded;
ret.onMessage = &friendlist_onMessage;
ret.onConnectionChange = &friendlist_onConnectionChange;
ret.onNickChange = &friendlist_onNickChange;
ret.onStatusChange = &friendlist_onStatusChange;
ret.onStatusMessageChange = &friendlist_onStatusMessageChange;
ret.onFileRecv = &friendlist_onFileRecv;
ret.onGroupInvite = &friendlist_onGroupInvite;
#ifdef AUDIO
ret->onInvite = &friendlist_onAV;
ret->onRinging = &friendlist_onAV;
ret->onStarting = &friendlist_onAV;
ret->onEnding = &friendlist_onAV;
ret->onError = &friendlist_onAV;
ret->onStart = &friendlist_onAV;
ret->onCancel = &friendlist_onAV;
ret->onReject = &friendlist_onAV;
ret->onEnd = &friendlist_onAV;
ret.onInvite = &friendlist_onAV;
ret.onRinging = &friendlist_onAV;
ret.onStarting = &friendlist_onAV;
ret.onEnding = &friendlist_onAV;
ret.onError = &friendlist_onAV;
ret.onStart = &friendlist_onAV;
ret.onCancel = &friendlist_onAV;
ret.onReject = &friendlist_onAV;
ret.onEnd = &friendlist_onAV;
ret->is_call = false;
ret->device_selection[0] = ret->device_selection[1] = -1;
ret.is_call = false;
ret.device_selection[0] = ret.device_selection[1] = -1;
#endif /* AUDIO */
ret->num = -1;
ret->active_box = -1;
ret.num = -1;
ret.active_box = -1;
Help *help = calloc(1, sizeof(Help));
if (help == NULL) {
if (help == NULL)
exit_toxic_err("failed in new_friendlist", FATALERR_MEMORY);
}
ret->help = help;
strcpy(ret->name, "contacts");
ret.help = help;
strcpy(ret.name, "contacts");
return ret;
}

View File

@ -35,29 +35,27 @@ struct LastOnline {
char hour_min_str[TIME_STR_SIZE]; /* holds 12/24-hour time string e.g. "10:43 PM" */
};
struct GroupChatInvite {
char *key;
struct GroupInvite {
uint8_t *data;
uint16_t length;
uint8_t type;
bool pending;
};
typedef struct {
char name[TOXIC_MAX_NAME_LENGTH + 1];
uint16_t namelength;
int namelength;
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
size_t statusmsg_len;
char pub_key[TOX_PUBLIC_KEY_SIZE];
uint32_t num;
int chatwin;
bool active;
Tox_Connection connection_status;
TOX_CONNECTION connection_status;
bool is_typing;
bool logging_on; /* saves preference for friend irrespective of global settings */
Tox_User_Status status;
uint8_t status;
struct LastOnline last_online;
struct GroupChatInvite group_invite;
struct GroupInvite group_invite;
struct FileTransfer file_receiver[MAX_FILES];
struct FileTransfer file_sender[MAX_FILES];
@ -65,7 +63,7 @@ typedef struct {
typedef struct {
char name[TOXIC_MAX_NAME_LENGTH + 1];
uint16_t namelength;
int namelength;
char pub_key[TOX_PUBLIC_KEY_SIZE];
uint32_t num;
bool active;
@ -81,14 +79,12 @@ typedef struct {
ToxicFriend *list;
} FriendsList;
ToxWindow *new_friendlist(void);
ToxWindow new_friendlist(void);
void disable_chatwin(uint32_t f_num);
int get_friendnum(uint8_t *name);
int load_blocklist(char *data);
void kill_friendlist(ToxWindow *self);
void kill_friendlist(void);
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort);
Tox_User_Status get_friend_status(uint32_t friendnumber);
Tox_Connection get_friend_connection_status(uint32_t friendnumber);
/* sorts friendlist_index first by connection status then alphabetically */
void sort_friendlist_index(void);

View File

@ -41,6 +41,7 @@
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])
@ -62,7 +63,7 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
return;
}
Tox_Err_Friend_Add err;
TOX_ERR_FRIEND_ADD err;
uint32_t friendnum = tox_friend_add_norequest(m, FrndRequests.request[req].key, &err);
if (err != TOX_ERR_FRIEND_ADD_OK) {
@ -70,7 +71,7 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
return;
} else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Friend request accepted.");
on_friend_added(m, friendnum, true);
on_friendadded(m, friendnum, true);
}
memset(&FrndRequests.request[req], 0, sizeof(struct friend_request));
@ -78,9 +79,8 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
int i;
for (i = FrndRequests.max_idx; i > 0; --i) {
if (FrndRequests.request[i - 1].active) {
if (FrndRequests.request[i - 1].active)
break;
}
}
FrndRequests.max_idx = i;
@ -92,8 +92,8 @@ void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg
{
const char *errmsg;
Tox_Err_Friend_Add err;
uint32_t f_num = tox_friend_add(m, (const uint8_t *) id_bin, (const uint8_t *) msg, strlen(msg), &err);
TOX_ERR_FRIEND_ADD err;
uint32_t f_num = tox_friend_add(m, (uint8_t *) id_bin, (uint8_t *) msg, strlen(msg), &err);
switch (err) {
case TOX_ERR_FRIEND_ADD_TOO_LONG:
@ -126,7 +126,7 @@ void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg
case TOX_ERR_FRIEND_ADD_OK:
errmsg = "Friend request sent.";
on_friend_added(m, f_num, true);
on_friendadded(m, f_num, true);
break;
case TOX_ERR_FRIEND_ADD_NULL:
@ -201,15 +201,21 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc != 1 || strlen(argv[1]) < 3) {
if (argc < 2 || strlen(argv[1]) < 3) {
avatar_unset(m);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Avatar has been unset.");
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Avatar is not set.");
return;
}
if (argv[1][0] != '\"') {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Path must be enclosed in quotes.");
return;
}
/* remove opening and closing quotes */
char path[MAX_STR_SIZE];
snprintf(path, sizeof(path), "%s", argv[1]);
int len = strlen(path);
snprintf(path, sizeof(path), "%s", &argv[1][1]);
int len = strlen(path) - 1;
if (len <= 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid path.");
@ -261,7 +267,7 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
return;
}
Tox_Err_Bootstrap err;
TOX_ERR_BOOTSTRAP err;
tox_bootstrap(m, ip, port, (uint8_t *) key_binary, &err);
tox_add_tcp_relay(m, ip, port, (uint8_t *) key_binary, &err);
@ -307,9 +313,8 @@ void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
int i;
for (i = FrndRequests.max_idx; i > 0; --i) {
if (FrndRequests.request[i - 1].active) {
if (FrndRequests.request[i - 1].active)
break;
}
}
FrndRequests.max_idx = i;
@ -324,42 +329,133 @@ void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
}
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Please specify group type: text | audio");
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group name required");
return;
}
uint8_t type;
const char *tmp_name = argv[1];
int len = strlen(tmp_name);
if (!strcasecmp(argv[1], "audio")) {
type = TOX_CONFERENCE_TYPE_AV;
} else if (!strcasecmp(argv[1], "text")) {
type = TOX_CONFERENCE_TYPE_TEXT;
if (len == 0 || len > TOX_GROUP_MAX_GROUP_NAME_LENGTH) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid group name.");
return;
}
char name[TOX_GROUP_MAX_GROUP_NAME_LENGTH];
if (argv[1][0] == '\"') { /* remove opening and closing quotes */
snprintf(name, sizeof(name), "%s", &argv[1][1]);
len -= 2;
name[len] = '\0';
} else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Valid group types are: text | audio");
snprintf(name, sizeof(name), "%s", argv[1]);
}
TOX_ERR_GROUP_NEW err;
uint32_t groupnum = tox_group_new(m, TOX_GROUP_PRIVACY_STATE_PUBLIC, (uint8_t *) name, len, &err);
if (err != TOX_ERR_GROUP_NEW_OK) {
switch (err) {
case TOX_ERR_GROUP_NEW_TOO_LONG: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group name length cannot exceed %d.",
TOX_GROUP_MAX_GROUP_NAME_LENGTH);
break;
}
case TOX_ERR_GROUP_NEW_EMPTY: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group name cannot be empty.");
break;
}
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize (error %d).", err);
break;
}
}
return;
}
if (type != TOX_CONFERENCE_TYPE_TEXT) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Toxic does not support audio groups.");
return;
}
int init = init_groupchat_win(m, groupnum, name, len);
Tox_Err_Conference_New err;
uint32_t groupnum = tox_conference_new(m, &err);
if (err != TOX_ERR_CONFERENCE_NEW_OK) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize (error %d)", err);
return;
}
if (init_groupchat_win(prompt, m, groupnum, type) == -1) {
if (init == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
tox_conference_delete(m, groupnum, NULL);
tox_group_leave(m, groupnum, NULL, 0, NULL);
} else if (init == -2) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
"You have been kicked from a group. Close the window and try again.");
tox_group_leave(m, groupnum, NULL, 0, NULL);
}
}
void cmd_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open.");
return;
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat [%d] created.", groupnum);
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Chat ID is required.");
return;
}
const char *chat_id = argv[1];
if (strlen(chat_id) != TOX_GROUP_CHAT_ID_SIZE * 2) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid chat ID");
return;
}
char id_bin[TOX_GROUP_CHAT_ID_SIZE] = {0};
size_t i;
char xch[3];
uint32_t x;
for (i = 0; i < TOX_GROUP_CHAT_ID_SIZE; ++i) {
xch[0] = chat_id[2 * i];
xch[1] = chat_id[2 * i + 1];
xch[2] = '\0';
if (sscanf(xch, "%02x", &x) != 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid chat ID.");
return;
}
id_bin[i] = x;
}
const char *passwd = NULL;
uint16_t passwd_len = 0;
if (argc > 1) {
passwd = argv[2];
passwd_len = strlen(passwd);
}
TOX_ERR_GROUP_JOIN err;
uint32_t groupnum = tox_group_join(m, (uint8_t *) id_bin, (uint8_t *) passwd, passwd_len, &err);
if (err != TOX_ERR_GROUP_JOIN_OK) {
if (err == TOX_ERR_GROUP_JOIN_TOO_LONG)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Password length cannot exceed %d.", TOX_GROUP_MAX_PASSWORD_SIZE);
else
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to join group (error %d).", err);
return;
}
int init = init_groupchat_win(m, groupnum, NULL, 0);
if (init == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
tox_group_leave(m, groupnum, NULL, 0, NULL);
} else if (init == -2) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
"You have been kicked from a group. Close the window and try again.");
tox_group_leave(m, groupnum, NULL, 0, NULL);
}
}
void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
@ -368,11 +464,10 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
struct chatlog *log = self->chatwin->log;
if (argc == 0) {
if (log->log_on) {
if (log->log_on)
msg = "Logging for this window is ON; type \"/log off\" to disable. (Logs are not encrypted)";
} else {
else
msg = "Logging for this window is OFF; type \"/log on\" to enable.";
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
return;
@ -399,9 +494,8 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
return;
} else if (!strcmp(swch, "0") || !strcmp(swch, "off")) {
if (self->is_chat) {
if (self->is_chat)
Friends.list[self->num].logging_on = false;
}
log_disable(log);
@ -428,7 +522,6 @@ void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", id_string);
}
#ifdef QRCODE
void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
char id_string[TOX_ADDRESS_SIZE * 2 + 1];
@ -486,7 +579,6 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
#endif /* QRPNG */
}
#endif /* QRCODE */
void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
@ -496,8 +588,16 @@ void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
}
char nick[MAX_STR_SIZE];
snprintf(nick, sizeof(nick), "%s", argv[1]);
size_t len = strlen(nick);
size_t len = 0;
if (argv[1][0] == '\"') { /* remove opening and closing quotes */
snprintf(nick, sizeof(nick), "%s", &argv[1][1]);
len = strlen(nick) - 1;
nick[len] = '\0';
} else {
snprintf(nick, sizeof(nick), "%s", argv[1]);
len = strlen(nick);
}
if (!valid_nick(nick)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid name.");
@ -509,6 +609,7 @@ void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
tox_self_set_name(m, (uint8_t *) nick, len, NULL);
prompt_update_nick(prompt, nick);
set_nick_all_groups(m, nick, len);
store_data(m, DATA_FILE);
}
@ -569,9 +670,8 @@ void cmd_requests(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
int count = 0;
for (i = 0; i < FrndRequests.max_idx; ++i) {
if (!FrndRequests.request[i].active) {
if (!FrndRequests.request[i].active)
continue;
}
char id[TOX_PUBLIC_KEY_SIZE * 2 + 1] = {0};
@ -584,34 +684,36 @@ void cmd_requests(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%d : %s", i, id);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", FrndRequests.request[i].msg);
if (++count < FrndRequests.num_requests) {
if (++count < FrndRequests.num_requests)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
}
}
}
void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
bool have_note = false;
const char *errmsg;
lock_status();
lock_status ();
if (argc < 1) {
if (argc >= 2) {
have_note = true;
} else if (argc < 1) {
errmsg = "Require a status. Statuses are: online, busy and away.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
goto finish;
}
const char *status_str = argv[1];
Tox_User_Status status;
TOX_USER_STATUS status;
if (!strcasecmp(status_str, "online")) {
if (!strcasecmp(status_str, "online"))
status = TOX_USER_STATUS_NONE;
} else if (!strcasecmp(status_str, "away")) {
else if (!strcasecmp(status_str, "away"))
status = TOX_USER_STATUS_AWAY;
} else if (!strcasecmp(status_str, "busy")) {
else if (!strcasecmp(status_str, "busy"))
status = TOX_USER_STATUS_BUSY;
} else {
else {
errmsg = "Invalid status. Valid statuses are: online, busy and away.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
goto finish;
@ -619,9 +721,23 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
tox_self_set_status(m, status);
prompt_update_status(prompt, status);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Your status has been changed to %s.", status_str);
set_status_all_groups(m, status);
if (have_note) {
if (argv[2][0] != '\"') {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Note must be enclosed in quotes.");
goto finish;
}
/* remove opening and closing quotes */
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "%s", &argv[2][1]);
int len = strlen(msg) - 1;
msg[len] = '\0';
prompt_update_statusmessage(prompt, m, msg);
}
finish:
unlock_status();
unlock_status ();
}

View File

@ -33,11 +33,10 @@ void cmd_clear(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE
void cmd_connect(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_groupchat(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_log(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_myid(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
#ifdef QRCODE
void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
#endif /* QRCODE */
void cmd_nick(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_note(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
@ -58,8 +57,4 @@ void cmd_list_video_devices(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)
void cmd_change_video_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
#endif /* VIDEO */
#ifdef PYTHON
void cmd_run(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
#endif /* PYTHON */
#endif /* GLOBAL_COMMANDS_H */
#endif /* #define GLOBAL_COMMANDS_H */

View File

@ -21,59 +21,707 @@
*/
#include <string.h>
#include <stdlib.h>
#include "toxic.h"
#include "windows.h"
#include "line_info.h"
#include "misc_tools.h"
#include "log.h"
#include "groupchat.h"
void cmd_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
extern GroupChat groupchats[MAX_GROUPCHAT_NUM];
void cmd_chatid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
Tox_Err_Conference_Title err;
char title[MAX_STR_SIZE];
char chatid[TOX_GROUP_CHAT_ID_SIZE * 2 + 1] = {0};
char chat_public_key[TOX_GROUP_CHAT_ID_SIZE];
TOX_ERR_GROUP_STATE_QUERIES err;
if (!tox_group_get_chat_id(m, self->num, (uint8_t *) chat_public_key, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve the Chat ID (error %d).", err);
return;
}
size_t i;
for (i = 0; i < TOX_GROUP_CHAT_ID_SIZE; ++i) {
char xx[3];
snprintf(xx, sizeof(xx), "%02X", chat_public_key[i] & 0xff);
strcat(chatid, xx);
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", chatid);
}
void cmd_ignore(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 1) {
size_t tlen = tox_conference_get_title_size(m, self->num, &err);
if (err != TOX_ERR_CONFERENCE_TITLE_OK) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title is not set");
return;
}
if (!tox_conference_get_title(m, self->num, (uint8_t *) title, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title is not set");
return;
}
title[tlen] = '\0';
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title is set to: %s", title);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer name must be specified.");
return;
}
snprintf(title, sizeof(title), "%s", argv[1]);
int len = strlen(title);
const char *nick = argv[1];
uint32_t peer_id;
if (!tox_conference_set_title(m, self->num, (uint8_t *) title, len, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title (error %d)", err);
if (group_get_nick_peer_id(self->num, nick, &peer_id) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid peer name '%s'.", nick);
return;
}
set_window_title(self, title, len);
TOX_ERR_GROUP_TOGGLE_IGNORE err;
if (!tox_group_toggle_ignore(m, self->num, peer_id, true, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to ignore %s (error %d).", nick, err);
return;
}
char timefrmt[TIME_STR_SIZE];
char selfnick[TOX_MAX_NAME_LENGTH];
get_time_str(timefrmt, sizeof(timefrmt));
tox_self_get_name(m, (uint8_t *) selfnick);
size_t sn_len = tox_self_get_name_size(m);
line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 1, BLUE, "-!- Ignoring %s", nick);
}
static void cmd_kickban_helper(ToxWindow *self, Tox *m, const char *nick, bool set_ban)
{
uint32_t peer_id;
if (group_get_nick_peer_id(self->num, nick, &peer_id) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid peer name '%s'.", nick);
return;
}
const char *type_str = set_ban ? "ban" : "kick";
TOX_ERR_GROUP_MOD_REMOVE_PEER err;
tox_group_mod_remove_peer(m, self->num, peer_id, set_ban, &err);
switch (err) {
case TOX_ERR_GROUP_MOD_REMOVE_PEER_OK: {
return;
}
case TOX_ERR_GROUP_MOD_REMOVE_PEER_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to %s %s.", type_str, nick);
return;
}
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to %s %s from the group (error %d).", type_str, nick,
err);
return;
}
}
}
void cmd_kick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer name must be specified.");
return;
}
cmd_kickban_helper(self, m, argv[1], false);
}
void cmd_ban(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
TOX_ERR_GROUP_BAN_QUERY err;
if (argc < 1) {
size_t num_banned = tox_group_ban_get_list_size(m, self->num, &err);
if (err != TOX_ERR_GROUP_BAN_QUERY_OK) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to get the ban list size (error %d).", err);
return;
}
if (num_banned == 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ban list is empty.");
return;
}
uint32_t ban_list[num_banned];
if (!tox_group_ban_get_list(m, self->num, ban_list, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to get the ban list (error %d).", err);
return;
}
uint16_t i;
for (i = 0; i < num_banned; ++i) {
uint32_t id = ban_list[i];
size_t len = tox_group_ban_get_name_size(m, self->num, id, &err);
if (err != TOX_ERR_GROUP_BAN_QUERY_OK) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve name length for ban %d (error %d).", id, err);
continue;
}
char tmp_nick[len];
if (!tox_group_ban_get_name(m, self->num, id, (uint8_t *) tmp_nick, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve name for ban %d (error %d).", id, err);
continue;
}
char nick[len + 1];
copy_tox_str(nick, sizeof(nick), tmp_nick, len);
uint64_t time_set = tox_group_ban_get_time_set(m, self->num, id, &err);
if (err != TOX_ERR_GROUP_BAN_QUERY_OK) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve timestamp for ban %d (error %d).", id, err);
continue;
}
struct tm tm_set = *localtime((const time_t *) &time_set);
char time_str[64];
strftime(time_str, sizeof(time_str), "%e %b %Y %H:%M:%S%p", &tm_set);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "ID %d : %s [Set:%s]", id, nick, time_str);
}
return;
}
cmd_kickban_helper(self, m, argv[1], true);
}
void cmd_unban(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ban ID must be specified.");
return;
}
int ban_id = atoi(argv[1]);
if (ban_id == 0 && strcmp(argv[1], "0")) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ban ID must be a non-negative interger.");
return;
}
TOX_ERR_GROUP_MOD_REMOVE_BAN err;
tox_group_mod_remove_ban(m, self->num, ban_id, &err);
switch (err) {
case TOX_ERR_GROUP_MOD_REMOVE_BAN_OK: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ban list entry with id %d has been removed.", ban_id);
return;
}
case TOX_ERR_GROUP_MOD_REMOVE_BAN_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to unban peers.");
return;
}
case TOX_ERR_GROUP_MOD_REMOVE_BAN_FAIL_ACTION: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ban ID does not exist.");
return;
}
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to remove ban list entry (error %d).", err);
return;
}
}
}
void cmd_mod(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer name must be specified.");
return;
}
const char *nick = argv[1];
uint32_t peer_id;
if (group_get_nick_peer_id(self->num, nick, &peer_id) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid peer name '%s'.", nick);
return;
}
TOX_ERR_GROUP_MOD_SET_ROLE err;
tox_group_mod_set_role(m, self->num, peer_id, TOX_GROUP_ROLE_MODERATOR, &err);
switch (err) {
case TOX_ERR_GROUP_MOD_SET_ROLE_OK: {
return;
}
case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to promote moderators.");
return;
}
case TOX_ERR_GROUP_MOD_SET_ROLE_ASSIGNMENT: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "This peer is already a moderator.");
return;
}
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to promote peer to moderator (error %d).", err);
return;
}
}
}
void cmd_unmod(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer name must be specified.");
return;
}
const char *nick = argv[1];
uint32_t peer_id;
if (group_get_nick_peer_id(self->num, nick, &peer_id) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid peer name '%s'.", nick);
return;
}
if (tox_group_peer_get_role(m, self->num, peer_id, NULL) != TOX_GROUP_ROLE_MODERATOR) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s is not a moderator", nick);
return;
}
TOX_ERR_GROUP_MOD_SET_ROLE err;
tox_group_mod_set_role(m, self->num, peer_id, TOX_GROUP_ROLE_USER, &err);
switch (err) {
case TOX_ERR_GROUP_MOD_SET_ROLE_OK: {
return;
}
case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Nice try.");
return;
}
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to revoke moderator powers from %s (error %d).", nick,
err);
return;
}
}
}
void cmd_mykey(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
char pk_string[TOX_GROUP_PEER_PUBLIC_KEY_SIZE * 2 + 1] = {0};
char pk[TOX_GROUP_PEER_PUBLIC_KEY_SIZE];
TOX_ERR_GROUP_SELF_QUERY err;
if (!tox_group_self_get_public_key(m, self->num, (uint8_t *) pk, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to fetch your public key (error %d)", err);
return;
}
size_t i;
for (i = 0; i < TOX_GROUP_PEER_PUBLIC_KEY_SIZE; ++i) {
char d[3];
snprintf(d, sizeof(d), "%02X", pk[i] & 0xff);
strcat(pk_string, d);
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", pk_string);
}
void cmd_set_passwd(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
const char *passwd = NULL;
size_t len = 0;
if (argc > 0) {
passwd = argv[1];
len = strlen(passwd);
}
TOX_ERR_GROUP_FOUNDER_SET_PASSWORD err;
tox_group_founder_set_password(m, self->num, (uint8_t *) passwd, len, &err);
switch (err) {
case TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_OK: {
if (len > 0)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Password has been set to %s.", passwd);
else
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Password has been unset.");
return;
}
case TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_TOO_LONG: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Password length must not exceed %d.",
TOX_GROUP_MAX_PASSWORD_SIZE);
return;
}
case TOX_ERR_GROUP_FOUNDER_SET_PASSWORD_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the password.");
return;
}
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set password (error %d).", err);
return;
}
}
}
void cmd_set_peerlimit(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
int maxpeers = 0;
if (argc < 1) {
TOX_ERR_GROUP_STATE_QUERIES err;
uint32_t maxpeers = tox_group_get_peer_limit(m, self->num, &err);
if (err != TOX_ERR_GROUP_STATE_QUERIES_OK) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve peer limit (error %d).", err);
return;
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer limit is set to %d", maxpeers);
return;
}
maxpeers = atoi(argv[1]);
if (maxpeers <= 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer limit must be a value greater than 0.");
return;
}
TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT err;
tox_group_founder_set_peer_limit(m, self->num, maxpeers, &err);
switch (err) {
case TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_OK: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer limit has been set to %d.", maxpeers);
return;
}
case TOX_ERR_GROUP_FOUNDER_SET_PEER_LIMIT_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the peer limit.");
return;
}
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set the peer limit (error %d).", err);
return;
}
}
}
void cmd_set_privacy(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
const char *pstate_str = NULL;
TOX_GROUP_PRIVACY_STATE privacy_state;
if (argc < 1) {
TOX_ERR_GROUP_STATE_QUERIES err;
privacy_state = tox_group_get_privacy_state(m, self->num, &err);
if (err != TOX_ERR_GROUP_STATE_QUERIES_OK) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve privacy state (error %d).", err);
return;
}
pstate_str = privacy_state == TOX_GROUP_PRIVACY_STATE_PRIVATE ? "private" : "public";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Privacy state is set to %s.", pstate_str);
return;
}
pstate_str = argv[1];
if (strcasecmp(pstate_str, "private") != 0 && strcasecmp(pstate_str, "public") != 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Privacy state must be \"private\" or \"public\".");
return;
}
privacy_state = strcasecmp(pstate_str,
"private") == 0 ? TOX_GROUP_PRIVACY_STATE_PRIVATE : TOX_GROUP_PRIVACY_STATE_PUBLIC;
TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE err;
tox_group_founder_set_privacy_state(m, self->num, privacy_state, &err);
switch (err) {
case TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_OK: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Privacy state has been set to %s.", pstate_str);
return;
}
case TOX_ERR_GROUP_FOUNDER_SET_PRIVACY_STATE_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the privacy state.");
return;
}
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error setting privacy state (error %d).", err);
return;
}
}
}
void cmd_silence(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer name must be specified.");
return;
}
const char *nick = argv[1];
uint32_t peer_id;
if (group_get_nick_peer_id(self->num, nick, &peer_id) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid peer name '%s'.", nick);
return;
}
TOX_ERR_GROUP_MOD_SET_ROLE err;
tox_group_mod_set_role(m, self->num, peer_id, TOX_GROUP_ROLE_OBSERVER, &err);
switch (err) {
case TOX_ERR_GROUP_MOD_SET_ROLE_OK: {
return;
}
case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to silence %s.", nick);
return;
}
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to silence %s (error %d).", nick, err);
return;
}
}
}
void cmd_unsilence(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer name must be specified.");
return;
}
const char *nick = argv[1];
uint32_t peer_id;
if (group_get_nick_peer_id(self->num, nick, &peer_id) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid peer name '%s'.", nick);
return;
}
if (tox_group_peer_get_role(m, self->num, peer_id, NULL) != TOX_GROUP_ROLE_OBSERVER) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s is not silenced.", nick);
return;
}
TOX_ERR_GROUP_MOD_SET_ROLE err;
tox_group_mod_set_role(m, self->num, peer_id, TOX_GROUP_ROLE_USER, &err);
switch (err) {
case TOX_ERR_GROUP_MOD_SET_ROLE_OK: {
return;
}
case TOX_ERR_GROUP_MOD_SET_ROLE_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to unsilence %s.", nick);
return;
}
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to unsilence %s (error %d).", nick, err);
return;
}
}
}
void cmd_rejoin(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
TOX_ERR_GROUP_RECONNECT err;
if (!tox_group_reconnect(m, self->num, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to rejoin group (error %d).", err);
return;
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Reconnecting to group...");
}
void cmd_set_topic(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 1) {
TOX_ERR_GROUP_STATE_QUERIES err;
size_t tlen = tox_group_get_topic_size(m, self->num, &err);
if (err != TOX_ERR_GROUP_STATE_QUERIES_OK) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve topic length (error %d).", err);
return;
}
if (tlen > 0) {
char cur_topic[tlen];
if (!tox_group_get_topic(m, self->num, (uint8_t *) cur_topic, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve topic (error %d).", err);
return;
}
cur_topic[tlen] = '\0';
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Topic is set to: %s", cur_topic);
} else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Topic is not set.");
}
return;
}
const char *topic = argv[1];
TOX_ERR_GROUP_TOPIC_SET err;
tox_group_set_topic(m, self->num, (uint8_t *) topic, strlen(topic), &err);
switch (err) {
case TOX_ERR_GROUP_TOPIC_SET_OK: {
/* handled below switch */
break;
}
case TOX_ERR_GROUP_TOPIC_SET_TOO_LONG: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Topic length must not exceed %d.", TOX_GROUP_MAX_TOPIC_LENGTH);
return;
}
case TOX_ERR_GROUP_TOPIC_SET_PERMISSIONS: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "You do not have permission to set the topic.");
return;
}
default: {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set the topic (error %d).", err);
return;
}
}
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
TOX_ERR_GROUP_SELF_QUERY sn_err;
size_t sn_len = tox_group_self_get_name_size(m, self->num, &sn_err);
char selfnick[sn_len];
if (!tox_group_self_get_name(m, self->num, (uint8_t *) selfnick, &sn_err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to retrieve your own name (error %d).", sn_err);
return;
}
selfnick[sn_len] = '\0';
line_info_add(self, timefrmt, selfnick, NULL, NAME_CHANGE, 0, 0, " set the group title to: %s", title);
line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 1, MAGENTA, "-!- You set the topic to: %s", topic);
char tmp_event[MAX_STR_SIZE];
snprintf(tmp_event, sizeof(tmp_event), "set title to %s", title);
snprintf(tmp_event, sizeof(tmp_event), "set topic to %s", topic);
write_to_log(tmp_event, selfnick, self->chatwin->log, true);
}
void cmd_unignore(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer must be specified.");
return;
}
const char *nick = argv[1];
uint32_t peer_id;
if (group_get_nick_peer_id(self->num, nick, &peer_id) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid peer name '%s'.", nick);
return;
}
TOX_ERR_GROUP_TOGGLE_IGNORE err;
if (!tox_group_toggle_ignore(m, self->num, peer_id, false, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to unignore %s (error %d).", nick, err);
return;
}
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 1, BLUE, "-!- You are no longer ignoring %s", nick);
}
void cmd_whois(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer must be specified.");
return;
}
GroupChat *chat = &groupchats[self->num];
if (!chat) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Whois failed.");
return;
}
const char *nick = argv[1];
uint32_t peer_id;
if (group_get_nick_peer_id(self->num, nick, &peer_id) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid peer name '%s'.", nick);
return;
}
int peer_index = get_peer_index(self->num, peer_id);
if (peer_index < 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Whois failed.");
return;
}
const char *status_str = "Online";
if (chat->peer_list[peer_index].status == TOX_USER_STATUS_BUSY)
status_str = "Busy";
else if (chat->peer_list[peer_index].status == TOX_USER_STATUS_AWAY)
status_str = "Away";
const char *role_str = "User";
if (chat->peer_list[peer_index].role == TOX_GROUP_ROLE_FOUNDER)
role_str = "Founder";
else if (chat->peer_list[peer_index].role == TOX_GROUP_ROLE_MODERATOR)
role_str = "Moderator";
else if (chat->peer_list[peer_index].role == TOX_GROUP_ROLE_OBSERVER)
role_str = "Observer";
char last_seen_str[128];
get_elapsed_time_str_2(last_seen_str, sizeof(last_seen_str), get_unix_time() - chat->peer_list[peer_index].last_active);
char pk_string[TOX_GROUP_PEER_PUBLIC_KEY_SIZE * 2 + 1] = {0};
size_t i;
for (i = 0; i < TOX_GROUP_PEER_PUBLIC_KEY_SIZE; ++i) {
char d[3];
snprintf(d, sizeof(d), "%02X", chat->peer_list[peer_index].public_key[i] & 0xff);
strcat(pk_string, d);
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Whois for %s", nick);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Role: %s", role_str);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Status: %s", status_str);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Last active: %s", last_seen_str);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Public key: %s", pk_string);
}

View File

@ -26,6 +26,23 @@
#include "windows.h"
#include "toxic.h"
void cmd_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_ban(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_chatid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_ignore(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_kick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_mod(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_mykey(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_prune(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_set_passwd(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_set_peerlimit(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_set_privacy(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_rejoin(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_set_topic(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_silence(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_unsilence(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_unban(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_unignore(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_unmod(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_whois(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
#endif /* GROUP_COMMANDS_H */
#endif /* GROUP_COMMANDS_H */

File diff suppressed because it is too large Load Diff

View File

@ -31,36 +31,37 @@
#define MAX_GROUPCHAT_NUM MAX_WINDOWS_NUM - 2
#define GROUP_EVENT_WAIT 3
typedef struct GroupPeer {
struct GroupPeer {
bool active;
char name[TOX_MAX_NAME_LENGTH];
size_t name_length;
uint32_t peernumber;
} GroupPeer;
uint32_t peer_id;
uint8_t public_key[TOX_GROUP_PEER_PUBLIC_KEY_SIZE];
TOX_USER_STATUS status;
TOX_GROUP_ROLE role;
uint64_t last_active;
};
typedef struct {
int chatwin;
bool active;
uint8_t type;
int side_pos; /* current position of the sidebar - used for scrolling up and down */
time_t start_time;
GroupPeer *peer_list;
size_t max_idx;
char *name_list;
size_t num_peers;
struct GroupPeer *peer_list;
char *name_list; /* List of peer names, needed for tab completion */
uint32_t num_peers; /* Number of peers in the chat/name_list array */
uint32_t max_idx; /* Maximum peer list index - 1 */
uint32_t groupnumber;
int chatwin;
bool active;
uint64_t time_connected; /* The time we successfully connected to the group */
int side_pos; /* current position of the sidebar - used for scrolling up and down */
} GroupChat;
/* Frees all Toxic associated data structures for a groupchat (does not call tox_conference_delete() ) */
void free_groupchat(ToxWindow *self, Tox *m, uint32_t groupnum);
void close_groupchat(ToxWindow *self, Tox *m, uint32_t groupnum);
int init_groupchat_win(Tox *m, uint32_t groupnum, const char *groupname, size_t length);
void set_nick_all_groups(Tox *m, const char *nick, size_t length);
void set_status_all_groups(Tox *m, uint8_t status);
int group_get_nick_peer_id(uint32_t groupnum, const char *nick, uint32_t *peer_id);
int get_peer_index(uint32_t groupnum, uint32_t peer_id);
int init_groupchat_win(ToxWindow *prompt, Tox *m, uint32_t groupnum, uint8_t type);
/* destroys and re-creates groupchat window with or without the peerlist */
/* destroys and re-creates groupchat window */
void redraw_groupchat_win(ToxWindow *self);
ToxWindow *new_group_chat(Tox *m, uint32_t groupnum);
#endif /* GROUPCHAT_H */
#endif /* #define GROUPCHAT_H */

View File

@ -27,29 +27,19 @@
#include "help.h"
#include "misc_tools.h"
#ifdef PYTHON
#include "api.h"
#endif /* PYTHON */
#ifdef PYTHON
#define HELP_MENU_HEIGHT 10
#else
#define HELP_MENU_HEIGHT 9
#endif /* PYTHON */
#define HELP_MENU_WIDTH 26
void help_init_menu(ToxWindow *self)
{
if (self->help->win) {
if (self->help->win)
delwin(self->help->win);
}
int y2, x2;
getmaxyx(self->window, y2, x2);
if (y2 < HELP_MENU_HEIGHT || x2 < HELP_MENU_WIDTH) {
if (y2 < HELP_MENU_HEIGHT || x2 < HELP_MENU_WIDTH)
return;
}
self->help->win = newwin(HELP_MENU_HEIGHT, HELP_MENU_WIDTH, 3, 3);
self->help->active = true;
@ -64,16 +54,14 @@ static void help_exit(ToxWindow *self)
static void help_init_window(ToxWindow *self, int height, int width)
{
if (self->help->win) {
if (self->help->win)
delwin(self->help->win);
}
int y2, x2;
getmaxyx(stdscr, y2, x2);
if (y2 <= 0 || x2 <= 0) {
if (y2 <= 0 || x2 <= 0)
return;
}
height = MIN(height, y2);
width = MIN(width, x2);
@ -107,13 +95,6 @@ static void help_draw_menu(ToxWindow *self)
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, "oup commands\n");
#ifdef PYTHON
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, " p");
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, "lugin commands\n");
#endif /* PYTHON */
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, " f");
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
@ -131,7 +112,7 @@ static void help_draw_menu(ToxWindow *self)
wprintw(win, "it menu\n");
box(win, ACS_VLINE, ACS_HLINE);
wnoutrefresh(win);
wrefresh(win);
}
static void help_draw_bottom_menu(WINDOW *win)
@ -172,18 +153,17 @@ static void help_draw_global(ToxWindow *self)
wprintw(win, " /connect <ip> <port> <key> : Manually connect to a DHT node\n");
wprintw(win, " /status <type> <msg> : Set status with optional note\n");
wprintw(win, " /note <msg> : Set a personal note\n");
wprintw(win, " /group : Create a group chat\n");
wprintw(win, " /join <chat id> <passwd> : Join a group chat with optional password\n");
wprintw(win, " /nick <nick> : Set your nickname\n");
wprintw(win, " /nospam <value> : Change part of your Tox ID to stop spam\n");
wprintw(win, " /log <on> or <off> : Enable/disable logging\n");
wprintw(win, " /group <type> : Create a group chat where type: text | audio\n");
wprintw(win, " /myid : Print your Tox ID\n");
#ifdef QRCODE
#ifdef QRPNG
wprintw(win, " /myqr <txt> or <png> : Print your Tox ID's QR code to a file.\n");
#else
wprintw(win, " /myqr : Print your Tox ID's QR code to a file.\n");
#endif /* QRPNG */
#endif /* QRCODE */
wprintw(win, " /clear : Clear window history\n");
wprintw(win, " /close : Close the current chat window\n");
wprintw(win, " /quit or /exit : Exit Toxic\n");
@ -206,18 +186,10 @@ static void help_draw_global(ToxWindow *self)
wprintw(win, " /svdev <type> <id> : Set active video device\n");
#endif /* VIDEO */
#ifdef PYTHON
wattron(win, A_BOLD);
wprintw(win, "\n Scripting:\n");
wattroff(win, A_BOLD);
wprintw(win, " /run <path> : Load and run the script at path\n");
#endif /* PYTHON */
help_draw_bottom_menu(win);
box(win, ACS_VLINE, ACS_HLINE);
wnoutrefresh(win);
wrefresh(win);
}
static void help_draw_chat(ToxWindow *self)
@ -230,8 +202,7 @@ static void help_draw_chat(ToxWindow *self)
wprintw(win, "Chat Commands:\n");
wattroff(win, A_BOLD | COLOR_PAIR(RED));
wprintw(win, " /invite <n> : Invite contact to a group chat\n");
wprintw(win, " /join : Join a pending group chat\n");
wprintw(win, " /gaccept <password> : Accept a group invite with optional password\n");
wprintw(win, " /sendfile <path> : Send a file\n");
wprintw(win, " /savefile <id> : Receive a file\n");
wprintw(win, " /cancel <type> <id> : Cancel file transfer where type: in|out\n");
@ -248,7 +219,6 @@ static void help_draw_chat(ToxWindow *self)
wprintw(win, " /sdev <type> <id> : Change active device\n");
wprintw(win, " /mute <type> : Mute active device if in call\n");
wprintw(win, " /sense <n> : VAD sensitivity threshold\n");
wprintw(win, " /bitrate <n> : Set the audio encoding bitrate\n");
#endif /* AUDIO */
#ifdef VIDEO
@ -261,7 +231,7 @@ static void help_draw_chat(ToxWindow *self)
help_draw_bottom_menu(win);
box(win, ACS_VLINE, ACS_HLINE);
wnoutrefresh(win);
wrefresh(win);
}
static void help_draw_keys(ToxWindow *self)
@ -287,7 +257,7 @@ static void help_draw_keys(ToxWindow *self)
help_draw_bottom_menu(win);
box(win, ACS_VLINE, ACS_HLINE);
wnoutrefresh(win);
wrefresh(win);
}
static void help_draw_group(ToxWindow *self)
@ -300,34 +270,39 @@ static void help_draw_group(ToxWindow *self)
wprintw(win, "Group commands:\n");
wattroff(win, A_BOLD | COLOR_PAIR(RED));
wprintw(win, " /title <msg> : Set group title (show current title if no msg)\n\n");
wprintw(win, " /chatid : Print the group chat id to share with others\n");
wprintw(win, " /mykey : Print your group public key\n");
wprintw(win, " /ignore <nick> : Ignore peer\n");
wprintw(win, " /unignore <nick> : Unignore peer \n");
wprintw(win, " /rejoin : Rejoin the group\n");
wprintw(win, " /topic <msg> : Set group topic (show current topic if no msg)\n");
wprintw(win, " /whisper <nick> <msg> : Send private message to nick\n");
wprintw(win, " /whois <nick> : Display info about nick.\n");
wattron(win, A_BOLD);
wprintw(win, " Moderator commands:\n");
wattroff(win, A_BOLD);
wprintw(win, " /kick <nick> : Kick peer\n");
wprintw(win, " /ban <nick> : Ban peer (leave nick blank to see ban list)\n");
wprintw(win, " /unban <Ban ID> : Unban entry\n");
wprintw(win, " /silence <nick> : Silences peer for the entire group\n");
wprintw(win, " /unsilence <nick> : Unsilences peer\n");
wattron(win, A_BOLD);
wprintw(win, " Founder commands:\n");
wattroff(win, A_BOLD);
wprintw(win, " /mod <nick> : Promote peer to moderator\n");
wprintw(win, " /unmod <nick> : Demote moderator to normal user\n");
wprintw(win, " /passwd <password> : Set group password (leave blank to unset)\n");
wprintw(win, " /peerlimit <num> : Set group peer limit\n");
wprintw(win, " /privacy <state> : Set group privacy state: private|public\n");
help_draw_bottom_menu(win);
box(win, ACS_VLINE, ACS_HLINE);
wnoutrefresh(win);
wrefresh(win);
}
#ifdef PYTHON
static void help_draw_plugin(ToxWindow *self)
{
WINDOW *win = self->help->win;
wmove(win, 1, 1);
wattron(win, A_BOLD | COLOR_PAIR(RED));
wprintw(win, "Plugin commands:\n");
wattroff(win, A_BOLD | COLOR_PAIR(RED));
draw_handler_help(win);
help_draw_bottom_menu(win);
box(win, ACS_VLINE, ACS_HLINE);
wnoutrefresh(win);
}
#endif /* PYTHON */
static void help_draw_contacts(ToxWindow *self)
{
WINDOW *win = self->help->win;
@ -347,13 +322,11 @@ static void help_draw_contacts(ToxWindow *self)
help_draw_bottom_menu(win);
box(win, ACS_VLINE, ACS_HLINE);
wnoutrefresh(win);
wrefresh(win);
}
void help_onKey(ToxWindow *self, wint_t key)
{
int height;
switch (key) {
case 'x':
case T_KEY_ESC:
@ -362,9 +335,9 @@ void help_onKey(ToxWindow *self, wint_t key)
case 'c':
#ifdef VIDEO
help_init_window(self, 23, 80);
help_init_window(self, 21, 80);
#elif AUDIO
help_init_window(self, 20, 80);
help_init_window(self, 18, 80);
#else
help_init_window(self, 10, 80);
#endif
@ -372,32 +345,21 @@ void help_onKey(ToxWindow *self, wint_t key)
break;
case 'g':
height = 22;
#ifdef VIDEO
height += 8;
help_init_window(self, 30, 80);
#elif AUDIO
height += 4;
help_init_window(self, 26, 80);
#else
help_init_window(self, 22, 80);
#endif
#ifdef PYTHON
height += 2;
#endif
help_init_window(self, height, 80);
self->help->type = HELP_GLOBAL;
break;
case 'r':
help_init_window(self, 6, 80);
help_init_window(self, 25, 80);
self->help->type = HELP_GROUP;
break;
#ifdef PYTHON
case 'p':
help_init_window(self, 4 + num_registered_handlers(), help_max_width());
self->help->type = HELP_PLUGIN;
break;
#endif /* PYTHON */
case 'f':
help_init_window(self, 10, 80);
self->help->type = HELP_CONTACTS;
@ -417,6 +379,8 @@ void help_onKey(ToxWindow *self, wint_t key)
void help_onDraw(ToxWindow *self)
{
curs_set(0);
switch (self->help->type) {
case HELP_MENU:
help_draw_menu(self);
@ -441,12 +405,5 @@ void help_onDraw(ToxWindow *self)
case HELP_GROUP:
help_draw_group(self);
break;
#ifdef PYTHON
case HELP_PLUGIN:
help_draw_plugin(self);
break;
#endif /* PYTHON */
}
}

View File

@ -33,13 +33,10 @@ typedef enum {
HELP_GROUP,
HELP_KEYS,
HELP_CONTACTS,
#ifdef PYTHON
HELP_PLUGIN,
#endif
} HELP_TYPES;
void help_onDraw(ToxWindow *self);
void help_init_menu(ToxWindow *self);
void help_onKey(ToxWindow *self, wint_t key);
#endif /* HELP_H */
#endif /* #define HELP_H */

View File

@ -43,9 +43,8 @@ void input_new_char(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_
ChatContext *ctx = self->chatwin;
/* this is the only place we need to do this check */
if (key == '\n') {
if (key == '\n')
key = L'';
}
int cur_len = wcwidth(key);
@ -78,19 +77,17 @@ static void input_backspace(ToxWindow *self, int x, int mx_x)
int cur_len = ctx->pos > 0 ? wcwidth(ctx->line[ctx->pos - 1]) : 0;
int s_len = ctx->start > 0 ? wcwidth(ctx->line[ctx->start - 1]) : 0;
if (ctx->start && (x >= mx_x - cur_len)) {
if (ctx->start && (x >= mx_x - cur_len))
ctx->start = MAX(0, ctx->start - 1 + (s_len - cur_len));
} else if (ctx->start) {
else if (ctx->start)
ctx->start = MAX(0, ctx->start - cur_len);
}
}
/* delete a char via delete key from input field and buffer */
static void input_delete(ToxWindow *self)
{
if (del_char_buf_frnt(self->chatwin) == -1) {
if (del_char_buf_frnt(self->chatwin) == -1)
sound_notify(self, notif_error, 0, NULL);
}
}
/* delete last typed word */
@ -107,17 +104,15 @@ static void input_del_word(ToxWindow *self, int x, int mx_x)
/* deletes entire line before cursor from input field and buffer */
static void input_discard(ToxWindow *self)
{
if (discard_buf(self->chatwin) == -1) {
if (discard_buf(self->chatwin) == -1)
sound_notify(self, notif_error, 0, NULL);
}
}
/* deletes entire line after cursor from input field and buffer */
static void input_kill(ChatContext *ctx)
{
if (kill_buf(ctx) == -1) {
if (kill_buf(ctx) == -1)
sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
}
}
static void input_yank(ToxWindow *self, int x, int mx_x)
@ -154,9 +149,8 @@ static void input_mv_home(ToxWindow *self)
{
ChatContext *ctx = self->chatwin;
if (ctx->pos <= 0) {
if (ctx->pos <= 0)
return;
}
ctx->pos = 0;
ctx->start = 0;
@ -167,20 +161,18 @@ static void input_mv_left(ToxWindow *self, int x, int mx_x)
{
ChatContext *ctx = self->chatwin;
if (ctx->pos <= 0) {
if (ctx->pos <= 0)
return;
}
int cur_len = ctx->pos > 0 ? wcwidth(ctx->line[ctx->pos - 1]) : 0;
int s_len = ctx->start > 0 ? wcwidth(ctx->line[ctx->start - 1]) : 0;
--ctx->pos;
if (ctx->start && (x >= mx_x - cur_len)) {
if (ctx->start && (x >= mx_x - cur_len))
ctx->start = MAX(0, ctx->start - 1 + (s_len - cur_len));
} else if (ctx->start) {
else if (ctx->start)
ctx->start = MAX(0, ctx->start - cur_len);
}
}
/* moves cursor/line position right in input field and buffer */
@ -188,9 +180,8 @@ static void input_mv_right(ToxWindow *self, int x, int mx_x)
{
ChatContext *ctx = self->chatwin;
if (ctx->pos >= ctx->len) {
if (ctx->pos >= ctx->len)
return;
}
++ctx->pos;

View File

@ -30,4 +30,4 @@ void input_new_char(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_
return true if key matches a function, false otherwise */
bool input_handle(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y);
#endif /* INPUT_H */
#endif /* #define INPUT_H */

View File

@ -40,9 +40,8 @@ void line_info_init(struct history *hst)
{
hst->line_root = calloc(1, sizeof(struct line_info));
if (hst->line_root == NULL) {
if (hst->line_root == NULL)
exit_toxic_err("failed in line_info_init", FATALERR_MEMORY);
}
hst->line_start = hst->line_root;
hst->line_end = hst->line_start;
@ -54,9 +53,8 @@ void line_info_reset_start(ToxWindow *self, struct history *hst)
{
struct line_info *line = hst->line_end;
if (line->prev == NULL) {
if (line->prev == NULL)
return;
}
int y2, x2;
getmaxyx(self->window, y2, x2);
@ -90,9 +88,8 @@ void line_info_cleanup(struct history *hst)
int i;
for (i = 0; i < hst->queue_sz; ++i) {
if (hst->queue[i]) {
if (hst->queue[i])
free(hst->queue[i]);
}
}
free(hst);
@ -117,46 +114,37 @@ static void line_info_root_fwd(struct history *hst)
/* returns ptr to queue item 0 and removes it from queue. Returns NULL if queue is empty. */
static struct line_info *line_info_ret_queue(struct history *hst)
{
if (hst->queue_sz <= 0) {
if (hst->queue_sz <= 0)
return NULL;
}
struct line_info *line = hst->queue[0];
int i;
for (i = 0; i < hst->queue_sz; ++i) {
for (i = 0; i < hst->queue_sz; ++i)
hst->queue[i] = hst->queue[i + 1];
}
--hst->queue_sz;
return line;
}
/* creates new line_info line and puts it in the queue.
*
* Returns the id of the new line.
* Returns -1 on failure.
*/
int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const char *name2, uint8_t type,
uint8_t bold, uint8_t colour, const char *msg, ...)
/* creates new line_info line and puts it in the queue. */
void line_info_add(ToxWindow *self, const char *timestr, const char *name1, const char *name2, uint8_t type,
uint8_t bold, uint8_t colour, const char *msg, ...)
{
if (!self) {
return -1;
}
if (!self)
return;
struct history *hst = self->chatwin->hst;
if (hst->queue_sz >= MAX_LINE_INFO_QUEUE) {
return -1;
}
if (hst->queue_sz >= MAX_LINE_INFO_QUEUE)
return;
struct line_info *new_line = calloc(1, sizeof(struct line_info));
if (new_line == NULL) {
if (new_line == NULL)
exit_toxic_err("failed in line_info_add", FATALERR_MEMORY);
}
char frmt_msg[MAX_LINE_INFO_MSG_SIZE] = {0};
@ -183,6 +171,11 @@ int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const
len += strlen(user_settings->line_normal) + 3;
break;
case IN_PRVT_MSG:
case OUT_PRVT_MSG:
len += strlen(user_settings->line_special) + 3;
break;
case CONNECTION:
len += strlen(user_settings->line_join) + 2;
break;
@ -214,9 +207,8 @@ int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const
int i;
for (i = 0; frmt_msg[i]; ++i) {
if (frmt_msg[i] == '\n') {
if (frmt_msg[i] == '\n')
++new_line->newlines;
}
}
}
@ -235,7 +227,6 @@ int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const
len += strlen(new_line->name2);
}
new_line->id = (hst->line_end->id + 1 + hst->queue_sz) % INT_MAX;
new_line->len = len;
new_line->type = type;
new_line->bold = bold;
@ -244,8 +235,6 @@ int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const
new_line->timestamp = get_unix_time();
hst->queue[hst->queue_sz++] = new_line;
return new_line->id;
}
/* adds a single queue item to hst if possible. only called once per call to line_info_print() */
@ -254,27 +243,24 @@ static void line_info_check_queue(ToxWindow *self)
struct history *hst = self->chatwin->hst;
struct line_info *line = line_info_ret_queue(hst);
if (line == NULL) {
if (line == NULL)
return;
}
if (hst->start_id > user_settings->history_size) {
if (hst->start_id > user_settings->history_size)
line_info_root_fwd(hst);
}
line->id = hst->line_end->id + 1;
line->prev = hst->line_end;
hst->line_end->next = line;
hst->line_end = line;
hst->line_end->id = line->id;
int y, y2, x, x2;
getmaxyx(self->window, y2, x2);
getyx(self->chatwin->history, y, x);
(void) x;
if (x2 <= SIDEBAR_WIDTH) {
if (x2 <= SIDEBAR_WIDTH)
return;
}
int offst = self->show_peerlist ? SIDEBAR_WIDTH : 0; /* offset width of groupchat sidebar */
int lines = 1 + line->newlines + (line->len / (x2 - offst));
@ -296,9 +282,8 @@ void line_info_print(ToxWindow *self)
{
ChatContext *ctx = self->chatwin;
if (ctx == NULL) {
if (ctx == NULL)
return;
}
struct history *hst = ctx->hst;
@ -306,25 +291,19 @@ void line_info_print(ToxWindow *self)
line_info_check_queue(self);
WINDOW *win = ctx->history;
wclear(win);
int y2, x2;
getmaxyx(self->window, y2, x2);
if (x2 <= SIDEBAR_WIDTH) {
if (x2 <= SIDEBAR_WIDTH)
return;
}
if (self->is_groupchat) {
if (self->is_groupchat)
wmove(win, 0, 0);
} else {
else
wmove(win, 2, 0);
}
struct line_info *line = hst->line_start->next;
int numlines = 0;
while (line && numlines++ <= y2) {
@ -338,20 +317,24 @@ void line_info_print(ToxWindow *self)
/* fallthrough */
case IN_MSG:
case IN_PRVT_MSG:
case OUT_PRVT_MSG:
wattron(win, COLOR_PAIR(BLUE));
wprintw(win, "%s ", line->timestr);
wattroff(win, COLOR_PAIR(BLUE));
int nameclr = GREEN;
if (line->colour) {
if (line->colour)
nameclr = line->colour;
} else if (type == IN_MSG) {
else if (type == IN_MSG)
nameclr = CYAN;
}
wattron(win, COLOR_PAIR(nameclr));
wprintw(win, "%s %s: ", user_settings->line_normal, line->name1);
wprintw(win, "%s %s: ", (type != OUT_PRVT_MSG && type != IN_PRVT_MSG) ?
user_settings->line_normal :
user_settings->line_special,
line->name1);
wattroff(win, COLOR_PAIR(nameclr));
char *msg = line->msg;
@ -359,24 +342,21 @@ void line_info_print(ToxWindow *self)
while (msg) {
char *line = strsep(&msg, "\n");
if (line[0] == '>') {
if (line[0] == '>')
wattron(win, COLOR_PAIR(GREEN));
} else if (line[0] == '<') {
else if (line[0] == '<')
wattron(win, COLOR_PAIR(RED));
}
wprintw(win, "%s%c", line, msg ? '\n' : '\0');
if (line[0] == '>') {
if (line[0] == '>')
wattroff(win, COLOR_PAIR(GREEN));
} else if (line[0] == '<') {
else if (line[0] == '<')
wattroff(win, COLOR_PAIR(RED));
}
// change the \0 set by strsep back to \n
if (msg) {
if (msg)
msg[-1] = '\n';
}
}
if (type == OUT_MSG && timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
@ -429,23 +409,19 @@ void line_info_print(ToxWindow *self)
wattroff(win, COLOR_PAIR(BLUE));
}
if (line->bold) {
if (line->bold)
wattron(win, A_BOLD);
}
if (line->colour) {
if (line->colour)
wattron(win, COLOR_PAIR(line->colour));
}
wprintw(win, "%s\n", line->msg);
if (line->bold) {
if (line->bold)
wattroff(win, A_BOLD);
}
if (line->colour) {
if (line->colour)
wattroff(win, COLOR_PAIR(line->colour));
}
break;
@ -454,9 +430,8 @@ void line_info_print(ToxWindow *self)
wprintw(win, "$ ");
wattroff(win, COLOR_PAIR(GREEN));
if (line->msg[0]) {
if (line->msg[0])
wprintw(win, "%s", line->msg);
}
wprintw(win, "\n");
break;
@ -520,9 +495,8 @@ void line_info_print(ToxWindow *self)
}
/* keep calling until queue is empty */
if (hst->queue_sz > 0) {
if (hst->queue_sz > 0)
line_info_print(self);
}
}
/* puts msg in specified line_info msg buffer */
@ -547,20 +521,16 @@ void line_info_set(ToxWindow *self, uint32_t id, char *msg)
static void line_info_scroll_up(struct history *hst)
{
if (hst->line_start->prev) {
if (hst->line_start->prev)
hst->line_start = hst->line_start->prev;
} else {
sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
}
else sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
}
static void line_info_scroll_down(struct history *hst)
{
if (hst->line_start->next) {
if (hst->line_start->next)
hst->line_start = hst->line_start->next;
} else {
sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
}
else sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
}
static void line_info_page_up(ToxWindow *self, struct history *hst)
@ -571,9 +541,8 @@ static void line_info_page_up(ToxWindow *self, struct history *hst)
int jump_dist = y2 / 2;
int i;
for (i = 0; i < jump_dist && hst->line_start->prev; ++i) {
for (i = 0; i < jump_dist && hst->line_start->prev; ++i)
hst->line_start = hst->line_start->prev;
}
}
static void line_info_page_down(ToxWindow *self, struct history *hst)
@ -584,9 +553,8 @@ static void line_info_page_down(ToxWindow *self, struct history *hst)
int jump_dist = y2 / 2;
int i;
for (i = 0; i < jump_dist && hst->line_start->next; ++i) {
for (i = 0; i < jump_dist && hst->line_start->next; ++i)
hst->line_start = hst->line_start->next;
}
}
bool line_info_onKey(ToxWindow *self, wint_t key)

View File

@ -31,14 +31,16 @@
#define MAX_LINE_INFO_QUEUE 1024
#define MAX_LINE_INFO_MSG_SIZE MAX_STR_SIZE + TOXIC_MAX_NAME_LENGTH + 32 /* needs extra room for log loading */
typedef enum {
enum {
SYS_MSG,
IN_MSG,
OUT_MSG,
OUT_MSG_READ, /* for sent messages that have received a read reply. don't set this with line_info_add */
OUT_MSG_READ, /* for sent messages that have received a read reply. */
IN_ACTION,
OUT_ACTION,
OUT_ACTION_READ, /* same as OUT_MSG_READ but for actions */
IN_PRVT_MSG, /* PRVT should only be used for groups */
OUT_PRVT_MSG,
PROMPT,
CONNECTION,
DISCONNECTION,
@ -74,13 +76,9 @@ struct history {
int queue_sz;
};
/* creates new line_info line and puts it in the queue.
*
* Returns the id of the new line.
* Returns -1 on failure.
*/
int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const char *name2, uint8_t type,
uint8_t bold, uint8_t colour, const char *msg, ...);
/* creates new line_info line and puts it in the queue. */
void line_info_add(ToxWindow *self, const char *timestr, const char *name1, const char *name2, uint8_t type,
uint8_t bold, uint8_t colour, const char *msg, ...);
/* Prints a section of history starting at line_start */
void line_info_print(ToxWindow *self);
@ -100,4 +98,4 @@ void line_info_reset_start(ToxWindow *self, struct history *hst);
void line_info_init(struct history *hst);
bool line_info_onKey(ToxWindow *self, wint_t key); /* returns true if key is a match */
#endif /* LINE_INFO_H */
#endif /* #define LINE_INFO_H */

View File

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

View File

@ -30,7 +30,7 @@ struct chatlog {
bool log_on; /* specific to current chat window */
};
typedef enum {
enum {
LOG_GROUP,
LOG_PROMPT,
LOG_CHAT,
@ -56,4 +56,4 @@ void load_chat_history(ToxWindow *self, struct chatlog *log);
Returns 0 on success or if no log exists, -1 on failure. */
int rename_logfile(char *src, char *dest, const char *selfkey, const char *otherkey, int winnum);
#endif /* LOG_H */
#endif /* #define LOG_H */

View File

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

View File

@ -40,7 +40,7 @@ struct chat_queue {
};
void cqueue_cleanup(struct chat_queue *q);
void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, int line_id);
void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, uint32_t line_id);
/* Tries to send the oldest unsent message in queue. */
void cqueue_try_send(ToxWindow *self, Tox *m);
@ -48,4 +48,4 @@ void cqueue_try_send(ToxWindow *self, Tox *m);
/* removes message with matching receipt from queue, writes to log and updates line to show the message was received. */
void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt);
#endif /* MESSAGE_QUEUE_H */
#endif /* #define MESSAGE_QUEUE_H */

View File

@ -26,9 +26,12 @@
#include <time.h>
#include <limits.h>
#include <dirent.h>
#if defined(__FreeBSD__)
#include <netinet/in.h>
#include <sys/socket.h>
#else
#include <arpa/inet.h>
#endif
#include <sys/stat.h>
#include "toxic.h"
@ -75,7 +78,7 @@ struct tm *get_time(void)
return timeinfo;
}
/*Puts the current time in buf in the format of [HH:mm:ss] */
/* Puts the current time in buf in the format of [HH:mm:ss] */
void get_time_str(char *buf, int bufsize)
{
if (user_settings->timestamps == TIMESTAMPS_OFF) {
@ -84,30 +87,43 @@ void get_time_str(char *buf, int bufsize)
}
const char *t = user_settings->timestamp_format;
if (strftime(buf, bufsize, t, get_time()) == 0) {
strftime(buf, bufsize, TIMESTAMP_DEFAULT, get_time());
}
strftime(buf, bufsize, t, get_time());
}
/* Converts seconds to string in format HH:mm:ss; truncates hours and minutes when necessary */
void get_elapsed_time_str(char *buf, int bufsize, time_t secs)
{
if (!secs) {
if (!secs)
return;
}
long int seconds = secs % 60;
long int minutes = (secs % 3600) / 60;
long int hours = secs / 3600;
if (!minutes && !hours) {
if (!minutes && !hours)
snprintf(buf, bufsize, "%.2ld", seconds);
} else if (!hours) {
else if (!hours)
snprintf(buf, bufsize, "%ld:%.2ld", minutes, seconds);
} else {
else
snprintf(buf, bufsize, "%ld:%.2ld:%.2ld", hours, minutes, seconds);
}
}
/* Converts seconds to string in format H hours, m minutes, s seconds */
void get_elapsed_time_str_2(char *buf, int bufsize, uint64_t secs)
{
if (!secs)
return;
long int seconds = secs % 60;
long int minutes = (secs % 3600) / 60;
long int hours = secs / 3600;
if (!minutes && !hours)
snprintf(buf, bufsize, "%ld seconds", seconds);
else if (!hours)
snprintf(buf, bufsize, "%ld minutes, %ld seconds", minutes, seconds);
else
snprintf(buf, bufsize, "%ld hours, %ld minutes, %ld seconds", hours, minutes, seconds);
}
/*
@ -119,12 +135,11 @@ void get_elapsed_time_str(char *buf, int bufsize, time_t secs)
*/
int hex_string_to_bin(const char *hex_string, size_t hex_len, char *output, size_t output_size)
{
if (output_size == 0 || hex_len != output_size * 2) {
if (output_size == 0 || hex_len != output_size * 2)
return -1;
}
for (size_t i = 0; i < output_size; ++i) {
sscanf(hex_string, "%2hhx", (unsigned char *)&output[i]);
sscanf(hex_string, "%2hhx", &output[i]);
hex_string += 2;
}
@ -133,20 +148,18 @@ int hex_string_to_bin(const char *hex_string, size_t hex_len, char *output, size
int hex_string_to_bytes(char *buf, int size, const char *keystr)
{
if (size % 2 != 0) {
if (size % 2 != 0)
return -1;
}
int i, res;
const char *pos = keystr;
for (i = 0; i < size; ++i) {
res = sscanf(pos, "%2hhx", (unsigned char *)&buf[i]);
res = sscanf(pos, "%2hhx", &buf[i]);
pos += 2;
if (res == EOF || res < 1) {
if (res == EOF || res < 1)
return -1;
}
}
return 0;
@ -159,15 +172,13 @@ int hex_string_to_bytes(char *buf, int size, const char *keystr)
*/
int bin_id_to_string(const char *bin_id, size_t bin_id_size, char *output, size_t output_size)
{
if (bin_id_size != TOX_ADDRESS_SIZE || output_size < (TOX_ADDRESS_SIZE * 2 + 1)) {
if (bin_id_size != TOX_ADDRESS_SIZE || output_size < (TOX_ADDRESS_SIZE * 2 + 1))
return -1;
}
size_t i;
for (i = 0; i < TOX_ADDRESS_SIZE; ++i) {
for (i = 0; i < TOX_ADDRESS_SIZE; ++i)
snprintf(&output[i * 2], output_size - (i * 2), "%02X", bin_id[i] & 0xff);
}
return 0;
}
@ -175,9 +186,8 @@ int bin_id_to_string(const char *bin_id, size_t bin_id_size, char *output, size_
/* Returns 1 if the string is empty, 0 otherwise */
int string_is_empty(const char *string)
{
if (!string) {
if (!string)
return true;
}
return string[0] == '\0';
}
@ -185,9 +195,8 @@ int string_is_empty(const char *string)
/* Returns 1 if the string is empty, 0 otherwise */
int wstring_is_empty(const wchar_t *string)
{
if (!string) {
if (!string)
return true;
}
return string[0] == L'\0';
}
@ -197,13 +206,11 @@ int mbs_to_wcs_buf(wchar_t *buf, const char *string, size_t n)
{
size_t len = mbstowcs(NULL, string, 0) + 1;
if (n < len) {
if (n < len)
return -1;
}
if ((len = mbstowcs(buf, string, n)) == (size_t) - 1) {
if ((len = mbstowcs(buf, string, n)) == (size_t) - 1)
return -1;
}
return len;
}
@ -213,13 +220,11 @@ int wcs_to_mbs_buf(char *buf, const wchar_t *string, size_t n)
{
size_t len = wcstombs(NULL, string, 0) + 1;
if (n < len) {
if (n < len)
return -1;
}
if ((len = wcstombs(buf, string, n)) == (size_t) - 1) {
if ((len = wcstombs(buf, string, n)) == (size_t) - 1)
return -1;
}
return len;
}
@ -238,9 +243,8 @@ int qsort_strcasecmp_hlpr(const void *str1, const void *str2)
- must not contain a newline or tab seqeunce */
int valid_nick(const char *nick)
{
if (!nick[0] || nick[0] == ' ') {
if (!nick[0] || nick[0] == ' ')
return 0;
}
int i;
@ -252,9 +256,7 @@ int valid_nick(const char *nick)
|| nick[i] == '\v'
|| nick[i] == '\r')
{
return 0;
}
}
return 1;
@ -266,9 +268,8 @@ void filter_str(char *str, size_t len)
size_t i;
for (i = 0; i < len; ++i) {
if (str[i] == '\n' || str[i] == '\r' || str[i] == '\t' || str[i] == '\v' || str[i] == '\0') {
if (str[i] == '\n' || str[i] == '\r' || str[i] == '\t' || str[i] == '\v' || str[i] == '\0')
str[i] = ' ';
}
}
}
@ -280,26 +281,22 @@ size_t get_file_name(char *namebuf, size_t bufsize, const char *pathname)
int len = strlen(pathname) - 1;
char *path = strdup(pathname);
if (path == NULL) {
if (path == NULL)
exit_toxic_err("failed in get_file_name", FATALERR_MEMORY);
}
while (len >= 0 && pathname[len] == '/') {
while (len >= 0 && pathname[len] == '/')
path[len--] = '\0';
}
char *finalname = strdup(path);
if (finalname == NULL) {
if (finalname == NULL)
exit_toxic_err("failed in get_file_name", FATALERR_MEMORY);
}
const char *basenm = strrchr(path, '/');
if (basenm != NULL) {
if (basenm[1]) {
if (basenm[1])
strcpy(finalname, &basenm[1]);
}
}
snprintf(namebuf, bufsize, "%s", finalname);
@ -316,15 +313,13 @@ size_t get_file_name(char *namebuf, size_t bufsize, const char *pathname)
*/
size_t get_base_dir(const char *path, size_t path_len, char *dir)
{
if (path_len == 0 || path == NULL) {
if (path_len == 0 || path == NULL)
return 0;
}
size_t dir_len = char_rfind(path, '/', path_len);
if (dir_len != 0 && dir_len < path_len) {
++dir_len; /* Leave trailing slash */
}
if (dir_len != 0 && dir_len < path_len)
++dir_len; /* Leave trailing slash */
memcpy(dir, path, dir_len);
dir[dir_len] = '\0';
@ -337,9 +332,8 @@ void str_to_lower(char *str)
{
int i;
for (i = 0; str[i]; ++i) {
for (i = 0; str[i]; ++i)
str[i] = tolower(str[i]);
}
}
/* puts friendnum's nick in buf, truncating at TOXIC_MAX_NAME_LENGTH if necessary.
@ -347,40 +341,36 @@ void str_to_lower(char *str)
Returns nick len */
size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum)
{
Tox_Err_Friend_Query err;
size_t len = tox_friend_get_name_size(m, friendnum, &err);
size_t len = tox_friend_get_name_size(m, friendnum, NULL);
if (err != TOX_ERR_FRIEND_QUERY_OK) {
goto on_error;
if (len == 0) {
strcpy(buf, UNKNOWN_NAME);
len = strlen(UNKNOWN_NAME);
} else {
if (!tox_friend_get_name(m, friendnum, (uint8_t *) buf, NULL)) {
goto on_error;
}
tox_friend_get_name(m, friendnum, (uint8_t *) buf, NULL);
}
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
buf[len] = '\0';
filter_str(buf, len);
return len;
on_error:
strcpy(buf, UNKNOWN_NAME);
len = strlen(UNKNOWN_NAME);
buf[len] = '\0';
return len;
}
/* same as get_nick_truncate but for groupchats */
int get_group_nick_truncate(Tox *m, char *buf, uint32_t peernum, uint32_t groupnum)
int get_group_nick_truncate(Tox *m, char *buf, uint32_t peer_id, int groupnum)
{
Tox_Err_Conference_Peer_Query err;
size_t len = tox_conference_peer_get_name_size(m, groupnum, peernum, &err);
TOX_ERR_GROUP_PEER_QUERY err;
size_t len = tox_group_peer_get_name_size(m, groupnum, peer_id, &err);
if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
goto on_error;
if (err != TOX_ERR_GROUP_PEER_QUERY_OK) {
strcpy(buf, UNKNOWN_NAME);
len = strlen(UNKNOWN_NAME);
} else {
if (!tox_conference_peer_get_name(m, groupnum, peernum, (uint8_t *) buf, NULL)) {
goto on_error;
tox_group_peer_get_name(m, groupnum, peer_id, (uint8_t *) buf, &err);
if (err != TOX_ERR_GROUP_PEER_QUERY_OK) {
strcpy(buf, UNKNOWN_NAME);
len = strlen(UNKNOWN_NAME);
}
}
@ -388,30 +378,21 @@ int get_group_nick_truncate(Tox *m, char *buf, uint32_t peernum, uint32_t groupn
buf[len] = '\0';
filter_str(buf, len);
return len;
on_error:
strcpy(buf, UNKNOWN_NAME);
len = strlen(UNKNOWN_NAME);
buf[len] = '\0';
return len;
}
/* copies data to msg buffer, removing return characters.
returns length of msg, which will be no larger than size-1 */
/* copies data to msg buffer.
returns length of msg.
returns 0 and nulls msg if length is too big for buffer size */
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) {
if (data[i] != '\r') {
msg[j++] = data[i];
}
if (length > size - 1) {
msg[0] = '\0';
return 0;
}
msg[j] = '\0';
return j;
memcpy(msg, data, length);
msg[length] = '\0';
return length;
}
/* returns index of the first instance of ch in s starting at idx.
@ -425,9 +406,8 @@ int char_find(int idx, const char *s, char ch)
int i = idx;
for (i = idx; s[i]; ++i) {
if (s[i] == ch) {
if (s[i] == ch)
break;
}
}
return i;
@ -444,9 +424,8 @@ int char_rfind(const char *s, char ch, int len)
int i = 0;
for (i = len; i > 0; --i) {
if (s[i] == ch) {
if (s[i] == ch)
break;
}
}
return i;
@ -481,36 +460,13 @@ bool file_exists(const char *path)
return stat(path, &s) == 0;
}
/*
* Checks the file type path points to and returns a File_Type enum value.
*
* Returns FILE_TYPE_DIRECTORY if path points to a directory.
* Returns FILE_TYPE_REGULAR if path points to a regular file.
* Returns FILE_TYPE_OTHER on any other result, including an invalid path.
*/
File_Type file_type(const char *path)
{
struct stat s;
stat(path, &s);
switch (s.st_mode & S_IFMT) {
case S_IFDIR:
return FILE_TYPE_DIRECTORY;
case S_IFREG:
return FILE_TYPE_REGULAR;
default:
return FILE_TYPE_OTHER;
}
}
/* returns file size. If file doesn't exist returns 0. */
off_t file_size(const char *path)
{
struct stat st;
if (stat(path, &st) == -1) {
if (stat(path, &st) == -1)
return 0;
}
return st.st_size;
}
@ -523,15 +479,13 @@ int check_file_signature(const char *signature, size_t size, FILE *fp)
{
char buf[size];
if (fread(buf, size, 1, fp) != 1) {
if (fread(buf, size, 1, fp) != 1)
return -1;
}
int ret = memcmp(signature, buf, size);
if (fseek(fp, 0L, SEEK_SET) == -1) {
if (fseek(fp, 0L, SEEK_SET) == -1)
return -1;
}
return ret == 0 ? 0 : 1;
}
@ -541,11 +495,10 @@ void set_window_title(ToxWindow *self, const char *title, int len)
{
char cpy[TOXIC_MAX_NAME_LENGTH + 1];
if (self->is_groupchat) { /* keep groupnumber in title */
if (self->is_groupchat) /* keep groupnumber in title */
snprintf(cpy, sizeof(cpy), "%d %s", self->num, title);
} else {
else
snprintf(cpy, sizeof(cpy), "%s", title);
}
if (len > MAX_WINDOW_NAME_LENGTH) {
strcpy(&cpy[MAX_WINDOW_NAME_LENGTH - 3], "...");

View File

@ -39,14 +39,6 @@
#define net_to_host(x, y) hst_to_net(x, y)
#endif
typedef enum File_Type
{
FILE_TYPE_REGULAR,
FILE_TYPE_DIRECTORY,
FILE_TYPE_OTHER,
} File_Type;
void hst_to_net(uint8_t *num, uint16_t numbytes);
/*
@ -77,6 +69,9 @@ void get_time_str(char *buf, int bufsize);
/* Converts seconds to string in format HH:mm:ss; truncates hours and minutes when necessary */
void get_elapsed_time_str(char *buf, int bufsize, time_t secs);
/* Converts seconds to string in format H hours, m minutes, s seconds */
void get_elapsed_time_str_2(char *buf, int bufsize, uint64_t secs);
/* get the current local time (not thread safe) */
struct tm *get_time(void);
@ -86,13 +81,13 @@ int string_is_empty(const char *string);
/* Same as above but for wide character strings */
int wstring_is_empty(const wchar_t *string);
/* converts a multibyte string to a wide character string (must provide buffer) */
/* convert a multibyte string to a wide character string (must provide buffer) */
int char_to_wcs_buf(wchar_t *buf, const char *string, size_t n);
/* converts wide character string into a multibyte string and puts in buf. */
int wcs_to_mbs_buf(char *buf, const wchar_t *string, size_t n);
/* converts a multibyte string to a wide character string and puts in buf) */
/* convert a multibyte string to a wide character string and puts in buf) */
int mbs_to_wcs_buf(wchar_t *buf, const char *string, size_t n);
/* Returns 1 if connection has timed out, 0 otherwise */
@ -134,10 +129,11 @@ void str_to_lower(char *str);
size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum);
/* same as get_nick_truncate but for groupchats */
int get_group_nick_truncate(Tox *m, char *buf, uint32_t peernum, uint32_t groupnum);
int get_group_nick_truncate(Tox *m, char *buf, uint32_t peer_id, int groupnum);
/* copies data to msg buffer.
returns length of msg, which will be no larger than size-1 */
returns length of msg.
returns 0 and nulls msg if length is too big for buffer size */
size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length);
/* returns index of the first instance of ch in s starting at idx.
@ -154,15 +150,6 @@ void bytes_convert_str(char *buf, int size, uint64_t bytes);
/* checks if a file exists. Returns true or false */
bool file_exists(const char *path);
/*
* Checks the file type path points to and returns a File_Type enum value.
*
* Returns FILE_TYPE_DIRECTORY if path points to a directory.
* Returns FILE_TYPE_REGULAR if path points to a regular file.
* Returns FILE_TYPE_OTHER on any other result, including an invalid path.
*/
File_Type file_type(const char *path);
/* returns file size. If file doesn't exist returns 0. */
off_t file_size(const char *path);
@ -187,4 +174,4 @@ bool is_ip4_address(const char *address);
*/
bool is_ip6_address(const char *address);
#endif /* MISC_TOOLS_H */
#endif /* #define MISC_TOOLS_H */

View File

@ -21,7 +21,6 @@
*/
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <curl/curl.h>
@ -42,7 +41,7 @@ extern struct Winthread Winthread;
#define MAX_DOMAIN_SIZE 32
#define MAX_SERVER_LINE MAX_DOMAIN_SIZE + (SERVER_KEY_SIZE * 2) + 3
static struct Nameservers {
struct Nameservers {
int lines;
char names[MAX_SERVERS][MAX_DOMAIN_SIZE];
char keys[MAX_SERVERS][SERVER_KEY_SIZE];
@ -97,49 +96,42 @@ static int load_nameserver_list(const char *path)
{
FILE *fp = fopen(path, "r");
if (fp == NULL) {
if (fp == NULL)
return -2;
}
char line[MAX_SERVER_LINE];
while (fgets(line, sizeof(line), fp) && Nameservers.lines < MAX_SERVERS) {
int linelen = strlen(line);
if (linelen < SERVER_KEY_SIZE * 2 + 5) {
if (linelen < SERVER_KEY_SIZE * 2 + 5)
continue;
}
if (line[linelen - 1] == '\n') {
if (line[linelen - 1] == '\n')
line[--linelen] = '\0';
}
const char *name = strtok(line, " ");
const char *keystr = strtok(NULL, " ");
if (name == NULL || keystr == NULL) {
if (name == NULL || keystr == NULL)
continue;
}
if (strlen(keystr) != SERVER_KEY_SIZE * 2) {
if (strlen(keystr) != SERVER_KEY_SIZE * 2)
continue;
}
snprintf(Nameservers.names[Nameservers.lines], sizeof(Nameservers.names[Nameservers.lines]), "%s", name);
int res = hex_string_to_bytes(Nameservers.keys[Nameservers.lines], SERVER_KEY_SIZE, keystr);
if (res == -1) {
if (res == -1)
continue;
}
++Nameservers.lines;
}
fclose(fp);
if (Nameservers.lines < 1) {
if (Nameservers.lines < 1)
return -3;
}
return 0;
}
@ -152,9 +144,8 @@ static int load_nameserver_list(const char *path)
*/
static int parse_addr(const char *addr, char *namebuf, size_t namebuf_sz, char *dombuf, size_t dombuf_sz)
{
if (strlen(addr) >= (MAX_STR_SIZE - strlen(NAMESERVER_API_PATH))) {
if (strlen(addr) >= (MAX_STR_SIZE - strlen(NAMESERVER_API_PATH)))
return -1;
}
char tmpaddr[MAX_STR_SIZE];
char *tmpname = NULL;
@ -164,9 +155,8 @@ static int parse_addr(const char *addr, char *namebuf, size_t namebuf_sz, char *
tmpname = strtok(tmpaddr, "@");
tmpdom = strtok(NULL, "");
if (tmpname == NULL || tmpdom == NULL) {
if (tmpname == NULL || tmpdom == NULL)
return -1;
}
str_to_lower(tmpdom);
snprintf(namebuf, namebuf_sz, "%s", tmpname);
@ -206,27 +196,23 @@ static int process_response(struct Recv_Curl_Data *recv_data)
{
size_t prefix_size = strlen(ID_PREFIX);
if (recv_data->length < TOX_ADDRESS_SIZE * 2 + prefix_size) {
if (recv_data->length < TOX_ADDRESS_SIZE * 2 + prefix_size)
return -1;
}
const char *IDstart = strstr(recv_data->data, ID_PREFIX);
if (IDstart == NULL) {
if (IDstart == NULL)
return -1;
}
if (strlen(IDstart) < TOX_ADDRESS_SIZE * 2 + prefix_size) {
if (strlen(IDstart) < TOX_ADDRESS_SIZE * 2 + prefix_size)
return -1;
}
char ID_string[TOX_ADDRESS_SIZE * 2 + 1];
memcpy(ID_string, IDstart + prefix_size, TOX_ADDRESS_SIZE * 2);
ID_string[TOX_ADDRESS_SIZE * 2] = 0;
if (hex_string_to_bin(ID_string, strlen(ID_string), t_data.id_bin, sizeof(t_data.id_bin)) == -1) {
if (hex_string_to_bin(ID_string, strlen(ID_string), t_data.id_bin, sizeof(t_data.id_bin)) == -1)
return -1;
}
return 0;
}
@ -247,11 +233,10 @@ void *lookup_thread_func(void *data)
char real_domain[MAX_DOMAIN_SIZE];
if (!get_domain_match(nameserver_key, real_domain, sizeof(real_domain), input_domain)) {
if (!strcasecmp(input_domain, "utox.org")) {
if (!strcasecmp(input_domain, "utox.org"))
lookup_error(self, "utox.org uses deprecated DNS-based lookups and is no longer supported by Toxic.");
} else {
else
lookup_error(self, "Name server domain not found.");
}
kill_lookup_thread();
}

View File

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

View File

@ -60,7 +60,7 @@ typedef enum _Flags {
} Flags;
int init_notify(int login_cooldown, int notification_timeout);
void terminate_notify(void);
void terminate_notify();
int sound_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indicator);
int sound_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id);

View File

@ -45,7 +45,7 @@ void bgrtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *
#endif /* __OBJC__ */
int osx_video_init(char **device_names, int *size);
void osx_video_release(void);
void osx_video_release();
/* Start device */
int osx_video_open_device(uint32_t selection, uint16_t *width, uint16_t *height);
/* Stop device */
@ -54,4 +54,4 @@ void osx_video_close_device(uint32_t device_idx);
int osx_video_read_device(uint8_t *y, uint8_t *u, uint8_t *v, uint16_t *width, uint16_t *height);
#endif /* OSX_VIDEO_H */
#endif /* OSX_VIDEO_H */

View File

@ -144,9 +144,8 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
device_names[i] = video_input_name;
}
if (i <= 0) {
if ( i <= 0 )
return nil;
}
*size = i;
@ -175,7 +174,7 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
NSError *error = NULL;
AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice: device error: &error];
if (error != NULL) {
if ( error != NULL ) {
[input release];
return -1;
}
@ -194,7 +193,7 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
AVCaptureInputPort *port = [input.ports objectAtIndex: 0];
CMFormatDescriptionRef format_description = port.formatDescription;
if (format_description) {
if ( format_description ) {
CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(format_description);
*width = dimensions.width;
*height = dimensions.height;
@ -209,10 +208,10 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
// TODO possibly get a better pixel format
if (_shouldMangleDimensions) {
[_linkerVideo setVideoSettings: @ {
(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA),
(id)kCVPixelBufferWidthKey: @640,
(id)kCVPixelBufferHeightKey: @480
}];
(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA),
(id)kCVPixelBufferWidthKey: @640,
(id)kCVPixelBufferHeightKey: @480
}];
} else {
[_linkerVideo setVideoSettings: @ {(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)}];
}
@ -304,9 +303,8 @@ int osx_video_init(char **device_names, int *size)
{
_OSXVideo = [[OSXVideo alloc] initWithDeviceNames: device_names AmtDevices: size];
if (_OSXVideo == nil) {
if ( _OSXVideo == nil )
return -1;
}
return 0;
}
@ -319,9 +317,8 @@ void osx_video_release()
int osx_video_open_device(uint32_t selection, uint16_t *width, uint16_t *height)
{
if (_OSXVideo == nil) {
if ( _OSXVideo == nil )
return -1;
}
return [_OSXVideo openVideoDeviceIndex: selection Width: width Height: height];
}
@ -333,9 +330,8 @@ void osx_video_close_device(uint32_t device_idx)
int osx_video_read_device(uint8_t *y, uint8_t *u, uint8_t *v, uint16_t *width, uint16_t *height)
{
if (_OSXVideo == nil) {
if ( _OSXVideo == nil )
return -1;
}
return [_OSXVideo getVideoFrameY: y U: u V: v Width: width Height: height];
}

View File

@ -49,27 +49,13 @@ extern struct Winthread Winthread;
extern FriendsList Friends;
FriendRequests FrndRequests;
#ifdef AUDIO
#define AC_NUM_GLOB_COMMANDS_AUDIO 2
#else
#define AC_NUM_GLOB_COMMANDS_AUDIO 0
#endif /* AUDIO */
#ifdef VIDEO
#define AC_NUM_GLOB_COMMANDS_VIDEO 2
#define AC_NUM_GLOB_COMMANDS 23
#elif AUDIO
#define AC_NUM_GLOB_COMMANDS 21
#else
#define AC_NUM_GLOB_COMMANDS_VIDEO 0
#endif /* VIDEO */
#ifdef PYTHON
#define AC_NUM_GLOB_COMMANDS_PYTHON 1
#else
#define AC_NUM_GLOB_COMMANDS_PYTHON 0
#endif /* PYTHON */
#ifdef QRCODE
#define AC_NUM_GLOB_COMMANDS_QRCODE 1
#else
#define AC_NUM_GLOB_COMMANDS_QRCODE 0
#endif /* QRCODE */
#define AC_NUM_GLOB_COMMANDS (17 + AC_NUM_GLOB_COMMANDS_AUDIO + AC_NUM_GLOB_COMMANDS_VIDEO + AC_NUM_GLOB_COMMANDS_PYTHON + AC_NUM_GLOB_COMMANDS_QRCODE)
#define AC_NUM_GLOB_COMMANDS 19
#endif
/* Array of global command names used for tab completion. */
static const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
@ -82,11 +68,10 @@ static const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/exit" },
{ "/group" },
{ "/help" },
{ "/join" },
{ "/log" },
{ "/myid" },
#ifdef QRCODE
{ "/myqr" },
#endif /* QRCODE */
{ "/nick" },
{ "/note" },
{ "/nospam" },
@ -108,12 +93,6 @@ static const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
#endif /* VIDEO */
#ifdef PYTHON
{ "/run" },
#endif /* PYTHON */
};
void kill_prompt_window(ToxWindow *self)
@ -137,7 +116,7 @@ void kill_prompt_window(ToxWindow *self)
}
/* callback: Updates own connection status in prompt statusbar */
void on_self_connection_status(Tox *m, Tox_Connection connection_status, void *userdata)
void prompt_onSelfConnectionChange(Tox *m, TOX_CONNECTION connection_status, void *userdata)
{
StatusBar *statusbar = prompt->stb;
statusbar->connection = connection_status;
@ -159,35 +138,26 @@ void prompt_update_statusmessage(ToxWindow *prompt, Tox *m, const char *statusms
size_t len = strlen(statusbar->statusmsg);
statusbar->statusmsg_len = len;
Tox_Err_Set_Info err;
tox_self_set_status_message(m, (const uint8_t *) statusmsg, len, &err);
TOX_ERR_SET_INFO err;
tox_self_set_status_message(m, (uint8_t *) statusmsg, len, &err);
if (err != TOX_ERR_SET_INFO_OK) {
if (err != TOX_ERR_SET_INFO_OK)
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set note (error %d)\n", err);
}
}
/* Updates own status in prompt statusbar */
void prompt_update_status(ToxWindow *prompt, Tox_User_Status status)
void prompt_update_status(ToxWindow *prompt, TOX_USER_STATUS status)
{
StatusBar *statusbar = prompt->stb;
statusbar->status = status;
}
/* Returns our own connection status */
Tox_Connection prompt_selfConnectionStatus(void)
{
StatusBar *statusbar = prompt->stb;
return statusbar->connection;
}
/* Adds friend request to pending friend requests.
Returns request number on success, -1 if queue is full. */
static int add_friend_request(const char *public_key, const char *data)
{
if (FrndRequests.max_idx >= MAX_FRIEND_REQUESTS) {
if (FrndRequests.max_idx >= MAX_FRIEND_REQUESTS)
return -1;
}
int i;
@ -197,9 +167,8 @@ static int add_friend_request(const char *public_key, const char *data)
memcpy(FrndRequests.request[i].key, public_key, TOX_PUBLIC_KEY_SIZE);
snprintf(FrndRequests.request[i].msg, sizeof(FrndRequests.request[i].msg), "%s", data);
if (i == FrndRequests.max_idx) {
if (i == FrndRequests.max_idx)
++FrndRequests.max_idx;
}
++FrndRequests.num_requests;
@ -218,13 +187,11 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
getyx(self->window, y, x);
getmaxyx(self->window, y2, x2);
if (x2 <= 0 || y2 <= 0) {
if (x2 <= 0 || y2 <= 0)
return;
}
if (ctx->pastemode && key == '\r') {
if (ctx->pastemode && key == '\r')
key = '\n';
}
/* ignore non-menu related input if active */
if (self->help->active) {
@ -237,9 +204,8 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
return;
}
if (line_info_onKey(self, key)) {
if (line_info_onKey(self, key))
return;
}
input_handle(self, key, x, y, x2, y2);
@ -247,17 +213,8 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
if (ctx->len > 1 && ctx->line[0] == '/') {
int diff = -1;
if (wcsncmp(ctx->line, L"/avatar ", wcslen(L"/avatar ")) == 0) {
if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0)
diff = dir_match(self, m, ctx->line, L"/avatar");
}
#ifdef PYTHON
else if (wcsncmp(ctx->line, L"/run ", wcslen(L"/run ")) == 0) {
diff = dir_match(self, m, ctx->line, L"/run");
}
#endif
else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) {
const char status_cmd_list[3][8] = {
{"online"},
@ -265,9 +222,8 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
{"busy"},
};
diff = complete_line(self, status_cmd_list, 3, 8);
} else {
} else
diff = complete_line(self, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
}
if (diff != -1) {
if (x + diff > x2 - 1) {
@ -289,9 +245,8 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
char line[MAX_STR_SIZE] = {0};
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
memset(&line, 0, sizeof(line));
}
line_info_add(self, NULL, NULL, NULL, PROMPT, 0, 0, "%s", line);
execute(ctx->history, self, m, line, GLOBAL_COMMAND_MODE);
@ -308,9 +263,8 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
int x2, y2;
getmaxyx(self->window, y2, x2);
if (y2 <= 0 || x2 <= 0) {
if (y2 <= 0 || x2 <= 0)
return;
}
ChatContext *ctx = self->chatwin;
@ -322,9 +276,8 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
curs_set(1);
if (ctx->len > 0) {
if (ctx->len > 0)
mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]);
}
StatusBar *statusbar = self->stb;
@ -332,7 +285,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
wmove(statusbar->topline, 0, 0);
pthread_mutex_lock(&Winthread.lock);
Tox_Connection connection = statusbar->connection;
TOX_CONNECTION connection = statusbar->connection;
pthread_mutex_unlock(&Winthread.lock);
if (connection != TOX_CONNECTION_NONE) {
@ -340,7 +293,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
const char *status_text = "ERROR";
pthread_mutex_lock(&Winthread.lock);
Tox_User_Status status = statusbar->status;
TOX_USER_STATUS status = statusbar->status;
pthread_mutex_unlock(&Winthread.lock);
switch (status) {
@ -384,7 +337,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
pthread_mutex_lock(&Winthread.lock);
size_t slen = tox_self_get_status_message_size(m);
tox_self_get_status_message(m, (uint8_t *) statusmsg);
tox_self_get_status_message (m, (uint8_t *) statusmsg);
statusmsg[slen] = '\0';
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
statusbar->statusmsg_len = strlen(statusbar->statusmsg);
@ -404,9 +357,8 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
statusbar->statusmsg_len = maxlen;
}
if (statusbar->statusmsg[0]) {
if (statusbar->statusmsg[0])
wprintw(statusbar->topline, " : %s", statusbar->statusmsg);
}
pthread_mutex_unlock(&Winthread.lock);
@ -421,21 +373,19 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
wnoutrefresh(self->window);
if (self->help->active) {
if (self->help->active)
help_onDraw(self);
}
}
static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnum, Tox_Connection connection_status)
static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnum , TOX_CONNECTION connection_status)
{
ChatContext *ctx = self->chatwin;
char nick[TOX_MAX_NAME_LENGTH] = {0}; /* stop removing this initiation */
get_nick_truncate(m, nick, friendnum);
if (!nick[0]) {
if (!nick[0])
snprintf(nick, sizeof(nick), "%s", UNKNOWN_NAME);
}
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
@ -450,25 +400,23 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnu
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg);
write_to_log(msg, nick, ctx->log, true);
if (self->active_box != -1) {
if (self->active_box != -1)
box_notify2(self, user_log_in, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, self->active_box,
"%s has come online", nick);
} else {
"%s has come online", nick );
else
box_notify(self, user_log_in, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, &self->active_box,
"Toxic", "%s has come online", nick);
}
"Toxic", "%s has come online", nick );
} else if (connection_status == TOX_CONNECTION_NONE) {
msg = "has gone offline";
line_info_add(self, timefrmt, nick, NULL, DISCONNECTION, 0, RED, msg);
write_to_log(msg, nick, ctx->log, true);
if (self->active_box != -1) {
if (self->active_box != -1)
box_notify2(self, user_log_out, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, self->active_box,
"%s has gone offline", nick);
} else {
"%s has gone offline", nick );
else
box_notify(self, user_log_out, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, &self->active_box,
"Toxic", "%s has gone offline", nick);
}
"Toxic", "%s has gone offline", nick );
}
}
@ -494,14 +442,13 @@ static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, con
sound_notify(self, generic_message, NT_WNDALERT_1 | NT_NOTIFWND, NULL);
}
void prompt_init_statusbar(ToxWindow *self, Tox *m, bool first_time_run)
void prompt_init_statusbar(ToxWindow *self, Tox *m)
{
int x2, y2;
getmaxyx(self->window, y2, x2);
if (y2 <= 0 || x2 <= 0) {
if (y2 <= 0 || x2 <= 0)
exit_toxic_err("failed in prompt_init_statusbar", FATALERR_CURSES);
}
(void) y2;
@ -519,12 +466,12 @@ void prompt_init_statusbar(ToxWindow *self, Tox *m, bool first_time_run)
size_t s_len = tox_self_get_status_message_size(m);
tox_self_get_status_message(m, (uint8_t *) statusmsg);
Tox_User_Status status = tox_self_get_status(m);
TOX_USER_STATUS status = tox_self_get_status(m);
nick[n_len] = '\0';
statusmsg[s_len] = '\0';
if (first_time_run) {
if (s_len == 0 || !strncmp(statusmsg, "Toxing on Toxic", strlen("Toxing on Toxic"))) {
snprintf(statusmsg, sizeof(statusmsg), "Toxing on Toxic");
s_len = strlen(statusmsg);
statusmsg[s_len] = '\0';
@ -560,9 +507,8 @@ static void prompt_onInit(ToxWindow *self, Tox *m)
int y2, x2;
getmaxyx(self->window, y2, x2);
if (y2 <= 0 || x2 <= 0) {
if (y2 <= 0 || x2 <= 0)
exit_toxic_err("failed in prompt_onInit", FATALERR_CURSES);
}
ChatContext *ctx = self->chatwin;
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
@ -571,9 +517,8 @@ static void prompt_onInit(ToxWindow *self, Tox *m)
ctx->log = calloc(1, sizeof(struct chatlog));
ctx->hst = calloc(1, sizeof(struct history));
if (ctx->log == NULL || ctx->hst == NULL) {
if (ctx->log == NULL || ctx->hst == NULL)
exit_toxic_err("failed in prompt_onInit", FATALERR_MEMORY);
}
line_info_init(ctx->hst);
@ -581,51 +526,46 @@ static void prompt_onInit(ToxWindow *self, Tox *m)
char myid[TOX_ADDRESS_SIZE];
tox_self_get_address(m, (uint8_t *) myid);
if (log_enable(self->name, myid, NULL, ctx->log, LOG_PROMPT) == -1) {
if (log_enable(self->name, myid, NULL, ctx->log, LOG_PROMPT) == -1)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
}
}
scrollok(ctx->history, 0);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
if (user_settings->show_welcome_msg == SHOW_WELCOME_MSG_ON) {
if (user_settings->show_welcome_msg == SHOW_WELCOME_MSG_ON)
print_welcome_msg(self);
}
}
ToxWindow *new_prompt(void)
ToxWindow new_prompt(void)
{
ToxWindow *ret = calloc(1, sizeof(ToxWindow));
ToxWindow ret;
memset(&ret, 0, sizeof(ret));
if (ret == NULL) {
exit_toxic_err("failed in new_prompt", FATALERR_MEMORY);
}
ret.num = -1;
ret.active = true;
ret.is_prompt = true;
ret->num = -1;
ret->is_prompt = true;
ret.onKey = &prompt_onKey;
ret.onDraw = &prompt_onDraw;
ret.onInit = &prompt_onInit;
ret.onConnectionChange = &prompt_onConnectionChange;
ret.onFriendRequest = &prompt_onFriendRequest;
ret->onKey = &prompt_onKey;
ret->onDraw = &prompt_onDraw;
ret->onInit = &prompt_onInit;
ret->onConnectionChange = &prompt_onConnectionChange;
ret->onFriendRequest = &prompt_onFriendRequest;
strcpy(ret->name, "home");
strcpy(ret.name, "home");
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
StatusBar *stb = calloc(1, sizeof(StatusBar));
Help *help = calloc(1, sizeof(Help));
if (stb == NULL || chatwin == NULL || help == NULL) {
if (stb == NULL || chatwin == NULL || help == NULL)
exit_toxic_err("failed in new_prompt", FATALERR_MEMORY);
}
ret->chatwin = chatwin;
ret->stb = stb;
ret->help = help;
ret.chatwin = chatwin;
ret.stb = stb;
ret.help = help;
ret->active_box = -1;
ret.active_box = -1;
return ret;
}

View File

@ -40,22 +40,17 @@ typedef struct {
struct friend_request request[MAX_FRIEND_REQUESTS];
} FriendRequests;
extern FriendRequests FrndRequests;
ToxWindow *new_prompt(void);
ToxWindow new_prompt(void);
void prep_prompt_win(void);
void prompt_init_statusbar(ToxWindow *self, Tox *m, bool first_time_run);
void prompt_init_statusbar(ToxWindow *self, Tox *m);
void prompt_update_nick(ToxWindow *prompt, const char *nick);
void prompt_update_statusmessage(ToxWindow *prompt, Tox *m, const char *statusmsg);
void prompt_update_status(ToxWindow *prompt, Tox_User_Status status);
void prompt_update_status(ToxWindow *prompt, TOX_USER_STATUS status);
void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected);
void kill_prompt_window(ToxWindow *self);
/* callback: Updates own connection status in prompt statusbar */
void on_self_connection_status(Tox *m, Tox_Connection connection_status, void *userdata);
/* Returns our own connection status */
Tox_Connection prompt_selfConnectionStatus(void);
void prompt_onSelfConnectionChange(Tox *m, TOX_CONNECTION connection_status, void *userdata);
#endif /* end of include guard: PROMPT_H */

View File

@ -1,367 +0,0 @@
/* python_api.c
*
*
* Copyright (C) 2017 Jakob Kreuze <jakob@memeware.net>
*
* This file is part of Toxic.
*
* Toxic is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Toxic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifdef PYTHON
#include <Python.h>
#include "api.h"
#include "execute.h"
extern Tox *user_tox;
static struct python_registered_func {
char *name;
char *help;
PyObject *callback;
struct python_registered_func *next;
} python_commands = {0};
static PyObject *python_api_display(PyObject *self, PyObject *args)
{
const char *msg;
if (!PyArg_ParseTuple(args, "s", &msg)) {
return NULL;
}
api_display(msg);
return Py_None;
}
static PyObject *python_api_get_nick(PyObject *self, PyObject *args)
{
char *name;
PyObject *ret;
if (!PyArg_ParseTuple(args, "")) {
return NULL;
}
name = api_get_nick();
if (name == NULL) {
return NULL;
}
ret = Py_BuildValue("s", name);
free(name);
return ret;
}
static PyObject *python_api_get_status(PyObject *self, PyObject *args)
{
PyObject *ret = NULL;
if (!PyArg_ParseTuple(args, "")) {
return NULL;
}
switch (api_get_status()) {
case TOX_USER_STATUS_NONE:
ret = Py_BuildValue("s", "online");
break;
case TOX_USER_STATUS_AWAY:
ret = Py_BuildValue("s", "away");
break;
case TOX_USER_STATUS_BUSY:
ret = Py_BuildValue("s", "busy");
break;
}
return ret;
}
static PyObject *python_api_get_status_message(PyObject *self, PyObject *args)
{
char *status;
PyObject *ret;
if (!PyArg_ParseTuple(args, "")) {
return NULL;
}
status = api_get_status_message();
if (status == NULL) {
return NULL;
}
ret = Py_BuildValue("s", status);
free(status);
return ret;
}
static PyObject *python_api_get_all_friends(PyObject *self, PyObject *args)
{
size_t i, ii;
FriendsList friends;
PyObject *cur, *ret;
char pubkey_buf[TOX_PUBLIC_KEY_SIZE * 2 + 1];
if (!PyArg_ParseTuple(args, "")) {
return NULL;
}
friends = api_get_friendslist();
ret = PyList_New(0);
for (i = 0; i < friends.num_friends; i++) {
for (ii = 0; ii < TOX_PUBLIC_KEY_SIZE; ii++) {
snprintf(pubkey_buf + ii * 2, 3, "%02X", friends.list[i].pub_key[ii] & 0xff);
}
pubkey_buf[TOX_PUBLIC_KEY_SIZE * 2] = '\0';
cur = Py_BuildValue("(s,s)", friends.list[i].name, pubkey_buf);
PyList_Append(ret, cur);
}
return ret;
}
static PyObject *python_api_send(PyObject *self, PyObject *args)
{
const char *msg;
if (!PyArg_ParseTuple(args, "s", &msg)) {
return NULL;
}
api_send(msg);
return Py_None;
}
static PyObject *python_api_execute(PyObject *self, PyObject *args)
{
int mode;
const char *command;
if (!PyArg_ParseTuple(args, "si", &command, &mode)) {
return NULL;
}
api_execute(command, mode);
return Py_None;
}
static PyObject *python_api_register(PyObject *self, PyObject *args)
{
struct python_registered_func *cur;
size_t command_len, help_len;
const char *command, *help;
PyObject *callback;
if (!PyArg_ParseTuple(args, "ssO:register_command", &command, &help, &callback)) {
return NULL;
}
if (!PyCallable_Check(callback)) {
PyErr_SetString(PyExc_TypeError, "Calback parameter must be callable");
return NULL;
}
if (command[0] != '/') {
PyErr_SetString(PyExc_TypeError, "Command must be prefixed with a '/'");
return NULL;
}
for (cur = &python_commands; ; cur = cur->next) {
if (cur->name != NULL && !strcmp(command, cur->name)) {
Py_XDECREF(cur->callback);
Py_XINCREF(callback);
cur->callback = callback;
break;
}
if (cur->next == NULL) {
Py_XINCREF(callback);
cur->next = malloc(sizeof(struct python_registered_func));
if (cur->next == NULL) {
return PyErr_NoMemory();
}
command_len = strlen(command);
cur->next->name = malloc(command_len + 1);
if (cur->next->name == NULL) {
return PyErr_NoMemory();
}
strncpy(cur->next->name, command, command_len + 1);
help_len = strlen(help);
cur->next->help = malloc(help_len + 1);
if (cur->next->help == NULL) {
return PyErr_NoMemory();
}
strncpy(cur->next->help, help, help_len + 1);
cur->next->callback = callback;
cur->next->next = NULL;
break;
}
}
Py_INCREF(Py_None);
return Py_None;
}
static PyMethodDef ToxicApiMethods[] = {
{"display", python_api_display, METH_VARARGS, "Display a message to the current prompt"},
{"get_nick", python_api_get_nick, METH_VARARGS, "Return the user's current nickname"},
{"get_status", python_api_get_status, METH_VARARGS, "Returns the user's current status"},
{"get_status_message", python_api_get_status_message, METH_VARARGS, "Return the user's current status message"},
{"get_all_friends", python_api_get_all_friends, METH_VARARGS, "Return all of the user's friends"},
{"send", python_api_send, METH_VARARGS, "Send the message to the current user"},
{"execute", python_api_execute, METH_VARARGS, "Execute a command like `/nick`"},
{"register", python_api_register, METH_VARARGS, "Register a command like `/nick` to a Python function"},
{NULL, NULL, 0, NULL},
};
static struct PyModuleDef toxic_api_module = {
PyModuleDef_HEAD_INIT,
"toxic_api",
NULL,
-1,
ToxicApiMethods
};
PyMODINIT_FUNC PyInit_toxic_api(void)
{
PyObject *m = PyModule_Create(&toxic_api_module);
PyObject *global_command_const = Py_BuildValue("i", GLOBAL_COMMAND_MODE);
PyObject *chat_command_const = Py_BuildValue("i", CHAT_COMMAND_MODE);
PyObject *groupchat_command_const = Py_BuildValue("i", GROUPCHAT_COMMAND_MODE);
PyObject_SetAttrString(m, "GLOBAL_COMMAND", global_command_const);
PyObject_SetAttrString(m, "CHAT_COMMAND", chat_command_const);
PyObject_SetAttrString(m, "GROUPCHAT_COMMAND", groupchat_command_const);
Py_DECREF(global_command_const);
Py_DECREF(chat_command_const);
Py_DECREF(groupchat_command_const);
return m;
}
void terminate_python(void)
{
struct python_registered_func *cur, *old;
if (python_commands.name != NULL) {
free(python_commands.name);
}
for (cur = python_commands.next; cur != NULL;) {
old = cur;
cur = cur->next;
free(old->name);
free(old);
}
Py_Finalize();
}
void init_python(Tox *m)
{
user_tox = m;
PyImport_AppendInittab("toxic_api", PyInit_toxic_api);
Py_Initialize();
}
void run_python(FILE *fp, char *path)
{
PyRun_SimpleFile(fp, path);
}
int do_python_command(int num_args, char (*args)[MAX_STR_SIZE])
{
int i;
PyObject *callback_args, *args_strings;
struct python_registered_func *cur;
for (cur = &python_commands; cur != NULL; cur = cur->next) {
if (cur->name == NULL) {
continue;
}
if (!strcmp(args[0], cur->name)) {
args_strings = PyList_New(0);
for (i = 1; i < num_args; i++) {
PyList_Append(args_strings, Py_BuildValue("s", args[i]));
}
callback_args = PyTuple_Pack(1, args_strings);
if (PyObject_CallObject(cur->callback, callback_args) == NULL) {
api_display("Exception raised in callback function");
}
return 0;
}
}
return 1;
}
int python_num_registered_handlers(void)
{
int n = 0;
struct python_registered_func *cur;
for (cur = &python_commands; cur != NULL; cur = cur->next) {
if (cur->name != NULL) {
n++;
}
}
return n;
}
int python_help_max_width(void)
{
size_t tmp;
int max = 0;
struct python_registered_func *cur;
for (cur = &python_commands; cur != NULL; cur = cur->next) {
if (cur->name != NULL) {
tmp = strlen(cur->help);
max = tmp > max ? tmp : max;
}
}
max = max > 50 ? 50 : max;
return 37 + max;
}
void python_draw_handler_help(WINDOW *win)
{
struct python_registered_func *cur;
for (cur = &python_commands; cur != NULL; cur = cur->next) {
if (cur->name != NULL) {
wprintw(win, " %-29s: %.50s\n", cur->name, cur->help);
}
}
}
#endif /* PYTHON */

View File

@ -1,39 +0,0 @@
/* python_api.h
*
*
* Copyright (C) 2017 Jakob Kreuze <jakob@memeware.net>
*
* This file is part of Toxic.
*
* Toxic is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Toxic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PYTHON_API_H
#define PYTHON_API_H
#ifdef PYTHON
#include <Python.h>
#endif /* PYTHON */
PyMODINIT_FUNC PyInit_toxic_api(void);
void terminate_python(void);
void init_python(Tox *m);
void run_python(FILE *fp, char *path);
int do_python_command(int num_args, char (*args)[MAX_STR_SIZE]);
int python_num_registered_handlers(void);
int python_help_max_width(void);
void python_draw_handler_help(WINDOW *win);
#endif /* PYTHON_API_H */

View File

@ -20,12 +20,9 @@
*
*/
#ifdef QRCODE
#include <stdlib.h>
#include <qrencode.h>
#include <stdbool.h>
#include <string.h>
#include "toxic.h"
#include "windows.h"
@ -52,9 +49,8 @@ int ID_to_QRcode_txt(const char *tox_id, const char *outfile)
{
FILE *fp = fopen(outfile, "wb");
if (fp == NULL) {
if (fp == NULL)
return -1;
}
QRcode *qr_obj = QRcode_encodeString(tox_id, 0, QR_ECLEVEL_L, QR_MODE_8, 0);
@ -66,16 +62,14 @@ int ID_to_QRcode_txt(const char *tox_id, const char *outfile)
size_t width = qr_obj->width;
size_t i, j;
for (i = 0; i < width + BORDER_LEN * 2; ++i) {
for (i = 0; i < width + BORDER_LEN * 2; ++i)
fprintf(fp, "%s", CHAR_1);
}
fprintf(fp, "\n");
for (i = 0; i < width; i += 2) {
for (j = 0; j < BORDER_LEN; ++j) {
for (j = 0; j < BORDER_LEN; ++j)
fprintf(fp, "%s", CHAR_1);
}
const unsigned char *row_1 = qr_obj->data + width * i;
const unsigned char *row_2 = row_1 + width;
@ -84,20 +78,18 @@ int ID_to_QRcode_txt(const char *tox_id, const char *outfile)
bool x = row_1[j] & 1;
bool y = (i + 1) < width ? (row_2[j] & 1) : false;
if (x && y) {
if (x && y)
fprintf(fp, " ");
} else if (x) {
else if (x)
fprintf(fp, "%s", CHAR_2);
} else if (y) {
else if (y)
fprintf(fp, "%s", CHAR_3);
} else {
else
fprintf(fp, "%s", CHAR_1);
}
}
for (j = 0; j < BORDER_LEN; ++j) {
for (j = 0; j < BORDER_LEN; ++j)
fprintf(fp, "%s", CHAR_1);
}
fprintf(fp, "\n");
}
@ -215,5 +207,3 @@ int ID_to_QRcode_png(const char *tox_id, const char *outfile)
return 0;
}
#endif /* QRPNG */
#endif /* QRCODE */

View File

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

View File

@ -68,6 +68,7 @@ static struct ui_strings {
const char *line_quit;
const char *line_alert;
const char *line_normal;
const char *line_special;
const char *mplex_away;
const char *mplex_away_note;
@ -94,6 +95,7 @@ static struct ui_strings {
"line_quit",
"line_alert",
"line_normal",
"line_special",
"mplex_away",
"mplex_away_note",
};
@ -122,12 +124,13 @@ static void ui_defaults(struct user_settings *settings)
snprintf(settings->line_quit, LINE_HINT_MAX + 1, "%s", LINE_QUIT);
snprintf(settings->line_alert, LINE_HINT_MAX + 1, "%s", LINE_ALERT);
snprintf(settings->line_normal, LINE_HINT_MAX + 1, "%s", LINE_NORMAL);
snprintf(settings->line_special, LINE_HINT_MAX + 1, "%s", LINE_SPECIAL);
settings->mplex_away = MPLEX_ON;
snprintf(settings->mplex_away_note,
sizeof(settings->mplex_away_note),
"%s",
MPLEX_AWAY_NOTE);
snprintf (settings->mplex_away_note,
sizeof (settings->mplex_away_note),
"%s",
MPLEX_AWAY_NOTE);
}
static const struct keys_strings {
@ -179,14 +182,12 @@ static const struct tox_strings {
const char *download_path;
const char *chatlogs_path;
const char *avatar_path;
const char *autorun_path;
const char *password_eval;
} tox_strings = {
"tox",
"download_path",
"chatlogs_path",
"avatar_path",
"autorun_path",
"password_eval",
};
@ -195,7 +196,6 @@ static void tox_defaults(struct user_settings *settings)
strcpy(settings->download_path, "");
strcpy(settings->chatlogs_path, "");
strcpy(settings->avatar_path, "");
strcpy(settings->autorun_path, "");
strcpy(settings->password_eval, "");
}
@ -253,18 +253,15 @@ static int key_parse(const char **bind)
int len = strlen(*bind);
if (len > 5) {
if (strncasecmp(*bind, "ctrl+", 5) == 0 && toupper(bind[0][5]) != 'M') { /* ctrl+m cannot be used */
if (strncasecmp(*bind, "ctrl+", 5) == 0 && toupper(bind[0][5]) != 'M') /* ctrl+m cannot be used */
return toupper(bind[0][5]) - 'A' + 1;
}
}
if (strncasecmp(*bind, "tab", 3) == 0) {
if (strncasecmp(*bind, "tab", 3) == 0)
return T_KEY_TAB;
}
if (strncasecmp(*bind, "page", 4) == 0) {
if (strncasecmp(*bind, "page", 4) == 0)
return len == 6 ? KEY_PPAGE : KEY_NPAGE;
}
return -1;
}
@ -307,9 +304,8 @@ int settings_load(struct user_settings *s, const char *patharg)
if (!file_exists(path)) {
FILE *fp = fopen(path, "w");
if (fp == NULL) {
if (fp == NULL)
return -1;
}
fclose(fp);
}
@ -328,18 +324,18 @@ int settings_load(struct user_settings *s, const char *patharg)
int time = 24;
if (config_setting_lookup_int(setting, ui_strings.time_format, &time)) {
if ( config_setting_lookup_int(setting, ui_strings.time_format, &time) ) {
if (time == 12) {
snprintf(s->timestamp_format, sizeof(s->timestamp_format), "%s", "%I:%M:%S %p");
snprintf(s->log_timestamp_format, sizeof(s->log_timestamp_format), "%s", "%Y/%m/%d [%I:%M:%S %p]");
}
}
if (config_setting_lookup_string(setting, ui_strings.timestamp_format, &str)) {
if ( config_setting_lookup_string(setting, ui_strings.timestamp_format, &str) ) {
snprintf(s->timestamp_format, sizeof(s->timestamp_format), "%s", str);
}
if (config_setting_lookup_string(setting, ui_strings.log_timestamp_format, &str)) {
if ( config_setting_lookup_string(setting, ui_strings.log_timestamp_format, &str) ) {
snprintf(s->log_timestamp_format, sizeof(s->log_timestamp_format), "%s", str);
}
@ -371,85 +367,70 @@ int settings_load(struct user_settings *s, const char *patharg)
config_setting_lookup_int(setting, ui_strings.history_size, &s->history_size);
config_setting_lookup_int(setting, ui_strings.nodeslist_update_freq, &s->nodeslist_update_freq);
if (config_setting_lookup_string(setting, ui_strings.line_join, &str)) {
if ( config_setting_lookup_string(setting, ui_strings.line_join, &str) ) {
snprintf(s->line_join, sizeof(s->line_join), "%s", str);
}
if (config_setting_lookup_string(setting, ui_strings.line_quit, &str)) {
if ( config_setting_lookup_string(setting, ui_strings.line_quit, &str) ) {
snprintf(s->line_quit, sizeof(s->line_quit), "%s", str);
}
if (config_setting_lookup_string(setting, ui_strings.line_alert, &str)) {
if ( config_setting_lookup_string(setting, ui_strings.line_alert, &str) ) {
snprintf(s->line_alert, sizeof(s->line_alert), "%s", str);
}
if (config_setting_lookup_string(setting, ui_strings.line_normal, &str)) {
if ( config_setting_lookup_string(setting, ui_strings.line_normal, &str) ) {
snprintf(s->line_normal, sizeof(s->line_normal), "%s", str);
}
config_setting_lookup_bool(setting, ui_strings.mplex_away, &s->mplex_away);
if ( config_setting_lookup_string(setting, ui_strings.line_special, &str) ) {
snprintf(s->line_special, sizeof(s->line_special), "%s", str);
}
if (config_setting_lookup_string(setting, ui_strings.mplex_away_note, &str)) {
snprintf(s->mplex_away_note, sizeof(s->mplex_away_note), "%s", str);
config_setting_lookup_bool (setting, ui_strings.mplex_away, &s->mplex_away);
if (config_setting_lookup_string (setting, ui_strings.mplex_away_note, &str)) {
snprintf (s->mplex_away_note, sizeof (s->mplex_away_note), "%s", str);
}
}
/* paths */
if ((setting = config_lookup(cfg, tox_strings.self)) != NULL) {
if (config_setting_lookup_string(setting, tox_strings.download_path, &str)) {
if ( config_setting_lookup_string(setting, tox_strings.download_path, &str) ) {
snprintf(s->download_path, sizeof(s->download_path), "%s", str);
int len = strlen(s->download_path);
/* make sure path ends with a '/' */
if (len >= sizeof(s->download_path) - 2) {
if (len >= sizeof(s->download_path) - 2)
s->download_path[0] = '\0';
} else if (s->download_path[len - 1] != '/') {
else if (s->download_path[len - 1] != '/')
strcat(&s->download_path[len - 1], "/");
}
}
if (config_setting_lookup_string(setting, tox_strings.chatlogs_path, &str)) {
if ( config_setting_lookup_string(setting, tox_strings.chatlogs_path, &str) ) {
snprintf(s->chatlogs_path, sizeof(s->chatlogs_path), "%s", str);
int len = strlen(s->chatlogs_path);
if (len >= sizeof(s->chatlogs_path) - 2) {
if (len >= sizeof(s->chatlogs_path) - 2)
s->chatlogs_path[0] = '\0';
} else if (s->chatlogs_path[len - 1] != '/') {
else if (s->chatlogs_path[len - 1] != '/')
strcat(&s->chatlogs_path[len - 1], "/");
}
}
if (config_setting_lookup_string(setting, tox_strings.avatar_path, &str)) {
if ( config_setting_lookup_string(setting, tox_strings.avatar_path, &str) ) {
snprintf(s->avatar_path, sizeof(s->avatar_path), "%s", str);
int len = strlen(str);
if (len >= sizeof(s->avatar_path)) {
if (len >= sizeof(s->avatar_path))
s->avatar_path[0] = '\0';
}
}
#ifdef PYTHON
if (config_setting_lookup_string(setting, tox_strings.autorun_path, &str)) {
snprintf(s->autorun_path, sizeof(s->autorun_path), "%s", str);
int len = strlen(str);
if (len >= sizeof(s->autorun_path) - 2) {
s->autorun_path[0] = '\0';
} else if (s->autorun_path[len - 1] != '/') {
strcat(&s->autorun_path[len - 1], "/");
}
}
#endif
if (config_setting_lookup_string(setting, tox_strings.password_eval, &str)) {
if ( config_setting_lookup_string(setting, tox_strings.password_eval, &str) ) {
snprintf(s->password_eval, sizeof(s->password_eval), "%s", str);
int len = strlen(str);
if (len >= sizeof(s->password_eval)) {
if (len >= sizeof(s->password_eval))
s->password_eval[0] = '\0';
}
}
}
@ -457,49 +438,38 @@ int settings_load(struct user_settings *s, const char *patharg)
if ((setting = config_lookup(cfg, key_strings.self)) != NULL) {
const char *tmp = NULL;
if (config_setting_lookup_string(setting, key_strings.next_tab, &tmp)) {
if (config_setting_lookup_string(setting, key_strings.next_tab, &tmp))
set_key_binding(&s->key_next_tab, &tmp);
}
if (config_setting_lookup_string(setting, key_strings.prev_tab, &tmp)) {
if (config_setting_lookup_string(setting, key_strings.prev_tab, &tmp))
set_key_binding(&s->key_prev_tab, &tmp);
}
if (config_setting_lookup_string(setting, key_strings.scroll_line_up, &tmp)) {
if (config_setting_lookup_string(setting, key_strings.scroll_line_up, &tmp))
set_key_binding(&s->key_scroll_line_up, &tmp);
}
if (config_setting_lookup_string(setting, key_strings.scroll_line_down, &tmp)) {
if (config_setting_lookup_string(setting, key_strings.scroll_line_down, &tmp))
set_key_binding(&s->key_scroll_line_down, &tmp);
}
if (config_setting_lookup_string(setting, key_strings.half_page_up, &tmp)) {
if (config_setting_lookup_string(setting, key_strings.half_page_up, &tmp))
set_key_binding(&s->key_half_page_up, &tmp);
}
if (config_setting_lookup_string(setting, key_strings.half_page_down, &tmp)) {
if (config_setting_lookup_string(setting, key_strings.half_page_down, &tmp))
set_key_binding(&s->key_half_page_down, &tmp);
}
if (config_setting_lookup_string(setting, key_strings.page_bottom, &tmp)) {
if (config_setting_lookup_string(setting, key_strings.page_bottom, &tmp))
set_key_binding(&s->key_page_bottom, &tmp);
}
if (config_setting_lookup_string(setting, key_strings.peer_list_up, &tmp)) {
if (config_setting_lookup_string(setting, key_strings.peer_list_up, &tmp))
set_key_binding(&s->key_peer_list_up, &tmp);
}
if (config_setting_lookup_string(setting, key_strings.peer_list_down, &tmp)) {
if (config_setting_lookup_string(setting, key_strings.peer_list_down, &tmp))
set_key_binding(&s->key_peer_list_down, &tmp);
}
if (config_setting_lookup_string(setting, key_strings.toggle_peerlist, &tmp)) {
if (config_setting_lookup_string(setting, key_strings.toggle_peerlist, &tmp))
set_key_binding(&s->key_toggle_peerlist, &tmp);
}
if (config_setting_lookup_string(setting, key_strings.toggle_pastemode, &tmp)) {
if (config_setting_lookup_string(setting, key_strings.toggle_pastemode, &tmp))
set_key_binding(&s->key_toggle_pastemode, &tmp);
}
}
#ifdef AUDIO
@ -519,60 +489,52 @@ int settings_load(struct user_settings *s, const char *patharg)
#ifdef SOUND_NOTIFY
if ((setting = config_lookup(cfg, sound_strings.self)) != NULL) {
if ((config_setting_lookup_string(setting, sound_strings.notif_error, &str) != CONFIG_TRUE) ||
!set_sound(notif_error, str)) {
if (str && strcasecmp(str, NO_SOUND) != 0) {
if ( (config_setting_lookup_string(setting, sound_strings.notif_error, &str) != CONFIG_TRUE) ||
!set_sound(notif_error, str) ) {
if (str && strcasecmp(str, NO_SOUND) != 0)
set_sound(notif_error, PACKAGE_DATADIR "/sounds/ToxicError.wav");
}
}
if (!config_setting_lookup_string(setting, sound_strings.user_log_in, &str) ||
!set_sound(user_log_in, str)) {
if (str && strcasecmp(str, NO_SOUND) != 0) {
if ( !config_setting_lookup_string(setting, sound_strings.user_log_in, &str) ||
!set_sound(user_log_in, str) ) {
if (str && strcasecmp(str, NO_SOUND) != 0)
set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ToxicContactOnline.wav");
}
}
if (!config_setting_lookup_string(setting, sound_strings.user_log_out, &str) ||
!set_sound(user_log_out, str)) {
if (str && strcasecmp(str, NO_SOUND) != 0) {
if ( !config_setting_lookup_string(setting, sound_strings.user_log_out, &str) ||
!set_sound(user_log_out, str) ) {
if (str && strcasecmp(str, NO_SOUND) != 0)
set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ToxicContactOffline.wav");
}
}
if (!config_setting_lookup_string(setting, sound_strings.call_incoming, &str) ||
!set_sound(call_incoming, str)) {
if (str && strcasecmp(str, NO_SOUND) != 0) {
if ( !config_setting_lookup_string(setting, sound_strings.call_incoming, &str) ||
!set_sound(call_incoming, str) ) {
if (str && strcasecmp(str, NO_SOUND) != 0)
set_sound(call_incoming, PACKAGE_DATADIR "/sounds/ToxicIncomingCall.wav");
}
}
if (!config_setting_lookup_string(setting, sound_strings.call_outgoing, &str) ||
!set_sound(call_outgoing, str)) {
if (str && strcasecmp(str, NO_SOUND) != 0) {
if ( !config_setting_lookup_string(setting, sound_strings.call_outgoing, &str) ||
!set_sound(call_outgoing, str) ) {
if (str && strcasecmp(str, NO_SOUND) != 0)
set_sound(call_outgoing, PACKAGE_DATADIR "/sounds/ToxicOutgoingCall.wav");
}
}
if (!config_setting_lookup_string(setting, sound_strings.generic_message, &str) ||
!set_sound(generic_message, str)) {
if (str && strcasecmp(str, NO_SOUND) != 0) {
if ( !config_setting_lookup_string(setting, sound_strings.generic_message, &str) ||
!set_sound(generic_message, str) ) {
if (str && strcasecmp(str, NO_SOUND) != 0)
set_sound(generic_message, PACKAGE_DATADIR "/sounds/ToxicRecvMessage.wav");
}
}
if (!config_setting_lookup_string(setting, sound_strings.transfer_pending, &str) ||
!set_sound(transfer_pending, str)) {
if (str && strcasecmp(str, NO_SOUND) != 0) {
if ( !config_setting_lookup_string(setting, sound_strings.transfer_pending, &str) ||
!set_sound(transfer_pending, str) ) {
if (str && strcasecmp(str, NO_SOUND) != 0)
set_sound(transfer_pending, PACKAGE_DATADIR "/sounds/ToxicTransferStart.wav");
}
}
if (!config_setting_lookup_string(setting, sound_strings.transfer_completed, &str) ||
!set_sound(transfer_completed, str)) {
if (str && strcasecmp(str, NO_SOUND) != 0) {
if ( !config_setting_lookup_string(setting, sound_strings.transfer_completed, &str) ||
!set_sound(transfer_completed, str) ) {
if (str && strcasecmp(str, NO_SOUND) != 0)
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/ToxicTransferComplete.wav");
}
}
} else {
set_sound(notif_error, PACKAGE_DATADIR "/sounds/ToxicError.wav");

View File

@ -59,11 +59,11 @@ struct user_settings {
char line_quit[LINE_HINT_MAX + 1];
char line_alert[LINE_HINT_MAX + 1];
char line_normal[LINE_HINT_MAX + 1];
char line_special[LINE_HINT_MAX + 1];
char download_path[PATH_MAX];
char chatlogs_path[PATH_MAX];
char avatar_path[PATH_MAX];
char autorun_path[PATH_MAX];
char password_eval[PASSWORD_EVAL_MAX];
int key_next_tab;
@ -88,7 +88,7 @@ struct user_settings {
#endif
};
enum settings_values {
enum {
AUTOLOG_OFF = 0,
AUTOLOG_ON = 1,
@ -114,16 +114,16 @@ enum settings_values {
MPLEX_OFF = 0,
MPLEX_ON = 1,
};
} settings_values;
#define LINE_JOIN "-->"
#define LINE_QUIT "<--"
#define LINE_ALERT "-!-"
#define LINE_NORMAL "---"
#define LINE_SPECIAL ">>>"
#define TIMESTAMP_DEFAULT "%H:%M:%S"
#define LOG_TIMESTAMP_DEFAULT "%Y/%m/%d [%H:%M:%S]"
#define MPLEX_AWAY_NOTE "Detached from screen"
int settings_load(struct user_settings *s, const char *patharg);
#endif /* SETTINGS_H */
#endif /* #define SETTINGS_H */

View File

@ -33,7 +33,7 @@
#include <tox/tox.h>
#include "execute.h"
#include "global_commands.h"
#include "windows.h"
#include "term_mplex.h"
#include "toxic.h"
@ -69,7 +69,7 @@ static char buffer [BUFFER_SIZE];
static bool auto_away_active = false;
static mplex_status mplex = MPLEX_NONE;
static Tox_User_Status prev_status = TOX_USER_STATUS_NONE;
static TOX_USER_STATUS prev_status = TOX_USER_STATUS_NONE;
static char prev_note [TOX_MAX_STATUS_MESSAGE_LENGTH] = "";
/* mutex for access to status data, for sync between:
@ -80,118 +80,108 @@ static char prev_note [TOX_MAX_STATUS_MESSAGE_LENGTH] = "";
static pthread_mutex_t status_lock;
static pthread_t mplex_tid;
void lock_status(void)
void lock_status ()
{
pthread_mutex_lock(&status_lock);
pthread_mutex_lock (&status_lock);
}
void unlock_status(void)
void unlock_status ()
{
pthread_mutex_unlock(&status_lock);
pthread_mutex_unlock (&status_lock);
}
static char *read_into_dyn_buffer(FILE *stream)
static char *read_into_dyn_buffer (FILE *stream)
{
const char *input_ptr = NULL;
char *dyn_buffer = NULL;
int dyn_buffer_size = 1; /* account for the \0 */
while ((input_ptr = fgets(buffer, BUFFER_SIZE, stream)) != NULL) {
int length = dyn_buffer_size + strlen(input_ptr);
while ((input_ptr = fgets (buffer, BUFFER_SIZE, stream)) != NULL) {
int length = dyn_buffer_size + strlen (input_ptr);
if (dyn_buffer) {
dyn_buffer = (char *) realloc(dyn_buffer, length);
} else {
dyn_buffer = (char *) malloc(length);
}
if (dyn_buffer)
dyn_buffer = (char *) realloc (dyn_buffer, length);
else
dyn_buffer = (char *) malloc (length);
strcpy(dyn_buffer + dyn_buffer_size - 1, input_ptr);
strcpy (dyn_buffer + dyn_buffer_size - 1, input_ptr);
dyn_buffer_size = length;
}
return dyn_buffer;
}
static char *extract_socket_path(const char *info)
static char *extract_socket_path (const char *info)
{
const char *search_str = " Socket";
const char *pos = strstr(info, search_str);
const char *pos = strstr (info, search_str);
char *end = NULL;
char *path = NULL;
if (!pos) {
if (!pos)
return NULL;
}
pos += strlen(search_str);
pos = strchr(pos, PATH_SEP_C);
pos += strlen (search_str);
pos = strchr (pos, PATH_SEP_C);
if (!pos) {
if (!pos)
return NULL;
}
end = strchr(pos, '\n');
end = strchr (pos, '\n');
if (!end) {
if (!end)
return NULL;
}
*end = '\0';
end = strrchr(pos, '.');
end = strrchr (pos, '.');
if (!end) {
if (!end)
return NULL;
}
path = (char *) malloc(end - pos + 1);
path = (char *) malloc (end - pos + 1);
*end = '\0';
return strcpy(path, pos);
return strcpy (path, pos);
}
static int detect_gnu_screen(void)
static int detect_gnu_screen ()
{
FILE *session_info_stream = NULL;
char *socket_name = NULL, *socket_path = NULL;
char *dyn_buffer = NULL;
socket_name = getenv("STY");
socket_name = getenv ("STY");
if (!socket_name) {
if (!socket_name)
goto nomplex;
}
session_info_stream = popen("env LC_ALL=C screen -ls", "r");
session_info_stream = popen ("env LC_ALL=C screen -ls", "r");
if (!session_info_stream) {
if (!session_info_stream)
goto nomplex;
}
dyn_buffer = read_into_dyn_buffer(session_info_stream);
dyn_buffer = read_into_dyn_buffer (session_info_stream);
if (!dyn_buffer) {
if (!dyn_buffer)
goto nomplex;
}
pclose(session_info_stream);
pclose (session_info_stream);
session_info_stream = NULL;
socket_path = extract_socket_path(dyn_buffer);
socket_path = extract_socket_path (dyn_buffer);
if (!socket_path) {
if (!socket_path)
goto nomplex;
}
free(dyn_buffer);
free (dyn_buffer);
dyn_buffer = NULL;
if (strlen(socket_path) + strlen(PATH_SEP_S) + strlen(socket_name) >= sizeof(mplex_data)) {
if (strlen(socket_path) + strlen(PATH_SEP_S) + strlen(socket_name) >= sizeof(mplex_data))
goto nomplex;
}
strcpy(mplex_data, socket_path);
strcat(mplex_data, PATH_SEP_S);
strcat(mplex_data, socket_name);
free(socket_path);
strcpy (mplex_data, socket_path);
strcat (mplex_data, PATH_SEP_S);
strcat (mplex_data, socket_name);
free (socket_path);
socket_path = NULL;
mplex = MPLEX_SCREEN;
@ -199,38 +189,33 @@ static int detect_gnu_screen(void)
nomplex:
if (session_info_stream) {
pclose(session_info_stream);
}
if (session_info_stream)
pclose (session_info_stream);
if (dyn_buffer) {
free(dyn_buffer);
}
if (dyn_buffer)
free (dyn_buffer);
if (socket_path) {
if (socket_path)
free(socket_path);
}
return 0;
}
static int detect_tmux(void)
static int detect_tmux ()
{
char *tmux_env = getenv("TMUX"), *pos;
char *tmux_env = getenv ("TMUX"), *pos;
if (!tmux_env) {
if (!tmux_env)
return 0;
}
/* find second separator */
pos = strrchr(tmux_env, ',');
pos = strrchr (tmux_env, ',');
if (!pos) {
if (!pos)
return 0;
}
/* store the session id for later use */
snprintf(mplex_data, sizeof(mplex_data), "$%s", pos + 1);
/* store the session number string for later use */
snprintf (mplex_data, sizeof(mplex_data), "%s", pos + 1);
mplex = MPLEX_TMUX;
return 1;
}
@ -243,102 +228,98 @@ static int detect_tmux(void)
Returns 1 if present, 0 otherwise. This value can be used to determine
whether an auto-away detection timer is needed.
*/
static int detect_mplex(void)
static int detect_mplex ()
{
/* try screen, and if fails try tmux */
return detect_gnu_screen() || detect_tmux();
return detect_gnu_screen () || detect_tmux ();
}
/* Detects gnu screen session attached/detached by examining permissions of
the session's unix socket.
*/
static int gnu_screen_is_detached(void)
static int gnu_screen_is_detached ()
{
if (mplex != MPLEX_SCREEN) {
if (mplex != MPLEX_SCREEN)
return 0;
}
struct stat sb;
if (stat(mplex_data, &sb) != 0) {
if (stat (mplex_data, &sb) != 0)
return 0;
}
/* execution permission (x) means attached */
return !(sb.st_mode & S_IXUSR);
return ! (sb.st_mode & S_IXUSR);
}
/* Detects tmux attached/detached by getting session data and finding the
current session's entry.
*/
static int tmux_is_detached(void)
current session's entry. An attached entry ends with "(attached)". Example:
$ tmux list-sessions
0: 1 windows (created Mon Mar 2 21:48:29 2015) [80x23] (attached)
1: 2 windows (created Mon Mar 2 21:48:43 2015) [80x23]
In this example, session 0 is attached and session 1 is detached.
*/
static int tmux_is_detached ()
{
if (mplex != MPLEX_TMUX) {
if (mplex != MPLEX_TMUX)
return 0;
}
FILE *session_info_stream = NULL;
char *dyn_buffer = NULL, *search_str = NULL;
char *entry_pos;
int detached;
const int numstr_len = strlen(mplex_data);
char *entry_pos, *nl_pos, *attached_pos;
const int numstr_len = strlen (mplex_data);
/* get the number of attached clients for each session */
session_info_stream = popen("tmux list-sessions -F \"#{session_id} #{session_attached}\"", "r");
session_info_stream = popen ("env LC_ALL=C tmux list-sessions", "r");
if (!session_info_stream) {
if (!session_info_stream)
goto fail;
}
dyn_buffer = read_into_dyn_buffer(session_info_stream);
dyn_buffer = read_into_dyn_buffer (session_info_stream);
if (!dyn_buffer) {
if (!dyn_buffer)
goto fail;
}
pclose(session_info_stream);
pclose (session_info_stream);
session_info_stream = NULL;
/* prepare search string, for finding the current session's entry */
search_str = (char *) malloc(numstr_len + 2);
search_str = (char *) malloc (numstr_len + 4);
search_str[0] = '\n';
strcpy(search_str + 1, mplex_data);
strcpy (search_str + 1, mplex_data);
strcat (search_str, ": ");
/* do the search */
if (strncmp(dyn_buffer, search_str + 1, numstr_len) == 0) {
if (strncmp (dyn_buffer, search_str + 1, numstr_len + 2) == 0)
entry_pos = dyn_buffer;
} else {
entry_pos = strstr(dyn_buffer, search_str);
}
else
entry_pos = strstr (dyn_buffer, search_str);
if (! entry_pos) {
if (! entry_pos)
goto fail;
}
entry_pos = strchr(entry_pos, ' ') + 1;
detached = strncmp(entry_pos, "0\n", 2) == 0;
/* find the next \n and look for the "(attached)" before it */
nl_pos = strchr (entry_pos + 1, '\n');
attached_pos = strstr (entry_pos + 1, "(attached)\n");
free(search_str);
free (search_str);
search_str = NULL;
free(dyn_buffer);
free (dyn_buffer);
dyn_buffer = NULL;
return detached;
return attached_pos == NULL || attached_pos > nl_pos;
fail:
if (session_info_stream) {
pclose(session_info_stream);
}
if (session_info_stream)
pclose (session_info_stream);
if (dyn_buffer) {
free(dyn_buffer);
}
if (dyn_buffer)
free (dyn_buffer);
if (search_str) {
free(search_str);
}
if (search_str)
free (search_str);
return 0;
}
@ -352,25 +333,24 @@ fail:
sample its state and update away status according to attached/detached state
of the mplex.
*/
static int mplex_is_detached(void)
static int mplex_is_detached ()
{
return gnu_screen_is_detached() || tmux_is_detached();
return gnu_screen_is_detached () || tmux_is_detached ();
}
static void mplex_timer_handler(Tox *m)
static void mplex_timer_handler (Tox *m)
{
Tox_User_Status current_status, new_status;
TOX_USER_STATUS current_status, new_status;
const char *new_note;
if (mplex == MPLEX_NONE) {
if (mplex == MPLEX_NONE)
return;
}
int detached = mplex_is_detached();
int detached = mplex_is_detached ();
pthread_mutex_lock(&Winthread.lock);
current_status = tox_self_get_status(m);
pthread_mutex_unlock(&Winthread.lock);
pthread_mutex_lock (&Winthread.lock);
current_status = tox_self_get_status (m);
pthread_mutex_unlock (&Winthread.lock);
if (auto_away_active && current_status == TOX_USER_STATUS_AWAY && !detached) {
auto_away_active = false;
@ -380,27 +360,25 @@ static void mplex_timer_handler(Tox *m)
auto_away_active = true;
prev_status = current_status;
new_status = TOX_USER_STATUS_AWAY;
pthread_mutex_lock(&Winthread.lock);
pthread_mutex_lock (&Winthread.lock);
size_t slen = tox_self_get_status_message_size(m);
tox_self_get_status_message(m, (uint8_t *) prev_note);
tox_self_get_status_message (m, (uint8_t *) prev_note);
prev_note[slen] = '\0';
pthread_mutex_unlock(&Winthread.lock);
pthread_mutex_unlock (&Winthread.lock);
new_note = user_settings->mplex_away_note;
} else {
} else
return;
}
char status_str[MAX_STR_SIZE];
char note_str[MAX_STR_SIZE];
const char *status = new_status == TOX_USER_STATUS_AWAY ? "away" :
new_status == TOX_USER_STATUS_BUSY ? "busy" : "online";
snprintf(status_str, sizeof(status_str), "/status %s", status);
snprintf(note_str, sizeof(status_str), "/note %s", new_note);
pthread_mutex_lock(&Winthread.lock);
execute(prompt->chatwin->history, prompt, m, status_str, GLOBAL_COMMAND_MODE);
execute(prompt->chatwin->history, prompt, m, note_str, GLOBAL_COMMAND_MODE);
pthread_mutex_unlock(&Winthread.lock);
char argv[3][MAX_STR_SIZE];
strcpy (argv[0], "/status");
strcpy (argv[1], (new_status == TOX_USER_STATUS_AWAY ? "away" :
new_status == TOX_USER_STATUS_BUSY ? "busy" : "online"));
argv[2][0] = '\"';
strcpy (argv[2] + 1, new_note);
strcat (argv[2], "\"");
pthread_mutex_lock (&Winthread.lock);
cmd_status (prompt->chatwin->history, prompt, m, 2, argv);
pthread_mutex_unlock (&Winthread.lock);
}
/* Time in seconds between calls to mplex_timer_handler */
@ -416,24 +394,20 @@ void *mplex_timer_thread(void *data)
}
}
int init_mplex_away_timer(Tox *m)
int init_mplex_away_timer (Tox *m)
{
if (! detect_mplex()) {
if (! detect_mplex ())
return 0;
}
if (! user_settings->mplex_away) {
if (! user_settings->mplex_away)
return 0;
}
/* status access mutex */
if (pthread_mutex_init(&status_lock, NULL) != 0) {
if (pthread_mutex_init (&status_lock, NULL) != 0)
return -1;
}
if (pthread_create(&mplex_tid, NULL, mplex_timer_thread, (void *) m) != 0) {
if (pthread_create(&mplex_tid, NULL, mplex_timer_thread, (void *) m) != 0)
return -1;
}
return 0;
}

View File

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

View File

@ -26,7 +26,6 @@
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdarg.h>
#include <signal.h>
#include <locale.h>
#include <string.h>
@ -50,9 +49,9 @@
#include "toxic.h"
#include "windows.h"
#include "friendlist.h"
#include "groupchat.h"
#include "prompt.h"
#include "misc_tools.h"
#include "groupchat.h"
#include "file_transfers.h"
#include "line_info.h"
#include "settings.h"
@ -77,11 +76,6 @@
ToxAV *av;
#endif /* AUDIO */
#ifdef PYTHON
#include "api.h"
#include "python_api.h"
#endif
#ifndef PACKAGE_DATADIR
#define PACKAGE_DATADIR "."
#endif
@ -111,17 +105,9 @@ static struct user_password {
int len;
} user_password;
static time_t last_signal_time;
static void catch_SIGINT(int sig)
{
time_t cur_time = get_unix_time();
if (difftime(cur_time, last_signal_time) <= 1) {
Winthread.sig_exit_toxic = 1;
} else {
last_signal_time = cur_time;
}
Winthread.sig_exit_toxic = 1;
}
static void catch_SIGSEGV(int sig)
@ -177,10 +163,6 @@ void exit_toxic_success(Tox *m)
terminate_audio();
#endif /* AUDIO */
#ifdef PYTHON
terminate_python();
#endif /* PYTHON */
free_global_data();
tox_kill(m);
endwin();
@ -229,9 +211,8 @@ static void init_term(void)
start_color();
if (user_settings->colour_theme == NATIVE_COLS) {
if (assume_default_colors(-1, -1) == OK) {
if (assume_default_colors(-1, -1) == OK)
bg_color = -1;
}
}
init_pair(0, COLOR_WHITE, COLOR_BLACK);
@ -268,15 +249,13 @@ static void queue_init_message(const char *msg, ...)
char **new_msgs = realloc(init_messages.msgs, sizeof(char *) * init_messages.num);
if (new_msgs == NULL) {
if (new_msgs == NULL)
exit_toxic_err("Failed in queue_init_message", FATALERR_MEMORY);
}
new_msgs[i] = malloc(MAX_STR_SIZE);
if (new_msgs[i] == NULL) {
if (new_msgs[i] == NULL)
exit_toxic_err("Failed in queue_init_message", FATALERR_MEMORY);
}
snprintf(new_msgs[i], MAX_STR_SIZE, "%s", frmt_msg);
init_messages.msgs = new_msgs;
@ -285,15 +264,13 @@ static void queue_init_message(const char *msg, ...)
/* called after messages have been printed to prompt and are no longer needed */
static void cleanup_init_messages(void)
{
if (init_messages.num <= 0) {
if (init_messages.num <= 0)
return;
}
int i;
for (i = 0; i < init_messages.num; ++i) {
for (i = 0; i < init_messages.num; ++i)
free(init_messages.msgs[i]);
}
free(init_messages.msgs);
}
@ -302,8 +279,18 @@ static void print_init_messages(ToxWindow *toxwin)
{
int i;
for (i = 0; i < init_messages.num; ++i) {
for (i = 0; i < init_messages.num; ++i)
line_info_add(toxwin, NULL, NULL, NULL, SYS_MSG, 0, 0, init_messages.msgs[i]);
}
static void load_groups(Tox *m)
{
size_t i;
size_t numgroups = tox_group_get_number_groups(m);
for (i = 0; i < numgroups; ++i) {
if (init_groupchat_win(m, i, NULL, 0) == -1)
tox_group_leave(m, i, NULL, 0, NULL);
}
}
@ -312,46 +299,12 @@ 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 (i = 0; i < numfriends; ++i)
friendlist_onFriendAdded(NULL, m, i, false);
}
sort_friendlist_index();
}
static void load_groups(ToxWindow *prompt, Tox *m)
{
size_t i;
size_t num_chats = tox_conference_get_chatlist_size(m);
uint32_t chatlist[num_chats];
if (num_chats) {
tox_conference_get_chatlist(m, chatlist);
}
for (i = 0; i < num_chats; ++i) {
uint32_t groupnum = chatlist[i];
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
tox_conference_delete(m, groupnum, NULL);
continue;
}
Tox_Err_Conference_Get_Type err;
Tox_Conference_Type type = tox_conference_get_type(m, groupnum, &err);
if (err != TOX_ERR_CONFERENCE_GET_TYPE_OK) {
tox_conference_delete(m, groupnum, NULL);
continue;
}
if (init_groupchat_win(prompt, m, groupnum, type) == -1) {
tox_conference_delete(m, groupnum, NULL);
continue;
}
}
}
/* return length of password on success, 0 on failure */
static int password_prompt(char *buf, int size)
{
@ -364,9 +317,8 @@ static int password_prompt(char *buf, int size)
nflags.c_lflag &= ~ECHO;
nflags.c_lflag |= ECHONL;
if (tcsetattr(fileno(stdin), TCSANOW, &nflags) != 0) {
if (tcsetattr(fileno(stdin), TCSANOW, &nflags) != 0)
return 0;
}
const char *p = fgets(buf, size, stdin);
int len = strlen(buf);
@ -374,16 +326,15 @@ static int password_prompt(char *buf, int size)
/* re-enable terminal echo */
tcsetattr(fileno(stdin), TCSANOW, &oflags);
if (p == NULL || len <= 1) {
if (p == NULL || len <= 1)
return 0;
}
/* eat overflowed stdin and return error */
if (buf[--len] != '\n') {
int ch;
while ((ch = getchar()) != '\n' && ch > 0) {
}
while ((ch = getchar()) != '\n' && ch > 0)
;
return 0;
}
@ -443,20 +394,17 @@ static void first_time_encrypt(const char *msg)
do {
system("clear");
printf("%s ", msg);
fflush(stdout);
if (!strcasecmp(ch, "y\n") || !strcasecmp(ch, "n\n") || !strcasecmp(ch, "yes\n")
|| !strcasecmp(ch, "no\n") || !strcasecmp(ch, "q\n")) {
|| !strcasecmp(ch, "no\n") || !strcasecmp(ch, "q\n"))
break;
}
} while (fgets(ch, sizeof(ch), stdin));
printf("\n");
if (ch[0] == 'q' || ch[0] == 'Q') {
if (ch[0] == 'q' || ch[0] == 'Q')
exit(0);
}
if (ch[0] == 'y' || ch[0] == 'Y') {
int len = 0;
@ -466,13 +414,11 @@ static void first_time_encrypt(const char *msg)
printf("Enter a new password (must be at least %d characters) ", MIN_PASSWORD_LEN);
while (valid_password == false) {
fflush(stdout); // Flush all before user input
len = password_prompt(user_password.pass, sizeof(user_password.pass));
user_password.len = len;
if (strcasecmp(user_password.pass, "q") == 0) {
if (strcasecmp(user_password.pass, "q") == 0)
exit(0);
}
if (string_is_empty(passconfirm) && (len < MIN_PASSWORD_LEN || len > MAX_PASSWORD_LEN)) {
printf("Password must be between %d and %d characters long. ", MIN_PASSWORD_LEN, MAX_PASSWORD_LEN);
@ -586,56 +532,63 @@ int store_data(Tox *m, const char *path)
static void init_tox_callbacks(Tox *m)
{
tox_callback_self_connection_status(m, on_self_connection_status);
tox_callback_friend_connection_status(m, on_friend_connection_status);
tox_callback_friend_typing(m, on_friend_typing);
tox_callback_friend_request(m, on_friend_request);
tox_callback_friend_message(m, on_friend_message);
tox_callback_friend_name(m, on_friend_name);
tox_callback_friend_status(m, on_friend_status);
tox_callback_friend_status_message(m, on_friend_status_message);
tox_callback_friend_read_receipt(m, on_friend_read_receipt);
tox_callback_conference_invite(m, on_conference_invite);
tox_callback_conference_message(m, on_conference_message);
tox_callback_conference_peer_list_changed(m, on_conference_peer_list_changed);
tox_callback_conference_peer_name(m, on_conference_peer_name);
tox_callback_conference_title(m, on_conference_title);
tox_callback_file_recv(m, on_file_recv);
tox_callback_file_chunk_request(m, on_file_chunk_request);
tox_callback_file_recv_control(m, on_file_recv_control);
tox_callback_file_recv_chunk(m, on_file_recv_chunk);
tox_callback_self_connection_status(m, prompt_onSelfConnectionChange, NULL);
tox_callback_friend_connection_status(m, on_connectionchange, NULL);
tox_callback_friend_typing(m, on_typing_change, NULL);
tox_callback_friend_request(m, on_request, NULL);
tox_callback_friend_message(m, on_message, NULL);
tox_callback_friend_name(m, on_nickchange, NULL);
tox_callback_friend_status(m, on_statuschange, NULL);
tox_callback_friend_status_message(m, on_statusmessagechange, NULL);
tox_callback_friend_read_receipt(m, on_read_receipt, NULL);
tox_callback_file_recv(m, on_file_recv, NULL);
tox_callback_file_chunk_request(m, on_file_chunk_request, NULL);
tox_callback_file_recv_control(m, on_file_control, NULL);
tox_callback_file_recv_chunk(m, on_file_recv_chunk, NULL);
tox_callback_group_invite(m, on_group_invite, NULL);
tox_callback_group_message(m, on_group_message, NULL);
tox_callback_group_private_message(m, on_group_private_message, NULL);
tox_callback_group_peer_join(m, on_group_peer_join, NULL);
tox_callback_group_peer_exit(m, on_group_peer_exit, NULL);
tox_callback_group_peer_name(m, on_group_nick_change, NULL);
tox_callback_group_peer_status(m, on_group_status_change, NULL);
tox_callback_group_topic(m, on_group_topic_change, NULL);
tox_callback_group_peer_limit(m, on_group_peer_limit, NULL);
tox_callback_group_privacy_state(m, on_group_privacy_state, NULL);
tox_callback_group_password(m, on_group_password, NULL);
tox_callback_group_self_join(m, on_group_self_join, NULL);
tox_callback_group_join_fail(m, on_group_rejected, NULL);
tox_callback_group_moderation(m, on_group_moderation, NULL);
}
static void init_tox_options(struct Tox_Options *tox_opts)
{
tox_options_default(tox_opts);
tox_options_set_ipv6_enabled(tox_opts, !arg_opts.use_ipv4);
tox_options_set_udp_enabled(tox_opts, !arg_opts.force_tcp);
tox_options_set_proxy_type(tox_opts, arg_opts.proxy_type);
tox_options_set_tcp_port(tox_opts, arg_opts.tcp_port);
tox_opts->ipv6_enabled = !arg_opts.use_ipv4;
tox_opts->udp_enabled = !arg_opts.force_tcp;
tox_opts->proxy_type = arg_opts.proxy_type;
tox_opts->tcp_port = arg_opts.tcp_port;
if (!tox_options_get_ipv6_enabled(tox_opts)) {
if (!tox_opts->ipv6_enabled)
queue_init_message("Forcing IPv4 connection");
}
if (tox_options_get_tcp_port(tox_opts)) {
queue_init_message("TCP relaying enabled on port %d", tox_options_get_tcp_port(tox_opts));
}
if (tox_opts->tcp_port)
queue_init_message("TCP relaying enabled on port %d", tox_opts->tcp_port);
if (tox_options_get_proxy_type(tox_opts) != TOX_PROXY_TYPE_NONE) {
tox_options_set_proxy_port(tox_opts, arg_opts.proxy_port);
tox_options_set_proxy_host(tox_opts, arg_opts.proxy_address);
const char *ps = tox_options_get_proxy_type(tox_opts) == TOX_PROXY_TYPE_SOCKS5 ? "SOCKS5" : "HTTP";
if (tox_opts->proxy_type != TOX_PROXY_TYPE_NONE) {
tox_opts->proxy_port = arg_opts.proxy_port;
tox_opts->proxy_host = arg_opts.proxy_address;
const char *ps = tox_opts->proxy_type == TOX_PROXY_TYPE_SOCKS5 ? "SOCKS5" : "HTTP";
char tmp[sizeof(arg_opts.proxy_address) + MAX_STR_SIZE];
char tmp[48];
snprintf(tmp, sizeof(tmp), "Using %s proxy %s : %d", ps, arg_opts.proxy_address, arg_opts.proxy_port);
queue_init_message("%s", tmp);
}
if (!tox_options_get_udp_enabled(tox_opts)) {
if (!tox_opts->udp_enabled) {
queue_init_message("UDP disabled");
} else if (tox_options_get_proxy_type(tox_opts) != TOX_PROXY_TYPE_NONE) {
} else if (tox_opts->proxy_type != TOX_PROXY_TYPE_NONE) {
const char *msg = "WARNING: Using a proxy without disabling UDP may leak your real IP address.";
queue_init_message("%s", msg);
msg = "Use the -t option to disable UDP.";
@ -646,7 +599,7 @@ static void init_tox_options(struct Tox_Options *tox_opts)
/* Returns a new Tox object on success.
* If object fails to initialize the toxic process will terminate.
*/
static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New *new_err)
static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW *new_err)
{
Tox *m = NULL;
@ -675,16 +628,14 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New
exit_toxic_err("failed in load_tox", FATALERR_ENCRYPT);
}
if (arg_opts.unencrypt_data && is_encrypted) {
if (arg_opts.unencrypt_data && is_encrypted)
queue_init_message("Data file '%s' has been unencrypted", data_path);
} else if (arg_opts.unencrypt_data) {
else if (arg_opts.unencrypt_data)
queue_init_message("Warning: passed --unencrypt-data option with unencrypted data file '%s'", data_path);
}
if (is_encrypted) {
if (!arg_opts.unencrypt_data) {
if (!arg_opts.unencrypt_data)
user_password.data_is_encrypted = true;
}
size_t pwlen = 0;
int pweval = user_settings->password_eval[0];
@ -698,8 +649,6 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New
char plain[plain_len];
while (true) {
fflush(stdout); // Flush before prompts so the user sees the question/message
if (pweval) {
pwlen = password_eval(user_password.pass, sizeof(user_password.pass));
} else {
@ -726,8 +675,9 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New
(uint8_t *) plain, &pwerr);
if (pwerr == TOX_ERR_DECRYPTION_OK) {
tox_options_set_savedata_type(tox_opts, TOX_SAVEDATA_TYPE_TOX_SAVE);
tox_options_set_savedata_data(tox_opts, (uint8_t *) plain, plain_len);
tox_opts->savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE;
tox_opts->savedata_data = (uint8_t *) plain;
tox_opts->savedata_length = plain_len;
m = tox_new(tox_opts, new_err);
@ -748,8 +698,9 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New
}
}
} else { /* data is not encrypted */
tox_options_set_savedata_type(tox_opts, TOX_SAVEDATA_TYPE_TOX_SAVE);
tox_options_set_savedata_data(tox_opts, (uint8_t *) data, len);
tox_opts->savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE;
tox_opts->savedata_data = (uint8_t *) data;
tox_opts->savedata_length = len;
m = tox_new(tox_opts, new_err);
@ -761,21 +712,18 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New
fclose(fp);
} else { /* Data file does not/should not exist */
if (file_exists(data_path)) {
if (file_exists(data_path))
exit_toxic_err("failed in load_tox", FATALERR_FILEOP);
}
tox_options_set_savedata_type(tox_opts, TOX_SAVEDATA_TYPE_NONE);
tox_opts->savedata_type = TOX_SAVEDATA_TYPE_NONE;
m = tox_new(tox_opts, new_err);
if (m == NULL) {
if (m == NULL)
return NULL;
}
if (store_data(m, data_path) == -1) {
if (store_data(m, data_path) == -1)
exit_toxic_err("failed in load_tox", FATALERR_FILEOP);
}
}
return m;
@ -783,41 +731,31 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New
static Tox *load_toxic(char *data_path)
{
Tox_Err_Options_New options_new_err;
struct Tox_Options *tox_opts = tox_options_new(&options_new_err);
struct Tox_Options tox_opts;
init_tox_options(&tox_opts);
if (!tox_opts) {
exit_toxic_err("tox_options_new returned fatal error", options_new_err);
}
TOX_ERR_NEW new_err;
Tox *m = load_tox(data_path, &tox_opts, &new_err);
init_tox_options(tox_opts);
Tox_Err_New new_err;
Tox *m = load_tox(data_path, tox_opts, &new_err);
if (new_err == TOX_ERR_NEW_PORT_ALLOC && tox_options_get_ipv6_enabled(tox_opts)) {
if (new_err == TOX_ERR_NEW_PORT_ALLOC && tox_opts.ipv6_enabled) {
queue_init_message("Falling back to ipv4");
tox_options_set_ipv6_enabled(tox_opts, false);
m = load_tox(data_path, tox_opts, &new_err);
tox_opts.ipv6_enabled = false;
m = load_tox(data_path, &tox_opts, &new_err);
}
if (!m) {
if (!m)
exit_toxic_err("tox_new returned fatal error", new_err);
}
if (new_err != TOX_ERR_NEW_OK) {
if (new_err != TOX_ERR_NEW_OK)
queue_init_message("tox_new returned non-fatal error %d", new_err);
}
init_tox_callbacks(m);
load_friendlist(m);
load_blocklist(BLOCK_FILE);
if (tox_self_get_name_size(m) == 0) {
if (tox_self_get_name_size(m) == 0)
tox_self_set_name(m, (uint8_t *) "Toxic User", strlen("Toxic User"), NULL);
}
tox_options_free(tox_opts);
return m;
}
@ -830,7 +768,7 @@ static void do_toxic(Tox *m)
return;
}
tox_iterate(m, NULL);
tox_iterate(m);
do_tox_connection(m);
pthread_mutex_unlock(&Winthread.lock);
}
@ -876,9 +814,8 @@ void *thread_cqueue(void *data)
ToxWindow *toxwin = get_window_ptr(i);
if (toxwin != NULL && toxwin->is_chat
&& get_friend_connection_status(toxwin->num) != TOX_CONNECTION_NONE) {
&& tox_friend_get_connection_status(m, toxwin->num, NULL) != TOX_CONNECTION_NONE)
cqueue_try_send(toxwin, m);
}
}
pthread_mutex_unlock(&Winthread.lock);
@ -900,7 +837,7 @@ void *thread_av(void *data)
usleep(toxav_iteration_interval(av) * 1000);
}
}
#endif /* AUDIO */
#endif /* AUDIO */
static void print_usage(void)
{
@ -920,13 +857,6 @@ static void print_usage(void)
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");
fprintf(stderr, " -v, --version Print the version\n");
}
static void print_version(void)
{
fprintf(stderr, "Toxic version %s\n", TOXICVER);
fprintf(stderr, "Toxcore version %d.%d.%d\n", tox_version_major(), tox_version_minor(), tox_version_patch());
}
static void set_default_opts(void)
@ -957,11 +887,10 @@ static void parse_args(int argc, char *argv[])
{"SOCKS5-proxy", required_argument, 0, 'p'},
{"HTTP-proxy", required_argument, 0, 'P'},
{"unencrypt-data", no_argument, 0, 'u'},
{"version", no_argument, 0, 'v'},
{NULL, no_argument, NULL, 0},
};
const char *opts_str = "4bdehotuxvc:f:n:r:p:P:T:";
const char *opts_str = "4bdehotuxc:f:n:r:p:P:T:";
int opt, indexptr;
long int port = 0;
@ -979,9 +908,8 @@ static void parse_args(int argc, char *argv[])
case 'c':
snprintf(arg_opts.config_path, sizeof(arg_opts.config_path), "%s", optarg);
if (!file_exists(arg_opts.config_path)) {
if (!file_exists(arg_opts.config_path))
queue_init_message("Config file not found");
}
break;
@ -997,26 +925,22 @@ static void parse_args(int argc, char *argv[])
case 'f':
arg_opts.use_custom_data = 1;
if (DATA_FILE) {
if (DATA_FILE)
free(DATA_FILE);
}
if (BLOCK_FILE) {
if (BLOCK_FILE)
free(BLOCK_FILE);
}
DATA_FILE = malloc(strlen(optarg) + 1);
strcpy(DATA_FILE, optarg);
if (DATA_FILE == NULL) {
if (DATA_FILE == NULL)
exit_toxic_err("failed in parse_args", FATALERR_MEMORY);
}
BLOCK_FILE = malloc(strlen(optarg) + strlen("-blocklist") + 1);
if (BLOCK_FILE == NULL) {
if (BLOCK_FILE == NULL)
exit_toxic_err("failed in parse_args", FATALERR_MEMORY);
}
strcpy(BLOCK_FILE, optarg);
strcat(BLOCK_FILE, "-blocklist");
@ -1038,15 +962,13 @@ static void parse_args(int argc, char *argv[])
arg_opts.proxy_type = TOX_PROXY_TYPE_SOCKS5;
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
if (++optind > argc || argv[optind - 1][0] == '-') {
if (++optind > argc || argv[optind - 1][0] == '-')
exit_toxic_err("Proxy error", FATALERR_PROXY);
}
port = strtol(argv[optind - 1], NULL, 10);
if (port <= 0 || port > MAX_PORT_RANGE) {
if (port <= 0 || port > MAX_PORT_RANGE)
exit_toxic_err("Proxy error", FATALERR_PROXY);
}
arg_opts.proxy_port = port;
break;
@ -1055,15 +977,13 @@ static void parse_args(int argc, char *argv[])
arg_opts.proxy_type = TOX_PROXY_TYPE_HTTP;
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
if (++optind > argc || argv[optind - 1][0] == '-') {
if (++optind > argc || argv[optind - 1][0] == '-')
exit_toxic_err("Proxy error", FATALERR_PROXY);
}
port = strtol(argv[optind - 1], NULL, 10);
if (port <= 0 || port > MAX_PORT_RANGE) {
if (port <= 0 || port > MAX_PORT_RANGE)
exit_toxic_err("Proxy error", FATALERR_PROXY);
}
arg_opts.proxy_port = port;
break;
@ -1071,9 +991,8 @@ static void parse_args(int argc, char *argv[])
case 'r':
snprintf(arg_opts.nameserver_path, sizeof(arg_opts.nameserver_path), "%s", optarg);
if (!file_exists(arg_opts.nameserver_path)) {
if (!file_exists(arg_opts.nameserver_path))
queue_init_message("nameserver list not found");
}
break;
@ -1084,9 +1003,8 @@ static void parse_args(int argc, char *argv[])
case 'T':
port = strtol(optarg, NULL, 10);
if (port <= 0 || port > MAX_PORT_RANGE) {
if (port <= 0 || port > MAX_PORT_RANGE)
port = 14191;
}
arg_opts.tcp_port = port;
break;
@ -1095,10 +1013,6 @@ static void parse_args(int argc, char *argv[])
arg_opts.unencrypt_data = 1;
break;
case 'v':
print_version();
exit(EXIT_SUCCESS);
case 'h':
default:
print_usage();
@ -1119,34 +1033,28 @@ static int rename_old_profile(const char *user_config_dir)
char old_data_file[strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(OLD_DATA_NAME) + 1];
snprintf(old_data_file, sizeof(old_data_file), "%s%s%s", user_config_dir, CONFIGDIR, OLD_DATA_NAME);
if (!file_exists(old_data_file)) {
if (!file_exists(old_data_file))
return 0;
}
if (file_exists(DATA_FILE)) {
if (file_exists(DATA_FILE))
return 0;
}
if (rename(old_data_file, DATA_FILE) != 0) {
if (rename(old_data_file, DATA_FILE) != 0)
return -1;
}
queue_init_message("Data file has been moved to %s", DATA_FILE);
char old_data_blocklist[strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(OLD_DATA_BLOCKLIST_NAME) + 1];
snprintf(old_data_blocklist, sizeof(old_data_blocklist), "%s%s%s", user_config_dir, CONFIGDIR, OLD_DATA_BLOCKLIST_NAME);
if (!file_exists(old_data_blocklist)) {
if (!file_exists(old_data_blocklist))
return 0;
}
if (file_exists(BLOCK_FILE)) {
if (file_exists(BLOCK_FILE))
return 0;
}
if (rename(old_data_blocklist, BLOCK_FILE) != 0) {
if (rename(old_data_blocklist, BLOCK_FILE) != 0)
return -1;
}
return 0;
}
@ -1157,15 +1065,13 @@ static int rename_old_profile(const char *user_config_dir)
*/
static void init_default_data_files(void)
{
if (arg_opts.use_custom_data) {
if (arg_opts.use_custom_data)
return;
}
char *user_config_dir = get_user_config_dir();
if (user_config_dir == NULL) {
if (user_config_dir == NULL)
exit_toxic_err("failed in init_default_data_files()", FATALERR_FILEOP);
}
int config_err = create_user_config_dirs(user_config_dir);
@ -1173,16 +1079,14 @@ static void init_default_data_files(void)
DATA_FILE = strdup(DATANAME);
BLOCK_FILE = strdup(BLOCKNAME);
if (DATA_FILE == NULL || BLOCK_FILE == NULL) {
if (DATA_FILE == NULL || BLOCK_FILE == NULL)
exit_toxic_err("failed in init_default_data_files()", FATALERR_MEMORY);
}
} else {
DATA_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(DATANAME) + 1);
BLOCK_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(BLOCKNAME) + 1);
if (DATA_FILE == NULL || BLOCK_FILE == NULL) {
if (DATA_FILE == NULL || BLOCK_FILE == NULL)
exit_toxic_err("failed in init_default_data_files()", FATALERR_MEMORY);
}
strcpy(DATA_FILE, user_config_dir);
strcat(DATA_FILE, CONFIGDIR);
@ -1194,9 +1098,8 @@ static void init_default_data_files(void)
}
/* For backwards compatibility with old toxic profile names. TODO: remove this some day */
if (rename_old_profile(user_config_dir) == -1) {
if (rename_old_profile(user_config_dir) == -1)
queue_init_message("Warning: Profile backwards compatibility failed.");
}
free(user_config_dir);
}
@ -1219,9 +1122,8 @@ int main(int argc, char **argv)
parse_args(argc, argv);
/* Use the -b flag to enable stderr */
if (!arg_opts.debug) {
if (!arg_opts.debug)
freopen("/dev/null", "w", stderr);
}
if (arg_opts.encrypt_data && arg_opts.unencrypt_data) {
arg_opts.encrypt_data = 0;
@ -1236,19 +1138,17 @@ int main(int argc, char **argv)
bool datafile_exists = file_exists(DATA_FILE);
if (!datafile_exists && !arg_opts.unencrypt_data) {
if (!datafile_exists && !arg_opts.unencrypt_data)
first_time_encrypt("Creating new data file. Would you like to encrypt it? Y/n (q to quit)");
} else if (arg_opts.encrypt_data) {
else if (arg_opts.encrypt_data)
first_time_encrypt("Encrypt existing data file? Y/n (q to quit)");
}
/* init user_settings struct and load settings from conf file */
user_settings = calloc(1, sizeof(struct user_settings));
if (user_settings == NULL) {
if (user_settings == NULL)
exit_toxic_err("failed in main", FATALERR_MEMORY);
}
const char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL;
@ -1269,37 +1169,32 @@ int main(int argc, char **argv)
#ifdef X11
if (init_xtra(DnD_callback) == -1) {
if (init_xtra(DnD_callback) == -1)
queue_init_message("X failed to initialize");
}
#endif /* X11 */
#endif
Tox *m = load_toxic(DATA_FILE);
if (arg_opts.encrypt_data && !datafile_exists) {
if (arg_opts.encrypt_data && !datafile_exists)
arg_opts.encrypt_data = 0;
}
init_term();
prompt = init_windows(m);
prompt_init_statusbar(prompt, m, !datafile_exists);
load_groups(prompt, m);
prompt_init_statusbar(prompt, m);
/* thread for ncurses stuff */
if (pthread_mutex_init(&Winthread.lock, NULL) != 0) {
if (pthread_mutex_init(&Winthread.lock, NULL) != 0)
exit_toxic_err("failed in main", FATALERR_MUTEX_INIT);
}
if (pthread_create(&Winthread.tid, NULL, thread_winref, (void *) m) != 0) {
if (pthread_create(&Winthread.tid, NULL, thread_winref, (void *) m) != 0)
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
}
/* thread for message queue */
if (pthread_create(&cqueue_thread.tid, NULL, thread_cqueue, (void *) m) != 0) {
if (pthread_create(&cqueue_thread.tid, NULL, thread_cqueue, (void *) m) != 0)
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
}
#ifdef AUDIO
@ -1311,34 +1206,24 @@ int main(int argc, char **argv)
#endif /* VIDEO */
/* AV thread */
if (pthread_create(&av_thread.tid, NULL, thread_av, (void *) av) != 0) {
if (pthread_create(&av_thread.tid, NULL, thread_av, (void *) av) != 0)
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
}
set_primary_device(input, user_settings->audio_in_dev);
set_primary_device(output, user_settings->audio_out_dev);
#elif SOUND_NOTIFY
if (init_devices() == de_InternalError) {
if ( init_devices() == de_InternalError )
queue_init_message("Failed to init audio devices");
}
#endif /* AUDIO */
#ifdef PYTHON
init_python(m);
invoke_autoruns(prompt->chatwin->history, prompt);
#endif /* PYTHON */
init_notify(60, 3000);
/* screen/tmux auto-away timer */
if (init_mplex_away_timer(m) == -1) {
if (init_mplex_away_timer(m) == -1)
queue_init_message("Failed to init mplex auto-away.");
}
int nodeslist_ret = load_DHT_nodeslist();
@ -1347,14 +1232,15 @@ int main(int argc, char **argv)
}
pthread_mutex_lock(&Winthread.lock);
load_groups(m);
print_init_messages(prompt);
pthread_mutex_unlock(&Winthread.lock);
cleanup_init_messages();
/* set user avatar from config file. if no path is supplied tox_unset_avatar is called */
char avatarstr[PATH_MAX + 11];
snprintf(avatarstr, sizeof(avatarstr), "/avatar %s", user_settings->avatar_path);
char avatarstr[MAX_STR_SIZE];
snprintf(avatarstr, sizeof(avatarstr), "/avatar \"%s\"", user_settings->avatar_path);
execute(prompt->chatwin->history, prompt, m, avatarstr, GLOBAL_COMMAND_MODE);
time_t last_save = get_unix_time();
@ -1367,9 +1253,8 @@ int main(int argc, char **argv)
if (timed_out(last_save, AUTOSAVE_FREQ)) {
pthread_mutex_lock(&Winthread.lock);
if (store_data(m, DATA_FILE) != 0) {
if (store_data(m, DATA_FILE) != 0)
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, "WARNING: Failed to save to data file");
}
pthread_mutex_unlock(&Winthread.lock);

View File

@ -96,8 +96,8 @@ typedef enum _FATAL_ERRS {
Uncomment if necessary */
/* #define URXVT_FIX */
void lock_status(void);
void unlock_status(void);
void lock_status ();
void unlock_status ();
void exit_toxic_success(Tox *m);
void exit_toxic_err(const char *errmsg, int errcode);
@ -105,32 +105,49 @@ void exit_toxic_err(const char *errmsg, int errcode);
int store_data(Tox *m, const char *path);
/* callbacks */
void on_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata);
void on_friend_connection_status(Tox *m, uint32_t friendnumber, Tox_Connection status, void *userdata);
void on_friend_message(Tox *m, uint32_t friendnumber, Tox_Message_Type type, const uint8_t *string, size_t length,
void *userdata);
void on_friend_name(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
void on_friend_status(Tox *m, uint32_t friendnumber, Tox_User_Status status, void *userdata);
void on_friend_status_message(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
void on_friend_added(Tox *m, uint32_t friendnumber, bool sort);
void on_conference_message(Tox *m, uint32_t groupnumber, uint32_t peernumber, Tox_Message_Type type,
const uint8_t *message, size_t length, void *userdata);
void on_conference_invite(Tox *m, uint32_t friendnumber, Tox_Conference_Type type, const uint8_t *group_pub_key,
size_t length, void *userdata);
void on_conference_peer_list_changed(Tox *m, uint32_t groupnumber, void *userdata);
void on_conference_peer_name(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *name,
size_t length, void *userdata);
void on_conference_title(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *title, size_t length,
void *userdata);
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata);
void on_connectionchange(Tox *m, uint32_t friendnumber, TOX_CONNECTION status, void *userdata);
void on_message(Tox *m, uint32_t friendnumber, TOX_MESSAGE_TYPE type, const uint8_t *string, size_t length,
void *userdata);
void on_action(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
void on_nickchange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
void on_statuschange(Tox *m, uint32_t friendnumber, TOX_USER_STATUS status, void *userdata);
void on_statusmessagechange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
void on_friendadded(Tox *m, uint32_t friendnumber, bool sort);
void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length,
void *userdata);
void on_groupinvite(Tox *m, int32_t friendnumber, uint8_t type, const uint8_t *group_pub_key, uint16_t length,
void *userdata);
void on_group_titlechange(Tox *m, int groupnumber, int peernumber, const uint8_t *title, uint8_t length,
void *userdata);
void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length,
void *userdata);
void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data,
size_t length, void *userdata);
void on_file_recv_control(Tox *m, uint32_t friendnumber, uint32_t filenumber, Tox_File_Control control,
void *userdata);
void on_file_control (Tox *m, uint32_t friendnumber, uint32_t filenumber, TOX_FILE_CONTROL control, void *userdata);
void on_file_recv(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint32_t kind, uint64_t file_size,
const uint8_t *filename, size_t filename_length, void *userdata);
void on_friend_typing(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata);
void on_friend_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata);
void on_typing_change(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata);
void on_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata);
void on_group_invite(Tox *m, uint32_t friendnumber, const uint8_t *invite_data, size_t length, void *userdata);
void on_group_message(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_MESSAGE_TYPE type,
const uint8_t *message, size_t length, void *userdata);
void on_group_private_message(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *message, size_t length,
void *userdata);
void on_group_peer_join(Tox *m, uint32_t groupnumber, uint32_t peernumber, void *userdata);
void on_group_peer_exit(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *partmsg, size_t length,
void *userdata);
void on_group_topic_change(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *topic, size_t length,
void *userdata);
void on_group_peer_limit(Tox *m, uint32_t groupnumber, uint32_t peer_limit, void *userdata);
void on_group_privacy_state(Tox *m, uint32_t groupnumber, TOX_GROUP_PRIVACY_STATE privacy_state, void *userdata);
void on_group_password(Tox *m, uint32_t groupnumber, const uint8_t *password, size_t length, void *userdata);
void on_group_nick_change(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *newname, size_t length,
void *userdata);
void on_group_status_change(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_USER_STATUS status, void *userdata);
void on_group_self_join(Tox *m, uint32_t groupnumber, void *userdata);
void on_group_rejected(Tox *m, uint32_t groupnumber, TOX_GROUP_JOIN_FAIL type, void *userdata);
void on_group_moderation(Tox *m, uint32_t groupnumber, uint32_t source_peernum, uint32_t target_peernum,
TOX_GROUP_MOD_EVENT type, void *userdata);
#endif /* TOXIC_H */
#endif /* #define TOXIC_H */

View File

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

View File

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

View File

@ -37,19 +37,18 @@
#include <stdlib.h>
#include <assert.h>
#ifdef VIDEO
#define default_video_bit_rate 5000
void on_video_receive_frame(ToxAV *av, uint32_t friend_number,
uint16_t width, uint16_t height,
uint8_t const *y, uint8_t const *u, uint8_t const *v,
int32_t ystride, int32_t ustride, int32_t vstride,
void *user_data);
void receive_video_frame_cb( ToxAV *av, uint32_t friend_number,
uint16_t width, uint16_t height,
uint8_t const *y, uint8_t const *u, uint8_t const *v,
int32_t ystride, int32_t ustride, int32_t vstride,
void *user_data );
void on_video_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t video_bit_rate, void *user_data);
void video_bit_rate_status_cb( ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate,
uint32_t video_bit_rate, void *user_data);
static void print_err(ToxWindow *self, const char *error_str)
static void print_err (ToxWindow *self, const char *error_str)
{
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", error_str);
}
@ -62,36 +61,35 @@ ToxAV *init_video(ToxWindow *self, Tox *tox)
CallControl.video_bit_rate = 0;
CallControl.video_frame_duration = 10;
if (!CallControl.av) {
if ( !CallControl.av ) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Video failed to init with ToxAV instance");
return NULL;
}
if (init_video_devices(CallControl.av) == vde_InternalError) {
if ( init_video_devices(CallControl.av) == vde_InternalError ) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init video devices");
return NULL;
}
toxav_callback_video_receive_frame(CallControl.av, on_video_receive_frame, &CallControl);
toxav_callback_video_bit_rate(CallControl.av, on_video_bit_rate, &CallControl);
toxav_callback_video_receive_frame(CallControl.av, receive_video_frame_cb, &CallControl);
toxav_callback_bit_rate_status(CallControl.av, video_bit_rate_status_cb, &CallControl);
return CallControl.av;
}
void terminate_video(void)
void terminate_video()
{
int i;
for (i = 0; i < CallControl.max_calls; ++i) {
for (i = 0; i < MAX_CALLS; ++i) {
Call *this_call = &CallControl.calls[i];
stop_video_transmission(this_call, i);
if (this_call->vout_idx != -1) {
if ( this_call->vout_idx != -1 )
close_video_device(vdt_output, this_call->vout_idx);
}
}
terminate_video_devices();
@ -102,22 +100,21 @@ void read_video_device_callback(int16_t width, int16_t height, const uint8_t *y,
{
uint32_t friend_number = *((uint32_t *)data); /* TODO: Or pass an array of call_idx's */
Call *this_call = &CallControl.calls[friend_number];
Toxav_Err_Send_Frame error;
TOXAV_ERR_SEND_FRAME error;
/* Drop frame if video sending is disabled */
if (CallControl.video_bit_rate == 0 || this_call->vin_idx == -1) {
if ( CallControl.video_bit_rate == 0 || this_call->vin_idx == -1 ) {
line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Video frame dropped.");
return;
}
if (toxav_video_send_frame(CallControl.av, friend_number, width, height, y, u, v, &error) == false) {
if ( toxav_video_send_frame(CallControl.av, friend_number, width, height, y, u, v, &error ) == false ) {
line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to send video frame");
if (error == TOXAV_ERR_SEND_FRAME_NULL) {
if ( error == TOXAV_ERR_SEND_FRAME_NULL )
line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to capture video frame");
} else if (error == TOXAV_ERR_SEND_FRAME_INVALID) {
else if ( error == TOXAV_ERR_SEND_FRAME_INVALID )
line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to prepare video frame");
}
}
}
@ -131,24 +128,24 @@ void write_video_device_callback(uint32_t friend_number, uint16_t width, uint16_
int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call)
{
if (!self || !av) {
if ( !self || !av) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to prepare transmission");
return -1;
}
CallControl.video_bit_rate = default_video_bit_rate;
if (toxav_video_set_bit_rate(CallControl.av, self->num, CallControl.video_bit_rate, NULL) == false) {
if ( toxav_bit_rate_set(CallControl.av, self->num, -1, CallControl.video_bit_rate, NULL) == false ) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set video bit rate");
return -1;
}
if (open_primary_video_device(vdt_input, &call->vin_idx) != vde_None) {
if ( open_primary_video_device(vdt_input, &call->vin_idx) != vde_None ) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open input video device!");
return -1;
}
if (register_video_device_callback(self->num, call->vin_idx, read_video_device_callback, &self->num) != vde_None) {
if ( register_video_device_callback(self->num, call->vin_idx, read_video_device_callback, &self->num) != vde_None ) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to register input video handler!");
return -1;
}
@ -159,9 +156,9 @@ int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call)
int stop_video_transmission(Call *call, int friend_number)
{
CallControl.video_bit_rate = 0;
toxav_video_set_bit_rate(CallControl.av, friend_number, CallControl.video_bit_rate, NULL);
toxav_bit_rate_set(CallControl.av, friend_number, -1, CallControl.video_bit_rate, NULL);
if (call->vin_idx != -1) {
if ( call->vin_idx != -1 ) {
close_video_device(vdt_input, call->vin_idx);
call->vin_idx = -1;
}
@ -179,7 +176,7 @@ int stop_video_transmission(Call *call, int friend_number)
/*
* Callbacks
*/
void on_video_receive_frame(ToxAV *av, uint32_t friend_number,
void receive_video_frame_cb(ToxAV *av, uint32_t friend_number,
uint16_t width, uint16_t height,
uint8_t const *y, uint8_t const *u, uint8_t const *v,
int32_t ystride, int32_t ustride, int32_t vstride,
@ -188,19 +185,19 @@ void on_video_receive_frame(ToxAV *av, uint32_t friend_number,
write_video_device_callback(friend_number, width, height, y, u, v, ystride, ustride, vstride, user_data);
}
void on_video_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t video_bit_rate, void *user_data)
void video_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate,
uint32_t video_bit_rate, void *user_data)
{
CallControl.video_bit_rate = video_bit_rate;
toxav_video_set_bit_rate(CallControl.av, friend_number, CallControl.video_bit_rate, NULL);
toxav_bit_rate_set(CallControl.av, friend_number, -1, CallControl.video_bit_rate, NULL);
}
void callback_recv_video_starting(uint32_t friend_number)
{
Call *this_call = &CallControl.calls[friend_number];
if (this_call->vout_idx != -1) {
if ( this_call->vout_idx != -1 )
return;
}
open_primary_video_device(vdt_output, &this_call->vout_idx);
}
@ -216,15 +213,15 @@ void callback_video_starting(uint32_t friend_number)
ToxWindow *windows = CallControl.prompt;
Call *this_call = &CallControl.calls[friend_number];
Toxav_Err_Call_Control error = TOXAV_ERR_CALL_CONTROL_OK;
TOXAV_ERR_CALL_CONTROL error = TOXAV_ERR_CALL_CONTROL_OK;
toxav_call_control(CallControl.av, friend_number, TOXAV_CALL_CONTROL_SHOW_VIDEO, &error);
if (error == TOXAV_ERR_CALL_CONTROL_OK) {
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].is_call && windows[i].num == friend_number) {
if (0 != start_video_transmission(&windows[i], CallControl.av, this_call)) {
if ( windows[i].is_call && windows[i].num == friend_number ) {
if ( 0 != start_video_transmission(&windows[i], CallControl.av, this_call) ) {
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!");
return;
}
@ -252,60 +249,54 @@ void cmd_video(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[M
const char *error_str;
Call *this_call = &CallControl.calls[self->num];
if (argc != 0) {
if ( argc != 0 ) {
error_str = "Unknown arguments.";
goto on_error;
}
if (!CallControl.av) {
if ( !CallControl.av ) {
error_str = "ToxAV not supported!";
goto on_error;
}
if (!self->stb->connection) {
if ( !self->stb->connection ) {
error_str = "Friend is offline.";
goto on_error;
}
if (!self->is_call) {
if ( !self->is_call ) {
error_str = "Not in call!";
goto on_error;
}
if (this_call->vin_idx == -1) {
if ( this_call->vin_idx == -1 )
callback_video_starting(self->num);
} else {
else
callback_video_end(self->num);
}
return;
on_error:
print_err(self, error_str);
print_err (self, error_str);
}
void cmd_list_video_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
const char *error_str;
if (argc != 1) {
if (argc < 1) {
error_str = "Type must be specified!";
} else {
error_str = "Only one argument allowed!";
}
if ( argc != 1 ) {
if ( argc < 1 ) error_str = "Type must be specified!";
else error_str = "Only one argument allowed!";
goto on_error;
}
VideoDeviceType type;
if (strcasecmp(argv[1], "in") == 0) { /* Input devices */
if ( strcasecmp(argv[1], "in") == 0 ) /* Input devices */
type = vdt_input;
}
else if (strcasecmp(argv[1], "out") == 0) { /* Output devices */
else if ( strcasecmp(argv[1], "out") == 0 ) /* Output devices */
type = vdt_output;
}
else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
@ -316,7 +307,7 @@ void cmd_list_video_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, c
return;
on_error:
print_err(self, error_str);
print_err (self, error_str);
}
/* This changes primary video device only */
@ -324,27 +315,21 @@ void cmd_change_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc,
{
const char *error_str;
if (argc != 2) {
if (argc < 1) {
error_str = "Type must be specified!";
} else if (argc < 2) {
error_str = "Must have id!";
} else {
error_str = "Only two arguments allowed!";
}
if ( argc != 2 ) {
if ( argc < 1 ) error_str = "Type must be specified!";
else if ( argc < 2 ) error_str = "Must have id!";
else error_str = "Only two arguments allowed!";
goto on_error;
}
VideoDeviceType type;
if (strcmp(argv[1], "in") == 0) { /* Input devices */
if ( strcmp(argv[1], "in") == 0 ) /* Input devices */
type = vdt_input;
}
else if (strcmp(argv[1], "out") == 0) { /* Output devices */
else if ( strcmp(argv[1], "out") == 0 ) /* Output devices */
type = vdt_output;
}
else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
@ -355,46 +340,40 @@ void cmd_change_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc,
char *end;
long int selection = strtol(argv[2], &end, 10);
if (*end) {
if ( *end ) {
error_str = "Invalid input";
goto on_error;
}
if (set_primary_video_device(type, selection) == vde_InvalidSelection) {
if ( set_primary_video_device(type, selection) == vde_InvalidSelection ) {
error_str = "Invalid selection!";
goto on_error;
}
return;
on_error:
print_err(self, error_str);
print_err (self, error_str);
}
void cmd_ccur_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
const char *error_str;
if (argc != 2) {
if (argc < 1) {
error_str = "Type must be specified!";
} else if (argc < 2) {
error_str = "Must have id!";
} else {
error_str = "Only two arguments allowed!";
}
if ( argc != 2 ) {
if ( argc < 1 ) error_str = "Type must be specified!";
else if ( argc < 2 ) error_str = "Must have id!";
else error_str = "Only two arguments allowed!";
goto on_error;
}
VideoDeviceType type;
if (strcmp(argv[1], "in") == 0) { /* Input devices */
if ( strcmp(argv[1], "in") == 0 ) /* Input devices */
type = vdt_input;
}
else if (strcmp(argv[1], "out") == 0) { /* Output devices */
else if ( strcmp(argv[1], "out") == 0 ) /* Output devices */
type = vdt_output;
}
else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
@ -405,23 +384,23 @@ void cmd_ccur_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, ch
char *end;
long int selection = strtol(argv[2], &end, 10);
if (*end) {
if ( *end ) {
error_str = "Invalid input";
goto on_error;
}
if (video_selection_valid(type, selection) == vde_InvalidSelection) {
if ( video_selection_valid(type, selection) == vde_InvalidSelection ) {
error_str = "Invalid selection!";
goto on_error;
}
/* If call is active, change device */
if (self->is_call) {
if ( self->is_call ) {
Call *this_call = &CallControl.calls[self->num];
if (this_call->ttas) {
if ( this_call->ttas ) {
if (type == vdt_output) {
if ( type == vdt_output ) {
} else {
/* TODO: check for failure */
close_video_device(vdt_input, this_call->vin_idx);
@ -435,16 +414,13 @@ void cmd_ccur_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, ch
return;
on_error:
print_err(self, error_str);
print_err (self, error_str);
}
void stop_video_stream(ToxWindow *self)
{
Call *this_call = &CallControl.calls[self->num];
if (this_call && this_call->vin_idx != -1) {
if (this_call && this_call->vin_idx != -1)
stop_video_transmission(this_call, self->num);
}
}
#endif /* VIDEO */

View File

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

View File

@ -30,19 +30,15 @@
#include <vpx/vpx_image.h>
#if defined(__OSX__)
#import "osx_video.h"
#else
#if defined(__linux__) || defined(__FreeBSD__)
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#if defined(__OpenBSD__) || defined(__NetBSD__)
#include <sys/videoio.h>
#else
#include <linux/videodev2.h>
#endif /* defined(__OpenBSD__) || defined(__NetBSD__) */
#endif /* __OSX__ */
#else /* __OSX__ */
#import "osx_video.h"
#endif
#include "line_info.h"
#include "settings.h"
@ -55,8 +51,6 @@
#include <unistd.h>
#include <stdlib.h>
#ifdef VIDEO
#define inline__ inline __attribute__((always_inline))
extern struct user_settings *user_settings;
@ -71,7 +65,7 @@ typedef struct VideoDevice {
void *cb_data; /* Data to be passed to callback */
int32_t friend_number; /* ToxAV friend number */
#if !defined(__OSX__)
#if defined(__linux__) || defined(__FreeBSD__)
int fd; /* File descriptor of video device selected/opened */
struct v4l2_format fmt;
struct VideoBuffer *buffers;
@ -98,7 +92,9 @@ static int size[2]; /* Size of above containers */
VideoDevice *video_devices_running[2][MAX_DEVICES] = {{NULL}}; /* Running devices */
uint32_t primary_video_device[2]; /* Primary device */
#ifdef VIDEO
static ToxAV *av = NULL;
#endif /* VIDEO */
/* q_mutex */
#define lock pthread_mutex_lock(&video_mutex);
@ -136,7 +132,7 @@ static void yuv420tobgr(uint16_t width, uint16_t height, const uint8_t *y,
}
}
#if !defined(__OSX__)
#if defined(__linux__) || defined(__FreeBSD__)
static void yuv422to420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v,
uint8_t *input, uint16_t width, uint16_t height)
{
@ -174,7 +170,7 @@ static int xioctl(int fh, unsigned long request, void *arg)
return r;
}
#endif
#endif /* __linux__ */
/* Meet devices */
#ifdef VIDEO
@ -185,13 +181,7 @@ VideoDeviceError init_video_devices()
{
size[vdt_input] = 0;
#if defined(__OSX__)
if (osx_video_init((char **)video_devices_names[vdt_input], &size[vdt_input]) != 0) {
return vde_InternalError;
}
#else /* not __OSX__*/
#if defined(__linux__) || defined(__FreeBSD__)
for (; size[vdt_input] <= MAX_DEVICES; ++size[vdt_input]) {
int fd;
@ -200,14 +190,14 @@ VideoDeviceError init_video_devices()
fd = open(device_address, O_RDWR | O_NONBLOCK, 0);
if (fd == -1) {
if ( fd == -1 ) {
break;
} else {
struct v4l2_capability cap;
char *video_input_name;
/* Query V4L for capture capabilities */
if (-1 != ioctl(fd, VIDIOC_QUERYCAP, &cap)) {
if ( -1 != ioctl(fd, VIDIOC_QUERYCAP, &cap) ) {
video_input_name = (char *)malloc(strlen((const char *)cap.card) + strlen(device_address) + 4);
strcpy(video_input_name, (char *)cap.card);
strcat(video_input_name, " (");
@ -226,6 +216,11 @@ VideoDeviceError init_video_devices()
}
}
#else /* __OSX__ */
if ( osx_video_init((char **)video_devices_names[vdt_input], &size[vdt_input]) != 0 )
return vde_InternalError;
#endif
size[vdt_output] = 1;
@ -233,15 +228,13 @@ VideoDeviceError init_video_devices()
video_devices_names[vdt_output][0] = video_output_name;
// Start poll thread
if (pthread_mutex_init(&video_mutex, NULL) != 0) {
if ( pthread_mutex_init(&video_mutex, NULL) != 0 )
return vde_InternalError;
}
pthread_t thread_id;
if (pthread_create(&thread_id, NULL, video_thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0) {
if ( pthread_create(&thread_id, NULL, video_thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0 )
return vde_InternalError;
}
#ifdef VIDEO
av = av_;
@ -250,7 +243,7 @@ VideoDeviceError init_video_devices()
return (VideoDeviceError) vde_None;
}
VideoDeviceError terminate_video_devices(void)
VideoDeviceError terminate_video_devices()
{
/* Cleanup if needed */
lock;
@ -265,9 +258,8 @@ VideoDeviceError terminate_video_devices(void)
free((void *)video_devices_names[vdt_input][i]);
}
if (pthread_mutex_destroy(&video_mutex) != 0) {
if ( pthread_mutex_destroy(&video_mutex) != 0 )
return (VideoDeviceError) vde_InternalError;
}
#ifdef __OSX__
osx_video_release();
@ -279,18 +271,16 @@ VideoDeviceError terminate_video_devices(void)
VideoDeviceError register_video_device_callback(int32_t friend_number, uint32_t device_idx,
VideoDataHandleCallback callback, void *data)
{
#if defined(__OSX__)
#if defined(__linux__) || defined(__FreeBSD__)
if (size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx]) {
if ( size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx]
|| !video_devices_running[vdt_input][device_idx]->fd )
return vde_InvalidSelection;
}
#else /* not __OSX__ */
#else /* __OSX__ */
if (size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx]
|| !video_devices_running[vdt_input][device_idx]->fd) {
if ( size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx] )
return vde_InvalidSelection;
}
#endif
@ -305,9 +295,7 @@ VideoDeviceError register_video_device_callback(int32_t friend_number, uint32_t
VideoDeviceError set_primary_video_device(VideoDeviceType type, int32_t selection)
{
if (size[type] <= selection || selection < 0) {
return vde_InvalidSelection;
}
if ( size[type] <= selection || selection < 0 ) return vde_InvalidSelection;
primary_video_device[type] = selection;
@ -326,16 +314,14 @@ void get_primary_video_device_name(VideoDeviceType type, char *buf, int size)
VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint32_t *device_idx)
{
if (size[type] <= selection || selection < 0) {
return vde_InvalidSelection;
}
if ( size[type] <= selection || selection < 0 ) return vde_InvalidSelection;
lock;
uint32_t i, temp_idx = -1;
for (i = 0; i < MAX_DEVICES; ++i) {
if (!video_devices_running[type][i]) {
if ( !video_devices_running[type][i] ) {
temp_idx = i;
break;
}
@ -347,7 +333,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
}
for (i = 0; i < MAX_DEVICES; i ++) { /* Check if any device has the same selection */
if (video_devices_running[type][i] && video_devices_running[type][i]->selection == selection) {
if ( video_devices_running[type][i] && video_devices_running[type][i]->selection == selection ) {
video_devices_running[type][temp_idx] = video_devices_running[type][i];
video_devices_running[type][i]->ref_count++;
@ -360,31 +346,23 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
VideoDevice *device = video_devices_running[type][temp_idx] = calloc(1, sizeof(VideoDevice));
device->selection = selection;
if (pthread_mutex_init(device->mutex, NULL) != 0) {
if ( pthread_mutex_init(device->mutex, NULL) != 0 ) {
free(device);
unlock;
return vde_InternalError;
}
if (type == vdt_input) {
if ( type == vdt_input ) {
video_thread_paused = true;
#if defined(__OSX__)
if (osx_video_open_device(selection, &device->video_width, &device->video_height) != 0) {
free(device);
unlock;
return vde_FailedStart;
}
#else /* not __OSX__*/
#if defined(__linux__) || defined(__FreeBSD__)
/* Open selected device */
char device_address[] = "/dev/videoXX";
snprintf(device_address + 10, sizeof(device_address) - 10, "%i", selection);
snprintf(device_address + 10 , sizeof(device_address) - 10, "%i", selection);
device->fd = open(device_address, O_RDWR);
if (device->fd == -1) {
if ( device->fd == -1 ) {
unlock;
return vde_FailedStart;
}
@ -392,7 +370,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
/* Obtain video device capabilities */
struct v4l2_capability cap;
if (-1 == xioctl(device->fd, VIDIOC_QUERYCAP, &cap)) {
if ( -1 == xioctl(device->fd, VIDIOC_QUERYCAP, &cap) ) {
close(device->fd);
free(device);
unlock;
@ -406,7 +384,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
if (-1 == xioctl(device->fd, VIDIOC_S_FMT, &fmt)) {
if ( -1 == xioctl(device->fd, VIDIOC_S_FMT, &fmt) ) {
close(device->fd);
free(device);
unlock;
@ -423,14 +401,14 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if (-1 == xioctl(device->fd, VIDIOC_REQBUFS, &req)) {
if ( -1 == xioctl(device->fd, VIDIOC_REQBUFS, &req) ) {
close(device->fd);
free(device);
unlock;
return vde_FailedStart;
}
if (req.count < 2) {
if ( req.count < 2 ) {
close(device->fd);
free(device);
unlock;
@ -447,7 +425,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if (-1 == xioctl(device->fd, VIDIOC_QUERYBUF, &buf)) {
if ( -1 == xioctl(device->fd, VIDIOC_QUERYBUF, &buf) ) {
close(device->fd);
free(device);
unlock;
@ -461,10 +439,9 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
MAP_SHARED /* recommended */,
device->fd, buf.m.offset);
if (MAP_FAILED == device->buffers[i].start) {
for (i = 0; i < buf.index; ++i) {
if ( MAP_FAILED == device->buffers[i].start ) {
for (i = 0; i < buf.index; ++i)
munmap(device->buffers[i].start, device->buffers[i].length);
}
close(device->fd);
free(device);
@ -485,10 +462,9 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if (-1 == xioctl(device->fd, VIDIOC_QBUF, &buf)) {
for (i = 0; i < device->n_buffers; ++i) {
if ( -1 == xioctl(device->fd, VIDIOC_QBUF, &buf) ) {
for (i = 0; i < device->n_buffers; ++i)
munmap(device->buffers[i].start, device->buffers[i].length);
}
close(device->fd);
free(device);
@ -500,16 +476,24 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
/* Turn on video stream */
if (-1 == xioctl(device->fd, VIDIOC_STREAMON, &type)) {
if ( -1 == xioctl(device->fd, VIDIOC_STREAMON, &type) ) {
close_video_device(vdt_input, temp_idx);
unlock;
return vde_FailedStart;
}
#else /* __OSX__ */
if ( osx_video_open_device(selection, &device->video_width, &device->video_height) != 0 ) {
free(device);
unlock;
return vde_FailedStart;
}
#endif
/* Create X11 window associated to device */
if ((device->x_display = XOpenDisplay(NULL)) == NULL) {
if ( (device->x_display = XOpenDisplay(NULL)) == NULL ) {
close_video_device(vdt_input, temp_idx);
unlock;
return vde_FailedStart;
@ -517,9 +501,9 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
int screen = DefaultScreen(device->x_display);
if (!(device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen), 0, 0,
device->video_width, device->video_height, 0, BlackPixel(device->x_display, screen),
BlackPixel(device->x_display, screen)))) {
if ( !(device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen), 0, 0,
device->video_width, device->video_height, 0, BlackPixel(device->x_display, screen),
BlackPixel(device->x_display, screen))) ) {
close_video_device(vdt_input, temp_idx);
unlock;
return vde_FailedStart;
@ -528,7 +512,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
XStoreName(device->x_display, device->x_window, "Video Preview");
XSelectInput(device->x_display, device->x_window, ExposureMask | ButtonPressMask | KeyPressMask);
if ((device->x_gc = DefaultGC(device->x_display, screen)) == NULL) {
if ( (device->x_gc = DefaultGC(device->x_display, screen)) == NULL ) {
close_video_device(vdt_input, temp_idx);
unlock;
return vde_FailedStart;
@ -549,7 +533,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
} else { /* vdt_output */
/* Create X11 window associated to device */
if ((device->x_display = XOpenDisplay(NULL)) == NULL) {
if ( (device->x_display = XOpenDisplay(NULL)) == NULL ) {
close_video_device(vdt_output, temp_idx);
unlock;
return vde_FailedStart;
@ -557,8 +541,8 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
int screen = DefaultScreen(device->x_display);
if (!(device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen), 0, 0,
100, 100, 0, BlackPixel(device->x_display, screen), BlackPixel(device->x_display, screen)))) {
if ( !(device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen), 0, 0,
100, 100, 0, BlackPixel(device->x_display, screen), BlackPixel(device->x_display, screen))) ) {
close_video_device(vdt_output, temp_idx);
unlock;
return vde_FailedStart;
@ -567,7 +551,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
XStoreName(device->x_display, device->x_window, "Video Receive");
XSelectInput(device->x_display, device->x_window, ExposureMask | ButtonPressMask | KeyPressMask);
if ((device->x_gc = DefaultGC(device->x_display, screen)) == NULL) {
if ( (device->x_gc = DefaultGC(device->x_display, screen)) == NULL ) {
close_video_device(vdt_output, temp_idx);
unlock;
return vde_FailedStart;
@ -591,25 +575,21 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
return vde_None;
}
VideoDeviceError write_video_out(uint16_t width, uint16_t height,
uint8_t const *y, uint8_t const *u, uint8_t const *v,
int32_t ystride, int32_t ustride, int32_t vstride,
void *user_data)
__inline VideoDeviceError write_video_out(uint16_t width, uint16_t height,
uint8_t const *y, uint8_t const *u, uint8_t const *v,
int32_t ystride, int32_t ustride, int32_t vstride,
void *user_data)
{
VideoDevice *device = video_devices_running[vdt_output][0];
if (!device) {
return vde_DeviceNotActive;
}
if ( !device ) return vde_DeviceNotActive;
if (!device->x_window) {
return vde_DeviceNotActive;
}
if ( !device->x_window ) return vde_DeviceNotActive;
pthread_mutex_lock(device->mutex);
/* Resize X11 window to correct size */
if (device->video_width != width || device->video_height != height) {
if ( device->video_width != width || device->video_height != height ) {
device->video_width = width;
device->video_height = height;
XResizeWindow(device->x_display, device->x_window, width, height);
@ -654,7 +634,7 @@ VideoDeviceError write_video_out(uint16_t width, uint16_t height,
return vde_None;
}
void *video_thread_poll(void *arg) // TODO: maybe use thread for every input source
void *video_thread_poll (void *arg) // TODO: maybe use thread for every input source
{
/*
* NOTE: We only need to poll input devices for data.
@ -672,13 +652,12 @@ void *video_thread_poll(void *arg) // TODO: maybe use thread for every input so
unlock;
if (video_thread_paused) {
usleep(10000); /* Wait for unpause. */
} else {
if ( video_thread_paused ) usleep(10000); /* Wait for unpause. */
else {
for (i = 0; i < size[vdt_input]; ++i) {
lock;
if (video_devices_running[vdt_input][i] != NULL) {
if ( video_devices_running[vdt_input][i] != NULL ) {
/* Obtain frame image data from device buffers */
VideoDevice *device = video_devices_running[vdt_input][i];
uint16_t video_width = device->video_width;
@ -687,21 +666,14 @@ void *video_thread_poll(void *arg) // TODO: maybe use thread for every input so
uint8_t *u = device->input.planes[1];
uint8_t *v = device->input.planes[2];
#if defined(__OSX__)
if (osx_video_read_device(y, u, v, &video_width, &video_height) != 0) {
unlock;
continue;
}
#else /* not __OSX__*/
#if defined(__linux__) || defined(__FreeBSD__)
struct v4l2_buffer buf;
memset(&(buf), 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (-1 == ioctl(device->fd, VIDIOC_DQBUF, &buf)) {
if ( -1 == ioctl(device->fd, VIDIOC_DQBUF, &buf) ) {
unlock;
continue;
}
@ -711,12 +683,18 @@ void *video_thread_poll(void *arg) // TODO: maybe use thread for every input so
/* Convert frame image data to YUV420 for ToxAV */
yuv422to420(y, u, v, data, video_width, video_height);
#else /* __OSX__*/
if ( osx_video_read_device(y, u, v, &video_width, &video_height) != 0 ) {
unlock;
continue;
}
#endif
/* Send frame data to friend through ToxAV */
if (device->cb) {
if ( device->cb )
device->cb(video_width, video_height, y, u, v, device->cb_data);
}
/* Convert YUV420 data to BGR */
uint8_t *img_data = malloc(video_width * video_height * 4);
@ -748,14 +726,14 @@ void *video_thread_poll(void *arg) // TODO: maybe use thread for every input so
XFlush(device->x_display);
free(img_data);
#if !defined(__OSX__)
#if defined(__linux__) || defined(__FreeBSD__)
if (-1 == xioctl(device->fd, VIDIOC_QBUF, &buf)) {
if ( -1 == xioctl(device->fd, VIDIOC_QBUF, &buf) ) {
unlock;
continue;
}
#endif
#endif /* __linux__ */
}
@ -771,41 +749,38 @@ void *video_thread_poll(void *arg) // TODO: maybe use thread for every input so
VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
{
if (device_idx >= MAX_DEVICES) {
return vde_InvalidSelection;
}
if ( device_idx >= MAX_DEVICES ) return vde_InvalidSelection;
lock;
VideoDevice *device = video_devices_running[type][device_idx];
VideoDeviceError rc = vde_None;
if (!device) {
if ( !device ) {
unlock;
return vde_DeviceNotActive;
}
video_devices_running[type][device_idx] = NULL;
if (!device->ref_count) {
if ( !device->ref_count ) {
if (type == vdt_input) {
#if defined(__OSX__)
osx_video_close_device(device_idx);
#else /* not __OSX__ */
if ( type == vdt_input ) {
#if defined(__linux__) || defined(__FreeBSD__)
enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl(device->fd, VIDIOC_STREAMOFF, &buf_type)) {}
if ( -1 == xioctl(device->fd, VIDIOC_STREAMOFF, &buf_type) ) {}
int i;
for (i = 0; i < device->n_buffers; ++i) {
if (-1 == munmap(device->buffers[i].start, device->buffers[i].length)) {
if ( -1 == munmap(device->buffers[i].start, device->buffers[i].length) ) {
}
}
close(device->fd);
#else /* __OSX__ */
osx_video_close_device(device_idx);
#endif
vpx_img_free(&device->input);
XDestroyWindow(device->x_display, device->x_window);
@ -813,9 +788,9 @@ VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
XCloseDisplay(device->x_display);
pthread_mutex_destroy(device->mutex);
#if !defined(__OSX__)
#if defined(__linux__) || defined(__FreeBSD__)
free(device->buffers);
#endif /* not __OSX__ */
#endif /* __linux__ */
free(device);
} else {
@ -827,9 +802,7 @@ VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
free(device);
}
} else {
device->ref_count--;
}
} else device->ref_count--;
unlock;
return rc;
@ -839,9 +812,8 @@ void print_video_devices(ToxWindow *self, VideoDeviceType type)
{
int i;
for (i = 0; i < size[type]; ++i) {
for (i = 0; i < size[type]; ++i)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%d: %s", i, video_devices_names[type][i]);
}
return;
}
@ -850,5 +822,3 @@ VideoDeviceError video_selection_valid(VideoDeviceType type, int32_t selection)
{
return (size[type] <= selection || selection < 0) ? vde_InvalidSelection : vde_None;
}
#endif /* VIDEO */

View File

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

View File

@ -39,166 +39,283 @@
extern char *DATA_FILE;
extern struct Winthread Winthread;
ToxWindow *windows[MAX_WINDOWS_NUM];
static uint8_t active_window_index;
static int num_active_windows;
static ToxWindow windows[MAX_WINDOWS_NUM];
static ToxWindow *active_window;
extern ToxWindow *prompt;
extern struct user_settings *user_settings;
static int num_active_windows;
/* CALLBACKS START */
void on_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
{
char msg[MAX_STR_SIZE + 1];
length = copy_tox_str(msg, sizeof(msg), (const char *) data, length);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onFriendRequest != NULL) {
windows[i]->onFriendRequest(windows[i], m, (const char *) public_key, msg, length);
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onFriendRequest != NULL) {
windows[i].onFriendRequest(&windows[i], m, (const char *) public_key, msg, length);
}
}
}
void on_friend_connection_status(Tox *m, uint32_t friendnumber, Tox_Connection connection_status, void *userdata)
void on_connectionchange(Tox *m, uint32_t friendnumber, TOX_CONNECTION connection_status, void *userdata)
{
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onConnectionChange != NULL) {
windows[i]->onConnectionChange(windows[i], m, friendnumber, connection_status);
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onConnectionChange != NULL)
windows[i].onConnectionChange(&windows[i], m, friendnumber, connection_status);
}
}
void on_friend_typing(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata)
void on_typing_change(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata)
{
if (user_settings->show_typing_other == SHOW_TYPING_OFF) {
if (user_settings->show_typing_other == SHOW_TYPING_OFF)
return;
}
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onTypingChange != NULL) {
windows[i]->onTypingChange(windows[i], m, friendnumber, is_typing);
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onTypingChange != NULL)
windows[i].onTypingChange(&windows[i], m, friendnumber, is_typing);
}
}
void on_friend_message(Tox *m, uint32_t friendnumber, Tox_Message_Type type, const uint8_t *string, size_t length,
void *userdata)
void on_message(Tox *m, uint32_t friendnumber, TOX_MESSAGE_TYPE type, const uint8_t *string, size_t length,
void *userdata)
{
char msg[MAX_STR_SIZE + 1];
length = copy_tox_str(msg, sizeof(msg), (const char *) string, length);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onMessage != NULL) {
windows[i]->onMessage(windows[i], m, friendnumber, type, msg, length);
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onMessage != NULL)
windows[i].onMessage(&windows[i], m, friendnumber, type, msg, length);
}
}
void on_friend_name(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata)
void on_nickchange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata)
{
char nick[TOXIC_MAX_NAME_LENGTH + 1];
length = copy_tox_str(nick, sizeof(nick), (const char *) string, length);
filter_str(nick, length);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onNickChange != NULL) {
windows[i]->onNickChange(windows[i], m, friendnumber, nick, length);
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onNickChange != NULL)
windows[i].onNickChange(&windows[i], m, friendnumber, nick, length);
}
store_data(m, DATA_FILE);
}
void on_friend_status_message(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata)
void on_statusmessagechange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata)
{
char msg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
length = copy_tox_str(msg, sizeof(msg), (const char *) string, length);
filter_str(msg, length);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onStatusMessageChange != NULL) {
windows[i]->onStatusMessageChange(windows[i], friendnumber, msg, length);
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onStatusMessageChange != NULL)
windows[i].onStatusMessageChange(&windows[i], friendnumber, msg, length);
}
}
void on_friend_status(Tox *m, uint32_t friendnumber, Tox_User_Status status, void *userdata)
void on_statuschange(Tox *m, uint32_t friendnumber, TOX_USER_STATUS status, void *userdata)
{
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onStatusChange != NULL) {
windows[i]->onStatusChange(windows[i], m, friendnumber, status);
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onStatusChange != NULL)
windows[i].onStatusChange(&windows[i], m, friendnumber, status);
}
}
void on_friend_added(Tox *m, uint32_t friendnumber, bool sort)
void on_friendadded(Tox *m, uint32_t friendnumber, bool sort)
{
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onFriendAdded != NULL) {
windows[i]->onFriendAdded(windows[i], m, friendnumber, sort);
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onFriendAdded != NULL)
windows[i].onFriendAdded(&windows[i], m, friendnumber, sort);
}
store_data(m, DATA_FILE);
}
void on_conference_message(Tox *m, uint32_t groupnumber, uint32_t peernumber, Tox_Message_Type type,
const uint8_t *message, size_t length, void *userdata)
void on_group_invite(Tox *m, uint32_t friendnumber, const uint8_t *invite_data, size_t length, void *userdata)
{
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupInvite != NULL)
windows[i].onGroupInvite(&windows[i], m, friendnumber, (char *) invite_data, length);
}
}
void on_group_message(Tox *m, uint32_t groupnumber, uint32_t peer_id, TOX_MESSAGE_TYPE type,
const uint8_t *message, size_t length, void *userdata)
{
char msg[MAX_STR_SIZE + 1];
length = copy_tox_str(msg, sizeof(msg), (const char *) message, length);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onGroupMessage != NULL) {
windows[i]->onGroupMessage(windows[i], m, groupnumber, peernumber, type, msg, length);
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupMessage != NULL)
windows[i].onGroupMessage(&windows[i], m, groupnumber, peer_id, type, msg, length);
}
}
void on_conference_invite(Tox *m, uint32_t friendnumber, Tox_Conference_Type type, const uint8_t *group_pub_key,
size_t length, void *userdata)
void on_group_private_message(Tox *m, uint32_t groupnumber, uint32_t peer_id, const uint8_t *message,
size_t length, void *userdata)
{
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onGroupInvite != NULL) {
windows[i]->onGroupInvite(windows[i], m, friendnumber, type, (char *) group_pub_key, length);
}
char msg[MAX_STR_SIZE + 1];
length = copy_tox_str(msg, sizeof(msg), (const char *) message, length);
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupPrivateMessage != NULL)
windows[i].onGroupPrivateMessage(&windows[i], m, groupnumber, peer_id, msg, length);
}
}
void on_conference_peer_list_changed(Tox *m, uint32_t groupnumber, void *userdata)
void on_group_status_change(Tox *m, uint32_t groupnumber, uint32_t peer_id, TOX_USER_STATUS status, void *userdata)
{
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onGroupNameListChange != NULL) {
windows[i]->onGroupNameListChange(windows[i], m, groupnumber);
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupStatusChange != NULL)
windows[i].onGroupStatusChange(&windows[i], m, groupnumber, peer_id, status);
}
}
void on_conference_peer_name(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *name,
size_t length, void *userdata)
void on_group_peer_join(Tox *m, uint32_t groupnumber, uint32_t peer_id, void *userdata)
{
char nick[TOXIC_MAX_NAME_LENGTH + 1];
length = copy_tox_str(nick, sizeof(nick), (const char *) name, length);
filter_str(nick, length);
size_t i;
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onGroupPeerNameChange != NULL) {
windows[i]->onGroupPeerNameChange(windows[i], m, groupnumber, peernumber, nick, length);
}
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupPeerJoin != NULL)
windows[i].onGroupPeerJoin(&windows[i], m, groupnumber, peer_id);
}
}
void on_conference_title(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *title, size_t length,
void *userdata)
void on_group_peer_exit(Tox *m, uint32_t groupnumber, uint32_t peer_id, const uint8_t *partmsg, size_t length,
void *userdata)
{
char msg[MAX_STR_SIZE + 1];
if (length == 0 || !partmsg) {
strcpy(msg, "Quit");
length = strlen(msg);
} else {
length = copy_tox_str(msg, sizeof(msg), (const char *) partmsg, length);
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupPeerExit != NULL)
windows[i].onGroupPeerExit(&windows[i], m, groupnumber, peer_id, msg, length);
}
}
void on_group_topic_change(Tox *m, uint32_t groupnumber, uint32_t peer_id, const uint8_t *topic, size_t length,
void *userdata)
{
char data[MAX_STR_SIZE + 1];
length = copy_tox_str(data, sizeof(data), (const char *) title, length);
length = copy_tox_str(data, sizeof(data), (const char *) topic, length);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onGroupTitleChange != NULL) {
windows[i]->onGroupTitleChange(windows[i], m, groupnumber, peernumber, data, length);
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupTopicChange != NULL)
windows[i].onGroupTopicChange(&windows[i], m, groupnumber, peer_id, data, length);
}
}
void on_group_peer_limit(Tox *m, uint32_t groupnumber, uint32_t peer_limit, void *userdata)
{
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupPeerLimit != NULL)
windows[i].onGroupPeerLimit(&windows[i], m, groupnumber, peer_limit);
}
}
void on_group_privacy_state(Tox *m, uint32_t groupnumber, TOX_GROUP_PRIVACY_STATE privacy_state, void *userdata)
{
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupPrivacyState != NULL)
windows[i].onGroupPrivacyState(&windows[i], m, groupnumber, privacy_state);
}
}
void on_group_password(Tox *m, uint32_t groupnumber, const uint8_t *password, size_t length, void *userdata)
{
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupPassword != NULL)
windows[i].onGroupPassword(&windows[i], m, groupnumber, (char *) password, length);
}
}
void on_group_nick_change(Tox *m, uint32_t groupnumber, uint32_t peer_id, const uint8_t *newname, size_t length,
void *userdata)
{
char name[TOXIC_MAX_NAME_LENGTH + 1];
length = copy_tox_str(name, sizeof(name), (const char *) newname, length);
filter_str(name, length);
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupNickChange != NULL)
windows[i].onGroupNickChange(&windows[i], m, groupnumber, peer_id, name, length);
}
}
void on_group_self_join(Tox *m, uint32_t groupnumber, void *userdata)
{
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupSelfJoin != NULL)
windows[i].onGroupSelfJoin(&windows[i], m, groupnumber);
}
}
void on_group_rejected(Tox *m, uint32_t groupnumber, TOX_GROUP_JOIN_FAIL type, void *userdata)
{
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupRejected != NULL)
windows[i].onGroupRejected(&windows[i], m, groupnumber, type);
}
}
void on_group_moderation(Tox *m, uint32_t groupnumber, uint32_t source_peer_id, uint32_t target_peer_id,
TOX_GROUP_MOD_EVENT type, void *userdata)
{
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupModeration != NULL)
windows[i].onGroupModeration(&windows[i], m, groupnumber, source_peer_id, target_peer_id, type);
}
}
@ -207,19 +324,19 @@ void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, u
{
struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
if (!ft) {
if (!ft)
return;
}
if (ft->file_type == TOX_FILE_KIND_AVATAR) {
on_avatar_chunk_request(m, ft, position, length);
return;
}
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onFileChunkRequest != NULL) {
windows[i]->onFileChunkRequest(windows[i], m, friendnumber, filenumber, position, length);
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onFileChunkRequest != NULL)
windows[i].onFileChunkRequest(&windows[i], m, friendnumber, filenumber, position, length);
}
}
@ -228,35 +345,35 @@ void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint
{
struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
if (!ft) {
if (!ft)
return;
}
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);
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onFileRecvChunk != NULL)
windows[i].onFileRecvChunk(&windows[i], m, friendnumber, filenumber, position, (char *) data, length);
}
}
void on_file_recv_control(Tox *m, uint32_t friendnumber, uint32_t filenumber, Tox_File_Control control,
void *userdata)
void on_file_control(Tox *m, uint32_t friendnumber, uint32_t filenumber, TOX_FILE_CONTROL control,
void *userdata)
{
struct FileTransfer *ft = get_file_transfer_struct(friendnumber, filenumber);
if (!ft) {
if (!ft)
return;
}
if (ft->file_type == TOX_FILE_KIND_AVATAR) {
on_avatar_file_control(m, ft, control);
return;
}
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onFileControl != NULL) {
windows[i]->onFileControl(windows[i], m, friendnumber, filenumber, control);
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onFileControl != NULL)
windows[i].onFileControl(&windows[i], m, friendnumber, filenumber, control);
}
}
@ -269,51 +386,50 @@ void on_file_recv(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint32_t k
return;
}
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onFileRecv != NULL) {
windows[i]->onFileRecv(windows[i], m, friendnumber, filenumber, file_size, (char *) filename,
filename_length);
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onFileRecv != NULL)
windows[i].onFileRecv(&windows[i], m, friendnumber, filenumber, file_size, (char *) filename,
filename_length);
}
}
void on_friend_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata)
void on_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata)
{
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL && windows[i]->onReadReceipt != NULL) {
windows[i]->onReadReceipt(windows[i], m, friendnumber, receipt);
}
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onReadReceipt != NULL)
windows[i].onReadReceipt(&windows[i], m, friendnumber, receipt);
}
}
/* CALLBACKS END */
int add_window(Tox *m, ToxWindow *w)
int add_window(Tox *m, ToxWindow w)
{
if (LINES < 2) {
if (LINES < 2)
return -1;
}
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; i++) {
if (windows[i] != NULL) {
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; i++) {
if (windows[i].active)
continue;
}
w->index = i;
w->window = newwin(LINES - 2, COLS, 0, 0);
w.window = newwin(LINES - 2, COLS, 0, 0);
if (w->window == NULL) {
if (w.window == NULL)
return -1;
}
#ifdef URXVT_FIX
/* Fixes text color problem on some terminals. */
wbkgd(w->window, COLOR_PAIR(6));
wbkgd(w.window, COLOR_PAIR(6));
#endif
windows[i] = w;
if (w->onInit) {
w->onInit(w, m);
}
if (w.onInit)
w.onInit(&w, m);
++num_active_windows;
@ -323,46 +439,42 @@ int add_window(Tox *m, ToxWindow *w)
return -1;
}
void set_active_window_index(uint8_t index)
void set_active_window(int index)
{
if (index < MAX_WINDOWS_NUM) {
active_window_index = index;
}
if (index < 0 || index >= MAX_WINDOWS_NUM)
return;
active_window = windows + index;
}
/* Shows next window when tab or back-tab is pressed */
void set_next_window(int ch)
{
if (ch == user_settings->key_next_tab) {
for (uint8_t i = active_window_index + 1; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] != NULL) {
set_active_window_index(i);
return;
}
}
} else {
uint8_t start = active_window_index == 0 ? MAX_WINDOWS_NUM - 1 : active_window_index - 1;
ToxWindow *end = windows + MAX_WINDOWS_NUM - 1;
ToxWindow *inf = active_window;
for (uint8_t i = start; i > 0; --i) {
if (windows[i] != NULL) {
set_active_window_index(i);
return;
}
}
while (true) {
if (ch == user_settings->key_next_tab) {
if (++active_window > end)
active_window = windows;
} else if (--active_window < windows)
active_window = end;
if (active_window->window)
return;
if (active_window == inf) /* infinite loop check */
exit_toxic_err("failed in set_next_window", FATALERR_INFLOOP);
}
set_active_window_index(0);
}
/* Deletes window w and cleans up */
void del_window(ToxWindow *w)
{
set_active_window_index(0);
set_active_window(0); /* Go to prompt screen */
uint8_t idx = w->index;
delwin(w->window);
free(windows[idx]);
windows[idx] = NULL;
memset(w, 0, sizeof(ToxWindow));
clear();
refresh();
@ -371,18 +483,13 @@ void del_window(ToxWindow *w)
ToxWindow *init_windows(Tox *m)
{
prompt = new_prompt();
int n_prompt = add_window(m, prompt);
int n_prompt = add_window(m, new_prompt());
if (n_prompt < 0) {
exit_toxic_err("add_window() for prompt failed in init_windows", FATALERR_WININIT);
}
if (n_prompt == -1 || add_window(m, new_friendlist()) == -1)
exit_toxic_err("failed in init_windows", FATALERR_WININIT);
if (add_window(m, new_friendlist()) == -1) {
exit_toxic_err("add_window() for friendlist failed in init_windows", FATALERR_WININIT);
}
set_active_window_index(n_prompt);
prompt = &windows[n_prompt];
active_window = prompt;
return prompt;
}
@ -398,26 +505,25 @@ void on_window_resize(void)
getmaxyx(stdscr, y2, x2);
y2 -= 2;
if (y2 <= 0 || x2 <= 0) {
if (y2 <= 0 || x2 <= 0)
return;
}
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] == NULL) {
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (!windows[i].active)
continue;
}
ToxWindow *w = windows[i];
ToxWindow *w = &windows[i];
if (windows[i]->is_friendlist) {
if (windows[i].is_friendlist) {
delwin(w->window);
w->window = newwin(y2, x2, 0, 0);
continue;
}
if (w->help->active) {
if (w->help->active)
wclear(w->help->win);
}
if (w->is_groupchat) {
delwin(w->chatwin->sidebar);
@ -439,9 +545,8 @@ void on_window_resize(void)
} else {
w->chatwin->history = subwin(w->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
if (!w->is_groupchat) {
if (!w->is_groupchat)
w->stb->topline = subwin(w->window, 2, x2, 0, 0);
}
}
#ifdef AUDIO
@ -451,7 +556,7 @@ void on_window_resize(void)
w->chatwin->infobox.win = newwin(INFOBOX_HEIGHT, INFOBOX_WIDTH + 1, 1, x2 - INFOBOX_WIDTH);
}
#endif /* AUDIO */
#endif /* AUDIO */
scrollok(w->chatwin->history, 0);
}
@ -461,9 +566,7 @@ static void draw_window_tab(ToxWindow *toxwin)
{
pthread_mutex_lock(&Winthread.lock);
if (toxwin->alert != WINDOW_ALERT_NONE) {
attron(COLOR_PAIR(toxwin->alert));
}
if (toxwin->alert != WINDOW_ALERT_NONE) attron(COLOR_PAIR(toxwin->alert));
pthread_mutex_unlock(&Winthread.lock);
@ -472,9 +575,7 @@ static void draw_window_tab(ToxWindow *toxwin)
pthread_mutex_lock(&Winthread.lock);
if (toxwin->alert != WINDOW_ALERT_NONE) {
attroff(COLOR_PAIR(toxwin->alert));
}
if (toxwin->alert != WINDOW_ALERT_NONE) attroff(COLOR_PAIR(toxwin->alert));
pthread_mutex_unlock(&Winthread.lock);
}
@ -483,14 +584,8 @@ static void draw_bar(void)
{
int y, x;
ToxWindow *w = windows[active_window_index];
if (w == NULL) {
return;
}
// save current cursor position
getyx(w->window, y, x);
getyx(active_window->window, y, x);
attron(COLOR_PAIR(BLUE));
mvhline(LINES - 2, 0, '_', COLS);
@ -498,32 +593,35 @@ static void draw_bar(void)
move(LINES - 1, 0);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] == NULL) {
continue;
}
attron(COLOR_PAIR(BLUE) | A_BOLD);
printw(" TOXIC " TOXICVER " |");
attroff(COLOR_PAIR(BLUE) | A_BOLD);
if (i == active_window_index) {
size_t i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (!windows[i].active)
continue;
if (windows + i == active_window)
#ifdef URXVT_FIX
attron(A_BOLD | COLOR_PAIR(GREEN));
} else {
else
#endif
attron(A_BOLD);
}
draw_window_tab(windows[i]);
draw_window_tab(&windows[i]);
if (i == active_window_index) {
if (windows + i == active_window)
#ifdef URXVT_FIX
attroff(A_BOLD | COLOR_PAIR(GREEN));
} else {
else
#endif
attroff(A_BOLD);
}
}
// restore cursor position after drawing
@ -534,13 +632,8 @@ static void draw_bar(void)
void draw_active_window(Tox *m)
{
ToxWindow *a = windows[active_window_index];
if (a == NULL) {
return;
}
pthread_mutex_lock(&Winthread.lock);
ToxWindow *a = active_window;
a->alert = WINDOW_ALERT_NONE;
pthread_mutex_unlock(&Winthread.lock);
@ -557,22 +650,19 @@ void draw_active_window(Tox *m)
#ifdef HAVE_WIDECHAR
int status = wget_wch(stdscr, &ch);
if (status == ERR) {
if (status == ERR)
return;
}
if (status == OK) {
if (status == OK)
ltr = iswprint(ch);
} else { /* if (status == KEY_CODE_YES) */
else /* if (status == KEY_CODE_YES) */
ltr = false;
}
#else
ch = getch();
if (ch == ERR) {
if (ch == ERR)
return;
}
/* TODO verify if this works */
ltr = isprint(ch);
@ -591,37 +681,28 @@ void draw_active_window(Tox *m)
call at least once per second */
void refresh_inactive_windows(void)
{
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
ToxWindow *toxwin = windows[i];
size_t i;
if (toxwin == NULL) {
continue;
}
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
ToxWindow *a = &windows[i];
if (i != active_window_index && !toxwin->is_friendlist) {
if (a->active && a != active_window && !a->is_friendlist) {
pthread_mutex_lock(&Winthread.lock);
line_info_print(toxwin);
line_info_print(a);
pthread_mutex_unlock(&Winthread.lock);
}
}
}
/* Returns a pointer to the ToxWindow in the ith index.
* Returns NULL if no ToxWindow exists.
*/
ToxWindow *get_window_ptr(size_t index)
/* returns a pointer to the ToxWindow in the ith index. Returns NULL if no ToxWindow exists */
ToxWindow *get_window_ptr(int i)
{
if (index >= MAX_WINDOWS_NUM) {
return NULL;
}
ToxWindow *toxwin = NULL;
return windows[index];
}
if (i >= 0 && i < MAX_WINDOWS_NUM && windows[i].active)
toxwin = &windows[i];
/* Returns a pointer to the currently active ToxWindow. */
ToxWindow *get_active_window(void)
{
return windows[active_window_index];
return toxwin;
}
void force_refresh(WINDOW *w)
@ -639,19 +720,15 @@ int get_num_active_windows(void)
/* destroys all chat and groupchat windows (should only be called on shutdown) */
void kill_all_windows(Tox *m)
{
for (uint8_t i = 2; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] == NULL) {
continue;
}
size_t i;
if (windows[i]->is_chat) {
kill_chat_window(windows[i], m);
} else if (windows[i]->is_groupchat) {
free_groupchat(windows[i], m, windows[i]->num);
}
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].is_chat)
kill_chat_window(&windows[i], m);
else if (windows[i].is_groupchat)
close_groupchat(&windows[i], m, windows[i].num);
}
/* TODO: use enum instead of magic indices */
kill_friendlist(windows[1]);
kill_prompt_window(windows[0]);
kill_prompt_window(prompt);
kill_friendlist();
}

View File

@ -36,13 +36,13 @@
#include "toxic.h"
#define MAX_WINDOWS_NUM 16
#define MAX_WINDOWS_NUM 32
#define MAX_WINDOW_NAME_LENGTH 22
#define CURS_Y_OFFSET 1 /* y-axis cursor offset for chat contexts */
#define CHATBOX_HEIGHT 2
/* Curses foreground colours (background is black) */
typedef enum {
enum {
WHITE,
GREEN,
CYAN,
@ -116,23 +116,33 @@ struct ToxWindow {
/* toxcore */
void(*onFriendRequest)(ToxWindow *, Tox *, const char *, const char *, size_t);
void(*onFriendAdded)(ToxWindow *, Tox *, uint32_t, bool);
void(*onConnectionChange)(ToxWindow *, Tox *, uint32_t, Tox_Connection);
void(*onMessage)(ToxWindow *, Tox *, uint32_t, Tox_Message_Type, const char *, size_t);
void(*onConnectionChange)(ToxWindow *, Tox *, uint32_t, TOX_CONNECTION);
void(*onMessage)(ToxWindow *, Tox *, uint32_t, TOX_MESSAGE_TYPE, const char *, size_t);
void(*onNickChange)(ToxWindow *, Tox *, uint32_t, const char *, size_t);
void(*onStatusChange)(ToxWindow *, Tox *, uint32_t, Tox_User_Status);
void(*onStatusChange)(ToxWindow *, Tox *, uint32_t, TOX_USER_STATUS);
void(*onStatusMessageChange)(ToxWindow *, uint32_t, const char *, size_t);
void(*onGroupMessage)(ToxWindow *, Tox *, uint32_t, uint32_t, Tox_Message_Type, const char *, size_t);
void(*onGroupInvite)(ToxWindow *, Tox *, int32_t, uint8_t, const char *, uint16_t);
void(*onGroupNameListChange)(ToxWindow *, Tox *, uint32_t);
void(*onGroupPeerNameChange)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t);
void(*onGroupTitleChange)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t);
void(*onFileChunkRequest)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, size_t);
void(*onFileRecvChunk)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, const char *, size_t);
void(*onFileControl)(ToxWindow *, Tox *, uint32_t, uint32_t, Tox_File_Control);
void(*onFileControl)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_FILE_CONTROL);
void(*onFileRecv)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, const char *, size_t);
void(*onTypingChange)(ToxWindow *, Tox *, uint32_t, bool);
void(*onReadReceipt)(ToxWindow *, Tox *, uint32_t, uint32_t);
void(*onGroupInvite)(ToxWindow *, Tox *, uint32_t, const char *, size_t);
void(*onGroupMessage)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_MESSAGE_TYPE, const char *, size_t);
void(*onGroupPrivateMessage)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t);
void(*onGroupPeerJoin)(ToxWindow *, Tox *, uint32_t, uint32_t);
void(*onGroupPeerExit)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t);
void(*onGroupNickChange)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t);
void(*onGroupStatusChange)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_USER_STATUS);
void(*onGroupTopicChange)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t);
void(*onGroupPeerLimit)(ToxWindow *, Tox *, uint32_t, uint32_t);
void(*onGroupPrivacyState)(ToxWindow *, Tox *, uint32_t, TOX_GROUP_PRIVACY_STATE);
void(*onGroupPassword)(ToxWindow *, Tox *, uint32_t, const char *, size_t);
void(*onGroupSelfJoin)(ToxWindow *, Tox *, uint32_t);
void(*onGroupRejected)(ToxWindow *, Tox *, uint32_t, TOX_GROUP_JOIN_FAIL);
void(*onGroupModeration)(ToxWindow *, Tox *, uint32_t, uint32_t, uint32_t, TOX_GROUP_MOD_EVENT);
#ifdef AUDIO
void(*onInvite)(ToxWindow *, ToxAV *, uint32_t, int);
@ -162,7 +172,7 @@ struct ToxWindow {
char name[TOXIC_MAX_NAME_LENGTH + 1];
uint32_t num; /* corresponds to friendnumber in chat windows */
uint8_t index; /* This window's index in the windows array */
bool active;
int x;
bool is_chat;
@ -187,8 +197,8 @@ struct StatusBar {
size_t statusmsg_len;
char nick[TOXIC_MAX_NAME_LENGTH + 1];
size_t nick_len;
Tox_User_Status status;
Tox_Connection connection;
TOX_USER_STATUS status;
TOX_CONNECTION connection;
};
#ifdef AUDIO
@ -252,18 +262,17 @@ struct Help {
ToxWindow *init_windows(Tox *m);
void draw_active_window(Tox *m);
int add_window(Tox *m, ToxWindow *w);
int add_window(Tox *m, ToxWindow w);
void del_window(ToxWindow *w);
void set_active_window_index(uint8_t index);
void set_active_window(int ch);
int get_num_active_windows(void);
void kill_all_windows(Tox *m); /* should only be called on shutdown */
void on_window_resize(void);
void force_refresh(WINDOW *w);
ToxWindow *get_window_ptr(size_t i);
ToxWindow *get_active_window(void);
ToxWindow *get_window_ptr(int i);
/* refresh inactive windows to prevent scrolling bugs.
call at least once per second */
void refresh_inactive_windows(void);
#endif /* WINDOWS_H */
#endif /* #define WINDOWS_H */

View File

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

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