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

Compare commits

...

152 Commits

Author SHA1 Message Date
b23ae5a4c3 add buffer yanking, clean up input functions 2014-07-14 14:44:42 -04:00
190e1e73e8 change tab names: prompt = home, friends = contacts 2014-07-13 15:34:09 -04:00
ee67cf0bf1 use full name for log 2014-07-10 02:54:56 -04:00
aaeb47dc14 create dns loopup threads in detached state & add a few missing error descriptions 2014-07-09 23:40:46 -04:00
e19b0ed710 delete subwindows before parent window on resize to prevent memory leaks 2014-07-09 22:12:51 -04:00
a774121c13 Merge pull request #183 from mannol1/master
Fixes problems with upstream changes
2014-07-10 01:30:17 +02:00
df676423a7 Fixed conflicts 2014-07-10 01:29:18 +02:00
cf8dda6b0d Fixes problems with upstream changes 2014-07-10 01:24:14 +02:00
1ce731471d fix potential race conditions 2014-07-09 02:21:01 -04:00
f98c77432b exit toxic properly on ^C 2014-07-08 20:21:51 -04:00
9fa5a3fdb6 fix window cleanup bugs & give prompt its own cleanup func 2014-07-08 19:24:44 -04:00
5b9fd70f30 autosave every 60 seconds 2014-07-08 14:46:50 -04:00
442f68cd31 wrap tox_get_name in function that truncates name if it's too long 2014-07-08 14:31:59 -04:00
e74212cb9e Merge pull request #181 from Ansa89/master
Use long int instead uint64_t
2014-07-08 12:00:48 -04:00
57b52f35b4 Use long int instead uint64_t 2014-07-08 09:39:42 +02:00
27a31a8399 truncate long chat window names 2014-07-07 19:39:33 -04:00
f1a3ed379e fix nick truncating 2014-07-07 19:08:33 -04:00
60f9be7234 Merge pull request #180 from Ansa89/master
Forgot about help
2014-07-07 11:10:45 +02:00
dcfb90bc63 Forgot about help 2014-07-07 09:36:29 +02:00
74b84c4252 some code cleanup 2014-07-07 03:12:47 -04:00
00e6546f0c namelength should be signed, -Werror is probably overkill 2014-07-06 22:31:11 -04:00
a009fbf20c use char instead of uint8_t, fix compiler warnings so toxic compiles with -Wall and -Werror on gcc and clang 2014-07-06 22:16:20 -04:00
2ed9448b41 Merge pull request #174 from mannol1/master
Make closing window end call
2014-07-06 22:52:11 +02:00
1575a40d61 reduce inactive window refresh rate 2014-07-06 16:18:34 -04:00
a784fdf9d5 Merge pull request #179 from Ansa89/master
Add option to disable audio support
2014-07-06 16:16:15 -04:00
612c0e1131 Add freebsd flags for ncursesw 2014-07-06 21:23:58 +02:00
16a82e1897 Add option to disable audio support 2014-07-06 19:57:08 +02:00
ad14baf601 remove unnecessary memsets 2014-07-06 03:41:48 -04:00
8b6a5813e6 fix line_info_reset_start() bugs, a few other small fixes/cleanup 2014-07-06 01:48:50 -04:00
f4c76e12f4 A/V api change. 2014-07-05 16:19:38 -04:00
3fa8c4be0b small fix 2014-07-05 15:20:33 -04:00
2f904371ae Merge branch 'master' of https://github.com/Tox/toxic 2014-07-05 14:47:55 -04:00
455eba3bfd fix help popup flickering issue on some terminals 2014-07-05 14:46:16 -04:00
48f6a0cd5e fix typo 2014-07-04 14:25:22 -04:00
50a15d2289 update screenshot 2014-07-04 14:21:58 -04:00
de1e61bd5a code cleanup, improve welcome message 2014-07-04 14:19:20 -04:00
7fba5a59bf Fixed implicit declaration warning and merge conflict leftover 2014-07-04 18:14:06 +02:00
3a86ee923e Fixed merge conflicts 2014-07-04 18:05:50 +02:00
65e726a51a Now closing the window will end the call 2014-07-04 18:04:03 +02:00
91c4414889 update screenshot 2014-07-04 03:35:27 -04:00
6754741f37 improve /help system and add startup welcome message 2014-07-04 03:24:29 -04:00
10d0e99d72 core api const-correctness update 2014-07-02 17:30:31 -04:00
9696acc8bd remove obsolete unixtime patch 2014-07-02 16:20:03 -04:00
0f37e50419 groupchat keys can sometimes start with a 0 2014-07-02 14:13:35 -04:00
95d09e4b75 fix window resizing bug on some platforms and add -O1 optimization flag 2014-07-01 19:39:25 -04:00
7c71c35797 possibly fix segfault 2014-07-01 15:04:29 -04:00
893cfaa543 correctly reposition call infobox on resize 2014-07-01 11:17:52 -04:00
3e22c9b829 allow friendlist to be resized properly 2014-07-01 01:17:31 -04:00
a968ca2a2e update toxic version to 0.4.3 2014-07-01 00:11:40 -04:00
c271622670 fix resizing bugs 2014-06-30 23:56:47 -04:00
a126f9c1a6 don't excessively update percentage complete line during file transfers 2014-06-30 14:17:07 -04:00
44d524134f need mutexes 2014-06-30 11:42:11 -04:00
7ae807002e file sender thread was a failed experiment - do_file_senders should only be called once per tox_do iteration 2014-06-30 03:03:43 -04:00
a194f7ad87 add option to use the default locale 2014-06-29 18:14:28 -04:00
61d3f7e63e fix tab completion in prompt window 2014-06-29 16:54:27 -04:00
8715e9c41e Merge pull request #170 from Ansa89/patch-1
Manpage fix
2014-06-29 11:58:39 -04:00
5da69e7f56 Manpage fix 2014-06-29 11:48:02 +02:00
ebc5cd9285 manpage fixes/rm redundant comments & make alerts setting more intuitive 2014-06-28 22:05:05 -04:00
97536d2a72 add setting option to disable timestamps 2014-06-28 20:33:46 -04:00
a2e6a25fc8 make prompt window look like chat/groupchat windows (fixes various bugs, allows history scrolling) 2014-06-28 18:40:22 -04:00
f8998b5891 properly close file senders on exit 2014-06-28 12:55:05 -04:00
8d4f7fc32b Merge pull request #169 from Ansa89/make_help
Add help target and toxic.conf manpage
2014-06-28 12:51:42 -04:00
828b7fb505 Add help target and toxic.conf manpage 2014-06-28 18:40:59 +02:00
74525bcd14 rm Werror for clang 2014-06-28 12:24:42 -04:00
33e98fd720 put file senders in one thread due to weird issues & a few fixes 2014-06-28 12:14:43 -04:00
134e5873a9 Merge pull request #165 from mannol1/master
Fixed setting buffer to half of the size
2014-06-27 01:46:24 +02:00
89a95eca16 Fixed setting buffer to half of the size 2014-06-27 01:45:15 +02:00
d881312e3e should fix the high cpu usage issue 2014-06-26 19:35:12 -04:00
da65ba4e8d give file senders their own threads 2014-06-26 18:20:56 -04:00
e8a39e1722 man page fixes/additions, rm unneeded toxic.conf file from install 2014-06-26 13:22:22 -04:00
581261afca fix backspace issue on some platforms 2014-06-26 11:19:51 -04:00
8d68b5cc01 Merge pull request #164 from Ansa89/man-page
Add manpage
2014-06-26 14:09:44 +02:00
353be3a7a2 Add manpage 2014-06-26 14:06:22 +02:00
b9af1b3293 Merge pull request #5 from Tox/master
Sync with main project
2014-06-26 13:28:43 +02:00
09badaa9ee refactor chat window input code, misc fixes 2014-06-26 02:52:01 -04:00
587f6518f7 Merge pull request #4 from Tox/master
Sync with main project
2014-06-25 11:09:59 +02:00
6c38e72654 Merge pull request #161 from Ansa89/fix-autoconnect
Try to fix autoconnect
2014-06-25 11:00:45 +02:00
599c2119d5 README.md: better wording 2014-06-25 10:54:05 +02:00
dfd89f2b5c Makefile: fix typo...again 2014-06-25 09:56:31 +02:00
7db3dcbdf6 Makefile: fix typo 2014-06-25 09:53:05 +02:00
5b268a1a6a Try to fix autoconnect (Tox/toxic#158) 2014-06-25 09:13:57 +02:00
43c1140aa2 improve input scrolling, fix some unicode issues (WIP) 2014-06-24 21:02:16 -04:00
0bc9725b98 forgot makefile 2014-06-24 17:52:57 -04:00
ef097757f3 general cleanup: rm unused config.h, add license info to device.c/h, add a couple compiler options and fix warnings 2014-06-24 17:47:35 -04:00
6490fa598c Merge pull request #157 from Ansa89/widechar
Wide characters support
2014-06-24 17:04:21 -04:00
c41464c990 fix dns compatibility for apple 2014-06-24 13:20:12 -04:00
94d7e3199e Put back license 2014-06-24 17:48:49 +02:00
140dd5e5d3 Put back license 2014-06-24 17:46:52 +02:00
251a81ef43 Create cfg directory 2014-06-24 17:37:11 +02:00
76f81c4d33 Wide characters support and removed unused files 2014-06-24 17:35:23 +02:00
b14a1bb7b9 Merge pull request #3 from Tox/master
Sync with main project
2014-06-24 17:25:25 +02:00
5f6f021039 Merge pull request #155 from theGeekPirate/patch-1
Polishing README.md
2014-06-24 15:00:35 +02:00
9b69cecfb1 Polishing README.md
- Corrected English phrasing throughout
- Display screenshot on the page instead of a link
- Clarification as to what 'libtoxav' is
- Numeration for compilation steps instead of an unsorted list
- Separated compilation instructions into steps and notes
- Added links for dependencies
2014-06-24 05:54:14 -07:00
f75248d177 Merge pull request #153 from Ansa89/master
README.md: add build status
2014-06-24 14:02:01 +02:00
97f8d6c074 README.md: add build status 2014-06-24 13:20:21 +02:00
c29d5d1ca2 Merge pull request #1 from Tox/master
Sync with main project
2014-06-24 12:51:24 +02:00
48c272acf8 Merge pull request #152 from Ansa89/without-autotools
Update readme instructions
2014-06-24 12:48:53 +02:00
f66b9137e8 Update README.md 2014-06-24 12:46:18 +02:00
c3dfaa5935 Update README.md 2014-06-24 12:45:14 +02:00
9a9ae03e41 Update .gitignore: revert previous commit 2014-06-24 12:41:49 +02:00
2bbc47d3f7 Update .gitignore: remove autotools 2014-06-24 12:37:43 +02:00
f12b0ee472 Update .gitignore: remove autotools 2014-06-24 12:35:45 +02:00
46e4ddfaf1 Update README.md 2014-06-24 12:30:33 +02:00
449b6fa5ff Update README.md 2014-06-24 12:28:56 +02:00
3913adedb0 Update .travis.yml: cosmetic fixes 2014-06-24 12:06:13 +02:00
4cf545d334 Merge pull request #149 from Ansa89/without-autotools
Remove autotools dependency
2014-06-24 12:03:52 +02:00
9225af06b1 Update .travis.yml: moved makefile in "build/" 2014-06-24 11:53:10 +02:00
562483823c Makefile: move to "build/" 2014-06-24 11:53:02 +02:00
57742bcd87 Makefile: use <TAB> instead of <SPACE> 2014-06-24 11:01:32 +02:00
5066ea637b Update .travis.yml: remove autotools 2014-06-24 10:53:24 +02:00
7b8cf65218 Makefile: remove Windows support and bump version 2014-06-24 09:02:06 +02:00
7ac7713268 improve call duration string & remove a couple unused functions 2014-06-24 02:58:18 -04:00
490c80dae9 don't allow calls to offline friends 2014-06-23 22:15:39 -04:00
f324d2d34b some fixups 2014-06-23 21:56:58 -04:00
f3ee120c48 Merge branch 'master' of https://github.com/Tox/toxic 2014-06-23 18:54:48 -04:00
63ea6154f4 show info box for audio calls 2014-06-23 18:54:23 -04:00
eafa660dee Merge pull request #151 from mannol1/master
Forgot to set index in some callbacks
2014-06-24 00:30:37 +02:00
2a6a5b13d7 Forgot to set index in some callbacks 2014-06-24 00:30:11 +02:00
47b9648f85 Makefile: fix typo 2014-06-24 00:23:37 +02:00
55c05a4092 Merge pull request #150 from mannol1/master
Reverse call_idx and enable running call when devices fail to load
2014-06-24 00:21:22 +02:00
476b056ed0 make it dynamic 2014-06-24 00:20:44 +02:00
c53600b550 Makefile: add per-system defaults
This is only an empty structure, but I hope it will help for add per-system defaults in future
2014-06-24 00:17:14 +02:00
f47991e18e Reverse call_idx and enable running call when devices fail to load 2014-06-23 23:57:12 +02:00
773a3f4abf Remove autotools 2014-06-23 23:24:24 +02:00
809f472cb4 Remove autotools 2014-06-23 23:24:03 +02:00
e8ee3d694a Remove autotools 2014-06-23 23:23:41 +02:00
fec501801e Remove autotools 2014-06-23 23:23:17 +02:00
c52fe21237 Remove autotools 2014-06-23 23:23:05 +02:00
f00c218e56 Remove autotools 2014-06-23 23:22:32 +02:00
1daa4c5ca6 Makefile: add toxic version 2014-06-23 22:32:10 +02:00
717f8986cd Makefile: checks for libs 2014-06-23 21:55:32 +02:00
65aba6e77d Merge pull request #147 from Ansa89/cast-localtime
Cast localtime
2014-06-23 21:30:19 +02:00
9f8a6a8b6b Use pkg-config for toxcore and toxav 2014-06-23 15:34:32 +02:00
b0bfb13241 Update Makefile
Cosmetic fixes
2014-06-23 14:07:23 +02:00
34102f72a2 Hand-written makefile
Compile toxic without autotools
2014-06-23 11:09:01 +02:00
cb93c6ec65 Cast time to "time_t" 2014-06-23 10:58:24 +02:00
78af10fa1f Cast time to "time_t" 2014-06-23 10:57:27 +02:00
52b7719180 Merge pull request #146 from mannol1/master
Changed code a bit and added new features
2014-06-22 21:10:25 +02:00
48361a003e Merged upstream and other fixes 2014-06-22 21:07:11 +02:00
34bd4a1c7c fix a bunch of implicit declarations 2014-06-21 21:41:38 -04:00
94b271da5d wat 2014-06-22 02:31:24 +02:00
e47f2c05f3 Added VAD, changed device i/o, mute option, dynamic device changing and more 2014-06-22 02:18:23 +02:00
6b9ef7e6c9 refactor string funcs 2014-06-21 17:55:01 -04:00
62239a1fda fix backspace bug 2014-06-21 11:55:32 -04:00
bba81ac884 fix offset issue 2014-06-20 23:56:59 -04:00
9f4248b1e1 redesign text input field to scroll horizontally, increase max string size 2014-06-20 23:08:13 -04:00
e06f0ffb7e Missed device.* 2014-06-21 02:04:25 +02:00
29b283c176 VAD sort of works 2014-06-21 01:58:00 +02:00
3e797db16e various fixes 2014-06-20 14:27:33 -04:00
034a8f5d8b code cleanup, improve do_connection 2014-06-19 13:50:41 -04:00
7ccf4b6432 Little fix(tm) 2014-05-29 23:42:22 +02:00
d18ba78d03 Allow toxic to compile without av 2014-05-29 23:25:09 +02:00
63 changed files with 3308 additions and 3636 deletions

13
.gitignore vendored
View File

@ -9,19 +9,10 @@
*.app
*.swp
*.la
m4/*
!m4/pkg.m4
configure
configure_aux
Makefile.in
aclocal.m4
config.h*
config.log
config.status
stamp-h1
autom4te.cache
.deps
.libs
*.orig
build/toxic
Makefile
build/*.o
build/*.d

View File

@ -4,56 +4,45 @@ compiler:
- clang
before_script:
#installing libsodium, needed for Core
- git clone git://github.com/jedisct1/libsodium.git > /dev/null
# Installing yasm (needed for compiling vpx) and openal
- sudo apt-get -yq install yasm libopenal-dev
# Installing libsodium, needed for toxcore
- git clone https://github.com/jedisct1/libsodium.git libsodium
- cd libsodium
- git checkout tags/0.4.2 > /dev/null
- ./autogen.sh > /dev/null
- ./configure > /dev/null
- make check -j3 > /dev/null
- sudo make install >/dev/null
- cd ..
#installing yasm, needed for compiling vpx
- sudo apt-get install yasm > /dev/null
#installing libconfig, needed for DHT_bootstrap_daemon
- wget http://www.hyperrealm.com/libconfig/libconfig-1.4.9.tar.gz > /dev/null
- tar -xvzf libconfig-1.4.9.tar.gz > /dev/null
- cd libconfig-1.4.9
- ./configure > /dev/null
- make -j3 > /dev/null
- make check -j2 || make check || exit 1 > /dev/null
- sudo make install > /dev/null
- cd ..
#installing libopus, needed for audio encoding/decoding
- wget http://downloads.xiph.org/releases/opus/opus-1.0.3.tar.gz > /dev/null
# Installing libopus, needed for audio encoding/decoding
- wget http://downloads.xiph.org/releases/opus/opus-1.0.3.tar.gz
- tar xzf opus-1.0.3.tar.gz > /dev/null
- cd opus-1.0.3
- ./configure > /dev/null
- make -j3 > /dev/null
- make -j2 || make || exit 1 > /dev/null
- sudo make install > /dev/null
- cd ..
#installing vpx
- git clone http://git.chromium.org/webm/libvpx.git > /dev/null
# Installing vpx
- git clone http://git.chromium.org/webm/libvpx.git libvpx
- cd libvpx
- ./configure --enable-shared > /dev/null
- make -j3 >/dev/null
- make -j2 || make || exit 1 > /dev/null
- sudo make install > /dev/null
- cd ..
#creating libraries links and updating cache
# Creating libraries links and updating cache
- sudo ldconfig > /dev/null
# creating librarys' links and updating cache
- sudo ldconfig
- git clone https://github.com/irungentoo/ProjectTox-Core.git toxcore
# Installing toxcore
- git clone https://github.com/irungentoo/toxcore.git toxcore
- cd toxcore
- autoreconf -i
- ./configure --disable-tests --disable-ntox --disable-daemon --enable-av
- make -j2
- make -j2 || make || exit 1
- sudo make install
- cd ..
- sudo apt-get install libopenal-dev -yq
script:
- autoreconf -i
- ./configure
- make -j2
- cd build
- make -j2 || make || exit 1
notifications:
email: false

View File

@ -1 +0,0 @@
See github contributors

View File

@ -672,3 +672,4 @@ may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

365
INSTALL
View File

@ -1,365 +0,0 @@
Installation Instructions
*************************
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
2006, 2007, 2008, 2009 Free Software Foundation, Inc.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. This file is offered as-is,
without warranty of any kind.
Basic Installation
==================
Briefly, the shell commands `./configure; make; make install' should
configure, build, and install this package. The following
more-detailed instructions are generic; see the `README' file for
instructions specific to this package. Some packages provide this
`INSTALL' file but do not implement all of the features documented
below. The lack of an optional feature in a given package is not
necessarily a bug. More recommendations for GNU packages can be found
in *note Makefile Conventions: (standards)Makefile Conventions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, and a
file `config.log' containing compiler output (useful mainly for
debugging `configure').
It can also use an optional file (typically called `config.cache'
and enabled with `--cache-file=config.cache' or simply `-C') that saves
the results of its tests to speed up reconfiguring. Caching is
disabled by default to prevent problems with accidental use of stale
cache files.
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If you are using the cache, and at
some point `config.cache' contains results you don't want to keep, you
may remove or edit it.
The file `configure.ac' (or `configure.in') is used to create
`configure' by a program called `autoconf'. You need `configure.ac' if
you want to change it or regenerate `configure' using a newer version
of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system.
Running `configure' might take a while. While running, it prints
some messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package, generally using the just-built uninstalled binaries.
4. Type `make install' to install the programs and any data files and
documentation. When installing into a prefix owned by root, it is
recommended that the package be configured and built as a regular
user, and only the `make install' phase executed with root
privileges.
5. Optionally, type `make installcheck' to repeat any self-tests, but
this time using the binaries in their final installed location.
This target does not install anything. Running this target as a
regular user, particularly if the prior `make install' required
root privileges, verifies that the installation completed
correctly.
6. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
7. Often, you can also type `make uninstall' to remove the installed
files again. In practice, not all packages have tested that
uninstallation works correctly, even though it is required by the
GNU Coding Standards.
8. Some packages, particularly those that use Automake, provide `make
distcheck', which can by used by developers to test that all other
targets like `make install' and `make uninstall' work correctly.
This target is generally not run by end users.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. Run `./configure --help'
for details on some of the pertinent environment variables.
You can give `configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here
is an example:
./configure CC=c99 CFLAGS=-g LIBS=-lposix
*Note Defining Variables::, for more details.
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you can use GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'. This
is known as a "VPATH" build.
With a non-GNU `make', it is safer to compile the package for one
architecture at a time in the source code directory. After you have
installed the package for one architecture, use `make distclean' before
reconfiguring for another architecture.
On MacOS X 10.5 and later systems, you can create libraries and
executables that work on multiple system types--known as "fat" or
"universal" binaries--by specifying multiple `-arch' options to the
compiler but only a single `-arch' option to the preprocessor. Like
this:
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CPP="gcc -E" CXXCPP="g++ -E"
This is not guaranteed to produce working output in all cases, you
may have to build one architecture at a time and combine the results
using the `lipo' tool if you have problems.
Installation Names
==================
By default, `make install' installs the package's commands under
`/usr/local/bin', include files under `/usr/local/include', etc. You
can specify an installation prefix other than `/usr/local' by giving
`configure' the option `--prefix=PREFIX', where PREFIX must be an
absolute file name.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
PREFIX as the prefix for installing programs and libraries.
Documentation and other data files still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=DIR' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them. In general, the
default for these options is expressed in terms of `${prefix}', so that
specifying just `--prefix' will affect all of the other directory
specifications that were not explicitly provided.
The most portable way to affect installation locations is to pass the
correct locations to `configure'; however, many packages provide one or
both of the following shortcuts of passing variable assignments to the
`make install' command line to change installation locations without
having to reconfigure or recompile.
The first method involves providing an override variable for each
affected directory. For example, `make install
prefix=/alternate/directory' will choose an alternate location for all
directory configuration variables that were expressed in terms of
`${prefix}'. Any directories that were specified during `configure',
but not in terms of `${prefix}', must each be overridden at install
time for the entire installation to be relocated. The approach of
makefile variable overrides for each directory variable is required by
the GNU Coding Standards, and ideally causes no recompilation.
However, some platforms have known limitations with the semantics of
shared libraries that end up requiring recompilation when using this
method, particularly noticeable in packages that use GNU Libtool.
The second method involves providing the `DESTDIR' variable. For
example, `make install DESTDIR=/alternate/directory' will prepend
`/alternate/directory' before all installation names. The approach of
`DESTDIR' overrides is not required by the GNU Coding Standards, and
does not work on platforms that have drive letters. On the other hand,
it does better at avoiding recompilation issues, and works well even
when some directory options were not specified in terms of `${prefix}'
at `configure' time.
Optional Features
=================
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Some packages offer the ability to configure how verbose the
execution of `make' will be. For these packages, running `./configure
--enable-silent-rules' sets the default to minimal output, which can be
overridden with `make V=1'; while running `./configure
--disable-silent-rules' sets the default to verbose, which can be
overridden with `make V=0'.
Particular systems
==================
On HP-UX, the default C compiler is not ANSI C compatible. If GNU
CC is not installed, it is recommended to use the following options in
order to use an ANSI C compiler:
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
parse its `<wchar.h>' header file. The option `-nodtk' can be used as
a workaround. If GNU CC is not installed, it is therefore recommended
to try
./configure CC="cc"
and if that doesn't work, try
./configure CC="cc -nodtk"
On Solaris, don't put `/usr/ucb' early in your `PATH'. This
directory contains several dysfunctional programs; working variants of
these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
in your `PATH', put it _after_ `/usr/bin'.
On Haiku, software installed for all users goes in `/boot/common',
not `/usr/local'. It is recommended to use the following options:
./configure --prefix=/boot/common
Specifying the System Type
==========================
There may be some features `configure' cannot figure out
automatically, but needs to determine by the type of machine the package
will run on. Usually, assuming the package is built to be run on the
_same_ architectures, `configure' can figure that out, but if it prints
a message saying it cannot guess the machine type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM
where SYSTEM can have one of these forms:
OS
KERNEL-OS
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should
use the option `--target=TYPE' to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the
"host" platform (i.e., that on which the generated programs will
eventually be run) with `--host=TYPE'.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Defining Variables
==================
Variables not defined in a site shell script can be set in the
environment passed to `configure'. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
them in the `configure' command line, using `VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc
causes the specified `gcc' to be used as the C compiler (unless it is
overridden in the site shell script).
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
an Autoconf bug. Until the bug is fixed you can use this workaround:
CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
`configure' Invocation
======================
`configure' recognizes the following options to control how it
operates.
`--help'
`-h'
Print a summary of all of the options to `configure', and exit.
`--help=short'
`--help=recursive'
Print a summary of the options unique to this package's
`configure', and exit. The `short' variant lists options used
only in the top level, while the `recursive' variant lists options
also present in any nested packages.
`--version'
`-V'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`--cache-file=FILE'
Enable the cache: use and save the results of the tests in FILE,
traditionally `config.cache'. FILE defaults to `/dev/null' to
disable caching.
`--config-cache'
`-C'
Alias for `--cache-file=config.cache'.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`--prefix=DIR'
Use DIR as the installation prefix. *note Installation Names::
for more details, including other options available for fine-tuning
the installation locations.
`--no-create'
`-n'
Run the configure checks, but stop before creating any output
files.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.

View File

@ -1,3 +0,0 @@
SUBDIRS = build misc
ACLOCAL_AMFLAGS = -I m4

0
NEWS
View File

1
README
View File

@ -1 +0,0 @@

View File

@ -1,25 +1,48 @@
# Toxic
# Toxic [![Build Status](https://travis-ci.org/Tox/toxic.png?branch=master)](https://travis-ci.org/Tox/toxic)
Toxic is a [Tox](https://tox.im)-based instant messenging client which formerly resided in the [Tox core repository](https://github.com/irungentoo/toxcore), and is now available as a standalone application.
![Toxic Screenshot](https://i.imgur.com/YOZ5NIB.png "Main Screen").
Toxic is an ncurses based instant messaging client for [Tox](http://tox.im) which formerly resided in the [Tox core repository](https://github.com/irungentoo/ProjectTox-Core) and is now available as a standalone program. It looks like [this](http://i.imgur.com/hL7WhVl.png).
## Installation
* Generate the configure script by running the ```autoreconf -i``` command.
* Execute the configure script with ```./configure``` (you may need to pass it the location of your dependency libraries, i.e.):
```./configure --prefix=/where/to/install --with-libtoxcore-headers=/path/to/ProjectTox-Core/toxcore --with-libtoxcore-libs=/path/to/ProjectTox-Core/build/.libs --with-libsodium-headers=/path/to/libsodium/include/ --with-libsodium-libs=/path/to/sodiumtest/lib/ ```
### Dependencies
##### Base
* [libtoxcore](https://github.com/irungentoo/toxcore)
* [ncurses](https://www.gnu.org/software/ncurses) (for Debian based systems, 'libncursesw5-dev')
* Audio calling support requires openal installed
* Compile with --disable-av to build without audio call support
* Compile and install the program with ```make && sudo make install```
##### Audio
* libtoxav (libtoxcore compiled with audio support)
* [openal](http://openal.org)
#### Notes
If your default prefix is /usr/local and you get the error: "error while loading shared libraries: libtoxcore.so.0: cannot open shared object file: No such file or directory", then you can try running ```sudo ldconfig```. If that doesn't fix it, run:
### Compiling
1. `cd build/`
2. `make PREFIX="/where/to/install"`
3. `sudo make install PREFIX="/where/to/install"`
### Compilation Notes
* 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)
* Audio call support is automatically enabled if all dependencies are found
* If you want to build toxic without audio call support, you can use `make DISABLE_AV=1`
### Packaging
* For packaging purpose, you can use `DESTDIR=""` to specify a directory where to store installed files
* `DESTDIR=""` can be used in addition to `PREFIX=""`:
* `DESTDIR=""` is meant to specify a directory where to store installed files (ex: "/tmp/build/pkg")
* `PREFIX=""` is meant to specify a prefix directory for binaries and data files (ex: "/usr/local")
### Troubleshooting
If your default prefix is "/usr/local" and you receive the following:
```
error while loading shared libraries: libtoxcore.so.0: cannot open shared object file: No such file or directory
```
you can attempt to correct it by running `sudo ldconfig`. If that doesn't work, run:
```
echo '/usr/local/lib/' | sudo tee -a /etc/ld.so.conf.d/locallib.conf
sudo ldconfig
```
If you dont already have them, you may need to install the ncurses libraries. For Debian based systems:
```
sudo apt-get install libncurses5-dev libncursesw5-dev
```
## Settings
After running Toxic for the first time an empty file called toxic.conf should reside in your home configuration directory (~/.config/tox for Linux users). For an example on how to use this config file to save settings such as auto-logging and time format see: toxic/misc/toxic.conf
Running Toxic for the first time creates an empty file called toxic.conf in your home configuration directory ("~/.config/tox" for Linux users). Adding options to this file allows you to enable auto-logging, change the time format (12/24 hour), and much more.
You can view our example config file [here](misc/toxic.conf.example).

132
build/Makefile Normal file
View File

@ -0,0 +1,132 @@
TOXIC_VERSION = 0.4.5
REV = $(shell git rev-list HEAD --count)
VERSION = $(TOXIC_VERSION)_r$(REV)
CFG_DIR = ../cfg
SRC_DIR = ../src
MISC_DIR = ../misc
DOC_DIR = ../doc
PREFIX = /usr/local
BINDIR = $(PREFIX)/bin
DATADIR = $(PREFIX)/share/toxic
MANDIR = $(PREFIX)/man
DATAFILES = DHTnodes toxic.conf.example
MANFILES = toxic.1 toxic.conf.5
LIBS = libtoxcore ncursesw
CFLAGS = -std=gnu99 -pthread -Wall -g
CFLAGS += -DTOXICVER="\"$(VERSION)\"" -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED
CFLAGS += -DPACKAGE_DATADIR="\"$(abspath $(DATADIR))\""
CFLAGS += $(USER_CFLAGS)
LDFLAGS = $(USER_LDFLAGS)
OBJ = chat.o chat_commands.o configdir.o dns.o execute.o file_senders.o
OBJ += friendlist.o global_commands.o groupchat.o line_info.o input.o help.o
OBJ += log.o misc_tools.o prompt.o settings.o toxic.o toxic_strings.o windows.o
# Variables for audio support
AUDIO_LIBS = libtoxav openal
AUDIO_CFLAGS = -D_SUPPORT_AUDIO
AUDIO_OBJ = device.o audio_call.o
# Check on wich system we are running
UNAME_S = $(shell uname -s)
ifeq ($(UNAME_S), Linux)
-include $(CFG_DIR)/Linux.mk
endif
ifeq ($(UNAME_S), FreeBSD)
-include $(CFG_DIR)/FreeBSD.mk
endif
ifeq ($(UNAME_S), Darwin)
-include $(CFG_DIR)/Darwin.mk
endif
ifeq ($(UNAME_S), Solaris)
-include $(CFG_DIR)/Solaris.mk
endif
# Check on which platform we are running
UNAME_M = $(shell uname -m)
ifeq ($(UNAME_M), x86_64)
-include $(CFG_DIR)/x86_64.mk
endif
ifneq ($(filter %86, $(UNAME_M)),)
-include $(CFG_DIR)/x86.mk
endif
ifneq ($(filter arm%, $(UNAME_M)),)
-include $(CFG_DIR)/arm.mk
endif
# Check if we want/can build audio
ifneq ($(DISABLE_AV), 1)
CHECK_AUDIO_LIBS = $(shell pkg-config $(AUDIO_LIBS) || echo -n "error")
ifneq ($(CHECK_AUDIO_LIBS), error)
LIBS += $(AUDIO_LIBS)
CFLAGS += $(AUDIO_CFLAGS)
OBJ += $(AUDIO_OBJ)
else
ifneq ($(MAKECMDGOALS), clean)
MISSING_AUDIO_LIBS = $(shell for lib in $(AUDIO_LIBS) ; do if ! pkg-config $$lib ; then echo $$lib ; fi ; done)
$(warning WARNING -- Toxic will be compiled without audio support)
$(warning WARNING -- You need these libraries for audio support)
$(warning WARNING -- $(MISSING_AUDIO_LIBS))
endif
endif
endif
# Check if we can build Toxic
CHECK_LIBS = $(shell pkg-config $(LIBS) || echo -n "error")
ifneq ($(CHECK_LIBS), error)
CFLAGS += $(shell pkg-config --cflags $(LIBS))
LDFLAGS += $(shell pkg-config --libs $(LIBS))
else
ifneq ($(MAKECMDGOALS), clean)
MISSING_LIBS = $(shell for lib in $(LIBS) ; do if ! pkg-config $$lib ; then echo $$lib ; fi ; done)
$(warning ERROR -- Cannot compile Toxic)
$(warning ERROR -- You need these libraries)
$(warning ERROR -- $(MISSING_LIBS))
$(error ERROR)
endif
endif
# Targets
all: toxic
toxic: $(OBJ)
@echo " LD $@"
@$(CC) $(CFLAGS) -o toxic $(OBJ) $(LDFLAGS)
install: toxic
mkdir -p $(abspath $(DESTDIR)/$(BINDIR))
mkdir -p $(abspath $(DESTDIR)/$(DATADIR))
mkdir -p $(abspath $(DESTDIR)/$(MANDIR))
@echo "Installing toxic executable"
@install -m 0755 toxic $(abspath $(DESTDIR)/$(BINDIR))
@echo "Installing data files"
@for f in $(DATAFILES) ; do \
install -m 0644 $(MISC_DIR)/$$f $(abspath $(DESTDIR)/$(DATADIR)) ;\
done
@echo "Installing man pages"
@for f in $(MANFILES) ; do \
section=$(abspath $(DESTDIR)/$(MANDIR))/man`echo $$f | rev | cut -d "." -f 1` ;\
file=$$section/$$f ;\
mkdir -p $$section ;\
install -m 0644 $(DOC_DIR)/$$f $$file ;\
sed -i'' -e 's:__VERSION__:'$(VERSION)':g' $$file ;\
sed -i'' -e 's:__DATADIR__:'$(abspath $(DATADIR))':g' $$file ;\
gzip -f -9 $$file ;\
done
%.o: $(SRC_DIR)/%.c
@echo " CC $@"
@$(CC) $(CFLAGS) -o $*.o -c $(SRC_DIR)/$*.c
@$(CC) -MM $(CFLAGS) $(SRC_DIR)/$*.c > $*.d
clean:
rm -rf *.d *.o toxic
-include $(CFG_DIR)/help.mk
-include $(OBJ:.o=.d)
.PHONY: clean all install

View File

@ -1,69 +0,0 @@
#Don't change this unless needed, else you'll break stuff
bin_PROGRAMS = toxic
toxic_SOURCES = $(top_srcdir)/src/toxic.c \
$(top_srcdir)/src/toxic.h \
$(top_srcdir)/src/chat.h \
$(top_srcdir)/src/chat.c \
$(top_srcdir)/src/configdir.h \
$(top_srcdir)/src/configdir.c \
$(top_srcdir)/src/prompt.h \
$(top_srcdir)/src/prompt.c \
$(top_srcdir)/src/friendlist.h \
$(top_srcdir)/src/friendlist.c \
$(top_srcdir)/src/windows.c \
$(top_srcdir)/src/windows.h \
$(top_srcdir)/src/groupchat.c \
$(top_srcdir)/src/groupchat.h \
$(top_srcdir)/src/global_commands.c \
$(top_srcdir)/src/global_commands.h \
$(top_srcdir)/src/chat_commands.c \
$(top_srcdir)/src/chat_commands.h \
$(top_srcdir)/src/execute.c \
$(top_srcdir)/src/execute.h \
$(top_srcdir)/src/misc_tools.c \
$(top_srcdir)/src/misc_tools.h \
$(top_srcdir)/src/toxic_strings.c \
$(top_srcdir)/src/toxic_strings.h \
$(top_srcdir)/src/log.c \
$(top_srcdir)/src/log.h \
$(top_srcdir)/src/file_senders.c \
$(top_srcdir)/src/file_senders.h \
$(top_srcdir)/src/line_info.c \
$(top_srcdir)/src/line_info.h \
$(top_srcdir)/src/settings.c \
$(top_srcdir)/src/settings.h \
$(top_srcdir)/src/dns.c \
$(top_srcdir)/src/dns.h
toxic_CFLAGS = -I$(top_srcdir) \
$(NCURSES_CFLAGS) \
$(LIBSODIUM_CFLAGS) \
$(LIBTOXCORE_CFLAGS) \
$(PTHREAD_CFLAGS)
toxic_CPPFLAGS = '-DTOXICVER="$(TOXIC_VERSION)"'
toxic_LDADD = $(LIBTOXCORE_LDFLAGS) \
$(LIBSODIUM_LDFLAGS) \
$(NCURSES_LIBS) \
$(LIBTOXCORE_LIBS) \
$(LIBSODIUM_LIBS) \
$(WINSOCK2_LIBS) \
$(PTHREAD_LIBS)
# For audio support
if BUILD_AV
toxic_SOURCES += $(top_srcdir)/src/audio_call.c \
$(top_srcdir)/src/audio_call.h
toxic_CFLAGS += $(LIBTOXAV_CFLAGS) \
$(OPENAL_CFLAGS)
toxic_LDADD += $(LIBTOXAV_LIBS) \
$(OPENAL_LIBS)
endif

3
cfg/FreeBSD.mk Normal file
View File

@ -0,0 +1,3 @@
# Specials options for freebsd systems
LIBS := $(filter-out ncursesw, $(LIBS))
LDFLAGS += -lncursesw

3
cfg/Linux.mk Normal file
View File

@ -0,0 +1,3 @@
# Specials options for linux systems
CFLAGS +=
LDFLAGS += -ldl -lresolv

17
cfg/help.mk Normal file
View File

@ -0,0 +1,17 @@
# Help target
help:
@echo "-- Targets --"
@echo " all: Build toxic [DEFAULT]"
@echo " toxic: Build toxic"
@echo " install: Build toxic and install it in PREFIX (default PREFIX is \"$(abspath $(PREFIX))\")"
@echo " clean: Remove built files"
@echo " help: This help"
@echo
@echo "-- Variables --"
@echo " DISABLE_AV: Set to \"1\" to force building without audio call support"
@echo " USER_CFLAGS: Add custom flags to default CFLAGS"
@echo " USER_LDFLAGS: Add custom flags to default LDFLAGS"
@echo " PREFIX: Specify a prefix directory for binaries, data files,... (default is \"$(abspath $(PREFIX))\")"
@echo " DESTDIR: Specify a directory where to store installed files (mainly for packaging purpose)"
.PHONY: help

View File

@ -1,506 +0,0 @@
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.65])
AC_INIT([toxic], [0.4.1], [https://tox.im/])
AC_CONFIG_AUX_DIR(configure_aux)
AC_CONFIG_SRCDIR([src/toxic.c])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([1.10 -Wall])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AC_CONFIG_MACRO_DIR([m4])
if test "x${prefix}" = "xNONE"; then
prefix="${ac_default_prefix}"
fi
DEPSEARCH=
LIBTOXCORE_SEARCH_HEADERS=
LIBTOXCORE_SEARCH_LIBS=
LIBSODIUM_SEARCH_HEADERS=
LIBSODIUM_SEARCH_LIBS=
LIBTOXCORE_FOUND="no"
NCURSES_FOUND="no"
NCURSES_WIDECHAR_SUPPORT="no"
AC_ARG_WITH(dependency-search,
AC_HELP_STRING([--with-dependency-search=DIR],
[search for dependencies in DIR, i.e. look for libraries in
DIR/lib and for headers in DIR/include]),
[
DEPSEARCH="$withval"
]
)
if test -n "$DEPSEARCH"; then
CFLAGS="$CFLAGS -I$DEPSEARCH/include"
CPPFLAGS="$CPPFLAGS -I$DEPSEARCH/include"
LDFLAGS="$LDFLAGS -L$DEPSEARCH/lib"
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$DEPSEARCH/lib/pkgconfig:/usr/local/lib/pkgconfig
fi
AC_ARG_WITH(libtoxcore-headers,
AC_HELP_STRING([--with-libtoxcore-headers=DIR],
[search for libtoxcore header files in DIR/tox]),
[
LIBTOXCORE_SEARCH_HEADERS="$withval"
AC_MSG_NOTICE([Will search for libtoxcore header files in $withval])
]
)
AC_ARG_WITH(libtoxcore-libs,
AC_HELP_STRING([--with-libtoxcore-libs=DIR],
[search for libtoxcore libraries in DIR]),
[
LIBTOXCORE_SEARCH_LIBS="$withval"
AC_MSG_NOTICE([Will search for libtoxcore libraries in $withval])
]
)
AC_ARG_WITH(libsodium-headers,
AC_HELP_STRING([--with-libsodium-headers=DIR],
[search for libsodium header files in DIR]),
[
LIBSODIUM_SEARCH_HEADERS="$withval"
AC_MSG_NOTICE([Will search for libsodium header files in $withval])
]
)
AC_ARG_WITH(libsodium-libs,
AC_HELP_STRING([--with-libsodium-libs=DIR],
[search for libsodium libraries in DIR]),
[
LIBSODIUM_SEARCH_LIBS="$withval"
AC_MSG_NOTICE([Will search for libsodium libraries in $withval])
]
)
WIN32=no
MACH=no
AC_CANONICAL_HOST
case $host_os in
*mingw*)
WIN32="yes"
;;
darwin*)
MACH=yes
;;
*freebsd*)
LDFLAGS="$LDFLAGS -L/usr/local/lib"
CFLAGS="$CFLAGS -I/usr/local/include"
CPPFLAGS="$CPPFLAGS -I/usr/local/include"
;;
esac
# Checks for programs.
AC_PROG_CC
AM_PROG_CC_C_O
AC_CHECK_HEADERS(
[limits.h locale.h stdint.h stdlib.h string.h unistd.h wchar.h wctype.h],
[],
[ AC_MSG_ERROR([required header is missing on your system]) ])
# Checks for typedefs, structures, and compiler characteristics.
AC_HEADER_STDBOOL
AC_TYPE_SIZE_T
AC_TYPE_UINT16_T
AC_TYPE_UINT32_T
AC_TYPE_UINT64_T
AC_TYPE_UINT8_T
# Checks for library functions.
AC_FUNC_MALLOC
AC_CHECK_FUNCS(
[iswprint memmove memset mkdir setlocale strchr strdup],
[],
[ AC_MSG_ERROR([required library function is missing on your system])])
AX_PTHREAD( [], [ AC_MSG_ERROR([pthreads not found on your system]) ])
# pkg-config based tests
PKG_PROG_PKG_CONFIG
if test -n "$PKG_CONFIG"; then
if test "x$WIN32" != "xyes"; then
PKG_CHECK_MODULES([NCURSES], [ncursesw],
[
NCURSES_FOUND="yes"
NCURSES_WIDECHAR_SUPPORT="yes"
],
[
NCURSES_WIDECHAR_SUPPORT="no"
PKG_CHECK_MODULES([NCURSES], [ncurses],
[
NCURSES_FOUND="yes"
],
[
AC_MSG_WARN([$NCURSES_PKG_ERRORS])
])
])
fi
else
AC_MSG_WARN([pkg-config was not found on your sytem])
fi
if (test "x$NCURSES_FOUND" = "xno") && (test "x$WIN32" != "xyes"); then
AC_PATH_PROG([CURSES_CONFIG], [ncursesw5-config], [no])
if test "x$CURSES_CONFIG" != "xno"; then
AC_MSG_CHECKING(ncurses cflags)
NCURSES_CFLAGS=`${CURSES_CONFIG} --cflags`
AC_MSG_RESULT($NCURSES_CFLAGS)
AC_MSG_CHECKING(ncurses libraries)
NCURSES_LIBS=`${CURSES_CONFIG} --libs`
AC_MSG_RESULT($NCURSES_LIBS)
AC_SUBST(NCURSES_CFLAGS)
AC_SUBST(NCURSES_LIBS)
NCURSES_FOUND="yes"
NCURSES_WIDECHAR_SUPPORT="yes"
fi
fi
if (test "x$NCURSES_FOUND" = "xno") && (test "x$WIN32" != "xyes"); then
unset ac_cv_path_CURSES_CONFIG
AC_PATH_PROG([CURSES_CONFIG], [ncursesw5.4-config], [no])
if test "x$CURSES_CONFIG" != "xno"; then
AC_MSG_CHECKING(ncurses cflags)
NCURSES_CFLAGS=`${CURSES_CONFIG} --cflags`
AC_MSG_RESULT($NCURSES_CFLAGS)
AC_MSG_CHECKING(ncurses libraries)
NCURSES_LIBS=`${CURSES_CONFIG} --libs`
AC_MSG_RESULT($NCURSES_LIBS)
AC_SUBST(NCURSES_CFLAGS)
AC_SUBST(NCURSES_LIBS)
NCURSES_FOUND="yes"
NCURSES_WIDECHAR_SUPPORT="yes"
fi
fi
if (test "x$NCURSES_FOUND" = "xno") && (test "x$WIN32" != "xyes"); then
unset ac_cv_path_CURSES_CONFIG
AC_PATH_PROG([CURSES_CONFIG], [ncurses5-config], [no])
if test "x$CURSES_CONFIG" != "xno"; then
AC_MSG_CHECKING(ncurses cflags)
NCURSES_CFLAGS=`${CURSES_CONFIG} --cflags`
AC_MSG_RESULT($NCURSES_CFLAGS)
AC_MSG_CHECKING(ncurses libraries)
NCURSES_LIBS=`${CURSES_CONFIG} --libs`
AC_MSG_RESULT($NCURSES_LIBS)
AC_SUBST(NCURSES_CFLAGS)
AC_SUBST(NCURSES_LIBS)
NCURSES_FOUND="yes"
fi
fi
if (test "x$NCURSES_FOUND" = "xno") && (test "x$WIN32" != "xyes"); then
unset ac_cv_path_CURSES_CONFIG
AC_PATH_PROG([CURSES_CONFIG], [ncurses5.4-config], [no])
if test "x$CURSES_CONFIG" != "xno"; then
AC_MSG_CHECKING(ncurses cflags)
NCURSES_CFLAGS=`${CURSES_CONFIG} --cflags`
AC_MSG_RESULT($NCURSES_CFLAGS)
AC_MSG_CHECKING(ncurses libraries)
NCURSES_LIBS=`${CURSES_CONFIG} --libs`
AC_MSG_RESULT($NCURSES_LIBS)
AC_SUBST(NCURSES_CFLAGS)
AC_SUBST(NCURSES_LIBS)
NCURSES_FOUND="yes"
fi
fi
if test "x$NCURSES_FOUND" = "xno"; then
AC_CHECK_HEADER([curses.h],
[],
[
AC_MSG_ERROR([headers for the ncurses library were not found on your system])
]
)
if test "x$WIN32" = "xyes"; then
dnl Check if pdcurses provides wide char support
NCURSES_WIDECHAR_SUPPORT="no"
AC_CHECK_LIB([pdcurses], [clear],
[],
[
AC_MSG_ERROR([required library pdcurses was not found on your system])
]
)
AC_CHECK_LIB(ws2_32, main,
[
WINSOCK2_LIBS="-lws2_32"
AC_SUBST(WINSOCK2_LIBS)
],
[
AC_MSG_ERROR([required library winsock2 was not found on the system, please check your MinGW installation])
]
)
AC_DEFINE([_WIN32_WINNT], [0x501],
[enable getaddrinfo/freeaddrinfo on XP and higher])
else
AC_CHECK_LIB([ncursesw], [wget_wch],
[
NCURSES_WIDECHAR_SUPPORT="yes"
],
[
unset ac_cv_lib_ncursesw_wget_wch
AC_CHECK_LIB([ncursesw], [wget_wch],
[
NCURSES_WIDECHAR_SUPPORT="yes"
],
[
NCURSES_WIDECHAR_SUPPORT="no"
AC_CHECK_LIB([ncurses], [clear],
[],
[
unset ac_cv_lib_ncurses_clear
AC_CHECK_LIB([ncurses], [clear],
[],
[
AC_MSG_ERROR([required library ncurses was not found on your system])
],
[
-ltinfo
]
)
]
)
],
[
-ltinfo
]
)
]
)
fi
fi
if test -n "$PKG_CONFIG"; then
PKG_CHECK_MODULES(LIBTOXCORE, [libtoxcore],
[
LIBTOXCORE_FOUND="yes"
],
[
AC_MSG_WARN([required library libsodium was not found in requested location $LIBSODIUM_SEARCH_LIBS])
])
fi
if test "x$LIBTOXCORE_FOUND" = "xno"; then
LIBSODIUM_LIBS=
LIBSODIUM_LDFLAGS=
LDFLAGS_SAVE="$LDFLAGS"
if test -n "$LIBSODIUM_SEARCH_LIBS"; then
LDFLAGS="$LDFLAGS -L$LIBSODIUM_SEARCH_LIBS"
AC_CHECK_LIB(sodium, randombytes_random,
[
LIBSODIUM_LDFLAGS="-L$LIBSODIUM_SEARCH_LIBS"
LIBSODIUM_LIBS="-lsodium"
],
[
AC_MSG_ERROR([required library libsodium was not found in requested location $LIBSODIUM_SEARCH_LIBS])
]
)
else
AC_CHECK_LIB(sodium, randombytes_random,
[],
[
AC_MSG_ERROR([required library libsodium was not found on your system, please check http://download.libsodium.org/libsodium/releases/])
]
)
fi
LDFLAGS="$LDFLAGS_SAVE"
AC_SUBST(LIBSODIUM_LIBS)
AC_SUBST(LIBSODIUM_LDFLAGS)
LIBTOXCORE_CFLAGS=
CFLAGS_SAVE="$CFLAGS"
CPPFLAGS_SAVE="$CPPFLAGS"
if test -n "$LIBTOXCORE_SEARCH_HEADERS"; then
CFLAGS="$CFLAGS -I$LIBTOXCORE_SEARCH_HEADERS"
CPPFLAGS="$CPPFLAGS -I$LIBTOXCORE_SEARCH_HEADERS"
AC_CHECK_HEADER([tox/tox.h],
[
LIBTOXCORE_CFLAGS="-I$LIBTOXCORE_SEARCH_HEADERS"
],
[
AC_MSG_ERROR([headers for the toxcore library were not found on your system])
]
)
else
AC_CHECK_HEADER([tox/tox.h],
[],
[
AC_MSG_ERROR([headers for the toxcore library were not found on your system])
],
)
fi
CFLAGS="$CFLAGS_SAVE"
CPPFLAGS="$CPPFLAGS_SAVE"
AC_SUBST(LIBTOXCORE_CFLAGS)
LIBTOXCORE_LIBS=
LIBTOXCORE_LDFLAGS=
LDFLAGS_SAVE="$LDFLAGS"
if test -n "$LIBTOXCORE_SEARCH_LIBS"; then
LDFLAGS="$LDFLAGS $LIBSODIUM_LDFLAGS -L$LIBTOXCORE_SEARCH_LIBS"
AC_CHECK_LIB([toxcore], [tox_new],
[
LIBTOXCORE_LDFLAGS="-L$LIBTOXCORE_SEARCH_LIBS"
LIBTOXCORE_LIBS="-ltoxcore"
],
[
AC_MSG_ERROR([required library toxcore was not found on your system])
],
[
$WINSOCK2_LIBS
$LIBSODIUM_LIBS
]
)
else
LDFLAGS="$LDFLAGS $LIBSODIUM_LDFLAGS"
AC_CHECK_LIB([toxcore], [tox_new],
[],
[
AC_MSG_ERROR([required library toxcore was not found on your system])
],
[
$WINSOCK2_LIBS
$LIBSODIUM_LIBS
]
)
fi
LDFLAGS="$LDFLAGS_SAVE"
AC_SUBST(LIBTOXCORE_LIBS)
AC_SUBST(LIBTOXCORE_LDFLAGS)
fi
AC_CHECK_HEADER([resolv.h], [],
[
AC_MSG_ERROR([resolv.h header was not found on your system])
])
AC_CHECK_LIB(resolv, __res_init, [],
[
AC_MSG_ERROR([libresolv library was not found on your system])
])
####
#### A/V Stuff
AV_SEARCH_DIR=
BUILD_AV="yes"
AC_ARG_WITH(libtoxav-prefix,
AC_HELP_STRING([--with-libtoxav-prefix=DIR],
[search for libtoxav in DIR, i.e. look for libraries in
DIR/lib and for headers in DIR/include]),
[
AV_SEARCH_DIR="$withval"
]
)
if test -n "$AV_SEARCH_DIR"; then
CFLAGS="$CFLAGS -I$AV_SEARCH_DIR/include"
CPPFLAGS="$CPPFLAGS -I$AV_SEARCH_DIR/include"
LDFLAGS="$LDFLAGS -L$AV_SEARCH_DIR/lib"
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$AV_SEARCH_DIR/lib/pkgconfig
fi
# Check if specified enable
AC_ARG_ENABLE([av],
[AC_HELP_STRING([--disable-av], [build AV support libraries (default: auto)]) ],
[
if test "x$enableval" = "xno"; then
BUILD_AV="no"
elif test "x$enableval" = "xyes"; then
BUILD_AV="yes"
fi
]
)
# Check for A/V library
if test "x$BUILD_AV" = "xyes"; then
PKG_CHECK_MODULES([OPENAL], [openal],
[],
[
if test "x$MACH" = "xyes"; then
CFLAGS="$CFLAGS -framework OpenAL"
AC_CHECK_HEADER([OpenAL/al.h],
[
OPENAL_CFLAGS="-framework OpenAL"
OPENAL_LIBS="-framework OpenAL"
AC_SUBST(OPENAL_CFLAGS)
AC_SUBST(OPENAL_LIBS)
],
[
AC_MSG_NOTICE([No openal framework; disabling A/V support])
BUILD_AV="no"
]
)
CFLAGS="$CFLAGS_SAVE"
else
AC_MSG_NOTICE([No openal library; disabling A/V support])
BUILD_AV="no"
fi
])
fi
if test "x$BUILD_AV" = "xyes"; then
PKG_CHECK_MODULES([LIBTOXAV], [libtoxav],
[
AC_CHECK_HEADER([tox/toxav.h],
[
# Place define for audio support
AC_DEFINE([_SUPPORT_AUDIO], [], [Is audio supported])
AC_MSG_NOTICE([Building with audio support])
],
[
AC_MSG_NOTICE([No A/V headers; disabling A/V support])
BUILD_AV="no"
],)
],
[
AC_MSG_NOTICE([No A/V library; disabling A/V support])
BUILD_AV="no"
])
fi
AM_CONDITIONAL(BUILD_AV, test "x$BUILD_AV" = "xyes")
TOXIC_VERSION="$PACKAGE_VERSION"
AC_PATH_PROG([GIT], [git], [no])
if test "x$GIT" != "xno"; then
if test -d ${srcdir}/.git; then
TOXIC_VERSION="${TOXIC_VERSION}_r`${GIT} rev-list HEAD --count`"
fi
fi
AC_SUBST(TOXIC_VERSION)
eval PACKAGE_DATADIR="${datadir}/${PACKAGE}"
eval PACKAGE_DATADIR="${PACKAGE_DATADIR}"
AC_DEFINE_UNQUOTED(PACKAGE_DATADIR, "$PACKAGE_DATADIR", [toxic data directory])
if test "x$NCURSES_WIDECHAR_SUPPORT" = "xyes"; then
AC_DEFINE([HAVE_WIDECHAR], [1], [ncurses wide char support available])
AC_DEFINE([_XOPEN_SOURCE_EXTENDED], [1],
[enable X/Open Portability Guide functionality])
fi
AC_CONFIG_FILES([Makefile
misc/Makefile
build/Makefile])
AC_OUTPUT

63
doc/toxic.1 Normal file
View File

@ -0,0 +1,63 @@
.TH TOXIC 1 "June 2014" "Toxic v__VERSION__" "User Manual"
.SH NAME
Toxic \- CLI client for Tox
.SH SYNOPSYS
.B toxic [\-f
.I data\-file
.B ] [\-x] [\-4] [\-c
.I config\-file
.B ] [\-n
.I nodes\-file
.B ] [\-h]
.SH DESCRIPTION
Toxic is an ncurses-based instant messaging client for Tox which formerly
resided in the Tox core repository, and is now available as a standalone
application.
.SH OPTIONS
.IP "\-f, \-\-file data\-file"
Use specified
.I data\-file
instead of
.IR ~/.config/tox/data
.IP "\-x, \-\-nodata"
Ignore data file
.IP "\-4, \-\-ipv4"
Force IPv4 connection
.IP "\-d, \-\-default_locale
Use default locale
.IP "\-c, \-\-config config\-file"
Use specified
.I config\-file
instead of
.IR ~/.config/tox/toxic.conf
.IP "\-n, \-\-nodes nodes\-file"
Use specified
.I nodes\-file
for DHT bootstrap nodes, instead of
.IR __DATADIR__/DHTnodes
.IP "\-h, \-\-help"
Show help message
.SH FILES
.IP __DATADIR__/DHTnodes
Default list of DHT bootstrap nodes.
.IP ~/.config/tox/data
Savestate which contains your personal info (nickname, Tox ID,...) and
your contacts list.
.IP ~/.config/tox/toxic.conf
Configuration file. See
.BR toxic.conf (5)
for more details.
.IP __DATADIR__/toxic.conf.example
Configuration example.
.SH BUGS
Unicode characters with a width larger than 1 column may cause
strange behaviour. Expect more bugs and bad
behaviour: this software is in a pre\-alpha stage.
.SH AUTHORS
JFreegman <JFreegman@gmail.com>
.SH SEE ALSO
.BR toxic.conf (5)
.SH LINKS
Project page on github: https://github.com/Tox/toxic
.br
IRC channel on Freenode: chat.freenode.net#tox

111
doc/toxic.conf.5 Normal file
View File

@ -0,0 +1,111 @@
.TH TOXIC.CONF 5 "June 2014" "Toxic v__VERSION__" "User Manual"
.SH NAME
toxic.conf \- Configuration file for toxic(1)
.SH DESCRIPTION
The
.I toxic.conf
file is the main configuration file for
.BR toxic (1)
client.
.SH SYNTAX
.IB <KEY> : <VALUE> ;
.PP
Lines starting with "#" are comments and will be ignored.
.PP
Keys:
.PP
.B time
.RS
Select between 24 and 12 hour time.
.br
Values: 24, 12
.RE
.PP
.B timestamps
.RS
Enable or disable timestamps.
.br
Values: 1 to enable, 0 to disable
.RE
.PP
.B autolog
.RS
Enable or disable autologging.
.br
Values: 1 to enable, 0 to disable
.RE
.PP
.B alerts
.RS
Enable or disable terminal alerts on events.
.br
Values: 1 to enable, 0 to disable
.RE
.PP
.B history_size
.RS
Maximum lines for chat window history.
.br
Values: <INTEGER> (for example: 700)
.RE
.PP
.B colour_theme
.RS
Select between toxic colour theme and native terminal colours.
.br
Values: 0 for toxic colours, 1 for terminal colours
.RE
.PP
.B audio_in_dev
.RS
Audio input device.
.br
Values: <INTEGER> (number correspond to "/lsdev in")
.RE
.PP
.B audio_out_dev
.RS
Audio output device.
.br
Values: <INTEGER> (number correspond to "/lsdev out")
.RE
.PP
.B download_path
.RS
Default path for downloads.
.br
Values: <STRING> (absolute path where to store downloaded files)
.RE
.SH EXAMPLES
Default settings from __DATADIR__/toxic.conf.exmaple:
.PP
time:24;
.br
timestamps:1;
.br
autolog:0;
.br
alerts:1;
.br
history_size:700;
.br
colour_theme:0;
.br
audio_in_dev:0;
.br
audio_out_dev:0;
.br
download_path:/home/USERNAME/Downloads/;
.SH FILES
.IP ~/.config/tox/toxic.conf
Main configuration file.
.IP __DATADIR__/toxic.conf.example
Configuration example.
.SH AUTHORS
JFreegman <JFreegman@gmail.com>
.SH SEE ALSO
.BR toxic (1)
.SH LINKS
Project page on github: https://github.com/Tox/toxic
.br
IRC channel on Freenode: chat.freenode.net#tox

View File

@ -1,52 +0,0 @@
--- /src/misc_tools.c
+++ /src/misc_tools.c
@@ -54,24 +54,11 @@
return val;
}
-/* Get the current local time */
-struct tm *get_time(void)
-{
- struct tm *timeinfo;
- time_t now;
- time(&now);
- timeinfo = localtime(&now);
- return timeinfo;
-}
-
/* Prints the time to given window */
void print_time(WINDOW *window)
{
- uint8_t s[MAX_STR_SIZE];
- strftime(s, MAX_STR_SIZE, "[%H:%M:%S] ", get_time());
-
wattron(window, COLOR_PAIR(BLUE));
- wprintw(window, "%s", s);
+ wprintw(window, "[%d] ", (int)time(NULL));
wattroff(window,COLOR_PAIR(BLUE));
}
--- /src/log.c
+++ /src/log.c
@@ -51,9 +51,7 @@
sprintf(&ident[2], "%02X", key[2] & 0xff);
ident[KEY_IDENT_DIGITS*2+1] = '\0';
} else {
- uint8_t s[MAX_STR_SIZE];
- strftime(s, MAX_STR_SIZE, "%Y-%m-%d[%H:%M:%S]", get_time());
- snprintf(ident, sizeof(ident), "%s", s);
+ snprintf(ident, sizeof(ident), "[%d]", (int)time(NULL));
path_len += strlen(ident) + 1;
}
@@ -95,9 +93,7 @@
else
snprintf(name_frmt, sizeof(name_frmt), "%s:", name);
- uint8_t s[MAX_STR_SIZE];
- strftime(s, MAX_STR_SIZE, "%Y/%m/%d [%H:%M:%S]", get_time());
- fprintf(log->file,"%s %s %s\n", s, name_frmt, msg);
+ fprintf(log->file,"[%d]\n", (int)time(NULL), name_frmt, msg);
uint64_t curtime = (uint64_t) time(NULL);

View File

@ -1,317 +0,0 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_pthread.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
#
# DESCRIPTION
#
# This macro figures out how to build C programs using POSIX threads. It
# sets the PTHREAD_LIBS output variable to the threads library and linker
# flags, and the PTHREAD_CFLAGS output variable to any special C compiler
# flags that are needed. (The user can also force certain compiler
# flags/libs to be tested by setting these environment variables.)
#
# Also sets PTHREAD_CC to any special C compiler that is needed for
# multi-threaded programs (defaults to the value of CC otherwise). (This
# is necessary on AIX to use the special cc_r compiler alias.)
#
# NOTE: You are assumed to not only compile your program with these flags,
# but also link it with them as well. e.g. you should link with
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
#
# If you are only building threads programs, you may wish to use these
# variables in your default LIBS, CFLAGS, and CC:
#
# LIBS="$PTHREAD_LIBS $LIBS"
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# CC="$PTHREAD_CC"
#
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
# (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
#
# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
# PTHREAD_PRIO_INHERIT symbol is defined when compiling with
# PTHREAD_CFLAGS.
#
# ACTION-IF-FOUND is a list of shell commands to run if a threads library
# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
# is not found. If ACTION-IF-FOUND is not specified, the default action
# will define HAVE_PTHREAD.
#
# Please let the authors know if this macro fails on any platform, or if
# you have any other suggestions or comments. This macro was based on work
# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
# Alejandro Forero Cuervo to the autoconf macro repository. We are also
# grateful for the helpful feedback of numerous users.
#
# Updated for Autoconf 2.68 by Daniel Richard G.
#
# LICENSE
#
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
# Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG>
#
# This program 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.
#
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 20
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
AC_DEFUN([AX_PTHREAD], [
AC_REQUIRE([AC_CANONICAL_HOST])
AC_LANG_PUSH([C])
ax_pthread_ok=no
# We used to check for pthread.h first, but this fails if pthread.h
# requires special compiler flags (e.g. on True64 or Sequent).
# It gets checked for in the link test anyway.
# First of all, check if the user has set any of the PTHREAD_LIBS,
# etcetera environment variables, and if threads linking works using
# them:
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes)
AC_MSG_RESULT($ax_pthread_ok)
if test x"$ax_pthread_ok" = xno; then
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
fi
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
fi
# We must check for the threads library under a number of different
# names; the ordering is very important because some systems
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
# libraries is broken (non-POSIX).
# Create a list of thread flags to try. Items starting with a "-" are
# C compiler flags, and other items are library names, except for "none"
# which indicates that we try without any flags at all, and "pthread-config"
# which is a program returning the flags for the Pth emulation library.
ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
# The ordering *is* (sometimes) important. Some notes on the
# individual items follow:
# pthreads: AIX (must check this before -lpthread)
# none: in case threads are in libc; should be tried before -Kthread and
# other compiler flags to prevent continual compiler warnings
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
# -pthreads: Solaris/gcc
# -mthreads: Mingw32/gcc, Lynx/gcc
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
# doesn't hurt to check since this sometimes defines pthreads too;
# also defines -D_REENTRANT)
# ... -mt is also the pthreads flag for HP/aCC
# pthread: Linux, etcetera
# --thread-safe: KAI C++
# pthread-config: use pthread-config program (for GNU Pth library)
case ${host_os} in
solaris*)
# On Solaris (at least, for some versions), libc contains stubbed
# (non-functional) versions of the pthreads routines, so link-based
# tests will erroneously succeed. (We need to link with -pthreads/-mt/
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
# a function called by this macro, so we could check for that, but
# who knows whether they'll stub that too in a future libc.) So,
# we'll just look for -pthreads and -lpthread first:
ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
;;
darwin*)
ax_pthread_flags="-pthread $ax_pthread_flags"
;;
esac
if test x"$ax_pthread_ok" = xno; then
for flag in $ax_pthread_flags; do
case $flag in
none)
AC_MSG_CHECKING([whether pthreads work without any flags])
;;
-*)
AC_MSG_CHECKING([whether pthreads work with $flag])
PTHREAD_CFLAGS="$flag"
;;
pthread-config)
AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no)
if test x"$ax_pthread_config" = xno; then continue; fi
PTHREAD_CFLAGS="`pthread-config --cflags`"
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
;;
*)
AC_MSG_CHECKING([for the pthreads library -l$flag])
PTHREAD_LIBS="-l$flag"
;;
esac
save_LIBS="$LIBS"
save_CFLAGS="$CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Check for various functions. We must include pthread.h,
# since some functions may be macros. (On the Sequent, we
# need a special flag -Kthread to make this header compile.)
# We check for pthread_join because it is in -lpthread on IRIX
# while pthread_create is in libc. We check for pthread_attr_init
# due to DEC craziness with -lpthreads. We check for
# pthread_cleanup_push because it is one of the few pthread
# functions on Solaris that doesn't have a non-functional libc stub.
# We try pthread_create on general principles.
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
static void routine(void *a) { a = 0; }
static void *start_routine(void *a) { return a; }],
[pthread_t th; pthread_attr_t attr;
pthread_create(&th, 0, start_routine, 0);
pthread_join(th, 0);
pthread_attr_init(&attr);
pthread_cleanup_push(routine, 0);
pthread_cleanup_pop(0) /* ; */])],
[ax_pthread_ok=yes],
[])
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
AC_MSG_RESULT($ax_pthread_ok)
if test "x$ax_pthread_ok" = xyes; then
break;
fi
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
done
fi
# Various other checks:
if test "x$ax_pthread_ok" = xyes; then
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
AC_MSG_CHECKING([for joinable pthread attribute])
attr_name=unknown
for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
[int attr = $attr; return attr /* ; */])],
[attr_name=$attr; break],
[])
done
AC_MSG_RESULT($attr_name)
if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
[Define to necessary symbol if this constant
uses a non-standard name on your system.])
fi
AC_MSG_CHECKING([if more special flags are required for pthreads])
flag=no
case ${host_os} in
aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";;
osf* | hpux*) flag="-D_REENTRANT";;
solaris*)
if test "$GCC" = "yes"; then
flag="-D_REENTRANT"
else
flag="-mt -D_REENTRANT"
fi
;;
esac
AC_MSG_RESULT(${flag})
if test "x$flag" != xno; then
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
fi
AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
ax_cv_PTHREAD_PRIO_INHERIT, [
AC_LINK_IFELSE([
AC_LANG_PROGRAM([[#include <pthread.h>]], [[int i = PTHREAD_PRIO_INHERIT;]])],
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
[ax_cv_PTHREAD_PRIO_INHERIT=no])
])
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.]))
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
# More AIX lossage: compile with *_r variant
if test "x$GCC" != xyes; then
case $host_os in
aix*)
AS_CASE(["x/$CC"],
[x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
[#handle absolute path differently from PATH based program lookup
AS_CASE(["x$CC"],
[x/*],
[AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
[AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
;;
esac
fi
fi
test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
AC_SUBST(PTHREAD_LIBS)
AC_SUBST(PTHREAD_CFLAGS)
AC_SUBST(PTHREAD_CC)
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
if test x"$ax_pthread_ok" = xyes; then
ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
:
else
ax_pthread_ok=no
$2
fi
AC_LANG_POP
])dnl AX_PTHREAD

199
m4/pkg.m4
View File

@ -1,199 +0,0 @@
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
# serial 1 (pkg-config-0.24)
#
# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
#
# This program 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 2 of the License, or
# (at your option) any later version.
#
# This program 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 this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# PKG_PROG_PKG_CONFIG([MIN-VERSION])
# ----------------------------------
AC_DEFUN([PKG_PROG_PKG_CONFIG],
[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
fi
if test -n "$PKG_CONFIG"; then
_pkg_min_version=m4_default([$1], [0.9.0])
AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
PKG_CONFIG=""
fi
fi[]dnl
])# PKG_PROG_PKG_CONFIG
# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
#
# Check to see whether a particular set of modules exists. Similar
# to PKG_CHECK_MODULES(), but does not set variables or print errors.
#
# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
# only at the first occurence in configure.ac, so if the first place
# it's called might be skipped (such as if it is within an "if", you
# have to call PKG_CHECK_EXISTS manually
# --------------------------------------------------------------
AC_DEFUN([PKG_CHECK_EXISTS],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
if test -n "$PKG_CONFIG" && \
AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
m4_default([$2], [:])
m4_ifvaln([$3], [else
$3])dnl
fi])
# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
# ---------------------------------------------
m4_define([_PKG_CONFIG],
[if test -n "$$1"; then
pkg_cv_[]$1="$$1"
elif test -n "$PKG_CONFIG"; then
PKG_CHECK_EXISTS([$3],
[pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes ],
[pkg_failed=yes])
else
pkg_failed=untried
fi[]dnl
])# _PKG_CONFIG
# _PKG_SHORT_ERRORS_SUPPORTED
# -----------------------------
AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
else
_pkg_short_errors_supported=no
fi[]dnl
])# _PKG_SHORT_ERRORS_SUPPORTED
# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
# [ACTION-IF-NOT-FOUND])
#
#
# Note that if there is a possibility the first call to
# PKG_CHECK_MODULES might not happen, you should be sure to include an
# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
#
#
# --------------------------------------------------------------
AC_DEFUN([PKG_CHECK_MODULES],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
pkg_failed=no
AC_MSG_CHECKING([for $1])
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
and $1[]_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details.])
if test $pkg_failed = yes; then
AC_MSG_RESULT([no])
_PKG_SHORT_ERRORS_SUPPORTED
if test $_pkg_short_errors_supported = yes; then
$1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
else
$1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
m4_default([$4], [AC_MSG_ERROR(
[Package requirements ($2) were not met:
$$1_PKG_ERRORS
Consider adjusting the PKG_CONFIG_PATH environment variable if you
installed software in a non-standard prefix.
_PKG_TEXT])[]dnl
])
elif test $pkg_failed = untried; then
AC_MSG_RESULT([no])
m4_default([$4], [AC_MSG_FAILURE(
[The pkg-config script could not be found or is too old. Make sure it
is in your PATH or set the PKG_CONFIG environment variable to the full
path to pkg-config.
_PKG_TEXT
To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
])
else
$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
$1[]_LIBS=$pkg_cv_[]$1[]_LIBS
AC_MSG_RESULT([yes])
$3
fi[]dnl
])# PKG_CHECK_MODULES
# PKG_INSTALLDIR(DIRECTORY)
# -------------------------
# Substitutes the variable pkgconfigdir as the location where a module
# should install pkg-config .pc files. By default the directory is
# $libdir/pkgconfig, but the default can be changed by passing
# DIRECTORY. The user can override through the --with-pkgconfigdir
# parameter.
AC_DEFUN([PKG_INSTALLDIR],
[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
m4_pushdef([pkg_description],
[pkg-config installation directory @<:@]pkg_default[@:>@])
AC_ARG_WITH([pkgconfigdir],
[AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
[with_pkgconfigdir=]pkg_default)
AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
m4_popdef([pkg_default])
m4_popdef([pkg_description])
]) dnl PKG_INSTALLDIR
# PKG_NOARCH_INSTALLDIR(DIRECTORY)
# -------------------------
# Substitutes the variable noarch_pkgconfigdir as the location where a
# module should install arch-independent pkg-config .pc files. By
# default the directory is $datadir/pkgconfig, but the default can be
# changed by passing DIRECTORY. The user can override through the
# --with-noarch-pkgconfigdir parameter.
AC_DEFUN([PKG_NOARCH_INSTALLDIR],
[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
m4_pushdef([pkg_description],
[pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
AC_ARG_WITH([noarch-pkgconfigdir],
[AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
[with_noarch_pkgconfigdir=]pkg_default)
AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
m4_popdef([pkg_default])
m4_popdef([pkg_description])
]) dnl PKG_NOARCH_INSTALLDIR

View File

@ -1 +0,0 @@
dist_pkgdata_DATA = DHTnodes

View File

@ -1,11 +1,14 @@
# 24 or 12 hour time
time:24;
# 1 to enable timestamps, 0 to disable
timestamps:1;
# 1 to enable autologging, 0 to disable
autolog:0;
# 1 to disbale terminal alerts on messages, 0 to enable
disable_alerts:0;
alerts:1;
# maximum lines for chat window history
history_size:700;

View File

@ -20,13 +20,10 @@
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "toxic.h"
#include "windows.h"
#include "audio_call.h"
#include "device.h"
#include "chat_commands.h"
#include "global_commands.h"
#include "line_info.h"
@ -48,31 +45,34 @@
#define _cbend pthread_exit(NULL)
#define AUDIO_FRAME_SIZE (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000)
#define MAX_CALLS 10
#define _True 1
#define _False 0
typedef struct _DeviceIx {
ALCdevice *dhndl; /* Handle of device selected/opened */
ALCcontext *ctx; /* Device context */
const char *devices[MAX_DEVICES]; /* Container of available devices */
int size; /* Size of above container */
int dix; /* Index of default device */
int index; /* Current index */
} DeviceIx;
#define frame_size (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000)
typedef struct _Call {
pthread_t ttid; /* Transmission thread id */
_Bool ttas; /* Transmission thread active status (0 - stopped, 1- running) */
_Bool ttas, has_output; /* Transmission thread active status (0 - stopped, 1- running) */
uint32_t in_idx, out_idx;
pthread_mutex_t mutex;
} Call;
struct _ASettings {
DeviceIx device[2];
void set_call(Call* call, _Bool start)
{
call->in_idx = -1;
call->out_idx = -1;
if ( start ) {
call->ttas = _True;
pthread_mutex_init(&call->mutex, NULL);
}
else {
call->ttid = 0;
pthread_mutex_destroy(&call->mutex);
}
}
struct _ASettings {
AudioError errors;
ToxAv *av;
@ -82,246 +82,66 @@ struct _ASettings {
Call calls[MAX_CALLS];
} ASettins;
void callback_recv_invite ( int32_t call_index, void *arg );
void callback_recv_ringing ( int32_t call_index, void *arg );
void callback_recv_invite ( int32_t call_index, void *arg );
void callback_recv_ringing ( int32_t call_index, void *arg );
void callback_recv_starting ( int32_t call_index, void *arg );
void callback_recv_ending ( int32_t call_index, void *arg );
void callback_recv_error ( int32_t call_index, void *arg );
void callback_call_started ( int32_t call_index, void *arg );
void callback_recv_ending ( int32_t call_index, void *arg );
void callback_recv_error ( int32_t call_index, void *arg );
void callback_call_started ( int32_t call_index, void *arg );
void callback_call_canceled ( int32_t call_index, void *arg );
void callback_call_rejected ( int32_t call_index, void *arg );
void callback_call_ended ( int32_t call_index, void *arg );
void callback_requ_timeout ( int32_t call_index, void *arg );
void callback_peer_timeout ( int32_t call_index, void *arg );
void callback_call_ended ( int32_t call_index, void *arg );
void callback_requ_timeout ( int32_t call_index, void *arg );
void callback_peer_timeout ( int32_t call_index, void *arg );
int stop_transmission(int call_index);
void write_device_callback(ToxAv* av, int32_t call_index, int16_t* data, int size);
static void print_err (ToxWindow *self, uint8_t *error_str)
static void print_err (ToxWindow *self, char *error_str)
{
line_info_add(self, NULL, NULL, NULL, error_str, SYS_MSG, 0, 0);
}
/* Opens device under current index
*/
int device_open (ToxWindow *self, _Devices type)
{
WINDOW *window = self->chatwin->history;
/* Do not error if no device */
if ( !ASettins.device[type].size ) return 0;
ALCdevice *prev_device = ASettins.device[type].dhndl;
uint8_t msg[MAX_STR_SIZE];
uint8_t *error = NULL;
if ( type == input ) {
ASettins.device[type].dhndl = alcCaptureOpenDevice(
ASettins.device[type].devices[ASettins.device[type].index],
av_DefaultSettings.audio_sample_rate,
AL_FORMAT_MONO16,
AUDIO_FRAME_SIZE * 4);
if (alcGetError(ASettins.device[type].dhndl) != AL_NO_ERROR) {
/* Now check if we have previous device and act acording to it */
if ( !prev_device ) {
error = "Error starting input device!";
ASettins.errors |= ErrorStartingCaptureDevice;
} else {
error = "Could not start input device, falling back to previous";
/* NOTE: What if device is opened? */
ASettins.device[type].dhndl = prev_device;
}
} else {
/* Close previous */
if ( prev_device )
alcCaptureCloseDevice(prev_device);
if ( window ) {
snprintf(msg, sizeof(msg), "Input device: %s", ASettins.device[type].devices[ASettins.device[type].index]);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
}
}
ASettins.device[type].ctx = NULL;
} else {
ASettins.device[type].dhndl = alcOpenDevice(ASettins.device[type].devices[ASettins.device[type].index]);
if (alcGetError(ASettins.device[type].dhndl) != AL_NO_ERROR) {
/* Now check if we have previous device and act acording to it */
if ( !prev_device ) {
error = "Error starting output device!";
ASettins.errors |= ErrorStartingOutputDevice;
ASettins.device[type].ctx = NULL;
} else {
error = "Could not start output device, falling back to previous";
/* NOTE: What if device is opened? */
ASettins.device[type].dhndl = prev_device;
}
} else {
/* Close previous */
if ( prev_device ) {
alcCaptureCloseDevice(prev_device);
alcMakeContextCurrent(NULL);
alcDestroyContext(ASettins.device[type].ctx);
}
ASettins.device[type].ctx = alcCreateContext(ASettins.device[type].dhndl, NULL);
if ( window ) {
snprintf(msg, sizeof(msg), "Output device: %s", ASettins.device[type].devices[ASettins.device[type].index]);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
}
}
}
if ( error ) {
if ( window ) {
snprintf(msg, sizeof(msg), "Error: %s", error);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
}
return -1;
} else return 0;
}
int device_close (ToxWindow *self, _Devices type)
{
/* Only close if device opened */
if ( ASettins.device[type].dhndl ) {
uint8_t *device = NULL;
if (type == input) {
alcCaptureCloseDevice(ASettins.device[type].dhndl);
device = "input";
} else {
alcCloseDevice(ASettins.device[type].dhndl);
alcMakeContextCurrent(NULL);
if ( ASettins.device[type].ctx )
alcDestroyContext(ASettins.device[type].ctx);
device = "output";
}
ASettins.device[type].index = ASettins.device[type].dix;
if ( device == NULL ) {
return -1;
}
if ( self ) {
uint8_t msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "Closed %s device", device);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
}
}
return 0;
}
int device_set(ToxWindow *self, _Devices type, long int selection)
{
uint8_t str[MAX_STR_SIZE];
uint8_t *s_type = type == input ? "input" : "output";
if ( selection < 0 || selection >= ASettins.device[type].size ) {
snprintf(str, sizeof(str), "Cannot set audio %s device: Invalid index: %ld", s_type, selection);
line_info_add(self, NULL, NULL, NULL, str, SYS_MSG, 0, 0);
return -1;
}
ASettins.device[type].index = selection;
if ( device_open(self, type) != 0 ) {
snprintf(str, sizeof(str), "Cannot open audio %s device index: %ld", s_type, selection);
line_info_add(self, NULL, NULL, NULL, str, SYS_MSG, 0, 0);
return -1;
}
return 0;
}
ToxAv *init_audio(ToxWindow *self, Tox *tox)
{
ASettins.cs = av_DefaultSettings;
ASettins.cs.video_height = ASettins.cs.video_width = 0;
ASettins.cs.max_video_height = ASettins.cs.max_video_width = 0;
ASettins.errors = NoError;
ASettins.errors = ae_None;
memset(ASettins.calls, 0, sizeof(Call) * 10);
/* Capture devices */
const char *stringed_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
ASettins.device[input].size = 0;
/* Streaming stuff from core */
if ( stringed_device_list ) {
const char *default_device = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
ASettins.av = toxav_new(tox, MAX_CALLS);
for ( ; *stringed_device_list; ++ASettins.device[input].size ) {
ASettins.device[input].devices[ASettins.device[input].size] = stringed_device_list;
if ( strcmp( default_device , ASettins.device[input].devices[ASettins.device[input].size] ) == 0 )
ASettins.device[input].index = ASettins.device[input].dix = ASettins.device[input].size;
stringed_device_list += strlen( stringed_device_list ) + 1;
}
if ( !ASettins.av ) {
ASettins.errors |= ae_StartingCoreAudio;
return NULL;
}
if ( init_devices(ASettins.av) == de_InternalError ) {
line_info_add(self, NULL, NULL, NULL, "Failed to init devices", SYS_MSG, 0, 0);
toxav_kill(ASettins.av);
return ASettins.av = NULL;
}
toxav_register_callstate_callback(callback_call_started, av_OnStart, self);
toxav_register_callstate_callback(callback_call_canceled, av_OnCancel, self);
toxav_register_callstate_callback(callback_call_rejected, av_OnReject, self);
toxav_register_callstate_callback(callback_call_ended, av_OnEnd, self);
toxav_register_callstate_callback(callback_recv_invite, av_OnInvite, self);
/* Output devices */
stringed_device_list = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
ASettins.device[output].size = 0;
toxav_register_callstate_callback(callback_recv_ringing, av_OnRinging, self);
toxav_register_callstate_callback(callback_recv_starting, av_OnStarting, self);
toxav_register_callstate_callback(callback_recv_ending, av_OnEnding, self);
if ( stringed_device_list ) {
const char *default_device = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
for ( ; *stringed_device_list; ++ASettins.device[output].size ) {
ASettins.device[output].devices[ASettins.device[output].size] = stringed_device_list;
if ( strcmp( default_device , ASettins.device[output].devices[ASettins.device[output].size] ) == 0 )
ASettins.device[output].index = ASettins.device[output].dix = ASettins.device[output].size;
stringed_device_list += strlen( stringed_device_list ) + 1;
}
}
if (!ASettins.device[input].size && !ASettins.device[output].size) {
uint8_t *msg = "No devices: disabling audio!";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
ASettins.av = NULL;
} else {
/* Streaming stuff from core */
ASettins.av = toxav_new(tox, MAX_CALLS);
if ( !ASettins.av ) {
ASettins.errors |= ErrorStartingCoreAudio;
return NULL;
}
toxav_register_callstate_callback(callback_call_started, av_OnStart, self);
toxav_register_callstate_callback(callback_call_canceled, av_OnCancel, self);
toxav_register_callstate_callback(callback_call_rejected, av_OnReject, self);
toxav_register_callstate_callback(callback_call_ended, av_OnEnd, self);
toxav_register_callstate_callback(callback_recv_invite, av_OnInvite, self);
toxav_register_callstate_callback(callback_recv_ringing, av_OnRinging, self);
toxav_register_callstate_callback(callback_recv_starting, av_OnStarting, self);
toxav_register_callstate_callback(callback_recv_ending, av_OnEnding, self);
toxav_register_callstate_callback(callback_recv_error, av_OnError, self);
toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout, self);
toxav_register_callstate_callback(callback_peer_timeout, av_OnPeerTimeout, self);
}
toxav_register_callstate_callback(callback_recv_error, av_OnError, self);
toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout, self);
toxav_register_callstate_callback(callback_peer_timeout, av_OnPeerTimeout, self);
toxav_register_audio_recv_callback(ASettins.av, write_device_callback);
return ASettins.av;
}
@ -335,159 +155,75 @@ void terminate_audio()
if ( ASettins.av )
toxav_kill(ASettins.av);
device_close(NULL, input);
device_close(NULL, output);
terminate_devices();
}
int errors()
void read_device_callback (const int16_t* captured, uint32_t size, void* data)
{
return ASettins.errors;
int32_t call_index = *((int32_t*)data); /* TODO: Or pass an array of call_idx's */
uint8_t encoded_payload[RTP_PAYLOAD_SIZE];
int32_t payload_size = toxav_prepare_audio_frame(ASettins.av, call_index, encoded_payload, RTP_PAYLOAD_SIZE, captured, size);
if ( payload_size <= 0 || toxav_send_audio(ASettins.av, call_index, encoded_payload, payload_size) < 0 ) {
/*fprintf(stderr, "Could not encode audio packet\n");*/
}
}
/*
* Transmission
*/
void *transmission(void *arg)
{
ToxWindow* self = arg;
int32_t call_index = self->call_index;
/* Missing audio support */
if ( !ASettins.av ) _cbend;
Call* this_call = &ASettins.calls[call_index];
this_call->ttas = _True;
/* Prepare devices */
alcCaptureStart(ASettins.device[input].dhndl);
alcMakeContextCurrent(ASettins.device[output].ctx);
int32_t dec_frame_len;
int16_t frame[4096];
int32_t sample = 0;
uint32_t buffer;
int32_t ready;
int32_t openal_buffers = 5;
uint32_t source, *buffers;
uint8_t encoded_payload[RTP_PAYLOAD_SIZE];
const int32_t frame_size = AUDIO_FRAME_SIZE;
/* Prepare buffers */
buffers = calloc(sizeof(uint32_t), openal_buffers);
alGenBuffers(openal_buffers, buffers);
alGenSources((uint32_t)1, &source);
alSourcei(source, AL_LOOPING, AL_FALSE);
uint16_t zeros[frame_size];
memset(zeros, 0, frame_size);
int16_t PCM[frame_size];
int32_t i = 0;
for (; i < openal_buffers; ++i) {
alBufferData(buffers[i], AL_FORMAT_MONO16, zeros, frame_size, 48000);
}
alSourceQueueBuffers(source, openal_buffers, buffers);
alSourcePlay(source);
if (alGetError() != AL_NO_ERROR) {
/* Print something? */
/*fprintf(stderr, "Error starting audio\n");*/
// goto cleanup;
}
/* Start transmission */
while (this_call->ttas) {
alcGetIntegerv(ASettins.device[input].dhndl, ALC_CAPTURE_SAMPLES, (int32_t) sizeof(int32_t), &sample);
/* RECORD AND SEND */
if (sample >= frame_size) {
alcCaptureSamples(ASettins.device[input].dhndl, frame, frame_size);
int32_t payload_size = toxav_prepare_audio_frame(ASettins.av, call_index, encoded_payload, RTP_PAYLOAD_SIZE, frame, frame_size);
if ( payload_size <= 0 || toxav_send_audio(ASettins.av, call_index, encoded_payload, payload_size) < 0 ) {
/*fprintf(stderr, "Could not encode audio packet\n");*/
}
}
/* PLAYBACK */
alGetSourcei(source, AL_BUFFERS_PROCESSED, &ready);
if (ready <= 0) continue;
dec_frame_len = toxav_recv_audio(ASettins.av, call_index, frame_size, PCM);
/* Play the packet */
if (dec_frame_len > 0) {
alSourceUnqueueBuffers(source, 1, &buffer);
alBufferData(buffer, AL_FORMAT_MONO16, PCM, dec_frame_len * 2 * 1, 48000);
int32_t error = alGetError();
if (error != AL_NO_ERROR) {
fprintf(stderr, "Error setting buffer %d\n", error);
break;
}
alSourceQueueBuffers(source, 1, &buffer);
if (alGetError() != AL_NO_ERROR) {
fprintf(stderr, "Error: could not buffer audio\n");
break;
}
alGetSourcei(source, AL_SOURCE_STATE, &ready);
if (ready != AL_PLAYING) alSourcePlay(source);
}
else {
/* Error ignored */
}
usleep(1000);
}
cleanup:
alDeleteSources(1, &source);
alDeleteBuffers(openal_buffers, buffers);
/*
device_close(NULL, input);
device_close(NULL, output);*/
_cbend;
void write_device_callback(ToxAv* av, int32_t call_index, int16_t* data, int size)
{
if (ASettins.calls[call_index].ttas)
write_out(ASettins.calls[call_index].out_idx, data, size, 1);
}
int start_transmission(ToxWindow *self)
{
if ( !ASettins.av || self->call_index == -1 ) return -1;
if ( !ASettins.av || self->call_idx == -1 ) return -1;
/* Don't provide support for video */
if ( 0 != toxav_prepare_transmission(ASettins.av, self->call_index, &ASettins.cs, 0) ) {
if ( 0 != toxav_prepare_transmission(ASettins.av, self->call_idx, &ASettins.cs, 0) ) {
line_info_add(self, NULL, NULL, NULL, "Could not prepare transmission", SYS_MSG, 0, 0);
}
if ( !toxav_capability_supported(ASettins.av, self->call_index, AudioDecoding) ||
!toxav_capability_supported(ASettins.av, self->call_index, AudioEncoding) )
return -1;
if ( 0 != pthread_create(&ASettins.calls[self->call_index].ttid, NULL, transmission, self ) &&
0 != pthread_detach(ASettins.calls[self->call_index].ttid) ) {
if ( !toxav_capability_supported(ASettins.av, self->call_idx, AudioDecoding) ||
!toxav_capability_supported(ASettins.av, self->call_idx, AudioEncoding) )
return -1;
set_call(&ASettins.calls[self->call_idx], _True);
if ( open_primary_device(input, &ASettins.calls[self->call_idx].in_idx) != de_None )
line_info_add(self, NULL, NULL, NULL, "Failed to open input device!", SYS_MSG, 0, 0);
if ( register_device_callback(self->call_idx, ASettins.calls[self->call_idx].in_idx,
read_device_callback, &self->call_idx, _True) != de_None)
/* Set VAD as true for all; TODO: Make it more dynamic */
line_info_add(self, NULL, NULL, NULL, "Failed to register input handler!", SYS_MSG, 0, 0);
if ( open_primary_device(output, &ASettins.calls[self->call_idx].out_idx) != de_None ) {
line_info_add(self, NULL, NULL, NULL, "Failed to open output device!", SYS_MSG, 0, 0);
ASettins.calls[self->call_idx].has_output = 0;
}
return 0;
}
int stop_transmission(int call_index)
{
toxav_kill_transmission(ASettins.av, call_index);
ASettins.calls[call_index].ttas = _False;
if ( ASettins.calls[call_index].ttas ) {
toxav_kill_transmission(ASettins.av, call_index);
ASettins.calls[call_index].ttas = _False;
if ( ASettins.calls[call_index].in_idx != -1 )
close_device(input, ASettins.calls[call_index].in_idx);
if ( ASettins.calls[call_index].out_idx != -1 )
close_device(output, ASettins.calls[call_index].out_idx);
set_call(&ASettins.calls[call_index], _False);
return 0;
}
return -1;
}
/*
* End of transmission
@ -517,14 +253,13 @@ void callback_recv_starting ( int32_t call_index, void* arg )
ToxWindow* windows = arg;
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i)
if (windows[i].onStarting != NULL && windows[i].call_index == call_index) {
if (windows[i].onStarting != NULL && windows[i].call_idx == call_index) {
windows[i].onStarting(&windows[i], ASettins.av, call_index);
if ( 0 != start_transmission(&windows[i]) ) {/* YEAH! */
line_info_add(&windows[i], NULL, NULL, NULL, "Error starting transmission!", SYS_MSG, 0, 0);
return;
}
return;
}
}
void callback_recv_ending ( int32_t call_index, void* arg )
{
@ -534,13 +269,14 @@ void callback_recv_ending ( int32_t call_index, void* arg )
void callback_recv_error ( int32_t call_index, void* arg )
{
CB_BODY(call_index, arg, onError);
stop_transmission(call_index);
}
void callback_call_started ( int32_t call_index, void* arg )
{
ToxWindow* windows = arg;
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i)
if (windows[i].onStart != NULL && windows[i].call_index == call_index) {
if (windows[i].onStart != NULL && windows[i].call_idx == call_index) {
windows[i].onStart(&windows[i], ASettins.av, call_index);
if ( 0 != start_transmission(&windows[i]) ) {/* YEAH! */
line_info_add(&windows[i], NULL, NULL, NULL, "Error starting transmission!", SYS_MSG, 0, 0);
@ -588,8 +324,8 @@ void callback_peer_timeout ( int32_t call_index, void* arg )
*/
void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
uint8_t msg[MAX_STR_SIZE];
uint8_t *error_str;
char msg[MAX_STR_SIZE];
char *error_str;
if (argc != 0) {
error_str = "Invalid syntax!";
@ -601,7 +337,12 @@ void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
goto on_error;
}
ToxAvError error = toxav_call(ASettins.av, &self->call_index, self->num, TypeAudio, 30);
if (!self->stb->is_online) {
error_str = "Friend is offline.";
goto on_error;
}
ToxAvError error = toxav_call(ASettins.av, &self->call_idx, self->num, TypeAudio, 30);
if ( error != ErrorNone ) {
if ( error == ErrorAlreadyInCall ) error_str = "Already in a call!";
@ -610,7 +351,7 @@ void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
goto on_error;
}
snprintf(msg, sizeof(msg), "Calling... idx: %d", self->call_index);
snprintf(msg, sizeof(msg), "Calling... idx: %d", self->call_idx);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
return;
@ -621,7 +362,7 @@ on_error:
void cmd_answer(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
uint8_t *error_str;
char *error_str;
if (argc != 0) {
error_str = "Invalid syntax!";
@ -633,7 +374,7 @@ void cmd_answer(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
goto on_error;
}
ToxAvError error = toxav_answer(ASettins.av, self->call_index, TypeAudio);
ToxAvError error = toxav_answer(ASettins.av, self->call_idx, TypeAudio);
if ( error != ErrorNone ) {
if ( error == ErrorInvalidState ) error_str = "Cannot answer in invalid state!";
@ -652,7 +393,7 @@ on_error:
void cmd_reject(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
uint8_t *error_str;
char *error_str;
if (argc != 0) {
error_str = "Invalid syntax!";
@ -664,7 +405,7 @@ void cmd_reject(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
goto on_error;
}
ToxAvError error = toxav_reject(ASettins.av, self->call_index, "Why not?");
ToxAvError error = toxav_reject(ASettins.av, self->call_idx, "Why not?");
if ( error != ErrorNone ) {
if ( error == ErrorInvalidState ) error_str = "Cannot reject in invalid state!";
@ -683,7 +424,7 @@ on_error:
void cmd_hangup(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
uint8_t *error_str;
char *error_str;
if (argc != 0) {
error_str = "Invalid syntax!";
@ -695,7 +436,7 @@ void cmd_hangup(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
goto on_error;
}
ToxAvError error = toxav_hangup(ASettins.av, self->call_index);
ToxAvError error = toxav_hangup(ASettins.av, self->call_idx);
if ( error != ErrorNone ) {
if ( error == ErrorInvalidState ) error_str = "Cannot hangup in invalid state!";
@ -712,7 +453,7 @@ on_error:
void cmd_cancel(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
uint8_t *error_str;
char *error_str;
if (argc != 0) {
error_str = "Invalid syntax!";
@ -724,11 +465,12 @@ void cmd_cancel(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
goto on_error;
}
ToxAvError error = toxav_cancel(ASettins.av, self->call_index, self->num,
ToxAvError error = toxav_cancel(ASettins.av, self->call_idx, self->num,
"Only those who appreciate small things know the beauty that is life");
if ( error != ErrorNone ) {
if ( error == ErrorNoCall ) error_str = "No call!";
else if ( error == ErrorInvalidState ) error_str = "Cannot cancel in invalid state!";
else error_str = "Internal error!";
goto on_error;
@ -744,8 +486,8 @@ on_error:
void cmd_list_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
uint8_t msg[MAX_STR_SIZE];
uint8_t *error_str;
char msg[MAX_STR_SIZE];
char *error_str;
if ( argc != 1 ) {
if ( argc < 1 ) error_str = "Type must be specified!";
@ -754,7 +496,7 @@ void cmd_list_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*
goto on_error;
}
_Devices type;
DeviceType type;
if ( strcmp(argv[1], "in") == 0 ) /* Input devices */
type = input;
@ -768,22 +510,18 @@ void cmd_list_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*
return;
}
int i = 0;
for ( ; i < ASettins.device[type].size; i ++) {
snprintf(msg, sizeof(msg), "%d: %s", i, ASettins.device[type].devices[i]);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
}
print_devices(self, type);
return;
on_error:
print_err (self, error_str);
}
/* This changes primary device only */
void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
uint8_t msg[MAX_STR_SIZE];
uint8_t *error_str;
char msg[MAX_STR_SIZE];
char *error_str;
if ( argc != 2 ) {
if ( argc < 1 ) error_str = "Type must be specified!";
@ -793,12 +531,7 @@ void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (
goto on_error;
}
if ( ASettins.calls[self->call_index].ttas ) { /* Transmission is active */
error_str = "Cannot change device while active transmission";
goto on_error;
}
_Devices type;
DeviceType type;
if ( strcmp(argv[1], "in") == 0 ) /* Input devices */
type = input;
@ -821,22 +554,184 @@ void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (
goto on_error;
}
if ( device_close(self, type) != 0 ) {
error_str = "Could not close device!";
if ( set_primary_device(type, selection) == de_InvalidSelection ) {
error_str="Invalid selection!";
goto on_error;
}
if ( device_set(self, type, selection ) == 0) {
/*snprintf(msg, sizeof(msg), "Selected: %s", ASettins.device[type].devices[selection]);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);*/
}
if ( device_open(self, type) == 0 ) {
snprintf(msg, sizeof(msg), "Now using: %s", ASettins.device[type].devices[selection]);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
}
return;
on_error:
print_err (self, error_str);
}
void cmd_ccur_device(WINDOW * window, ToxWindow * self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
char msg[MAX_STR_SIZE];
char *error_str;
if ( argc != 2 ) {
if ( argc < 1 ) error_str = "Type must be specified!";
else if ( argc < 2 ) error_str = "Must have id!";
else error_str = "Only two arguments allowed!";
goto on_error;
}
DeviceType type;
if ( strcmp(argv[1], "in") == 0 ) /* Input devices */
type = input;
else if ( strcmp(argv[1], "out") == 0 ) /* Output devices */
type = output;
else {
snprintf(msg, sizeof(msg), "Invalid type: %s", argv[1]);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
return;
}
char *end;
long int selection = strtol(argv[2], &end, 10);
if ( *end ) {
error_str = "Invalid input";
goto on_error;
}
if ( selection_valid(type, selection) == de_InvalidSelection ) {
error_str="Invalid selection!";
goto on_error;
}
/* If call is active, change device */
if ( self->call_idx > -1) {
Call* this_call = &ASettins.calls[self->call_idx];
if (this_call->ttas) {
if (type == output) {
pthread_mutex_lock(&this_call->mutex);
close_device(output, this_call->out_idx);
this_call->has_output = open_device(output, selection, &this_call->out_idx)
== de_None ? 1 : 0;
pthread_mutex_unlock(&this_call->mutex);
}
else {
/* TODO: check for failure */
close_device(input, this_call->in_idx);
open_device(input, selection, &this_call->in_idx);
/* Set VAD as true for all; TODO: Make it more dynamic */
register_device_callback(self->call_idx, this_call->in_idx, read_device_callback, &self->call_idx, _True);
}
}
}
self->device_selection[type] = selection;
return;
on_error:
print_err (self, error_str);
}
void cmd_mute(WINDOW * window, ToxWindow * self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
char msg[MAX_STR_SIZE];
char *error_str;
if ( argc != 1 ) {
if ( argc < 1 ) error_str = "Type must be specified!";
else error_str = "Only two arguments allowed!";
goto on_error;
}
DeviceType type;
if ( strcmp(argv[1], "in") == 0 ) /* Input devices */
type = input;
else if ( strcmp(argv[1], "out") == 0 ) /* Output devices */
type = output;
else {
snprintf(msg, sizeof(msg), "Invalid type: %s", argv[1]);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
return;
}
/* If call is active, use this_call values */
if ( self->call_idx > -1) {
Call* this_call = &ASettins.calls[self->call_idx];
pthread_mutex_lock(&this_call->mutex);
if (type == input) {
device_mute(type, this_call->in_idx);
self->chatwin->infobox.in_is_muted ^= 1;
} else {
device_mute(type, this_call->out_idx);
self->chatwin->infobox.out_is_muted ^= 1;
}
pthread_mutex_unlock(&this_call->mutex);
}
return;
on_error:
print_err (self, error_str);
}
void cmd_sense(WINDOW * window, ToxWindow * self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
char *error_str;
if ( argc != 1 ) {
if ( argc < 1 ) error_str = "Must have value!";
else error_str = "Only two arguments allowed!";
goto on_error;
}
char *end;
float value = strtof(argv[1], &end);
if ( *end ) {
error_str = "Invalid input";
goto on_error;
}
/* Call must be active */
if ( self->call_idx > -1) {
device_set_VAD_treshold(ASettins.calls[self->call_idx].in_idx, value);
self->chatwin->infobox.vad_lvl = value;
}
return;
on_error:
print_err (self, error_str);
}
void stop_current_call(ToxWindow* self)
{
ToxAvCallState callstate;
if ( ASettins.av != NULL && self->call_idx != -1 &&
( callstate = toxav_get_call_state(ASettins.av, self->call_idx) ) != av_CallNonExistant) {
switch (callstate)
{
case av_CallActive:
case av_CallHold:
toxav_hangup(ASettins.av, self->call_idx);
break;
case av_CallInviting:
toxav_cancel(ASettins.av, self->call_idx, 0, "Not interested anymore");
break;
case av_CallStarting:
toxav_reject(ASettins.av, self->call_idx, "Not interested");
break;
default:
break;
}
}
}

View File

@ -25,32 +25,23 @@
#include <tox/toxav.h>
#include "toxic.h"
#include "windows.h"
#include "device.h"
#define MAX_DEVICES 32
#define VAD_THRESHOLD_DEFAULT 40.0
typedef enum _AudioError {
NoError = 0,
ErrorStartingCaptureDevice = 1 << 0,
ErrorStartingOutputDevice = 1 << 1,
ErrorStartingCoreAudio = 1 << 2
ae_None = 0,
ae_StartingCaptureDevice = 1 << 0,
ae_StartingOutputDevice = 1 << 1,
ae_StartingCoreAudio = 1 << 2
} AudioError;
typedef enum _Devices {
input,
output,
} _Devices;
/* You will have to pass pointer to first member of 'windows'
* declared in windows.c otherwise undefined behaviour will
*/
ToxAv *init_audio(ToxWindow *self, Tox *tox);
void terminate_audio();
int errors();
int start_transmission(ToxWindow *self);
int device_set(ToxWindow *self, _Devices type, long int selection);
void stop_current_call(ToxWindow *self);
#endif /* _audio_h */

File diff suppressed because it is too large Load Diff

View File

@ -20,10 +20,6 @@
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
@ -33,6 +29,7 @@
#include "friendlist.h"
#include "execute.h"
#include "line_info.h"
#include "groupchat.h"
extern ToxWindow *prompt;
@ -41,61 +38,9 @@ extern ToxicFriend friends[MAX_FRIENDS_NUM];
extern FileSender file_senders[MAX_FILES];
extern uint8_t max_file_senders_index;
void cmd_chat_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
struct history *hst = self->chatwin->hst;
line_info_clear(hst);
struct line_info *start = hst->line_start;
if (argc == 1) {
if (!strcmp(argv[1], "global")) {
execute(window, self, m, "/help", GLOBAL_COMMAND_MODE);
return;
}
}
uint8_t *msg = "Chat commands:";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
#ifdef _SUPPORT_AUDIO
#define NUMLINES 13
#else
#define NUMLINES 9
#endif
uint8_t lines[NUMLINES][MAX_STR_SIZE] = {
#ifdef _SUPPORT_AUDIO
{ " /call : Audio call" },
{ " /cancel : Cancel call" },
{ " /answer : Answer incomming call" },
{ " /reject : Reject incoming call" },
{ " /hangup : Hangup active call" },
#endif /* _SUPPORT_AUDIO */
{ " /invite <n> : Invite friend to a group chat" },
{ " /join : Join a pending group chat" },
{ " /log <on> or <off> : Enable/disable logging" },
{ " /sendfile <filepath> : Send a file" },
{ " /savefile <n> : Receive a file" },
{ " /close : Close the current chat window" },
{ " /help : Print this message again" },
{ " /help global : Show a list of global commands" },
};
int i;
for (i = 0; i < NUMLINES; ++i)
line_info_add(self, NULL, NULL, NULL, lines[i], SYS_MSG, 0, 0);
msg = " * Use Page Up/Page Down to scroll chat history\n";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
hst->line_start = start;
}
void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
uint8_t *errmsg;
char *errmsg;
if (argc < 1) {
errmsg = "Invalid syntax";
@ -112,19 +57,19 @@ void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
}
if (tox_invite_friend(m, self->num, groupnum) == -1) {
errmsg = "Failed to invite friend.";
errmsg = "Failed to invite contact to group.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
return;
}
uint8_t msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "Invited friend to Room #%d.", groupnum);
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "Invited contact to Group %d.", groupnum);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
}
void cmd_join_group(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
uint8_t *errmsg;
char *errmsg;
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
errmsg = " * Warning: Too many windows are open.";
@ -132,15 +77,15 @@ void cmd_join_group(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
return;
}
uint8_t *groupkey = friends[self->num].pending_groupchat;
char *groupkey = friends[self->num].groupchat_key;
if (groupkey[0] == '\0') {
if (!friends[self->num].groupchat_pending) {
errmsg = "No pending group chat invite.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
return;
}
int groupnum = tox_join_groupchat(m, self->num, groupkey);
int groupnum = tox_join_groupchat(m, self->num, (uint8_t *) groupkey);
if (groupnum == -1) {
errmsg = "Group chat instance failed to initialize.";
@ -158,7 +103,7 @@ void cmd_join_group(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
uint8_t *errmsg;
char *errmsg;
if (argc != 1) {
errmsg = "Invalid syntax.";
@ -180,10 +125,10 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
return;
}
uint8_t *filename = friends[self->num].file_receiver.filenames[filenum];
char *filename = friends[self->num].file_receiver.filenames[filenum];
if (tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_ACCEPT, 0, 0) == 0) {
uint8_t msg[MAX_STR_SIZE];
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "Saving file as: '%s' (%.1f%%)", filename, 0.0);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
friends[self->num].file_receiver.line_id[filenum] = self->chatwin->hst->line_end->id + 1;
@ -203,7 +148,7 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
uint8_t *errmsg;
char *errmsg;
if (max_file_senders_index >= (MAX_FILES - 1)) {
errmsg = "Please wait for some of your outgoing file transfers to complete.";
@ -217,7 +162,7 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
return;
}
uint8_t *path = argv[1];
char *path = argv[1];
if (path[0] != '\"') {
errmsg = "File path must be enclosed in quotes.";
@ -225,8 +170,9 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
return;
}
path[strlen(++path) - 1] = L'\0';
int path_len = strlen(path);
++path;
int path_len = strlen(path) - 1;
path[path_len] = '\0';
if (path_len > MAX_STR_SIZE) {
errmsg = "File path exceeds character limit.";
@ -246,9 +192,9 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
uint64_t filesize = ftell(file_to_send);
fseek(file_to_send, 0, SEEK_SET);
uint8_t filename[MAX_STR_SIZE];
get_file_name(filename, path);
int filenum = tox_new_file_sender(m, self->num, filesize, filename, strlen(filename));
char filename[MAX_STR_SIZE];
get_file_name(filename, sizeof(filename), path);
int filenum = tox_new_file_sender(m, self->num, filesize, (const uint8_t *) filename, strlen(filename));
if (filenum == -1) {
errmsg = "Error sending file.";
@ -271,7 +217,7 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
file_senders[i].piecelen = fread(file_senders[i].nextpiece, 1,
tox_file_data_size(m, self->num), file_to_send);
uint8_t msg[MAX_STR_SIZE];
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "Sending file: '%s'", path);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);

View File

@ -26,19 +26,20 @@
#include "windows.h"
#include "toxic.h"
void cmd_chat_help(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_groupinvite(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_join_group(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_savefile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_sendfile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
#ifdef _SUPPORT_AUDIO
void cmd_call(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_answer(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_reject(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_hangup(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_cancel(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_sense(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
#endif /* _SUPPORT_AUDIO */
#endif /* #define _chat_commands_h */

View File

@ -20,10 +20,6 @@
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

432
src/device.c Normal file
View File

@ -0,0 +1,432 @@
/* device.c
*
*
* Copyright (C) 2014 Toxic All Rights Reserved.
*
* This file is part of Toxic.
*
* Toxic is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Toxic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "audio_call.h"
#include "line_info.h"
#ifdef __APPLE__
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#else
#include <AL/al.h>
#include <AL/alc.h>
#endif
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <tox/toxav.h>
#define openal_bufs 5
#define sample_rate 48000
#define inline__ inline __attribute__((always_inline))
#define frame_size (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000)
typedef struct _Device {
ALCdevice *dhndl; /* Handle of device selected/opened */
ALCcontext *ctx; /* Device context */
DataHandleCallback cb; /* Use this to handle data from input device usually */
void* cb_data; /* Data to be passed to callback */
int32_t call_idx; /* ToxAv call index */
uint32_t source, buffers[openal_bufs]; /* Playback source/buffers */
size_t ref_count;
int32_t selection;
_Bool enable_VAD;
_Bool muted;
float VAD_treshold; /* 40 is usually recommended value */
pthread_mutex_t mutex[1];
} Device;
const char *ddevice_names[2]; /* Default device */
const char *devices_names[2][MAX_DEVICES]; /* Container of available devices */
static int size[2]; /* Size of above containers */
Device *running[2][MAX_DEVICES]; /* Running devices */
uint32_t primary_device[2]; /* Primary device */
static ToxAv* av = NULL;
/* q_mutex */
#define lock pthread_mutex_lock(&mutex)
#define unlock pthread_mutex_unlock(&mutex)
pthread_mutex_t mutex;
_Bool thread_running = _True,
thread_paused = _True; /* Thread control */
void* thread_poll(void*);
/* Meet devices */
DeviceError init_devices(ToxAv* av_)
{
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 ( (stringed_device_list = alcGetString(NULL, ALC_DEVICE_SPECIFIER)) ) {
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
pthread_mutex_init(&mutex, NULL);
pthread_t thread_id;
if ( pthread_create(&thread_id, NULL, thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0)
return de_InternalError;
av = av_;
return (DeviceError) ae_None;
}
DeviceError terminate_devices()
{
/* Cleanup if needed */
thread_running = false;
usleep(20000);
pthread_mutex_destroy(&mutex);
return (DeviceError) ae_None;
}
DeviceError device_mute(DeviceType type, uint32_t device_idx)
{
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
lock;
Device* device = running[type][device_idx];
if (!device) {
unlock;
return de_DeviceNotActive;
}
device->muted = !device->muted;
unlock;
return de_None;
}
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
{
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
lock;
Device* device = running[input][device_idx];
if (!device) {
unlock;
return de_DeviceNotActive;
}
device->VAD_treshold = value;
unlock;
return de_None;
}
DeviceError set_primary_device(DeviceType type, int32_t selection)
{
if (size[type] <= selection || selection < 0) return de_InvalidSelection;
primary_device[type] = selection;
return de_None;
}
DeviceError open_primary_device(DeviceType type, uint32_t* device_idx)
{
return open_device(type, primary_device[type], device_idx);
}
// TODO: generate buffers separately
DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx)
{
if (size[type] <= selection || selection < 0) return de_InvalidSelection;
lock;
uint32_t i;
for (i = 0; i < MAX_DEVICES && running[type][i] != NULL; i ++);
if (i == MAX_DEVICES) { unlock; return de_AllDevicesBusy; }
else *device_idx = i;
Device* device = running[type][*device_idx] = calloc(1, sizeof(Device));;
device->selection = selection;
for (i = 0; i < *device_idx; i ++) { /* Check if any previous has the same selection */
if ( running[type][i]->selection == selection ) {
device->dhndl = running[type][i]->dhndl;
if (type == output) {
device->ctx = running[type][i]->ctx;
memcpy(device->buffers, running[type][i]->buffers, sizeof(running[type][i]->buffers));
device->source = running[type][i]->source;
}
device->ref_count++;
pthread_mutex_init(device->mutex, NULL);
unlock;
return de_None;
}
}
if (type == input) {
device->dhndl = alcCaptureOpenDevice(devices_names[type][selection],
av_DefaultSettings.audio_sample_rate, AL_FORMAT_MONO16, frame_size * 2);
device->VAD_treshold = VAD_THRESHOLD_DEFAULT;
}
else {
device->dhndl = alcOpenDevice(devices_names[type][selection]);
if ( !device->dhndl ) {
free(device);
running[type][*device_idx] = NULL;
unlock;
return de_FailedStart;
}
device->ctx = alcCreateContext(device->dhndl, NULL);
alcMakeContextCurrent(device->ctx);
alGenBuffers(openal_bufs, device->buffers);
alGenSources((uint32_t)1, &device->source);
alSourcei(device->source, AL_LOOPING, AL_FALSE);
uint16_t zeros[frame_size];
memset(zeros, 0, frame_size*2);
for ( i =0; i < openal_bufs; ++i) {
alBufferData(device->buffers[i], AL_FORMAT_MONO16, zeros, frame_size*2, sample_rate);
}
alSourceQueueBuffers(device->source, openal_bufs, device->buffers);
alSourcePlay(device->source);
}
if (alcGetError(device->dhndl) != AL_NO_ERROR) {
free(device);
running[type][*device_idx] = NULL;
unlock;
return de_FailedStart;
}
if (type == input) {
alcCaptureStart(device->dhndl);
thread_paused = _False;
}
pthread_mutex_init(device->mutex, NULL);
unlock;
return de_None;
}
DeviceError close_device(DeviceType type, uint32_t device_idx)
{
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
lock;
Device* device = running[type][device_idx];
if (!device) {
unlock;
return de_DeviceNotActive;
}
if ( !(device->ref_count--) ) {
running[type][device_idx] = NULL;
unlock;
DeviceError rc = de_None;
if (type == input) {
if ( !alcCaptureCloseDevice(device->dhndl) ) rc = de_AlError;
}
else {
if (alcGetCurrentContext() != device->ctx) alcMakeContextCurrent(device->ctx);
alDeleteSources(1, &device->source);
alDeleteBuffers(openal_bufs, device->buffers);
if ( !alcCloseDevice(device->dhndl) ) rc = de_AlError;
alcMakeContextCurrent(NULL);
if ( device->ctx ) alcDestroyContext(device->ctx);
}
free(device);
return rc;
}
unlock;
return de_None;
}
DeviceError register_device_callback( int32_t call_idx, 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)
return de_InvalidSelection;
lock;
running[input][device_idx]->cb = callback;
running[input][device_idx]->cb_data = data;
running[input][device_idx]->enable_VAD = enable_VAD;
running[input][device_idx]->call_idx = call_idx;
unlock;
return de_None;
}
inline__ DeviceError write_out(uint32_t device_idx, int16_t* data, uint32_t lenght, uint8_t channels)
{
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
Device* device = running[output][device_idx];
if (!device || device->muted) return de_DeviceNotActive;
pthread_mutex_lock(device->mutex);
ALuint bufid;
ALint processed, queued;
alGetSourcei(device->source, AL_BUFFERS_PROCESSED, &processed);
alGetSourcei(device->source, AL_BUFFERS_QUEUED, &queued);
if(processed) {
ALuint bufids[processed];
alSourceUnqueueBuffers(device->source, processed, bufids);
alDeleteBuffers(processed - 1, bufids + 1);
bufid = bufids[0];
}
else if(queued < 16) alGenBuffers(1, &bufid);
else {
pthread_mutex_unlock(device->mutex);
return de_Busy;
}
alBufferData(bufid, AL_FORMAT_MONO16, data, lenght * 2 * channels, av_DefaultSettings.audio_sample_rate);
alSourceQueueBuffers(device->source, 1, &bufid);
ALint state;
alGetSourcei(device->source, AL_SOURCE_STATE, &state);
if(state != AL_PLAYING) alSourcePlay(device->source);
pthread_mutex_unlock(device->mutex);
return de_None;
}
void* thread_poll (void* arg) // TODO: maybe use thread for every input source
{
/*
* NOTE: We only need to poll input devices for data.
*/
(void)arg;
uint32_t i;
int32_t sample = 0;
int f_size = frame_size;
while (thread_running)
{
if (thread_paused) usleep(10000); /* Wait for unpause. */
else
{
for (i = 0; i < size[input]; i ++)
{
lock;
if (running[input][i] != NULL)
{
alcGetIntegerv(running[input][i]->dhndl, ALC_CAPTURE_SAMPLES, sizeof(int32_t), &sample);
if (sample < f_size) {
unlock;
continue;
}
Device* device = running[input][i];
int16_t frame[4096];
alcCaptureSamples(device->dhndl, frame, f_size);
if ( device->muted ||
(device->enable_VAD && !toxav_has_activity(av, device->call_idx, frame, f_size, device->VAD_treshold)))
{ unlock; continue; } /* Skip if no voice activity */
if ( device->cb ) device->cb(frame, f_size, device->cb_data);
}
unlock;
}
usleep(5000);
}
}
pthread_exit(NULL);
}
void print_devices(ToxWindow* self, DeviceType type)
{
int i = 0;
for ( ; i < size[type]; i ++) {
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "%d: %s", i, devices_names[type][i]);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
}
return;
}
DeviceError selection_valid(DeviceType type, int32_t selection)
{
return (size[type] <= selection || selection < 0) ? de_InvalidSelection : de_None;
}
void* get_device_callback_data(uint32_t device_idx)
{
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
return NULL;
return running[input][device_idx]->cb_data;
}

84
src/device.h Normal file
View File

@ -0,0 +1,84 @@
/* device.h
*
*
* Copyright (C) 2014 Toxic All Rights Reserved.
*
* This file is part of Toxic.
*
* Toxic is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Toxic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* You can have multiple sources (Input devices) but only one output device.
* Pass buffers to output device via write();
* Read from running input device(s) via select()/callback combo.
*/
#ifndef _device_h
#define _device_h
#define MAX_DEVICES 32
#include <inttypes.h>
#include "windows.h"
#define _True 1
#define _False 0
typedef enum DeviceType {
input,
output,
} DeviceType;
typedef enum DeviceError {
de_None,
de_InternalError = -1,
de_InvalidSelection = -2,
de_FailedStart = -3,
de_Busy = -4,
de_AllDevicesBusy = -5,
de_DeviceNotActive = -6,
de_BufferError = -7,
de_AlError = -8,
} DeviceError;
typedef void (*DataHandleCallback) (const int16_t*, uint32_t size, void* data);
DeviceError init_devices(ToxAv* av);
DeviceError terminate_devices();
/* Callback handles ready data from INPUT device */
DeviceError register_device_callback(int32_t call_idx, uint32_t device_idx, DataHandleCallback callback, void* data, _Bool enable_VAD);
void* get_device_callback_data(uint32_t device_idx);
/* toggle device mute */
DeviceError device_mute(DeviceType type, uint32_t device_idx);
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value);
DeviceError set_primary_device(DeviceType type, int32_t selection);
DeviceError open_primary_device(DeviceType type, uint32_t* device_idx);
/* Start device */
DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx);
/* Stop device */
DeviceError close_device(DeviceType type, uint32_t device_idx);
/* Write data to device */
DeviceError write_out(uint32_t device_idx, int16_t* data, uint32_t lenght, uint8_t channels);
void print_devices(ToxWindow* self, DeviceType type);
DeviceError selection_valid(DeviceType type, int32_t selection);
#endif /* _device_h */

116
src/dns.c
View File

@ -20,16 +20,17 @@
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#ifdef __APPLE__
#include <arpa/nameser_compat.h>
#else
#include <arpa/nameser.h>
#endif /* ifdef __APPLE__ */
#include <tox/toxdns.h>
#include "toxic.h"
@ -44,14 +45,16 @@
#define TOX_DNS3_TXT_PREFIX "v=tox3;id="
#define DNS3_KEY_SZ 32
extern struct _Winthread Winthread;
/* TODO: process keys from key file instead of hard-coding like a noob */
static struct dns3_server {
uint8_t *name;
uint8_t key[DNS3_KEY_SZ];
char *name;
char key[DNS3_KEY_SZ];
} dns3_servers[] = {
{
"utox.org",
{
"utox.org",
{
0xD3, 0x15, 0x4F, 0x65, 0xD2, 0x8A, 0x5B, 0x41, 0xA0, 0x5D, 0x4A, 0xC7, 0xE4, 0xB3, 0x9C, 0x6B,
0x1C, 0x23, 0x3C, 0xC8, 0x57, 0xFB, 0x36, 0x5C, 0x56, 0xE8, 0x39, 0x27, 0x37, 0x46, 0x2A, 0x12
}
@ -67,26 +70,27 @@ static struct dns3_server {
static struct _thread_data {
ToxWindow *self;
uint8_t id_bin[TOX_FRIEND_ADDRESS_SIZE];
uint8_t addr[MAX_STR_SIZE];
uint8_t msg[MAX_STR_SIZE];
char id_bin[TOX_FRIEND_ADDRESS_SIZE];
char addr[MAX_STR_SIZE];
char msg[MAX_STR_SIZE];
uint8_t busy;
Tox *m;
} t_data;
static struct _dns_thread {
pthread_t tid;
pthread_mutex_t lock;
pthread_attr_t attr;
} dns_thread;
static int dns_error(ToxWindow *self, uint8_t *errmsg)
{
uint8_t msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "DNS lookup failed: %s", errmsg);
pthread_mutex_lock(&dns_thread.lock);
static int dns_error(ToxWindow *self, char *errmsg)
{
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "User lookup failed: %s", errmsg);
pthread_mutex_lock(&Winthread.lock);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
pthread_mutex_unlock(&dns_thread.lock);
pthread_mutex_unlock(&Winthread.lock);
return -1;
}
@ -97,15 +101,16 @@ static void kill_dns_thread(void *dns_obj)
tox_dns3_kill(dns_obj);
memset(&t_data, 0, sizeof(struct _thread_data));
pthread_exit(0);
pthread_attr_destroy(&dns_thread.attr);
pthread_exit(NULL);
}
/* puts TXT from dns response in buf. Returns length of TXT on success, -1 on fail.*/
static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, uint8_t *buf)
static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, char *buf)
{
uint8_t *ans_pt = answer + sizeof(HEADER);
uint8_t *ans_end = answer + ans_len;
uint8_t exp_ans[PACKETSZ];
char exp_ans[PACKETSZ];
int len = dn_expand(answer, ans_end, ans_pt, exp_ans, sizeof(exp_ans));
@ -115,13 +120,13 @@ static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, uint
ans_pt += len;
if (ans_pt > ans_end - 4)
return dns_error(self, "Reply was too short.");
return dns_error(self, "DNS reply was too short.");
int type;
GETSHORT(type, ans_pt);
if (type != T_TXT)
return dns_error(self, "Broken reply.");
return dns_error(self, "Broken DNS reply.");
ans_pt += INT16SZ; /* class */
@ -138,7 +143,7 @@ static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, uint
ans_pt += len;
if (ans_pt > ans_end - 10)
return dns_error(self, "Reply was too short.");
return dns_error(self, "DNS reply was too short.");
GETSHORT(type, ans_pt);
ans_pt += INT16SZ;
@ -151,7 +156,7 @@ static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, uint
} while (type == T_CNAME);
if (type != T_TXT)
return dns_error(self, "Not a TXT record.");
return dns_error(self, "DNS response failed.");
uint32_t txt_len = *ans_pt;
@ -169,10 +174,10 @@ static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, uint
and the domain in dombuf.
return length of username on success, -1 on failure */
static int parse_addr(uint8_t *addr, uint8_t *namebuf, uint8_t *dombuf)
static int parse_addr(char *addr, char *namebuf, char *dombuf)
{
uint8_t tmpaddr[MAX_STR_SIZE];
uint8_t *tmpname, *tmpdom;
char tmpaddr[MAX_STR_SIZE];
char *tmpname, *tmpdom;
strcpy(tmpaddr, addr);
tmpname = strtok(tmpaddr, "@");
@ -193,8 +198,8 @@ void *dns3_lookup_thread(void *data)
{
ToxWindow *self = t_data.self;
uint8_t domain[MAX_STR_SIZE];
uint8_t name[MAX_STR_SIZE];
char domain[MAX_STR_SIZE];
char name[MAX_STR_SIZE];
int namelen = parse_addr(t_data.addr, name, domain);
@ -204,7 +209,8 @@ void *dns3_lookup_thread(void *data)
}
/* get domain name/pub key */
uint8_t *DNS_pubkey, *domname = NULL;
char *DNS_pubkey = NULL;
char *domname = NULL;
int i;
for (i = 0; i < NUM_DNS3_SERVERS; ++i) {
@ -220,85 +226,91 @@ void *dns3_lookup_thread(void *data)
kill_dns_thread(NULL);
}
void *dns_obj = tox_dns3_new(DNS_pubkey);
void *dns_obj = tox_dns3_new((uint8_t *) DNS_pubkey);
if (dns_obj == NULL) {
dns_error(self, "Core failed to create DNS object.");
kill_dns_thread(NULL);
}
uint8_t string[MAX_DNS_REQST_SIZE];
char string[MAX_DNS_REQST_SIZE];
uint32_t request_id;
int str_len = tox_generate_dns3_string(dns_obj, string, sizeof(string), &request_id, name, namelen);
int str_len = tox_generate_dns3_string(dns_obj, (uint8_t *) string, sizeof(string), &request_id,
(uint8_t *) name, namelen);
if (str_len == -1) {
dns_error(self, "Core failed to generate dns3 string.");
dns_error(self, "Core failed to generate DNS3 string.");
kill_dns_thread(dns_obj);
}
string[str_len] = '\0';
u_char answer[PACKETSZ];
uint8_t d_string[MAX_DNS_REQST_SIZE];
char d_string[MAX_DNS_REQST_SIZE];
/* format string and create dns query */
snprintf(d_string, sizeof(d_string), "_%s._tox.%s", string, domname);
int ans_len = res_query(d_string, C_IN, T_TXT, answer, sizeof(answer));
if (ans_len <= 0) {
dns_error(self, "Query failed.");
dns_error(self, "DNS query failed.");
kill_dns_thread(dns_obj);
}
uint8_t ans_id[MAX_DNS_REQST_SIZE];
char ans_id[MAX_DNS_REQST_SIZE];
/* extract TXT from DNS response */
if (parse_dns_response(self, answer, ans_len, ans_id) == -1)
kill_dns_thread(dns_obj);
uint8_t encrypted_id[MAX_DNS_REQST_SIZE];
char encrypted_id[MAX_DNS_REQST_SIZE];
int prfx_len = strlen(TOX_DNS3_TXT_PREFIX);
/* extract the encrypted ID from TXT response */
if (strncmp(ans_id, TOX_DNS3_TXT_PREFIX, prfx_len) != 0) {
dns_error(self, "Bad dns3 TXT response.");
dns_error(self, "Bad DNS3 TXT response.");
kill_dns_thread(dns_obj);
}
memcpy(encrypted_id, ans_id + prfx_len, ans_len - prfx_len);
if (tox_decrypt_dns3_TXT(dns_obj, t_data.id_bin, encrypted_id, strlen(encrypted_id), request_id) == -1) {
dns_error(self, "Core failed to decrypt response.");
if (tox_decrypt_dns3_TXT(dns_obj, (uint8_t *) t_data.id_bin, (uint8_t *) encrypted_id,
strlen(encrypted_id), request_id) == -1) {
dns_error(self, "Core failed to decrypt DNS response.");
kill_dns_thread(dns_obj);
}
pthread_mutex_lock(&dns_thread.lock);
pthread_mutex_lock(&Winthread.lock);
cmd_add_helper(self, t_data.m, t_data.id_bin, t_data.msg);
pthread_mutex_unlock(&dns_thread.lock);
pthread_mutex_unlock(&Winthread.lock);
kill_dns_thread(dns_obj);
return 0;
}
/* creates new thread for dns3 lookup. Only allows one lookup at a time. */
void dns3_lookup(ToxWindow *self, Tox *m, uint8_t *id_bin, uint8_t *addr, uint8_t *msg)
void dns3_lookup(ToxWindow *self, Tox *m, char *id_bin, char *addr, char *msg)
{
if (t_data.busy) {
uint8_t *err = "Please wait for previous user lookup to finish.";
char *err = "Please wait for previous user lookup to finish.";
line_info_add(self, NULL, NULL, NULL, err, SYS_MSG, 0, 0);
return;
}
t_data.self = self;
snprintf(t_data.id_bin, sizeof(t_data.id_bin), "%s", id_bin);
snprintf(t_data.addr, sizeof(t_data.addr), "%s", addr);
snprintf(t_data.msg, sizeof(t_data.msg), "%s", msg);
t_data.self = self;
t_data.m = m;
t_data.busy = 1;
if (pthread_create(&dns_thread.tid, NULL, dns3_lookup_thread, NULL) != 0)
exit_toxic_err("failed in dns3_lookup", FATALERR_THREAD_CREATE);
if (pthread_attr_init(&dns_thread.attr) != 0)
exit_toxic_err("failed in dns3_lookup", FATALERR_THREAD_ATTR);
if (pthread_mutex_init(&dns_thread.lock, NULL) != 0)
exit_toxic_err("failed in dns3_lookup", FATALERR_MUTEX_INIT);
if (pthread_attr_setdetachstate(&dns_thread.attr, PTHREAD_CREATE_DETACHED) != 0)
exit_toxic_err("failed in dns3_lookup", FATALERR_THREAD_ATTR);
if (pthread_create(&dns_thread.tid, &dns_thread.attr, dns3_lookup_thread, NULL) != 0)
exit_toxic_err("failed in dns3_lookup", FATALERR_THREAD_CREATE);
}

View File

@ -27,6 +27,6 @@
#define _dns_h
/* creates new thread for dns3 lookup. Only allows one lookup at a time. */
void dns3_lookup(ToxWindow *self, Tox *m, uint8_t *id_bin, uint8_t *addr, uint8_t *msg);
void dns3_lookup(ToxWindow *self, Tox *m, char *id_bin, char *addr, char *msg);
#endif /* #define _dns_h */

View File

@ -20,10 +20,6 @@
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <assert.h>
@ -34,6 +30,7 @@
#include "chat_commands.h"
#include "global_commands.h"
#include "line_info.h"
#include "misc_tools.h"
struct cmd_func {
const char *name;
@ -63,7 +60,6 @@ static struct cmd_func global_commands[] = {
};
static struct cmd_func chat_commands[] = {
{ "/help", cmd_chat_help },
{ "/invite", cmd_groupinvite },
{ "/join", cmd_join_group },
{ "/savefile", cmd_savefile },
@ -75,6 +71,9 @@ static struct cmd_func chat_commands[] = {
{ "/answer", cmd_answer },
{ "/reject", cmd_reject },
{ "/hangup", cmd_hangup },
{ "/sdev", cmd_ccur_device },
{ "/mute", cmd_mute },
{ "/sense", cmd_sense },
#endif /* _SUPPORT_AUDIO */
};
@ -92,7 +91,7 @@ static int parse_command(WINDOW *w, ToxWindow *self, char *cmd, char (*args)[MAX
end = strchr(cmd + 1, '\"');
if (end++ == NULL) { /* Increment past the end quote */
uint8_t *errmsg = "Invalid argument. Did you forget a closing \"?";
char *errmsg = "Invalid argument. Did you forget a closing \"?";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
return -1;
}
@ -135,7 +134,7 @@ void execute(WINDOW *w, ToxWindow *self, Tox *m, char *cmd, int mode)
if (string_is_empty(cmd))
return;
char args[MAX_NUM_ARGS][MAX_STR_SIZE] = {0};
char args[MAX_NUM_ARGS][MAX_STR_SIZE];
int num_args = parse_command(w, self, cmd, args);
if (num_args == -1)
@ -159,6 +158,5 @@ void execute(WINDOW *w, ToxWindow *self, Tox *m, char *cmd, int mode)
if (do_command(w, self, m, num_args, GLOBAL_NUM_COMMANDS, global_commands, args) == 0)
return;
uint8_t *errmsg = "Invalid command.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
line_info_add(self, NULL, NULL, NULL, "Invalid command.", SYS_MSG, 0, 0);
}

View File

@ -30,10 +30,10 @@
#ifdef _SUPPORT_AUDIO
#define GLOBAL_NUM_COMMANDS 16
#define CHAT_NUM_COMMANDS 10
#define CHAT_NUM_COMMANDS 12
#else
#define GLOBAL_NUM_COMMANDS 14
#define CHAT_NUM_COMMANDS 5
#define CHAT_NUM_COMMANDS 4
#endif /* _SUPPORT_AUDIO */
enum {

View File

@ -20,27 +20,22 @@
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include "toxic.h"
#include "windows.h"
#include "file_senders.h"
#include "line_info.h"
#include "misc_tools.h"
FileSender file_senders[MAX_FILES];
uint8_t max_file_senders_index;
static void close_file_sender(int i)
static void set_max_file_senders_index(void)
{
fclose(file_senders[i].file);
memset(&file_senders[i], 0, sizeof(FileSender));
int j;
for (j = max_file_senders_index; j > 0; --j) {
@ -51,20 +46,38 @@ static void close_file_sender(int i)
max_file_senders_index = j;
}
/* Should only be called on exit */
void close_all_file_senders(void)
static void close_file_sender(ToxWindow *self, Tox *m, int i, char *msg, int CTRL, int filenum, int32_t friendnum)
{
if (self->chatwin != NULL) {
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
alert_window(file_senders[i].toxwin, WINDOW_ALERT_2, true);
}
tox_file_send_control(m, friendnum, 0, filenum, CTRL, 0, 0);
fclose(file_senders[i].file);
memset(&file_senders[i], 0, sizeof(FileSender));
set_max_file_senders_index();
}
void close_all_file_senders(Tox *m)
{
int i;
for (i = 0; i < max_file_senders_index; ++i) {
if (file_senders[i].active)
if (file_senders[i].active) {
fclose(file_senders[i].file);
tox_file_send_control(m, file_senders[i].friendnum, 0, file_senders[i].filenum,
TOX_FILECONTROL_KILL, 0, 0);
memset(&file_senders[i], 0, sizeof(FileSender));
}
set_max_file_senders_index();
}
}
void do_file_senders(Tox *m)
{
uint8_t msg[MAX_STR_SIZE];
char msg[MAX_STR_SIZE];
int i;
for (i = 0; i < max_file_senders_index; ++i) {
@ -72,57 +85,43 @@ void do_file_senders(Tox *m)
continue;
ToxWindow *self = file_senders[i].toxwin;
uint8_t *pathname = file_senders[i].pathname;
char *pathname = file_senders[i].pathname;
int filenum = file_senders[i].filenum;
int32_t friendnum = file_senders[i].friendnum;
FILE *fp = file_senders[i].file;
uint64_t current_time = get_unix_time();
/* If file transfer has timed out kill transfer and send kill control */
if (timed_out(file_senders[i].timestamp, current_time, TIMEOUT_FILESENDER)) {
if (self->chatwin != NULL) {
snprintf(msg, sizeof(msg), "File transfer for '%s' timed out.", pathname);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
alert_window(file_senders[i].toxwin, WINDOW_ALERT_2, true);
}
tox_file_send_control(m, friendnum, 0, filenum, TOX_FILECONTROL_KILL, 0, 0);
close_file_sender(i);
if (timed_out(file_senders[i].timestamp, get_unix_time(), TIMEOUT_FILESENDER)) {
snprintf(msg, sizeof(msg), "File transfer for '%s' timed out.", pathname);
close_file_sender(self, m, i, msg, TOX_FILECONTROL_KILL, filenum, friendnum);
continue;
}
while (true) {
if (tox_file_send_data(m, friendnum, filenum, file_senders[i].nextpiece,
if (tox_file_send_data(m, friendnum, filenum, (uint8_t *) file_senders[i].nextpiece,
file_senders[i].piecelen) == -1)
break;
file_senders[i].timestamp = current_time;
uint64_t curtime = get_unix_time();
file_senders[i].timestamp = curtime;
file_senders[i].piecelen = fread(file_senders[i].nextpiece, 1,
tox_file_data_size(m, friendnum), fp);
long double remain = (long double) tox_file_data_remaining(m, friendnum, filenum, 0);
/* refresh line with percentage complete */
if (self->chatwin != NULL) {
if ((self->chatwin != NULL && timed_out(file_senders[i].last_progress, curtime, 1)) || !remain) {
file_senders[i].last_progress = curtime;
uint64_t size = file_senders[i].size;
long double remain = (long double) tox_file_data_remaining(m, friendnum, filenum, 0);
long double pct_remain = 100;
long double pct_remain = remain ? (1 - (remain / size)) * 100 : 100;
if (remain)
pct_remain = (1 - (remain / size)) * 100;
const uint8_t *name = file_senders[i].pathname;
snprintf(msg, sizeof(msg), "File transfer for '%s' accepted (%.1Lf%%)", name, pct_remain);
snprintf(msg, sizeof(msg), "File transfer for '%s' accepted (%.1Lf%%)", pathname, pct_remain);
line_info_set(self, file_senders[i].line_id, msg);
}
if (file_senders[i].piecelen == 0) {
if (self->chatwin != NULL) {
snprintf(msg, sizeof(msg), "File '%s' successfuly sent.", pathname);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
alert_window(file_senders[i].toxwin, WINDOW_ALERT_2, true);
}
tox_file_send_control(m, friendnum, 0, filenum, TOX_FILECONTROL_FINISHED, 0, 0);
close_file_sender(i);
snprintf(msg, sizeof(msg), "File '%s' successfuly sent.", pathname);
close_file_sender(self, m, i, msg, TOX_FILECONTROL_FINISHED, filenum, friendnum);
break;
}
}

View File

@ -27,8 +27,8 @@
#include "windows.h"
#define FILE_PIECE_SIZE 2048 /* must be >= (MAX_CRYPTO_DATA_SIZE - 2) in toxcore/net_crypto.h */
#define MAX_FILES 256
#define TIMEOUT_FILESENDER 300
#define MAX_FILES 255
#define TIMEOUT_FILESENDER 120
typedef struct {
FILE *file;
@ -36,17 +36,16 @@ typedef struct {
int32_t friendnum;
bool active;
int filenum;
uint8_t nextpiece[FILE_PIECE_SIZE];
char nextpiece[FILE_PIECE_SIZE];
uint16_t piecelen;
uint8_t pathname[MAX_STR_SIZE];
char pathname[MAX_STR_SIZE];
uint64_t timestamp;
uint64_t last_progress;
uint64_t size;
uint32_t line_id;
} FileSender;
/* Should only be called on exit */
void close_all_file_senders(void);
void close_all_file_senders(Tox *m);
void do_file_senders(Tox *m);
#endif /* #define _filesenders_h */

View File

@ -20,10 +20,6 @@
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
@ -59,9 +55,10 @@ static int friendlist_index[MAX_FRIENDS_NUM] = {0};
static struct _pendingDel {
int num;
bool active;
WINDOW *popup;
} pendingdelete;
#define S_WEIGHT 100
#define S_WEIGHT 100000
static int index_name_cmp(const void *n1, const void *n2)
{
@ -91,7 +88,7 @@ void sort_friendlist_index(void)
static void update_friend_last_online(int32_t num, uint64_t timestamp)
{
friends[num].last_online.last_on = timestamp;
friends[num].last_online.tm = *localtime(&timestamp);
friends[num].last_online.tm = *localtime((const time_t*)&timestamp);
/* if the format changes make sure TIME_STR_SIZE is the correct size */
const char *t = user_settings->time == TIME_12 ? "%I:%M %p" : "%H:%M";
@ -99,7 +96,7 @@ static void update_friend_last_online(int32_t num, uint64_t timestamp)
&friends[num].last_online.tm);
}
static void friendlist_onMessage(ToxWindow *self, Tox *m, int32_t num, uint8_t *str, uint16_t len)
static void friendlist_onMessage(ToxWindow *self, Tox *m, int32_t num, const char *str, uint16_t len)
{
if (num >= max_friends_index)
return;
@ -108,19 +105,15 @@ static void friendlist_onMessage(ToxWindow *self, Tox *m, int32_t num, uint8_t *
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
friends[num].chatwin = add_window(m, new_chat(m, friends[num].num));
} else {
str[len] = '\0';
char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, num);
uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'};
int n_len = tox_get_name(m, num, nick);
n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH - 1);
nick[n_len] = '\0';
uint8_t timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt);
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
line_info_add(prompt, timefrmt, nick, NULL, str, IN_MSG, 0, 0);
uint8_t *msg = "* Warning: Too many windows are open.";
char *msg = "* Warning: Too many windows are open.";
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, RED);
alert_window(prompt, WINDOW_ALERT_1, true);
}
@ -138,15 +131,16 @@ static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, int32_t num,
sort_friendlist_index();
}
static void friendlist_onNickChange(ToxWindow *self, Tox *m, int32_t num, uint8_t *str, uint16_t len)
static void friendlist_onNickChange(ToxWindow *self, Tox *m, int32_t num, const char *nick, uint16_t len)
{
if (len > TOX_MAX_NAME_LENGTH || num >= max_friends_index)
return;
char tempname[TOX_MAX_NAME_LENGTH];
strcpy(tempname, nick);
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
str[len] = '\0';
strcpy(friends[num].name, str);
tempname[len] = '\0';
snprintf(friends[num].name, sizeof(friends[num].name), "%s", tempname);
friends[num].namelength = len;
sort_friendlist_index();
}
@ -159,16 +153,13 @@ static void friendlist_onStatusChange(ToxWindow *self, Tox *m, int32_t num, uint
friends[num].status = status;
}
static void friendlist_onStatusMessageChange(ToxWindow *self, int32_t num, uint8_t *str, uint16_t len)
static void friendlist_onStatusMessageChange(ToxWindow *self, int32_t num, const char *status, uint16_t len)
{
if (len > TOX_MAX_STATUSMESSAGE_LENGTH || num >= max_friends_index)
return;
str[len] = '\0';
snprintf(friends[num].statusmsg, sizeof(friends[num].statusmsg), "%s", str);
len = strlen(friends[num].statusmsg);
friends[num].statusmsg_len = len;
friends[num].statusmsg[len] = '\0';
snprintf(friends[num].statusmsg, sizeof(friends[num].statusmsg), "%s", status);
friends[num].statusmsg_len = strlen(friends[num].statusmsg);
}
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_t num, bool sort)
@ -185,17 +176,19 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_t num, bool sort)
friends[i].chatwin = -1;
friends[i].online = false;
friends[i].status = TOX_USERSTATUS_NONE;
friends[i].namelength = tox_get_name(m, num, friends[i].name);
friends[i].logging_on = (bool) user_settings->autolog == AUTOLOG_ON;
tox_get_client_id(m, num, friends[i].pub_key);
tox_get_client_id(m, num, (uint8_t *) friends[i].pub_key);
update_friend_last_online(i, tox_get_last_online(m, i));
if (friends[i].namelength == -1 || friends[i].name[0] == '\0') {
strcpy(friends[i].name, (uint8_t *) UNKNOWN_NAME);
char tempname[TOX_MAX_NAME_LENGTH] = {0};
int len = get_nick_truncate(m, tempname, num);
if (len == -1 || tempname[0] == '\0') {
strcpy(friends[i].name, UNKNOWN_NAME);
friends[i].namelength = strlen(UNKNOWN_NAME);
} else { /* Enforce toxic's maximum name length */
friends[i].namelength = MIN(friends[i].namelength, TOXIC_MAX_NAME_LENGTH);
friends[i].name[friends[i].namelength] = '\0';
friends[i].namelength = len;
snprintf(friends[i].name, sizeof(friends[i].name), "%s", tempname);
}
num_friends = tox_count_friendlist(m);
@ -212,7 +205,7 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_t num, bool sort)
}
static void friendlist_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t filenum,
uint64_t filesize, uint8_t *filename, uint16_t filename_len)
uint64_t filesize, const char *filename, uint16_t filename_len)
{
if (num >= max_friends_index)
return;
@ -223,12 +216,10 @@ static void friendlist_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, u
} else {
tox_file_send_control(m, num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0);
uint8_t nick[TOX_MAX_NAME_LENGTH];
int n_len = tox_get_name(m, num, nick);
n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH - 1);
nick[n_len] = '\0';
char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, num);
uint8_t msg[MAX_STR_SIZE];
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "* File transfer from %s failed: too many windows are open.", nick);
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, RED);
@ -237,7 +228,7 @@ static void friendlist_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, u
}
}
static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, uint8_t *group_pub_key)
static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, const char *group_pub_key)
{
if (num >= max_friends_index)
return;
@ -246,12 +237,10 @@ static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, uint8
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
friends[num].chatwin = add_window(m, new_chat(m, friends[num].num));
} else {
uint8_t nick[TOX_MAX_NAME_LENGTH];
int n_len = tox_get_name(m, num, nick);
n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH - 1);
nick[n_len] = '\0';
char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, num);
uint8_t msg[MAX_STR_SIZE];
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "* Group chat invite from %s failed: too many windows are open.", nick);
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, RED);
@ -296,10 +285,7 @@ static void delete_friend(Tox *m, int32_t f_num)
/* activates delete friend popup */
static void del_friend_activate(ToxWindow *self, Tox *m, int32_t f_num)
{
int x2, y2;
getmaxyx(self->window, y2, x2);
self->popup = newwin(3, 22 + TOXIC_MAX_NAME_LENGTH, 8, 8);
pendingdelete.popup = newwin(3, 22 + TOXIC_MAX_NAME_LENGTH - 1, 8, 8);
pendingdelete.active = true;
pendingdelete.num = f_num;
}
@ -310,30 +296,29 @@ static void del_friend_deactivate(ToxWindow *self, Tox *m, wint_t key)
if (key == 'y')
delete_friend(m, pendingdelete.num);
delwin(pendingdelete.popup);
memset(&pendingdelete, 0, sizeof(pendingdelete));
delwin(self->popup);
self->popup = NULL;
clear();
refresh();
}
static void draw_popup(ToxWindow *self, Tox *m)
static void draw_popup(void)
{
if (self->popup == NULL)
if (!pendingdelete.active)
return;
wattron(self->popup, A_BOLD);
box(self->popup, ACS_VLINE, ACS_HLINE);
wattroff(self->popup, A_BOLD);
wattron(pendingdelete.popup, A_BOLD);
box(pendingdelete.popup, ACS_VLINE, ACS_HLINE);
wattroff(pendingdelete.popup, A_BOLD);
wmove(self->popup, 1, 1);
wprintw(self->popup, "Delete contact ");
wattron(self->popup, A_BOLD);
wprintw(self->popup, "%s", friends[pendingdelete.num].name);
wattroff(self->popup, A_BOLD);
wprintw(self->popup, "? y/n");
wmove(pendingdelete.popup, 1, 1);
wprintw(pendingdelete.popup, "Delete contact ");
wattron(pendingdelete.popup, A_BOLD);
wprintw(pendingdelete.popup, "%s", friends[pendingdelete.num].name);
wattroff(pendingdelete.popup, A_BOLD);
wprintw(pendingdelete.popup, "? y/n");
wrefresh(self->popup);
wrefresh(pendingdelete.popup);
}
static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
@ -360,7 +345,7 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
friends[f].chatwin = add_window(m, new_chat(m, friends[f].num));
set_active_window(friends[f].chatwin);
} else {
uint8_t *msg = "* Warning: Too many windows are open.";
char *msg = "* Warning: Too many windows are open.";
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, RED);
alert_window(prompt, WINDOW_ALERT_1, true);
@ -383,16 +368,16 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
getmaxyx(self->window, y2, x2);
uint64_t cur_time = get_unix_time();
struct tm cur_loc_tm = *localtime(&cur_time);
struct tm cur_loc_tm = *localtime((const time_t*)&cur_time);
bool fix_statuses = x2 != self->x; /* true if window x axis has changed */
bool fix_statuses = x2 != self->x; /* true if window max x value has changed */
wattron(self->window, COLOR_PAIR(CYAN));
wprintw(self->window, " Open a chat window with the");
wattron(self->window, A_BOLD);
wprintw(self->window, " Enter ");
wattroff(self->window, A_BOLD);
wprintw(self->window, "key. Delete a friend with the");
wprintw(self->window, "key. Delete a contact with the");
wattron(self->window, A_BOLD);
wprintw(self->window, " Delete ");
wattroff(self->window, A_BOLD);
@ -408,7 +393,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
wattroff(self->window, A_BOLD);
wprintw(self->window, "%d/%d \n\n", nf, num_friends);
if ((y2 - FLIST_OFST) <= 0) /* don't allow division by zero */
if ((y2 - FLIST_OFST) <= 0)
return;
int selected_num = 0;
@ -473,16 +458,14 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
/* Reset friends[f].statusmsg on window resize */
if (fix_statuses) {
uint8_t statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH] = {'\0'};
char statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH];
pthread_mutex_lock(&Winthread.lock);
uint16_t s_len = tox_get_status_message(m, friends[f].num, statusmsg,
TOX_MAX_STATUSMESSAGE_LENGTH);
tox_get_status_message(m, friends[f].num, (uint8_t *) statusmsg, TOX_MAX_STATUSMESSAGE_LENGTH);
pthread_mutex_unlock(&Winthread.lock);
friends[f].statusmsg_len = s_len;
friends[f].statusmsg[s_len] = '\0';
snprintf(friends[f].statusmsg, sizeof(friends[f].statusmsg), "%s", statusmsg);
friends[f].statusmsg_len = strlen(friends[f].statusmsg);
}
/* Truncate note if it doesn't fit on one line */
@ -516,7 +499,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
if (last_seen != 0) {
int day_dist = (cur_loc_tm.tm_yday - friends[f].last_online.tm.tm_yday) % 365;
const uint8_t *hourmin = friends[f].last_online.hour_min_str;
const char *hourmin = friends[f].last_online.hour_min_str;
switch (day_dist) {
case 0:
@ -539,8 +522,6 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
}
self->x = x2;
wrefresh(self->window);
draw_popup(self, m);
if (num_friends) {
wmove(self->window, y2 - 1, 1);
@ -554,6 +535,9 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
for (i = 0; i < TOX_CLIENT_ID_SIZE; ++i)
wprintw(self->window, "%02X", friends[selected_num].pub_key[i] & 0xff);
}
wrefresh(self->window);
draw_popup();
}
void disable_chatwin(int32_t f_num)
@ -574,19 +558,17 @@ static void friendlist_onAv(ToxWindow *self, ToxAv *av, int call_index)
if (friends[id].chatwin == -1) {
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
friends[id].chatwin = add_window(m, new_chat(m, friends[id].num));
if (toxav_get_call_state(av, call_index) == av_CallStarting) /* Only open windows when call is incoming */
friends[id].chatwin = add_window(m, new_chat(m, friends[id].num));
} else {
uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'};
int n_len = tox_get_name(m, id, nick);
char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, friends[id].num);
n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH - 1);
nick[n_len] = '\0';
uint8_t msg[MAX_STR_SIZE];
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "Audio action from: %s!", nick);
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
uint8_t *errmsg = "* Warning: Too many windows are open.";
char *errmsg = "* Warning: Too many windows are open.";
line_info_add(prompt, NULL, NULL, NULL, errmsg, SYS_MSG, 0, RED);
alert_window(prompt, WINDOW_ALERT_0, true);
@ -601,6 +583,7 @@ ToxWindow new_friendlist(void)
memset(&ret, 0, sizeof(ret));
ret.active = true;
ret.is_friendlist = true;
ret.onKey = &friendlist_onKey;
ret.onDraw = &friendlist_onDraw;
@ -627,9 +610,10 @@ ToxWindow new_friendlist(void)
ret.onRequestTimeout = &friendlist_onAv;
ret.onPeerTimeout = &friendlist_onAv;
ret.call_index = -1;
ret.call_idx = -1;
ret.device_selection[0] = ret.device_selection[1] = -1;
#endif /* _SUPPORT_AUDIO */
strcpy(ret.name, "friends");
strcpy(ret.name, "contacts");
return ret;
}

View File

@ -29,29 +29,29 @@
#include "windows.h"
#include "file_senders.h"
#define TIME_STR_SIZE 16
struct FileReceiver {
uint8_t filenames[MAX_FILES][MAX_STR_SIZE];
char filenames[MAX_FILES][MAX_STR_SIZE];
FILE *files[MAX_FILES];
bool pending[MAX_FILES];
uint64_t size[MAX_FILES];
uint64_t last_progress[MAX_FILES];
uint32_t line_id[MAX_FILES];
};
struct LastOnline {
uint64_t last_on;
struct tm tm;
uint8_t hour_min_str[TIME_STR_SIZE]; /* holds 12-hour time string e.g. "10:43 PM" */
char hour_min_str[TIME_STR_SIZE]; /* holds 12/24-hour time string e.g. "10:43 PM" */
};
typedef struct {
uint8_t name[TOX_MAX_NAME_LENGTH];
uint16_t namelength;
uint8_t statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH];
char name[TOXIC_MAX_NAME_LENGTH];
int namelength;
char statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH];
uint16_t statusmsg_len;
uint8_t pending_groupchat[TOX_CLIENT_ID_SIZE];
uint8_t pub_key[TOX_CLIENT_ID_SIZE];
char groupchat_key[TOX_CLIENT_ID_SIZE];
bool groupchat_pending;
char pub_key[TOX_CLIENT_ID_SIZE];
int32_t num;
int chatwin;
bool active;

View File

@ -20,12 +20,9 @@
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include "toxic.h"
#include "windows.h"
@ -34,19 +31,22 @@
#include "log.h"
#include "line_info.h"
#include "dns.h"
#include "groupchat.h"
#include "prompt.h"
#include "help.h"
extern char *DATA_FILE;
extern ToxWindow *prompt;
extern ToxicFriend friends[MAX_FRIENDS_NUM];
extern uint8_t pending_frnd_requests[MAX_FRIENDS_NUM][TOX_CLIENT_ID_SIZE];
extern char pending_frnd_requests[MAX_FRIENDS_NUM][TOX_CLIENT_ID_SIZE];
extern uint8_t num_frnd_requests;
/* command functions */
void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
uint8_t *msg;
char *msg;
if (argc != 1) {
msg = "Invalid syntax.";
@ -68,7 +68,7 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
return;
}
int32_t friendnum = tox_add_friend_norequest(m, pending_frnd_requests[req]);
int32_t friendnum = tox_add_friend_norequest(m, (uint8_t *) pending_frnd_requests[req]);
if (friendnum == -1)
msg = "Failed to add friend.";
@ -90,10 +90,10 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
}
void cmd_add_helper(ToxWindow *self, Tox *m, uint8_t *id_bin, uint8_t *msg)
void cmd_add_helper(ToxWindow *self, Tox *m, char *id_bin, char *msg)
{
uint8_t *errmsg;
int32_t f_num = tox_add_friend(m, id_bin, msg, strlen(msg));
char *errmsg;
int32_t f_num = tox_add_friend(m, (uint8_t *) id_bin, (uint8_t *) msg, (uint16_t) strlen(msg));
switch (f_num) {
case TOX_FAERR_TOOLONG:
@ -135,7 +135,7 @@ void cmd_add_helper(ToxWindow *self, Tox *m, uint8_t *id_bin, uint8_t *msg)
void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
uint8_t *errmsg;
char *errmsg;
if (argc < 1) {
errmsg = "Invalid syntax.";
@ -144,10 +144,10 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
}
char *id = argv[1];
uint8_t msg[MAX_STR_SIZE];
char msg[MAX_STR_SIZE];
if (argc > 1) {
uint8_t *temp = argv[2];
char *temp = argv[2];
if (temp[0] != '\"') {
errmsg = "Message must be enclosed in quotes.";
@ -155,17 +155,18 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
return;
}
temp[strlen(++temp) - 1] = L'\0';
++temp;
temp[strlen(temp) - 1] = '\0';
snprintf(msg, sizeof(msg), "%s", temp);
} else {
uint8_t selfname[TOX_MAX_NAME_LENGTH];
uint16_t n_len = tox_get_self_name(m, selfname);
char selfname[TOX_MAX_NAME_LENGTH];
uint16_t n_len = tox_get_self_name(m, (uint8_t *) selfname);
selfname[n_len] = '\0';
snprintf(msg, sizeof(msg), "Hello, my name is %s. Care to Tox?", selfname);
}
uint8_t id_bin[TOX_FRIEND_ADDRESS_SIZE] = {0};
uint16_t id_len = strlen(id);
char id_bin[TOX_FRIEND_ADDRESS_SIZE] = {0};
uint16_t id_len = (uint16_t) strlen(id);
/* try to add tox ID */
if (id_len == 2 * TOX_FRIEND_ADDRESS_SIZE) {
@ -197,17 +198,13 @@ void cmd_clear(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[M
{
line_info_clear(self->chatwin->hst);
wclear(window);
if (self->is_prompt) {
int y2, x2;
getmaxyx(window, y2, x2);
wmove(self->chatwin->history, y2 - 1, 2);
}
endwin();
refresh();
}
void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
uint8_t *errmsg;
char *errmsg;
/* check arguments */
if (argc != 3) {
@ -216,9 +213,9 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
return;
}
char *ip = argv[1];
char *port = argv[2];
char *key = argv[3];
const char *ip = argv[1];
const char *port = argv[2];
const char *key = argv[3];
if (atoi(port) == 0) {
errmsg = "Invalid syntax.";
@ -226,15 +223,14 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
return;
}
uint8_t *binary_string = hex_string_to_bin(key);
tox_bootstrap_from_address(m, ip, TOX_ENABLE_IPV6_DEFAULT,
htons(atoi(port)), binary_string);
char *binary_string = hex_string_to_bin(key);
tox_bootstrap_from_address(m, ip, TOX_ENABLE_IPV6_DEFAULT, htons(atoi(port)), (uint8_t *) binary_string);
free(binary_string);
}
void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
uint8_t *errmsg;
char *errmsg;
if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
errmsg = " * Warning: Too many windows are open.";
@ -257,14 +253,14 @@ void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
return;
}
uint8_t msg[MAX_STR_SIZE];
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "Group chat created as %d.", groupnum);
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
}
void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
uint8_t *msg;
char *msg;
struct chatlog *log = self->chatwin->log;
if (argc == 0) {
@ -277,7 +273,7 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
return;
}
uint8_t *swch = argv[1];
char *swch = argv[1];
if (!strcmp(swch, "1") || !strcmp(swch, "on")) {
@ -285,8 +281,8 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
friends[self->num].logging_on = true;
log_enable(self->name, friends[self->num].pub_key, log);
} else if (self->is_prompt) {
uint8_t myid[TOX_FRIEND_ADDRESS_SIZE];
tox_get_address(m, myid);
char myid[TOX_FRIEND_ADDRESS_SIZE];
tox_get_address(m, (uint8_t *) myid);
log_enable(self->name, myid, log);
} else if (self->is_groupchat) {
log_enable(self->name, NULL, log);
@ -313,8 +309,8 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
char id[TOX_FRIEND_ADDRESS_SIZE * 2 + 1] = {0};
uint8_t address[TOX_FRIEND_ADDRESS_SIZE];
tox_get_address(m, address);
char address[TOX_FRIEND_ADDRESS_SIZE];
tox_get_address(m, (uint8_t *) address);
size_t i;
@ -329,7 +325,7 @@ void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
uint8_t *errmsg;
char *errmsg;
/* check arguments */
if (argc < 1) {
@ -338,13 +334,13 @@ void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
return;
}
uint8_t *nick = argv[1];
char *nick = argv[1];
int len = strlen(nick);
if (nick[0] == '\"') {
++nick;
len -= 2;
nick[len] = L'\0';
nick[len] = '\0';
}
if (!valid_nick(nick)) {
@ -354,18 +350,17 @@ void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
}
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
nick[len] = '\0';
nick[len] = L'\0';
tox_set_name(m, nick, len);
prompt_update_nick(prompt, nick, len);
tox_set_name(m, (uint8_t *) nick, (uint16_t) len);
prompt_update_nick(prompt, nick);
store_data(m, DATA_FILE);
}
void cmd_note(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
uint8_t *errmsg;
char *errmsg;
if (argc < 1) {
errmsg = "Wrong number of arguments.";
@ -373,7 +368,7 @@ void cmd_note(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
return;
}
uint8_t *msg = argv[1];
char *msg = argv[1];
if (msg[0] != '\"') {
errmsg = "Note must be enclosed in quotes.";
@ -381,59 +376,16 @@ void cmd_note(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
return;
}
msg[strlen(++msg) - 1] = L'\0';
uint16_t len = strlen(msg);
tox_set_status_message(m, msg, len);
prompt_update_statusmessage(prompt, msg, len);
++msg;
int len = strlen(msg) - 1;
msg[len] = '\0';
tox_set_status_message(m, (uint8_t *) msg, (uint16_t) len);
prompt_update_statusmessage(prompt, msg);
}
void cmd_prompt_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
struct history *hst = self->chatwin->hst;
line_info_clear(hst);
struct line_info *start = hst->line_start;
uint8_t *msg = "Global commands:";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
#ifdef _SUPPORT_AUDIO
#define NUMLINES 14
#else
#define NUMLINES 12
#endif
uint8_t lines[NUMLINES][MAX_STR_SIZE] = {
{ " /add <id> <msg> : Add friend with optional message" },
{ " /accept <n> : Accept friend request" },
{ " /connect <ip> <port> <key> : Manually connect to a DHT node" },
{ " /status <type> <msg> : Set status with optional note" },
{ " /note <msg> : Set a personal note" },
{ " /nick <nick> : Set your nickname" },
{ " /log <on> or <off> : Enable/disable logging" },
{ " /groupchat : Create a group chat" },
{ " /myid : Print your ID" },
{ " /help : Print this message again" },
{ " /clear : Clear window history" },
{ " /quit or /exit : Exit Toxic" },
#ifdef _SUPPORT_AUDIO
{ " /lsdev <type> : List devices where type: in|out" },
{ " /sdev <type> <id> : Set active device" },
#endif /* _SUPPORT_AUDIO */
};
int i;
for (i = 0; i < NUMLINES; ++i)
line_info_add(self, NULL, NULL, NULL, lines[i], SYS_MSG, 0, 0);
msg = " * Argument messages must be enclosed in quotation marks.";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
msg = " * Use ctrl-o and ctrl-p to navigate through the tabs.";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
line_info_add(self, NULL, NULL, NULL, "", SYS_MSG, 0, 0);
hst->line_start = start;
help_init_menu(self);
}
void cmd_quit(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
@ -443,8 +395,8 @@ void cmd_quit(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
uint8_t *msg = NULL;
uint8_t *errmsg;
char *msg = NULL;
char *errmsg;
if (argc >= 2) {
msg = argv[2];
@ -462,7 +414,6 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
char *status = argv[1];
str_to_lower(status);
int len = strlen(status);
TOX_USERSTATUS status_kind;
@ -482,9 +433,10 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
prompt_update_status(prompt, status_kind);
if (msg != NULL) {
msg[strlen(++msg) - 1] = L'\0'; /* remove opening and closing quotes */
uint16_t len = strlen(msg);
tox_set_status_message(m, msg, len);
prompt_update_statusmessage(prompt, msg, len);
++msg;
int len = strlen(msg) - 1;
msg[len] = '\0'; /* remove opening and closing quotes */
tox_set_status_message(m, (uint8_t *) msg, (uint16_t) len);
prompt_update_statusmessage(prompt, msg);
}
}

View File

@ -39,7 +39,7 @@ void cmd_prompt_help(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_ST
void cmd_quit(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_status(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
void cmd_add_helper(ToxWindow *self, Tox *m, uint8_t *id_bin, uint8_t *msg);
void cmd_add_helper(ToxWindow *self, Tox *m, char *id_bin, char *msg);
#ifdef _SUPPORT_AUDIO
void cmd_list_devices(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);

View File

@ -20,13 +20,14 @@
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* needed for strcasestr() and wcswidth() */
#endif
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <wchar.h>
#include "windows.h"
#include "toxic.h"
@ -38,9 +39,10 @@
#include "log.h"
#include "line_info.h"
#include "settings.h"
#include "input.h"
#include "help.h"
extern char *DATA_FILE;
extern int store_data(Tox *m, char *path);
static GroupChat groupchats[MAX_GROUPCHAT_NUM];
static int max_groupchat_index = 0;
@ -48,7 +50,7 @@ static int max_groupchat_index = 0;
extern struct user_settings *user_settings;
/* temporary until group chats have unique commands */
extern const uint8_t glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE];
extern const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE];
int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum)
{
@ -67,9 +69,6 @@ int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum)
groupchats[i].peer_name_lengths = malloc(sizeof(uint16_t));
groupchats[i].oldpeer_name_lengths = malloc(sizeof(uint16_t));
memset(groupchats[i].peer_names, 0, sizeof(uint8_t) * TOX_MAX_NAME_LENGTH);
memset(groupchats[i].peer_name_lengths, 0, sizeof(uint16_t));
memcpy(&groupchats[i].oldpeer_names[0], UNKNOWN_NAME, sizeof(UNKNOWN_NAME));
groupchats[i].oldpeer_name_lengths[0] = (uint16_t) strlen(UNKNOWN_NAME);
@ -92,15 +91,17 @@ void kill_groupchat_window(ToxWindow *self)
log_disable(ctx->log);
line_info_cleanup(ctx->hst);
delwin(ctx->linewin);
del_window(self);
delwin(ctx->history);
delwin(ctx->sidebar);
free(ctx->log);
free(ctx->hst);
free(ctx);
free(self->help);
del_window(self);
}
static void close_groupchat(ToxWindow *self, Tox *m, int groupnum)
{
set_active_window(0);
tox_del_groupchat(m, groupnum);
free(groupchats[groupnum].peer_names);
@ -120,60 +121,16 @@ static void close_groupchat(ToxWindow *self, Tox *m, int groupnum)
kill_groupchat_window(self);
}
static void print_groupchat_help(ToxWindow *self)
{
struct history *hst = self->chatwin->hst;
line_info_clear(hst);
struct line_info *start = hst->line_start;
uint8_t *msg = "Group chat commands:";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
#define NUMLINES 9
uint8_t lines[NUMLINES][MAX_STR_SIZE] = {
{ " /add <id> <msg> : Add friend with optional message" },
{ " /status <type> <msg>: Set your status with optional note" },
{ " /note <msg> : Set a personal note" },
{ " /nick <nick> : Set your nickname" },
{ " /groupchat : Create a group chat" },
{ " /log <on> or <off> : Enable/disable logging" },
{ " /close : Close the current group chat" },
{ " /help : Print this message again" },
{ " /help global : Show a list of global commands" },
};
int i;
for (i = 0; i < NUMLINES; ++i)
line_info_add(self, NULL, NULL, NULL, lines[i], SYS_MSG, 0, 0);
msg = " * Use Page Up/Page Down keys to scroll chat history";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
msg = " * Scroll peer list with the ctrl-] and ctrl-[ keys.";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
msg = " * Notice, some friends will be missing names while finding peers";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, 0);
line_info_add(self, NULL, NULL, NULL, "", SYS_MSG, 0, 0);
hst->line_start = start;
}
static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, int groupnum, int peernum,
uint8_t *msg, uint16_t len)
const char *msg, uint16_t len)
{
if (self->num != groupnum)
return;
msg[len] = '\0';
ChatContext *ctx = self->chatwin;
uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'};
int n_len = tox_group_peername(m, groupnum, peernum, nick);
char nick[TOX_MAX_NAME_LENGTH];
int n_len = tox_group_peername(m, groupnum, peernum, (uint8_t *) nick);
n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH - 1); /* enforce client max name length */
nick[n_len] = '\0';
@ -181,13 +138,13 @@ static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, int groupnum, int
int alert_type = WINDOW_ALERT_1;
bool beep = false;
uint8_t selfnick[TOX_MAX_NAME_LENGTH];
uint16_t sn_len = tox_get_self_name(m, selfnick);
char selfnick[TOX_MAX_NAME_LENGTH];
uint16_t sn_len = tox_get_self_name(m, (uint8_t *) selfnick);
selfnick[sn_len] = '\0';
int nick_clr = strcmp(nick, selfnick) == 0 ? GREEN : CYAN;
bool nick_match = strcasestr(msg, selfnick) && strncmp(selfnick, nick, TOXIC_MAX_NAME_LENGTH);
bool nick_match = strcasestr(msg, selfnick) && strncmp(selfnick, nick, TOXIC_MAX_NAME_LENGTH - 1);
if (nick_match) {
alert_type = WINDOW_ALERT_0;
@ -197,29 +154,27 @@ static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, int groupnum, int
alert_window(self, alert_type, beep);
uint8_t timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt);
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
line_info_add(self, timefrmt, nick, NULL, msg, IN_MSG, 0, nick_clr);
write_to_log(msg, nick, ctx->log, false);
}
static void groupchat_onGroupAction(ToxWindow *self, Tox *m, int groupnum, int peernum, uint8_t *action,
static void groupchat_onGroupAction(ToxWindow *self, Tox *m, int groupnum, int peernum, const char *action,
uint16_t len)
{
if (self->num != groupnum)
return;
action[len] = '\0';
ChatContext *ctx = self->chatwin;
/* check if message contains own name and alert appropriately */
int alert_type = WINDOW_ALERT_1;
bool beep = false;
uint8_t selfnick[TOX_MAX_NAME_LENGTH];
uint16_t n_len = tox_get_self_name(m, selfnick);
char selfnick[TOX_MAX_NAME_LENGTH];
uint16_t n_len = tox_get_self_name(m, (uint8_t *) selfnick);
selfnick[n_len] = '\0';
bool nick_match = strcasestr(action, selfnick);
@ -231,14 +186,13 @@ static void groupchat_onGroupAction(ToxWindow *self, Tox *m, int groupnum, int p
alert_window(self, alert_type, beep);
uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'};
n_len = tox_group_peername(m, groupnum, peernum, nick);
char nick[TOX_MAX_NAME_LENGTH];
n_len = tox_group_peername(m, groupnum, peernum, (uint8_t *) nick);
n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH - 1);
nick[n_len] = '\0';
uint8_t timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt);
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
line_info_add(self, timefrmt, nick, NULL, action, ACTION, 0, 0);
write_to_log(action, nick, ctx->log, true);
@ -265,14 +219,11 @@ static void copy_peernames(int gnum, uint8_t peerlist[][TOX_MAX_NAME_LENGTH], ui
exit_toxic_err("failed in copy_peernames", FATALERR_MEMORY);
}
memset(groupchats[gnum].peer_names, 0, sizeof(uint8_t) * npeers * N);
memset(groupchats[gnum].peer_name_lengths, 0, sizeof(uint16_t) * npeers);
uint16_t unknown_len = strlen(UNKNOWN_NAME);
uint16_t unknown_len = (uint16_t) strlen(UNKNOWN_NAME);
int i;
for (i = 0; i < npeers; ++i) {
if (string_is_empty(peerlist[i])) {
if (string_is_empty((char *) peerlist[i])) {
memcpy(&groupchats[gnum].peer_names[i * N], UNKNOWN_NAME, sizeof(UNKNOWN_NAME));
groupchats[gnum].peer_name_lengths[i] = unknown_len;
} else {
@ -292,18 +243,18 @@ static void copy_peernames(int gnum, uint8_t peerlist[][TOX_MAX_NAME_LENGTH], ui
}
static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnum, int peernum,
uint8_t change)
uint8_t change)
{
if (self->num != groupnum)
return;
if (groupnum > MAX_GROUPCHAT_NUM)
if (groupnum > max_groupchat_index)
return;
groupchats[groupnum].num_peers = tox_group_number_peers(m, groupnum);
int num_peers = groupchats[groupnum].num_peers;
if (peernum >= num_peers)
if (peernum > num_peers)
return;
/* get old peer name before updating name list */
@ -335,49 +286,49 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu
ChatContext *ctx = self->chatwin;
uint8_t *event;
uint8_t timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt);
char *event;
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
switch (change) {
case TOX_CHAT_CHANGE_PEER_ADD:
event = "has joined the room";
line_info_add(self, timefrmt, peername, NULL, event, CONNECTION, 0, GREEN);
write_to_log(event, peername, ctx->log, true);
line_info_add(self, timefrmt, (char *) peername, NULL, event, CONNECTION, 0, GREEN);
write_to_log(event, (char *) peername, ctx->log, true);
break;
case TOX_CHAT_CHANGE_PEER_DEL:
event = "has left the room";
line_info_add(self, timefrmt, oldpeername, NULL, event, CONNECTION, 0, 0);
line_info_add(self, timefrmt, (char *) oldpeername, NULL, event, CONNECTION, 0, 0);
if (groupchats[self->num].side_pos > 0)
--groupchats[self->num].side_pos;
write_to_log(event, oldpeername, ctx->log, true);
write_to_log(event, (char *) oldpeername, ctx->log, true);
break;
case TOX_CHAT_CHANGE_PEER_NAME:
event = " is now known as ";
line_info_add(self, timefrmt, oldpeername, peername, event, NAME_CHANGE, 0, 0);
line_info_add(self, timefrmt, (char *) oldpeername, (char *) peername, event, NAME_CHANGE, 0, 0);
uint8_t tmp_event[TOXIC_MAX_NAME_LENGTH * 2 + 32];
snprintf(tmp_event, sizeof(tmp_event), "is now known as %s", peername);
write_to_log(tmp_event, oldpeername, ctx->log, true);
char tmp_event[TOXIC_MAX_NAME_LENGTH * 2 + 32];
snprintf(tmp_event, sizeof(tmp_event), "is now known as %s", (char *) peername);
write_to_log(tmp_event, (char *) oldpeername, ctx->log, true);
break;
}
alert_window(self, WINDOW_ALERT_2, false);
}
static void send_group_action(ToxWindow *self, ChatContext *ctx, Tox *m, uint8_t *action)
static void send_group_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
{
if (action == NULL) {
wprintw(ctx->history, "Invalid syntax.\n");
return;
}
if (tox_group_action_send(m, self->num, action, strlen(action)) == -1) {
uint8_t *errmsg = " * Failed to send action.";
if (tox_group_action_send(m, self->num, (uint8_t *) action, strlen(action)) == -1) {
char *errmsg = " * Failed to send action.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, RED);
}
}
@ -389,196 +340,92 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
int x, y, y2, x2;
getyx(self->window, y, x);
getmaxyx(self->window, y2, x2);
int cur_len = 0;
if (ltr) {
if ( (ctx->len < MAX_STR_SIZE - 1) && (ctx->len < (x2 * (CHATBOX_HEIGHT - 1) - 1)) ) {
add_char_to_buf(ctx, key);
if (x2 <= 0)
return;
if (x == x2 - 1)
wmove(self->window, y + 1, 0);
else
wmove(self->window, y, x + MAX(1, wcwidth(key)));
}
if (self->help->active) {
help_onKey(self, key);
return;
}
} else { /* if (!ltr) */
if (ltr) { /* char is printable */
input_new_char(self, key, x, y, x2, y2);
return;
}
if (line_info_onKey(self, key))
return;
if (line_info_onKey(self, key))
return;
if (key == 0x107 || key == 0x8 || key == 0x7f) { /* BACKSPACE key: Remove character behind pos */
if (ctx->pos > 0) {
cur_len = MAX(1, wcwidth(ctx->line[ctx->pos - 1]));
del_char_buf_bck(ctx);
if (input_handle(self, key, x, y, x2, y2))
return;
if (x == 0)
wmove(self->window, y - 1, x2 - cur_len);
else
wmove(self->window, y, x - cur_len);
} else {
beep();
}
}
if (key == '\t') { /* TAB key: auto-completes peer name or command */
if (ctx->len > 0) {
int diff;
else if (key == KEY_DC) { /* DEL key: Remove character at pos */
if (ctx->pos != ctx->len)
del_char_buf_frnt(ctx);
else
beep();
}
else if (key == T_KEY_DISCARD) { /* CTRL-U: Delete entire line behind pos */
if (ctx->pos > 0) {
discard_buf(ctx);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
} else {
beep();
}
}
else if (key == T_KEY_KILL) { /* CTRL-K: Delete entire line in front of pos */
if (ctx->pos != ctx->len)
kill_buf(ctx);
else
beep();
}
else if (key == KEY_HOME || key == T_KEY_C_A) { /* HOME/C-a key: Move cursor to start of line */
if (ctx->pos > 0) {
ctx->pos = 0;
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
}
}
else if (key == KEY_END || key == T_KEY_C_E) { /* END/C-e key: move cursor to end of line */
if (ctx->pos != ctx->len) {
ctx->pos = ctx->len;
mv_curs_end(self->window, MAX(0, wcswidth(ctx->line, (CHATBOX_HEIGHT - 1)*x2)), y2, x2);
}
}
else if (key == KEY_LEFT) {
if (ctx->pos > 0) {
--ctx->pos;
cur_len = MAX(1, wcwidth(ctx->line[ctx->pos]));
if (x == 0)
wmove(self->window, y - 1, x2 - cur_len);
else
wmove(self->window, y, x - cur_len);
} else {
beep();
}
}
else if (key == KEY_RIGHT) {
if (ctx->pos < ctx->len) {
cur_len = MAX(1, wcwidth(ctx->line[ctx->pos]));
++ctx->pos;
if (x == x2 - 1)
wmove(self->window, y + 1, 0);
else
wmove(self->window, y, x + cur_len);
} else {
beep();
}
}
else if (key == KEY_UP) { /* fetches previous item in history */
fetch_hist_item(ctx, MOVE_UP);
mv_curs_end(self->window, ctx->len, y2, x2);
}
else if (key == KEY_DOWN) { /* fetches next item in history */
fetch_hist_item(ctx, MOVE_DOWN);
mv_curs_end(self->window, ctx->len, y2, x2);
}
else if (key == '\t') { /* TAB key: completes peer name */
if (ctx->len > 0) {
int diff;
if ((ctx->line[0] != '/') || (ctx->line[1] == 'm' && ctx->line[2] == 'e'))
diff = complete_line(ctx, groupchats[self->num].peer_names,
if ((ctx->line[0] != '/') || (ctx->line[1] == 'm' && ctx->line[2] == 'e'))
diff = complete_line(ctx, groupchats[self->num].peer_names,
groupchats[self->num].num_peers, TOX_MAX_NAME_LENGTH);
else
diff = complete_line(ctx, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
else
diff = complete_line(ctx, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
if (diff != -1) {
if (x + diff > x2 - 1) {
int ofst = (x + diff - 1) - (x2 - 1);
wmove(self->window, y + 1, ofst);
} else {
wmove(self->window, y, x + diff);
}
if (diff != -1) {
if (x + diff > x2 - 1) {
wmove(self->window, y, x + diff);
ctx->start += diff;
} else {
beep();
wmove(self->window, y, x + diff);
}
} else {
beep();
}
} else {
beep();
}
} else if (key == T_KEY_C_RB) { /* Scroll peerlist up and down one position */
int L = y2 - CHATBOX_HEIGHT - SDBAR_OFST;
/* Scroll peerlist up and down one position if list overflows window */
else if (key == T_KEY_C_LB) {
int L = y2 - CHATBOX_HEIGHT - SDBAR_OFST;
if (groupchats[self->num].side_pos < groupchats[self->num].num_peers - L)
++groupchats[self->num].side_pos;
} else if (key == T_KEY_C_LB) {
if (groupchats[self->num].side_pos > 0)
--groupchats[self->num].side_pos;
} else if (key == '\n') {
rm_trailing_spaces_buf(ctx);
if (groupchats[self->num].side_pos < groupchats[self->num].num_peers - L)
++groupchats[self->num].side_pos;
}
char line[MAX_STR_SIZE];
else if (key == T_KEY_C_RB) {
if (groupchats[self->num].side_pos > 0)
--groupchats[self->num].side_pos;
}
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
memset(&line, 0, sizeof(line));
/* RETURN key: Execute command or print line */
else if (key == '\n') {
rm_trailing_spaces_buf(ctx);
if (!string_is_empty(line))
add_line_to_hist(ctx);
uint8_t line[MAX_STR_SIZE];
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
memset(&line, 0, sizeof(line));
wclear(ctx->linewin);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
if (!string_is_empty(line))
add_line_to_hist(ctx);
if (line[0] == '/') {
if (strcmp(line, "/close") == 0) {
close_groupchat(self, m, self->num);
return;
} else if (strcmp(line, "/help") == 0) {
if (strcmp(line, "help global") == 0)
execute(ctx->history, self, m, "/help", GLOBAL_COMMAND_MODE);
else
print_groupchat_help(self);
} else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
send_group_action(self, ctx, m, line + strlen("/me "));
} else {
execute(ctx->history, self, m, line, GROUPCHAT_COMMAND_MODE);
}
} else if (!string_is_empty(line)) {
if (tox_group_message_send(m, self->num, line, strlen(line)) == -1) {
uint8_t *errmsg = " * Failed to send message.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, RED);
}
if (line[0] == '/') {
if (strcmp(line, "/close") == 0) {
close_groupchat(self, m, self->num);
return;
} else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
send_group_action(self, ctx, m, line + strlen("/me "));
} else {
execute(ctx->history, self, m, line, GROUPCHAT_COMMAND_MODE);
}
} else if (!string_is_empty(line)) {
if (tox_group_message_send(m, self->num, (uint8_t *) line, strlen(line)) == -1) {
char *errmsg = " * Failed to send message.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, RED);
}
reset_buf(ctx);
}
wclear(ctx->linewin);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
reset_buf(ctx);
}
}
static void groupchat_onDraw(ToxWindow *self, Tox *m)
{
int x2, y2;
getmaxyx(self->window, y2, x2);
@ -587,22 +434,14 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
line_info_print(self);
wclear(ctx->linewin);
scrollok(ctx->history, 0);
curs_set(1);
if (ctx->len > 0) {
uint8_t line[MAX_STR_SIZE];
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
reset_buf(ctx);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
} else {
mvwprintw(ctx->linewin, 1, 0, "%s", line);
}
}
if (ctx->len > 0)
mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]);
wclear(ctx->sidebar);
mvwhline(ctx->linewin, 0, 0, ACS_HLINE, x2);
mvwhline(self->window, y2 - CHATBOX_HEIGHT, 0, ACS_HLINE, x2);
mvwvline(ctx->sidebar, 0, 0, ACS_VLINE, y2 - CHATBOX_HEIGHT);
mvwaddch(ctx->sidebar, y2 - CHATBOX_HEIGHT, 0, ACS_BTEE);
@ -625,43 +464,51 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
int peer = i + groupchats[self->num].side_pos;
/* truncate nick to fit in side panel without modifying list */
uint8_t tmpnck[TOX_MAX_NAME_LENGTH];
char tmpnck[TOX_MAX_NAME_LENGTH];
memcpy(tmpnck, &groupchats[self->num].peer_names[peer * N], SIDEBAR_WIDTH - 2);
tmpnck[SIDEBAR_WIDTH - 2] = '\0';
wprintw(ctx->sidebar, "%s\n", tmpnck);
}
int y, x;
getyx(self->window, y, x);
(void) x;
int new_x = ctx->start ? x2 - 1 : wcswidth(ctx->line, ctx->pos);
wmove(self->window, y + 1, new_x);
wrefresh(self->window);
if (self->help->active)
help_onDraw(self);
}
static void groupchat_onInit(ToxWindow *self, Tox *m)
{
int x, y;
getmaxyx(self->window, y, x);
int x2, y2;
getmaxyx(self->window, y2, x2);
ChatContext *ctx = self->chatwin;
ctx->history = subwin(self->window, y - CHATBOX_HEIGHT + 1, x - SIDEBAR_WIDTH - 1, 0, 0);
ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x, y - CHATBOX_HEIGHT, 0);
ctx->sidebar = subwin(self->window, y - CHATBOX_HEIGHT + 1, SIDEBAR_WIDTH, 0, x - SIDEBAR_WIDTH);
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2 - SIDEBAR_WIDTH - 1, 0, 0);
ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
ctx->sidebar = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, SIDEBAR_WIDTH, 0, x2 - SIDEBAR_WIDTH);
ctx->hst = malloc(sizeof(struct history));
ctx->log = malloc(sizeof(struct chatlog));
ctx->hst = calloc(1, sizeof(struct history));
ctx->log = calloc(1, sizeof(struct chatlog));
if (ctx->log == NULL || ctx->hst == NULL)
exit_toxic_err("failed in groupchat_onInit", FATALERR_MEMORY);
memset(ctx->hst, 0, sizeof(struct history));
memset(ctx->log, 0, sizeof(struct chatlog));
line_info_init(ctx->hst);
print_groupchat_help(self);
if (user_settings->autolog == AUTOLOG_ON)
log_enable(self->name, NULL, ctx->log);
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
wmove(self->window, y - CURS_Y_OFFSET, 0);
scrollok(ctx->history, 0);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
}
ToxWindow new_group_chat(Tox *m, int groupnum)
@ -679,14 +526,17 @@ ToxWindow new_group_chat(Tox *m, int groupnum)
ret.onGroupNamelistChange = &groupchat_onGroupNamelistChange;
ret.onGroupAction = &groupchat_onGroupAction;
snprintf(ret.name, sizeof(ret.name), "Room #%d", groupnum);
snprintf(ret.name, sizeof(ret.name), "Group %d", groupnum);
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
Help *help = calloc(1, sizeof(Help));
if (chatwin == NULL)
if (chatwin == NULL || help == NULL)
exit_toxic_err("failed in new_group_chat", FATALERR_MEMORY);
ret.chatwin = chatwin;
ret.help = help;
ret.num = groupnum;
return ret;

View File

@ -28,7 +28,7 @@
#define SIDEBAR_WIDTH 16
#define SDBAR_OFST 2 /* Offset for the peer number box at the top of the statusbar */
#define MAX_GROUPCHAT_NUM MAX_WINDOWS_NUM
#define MAX_GROUPCHAT_NUM MAX_WINDOWS_NUM - 2
typedef struct {
int chatwin;

282
src/help.c Normal file
View File

@ -0,0 +1,282 @@
/* help.c
*
*
* Copyright (C) 2014 Toxic All Rights Reserved.
*
* This file is part of Toxic.
*
* Toxic is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Toxic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <string.h>
#include "windows.h"
#include "toxic.h"
#include "help.h"
#include "misc_tools.h"
#define HELP_MENU_HEIGHT 7
#define HELP_MENU_WIDTH 26
void help_init_menu(ToxWindow *self)
{
if (self->help->win)
delwin(self->help->win);
int y2, x2;
getmaxyx(self->window, y2, x2);
if (y2 < HELP_MENU_HEIGHT || x2 < HELP_MENU_WIDTH)
return;
self->help->win = newwin(HELP_MENU_HEIGHT, HELP_MENU_WIDTH, 3, 3);
self->help->active = true;
self->help->type = HELP_MENU;
}
static void help_exit(ToxWindow *self)
{
delwin(self->help->win);
memset(self->help, 0, sizeof(Help));
}
static void help_init_window(ToxWindow *self, int height, int width)
{
if (self->help->win)
delwin(self->help->win);
int y2, x2;
getmaxyx(stdscr, y2, x2);
height = MIN(height, y2);
width = MIN(width, x2);
self->help->win = newwin(height, width, 0, 0);
}
static void help_draw_menu(ToxWindow *self)
{
WINDOW *win = self->help->win;
wmove(win, 1, 1);
wattron(win, A_BOLD | COLOR_PAIR(RED));
wprintw(win, " Help Menu\n");
wattroff(win, A_BOLD | COLOR_PAIR(RED));
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, " G");
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, "lobal commands\n");
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, " C");
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, "hat commands\n");
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, " K");
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, "ey bindings\n");
wprintw(win, " E");
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, "x");
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, "it menu\n");
box(win, ACS_VLINE, ACS_HLINE);
wrefresh(win);
}
static void help_draw_bottom_menu(WINDOW *win)
{
int y2, x2;
getmaxyx(win, y2, x2);
(void) x2;
wmove(win, y2 - 2, 1);
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, " M");
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, "ain menu |");
wprintw(win, " E");
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, "x");
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
wprintw(win, "it");
}
static void help_draw_global(ToxWindow *self)
{
WINDOW *win = self->help->win;
wmove(win, 1, 1);
wattron(win, A_BOLD | COLOR_PAIR(RED));
wprintw(win, "Global Commands:\n");
wattroff(win, A_BOLD | COLOR_PAIR(RED));
wprintw(win, " /add <id> <msg> : Add contact with optional message\n");
wprintw(win, " /accept <n> : Accept friend request\n");
wprintw(win, " /connect <ip> <port> <key> : Manually connect to a DHT node\n");
wprintw(win, " /status <type> <msg> : Set status with optional note\n");
wprintw(win, " /note <msg> : Set a personal note\n");
wprintw(win, " /nick <nick> : Set your nickname\n");
wprintw(win, " /log <on> or <off> : Enable/disable logging\n");
wprintw(win, " /groupchat : Create a group chat\n");
wprintw(win, " /myid : Print your ID\n");
wprintw(win, " /clear : Clear window history\n");
wprintw(win, " /close : Close the current chat window\n");
wprintw(win, " /quit or /exit : Exit Toxic\n");
#ifdef _SUPPORT_AUDIO
wattron(win, A_BOLD);
wprintw(win, "\n Audio:\n");
wattroff(win, A_BOLD);
wprintw(win, " /lsdev <type> : List devices where type: in|out\n");
wprintw(win, " /sdev <type> <id> : Set active device\n");
#endif /* _SUPPORT_AUDIO */
help_draw_bottom_menu(win);
box(win, ACS_VLINE, ACS_HLINE);
wrefresh(win);
}
static void help_draw_chat(ToxWindow *self)
{
WINDOW *win = self->help->win;
wmove(win, 1, 1);
wattron(win, A_BOLD | COLOR_PAIR(RED));
wprintw(win, "Chat Commands:\n");
wattroff(win, A_BOLD | COLOR_PAIR(RED));
wprintw(win, " /invite <n> : Invite contact to a group chat\n");
wprintw(win, " /join : Join a pending group chat\n");
wprintw(win, " /sendfile <path> : Send a file\n");
wprintw(win, " /savefile <n> : Receive a file\n");
#ifdef _SUPPORT_AUDIO
wattron(win, A_BOLD);
wprintw(win, "\n Audio:\n");
wattroff(win, A_BOLD);
wprintw(win, " /call : Audio call\n");
wprintw(win, " /cancel : Cancel call\n");
wprintw(win, " /answer : Answer incomming call\n");
wprintw(win, " /reject : Reject incoming call\n");
wprintw(win, " /hangup : Hangup active call\n");
wprintw(win, " /sdev <type> <id> : Change active device\n");
wprintw(win, " /mute <type> : Mute active device if in call\n");
wprintw(win, " /sense <n> : VAD sensitivity treshold\n");
#endif /* _SUPPORT_AUDIO */
help_draw_bottom_menu(win);
box(win, ACS_VLINE, ACS_HLINE);
wrefresh(win);
}
static void help_draw_keys(ToxWindow *self)
{
WINDOW *win = self->help->win;
wmove(win, 1, 1);
wattron(win, A_BOLD | COLOR_PAIR(RED));
wprintw(win, "Key bindings:\n");
wattroff(win, A_BOLD | COLOR_PAIR(RED));
wprintw(win, " Ctrl+O and Ctrl+P : Navigate through the tabs\n");
wprintw(win, " Page Up and Page Down : Scroll window history one line\n");
wprintw(win, " Ctrl+F and Ctrl+V : Scroll window history half a page\n");
wprintw(win, " Ctrl+H : Move to the bottom of window history\n");
wprintw(win, " Ctrl+[ and Ctrl+] : Scroll peer list in groupchats\n");
help_draw_bottom_menu(win);
box(win, ACS_VLINE, ACS_HLINE);
wrefresh(win);
}
void help_onKey(ToxWindow *self, wint_t key)
{
switch(key) {
case 'x':
case T_KEY_ESC:
help_exit(self);
break;
case 'c':
#ifdef _SUPPORT_AUDIO
help_init_window(self, 19, 80);
#else
help_init_window(self, 9, 80);
#endif
self->help->type = HELP_CHAT;
break;
case 'g':
#ifdef _SUPPORT_AUDIO
help_init_window(self, 21, 80);
#else
help_init_window(self, 17, 80);
#endif
self->help->type = HELP_GLOBAL;
break;
case 'k':
help_init_window(self, 10, 80);
self->help->type = HELP_KEYS;
break;
case 'm':
help_init_menu(self);
self->help->type = HELP_MENU;
break;
}
}
void help_onDraw(ToxWindow *self)
{
curs_set(0);
switch(self->help->type) {
case HELP_MENU:
help_draw_menu(self);
return;
case HELP_CHAT:
help_draw_chat(self);
break;
case HELP_GLOBAL:
help_draw_global(self);
break;
case HELP_KEYS:
help_draw_keys(self);
break;
case HELP_GROUP:
break;
}
}

41
src/help.h Normal file
View File

@ -0,0 +1,41 @@
/* help.h
*
*
* Copyright (C) 2014 Toxic All Rights Reserved.
*
* This file is part of Toxic.
*
* Toxic is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Toxic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef _help_h
#define _help_h
#include "toxic.h"
#include "windows.h"
typedef enum {
HELP_MENU,
HELP_GLOBAL,
HELP_CHAT,
HELP_GROUP,
HELP_KEYS,
} HELP_TYPES;
void help_onDraw(ToxWindow *self);
void help_init_menu(ToxWindow *self);
void help_onKey(ToxWindow *self, wint_t key);
#endif /* #define _help_h */

248
src/input.c Normal file
View File

@ -0,0 +1,248 @@
/* input.c
*
*
* Copyright (C) 2014 Toxic All Rights Reserved.
*
* This file is part of Toxic.
*
* Toxic is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Toxic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* needed for wcwidth() */
#endif
#include <wchar.h>
#include "toxic.h"
#include "windows.h"
#include "misc_tools.h"
#include "toxic_strings.h"
#include "line_info.h"
/* add a char to input field and buffer */
void input_new_char(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y)
{
ChatContext *ctx = self->chatwin;
int cur_len = wcwidth(key);
/* this is the only place we need to do this check */
if (cur_len == -1) {
beep();
return;
}
if (add_char_to_buf(ctx, key) == -1) {
beep();
return;
}
if (x + cur_len >= mx_x) {
int s_len = wcwidth(ctx->line[ctx->start]);
ctx->start += 1 + MAX(0, cur_len - s_len);
}
}
/* delete a char via backspace key from input field and buffer */
static void input_backspace(ToxWindow *self, int x, int mx_x)
{
ChatContext *ctx = self->chatwin;
if (del_char_buf_bck(ctx) == -1) {
beep();
return;
}
int cur_len = wcwidth(ctx->line[ctx->pos - 1]);
int s_len = wcwidth(ctx->line[ctx->start - 1]);
if (ctx->start && (x >= mx_x - cur_len))
ctx->start = MAX(0, ctx->start - 1 + (s_len - cur_len));
else if (ctx->start && (ctx->pos == ctx->len))
ctx->start = MAX(0, ctx->start - cur_len);
else if (ctx->start)
ctx->start = MAX(0, ctx->start - cur_len);
}
/* delete a char via delete key from input field and buffer */
static void input_delete(ToxWindow *self)
{
if (del_char_buf_frnt(self->chatwin) == -1)
beep();
}
/* deletes entire line before cursor from input field and buffer */
static void input_discard(ToxWindow *self)
{
if (discard_buf(self->chatwin) == -1)
beep();
}
/* deletes entire line after cursor from input field and buffer */
static void input_kill(ChatContext *ctx)
{
if (kill_buf(ctx) == -1)
beep();
}
static void input_yank(ToxWindow *self, int x, int mx_x)
{
ChatContext *ctx = self->chatwin;
if (yank_buf(ctx) == -1) {
beep();
return;
}
int yank_cols = MAX(0, wcswidth(ctx->yank, ctx->yank_len));
if (x + yank_cols >= mx_x) {
int rmdr = MAX(0, (x + yank_cols) - mx_x);
int s_len = wcswidth(&ctx->line[ctx->start], rmdr);
ctx->start += s_len + 1;
}
}
/* moves cursor/line position to end of line in input field and buffer */
static void input_mv_end(ToxWindow *self, int y, int mx_x)
{
ChatContext *ctx = self->chatwin;
ctx->pos = ctx->len;
int wlen = wcswidth(ctx->line, sizeof(ctx->line));
ctx->start = MAX(0, 1 + (mx_x * (wlen / mx_x) - mx_x) + (wlen % mx_x));
}
/* moves cursor/line position to start of line in input field and buffer */
static void input_mv_home(ToxWindow *self)
{
ChatContext *ctx = self->chatwin;
if (ctx->pos <= 0)
return;
ctx->pos = 0;
ctx->start = 0;
}
/* moves cursor/line position left in input field and buffer */
static void input_mv_left(ToxWindow *self, int x, int mx_x)
{
ChatContext *ctx = self->chatwin;
if (ctx->pos <= 0)
return;
int cur_len = wcwidth(ctx->line[ctx->pos - 1]);
--ctx->pos;
int s_len = wcwidth(ctx->line[ctx->start - 1]);
if (ctx->start && (x >= mx_x - cur_len))
ctx->start = MAX(0, ctx->start - 1 + (s_len - cur_len));
else if (ctx->start && (ctx->pos == ctx->len))
ctx->start = MAX(0, ctx->start - cur_len);
else if (ctx->start)
ctx->start = MAX(0, ctx->start - cur_len);
}
/* moves cursor/line position right in input field and buffer */
static void input_mv_right(ToxWindow *self, int x, int mx_x)
{
ChatContext *ctx = self->chatwin;
if (ctx->pos >= ctx->len)
return;
++ctx->pos;
int cur_len = wcwidth(ctx->line[ctx->pos - 1]);
if (x + cur_len >= mx_x) {
int s_len = wcwidth(ctx->line[ctx->start]);
ctx->start += 1 + MAX(0, cur_len - s_len);
}
}
/* puts a line history item in input field and buffer */
static void input_history(ToxWindow *self, wint_t key, int mx_x)
{
ChatContext *ctx = self->chatwin;
fetch_hist_item(ctx, key);
ctx->start = mx_x * (ctx->len / mx_x);
}
/* Handles non-printable input keys that behave the same for all types of chat windows.
return true if key matches a function, false otherwise */
bool input_handle(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y)
{
bool match = true;
switch (key) {
case 0x7f:
case KEY_BACKSPACE:
input_backspace(self, x, mx_x);
break;
case KEY_DC:
input_delete(self);
break;
case T_KEY_DISCARD:
input_discard(self);
break;
case T_KEY_KILL:
input_kill(self->chatwin);
break;
case T_KEY_C_Y:
input_yank(self, x, mx_x);
break;
case KEY_HOME:
case T_KEY_C_A:
input_mv_home(self);
break;
case KEY_END:
case T_KEY_C_E:
input_mv_end(self, y, mx_x);
break;
case KEY_LEFT:
input_mv_left(self, x, mx_x);
break;
case KEY_RIGHT:
input_mv_right(self, x, mx_x);
break;
case KEY_UP:
case KEY_DOWN:
input_history(self, key, mx_x);
break;
default:
match = false;
break;
}
return match;
}

33
src/input.h Normal file
View File

@ -0,0 +1,33 @@
/* input.h
*
*
* Copyright (C) 2014 Toxic All Rights Reserved.
*
* This file is part of Toxic.
*
* Toxic is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Toxic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef _input_h
#define _input_h
/* add a char to input field and buffer for given chatcontext */
void input_new_char(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y);
/* Handles non-printable input keys that behave the same for all types of chat windows.
return true if key matches a function, false otherwise */
bool input_handle(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y);
#endif /* #define _input_h */

View File

@ -20,10 +20,6 @@
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
@ -38,33 +34,39 @@ extern struct user_settings *user_settings;
void line_info_init(struct history *hst)
{
hst->line_root = malloc(sizeof(struct line_info));
hst->line_root = calloc(1, sizeof(struct line_info));
if (hst->line_root == NULL)
exit_toxic_err("failed in line_info_init", FATALERR_MEMORY);
memset(hst->line_root, 0, sizeof(struct line_info));
hst->line_start = hst->line_root;
hst->line_end = hst->line_start;
hst->queue_sz = 0;
}
/* resets line_start */
/* resets line_start (page end) */
static void line_info_reset_start(ToxWindow *self, struct history *hst)
{
struct line_info *line = hst->line_end;
if (line->prev == NULL)
return;
int y2, x2;
getmaxyx(self->window, y2, x2);
struct line_info *line = hst->line_end;
uint16_t lncnt = 0;
int side_offst = self->is_groupchat ? SIDEBAR_WIDTH : 0;
int top_offst = self->is_chat ? 3 : 0;
int top_offst = self->is_chat || self->is_prompt ? 2 : 0;
int max_y = (y2 - CHATBOX_HEIGHT - top_offst);
while (line->prev && lncnt < max_y) {
int curlines = 0;
int nxtlines = line->newlines + (line->len / (x2 - side_offst));
do {
curlines += 1 + nxtlines;
line = line->prev;
lncnt += (1 + line->len / (x2 - side_offst));
}
nxtlines = line->newlines + (line->len / (x2 - side_offst));
} while (line->prev && curlines + nxtlines < max_y);
hst->line_start = line;
}
@ -78,6 +80,13 @@ void line_info_cleanup(struct history *hst)
free(tmp1);
tmp1 = tmp2;
}
int i;
for (i = 0; i < hst->queue_sz; ++i) {
if (hst->queue[i])
free(hst->queue[i]);
}
}
/* moves root forward and frees previous root */
@ -124,17 +133,15 @@ static struct line_info *line_info_ret_queue(struct history *hst)
}
/* creates new line_info line and puts it in the queue */
void line_info_add(ToxWindow *self, uint8_t *tmstmp, uint8_t *name1, uint8_t *name2, uint8_t *msg,
uint8_t type, uint8_t bold, uint8_t colour)
void line_info_add(ToxWindow *self, char *tmstmp, char *name1, char *name2, const char *msg, uint8_t type,
uint8_t bold, uint8_t colour)
{
struct history *hst = self->chatwin->hst;
struct line_info *new_line = malloc(sizeof(struct line_info));
struct line_info *new_line = calloc(1, sizeof(struct line_info));
if (new_line == NULL)
exit_toxic_err("failed in line_info_add", FATALERR_MEMORY);
memset(new_line, 0, sizeof(struct line_info));
int len = 1; /* there will always be a newline */
/* for type-specific formatting in print function */
@ -211,13 +218,14 @@ static void line_info_check_queue(ToxWindow *self)
int y, y2, x, x2;
getmaxyx(self->window, y2, x2);
getyx(self->chatwin->history, y, x);
(void) x;
if (x2 <= SIDEBAR_WIDTH)
return;
int offst = self->is_groupchat ? SIDEBAR_WIDTH : 0; /* offset width of groupchat sidebar */
int lines = 1 + line->newlines + (line->len / (x2 - offst));
int max_y = self->is_prompt ? y2 : y2 - CHATBOX_HEIGHT;
int max_y = y2 - CHATBOX_HEIGHT;
/* move line_start forward proportionate to the number of new lines */
if (y + lines - 1 >= max_y) {
@ -246,9 +254,6 @@ void line_info_print(ToxWindow *self)
int y2, x2;
getmaxyx(self->window, y2, x2);
if (self->is_prompt)
y2 = user_settings->history_size; /* temporary fix to make prompt scroll */
if (x2 <= SIDEBAR_WIDTH)
return;
@ -258,7 +263,6 @@ void line_info_print(ToxWindow *self)
wmove(win, 2, 0);
struct line_info *line = hst->line_start->next;
int offst = self->is_groupchat ? SIDEBAR_WIDTH : 0;
int numlines = 0;
while (line && numlines++ <= y2) {
@ -379,7 +383,7 @@ void line_info_print(ToxWindow *self)
line_info_print(self);
}
void line_info_set(ToxWindow *self, uint32_t id, uint8_t *msg)
void line_info_set(ToxWindow *self, uint32_t id, char *msg)
{
struct line_info *line = self->chatwin->hst->line_end;
@ -393,10 +397,10 @@ void line_info_set(ToxWindow *self, uint32_t id, uint8_t *msg)
}
}
static void line_info_goto_root(struct history *hst)
/* static void line_info_goto_root(struct history *hst)
{
hst->line_start = hst->line_root;
}
} */
static void line_info_scroll_up(struct history *hst)
{
@ -416,6 +420,7 @@ static void line_info_page_up(ToxWindow *self, struct history *hst)
{
int x2, y2;
getmaxyx(self->window, y2, x2);
(void) x2;
int jump_dist = y2 / 2;
int i;
@ -427,6 +432,7 @@ static void line_info_page_down(ToxWindow *self, struct history *hst)
{
int x2, y2;
getmaxyx(self->window, y2, x2);
(void) x2;
int jump_dist = y2 / 2;
int i;
@ -441,11 +447,11 @@ bool line_info_onKey(ToxWindow *self, wint_t key)
switch (key) {
/* TODO: Find good key bindings for all this stuff */
case T_KEY_C_H:
case T_KEY_C_F:
line_info_page_up(self, hst);
break;
case T_KEY_C_B:
case T_KEY_C_V:
line_info_page_down(self, hst);
break;
@ -459,12 +465,12 @@ bool line_info_onKey(ToxWindow *self, wint_t key)
/* case ?:
line_info_goto_root(hst);
break;
case ?:
line_info_reset_start(self, hst);
break; */
case T_KEY_C_H:
line_info_reset_start(self, hst);
break;
default:
match = false;
break;

View File

@ -27,8 +27,8 @@
#include "toxic.h"
#define MAX_HISTORY 10000
#define MIN_HISTORY 20
#define MAX_QUEUE 32
#define MIN_HISTORY 40
#define MAX_QUEUE 128
enum {
SYS_MSG,
@ -41,10 +41,10 @@ enum {
} LINE_TYPE;
struct line_info {
uint8_t timestamp[TIME_STR_SIZE];
uint8_t name1[TOXIC_MAX_NAME_LENGTH];
uint8_t name2[TOXIC_MAX_NAME_LENGTH];
uint8_t msg[TOX_MAX_MESSAGE_LENGTH];
char timestamp[TIME_STR_SIZE];
char name1[TOXIC_MAX_NAME_LENGTH];
char name2[TOXIC_MAX_NAME_LENGTH];
char msg[TOX_MAX_MESSAGE_LENGTH];
uint8_t type;
uint8_t bold;
uint8_t colour;
@ -68,7 +68,7 @@ struct history {
};
/* creates new line_info line and puts it in the queue */
void line_info_add(ToxWindow *self, uint8_t *tmstmp, uint8_t *name1, uint8_t *name2, uint8_t *msg,
void line_info_add(ToxWindow *self, char *tmstmp, char *name1, char *name2, const char *msg,
uint8_t type, uint8_t bold, uint8_t colour);
/* Prints a section of history starting at line_start */
@ -81,7 +81,7 @@ void line_info_cleanup(struct history *hst);
void line_info_clear(struct history *hst);
/* puts msg in specified line_info msg buffer */
void line_info_set(ToxWindow *self, uint32_t id, uint8_t *msg);
void line_info_set(ToxWindow *self, uint32_t id, char *msg);
void line_info_init(struct history *hst);
bool line_info_onKey(ToxWindow *self, wint_t key); /* returns true if key is a match */

View File

@ -20,10 +20,6 @@
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <time.h>
@ -38,7 +34,7 @@
extern struct user_settings *user_settings;
/* Creates/fetches log file by appending to the config dir the name and a pseudo-unique identity */
void init_logging_session(uint8_t *name, uint8_t *key, struct chatlog *log)
void init_logging_session(char *name, char *key, struct chatlog *log)
{
if (!log->log_on)
return;
@ -50,7 +46,7 @@ void init_logging_session(uint8_t *name, uint8_t *key, struct chatlog *log)
int path_len = strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(name);
/* use first 4 digits of key as log ident. If no key use a timestamp */
uint8_t ident[32];
char ident[32];
if (key != NULL) {
path_len += (KEY_IDENT_DIGITS * 2 + 5);
@ -69,7 +65,7 @@ void init_logging_session(uint8_t *name, uint8_t *key, struct chatlog *log)
return;
}
uint8_t log_path[MAX_STR_SIZE];
char log_path[MAX_STR_SIZE];
snprintf(log_path, MAX_STR_SIZE, "%s%s%s-%s.log",
user_config_dir, CONFIGDIR, name, ident);
@ -86,7 +82,7 @@ void init_logging_session(uint8_t *name, uint8_t *key, struct chatlog *log)
fprintf(log->file, "\n*** NEW SESSION ***\n\n");
}
void write_to_log(const uint8_t *msg, uint8_t *name, struct chatlog *log, bool event)
void write_to_log(const char *msg, char *name, struct chatlog *log, bool event)
{
if (!log->log_on)
return;
@ -96,7 +92,7 @@ void write_to_log(const uint8_t *msg, uint8_t *name, struct chatlog *log, bool e
return;
}
uint8_t name_frmt[TOXIC_MAX_NAME_LENGTH + 3];
char name_frmt[TOXIC_MAX_NAME_LENGTH + 3];
if (event)
snprintf(name_frmt, sizeof(name_frmt), "* %s", name);
@ -104,7 +100,7 @@ void write_to_log(const uint8_t *msg, uint8_t *name, struct chatlog *log, bool e
snprintf(name_frmt, sizeof(name_frmt), "%s:", name);
const char *t = user_settings->time == TIME_12 ? "%Y/%m/%d [%I:%M:%S %p]" : "%Y/%m/%d [%H:%M:%S]";
uint8_t s[MAX_STR_SIZE];
char s[MAX_STR_SIZE];
strftime(s, MAX_STR_SIZE, t, get_time());
fprintf(log->file, "%s %s %s\n", s, name_frmt, msg);
@ -116,7 +112,7 @@ void write_to_log(const uint8_t *msg, uint8_t *name, struct chatlog *log, bool e
}
}
void log_enable(uint8_t *name, uint8_t *key, struct chatlog *log)
void log_enable(char *name, char *key, struct chatlog *log)
{
log->log_on = true;

View File

@ -33,13 +33,13 @@ struct chatlog {
};
/* Creates/fetches log file by appending to the config dir the name and a pseudo-unique identity */
void init_logging_session(uint8_t *name, uint8_t *key, struct chatlog *log);
void init_logging_session(char *name, char *key, struct chatlog *log);
/* formats/writes line to log file */
void write_to_log(const uint8_t *msg, uint8_t *name, struct chatlog *log, bool event);
void write_to_log(const char *msg, char *name, struct chatlog *log, bool event);
/* enables logging for specified log and creates/fetches file if necessary */
void log_enable(uint8_t *name, uint8_t *key, struct chatlog *log);
void log_enable(char *name, char *key, struct chatlog *log);
/* disables logging for specified log and closes file */
void log_disable(struct chatlog *log);

View File

@ -20,11 +20,8 @@
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <limits.h>
@ -49,19 +46,49 @@ uint64_t get_unix_time(void)
return current_unix_time;
}
/* Returns 1 if connection has timed out, 0 otherwise */
int timed_out(uint64_t timestamp, uint64_t curtime, uint64_t timeout)
{
return timestamp + timeout <= curtime;
}
/* Get the current local time */
struct tm *get_time(void)
{
struct tm *timeinfo;
uint64_t t = get_unix_time();
timeinfo = localtime(&t);
timeinfo = localtime((const time_t*) &t);
return timeinfo;
}
void get_time_str(uint8_t *buf)
/*Puts the current time in buf in the format of [HH:mm:ss] */
void get_time_str(char *buf, int bufsize)
{
if (user_settings->timestamps == TIMESTAMPS_OFF) {
buf[0] = '\0';
return;
}
const char *t = user_settings->time == TIME_12 ? "[%-I:%M:%S] " : "[%H:%M:%S] ";
strftime(buf, TIME_STR_SIZE, t, get_time());
strftime(buf, bufsize, t, get_time());
}
/* Converts seconds to string in format HH:mm:ss; truncates hours and minutes when necessary */
void get_elapsed_time_str(char *buf, int bufsize, uint64_t secs)
{
if (!secs)
return;
long int seconds = secs % 60;
long int minutes = (secs % 3600) / 60;
long int hours = secs / 3600;
if (!minutes && !hours)
snprintf(buf, bufsize, "%.2ld", seconds);
else if (!hours)
snprintf(buf, bufsize, "%ld:%.2ld", minutes, seconds);
else
snprintf(buf, bufsize, "%ld:%.2ld:%.2ld", hours, minutes, seconds);
}
char *hex_string_to_bin(const char *hex_string)
@ -69,11 +96,8 @@ char *hex_string_to_bin(const char *hex_string)
size_t len = strlen(hex_string);
char *val = malloc(len);
if (val == NULL) {
endwin();
fprintf(stderr, "malloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
if (val == NULL)
exit_toxic_err("failed in hex_string_to_bin", FATALERR_MEMORY);
size_t i;
@ -89,88 +113,34 @@ int string_is_empty(char *string)
return string[0] == '\0';
}
/* convert a multibyte string to a wide character string (must provide buffer) */
int mbs_to_wcs_buf(wchar_t *buf, const uint8_t *string, size_t n)
/* convert a multibyte string to a wide character string and puts in buf. */
int mbs_to_wcs_buf(wchar_t *buf, const char *string, size_t n)
{
size_t len = mbstowcs(NULL, string, 0) + 1;
if (n < len)
return -1;
if ((len = mbstowcs(buf, string, n)) == (size_t) - 1)
if ((len = mbstowcs(buf, string, n)) == (size_t) -1)
return -1;
return len;
}
/* converts wide character string into a multibyte string.
Same thing as wcs_to_mbs() but caller must provide its own buffer */
int wcs_to_mbs_buf(uint8_t *buf, const wchar_t *string, size_t n)
/* converts wide character string into a multibyte string and puts in buf. */
int wcs_to_mbs_buf(char *buf, const wchar_t *string, size_t n)
{
size_t len = wcstombs(NULL, string, 0) + 1;
if (n < len)
return -1;
if ((len = wcstombs(buf, string, n)) == (size_t) - 1)
if ((len = wcstombs(buf, string, n)) == (size_t) -1)
return -1;
return len;
}
/* convert wide characters to multibyte string: string returned must be freed */
uint8_t *wcs_to_mbs(wchar_t *string)
{
uint8_t *ret = NULL;
size_t len = wcstombs(NULL, string, 0);
if (len != (size_t) - 1) {
ret = malloc(++len);
if (ret != NULL) {
if (wcstombs(ret, string, len) == (size_t) - 1)
return NULL;
}
} else {
ret = malloc(2);
if (ret != NULL) {
ret[0] = ' ';
ret[1] = '\0';
}
}
if (ret == NULL) {
endwin();
fprintf(stderr, "malloc() failed. Aborting...\n");
exit(EXIT_FAILURE);
}
return ret;
}
/* convert a wide char to multibyte string */
char *wc_to_char(wchar_t ch)
{
static char ret[MB_LEN_MAX + 1];
int len = wctomb(ret, ch);
if (len == -1) {
ret[0] = ' ';
ret[1] = '\0';
} else {
ret[len] = '\0';
}
return ret;
}
/* Returns 1 if connection has timed out, 0 otherwise */
int timed_out(uint64_t timestamp, uint64_t curtime, uint64_t timeout)
{
return timestamp + timeout <= curtime;
}
/* Colours the window tab according to type. Beeps if is_beep is true */
void alert_window(ToxWindow *self, int type, bool is_beep)
{
@ -205,7 +175,7 @@ int qsort_strcasecmp_hlpr(const void *nick1, const void *nick2)
- cannot start with a space
- must not contain a forward slash (for logfile naming purposes)
- must not contain contiguous spaces */
int valid_nick(uint8_t *nick)
int valid_nick(char *nick)
{
if (!nick[0] || nick[0] == ' ')
return 0;
@ -223,39 +193,44 @@ int valid_nick(uint8_t *nick)
return 1;
}
/* Moves cursor to the end of the line in given window */
void mv_curs_end(WINDOW *w, size_t len, int max_y, int max_x)
{
int end_y = (len / max_x) + (max_y - CURS_Y_OFFSET);
int end_x = len % max_x;
wmove(w, end_y, end_x);
}
/* gets base file name from path or original file name if no path is supplied */
void get_file_name(uint8_t *namebuf, uint8_t *pathname)
void get_file_name(char *namebuf, int bufsize, const char *pathname)
{
int idx = strlen(pathname) - 1;
while (idx >= 0 && pathname[idx] == '/')
pathname[idx--] = '\0';
char tmpname[MAX_STR_SIZE];
snprintf(tmpname, sizeof(tmpname), "%s", pathname);
uint8_t *filename = strrchr(pathname, '/');
while (idx >= 0 && pathname[idx] == '/')
tmpname[idx--] = '\0';
char *filename = strrchr(tmpname, '/');
if (filename != NULL) {
if (!strlen(++filename))
filename = pathname;
filename = tmpname;
} else {
filename = pathname;
filename = tmpname;
}
snprintf(namebuf, MAX_STR_SIZE, "%s", filename);
snprintf(namebuf, bufsize, "%s", filename);
}
/* converts str to all lowercase */
void str_to_lower(uint8_t *str)
void str_to_lower(char *str)
{
int i;
for (i = 0; str[i]; ++i)
str[i] = tolower(str[i]);
}
/* puts friendnum's nick in buf, truncating at TOXIC_MAX_NAME_LENGTH if necessary.
Returns nick len on success, -1 on failure */
int get_nick_truncate(Tox *m, char *buf, int friendnum)
{
int len = tox_get_name(m, friendnum, (uint8_t *) buf);
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
buf[len] = '\0';
return len;
}

View File

@ -39,8 +39,11 @@ char *hex_string_to_bin(const char *hex_string);
/* get the current unix time */
uint64_t get_unix_time(void);
/*Puts the current time in buf in the format of [Hour:Min:Sec] */
void get_time_str(uint8_t *buf);
/*Puts the current time in buf in the format of [HH:mm:ss] */
void get_time_str(char *buf, int bufsize);
/* Converts seconds to string in format HH:mm:ss; truncates hours and minutes when necessary */
void get_elapsed_time_str(char *buf, int bufsize, uint64_t secs);
/* get the current local time */
struct tm *get_time(void);
@ -52,17 +55,13 @@ void update_unix_time(void);
int string_is_empty(char *string);
/* convert a multibyte string to a wide character string (must provide buffer) */
int char_to_wcs_buf(wchar_t *buf, const uint8_t *string, size_t n);
int char_to_wcs_buf(wchar_t *buf, const char *string, size_t n);
/* converts wide character string into a multibyte string.
Same thing as wcs_to_mbs() but caller must provide its own buffer */
int wcs_to_mbs_buf(uint8_t *buf, const wchar_t *string, size_t n);
/* converts wide character string into a multibyte string and puts in buf. */
int wcs_to_mbs_buf(char *buf, const wchar_t *string, size_t n);
/* convert wide characters to multibyte string: string returned must be free'd */
uint8_t *wcs_to_mbs(wchar_t *string);
/* convert a wide char to multibyte char */
char *wc_to_char(wchar_t ch);
/* convert a multibyte string to a wide character string and puts in buf) */
int mbs_to_wcs_buf(wchar_t *buf, const char *string, size_t n);
/* Returns 1 if connection has timed out, 0 otherwise */
int timed_out(uint64_t timestamp, uint64_t timeout, uint64_t curtime);
@ -78,15 +77,16 @@ int qsort_strcasecmp_hlpr(const void *nick1, const void *nick2);
- cannot start with a space
- must not contain a forward slash (for logfile naming purposes)
- must not contain contiguous spaces */
int valid_nick(uint8_t *nick);
/* Moves the cursor to the end of the line in given window */
void mv_curs_end(WINDOW *w, size_t len, int max_y, int max_x);
int valid_nick(char *nick);
/* gets base file name from path or original file name if no path is supplied */
void get_file_name(uint8_t *namebuf, uint8_t *pathname);
void get_file_name(char *namebuf, int bufsize, const char *pathname);
/* converts str to all uppercase */
void str_to_lower(uint8_t *str);
/* converts str to all lowercase */
void str_to_lower(char *str);
/* puts friendnum's nick in buf, truncating at TOXIC_MAX_NAME_LENGTH if necessary.
Returns nick len on success, -1 on failure */
int get_nick_truncate(Tox *m, char *buf, int friendnum);
#endif /* #define _misc_tools_h */

View File

@ -20,12 +20,13 @@
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* needed for wcswidth() */
#endif
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "toxic.h"
#include "windows.h"
@ -36,16 +37,18 @@
#include "log.h"
#include "line_info.h"
#include "settings.h"
#include "input.h"
#include "help.h"
uint8_t pending_frnd_requests[MAX_FRIENDS_NUM][TOX_CLIENT_ID_SIZE] = {0};
uint8_t num_frnd_requests = 0;
char pending_frnd_requests[MAX_FRIENDS_NUM][TOX_CLIENT_ID_SIZE];
uint16_t num_frnd_requests = 0;
extern ToxWindow *prompt;
struct _Winthread Winthread;
extern struct user_settings *user_settings;
/* Array of global command names used for tab completion. */
const uint8_t glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
{ "/accept" },
{ "/add" },
{ "/clear" },
@ -70,8 +73,29 @@ const uint8_t glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
#endif /* _SUPPORT_AUDIO */
};
void kill_prompt_window(ToxWindow *self)
{
ChatContext *ctx = self->chatwin;
StatusBar *statusbar = self->stb;
log_disable(ctx->log);
line_info_cleanup(ctx->hst);
delwin(ctx->linewin);
delwin(ctx->history);
delwin(statusbar->topline);
free(ctx->log);
free(ctx->hst);
free(ctx);
free(self->help);
free(statusbar);
del_window(self);
}
/* Updates own nick in prompt statusbar */
void prompt_update_nick(ToxWindow *prompt, uint8_t *nick, uint16_t len)
void prompt_update_nick(ToxWindow *prompt, char *nick)
{
StatusBar *statusbar = prompt->stb;
snprintf(statusbar->nick, sizeof(statusbar->nick), "%s", nick);
@ -79,7 +103,7 @@ void prompt_update_nick(ToxWindow *prompt, uint8_t *nick, uint16_t len)
}
/* Updates own statusmessage in prompt statusbar */
void prompt_update_statusmessage(ToxWindow *prompt, uint8_t *statusmsg, uint16_t len)
void prompt_update_statusmessage(ToxWindow *prompt, char *statusmsg)
{
StatusBar *statusbar = prompt->stb;
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
@ -102,7 +126,7 @@ void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected)
/* Adds friend request to pending friend requests.
Returns request number on success, -1 if queue is full or other error. */
static int add_friend_request(const uint8_t *public_key)
static int add_friend_request(const char *public_key)
{
if (num_frnd_requests >= MAX_FRIENDS_NUM)
return -1;
@ -128,184 +152,87 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
ChatContext *ctx = self->chatwin;
int x, y, y2, x2;
getyx(ctx->history, y, x);
getmaxyx(ctx->history, y2, x2);
getyx(self->window, y, x);
getmaxyx(self->window, y2, x2);
if (ltr) {
if (ctx->len < (MAX_STR_SIZE - 1)) {
add_char_to_buf(ctx, key);
}
} else { /* if (!ltr) */
if (x2 <= 0)
return;
/* BACKSPACE key: Remove one character from line */
if (key == 0x107 || key == 0x8 || key == 0x7f) {
if (ctx->pos > 0) {
del_char_buf_bck(ctx);
wmove(ctx->history, y, x - 1); /* not necessary but fixes a display glitch */
} else {
beep();
}
}
/* ignore non-menu related input if active */
if (self->help->active) {
help_onKey(self, key);
return;
}
else if (key == KEY_DC) { /* DEL key: Remove character at pos */
if (ctx->pos != ctx->len) {
del_char_buf_frnt(ctx);
} else {
beep();
}
}
if (ltr) { /* char is printable */
input_new_char(self, key, x, y, x2, y2);
return;
}
else if (key == T_KEY_DISCARD) { /* CTRL-U: Delete entire line behind pos */
if (ctx->pos > 0) {
wmove(ctx->history, ctx->orig_y, X_OFST);
wclrtobot(ctx->history);
discard_buf(ctx);
} else {
beep();
}
}
if (line_info_onKey(self, key))
return;
else if (key == T_KEY_KILL) { /* CTRL-K: Delete entire line in front of pos */
if (ctx->len != ctx->pos)
kill_buf(ctx);
else
beep();
}
input_handle(self, key, x, y, x2, y2);
else if (key == KEY_HOME || key == T_KEY_C_A) { /* HOME/C-a key: Move cursor to start of line */
if (ctx->pos != 0)
ctx->pos = 0;
}
if (key == '\t') { /* TAB key: auto-completes command */
if (ctx->len > 1 && ctx->line[0] == '/') {
int diff = complete_line(ctx, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
else if (key == KEY_END || key == T_KEY_C_E) { /* END/C-e key: move cursor to end of line */
if (ctx->pos != ctx->len)
ctx->pos = ctx->len;
}
else if (key == KEY_LEFT) {
if (ctx->pos > 0)
--ctx->pos;
else
beep();
}
else if (key == KEY_RIGHT) {
if (ctx->pos < ctx->len)
++ctx->pos;
else
beep();
}
else if (key == KEY_UP) { /* fetches previous item in history */
wmove(ctx->history, ctx->orig_y, X_OFST);
fetch_hist_item(ctx, MOVE_UP);
/* adjust line y origin appropriately when window scrolls down */
if (ctx->at_bottom && ctx->len >= x2 - X_OFST) {
int px2 = ctx->len >= x2 ? x2 : x2 - X_OFST;
int p_ofst = px2 != x2 ? 0 : X_OFST;
if (px2 <= 0)
return;
int k = ctx->orig_y + ((ctx->len + p_ofst) / px2);
if (k >= y2) {
--ctx->orig_y;
if (diff != -1) {
if (x + diff > x2 - 1) {
wmove(self->window, y, x + diff);
ctx->start += diff;
} else {
wmove(self->window, y, x + diff);
}
}
}
else if (key == KEY_DOWN) { /* fetches next item in history */
wmove(ctx->history, ctx->orig_y, X_OFST);
fetch_hist_item(ctx, MOVE_DOWN);
}
else if (key == '\t') { /* TAB key: completes command */
if (ctx->len > 1 && ctx->line[0] == '/') {
if (complete_line(ctx, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE) == -1)
beep();
} else {
beep();
}
} else {
beep();
}
} else if (key == '\n') {
rm_trailing_spaces_buf(ctx);
/* RETURN key: execute command */
else if (key == '\n') {
rm_trailing_spaces_buf(ctx);
char line[MAX_STR_SIZE] = {0};
wprintw(ctx->history, "\n");
uint8_t line[MAX_STR_SIZE] = {0};
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
memset(&line, 0, sizeof(line));
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
memset(&line, 0, sizeof(line));
if (!string_is_empty(line))
add_line_to_hist(ctx);
if (!string_is_empty(line))
add_line_to_hist(ctx);
line_info_add(self, NULL, NULL, NULL, line, PROMPT, 0, 0);
execute(ctx->history, self, m, line, GLOBAL_COMMAND_MODE);
line_info_add(self, NULL, NULL, NULL, line, PROMPT, 0, 0);
execute(ctx->history, self, m, line, GLOBAL_COMMAND_MODE);
reset_buf(ctx);
}
wclear(ctx->linewin);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
reset_buf(ctx);
}
}
static void prompt_onDraw(ToxWindow *self, Tox *m)
{
int x2, y2;
getmaxyx(self->window, y2, x2);
ChatContext *ctx = self->chatwin;
int x, y, x2, y2;
getyx(ctx->history, y, x);
getmaxyx(ctx->history, y2, x2);
line_info_print(self);
wclear(ctx->linewin);
curs_set(1);
scrollok(ctx->history, 1);
line_info_print(self);
/* if len is >= screen width offset max x by X_OFST to account for prompt char */
int px2 = ctx->len >= x2 ? x2 : x2 - X_OFST;
if (px2 <= 0)
return;
/* len offset to account for prompt char (0 if len is < width of screen) */
int p_ofst = px2 != x2 ? 0 : X_OFST;
if (ctx->len > 0) {
uint8_t line[MAX_STR_SIZE];
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
reset_buf(ctx);
else
mvwprintw(ctx->history, ctx->orig_y, X_OFST, line);
int k = ctx->orig_y + ((ctx->len + p_ofst) / px2);
ctx->at_bottom = k == y2 - 1;
bool botm = k == y2;
bool edge = (ctx->len + p_ofst) % px2 == 0;
/* move point of line origin up when input scrolls screen down */
if (edge && botm)
--ctx->orig_y;
} else { /* Mark point of origin for new line */
ctx->orig_y = y;
}
wattron(ctx->history, COLOR_PAIR(GREEN));
mvwprintw(ctx->history, ctx->orig_y, 0, "$ ");
wattroff(ctx->history, COLOR_PAIR(GREEN));
if (ctx->len > 0)
mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]);
StatusBar *statusbar = self->stb;
werase(statusbar->topline);
mvwhline(statusbar->topline, 1, 0, ACS_HLINE, x2);
wmove(statusbar->topline, 0, 0);
if (statusbar->is_online) {
int colour = WHITE;
const uint8_t *status_text = "Unknown";
const char *status_text = "Unknown";
switch (statusbar->status) {
case TOX_USERSTATUS_NONE:
@ -337,7 +264,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
wprintw(statusbar->topline, " %s", statusbar->nick);
wattroff(statusbar->topline, A_BOLD);
} else {
wprintw(statusbar->topline, "[Offline]");
wprintw(statusbar->topline, " [Offline]");
wattron(statusbar->topline, A_BOLD);
wprintw(statusbar->topline, " %s ", statusbar->nick);
wattroff(statusbar->topline, A_BOLD);
@ -346,10 +273,19 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
if (statusbar->statusmsg[0])
wprintw(statusbar->topline, " - %s", statusbar->statusmsg);
/* put cursor back in correct spot */
int y_m = ctx->orig_y + ((ctx->pos + p_ofst) / px2);
int x_m = (ctx->pos + X_OFST) % x2;
wmove(self->window, y_m, x_m);
mvwhline(self->window, y2 - CHATBOX_HEIGHT, 0, ACS_HLINE, x2);
int y, x;
getyx(self->window, y, x);
(void) x;
int new_x = ctx->start ? x2 - 1 : wcswidth(ctx->line, ctx->pos);
wmove(self->window, y + 1, new_x);
wrefresh(self->window);
if (self->help->active)
help_onDraw(self);
}
static void prompt_onConnectionChange(ToxWindow *self, Tox *m, int32_t friendnum , uint8_t status)
@ -359,20 +295,15 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, int32_t friendnum
ChatContext *ctx = self->chatwin;
uint8_t nick[TOX_MAX_NAME_LENGTH] = {0};
int n_len = tox_get_name(m, friendnum, nick);
n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH - 1);
char nick[TOX_MAX_NAME_LENGTH] = {0}; /* stop removing this initiation */
get_nick_truncate(m, nick, friendnum);
if (!nick[0]) {
if (!nick[0])
snprintf(nick, sizeof(nick), "%s", UNKNOWN_NAME);
n_len = strlen(UNKNOWN_NAME);
}
nick[n_len] = '\0';
uint8_t timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt);
uint8_t *msg;
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
char *msg;
if (status == 1) {
msg = "has come online";
@ -386,15 +317,15 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, int32_t friendnum
}
}
static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const uint8_t *key, const uint8_t *data,
static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, const char *data,
uint16_t length)
{
ChatContext *ctx = self->chatwin;
uint8_t timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt);
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
uint8_t msg[MAX_STR_SIZE];
char msg[MAX_STR_SIZE];
snprintf(msg, sizeof(msg), "Friend request with the message '%s'", data);
line_info_add(self, timefrmt, NULL, NULL, msg, SYS_MSG, 0, 0);
write_to_log(msg, "", ctx->log, true);
@ -402,7 +333,7 @@ static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const uint8_t *key,
int n = add_friend_request(key);
if (n == -1) {
uint8_t *errmsg = "Friend request queue is full. Discarding request.";
char *errmsg = "Friend request queue is full. Discarding request.";
line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, 0);
write_to_log(errmsg, "", ctx->log, true);
return;
@ -417,18 +348,19 @@ void prompt_init_statusbar(ToxWindow *self, Tox *m)
{
int x2, y2;
getmaxyx(self->window, y2, x2);
(void) y2;
/* Init statusbar info */
StatusBar *statusbar = self->stb;
statusbar->status = TOX_USERSTATUS_NONE;
statusbar->is_online = false;
uint8_t nick[TOX_MAX_NAME_LENGTH];
uint8_t statusmsg[MAX_STR_SIZE];
char nick[TOX_MAX_NAME_LENGTH];
char statusmsg[MAX_STR_SIZE];
pthread_mutex_lock(&Winthread.lock);
uint16_t n_len = tox_get_self_name(m, nick);
uint16_t s_len = tox_get_self_status_message(m, statusmsg, MAX_STR_SIZE);
uint16_t n_len = tox_get_self_name(m, (uint8_t *) nick);
uint16_t s_len = tox_get_self_status_message(m, (uint8_t *) statusmsg, MAX_STR_SIZE);
uint8_t status = tox_get_self_user_status(m);
pthread_mutex_unlock(&Winthread.lock);
@ -436,9 +368,9 @@ void prompt_init_statusbar(ToxWindow *self, Tox *m)
statusmsg[s_len] = '\0';
/* load prev status message or show toxic version if it has never been set */
uint8_t ver[strlen(TOXICVER) + 1];
char ver[strlen(TOXICVER) + 1];
strcpy(ver, TOXICVER);
const uint8_t *toxic_ver = strtok(ver, "_");
const char *toxic_ver = strtok(ver, "_");
if ( (!strcmp("Online", statusmsg) || !strncmp("Toxing on Toxic", statusmsg, 15)) && toxic_ver != NULL) {
snprintf(statusmsg, MAX_STR_SIZE, "Toxing on Toxic v.%s", toxic_ver);
@ -446,44 +378,58 @@ void prompt_init_statusbar(ToxWindow *self, Tox *m)
statusmsg[s_len] = '\0';
}
prompt_update_statusmessage(prompt, statusmsg, s_len);
prompt_update_statusmessage(prompt, statusmsg);
prompt_update_status(prompt, status);
prompt_update_nick(prompt, nick, n_len);
prompt_update_nick(prompt, nick);
/* Init statusbar subwindow */
statusbar->topline = subwin(self->window, 2, x2, 0, 0);
}
static void print_welcome_msg(ToxWindow *self)
{
line_info_add(self, NULL, NULL, NULL, " _____ _____ _____ ____ ", SYS_MSG, 1, BLUE);
line_info_add(self, NULL, NULL, NULL, " |_ _/ _ \\ \\/ /_ _/ ___|", SYS_MSG, 1, BLUE);
line_info_add(self, NULL, NULL, NULL, " | || | | \\ / | | | ", SYS_MSG, 1, BLUE);
line_info_add(self, NULL, NULL, NULL, " | || |_| / \\ | | |___ ", SYS_MSG, 1, BLUE);
line_info_add(self, NULL, NULL, NULL, " |_| \\___/_/\\_\\___\\____|", SYS_MSG, 1, BLUE);
line_info_add(self, NULL, NULL, NULL, "", SYS_MSG, 0, 0);
char *msg = "Welcome to Toxic, a free, open source Tox-based instant messenging client.";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
msg = "Type \"/help\" for assistance. Further help may be found via the man page.";
line_info_add(self, NULL, NULL, NULL, msg, SYS_MSG, 1, CYAN);
line_info_add(self, NULL, NULL, NULL, "", SYS_MSG, 0, 0);
}
static void prompt_onInit(ToxWindow *self, Tox *m)
{
ChatContext *ctx = self->chatwin;
curs_set(1);
int y2, x2;
getmaxyx(self->window, y2, x2);
ctx->history = subwin(self->window, y2, x2, 0, 0);
scrollok(ctx->history, 1);
ChatContext *ctx = self->chatwin;
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
ctx->log = malloc(sizeof(struct chatlog));
ctx->hst = malloc(sizeof(struct history));
ctx->log = calloc(1, sizeof(struct chatlog));
ctx->hst = calloc(1, sizeof(struct history));
if (ctx->log == NULL || ctx->hst == NULL)
exit_toxic_err("failed in prompt_onInit", FATALERR_MEMORY);
memset(ctx->log, 0, sizeof(struct chatlog));
memset(ctx->hst, 0, sizeof(struct history));
line_info_init(ctx->hst);
if (user_settings->autolog == AUTOLOG_ON) {
uint8_t myid[TOX_FRIEND_ADDRESS_SIZE];
tox_get_address(m, myid);
char myid[TOX_FRIEND_ADDRESS_SIZE];
tox_get_address(m, (uint8_t *) myid);
log_enable(self->name, myid, ctx->log);
}
execute(ctx->history, self, m, "/help", GLOBAL_COMMAND_MODE);
wmove(ctx->history, y2 - 1, 2);
scrollok(ctx->history, 0);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
print_welcome_msg(self);
}
ToxWindow new_prompt(void)
@ -500,16 +446,18 @@ ToxWindow new_prompt(void)
ret.onConnectionChange = &prompt_onConnectionChange;
ret.onFriendRequest = &prompt_onFriendRequest;
strcpy(ret.name, "prompt");
strcpy(ret.name, "home");
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
StatusBar *stb = calloc(1, sizeof(StatusBar));
Help *help = calloc(1, sizeof(Help));
if (stb == NULL || chatwin == NULL)
if (stb == NULL || chatwin == NULL || help == NULL)
exit_toxic_err("failed in new_prompt", FATALERR_MEMORY);
ret.chatwin = chatwin;
ret.stb = stb;
ret.help = help;
return ret;
}

View File

@ -26,8 +26,6 @@
#include "toxic.h"
#include "windows.h"
#define X_OFST 2 /* offset to account for prompt char */
#ifdef _SUPPORT_AUDIO
#define AC_NUM_GLOB_COMMANDS 17
#else
@ -37,9 +35,10 @@
ToxWindow new_prompt(void);
void prep_prompt_win(void);
void prompt_init_statusbar(ToxWindow *self, Tox *m);
void prompt_update_nick(ToxWindow *prompt, uint8_t *nick, uint16_t len);
void prompt_update_statusmessage(ToxWindow *prompt, uint8_t *statusmsg, uint16_t len);
void prompt_update_nick(ToxWindow *prompt, char *nick);
void prompt_update_statusmessage(ToxWindow *prompt, char *statusmsg);
void prompt_update_status(ToxWindow *prompt, uint8_t status);
void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected);
void kill_prompt_window(ToxWindow *self);
#endif /* end of include guard: PROMPT_H_UZYGWFFL */

View File

@ -20,10 +20,6 @@
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
@ -32,14 +28,15 @@
#include "configdir.h"
#ifdef _SUPPORT_AUDIO
#include "audio_call.h"
#endif
#include "device.h"
#endif /* _SUPPORT_AUDIO */
#include "settings.h"
#include "line_info.h"
static void uset_autolog(struct user_settings *s, const char *val);
static void uset_time(struct user_settings *s, const char *val);
static void uset_timestamps(struct user_settings *s, const char *val);
static void uset_alerts(struct user_settings *s, const char *val);
static void uset_colours(struct user_settings *s, const char *val);
static void uset_hst_size(struct user_settings *s, const char *val);
@ -56,7 +53,8 @@ struct {
} user_settings_list[] = {
{ "autolog", uset_autolog },
{ "time", uset_time },
{ "disable_alerts", uset_alerts },
{ "timestamps", uset_timestamps },
{ "alerts", uset_alerts },
{ "colour_theme", uset_colours },
{ "history_size", uset_hst_size },
{ "download_path", uset_dwnld_path },
@ -83,6 +81,14 @@ static void uset_time(struct user_settings *s, const char *val)
s->time = n == TIME_12 ? TIME_12 : TIME_24;
}
static void uset_timestamps(struct user_settings *s, const char *val)
{
int n = atoi(val);
/* default on if invalid value */
s->timestamps = n == TIMESTAMPS_OFF ? TIMESTAMPS_OFF : TIMESTAMPS_ON;
}
static void uset_alerts(struct user_settings *s, const char *val)
{
int n = atoi(val);
@ -159,7 +165,8 @@ static void set_default_settings(struct user_settings *s)
/* see settings_values enum in settings.h for defaults */
uset_autolog(s, "0");
uset_time(s, "24");
uset_alerts(s, "0");
uset_timestamps(s, "1");
uset_alerts(s, "1");
uset_colours(s, "0");
uset_hst_size(s, "700");
uset_dwnld_path(s, NULL);
@ -209,7 +216,7 @@ int settings_load(struct user_settings *s, char *path)
int i;
for (i = 0; i < NUM_SETTINGS; ++i) {
if (!strcmp(user_settings_list[i].key, key)) {
if (strcmp(user_settings_list[i].key, key) == 0) {
(user_settings_list[i].func)(s, val);
break;
}

View File

@ -26,16 +26,17 @@
#include "toxic.h"
#ifdef _SUPPORT_AUDIO
#define NUM_SETTINGS 8
#define NUM_SETTINGS 9
#else
#define NUM_SETTINGS 6
#endif
#define NUM_SETTINGS 7
#endif /* _SUPPORT_AUDIO */
/* holds user setting values */
struct user_settings {
int autolog; /* boolean */
int alerts; /* boolean */
int time; /* 12 or 24 */
int timestamps; /* boolean */
int colour_theme; /* boolean (0 for default toxic colours) */
int history_size; /* int between MIN_HISTORY and MAX_HISTORY */
char download_path[MAX_STR_SIZE];
@ -53,8 +54,11 @@ enum {
TIME_24 = 24,
TIME_12 = 12,
ALERTS_DISABLED = 1,
ALERTS_ENABLED = 0,
TIMESTAMPS_OFF = 0,
TIMESTAMPS_ON = 1,
ALERTS_DISABLED = 0,
ALERTS_ENABLED = 1,
NATIVE_COLS = 1,
DFLT_COLS = 0,

View File

@ -20,14 +20,6 @@
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifndef SIGWINCH
#define SIGWINCH 28
#endif
#include <curses.h>
#include <errno.h>
#include <stdio.h>
@ -57,6 +49,7 @@
#include "file_senders.h"
#include "line_info.h"
#include "settings.h"
#include "log.h"
#ifdef _SUPPORT_AUDIO
#include "audio_call.h"
@ -74,9 +67,12 @@ ToxAv *av;
char *DATA_FILE = NULL;
ToxWindow *prompt = NULL;
#define AUTOSAVE_FREQ 60
struct arg_opts {
int ignore_data_file;
int use_ipv4;
int default_locale;
char config_path[MAX_STR_SIZE];
char nodes_path[MAX_STR_SIZE];
} arg_opts;
@ -84,30 +80,30 @@ struct arg_opts {
struct _Winthread Winthread;
struct user_settings *user_settings = NULL;
static void ignore_SIGINT(int sig)
static void catch_SIGINT(int sig)
{
return;
Winthread.sig_exit_toxic = true;
}
static void flag_window_resize(int sig)
{
Winthread.flag_resize = true;
}
void exit_toxic_success(Tox *m)
{
store_data(m, DATA_FILE);
close_all_file_senders();
close_all_file_senders(m);
kill_all_windows();
log_disable(prompt->chatwin->log);
line_info_cleanup(prompt->chatwin->hst);
free(DATA_FILE);
free(prompt->stb);
free(prompt->chatwin->log);
free(prompt->chatwin->hst);
free(prompt->chatwin);
free(user_settings);
#ifdef _SUPPORT_AUDIO
terminate_audio();
#endif /* _SUPPORT_AUDIO */
tox_kill(m);
endwin();
fprintf(stderr, "Toxic session ended gracefully.\n");
exit(EXIT_SUCCESS);
}
@ -123,13 +119,16 @@ void exit_toxic_err(const char *errmsg, int errcode)
static void init_term(void)
{
signal(SIGWINCH, on_window_resize);
signal(SIGWINCH, flag_window_resize);
#if HAVE_WIDECHAR
if (setlocale(LC_ALL, "") == NULL)
exit_toxic_err("Could not set your locale, plese check your locale settings or"
"disable wide char support", FATALERR_LOCALE_SET);
if (!arg_opts.default_locale) {
if (setlocale(LC_ALL, "") == NULL)
exit_toxic_err("Could not set your locale, please check your locale settings or "
"disable unicode support with the -d flag.", FATALERR_LOCALE_SET);
}
#endif
initscr();
@ -217,12 +216,14 @@ static Tox *init_tox(int ipv4)
#define MAXNODES 50
#define NODELEN (MAXLINE - TOX_CLIENT_ID_SIZE - 7)
static int linecnt = 0;
static char nodes[MAXNODES][NODELEN];
static uint16_t ports[MAXNODES];
static uint8_t keys[MAXNODES][TOX_CLIENT_ID_SIZE];
static struct _toxNodes {
int lines;
char nodes[MAXNODES][NODELEN];
uint16_t ports[MAXNODES];
char keys[MAXNODES][TOX_CLIENT_ID_SIZE];
} toxNodes;
static int nodelist_load(char *filename)
static int nodelist_load(const char *filename)
{
if (!filename)
return 1;
@ -234,7 +235,7 @@ static int nodelist_load(char *filename)
char line[MAXLINE];
while (fgets(line, sizeof(line), fp) && linecnt < MAXNODES) {
while (fgets(line, sizeof(line), fp) && toxNodes.lines < MAXNODES) {
if (strlen(line) > MINLINE) {
const char *name = strtok(line, " ");
const char *port = strtok(NULL, " ");
@ -244,19 +245,19 @@ static int nodelist_load(char *filename)
if (name == NULL || port == NULL || key_ascii == NULL)
continue;
snprintf(nodes[linecnt], sizeof(nodes[linecnt]), "%s", name);
nodes[linecnt][NODELEN - 1] = 0;
ports[linecnt] = htons(atoi(port));
snprintf(toxNodes.nodes[toxNodes.lines], sizeof(toxNodes.nodes[toxNodes.lines]), "%s", name);
toxNodes.nodes[toxNodes.lines][NODELEN - 1] = 0;
toxNodes.ports[toxNodes.lines] = htons(atoi(port));
uint8_t *key_binary = hex_string_to_bin(key_ascii);
memcpy(keys[linecnt], key_binary, TOX_CLIENT_ID_SIZE);
char *key_binary = hex_string_to_bin(key_ascii);
memcpy(toxNodes.keys[toxNodes.lines], key_binary, TOX_CLIENT_ID_SIZE);
free(key_binary);
linecnt++;
toxNodes.lines++;
}
}
if (linecnt < 1) {
if (toxNodes.lines < 1) {
fclose(fp);
return 2;
}
@ -267,8 +268,8 @@ static int nodelist_load(char *filename)
int init_connection_helper(Tox *m, int line)
{
return tox_bootstrap_from_address(m, nodes[line], TOX_ENABLE_IPV6_DEFAULT,
ports[line], keys[line]);
return tox_bootstrap_from_address(m, toxNodes.nodes[line], TOX_ENABLE_IPV6_DEFAULT,
toxNodes.ports[line], (uint8_t *) toxNodes.keys[line]);
}
/* Connects to a random DHT node listed in the DHTnodes file
@ -285,8 +286,8 @@ static bool srvlist_loaded = false;
int init_connection(Tox *m)
{
if (linecnt > 0) /* already loaded nodelist */
return init_connection_helper(m, rand() % linecnt) ? 0 : 3;
if (toxNodes.lines > 0) /* already loaded nodelist */
return init_connection_helper(m, rand() % toxNodes.lines) ? 0 : 3;
/* only once:
* - load the nodelist
@ -301,15 +302,15 @@ int init_connection(Tox *m)
else
res = nodelist_load(arg_opts.nodes_path);
if (linecnt < 1)
if (toxNodes.lines < 1)
return res;
res = 3;
int i;
int n = MIN(NUM_INIT_NODES, linecnt);
int n = MIN(NUM_INIT_NODES, toxNodes.lines);
for (i = 0; i < n; ++i) {
if (init_connection_helper(m, rand() % linecnt))
if (init_connection_helper(m, rand() % toxNodes.lines))
res = 0;
}
@ -320,30 +321,37 @@ int init_connection(Tox *m)
return 4;
}
#define TRY_CONNECT 10 /* Seconds between connection attempts when DHT is not connected */
static void do_connection(Tox *m, ToxWindow *prompt)
{
uint8_t msg[MAX_STR_SIZE] = {0};
char msg[MAX_STR_SIZE] = {0};
static int conn_try = 0;
static int conn_err = 0;
static bool dht_on = false;
static bool was_connected = false;
static uint64_t last_conn_try = 0;
uint64_t curtime = get_unix_time();
bool is_connected = tox_isconnected(m);
if (!dht_on && !is_connected && !(conn_try++ % 100)) {
if (!conn_err) {
if ((conn_err = init_connection(m))) {
snprintf(msg, sizeof(msg), "\nAuto-connect failed with error code %d", conn_err);
}
}
} else if (!dht_on && is_connected) {
dht_on = true;
prompt_update_connectionstatus(prompt, dht_on);
if (was_connected && is_connected)
return;
if (!was_connected && is_connected) {
was_connected = true;
prompt_update_connectionstatus(prompt, was_connected);
snprintf(msg, sizeof(msg), "DHT connected.");
} else if (dht_on && !is_connected) {
dht_on = false;
prompt_update_connectionstatus(prompt, dht_on);
snprintf(msg, sizeof(msg), "\nDHT disconnected. Attempting to reconnect.");
} else if (was_connected && !is_connected) {
was_connected = false;
prompt_update_connectionstatus(prompt, was_connected);
snprintf(msg, sizeof(msg), "DHT disconnected. Attempting to reconnect.");
} else if (!was_connected && !is_connected && timed_out(last_conn_try, curtime, TRY_CONNECT)) {
/* if autoconnect has already failed there's no point in trying again */
if (conn_err == 0) {
last_conn_try = curtime;
if ((conn_err = init_connection(m)) != 0)
snprintf(msg, sizeof(msg), "Auto-connect failed with error code %d", conn_err);
}
}
if (msg[0])
@ -376,8 +384,8 @@ int store_data(Tox *m, char *path)
return 1;
FILE *fd;
size_t len;
uint8_t *buf;
int len;
char *buf;
len = tox_size(m);
buf = malloc(len);
@ -385,7 +393,7 @@ int store_data(Tox *m, char *path)
if (buf == NULL)
return 2;
tox_save(m, buf);
tox_save(m, (uint8_t *) buf);
fd = fopen(path, "wb");
@ -411,8 +419,8 @@ static void load_data(Tox *m, char *path)
return;
FILE *fd;
size_t len;
uint8_t *buf;
int len;
char *buf;
if ((fd = fopen(path, "rb")) != NULL) {
fseek(fd, 0, SEEK_END);
@ -432,15 +440,13 @@ static void load_data(Tox *m, char *path)
exit_toxic_err("failed in load_data", FATALERR_FREAD);
}
tox_load(m, buf, len);
tox_load(m, (uint8_t *) buf, len);
load_friendlist(m);
free(buf);
fclose(fd);
} else {
int st;
if ((st = store_data(m, path)) != 0)
if (store_data(m, path) != 0)
exit_toxic_err("failed in load_data", FATALERR_STORE_DATA);
}
}
@ -448,39 +454,55 @@ static void load_data(Tox *m, char *path)
static void do_toxic(Tox *m, ToxWindow *prompt)
{
pthread_mutex_lock(&Winthread.lock);
do_connection(m, prompt);
do_file_senders(m);
tox_do(m); /* main tox-core loop */
pthread_mutex_unlock(&Winthread.lock);
}
#define INACTIVE_WIN_REFRESH_RATE 10
void *thread_winref(void *data)
{
Tox *m = (Tox *) data;
uint8_t draw_count = 0;
while (true) {
draw_active_window(m);
refresh_inactive_windows();
draw_count++;
if (Winthread.flag_resize) {
on_window_resize();
Winthread.flag_resize = false;
} else if (draw_count >= INACTIVE_WIN_REFRESH_RATE) {
refresh_inactive_windows();
draw_count = 0;
}
if (Winthread.sig_exit_toxic) {
pthread_mutex_lock(&Winthread.lock);
exit_toxic_success(m);
}
}
}
static void print_usage(void)
{
fprintf(stderr, "usage: toxic [OPTION] [FILE ...]\n");
fprintf(stderr, " -f, --file Use specified data file\n");
fprintf(stderr, " -x, --nodata Ignore data file\n");
fprintf(stderr, " -4, --ipv4 Force IPv4 connection\n");
fprintf(stderr, " -c, --config Use specified config file\n");
fprintf(stderr, " -n, --nodes Use specified DHTnodes file\n");
fprintf(stderr, " -h, --help Show this message and exit\n");
fprintf(stderr, " -f, --file Use specified data file\n");
fprintf(stderr, " -x, --nodata Ignore data file\n");
fprintf(stderr, " -4, --ipv4 Force IPv4 connection\n");
fprintf(stderr, " -d, --default_locale Use default locale\n");
fprintf(stderr, " -c, --config Use specified config file\n");
fprintf(stderr, " -n, --nodes Use specified DHTnodes file\n");
fprintf(stderr, " -h, --help Show this message and exit\n");
}
static void set_default_opts(void)
{
arg_opts.use_ipv4 = 0;
arg_opts.ignore_data_file = 0;
arg_opts.default_locale = 0;
}
static void parse_args(int argc, char *argv[])
@ -491,12 +513,13 @@ static void parse_args(int argc, char *argv[])
{"file", required_argument, 0, 'f'},
{"nodata", no_argument, 0, 'x'},
{"ipv4", no_argument, 0, '4'},
{"default_locale", no_argument, 0, 'd'},
{"config", required_argument, 0, 'c'},
{"nodes", required_argument, 0, 'n'},
{"help", no_argument, 0, 'h'},
};
const char *opts_str = "4xf:c:n:h";
const char *opts_str = "4xdf:c:n:h";
int opt, indexptr;
while ((opt = getopt_long(argc, argv, opts_str, long_opts, &indexptr)) != -1) {
@ -521,6 +544,10 @@ static void parse_args(int argc, char *argv[])
snprintf(arg_opts.nodes_path, sizeof(arg_opts.nodes_path), "%s", optarg);
break;
case 'd':
arg_opts.default_locale = 1;
break;
case 'h':
default:
print_usage();
@ -539,7 +566,7 @@ int main(int argc, char *argv[])
/* Make sure all written files are read/writeable only by the current user. */
umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
signal(SIGINT, ignore_SIGINT);
signal(SIGINT, catch_SIGINT);
config_err = create_user_config_dir(user_config_dir);
@ -582,30 +609,23 @@ int main(int argc, char *argv[])
prompt = init_windows(m);
/* create new thread for ncurses stuff */
/* thread for ncurses stuff */
if (pthread_mutex_init(&Winthread.lock, NULL) != 0)
exit_toxic_err("failed in main", FATALERR_MUTEX_INIT);
if (pthread_create(&Winthread.tid, NULL, thread_winref, (void *) m) != 0)
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
uint8_t *msg;
char *msg;
#ifdef _SUPPORT_AUDIO
av = init_audio(prompt, m);
device_set(prompt, input, user_settings->audio_in_dev);
device_set(prompt, output, user_settings->audio_out_dev);
if ( errors() == NoError )
msg = "Audio initiated with no problems.";
else /* Get error code and stuff */
msg = "Error initiating audio!";
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
set_primary_device(input, user_settings->audio_in_dev);
set_primary_device(output, user_settings->audio_out_dev);
#endif /* _SUPPORT_AUDIO */
if (config_err) {
@ -613,20 +633,30 @@ int main(int argc, char *argv[])
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
}
if (settings_err == -1) {
msg = "Failed to load user settings";
line_info_add(prompt, NULL, NULL, NULL, msg, SYS_MSG, 0, 0);
}
sort_friendlist_index();
prompt_init_statusbar(prompt, m);
uint64_t last_save = get_unix_time();
while (true) {
update_unix_time();
do_toxic(m, prompt);
usleep(10000);
uint64_t cur_time = get_unix_time();
if (timed_out(last_save, cur_time, AUTOSAVE_FREQ)) {
pthread_mutex_lock(&Winthread.lock);
store_data(m, DATA_FILE);
pthread_mutex_unlock(&Winthread.lock);
last_save = cur_time;
}
usleep(40000);
}
return 0;

View File

@ -27,6 +27,14 @@
#define TOXICVER "NOVER_" /* Use the -D flag to set this */
#endif
#ifndef SIGWINCH
#define SIGWINCH 28
#endif
#ifndef SIGINT
#define SIGINT 2
#endif
#include <stdbool.h>
#include <curses.h>
@ -35,13 +43,14 @@
#define UNKNOWN_NAME "Anonymous"
#define MAX_FRIENDS_NUM 500
#define MAX_STR_SIZE 256
#define MAX_STR_SIZE TOX_MAX_MESSAGE_LENGTH
#define MAX_CMDNAME_SIZE 64
#define TOXIC_MAX_NAME_LENGTH 32 /* Must be <= TOX_MAX_NAME_LENGTH */
#define KEY_IDENT_DIGITS 2 /* number of hex digits to display for the pub-key based identifier */
#define TIME_STR_SIZE 16
/* ASCII key codes */
#define T_KEY_ESC 0X1B /* esc key */
#define T_KEY_KILL 0x0B /* ctrl-k */
#define T_KEY_DISCARD 0x15 /* ctrl-u */
#define T_KEY_NEXT 0x10 /* ctrl-p */
@ -50,24 +59,22 @@
#define T_KEY_C_A 0x01 /* ctrl-a */
#define T_KEY_C_RB 0x1D /* ctrl-] */
#define T_KEY_C_LB 0x1B /* ctrl-[ */
#define T_KEY_C_B 0x02 /* ctrl-b */
#define T_KEY_C_V 0x16 /* ctrl-v */
#define T_KEY_C_F 0x06 /* ctrl-f */
#define T_KEY_C_H 0x08 /* ctrl-h */
enum {
MOVE_UP,
MOVE_DOWN,
} KEY_DIRS;
#define T_KEY_C_Y 0x19 /* ctrl-y */
typedef enum _FATAL_ERRS {
FATALERR_MEMORY = -1, /* malloc() or calloc() failed */
FATALERR_FREAD = -2, /* fread() failed on critical read */
FATALERR_THREAD_CREATE = -3,
FATALERR_MUTEX_INIT = -4,
FATALERR_LOCALE_SET = -5,
FATALERR_STORE_DATA = -6,
FATALERR_NETWORKINIT = -7, /* Tox network failed to init */
FATALERR_INFLOOP = -8, /* infinite loop detected */
FATALERR_WININIT = -9, /* window init failed */
FATALERR_MEMORY = -1, /* malloc() or calloc() failed */
FATALERR_FREAD = -2, /* fread() failed on critical read */
FATALERR_THREAD_CREATE = -3, /* thread creation failed */
FATALERR_MUTEX_INIT = -4, /* mutex init failed */
FATALERR_THREAD_ATTR = -5, /* thread attr object init failed */
FATALERR_LOCALE_SET = -6, /* system locale not set */
FATALERR_STORE_DATA = -7, /* store_data failed in critical section */
FATALERR_NETWORKINIT = -8, /* Tox network failed to init */
FATALERR_INFLOOP = -9, /* infinite loop detected */
FATALERR_WININIT = -10, /* window init failed */
} FATAL_ERRS;
/* Fixes text color problem on some terminals.
@ -77,23 +84,25 @@ typedef enum _FATAL_ERRS {
void exit_toxic_success(Tox *m);
void exit_toxic_err(const char *errmsg, int errcode);
int store_data(Tox *m, char *path);
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata);
void on_connectionchange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata);
void on_message(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_action(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_nickchange(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_message(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata);
void on_action(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata);
void on_nickchange(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata);
void on_statuschange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata);
void on_statusmessagechange(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata);
void on_statusmessagechange(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata);
void on_friendadded(Tox *m, int32_t friendnumber, bool sort);
void on_groupmessage(Tox *m, int groupnumber, int peernumber, uint8_t *message, uint16_t length, void *userdata);
void on_groupaction(Tox *m, int groupnumber, int peernumber, uint8_t *action, uint16_t length, void *userdata);
void on_groupinvite(Tox *m, int32_t friendnumber, uint8_t *group_pub_key, void *userdata);
void on_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *message, uint16_t length, void *userdata);
void on_groupaction(Tox *m, int groupnumber, int peernumber, const uint8_t *action, uint16_t length, void *userdata);
void on_groupinvite(Tox *m, int32_t friendnumber, const uint8_t *group_pub_key, void *userdata);
void on_group_namelistchange(Tox *m, int groupnumber, int peernumber, uint8_t change, void *userdata);
void on_file_sendrequest(Tox *m, int32_t friendnumber, uint8_t filenumber, uint64_t filesize, uint8_t *pathname,
void on_file_sendrequest(Tox *m, int32_t friendnumber, uint8_t filenumber, uint64_t filesize, const uint8_t *pathname,
uint16_t pathname_length, void *userdata);
void on_file_control(Tox *m, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber, uint8_t control_type,
uint8_t *data, uint16_t length, void *userdata);
void on_file_data(Tox *m, int32_t friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata);
const uint8_t *data, uint16_t length, void *userdata);
void on_file_data(Tox *m, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length, void *userdata);
void on_typing_change(Tox *m, int32_t friendnumber, uint8_t is_typing, void *userdata);
#endif /* #define _toxic_h */

View File

@ -20,96 +20,116 @@
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "toxic.h"
#include "windows.h"
#include "misc_tools.h"
#include "toxic_strings.h"
/* Adds char to line at pos */
void add_char_to_buf(ChatContext *ctx, wint_t ch)
/* Adds char to line at pos. Return 0 on success, -1 if line buffer is full */
int add_char_to_buf(ChatContext *ctx, wint_t ch)
{
if (ctx->pos < 0 || ctx->len >= MAX_STR_SIZE)
return;
/* move all chars including null in front of pos one space forward and insert char in pos */
int i;
for (i = ctx->len; i >= ctx->pos && i >= 0; --i)
ctx->line[i + 1] = ctx->line[i];
if (ctx->len >= MAX_STR_SIZE - 1)
return -1;
wmemmove(&ctx->line[ctx->pos + 1], &ctx->line[ctx->pos], ctx->len - ctx->pos);
ctx->line[ctx->pos++] = ch;
++ctx->len;
ctx->line[++ctx->len] = L'\0';
return 0;
}
/* Deletes the character before pos */
void del_char_buf_bck(ChatContext *ctx)
/* Deletes the character before pos. Return 0 on success, -1 if nothing to delete */
int del_char_buf_bck(ChatContext *ctx)
{
if (ctx->pos <= 0)
return;
int i;
/* similar to add_char_to_buf but deletes a char */
for (i = ctx->pos - 1; i <= ctx->len; ++i)
ctx->line[i] = ctx->line[i + 1];
return -1;
wmemmove(&ctx->line[ctx->pos - 1], &ctx->line[ctx->pos], ctx->len - ctx->pos);
--ctx->pos;
--ctx->len;
ctx->line[--ctx->len] = L'\0';
return 0;
}
/* Deletes the character at pos */
void del_char_buf_frnt(ChatContext *ctx)
/* Deletes the character at pos. Return 0 on success, -1 if nothing to delete. */
int del_char_buf_frnt(ChatContext *ctx)
{
if (ctx->pos < 0 || ctx->pos >= ctx->len)
return;
if (ctx->pos >= ctx->len)
return -1;
int i;
wmemmove(&ctx->line[ctx->pos], &ctx->line[ctx->pos + 1], ctx->len - ctx->pos - 1);
ctx->line[--ctx->len] = L'\0';
for (i = ctx->pos; i < ctx->len; ++i)
ctx->line[i] = ctx->line[i + 1];
--ctx->len;
return 0;
}
/* Deletes the line from beginning to pos */
void discard_buf(ChatContext *ctx)
/* Deletes the line from beginning to pos and puts discarded portion in yank buffer.
Return 0 on success, -1 if noting to discard. */
int discard_buf(ChatContext *ctx)
{
if (ctx->pos <= 0)
return;
return -1;
int i;
int c = 0;
for (i = ctx->pos; i <= ctx->len; ++i)
ctx->line[c++] = ctx->line[i];
ctx->yank_len = ctx->pos;
wmemcpy(ctx->yank, ctx->line, ctx->yank_len);
ctx->yank[ctx->yank_len] = L'\0';
wmemmove(ctx->line, &ctx->line[ctx->pos], ctx->len - ctx->pos);
ctx->len -= ctx->pos;
ctx->pos = 0;
ctx->len = c - 1;
ctx->start = 0;
ctx->line[ctx->len] = L'\0';
return 0;
}
/* Deletes the line from pos to len */
void kill_buf(ChatContext *ctx)
/* Deletes the line from pos to len and puts killed portion in yank buffer.
Return 0 on success, -1 if nothing to kill. */
int kill_buf(ChatContext *ctx)
{
if (ctx->len == ctx->pos)
return;
if (ctx->len <= ctx->pos)
return -1;
ctx->yank_len = ctx->len - ctx->pos;
wmemcpy(ctx->yank, &ctx->line[ctx->pos], ctx->yank_len);
ctx->yank[ctx->yank_len] = L'\0';
ctx->line[ctx->pos] = L'\0';
ctx->len = ctx->pos;
return 0;
}
/* nulls line and sets pos and len to 0 */
/* Inserts string in ctx->yank into line at pos.
Return 0 on success, -1 if yank buffer is empty or too long */
int yank_buf(ChatContext *ctx)
{
if (!ctx->yank[0])
return -1;
if (ctx->yank_len + ctx->len >= MAX_STR_SIZE - 1)
return -1;
wmemmove(&ctx->line[ctx->pos + ctx->yank_len], &ctx->line[ctx->pos], ctx->len - ctx->pos);
wmemcpy(&ctx->line[ctx->pos], ctx->yank, ctx->yank_len);
ctx->pos += ctx->yank_len;
ctx->len += ctx->yank_len;
ctx->line[ctx->len] = L'\0';
return 0;
}
/* nulls line and sets pos, len and start to 0 */
void reset_buf(ChatContext *ctx)
{
ctx->line[0] = L'\0';
ctx->pos = 0;
ctx->len = 0;
ctx->start = 0;
}
/* Removes trailing spaces from line. */
@ -168,7 +188,7 @@ void add_line_to_hist(ChatContext *ctx)
resets line if at end of history */
void fetch_hist_item(ChatContext *ctx, int key_dir)
{
if (key_dir == MOVE_UP) {
if (key_dir == KEY_UP) {
if (--ctx->hst_pos < 0) {
ctx->hst_pos = 0;
beep();
@ -202,19 +222,19 @@ int complete_line(ChatContext *ctx, const void *list, int n_items, int size)
if (ctx->pos <= 0 || ctx->len <= 0 || ctx->len >= MAX_STR_SIZE)
return -1;
const uint8_t *L = (uint8_t *) list;
const char *L = (char *) list;
uint8_t ubuf[MAX_STR_SIZE];
char ubuf[MAX_STR_SIZE];
/* work with multibyte string copy of buf for simplicity */
if (wcs_to_mbs_buf(ubuf, ctx->line, MAX_STR_SIZE) == -1)
if (wcs_to_mbs_buf(ubuf, ctx->line, sizeof(ubuf)) == -1)
return -1;
/* isolate substring from space behind pos to pos */
uint8_t tmp[MAX_STR_SIZE];
char tmp[MAX_STR_SIZE];
snprintf(tmp, sizeof(tmp), "%s", ubuf);
tmp[ctx->pos] = '\0';
uint8_t *sub = strrchr(tmp, ' ');
char *sub = strrchr(tmp, ' ');
int n_endchrs = 1; /* 1 = append space to end of match, 2 = append ": " */
if (!sub++) {
@ -228,7 +248,7 @@ int complete_line(ChatContext *ctx, const void *list, int n_items, int size)
return -1;
int s_len = strlen(sub);
const uint8_t *match;
const char *match;
bool is_match = false;
int i;
@ -236,7 +256,7 @@ int complete_line(ChatContext *ctx, const void *list, int n_items, int size)
for (i = 0; i < n_items; ++i) {
match = &L[i * size];
if (is_match = strncasecmp(match, sub, s_len) == 0)
if ((is_match = strncasecmp(match, sub, s_len) == 0))
break;
}
@ -244,7 +264,7 @@ int complete_line(ChatContext *ctx, const void *list, int n_items, int size)
return -1;
/* put match in correct spot in buf and append endchars (space or ": ") */
const uint8_t *endchrs = n_endchrs == 1 ? " " : ": ";
const char *endchrs = n_endchrs == 1 ? " " : ": ";
int m_len = strlen(match);
int strt = ctx->pos - s_len;
int diff = m_len - s_len + n_endchrs;
@ -252,7 +272,7 @@ int complete_line(ChatContext *ctx, const void *list, int n_items, int size)
if (ctx->len + diff > MAX_STR_SIZE)
return -1;
uint8_t tmpend[MAX_STR_SIZE];
char tmpend[MAX_STR_SIZE];
strcpy(tmpend, &ubuf[ctx->pos]);
strcpy(&ubuf[strt], match);
strcpy(&ubuf[strt + m_len], endchrs);
@ -266,8 +286,8 @@ int complete_line(ChatContext *ctx, const void *list, int n_items, int size)
wcscpy(ctx->line, newbuf);
ctx->len += (size_t) diff;
ctx->pos += (size_t) diff;
ctx->len += diff;
ctx->pos += diff;
return diff;
}

View File

@ -25,24 +25,30 @@
#include "windows.h"
/* Adds char to line at pos */
void add_char_to_buf(ChatContext *ctx, wint_t ch);
/* Adds char to line at pos. Return 0 on success, -1 if line buffer is full */
int add_char_to_buf(ChatContext *ctx, wint_t ch);
/* Deletes the character before pos */
void del_char_buf_bck(ChatContext *ctx);
/* Deletes the character before pos. Return 0 on success, -1 if nothing to delete */
int del_char_buf_bck(ChatContext *ctx);
/* Deletes the character at pos */
void del_char_buf_frnt(ChatContext *ctx);
/* Deletes the character at pos. Return 0 on success, -1 if nothing to delete. */
int del_char_buf_frnt(ChatContext *ctx);
/* Deletes the line from beginning to pos */
void discard_buf(ChatContext *ctx);
/* Deletes the line from beginning to pos and puts discarded portion in yank buffer.
Return 0 on success, -1 if noting to discard */
int discard_buf(ChatContext *ctx);
/* Deletes the line from pos to len */
void kill_buf(ChatContext *ctx);
/* Deletes the line from pos to len and puts killed portion in yank buffer.
Return 0 on success, -1 if nothing to kill. */
int kill_buf(ChatContext *ctx);
/* nulls line and sets pos and len to 0 */
/* nulls line and sets pos, len and start to 0 */
void reset_buf(ChatContext *ctx);
/* Inserts string in ctx->yank into line at pos.
Return 0 on success, -1 if yank buffer is empty or too long */
int yank_buf(ChatContext *ctx);
/* Removes trailing spaces from line. */
void rm_trailing_spaces_buf(ChatContext *ctx);

View File

@ -20,19 +20,18 @@
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <ctype.h>
#include "friendlist.h"
#include "prompt.h"
#include "toxic.h"
#include "windows.h"
#include "groupchat.h"
#include "chat.h"
#include "line_info.h"
extern char *DATA_FILE;
extern struct _Winthread Winthread;
@ -50,7 +49,7 @@ void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, uint16_t
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onFriendRequest != NULL)
windows[i].onFriendRequest(&windows[i], m, public_key, data, length);
windows[i].onFriendRequest(&windows[i], m, (const char *) public_key, (const char *) data, length);
}
}
@ -74,27 +73,27 @@ void on_typing_change(Tox *m, int32_t friendnumber, uint8_t is_typing, void *use
}
}
void on_message(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata)
void on_message(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata)
{
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onMessage != NULL)
windows[i].onMessage(&windows[i], m, friendnumber, string, length);
windows[i].onMessage(&windows[i], m, friendnumber, (const char *) string, length);
}
}
void on_action(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata)
void on_action(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata)
{
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onAction != NULL)
windows[i].onAction(&windows[i], m, friendnumber, string, length);
windows[i].onAction(&windows[i], m, friendnumber, (const char *) string, length);
}
}
void on_nickchange(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata)
void on_nickchange(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata)
{
if (friendnumber < 0 || friendnumber > MAX_FRIENDS_NUM)
return;
@ -103,20 +102,19 @@ void on_nickchange(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t lengt
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onNickChange != NULL)
windows[i].onNickChange(&windows[i], m, friendnumber, string, length);
windows[i].onNickChange(&windows[i], m, friendnumber, (const char *) string, length);
}
if (store_data(m, DATA_FILE))
wprintw(prompt->window, "\nCould not store Tox data\n");
store_data(m, DATA_FILE);
}
void on_statusmessagechange(Tox *m, int32_t friendnumber, uint8_t *string, uint16_t length, void *userdata)
void on_statusmessagechange(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata)
{
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onStatusMessageChange != NULL)
windows[i].onStatusMessageChange(&windows[i], friendnumber, string, length);
windows[i].onStatusMessageChange(&windows[i], friendnumber, (const char *) string, length);
}
}
@ -139,39 +137,38 @@ void on_friendadded(Tox *m, int32_t friendnumber, bool sort)
windows[i].onFriendAdded(&windows[i], m, friendnumber, sort);
}
if (store_data(m, DATA_FILE))
wprintw(prompt->window, "\nCould not store Tox data\n");
store_data(m, DATA_FILE);
}
void on_groupmessage(Tox *m, int groupnumber, int peernumber, uint8_t *message, uint16_t length,
void on_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *message, uint16_t length,
void *userdata)
{
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupMessage != NULL)
windows[i].onGroupMessage(&windows[i], m, groupnumber, peernumber, message, length);
windows[i].onGroupMessage(&windows[i], m, groupnumber, peernumber, (const char *) message, length);
}
}
void on_groupaction(Tox *m, int groupnumber, int peernumber, uint8_t *action, uint16_t length,
void on_groupaction(Tox *m, int groupnumber, int peernumber, const uint8_t *action, uint16_t length,
void *userdata)
{
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupAction != NULL)
windows[i].onGroupAction(&windows[i], m, groupnumber, peernumber, action, length);
windows[i].onGroupAction(&windows[i], m, groupnumber, peernumber, (const char *) action, length);
}
}
void on_groupinvite(Tox *m, int32_t friendnumber, uint8_t *group_pub_key, void *userdata)
void on_groupinvite(Tox *m, int32_t friendnumber, const uint8_t *group_pub_key, void *userdata)
{
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onGroupInvite != NULL)
windows[i].onGroupInvite(&windows[i], m, friendnumber, group_pub_key);
windows[i].onGroupInvite(&windows[i], m, friendnumber, (const char *) group_pub_key);
}
}
@ -186,37 +183,37 @@ void on_group_namelistchange(Tox *m, int groupnumber, int peernumber, uint8_t ch
}
void on_file_sendrequest(Tox *m, int32_t friendnumber, uint8_t filenumber, uint64_t filesize,
uint8_t *filename, uint16_t filename_length, void *userdata)
const uint8_t *filename, uint16_t filename_length, void *userdata)
{
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onFileSendRequest != NULL)
windows[i].onFileSendRequest(&windows[i], m, friendnumber, filenumber, filesize,
filename, filename_length);
(const char *) filename, filename_length);
}
}
void on_file_control (Tox *m, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber,
uint8_t control_type, uint8_t *data, uint16_t length, void *userdata)
uint8_t control_type, const uint8_t *data, uint16_t length, void *userdata)
{
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onFileControl != NULL)
windows[i].onFileControl(&windows[i], m, friendnumber, receive_send, filenumber,
control_type, data, length);
control_type, (const char *) data, length);
}
}
void on_file_data(Tox *m, int32_t friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length,
void on_file_data(Tox *m, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length,
void *userdata)
{
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].onFileData != NULL)
windows[i].onFileData(&windows[i], m, friendnumber, filenumber, data, length);
windows[i].onFileData(&windows[i], m, friendnumber, filenumber, (const char *) data, length);
}
}
@ -255,17 +252,12 @@ int add_window(Tox *m, ToxWindow w)
return -1;
}
/* Deletes window w and cleans up */
void del_window(ToxWindow *w)
void set_active_window(int index)
{
active_window = windows; /* Go to prompt screen */
if (index < 0 || index >= MAX_WINDOWS_NUM)
return;
delwin(w->window);
memset(w, 0, sizeof(ToxWindow));
clear();
refresh();
--num_active_windows;
active_window = windows + index;
}
/* Shows next window when tab or back-tab is pressed */
@ -289,12 +281,17 @@ void set_next_window(int ch)
}
}
void set_active_window(int index)
/* Deletes window w and cleans up */
void del_window(ToxWindow *w)
{
if (index < 0 || index >= MAX_WINDOWS_NUM)
return;
set_active_window(0); /* Go to prompt screen */
active_window = windows + index;
delwin(w->window);
memset(w, 0, sizeof(ToxWindow));
clear();
refresh();
--num_active_windows;
}
ToxWindow *init_windows(Tox *m)
@ -310,10 +307,63 @@ ToxWindow *init_windows(Tox *m)
return prompt;
}
void on_window_resize(int sig)
void on_window_resize(void)
{
endwin();
refresh();
clear();
/* equivalent to LINES and COLS */
int x2, y2;
getmaxyx(stdscr, y2, x2);
y2 -= 2;
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (!windows[i].active)
continue;
ToxWindow *w = &windows[i];
if (windows[i].is_friendlist) {
delwin(w->window);
w->window = newwin(y2, x2, 0, 0);
continue;
}
if (w->help->active)
wclear(w->help->win);
if (w->is_groupchat)
delwin(w->chatwin->sidebar);
else
delwin(w->stb->topline);
delwin(w->chatwin->linewin);
delwin(w->chatwin->history);
delwin(w->window);
w->window = newwin(y2, x2, 0, 0);
w->chatwin->linewin = subwin(w->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
if (w->is_groupchat) {
w->chatwin->history = subwin(w->window, y2 - CHATBOX_HEIGHT + 1, x2 - SIDEBAR_WIDTH - 1, 0, 0);
w->chatwin->sidebar = subwin(w->window, y2 - CHATBOX_HEIGHT + 1, SIDEBAR_WIDTH, 0, x2 - SIDEBAR_WIDTH);
} else {
w->chatwin->history = subwin(w->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
w->stb->topline = subwin(w->window, 2, x2, 0, 0);
}
#ifdef _SUPPORT_AUDIO
if (w->chatwin->infobox.active) {
delwin(w->chatwin->infobox.win);
w->chatwin->infobox.win = newwin(INFOBOX_HEIGHT, INFOBOX_WIDTH + 1, 1, x2 - INFOBOX_WIDTH);
}
#endif /* _SUPPORT_AUDIO */
scrollok(w->chatwin->history, 0);
}
}
static void draw_window_tab(ToxWindow toxwin)
@ -391,12 +441,7 @@ void draw_active_window(Tox *m)
draw_bar();
touchwin(a->window);
#ifndef WIN32
wresize(a->window, LINES - 2, COLS);
#endif
a->onDraw(a, m);
wrefresh(a->window);
/* Handle input */
bool ltr;
@ -419,7 +464,7 @@ void draw_active_window(Tox *m)
/* TODO verify if this works */
ltr = isprint(ch);
#endif
#endif /* HAVE_WIDECHAR */
if (!ltr && (ch == T_KEY_NEXT || ch == T_KEY_PREV)) {
set_next_window((int) ch);
@ -439,7 +484,7 @@ void refresh_inactive_windows(void)
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
ToxWindow *a = &windows[i];
if (a->active && a != active_window && (a->is_chat || a->is_groupchat))
if (a->active && a != active_window && !a->is_friendlist)
line_info_print(a);
}
}
@ -452,6 +497,8 @@ int get_num_active_windows(void)
/* destroys all chat and groupchat windows (should only be called on shutdown) */
void kill_all_windows(void)
{
kill_prompt_window(prompt);
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {

View File

@ -36,8 +36,9 @@
#include "toxic.h"
#define MAX_WINDOWS_NUM 32
#define CURS_Y_OFFSET 3 /* y-axis cursor offset for chat contexts */
#define CHATBOX_HEIGHT 4
#define MAX_WINDOW_NAME_LENGTH 16
#define CURS_Y_OFFSET 1 /* y-axis cursor offset for chat contexts */
#define CHATBOX_HEIGHT 2
/* Curses foreground colours (background is black) */
enum {
@ -65,32 +66,35 @@ enum {
struct _Winthread {
pthread_t tid;
pthread_mutex_t lock;
bool sig_exit_toxic;
bool flag_resize;
};
typedef struct ToxWindow ToxWindow;
typedef struct StatusBar StatusBar;
typedef struct PromptBuf PromptBuf;
typedef struct ChatContext ChatContext;
typedef struct Help Help;
struct ToxWindow {
void(*onKey)(ToxWindow *, Tox *, wint_t, bool);
void(*onDraw)(ToxWindow *, Tox *);
void(*onInit)(ToxWindow *, Tox *);
void(*onFriendRequest)(ToxWindow *, Tox *, const uint8_t *, const uint8_t *, uint16_t);
void(*onFriendRequest)(ToxWindow *, Tox *, const char *, const char *, uint16_t);
void(*onFriendAdded)(ToxWindow *, Tox *, int32_t, bool);
void(*onConnectionChange)(ToxWindow *, Tox *, int32_t, uint8_t);
void(*onMessage)(ToxWindow *, Tox *, int32_t, uint8_t *, uint16_t);
void(*onNickChange)(ToxWindow *, Tox *, int32_t, uint8_t *, uint16_t);
void(*onMessage)(ToxWindow *, Tox *, int32_t, const char *, uint16_t);
void(*onNickChange)(ToxWindow *, Tox *, int32_t, const char *, uint16_t);
void(*onStatusChange)(ToxWindow *, Tox *, int32_t, uint8_t);
void(*onStatusMessageChange)(ToxWindow *, int32_t, uint8_t *, uint16_t);
void(*onAction)(ToxWindow *, Tox *, int32_t, uint8_t *, uint16_t);
void(*onGroupMessage)(ToxWindow *, Tox *, int, int, uint8_t *, uint16_t);
void(*onGroupAction)(ToxWindow *, Tox *, int, int, uint8_t *, uint16_t);
void(*onGroupInvite)(ToxWindow *, Tox *, int32_t, uint8_t *);
void(*onStatusMessageChange)(ToxWindow *, int32_t, const char *, uint16_t);
void(*onAction)(ToxWindow *, Tox *, int32_t, const char *, uint16_t);
void(*onGroupMessage)(ToxWindow *, Tox *, int, int, const char *, uint16_t);
void(*onGroupAction)(ToxWindow *, Tox *, int, int, const char *, uint16_t);
void(*onGroupInvite)(ToxWindow *, Tox *, int32_t, const char *);
void(*onGroupNamelistChange)(ToxWindow *, Tox *, int, int, uint8_t);
void(*onFileSendRequest)(ToxWindow *, Tox *, int32_t, uint8_t, uint64_t, uint8_t *, uint16_t);
void(*onFileControl)(ToxWindow *, Tox *, int32_t, uint8_t, uint8_t, uint8_t, uint8_t *, uint16_t);
void(*onFileData)(ToxWindow *, Tox *, int32_t, uint8_t, uint8_t *, uint16_t);
void(*onFileSendRequest)(ToxWindow *, Tox *, int32_t, uint8_t, uint64_t, const char *, uint16_t);
void(*onFileControl)(ToxWindow *, Tox *, int32_t, uint8_t, uint8_t, uint8_t, const char *, uint16_t);
void(*onFileData)(ToxWindow *, Tox *, int32_t, uint8_t, const char *, uint16_t);
void(*onTypingChange)(ToxWindow *, Tox *, int32_t, uint8_t);
#ifdef _SUPPORT_AUDIO
@ -107,19 +111,21 @@ struct ToxWindow {
void(*onRequestTimeout)(ToxWindow *, ToxAv *, int);
void(*onPeerTimeout)(ToxWindow *, ToxAv *, int);
int call_index; /* If in a call will have this index set, otherwise it's -1.
* Don't modify outside av callbacks. */
int call_idx; /* If in a call will have this index set, otherwise it's -1.
* Don't modify outside av callbacks. */
int device_selection[2]; /* -1 if not set, if set uses these selections instead of primary device */
#endif /* _SUPPORT_AUDIO */
char name[TOX_MAX_NAME_LENGTH];
char name[TOXIC_MAX_NAME_LENGTH];
int32_t num; /* corresponds to friendnumber in chat windows */
bool active;
int x;
/* window type identifiers */
bool is_chat;
bool is_groupchat;
bool is_prompt;
bool is_friendlist;
bool alert0;
bool alert1;
@ -127,46 +133,77 @@ struct ToxWindow {
ChatContext *chatwin;
StatusBar *stb;
Help *help;
WINDOW *popup;
WINDOW *window;
};
/* statusbar info holder */
struct StatusBar {
WINDOW *topline;
uint8_t statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH];
char statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH];
uint16_t statusmsg_len;
uint8_t nick[TOX_MAX_NAME_LENGTH];
uint16_t nick_len;
char nick[TOXIC_MAX_NAME_LENGTH];
int nick_len;
uint8_t status;
bool is_online;
};
#ifdef _SUPPORT_AUDIO
#define INFOBOX_HEIGHT 7
#define INFOBOX_WIDTH 21
/* holds display info for audio calls */
struct infobox {
float vad_lvl;
bool in_is_muted;
bool out_is_muted;
bool hide;
bool active;
uint64_t lastupdate;
uint64_t starttime;
char timestr[TIME_STR_SIZE];
WINDOW *win;
};
#endif /* _SUPPORT_AUDIO */
#define MAX_LINE_HIST 128
/* chat and groupchat window/buffer holder */
struct ChatContext {
wchar_t line[MAX_STR_SIZE];
size_t pos;
size_t len;
int pos;
int len;
int start; /* the position to start printing line at */
wchar_t ln_history[MAX_LINE_HIST][MAX_STR_SIZE]; /* history for input lines/commands */
int hst_pos;
int hst_tot;
wchar_t yank[MAX_STR_SIZE]; /* contains last killed/discarded line */
int yank_len;
struct history *hst;
struct chatlog *log;
#ifdef _SUPPORT_AUDIO
struct infobox infobox;
#endif
uint8_t self_is_typing;
WINDOW *history;
WINDOW *linewin;
WINDOW *sidebar;
};
/* specific for prompt */
bool at_bottom; /* true if line end is at bottom of window */
int orig_y; /* y axis point of line origin */
struct Help {
WINDOW *win;
int type;
bool active;
};
ToxWindow *init_windows(Tox *m);
@ -176,6 +213,10 @@ void del_window(ToxWindow *w);
void set_active_window(int ch);
int get_num_active_windows(void);
void kill_all_windows(void); /* should only be called on shutdown */
void on_window_resize(int sig);
void on_window_resize(void);
/* refresh inactive windows to prevent scrolling bugs.
call at least once per second */
void refresh_inactive_windows(void);
#endif /* #define _windows_h */