mirror of
https://github.com/Tha14/toxic.git
synced 2025-06-27 17:56:46 +02:00
Compare commits
71 Commits
Author | SHA1 | Date | |
---|---|---|---|
b1d8ab102f | |||
c387df35f8 | |||
351a50c214 | |||
93175314b5 | |||
b905a1a3c5 | |||
c4386b195f | |||
ed1e617380 | |||
1382adb1f6 | |||
ecf1c317b7 | |||
cf0b99f1e5 | |||
3605a296a9 | |||
9375d220f9 | |||
8f94b0a218 | |||
85a0becbf9 | |||
fec36ad9e6 | |||
ecdf6f01d2 | |||
e1bfa30769 | |||
ebcbc7497b | |||
e844ece28b | |||
8508451ba6 | |||
5cc83a7cb5 | |||
febc725763 | |||
f2c116feb3 | |||
52dd60dc86 | |||
80c0500299 | |||
ab490d28b4 | |||
a9f7f85617 | |||
1bfc1ba371 | |||
2ede39369a | |||
922c184195 | |||
56a9571509 | |||
0136f22076 | |||
c4ace288af | |||
6d3fbfee59 | |||
be5e7906da | |||
369f26932e | |||
22ea522baf | |||
4f60d546e6 | |||
76d1eafdc0 | |||
37912f2d88 | |||
09710327c5 | |||
acee4615f8 | |||
5ed26eda9b | |||
6d2b90ac9f | |||
02ea0fac44 | |||
7d3d129624 | |||
b3ed8bc35c | |||
90210daca7 | |||
0e13a1f1bc | |||
09e2690211 | |||
e65e3af274 | |||
c6c60d018e | |||
451d4ced80 | |||
7a7402ff86 | |||
600e013adc | |||
1d71e2eb18 | |||
f858714edd | |||
4df44a7274 | |||
a26ed9d28f | |||
2bd5083b8f | |||
8805f694b9 | |||
71040355fd | |||
6bc5d8c543 | |||
abb39ea6b5 | |||
15846d2b50 | |||
958df9f2e8 | |||
2fd43aebee | |||
34c29745cc | |||
da6fe41d75 | |||
e17fa89d8f | |||
f056f13329 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -16,3 +16,4 @@ stamp-h1
|
|||||||
build/toxic
|
build/toxic
|
||||||
build/*.o
|
build/*.o
|
||||||
build/*.d
|
build/*.d
|
||||||
|
apidoc/python/build
|
||||||
|
30
INSTALL.md
30
INSTALL.md
@ -1,57 +1,53 @@
|
|||||||
# Installation
|
# Installation
|
||||||
* [Dependencies](#deps)
|
* [Dependencies](#dependencies)
|
||||||
* [OS X Notes](#deps_osx)
|
* [OS X Notes](#os-x-notes)
|
||||||
* [Compiling](#compiling)
|
* [Compiling](#compiling)
|
||||||
* [Documentation](#docs)
|
* [Documentation](#documentation)
|
||||||
* [Notes](#notes)
|
* [Notes](#notes)
|
||||||
* [Compilation variables](#comp_vars)
|
* [Compilation variables](#compilation-variables)
|
||||||
* [Packaging](#packaging)
|
* [Packaging](#packaging)
|
||||||
|
|
||||||
<a name="deps" />
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
| Name | Needed by | Debian package |
|
| Name | Needed by | Debian package |
|
||||||
|------------------------------------------------------|----------------------------|---------------------|
|
|------------------------------------------------------|----------------------------|---------------------|
|
||||||
| [Tox Core](https://github.com/irungentoo/toxcore) | BASE | *None* |
|
| [Tox Core](https://github.com/toktok/c-toxcore) | BASE | *None* |
|
||||||
| [NCurses](https://www.gnu.org/software/ncurses) | BASE | libncursesw5-dev |
|
| [NCurses](https://www.gnu.org/software/ncurses) | BASE | libncursesw5-dev |
|
||||||
| [LibConfig](http://www.hyperrealm.com/libconfig) | BASE | libconfig-dev |
|
| [LibConfig](http://www.hyperrealm.com/libconfig) | BASE | libconfig-dev |
|
||||||
| [GNUmake](https://www.gnu.org/software/make) | BASE | make |
|
| [GNUmake](https://www.gnu.org/software/make) | BASE | make |
|
||||||
| [libcurl](http://curl.haxx.se/) | BASE | libcurl4-openssl-dev|
|
| [libcurl](http://curl.haxx.se/) | BASE | libcurl4-openssl-dev|
|
||||||
| [libqrencode](https://fukuchi.org/works/qrencode/) | BASE | libqrencode-dev |
|
| [libqrencode](https://fukuchi.org/works/qrencode/) | BASE | libqrencode-dev |
|
||||||
| [Tox Core AV](https://github.com/irungentoo/toxcore) | AUDIO | *None* |
|
| [Tox Core AV](https://github.com/toktok/c-toxcore) | AUDIO | *None* |
|
||||||
| [OpenAL](http://openal.org) | AUDIO, SOUND NOTIFICATIONS | libopenal-dev |
|
| [OpenAL](http://openal.org) | AUDIO, SOUND NOTIFICATIONS | libopenal-dev |
|
||||||
| [OpenALUT](http://openal.org) | SOUND NOTIFICATIONS | libalut-dev |
|
| [OpenALUT](http://openal.org) | SOUND NOTIFICATIONS | libalut-dev |
|
||||||
| [LibNotify](https://developer.gnome.org/libnotify) | DESKTOP NOTIFICATIONS | libnotify-dev |
|
| [LibNotify](https://developer.gnome.org/libnotify) | DESKTOP NOTIFICATIONS | libnotify-dev |
|
||||||
|
| [Python 3](http://www.python.org/) | PYTHON | python3-dev |
|
||||||
| [AsciiDoc](http://asciidoc.org/index.html) | DOCUMENTATION<sup>1</sup> | asciidoc |
|
| [AsciiDoc](http://asciidoc.org/index.html) | DOCUMENTATION<sup>1</sup> | asciidoc |
|
||||||
<sup>1</sup>: see [Documentation](#docs)
|
|
||||||
|
|
||||||
<a name="deps_osx" />
|
<sup>1</sup>: see [Documentation](#documentation)
|
||||||
|
|
||||||
#### OS X Notes
|
#### OS X Notes
|
||||||
Using [Homebrew](http://brew.sh):
|
Using [Homebrew](http://brew.sh):
|
||||||
```
|
```
|
||||||
brew install openal-soft freealut libconfig
|
brew install openal-soft freealut libconfig
|
||||||
brew install https://raw.githubusercontent.com/Tox/homebrew-tox/master/Formula/libtoxcore.rb
|
brew install --HEAD https://raw.githubusercontent.com/Tox/homebrew-tox/master/Formula/libtoxcore.rb
|
||||||
brew install https://raw.githubusercontent.com/Homebrew/homebrew-x11/master/libnotify.rb
|
brew install libnotify
|
||||||
```
|
```
|
||||||
|
|
||||||
You can omit `libnotify` if you intend to build without desktop notifications enabled.
|
You can omit `libnotify` if you intend to build without desktop notifications enabled.
|
||||||
|
|
||||||
<a name="Compiling">
|
|
||||||
## Compiling
|
## Compiling
|
||||||
```
|
```
|
||||||
make PREFIX="/where/to/install"
|
make PREFIX="/where/to/install"
|
||||||
sudo make install PREFIX="/where/to/install"
|
sudo make install PREFIX="/where/to/install"
|
||||||
```
|
```
|
||||||
|
|
||||||
<a name="docs" />
|
|
||||||
#### Documentation
|
#### Documentation
|
||||||
Run `make doc` in the build directory after editing the asciidoc files to regenerate the manpages.<br />
|
Run `make doc` in the build directory after editing the asciidoc files to regenerate the manpages.<br />
|
||||||
**NOTE FOR DEVELOPERS**: asciidoc files and generated manpages will need to be commited together.<br />
|
**NOTE FOR DEVELOPERS**: asciidoc files and generated manpages will need to be commited together.<br />
|
||||||
**NOTE FOR EVERYONE**: [asciidoc](http://asciidoc.org/index.html) (and this step) is only required for regenerating manpages when you modify them.
|
**NOTE FOR EVERYONE**: [asciidoc](http://asciidoc.org/index.html) (and this step) is only required for regenerating manpages when you modify them.
|
||||||
|
|
||||||
<a name="notes" />
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
<a name="comp_vars" />
|
|
||||||
#### Compilation variables
|
#### Compilation variables
|
||||||
* You can add specific flags to the Makefile with `USER_CFLAGS=""` and/or `USER_LDFLAGS=""`
|
* You can add specific flags to the Makefile with `USER_CFLAGS=""` and/or `USER_LDFLAGS=""`
|
||||||
* You can pass your own flags to the Makefile with `CFLAGS=""` and/or `LDFLAGS=""` (this will supersede the default ones)
|
* You can pass your own flags to the Makefile with `CFLAGS=""` and/or `LDFLAGS=""` (this will supersede the default ones)
|
||||||
@ -60,11 +56,11 @@ Run `make doc` in the build directory after editing the asciidoc files to regene
|
|||||||
* `DISABLE_AV=1` → build toxic without audio call support
|
* `DISABLE_AV=1` → build toxic without audio call support
|
||||||
* `DISABLE_SOUND_NOTIFY=1` → build toxic without sound notifications support
|
* `DISABLE_SOUND_NOTIFY=1` → build toxic without sound notifications support
|
||||||
* `DISABLE_DESKTOP_NOTIFY=1` → build toxic without desktop notifications support
|
* `DISABLE_DESKTOP_NOTIFY=1` → build toxic without desktop notifications support
|
||||||
|
* Features excluded from the default build must be explicitly enabled using special variables:
|
||||||
|
* `ENABLE_PYTHON=1` → build toxic with Python scripting support
|
||||||
|
|
||||||
<a name="packaging" />
|
|
||||||
#### Packaging
|
#### Packaging
|
||||||
* For packaging purpose, you can use `DESTDIR=""` to specify a directory where to store installed files
|
* 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=""` can be used in addition to `PREFIX=""`:
|
||||||
* `DESTDIR=""` is meant to specify a directory where to store installed files (ex: "/tmp/build/pkg")
|
* `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")
|
* `PREFIX=""` is meant to specify a prefix directory for binaries and data files (ex: "/usr/local")
|
||||||
|
|
||||||
|
3
Makefile
3
Makefile
@ -30,6 +30,9 @@ endif
|
|||||||
ifeq ($(UNAME_S), OpenBSD)
|
ifeq ($(UNAME_S), OpenBSD)
|
||||||
-include $(CFG_DIR)/systems/FreeBSD.mk
|
-include $(CFG_DIR)/systems/FreeBSD.mk
|
||||||
endif
|
endif
|
||||||
|
ifeq ($(UNAME_S), NetBSD)
|
||||||
|
-include $(CFG_DIR)/systems/FreeBSD.mk
|
||||||
|
endif
|
||||||
ifeq ($(UNAME_S), Darwin)
|
ifeq ($(UNAME_S), Darwin)
|
||||||
-include $(CFG_DIR)/systems/Darwin.mk
|
-include $(CFG_DIR)/systems/Darwin.mk
|
||||||
endif
|
endif
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
src="https://scan.coverity.com/projects/4975/badge.svg"/>
|
src="https://scan.coverity.com/projects/4975/badge.svg"/>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
Toxic is a [Tox](https://tox.chat)-based instant messenging client which formerly resided in the [Tox core repository](https://github.com/irungentoo/toxcore), and is now available as a standalone application.
|
Toxic is a [Tox](https://tox.chat)-based instant messenging client which formerly resided in the [Tox core repository](https://github.com/toktok/c-toxcore), and is now available as a standalone application.
|
||||||
|
|
||||||
[](https://i.imgur.com/san99Z2.png)
|
[](https://i.imgur.com/san99Z2.png)
|
||||||
|
|
||||||
|
20
apidoc/python/Makefile
Normal file
20
apidoc/python/Makefile
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Minimal makefile for Sphinx documentation
|
||||||
|
#
|
||||||
|
|
||||||
|
# You can set these variables from the command line.
|
||||||
|
SPHINXOPTS =
|
||||||
|
SPHINXBUILD = sphinx-build
|
||||||
|
SPHINXPROJ = toxic_api
|
||||||
|
SOURCEDIR = source
|
||||||
|
BUILDDIR = build
|
||||||
|
|
||||||
|
# Put it first so that "make" without argument is like "make help".
|
||||||
|
help:
|
||||||
|
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||||
|
|
||||||
|
.PHONY: help Makefile
|
||||||
|
|
||||||
|
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||||
|
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||||
|
%: Makefile
|
||||||
|
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
157
apidoc/python/source/conf.py
Normal file
157
apidoc/python/source/conf.py
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# toxic_api documentation build configuration file, created by
|
||||||
|
# sphinx-quickstart on Tue May 16 08:58:24 2017.
|
||||||
|
#
|
||||||
|
# This file is execfile()d with the current directory set to its
|
||||||
|
# containing dir.
|
||||||
|
#
|
||||||
|
# Note that not all possible configuration values are present in this
|
||||||
|
# autogenerated file.
|
||||||
|
#
|
||||||
|
# All configuration values have a default; values that are commented out
|
||||||
|
# serve to show the default.
|
||||||
|
|
||||||
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
|
#
|
||||||
|
# import os
|
||||||
|
# import sys
|
||||||
|
# sys.path.insert(0, os.path.abspath('.'))
|
||||||
|
|
||||||
|
|
||||||
|
# -- General configuration ------------------------------------------------
|
||||||
|
|
||||||
|
# If your documentation needs a minimal Sphinx version, state it here.
|
||||||
|
#
|
||||||
|
# needs_sphinx = '1.0'
|
||||||
|
|
||||||
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
|
# ones.
|
||||||
|
extensions = []
|
||||||
|
|
||||||
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
templates_path = ['_templates']
|
||||||
|
|
||||||
|
# The suffix(es) of source filenames.
|
||||||
|
# You can specify multiple suffix as a list of string:
|
||||||
|
#
|
||||||
|
# source_suffix = ['.rst', '.md']
|
||||||
|
source_suffix = '.rst'
|
||||||
|
|
||||||
|
# The master toctree document.
|
||||||
|
master_doc = 'index'
|
||||||
|
|
||||||
|
# General information about the project.
|
||||||
|
project = 'toxic_api'
|
||||||
|
copyright = '2017, Jakob Kreuze'
|
||||||
|
author = 'Jakob Kreuze'
|
||||||
|
|
||||||
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
|
# |version| and |release|, also used in various other places throughout the
|
||||||
|
# built documents.
|
||||||
|
#
|
||||||
|
# The short X.Y version.
|
||||||
|
version = '0.8.1'
|
||||||
|
# The full version, including alpha/beta/rc tags.
|
||||||
|
release = '0.8.1'
|
||||||
|
|
||||||
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
|
# for a list of supported languages.
|
||||||
|
#
|
||||||
|
# This is also used if you do content translation via gettext catalogs.
|
||||||
|
# Usually you set "language" from the command line for these cases.
|
||||||
|
language = None
|
||||||
|
|
||||||
|
# List of patterns, relative to source directory, that match files and
|
||||||
|
# directories to ignore when looking for source files.
|
||||||
|
# This patterns also effect to html_static_path and html_extra_path
|
||||||
|
exclude_patterns = []
|
||||||
|
|
||||||
|
# The name of the Pygments (syntax highlighting) style to use.
|
||||||
|
pygments_style = 'sphinx'
|
||||||
|
|
||||||
|
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||||
|
todo_include_todos = False
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTML output ----------------------------------------------
|
||||||
|
|
||||||
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
|
# a list of builtin themes.
|
||||||
|
#
|
||||||
|
html_theme = 'alabaster'
|
||||||
|
|
||||||
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
|
# further. For a list of options available for each theme, see the
|
||||||
|
# documentation.
|
||||||
|
#
|
||||||
|
# html_theme_options = {}
|
||||||
|
|
||||||
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
|
html_static_path = ['_static']
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTMLHelp output ------------------------------------------
|
||||||
|
|
||||||
|
# Output file base name for HTML help builder.
|
||||||
|
htmlhelp_basename = 'toxic_apidoc'
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for LaTeX output ---------------------------------------------
|
||||||
|
|
||||||
|
latex_elements = {
|
||||||
|
# The paper size ('letterpaper' or 'a4paper').
|
||||||
|
#
|
||||||
|
# 'papersize': 'letterpaper',
|
||||||
|
|
||||||
|
# The font size ('10pt', '11pt' or '12pt').
|
||||||
|
#
|
||||||
|
# 'pointsize': '10pt',
|
||||||
|
|
||||||
|
# Additional stuff for the LaTeX preamble.
|
||||||
|
#
|
||||||
|
# 'preamble': '',
|
||||||
|
|
||||||
|
# Latex figure (float) alignment
|
||||||
|
#
|
||||||
|
# 'figure_align': 'htbp',
|
||||||
|
}
|
||||||
|
|
||||||
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
|
# (source start file, target name, title,
|
||||||
|
# author, documentclass [howto, manual, or own class]).
|
||||||
|
latex_documents = [
|
||||||
|
(master_doc, 'toxic_api.tex', 'toxic\\_api Documentation',
|
||||||
|
'Jakob Kreuze', 'manual'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for manual page output ---------------------------------------
|
||||||
|
|
||||||
|
# One entry per manual page. List of tuples
|
||||||
|
# (source start file, name, description, authors, manual section).
|
||||||
|
man_pages = [
|
||||||
|
(master_doc, 'toxic_api', 'toxic_api Documentation',
|
||||||
|
[author], 1)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for Texinfo output -------------------------------------------
|
||||||
|
|
||||||
|
# Grouping the document tree into Texinfo files. List of tuples
|
||||||
|
# (source start file, target name, title, author,
|
||||||
|
# dir menu entry, description, category)
|
||||||
|
texinfo_documents = [
|
||||||
|
(master_doc, 'toxic_api', 'toxic_api Documentation',
|
||||||
|
author, 'toxic_api', 'One line description of project.',
|
||||||
|
'Miscellaneous'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
8
apidoc/python/source/examples.rst
Normal file
8
apidoc/python/source/examples.rst
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
============
|
||||||
|
API Examples
|
||||||
|
============
|
||||||
|
|
||||||
|
Fortune
|
||||||
|
=======
|
||||||
|
.. literalinclude:: fortune.py
|
||||||
|
:language: python
|
37
apidoc/python/source/fortune.py
Normal file
37
apidoc/python/source/fortune.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import toxic_api
|
||||||
|
import random
|
||||||
|
|
||||||
|
FORTUNES = [
|
||||||
|
"A bug in the code is worth two in the documentation.",
|
||||||
|
"A bug in the hand is better than one as yet undetected.",
|
||||||
|
"\"A debugged program is one for which you have not yet found the "
|
||||||
|
"conditions that make it fail.\" -- Jerry Ogdin"
|
||||||
|
]
|
||||||
|
|
||||||
|
def send_fortune(args):
|
||||||
|
"""Callback function that sends the contact of the current window a
|
||||||
|
given number of random fortunes.
|
||||||
|
"""
|
||||||
|
if len(args) != 1:
|
||||||
|
toxic_api.display("Only one argument allowed!")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
count = int(args[0])
|
||||||
|
except ValueError:
|
||||||
|
toxic_api.display("Argument must be a number!")
|
||||||
|
return
|
||||||
|
|
||||||
|
if count < 0 or count > 20:
|
||||||
|
toxic_api.display("Argument is too large!")
|
||||||
|
return
|
||||||
|
|
||||||
|
name = toxic_api.get_nick()
|
||||||
|
|
||||||
|
toxic_api.send("%s has decided to send you %d fortunes:" % (name, count))
|
||||||
|
for _ in range(count):
|
||||||
|
toxic_api.send(random.choice(FORTUNES))
|
||||||
|
|
||||||
|
|
||||||
|
toxic_api.register("/fortune", "Send a fortune to the contact of the current "
|
||||||
|
"window", send_fortune)
|
9
apidoc/python/source/index.rst
Normal file
9
apidoc/python/source/index.rst
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
Toxic Scripting Interface Documentation
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
intro
|
||||||
|
reference
|
||||||
|
examples
|
12
apidoc/python/source/intro.rst
Normal file
12
apidoc/python/source/intro.rst
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
=========================
|
||||||
|
Toxic Scripting Interface
|
||||||
|
=========================
|
||||||
|
|
||||||
|
A Python scripting interface to `Toxic <https://github.com/JFreegman/toxic>`_.
|
||||||
|
|
||||||
|
|
||||||
|
Getting Started
|
||||||
|
===============
|
||||||
|
Toxic is compiled with Python support by default. To access the scripting interface, simply import "toxic_api" in your script.
|
||||||
|
|
||||||
|
Scripts can be run by issuing "/run <path>" from toxic, or placing them in the "autorun_path" from your toxic configuration file.
|
73
apidoc/python/source/reference.rst
Normal file
73
apidoc/python/source/reference.rst
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
=============
|
||||||
|
API Reference
|
||||||
|
=============
|
||||||
|
|
||||||
|
Messages
|
||||||
|
========
|
||||||
|
.. function:: display(msg)
|
||||||
|
|
||||||
|
Display a message to the user through the current window.
|
||||||
|
|
||||||
|
:param msg: The message to display.
|
||||||
|
:type msg: string
|
||||||
|
:rtype: none
|
||||||
|
|
||||||
|
.. function:: send(msg)
|
||||||
|
|
||||||
|
Send a message to the user specified by the currently open conversation.
|
||||||
|
|
||||||
|
:param msg: The message to display.
|
||||||
|
:type msg: string
|
||||||
|
:rtype: none
|
||||||
|
|
||||||
|
|
||||||
|
State
|
||||||
|
=====
|
||||||
|
.. function:: get_nick()
|
||||||
|
|
||||||
|
Return the user's current nickname.
|
||||||
|
|
||||||
|
:rtype: string
|
||||||
|
|
||||||
|
.. function:: get_status()
|
||||||
|
|
||||||
|
Return a string representing the user's current status. Can be either "online", "away", or "busy".
|
||||||
|
|
||||||
|
:rtype: string
|
||||||
|
|
||||||
|
.. function:: get_status_message()
|
||||||
|
|
||||||
|
Return the user's current status message.
|
||||||
|
|
||||||
|
:rtype: string
|
||||||
|
|
||||||
|
.. function:: get_all_friends()
|
||||||
|
|
||||||
|
Return a list of all the user's friends.
|
||||||
|
|
||||||
|
:rtype: list of (string, string) tuples containing the nickname followed by their public key
|
||||||
|
|
||||||
|
|
||||||
|
Commands
|
||||||
|
========
|
||||||
|
.. function:: execute(command, class)
|
||||||
|
|
||||||
|
Executes the given command. The API exports three constants for the class parameter; GLOBAL_COMMAND, CHAT_COMMAND, and GROUPCHAT_COMMAND.
|
||||||
|
|
||||||
|
:param command: The command to execute.
|
||||||
|
:type command: string
|
||||||
|
:param class: The class of the command.
|
||||||
|
:type class: int
|
||||||
|
:rtype: none
|
||||||
|
|
||||||
|
.. function:: register(command, help, callback)
|
||||||
|
|
||||||
|
Register a callback to be executed whenever command is run. The callback function will be called with one argument, a list of arguments from when the user calls the command.
|
||||||
|
|
||||||
|
:param command: The command to listen for.
|
||||||
|
:type command: string
|
||||||
|
:param help: A description of the command to be shown in the help menu.
|
||||||
|
:type help: string
|
||||||
|
:param callback: The function to be called.
|
||||||
|
:type callback: callable
|
||||||
|
:rtype: none
|
11
astylerc
Normal file
11
astylerc
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
--style=kr
|
||||||
|
--pad-header
|
||||||
|
--max-code-length=120
|
||||||
|
--convert-tabs
|
||||||
|
--indent-switches
|
||||||
|
--pad-oper
|
||||||
|
--align-pointer=name
|
||||||
|
--align-reference=name
|
||||||
|
--preserve-date
|
||||||
|
--lineend=linux
|
||||||
|
--break-blocks
|
@ -18,4 +18,4 @@ else ifneq ($(MAKECMDGOALS), clean)
|
|||||||
$(warning WARNING -- Toxic will be compiled without audio support)
|
$(warning WARNING -- Toxic will be compiled without audio support)
|
||||||
$(warning WARNING -- You need these libraries for audio support)
|
$(warning WARNING -- You need these libraries for audio support)
|
||||||
$(warning WARNING -- $(MISSING_AUDIO_LIBS))
|
$(warning WARNING -- $(MISSING_AUDIO_LIBS))
|
||||||
endif
|
endif
|
||||||
|
@ -34,6 +34,18 @@ ifneq ($(DESK_NOTIFY), disabled)
|
|||||||
-include $(CHECKS_DIR)/desktop_notifications.mk
|
-include $(CHECKS_DIR)/desktop_notifications.mk
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# Check if we want build QR exported as PNG support
|
||||||
|
QR_PNG = $(shell if [ -z "$(DISABLE_QRPNG)" ] || [ "$(DISABLE_QRPNG)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
|
||||||
|
ifneq ($(QR_PNG), disabled)
|
||||||
|
-include $(CHECKS_DIR)/qr_png.mk
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Check if we want build Python scripting support
|
||||||
|
PYTHON = $(shell if [ -z "$(ENABLE_PYTHON)" ] || [ "$(ENABLE_PYTHON)" = "0" ] ; then echo disabled ; else echo enabled ; fi)
|
||||||
|
ifneq ($(PYTHON), disabled)
|
||||||
|
-include $(CHECKS_DIR)/python.mk
|
||||||
|
endif
|
||||||
|
|
||||||
# Check if we can build Toxic
|
# Check if we can build Toxic
|
||||||
CHECK_LIBS = $(shell $(PKG_CONFIG) --exists $(LIBS) || echo -n "error")
|
CHECK_LIBS = $(shell $(PKG_CONFIG) --exists $(LIBS) || echo -n "error")
|
||||||
ifneq ($(CHECK_LIBS), error)
|
ifneq ($(CHECK_LIBS), error)
|
||||||
|
15
cfg/checks/python.mk
Normal file
15
cfg/checks/python.mk
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Variables for Python scripting support
|
||||||
|
PYTHON3_LIBS = python3
|
||||||
|
PYTHON_CFLAGS = -DPYTHON
|
||||||
|
PYTHON_OBJ = api.o python_api.o
|
||||||
|
|
||||||
|
# Check if we can build Python scripting support
|
||||||
|
CHECK_PYTHON3_LIBS = $(shell $(PKG_CONFIG) --exists $(PYTHON3_LIBS) || echo -n "error")
|
||||||
|
ifneq ($(CHECK_PYTHON3_LIBS), error)
|
||||||
|
LDFLAGS += $(shell python3-config --ldflags)
|
||||||
|
CFLAGS += $(PYTHON_CFLAGS) $(shell python3-config --includes)
|
||||||
|
OBJ += $(PYTHON_OBJ)
|
||||||
|
else ifneq ($(MAKECMDGOALS), clean)
|
||||||
|
$(warning WARNING -- Toxic will be compiled without Python scripting support)
|
||||||
|
$(warning WARNING -- You need python3 installed for Python scripting support)
|
||||||
|
endif
|
15
cfg/checks/qr_png.mk
Normal file
15
cfg/checks/qr_png.mk
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Variables for QR exported as PNG support
|
||||||
|
PNG_LIBS = libpng
|
||||||
|
PNG_CFLAGS = -DQRPNG
|
||||||
|
|
||||||
|
# Check if we can build QR exported as PNG support
|
||||||
|
CHECK_PNG_LIBS = $(shell pkg-config --exists $(PNG_LIBS) || echo -n "error")
|
||||||
|
ifneq ($(CHECK_PNG_LIBS), error)
|
||||||
|
LIBS += $(PNG_LIBS)
|
||||||
|
CFLAGS += $(PNG_CFLAGS)
|
||||||
|
else ifneq ($(MAKECMDGOALS), clean)
|
||||||
|
MISSING_PNG_LIBS = $(shell for lib in $(PNG_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
|
||||||
|
$(warning WARNING -- Toxic will be compiled without QR exported as PNG support)
|
||||||
|
$(warning WARNING -- You need these libraries for QR exported as PNG support)
|
||||||
|
$(warning WARNING -- $(MISSING_PNG_LIBS))
|
||||||
|
endif
|
@ -8,14 +8,14 @@ else
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
# Check if we can build video support
|
# Check if we can build video support
|
||||||
CHECK_VIDEO_LIBS = $(shell pkg-config --exists $(VIDEO_LIBS) || echo -n "error")
|
CHECK_VIDEO_LIBS = $(shell $(PKG_CONFIG) --exists $(VIDEO_LIBS) || echo -n "error")
|
||||||
ifneq ($(CHECK_VIDEO_LIBS), error)
|
ifneq ($(CHECK_VIDEO_LIBS), error)
|
||||||
LIBS += $(VIDEO_LIBS)
|
LIBS += $(VIDEO_LIBS)
|
||||||
CFLAGS += $(VIDEO_CFLAGS)
|
CFLAGS += $(VIDEO_CFLAGS)
|
||||||
OBJ += $(VIDEO_OBJ)
|
OBJ += $(VIDEO_OBJ)
|
||||||
else ifneq ($(MAKECMDGOALS), clean)
|
else ifneq ($(MAKECMDGOALS), clean)
|
||||||
MISSING_VIDEO_LIBS = $(shell for lib in $(VIDEO_LIBS) ; do if ! pkg-config --exists $$lib ; then echo $$lib ; fi ; done)
|
MISSING_VIDEO_LIBS = $(shell for lib in $(VIDEO_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
|
||||||
$(warning WARNING -- Toxic will be compiled without video support)
|
$(warning WARNING -- Toxic will be compiled without video support)
|
||||||
$(warning WARNING -- You will need these libraries for video support)
|
$(warning WARNING -- You will need these libraries for video support)
|
||||||
$(warning WARNING -- $(MISSING_VIDEO_LIBS))
|
$(warning WARNING -- $(MISSING_VIDEO_LIBS))
|
||||||
endif
|
endif
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Version
|
# Version
|
||||||
TOXIC_VERSION = 0.7.1
|
TOXIC_VERSION = 0.8.1
|
||||||
REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error")
|
REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error")
|
||||||
ifneq (, $(findstring error, $(REV)))
|
ifneq (, $(findstring error, $(REV)))
|
||||||
VERSION = $(TOXIC_VERSION)
|
VERSION = $(TOXIC_VERSION)
|
||||||
|
@ -14,6 +14,8 @@ help:
|
|||||||
@echo " DISABLE_AV: Set to \"1\" to force building without audio call support"
|
@echo " DISABLE_AV: Set to \"1\" to force building without audio call support"
|
||||||
@echo " DISABLE_SOUND_NOTIFY: Set to \"1\" to force building without sound notification support"
|
@echo " DISABLE_SOUND_NOTIFY: Set to \"1\" to force building without sound notification support"
|
||||||
@echo " DISABLE_DESKTOP_NOTIFY: Set to \"1\" to force building without desktop notifications support"
|
@echo " DISABLE_DESKTOP_NOTIFY: Set to \"1\" to force building without desktop notifications support"
|
||||||
|
@echo " DISABLE_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_CFLAGS: Add custom flags to default CFLAGS"
|
||||||
@echo " USER_LDFLAGS: Add custom flags to default LDFLAGS"
|
@echo " USER_LDFLAGS: Add custom flags to default LDFLAGS"
|
||||||
@echo " PREFIX: Specify a prefix directory for binaries, data files,... (default is \"$(abspath $(PREFIX))\")"
|
@echo " PREFIX: Specify a prefix directory for binaries, data files,... (default is \"$(abspath $(PREFIX))\")"
|
||||||
|
@ -35,7 +35,7 @@ install: $(BUILD_DIR)/toxic
|
|||||||
mv temp_file $$file ;\
|
mv temp_file $$file ;\
|
||||||
sed -e 's:__DATADIR__:'$(abspath $(DATADIR))':g' $$file > temp_file && \
|
sed -e 's:__DATADIR__:'$(abspath $(DATADIR))':g' $$file > temp_file && \
|
||||||
mv temp_file $$file ;\
|
mv temp_file $$file ;\
|
||||||
gzip -f -9 $$file ;\
|
gzip -f -n -9 $$file ;\
|
||||||
done
|
done
|
||||||
|
|
||||||
.PHONY: install
|
.PHONY: install
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
'\" t
|
'\" t
|
||||||
.\" Title: toxic.conf
|
.\" Title: toxic.conf
|
||||||
.\" Author: [see the "AUTHORS" section]
|
.\" Author: [see the "AUTHORS" section]
|
||||||
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
|
||||||
.\" Date: 2016-07-21
|
.\" Date: 2016-09-20
|
||||||
.\" Manual: Toxic Manual
|
.\" Manual: Toxic Manual
|
||||||
.\" Source: toxic __VERSION__
|
.\" Source: toxic __VERSION__
|
||||||
.\" Language: English
|
.\" Language: English
|
||||||
.\"
|
.\"
|
||||||
.TH "TOXIC\&.CONF" "5" "2016\-07\-21" "toxic __VERSION__" "Toxic Manual"
|
.TH "TOXIC\&.CONF" "5" "2016\-09\-20" "toxic __VERSION__" "Toxic Manual"
|
||||||
.\" -----------------------------------------------------------------
|
.\" -----------------------------------------------------------------
|
||||||
.\" * Define some portability stuff
|
.\" * Define some portability stuff
|
||||||
.\" -----------------------------------------------------------------
|
.\" -----------------------------------------------------------------
|
||||||
@ -227,6 +227,11 @@ Default path for downloads\&. String value\&. Absolute path for downloaded files
|
|||||||
Path for your avatar (file must be a \&.png and cannot exceed 16\&.3 KiB)
|
Path for your avatar (file must be a \&.png and cannot exceed 16\&.3 KiB)
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
|
\fBautorun_path\fR
|
||||||
|
.RS 4
|
||||||
|
Path for any scripts that should be run on startup
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
\fBchatlogs_path\fR
|
\fBchatlogs_path\fR
|
||||||
.RS 4
|
.RS 4
|
||||||
Default path for chatlogs\&. String value\&. Absolute path for chatlog files\&.
|
Default path for chatlogs\&. String value\&. Absolute path for chatlog files\&.
|
||||||
|
@ -143,6 +143,9 @@ OPTIONS
|
|||||||
*avatar_path*;;
|
*avatar_path*;;
|
||||||
Path for your avatar (file must be a .png and cannot exceed 16.3 KiB)
|
Path for your avatar (file must be a .png and cannot exceed 16.3 KiB)
|
||||||
|
|
||||||
|
*autorun_path*;;
|
||||||
|
Path for any scripts that should be run on startup
|
||||||
|
|
||||||
*chatlogs_path*;;
|
*chatlogs_path*;;
|
||||||
Default path for chatlogs. String value. Absolute path for chatlog files.
|
Default path for chatlogs. String value. Absolute path for chatlog files.
|
||||||
|
|
||||||
|
@ -87,6 +87,9 @@ tox = {
|
|||||||
// Path for your avatar (file must be a .png and cannot exceed 64 KiB)
|
// Path for your avatar (file must be a .png and cannot exceed 64 KiB)
|
||||||
// avatar_path="/home/USERNAME/Pictures/youravatar.png";
|
// avatar_path="/home/USERNAME/Pictures/youravatar.png";
|
||||||
|
|
||||||
|
// Path for scripts that should be run on startup
|
||||||
|
// autorun_path="/home/USERNAME/toxic_scripts/";
|
||||||
|
|
||||||
// Path for chatlogs
|
// Path for chatlogs
|
||||||
// chatlogs_path="/home/USERNAME/toxic_chatlogs/";
|
// chatlogs_path="/home/USERNAME/toxic_chatlogs/";
|
||||||
};
|
};
|
||||||
@ -118,4 +121,3 @@ keys = {
|
|||||||
toggle_peerlist="Ctrl+b";
|
toggle_peerlist="Ctrl+b";
|
||||||
toggle_paste_mode="Ctrl+T";
|
toggle_paste_mode="Ctrl+T";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
210
src/api.c
Normal file
210
src/api.c
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
/* 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"
|
||||||
|
#endif /* PYTHON */
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
42
src/api.h
Normal file
42
src/api.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/* 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);
|
||||||
|
|
||||||
|
#endif /* #define API_H */
|
136
src/audio_call.c
136
src/audio_call.c
@ -61,7 +61,7 @@ extern FriendsList Friends;
|
|||||||
|
|
||||||
#define frame_size (CallControl.audio_sample_rate * CallControl.audio_frame_duration / 1000)
|
#define frame_size (CallControl.audio_sample_rate * CallControl.audio_frame_duration / 1000)
|
||||||
|
|
||||||
static int set_call(Call* call, bool start)
|
static int set_call(Call *call, bool start)
|
||||||
{
|
{
|
||||||
call->in_idx = -1;
|
call->in_idx = -1;
|
||||||
call->out_idx = -1;
|
call->out_idx = -1;
|
||||||
@ -75,17 +75,18 @@ static int set_call(Call* call, bool start)
|
|||||||
|
|
||||||
if ( pthread_mutex_init(&call->mutex, NULL) != 0 )
|
if ( pthread_mutex_init(&call->mutex, NULL) != 0 )
|
||||||
return -1;
|
return -1;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
call->ttid = 0;
|
call->ttid = 0;
|
||||||
|
|
||||||
if ( pthread_mutex_destroy(&call->mutex) != 0 )
|
if ( pthread_mutex_destroy(&call->mutex) != 0 )
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void call_cb ( ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data );
|
void call_cb ( ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled,
|
||||||
|
void *user_data );
|
||||||
void callstate_cb ( ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data );
|
void callstate_cb ( ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data );
|
||||||
void receive_audio_frame_cb ( ToxAV *av, uint32_t friend_number, int16_t const *pcm, size_t sample_count,
|
void receive_audio_frame_cb ( ToxAV *av, uint32_t friend_number, int16_t const *pcm, size_t sample_count,
|
||||||
uint8_t channels, uint32_t sampling_rate, void *user_data );
|
uint8_t channels, uint32_t sampling_rate, void *user_data );
|
||||||
@ -103,7 +104,7 @@ void callback_call_canceled ( uint32_t friend_number );
|
|||||||
void callback_call_rejected ( uint32_t friend_number );
|
void callback_call_rejected ( uint32_t friend_number );
|
||||||
void callback_call_ended ( uint32_t friend_number );
|
void callback_call_ended ( uint32_t friend_number );
|
||||||
|
|
||||||
void write_device_callback( uint32_t friend_number, const int16_t* PCM, uint16_t sample_count, uint8_t channels,
|
void write_device_callback( uint32_t friend_number, const int16_t *PCM, uint16_t sample_count, uint8_t channels,
|
||||||
uint32_t sample_rate );
|
uint32_t sample_rate );
|
||||||
|
|
||||||
static void print_err (ToxWindow *self, const char *error_str)
|
static void print_err (ToxWindow *self, const char *error_str)
|
||||||
@ -158,6 +159,7 @@ ToxAV *init_audio(ToxWindow *self, Tox *tox)
|
|||||||
void terminate_audio()
|
void terminate_audio()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_CALLS; ++i)
|
for (i = 0; i < MAX_CALLS; ++i)
|
||||||
stop_transmission(&CallControl.calls[i], i);
|
stop_transmission(&CallControl.calls[i], i);
|
||||||
|
|
||||||
@ -167,7 +169,7 @@ void terminate_audio()
|
|||||||
terminate_devices();
|
terminate_devices();
|
||||||
}
|
}
|
||||||
|
|
||||||
void read_device_callback(const int16_t* captured, uint32_t size, void* data)
|
void read_device_callback(const int16_t *captured, uint32_t size, void *data)
|
||||||
{
|
{
|
||||||
TOXAV_ERR_SEND_FRAME error;
|
TOXAV_ERR_SEND_FRAME error;
|
||||||
uint32_t friend_number = *((uint32_t *)data); /* TODO: Or pass an array of call_idx's */
|
uint32_t friend_number = *((uint32_t *)data); /* TODO: Or pass an array of call_idx's */
|
||||||
@ -175,13 +177,13 @@ void read_device_callback(const int16_t* captured, uint32_t size, void* data)
|
|||||||
((int64_t) CallControl.audio_frame_duration) / 1000;
|
((int64_t) CallControl.audio_frame_duration) / 1000;
|
||||||
|
|
||||||
if ( sample_count <= 0 || toxav_audio_send_frame(CallControl.av, friend_number,
|
if ( sample_count <= 0 || toxav_audio_send_frame(CallControl.av, friend_number,
|
||||||
captured, sample_count,
|
captured, sample_count,
|
||||||
CallControl.audio_channels,
|
CallControl.audio_channels,
|
||||||
CallControl.audio_sample_rate, &error) == false )
|
CallControl.audio_sample_rate, &error) == false ) {
|
||||||
{}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_device_callback(uint32_t friend_number, const int16_t* PCM, uint16_t sample_count, uint8_t channels,
|
void write_device_callback(uint32_t friend_number, const int16_t *PCM, uint16_t sample_count, uint8_t channels,
|
||||||
uint32_t sample_rate)
|
uint32_t sample_rate)
|
||||||
{
|
{
|
||||||
if ( CallControl.calls[friend_number].ttas )
|
if ( CallControl.calls[friend_number].ttas )
|
||||||
@ -199,7 +201,7 @@ int start_transmission(ToxWindow *self, Call *call)
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
DeviceError error = open_primary_device(input, &call->in_idx,
|
DeviceError error = open_primary_device(input, &call->in_idx,
|
||||||
CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels);
|
CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels);
|
||||||
|
|
||||||
if ( error != de_None ) {
|
if ( error != de_None ) {
|
||||||
if ( error == de_FailedStart)
|
if ( error == de_FailedStart)
|
||||||
@ -210,12 +212,12 @@ int start_transmission(ToxWindow *self, Call *call)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( register_device_callback(self->num, call->in_idx,
|
if ( register_device_callback(self->num, call->in_idx,
|
||||||
read_device_callback, &self->num, true) != de_None)
|
read_device_callback, &self->num, true) != de_None)
|
||||||
/* Set VAD as true for all; TODO: Make it more dynamic */
|
/* Set VAD as true for all; TODO: Make it more dynamic */
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to register input handler!");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to register input handler!");
|
||||||
|
|
||||||
if ( open_primary_device(output, &call->out_idx,
|
if ( open_primary_device(output, &call->out_idx,
|
||||||
CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels) != de_None ) {
|
CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels) != de_None ) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open output device!");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open output device!");
|
||||||
call->has_output = 0;
|
call->has_output = 0;
|
||||||
}
|
}
|
||||||
@ -286,7 +288,8 @@ void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_
|
|||||||
callback_call_ended(friend_number);
|
callback_call_ended(friend_number);
|
||||||
CallControl.pending_call = false;
|
CallControl.pending_call = false;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ( TOXAV_FRIEND_CALL_STATE_FINISHED ):
|
case ( TOXAV_FRIEND_CALL_STATE_FINISHED ):
|
||||||
if ( CallControl.pending_call )
|
if ( CallControl.pending_call )
|
||||||
callback_call_rejected(friend_number);
|
callback_call_rejected(friend_number);
|
||||||
@ -304,7 +307,8 @@ void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_
|
|||||||
CallControl.call_state = 0;
|
CallControl.call_state = 0;
|
||||||
CallControl.pending_call = false;
|
CallControl.pending_call = false;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if ( CallControl.pending_call ) {
|
if ( CallControl.pending_call ) {
|
||||||
/* Start answered call */
|
/* Start answered call */
|
||||||
@ -313,6 +317,7 @@ void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
|
|
||||||
/* Handle receiving client video call states */
|
/* Handle receiving client video call states */
|
||||||
if ( state & TOXAV_FRIEND_CALL_STATE_SENDING_V )
|
if ( state & TOXAV_FRIEND_CALL_STATE_SENDING_V )
|
||||||
callback_recv_video_starting(friend_number);
|
callback_recv_video_starting(friend_number);
|
||||||
@ -322,13 +327,13 @@ void callstate_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_
|
|||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void receive_audio_frame_cb(ToxAV *av, uint32_t friend_number,
|
void receive_audio_frame_cb(ToxAV *av, uint32_t friend_number,
|
||||||
int16_t const *pcm, size_t sample_count,
|
int16_t const *pcm, size_t sample_count,
|
||||||
uint8_t channels, uint32_t sampling_rate, void *user_data)
|
uint8_t channels, uint32_t sampling_rate, void *user_data)
|
||||||
{
|
{
|
||||||
write_device_callback(friend_number, pcm, sample_count, channels, sampling_rate);
|
write_device_callback(friend_number, pcm, sample_count, channels, sampling_rate);
|
||||||
}
|
}
|
||||||
@ -337,6 +342,7 @@ void audio_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_
|
|||||||
uint32_t video_bit_rate, void *user_data)
|
uint32_t video_bit_rate, void *user_data)
|
||||||
{
|
{
|
||||||
CallControl.audio_bit_rate = audio_bit_rate;
|
CallControl.audio_bit_rate = audio_bit_rate;
|
||||||
|
toxav_bit_rate_set(av, friend_number, audio_bit_rate, video_bit_rate, user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void callback_recv_invite(Tox *m, uint32_t friend_number)
|
void callback_recv_invite(Tox *m, uint32_t friend_number)
|
||||||
@ -373,14 +379,16 @@ void callback_recv_ringing(uint32_t friend_number)
|
|||||||
}
|
}
|
||||||
void callback_recv_starting(uint32_t friend_number)
|
void callback_recv_starting(uint32_t friend_number)
|
||||||
{
|
{
|
||||||
ToxWindow* windows = CallControl.prompt;
|
ToxWindow *windows = CallControl.prompt;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if ( windows[i].onStarting != NULL && windows[i].num == friend_number ) {
|
if ( windows[i].onStarting != NULL && windows[i].num == friend_number ) {
|
||||||
windows[i].onStarting(&windows[i], CallControl.av, friend_number, CallControl.call_state);
|
windows[i].onStarting(&windows[i], CallControl.av, friend_number, CallControl.call_state);
|
||||||
|
|
||||||
if ( 0 != start_transmission(&windows[i], &CallControl.calls[friend_number]) ) /* YEAH! */
|
if ( 0 != start_transmission(&windows[i], &CallControl.calls[friend_number]) ) /* YEAH! */
|
||||||
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0 , "Error starting transmission!");
|
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -399,12 +407,14 @@ void callback_recv_ending(uint32_t friend_number)
|
|||||||
}
|
}
|
||||||
void callback_call_started(uint32_t friend_number)
|
void callback_call_started(uint32_t friend_number)
|
||||||
{
|
{
|
||||||
ToxWindow* windows = CallControl.prompt;
|
ToxWindow *windows = CallControl.prompt;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i)
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i)
|
||||||
if ( windows[i].onStart != NULL && windows[i].num == friend_number ) {
|
if ( windows[i].onStart != NULL && windows[i].num == friend_number ) {
|
||||||
windows[i].onStart(&windows[i], CallControl.av, friend_number, CallControl.call_state);
|
windows[i].onStart(&windows[i], CallControl.av, friend_number, CallControl.call_state);
|
||||||
|
|
||||||
if ( 0 != start_transmission(&windows[i], &CallControl.calls[friend_number]) ) {/* YEAH! */
|
if ( 0 != start_transmission(&windows[i], &CallControl.calls[friend_number]) ) {/* YEAH! */
|
||||||
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!");
|
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!");
|
||||||
return;
|
return;
|
||||||
@ -479,6 +489,7 @@ void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
|||||||
}
|
}
|
||||||
|
|
||||||
toxav_call(CallControl.av, self->num, CallControl.audio_bit_rate, CallControl.video_bit_rate, &error);
|
toxav_call(CallControl.av, self->num, CallControl.audio_bit_rate, CallControl.video_bit_rate, &error);
|
||||||
|
|
||||||
if ( error != TOXAV_ERR_CALL_OK ) {
|
if ( error != TOXAV_ERR_CALL_OK ) {
|
||||||
if ( error == TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL ) error_str = "Already in a call!";
|
if ( error == TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL ) error_str = "Already in a call!";
|
||||||
else if ( error == TOXAV_ERR_CALL_MALLOC ) error_str = "Memory allocation issue";
|
else if ( error == TOXAV_ERR_CALL_MALLOC ) error_str = "Memory allocation issue";
|
||||||
@ -518,6 +529,7 @@ void cmd_answer(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
|||||||
}
|
}
|
||||||
|
|
||||||
toxav_answer(CallControl.av, self->num, CallControl.audio_bit_rate, CallControl.video_bit_rate, &error);
|
toxav_answer(CallControl.av, self->num, CallControl.audio_bit_rate, CallControl.video_bit_rate, &error);
|
||||||
|
|
||||||
if ( error != TOXAV_ERR_ANSWER_OK ) {
|
if ( error != TOXAV_ERR_ANSWER_OK ) {
|
||||||
if ( error == TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING ) error_str = "No incoming call!";
|
if ( error == TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING ) error_str = "No incoming call!";
|
||||||
else if ( error == TOXAV_ERR_ANSWER_CODEC_INITIALIZATION ) error_str = "Failed to initialize codecs!";
|
else if ( error == TOXAV_ERR_ANSWER_CODEC_INITIALIZATION ) error_str = "Failed to initialize codecs!";
|
||||||
@ -621,6 +633,9 @@ void cmd_list_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Refresh device list.
|
||||||
|
get_devices_names();
|
||||||
|
|
||||||
print_devices(self, type);
|
print_devices(self, type);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -664,7 +679,7 @@ void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( set_primary_device(type, selection) == de_InvalidSelection ) {
|
if ( set_primary_device(type, selection) == de_InvalidSelection ) {
|
||||||
error_str="Invalid selection!";
|
error_str = "Invalid selection!";
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -708,13 +723,14 @@ void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( selection_valid(type, selection) == de_InvalidSelection ) {
|
if ( selection_valid(type, selection) == de_InvalidSelection ) {
|
||||||
error_str="Invalid selection!";
|
error_str = "Invalid selection!";
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If call is active, change device */
|
/* If call is active, change device */
|
||||||
if ( self->is_call ) {
|
if ( self->is_call ) {
|
||||||
Call* this_call = &CallControl.calls[self->num];
|
Call *this_call = &CallControl.calls[self->num];
|
||||||
|
|
||||||
if ( this_call->ttas ) {
|
if ( this_call->ttas ) {
|
||||||
|
|
||||||
|
|
||||||
@ -722,15 +738,14 @@ void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
|
|||||||
pthread_mutex_lock(&this_call->mutex);
|
pthread_mutex_lock(&this_call->mutex);
|
||||||
close_device(output, this_call->out_idx);
|
close_device(output, this_call->out_idx);
|
||||||
this_call->has_output = open_device(output, selection, &this_call->out_idx,
|
this_call->has_output = open_device(output, selection, &this_call->out_idx,
|
||||||
CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels)
|
CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels)
|
||||||
== de_None ? 1 : 0;
|
== de_None ? 1 : 0;
|
||||||
pthread_mutex_unlock(&this_call->mutex);
|
pthread_mutex_unlock(&this_call->mutex);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
/* TODO: check for failure */
|
/* TODO: check for failure */
|
||||||
close_device(input, this_call->in_idx);
|
close_device(input, this_call->in_idx);
|
||||||
open_device(input, selection, &this_call->in_idx, CallControl.audio_sample_rate,
|
open_device(input, selection, &this_call->in_idx, CallControl.audio_sample_rate,
|
||||||
CallControl.audio_frame_duration, CallControl.audio_channels);
|
CallControl.audio_frame_duration, CallControl.audio_channels);
|
||||||
/* Set VAD as true for all; TODO: Make it more dynamic */
|
/* Set VAD as true for all; TODO: Make it more dynamic */
|
||||||
register_device_callback(self->num, this_call->in_idx, read_device_callback, &self->num, true);
|
register_device_callback(self->num, this_call->in_idx, read_device_callback, &self->num, true);
|
||||||
}
|
}
|
||||||
@ -740,7 +755,7 @@ void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
|
|||||||
self->device_selection[type] = selection;
|
self->device_selection[type] = selection;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
on_error:
|
on_error:
|
||||||
print_err (self, error_str);
|
print_err (self, error_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -771,9 +786,10 @@ void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
|||||||
|
|
||||||
/* If call is active, use this_call values */
|
/* If call is active, use this_call values */
|
||||||
if ( self->is_call ) {
|
if ( self->is_call ) {
|
||||||
Call* this_call = &CallControl.calls[self->num];
|
Call *this_call = &CallControl.calls[self->num];
|
||||||
|
|
||||||
pthread_mutex_lock(&this_call->mutex);
|
pthread_mutex_lock(&this_call->mutex);
|
||||||
|
|
||||||
if ( type == input ) {
|
if ( type == input ) {
|
||||||
device_mute(type, this_call->in_idx);
|
device_mute(type, this_call->in_idx);
|
||||||
self->chatwin->infobox.in_is_muted ^= 1;
|
self->chatwin->infobox.in_is_muted ^= 1;
|
||||||
@ -781,12 +797,13 @@ void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
|||||||
device_mute(type, this_call->out_idx);
|
device_mute(type, this_call->out_idx);
|
||||||
self->chatwin->infobox.out_is_muted ^= 1;
|
self->chatwin->infobox.out_is_muted ^= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&this_call->mutex);
|
pthread_mutex_unlock(&this_call->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
on_error:
|
on_error:
|
||||||
print_err (self, error_str);
|
print_err (self, error_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -821,8 +838,57 @@ on_error:
|
|||||||
print_err (self, error_str);
|
print_err (self, error_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cmd_bitrate(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
|
{
|
||||||
|
char *error_str;
|
||||||
|
|
||||||
void stop_current_call(ToxWindow* self)
|
if ( argc != 1 ) {
|
||||||
|
error_str = "Must have value!";
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( self->is_call == false ) {
|
||||||
|
error_str = "Must be in a call";
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t bitrate = strtol(argv[1], NULL, 10);
|
||||||
|
|
||||||
|
TOXAV_ERR_BIT_RATE_SET error;
|
||||||
|
audio_bit_rate_status_cb(CallControl.av, self->num, bitrate, -1, &error);
|
||||||
|
|
||||||
|
if (error != TOXAV_ERR_BIT_RATE_SET_OK) {
|
||||||
|
switch (error) {
|
||||||
|
case TOXAV_ERR_BIT_RATE_SET_SYNC:
|
||||||
|
error_str = "Syncronization error occured";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOXAV_ERR_BIT_RATE_SET_INVALID_AUDIO_BIT_RATE:
|
||||||
|
error_str = "Invalid audio bit rate value (valid is 6-510)";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_FOUND:
|
||||||
|
error_str = "Friend not found";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_IN_CALL:
|
||||||
|
error_str = "Friend is not in the call";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
error_str = "Unknown error";
|
||||||
|
}
|
||||||
|
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
on_error:
|
||||||
|
print_err (self, error_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop_current_call(ToxWindow *self)
|
||||||
{
|
{
|
||||||
if ( CallControl.pending_call ) {
|
if ( CallControl.pending_call ) {
|
||||||
toxav_call_control(CallControl.av, self->num, TOXAV_CALL_CONTROL_CANCEL, NULL);
|
toxav_call_control(CallControl.av, self->num, TOXAV_CALL_CONTROL_CANCEL, NULL);
|
||||||
|
@ -56,7 +56,7 @@ typedef struct Device {
|
|||||||
ALCdevice *dhndl; /* Handle of device selected/opened */
|
ALCdevice *dhndl; /* Handle of device selected/opened */
|
||||||
ALCcontext *ctx; /* Device context */
|
ALCcontext *ctx; /* Device context */
|
||||||
DataHandleCallback cb; /* Use this to handle data from input device usually */
|
DataHandleCallback cb; /* Use this to handle data from input device usually */
|
||||||
void* cb_data; /* Data to be passed to callback */
|
void *cb_data; /* Data to be passed to callback */
|
||||||
int32_t friend_number; /* ToxAV friend number */
|
int32_t friend_number; /* ToxAV friend number */
|
||||||
|
|
||||||
uint32_t source, buffers[OPENAL_BUFS]; /* Playback source/buffers */
|
uint32_t source, buffers[OPENAL_BUFS]; /* Playback source/buffers */
|
||||||
@ -80,7 +80,7 @@ Device *running[2][MAX_DEVICES] = {{NULL}}; /* Running devices */
|
|||||||
uint32_t primary_device[2]; /* Primary device */
|
uint32_t primary_device[2]; /* Primary device */
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
static ToxAV* av = NULL;
|
static ToxAV *av = NULL;
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
/* q_mutex */
|
/* q_mutex */
|
||||||
@ -90,47 +90,24 @@ pthread_mutex_t mutex;
|
|||||||
|
|
||||||
|
|
||||||
bool thread_running = true,
|
bool thread_running = true,
|
||||||
thread_paused = true; /* Thread control */
|
thread_paused = true; /* Thread control */
|
||||||
|
|
||||||
void* thread_poll(void*);
|
void *thread_poll(void *);
|
||||||
/* Meet devices */
|
/* Meet devices */
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
DeviceError init_devices(ToxAV* av_)
|
DeviceError init_devices(ToxAV *av_)
|
||||||
#else
|
#else
|
||||||
DeviceError init_devices()
|
DeviceError init_devices()
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
{
|
{
|
||||||
const char *stringed_device_list;
|
get_devices_names();
|
||||||
|
|
||||||
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
|
// Start poll thread
|
||||||
if (pthread_mutex_init(&mutex, NULL) != 0)
|
if (pthread_mutex_init(&mutex, NULL) != 0)
|
||||||
return de_InternalError;
|
return de_InternalError;
|
||||||
|
|
||||||
pthread_t thread_id;
|
pthread_t thread_id;
|
||||||
|
|
||||||
if ( pthread_create(&thread_id, NULL, thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0)
|
if ( pthread_create(&thread_id, NULL, thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0)
|
||||||
return de_InternalError;
|
return de_InternalError;
|
||||||
|
|
||||||
@ -156,12 +133,45 @@ DeviceError terminate_devices()
|
|||||||
return (DeviceError) de_None;
|
return (DeviceError) de_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DeviceError device_mute(DeviceType type, uint32_t device_idx)
|
DeviceError device_mute(DeviceType type, uint32_t device_idx)
|
||||||
{
|
{
|
||||||
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
|
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
|
||||||
|
|
||||||
lock;
|
lock;
|
||||||
|
|
||||||
Device* device = running[type][device_idx];
|
Device *device = running[type][device_idx];
|
||||||
|
|
||||||
if (!device) {
|
if (!device) {
|
||||||
unlock;
|
unlock;
|
||||||
@ -178,9 +188,10 @@ DeviceError device_mute(DeviceType type, uint32_t device_idx)
|
|||||||
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
|
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
|
||||||
{
|
{
|
||||||
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
|
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
|
||||||
|
|
||||||
lock;
|
lock;
|
||||||
|
|
||||||
Device* device = running[input][device_idx];
|
Device *device = running[input][device_idx];
|
||||||
|
|
||||||
if (!device) {
|
if (!device) {
|
||||||
unlock;
|
unlock;
|
||||||
@ -198,12 +209,14 @@ DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
|
|||||||
DeviceError set_primary_device(DeviceType type, int32_t selection)
|
DeviceError set_primary_device(DeviceType type, int32_t selection)
|
||||||
{
|
{
|
||||||
if (size[type] <= selection || selection < 0) return de_InvalidSelection;
|
if (size[type] <= selection || selection < 0) return de_InvalidSelection;
|
||||||
|
|
||||||
primary_device[type] = selection;
|
primary_device[type] = selection;
|
||||||
|
|
||||||
return de_None;
|
return de_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceError open_primary_device(DeviceType type, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels)
|
DeviceError open_primary_device(DeviceType type, uint32_t *device_idx, uint32_t sample_rate, uint32_t frame_duration,
|
||||||
|
uint8_t channels)
|
||||||
{
|
{
|
||||||
return open_device(type, primary_device[type], device_idx, sample_rate, frame_duration, channels);
|
return open_device(type, primary_device[type], device_idx, sample_rate, frame_duration, channels);
|
||||||
}
|
}
|
||||||
@ -214,7 +227,8 @@ void get_primary_device_name(DeviceType type, char *buf, int size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: generate buffers separately
|
// TODO: generate buffers separately
|
||||||
DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels)
|
DeviceError open_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;
|
||||||
|
|
||||||
@ -225,10 +239,13 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
|
|||||||
const uint32_t frame_size = (sample_rate * frame_duration / 1000);
|
const uint32_t frame_size = (sample_rate * frame_duration / 1000);
|
||||||
|
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_DEVICES && running[type][i] != NULL; ++i);
|
for (i = 0; i < MAX_DEVICES && running[type][i] != NULL; ++i);
|
||||||
|
|
||||||
if (i == MAX_DEVICES) { unlock; return de_AllDevicesBusy; }
|
if (i == MAX_DEVICES) {
|
||||||
else *device_idx = i;
|
unlock;
|
||||||
|
return de_AllDevicesBusy;
|
||||||
|
} else *device_idx = i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_DEVICES; i ++) { /* Check if any device has the same selection */
|
for (i = 0; i < MAX_DEVICES; i ++) { /* Check if any device has the same selection */
|
||||||
if ( running[type][i] && running[type][i]->selection == selection ) {
|
if ( running[type][i] && running[type][i]->selection == selection ) {
|
||||||
@ -242,7 +259,7 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Device* device = running[type][*device_idx] = calloc(1, sizeof(Device));
|
Device *device = running[type][*device_idx] = calloc(1, sizeof(Device));
|
||||||
device->selection = selection;
|
device->selection = selection;
|
||||||
|
|
||||||
device->sample_rate = sample_rate;
|
device->sample_rate = sample_rate;
|
||||||
@ -258,12 +275,12 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
|
|||||||
if (type == input) {
|
if (type == input) {
|
||||||
device->dhndl = alcCaptureOpenDevice(devices_names[type][selection],
|
device->dhndl = alcCaptureOpenDevice(devices_names[type][selection],
|
||||||
sample_rate, device->sound_mode, frame_size * 2);
|
sample_rate, device->sound_mode, frame_size * 2);
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
device->VAD_treshold = user_settings->VAD_treshold;
|
device->VAD_treshold = user_settings->VAD_treshold;
|
||||||
#endif
|
#endif
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
device->dhndl = alcOpenDevice(devices_names[type][selection]);
|
device->dhndl = alcOpenDevice(devices_names[type][selection]);
|
||||||
|
|
||||||
if ( !device->dhndl ) {
|
if ( !device->dhndl ) {
|
||||||
free(device);
|
free(device);
|
||||||
running[type][*device_idx] = NULL;
|
running[type][*device_idx] = NULL;
|
||||||
@ -279,10 +296,10 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
|
|||||||
alSourcei(device->source, AL_LOOPING, AL_FALSE);
|
alSourcei(device->source, AL_LOOPING, AL_FALSE);
|
||||||
|
|
||||||
uint16_t zeros[frame_size];
|
uint16_t zeros[frame_size];
|
||||||
memset(zeros, 0, frame_size*2);
|
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);
|
alBufferData(device->buffers[i], device->sound_mode, zeros, frame_size * 2, sample_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
alSourceQueueBuffers(device->source, OPENAL_BUFS, device->buffers);
|
alSourceQueueBuffers(device->source, OPENAL_BUFS, device->buffers);
|
||||||
@ -310,7 +327,7 @@ DeviceError close_device(DeviceType type, uint32_t device_idx)
|
|||||||
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
|
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
|
||||||
|
|
||||||
lock;
|
lock;
|
||||||
Device* device = running[type][device_idx];
|
Device *device = running[type][device_idx];
|
||||||
DeviceError rc = de_None;
|
DeviceError rc = de_None;
|
||||||
|
|
||||||
if (!device) {
|
if (!device) {
|
||||||
@ -323,27 +340,28 @@ DeviceError close_device(DeviceType type, uint32_t device_idx)
|
|||||||
if ( !device->ref_count ) {
|
if ( !device->ref_count ) {
|
||||||
if (type == input) {
|
if (type == input) {
|
||||||
if ( !alcCaptureCloseDevice(device->dhndl) ) rc = de_AlError;
|
if ( !alcCaptureCloseDevice(device->dhndl) ) rc = de_AlError;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (alcGetCurrentContext() != device->ctx) alcMakeContextCurrent(device->ctx);
|
if (alcGetCurrentContext() != device->ctx) alcMakeContextCurrent(device->ctx);
|
||||||
|
|
||||||
alDeleteSources(1, &device->source);
|
alDeleteSources(1, &device->source);
|
||||||
alDeleteBuffers(OPENAL_BUFS, device->buffers);
|
alDeleteBuffers(OPENAL_BUFS, device->buffers);
|
||||||
|
|
||||||
alcMakeContextCurrent(NULL);
|
alcMakeContextCurrent(NULL);
|
||||||
|
|
||||||
if ( device->ctx ) alcDestroyContext(device->ctx);
|
if ( device->ctx ) alcDestroyContext(device->ctx);
|
||||||
|
|
||||||
if ( !alcCloseDevice(device->dhndl) ) rc = de_AlError;
|
if ( !alcCloseDevice(device->dhndl) ) rc = de_AlError;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(device);
|
free(device);
|
||||||
}
|
} else device->ref_count--;
|
||||||
else device->ref_count--;
|
|
||||||
|
|
||||||
unlock;
|
unlock;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
return de_InvalidSelection;
|
||||||
@ -358,12 +376,12 @@ DeviceError register_device_callback( int32_t friend_number, uint32_t device_idx
|
|||||||
return de_None;
|
return de_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline__ DeviceError write_out(uint32_t device_idx, const int16_t* data, uint32_t sample_count, uint8_t channels,
|
inline__ DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_t sample_count, uint8_t channels,
|
||||||
uint32_t sample_rate)
|
uint32_t sample_rate)
|
||||||
{
|
{
|
||||||
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
|
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
|
||||||
|
|
||||||
Device* device = running[output][device_idx];
|
Device *device = running[output][device_idx];
|
||||||
|
|
||||||
if (!device || device->muted) return de_DeviceNotActive;
|
if (!device || device->muted) return de_DeviceNotActive;
|
||||||
|
|
||||||
@ -375,33 +393,33 @@ inline__ DeviceError write_out(uint32_t device_idx, const int16_t* data, uint32_
|
|||||||
alGetSourcei(device->source, AL_BUFFERS_PROCESSED, &processed);
|
alGetSourcei(device->source, AL_BUFFERS_PROCESSED, &processed);
|
||||||
alGetSourcei(device->source, AL_BUFFERS_QUEUED, &queued);
|
alGetSourcei(device->source, AL_BUFFERS_QUEUED, &queued);
|
||||||
|
|
||||||
if(processed) {
|
if (processed) {
|
||||||
ALuint bufids[processed];
|
ALuint bufids[processed];
|
||||||
alSourceUnqueueBuffers(device->source, processed, bufids);
|
alSourceUnqueueBuffers(device->source, processed, bufids);
|
||||||
alDeleteBuffers(processed - 1, bufids + 1);
|
alDeleteBuffers(processed - 1, bufids + 1);
|
||||||
bufid = bufids[0];
|
bufid = bufids[0];
|
||||||
}
|
} else if (queued < 16) alGenBuffers(1, &bufid);
|
||||||
else if(queued < 16) alGenBuffers(1, &bufid);
|
|
||||||
else {
|
else {
|
||||||
pthread_mutex_unlock(device->mutex);
|
pthread_mutex_unlock(device->mutex);
|
||||||
return de_Busy;
|
return de_Busy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
alBufferData(bufid, channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, data, sample_count * 2 * channels, sample_rate);
|
alBufferData(bufid, channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, data, sample_count * 2 * channels,
|
||||||
|
sample_rate);
|
||||||
alSourceQueueBuffers(device->source, 1, &bufid);
|
alSourceQueueBuffers(device->source, 1, &bufid);
|
||||||
|
|
||||||
ALint state;
|
ALint state;
|
||||||
alGetSourcei(device->source, AL_SOURCE_STATE, &state);
|
alGetSourcei(device->source, AL_SOURCE_STATE, &state);
|
||||||
|
|
||||||
if(state != AL_PLAYING) alSourcePlay(device->source);
|
if (state != AL_PLAYING) alSourcePlay(device->source);
|
||||||
|
|
||||||
|
|
||||||
pthread_mutex_unlock(device->mutex);
|
pthread_mutex_unlock(device->mutex);
|
||||||
return de_None;
|
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.
|
* NOTE: We only need to poll input devices for data.
|
||||||
@ -411,9 +429,9 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
|
|||||||
int32_t sample = 0;
|
int32_t sample = 0;
|
||||||
|
|
||||||
|
|
||||||
while (1)
|
while (1) {
|
||||||
{
|
|
||||||
lock;
|
lock;
|
||||||
|
|
||||||
if (!thread_running) {
|
if (!thread_running) {
|
||||||
unlock;
|
unlock;
|
||||||
break;
|
break;
|
||||||
@ -422,7 +440,7 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
|
|||||||
bool paused = thread_paused;
|
bool paused = thread_paused;
|
||||||
unlock;
|
unlock;
|
||||||
|
|
||||||
/* Wait for unpause. */
|
/* Wait for unpause. */
|
||||||
if (paused) {
|
if (paused) {
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
}
|
}
|
||||||
@ -430,6 +448,7 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
|
|||||||
else {
|
else {
|
||||||
for (i = 0; i < size[input]; ++i) {
|
for (i = 0; i < size[input]; ++i) {
|
||||||
lock;
|
lock;
|
||||||
|
|
||||||
if (running[input][i] != NULL) {
|
if (running[input][i] != NULL) {
|
||||||
alcGetIntegerv(running[input][i]->dhndl, ALC_CAPTURE_SAMPLES, sizeof(int32_t), &sample);
|
alcGetIntegerv(running[input][i]->dhndl, ALC_CAPTURE_SAMPLES, sizeof(int32_t), &sample);
|
||||||
|
|
||||||
@ -439,7 +458,8 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
|
|||||||
unlock;
|
unlock;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Device* device = running[input][i];
|
|
||||||
|
Device *device = running[input][i];
|
||||||
|
|
||||||
int16_t frame[16000];
|
int16_t frame[16000];
|
||||||
alcCaptureSamples(device->dhndl, frame, f_size);
|
alcCaptureSamples(device->dhndl, frame, f_size);
|
||||||
@ -451,8 +471,10 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
|
|||||||
|
|
||||||
if ( device->cb ) device->cb(frame, f_size, device->cb_data);
|
if ( device->cb ) device->cb(frame, f_size, device->cb_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock;
|
unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
usleep(5000);
|
usleep(5000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -460,12 +482,13 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
|
|||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_devices(ToxWindow* self, DeviceType type)
|
void print_devices(ToxWindow *self, DeviceType type)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < size[type]; ++i)
|
for (i = 0; i < size[type]; ++i) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%d: %s", i, devices_names[type][i]);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, i == primary_device[type] ? 1 : 0, 0, "%d: %s", i, devices_names[type][i]);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -475,7 +498,7 @@ DeviceError selection_valid(DeviceType type, int32_t selection)
|
|||||||
return (size[type] <= selection || selection < 0) ? de_InvalidSelection : de_None;
|
return (size[type] <= selection || selection < 0) ? de_InvalidSelection : de_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* get_device_callback_data(uint32_t device_idx)
|
void *get_device_callback_data(uint32_t device_idx)
|
||||||
{
|
{
|
||||||
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
|
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -52,20 +52,22 @@ typedef enum DeviceError {
|
|||||||
de_AlError = -9,
|
de_AlError = -9,
|
||||||
} DeviceError;
|
} DeviceError;
|
||||||
|
|
||||||
typedef void (*DataHandleCallback) (const int16_t*, uint32_t size, void* data);
|
typedef void (*DataHandleCallback) (const int16_t *, uint32_t size, void *data);
|
||||||
|
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
DeviceError init_devices(ToxAV* av);
|
DeviceError init_devices(ToxAV *av);
|
||||||
#else
|
#else
|
||||||
DeviceError init_devices();
|
DeviceError init_devices();
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
|
void get_devices_names();
|
||||||
DeviceError terminate_devices();
|
DeviceError terminate_devices();
|
||||||
|
|
||||||
/* Callback handles ready data from INPUT device */
|
/* Callback handles ready data from INPUT device */
|
||||||
DeviceError register_device_callback(int32_t friend_number, uint32_t device_idx, DataHandleCallback callback, void* data, bool enable_VAD);
|
DeviceError register_device_callback(int32_t friend_number, uint32_t device_idx, DataHandleCallback callback,
|
||||||
void* get_device_callback_data(uint32_t device_idx);
|
void *data, bool enable_VAD);
|
||||||
|
void *get_device_callback_data(uint32_t device_idx);
|
||||||
|
|
||||||
/* toggle device mute */
|
/* toggle device mute */
|
||||||
DeviceError device_mute(DeviceType type, uint32_t device_idx);
|
DeviceError device_mute(DeviceType type, uint32_t device_idx);
|
||||||
@ -75,16 +77,19 @@ DeviceError device_set_VAD_treshold(uint32_t device_idx, float value);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
DeviceError set_primary_device(DeviceType type, int32_t selection);
|
DeviceError set_primary_device(DeviceType type, int32_t selection);
|
||||||
DeviceError open_primary_device(DeviceType type, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels);
|
DeviceError open_primary_device(DeviceType type, uint32_t *device_idx, uint32_t sample_rate, uint32_t frame_duration,
|
||||||
|
uint8_t channels);
|
||||||
/* Start device */
|
/* Start device */
|
||||||
DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels);
|
DeviceError open_device(DeviceType type, int32_t selection, uint32_t *device_idx, uint32_t sample_rate,
|
||||||
|
uint32_t frame_duration, uint8_t channels);
|
||||||
/* Stop device */
|
/* Stop device */
|
||||||
DeviceError close_device(DeviceType type, uint32_t device_idx);
|
DeviceError close_device(DeviceType type, uint32_t device_idx);
|
||||||
|
|
||||||
/* Write data to device */
|
/* Write data to device */
|
||||||
DeviceError write_out(uint32_t device_idx, const int16_t* data, uint32_t length, uint8_t channels, uint32_t sample_rate);
|
DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_t length, uint8_t channels,
|
||||||
|
uint32_t sample_rate);
|
||||||
|
|
||||||
void print_devices(ToxWindow* self, DeviceType type);
|
void print_devices(ToxWindow *self, DeviceType type);
|
||||||
void get_primary_device_name(DeviceType type, char *buf, int size);
|
void get_primary_device_name(DeviceType type, char *buf, int size);
|
||||||
|
|
||||||
DeviceError selection_valid(DeviceType type, int32_t selection);
|
DeviceError selection_valid(DeviceType type, int32_t selection);
|
||||||
|
@ -25,10 +25,10 @@
|
|||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/dir.h>
|
#include <sys/dir.h>
|
||||||
#else
|
#else
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#endif /* ifdef __APPLE__ */
|
#endif /* ifdef __APPLE__ */
|
||||||
|
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
@ -108,7 +108,11 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
|
|||||||
|
|
||||||
/* TODO: generalize this */
|
/* TODO: generalize this */
|
||||||
bool dir_search = !strncmp(ubuf, "/sendfile", strlen("/sendfile"))
|
bool dir_search = !strncmp(ubuf, "/sendfile", strlen("/sendfile"))
|
||||||
|| !strncmp(ubuf, "/avatar", strlen("/avatar"));
|
|| !strncmp(ubuf, "/avatar", strlen("/avatar"));
|
||||||
|
|
||||||
|
#ifdef PYTHON
|
||||||
|
dir_search = dir_search || !strncmp(ubuf, "/run", strlen("/run"));
|
||||||
|
#endif
|
||||||
|
|
||||||
/* isolate substring from space behind pos to pos */
|
/* isolate substring from space behind pos to pos */
|
||||||
char tmp[MAX_STR_SIZE];
|
char tmp[MAX_STR_SIZE];
|
||||||
@ -185,6 +189,7 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
|
|||||||
int n_endchrs = strlen(endchrs);
|
int n_endchrs = strlen(endchrs);
|
||||||
int strt = ctx->pos - s_len;
|
int strt = ctx->pos - s_len;
|
||||||
int diff = match_len - s_len + n_endchrs;
|
int diff = match_len - s_len + n_endchrs;
|
||||||
|
|
||||||
if (ctx->len + diff >= MAX_STR_SIZE)
|
if (ctx->len + diff >= MAX_STR_SIZE)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -282,13 +287,13 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
|
|||||||
if (dp == NULL)
|
if (dp == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
char dirnames[MAX_DIRS][NAME_MAX];
|
char dirnames[MAX_DIRS][NAME_MAX + 1];
|
||||||
struct dirent *entry;
|
struct dirent *entry;
|
||||||
int dircount = 0;
|
int dircount = 0;
|
||||||
|
|
||||||
while ((entry = readdir(dp)) && dircount < MAX_DIRS) {
|
while ((entry = readdir(dp)) && dircount < MAX_DIRS) {
|
||||||
if (strncmp(entry->d_name, b_name, b_name_len) == 0
|
if (strncmp(entry->d_name, b_name, b_name_len) == 0
|
||||||
&& strcmp(".", entry->d_name) && strcmp("..", entry->d_name)) {
|
&& strcmp(".", entry->d_name) && strcmp("..", entry->d_name)) {
|
||||||
snprintf(dirnames[dircount], sizeof(dirnames[dircount]), "%s", entry->d_name);
|
snprintf(dirnames[dircount], sizeof(dirnames[dircount]), "%s", entry->d_name);
|
||||||
++dircount;
|
++dircount;
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,7 @@ int avatar_send(Tox *m, uint32_t friendnum)
|
|||||||
TOX_ERR_FILE_SEND err;
|
TOX_ERR_FILE_SEND err;
|
||||||
uint32_t filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_AVATAR, (size_t) Avatar.size,
|
uint32_t filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_AVATAR, (size_t) Avatar.size,
|
||||||
NULL, (uint8_t *) Avatar.name, Avatar.name_len, &err);
|
NULL, (uint8_t *) Avatar.name, Avatar.name_len, &err);
|
||||||
|
|
||||||
if (Avatar.size == 0)
|
if (Avatar.size == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -150,6 +151,7 @@ void on_avatar_file_control(Tox *m, struct FileTransfer *ft, TOX_FILE_CONTROL co
|
|||||||
} else if (ft->state == FILE_TRANSFER_PAUSED) {
|
} else if (ft->state == FILE_TRANSFER_PAUSED) {
|
||||||
ft->state = FILE_TRANSFER_STARTED;
|
ft->state = FILE_TRANSFER_STARTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_FILE_CONTROL_PAUSE:
|
case TOX_FILE_CONTROL_PAUSE:
|
||||||
|
@ -251,6 +251,7 @@ static int update_DHT_nodeslist(const char *nodes_path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct Recv_Curl_Data recv_data;
|
struct Recv_Curl_Data recv_data;
|
||||||
|
|
||||||
memset(&recv_data, 0, sizeof(struct Recv_Curl_Data));
|
memset(&recv_data, 0, sizeof(struct Recv_Curl_Data));
|
||||||
|
|
||||||
if (curl_fetch_nodes_JSON(&recv_data) == -1) {
|
if (curl_fetch_nodes_JSON(&recv_data) == -1) {
|
||||||
@ -476,7 +477,7 @@ void *load_nodeslist_thread(void *data)
|
|||||||
/* If nodeslist does not contain any valid entries we set the last_scan value
|
/* If nodeslist does not contain any valid entries we set the last_scan value
|
||||||
* to 0 so that it will fetch a new list the next time this function is called.
|
* to 0 so that it will fetch a new list the next time this function is called.
|
||||||
*/
|
*/
|
||||||
if (idx == 0) {
|
if (Nodes.count == 0) {
|
||||||
const char *s = "{\"last_scan\":0}";
|
const char *s = "{\"last_scan\":0}";
|
||||||
rewind(fp);
|
rewind(fp);
|
||||||
fwrite(s, strlen(s), 1, fp); // Not much we can do if it fails
|
fwrite(s, strlen(s), 1, fp); // Not much we can do if it fails
|
||||||
@ -523,6 +524,7 @@ int load_DHT_nodeslist(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
thread_data.active = true;
|
thread_data.active = true;
|
||||||
|
|
||||||
if (pthread_create(&thread_data.tid, &thread_data.attr, load_nodeslist_thread, NULL) != 0) {
|
if (pthread_create(&thread_data.tid, &thread_data.attr, load_nodeslist_thread, NULL) != 0) {
|
||||||
thread_data.active = false;
|
thread_data.active = false;
|
||||||
return -5;
|
return -5;
|
||||||
|
73
src/chat.c
73
src/chat.c
@ -48,9 +48,9 @@
|
|||||||
#include "message_queue.h"
|
#include "message_queue.h"
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
#include "audio_call.h"
|
#include "audio_call.h"
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
#include "video_call.h"
|
#include "video_call.h"
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
@ -65,8 +65,12 @@ static void init_infobox(ToxWindow *self);
|
|||||||
static void kill_infobox(ToxWindow *self);
|
static void kill_infobox(ToxWindow *self);
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
#ifdef AUDIO
|
#if defined(AUDIO) && defined(PYTHON)
|
||||||
#define AC_NUM_CHAT_COMMANDS 30
|
#define AC_NUM_CHAT_COMMANDS 32
|
||||||
|
#elif AUDIO
|
||||||
|
#define AC_NUM_CHAT_COMMANDS 31
|
||||||
|
#elif PYTHON
|
||||||
|
#define AC_NUM_CHAT_COMMANDS 23
|
||||||
#else
|
#else
|
||||||
#define AC_NUM_CHAT_COMMANDS 22
|
#define AC_NUM_CHAT_COMMANDS 22
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
@ -106,8 +110,15 @@ static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
|
|||||||
{ "/mute" },
|
{ "/mute" },
|
||||||
{ "/sense" },
|
{ "/sense" },
|
||||||
{ "/video" },
|
{ "/video" },
|
||||||
|
{ "/bitrate" },
|
||||||
|
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
|
#ifdef PYTHON
|
||||||
|
|
||||||
|
{ "/run" },
|
||||||
|
|
||||||
|
#endif /* PYTHON */
|
||||||
};
|
};
|
||||||
|
|
||||||
static void set_self_typingstatus(ToxWindow *self, Tox *m, bool is_typing)
|
static void set_self_typingstatus(ToxWindow *self, Tox *m, bool is_typing)
|
||||||
@ -152,7 +163,7 @@ void kill_chat_window(ToxWindow *self, Tox *m)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void recv_message_helper(ToxWindow *self, Tox *m, uint32_t num, const char *msg, size_t len,
|
static void recv_message_helper(ToxWindow *self, Tox *m, uint32_t num, const char *msg, size_t len,
|
||||||
const char *nick, const char *timefrmt)
|
const char *nick, const char *timefrmt)
|
||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
@ -161,10 +172,10 @@ static void recv_message_helper(ToxWindow *self, Tox *m, uint32_t num, const cha
|
|||||||
|
|
||||||
if (self->active_box != -1)
|
if (self->active_box != -1)
|
||||||
box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
|
box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
|
||||||
self->active_box, "%s", msg);
|
self->active_box, "%s", msg);
|
||||||
else
|
else
|
||||||
box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
|
box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
|
||||||
&self->active_box, nick, "%s", msg);
|
&self->active_box, nick, "%s", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void recv_action_helper(ToxWindow *self, Tox *m, uint32_t num, const char *action, size_t len,
|
static void recv_action_helper(ToxWindow *self, Tox *m, uint32_t num, const char *action, size_t len,
|
||||||
@ -177,10 +188,10 @@ static void recv_action_helper(ToxWindow *self, Tox *m, uint32_t num, const char
|
|||||||
|
|
||||||
if (self->active_box != -1)
|
if (self->active_box != -1)
|
||||||
box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
|
box_notify2(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
|
||||||
self->active_box, "* %s %s", nick, action );
|
self->active_box, "* %s %s", nick, action );
|
||||||
else
|
else
|
||||||
box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
|
box_notify(self, generic_message, NT_WNDALERT_1 | NT_NOFOCUS | user_settings->bell_on_message,
|
||||||
&self->active_box, self->name, "* %s %s", nick, action );
|
&self->active_box, self->name, "* %s %s", nick, action );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chat_onMessage(ToxWindow *self, Tox *m, uint32_t num, TOX_MESSAGE_TYPE type, const char *msg, size_t len)
|
static void chat_onMessage(ToxWindow *self, Tox *m, uint32_t num, TOX_MESSAGE_TYPE type, const char *msg, size_t len)
|
||||||
@ -454,7 +465,7 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint
|
|||||||
if (ft->state == FILE_TRANSFER_PENDING) {
|
if (ft->state == FILE_TRANSFER_PENDING) {
|
||||||
ft->state = FILE_TRANSFER_STARTED;
|
ft->state = FILE_TRANSFER_STARTED;
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer [%d] for '%s' accepted.",
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer [%d] for '%s' accepted.",
|
||||||
ft->index, ft->file_name);
|
ft->index, ft->file_name);
|
||||||
char progline[MAX_STR_SIZE];
|
char progline[MAX_STR_SIZE];
|
||||||
init_progress_bar(progline);
|
init_progress_bar(progline);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
|
||||||
@ -466,10 +477,12 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOX_FILE_CONTROL_PAUSE: {
|
case TOX_FILE_CONTROL_PAUSE: {
|
||||||
ft->state = FILE_TRANSFER_PAUSED;
|
ft->state = FILE_TRANSFER_PAUSED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOX_FILE_CONTROL_CANCEL: {
|
case TOX_FILE_CONTROL_CANCEL: {
|
||||||
snprintf(msg, sizeof(msg), "File transfer for '%s' was aborted.", ft->file_name);
|
snprintf(msg, sizeof(msg), "File transfer for '%s' was aborted.", ft->file_name);
|
||||||
close_file_transfer(self, m, ft, -1, msg, notif_error);
|
close_file_transfer(self, m, ft, -1, msg, notif_error);
|
||||||
@ -548,7 +561,7 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_
|
|||||||
bytes_convert_str(sizestr, sizeof(sizestr), file_size);
|
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);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer request for '%s' (%s)", filename, sizestr);
|
||||||
|
|
||||||
char file_path[MAX_STR_SIZE];
|
char file_path[PATH_MAX + name_length + 1];
|
||||||
size_t path_len = name_length;
|
size_t path_len = name_length;
|
||||||
|
|
||||||
/* use specified download path in config if possible */
|
/* use specified download path in config if possible */
|
||||||
@ -601,10 +614,10 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_
|
|||||||
|
|
||||||
if (self->active_box != -1)
|
if (self->active_box != -1)
|
||||||
box_notify2(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS | user_settings->bell_on_filetrans,
|
box_notify2(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS | user_settings->bell_on_filetrans,
|
||||||
self->active_box, "Incoming file: %s", filename );
|
self->active_box, "Incoming file: %s", filename );
|
||||||
else
|
else
|
||||||
box_notify(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS | user_settings->bell_on_filetrans,
|
box_notify(self, transfer_pending, NT_WNDALERT_0 | NT_NOFOCUS | user_settings->bell_on_filetrans,
|
||||||
&self->active_box, self->name, "Incoming file: %s", filename );
|
&self->active_box, self->name, "Incoming file: %s", filename );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, uint8_t type, const char *group_pub_key,
|
static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, uint8_t type, const char *group_pub_key,
|
||||||
@ -671,8 +684,10 @@ void chat_onRinging (ToxWindow *self, ToxAV *av, uint32_t friend_number, int sta
|
|||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ringing...type \"/hangup\" to cancel it.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ringing...type \"/hangup\" to cancel it.");
|
||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
|
|
||||||
if (self->ringing_sound == -1)
|
if (self->ringing_sound == -1)
|
||||||
sound_notify(self, call_outgoing, NT_LOOP, &self->ringing_sound);
|
sound_notify(self, call_outgoing, NT_LOOP, &self->ringing_sound);
|
||||||
|
|
||||||
#endif /* SOUND_NOTIFY */
|
#endif /* SOUND_NOTIFY */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -881,8 +896,8 @@ static void send_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
|
|||||||
char timefrmt[TIME_STR_SIZE];
|
char timefrmt[TIME_STR_SIZE];
|
||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
|
|
||||||
line_info_add(self, timefrmt, selfname, NULL, OUT_ACTION, 0, 0, "%s", action);
|
int 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);
|
cqueue_add(ctx->cqueue, action, strlen(action), OUT_ACTION, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||||
@ -927,11 +942,20 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
diff = dir_match(self, m, ctx->line, L"/sendfile");
|
diff = dir_match(self, m, ctx->line, L"/sendfile");
|
||||||
} else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) {
|
} else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) {
|
||||||
diff = dir_match(self, m, ctx->line, L"/avatar");
|
diff = dir_match(self, m, ctx->line, L"/avatar");
|
||||||
} else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0){
|
}
|
||||||
|
|
||||||
|
#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] = {
|
const char status_cmd_list[3][8] = {
|
||||||
{"online"},
|
{"online"},
|
||||||
{"away"},
|
{"away"},
|
||||||
{"busy"},
|
{"busy"},
|
||||||
};
|
};
|
||||||
diff = complete_line(self, status_cmd_list, 3, 8);
|
diff = complete_line(self, status_cmd_list, 3, 8);
|
||||||
} else {
|
} else {
|
||||||
@ -950,8 +974,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
} else if (key == '\r') {
|
} else if (key == '\r') {
|
||||||
rm_trailing_spaces_buf(ctx);
|
rm_trailing_spaces_buf(ctx);
|
||||||
|
|
||||||
if (!wstring_is_empty(ctx->line))
|
if (!wstring_is_empty(ctx->line)) {
|
||||||
{
|
|
||||||
add_line_to_hist(ctx);
|
add_line_to_hist(ctx);
|
||||||
|
|
||||||
wstrsubst(ctx->line, L'¶', L'\n');
|
wstrsubst(ctx->line, L'¶', L'\n');
|
||||||
@ -980,8 +1003,8 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
char timefrmt[TIME_STR_SIZE];
|
char timefrmt[TIME_STR_SIZE];
|
||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
|
|
||||||
line_info_add(self, timefrmt, selfname, NULL, OUT_MSG, 0, 0, "%s", line);
|
int 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);
|
cqueue_add(ctx->cqueue, line, strlen(line), OUT_MSG, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1029,9 +1052,11 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
case TOX_USER_STATUS_NONE:
|
case TOX_USER_STATUS_NONE:
|
||||||
colour = GREEN;
|
colour = GREEN;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_USER_STATUS_AWAY:
|
case TOX_USER_STATUS_AWAY:
|
||||||
colour = YELLOW;
|
colour = YELLOW;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_USER_STATUS_BUSY:
|
case TOX_USER_STATUS_BUSY:
|
||||||
colour = RED;
|
colour = RED;
|
||||||
break;
|
break;
|
||||||
@ -1107,9 +1132,11 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
wnoutrefresh(self->window);
|
wnoutrefresh(self->window);
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
|
|
||||||
if (ctx->infobox.active) {
|
if (ctx->infobox.active) {
|
||||||
draw_infobox(self);
|
draw_infobox(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (self->help->active)
|
if (self->help->active)
|
||||||
|
@ -92,8 +92,10 @@ void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tox_invite_friend(m, self->num, groupnum) == -1) {
|
TOX_ERR_CONFERENCE_INVITE err;
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to group.");
|
|
||||||
|
if (!tox_conference_invite(m, self->num, groupnum, &err)) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to group (error %d)", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,24 +118,23 @@ void cmd_join_group(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int groupnum = -1;
|
if (type != TOX_CONFERENCE_TYPE_TEXT) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Toxic does not support audio groups.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (type == TOX_GROUPCHAT_TYPE_TEXT)
|
TOX_ERR_CONFERENCE_JOIN err;
|
||||||
groupnum = tox_join_groupchat(m, self->num, (uint8_t *) groupkey, length);
|
|
||||||
/*#ifdef AUDIO
|
|
||||||
else
|
|
||||||
groupnum = toxav_join_av_groupchat(m, self->num, (uint8_t *) groupkey, length,
|
|
||||||
NULL, NULL);
|
|
||||||
#endif*/
|
|
||||||
|
|
||||||
if (groupnum == -1) {
|
uint32_t groupnum = tox_conference_join(m, self->num, (uint8_t *) groupkey, length, &err);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize.");
|
|
||||||
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (init_groupchat_win(prompt, m, groupnum, type) == -1) {
|
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.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
|
||||||
tox_del_groupchat(m, groupnum);
|
tox_conference_delete(m, groupnum, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,6 +191,7 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
on_recv_error:
|
on_recv_error:
|
||||||
|
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND:
|
case TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND:
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend not found.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend not found.");
|
||||||
@ -258,7 +260,7 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
|||||||
|
|
||||||
TOX_ERR_FILE_SEND err;
|
TOX_ERR_FILE_SEND err;
|
||||||
uint32_t filenum = tox_file_send(m, self->num, TOX_FILE_KIND_DATA, (uint64_t) filesize, NULL,
|
uint32_t filenum = tox_file_send(m, self->num, TOX_FILE_KIND_DATA, (uint64_t) filesize, NULL,
|
||||||
(uint8_t *) file_name, namelen, &err);
|
(uint8_t *) file_name, namelen, &err);
|
||||||
|
|
||||||
if (err != TOX_ERR_FILE_SEND_OK)
|
if (err != TOX_ERR_FILE_SEND_OK)
|
||||||
goto on_send_error;
|
goto on_send_error;
|
||||||
@ -282,6 +284,7 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
on_send_error:
|
on_send_error:
|
||||||
|
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND:
|
case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND:
|
||||||
errmsg = "File transfer failed: Invalid friend.";
|
errmsg = "File transfer failed: Invalid friend.";
|
||||||
|
@ -41,6 +41,7 @@ void cmd_cancel(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZ
|
|||||||
void cmd_ccur_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_ccur_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
void cmd_mute(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_mute(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
void cmd_sense(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_sense(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
|
void cmd_bitrate(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
|
#include "api.h"
|
||||||
|
|
||||||
struct cmd_func {
|
struct cmd_func {
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -65,8 +66,11 @@ static struct cmd_func global_commands[] = {
|
|||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
{ "/lsvdev", cmd_list_video_devices },
|
{ "/lsvdev", cmd_list_video_devices },
|
||||||
{ "/svdev" , cmd_change_video_device },
|
{ "/svdev", cmd_change_video_device },
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
|
#ifdef PYTHON
|
||||||
|
{ "/run", cmd_run },
|
||||||
|
#endif /* PYTHON */
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -83,6 +87,7 @@ static struct cmd_func chat_commands[] = {
|
|||||||
{ "/hangup", cmd_hangup },
|
{ "/hangup", cmd_hangup },
|
||||||
{ "/mute", cmd_mute },
|
{ "/mute", cmd_mute },
|
||||||
{ "/sense", cmd_sense },
|
{ "/sense", cmd_sense },
|
||||||
|
{ "/bitrate", cmd_bitrate },
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
{ "/video", cmd_video },
|
{ "/video", cmd_video },
|
||||||
@ -186,11 +191,19 @@ void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode)
|
|||||||
case GROUPCHAT_COMMAND_MODE:
|
case GROUPCHAT_COMMAND_MODE:
|
||||||
if (do_command(w, self, m, num_args, group_commands, args) == 0)
|
if (do_command(w, self, m, num_args, group_commands, args) == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (do_command(w, self, m, num_args, global_commands, args) == 0)
|
if (do_command(w, self, m, num_args, global_commands, args) == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#ifdef PYTHON
|
||||||
|
|
||||||
|
if (do_plugin_command(num_args, args) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid command.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid command.");
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filen
|
|||||||
* Returns NULL on failure.
|
* Returns NULL on failure.
|
||||||
*/
|
*/
|
||||||
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t index,
|
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t index,
|
||||||
FILE_TRANSFER_DIRECTION direction)
|
FILE_TRANSFER_DIRECTION direction)
|
||||||
{
|
{
|
||||||
if (direction != FILE_TRANSFER_RECV && direction != FILE_TRANSFER_SEND)
|
if (direction != FILE_TRANSFER_RECV && direction != FILE_TRANSFER_SEND)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -145,8 +145,8 @@ struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t
|
|||||||
|
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
for (i = 0; i < MAX_FILES; ++i) {
|
||||||
struct FileTransfer *ft = direction == FILE_TRANSFER_SEND ?
|
struct FileTransfer *ft = direction == FILE_TRANSFER_SEND ?
|
||||||
&Friends.list[friendnum].file_sender[i] :
|
&Friends.list[friendnum].file_sender[i] :
|
||||||
&Friends.list[friendnum].file_receiver[i];
|
&Friends.list[friendnum].file_receiver[i];
|
||||||
|
|
||||||
if (ft->state != FILE_TRANSFER_INACTIVE && ft->index == index)
|
if (ft->state != FILE_TRANSFER_INACTIVE && ft->index == index)
|
||||||
return ft;
|
return ft;
|
||||||
|
@ -87,7 +87,7 @@ struct FileTransfer *get_file_transfer_struct(uint32_t friendnum, uint32_t filen
|
|||||||
* Returns NULL on failure.
|
* Returns NULL on failure.
|
||||||
*/
|
*/
|
||||||
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t index,
|
struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnum, uint32_t index,
|
||||||
FILE_TRANSFER_DIRECTION direction);
|
FILE_TRANSFER_DIRECTION direction);
|
||||||
|
|
||||||
/* Initializes an unused file transfer and returns its pointer.
|
/* Initializes an unused file transfer and returns its pointer.
|
||||||
* Returns NULL on failure.
|
* Returns NULL on failure.
|
||||||
|
@ -153,10 +153,14 @@ static int save_blocklist(char *path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Blocked.list[i].active) {
|
if (Blocked.list[i].active) {
|
||||||
|
if (Blocked.list[i].namelength > TOXIC_MAX_NAME_LENGTH) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
BlockedFriend tmp;
|
BlockedFriend tmp;
|
||||||
memset(&tmp, 0, sizeof(BlockedFriend));
|
memset(&tmp, 0, sizeof(BlockedFriend));
|
||||||
tmp.namelength = htons(Blocked.list[i].namelength);
|
tmp.namelength = htons(Blocked.list[i].namelength);
|
||||||
memcpy(tmp.name, Blocked.list[i].name, Blocked.list[i].namelength + 1);
|
memcpy(tmp.name, Blocked.list[i].name, Blocked.list[i].namelength + 1); // Include null byte
|
||||||
memcpy(tmp.pub_key, Blocked.list[i].pub_key, TOX_PUBLIC_KEY_SIZE);
|
memcpy(tmp.pub_key, Blocked.list[i].pub_key, TOX_PUBLIC_KEY_SIZE);
|
||||||
|
|
||||||
uint8_t lastonline[sizeof(uint64_t)];
|
uint8_t lastonline[sizeof(uint64_t)];
|
||||||
@ -250,10 +254,15 @@ int load_blocklist(char *path)
|
|||||||
memset(&Blocked.list[i], 0, sizeof(BlockedFriend));
|
memset(&Blocked.list[i], 0, sizeof(BlockedFriend));
|
||||||
|
|
||||||
memcpy(&tmp, data + i * sizeof(BlockedFriend), 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].active = true;
|
||||||
Blocked.list[i].num = i;
|
Blocked.list[i].num = i;
|
||||||
Blocked.list[i].namelength = MIN(TOXIC_MAX_NAME_LENGTH, ntohs(tmp.namelength));
|
memcpy(Blocked.list[i].name, tmp.name, Blocked.list[i].namelength + 1); // copy null byte
|
||||||
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);
|
memcpy(Blocked.list[i].pub_key, tmp.pub_key, TOX_PUBLIC_KEY_SIZE);
|
||||||
|
|
||||||
uint8_t lastonline[sizeof(uint64_t)];
|
uint8_t lastonline[sizeof(uint64_t)];
|
||||||
@ -317,7 +326,7 @@ static void sort_blocklist_index(void)
|
|||||||
static void update_friend_last_online(uint32_t num, time_t timestamp)
|
static void update_friend_last_online(uint32_t num, time_t timestamp)
|
||||||
{
|
{
|
||||||
Friends.list[num].last_online.last_on = timestamp;
|
Friends.list[num].last_online.last_on = timestamp;
|
||||||
Friends.list[num].last_online.tm = *localtime((const time_t*)×tamp);
|
Friends.list[num].last_online.tm = *localtime((const time_t *)×tamp);
|
||||||
|
|
||||||
/* if the format changes make sure TIME_STR_SIZE is the correct size */
|
/* if the format changes make sure TIME_STR_SIZE is the correct size */
|
||||||
const char *t = user_settings->timestamp_format;
|
const char *t = user_settings->timestamp_format;
|
||||||
@ -538,7 +547,7 @@ static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, uint8
|
|||||||
get_nick_truncate(m, nick, num);
|
get_nick_truncate(m, nick, num);
|
||||||
|
|
||||||
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED,
|
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED,
|
||||||
"* Group chat invite from %s failed: too many windows are open.", nick);
|
"* Group chat invite from %s failed: too many windows are open.", nick);
|
||||||
|
|
||||||
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
|
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
|
||||||
}
|
}
|
||||||
@ -560,6 +569,7 @@ static void select_friend(ToxWindow *self, wint_t key, int *selected, int num)
|
|||||||
static void delete_friend(Tox *m, uint32_t f_num)
|
static void delete_friend(Tox *m, uint32_t f_num)
|
||||||
{
|
{
|
||||||
TOX_ERR_FRIEND_DELETE err;
|
TOX_ERR_FRIEND_DELETE err;
|
||||||
|
|
||||||
if (tox_friend_delete(m, f_num, &err) != true) {
|
if (tox_friend_delete(m, f_num, &err) != true) {
|
||||||
fprintf(stderr, "tox_friend_delete failed with error %d\n", err);
|
fprintf(stderr, "tox_friend_delete failed with error %d\n", err);
|
||||||
return;
|
return;
|
||||||
@ -645,16 +655,18 @@ static void draw_del_popup(void)
|
|||||||
wattron(PendingDelete.popup, A_BOLD);
|
wattron(PendingDelete.popup, A_BOLD);
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
|
|
||||||
if (blocklist_view == 0)
|
if (blocklist_view == 0)
|
||||||
wprintw(PendingDelete.popup, "%s", Friends.list[PendingDelete.num].name);
|
wprintw(PendingDelete.popup, "%s", Friends.list[PendingDelete.num].name);
|
||||||
else
|
else
|
||||||
wprintw(PendingDelete.popup, "%s", Blocked.list[PendingDelete.num].name);
|
wprintw(PendingDelete.popup, "%s", Blocked.list[PendingDelete.num].name);
|
||||||
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
wattroff(PendingDelete.popup, A_BOLD);
|
wattroff(PendingDelete.popup, A_BOLD);
|
||||||
wprintw(PendingDelete.popup, "? y/n");
|
wprintw(PendingDelete.popup, "? y/n");
|
||||||
|
|
||||||
wrefresh(PendingDelete.popup);
|
wnoutrefresh(PendingDelete.popup);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* deletes contact from blocked list */
|
/* deletes contact from blocked list */
|
||||||
@ -799,6 +811,7 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
block_friend(m, f);
|
block_friend(m, f);
|
||||||
else
|
else
|
||||||
unblock_friend(m, f);
|
unblock_friend(m, f);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KEY_RIGHT:
|
case KEY_RIGHT:
|
||||||
@ -811,6 +824,7 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
select_friend(self, key, &Friends.num_selected, Friends.num_friends);
|
select_friend(self, key, &Friends.num_selected, Friends.num_friends);
|
||||||
else
|
else
|
||||||
select_friend(self, key, &Blocked.num_selected, Blocked.num_blocked);
|
select_friend(self, key, &Blocked.num_selected, Blocked.num_blocked);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -881,7 +895,7 @@ static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2)
|
|||||||
wprintw(self->window, "%02X", Blocked.list[selected_num].pub_key[i] & 0xff);
|
wprintw(self->window, "%02X", Blocked.list[selected_num].pub_key[i] & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
wrefresh(self->window);
|
wnoutrefresh(self->window);
|
||||||
draw_del_popup();
|
draw_del_popup();
|
||||||
|
|
||||||
if (self->help->active)
|
if (self->help->active)
|
||||||
@ -970,9 +984,11 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
case TOX_USER_STATUS_NONE:
|
case TOX_USER_STATUS_NONE:
|
||||||
colour = GREEN;
|
colour = GREEN;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_USER_STATUS_AWAY:
|
case TOX_USER_STATUS_AWAY:
|
||||||
colour = YELLOW;
|
colour = YELLOW;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_USER_STATUS_BUSY:
|
case TOX_USER_STATUS_BUSY:
|
||||||
colour = RED;
|
colour = RED;
|
||||||
break;
|
break;
|
||||||
@ -1054,9 +1070,9 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
|
|
||||||
int day_dist = (
|
int day_dist = (
|
||||||
cur_loc_tm.tm_yday - Friends.list[f].last_online.tm.tm_yday
|
cur_loc_tm.tm_yday - Friends.list[f].last_online.tm.tm_yday
|
||||||
+ ((cur_loc_tm.tm_year - Friends.list[f].last_online.tm.tm_year) * 365)
|
+ ((cur_loc_tm.tm_year - Friends.list[f].last_online.tm.tm_year) * 365)
|
||||||
);
|
);
|
||||||
const char *hourmin = Friends.list[f].last_online.hour_min_str;
|
const char *hourmin = Friends.list[f].last_online.hour_min_str;
|
||||||
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
@ -1096,7 +1112,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
wprintw(self->window, "%02X", Friends.list[selected_num].pub_key[i] & 0xff);
|
wprintw(self->window, "%02X", Friends.list[selected_num].pub_key[i] & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
wrefresh(self->window);
|
wnoutrefresh(self->window);
|
||||||
draw_del_popup();
|
draw_del_popup();
|
||||||
|
|
||||||
if (self->help->active)
|
if (self->help->active)
|
||||||
@ -1112,7 +1128,8 @@ void disable_chatwin(uint32_t f_num)
|
|||||||
static void friendlist_onAV(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
|
static void friendlist_onAV(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
|
||||||
{
|
{
|
||||||
assert(0);
|
assert(0);
|
||||||
if( friend_number >= Friends.max_idx)
|
|
||||||
|
if ( friend_number >= Friends.max_idx)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
assert(0);
|
assert(0);
|
||||||
@ -1120,7 +1137,7 @@ static void friendlist_onAV(ToxWindow *self, ToxAV *av, uint32_t friend_number,
|
|||||||
|
|
||||||
if (Friends.list[friend_number].chatwin == -1) {
|
if (Friends.list[friend_number].chatwin == -1) {
|
||||||
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
||||||
if(state != TOXAV_FRIEND_CALL_STATE_FINISHED) {
|
if (state != TOXAV_FRIEND_CALL_STATE_FINISHED) {
|
||||||
Friends.list[friend_number].chatwin = add_window(m, new_chat(m, Friends.list[friend_number].num));
|
Friends.list[friend_number].chatwin = add_window(m, new_chat(m, Friends.list[friend_number].num));
|
||||||
set_active_window(Friends.list[friend_number].chatwin);
|
set_active_window(Friends.list[friend_number].chatwin);
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ struct GroupChatInvite {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char name[TOXIC_MAX_NAME_LENGTH + 1];
|
char name[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
int namelength;
|
uint16_t namelength;
|
||||||
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
|
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
|
||||||
size_t statusmsg_len;
|
size_t statusmsg_len;
|
||||||
char pub_key[TOX_PUBLIC_KEY_SIZE];
|
char pub_key[TOX_PUBLIC_KEY_SIZE];
|
||||||
@ -65,7 +65,7 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char name[TOXIC_MAX_NAME_LENGTH + 1];
|
char name[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
int namelength;
|
uint16_t namelength;
|
||||||
char pub_key[TOX_PUBLIC_KEY_SIZE];
|
char pub_key[TOX_PUBLIC_KEY_SIZE];
|
||||||
uint32_t num;
|
uint32_t num;
|
||||||
bool active;
|
bool active;
|
||||||
|
@ -130,6 +130,7 @@ void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_ERR_FRIEND_ADD_NULL:
|
case TOX_ERR_FRIEND_ADD_NULL:
|
||||||
|
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
default:
|
default:
|
||||||
errmsg = "Faile to add friend: Unknown error.";
|
errmsg = "Faile to add friend: Unknown error.";
|
||||||
@ -260,6 +261,7 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
char key_binary[TOX_PUBLIC_KEY_SIZE * 2 + 1];
|
char key_binary[TOX_PUBLIC_KEY_SIZE * 2 + 1];
|
||||||
|
|
||||||
if (hex_string_to_bin(ascii_key, strlen(ascii_key), key_binary, TOX_PUBLIC_KEY_SIZE) == -1) {
|
if (hex_string_to_bin(ascii_key, strlen(ascii_key), key_binary, TOX_PUBLIC_KEY_SIZE) == -1) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid key.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid key.");
|
||||||
return;
|
return;
|
||||||
@ -281,6 +283,7 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
|
|||||||
case TOX_ERR_BOOTSTRAP_NULL:
|
case TOX_ERR_BOOTSTRAP_NULL:
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed.");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -333,31 +336,31 @@ void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
|
|||||||
uint8_t type;
|
uint8_t type;
|
||||||
|
|
||||||
if (!strcasecmp(argv[1], "audio"))
|
if (!strcasecmp(argv[1], "audio"))
|
||||||
type = TOX_GROUPCHAT_TYPE_AV;
|
type = TOX_CONFERENCE_TYPE_AV;
|
||||||
else if (!strcasecmp(argv[1], "text"))
|
else if (!strcasecmp(argv[1], "text"))
|
||||||
type = TOX_GROUPCHAT_TYPE_TEXT;
|
type = TOX_CONFERENCE_TYPE_TEXT;
|
||||||
else {
|
else {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Valid group types are: text | audio");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Valid group types are: text | audio");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int groupnum = -1;
|
if (type != TOX_CONFERENCE_TYPE_TEXT) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Toxic does not support audio groups.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (type == TOX_GROUPCHAT_TYPE_TEXT)
|
TOX_ERR_CONFERENCE_NEW err;
|
||||||
groupnum = tox_add_groupchat(m);
|
|
||||||
/*#ifdef AUDIO
|
|
||||||
else
|
|
||||||
groupnum = toxav_add_av_groupchat(m, NULL, NULL);
|
|
||||||
#endif*/
|
|
||||||
|
|
||||||
if (groupnum == -1) {
|
uint32_t groupnum = tox_conference_new(m, &err);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize.");
|
|
||||||
|
if (err != TOX_ERR_CONFERENCE_NEW_OK) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize (error %d)", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (init_groupchat_win(prompt, m, groupnum, type) == -1) {
|
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.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
|
||||||
tox_del_groupchat(m, groupnum);
|
tox_conference_delete(m, groupnum, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -448,25 +451,42 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
|||||||
char dir[data_file_len + 1];
|
char dir[data_file_len + 1];
|
||||||
size_t dir_len = get_base_dir(DATA_FILE, data_file_len, dir);
|
size_t dir_len = get_base_dir(DATA_FILE, data_file_len, dir);
|
||||||
|
|
||||||
char qr_path[dir_len + nick_len + strlen(QRCODE_FILENAME_EXT) + 1];
|
#ifdef QRPNG
|
||||||
snprintf(qr_path, sizeof(qr_path), "%s%s%s", dir, nick, QRCODE_FILENAME_EXT);
|
|
||||||
|
|
||||||
FILE *output = fopen(qr_path, "wb");
|
if (argc == 0) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Required 'txt' or 'png'");
|
||||||
|
return;
|
||||||
|
} else if (!strcmp(argv[1], "txt")) {
|
||||||
|
|
||||||
if (output == NULL) {
|
#endif /* QRPNG */
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
|
char qr_path[dir_len + nick_len + strlen(QRCODE_FILENAME_EXT) + 1];
|
||||||
|
snprintf(qr_path, sizeof(qr_path), "%s%s%s", dir, nick, QRCODE_FILENAME_EXT);
|
||||||
|
|
||||||
|
if (ID_to_QRcode_txt(id_string, qr_path) == -1) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path);
|
||||||
|
|
||||||
|
#ifdef QRPNG
|
||||||
|
} else if (!strcmp(argv[1], "png")) {
|
||||||
|
char qr_path[dir_len + nick_len + strlen(QRCODE_FILENAME_EXT_PNG) + 1];
|
||||||
|
snprintf(qr_path, sizeof(qr_path), "%s%s%s", dir, nick, QRCODE_FILENAME_EXT_PNG);
|
||||||
|
|
||||||
|
if (ID_to_QRcode_png(id_string, qr_path) == -1) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Unknown option '%s' -- Required 'txt' or 'png'", argv[1]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ID_to_QRcode(id_string, output) == -1) {
|
#endif /* QRPNG */
|
||||||
fclose(output);
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path);
|
|
||||||
|
|
||||||
fclose(output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
@ -543,8 +563,10 @@ void cmd_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
|||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Your new Tox ID is:");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Your new Tox ID is:");
|
||||||
cmd_myid(window, self, m, 0, NULL);
|
cmd_myid(window, self, m, 0, NULL);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Any services that relied on your old ID will need to be updated manually.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "If you ever want your old Tox ID back, type '/nospam %X'", old_nospam);
|
"Any services that relied on your old ID will need to be updated manually.");
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "If you ever want your old Tox ID back, type '/nospam %X'",
|
||||||
|
old_nospam);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_prompt_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_prompt_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
@ -633,6 +655,9 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
|||||||
msg[len] = '\0';
|
msg[len] = '\0';
|
||||||
|
|
||||||
prompt_update_statusmessage(prompt, m, msg);
|
prompt_update_statusmessage(prompt, m, msg);
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Your status has been changed to %s: \"%s\".", status_str, msg);
|
||||||
|
} else {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Your status has been changed to %s.", status_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
|
@ -56,4 +56,8 @@ void cmd_list_video_devices(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)
|
|||||||
void cmd_change_video_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_change_video_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
|
|
||||||
|
#ifdef PYTHON
|
||||||
|
void cmd_run(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* #define GLOBAL_COMMANDS_H */
|
#endif /* #define GLOBAL_COMMANDS_H */
|
||||||
|
@ -30,18 +30,25 @@
|
|||||||
|
|
||||||
void cmd_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
|
TOX_ERR_CONFERENCE_TITLE err;
|
||||||
char title[MAX_STR_SIZE];
|
char title[MAX_STR_SIZE];
|
||||||
|
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
int tlen = tox_group_get_title(m, self->num, (uint8_t *) title, TOX_MAX_NAME_LENGTH);
|
size_t tlen = tox_conference_get_title_size(m, self->num, &err);
|
||||||
|
|
||||||
if (tlen != -1) {
|
if (err != TOX_ERR_CONFERENCE_TITLE_OK) {
|
||||||
title[tlen] = '\0';
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title is set to: %s", title);
|
|
||||||
} else {
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title is not set");
|
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);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,8 +62,8 @@ void cmd_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
|
|||||||
int len = strlen(title) - 1;
|
int len = strlen(title) - 1;
|
||||||
title[len] = '\0';
|
title[len] = '\0';
|
||||||
|
|
||||||
if (tox_group_set_title(m, self->num, (uint8_t *) title, len) != 0) {
|
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.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title (error %d)", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
315
src/groupchat.c
315
src/groupchat.c
@ -69,8 +69,12 @@ static int max_groupchat_index = 0;
|
|||||||
extern struct user_settings *user_settings;
|
extern struct user_settings *user_settings;
|
||||||
extern struct Winthread Winthread;
|
extern struct Winthread Winthread;
|
||||||
|
|
||||||
#ifdef AUDIO
|
#if defined(AUDIO) && defined(PYTHON)
|
||||||
|
#define AC_NUM_GROUP_COMMANDS 25
|
||||||
|
#elif AUDIO
|
||||||
#define AC_NUM_GROUP_COMMANDS 24
|
#define AC_NUM_GROUP_COMMANDS 24
|
||||||
|
#elif PYTHON
|
||||||
|
#define AC_NUM_GROUP_COMMANDS 21
|
||||||
#else
|
#else
|
||||||
#define AC_NUM_GROUP_COMMANDS 20
|
#define AC_NUM_GROUP_COMMANDS 20
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
@ -98,25 +102,18 @@ static const char group_cmd_list[AC_NUM_GROUP_COMMANDS][MAX_CMDNAME_SIZE] = {
|
|||||||
{ "/status" },
|
{ "/status" },
|
||||||
{ "/title" },
|
{ "/title" },
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef PYTHON
|
||||||
|
|
||||||
{ "/lsdev" },
|
{ "/run" },
|
||||||
{ "/sdev" },
|
|
||||||
{ "/mute" },
|
|
||||||
{ "/sense" },
|
|
||||||
|
|
||||||
#endif /* AUDIO */
|
#endif /* PYTHON */
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef AUDIO
|
int init_groupchat_win(ToxWindow *prompt, Tox *m, uint32_t groupnum, uint8_t type)
|
||||||
static int group_audio_open_out_device(int groupnum);
|
|
||||||
static int group_audio_close_out_device(int groupnum);
|
|
||||||
#endif /* AUDIO */
|
|
||||||
|
|
||||||
int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum, uint8_t type)
|
|
||||||
{
|
{
|
||||||
if (groupnum > MAX_GROUPCHAT_NUM)
|
if (groupnum > MAX_GROUPCHAT_NUM) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
ToxWindow self = new_group_chat(m, groupnum);
|
ToxWindow self = new_group_chat(m, groupnum);
|
||||||
int i;
|
int i;
|
||||||
@ -135,18 +132,12 @@ int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum, uint8_t type)
|
|||||||
groupchats[i].oldpeer_name_lengths = malloc(sizeof(uint16_t));
|
groupchats[i].oldpeer_name_lengths = malloc(sizeof(uint16_t));
|
||||||
|
|
||||||
if (groupchats[i].peer_names == NULL || groupchats[i].oldpeer_names == NULL
|
if (groupchats[i].peer_names == NULL || groupchats[i].oldpeer_names == NULL
|
||||||
|| groupchats[i].peer_name_lengths == NULL || groupchats[i].oldpeer_name_lengths == NULL)
|
|| groupchats[i].peer_name_lengths == NULL || groupchats[i].oldpeer_name_lengths == NULL)
|
||||||
exit_toxic_err("failed in init_groupchat_win", FATALERR_MEMORY);
|
exit_toxic_err("failed in init_groupchat_win", FATALERR_MEMORY);
|
||||||
|
|
||||||
memcpy(&groupchats[i].oldpeer_names[0], UNKNOWN_NAME, sizeof(UNKNOWN_NAME));
|
memcpy(&groupchats[i].oldpeer_names[0], UNKNOWN_NAME, sizeof(UNKNOWN_NAME));
|
||||||
groupchats[i].oldpeer_name_lengths[0] = (uint16_t) strlen(UNKNOWN_NAME);
|
groupchats[i].oldpeer_name_lengths[0] = (uint16_t) strlen(UNKNOWN_NAME);
|
||||||
|
|
||||||
#ifdef AUDIO
|
|
||||||
if (type == TOX_GROUPCHAT_TYPE_AV)
|
|
||||||
if (group_audio_open_out_device(i) == -1)
|
|
||||||
fprintf(stderr, "Group Audio failed to init\n");
|
|
||||||
#endif /* AUDIO */
|
|
||||||
|
|
||||||
set_active_window(groupchats[i].chatwin);
|
set_active_window(groupchats[i].chatwin);
|
||||||
|
|
||||||
if (i == max_groupchat_index)
|
if (i == max_groupchat_index)
|
||||||
@ -174,12 +165,9 @@ static void kill_groupchat_window(ToxWindow *self)
|
|||||||
del_window(self);
|
del_window(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void close_groupchat(ToxWindow *self, Tox *m, int groupnum)
|
void close_groupchat(ToxWindow *self, Tox *m, uint32_t groupnum)
|
||||||
{
|
{
|
||||||
tox_del_groupchat(m, groupnum);
|
tox_conference_delete(m, groupnum, NULL);
|
||||||
#ifdef AUDIO
|
|
||||||
group_audio_close_out_device(groupnum);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
free(groupchats[groupnum].peer_names);
|
free(groupchats[groupnum].peer_names);
|
||||||
free(groupchats[groupnum].oldpeer_names);
|
free(groupchats[groupnum].oldpeer_names);
|
||||||
@ -237,8 +225,8 @@ void redraw_groupchat_win(ToxWindow *self)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, int groupnum, int peernum,
|
static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, uint32_t groupnum, uint32_t peernum,
|
||||||
const char *msg, uint16_t len)
|
TOX_MESSAGE_TYPE type, const char *msg, size_t len)
|
||||||
{
|
{
|
||||||
if (self->num != groupnum)
|
if (self->num != groupnum)
|
||||||
return;
|
return;
|
||||||
@ -266,56 +254,20 @@ static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, int groupnum, int
|
|||||||
box_silent_notify(self, NT_NOFOCUS, &self->active_box, self->name, "%s %s", nick, msg);
|
box_silent_notify(self, NT_NOFOCUS, &self->active_box, self->name, "%s %s", nick, msg);
|
||||||
|
|
||||||
nick_clr = RED;
|
nick_clr = RED;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
sound_notify(self, silent, NT_WNDALERT_1, NULL);
|
sound_notify(self, silent, NT_WNDALERT_1, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
char timefrmt[TIME_STR_SIZE];
|
char timefrmt[TIME_STR_SIZE];
|
||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
|
|
||||||
line_info_add(self, timefrmt, nick, NULL, IN_MSG, 0, nick_clr, "%s", msg);
|
line_info_add(self, timefrmt, nick, NULL, type == TOX_MESSAGE_TYPE_NORMAL ? IN_MSG : IN_ACTION, 0, nick_clr, "%s", msg);
|
||||||
write_to_log(msg, nick, ctx->log, false);
|
write_to_log(msg, nick, ctx->log, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void groupchat_onGroupAction(ToxWindow *self, Tox *m, int groupnum, int peernum, const char *action,
|
static void groupchat_onGroupTitleChange(ToxWindow *self, Tox *m, uint32_t groupnum, uint32_t peernum,
|
||||||
uint16_t len)
|
const char *title,
|
||||||
{
|
size_t length)
|
||||||
if (self->num != groupnum)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ChatContext *ctx = self->chatwin;
|
|
||||||
|
|
||||||
char nick[TOX_MAX_NAME_LENGTH];
|
|
||||||
get_group_nick_truncate(m, nick, peernum, groupnum);
|
|
||||||
|
|
||||||
char selfnick[TOX_MAX_NAME_LENGTH];
|
|
||||||
tox_self_get_name(m, (uint8_t *) selfnick);
|
|
||||||
|
|
||||||
size_t n_len = tox_self_get_name_size(m);
|
|
||||||
selfnick[n_len] = '\0';
|
|
||||||
|
|
||||||
if (strcasestr(action, selfnick)) {
|
|
||||||
sound_notify(self, generic_message, NT_WNDALERT_0 | user_settings->bell_on_message, NULL);
|
|
||||||
|
|
||||||
if (self->active_box != -1)
|
|
||||||
box_silent_notify2(self, NT_NOFOCUS, self->active_box, "* %s %s", nick, action );
|
|
||||||
else
|
|
||||||
box_silent_notify(self, NT_NOFOCUS, &self->active_box, self->name, "* %s %s", nick, action);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sound_notify(self, silent, NT_WNDALERT_1, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
char timefrmt[TIME_STR_SIZE];
|
|
||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
|
||||||
|
|
||||||
line_info_add(self, timefrmt, nick, NULL, IN_ACTION, 0, 0, "%s", action);
|
|
||||||
write_to_log(action, nick, ctx->log, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void groupchat_onGroupTitleChange(ToxWindow *self, Tox *m, int groupnum, int peernum, const char *title,
|
|
||||||
uint8_t length)
|
|
||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
@ -341,7 +293,7 @@ static void groupchat_onGroupTitleChange(ToxWindow *self, Tox *m, int groupnum,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Puts two copies of peerlist/lengths in chat instance */
|
/* Puts two copies of peerlist/lengths in chat instance */
|
||||||
static void copy_peernames(int gnum, uint8_t peerlist[][TOX_MAX_NAME_LENGTH], uint16_t lengths[], int npeers)
|
static void copy_peernames(Tox *m, uint32_t gnum, size_t npeers)
|
||||||
{
|
{
|
||||||
/* Assumes these are initiated in init_groupchat_win */
|
/* Assumes these are initiated in init_groupchat_win */
|
||||||
free(groupchats[gnum].peer_names);
|
free(groupchats[gnum].peer_names);
|
||||||
@ -351,27 +303,34 @@ static void copy_peernames(int gnum, uint8_t peerlist[][TOX_MAX_NAME_LENGTH], ui
|
|||||||
|
|
||||||
int N = TOX_MAX_NAME_LENGTH;
|
int N = TOX_MAX_NAME_LENGTH;
|
||||||
|
|
||||||
groupchats[gnum].peer_names = malloc(sizeof(uint8_t) * npeers * N);
|
groupchats[gnum].peer_names = calloc(1, sizeof(uint8_t) * npeers * N);
|
||||||
groupchats[gnum].oldpeer_names = malloc(sizeof(uint8_t) * npeers * N);
|
groupchats[gnum].oldpeer_names = calloc(1, sizeof(uint8_t) * npeers * N);
|
||||||
groupchats[gnum].peer_name_lengths = malloc(sizeof(uint16_t) * npeers);
|
groupchats[gnum].peer_name_lengths = calloc(1, sizeof(uint16_t) * npeers);
|
||||||
groupchats[gnum].oldpeer_name_lengths = malloc(sizeof(uint16_t) * npeers);
|
groupchats[gnum].oldpeer_name_lengths = calloc(1, sizeof(uint16_t) * npeers);
|
||||||
|
|
||||||
if (groupchats[gnum].peer_names == NULL || groupchats[gnum].oldpeer_names == NULL
|
if (groupchats[gnum].peer_names == NULL || groupchats[gnum].oldpeer_names == NULL
|
||||||
|| groupchats[gnum].peer_name_lengths == NULL || groupchats[gnum].oldpeer_name_lengths == NULL) {
|
|| groupchats[gnum].peer_name_lengths == NULL || groupchats[gnum].oldpeer_name_lengths == NULL) {
|
||||||
exit_toxic_err("failed in copy_peernames", FATALERR_MEMORY);
|
exit_toxic_err("failed in copy_peernames()", FATALERR_MEMORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t u_len = strlen(UNKNOWN_NAME);
|
uint16_t u_len = strlen(UNKNOWN_NAME);
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < npeers; ++i) {
|
for (i = 0; i < npeers; ++i) {
|
||||||
if (!lengths[i]) {
|
uint8_t name[TOX_MAX_NAME_LENGTH];
|
||||||
|
TOX_ERR_CONFERENCE_PEER_QUERY err;
|
||||||
|
|
||||||
|
size_t n_len = tox_conference_peer_get_name_size(m, gnum, i, &err);
|
||||||
|
|
||||||
|
if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
|
||||||
memcpy(&groupchats[gnum].peer_names[i * N], UNKNOWN_NAME, u_len);
|
memcpy(&groupchats[gnum].peer_names[i * N], UNKNOWN_NAME, u_len);
|
||||||
groupchats[gnum].peer_names[i * N + u_len] = '\0';
|
groupchats[gnum].peer_names[i * N + u_len] = '\0';
|
||||||
groupchats[gnum].peer_name_lengths[i] = u_len;
|
groupchats[gnum].peer_name_lengths[i] = u_len;
|
||||||
} else {
|
} else {
|
||||||
uint16_t n_len = MIN(lengths[i], TOXIC_MAX_NAME_LENGTH - 1);
|
tox_conference_peer_get_name(m, gnum, i, name, NULL);
|
||||||
memcpy(&groupchats[gnum].peer_names[i * N], peerlist[i], n_len);
|
n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH - 1);
|
||||||
|
memcpy(&groupchats[gnum].peer_names[i * N], name, n_len);
|
||||||
groupchats[gnum].peer_names[i * N + n_len] = '\0';
|
groupchats[gnum].peer_names[i * N + n_len] = '\0';
|
||||||
groupchats[gnum].peer_name_lengths[i] = n_len;
|
groupchats[gnum].peer_name_lengths[i] = n_len;
|
||||||
filter_str((char *) &groupchats[gnum].peer_names[i * N], n_len);
|
filter_str((char *) &groupchats[gnum].peer_names[i * N], n_len);
|
||||||
@ -385,8 +344,8 @@ static void copy_peernames(int gnum, uint8_t peerlist[][TOX_MAX_NAME_LENGTH], ui
|
|||||||
struct group_add_thrd {
|
struct group_add_thrd {
|
||||||
Tox *m;
|
Tox *m;
|
||||||
ToxWindow *self;
|
ToxWindow *self;
|
||||||
int peernum;
|
uint32_t peernum;
|
||||||
int groupnum;
|
uint32_t groupnum;
|
||||||
time_t timestamp;
|
time_t timestamp;
|
||||||
pthread_t tid;
|
pthread_t tid;
|
||||||
pthread_attr_t attr;
|
pthread_attr_t attr;
|
||||||
@ -429,7 +388,8 @@ void *group_add_wait(void *data)
|
|||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnum, int peernum, uint8_t change)
|
static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, uint32_t groupnum, uint32_t peernum,
|
||||||
|
TOX_CONFERENCE_STATE_CHANGE change)
|
||||||
{
|
{
|
||||||
if (self->num != groupnum)
|
if (self->num != groupnum)
|
||||||
return;
|
return;
|
||||||
@ -437,8 +397,15 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu
|
|||||||
if (groupnum > max_groupchat_index)
|
if (groupnum > max_groupchat_index)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
groupchats[groupnum].num_peers = tox_group_number_peers(m, groupnum);
|
TOX_ERR_CONFERENCE_PEER_QUERY err;
|
||||||
int num_peers = groupchats[groupnum].num_peers;
|
|
||||||
|
uint32_t num_peers = tox_conference_peer_count(m, groupnum, &err);
|
||||||
|
|
||||||
|
if (err == TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
|
||||||
|
groupchats[groupnum].num_peers = num_peers;
|
||||||
|
} else {
|
||||||
|
num_peers = groupchats[groupnum].num_peers;
|
||||||
|
}
|
||||||
|
|
||||||
if (peernum > num_peers)
|
if (peernum > num_peers)
|
||||||
return;
|
return;
|
||||||
@ -446,28 +413,19 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu
|
|||||||
/* get old peer name before updating name list */
|
/* get old peer name before updating name list */
|
||||||
uint8_t oldpeername[TOX_MAX_NAME_LENGTH];
|
uint8_t oldpeername[TOX_MAX_NAME_LENGTH];
|
||||||
|
|
||||||
if (change != TOX_CHAT_CHANGE_PEER_ADD) {
|
if (change != TOX_CONFERENCE_STATE_CHANGE_PEER_JOIN) {
|
||||||
memcpy(oldpeername, &groupchats[groupnum].oldpeer_names[peernum * TOX_MAX_NAME_LENGTH],
|
memcpy(oldpeername, &groupchats[groupnum].oldpeer_names[peernum * TOX_MAX_NAME_LENGTH], sizeof(oldpeername));
|
||||||
sizeof(oldpeername));
|
|
||||||
uint16_t old_n_len = groupchats[groupnum].oldpeer_name_lengths[peernum];
|
uint16_t old_n_len = groupchats[groupnum].oldpeer_name_lengths[peernum];
|
||||||
oldpeername[old_n_len] = '\0';
|
oldpeername[old_n_len] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update name/len lists */
|
/* Update name/len lists */
|
||||||
uint8_t tmp_peerlist[num_peers][TOX_MAX_NAME_LENGTH];
|
copy_peernames(m, groupnum, num_peers);
|
||||||
uint16_t tmp_peerlens[num_peers];
|
|
||||||
|
|
||||||
if (tox_group_get_names(m, groupnum, tmp_peerlist, tmp_peerlens, num_peers) == -1) {
|
|
||||||
memset(tmp_peerlist, 0, sizeof(tmp_peerlist));
|
|
||||||
memset(tmp_peerlens, 0, sizeof(tmp_peerlens));
|
|
||||||
}
|
|
||||||
|
|
||||||
copy_peernames(groupnum, tmp_peerlist, tmp_peerlens, num_peers);
|
|
||||||
|
|
||||||
/* get current peername then sort namelist */
|
/* get current peername then sort namelist */
|
||||||
uint8_t peername[TOX_MAX_NAME_LENGTH];
|
uint8_t peername[TOX_MAX_NAME_LENGTH];
|
||||||
|
|
||||||
if (change != TOX_CHAT_CHANGE_PEER_DEL) {
|
if (change != TOX_CONFERENCE_STATE_CHANGE_PEER_EXIT) {
|
||||||
uint16_t n_len = groupchats[groupnum].peer_name_lengths[peernum];
|
uint16_t n_len = groupchats[groupnum].peer_name_lengths[peernum];
|
||||||
memcpy(peername, &groupchats[groupnum].peer_names[peernum * TOX_MAX_NAME_LENGTH], sizeof(peername));
|
memcpy(peername, &groupchats[groupnum].peer_names[peernum * TOX_MAX_NAME_LENGTH], sizeof(peername));
|
||||||
peername[n_len] = '\0';
|
peername[n_len] = '\0';
|
||||||
@ -482,7 +440,7 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu
|
|||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
|
|
||||||
switch (change) {
|
switch (change) {
|
||||||
case TOX_CHAT_CHANGE_PEER_ADD:
|
case TOX_CONFERENCE_STATE_CHANGE_PEER_JOIN:
|
||||||
if (!timed_out(groupchats[groupnum].start_time, GROUP_EVENT_WAIT))
|
if (!timed_out(groupchats[groupnum].start_time, GROUP_EVENT_WAIT))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -512,7 +470,7 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_CHAT_CHANGE_PEER_DEL:
|
case TOX_CONFERENCE_STATE_CHANGE_PEER_EXIT:
|
||||||
event = "has left the room";
|
event = "has left the room";
|
||||||
line_info_add(self, timefrmt, (char *) oldpeername, NULL, DISCONNECTION, 0, RED, event);
|
line_info_add(self, timefrmt, (char *) oldpeername, NULL, DISCONNECTION, 0, RED, event);
|
||||||
|
|
||||||
@ -522,7 +480,7 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu
|
|||||||
write_to_log(event, (char *) oldpeername, ctx->log, true);
|
write_to_log(event, (char *) oldpeername, ctx->log, true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_CHAT_CHANGE_PEER_NAME:
|
case TOX_CONFERENCE_STATE_CHANGE_PEER_NAME_CHANGE:
|
||||||
if (!timed_out(groupchats[self->num].start_time, GROUP_EVENT_WAIT))
|
if (!timed_out(groupchats[self->num].start_time, GROUP_EVENT_WAIT))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -549,9 +507,10 @@ static void send_group_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *a
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tox_group_action_send(m, self->num, (uint8_t *) action, strlen(action)) == -1) {
|
TOX_ERR_CONFERENCE_SEND_MESSAGE err;
|
||||||
const char *errmsg = " * Failed to send action.";
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, errmsg);
|
if (!tox_conference_send_message(m, self->num, TOX_MESSAGE_TYPE_ACTION, (uint8_t *) action, strlen(action), &err)) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send action (error %d)", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,7 +554,16 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
TOX_MAX_NAME_LENGTH);
|
TOX_MAX_NAME_LENGTH);
|
||||||
} else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) {
|
} else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) {
|
||||||
diff = dir_match(self, m, ctx->line, L"/avatar");
|
diff = dir_match(self, m, ctx->line, L"/avatar");
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
#ifdef PYTHON
|
||||||
|
else if (wcsncmp(ctx->line, L"/run \"", wcslen(L"/run \"")) == 0) {
|
||||||
|
diff = dir_match(self, m, ctx->line, L"/run");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
else {
|
||||||
diff = complete_line(self, group_cmd_list, AC_NUM_GROUP_COMMANDS, MAX_CMDNAME_SIZE);
|
diff = complete_line(self, group_cmd_list, AC_NUM_GROUP_COMMANDS, MAX_CMDNAME_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -621,8 +589,7 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
} else if (key == '\r') {
|
} else if (key == '\r') {
|
||||||
rm_trailing_spaces_buf(ctx);
|
rm_trailing_spaces_buf(ctx);
|
||||||
|
|
||||||
if (!wstring_is_empty(ctx->line))
|
if (!wstring_is_empty(ctx->line)) {
|
||||||
{
|
|
||||||
add_line_to_hist(ctx);
|
add_line_to_hist(ctx);
|
||||||
|
|
||||||
wstrsubst(ctx->line, L'¶', L'\n');
|
wstrsubst(ctx->line, L'¶', L'\n');
|
||||||
@ -642,9 +609,10 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
execute(ctx->history, self, m, line, GROUPCHAT_COMMAND_MODE);
|
execute(ctx->history, self, m, line, GROUPCHAT_COMMAND_MODE);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (tox_group_message_send(m, self->num, (uint8_t *) line, strlen(line)) == -1) {
|
TOX_ERR_CONFERENCE_SEND_MESSAGE err;
|
||||||
const char *errmsg = " * Failed to send message.";
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, errmsg);
|
if (!tox_conference_send_message(m, self->num, TOX_MESSAGE_TYPE_NORMAL, (uint8_t *) line, strlen(line), &err)) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send message (error %d)", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -702,7 +670,7 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
wmove(ctx->sidebar, i + 2, 1);
|
wmove(ctx->sidebar, i + 2, 1);
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
int peer = i + groupchats[self->num].side_pos;
|
uint32_t peer = i + groupchats[self->num].side_pos;
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
/* truncate nick to fit in side panel without modifying list */
|
/* truncate nick to fit in side panel without modifying list */
|
||||||
@ -725,7 +693,7 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
|
int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
|
||||||
wmove(self->window, y + 1, new_x);
|
wmove(self->window, y + 1, new_x);
|
||||||
|
|
||||||
wrefresh(self->window);
|
wnoutrefresh(self->window);
|
||||||
|
|
||||||
if (self->help->active)
|
if (self->help->active)
|
||||||
help_onDraw(self);
|
help_onDraw(self);
|
||||||
@ -767,125 +735,7 @@ static void groupchat_onInit(ToxWindow *self, Tox *m)
|
|||||||
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ToxWindow new_group_chat(Tox *m, uint32_t groupnum)
|
||||||
#ifdef AUDIO
|
|
||||||
static int group_audio_open_out_device(int groupnum)
|
|
||||||
{
|
|
||||||
char dname[MAX_STR_SIZE];
|
|
||||||
get_primary_device_name(output, dname, sizeof(dname));
|
|
||||||
dname[MAX_STR_SIZE - 1] = '\0';
|
|
||||||
|
|
||||||
groupchats[groupnum].audio.dvhandle = alcOpenDevice(dname);
|
|
||||||
|
|
||||||
if (groupchats[groupnum].audio.dvhandle == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
groupchats[groupnum].audio.dvctx = alcCreateContext(groupchats[groupnum].audio.dvhandle, NULL);
|
|
||||||
alcMakeContextCurrent(groupchats[groupnum].audio.dvctx);
|
|
||||||
alGenBuffers(OPENAL_BUFS, groupchats[groupnum].audio.buffers);
|
|
||||||
alGenSources((uint32_t) 1, &groupchats[groupnum].audio.source);
|
|
||||||
alSourcei(groupchats[groupnum].audio.source, AL_LOOPING, AL_FALSE);
|
|
||||||
|
|
||||||
if (alcGetError(groupchats[groupnum].audio.dvhandle) != AL_NO_ERROR) {
|
|
||||||
group_audio_close_out_device(groupnum);
|
|
||||||
groupchats[groupnum].audio.dvhandle = NULL;
|
|
||||||
groupchats[groupnum].audio.dvctx = NULL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
alSourceQueueBuffers(groupchats[groupnum].audio.source, OPENAL_BUFS, groupchats[groupnum].audio.buffers);
|
|
||||||
alSourcePlay(groupchats[groupnum].audio.source);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int group_audio_close_out_device(int groupnum)
|
|
||||||
{
|
|
||||||
if (!groupchats[groupnum].audio.dvhandle)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (!groupchats[groupnum].audio.dvctx)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (alcGetCurrentContext() != groupchats[groupnum].audio.dvctx)
|
|
||||||
alcMakeContextCurrent(groupchats[groupnum].audio.dvctx);
|
|
||||||
|
|
||||||
alDeleteSources((uint32_t) 1, &groupchats[groupnum].audio.source);
|
|
||||||
alDeleteBuffers(OPENAL_BUFS, groupchats[groupnum].audio.buffers);
|
|
||||||
|
|
||||||
alcMakeContextCurrent(NULL);
|
|
||||||
alcDestroyContext(groupchats[groupnum].audio.dvctx);
|
|
||||||
|
|
||||||
if (!alcCloseDevice(groupchats[groupnum].audio.dvhandle))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// static int group_audio_write(int peernum, int groupnum, const int16_t *pcm, unsigned int samples, uint8_t channels,
|
|
||||||
// unsigned int sample_rate)
|
|
||||||
// {
|
|
||||||
// if (!pcm)
|
|
||||||
// return -1;
|
|
||||||
|
|
||||||
// if (channels == 0 || channels > 2)
|
|
||||||
// return -2;
|
|
||||||
|
|
||||||
// ALuint bufid;
|
|
||||||
// ALint processed = 0, queued = 0;
|
|
||||||
|
|
||||||
// alGetSourcei(groupchats[groupnum].audio.source, AL_BUFFERS_PROCESSED, &processed);
|
|
||||||
// alGetSourcei(groupchats[groupnum].audio.source, AL_BUFFERS_QUEUED, &queued);
|
|
||||||
// fprintf(stderr, "source: %d, queued: %d, processed: %d\n", groupchats[groupnum].audio.source, queued, processed);
|
|
||||||
|
|
||||||
// if (processed) {
|
|
||||||
// ALuint bufids[processed];
|
|
||||||
// alSourceUnqueueBuffers(groupchats[groupnum].audio.source, processed, bufids);
|
|
||||||
// alDeleteBuffers(processed - 1, bufids + 1);
|
|
||||||
// bufid = bufids[0];
|
|
||||||
// } else if (queued < 16) {
|
|
||||||
// alGenBuffers(1, &bufid);
|
|
||||||
// } else {
|
|
||||||
// return -3;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// int length = samples * channels * sizeof(int16_t);
|
|
||||||
|
|
||||||
// alBufferData(bufid, (channels == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, pcm, length, sample_rate);
|
|
||||||
// alSourceQueueBuffers(groupchats[groupnum].audio.source, 1, &bufid);
|
|
||||||
|
|
||||||
// ALint state;
|
|
||||||
// alGetSourcei(groupchats[groupnum].audio.source, AL_SOURCE_STATE, &state);
|
|
||||||
|
|
||||||
// if (state != AL_PLAYING)
|
|
||||||
// alSourcePlay(groupchats[groupnum].audio.source);
|
|
||||||
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
static void groupchat_onWriteDevice(ToxWindow *self, Tox *m, uint32_t groupnum, int peernum, const int16_t *pcm,
|
|
||||||
unsigned int samples, uint8_t channels, unsigned int sample_rate)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
|
|
||||||
// if (groupnum != self->num)
|
|
||||||
// return;
|
|
||||||
|
|
||||||
// if (peernum < 0)
|
|
||||||
// return;
|
|
||||||
|
|
||||||
// if (groupchats[groupnum].audio.dvhandle == NULL)
|
|
||||||
// fprintf(stderr, "dvhandle is null)\n");
|
|
||||||
|
|
||||||
// if (groupchats[groupnum].audio.dvctx == NULL)
|
|
||||||
// fprintf(stderr, "ctx is null\n");
|
|
||||||
|
|
||||||
// int ret = group_audio_write(peernum, groupnum, pcm, samples, channels, sample_rate);
|
|
||||||
// fprintf(stderr, "write: %d\n", ret);
|
|
||||||
}
|
|
||||||
#endif /* AUDIO */
|
|
||||||
|
|
||||||
ToxWindow new_group_chat(Tox *m, int groupnum)
|
|
||||||
{
|
{
|
||||||
ToxWindow ret;
|
ToxWindow ret;
|
||||||
memset(&ret, 0, sizeof(ret));
|
memset(&ret, 0, sizeof(ret));
|
||||||
@ -898,13 +748,8 @@ ToxWindow new_group_chat(Tox *m, int groupnum)
|
|||||||
ret.onInit = &groupchat_onInit;
|
ret.onInit = &groupchat_onInit;
|
||||||
ret.onGroupMessage = &groupchat_onGroupMessage;
|
ret.onGroupMessage = &groupchat_onGroupMessage;
|
||||||
ret.onGroupNamelistChange = &groupchat_onGroupNamelistChange;
|
ret.onGroupNamelistChange = &groupchat_onGroupNamelistChange;
|
||||||
ret.onGroupAction = &groupchat_onGroupAction;
|
|
||||||
ret.onGroupTitleChange = &groupchat_onGroupTitleChange;
|
ret.onGroupTitleChange = &groupchat_onGroupTitleChange;
|
||||||
|
|
||||||
#ifdef AUDIO
|
|
||||||
ret.onWriteDevice = &groupchat_onWriteDevice;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
snprintf(ret.name, sizeof(ret.name), "Group %d", groupnum);
|
snprintf(ret.name, sizeof(ret.name), "Group %d", groupnum);
|
||||||
|
|
||||||
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
|
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
|
||||||
|
@ -26,61 +26,30 @@
|
|||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
|
|
||||||
#ifdef AUDIO
|
|
||||||
#include "audio_call.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef AUDIO
|
|
||||||
#ifdef __APPLE__
|
|
||||||
#include <OpenAL/al.h>
|
|
||||||
#include <OpenAL/alc.h>
|
|
||||||
#else
|
|
||||||
#include <AL/al.h>
|
|
||||||
#include <AL/alc.h>
|
|
||||||
/* compatibility with older versions of OpenAL */
|
|
||||||
#ifndef ALC_ALL_DEVICES_SPECIFIER
|
|
||||||
#include <AL/alext.h>
|
|
||||||
#endif /* ALC_ALL_DEVICES_SPECIFIER */
|
|
||||||
#endif /* __APPLE__ */
|
|
||||||
#endif /* AUDIO */
|
|
||||||
|
|
||||||
#define SIDEBAR_WIDTH 16
|
#define SIDEBAR_WIDTH 16
|
||||||
#define SDBAR_OFST 2 /* Offset for the peer number box at the top of the statusbar */
|
#define SDBAR_OFST 2 /* Offset for the peer number box at the top of the statusbar */
|
||||||
#define MAX_GROUPCHAT_NUM MAX_WINDOWS_NUM - 2
|
#define MAX_GROUPCHAT_NUM MAX_WINDOWS_NUM - 2
|
||||||
#define GROUP_EVENT_WAIT 3
|
#define GROUP_EVENT_WAIT 3
|
||||||
|
|
||||||
#ifdef AUDIO
|
|
||||||
struct GAudio {
|
|
||||||
ALCdevice *dvhandle; /* Handle of device selected/opened */
|
|
||||||
ALCcontext *dvctx;
|
|
||||||
ALuint source;
|
|
||||||
ALuint buffers[OPENAL_BUFS];
|
|
||||||
};
|
|
||||||
#endif /* AUDIO */
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int chatwin;
|
int chatwin;
|
||||||
bool active;
|
bool active;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
int num_peers;
|
uint32_t num_peers;
|
||||||
int side_pos; /* current position of the sidebar - used for scrolling up and down */
|
int side_pos; /* current position of the sidebar - used for scrolling up and down */
|
||||||
time_t start_time;
|
time_t start_time;
|
||||||
uint8_t *peer_names;
|
uint8_t *peer_names;
|
||||||
uint8_t *oldpeer_names;
|
uint8_t *oldpeer_names;
|
||||||
uint16_t *peer_name_lengths;
|
uint16_t *peer_name_lengths;
|
||||||
uint16_t *oldpeer_name_lengths;
|
uint16_t *oldpeer_name_lengths;
|
||||||
|
|
||||||
#ifdef AUDIO
|
|
||||||
struct GAudio audio;
|
|
||||||
#endif
|
|
||||||
} GroupChat;
|
} GroupChat;
|
||||||
|
|
||||||
void close_groupchat(ToxWindow *self, Tox *m, int groupnum);
|
void close_groupchat(ToxWindow *self, Tox *m, uint32_t groupnum);
|
||||||
int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum, uint8_t type);
|
int init_groupchat_win(ToxWindow *prompt, Tox *m, uint32_t groupnum, uint8_t type);
|
||||||
|
|
||||||
/* destroys and re-creates groupchat window with or without the peerlist */
|
/* destroys and re-creates groupchat window with or without the peerlist */
|
||||||
void redraw_groupchat_win(ToxWindow *self);
|
void redraw_groupchat_win(ToxWindow *self);
|
||||||
|
|
||||||
ToxWindow new_group_chat(Tox *m, int groupnum);
|
ToxWindow new_group_chat(Tox *m, uint32_t groupnum);
|
||||||
|
|
||||||
#endif /* #define GROUPCHAT_H */
|
#endif /* #define GROUPCHAT_H */
|
||||||
|
98
src/help.c
98
src/help.c
@ -27,7 +27,15 @@
|
|||||||
#include "help.h"
|
#include "help.h"
|
||||||
#include "misc_tools.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
|
#define HELP_MENU_HEIGHT 9
|
||||||
|
#endif /* PYTHON */
|
||||||
#define HELP_MENU_WIDTH 26
|
#define HELP_MENU_WIDTH 26
|
||||||
|
|
||||||
void help_init_menu(ToxWindow *self)
|
void help_init_menu(ToxWindow *self)
|
||||||
@ -95,6 +103,13 @@ static void help_draw_menu(ToxWindow *self)
|
|||||||
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||||
wprintw(win, "oup commands\n");
|
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));
|
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||||
wprintw(win, " f");
|
wprintw(win, " f");
|
||||||
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||||
@ -112,7 +127,7 @@ static void help_draw_menu(ToxWindow *self)
|
|||||||
wprintw(win, "it menu\n");
|
wprintw(win, "it menu\n");
|
||||||
|
|
||||||
box(win, ACS_VLINE, ACS_HLINE);
|
box(win, ACS_VLINE, ACS_HLINE);
|
||||||
wrefresh(win);
|
wnoutrefresh(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void help_draw_bottom_menu(WINDOW *win)
|
static void help_draw_bottom_menu(WINDOW *win)
|
||||||
@ -158,7 +173,11 @@ static void help_draw_global(ToxWindow *self)
|
|||||||
wprintw(win, " /log <on> or <off> : Enable/disable logging\n");
|
wprintw(win, " /log <on> or <off> : Enable/disable logging\n");
|
||||||
wprintw(win, " /group <type> : Create a group chat where type: text | audio\n");
|
wprintw(win, " /group <type> : Create a group chat where type: text | audio\n");
|
||||||
wprintw(win, " /myid : Print your Tox ID\n");
|
wprintw(win, " /myid : Print your Tox ID\n");
|
||||||
|
#ifdef QRPNG
|
||||||
|
wprintw(win, " /myqr <txt> or <png> : Print your Tox ID's QR code to a file.\n");
|
||||||
|
#else
|
||||||
wprintw(win, " /myqr : Print your Tox ID's QR code to a file.\n");
|
wprintw(win, " /myqr : Print your Tox ID's QR code to a file.\n");
|
||||||
|
#endif /* QRPNG */
|
||||||
wprintw(win, " /clear : Clear window history\n");
|
wprintw(win, " /clear : Clear window history\n");
|
||||||
wprintw(win, " /close : Close the current chat window\n");
|
wprintw(win, " /close : Close the current chat window\n");
|
||||||
wprintw(win, " /quit or /exit : Exit Toxic\n");
|
wprintw(win, " /quit or /exit : Exit Toxic\n");
|
||||||
@ -181,10 +200,18 @@ static void help_draw_global(ToxWindow *self)
|
|||||||
wprintw(win, " /svdev <type> <id> : Set active video device\n");
|
wprintw(win, " /svdev <type> <id> : Set active video device\n");
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
|
|
||||||
|
#ifdef PYTHON
|
||||||
|
wattron(win, A_BOLD);
|
||||||
|
wprintw(win, "\n Scripting:\n");
|
||||||
|
wattroff(win, A_BOLD);
|
||||||
|
|
||||||
|
wprintw(win, " /run <path> : Load and run the script at path\n");
|
||||||
|
#endif /* PYTHON */
|
||||||
|
|
||||||
help_draw_bottom_menu(win);
|
help_draw_bottom_menu(win);
|
||||||
|
|
||||||
box(win, ACS_VLINE, ACS_HLINE);
|
box(win, ACS_VLINE, ACS_HLINE);
|
||||||
wrefresh(win);
|
wnoutrefresh(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void help_draw_chat(ToxWindow *self)
|
static void help_draw_chat(ToxWindow *self)
|
||||||
@ -215,6 +242,7 @@ static void help_draw_chat(ToxWindow *self)
|
|||||||
wprintw(win, " /sdev <type> <id> : Change active device\n");
|
wprintw(win, " /sdev <type> <id> : Change active device\n");
|
||||||
wprintw(win, " /mute <type> : Mute active device if in call\n");
|
wprintw(win, " /mute <type> : Mute active device if in call\n");
|
||||||
wprintw(win, " /sense <n> : VAD sensitivity threshold\n");
|
wprintw(win, " /sense <n> : VAD sensitivity threshold\n");
|
||||||
|
wprintw(win, " /bitrate <n> : Set the audio encoding bitrate\n");
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
@ -227,7 +255,7 @@ static void help_draw_chat(ToxWindow *self)
|
|||||||
help_draw_bottom_menu(win);
|
help_draw_bottom_menu(win);
|
||||||
|
|
||||||
box(win, ACS_VLINE, ACS_HLINE);
|
box(win, ACS_VLINE, ACS_HLINE);
|
||||||
wrefresh(win);
|
wnoutrefresh(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void help_draw_keys(ToxWindow *self)
|
static void help_draw_keys(ToxWindow *self)
|
||||||
@ -253,7 +281,7 @@ static void help_draw_keys(ToxWindow *self)
|
|||||||
help_draw_bottom_menu(win);
|
help_draw_bottom_menu(win);
|
||||||
|
|
||||||
box(win, ACS_VLINE, ACS_HLINE);
|
box(win, ACS_VLINE, ACS_HLINE);
|
||||||
wrefresh(win);
|
wnoutrefresh(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void help_draw_group(ToxWindow *self)
|
static void help_draw_group(ToxWindow *self)
|
||||||
@ -271,9 +299,29 @@ static void help_draw_group(ToxWindow *self)
|
|||||||
help_draw_bottom_menu(win);
|
help_draw_bottom_menu(win);
|
||||||
|
|
||||||
box(win, ACS_VLINE, ACS_HLINE);
|
box(win, ACS_VLINE, ACS_HLINE);
|
||||||
wrefresh(win);
|
wnoutrefresh(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
static void help_draw_contacts(ToxWindow *self)
|
static void help_draw_contacts(ToxWindow *self)
|
||||||
{
|
{
|
||||||
WINDOW *win = self->help->win;
|
WINDOW *win = self->help->win;
|
||||||
@ -293,12 +341,14 @@ static void help_draw_contacts(ToxWindow *self)
|
|||||||
help_draw_bottom_menu(win);
|
help_draw_bottom_menu(win);
|
||||||
|
|
||||||
box(win, ACS_VLINE, ACS_HLINE);
|
box(win, ACS_VLINE, ACS_HLINE);
|
||||||
wrefresh(win);
|
wnoutrefresh(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
void help_onKey(ToxWindow *self, wint_t key)
|
void help_onKey(ToxWindow *self, wint_t key)
|
||||||
{
|
{
|
||||||
switch(key) {
|
int height;
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
case 'x':
|
case 'x':
|
||||||
case T_KEY_ESC:
|
case T_KEY_ESC:
|
||||||
help_exit(self);
|
help_exit(self);
|
||||||
@ -306,9 +356,9 @@ void help_onKey(ToxWindow *self, wint_t key)
|
|||||||
|
|
||||||
case 'c':
|
case 'c':
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
help_init_window(self, 22, 80);
|
help_init_window(self, 23, 80);
|
||||||
#elif AUDIO
|
#elif AUDIO
|
||||||
help_init_window(self, 19, 80);
|
help_init_window(self, 20, 80);
|
||||||
#else
|
#else
|
||||||
help_init_window(self, 10, 80);
|
help_init_window(self, 10, 80);
|
||||||
#endif
|
#endif
|
||||||
@ -316,13 +366,16 @@ void help_onKey(ToxWindow *self, wint_t key)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'g':
|
case 'g':
|
||||||
|
height = 22;
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
help_init_window(self, 30, 80);
|
height += 8;
|
||||||
#elif AUDIO
|
#elif AUDIO
|
||||||
help_init_window(self, 26, 80);
|
height += 4;
|
||||||
#else
|
|
||||||
help_init_window(self, 22, 80);
|
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef PYTHON
|
||||||
|
height += 2;
|
||||||
|
#endif
|
||||||
|
help_init_window(self, height, 80);
|
||||||
self->help->type = HELP_GLOBAL;
|
self->help->type = HELP_GLOBAL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -331,6 +384,14 @@ void help_onKey(ToxWindow *self, wint_t key)
|
|||||||
self->help->type = HELP_GROUP;
|
self->help->type = HELP_GROUP;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
#ifdef PYTHON
|
||||||
|
|
||||||
|
case 'p':
|
||||||
|
help_init_window(self, 4 + num_registered_handlers(), help_max_width());
|
||||||
|
self->help->type = HELP_PLUGIN;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
help_init_window(self, 10, 80);
|
help_init_window(self, 10, 80);
|
||||||
self->help->type = HELP_CONTACTS;
|
self->help->type = HELP_CONTACTS;
|
||||||
@ -350,9 +411,7 @@ void help_onKey(ToxWindow *self, wint_t key)
|
|||||||
|
|
||||||
void help_onDraw(ToxWindow *self)
|
void help_onDraw(ToxWindow *self)
|
||||||
{
|
{
|
||||||
curs_set(0);
|
switch (self->help->type) {
|
||||||
|
|
||||||
switch(self->help->type) {
|
|
||||||
case HELP_MENU:
|
case HELP_MENU:
|
||||||
help_draw_menu(self);
|
help_draw_menu(self);
|
||||||
return;
|
return;
|
||||||
@ -376,5 +435,12 @@ void help_onDraw(ToxWindow *self)
|
|||||||
case HELP_GROUP:
|
case HELP_GROUP:
|
||||||
help_draw_group(self);
|
help_draw_group(self);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
#ifdef PYTHON
|
||||||
|
|
||||||
|
case HELP_PLUGIN:
|
||||||
|
help_draw_plugin(self);
|
||||||
|
break;
|
||||||
|
#endif /* PYTHON */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,9 @@ typedef enum {
|
|||||||
HELP_GROUP,
|
HELP_GROUP,
|
||||||
HELP_KEYS,
|
HELP_KEYS,
|
||||||
HELP_CONTACTS,
|
HELP_CONTACTS,
|
||||||
|
#ifdef PYTHON
|
||||||
|
HELP_PLUGIN,
|
||||||
|
#endif
|
||||||
} HELP_TYPES;
|
} HELP_TYPES;
|
||||||
|
|
||||||
void help_onDraw(ToxWindow *self);
|
void help_onDraw(ToxWindow *self);
|
||||||
|
@ -275,9 +275,9 @@ bool input_handle(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y)
|
|||||||
self->show_peerlist ^= 1;
|
self->show_peerlist ^= 1;
|
||||||
redraw_groupchat_win(self);
|
redraw_groupchat_win(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
match = true;
|
match = true;
|
||||||
}
|
} else if (key == user_settings->key_toggle_pastemode) {
|
||||||
else if (key == user_settings->key_toggle_pastemode) {
|
|
||||||
self->chatwin->pastemode ^= 1;
|
self->chatwin->pastemode ^= 1;
|
||||||
match = true;
|
match = true;
|
||||||
}
|
}
|
||||||
|
@ -129,17 +129,21 @@ static struct line_info *line_info_ret_queue(struct history *hst)
|
|||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* creates new line_info line and puts it in the queue. */
|
/* creates new line_info line and puts it in the queue.
|
||||||
void line_info_add(ToxWindow *self, const char *timestr, const char *name1, const char *name2, uint8_t type,
|
*
|
||||||
uint8_t bold, uint8_t colour, const char *msg, ...)
|
* Returns the id of the new line.
|
||||||
|
* Returns -1 on failure.
|
||||||
|
*/
|
||||||
|
int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const char *name2, uint8_t type,
|
||||||
|
uint8_t bold, uint8_t colour, const char *msg, ...)
|
||||||
{
|
{
|
||||||
if (!self)
|
if (!self)
|
||||||
return;
|
return -1;
|
||||||
|
|
||||||
struct history *hst = self->chatwin->hst;
|
struct history *hst = self->chatwin->hst;
|
||||||
|
|
||||||
if (hst->queue_sz >= MAX_LINE_INFO_QUEUE)
|
if (hst->queue_sz >= MAX_LINE_INFO_QUEUE)
|
||||||
return;
|
return -1;
|
||||||
|
|
||||||
struct line_info *new_line = calloc(1, sizeof(struct line_info));
|
struct line_info *new_line = calloc(1, sizeof(struct line_info));
|
||||||
|
|
||||||
@ -158,12 +162,14 @@ void line_info_add(ToxWindow *self, const char *timestr, const char *name1, cons
|
|||||||
/* for type-specific formatting in print function */
|
/* for type-specific formatting in print function */
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case IN_ACTION:
|
case IN_ACTION:
|
||||||
|
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case OUT_ACTION:
|
case OUT_ACTION:
|
||||||
len += strlen(user_settings->line_normal) + 2;
|
len += strlen(user_settings->line_normal) + 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IN_MSG:
|
case IN_MSG:
|
||||||
|
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case OUT_MSG:
|
case OUT_MSG:
|
||||||
len += strlen(user_settings->line_normal) + 3;
|
len += strlen(user_settings->line_normal) + 3;
|
||||||
@ -220,6 +226,7 @@ void line_info_add(ToxWindow *self, const char *timestr, const char *name1, cons
|
|||||||
len += strlen(new_line->name2);
|
len += strlen(new_line->name2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_line->id = (hst->line_end->id + 1 + hst->queue_sz) % INT_MAX;
|
||||||
new_line->len = len;
|
new_line->len = len;
|
||||||
new_line->type = type;
|
new_line->type = type;
|
||||||
new_line->bold = bold;
|
new_line->bold = bold;
|
||||||
@ -228,6 +235,8 @@ void line_info_add(ToxWindow *self, const char *timestr, const char *name1, cons
|
|||||||
new_line->timestamp = get_unix_time();
|
new_line->timestamp = get_unix_time();
|
||||||
|
|
||||||
hst->queue[hst->queue_sz++] = new_line;
|
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() */
|
/* adds a single queue item to hst if possible. only called once per call to line_info_print() */
|
||||||
@ -242,10 +251,10 @@ static void line_info_check_queue(ToxWindow *self)
|
|||||||
if (hst->start_id > user_settings->history_size)
|
if (hst->start_id > user_settings->history_size)
|
||||||
line_info_root_fwd(hst);
|
line_info_root_fwd(hst);
|
||||||
|
|
||||||
line->id = hst->line_end->id + 1;
|
|
||||||
line->prev = hst->line_end;
|
line->prev = hst->line_end;
|
||||||
hst->line_end->next = line;
|
hst->line_end->next = line;
|
||||||
hst->line_end = line;
|
hst->line_end = line;
|
||||||
|
hst->line_end->id = line->id;
|
||||||
|
|
||||||
int y, y2, x, x2;
|
int y, y2, x, x2;
|
||||||
getmaxyx(self->window, y2, x2);
|
getmaxyx(self->window, y2, x2);
|
||||||
@ -304,8 +313,10 @@ void line_info_print(ToxWindow *self)
|
|||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case OUT_MSG:
|
case OUT_MSG:
|
||||||
|
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case OUT_MSG_READ:
|
case OUT_MSG_READ:
|
||||||
|
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case IN_MSG:
|
case IN_MSG:
|
||||||
wattron(win, COLOR_PAIR(BLUE));
|
wattron(win, COLOR_PAIR(BLUE));
|
||||||
@ -323,10 +334,10 @@ void line_info_print(ToxWindow *self)
|
|||||||
wprintw(win, "%s %s: ", user_settings->line_normal, line->name1);
|
wprintw(win, "%s %s: ", user_settings->line_normal, line->name1);
|
||||||
wattroff(win, COLOR_PAIR(nameclr));
|
wattroff(win, COLOR_PAIR(nameclr));
|
||||||
|
|
||||||
char* msg = line->msg;
|
char *msg = line->msg;
|
||||||
while (msg)
|
|
||||||
{
|
while (msg) {
|
||||||
char* line = strsep(&msg, "\n");
|
char *line = strsep(&msg, "\n");
|
||||||
|
|
||||||
if (line[0] == '>')
|
if (line[0] == '>')
|
||||||
wattron(win, COLOR_PAIR(GREEN));
|
wattron(win, COLOR_PAIR(GREEN));
|
||||||
@ -360,8 +371,10 @@ void line_info_print(ToxWindow *self)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OUT_ACTION_READ:
|
case OUT_ACTION_READ:
|
||||||
|
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case OUT_ACTION:
|
case OUT_ACTION:
|
||||||
|
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case IN_ACTION:
|
case IN_ACTION:
|
||||||
wattron(win, COLOR_PAIR(BLUE));
|
wattron(win, COLOR_PAIR(BLUE));
|
||||||
@ -548,20 +561,15 @@ bool line_info_onKey(ToxWindow *self, wint_t key)
|
|||||||
|
|
||||||
if (key == user_settings->key_half_page_up) {
|
if (key == user_settings->key_half_page_up) {
|
||||||
line_info_page_up(self, hst);
|
line_info_page_up(self, hst);
|
||||||
}
|
} else if (key == user_settings->key_half_page_down) {
|
||||||
else if (key == user_settings->key_half_page_down) {
|
|
||||||
line_info_page_down(self, hst);
|
line_info_page_down(self, hst);
|
||||||
}
|
} else if (key == user_settings->key_scroll_line_up) {
|
||||||
else if (key == user_settings->key_scroll_line_up) {
|
|
||||||
line_info_scroll_up(hst);
|
line_info_scroll_up(hst);
|
||||||
}
|
} else if (key == user_settings->key_scroll_line_down) {
|
||||||
else if (key == user_settings->key_scroll_line_down) {
|
|
||||||
line_info_scroll_down(hst);
|
line_info_scroll_down(hst);
|
||||||
}
|
} else if (key == user_settings->key_page_bottom) {
|
||||||
else if (key == user_settings->key_page_bottom) {
|
|
||||||
line_info_reset_start(self, hst);
|
line_info_reset_start(self, hst);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
match = false;
|
match = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,9 +74,13 @@ struct history {
|
|||||||
int queue_sz;
|
int queue_sz;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* creates new line_info line and puts it in the queue. */
|
/* creates new line_info line and puts it in the queue.
|
||||||
void line_info_add(ToxWindow *self, const char *timestr, const char *name1, const char *name2, uint8_t type,
|
*
|
||||||
uint8_t bold, uint8_t colour, const char *msg, ...);
|
* Returns the id of the new line.
|
||||||
|
* Returns -1 on failure.
|
||||||
|
*/
|
||||||
|
int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const char *name2, uint8_t type,
|
||||||
|
uint8_t bold, uint8_t colour, const char *msg, ...);
|
||||||
|
|
||||||
/* Prints a section of history starting at line_start */
|
/* Prints a section of history starting at line_start */
|
||||||
void line_info_print(ToxWindow *self);
|
void line_info_print(ToxWindow *self);
|
||||||
|
@ -262,6 +262,7 @@ int rename_logfile(char *src, char *dest, const char *selfkey, const char *other
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
on_error:
|
on_error:
|
||||||
|
|
||||||
if (log_on)
|
if (log_on)
|
||||||
log_enable(src, selfkey, otherkey, log, LOG_CHAT);
|
log_enable(src, selfkey, otherkey, log, LOG_CHAT);
|
||||||
|
|
||||||
|
@ -42,8 +42,12 @@ void cqueue_cleanup(struct chat_queue *q)
|
|||||||
free(q);
|
free(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, uint32_t line_id)
|
void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, int line_id)
|
||||||
{
|
{
|
||||||
|
if (line_id < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
struct cqueue_msg *new_m = malloc(sizeof(struct cqueue_msg));
|
struct cqueue_msg *new_m = malloc(sizeof(struct cqueue_msg));
|
||||||
|
|
||||||
if (new_m == NULL)
|
if (new_m == NULL)
|
||||||
|
@ -40,7 +40,7 @@ struct chat_queue {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void cqueue_cleanup(struct chat_queue *q);
|
void cqueue_cleanup(struct chat_queue *q);
|
||||||
void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, uint32_t line_id);
|
void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, int line_id);
|
||||||
|
|
||||||
/* Tries to send the oldest unsent message in queue. */
|
/* Tries to send the oldest unsent message in queue. */
|
||||||
void cqueue_try_send(ToxWindow *self, Tox *m);
|
void cqueue_try_send(ToxWindow *self, Tox *m);
|
||||||
|
@ -26,9 +26,12 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#if SYSTEM == BSD
|
||||||
#include <sys/stat.h>
|
#include <netinet/in.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#endif /* BSD! */
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
@ -70,7 +73,7 @@ struct tm *get_time(void)
|
|||||||
{
|
{
|
||||||
struct tm *timeinfo;
|
struct tm *timeinfo;
|
||||||
time_t t = get_unix_time();
|
time_t t = get_unix_time();
|
||||||
timeinfo = localtime((const time_t*) &t);
|
timeinfo = localtime((const time_t *) &t);
|
||||||
return timeinfo;
|
return timeinfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +159,7 @@ int bin_id_to_string(const char *bin_id, size_t bin_id_size, char *output, size_
|
|||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < TOX_ADDRESS_SIZE; ++i)
|
for (i = 0; i < TOX_ADDRESS_SIZE; ++i)
|
||||||
snprintf(&output[i*2], output_size - (i * 2), "%02X", bin_id[i] & 0xff);
|
snprintf(&output[i * 2], output_size - (i * 2), "%02X", bin_id[i] & 0xff);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -187,7 +190,7 @@ int mbs_to_wcs_buf(wchar_t *buf, const char *string, size_t n)
|
|||||||
if (n < len)
|
if (n < len)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if ((len = mbstowcs(buf, string, n)) == (size_t) -1)
|
if ((len = mbstowcs(buf, string, n)) == (size_t) - 1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
@ -201,7 +204,7 @@ int wcs_to_mbs_buf(char *buf, const wchar_t *string, size_t n)
|
|||||||
if (n < len)
|
if (n < len)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if ((len = wcstombs(buf, string, n)) == (size_t) -1)
|
if ((len = wcstombs(buf, string, n)) == (size_t) - 1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
@ -228,11 +231,11 @@ int valid_nick(const char *nick)
|
|||||||
|
|
||||||
for (i = 0; nick[i]; ++i) {
|
for (i = 0; nick[i]; ++i) {
|
||||||
if ((nick[i] == ' ' && nick[i + 1] == ' ')
|
if ((nick[i] == ' ' && nick[i + 1] == ' ')
|
||||||
|| nick[i] == '/'
|
|| nick[i] == '/'
|
||||||
|| nick[i] == '\n'
|
|| nick[i] == '\n'
|
||||||
|| nick[i] == '\t'
|
|| nick[i] == '\t'
|
||||||
|| nick[i] == '\v'
|
|| nick[i] == '\v'
|
||||||
|| nick[i] == '\r')
|
|| nick[i] == '\r')
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -319,45 +322,71 @@ void str_to_lower(char *str)
|
|||||||
Returns nick len */
|
Returns nick len */
|
||||||
size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum)
|
size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum)
|
||||||
{
|
{
|
||||||
size_t len = tox_friend_get_name_size(m, friendnum, NULL);
|
TOX_ERR_FRIEND_QUERY err;
|
||||||
|
size_t len = tox_friend_get_name_size(m, friendnum, &err);
|
||||||
|
|
||||||
if (len == 0) {
|
if (err != TOX_ERR_FRIEND_QUERY_OK) {
|
||||||
strcpy(buf, UNKNOWN_NAME);
|
goto on_error;
|
||||||
len = strlen(UNKNOWN_NAME);
|
|
||||||
} else {
|
} else {
|
||||||
tox_friend_get_name(m, friendnum, (uint8_t *) buf, NULL);
|
if (!tox_friend_get_name(m, friendnum, (uint8_t *) buf, NULL)) {
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
|
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
|
||||||
buf[len] = '\0';
|
buf[len] = '\0';
|
||||||
filter_str(buf, len);
|
filter_str(buf, len);
|
||||||
return len;
|
return len;
|
||||||
|
|
||||||
|
on_error:
|
||||||
|
strcpy(buf, UNKNOWN_NAME);
|
||||||
|
len = strlen(UNKNOWN_NAME);
|
||||||
|
buf[len] = '\0';
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* same as get_nick_truncate but for groupchats */
|
/* same as get_nick_truncate but for groupchats */
|
||||||
int get_group_nick_truncate(Tox *m, char *buf, int peernum, int groupnum)
|
int get_group_nick_truncate(Tox *m, char *buf, uint32_t peernum, uint32_t groupnum)
|
||||||
{
|
{
|
||||||
int len = tox_group_peername(m, groupnum, peernum, (uint8_t *) buf);
|
TOX_ERR_CONFERENCE_PEER_QUERY err;
|
||||||
|
size_t len = tox_conference_peer_get_name_size(m, groupnum, peernum, &err);
|
||||||
|
|
||||||
if (len == -1) {
|
if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
|
||||||
strcpy(buf, UNKNOWN_NAME);
|
goto on_error;
|
||||||
len = strlen(UNKNOWN_NAME);
|
} else {
|
||||||
|
if (!tox_conference_peer_get_name(m, groupnum, peernum, (uint8_t *) buf, NULL)) {
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
|
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
|
||||||
buf[len] = '\0';
|
buf[len] = '\0';
|
||||||
filter_str(buf, len);
|
filter_str(buf, len);
|
||||||
return len;
|
return len;
|
||||||
|
|
||||||
|
on_error:
|
||||||
|
strcpy(buf, UNKNOWN_NAME);
|
||||||
|
len = strlen(UNKNOWN_NAME);
|
||||||
|
buf[len] = '\0';
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copies data to msg buffer.
|
/* copies data to msg buffer, removing return characters.
|
||||||
returns length of msg, which will be no larger than size-1 */
|
returns length of msg, which will be no larger than size-1 */
|
||||||
size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length)
|
size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length)
|
||||||
{
|
{
|
||||||
size_t len = MIN(length, size - 1);
|
size_t i;
|
||||||
memcpy(msg, data, len);
|
size_t j = 0;
|
||||||
msg[len] = '\0';
|
|
||||||
return len;
|
for (i = 0; (i < length) && (j < size - 1); ++i) {
|
||||||
|
if (data[i] != '\r') {
|
||||||
|
msg[j++] = data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
msg[j] = '\0';
|
||||||
|
|
||||||
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns index of the first instance of ch in s starting at idx.
|
/* returns index of the first instance of ch in s starting at idx.
|
||||||
|
@ -126,7 +126,7 @@ void str_to_lower(char *str);
|
|||||||
size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum);
|
size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum);
|
||||||
|
|
||||||
/* same as get_nick_truncate but for groupchats */
|
/* same as get_nick_truncate but for groupchats */
|
||||||
int get_group_nick_truncate(Tox *m, char *buf, int peernum, int groupnum);
|
int get_group_nick_truncate(Tox *m, char *buf, uint32_t peernum, uint32_t groupnum);
|
||||||
|
|
||||||
/* copies data to msg buffer.
|
/* copies data to msg buffer.
|
||||||
returns length of msg, which will be no larger than size-1 */
|
returns length of msg, which will be no larger than size-1 */
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
|
||||||
@ -249,21 +250,29 @@ void *lookup_thread_func(void *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct Recv_Curl_Data recv_data;
|
struct Recv_Curl_Data recv_data;
|
||||||
|
|
||||||
memset(&recv_data, 0, sizeof(struct Recv_Curl_Data));
|
memset(&recv_data, 0, sizeof(struct Recv_Curl_Data));
|
||||||
|
|
||||||
char post_data[MAX_STR_SIZE];
|
char post_data[MAX_STR_SIZE];
|
||||||
|
|
||||||
snprintf(post_data, sizeof(post_data), "{\"action\": 3, \"name\": \"%s\"}", name);
|
snprintf(post_data, sizeof(post_data), "{\"action\": 3, \"name\": \"%s\"}", name);
|
||||||
|
|
||||||
struct curl_slist *headers = NULL;
|
struct curl_slist *headers = NULL;
|
||||||
|
|
||||||
headers = curl_slist_append(headers, "Content-Type: application/json");
|
headers = curl_slist_append(headers, "Content-Type: application/json");
|
||||||
|
|
||||||
headers = curl_slist_append(headers, "charsets: utf-8");
|
headers = curl_slist_append(headers, "charsets: utf-8");
|
||||||
|
|
||||||
curl_easy_setopt(c_handle, CURLOPT_HTTPHEADER, headers);
|
curl_easy_setopt(c_handle, CURLOPT_HTTPHEADER, headers);
|
||||||
|
|
||||||
curl_easy_setopt(c_handle, CURLOPT_URL, real_domain);
|
curl_easy_setopt(c_handle, CURLOPT_URL, real_domain);
|
||||||
|
|
||||||
curl_easy_setopt(c_handle, CURLOPT_WRITEFUNCTION, curl_cb_write_data);
|
curl_easy_setopt(c_handle, CURLOPT_WRITEFUNCTION, curl_cb_write_data);
|
||||||
|
|
||||||
curl_easy_setopt(c_handle, CURLOPT_WRITEDATA, &recv_data);
|
curl_easy_setopt(c_handle, CURLOPT_WRITEDATA, &recv_data);
|
||||||
|
|
||||||
curl_easy_setopt(c_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
|
curl_easy_setopt(c_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
|
||||||
|
|
||||||
curl_easy_setopt(c_handle, CURLOPT_POSTFIELDS, post_data);
|
curl_easy_setopt(c_handle, CURLOPT_POSTFIELDS, post_data);
|
||||||
|
|
||||||
int proxy_ret = set_curl_proxy(c_handle, arg_opts.proxy_address, arg_opts.proxy_port, arg_opts.proxy_type);
|
int proxy_ret = set_curl_proxy(c_handle, arg_opts.proxy_address, arg_opts.proxy_port, arg_opts.proxy_type);
|
||||||
|
164
src/notify.c
164
src/notify.c
@ -38,24 +38,24 @@
|
|||||||
#include "xtra.h"
|
#include "xtra.h"
|
||||||
|
|
||||||
#if defined(AUDIO) || defined(SOUND_NOTIFY)
|
#if defined(AUDIO) || defined(SOUND_NOTIFY)
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <OpenAL/al.h>
|
#include <OpenAL/al.h>
|
||||||
#include <OpenAL/alc.h>
|
#include <OpenAL/alc.h>
|
||||||
#else
|
#else
|
||||||
#include <AL/al.h>
|
#include <AL/al.h>
|
||||||
#include <AL/alc.h>
|
#include <AL/alc.h>
|
||||||
/* compatibility with older versions of OpenAL */
|
/* compatibility with older versions of OpenAL */
|
||||||
#ifndef ALC_ALL_DEVICES_SPECIFIER
|
#ifndef ALC_ALL_DEVICES_SPECIFIER
|
||||||
#include <AL/alext.h>
|
#include <AL/alext.h>
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
#include <AL/alut.h> /* freealut packet */
|
#include <AL/alut.h> /* freealut packet */
|
||||||
#endif
|
#endif
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
#include <libnotify/notify.h>
|
#include <libnotify/notify.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MAX_BOX_MSG_LEN 127
|
#define MAX_BOX_MSG_LEN 127
|
||||||
@ -75,7 +75,7 @@ struct Control {
|
|||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
uint32_t device_idx; /* index of output device */
|
uint32_t device_idx; /* index of output device */
|
||||||
char* sounds[SOUNDS_SIZE];
|
char *sounds[SOUNDS_SIZE];
|
||||||
#endif /* SOUND_NOTIFY */
|
#endif /* SOUND_NOTIFY */
|
||||||
} Control = {0};
|
} Control = {0};
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ struct _ActiveNotifications {
|
|||||||
bool active;
|
bool active;
|
||||||
int *id_indicator;
|
int *id_indicator;
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
NotifyNotification* box;
|
NotifyNotification *box;
|
||||||
char messages[MAX_BOX_MSG_LEN + 1][MAX_BOX_MSG_LEN + 1];
|
char messages[MAX_BOX_MSG_LEN + 1][MAX_BOX_MSG_LEN + 1];
|
||||||
char title[64];
|
char title[64];
|
||||||
size_t size;
|
size_t size;
|
||||||
@ -188,15 +188,17 @@ void graceful_clear()
|
|||||||
|
|
||||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
||||||
if (actives[i].active) {
|
if (actives[i].active) {
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
|
|
||||||
if (actives[i].box) {
|
if (actives[i].box) {
|
||||||
GError* ignore;
|
GError *ignore;
|
||||||
notify_notification_close(actives[i].box, &ignore);
|
notify_notification_close(actives[i].box, &ignore);
|
||||||
actives[i].box = NULL;
|
actives[i].box = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if(actives[i].id_indicator)
|
#endif
|
||||||
|
|
||||||
|
if (actives[i].id_indicator)
|
||||||
*actives[i].id_indicator = -1; /* reset indicator value */
|
*actives[i].id_indicator = -1; /* reset indicator value */
|
||||||
|
|
||||||
if ( actives[i].looping ) {
|
if ( actives[i].looping ) {
|
||||||
@ -221,11 +223,11 @@ void graceful_clear()
|
|||||||
control_unlock();
|
control_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void* do_playing(void* _p)
|
void *do_playing(void *_p)
|
||||||
{
|
{
|
||||||
(void)_p;
|
(void)_p;
|
||||||
|
|
||||||
while(true) {
|
while (true) {
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
if (!Control.poll_active) {
|
if (!Control.poll_active) {
|
||||||
@ -240,59 +242,67 @@ void* do_playing(void* _p)
|
|||||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
||||||
|
|
||||||
if (actives[i].looping) has_looping = true;
|
if (actives[i].looping) has_looping = true;
|
||||||
|
|
||||||
test_active_notify = actives[i].active && !actives[i].looping;
|
test_active_notify = actives[i].active && !actives[i].looping;
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
test_active_notify = test_active_notify && !actives[i].box;
|
test_active_notify = test_active_notify && !actives[i].box;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (test_active_notify) {
|
if (test_active_notify) {
|
||||||
if(actives[i].id_indicator)
|
if (actives[i].id_indicator)
|
||||||
*actives[i].id_indicator = -1; /* reset indicator value */
|
*actives[i].id_indicator = -1; /* reset indicator value */
|
||||||
|
|
||||||
if (!is_playing(actives[i].source)) {
|
if (!is_playing(actives[i].source)) {
|
||||||
/* Close */
|
/* Close */
|
||||||
alSourceStop(actives[i].source);
|
alSourceStop(actives[i].source);
|
||||||
alDeleteSources(1, &actives[i].source);
|
alDeleteSources(1, &actives[i].source);
|
||||||
alDeleteBuffers(1, &actives[i].buffer);
|
alDeleteBuffers(1, &actives[i].buffer);
|
||||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef BOX_NOTIFY
|
|
||||||
else if (actives[i].box && time(NULL) >= actives[i].n_timeout)
|
#ifdef BOX_NOTIFY
|
||||||
{
|
else if (actives[i].box && time(NULL) >= actives[i].n_timeout) {
|
||||||
GError* ignore;
|
GError *ignore;
|
||||||
notify_notification_close(actives[i].box, &ignore);
|
notify_notification_close(actives[i].box, &ignore);
|
||||||
actives[i].box = NULL;
|
actives[i].box = NULL;
|
||||||
if(actives[i].id_indicator)
|
|
||||||
|
if (actives[i].id_indicator)
|
||||||
*actives[i].id_indicator = -1; /* reset indicator value */
|
*actives[i].id_indicator = -1; /* reset indicator value */
|
||||||
|
|
||||||
if (!actives[i].looping && !is_playing(actives[i].source)) {
|
if (!actives[i].looping && !is_playing(actives[i].source)) {
|
||||||
/* stop source if not looping or playing, just terminate box */
|
/* stop source if not looping or playing, just terminate box */
|
||||||
alSourceStop(actives[i].source);
|
alSourceStop(actives[i].source);
|
||||||
alDeleteSources(1, &actives[i].source);
|
alDeleteSources(1, &actives[i].source);
|
||||||
alDeleteBuffers(1, &actives[i].buffer);
|
alDeleteBuffers(1, &actives[i].buffer);
|
||||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* device is opened and no activity in under DEVICE_COOLDOWN time, close device*/
|
/* device is opened and no activity in under DEVICE_COOLDOWN time, close device*/
|
||||||
if (device_opened && !has_looping &&
|
if (device_opened && !has_looping &&
|
||||||
(time(NULL) - last_opened_update) > DEVICE_COOLDOWN) {
|
(time(NULL) - last_opened_update) > DEVICE_COOLDOWN) {
|
||||||
m_close_device();
|
m_close_device();
|
||||||
}
|
}
|
||||||
|
|
||||||
has_looping = false;
|
has_looping = false;
|
||||||
|
|
||||||
control_unlock();
|
control_unlock();
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int play_source(uint32_t source, uint32_t buffer, bool looping)
|
int play_source(uint32_t source, uint32_t buffer, bool looping)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
for (; i < ACTIVE_NOTIFS_MAX && actives[i].active; i ++);
|
for (; i < ACTIVE_NOTIFS_MAX && actives[i].active; i ++);
|
||||||
|
|
||||||
if ( i == ACTIVE_NOTIFS_MAX ) {
|
if ( i == ACTIVE_NOTIFS_MAX ) {
|
||||||
return -1; /* Full */
|
return -1; /* Full */
|
||||||
}
|
}
|
||||||
@ -308,11 +318,11 @@ int play_source(uint32_t source, uint32_t buffer, bool looping)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#elif BOX_NOTIFY
|
#elif BOX_NOTIFY
|
||||||
void* do_playing(void* _p)
|
void *do_playing(void *_p)
|
||||||
{
|
{
|
||||||
(void)_p;
|
(void)_p;
|
||||||
|
|
||||||
while(true) {
|
while (true) {
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
if (!Control.poll_active) {
|
if (!Control.poll_active) {
|
||||||
@ -323,20 +333,22 @@ void* do_playing(void* _p)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
||||||
if (actives[i].box && time(NULL) >= actives[i].n_timeout)
|
if (actives[i].box && time(NULL) >= actives[i].n_timeout) {
|
||||||
{
|
GError *ignore;
|
||||||
GError* ignore;
|
|
||||||
notify_notification_close(actives[i].box, &ignore);
|
notify_notification_close(actives[i].box, &ignore);
|
||||||
actives[i].box = NULL;
|
actives[i].box = NULL;
|
||||||
if(actives[i].id_indicator)
|
|
||||||
|
if (actives[i].id_indicator)
|
||||||
*actives[i].id_indicator = -1; /* reset indicator value */
|
*actives[i].id_indicator = -1; /* reset indicator value */
|
||||||
|
|
||||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
control_unlock();
|
control_unlock();
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,7 +359,7 @@ void graceful_clear()
|
|||||||
|
|
||||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
||||||
if (actives[i].box) {
|
if (actives[i].box) {
|
||||||
GError* ignore;
|
GError *ignore;
|
||||||
notify_notification_close(actives[i].box, &ignore);
|
notify_notification_close(actives[i].box, &ignore);
|
||||||
actives[i].box = NULL;
|
actives[i].box = NULL;
|
||||||
}
|
}
|
||||||
@ -378,6 +390,7 @@ int init_notify(int login_cooldown, int notification_timeout)
|
|||||||
#endif /* SOUND_NOTIFY */
|
#endif /* SOUND_NOTIFY */
|
||||||
|
|
||||||
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
||||||
|
|
||||||
if (pthread_mutex_init(Control.poll_mutex, NULL) != 0)
|
if (pthread_mutex_init(Control.poll_mutex, NULL) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -419,7 +432,9 @@ void terminate_notify()
|
|||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
for (; i < SOUNDS_SIZE; i ++) free(Control.sounds[i]);
|
for (; i < SOUNDS_SIZE; i ++) free(Control.sounds[i]);
|
||||||
|
|
||||||
alutExit();
|
alutExit();
|
||||||
#endif /* SOUND_NOTIFY */
|
#endif /* SOUND_NOTIFY */
|
||||||
|
|
||||||
@ -429,7 +444,7 @@ void terminate_notify()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
int set_sound(Notification sound, const char* value)
|
int set_sound(Notification sound, const char *value)
|
||||||
{
|
{
|
||||||
if (sound == silent) return 0;
|
if (sound == silent) return 0;
|
||||||
|
|
||||||
@ -457,10 +472,11 @@ int play_sound_internal(Notification what, bool loop)
|
|||||||
alSourcei(source, AL_LOOPING, loop);
|
alSourcei(source, AL_LOOPING, loop);
|
||||||
|
|
||||||
int rc = play_source(source, buffer, loop);
|
int rc = play_source(source, buffer, loop);
|
||||||
|
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
alSourceStop(source);
|
alSourceStop(source);
|
||||||
alDeleteSources(1, &source);
|
alDeleteSources(1, &source);
|
||||||
alDeleteBuffers(1,&buffer);
|
alDeleteBuffers(1, &buffer);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -472,6 +488,7 @@ int play_notify_sound(Notification notif, uint64_t flags)
|
|||||||
int rc = -1;
|
int rc = -1;
|
||||||
|
|
||||||
if (flags & NT_BEEP) beep();
|
if (flags & NT_BEEP) beep();
|
||||||
|
|
||||||
if (notif != silent) {
|
if (notif != silent) {
|
||||||
if ( !Control.poll_active || !Control.sounds[notif] )
|
if ( !Control.poll_active || !Control.sounds[notif] )
|
||||||
return -1;
|
return -1;
|
||||||
@ -487,17 +504,21 @@ void stop_sound(int id)
|
|||||||
{
|
{
|
||||||
if (id >= 0 && id < ACTIVE_NOTIFS_MAX && actives[id].looping && actives[id].active ) {
|
if (id >= 0 && id < ACTIVE_NOTIFS_MAX && actives[id].looping && actives[id].active ) {
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
|
|
||||||
if (actives[id].box) {
|
if (actives[id].box) {
|
||||||
GError* ignore;
|
GError *ignore;
|
||||||
notify_notification_close(actives[id].box, &ignore);
|
notify_notification_close(actives[id].box, &ignore);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (actives[id].id_indicator)
|
if (actives[id].id_indicator)
|
||||||
*actives[id].id_indicator = -1;
|
*actives[id].id_indicator = -1;
|
||||||
|
|
||||||
// alSourcei(actives[id].source, AL_LOOPING, false);
|
// alSourcei(actives[id].source, AL_LOOPING, false);
|
||||||
alSourceStop(actives[id].source);
|
alSourceStop(actives[id].source);
|
||||||
alDeleteSources(1, &actives[id].source);
|
alDeleteSources(1, &actives[id].source);
|
||||||
alDeleteBuffers(1,&actives[id].buffer);
|
alDeleteBuffers(1, &actives[id].buffer);
|
||||||
memset(&actives[id], 0, sizeof(struct _ActiveNotifications));
|
memset(&actives[id], 0, sizeof(struct _ActiveNotifications));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -508,6 +529,7 @@ static int m_play_sound(Notification notif, uint64_t flags)
|
|||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
return play_notify_sound(notif, flags);
|
return play_notify_sound(notif, flags);
|
||||||
#else
|
#else
|
||||||
|
|
||||||
if (notif != silent)
|
if (notif != silent)
|
||||||
beep();
|
beep();
|
||||||
|
|
||||||
@ -516,12 +538,12 @@ static int m_play_sound(Notification notif, uint64_t flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
void m_notify_action(NotifyNotification *box, char *action, void* data)
|
void m_notify_action(NotifyNotification *box, char *action, void *data)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator)
|
int sound_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indicator)
|
||||||
{
|
{
|
||||||
tab_notify(self, flags);
|
tab_notify(self, flags);
|
||||||
|
|
||||||
@ -540,6 +562,7 @@ int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_in
|
|||||||
|
|
||||||
if (id == -1) {
|
if (id == -1) {
|
||||||
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].box; id++);
|
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].box; id++);
|
||||||
|
|
||||||
if ( id == ACTIVE_NOTIFS_MAX ) {
|
if ( id == ACTIVE_NOTIFS_MAX ) {
|
||||||
control_unlock();
|
control_unlock();
|
||||||
return -1; /* Full */
|
return -1; /* Full */
|
||||||
@ -558,7 +581,7 @@ int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_in
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
|
int sound_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id)
|
||||||
{
|
{
|
||||||
tab_notify(self, flags);
|
tab_notify(self, flags);
|
||||||
|
|
||||||
@ -566,6 +589,7 @@ int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (id < 0 || id >= ACTIVE_NOTIFS_MAX) return -1;
|
if (id < 0 || id >= ACTIVE_NOTIFS_MAX) return -1;
|
||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
@ -578,7 +602,7 @@ int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
|
|||||||
|
|
||||||
alSourceStop(actives[id].source);
|
alSourceStop(actives[id].source);
|
||||||
alDeleteSources(1, &actives[id].source);
|
alDeleteSources(1, &actives[id].source);
|
||||||
alDeleteBuffers(1,&actives[id].buffer);
|
alDeleteBuffers(1, &actives[id].buffer);
|
||||||
|
|
||||||
alGenSources(1, &actives[id].source);
|
alGenSources(1, &actives[id].source);
|
||||||
alGenBuffers(1, &actives[id].buffer);
|
alGenBuffers(1, &actives[id].buffer);
|
||||||
@ -592,6 +616,7 @@ int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
|
|||||||
|
|
||||||
return id;
|
return id;
|
||||||
#else
|
#else
|
||||||
|
|
||||||
if (notif != silent)
|
if (notif != silent)
|
||||||
beep();
|
beep();
|
||||||
|
|
||||||
@ -599,7 +624,8 @@ int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
|
|||||||
#endif /* SOUND_NOTIFY */
|
#endif /* SOUND_NOTIFY */
|
||||||
}
|
}
|
||||||
|
|
||||||
int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator, const char* title, const char* format, ...)
|
int box_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indicator, const char *title,
|
||||||
|
const char *format, ...)
|
||||||
{
|
{
|
||||||
if (notifications_are_disabled(flags)) {
|
if (notifications_are_disabled(flags)) {
|
||||||
tab_notify(self, flags);
|
tab_notify(self, flags);
|
||||||
@ -613,9 +639,11 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi
|
|||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
|
|
||||||
if (id == -1) { /* Could not play */
|
if (id == -1) { /* Could not play */
|
||||||
|
|
||||||
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++);
|
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++);
|
||||||
|
|
||||||
if ( id == ACTIVE_NOTIFS_MAX ) {
|
if ( id == ACTIVE_NOTIFS_MAX ) {
|
||||||
control_unlock();
|
control_unlock();
|
||||||
return -1; /* Full */
|
return -1; /* Full */
|
||||||
@ -623,17 +651,23 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi
|
|||||||
|
|
||||||
actives[id].active = 1;
|
actives[id].active = 1;
|
||||||
actives[id].id_indicator = id_indicator;
|
actives[id].id_indicator = id_indicator;
|
||||||
|
|
||||||
if (id_indicator) *id_indicator = id;
|
if (id_indicator) *id_indicator = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
if (id == -1)
|
if (id == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
#endif /* SOUND_NOTIFY */
|
#endif /* SOUND_NOTIFY */
|
||||||
|
|
||||||
snprintf(actives[id].title, sizeof(actives[id].title), "%s", title);
|
snprintf(actives[id].title, sizeof(actives[id].title), "%s", title);
|
||||||
|
|
||||||
if (strlen(title) > 23) strcpy(actives[id].title + 20, "...");
|
if (strlen(title) > 23) strcpy(actives[id].title + 20, "...");
|
||||||
|
|
||||||
va_list __ARGS__; va_start (__ARGS__, format);
|
va_list __ARGS__;
|
||||||
|
va_start (__ARGS__, format);
|
||||||
vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
|
vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
|
||||||
va_end (__ARGS__);
|
va_end (__ARGS__);
|
||||||
|
|
||||||
@ -656,7 +690,7 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi
|
|||||||
#endif /* BOX_NOTIFY */
|
#endif /* BOX_NOTIFY */
|
||||||
}
|
}
|
||||||
|
|
||||||
int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, const char* format, ...)
|
int box_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id, const char *format, ...)
|
||||||
{
|
{
|
||||||
if (notifications_are_disabled(flags)) {
|
if (notifications_are_disabled(flags)) {
|
||||||
tab_notify(self, flags);
|
tab_notify(self, flags);
|
||||||
@ -675,7 +709,8 @@ int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, con
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
va_list __ARGS__; va_start (__ARGS__, format);
|
va_list __ARGS__;
|
||||||
|
va_start (__ARGS__, format);
|
||||||
vsnprintf (actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __ARGS__);
|
vsnprintf (actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __ARGS__);
|
||||||
va_end (__ARGS__);
|
va_end (__ARGS__);
|
||||||
|
|
||||||
@ -688,7 +723,8 @@ int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, con
|
|||||||
char formated[128 * 129] = {'\0'};
|
char formated[128 * 129] = {'\0'};
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (; i <actives[id].size; i ++) {
|
|
||||||
|
for (; i < actives[id].size; i ++) {
|
||||||
strcat(formated, actives[id].messages[i]);
|
strcat(formated, actives[id].messages[i]);
|
||||||
strcat(formated, "\n");
|
strcat(formated, "\n");
|
||||||
}
|
}
|
||||||
@ -706,7 +742,7 @@ int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, con
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const char* title, const char* format, ...)
|
int box_silent_notify(ToxWindow *self, uint64_t flags, int *id_indicator, const char *title, const char *format, ...)
|
||||||
{
|
{
|
||||||
tab_notify(self, flags);
|
tab_notify(self, flags);
|
||||||
|
|
||||||
@ -718,7 +754,9 @@ int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const
|
|||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
int id;
|
int id;
|
||||||
|
|
||||||
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++);
|
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++);
|
||||||
|
|
||||||
if ( id == ACTIVE_NOTIFS_MAX ) {
|
if ( id == ACTIVE_NOTIFS_MAX ) {
|
||||||
control_unlock();
|
control_unlock();
|
||||||
return -1; /* Full */
|
return -1; /* Full */
|
||||||
@ -730,9 +768,11 @@ int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
snprintf(actives[id].title, sizeof(actives[id].title), "%s", title);
|
snprintf(actives[id].title, sizeof(actives[id].title), "%s", title);
|
||||||
|
|
||||||
if (strlen(title) > 23) strcpy(actives[id].title + 20, "...");
|
if (strlen(title) > 23) strcpy(actives[id].title + 20, "...");
|
||||||
|
|
||||||
va_list __ARGS__; va_start (__ARGS__, format);
|
va_list __ARGS__;
|
||||||
|
va_start (__ARGS__, format);
|
||||||
vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
|
vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
|
||||||
va_end (__ARGS__);
|
va_end (__ARGS__);
|
||||||
|
|
||||||
@ -756,7 +796,7 @@ int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int box_silent_notify2(ToxWindow* self, uint64_t flags, int id, const char* format, ...)
|
int box_silent_notify2(ToxWindow *self, uint64_t flags, int id, const char *format, ...)
|
||||||
{
|
{
|
||||||
tab_notify(self, flags);
|
tab_notify(self, flags);
|
||||||
|
|
||||||
@ -772,7 +812,8 @@ int box_silent_notify2(ToxWindow* self, uint64_t flags, int id, const char* form
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
va_list __ARGS__; va_start (__ARGS__, format);
|
va_list __ARGS__;
|
||||||
|
va_start (__ARGS__, format);
|
||||||
vsnprintf (actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __ARGS__);
|
vsnprintf (actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __ARGS__);
|
||||||
va_end (__ARGS__);
|
va_end (__ARGS__);
|
||||||
|
|
||||||
@ -785,7 +826,8 @@ int box_silent_notify2(ToxWindow* self, uint64_t flags, int id, const char* form
|
|||||||
char formated[128 * 129] = {'\0'};
|
char formated[128 * 129] = {'\0'};
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (; i <actives[id].size; i ++) {
|
|
||||||
|
for (; i < actives[id].size; i ++) {
|
||||||
strcat(formated, actives[id].messages[i]);
|
strcat(formated, actives[id].messages[i]);
|
||||||
strcat(formated, "\n");
|
strcat(formated, "\n");
|
||||||
}
|
}
|
||||||
|
18
src/notify.h
18
src/notify.h
@ -26,8 +26,7 @@
|
|||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
|
|
||||||
typedef enum _Notification
|
typedef enum _Notification {
|
||||||
{
|
|
||||||
silent = -1,
|
silent = -1,
|
||||||
notif_error,
|
notif_error,
|
||||||
self_log_in,
|
self_log_in,
|
||||||
@ -63,18 +62,19 @@ typedef enum _Flags {
|
|||||||
int init_notify(int login_cooldown, int notification_timeout);
|
int init_notify(int login_cooldown, int notification_timeout);
|
||||||
void terminate_notify();
|
void terminate_notify();
|
||||||
|
|
||||||
int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator);
|
int sound_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indicator);
|
||||||
int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id);
|
int sound_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id);
|
||||||
|
|
||||||
void stop_sound(int id);
|
void stop_sound(int id);
|
||||||
|
|
||||||
int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator, const char* title, const char* format, ...);
|
int box_notify(ToxWindow *self, Notification notif, uint64_t flags, int *id_indicator, const char *title,
|
||||||
int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, const char* format, ...);
|
const char *format, ...);
|
||||||
int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const char* title, const char* format, ...);
|
int box_notify2(ToxWindow *self, Notification notif, uint64_t flags, int id, const char *format, ...);
|
||||||
int box_silent_notify2(ToxWindow* self, uint64_t flags, int id, const char* format, ...);
|
int box_silent_notify(ToxWindow *self, uint64_t flags, int *id_indicator, const char *title, const char *format, ...);
|
||||||
|
int box_silent_notify2(ToxWindow *self, uint64_t flags, int id, const char *format, ...);
|
||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
int set_sound(Notification sound, const char* value);
|
int set_sound(Notification sound, const char *value);
|
||||||
#endif /* SOUND_NOTIFY */
|
#endif /* SOUND_NOTIFY */
|
||||||
|
|
||||||
#endif /* NOTIFY_H */
|
#endif /* NOTIFY_H */
|
||||||
|
@ -31,13 +31,16 @@
|
|||||||
#endif /* __OBJC__ */
|
#endif /* __OBJC__ */
|
||||||
|
|
||||||
#define RELEASE_CHK(func, obj) if ((obj))\
|
#define RELEASE_CHK(func, obj) if ((obj))\
|
||||||
func((obj));
|
func((obj));
|
||||||
|
|
||||||
void bgrtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *rgb, uint16_t width, uint16_t height);
|
void bgrtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *rgb, uint16_t width, uint16_t height);
|
||||||
|
|
||||||
#ifdef __OBJC__
|
#ifdef __OBJC__
|
||||||
@interface OSXVideo : NSObject <AVCaptureVideoDataOutputSampleBufferDelegate>
|
@interface OSXVideo :
|
||||||
- (instancetype)initWithDeviceNames:(char **)device_names AmtDevices:(int *)size;
|
NSObject <AVCaptureVideoDataOutputSampleBufferDelegate>
|
||||||
|
- (instancetype)initWithDeviceNames:
|
||||||
|
(char **)device_names AmtDevices:
|
||||||
|
(int *)size;
|
||||||
@end
|
@end
|
||||||
#endif /* __OBJC__ */
|
#endif /* __OBJC__ */
|
||||||
|
|
||||||
|
106
src/osx_video.m
106
src/osx_video.m
@ -44,19 +44,19 @@
|
|||||||
static uint8_t rgb_to_y(int r, int g, int b)
|
static uint8_t rgb_to_y(int r, int g, int b)
|
||||||
{
|
{
|
||||||
int y = ((9798 * r + 19235 * g + 3736 * b) >> 15);
|
int y = ((9798 * r + 19235 * g + 3736 * b) >> 15);
|
||||||
return y>255? 255 : y<0 ? 0 : y;
|
return y > 255 ? 255 : y < 0 ? 0 : y;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t rgb_to_u(int r, int g, int b)
|
static uint8_t rgb_to_u(int r, int g, int b)
|
||||||
{
|
{
|
||||||
int u = ((-5538 * r + -10846 * g + 16351 * b) >> 15) + 128;
|
int u = ((-5538 * r + -10846 * g + 16351 * b) >> 15) + 128;
|
||||||
return u>255? 255 : u<0 ? 0 : u;
|
return u > 255 ? 255 : u < 0 ? 0 : u;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t rgb_to_v(int r, int g, int b)
|
static uint8_t rgb_to_v(int r, int g, int b)
|
||||||
{
|
{
|
||||||
int v = ((16351 * r + -13697 * g + -2664 * b) >> 15) + 128;
|
int v = ((16351 * r + -13697 * g + -2664 * b) >> 15) + 128;
|
||||||
return v>255? 255 : v<0 ? 0 : v;
|
return v > 255 ? 255 : v < 0 ? 0 : v;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *rgb, uint16_t width, uint16_t height)
|
void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t *rgb, uint16_t width, uint16_t height)
|
||||||
@ -65,9 +65,10 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
|
|||||||
uint8_t *p;
|
uint8_t *p;
|
||||||
uint8_t r, g, b;
|
uint8_t r, g, b;
|
||||||
|
|
||||||
for(y = 0; y != height; y += 2) {
|
for (y = 0; y != height; y += 2) {
|
||||||
p = rgb;
|
p = rgb;
|
||||||
for(x = 0; x != width; x++) {
|
|
||||||
|
for (x = 0; x != width; x++) {
|
||||||
b = *rgb++;
|
b = *rgb++;
|
||||||
g = *rgb++;
|
g = *rgb++;
|
||||||
r = *rgb++;
|
r = *rgb++;
|
||||||
@ -76,7 +77,7 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
|
|||||||
*plane_y++ = rgb_to_y(r, g, b);
|
*plane_y++ = rgb_to_y(r, g, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(x = 0; x != width / 2; x++) {
|
for (x = 0; x != width / 2; x++) {
|
||||||
b = *rgb++;
|
b = *rgb++;
|
||||||
g = *rgb++;
|
g = *rgb++;
|
||||||
r = *rgb++;
|
r = *rgb++;
|
||||||
@ -91,9 +92,12 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
|
|||||||
|
|
||||||
*plane_y++ = rgb_to_y(r, g, b);
|
*plane_y++ = rgb_to_y(r, g, b);
|
||||||
|
|
||||||
b = ((int)b + (int)*(rgb - 8) + (int)*p + (int)*(p + 4) + 2) / 4; p++;
|
b = ((int)b + (int) * (rgb - 8) + (int) * p + (int) * (p + 4) + 2) / 4;
|
||||||
g = ((int)g + (int)*(rgb - 7) + (int)*p + (int)*(p + 4) + 2) / 4; p++;
|
p++;
|
||||||
r = ((int)r + (int)*(rgb - 6) + (int)*p + (int)*(p + 4) + 2) / 4; p++;
|
g = ((int)g + (int) * (rgb - 7) + (int) * p + (int) * (p + 4) + 2) / 4;
|
||||||
|
p++;
|
||||||
|
r = ((int)r + (int) * (rgb - 6) + (int) * p + (int) * (p + 4) + 2) / 4;
|
||||||
|
p++;
|
||||||
p++;
|
p++;
|
||||||
|
|
||||||
*plane_u++ = rgb_to_u(r, g, b);
|
*plane_u++ = rgb_to_u(r, g, b);
|
||||||
@ -122,28 +126,34 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
|
|||||||
BOOL _shouldMangleDimensions;
|
BOOL _shouldMangleDimensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithDeviceNames: (char **)device_names AmtDevices: (int *)size {
|
- (instancetype)initWithDeviceNames:
|
||||||
|
(char **)device_names AmtDevices:
|
||||||
|
(int *)size
|
||||||
|
{
|
||||||
_session = [[AVCaptureSession alloc] init];
|
_session = [[AVCaptureSession alloc] init];
|
||||||
|
|
||||||
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
|
NSArray *devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < [devices count]; ++i) {
|
for (i = 0; i < [devices count]; ++i) {
|
||||||
AVCaptureDevice *device = [devices objectAtIndex:i];
|
AVCaptureDevice *device = [devices objectAtIndex: i];
|
||||||
char *video_input_name;
|
char *video_input_name;
|
||||||
NSString *localizedName = [device localizedName];
|
NSString *localizedName = [device localizedName];
|
||||||
video_input_name = (char*)malloc(strlen([localizedName cStringUsingEncoding:NSUTF8StringEncoding]) + 1);
|
video_input_name = (char *)malloc(strlen([localizedName cStringUsingEncoding: NSUTF8StringEncoding]) + 1);
|
||||||
strcpy(video_input_name, (char*)[localizedName cStringUsingEncoding:NSUTF8StringEncoding]);
|
strcpy(video_input_name, (char *)[localizedName cStringUsingEncoding: NSUTF8StringEncoding]);
|
||||||
device_names[i] = video_input_name;
|
device_names[i] = video_input_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( i <= 0 )
|
if ( i <= 0 )
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
*size = i;
|
*size = i;
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc {
|
- (void)dealloc
|
||||||
|
{
|
||||||
pthread_mutex_destroy(&_frameLock);
|
pthread_mutex_destroy(&_frameLock);
|
||||||
[_session release];
|
[_session release];
|
||||||
[_linkerVideo release];
|
[_linkerVideo release];
|
||||||
@ -151,14 +161,18 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
|
|||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int)openVideoDeviceIndex: (uint32_t)device_idx Width: (uint16_t *)width Height: (uint16_t *)height {
|
- (int)openVideoDeviceIndex:
|
||||||
|
(uint32_t)device_idx Width:
|
||||||
|
(uint16_t *)width Height:
|
||||||
|
(uint16_t *)height
|
||||||
|
{
|
||||||
pthread_mutex_init(&_frameLock, NULL);
|
pthread_mutex_init(&_frameLock, NULL);
|
||||||
pthread_mutex_lock(&_frameLock);
|
pthread_mutex_lock(&_frameLock);
|
||||||
_processingQueue = dispatch_queue_create("Toxic processing queue", DISPATCH_QUEUE_SERIAL);
|
_processingQueue = dispatch_queue_create("Toxic processing queue", DISPATCH_QUEUE_SERIAL);
|
||||||
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
|
NSArray *devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo];
|
||||||
AVCaptureDevice *device = [devices objectAtIndex:device_idx];
|
AVCaptureDevice *device = [devices objectAtIndex: device_idx];
|
||||||
NSError *error = NULL;
|
NSError *error = NULL;
|
||||||
AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error];
|
AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice: device error: &error];
|
||||||
|
|
||||||
if ( error != NULL ) {
|
if ( error != NULL ) {
|
||||||
[input release];
|
[input release];
|
||||||
@ -166,7 +180,7 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
[_session beginConfiguration];
|
[_session beginConfiguration];
|
||||||
[_session addInput:input];
|
[_session addInput: input];
|
||||||
//_session.sessionPreset = AVCaptureSessionPreset640x480;
|
//_session.sessionPreset = AVCaptureSessionPreset640x480;
|
||||||
//*width = 640;
|
//*width = 640;
|
||||||
//*height = 480;
|
//*height = 480;
|
||||||
@ -176,8 +190,9 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
|
|||||||
[device release];
|
[device release];
|
||||||
|
|
||||||
/* Obtain device resolution */
|
/* Obtain device resolution */
|
||||||
AVCaptureInputPort *port = [input.ports objectAtIndex:0];
|
AVCaptureInputPort *port = [input.ports objectAtIndex: 0];
|
||||||
CMFormatDescriptionRef format_description = port.formatDescription;
|
CMFormatDescriptionRef format_description = port.formatDescription;
|
||||||
|
|
||||||
if ( format_description ) {
|
if ( format_description ) {
|
||||||
CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(format_description);
|
CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(format_description);
|
||||||
*width = dimensions.width;
|
*width = dimensions.width;
|
||||||
@ -188,36 +203,47 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
_linkerVideo = [[AVCaptureVideoDataOutput alloc] init];
|
_linkerVideo = [[AVCaptureVideoDataOutput alloc] init];
|
||||||
[_linkerVideo setSampleBufferDelegate:self queue:_processingQueue];
|
[_linkerVideo setSampleBufferDelegate: self queue: _processingQueue];
|
||||||
|
|
||||||
// TODO possibly get a better pixel format
|
// TODO possibly get a better pixel format
|
||||||
if (_shouldMangleDimensions) {
|
if (_shouldMangleDimensions) {
|
||||||
[_linkerVideo setVideoSettings:@{(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA),
|
[_linkerVideo setVideoSettings: @ {
|
||||||
(id)kCVPixelBufferWidthKey: @640,
|
(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA),
|
||||||
(id)kCVPixelBufferHeightKey: @480}];
|
(id)kCVPixelBufferWidthKey: @640,
|
||||||
|
(id)kCVPixelBufferHeightKey: @480
|
||||||
|
}];
|
||||||
} else {
|
} else {
|
||||||
[_linkerVideo setVideoSettings:@{(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)}];
|
[_linkerVideo setVideoSettings: @ {(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)}];
|
||||||
}
|
}
|
||||||
[_session addOutput:_linkerVideo];
|
|
||||||
|
[_session addOutput: _linkerVideo];
|
||||||
[_session startRunning];
|
[_session startRunning];
|
||||||
|
|
||||||
pthread_mutex_unlock(&_frameLock);
|
pthread_mutex_unlock(&_frameLock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)closeVideoDeviceIndex: (uint32_t)device_idx {
|
- (void)closeVideoDeviceIndex:
|
||||||
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
|
(uint32_t)device_idx
|
||||||
AVCaptureDevice *device = [devices objectAtIndex:device_idx];
|
{
|
||||||
|
NSArray *devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo];
|
||||||
|
AVCaptureDevice *device = [devices objectAtIndex: device_idx];
|
||||||
NSError *error = NULL;
|
NSError *error = NULL;
|
||||||
AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error];
|
AVCaptureInput *input = [[AVCaptureDeviceInput alloc] initWithDevice: device error: &error];
|
||||||
[_session stopRunning];
|
[_session stopRunning];
|
||||||
[_session removeOutput:_linkerVideo];
|
[_session removeOutput: _linkerVideo];
|
||||||
[_session removeInput:input];
|
[_session removeInput: input];
|
||||||
[_linkerVideo release];
|
[_linkerVideo release];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
|
- (void)captureOutput:
|
||||||
|
(AVCaptureOutput *)captureOutput didOutputSampleBuffer:
|
||||||
|
(CMSampleBufferRef)sampleBuffer fromConnection:
|
||||||
|
(AVCaptureConnection *)connection
|
||||||
|
{
|
||||||
pthread_mutex_lock(&_frameLock);
|
pthread_mutex_lock(&_frameLock);
|
||||||
CVImageBufferRef img = CMSampleBufferGetImageBuffer(sampleBuffer);
|
CVImageBufferRef img = CMSampleBufferGetImageBuffer(sampleBuffer);
|
||||||
|
|
||||||
if (!img) {
|
if (!img) {
|
||||||
NSLog(@"Toxic WARNING: Bad sampleBuffer from AVfoundation!");
|
NSLog(@"Toxic WARNING: Bad sampleBuffer from AVfoundation!");
|
||||||
} else {
|
} else {
|
||||||
@ -228,10 +254,17 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
|
|||||||
// we're not going to do anything to it, so it's safe to lock it always
|
// we're not going to do anything to it, so it's safe to lock it always
|
||||||
CVPixelBufferLockBaseAddress(_currentFrame, kCVPixelBufferLock_ReadOnly);
|
CVPixelBufferLockBaseAddress(_currentFrame, kCVPixelBufferLock_ReadOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&_frameLock);
|
pthread_mutex_unlock(&_frameLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int)getVideoFrameY: (uint8_t *)y U: (uint8_t *)u V: (uint8_t *)v Width: (uint16_t *)width Height: (uint16_t *)height {
|
- (int)getVideoFrameY:
|
||||||
|
(uint8_t *)y U:
|
||||||
|
(uint8_t *)u V:
|
||||||
|
(uint8_t *)v Width:
|
||||||
|
(uint16_t *)width Height:
|
||||||
|
(uint16_t *)height
|
||||||
|
{
|
||||||
if (!_currentFrame) {
|
if (!_currentFrame) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -240,6 +273,7 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
|
|||||||
CFRetain(_currentFrame);
|
CFRetain(_currentFrame);
|
||||||
|
|
||||||
CFTypeID imageType = CFGetTypeID(_currentFrame);
|
CFTypeID imageType = CFGetTypeID(_currentFrame);
|
||||||
|
|
||||||
if (imageType == CVPixelBufferGetTypeID()) {
|
if (imageType == CVPixelBufferGetTypeID()) {
|
||||||
// TODO maybe handle other formats
|
// TODO maybe handle other formats
|
||||||
bgrxtoyuv420(y, u, v, CVPixelBufferGetBaseAddress(_currentFrame), *width, *height);
|
bgrxtoyuv420(y, u, v, CVPixelBufferGetBaseAddress(_currentFrame), *width, *height);
|
||||||
@ -263,7 +297,7 @@ void bgrxtoyuv420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v, uint8_t
|
|||||||
/*
|
/*
|
||||||
* C-interface for OSXVideo
|
* C-interface for OSXVideo
|
||||||
*/
|
*/
|
||||||
static OSXVideo* _OSXVideo = nil;
|
static OSXVideo *_OSXVideo = nil;
|
||||||
|
|
||||||
int osx_video_init(char **device_names, int *size)
|
int osx_video_init(char **device_names, int *size)
|
||||||
{
|
{
|
||||||
|
41
src/prompt.c
41
src/prompt.c
@ -49,10 +49,16 @@ extern struct Winthread Winthread;
|
|||||||
|
|
||||||
extern FriendsList Friends;
|
extern FriendsList Friends;
|
||||||
FriendRequests FrndRequests;
|
FriendRequests FrndRequests;
|
||||||
#ifdef VIDEO
|
#if defined(PYTHON) && defined(VIDEO)
|
||||||
|
#define AC_NUM_GLOB_COMMANDS 23
|
||||||
|
#elif defined(PYTHON) && defined(AUDIO)
|
||||||
|
#define AC_NUM_GLOB_COMMANDS 21
|
||||||
|
#elif VIDEO
|
||||||
#define AC_NUM_GLOB_COMMANDS 22
|
#define AC_NUM_GLOB_COMMANDS 22
|
||||||
#elif AUDIO
|
#elif AUDIO
|
||||||
#define AC_NUM_GLOB_COMMANDS 20
|
#define AC_NUM_GLOB_COMMANDS 20
|
||||||
|
#elif PYTHON
|
||||||
|
#define AC_NUM_GLOB_COMMANDS 19
|
||||||
#else
|
#else
|
||||||
#define AC_NUM_GLOB_COMMANDS 18
|
#define AC_NUM_GLOB_COMMANDS 18
|
||||||
#endif
|
#endif
|
||||||
@ -92,6 +98,12 @@ static const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
|
|||||||
|
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
|
|
||||||
|
#ifdef PYTHON
|
||||||
|
|
||||||
|
{ "/run" },
|
||||||
|
|
||||||
|
#endif /* PYTHON */
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void kill_prompt_window(ToxWindow *self)
|
void kill_prompt_window(ToxWindow *self)
|
||||||
@ -214,11 +226,18 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
|
|
||||||
if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0)
|
if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0)
|
||||||
diff = dir_match(self, m, ctx->line, L"/avatar");
|
diff = dir_match(self, m, ctx->line, L"/avatar");
|
||||||
else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0){
|
|
||||||
|
#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] = {
|
const char status_cmd_list[3][8] = {
|
||||||
{"online"},
|
{"online"},
|
||||||
{"away"},
|
{"away"},
|
||||||
{"busy"},
|
{"busy"},
|
||||||
};
|
};
|
||||||
diff = complete_line(self, status_cmd_list, 3, 8);
|
diff = complete_line(self, status_cmd_list, 3, 8);
|
||||||
} else
|
} else
|
||||||
@ -238,8 +257,7 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
} else if (key == '\r') {
|
} else if (key == '\r') {
|
||||||
rm_trailing_spaces_buf(ctx);
|
rm_trailing_spaces_buf(ctx);
|
||||||
|
|
||||||
if (!wstring_is_empty(ctx->line))
|
if (!wstring_is_empty(ctx->line)) {
|
||||||
{
|
|
||||||
add_line_to_hist(ctx);
|
add_line_to_hist(ctx);
|
||||||
wstrsubst(ctx->line, L'¶', L'\n');
|
wstrsubst(ctx->line, L'¶', L'\n');
|
||||||
|
|
||||||
@ -301,10 +319,12 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
|||||||
status_text = "Online";
|
status_text = "Online";
|
||||||
colour = GREEN;
|
colour = GREEN;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_USER_STATUS_AWAY:
|
case TOX_USER_STATUS_AWAY:
|
||||||
status_text = "Away";
|
status_text = "Away";
|
||||||
colour = YELLOW;
|
colour = YELLOW;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_USER_STATUS_BUSY:
|
case TOX_USER_STATUS_BUSY:
|
||||||
status_text = "Busy";
|
status_text = "Busy";
|
||||||
colour = RED;
|
colour = RED;
|
||||||
@ -335,7 +355,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
size_t slen = tox_self_get_status_message_size(m);
|
size_t slen = tox_self_get_status_message_size(m);
|
||||||
tox_self_get_status_message (m, (uint8_t*) statusmsg);
|
tox_self_get_status_message (m, (uint8_t *) statusmsg);
|
||||||
statusmsg[slen] = '\0';
|
statusmsg[slen] = '\0';
|
||||||
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
|
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
|
||||||
statusbar->statusmsg_len = strlen(statusbar->statusmsg);
|
statusbar->statusmsg_len = strlen(statusbar->statusmsg);
|
||||||
@ -375,7 +395,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
|||||||
help_onDraw(self);
|
help_onDraw(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnum , TOX_CONNECTION connection_status)
|
static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnum, TOX_CONNECTION connection_status)
|
||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
@ -404,8 +424,7 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnu
|
|||||||
else
|
else
|
||||||
box_notify(self, user_log_in, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, &self->active_box,
|
box_notify(self, user_log_in, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, &self->active_box,
|
||||||
"Toxic", "%s has come online", nick );
|
"Toxic", "%s has come online", nick );
|
||||||
}
|
} else if (connection_status == TOX_CONNECTION_NONE) {
|
||||||
else if (connection_status == TOX_CONNECTION_NONE) {
|
|
||||||
msg = "has gone offline";
|
msg = "has gone offline";
|
||||||
line_info_add(self, timefrmt, nick, NULL, DISCONNECTION, 0, RED, msg);
|
line_info_add(self, timefrmt, nick, NULL, DISCONNECTION, 0, RED, msg);
|
||||||
write_to_log(msg, nick, ctx->log, true);
|
write_to_log(msg, nick, ctx->log, true);
|
||||||
|
347
src/python_api.c
Normal file
347
src/python_api.c
Normal file
@ -0,0 +1,347 @@
|
|||||||
|
/* 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"
|
||||||
|
#endif /* PYTHON */
|
||||||
|
|
||||||
|
#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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
39
src/python_api.h
Normal file
39
src/python_api.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/* 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 /* #define PYTHON_API_H */
|
127
src/qr_code.c
127
src/qr_code.c
@ -23,30 +23,42 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <qrencode.h>
|
#include <qrencode.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#include "qr_code.h"
|
#include "qr_code.h"
|
||||||
|
|
||||||
|
#ifdef QRPNG
|
||||||
|
#include <png.h>
|
||||||
|
#define INCHES_PER_METER (100.0/2.54)
|
||||||
|
#define DPI 72
|
||||||
|
#define SQUARE_SIZE 5
|
||||||
|
#endif /* QRPNG */
|
||||||
|
|
||||||
#define BORDER_LEN 1
|
#define BORDER_LEN 1
|
||||||
#define CHAR_1 "\342\226\210"
|
#define CHAR_1 "\342\226\210"
|
||||||
#define CHAR_2 "\342\226\204"
|
#define CHAR_2 "\342\226\204"
|
||||||
#define CHAR_3 "\342\226\200"
|
#define CHAR_3 "\342\226\200"
|
||||||
|
|
||||||
/* Converts a tox ID string into a QRcode and prints it to the given file stream.
|
/* Converts a tox ID string into a QRcode and prints it into the given filename.
|
||||||
*
|
*
|
||||||
* Returns 0 on success.
|
* Returns 0 on success.
|
||||||
* Returns -1 on failure.
|
* Returns -1 on failure.
|
||||||
*/
|
*/
|
||||||
int ID_to_QRcode(const char *tox_id, FILE *fp)
|
int ID_to_QRcode_txt(const char *tox_id, const char *outfile)
|
||||||
{
|
{
|
||||||
|
FILE *fp = fopen(outfile, "wb");
|
||||||
|
|
||||||
if (fp == NULL)
|
if (fp == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
QRcode *qr_obj = QRcode_encodeString(tox_id, 0, QR_ECLEVEL_L, QR_MODE_8, 0);
|
QRcode *qr_obj = QRcode_encodeString(tox_id, 0, QR_ECLEVEL_L, QR_MODE_8, 0);
|
||||||
|
|
||||||
if (qr_obj == NULL)
|
if (qr_obj == NULL) {
|
||||||
|
fclose(fp);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
size_t width = qr_obj->width;
|
size_t width = qr_obj->width;
|
||||||
size_t i, j;
|
size_t i, j;
|
||||||
@ -83,7 +95,116 @@ int ID_to_QRcode(const char *tox_id, FILE *fp)
|
|||||||
fprintf(fp, "\n");
|
fprintf(fp, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
QRcode_free(qr_obj);
|
QRcode_free(qr_obj);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef QRPNG
|
||||||
|
/* Converts a tox ID string into a QRcode and prints it into the given filename as png.
|
||||||
|
*
|
||||||
|
* Returns 0 on success.
|
||||||
|
* Returns -1 on failure.
|
||||||
|
*/
|
||||||
|
int ID_to_QRcode_png(const char *tox_id, const char *outfile)
|
||||||
|
{
|
||||||
|
static FILE *fp;
|
||||||
|
unsigned char *p;
|
||||||
|
unsigned char black[4] = {0, 0, 0, 255};
|
||||||
|
size_t x, y, xx, yy, real_width;
|
||||||
|
png_structp png_ptr;
|
||||||
|
png_infop info_ptr;
|
||||||
|
|
||||||
|
fp = fopen(outfile, "wb");
|
||||||
|
|
||||||
|
if (fp == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRcode *qr_obj = QRcode_encodeString(tox_id, 0, QR_ECLEVEL_L, QR_MODE_8, 0);
|
||||||
|
|
||||||
|
if (qr_obj == NULL) {
|
||||||
|
fclose(fp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
real_width = (qr_obj->width + BORDER_LEN * 2) * SQUARE_SIZE;
|
||||||
|
size_t row_size = real_width * 4;
|
||||||
|
unsigned char row[row_size];
|
||||||
|
|
||||||
|
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
if (png_ptr == NULL) {
|
||||||
|
fclose(fp);
|
||||||
|
QRcode_free(qr_obj);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
info_ptr = png_create_info_struct(png_ptr);
|
||||||
|
|
||||||
|
if (info_ptr == NULL) {
|
||||||
|
fclose(fp);
|
||||||
|
QRcode_free(qr_obj);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||||
|
fclose(fp);
|
||||||
|
QRcode_free(qr_obj);
|
||||||
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_init_io(png_ptr, fp);
|
||||||
|
png_set_IHDR(png_ptr, info_ptr, real_width, real_width, 8,
|
||||||
|
PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
|
||||||
|
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||||
|
png_set_pHYs(png_ptr, info_ptr, DPI * INCHES_PER_METER,
|
||||||
|
DPI * INCHES_PER_METER, PNG_RESOLUTION_METER);
|
||||||
|
png_write_info(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
/* top margin */
|
||||||
|
memset(row, 0xff, row_size);
|
||||||
|
|
||||||
|
for (y = 0; y < BORDER_LEN * SQUARE_SIZE; y++) {
|
||||||
|
png_write_row(png_ptr, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* data */
|
||||||
|
p = qr_obj->data;
|
||||||
|
|
||||||
|
for (y = 0; y < qr_obj->width; y++) {
|
||||||
|
memset(row, 0xff, row_size);
|
||||||
|
|
||||||
|
for (x = 0; x < qr_obj->width; x++) {
|
||||||
|
for (xx = 0; xx < SQUARE_SIZE; xx++) {
|
||||||
|
if (*p & 1) {
|
||||||
|
memcpy(&row[((BORDER_LEN + x) * SQUARE_SIZE + xx) * 4], black, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (yy = 0; yy < SQUARE_SIZE; yy++) {
|
||||||
|
png_write_row(png_ptr, row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* bottom margin */
|
||||||
|
memset(row, 0xff, row_size);
|
||||||
|
|
||||||
|
for (y = 0; y < BORDER_LEN * SQUARE_SIZE; y++) {
|
||||||
|
png_write_row(png_ptr, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
png_write_end(png_ptr, info_ptr);
|
||||||
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
QRcode_free(qr_obj);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* QRPNG */
|
||||||
|
@ -25,11 +25,21 @@
|
|||||||
|
|
||||||
#define QRCODE_FILENAME_EXT ".QRcode"
|
#define QRCODE_FILENAME_EXT ".QRcode"
|
||||||
|
|
||||||
/* Converts a tox ID string into a QRcode and prints it to the given file stream.
|
/* Converts a tox ID string into a QRcode and prints it into the given filename.
|
||||||
*
|
*
|
||||||
* Returns 0 on success.
|
* Returns 0 on success.
|
||||||
* Returns -1 on failure.
|
* Returns -1 on failure.
|
||||||
*/
|
*/
|
||||||
int ID_to_QRcode(const char *tox_id, FILE *fp);
|
int ID_to_QRcode_txt(const char *tox_id, const char *outfile);
|
||||||
|
|
||||||
|
#ifdef QRPNG
|
||||||
|
#define QRCODE_FILENAME_EXT_PNG ".QRcode.png"
|
||||||
|
/* Converts a tox ID string into a QRcode and prints it into the given filename as png.
|
||||||
|
*
|
||||||
|
* Returns 0 on success.
|
||||||
|
* Returns -1 on failure.
|
||||||
|
*/
|
||||||
|
int ID_to_QRcode_png(const char *tox_id, const char *outfile);
|
||||||
|
#endif /* QRPNG */
|
||||||
|
|
||||||
#endif /* QR_CODE */
|
#endif /* QR_CODE */
|
||||||
|
176
src/settings.c
176
src/settings.c
@ -32,45 +32,45 @@
|
|||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
#include "audio_device.h"
|
#include "audio_device.h"
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
|
|
||||||
#ifndef PACKAGE_DATADIR
|
#ifndef PACKAGE_DATADIR
|
||||||
#define PACKAGE_DATADIR "."
|
#define PACKAGE_DATADIR "."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define NO_SOUND "silent"
|
#define NO_SOUND "silent"
|
||||||
|
|
||||||
static struct ui_strings {
|
static struct ui_strings {
|
||||||
const char* self;
|
const char *self;
|
||||||
const char* timestamps;
|
const char *timestamps;
|
||||||
const char* time_format;
|
const char *time_format;
|
||||||
const char* timestamp_format;
|
const char *timestamp_format;
|
||||||
const char* log_timestamp_format;
|
const char *log_timestamp_format;
|
||||||
const char* alerts;
|
const char *alerts;
|
||||||
const char* bell_on_message;
|
const char *bell_on_message;
|
||||||
const char* bell_on_filetrans;
|
const char *bell_on_filetrans;
|
||||||
const char* bell_on_filetrans_accept;
|
const char *bell_on_filetrans_accept;
|
||||||
const char* bell_on_invite;
|
const char *bell_on_invite;
|
||||||
const char* native_colors;
|
const char *native_colors;
|
||||||
const char* autolog;
|
const char *autolog;
|
||||||
const char* history_size;
|
const char *history_size;
|
||||||
const char* show_typing_self;
|
const char *show_typing_self;
|
||||||
const char* show_typing_other;
|
const char *show_typing_other;
|
||||||
const char* show_welcome_msg;
|
const char *show_welcome_msg;
|
||||||
const char* show_connection_msg;
|
const char *show_connection_msg;
|
||||||
const char* nodeslist_update_freq;
|
const char *nodeslist_update_freq;
|
||||||
|
|
||||||
const char* line_join;
|
const char *line_join;
|
||||||
const char* line_quit;
|
const char *line_quit;
|
||||||
const char* line_alert;
|
const char *line_alert;
|
||||||
const char* line_normal;
|
const char *line_normal;
|
||||||
|
|
||||||
const char* mplex_away;
|
const char *mplex_away;
|
||||||
const char* mplex_away_note;
|
const char *mplex_away_note;
|
||||||
} ui_strings = {
|
} ui_strings = {
|
||||||
"ui",
|
"ui",
|
||||||
"timestamps",
|
"timestamps",
|
||||||
@ -98,7 +98,7 @@ static struct ui_strings {
|
|||||||
"mplex_away_note",
|
"mplex_away_note",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ui_defaults(struct user_settings* settings)
|
static void ui_defaults(struct user_settings *settings)
|
||||||
{
|
{
|
||||||
settings->timestamps = TIMESTAMPS_ON;
|
settings->timestamps = TIMESTAMPS_ON;
|
||||||
snprintf(settings->timestamp_format, sizeof(settings->timestamp_format), "%s", TIMESTAMP_DEFAULT);
|
snprintf(settings->timestamp_format, sizeof(settings->timestamp_format), "%s", TIMESTAMP_DEFAULT);
|
||||||
@ -131,18 +131,18 @@ static void ui_defaults(struct user_settings* settings)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct keys_strings {
|
static const struct keys_strings {
|
||||||
const char* self;
|
const char *self;
|
||||||
const char* next_tab;
|
const char *next_tab;
|
||||||
const char* prev_tab;
|
const char *prev_tab;
|
||||||
const char* scroll_line_up;
|
const char *scroll_line_up;
|
||||||
const char* scroll_line_down;
|
const char *scroll_line_down;
|
||||||
const char* half_page_up;
|
const char *half_page_up;
|
||||||
const char* half_page_down;
|
const char *half_page_down;
|
||||||
const char* page_bottom;
|
const char *page_bottom;
|
||||||
const char* peer_list_up;
|
const char *peer_list_up;
|
||||||
const char* peer_list_down;
|
const char *peer_list_down;
|
||||||
const char* toggle_peerlist;
|
const char *toggle_peerlist;
|
||||||
const char* toggle_pastemode;
|
const char *toggle_pastemode;
|
||||||
} key_strings = {
|
} key_strings = {
|
||||||
"keys",
|
"keys",
|
||||||
"next_tab",
|
"next_tab",
|
||||||
@ -159,7 +159,7 @@ static const struct keys_strings {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* defines from toxic.h */
|
/* defines from toxic.h */
|
||||||
static void key_defaults(struct user_settings* settings)
|
static void key_defaults(struct user_settings *settings)
|
||||||
{
|
{
|
||||||
settings->key_next_tab = T_KEY_NEXT;
|
settings->key_next_tab = T_KEY_NEXT;
|
||||||
settings->key_prev_tab = T_KEY_PREV;
|
settings->key_prev_tab = T_KEY_PREV;
|
||||||
@ -175,33 +175,36 @@ static void key_defaults(struct user_settings* settings)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct tox_strings {
|
static const struct tox_strings {
|
||||||
const char* self;
|
const char *self;
|
||||||
const char* download_path;
|
const char *download_path;
|
||||||
const char* chatlogs_path;
|
const char *chatlogs_path;
|
||||||
const char* avatar_path;
|
const char *avatar_path;
|
||||||
const char* password_eval;
|
const char *autorun_path;
|
||||||
|
const char *password_eval;
|
||||||
} tox_strings = {
|
} tox_strings = {
|
||||||
"tox",
|
"tox",
|
||||||
"download_path",
|
"download_path",
|
||||||
"chatlogs_path",
|
"chatlogs_path",
|
||||||
"avatar_path",
|
"avatar_path",
|
||||||
|
"autorun_path",
|
||||||
"password_eval",
|
"password_eval",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void tox_defaults(struct user_settings* settings)
|
static void tox_defaults(struct user_settings *settings)
|
||||||
{
|
{
|
||||||
strcpy(settings->download_path, "");
|
strcpy(settings->download_path, "");
|
||||||
strcpy(settings->chatlogs_path, "");
|
strcpy(settings->chatlogs_path, "");
|
||||||
strcpy(settings->avatar_path, "");
|
strcpy(settings->avatar_path, "");
|
||||||
|
strcpy(settings->autorun_path, "");
|
||||||
strcpy(settings->password_eval, "");
|
strcpy(settings->password_eval, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
static const struct audio_strings {
|
static const struct audio_strings {
|
||||||
const char* self;
|
const char *self;
|
||||||
const char* input_device;
|
const char *input_device;
|
||||||
const char* output_device;
|
const char *output_device;
|
||||||
const char* VAD_treshold;
|
const char *VAD_treshold;
|
||||||
} audio_strings = {
|
} audio_strings = {
|
||||||
"audio",
|
"audio",
|
||||||
"input_device",
|
"input_device",
|
||||||
@ -209,7 +212,7 @@ static const struct audio_strings {
|
|||||||
"VAD_treshold",
|
"VAD_treshold",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void audio_defaults(struct user_settings* settings)
|
static void audio_defaults(struct user_settings *settings)
|
||||||
{
|
{
|
||||||
settings->audio_in_dev = 0;
|
settings->audio_in_dev = 0;
|
||||||
settings->audio_out_dev = 0;
|
settings->audio_out_dev = 0;
|
||||||
@ -219,17 +222,17 @@ static void audio_defaults(struct user_settings* settings)
|
|||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
static const struct sound_strings {
|
static const struct sound_strings {
|
||||||
const char* self;
|
const char *self;
|
||||||
const char* notif_error;
|
const char *notif_error;
|
||||||
const char* self_log_in;
|
const char *self_log_in;
|
||||||
const char* self_log_out;
|
const char *self_log_out;
|
||||||
const char* user_log_in;
|
const char *user_log_in;
|
||||||
const char* user_log_out;
|
const char *user_log_out;
|
||||||
const char* call_incoming;
|
const char *call_incoming;
|
||||||
const char* call_outgoing;
|
const char *call_outgoing;
|
||||||
const char* generic_message;
|
const char *generic_message;
|
||||||
const char* transfer_pending;
|
const char *transfer_pending;
|
||||||
const char* transfer_completed;
|
const char *transfer_completed;
|
||||||
} sound_strings = {
|
} sound_strings = {
|
||||||
"sounds",
|
"sounds",
|
||||||
"notif_error",
|
"notif_error",
|
||||||
@ -245,11 +248,12 @@ static const struct sound_strings {
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int key_parse(const char **bind) {
|
static int key_parse(const char **bind)
|
||||||
|
{
|
||||||
int len = strlen(*bind);
|
int len = strlen(*bind);
|
||||||
|
|
||||||
if (len > 5) {
|
if (len > 5) {
|
||||||
if(strncasecmp(*bind, "ctrl+", 5) == 0 && toupper(bind[0][5]) != 'M') /* ctrl+m cannot be used */
|
if (strncasecmp(*bind, "ctrl+", 5) == 0 && toupper(bind[0][5]) != 'M') /* ctrl+m cannot be used */
|
||||||
return toupper(bind[0][5]) - 'A' + 1;
|
return toupper(bind[0][5]) - 'A' + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,7 +266,8 @@ static int key_parse(const char **bind) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_key_binding(int *key, const char **bind) {
|
static void set_key_binding(int *key, const char **bind)
|
||||||
|
{
|
||||||
int code = key_parse(bind);
|
int code = key_parse(bind);
|
||||||
|
|
||||||
if (code != -1) {
|
if (code != -1) {
|
||||||
@ -318,6 +323,7 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
config_setting_lookup_bool(setting, ui_strings.timestamps, &s->timestamps);
|
config_setting_lookup_bool(setting, ui_strings.timestamps, &s->timestamps);
|
||||||
|
|
||||||
int time = 24;
|
int time = 24;
|
||||||
|
|
||||||
if ( config_setting_lookup_int(setting, ui_strings.time_format, &time) ) {
|
if ( config_setting_lookup_int(setting, ui_strings.time_format, &time) ) {
|
||||||
if (time == 12) {
|
if (time == 12) {
|
||||||
snprintf(s->timestamp_format, sizeof(s->timestamp_format), "%s", "%I:%M:%S %p");
|
snprintf(s->timestamp_format, sizeof(s->timestamp_format), "%s", "%I:%M:%S %p");
|
||||||
@ -338,12 +344,15 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
if (config_setting_lookup_bool(setting, ui_strings.bell_on_message, &s->bell_on_message)) {
|
if (config_setting_lookup_bool(setting, ui_strings.bell_on_message, &s->bell_on_message)) {
|
||||||
s->bell_on_message = s->bell_on_message ? NT_BEEP : 0;
|
s->bell_on_message = s->bell_on_message ? NT_BEEP : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config_setting_lookup_bool(setting, ui_strings.bell_on_filetrans, &s->bell_on_filetrans)) {
|
if (config_setting_lookup_bool(setting, ui_strings.bell_on_filetrans, &s->bell_on_filetrans)) {
|
||||||
s->bell_on_filetrans = s->bell_on_filetrans ? NT_BEEP : 0;
|
s->bell_on_filetrans = s->bell_on_filetrans ? NT_BEEP : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config_setting_lookup_bool(setting, ui_strings.bell_on_filetrans_accept, &s->bell_on_filetrans_accept)) {
|
if (config_setting_lookup_bool(setting, ui_strings.bell_on_filetrans_accept, &s->bell_on_filetrans_accept)) {
|
||||||
s->bell_on_filetrans_accept = s->bell_on_filetrans_accept ? NT_BEEP : 0;
|
s->bell_on_filetrans_accept = s->bell_on_filetrans_accept ? NT_BEEP : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config_setting_lookup_bool(setting, ui_strings.bell_on_invite, &s->bell_on_invite)) {
|
if (config_setting_lookup_bool(setting, ui_strings.bell_on_invite, &s->bell_on_invite)) {
|
||||||
s->bell_on_invite = s->bell_on_invite ? NT_BEEP : 0;
|
s->bell_on_invite = s->bell_on_invite ? NT_BEEP : 0;
|
||||||
}
|
}
|
||||||
@ -361,12 +370,15 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
if ( config_setting_lookup_string(setting, ui_strings.line_join, &str) ) {
|
if ( config_setting_lookup_string(setting, ui_strings.line_join, &str) ) {
|
||||||
snprintf(s->line_join, sizeof(s->line_join), "%s", str);
|
snprintf(s->line_join, sizeof(s->line_join), "%s", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( config_setting_lookup_string(setting, ui_strings.line_quit, &str) ) {
|
if ( config_setting_lookup_string(setting, ui_strings.line_quit, &str) ) {
|
||||||
snprintf(s->line_quit, sizeof(s->line_quit), "%s", str);
|
snprintf(s->line_quit, sizeof(s->line_quit), "%s", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( config_setting_lookup_string(setting, ui_strings.line_alert, &str) ) {
|
if ( config_setting_lookup_string(setting, ui_strings.line_alert, &str) ) {
|
||||||
snprintf(s->line_alert, sizeof(s->line_alert), "%s", str);
|
snprintf(s->line_alert, sizeof(s->line_alert), "%s", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( config_setting_lookup_string(setting, ui_strings.line_normal, &str) ) {
|
if ( config_setting_lookup_string(setting, ui_strings.line_normal, &str) ) {
|
||||||
snprintf(s->line_normal, sizeof(s->line_normal), "%s", str);
|
snprintf(s->line_normal, sizeof(s->line_normal), "%s", str);
|
||||||
}
|
}
|
||||||
@ -409,6 +421,20 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
s->avatar_path[0] = '\0';
|
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);
|
snprintf(s->password_eval, sizeof(s->password_eval), "%s", str);
|
||||||
int len = strlen(str);
|
int len = strlen(str);
|
||||||
@ -420,32 +446,44 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
|
|
||||||
/* keys */
|
/* keys */
|
||||||
if ((setting = config_lookup(cfg, key_strings.self)) != NULL) {
|
if ((setting = config_lookup(cfg, key_strings.self)) != NULL) {
|
||||||
const char* tmp = NULL;
|
const char *tmp = NULL;
|
||||||
|
|
||||||
if (config_setting_lookup_string(setting, key_strings.next_tab, &tmp))
|
if (config_setting_lookup_string(setting, key_strings.next_tab, &tmp))
|
||||||
set_key_binding(&s->key_next_tab, &tmp);
|
set_key_binding(&s->key_next_tab, &tmp);
|
||||||
|
|
||||||
if (config_setting_lookup_string(setting, key_strings.prev_tab, &tmp))
|
if (config_setting_lookup_string(setting, key_strings.prev_tab, &tmp))
|
||||||
set_key_binding(&s->key_prev_tab, &tmp);
|
set_key_binding(&s->key_prev_tab, &tmp);
|
||||||
|
|
||||||
if (config_setting_lookup_string(setting, key_strings.scroll_line_up, &tmp))
|
if (config_setting_lookup_string(setting, key_strings.scroll_line_up, &tmp))
|
||||||
set_key_binding(&s->key_scroll_line_up, &tmp);
|
set_key_binding(&s->key_scroll_line_up, &tmp);
|
||||||
|
|
||||||
if (config_setting_lookup_string(setting, key_strings.scroll_line_down, &tmp))
|
if (config_setting_lookup_string(setting, key_strings.scroll_line_down, &tmp))
|
||||||
set_key_binding(&s->key_scroll_line_down, &tmp);
|
set_key_binding(&s->key_scroll_line_down, &tmp);
|
||||||
|
|
||||||
if (config_setting_lookup_string(setting, key_strings.half_page_up, &tmp))
|
if (config_setting_lookup_string(setting, key_strings.half_page_up, &tmp))
|
||||||
set_key_binding(&s->key_half_page_up, &tmp);
|
set_key_binding(&s->key_half_page_up, &tmp);
|
||||||
|
|
||||||
if (config_setting_lookup_string(setting, key_strings.half_page_down, &tmp))
|
if (config_setting_lookup_string(setting, key_strings.half_page_down, &tmp))
|
||||||
set_key_binding(&s->key_half_page_down, &tmp);
|
set_key_binding(&s->key_half_page_down, &tmp);
|
||||||
|
|
||||||
if (config_setting_lookup_string(setting, key_strings.page_bottom, &tmp))
|
if (config_setting_lookup_string(setting, key_strings.page_bottom, &tmp))
|
||||||
set_key_binding(&s->key_page_bottom, &tmp);
|
set_key_binding(&s->key_page_bottom, &tmp);
|
||||||
|
|
||||||
if (config_setting_lookup_string(setting, key_strings.peer_list_up, &tmp))
|
if (config_setting_lookup_string(setting, key_strings.peer_list_up, &tmp))
|
||||||
set_key_binding(&s->key_peer_list_up, &tmp);
|
set_key_binding(&s->key_peer_list_up, &tmp);
|
||||||
|
|
||||||
if (config_setting_lookup_string(setting, key_strings.peer_list_down, &tmp))
|
if (config_setting_lookup_string(setting, key_strings.peer_list_down, &tmp))
|
||||||
set_key_binding(&s->key_peer_list_down, &tmp);
|
set_key_binding(&s->key_peer_list_down, &tmp);
|
||||||
|
|
||||||
if (config_setting_lookup_string(setting, key_strings.toggle_peerlist, &tmp))
|
if (config_setting_lookup_string(setting, key_strings.toggle_peerlist, &tmp))
|
||||||
set_key_binding(&s->key_toggle_peerlist, &tmp);
|
set_key_binding(&s->key_toggle_peerlist, &tmp);
|
||||||
|
|
||||||
if (config_setting_lookup_string(setting, key_strings.toggle_pastemode, &tmp))
|
if (config_setting_lookup_string(setting, key_strings.toggle_pastemode, &tmp))
|
||||||
set_key_binding(&s->key_toggle_pastemode, &tmp);
|
set_key_binding(&s->key_toggle_pastemode, &tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
|
|
||||||
if ((setting = config_lookup(cfg, audio_strings.self)) != NULL) {
|
if ((setting = config_lookup(cfg, audio_strings.self)) != NULL) {
|
||||||
config_setting_lookup_int(setting, audio_strings.input_device, &s->audio_in_dev);
|
config_setting_lookup_int(setting, audio_strings.input_device, &s->audio_in_dev);
|
||||||
s->audio_in_dev = s->audio_in_dev < 0 || s->audio_in_dev > MAX_DEVICES ? 0 : s->audio_in_dev;
|
s->audio_in_dev = s->audio_in_dev < 0 || s->audio_in_dev > MAX_DEVICES ? 0 : s->audio_in_dev;
|
||||||
@ -455,9 +493,11 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
|
|
||||||
config_setting_lookup_float(setting, audio_strings.VAD_treshold, &s->VAD_treshold);
|
config_setting_lookup_float(setting, audio_strings.VAD_treshold, &s->VAD_treshold);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
|
|
||||||
if ((setting = config_lookup(cfg, sound_strings.self)) != NULL) {
|
if ((setting = config_lookup(cfg, sound_strings.self)) != NULL) {
|
||||||
if ( (config_setting_lookup_string(setting, sound_strings.notif_error, &str) != CONFIG_TRUE) ||
|
if ( (config_setting_lookup_string(setting, sound_strings.notif_error, &str) != CONFIG_TRUE) ||
|
||||||
!set_sound(notif_error, str) ) {
|
!set_sound(notif_error, str) ) {
|
||||||
@ -506,8 +546,7 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
if (str && strcasecmp(str, NO_SOUND) != 0)
|
||||||
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/ToxicTransferComplete.wav");
|
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/ToxicTransferComplete.wav");
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
set_sound(notif_error, PACKAGE_DATADIR "/sounds/ToxicError.wav");
|
set_sound(notif_error, PACKAGE_DATADIR "/sounds/ToxicError.wav");
|
||||||
set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ToxicContactOnline.wav");
|
set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ToxicContactOnline.wav");
|
||||||
set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ToxicContactOffline.wav");
|
set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ToxicContactOffline.wav");
|
||||||
@ -517,6 +556,7 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
set_sound(transfer_pending, PACKAGE_DATADIR "/sounds/ToxicTransferStart.wav");
|
set_sound(transfer_pending, PACKAGE_DATADIR "/sounds/ToxicTransferStart.wav");
|
||||||
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/ToxicTransferComplete.wav");
|
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/ToxicTransferComplete.wav");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
config_destroy(cfg);
|
config_destroy(cfg);
|
||||||
|
@ -63,6 +63,7 @@ struct user_settings {
|
|||||||
char download_path[PATH_MAX];
|
char download_path[PATH_MAX];
|
||||||
char chatlogs_path[PATH_MAX];
|
char chatlogs_path[PATH_MAX];
|
||||||
char avatar_path[PATH_MAX];
|
char avatar_path[PATH_MAX];
|
||||||
|
char autorun_path[PATH_MAX];
|
||||||
char password_eval[PASSWORD_EVAL_MAX];
|
char password_eval[PASSWORD_EVAL_MAX];
|
||||||
|
|
||||||
int key_next_tab;
|
int key_next_tab;
|
||||||
|
@ -52,8 +52,7 @@ extern struct Winthread Winthread;
|
|||||||
#define PATH_SEP_S "/"
|
#define PATH_SEP_S "/"
|
||||||
#define PATH_SEP_C '/'
|
#define PATH_SEP_C '/'
|
||||||
|
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
|
||||||
MPLEX_NONE,
|
MPLEX_NONE,
|
||||||
MPLEX_SCREEN,
|
MPLEX_SCREEN,
|
||||||
MPLEX_TMUX,
|
MPLEX_TMUX,
|
||||||
@ -97,13 +96,14 @@ static char *read_into_dyn_buffer (FILE *stream)
|
|||||||
char *dyn_buffer = NULL;
|
char *dyn_buffer = NULL;
|
||||||
int dyn_buffer_size = 1; /* account for the \0 */
|
int dyn_buffer_size = 1; /* account for the \0 */
|
||||||
|
|
||||||
while ((input_ptr = fgets (buffer, BUFFER_SIZE, stream)) != NULL)
|
while ((input_ptr = fgets (buffer, BUFFER_SIZE, stream)) != NULL) {
|
||||||
{
|
|
||||||
int length = dyn_buffer_size + strlen (input_ptr);
|
int length = dyn_buffer_size + strlen (input_ptr);
|
||||||
|
|
||||||
if (dyn_buffer)
|
if (dyn_buffer)
|
||||||
dyn_buffer = (char*) realloc (dyn_buffer, length);
|
dyn_buffer = (char *) realloc (dyn_buffer, length);
|
||||||
else
|
else
|
||||||
dyn_buffer = (char*) malloc (length);
|
dyn_buffer = (char *) malloc (length);
|
||||||
|
|
||||||
strcpy (dyn_buffer + dyn_buffer_size - 1, input_ptr);
|
strcpy (dyn_buffer + dyn_buffer_size - 1, input_ptr);
|
||||||
dyn_buffer_size = length;
|
dyn_buffer_size = length;
|
||||||
}
|
}
|
||||||
@ -116,26 +116,29 @@ static char *extract_socket_path (const char *info)
|
|||||||
const char *search_str = " Socket";
|
const char *search_str = " Socket";
|
||||||
const char *pos = strstr (info, search_str);
|
const char *pos = strstr (info, search_str);
|
||||||
char *end = NULL;
|
char *end = NULL;
|
||||||
char* path = NULL;
|
char *path = NULL;
|
||||||
|
|
||||||
if (!pos)
|
if (!pos)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
pos += strlen (search_str);
|
pos += strlen (search_str);
|
||||||
pos = strchr (pos, PATH_SEP_C);
|
pos = strchr (pos, PATH_SEP_C);
|
||||||
|
|
||||||
if (!pos)
|
if (!pos)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
end = strchr (pos, '\n');
|
end = strchr (pos, '\n');
|
||||||
|
|
||||||
if (!end)
|
if (!end)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
*end = '\0';
|
*end = '\0';
|
||||||
end = strrchr (pos, '.');
|
end = strrchr (pos, '.');
|
||||||
|
|
||||||
if (!end)
|
if (!end)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
path = (char*) malloc (end - pos + 1);
|
path = (char *) malloc (end - pos + 1);
|
||||||
*end = '\0';
|
*end = '\0';
|
||||||
return strcpy (path, pos);
|
return strcpy (path, pos);
|
||||||
}
|
}
|
||||||
@ -147,14 +150,17 @@ static int detect_gnu_screen ()
|
|||||||
char *dyn_buffer = NULL;
|
char *dyn_buffer = NULL;
|
||||||
|
|
||||||
socket_name = getenv ("STY");
|
socket_name = getenv ("STY");
|
||||||
|
|
||||||
if (!socket_name)
|
if (!socket_name)
|
||||||
goto nomplex;
|
goto nomplex;
|
||||||
|
|
||||||
session_info_stream = popen ("env LC_ALL=C screen -ls", "r");
|
session_info_stream = popen ("env LC_ALL=C screen -ls", "r");
|
||||||
|
|
||||||
if (!session_info_stream)
|
if (!session_info_stream)
|
||||||
goto nomplex;
|
goto nomplex;
|
||||||
|
|
||||||
dyn_buffer = read_into_dyn_buffer (session_info_stream);
|
dyn_buffer = read_into_dyn_buffer (session_info_stream);
|
||||||
|
|
||||||
if (!dyn_buffer)
|
if (!dyn_buffer)
|
||||||
goto nomplex;
|
goto nomplex;
|
||||||
|
|
||||||
@ -162,6 +168,7 @@ static int detect_gnu_screen ()
|
|||||||
session_info_stream = NULL;
|
session_info_stream = NULL;
|
||||||
|
|
||||||
socket_path = extract_socket_path (dyn_buffer);
|
socket_path = extract_socket_path (dyn_buffer);
|
||||||
|
|
||||||
if (!socket_path)
|
if (!socket_path)
|
||||||
goto nomplex;
|
goto nomplex;
|
||||||
|
|
||||||
@ -181,28 +188,34 @@ static int detect_gnu_screen ()
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
nomplex:
|
nomplex:
|
||||||
|
|
||||||
if (session_info_stream)
|
if (session_info_stream)
|
||||||
pclose (session_info_stream);
|
pclose (session_info_stream);
|
||||||
|
|
||||||
if (dyn_buffer)
|
if (dyn_buffer)
|
||||||
free (dyn_buffer);
|
free (dyn_buffer);
|
||||||
|
|
||||||
if (socket_path)
|
if (socket_path)
|
||||||
free(socket_path);
|
free(socket_path);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int detect_tmux ()
|
static int detect_tmux ()
|
||||||
{
|
{
|
||||||
char *tmux_env = getenv ("TMUX"), *pos;
|
char *tmux_env = getenv ("TMUX"), *pos;
|
||||||
|
|
||||||
if (!tmux_env)
|
if (!tmux_env)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* find second separator */
|
/* find second separator */
|
||||||
pos = strrchr (tmux_env, ',');
|
pos = strrchr (tmux_env, ',');
|
||||||
|
|
||||||
if (!pos)
|
if (!pos)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* store the session number string for later use */
|
/* store the session id for later use */
|
||||||
snprintf (mplex_data, sizeof(mplex_data), "%s", pos + 1);
|
snprintf (mplex_data, sizeof(mplex_data), "$%s", pos + 1);
|
||||||
mplex = MPLEX_TMUX;
|
mplex = MPLEX_TMUX;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -230,6 +243,7 @@ static int gnu_screen_is_detached ()
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
|
|
||||||
if (stat (mplex_data, &sb) != 0)
|
if (stat (mplex_data, &sb) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -238,14 +252,8 @@ static int gnu_screen_is_detached ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Detects tmux attached/detached by getting session data and finding the
|
/* Detects tmux attached/detached by getting session data and finding the
|
||||||
current session's entry. An attached entry ends with "(attached)". Example:
|
current session's entry.
|
||||||
|
*/
|
||||||
$ 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 ()
|
static int tmux_is_detached ()
|
||||||
{
|
{
|
||||||
if (mplex != MPLEX_TMUX)
|
if (mplex != MPLEX_TMUX)
|
||||||
@ -253,14 +261,18 @@ static int tmux_is_detached ()
|
|||||||
|
|
||||||
FILE *session_info_stream = NULL;
|
FILE *session_info_stream = NULL;
|
||||||
char *dyn_buffer = NULL, *search_str = NULL;
|
char *dyn_buffer = NULL, *search_str = NULL;
|
||||||
char *entry_pos, *nl_pos, *attached_pos;
|
char *entry_pos;
|
||||||
|
int detached;
|
||||||
const int numstr_len = strlen (mplex_data);
|
const int numstr_len = strlen (mplex_data);
|
||||||
|
|
||||||
session_info_stream = popen ("env LC_ALL=C tmux list-sessions", "r");
|
/* get the number of attached clients for each session */
|
||||||
|
session_info_stream = popen ("tmux list-sessions -F \"#{session_id} #{session_attached}\"", "r");
|
||||||
|
|
||||||
if (!session_info_stream)
|
if (!session_info_stream)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
dyn_buffer = read_into_dyn_buffer (session_info_stream);
|
dyn_buffer = read_into_dyn_buffer (session_info_stream);
|
||||||
|
|
||||||
if (!dyn_buffer)
|
if (!dyn_buffer)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
@ -268,13 +280,12 @@ static int tmux_is_detached ()
|
|||||||
session_info_stream = NULL;
|
session_info_stream = NULL;
|
||||||
|
|
||||||
/* prepare search string, for finding the current session's entry */
|
/* prepare search string, for finding the current session's entry */
|
||||||
search_str = (char*) malloc (numstr_len + 4);
|
search_str = (char *) malloc (numstr_len + 2);
|
||||||
search_str[0] = '\n';
|
search_str[0] = '\n';
|
||||||
strcpy (search_str + 1, mplex_data);
|
strcpy (search_str + 1, mplex_data);
|
||||||
strcat (search_str, ": ");
|
|
||||||
|
|
||||||
/* do the search */
|
/* do the search */
|
||||||
if (strncmp (dyn_buffer, search_str + 1, numstr_len + 2) == 0)
|
if (strncmp (dyn_buffer, search_str + 1, numstr_len) == 0)
|
||||||
entry_pos = dyn_buffer;
|
entry_pos = dyn_buffer;
|
||||||
else
|
else
|
||||||
entry_pos = strstr (dyn_buffer, search_str);
|
entry_pos = strstr (dyn_buffer, search_str);
|
||||||
@ -282,9 +293,8 @@ static int tmux_is_detached ()
|
|||||||
if (! entry_pos)
|
if (! entry_pos)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* find the next \n and look for the "(attached)" before it */
|
entry_pos = strchr (entry_pos, ' ') + 1;
|
||||||
nl_pos = strchr (entry_pos + 1, '\n');
|
detached = strncmp (entry_pos, "0\n", 2) == 0;
|
||||||
attached_pos = strstr (entry_pos + 1, "(attached)\n");
|
|
||||||
|
|
||||||
free (search_str);
|
free (search_str);
|
||||||
search_str = NULL;
|
search_str = NULL;
|
||||||
@ -292,15 +302,19 @@ static int tmux_is_detached ()
|
|||||||
free (dyn_buffer);
|
free (dyn_buffer);
|
||||||
dyn_buffer = NULL;
|
dyn_buffer = NULL;
|
||||||
|
|
||||||
return attached_pos == NULL || attached_pos > nl_pos;
|
return detached;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
|
||||||
if (session_info_stream)
|
if (session_info_stream)
|
||||||
pclose (session_info_stream);
|
pclose (session_info_stream);
|
||||||
|
|
||||||
if (dyn_buffer)
|
if (dyn_buffer)
|
||||||
free (dyn_buffer);
|
free (dyn_buffer);
|
||||||
|
|
||||||
if (search_str)
|
if (search_str)
|
||||||
free (search_str);
|
free (search_str);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,26 +346,21 @@ static void mplex_timer_handler (Tox *m)
|
|||||||
current_status = tox_self_get_status (m);
|
current_status = tox_self_get_status (m);
|
||||||
pthread_mutex_unlock (&Winthread.lock);
|
pthread_mutex_unlock (&Winthread.lock);
|
||||||
|
|
||||||
if (auto_away_active && current_status == TOX_USER_STATUS_AWAY && !detached)
|
if (auto_away_active && current_status == TOX_USER_STATUS_AWAY && !detached) {
|
||||||
{
|
|
||||||
auto_away_active = false;
|
auto_away_active = false;
|
||||||
new_status = prev_status;
|
new_status = prev_status;
|
||||||
new_note = prev_note;
|
new_note = prev_note;
|
||||||
}
|
} else if (current_status == TOX_USER_STATUS_NONE && detached) {
|
||||||
else
|
|
||||||
if (current_status == TOX_USER_STATUS_NONE && detached)
|
|
||||||
{
|
|
||||||
auto_away_active = true;
|
auto_away_active = true;
|
||||||
prev_status = current_status;
|
prev_status = current_status;
|
||||||
new_status = TOX_USER_STATUS_AWAY;
|
new_status = TOX_USER_STATUS_AWAY;
|
||||||
pthread_mutex_lock (&Winthread.lock);
|
pthread_mutex_lock (&Winthread.lock);
|
||||||
size_t slen = tox_self_get_status_message_size(m);
|
size_t slen = tox_self_get_status_message_size(m);
|
||||||
tox_self_get_status_message (m, (uint8_t*) prev_note);
|
tox_self_get_status_message (m, (uint8_t *) prev_note);
|
||||||
prev_note[slen] = '\0';
|
prev_note[slen] = '\0';
|
||||||
pthread_mutex_unlock (&Winthread.lock);
|
pthread_mutex_unlock (&Winthread.lock);
|
||||||
new_note = user_settings->mplex_away_note;
|
new_note = user_settings->mplex_away_note;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
char argv[3][MAX_STR_SIZE];
|
char argv[3][MAX_STR_SIZE];
|
||||||
|
119
src/toxic.c
119
src/toxic.c
@ -26,6 +26,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -64,7 +65,7 @@
|
|||||||
#include "bootstrap.h"
|
#include "bootstrap.h"
|
||||||
|
|
||||||
#ifdef X11
|
#ifdef X11
|
||||||
#include "xtra.h"
|
#include "xtra.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
@ -75,8 +76,13 @@
|
|||||||
ToxAV *av;
|
ToxAV *av;
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
|
#ifdef PYTHON
|
||||||
|
#include "api.h"
|
||||||
|
#include "python_api.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef PACKAGE_DATADIR
|
#ifndef PACKAGE_DATADIR
|
||||||
#define PACKAGE_DATADIR "."
|
#define PACKAGE_DATADIR "."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Export for use in Callbacks */
|
/* Export for use in Callbacks */
|
||||||
@ -104,9 +110,17 @@ static struct user_password {
|
|||||||
int len;
|
int len;
|
||||||
} user_password;
|
} user_password;
|
||||||
|
|
||||||
|
static time_t last_signal_time;
|
||||||
|
|
||||||
static void catch_SIGINT(int sig)
|
static void catch_SIGINT(int sig)
|
||||||
{
|
{
|
||||||
Winthread.sig_exit_toxic = 1;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void catch_SIGSEGV(int sig)
|
static void catch_SIGSEGV(int sig)
|
||||||
@ -162,6 +176,10 @@ void exit_toxic_success(Tox *m)
|
|||||||
terminate_audio();
|
terminate_audio();
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
|
#ifdef PYTHON
|
||||||
|
terminate_python();
|
||||||
|
#endif /* PYTHON */
|
||||||
|
|
||||||
free_global_data();
|
free_global_data();
|
||||||
tox_kill(m);
|
tox_kill(m);
|
||||||
endwin();
|
endwin();
|
||||||
@ -320,8 +338,10 @@ static int password_prompt(char *buf, int size)
|
|||||||
/* eat overflowed stdin and return error */
|
/* eat overflowed stdin and return error */
|
||||||
if (buf[--len] != '\n') {
|
if (buf[--len] != '\n') {
|
||||||
int ch;
|
int ch;
|
||||||
|
|
||||||
while ((ch = getchar()) != '\n' && ch > 0)
|
while ((ch = getchar()) != '\n' && ch > 0)
|
||||||
;
|
;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,6 +358,7 @@ static int password_eval(char *buf, int size)
|
|||||||
|
|
||||||
/* Run password_eval command */
|
/* Run password_eval command */
|
||||||
FILE *f = popen(user_settings->password_eval, "r");
|
FILE *f = popen(user_settings->password_eval, "r");
|
||||||
|
|
||||||
if (f == NULL) {
|
if (f == NULL) {
|
||||||
fprintf(stderr, "Executing password_eval failed\n");
|
fprintf(stderr, "Executing password_eval failed\n");
|
||||||
return 0;
|
return 0;
|
||||||
@ -345,6 +366,7 @@ static int password_eval(char *buf, int size)
|
|||||||
|
|
||||||
/* Get output from command */
|
/* Get output from command */
|
||||||
char *ret = fgets(buf, size, f);
|
char *ret = fgets(buf, size, f);
|
||||||
|
|
||||||
if (ret == NULL) {
|
if (ret == NULL) {
|
||||||
fprintf(stderr, "Reading password from password_eval command failed\n");
|
fprintf(stderr, "Reading password from password_eval command failed\n");
|
||||||
pclose(f);
|
pclose(f);
|
||||||
@ -353,6 +375,7 @@ static int password_eval(char *buf, int size)
|
|||||||
|
|
||||||
/* Get exit status */
|
/* Get exit status */
|
||||||
int status = pclose(f);
|
int status = pclose(f);
|
||||||
|
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
fprintf(stderr, "password_eval command returned error %d\n", status);
|
fprintf(stderr, "password_eval command returned error %d\n", status);
|
||||||
return 0;
|
return 0;
|
||||||
@ -360,6 +383,7 @@ static int password_eval(char *buf, int size)
|
|||||||
|
|
||||||
/* Removez whitespace or \n at end */
|
/* Removez whitespace or \n at end */
|
||||||
int i, len = strlen(buf);
|
int i, len = strlen(buf);
|
||||||
|
|
||||||
for (i = len - 1; i > 0 && isspace(buf[i]); i--) {
|
for (i = len - 1; i > 0 && isspace(buf[i]); i--) {
|
||||||
buf[i] = 0;
|
buf[i] = 0;
|
||||||
len--;
|
len--;
|
||||||
@ -376,9 +400,10 @@ static void first_time_encrypt(const char *msg)
|
|||||||
do {
|
do {
|
||||||
system("clear");
|
system("clear");
|
||||||
printf("%s ", msg);
|
printf("%s ", msg);
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
if (!strcasecmp(ch, "y\n") || !strcasecmp(ch, "n\n") || !strcasecmp(ch, "yes\n")
|
if (!strcasecmp(ch, "y\n") || !strcasecmp(ch, "n\n") || !strcasecmp(ch, "yes\n")
|
||||||
|| !strcasecmp(ch, "no\n") || !strcasecmp(ch, "q\n"))
|
|| !strcasecmp(ch, "no\n") || !strcasecmp(ch, "q\n"))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
} while (fgets(ch, sizeof(ch), stdin));
|
} while (fgets(ch, sizeof(ch), stdin));
|
||||||
@ -396,6 +421,7 @@ static void first_time_encrypt(const char *msg)
|
|||||||
printf("Enter a new password (must be at least %d characters) ", MIN_PASSWORD_LEN);
|
printf("Enter a new password (must be at least %d characters) ", MIN_PASSWORD_LEN);
|
||||||
|
|
||||||
while (valid_password == false) {
|
while (valid_password == false) {
|
||||||
|
fflush(stdout); // Flush all before user input
|
||||||
len = password_prompt(user_password.pass, sizeof(user_password.pass));
|
len = password_prompt(user_password.pass, sizeof(user_password.pass));
|
||||||
user_password.len = len;
|
user_password.len = len;
|
||||||
|
|
||||||
@ -514,24 +540,23 @@ int store_data(Tox *m, const char *path)
|
|||||||
|
|
||||||
static void init_tox_callbacks(Tox *m)
|
static void init_tox_callbacks(Tox *m)
|
||||||
{
|
{
|
||||||
tox_callback_self_connection_status(m, prompt_onSelfConnectionChange, NULL);
|
tox_callback_self_connection_status(m, prompt_onSelfConnectionChange);
|
||||||
tox_callback_friend_connection_status(m, on_connectionchange, NULL);
|
tox_callback_friend_connection_status(m, on_connectionchange);
|
||||||
tox_callback_friend_typing(m, on_typing_change, NULL);
|
tox_callback_friend_typing(m, on_typing_change);
|
||||||
tox_callback_friend_request(m, on_request, NULL);
|
tox_callback_friend_request(m, on_request);
|
||||||
tox_callback_friend_message(m, on_message, NULL);
|
tox_callback_friend_message(m, on_message);
|
||||||
tox_callback_friend_name(m, on_nickchange, NULL);
|
tox_callback_friend_name(m, on_nickchange);
|
||||||
tox_callback_friend_status(m, on_statuschange, NULL);
|
tox_callback_friend_status(m, on_statuschange);
|
||||||
tox_callback_friend_status_message(m, on_statusmessagechange, NULL);
|
tox_callback_friend_status_message(m, on_statusmessagechange);
|
||||||
tox_callback_friend_read_receipt(m, on_read_receipt, NULL);
|
tox_callback_friend_read_receipt(m, on_read_receipt);
|
||||||
tox_callback_group_invite(m, on_groupinvite, NULL);
|
tox_callback_conference_invite(m, on_groupinvite);
|
||||||
tox_callback_group_message(m, on_groupmessage, NULL);
|
tox_callback_conference_message(m, on_groupmessage);
|
||||||
tox_callback_group_action(m, on_groupaction, NULL);
|
tox_callback_conference_namelist_change(m, on_group_namelistchange);
|
||||||
tox_callback_group_namelist_change(m, on_group_namelistchange, NULL);
|
tox_callback_conference_title(m, on_group_titlechange);
|
||||||
tox_callback_group_title(m, on_group_titlechange, NULL);
|
tox_callback_file_recv(m, on_file_recv);
|
||||||
tox_callback_file_recv(m, on_file_recv, NULL);
|
tox_callback_file_chunk_request(m, on_file_chunk_request);
|
||||||
tox_callback_file_chunk_request(m, on_file_chunk_request, NULL);
|
tox_callback_file_recv_control(m, on_file_control);
|
||||||
tox_callback_file_recv_control(m, on_file_control, NULL);
|
tox_callback_file_recv_chunk(m, on_file_recv_chunk);
|
||||||
tox_callback_file_recv_chunk(m, on_file_recv_chunk, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_tox_options(struct Tox_Options *tox_opts)
|
static void init_tox_options(struct Tox_Options *tox_opts)
|
||||||
@ -554,7 +579,7 @@ static void init_tox_options(struct Tox_Options *tox_opts)
|
|||||||
tox_opts->proxy_host = arg_opts.proxy_address;
|
tox_opts->proxy_host = arg_opts.proxy_address;
|
||||||
const char *ps = tox_opts->proxy_type == TOX_PROXY_TYPE_SOCKS5 ? "SOCKS5" : "HTTP";
|
const char *ps = tox_opts->proxy_type == TOX_PROXY_TYPE_SOCKS5 ? "SOCKS5" : "HTTP";
|
||||||
|
|
||||||
char tmp[48];
|
char tmp[sizeof(arg_opts.proxy_address) + MAX_STR_SIZE];
|
||||||
snprintf(tmp, sizeof(tmp), "Using %s proxy %s : %d", ps, arg_opts.proxy_address, arg_opts.proxy_port);
|
snprintf(tmp, sizeof(tmp), "Using %s proxy %s : %d", ps, arg_opts.proxy_address, arg_opts.proxy_port);
|
||||||
queue_init_message("%s", tmp);
|
queue_init_message("%s", tmp);
|
||||||
}
|
}
|
||||||
@ -612,6 +637,7 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
|
|||||||
|
|
||||||
size_t pwlen = 0;
|
size_t pwlen = 0;
|
||||||
int pweval = user_settings->password_eval[0];
|
int pweval = user_settings->password_eval[0];
|
||||||
|
|
||||||
if (!pweval) {
|
if (!pweval) {
|
||||||
system("clear"); // TODO: is this portable?
|
system("clear"); // TODO: is this portable?
|
||||||
printf("Enter password (q to quit) ");
|
printf("Enter password (q to quit) ");
|
||||||
@ -621,11 +647,14 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, TOX_ERR_NEW
|
|||||||
char plain[plain_len];
|
char plain[plain_len];
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
fflush(stdout); // Flush before prompts so the user sees the question/message
|
||||||
|
|
||||||
if (pweval) {
|
if (pweval) {
|
||||||
pwlen = password_eval(user_password.pass, sizeof(user_password.pass));
|
pwlen = password_eval(user_password.pass, sizeof(user_password.pass));
|
||||||
} else {
|
} else {
|
||||||
pwlen = password_prompt(user_password.pass, sizeof(user_password.pass));
|
pwlen = password_prompt(user_password.pass, sizeof(user_password.pass));
|
||||||
}
|
}
|
||||||
|
|
||||||
user_password.len = pwlen;
|
user_password.len = pwlen;
|
||||||
|
|
||||||
if (strcasecmp(user_password.pass, "q") == 0) {
|
if (strcasecmp(user_password.pass, "q") == 0) {
|
||||||
@ -739,7 +768,7 @@ static void do_toxic(Tox *m)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tox_iterate(m);
|
tox_iterate(m, NULL);
|
||||||
do_tox_connection(m);
|
do_tox_connection(m);
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
}
|
}
|
||||||
@ -785,7 +814,7 @@ void *thread_cqueue(void *data)
|
|||||||
ToxWindow *toxwin = get_window_ptr(i);
|
ToxWindow *toxwin = get_window_ptr(i);
|
||||||
|
|
||||||
if (toxwin != NULL && toxwin->is_chat
|
if (toxwin != NULL && toxwin->is_chat
|
||||||
&& tox_friend_get_connection_status(m, toxwin->num, NULL) != TOX_CONNECTION_NONE)
|
&& tox_friend_get_connection_status(m, toxwin->num, NULL) != TOX_CONNECTION_NONE)
|
||||||
cqueue_try_send(toxwin, m);
|
cqueue_try_send(toxwin, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -828,6 +857,13 @@ static void print_usage(void)
|
|||||||
fprintf(stderr, " -t, --force-tcp Force toxic to use a TCP connection (use with proxies)\n");
|
fprintf(stderr, " -t, --force-tcp Force toxic to use a TCP connection (use with proxies)\n");
|
||||||
fprintf(stderr, " -T, --tcp-server Act as a TCP relay server: Requires [port]\n");
|
fprintf(stderr, " -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, " -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)
|
static void set_default_opts(void)
|
||||||
@ -858,10 +894,11 @@ static void parse_args(int argc, char *argv[])
|
|||||||
{"SOCKS5-proxy", required_argument, 0, 'p'},
|
{"SOCKS5-proxy", required_argument, 0, 'p'},
|
||||||
{"HTTP-proxy", required_argument, 0, 'P'},
|
{"HTTP-proxy", required_argument, 0, 'P'},
|
||||||
{"unencrypt-data", no_argument, 0, 'u'},
|
{"unencrypt-data", no_argument, 0, 'u'},
|
||||||
|
{"version", no_argument, 0, 'v'},
|
||||||
{NULL, no_argument, NULL, 0},
|
{NULL, no_argument, NULL, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *opts_str = "4bdehotuxc:f:n:r:p:P:T:";
|
const char *opts_str = "4bdehotuxvc:f:n:r:p:P:T:";
|
||||||
int opt, indexptr;
|
int opt, indexptr;
|
||||||
long int port = 0;
|
long int port = 0;
|
||||||
|
|
||||||
@ -933,10 +970,10 @@ static void parse_args(int argc, char *argv[])
|
|||||||
arg_opts.proxy_type = TOX_PROXY_TYPE_SOCKS5;
|
arg_opts.proxy_type = TOX_PROXY_TYPE_SOCKS5;
|
||||||
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
|
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
|
||||||
|
|
||||||
if (++optind > argc || argv[optind-1][0] == '-')
|
if (++optind > argc || argv[optind - 1][0] == '-')
|
||||||
exit_toxic_err("Proxy error", FATALERR_PROXY);
|
exit_toxic_err("Proxy error", FATALERR_PROXY);
|
||||||
|
|
||||||
port = strtol(argv[optind-1], NULL, 10);
|
port = strtol(argv[optind - 1], NULL, 10);
|
||||||
|
|
||||||
if (port <= 0 || port > MAX_PORT_RANGE)
|
if (port <= 0 || port > MAX_PORT_RANGE)
|
||||||
exit_toxic_err("Proxy error", FATALERR_PROXY);
|
exit_toxic_err("Proxy error", FATALERR_PROXY);
|
||||||
@ -948,10 +985,10 @@ static void parse_args(int argc, char *argv[])
|
|||||||
arg_opts.proxy_type = TOX_PROXY_TYPE_HTTP;
|
arg_opts.proxy_type = TOX_PROXY_TYPE_HTTP;
|
||||||
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
|
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
|
||||||
|
|
||||||
if (++optind > argc || argv[optind-1][0] == '-')
|
if (++optind > argc || argv[optind - 1][0] == '-')
|
||||||
exit_toxic_err("Proxy error", FATALERR_PROXY);
|
exit_toxic_err("Proxy error", FATALERR_PROXY);
|
||||||
|
|
||||||
port = strtol(argv[optind-1], NULL, 10);
|
port = strtol(argv[optind - 1], NULL, 10);
|
||||||
|
|
||||||
if (port <= 0 || port > MAX_PORT_RANGE)
|
if (port <= 0 || port > MAX_PORT_RANGE)
|
||||||
exit_toxic_err("Proxy error", FATALERR_PROXY);
|
exit_toxic_err("Proxy error", FATALERR_PROXY);
|
||||||
@ -984,6 +1021,10 @@ static void parse_args(int argc, char *argv[])
|
|||||||
arg_opts.unencrypt_data = 1;
|
arg_opts.unencrypt_data = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'v':
|
||||||
|
print_version();
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
default:
|
default:
|
||||||
print_usage();
|
print_usage();
|
||||||
@ -1077,7 +1118,7 @@ static void init_default_data_files(void)
|
|||||||
|
|
||||||
// this doesn't do anything (yet)
|
// this doesn't do anything (yet)
|
||||||
#ifdef X11
|
#ifdef X11
|
||||||
void DnD_callback(const char* asdv, DropType dt)
|
void DnD_callback(const char *asdv, DropType dt)
|
||||||
{
|
{
|
||||||
// if (dt != DT_plain)
|
// if (dt != DT_plain)
|
||||||
// return;
|
// return;
|
||||||
@ -1124,7 +1165,7 @@ int main(int argc, char **argv)
|
|||||||
const char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL;
|
const char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL;
|
||||||
|
|
||||||
if (settings_load(user_settings, p) == -1) {
|
if (settings_load(user_settings, p) == -1) {
|
||||||
queue_init_message("Failed to load user settings");
|
queue_init_message("Failed to load user settings");
|
||||||
}
|
}
|
||||||
|
|
||||||
int curl_init = curl_global_init(CURL_GLOBAL_ALL);
|
int curl_init = curl_global_init(CURL_GLOBAL_ALL);
|
||||||
@ -1139,8 +1180,10 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef X11
|
#ifdef X11
|
||||||
|
|
||||||
if (init_xtra(DnD_callback) == -1)
|
if (init_xtra(DnD_callback) == -1)
|
||||||
queue_init_message("X failed to initialize");
|
queue_init_message("X failed to initialize");
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Tox *m = load_toxic(DATA_FILE);
|
Tox *m = load_toxic(DATA_FILE);
|
||||||
@ -1182,11 +1225,19 @@ int main(int argc, char **argv)
|
|||||||
set_primary_device(output, user_settings->audio_out_dev);
|
set_primary_device(output, user_settings->audio_out_dev);
|
||||||
|
|
||||||
#elif SOUND_NOTIFY
|
#elif SOUND_NOTIFY
|
||||||
|
|
||||||
if ( init_devices() == de_InternalError )
|
if ( init_devices() == de_InternalError )
|
||||||
queue_init_message("Failed to init audio devices");
|
queue_init_message("Failed to init audio devices");
|
||||||
|
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
|
#ifdef PYTHON
|
||||||
|
|
||||||
|
init_python(m);
|
||||||
|
invoke_autoruns(prompt->chatwin->history, prompt);
|
||||||
|
|
||||||
|
#endif /* PYTHON */
|
||||||
|
|
||||||
init_notify(60, 3000);
|
init_notify(60, 3000);
|
||||||
|
|
||||||
/* screen/tmux auto-away timer */
|
/* screen/tmux auto-away timer */
|
||||||
@ -1206,7 +1257,7 @@ int main(int argc, char **argv)
|
|||||||
cleanup_init_messages();
|
cleanup_init_messages();
|
||||||
|
|
||||||
/* set user avatar from config file. if no path is supplied tox_unset_avatar is called */
|
/* set user avatar from config file. if no path is supplied tox_unset_avatar is called */
|
||||||
char avatarstr[MAX_STR_SIZE];
|
char avatarstr[PATH_MAX + 11];
|
||||||
snprintf(avatarstr, sizeof(avatarstr), "/avatar \"%s\"", user_settings->avatar_path);
|
snprintf(avatarstr, sizeof(avatarstr), "/avatar \"%s\"", user_settings->avatar_path);
|
||||||
execute(prompt->chatwin->history, prompt, m, avatarstr, GLOBAL_COMMAND_MODE);
|
execute(prompt->chatwin->history, prompt, m, avatarstr, GLOBAL_COMMAND_MODE);
|
||||||
|
|
||||||
@ -1219,8 +1270,10 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
if (timed_out(last_save, AUTOSAVE_FREQ)) {
|
if (timed_out(last_save, AUTOSAVE_FREQ)) {
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
|
|
||||||
if (store_data(m, DATA_FILE) != 0)
|
if (store_data(m, DATA_FILE) != 0)
|
||||||
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, "WARNING: Failed to save to data file");
|
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, "WARNING: Failed to save to data file");
|
||||||
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
last_save = cur_time;
|
last_save = cur_time;
|
||||||
|
19
src/toxic.h
19
src/toxic.h
@ -107,18 +107,23 @@ int store_data(Tox *m, const char *path);
|
|||||||
/* callbacks */
|
/* callbacks */
|
||||||
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata);
|
void on_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_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_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_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_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_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_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_friendadded(Tox *m, uint32_t friendnumber, bool sort);
|
||||||
void on_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *message, uint16_t length, void *userdata);
|
void on_groupmessage(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_MESSAGE_TYPE type,
|
||||||
void on_groupaction(Tox *m, int groupnumber, int peernumber, const uint8_t *action, uint16_t length, void *userdata);
|
const uint8_t *message, 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_groupinvite(Tox *m, uint32_t friendnumber, TOX_CONFERENCE_TYPE type, const uint8_t *group_pub_key,
|
||||||
void on_group_namelistchange(Tox *m, int groupnumber, int peernumber, uint8_t change, void *userdata);
|
size_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_group_namelistchange(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_CONFERENCE_STATE_CHANGE change,
|
||||||
void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length, void *userdata);
|
void *userdata);
|
||||||
|
void on_group_titlechange(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *title, size_t length,
|
||||||
|
void *userdata);
|
||||||
|
void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length,
|
||||||
|
void *userdata);
|
||||||
void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data,
|
void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data,
|
||||||
size_t length, void *userdata);
|
size_t length, void *userdata);
|
||||||
void on_file_control (Tox *m, uint32_t friendnumber, uint32_t filenumber, TOX_FILE_CONTROL control, void *userdata);
|
void on_file_control (Tox *m, uint32_t friendnumber, uint32_t filenumber, TOX_FILE_CONTROL control, void *userdata);
|
||||||
|
@ -136,13 +136,13 @@ int del_word_buf(ChatContext *ctx)
|
|||||||
int i = ctx->pos, count = 0;
|
int i = ctx->pos, count = 0;
|
||||||
|
|
||||||
/* traverse past empty space */
|
/* traverse past empty space */
|
||||||
while (i > 0 && ctx->line[i-1] == L' ') {
|
while (i > 0 && ctx->line[i - 1] == L' ') {
|
||||||
++count;
|
++count;
|
||||||
--i;
|
--i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* traverse past last entered word */
|
/* traverse past last entered word */
|
||||||
while (i > 0 && ctx->line[i-1] != L' ') {
|
while (i > 0 && ctx->line[i - 1] != L' ') {
|
||||||
++count;
|
++count;
|
||||||
--i;
|
--i;
|
||||||
}
|
}
|
||||||
@ -243,18 +243,20 @@ void fetch_hist_item(ChatContext *ctx, int key_dir)
|
|||||||
ctx->len = h_len;
|
ctx->len = h_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
void strsubst(char* str, char old, char new)
|
void strsubst(char *str, char old, char new)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; str[i] != '\0'; ++i)
|
for (i = 0; str[i] != '\0'; ++i)
|
||||||
if (str[i] == old)
|
if (str[i] == old)
|
||||||
str[i] = new;
|
str[i] = new;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wstrsubst(wchar_t* str, wchar_t old, wchar_t new)
|
void wstrsubst(wchar_t *str, wchar_t old, wchar_t new)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; str[i] != L'\0'; ++i)
|
for (i = 0; str[i] != L'\0'; ++i)
|
||||||
if (str[i] == old)
|
if (str[i] == old)
|
||||||
str[i] = new;
|
str[i] = new;
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ void reset_buf(ChatContext *ctx);
|
|||||||
Return 0 on success, -1 if yank buffer is empty or too long */
|
Return 0 on success, -1 if yank buffer is empty or too long */
|
||||||
int yank_buf(ChatContext *ctx);
|
int yank_buf(ChatContext *ctx);
|
||||||
|
|
||||||
/* Deletes all characters from line starting at pos and going backwards
|
/* Deletes all characters from line starting at pos and going backwards
|
||||||
until we find a space or run out of characters.
|
until we find a space or run out of characters.
|
||||||
Return 0 on success, -1 if no line or already at the beginning */
|
Return 0 on success, -1 if no line or already at the beginning */
|
||||||
int del_word_buf(ChatContext *ctx);
|
int del_word_buf(ChatContext *ctx);
|
||||||
|
@ -40,13 +40,13 @@
|
|||||||
#define default_video_bit_rate 5000
|
#define default_video_bit_rate 5000
|
||||||
|
|
||||||
void receive_video_frame_cb( ToxAV *av, uint32_t friend_number,
|
void receive_video_frame_cb( ToxAV *av, uint32_t friend_number,
|
||||||
uint16_t width, uint16_t height,
|
uint16_t width, uint16_t height,
|
||||||
uint8_t const *y, uint8_t const *u, uint8_t const *v,
|
uint8_t const *y, uint8_t const *u, uint8_t const *v,
|
||||||
int32_t ystride, int32_t ustride, int32_t vstride,
|
int32_t ystride, int32_t ustride, int32_t vstride,
|
||||||
void *user_data );
|
void *user_data );
|
||||||
|
|
||||||
void video_bit_rate_status_cb( ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate,
|
void video_bit_rate_status_cb( ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate,
|
||||||
uint32_t video_bit_rate, void *user_data);
|
uint32_t video_bit_rate, void *user_data);
|
||||||
|
|
||||||
static void print_err (ToxWindow *self, const char *error_str)
|
static void print_err (ToxWindow *self, const char *error_str)
|
||||||
{
|
{
|
||||||
@ -82,22 +82,24 @@ ToxAV *init_video(ToxWindow *self, Tox *tox)
|
|||||||
void terminate_video()
|
void terminate_video()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_CALLS; ++i) {
|
for (i = 0; i < MAX_CALLS; ++i) {
|
||||||
Call* this_call = &CallControl.calls[i];
|
Call *this_call = &CallControl.calls[i];
|
||||||
|
|
||||||
stop_video_transmission(this_call, i);
|
stop_video_transmission(this_call, i);
|
||||||
|
|
||||||
if( this_call->vout_idx != -1 )
|
if ( this_call->vout_idx != -1 )
|
||||||
close_video_device(vdt_output, this_call->vout_idx);
|
close_video_device(vdt_output, this_call->vout_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
terminate_video_devices();
|
terminate_video_devices();
|
||||||
}
|
}
|
||||||
|
|
||||||
void read_video_device_callback(int16_t width, int16_t height, const uint8_t* y, const uint8_t* u, const uint8_t* v, void* data)
|
void read_video_device_callback(int16_t width, int16_t height, const uint8_t *y, const uint8_t *u, const uint8_t *v,
|
||||||
|
void *data)
|
||||||
{
|
{
|
||||||
uint32_t friend_number = *((uint32_t*)data); /* TODO: Or pass an array of call_idx's */
|
uint32_t friend_number = *((uint32_t *)data); /* TODO: Or pass an array of call_idx's */
|
||||||
Call* this_call = &CallControl.calls[friend_number];
|
Call *this_call = &CallControl.calls[friend_number];
|
||||||
TOXAV_ERR_SEND_FRAME error;
|
TOXAV_ERR_SEND_FRAME error;
|
||||||
|
|
||||||
/* Drop frame if video sending is disabled */
|
/* Drop frame if video sending is disabled */
|
||||||
@ -117,9 +119,9 @@ void read_video_device_callback(int16_t width, int16_t height, const uint8_t* y,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void write_video_device_callback(uint32_t friend_number, uint16_t width, uint16_t height,
|
void write_video_device_callback(uint32_t friend_number, uint16_t width, uint16_t height,
|
||||||
uint8_t const *y, uint8_t const *u, uint8_t const *v,
|
uint8_t const *y, uint8_t const *u, uint8_t const *v,
|
||||||
int32_t ystride, int32_t ustride, int32_t vstride,
|
int32_t ystride, int32_t ustride, int32_t vstride,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
write_video_out(width, height, y, u, v, ystride, ustride, vstride, user_data);
|
write_video_out(width, height, y, u, v, ystride, ustride, vstride, user_data);
|
||||||
}
|
}
|
||||||
@ -175,16 +177,16 @@ int stop_video_transmission(Call *call, int friend_number)
|
|||||||
* Callbacks
|
* Callbacks
|
||||||
*/
|
*/
|
||||||
void receive_video_frame_cb(ToxAV *av, uint32_t friend_number,
|
void receive_video_frame_cb(ToxAV *av, uint32_t friend_number,
|
||||||
uint16_t width, uint16_t height,
|
uint16_t width, uint16_t height,
|
||||||
uint8_t const *y, uint8_t const *u, uint8_t const *v,
|
uint8_t const *y, uint8_t const *u, uint8_t const *v,
|
||||||
int32_t ystride, int32_t ustride, int32_t vstride,
|
int32_t ystride, int32_t ustride, int32_t vstride,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
write_video_device_callback(friend_number, width, height, y, u, v, ystride, ustride, vstride, user_data);
|
write_video_device_callback(friend_number, width, height, y, u, v, ystride, ustride, vstride, user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void video_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate,
|
void video_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate,
|
||||||
uint32_t video_bit_rate, void *user_data)
|
uint32_t video_bit_rate, void *user_data)
|
||||||
{
|
{
|
||||||
CallControl.video_bit_rate = video_bit_rate;
|
CallControl.video_bit_rate = video_bit_rate;
|
||||||
toxav_bit_rate_set(CallControl.av, friend_number, -1, CallControl.video_bit_rate, NULL);
|
toxav_bit_rate_set(CallControl.av, friend_number, -1, CallControl.video_bit_rate, NULL);
|
||||||
@ -192,7 +194,7 @@ void video_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, uint32_t audio_
|
|||||||
|
|
||||||
void callback_recv_video_starting(uint32_t friend_number)
|
void callback_recv_video_starting(uint32_t friend_number)
|
||||||
{
|
{
|
||||||
Call* this_call = &CallControl.calls[friend_number];
|
Call *this_call = &CallControl.calls[friend_number];
|
||||||
|
|
||||||
if ( this_call->vout_idx != -1 )
|
if ( this_call->vout_idx != -1 )
|
||||||
return;
|
return;
|
||||||
@ -201,21 +203,22 @@ void callback_recv_video_starting(uint32_t friend_number)
|
|||||||
}
|
}
|
||||||
void callback_recv_video_end(uint32_t friend_number)
|
void callback_recv_video_end(uint32_t friend_number)
|
||||||
{
|
{
|
||||||
Call* this_call = &CallControl.calls[friend_number];
|
Call *this_call = &CallControl.calls[friend_number];
|
||||||
|
|
||||||
close_video_device(vdt_output, this_call->vout_idx);
|
close_video_device(vdt_output, this_call->vout_idx);
|
||||||
this_call->vout_idx = -1;
|
this_call->vout_idx = -1;
|
||||||
}
|
}
|
||||||
void callback_video_starting(uint32_t friend_number)
|
void callback_video_starting(uint32_t friend_number)
|
||||||
{
|
{
|
||||||
ToxWindow* windows = CallControl.prompt;
|
ToxWindow *windows = CallControl.prompt;
|
||||||
Call* this_call = &CallControl.calls[friend_number];
|
Call *this_call = &CallControl.calls[friend_number];
|
||||||
|
|
||||||
TOXAV_ERR_CALL_CONTROL error = TOXAV_ERR_CALL_CONTROL_OK;
|
TOXAV_ERR_CALL_CONTROL error = TOXAV_ERR_CALL_CONTROL_OK;
|
||||||
toxav_call_control(CallControl.av, friend_number, TOXAV_CALL_CONTROL_SHOW_VIDEO, &error);
|
toxav_call_control(CallControl.av, friend_number, TOXAV_CALL_CONTROL_SHOW_VIDEO, &error);
|
||||||
|
|
||||||
if (error == TOXAV_ERR_CALL_CONTROL_OK) {
|
if (error == TOXAV_ERR_CALL_CONTROL_OK) {
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if ( windows[i].is_call && windows[i].num == friend_number ) {
|
if ( windows[i].is_call && windows[i].num == friend_number ) {
|
||||||
if ( 0 != start_video_transmission(&windows[i], CallControl.av, this_call) ) {
|
if ( 0 != start_video_transmission(&windows[i], CallControl.av, this_call) ) {
|
||||||
@ -244,7 +247,7 @@ void callback_video_end(uint32_t friend_number)
|
|||||||
void cmd_video(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_video(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
const char *error_str;
|
const char *error_str;
|
||||||
Call* this_call = &CallControl.calls[self->num];
|
Call *this_call = &CallControl.calls[self->num];
|
||||||
|
|
||||||
if ( argc != 0 ) {
|
if ( argc != 0 ) {
|
||||||
error_str = "Unknown arguments.";
|
error_str = "Unknown arguments.";
|
||||||
@ -387,18 +390,18 @@ void cmd_ccur_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, ch
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( video_selection_valid(type, selection) == vde_InvalidSelection ) {
|
if ( video_selection_valid(type, selection) == vde_InvalidSelection ) {
|
||||||
error_str="Invalid selection!";
|
error_str = "Invalid selection!";
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If call is active, change device */
|
/* If call is active, change device */
|
||||||
if ( self->is_call ) {
|
if ( self->is_call ) {
|
||||||
Call* this_call = &CallControl.calls[self->num];
|
Call *this_call = &CallControl.calls[self->num];
|
||||||
|
|
||||||
if ( this_call->ttas ) {
|
if ( this_call->ttas ) {
|
||||||
|
|
||||||
if ( type == vdt_output ) {
|
if ( type == vdt_output ) {
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
/* TODO: check for failure */
|
/* TODO: check for failure */
|
||||||
close_video_device(vdt_input, this_call->vin_idx);
|
close_video_device(vdt_input, this_call->vin_idx);
|
||||||
open_video_device(vdt_input, selection, &this_call->vin_idx);
|
open_video_device(vdt_input, selection, &this_call->vin_idx);
|
||||||
@ -410,7 +413,7 @@ void cmd_ccur_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, ch
|
|||||||
self->video_device_selection[type] = selection;
|
self->video_device_selection[type] = selection;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
on_error:
|
on_error:
|
||||||
print_err (self, error_str);
|
print_err (self, error_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,14 +30,18 @@
|
|||||||
|
|
||||||
#include <vpx/vpx_image.h>
|
#include <vpx/vpx_image.h>
|
||||||
|
|
||||||
#if defined(__linux__) || defined(__FreeBSD__)
|
#if defined(__OSX__)
|
||||||
|
#import "osx_video.h"
|
||||||
|
#else
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#if defined(__linux__)
|
||||||
#include <linux/videodev2.h>
|
#include <linux/videodev2.h>
|
||||||
#else /* __OSX__ */
|
#else
|
||||||
#import "osx_video.h"
|
#include <sys/videoio.h>
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
@ -62,10 +66,10 @@ struct VideoBuffer {
|
|||||||
|
|
||||||
typedef struct VideoDevice {
|
typedef struct VideoDevice {
|
||||||
VideoDataHandleCallback cb; /* Use this to handle data from input device usually */
|
VideoDataHandleCallback cb; /* Use this to handle data from input device usually */
|
||||||
void* cb_data; /* Data to be passed to callback */
|
void *cb_data; /* Data to be passed to callback */
|
||||||
int32_t friend_number; /* ToxAV friend number */
|
int32_t friend_number; /* ToxAV friend number */
|
||||||
|
|
||||||
#if defined(__linux__) || defined(__FreeBSD__)
|
#if defined(__linux__) || SYSTEM == BSD
|
||||||
int fd; /* File descriptor of video device selected/opened */
|
int fd; /* File descriptor of video device selected/opened */
|
||||||
struct v4l2_format fmt;
|
struct v4l2_format fmt;
|
||||||
struct VideoBuffer *buffers;
|
struct VideoBuffer *buffers;
|
||||||
@ -93,7 +97,7 @@ VideoDevice *video_devices_running[2][MAX_DEVICES] = {{NULL}}; /* Running de
|
|||||||
uint32_t primary_video_device[2]; /* Primary device */
|
uint32_t primary_video_device[2]; /* Primary device */
|
||||||
|
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
static ToxAV* av = NULL;
|
static ToxAV *av = NULL;
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
|
|
||||||
/* q_mutex */
|
/* q_mutex */
|
||||||
@ -102,15 +106,16 @@ static ToxAV* av = NULL;
|
|||||||
pthread_mutex_t video_mutex;
|
pthread_mutex_t video_mutex;
|
||||||
|
|
||||||
bool video_thread_running = true,
|
bool video_thread_running = true,
|
||||||
video_thread_paused = true; /* Thread control */
|
video_thread_paused = true; /* Thread control */
|
||||||
|
|
||||||
void* video_thread_poll(void*);
|
void *video_thread_poll(void *);
|
||||||
|
|
||||||
static void yuv420tobgr(uint16_t width, uint16_t height, const uint8_t *y,
|
static void yuv420tobgr(uint16_t width, uint16_t height, const uint8_t *y,
|
||||||
const uint8_t *u, const uint8_t *v, unsigned int ystride,
|
const uint8_t *u, const uint8_t *v, unsigned int ystride,
|
||||||
unsigned int ustride, unsigned int vstride, uint8_t *out)
|
unsigned int ustride, unsigned int vstride, uint8_t *out)
|
||||||
{
|
{
|
||||||
unsigned long int i, j;
|
unsigned long int i, j;
|
||||||
|
|
||||||
for (i = 0; i < height; ++i) {
|
for (i = 0; i < height; ++i) {
|
||||||
for (j = 0; j < width; ++j) {
|
for (j = 0; j < width; ++j) {
|
||||||
uint8_t *point = out + 4 * ((i * width) + j);
|
uint8_t *point = out + 4 * ((i * width) + j);
|
||||||
@ -123,21 +128,23 @@ static void yuv420tobgr(uint16_t width, uint16_t height, const uint8_t *y,
|
|||||||
int g = (298 * (t_y - 16) - 100 * (t_u - 128) - 208 * (t_v - 128) + 128) >> 8;
|
int g = (298 * (t_y - 16) - 100 * (t_u - 128) - 208 * (t_v - 128) + 128) >> 8;
|
||||||
int b = (298 * (t_y - 16) + 516 * (t_u - 128) + 128) >> 8;
|
int b = (298 * (t_y - 16) + 516 * (t_u - 128) + 128) >> 8;
|
||||||
|
|
||||||
point[2] = r>255? 255 : r<0 ? 0 : r;
|
point[2] = r > 255 ? 255 : r < 0 ? 0 : r;
|
||||||
point[1] = g>255? 255 : g<0 ? 0 : g;
|
point[1] = g > 255 ? 255 : g < 0 ? 0 : g;
|
||||||
point[0] = b>255? 255 : b<0 ? 0 : b;
|
point[0] = b > 255 ? 255 : b < 0 ? 0 : b;
|
||||||
point[3] = ~0;
|
point[3] = ~0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__linux__) || defined(__FreeBSD__)
|
#if defined(__linux__) || SYSTEM == BSD
|
||||||
static void yuv422to420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v,
|
static void yuv422to420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v,
|
||||||
uint8_t *input, uint16_t width, uint16_t height)
|
uint8_t *input, uint16_t width, uint16_t height)
|
||||||
{
|
{
|
||||||
uint8_t *end = input + width * height * 2;
|
uint8_t *end = input + width * height * 2;
|
||||||
|
|
||||||
while (input != end) {
|
while (input != end) {
|
||||||
uint8_t *line_end = input + width * 2;
|
uint8_t *line_end = input + width * 2;
|
||||||
|
|
||||||
while (input != line_end) {
|
while (input != line_end) {
|
||||||
*plane_y++ = *input++;
|
*plane_y++ = *input++;
|
||||||
*plane_u++ = *input++;
|
*plane_u++ = *input++;
|
||||||
@ -146,6 +153,7 @@ static void yuv422to420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v,
|
|||||||
}
|
}
|
||||||
|
|
||||||
line_end = input + width * 2;
|
line_end = input + width * 2;
|
||||||
|
|
||||||
while (input != line_end) {
|
while (input != line_end) {
|
||||||
*plane_y++ = *input++;
|
*plane_y++ = *input++;
|
||||||
input++;//u
|
input++;//u
|
||||||
@ -166,56 +174,59 @@ static int xioctl(int fh, unsigned long request, void *arg)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* __linux__ */
|
#endif
|
||||||
|
|
||||||
/* Meet devices */
|
/* Meet devices */
|
||||||
#ifdef VIDEO
|
#ifdef VIDEO
|
||||||
VideoDeviceError init_video_devices(ToxAV* av_)
|
VideoDeviceError init_video_devices(ToxAV *av_)
|
||||||
#else
|
#else
|
||||||
VideoDeviceError init_video_devices()
|
VideoDeviceError init_video_devices()
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
{
|
{
|
||||||
size[vdt_input] = 0;
|
size[vdt_input] = 0;
|
||||||
|
|
||||||
#if defined(__linux__) || defined(__FreeBSD__)
|
#if defined(__OSX__)
|
||||||
|
if( osx_video_init((char**)video_devices_names[vdt_input], &size[vdt_input]) != 0 )
|
||||||
|
return vde_InternalError;
|
||||||
|
#else /* not __OSX__*/
|
||||||
|
|
||||||
for (; size[vdt_input] <= MAX_DEVICES; ++size[vdt_input]) {
|
for (; size[vdt_input] <= MAX_DEVICES; ++size[vdt_input]) {
|
||||||
int fd;
|
int fd;
|
||||||
char device_address[] = "/dev/videoXX";
|
char device_address[] = "/dev/videoXX";
|
||||||
snprintf(device_address + 10, sizeof(char) * strlen(device_address) - 10, "%i", size[vdt_input]);
|
snprintf(device_address + 10, sizeof(char) * strlen(device_address) - 10, "%i", size[vdt_input]);
|
||||||
|
|
||||||
fd = open(device_address, O_RDWR | O_NONBLOCK, 0);
|
fd = open(device_address, O_RDWR | O_NONBLOCK, 0);
|
||||||
|
|
||||||
if ( fd == -1 ) {
|
if ( fd == -1 ) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
struct v4l2_capability cap;
|
struct v4l2_capability cap;
|
||||||
char* video_input_name;
|
char *video_input_name;
|
||||||
|
|
||||||
/* Query V4L for capture capabilities */
|
/* 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);
|
video_input_name = (char *)malloc(strlen((const char *)cap.card) + strlen(device_address) + 4);
|
||||||
strcpy(video_input_name, (char*)cap.card);
|
strcpy(video_input_name, (char *)cap.card);
|
||||||
strcat(video_input_name, " (");
|
strcat(video_input_name, " (");
|
||||||
strcat(video_input_name, (char*)device_address);
|
strcat(video_input_name, (char *)device_address);
|
||||||
strcat(video_input_name, ")");
|
strcat(video_input_name, ")");
|
||||||
} else {
|
} else {
|
||||||
video_input_name = (char*)malloc(strlen(device_address) + 3);
|
video_input_name = (char *)malloc(strlen(device_address) + 3);
|
||||||
strcpy(video_input_name, "(");
|
strcpy(video_input_name, "(");
|
||||||
strcat(video_input_name, device_address);
|
strcat(video_input_name, device_address);
|
||||||
strcat(video_input_name, ")");
|
strcat(video_input_name, ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
video_devices_names[vdt_input][size[vdt_input]] = video_input_name;
|
video_devices_names[vdt_input][size[vdt_input]] = video_input_name;
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* __OSX__ */
|
|
||||||
if( osx_video_init((char**)video_devices_names[vdt_input], &size[vdt_input]) != 0 )
|
|
||||||
return vde_InternalError;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
size[vdt_output] = 1;
|
size[vdt_output] = 1;
|
||||||
char* video_output_name = "Toxic Video Receiver";
|
char *video_output_name = "Toxic Video Receiver";
|
||||||
video_devices_names[vdt_output][0] = video_output_name;
|
video_devices_names[vdt_output][0] = video_output_name;
|
||||||
|
|
||||||
// Start poll thread
|
// Start poll thread
|
||||||
@ -223,6 +234,7 @@ VideoDeviceError init_video_devices()
|
|||||||
return vde_InternalError;
|
return vde_InternalError;
|
||||||
|
|
||||||
pthread_t thread_id;
|
pthread_t thread_id;
|
||||||
|
|
||||||
if ( pthread_create(&thread_id, NULL, video_thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0 )
|
if ( pthread_create(&thread_id, NULL, video_thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0 )
|
||||||
return vde_InternalError;
|
return vde_InternalError;
|
||||||
|
|
||||||
@ -243,8 +255,9 @@ VideoDeviceError terminate_video_devices()
|
|||||||
usleep(20000);
|
usleep(20000);
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < size[vdt_input]; ++i) {
|
for (i = 0; i < size[vdt_input]; ++i) {
|
||||||
free((void*)video_devices_names[vdt_input][i]);
|
free((void *)video_devices_names[vdt_input][i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( pthread_mutex_destroy(&video_mutex) != 0 )
|
if ( pthread_mutex_destroy(&video_mutex) != 0 )
|
||||||
@ -258,14 +271,19 @@ VideoDeviceError terminate_video_devices()
|
|||||||
}
|
}
|
||||||
|
|
||||||
VideoDeviceError register_video_device_callback(int32_t friend_number, uint32_t device_idx,
|
VideoDeviceError register_video_device_callback(int32_t friend_number, uint32_t device_idx,
|
||||||
VideoDataHandleCallback callback, void* data)
|
VideoDataHandleCallback callback, void *data)
|
||||||
{
|
{
|
||||||
#if defined(__linux__) || defined(__FreeBSD__)
|
#if defined(__OSX__)
|
||||||
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 /* __OSX__ */
|
|
||||||
if ( size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx] )
|
if ( size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx] )
|
||||||
return vde_InvalidSelection;
|
return vde_InvalidSelection;
|
||||||
|
|
||||||
|
#else /* not __OSX__ */
|
||||||
|
|
||||||
|
if ( size[vdt_input] <= device_idx || !video_devices_running[vdt_input][device_idx]
|
||||||
|
|| !video_devices_running[vdt_input][device_idx]->fd )
|
||||||
|
return vde_InvalidSelection;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
lock;
|
lock;
|
||||||
@ -286,7 +304,7 @@ VideoDeviceError set_primary_video_device(VideoDeviceType type, int32_t selectio
|
|||||||
return vde_None;
|
return vde_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoDeviceError open_primary_video_device(VideoDeviceType type, uint32_t* device_idx)
|
VideoDeviceError open_primary_video_device(VideoDeviceType type, uint32_t *device_idx)
|
||||||
{
|
{
|
||||||
return open_video_device(type, primary_video_device[type], device_idx);
|
return open_video_device(type, primary_video_device[type], device_idx);
|
||||||
}
|
}
|
||||||
@ -296,7 +314,7 @@ void get_primary_video_device_name(VideoDeviceType type, char *buf, int size)
|
|||||||
memcpy(buf, dvideo_device_names[type], size);
|
memcpy(buf, dvideo_device_names[type], size);
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint32_t* device_idx)
|
VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint32_t *device_idx)
|
||||||
{
|
{
|
||||||
if ( size[type] <= selection || selection < 0 ) return vde_InvalidSelection;
|
if ( size[type] <= selection || selection < 0 ) return vde_InvalidSelection;
|
||||||
|
|
||||||
@ -327,7 +345,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoDevice* device = video_devices_running[type][temp_idx] = calloc(1, sizeof(VideoDevice));
|
VideoDevice *device = video_devices_running[type][temp_idx] = calloc(1, sizeof(VideoDevice));
|
||||||
device->selection = selection;
|
device->selection = selection;
|
||||||
|
|
||||||
if ( pthread_mutex_init(device->mutex, NULL) != 0 ) {
|
if ( pthread_mutex_init(device->mutex, NULL) != 0 ) {
|
||||||
@ -339,12 +357,19 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
|||||||
if ( type == vdt_input ) {
|
if ( type == vdt_input ) {
|
||||||
video_thread_paused = true;
|
video_thread_paused = true;
|
||||||
|
|
||||||
#if defined(__linux__) || defined(__FreeBSD__)
|
#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__*/
|
||||||
/* Open selected device */
|
/* Open selected device */
|
||||||
char device_address[] = "/dev/videoXX";
|
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);
|
device->fd = open(device_address, O_RDWR);
|
||||||
|
|
||||||
if ( device->fd == -1 ) {
|
if ( device->fd == -1 ) {
|
||||||
unlock;
|
unlock;
|
||||||
return vde_FailedStart;
|
return vde_FailedStart;
|
||||||
@ -352,6 +377,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
|||||||
|
|
||||||
/* Obtain video device capabilities */
|
/* Obtain video device capabilities */
|
||||||
struct v4l2_capability cap;
|
struct v4l2_capability cap;
|
||||||
|
|
||||||
if ( -1 == xioctl(device->fd, VIDIOC_QUERYCAP, &cap) ) {
|
if ( -1 == xioctl(device->fd, VIDIOC_QUERYCAP, &cap) ) {
|
||||||
close(device->fd);
|
close(device->fd);
|
||||||
free(device);
|
free(device);
|
||||||
@ -365,7 +391,8 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
|||||||
|
|
||||||
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
|
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);
|
close(device->fd);
|
||||||
free(device);
|
free(device);
|
||||||
unlock;
|
unlock;
|
||||||
@ -381,6 +408,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
|||||||
req.count = 4;
|
req.count = 4;
|
||||||
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
req.memory = V4L2_MEMORY_MMAP;
|
req.memory = V4L2_MEMORY_MMAP;
|
||||||
|
|
||||||
if ( -1 == xioctl(device->fd, VIDIOC_REQBUFS, &req) ) {
|
if ( -1 == xioctl(device->fd, VIDIOC_REQBUFS, &req) ) {
|
||||||
close(device->fd);
|
close(device->fd);
|
||||||
free(device);
|
free(device);
|
||||||
@ -414,20 +442,22 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
|||||||
|
|
||||||
device->buffers[i].length = buf.length;
|
device->buffers[i].length = buf.length;
|
||||||
device->buffers[i].start = mmap(NULL /* start anywhere */,
|
device->buffers[i].start = mmap(NULL /* start anywhere */,
|
||||||
buf.length,
|
buf.length,
|
||||||
PROT_READ | PROT_WRITE /* required */,
|
PROT_READ | PROT_WRITE /* required */,
|
||||||
MAP_SHARED /* recommended */,
|
MAP_SHARED /* recommended */,
|
||||||
device->fd, buf.m.offset);
|
device->fd, buf.m.offset);
|
||||||
|
|
||||||
if ( MAP_FAILED == device->buffers[i].start ) {
|
if ( MAP_FAILED == device->buffers[i].start ) {
|
||||||
for (i = 0; i < buf.index; ++i)
|
for (i = 0; i < buf.index; ++i)
|
||||||
munmap(device->buffers[i].start, device->buffers[i].length);
|
munmap(device->buffers[i].start, device->buffers[i].length);
|
||||||
|
|
||||||
close(device->fd);
|
close(device->fd);
|
||||||
free(device);
|
free(device);
|
||||||
unlock;
|
unlock;
|
||||||
return vde_FailedStart;
|
return vde_FailedStart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
device->n_buffers = i;
|
device->n_buffers = i;
|
||||||
|
|
||||||
enum v4l2_buf_type type;
|
enum v4l2_buf_type type;
|
||||||
@ -443,6 +473,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
|||||||
if ( -1 == xioctl(device->fd, VIDIOC_QBUF, &buf) ) {
|
if ( -1 == xioctl(device->fd, VIDIOC_QBUF, &buf) ) {
|
||||||
for (i = 0; i < device->n_buffers; ++i)
|
for (i = 0; i < device->n_buffers; ++i)
|
||||||
munmap(device->buffers[i].start, device->buffers[i].length);
|
munmap(device->buffers[i].start, device->buffers[i].length);
|
||||||
|
|
||||||
close(device->fd);
|
close(device->fd);
|
||||||
free(device);
|
free(device);
|
||||||
unlock;
|
unlock;
|
||||||
@ -459,12 +490,6 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
|||||||
return vde_FailedStart;
|
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
|
#endif
|
||||||
|
|
||||||
/* Create X11 window associated to device */
|
/* Create X11 window associated to device */
|
||||||
@ -477,15 +502,15 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
|||||||
int screen = DefaultScreen(device->x_display);
|
int screen = DefaultScreen(device->x_display);
|
||||||
|
|
||||||
if ( !(device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen), 0, 0,
|
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),
|
device->video_width, device->video_height, 0, BlackPixel(device->x_display, screen),
|
||||||
BlackPixel(device->x_display, screen))) ) {
|
BlackPixel(device->x_display, screen))) ) {
|
||||||
close_video_device(vdt_input, temp_idx);
|
close_video_device(vdt_input, temp_idx);
|
||||||
unlock;
|
unlock;
|
||||||
return vde_FailedStart;
|
return vde_FailedStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
XStoreName(device->x_display, device->x_window, "Video Preview");
|
XStoreName(device->x_display, device->x_window, "Video Preview");
|
||||||
XSelectInput(device->x_display, device->x_window, ExposureMask|ButtonPressMask|KeyPressMask);
|
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);
|
close_video_device(vdt_input, temp_idx);
|
||||||
@ -517,14 +542,14 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
|||||||
int screen = DefaultScreen(device->x_display);
|
int screen = DefaultScreen(device->x_display);
|
||||||
|
|
||||||
if ( !(device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen), 0, 0,
|
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))) ) {
|
100, 100, 0, BlackPixel(device->x_display, screen), BlackPixel(device->x_display, screen))) ) {
|
||||||
close_video_device(vdt_output, temp_idx);
|
close_video_device(vdt_output, temp_idx);
|
||||||
unlock;
|
unlock;
|
||||||
return vde_FailedStart;
|
return vde_FailedStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
XStoreName(device->x_display, device->x_window, "Video Receive");
|
XStoreName(device->x_display, device->x_window, "Video Receive");
|
||||||
XSelectInput(device->x_display, device->x_window, ExposureMask|ButtonPressMask|KeyPressMask);
|
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);
|
close_video_device(vdt_output, temp_idx);
|
||||||
@ -551,15 +576,15 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
|
|||||||
}
|
}
|
||||||
|
|
||||||
__inline VideoDeviceError write_video_out(uint16_t width, uint16_t height,
|
__inline VideoDeviceError write_video_out(uint16_t width, uint16_t height,
|
||||||
uint8_t const *y, uint8_t const *u, uint8_t const *v,
|
uint8_t const *y, uint8_t const *u, uint8_t const *v,
|
||||||
int32_t ystride, int32_t ustride, int32_t vstride,
|
int32_t ystride, int32_t ustride, int32_t vstride,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
VideoDevice* device = video_devices_running[vdt_output][0];
|
VideoDevice *device = video_devices_running[vdt_output][0];
|
||||||
|
|
||||||
if ( !device ) return vde_DeviceNotActive;
|
if ( !device ) return vde_DeviceNotActive;
|
||||||
|
|
||||||
if( !device->x_window ) return vde_DeviceNotActive;
|
if ( !device->x_window ) return vde_DeviceNotActive;
|
||||||
|
|
||||||
pthread_mutex_lock(device->mutex);
|
pthread_mutex_lock(device->mutex);
|
||||||
|
|
||||||
@ -594,7 +619,7 @@ __inline VideoDeviceError write_video_out(uint16_t width, uint16_t height,
|
|||||||
.red_mask = 0xFF0000,
|
.red_mask = 0xFF0000,
|
||||||
.green_mask = 0xFF00,
|
.green_mask = 0xFF00,
|
||||||
.blue_mask = 0xFF,
|
.blue_mask = 0xFF,
|
||||||
.data = (char*)img_data
|
.data = (char *)img_data
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Render image data */
|
/* Render image data */
|
||||||
@ -609,7 +634,7 @@ __inline VideoDeviceError write_video_out(uint16_t width, uint16_t height,
|
|||||||
return vde_None;
|
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.
|
* NOTE: We only need to poll input devices for data.
|
||||||
@ -619,26 +644,34 @@ void* video_thread_poll (void* arg) // TODO: maybe use thread for every input so
|
|||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
lock;
|
lock;
|
||||||
|
|
||||||
if (!video_thread_running) {
|
if (!video_thread_running) {
|
||||||
unlock;
|
unlock;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock;
|
unlock;
|
||||||
|
|
||||||
if ( video_thread_paused ) usleep(10000); /* Wait for unpause. */
|
if ( video_thread_paused ) usleep(10000); /* Wait for unpause. */
|
||||||
else {
|
else {
|
||||||
for (i = 0; i < size[vdt_input]; ++i) {
|
for (i = 0; i < size[vdt_input]; ++i) {
|
||||||
lock;
|
lock;
|
||||||
|
|
||||||
if ( video_devices_running[vdt_input][i] != NULL ) {
|
if ( video_devices_running[vdt_input][i] != NULL ) {
|
||||||
/* Obtain frame image data from device buffers */
|
/* Obtain frame image data from device buffers */
|
||||||
VideoDevice* device = video_devices_running[vdt_input][i];
|
VideoDevice *device = video_devices_running[vdt_input][i];
|
||||||
uint16_t video_width = device->video_width;
|
uint16_t video_width = device->video_width;
|
||||||
uint16_t video_height = device->video_height;
|
uint16_t video_height = device->video_height;
|
||||||
uint8_t *y = device->input.planes[0];
|
uint8_t *y = device->input.planes[0];
|
||||||
uint8_t *u = device->input.planes[1];
|
uint8_t *u = device->input.planes[1];
|
||||||
uint8_t *v = device->input.planes[2];
|
uint8_t *v = device->input.planes[2];
|
||||||
|
|
||||||
#if defined(__linux__) || defined(__FreeBSD__)
|
#if defined(__OSX__)
|
||||||
|
if ( osx_video_read_device(y, u, v, &video_width, &video_height) != 0 ) {
|
||||||
|
unlock;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#else /* not __OSX__*/
|
||||||
struct v4l2_buffer buf;
|
struct v4l2_buffer buf;
|
||||||
memset(&(buf), 0, sizeof(buf));
|
memset(&(buf), 0, sizeof(buf));
|
||||||
|
|
||||||
@ -650,16 +683,11 @@ void* video_thread_poll (void* arg) // TODO: maybe use thread for every input so
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *data = (void*)device->buffers[buf.index].start;
|
void *data = (void *)device->buffers[buf.index].start;
|
||||||
|
|
||||||
/* Convert frame image data to YUV420 for ToxAV */
|
/* Convert frame image data to YUV420 for ToxAV */
|
||||||
yuv422to420(y, u, v, data, video_width, video_height);
|
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
|
#endif
|
||||||
|
|
||||||
/* Send frame data to friend through ToxAV */
|
/* Send frame data to friend through ToxAV */
|
||||||
@ -669,7 +697,7 @@ void* video_thread_poll (void* arg) // TODO: maybe use thread for every input so
|
|||||||
/* Convert YUV420 data to BGR */
|
/* Convert YUV420 data to BGR */
|
||||||
uint8_t *img_data = malloc(video_width * video_height * 4);
|
uint8_t *img_data = malloc(video_width * video_height * 4);
|
||||||
yuv420tobgr(video_width, video_height, y, u, v,
|
yuv420tobgr(video_width, video_height, y, u, v,
|
||||||
video_width, video_width/2, video_width/2, img_data);
|
video_width, video_width / 2, video_width / 2, img_data);
|
||||||
|
|
||||||
/* Allocate image data in X11 */
|
/* Allocate image data in X11 */
|
||||||
XImage image = {
|
XImage image = {
|
||||||
@ -685,7 +713,7 @@ void* video_thread_poll (void* arg) // TODO: maybe use thread for every input so
|
|||||||
.red_mask = 0xFF0000,
|
.red_mask = 0xFF0000,
|
||||||
.green_mask = 0xFF00,
|
.green_mask = 0xFF00,
|
||||||
.blue_mask = 0xFF,
|
.blue_mask = 0xFF,
|
||||||
.data = (char*)img_data
|
.data = (char *)img_data
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Render image data */
|
/* Render image data */
|
||||||
@ -696,16 +724,20 @@ void* video_thread_poll (void* arg) // TODO: maybe use thread for every input so
|
|||||||
XFlush(device->x_display);
|
XFlush(device->x_display);
|
||||||
free(img_data);
|
free(img_data);
|
||||||
|
|
||||||
#if defined(__linux__) || defined(__FreeBSD__)
|
#if defined(__linux__) || SYSTEM == BSD
|
||||||
|
|
||||||
if ( -1 == xioctl(device->fd, VIDIOC_QBUF, &buf) ) {
|
if ( -1 == xioctl(device->fd, VIDIOC_QBUF, &buf) ) {
|
||||||
unlock;
|
unlock;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif /* __linux__ */
|
|
||||||
|
#endif /* __linux__ / BSD */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock;
|
unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
usleep(1000 * 1000 / 24);
|
usleep(1000 * 1000 / 24);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -731,19 +763,23 @@ VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
|
|||||||
if ( !device->ref_count ) {
|
if ( !device->ref_count ) {
|
||||||
|
|
||||||
if ( type == vdt_input ) {
|
if ( type == vdt_input ) {
|
||||||
#if defined(__linux__) || defined(__FreeBSD__)
|
#if defined(__OSX__)
|
||||||
|
|
||||||
|
osx_video_close_device(device_idx);
|
||||||
|
#else /* not __OSX__ */
|
||||||
enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
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;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < device->n_buffers; ++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);
|
close(device->fd);
|
||||||
|
|
||||||
#else /* __OSX__ */
|
|
||||||
osx_video_close_device(device_idx);
|
|
||||||
#endif
|
#endif
|
||||||
vpx_img_free(&device->input);
|
vpx_img_free(&device->input);
|
||||||
XDestroyWindow(device->x_display, device->x_window);
|
XDestroyWindow(device->x_display, device->x_window);
|
||||||
@ -751,9 +787,9 @@ VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
|
|||||||
XCloseDisplay(device->x_display);
|
XCloseDisplay(device->x_display);
|
||||||
pthread_mutex_destroy(device->mutex);
|
pthread_mutex_destroy(device->mutex);
|
||||||
|
|
||||||
#if defined(__linux__) || defined(__FreeBSD__)
|
#if defined(__linux__) || SYSTEM == BSD
|
||||||
free(device->buffers);
|
free(device->buffers);
|
||||||
#endif /* __linux__ */
|
#endif /* __linux__ / BSD */
|
||||||
|
|
||||||
free(device);
|
free(device);
|
||||||
} else {
|
} else {
|
||||||
@ -765,14 +801,13 @@ VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
|
|||||||
free(device);
|
free(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} else device->ref_count--;
|
||||||
else device->ref_count--;
|
|
||||||
|
|
||||||
unlock;
|
unlock;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_video_devices(ToxWindow* self, VideoDeviceType type)
|
void print_video_devices(ToxWindow *self, VideoDeviceType type)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -45,10 +45,11 @@ typedef enum VideoDeviceError {
|
|||||||
vde_CaptureError = -9,
|
vde_CaptureError = -9,
|
||||||
} VideoDeviceError;
|
} 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
|
#ifdef VIDEO
|
||||||
VideoDeviceError init_video_devices(ToxAV* av);
|
VideoDeviceError init_video_devices(ToxAV *av);
|
||||||
#else
|
#else
|
||||||
VideoDeviceError init_video_devices();
|
VideoDeviceError init_video_devices();
|
||||||
#endif /* VIDEO */
|
#endif /* VIDEO */
|
||||||
@ -56,20 +57,22 @@ VideoDeviceError init_video_devices();
|
|||||||
VideoDeviceError terminate_video_devices();
|
VideoDeviceError terminate_video_devices();
|
||||||
|
|
||||||
/* Callback handles ready data from INPUT device */
|
/* Callback handles ready data from INPUT device */
|
||||||
VideoDeviceError register_video_device_callback(int32_t call_idx, uint32_t device_idx, VideoDataHandleCallback callback, void* data);
|
VideoDeviceError register_video_device_callback(int32_t call_idx, uint32_t device_idx, VideoDataHandleCallback callback,
|
||||||
void* get_video_device_callback_data(uint32_t device_idx);
|
void *data);
|
||||||
|
void *get_video_device_callback_data(uint32_t device_idx);
|
||||||
|
|
||||||
VideoDeviceError set_primary_video_device(VideoDeviceType type, int32_t selection);
|
VideoDeviceError set_primary_video_device(VideoDeviceType type, int32_t selection);
|
||||||
VideoDeviceError open_primary_video_device(VideoDeviceType type, uint32_t* device_idx);
|
VideoDeviceError open_primary_video_device(VideoDeviceType type, uint32_t *device_idx);
|
||||||
/* Start device */
|
/* Start device */
|
||||||
VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint32_t* device_idx);
|
VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint32_t *device_idx);
|
||||||
/* Stop device */
|
/* Stop device */
|
||||||
VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx);
|
VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx);
|
||||||
|
|
||||||
/* Write data to device */
|
/* Write data to device */
|
||||||
VideoDeviceError write_video_out(uint16_t width, uint16_t height, uint8_t const *y, uint8_t const *u, uint8_t const *v, int32_t ystride, int32_t ustride, int32_t vstride, void *user_data);
|
VideoDeviceError write_video_out(uint16_t width, uint16_t height, uint8_t const *y, uint8_t const *u, uint8_t const *v,
|
||||||
|
int32_t ystride, int32_t ustride, int32_t vstride, void *user_data);
|
||||||
|
|
||||||
void print_video_devices(ToxWindow* self, VideoDeviceType type);
|
void print_video_devices(ToxWindow *self, VideoDeviceType type);
|
||||||
void get_primary_video_device_name(VideoDeviceType type, char *buf, int size);
|
void get_primary_video_device_name(VideoDeviceType type, char *buf, int size);
|
||||||
|
|
||||||
VideoDeviceError video_selection_valid(VideoDeviceType type, int32_t selection);
|
VideoDeviceError video_selection_valid(VideoDeviceType type, int32_t selection);
|
||||||
|
@ -151,8 +151,8 @@ void on_friendadded(Tox *m, uint32_t friendnumber, bool sort)
|
|||||||
store_data(m, DATA_FILE);
|
store_data(m, DATA_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *message, uint16_t length,
|
void on_groupmessage(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_MESSAGE_TYPE type,
|
||||||
void *userdata)
|
const uint8_t *message, size_t length, void *userdata)
|
||||||
{
|
{
|
||||||
char msg[MAX_STR_SIZE + 1];
|
char msg[MAX_STR_SIZE + 1];
|
||||||
length = copy_tox_str(msg, sizeof(msg), (const char *) message, length);
|
length = copy_tox_str(msg, sizeof(msg), (const char *) message, length);
|
||||||
@ -161,26 +161,12 @@ void on_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *mes
|
|||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onGroupMessage != NULL)
|
if (windows[i].onGroupMessage != NULL)
|
||||||
windows[i].onGroupMessage(&windows[i], m, groupnumber, peernumber, msg, length);
|
windows[i].onGroupMessage(&windows[i], m, groupnumber, peernumber, type, msg, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_groupaction(Tox *m, int groupnumber, int peernumber, const uint8_t *action, uint16_t length,
|
void on_groupinvite(Tox *m, uint32_t friendnumber, TOX_CONFERENCE_TYPE type, const uint8_t *group_pub_key,
|
||||||
void *userdata)
|
size_t length, void *userdata)
|
||||||
{
|
|
||||||
char msg[MAX_STR_SIZE + 1];
|
|
||||||
length = copy_tox_str(msg, sizeof(msg), (const char *) action, length);
|
|
||||||
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
|
||||||
if (windows[i].onGroupAction != NULL)
|
|
||||||
windows[i].onGroupAction(&windows[i], m, groupnumber, peernumber, msg, length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_groupinvite(Tox *m, int32_t friendnumber, uint8_t type, const uint8_t *group_pub_key, uint16_t length,
|
|
||||||
void *userdata)
|
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
@ -190,7 +176,8 @@ void on_groupinvite(Tox *m, int32_t friendnumber, uint8_t type, const uint8_t *g
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_group_namelistchange(Tox *m, int groupnumber, int peernumber, uint8_t change, void *userdata)
|
void on_group_namelistchange(Tox *m, uint32_t groupnumber, uint32_t peernumber, TOX_CONFERENCE_STATE_CHANGE change,
|
||||||
|
void *userdata)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
@ -200,7 +187,7 @@ void on_group_namelistchange(Tox *m, int groupnumber, int peernumber, uint8_t ch
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_group_titlechange(Tox *m, int groupnumber, int peernumber, const uint8_t *title, uint8_t length,
|
void on_group_titlechange(Tox *m, uint32_t groupnumber, uint32_t peernumber, const uint8_t *title, size_t length,
|
||||||
void *userdata)
|
void *userdata)
|
||||||
{
|
{
|
||||||
char data[MAX_STR_SIZE + 1];
|
char data[MAX_STR_SIZE + 1];
|
||||||
@ -445,10 +432,12 @@ void on_window_resize(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
|
|
||||||
if (w->chatwin->infobox.active) {
|
if (w->chatwin->infobox.active) {
|
||||||
delwin(w->chatwin->infobox.win);
|
delwin(w->chatwin->infobox.win);
|
||||||
w->chatwin->infobox.win = newwin(INFOBOX_HEIGHT, INFOBOX_WIDTH + 1, 1, x2 - INFOBOX_WIDTH);
|
w->chatwin->infobox.win = newwin(INFOBOX_HEIGHT, INFOBOX_WIDTH + 1, 1, x2 - INFOBOX_WIDTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
scrollok(w->chatwin->history, 0);
|
scrollok(w->chatwin->history, 0);
|
||||||
@ -458,20 +447,24 @@ void on_window_resize(void)
|
|||||||
static void draw_window_tab(ToxWindow *toxwin)
|
static void draw_window_tab(ToxWindow *toxwin)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
|
|
||||||
if (toxwin->alert != WINDOW_ALERT_NONE) attron(COLOR_PAIR(toxwin->alert));
|
if (toxwin->alert != WINDOW_ALERT_NONE) attron(COLOR_PAIR(toxwin->alert));
|
||||||
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
clrtoeol();
|
clrtoeol();
|
||||||
printw(" [%s]", toxwin->name);
|
printw(" [%s]", toxwin->name);
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
|
|
||||||
if (toxwin->alert != WINDOW_ALERT_NONE) attroff(COLOR_PAIR(toxwin->alert));
|
if (toxwin->alert != WINDOW_ALERT_NONE) attroff(COLOR_PAIR(toxwin->alert));
|
||||||
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_bar(void)
|
static void draw_bar(void)
|
||||||
{
|
{
|
||||||
int y,x;
|
int y, x;
|
||||||
|
|
||||||
// save current cursor position
|
// save current cursor position
|
||||||
getyx(active_window->window, y, x);
|
getyx(active_window->window, y, x);
|
||||||
@ -482,10 +475,6 @@ static void draw_bar(void)
|
|||||||
|
|
||||||
move(LINES - 1, 0);
|
move(LINES - 1, 0);
|
||||||
|
|
||||||
attron(COLOR_PAIR(BLUE) | A_BOLD);
|
|
||||||
printw(" TOXIC " TOXICVER " |");
|
|
||||||
attroff(COLOR_PAIR(BLUE) | A_BOLD);
|
|
||||||
|
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
@ -595,6 +584,12 @@ ToxWindow *get_window_ptr(int i)
|
|||||||
return toxwin;
|
return toxwin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* returns a pointer to the currently open ToxWindow. */
|
||||||
|
ToxWindow *get_active_window(void)
|
||||||
|
{
|
||||||
|
return active_window;
|
||||||
|
}
|
||||||
|
|
||||||
void force_refresh(WINDOW *w)
|
void force_refresh(WINDOW *w)
|
||||||
{
|
{
|
||||||
wclear(w);
|
wclear(w);
|
||||||
|
@ -121,11 +121,10 @@ struct ToxWindow {
|
|||||||
void(*onNickChange)(ToxWindow *, Tox *, uint32_t, const char *, size_t);
|
void(*onNickChange)(ToxWindow *, Tox *, uint32_t, const char *, size_t);
|
||||||
void(*onStatusChange)(ToxWindow *, Tox *, uint32_t, TOX_USER_STATUS);
|
void(*onStatusChange)(ToxWindow *, Tox *, uint32_t, TOX_USER_STATUS);
|
||||||
void(*onStatusMessageChange)(ToxWindow *, uint32_t, const char *, size_t);
|
void(*onStatusMessageChange)(ToxWindow *, uint32_t, const char *, size_t);
|
||||||
void(*onGroupMessage)(ToxWindow *, Tox *, int, int, const char *, uint16_t);
|
void(*onGroupMessage)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_MESSAGE_TYPE, const char *, size_t);
|
||||||
void(*onGroupAction)(ToxWindow *, Tox *, int, int, const char *, uint16_t);
|
|
||||||
void(*onGroupInvite)(ToxWindow *, Tox *, int32_t, uint8_t, const char *, uint16_t);
|
void(*onGroupInvite)(ToxWindow *, Tox *, int32_t, uint8_t, const char *, uint16_t);
|
||||||
void(*onGroupNamelistChange)(ToxWindow *, Tox *, int, int, uint8_t);
|
void(*onGroupNamelistChange)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_CONFERENCE_STATE_CHANGE);
|
||||||
void(*onGroupTitleChange)(ToxWindow *, Tox *, int, int, const char *, uint8_t);
|
void(*onGroupTitleChange)(ToxWindow *, Tox *, uint32_t, uint32_t, const char *, size_t);
|
||||||
void(*onFileChunkRequest)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, size_t);
|
void(*onFileChunkRequest)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, size_t);
|
||||||
void(*onFileRecvChunk)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, const char *, size_t);
|
void(*onFileRecvChunk)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, const char *, size_t);
|
||||||
void(*onFileControl)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_FILE_CONTROL);
|
void(*onFileControl)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_FILE_CONTROL);
|
||||||
@ -260,6 +259,7 @@ void kill_all_windows(Tox *m); /* should only be called on shutdown */
|
|||||||
void on_window_resize(void);
|
void on_window_resize(void);
|
||||||
void force_refresh(WINDOW *w);
|
void force_refresh(WINDOW *w);
|
||||||
ToxWindow *get_window_ptr(int i);
|
ToxWindow *get_window_ptr(int i);
|
||||||
|
ToxWindow *get_active_window(void);
|
||||||
|
|
||||||
/* refresh inactive windows to prevent scrolling bugs.
|
/* refresh inactive windows to prevent scrolling bugs.
|
||||||
call at least once per second */
|
call at least once per second */
|
||||||
|
61
src/xtra.c
61
src/xtra.c
@ -57,8 +57,7 @@ struct _Xtra {
|
|||||||
Atom expecting_type;
|
Atom expecting_type;
|
||||||
} Xtra;
|
} Xtra;
|
||||||
|
|
||||||
typedef struct _Property
|
typedef struct _Property {
|
||||||
{
|
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
int read_format;
|
int read_format;
|
||||||
unsigned long read_num;
|
unsigned long read_num;
|
||||||
@ -97,21 +96,23 @@ Property read_property(Window s, Atom p)
|
|||||||
Atom get_dnd_type(long *a, int l)
|
Atom get_dnd_type(long *a, int l)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
for (; i < l; i ++) {
|
for (; i < l; i ++) {
|
||||||
if (a[i] != XtraNil) return a[i]; /* Get first valid */
|
if (a[i] != XtraNil) return a[i]; /* Get first valid */
|
||||||
}
|
}
|
||||||
|
|
||||||
return XtraNil;
|
return XtraNil;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO maybe support only certain types in the future */
|
/* TODO maybe support only certain types in the future */
|
||||||
static void handle_xdnd_enter(XClientMessageEvent* e)
|
static void handle_xdnd_enter(XClientMessageEvent *e)
|
||||||
{
|
{
|
||||||
Xtra.handling_version = (e->data.l[1] >> 24);
|
Xtra.handling_version = (e->data.l[1] >> 24);
|
||||||
|
|
||||||
if ((e->data.l[1] & 1)) {
|
if ((e->data.l[1] & 1)) {
|
||||||
// Fetch the list of possible conversions
|
// Fetch the list of possible conversions
|
||||||
Property p = read_property(e->data.l[0], XdndTypeList);
|
Property p = read_property(e->data.l[0], XdndTypeList);
|
||||||
Xtra.expecting_type = get_dnd_type((long*)p.data, p.read_num);
|
Xtra.expecting_type = get_dnd_type((long *)p.data, p.read_num);
|
||||||
XFree(p.data);
|
XFree(p.data);
|
||||||
} else {
|
} else {
|
||||||
// Use the available list
|
// Use the available list
|
||||||
@ -119,7 +120,7 @@ static void handle_xdnd_enter(XClientMessageEvent* e)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_xdnd_position(XClientMessageEvent* e)
|
static void handle_xdnd_position(XClientMessageEvent *e)
|
||||||
{
|
{
|
||||||
XEvent ev = {
|
XEvent ev = {
|
||||||
.xclient = {
|
.xclient = {
|
||||||
@ -143,7 +144,7 @@ static void handle_xdnd_position(XClientMessageEvent* e)
|
|||||||
XFlush(Xtra.display);
|
XFlush(Xtra.display);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_xdnd_drop(XClientMessageEvent* e)
|
static void handle_xdnd_drop(XClientMessageEvent *e)
|
||||||
{
|
{
|
||||||
/* Not expecting any type */
|
/* Not expecting any type */
|
||||||
if (Xtra.expecting_type == XtraNil) {
|
if (Xtra.expecting_type == XtraNil) {
|
||||||
@ -172,7 +173,7 @@ static void handle_xdnd_drop(XClientMessageEvent* e)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_xdnd_selection(XSelectionEvent* e)
|
static void handle_xdnd_selection(XSelectionEvent *e)
|
||||||
{
|
{
|
||||||
/* DnD succesfully finished, send finished and call callback */
|
/* DnD succesfully finished, send finished and call callback */
|
||||||
XEvent ev = {
|
XEvent ev = {
|
||||||
@ -199,12 +200,12 @@ static void handle_xdnd_selection(XSelectionEvent* e)
|
|||||||
|
|
||||||
|
|
||||||
/* Call callback for every entry */
|
/* Call callback for every entry */
|
||||||
if (Xtra.on_drop && p.read_num)
|
if (Xtra.on_drop && p.read_num) {
|
||||||
{
|
|
||||||
char *sptr;
|
char *sptr;
|
||||||
char *str = strtok_r((char *) p.data, "\n\r", &sptr);
|
char *str = strtok_r((char *) p.data, "\n\r", &sptr);
|
||||||
|
|
||||||
if (str) Xtra.on_drop(str, dt);
|
if (str) 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);
|
Xtra.on_drop(str, dt);
|
||||||
}
|
}
|
||||||
@ -212,7 +213,7 @@ static void handle_xdnd_selection(XSelectionEvent* e)
|
|||||||
if (p.data) XFree(p.data);
|
if (p.data) XFree(p.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *event_loop(void* p)
|
void *event_loop(void *p)
|
||||||
{
|
{
|
||||||
/* Handle events like a real nigga */
|
/* Handle events like a real nigga */
|
||||||
|
|
||||||
@ -221,30 +222,27 @@ void *event_loop(void* p)
|
|||||||
XEvent event;
|
XEvent event;
|
||||||
int pending;
|
int pending;
|
||||||
|
|
||||||
while (Xtra.display)
|
while (Xtra.display) {
|
||||||
{
|
|
||||||
/* NEEDMOEVENTSFODEMPROGRAMS */
|
/* NEEDMOEVENTSFODEMPROGRAMS */
|
||||||
|
|
||||||
XLockDisplay(Xtra.display);
|
XLockDisplay(Xtra.display);
|
||||||
if((pending = XPending(Xtra.display))) XNextEvent(Xtra.display, &event);
|
|
||||||
|
|
||||||
if (!pending)
|
if ((pending = XPending(Xtra.display))) XNextEvent(Xtra.display, &event);
|
||||||
{
|
|
||||||
|
if (!pending) {
|
||||||
XUnlockDisplay(Xtra.display);
|
XUnlockDisplay(Xtra.display);
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.type == ClientMessage)
|
if (event.type == ClientMessage) {
|
||||||
{
|
|
||||||
Atom type = event.xclient.message_type;
|
Atom type = event.xclient.message_type;
|
||||||
|
|
||||||
if (type == XdndEnter) handle_xdnd_enter(&event.xclient);
|
if (type == XdndEnter) handle_xdnd_enter(&event.xclient);
|
||||||
else if (type == XdndPosition) handle_xdnd_position(&event.xclient);
|
else if (type == XdndPosition) handle_xdnd_position(&event.xclient);
|
||||||
else if (type == XdndDrop) handle_xdnd_drop(&event.xclient);
|
else if (type == XdndDrop) handle_xdnd_drop(&event.xclient);
|
||||||
else if (type == XtraTerminate) break;
|
else if (type == XtraTerminate) break;
|
||||||
}
|
} else if (event.type == SelectionNotify) handle_xdnd_selection(&event.xselection);
|
||||||
else if (event.type == SelectionNotify) handle_xdnd_selection(&event.xselection);
|
|
||||||
/* AINNOBODYCANHANDLEDEMEVENTS*/
|
/* AINNOBODYCANHANDLEDEMEVENTS*/
|
||||||
else XSendEvent(Xtra.display, Xtra.terminal_window, 0, 0, &event);
|
else XSendEvent(Xtra.display, Xtra.terminal_window, 0, 0, &event);
|
||||||
|
|
||||||
@ -256,6 +254,7 @@ void *event_loop(void* p)
|
|||||||
* otherwise HEWUSAGUDBOI happens
|
* otherwise HEWUSAGUDBOI happens
|
||||||
*/
|
*/
|
||||||
if (Xtra.display) XCloseDisplay(Xtra.display);
|
if (Xtra.display) XCloseDisplay(Xtra.display);
|
||||||
|
|
||||||
return (Xtra.display = NULL);
|
return (Xtra.display = NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,6 +266,7 @@ int init_xtra(drop_callback d)
|
|||||||
else Xtra.on_drop = d;
|
else Xtra.on_drop = d;
|
||||||
|
|
||||||
XInitThreads();
|
XInitThreads();
|
||||||
|
|
||||||
if ( !(Xtra.display = XOpenDisplay(NULL))) return -1;
|
if ( !(Xtra.display = XOpenDisplay(NULL))) return -1;
|
||||||
|
|
||||||
Xtra.terminal_window = focused_window_id();
|
Xtra.terminal_window = focused_window_id();
|
||||||
@ -274,7 +274,7 @@ int init_xtra(drop_callback d)
|
|||||||
/* OSX: if focused window is 0, it means toxic is ran from
|
/* OSX: if focused window is 0, it means toxic is ran from
|
||||||
* native terminal and not X11 terminal window, silently exit */
|
* native terminal and not X11 terminal window, silently exit */
|
||||||
if (!Xtra.terminal_window)
|
if (!Xtra.terminal_window)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
{
|
{
|
||||||
/* Create an invisible window which will act as proxy for the DnD operation. */
|
/* Create an invisible window which will act as proxy for the DnD operation. */
|
||||||
@ -300,15 +300,15 @@ int init_xtra(drop_callback d)
|
|||||||
&root, &x, &y, &wht, &hht, &b, &d);
|
&root, &x, &y, &wht, &hht, &b, &d);
|
||||||
|
|
||||||
if (! (Xtra.proxy_window = XCreateWindow
|
if (! (Xtra.proxy_window = XCreateWindow
|
||||||
(Xtra.display, Xtra.terminal_window, /* Parent */
|
(Xtra.display, Xtra.terminal_window, /* Parent */
|
||||||
0, 0, /* Position */
|
0, 0, /* Position */
|
||||||
wht, hht, /* Width + height */
|
wht, hht, /* Width + height */
|
||||||
0, /* Border width */
|
0, /* Border width */
|
||||||
CopyFromParent, /* Depth */
|
CopyFromParent, /* Depth */
|
||||||
InputOnly, /* Class */
|
InputOnly, /* Class */
|
||||||
CopyFromParent, /* Visual */
|
CopyFromParent, /* Visual */
|
||||||
CWEventMask | CWCursor, /* Value mask */
|
CWEventMask | CWCursor, /* Value mask */
|
||||||
&attr)) ) /* Attributes for value mask */
|
&attr)) ) /* Attributes for value mask */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,9 +335,10 @@ int init_xtra(drop_callback d)
|
|||||||
XA_ATOM,
|
XA_ATOM,
|
||||||
32,
|
32,
|
||||||
PropModeReplace,
|
PropModeReplace,
|
||||||
(unsigned char*)&XdndVersion, 1);
|
(unsigned char *)&XdndVersion, 1);
|
||||||
|
|
||||||
pthread_t id;
|
pthread_t id;
|
||||||
|
|
||||||
if (pthread_create(&id, NULL, event_loop, NULL) != 0)
|
if (pthread_create(&id, NULL, event_loop, NULL) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -28,10 +28,10 @@
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
DT_plain,
|
DT_plain,
|
||||||
DT_file_list
|
DT_file_list
|
||||||
}
|
}
|
||||||
DropType;
|
DropType;
|
||||||
|
|
||||||
typedef void (*drop_callback) (const char*, DropType);
|
typedef void (*drop_callback) (const char *, DropType);
|
||||||
|
|
||||||
int init_xtra(drop_callback d);
|
int init_xtra(drop_callback d);
|
||||||
void terminate_xtra();
|
void terminate_xtra();
|
||||||
|
Reference in New Issue
Block a user