mirror of
https://github.com/Tha14/toxic.git
synced 2025-06-27 05:06:46 +02:00
Compare commits
162 Commits
Author | SHA1 | Date | |
---|---|---|---|
bf09b3b6c4 | |||
2d3c5c9450 | |||
ae87b2eb2d | |||
c34ecc8dfd | |||
2c2938c647 | |||
22dd883f28 | |||
dfbb1338a5 | |||
f8dc82516e | |||
59b16f7760 | |||
a11289de79 | |||
a64b8cae89 | |||
470eaeb97b | |||
6503349ed3 | |||
ec23cedc3a | |||
ce1ae1d7dc | |||
6669d5632f | |||
59e1114997 | |||
c20510e5aa | |||
2b2e746549 | |||
dc5a8d44e5 | |||
090d3339a0 | |||
442d9e22b4 | |||
0c39e7b158 | |||
3e3f2614b5 | |||
53e4b2c971 | |||
d6c57c7aa3 | |||
3efc984ae9 | |||
7618a0871a | |||
b87f73cc47 | |||
785d39d78f | |||
38a0f6fae4 | |||
710be51cad | |||
50438425e5 | |||
4b4bfe8876 | |||
67da4bdd5b | |||
e230badb47 | |||
d48d9ed4dc | |||
b9fe6bfa10 | |||
5cbbb62ce2 | |||
3369c9d808 | |||
dfc594f949 | |||
d714cda145 | |||
428e1e4100 | |||
2b19f56e63 | |||
4badc983ea | |||
c8a4f88ff3 | |||
eeeaf8d707 | |||
37b3b5a5ed | |||
a561ef8c49 | |||
89f200e870 | |||
2823115a6c | |||
5599d73760 | |||
bac66cb5ad | |||
61c50972e3 | |||
ff0fbbc379 | |||
4a124dea43 | |||
e722b665d1 | |||
4365b8d5ad | |||
e55e5f3f7e | |||
d1036c8538 | |||
9240f62829 | |||
1b89bc9051 | |||
7700ef83e0 | |||
9922b3a4f3 | |||
d561d2e1ac | |||
7865cea284 | |||
424189cad9 | |||
82aa64e8f7 | |||
a0418520a2 | |||
f451d961bc | |||
a4da9fd49e | |||
0a0891fa98 | |||
9464b369a4 | |||
47692edee4 | |||
73c94b25ba | |||
ab2ea5936d | |||
90985af007 | |||
5aad8764b1 | |||
5a175f374a | |||
4acfe84171 | |||
e995a1cb69 | |||
867f041c23 | |||
7e49ba92b2 | |||
2fa53c0531 | |||
673800c947 | |||
835b821b75 | |||
78587ad20b | |||
09bbec79cf | |||
751b5f9943 | |||
4a337ae3cb | |||
1baeb15073 | |||
141b36af04 | |||
4238c20e72 | |||
4e177d60b0 | |||
1bd880708b | |||
76c21c8b34 | |||
dd8c2caac7 | |||
7a7e8a7f8d | |||
43f45d67a4 | |||
adb36a39bb | |||
5a0d9f5e9f | |||
a4e8cb3971 | |||
e22b7a336c | |||
317fa42b20 | |||
884f8dda37 | |||
f5090532fb | |||
ae04dd8fa5 | |||
00e4075937 | |||
d65f3ea58d | |||
008163bf6c | |||
f09002a49a | |||
431290d47a | |||
b66874b7b3 | |||
1b9fd7f936 | |||
0a1457acde | |||
d2008aa92f | |||
e83356faef | |||
fd4161832b | |||
0a132b0eb5 | |||
9c7ac9043a | |||
b86c0d357f | |||
75dd26518f | |||
2cc261c619 | |||
f7d46f1100 | |||
be264528d2 | |||
c825adc1e3 | |||
4e9f125e95 | |||
d26c8fe447 | |||
e42d635195 | |||
a32cd1c19b | |||
14dc02ac83 | |||
e4a28d1839 | |||
0908920b51 | |||
8a882916fb | |||
55ada8ad2f | |||
2094186c0f | |||
d3a489b756 | |||
e6b18231c0 | |||
cc0145d561 | |||
9f0daca5eb | |||
1f2bd44dce | |||
6492bd12f9 | |||
43552161f9 | |||
e5d45fdf1d | |||
bd69c8da18 | |||
8c3e3ebe24 | |||
7eebbd982d | |||
5c66f5c161 | |||
40f70fc1e3 | |||
9cf4427375 | |||
23cf9686cb | |||
70add920fe | |||
c56c6cc219 | |||
e9a0296851 | |||
de30433e26 | |||
fa64fa8b93 | |||
50c7942cb5 | |||
e7697b8fba | |||
b46a77f977 | |||
38909afa89 | |||
5af561c811 | |||
ae984d4f04 |
@ -1,15 +1,15 @@
|
|||||||
language: c
|
language: c
|
||||||
compiler:
|
compiler:
|
||||||
- gcc
|
- gcc
|
||||||
# - clang # Fix me
|
- clang
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
# Installing yasm (needed for compiling vpx) and openal
|
# Installing yasm (needed for compiling vpx) and openal
|
||||||
- sudo apt-get -yq install yasm libopenal-dev libconfig-dev libalut-dev libnotify-dev asciidoc
|
- sudo apt-get -yq install yasm libopenal-dev libconfig-dev libalut-dev libnotify-dev clang llvm-dev
|
||||||
# Installing libsodium, needed for toxcore
|
# Installing libsodium, needed for toxcore
|
||||||
- git clone https://github.com/jedisct1/libsodium.git libsodium
|
- git clone https://github.com/jedisct1/libsodium.git libsodium
|
||||||
- cd libsodium
|
- cd libsodium
|
||||||
- git checkout tags/0.7.0 > /dev/null
|
- git checkout tags/1.0.2 > /dev/null
|
||||||
- ./autogen.sh > /dev/null
|
- ./autogen.sh > /dev/null
|
||||||
- ./configure > /dev/null
|
- ./configure > /dev/null
|
||||||
- make check -j2 || make check || exit 1 > /dev/null
|
- make check -j2 || make check || exit 1 > /dev/null
|
||||||
@ -41,7 +41,6 @@ before_script:
|
|||||||
- sudo make install
|
- sudo make install
|
||||||
- cd ..
|
- cd ..
|
||||||
script:
|
script:
|
||||||
- cd build
|
|
||||||
- make -j2 || make || exit 1
|
- make -j2 || make || exit 1
|
||||||
notifications:
|
notifications:
|
||||||
email: false
|
email: false
|
||||||
|
68
INSTALL.md
Normal file
68
INSTALL.md
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
# Installation
|
||||||
|
* [Dependencies](#deps)
|
||||||
|
* [OS X Notes](#deps_osx)
|
||||||
|
* [Compiling](#compiling)
|
||||||
|
* [Documentation](#docs)
|
||||||
|
* [Notes](#notes)
|
||||||
|
* [Compilation variables](#comp_vars)
|
||||||
|
* [Packaging](#packaging)
|
||||||
|
|
||||||
|
<a name="deps" />
|
||||||
|
## Dependencies
|
||||||
|
| Name | Needed by | Debian package |
|
||||||
|
|------------------------------------------------------|----------------------------|------------------|
|
||||||
|
| [Tox Core](https://github.com/irungentoo/toxcore) | BASE | *None* |
|
||||||
|
| [NCurses](https://www.gnu.org/software/ncurses) | BASE | libncursesw5-dev |
|
||||||
|
| [LibConfig](http://www.hyperrealm.com/libconfig) | BASE | libconfig-dev |
|
||||||
|
| [GNUmake](https://www.gnu.org/software/make) | BASE | make |
|
||||||
|
| [Tox Core AV](https://github.com/irungentoo/toxcore) | AUDIO | *None* |
|
||||||
|
| [OpenAL](http://openal.org) | AUDIO, SOUND NOTIFICATIONS | libopenal-dev |
|
||||||
|
| [OpenALUT](http://openal.org) | SOUND NOTIFICATIONS | libalut-dev |
|
||||||
|
| [LibNotify](https://developer.gnome.org/libnotify) | DESKTOP NOTIFICATIONS | libnotify-dev |
|
||||||
|
| [AsciiDoc](http://asciidoc.org/index.html) | DOCUMENTATION<sup>1</sup> | asciidoc |
|
||||||
|
<sup>1</sup>: see [Documentation](#docs)
|
||||||
|
|
||||||
|
<a name="deps_osx" />
|
||||||
|
#### OS X Notes
|
||||||
|
Using [Homebrew](http://brew.sh):
|
||||||
|
```
|
||||||
|
brew install openal-soft freealut libconfig
|
||||||
|
brew install https://raw.githubusercontent.com/Tox/homebrew-tox/master/Formula/libtoxcore.rb
|
||||||
|
brew install https://raw.githubusercontent.com/Homebrew/homebrew-x11/master/libnotify.rb
|
||||||
|
```
|
||||||
|
|
||||||
|
You can omit `libnotify` if you intend to build without desktop notifications enabled.
|
||||||
|
|
||||||
|
<a name="Compiling">
|
||||||
|
## Compiling
|
||||||
|
```
|
||||||
|
make PREFIX="/where/to/install"
|
||||||
|
sudo make install PREFIX="/where/to/install"
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="docs" />
|
||||||
|
#### Documentation
|
||||||
|
Run `make doc` in the build directory after editing the asciidoc files to regenerate the manpages.<br />
|
||||||
|
**NOTE FOR DEVELOPERS**: asciidoc files and generated manpages will need to be commited together.<br />
|
||||||
|
**NOTE FOR EVERYONE**: [asciidoc](http://asciidoc.org/index.html) (and this step) is only required for regenerating manpages when you modify them.
|
||||||
|
|
||||||
|
<a name="notes" />
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
<a name="comp_vars" />
|
||||||
|
#### Compilation variables
|
||||||
|
* You can add specific flags to the Makefile with `USER_CFLAGS=""` and/or `USER_LDFLAGS=""`
|
||||||
|
* You can pass your own flags to the Makefile with `CFLAGS=""` and/or `LDFLAGS=""` (this will supersede the default ones)
|
||||||
|
* Additional features are automatically enabled if all dependencies are found, but you can disable them by using special variables:
|
||||||
|
* `DISABLE_X11=1` → build toxic without X11 support (needed for focus tracking)
|
||||||
|
* `DISABLE_AV=1` → build toxic without audio call support
|
||||||
|
* `DISABLE_SOUND_NOTIFY=1` → build toxic without sound notifications support
|
||||||
|
* `DISABLE_DESKTOP_NOTIFY=1` → build toxic without desktop notifications support
|
||||||
|
|
||||||
|
<a name="packaging" />
|
||||||
|
#### Packaging
|
||||||
|
* For packaging purpose, you can use `DESTDIR=""` to specify a directory where to store installed files
|
||||||
|
* `DESTDIR=""` can be used in addition to `PREFIX=""`:
|
||||||
|
* `DESTDIR=""` is meant to specify a directory where to store installed files (ex: "/tmp/build/pkg")
|
||||||
|
* `PREFIX=""` is meant to specify a prefix directory for binaries and data files (ex: "/usr/local")
|
||||||
|
|
77
Makefile
Normal file
77
Makefile
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
BASE_DIR = $(shell pwd -P)
|
||||||
|
CFG_DIR = $(BASE_DIR)/cfg
|
||||||
|
|
||||||
|
-include $(CFG_DIR)/global_vars.mk
|
||||||
|
|
||||||
|
LIBS = libtoxcore ncursesw libconfig
|
||||||
|
|
||||||
|
CFLAGS = -std=gnu99 -pthread -Wall -g
|
||||||
|
CFLAGS += '-DTOXICVER="$(VERSION)"' -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED -D_FILE_OFFSET_BITS=64
|
||||||
|
CFLAGS += '-DPACKAGE_DATADIR="$(abspath $(DATADIR))"'
|
||||||
|
CFLAGS += $(USER_CFLAGS)
|
||||||
|
LDFLAGS = $(USER_LDFLAGS)
|
||||||
|
|
||||||
|
OBJ = chat.o chat_commands.o configdir.o dns.o execute.o file_transfers.o notify.o
|
||||||
|
OBJ += friendlist.o global_commands.o groupchat.o line_info.o input.o help.o autocomplete.o
|
||||||
|
OBJ += log.o misc_tools.o prompt.o settings.o toxic.o toxic_strings.o windows.o message_queue.o
|
||||||
|
OBJ += group_commands.o term_mplex.o
|
||||||
|
|
||||||
|
# Check on wich system we are running
|
||||||
|
UNAME_S = $(shell uname -s)
|
||||||
|
ifeq ($(UNAME_S), Linux)
|
||||||
|
-include $(CFG_DIR)/systems/Linux.mk
|
||||||
|
endif
|
||||||
|
ifeq ($(UNAME_S), FreeBSD)
|
||||||
|
-include $(CFG_DIR)/systems/FreeBSD.mk
|
||||||
|
endif
|
||||||
|
ifeq ($(UNAME_S), OpenBSD)
|
||||||
|
-include $(CFG_DIR)/systems/FreeBSD.mk
|
||||||
|
endif
|
||||||
|
ifeq ($(UNAME_S), Darwin)
|
||||||
|
-include $(CFG_DIR)/systems/Darwin.mk
|
||||||
|
endif
|
||||||
|
ifeq ($(UNAME_S), Solaris)
|
||||||
|
-include $(CFG_DIR)/systems/Solaris.mk
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Check on which platform we are running
|
||||||
|
UNAME_M = $(shell uname -m)
|
||||||
|
ifeq ($(UNAME_M), x86_64)
|
||||||
|
-include $(CFG_DIR)/platforms/x86_64.mk
|
||||||
|
endif
|
||||||
|
ifneq ($(filter %86, $(UNAME_M)),)
|
||||||
|
-include $(CFG_DIR)/platforms/x86.mk
|
||||||
|
endif
|
||||||
|
ifneq ($(filter arm%, $(UNAME_M)),)
|
||||||
|
-include $(CFG_DIR)/platforms/arm.mk
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Include all needed checks
|
||||||
|
-include $(CFG_DIR)/checks/check_features.mk
|
||||||
|
|
||||||
|
# Fix path for object files
|
||||||
|
OBJ := $(addprefix $(BUILD_DIR)/, $(OBJ))
|
||||||
|
|
||||||
|
# Targets
|
||||||
|
all: $(BUILD_DIR)/toxic
|
||||||
|
|
||||||
|
$(BUILD_DIR)/toxic: $(OBJ)
|
||||||
|
@echo " LD $(@:$(BUILD_DIR)/%=%)"
|
||||||
|
@$(CC) $(CFLAGS) -o $(BUILD_DIR)/toxic $(OBJ) $(LDFLAGS)
|
||||||
|
|
||||||
|
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
|
||||||
|
@if [ ! -e $(BUILD_DIR) ]; then \
|
||||||
|
mkdir -p $(BUILD_DIR) ;\
|
||||||
|
fi
|
||||||
|
@echo " CC $(@:$(BUILD_DIR)/%=%)"
|
||||||
|
@$(CC) $(CFLAGS) -o $(BUILD_DIR)/$*.o -c $(SRC_DIR)/$*.c
|
||||||
|
@$(CC) -MM $(CFLAGS) $(SRC_DIR)/$*.c > $(BUILD_DIR)/$*.d
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(BUILD_DIR)/*.d $(BUILD_DIR)/*.o $(BUILD_DIR)/toxic
|
||||||
|
|
||||||
|
-include $(BUILD_DIR)/$(OBJ:.o=.d)
|
||||||
|
|
||||||
|
-include $(CFG_DIR)/targets/*.mk
|
||||||
|
|
||||||
|
.PHONY: clean all
|
67
README.md
67
README.md
@ -1,53 +1,31 @@
|
|||||||
# Toxic [](https://travis-ci.org/Tox/toxic)
|
# Toxic [](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 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.
|
||||||
|
|
||||||

|
[](https://i.imgur.com/san99Z2.png)
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
[Use our repositories](https://wiki.tox.im/Binaries#Linux)<br />
|
||||||
|
[Compile it yourself](/INSTALL.md)
|
||||||
|
|
||||||
### Dependencies
|
## Downloads
|
||||||
##### Base
|
If you don't like installation methods listed above, you can still download precompiled binaries from [jenkins](https://jenkins.libtoxcore.so):
|
||||||
* [libtoxcore](https://github.com/irungentoo/toxcore)
|
* [Linux 32 bit](https://jenkins.libtoxcore.so/job/toxic_linux_i386/lastSuccessfulBuild/artifact/toxic_linux_i386.tar.xz) [](https://jenkins.libtoxcore.so/job/toxic_linux_i386/lastSuccessfulBuild/artifact/toxic_linux_i386.tar.xz)
|
||||||
* [ncurses](https://www.gnu.org/software/ncurses) (for Debian based systems, 'libncursesw5-dev')
|
* [Linux 64 bit](https://jenkins.libtoxcore.so/job/toxic_linux_amd64/lastSuccessfulBuild/artifact/toxic_linux_amd64.tar.xz) [](https://jenkins.libtoxcore.so/job/toxic_linux_amd64/lastSuccessfulBuild/artifact/toxic_linux_amd64.tar.xz)
|
||||||
* [libconfig](http://www.hyperrealm.com/libconfig) (for Debian based systems, 'libconfig-dev')
|
* [~~Linux ARMv6~~](https://jenkins.libtoxcore.so/job/toxic_linux_armv6/lastSuccessfulBuild/artifact/toxic_linux_armv6.tar.xz) **CURRENTLY DISABLED** [](https://jenkins.libtoxcore.so/job/toxic_linux_armv6/lastSuccessfulBuild/artifact/toxic_linux_armv6.tar.xz)
|
||||||
|
|
||||||
##### Audio
|
#### DEBs packages
|
||||||
* libtoxav ([libtoxcore](https://github.com/irungentoo/toxcore) compiled with audio support)
|
* [toxic-i386.deb](https://jenkins.libtoxcore.so/job/toxic-linux-pkg/lastSuccessfulBuild/artifact/toxic-i386.deb)
|
||||||
* [openal](http://openal.org) (for Debian based systems, 'libopenal-dev')
|
* [toxic-x86_64.deb](https://jenkins.libtoxcore.so/job/toxic-linux-pkg/lastSuccessfulBuild/artifact/toxic-x86_64.deb)
|
||||||
|
|
||||||
##### Sound notifications
|
#### RPMs packages
|
||||||
* [openal](http://openal.org) (for Debian based systems, 'libopenal-dev')
|
* [toxic-i386.rpm](https://jenkins.libtoxcore.so/job/toxic-linux-pkg/lastSuccessfulBuild/artifact/toxic-i386.rpm)
|
||||||
* [openalut](http://openal.org) (for Debian based systems, 'libalut-dev')
|
* [toxic-x86_64.rpm](https://jenkins.libtoxcore.so/job/toxic-linux-pkg/lastSuccessfulBuild/artifact/toxic-x86_64.rpm)
|
||||||
|
|
||||||
##### Desktop notifications
|
## Settings
|
||||||
* [libnotify](https://developer.gnome.org/libnotify) (for Debian based systems, 'libnotify-dev')
|
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).
|
||||||
|
|
||||||
##### Documentation
|
## Troubleshooting
|
||||||
* [Asciidoc](http://asciidoc.org/index.html) (only required for regenerating manpages)
|
|
||||||
* Run `make doc` after editing the asciidoc files to regenerate the manpages.
|
|
||||||
* **NOTE FOR DEVELOPERS**: asciidoc files and generated manpages will need to be commited together.
|
|
||||||
|
|
||||||
### 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)
|
|
||||||
* Additional features are automatically enabled if all dependencies are found, but you can disable them by using special variables:
|
|
||||||
* `DISABLE_X11=1` → build toxic without X11 support (needed for focus tracking)
|
|
||||||
* `DISABLE_AV=1` → build toxic without audio call support
|
|
||||||
* `DISABLE_SOUND_NOTIFY=1` → build toxic without sound notifications support
|
|
||||||
* `DISABLE_DESKTOP_NOTIFY=1` → build toxic without desktop notifications support
|
|
||||||
|
|
||||||
### 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:
|
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
|
error while loading shared libraries: libtoxcore.so.0: cannot open shared object file: No such file or directory
|
||||||
@ -58,12 +36,3 @@ echo '/usr/local/lib/' | sudo tee -a /etc/ld.so.conf.d/locallib.conf
|
|||||||
sudo ldconfig
|
sudo ldconfig
|
||||||
```
|
```
|
||||||
|
|
||||||
## Precompiled binaries
|
|
||||||
You can download precompiled binaries from [jenkins](https://jenkins.libtoxcore.so):
|
|
||||||
* [Linux 32 bit](https://jenkins.libtoxcore.so/job/toxic_linux_i386/lastSuccessfulBuild/artifact/toxic_linux_i386.tar.xz)
|
|
||||||
* [Linux 64 bit](https://jenkins.libtoxcore.so/job/toxic_linux_amd64/lastSuccessfulBuild/artifact/toxic_linux_amd64.tar.xz)
|
|
||||||
|
|
||||||
## Settings
|
|
||||||
Running Toxic for the first time creates an empty file called toxic.conf in your home configuration directory ("~/.config/tox" for Linux users). Adding options to this file allows you to enable auto-logging, change the time format (12/24 hour), and much more.
|
|
||||||
You can view our example config file [here](misc/toxic.conf.example).
|
|
||||||
|
|
||||||
|
@ -1,67 +0,0 @@
|
|||||||
BASE_DIR = $(shell cd .. && pwd -P)
|
|
||||||
CFG_DIR = $(BASE_DIR)/cfg
|
|
||||||
|
|
||||||
-include $(CFG_DIR)/global_vars.mk
|
|
||||||
|
|
||||||
LIBS = libtoxcore ncursesw libconfig
|
|
||||||
|
|
||||||
CFLAGS = -std=gnu99 -pthread -Wall -g
|
|
||||||
CFLAGS += '-DTOXICVER="$(VERSION)"' -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED -D_FILE_OFFSET_BITS=64
|
|
||||||
CFLAGS += '-DPACKAGE_DATADIR="$(abspath $(DATADIR))"'
|
|
||||||
CFLAGS += $(USER_CFLAGS)
|
|
||||||
LDFLAGS = $(USER_LDFLAGS)
|
|
||||||
|
|
||||||
OBJ = chat.o chat_commands.o configdir.o dns.o execute.o file_senders.o notify.o
|
|
||||||
OBJ += friendlist.o global_commands.o groupchat.o line_info.o input.o help.o autocomplete.o
|
|
||||||
OBJ += log.o misc_tools.o prompt.o settings.o toxic.o toxic_strings.o windows.o message_queue.o
|
|
||||||
|
|
||||||
# Check on wich system we are running
|
|
||||||
UNAME_S = $(shell uname -s)
|
|
||||||
ifeq ($(UNAME_S), Linux)
|
|
||||||
-include $(CFG_DIR)/systems/Linux.mk
|
|
||||||
endif
|
|
||||||
ifeq ($(UNAME_S), FreeBSD)
|
|
||||||
-include $(CFG_DIR)/systems/FreeBSD.mk
|
|
||||||
endif
|
|
||||||
ifeq ($(UNAME_S), Darwin)
|
|
||||||
-include $(CFG_DIR)/systems/Darwin.mk
|
|
||||||
endif
|
|
||||||
ifeq ($(UNAME_S), Solaris)
|
|
||||||
-include $(CFG_DIR)/systems/Solaris.mk
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Check on which platform we are running
|
|
||||||
UNAME_M = $(shell uname -m)
|
|
||||||
ifeq ($(UNAME_M), x86_64)
|
|
||||||
-include $(CFG_DIR)/platforms/x86_64.mk
|
|
||||||
endif
|
|
||||||
ifneq ($(filter %86, $(UNAME_M)),)
|
|
||||||
-include $(CFG_DIR)/platforms/x86.mk
|
|
||||||
endif
|
|
||||||
ifneq ($(filter arm%, $(UNAME_M)),)
|
|
||||||
-include $(CFG_DIR)/platforms/arm.mk
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Include all needed checks
|
|
||||||
-include $(CFG_DIR)/checks/check_features.mk
|
|
||||||
|
|
||||||
# Targets
|
|
||||||
all: toxic doc
|
|
||||||
|
|
||||||
toxic: $(OBJ)
|
|
||||||
@echo " LD $@"
|
|
||||||
@$(CC) $(CFLAGS) -o toxic $(OBJ) $(LDFLAGS)
|
|
||||||
|
|
||||||
%.o: $(SRC_DIR)/%.c
|
|
||||||
@echo " CC $@"
|
|
||||||
@$(CC) $(CFLAGS) -o $*.o -c $(SRC_DIR)/$*.c
|
|
||||||
@$(CC) -MM $(CFLAGS) $(SRC_DIR)/$*.c > $*.d
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f *.d *.o toxic
|
|
||||||
|
|
||||||
-include $(OBJ:.o=.d)
|
|
||||||
|
|
||||||
-include $(CFG_DIR)/targets/*.mk
|
|
||||||
|
|
||||||
.PHONY: clean all
|
|
@ -2,22 +2,20 @@
|
|||||||
AUDIO_LIBS = libtoxav openal
|
AUDIO_LIBS = libtoxav openal
|
||||||
AUDIO_CFLAGS = -DAUDIO
|
AUDIO_CFLAGS = -DAUDIO
|
||||||
ifneq (, $(findstring device.o, $(OBJ)))
|
ifneq (, $(findstring device.o, $(OBJ)))
|
||||||
AUDIO_OBJ = audio_call.o
|
AUDIO_OBJ = audio_call.o
|
||||||
else
|
else
|
||||||
AUDIO_OBJ = audio_call.o device.o
|
AUDIO_OBJ = audio_call.o device.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Check if we can build audio support
|
# Check if we can build audio support
|
||||||
CHECK_AUDIO_LIBS = $(shell pkg-config --exists $(AUDIO_LIBS) || echo -n "error")
|
CHECK_AUDIO_LIBS = $(shell pkg-config --exists $(AUDIO_LIBS) || echo -n "error")
|
||||||
ifneq ($(CHECK_AUDIO_LIBS), error)
|
ifneq ($(CHECK_AUDIO_LIBS), error)
|
||||||
LIBS += $(AUDIO_LIBS)
|
LIBS += $(AUDIO_LIBS)
|
||||||
CFLAGS += $(AUDIO_CFLAGS)
|
CFLAGS += $(AUDIO_CFLAGS)
|
||||||
OBJ += $(AUDIO_OBJ)
|
OBJ += $(AUDIO_OBJ)
|
||||||
else
|
else ifneq ($(MAKECMDGOALS), clean)
|
||||||
ifneq ($(MAKECMDGOALS), clean)
|
MISSING_AUDIO_LIBS = $(shell for lib in $(AUDIO_LIBS) ; do if ! pkg-config --exists $$lib ; then echo $$lib ; fi ; done)
|
||||||
MISSING_AUDIO_LIBS = $(shell for lib in $(AUDIO_LIBS) ; do if ! pkg-config --exists $$lib ; then echo $$lib ; fi ; done)
|
$(warning WARNING -- Toxic will be compiled without audio support)
|
||||||
$(warning WARNING -- Toxic will be compiled without audio support)
|
$(warning WARNING -- You need these libraries for audio support)
|
||||||
$(warning WARNING -- You need these libraries for audio support)
|
$(warning WARNING -- $(MISSING_AUDIO_LIBS))
|
||||||
$(warning WARNING -- $(MISSING_AUDIO_LIBS))
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
|
@ -3,38 +3,36 @@ CHECKS_DIR = $(CFG_DIR)/checks
|
|||||||
# Check if we want build X11 support
|
# Check if we want build X11 support
|
||||||
X11 = $(shell if [ -z "$(DISABLE_X11)" ] || [ "$(DISABLE_X11)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
|
X11 = $(shell if [ -z "$(DISABLE_X11)" ] || [ "$(DISABLE_X11)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
|
||||||
ifneq ($(X11), disabled)
|
ifneq ($(X11), disabled)
|
||||||
-include $(CHECKS_DIR)/x11.mk
|
-include $(CHECKS_DIR)/x11.mk
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Check if we want build audio support
|
# Check if we want build audio support
|
||||||
AUDIO = $(shell if [ -z "$(DISABLE_AV)" ] || [ "$(DISABLE_AV)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
|
AUDIO = $(shell if [ -z "$(DISABLE_AV)" ] || [ "$(DISABLE_AV)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
|
||||||
ifneq ($(AUDIO), disabled)
|
ifneq ($(AUDIO), disabled)
|
||||||
-include $(CHECKS_DIR)/av.mk
|
-include $(CHECKS_DIR)/av.mk
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Check if we want build sound notifications support
|
# Check if we want build sound notifications support
|
||||||
SND_NOTIFY = $(shell if [ -z "$(DISABLE_SOUND_NOTIFY)" ] || [ "$(DISABLE_SOUND_NOTIFY)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
|
SND_NOTIFY = $(shell if [ -z "$(DISABLE_SOUND_NOTIFY)" ] || [ "$(DISABLE_SOUND_NOTIFY)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
|
||||||
ifneq ($(SND_NOTIFY), disabled)
|
ifneq ($(SND_NOTIFY), disabled)
|
||||||
-include $(CHECKS_DIR)/sound_notifications.mk
|
-include $(CHECKS_DIR)/sound_notifications.mk
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Check if we want build desktop notifications support
|
# Check if we want build desktop notifications support
|
||||||
DESK_NOTIFY = $(shell if [ -z "$(DISABLE_DESKTOP_NOTIFY)" ] || [ "$(DISABLE_DESKTOP_NOTIFY)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
|
DESK_NOTIFY = $(shell if [ -z "$(DISABLE_DESKTOP_NOTIFY)" ] || [ "$(DISABLE_DESKTOP_NOTIFY)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
|
||||||
ifneq ($(DESK_NOTIFY), disabled)
|
ifneq ($(DESK_NOTIFY), disabled)
|
||||||
-include $(CHECKS_DIR)/desktop_notifications.mk
|
-include $(CHECKS_DIR)/desktop_notifications.mk
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Check if we can build Toxic
|
# Check if we can build Toxic
|
||||||
CHECK_LIBS = $(shell pkg-config --exists $(LIBS) || echo -n "error")
|
CHECK_LIBS = $(shell pkg-config --exists $(LIBS) || echo -n "error")
|
||||||
ifneq ($(CHECK_LIBS), error)
|
ifneq ($(CHECK_LIBS), error)
|
||||||
CFLAGS += $(shell pkg-config --cflags $(LIBS))
|
CFLAGS += $(shell pkg-config --cflags $(LIBS))
|
||||||
LDFLAGS += $(shell pkg-config --libs $(LIBS))
|
LDFLAGS += $(shell pkg-config --libs $(LIBS))
|
||||||
else
|
else ifneq ($(MAKECMDGOALS), clean)
|
||||||
ifneq ($(MAKECMDGOALS), clean)
|
MISSING_LIBS = $(shell for lib in $(LIBS) ; do if ! pkg-config --exists $$lib ; then echo $$lib ; fi ; done)
|
||||||
MISSING_LIBS = $(shell for lib in $(LIBS) ; do if ! pkg-config --exists $$lib ; then echo $$lib ; fi ; done)
|
$(warning ERROR -- Cannot compile Toxic)
|
||||||
$(warning ERROR -- Cannot compile Toxic)
|
$(warning ERROR -- You need these libraries)
|
||||||
$(warning ERROR -- You need these libraries)
|
$(warning ERROR -- $(MISSING_LIBS))
|
||||||
$(warning ERROR -- $(MISSING_LIBS))
|
$(error ERROR)
|
||||||
$(error ERROR)
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
|
@ -5,13 +5,11 @@ DESK_NOTIFY_CFLAGS = -DBOX_NOTIFY
|
|||||||
# Check if we can build desktop notifications support
|
# Check if we can build desktop notifications support
|
||||||
CHECK_DESK_NOTIFY_LIBS = $(shell pkg-config --exists $(DESK_NOTIFY_LIBS) || echo -n "error")
|
CHECK_DESK_NOTIFY_LIBS = $(shell pkg-config --exists $(DESK_NOTIFY_LIBS) || echo -n "error")
|
||||||
ifneq ($(CHECK_DESK_NOTIFY_LIBS), error)
|
ifneq ($(CHECK_DESK_NOTIFY_LIBS), error)
|
||||||
LIBS += $(DESK_NOTIFY_LIBS)
|
LIBS += $(DESK_NOTIFY_LIBS)
|
||||||
CFLAGS += $(DESK_NOTIFY_CFLAGS)
|
CFLAGS += $(DESK_NOTIFY_CFLAGS)
|
||||||
else
|
else ifneq ($(MAKECMDGOALS), clean)
|
||||||
ifneq ($(MAKECMDGOALS), clean)
|
MISSING_DESK_NOTIFY_LIBS = $(shell for lib in $(DESK_NOTIFY_LIBS) ; do if ! pkg-config --exists $$lib ; then echo $$lib ; fi ; done)
|
||||||
MISSING_DESK_NOTIFY_LIBS = $(shell for lib in $(DESK_NOTIFY_LIBS) ; do if ! pkg-config --exists $$lib ; then echo $$lib ; fi ; done)
|
$(warning WARNING -- Toxic will be compiled without desktop notifications support)
|
||||||
$(warning WARNING -- Toxic will be compiled without desktop notifications support)
|
$(warning WARNING -- You need these libraries for desktop notifications support)
|
||||||
$(warning WARNING -- You need these libraries for desktop notifications support)
|
$(warning WARNING -- $(MISSING_DESK_NOTIFY_LIBS))
|
||||||
$(warning WARNING -- $(MISSING_DESK_NOTIFY_LIBS))
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
|
@ -2,22 +2,20 @@
|
|||||||
SND_NOTIFY_LIBS = openal freealut
|
SND_NOTIFY_LIBS = openal freealut
|
||||||
SND_NOTIFY_CFLAGS = -DSOUND_NOTIFY
|
SND_NOTIFY_CFLAGS = -DSOUND_NOTIFY
|
||||||
ifneq (, $(findstring device.o, $(OBJ)))
|
ifneq (, $(findstring device.o, $(OBJ)))
|
||||||
SND_NOTIFY_OBJ =
|
SND_NOTIFY_OBJ =
|
||||||
else
|
else
|
||||||
SND_NOTIFY_OBJ = device.o
|
SND_NOTIFY_OBJ = device.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Check if we can build sound notifications support
|
# Check if we can build sound notifications support
|
||||||
CHECK_SND_NOTIFY_LIBS = $(shell pkg-config --exists $(SND_NOTIFY_LIBS) || echo -n "error")
|
CHECK_SND_NOTIFY_LIBS = $(shell pkg-config --exists $(SND_NOTIFY_LIBS) || echo -n "error")
|
||||||
ifneq ($(CHECK_SND_NOTIFY_LIBS), error)
|
ifneq ($(CHECK_SND_NOTIFY_LIBS), error)
|
||||||
LIBS += $(SND_NOTIFY_LIBS)
|
LIBS += $(SND_NOTIFY_LIBS)
|
||||||
CFLAGS += $(SND_NOTIFY_CFLAGS)
|
CFLAGS += $(SND_NOTIFY_CFLAGS)
|
||||||
OBJ += $(SND_NOTIFY_OBJ)
|
OBJ += $(SND_NOTIFY_OBJ)
|
||||||
else
|
else ifneq ($(MAKECMDGOALS), clean)
|
||||||
ifneq ($(MAKECMDGOALS), clean)
|
MISSING_SND_NOTIFY_LIBS = $(shell for lib in $(SND_NOTIFY_LIBS) ; do if ! pkg-config --exists $$lib ; then echo $$lib ; fi ; done)
|
||||||
MISSING_SND_NOTIFY_LIBS = $(shell for lib in $(SND_NOTIFY_LIBS) ; do if ! pkg-config --exists $$lib ; then echo $$lib ; fi ; done)
|
$(warning WARNING -- Toxic will be compiled without sound notifications support)
|
||||||
$(warning WARNING -- Toxic will be compiled without sound notifications support)
|
$(warning WARNING -- You need these libraries for sound notifications support)
|
||||||
$(warning WARNING -- You need these libraries for sound notifications support)
|
$(warning WARNING -- $(MISSING_SND_NOTIFY_LIBS))
|
||||||
$(warning WARNING -- $(MISSING_SND_NOTIFY_LIBS))
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
# Variables for X11 support
|
# Variables for X11 support
|
||||||
X11_LIBS = x11
|
X11_LIBS = x11
|
||||||
X11_CFLAGS = -DX11
|
X11_CFLAGS = -DX11
|
||||||
|
X11_OBJ = xtra.o
|
||||||
|
|
||||||
# Check if we can build X11 support
|
# Check if we can build X11 support
|
||||||
CHECK_X11_LIBS = $(shell pkg-config --exists $(X11_LIBS) || echo -n "error")
|
CHECK_X11_LIBS = $(shell pkg-config --exists $(X11_LIBS) || echo -n "error")
|
||||||
ifneq ($(CHECK_X11_LIBS), error)
|
ifneq ($(CHECK_X11_LIBS), error)
|
||||||
LIBS += $(X11_LIBS)
|
LIBS += $(X11_LIBS)
|
||||||
CFLAGS += $(X11_CFLAGS)
|
CFLAGS += $(X11_CFLAGS)
|
||||||
else
|
OBJ += $(X11_OBJ)
|
||||||
ifneq ($(MAKECMDGOALS), clean)
|
else ifneq ($(MAKECMDGOALS), clean)
|
||||||
MISSING_X11_LIBS = $(shell for lib in $(X11_LIBS) ; do if ! pkg-config --exists $$lib ; then echo $$lib ; fi ; done)
|
MISSING_X11_LIBS = $(shell for lib in $(X11_LIBS) ; do if ! pkg-config --exists $$lib ; then echo $$lib ; fi ; done)
|
||||||
$(warning WARNING -- Toxic will be compiled without x11 support (needed for focus tracking))
|
$(warning WARNING -- Toxic will be compiled without x11 support (needed for focus tracking and drag&drop support))
|
||||||
$(warning WARNING -- You need these libraries for x11 support)
|
$(warning WARNING -- You need these libraries for x11 support)
|
||||||
$(warning WARNING -- $(MISSING_X11_LIBS))
|
$(warning WARNING -- $(MISSING_X11_LIBS))
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
# Version
|
# Version
|
||||||
TOXIC_VERSION = 0.5.2
|
TOXIC_VERSION = 0.6.0
|
||||||
REV = $(shell git rev-list HEAD --count)
|
REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error")
|
||||||
VERSION = $(TOXIC_VERSION)_r$(REV)
|
ifneq (, $(findstring error, $(REV)))
|
||||||
|
VERSION = $(TOXIC_VERSION)
|
||||||
|
else
|
||||||
|
VERSION = $(TOXIC_VERSION)_r$(REV)
|
||||||
|
endif
|
||||||
|
|
||||||
# Project directories
|
# Project directories
|
||||||
|
BUILD_DIR = $(BASE_DIR)/build
|
||||||
DOC_DIR = $(BASE_DIR)/doc
|
DOC_DIR = $(BASE_DIR)/doc
|
||||||
SRC_DIR = $(BASE_DIR)/src
|
SRC_DIR = $(BASE_DIR)/src
|
||||||
SND_DIR = $(BASE_DIR)/sounds
|
SND_DIR = $(BASE_DIR)/sounds
|
||||||
@ -12,12 +17,14 @@ MISC_DIR = $(BASE_DIR)/misc
|
|||||||
# Project files
|
# Project files
|
||||||
MANFILES = toxic.1 toxic.conf.5
|
MANFILES = toxic.1 toxic.conf.5
|
||||||
DATAFILES = DHTnodes DNSservers toxic.conf.example
|
DATAFILES = DHTnodes DNSservers toxic.conf.example
|
||||||
SNDFILES = ContactLogsIn.wav ContactLogsOut.wav Error.wav IncomingCall.wav
|
DESKFILE = toxic.desktop
|
||||||
SNDFILES += LogIn.wav LogOut.wav NewMessage.wav OutgoingCall.wav
|
SNDFILES = ToxicContactOnline.wav ToxicContactOffline.wav ToxicError.wav
|
||||||
SNDFILES += TransferComplete.wav TransferPending.wav
|
SNDFILES += ToxicRecvMessage.wav ToxicOutgoingCall.wav ToxicIncomingCall.wav
|
||||||
|
SNDFILES += ToxicTransferComplete.wav ToxicTransferStart.wav
|
||||||
|
|
||||||
# Install directories
|
# Install directories
|
||||||
PREFIX = /usr/local
|
PREFIX = /usr/local
|
||||||
BINDIR = $(PREFIX)/bin
|
BINDIR = $(PREFIX)/bin
|
||||||
DATADIR = $(PREFIX)/share/toxic
|
DATADIR = $(PREFIX)/share/toxic
|
||||||
MANDIR = $(PREFIX)/share/man
|
MANDIR = $(PREFIX)/share/man
|
||||||
|
APPDIR = $(PREFIX)/share/applications
|
||||||
|
10
cfg/systems/Darwin.mk
Normal file
10
cfg/systems/Darwin.mk
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Special options for OS X
|
||||||
|
# This assumes the use of Homebrew. Change the paths if using MacPorts or Fink.
|
||||||
|
|
||||||
|
PKG_CONFIG_PATH = $(shell export PKG_CONFIG_PATH=/usr/lib/pkgconfig:/usr/local/opt/libconfig/lib/pkgconfig:/usr/local/lib/pkgconfig:/opt/X11/lib/pkgconfig)
|
||||||
|
|
||||||
|
LIBS := $(filter-out ncursesw, $(LIBS))
|
||||||
|
|
||||||
|
# OS X ships a usable, recent version of ncurses, but calls it ncurses not ncursesw.
|
||||||
|
LDFLAGS += -lncurses -lalut -ltoxav -ltoxcore -ltoxdns -lresolv -lconfig -ltoxencryptsave -g
|
||||||
|
CFLAGS += -I/usr/local/opt/freealut/include/AL -I/usr/local/opt/glib/include/glib-2.0 -g
|
@ -1,4 +1,4 @@
|
|||||||
# Specials options for linux systems
|
# Specials options for linux systems
|
||||||
CFLAGS +=
|
CFLAGS +=
|
||||||
LDFLAGS += -ldl -lresolv
|
LDFLAGS += -ldl -lresolv -lrt
|
||||||
MANDIR = $(PREFIX)/share/man
|
MANDIR = $(PREFIX)/share/man
|
||||||
|
@ -1,25 +1,31 @@
|
|||||||
# Install target
|
# Install target
|
||||||
install: toxic doc
|
install: $(BUILD_DIR)/toxic
|
||||||
mkdir -p $(abspath $(DESTDIR)/$(BINDIR))
|
|
||||||
mkdir -p $(abspath $(DESTDIR)/$(DATADIR))
|
|
||||||
mkdir -p $(abspath $(DESTDIR)/$(DATADIR))/sounds
|
|
||||||
mkdir -p $(abspath $(DESTDIR)/$(MANDIR))
|
|
||||||
|
|
||||||
@echo "Installing toxic executable"
|
@echo "Installing toxic executable"
|
||||||
@install -m 0755 toxic $(abspath $(DESTDIR)/$(BINDIR))
|
@mkdir -p $(abspath $(DESTDIR)/$(BINDIR))
|
||||||
|
@install -m 0755 $(BUILD_DIR)/toxic $(abspath $(DESTDIR)/$(BINDIR)/toxic)
|
||||||
|
|
||||||
|
@echo "Installing desktop file"
|
||||||
|
@mkdir -p $(abspath $(DESTDIR)/$(APPDIR))
|
||||||
|
@install -m 0644 $(MISC_DIR)/$(DESKFILE) $(abspath $(DESTDIR)/$(APPDIR)/$(DESKFILE))
|
||||||
|
|
||||||
@echo "Installing data files"
|
@echo "Installing data files"
|
||||||
|
@mkdir -p $(abspath $(DESTDIR)/$(DATADIR))
|
||||||
@for f in $(DATAFILES) ; do \
|
@for f in $(DATAFILES) ; do \
|
||||||
install -m 0644 $(MISC_DIR)/$$f $(abspath $(DESTDIR)/$(DATADIR)) ;\
|
install -m 0644 $(MISC_DIR)/$$f $(abspath $(DESTDIR)/$(DATADIR)/$$f) ;\
|
||||||
file=$(abspath $(DESTDIR)/$(DATADIR))/$$f ;\
|
file=$(abspath $(DESTDIR)/$(DATADIR)/$$f) ;\
|
||||||
sed -i'' -e 's:__DATADIR__:'$(abspath $(DATADIR))':g' $$file ;\
|
sed -i'' -e 's:__DATADIR__:'$(abspath $(DATADIR))':g' $$file ;\
|
||||||
done
|
done
|
||||||
|
@mkdir -p $(abspath $(DESTDIR)/$(DATADIR))/sounds
|
||||||
@for f in $(SNDFILES) ; do \
|
@for f in $(SNDFILES) ; do \
|
||||||
install -m 0644 $(SND_DIR)/$$f $(abspath $(DESTDIR)/$(DATADIR))/sounds ;\
|
install -m 0644 $(SND_DIR)/$$f $(abspath $(DESTDIR)/$(DATADIR)/sounds/$$f) ;\
|
||||||
done
|
done
|
||||||
|
|
||||||
@echo "Installing man pages"
|
@echo "Installing man pages"
|
||||||
|
@mkdir -p $(abspath $(DESTDIR)/$(MANDIR))
|
||||||
@for f in $(MANFILES) ; do \
|
@for f in $(MANFILES) ; do \
|
||||||
|
if [ ! -e "$(DOC_DIR)/$$f" ]; then \
|
||||||
|
continue ;\
|
||||||
|
fi ;\
|
||||||
section=$(abspath $(DESTDIR)/$(MANDIR))/man`echo $$f | rev | cut -d "." -f 1` ;\
|
section=$(abspath $(DESTDIR)/$(MANDIR))/man`echo $$f | rev | cut -d "." -f 1` ;\
|
||||||
file=$$section/$$f ;\
|
file=$$section/$$f ;\
|
||||||
mkdir -p $$section ;\
|
mkdir -p $$section ;\
|
||||||
|
18
doc/toxic.1
18
doc/toxic.1
@ -2,12 +2,12 @@
|
|||||||
.\" Title: toxic
|
.\" Title: toxic
|
||||||
.\" Author: [see the "AUTHORS" section]
|
.\" Author: [see the "AUTHORS" section]
|
||||||
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
||||||
.\" Date: 2014-09-19
|
.\" Date: 2014-12-27
|
||||||
.\" Manual: Toxic Manual
|
.\" Manual: Toxic Manual
|
||||||
.\" Source: toxic __VERSION__
|
.\" Source: toxic __VERSION__
|
||||||
.\" Language: English
|
.\" Language: English
|
||||||
.\"
|
.\"
|
||||||
.TH "TOXIC" "1" "2014\-09\-19" "toxic __VERSION__" "Toxic Manual"
|
.TH "TOXIC" "1" "2014\-12\-27" "toxic __VERSION__" "Toxic Manual"
|
||||||
.\" -----------------------------------------------------------------
|
.\" -----------------------------------------------------------------
|
||||||
.\" * Define some portability stuff
|
.\" * Define some portability stuff
|
||||||
.\" -----------------------------------------------------------------
|
.\" -----------------------------------------------------------------
|
||||||
@ -91,9 +91,14 @@ for DHT bootstrap nodes, instead of
|
|||||||
Do not connect to the DHT network
|
Do not connect to the DHT network
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
\-p, \-\-proxy
|
\-p, \-\-SOCKS5\-proxy
|
||||||
.RS 4
|
.RS 4
|
||||||
Use proxy: Requires [IP] [port]
|
Use a SOCKS5 proxy: Requires [IP] [port]
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
\-P, \-\-HTTP\-proxy
|
||||||
|
.RS 4
|
||||||
|
Use a HTTP proxy: Requires [IP] [port]
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
\-r, \-\-dnslist
|
\-r, \-\-dnslist
|
||||||
@ -110,11 +115,6 @@ Force TCP connection (use this with proxies)
|
|||||||
.RS 4
|
.RS 4
|
||||||
Unencrypt a data file\&. A warning will appear if this option is used with a data file that is already unencrypted\&.
|
Unencrypt a data file\&. A warning will appear if this option is used with a data file that is already unencrypted\&.
|
||||||
.RE
|
.RE
|
||||||
.PP
|
|
||||||
\-x, \-\-nodata
|
|
||||||
.RS 4
|
|
||||||
Ignore data file
|
|
||||||
.RE
|
|
||||||
.SH "FILES"
|
.SH "FILES"
|
||||||
.PP
|
.PP
|
||||||
__DATADIR__/DHTnodes
|
__DATADIR__/DHTnodes
|
||||||
|
@ -31,7 +31,7 @@ OPTIONS
|
|||||||
Use default locale
|
Use default locale
|
||||||
|
|
||||||
-e, --encrypt-data::
|
-e, --encrypt-data::
|
||||||
Encrypt an unencrypted data file. An error will occur if this option
|
Encrypt an unencrypted data file. An error will occur if this option
|
||||||
is used with an encrypted data file.
|
is used with an encrypted data file.
|
||||||
|
|
||||||
-f, --file data-file::
|
-f, --file data-file::
|
||||||
@ -47,8 +47,11 @@ OPTIONS
|
|||||||
-o, --noconnect::
|
-o, --noconnect::
|
||||||
Do not connect to the DHT network
|
Do not connect to the DHT network
|
||||||
|
|
||||||
-p, --proxy::
|
-p, --SOCKS5-proxy::
|
||||||
Use proxy: Requires [IP] [port]
|
Use a SOCKS5 proxy: Requires [IP] [port]
|
||||||
|
|
||||||
|
-P, --HTTP-proxy::
|
||||||
|
Use a HTTP proxy: Requires [IP] [port]
|
||||||
|
|
||||||
-r, --dnslist::
|
-r, --dnslist::
|
||||||
Use specified DNSservers file
|
Use specified DNSservers file
|
||||||
@ -57,12 +60,9 @@ OPTIONS
|
|||||||
Force TCP connection (use this with proxies)
|
Force TCP connection (use this with proxies)
|
||||||
|
|
||||||
-u, --unencrypt-data::
|
-u, --unencrypt-data::
|
||||||
Unencrypt a data file. A warning will appear if this option is used
|
Unencrypt a data file. A warning will appear if this option is used
|
||||||
with a data file that is already unencrypted.
|
with a data file that is already unencrypted.
|
||||||
|
|
||||||
-x, --nodata::
|
|
||||||
Ignore data file
|
|
||||||
|
|
||||||
FILES
|
FILES
|
||||||
-----
|
-----
|
||||||
{datadir}/DHTnodes::
|
{datadir}/DHTnodes::
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
.\" Title: toxic.conf
|
.\" Title: toxic.conf
|
||||||
.\" Author: [see the "AUTHORS" section]
|
.\" Author: [see the "AUTHORS" section]
|
||||||
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
||||||
.\" Date: 2014-09-19
|
.\" Date: 2015-02-26
|
||||||
.\" Manual: Toxic Manual
|
.\" Manual: Toxic Manual
|
||||||
.\" Source: toxic __VERSION__
|
.\" Source: toxic __VERSION__
|
||||||
.\" Language: English
|
.\" Language: English
|
||||||
.\"
|
.\"
|
||||||
.TH "TOXIC\&.CONF" "5" "2014\-09\-19" "toxic __VERSION__" "Toxic Manual"
|
.TH "TOXIC\&.CONF" "5" "2015\-02\-26" "toxic __VERSION__" "Toxic Manual"
|
||||||
.\" -----------------------------------------------------------------
|
.\" -----------------------------------------------------------------
|
||||||
.\" * Define some portability stuff
|
.\" * Define some portability stuff
|
||||||
.\" -----------------------------------------------------------------
|
.\" -----------------------------------------------------------------
|
||||||
@ -66,6 +66,23 @@ Configuration related to interface elements\&.
|
|||||||
Enable or disable timestamps\&. true or false
|
Enable or disable timestamps\&. true or false
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
|
\fBtime_format\fR
|
||||||
|
.RS 4
|
||||||
|
Select between 24 and 12 hour time\&. Specify 24 or 12\&. Setting timestamp_format and log_timestamp_format will override this setting\&.
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
\fBtimestamp_format\fR
|
||||||
|
.RS 4
|
||||||
|
Time format string for the interface enclosed by double quotes\&. See
|
||||||
|
\fBdate\fR(1)
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
\fBlog_timestamp_format\fR
|
||||||
|
.RS 4
|
||||||
|
Time format string for logging enclosed by double quotes\&. See
|
||||||
|
\fBdate\fR(1)
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
\fBalerts\fR
|
\fBalerts\fR
|
||||||
.RS 4
|
.RS 4
|
||||||
Enable or disable terminal alerts on events\&. true or false
|
Enable or disable terminal alerts on events\&. true or false
|
||||||
@ -81,11 +98,6 @@ Select between native terminal colors and toxic color theme\&. true or false
|
|||||||
Enable or disable autologging\&. true or false
|
Enable or disable autologging\&. true or false
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
\fBtime_format\fR
|
|
||||||
.RS 4
|
|
||||||
Select between 24 and 12 hour time\&. Specify 24 or 12
|
|
||||||
.RE
|
|
||||||
.PP
|
|
||||||
\fBshow_typing_other\fR
|
\fBshow_typing_other\fR
|
||||||
.RS 4
|
.RS 4
|
||||||
Show when others are typing in a 1\-on\-1 chat\&. true or false
|
Show when others are typing in a 1\-on\-1 chat\&. true or false
|
||||||
@ -105,6 +117,36 @@ Show welcome message on startup\&. true or false
|
|||||||
.RS 4
|
.RS 4
|
||||||
Maximum lines for chat window history\&. Integer value\&. (for example: 700)
|
Maximum lines for chat window history\&. Integer value\&. (for example: 700)
|
||||||
.RE
|
.RE
|
||||||
|
.PP
|
||||||
|
\fBline_join\fR
|
||||||
|
.RS 4
|
||||||
|
Indicator for when someone connects or joins a group\&. Three characters max for line_ settings\&.
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
\fBline_quit\fR
|
||||||
|
.RS 4
|
||||||
|
Indicator for when someone disconnects or leaves a group\&.
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
\fBline_alert\fR
|
||||||
|
.RS 4
|
||||||
|
Indicator for alert messages\&.
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
\fBline_normal\fR
|
||||||
|
.RS 4
|
||||||
|
Indicator for normal messages\&.
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
\fBmplex_away\fR
|
||||||
|
.RS 4
|
||||||
|
Set user status when attaching and detaching from GNU screen or tmux\&. true or false
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
\fBmplex_away_note\fR
|
||||||
|
.RS 4
|
||||||
|
Status message to set when status is set to away due to screen/tmux detach\&. When attaching, the status message is set back to the original value\&.
|
||||||
|
.RE
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
\fBaudio\fR
|
\fBaudio\fR
|
||||||
@ -155,7 +197,7 @@ Configuration related to notification sounds\&. Special value "silent" can be us
|
|||||||
|
|
||||||
Each value is a string which corresponds to the absolute path of a wav sound file\&.
|
Each value is a string which corresponds to the absolute path of a wav sound file\&.
|
||||||
.PP
|
.PP
|
||||||
\fBerror\fR
|
\fBnotif_error\fR
|
||||||
.RS 4
|
.RS 4
|
||||||
Sound to play when an error occurs\&.
|
Sound to play when an error occurs\&.
|
||||||
.RE
|
.RE
|
||||||
@ -256,6 +298,11 @@ Key combination to scroll contacts list up\&.
|
|||||||
.RS 4
|
.RS 4
|
||||||
Key combination to scroll contacts list down\&.
|
Key combination to scroll contacts list down\&.
|
||||||
.RE
|
.RE
|
||||||
|
.PP
|
||||||
|
\fBtoggle_peerlist\fR
|
||||||
|
.RS 4
|
||||||
|
Toggle the peer list on and off\&.
|
||||||
|
.RE
|
||||||
.RE
|
.RE
|
||||||
.SH "FILES"
|
.SH "FILES"
|
||||||
.PP
|
.PP
|
||||||
|
@ -42,6 +42,18 @@ OPTIONS
|
|||||||
*timestamps*;;
|
*timestamps*;;
|
||||||
Enable or disable timestamps. true or false
|
Enable or disable timestamps. true or false
|
||||||
|
|
||||||
|
*time_format*;;
|
||||||
|
Select between 24 and 12 hour time. Specify 24 or 12. Setting
|
||||||
|
timestamp_format and log_timestamp_format will override this setting.
|
||||||
|
|
||||||
|
*timestamp_format*;;
|
||||||
|
Time format string for the interface enclosed by double quotes.
|
||||||
|
See *date*(1)
|
||||||
|
|
||||||
|
*log_timestamp_format*;;
|
||||||
|
Time format string for logging enclosed by double quotes.
|
||||||
|
See *date*(1)
|
||||||
|
|
||||||
*alerts*;;
|
*alerts*;;
|
||||||
Enable or disable terminal alerts on events. true or false
|
Enable or disable terminal alerts on events. true or false
|
||||||
|
|
||||||
@ -51,9 +63,6 @@ OPTIONS
|
|||||||
*autolog*;;
|
*autolog*;;
|
||||||
Enable or disable autologging. true or false
|
Enable or disable autologging. true or false
|
||||||
|
|
||||||
*time_format*;;
|
|
||||||
Select between 24 and 12 hour time. Specify 24 or 12
|
|
||||||
|
|
||||||
*show_typing_other*;;
|
*show_typing_other*;;
|
||||||
Show when others are typing in a 1-on-1 chat. true or false
|
Show when others are typing in a 1-on-1 chat. true or false
|
||||||
|
|
||||||
@ -66,6 +75,27 @@ OPTIONS
|
|||||||
*history_size*;;
|
*history_size*;;
|
||||||
Maximum lines for chat window history. Integer value. (for example: 700)
|
Maximum lines for chat window history. Integer value. (for example: 700)
|
||||||
|
|
||||||
|
*line_join*;;
|
||||||
|
Indicator for when someone connects or joins a group.
|
||||||
|
Three characters max for line_ settings.
|
||||||
|
|
||||||
|
*line_quit*;;
|
||||||
|
Indicator for when someone disconnects or leaves a group.
|
||||||
|
|
||||||
|
*line_alert*;;
|
||||||
|
Indicator for alert messages.
|
||||||
|
|
||||||
|
*line_normal*;;
|
||||||
|
Indicator for normal messages.
|
||||||
|
|
||||||
|
*mplex_away*;;
|
||||||
|
Set user status when attaching and detaching from GNU screen or tmux.
|
||||||
|
true or false
|
||||||
|
|
||||||
|
*mplex_away_note*;;
|
||||||
|
Status message to set when status is set to away due to screen/tmux
|
||||||
|
detach. When attaching, the status message is set back to the original
|
||||||
|
value.
|
||||||
|
|
||||||
*audio*::
|
*audio*::
|
||||||
Configuration related to audio devices.
|
Configuration related to audio devices.
|
||||||
@ -99,7 +129,7 @@ OPTIONS
|
|||||||
Each value is a string which corresponds to the absolute path of a wav
|
Each value is a string which corresponds to the absolute path of a wav
|
||||||
sound file.
|
sound file.
|
||||||
|
|
||||||
*error*;;
|
*notif_error*;;
|
||||||
Sound to play when an error occurs.
|
Sound to play when an error occurs.
|
||||||
|
|
||||||
*self_log_in*;;
|
*self_log_in*;;
|
||||||
@ -161,6 +191,9 @@ OPTIONS
|
|||||||
*peer_list_down*;;
|
*peer_list_down*;;
|
||||||
Key combination to scroll contacts list down.
|
Key combination to scroll contacts list down.
|
||||||
|
|
||||||
|
*toggle_peerlist*;;
|
||||||
|
Toggle the peer list on and off.
|
||||||
|
|
||||||
|
|
||||||
FILES
|
FILES
|
||||||
-----
|
-----
|
||||||
|
@ -1,11 +1,20 @@
|
|||||||
192.254.75.98 33445 951C88B7E75C867418ACDB5D273821372BB5BD652740BCDF623A4FA293E75D2F
|
192.254.75.102 33445 951C88B7E75C867418ACDB5D273821372BB5BD652740BCDF623A4FA293E75D2F
|
||||||
37.187.46.132 33445 A9D98212B3F972BD11DA52BEB0658C326FCCC1BFD49F347F9C2D3D8B61E1B927
|
|
||||||
144.76.60.215 33445 04119E835DF3E78BACF0F84235B300546AF8B936F035185E2A8E9E0A67C8924F
|
144.76.60.215 33445 04119E835DF3E78BACF0F84235B300546AF8B936F035185E2A8E9E0A67C8924F
|
||||||
23.226.230.47 33445 A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074
|
23.226.230.47 33445 A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074
|
||||||
54.199.139.199 33445 7F9C31FE850E97CEFD4C4591DF93FC757C7C12549DDD55F8EEAECC34FE76C029
|
178.62.125.224 33445 10B20C49ACBD968D7C80F2E8438F92EA51F189F4E70CFBBB2C2C8C799E97F03E
|
||||||
192.210.149.121 33445 F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67
|
|
||||||
37.59.102.176 33445 B98A2CEAA6C6A2FADC2C3632D284318B60FE5375CCB41EFA081AB67F500C1B0B
|
|
||||||
178.21.112.187 33445 4B2C19E924972CB9B57732FB172F8A8604DE13EEDA2A6234E348983344B23057
|
178.21.112.187 33445 4B2C19E924972CB9B57732FB172F8A8604DE13EEDA2A6234E348983344B23057
|
||||||
107.161.17.51 33445 7BE3951B97CA4B9ECDDA768E8C52BA19E9E2690AB584787BF4C90E04DBB75111
|
195.154.119.113 33445 E398A69646B8CEACA9F0B84F553726C1C49270558C57DF5F3C368F05A7D71354
|
||||||
31.7.57.236 443 2A4B50D1D525DA2E669592A20C327B5FAD6C7E5962DC69296F9FEC77C4436E4E
|
192.210.149.121 33445 F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67
|
||||||
63.165.243.15 443 8CD087E31C67568103E8C2A28653337E90E6B8EDA0D765D57C6B5172B4F1F04C
|
104.219.184.206 443 8CD087E31C67568103E8C2A28653337E90E6B8EDA0D765D57C6B5172B4F1F04C
|
||||||
|
76.191.23.96 33445 93574A3FAB7D612FEA29FD8D67D3DD10DFD07A075A5D62E8AF3DD9F5D0932E11
|
||||||
|
46.38.239.179 33445 F5A1A38EFB6BD3C2C8AF8B10D85F0F89E931704D349F1D0720C3C4059AF2440A
|
||||||
|
178.62.250.138 33445 788236D34978D1D5BD822F0A5BEBD2C53C64CC31CD3149350EE27D4D9A2F9B6B
|
||||||
|
78.225.128.39 33445 7A2306BFBA665E5480AE59B31E116BE9C04DCEFE04D9FE25082316FA34B4DA0C
|
||||||
|
130.133.110.14 33445 461FA3776EF0FA655F1A05477DF1B3B614F7D6B124F7DB1DD4FE3C08B03B640F
|
||||||
|
104.167.101.29 33445 5918AC3C06955962A75AD7DF4F80A5D7C34F7DB9E1498D2E0495DE35B3FE8A57
|
||||||
|
195.154.109.148 33445 391C96CB67AE893D4782B8E4495EB9D89CF1031F48460C06075AA8CE76D50A21
|
||||||
|
192.3.173.88 33445 3E1FFDEB667BFF549F619EC6737834762124F50A89C8D0DBF1DDF64A2DD6CD1B
|
||||||
|
205.185.116.116 33445 A179B09749AC826FF01F37A9613F6B57118AE014D4196A0E1105A98F93A54702
|
||||||
|
198.98.51.198 33445 1D5A5F2F5D6233058BF0259B09622FB40B482E4FA0931EB8FD3AB8E7BF7DAF6F
|
||||||
|
80.232.246.79 33445 0B8DCEAA7BDDC44BB11173F987CAE3566A2D7057D8DD3CC642BD472B9391002A
|
||||||
|
|
||||||
|
@ -17,6 +17,9 @@ ui = {
|
|||||||
// 24 or 12 hour time
|
// 24 or 12 hour time
|
||||||
time_format=24;
|
time_format=24;
|
||||||
|
|
||||||
|
// timestamp format string according to date/strftime format. Overrides time_format setting
|
||||||
|
timestamp_format="%H:%M:%S";
|
||||||
|
|
||||||
// true to show you when others are typing a message in 1-on-1 chats
|
// true to show you when others are typing a message in 1-on-1 chats
|
||||||
show_typing_other=true;
|
show_typing_other=true;
|
||||||
|
|
||||||
@ -28,6 +31,24 @@ ui = {
|
|||||||
|
|
||||||
// maximum lines for chat window history
|
// maximum lines for chat window history
|
||||||
history_size=700;
|
history_size=700;
|
||||||
|
|
||||||
|
// Indicator for display when someone connects or joins a group.
|
||||||
|
line_join="-->";
|
||||||
|
|
||||||
|
// Indicator for display when someone disconnects or leaves a group.
|
||||||
|
line_quit="<--";
|
||||||
|
|
||||||
|
// Indicator for alert messages.
|
||||||
|
line_alert="-!-";
|
||||||
|
|
||||||
|
// Indicator for normal messages.
|
||||||
|
line_normal="---";
|
||||||
|
|
||||||
|
// true to change status based on screen/tmux attach/detach, false to disable
|
||||||
|
mplex_away=true;
|
||||||
|
|
||||||
|
// Status message to use when status set to away due to screen/tmux detach
|
||||||
|
mplex_away_note="Away from keyboard, be back soon!"
|
||||||
};
|
};
|
||||||
|
|
||||||
audio = {
|
audio = {
|
||||||
@ -54,16 +75,14 @@ tox = {
|
|||||||
|
|
||||||
// To disable a sound set the path to "silent"
|
// To disable a sound set the path to "silent"
|
||||||
sounds = {
|
sounds = {
|
||||||
error="__DATADIR__/sounds/Error.wav";
|
error="__DATADIR__/sounds/ToxicError.wav";
|
||||||
self_log_in="__DATADIR__/sounds/LogIn.wav";
|
user_log_in="__DATADIR__/sounds/ToxicContactOnline.wav";
|
||||||
self_log_out="__DATADIR__/sounds/LogOut.wav";
|
user_log_out="__DATADIR__/sounds/ToxicContactOffline.wav";
|
||||||
user_log_in="__DATADIR__/sounds/ContactLogsIn.wav";
|
call_incoming="__DATADIR__/sounds/ToxicIncomingCall.wav";
|
||||||
user_log_out="__DATADIR__/sounds/ContactLogsOut.wav";
|
call_outgoing="__DATADIR__/sounds/ToxicOutgoingCall.wav";
|
||||||
call_incoming="__DATADIR__/sounds/IncomingCall.wav";
|
generic_message="__DATADIR__/sounds/ToxicRecvMessage.wav";
|
||||||
call_outgoing="__DATADIR__/sounds/OutgoingCall.wav";
|
transfer_pending="__DATADIR__/sounds/ToxicTransferStart.wav";
|
||||||
generic_message="__DATADIR__/sounds/NewMessage.wav";
|
transfer_completed="__DATADIR__/sounds/ToxicTransferComplete.wav";
|
||||||
transfer_pending="__DATADIR__/sounds/TransferPending.wav";
|
|
||||||
transfer_completed="__DATADIR__/sounds/TransferComplete.wav";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Currently supported: Ctrl modified keys, Tab, PAGEUP and PAGEDOWN (case insensitive)
|
// Currently supported: Ctrl modified keys, Tab, PAGEUP and PAGEDOWN (case insensitive)
|
||||||
@ -78,5 +97,6 @@ keys = {
|
|||||||
page_bottom="Ctrl+H";
|
page_bottom="Ctrl+H";
|
||||||
peer_list_up="Ctrl+[";
|
peer_list_up="Ctrl+[";
|
||||||
peer_list_down="Ctrl+]";
|
peer_list_down="Ctrl+]";
|
||||||
|
toggle_peerlist="Ctrl+b";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
11
misc/toxic.desktop
Normal file
11
misc/toxic.desktop
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Version=1.0
|
||||||
|
Type=Application
|
||||||
|
Name=Toxic
|
||||||
|
Comment=A CLI based Tox client
|
||||||
|
TryExec=toxic
|
||||||
|
Exec=toxic
|
||||||
|
Icon=utilities-terminal
|
||||||
|
Categories=InstantMessaging;AudioVideo;Network;
|
||||||
|
Terminal=true
|
||||||
|
MimeType=x-scheme-handler/tox;
|
Binary file not shown.
Binary file not shown.
BIN
sounds/Error.wav
BIN
sounds/Error.wav
Binary file not shown.
Binary file not shown.
BIN
sounds/LogIn.wav
BIN
sounds/LogIn.wav
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
sounds/ToxicContactOffline.wav
Normal file
BIN
sounds/ToxicContactOffline.wav
Normal file
Binary file not shown.
BIN
sounds/ToxicContactOnline.wav
Normal file
BIN
sounds/ToxicContactOnline.wav
Normal file
Binary file not shown.
BIN
sounds/ToxicError.wav
Normal file
BIN
sounds/ToxicError.wav
Normal file
Binary file not shown.
BIN
sounds/ToxicIncomingCall.wav
Normal file
BIN
sounds/ToxicIncomingCall.wav
Normal file
Binary file not shown.
BIN
sounds/ToxicOutgoingCall.wav
Normal file
BIN
sounds/ToxicOutgoingCall.wav
Normal file
Binary file not shown.
BIN
sounds/ToxicRecvMessage.wav
Normal file
BIN
sounds/ToxicRecvMessage.wav
Normal file
Binary file not shown.
BIN
sounds/ToxicTransferComplete.wav
Normal file
BIN
sounds/ToxicTransferComplete.wav
Normal file
Binary file not shown.
BIN
sounds/ToxicTransferStart.wav
Normal file
BIN
sounds/ToxicTransferStart.wav
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1 +1,2 @@
|
|||||||
Tox's sounds are licensed under the "Creative Commons Attribution 3.0 Unported", all credit attributed to Adam Reid.
|
ToxicError.wav, ToxicRecvMessage.wav, ToxicContactOffline.wav, ToxicIncomingCall.wav, ToxicTransferComplete.wav, ToxicContactOnline.wav, ToxicOutgoingCall.wav and ToxicTransferStart.wav
|
||||||
|
are licensed under the "Creative Commons Attribution 3.0 Unported". All credit attributed to Jfreegman.
|
||||||
|
280
src/audio_call.c
280
src/audio_call.c
@ -55,19 +55,11 @@
|
|||||||
|
|
||||||
#define frame_size (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000)
|
#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, has_output; /* Transmission thread active status (0 - stopped, 1- running) */
|
|
||||||
uint32_t in_idx, out_idx;
|
|
||||||
pthread_mutex_t mutex;
|
|
||||||
} Call;
|
|
||||||
|
|
||||||
|
|
||||||
static int set_call(Call* call, bool start)
|
static int set_call(Call* call, bool start)
|
||||||
{
|
{
|
||||||
call->in_idx = -1;
|
call->in_idx = -1;
|
||||||
call->out_idx = -1;
|
call->out_idx = -1;
|
||||||
|
|
||||||
if ( start ) {
|
if ( start ) {
|
||||||
call->ttas = true;
|
call->ttas = true;
|
||||||
|
|
||||||
@ -87,9 +79,9 @@ struct ASettings {
|
|||||||
AudioError errors;
|
AudioError errors;
|
||||||
|
|
||||||
ToxAv *av;
|
ToxAv *av;
|
||||||
|
|
||||||
ToxAvCSettings cs;
|
ToxAvCSettings cs;
|
||||||
|
|
||||||
Call calls[MAX_CALLS];
|
Call calls[MAX_CALLS];
|
||||||
} ASettins;
|
} ASettins;
|
||||||
|
|
||||||
@ -105,8 +97,7 @@ void callback_requ_timeout ( void* av, int32_t call_index, void *arg );
|
|||||||
void callback_peer_timeout ( void* av, int32_t call_index, void *arg );
|
void callback_peer_timeout ( void* av, int32_t call_index, void *arg );
|
||||||
void callback_media_change ( void* av, int32_t call_index, void *arg );
|
void callback_media_change ( void* av, int32_t call_index, void *arg );
|
||||||
|
|
||||||
int stop_transmission(int call_index);
|
void write_device_callback( void* agent, int32_t call_index, const int16_t* PCM, uint16_t size, void* arg );
|
||||||
void write_device_callback(ToxAv* av, int32_t call_index, int16_t* data, int size, void* userdata);
|
|
||||||
|
|
||||||
static void print_err (ToxWindow *self, const char *error_str)
|
static void print_err (ToxWindow *self, const char *error_str)
|
||||||
{
|
{
|
||||||
@ -114,15 +105,15 @@ static void print_err (ToxWindow *self, const char *error_str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ToxAv *init_audio(ToxWindow *self, Tox *tox)
|
ToxAv *init_audio(ToxWindow *self, Tox *tox)
|
||||||
{
|
{
|
||||||
ASettins.cs = av_DefaultSettings;
|
ASettins.cs = av_DefaultSettings;
|
||||||
ASettins.cs.max_video_height = ASettins.cs.max_video_width = 0;
|
ASettins.cs.max_video_height = ASettins.cs.max_video_width = 0;
|
||||||
|
|
||||||
ASettins.errors = ae_None;
|
|
||||||
|
|
||||||
memset(ASettins.calls, 0, sizeof(Call) * 10);
|
|
||||||
|
|
||||||
|
ASettins.errors = ae_None;
|
||||||
|
|
||||||
|
memset(ASettins.calls, 0, sizeof(ASettins.calls));
|
||||||
|
|
||||||
|
|
||||||
/* Streaming stuff from core */
|
/* Streaming stuff from core */
|
||||||
|
|
||||||
ASettins.av = toxav_new(tox, MAX_CALLS);
|
ASettins.av = toxav_new(tox, MAX_CALLS);
|
||||||
@ -131,7 +122,7 @@ ToxAv *init_audio(ToxWindow *self, Tox *tox)
|
|||||||
ASettins.errors |= ae_StartingCoreAudio;
|
ASettins.errors |= ae_StartingCoreAudio;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( init_devices(ASettins.av) == de_InternalError ) {
|
if ( init_devices(ASettins.av) == de_InternalError ) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init devices");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init devices");
|
||||||
toxav_kill(ASettins.av);
|
toxav_kill(ASettins.av);
|
||||||
@ -145,14 +136,14 @@ ToxAv *init_audio(ToxWindow *self, Tox *tox)
|
|||||||
toxav_register_callstate_callback(ASettins.av, callback_recv_invite, av_OnInvite, self);
|
toxav_register_callstate_callback(ASettins.av, callback_recv_invite, av_OnInvite, self);
|
||||||
|
|
||||||
toxav_register_callstate_callback(ASettins.av, callback_recv_ringing, av_OnRinging, self);
|
toxav_register_callstate_callback(ASettins.av, callback_recv_ringing, av_OnRinging, self);
|
||||||
toxav_register_callstate_callback(ASettins.av, callback_recv_starting, av_OnStarting, self);
|
toxav_register_callstate_callback(ASettins.av, callback_recv_starting, av_OnStart, self);
|
||||||
toxav_register_callstate_callback(ASettins.av, callback_recv_ending, av_OnEnding, self);
|
toxav_register_callstate_callback(ASettins.av, callback_recv_ending, av_OnEnd, self);
|
||||||
|
|
||||||
toxav_register_callstate_callback(ASettins.av, callback_requ_timeout, av_OnRequestTimeout, self);
|
toxav_register_callstate_callback(ASettins.av, callback_requ_timeout, av_OnRequestTimeout, self);
|
||||||
toxav_register_callstate_callback(ASettins.av, callback_peer_timeout, av_OnPeerTimeout, self);
|
toxav_register_callstate_callback(ASettins.av, callback_peer_timeout, av_OnPeerTimeout, self);
|
||||||
toxav_register_callstate_callback(ASettins.av, callback_media_change, av_OnMediaChange, self);
|
//toxav_register_callstate_callback(ASettins.av, callback_media_change, av_OnMediaChange, self);
|
||||||
|
|
||||||
toxav_register_audio_recv_callback(ASettins.av, write_device_callback, NULL);
|
toxav_register_audio_callback(ASettins.av, write_device_callback, NULL);
|
||||||
|
|
||||||
return ASettins.av;
|
return ASettins.av;
|
||||||
}
|
}
|
||||||
@ -160,19 +151,19 @@ ToxAv *init_audio(ToxWindow *self, Tox *tox)
|
|||||||
void terminate_audio()
|
void terminate_audio()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < MAX_CALLS; i ++)
|
for (i = 0; i < MAX_CALLS; ++i)
|
||||||
stop_transmission(i);
|
stop_transmission(&ASettins.calls[i], i);
|
||||||
|
|
||||||
if ( ASettins.av )
|
if ( ASettins.av )
|
||||||
toxav_kill(ASettins.av);
|
toxav_kill(ASettins.av);
|
||||||
|
|
||||||
terminate_devices();
|
terminate_devices();
|
||||||
}
|
}
|
||||||
|
|
||||||
void read_device_callback (const int16_t* captured, uint32_t size, void* data)
|
void read_device_callback (const int16_t* captured, uint32_t size, void* data)
|
||||||
{
|
{
|
||||||
int32_t call_index = *((int32_t*)data); /* TODO: Or pass an array of call_idx's */
|
int32_t call_index = *((int32_t*)data); /* TODO: Or pass an array of call_idx's */
|
||||||
|
|
||||||
uint8_t encoded_payload[RTP_PAYLOAD_SIZE];
|
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);
|
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 ) {
|
if ( payload_size <= 0 || toxav_send_audio(ASettins.av, call_index, encoded_payload, payload_size) < 0 ) {
|
||||||
@ -180,72 +171,77 @@ void read_device_callback (const int16_t* captured, uint32_t size, void* data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void write_device_callback(void *agent, int32_t call_index, const int16_t* PCM, uint16_t size, void* arg)
|
||||||
void write_device_callback(ToxAv* av, int32_t call_index, int16_t* data, int size, void* userdata)
|
|
||||||
{
|
{
|
||||||
(void)userdata;
|
(void)arg;
|
||||||
|
(void)agent;
|
||||||
|
|
||||||
if (call_index >= 0 && ASettins.calls[call_index].ttas) {
|
if (call_index >= 0 && ASettins.calls[call_index].ttas) {
|
||||||
ToxAvCSettings csettings = ASettins.cs;
|
ToxAvCSettings csettings = ASettins.cs;
|
||||||
toxav_get_peer_csettings(av, call_index, 0, &csettings);
|
toxav_get_peer_csettings(ASettins.av, call_index, 0, &csettings);
|
||||||
write_out(ASettins.calls[call_index].out_idx, data, size, csettings.audio_channels);
|
write_out(ASettins.calls[call_index].out_idx, PCM, size, csettings.audio_channels);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int start_transmission(ToxWindow *self)
|
int start_transmission(ToxWindow *self, Call *call)
|
||||||
{
|
{
|
||||||
if ( !ASettins.av || self->call_idx == -1 ) return -1;
|
if ( !self || !ASettins.av || self->call_idx == -1 ) {
|
||||||
|
|
||||||
/* Don't provide support for video */
|
|
||||||
if ( 0 != toxav_prepare_transmission(ASettins.av, self->call_idx, av_jbufdc * 2, av_VADd, 0) ) {
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Could not prepare transmission");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Could not prepare transmission");
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !toxav_capability_supported(ASettins.av, self->call_idx, AudioDecoding) ||
|
/* Don't provide support for video */
|
||||||
!toxav_capability_supported(ASettins.av, self->call_idx, AudioEncoding) )
|
if ( 0 != toxav_prepare_transmission(ASettins.av, self->call_idx, 0) ) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Could not prepare transmission");
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
if (set_call(&ASettins.calls[self->call_idx], true) == -1)
|
|
||||||
|
if ( !toxav_capability_supported(ASettins.av, self->call_idx, av_AudioDecoding) ||
|
||||||
|
!toxav_capability_supported(ASettins.av, self->call_idx, av_AudioEncoding) )
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (set_call(call, true) == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
ToxAvCSettings csettings;
|
ToxAvCSettings csettings;
|
||||||
toxav_get_peer_csettings(ASettins.av, self->call_idx, 0, &csettings);
|
toxav_get_peer_csettings(ASettins.av, self->call_idx, 0, &csettings);
|
||||||
|
|
||||||
if ( open_primary_device(input, &ASettins.calls[self->call_idx].in_idx,
|
if ( open_primary_device(input, &call->in_idx,
|
||||||
csettings.audio_sample_rate, csettings.audio_frame_duration, csettings.audio_channels) != de_None )
|
csettings.audio_sample_rate, csettings.audio_frame_duration, csettings.audio_channels) != de_None )
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open input device!");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open input device!");
|
||||||
|
|
||||||
if ( register_device_callback(self->call_idx, ASettins.calls[self->call_idx].in_idx,
|
if ( register_device_callback(self->call_idx, call->in_idx,
|
||||||
read_device_callback, &self->call_idx, true) != de_None)
|
read_device_callback, &self->call_idx, true) != de_None)
|
||||||
/* Set VAD as true for all; TODO: Make it more dynamic */
|
/* Set VAD as true for all; TODO: Make it more dynamic */
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to register input handler!");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to register input handler!");
|
||||||
|
|
||||||
if ( open_primary_device(output, &ASettins.calls[self->call_idx].out_idx,
|
if ( open_primary_device(output, &call->out_idx,
|
||||||
csettings.audio_sample_rate, csettings.audio_frame_duration, csettings.audio_channels) != de_None ) {
|
csettings.audio_sample_rate, csettings.audio_frame_duration, csettings.audio_channels) != de_None ) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open output device!");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open output device!");
|
||||||
ASettins.calls[self->call_idx].has_output = 0;
|
call->has_output = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int stop_transmission(int call_index)
|
int stop_transmission(Call *call, int32_t call_index)
|
||||||
{
|
{
|
||||||
if ( ASettins.calls[call_index].ttas ) {
|
if ( call->ttas ) {
|
||||||
toxav_kill_transmission(ASettins.av, call_index);
|
toxav_kill_transmission(ASettins.av, call_index);
|
||||||
ASettins.calls[call_index].ttas = false;
|
call->ttas = false;
|
||||||
|
|
||||||
if ( ASettins.calls[call_index].in_idx != -1 )
|
if ( call->in_idx != -1 )
|
||||||
close_device(input, ASettins.calls[call_index].in_idx);
|
close_device(input, call->in_idx);
|
||||||
|
|
||||||
if ( ASettins.calls[call_index].out_idx != -1 )
|
if ( call->out_idx != -1 )
|
||||||
close_device(output, ASettins.calls[call_index].out_idx);
|
close_device(output, call->out_idx);
|
||||||
|
|
||||||
if (set_call(&ASettins.calls[call_index], false) == -1)
|
if (set_call(call, false) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -273,12 +269,12 @@ void callback_recv_ringing ( void* av, int32_t call_index, void* arg )
|
|||||||
}
|
}
|
||||||
void callback_recv_starting ( void* av, int32_t call_index, void* arg )
|
void callback_recv_starting ( void* av, int32_t call_index, void* arg )
|
||||||
{
|
{
|
||||||
ToxWindow* windows = arg;
|
ToxWindow* windows = arg;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i)
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i)
|
||||||
if (windows[i].onStarting != NULL && windows[i].call_idx == call_index) {
|
if (windows[i].onStarting != NULL && windows[i].call_idx == call_index) {
|
||||||
windows[i].onStarting(&windows[i], ASettins.av, call_index);
|
windows[i].onStarting(&windows[i], ASettins.av, call_index);
|
||||||
if ( 0 != start_transmission(&windows[i]) ) {/* YEAH! */
|
if ( 0 != start_transmission(&windows[i], &ASettins.calls[call_index])) {/* YEAH! */
|
||||||
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0 , "Error starting transmission!");
|
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0 , "Error starting transmission!");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -287,17 +283,17 @@ void callback_recv_starting ( void* av, int32_t call_index, void* arg )
|
|||||||
void callback_recv_ending ( void* av, int32_t call_index, void* arg )
|
void callback_recv_ending ( void* av, int32_t call_index, void* arg )
|
||||||
{
|
{
|
||||||
CB_BODY(call_index, arg, onEnding);
|
CB_BODY(call_index, arg, onEnding);
|
||||||
stop_transmission(call_index);
|
stop_transmission(&ASettins.calls[call_index], call_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void callback_call_started ( void* av, int32_t call_index, void* arg )
|
void callback_call_started ( void* av, int32_t call_index, void* arg )
|
||||||
{
|
{
|
||||||
ToxWindow* windows = arg;
|
ToxWindow* windows = arg;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i)
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i)
|
||||||
if (windows[i].onStart != NULL && windows[i].call_idx == call_index) {
|
if (windows[i].onStart != NULL && windows[i].call_idx == call_index) {
|
||||||
windows[i].onStart(&windows[i], ASettins.av, call_index);
|
windows[i].onStart(&windows[i], ASettins.av, call_index);
|
||||||
if ( 0 != start_transmission(&windows[i]) ) {/* YEAH! */
|
if ( 0 != start_transmission(&windows[i], &ASettins.calls[call_index]) ) {/* YEAH! */
|
||||||
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!");
|
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -308,7 +304,7 @@ void callback_call_canceled ( void* av, int32_t call_index, void* arg )
|
|||||||
CB_BODY(call_index, arg, onCancel);
|
CB_BODY(call_index, arg, onCancel);
|
||||||
|
|
||||||
/* In case call is active */
|
/* In case call is active */
|
||||||
stop_transmission(call_index);
|
stop_transmission(&ASettins.calls[call_index], call_index);
|
||||||
}
|
}
|
||||||
void callback_call_rejected ( void* av, int32_t call_index, void* arg )
|
void callback_call_rejected ( void* av, int32_t call_index, void* arg )
|
||||||
{
|
{
|
||||||
@ -317,7 +313,7 @@ void callback_call_rejected ( void* av, int32_t call_index, void* arg )
|
|||||||
void callback_call_ended ( void* av, int32_t call_index, void* arg )
|
void callback_call_ended ( void* av, int32_t call_index, void* arg )
|
||||||
{
|
{
|
||||||
CB_BODY(call_index, arg, onEnd);
|
CB_BODY(call_index, arg, onEnd);
|
||||||
stop_transmission(call_index);
|
stop_transmission(&ASettins.calls[call_index], call_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void callback_requ_timeout ( void* av, int32_t call_index, void* arg )
|
void callback_requ_timeout ( void* av, int32_t call_index, void* arg )
|
||||||
@ -327,16 +323,18 @@ void callback_requ_timeout ( void* av, int32_t call_index, void* arg )
|
|||||||
void callback_peer_timeout ( void* av, int32_t call_index, void* arg )
|
void callback_peer_timeout ( void* av, int32_t call_index, void* arg )
|
||||||
{
|
{
|
||||||
CB_BODY(call_index, arg, onPeerTimeout);
|
CB_BODY(call_index, arg, onPeerTimeout);
|
||||||
stop_transmission(call_index);
|
stop_transmission(&ASettins.calls[call_index], call_index);
|
||||||
/* Call is stopped manually since there might be some other
|
/* Call is stopped manually since there might be some other
|
||||||
* actions that one can possibly take on timeout
|
* actions that one can possibly take on timeout
|
||||||
*/
|
*/
|
||||||
toxav_stop_call(ASettins.av, call_index);
|
toxav_stop_call(ASettins.av, call_index);
|
||||||
}
|
}
|
||||||
void callback_media_change(void* av, int32_t call_index, void* arg)
|
|
||||||
{
|
// void callback_media_change(void* av, int32_t call_index, void* arg)
|
||||||
|
// {
|
||||||
/*... TODO cancel all media change requests */
|
/*... TODO cancel all media change requests */
|
||||||
}
|
// }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* End of Callbacks
|
* End of Callbacks
|
||||||
*/
|
*/
|
||||||
@ -359,15 +357,15 @@ void cmd_call(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
|||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self->stb->is_online) {
|
if (!self->stb->connection) {
|
||||||
error_str = "Friend is offline.";
|
error_str = "Friend is offline.";
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
ToxAvError error = toxav_call(ASettins.av, &self->call_idx, self->num, &ASettins.cs, 30);
|
ToxAvError error = toxav_call(ASettins.av, &self->call_idx, self->num, &ASettins.cs, 30);
|
||||||
|
|
||||||
if ( error != ErrorNone ) {
|
if ( error != av_ErrorNone ) {
|
||||||
if ( error == ErrorAlreadyInCall ) error_str = "Already in a call!";
|
if ( error == av_ErrorAlreadyInCallWithPeer ) error_str = "Already in a call!";
|
||||||
else error_str = "Internal error!";
|
else error_str = "Internal error!";
|
||||||
|
|
||||||
goto on_error;
|
goto on_error;
|
||||||
@ -396,9 +394,9 @@ void cmd_answer(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
|||||||
|
|
||||||
ToxAvError error = toxav_answer(ASettins.av, self->call_idx, &ASettins.cs);
|
ToxAvError error = toxav_answer(ASettins.av, self->call_idx, &ASettins.cs);
|
||||||
|
|
||||||
if ( error != ErrorNone ) {
|
if ( error != av_ErrorNone ) {
|
||||||
if ( error == ErrorInvalidState ) error_str = "Cannot answer in invalid state!";
|
if ( error == av_ErrorInvalidState ) error_str = "Cannot answer in invalid state!";
|
||||||
else if ( error == ErrorNoCall ) error_str = "No incoming call!";
|
else if ( error == av_ErrorNoCall ) error_str = "No incoming call!";
|
||||||
else error_str = "Internal error!";
|
else error_str = "Internal error!";
|
||||||
|
|
||||||
goto on_error;
|
goto on_error;
|
||||||
@ -427,9 +425,9 @@ void cmd_reject(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
|||||||
|
|
||||||
ToxAvError error = toxav_reject(ASettins.av, self->call_idx, "Why not?");
|
ToxAvError error = toxav_reject(ASettins.av, self->call_idx, "Why not?");
|
||||||
|
|
||||||
if ( error != ErrorNone ) {
|
if ( error != av_ErrorNone ) {
|
||||||
if ( error == ErrorInvalidState ) error_str = "Cannot reject in invalid state!";
|
if ( error == av_ErrorInvalidState ) error_str = "Cannot reject in invalid state!";
|
||||||
else if ( error == ErrorNoCall ) error_str = "No incoming call!";
|
else if ( error == av_ErrorNoCall ) error_str = "No incoming call!";
|
||||||
else error_str = "Internal error!";
|
else error_str = "Internal error!";
|
||||||
|
|
||||||
goto on_error;
|
goto on_error;
|
||||||
@ -469,9 +467,9 @@ void cmd_hangup(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
|||||||
error = toxav_hangup(ASettins.av, self->call_idx);
|
error = toxav_hangup(ASettins.av, self->call_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( error != ErrorNone ) {
|
if ( error != av_ErrorNone ) {
|
||||||
if ( error == ErrorInvalidState ) error_str = "Cannot hangup in invalid state!";
|
if ( error == av_ErrorInvalidState ) error_str = "Cannot hangup in invalid state!";
|
||||||
else if ( error == ErrorNoCall ) error_str = "No call!";
|
else if ( error == av_ErrorNoCall ) error_str = "No call!";
|
||||||
else error_str = "Internal error!";
|
else error_str = "Internal error!";
|
||||||
|
|
||||||
goto on_error;
|
goto on_error;
|
||||||
@ -495,10 +493,10 @@ void cmd_list_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*
|
|||||||
|
|
||||||
DeviceType type;
|
DeviceType type;
|
||||||
|
|
||||||
if ( strcmp(argv[1], "in") == 0 ) /* Input devices */
|
if ( strcasecmp(argv[1], "in") == 0 ) /* Input devices */
|
||||||
type = input;
|
type = input;
|
||||||
|
|
||||||
else if ( strcmp(argv[1], "out") == 0 ) /* Output devices */
|
else if ( strcasecmp(argv[1], "out") == 0 ) /* Output devices */
|
||||||
type = output;
|
type = output;
|
||||||
|
|
||||||
else {
|
else {
|
||||||
@ -547,12 +545,12 @@ void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (
|
|||||||
error_str = "Invalid input";
|
error_str = "Invalid input";
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( set_primary_device(type, selection) == de_InvalidSelection ) {
|
if ( set_primary_device(type, selection) == de_InvalidSelection ) {
|
||||||
error_str="Invalid selection!";
|
error_str="Invalid selection!";
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
on_error:
|
on_error:
|
||||||
print_err (self, error_str);
|
print_err (self, error_str);
|
||||||
@ -561,71 +559,71 @@ on_error:
|
|||||||
void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
const char *error_str;
|
const char *error_str;
|
||||||
|
|
||||||
if ( argc != 2 ) {
|
if ( argc != 2 ) {
|
||||||
if ( argc < 1 ) error_str = "Type must be specified!";
|
if ( argc < 1 ) error_str = "Type must be specified!";
|
||||||
else if ( argc < 2 ) error_str = "Must have id!";
|
else if ( argc < 2 ) error_str = "Must have id!";
|
||||||
else error_str = "Only two arguments allowed!";
|
else error_str = "Only two arguments allowed!";
|
||||||
|
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceType type;
|
DeviceType type;
|
||||||
|
|
||||||
if ( strcmp(argv[1], "in") == 0 ) /* Input devices */
|
if ( strcmp(argv[1], "in") == 0 ) /* Input devices */
|
||||||
type = input;
|
type = input;
|
||||||
|
|
||||||
else if ( strcmp(argv[1], "out") == 0 ) /* Output devices */
|
else if ( strcmp(argv[1], "out") == 0 ) /* Output devices */
|
||||||
type = output;
|
type = output;
|
||||||
|
|
||||||
else {
|
else {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char *end;
|
char *end;
|
||||||
long int selection = strtol(argv[2], &end, 10);
|
long int selection = strtol(argv[2], &end, 10);
|
||||||
|
|
||||||
if ( *end ) {
|
if ( *end ) {
|
||||||
error_str = "Invalid input";
|
error_str = "Invalid input";
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( selection_valid(type, selection) == de_InvalidSelection ) {
|
if ( selection_valid(type, selection) == de_InvalidSelection ) {
|
||||||
error_str="Invalid selection!";
|
error_str="Invalid selection!";
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If call is active, change device */
|
/* If call is active, change device */
|
||||||
if ( self->call_idx > -1) {
|
if ( self->call_idx > -1) {
|
||||||
Call* this_call = &ASettins.calls[self->call_idx];
|
Call* this_call = &ASettins.calls[self->call_idx];
|
||||||
if (this_call->ttas) {
|
if (this_call->ttas) {
|
||||||
|
|
||||||
ToxAvCSettings csettings;
|
ToxAvCSettings csettings;
|
||||||
toxav_get_peer_csettings(ASettins.av, self->call_idx, 0, &csettings);
|
toxav_get_peer_csettings(ASettins.av, self->call_idx, 0, &csettings);
|
||||||
|
|
||||||
if (type == output) {
|
if (type == output) {
|
||||||
pthread_mutex_lock(&this_call->mutex);
|
pthread_mutex_lock(&this_call->mutex);
|
||||||
close_device(output, this_call->out_idx);
|
close_device(output, this_call->out_idx);
|
||||||
this_call->has_output = open_device(output, selection, &this_call->out_idx,
|
this_call->has_output = open_device(output, selection, &this_call->out_idx,
|
||||||
csettings.audio_sample_rate, csettings.audio_frame_duration, csettings.audio_channels)
|
csettings.audio_sample_rate, csettings.audio_frame_duration, csettings.audio_channels)
|
||||||
== de_None ? 1 : 0;
|
== de_None ? 1 : 0;
|
||||||
pthread_mutex_unlock(&this_call->mutex);
|
pthread_mutex_unlock(&this_call->mutex);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* TODO: check for failure */
|
/* TODO: check for failure */
|
||||||
close_device(input, this_call->in_idx);
|
close_device(input, this_call->in_idx);
|
||||||
open_device(input, selection, &this_call->in_idx, csettings.audio_sample_rate,
|
open_device(input, selection, &this_call->in_idx, csettings.audio_sample_rate,
|
||||||
csettings.audio_frame_duration, csettings.audio_channels);
|
csettings.audio_frame_duration, csettings.audio_channels);
|
||||||
/* Set VAD as true for all; TODO: Make it more dynamic */
|
/* Set VAD as true for all; TODO: Make it more dynamic */
|
||||||
register_device_callback(self->call_idx, this_call->in_idx, read_device_callback, &self->call_idx, true);
|
register_device_callback(self->call_idx, this_call->in_idx, read_device_callback, &self->call_idx, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self->device_selection[type] = selection;
|
self->device_selection[type] = selection;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
on_error:
|
on_error:
|
||||||
print_err (self, error_str);
|
print_err (self, error_str);
|
||||||
@ -634,33 +632,33 @@ void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
|
|||||||
void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
const char *error_str;
|
const char *error_str;
|
||||||
|
|
||||||
if ( argc != 1 ) {
|
if ( argc != 1 ) {
|
||||||
if ( argc < 1 ) error_str = "Type must be specified!";
|
if ( argc < 1 ) error_str = "Type must be specified!";
|
||||||
else error_str = "Only two arguments allowed!";
|
else error_str = "Only two arguments allowed!";
|
||||||
|
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceType type;
|
DeviceType type;
|
||||||
|
|
||||||
if ( strcasecmp(argv[1], "in") == 0 ) /* Input devices */
|
if ( strcasecmp(argv[1], "in") == 0 ) /* Input devices */
|
||||||
type = input;
|
type = input;
|
||||||
|
|
||||||
else if ( strcasecmp(argv[1], "out") == 0 ) /* Output devices */
|
else if ( strcasecmp(argv[1], "out") == 0 ) /* Output devices */
|
||||||
type = output;
|
type = output;
|
||||||
|
|
||||||
else {
|
else {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* If call is active, use this_call values */
|
/* If call is active, use this_call values */
|
||||||
if ( self->call_idx > -1) {
|
if ( self->call_idx > -1) {
|
||||||
Call* this_call = &ASettins.calls[self->call_idx];
|
Call* this_call = &ASettins.calls[self->call_idx];
|
||||||
|
|
||||||
pthread_mutex_lock(&this_call->mutex);
|
pthread_mutex_lock(&this_call->mutex);
|
||||||
if (type == input) {
|
if (type == input) {
|
||||||
device_mute(type, this_call->in_idx);
|
device_mute(type, this_call->in_idx);
|
||||||
self->chatwin->infobox.in_is_muted ^= 1;
|
self->chatwin->infobox.in_is_muted ^= 1;
|
||||||
@ -670,9 +668,9 @@ void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
|||||||
}
|
}
|
||||||
pthread_mutex_unlock(&this_call->mutex);
|
pthread_mutex_unlock(&this_call->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
on_error:
|
on_error:
|
||||||
print_err (self, error_str);
|
print_err (self, error_str);
|
||||||
}
|
}
|
||||||
@ -680,40 +678,40 @@ void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
|||||||
void cmd_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
const char *error_str;
|
const char *error_str;
|
||||||
|
|
||||||
if ( argc != 1 ) {
|
if ( argc != 1 ) {
|
||||||
if ( argc < 1 ) error_str = "Must have value!";
|
if ( argc < 1 ) error_str = "Must have value!";
|
||||||
else error_str = "Only two arguments allowed!";
|
else error_str = "Only two arguments allowed!";
|
||||||
|
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *end;
|
char *end;
|
||||||
float value = strtof(argv[1], &end);
|
float value = strtof(argv[1], &end);
|
||||||
|
|
||||||
if ( *end ) {
|
if ( *end ) {
|
||||||
error_str = "Invalid input";
|
error_str = "Invalid input";
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Call must be active */
|
/* Call must be active */
|
||||||
if ( self->call_idx > -1) {
|
if ( self->call_idx > -1) {
|
||||||
device_set_VAD_treshold(ASettins.calls[self->call_idx].in_idx, value);
|
device_set_VAD_treshold(ASettins.calls[self->call_idx].in_idx, value);
|
||||||
self->chatwin->infobox.vad_lvl = value;
|
self->chatwin->infobox.vad_lvl = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
on_error:
|
on_error:
|
||||||
print_err (self, error_str);
|
print_err (self, error_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void stop_current_call(ToxWindow* self)
|
void stop_current_call(ToxWindow* self)
|
||||||
{
|
{
|
||||||
ToxAvCallState callstate;
|
ToxAvCallState callstate;
|
||||||
if ( ASettins.av != NULL && self->call_idx != -1 &&
|
if ( ASettins.av != NULL && self->call_idx != -1 &&
|
||||||
( callstate = toxav_get_call_state(ASettins.av, self->call_idx) ) != av_CallNonExistant) {
|
( callstate = toxav_get_call_state(ASettins.av, self->call_idx) ) != av_CallNonExistent) {
|
||||||
switch (callstate)
|
switch (callstate)
|
||||||
{
|
{
|
||||||
case av_CallActive:
|
case av_CallActive:
|
||||||
|
@ -34,12 +34,18 @@ typedef enum _AudioError {
|
|||||||
ae_StartingCoreAudio = 1 << 2
|
ae_StartingCoreAudio = 1 << 2
|
||||||
} AudioError;
|
} AudioError;
|
||||||
|
|
||||||
/* You will have to pass pointer to first member of 'windows'
|
typedef struct Call {
|
||||||
* declared in windows.c otherwise undefined behaviour will
|
pthread_t ttid; /* Transmission thread id */
|
||||||
*/
|
bool ttas, has_output; /* Transmission thread active status (0 - stopped, 1- running) */
|
||||||
|
uint32_t in_idx, out_idx;
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
} Call;
|
||||||
|
|
||||||
|
/* You will have to pass pointer to first member of 'windows' declared in windows.c */
|
||||||
ToxAv *init_audio(ToxWindow *self, Tox *tox);
|
ToxAv *init_audio(ToxWindow *self, Tox *tox);
|
||||||
void terminate_audio();
|
void terminate_audio();
|
||||||
|
int start_transmission(ToxWindow *self, Call *call);
|
||||||
|
int stop_transmission(Call *call, int call_index);
|
||||||
void stop_current_call(ToxWindow *self);
|
void stop_current_call(ToxWindow *self);
|
||||||
|
|
||||||
#endif /* AUDIO_H */
|
#endif /* AUDIO_H */
|
||||||
|
@ -209,7 +209,7 @@ static void complt_home_dir(ToxWindow *self, char *path, int pathsize, const cha
|
|||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
char homedir[MAX_STR_SIZE];
|
char homedir[MAX_STR_SIZE] = {0};
|
||||||
get_home_dir(homedir, sizeof(homedir));
|
get_home_dir(homedir, sizeof(homedir));
|
||||||
|
|
||||||
char newline[MAX_STR_SIZE];
|
char newline[MAX_STR_SIZE];
|
||||||
@ -245,7 +245,7 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
|
|||||||
const wchar_t *tmpline = &line[wcslen(cmd) + 2]; /* start after "/command \"" */
|
const wchar_t *tmpline = &line[wcslen(cmd) + 2]; /* start after "/command \"" */
|
||||||
|
|
||||||
if (wcs_to_mbs_buf(b_path, tmpline, sizeof(b_path)) == -1)
|
if (wcs_to_mbs_buf(b_path, tmpline, sizeof(b_path)) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (wcs_to_mbs_buf(b_cmd, cmd, sizeof(b_cmd)) == -1)
|
if (wcs_to_mbs_buf(b_cmd, cmd, sizeof(b_cmd)) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
@ -257,11 +257,11 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
|
|||||||
|
|
||||||
if (!b_path[0]) { /* list everything in pwd */
|
if (!b_path[0]) { /* list everything in pwd */
|
||||||
b_path[0] = '.';
|
b_path[0] = '.';
|
||||||
b_path[1] = '\0';
|
b_path[1] = '\0';
|
||||||
} else if (!si && b_path[0] != '/') { /* look for matches in pwd */
|
} else if (!si && b_path[0] != '/') { /* look for matches in pwd */
|
||||||
char tmp[MAX_STR_SIZE];
|
char tmp[MAX_STR_SIZE];
|
||||||
snprintf(tmp, sizeof(tmp), ".%s", b_path);
|
snprintf(tmp, sizeof(tmp), ".%s", b_path);
|
||||||
strcpy(b_path, tmp);
|
strcpy(b_path, tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
strcpy(b_name, &b_path[si + 1]);
|
strcpy(b_name, &b_path[si + 1]);
|
||||||
@ -277,13 +277,15 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
|
|||||||
int dircount = 0;
|
int dircount = 0;
|
||||||
|
|
||||||
while ((entry = readdir(dp)) && dircount < MAX_DIRS) {
|
while ((entry = readdir(dp)) && dircount < MAX_DIRS) {
|
||||||
if (strncmp(entry->d_name, b_name, b_name_len) == 0
|
if (strncmp(entry->d_name, b_name, b_name_len) == 0
|
||||||
&& strcmp(".", entry->d_name) && strcmp("..", entry->d_name)) {
|
&& strcmp(".", entry->d_name) && strcmp("..", entry->d_name)) {
|
||||||
snprintf(dirnames[dircount], sizeof(dirnames[dircount]), "%s", entry->d_name);
|
snprintf(dirnames[dircount], sizeof(dirnames[dircount]), "%s", entry->d_name);
|
||||||
++dircount;
|
++dircount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
closedir(dp);
|
||||||
|
|
||||||
if (dircount == 0)
|
if (dircount == 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
681
src/chat.c
681
src/chat.c
File diff suppressed because it is too large
Load Diff
@ -31,15 +31,11 @@
|
|||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "groupchat.h"
|
#include "groupchat.h"
|
||||||
#include "chat.h"
|
#include "chat.h"
|
||||||
#include "file_senders.h"
|
#include "file_transfers.h"
|
||||||
|
|
||||||
extern ToxWindow *prompt;
|
extern ToxWindow *prompt;
|
||||||
extern FriendsList Friends;
|
extern FriendsList Friends;
|
||||||
|
|
||||||
extern FileSender file_senders[MAX_FILES];
|
|
||||||
extern uint8_t max_file_senders_index;
|
|
||||||
extern uint8_t num_active_file_senders;
|
|
||||||
|
|
||||||
void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
@ -47,46 +43,35 @@ void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char msg[MAX_STR_SIZE];
|
||||||
const char *inoutstr = argv[1];
|
const char *inoutstr = argv[1];
|
||||||
int filenum = atoi(argv[2]);
|
int idx = atoi(argv[2]);
|
||||||
|
|
||||||
if (filenum >= MAX_FILES || filenum < 0) {
|
if (idx >= MAX_FILES || idx < 0) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcasecmp(inoutstr, "in") == 0) { /* cancel an incoming file transfer */
|
if (strcasecmp(inoutstr, "in") == 0) { /* cancel an incoming file transfer */
|
||||||
if (!Friends.list[self->num].file_receiver[filenum].active) {
|
if (!Friends.list[self->num].file_receiver[idx].active) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *filepath = Friends.list[self->num].file_receiver[filenum].filename;
|
const char *file_path = Friends.list[self->num].file_receiver[idx].file_path;
|
||||||
char name[MAX_STR_SIZE];
|
char file_name[MAX_STR_SIZE];
|
||||||
get_file_name(name, sizeof(name), filepath);
|
get_file_name(file_name, sizeof(file_name), file_path);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer for '%s' canceled.", name);
|
snprintf(msg, sizeof(msg), "File transfer for '%s' canceled.", file_name);
|
||||||
chat_close_file_receiver(m, filenum, self->num, TOX_FILECONTROL_KILL);
|
close_file_transfer(self, m, get_file_receiver_filenum(idx), self->num, TOX_FILE_CONTROL_CANCEL, msg, silent);
|
||||||
return;
|
return;
|
||||||
} else if (strcasecmp(inoutstr, "out") == 0) { /* cancel an outgoing file transfer */
|
} else if (strcasecmp(inoutstr, "out") == 0) { /* cancel an outgoing file transfer */
|
||||||
int i;
|
if (!Friends.list[self->num].file_sender[idx].active) {
|
||||||
bool match = false;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
|
||||||
if (file_senders[i].active && file_senders[i].filenum == filenum) {
|
|
||||||
match = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!match) {
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *filename = file_senders[i].filename;
|
snprintf(msg, sizeof(msg), "File transfer for '%s' canceled.", Friends.list[self->num].file_sender[idx].file_name);
|
||||||
char msg[MAX_STR_SIZE];
|
close_file_transfer(self, m, idx, self->num, TOX_FILE_CONTROL_CANCEL, msg, silent);
|
||||||
snprintf(msg, sizeof(msg), "File transfer for '%s' canceled.", filename);
|
|
||||||
close_file_sender(self, m, i, msg, TOX_FILECONTROL_KILL, filenum, self->num);
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type must be 'in' or 'out'.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type must be 'in' or 'out'.");
|
||||||
@ -125,24 +110,34 @@ void cmd_join_group(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
|
|||||||
|
|
||||||
const char *groupkey = Friends.list[self->num].group_invite.key;
|
const char *groupkey = Friends.list[self->num].group_invite.key;
|
||||||
uint16_t length = Friends.list[self->num].group_invite.length;
|
uint16_t length = Friends.list[self->num].group_invite.length;
|
||||||
|
uint8_t type = Friends.list[self->num].group_invite.type;
|
||||||
|
|
||||||
if (!Friends.list[self->num].group_invite.pending) {
|
if (!Friends.list[self->num].group_invite.pending) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending group chat invite.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending group chat invite.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int groupnum = tox_join_groupchat(m, self->num, (uint8_t *) groupkey, length);
|
int groupnum = -1;
|
||||||
|
|
||||||
|
if (type == TOX_GROUPCHAT_TYPE_TEXT)
|
||||||
|
groupnum = tox_join_groupchat(m, self->num, (uint8_t *) groupkey, length);
|
||||||
|
#ifdef AUDIO
|
||||||
|
else
|
||||||
|
groupnum = toxav_join_av_groupchat(m, self->num, (uint8_t *) groupkey, length,
|
||||||
|
write_device_callback_group, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (groupnum == -1) {
|
if (groupnum == -1) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (init_groupchat_win(prompt, m, groupnum) == -1) {
|
if (init_groupchat_win(prompt, m, groupnum, type) == -1) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
|
||||||
tox_del_groupchat(m, groupnum);
|
tox_del_groupchat(m, groupnum);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
@ -152,50 +147,73 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t filenum = atoi(argv[1]);
|
int idx = atoi(argv[1]);
|
||||||
|
|
||||||
if ((filenum == 0 && strcmp(argv[1], "0")) || filenum >= MAX_FILES) {
|
if ((idx == 0 && strcmp(argv[1], "0")) || idx >= MAX_FILES) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Friends.list[self->num].file_receiver[filenum].pending) {
|
uint32_t filenum = get_file_receiver_filenum(idx);
|
||||||
|
|
||||||
|
if (!Friends.list[self->num].file_receiver[idx].pending) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *filename = Friends.list[self->num].file_receiver[filenum].filename;
|
const char *file_path = Friends.list[self->num].file_receiver[idx].file_path;
|
||||||
|
|
||||||
if (tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_ACCEPT, 0, 0) == 0) {
|
TOX_ERR_FILE_CONTROL err;
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%d] as: '%s'", filenum, filename);
|
tox_file_control(m, self->num, filenum, TOX_FILE_CONTROL_RESUME, &err);
|
||||||
|
|
||||||
/* prep progress bar line */
|
if (err != TOX_ERR_FILE_CONTROL_OK)
|
||||||
char progline[MAX_STR_SIZE];
|
goto on_recv_error;
|
||||||
prep_prog_line(progline);
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
|
|
||||||
Friends.list[self->num].file_receiver[filenum].line_id = self->chatwin->hst->line_end->id + 2;
|
|
||||||
|
|
||||||
if ((Friends.list[self->num].file_receiver[filenum].file = fopen(filename, "a")) == NULL) {
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%d] as: '%s'", idx, file_path);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "* Error writing to file.");
|
|
||||||
tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0);
|
/* prep progress bar line */
|
||||||
} else {
|
char progline[MAX_STR_SIZE];
|
||||||
Friends.list[self->num].file_receiver[filenum].active = true;
|
prep_prog_line(progline);
|
||||||
++Friends.list[self->num].active_file_receivers;
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
|
||||||
}
|
Friends.list[self->num].file_receiver[idx].line_id = self->chatwin->hst->line_end->id + 2;
|
||||||
|
Friends.list[self->num].file_receiver[idx].pending = false;
|
||||||
|
|
||||||
|
if ((Friends.list[self->num].file_receiver[idx].file = fopen(file_path, "a")) == NULL) {
|
||||||
|
tox_file_control(m, self->num, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Invalid file path.");
|
||||||
} else {
|
} else {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed.");
|
Friends.list[self->num].file_receiver[idx].active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Friends.list[self->num].file_receiver[filenum].pending = false;
|
return;
|
||||||
|
|
||||||
|
on_recv_error:
|
||||||
|
switch (err) {
|
||||||
|
case TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND:
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend not found.");
|
||||||
|
return;
|
||||||
|
|
||||||
|
case TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED:
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend is not online.");
|
||||||
|
return;
|
||||||
|
|
||||||
|
case TOX_ERR_FILE_CONTROL_NOT_FOUND:
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Invalid filenumber.");
|
||||||
|
return;
|
||||||
|
|
||||||
|
case TOX_ERR_FILE_CONTROL_SENDQ:
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Connection error.");
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed (error %d)\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
if (max_file_senders_index >= (MAX_FILES - 1)) {
|
const char *errmsg = NULL;
|
||||||
const char *errmsg = "Please wait for some of your outgoing file transfers to complete.";
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path required.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path required.");
|
||||||
@ -227,50 +245,67 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
|||||||
|
|
||||||
off_t filesize = file_size(path);
|
off_t filesize = file_size(path);
|
||||||
|
|
||||||
if (filesize == -1) {
|
if (filesize == 0) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File corrupt.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file.");
|
||||||
fclose(file_to_send);
|
fclose(file_to_send);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char filename[MAX_STR_SIZE] = {0};
|
char file_name[TOX_MAX_FILENAME_LENGTH];
|
||||||
get_file_name(filename, sizeof(filename), path);
|
get_file_name(file_name, sizeof(file_name), path);
|
||||||
int namelen = strlen(filename);
|
size_t namelen = strlen(file_name);
|
||||||
int filenum = tox_new_file_sender(m, self->num, filesize, (const uint8_t *) filename, namelen);
|
|
||||||
|
|
||||||
if (filenum == -1) {
|
TOX_ERR_FILE_SEND err;
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error sending file.");
|
uint32_t filenum = tox_file_send(m, self->num, TOX_FILE_KIND_DATA, (uint64_t) filesize,
|
||||||
fclose(file_to_send);
|
NULL, (uint8_t *) file_name, namelen, &err);
|
||||||
return;
|
|
||||||
|
if (err != TOX_ERR_FILE_SEND_OK)
|
||||||
|
goto on_send_error;
|
||||||
|
|
||||||
|
uint32_t idx = get_file_transfer_index(filenum);
|
||||||
|
|
||||||
|
if (idx >= MAX_FILES) {
|
||||||
|
errmsg = "File transfer failed: Too many concurrent file transfers";
|
||||||
|
goto on_send_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i;
|
memcpy(Friends.list[self->num].file_sender[idx].file_name, file_name, namelen + 1);
|
||||||
|
Friends.list[self->num].file_sender[idx].active = true;
|
||||||
|
Friends.list[self->num].file_sender[idx].started = false;
|
||||||
|
Friends.list[self->num].file_sender[idx].file = file_to_send;
|
||||||
|
Friends.list[self->num].file_sender[idx].timestamp = get_unix_time();
|
||||||
|
Friends.list[self->num].file_sender[idx].file_size = filesize;
|
||||||
|
|
||||||
for (i = 0; i < MAX_FILES; ++i) {
|
char sizestr[32];
|
||||||
if (!file_senders[i].active) {
|
bytes_convert_str(sizestr, sizeof(sizestr), filesize);
|
||||||
memcpy(file_senders[i].filename, filename, namelen + 1);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Sending file [%d]: '%s' (%s)", idx, file_name, sizestr);
|
||||||
file_senders[i].active = true;
|
|
||||||
file_senders[i].toxwin = self;
|
|
||||||
file_senders[i].file = file_to_send;
|
|
||||||
file_senders[i].filenum = filenum;
|
|
||||||
file_senders[i].friendnum = self->num;
|
|
||||||
file_senders[i].timestamp = get_unix_time();
|
|
||||||
file_senders[i].size = filesize;
|
|
||||||
file_senders[i].piecelen = fread(file_senders[i].nextpiece, 1,
|
|
||||||
tox_file_data_size(m, self->num), file_to_send);
|
|
||||||
|
|
||||||
char sizestr[32];
|
return;
|
||||||
bytes_convert_str(sizestr, sizeof(sizestr), filesize);
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0,
|
|
||||||
"Sending file [%d]: '%s' (%s)", filenum, filename, sizestr);
|
|
||||||
|
|
||||||
++num_active_file_senders;
|
on_send_error:
|
||||||
|
switch (err) {
|
||||||
|
case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND:
|
||||||
|
errmsg = "File transfer failed: Invalid friend.";
|
||||||
|
break;
|
||||||
|
|
||||||
if (i == max_file_senders_index)
|
case TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED:
|
||||||
++max_file_senders_index;
|
errmsg = "File transfer failed: Friend is offline.";
|
||||||
|
break;
|
||||||
|
|
||||||
reset_file_sender_queue();
|
case TOX_ERR_FILE_SEND_NAME_TOO_LONG:
|
||||||
return;
|
errmsg = "File transfer failed: Filename is too long.";
|
||||||
}
|
break;
|
||||||
|
|
||||||
|
case TOX_ERR_FILE_SEND_TOO_MANY:
|
||||||
|
errmsg = "File transfer failed: Too many concurrent file transfers.";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
errmsg = "File transfer failed";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", errmsg);
|
||||||
|
tox_file_control(m, self->num, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
|
||||||
|
fclose(file_to_send);
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ void get_home_dir(char *home, int size)
|
|||||||
*/
|
*/
|
||||||
char *get_user_config_dir(void)
|
char *get_user_config_dir(void)
|
||||||
{
|
{
|
||||||
char home[NSS_BUFLEN_PASSWD];
|
char home[NSS_BUFLEN_PASSWD] = {0};
|
||||||
get_home_dir(home, sizeof(home));
|
get_home_dir(home, sizeof(home));
|
||||||
|
|
||||||
char *user_config_dir;
|
char *user_config_dir;
|
||||||
|
72
src/device.c
72
src/device.c
@ -38,8 +38,8 @@
|
|||||||
/* compatibility with older versions of OpenAL */
|
/* compatibility with older versions of OpenAL */
|
||||||
#ifndef ALC_ALL_DEVICES_SPECIFIER
|
#ifndef ALC_ALL_DEVICES_SPECIFIER
|
||||||
#include <AL/alext.h>
|
#include <AL/alext.h>
|
||||||
#endif
|
#endif /* ALC_ALL_DEVICES_SPECIFIER */
|
||||||
#endif
|
#endif /* __APPLE__ */
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -48,7 +48,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#define OPENAL_BUFS 5
|
|
||||||
#define inline__ inline __attribute__((always_inline))
|
#define inline__ inline __attribute__((always_inline))
|
||||||
|
|
||||||
extern struct user_settings *user_settings;
|
extern struct user_settings *user_settings;
|
||||||
@ -173,16 +172,16 @@ DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
|
|||||||
{
|
{
|
||||||
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
|
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
|
||||||
lock;
|
lock;
|
||||||
|
|
||||||
Device* device = running[input][device_idx];
|
Device* device = running[input][device_idx];
|
||||||
|
|
||||||
if (!device) {
|
if (!device) {
|
||||||
unlock;
|
unlock;
|
||||||
return de_DeviceNotActive;
|
return de_DeviceNotActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
device->VAD_treshold = value;
|
device->VAD_treshold = value;
|
||||||
|
|
||||||
unlock;
|
unlock;
|
||||||
return de_None;
|
return de_None;
|
||||||
}
|
}
|
||||||
@ -202,6 +201,10 @@ DeviceError open_primary_device(DeviceType type, uint32_t* device_idx, uint32_t
|
|||||||
return open_device(type, primary_device[type], device_idx, sample_rate, frame_duration, channels);
|
return open_device(type, primary_device[type], device_idx, sample_rate, frame_duration, channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void get_primary_device_name(DeviceType type, char *buf, int size)
|
||||||
|
{
|
||||||
|
memcpy(buf, ddevice_names[type], size);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: generate buffers separately
|
// TODO: generate buffers separately
|
||||||
DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels)
|
DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx, uint32_t sample_rate, uint32_t frame_duration, uint8_t channels)
|
||||||
@ -215,7 +218,7 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
|
|||||||
const uint32_t frame_size = (sample_rate * frame_duration / 1000);
|
const uint32_t frame_size = (sample_rate * frame_duration / 1000);
|
||||||
|
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
for (i = 0; i < MAX_DEVICES && running[type][i] != NULL; i ++);
|
for (i = 0; i < MAX_DEVICES && running[type][i] != NULL; ++i);
|
||||||
|
|
||||||
if (i == MAX_DEVICES) { unlock; return de_AllDevicesBusy; }
|
if (i == MAX_DEVICES) { unlock; return de_AllDevicesBusy; }
|
||||||
else *device_idx = i;
|
else *device_idx = i;
|
||||||
@ -271,7 +274,7 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
|
|||||||
uint16_t zeros[frame_size];
|
uint16_t zeros[frame_size];
|
||||||
memset(zeros, 0, frame_size*2);
|
memset(zeros, 0, frame_size*2);
|
||||||
|
|
||||||
for ( i =0; i < OPENAL_BUFS; ++i) {
|
for ( i = 0; i < OPENAL_BUFS; ++i ) {
|
||||||
alBufferData(device->buffers[i], device->sound_mode, zeros, frame_size*2, sample_rate);
|
alBufferData(device->buffers[i], device->sound_mode, zeros, frame_size*2, sample_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,9 +326,9 @@ DeviceError close_device(DeviceType type, uint32_t device_idx)
|
|||||||
alDeleteSources(1, &device->source);
|
alDeleteSources(1, &device->source);
|
||||||
alDeleteBuffers(OPENAL_BUFS, device->buffers);
|
alDeleteBuffers(OPENAL_BUFS, device->buffers);
|
||||||
|
|
||||||
if ( !alcCloseDevice(device->dhndl) ) rc = de_AlError;
|
|
||||||
alcMakeContextCurrent(NULL);
|
alcMakeContextCurrent(NULL);
|
||||||
if ( device->ctx ) alcDestroyContext(device->ctx);
|
if ( device->ctx ) alcDestroyContext(device->ctx);
|
||||||
|
if ( !alcCloseDevice(device->dhndl) ) rc = de_AlError;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(device);
|
free(device);
|
||||||
@ -340,33 +343,33 @@ DeviceError register_device_callback( int32_t call_idx, uint32_t device_idx, Dat
|
|||||||
{
|
{
|
||||||
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
|
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
|
||||||
return de_InvalidSelection;
|
return de_InvalidSelection;
|
||||||
|
|
||||||
lock;
|
lock;
|
||||||
running[input][device_idx]->cb = callback;
|
running[input][device_idx]->cb = callback;
|
||||||
running[input][device_idx]->cb_data = data;
|
running[input][device_idx]->cb_data = data;
|
||||||
running[input][device_idx]->enable_VAD = enable_VAD;
|
running[input][device_idx]->enable_VAD = enable_VAD;
|
||||||
running[input][device_idx]->call_idx = call_idx;
|
running[input][device_idx]->call_idx = call_idx;
|
||||||
unlock;
|
unlock;
|
||||||
|
|
||||||
return de_None;
|
return de_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline__ DeviceError write_out(uint32_t device_idx, int16_t* data, uint32_t lenght, uint8_t channels)
|
inline__ DeviceError write_out(uint32_t device_idx, const int16_t* data, uint32_t length, uint8_t channels)
|
||||||
{
|
{
|
||||||
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
|
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
|
||||||
|
|
||||||
Device* device = running[output][device_idx];
|
Device* device = running[output][device_idx];
|
||||||
|
|
||||||
if (!device || device->muted) return de_DeviceNotActive;
|
if (!device || device->muted) return de_DeviceNotActive;
|
||||||
|
|
||||||
pthread_mutex_lock(device->mutex);
|
pthread_mutex_lock(device->mutex);
|
||||||
|
|
||||||
|
|
||||||
ALuint bufid;
|
ALuint bufid;
|
||||||
ALint processed, queued;
|
ALint processed, queued;
|
||||||
alGetSourcei(device->source, AL_BUFFERS_PROCESSED, &processed);
|
alGetSourcei(device->source, AL_BUFFERS_PROCESSED, &processed);
|
||||||
alGetSourcei(device->source, AL_BUFFERS_QUEUED, &queued);
|
alGetSourcei(device->source, AL_BUFFERS_QUEUED, &queued);
|
||||||
|
|
||||||
if(processed) {
|
if(processed) {
|
||||||
ALuint bufids[processed];
|
ALuint bufids[processed];
|
||||||
alSourceUnqueueBuffers(device->source, processed, bufids);
|
alSourceUnqueueBuffers(device->source, processed, bufids);
|
||||||
@ -378,17 +381,17 @@ inline__ DeviceError write_out(uint32_t device_idx, int16_t* data, uint32_t leng
|
|||||||
pthread_mutex_unlock(device->mutex);
|
pthread_mutex_unlock(device->mutex);
|
||||||
return de_Busy;
|
return de_Busy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
alBufferData(bufid, device->sound_mode, data, lenght * 2 * channels, device->sample_rate);
|
alBufferData(bufid, device->sound_mode, data, length * 2 * channels, device->sample_rate);
|
||||||
alSourceQueueBuffers(device->source, 1, &bufid);
|
alSourceQueueBuffers(device->source, 1, &bufid);
|
||||||
|
|
||||||
ALint state;
|
ALint state;
|
||||||
alGetSourcei(device->source, AL_SOURCE_STATE, &state);
|
alGetSourcei(device->source, AL_SOURCE_STATE, &state);
|
||||||
|
|
||||||
if(state != AL_PLAYING) alSourcePlay(device->source);
|
if(state != AL_PLAYING) alSourcePlay(device->source);
|
||||||
|
|
||||||
|
|
||||||
pthread_mutex_unlock(device->mutex);
|
pthread_mutex_unlock(device->mutex);
|
||||||
return de_None;
|
return de_None;
|
||||||
}
|
}
|
||||||
@ -408,7 +411,7 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
|
|||||||
if (thread_paused) usleep(10000); /* Wait for unpause. */
|
if (thread_paused) usleep(10000); /* Wait for unpause. */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (i = 0; i < size[input]; i ++)
|
for (i = 0; i < size[input]; ++i)
|
||||||
{
|
{
|
||||||
lock;
|
lock;
|
||||||
if (running[input][i] != NULL)
|
if (running[input][i] != NULL)
|
||||||
@ -426,12 +429,10 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
|
|||||||
int16_t frame[16000];
|
int16_t frame[16000];
|
||||||
alcCaptureSamples(device->dhndl, frame, f_size);
|
alcCaptureSamples(device->dhndl, frame, f_size);
|
||||||
|
|
||||||
if ( device->muted
|
if (device->muted) {
|
||||||
#ifdef AUDIO
|
unlock;
|
||||||
|| (device->enable_VAD && !toxav_has_activity(av, device->call_idx, frame, f_size, device->VAD_treshold))
|
continue;
|
||||||
#endif /* AUDIO */
|
}
|
||||||
)
|
|
||||||
{ unlock; continue; } /* Skip if no voice activity */
|
|
||||||
|
|
||||||
if ( device->cb ) device->cb(frame, f_size, device->cb_data);
|
if ( device->cb ) device->cb(frame, f_size, device->cb_data);
|
||||||
}
|
}
|
||||||
@ -446,8 +447,9 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
|
|||||||
|
|
||||||
void print_devices(ToxWindow* self, DeviceType type)
|
void print_devices(ToxWindow* self, DeviceType type)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i;
|
||||||
for ( ; i < size[type]; i ++)
|
|
||||||
|
for (i = 0; i < size[type]; ++i)
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%d: %s", i, devices_names[type][i]);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%d: %s", i, devices_names[type][i]);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#ifndef DEVICE_H
|
#ifndef DEVICE_H
|
||||||
#define DEVICE_H
|
#define DEVICE_H
|
||||||
|
|
||||||
|
#define OPENAL_BUFS 5
|
||||||
#define MAX_DEVICES 32
|
#define MAX_DEVICES 32
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
@ -81,9 +82,10 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
|
|||||||
DeviceError close_device(DeviceType type, uint32_t device_idx);
|
DeviceError close_device(DeviceType type, uint32_t device_idx);
|
||||||
|
|
||||||
/* Write data to device */
|
/* Write data to device */
|
||||||
DeviceError write_out(uint32_t device_idx, int16_t* data, uint32_t lenght, uint8_t channels);
|
DeviceError write_out(uint32_t device_idx, const int16_t* data, uint32_t length, uint8_t channels);
|
||||||
|
|
||||||
void print_devices(ToxWindow* self, DeviceType type);
|
void print_devices(ToxWindow* self, DeviceType type);
|
||||||
|
void get_primary_device_name(DeviceType type, char *buf, int size);
|
||||||
|
|
||||||
DeviceError selection_valid(DeviceType type, int32_t selection);
|
DeviceError selection_valid(DeviceType type, int32_t selection);
|
||||||
#endif /* DEVICE_H */
|
#endif /* DEVICE_H */
|
||||||
|
86
src/dns.c
86
src/dns.c
@ -47,7 +47,7 @@
|
|||||||
#define TOX_DNS3_TXT_PREFIX "v=tox3;id="
|
#define TOX_DNS3_TXT_PREFIX "v=tox3;id="
|
||||||
|
|
||||||
extern struct Winthread Winthread;
|
extern struct Winthread Winthread;
|
||||||
extern struct _dns3_servers dns3_servers;
|
extern struct dns3_servers dns3_servers;
|
||||||
extern struct arg_opts arg_opts;
|
extern struct arg_opts arg_opts;
|
||||||
|
|
||||||
#define NUM_DNS3_BACKUP_SERVERS 2
|
#define NUM_DNS3_BACKUP_SERVERS 2
|
||||||
@ -73,16 +73,16 @@ static struct dns3_server_backup {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct _thread_data {
|
static struct thread_data {
|
||||||
ToxWindow *self;
|
ToxWindow *self;
|
||||||
char id_bin[TOX_FRIEND_ADDRESS_SIZE];
|
char id_bin[TOX_ADDRESS_SIZE];
|
||||||
char addr[MAX_STR_SIZE];
|
char addr[MAX_STR_SIZE];
|
||||||
char msg[MAX_STR_SIZE];
|
char msg[MAX_STR_SIZE];
|
||||||
uint8_t busy;
|
uint8_t busy;
|
||||||
Tox *m;
|
Tox *m;
|
||||||
} t_data;
|
} t_data;
|
||||||
|
|
||||||
static struct _dns_thread {
|
static struct dns_thread {
|
||||||
pthread_t tid;
|
pthread_t tid;
|
||||||
pthread_attr_t attr;
|
pthread_attr_t attr;
|
||||||
} dns_thread;
|
} dns_thread;
|
||||||
@ -92,7 +92,7 @@ static struct _dns_thread {
|
|||||||
#define MAX_DOMAIN_SIZE 32
|
#define MAX_DOMAIN_SIZE 32
|
||||||
#define MAX_DNS_LINE MAX_DOMAIN_SIZE + (DNS3_KEY_SIZE * 2) + 3
|
#define MAX_DNS_LINE MAX_DOMAIN_SIZE + (DNS3_KEY_SIZE * 2) + 3
|
||||||
|
|
||||||
struct _dns3_servers {
|
struct dns3_servers {
|
||||||
bool loaded;
|
bool loaded;
|
||||||
int lines;
|
int lines;
|
||||||
char names[MAX_DNS_SERVERS][MAX_DOMAIN_SIZE];
|
char names[MAX_DNS_SERVERS][MAX_DOMAIN_SIZE];
|
||||||
@ -152,12 +152,12 @@ static int dns_error(ToxWindow *self, const char *errmsg)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kill_dns_thread(void *dns_obj)
|
static void killdns_thread(void *dns_obj)
|
||||||
{
|
{
|
||||||
if (dns_obj)
|
if (dns_obj)
|
||||||
tox_dns3_kill(dns_obj);
|
tox_dns3_kill(dns_obj);
|
||||||
|
|
||||||
memset(&t_data, 0, sizeof(struct _thread_data));
|
memset(&t_data, 0, sizeof(struct thread_data));
|
||||||
pthread_attr_destroy(&dns_thread.attr);
|
pthread_attr_destroy(&dns_thread.attr);
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
@ -168,39 +168,39 @@ static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, char
|
|||||||
uint8_t *ans_pt = answer + sizeof(HEADER);
|
uint8_t *ans_pt = answer + sizeof(HEADER);
|
||||||
uint8_t *ans_end = answer + ans_len;
|
uint8_t *ans_end = answer + ans_len;
|
||||||
char exp_ans[PACKETSZ];
|
char exp_ans[PACKETSZ];
|
||||||
|
|
||||||
int len = dn_expand(answer, ans_end, ans_pt, exp_ans, sizeof(exp_ans));
|
int len = dn_expand(answer, ans_end, ans_pt, exp_ans, sizeof(exp_ans));
|
||||||
|
|
||||||
if (len == -1)
|
if (len == -1)
|
||||||
return dns_error(self, "dn_expand failed.");
|
return dns_error(self, "dn_expand failed.");
|
||||||
|
|
||||||
ans_pt += len;
|
ans_pt += len;
|
||||||
|
|
||||||
if (ans_pt > ans_end - 4)
|
if (ans_pt > ans_end - 4)
|
||||||
return dns_error(self, "DNS reply was too short.");
|
return dns_error(self, "DNS reply was too short.");
|
||||||
|
|
||||||
int type;
|
int type;
|
||||||
GETSHORT(type, ans_pt);
|
GETSHORT(type, ans_pt);
|
||||||
|
|
||||||
if (type != T_TXT)
|
if (type != T_TXT)
|
||||||
return dns_error(self, "Broken DNS reply.");
|
return dns_error(self, "Broken DNS reply.");
|
||||||
|
|
||||||
|
|
||||||
ans_pt += INT16SZ; /* class */
|
ans_pt += INT16SZ; /* class */
|
||||||
uint32_t size = 0;
|
uint32_t size = 0;
|
||||||
|
|
||||||
/* recurse through CNAME rr's */
|
/* recurse through CNAME rr's */
|
||||||
do {
|
do {
|
||||||
ans_pt += size;
|
ans_pt += size;
|
||||||
len = dn_expand(answer, ans_end, ans_pt, exp_ans, sizeof(exp_ans));
|
len = dn_expand(answer, ans_end, ans_pt, exp_ans, sizeof(exp_ans));
|
||||||
|
|
||||||
if (len == -1)
|
if (len == -1)
|
||||||
return dns_error(self, "Second dn_expand failed.");
|
return dns_error(self, "Second dn_expand failed.");
|
||||||
|
|
||||||
ans_pt += len;
|
ans_pt += len;
|
||||||
|
|
||||||
if (ans_pt > ans_end - 10)
|
if (ans_pt > ans_end - 10)
|
||||||
return dns_error(self, "DNS reply was too short.");
|
return dns_error(self, "DNS reply was too short.");
|
||||||
|
|
||||||
GETSHORT(type, ans_pt);
|
GETSHORT(type, ans_pt);
|
||||||
ans_pt += INT16SZ;
|
ans_pt += INT16SZ;
|
||||||
@ -208,12 +208,12 @@ static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, char
|
|||||||
GETSHORT(size, ans_pt);
|
GETSHORT(size, ans_pt);
|
||||||
|
|
||||||
if (ans_pt + size < answer || ans_pt + size > ans_end)
|
if (ans_pt + size < answer || ans_pt + size > ans_end)
|
||||||
return dns_error(self, "RR overflow.");
|
return dns_error(self, "RR overflow.");
|
||||||
|
|
||||||
} while (type == T_CNAME);
|
} while (type == T_CNAME);
|
||||||
|
|
||||||
if (type != T_TXT)
|
if (type != T_TXT)
|
||||||
return dns_error(self, "DNS response failed.");
|
return dns_error(self, "DNS response failed.");
|
||||||
|
|
||||||
uint32_t txt_len = *ans_pt;
|
uint32_t txt_len = *ans_pt;
|
||||||
|
|
||||||
@ -230,7 +230,7 @@ static int parse_dns_response(ToxWindow *self, u_char *answer, int ans_len, char
|
|||||||
return txt_len;
|
return txt_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Takes address addr in the form "username@domain", puts the username in namebuf,
|
/* Takes address addr in the form "username@domain", puts the username in namebuf,
|
||||||
and the domain in dombuf.
|
and the domain in dombuf.
|
||||||
|
|
||||||
return length of username on success, -1 on failure */
|
return length of username on success, -1 on failure */
|
||||||
@ -299,7 +299,7 @@ void *dns3_lookup_thread(void *data)
|
|||||||
|
|
||||||
if (namelen == -1) {
|
if (namelen == -1) {
|
||||||
dns_error(self, "Must be a Tox ID or an address in the form username@domain");
|
dns_error(self, "Must be a Tox ID or an address in the form username@domain");
|
||||||
kill_dns_thread(NULL);
|
killdns_thread(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
char DNS_pubkey[DNS3_KEY_SIZE];
|
char DNS_pubkey[DNS3_KEY_SIZE];
|
||||||
@ -309,25 +309,25 @@ void *dns3_lookup_thread(void *data)
|
|||||||
|
|
||||||
if (match == -1) {
|
if (match == -1) {
|
||||||
dns_error(self, "Domain not found.");
|
dns_error(self, "Domain not found.");
|
||||||
kill_dns_thread(NULL);
|
killdns_thread(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *dns_obj = tox_dns3_new((uint8_t *) DNS_pubkey);
|
void *dns_obj = tox_dns3_new((uint8_t *) DNS_pubkey);
|
||||||
|
|
||||||
if (dns_obj == NULL) {
|
if (dns_obj == NULL) {
|
||||||
dns_error(self, "Core failed to create DNS object.");
|
dns_error(self, "Core failed to create DNS object.");
|
||||||
kill_dns_thread(NULL);
|
killdns_thread(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
char string[MAX_DNS_REQST_SIZE + 1];
|
char string[MAX_DNS_REQST_SIZE + 1];
|
||||||
uint32_t request_id;
|
uint32_t request_id;
|
||||||
|
|
||||||
int str_len = tox_generate_dns3_string(dns_obj, (uint8_t *) string, sizeof(string), &request_id,
|
int str_len = tox_generate_dns3_string(dns_obj, (uint8_t *) string, sizeof(string), &request_id,
|
||||||
(uint8_t *) name, namelen);
|
(uint8_t *) name, namelen);
|
||||||
|
|
||||||
if (str_len == -1) {
|
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);
|
killdns_thread(dns_obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
string[str_len] = '\0';
|
string[str_len] = '\0';
|
||||||
@ -341,14 +341,14 @@ void *dns3_lookup_thread(void *data)
|
|||||||
|
|
||||||
if (ans_len <= 0) {
|
if (ans_len <= 0) {
|
||||||
dns_error(self, "DNS query failed.");
|
dns_error(self, "DNS query failed.");
|
||||||
kill_dns_thread(dns_obj);
|
killdns_thread(dns_obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
char ans_id[MAX_DNS_REQST_SIZE + 1];
|
char ans_id[MAX_DNS_REQST_SIZE + 1];
|
||||||
|
|
||||||
/* extract TXT from DNS response */
|
/* extract TXT from DNS response */
|
||||||
if (parse_dns_response(self, answer, ans_len, ans_id) == -1)
|
if (parse_dns_response(self, answer, ans_len, ans_id) == -1)
|
||||||
kill_dns_thread(dns_obj);
|
killdns_thread(dns_obj);
|
||||||
|
|
||||||
char encrypted_id[MAX_DNS_REQST_SIZE + 1];
|
char encrypted_id[MAX_DNS_REQST_SIZE + 1];
|
||||||
int prfx_len = strlen(TOX_DNS3_TXT_PREFIX);
|
int prfx_len = strlen(TOX_DNS3_TXT_PREFIX);
|
||||||
@ -356,36 +356,35 @@ void *dns3_lookup_thread(void *data)
|
|||||||
/* extract the encrypted ID from TXT response */
|
/* extract the encrypted ID from TXT response */
|
||||||
if (strncmp(ans_id, TOX_DNS3_TXT_PREFIX, prfx_len) != 0) {
|
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);
|
killdns_thread(dns_obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(encrypted_id, ans_id + prfx_len, ans_len - prfx_len);
|
memcpy(encrypted_id, ans_id + prfx_len, ans_len - prfx_len);
|
||||||
|
|
||||||
if (tox_decrypt_dns3_TXT(dns_obj, (uint8_t *) t_data.id_bin, (uint8_t *) encrypted_id,
|
if (tox_decrypt_dns3_TXT(dns_obj, (uint8_t *) t_data.id_bin, (uint8_t *) encrypted_id,
|
||||||
strlen(encrypted_id), request_id) == -1) {
|
strlen(encrypted_id), request_id) == -1) {
|
||||||
dns_error(self, "Core failed to decrypt DNS response.");
|
dns_error(self, "Core failed to decrypt DNS response.");
|
||||||
kill_dns_thread(dns_obj);
|
killdns_thread(dns_obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
cmd_add_helper(self, t_data.m, t_data.id_bin, t_data.msg);
|
cmd_add_helper(self, t_data.m, t_data.id_bin, t_data.msg);
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
kill_dns_thread(dns_obj);
|
killdns_thread(dns_obj);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* creates new thread for dns3 lookup. Only allows one lookup at a time. */
|
/* creates new thread for dns3 lookup. Only allows one lookup at a time. */
|
||||||
void dns3_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr, const char *msg)
|
void dns3_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr, const char *msg)
|
||||||
{
|
{
|
||||||
if (arg_opts.use_proxy && arg_opts.force_tcp) {
|
if (arg_opts.proxy_type != TOX_PROXY_TYPE_NONE && arg_opts.force_tcp) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "DNS lookups are disabled.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "DNS lookups are disabled.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t_data.busy) {
|
if (t_data.busy) {
|
||||||
const char *err = "Please wait for previous user lookup to finish.";
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Please wait for previous user lookup to finish.");
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, err);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,12 +406,23 @@ void dns3_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr,
|
|||||||
t_data.m = m;
|
t_data.m = m;
|
||||||
t_data.busy = 1;
|
t_data.busy = 1;
|
||||||
|
|
||||||
if (pthread_attr_init(&dns_thread.attr) != 0)
|
if (pthread_attr_init(&dns_thread.attr) != 0) {
|
||||||
exit_toxic_err("failed in dns3_lookup", FATALERR_THREAD_ATTR);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: DNS thread attr failed to init");
|
||||||
|
memset(&t_data, 0, sizeof(struct thread_data));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (pthread_attr_setdetachstate(&dns_thread.attr, PTHREAD_CREATE_DETACHED) != 0)
|
if (pthread_attr_setdetachstate(&dns_thread.attr, PTHREAD_CREATE_DETACHED) != 0) {
|
||||||
exit_toxic_err("failed in dns3_lookup", FATALERR_THREAD_ATTR);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: DNS thread attr failed to set");
|
||||||
|
pthread_attr_destroy(&dns_thread.attr);
|
||||||
|
memset(&t_data, 0, sizeof(struct thread_data));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (pthread_create(&dns_thread.tid, &dns_thread.attr, dns3_lookup_thread, NULL) != 0)
|
if (pthread_create(&dns_thread.tid, &dns_thread.attr, dns3_lookup_thread, NULL) != 0) {
|
||||||
exit_toxic_err("failed in dns3_lookup", FATALERR_THREAD_CREATE);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: DNS thread failed to init");
|
||||||
|
pthread_attr_destroy(&dns_thread.attr);
|
||||||
|
memset(&t_data, 0, sizeof(struct thread_data));
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "execute.h"
|
#include "execute.h"
|
||||||
#include "chat_commands.h"
|
#include "chat_commands.h"
|
||||||
#include "global_commands.h"
|
#include "global_commands.h"
|
||||||
|
#include "group_commands.h"
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
@ -46,7 +47,7 @@ static struct cmd_func global_commands[] = {
|
|||||||
{ "/connect", cmd_connect },
|
{ "/connect", cmd_connect },
|
||||||
{ "/decline", cmd_decline },
|
{ "/decline", cmd_decline },
|
||||||
{ "/exit", cmd_quit },
|
{ "/exit", cmd_quit },
|
||||||
{ "/groupchat", cmd_groupchat },
|
{ "/group", cmd_groupchat },
|
||||||
{ "/help", cmd_prompt_help },
|
{ "/help", cmd_prompt_help },
|
||||||
{ "/log", cmd_log },
|
{ "/log", cmd_log },
|
||||||
{ "/myid", cmd_myid },
|
{ "/myid", cmd_myid },
|
||||||
@ -74,7 +75,16 @@ static struct cmd_func chat_commands[] = {
|
|||||||
{ "/answer", cmd_answer },
|
{ "/answer", cmd_answer },
|
||||||
{ "/reject", cmd_reject },
|
{ "/reject", cmd_reject },
|
||||||
{ "/hangup", cmd_hangup },
|
{ "/hangup", cmd_hangup },
|
||||||
{ "/sdev", cmd_ccur_device },
|
{ "/mute", cmd_mute },
|
||||||
|
{ "/sense", cmd_sense },
|
||||||
|
#endif /* AUDIO */
|
||||||
|
{ NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct cmd_func group_commands[] = {
|
||||||
|
{ "/title", cmd_set_title },
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
{ "/mute", cmd_mute },
|
{ "/mute", cmd_mute },
|
||||||
{ "/sense", cmd_sense },
|
{ "/sense", cmd_sense },
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
@ -165,6 +175,8 @@ void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case GROUPCHAT_COMMAND_MODE:
|
case GROUPCHAT_COMMAND_MODE:
|
||||||
|
if (do_command(w, self, m, num_args, group_commands, args) == 0)
|
||||||
|
return;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,8 @@ uint8_t max_file_senders_index;
|
|||||||
uint8_t num_active_file_senders;
|
uint8_t num_active_file_senders;
|
||||||
extern FriendsList Friends;
|
extern FriendsList Friends;
|
||||||
|
|
||||||
|
#define NUM_PROG_MARKS 50 /* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */
|
||||||
|
|
||||||
/* creates initial progress line that will be updated during file transfer.
|
/* creates initial progress line that will be updated during file transfer.
|
||||||
Assumes progline is of size MAX_STR_SIZE */
|
Assumes progline is of size MAX_STR_SIZE */
|
||||||
void prep_prog_line(char *progline)
|
void prep_prog_line(char *progline)
|
||||||
@ -51,7 +53,7 @@ void prep_prog_line(char *progline)
|
|||||||
strcat(progline, "] 0%");
|
strcat(progline, "] 0%");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* prints a progress bar for file transfers.
|
/* prints a progress bar for file transfers.
|
||||||
if friendnum is -1 we're sending the file, otherwise we're receiving. */
|
if friendnum is -1 we're sending the file, otherwise we're receiving. */
|
||||||
void print_progress_bar(ToxWindow *self, int idx, int friendnum, double pct_done)
|
void print_progress_bar(ToxWindow *self, int idx, int friendnum, double pct_done)
|
||||||
{
|
{
|
||||||
@ -134,7 +136,7 @@ static void refresh_sender_prog(Tox *m)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
int filenum = file_senders[i].filenum;
|
int filenum = file_senders[i].filenum;
|
||||||
int32_t friendnum = file_senders[i].friendnum;
|
uint32_t friendnum = file_senders[i].friendnum;
|
||||||
double remain = (double) tox_file_data_remaining(m, friendnum, filenum, 0);
|
double remain = (double) tox_file_data_remaining(m, friendnum, filenum, 0);
|
||||||
|
|
||||||
/* must be called once per second */
|
/* must be called once per second */
|
||||||
@ -173,11 +175,11 @@ void reset_file_sender_queue(void)
|
|||||||
|
|
||||||
/* set CTRL to -1 if we don't want to send a control signal.
|
/* set CTRL to -1 if we don't want to send a control signal.
|
||||||
set msg to NULL if we don't want to display a message */
|
set msg to NULL if we don't want to display a message */
|
||||||
void close_file_sender(ToxWindow *self, Tox *m, int i, const char *msg, int CTRL, int filenum, int32_t friendnum)
|
void close_file_sender(ToxWindow *self, Tox *m, int i, const char *msg, int CTRL, int filenum, uint32_t friendnum)
|
||||||
{
|
{
|
||||||
if (msg != NULL)
|
if (msg != NULL)
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", msg);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", msg);
|
||||||
|
|
||||||
if (CTRL > 0)
|
if (CTRL > 0)
|
||||||
tox_file_send_control(m, friendnum, 0, filenum, CTRL, 0, 0);
|
tox_file_send_control(m, friendnum, 0, filenum, CTRL, 0, 0);
|
||||||
|
|
||||||
@ -190,7 +192,7 @@ void close_file_sender(ToxWindow *self, Tox *m, int i, const char *msg, int CTRL
|
|||||||
|
|
||||||
void close_all_file_senders(Tox *m)
|
void close_all_file_senders(Tox *m)
|
||||||
{
|
{
|
||||||
int i;
|
uint8_t i;
|
||||||
|
|
||||||
for (i = 0; i < max_file_senders_index; ++i) {
|
for (i = 0; i < max_file_senders_index; ++i) {
|
||||||
if (file_senders[i].active) {
|
if (file_senders[i].active) {
|
||||||
@ -204,17 +206,21 @@ void close_all_file_senders(Tox *m)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void send_file_data(ToxWindow *self, Tox *m, int i, int32_t friendnum, int filenum, const char *filename)
|
static void send_file_data(ToxWindow *self, Tox *m, uint8_t i, uint32_t friendnum, uint32_t filenum,
|
||||||
|
const char *filename)
|
||||||
{
|
{
|
||||||
FILE *fp = file_senders[i].file;
|
FILE *fp = file_senders[i].file;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (tox_file_send_data(m, friendnum, filenum, (uint8_t *) file_senders[i].nextpiece,
|
TOX_ERR_FILE_SEND_CHUNK err;
|
||||||
file_senders[i].piecelen) == -1)
|
if (!tox_file_send_chunk(m, friendnum, filenum, (uint8_t *) file_senders[i].nextpiece,
|
||||||
|
file_senders[i].piecelen, &err) {
|
||||||
|
fprintf(stderr, "tox_file_send_chunk failed with error %d\n", err);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
file_senders[i].timestamp = get_unix_time();
|
file_senders[i].timestamp = get_unix_time();
|
||||||
file_senders[i].bps += file_senders[i].piecelen;
|
file_senders[i].bps += file_senders[i].piecelen;
|
||||||
file_senders[i].piecelen = fread(file_senders[i].nextpiece, 1,
|
file_senders[i].piecelen = fread(file_senders[i].nextpiece, 1,
|
||||||
tox_file_data_size(m, friendnum), fp);
|
tox_file_data_size(m, friendnum), fp);
|
||||||
|
|
||||||
@ -257,7 +263,7 @@ void do_file_senders(Tox *m)
|
|||||||
ToxWindow *self = file_senders[i].toxwin;
|
ToxWindow *self = file_senders[i].toxwin;
|
||||||
char *filename = file_senders[i].filename;
|
char *filename = file_senders[i].filename;
|
||||||
int filenum = file_senders[i].filenum;
|
int filenum = file_senders[i].filenum;
|
||||||
int32_t friendnum = file_senders[i].friendnum;
|
uint32_t friendnum = file_senders[i].friendnum;
|
||||||
|
|
||||||
/* kill file transfer if chatwindow is closed */
|
/* kill file transfer if chatwindow is closed */
|
||||||
if (self->chatwin == NULL) {
|
if (self->chatwin == NULL) {
|
||||||
@ -266,12 +272,12 @@ void do_file_senders(Tox *m)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* If file transfer has timed out kill transfer and send kill control */
|
/* If file transfer has timed out kill transfer and send kill control */
|
||||||
if (timed_out(file_senders[i].timestamp, get_unix_time(), TIMEOUT_FILESENDER)) {
|
if (timed_out(file_senders[i].timestamp, get_unix_time(), TIMEOUT_FILESENDER)
|
||||||
|
&& (!file_senders[i].paused || (file_senders[i].paused && file_senders[i].noconnection))) {
|
||||||
char msg[MAX_STR_SIZE];
|
char msg[MAX_STR_SIZE];
|
||||||
snprintf(msg, sizeof(msg), "File transfer for '%s' timed out.", filename);
|
snprintf(msg, sizeof(msg), "File transfer for '%s' timed out.", filename);
|
||||||
close_file_sender(self, m, i, msg, TOX_FILECONTROL_KILL, filenum, friendnum);
|
close_file_sender(self, m, i, msg, TOX_FILECONTROL_KILL, filenum, friendnum);
|
||||||
sound_notify(self, error, NT_NOFOCUS | NT_WNDALERT_2, NULL);
|
|
||||||
|
|
||||||
if (self->active_box != -1)
|
if (self->active_box != -1)
|
||||||
box_notify2(self, error, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", msg);
|
box_notify2(self, error, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", msg);
|
||||||
else
|
else
|
||||||
@ -280,7 +286,7 @@ void do_file_senders(Tox *m)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!file_senders[i].noconnection && !file_senders[i].finished)
|
if ( !(file_senders[i].paused | file_senders[i].noconnection | file_senders[i].finished) )
|
||||||
send_file_data(self, m, i, friendnum, filenum, filename);
|
send_file_data(self, m, i, friendnum, filenum, filename);
|
||||||
|
|
||||||
file_senders[i].queue_pos = num_active_file_senders - 1;
|
file_senders[i].queue_pos = num_active_file_senders - 1;
|
||||||
|
@ -33,21 +33,22 @@
|
|||||||
#define FILE_PIECE_SIZE 2048 /* must be >= (MAX_CRYPTO_DATA_SIZE - 2) in toxcore/net_crypto.h */
|
#define FILE_PIECE_SIZE 2048 /* must be >= (MAX_CRYPTO_DATA_SIZE - 2) in toxcore/net_crypto.h */
|
||||||
#define MAX_FILES 32
|
#define MAX_FILES 32
|
||||||
#define TIMEOUT_FILESENDER 120
|
#define TIMEOUT_FILESENDER 120
|
||||||
#define NUM_PROG_MARKS 50 /* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FILE *file;
|
FILE *file;
|
||||||
ToxWindow *toxwin;
|
ToxWindow *toxwin;
|
||||||
int32_t friendnum;
|
uint32_t friendnum;
|
||||||
bool active;
|
bool active;
|
||||||
bool noconnection;
|
bool noconnection; /* set when the connection has been interrupted */
|
||||||
bool finished;
|
bool paused; /* set when transfer has been explicitly paused */
|
||||||
|
bool finished; /* set after entire file has been sent but no TOX_FILECONTROL_FINISHED receieved */
|
||||||
|
bool started; /* set after TOX_FILECONTROL_ACCEPT received */
|
||||||
int filenum;
|
int filenum;
|
||||||
char nextpiece[FILE_PIECE_SIZE];
|
char nextpiece[FILE_PIECE_SIZE];
|
||||||
uint16_t piecelen;
|
size_t piecelen;
|
||||||
char filename[MAX_STR_SIZE];
|
char filename[MAX_STR_SIZE];
|
||||||
uint64_t timestamp;
|
uint64_t timestamp; /* marks the last time data was successfully transfered */
|
||||||
uint64_t last_progress;
|
uint64_t last_progress; /* marks the last time the progress bar was refreshed */
|
||||||
double bps;
|
double bps;
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
uint32_t line_id;
|
uint32_t line_id;
|
||||||
@ -58,7 +59,7 @@ typedef struct {
|
|||||||
Assumes progline is of size MAX_STR_SIZE */
|
Assumes progline is of size MAX_STR_SIZE */
|
||||||
void prep_prog_line(char *progline);
|
void prep_prog_line(char *progline);
|
||||||
|
|
||||||
/* prints a progress bar for file transfers.
|
/* prints a progress bar for file transfers.
|
||||||
if friendnum is -1 we're sending the file, otherwise we're receiving. */
|
if friendnum is -1 we're sending the file, otherwise we're receiving. */
|
||||||
void print_progress_bar(ToxWindow *self, int idx, int friendnum, double pct_remain);
|
void print_progress_bar(ToxWindow *self, int idx, int friendnum, double pct_remain);
|
||||||
|
|
||||||
|
194
src/file_transfers.c
Normal file
194
src/file_transfers.c
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
/* file_transfers.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 <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
#include "friendlist.h"
|
||||||
|
#include "file_transfers.h"
|
||||||
|
#include "line_info.h"
|
||||||
|
#include "misc_tools.h"
|
||||||
|
#include "notify.h"
|
||||||
|
|
||||||
|
extern FriendsList Friends;
|
||||||
|
|
||||||
|
#define NUM_PROG_MARKS 50 /* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */
|
||||||
|
|
||||||
|
/* creates initial progress line that will be updated during file transfer.
|
||||||
|
Assumes progline is of size MAX_STR_SIZE */
|
||||||
|
void prep_prog_line(char *progline)
|
||||||
|
{
|
||||||
|
strcpy(progline, "0.0 B/s [");
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_PROG_MARKS; ++i)
|
||||||
|
strcat(progline, "-");
|
||||||
|
|
||||||
|
strcat(progline, "] 0%");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* prints a progress bar for file transfers.
|
||||||
|
if friendnum is -1 we're sending the file, otherwise we're receiving. */
|
||||||
|
void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t line_id)
|
||||||
|
{
|
||||||
|
char msg[MAX_STR_SIZE];
|
||||||
|
bytes_convert_str(msg, sizeof(msg), bps);
|
||||||
|
strcat(msg, "/s [");
|
||||||
|
|
||||||
|
int n = pct_done / (100 / NUM_PROG_MARKS);
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < n; ++i)
|
||||||
|
strcat(msg, "#");
|
||||||
|
|
||||||
|
for (j = i; j < NUM_PROG_MARKS; ++j)
|
||||||
|
strcat(msg, "-");
|
||||||
|
|
||||||
|
strcat(msg, "] ");
|
||||||
|
|
||||||
|
char pctstr[16];
|
||||||
|
const char *frmt = pct_done == 100 ? "%.f%%" : "%.1f%%";
|
||||||
|
snprintf(pctstr, sizeof(pctstr), frmt, pct_done);
|
||||||
|
strcat(msg, pctstr);
|
||||||
|
|
||||||
|
line_info_set(self, line_id, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Filenumbers >= this number are receiving, otherwise sending.
|
||||||
|
* Warning: This behaviour is not defined by the Tox API and is subject to change at any time.
|
||||||
|
*/
|
||||||
|
#define FILE_NUMBER_MAGIC_NUM (1 << 16)
|
||||||
|
|
||||||
|
/* Returns filenum's file transfer array index */
|
||||||
|
uint32_t get_file_transfer_index(uint32_t filenum)
|
||||||
|
{
|
||||||
|
return filenum >= FILE_NUMBER_MAGIC_NUM ? (filenum >> 16) - 1 : filenum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the filenumber of a file receiver's index */
|
||||||
|
uint32_t get_file_receiver_filenum(uint32_t idx)
|
||||||
|
{
|
||||||
|
return (idx + 1) << 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if filenum is associated with a file receiver, false if file sender */
|
||||||
|
bool filenum_is_sending(uint32_t filenum)
|
||||||
|
{
|
||||||
|
return filenum < FILE_NUMBER_MAGIC_NUM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* refreshes active file receiver status bars for friendnum */
|
||||||
|
void refresh_file_transfer_progress(ToxWindow *self, Tox *m, uint32_t friendnum)
|
||||||
|
{
|
||||||
|
uint64_t curtime = get_unix_time();
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_FILES; ++i) {
|
||||||
|
if (Friends.list[friendnum].file_receiver[i].active) {
|
||||||
|
if (timed_out(Friends.list[friendnum].file_receiver[i].last_progress, curtime, 1)) {
|
||||||
|
uint64_t size = Friends.list[friendnum].file_receiver[i].file_size;
|
||||||
|
double remain = size - Friends.list[friendnum].file_receiver[i].position;
|
||||||
|
double pct_done = remain > 0 ? (1 - (remain / size)) * 100 : 100;
|
||||||
|
|
||||||
|
print_progress_bar(self, Friends.list[friendnum].file_receiver[i].bps, pct_done,
|
||||||
|
Friends.list[friendnum].file_receiver[i].line_id);
|
||||||
|
|
||||||
|
Friends.list[friendnum].file_receiver[i].bps = 0;
|
||||||
|
Friends.list[friendnum].file_receiver[i].last_progress = curtime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Friends.list[friendnum].file_sender[i].active) {
|
||||||
|
if (timed_out(Friends.list[friendnum].file_sender[i].last_progress, curtime, 1)) {
|
||||||
|
uint64_t size = Friends.list[friendnum].file_sender[i].file_size;
|
||||||
|
double remain = size - Friends.list[friendnum].file_sender[i].position;
|
||||||
|
double pct_done = remain > 0 ? (1 - (remain / size)) * 100 : 100;
|
||||||
|
|
||||||
|
print_progress_bar(self, Friends.list[friendnum].file_sender[i].bps, pct_done,
|
||||||
|
Friends.list[friendnum].file_sender[i].line_id);
|
||||||
|
|
||||||
|
Friends.list[friendnum].file_sender[i].bps = 0;
|
||||||
|
Friends.list[friendnum].file_sender[i].last_progress = curtime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Closes file transfer with filenum.
|
||||||
|
* Set CTRL to -1 if we don't want to send a control signal.
|
||||||
|
* Set message or self to NULL if we don't want to display a message.
|
||||||
|
*/
|
||||||
|
void close_file_transfer(ToxWindow *self, Tox *m, uint32_t filenum, uint32_t friendnum, int CTRL,
|
||||||
|
const char *message, Notification sound_type)
|
||||||
|
{
|
||||||
|
uint32_t idx = get_file_transfer_index(filenum);
|
||||||
|
bool sending = filenum_is_sending(filenum);
|
||||||
|
|
||||||
|
if (sending && Friends.list[friendnum].file_sender[idx].active) {
|
||||||
|
FILE *fp = Friends.list[friendnum].file_sender[idx].file;
|
||||||
|
|
||||||
|
if (fp)
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
memset(&Friends.list[friendnum].file_sender[idx], 0, sizeof(struct FileSender));
|
||||||
|
}
|
||||||
|
else if (!sending && Friends.list[friendnum].file_receiver[idx].active) {
|
||||||
|
FILE *fp = Friends.list[friendnum].file_receiver[idx].file;
|
||||||
|
|
||||||
|
if (fp)
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
memset(&Friends.list[friendnum].file_receiver[idx], 0, sizeof(struct FileReceiver));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (CTRL >= 0)
|
||||||
|
tox_file_control(m, friendnum, filenum, CTRL, NULL);
|
||||||
|
|
||||||
|
if (message && self) {
|
||||||
|
if (self->active_box != -1)
|
||||||
|
box_notify2(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", message);
|
||||||
|
else
|
||||||
|
box_notify(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", message);
|
||||||
|
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Kills all active file transfers for friendnum */
|
||||||
|
void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_FILES; ++i) {
|
||||||
|
fprintf(stderr, "%lu\n", i);
|
||||||
|
if (Friends.list[friendnum].file_sender[i].active)
|
||||||
|
close_file_transfer(NULL, m, i, friendnum, -1, NULL, silent);
|
||||||
|
if (Friends.list[friendnum].file_receiver[i].active)
|
||||||
|
close_file_transfer(NULL, m, get_file_receiver_filenum(i), friendnum, -1, NULL, silent);
|
||||||
|
}
|
||||||
|
}
|
96
src/file_transfers.h
Normal file
96
src/file_transfers.h
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/* file_transfers.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 FILE_TRANSFERS_H
|
||||||
|
#define FILE_TRANSFERS_H
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
#include "notify.h"
|
||||||
|
|
||||||
|
#define KiB 1024
|
||||||
|
#define MiB 1048576 /* 1024 ^ 2 */
|
||||||
|
#define GiB 1073741824 /* 1024 ^ 3 */
|
||||||
|
|
||||||
|
#define FILE_PIECE_SIZE 2048
|
||||||
|
#define MAX_FILES 32
|
||||||
|
#define TIMEOUT_FILESENDER 120
|
||||||
|
|
||||||
|
struct FileSender {
|
||||||
|
FILE *file;
|
||||||
|
char file_name[TOX_MAX_FILENAME_LENGTH];
|
||||||
|
bool active;
|
||||||
|
bool noconnection; /* set when the connection has been interrupted */
|
||||||
|
bool paused; /* set when transfer has been explicitly paused */
|
||||||
|
bool started; /* set after TOX_FILECONTROL_ACCEPT received */
|
||||||
|
uint64_t timestamp; /* marks the last time data was successfully transfered */
|
||||||
|
double bps;
|
||||||
|
uint64_t file_size;
|
||||||
|
uint64_t last_progress; /* marks the last time the progress bar was refreshed */
|
||||||
|
uint64_t position;
|
||||||
|
uint32_t line_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FileReceiver {
|
||||||
|
FILE *file;
|
||||||
|
char file_path[PATH_MAX + 1];
|
||||||
|
bool pending;
|
||||||
|
bool active;
|
||||||
|
double bps;
|
||||||
|
uint64_t file_size;
|
||||||
|
uint64_t last_progress;
|
||||||
|
uint64_t position;
|
||||||
|
uint32_t line_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* creates initial progress line that will be updated during file transfer.
|
||||||
|
progline must be at lesat MAX_STR_SIZE bytes */
|
||||||
|
void prep_prog_line(char *progline);
|
||||||
|
|
||||||
|
/* prints a progress bar for file transfers */
|
||||||
|
void print_progress_bar(ToxWindow *self, double pct_done, double bps, uint32_t line_id);
|
||||||
|
|
||||||
|
/* refreshes active file receiver status bars for friendnum */
|
||||||
|
void refresh_file_transfer_progress(ToxWindow *self, Tox *m, uint32_t friendnum);
|
||||||
|
|
||||||
|
/* Returns filenum's file transfer array index */
|
||||||
|
uint32_t get_file_transfer_index(uint32_t filenum);
|
||||||
|
|
||||||
|
/* Returns the filenumber of a file receiver's index */
|
||||||
|
uint32_t get_file_receiver_filenum(uint32_t idx);
|
||||||
|
|
||||||
|
/* Return true if filenum is associated with a file receiver, false if file sender */
|
||||||
|
bool filenum_is_sending(uint32_t filenum);
|
||||||
|
|
||||||
|
/* Closes file transfer with filenum.
|
||||||
|
* Set CTRL to -1 if we don't want to send a control signal.
|
||||||
|
* Set message or self to NULL if we don't want to display a message.
|
||||||
|
*/
|
||||||
|
void close_file_transfer(ToxWindow *self, Tox *m, uint32_t filenum, uint32_t friendnum, int CTRL,
|
||||||
|
const char *message, Notification sound_type);
|
||||||
|
|
||||||
|
/* Kills all active file transfers for friendnum */
|
||||||
|
void kill_all_file_transfers_friend(Tox *m, uint32_t friendnum);
|
||||||
|
|
||||||
|
#endif /* #define FILE_TRANSFERS_H */
|
422
src/friendlist.c
422
src/friendlist.c
@ -59,16 +59,15 @@ static struct Blocked {
|
|||||||
int num_selected;
|
int num_selected;
|
||||||
int max_idx;
|
int max_idx;
|
||||||
int num_blocked;
|
int num_blocked;
|
||||||
|
uint32_t *index;
|
||||||
int *index;
|
|
||||||
BlockedFriend *list;
|
BlockedFriend *list;
|
||||||
} Blocked;
|
} Blocked;
|
||||||
|
|
||||||
static struct pendingDel {
|
static struct PendingDel {
|
||||||
int num;
|
uint32_t num;
|
||||||
bool active;
|
bool active;
|
||||||
WINDOW *popup;
|
WINDOW *popup;
|
||||||
} pendingdelete;
|
} PendingDelete;
|
||||||
|
|
||||||
static void realloc_friends(int n)
|
static void realloc_friends(int n)
|
||||||
{
|
{
|
||||||
@ -81,7 +80,7 @@ static void realloc_friends(int n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ToxicFriend *f = realloc(Friends.list, n * sizeof(ToxicFriend));
|
ToxicFriend *f = realloc(Friends.list, n * sizeof(ToxicFriend));
|
||||||
int *f_idx = realloc(Friends.index, n * sizeof(int));
|
uint32_t *f_idx = realloc(Friends.index, n * sizeof(uint32_t));
|
||||||
|
|
||||||
if (f == NULL || f_idx == NULL)
|
if (f == NULL || f_idx == NULL)
|
||||||
exit_toxic_err("failed in realloc_friends", FATALERR_MEMORY);
|
exit_toxic_err("failed in realloc_friends", FATALERR_MEMORY);
|
||||||
@ -101,7 +100,7 @@ static void realloc_blocklist(int n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
BlockedFriend *b = realloc(Blocked.list, n * sizeof(BlockedFriend));
|
BlockedFriend *b = realloc(Blocked.list, n * sizeof(BlockedFriend));
|
||||||
int *b_idx = realloc(Blocked.index, n * sizeof(int));
|
uint32_t *b_idx = realloc(Blocked.index, n * sizeof(uint32_t));
|
||||||
|
|
||||||
if (b == NULL || b_idx == NULL)
|
if (b == NULL || b_idx == NULL)
|
||||||
exit_toxic_err("failed in realloc_blocklist", FATALERR_MEMORY);
|
exit_toxic_err("failed in realloc_blocklist", FATALERR_MEMORY);
|
||||||
@ -125,9 +124,6 @@ void kill_friendlist(void)
|
|||||||
|
|
||||||
static int save_blocklist(char *path)
|
static int save_blocklist(char *path)
|
||||||
{
|
{
|
||||||
if (arg_opts.ignore_data_file)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (path == NULL)
|
if (path == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -138,7 +134,7 @@ static int save_blocklist(char *path)
|
|||||||
exit_toxic_err("Failed in save_blocklist", FATALERR_MEMORY);
|
exit_toxic_err("Failed in save_blocklist", FATALERR_MEMORY);
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
int ret = -1;
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
for (i = 0; i < Blocked.max_idx; ++i) {
|
for (i = 0; i < Blocked.max_idx; ++i) {
|
||||||
@ -150,7 +146,7 @@ static int save_blocklist(char *path)
|
|||||||
memset(&tmp, 0, sizeof(BlockedFriend));
|
memset(&tmp, 0, sizeof(BlockedFriend));
|
||||||
tmp.namelength = htons(Blocked.list[i].namelength);
|
tmp.namelength = htons(Blocked.list[i].namelength);
|
||||||
memcpy(tmp.name, Blocked.list[i].name, Blocked.list[i].namelength + 1);
|
memcpy(tmp.name, Blocked.list[i].name, Blocked.list[i].namelength + 1);
|
||||||
memcpy(tmp.pub_key, Blocked.list[i].pub_key, TOX_CLIENT_ID_SIZE);
|
memcpy(tmp.pub_key, Blocked.list[i].pub_key, TOX_PUBLIC_KEY_SIZE);
|
||||||
|
|
||||||
uint8_t lastonline[sizeof(uint64_t)];
|
uint8_t lastonline[sizeof(uint64_t)];
|
||||||
memcpy(lastonline, &Blocked.list[i].last_on, sizeof(uint64_t));
|
memcpy(lastonline, &Blocked.list[i].last_on, sizeof(uint64_t));
|
||||||
@ -167,15 +163,16 @@ static int save_blocklist(char *path)
|
|||||||
if (fp == NULL)
|
if (fp == NULL)
|
||||||
goto on_error;
|
goto on_error;
|
||||||
|
|
||||||
if (fwrite(data, len, 1, fp) == 1)
|
if (fwrite(data, len, 1, fp) != 1)
|
||||||
ret = 0;
|
goto on_error;
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return ret;
|
free(data);
|
||||||
|
return 0;
|
||||||
|
|
||||||
on_error:
|
on_error:
|
||||||
free(data);
|
free(data);
|
||||||
return ret;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sort_blocklist_index(void);
|
static void sort_blocklist_index(void);
|
||||||
@ -192,14 +189,14 @@ int load_blocklist(char *path)
|
|||||||
|
|
||||||
off_t len = file_size(path);
|
off_t len = file_size(path);
|
||||||
|
|
||||||
if (len == -1) {
|
if (len == 0) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *data = malloc(len);
|
char *data = malloc(len);
|
||||||
|
|
||||||
if (data == NULL) {
|
if (data == NULL) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
exit_toxic_err("Failed in load_blocklist", FATALERR_MEMORY);
|
exit_toxic_err("Failed in load_blocklist", FATALERR_MEMORY);
|
||||||
}
|
}
|
||||||
@ -231,7 +228,7 @@ int load_blocklist(char *path)
|
|||||||
Blocked.list[i].num = i;
|
Blocked.list[i].num = i;
|
||||||
Blocked.list[i].namelength = ntohs(tmp.namelength);
|
Blocked.list[i].namelength = ntohs(tmp.namelength);
|
||||||
memcpy(Blocked.list[i].name, tmp.name, Blocked.list[i].namelength + 1);
|
memcpy(Blocked.list[i].name, tmp.name, Blocked.list[i].namelength + 1);
|
||||||
memcpy(Blocked.list[i].pub_key, tmp.pub_key, TOX_CLIENT_ID_SIZE);
|
memcpy(Blocked.list[i].pub_key, tmp.pub_key, TOX_PUBLIC_KEY_SIZE);
|
||||||
|
|
||||||
uint8_t lastonline[sizeof(uint64_t)];
|
uint8_t lastonline[sizeof(uint64_t)];
|
||||||
memcpy(lastonline, &tmp.last_on, sizeof(uint64_t));
|
memcpy(lastonline, &tmp.last_on, sizeof(uint64_t));
|
||||||
@ -254,8 +251,8 @@ static int index_name_cmp(const void *n1, const void *n2)
|
|||||||
int res = qsort_strcasecmp_hlpr(Friends.list[*(int *) n1].name, Friends.list[*(int *) n2].name);
|
int res = qsort_strcasecmp_hlpr(Friends.list[*(int *) n1].name, Friends.list[*(int *) n2].name);
|
||||||
|
|
||||||
/* Use weight to make qsort always put online friends before offline */
|
/* Use weight to make qsort always put online friends before offline */
|
||||||
res = Friends.list[*(int *) n1].online ? (res - S_WEIGHT) : (res + S_WEIGHT);
|
res = Friends.list[*(int *) n1].connection_status ? (res - S_WEIGHT) : (res + S_WEIGHT);
|
||||||
res = Friends.list[*(int *) n2].online ? (res + S_WEIGHT) : (res - S_WEIGHT);
|
res = Friends.list[*(int *) n2].connection_status ? (res + S_WEIGHT) : (res - S_WEIGHT);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -263,15 +260,15 @@ static int index_name_cmp(const void *n1, const void *n2)
|
|||||||
/* sorts Friends.index first by connection status then alphabetically */
|
/* sorts Friends.index first by connection status then alphabetically */
|
||||||
void sort_friendlist_index(void)
|
void sort_friendlist_index(void)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
int n = 0;
|
uint32_t n = 0;
|
||||||
|
|
||||||
for (i = 0; i < Friends.max_idx; ++i) {
|
for (i = 0; i < Friends.max_idx; ++i) {
|
||||||
if (Friends.list[i].active)
|
if (Friends.list[i].active)
|
||||||
Friends.index[n++] = Friends.list[i].num;
|
Friends.index[n++] = Friends.list[i].num;
|
||||||
}
|
}
|
||||||
|
|
||||||
qsort(Friends.index, Friends.num_friends, sizeof(int), index_name_cmp);
|
qsort(Friends.index, Friends.num_friends, sizeof(uint32_t), index_name_cmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int index_name_cmp_block(const void *n1, const void *n2)
|
static int index_name_cmp_block(const void *n1, const void *n2)
|
||||||
@ -281,85 +278,87 @@ static int index_name_cmp_block(const void *n1, const void *n2)
|
|||||||
|
|
||||||
static void sort_blocklist_index(void)
|
static void sort_blocklist_index(void)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
int n = 0;
|
uint32_t n = 0;
|
||||||
|
|
||||||
for (i = 0; i < Blocked.max_idx; ++i) {
|
for (i = 0; i < Blocked.max_idx; ++i) {
|
||||||
if (Blocked.list[i].active)
|
if (Blocked.list[i].active)
|
||||||
Blocked.index[n++] = Blocked.list[i].num;
|
Blocked.index[n++] = Blocked.list[i].num;
|
||||||
}
|
}
|
||||||
|
|
||||||
qsort(Blocked.index, Blocked.num_blocked, sizeof(int), index_name_cmp_block);
|
qsort(Blocked.index, Blocked.num_blocked, sizeof(uint32_t), index_name_cmp_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_friend_last_online(int32_t num, uint64_t timestamp)
|
static void update_friend_last_online(uint32_t num, uint64_t timestamp)
|
||||||
{
|
{
|
||||||
Friends.list[num].last_online.last_on = timestamp;
|
Friends.list[num].last_online.last_on = timestamp;
|
||||||
Friends.list[num].last_online.tm = *localtime((const time_t*)×tamp);
|
Friends.list[num].last_online.tm = *localtime((const time_t*)×tamp);
|
||||||
|
|
||||||
/* if the format changes make sure TIME_STR_SIZE is the correct size */
|
/* if the format changes make sure TIME_STR_SIZE is the correct size */
|
||||||
const char *t = user_settings->time == TIME_12 ? "%I:%M %p" : "%H:%M";
|
const char *t = user_settings->timestamp_format;
|
||||||
strftime(Friends.list[num].last_online.hour_min_str, TIME_STR_SIZE, t,
|
strftime(Friends.list[num].last_online.hour_min_str, TIME_STR_SIZE, t,
|
||||||
&Friends.list[num].last_online.tm);
|
&Friends.list[num].last_online.tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void friendlist_onMessage(ToxWindow *self, Tox *m, int32_t num, const char *str, uint16_t len)
|
static void friendlist_onMessage(ToxWindow *self, Tox *m, uint32_t num, TOX_MESSAGE_TYPE type, const char *str,
|
||||||
|
size_t length)
|
||||||
{
|
{
|
||||||
if (num >= Friends.max_idx)
|
if (num >= Friends.max_idx)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Friends.list[num].chatwin == -1) {
|
if (Friends.list[num].chatwin != -1)
|
||||||
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
return;
|
||||||
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
|
|
||||||
} else {
|
|
||||||
char nick[TOX_MAX_NAME_LENGTH];
|
|
||||||
get_nick_truncate(m, nick, num);
|
|
||||||
|
|
||||||
char timefrmt[TIME_STR_SIZE];
|
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
|
||||||
|
return;
|
||||||
line_info_add(prompt, timefrmt, nick, NULL, IN_MSG, 0, 0, "%s", str);
|
|
||||||
|
|
||||||
const char *msg = "* Warning: Too many windows are open.";
|
|
||||||
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, msg);
|
|
||||||
sound_notify(prompt, error, NT_WNDALERT_1, NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char nick[TOX_MAX_NAME_LENGTH];
|
||||||
|
get_nick_truncate(m, nick, num);
|
||||||
|
|
||||||
|
char timefrmt[TIME_STR_SIZE];
|
||||||
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
|
|
||||||
|
line_info_add(prompt, timefrmt, nick, NULL, IN_MSG, 0, 0, "%s", str);
|
||||||
|
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, "* Warning: Too many windows are open.");
|
||||||
|
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, int32_t num, uint8_t status)
|
static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_CONNECTION connection_status)
|
||||||
{
|
{
|
||||||
if (num >= Friends.max_idx)
|
if (num >= Friends.max_idx)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Friends.list[num].online = status;
|
if (connection_status == TOX_CONNECTION_NONE)
|
||||||
|
--Friends.num_online;
|
||||||
|
else
|
||||||
|
++Friends.num_online;
|
||||||
|
|
||||||
|
Friends.list[num].connection_status = connection_status;
|
||||||
update_friend_last_online(num, get_unix_time());
|
update_friend_last_online(num, get_unix_time());
|
||||||
store_data(m, DATA_FILE);
|
store_data(m, DATA_FILE);
|
||||||
sort_friendlist_index();
|
sort_friendlist_index();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void friendlist_onNickChange(ToxWindow *self, Tox *m, int32_t num, const char *nick, uint16_t len)
|
static void friendlist_onNickChange(ToxWindow *self, Tox *m, uint32_t num, const char *nick, size_t length)
|
||||||
{
|
{
|
||||||
if (len > TOX_MAX_NAME_LENGTH || num >= Friends.max_idx)
|
if (num >= Friends.max_idx)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* save old name for log renaming */
|
/* save old name for log renaming */
|
||||||
char oldname[TOXIC_MAX_NAME_LENGTH];
|
char oldname[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
snprintf(oldname, sizeof(oldname), "%s", Friends.list[num].name);
|
snprintf(oldname, sizeof(oldname), "%s", Friends.list[num].name);
|
||||||
|
|
||||||
/* update name */
|
/* update name */
|
||||||
char tempname[TOX_MAX_NAME_LENGTH];
|
snprintf(Friends.list[num].name, sizeof(Friends.list[num].name), "%s", nick);
|
||||||
strcpy(tempname, nick);
|
Friends.list[num].namelength = strlen(Friends.list[num].name);
|
||||||
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
|
|
||||||
tempname[len] = '\0';
|
|
||||||
snprintf(Friends.list[num].name, sizeof(Friends.list[num].name), "%s", tempname);
|
|
||||||
Friends.list[num].namelength = len;
|
|
||||||
|
|
||||||
/* get data for chatlog renaming */
|
/* get data for chatlog renaming */
|
||||||
char newnamecpy[TOXIC_MAX_NAME_LENGTH];
|
char newnamecpy[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
char myid[TOX_FRIEND_ADDRESS_SIZE];
|
char myid[TOX_ADDRESS_SIZE];
|
||||||
strcpy(newnamecpy, tempname);
|
strcpy(newnamecpy, Friends.list[num].name);
|
||||||
tox_get_address(m, (uint8_t *) myid);
|
tox_self_get_address(m, (uint8_t *) myid);
|
||||||
|
|
||||||
if (strcmp(oldname, newnamecpy) != 0)
|
if (strcmp(oldname, newnamecpy) != 0)
|
||||||
rename_logfile(oldname, newnamecpy, myid, Friends.list[num].pub_key, Friends.list[num].chatwin);
|
rename_logfile(oldname, newnamecpy, myid, Friends.list[num].pub_key, Friends.list[num].chatwin);
|
||||||
@ -367,7 +366,7 @@ static void friendlist_onNickChange(ToxWindow *self, Tox *m, int32_t num, const
|
|||||||
sort_friendlist_index();
|
sort_friendlist_index();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void friendlist_onStatusChange(ToxWindow *self, Tox *m, int32_t num, uint8_t status)
|
static void friendlist_onStatusChange(ToxWindow *self, Tox *m, uint32_t num, TOX_USER_STATUS status)
|
||||||
{
|
{
|
||||||
if (num >= Friends.max_idx)
|
if (num >= Friends.max_idx)
|
||||||
return;
|
return;
|
||||||
@ -375,50 +374,47 @@ static void friendlist_onStatusChange(ToxWindow *self, Tox *m, int32_t num, uint
|
|||||||
Friends.list[num].status = status;
|
Friends.list[num].status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void friendlist_onStatusMessageChange(ToxWindow *self, int32_t num, const char *status, uint16_t len)
|
static void friendlist_onStatusMessageChange(ToxWindow *self, uint32_t num, const char *note, size_t length)
|
||||||
{
|
{
|
||||||
if (len > TOX_MAX_STATUSMESSAGE_LENGTH || num >= Friends.max_idx)
|
if (length > TOX_MAX_STATUS_MESSAGE_LENGTH || num >= Friends.max_idx)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
snprintf(Friends.list[num].statusmsg, sizeof(Friends.list[num].statusmsg), "%s", status);
|
snprintf(Friends.list[num].statusmsg, sizeof(Friends.list[num].statusmsg), "%s", note);
|
||||||
Friends.list[num].statusmsg_len = strlen(Friends.list[num].statusmsg);
|
Friends.list[num].statusmsg_len = strlen(Friends.list[num].statusmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_t num, bool sort)
|
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort)
|
||||||
{
|
{
|
||||||
if (Friends.max_idx < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
|
|
||||||
Friends.num_friends = tox_count_friendlist(m);
|
|
||||||
realloc_friends(Friends.max_idx + 1);
|
realloc_friends(Friends.max_idx + 1);
|
||||||
memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend));
|
memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend));
|
||||||
|
|
||||||
int i;
|
uint32_t i;
|
||||||
|
|
||||||
for (i = 0; i <= Friends.max_idx; ++i) {
|
for (i = 0; i <= Friends.max_idx; ++i) {
|
||||||
if (Friends.list[i].active)
|
if (Friends.list[i].active)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
++Friends.num_friends;
|
||||||
|
|
||||||
Friends.list[i].num = num;
|
Friends.list[i].num = num;
|
||||||
Friends.list[i].active = true;
|
Friends.list[i].active = true;
|
||||||
Friends.list[i].chatwin = -1;
|
Friends.list[i].chatwin = -1;
|
||||||
Friends.list[i].online = false;
|
Friends.list[i].connection_status = TOX_CONNECTION_NONE;
|
||||||
Friends.list[i].status = TOX_USERSTATUS_NONE;
|
Friends.list[i].status = TOX_USER_STATUS_NONE;
|
||||||
Friends.list[i].logging_on = (bool) user_settings->autolog == AUTOLOG_ON;
|
Friends.list[i].logging_on = (bool) user_settings->autolog == AUTOLOG_ON;
|
||||||
tox_get_client_id(m, num, (uint8_t *) Friends.list[i].pub_key);
|
|
||||||
update_friend_last_online(i, tox_get_last_online(m, i));
|
TOX_ERR_FRIEND_GET_PUBLIC_KEY err;
|
||||||
|
tox_friend_get_public_key(m, num, (uint8_t *) Friends.list[i].pub_key, &err);
|
||||||
|
|
||||||
|
if (err != TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK)
|
||||||
|
fprintf(stderr, "tox_friend_get_public_key failed (error %d)\n", err);
|
||||||
|
|
||||||
|
// update_friend_last_online(i, 0);
|
||||||
|
|
||||||
char tempname[TOX_MAX_NAME_LENGTH] = {0};
|
char tempname[TOX_MAX_NAME_LENGTH] = {0};
|
||||||
int len = get_nick_truncate(m, tempname, num);
|
get_nick_truncate(m, tempname, num);
|
||||||
|
snprintf(Friends.list[i].name, sizeof(Friends.list[i].name), "%s", tempname);
|
||||||
if (len == -1 || tempname[0] == '\0') {
|
Friends.list[i].namelength = strlen(Friends.list[i].name);
|
||||||
strcpy(Friends.list[i].name, UNKNOWN_NAME);
|
|
||||||
Friends.list[i].namelength = strlen(UNKNOWN_NAME);
|
|
||||||
} else { /* Enforce toxic's maximum name length */
|
|
||||||
Friends.list[i].namelength = len;
|
|
||||||
snprintf(Friends.list[i].name, sizeof(Friends.list[i].name), "%s", tempname);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == Friends.max_idx)
|
if (i == Friends.max_idx)
|
||||||
++Friends.max_idx;
|
++Friends.max_idx;
|
||||||
@ -431,9 +427,8 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_t num, bool sort)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* puts blocked friend back in friendlist. fnum is new friend number, bnum is blocked number */
|
/* puts blocked friend back in friendlist. fnum is new friend number, bnum is blocked number */
|
||||||
static void friendlist_add_blocked(Tox *m, int32_t fnum, int32_t bnum)
|
static void friendlist_add_blocked(Tox *m, uint32_t fnum, uint32_t bnum)
|
||||||
{
|
{
|
||||||
Friends.num_friends = tox_count_friendlist(m);
|
|
||||||
realloc_friends(Friends.max_idx + 1);
|
realloc_friends(Friends.max_idx + 1);
|
||||||
memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend));
|
memset(&Friends.list[Friends.max_idx], 0, sizeof(ToxicFriend));
|
||||||
|
|
||||||
@ -443,15 +438,17 @@ static void friendlist_add_blocked(Tox *m, int32_t fnum, int32_t bnum)
|
|||||||
if (Friends.list[i].active)
|
if (Friends.list[i].active)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
++Friends.num_friends;
|
||||||
|
|
||||||
Friends.list[i].num = fnum;
|
Friends.list[i].num = fnum;
|
||||||
Friends.list[i].active = true;
|
Friends.list[i].active = true;
|
||||||
Friends.list[i].chatwin = -1;
|
Friends.list[i].chatwin = -1;
|
||||||
Friends.list[i].status = TOX_USERSTATUS_NONE;
|
Friends.list[i].status = TOX_USER_STATUS_NONE;
|
||||||
Friends.list[i].logging_on = (bool) user_settings->autolog == AUTOLOG_ON;
|
Friends.list[i].logging_on = (bool) user_settings->autolog == AUTOLOG_ON;
|
||||||
Friends.list[i].namelength = Blocked.list[bnum].namelength;
|
Friends.list[i].namelength = Blocked.list[bnum].namelength;
|
||||||
update_friend_last_online(i, Blocked.list[bnum].last_on);
|
update_friend_last_online(i, Blocked.list[bnum].last_on);
|
||||||
memcpy(Friends.list[i].name, Blocked.list[bnum].name, Friends.list[i].namelength + 1);
|
memcpy(Friends.list[i].name, Blocked.list[bnum].name, Friends.list[i].namelength + 1);
|
||||||
memcpy(Friends.list[i].pub_key, Blocked.list[bnum].pub_key, TOX_CLIENT_ID_SIZE);
|
memcpy(Friends.list[i].pub_key, Blocked.list[bnum].pub_key, TOX_PUBLIC_KEY_SIZE);
|
||||||
|
|
||||||
if (i == Friends.max_idx)
|
if (i == Friends.max_idx)
|
||||||
++Friends.max_idx;
|
++Friends.max_idx;
|
||||||
@ -463,45 +460,52 @@ static void friendlist_add_blocked(Tox *m, int32_t fnum, int32_t bnum)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void friendlist_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t filenum,
|
static void friendlist_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_t filenum, uint32_t kind,
|
||||||
uint64_t filesize, const char *filename, uint16_t filename_len)
|
uint64_t file_size, const char *filename, size_t name_length)
|
||||||
{
|
{
|
||||||
if (num >= Friends.max_idx)
|
if (num >= Friends.max_idx)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Friends.list[num].chatwin == -1) {
|
if (Friends.list[num].chatwin != -1)
|
||||||
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
return;
|
||||||
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
|
|
||||||
} else {
|
|
||||||
tox_file_send_control(m, num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0);
|
|
||||||
|
|
||||||
char nick[TOX_MAX_NAME_LENGTH];
|
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
||||||
get_nick_truncate(m, nick, num);
|
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
|
||||||
|
return;
|
||||||
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED,
|
|
||||||
"* File transfer from %s failed: too many windows are open.", nick);
|
|
||||||
|
|
||||||
sound_notify(prompt, error, NT_WNDALERT_1, NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tox_file_control(m, num, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
|
||||||
|
|
||||||
|
char nick[TOX_MAX_NAME_LENGTH];
|
||||||
|
get_nick_truncate(m, nick, num);
|
||||||
|
|
||||||
|
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED,
|
||||||
|
"* File transfer from %s failed: too many windows are open.", nick);
|
||||||
|
|
||||||
|
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, const char *group_pub_key, uint16_t length)
|
static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, uint8_t type, const char *group_pub_key,
|
||||||
|
uint16_t length)
|
||||||
{
|
{
|
||||||
if (num >= Friends.max_idx)
|
if (num >= Friends.max_idx)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Friends.list[num].chatwin == -1) {
|
if (Friends.list[num].chatwin != -1)
|
||||||
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
return;
|
||||||
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
|
|
||||||
} else {
|
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
||||||
char nick[TOX_MAX_NAME_LENGTH];
|
Friends.list[num].chatwin = add_window(m, new_chat(m, Friends.list[num].num));
|
||||||
get_nick_truncate(m, nick, num);
|
return;
|
||||||
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED,
|
|
||||||
"* Group chat invite from %s failed: too many windows are open.", nick);
|
|
||||||
sound_notify(prompt, error, NT_WNDALERT_1, NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char nick[TOX_MAX_NAME_LENGTH];
|
||||||
|
get_nick_truncate(m, nick, num);
|
||||||
|
|
||||||
|
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED,
|
||||||
|
"* Group chat invite from %s failed: too many windows are open.", nick);
|
||||||
|
|
||||||
|
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* move friendlist/blocklist cursor up and down */
|
/* move friendlist/blocklist cursor up and down */
|
||||||
@ -518,8 +522,20 @@ static void select_friend(ToxWindow *self, wint_t key, int *selected, int num)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void delete_friend(Tox *m, int32_t f_num)
|
static void delete_friend(Tox *m, uint32_t f_num)
|
||||||
{
|
{
|
||||||
|
TOX_ERR_FRIEND_DELETE err;
|
||||||
|
if (tox_friend_delete(m, f_num, &err) != true) {
|
||||||
|
fprintf(stderr, "tox_friend_delete failed with error %d\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
--Friends.num_friends;
|
||||||
|
|
||||||
|
if (Friends.list[f_num].connection_status != TOX_CONNECTION_NONE)
|
||||||
|
--Friends.num_online;
|
||||||
|
|
||||||
|
/* close friend's chatwindow if it's currently open */
|
||||||
if (Friends.list[f_num].chatwin >= 0) {
|
if (Friends.list[f_num].chatwin >= 0) {
|
||||||
ToxWindow *toxwin = get_window_ptr(Friends.list[f_num].chatwin);
|
ToxWindow *toxwin = get_window_ptr(Friends.list[f_num].chatwin);
|
||||||
|
|
||||||
@ -532,7 +548,6 @@ static void delete_friend(Tox *m, int32_t f_num)
|
|||||||
if (Friends.list[f_num].group_invite.key != NULL)
|
if (Friends.list[f_num].group_invite.key != NULL)
|
||||||
free(Friends.list[f_num].group_invite.key);
|
free(Friends.list[f_num].group_invite.key);
|
||||||
|
|
||||||
tox_del_friend(m, f_num);
|
|
||||||
memset(&Friends.list[f_num], 0, sizeof(ToxicFriend));
|
memset(&Friends.list[f_num], 0, sizeof(ToxicFriend));
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
@ -543,7 +558,6 @@ static void delete_friend(Tox *m, int32_t f_num)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Friends.max_idx = i;
|
Friends.max_idx = i;
|
||||||
Friends.num_friends = tox_count_friendlist(m);
|
|
||||||
realloc_friends(i);
|
realloc_friends(i);
|
||||||
|
|
||||||
/* make sure num_selected stays within Friends.num_friends range */
|
/* make sure num_selected stays within Friends.num_friends range */
|
||||||
@ -554,60 +568,60 @@ static void delete_friend(Tox *m, int32_t f_num)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* activates delete friend popup */
|
/* activates delete friend popup */
|
||||||
static void del_friend_activate(ToxWindow *self, Tox *m, int32_t f_num)
|
static void del_friend_activate(ToxWindow *self, Tox *m, uint32_t f_num)
|
||||||
{
|
{
|
||||||
pendingdelete.popup = newwin(3, 22 + TOXIC_MAX_NAME_LENGTH - 1, 8, 8);
|
PendingDelete.popup = newwin(3, 22 + TOXIC_MAX_NAME_LENGTH, 8, 8);
|
||||||
pendingdelete.active = true;
|
PendingDelete.active = true;
|
||||||
pendingdelete.num = f_num;
|
PendingDelete.num = f_num;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void delete_blocked_friend(int32_t bnum);
|
static void delete_blocked_friend(uint32_t bnum);
|
||||||
|
|
||||||
/* deactivates delete friend popup and deletes friend if instructed */
|
/* deactivates delete friend popup and deletes friend if instructed */
|
||||||
static void del_friend_deactivate(ToxWindow *self, Tox *m, wint_t key)
|
static void del_friend_deactivate(ToxWindow *self, Tox *m, wint_t key)
|
||||||
{
|
{
|
||||||
if (key == 'y') {
|
if (key == 'y') {
|
||||||
if (blocklist_view == 0) {
|
if (blocklist_view == 0) {
|
||||||
delete_friend(m, pendingdelete.num);
|
delete_friend(m, PendingDelete.num);
|
||||||
sort_friendlist_index();
|
sort_friendlist_index();
|
||||||
} else {
|
} else {
|
||||||
delete_blocked_friend(pendingdelete.num);
|
delete_blocked_friend(PendingDelete.num);
|
||||||
sort_blocklist_index();
|
sort_blocklist_index();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delwin(pendingdelete.popup);
|
delwin(PendingDelete.popup);
|
||||||
memset(&pendingdelete, 0, sizeof(pendingdelete));
|
memset(&PendingDelete, 0, sizeof(PendingDelete));
|
||||||
clear();
|
clear();
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_del_popup(void)
|
static void draw_del_popup(void)
|
||||||
{
|
{
|
||||||
if (!pendingdelete.active)
|
if (!PendingDelete.active)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
wattron(pendingdelete.popup, A_BOLD);
|
wattron(PendingDelete.popup, A_BOLD);
|
||||||
box(pendingdelete.popup, ACS_VLINE, ACS_HLINE);
|
box(PendingDelete.popup, ACS_VLINE, ACS_HLINE);
|
||||||
wattroff(pendingdelete.popup, A_BOLD);
|
wattroff(PendingDelete.popup, A_BOLD);
|
||||||
|
|
||||||
wmove(pendingdelete.popup, 1, 1);
|
wmove(PendingDelete.popup, 1, 1);
|
||||||
wprintw(pendingdelete.popup, "Delete contact ");
|
wprintw(PendingDelete.popup, "Delete contact ");
|
||||||
wattron(pendingdelete.popup, A_BOLD);
|
wattron(PendingDelete.popup, A_BOLD);
|
||||||
|
|
||||||
if (blocklist_view == 0)
|
if (blocklist_view == 0)
|
||||||
wprintw(pendingdelete.popup, "%s", Friends.list[pendingdelete.num].name);
|
wprintw(PendingDelete.popup, "%s", Friends.list[PendingDelete.num].name);
|
||||||
else
|
else
|
||||||
wprintw(pendingdelete.popup, "%s", Blocked.list[pendingdelete.num].name);
|
wprintw(PendingDelete.popup, "%s", Blocked.list[PendingDelete.num].name);
|
||||||
|
|
||||||
wattroff(pendingdelete.popup, A_BOLD);
|
wattroff(PendingDelete.popup, A_BOLD);
|
||||||
wprintw(pendingdelete.popup, "? y/n");
|
wprintw(PendingDelete.popup, "? y/n");
|
||||||
|
|
||||||
wrefresh(pendingdelete.popup);
|
wrefresh(PendingDelete.popup);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* deletes contact from blocked list */
|
/* deletes contact from blocked list */
|
||||||
static void delete_blocked_friend(int32_t bnum)
|
static void delete_blocked_friend(uint32_t bnum)
|
||||||
{
|
{
|
||||||
memset(&Blocked.list[bnum], 0, sizeof(BlockedFriend));
|
memset(&Blocked.list[bnum], 0, sizeof(BlockedFriend));
|
||||||
|
|
||||||
@ -628,12 +642,12 @@ static void delete_blocked_friend(int32_t bnum)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* deletes contact from friendlist and puts in blocklist */
|
/* deletes contact from friendlist and puts in blocklist */
|
||||||
void block_friend(Tox *m, int32_t fnum)
|
void block_friend(Tox *m, uint32_t fnum)
|
||||||
{
|
{
|
||||||
if (Friends.num_friends <= 0)
|
if (Friends.num_friends <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
realloc_blocklist(Blocked.max_idx + 1);
|
realloc_blocklist(Blocked.max_idx + 1);
|
||||||
memset(&Blocked.list[Blocked.max_idx], 0, sizeof(BlockedFriend));
|
memset(&Blocked.list[Blocked.max_idx], 0, sizeof(BlockedFriend));
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
@ -646,8 +660,8 @@ void block_friend(Tox *m, int32_t fnum)
|
|||||||
Blocked.list[i].num = i;
|
Blocked.list[i].num = i;
|
||||||
Blocked.list[i].namelength = Friends.list[fnum].namelength;
|
Blocked.list[i].namelength = Friends.list[fnum].namelength;
|
||||||
Blocked.list[i].last_on = Friends.list[fnum].last_online.last_on;
|
Blocked.list[i].last_on = Friends.list[fnum].last_online.last_on;
|
||||||
memcpy(Blocked.list[i].pub_key, Friends.list[fnum].pub_key, TOX_CLIENT_ID_SIZE);
|
memcpy(Blocked.list[i].pub_key, Friends.list[fnum].pub_key, TOX_PUBLIC_KEY_SIZE);
|
||||||
memcpy(Blocked.list[i].name, Friends.list[fnum].name, Friends.list[fnum].namelength + 1);
|
memcpy(Blocked.list[i].name, Friends.list[fnum].name, Friends.list[fnum].namelength + 1);
|
||||||
|
|
||||||
++Blocked.num_blocked;
|
++Blocked.num_blocked;
|
||||||
|
|
||||||
@ -664,15 +678,16 @@ void block_friend(Tox *m, int32_t fnum)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* removes friend from blocklist, puts back in friendlist */
|
/* removes friend from blocklist, puts back in friendlist */
|
||||||
static void unblock_friend(Tox *m, int32_t bnum)
|
static void unblock_friend(Tox *m, uint32_t bnum)
|
||||||
{
|
{
|
||||||
if (Blocked.num_blocked <= 0)
|
if (Blocked.num_blocked <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int32_t friendnum = tox_add_friend_norequest(m, (uint8_t *) Blocked.list[bnum].pub_key);
|
TOX_ERR_FRIEND_ADD err;
|
||||||
|
uint32_t friendnum = tox_friend_add_norequest(m, (uint8_t *) Blocked.list[bnum].pub_key, &err);
|
||||||
|
|
||||||
if (friendnum == -1) {
|
if (err != TOX_ERR_FRIEND_ADD_OK) {
|
||||||
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to unblock friend");
|
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to unblock friend (error %d)\n", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -709,7 +724,7 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
f = Friends.index[Friends.num_selected];
|
f = Friends.index[Friends.num_selected];
|
||||||
|
|
||||||
/* lock screen and force decision on deletion popup */
|
/* lock screen and force decision on deletion popup */
|
||||||
if (pendingdelete.active) {
|
if (PendingDelete.active) {
|
||||||
if (key == 'y' || key == 'n')
|
if (key == 'y' || key == 'n')
|
||||||
del_friend_deactivate(self, m, key);
|
del_friend_deactivate(self, m, key);
|
||||||
|
|
||||||
@ -733,7 +748,7 @@ static void friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
} else {
|
} else {
|
||||||
const char *msg = "* Warning: Too many windows are open.";
|
const char *msg = "* Warning: Too many windows are open.";
|
||||||
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, msg);
|
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, msg);
|
||||||
sound_notify(prompt, error, NT_WNDALERT_1, NULL);
|
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -775,7 +790,7 @@ static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2)
|
|||||||
if ((y2 - FLIST_OFST) <= 0)
|
if ((y2 - FLIST_OFST) <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int selected_num = 0;
|
uint32_t selected_num = 0;
|
||||||
|
|
||||||
/* Determine which portion of friendlist to draw based on current position */
|
/* Determine which portion of friendlist to draw based on current position */
|
||||||
int page = Blocked.num_selected / (y2 - FLIST_OFST);
|
int page = Blocked.num_selected / (y2 - FLIST_OFST);
|
||||||
@ -785,7 +800,7 @@ static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = start; i < Blocked.num_blocked && i < end; ++i) {
|
for (i = start; i < Blocked.num_blocked && i < end; ++i) {
|
||||||
int f = Blocked.index[i];
|
uint32_t f = Blocked.index[i];
|
||||||
bool f_selected = false;
|
bool f_selected = false;
|
||||||
|
|
||||||
if (i == Blocked.num_selected) {
|
if (i == Blocked.num_selected) {
|
||||||
@ -825,7 +840,7 @@ static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2)
|
|||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < TOX_CLIENT_ID_SIZE; ++i)
|
for (i = 0; i < TOX_PUBLIC_KEY_SIZE; ++i)
|
||||||
wprintw(self->window, "%02X", Blocked.list[selected_num].pub_key[i] & 0xff);
|
wprintw(self->window, "%02X", Blocked.list[selected_num].pub_key[i] & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -858,22 +873,18 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t cur_time = get_unix_time();
|
// uint64_t cur_time = get_unix_time();
|
||||||
struct tm cur_loc_tm = *localtime((const time_t *) &cur_time);
|
// struct tm cur_loc_tm = *localtime((const time_t *) &cur_time);
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
|
||||||
int nf = tox_get_num_online_friends(m);
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
|
||||||
|
|
||||||
wattron(self->window, A_BOLD);
|
wattron(self->window, A_BOLD);
|
||||||
wprintw(self->window, " Online: ");
|
wprintw(self->window, " Online: ");
|
||||||
wattroff(self->window, A_BOLD);
|
wattroff(self->window, A_BOLD);
|
||||||
wprintw(self->window, "%d/%d \n\n", nf, Friends.num_friends);
|
wprintw(self->window, "%d/%d \n\n", Friends.num_online, Friends.num_friends);
|
||||||
|
|
||||||
if ((y2 - FLIST_OFST) <= 0)
|
if ((y2 - FLIST_OFST) <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int selected_num = 0;
|
uint32_t selected_num = 0;
|
||||||
|
|
||||||
/* Determine which portion of friendlist to draw based on current position */
|
/* Determine which portion of friendlist to draw based on current position */
|
||||||
int page = Friends.num_selected / (y2 - FLIST_OFST);
|
int page = Friends.num_selected / (y2 - FLIST_OFST);
|
||||||
@ -883,7 +894,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = start; i < Friends.num_friends && i < end; ++i) {
|
for (i = start; i < Friends.num_friends && i < end; ++i) {
|
||||||
int f = Friends.index[i];
|
uint32_t f = Friends.index[i];
|
||||||
bool f_selected = false;
|
bool f_selected = false;
|
||||||
|
|
||||||
if (Friends.list[f].active) {
|
if (Friends.list[f].active) {
|
||||||
@ -897,26 +908,20 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
wprintw(self->window, " ");
|
wprintw(self->window, " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Friends.list[f].online) {
|
if (Friends.list[f].connection_status != TOX_CONNECTION_NONE) {
|
||||||
uint8_t status = Friends.list[f].status;
|
TOX_USER_STATUS status = Friends.list[f].status;
|
||||||
int colour = WHITE;
|
int colour = MAGENTA;
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case TOX_USERSTATUS_NONE:
|
case TOX_USER_STATUS_NONE:
|
||||||
colour = GREEN;
|
colour = GREEN;
|
||||||
break;
|
break;
|
||||||
|
case TOX_USER_STATUS_AWAY:
|
||||||
case TOX_USERSTATUS_AWAY:
|
|
||||||
colour = YELLOW;
|
colour = YELLOW;
|
||||||
break;
|
break;
|
||||||
|
case TOX_USER_STATUS_BUSY:
|
||||||
case TOX_USERSTATUS_BUSY:
|
|
||||||
colour = RED;
|
colour = RED;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_USERSTATUS_INVALID:
|
|
||||||
colour = MAGENTA;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wattron(self->window, COLOR_PAIR(colour) | A_BOLD);
|
wattron(self->window, COLOR_PAIR(colour) | A_BOLD);
|
||||||
@ -935,18 +940,20 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
/* Reset Friends.list[f].statusmsg on window resize */
|
/* Reset Friends.list[f].statusmsg on window resize */
|
||||||
if (fix_statuses) {
|
if (fix_statuses) {
|
||||||
char statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH];
|
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH];
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
tox_get_status_message(m, Friends.list[f].num, (uint8_t *) statusmsg, TOX_MAX_STATUSMESSAGE_LENGTH);
|
tox_friend_get_status_message(m, Friends.list[f].num, (uint8_t *) statusmsg, NULL);
|
||||||
|
size_t s_len = tox_friend_get_status_message_size(m, Friends.list[f].num, NULL);
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
|
filter_str(statusmsg, s_len);
|
||||||
snprintf(Friends.list[f].statusmsg, sizeof(Friends.list[f].statusmsg), "%s", statusmsg);
|
snprintf(Friends.list[f].statusmsg, sizeof(Friends.list[f].statusmsg), "%s", statusmsg);
|
||||||
Friends.list[f].statusmsg_len = strlen(Friends.list[f].statusmsg);
|
Friends.list[f].statusmsg_len = strlen(Friends.list[f].statusmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Truncate note if it doesn't fit on one line */
|
/* Truncate note if it doesn't fit on one line */
|
||||||
uint16_t maxlen = x2 - getcurx(self->window) - 2;
|
size_t maxlen = x2 - getcurx(self->window) - 2;
|
||||||
|
|
||||||
if (Friends.list[f].statusmsg_len > maxlen) {
|
if (Friends.list[f].statusmsg_len > maxlen) {
|
||||||
Friends.list[f].statusmsg[maxlen - 3] = '\0';
|
Friends.list[f].statusmsg[maxlen - 3] = '\0';
|
||||||
@ -972,28 +979,34 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
if (f_selected)
|
if (f_selected)
|
||||||
wattroff(self->window, COLOR_PAIR(BLUE));
|
wattroff(self->window, COLOR_PAIR(BLUE));
|
||||||
|
|
||||||
uint64_t last_seen = Friends.list[f].last_online.last_on;
|
wprintw(self->window, "\n");
|
||||||
|
/* Last online is currently broken in core */
|
||||||
|
|
||||||
if (last_seen != 0) {
|
// uint64_t last_seen = Friends.list[f].last_online.last_on;
|
||||||
int day_dist = (cur_loc_tm.tm_yday - Friends.list[f].last_online.tm.tm_yday) % 365;
|
//
|
||||||
const char *hourmin = Friends.list[f].last_online.hour_min_str;
|
// if (last_seen != 0) {
|
||||||
|
// int day_dist = (
|
||||||
|
// cur_loc_tm.tm_yday - Friends.list[f].last_online.tm.tm_yday
|
||||||
|
// + ((cur_loc_tm.tm_year - Friends.list[f].last_online.tm.tm_year) * 365)
|
||||||
|
// );
|
||||||
|
// const char *hourmin = Friends.list[f].last_online.hour_min_str;
|
||||||
|
|
||||||
switch (day_dist) {
|
// switch (day_dist) {
|
||||||
case 0:
|
// case 0:
|
||||||
wprintw(self->window, " Last seen: Today %s\n", hourmin);
|
// wprintw(self->window, " Last seen: Today %s\n", hourmin);
|
||||||
break;
|
// break;
|
||||||
|
|
||||||
case 1:
|
// case 1:
|
||||||
wprintw(self->window, " Last seen: Yesterday %s\n", hourmin);
|
// wprintw(self->window, " Last seen: Yesterday %s\n", hourmin);
|
||||||
break;
|
// break;
|
||||||
|
|
||||||
default:
|
// default:
|
||||||
wprintw(self->window, " Last seen: %d days ago\n", day_dist);
|
// wprintw(self->window, " Last seen: %d days ago\n", day_dist);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
wprintw(self->window, " Last seen: Never\n");
|
// wprintw(self->window, " Last seen: Never\n");
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1009,7 +1022,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < TOX_CLIENT_ID_SIZE; ++i)
|
for (i = 0; i < TOX_PUBLIC_KEY_SIZE; ++i)
|
||||||
wprintw(self->window, "%02X", Friends.list[selected_num].pub_key[i] & 0xff);
|
wprintw(self->window, "%02X", Friends.list[selected_num].pub_key[i] & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1020,7 +1033,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
|||||||
help_onDraw(self);
|
help_onDraw(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void disable_chatwin(int32_t f_num)
|
void disable_chatwin(uint32_t f_num)
|
||||||
{
|
{
|
||||||
Friends.list[f_num].chatwin = -1;
|
Friends.list[f_num].chatwin = -1;
|
||||||
}
|
}
|
||||||
@ -1030,7 +1043,7 @@ static void friendlist_onAv(ToxWindow *self, ToxAv *av, int call_index)
|
|||||||
{
|
{
|
||||||
int id = toxav_get_peer_id(av, call_index, 0);
|
int id = toxav_get_peer_id(av, call_index, 0);
|
||||||
|
|
||||||
if ( id != ErrorInternal && id >= Friends.max_idx)
|
if ( id != av_ErrorUnknown && id >= Friends.max_idx)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Tox *m = toxav_get_tox(av);
|
Tox *m = toxav_get_tox(av);
|
||||||
@ -1039,7 +1052,7 @@ static void friendlist_onAv(ToxWindow *self, ToxAv *av, int call_index)
|
|||||||
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
if (get_num_active_windows() < MAX_WINDOWS_NUM) {
|
||||||
if (toxav_get_call_state(av, call_index) == av_CallStarting) { /* Only open windows when call is incoming */
|
if (toxav_get_call_state(av, call_index) == av_CallStarting) { /* Only open windows when call is incoming */
|
||||||
Friends.list[id].chatwin = add_window(m, new_chat(m, Friends.list[id].num));
|
Friends.list[id].chatwin = add_window(m, new_chat(m, Friends.list[id].num));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
char nick[TOX_MAX_NAME_LENGTH];
|
char nick[TOX_MAX_NAME_LENGTH];
|
||||||
get_nick_truncate(m, nick, Friends.list[id].num);
|
get_nick_truncate(m, nick, Friends.list[id].num);
|
||||||
@ -1047,8 +1060,8 @@ static void friendlist_onAv(ToxWindow *self, ToxAv *av, int call_index)
|
|||||||
|
|
||||||
const char *errmsg = "* Warning: Too many windows are open.";
|
const char *errmsg = "* Warning: Too many windows are open.";
|
||||||
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, errmsg);
|
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, errmsg);
|
||||||
|
|
||||||
sound_notify(prompt, error, NT_WNDALERT_1, NULL);
|
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1067,11 +1080,10 @@ ToxWindow new_friendlist(void)
|
|||||||
ret.onFriendAdded = &friendlist_onFriendAdded;
|
ret.onFriendAdded = &friendlist_onFriendAdded;
|
||||||
ret.onMessage = &friendlist_onMessage;
|
ret.onMessage = &friendlist_onMessage;
|
||||||
ret.onConnectionChange = &friendlist_onConnectionChange;
|
ret.onConnectionChange = &friendlist_onConnectionChange;
|
||||||
ret.onAction = &friendlist_onMessage; /* Action has identical behaviour to message */
|
|
||||||
ret.onNickChange = &friendlist_onNickChange;
|
ret.onNickChange = &friendlist_onNickChange;
|
||||||
ret.onStatusChange = &friendlist_onStatusChange;
|
ret.onStatusChange = &friendlist_onStatusChange;
|
||||||
ret.onStatusMessageChange = &friendlist_onStatusMessageChange;
|
ret.onStatusMessageChange = &friendlist_onStatusMessageChange;
|
||||||
ret.onFileSendRequest = &friendlist_onFileSendRequest;
|
ret.onFileRecv = &friendlist_onFileRecv;
|
||||||
ret.onGroupInvite = &friendlist_onGroupInvite;
|
ret.onGroupInvite = &friendlist_onGroupInvite;
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
@ -1086,18 +1098,18 @@ ToxWindow new_friendlist(void)
|
|||||||
ret.onEnd = &friendlist_onAv;
|
ret.onEnd = &friendlist_onAv;
|
||||||
ret.onRequestTimeout = &friendlist_onAv;
|
ret.onRequestTimeout = &friendlist_onAv;
|
||||||
ret.onPeerTimeout = &friendlist_onAv;
|
ret.onPeerTimeout = &friendlist_onAv;
|
||||||
|
|
||||||
ret.call_idx = -1;
|
ret.call_idx = -1;
|
||||||
ret.device_selection[0] = ret.device_selection[1] = -1;
|
ret.device_selection[0] = ret.device_selection[1] = -1;
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
ret.active_box = -1;
|
ret.active_box = -1;
|
||||||
|
|
||||||
Help *help = calloc(1, sizeof(Help));
|
Help *help = calloc(1, sizeof(Help));
|
||||||
|
|
||||||
if (help == NULL)
|
if (help == NULL)
|
||||||
exit_toxic_err("failed in new_friendlist", FATALERR_MEMORY);
|
exit_toxic_err("failed in new_friendlist", FATALERR_MEMORY);
|
||||||
|
|
||||||
ret.help = help;
|
ret.help = help;
|
||||||
strcpy(ret.name, "contacts");
|
strcpy(ret.name, "contacts");
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -27,20 +27,7 @@
|
|||||||
|
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#include "file_senders.h"
|
#include "file_transfers.h"
|
||||||
|
|
||||||
struct FileReceiver {
|
|
||||||
char filename[MAX_STR_SIZE];
|
|
||||||
int filenum;
|
|
||||||
FILE *file;
|
|
||||||
bool pending;
|
|
||||||
bool active;
|
|
||||||
uint64_t size;
|
|
||||||
uint64_t bytes_recv;
|
|
||||||
double bps;
|
|
||||||
uint64_t last_progress; /* unix-time when we last updated progress */
|
|
||||||
uint32_t line_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct LastOnline {
|
struct LastOnline {
|
||||||
uint64_t last_on;
|
uint64_t last_on;
|
||||||
@ -51,51 +38,55 @@ struct LastOnline {
|
|||||||
struct GroupChatInvite {
|
struct GroupChatInvite {
|
||||||
char *key;
|
char *key;
|
||||||
uint16_t length;
|
uint16_t length;
|
||||||
|
uint8_t type;
|
||||||
bool pending;
|
bool pending;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char name[TOXIC_MAX_NAME_LENGTH];
|
char name[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
int namelength;
|
int namelength;
|
||||||
char statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH];
|
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
|
||||||
uint16_t statusmsg_len;
|
size_t statusmsg_len;
|
||||||
char pub_key[TOX_CLIENT_ID_SIZE];
|
char pub_key[TOX_PUBLIC_KEY_SIZE];
|
||||||
int32_t num;
|
uint32_t num;
|
||||||
int chatwin;
|
int chatwin;
|
||||||
bool active;
|
bool active;
|
||||||
bool online;
|
TOX_CONNECTION connection_status;
|
||||||
uint8_t is_typing;
|
bool is_typing;
|
||||||
bool logging_on; /* saves preference for friend irrespective of global settings */
|
bool logging_on; /* saves preference for friend irrespective of global settings */
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
|
|
||||||
struct LastOnline last_online;
|
struct LastOnline last_online;
|
||||||
struct FileReceiver file_receiver[MAX_FILES];
|
|
||||||
struct GroupChatInvite group_invite;
|
struct GroupChatInvite group_invite;
|
||||||
uint8_t active_file_receivers;
|
|
||||||
|
struct FileReceiver file_receiver[MAX_FILES];
|
||||||
|
struct FileSender file_sender[MAX_FILES];
|
||||||
} ToxicFriend;
|
} ToxicFriend;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char name[TOXIC_MAX_NAME_LENGTH];
|
char name[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
int namelength;
|
int namelength;
|
||||||
char pub_key[TOX_CLIENT_ID_SIZE];
|
char pub_key[TOX_PUBLIC_KEY_SIZE];
|
||||||
int32_t num;
|
uint32_t num;
|
||||||
bool active;
|
bool active;
|
||||||
uint64_t last_on;
|
uint64_t last_on;
|
||||||
} BlockedFriend;
|
} BlockedFriend;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int num_selected;
|
int num_selected;
|
||||||
int max_idx; /* 1 + the index of the last friend in list */
|
size_t num_friends;
|
||||||
int num_friends;
|
size_t num_online;
|
||||||
int *index;
|
size_t max_idx; /* 1 + the index of the last friend in list */
|
||||||
|
uint32_t *index;
|
||||||
ToxicFriend *list;
|
ToxicFriend *list;
|
||||||
} FriendsList;
|
} FriendsList;
|
||||||
|
|
||||||
ToxWindow new_friendlist(void);
|
ToxWindow new_friendlist(void);
|
||||||
void disable_chatwin(int32_t f_num);
|
void disable_chatwin(uint32_t f_num);
|
||||||
int get_friendnum(uint8_t *name);
|
int get_friendnum(uint8_t *name);
|
||||||
int load_blocklist(char *data);
|
int load_blocklist(char *data);
|
||||||
void kill_friendlist(void);
|
void kill_friendlist(void);
|
||||||
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_t num, bool sort);
|
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort);
|
||||||
|
|
||||||
/* sorts friendlist_index first by connection status then alphabetically */
|
/* sorts friendlist_index first by connection status then alphabetically */
|
||||||
void sort_friendlist_index(void);
|
void sort_friendlist_index(void);
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include "groupchat.h"
|
#include "groupchat.h"
|
||||||
#include "prompt.h"
|
#include "prompt.h"
|
||||||
#include "help.h"
|
#include "help.h"
|
||||||
|
#include "term_mplex.h"
|
||||||
|
|
||||||
extern char *DATA_FILE;
|
extern char *DATA_FILE;
|
||||||
extern ToxWindow *prompt;
|
extern ToxWindow *prompt;
|
||||||
@ -60,13 +61,14 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *msg;
|
TOX_ERR_FRIEND_ADD err;
|
||||||
int32_t friendnum = tox_add_friend_norequest(m, FrndRequests.request[req].key);
|
uint32_t friendnum = tox_friend_add_norequest(m, FrndRequests.request[req].key, &err);
|
||||||
|
|
||||||
if (friendnum == -1)
|
if (err != TOX_ERR_FRIEND_ADD_OK) {
|
||||||
msg = "Failed to add friend.";
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to add friend (error %d\n)", err);
|
||||||
else {
|
return;
|
||||||
msg = "Friend request accepted.";
|
} else {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Friend request accepted.");
|
||||||
on_friendadded(m, friendnum, true);
|
on_friendadded(m, friendnum, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,47 +83,55 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
|||||||
|
|
||||||
FrndRequests.max_idx = i;
|
FrndRequests.max_idx = i;
|
||||||
--FrndRequests.num_requests;
|
--FrndRequests.num_requests;
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_add_helper(ToxWindow *self, Tox *m, char *id_bin, char *msg)
|
void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg)
|
||||||
{
|
{
|
||||||
const char *errmsg;
|
const char *errmsg;
|
||||||
int32_t f_num = tox_add_friend(m, (uint8_t *) id_bin, (uint8_t *) msg, (uint16_t) strlen(msg));
|
|
||||||
|
|
||||||
switch (f_num) {
|
TOX_ERR_FRIEND_ADD err;
|
||||||
case TOX_FAERR_TOOLONG:
|
uint32_t f_num = tox_friend_add(m, (uint8_t *) id_bin, (uint8_t *) msg, strlen(msg), &err);
|
||||||
|
|
||||||
|
switch (err) {
|
||||||
|
case TOX_ERR_FRIEND_ADD_TOO_LONG:
|
||||||
errmsg = "Message is too long.";
|
errmsg = "Message is too long.";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_FAERR_NOMESSAGE:
|
case TOX_ERR_FRIEND_ADD_NO_MESSAGE:
|
||||||
errmsg = "Please add a message to your request.";
|
errmsg = "Please add a message to your request.";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_FAERR_OWNKEY:
|
case TOX_ERR_FRIEND_ADD_OWN_KEY:
|
||||||
errmsg = "That appears to be your own ID.";
|
errmsg = "That appears to be your own ID.";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_FAERR_ALREADYSENT:
|
case TOX_ERR_FRIEND_ADD_ALREADY_SENT:
|
||||||
errmsg = "Friend request has already been sent.";
|
errmsg = "Friend request has already been sent.";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_FAERR_UNKNOWN:
|
case TOX_ERR_FRIEND_ADD_BAD_CHECKSUM:
|
||||||
errmsg = "Undefined error when adding friend.";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TOX_FAERR_BADCHECKSUM:
|
|
||||||
errmsg = "Bad checksum in address.";
|
errmsg = "Bad checksum in address.";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_FAERR_SETNEWNOSPAM:
|
case TOX_ERR_FRIEND_ADD_SET_NEW_NOSPAM:
|
||||||
errmsg = "Nospam was different.";
|
errmsg = "Nospam was different.";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
case TOX_ERR_FRIEND_ADD_MALLOC:
|
||||||
|
errmsg = "Core memory allocation failed.";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOX_ERR_FRIEND_ADD_OK:
|
||||||
errmsg = "Friend request sent.";
|
errmsg = "Friend request sent.";
|
||||||
on_friendadded(m, f_num, true);
|
on_friendadded(m, f_num, true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOX_ERR_FRIEND_ADD_NULL:
|
||||||
|
/* fallthrough */
|
||||||
|
default:
|
||||||
|
errmsg = "Faile to add friend: Unknown error.";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
||||||
@ -151,21 +161,23 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
|||||||
snprintf(msg, sizeof(msg), "%s", tmp);
|
snprintf(msg, sizeof(msg), "%s", tmp);
|
||||||
} else {
|
} else {
|
||||||
char selfname[TOX_MAX_NAME_LENGTH];
|
char selfname[TOX_MAX_NAME_LENGTH];
|
||||||
uint16_t n_len = tox_get_self_name(m, (uint8_t *) selfname);
|
tox_self_get_name(m, (uint8_t *) selfname);
|
||||||
|
|
||||||
|
size_t n_len = tox_self_get_name_size(m);
|
||||||
selfname[n_len] = '\0';
|
selfname[n_len] = '\0';
|
||||||
snprintf(msg, sizeof(msg), "Hello, my name is %s. Care to Tox?", selfname);
|
snprintf(msg, sizeof(msg), "Hello, my name is %s. Care to Tox?", selfname);
|
||||||
}
|
}
|
||||||
|
|
||||||
char id_bin[TOX_FRIEND_ADDRESS_SIZE] = {0};
|
char id_bin[TOX_ADDRESS_SIZE] = {0};
|
||||||
uint16_t id_len = (uint16_t) strlen(id);
|
uint16_t id_len = (uint16_t) strlen(id);
|
||||||
|
|
||||||
/* try to add tox ID */
|
/* try to add tox ID */
|
||||||
if (id_len == 2 * TOX_FRIEND_ADDRESS_SIZE) {
|
if (id_len == 2 * TOX_ADDRESS_SIZE) {
|
||||||
size_t i;
|
size_t i;
|
||||||
char xx[3];
|
char xx[3];
|
||||||
uint32_t x;
|
uint32_t x;
|
||||||
|
|
||||||
for (i = 0; i < TOX_FRIEND_ADDRESS_SIZE; ++i) {
|
for (i = 0; i < TOX_ADDRESS_SIZE; ++i) {
|
||||||
xx[0] = id[2 * i];
|
xx[0] = id[2 * i];
|
||||||
xx[1] = id[2 * i + 1];
|
xx[1] = id[2 * i + 1];
|
||||||
xx[2] = '\0';
|
xx[2] = '\0';
|
||||||
@ -186,85 +198,78 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
|||||||
|
|
||||||
void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
if (argc < 2) {
|
// if (argc < 2) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: No file path supplied.");
|
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: No file path supplied.");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
/* turns the avatar off */
|
// /* turns the avatar off */
|
||||||
if (strlen(argv[1]) < 3) {
|
// if (strlen(argv[1]) < 3) {
|
||||||
tox_unset_avatar(m);
|
// tox_unset_avatar(m);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No avatar set.");
|
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No avatar set.");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (argv[1][0] != '\"') {
|
// if (argv[1][0] != '\"') {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Path must be enclosed in quotes.");
|
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Path must be enclosed in quotes.");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
/* remove opening and closing quotes */
|
// /* remove opening and closing quotes */
|
||||||
char path[MAX_STR_SIZE];
|
// char path[MAX_STR_SIZE];
|
||||||
snprintf(path, sizeof(path), "%s", &argv[1][1]);
|
// snprintf(path, sizeof(path), "%s", &argv[1][1]);
|
||||||
int len = strlen(path) - 1;
|
// int len = strlen(path) - 1;
|
||||||
path[len] = '\0';
|
// path[len] = '\0';
|
||||||
|
|
||||||
off_t sz = file_size(path);
|
// off_t sz = file_size(path);
|
||||||
|
|
||||||
if (sz <= 8) {
|
// if (sz <= 8) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Invalid file.");
|
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Invalid file.");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (sz > TOX_AVATAR_MAX_DATA_LENGTH) {
|
// FILE *fp = fopen(path, "rb");
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: File is too large.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE *fp = fopen(path, "rb");
|
// if (fp == NULL) {
|
||||||
|
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Could not open file.");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
if (fp == NULL) {
|
// char PNG_signature[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Could not open file.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char PNG_signature[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
|
// if (check_file_signature(PNG_signature, sizeof(PNG_signature), fp) != 0) {
|
||||||
|
// fclose(fp);
|
||||||
|
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: File type not supported.");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
if (check_file_signature(PNG_signature, sizeof(PNG_signature), fp) != 0) {
|
// char *avatar = malloc(sz);
|
||||||
fclose(fp);
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: File type not supported.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *avatar = malloc(sz);
|
// if (avatar == NULL)
|
||||||
|
// exit_toxic_err("Failed in cmd_avatar", FATALERR_MEMORY);
|
||||||
|
|
||||||
if (avatar == NULL)
|
// if (fread(avatar, sz, 1, fp) != 1) {
|
||||||
exit_toxic_err("Failed in set_avatar", FATALERR_MEMORY);
|
// fclose(fp);
|
||||||
|
// free(avatar);
|
||||||
|
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Read fail.");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
if (fread(avatar, sz, 1, fp) != 1) {
|
// if (tox_set_avatar(m, TOX_AVATAR_FORMAT_PNG, (const uint8_t *) avatar, (uint32_t) sz) == -1)
|
||||||
fclose(fp);
|
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar");
|
||||||
free(avatar);
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Read fail.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tox_set_avatar(m, TOX_AVATAR_FORMAT_PNG, (const uint8_t *) avatar, (uint32_t) sz) == -1)
|
// char filename[MAX_STR_SIZE];
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Core error.");
|
// get_file_name(filename, sizeof(filename), path);
|
||||||
|
// line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Avatar set to '%s'", filename);
|
||||||
|
|
||||||
char filename[MAX_STR_SIZE];
|
// fclose(fp);
|
||||||
get_file_name(filename, sizeof(filename), path);
|
// free(avatar);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Avatar set to '%s'", filename);
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
free(avatar);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_clear(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_clear(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
line_info_clear(self->chatwin->hst);
|
line_info_clear(self->chatwin->hst);
|
||||||
wclear(window);
|
force_refresh(window);
|
||||||
endwin();
|
|
||||||
refresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
@ -284,8 +289,26 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
char *binary_string = hex_string_to_bin(key);
|
char *binary_string = hex_string_to_bin(key);
|
||||||
tox_bootstrap_from_address(m, ip, atoi(port), (uint8_t *) binary_string);
|
|
||||||
|
TOX_ERR_BOOTSTRAP err;
|
||||||
|
tox_bootstrap(m, ip, atoi(port), (uint8_t *) binary_string, &err);
|
||||||
free(binary_string);
|
free(binary_string);
|
||||||
|
|
||||||
|
switch (err) {
|
||||||
|
case TOX_ERR_BOOTSTRAP_BAD_HOST:
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed: Invalid IP.");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOX_ERR_BOOTSTRAP_BAD_PORT:
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed: Invalid port.");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOX_ERR_BOOTSTRAP_NULL:
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed.");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
@ -327,14 +350,37 @@ void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*arg
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int groupnum = tox_add_groupchat(m);
|
if (argc < 1) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Please specify group type: text | audio");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t type;
|
||||||
|
|
||||||
|
if (!strcasecmp(argv[1], "audio"))
|
||||||
|
type = TOX_GROUPCHAT_TYPE_AV;
|
||||||
|
else if (!strcasecmp(argv[1], "text"))
|
||||||
|
type = TOX_GROUPCHAT_TYPE_TEXT;
|
||||||
|
else {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Valid group types are: text | audio");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int groupnum = -1;
|
||||||
|
|
||||||
|
if (type == TOX_GROUPCHAT_TYPE_TEXT)
|
||||||
|
groupnum = tox_add_groupchat(m);
|
||||||
|
#ifdef AUDIO
|
||||||
|
else
|
||||||
|
groupnum = toxav_add_av_groupchat(m, write_device_callback_group, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (groupnum == -1) {
|
if (groupnum == -1) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (init_groupchat_win(prompt, m, groupnum) == -1) {
|
if (init_groupchat_win(prompt, m, groupnum, type) == -1) {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat window failed to initialize.");
|
||||||
tox_del_groupchat(m, groupnum);
|
tox_del_groupchat(m, groupnum);
|
||||||
return;
|
return;
|
||||||
@ -361,8 +407,8 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
|||||||
const char *swch = argv[1];
|
const char *swch = argv[1];
|
||||||
|
|
||||||
if (!strcmp(swch, "1") || !strcmp(swch, "on")) {
|
if (!strcmp(swch, "1") || !strcmp(swch, "on")) {
|
||||||
char myid[TOX_FRIEND_ADDRESS_SIZE];
|
char myid[TOX_ADDRESS_SIZE];
|
||||||
tox_get_address(m, (uint8_t *) myid);
|
tox_self_get_address(m, (uint8_t *) myid);
|
||||||
|
|
||||||
if (self->is_chat) {
|
if (self->is_chat) {
|
||||||
Friends.list[self->num].logging_on = true;
|
Friends.list[self->num].logging_on = true;
|
||||||
@ -393,13 +439,13 @@ 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])
|
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};
|
char id[TOX_ADDRESS_SIZE * 2 + 1] = {0};
|
||||||
char address[TOX_FRIEND_ADDRESS_SIZE];
|
char address[TOX_ADDRESS_SIZE];
|
||||||
tox_get_address(m, (uint8_t *) address);
|
tox_self_get_address(m, (uint8_t *) address);
|
||||||
|
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < TOX_FRIEND_ADDRESS_SIZE; ++i) {
|
for (i = 0; i < TOX_ADDRESS_SIZE; ++i) {
|
||||||
char xx[3];
|
char xx[3];
|
||||||
snprintf(xx, sizeof(xx), "%02X", address[i] & 0xff);
|
snprintf(xx, sizeof(xx), "%02X", address[i] & 0xff);
|
||||||
strcat(id, xx);
|
strcat(id, xx);
|
||||||
@ -416,7 +462,7 @@ void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
|||||||
}
|
}
|
||||||
|
|
||||||
char nick[MAX_STR_SIZE];
|
char nick[MAX_STR_SIZE];
|
||||||
int len = 0;
|
size_t len = 0;
|
||||||
|
|
||||||
if (argv[1][0] == '\"') { /* remove opening and closing quotes */
|
if (argv[1][0] == '\"') { /* remove opening and closing quotes */
|
||||||
snprintf(nick, sizeof(nick), "%s", &argv[1][1]);
|
snprintf(nick, sizeof(nick), "%s", &argv[1][1]);
|
||||||
@ -435,7 +481,7 @@ void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
|||||||
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
|
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
|
||||||
nick[len] = '\0';
|
nick[len] = '\0';
|
||||||
|
|
||||||
tox_set_name(m, (uint8_t *) nick, (uint16_t) len);
|
tox_self_set_name(m, (uint8_t *) nick, len, NULL);
|
||||||
prompt_update_nick(prompt, nick);
|
prompt_update_nick(prompt, nick);
|
||||||
|
|
||||||
store_data(m, DATA_FILE);
|
store_data(m, DATA_FILE);
|
||||||
@ -486,9 +532,9 @@ void cmd_requests(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
|||||||
if (!FrndRequests.request[i].active)
|
if (!FrndRequests.request[i].active)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
char id[TOX_CLIENT_ID_SIZE * 2 + 1] = {0};
|
char id[TOX_PUBLIC_KEY_SIZE * 2 + 1] = {0};
|
||||||
|
|
||||||
for (j = 0; j < TOX_CLIENT_ID_SIZE; ++j) {
|
for (j = 0; j < TOX_PUBLIC_KEY_SIZE; ++j) {
|
||||||
char d[3];
|
char d[3];
|
||||||
snprintf(d, sizeof(d), "%02X", FrndRequests.request[i].key[j] & 0xff);
|
snprintf(d, sizeof(d), "%02X", FrndRequests.request[i].key[j] & 0xff);
|
||||||
strcat(id, d);
|
strcat(id, d);
|
||||||
@ -503,43 +549,42 @@ void cmd_requests(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
|||||||
}
|
}
|
||||||
|
|
||||||
void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
{
|
{
|
||||||
bool have_note = false;
|
bool have_note = false;
|
||||||
const char *errmsg;
|
const char *errmsg;
|
||||||
|
|
||||||
|
lock_status ();
|
||||||
|
|
||||||
if (argc >= 2) {
|
if (argc >= 2) {
|
||||||
have_note = true;
|
have_note = true;
|
||||||
} else if (argc < 1) {
|
} else if (argc < 1) {
|
||||||
errmsg = "Require a status. Statuses are: online, busy and away.";
|
errmsg = "Require a status. Statuses are: online, busy and away.";
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
||||||
return;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
char status[MAX_STR_SIZE];
|
const char *status_str = argv[1];
|
||||||
snprintf(status, sizeof(status), "%s", argv[1]);
|
TOX_USER_STATUS status;
|
||||||
str_to_lower(status);
|
|
||||||
|
|
||||||
TOX_USERSTATUS status_kind;
|
if (!strcasecmp(status_str, "online"))
|
||||||
|
status = TOX_USER_STATUS_NONE;
|
||||||
if (!strcmp(status, "online"))
|
else if (!strcasecmp(status_str, "away"))
|
||||||
status_kind = TOX_USERSTATUS_NONE;
|
status = TOX_USER_STATUS_AWAY;
|
||||||
else if (!strcmp(status, "away"))
|
else if (!strcasecmp(status_str, "busy"))
|
||||||
status_kind = TOX_USERSTATUS_AWAY;
|
status = TOX_USER_STATUS_BUSY;
|
||||||
else if (!strcmp(status, "busy"))
|
|
||||||
status_kind = TOX_USERSTATUS_BUSY;
|
|
||||||
else {
|
else {
|
||||||
errmsg = "Invalid status. Valid statuses are: online, busy and away.";
|
errmsg = "Invalid status. Valid statuses are: online, busy and away.";
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
||||||
return;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
tox_set_user_status(m, status_kind);
|
tox_self_set_status(m, status);
|
||||||
prompt_update_status(prompt, status_kind);
|
prompt_update_status(prompt, status);
|
||||||
|
|
||||||
if (have_note) {
|
if (have_note) {
|
||||||
if (argv[2][0] != '\"') {
|
if (argv[2][0] != '\"') {
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Note must be enclosed in quotes.");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Note must be enclosed in quotes.");
|
||||||
return;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* remove opening and closing quotes */
|
/* remove opening and closing quotes */
|
||||||
@ -550,4 +595,7 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
|||||||
|
|
||||||
prompt_update_statusmessage(prompt, m, msg);
|
prompt_update_statusmessage(prompt, m, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
finish:
|
||||||
|
unlock_status ();
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ void cmd_quit(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]
|
|||||||
void cmd_requests(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_requests(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_status(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
|
|
||||||
void cmd_add_helper(ToxWindow *self, Tox *m, char *id_bin, char *msg);
|
void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg);
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
void cmd_list_devices(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_list_devices(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
|
79
src/group_commands.c
Normal file
79
src/group_commands.c
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/* group_commands.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 "toxic.h"
|
||||||
|
#include "windows.h"
|
||||||
|
#include "line_info.h"
|
||||||
|
#include "misc_tools.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
void cmd_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
|
{
|
||||||
|
char title[MAX_STR_SIZE];
|
||||||
|
|
||||||
|
if (argc < 1) {
|
||||||
|
int tlen = tox_group_get_title(m, self->num, (uint8_t *) title, TOX_MAX_NAME_LENGTH);
|
||||||
|
|
||||||
|
if (tlen != -1) {
|
||||||
|
title[tlen] = '\0';
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title is set to: %s", title);
|
||||||
|
} else {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title is not set");
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argv[1][0] != '\"') {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title must be enclosed in quotes.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove opening and closing quotes */
|
||||||
|
snprintf(title, sizeof(title), "%s", &argv[1][1]);
|
||||||
|
int len = strlen(title) - 1;
|
||||||
|
title[len] = '\0';
|
||||||
|
|
||||||
|
if (tox_group_set_title(m, self->num, (uint8_t *) title, len) != 0) {
|
||||||
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_window_title(self, title, len);
|
||||||
|
|
||||||
|
char timefrmt[TIME_STR_SIZE];
|
||||||
|
char selfnick[TOX_MAX_NAME_LENGTH];
|
||||||
|
|
||||||
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
|
|
||||||
|
tox_self_get_name(m, (uint8_t *) selfnick);
|
||||||
|
size_t sn_len = tox_self_get_name_size(m);
|
||||||
|
selfnick[sn_len] = '\0';
|
||||||
|
|
||||||
|
line_info_add(self, timefrmt, selfnick, NULL, NAME_CHANGE, 0, 0, " set the group title to: %s", title);
|
||||||
|
|
||||||
|
char tmp_event[MAX_STR_SIZE];
|
||||||
|
snprintf(tmp_event, sizeof(tmp_event), "set title to %s", title);
|
||||||
|
write_to_log(tmp_event, selfnick, self->chatwin->log, true);
|
||||||
|
}
|
31
src/group_commands.h
Normal file
31
src/group_commands.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/* group_commands.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 GROUP_COMMANDS_H
|
||||||
|
#define GROUP_COMMANDS_H
|
||||||
|
|
||||||
|
#include "windows.h"
|
||||||
|
#include "toxic.h"
|
||||||
|
|
||||||
|
void cmd_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
|
|
||||||
|
#endif /* GROUP_COMMANDS_H */
|
479
src/groupchat.c
479
src/groupchat.c
@ -29,6 +29,21 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <OpenAL/al.h>
|
||||||
|
#include <OpenAL/alc.h>
|
||||||
|
#else
|
||||||
|
#include <AL/al.h>
|
||||||
|
#include <AL/alc.h>
|
||||||
|
/* compatibility with older versions of OpenAL */
|
||||||
|
#ifndef ALC_ALL_DEVICES_SPECIFIER
|
||||||
|
#include <AL/alext.h>
|
||||||
|
#endif /* ALC_ALL_DEVICES_SPECIFIER */
|
||||||
|
#endif /* __APPLE__ */
|
||||||
|
#endif /* AUDIO */
|
||||||
|
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
@ -44,6 +59,7 @@
|
|||||||
#include "help.h"
|
#include "help.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
#include "autocomplete.h"
|
#include "autocomplete.h"
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
extern char *DATA_FILE;
|
extern char *DATA_FILE;
|
||||||
|
|
||||||
@ -51,22 +67,65 @@ static GroupChat groupchats[MAX_GROUPCHAT_NUM];
|
|||||||
static int max_groupchat_index = 0;
|
static int max_groupchat_index = 0;
|
||||||
|
|
||||||
extern struct user_settings *user_settings;
|
extern struct user_settings *user_settings;
|
||||||
|
extern struct Winthread Winthread;
|
||||||
|
|
||||||
/* temporary until group chats have unique commands */
|
#ifdef AUDIO
|
||||||
extern const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE];
|
#define AC_NUM_GROUP_COMMANDS 22
|
||||||
|
#else
|
||||||
|
#define AC_NUM_GROUP_COMMANDS 18
|
||||||
|
#endif /* AUDIO */
|
||||||
|
|
||||||
int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum)
|
/* Array of groupchat command names used for tab completion. */
|
||||||
|
static const char group_cmd_list[AC_NUM_GROUP_COMMANDS][MAX_CMDNAME_SIZE] = {
|
||||||
|
{ "/accept" },
|
||||||
|
{ "/add" },
|
||||||
|
{ "/avatar" },
|
||||||
|
{ "/clear" },
|
||||||
|
{ "/close" },
|
||||||
|
{ "/connect" },
|
||||||
|
{ "/decline" },
|
||||||
|
{ "/exit" },
|
||||||
|
{ "/group" },
|
||||||
|
{ "/help" },
|
||||||
|
{ "/log" },
|
||||||
|
{ "/myid" },
|
||||||
|
{ "/nick" },
|
||||||
|
{ "/note" },
|
||||||
|
{ "/quit" },
|
||||||
|
{ "/requests" },
|
||||||
|
{ "/status" },
|
||||||
|
{ "/title" },
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
|
|
||||||
|
{ "/lsdev" },
|
||||||
|
{ "/sdev" },
|
||||||
|
{ "/mute" },
|
||||||
|
{ "/sense" },
|
||||||
|
|
||||||
|
#endif /* AUDIO */
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
|
static int group_audio_open_out_device(int groupnum);
|
||||||
|
static int group_audio_close_out_device(int groupnum);
|
||||||
|
#endif /* AUDIO */
|
||||||
|
|
||||||
|
int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum, uint8_t type)
|
||||||
{
|
{
|
||||||
if (groupnum > MAX_GROUPCHAT_NUM)
|
if (groupnum > MAX_GROUPCHAT_NUM)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
ToxWindow self = new_group_chat(m, groupnum);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i <= max_groupchat_index; ++i) {
|
for (i = 0; i <= max_groupchat_index; ++i) {
|
||||||
if (!groupchats[i].active) {
|
if (!groupchats[i].active) {
|
||||||
groupchats[i].chatwin = add_window(m, new_group_chat(m, groupnum));
|
groupchats[i].chatwin = add_window(m, self);
|
||||||
groupchats[i].active = true;
|
groupchats[i].active = true;
|
||||||
groupchats[i].num_peers = 0;
|
groupchats[i].num_peers = 0;
|
||||||
|
groupchats[i].type = type;
|
||||||
|
groupchats[i].start_time = get_unix_time();
|
||||||
|
|
||||||
groupchats[i].peer_names = malloc(sizeof(uint8_t) * TOX_MAX_NAME_LENGTH);
|
groupchats[i].peer_names = malloc(sizeof(uint8_t) * TOX_MAX_NAME_LENGTH);
|
||||||
groupchats[i].oldpeer_names = malloc(sizeof(uint8_t) * TOX_MAX_NAME_LENGTH);
|
groupchats[i].oldpeer_names = malloc(sizeof(uint8_t) * TOX_MAX_NAME_LENGTH);
|
||||||
@ -80,6 +139,12 @@ int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum)
|
|||||||
memcpy(&groupchats[i].oldpeer_names[0], UNKNOWN_NAME, sizeof(UNKNOWN_NAME));
|
memcpy(&groupchats[i].oldpeer_names[0], UNKNOWN_NAME, sizeof(UNKNOWN_NAME));
|
||||||
groupchats[i].oldpeer_name_lengths[0] = (uint16_t) strlen(UNKNOWN_NAME);
|
groupchats[i].oldpeer_name_lengths[0] = (uint16_t) strlen(UNKNOWN_NAME);
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
|
if (type == TOX_GROUPCHAT_TYPE_AV)
|
||||||
|
if (group_audio_open_out_device(i) == -1)
|
||||||
|
fprintf(stderr, "Group Audio failed to init\n");
|
||||||
|
#endif /* AUDIO */
|
||||||
|
|
||||||
set_active_window(groupchats[i].chatwin);
|
set_active_window(groupchats[i].chatwin);
|
||||||
|
|
||||||
if (i == max_groupchat_index)
|
if (i == max_groupchat_index)
|
||||||
@ -92,7 +157,7 @@ int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void kill_groupchat_window(ToxWindow *self)
|
static void kill_groupchat_window(ToxWindow *self)
|
||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
@ -107,9 +172,12 @@ void kill_groupchat_window(ToxWindow *self)
|
|||||||
del_window(self);
|
del_window(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void close_groupchat(ToxWindow *self, Tox *m, int groupnum)
|
void close_groupchat(ToxWindow *self, Tox *m, int groupnum)
|
||||||
{
|
{
|
||||||
tox_del_groupchat(m, groupnum);
|
tox_del_groupchat(m, groupnum);
|
||||||
|
#ifdef AUDIO
|
||||||
|
group_audio_close_out_device(groupnum);
|
||||||
|
#endif
|
||||||
|
|
||||||
free(groupchats[groupnum].peer_names);
|
free(groupchats[groupnum].peer_names);
|
||||||
free(groupchats[groupnum].oldpeer_names);
|
free(groupchats[groupnum].oldpeer_names);
|
||||||
@ -128,6 +196,42 @@ static void close_groupchat(ToxWindow *self, Tox *m, int groupnum)
|
|||||||
kill_groupchat_window(self);
|
kill_groupchat_window(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* destroys and re-creates groupchat window with or without the peerlist */
|
||||||
|
void redraw_groupchat_win(ToxWindow *self)
|
||||||
|
{
|
||||||
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
|
endwin();
|
||||||
|
refresh();
|
||||||
|
clear();
|
||||||
|
|
||||||
|
int x2, y2;
|
||||||
|
getmaxyx(stdscr, y2, x2);
|
||||||
|
y2 -= 2;
|
||||||
|
|
||||||
|
if (ctx->sidebar) {
|
||||||
|
delwin(ctx->sidebar);
|
||||||
|
ctx->sidebar = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
delwin(ctx->linewin);
|
||||||
|
delwin(ctx->history);
|
||||||
|
delwin(self->window);
|
||||||
|
|
||||||
|
self->window = newwin(y2, x2, 0, 0);
|
||||||
|
ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
|
||||||
|
|
||||||
|
if (self->show_peerlist) {
|
||||||
|
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2 - SIDEBAR_WIDTH - 1, 0, 0);
|
||||||
|
ctx->sidebar = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, SIDEBAR_WIDTH, 0, x2 - SIDEBAR_WIDTH);
|
||||||
|
} else {
|
||||||
|
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollok(ctx->history, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, int groupnum, int peernum,
|
static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, int groupnum, int peernum,
|
||||||
const char *msg, uint16_t len)
|
const char *msg, uint16_t len)
|
||||||
{
|
{
|
||||||
@ -137,20 +241,20 @@ static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, int groupnum, int
|
|||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
char nick[TOX_MAX_NAME_LENGTH];
|
char nick[TOX_MAX_NAME_LENGTH];
|
||||||
int n_len = tox_group_peername(m, groupnum, peernum, (uint8_t *) nick);
|
get_group_nick_truncate(m, nick, peernum, groupnum);
|
||||||
n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH - 1); /* enforce client max name length */
|
|
||||||
nick[n_len] = '\0';
|
|
||||||
|
|
||||||
char selfnick[TOX_MAX_NAME_LENGTH];
|
char selfnick[TOX_MAX_NAME_LENGTH];
|
||||||
uint16_t sn_len = tox_get_self_name(m, (uint8_t *) selfnick);
|
tox_self_get_name(m, (uint8_t *) selfnick);
|
||||||
|
|
||||||
|
size_t sn_len = tox_self_get_name_size(m);
|
||||||
selfnick[sn_len] = '\0';
|
selfnick[sn_len] = '\0';
|
||||||
|
|
||||||
int nick_clr = strcmp(nick, selfnick) == 0 ? GREEN : CYAN;
|
int nick_clr = strcmp(nick, selfnick) == 0 ? GREEN : CYAN;
|
||||||
|
|
||||||
/* Only play sound if mentioned */
|
/* Only play sound if mentioned by someone else */
|
||||||
if (strcasestr(msg, selfnick) && strncmp(selfnick, nick, TOXIC_MAX_NAME_LENGTH - 1)) {
|
if (strcasestr(msg, selfnick) && strcmp(selfnick, nick)) {
|
||||||
sound_notify(self, generic_message, NT_WNDALERT_0, NULL);
|
sound_notify(self, generic_message, NT_WNDALERT_0, NULL);
|
||||||
|
|
||||||
if (self->active_box != -1)
|
if (self->active_box != -1)
|
||||||
box_silent_notify2(self, NT_NOFOCUS, self->active_box, "%s %s", nick, msg);
|
box_silent_notify2(self, NT_NOFOCUS, self->active_box, "%s %s", nick, msg);
|
||||||
else
|
else
|
||||||
@ -158,7 +262,9 @@ static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, int groupnum, int
|
|||||||
|
|
||||||
nick_clr = RED;
|
nick_clr = RED;
|
||||||
}
|
}
|
||||||
else sound_notify(self, silent, NT_WNDALERT_1, NULL);
|
else {
|
||||||
|
sound_notify(self, silent, NT_WNDALERT_1, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
char timefrmt[TIME_STR_SIZE];
|
char timefrmt[TIME_STR_SIZE];
|
||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
@ -175,29 +281,26 @@ static void groupchat_onGroupAction(ToxWindow *self, Tox *m, int groupnum, int p
|
|||||||
|
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
|
char nick[TOX_MAX_NAME_LENGTH];
|
||||||
|
get_group_nick_truncate(m, nick, peernum, groupnum);
|
||||||
|
|
||||||
char selfnick[TOX_MAX_NAME_LENGTH];
|
char selfnick[TOX_MAX_NAME_LENGTH];
|
||||||
uint16_t n_len = tox_get_self_name(m, (uint8_t *) selfnick);
|
tox_self_get_name(m, (uint8_t *) selfnick);
|
||||||
|
|
||||||
|
size_t n_len = tox_self_get_name_size(m);
|
||||||
selfnick[n_len] = '\0';
|
selfnick[n_len] = '\0';
|
||||||
|
|
||||||
if (strcasestr(action, selfnick)) {
|
if (strcasestr(action, selfnick)) {
|
||||||
sound_notify(self, generic_message, NT_WNDALERT_0, NULL);
|
sound_notify(self, generic_message, NT_WNDALERT_0, NULL);
|
||||||
|
|
||||||
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';
|
|
||||||
|
|
||||||
if (self->active_box != -1)
|
if (self->active_box != -1)
|
||||||
box_silent_notify2(self, NT_NOFOCUS, self->active_box, "* %s %s", nick, action );
|
box_silent_notify2(self, NT_NOFOCUS, self->active_box, "* %s %s", nick, action );
|
||||||
else
|
else
|
||||||
box_silent_notify(self, NT_NOFOCUS, &self->active_box, self->name, "* %s %s", nick, action);
|
box_silent_notify(self, NT_NOFOCUS, &self->active_box, self->name, "* %s %s", nick, action);
|
||||||
}
|
}
|
||||||
else sound_notify(self, silent, NT_WNDALERT_1, NULL);
|
else {
|
||||||
|
sound_notify(self, silent, NT_WNDALERT_1, NULL);
|
||||||
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';
|
|
||||||
|
|
||||||
char timefrmt[TIME_STR_SIZE];
|
char timefrmt[TIME_STR_SIZE];
|
||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
@ -206,6 +309,32 @@ static void groupchat_onGroupAction(ToxWindow *self, Tox *m, int groupnum, int p
|
|||||||
write_to_log(action, nick, ctx->log, true);
|
write_to_log(action, nick, ctx->log, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void groupchat_onGroupTitleChange(ToxWindow *self, Tox *m, int groupnum, int peernum, const char *title,
|
||||||
|
uint8_t length)
|
||||||
|
{
|
||||||
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
|
if (self->num != groupnum)
|
||||||
|
return;
|
||||||
|
|
||||||
|
set_window_title(self, title, length);
|
||||||
|
|
||||||
|
char timefrmt[TIME_STR_SIZE];
|
||||||
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
|
|
||||||
|
/* don't announce title when we join the room */
|
||||||
|
if (!timed_out(groupchats[self->num].start_time, get_unix_time(), GROUP_EVENT_WAIT))
|
||||||
|
return;
|
||||||
|
|
||||||
|
char nick[TOX_MAX_NAME_LENGTH];
|
||||||
|
get_group_nick_truncate(m, nick, peernum, groupnum);
|
||||||
|
line_info_add(self, timefrmt, nick, NULL, NAME_CHANGE, 0, 0, " set the group title to: %s", title);
|
||||||
|
|
||||||
|
char tmp_event[MAX_STR_SIZE];
|
||||||
|
snprintf(tmp_event, sizeof(tmp_event), "set title to %s", title);
|
||||||
|
write_to_log(tmp_event, nick, ctx->log, true);
|
||||||
|
}
|
||||||
|
|
||||||
/* Puts two copies of peerlist/lengths in chat instance */
|
/* Puts two copies of peerlist/lengths in chat instance */
|
||||||
static void copy_peernames(int gnum, uint8_t peerlist[][TOX_MAX_NAME_LENGTH], uint16_t lengths[], int npeers)
|
static void copy_peernames(int gnum, uint8_t peerlist[][TOX_MAX_NAME_LENGTH], uint16_t lengths[], int npeers)
|
||||||
{
|
{
|
||||||
@ -227,31 +356,75 @@ static void copy_peernames(int gnum, uint8_t peerlist[][TOX_MAX_NAME_LENGTH], ui
|
|||||||
exit_toxic_err("failed in copy_peernames", FATALERR_MEMORY);
|
exit_toxic_err("failed in copy_peernames", FATALERR_MEMORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t unknown_len = (uint16_t) strlen(UNKNOWN_NAME);
|
uint16_t u_len = strlen(UNKNOWN_NAME);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < npeers; ++i) {
|
for (i = 0; i < npeers; ++i) {
|
||||||
if (string_is_empty((char *) peerlist[i])) {
|
if (!lengths[i]) {
|
||||||
memcpy(&groupchats[gnum].peer_names[i * N], UNKNOWN_NAME, sizeof(UNKNOWN_NAME));
|
memcpy(&groupchats[gnum].peer_names[i * N], UNKNOWN_NAME, u_len);
|
||||||
groupchats[gnum].peer_name_lengths[i] = unknown_len;
|
groupchats[gnum].peer_names[i * N + u_len] = '\0';
|
||||||
|
groupchats[gnum].peer_name_lengths[i] = u_len;
|
||||||
} else {
|
} else {
|
||||||
memcpy(&groupchats[gnum].peer_names[i * N], peerlist[i], N);
|
uint16_t n_len = MIN(lengths[i], TOXIC_MAX_NAME_LENGTH - 1);
|
||||||
uint16_t n_len = lengths[i];
|
memcpy(&groupchats[gnum].peer_names[i * N], peerlist[i], n_len);
|
||||||
|
|
||||||
n_len = MIN(n_len, TOXIC_MAX_NAME_LENGTH - 1);
|
|
||||||
|
|
||||||
groupchats[gnum].peer_names[i * N + n_len] = '\0';
|
groupchats[gnum].peer_names[i * N + n_len] = '\0';
|
||||||
groupchats[gnum].peer_name_lengths[i] = n_len;
|
groupchats[gnum].peer_name_lengths[i] = n_len;
|
||||||
|
filter_str((char *) &groupchats[gnum].peer_names[i * N], n_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(groupchats[gnum].oldpeer_names, groupchats[gnum].peer_names, N * npeers);
|
memcpy(groupchats[gnum].oldpeer_names, groupchats[gnum].peer_names, N * npeers);
|
||||||
memcpy(groupchats[gnum].oldpeer_name_lengths, groupchats[gnum].peer_name_lengths,
|
memcpy(groupchats[gnum].oldpeer_name_lengths, groupchats[gnum].peer_name_lengths, sizeof(uint16_t) * npeers);
|
||||||
sizeof(uint16_t) * npeers);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnum, int peernum,
|
struct group_add_thrd {
|
||||||
uint8_t change)
|
Tox *m;
|
||||||
|
ToxWindow *self;
|
||||||
|
int peernum;
|
||||||
|
int groupnum;
|
||||||
|
uint64_t timestamp;
|
||||||
|
pthread_t tid;
|
||||||
|
pthread_attr_t attr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Waits GROUP_EVENT_WAIT seconds for a new peer to set their name before announcing them */
|
||||||
|
void *group_add_wait(void *data)
|
||||||
|
{
|
||||||
|
struct group_add_thrd *thrd = (struct group_add_thrd *) data;
|
||||||
|
ToxWindow *self = thrd->self;
|
||||||
|
Tox *m = thrd->m;
|
||||||
|
char peername[TOX_MAX_NAME_LENGTH];
|
||||||
|
|
||||||
|
/* keep polling for a name that differs from the default until we run out of time */
|
||||||
|
while (true) {
|
||||||
|
usleep(100000);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
|
get_group_nick_truncate(m, peername, thrd->peernum, thrd->groupnum);
|
||||||
|
|
||||||
|
if (strcmp(peername, DEFAULT_TOX_NAME) || timed_out(thrd->timestamp, get_unix_time(), GROUP_EVENT_WAIT)) {
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *event = "has joined the room";
|
||||||
|
char timefrmt[TIME_STR_SIZE];
|
||||||
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
|
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
|
line_info_add(self, timefrmt, (char *) peername, NULL, CONNECTION, 0, GREEN, event);
|
||||||
|
write_to_log(event, (char *) peername, self->chatwin->log, true);
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
|
pthread_attr_destroy(&thrd->attr);
|
||||||
|
free(thrd);
|
||||||
|
pthread_exit(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnum, int peernum, uint8_t change)
|
||||||
{
|
{
|
||||||
if (self->num != groupnum)
|
if (self->num != groupnum)
|
||||||
return;
|
return;
|
||||||
@ -278,7 +451,12 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu
|
|||||||
/* Update name/len lists */
|
/* Update name/len lists */
|
||||||
uint8_t tmp_peerlist[num_peers][TOX_MAX_NAME_LENGTH];
|
uint8_t tmp_peerlist[num_peers][TOX_MAX_NAME_LENGTH];
|
||||||
uint16_t tmp_peerlens[num_peers];
|
uint16_t tmp_peerlens[num_peers];
|
||||||
tox_group_get_names(m, groupnum, tmp_peerlist, tmp_peerlens, num_peers);
|
|
||||||
|
if (tox_group_get_names(m, groupnum, tmp_peerlist, tmp_peerlens, num_peers) == -1) {
|
||||||
|
memset(tmp_peerlist, 0, sizeof(tmp_peerlist));
|
||||||
|
memset(tmp_peerlens, 0, sizeof(tmp_peerlens));
|
||||||
|
}
|
||||||
|
|
||||||
copy_peernames(groupnum, tmp_peerlist, tmp_peerlens, num_peers);
|
copy_peernames(groupnum, tmp_peerlist, tmp_peerlens, num_peers);
|
||||||
|
|
||||||
/* get current peername then sort namelist */
|
/* get current peername then sort namelist */
|
||||||
@ -300,14 +478,38 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu
|
|||||||
|
|
||||||
switch (change) {
|
switch (change) {
|
||||||
case TOX_CHAT_CHANGE_PEER_ADD:
|
case TOX_CHAT_CHANGE_PEER_ADD:
|
||||||
event = "has joined the room";
|
if (!timed_out(groupchats[groupnum].start_time, get_unix_time(), GROUP_EVENT_WAIT))
|
||||||
line_info_add(self, timefrmt, (char *) peername, NULL, CONNECTION, 0, GREEN, event);
|
break;
|
||||||
write_to_log(event, (char *) peername, ctx->log, true);
|
|
||||||
|
struct group_add_thrd *thrd = malloc(sizeof(struct group_add_thrd));
|
||||||
|
thrd->m = m;
|
||||||
|
thrd->peernum = peernum;
|
||||||
|
thrd->groupnum = groupnum;
|
||||||
|
thrd->self = self;
|
||||||
|
thrd->timestamp = get_unix_time();
|
||||||
|
|
||||||
|
if (pthread_attr_init(&thrd->attr) != 0) {
|
||||||
|
free(thrd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pthread_attr_setdetachstate(&thrd->attr, PTHREAD_CREATE_DETACHED) != 0) {
|
||||||
|
pthread_attr_destroy(&thrd->attr);
|
||||||
|
free(thrd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pthread_create(&thrd->tid, &thrd->attr, group_add_wait, (void *) thrd) != 0) {
|
||||||
|
pthread_attr_destroy(&thrd->attr);
|
||||||
|
free(thrd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_CHAT_CHANGE_PEER_DEL:
|
case TOX_CHAT_CHANGE_PEER_DEL:
|
||||||
event = "has left the room";
|
event = "has left the room";
|
||||||
line_info_add(self, timefrmt, (char *) oldpeername, NULL, CONNECTION, 0, RED, event);
|
line_info_add(self, timefrmt, (char *) oldpeername, NULL, DISCONNECTION, 0, RED, event);
|
||||||
|
|
||||||
if (groupchats[self->num].side_pos > 0)
|
if (groupchats[self->num].side_pos > 0)
|
||||||
--groupchats[self->num].side_pos;
|
--groupchats[self->num].side_pos;
|
||||||
@ -316,6 +518,13 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_CHAT_CHANGE_PEER_NAME:
|
case TOX_CHAT_CHANGE_PEER_NAME:
|
||||||
|
if (!timed_out(groupchats[self->num].start_time, get_unix_time(), GROUP_EVENT_WAIT))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* ignore initial name change (TODO: this is a bad way to do this) */
|
||||||
|
if (strcmp((char *) oldpeername, DEFAULT_TOX_NAME) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
event = " is now known as ";
|
event = " is now known as ";
|
||||||
line_info_add(self, timefrmt, (char *) oldpeername, (char *) peername, NAME_CHANGE, 0, 0, event);
|
line_info_add(self, timefrmt, (char *) oldpeername, (char *) peername, NAME_CHANGE, 0, 0, event);
|
||||||
|
|
||||||
@ -374,12 +583,12 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
|
|
||||||
/* TODO: make this not suck */
|
/* TODO: make this not suck */
|
||||||
if (ctx->line[0] != L'/' || wcscmp(ctx->line, L"/me") == 0) {
|
if (ctx->line[0] != L'/' || wcscmp(ctx->line, L"/me") == 0) {
|
||||||
diff = complete_line(self, groupchats[self->num].peer_names, groupchats[self->num].num_peers,
|
diff = complete_line(self, groupchats[self->num].peer_names, groupchats[self->num].num_peers,
|
||||||
TOX_MAX_NAME_LENGTH);
|
TOX_MAX_NAME_LENGTH);
|
||||||
} else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) {
|
} else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) {
|
||||||
diff = dir_match(self, m, ctx->line, L"/avatar");
|
diff = dir_match(self, m, ctx->line, L"/avatar");
|
||||||
} else {
|
} else {
|
||||||
diff = complete_line(self, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
|
diff = complete_line(self, group_cmd_list, AC_NUM_GROUP_COMMANDS, MAX_CMDNAME_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (diff != -1) {
|
if (diff != -1) {
|
||||||
@ -388,10 +597,10 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
|
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sound_notify(self, error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sound_notify(self, error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
}
|
}
|
||||||
} else if (key == user_settings->key_peer_list_down) { /* Scroll peerlist up and down one position */
|
} else if (key == user_settings->key_peer_list_down) { /* Scroll peerlist up and down one position */
|
||||||
int L = y2 - CHATBOX_HEIGHT - SDBAR_OFST;
|
int L = y2 - CHATBOX_HEIGHT - SDBAR_OFST;
|
||||||
@ -450,35 +659,37 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]);
|
mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]);
|
||||||
|
|
||||||
wclear(ctx->sidebar);
|
wclear(ctx->sidebar);
|
||||||
|
|
||||||
mvwhline(self->window, y2 - CHATBOX_HEIGHT, 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);
|
|
||||||
|
|
||||||
int num_peers = groupchats[self->num].num_peers;
|
if (self->show_peerlist) {
|
||||||
|
mvwvline(ctx->sidebar, 0, 0, ACS_VLINE, y2 - CHATBOX_HEIGHT);
|
||||||
|
mvwaddch(ctx->sidebar, y2 - CHATBOX_HEIGHT, 0, ACS_BTEE);
|
||||||
|
|
||||||
wmove(ctx->sidebar, 0, 1);
|
int num_peers = groupchats[self->num].num_peers;
|
||||||
wattron(ctx->sidebar, A_BOLD);
|
|
||||||
wprintw(ctx->sidebar, "Peers: %d\n", num_peers);
|
|
||||||
wattroff(ctx->sidebar, A_BOLD);
|
|
||||||
|
|
||||||
mvwaddch(ctx->sidebar, 1, 0, ACS_LTEE);
|
wmove(ctx->sidebar, 0, 1);
|
||||||
mvwhline(ctx->sidebar, 1, 1, ACS_HLINE, SIDEBAR_WIDTH - 1);
|
wattron(ctx->sidebar, A_BOLD);
|
||||||
|
wprintw(ctx->sidebar, "Peers: %d\n", num_peers);
|
||||||
|
wattroff(ctx->sidebar, A_BOLD);
|
||||||
|
|
||||||
int N = TOX_MAX_NAME_LENGTH;
|
mvwaddch(ctx->sidebar, 1, 0, ACS_LTEE);
|
||||||
int maxlines = y2 - SDBAR_OFST - CHATBOX_HEIGHT;
|
mvwhline(ctx->sidebar, 1, 1, ACS_HLINE, SIDEBAR_WIDTH - 1);
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < num_peers && i < maxlines; ++i) {
|
int maxlines = y2 - SDBAR_OFST - CHATBOX_HEIGHT;
|
||||||
wmove(ctx->sidebar, i + 2, 1);
|
int i;
|
||||||
int peer = i + groupchats[self->num].side_pos;
|
|
||||||
|
|
||||||
/* truncate nick to fit in side panel without modifying list */
|
for (i = 0; i < num_peers && i < maxlines; ++i) {
|
||||||
char tmpnck[TOX_MAX_NAME_LENGTH];
|
wmove(ctx->sidebar, i + 2, 1);
|
||||||
memcpy(tmpnck, &groupchats[self->num].peer_names[peer * N], SIDEBAR_WIDTH - 2);
|
int peer = i + groupchats[self->num].side_pos;
|
||||||
tmpnck[SIDEBAR_WIDTH - 2] = '\0';
|
|
||||||
|
|
||||||
wprintw(ctx->sidebar, "%s\n", tmpnck);
|
/* truncate nick to fit in side panel without modifying list */
|
||||||
|
char tmpnck[TOX_MAX_NAME_LENGTH];
|
||||||
|
int maxlen = SIDEBAR_WIDTH - 2;
|
||||||
|
memcpy(tmpnck, &groupchats[self->num].peer_names[peer * TOX_MAX_NAME_LENGTH], maxlen);
|
||||||
|
tmpnck[maxlen] = '\0';
|
||||||
|
|
||||||
|
wprintw(ctx->sidebar, "%s\n", tmpnck);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int y, x;
|
int y, x;
|
||||||
@ -513,8 +724,8 @@ static void groupchat_onInit(ToxWindow *self, Tox *m)
|
|||||||
line_info_init(ctx->hst);
|
line_info_init(ctx->hst);
|
||||||
|
|
||||||
if (user_settings->autolog == AUTOLOG_ON) {
|
if (user_settings->autolog == AUTOLOG_ON) {
|
||||||
char myid[TOX_FRIEND_ADDRESS_SIZE];
|
char myid[TOX_ADDRESS_SIZE];
|
||||||
tox_get_address(m, (uint8_t *) myid);
|
tox_self_get_address(m, (uint8_t *) myid);
|
||||||
log_enable(self->name, myid, NULL, ctx->log, LOG_GROUP);
|
log_enable(self->name, myid, NULL, ctx->log, LOG_GROUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -524,6 +735,124 @@ static void groupchat_onInit(ToxWindow *self, Tox *m)
|
|||||||
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
|
static int group_audio_open_out_device(int groupnum)
|
||||||
|
{
|
||||||
|
char dname[MAX_STR_SIZE];
|
||||||
|
get_primary_device_name(output, dname, sizeof(dname));
|
||||||
|
dname[MAX_STR_SIZE - 1] = '\0';
|
||||||
|
|
||||||
|
groupchats[groupnum].audio.dvhandle = alcOpenDevice(dname);
|
||||||
|
|
||||||
|
if (groupchats[groupnum].audio.dvhandle == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
groupchats[groupnum].audio.dvctx = alcCreateContext(groupchats[groupnum].audio.dvhandle, NULL);
|
||||||
|
alcMakeContextCurrent(groupchats[groupnum].audio.dvctx);
|
||||||
|
alGenBuffers(OPENAL_BUFS, groupchats[groupnum].audio.buffers);
|
||||||
|
alGenSources((uint32_t) 1, &groupchats[groupnum].audio.source);
|
||||||
|
alSourcei(groupchats[groupnum].audio.source, AL_LOOPING, AL_FALSE);
|
||||||
|
|
||||||
|
if (alcGetError(groupchats[groupnum].audio.dvhandle) != AL_NO_ERROR) {
|
||||||
|
group_audio_close_out_device(groupnum);
|
||||||
|
groupchats[groupnum].audio.dvhandle = NULL;
|
||||||
|
groupchats[groupnum].audio.dvctx = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
alSourceQueueBuffers(groupchats[groupnum].audio.source, OPENAL_BUFS, groupchats[groupnum].audio.buffers);
|
||||||
|
alSourcePlay(groupchats[groupnum].audio.source);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int group_audio_close_out_device(int groupnum)
|
||||||
|
{
|
||||||
|
if (!groupchats[groupnum].audio.dvhandle)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!groupchats[groupnum].audio.dvctx)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (alcGetCurrentContext() != groupchats[groupnum].audio.dvctx)
|
||||||
|
alcMakeContextCurrent(groupchats[groupnum].audio.dvctx);
|
||||||
|
|
||||||
|
alDeleteSources((uint32_t) 1, &groupchats[groupnum].audio.source);
|
||||||
|
alDeleteBuffers(OPENAL_BUFS, groupchats[groupnum].audio.buffers);
|
||||||
|
|
||||||
|
alcMakeContextCurrent(NULL);
|
||||||
|
alcDestroyContext(groupchats[groupnum].audio.dvctx);
|
||||||
|
|
||||||
|
if (!alcCloseDevice(groupchats[groupnum].audio.dvhandle))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int group_audio_write(int peernum, int groupnum, const int16_t *pcm, unsigned int samples, uint8_t channels,
|
||||||
|
unsigned int sample_rate)
|
||||||
|
{
|
||||||
|
if (!pcm)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (channels == 0 || channels > 2)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
ALuint bufid;
|
||||||
|
ALint processed = 0, queued = 0;
|
||||||
|
|
||||||
|
alGetSourcei(groupchats[groupnum].audio.source, AL_BUFFERS_PROCESSED, &processed);
|
||||||
|
alGetSourcei(groupchats[groupnum].audio.source, AL_BUFFERS_QUEUED, &queued);
|
||||||
|
fprintf(stderr, "source: %d, queued: %d, processed: %d\n", groupchats[groupnum].audio.source, queued, processed);
|
||||||
|
|
||||||
|
if (processed) {
|
||||||
|
ALuint bufids[processed];
|
||||||
|
alSourceUnqueueBuffers(groupchats[groupnum].audio.source, processed, bufids);
|
||||||
|
alDeleteBuffers(processed - 1, bufids + 1);
|
||||||
|
bufid = bufids[0];
|
||||||
|
} else if (queued < 16) {
|
||||||
|
alGenBuffers(1, &bufid);
|
||||||
|
} else {
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
int length = samples * channels * sizeof(int16_t);
|
||||||
|
|
||||||
|
alBufferData(bufid, (channels == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, pcm, length, sample_rate);
|
||||||
|
alSourceQueueBuffers(groupchats[groupnum].audio.source, 1, &bufid);
|
||||||
|
|
||||||
|
ALint state;
|
||||||
|
alGetSourcei(groupchats[groupnum].audio.source, AL_SOURCE_STATE, &state);
|
||||||
|
|
||||||
|
if (state != AL_PLAYING)
|
||||||
|
alSourcePlay(groupchats[groupnum].audio.source);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void groupchat_onWriteDevice(ToxWindow *self, Tox *m, int groupnum, int peernum, const int16_t *pcm,
|
||||||
|
unsigned int samples, uint8_t channels, unsigned int sample_rate)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (groupnum != self->num)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (peernum < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (groupchats[groupnum].audio.dvhandle == NULL)
|
||||||
|
fprintf(stderr, "dvhandle is null)\n");
|
||||||
|
|
||||||
|
if (groupchats[groupnum].audio.dvctx == NULL)
|
||||||
|
fprintf(stderr, "ctx is null\n");
|
||||||
|
|
||||||
|
int ret = group_audio_write(peernum, groupnum, pcm, samples, channels, sample_rate);
|
||||||
|
fprintf(stderr, "write: %d\n", ret);
|
||||||
|
}
|
||||||
|
#endif /* AUDIO */
|
||||||
|
|
||||||
ToxWindow new_group_chat(Tox *m, int groupnum)
|
ToxWindow new_group_chat(Tox *m, int groupnum)
|
||||||
{
|
{
|
||||||
ToxWindow ret;
|
ToxWindow ret;
|
||||||
@ -538,6 +867,11 @@ ToxWindow new_group_chat(Tox *m, int groupnum)
|
|||||||
ret.onGroupMessage = &groupchat_onGroupMessage;
|
ret.onGroupMessage = &groupchat_onGroupMessage;
|
||||||
ret.onGroupNamelistChange = &groupchat_onGroupNamelistChange;
|
ret.onGroupNamelistChange = &groupchat_onGroupNamelistChange;
|
||||||
ret.onGroupAction = &groupchat_onGroupAction;
|
ret.onGroupAction = &groupchat_onGroupAction;
|
||||||
|
ret.onGroupTitleChange = &groupchat_onGroupTitleChange;
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
|
ret.onWriteDevice = &groupchat_onWriteDevice;
|
||||||
|
#endif
|
||||||
|
|
||||||
snprintf(ret.name, sizeof(ret.name), "Group %d", groupnum);
|
snprintf(ret.name, sizeof(ret.name), "Group %d", groupnum);
|
||||||
|
|
||||||
@ -551,6 +885,7 @@ ToxWindow new_group_chat(Tox *m, int groupnum)
|
|||||||
ret.help = help;
|
ret.help = help;
|
||||||
|
|
||||||
ret.num = groupnum;
|
ret.num = groupnum;
|
||||||
|
ret.show_peerlist = true;
|
||||||
ret.active_box = -1;
|
ret.active_box = -1;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -26,23 +26,61 @@
|
|||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
|
#include "audio_call.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <OpenAL/al.h>
|
||||||
|
#include <OpenAL/alc.h>
|
||||||
|
#else
|
||||||
|
#include <AL/al.h>
|
||||||
|
#include <AL/alc.h>
|
||||||
|
/* compatibility with older versions of OpenAL */
|
||||||
|
#ifndef ALC_ALL_DEVICES_SPECIFIER
|
||||||
|
#include <AL/alext.h>
|
||||||
|
#endif /* ALC_ALL_DEVICES_SPECIFIER */
|
||||||
|
#endif /* __APPLE__ */
|
||||||
|
#endif /* AUDIO */
|
||||||
|
|
||||||
#define SIDEBAR_WIDTH 16
|
#define SIDEBAR_WIDTH 16
|
||||||
#define SDBAR_OFST 2 /* Offset for the peer number box at the top of the statusbar */
|
#define SDBAR_OFST 2 /* Offset for the peer number box at the top of the statusbar */
|
||||||
#define MAX_GROUPCHAT_NUM MAX_WINDOWS_NUM - 2
|
#define MAX_GROUPCHAT_NUM MAX_WINDOWS_NUM - 2
|
||||||
|
#define GROUP_EVENT_WAIT 3
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
|
struct GAudio {
|
||||||
|
ALCdevice *dvhandle; /* Handle of device selected/opened */
|
||||||
|
ALCcontext *dvctx;
|
||||||
|
ALuint source;
|
||||||
|
ALuint buffers[OPENAL_BUFS];
|
||||||
|
};
|
||||||
|
#endif /* AUDIO */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int chatwin;
|
int chatwin;
|
||||||
bool active;
|
bool active;
|
||||||
|
uint8_t type;
|
||||||
int num_peers;
|
int num_peers;
|
||||||
int side_pos; /* current position of the sidebar - used for scrolling up and down */
|
int side_pos; /* current position of the sidebar - used for scrolling up and down */
|
||||||
|
uint64_t start_time;
|
||||||
uint8_t *peer_names;
|
uint8_t *peer_names;
|
||||||
uint8_t *oldpeer_names;
|
uint8_t *oldpeer_names;
|
||||||
uint16_t *peer_name_lengths;
|
uint16_t *peer_name_lengths;
|
||||||
uint16_t *oldpeer_name_lengths;
|
uint16_t *oldpeer_name_lengths;
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
|
struct GAudio audio;
|
||||||
|
#endif
|
||||||
} GroupChat;
|
} GroupChat;
|
||||||
|
|
||||||
void kill_groupchat_window(ToxWindow *self);
|
void close_groupchat(ToxWindow *self, Tox *m, int groupnum);
|
||||||
int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum);
|
int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum, uint8_t type);
|
||||||
|
|
||||||
|
/* destroys and re-creates groupchat window with or without the peerlist */
|
||||||
|
void redraw_groupchat_win(ToxWindow *self);
|
||||||
|
|
||||||
ToxWindow new_group_chat(Tox *m, int groupnum);
|
ToxWindow new_group_chat(Tox *m, int groupnum);
|
||||||
|
|
||||||
#endif /* #define GROUPCHAT_H */
|
#endif /* #define GROUPCHAT_H */
|
||||||
|
50
src/help.c
50
src/help.c
@ -27,7 +27,7 @@
|
|||||||
#include "help.h"
|
#include "help.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
|
|
||||||
#define HELP_MENU_HEIGHT 8
|
#define HELP_MENU_HEIGHT 9
|
||||||
#define HELP_MENU_WIDTH 26
|
#define HELP_MENU_WIDTH 26
|
||||||
|
|
||||||
void help_init_menu(ToxWindow *self)
|
void help_init_menu(ToxWindow *self)
|
||||||
@ -86,6 +86,12 @@ static void help_draw_menu(ToxWindow *self)
|
|||||||
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||||
wprintw(win, "hat commands\n");
|
wprintw(win, "hat commands\n");
|
||||||
|
|
||||||
|
wprintw(win, " g");
|
||||||
|
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||||
|
wprintw(win, "r");
|
||||||
|
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||||
|
wprintw(win, "oup commands\n");
|
||||||
|
|
||||||
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
|
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||||
wprintw(win, " f");
|
wprintw(win, " f");
|
||||||
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||||
@ -146,7 +152,7 @@ static void help_draw_global(ToxWindow *self)
|
|||||||
wprintw(win, " /note <msg> : Set a personal note\n");
|
wprintw(win, " /note <msg> : Set a personal note\n");
|
||||||
wprintw(win, " /nick <nick> : Set your nickname\n");
|
wprintw(win, " /nick <nick> : Set your nickname\n");
|
||||||
wprintw(win, " /log <on> or <off> : Enable/disable logging\n");
|
wprintw(win, " /log <on> or <off> : Enable/disable logging\n");
|
||||||
wprintw(win, " /groupchat : Create a group chat\n");
|
wprintw(win, " /group <type> : Create a group chat where type: text | audio\n");
|
||||||
wprintw(win, " /myid : Print your Tox ID\n");
|
wprintw(win, " /myid : Print your Tox ID\n");
|
||||||
wprintw(win, " /clear : Clear window history\n");
|
wprintw(win, " /clear : Clear window history\n");
|
||||||
wprintw(win, " /close : Close the current chat window\n");
|
wprintw(win, " /close : Close the current chat window\n");
|
||||||
@ -194,7 +200,7 @@ static void help_draw_chat(ToxWindow *self)
|
|||||||
wprintw(win, " /hangup : Hangup active call\n");
|
wprintw(win, " /hangup : Hangup active call\n");
|
||||||
wprintw(win, " /sdev <type> <id> : Change active device\n");
|
wprintw(win, " /sdev <type> <id> : Change active device\n");
|
||||||
wprintw(win, " /mute <type> : Mute active device if in call\n");
|
wprintw(win, " /mute <type> : Mute active device if in call\n");
|
||||||
wprintw(win, " /sense <n> : VAD sensitivity treshold\n");
|
wprintw(win, " /sense <n> : VAD sensitivity threshold\n");
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
help_draw_bottom_menu(win);
|
help_draw_bottom_menu(win);
|
||||||
@ -217,7 +223,8 @@ static void help_draw_keys(ToxWindow *self)
|
|||||||
wprintw(win, " Page Up and Page Down : Scroll window history one line\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+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+H : Move to the bottom of window history\n");
|
||||||
wprintw(win, " Ctrl+[ and Ctrl+] : Scroll peer list in groupchats\n\n");
|
wprintw(win, " Ctrl+[ and Ctrl+] : Scroll peer list in groupchats\n");
|
||||||
|
wprintw(win, " Ctrl+B : Toggle the groupchat peerlist\n\n");
|
||||||
wprintw(win, " (Note: Custom keybindings override these defaults.)\n\n");
|
wprintw(win, " (Note: Custom keybindings override these defaults.)\n\n");
|
||||||
|
|
||||||
help_draw_bottom_menu(win);
|
help_draw_bottom_menu(win);
|
||||||
@ -226,6 +233,31 @@ static void help_draw_keys(ToxWindow *self)
|
|||||||
wrefresh(win);
|
wrefresh(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void help_draw_group(ToxWindow *self)
|
||||||
|
{
|
||||||
|
WINDOW *win = self->help->win;
|
||||||
|
|
||||||
|
wmove(win, 1, 1);
|
||||||
|
|
||||||
|
wattron(win, A_BOLD | COLOR_PAIR(RED));
|
||||||
|
wprintw(win, "Group commands:\n");
|
||||||
|
wattroff(win, A_BOLD | COLOR_PAIR(RED));
|
||||||
|
|
||||||
|
wprintw(win, " /title <msg> : Set group title (show current title if no msg)\n\n");
|
||||||
|
|
||||||
|
wattron(win, A_BOLD);
|
||||||
|
wprintw(win, " Audio commands:\n");
|
||||||
|
wattroff(win, A_BOLD);
|
||||||
|
|
||||||
|
wprintw(win, " /mute <type> : Mute active device where type: in | out\n");
|
||||||
|
wprintw(win, " /sense <n> : VAD sensitivity threshold\n\n");
|
||||||
|
|
||||||
|
help_draw_bottom_menu(win);
|
||||||
|
|
||||||
|
box(win, ACS_VLINE, ACS_HLINE);
|
||||||
|
wrefresh(win);
|
||||||
|
}
|
||||||
|
|
||||||
static void help_draw_contacts(ToxWindow *self)
|
static void help_draw_contacts(ToxWindow *self)
|
||||||
{
|
{
|
||||||
WINDOW *win = self->help->win;
|
WINDOW *win = self->help->win;
|
||||||
@ -274,13 +306,20 @@ void help_onKey(ToxWindow *self, wint_t key)
|
|||||||
self->help->type = HELP_GLOBAL;
|
self->help->type = HELP_GLOBAL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
#ifdef AUDIO /* remove if/when we add non-audio group commands */
|
||||||
|
case 'r':
|
||||||
|
help_init_window(self, 10, 80);
|
||||||
|
self->help->type = HELP_GROUP;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
help_init_window(self, 10, 80);
|
help_init_window(self, 10, 80);
|
||||||
self->help->type = HELP_CONTACTS;
|
self->help->type = HELP_CONTACTS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'k':
|
case 'k':
|
||||||
help_init_window(self, 12, 80);
|
help_init_window(self, 13, 80);
|
||||||
self->help->type = HELP_KEYS;
|
self->help->type = HELP_KEYS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -317,6 +356,7 @@ void help_onDraw(ToxWindow *self)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case HELP_GROUP:
|
case HELP_GROUP:
|
||||||
|
help_draw_group(self);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
49
src/input.c
49
src/input.c
@ -32,6 +32,10 @@
|
|||||||
#include "toxic_strings.h"
|
#include "toxic_strings.h"
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
|
#include "groupchat.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
|
extern struct user_settings *user_settings;
|
||||||
|
|
||||||
/* add a char to input field and buffer */
|
/* add a char to input field and buffer */
|
||||||
void input_new_char(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y)
|
void input_new_char(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y)
|
||||||
@ -42,12 +46,12 @@ void input_new_char(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_
|
|||||||
|
|
||||||
/* this is the only place we need to do this check */
|
/* this is the only place we need to do this check */
|
||||||
if (cur_len == -1) {
|
if (cur_len == -1) {
|
||||||
sound_notify(self, error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (add_char_to_buf(ctx, key) == -1) {
|
if (add_char_to_buf(ctx, key) == -1) {
|
||||||
sound_notify(self, error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +67,7 @@ static void input_backspace(ToxWindow *self, int x, int mx_x)
|
|||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
if (del_char_buf_bck(ctx) == -1) {
|
if (del_char_buf_bck(ctx) == -1) {
|
||||||
sound_notify(self, error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,21 +84,32 @@ static void input_backspace(ToxWindow *self, int x, int mx_x)
|
|||||||
static void input_delete(ToxWindow *self)
|
static void input_delete(ToxWindow *self)
|
||||||
{
|
{
|
||||||
if (del_char_buf_frnt(self->chatwin) == -1)
|
if (del_char_buf_frnt(self->chatwin) == -1)
|
||||||
sound_notify(self, error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* delete last typed word */
|
||||||
|
static void input_del_word(ToxWindow *self, int x, int mx_x)
|
||||||
|
{
|
||||||
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
|
if (del_word_buf(ctx) == -1) {
|
||||||
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* deletes entire line before cursor from input field and buffer */
|
/* deletes entire line before cursor from input field and buffer */
|
||||||
static void input_discard(ToxWindow *self)
|
static void input_discard(ToxWindow *self)
|
||||||
{
|
{
|
||||||
if (discard_buf(self->chatwin) == -1)
|
if (discard_buf(self->chatwin) == -1)
|
||||||
sound_notify(self, error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* deletes entire line after cursor from input field and buffer */
|
/* deletes entire line after cursor from input field and buffer */
|
||||||
static void input_kill(ChatContext *ctx)
|
static void input_kill(ChatContext *ctx)
|
||||||
{
|
{
|
||||||
if (kill_buf(ctx) == -1)
|
if (kill_buf(ctx) == -1)
|
||||||
sound_notify(NULL, error, NT_ALWAYS, NULL);
|
sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void input_yank(ToxWindow *self, int x, int mx_x)
|
static void input_yank(ToxWindow *self, int x, int mx_x)
|
||||||
@ -102,7 +117,7 @@ static void input_yank(ToxWindow *self, int x, int mx_x)
|
|||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
if (yank_buf(ctx) == -1) {
|
if (yank_buf(ctx) == -1) {
|
||||||
sound_notify(self, error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,6 +228,10 @@ bool input_handle(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y)
|
|||||||
input_yank(self, x, mx_x);
|
input_yank(self, x, mx_x);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_KEY_C_W:
|
||||||
|
input_del_word(self, x, mx_x);
|
||||||
|
break;
|
||||||
|
|
||||||
case KEY_HOME:
|
case KEY_HOME:
|
||||||
case T_KEY_C_A:
|
case T_KEY_C_A:
|
||||||
input_mv_home(self);
|
input_mv_home(self);
|
||||||
@ -236,10 +255,26 @@ bool input_handle(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y)
|
|||||||
input_history(self, key, mx_x);
|
input_history(self, key, mx_x);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_KEY_C_L:
|
||||||
|
force_refresh(self->chatwin->history);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
match = false;
|
match = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: this special case is ugly.
|
||||||
|
maybe convert entire function to if/else and make them all customizable keys? */
|
||||||
|
if (!match && key == user_settings->key_toggle_peerlist) {
|
||||||
|
if (self->is_groupchat) {
|
||||||
|
self->show_peerlist ^= 1;
|
||||||
|
redraw_groupchat_win(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
match = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
103
src/line_info.c
103
src/line_info.c
@ -59,7 +59,7 @@ void line_info_reset_start(ToxWindow *self, struct history *hst)
|
|||||||
int y2, x2;
|
int y2, x2;
|
||||||
getmaxyx(self->window, y2, x2);
|
getmaxyx(self->window, y2, x2);
|
||||||
|
|
||||||
int side_offst = self->is_groupchat ? SIDEBAR_WIDTH : 0;
|
int side_offst = self->show_peerlist ? SIDEBAR_WIDTH : 0;
|
||||||
int top_offst = self->is_chat || self->is_prompt ? 2 : 0;
|
int top_offst = self->is_chat || self->is_prompt ? 2 : 0;
|
||||||
int max_y = (y2 - CHATBOX_HEIGHT - top_offst);
|
int max_y = (y2 - CHATBOX_HEIGHT - top_offst);
|
||||||
|
|
||||||
@ -130,8 +130,8 @@ static struct line_info *line_info_ret_queue(struct history *hst)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* creates new line_info line and puts it in the queue. */
|
/* creates new line_info line and puts it in the queue. */
|
||||||
void line_info_add(ToxWindow *self, char *timestr, char *name1, char *name2, uint8_t type, uint8_t bold,
|
void line_info_add(ToxWindow *self, const char *timestr, const char *name1, const char *name2, uint8_t type,
|
||||||
uint8_t colour, const char *msg, ...)
|
uint8_t bold, uint8_t colour, const char *msg, ...)
|
||||||
{
|
{
|
||||||
struct history *hst = self->chatwin->hst;
|
struct history *hst = self->chatwin->hst;
|
||||||
|
|
||||||
@ -156,23 +156,27 @@ void line_info_add(ToxWindow *self, char *timestr, char *name1, char *name2, uin
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case IN_ACTION:
|
case IN_ACTION:
|
||||||
case OUT_ACTION:
|
case OUT_ACTION:
|
||||||
len += 5;
|
len += strlen(user_settings->line_normal) + 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IN_MSG:
|
case IN_MSG:
|
||||||
case OUT_MSG:
|
case OUT_MSG:
|
||||||
len += 6;
|
len += strlen(user_settings->line_normal) + 3;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CONNECTION:
|
case CONNECTION:
|
||||||
len += 5;
|
len += strlen(user_settings->line_join) + 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DISCONNECTION:
|
||||||
|
len += strlen(user_settings->line_quit) + 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SYS_MSG:
|
case SYS_MSG:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NAME_CHANGE:
|
case NAME_CHANGE:
|
||||||
len += 4;
|
len += strlen(user_settings->line_alert) + 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PROMPT:
|
case PROMPT:
|
||||||
@ -198,7 +202,7 @@ void line_info_add(ToxWindow *self, char *timestr, char *name1, char *name2, uin
|
|||||||
|
|
||||||
if (timestr) {
|
if (timestr) {
|
||||||
snprintf(new_line->timestr, sizeof(new_line->timestr), "%s", timestr);
|
snprintf(new_line->timestr, sizeof(new_line->timestr), "%s", timestr);
|
||||||
len += strlen(new_line->timestr);
|
len += strlen(new_line->timestr) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name1) {
|
if (name1) {
|
||||||
@ -222,7 +226,7 @@ void line_info_add(ToxWindow *self, char *timestr, char *name1, char *name2, uin
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* adds a single queue item to hst if possible. only called once per call to line_info_print() */
|
/* adds a single queue item to hst if possible. only called once per call to line_info_print() */
|
||||||
static void line_info_check_queue(ToxWindow *self)
|
static void line_info_check_queue(ToxWindow *self)
|
||||||
{
|
{
|
||||||
struct history *hst = self->chatwin->hst;
|
struct history *hst = self->chatwin->hst;
|
||||||
struct line_info *line = line_info_ret_queue(hst);
|
struct line_info *line = line_info_ret_queue(hst);
|
||||||
@ -246,7 +250,7 @@ static void line_info_check_queue(ToxWindow *self)
|
|||||||
if (x2 <= SIDEBAR_WIDTH)
|
if (x2 <= SIDEBAR_WIDTH)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int offst = self->is_groupchat ? SIDEBAR_WIDTH : 0; /* offset width of groupchat sidebar */
|
int offst = self->show_peerlist ? SIDEBAR_WIDTH : 0; /* offset width of groupchat sidebar */
|
||||||
int lines = 1 + line->newlines + (line->len / (x2 - offst));
|
int lines = 1 + line->newlines + (line->len / (x2 - offst));
|
||||||
int max_y = y2 - CHATBOX_HEIGHT;
|
int max_y = y2 - CHATBOX_HEIGHT;
|
||||||
|
|
||||||
@ -258,10 +262,6 @@ static void line_info_check_queue(ToxWindow *self)
|
|||||||
++hst->start_id;
|
++hst->start_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* force move to bottom of history when we print an outgoing message */
|
|
||||||
if (line->type == OUT_MSG)
|
|
||||||
line_info_reset_start(self, hst);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NOREAD_FLAG_TIMEOUT 5 /* seconds before a sent message with no read receipt is flagged as unread */
|
#define NOREAD_FLAG_TIMEOUT 5 /* seconds before a sent message with no read receipt is flagged as unread */
|
||||||
@ -302,7 +302,7 @@ void line_info_print(ToxWindow *self)
|
|||||||
case OUT_MSG_READ:
|
case OUT_MSG_READ:
|
||||||
case IN_MSG:
|
case IN_MSG:
|
||||||
wattron(win, COLOR_PAIR(BLUE));
|
wattron(win, COLOR_PAIR(BLUE));
|
||||||
wprintw(win, "%s", line->timestr);
|
wprintw(win, "%s ", line->timestr);
|
||||||
wattroff(win, COLOR_PAIR(BLUE));
|
wattroff(win, COLOR_PAIR(BLUE));
|
||||||
|
|
||||||
int nameclr = GREEN;
|
int nameclr = GREEN;
|
||||||
@ -313,7 +313,7 @@ void line_info_print(ToxWindow *self)
|
|||||||
nameclr = CYAN;
|
nameclr = CYAN;
|
||||||
|
|
||||||
wattron(win, COLOR_PAIR(nameclr));
|
wattron(win, COLOR_PAIR(nameclr));
|
||||||
wprintw(win, "--- %s: ", line->name1);
|
wprintw(win, "%s %s: ", user_settings->line_normal, line->name1);
|
||||||
wattroff(win, COLOR_PAIR(nameclr));
|
wattroff(win, COLOR_PAIR(nameclr));
|
||||||
|
|
||||||
if (line->msg[0] == '>')
|
if (line->msg[0] == '>')
|
||||||
@ -342,11 +342,11 @@ void line_info_print(ToxWindow *self)
|
|||||||
case OUT_ACTION:
|
case OUT_ACTION:
|
||||||
case IN_ACTION:
|
case IN_ACTION:
|
||||||
wattron(win, COLOR_PAIR(BLUE));
|
wattron(win, COLOR_PAIR(BLUE));
|
||||||
wprintw(win, "%s", line->timestr);
|
wprintw(win, "%s ", line->timestr);
|
||||||
wattroff(win, COLOR_PAIR(BLUE));
|
wattroff(win, COLOR_PAIR(BLUE));
|
||||||
|
|
||||||
wattron(win, COLOR_PAIR(YELLOW));
|
wattron(win, COLOR_PAIR(YELLOW));
|
||||||
wprintw(win, "-*- %s %s", line->name1, line->msg);
|
wprintw(win, "%s %s %s", user_settings->line_normal, line->name1, line->msg);
|
||||||
wattroff(win, COLOR_PAIR(YELLOW));
|
wattroff(win, COLOR_PAIR(YELLOW));
|
||||||
|
|
||||||
if (type == OUT_ACTION && timed_out(line->timestamp, get_unix_time(), NOREAD_FLAG_TIMEOUT)) {
|
if (type == OUT_ACTION && timed_out(line->timestamp, get_unix_time(), NOREAD_FLAG_TIMEOUT)) {
|
||||||
@ -366,7 +366,7 @@ void line_info_print(ToxWindow *self)
|
|||||||
case SYS_MSG:
|
case SYS_MSG:
|
||||||
if (line->timestr[0]) {
|
if (line->timestr[0]) {
|
||||||
wattron(win, COLOR_PAIR(BLUE));
|
wattron(win, COLOR_PAIR(BLUE));
|
||||||
wprintw(win, "%s", line->timestr);
|
wprintw(win, "%s ", line->timestr);
|
||||||
wattroff(win, COLOR_PAIR(BLUE));
|
wattroff(win, COLOR_PAIR(BLUE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,11 +399,28 @@ void line_info_print(ToxWindow *self)
|
|||||||
|
|
||||||
case CONNECTION:
|
case CONNECTION:
|
||||||
wattron(win, COLOR_PAIR(BLUE));
|
wattron(win, COLOR_PAIR(BLUE));
|
||||||
wprintw(win, "%s", line->timestr);
|
wprintw(win, "%s ", line->timestr);
|
||||||
wattroff(win, COLOR_PAIR(BLUE));
|
wattroff(win, COLOR_PAIR(BLUE));
|
||||||
|
|
||||||
wattron(win, COLOR_PAIR(line->colour));
|
wattron(win, COLOR_PAIR(line->colour));
|
||||||
wprintw(win, "%s ", line->colour == RED ? "<--" : "-->");
|
wprintw(win, "%s ", user_settings->line_join);
|
||||||
|
|
||||||
|
wattron(win, A_BOLD);
|
||||||
|
wprintw(win, "%s ", line->name1);
|
||||||
|
wattroff(win, A_BOLD);
|
||||||
|
|
||||||
|
wprintw(win, "%s\n", line->msg);
|
||||||
|
wattroff(win, COLOR_PAIR(line->colour));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DISCONNECTION:
|
||||||
|
wattron(win, COLOR_PAIR(BLUE));
|
||||||
|
wprintw(win, "%s ", line->timestr);
|
||||||
|
wattroff(win, COLOR_PAIR(BLUE));
|
||||||
|
|
||||||
|
wattron(win, COLOR_PAIR(line->colour));
|
||||||
|
wprintw(win, "%s ", user_settings->line_quit);
|
||||||
|
|
||||||
wattron(win, A_BOLD);
|
wattron(win, A_BOLD);
|
||||||
wprintw(win, "%s ", line->name1);
|
wprintw(win, "%s ", line->name1);
|
||||||
@ -416,11 +433,11 @@ void line_info_print(ToxWindow *self)
|
|||||||
|
|
||||||
case NAME_CHANGE:
|
case NAME_CHANGE:
|
||||||
wattron(win, COLOR_PAIR(BLUE));
|
wattron(win, COLOR_PAIR(BLUE));
|
||||||
wprintw(win, "%s", line->timestr);
|
wprintw(win, "%s ", line->timestr);
|
||||||
wattroff(win, COLOR_PAIR(BLUE));
|
wattroff(win, COLOR_PAIR(BLUE));
|
||||||
|
|
||||||
wattron(win, COLOR_PAIR(MAGENTA));
|
wattron(win, COLOR_PAIR(MAGENTA));
|
||||||
wprintw(win, "-!- ");
|
wprintw(win, "%s ", user_settings->line_alert);
|
||||||
wattron(win, A_BOLD);
|
wattron(win, A_BOLD);
|
||||||
wprintw(win, "%s", line->name1);
|
wprintw(win, "%s", line->name1);
|
||||||
wattroff(win, A_BOLD);
|
wattroff(win, A_BOLD);
|
||||||
@ -467,14 +484,14 @@ static void line_info_scroll_up(struct history *hst)
|
|||||||
{
|
{
|
||||||
if (hst->line_start->prev)
|
if (hst->line_start->prev)
|
||||||
hst->line_start = hst->line_start->prev;
|
hst->line_start = hst->line_start->prev;
|
||||||
else sound_notify(NULL, error, NT_ALWAYS, NULL);
|
else sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void line_info_scroll_down(struct history *hst)
|
static void line_info_scroll_down(struct history *hst)
|
||||||
{
|
{
|
||||||
if (hst->line_start->next)
|
if (hst->line_start->next)
|
||||||
hst->line_start = hst->line_start->next;
|
hst->line_start = hst->line_start->next;
|
||||||
else sound_notify(NULL, error, NT_ALWAYS, NULL);
|
else sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void line_info_page_up(ToxWindow *self, struct history *hst)
|
static void line_info_page_up(ToxWindow *self, struct history *hst)
|
||||||
@ -506,24 +523,24 @@ bool line_info_onKey(ToxWindow *self, wint_t key)
|
|||||||
struct history *hst = self->chatwin->hst;
|
struct history *hst = self->chatwin->hst;
|
||||||
bool match = true;
|
bool match = true;
|
||||||
|
|
||||||
if (key == user_settings->key_half_page_up) {
|
if (key == user_settings->key_half_page_up) {
|
||||||
line_info_page_up(self, hst);
|
line_info_page_up(self, hst);
|
||||||
}
|
}
|
||||||
else if (key == user_settings->key_half_page_down) {
|
else if (key == user_settings->key_half_page_down) {
|
||||||
line_info_page_down(self, hst);
|
line_info_page_down(self, hst);
|
||||||
}
|
}
|
||||||
else if (key == user_settings->key_scroll_line_up) {
|
else if (key == user_settings->key_scroll_line_up) {
|
||||||
line_info_scroll_up(hst);
|
line_info_scroll_up(hst);
|
||||||
}
|
}
|
||||||
else if (key == user_settings->key_scroll_line_down) {
|
else if (key == user_settings->key_scroll_line_down) {
|
||||||
line_info_scroll_down(hst);
|
line_info_scroll_down(hst);
|
||||||
}
|
}
|
||||||
else if (key == user_settings->key_page_bottom) {
|
else if (key == user_settings->key_page_bottom) {
|
||||||
line_info_reset_start(self, hst);
|
line_info_reset_start(self, hst);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
match = false;
|
match = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
@ -41,13 +41,14 @@ enum {
|
|||||||
OUT_ACTION_READ, /* same as OUT_MSG_READ but for actions */
|
OUT_ACTION_READ, /* same as OUT_MSG_READ but for actions */
|
||||||
PROMPT,
|
PROMPT,
|
||||||
CONNECTION,
|
CONNECTION,
|
||||||
|
DISCONNECTION,
|
||||||
NAME_CHANGE,
|
NAME_CHANGE,
|
||||||
} LINE_TYPE;
|
} LINE_TYPE;
|
||||||
|
|
||||||
struct line_info {
|
struct line_info {
|
||||||
char timestr[TIME_STR_SIZE];
|
char timestr[TIME_STR_SIZE];
|
||||||
char name1[TOXIC_MAX_NAME_LENGTH];
|
char name1[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
char name2[TOXIC_MAX_NAME_LENGTH];
|
char name2[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
char msg[MAX_LINE_INFO_MSG_SIZE];
|
char msg[MAX_LINE_INFO_MSG_SIZE];
|
||||||
uint64_t timestamp;
|
uint64_t timestamp;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
@ -74,8 +75,8 @@ struct history {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* creates new line_info line and puts it in the queue. */
|
/* creates new line_info line and puts it in the queue. */
|
||||||
void line_info_add(ToxWindow *self, char *timestr, char *name1, char *name2, uint8_t type, uint8_t bold,
|
void line_info_add(ToxWindow *self, const char *timestr, const char *name1, const char *name2, uint8_t type,
|
||||||
uint8_t colour, const char *msg, ...);
|
uint8_t bold, uint8_t colour, const char *msg, ...);
|
||||||
|
|
||||||
/* Prints a section of history starting at line_start */
|
/* Prints a section of history starting at line_start */
|
||||||
void line_info_print(ToxWindow *self);
|
void line_info_print(ToxWindow *self);
|
||||||
|
@ -134,7 +134,7 @@ void write_to_log(const char *msg, const char *name, struct chatlog *log, bool e
|
|||||||
else
|
else
|
||||||
snprintf(name_frmt, sizeof(name_frmt), "%s:", name);
|
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]";
|
const char *t = user_settings->log_timestamp_format;
|
||||||
char s[MAX_STR_SIZE];
|
char s[MAX_STR_SIZE];
|
||||||
strftime(s, MAX_STR_SIZE, t, get_time());
|
strftime(s, MAX_STR_SIZE, t, get_time());
|
||||||
fprintf(log->file, "%s %s %s\n", s, name_frmt, msg);
|
fprintf(log->file, "%s %s %s\n", s, name_frmt, msg);
|
||||||
|
@ -42,7 +42,7 @@ void cqueue_cleanup(struct chat_queue *q)
|
|||||||
free(q);
|
free(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cqueue_add(struct chat_queue *q, const char *msg, int len, uint8_t type, uint32_t line_id)
|
void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, uint32_t line_id)
|
||||||
{
|
{
|
||||||
struct cqueue_msg *new_m = malloc(sizeof(struct cqueue_msg));
|
struct cqueue_msg *new_m = malloc(sizeof(struct cqueue_msg));
|
||||||
|
|
||||||
@ -103,7 +103,9 @@ void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
char selfname[TOX_MAX_NAME_LENGTH];
|
char selfname[TOX_MAX_NAME_LENGTH];
|
||||||
uint16_t len = tox_get_self_name(m, (uint8_t *) selfname);
|
tox_self_get_name(m, (uint8_t *) selfname);
|
||||||
|
|
||||||
|
size_t len = tox_self_get_name_size(m);
|
||||||
selfname[len] = '\0';
|
selfname[len] = '\0';
|
||||||
|
|
||||||
write_to_log(msg->message, selfname, self->chatwin->log, msg->type == OUT_ACTION);
|
write_to_log(msg->message, selfname, self->chatwin->log, msg->type == OUT_ACTION);
|
||||||
@ -127,30 +129,28 @@ void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CQUEUE_TRY_SEND_INTERVAL 10
|
#define CQUEUE_TRY_SEND_INTERVAL 60
|
||||||
|
|
||||||
/* Tries to send the oldest unsent message in queue. */
|
/* Tries to send the oldest unsent message in queue. */
|
||||||
void cqueue_try_send(ToxWindow *self, Tox *m)
|
void cqueue_try_send(ToxWindow *self, Tox *m)
|
||||||
{
|
{
|
||||||
struct chat_queue *q = self->chatwin->cqueue;
|
struct chat_queue *q = self->chatwin->cqueue;
|
||||||
struct cqueue_msg *msg = q->root;
|
struct cqueue_msg *msg = q->root;
|
||||||
|
|
||||||
|
if (!msg)
|
||||||
|
return;
|
||||||
|
|
||||||
uint64_t curtime = get_unix_time();
|
uint64_t curtime = get_unix_time();
|
||||||
|
|
||||||
while (msg) {
|
if (msg->receipt != 0 && !timed_out(msg->last_send_try, curtime, CQUEUE_TRY_SEND_INTERVAL))
|
||||||
if (msg->receipt != 0 && !timed_out(msg->last_send_try, curtime, CQUEUE_TRY_SEND_INTERVAL)) {
|
|
||||||
msg = msg->next;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t receipt = 0;
|
|
||||||
|
|
||||||
if (msg->type == OUT_MSG)
|
|
||||||
receipt = tox_send_message(m, self->num, (uint8_t *) msg->message, msg->len);
|
|
||||||
else
|
|
||||||
receipt = tox_send_action(m, self->num, (uint8_t *) msg->message, msg->len);
|
|
||||||
|
|
||||||
msg->last_send_try = curtime;
|
|
||||||
msg->receipt = receipt;
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
uint32_t receipt = 0;
|
||||||
|
|
||||||
|
TOX_MESSAGE_TYPE type = msg->type == OUT_MSG ? TOX_MESSAGE_TYPE_NORMAL : TOX_MESSAGE_TYPE_ACTION;
|
||||||
|
receipt = tox_friend_send_message(m, self->num, type, (uint8_t *) msg->message, msg->len, NULL);
|
||||||
|
|
||||||
|
msg->last_send_try = curtime;
|
||||||
|
msg->receipt = receipt;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
struct cqueue_msg {
|
struct cqueue_msg {
|
||||||
char message[MAX_STR_SIZE];
|
char message[MAX_STR_SIZE];
|
||||||
int len;
|
size_t len;
|
||||||
int line_id;
|
int line_id;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint32_t receipt;
|
uint32_t receipt;
|
||||||
@ -40,7 +40,7 @@ struct chat_queue {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void cqueue_cleanup(struct chat_queue *q);
|
void cqueue_cleanup(struct chat_queue *q);
|
||||||
void cqueue_add(struct chat_queue *q, const char *msg, int len, uint8_t type, uint32_t line_id);
|
void cqueue_add(struct chat_queue *q, const char *msg, size_t len, uint8_t type, uint32_t line_id);
|
||||||
|
|
||||||
/* Tries to send the oldest unsent message in queue. */
|
/* Tries to send the oldest unsent message in queue. */
|
||||||
void cqueue_try_send(ToxWindow *self, Tox *m);
|
void cqueue_try_send(ToxWindow *self, Tox *m);
|
||||||
@ -48,4 +48,4 @@ void cqueue_try_send(ToxWindow *self, Tox *m);
|
|||||||
/* removes message with matching receipt from queue, writes to log and updates line to show the message was received. */
|
/* removes message with matching receipt from queue, writes to log and updates line to show the message was received. */
|
||||||
void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt);
|
void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt);
|
||||||
|
|
||||||
#endif /* #define MESSAGE_QUEUE_H */
|
#endif /* #define MESSAGE_QUEUE_H */
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "file_senders.h"
|
#include "file_transfers.h"
|
||||||
|
|
||||||
extern ToxWindow *prompt;
|
extern ToxWindow *prompt;
|
||||||
extern struct user_settings *user_settings;
|
extern struct user_settings *user_settings;
|
||||||
@ -87,7 +87,7 @@ void get_time_str(char *buf, int bufsize)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *t = user_settings->time == TIME_12 ? "%I:%M:%S " : "%H:%M:%S ";
|
const char *t = user_settings->timestamp_format;
|
||||||
strftime(buf, bufsize, t, get_time());
|
strftime(buf, bufsize, t, get_time());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,8 +188,9 @@ int qsort_strcasecmp_hlpr(const void *str1, const void *str2)
|
|||||||
- cannot be empty
|
- cannot be empty
|
||||||
- cannot start with a space
|
- cannot start with a space
|
||||||
- must not contain a forward slash (for logfile naming purposes)
|
- must not contain a forward slash (for logfile naming purposes)
|
||||||
- must not contain contiguous spaces */
|
- must not contain contiguous spaces
|
||||||
int valid_nick(char *nick)
|
- must not contain a newline or tab seqeunce */
|
||||||
|
int valid_nick(const char *nick)
|
||||||
{
|
{
|
||||||
if (!nick[0] || nick[0] == ' ')
|
if (!nick[0] || nick[0] == ' ')
|
||||||
return 0;
|
return 0;
|
||||||
@ -197,16 +198,30 @@ int valid_nick(char *nick)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; nick[i]; ++i) {
|
for (i = 0; nick[i]; ++i) {
|
||||||
if (nick[i] == ' ' && nick[i + 1] == ' ')
|
if ((nick[i] == ' ' && nick[i + 1] == ' ')
|
||||||
return 0;
|
|| nick[i] == '/'
|
||||||
|
|| nick[i] == '\n'
|
||||||
|
|| nick[i] == '\t'
|
||||||
|
|| nick[i] == '\v'
|
||||||
|
|| nick[i] == '\r')
|
||||||
|
|
||||||
if (nick[i] == '/')
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Converts all newline/tab chars to spaces (use for strings that should be contained to a single line) */
|
||||||
|
void filter_str(char *str, size_t len)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; ++i) {
|
||||||
|
if (str[i] == '\n' || str[i] == '\r' || str[i] == '\t' || str[i] == '\v')
|
||||||
|
str[i] = ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* gets base file name from path or original file name if no path is supplied */
|
/* gets base file name from path or original file name if no path is supplied */
|
||||||
void get_file_name(char *namebuf, int bufsize, const char *pathname)
|
void get_file_name(char *namebuf, int bufsize, const char *pathname)
|
||||||
{
|
{
|
||||||
@ -246,12 +261,48 @@ void str_to_lower(char *str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* puts friendnum's nick in buf, truncating at TOXIC_MAX_NAME_LENGTH if necessary.
|
/* puts friendnum's nick in buf, truncating at TOXIC_MAX_NAME_LENGTH if necessary.
|
||||||
Returns nick len on success, -1 on failure */
|
if toxcore API call fails, put UNKNOWN_NAME in buf
|
||||||
int get_nick_truncate(Tox *m, char *buf, int friendnum)
|
Returns nick len */
|
||||||
|
size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum)
|
||||||
{
|
{
|
||||||
int len = tox_get_name(m, friendnum, (uint8_t *) buf);
|
size_t len = tox_friend_get_name_size(m, friendnum, NULL);
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
strcpy(buf, UNKNOWN_NAME);
|
||||||
|
len = strlen(UNKNOWN_NAME);
|
||||||
|
} else {
|
||||||
|
tox_friend_get_name(m, friendnum, (uint8_t *) buf, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
|
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
|
||||||
buf[len] = '\0';
|
buf[len] = '\0';
|
||||||
|
filter_str(buf, len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* same as get_nick_truncate but for groupchats */
|
||||||
|
int get_group_nick_truncate(Tox *m, char *buf, int peernum, int groupnum)
|
||||||
|
{
|
||||||
|
int len = tox_group_peername(m, groupnum, peernum, (uint8_t *) buf);
|
||||||
|
|
||||||
|
if (len == -1) {
|
||||||
|
strcpy(buf, UNKNOWN_NAME);
|
||||||
|
len = strlen(UNKNOWN_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
|
||||||
|
buf[len] = '\0';
|
||||||
|
filter_str(buf, len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copies data to msg buffer.
|
||||||
|
returns length of msg, which will be no larger than size-1 */
|
||||||
|
size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length)
|
||||||
|
{
|
||||||
|
size_t len = MIN(length, size - 1);
|
||||||
|
memcpy(msg, data, len);
|
||||||
|
msg[len] = '\0';
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,18 +363,18 @@ bool file_exists(const char *path)
|
|||||||
return stat(path, &s) == 0;
|
return stat(path, &s) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns file size or -1 on error */
|
/* returns file size or 0 on error */
|
||||||
off_t file_size(const char *path)
|
off_t file_size(const char *path)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if (stat(path, &st) == -1)
|
if (stat(path, &st) == -1)
|
||||||
return -1;
|
return 0;
|
||||||
|
|
||||||
return st.st_size;
|
return st.st_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* compares the first size bytes of fp to signature.
|
/* compares the first size bytes of fp to signature.
|
||||||
Returns 0 if they are the same, 1 if they differ, and -1 on error.
|
Returns 0 if they are the same, 1 if they differ, and -1 on error.
|
||||||
|
|
||||||
On success this function will seek back to the beginning of fp */
|
On success this function will seek back to the beginning of fp */
|
||||||
@ -341,3 +392,21 @@ int check_file_signature(const char *signature, size_t size, FILE *fp)
|
|||||||
|
|
||||||
return ret == 0 ? 0 : 1;
|
return ret == 0 ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* sets window title in tab bar. */
|
||||||
|
void set_window_title(ToxWindow *self, const char *title, int len)
|
||||||
|
{
|
||||||
|
char cpy[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
|
|
||||||
|
if (self->is_groupchat) /* keep groupnumber in title */
|
||||||
|
snprintf(cpy, sizeof(cpy), "%d %s", self->num, title);
|
||||||
|
else
|
||||||
|
snprintf(cpy, sizeof(cpy), "%s", title);
|
||||||
|
|
||||||
|
if (len > MAX_WINDOW_NAME_LENGTH) {
|
||||||
|
strcpy(&cpy[MAX_WINDOW_NAME_LENGTH - 3], "...");
|
||||||
|
cpy[MAX_WINDOW_NAME_LENGTH] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(self->name, sizeof(self->name), "%s", cpy);
|
||||||
|
}
|
||||||
|
@ -87,8 +87,12 @@ int qsort_strcasecmp_hlpr(const void *str1, const void *str2);
|
|||||||
- cannot be empty
|
- cannot be empty
|
||||||
- cannot start with a space
|
- cannot start with a space
|
||||||
- must not contain a forward slash (for logfile naming purposes)
|
- must not contain a forward slash (for logfile naming purposes)
|
||||||
- must not contain contiguous spaces */
|
- must not contain contiguous spaces
|
||||||
int valid_nick(char *nick);
|
- must not contain a newline or tab seqeunce */
|
||||||
|
int valid_nick(const char *nick);
|
||||||
|
|
||||||
|
/* Converts all newline/tab chars to spaces (use for strings that should be contained to a single line) */
|
||||||
|
void filter_str(char *str, size_t len);;
|
||||||
|
|
||||||
/* gets base file name from path or original file name if no path is supplied */
|
/* gets base file name from path or original file name if no path is supplied */
|
||||||
void get_file_name(char *namebuf, int bufsize, const char *pathname);
|
void get_file_name(char *namebuf, int bufsize, const char *pathname);
|
||||||
@ -98,7 +102,14 @@ void str_to_lower(char *str);
|
|||||||
|
|
||||||
/* puts friendnum's nick in buf, truncating at TOXIC_MAX_NAME_LENGTH if necessary.
|
/* puts friendnum's nick in buf, truncating at TOXIC_MAX_NAME_LENGTH if necessary.
|
||||||
Returns nick len on success, -1 on failure */
|
Returns nick len on success, -1 on failure */
|
||||||
int get_nick_truncate(Tox *m, char *buf, int friendnum);
|
size_t get_nick_truncate(Tox *m, char *buf, uint32_t friendnum);
|
||||||
|
|
||||||
|
/* same as get_nick_truncate but for groupchats */
|
||||||
|
int get_group_nick_truncate(Tox *m, char *buf, int peernum, int groupnum);
|
||||||
|
|
||||||
|
/* copies data to msg buffer.
|
||||||
|
returns length of msg, which will be no larger than size-1 */
|
||||||
|
size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length);
|
||||||
|
|
||||||
/* returns index of the first instance of ch in s starting at idx.
|
/* returns index of the first instance of ch in s starting at idx.
|
||||||
returns length of s if char not found */
|
returns length of s if char not found */
|
||||||
@ -114,13 +125,16 @@ void bytes_convert_str(char *buf, int size, uint64_t bytes);
|
|||||||
/* checks if a file exists. Returns true or false */
|
/* checks if a file exists. Returns true or false */
|
||||||
bool file_exists(const char *path);
|
bool file_exists(const char *path);
|
||||||
|
|
||||||
/* returns file size or -1 on error */
|
/* returns file size or 0 on error */
|
||||||
off_t file_size(const char *path);
|
off_t file_size(const char *path);
|
||||||
|
|
||||||
/* compares the first size bytes of fp and signature.
|
/* compares the first size bytes of fp and signature.
|
||||||
Returns 0 if they are the same, 1 if they differ, and -1 on error.
|
Returns 0 if they are the same, 1 if they differ, and -1 on error.
|
||||||
|
|
||||||
On success this function will seek back to the beginning of fp */
|
On success this function will seek back to the beginning of fp */
|
||||||
int check_file_signature(const char *signature, size_t size, FILE *fp);
|
int check_file_signature(const char *signature, size_t size, FILE *fp);
|
||||||
|
|
||||||
|
/* sets window title in tab bar. */
|
||||||
|
void set_window_title(ToxWindow *self, const char *title, int len);
|
||||||
|
|
||||||
#endif /* #define MISC_TOOLS_H */
|
#endif /* #define MISC_TOOLS_H */
|
||||||
|
242
src/notify.c
242
src/notify.c
@ -1,5 +1,5 @@
|
|||||||
/* notify.c
|
/* notify.c
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Toxic All Rights Reserved.
|
* Copyright (C) 2014 Toxic All Rights Reserved.
|
||||||
*
|
*
|
||||||
@ -35,6 +35,7 @@
|
|||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
|
#include "xtra.h"
|
||||||
|
|
||||||
#if defined(AUDIO) || defined(SOUND_NOTIFY)
|
#if defined(AUDIO) || defined(SOUND_NOTIFY)
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
@ -53,10 +54,6 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
#ifdef X11
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#endif /* X11 */
|
|
||||||
|
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
#include <libnotify/notify.h>
|
#include <libnotify/notify.h>
|
||||||
#endif
|
#endif
|
||||||
@ -70,16 +67,12 @@ extern struct user_settings *user_settings;
|
|||||||
struct Control {
|
struct Control {
|
||||||
time_t cooldown;
|
time_t cooldown;
|
||||||
time_t notif_timeout;
|
time_t notif_timeout;
|
||||||
#ifdef X11
|
|
||||||
Display *display;
|
|
||||||
unsigned long this_window;
|
|
||||||
#endif /* X11 */
|
|
||||||
|
|
||||||
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
||||||
pthread_mutex_t poll_mutex[1];
|
pthread_mutex_t poll_mutex[1];
|
||||||
bool poll_active;
|
bool poll_active;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
uint32_t device_idx; /* index of output device */
|
uint32_t device_idx; /* index of output device */
|
||||||
char* sounds[SOUNDS_SIZE];
|
char* sounds[SOUNDS_SIZE];
|
||||||
@ -101,7 +94,7 @@ struct _ActiveNotifications {
|
|||||||
size_t size;
|
size_t size;
|
||||||
time_t n_timeout;
|
time_t n_timeout;
|
||||||
#endif
|
#endif
|
||||||
} actives[ACTIVE_NOTIFS_MAX] = {{0}};
|
} actives[ACTIVE_NOTIFS_MAX];
|
||||||
/**********************************************************************************/
|
/**********************************************************************************/
|
||||||
/**********************************************************************************/
|
/**********************************************************************************/
|
||||||
/**********************************************************************************/
|
/**********************************************************************************/
|
||||||
@ -114,31 +107,19 @@ static void tab_notify(ToxWindow *self, uint64_t flags)
|
|||||||
if (self == NULL)
|
if (self == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (flags & NT_WNDALERT_0)
|
if (flags & NT_WNDALERT_0)
|
||||||
self->alert = WINDOW_ALERT_0;
|
self->alert = WINDOW_ALERT_0;
|
||||||
else if ( (flags & NT_WNDALERT_1) && (!self->alert || self->alert > WINDOW_ALERT_0) )
|
else if ( (flags & NT_WNDALERT_1) && (!self->alert || self->alert > WINDOW_ALERT_0) )
|
||||||
self->alert = WINDOW_ALERT_1;
|
self->alert = WINDOW_ALERT_1;
|
||||||
else if ( (flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1) )
|
else if ( (flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1) )
|
||||||
self->alert = WINDOW_ALERT_2;
|
self->alert = WINDOW_ALERT_2;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef X11
|
|
||||||
long unsigned int get_focused_window_id()
|
|
||||||
{
|
|
||||||
if (!Control.display) return 0;
|
|
||||||
|
|
||||||
Window focus;
|
|
||||||
int revert;
|
|
||||||
XGetInputFocus(Control.display, &focus, &revert);
|
|
||||||
return focus;
|
|
||||||
}
|
|
||||||
#endif /* X11 */
|
|
||||||
|
|
||||||
static bool notifications_are_disabled(uint64_t flags)
|
static bool notifications_are_disabled(uint64_t flags)
|
||||||
{
|
{
|
||||||
bool res = flags & NT_RESTOL && Control.cooldown > get_unix_time();
|
bool res = flags & NT_RESTOL && Control.cooldown > get_unix_time();
|
||||||
#ifdef X11
|
#ifdef X11
|
||||||
return res || (flags & NT_NOFOCUS && Control.this_window == get_focused_window_id());
|
return res || (flags & NT_NOFOCUS && is_focused());
|
||||||
#else
|
#else
|
||||||
return res;
|
return res;
|
||||||
#endif
|
#endif
|
||||||
@ -173,23 +154,23 @@ static bool device_opened = false;
|
|||||||
time_t last_opened_update = 0;
|
time_t last_opened_update = 0;
|
||||||
|
|
||||||
bool m_open_device()
|
bool m_open_device()
|
||||||
{
|
{
|
||||||
last_opened_update = time(NULL);
|
last_opened_update = get_unix_time();
|
||||||
|
|
||||||
if (device_opened) return true;
|
if (device_opened) return true;
|
||||||
|
|
||||||
/* Blah error check */
|
/* Blah error check */
|
||||||
open_primary_device(output, &Control.device_idx, 48000, 20, 1);
|
open_primary_device(output, &Control.device_idx, 48000, 20, 1);
|
||||||
|
|
||||||
return (device_opened = true);
|
return (device_opened = true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool m_close_device()
|
bool m_close_device()
|
||||||
{
|
{
|
||||||
if (!device_opened) return true;
|
if (!device_opened) return true;
|
||||||
|
|
||||||
close_device(output, Control.device_idx);
|
close_device(output, Control.device_idx);
|
||||||
|
|
||||||
return !(device_opened = false);
|
return !(device_opened = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,25 +189,26 @@ void graceful_clear()
|
|||||||
actives[i].box = NULL;
|
actives[i].box = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(actives[i].id_indicator) *actives[i].id_indicator = -1; // reset indicator value
|
if(actives[i].id_indicator)
|
||||||
|
*actives[i].id_indicator = -1; /* reset indicator value */
|
||||||
|
|
||||||
if ( actives[i].looping ) {
|
if ( actives[i].looping ) {
|
||||||
stop_sound(i);
|
stop_sound(i);
|
||||||
} else {
|
} else {
|
||||||
if (!is_playing(actives[i].source))
|
if (!is_playing(actives[i].source))
|
||||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
||||||
else break;
|
else break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == ACTIVE_NOTIFS_MAX) {
|
if (i == ACTIVE_NOTIFS_MAX) {
|
||||||
m_close_device(); /* In case it's opened */
|
m_close_device(); /* In case it's opened */
|
||||||
control_unlock();
|
control_unlock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
usleep(1000);
|
usleep(1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -235,57 +217,60 @@ void* do_playing(void* _p)
|
|||||||
{
|
{
|
||||||
(void)_p;
|
(void)_p;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
bool has_looping = false;
|
bool has_looping = false;
|
||||||
|
|
||||||
while(Control.poll_active) {
|
while(Control.poll_active) {
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
|
|
||||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
||||||
|
|
||||||
if (actives[i].looping) has_looping = true;
|
if (actives[i].looping) has_looping = true;
|
||||||
|
|
||||||
if (actives[i].active && !actives[i].looping
|
if (actives[i].active && !actives[i].looping
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
&& !actives[i].box
|
&& !actives[i].box
|
||||||
#endif
|
#endif
|
||||||
) {
|
) {
|
||||||
|
if(actives[i].id_indicator)
|
||||||
|
*actives[i].id_indicator = -1; /* reset indicator value */
|
||||||
|
|
||||||
if (!is_playing(actives[i].source)) {
|
if (!is_playing(actives[i].source)) {
|
||||||
/* Close */
|
/* Close */
|
||||||
alSourceStop(actives[i].source);
|
alSourceStop(actives[i].source);
|
||||||
alDeleteSources(1, &actives[i].source);
|
alDeleteSources(1, &actives[i].source);
|
||||||
alDeleteBuffers(1,&actives[i].buffer);
|
alDeleteBuffers(1, &actives[i].buffer);
|
||||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
else if (actives[i].box && time(NULL) >= actives[i].n_timeout)
|
else if (actives[i].box && get_unix_time() >= actives[i].n_timeout)
|
||||||
{
|
{
|
||||||
GError* ignore;
|
GError* ignore;
|
||||||
notify_notification_close(actives[i].box, &ignore);
|
notify_notification_close(actives[i].box, &ignore);
|
||||||
actives[i].box = NULL;
|
actives[i].box = NULL;
|
||||||
|
if(actives[i].id_indicator)
|
||||||
if(actives[i].id_indicator) *actives[i].id_indicator = -1; // reset indicator value
|
*actives[i].id_indicator = -1; /* reset indicator value */
|
||||||
|
|
||||||
if (!actives[i].looping && !is_playing(actives[i].source)) {
|
if (!actives[i].looping && !is_playing(actives[i].source)) {
|
||||||
/* stop source if not looping or playing, just terminate box */
|
/* stop source if not looping or playing, just terminate box */
|
||||||
alSourceStop(actives[i].source);
|
alSourceStop(actives[i].source);
|
||||||
alDeleteSources(1, &actives[i].source);
|
alDeleteSources(1, &actives[i].source);
|
||||||
alDeleteBuffers(1,&actives[i].buffer);
|
alDeleteBuffers(1, &actives[i].buffer);
|
||||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* device is opened and no activity in under DEVICE_COOLDOWN time, close device*/
|
/* device is opened and no activity in under DEVICE_COOLDOWN time, close device*/
|
||||||
if (device_opened && !has_looping &&
|
if (device_opened && !has_looping &&
|
||||||
(time(NULL) - last_opened_update) > DEVICE_COOLDOWN) {
|
(get_unix_time() - last_opened_update) > DEVICE_COOLDOWN) {
|
||||||
m_close_device();
|
m_close_device();
|
||||||
}
|
}
|
||||||
has_looping = false;
|
has_looping = false;
|
||||||
|
|
||||||
control_unlock();
|
control_unlock();
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
}
|
}
|
||||||
@ -293,20 +278,20 @@ void* do_playing(void* _p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int play_source(uint32_t source, uint32_t buffer, bool looping)
|
int play_source(uint32_t source, uint32_t buffer, bool looping)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (; i < ACTIVE_NOTIFS_MAX && actives[i].active; i ++);
|
for (; i < ACTIVE_NOTIFS_MAX && actives[i].active; i ++);
|
||||||
if ( i == ACTIVE_NOTIFS_MAX ) {
|
if ( i == ACTIVE_NOTIFS_MAX ) {
|
||||||
return -1; /* Full */
|
return -1; /* Full */
|
||||||
}
|
}
|
||||||
|
|
||||||
alSourcePlay(source);
|
alSourcePlay(source);
|
||||||
|
|
||||||
actives[i].active = 1;
|
actives[i].active = 1;
|
||||||
actives[i].source = source;
|
actives[i].source = source;
|
||||||
actives[i].buffer = buffer;
|
actives[i].buffer = buffer;
|
||||||
actives[i].looping = looping;
|
actives[i].looping = looping;
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,13 +303,14 @@ void* do_playing(void* _p)
|
|||||||
while(Control.poll_active) {
|
while(Control.poll_active) {
|
||||||
control_lock();
|
control_lock();
|
||||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
||||||
if (actives[i].box && time(NULL) >= actives[i].n_timeout)
|
if (actives[i].box && get_unix_time() >= actives[i].n_timeout)
|
||||||
{
|
{
|
||||||
GError* ignore;
|
GError* ignore;
|
||||||
notify_notification_close(actives[i].box, &ignore);
|
notify_notification_close(actives[i].box, &ignore);
|
||||||
actives[i].box = NULL;
|
actives[i].box = NULL;
|
||||||
|
if(actives[i].id_indicator)
|
||||||
if(actives[i].id_indicator) *actives[i].id_indicator = -1; // reset indicator value
|
*actives[i].id_indicator = -1; /* reset indicator value */
|
||||||
|
|
||||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -338,18 +324,20 @@ void graceful_clear()
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
||||||
if (actives[i].box) {
|
if (actives[i].box) {
|
||||||
GError* ignore;
|
GError* ignore;
|
||||||
notify_notification_close(actives[i].box, &ignore);
|
notify_notification_close(actives[i].box, &ignore);
|
||||||
actives[i].box = NULL;
|
actives[i].box = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(actives[i].id_indicator) *actives[i].id_indicator = -1; // reset indicator value
|
if (actives[i].id_indicator)
|
||||||
|
*actives[i].id_indicator = -1; /* reset indicator value */
|
||||||
|
|
||||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
||||||
}
|
}
|
||||||
|
|
||||||
control_unlock();
|
control_unlock();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -368,7 +356,7 @@ int init_notify(int login_cooldown, int notification_timeout)
|
|||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
alutInitWithoutContext(NULL, NULL);
|
alutInitWithoutContext(NULL, NULL);
|
||||||
#endif /* SOUND_NOTIFY */
|
#endif /* SOUND_NOTIFY */
|
||||||
|
|
||||||
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
||||||
if (pthread_mutex_init(Control.poll_mutex, NULL) != 0)
|
if (pthread_mutex_init(Control.poll_mutex, NULL) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
@ -379,29 +367,25 @@ int init_notify(int login_cooldown, int notification_timeout)
|
|||||||
pthread_mutex_destroy(Control.poll_mutex);
|
pthread_mutex_destroy(Control.poll_mutex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Control.poll_active = 1;
|
Control.poll_active = 1;
|
||||||
#endif
|
#endif
|
||||||
|
Control.cooldown = get_unix_time() + login_cooldown;
|
||||||
Control.cooldown = time(NULL) + login_cooldown;
|
|
||||||
#ifdef X11
|
|
||||||
Control.display = XOpenDisplay(NULL);
|
|
||||||
Control.this_window = get_focused_window_id();
|
|
||||||
#endif /* X11 */
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
notify_init("toxic");
|
notify_init("Toxic");
|
||||||
#endif
|
#endif
|
||||||
Control.notif_timeout = notification_timeout;
|
Control.notif_timeout = notification_timeout;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void terminate_notify()
|
void terminate_notify()
|
||||||
{
|
{
|
||||||
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
||||||
if ( !Control.poll_active ) return;
|
if ( !Control.poll_active ) return;
|
||||||
Control.poll_active = 0;
|
Control.poll_active = 0;
|
||||||
|
|
||||||
graceful_clear();
|
graceful_clear();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -410,7 +394,7 @@ void terminate_notify()
|
|||||||
for (; i < SOUNDS_SIZE; i ++) free(Control.sounds[i]);
|
for (; i < SOUNDS_SIZE; i ++) free(Control.sounds[i]);
|
||||||
alutExit();
|
alutExit();
|
||||||
#endif /* SOUND_NOTIFY */
|
#endif /* SOUND_NOTIFY */
|
||||||
|
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
notify_uninit();
|
notify_uninit();
|
||||||
#endif
|
#endif
|
||||||
@ -420,7 +404,7 @@ void terminate_notify()
|
|||||||
int set_sound(Notification sound, const char* value)
|
int set_sound(Notification sound, const char* value)
|
||||||
{
|
{
|
||||||
if (sound == silent) return 0;
|
if (sound == silent) return 0;
|
||||||
|
|
||||||
free(Control.sounds[sound]);
|
free(Control.sounds[sound]);
|
||||||
|
|
||||||
size_t len = strlen(value) + 1;
|
size_t len = strlen(value) + 1;
|
||||||
@ -432,18 +416,18 @@ int set_sound(Notification sound, const char* value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int play_sound_internal(Notification what, bool loop)
|
int play_sound_internal(Notification what, bool loop)
|
||||||
{
|
{
|
||||||
uint32_t source;
|
uint32_t source;
|
||||||
uint32_t buffer;
|
uint32_t buffer;
|
||||||
|
|
||||||
m_open_device();
|
m_open_device();
|
||||||
|
|
||||||
alGenSources(1, &source);
|
alGenSources(1, &source);
|
||||||
alGenBuffers(1, &buffer);
|
alGenBuffers(1, &buffer);
|
||||||
buffer = alutCreateBufferFromFile(Control.sounds[what]);
|
buffer = alutCreateBufferFromFile(Control.sounds[what]);
|
||||||
alSourcei(source, AL_BUFFER, buffer);
|
alSourcei(source, AL_BUFFER, buffer);
|
||||||
alSourcei(source, AL_LOOPING, loop);
|
alSourcei(source, AL_LOOPING, loop);
|
||||||
|
|
||||||
int rc = play_source(source, buffer, loop);
|
int rc = play_source(source, buffer, loop);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
alSourceStop(source);
|
alSourceStop(source);
|
||||||
@ -451,7 +435,7 @@ int play_sound_internal(Notification what, bool loop)
|
|||||||
alDeleteBuffers(1,&buffer);
|
alDeleteBuffers(1,&buffer);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -480,7 +464,8 @@ void stop_sound(int id)
|
|||||||
notify_notification_close(actives[id].box, &ignore);
|
notify_notification_close(actives[id].box, &ignore);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
*actives[id].id_indicator = -1;
|
if (actives[id].id_indicator)
|
||||||
|
*actives[id].id_indicator = -1;
|
||||||
// alSourcei(actives[id].source, AL_LOOPING, false);
|
// alSourcei(actives[id].source, AL_LOOPING, false);
|
||||||
alSourceStop(actives[id].source);
|
alSourceStop(actives[id].source);
|
||||||
alDeleteSources(1, &actives[id].source);
|
alDeleteSources(1, &actives[id].source);
|
||||||
@ -499,11 +484,11 @@ static int m_play_sound(Notification notif, uint64_t flags)
|
|||||||
beep();
|
beep();
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
#endif /* SOUND_NOTIFY */
|
#endif /* SOUND_NOTIFY */
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef BOX_NOTIFY
|
#ifdef BOX_NOTIFY
|
||||||
void m_notify_action(NotifyNotification *box, char *action, void* data)
|
void m_notify_action(NotifyNotification *box, char *action, void* data)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -514,81 +499,80 @@ int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_in
|
|||||||
|
|
||||||
if (notifications_are_disabled(flags))
|
if (notifications_are_disabled(flags))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
int id = -1;
|
int id = -1;
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
if (self && (!self->stb || self->stb->status != TOX_USERSTATUS_BUSY) && user_settings->alerts == ALERTS_ENABLED)
|
if (self && (!self->stb || self->stb->status != TOX_USER_STATUS_BUSY) && user_settings->alerts == ALERTS_ENABLED)
|
||||||
id = m_play_sound(notif, flags);
|
id = m_play_sound(notif, flags);
|
||||||
|
|
||||||
else if (flags & NT_ALWAYS)
|
else if (flags & NT_ALWAYS)
|
||||||
id = m_play_sound(notif, flags);
|
id = m_play_sound(notif, flags);
|
||||||
|
|
||||||
#if defined(BOX_NOTIFY) && !defined(SOUND_NOTIFY)
|
#if defined(BOX_NOTIFY) && !defined(SOUND_NOTIFY)
|
||||||
|
|
||||||
if (id == -1) {
|
if (id == -1) {
|
||||||
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].box; id ++);
|
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].box; id++);
|
||||||
if ( id == ACTIVE_NOTIFS_MAX ) {
|
if ( id == ACTIVE_NOTIFS_MAX ) {
|
||||||
control_unlock();
|
control_unlock();
|
||||||
return -1; /* Full */
|
return -1; /* Full */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ( id_indicator && id != -1 ) {
|
if ( id_indicator && id != -1 ) {
|
||||||
actives[id].id_indicator = id_indicator;
|
actives[id].id_indicator = id_indicator;
|
||||||
*id_indicator = id;
|
*id_indicator = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
control_unlock();
|
control_unlock();
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
|
int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
|
||||||
{
|
{
|
||||||
tab_notify(self, flags);
|
tab_notify(self, flags);
|
||||||
|
|
||||||
if (notifications_are_disabled(flags))
|
if (notifications_are_disabled(flags))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (id < 0 || id >= ACTIVE_NOTIFS_MAX) return -1;
|
if (id < 0 || id >= ACTIVE_NOTIFS_MAX) return -1;
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
if (!actives[id].active || !Control.sounds[notif]) {
|
if (!actives[id].active || !Control.sounds[notif]) {
|
||||||
control_unlock();
|
control_unlock();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_open_device();
|
m_open_device();
|
||||||
|
|
||||||
alSourceStop(actives[id].source);
|
alSourceStop(actives[id].source);
|
||||||
alDeleteSources(1, &actives[id].source);
|
alDeleteSources(1, &actives[id].source);
|
||||||
alDeleteBuffers(1,&actives[id].buffer);
|
alDeleteBuffers(1,&actives[id].buffer);
|
||||||
|
|
||||||
|
|
||||||
alGenSources(1, &actives[id].source);
|
alGenSources(1, &actives[id].source);
|
||||||
alGenBuffers(1, &actives[id].buffer);
|
alGenBuffers(1, &actives[id].buffer);
|
||||||
actives[id].buffer = alutCreateBufferFromFile(Control.sounds[notif]);
|
actives[id].buffer = alutCreateBufferFromFile(Control.sounds[notif]);
|
||||||
alSourcei(actives[id].source, AL_BUFFER, actives[id].buffer);
|
alSourcei(actives[id].source, AL_BUFFER, actives[id].buffer);
|
||||||
alSourcei(actives[id].source, AL_LOOPING, flags & NT_LOOP);
|
alSourcei(actives[id].source, AL_LOOPING, flags & NT_LOOP);
|
||||||
|
|
||||||
alSourcePlay(actives[id].source);
|
alSourcePlay(actives[id].source);
|
||||||
|
|
||||||
control_unlock();
|
control_unlock();
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
#else
|
#else
|
||||||
if (notif != silent)
|
if (notif != silent)
|
||||||
beep();
|
beep();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
#endif /* SOUND_NOTIFY */
|
#endif /* SOUND_NOTIFY */
|
||||||
}
|
}
|
||||||
|
|
||||||
int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator, char* title, const char* format, ...)
|
int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator, const char* title, const char* format, ...)
|
||||||
{
|
{
|
||||||
if (notifications_are_disabled(flags)) {
|
if (notifications_are_disabled(flags)) {
|
||||||
tab_notify(self, flags);
|
tab_notify(self, flags);
|
||||||
@ -610,7 +594,7 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi
|
|||||||
return -1; /* Full */
|
return -1; /* Full */
|
||||||
}
|
}
|
||||||
|
|
||||||
actives[id].active = 1;
|
actives[id].active = 1;
|
||||||
actives[id].id_indicator = id_indicator;
|
actives[id].id_indicator = id_indicator;
|
||||||
if (id_indicator) *id_indicator = id;
|
if (id_indicator) *id_indicator = id;
|
||||||
}
|
}
|
||||||
@ -623,13 +607,13 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi
|
|||||||
vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
|
vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
|
||||||
va_end (__ARGS__);
|
va_end (__ARGS__);
|
||||||
|
|
||||||
if (strlen(actives[id].messages[0]) > MAX_BOX_MSG_LEN - 3)
|
if (strlen(actives[id].messages[0]) > MAX_BOX_MSG_LEN - 3)
|
||||||
strcpy(actives[id].messages[0] + MAX_BOX_MSG_LEN - 3, "...");
|
strcpy(actives[id].messages[0] + MAX_BOX_MSG_LEN - 3, "...");
|
||||||
|
|
||||||
actives[id].box = notify_notification_new(actives[id].title, actives[id].messages[0], NULL);
|
actives[id].box = notify_notification_new(actives[id].title, actives[id].messages[0], NULL);
|
||||||
actives[id].size ++;
|
actives[id].size++;
|
||||||
actives[id].n_timeout = time(NULL) + Control.notif_timeout / 1000;
|
actives[id].n_timeout = get_unix_time() + Control.notif_timeout / 1000;
|
||||||
|
|
||||||
notify_notification_set_timeout(actives[id].box, Control.notif_timeout);
|
notify_notification_set_timeout(actives[id].box, Control.notif_timeout);
|
||||||
notify_notification_set_app_name(actives[id].box, "toxic");
|
notify_notification_set_app_name(actives[id].box, "toxic");
|
||||||
/*notify_notification_add_action(actives[id].box, "lel", "default", m_notify_action, self, NULL);*/
|
/*notify_notification_add_action(actives[id].box, "lel", "default", m_notify_action, self, NULL);*/
|
||||||
@ -668,8 +652,8 @@ int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, con
|
|||||||
if (strlen(actives[id].messages[actives[id].size]) > MAX_BOX_MSG_LEN - 3)
|
if (strlen(actives[id].messages[actives[id].size]) > MAX_BOX_MSG_LEN - 3)
|
||||||
strcpy(actives[id].messages[actives[id].size] + MAX_BOX_MSG_LEN - 3, "...");
|
strcpy(actives[id].messages[actives[id].size] + MAX_BOX_MSG_LEN - 3, "...");
|
||||||
|
|
||||||
actives[id].size ++;
|
actives[id].size++;
|
||||||
actives[id].n_timeout = time(NULL) + Control.notif_timeout / 1000;
|
actives[id].n_timeout = get_unix_time() + Control.notif_timeout / 1000;
|
||||||
|
|
||||||
char formated[128 * 129] = {'\0'};
|
char formated[128 * 129] = {'\0'};
|
||||||
|
|
||||||
@ -703,7 +687,7 @@ int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const
|
|||||||
|
|
||||||
control_lock();
|
control_lock();
|
||||||
|
|
||||||
int id;
|
int id;
|
||||||
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++);
|
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++);
|
||||||
if ( id == ACTIVE_NOTIFS_MAX ) {
|
if ( id == ACTIVE_NOTIFS_MAX ) {
|
||||||
control_unlock();
|
control_unlock();
|
||||||
@ -722,13 +706,13 @@ int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const
|
|||||||
vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
|
vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
|
||||||
va_end (__ARGS__);
|
va_end (__ARGS__);
|
||||||
|
|
||||||
if (strlen(actives[id].messages[0]) > MAX_BOX_MSG_LEN - 3)
|
if (strlen(actives[id].messages[0]) > MAX_BOX_MSG_LEN - 3)
|
||||||
strcpy(actives[id].messages[0] + MAX_BOX_MSG_LEN - 3, "...");
|
strcpy(actives[id].messages[0] + MAX_BOX_MSG_LEN - 3, "...");
|
||||||
|
|
||||||
actives[id].active = 1;
|
actives[id].active = 1;
|
||||||
actives[id].box = notify_notification_new(actives[id].title, actives[id].messages[0], NULL);
|
actives[id].box = notify_notification_new(actives[id].title, actives[id].messages[0], NULL);
|
||||||
actives[id].size ++;
|
actives[id].size ++;
|
||||||
actives[id].n_timeout = time(NULL) + Control.notif_timeout / 1000;
|
actives[id].n_timeout = get_unix_time() + Control.notif_timeout / 1000;
|
||||||
|
|
||||||
notify_notification_set_timeout(actives[id].box, Control.notif_timeout);
|
notify_notification_set_timeout(actives[id].box, Control.notif_timeout);
|
||||||
notify_notification_set_app_name(actives[id].box, "toxic");
|
notify_notification_set_app_name(actives[id].box, "toxic");
|
||||||
@ -766,7 +750,7 @@ int box_silent_notify2(ToxWindow* self, uint64_t flags, int id, const char* form
|
|||||||
strcpy(actives[id].messages[actives[id].size] + MAX_BOX_MSG_LEN - 3, "...");
|
strcpy(actives[id].messages[actives[id].size] + MAX_BOX_MSG_LEN - 3, "...");
|
||||||
|
|
||||||
actives[id].size ++;
|
actives[id].size ++;
|
||||||
actives[id].n_timeout = time(NULL) + Control.notif_timeout / 1000;
|
actives[id].n_timeout = get_unix_time() + Control.notif_timeout / 1000;
|
||||||
|
|
||||||
char formated[128 * 129] = {'\0'};
|
char formated[128 * 129] = {'\0'};
|
||||||
|
|
||||||
|
10
src/notify.h
10
src/notify.h
@ -1,5 +1,5 @@
|
|||||||
/* notify.h
|
/* notify.h
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Toxic All Rights Reserved.
|
* Copyright (C) 2014 Toxic All Rights Reserved.
|
||||||
*
|
*
|
||||||
@ -29,7 +29,7 @@
|
|||||||
typedef enum _Notification
|
typedef enum _Notification
|
||||||
{
|
{
|
||||||
silent = -1,
|
silent = -1,
|
||||||
error,
|
notif_error,
|
||||||
self_log_in,
|
self_log_in,
|
||||||
self_log_out,
|
self_log_out,
|
||||||
user_log_in,
|
user_log_in,
|
||||||
@ -49,14 +49,14 @@ typedef enum _Flags {
|
|||||||
NT_LOOP = 1 << 2, /* Loop sound. If this setting active, notify() will return id of the sound
|
NT_LOOP = 1 << 2, /* Loop sound. If this setting active, notify() will return id of the sound
|
||||||
* so it could be stopped. It will return 0 if error or NT_NATIVE flag is set and play \a instead
|
* so it could be stopped. It will return 0 if error or NT_NATIVE flag is set and play \a instead
|
||||||
*/
|
*/
|
||||||
NT_RESTOL = 1 << 3, /* Respect tolerance. Usually used to stop flood at toxic startup
|
NT_RESTOL = 1 << 3, /* Respect tolerance. Usually used to stop flood at toxic startup
|
||||||
* Only works if login_cooldown is true when calling init_notify()
|
* Only works if login_cooldown is true when calling init_notify()
|
||||||
*/
|
*/
|
||||||
NT_NOTIFWND = 1 << 4, /* Pop notify window. NOTE: only works(/WILL WORK) if libnotify is present */
|
NT_NOTIFWND = 1 << 4, /* Pop notify window. NOTE: only works(/WILL WORK) if libnotify is present */
|
||||||
NT_WNDALERT_0 = 1 << 5, /* Alert toxic */
|
NT_WNDALERT_0 = 1 << 5, /* Alert toxic */
|
||||||
NT_WNDALERT_1 = 1 << 6, /* Alert toxic */
|
NT_WNDALERT_1 = 1 << 6, /* Alert toxic */
|
||||||
NT_WNDALERT_2 = 1 << 7, /* Alert toxic */
|
NT_WNDALERT_2 = 1 << 7, /* Alert toxic */
|
||||||
|
|
||||||
NT_ALWAYS = 1 << 8, /* Force sound to play */
|
NT_ALWAYS = 1 << 8, /* Force sound to play */
|
||||||
} Flags;
|
} Flags;
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id);
|
|||||||
|
|
||||||
void stop_sound(int id);
|
void stop_sound(int id);
|
||||||
|
|
||||||
int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator, char* title, const char* format, ...);
|
int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator, const char* title, const char* format, ...);
|
||||||
int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, const char* format, ...);
|
int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, const char* format, ...);
|
||||||
int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const char* title, const char* format, ...);
|
int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const char* title, const char* format, ...);
|
||||||
int box_silent_notify2(ToxWindow* self, uint64_t flags, int id, const char* format, ...);
|
int box_silent_notify2(ToxWindow* self, uint64_t flags, int id, const char* format, ...);
|
||||||
|
122
src/prompt.c
122
src/prompt.c
@ -48,17 +48,22 @@ extern struct Winthread Winthread;
|
|||||||
|
|
||||||
FriendRequests FrndRequests;
|
FriendRequests FrndRequests;
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
|
#define AC_NUM_GLOB_COMMANDS 18
|
||||||
|
#else
|
||||||
|
#define AC_NUM_GLOB_COMMANDS 16
|
||||||
|
#endif /* AUDIO */
|
||||||
|
|
||||||
/* Array of global command names used for tab completion. */
|
/* Array of global command names used for tab completion. */
|
||||||
const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
|
static const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
|
||||||
{ "/accept" },
|
{ "/accept" },
|
||||||
{ "/add" },
|
{ "/add" },
|
||||||
{ "/avatar" },
|
{ "/avatar" },
|
||||||
{ "/clear" },
|
{ "/clear" },
|
||||||
{ "/close" }, /* rm /close when groupchats gets its own list */
|
|
||||||
{ "/connect" },
|
{ "/connect" },
|
||||||
{ "/decline" },
|
{ "/decline" },
|
||||||
{ "/exit" },
|
{ "/exit" },
|
||||||
{ "/groupchat" },
|
{ "/group" },
|
||||||
{ "/help" },
|
{ "/help" },
|
||||||
{ "/log" },
|
{ "/log" },
|
||||||
{ "/myid" },
|
{ "/myid" },
|
||||||
@ -76,7 +81,7 @@ const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
|
|||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
};
|
};
|
||||||
|
|
||||||
void kill_prompt_window(ToxWindow *self)
|
void kill_prompt_window(ToxWindow *self)
|
||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
StatusBar *statusbar = self->stb;
|
StatusBar *statusbar = self->stb;
|
||||||
@ -96,6 +101,13 @@ void kill_prompt_window(ToxWindow *self)
|
|||||||
del_window(self);
|
del_window(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* callback: Updates own connection status in prompt statusbar */
|
||||||
|
void prompt_onSelfConnectionChange(Tox *m, TOX_CONNECTION connection_status, void *userdata)
|
||||||
|
{
|
||||||
|
StatusBar *statusbar = prompt->stb;
|
||||||
|
statusbar->connection = connection_status;
|
||||||
|
}
|
||||||
|
|
||||||
/* Updates own nick in prompt statusbar */
|
/* Updates own nick in prompt statusbar */
|
||||||
void prompt_update_nick(ToxWindow *prompt, const char *nick)
|
void prompt_update_nick(ToxWindow *prompt, const char *nick)
|
||||||
{
|
{
|
||||||
@ -109,25 +121,23 @@ void prompt_update_statusmessage(ToxWindow *prompt, Tox *m, const char *statusms
|
|||||||
{
|
{
|
||||||
StatusBar *statusbar = prompt->stb;
|
StatusBar *statusbar = prompt->stb;
|
||||||
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
|
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
|
||||||
int len = strlen(statusbar->statusmsg);
|
size_t len = strlen(statusbar->statusmsg);
|
||||||
statusbar->statusmsg_len = len;
|
statusbar->statusmsg_len = len;
|
||||||
tox_set_status_message(m, (uint8_t *) statusmsg, (uint64_t) len);
|
|
||||||
|
TOX_ERR_SET_INFO err;
|
||||||
|
tox_self_set_status_message(m, (uint8_t *) statusmsg, len, &err);
|
||||||
|
|
||||||
|
if (err != TOX_ERR_SET_INFO_OK)
|
||||||
|
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set note (error %d)\n", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Updates own status in prompt statusbar */
|
/* Updates own status in prompt statusbar */
|
||||||
void prompt_update_status(ToxWindow *prompt, uint8_t status)
|
void prompt_update_status(ToxWindow *prompt, TOX_USER_STATUS status)
|
||||||
{
|
{
|
||||||
StatusBar *statusbar = prompt->stb;
|
StatusBar *statusbar = prompt->stb;
|
||||||
statusbar->status = status;
|
statusbar->status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Updates own connection status in prompt statusbar */
|
|
||||||
void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected)
|
|
||||||
{
|
|
||||||
StatusBar *statusbar = prompt->stb;
|
|
||||||
statusbar->is_online = is_connected;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Adds friend request to pending friend requests.
|
/* Adds friend request to pending friend requests.
|
||||||
Returns request number on success, -1 if queue is full. */
|
Returns request number on success, -1 if queue is full. */
|
||||||
static int add_friend_request(const char *public_key, const char *data)
|
static int add_friend_request(const char *public_key, const char *data)
|
||||||
@ -140,7 +150,7 @@ static int add_friend_request(const char *public_key, const char *data)
|
|||||||
for (i = 0; i <= FrndRequests.max_idx; ++i) {
|
for (i = 0; i <= FrndRequests.max_idx; ++i) {
|
||||||
if (!FrndRequests.request[i].active) {
|
if (!FrndRequests.request[i].active) {
|
||||||
FrndRequests.request[i].active = true;
|
FrndRequests.request[i].active = true;
|
||||||
memcpy(FrndRequests.request[i].key, public_key, TOX_CLIENT_ID_SIZE);
|
memcpy(FrndRequests.request[i].key, public_key, TOX_PUBLIC_KEY_SIZE);
|
||||||
snprintf(FrndRequests.request[i].msg, sizeof(FrndRequests.request[i].msg), "%s", data);
|
snprintf(FrndRequests.request[i].msg, sizeof(FrndRequests.request[i].msg), "%s", data);
|
||||||
|
|
||||||
if (i == FrndRequests.max_idx)
|
if (i == FrndRequests.max_idx)
|
||||||
@ -188,7 +198,14 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
|
|
||||||
if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0)
|
if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0)
|
||||||
diff = dir_match(self, m, ctx->line, L"/avatar");
|
diff = dir_match(self, m, ctx->line, L"/avatar");
|
||||||
else
|
else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0){
|
||||||
|
const char status_cmd_list[3][8] = {
|
||||||
|
{"online"},
|
||||||
|
{"away"},
|
||||||
|
{"busy"},
|
||||||
|
};
|
||||||
|
diff = complete_line(self, status_cmd_list, 3, 8);
|
||||||
|
} else
|
||||||
diff = complete_line(self, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
|
diff = complete_line(self, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
|
||||||
|
|
||||||
if (diff != -1) {
|
if (diff != -1) {
|
||||||
@ -197,10 +214,10 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
|
ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sound_notify(self, error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sound_notify(self, error, 0, NULL);
|
sound_notify(self, notif_error, 0, NULL);
|
||||||
}
|
}
|
||||||
} else if (key == '\n') {
|
} else if (key == '\n') {
|
||||||
rm_trailing_spaces_buf(ctx);
|
rm_trailing_spaces_buf(ctx);
|
||||||
@ -241,30 +258,23 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
|||||||
mvwhline(statusbar->topline, 1, 0, ACS_HLINE, x2);
|
mvwhline(statusbar->topline, 1, 0, ACS_HLINE, x2);
|
||||||
wmove(statusbar->topline, 0, 0);
|
wmove(statusbar->topline, 0, 0);
|
||||||
|
|
||||||
if (statusbar->is_online) {
|
if (statusbar->connection != TOX_CONNECTION_NONE) {
|
||||||
int colour = WHITE;
|
int colour = MAGENTA;
|
||||||
const char *status_text = "Unknown";
|
const char *status_text = "ERROR";
|
||||||
|
|
||||||
switch (statusbar->status) {
|
switch (statusbar->status) {
|
||||||
case TOX_USERSTATUS_NONE:
|
case TOX_USER_STATUS_NONE:
|
||||||
status_text = "Online";
|
status_text = "Online";
|
||||||
colour = GREEN;
|
colour = GREEN;
|
||||||
break;
|
break;
|
||||||
|
case TOX_USER_STATUS_AWAY:
|
||||||
case TOX_USERSTATUS_AWAY:
|
|
||||||
status_text = "Away";
|
status_text = "Away";
|
||||||
colour = YELLOW;
|
colour = YELLOW;
|
||||||
break;
|
break;
|
||||||
|
case TOX_USER_STATUS_BUSY:
|
||||||
case TOX_USERSTATUS_BUSY:
|
|
||||||
status_text = "Busy";
|
status_text = "Busy";
|
||||||
colour = RED;
|
colour = RED;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOX_USERSTATUS_INVALID:
|
|
||||||
status_text = "ERROR";
|
|
||||||
colour = MAGENTA;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wattron(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
|
wattron(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
|
||||||
@ -283,10 +293,10 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
/* Reset statusbar->statusmsg on window resize */
|
/* Reset statusbar->statusmsg on window resize */
|
||||||
if (x2 != self->x) {
|
if (x2 != self->x) {
|
||||||
char statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH] = {0};
|
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH];
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
tox_get_self_status_message(m, (uint8_t *) statusmsg, TOX_MAX_STATUSMESSAGE_LENGTH);
|
tox_self_get_status_message(m, (uint8_t *) statusmsg);
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
|
snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg);
|
||||||
@ -322,7 +332,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
|||||||
help_onDraw(self);
|
help_onDraw(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prompt_onConnectionChange(ToxWindow *self, Tox *m, int32_t friendnum , uint8_t status)
|
static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnum , TOX_CONNECTION connection_status)
|
||||||
{
|
{
|
||||||
if (friendnum < 0)
|
if (friendnum < 0)
|
||||||
return;
|
return;
|
||||||
@ -339,24 +349,24 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, int32_t friendnum
|
|||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
const char *msg;
|
const char *msg;
|
||||||
|
|
||||||
if (status == 1) {
|
if (connection_status != TOX_CONNECTION_NONE) {
|
||||||
msg = "has come online";
|
msg = "has come online";
|
||||||
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg);
|
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg);
|
||||||
write_to_log(msg, nick, ctx->log, true);
|
write_to_log(msg, nick, ctx->log, true);
|
||||||
|
|
||||||
if (self->active_box != -1)
|
if (self->active_box != -1)
|
||||||
box_notify2(self, user_log_in, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, self->active_box,
|
box_notify2(self, user_log_in, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, self->active_box,
|
||||||
"%s has come online", nick );
|
"%s has come online", nick );
|
||||||
else
|
else
|
||||||
box_notify(self, user_log_in, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, &self->active_box,
|
box_notify(self, user_log_in, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, &self->active_box,
|
||||||
"Toxic", "%s has come online", nick );
|
"Toxic", "%s has come online", nick );
|
||||||
} else {
|
} else {
|
||||||
msg = "has gone offline";
|
msg = "has gone offline";
|
||||||
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, RED, msg);
|
line_info_add(self, timefrmt, nick, NULL, DISCONNECTION, 0, RED, msg);
|
||||||
write_to_log(msg, nick, ctx->log, true);
|
write_to_log(msg, nick, ctx->log, true);
|
||||||
|
|
||||||
if (self->active_box != -1)
|
if (self->active_box != -1)
|
||||||
box_notify2(self, user_log_out, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, self->active_box,
|
box_notify2(self, user_log_out, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, self->active_box,
|
||||||
"%s has gone offline", nick );
|
"%s has gone offline", nick );
|
||||||
else
|
else
|
||||||
box_notify(self, user_log_out, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, &self->active_box,
|
box_notify(self, user_log_out, NT_WNDALERT_2 | NT_NOTIFWND | NT_RESTOL, &self->active_box,
|
||||||
@ -364,8 +374,7 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, int32_t friendnum
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, const char *data,
|
static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, const char *data, size_t length)
|
||||||
uint16_t length)
|
|
||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
@ -395,26 +404,25 @@ void prompt_init_statusbar(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
/* Init statusbar info */
|
/* Init statusbar info */
|
||||||
StatusBar *statusbar = self->stb;
|
StatusBar *statusbar = self->stb;
|
||||||
statusbar->status = TOX_USERSTATUS_NONE;
|
statusbar->status = TOX_USER_STATUS_NONE;
|
||||||
statusbar->is_online = false;
|
statusbar->connection = TOX_CONNECTION_NONE;
|
||||||
|
|
||||||
char nick[TOX_MAX_NAME_LENGTH];
|
char nick[TOX_MAX_NAME_LENGTH];
|
||||||
char statusmsg[MAX_STR_SIZE];
|
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH];
|
||||||
|
|
||||||
uint16_t n_len = tox_get_self_name(m, (uint8_t *) nick);
|
size_t n_len = tox_self_get_name_size(m);
|
||||||
uint16_t s_len = tox_get_self_status_message(m, (uint8_t *) statusmsg, MAX_STR_SIZE);
|
tox_self_get_name(m, (uint8_t *) nick);
|
||||||
uint8_t status = tox_get_self_user_status(m);
|
|
||||||
|
size_t s_len = tox_self_get_status_message_size(m);
|
||||||
|
tox_self_get_status_message(m, (uint8_t *) statusmsg);
|
||||||
|
|
||||||
|
TOX_USER_STATUS status = tox_self_get_status(m);
|
||||||
|
|
||||||
nick[n_len] = '\0';
|
nick[n_len] = '\0';
|
||||||
statusmsg[s_len] = '\0';
|
statusmsg[s_len] = '\0';
|
||||||
|
|
||||||
/* load prev status message or show toxic version if it has never been set */
|
if (s_len == 0 || !strncmp(statusmsg, "Toxing on Toxic", strlen("Toxing on Toxic"))) {
|
||||||
char ver[strlen(TOXICVER) + 1];
|
snprintf(statusmsg, sizeof(statusmsg), "Toxing on Toxic");
|
||||||
strcpy(ver, TOXICVER);
|
|
||||||
const char *toxic_ver = strtok(ver, "_");
|
|
||||||
|
|
||||||
if ( (s_len <= 0 || !strncmp("Toxing on Toxic", statusmsg, strlen("Toxing on Toxic"))) && toxic_ver != NULL) {
|
|
||||||
snprintf(statusmsg, sizeof(statusmsg), "Toxing on Toxic v.%s", toxic_ver);
|
|
||||||
s_len = strlen(statusmsg);
|
s_len = strlen(statusmsg);
|
||||||
statusmsg[s_len] = '\0';
|
statusmsg[s_len] = '\0';
|
||||||
}
|
}
|
||||||
@ -433,7 +441,7 @@ 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, 1, BLUE, " | || |_| / \\ | | |___ ");
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, BLUE, " |_| \\___/_/\\_\\___\\____|");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, BLUE, " |_| \\___/_/\\_\\___\\____| v." TOXICVER);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
|
||||||
|
|
||||||
const char *msg = "Welcome to Toxic, a free, open source Tox-based instant messenging client.";
|
const char *msg = "Welcome to Toxic, a free, open source Tox-based instant messenging client.";
|
||||||
@ -462,8 +470,8 @@ static void prompt_onInit(ToxWindow *self, Tox *m)
|
|||||||
line_info_init(ctx->hst);
|
line_info_init(ctx->hst);
|
||||||
|
|
||||||
if (user_settings->autolog == AUTOLOG_ON) {
|
if (user_settings->autolog == AUTOLOG_ON) {
|
||||||
char myid[TOX_FRIEND_ADDRESS_SIZE];
|
char myid[TOX_ADDRESS_SIZE];
|
||||||
tox_get_address(m, (uint8_t *) myid);
|
tox_self_get_address(m, (uint8_t *) myid);
|
||||||
log_enable(self->name, myid, NULL, ctx->log, LOG_PROMPT);
|
log_enable(self->name, myid, NULL, ctx->log, LOG_PROMPT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -502,6 +510,6 @@ ToxWindow new_prompt(void)
|
|||||||
ret.help = help;
|
ret.help = help;
|
||||||
|
|
||||||
ret.active_box = -1;
|
ret.active_box = -1;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
13
src/prompt.h
13
src/prompt.h
@ -26,18 +26,12 @@
|
|||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
|
|
||||||
#ifdef AUDIO
|
|
||||||
#define AC_NUM_GLOB_COMMANDS 19
|
|
||||||
#else
|
|
||||||
#define AC_NUM_GLOB_COMMANDS 17
|
|
||||||
#endif /* AUDIO */
|
|
||||||
|
|
||||||
#define MAX_FRIEND_REQUESTS 32
|
#define MAX_FRIEND_REQUESTS 32
|
||||||
|
|
||||||
struct friend_request {
|
struct friend_request {
|
||||||
bool active;
|
bool active;
|
||||||
char msg[MAX_STR_SIZE];
|
char msg[MAX_STR_SIZE];
|
||||||
uint8_t key[TOX_CLIENT_ID_SIZE];
|
uint8_t key[TOX_PUBLIC_KEY_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -51,8 +45,11 @@ void prep_prompt_win(void);
|
|||||||
void prompt_init_statusbar(ToxWindow *self, Tox *m);
|
void prompt_init_statusbar(ToxWindow *self, Tox *m);
|
||||||
void prompt_update_nick(ToxWindow *prompt, const char *nick);
|
void prompt_update_nick(ToxWindow *prompt, const char *nick);
|
||||||
void prompt_update_statusmessage(ToxWindow *prompt, Tox *m, const char *statusmsg);
|
void prompt_update_statusmessage(ToxWindow *prompt, Tox *m, const char *statusmsg);
|
||||||
void prompt_update_status(ToxWindow *prompt, uint8_t status);
|
void prompt_update_status(ToxWindow *prompt, TOX_USER_STATUS status);
|
||||||
void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected);
|
void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected);
|
||||||
void kill_prompt_window(ToxWindow *self);
|
void kill_prompt_window(ToxWindow *self);
|
||||||
|
|
||||||
|
/* callback: Updates own connection status in prompt statusbar */
|
||||||
|
void prompt_onSelfConnectionChange(Tox *m, TOX_CONNECTION connection_status, void *userdata);
|
||||||
|
|
||||||
#endif /* end of include guard: PROMPT_H */
|
#endif /* end of include guard: PROMPT_H */
|
||||||
|
257
src/settings.c
257
src/settings.c
@ -47,31 +47,51 @@
|
|||||||
static struct ui_strings {
|
static struct ui_strings {
|
||||||
const char* self;
|
const char* self;
|
||||||
const char* timestamps;
|
const char* timestamps;
|
||||||
|
const char* time_format;
|
||||||
|
const char* timestamp_format;
|
||||||
|
const char* log_timestamp_format;
|
||||||
const char* alerts;
|
const char* alerts;
|
||||||
const char* native_colors;
|
const char* native_colors;
|
||||||
const char* autolog;
|
const char* autolog;
|
||||||
const char* time_format;
|
|
||||||
const char* history_size;
|
const char* history_size;
|
||||||
const char* show_typing_self;
|
const char* show_typing_self;
|
||||||
const char* show_typing_other;
|
const char* show_typing_other;
|
||||||
const char* show_welcome_msg;
|
const char* show_welcome_msg;
|
||||||
|
|
||||||
|
const char* line_join;
|
||||||
|
const char* line_quit;
|
||||||
|
const char* line_alert;
|
||||||
|
const char* line_normal;
|
||||||
|
|
||||||
|
const char* mplex_away;
|
||||||
|
const char* mplex_away_note;
|
||||||
} ui_strings = {
|
} ui_strings = {
|
||||||
"ui",
|
"ui",
|
||||||
"timestamps",
|
"timestamps",
|
||||||
|
"time_format",
|
||||||
|
"timestamp_format",
|
||||||
|
"log_timestamp_format",
|
||||||
"alerts",
|
"alerts",
|
||||||
"native_colors",
|
"native_colors",
|
||||||
"autolog",
|
"autolog",
|
||||||
"time_format",
|
|
||||||
"history_size",
|
"history_size",
|
||||||
"show_typing_self",
|
"show_typing_self",
|
||||||
"show_typing_other",
|
"show_typing_other",
|
||||||
"show_welcome_msg",
|
"show_welcome_msg",
|
||||||
|
"line_join",
|
||||||
|
"line_quit",
|
||||||
|
"line_alert",
|
||||||
|
"line_normal",
|
||||||
|
"mplex_away",
|
||||||
|
"mplex_away_note",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ui_defaults(struct user_settings* settings)
|
static void ui_defaults(struct user_settings* settings)
|
||||||
{
|
{
|
||||||
settings->timestamps = TIMESTAMPS_ON;
|
settings->timestamps = TIMESTAMPS_ON;
|
||||||
settings->time = TIME_24;
|
snprintf(settings->timestamp_format, sizeof(settings->timestamp_format), "%s", TIMESTAMP_DEFAULT);
|
||||||
|
snprintf(settings->log_timestamp_format, sizeof(settings->log_timestamp_format), "%s", LOG_TIMESTAMP_DEFAULT);
|
||||||
|
|
||||||
settings->autolog = AUTOLOG_OFF;
|
settings->autolog = AUTOLOG_OFF;
|
||||||
settings->alerts = ALERTS_ENABLED;
|
settings->alerts = ALERTS_ENABLED;
|
||||||
settings->colour_theme = DFLT_COLS;
|
settings->colour_theme = DFLT_COLS;
|
||||||
@ -79,44 +99,58 @@ static void ui_defaults(struct user_settings* settings)
|
|||||||
settings->show_typing_self = SHOW_TYPING_ON;
|
settings->show_typing_self = SHOW_TYPING_ON;
|
||||||
settings->show_typing_other = SHOW_TYPING_ON;
|
settings->show_typing_other = SHOW_TYPING_ON;
|
||||||
settings->show_welcome_msg = SHOW_WELCOME_MSG_ON;
|
settings->show_welcome_msg = SHOW_WELCOME_MSG_ON;
|
||||||
|
|
||||||
|
snprintf(settings->line_join, LINE_HINT_MAX + 1, "%s", LINE_JOIN);
|
||||||
|
snprintf(settings->line_quit, LINE_HINT_MAX + 1, "%s", LINE_QUIT);
|
||||||
|
snprintf(settings->line_alert, LINE_HINT_MAX + 1, "%s", LINE_ALERT);
|
||||||
|
snprintf(settings->line_normal, LINE_HINT_MAX + 1, "%s", LINE_NORMAL);
|
||||||
|
|
||||||
|
settings->mplex_away = MPLEX_ON;
|
||||||
|
snprintf (settings->mplex_away_note,
|
||||||
|
sizeof (settings->mplex_away_note),
|
||||||
|
"%s",
|
||||||
|
MPLEX_AWAY_NOTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct keys_strings {
|
static const struct keys_strings {
|
||||||
const char* self;
|
const char* self;
|
||||||
const char* next_tab;
|
const char* next_tab;
|
||||||
const char* prev_tab;
|
const char* prev_tab;
|
||||||
const char* scroll_line_up;
|
const char* scroll_line_up;
|
||||||
const char* scroll_line_down;
|
const char* scroll_line_down;
|
||||||
const char* half_page_up;
|
const char* half_page_up;
|
||||||
const char* half_page_down;
|
const char* half_page_down;
|
||||||
const char* page_bottom;
|
const char* page_bottom;
|
||||||
const char* peer_list_up;
|
const char* peer_list_up;
|
||||||
const char* peer_list_down;
|
const char* peer_list_down;
|
||||||
|
const char* toggle_peerlist;
|
||||||
} key_strings = {
|
} key_strings = {
|
||||||
"keys",
|
"keys",
|
||||||
"next_tab",
|
"next_tab",
|
||||||
"prev_tab",
|
"prev_tab",
|
||||||
"scroll_line_up",
|
"scroll_line_up",
|
||||||
"scroll_line_down",
|
"scroll_line_down",
|
||||||
"half_page_up",
|
"half_page_up",
|
||||||
"half_page_down",
|
"half_page_down",
|
||||||
"page_bottom",
|
"page_bottom",
|
||||||
"peer_list_up",
|
"peer_list_up",
|
||||||
"peer_list_down"
|
"peer_list_down",
|
||||||
|
"toggle_peerlist",
|
||||||
};
|
};
|
||||||
|
|
||||||
/* defines from toxic.h */
|
/* defines from toxic.h */
|
||||||
static void key_defaults(struct user_settings* settings)
|
static void key_defaults(struct user_settings* settings)
|
||||||
{
|
{
|
||||||
settings->key_next_tab = T_KEY_NEXT;
|
settings->key_next_tab = T_KEY_NEXT;
|
||||||
settings->key_prev_tab = T_KEY_PREV;
|
settings->key_prev_tab = T_KEY_PREV;
|
||||||
settings->key_scroll_line_up = KEY_PPAGE;
|
settings->key_scroll_line_up = KEY_PPAGE;
|
||||||
settings->key_scroll_line_down = KEY_NPAGE;
|
settings->key_scroll_line_down = KEY_NPAGE;
|
||||||
settings->key_half_page_up = T_KEY_C_F;
|
settings->key_half_page_up = T_KEY_C_F;
|
||||||
settings->key_half_page_down = T_KEY_C_V;
|
settings->key_half_page_down = T_KEY_C_V;
|
||||||
settings->key_page_bottom = T_KEY_C_H;
|
settings->key_page_bottom = T_KEY_C_H;
|
||||||
settings->key_peer_list_up = T_KEY_C_LB;
|
settings->key_peer_list_up = T_KEY_C_LB;
|
||||||
settings->key_peer_list_down = T_KEY_C_RB;
|
settings->key_peer_list_down = T_KEY_C_RB;
|
||||||
|
settings->key_toggle_peerlist = T_KEY_C_B;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct tox_strings {
|
static const struct tox_strings {
|
||||||
@ -162,7 +196,7 @@ static void audio_defaults(struct user_settings* settings)
|
|||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
static const struct sound_strings {
|
static const struct sound_strings {
|
||||||
const char* self;
|
const char* self;
|
||||||
const char* error;
|
const char* notif_error;
|
||||||
const char* self_log_in;
|
const char* self_log_in;
|
||||||
const char* self_log_out;
|
const char* self_log_out;
|
||||||
const char* user_log_in;
|
const char* user_log_in;
|
||||||
@ -174,7 +208,7 @@ static const struct sound_strings {
|
|||||||
const char* transfer_completed;
|
const char* transfer_completed;
|
||||||
} sound_strings = {
|
} sound_strings = {
|
||||||
"sounds",
|
"sounds",
|
||||||
"error",
|
"notif_error",
|
||||||
"self_log_in",
|
"self_log_in",
|
||||||
"self_log_out",
|
"self_log_out",
|
||||||
"user_log_in",
|
"user_log_in",
|
||||||
@ -191,11 +225,11 @@ static int key_parse(const char** bind){
|
|||||||
int len = strlen(*bind);
|
int len = strlen(*bind);
|
||||||
|
|
||||||
if (len > 5) {
|
if (len > 5) {
|
||||||
if(strncasecmp(*bind, "ctrl+", 5) == 0)
|
if(strncasecmp(*bind, "ctrl+", 5) == 0)
|
||||||
return toupper(bind[0][5]) - 'A' + 1;
|
return toupper(bind[0][5]) - 'A' + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strncasecmp(*bind, "tab", 3) == 0)
|
if (strncasecmp(*bind, "tab", 3) == 0)
|
||||||
return T_KEY_TAB;
|
return T_KEY_TAB;
|
||||||
|
|
||||||
if (strncasecmp(*bind, "page", 4) == 0)
|
if (strncasecmp(*bind, "page", 4) == 0)
|
||||||
@ -209,7 +243,7 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
config_t cfg[1];
|
config_t cfg[1];
|
||||||
config_setting_t *setting;
|
config_setting_t *setting;
|
||||||
const char *str = NULL;
|
const char *str = NULL;
|
||||||
|
|
||||||
/* Load default settings */
|
/* Load default settings */
|
||||||
ui_defaults(s);
|
ui_defaults(s);
|
||||||
tox_defaults(s);
|
tox_defaults(s);
|
||||||
@ -250,6 +284,23 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
/* ui */
|
/* ui */
|
||||||
if ((setting = config_lookup(cfg, ui_strings.self)) != NULL) {
|
if ((setting = config_lookup(cfg, ui_strings.self)) != NULL) {
|
||||||
config_setting_lookup_bool(setting, ui_strings.timestamps, &s->timestamps);
|
config_setting_lookup_bool(setting, ui_strings.timestamps, &s->timestamps);
|
||||||
|
|
||||||
|
int time = 24;
|
||||||
|
if ( config_setting_lookup_int(setting, ui_strings.time_format, &time) ) {
|
||||||
|
if (time == 12) {
|
||||||
|
snprintf(s->timestamp_format, sizeof(s->timestamp_format), "%s", "%I:%M:%S %p");
|
||||||
|
snprintf(s->log_timestamp_format, sizeof(s->log_timestamp_format), "%s", "%Y/%m/%d [%I:%M:%S %p]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( config_setting_lookup_string(setting, ui_strings.timestamp_format, &str) ) {
|
||||||
|
snprintf(s->timestamp_format, sizeof(s->timestamp_format), "%s", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( config_setting_lookup_string(setting, ui_strings.log_timestamp_format, &str) ) {
|
||||||
|
snprintf(s->log_timestamp_format, sizeof(s->log_timestamp_format), "%s", str);
|
||||||
|
}
|
||||||
|
|
||||||
config_setting_lookup_bool(setting, ui_strings.alerts, &s->alerts);
|
config_setting_lookup_bool(setting, ui_strings.alerts, &s->alerts);
|
||||||
config_setting_lookup_bool(setting, ui_strings.autolog, &s->autolog);
|
config_setting_lookup_bool(setting, ui_strings.autolog, &s->autolog);
|
||||||
config_setting_lookup_bool(setting, ui_strings.native_colors, &s->colour_theme);
|
config_setting_lookup_bool(setting, ui_strings.native_colors, &s->colour_theme);
|
||||||
@ -257,8 +308,25 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
config_setting_lookup_bool(setting, ui_strings.show_typing_self, &s->show_typing_self);
|
config_setting_lookup_bool(setting, ui_strings.show_typing_self, &s->show_typing_self);
|
||||||
config_setting_lookup_bool(setting, ui_strings.show_typing_other, &s->show_typing_other);
|
config_setting_lookup_bool(setting, ui_strings.show_typing_other, &s->show_typing_other);
|
||||||
config_setting_lookup_bool(setting, ui_strings.show_welcome_msg, &s->show_welcome_msg);
|
config_setting_lookup_bool(setting, ui_strings.show_welcome_msg, &s->show_welcome_msg);
|
||||||
config_setting_lookup_int(setting, ui_strings.time_format, &s->time);
|
|
||||||
s->time = s->time == TIME_24 || s->time == TIME_12 ? s->time : TIME_24; /* Check defaults */
|
if ( config_setting_lookup_string(setting, ui_strings.line_join, &str) ) {
|
||||||
|
snprintf(s->line_join, sizeof(s->line_join), "%s", str);
|
||||||
|
}
|
||||||
|
if ( config_setting_lookup_string(setting, ui_strings.line_quit, &str) ) {
|
||||||
|
snprintf(s->line_quit, sizeof(s->line_quit), "%s", str);
|
||||||
|
}
|
||||||
|
if ( config_setting_lookup_string(setting, ui_strings.line_alert, &str) ) {
|
||||||
|
snprintf(s->line_alert, sizeof(s->line_alert), "%s", str);
|
||||||
|
}
|
||||||
|
if ( config_setting_lookup_string(setting, ui_strings.line_normal, &str) ) {
|
||||||
|
snprintf(s->line_normal, sizeof(s->line_normal), "%s", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
config_setting_lookup_bool (setting, ui_strings.mplex_away, &s->mplex_away);
|
||||||
|
|
||||||
|
if (config_setting_lookup_string (setting, ui_strings.mplex_away_note, &str)) {
|
||||||
|
snprintf (s->mplex_away_note, sizeof (s->mplex_away_note), "%s", str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* paths */
|
/* paths */
|
||||||
@ -278,7 +346,7 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
snprintf(s->chatlogs_path, sizeof(s->chatlogs_path), "%s", str);
|
snprintf(s->chatlogs_path, sizeof(s->chatlogs_path), "%s", str);
|
||||||
int len = strlen(s->chatlogs_path);
|
int len = strlen(s->chatlogs_path);
|
||||||
|
|
||||||
if (len >= sizeof(s->chatlogs_path) - 2)
|
if (len >= sizeof(s->chatlogs_path) - 2)
|
||||||
s->chatlogs_path[0] = '\0';
|
s->chatlogs_path[0] = '\0';
|
||||||
else if (s->chatlogs_path[len - 1] != '/')
|
else if (s->chatlogs_path[len - 1] != '/')
|
||||||
strcat(&s->chatlogs_path[len - 1], "/");
|
strcat(&s->chatlogs_path[len - 1], "/");
|
||||||
@ -286,112 +354,109 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
|
|
||||||
if ( config_setting_lookup_string(setting, tox_strings.avatar_path, &str) ) {
|
if ( config_setting_lookup_string(setting, tox_strings.avatar_path, &str) ) {
|
||||||
snprintf(s->avatar_path, sizeof(s->avatar_path), "%s", str);
|
snprintf(s->avatar_path, sizeof(s->avatar_path), "%s", str);
|
||||||
int len = strlen(s->avatar_path);
|
int len = strlen(str);
|
||||||
|
|
||||||
if (len >= sizeof(s->avatar_path))
|
if (len >= sizeof(s->avatar_path))
|
||||||
s->avatar_path[0] = '\0';
|
s->avatar_path[0] = '\0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* keys */
|
/* keys */
|
||||||
if ((setting = config_lookup(cfg, key_strings.self)) != NULL) {
|
if ((setting = config_lookup(cfg, key_strings.self)) != NULL) {
|
||||||
const char* tmp = NULL;
|
const char* tmp = NULL;
|
||||||
if (config_setting_lookup_string(setting, key_strings.next_tab, &tmp)) s->key_next_tab = key_parse(&tmp);
|
if (config_setting_lookup_string(setting, key_strings.next_tab, &tmp))
|
||||||
if (config_setting_lookup_string(setting, key_strings.prev_tab, &tmp)) s->key_prev_tab = key_parse(&tmp);
|
s->key_next_tab = key_parse(&tmp);
|
||||||
if (config_setting_lookup_string(setting, key_strings.scroll_line_up, &tmp)) s->key_scroll_line_up = key_parse(&tmp);
|
if (config_setting_lookup_string(setting, key_strings.prev_tab, &tmp))
|
||||||
if (config_setting_lookup_string(setting, key_strings.scroll_line_down, &tmp)) s->key_scroll_line_down= key_parse(&tmp);
|
s->key_prev_tab = key_parse(&tmp);
|
||||||
if (config_setting_lookup_string(setting, key_strings.half_page_up, &tmp)) s->key_half_page_up = key_parse(&tmp);
|
if (config_setting_lookup_string(setting, key_strings.scroll_line_up, &tmp))
|
||||||
if (config_setting_lookup_string(setting, key_strings.half_page_down, &tmp)) s->key_half_page_down = key_parse(&tmp);
|
s->key_scroll_line_up = key_parse(&tmp);
|
||||||
if (config_setting_lookup_string(setting, key_strings.page_bottom, &tmp)) s->key_page_bottom = key_parse(&tmp);
|
if (config_setting_lookup_string(setting, key_strings.scroll_line_down, &tmp))
|
||||||
if (config_setting_lookup_string(setting, key_strings.peer_list_up, &tmp)) s->key_peer_list_up = key_parse(&tmp);
|
s->key_scroll_line_down= key_parse(&tmp);
|
||||||
if (config_setting_lookup_string(setting, key_strings.peer_list_down, &tmp)) s->key_peer_list_down = key_parse(&tmp);
|
if (config_setting_lookup_string(setting, key_strings.half_page_up, &tmp))
|
||||||
}
|
s->key_half_page_up = key_parse(&tmp);
|
||||||
|
if (config_setting_lookup_string(setting, key_strings.half_page_down, &tmp))
|
||||||
|
s->key_half_page_down = key_parse(&tmp);
|
||||||
|
if (config_setting_lookup_string(setting, key_strings.page_bottom, &tmp))
|
||||||
|
s->key_page_bottom = key_parse(&tmp);
|
||||||
|
if (config_setting_lookup_string(setting, key_strings.peer_list_up, &tmp))
|
||||||
|
s->key_peer_list_up = key_parse(&tmp);
|
||||||
|
if (config_setting_lookup_string(setting, key_strings.peer_list_down, &tmp))
|
||||||
|
s->key_peer_list_down = key_parse(&tmp);
|
||||||
|
if (config_setting_lookup_string(setting, key_strings.toggle_peerlist, &tmp))
|
||||||
|
s->key_toggle_peerlist = key_parse(&tmp);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
if ((setting = config_lookup(cfg, audio_strings.self)) != NULL) {
|
if ((setting = config_lookup(cfg, audio_strings.self)) != NULL) {
|
||||||
config_setting_lookup_int(setting, audio_strings.input_device, &s->audio_in_dev);
|
config_setting_lookup_int(setting, audio_strings.input_device, &s->audio_in_dev);
|
||||||
s->audio_in_dev = s->audio_in_dev < 0 || s->audio_in_dev > MAX_DEVICES ? 0 : s->audio_in_dev;
|
s->audio_in_dev = s->audio_in_dev < 0 || s->audio_in_dev > MAX_DEVICES ? 0 : s->audio_in_dev;
|
||||||
|
|
||||||
config_setting_lookup_int(setting, audio_strings.output_device, &s->audio_out_dev);
|
config_setting_lookup_int(setting, audio_strings.output_device, &s->audio_out_dev);
|
||||||
s->audio_out_dev = s->audio_out_dev < 0 || s->audio_out_dev > MAX_DEVICES ? 0 : s->audio_out_dev;
|
s->audio_out_dev = s->audio_out_dev < 0 || s->audio_out_dev > MAX_DEVICES ? 0 : s->audio_out_dev;
|
||||||
|
|
||||||
config_setting_lookup_float(setting, audio_strings.VAD_treshold, &s->VAD_treshold);
|
config_setting_lookup_float(setting, audio_strings.VAD_treshold, &s->VAD_treshold);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
#ifdef SOUND_NOTIFY
|
||||||
if ((setting = config_lookup(cfg, sound_strings.self)) != NULL) {
|
if ((setting = config_lookup(cfg, sound_strings.self)) != NULL) {
|
||||||
if ( (config_setting_lookup_string(setting, sound_strings.error, &str) != CONFIG_TRUE) ||
|
if ( (config_setting_lookup_string(setting, sound_strings.notif_error, &str) != CONFIG_TRUE) ||
|
||||||
!set_sound(error, str) ) {
|
!set_sound(notif_error, str) ) {
|
||||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
if (str && strcasecmp(str, NO_SOUND) != 0)
|
||||||
set_sound(error, PACKAGE_DATADIR "/sounds/Error.wav");
|
set_sound(notif_error, PACKAGE_DATADIR "/sounds/ToxicError.wav");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !config_setting_lookup_string(setting, sound_strings.user_log_in, &str) ||
|
if ( !config_setting_lookup_string(setting, sound_strings.user_log_in, &str) ||
|
||||||
!set_sound(user_log_in, str) ) {
|
!set_sound(user_log_in, str) ) {
|
||||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
if (str && strcasecmp(str, NO_SOUND) != 0)
|
||||||
set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ContactLogsIn.wav");
|
set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ToxicContactOnline.wav");
|
||||||
}
|
|
||||||
|
|
||||||
if ( !config_setting_lookup_string(setting, sound_strings.self_log_in, &str) ||
|
|
||||||
!set_sound(self_log_in, str) ) {
|
|
||||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
|
||||||
set_sound(self_log_in, PACKAGE_DATADIR "/sounds/LogIn.wav");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !config_setting_lookup_string(setting, sound_strings.user_log_out, &str) ||
|
if ( !config_setting_lookup_string(setting, sound_strings.user_log_out, &str) ||
|
||||||
!set_sound(user_log_out, str) ) {
|
!set_sound(user_log_out, str) ) {
|
||||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
if (str && strcasecmp(str, NO_SOUND) != 0)
|
||||||
set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ContactLogsOut.wav");
|
set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ToxicContactOffline.wav");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !config_setting_lookup_string(setting, sound_strings.self_log_out, &str) ||
|
|
||||||
!set_sound(self_log_out, str) ) {
|
|
||||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
|
||||||
set_sound(self_log_out, PACKAGE_DATADIR "/sounds/LogOut.wav");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !config_setting_lookup_string(setting, sound_strings.call_incoming, &str) ||
|
if ( !config_setting_lookup_string(setting, sound_strings.call_incoming, &str) ||
|
||||||
!set_sound(call_incoming, str) ) {
|
!set_sound(call_incoming, str) ) {
|
||||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
if (str && strcasecmp(str, NO_SOUND) != 0)
|
||||||
set_sound(call_incoming, PACKAGE_DATADIR "/sounds/IncomingCall.wav");
|
set_sound(call_incoming, PACKAGE_DATADIR "/sounds/ToxicIncomingCall.wav");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !config_setting_lookup_string(setting, sound_strings.call_outgoing, &str) ||
|
if ( !config_setting_lookup_string(setting, sound_strings.call_outgoing, &str) ||
|
||||||
!set_sound(call_outgoing, str) ) {
|
!set_sound(call_outgoing, str) ) {
|
||||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
if (str && strcasecmp(str, NO_SOUND) != 0)
|
||||||
set_sound(call_outgoing, PACKAGE_DATADIR "/sounds/OutgoingCall.wav");
|
set_sound(call_outgoing, PACKAGE_DATADIR "/sounds/ToxicOutgoingCall.wav");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !config_setting_lookup_string(setting, sound_strings.generic_message, &str) ||
|
if ( !config_setting_lookup_string(setting, sound_strings.generic_message, &str) ||
|
||||||
!set_sound(generic_message, str) ) {
|
!set_sound(generic_message, str) ) {
|
||||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
if (str && strcasecmp(str, NO_SOUND) != 0)
|
||||||
set_sound(generic_message, PACKAGE_DATADIR "/sounds/NewMessage.wav");
|
set_sound(generic_message, PACKAGE_DATADIR "/sounds/ToxicRecvMessage.wav");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !config_setting_lookup_string(setting, sound_strings.transfer_pending, &str) ||
|
if ( !config_setting_lookup_string(setting, sound_strings.transfer_pending, &str) ||
|
||||||
!set_sound(transfer_pending, str) ) {
|
!set_sound(transfer_pending, str) ) {
|
||||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
if (str && strcasecmp(str, NO_SOUND) != 0)
|
||||||
set_sound(transfer_pending, PACKAGE_DATADIR "/sounds/TransferPending.wav");
|
set_sound(transfer_pending, PACKAGE_DATADIR "/sounds/ToxicTransferStart.wav");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !config_setting_lookup_string(setting, sound_strings.transfer_completed, &str) ||
|
if ( !config_setting_lookup_string(setting, sound_strings.transfer_completed, &str) ||
|
||||||
!set_sound(transfer_completed, str) ) {
|
!set_sound(transfer_completed, str) ) {
|
||||||
if (str && strcasecmp(str, NO_SOUND) != 0)
|
if (str && strcasecmp(str, NO_SOUND) != 0)
|
||||||
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/TransferComplete.wav");
|
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/ToxicTransferComplete.wav");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
set_sound(error, PACKAGE_DATADIR "/sounds/Error.wav");
|
set_sound(notif_error, PACKAGE_DATADIR "/sounds/ToxicError.wav");
|
||||||
set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ContactLogsIn.wav");
|
set_sound(user_log_in, PACKAGE_DATADIR "/sounds/ToxicContactOnline.wav");
|
||||||
set_sound(self_log_in, PACKAGE_DATADIR "/sounds/LogIn.wav");
|
set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ToxicContactOffline.wav");
|
||||||
set_sound(user_log_out, PACKAGE_DATADIR "/sounds/ContactLogsOut.wav");
|
set_sound(call_incoming, PACKAGE_DATADIR "/sounds/ToxicIncomingCall.wav");
|
||||||
set_sound(self_log_out, PACKAGE_DATADIR "/sounds/LogOut.wav");
|
set_sound(call_outgoing, PACKAGE_DATADIR "/sounds/ToxicOutgoingCall.wav");
|
||||||
set_sound(call_incoming, PACKAGE_DATADIR "/sounds/IncomingCall.wav");
|
set_sound(generic_message, PACKAGE_DATADIR "/sounds/ToxicRecvMessage.wav");
|
||||||
set_sound(call_outgoing, PACKAGE_DATADIR "/sounds/OutgoingCall.wav");
|
set_sound(transfer_pending, PACKAGE_DATADIR "/sounds/ToxicTransferStart.wav");
|
||||||
set_sound(generic_message, PACKAGE_DATADIR "/sounds/NewMessage.wav");
|
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/ToxicTransferComplete.wav");
|
||||||
set_sound(transfer_pending, PACKAGE_DATADIR "/sounds/TransferPending.wav");
|
|
||||||
set_sound(transfer_completed, PACKAGE_DATADIR "/sounds/TransferComplete.wav");
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -25,31 +25,48 @@
|
|||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include <tox/tox.h>
|
||||||
|
|
||||||
|
/* Represents line_* hints max strlen */
|
||||||
|
#define LINE_HINT_MAX 3
|
||||||
|
|
||||||
/* holds user setting values */
|
/* holds user setting values */
|
||||||
struct user_settings {
|
struct user_settings {
|
||||||
int autolog; /* boolean */
|
int autolog; /* boolean */
|
||||||
int alerts; /* boolean */
|
int alerts; /* boolean */
|
||||||
int time; /* 12 or 24 */
|
|
||||||
int timestamps; /* boolean */
|
int timestamps; /* boolean */
|
||||||
|
char timestamp_format[TIME_STR_SIZE];
|
||||||
|
char log_timestamp_format[TIME_STR_SIZE];
|
||||||
|
|
||||||
int colour_theme; /* boolean (0 for default toxic colours) */
|
int colour_theme; /* boolean (0 for default toxic colours) */
|
||||||
int history_size; /* int between MIN_HISTORY and MAX_HISTORY */
|
int history_size; /* int between MIN_HISTORY and MAX_HISTORY */
|
||||||
int show_typing_self; /* boolean */
|
int show_typing_self; /* boolean */
|
||||||
int show_typing_other; /* boolean */
|
int show_typing_other; /* boolean */
|
||||||
int show_welcome_msg; /* boolean */
|
int show_welcome_msg; /* boolean */
|
||||||
|
|
||||||
|
char line_join[LINE_HINT_MAX + 1];
|
||||||
|
char line_quit[LINE_HINT_MAX + 1];
|
||||||
|
char line_alert[LINE_HINT_MAX + 1];
|
||||||
|
char line_normal[LINE_HINT_MAX + 1];
|
||||||
|
|
||||||
char download_path[PATH_MAX];
|
char download_path[PATH_MAX];
|
||||||
char chatlogs_path[PATH_MAX];
|
char chatlogs_path[PATH_MAX];
|
||||||
char avatar_path[PATH_MAX];
|
char avatar_path[PATH_MAX];
|
||||||
|
|
||||||
int key_next_tab;
|
int key_next_tab;
|
||||||
int key_prev_tab;
|
int key_prev_tab;
|
||||||
int key_scroll_line_up;
|
int key_scroll_line_up;
|
||||||
int key_scroll_line_down;
|
int key_scroll_line_down;
|
||||||
int key_half_page_up;
|
int key_half_page_up;
|
||||||
int key_half_page_down;
|
int key_half_page_down;
|
||||||
int key_page_bottom;
|
int key_page_bottom;
|
||||||
int key_peer_list_up;
|
int key_peer_list_up;
|
||||||
int key_peer_list_down;
|
int key_peer_list_down;
|
||||||
|
int key_toggle_peerlist;
|
||||||
|
|
||||||
|
int mplex_away; /* boolean (1 for reaction to terminal attach/detach) */
|
||||||
|
char mplex_away_note [TOX_MAX_STATUS_MESSAGE_LENGTH];
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
int audio_in_dev;
|
int audio_in_dev;
|
||||||
@ -62,9 +79,6 @@ enum {
|
|||||||
AUTOLOG_OFF = 0,
|
AUTOLOG_OFF = 0,
|
||||||
AUTOLOG_ON = 1,
|
AUTOLOG_ON = 1,
|
||||||
|
|
||||||
TIME_24 = 24,
|
|
||||||
TIME_12 = 12,
|
|
||||||
|
|
||||||
TIMESTAMPS_OFF = 0,
|
TIMESTAMPS_OFF = 0,
|
||||||
TIMESTAMPS_ON = 1,
|
TIMESTAMPS_ON = 1,
|
||||||
|
|
||||||
@ -81,7 +95,18 @@ enum {
|
|||||||
SHOW_WELCOME_MSG_ON = 1,
|
SHOW_WELCOME_MSG_ON = 1,
|
||||||
|
|
||||||
DFLT_HST_SIZE = 700,
|
DFLT_HST_SIZE = 700,
|
||||||
|
|
||||||
|
MPLEX_OFF = 0,
|
||||||
|
MPLEX_ON = 1,
|
||||||
} settings_values;
|
} settings_values;
|
||||||
|
|
||||||
|
#define LINE_JOIN "-->"
|
||||||
|
#define LINE_QUIT "<--"
|
||||||
|
#define LINE_ALERT "-!-"
|
||||||
|
#define LINE_NORMAL "---"
|
||||||
|
#define TIMESTAMP_DEFAULT "%H:%M:%S"
|
||||||
|
#define LOG_TIMESTAMP_DEFAULT "%Y/%m/%d [%H:%M:%S]"
|
||||||
|
#define MPLEX_AWAY_NOTE "Detached from screen"
|
||||||
|
|
||||||
int settings_load(struct user_settings *s, const char *patharg);
|
int settings_load(struct user_settings *s, const char *patharg);
|
||||||
#endif /* #define SETTINGS_H */
|
#endif /* #define SETTINGS_H */
|
||||||
|
390
src/term_mplex.c
Normal file
390
src/term_mplex.c
Normal file
@ -0,0 +1,390 @@
|
|||||||
|
/* term_mplex.c
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 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 <limits.h> /* PATH_MAX */
|
||||||
|
#include <stdio.h> /* fgets, popen, pclose */
|
||||||
|
#include <stdlib.h> /* malloc, realloc, free, getenv */
|
||||||
|
#include <string.h> /* strlen, strcpy, strstr, strchr, strrchr, strcat, strncmp */
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <tox/tox.h>
|
||||||
|
|
||||||
|
#include "global_commands.h"
|
||||||
|
#include "windows.h"
|
||||||
|
#include "term_mplex.h"
|
||||||
|
#include "toxic.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
|
extern struct ToxWindow *prompt;
|
||||||
|
extern struct user_settings *user_settings;
|
||||||
|
extern struct Winthread Winthread;
|
||||||
|
|
||||||
|
#if defined(PATH_MAX) && PATH_MAX > 512
|
||||||
|
#define BUFFER_SIZE PATH_MAX
|
||||||
|
#else
|
||||||
|
#define BUFFER_SIZE 512
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PATH_SEP_S "/"
|
||||||
|
#define PATH_SEP_C '/'
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
MPLEX_NONE,
|
||||||
|
MPLEX_SCREEN,
|
||||||
|
MPLEX_TMUX,
|
||||||
|
} mplex_status;
|
||||||
|
|
||||||
|
/* used for:
|
||||||
|
- storing screen socket name
|
||||||
|
- storing tmux session number in string form */
|
||||||
|
static char mplex_data [BUFFER_SIZE];
|
||||||
|
|
||||||
|
static char buffer [BUFFER_SIZE];
|
||||||
|
|
||||||
|
/* Differentiates between mplex auto-away and manual-away */
|
||||||
|
static bool auto_away_active = false;
|
||||||
|
|
||||||
|
static mplex_status mplex = MPLEX_NONE;
|
||||||
|
static TOX_USER_STATUS prev_status = TOX_USER_STATUS_NONE;
|
||||||
|
static char prev_note [TOX_MAX_STATUS_MESSAGE_LENGTH] = "";
|
||||||
|
|
||||||
|
/* mutex for access to status data, for sync between:
|
||||||
|
- user command /status from ncurses thread
|
||||||
|
- auto-away POSIX timer, which runs from a separate thread
|
||||||
|
after init, should be accessed only by cmd_status()
|
||||||
|
*/
|
||||||
|
static pthread_mutex_t status_lock;
|
||||||
|
static pthread_t mplex_tid;
|
||||||
|
|
||||||
|
void lock_status ()
|
||||||
|
{
|
||||||
|
pthread_mutex_lock (&status_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlock_status ()
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock (&status_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *read_into_dyn_buffer (FILE *stream)
|
||||||
|
{
|
||||||
|
const char *input_ptr = NULL;
|
||||||
|
char *dyn_buffer = NULL;
|
||||||
|
int dyn_buffer_size = 1; /* account for the \0 */
|
||||||
|
|
||||||
|
while ((input_ptr = fgets (buffer, BUFFER_SIZE, stream)) != NULL)
|
||||||
|
{
|
||||||
|
int length = dyn_buffer_size + strlen (input_ptr);
|
||||||
|
if (dyn_buffer)
|
||||||
|
dyn_buffer = (char*) realloc (dyn_buffer, length);
|
||||||
|
else
|
||||||
|
dyn_buffer = (char*) malloc (length);
|
||||||
|
strcpy (dyn_buffer + dyn_buffer_size - 1, input_ptr);
|
||||||
|
dyn_buffer_size = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dyn_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *extract_socket_path (const char *info)
|
||||||
|
{
|
||||||
|
const char *search_str = " Socket";
|
||||||
|
const char *pos = strstr (info, search_str);
|
||||||
|
char *end = NULL;
|
||||||
|
char* path = NULL;
|
||||||
|
|
||||||
|
if (!pos)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pos += strlen (search_str);
|
||||||
|
pos = strchr (pos, PATH_SEP_C);
|
||||||
|
if (!pos)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
end = strchr (pos, '\n');
|
||||||
|
if (!end)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*end = '\0';
|
||||||
|
end = strrchr (pos, '.');
|
||||||
|
if (!end)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
path = (char*) malloc (end - pos + 1);
|
||||||
|
*end = '\0';
|
||||||
|
return strcpy (path, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int detect_gnu_screen ()
|
||||||
|
{
|
||||||
|
FILE *session_info_stream = NULL;
|
||||||
|
char *socket_name = NULL, *socket_path = NULL;
|
||||||
|
char *dyn_buffer = NULL;
|
||||||
|
|
||||||
|
socket_name = getenv ("STY");
|
||||||
|
if (!socket_name)
|
||||||
|
goto nomplex;
|
||||||
|
|
||||||
|
session_info_stream = popen ("env LC_ALL=C screen -ls", "r");
|
||||||
|
if (!session_info_stream)
|
||||||
|
goto nomplex;
|
||||||
|
|
||||||
|
dyn_buffer = read_into_dyn_buffer (session_info_stream);
|
||||||
|
if (!dyn_buffer)
|
||||||
|
goto nomplex;
|
||||||
|
|
||||||
|
pclose (session_info_stream);
|
||||||
|
session_info_stream = NULL;
|
||||||
|
|
||||||
|
socket_path = extract_socket_path (dyn_buffer);
|
||||||
|
if (!socket_path)
|
||||||
|
goto nomplex;
|
||||||
|
|
||||||
|
free (dyn_buffer);
|
||||||
|
dyn_buffer = NULL;
|
||||||
|
strcpy (mplex_data, socket_path);
|
||||||
|
strcat (mplex_data, PATH_SEP_S);
|
||||||
|
strcat (mplex_data, socket_name);
|
||||||
|
free (socket_path);
|
||||||
|
socket_path = NULL;
|
||||||
|
|
||||||
|
mplex = MPLEX_SCREEN;
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
nomplex:
|
||||||
|
if (session_info_stream)
|
||||||
|
pclose (session_info_stream);
|
||||||
|
if (dyn_buffer)
|
||||||
|
free (dyn_buffer);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int detect_tmux ()
|
||||||
|
{
|
||||||
|
char *tmux_env = getenv ("TMUX"), *pos;
|
||||||
|
if (!tmux_env)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* find second separator */
|
||||||
|
pos = strrchr (tmux_env, ',');
|
||||||
|
if (!pos)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* store the session number string for later use */
|
||||||
|
strcpy (mplex_data, pos + 1);
|
||||||
|
mplex = MPLEX_TMUX;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Checks whether a terminal multiplexer (mplex) is present, and finds
|
||||||
|
its unix socket.
|
||||||
|
|
||||||
|
GNU screen and tmux are supported.
|
||||||
|
|
||||||
|
Returns 1 if present, 0 otherwise. This value can be used to determine
|
||||||
|
whether an auto-away detection timer is needed.
|
||||||
|
*/
|
||||||
|
static int detect_mplex ()
|
||||||
|
{
|
||||||
|
/* try screen, and if fails try tmux */
|
||||||
|
return detect_gnu_screen () || detect_tmux ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Detects gnu screen session attached/detached by examining permissions of
|
||||||
|
the session's unix socket.
|
||||||
|
*/
|
||||||
|
static int gnu_screen_is_detached ()
|
||||||
|
{
|
||||||
|
if (mplex != MPLEX_SCREEN)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
struct stat sb;
|
||||||
|
if (stat (mplex_data, &sb) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* execution permission (x) means attached */
|
||||||
|
return ! (sb.st_mode & S_IXUSR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Detects tmux attached/detached by getting session data and finding the
|
||||||
|
current session's entry. An attached entry ends with "(attached)". Example:
|
||||||
|
|
||||||
|
$ tmux list-sessions
|
||||||
|
0: 1 windows (created Mon Mar 2 21:48:29 2015) [80x23] (attached)
|
||||||
|
1: 2 windows (created Mon Mar 2 21:48:43 2015) [80x23]
|
||||||
|
|
||||||
|
In this example, session 0 is attached and session 1 is detached.
|
||||||
|
*/
|
||||||
|
static int tmux_is_detached ()
|
||||||
|
{
|
||||||
|
if (mplex != MPLEX_TMUX)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
FILE *session_info_stream = NULL;
|
||||||
|
char *dyn_buffer = NULL, *search_str = NULL;
|
||||||
|
char *entry_pos, *nl_pos, *attached_pos;
|
||||||
|
const int numstr_len = strlen (mplex_data);
|
||||||
|
|
||||||
|
session_info_stream = popen ("env LC_ALL=C tmux list-sessions", "r");
|
||||||
|
if (!session_info_stream)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
dyn_buffer = read_into_dyn_buffer (session_info_stream);
|
||||||
|
if (!dyn_buffer)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
pclose (session_info_stream);
|
||||||
|
session_info_stream = NULL;
|
||||||
|
|
||||||
|
/* prepare search string, for finding the current session's entry */
|
||||||
|
search_str = (char*) malloc (numstr_len + 4);
|
||||||
|
search_str[0] = '\n';
|
||||||
|
strcpy (search_str + 1, mplex_data);
|
||||||
|
strcat (search_str, ": ");
|
||||||
|
|
||||||
|
/* do the search */
|
||||||
|
if (strncmp (dyn_buffer, search_str + 1, numstr_len + 2) == 0)
|
||||||
|
entry_pos = dyn_buffer;
|
||||||
|
else
|
||||||
|
entry_pos = strstr (dyn_buffer, search_str);
|
||||||
|
|
||||||
|
if (! entry_pos)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* find the next \n and look for the "(attached)" before it */
|
||||||
|
nl_pos = strchr (entry_pos + 1, '\n');
|
||||||
|
attached_pos = strstr (entry_pos + 1, "(attached)\n");
|
||||||
|
|
||||||
|
free (search_str);
|
||||||
|
search_str = NULL;
|
||||||
|
|
||||||
|
free (dyn_buffer);
|
||||||
|
dyn_buffer = NULL;
|
||||||
|
|
||||||
|
return attached_pos == NULL || attached_pos > nl_pos;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (session_info_stream)
|
||||||
|
pclose (session_info_stream);
|
||||||
|
if (dyn_buffer)
|
||||||
|
free (dyn_buffer);
|
||||||
|
if (search_str)
|
||||||
|
free (search_str);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Checks whether there is a terminal multiplexer present, but in detached
|
||||||
|
state. Returns 1 if detached, 0 if attached or if there is no terminal
|
||||||
|
multiplexer.
|
||||||
|
|
||||||
|
If detect_mplex_socket() failed to find a mplex, there is no need to call
|
||||||
|
this function. If it did find one, this function can be used to periodically
|
||||||
|
sample its state and update away status according to attached/detached state
|
||||||
|
of the mplex.
|
||||||
|
*/
|
||||||
|
static int mplex_is_detached ()
|
||||||
|
{
|
||||||
|
return gnu_screen_is_detached () || tmux_is_detached ();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mplex_timer_handler (Tox *m)
|
||||||
|
{
|
||||||
|
TOX_USER_STATUS current_status, new_status;
|
||||||
|
const char *new_note;
|
||||||
|
|
||||||
|
if (mplex == MPLEX_NONE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int detached = mplex_is_detached ();
|
||||||
|
|
||||||
|
pthread_mutex_lock (&Winthread.lock);
|
||||||
|
current_status = tox_self_get_status (m);
|
||||||
|
pthread_mutex_unlock (&Winthread.lock);
|
||||||
|
|
||||||
|
if (auto_away_active && current_status == TOX_USER_STATUS_AWAY && !detached)
|
||||||
|
{
|
||||||
|
auto_away_active = false;
|
||||||
|
new_status = prev_status;
|
||||||
|
new_note = prev_note;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (current_status == TOX_USER_STATUS_NONE && detached)
|
||||||
|
{
|
||||||
|
auto_away_active = true;
|
||||||
|
prev_status = current_status;
|
||||||
|
new_status = TOX_USER_STATUS_AWAY;
|
||||||
|
pthread_mutex_lock (&Winthread.lock);
|
||||||
|
tox_self_get_status_message (m, (uint8_t*) prev_note);
|
||||||
|
pthread_mutex_unlock (&Winthread.lock);
|
||||||
|
new_note = user_settings->mplex_away_note;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
|
||||||
|
char argv[3][MAX_STR_SIZE];
|
||||||
|
strcpy (argv[0], "/status");
|
||||||
|
strcpy (argv[1], (new_status == TOX_USER_STATUS_AWAY ? "away" :
|
||||||
|
new_status == TOX_USER_STATUS_BUSY ? "busy" : "online"));
|
||||||
|
argv[2][0] = '\"';
|
||||||
|
strcpy (argv[2] + 1, new_note);
|
||||||
|
strcat (argv[2], "\"");
|
||||||
|
pthread_mutex_lock (&Winthread.lock);
|
||||||
|
cmd_status (prompt->chatwin->history, prompt, m, 2, argv);
|
||||||
|
pthread_mutex_unlock (&Winthread.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Time in seconds between calls to mplex_timer_handler */
|
||||||
|
#define MPLEX_TIMER_INTERVAL 5
|
||||||
|
|
||||||
|
void *mplex_timer_thread(void *data)
|
||||||
|
{
|
||||||
|
Tox *m = (Tox *) data;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
sleep(MPLEX_TIMER_INTERVAL);
|
||||||
|
mplex_timer_handler(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int init_mplex_away_timer (Tox *m)
|
||||||
|
{
|
||||||
|
if (! detect_mplex ())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (! user_settings->mplex_away)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* status access mutex */
|
||||||
|
if (pthread_mutex_init (&status_lock, NULL) != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (pthread_create(&mplex_tid, NULL, mplex_timer_thread, (void *) m) != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
35
src/term_mplex.h
Normal file
35
src/term_mplex.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/* term_mplex.h
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 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 TERM_MPLEX_H
|
||||||
|
#define TERM_MPLEX_H
|
||||||
|
|
||||||
|
/* Checks if Toxic runs inside a terminal multiplexer (GNU screen or tmux). If
|
||||||
|
yes, it initializes a timer which periodically checks the attached/detached
|
||||||
|
state of the terminal and updates away status accordingly.
|
||||||
|
*/
|
||||||
|
int init_mplex_away_timer (Tox *m);
|
||||||
|
|
||||||
|
void lock_status ();
|
||||||
|
void unlock_status ();
|
||||||
|
|
||||||
|
#endif /* #define TERM_MPLEX_H */
|
497
src/toxic.c
497
src/toxic.c
@ -1,4 +1,4 @@
|
|||||||
/* main.c
|
/* toxic.c
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Toxic All Rights Reserved.
|
* Copyright (C) 2014 Toxic All Rights Reserved.
|
||||||
@ -49,7 +49,7 @@
|
|||||||
#include "friendlist.h"
|
#include "friendlist.h"
|
||||||
#include "prompt.h"
|
#include "prompt.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
#include "file_senders.h"
|
#include "file_transfers.h"
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
@ -57,33 +57,36 @@
|
|||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "message_queue.h"
|
#include "message_queue.h"
|
||||||
#include "execute.h"
|
#include "execute.h"
|
||||||
|
#include "term_mplex.h"
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef X11
|
||||||
#include "audio_call.h"
|
#include "xtra.h"
|
||||||
#endif /* AUDIO */
|
|
||||||
|
|
||||||
#ifndef PACKAGE_DATADIR
|
|
||||||
#define PACKAGE_DATADIR "."
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
|
#include "audio_call.h"
|
||||||
ToxAv *av;
|
ToxAv *av;
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
|
#ifndef PACKAGE_DATADIR
|
||||||
|
#define PACKAGE_DATADIR "."
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Export for use in Callbacks */
|
/* Export for use in Callbacks */
|
||||||
char *DATA_FILE = NULL;
|
char *DATA_FILE = NULL;
|
||||||
char *BLOCK_FILE = NULL;
|
char *BLOCK_FILE = NULL;
|
||||||
ToxWindow *prompt = NULL;
|
ToxWindow *prompt = NULL;
|
||||||
|
|
||||||
#define AUTOSAVE_FREQ 60
|
#define AUTOSAVE_FREQ 60
|
||||||
|
#define MIN_PASSWORD_LEN 6
|
||||||
|
#define MAX_PASSWORD_LEN 64
|
||||||
|
|
||||||
struct Winthread Winthread;
|
struct Winthread Winthread;
|
||||||
struct cqueue_thread cqueue_thread;
|
struct cqueue_thread cqueue_thread;
|
||||||
|
struct audio_thread audio_thread;
|
||||||
struct arg_opts arg_opts;
|
struct arg_opts arg_opts;
|
||||||
struct user_settings *user_settings = NULL;
|
struct user_settings *user_settings = NULL;
|
||||||
|
|
||||||
#define MIN_PASSWORD_LEN 6
|
|
||||||
#define MAX_PASSWORD_LEN 64
|
|
||||||
|
|
||||||
static struct user_password {
|
static struct user_password {
|
||||||
bool data_is_encrypted;
|
bool data_is_encrypted;
|
||||||
@ -98,7 +101,7 @@ static void catch_SIGINT(int sig)
|
|||||||
|
|
||||||
static void catch_SIGSEGV(int sig)
|
static void catch_SIGSEGV(int sig)
|
||||||
{
|
{
|
||||||
freopen("/dev/tty", "w", stderr);
|
freopen("/dev/tty", "w", stderr); // make sure stderr is enabled since we may have disabled it
|
||||||
endwin();
|
endwin();
|
||||||
fprintf(stderr, "Caught SIGSEGV: Aborting toxic session.\n");
|
fprintf(stderr, "Caught SIGSEGV: Aborting toxic session.\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
@ -120,30 +123,32 @@ void exit_toxic_success(Tox *m)
|
|||||||
{
|
{
|
||||||
store_data(m, DATA_FILE);
|
store_data(m, DATA_FILE);
|
||||||
memset(&user_password, 0, sizeof(struct user_password));
|
memset(&user_password, 0, sizeof(struct user_password));
|
||||||
close_all_file_senders(m);
|
|
||||||
kill_all_windows(m);
|
kill_all_windows(m);
|
||||||
|
terminate_notify();
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
|
terminate_audio();
|
||||||
|
#endif /* AUDIO */
|
||||||
|
|
||||||
free(DATA_FILE);
|
free(DATA_FILE);
|
||||||
free(BLOCK_FILE);
|
free(BLOCK_FILE);
|
||||||
free(user_settings);
|
free(user_settings);
|
||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
|
||||||
// sound_notify(NULL, self_log_out, NT_ALWAYS, NULL);
|
|
||||||
#endif /* SOUND_NOTIFY */
|
|
||||||
terminate_notify();
|
|
||||||
#ifdef AUDIO
|
|
||||||
terminate_audio();
|
|
||||||
#endif /* AUDIO */
|
|
||||||
tox_kill(m);
|
tox_kill(m);
|
||||||
endwin();
|
endwin();
|
||||||
|
|
||||||
|
#ifdef X11
|
||||||
|
/* We have to terminate xtra last coz reasons
|
||||||
|
* Please don't call this anywhere else coz trust me
|
||||||
|
*/
|
||||||
|
terminate_xtra();
|
||||||
|
#endif /* X11 */
|
||||||
|
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void exit_toxic_err(const char *errmsg, int errcode)
|
void exit_toxic_err(const char *errmsg, int errcode)
|
||||||
{
|
{
|
||||||
if (errmsg == NULL)
|
|
||||||
errmsg = "No error message";
|
|
||||||
|
|
||||||
freopen("/dev/tty", "w", stderr);
|
freopen("/dev/tty", "w", stderr);
|
||||||
endwin();
|
endwin();
|
||||||
fprintf(stderr, "Toxic session aborted with error code %d (%s)\n", errcode, errmsg);
|
fprintf(stderr, "Toxic session aborted with error code %d (%s)\n", errcode, errmsg);
|
||||||
@ -157,7 +162,7 @@ static void init_term(void)
|
|||||||
if (!arg_opts.default_locale) {
|
if (!arg_opts.default_locale) {
|
||||||
if (setlocale(LC_ALL, "") == NULL)
|
if (setlocale(LC_ALL, "") == NULL)
|
||||||
exit_toxic_err("Could not set your locale, please check your locale settings or "
|
exit_toxic_err("Could not set your locale, please check your locale settings or "
|
||||||
"disable unicode support with the -d flag.", FATALERR_LOCALE_SET);
|
"disable unicode support with the -d flag.", FATALERR_LOCALE_NOT_SET);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -245,91 +250,16 @@ static void print_init_messages(ToxWindow *toxwin)
|
|||||||
line_info_add(toxwin, NULL, NULL, NULL, SYS_MSG, 0, 0, init_messages.msgs[i]);
|
line_info_add(toxwin, NULL, NULL, NULL, SYS_MSG, 0, 0, init_messages.msgs[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Tox *init_tox(void)
|
|
||||||
{
|
|
||||||
Tox_Options tox_opts;
|
|
||||||
tox_opts.ipv6enabled = !arg_opts.use_ipv4;
|
|
||||||
tox_opts.udp_disabled = arg_opts.force_tcp;
|
|
||||||
tox_opts.proxy_enabled = arg_opts.use_proxy;
|
|
||||||
|
|
||||||
if (tox_opts.proxy_enabled) {
|
|
||||||
tox_opts.proxy_port = arg_opts.proxy_port;
|
|
||||||
snprintf(tox_opts.proxy_address, sizeof(tox_opts.proxy_address), "%s", arg_opts.proxy_address);
|
|
||||||
|
|
||||||
char tmp[48];
|
|
||||||
snprintf(tmp, sizeof(tmp), "Using proxy %s : %d",
|
|
||||||
arg_opts.proxy_address, arg_opts.proxy_port);
|
|
||||||
queue_init_message("%s", tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tox_opts.udp_disabled) {
|
|
||||||
queue_init_message("UDP disabled");
|
|
||||||
} else if (tox_opts.proxy_enabled) {
|
|
||||||
const char *msg = "WARNING: Using a proxy without disabling UDP may leak your real IP address.";
|
|
||||||
queue_init_message("%s", msg);
|
|
||||||
msg = "Use the -t option to disable UDP.";
|
|
||||||
queue_init_message("%s", msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Init core */
|
|
||||||
Tox *m = tox_new(&tox_opts);
|
|
||||||
|
|
||||||
if (tox_opts.ipv6enabled && m == NULL) {
|
|
||||||
queue_init_message("IPv6 failed to initialize");
|
|
||||||
tox_opts.ipv6enabled = 0;
|
|
||||||
m = tox_new(&tox_opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tox_opts.ipv6enabled)
|
|
||||||
queue_init_message("Forcing IPv4 connection");
|
|
||||||
|
|
||||||
if (tox_opts.proxy_enabled && m == NULL)
|
|
||||||
exit_toxic_err("Proxy error", FATALERR_PROXY);
|
|
||||||
|
|
||||||
if (m == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* Callbacks */
|
|
||||||
tox_callback_connection_status(m, on_connectionchange, NULL);
|
|
||||||
tox_callback_typing_change(m, on_typing_change, NULL);
|
|
||||||
tox_callback_friend_request(m, on_request, NULL);
|
|
||||||
tox_callback_friend_message(m, on_message, NULL);
|
|
||||||
tox_callback_name_change(m, on_nickchange, NULL);
|
|
||||||
tox_callback_user_status(m, on_statuschange, NULL);
|
|
||||||
tox_callback_status_message(m, on_statusmessagechange, NULL);
|
|
||||||
tox_callback_friend_action(m, on_action, NULL);
|
|
||||||
tox_callback_group_invite(m, on_groupinvite, NULL);
|
|
||||||
tox_callback_group_message(m, on_groupmessage, NULL);
|
|
||||||
tox_callback_group_action(m, on_groupaction, NULL);
|
|
||||||
tox_callback_group_namelist_change(m, on_group_namelistchange, NULL);
|
|
||||||
tox_callback_file_send_request(m, on_file_sendrequest, NULL);
|
|
||||||
tox_callback_file_control(m, on_file_control, NULL);
|
|
||||||
tox_callback_file_data(m, on_file_data, NULL);
|
|
||||||
tox_callback_read_receipt(m, on_read_receipt, NULL);
|
|
||||||
|
|
||||||
#ifdef __linux__
|
|
||||||
tox_set_name(m, (uint8_t *) "Cool dude", strlen("Cool dude"));
|
|
||||||
#elif defined(__FreeBSD__)
|
|
||||||
tox_set_name(m, (uint8_t *) "Nerd", strlen("Nerd"));
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
tox_set_name(m, (uint8_t *) "Hipster", strlen("Hipster")); /* This used to users of other Unixes are hipsters */
|
|
||||||
#else
|
|
||||||
tox_set_name(m, (uint8_t *) "Registered Minix user #4", strlen("Registered Minix user #4"));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MIN_NODE_LINE 50 /* IP: 7 + port: 5 + key: 38 + spaces: 2 = 70. ! (& e.g. tox.im = 6) */
|
#define MIN_NODE_LINE 50 /* IP: 7 + port: 5 + key: 38 + spaces: 2 = 70. ! (& e.g. tox.im = 6) */
|
||||||
#define MAX_NODE_LINE 256 /* Approx max number of chars in a sever line (name + port + key) */
|
#define MAX_NODE_LINE 256 /* Approx max number of chars in a sever line (name + port + key) */
|
||||||
#define MAXNODES 50
|
#define MAXNODES 50
|
||||||
#define NODELEN (MAX_NODE_LINE - TOX_CLIENT_ID_SIZE - 7)
|
#define NODELEN (MAX_NODE_LINE - TOX_PUBLIC_KEY_SIZE - 7)
|
||||||
|
|
||||||
static struct toxNodes {
|
static struct toxNodes {
|
||||||
int lines;
|
int lines;
|
||||||
char nodes[MAXNODES][NODELEN];
|
char nodes[MAXNODES][NODELEN];
|
||||||
uint16_t ports[MAXNODES];
|
uint16_t ports[MAXNODES];
|
||||||
char keys[MAXNODES][TOX_CLIENT_ID_SIZE];
|
char keys[MAXNODES][TOX_PUBLIC_KEY_SIZE];
|
||||||
} toxNodes;
|
} toxNodes;
|
||||||
|
|
||||||
static int load_nodelist(const char *filename)
|
static int load_nodelist(const char *filename)
|
||||||
@ -359,7 +289,7 @@ static int load_nodelist(const char *filename)
|
|||||||
toxNodes.ports[toxNodes.lines] = atoi(port);
|
toxNodes.ports[toxNodes.lines] = atoi(port);
|
||||||
|
|
||||||
char *key_binary = hex_string_to_bin(key_ascii);
|
char *key_binary = hex_string_to_bin(key_ascii);
|
||||||
memcpy(toxNodes.keys[toxNodes.lines], key_binary, TOX_CLIENT_ID_SIZE);
|
memcpy(toxNodes.keys[toxNodes.lines], key_binary, TOX_PUBLIC_KEY_SIZE);
|
||||||
free(key_binary);
|
free(key_binary);
|
||||||
|
|
||||||
toxNodes.lines++;
|
toxNodes.lines++;
|
||||||
@ -376,7 +306,7 @@ static int load_nodelist(const char *filename)
|
|||||||
|
|
||||||
int init_connection_helper(Tox *m, int line)
|
int init_connection_helper(Tox *m, int line)
|
||||||
{
|
{
|
||||||
return tox_bootstrap_from_address(m, toxNodes.nodes[line], toxNodes.ports[line], (uint8_t *) toxNodes.keys[line]);
|
return tox_bootstrap(m, toxNodes.nodes[line], toxNodes.ports[line], (uint8_t *) toxNodes.keys[line], NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Connects to a random DHT node listed in the DHTnodes file
|
/* Connects to a random DHT node listed in the DHTnodes file
|
||||||
@ -428,50 +358,10 @@ int init_connection(Tox *m)
|
|||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TRY_CONNECT 10 /* Seconds between connection attempts when DHT is not connected */
|
|
||||||
|
|
||||||
static void do_connection(Tox *m, ToxWindow *prompt)
|
|
||||||
{
|
|
||||||
if (arg_opts.no_connect == 1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
char msg[MAX_STR_SIZE] = {0};
|
|
||||||
|
|
||||||
static int conn_err = 0;
|
|
||||||
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 (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 (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])
|
|
||||||
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void load_friendlist(Tox *m)
|
static void load_friendlist(Tox *m)
|
||||||
{
|
{
|
||||||
uint32_t i;
|
size_t i;
|
||||||
uint32_t numfriends = tox_count_friendlist(m);
|
size_t numfriends = tox_self_get_friend_list_size(m);
|
||||||
|
|
||||||
for (i = 0; i < numfriends; ++i)
|
for (i = 0; i < numfriends; ++i)
|
||||||
friendlist_onFriendAdded(NULL, m, i, false);
|
friendlist_onFriendAdded(NULL, m, i, false);
|
||||||
@ -524,7 +414,7 @@ static void first_time_encrypt(const char *msg)
|
|||||||
system("clear");
|
system("clear");
|
||||||
printf("%s ", msg);
|
printf("%s ", msg);
|
||||||
|
|
||||||
if (!strcasecmp(ch, "y\n") || !strcasecmp(ch, "n\n") || !strcasecmp(ch, "yes\n")
|
if (!strcasecmp(ch, "y\n") || !strcasecmp(ch, "n\n") || !strcasecmp(ch, "yes\n")
|
||||||
|| !strcasecmp(ch, "no\n") || !strcasecmp(ch, "q\n"))
|
|| !strcasecmp(ch, "no\n") || !strcasecmp(ch, "q\n"))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -539,6 +429,7 @@ static void first_time_encrypt(const char *msg)
|
|||||||
int len = 0;
|
int len = 0;
|
||||||
bool valid_password = false;
|
bool valid_password = false;
|
||||||
char passconfirm[MAX_PASSWORD_LEN + 1] = {0};
|
char passconfirm[MAX_PASSWORD_LEN + 1] = {0};
|
||||||
|
|
||||||
printf("Enter a new password (must be at least %d characters) ", MIN_PASSWORD_LEN);
|
printf("Enter a new password (must be at least %d characters) ", MIN_PASSWORD_LEN);
|
||||||
|
|
||||||
while (valid_password == false) {
|
while (valid_password == false) {
|
||||||
@ -569,7 +460,7 @@ static void first_time_encrypt(const char *msg)
|
|||||||
valid_password = true;
|
valid_password = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
queue_init_message("Data file '%s' has been encrypted", DATA_FILE);
|
queue_init_message("Data file '%s' will be encrypted", DATA_FILE);
|
||||||
memset(passconfirm, 0, sizeof(passconfirm));
|
memset(passconfirm, 0, sizeof(passconfirm));
|
||||||
user_password.data_is_encrypted = true;
|
user_password.data_is_encrypted = true;
|
||||||
}
|
}
|
||||||
@ -579,94 +470,144 @@ static void first_time_encrypt(const char *msg)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Store Messenger to given location
|
* Store Messenger to given location
|
||||||
* Return 0 stored successfully or ignoring data file
|
* Return 0 if stored successfully or ignoring data file. Return -1 on error
|
||||||
* Return -1 file path is NULL
|
|
||||||
* Return -2 malloc failed
|
|
||||||
* Return -3 opening path failed
|
|
||||||
* Return -4 fwrite failed
|
|
||||||
*/
|
*/
|
||||||
int store_data(Tox *m, const char *path)
|
int store_data(Tox *m, const char *path)
|
||||||
{
|
{
|
||||||
if (arg_opts.ignore_data_file)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (path == NULL)
|
if (path == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
int len = user_password.data_is_encrypted ? tox_encrypted_size(m) : tox_size(m);
|
size_t len = user_password.data_is_encrypted ? tox_encrypted_size(m) : tox_get_savedata_size(m);
|
||||||
char *buf = malloc(len);
|
char *buf = malloc(len);
|
||||||
|
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return -2;
|
exit_toxic_err("failed in store_data", FATALERR_MEMORY);
|
||||||
|
|
||||||
if (user_password.data_is_encrypted && !arg_opts.unencrypt_data)
|
if (user_password.data_is_encrypted && !arg_opts.unencrypt_data) {
|
||||||
tox_encrypted_save(m, (uint8_t *) buf, (uint8_t *) user_password.pass, user_password.len);
|
if (tox_encrypted_save(m, (uint8_t *) buf, (uint8_t *) user_password.pass, user_password.len) != 0) {
|
||||||
else
|
free(buf);
|
||||||
tox_save(m, (uint8_t *) buf);
|
return -1;
|
||||||
|
}
|
||||||
FILE *fd = fopen(path, "wb");
|
} else {
|
||||||
|
tox_get_savedata(m, (uint8_t *) buf);
|
||||||
if (fd == NULL) {
|
|
||||||
free(buf);
|
|
||||||
return -3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fwrite(buf, len, 1, fd) != 1) {
|
FILE *fp = fopen(path, "wb");
|
||||||
|
|
||||||
|
if (fp == NULL) {
|
||||||
free(buf);
|
free(buf);
|
||||||
fclose(fd);
|
return -1;
|
||||||
return -4;
|
}
|
||||||
|
|
||||||
|
if (fwrite(buf, len, 1, fp) != 1) {
|
||||||
|
free(buf);
|
||||||
|
fclose(fp);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
fclose(fd);
|
fclose(fp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void load_data(Tox *m, char *path)
|
static void init_tox_callbacks(Tox *m)
|
||||||
{
|
{
|
||||||
if (arg_opts.ignore_data_file)
|
tox_callback_self_connection_status(m, prompt_onSelfConnectionChange, NULL);
|
||||||
return;
|
tox_callback_friend_connection_status(m, on_connectionchange, NULL);
|
||||||
|
tox_callback_friend_typing(m, on_typing_change, NULL);
|
||||||
|
tox_callback_friend_request(m, on_request, NULL);
|
||||||
|
tox_callback_friend_message(m, on_message, NULL);
|
||||||
|
tox_callback_friend_name(m, on_nickchange, NULL);
|
||||||
|
tox_callback_friend_status(m, on_statuschange, NULL);
|
||||||
|
tox_callback_friend_status_message(m, on_statusmessagechange, NULL);
|
||||||
|
tox_callback_friend_read_receipt(m, on_read_receipt, NULL);
|
||||||
|
tox_callback_group_invite(m, on_groupinvite, NULL);
|
||||||
|
tox_callback_group_message(m, on_groupmessage, NULL);
|
||||||
|
tox_callback_group_action(m, on_groupaction, NULL);
|
||||||
|
tox_callback_group_namelist_change(m, on_group_namelistchange, NULL);
|
||||||
|
tox_callback_group_title(m, on_group_titlechange, NULL);
|
||||||
|
tox_callback_file_recv(m, on_file_recv, NULL);
|
||||||
|
tox_callback_file_chunk_request(m, on_file_chunk_request, NULL);
|
||||||
|
tox_callback_file_recv_control(m, on_file_control, NULL);
|
||||||
|
tox_callback_file_recv_chunk(m, on_file_recv_chunk, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
FILE *fd;
|
static void init_tox_options(struct Tox_Options *tox_opts)
|
||||||
|
{
|
||||||
|
tox_opts->ipv6_enabled = !arg_opts.use_ipv4;
|
||||||
|
tox_opts->udp_enabled = !arg_opts.force_tcp;
|
||||||
|
tox_opts->proxy_type = arg_opts.proxy_type;
|
||||||
|
|
||||||
if ((fd = fopen(path, "rb")) != NULL) {
|
if (!tox_opts->ipv6_enabled)
|
||||||
off_t len = file_size(path);
|
queue_init_message("Forcing IPv4 connection");
|
||||||
|
|
||||||
if (len == -1) {
|
if (tox_opts->proxy_type != TOX_PROXY_TYPE_NONE) {
|
||||||
fclose(fd);
|
tox_opts->proxy_port = arg_opts.proxy_port;
|
||||||
exit_toxic_err("failed in load_data", FATALERR_FILEOP);
|
tox_opts->proxy_host = arg_opts.proxy_address;
|
||||||
|
const char *ps = tox_opts->proxy_type == TOX_PROXY_TYPE_SOCKS5 ? "SOCKS5" : "HTTP";
|
||||||
|
|
||||||
|
char tmp[48];
|
||||||
|
snprintf(tmp, sizeof(tmp), "Using %s proxy %s : %d", ps, arg_opts.proxy_address, arg_opts.proxy_port);
|
||||||
|
queue_init_message("%s", tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tox_opts->udp_enabled) {
|
||||||
|
queue_init_message("UDP disabled");
|
||||||
|
} else if (tox_opts->proxy_type != TOX_PROXY_TYPE_NONE) {
|
||||||
|
const char *msg = "WARNING: Using a proxy without disabling UDP may leak your real IP address.";
|
||||||
|
queue_init_message("%s", msg);
|
||||||
|
msg = "Use the -t option to disable UDP.";
|
||||||
|
queue_init_message("%s", msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns a new Tox object on success.
|
||||||
|
* If object fails to initialize the toxic process will terminate.
|
||||||
|
*/
|
||||||
|
static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts)
|
||||||
|
{
|
||||||
|
Tox *m = NULL;
|
||||||
|
|
||||||
|
FILE *fp = fopen(data_path, "rb");
|
||||||
|
|
||||||
|
if (fp != NULL) {
|
||||||
|
off_t len = file_size(data_path);
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
fclose(fp);
|
||||||
|
exit_toxic_err("failed in load_toxic", FATALERR_FILEOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *buf = malloc(len);
|
char *buf = malloc(len);
|
||||||
|
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
fclose(fd);
|
fclose(fp);
|
||||||
exit_toxic_err("failed in load_data", FATALERR_MEMORY);
|
exit_toxic_err("failed in load_toxic", FATALERR_MEMORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fread(buf, len, 1, fd) != 1) {
|
if (fread(buf, len, 1, fp) != 1) {
|
||||||
free(buf);
|
free(buf);
|
||||||
fclose(fd);
|
fclose(fp);
|
||||||
exit_toxic_err("failed in load_data", FATALERR_FILEOP);
|
exit_toxic_err("failed in load_toxic", FATALERR_FILEOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_encrypted = tox_is_data_encrypted((uint8_t *) buf);
|
bool is_encrypted = tox_is_data_encrypted((uint8_t *) buf);
|
||||||
|
|
||||||
/* attempt to encrypt an already encrypted data file */
|
/* attempt to encrypt an already encrypted data file */
|
||||||
if (arg_opts.encrypt_data && is_encrypted)
|
if (arg_opts.encrypt_data && is_encrypted)
|
||||||
exit_toxic_err("failed in load_data", FATALERR_ENCRYPT);
|
exit_toxic_err("failed in load_toxic", FATALERR_ENCRYPT);
|
||||||
|
|
||||||
if (arg_opts.unencrypt_data && is_encrypted)
|
if (arg_opts.unencrypt_data && is_encrypted)
|
||||||
queue_init_message("Data file '%s' has been unencrypted", path);
|
queue_init_message("Data file '%s' has been unencrypted", data_path);
|
||||||
else if (arg_opts.unencrypt_data)
|
else if (arg_opts.unencrypt_data)
|
||||||
queue_init_message("Warning: passed --unencrypt-data option with unencrypted data file '%s'", path);
|
queue_init_message("Warning: passed --unencrypt-data option with unencrypted data file '%s'", data_path);
|
||||||
|
|
||||||
if (is_encrypted) {
|
if (is_encrypted) {
|
||||||
if (!arg_opts.unencrypt_data)
|
if (!arg_opts.unencrypt_data)
|
||||||
user_password.data_is_encrypted = true;
|
user_password.data_is_encrypted = true;
|
||||||
|
|
||||||
int pwlen = 0;
|
size_t pwlen = 0;
|
||||||
system("clear");
|
system("clear"); // TODO: is this portable?
|
||||||
printf("Enter password (q to quit) ");
|
printf("Enter password (q to quit) ");
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -683,37 +624,73 @@ static void load_data(Tox *m, char *path)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tox_encrypted_load(m, (uint8_t *) buf, len, (uint8_t *) user_password.pass, pwlen) == 0) {
|
TOX_ERR_ENCRYPTED_NEW enc_err;
|
||||||
|
m = tox_encrypted_new(tox_opts, (uint8_t *) buf, len, (uint8_t *) user_password.pass, pwlen, &enc_err);
|
||||||
|
|
||||||
|
if (enc_err == TOX_ERR_ENCRYPTED_NEW_OK) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else if (enc_err == TOX_ERR_ENCRYPTED_NEW_LOAD_DECRYPTION_FAILED) {
|
||||||
system("clear");
|
system("clear");
|
||||||
sleep(1);
|
sleep(1);
|
||||||
printf("Invalid password. Try again. ");
|
printf("Invalid password. Try again. ");
|
||||||
|
} else {
|
||||||
|
exit_toxic_err("tox_encrypted_new() failed", enc_err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tox_load(m, (uint8_t *) buf, len);
|
TOX_ERR_NEW err;
|
||||||
|
m = tox_new(tox_opts, (uint8_t *) buf, len, &err);
|
||||||
|
|
||||||
|
if (err != TOX_ERR_NEW_OK)
|
||||||
|
exit_toxic_err("tox_new() failed", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
load_friendlist(m);
|
|
||||||
load_blocklist(BLOCK_FILE);
|
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
fclose(fd);
|
fclose(fp);
|
||||||
} else {
|
} else {
|
||||||
if (store_data(m, path) != 0)
|
/* if file exists then open() failing is fatal */
|
||||||
exit_toxic_err("failed in load_data", FATALERR_STORE_DATA);
|
if (file_exists(data_path))
|
||||||
|
exit_toxic_err("failed in load_toxic", FATALERR_FILEOP);
|
||||||
|
|
||||||
|
TOX_ERR_NEW err;
|
||||||
|
m = tox_new(tox_opts, NULL, 0, &err);
|
||||||
|
|
||||||
|
if (err != TOX_ERR_NEW_OK)
|
||||||
|
exit_toxic_err("tox_new() failed", err);
|
||||||
|
|
||||||
|
if (store_data(m, data_path) == -1)
|
||||||
|
exit_toxic_err("failed in load_toxic", FATALERR_FILEOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Tox *load_toxic(char *data_path)
|
||||||
|
{
|
||||||
|
struct Tox_Options tox_opts;
|
||||||
|
init_tox_options(&tox_opts);
|
||||||
|
|
||||||
|
Tox *m = load_tox(data_path, &tox_opts);
|
||||||
|
|
||||||
|
if (m == NULL)
|
||||||
|
exit_toxic_err("load_tox() failed", FATALERR_TOX_INIT);
|
||||||
|
|
||||||
|
init_tox_callbacks(m);
|
||||||
|
load_friendlist(m);
|
||||||
|
load_blocklist(BLOCK_FILE);
|
||||||
|
|
||||||
|
if (tox_self_get_name_size(m) == 0)
|
||||||
|
tox_self_set_name(m, (uint8_t *) "Toxic User", strlen("Toxic User"), NULL);
|
||||||
|
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_toxic(Tox *m, ToxWindow *prompt)
|
static void do_toxic(Tox *m, ToxWindow *prompt)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
do_connection(m, prompt);
|
|
||||||
do_file_senders(m);
|
|
||||||
|
|
||||||
if (arg_opts.no_connect == 0)
|
if (arg_opts.no_connect == 0)
|
||||||
tox_do(m); /* main tox-core loop */
|
tox_iterate(m); /* main toxcore loop */
|
||||||
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
}
|
}
|
||||||
@ -751,20 +728,38 @@ void *thread_cqueue(void *data)
|
|||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
int i;
|
|
||||||
|
size_t i;
|
||||||
|
|
||||||
for (i = 2; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 2; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
ToxWindow *toxwin = get_window_ptr(i);
|
ToxWindow *toxwin = get_window_ptr(i);
|
||||||
|
|
||||||
if (toxwin != NULL && toxwin->is_chat && tox_get_friend_connection_status(m, toxwin->num) == 1)
|
if (toxwin != NULL && toxwin->is_chat
|
||||||
|
&& tox_friend_get_connection_status(m, toxwin->num, NULL) != TOX_CONNECTION_NONE)
|
||||||
cqueue_try_send(toxwin, m);
|
cqueue_try_send(toxwin, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
usleep(7000);
|
|
||||||
|
usleep(4000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
|
void *thread_audio(void *data)
|
||||||
|
{
|
||||||
|
ToxAv *av = (ToxAv *) data;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
|
toxav_do(av);
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
|
usleep(toxav_do_interval(av) * 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* AUDIO */
|
||||||
|
|
||||||
static void print_usage(void)
|
static void print_usage(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "usage: toxic [OPTION] [FILE ...]\n");
|
fprintf(stderr, "usage: toxic [OPTION] [FILE ...]\n");
|
||||||
@ -777,11 +772,11 @@ static void print_usage(void)
|
|||||||
fprintf(stderr, " -h, --help Show this message and exit\n");
|
fprintf(stderr, " -h, --help Show this message and exit\n");
|
||||||
fprintf(stderr, " -n, --nodes Use specified DHTnodes file\n");
|
fprintf(stderr, " -n, --nodes Use specified DHTnodes file\n");
|
||||||
fprintf(stderr, " -o, --noconnect Do not connect to the DHT network\n");
|
fprintf(stderr, " -o, --noconnect Do not connect to the DHT network\n");
|
||||||
fprintf(stderr, " -p, --proxy Use proxy: Requires [IP] [port]\n");
|
fprintf(stderr, " -p, --SOCKS5-proxy Use SOCKS5 proxy: Requires [IP] [port]\n");
|
||||||
|
fprintf(stderr, " -P, --HTTP-proxy Use HTTP proxy: Requires [IP] [port]\n");
|
||||||
fprintf(stderr, " -r, --dnslist Use specified DNSservers file\n");
|
fprintf(stderr, " -r, --dnslist Use specified DNSservers file\n");
|
||||||
fprintf(stderr, " -t, --force-tcp Force TCP connection (use this with proxies)\n");
|
fprintf(stderr, " -t, --force-tcp Force TCP connection (use this with proxies)\n");
|
||||||
fprintf(stderr, " -u, --unencrypt-data Unencrypt an encrypted data file\n");
|
fprintf(stderr, " -u, --unencrypt-data Unencrypt an encrypted data file\n");
|
||||||
fprintf(stderr, " -x, --nodata Ignore data file\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_default_opts(void)
|
static void set_default_opts(void)
|
||||||
@ -789,6 +784,7 @@ static void set_default_opts(void)
|
|||||||
memset(&arg_opts, 0, sizeof(struct arg_opts));
|
memset(&arg_opts, 0, sizeof(struct arg_opts));
|
||||||
|
|
||||||
/* set any non-zero defaults here*/
|
/* set any non-zero defaults here*/
|
||||||
|
arg_opts.proxy_type = TOX_PROXY_TYPE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_args(int argc, char *argv[])
|
static void parse_args(int argc, char *argv[])
|
||||||
@ -797,7 +793,6 @@ static void parse_args(int argc, char *argv[])
|
|||||||
|
|
||||||
static struct option long_opts[] = {
|
static struct option long_opts[] = {
|
||||||
{"file", required_argument, 0, 'f'},
|
{"file", required_argument, 0, 'f'},
|
||||||
{"nodata", no_argument, 0, 'x'},
|
|
||||||
{"ipv4", no_argument, 0, '4'},
|
{"ipv4", no_argument, 0, '4'},
|
||||||
{"debug", no_argument, 0, 'b'},
|
{"debug", no_argument, 0, 'b'},
|
||||||
{"default-locale", no_argument, 0, 'd'},
|
{"default-locale", no_argument, 0, 'd'},
|
||||||
@ -808,12 +803,13 @@ static void parse_args(int argc, char *argv[])
|
|||||||
{"noconnect", no_argument, 0, 'o'},
|
{"noconnect", no_argument, 0, 'o'},
|
||||||
{"dnslist", required_argument, 0, 'r'},
|
{"dnslist", required_argument, 0, 'r'},
|
||||||
{"force-tcp", no_argument, 0, 't'},
|
{"force-tcp", no_argument, 0, 't'},
|
||||||
{"proxy", required_argument, 0, 'p'},
|
{"SOCKS5-proxy", required_argument, 0, 'p'},
|
||||||
|
{"HTTP-proxy", required_argument, 0, 'P'},
|
||||||
{"unencrypt-data", no_argument, 0, 'u'},
|
{"unencrypt-data", no_argument, 0, 'u'},
|
||||||
{NULL, no_argument, NULL, 0},
|
{NULL, no_argument, NULL, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *opts_str = "4bdehotuxc:f:n:r:p:";
|
const char *opts_str = "4bdehotuxc:f:n:r:p:P:";
|
||||||
int opt, indexptr;
|
int opt, indexptr;
|
||||||
|
|
||||||
while ((opt = getopt_long(argc, argv, opts_str, long_opts, &indexptr)) != -1) {
|
while ((opt = getopt_long(argc, argv, opts_str, long_opts, &indexptr)) != -1) {
|
||||||
@ -873,7 +869,17 @@ static void parse_args(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
arg_opts.use_proxy = 1;
|
arg_opts.proxy_type = TOX_PROXY_TYPE_SOCKS5;
|
||||||
|
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
|
||||||
|
|
||||||
|
if (++optind > argc || argv[optind-1][0] == '-')
|
||||||
|
exit_toxic_err("Proxy error", FATALERR_PROXY);
|
||||||
|
|
||||||
|
arg_opts.proxy_port = (uint16_t) atoi(argv[optind-1]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'P':
|
||||||
|
arg_opts.proxy_type = TOX_PROXY_TYPE_HTTP;
|
||||||
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
|
snprintf(arg_opts.proxy_address, sizeof(arg_opts.proxy_address), "%s", optarg);
|
||||||
|
|
||||||
if (++optind > argc || argv[optind-1][0] == '-')
|
if (++optind > argc || argv[optind-1][0] == '-')
|
||||||
@ -898,11 +904,6 @@ static void parse_args(int argc, char *argv[])
|
|||||||
arg_opts.unencrypt_data = 1;
|
arg_opts.unencrypt_data = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'x':
|
|
||||||
arg_opts.ignore_data_file = 1;
|
|
||||||
queue_init_message("Ignoring data file");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
default:
|
default:
|
||||||
print_usage();
|
print_usage();
|
||||||
@ -966,32 +967,42 @@ static useconds_t optimal_msleepval(uint64_t *looptimer, uint64_t *loopcount, ui
|
|||||||
return new_sleep;
|
return new_sleep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef X11
|
||||||
|
// FIXME
|
||||||
|
void DnD_callback(const char* asdv, DropType dt)
|
||||||
|
{
|
||||||
|
if (dt != DT_plain)
|
||||||
|
return;
|
||||||
|
|
||||||
|
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, asdv);
|
||||||
|
}
|
||||||
|
#endif /* X11 */
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
parse_args(argc, argv);
|
parse_args(argc, argv);
|
||||||
|
|
||||||
|
/* Use the -b flag to enable stderr */
|
||||||
|
if (!arg_opts.debug)
|
||||||
|
freopen("/dev/null", "w", stderr);
|
||||||
|
|
||||||
if (arg_opts.encrypt_data && arg_opts.unencrypt_data) {
|
if (arg_opts.encrypt_data && arg_opts.unencrypt_data) {
|
||||||
arg_opts.encrypt_data = 0;
|
arg_opts.encrypt_data = 0;
|
||||||
arg_opts.unencrypt_data = 0;
|
arg_opts.unencrypt_data = 0;
|
||||||
queue_init_message("Warning: Using --unencrypt-data and --encrypt-data simultaneously has no effect");
|
queue_init_message("Warning: Using --unencrypt-data and --encrypt-data simultaneously has no effect");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Use the -b flag to enable stderr */
|
|
||||||
if (!arg_opts.debug)
|
|
||||||
freopen("/dev/null", "w", stderr);
|
|
||||||
|
|
||||||
/* Make sure all written files are read/writeable only by the current user. */
|
/* Make sure all written files are read/writeable only by the current user. */
|
||||||
umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||||
|
|
||||||
int config_err = init_default_data_files();
|
int config_err = init_default_data_files();
|
||||||
bool datafile_exists = file_exists(DATA_FILE);
|
bool datafile_exists = file_exists(DATA_FILE);
|
||||||
|
|
||||||
if (!arg_opts.ignore_data_file) {
|
if (!datafile_exists && !arg_opts.unencrypt_data)
|
||||||
if (!datafile_exists && !arg_opts.unencrypt_data)
|
first_time_encrypt("Creating new data file. Would you like to encrypt it? Y/n (q to quit)");
|
||||||
first_time_encrypt("Creating new data file. Would you like to encrypt it? Y/n (q to quit)");
|
else if (arg_opts.encrypt_data)
|
||||||
else if (arg_opts.encrypt_data)
|
first_time_encrypt("Encrypt existing data file? Y/n (q to quit)");
|
||||||
first_time_encrypt("Encrypt existing data file? Y/n (q to quit)");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* init user_settings struct and load settings from conf file */
|
/* init user_settings struct and load settings from conf file */
|
||||||
user_settings = calloc(1, sizeof(struct user_settings));
|
user_settings = calloc(1, sizeof(struct user_settings));
|
||||||
@ -1002,20 +1013,19 @@ int main(int argc, char *argv[])
|
|||||||
const char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL;
|
const char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL;
|
||||||
int settings_err = settings_load(user_settings, p);
|
int settings_err = settings_load(user_settings, p);
|
||||||
|
|
||||||
Tox *m = init_tox();
|
#ifdef X11
|
||||||
|
if (init_xtra(DnD_callback) == -1)
|
||||||
|
queue_init_message("X failed to initialize");
|
||||||
|
#endif
|
||||||
|
|
||||||
if (m == NULL)
|
Tox *m = load_toxic(DATA_FILE);
|
||||||
exit_toxic_err("failed in main", FATALERR_NETWORKINIT);
|
|
||||||
|
|
||||||
if (!arg_opts.ignore_data_file) {
|
if (arg_opts.encrypt_data && !datafile_exists)
|
||||||
if (arg_opts.encrypt_data && !datafile_exists)
|
arg_opts.encrypt_data = 0;
|
||||||
arg_opts.encrypt_data = 0;
|
|
||||||
|
|
||||||
load_data(m, DATA_FILE);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
init_term();
|
init_term();
|
||||||
|
|
||||||
prompt = init_windows(m);
|
prompt = init_windows(m);
|
||||||
prompt_init_statusbar(prompt, m);
|
prompt_init_statusbar(prompt, m);
|
||||||
|
|
||||||
@ -1034,6 +1044,10 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
av = init_audio(prompt, m);
|
av = init_audio(prompt, m);
|
||||||
|
|
||||||
|
/* audio thread */
|
||||||
|
if (pthread_create(&audio_thread.tid, NULL, thread_audio, (void *) av) != 0)
|
||||||
|
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
|
||||||
|
|
||||||
set_primary_device(input, user_settings->audio_in_dev);
|
set_primary_device(input, user_settings->audio_in_dev);
|
||||||
set_primary_device(output, user_settings->audio_out_dev);
|
set_primary_device(output, user_settings->audio_out_dev);
|
||||||
|
|
||||||
@ -1042,15 +1056,11 @@ int main(int argc, char *argv[])
|
|||||||
queue_init_message("Failed to init audio devices");
|
queue_init_message("Failed to init audio devices");
|
||||||
|
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
init_notify(60, 3000);
|
init_notify(60, 3000);
|
||||||
|
|
||||||
#ifdef SOUND_NOTIFY
|
|
||||||
// sound_notify(prompt, self_log_in, 0, NULL);
|
|
||||||
#endif /* SOUND_NOTIFY */
|
|
||||||
|
|
||||||
const char *msg;
|
const char *msg;
|
||||||
|
|
||||||
if (config_err) {
|
if (config_err) {
|
||||||
msg = "Unable to determine configuration directory. Defaulting to 'data' for data file...";
|
msg = "Unable to determine configuration directory. Defaulting to 'data' for data file...";
|
||||||
queue_init_message("%s", msg);
|
queue_init_message("%s", msg);
|
||||||
@ -1059,6 +1069,10 @@ int main(int argc, char *argv[])
|
|||||||
if (settings_err == -1)
|
if (settings_err == -1)
|
||||||
queue_init_message("Failed to load user settings");
|
queue_init_message("Failed to load user settings");
|
||||||
|
|
||||||
|
/* screen/tmux auto-away timer */
|
||||||
|
if (init_mplex_away_timer(m) == -1)
|
||||||
|
queue_init_message("Failed to init mplex auto-away.");
|
||||||
|
|
||||||
print_init_messages(prompt);
|
print_init_messages(prompt);
|
||||||
cleanup_init_messages();
|
cleanup_init_messages();
|
||||||
|
|
||||||
@ -1079,7 +1093,8 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
if (timed_out(last_save, cur_time, AUTOSAVE_FREQ)) {
|
if (timed_out(last_save, cur_time, AUTOSAVE_FREQ)) {
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
store_data(m, DATA_FILE);
|
if (store_data(m, DATA_FILE) != 0)
|
||||||
|
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, "WARNING: Failed to save to data file");
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
last_save = cur_time;
|
last_save = cur_time;
|
||||||
|
65
src/toxic.h
65
src/toxic.h
@ -24,7 +24,7 @@
|
|||||||
#define TOXIC_H
|
#define TOXIC_H
|
||||||
|
|
||||||
#ifndef TOXICVER
|
#ifndef TOXICVER
|
||||||
#define TOXICVER "NOVER_" /* Use the -D flag to set this */
|
#define TOXICVER "NOVERS" /* Use the -D flag to set this */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef SIGWINCH
|
#ifndef SIGWINCH
|
||||||
@ -41,12 +41,13 @@
|
|||||||
#include <tox/tox.h>
|
#include <tox/tox.h>
|
||||||
|
|
||||||
#define UNKNOWN_NAME "Anonymous"
|
#define UNKNOWN_NAME "Anonymous"
|
||||||
|
#define DEFAULT_TOX_NAME "Tox User" /* should always be the same as toxcore's default name */
|
||||||
|
|
||||||
#define MAX_STR_SIZE TOX_MAX_MESSAGE_LENGTH
|
#define MAX_STR_SIZE TOX_MAX_MESSAGE_LENGTH /* must be >= TOX_MAX_MESSAGE_LENGTH */
|
||||||
#define MAX_CMDNAME_SIZE 64
|
#define MAX_CMDNAME_SIZE 64
|
||||||
#define TOXIC_MAX_NAME_LENGTH 32 /* Must be <= TOX_MAX_NAME_LENGTH */
|
#define TOXIC_MAX_NAME_LENGTH 32 /* Must be <= TOX_MAX_NAME_LENGTH */
|
||||||
#define KEY_IDENT_DIGITS 3 /* number of hex digits to display for the pub-key based identifier */
|
#define KEY_IDENT_DIGITS 3 /* number of hex digits to display for the pub-key based identifier */
|
||||||
#define TIME_STR_SIZE 16
|
#define TIME_STR_SIZE 32
|
||||||
|
|
||||||
/* ASCII key codes */
|
/* ASCII key codes */
|
||||||
#define T_KEY_ESC 0x1B /* ESC key */
|
#define T_KEY_ESC 0x1B /* ESC key */
|
||||||
@ -62,6 +63,9 @@
|
|||||||
#define T_KEY_C_F 0x06 /* ctrl-f */
|
#define T_KEY_C_F 0x06 /* ctrl-f */
|
||||||
#define T_KEY_C_H 0x08 /* ctrl-h */
|
#define T_KEY_C_H 0x08 /* ctrl-h */
|
||||||
#define T_KEY_C_Y 0x19 /* ctrl-y */
|
#define T_KEY_C_Y 0x19 /* ctrl-y */
|
||||||
|
#define T_KEY_C_L 0x0C /* ctrl-l */
|
||||||
|
#define T_KEY_C_W 0x17 /* ctrl-w */
|
||||||
|
#define T_KEY_C_B 0x02 /* ctrl-b */
|
||||||
#define T_KEY_TAB 0x09 /* TAB key */
|
#define T_KEY_TAB 0x09 /* TAB key */
|
||||||
|
|
||||||
#define ONLINE_CHAR "*"
|
#define ONLINE_CHAR "*"
|
||||||
@ -73,42 +77,53 @@ typedef enum _FATAL_ERRS {
|
|||||||
FATALERR_THREAD_CREATE = -3, /* thread creation failed for critical thread */
|
FATALERR_THREAD_CREATE = -3, /* thread creation failed for critical thread */
|
||||||
FATALERR_MUTEX_INIT = -4, /* mutex init for critical thread failed */
|
FATALERR_MUTEX_INIT = -4, /* mutex init for critical thread failed */
|
||||||
FATALERR_THREAD_ATTR = -5, /* thread attr object init failed */
|
FATALERR_THREAD_ATTR = -5, /* thread attr object init failed */
|
||||||
FATALERR_LOCALE_SET = -6, /* system locale not set */
|
FATALERR_LOCALE_NOT_SET = -6, /* system locale not set */
|
||||||
FATALERR_STORE_DATA = -7, /* store_data failed in critical section */
|
FATALERR_STORE_DATA = -7, /* store_data failed in critical section */
|
||||||
FATALERR_NETWORKINIT = -8, /* Tox network failed to init */
|
FATALERR_INFLOOP = -8, /* infinite loop detected */
|
||||||
FATALERR_INFLOOP = -9, /* infinite loop detected */
|
FATALERR_WININIT = -9, /* window init failed */
|
||||||
FATALERR_WININIT = -10, /* window init failed */
|
FATALERR_PROXY = -10, /* Tox network failed to init using a proxy */
|
||||||
FATALERR_PROXY = -11, /* Tox network failed to init using a proxy */
|
FATALERR_ENCRYPT = -11, /* Data file encryption failure */
|
||||||
FATALERR_ENCRYPT = -12, /* Data file encryption failure */
|
FATALERR_TOX_INIT = -12, /* Tox instance failed to initialize */
|
||||||
} FATAL_ERRS;
|
} FATAL_ERRS;
|
||||||
|
|
||||||
/* Fixes text color problem on some terminals.
|
/* Fixes text color problem on some terminals.
|
||||||
Uncomment if necessary */
|
Uncomment if necessary */
|
||||||
/* #define URXVT_FIX */
|
/* #define URXVT_FIX */
|
||||||
|
|
||||||
|
void lock_status ();
|
||||||
|
void unlock_status ();
|
||||||
|
|
||||||
void exit_toxic_success(Tox *m);
|
void exit_toxic_success(Tox *m);
|
||||||
void exit_toxic_err(const char *errmsg, int errcode);
|
void exit_toxic_err(const char *errmsg, int errcode);
|
||||||
|
|
||||||
int store_data(Tox *m, const char *path);
|
int store_data(Tox *m, const char *path);
|
||||||
|
|
||||||
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata);
|
/* callbacks */
|
||||||
void on_connectionchange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata);
|
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata);
|
||||||
void on_message(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata);
|
void on_connectionchange(Tox *m, uint32_t friendnumber, TOX_CONNECTION status, void *userdata);
|
||||||
void on_action(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata);
|
void on_message(Tox *m, uint32_t friendnumber, TOX_MESSAGE_TYPE type, const uint8_t *string, size_t length, void *userdata);
|
||||||
void on_nickchange(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata);
|
void on_action(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
|
||||||
void on_statuschange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata);
|
void on_nickchange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
|
||||||
void on_statusmessagechange(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata);
|
void on_statuschange(Tox *m, uint32_t friendnumber, TOX_USER_STATUS status, void *userdata);
|
||||||
void on_friendadded(Tox *m, int32_t friendnumber, bool sort);
|
void on_statusmessagechange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata);
|
||||||
|
void on_friendadded(Tox *m, uint32_t friendnumber, bool sort);
|
||||||
void on_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *message, uint16_t length, 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_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, uint16_t length, void *userdata);
|
void on_groupinvite(Tox *m, int32_t friendnumber, uint8_t type, const uint8_t *group_pub_key, uint16_t length, void *userdata);
|
||||||
void on_group_namelistchange(Tox *m, int groupnumber, int peernumber, uint8_t change, 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, const uint8_t *pathname,
|
void on_group_titlechange(Tox *m, int groupnumber, int peernumber, const uint8_t *title, uint8_t length, void *userdata);
|
||||||
uint16_t pathname_length, void *userdata);
|
void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length, void *userdata);
|
||||||
void on_file_control(Tox *m, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber, uint8_t control_type,
|
void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data,
|
||||||
const uint8_t *data, uint16_t length, void *userdata);
|
size_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_file_control (Tox *m, uint32_t friendnumber, uint32_t filenumber, TOX_FILE_CONTROL control, void *userdata);
|
||||||
void on_typing_change(Tox *m, int32_t friendnumber, uint8_t is_typing, void *userdata);
|
void on_file_recv(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint32_t kind, uint64_t file_size,
|
||||||
void on_read_receipt(Tox *m, int32_t, uint32_t, void *userdata);
|
const uint8_t *filename, size_t filename_length, void *userdata);
|
||||||
|
void on_typing_change(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata);
|
||||||
|
void on_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata);
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
|
void write_device_callback_group(Tox *m, int groupnum, int peernum, const int16_t *pcm, unsigned int samples,
|
||||||
|
uint8_t channels, unsigned int sample_rate, void *arg);
|
||||||
|
#endif /* AUDIO */
|
||||||
|
|
||||||
#endif /* #define TOXIC_H */
|
#endif /* #define TOXIC_H */
|
||||||
|
@ -121,6 +121,39 @@ int yank_buf(ChatContext *ctx)
|
|||||||
ctx->pos += ctx->yank_len;
|
ctx->pos += ctx->yank_len;
|
||||||
ctx->len += ctx->yank_len;
|
ctx->len += ctx->yank_len;
|
||||||
ctx->line[ctx->len] = L'\0';
|
ctx->line[ctx->len] = L'\0';
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deletes all characters from line starting at pos and going backwards
|
||||||
|
until we find a space or run out of characters.
|
||||||
|
Return 0 on success, -1 if nothing to delete */
|
||||||
|
int del_word_buf(ChatContext *ctx)
|
||||||
|
{
|
||||||
|
if (ctx->len == 0 || ctx->pos == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int i = ctx->pos, count = 0;
|
||||||
|
|
||||||
|
/* traverse past empty space */
|
||||||
|
while (i > 0 && ctx->line[i-1] == L' ') {
|
||||||
|
++count;
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* traverse past last entered word */
|
||||||
|
while (i > 0 && ctx->line[i-1] != L' ') {
|
||||||
|
++count;
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
|
||||||
|
wmemmove(&ctx->line[i], &ctx->line[ctx->pos], ctx->len - ctx->pos);
|
||||||
|
|
||||||
|
ctx->start = MAX(0, ctx->start - count); /* TODO: take into account widechar */
|
||||||
|
ctx->len -= count;
|
||||||
|
ctx->pos -= count;
|
||||||
|
ctx->line[ctx->len] = L'\0';
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,7 +225,7 @@ void fetch_hist_item(ChatContext *ctx, int key_dir)
|
|||||||
if (key_dir == KEY_UP) {
|
if (key_dir == KEY_UP) {
|
||||||
if (--ctx->hst_pos < 0) {
|
if (--ctx->hst_pos < 0) {
|
||||||
ctx->hst_pos = 0;
|
ctx->hst_pos = 0;
|
||||||
sound_notify(NULL, error, NT_ALWAYS, NULL);
|
sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (++ctx->hst_pos >= ctx->hst_tot) {
|
if (++ctx->hst_pos >= ctx->hst_tot) {
|
||||||
|
@ -49,6 +49,11 @@ void reset_buf(ChatContext *ctx);
|
|||||||
Return 0 on success, -1 if yank buffer is empty or too long */
|
Return 0 on success, -1 if yank buffer is empty or too long */
|
||||||
int yank_buf(ChatContext *ctx);
|
int yank_buf(ChatContext *ctx);
|
||||||
|
|
||||||
|
/* Deletes all characters from line starting at pos and going backwards
|
||||||
|
until we find a space or run out of characters.
|
||||||
|
Return 0 on success, -1 if no line or already at the beginning */
|
||||||
|
int del_word_buf(ChatContext *ctx);
|
||||||
|
|
||||||
/* Removes trailing spaces from line. */
|
/* Removes trailing spaces from line. */
|
||||||
void rm_trailing_spaces_buf(ChatContext *ctx);
|
void rm_trailing_spaces_buf(ChatContext *ctx);
|
||||||
|
|
||||||
|
199
src/windows.c
199
src/windows.c
@ -32,6 +32,7 @@
|
|||||||
#include "groupchat.h"
|
#include "groupchat.h"
|
||||||
#include "chat.h"
|
#include "chat.h"
|
||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
|
#include "misc_tools.h"
|
||||||
|
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
extern char *DATA_FILE;
|
extern char *DATA_FILE;
|
||||||
@ -45,32 +46,36 @@ extern struct user_settings *user_settings;
|
|||||||
static int num_active_windows;
|
static int num_active_windows;
|
||||||
|
|
||||||
/* CALLBACKS START */
|
/* CALLBACKS START */
|
||||||
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata)
|
void on_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
|
||||||
{
|
{
|
||||||
int i;
|
char msg[MAX_STR_SIZE + 1];
|
||||||
|
length = copy_tox_str(msg, sizeof(msg), (const char *) data, length);
|
||||||
|
|
||||||
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onFriendRequest != NULL)
|
if (windows[i].onFriendRequest != NULL) {
|
||||||
windows[i].onFriendRequest(&windows[i], m, (const char *) public_key, (const char *) data, length);
|
windows[i].onFriendRequest(&windows[i], m, (const char *) public_key, msg, length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_connectionchange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata)
|
void on_connectionchange(Tox *m, uint32_t friendnumber, TOX_CONNECTION connection_status, void *userdata)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onConnectionChange != NULL)
|
if (windows[i].onConnectionChange != NULL)
|
||||||
windows[i].onConnectionChange(&windows[i], m, friendnumber, status);
|
windows[i].onConnectionChange(&windows[i], m, friendnumber, connection_status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_typing_change(Tox *m, int32_t friendnumber, uint8_t is_typing, void *userdata)
|
void on_typing_change(Tox *m, uint32_t friendnumber, bool is_typing, void *userdata)
|
||||||
{
|
{
|
||||||
if (user_settings->show_typing_other == SHOW_TYPING_OFF)
|
if (user_settings->show_typing_other == SHOW_TYPING_OFF)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onTypingChange != NULL)
|
if (windows[i].onTypingChange != NULL)
|
||||||
@ -78,51 +83,53 @@ void on_typing_change(Tox *m, int32_t friendnumber, uint8_t is_typing, void *use
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_message(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata)
|
void on_message(Tox *m, uint32_t friendnumber, TOX_MESSAGE_TYPE type, const uint8_t *string, size_t length,
|
||||||
|
void *userdata)
|
||||||
{
|
{
|
||||||
int i;
|
char msg[MAX_STR_SIZE + 1];
|
||||||
|
length = copy_tox_str(msg, sizeof(msg), (const char *) string, length);
|
||||||
|
|
||||||
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onMessage != NULL)
|
if (windows[i].onMessage != NULL)
|
||||||
windows[i].onMessage(&windows[i], m, friendnumber, (const char *) string, length);
|
windows[i].onMessage(&windows[i], m, friendnumber, type, msg, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_action(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata)
|
void on_nickchange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata)
|
||||||
{
|
{
|
||||||
int i;
|
char nick[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
|
length = copy_tox_str(nick, sizeof(nick), (const char *) string, length);
|
||||||
|
filter_str(nick, length);
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
size_t i;
|
||||||
if (windows[i].onAction != NULL)
|
|
||||||
windows[i].onAction(&windows[i], m, friendnumber, (const char *) string, length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_nickchange(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onNickChange != NULL)
|
if (windows[i].onNickChange != NULL)
|
||||||
windows[i].onNickChange(&windows[i], m, friendnumber, (const char *) string, length);
|
windows[i].onNickChange(&windows[i], m, friendnumber, nick, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
store_data(m, DATA_FILE);
|
store_data(m, DATA_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_statusmessagechange(Tox *m, int32_t friendnumber, const uint8_t *string, uint16_t length, void *userdata)
|
void on_statusmessagechange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata)
|
||||||
{
|
{
|
||||||
int i;
|
char msg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
|
||||||
|
length = copy_tox_str(msg, sizeof(msg), (const char *) string, length);
|
||||||
|
filter_str(msg, length);
|
||||||
|
|
||||||
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onStatusMessageChange != NULL)
|
if (windows[i].onStatusMessageChange != NULL)
|
||||||
windows[i].onStatusMessageChange(&windows[i], friendnumber, (const char *) string, length);
|
windows[i].onStatusMessageChange(&windows[i], friendnumber, msg, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_statuschange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata)
|
void on_statuschange(Tox *m, uint32_t friendnumber, TOX_USER_STATUS status, void *userdata)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onStatusChange != NULL)
|
if (windows[i].onStatusChange != NULL)
|
||||||
@ -130,9 +137,9 @@ void on_statuschange(Tox *m, int32_t friendnumber, uint8_t status, void *userdat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_friendadded(Tox *m, int32_t friendnumber, bool sort)
|
void on_friendadded(Tox *m, uint32_t friendnumber, bool sort)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onFriendAdded != NULL)
|
if (windows[i].onFriendAdded != NULL)
|
||||||
@ -145,38 +152,45 @@ void on_friendadded(Tox *m, int32_t friendnumber, bool sort)
|
|||||||
void on_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *message, uint16_t length,
|
void on_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *message, uint16_t length,
|
||||||
void *userdata)
|
void *userdata)
|
||||||
{
|
{
|
||||||
int i;
|
char msg[MAX_STR_SIZE + 1];
|
||||||
|
length = copy_tox_str(msg, sizeof(msg), (const char *) message, length);
|
||||||
|
|
||||||
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onGroupMessage != NULL)
|
if (windows[i].onGroupMessage != NULL)
|
||||||
windows[i].onGroupMessage(&windows[i], m, groupnumber, peernumber, (const char *) message, length);
|
windows[i].onGroupMessage(&windows[i], m, groupnumber, peernumber, msg, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_groupaction(Tox *m, int groupnumber, int peernumber, const uint8_t *action, uint16_t length,
|
void on_groupaction(Tox *m, int groupnumber, int peernumber, const uint8_t *action, uint16_t length,
|
||||||
void *userdata)
|
void *userdata)
|
||||||
{
|
{
|
||||||
int i;
|
char msg[MAX_STR_SIZE + 1];
|
||||||
|
length = copy_tox_str(msg, sizeof(msg), (const char *) action, length);
|
||||||
|
|
||||||
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onGroupAction != NULL)
|
if (windows[i].onGroupAction != NULL)
|
||||||
windows[i].onGroupAction(&windows[i], m, groupnumber, peernumber, (const char *) action, length);
|
windows[i].onGroupAction(&windows[i], m, groupnumber, peernumber, msg, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_groupinvite(Tox *m, int32_t friendnumber, const uint8_t *group_pub_key, uint16_t length, void *userdata)
|
void on_groupinvite(Tox *m, int32_t friendnumber, uint8_t type, const uint8_t *group_pub_key, uint16_t length,
|
||||||
|
void *userdata)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onGroupInvite != NULL)
|
if (windows[i].onGroupInvite != NULL)
|
||||||
windows[i].onGroupInvite(&windows[i], m, friendnumber, (const char *) group_pub_key, length);
|
windows[i].onGroupInvite(&windows[i], m, friendnumber, type, (char *) group_pub_key, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_group_namelistchange(Tox *m, int groupnumber, int peernumber, uint8_t change, void *userdata)
|
void on_group_namelistchange(Tox *m, int groupnumber, int peernumber, uint8_t change, void *userdata)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onGroupNamelistChange != NULL)
|
if (windows[i].onGroupNamelistChange != NULL)
|
||||||
@ -184,50 +198,88 @@ 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,
|
void on_group_titlechange(Tox *m, int groupnumber, int peernumber, const uint8_t *title, uint8_t length,
|
||||||
const uint8_t *filename, uint16_t filename_length, void *userdata)
|
void *userdata)
|
||||||
{
|
{
|
||||||
int i;
|
char data[MAX_STR_SIZE + 1];
|
||||||
|
length = copy_tox_str(data, sizeof(data), (const char *) title, length);
|
||||||
|
|
||||||
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onFileSendRequest != NULL)
|
if (windows[i].onGroupTitleChange != NULL)
|
||||||
windows[i].onFileSendRequest(&windows[i], m, friendnumber, filenumber, filesize,
|
windows[i].onGroupTitleChange(&windows[i], m, groupnumber, peernumber, data, length);
|
||||||
(const char *) filename, filename_length);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_file_control (Tox *m, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber,
|
void on_file_chunk_request(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position,
|
||||||
uint8_t control_type, const uint8_t *data, uint16_t length, void *userdata)
|
size_t length, void *userdata)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i].onFileChunkRequest != NULL)
|
||||||
|
windows[i].onFileChunkRequest(&windows[i], m, friendnumber, filenumber, position, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_file_recv_chunk(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint64_t position,
|
||||||
|
const uint8_t *data, size_t length, void *user_data)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i].onFileRecvChunk != NULL)
|
||||||
|
windows[i].onFileRecvChunk(&windows[i], m, friendnumber, filenumber, position, (char *) data, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_file_control(Tox *m, uint32_t friendnumber, uint32_t filenumber, TOX_FILE_CONTROL control,
|
||||||
|
void *userdata)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onFileControl != NULL)
|
if (windows[i].onFileControl != NULL)
|
||||||
windows[i].onFileControl(&windows[i], m, friendnumber, receive_send, filenumber,
|
windows[i].onFileControl(&windows[i], m, friendnumber, filenumber, control);
|
||||||
control_type, (const char *) data, length);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_file_data(Tox *m, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length,
|
void on_file_recv(Tox *m, uint32_t friendnumber, uint32_t filenumber, uint32_t kind, uint64_t file_size,
|
||||||
void *userdata)
|
const uint8_t *filename, size_t filename_length, void *userdata)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onFileData != NULL)
|
if (windows[i].onFileRecv != NULL)
|
||||||
windows[i].onFileData(&windows[i], m, friendnumber, filenumber, (const char *) data, length);
|
windows[i].onFileRecv(&windows[i], m, friendnumber, filenumber, kind, file_size, (char *) filename,
|
||||||
|
filename_length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_read_receipt(Tox *m, int32_t friendnumber, uint32_t receipt, void *userdata)
|
void on_read_receipt(Tox *m, uint32_t friendnumber, uint32_t receipt, void *userdata)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].onReadReceipt != NULL)
|
if (windows[i].onReadReceipt != NULL)
|
||||||
windows[i].onReadReceipt(&windows[i], m, friendnumber, receipt);
|
windows[i].onReadReceipt(&windows[i], m, friendnumber, receipt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
|
void write_device_callback_group(Tox *m, int groupnum, int peernum, const int16_t *pcm, unsigned int samples,
|
||||||
|
uint8_t channels, unsigned int sample_rate, void *arg)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
|
if (windows[i].onWriteDevice != NULL)
|
||||||
|
windows[i].onWriteDevice(&windows[i], m, groupnum, peernum, pcm, samples, channels, samples);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* AUDIO */
|
||||||
|
|
||||||
/* CALLBACKS END */
|
/* CALLBACKS END */
|
||||||
|
|
||||||
int add_window(Tox *m, ToxWindow w)
|
int add_window(Tox *m, ToxWindow w)
|
||||||
@ -235,7 +287,7 @@ int add_window(Tox *m, ToxWindow w)
|
|||||||
if (LINES < 2)
|
if (LINES < 2)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; i++) {
|
for (i = 0; i < MAX_WINDOWS_NUM; i++) {
|
||||||
if (windows[i].active)
|
if (windows[i].active)
|
||||||
@ -329,7 +381,7 @@ void on_window_resize(void)
|
|||||||
getmaxyx(stdscr, y2, x2);
|
getmaxyx(stdscr, y2, x2);
|
||||||
y2 -= 2;
|
y2 -= 2;
|
||||||
|
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (!windows[i].active)
|
if (!windows[i].active)
|
||||||
@ -346,10 +398,12 @@ void on_window_resize(void)
|
|||||||
if (w->help->active)
|
if (w->help->active)
|
||||||
wclear(w->help->win);
|
wclear(w->help->win);
|
||||||
|
|
||||||
if (w->is_groupchat)
|
if (w->is_groupchat) {
|
||||||
delwin(w->chatwin->sidebar);
|
delwin(w->chatwin->sidebar);
|
||||||
else
|
w->chatwin->sidebar = NULL;
|
||||||
|
} else {
|
||||||
delwin(w->stb->topline);
|
delwin(w->stb->topline);
|
||||||
|
}
|
||||||
|
|
||||||
delwin(w->chatwin->linewin);
|
delwin(w->chatwin->linewin);
|
||||||
delwin(w->chatwin->history);
|
delwin(w->chatwin->history);
|
||||||
@ -358,12 +412,14 @@ void on_window_resize(void)
|
|||||||
w->window = newwin(y2, x2, 0, 0);
|
w->window = newwin(y2, x2, 0, 0);
|
||||||
w->chatwin->linewin = subwin(w->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
|
w->chatwin->linewin = subwin(w->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
|
||||||
|
|
||||||
if (w->is_groupchat) {
|
if (w->show_peerlist) {
|
||||||
w->chatwin->history = subwin(w->window, y2 - CHATBOX_HEIGHT + 1, x2 - SIDEBAR_WIDTH - 1, 0, 0);
|
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);
|
w->chatwin->sidebar = subwin(w->window, y2 - CHATBOX_HEIGHT + 1, SIDEBAR_WIDTH, 0, x2 - SIDEBAR_WIDTH);
|
||||||
} else {
|
} else {
|
||||||
w->chatwin->history = subwin(w->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
|
w->chatwin->history = subwin(w->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
|
||||||
w->stb->topline = subwin(w->window, 2, x2, 0, 0);
|
|
||||||
|
if (!w->is_groupchat)
|
||||||
|
w->stb->topline = subwin(w->window, 2, x2, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
@ -397,7 +453,7 @@ static void draw_bar(void)
|
|||||||
printw(" TOXIC " TOXICVER " |");
|
printw(" TOXIC " TOXICVER " |");
|
||||||
attroff(COLOR_PAIR(BLUE) | A_BOLD);
|
attroff(COLOR_PAIR(BLUE) | A_BOLD);
|
||||||
|
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (!windows[i].active)
|
if (!windows[i].active)
|
||||||
@ -471,11 +527,11 @@ void draw_active_window(Tox *m)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* refresh inactive windows to prevent scrolling bugs.
|
/* refresh inactive windows to prevent scrolling bugs.
|
||||||
call at least once per second */
|
call at least once per second */
|
||||||
void refresh_inactive_windows(void)
|
void refresh_inactive_windows(void)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
ToxWindow *a = &windows[i];
|
ToxWindow *a = &windows[i];
|
||||||
@ -496,6 +552,13 @@ ToxWindow *get_window_ptr(int i)
|
|||||||
return toxwin;
|
return toxwin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void force_refresh(WINDOW *w)
|
||||||
|
{
|
||||||
|
wclear(w);
|
||||||
|
endwin();
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
int get_num_active_windows(void)
|
int get_num_active_windows(void)
|
||||||
{
|
{
|
||||||
return num_active_windows;
|
return num_active_windows;
|
||||||
@ -504,13 +567,13 @@ int get_num_active_windows(void)
|
|||||||
/* destroys all chat and groupchat windows (should only be called on shutdown) */
|
/* destroys all chat and groupchat windows (should only be called on shutdown) */
|
||||||
void kill_all_windows(Tox *m)
|
void kill_all_windows(Tox *m)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||||
if (windows[i].is_chat)
|
if (windows[i].is_chat)
|
||||||
kill_chat_window(&windows[i], m);
|
kill_chat_window(&windows[i], m);
|
||||||
else if (windows[i].is_groupchat)
|
else if (windows[i].is_groupchat)
|
||||||
kill_groupchat_window(&windows[i]);
|
close_groupchat(&windows[i], m, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
kill_prompt_window(prompt);
|
kill_prompt_window(prompt);
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
|
|
||||||
#define MAX_WINDOWS_NUM 32
|
#define MAX_WINDOWS_NUM 32
|
||||||
#define MAX_WINDOW_NAME_LENGTH 16
|
#define MAX_WINDOW_NAME_LENGTH 22
|
||||||
#define CURS_Y_OFFSET 1 /* y-axis cursor offset for chat contexts */
|
#define CURS_Y_OFFSET 1 /* y-axis cursor offset for chat contexts */
|
||||||
#define CHATBOX_HEIGHT 2
|
#define CHATBOX_HEIGHT 2
|
||||||
|
|
||||||
@ -76,22 +76,26 @@ struct cqueue_thread {
|
|||||||
pthread_t tid;
|
pthread_t tid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct audio_thread {
|
||||||
|
pthread_t tid;
|
||||||
|
};
|
||||||
|
|
||||||
struct arg_opts {
|
struct arg_opts {
|
||||||
int ignore_data_file;
|
bool use_ipv4;
|
||||||
int use_ipv4;
|
bool force_tcp;
|
||||||
int force_tcp;
|
bool debug;
|
||||||
int debug;
|
bool default_locale;
|
||||||
int default_locale;
|
bool use_custom_data;
|
||||||
int use_custom_data;
|
bool no_connect;
|
||||||
int no_connect;
|
bool encrypt_data;
|
||||||
int encrypt_data;
|
bool unencrypt_data;
|
||||||
int unencrypt_data;
|
|
||||||
char dns_path[MAX_STR_SIZE];
|
char dns_path[MAX_STR_SIZE];
|
||||||
char config_path[MAX_STR_SIZE];
|
char config_path[MAX_STR_SIZE];
|
||||||
char nodes_path[MAX_STR_SIZE];
|
char nodes_path[MAX_STR_SIZE];
|
||||||
|
|
||||||
int use_proxy;
|
|
||||||
char proxy_address[256];
|
char proxy_address[256];
|
||||||
|
uint8_t proxy_type;
|
||||||
uint16_t proxy_port;
|
uint16_t proxy_port;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -102,26 +106,30 @@ typedef struct ChatContext ChatContext;
|
|||||||
typedef struct Help Help;
|
typedef struct Help Help;
|
||||||
|
|
||||||
struct ToxWindow {
|
struct ToxWindow {
|
||||||
|
/* ncurses */
|
||||||
void(*onKey)(ToxWindow *, Tox *, wint_t, bool);
|
void(*onKey)(ToxWindow *, Tox *, wint_t, bool);
|
||||||
void(*onDraw)(ToxWindow *, Tox *);
|
void(*onDraw)(ToxWindow *, Tox *);
|
||||||
void(*onInit)(ToxWindow *, Tox *);
|
void(*onInit)(ToxWindow *, Tox *);
|
||||||
void(*onFriendRequest)(ToxWindow *, Tox *, const char *, const char *, uint16_t);
|
|
||||||
void(*onFriendAdded)(ToxWindow *, Tox *, int32_t, bool);
|
/* toxcore */
|
||||||
void(*onConnectionChange)(ToxWindow *, Tox *, int32_t, uint8_t);
|
void(*onFriendRequest)(ToxWindow *, Tox *, const char *, const char *, size_t);
|
||||||
void(*onMessage)(ToxWindow *, Tox *, int32_t, const char *, uint16_t);
|
void(*onFriendAdded)(ToxWindow *, Tox *, uint32_t, bool);
|
||||||
void(*onNickChange)(ToxWindow *, Tox *, int32_t, const char *, uint16_t);
|
void(*onConnectionChange)(ToxWindow *, Tox *, uint32_t, TOX_CONNECTION);
|
||||||
void(*onStatusChange)(ToxWindow *, Tox *, int32_t, uint8_t);
|
void(*onMessage)(ToxWindow *, Tox *, uint32_t, TOX_MESSAGE_TYPE, const char *, size_t);
|
||||||
void(*onStatusMessageChange)(ToxWindow *, int32_t, const char *, uint16_t);
|
void(*onNickChange)(ToxWindow *, Tox *, uint32_t, const char *, size_t);
|
||||||
void(*onAction)(ToxWindow *, Tox *, int32_t, const char *, uint16_t);
|
void(*onStatusChange)(ToxWindow *, Tox *, uint32_t, TOX_USER_STATUS);
|
||||||
|
void(*onStatusMessageChange)(ToxWindow *, uint32_t, const char *, size_t);
|
||||||
void(*onGroupMessage)(ToxWindow *, Tox *, int, int, 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(*onGroupAction)(ToxWindow *, Tox *, int, int, const char *, uint16_t);
|
||||||
void(*onGroupInvite)(ToxWindow *, Tox *, int32_t, const char *, uint16_t);
|
void(*onGroupInvite)(ToxWindow *, Tox *, int32_t, uint8_t, const char *, uint16_t);
|
||||||
void(*onGroupNamelistChange)(ToxWindow *, Tox *, int, int, uint8_t);
|
void(*onGroupNamelistChange)(ToxWindow *, Tox *, int, int, uint8_t);
|
||||||
void(*onFileSendRequest)(ToxWindow *, Tox *, int32_t, uint8_t, uint64_t, const char *, uint16_t);
|
void(*onGroupTitleChange)(ToxWindow *, Tox *, int, int, const char *, uint8_t);
|
||||||
void(*onFileControl)(ToxWindow *, Tox *, int32_t, uint8_t, uint8_t, uint8_t, const char *, uint16_t);
|
void(*onFileChunkRequest)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, size_t);
|
||||||
void(*onFileData)(ToxWindow *, Tox *, int32_t, uint8_t, const char *, uint16_t);
|
void(*onFileRecvChunk)(ToxWindow *, Tox *, uint32_t, uint32_t, uint64_t, const char *, size_t);
|
||||||
void(*onTypingChange)(ToxWindow *, Tox *, int32_t, uint8_t);
|
void(*onFileControl)(ToxWindow *, Tox *, uint32_t, uint32_t, TOX_FILE_CONTROL);
|
||||||
void(*onReadReceipt)(ToxWindow *, Tox *, int32_t, uint32_t);
|
void(*onFileRecv)(ToxWindow *, Tox *, uint32_t, uint32_t, uint32_t, uint64_t, const char *, size_t);
|
||||||
|
void(*onTypingChange)(ToxWindow *, Tox *, uint32_t, bool);
|
||||||
|
void(*onReadReceipt)(ToxWindow *, Tox *, uint32_t, uint32_t);
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
|
|
||||||
@ -136,8 +144,9 @@ struct ToxWindow {
|
|||||||
void(*onEnd)(ToxWindow *, ToxAv *, int);
|
void(*onEnd)(ToxWindow *, ToxAv *, int);
|
||||||
void(*onRequestTimeout)(ToxWindow *, ToxAv *, int);
|
void(*onRequestTimeout)(ToxWindow *, ToxAv *, int);
|
||||||
void(*onPeerTimeout)(ToxWindow *, ToxAv *, int);
|
void(*onPeerTimeout)(ToxWindow *, ToxAv *, int);
|
||||||
|
void(*onWriteDevice)(ToxWindow *, Tox *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int);
|
||||||
|
|
||||||
int call_idx; /* If in a call will have this index set, otherwise it's -1.
|
int call_idx; /* If in a call will have this index set, otherwise it's -1.
|
||||||
* Don't modify outside av callbacks. */
|
* Don't modify outside av callbacks. */
|
||||||
int device_selection[2]; /* -1 if not set, if set uses these selections instead of primary device */
|
int device_selection[2]; /* -1 if not set, if set uses these selections instead of primary device */
|
||||||
|
|
||||||
@ -145,16 +154,17 @@ struct ToxWindow {
|
|||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
|
||||||
int active_box; /* For box notify */
|
int active_box; /* For box notify */
|
||||||
|
|
||||||
char name[TOXIC_MAX_NAME_LENGTH];
|
char name[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
int32_t num; /* corresponds to friendnumber in chat windows */
|
uint32_t num; /* corresponds to friendnumber in chat windows */
|
||||||
bool active;
|
bool active;
|
||||||
int x;
|
int x;
|
||||||
|
|
||||||
bool is_chat;
|
bool is_chat;
|
||||||
bool is_groupchat;
|
|
||||||
bool is_prompt;
|
bool is_prompt;
|
||||||
bool is_friendlist;
|
bool is_friendlist;
|
||||||
|
bool is_groupchat;
|
||||||
|
int show_peerlist; /* used to toggle groupchat peerlist */
|
||||||
|
|
||||||
WINDOW_ALERTS alert;
|
WINDOW_ALERTS alert;
|
||||||
|
|
||||||
@ -168,19 +178,19 @@ struct ToxWindow {
|
|||||||
/* statusbar info holder */
|
/* statusbar info holder */
|
||||||
struct StatusBar {
|
struct StatusBar {
|
||||||
WINDOW *topline;
|
WINDOW *topline;
|
||||||
char statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH];
|
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
|
||||||
uint16_t statusmsg_len;
|
size_t statusmsg_len;
|
||||||
char nick[TOXIC_MAX_NAME_LENGTH];
|
char nick[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
int nick_len;
|
size_t nick_len;
|
||||||
uint8_t status;
|
TOX_USER_STATUS status;
|
||||||
bool is_online;
|
TOX_CONNECTION connection;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
|
|
||||||
|
|
||||||
#define INFOBOX_HEIGHT 7
|
#define INFOBOX_HEIGHT 7
|
||||||
#define INFOBOX_WIDTH 21
|
#define INFOBOX_WIDTH 21
|
||||||
|
|
||||||
/* holds display info for audio calls */
|
/* holds display info for audio calls */
|
||||||
struct infobox {
|
struct infobox {
|
||||||
float vad_lvl;
|
float vad_lvl;
|
||||||
@ -242,9 +252,10 @@ void set_active_window(int ch);
|
|||||||
int get_num_active_windows(void);
|
int get_num_active_windows(void);
|
||||||
void kill_all_windows(Tox *m); /* should only be called on shutdown */
|
void kill_all_windows(Tox *m); /* should only be called on shutdown */
|
||||||
void on_window_resize(void);
|
void on_window_resize(void);
|
||||||
|
void force_refresh(WINDOW *w);
|
||||||
ToxWindow *get_window_ptr(int i);
|
ToxWindow *get_window_ptr(int i);
|
||||||
|
|
||||||
/* refresh inactive windows to prevent scrolling bugs.
|
/* refresh inactive windows to prevent scrolling bugs.
|
||||||
call at least once per second */
|
call at least once per second */
|
||||||
void refresh_inactive_windows(void);
|
void refresh_inactive_windows(void);
|
||||||
|
|
||||||
|
377
src/xtra.c
Normal file
377
src/xtra.c
Normal file
@ -0,0 +1,377 @@
|
|||||||
|
/* xtra.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 "xtra.h"
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xatom.h>
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
const Atom XtraTerminate = 1;
|
||||||
|
const Atom XtraNil = 0;
|
||||||
|
|
||||||
|
static Atom XdndAware;
|
||||||
|
static Atom XdndEnter;
|
||||||
|
static Atom XdndLeave;
|
||||||
|
static Atom XdndPosition;
|
||||||
|
static Atom XdndStatus;
|
||||||
|
static Atom XdndDrop;
|
||||||
|
static Atom XdndSelection;
|
||||||
|
static Atom XdndDATA;
|
||||||
|
static Atom XdndTypeList;
|
||||||
|
static Atom XdndActionCopy;
|
||||||
|
static Atom XdndFinished;
|
||||||
|
|
||||||
|
struct _Xtra {
|
||||||
|
drop_callback on_drop;
|
||||||
|
Display *display;
|
||||||
|
Window terminal_window;
|
||||||
|
Window proxy_window;
|
||||||
|
Window source_window; /* When we have a drop */
|
||||||
|
Atom handling_version;
|
||||||
|
Atom expecting_type;
|
||||||
|
} Xtra;
|
||||||
|
|
||||||
|
typedef struct _Property
|
||||||
|
{
|
||||||
|
unsigned char *data;
|
||||||
|
int read_format;
|
||||||
|
unsigned long read_num;
|
||||||
|
Atom read_type;
|
||||||
|
} Property;
|
||||||
|
|
||||||
|
Property read_property(Window s, Atom p)
|
||||||
|
{
|
||||||
|
Atom read_type;
|
||||||
|
int read_format;
|
||||||
|
unsigned long read_num;
|
||||||
|
unsigned long left_bytes;
|
||||||
|
unsigned char *data = NULL;
|
||||||
|
|
||||||
|
int read_bytes = 1024;
|
||||||
|
|
||||||
|
/* Keep trying to read the property until there are no bytes unread */
|
||||||
|
do {
|
||||||
|
if (data) XFree(data);
|
||||||
|
|
||||||
|
XGetWindowProperty(Xtra.display, s,
|
||||||
|
p, 0,
|
||||||
|
read_bytes,
|
||||||
|
False, AnyPropertyType,
|
||||||
|
&read_type, &read_format,
|
||||||
|
&read_num, &left_bytes,
|
||||||
|
&data);
|
||||||
|
|
||||||
|
read_bytes *= 2;
|
||||||
|
} while (left_bytes != 0);
|
||||||
|
|
||||||
|
Property property = {data, read_format, read_num, read_type};
|
||||||
|
return property;
|
||||||
|
}
|
||||||
|
|
||||||
|
Atom get_dnd_type(long *a, int l)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
for (; i < l; i ++) {
|
||||||
|
if (a[i] != XtraNil) return a[i]; /* Get first valid */
|
||||||
|
}
|
||||||
|
return XtraNil;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO maybe support only certain types in the future */
|
||||||
|
static void handle_xdnd_enter(XClientMessageEvent* e)
|
||||||
|
{
|
||||||
|
Xtra.handling_version = (e->data.l[1] >> 24);
|
||||||
|
|
||||||
|
if ((e->data.l[1] & 1)) {
|
||||||
|
// Fetch the list of possible conversions
|
||||||
|
Property p = read_property(e->data.l[0], XdndTypeList);
|
||||||
|
Xtra.expecting_type = get_dnd_type((long*)p.data, p.read_num);
|
||||||
|
XFree(p.data);
|
||||||
|
} else {
|
||||||
|
// Use the available list
|
||||||
|
Xtra.expecting_type = get_dnd_type(e->data.l + 2, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_xdnd_position(XClientMessageEvent* e)
|
||||||
|
{
|
||||||
|
XEvent ev = {
|
||||||
|
.xclient = {
|
||||||
|
.type = ClientMessage,
|
||||||
|
.display = e->display,
|
||||||
|
.window = e->data.l[0],
|
||||||
|
.message_type = XdndStatus,
|
||||||
|
.format = 32,
|
||||||
|
.data = {
|
||||||
|
.l = {
|
||||||
|
Xtra.proxy_window,
|
||||||
|
(Xtra.expecting_type != XtraNil),
|
||||||
|
0, 0,
|
||||||
|
XdndActionCopy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
XSendEvent(Xtra.display, e->data.l[0], False, NoEventMask, &ev);
|
||||||
|
XFlush(Xtra.display);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_xdnd_drop(XClientMessageEvent* e)
|
||||||
|
{
|
||||||
|
/* Not expecting any type */
|
||||||
|
if (Xtra.expecting_type == XtraNil) {
|
||||||
|
XEvent ev = {
|
||||||
|
.xclient = {
|
||||||
|
.type = ClientMessage,
|
||||||
|
.display = e->display,
|
||||||
|
.window = e->data.l[0],
|
||||||
|
.message_type = XdndFinished,
|
||||||
|
.format = 32,
|
||||||
|
.data = {
|
||||||
|
.l = {Xtra.proxy_window, 0, 0}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
XSendEvent(Xtra.display, e->data.l[0], False, NoEventMask, &ev);
|
||||||
|
} else {
|
||||||
|
Xtra.source_window = e->data.l[0];
|
||||||
|
XConvertSelection(Xtra.display,
|
||||||
|
XdndSelection,
|
||||||
|
Xtra.expecting_type,
|
||||||
|
XdndSelection,
|
||||||
|
Xtra.proxy_window,
|
||||||
|
Xtra.handling_version >= 1 ? e->data.l[2] : CurrentTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_xdnd_selection(XSelectionEvent* e)
|
||||||
|
{
|
||||||
|
/* DnD succesfully finished, send finished and call callback */
|
||||||
|
XEvent ev = {
|
||||||
|
.xclient = {
|
||||||
|
.type = ClientMessage,
|
||||||
|
.display = Xtra.display,
|
||||||
|
.window = Xtra.source_window,
|
||||||
|
.message_type = XdndFinished,
|
||||||
|
.format = 32,
|
||||||
|
.data = {
|
||||||
|
.l = {Xtra.proxy_window, 1, XdndActionCopy}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
XSendEvent(Xtra.display, Xtra.source_window, False, NoEventMask, &ev);
|
||||||
|
|
||||||
|
Property p = read_property(Xtra.proxy_window, XdndSelection);
|
||||||
|
DropType dt;
|
||||||
|
|
||||||
|
if (strcmp(XGetAtomName(Xtra.display, p.read_type), "text/uri-list") == 0)
|
||||||
|
dt = DT_file_list;
|
||||||
|
else /* text/uri-list */
|
||||||
|
dt = DT_plain;
|
||||||
|
|
||||||
|
|
||||||
|
/* Call callback for every entry */
|
||||||
|
if (Xtra.on_drop && p.read_num)
|
||||||
|
{
|
||||||
|
char *sptr;
|
||||||
|
char *str = strtok_r((char *) p.data, "\n\r", &sptr);
|
||||||
|
|
||||||
|
if (str) Xtra.on_drop(str, dt);
|
||||||
|
while ((str = strtok_r(NULL, "\n\r", &sptr)))
|
||||||
|
Xtra.on_drop(str, dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p.data) XFree(p.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *event_loop(void* p)
|
||||||
|
{
|
||||||
|
/* Handle events like a real nigga */
|
||||||
|
|
||||||
|
(void) p; /* DINDUNOTHIN */
|
||||||
|
|
||||||
|
XEvent event;
|
||||||
|
int pending;
|
||||||
|
|
||||||
|
while (Xtra.display)
|
||||||
|
{
|
||||||
|
/* NEEDMOEVENTSFODEMPROGRAMS */
|
||||||
|
|
||||||
|
XLockDisplay(Xtra.display);
|
||||||
|
if((pending = XPending(Xtra.display))) XNextEvent(Xtra.display, &event);
|
||||||
|
|
||||||
|
if (!pending)
|
||||||
|
{
|
||||||
|
XUnlockDisplay(Xtra.display);
|
||||||
|
usleep(10000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.type == ClientMessage)
|
||||||
|
{
|
||||||
|
Atom type = event.xclient.message_type;
|
||||||
|
|
||||||
|
if (type == XdndEnter) handle_xdnd_enter(&event.xclient);
|
||||||
|
else if (type == XdndPosition) handle_xdnd_position(&event.xclient);
|
||||||
|
else if (type == XdndDrop) handle_xdnd_drop(&event.xclient);
|
||||||
|
else if (type == XtraTerminate) break;
|
||||||
|
}
|
||||||
|
else if (event.type == SelectionNotify) handle_xdnd_selection(&event.xselection);
|
||||||
|
/* AINNOBODYCANHANDLEDEMEVENTS*/
|
||||||
|
else XSendEvent(Xtra.display, Xtra.terminal_window, 0, 0, &event);
|
||||||
|
|
||||||
|
XUnlockDisplay(Xtra.display);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Actual XTRA termination
|
||||||
|
* Please call xtra_terminate() at exit
|
||||||
|
* otherwise HEWUSAGUDBOI happens
|
||||||
|
*/
|
||||||
|
if (Xtra.display) XCloseDisplay(Xtra.display);
|
||||||
|
return (Xtra.display = NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int init_xtra(drop_callback d)
|
||||||
|
{
|
||||||
|
memset(&Xtra, 0, sizeof(Xtra));
|
||||||
|
|
||||||
|
if (!d) return -1;
|
||||||
|
else Xtra.on_drop = d;
|
||||||
|
|
||||||
|
XInitThreads();
|
||||||
|
if ( !(Xtra.display = XOpenDisplay(NULL))) return -1;
|
||||||
|
|
||||||
|
Xtra.terminal_window = focused_window_id();
|
||||||
|
|
||||||
|
{
|
||||||
|
/* Create an invisible window which will act as proxy for the DnD operation. */
|
||||||
|
XSetWindowAttributes attr = {0};
|
||||||
|
attr.event_mask = EnterWindowMask |
|
||||||
|
LeaveWindowMask |
|
||||||
|
ButtonMotionMask |
|
||||||
|
ButtonPressMask |
|
||||||
|
ButtonReleaseMask |
|
||||||
|
ResizeRedirectMask;
|
||||||
|
|
||||||
|
attr.do_not_propagate_mask = NoEventMask;
|
||||||
|
|
||||||
|
Window root;
|
||||||
|
int x, y;
|
||||||
|
unsigned int wht, hht, b, d;
|
||||||
|
|
||||||
|
/* Since we cannot capture resize events for parent window we will have to create
|
||||||
|
* this window to have maximum size as defined in root window
|
||||||
|
*/
|
||||||
|
XGetGeometry(Xtra.display,
|
||||||
|
XDefaultRootWindow(Xtra.display),
|
||||||
|
&root, &x, &y, &wht, &hht, &b, &d);
|
||||||
|
|
||||||
|
if (! (Xtra.proxy_window = XCreateWindow
|
||||||
|
(Xtra.display, Xtra.terminal_window, /* Parent */
|
||||||
|
0, 0, /* Position */
|
||||||
|
wht, hht, /* Width + height */
|
||||||
|
0, /* Border width */
|
||||||
|
CopyFromParent, /* Depth */
|
||||||
|
InputOnly, /* Class */
|
||||||
|
CopyFromParent, /* Visual */
|
||||||
|
CWEventMask | CWCursor, /* Value mask */
|
||||||
|
&attr)) ) /* Attributes for value mask */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XMapWindow(Xtra.display, Xtra.proxy_window); /* Show window (sandwich) */
|
||||||
|
XLowerWindow(Xtra.display, Xtra.proxy_window); /* Don't interfere with parent lmao */
|
||||||
|
|
||||||
|
XdndAware = XInternAtom(Xtra.display, "XdndAware", False);
|
||||||
|
XdndEnter = XInternAtom(Xtra.display, "XdndEnter", False);
|
||||||
|
XdndLeave = XInternAtom(Xtra.display, "XdndLeave", False);
|
||||||
|
XdndPosition = XInternAtom(Xtra.display, "XdndPosition", False);
|
||||||
|
XdndStatus = XInternAtom(Xtra.display, "XdndStatus", False);
|
||||||
|
XdndDrop = XInternAtom(Xtra.display, "XdndDrop", False);
|
||||||
|
XdndSelection = XInternAtom(Xtra.display, "XdndSelection", False);
|
||||||
|
XdndDATA = XInternAtom(Xtra.display, "XdndDATA", False);
|
||||||
|
XdndTypeList = XInternAtom(Xtra.display, "XdndTypeList", False);
|
||||||
|
XdndActionCopy = XInternAtom(Xtra.display, "XdndActionCopy", False);
|
||||||
|
XdndFinished = XInternAtom(Xtra.display, "XdndFinished", False);
|
||||||
|
|
||||||
|
/* Inform my nigga windows that we are aware of dnd */
|
||||||
|
Atom XdndVersion = 3;
|
||||||
|
XChangeProperty(Xtra.display,
|
||||||
|
Xtra.proxy_window,
|
||||||
|
XdndAware,
|
||||||
|
XA_ATOM,
|
||||||
|
32,
|
||||||
|
PropModeReplace,
|
||||||
|
(unsigned char*)&XdndVersion, 1);
|
||||||
|
|
||||||
|
pthread_t id;
|
||||||
|
pthread_create(&id, NULL, event_loop, NULL);
|
||||||
|
pthread_detach(id);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void terminate_xtra()
|
||||||
|
{
|
||||||
|
if (!Xtra.display) return;
|
||||||
|
|
||||||
|
XEvent terminate = {
|
||||||
|
.xclient = {
|
||||||
|
.type = ClientMessage,
|
||||||
|
.display = Xtra.display,
|
||||||
|
.message_type = XtraTerminate,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
XLockDisplay(Xtra.display);
|
||||||
|
XDeleteProperty(Xtra.display, Xtra.proxy_window, XdndAware);
|
||||||
|
XSendEvent(Xtra.display, Xtra.proxy_window, 0, NoEventMask, &terminate);
|
||||||
|
XUnlockDisplay(Xtra.display);
|
||||||
|
|
||||||
|
while (Xtra.display); /* Wait for termination */
|
||||||
|
}
|
||||||
|
|
||||||
|
long unsigned int focused_window_id()
|
||||||
|
{
|
||||||
|
if (!Xtra.display) return 0;
|
||||||
|
|
||||||
|
Window focus;
|
||||||
|
int revert;
|
||||||
|
XLockDisplay(Xtra.display);
|
||||||
|
XGetInputFocus(Xtra.display, &focus, &revert);
|
||||||
|
XUnlockDisplay(Xtra.display);
|
||||||
|
return focus;
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_focused()
|
||||||
|
{
|
||||||
|
return Xtra.proxy_window == focused_window_id() || Xtra.terminal_window == focused_window_id();
|
||||||
|
}
|
41
src/xtra.h
Normal file
41
src/xtra.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/* xtra.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 XTRA_H
|
||||||
|
#define XTRA_H
|
||||||
|
|
||||||
|
/* NOTE: If no xlib present don't compile */
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DT_plain,
|
||||||
|
DT_file_list
|
||||||
|
}
|
||||||
|
DropType;
|
||||||
|
|
||||||
|
typedef void (*drop_callback) (const char*, DropType);
|
||||||
|
|
||||||
|
int init_xtra(drop_callback d);
|
||||||
|
void terminate_xtra();
|
||||||
|
long unsigned int focused_window_id();
|
||||||
|
int is_focused(); /* returns bool */
|
||||||
|
|
||||||
|
#endif /* XTRA_H */
|
Reference in New Issue
Block a user