mirror of
https://github.com/Tha14/toxic.git
synced 2025-12-06 11:26:35 +01:00
Compare commits
82 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
97a8ecd115 | ||
|
|
64d782569a | ||
|
|
6248baf98b | ||
|
|
33cfca7ecc | ||
|
|
a01cc35368 | ||
|
|
b10eebd77e | ||
|
|
05661ca9b6 | ||
|
|
784883f773 | ||
|
|
a9e5723ca4 | ||
|
|
95dfea8d29 | ||
|
|
e574af7d68 | ||
|
|
2918ca45a2 | ||
|
|
6ad744f770 | ||
|
|
5b394e6f35 | ||
|
|
940af2c711 | ||
|
|
544c402f78 | ||
|
|
cee9e624b8 | ||
|
|
2e65ee3609 | ||
|
|
3a176e1cab | ||
|
|
00cccad22c | ||
|
|
a432d733d7 | ||
|
|
893e88294b | ||
|
|
b071a9e992 | ||
|
|
48cf4ebf02 | ||
|
|
773a75b948 | ||
|
|
133c0e8d63 | ||
|
|
bf54cb36ef | ||
|
|
032853b5c9 | ||
|
|
650c13ca7a | ||
|
|
9d5fe03285 | ||
|
|
c3f68b60d3 | ||
|
|
1c16467eb9 | ||
|
|
3c74385f5c | ||
|
|
c07c0028bb | ||
|
|
dc3b2e04ab | ||
|
|
7fd3aa9164 | ||
|
|
4c60312e2d | ||
|
|
16e29aa4e0 | ||
|
|
bd7b073155 | ||
|
|
f25cf870e6 | ||
|
|
13291d0365 | ||
|
|
9ee7a48910 | ||
|
|
daf4614ba6 | ||
|
|
919d36369c | ||
|
|
618704df76 | ||
|
|
9a70dd9651 | ||
|
|
e2d310b10f | ||
|
|
a1015a366a | ||
|
|
913ec7b3fe | ||
|
|
4a52b06954 | ||
|
|
89f9c07b9e | ||
|
|
388d78d11e | ||
|
|
a2a23b3932 | ||
|
|
f405ae8b42 | ||
|
|
cf3f6750eb | ||
|
|
4de22d067a | ||
|
|
51e274ea38 | ||
|
|
0a6ce62363 | ||
|
|
13c5de5531 | ||
|
|
21f8e7f398 | ||
|
|
bcf4a5af90 | ||
|
|
09f90d095b | ||
|
|
416ebc9ab8 | ||
|
|
3ca22aa714 | ||
|
|
8dd25e1f0b | ||
|
|
5b9bd603ea | ||
|
|
3c2c1f15ce | ||
|
|
6876df4a45 | ||
|
|
1ff97161fb | ||
|
|
667410e879 | ||
|
|
a862874740 | ||
|
|
79bde4e5bf | ||
|
|
833b724e9f | ||
|
|
96b68058bb | ||
|
|
e823233149 | ||
|
|
3ac22fafe4 | ||
|
|
71f2ac170c | ||
|
|
0ef888eea3 | ||
|
|
a9b0028a15 | ||
|
|
b18e6cff5a | ||
|
|
424a1c94d9 | ||
|
|
009095af24 |
@@ -5,11 +5,11 @@ compiler:
|
||||
|
||||
before_script:
|
||||
# Installing yasm (needed for compiling vpx) and openal
|
||||
- sudo apt-get -yq install yasm libopenal-dev libconfig-dev libalut-dev
|
||||
- sudo apt-get -yq install yasm libopenal-dev libconfig-dev libalut-dev libnotify-dev asciidoc
|
||||
# Installing libsodium, needed for toxcore
|
||||
- git clone https://github.com/jedisct1/libsodium.git libsodium
|
||||
- cd libsodium
|
||||
- git checkout tags/0.4.2 > /dev/null
|
||||
- git checkout tags/0.7.0 > /dev/null
|
||||
- ./autogen.sh > /dev/null
|
||||
- ./configure > /dev/null
|
||||
- make check -j2 || make check || exit 1 > /dev/null
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 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.
|
||||
|
||||

|
||||

|
||||
|
||||
## Installation
|
||||
|
||||
@@ -36,6 +36,7 @@ Toxic is a [Tox](https://tox.im)-based instant messenging client which formerly
|
||||
* 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
|
||||
|
||||
@@ -6,14 +6,14 @@ CFG_DIR = $(BASE_DIR)/cfg
|
||||
LIBS = libtoxcore ncursesw libconfig
|
||||
|
||||
CFLAGS = -std=gnu99 -pthread -Wall -g
|
||||
CFLAGS += -DTOXICVER="\"$(VERSION)\"" -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED
|
||||
CFLAGS += -DPACKAGE_DATADIR="\"$(abspath $(DATADIR))\""
|
||||
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
|
||||
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)
|
||||
@@ -58,7 +58,7 @@ toxic: $(OBJ)
|
||||
@$(CC) -MM $(CFLAGS) $(SRC_DIR)/$*.c > $*.d
|
||||
|
||||
clean:
|
||||
rm -rf *.d *.o toxic
|
||||
rm -f *.d *.o toxic
|
||||
|
||||
-include $(OBJ:.o=.d)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Variables for audio call support
|
||||
AUDIO_LIBS = libtoxav openal
|
||||
AUDIO_CFLAGS = -D_AUDIO
|
||||
AUDIO_CFLAGS = -DAUDIO
|
||||
ifneq (, $(findstring device.o, $(OBJ)))
|
||||
AUDIO_OBJ = audio_call.o
|
||||
else
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
CHECKS_DIR = $(CFG_DIR)/checks
|
||||
|
||||
# Check if we can use X11
|
||||
CHECK_X11_LIBS = $(shell pkg-config --exists x11 || echo -n "error")
|
||||
ifneq ($(CHECK_X11_LIBS), error)
|
||||
LIBS += x11
|
||||
CFLAGS += -D_X11
|
||||
# Check if we want build X11 support
|
||||
X11 = $(shell if [ -z "$(DISABLE_X11)" ] || [ "$(DISABLE_X11)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
|
||||
ifneq ($(X11), disabled)
|
||||
-include $(CHECKS_DIR)/x11.mk
|
||||
endif
|
||||
|
||||
# Check if we want build audio support
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Variables for desktop notifications support
|
||||
DESK_NOTIFY_LIBS = libnotify
|
||||
DESK_NOTIFY_CFLAGS = -D_BOX_NOTIFY
|
||||
DESK_NOTIFY_CFLAGS = -DBOX_NOTIFY
|
||||
|
||||
# Check if we can build desktop notifications support
|
||||
CHECK_DESK_NOTIFY_LIBS = $(shell pkg-config --exists $(DESK_NOTIFY_LIBS) || echo -n "error")
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Variables for sound notifications support
|
||||
SND_NOTIFY_LIBS = openal freealut
|
||||
SND_NOTIFY_CFLAGS = -D_SOUND_NOTIFY
|
||||
SND_NOTIFY_CFLAGS = -DSOUND_NOTIFY
|
||||
ifneq (, $(findstring device.o, $(OBJ)))
|
||||
SND_NOTIFY_OBJ =
|
||||
else
|
||||
|
||||
17
cfg/checks/x11.mk
Normal file
17
cfg/checks/x11.mk
Normal file
@@ -0,0 +1,17 @@
|
||||
# Variables for X11 support
|
||||
X11_LIBS = x11
|
||||
X11_CFLAGS = -DX11
|
||||
|
||||
# Check if we can build X11 support
|
||||
CHECK_X11_LIBS = $(shell pkg-config --exists $(X11_LIBS) || echo -n "error")
|
||||
ifneq ($(CHECK_X11_LIBS), error)
|
||||
LIBS += $(X11_LIBS)
|
||||
CFLAGS += $(X11_CFLAGS)
|
||||
else
|
||||
ifneq ($(MAKECMDGOALS), clean)
|
||||
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 -- You need these libraries for x11 support)
|
||||
$(warning WARNING -- $(MISSING_X11_LIBS))
|
||||
endif
|
||||
endif
|
||||
@@ -1,5 +1,5 @@
|
||||
# Version
|
||||
TOXIC_VERSION = 0.5.0
|
||||
TOXIC_VERSION = 0.5.2
|
||||
REV = $(shell git rev-list HEAD --count)
|
||||
VERSION = $(TOXIC_VERSION)_r$(REV)
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ help:
|
||||
@echo " help: This help"
|
||||
@echo
|
||||
@echo "-- Variables --"
|
||||
@echo " DISABLE_X11: Set to \"1\" to force building without X11 support"
|
||||
@echo " DISABLE_AV: Set to \"1\" to force building without audio call support"
|
||||
@echo " DISABLE_SOUND_NOTIFY: Set to \"1\" to force building without sound notification support"
|
||||
@echo " DISABLE_DESKTOP_NOTIFY: Set to \"1\" to force building without desktop notifications support"
|
||||
|
||||
16
doc/toxic.1
16
doc/toxic.1
@@ -2,12 +2,12 @@
|
||||
.\" Title: toxic
|
||||
.\" Author: [see the "AUTHORS" section]
|
||||
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
||||
.\" Date: 2014-08-21
|
||||
.\" Date: 2014-09-19
|
||||
.\" Manual: Toxic Manual
|
||||
.\" Source: toxic __VERSION__
|
||||
.\" Language: English
|
||||
.\"
|
||||
.TH "TOXIC" "1" "2014\-08\-21" "toxic __VERSION__" "Toxic Manual"
|
||||
.TH "TOXIC" "1" "2014\-09\-19" "toxic __VERSION__" "Toxic Manual"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * Define some portability stuff
|
||||
.\" -----------------------------------------------------------------
|
||||
@@ -55,11 +55,16 @@ instead of
|
||||
\fI~/\&.config/tox/toxic\&.conf\fR
|
||||
.RE
|
||||
.PP
|
||||
\-d, \-\-default_locale
|
||||
\-d, \-\-default\-locale
|
||||
.RS 4
|
||||
Use default locale
|
||||
.RE
|
||||
.PP
|
||||
\-e, \-\-encrypt\-data
|
||||
.RS 4
|
||||
Encrypt an unencrypted data file\&. An error will occur if this option is used with an encrypted data file\&.
|
||||
.RE
|
||||
.PP
|
||||
\-f, \-\-file data\-file
|
||||
.RS 4
|
||||
Use specified
|
||||
@@ -101,6 +106,11 @@ Use specified DNSservers file
|
||||
Force TCP connection (use this with proxies)
|
||||
.RE
|
||||
.PP
|
||||
\-u, \-\-unencrypt\-data
|
||||
.RS 4
|
||||
Unencrypt a data file\&. A warning will appear if this option is used with a data file that is already unencrypted\&.
|
||||
.RE
|
||||
.PP
|
||||
\-x, \-\-nodata
|
||||
.RS 4
|
||||
Ignore data file
|
||||
|
||||
@@ -27,11 +27,15 @@ OPTIONS
|
||||
-c, --config config-file::
|
||||
Use specified 'config-file' instead of '~/.config/tox/toxic.conf'
|
||||
|
||||
-d, --default_locale::
|
||||
-d, --default-locale::
|
||||
Use default locale
|
||||
|
||||
-e, --encrypt-data::
|
||||
Encrypt an unencrypted data file. An error will occur if this option
|
||||
is used with an encrypted data file.
|
||||
|
||||
-f, --file data-file::
|
||||
Use specified 'data-file' instead of '~/.config/tox/data'
|
||||
Use specified 'data-file' instead of '~/.config/tox/data'
|
||||
|
||||
-h, --help::
|
||||
Show help message
|
||||
@@ -52,6 +56,10 @@ OPTIONS
|
||||
-t, --force-tcp::
|
||||
Force TCP connection (use this with proxies)
|
||||
|
||||
-u, --unencrypt-data::
|
||||
Unencrypt a data file. A warning will appear if this option is used
|
||||
with a data file that is already unencrypted.
|
||||
|
||||
-x, --nodata::
|
||||
Ignore data file
|
||||
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
.\" Title: toxic.conf
|
||||
.\" Author: [see the "AUTHORS" section]
|
||||
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
||||
.\" Date: 2014-08-21
|
||||
.\" Date: 2014-09-19
|
||||
.\" Manual: Toxic Manual
|
||||
.\" Source: toxic __VERSION__
|
||||
.\" Language: English
|
||||
.\"
|
||||
.TH "TOXIC\&.CONF" "5" "2014\-08\-21" "toxic __VERSION__" "Toxic Manual"
|
||||
.TH "TOXIC\&.CONF" "5" "2014\-09\-19" "toxic __VERSION__" "Toxic Manual"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * Define some portability stuff
|
||||
.\" -----------------------------------------------------------------
|
||||
@@ -96,6 +96,11 @@ Show when others are typing in a 1\-on\-1 chat\&. true or false
|
||||
Show others when you\(cqre typing in a 1\-on\-1 chat\&. true or false
|
||||
.RE
|
||||
.PP
|
||||
\fBshow_welcome_msg\fR
|
||||
.RS 4
|
||||
Show welcome message on startup\&. true or false
|
||||
.RE
|
||||
.PP
|
||||
\fBhistory_size\fR
|
||||
.RS 4
|
||||
Maximum lines for chat window history\&. Integer value\&. (for example: 700)
|
||||
@@ -133,6 +138,11 @@ Configuration related to paths\&.
|
||||
Default path for downloads\&. String value\&. Absolute path for downloaded files\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBavatar_path\fR
|
||||
.RS 4
|
||||
Path for your avatar (file must be a \&.png and cannot exceed 16\&.3 KiB)
|
||||
.RE
|
||||
.PP
|
||||
\fBchatlogs_path\fR
|
||||
.RS 4
|
||||
Default path for chatlogs\&. String value\&. Absolute path for chatlog files\&.
|
||||
|
||||
@@ -60,6 +60,9 @@ OPTIONS
|
||||
*show_typing_self*;;
|
||||
Show others when you're typing in a 1-on-1 chat. true or false
|
||||
|
||||
*show_welcome_msg*;;
|
||||
Show welcome message on startup. true or false
|
||||
|
||||
*history_size*;;
|
||||
Maximum lines for chat window history. Integer value. (for example: 700)
|
||||
|
||||
@@ -84,6 +87,9 @@ OPTIONS
|
||||
Default path for downloads. String value. Absolute path for downloaded
|
||||
files.
|
||||
|
||||
*avatar_path*;;
|
||||
Path for your avatar (file must be a .png and cannot exceed 16.3 KiB)
|
||||
|
||||
*chatlogs_path*;;
|
||||
Default path for chatlogs. String value. Absolute path for chatlog files.
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
192.254.75.98 33445 951C88B7E75C867418ACDB5D273821372BB5BD652740BCDF623A4FA293E75D2F
|
||||
37.187.46.132 33445 A9D98212B3F972BD11DA52BEB0658C326FCCC1BFD49F347F9C2D3D8B61E1B927
|
||||
144.76.60.215 33445 04119E835DF3E78BACF0F84235B300546AF8B936F035185E2A8E9E0A67C8924F
|
||||
23.226.230.47 33445 A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074
|
||||
54.199.139.199 33445 7F9C31FE850E97CEFD4C4591DF93FC757C7C12549DDD55F8EEAECC34FE76C029
|
||||
23.226.230.47 33445 A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074
|
||||
54.199.139.199 33445 7F9C31FE850E97CEFD4C4591DF93FC757C7C12549DDD55F8EEAECC34FE76C029
|
||||
192.210.149.121 33445 F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67
|
||||
37.59.102.176 33445 B98A2CEAA6C6A2FADC2C3632D284318B60FE5375CCB41EFA081AB67F500C1B0B
|
||||
95.85.13.245 33445 7187969BB10B54C98538BAE94C069CE5C84E650D54F7E596543D8FB1ECF4CF23
|
||||
178.21.112.187 33445 4B2C19E924972CB9B57732FB172F8A8604DE13EEDA2A6234E348983344B23057
|
||||
76.191.23.96 33445 4BA57660DE3E854C530EED601BF8D54B7EFAE960523B6CFC10210CC08E2CB808
|
||||
107.161.17.51 33445 7BE3951B97CA4B9ECDDA768E8C52BA19E9E2690AB584787BF4C90E04DBB75111
|
||||
31.7.57.236 443 2A4B50D1D525DA2E669592A20C327B5FAD6C7E5962DC69296F9FEC77C4436E4E
|
||||
63.165.243.15 443 8CD087E31C67568103E8C2A28653337E90E6B8EDA0D765D57C6B5172B4F1F04C
|
||||
|
||||
@@ -23,6 +23,9 @@ ui = {
|
||||
// true to show others when you're typing a message in 1-on-1 chats
|
||||
show_typing_self=true;
|
||||
|
||||
// true to show the welcome message on startup
|
||||
show_welcome_msg=true;
|
||||
|
||||
// maximum lines for chat window history
|
||||
history_size=700;
|
||||
};
|
||||
@@ -42,6 +45,9 @@ tox = {
|
||||
// Path for downloaded files
|
||||
// download_path="/home/USERNAME/Downloads/";
|
||||
|
||||
// Path for your avatar (file must be a .png and cannot exceed 16.3 KiB)
|
||||
// avatar_path="/home/USERNAME/Pictures/youravatar.png";
|
||||
|
||||
// Path for chatlogs
|
||||
// chatlogs_path="/home/USERNAME/toxic_chatlogs/";
|
||||
};
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "line_info.h"
|
||||
#include "notify.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <curses.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
@@ -48,36 +49,41 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define _cbend pthread_exit(NULL)
|
||||
#define cbend pthread_exit(NULL)
|
||||
|
||||
#define MAX_CALLS 10
|
||||
|
||||
#define frame_size (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000)
|
||||
|
||||
typedef struct _Call {
|
||||
typedef struct Call {
|
||||
pthread_t ttid; /* Transmission thread id */
|
||||
_Bool ttas, has_output; /* Transmission thread active status (0 - stopped, 1- running) */
|
||||
bool ttas, has_output; /* Transmission thread active status (0 - stopped, 1- running) */
|
||||
uint32_t in_idx, out_idx;
|
||||
pthread_mutex_t mutex;
|
||||
} Call;
|
||||
|
||||
|
||||
void set_call(Call* call, _Bool start)
|
||||
static int set_call(Call* call, bool start)
|
||||
{
|
||||
call->in_idx = -1;
|
||||
call->out_idx = -1;
|
||||
|
||||
if ( start ) {
|
||||
call->ttas = _True;
|
||||
pthread_mutex_init(&call->mutex, NULL);
|
||||
call->ttas = true;
|
||||
|
||||
if (pthread_mutex_init(&call->mutex, NULL) != 0)
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
call->ttid = 0;
|
||||
pthread_mutex_destroy(&call->mutex);
|
||||
if (pthread_mutex_destroy(&call->mutex) != 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct _ASettings {
|
||||
struct ASettings {
|
||||
AudioError errors;
|
||||
|
||||
ToxAv *av;
|
||||
@@ -198,7 +204,8 @@ int start_transmission(ToxWindow *self)
|
||||
!toxav_capability_supported(ASettins.av, self->call_idx, AudioEncoding) )
|
||||
return -1;
|
||||
|
||||
set_call(&ASettins.calls[self->call_idx], _True);
|
||||
if (set_call(&ASettins.calls[self->call_idx], true) == -1)
|
||||
return -1;
|
||||
|
||||
ToxAvCSettings csettings;
|
||||
toxav_get_peer_csettings(ASettins.av, self->call_idx, 0, &csettings);
|
||||
@@ -206,9 +213,9 @@ int start_transmission(ToxWindow *self)
|
||||
if ( open_primary_device(input, &ASettins.calls[self->call_idx].in_idx,
|
||||
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!");
|
||||
|
||||
|
||||
if ( register_device_callback(self->call_idx, ASettins.calls[self->call_idx].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 */
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to register input handler!");
|
||||
|
||||
@@ -225,7 +232,7 @@ int stop_transmission(int call_index)
|
||||
{
|
||||
if ( ASettins.calls[call_index].ttas ) {
|
||||
toxav_kill_transmission(ASettins.av, call_index);
|
||||
ASettins.calls[call_index].ttas = _False;
|
||||
ASettins.calls[call_index].ttas = false;
|
||||
|
||||
if ( ASettins.calls[call_index].in_idx != -1 )
|
||||
close_device(input, ASettins.calls[call_index].in_idx);
|
||||
@@ -233,7 +240,9 @@ int stop_transmission(int call_index)
|
||||
if ( ASettins.calls[call_index].out_idx != -1 )
|
||||
close_device(output, ASettins.calls[call_index].out_idx);
|
||||
|
||||
set_call(&ASettins.calls[call_index], _False);
|
||||
if (set_call(&ASettins.calls[call_index], false) == -1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -452,7 +461,7 @@ void cmd_hangup(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
||||
if (toxav_get_call_state(ASettins.av, self->call_idx) == av_CallInviting) {
|
||||
error = toxav_cancel(ASettins.av, self->call_idx, self->num,
|
||||
"Only those who appreciate small things know the beauty that is life");
|
||||
#ifdef _SOUND_NOTIFY
|
||||
#ifdef SOUND_NOTIFY
|
||||
stop_sound(self->ringing_sound);
|
||||
#endif
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call canceled!");
|
||||
@@ -610,7 +619,7 @@ void cmd_ccur_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*a
|
||||
open_device(input, selection, &this_call->in_idx, csettings.audio_sample_rate,
|
||||
csettings.audio_frame_duration, csettings.audio_channels);
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _audio_h
|
||||
#define _audio_h
|
||||
#ifndef AUDIO_H
|
||||
#define AUDIO_H
|
||||
|
||||
#include <tox/toxav.h>
|
||||
|
||||
@@ -42,4 +42,4 @@ void terminate_audio();
|
||||
|
||||
void stop_current_call(ToxWindow *self);
|
||||
|
||||
#endif /* _audio_h */
|
||||
#endif /* AUDIO_H */
|
||||
|
||||
@@ -104,7 +104,9 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
|
||||
if (wcs_to_mbs_buf(ubuf, ctx->line, sizeof(ubuf)) == -1)
|
||||
return -1;
|
||||
|
||||
bool dir_search = strncmp(ubuf, "/sendfile", strlen("/sendfile")) == 0;
|
||||
/* TODO: generalize this */
|
||||
bool dir_search = !strncmp(ubuf, "/sendfile", strlen("/sendfile"))
|
||||
|| !strncmp(ubuf, "/avatar", strlen("/avatar"));
|
||||
|
||||
/* isolate substring from space behind pos to pos */
|
||||
char tmp[MAX_STR_SIZE];
|
||||
@@ -202,8 +204,8 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
|
||||
return diff;
|
||||
}
|
||||
|
||||
/* transforms a sendfile tab complete contaning the shorthand "~/" into the full home directory.*/
|
||||
static void complt_home_dir(ToxWindow *self, char *path, int pathsize)
|
||||
/* transforms a tab complete starting with the shorthand "~" into the full home directory.*/
|
||||
static void complt_home_dir(ToxWindow *self, char *path, int pathsize, const char *cmd, int cmdlen)
|
||||
{
|
||||
ChatContext *ctx = self->chatwin;
|
||||
|
||||
@@ -211,8 +213,8 @@ static void complt_home_dir(ToxWindow *self, char *path, int pathsize)
|
||||
get_home_dir(homedir, sizeof(homedir));
|
||||
|
||||
char newline[MAX_STR_SIZE];
|
||||
snprintf(newline, sizeof(newline), "/sendfile \"%s%s", homedir, path + 1);
|
||||
snprintf(path, pathsize, "%s", &newline[11]);
|
||||
snprintf(newline, sizeof(newline), "%s \"%s%s", cmd, homedir, path + 1);
|
||||
snprintf(path, pathsize, "%s", &newline[cmdlen]);
|
||||
|
||||
wchar_t wline[MAX_STR_SIZE];
|
||||
|
||||
@@ -229,23 +231,27 @@ static void complt_home_dir(ToxWindow *self, char *path, int pathsize)
|
||||
ctx->len = ctx->pos;
|
||||
}
|
||||
|
||||
/* attempts to match /sendfile "<incomplete-dir>" line to matching directories.
|
||||
/* attempts to match /command "<incomplete-dir>" line to matching directories.
|
||||
|
||||
if only one match, auto-complete line.
|
||||
return diff between old len and new len of ctx->line, -1 if no matches or > 1 match */
|
||||
#define MAX_DIRS 512
|
||||
|
||||
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line)
|
||||
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
|
||||
{
|
||||
char b_path[MAX_STR_SIZE];
|
||||
char b_name[MAX_STR_SIZE];
|
||||
const wchar_t *tmpline = &line[11]; /* start after "/sendfile \"" */
|
||||
char b_cmd[MAX_STR_SIZE];
|
||||
const wchar_t *tmpline = &line[wcslen(cmd) + 2]; /* start after "/command \"" */
|
||||
|
||||
if (wcs_to_mbs_buf(b_path, tmpline, sizeof(b_path)) == -1)
|
||||
return -1;
|
||||
|
||||
if (wcs_to_mbs_buf(b_cmd, cmd, sizeof(b_cmd)) == -1)
|
||||
return -1;
|
||||
|
||||
if (b_path[0] == '~')
|
||||
complt_home_dir(self, b_path, sizeof(b_path));
|
||||
complt_home_dir(self, b_path, sizeof(b_path), b_cmd, strlen(b_cmd) + 2);
|
||||
|
||||
int si = char_rfind(b_path, '/', strlen(b_path));
|
||||
|
||||
@@ -261,7 +267,6 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line)
|
||||
strcpy(b_name, &b_path[si + 1]);
|
||||
b_path[si + 1] = '\0';
|
||||
int b_name_len = strlen(b_name);
|
||||
|
||||
DIR *dp = opendir(b_path);
|
||||
|
||||
if (dp == NULL)
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _autocomplete_h
|
||||
#define _autocomplete_h
|
||||
#ifndef AUTOCOMPLETE_H
|
||||
#define AUTOCOMPLETE_H
|
||||
|
||||
/* looks for all instances in list that begin with the last entered word in line according to pos,
|
||||
then fills line with the complete word. e.g. "Hello jo" would complete the line
|
||||
@@ -33,10 +33,10 @@
|
||||
Returns the difference between the old len and new len of line on success, -1 if error */
|
||||
int complete_line(ToxWindow *self, const void *list, int n_items, int size);
|
||||
|
||||
/* attempts to match /sendfile "<incomplete-dir>" line to matching directories.
|
||||
/* attempts to match /command "<incomplete-dir>" line to matching directories.
|
||||
|
||||
if only one match, auto-complete line.
|
||||
return diff between old len and new len of ctx->line, -1 if no matches or > 1 match */
|
||||
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line);
|
||||
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd);
|
||||
|
||||
#endif /* #define _autocomplete_h */
|
||||
#endif /* #define AUTOCOMPLETE_H */
|
||||
|
||||
191
src/chat.c
191
src/chat.c
@@ -43,35 +43,37 @@
|
||||
#include "help.h"
|
||||
#include "autocomplete.h"
|
||||
#include "notify.h"
|
||||
#include "message_queue.h"
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
#include "audio_call.h"
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
|
||||
|
||||
extern char *DATA_FILE;
|
||||
|
||||
extern FileSender file_senders[MAX_FILES];
|
||||
extern _Friends Friends;
|
||||
extern FriendsList Friends;
|
||||
|
||||
extern struct _Winthread Winthread;
|
||||
extern struct user_settings *user_settings_;
|
||||
extern struct Winthread Winthread;
|
||||
extern struct user_settings *user_settings;
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
static void init_infobox(ToxWindow *self);
|
||||
static void kill_infobox(ToxWindow *self);
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
|
||||
#ifdef _AUDIO
|
||||
#define AC_NUM_CHAT_COMMANDS 26
|
||||
#ifdef AUDIO
|
||||
#define AC_NUM_CHAT_COMMANDS 27
|
||||
#else
|
||||
#define AC_NUM_CHAT_COMMANDS 19
|
||||
#endif /* _AUDIO */
|
||||
#define AC_NUM_CHAT_COMMANDS 20
|
||||
#endif /* AUDIO */
|
||||
|
||||
/* Array of chat command names used for tab completion. */
|
||||
static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
|
||||
{ "/accept" },
|
||||
{ "/add" },
|
||||
{ "/avatar" },
|
||||
{ "/cancel" },
|
||||
{ "/clear" },
|
||||
{ "/close" },
|
||||
@@ -90,7 +92,7 @@ static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
|
||||
{ "/sendfile" },
|
||||
{ "/status" },
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
|
||||
{ "/call" },
|
||||
{ "/answer" },
|
||||
@@ -100,12 +102,12 @@ static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
|
||||
{ "/mute" },
|
||||
{ "/sense" },
|
||||
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
};
|
||||
|
||||
static void set_self_typingstatus(ToxWindow *self, Tox *m, uint8_t is_typing)
|
||||
{
|
||||
if (user_settings_->show_typing_self == SHOW_TYPING_OFF)
|
||||
if (user_settings->show_typing_self == SHOW_TYPING_OFF)
|
||||
return;
|
||||
|
||||
ChatContext *ctx = self->chatwin;
|
||||
@@ -134,8 +136,9 @@ void kill_chat_window(ToxWindow *self, Tox *m)
|
||||
close_all_file_receivers(m, self->num);
|
||||
log_disable(ctx->log);
|
||||
line_info_cleanup(ctx->hst);
|
||||
cqueue_cleanup(ctx->cqueue);
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
stop_current_call(self);
|
||||
#endif
|
||||
|
||||
@@ -144,7 +147,6 @@ void kill_chat_window(ToxWindow *self, Tox *m)
|
||||
delwin(statusbar->topline);
|
||||
|
||||
free(ctx->log);
|
||||
free(ctx->hst);
|
||||
free(ctx);
|
||||
free(self->help);
|
||||
free(statusbar);
|
||||
@@ -196,8 +198,8 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, int32_t num, uint8_
|
||||
|
||||
if (status == 1) { /* Friend goes online */
|
||||
statusbar->is_online = true;
|
||||
Friends.list[num].is_typing = user_settings_->show_typing_other == SHOW_TYPING_ON
|
||||
? tox_get_is_typing(m, num) : 0;
|
||||
Friends.list[num].is_typing = user_settings->show_typing_other == SHOW_TYPING_ON
|
||||
? tox_get_is_typing(m, num) : 0;
|
||||
chat_resume_file_transfers(m, num);
|
||||
|
||||
msg = "has come online";
|
||||
@@ -239,7 +241,7 @@ static void chat_onAction(ToxWindow *self, Tox *m, int32_t num, const char *acti
|
||||
char timefrmt[TIME_STR_SIZE];
|
||||
get_time_str(timefrmt, sizeof(timefrmt));
|
||||
|
||||
line_info_add(self, timefrmt, nick, NULL, ACTION, 0, 0, "%s", action);
|
||||
line_info_add(self, timefrmt, nick, NULL, IN_ACTION, 0, 0, "%s", action);
|
||||
write_to_log(action, nick, ctx->log, true);
|
||||
|
||||
if (self->active_box != -1)
|
||||
@@ -287,14 +289,17 @@ static void chat_onStatusMessageChange(ToxWindow *self, int32_t num, const char
|
||||
statusbar->statusmsg_len = strlen(statusbar->statusmsg);
|
||||
}
|
||||
|
||||
static void chat_onReadReceipt(ToxWindow *self, Tox *m, int32_t num, uint32_t receipt)
|
||||
{
|
||||
cqueue_remove(self, m, receipt);
|
||||
}
|
||||
|
||||
static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t filenum,
|
||||
uint64_t filesize, const char *pathname, uint16_t path_len)
|
||||
{
|
||||
if (self->num != num)
|
||||
return;
|
||||
|
||||
const char *errmsg;
|
||||
|
||||
/* holds the filename appended to the user specified path */
|
||||
char filename_path[MAX_STR_SIZE] = {0};
|
||||
|
||||
@@ -308,20 +313,18 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t
|
||||
filename_nopath, sizestr);
|
||||
|
||||
if (filenum >= MAX_FILES) {
|
||||
errmsg = "Too many pending file requests; discarding.";
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Too many pending file requests; discarding.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* use specified path in config if possible */
|
||||
if (user_settings_->download_path[0]) {
|
||||
snprintf(filename_path, sizeof(filename_path), "%s%s", user_settings_->download_path, filename_nopath);
|
||||
len += strlen(user_settings_->download_path);
|
||||
if (user_settings->download_path[0]) {
|
||||
snprintf(filename_path, sizeof(filename_path), "%s%s", user_settings->download_path, filename_nopath);
|
||||
len += strlen(user_settings->download_path);
|
||||
}
|
||||
|
||||
if (len >= sizeof(Friends.list[num].file_receiver[filenum].filename)) {
|
||||
errmsg = "File name too long; discarding.";
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File name too long; discarding.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -351,8 +354,7 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t
|
||||
filename[len + d_len] = '\0';
|
||||
|
||||
if (count > 999) {
|
||||
errmsg = "Error saving file to disk.";
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error saving file to disk.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -494,7 +496,10 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, int32_t num, uint8_t rec
|
||||
case TOX_FILECONTROL_FINISHED:
|
||||
if (receive_send == 0) {
|
||||
print_progress_bar(self, filenum, num, 100.0);
|
||||
snprintf(msg, sizeof(msg), "File transfer for '%s' complete.", filename);
|
||||
|
||||
char filename_nopath[MAX_STR_SIZE];
|
||||
get_file_name(filename_nopath, sizeof(filename_nopath), filename);
|
||||
snprintf(msg, sizeof(msg), "File transfer for '%s' complete.", filename_nopath);
|
||||
chat_close_file_receiver(m, filenum, num, TOX_FILECONTROL_FINISHED);
|
||||
} else {
|
||||
snprintf(msg, sizeof(msg), "File '%s' successfuly sent.", filename);
|
||||
@@ -524,7 +529,12 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, int32_t num, uint8_t rec
|
||||
uint64_t datapos;
|
||||
memcpy(&datapos, tmp, sizeof(uint64_t));
|
||||
|
||||
fseek(fp, datapos, SEEK_SET);
|
||||
if (fseek(fp, datapos, SEEK_SET) == -1) {
|
||||
snprintf(msg, sizeof(msg), "File transfer for '%s' failed.", filename);
|
||||
close_file_sender(self, m, send_idx, NULL, TOX_FILECONTROL_FINISHED, filenum, num);
|
||||
break;
|
||||
}
|
||||
|
||||
tox_file_send_control(m, num, 0, filenum, TOX_FILECONTROL_ACCEPT, 0, 0);
|
||||
file_senders[send_idx].noconnection = false;
|
||||
break;
|
||||
@@ -553,32 +563,40 @@ static void chat_onFileData(ToxWindow *self, Tox *m, int32_t num, uint8_t filenu
|
||||
Friends.list[num].file_receiver[filenum].bytes_recv += length;
|
||||
}
|
||||
|
||||
static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, const char *group_pub_key)
|
||||
static void chat_onGroupInvite(ToxWindow *self, Tox *m, int32_t friendnumber, const char *group_pub_key, uint16_t length)
|
||||
{
|
||||
if (self->num != friendnumber)
|
||||
return;
|
||||
|
||||
if (Friends.list[friendnumber].group_invite.key != NULL)
|
||||
free(Friends.list[friendnumber].group_invite.key);
|
||||
|
||||
char *k = malloc(length);
|
||||
|
||||
if (k == NULL)
|
||||
exit_toxic_err("Failed in chat_onGroupInvite", FATALERR_MEMORY);
|
||||
|
||||
memcpy(k, group_pub_key, length);
|
||||
Friends.list[friendnumber].group_invite.key = k;
|
||||
Friends.list[friendnumber].group_invite.pending = true;
|
||||
Friends.list[friendnumber].group_invite.length = length;
|
||||
|
||||
char name[TOX_MAX_NAME_LENGTH];
|
||||
get_nick_truncate(m, name, friendnumber);
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s has invited you to a group chat.", name);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type \"/join\" to join the chat.");
|
||||
|
||||
memcpy(Friends.list[friendnumber].groupchat_key, group_pub_key,
|
||||
sizeof(Friends.list[friendnumber].groupchat_key));
|
||||
Friends.list[friendnumber].groupchat_pending = true;
|
||||
|
||||
|
||||
sound_notify(self, generic_message, NT_WNDALERT_2, NULL);
|
||||
|
||||
|
||||
if (self->active_box != -1)
|
||||
box_silent_notify2(self, NT_WNDALERT_2 | NT_NOFOCUS, self->active_box, "invites you to join group chat");
|
||||
else
|
||||
box_silent_notify(self, NT_WNDALERT_2 | NT_NOFOCUS, &self->active_box, name, "invites you to join group chat");
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s has invited you to a group chat.", name);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type \"/join\" to join the chat.");
|
||||
}
|
||||
|
||||
/* Av Stuff */
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
|
||||
void chat_onInvite (ToxWindow *self, ToxAv *av, int call_index)
|
||||
{
|
||||
@@ -607,10 +625,10 @@ void chat_onRinging (ToxWindow *self, ToxAv *av, int call_index)
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ringing...type \"/hangup\" to cancel it.");
|
||||
|
||||
#ifdef _SOUND_NOTIFY
|
||||
#ifdef SOUND_NOTIFY
|
||||
if (self->ringing_sound == -1)
|
||||
sound_notify(self, call_outgoing, NT_LOOP, &self->ringing_sound);
|
||||
#endif /* _SOUND_NOTIFY */
|
||||
#endif /* SOUND_NOTIFY */
|
||||
}
|
||||
|
||||
void chat_onStarting (ToxWindow *self, ToxAv *av, int call_index)
|
||||
@@ -622,9 +640,9 @@ void chat_onStarting (ToxWindow *self, ToxAv *av, int call_index)
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call started! Type: \"/hangup\" to end it.");
|
||||
|
||||
#ifdef _SOUND_NOTIFY
|
||||
#ifdef SOUND_NOTIFY
|
||||
stop_sound(self->ringing_sound);
|
||||
#endif /* _SOUND_NOTIFY */
|
||||
#endif /* SOUND_NOTIFY */
|
||||
}
|
||||
|
||||
void chat_onEnding (ToxWindow *self, ToxAv *av, int call_index)
|
||||
@@ -636,9 +654,9 @@ void chat_onEnding (ToxWindow *self, ToxAv *av, int call_index)
|
||||
self->call_idx = -1;
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call ended!");
|
||||
|
||||
#ifdef _SOUND_NOTIFY
|
||||
#ifdef SOUND_NOTIFY
|
||||
stop_sound(self->ringing_sound);
|
||||
#endif /* _SOUND_NOTIFY */
|
||||
#endif /* SOUND_NOTIFY */
|
||||
}
|
||||
|
||||
void chat_onError (ToxWindow *self, ToxAv *av, int call_index)
|
||||
@@ -649,9 +667,9 @@ void chat_onError (ToxWindow *self, ToxAv *av, int call_index)
|
||||
self->call_idx = -1;
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error!");
|
||||
|
||||
#ifdef _SOUND_NOTIFY
|
||||
#ifdef SOUND_NOTIFY
|
||||
stop_sound(self->ringing_sound);
|
||||
#endif /* _SOUND_NOTIFY */
|
||||
#endif /* SOUND_NOTIFY */
|
||||
}
|
||||
|
||||
void chat_onStart (ToxWindow *self, ToxAv *av, int call_index)
|
||||
@@ -663,9 +681,9 @@ void chat_onStart (ToxWindow *self, ToxAv *av, int call_index)
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call started! Type: \"/hangup\" to end it.");
|
||||
|
||||
#ifdef _SOUND_NOTIFY
|
||||
#ifdef SOUND_NOTIFY
|
||||
stop_sound(self->ringing_sound);
|
||||
#endif /* _SOUND_NOTIFY */
|
||||
#endif /* SOUND_NOTIFY */
|
||||
}
|
||||
|
||||
void chat_onCancel (ToxWindow *self, ToxAv *av, int call_index)
|
||||
@@ -677,9 +695,9 @@ void chat_onCancel (ToxWindow *self, ToxAv *av, int call_index)
|
||||
self->call_idx = -1;
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call canceled!");
|
||||
|
||||
#ifdef _SOUND_NOTIFY
|
||||
#ifdef SOUND_NOTIFY
|
||||
stop_sound(self->ringing_sound);
|
||||
#endif /* _SOUND_NOTIFY */
|
||||
#endif /* SOUND_NOTIFY */
|
||||
}
|
||||
|
||||
void chat_onReject (ToxWindow *self, ToxAv *av, int call_index)
|
||||
@@ -690,9 +708,9 @@ void chat_onReject (ToxWindow *self, ToxAv *av, int call_index)
|
||||
self->call_idx = -1;
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Rejected!");
|
||||
|
||||
#ifdef _SOUND_NOTIFY
|
||||
#ifdef SOUND_NOTIFY
|
||||
stop_sound(self->ringing_sound);
|
||||
#endif /* _SOUND_NOTIFY */
|
||||
#endif /* SOUND_NOTIFY */
|
||||
}
|
||||
|
||||
void chat_onEnd (ToxWindow *self, ToxAv *av, int call_index)
|
||||
@@ -704,9 +722,9 @@ void chat_onEnd (ToxWindow *self, ToxAv *av, int call_index)
|
||||
self->call_idx = -1;
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call ended!");
|
||||
|
||||
#ifdef _SOUND_NOTIFY
|
||||
#ifdef SOUND_NOTIFY
|
||||
stop_sound(self->ringing_sound);
|
||||
#endif /* _SOUND_NOTIFY */
|
||||
#endif /* SOUND_NOTIFY */
|
||||
}
|
||||
|
||||
void chat_onRequestTimeout (ToxWindow *self, ToxAv *av, int call_index)
|
||||
@@ -717,9 +735,9 @@ void chat_onRequestTimeout (ToxWindow *self, ToxAv *av, int call_index)
|
||||
self->call_idx = -1;
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No answer!");
|
||||
|
||||
#ifdef _SOUND_NOTIFY
|
||||
#ifdef SOUND_NOTIFY
|
||||
stop_sound(self->ringing_sound);
|
||||
#endif /* _SOUND_NOTIFY */
|
||||
#endif /* SOUND_NOTIFY */
|
||||
}
|
||||
|
||||
void chat_onPeerTimeout (ToxWindow *self, ToxAv *av, int call_index)
|
||||
@@ -731,9 +749,9 @@ void chat_onPeerTimeout (ToxWindow *self, ToxAv *av, int call_index)
|
||||
self->call_idx = -1;
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Peer disconnected; call ended!");
|
||||
|
||||
#ifdef _SOUND_NOTIFY
|
||||
#ifdef SOUND_NOTIFY
|
||||
stop_sound(self->ringing_sound);
|
||||
#endif /* _SOUND_NOTIFY */
|
||||
#endif /* SOUND_NOTIFY */
|
||||
}
|
||||
|
||||
static void init_infobox(ToxWindow *self)
|
||||
@@ -748,7 +766,7 @@ static void init_infobox(ToxWindow *self)
|
||||
|
||||
ctx->infobox.win = newwin(INFOBOX_HEIGHT, INFOBOX_WIDTH + 1, 1, x2 - INFOBOX_WIDTH);
|
||||
ctx->infobox.starttime = get_unix_time();
|
||||
ctx->infobox.vad_lvl = user_settings_->VAD_treshold;
|
||||
ctx->infobox.vad_lvl = user_settings->VAD_treshold;
|
||||
ctx->infobox.active = true;
|
||||
strcpy(ctx->infobox.timestr, "00");
|
||||
}
|
||||
@@ -818,7 +836,7 @@ static void draw_infobox(ToxWindow *self)
|
||||
wrefresh(infobox->win);
|
||||
}
|
||||
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
|
||||
static void send_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
|
||||
{
|
||||
@@ -832,13 +850,8 @@ static void send_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
|
||||
char timefrmt[TIME_STR_SIZE];
|
||||
get_time_str(timefrmt, sizeof(timefrmt));
|
||||
|
||||
line_info_add(self, timefrmt, selfname, NULL, ACTION, 0, 0, "%s", action);
|
||||
|
||||
if (tox_send_action(m, self->num, (uint8_t *) action, strlen(action)) == 0) {
|
||||
line_info_add(self, NULL, selfname, NULL, SYS_MSG, 0, RED, " * Failed to send action.");
|
||||
} else {
|
||||
write_to_log(action, selfname, ctx->log, true);
|
||||
}
|
||||
line_info_add(self, timefrmt, selfname, NULL, OUT_ACTION, 0, 0, "%s", action);
|
||||
cqueue_add(ctx->cqueue, action, strlen(action), OUT_ACTION, ctx->hst->line_end->id + 1);
|
||||
}
|
||||
|
||||
static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
@@ -875,8 +888,11 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
if (key == '\t' && ctx->len > 1 && ctx->line[0] == '/') { /* TAB key: auto-complete */
|
||||
int diff = -1;
|
||||
|
||||
/* TODO: make this not suck */
|
||||
if (wcsncmp(ctx->line, L"/sendfile \"", wcslen(L"/sendfile \"")) == 0) {
|
||||
diff = dir_match(self, m, ctx->line);
|
||||
diff = dir_match(self, m, ctx->line, L"/sendfile");
|
||||
} else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) {
|
||||
diff = dir_match(self, m, ctx->line, L"/avatar");
|
||||
} else {
|
||||
diff = complete_line(self, chat_cmd_list, AC_NUM_CHAT_COMMANDS, MAX_CMDNAME_SIZE);
|
||||
}
|
||||
@@ -919,12 +935,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
get_time_str(timefrmt, sizeof(timefrmt));
|
||||
|
||||
line_info_add(self, timefrmt, selfname, NULL, OUT_MSG, 0, 0, "%s", line);
|
||||
|
||||
if (!statusbar->is_online || tox_send_message(m, self->num, (uint8_t *) line, strlen(line)) == 0) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send message.");
|
||||
} else {
|
||||
write_to_log(line, selfname, ctx->log, false);
|
||||
}
|
||||
cqueue_add(ctx->cqueue, line, strlen(line), OUT_MSG, ctx->hst->line_end->id + 1);
|
||||
}
|
||||
|
||||
wclear(ctx->linewin);
|
||||
@@ -1023,7 +1034,7 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
|
||||
}
|
||||
|
||||
if (statusbar->statusmsg[0])
|
||||
wprintw(statusbar->topline, "- %s ", statusbar->statusmsg);
|
||||
wprintw(statusbar->topline, ": %s ", statusbar->statusmsg);
|
||||
|
||||
wclrtoeol(statusbar->topline);
|
||||
wmove(statusbar->topline, 0, x2 - (KEY_IDENT_DIGITS * 2) - 3);
|
||||
@@ -1046,7 +1057,7 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
|
||||
|
||||
wrefresh(self->window);
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
if (ctx->infobox.active) {
|
||||
draw_infobox(self);
|
||||
wrefresh(self->window);
|
||||
@@ -1090,14 +1101,21 @@ static void chat_onInit(ToxWindow *self, Tox *m)
|
||||
|
||||
ctx->hst = calloc(1, sizeof(struct history));
|
||||
ctx->log = calloc(1, sizeof(struct chatlog));
|
||||
ctx->cqueue = calloc(1, sizeof(struct chat_queue));
|
||||
|
||||
if (ctx->log == NULL || ctx->hst == NULL)
|
||||
if (ctx->log == NULL || ctx->hst == NULL || ctx->cqueue == NULL)
|
||||
exit_toxic_err("failed in chat_onInit", FATALERR_MEMORY);
|
||||
|
||||
line_info_init(ctx->hst);
|
||||
|
||||
if (Friends.list[self->num].logging_on)
|
||||
log_enable(nick, Friends.list[self->num].pub_key, ctx->log);
|
||||
char myid[TOX_FRIEND_ADDRESS_SIZE];
|
||||
tox_get_address(m, (uint8_t *) myid);
|
||||
|
||||
log_enable(nick, myid, Friends.list[self->num].pub_key, ctx->log, LOG_CHAT);
|
||||
load_chat_history(self, ctx->log);
|
||||
|
||||
if (!Friends.list[self->num].logging_on)
|
||||
log_disable(ctx->log);
|
||||
|
||||
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
|
||||
|
||||
@@ -1127,8 +1145,9 @@ ToxWindow new_chat(Tox *m, int32_t friendnum)
|
||||
ret.onFileSendRequest = &chat_onFileSendRequest;
|
||||
ret.onFileControl = &chat_onFileControl;
|
||||
ret.onFileData = &chat_onFileData;
|
||||
ret.onReadReceipt = &chat_onReadReceipt;
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
ret.onInvite = &chat_onInvite;
|
||||
ret.onRinging = &chat_onRinging;
|
||||
ret.onStarting = &chat_onStarting;
|
||||
@@ -1144,7 +1163,7 @@ ToxWindow new_chat(Tox *m, int32_t friendnum)
|
||||
ret.call_idx = -1;
|
||||
ret.device_selection[0] = ret.device_selection[1] = -1;
|
||||
ret.ringing_sound = -1;
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
|
||||
ret.active_box = -1;
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CHAT_H_6489PZ13
|
||||
#define CHAT_H_6489PZ13
|
||||
#ifndef CHAT_H
|
||||
#define CHAT_H
|
||||
|
||||
#include "windows.h"
|
||||
#include "toxic.h"
|
||||
@@ -32,4 +32,4 @@ void chat_close_file_receiver(Tox *m, int filenum, int friendnum, int CTRL);
|
||||
void kill_chat_window(ToxWindow *self, Tox *m);
|
||||
ToxWindow new_chat(Tox *m, int32_t friendnum);
|
||||
|
||||
#endif /* end of include guard: CHAT_H_6489PZ13 */
|
||||
#endif /* end of include guard: CHAT_H */
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "file_senders.h"
|
||||
|
||||
extern ToxWindow *prompt;
|
||||
extern _Friends Friends;
|
||||
extern FriendsList Friends;
|
||||
|
||||
extern FileSender file_senders[MAX_FILES];
|
||||
extern uint8_t max_file_senders_index;
|
||||
@@ -123,14 +123,15 @@ void cmd_join_group(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
|
||||
return;
|
||||
}
|
||||
|
||||
const char *groupkey = Friends.list[self->num].groupchat_key;
|
||||
const char *groupkey = Friends.list[self->num].group_invite.key;
|
||||
uint16_t length = Friends.list[self->num].group_invite.length;
|
||||
|
||||
if (!Friends.list[self->num].groupchat_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.");
|
||||
return;
|
||||
}
|
||||
|
||||
int groupnum = tox_join_groupchat(m, self->num, (uint8_t *) groupkey);
|
||||
int groupnum = tox_join_groupchat(m, self->num, (uint8_t *) groupkey, length);
|
||||
|
||||
if (groupnum == -1) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Group chat instance failed to initialize.");
|
||||
@@ -224,9 +225,13 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
||||
return;
|
||||
}
|
||||
|
||||
fseek(file_to_send, 0, SEEK_END);
|
||||
uint64_t filesize = ftell(file_to_send);
|
||||
fseek(file_to_send, 0, SEEK_SET);
|
||||
off_t filesize = file_size(path);
|
||||
|
||||
if (filesize == -1) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File corrupt.");
|
||||
fclose(file_to_send);
|
||||
return;
|
||||
}
|
||||
|
||||
char filename[MAX_STR_SIZE] = {0};
|
||||
get_file_name(filename, sizeof(filename), path);
|
||||
@@ -235,6 +240,7 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
||||
|
||||
if (filenum == -1) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error sending file.");
|
||||
fclose(file_to_send);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _chat_commands_h
|
||||
#define _chat_commands_h
|
||||
#ifndef CHAT_COMMANDS_H
|
||||
#define CHAT_COMMANDS_H
|
||||
|
||||
#include "windows.h"
|
||||
#include "toxic.h"
|
||||
@@ -32,7 +32,7 @@ void cmd_join_group(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR
|
||||
void cmd_savefile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_sendfile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
void cmd_call(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_answer(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_reject(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
@@ -41,6 +41,6 @@ void cmd_cancel(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZ
|
||||
void cmd_ccur_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_mute(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_sense(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
|
||||
#endif /* #define _chat_commands_h */
|
||||
#endif /* #define CHAT_COMMANDS_H */
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _configdir_h
|
||||
#define _configdir_h
|
||||
#ifndef CONFIGDIR_H
|
||||
#define CONFIGDIR_H
|
||||
|
||||
#ifndef NSS_BUFLEN_PASSWD
|
||||
#define NSS_BUFLEN_PASSWD 4096
|
||||
@@ -38,4 +38,4 @@ char *get_user_config_dir(void);
|
||||
void get_home_dir(char *home, int size);
|
||||
int create_user_config_dirs(char *path);
|
||||
|
||||
#endif /* #define _configdir_h */
|
||||
#endif /* #define CONFIGDIR_H */
|
||||
|
||||
110
src/device.c
110
src/device.c
@@ -22,7 +22,7 @@
|
||||
|
||||
#include "device.h"
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
#include "audio_call.h"
|
||||
#endif
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
@@ -50,9 +51,9 @@
|
||||
#define OPENAL_BUFS 5
|
||||
#define inline__ inline __attribute__((always_inline))
|
||||
|
||||
extern struct user_settings *user_settings_;
|
||||
extern struct user_settings *user_settings;
|
||||
|
||||
typedef struct _Device {
|
||||
typedef struct Device {
|
||||
ALCdevice *dhndl; /* Handle of device selected/opened */
|
||||
ALCcontext *ctx; /* Device context */
|
||||
DataHandleCallback cb; /* Use this to handle data from input device usually */
|
||||
@@ -60,15 +61,15 @@ typedef struct _Device {
|
||||
int32_t call_idx; /* ToxAv call index */
|
||||
|
||||
uint32_t source, buffers[OPENAL_BUFS]; /* Playback source/buffers */
|
||||
size_t ref_count;
|
||||
uint32_t ref_count;
|
||||
int32_t selection;
|
||||
_Bool enable_VAD;
|
||||
_Bool muted;
|
||||
bool enable_VAD;
|
||||
bool muted;
|
||||
pthread_mutex_t mutex[1];
|
||||
uint32_t sample_rate;
|
||||
uint32_t frame_duration;
|
||||
int32_t sound_mode;
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
float VAD_treshold; /* 40 is usually recommended value */
|
||||
#endif
|
||||
} Device;
|
||||
@@ -76,12 +77,12 @@ typedef struct _Device {
|
||||
const char *ddevice_names[2]; /* Default device */
|
||||
const char *devices_names[2][MAX_DEVICES]; /* Container of available devices */
|
||||
static int size[2]; /* Size of above containers */
|
||||
Device *running[2][MAX_DEVICES]; /* Running devices */
|
||||
Device *running[2][MAX_DEVICES] = {{NULL}}; /* Running devices */
|
||||
uint32_t primary_device[2]; /* Primary device */
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
static ToxAv* av = NULL;
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
|
||||
/* q_mutex */
|
||||
#define lock pthread_mutex_lock(&mutex)
|
||||
@@ -89,21 +90,19 @@ static ToxAv* av = NULL;
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
|
||||
_Bool thread_running = _True,
|
||||
thread_paused = _True; /* Thread control */
|
||||
bool thread_running = true,
|
||||
thread_paused = true; /* Thread control */
|
||||
|
||||
void* thread_poll(void*);
|
||||
/* Meet devices */
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
DeviceError init_devices(ToxAv* av_)
|
||||
#else
|
||||
DeviceError init_devices()
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
{
|
||||
const char *stringed_device_list;
|
||||
|
||||
|
||||
|
||||
|
||||
size[input] = 0;
|
||||
if ( (stringed_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER)) ) {
|
||||
ddevice_names[input] = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
|
||||
@@ -114,8 +113,6 @@ DeviceError init_devices()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
size[output] = 0;
|
||||
if ( (stringed_device_list = alcGetString(NULL, ALC_DEVICE_SPECIFIER)) ) {
|
||||
ddevice_names[output] = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
|
||||
@@ -125,18 +122,18 @@ DeviceError init_devices()
|
||||
stringed_device_list += strlen( stringed_device_list ) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Start poll thread
|
||||
|
||||
pthread_mutex_init(&mutex, NULL);
|
||||
if (pthread_mutex_init(&mutex, NULL) != 0)
|
||||
return de_InternalError;
|
||||
|
||||
pthread_t thread_id;
|
||||
if ( pthread_create(&thread_id, NULL, thread_poll, NULL) != 0 || pthread_detach(thread_id) != 0)
|
||||
return de_InternalError;
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
av = av_;
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
|
||||
return (DeviceError) de_None;
|
||||
}
|
||||
@@ -147,7 +144,8 @@ DeviceError terminate_devices()
|
||||
thread_running = false;
|
||||
usleep(20000);
|
||||
|
||||
pthread_mutex_destroy(&mutex);
|
||||
if (pthread_mutex_destroy(&mutex) != 0)
|
||||
return (DeviceError) de_InternalError;
|
||||
|
||||
return (DeviceError) de_None;
|
||||
}
|
||||
@@ -170,7 +168,7 @@ DeviceError device_mute(DeviceType type, uint32_t device_idx)
|
||||
return de_None;
|
||||
}
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value)
|
||||
{
|
||||
if (device_idx >= MAX_DEVICES) return de_InvalidSelection;
|
||||
@@ -222,6 +220,18 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
|
||||
if (i == MAX_DEVICES) { unlock; return de_AllDevicesBusy; }
|
||||
else *device_idx = i;
|
||||
|
||||
for (i = 0; i < MAX_DEVICES; i ++) { /* Check if any device has the same selection */
|
||||
if ( running[type][i] && running[type][i]->selection == selection ) {
|
||||
// printf("a%d-%d:%p ", selection, i, running[type][i]->dhndl);
|
||||
|
||||
running[type][*device_idx] = running[type][i];
|
||||
running[type][i]->ref_count ++;
|
||||
|
||||
unlock;
|
||||
return de_None;
|
||||
}
|
||||
}
|
||||
|
||||
Device* device = running[type][*device_idx] = calloc(1, sizeof(Device));
|
||||
device->selection = selection;
|
||||
|
||||
@@ -229,26 +239,17 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
|
||||
device->frame_duration = frame_duration;
|
||||
device->sound_mode = channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
|
||||
|
||||
for (i = 0; i < *device_idx; i ++) { /* Check if any previous has the same selection */
|
||||
if ( running[type][i]->selection == selection ) {
|
||||
device->dhndl = running[type][i]->dhndl;
|
||||
if (type == output) {
|
||||
device->ctx = running[type][i]->ctx;
|
||||
memcpy(device->buffers, running[type][i]->buffers, sizeof(running[type][i]->buffers));
|
||||
device->source = running[type][i]->source;
|
||||
}
|
||||
device->ref_count++;
|
||||
pthread_mutex_init(device->mutex, NULL);
|
||||
unlock;
|
||||
return de_None;
|
||||
}
|
||||
if (pthread_mutex_init(device->mutex, NULL) != 0) {
|
||||
free(device);
|
||||
unlock;
|
||||
return de_InternalError;
|
||||
}
|
||||
|
||||
if (type == input) {
|
||||
device->dhndl = alcCaptureOpenDevice(devices_names[type][selection],
|
||||
sample_rate, device->sound_mode, frame_size * 2);
|
||||
#ifdef _AUDIO
|
||||
device->VAD_treshold = user_settings_->VAD_treshold;
|
||||
#ifdef AUDIO
|
||||
device->VAD_treshold = user_settings->VAD_treshold;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
@@ -287,10 +288,9 @@ DeviceError open_device(DeviceType type, int32_t selection, uint32_t* device_idx
|
||||
|
||||
if (type == input) {
|
||||
alcCaptureStart(device->dhndl);
|
||||
thread_paused = _False;
|
||||
thread_paused = false;
|
||||
}
|
||||
|
||||
pthread_mutex_init(device->mutex, NULL);
|
||||
unlock;
|
||||
return de_None;
|
||||
}
|
||||
@@ -301,17 +301,18 @@ DeviceError close_device(DeviceType type, uint32_t device_idx)
|
||||
|
||||
lock;
|
||||
Device* device = running[type][device_idx];
|
||||
DeviceError rc = de_None;
|
||||
|
||||
if (!device) {
|
||||
unlock;
|
||||
return de_DeviceNotActive;
|
||||
}
|
||||
|
||||
if ( !(device->ref_count--) ) {
|
||||
running[type][device_idx] = NULL;
|
||||
unlock;
|
||||
running[type][device_idx] = NULL;
|
||||
|
||||
if ( !device->ref_count ) {
|
||||
|
||||
DeviceError rc = de_None;
|
||||
// printf("Closed device ");
|
||||
|
||||
if (type == input) {
|
||||
if ( !alcCaptureCloseDevice(device->dhndl) ) rc = de_AlError;
|
||||
@@ -328,16 +329,15 @@ DeviceError close_device(DeviceType type, uint32_t device_idx)
|
||||
}
|
||||
|
||||
free(device);
|
||||
return rc;
|
||||
}
|
||||
else device->ref_count--;
|
||||
|
||||
unlock;
|
||||
|
||||
return de_None;
|
||||
return rc;
|
||||
}
|
||||
|
||||
DeviceError register_device_callback( int32_t call_idx, uint32_t device_idx, DataHandleCallback callback, void* data, _Bool enable_VAD)
|
||||
{
|
||||
DeviceError register_device_callback( int32_t call_idx, uint32_t device_idx, DataHandleCallback callback, void* data, bool enable_VAD)
|
||||
{
|
||||
if (size[input] <= device_idx || !running[input][device_idx] || running[input][device_idx]->dhndl == NULL)
|
||||
return de_InvalidSelection;
|
||||
|
||||
@@ -427,9 +427,9 @@ void* thread_poll (void* arg) // TODO: maybe use thread for every input source
|
||||
alcCaptureSamples(device->dhndl, frame, f_size);
|
||||
|
||||
if ( device->muted
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
|| (device->enable_VAD && !toxav_has_activity(av, device->call_idx, frame, f_size, device->VAD_treshold))
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
)
|
||||
{ unlock; continue; } /* Skip if no voice activity */
|
||||
|
||||
@@ -464,4 +464,4 @@ void* get_device_callback_data(uint32_t device_idx)
|
||||
return NULL;
|
||||
|
||||
return running[input][device_idx]->cb_data;
|
||||
}
|
||||
}
|
||||
|
||||
17
src/device.h
17
src/device.h
@@ -26,16 +26,13 @@
|
||||
* Read from running input device(s) via select()/callback combo.
|
||||
*/
|
||||
|
||||
#ifndef _device_h
|
||||
#define _device_h
|
||||
#ifndef DEVICE_H
|
||||
#define DEVICE_H
|
||||
|
||||
#define MAX_DEVICES 32
|
||||
#include <inttypes.h>
|
||||
#include "windows.h"
|
||||
|
||||
#define _True 1
|
||||
#define _False 0
|
||||
|
||||
typedef enum DeviceType {
|
||||
input,
|
||||
output,
|
||||
@@ -57,22 +54,22 @@ typedef enum DeviceError {
|
||||
typedef void (*DataHandleCallback) (const int16_t*, uint32_t size, void* data);
|
||||
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
DeviceError init_devices(ToxAv* av);
|
||||
#else
|
||||
DeviceError init_devices();
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
|
||||
DeviceError terminate_devices();
|
||||
|
||||
/* Callback handles ready data from INPUT device */
|
||||
DeviceError register_device_callback(int32_t call_idx, uint32_t device_idx, DataHandleCallback callback, void* data, _Bool enable_VAD);
|
||||
DeviceError register_device_callback(int32_t call_idx, uint32_t device_idx, DataHandleCallback callback, void* data, bool enable_VAD);
|
||||
void* get_device_callback_data(uint32_t device_idx);
|
||||
|
||||
/* toggle device mute */
|
||||
DeviceError device_mute(DeviceType type, uint32_t device_idx);
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
DeviceError device_set_VAD_treshold(uint32_t device_idx, float value);
|
||||
#endif
|
||||
|
||||
@@ -89,4 +86,4 @@ DeviceError write_out(uint32_t device_idx, int16_t* data, uint32_t lenght, uint8
|
||||
void print_devices(ToxWindow* self, DeviceType type);
|
||||
|
||||
DeviceError selection_valid(DeviceType type, int32_t selection);
|
||||
#endif /* _device_h */
|
||||
#endif /* DEVICE_H */
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
#define MAX_DNS_REQST_SIZE 255
|
||||
#define TOX_DNS3_TXT_PREFIX "v=tox3;id="
|
||||
|
||||
extern struct _Winthread Winthread;
|
||||
extern struct Winthread Winthread;
|
||||
extern struct _dns3_servers dns3_servers;
|
||||
extern struct arg_opts arg_opts;
|
||||
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
/* Does DNS lookup for addr and puts resulting tox id in id_bin.
|
||||
Return 0 on success, -1 on failure. */
|
||||
|
||||
#ifndef _dns_h
|
||||
#define _dns_h
|
||||
#ifndef DNS_H
|
||||
#define DNS_H
|
||||
|
||||
/* 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);
|
||||
|
||||
#endif /* #define _dns_h */
|
||||
#endif /* #define DNS_H */
|
||||
|
||||
@@ -41,6 +41,7 @@ struct cmd_func {
|
||||
static struct cmd_func global_commands[] = {
|
||||
{ "/accept", cmd_accept },
|
||||
{ "/add", cmd_add },
|
||||
{ "/avatar", cmd_avatar },
|
||||
{ "/clear", cmd_clear },
|
||||
{ "/connect", cmd_connect },
|
||||
{ "/decline", cmd_decline },
|
||||
@@ -55,11 +56,11 @@ static struct cmd_func global_commands[] = {
|
||||
{ "/quit", cmd_quit },
|
||||
{ "/requests", cmd_requests },
|
||||
{ "/status", cmd_status },
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
{ "/lsdev", cmd_list_devices },
|
||||
{ "/sdev", cmd_change_device },
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
static struct cmd_func chat_commands[] = {
|
||||
@@ -68,8 +69,7 @@ static struct cmd_func chat_commands[] = {
|
||||
{ "/join", cmd_join_group },
|
||||
{ "/savefile", cmd_savefile },
|
||||
{ "/sendfile", cmd_sendfile },
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
{ "/call", cmd_call },
|
||||
{ "/answer", cmd_answer },
|
||||
{ "/reject", cmd_reject },
|
||||
@@ -77,7 +77,8 @@ static struct cmd_func chat_commands[] = {
|
||||
{ "/sdev", cmd_ccur_device },
|
||||
{ "/mute", cmd_mute },
|
||||
{ "/sense", cmd_sense },
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
/* Parses input command and puts args into arg array.
|
||||
@@ -101,7 +102,7 @@ static int parse_command(WINDOW *w, ToxWindow *self, const char *input, char (*a
|
||||
i = char_find(1, cmd, '\"');
|
||||
|
||||
if (cmd[i] == '\0') {
|
||||
char *errmsg = "Invalid argument. Did you forget a closing \"?";
|
||||
const char *errmsg = "Invalid argument. Did you forget a closing \"?";
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
||||
free(cmd);
|
||||
return -1;
|
||||
@@ -118,7 +119,7 @@ static int parse_command(WINDOW *w, ToxWindow *self, const char *input, char (*a
|
||||
|
||||
char tmp[MAX_STR_SIZE];
|
||||
snprintf(tmp, sizeof(tmp), "%s", &cmd[i + 1]);
|
||||
strcpy(cmd, tmp);
|
||||
strcpy(cmd, tmp); /* tmp will always fit inside cmd */
|
||||
}
|
||||
|
||||
free(cmd);
|
||||
@@ -126,12 +127,12 @@ static int parse_command(WINDOW *w, ToxWindow *self, const char *input, char (*a
|
||||
}
|
||||
|
||||
/* Matches command to respective function. Returns 0 on match, 1 on no match */
|
||||
static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, int num_cmds,
|
||||
struct cmd_func *commands, char (*args)[MAX_STR_SIZE])
|
||||
static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, struct cmd_func *commands,
|
||||
char (*args)[MAX_STR_SIZE])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_cmds; ++i) {
|
||||
for (i = 0; commands[i].name != NULL; ++i) {
|
||||
if (strcmp(args[0], commands[i].name) == 0) {
|
||||
(commands[i].func)(w, self, m, num_args - 1, args);
|
||||
return 0;
|
||||
@@ -158,7 +159,7 @@ void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode)
|
||||
Note: Global commands must come last in case of duplicate command names */
|
||||
switch (mode) {
|
||||
case CHAT_COMMAND_MODE:
|
||||
if (do_command(w, self, m, num_args, CHAT_NUM_COMMANDS, chat_commands, args) == 0)
|
||||
if (do_command(w, self, m, num_args, chat_commands, args) == 0)
|
||||
return;
|
||||
|
||||
break;
|
||||
@@ -167,7 +168,7 @@ void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode)
|
||||
break;
|
||||
}
|
||||
|
||||
if (do_command(w, self, m, num_args, GLOBAL_NUM_COMMANDS, global_commands, args) == 0)
|
||||
if (do_command(w, self, m, num_args, global_commands, args) == 0)
|
||||
return;
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid command.");
|
||||
|
||||
@@ -20,22 +20,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _execute_h
|
||||
#define _execute_h
|
||||
#ifndef EXECUTE_H
|
||||
#define EXECUTE_H
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
|
||||
#define MAX_NUM_ARGS 4 /* Includes command */
|
||||
|
||||
#ifdef _AUDIO
|
||||
#define GLOBAL_NUM_COMMANDS 18
|
||||
#define CHAT_NUM_COMMANDS 12
|
||||
#else
|
||||
#define GLOBAL_NUM_COMMANDS 16
|
||||
#define CHAT_NUM_COMMANDS 5
|
||||
#endif /* _AUDIO */
|
||||
|
||||
enum {
|
||||
GLOBAL_COMMAND_MODE,
|
||||
CHAT_COMMAND_MODE,
|
||||
@@ -44,4 +36,4 @@ enum {
|
||||
|
||||
void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode);
|
||||
|
||||
#endif /* #define _execute_h */
|
||||
#endif /* #define EXECUTE_H */
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
FileSender file_senders[MAX_FILES];
|
||||
uint8_t max_file_senders_index;
|
||||
uint8_t num_active_file_senders;
|
||||
extern _Friends Friends;
|
||||
extern FriendsList Friends;
|
||||
|
||||
/* creates initial progress line that will be updated during file transfer.
|
||||
Assumes progline is of size MAX_STR_SIZE */
|
||||
@@ -229,7 +229,7 @@ static void send_file_data(ToxWindow *self, Tox *m, int i, int32_t friendnum, in
|
||||
snprintf(msg, sizeof(msg), "File transfer for '%s' failed: Read error.", file_senders[i].filename);
|
||||
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)
|
||||
box_notify2(self, error, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", msg);
|
||||
else
|
||||
@@ -276,6 +276,7 @@ void do_file_senders(Tox *m)
|
||||
box_notify2(self, error, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", msg);
|
||||
else
|
||||
box_notify(self, error, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", msg);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _filesenders_h
|
||||
#define _filesenders_h
|
||||
#ifndef FILESENDERS_H
|
||||
#define FILESENDERS_H
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
@@ -72,4 +72,4 @@ void reset_file_sender_queue(void);
|
||||
void close_all_file_senders(Tox *m);
|
||||
void do_file_senders(Tox *m);
|
||||
|
||||
#endif /* #define _filesenders_h */
|
||||
#endif /* #define FILESENDERS_H */
|
||||
|
||||
@@ -37,8 +37,9 @@
|
||||
#include "settings.h"
|
||||
#include "notify.h"
|
||||
#include "help.h"
|
||||
#include "log.h"
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
#include "audio_call.h"
|
||||
#endif
|
||||
|
||||
@@ -46,15 +47,15 @@
|
||||
extern char *DATA_FILE;
|
||||
extern char *BLOCK_FILE;
|
||||
extern ToxWindow *prompt;
|
||||
extern struct _Winthread Winthread;
|
||||
extern struct user_settings *user_settings_;
|
||||
extern struct Winthread Winthread;
|
||||
extern struct user_settings *user_settings;
|
||||
extern struct arg_opts arg_opts;
|
||||
|
||||
static uint8_t blocklist_view = 0; /* 0 if we're in friendlist view, 1 if we're in blocklist view */
|
||||
|
||||
_Friends Friends;
|
||||
FriendsList Friends;
|
||||
|
||||
static struct _Blocked {
|
||||
static struct Blocked {
|
||||
int num_selected;
|
||||
int max_idx;
|
||||
int num_blocked;
|
||||
@@ -63,7 +64,7 @@ static struct _Blocked {
|
||||
BlockedFriend *list;
|
||||
} Blocked;
|
||||
|
||||
static struct _pendingDel {
|
||||
static struct pendingDel {
|
||||
int num;
|
||||
bool active;
|
||||
WINDOW *popup;
|
||||
@@ -111,6 +112,13 @@ static void realloc_blocklist(int n)
|
||||
|
||||
void kill_friendlist(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < Friends.max_idx; ++i) {
|
||||
if (Friends.list[i].active && Friends.list[i].group_invite.key != NULL)
|
||||
free(Friends.list[i].group_invite.key);
|
||||
}
|
||||
|
||||
realloc_blocklist(0);
|
||||
realloc_friends(0);
|
||||
}
|
||||
@@ -130,11 +138,12 @@ static int save_blocklist(char *path)
|
||||
exit_toxic_err("Failed in save_blocklist", FATALERR_MEMORY);
|
||||
|
||||
int i;
|
||||
int ret = -1;
|
||||
int count = 0;
|
||||
|
||||
for (i = 0; i < Blocked.max_idx; ++i) {
|
||||
if (count > Blocked.num_blocked)
|
||||
return -1;
|
||||
goto on_error;
|
||||
|
||||
if (Blocked.list[i].active) {
|
||||
BlockedFriend tmp;
|
||||
@@ -155,17 +164,16 @@ static int save_blocklist(char *path)
|
||||
|
||||
FILE *fp = fopen(path, "wb");
|
||||
|
||||
if (fp == NULL) {
|
||||
free(data);
|
||||
return -1;
|
||||
}
|
||||
if (fp == NULL)
|
||||
goto on_error;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
if (fwrite(data, len, 1, fp) != 1)
|
||||
ret = -1;
|
||||
if (fwrite(data, len, 1, fp) == 1)
|
||||
ret = 0;
|
||||
|
||||
fclose(fp);
|
||||
return ret;
|
||||
|
||||
on_error:
|
||||
free(data);
|
||||
return ret;
|
||||
}
|
||||
@@ -182,9 +190,12 @@ int load_blocklist(char *path)
|
||||
if (fp == NULL)
|
||||
return -1;
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
int len = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
off_t len = file_size(path);
|
||||
|
||||
if (len == -1) {
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *data = malloc(len);
|
||||
|
||||
@@ -287,7 +298,7 @@ static void update_friend_last_online(int32_t num, uint64_t timestamp)
|
||||
Friends.list[num].last_online.tm = *localtime((const time_t*)×tamp);
|
||||
|
||||
/* 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->time == TIME_12 ? "%I:%M %p" : "%H:%M";
|
||||
strftime(Friends.list[num].last_online.hour_min_str, TIME_STR_SIZE, t,
|
||||
&Friends.list[num].last_online.tm);
|
||||
}
|
||||
@@ -332,12 +343,27 @@ static void friendlist_onNickChange(ToxWindow *self, Tox *m, int32_t num, const
|
||||
if (len > TOX_MAX_NAME_LENGTH || num >= Friends.max_idx)
|
||||
return;
|
||||
|
||||
/* save old name for log renaming */
|
||||
char oldname[TOXIC_MAX_NAME_LENGTH];
|
||||
snprintf(oldname, sizeof(oldname), "%s", Friends.list[num].name);
|
||||
|
||||
/* update name */
|
||||
char tempname[TOX_MAX_NAME_LENGTH];
|
||||
strcpy(tempname, nick);
|
||||
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 */
|
||||
char newnamecpy[TOXIC_MAX_NAME_LENGTH];
|
||||
char myid[TOX_FRIEND_ADDRESS_SIZE];
|
||||
strcpy(newnamecpy, tempname);
|
||||
tox_get_address(m, (uint8_t *) myid);
|
||||
|
||||
if (strcmp(oldname, newnamecpy) != 0)
|
||||
rename_logfile(oldname, newnamecpy, myid, Friends.list[num].pub_key, Friends.list[num].chatwin);
|
||||
|
||||
sort_friendlist_index();
|
||||
}
|
||||
|
||||
@@ -379,7 +405,7 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_t num, bool sort)
|
||||
Friends.list[i].chatwin = -1;
|
||||
Friends.list[i].online = false;
|
||||
Friends.list[i].status = TOX_USERSTATUS_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));
|
||||
|
||||
@@ -421,7 +447,7 @@ static void friendlist_add_blocked(Tox *m, int32_t fnum, int32_t bnum)
|
||||
Friends.list[i].active = true;
|
||||
Friends.list[i].chatwin = -1;
|
||||
Friends.list[i].status = TOX_USERSTATUS_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;
|
||||
update_friend_last_online(i, Blocked.list[bnum].last_on);
|
||||
memcpy(Friends.list[i].name, Blocked.list[bnum].name, Friends.list[i].namelength + 1);
|
||||
@@ -460,7 +486,7 @@ static void friendlist_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, u
|
||||
}
|
||||
}
|
||||
|
||||
static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, const char *group_pub_key)
|
||||
static void friendlist_onGroupInvite(ToxWindow *self, Tox *m, int32_t num, const char *group_pub_key, uint16_t length)
|
||||
{
|
||||
if (num >= Friends.max_idx)
|
||||
return;
|
||||
@@ -503,6 +529,9 @@ static void delete_friend(Tox *m, int32_t f_num)
|
||||
}
|
||||
}
|
||||
|
||||
if (Friends.list[f_num].group_invite.key != NULL)
|
||||
free(Friends.list[f_num].group_invite.key);
|
||||
|
||||
tox_del_friend(m, f_num);
|
||||
memset(&Friends.list[f_num], 0, sizeof(ToxicFriend));
|
||||
|
||||
@@ -996,12 +1025,11 @@ void disable_chatwin(int32_t f_num)
|
||||
Friends.list[f_num].chatwin = -1;
|
||||
}
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
static void friendlist_onAv(ToxWindow *self, ToxAv *av, int call_index)
|
||||
{
|
||||
int id = toxav_get_peer_id(av, call_index, 0);
|
||||
|
||||
/*id++;*/
|
||||
if ( id != ErrorInternal && id >= Friends.max_idx)
|
||||
return;
|
||||
|
||||
@@ -1024,7 +1052,7 @@ static void friendlist_onAv(ToxWindow *self, ToxAv *av, int call_index)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
|
||||
ToxWindow new_friendlist(void)
|
||||
{
|
||||
@@ -1046,7 +1074,7 @@ ToxWindow new_friendlist(void)
|
||||
ret.onFileSendRequest = &friendlist_onFileSendRequest;
|
||||
ret.onGroupInvite = &friendlist_onGroupInvite;
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
ret.onInvite = &friendlist_onAv;
|
||||
ret.onRinging = &friendlist_onAv;
|
||||
ret.onStarting = &friendlist_onAv;
|
||||
@@ -1061,7 +1089,7 @@ ToxWindow new_friendlist(void)
|
||||
|
||||
ret.call_idx = -1;
|
||||
ret.device_selection[0] = ret.device_selection[1] = -1;
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
|
||||
ret.active_box = -1;
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef FRIENDLIST_H_53I41IM
|
||||
#define FRIENDLIST_H_53I41IM
|
||||
#ifndef FRIENDLIST_H
|
||||
#define FRIENDLIST_H
|
||||
|
||||
#include <time.h>
|
||||
|
||||
@@ -48,13 +48,17 @@ struct LastOnline {
|
||||
char hour_min_str[TIME_STR_SIZE]; /* holds 12/24-hour time string e.g. "10:43 PM" */
|
||||
};
|
||||
|
||||
struct GroupChatInvite {
|
||||
char *key;
|
||||
uint16_t length;
|
||||
bool pending;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
char name[TOXIC_MAX_NAME_LENGTH];
|
||||
int namelength;
|
||||
char statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH];
|
||||
uint16_t statusmsg_len;
|
||||
char groupchat_key[TOX_CLIENT_ID_SIZE];
|
||||
bool groupchat_pending;
|
||||
char pub_key[TOX_CLIENT_ID_SIZE];
|
||||
int32_t num;
|
||||
int chatwin;
|
||||
@@ -65,6 +69,7 @@ typedef struct {
|
||||
uint8_t status;
|
||||
struct LastOnline last_online;
|
||||
struct FileReceiver file_receiver[MAX_FILES];
|
||||
struct GroupChatInvite group_invite;
|
||||
uint8_t active_file_receivers;
|
||||
} ToxicFriend;
|
||||
|
||||
@@ -83,7 +88,7 @@ typedef struct {
|
||||
int num_friends;
|
||||
int *index;
|
||||
ToxicFriend *list;
|
||||
} _Friends;
|
||||
} FriendsList;
|
||||
|
||||
ToxWindow new_friendlist(void);
|
||||
void disable_chatwin(int32_t f_num);
|
||||
@@ -95,4 +100,4 @@ void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int32_t num, bool sort);
|
||||
/* sorts friendlist_index first by connection status then alphabetically */
|
||||
void sort_friendlist_index(void);
|
||||
|
||||
#endif /* end of include guard: FRIENDLIST_H_53I41IM */
|
||||
#endif /* end of include guard: FRIENDLIST_H */
|
||||
|
||||
@@ -37,8 +37,8 @@
|
||||
|
||||
extern char *DATA_FILE;
|
||||
extern ToxWindow *prompt;
|
||||
extern _Friends Friends;
|
||||
extern _FriendRequests FriendRequests;
|
||||
extern FriendsList Friends;
|
||||
extern FriendRequests FrndRequests;
|
||||
|
||||
/* command functions */
|
||||
void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
@@ -55,13 +55,13 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
||||
return;
|
||||
}
|
||||
|
||||
if (!FriendRequests.request[req].active) {
|
||||
if (!FrndRequests.request[req].active) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
|
||||
return;
|
||||
}
|
||||
|
||||
const char *msg;
|
||||
int32_t friendnum = tox_add_friend_norequest(m, FriendRequests.request[req].key);
|
||||
int32_t friendnum = tox_add_friend_norequest(m, FrndRequests.request[req].key);
|
||||
|
||||
if (friendnum == -1)
|
||||
msg = "Failed to add friend.";
|
||||
@@ -70,17 +70,17 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
|
||||
on_friendadded(m, friendnum, true);
|
||||
}
|
||||
|
||||
memset(&FriendRequests.request[req], 0, sizeof(struct _friend_request));
|
||||
memset(&FrndRequests.request[req], 0, sizeof(struct friend_request));
|
||||
|
||||
int i;
|
||||
|
||||
for (i = FriendRequests.max_idx; i > 0; --i) {
|
||||
if (FriendRequests.request[i - 1].active)
|
||||
for (i = FrndRequests.max_idx; i > 0; --i) {
|
||||
if (FrndRequests.request[i - 1].active)
|
||||
break;
|
||||
}
|
||||
|
||||
FriendRequests.max_idx = i;
|
||||
--FriendRequests.num_requests;
|
||||
FrndRequests.max_idx = i;
|
||||
--FrndRequests.num_requests;
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", msg);
|
||||
}
|
||||
|
||||
@@ -184,6 +184,81 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
||||
}
|
||||
}
|
||||
|
||||
void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
if (argc < 2) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: No file path supplied.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* turns the avatar off */
|
||||
if (strlen(argv[1]) < 3) {
|
||||
tox_unset_avatar(m);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No avatar set.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (argv[1][0] != '\"') {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Path must be enclosed in quotes.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* remove opening and closing quotes */
|
||||
char path[MAX_STR_SIZE];
|
||||
snprintf(path, sizeof(path), "%s", &argv[1][1]);
|
||||
int len = strlen(path) - 1;
|
||||
path[len] = '\0';
|
||||
|
||||
off_t sz = file_size(path);
|
||||
|
||||
if (sz <= 8) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Invalid file.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (sz > TOX_AVATAR_MAX_DATA_LENGTH) {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
char *avatar = malloc(sz);
|
||||
|
||||
if (avatar == NULL)
|
||||
exit_toxic_err("Failed in set_avatar", FATALERR_MEMORY);
|
||||
|
||||
if (fread(avatar, sz, 1, fp) != 1) {
|
||||
fclose(fp);
|
||||
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)
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set avatar: Core error.");
|
||||
|
||||
char filename[MAX_STR_SIZE];
|
||||
get_file_name(filename, sizeof(filename), path);
|
||||
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])
|
||||
{
|
||||
line_info_clear(self->chatwin->hst);
|
||||
@@ -227,22 +302,22 @@ void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!FriendRequests.request[req].active) {
|
||||
if (!FrndRequests.request[req].active) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&FriendRequests.request[req], 0, sizeof(struct _friend_request));
|
||||
memset(&FrndRequests.request[req], 0, sizeof(struct friend_request));
|
||||
|
||||
int i;
|
||||
|
||||
for (i = FriendRequests.max_idx; i > 0; --i) {
|
||||
if (FriendRequests.request[i - 1].active)
|
||||
for (i = FrndRequests.max_idx; i > 0; --i) {
|
||||
if (FrndRequests.request[i - 1].active)
|
||||
break;
|
||||
}
|
||||
|
||||
FriendRequests.max_idx = i;
|
||||
--FriendRequests.num_requests;
|
||||
FrndRequests.max_idx = i;
|
||||
--FrndRequests.num_requests;
|
||||
}
|
||||
|
||||
void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
@@ -286,16 +361,16 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
||||
const char *swch = argv[1];
|
||||
|
||||
if (!strcmp(swch, "1") || !strcmp(swch, "on")) {
|
||||
char myid[TOX_FRIEND_ADDRESS_SIZE];
|
||||
tox_get_address(m, (uint8_t *) myid);
|
||||
|
||||
if (self->is_chat) {
|
||||
Friends.list[self->num].logging_on = true;
|
||||
log_enable(self->name, Friends.list[self->num].pub_key, log);
|
||||
log_enable(self->name, myid, Friends.list[self->num].pub_key, log, LOG_CHAT);
|
||||
} else if (self->is_prompt) {
|
||||
char myid[TOX_FRIEND_ADDRESS_SIZE];
|
||||
tox_get_address(m, (uint8_t *) myid);
|
||||
log_enable(self->name, myid, log);
|
||||
log_enable(self->name, myid, NULL, log, LOG_PROMPT);
|
||||
} else if (self->is_groupchat) {
|
||||
log_enable(self->name, NULL, log);
|
||||
log_enable(self->name, myid, NULL, log, LOG_GROUP);
|
||||
}
|
||||
|
||||
msg = "Logging enabled";
|
||||
@@ -399,7 +474,7 @@ void cmd_quit(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
|
||||
|
||||
void cmd_requests(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
if (FriendRequests.num_requests == 0) {
|
||||
if (FrndRequests.num_requests == 0) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend requests.");
|
||||
return;
|
||||
}
|
||||
@@ -407,22 +482,22 @@ void cmd_requests(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
|
||||
int i, j;
|
||||
int count = 0;
|
||||
|
||||
for (i = 0; i < FriendRequests.max_idx; ++i) {
|
||||
if (!FriendRequests.request[i].active)
|
||||
for (i = 0; i < FrndRequests.max_idx; ++i) {
|
||||
if (!FrndRequests.request[i].active)
|
||||
continue;
|
||||
|
||||
char id[TOX_CLIENT_ID_SIZE * 2 + 1] = {0};
|
||||
|
||||
for (j = 0; j < TOX_CLIENT_ID_SIZE; ++j) {
|
||||
char d[3];
|
||||
snprintf(d, sizeof(d), "%02X", FriendRequests.request[i].key[j] & 0xff);
|
||||
snprintf(d, sizeof(d), "%02X", FrndRequests.request[i].key[j] & 0xff);
|
||||
strcat(id, d);
|
||||
}
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%d : %s", i, id);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", FriendRequests.request[i].msg);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", FrndRequests.request[i].msg);
|
||||
|
||||
if (++count < FriendRequests.num_requests)
|
||||
if (++count < FrndRequests.num_requests)
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,14 +20,15 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _global_commands_h
|
||||
#define _global_commands_h
|
||||
#ifndef GLOBAL_COMMANDS_H
|
||||
#define GLOBAL_COMMANDS_H
|
||||
|
||||
#include "windows.h"
|
||||
#include "toxic.h"
|
||||
|
||||
void cmd_accept(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_add(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_clear(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_connect(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
@@ -43,9 +44,9 @@ void cmd_status(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZ
|
||||
|
||||
void cmd_add_helper(ToxWindow *self, Tox *m, char *id_bin, char *msg);
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
void cmd_list_devices(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
void cmd_change_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
|
||||
#endif /* #define _global_commands_h */
|
||||
#endif /* #define GLOBAL_COMMANDS_H */
|
||||
|
||||
@@ -50,7 +50,7 @@ extern char *DATA_FILE;
|
||||
static GroupChat groupchats[MAX_GROUPCHAT_NUM];
|
||||
static int max_groupchat_index = 0;
|
||||
|
||||
extern struct user_settings *user_settings_;
|
||||
extern struct user_settings *user_settings;
|
||||
|
||||
/* temporary until group chats have unique commands */
|
||||
extern const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE];
|
||||
@@ -67,11 +67,16 @@ int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum)
|
||||
groupchats[i].chatwin = add_window(m, new_group_chat(m, groupnum));
|
||||
groupchats[i].active = true;
|
||||
groupchats[i].num_peers = 0;
|
||||
|
||||
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].peer_name_lengths = malloc(sizeof(uint16_t));
|
||||
groupchats[i].oldpeer_name_lengths = malloc(sizeof(uint16_t));
|
||||
|
||||
if (groupchats[i].peer_names == NULL || groupchats[i].oldpeer_names == NULL
|
||||
|| groupchats[i].peer_name_lengths == NULL || groupchats[i].oldpeer_name_lengths == NULL)
|
||||
exit_toxic_err("failed in init_groupchat_win", FATALERR_MEMORY);
|
||||
|
||||
memcpy(&groupchats[i].oldpeer_names[0], UNKNOWN_NAME, sizeof(UNKNOWN_NAME));
|
||||
groupchats[i].oldpeer_name_lengths[0] = (uint16_t) strlen(UNKNOWN_NAME);
|
||||
|
||||
@@ -97,7 +102,6 @@ void kill_groupchat_window(ToxWindow *self)
|
||||
delwin(ctx->history);
|
||||
delwin(ctx->sidebar);
|
||||
free(ctx->log);
|
||||
free(ctx->hst);
|
||||
free(ctx);
|
||||
free(self->help);
|
||||
del_window(self);
|
||||
@@ -198,7 +202,7 @@ static void groupchat_onGroupAction(ToxWindow *self, Tox *m, int groupnum, int p
|
||||
char timefrmt[TIME_STR_SIZE];
|
||||
get_time_str(timefrmt, sizeof(timefrmt));
|
||||
|
||||
line_info_add(self, timefrmt, nick, NULL, ACTION, 0, 0, "%s", action);
|
||||
line_info_add(self, timefrmt, nick, NULL, IN_ACTION, 0, 0, "%s", action);
|
||||
write_to_log(action, nick, ctx->log, true);
|
||||
}
|
||||
|
||||
@@ -303,7 +307,7 @@ static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnu
|
||||
|
||||
case TOX_CHAT_CHANGE_PEER_DEL:
|
||||
event = "has left the room";
|
||||
line_info_add(self, timefrmt, (char *) oldpeername, NULL, CONNECTION, 0, 0, event);
|
||||
line_info_add(self, timefrmt, (char *) oldpeername, NULL, CONNECTION, 0, RED, event);
|
||||
|
||||
if (groupchats[self->num].side_pos > 0)
|
||||
--groupchats[self->num].side_pos;
|
||||
@@ -368,11 +372,15 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
if (ctx->len > 0) {
|
||||
int diff;
|
||||
|
||||
if ((ctx->line[0] != '/') || (ctx->line[1] == 'm' && ctx->line[2] == 'e'))
|
||||
diff = complete_line(self, groupchats[self->num].peer_names,
|
||||
groupchats[self->num].num_peers, TOX_MAX_NAME_LENGTH);
|
||||
else
|
||||
/* TODO: make this not suck */
|
||||
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,
|
||||
TOX_MAX_NAME_LENGTH);
|
||||
} else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) {
|
||||
diff = dir_match(self, m, ctx->line, L"/avatar");
|
||||
} else {
|
||||
diff = complete_line(self, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
|
||||
}
|
||||
|
||||
if (diff != -1) {
|
||||
if (x + diff > x2 - 1) {
|
||||
@@ -385,12 +393,12 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
} else {
|
||||
sound_notify(self, 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;
|
||||
|
||||
if (groupchats[self->num].side_pos < groupchats[self->num].num_peers - L)
|
||||
++groupchats[self->num].side_pos;
|
||||
} else if (key == user_settings_->key_peer_list_up) {
|
||||
} else if (key == user_settings->key_peer_list_up) {
|
||||
if (groupchats[self->num].side_pos > 0)
|
||||
--groupchats[self->num].side_pos;
|
||||
} else if (key == '\n') {
|
||||
@@ -504,8 +512,11 @@ static void groupchat_onInit(ToxWindow *self, Tox *m)
|
||||
|
||||
line_info_init(ctx->hst);
|
||||
|
||||
if (user_settings_->autolog == AUTOLOG_ON)
|
||||
log_enable(self->name, NULL, ctx->log);
|
||||
if (user_settings->autolog == AUTOLOG_ON) {
|
||||
char myid[TOX_FRIEND_ADDRESS_SIZE];
|
||||
tox_get_address(m, (uint8_t *) myid);
|
||||
log_enable(self->name, myid, NULL, ctx->log, LOG_GROUP);
|
||||
}
|
||||
|
||||
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _groupchat_h
|
||||
#define _groupchat_h
|
||||
#ifndef GROUPCHAT_H
|
||||
#define GROUPCHAT_H
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
@@ -45,4 +45,4 @@ void kill_groupchat_window(ToxWindow *self);
|
||||
int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum);
|
||||
ToxWindow new_group_chat(Tox *m, int groupnum);
|
||||
|
||||
#endif /* #define _groupchat_h */
|
||||
#endif /* #define GROUPCHAT_H */
|
||||
|
||||
17
src/help.c
17
src/help.c
@@ -138,6 +138,7 @@ static void help_draw_global(ToxWindow *self)
|
||||
|
||||
wprintw(win, " /add <addr> <msg> : Add contact with optional message\n");
|
||||
wprintw(win, " /accept <id> : Accept friend request\n");
|
||||
wprintw(win, " /avatar <path> : Set a personal avatar\n");
|
||||
wprintw(win, " /decline <id> : Decline friend request\n");
|
||||
wprintw(win, " /requests : List pending friend requests\n");
|
||||
wprintw(win, " /connect <ip> <port> <key> : Manually connect to a DHT node\n");
|
||||
@@ -151,14 +152,14 @@ static void help_draw_global(ToxWindow *self)
|
||||
wprintw(win, " /close : Close the current chat window\n");
|
||||
wprintw(win, " /quit or /exit : Exit Toxic\n");
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
wattron(win, A_BOLD);
|
||||
wprintw(win, "\n Audio:\n");
|
||||
wattroff(win, A_BOLD);
|
||||
|
||||
wprintw(win, " /lsdev <type> : List devices where type: in|out\n");
|
||||
wprintw(win, " /sdev <type> <id> : Set active device\n");
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
|
||||
help_draw_bottom_menu(win);
|
||||
|
||||
@@ -182,7 +183,7 @@ static void help_draw_chat(ToxWindow *self)
|
||||
wprintw(win, " /savefile <id> : Receive a file\n");
|
||||
wprintw(win, " /cancel <type> <id> : Cancel file transfer where type: in|out\n");
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
wattron(win, A_BOLD);
|
||||
wprintw(win, "\n Audio:\n");
|
||||
wattroff(win, A_BOLD);
|
||||
@@ -194,7 +195,7 @@ static void help_draw_chat(ToxWindow *self)
|
||||
wprintw(win, " /sdev <type> <id> : Change active device\n");
|
||||
wprintw(win, " /mute <type> : Mute active device if in call\n");
|
||||
wprintw(win, " /sense <n> : VAD sensitivity treshold\n");
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
|
||||
help_draw_bottom_menu(win);
|
||||
|
||||
@@ -256,7 +257,7 @@ void help_onKey(ToxWindow *self, wint_t key)
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
help_init_window(self, 19, 80);
|
||||
#else
|
||||
help_init_window(self, 9, 80);
|
||||
@@ -265,10 +266,10 @@ void help_onKey(ToxWindow *self, wint_t key)
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
#ifdef _AUDIO
|
||||
help_init_window(self, 23, 80);
|
||||
#ifdef AUDIO
|
||||
help_init_window(self, 24, 80);
|
||||
#else
|
||||
help_init_window(self, 19, 80);
|
||||
help_init_window(self, 20, 80);
|
||||
#endif
|
||||
self->help->type = HELP_GLOBAL;
|
||||
break;
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _help_h
|
||||
#define _help_h
|
||||
#ifndef HELP_H
|
||||
#define HELP_H
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
@@ -39,4 +39,4 @@ void help_onDraw(ToxWindow *self);
|
||||
void help_init_menu(ToxWindow *self);
|
||||
void help_onKey(ToxWindow *self, wint_t key);
|
||||
|
||||
#endif /* #define _help_h */
|
||||
#endif /* #define HELP_H */
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _input_h
|
||||
#define _input_h
|
||||
#ifndef INPUT_H
|
||||
#define INPUT_H
|
||||
|
||||
/* add a char to input field and buffer for given chatcontext */
|
||||
void input_new_char(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y);
|
||||
@@ -30,4 +30,4 @@ void input_new_char(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_
|
||||
return true if key matches a function, false otherwise */
|
||||
bool input_handle(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y);
|
||||
|
||||
#endif /* #define _input_h */
|
||||
#endif /* #define INPUT_H */
|
||||
137
src/line_info.c
137
src/line_info.c
@@ -31,8 +31,10 @@
|
||||
#include "groupchat.h"
|
||||
#include "settings.h"
|
||||
#include "notify.h"
|
||||
#include "message_queue.h"
|
||||
#include "misc_tools.h"
|
||||
|
||||
extern struct user_settings *user_settings_;
|
||||
extern struct user_settings *user_settings;
|
||||
|
||||
void line_info_init(struct history *hst)
|
||||
{
|
||||
@@ -46,8 +48,8 @@ void line_info_init(struct history *hst)
|
||||
hst->queue_sz = 0;
|
||||
}
|
||||
|
||||
/* resets line_start (page end) */
|
||||
static void line_info_reset_start(ToxWindow *self, struct history *hst)
|
||||
/* resets line_start (moves to end of chat history) */
|
||||
void line_info_reset_start(ToxWindow *self, struct history *hst)
|
||||
{
|
||||
struct line_info *line = hst->line_end;
|
||||
|
||||
@@ -89,6 +91,8 @@ void line_info_cleanup(struct history *hst)
|
||||
if (hst->queue[i])
|
||||
free(hst->queue[i]);
|
||||
}
|
||||
|
||||
free(hst);
|
||||
}
|
||||
|
||||
/* moves root forward and frees previous root */
|
||||
@@ -107,22 +111,13 @@ static void line_info_root_fwd(struct history *hst)
|
||||
hst->line_root = tmp;
|
||||
}
|
||||
|
||||
/* adds a line_info line to queue */
|
||||
static void line_info_add_queue(struct history *hst, struct line_info *line)
|
||||
{
|
||||
if (hst->queue_sz >= MAX_QUEUE)
|
||||
return;
|
||||
|
||||
hst->queue[hst->queue_sz++] = line;
|
||||
}
|
||||
|
||||
/* returns ptr to queue item 0 and removes it from queue */
|
||||
/* returns ptr to queue item 0 and removes it from queue. Returns NULL if queue is empty. */
|
||||
static struct line_info *line_info_ret_queue(struct history *hst)
|
||||
{
|
||||
if (hst->queue_sz <= 0)
|
||||
return NULL;
|
||||
|
||||
struct line_info *ret = hst->queue[0];
|
||||
struct line_info *line = hst->queue[0];
|
||||
|
||||
int i;
|
||||
|
||||
@@ -131,21 +126,24 @@ static struct line_info *line_info_ret_queue(struct history *hst)
|
||||
|
||||
--hst->queue_sz;
|
||||
|
||||
return ret;
|
||||
return line;
|
||||
}
|
||||
|
||||
/* creates new line_info line and puts it in the queue.
|
||||
SYS_MSG lines may contain an arbitrary number of arguments for string formatting */
|
||||
void line_info_add(ToxWindow *self, char *tmstmp, char *name1, char *name2, uint8_t type, uint8_t bold,
|
||||
/* 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,
|
||||
uint8_t colour, const char *msg, ...)
|
||||
{
|
||||
struct history *hst = self->chatwin->hst;
|
||||
|
||||
if (hst->queue_sz >= MAX_LINE_INFO_QUEUE)
|
||||
return;
|
||||
|
||||
struct line_info *new_line = calloc(1, sizeof(struct line_info));
|
||||
|
||||
if (new_line == NULL)
|
||||
exit_toxic_err("failed in line_info_add", FATALERR_MEMORY);
|
||||
|
||||
char frmt_msg[MAX_STR_SIZE] = {0};
|
||||
char frmt_msg[MAX_LINE_INFO_MSG_SIZE] = {0};
|
||||
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
@@ -156,14 +154,27 @@ void line_info_add(ToxWindow *self, char *tmstmp, char *name1, char *name2, uint
|
||||
|
||||
/* for type-specific formatting in print function */
|
||||
switch (type) {
|
||||
case ACTION:
|
||||
case IN_ACTION:
|
||||
case OUT_ACTION:
|
||||
len += 5;
|
||||
break;
|
||||
|
||||
case IN_MSG:
|
||||
case OUT_MSG:
|
||||
len += 6;
|
||||
break;
|
||||
|
||||
case CONNECTION:
|
||||
len += 3;
|
||||
len += 5;
|
||||
break;
|
||||
|
||||
case SYS_MSG:
|
||||
break;
|
||||
|
||||
case NAME_CHANGE:
|
||||
len += 4;
|
||||
break;
|
||||
|
||||
case PROMPT:
|
||||
++len;
|
||||
break;
|
||||
@@ -185,9 +196,9 @@ void line_info_add(ToxWindow *self, char *tmstmp, char *name1, char *name2, uint
|
||||
}
|
||||
}
|
||||
|
||||
if (tmstmp) {
|
||||
snprintf(new_line->timestamp, sizeof(new_line->timestamp), "%s", tmstmp);
|
||||
len += strlen(new_line->timestamp);
|
||||
if (timestr) {
|
||||
snprintf(new_line->timestr, sizeof(new_line->timestr), "%s", timestr);
|
||||
len += strlen(new_line->timestr);
|
||||
}
|
||||
|
||||
if (name1) {
|
||||
@@ -204,8 +215,10 @@ void line_info_add(ToxWindow *self, char *tmstmp, char *name1, char *name2, uint
|
||||
new_line->type = type;
|
||||
new_line->bold = bold;
|
||||
new_line->colour = colour;
|
||||
new_line->noread_flag = false;
|
||||
new_line->timestamp = get_unix_time();
|
||||
|
||||
line_info_add_queue(hst, new_line);
|
||||
hst->queue[hst->queue_sz++] = new_line;
|
||||
}
|
||||
|
||||
/* adds a single queue item to hst if possible. only called once per call to line_info_print() */
|
||||
@@ -217,7 +230,7 @@ static void line_info_check_queue(ToxWindow *self)
|
||||
if (line == NULL)
|
||||
return;
|
||||
|
||||
if (hst->start_id > user_settings_->history_size)
|
||||
if (hst->start_id > user_settings->history_size)
|
||||
line_info_root_fwd(hst);
|
||||
|
||||
line->id = hst->line_end->id + 1;
|
||||
@@ -245,8 +258,14 @@ static void line_info_check_queue(ToxWindow *self)
|
||||
++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 */
|
||||
|
||||
void line_info_print(ToxWindow *self)
|
||||
{
|
||||
ChatContext *ctx = self->chatwin;
|
||||
@@ -280,9 +299,10 @@ void line_info_print(ToxWindow *self)
|
||||
|
||||
switch (type) {
|
||||
case OUT_MSG:
|
||||
case OUT_MSG_READ:
|
||||
case IN_MSG:
|
||||
wattron(win, COLOR_PAIR(BLUE));
|
||||
wprintw(win, "%s", line->timestamp);
|
||||
wprintw(win, "%s", line->timestr);
|
||||
wattroff(win, COLOR_PAIR(BLUE));
|
||||
|
||||
int nameclr = GREEN;
|
||||
@@ -293,34 +313,60 @@ void line_info_print(ToxWindow *self)
|
||||
nameclr = CYAN;
|
||||
|
||||
wattron(win, COLOR_PAIR(nameclr));
|
||||
wprintw(win, "%s: ", line->name1);
|
||||
wprintw(win, "--- %s: ", line->name1);
|
||||
wattroff(win, COLOR_PAIR(nameclr));
|
||||
|
||||
if (line->msg[0] == '>')
|
||||
wattron(win, COLOR_PAIR(GREEN));
|
||||
|
||||
wprintw(win, "%s\n", line->msg);
|
||||
wprintw(win, "%s", line->msg);
|
||||
|
||||
if (line->msg[0] == '>')
|
||||
wattroff(win, COLOR_PAIR(GREEN));
|
||||
|
||||
if (type == OUT_MSG && timed_out(line->timestamp, get_unix_time(), NOREAD_FLAG_TIMEOUT)) {
|
||||
wattron(win, COLOR_PAIR(RED));
|
||||
wprintw(win, " x", line->msg);
|
||||
wattroff(win, COLOR_PAIR(RED));
|
||||
|
||||
if (line->noread_flag == false) {
|
||||
line->noread_flag = true;
|
||||
line->len += 2;
|
||||
}
|
||||
}
|
||||
|
||||
wprintw(win, "\n", line->msg);
|
||||
break;
|
||||
|
||||
case ACTION:
|
||||
case OUT_ACTION_READ:
|
||||
case OUT_ACTION:
|
||||
case IN_ACTION:
|
||||
wattron(win, COLOR_PAIR(BLUE));
|
||||
wprintw(win, "%s", line->timestamp);
|
||||
wprintw(win, "%s", line->timestr);
|
||||
wattroff(win, COLOR_PAIR(BLUE));
|
||||
|
||||
wattron(win, COLOR_PAIR(YELLOW));
|
||||
wprintw(win, "* %s %s\n", line->name1, line->msg);
|
||||
wprintw(win, "-*- %s %s", line->name1, line->msg);
|
||||
wattroff(win, COLOR_PAIR(YELLOW));
|
||||
|
||||
if (type == OUT_ACTION && timed_out(line->timestamp, get_unix_time(), NOREAD_FLAG_TIMEOUT)) {
|
||||
wattron(win, COLOR_PAIR(RED));
|
||||
wprintw(win, " x", line->msg);
|
||||
wattroff(win, COLOR_PAIR(RED));
|
||||
|
||||
if (line->noread_flag == false) {
|
||||
line->noread_flag = true;
|
||||
line->len += 2;
|
||||
}
|
||||
}
|
||||
|
||||
wprintw(win, "\n", line->msg);
|
||||
break;
|
||||
|
||||
case SYS_MSG:
|
||||
if (line->timestamp[0]) {
|
||||
if (line->timestr[0]) {
|
||||
wattron(win, COLOR_PAIR(BLUE));
|
||||
wprintw(win, "%s", line->timestamp);
|
||||
wprintw(win, "%s", line->timestr);
|
||||
wattroff(win, COLOR_PAIR(BLUE));
|
||||
}
|
||||
|
||||
@@ -353,13 +399,16 @@ void line_info_print(ToxWindow *self)
|
||||
|
||||
case CONNECTION:
|
||||
wattron(win, COLOR_PAIR(BLUE));
|
||||
wprintw(win, "%s", line->timestamp);
|
||||
wprintw(win, "%s", line->timestr);
|
||||
wattroff(win, COLOR_PAIR(BLUE));
|
||||
|
||||
wattron(win, COLOR_PAIR(line->colour));
|
||||
wprintw(win, "%s ", line->colour == RED ? "<--" : "-->");
|
||||
|
||||
wattron(win, A_BOLD);
|
||||
wprintw(win, "* %s ", line->name1);
|
||||
wprintw(win, "%s ", line->name1);
|
||||
wattroff(win, A_BOLD);
|
||||
|
||||
wprintw(win, "%s\n", line->msg);
|
||||
wattroff(win, COLOR_PAIR(line->colour));
|
||||
|
||||
@@ -367,12 +416,13 @@ void line_info_print(ToxWindow *self)
|
||||
|
||||
case NAME_CHANGE:
|
||||
wattron(win, COLOR_PAIR(BLUE));
|
||||
wprintw(win, "%s", line->timestamp);
|
||||
wprintw(win, "%s", line->timestr);
|
||||
wattroff(win, COLOR_PAIR(BLUE));
|
||||
|
||||
wattron(win, COLOR_PAIR(MAGENTA));
|
||||
wprintw(win, "-!- ");
|
||||
wattron(win, A_BOLD);
|
||||
wprintw(win, "* %s", line->name1);
|
||||
wprintw(win, "%s", line->name1);
|
||||
wattroff(win, A_BOLD);
|
||||
|
||||
wprintw(win, "%s", line->msg);
|
||||
@@ -393,6 +443,7 @@ void line_info_print(ToxWindow *self)
|
||||
line_info_print(self);
|
||||
}
|
||||
|
||||
/* puts msg in specified line_info msg buffer */
|
||||
void line_info_set(ToxWindow *self, uint32_t id, char *msg)
|
||||
{
|
||||
struct line_info *line = self->chatwin->hst->line_end;
|
||||
@@ -455,19 +506,19 @@ bool line_info_onKey(ToxWindow *self, wint_t key)
|
||||
struct history *hst = self->chatwin->hst;
|
||||
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);
|
||||
}
|
||||
else if (key == user_settings_->key_half_page_down) {
|
||||
else if (key == user_settings->key_half_page_down) {
|
||||
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);
|
||||
}
|
||||
else if (key == user_settings_->key_scroll_line_down) {
|
||||
else if (key == user_settings->key_scroll_line_down) {
|
||||
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);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -20,36 +20,42 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _line_info_h
|
||||
#define _line_info_h
|
||||
#ifndef LINE_INFO_H
|
||||
#define LINE_INFO_H
|
||||
|
||||
#include "windows.h"
|
||||
#include "toxic.h"
|
||||
|
||||
#define MAX_HISTORY 100000
|
||||
#define MIN_HISTORY 40
|
||||
#define MAX_QUEUE 128
|
||||
#define MAX_LINE_INFO_QUEUE 1024
|
||||
#define MAX_LINE_INFO_MSG_SIZE MAX_STR_SIZE + TOXIC_MAX_NAME_LENGTH + 32 /* needs extra room for log loading */
|
||||
|
||||
enum {
|
||||
SYS_MSG,
|
||||
IN_MSG,
|
||||
OUT_MSG,
|
||||
OUT_MSG_READ, /* for sent messages that have received a read reply. don't set this with line_info_add */
|
||||
IN_ACTION,
|
||||
OUT_ACTION,
|
||||
OUT_ACTION_READ, /* same as OUT_MSG_READ but for actions */
|
||||
PROMPT,
|
||||
ACTION,
|
||||
CONNECTION,
|
||||
NAME_CHANGE,
|
||||
} LINE_TYPE;
|
||||
|
||||
struct line_info {
|
||||
char timestamp[TIME_STR_SIZE];
|
||||
char timestr[TIME_STR_SIZE];
|
||||
char name1[TOXIC_MAX_NAME_LENGTH];
|
||||
char name2[TOXIC_MAX_NAME_LENGTH];
|
||||
char msg[TOX_MAX_MESSAGE_LENGTH];
|
||||
char msg[MAX_LINE_INFO_MSG_SIZE];
|
||||
uint64_t timestamp;
|
||||
uint8_t type;
|
||||
uint8_t bold;
|
||||
uint8_t colour;
|
||||
uint8_t noread_flag; /* true if a line should be flagged as unread */
|
||||
uint32_t id;
|
||||
uint16_t len; /* combined len of all strings */
|
||||
uint16_t len; /* combined len of entire line */
|
||||
uint8_t newlines;
|
||||
|
||||
struct line_info *prev;
|
||||
@@ -63,13 +69,12 @@ struct history {
|
||||
struct line_info *line_end;
|
||||
uint32_t start_id; /* keeps track of where line_start should be when at bottom of history */
|
||||
|
||||
struct line_info *queue[MAX_QUEUE];
|
||||
struct line_info *queue[MAX_LINE_INFO_QUEUE];
|
||||
int queue_sz;
|
||||
};
|
||||
|
||||
/* creates new line_info line and puts it in the queue.
|
||||
SYS_MSG lines may contain an arbitrary number of arguments for string formatting */
|
||||
void line_info_add(ToxWindow *self, char *tmstmp, char *name1, char *name2, uint8_t type, uint8_t bold,
|
||||
/* 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,
|
||||
uint8_t colour, const char *msg, ...);
|
||||
|
||||
/* Prints a section of history starting at line_start */
|
||||
@@ -84,7 +89,10 @@ void line_info_clear(struct history *hst);
|
||||
/* puts msg in specified line_info msg buffer */
|
||||
void line_info_set(ToxWindow *self, uint32_t id, char *msg);
|
||||
|
||||
/* resets line_start (moves to end of chat history) */
|
||||
void line_info_reset_start(ToxWindow *self, struct history *hst);
|
||||
|
||||
void line_info_init(struct history *hst);
|
||||
bool line_info_onKey(ToxWindow *self, wint_t key); /* returns true if key is a match */
|
||||
|
||||
#endif /* #define _line_info_h */
|
||||
#endif /* #define LINE_INFO_H */
|
||||
|
||||
218
src/log.c
218
src/log.c
@@ -23,6 +23,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "configdir.h"
|
||||
#include "toxic.h"
|
||||
@@ -30,62 +31,92 @@
|
||||
#include "misc_tools.h"
|
||||
#include "log.h"
|
||||
#include "settings.h"
|
||||
#include "line_info.h"
|
||||
|
||||
extern struct user_settings *user_settings_;
|
||||
extern struct user_settings *user_settings;
|
||||
|
||||
/* Creates/fetches log file by appending to the config dir the name and a pseudo-unique identity */
|
||||
void init_logging_session(char *name, const char *key, struct chatlog *log)
|
||||
/* There are three types of logs: chat logs, groupchat logs, and prompt logs (see LOG_TYPE in log.h)
|
||||
A prompt log is in the format: LOGDIR/selfkey-home.log
|
||||
A chat log is in the format: LOGDIR/selfkey-friendname-otherkey.log
|
||||
A groupchat log is in the format: LOGDIR/selfkey-groupname-date[time].log
|
||||
|
||||
Only the first (KEY_IDENT_DIGITS * 2) numbers of the key are used.
|
||||
|
||||
Returns 0 on success, -1 if the path is too long */
|
||||
static int get_log_path(char *dest, int destsize, char *name, const char *selfkey, const char *otherkey, int logtype)
|
||||
{
|
||||
if (!log->log_on)
|
||||
return;
|
||||
|
||||
if (!valid_nick(name))
|
||||
name = UNKNOWN_NAME;
|
||||
|
||||
const char *set_path = user_settings_->chatlogs_path;
|
||||
const char *namedash = logtype == LOG_PROMPT ? "" : "-";
|
||||
const char *set_path = user_settings->chatlogs_path;
|
||||
|
||||
char *user_config_dir = get_user_config_dir();
|
||||
int path_len = strlen(set_path) + strlen(name) ? *set_path
|
||||
: strlen(user_config_dir) + strlen(LOGDIR) + strlen(name);
|
||||
int path_len = strlen(name) + strlen(".log") + strlen("-") + strlen(namedash);
|
||||
path_len += strlen(set_path) ? *set_path : strlen(user_config_dir) + strlen(LOGDIR);
|
||||
|
||||
/* use first 4 digits of key as log ident. If no key use a timestamp */
|
||||
char ident[32];
|
||||
/* first 6 digits of selfkey */
|
||||
char self_id[32];
|
||||
path_len += KEY_IDENT_DIGITS * 2;
|
||||
sprintf(&self_id[0], "%02X", selfkey[0] & 0xff);
|
||||
sprintf(&self_id[2], "%02X", selfkey[1] & 0xff);
|
||||
sprintf(&self_id[4], "%02X", selfkey[2] & 0xff);
|
||||
self_id[KEY_IDENT_DIGITS * 2] = '\0';
|
||||
|
||||
if (key != NULL) {
|
||||
path_len += (KEY_IDENT_DIGITS * 2 + 5);
|
||||
sprintf(&ident[0], "%02X", key[0] & 0xff);
|
||||
sprintf(&ident[2], "%02X", key[1] & 0xff);
|
||||
ident[KEY_IDENT_DIGITS * 2 + 1] = '\0';
|
||||
} else {
|
||||
strftime(ident, sizeof(ident), "%Y-%m-%d[%H:%M:%S]", get_time());
|
||||
path_len += strlen(ident) + 1;
|
||||
char other_id[32] = {0};
|
||||
|
||||
switch (logtype) {
|
||||
case LOG_CHAT:
|
||||
path_len += KEY_IDENT_DIGITS * 2;
|
||||
sprintf(&other_id[0], "%02X", otherkey[0] & 0xff);
|
||||
sprintf(&other_id[2], "%02X", otherkey[1] & 0xff);
|
||||
sprintf(&other_id[4], "%02X", otherkey[2] & 0xff);
|
||||
other_id[KEY_IDENT_DIGITS * 2] = '\0';
|
||||
break;
|
||||
|
||||
case LOG_GROUP:
|
||||
strftime(other_id, sizeof(other_id), "%Y-%m-%d[%H:%M:%S]", get_time());
|
||||
path_len += strlen(other_id);
|
||||
break;
|
||||
}
|
||||
|
||||
if (path_len >= MAX_STR_SIZE) {
|
||||
log->log_on = false;
|
||||
if (path_len >= destsize) {
|
||||
free(user_config_dir);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
char log_path[MAX_STR_SIZE];
|
||||
|
||||
if (*set_path)
|
||||
snprintf(log_path, sizeof(log_path), "%s%s-%s.log", set_path, name, ident);
|
||||
if (!string_is_empty(set_path))
|
||||
snprintf(dest, destsize, "%s%s-%s%s%s.log", set_path, self_id, name, namedash, other_id);
|
||||
else
|
||||
snprintf(log_path, sizeof(log_path), "%s%s%s-%s.log", user_config_dir, LOGDIR, name, ident);
|
||||
snprintf(dest, destsize, "%s%s%s-%s%s%s.log", user_config_dir, LOGDIR, self_id, name, namedash, other_id);
|
||||
|
||||
free(user_config_dir);
|
||||
|
||||
log->file = fopen(log_path, "a");
|
||||
|
||||
if (log->file == NULL) {
|
||||
log->log_on = false;
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(log->file, "\n*** NEW SESSION ***\n\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Opens log file or creates a new one */
|
||||
static int init_logging_session(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype)
|
||||
{
|
||||
if (selfkey == NULL || (logtype == LOG_CHAT && otherkey == NULL))
|
||||
return -1;
|
||||
|
||||
char log_path[MAX_STR_SIZE];
|
||||
|
||||
if (get_log_path(log_path, sizeof(log_path), name, selfkey, otherkey, logtype) == -1)
|
||||
return -1;
|
||||
|
||||
log->file = fopen(log_path, "a+");
|
||||
snprintf(log->path, sizeof(log->path), "%s", log_path);
|
||||
|
||||
if (log->file == NULL)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define LOG_FLUSH_LIMIT 1 /* limits calls to fflush to a max of one per LOG_FLUSH_LIMIT seconds */
|
||||
|
||||
void write_to_log(const char *msg, const char *name, struct chatlog *log, bool event)
|
||||
{
|
||||
if (!log->log_on)
|
||||
@@ -103,7 +134,7 @@ void write_to_log(const char *msg, const char *name, struct chatlog *log, bool e
|
||||
else
|
||||
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->time == TIME_12 ? "%Y/%m/%d [%I:%M:%S %p]" : "%Y/%m/%d [%H:%M:%S]";
|
||||
char s[MAX_STR_SIZE];
|
||||
strftime(s, MAX_STR_SIZE, t, get_time());
|
||||
fprintf(log->file, "%s %s %s\n", s, name_frmt, msg);
|
||||
@@ -116,20 +147,119 @@ void write_to_log(const char *msg, const char *name, struct chatlog *log, bool e
|
||||
}
|
||||
}
|
||||
|
||||
void log_enable(char *name, const char *key, struct chatlog *log)
|
||||
void log_disable(struct chatlog *log)
|
||||
{
|
||||
if (log->file != NULL)
|
||||
fclose(log->file);
|
||||
|
||||
memset(log, 0, sizeof(struct chatlog));
|
||||
}
|
||||
|
||||
void log_enable(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype)
|
||||
{
|
||||
log->log_on = true;
|
||||
|
||||
if (log->file == NULL)
|
||||
init_logging_session(name, key, log);
|
||||
if (log->file != NULL)
|
||||
return;
|
||||
|
||||
if (init_logging_session(name, selfkey, otherkey, log, logtype) == -1)
|
||||
log_disable(log);
|
||||
}
|
||||
|
||||
void log_disable(struct chatlog *log)
|
||||
/* Loads previous history from chat log */
|
||||
void load_chat_history(ToxWindow *self, struct chatlog *log)
|
||||
{
|
||||
log->log_on = false;
|
||||
if (log->file == NULL)
|
||||
return;
|
||||
|
||||
if (log->file != NULL) {
|
||||
fclose(log->file);
|
||||
log->file = NULL;
|
||||
off_t sz = file_size(log->path);
|
||||
|
||||
if (sz <= 0)
|
||||
return;
|
||||
|
||||
char *hstbuf = malloc(sz);
|
||||
|
||||
if (hstbuf == NULL)
|
||||
exit_toxic_err("failed in load_chat_history", FATALERR_MEMORY);
|
||||
|
||||
if (fseek(log->file, 0L, SEEK_SET) == -1) {
|
||||
free(hstbuf);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to read log file");
|
||||
return;
|
||||
}
|
||||
|
||||
if (fread(hstbuf, sz, 1, log->file) != 1) {
|
||||
free(hstbuf);
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to read log file");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Number of history lines to load: must not be larger than MAX_LINE_INFO_QUEUE - 2 */
|
||||
int L = MIN(MAX_LINE_INFO_QUEUE - 2, user_settings->history_size);
|
||||
int start, count = 0;
|
||||
|
||||
/* start at end and backtrace L lines or to the beginning of buffer */
|
||||
for (start = sz - 1; start >= 0 && count < L; --start) {
|
||||
if (hstbuf[start] == '\n')
|
||||
++count;
|
||||
}
|
||||
|
||||
const char *line = strtok(&hstbuf[start + 1], "\n");
|
||||
|
||||
if (line == NULL) {
|
||||
free(hstbuf);
|
||||
return;
|
||||
}
|
||||
|
||||
while (line != NULL && count--) {
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", line);
|
||||
line = strtok(NULL, "\n");
|
||||
}
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
|
||||
free(hstbuf);
|
||||
}
|
||||
|
||||
/* renames chatlog file replacing src with dest.
|
||||
Returns 0 on success or if no log exists, -1 on failure. */
|
||||
int rename_logfile(char *src, char *dest, const char *selfkey, const char *otherkey, int winnum)
|
||||
{
|
||||
ToxWindow *toxwin = get_window_ptr(winnum);
|
||||
struct chatlog *log = NULL;
|
||||
bool log_on = false;
|
||||
|
||||
/* disable log if necessary and save its state */
|
||||
if (toxwin != NULL) {
|
||||
log = toxwin->chatwin->log;
|
||||
log_on = log->log_on;
|
||||
}
|
||||
|
||||
if (log_on)
|
||||
log_disable(log);
|
||||
|
||||
char newpath[MAX_STR_SIZE];
|
||||
char oldpath[MAX_STR_SIZE];
|
||||
|
||||
if (get_log_path(oldpath, sizeof(oldpath), src, selfkey, otherkey, LOG_CHAT) == -1)
|
||||
goto on_error;
|
||||
|
||||
if (!file_exists(oldpath))
|
||||
return 0;
|
||||
|
||||
if (get_log_path(newpath, sizeof(newpath), dest, selfkey, otherkey, LOG_CHAT) == -1)
|
||||
goto on_error;
|
||||
|
||||
if (rename(oldpath, newpath) != 0)
|
||||
goto on_error;
|
||||
|
||||
if (log_on)
|
||||
log_enable(dest, selfkey, otherkey, log, LOG_CHAT);
|
||||
|
||||
return 0;
|
||||
|
||||
on_error:
|
||||
if (log_on)
|
||||
log_enable(src, selfkey, otherkey, log, LOG_CHAT);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
26
src/log.h
26
src/log.h
@@ -20,28 +20,36 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _log_h
|
||||
#define _log_h
|
||||
|
||||
#define LOG_FLUSH_LIMIT 2 /* limits calls to fflush(logfile) to a max of one per LOG_FLUSH_LIMIT seconds */
|
||||
#ifndef LOG_H
|
||||
#define LOG_H
|
||||
|
||||
struct chatlog {
|
||||
FILE *file;
|
||||
uint64_t lastwrite;
|
||||
int pos;
|
||||
char path[MAX_STR_SIZE];
|
||||
bool log_on; /* specific to current chat window */
|
||||
};
|
||||
|
||||
/* Creates/fetches log file by appending to the config dir the name and a pseudo-unique identity */
|
||||
void init_logging_session(char *name, const char *key, struct chatlog *log);
|
||||
enum {
|
||||
LOG_GROUP,
|
||||
LOG_PROMPT,
|
||||
LOG_CHAT,
|
||||
} LOG_TYPE;
|
||||
|
||||
/* formats/writes line to log file */
|
||||
void write_to_log(const char *msg, const char *name, struct chatlog *log, bool event);
|
||||
|
||||
/* enables logging for specified log and creates/fetches file if necessary */
|
||||
void log_enable(char *name, const char *key, struct chatlog *log);
|
||||
void log_enable(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype);
|
||||
|
||||
/* disables logging for specified log and closes file */
|
||||
void log_disable(struct chatlog *log);
|
||||
|
||||
#endif /* #define _log_h */
|
||||
/* Loads previous history from chat log */
|
||||
void load_chat_history(ToxWindow *self, struct chatlog *log);
|
||||
|
||||
/* renames chatlog file replacing src with dest.
|
||||
Returns 0 on success or if no log exists, -1 on failure. */
|
||||
int rename_logfile(char *src, char *dest, const char *selfkey, const char *otherkey, int winnum);
|
||||
|
||||
#endif /* #define LOG_H */
|
||||
|
||||
156
src/message_queue.c
Normal file
156
src/message_queue.c
Normal file
@@ -0,0 +1,156 @@
|
||||
/* message_queue.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 <stdlib.h>
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
#include "message_queue.h"
|
||||
#include "misc_tools.h"
|
||||
#include "line_info.h"
|
||||
#include "log.h"
|
||||
|
||||
void cqueue_cleanup(struct chat_queue *q)
|
||||
{
|
||||
struct cqueue_msg *tmp1 = q->root;
|
||||
|
||||
while (tmp1) {
|
||||
struct cqueue_msg *tmp2 = tmp1->next;
|
||||
free(tmp1);
|
||||
tmp1 = tmp2;
|
||||
}
|
||||
|
||||
free(q);
|
||||
}
|
||||
|
||||
void cqueue_add(struct chat_queue *q, const char *msg, int len, uint8_t type, uint32_t line_id)
|
||||
{
|
||||
struct cqueue_msg *new_m = malloc(sizeof(struct cqueue_msg));
|
||||
|
||||
if (new_m == NULL)
|
||||
exit_toxic_err("failed in cqueue_message", FATALERR_MEMORY);
|
||||
|
||||
snprintf(new_m->message, sizeof(new_m->message), "%s", msg);
|
||||
new_m->len = len;
|
||||
new_m->type = type;
|
||||
new_m->line_id = line_id;
|
||||
new_m->last_send_try = 0;
|
||||
new_m->receipt = 0;
|
||||
new_m->next = NULL;
|
||||
|
||||
if (q->root == NULL) {
|
||||
new_m->prev = NULL;
|
||||
q->root = new_m;
|
||||
} else {
|
||||
new_m->prev = q->end;
|
||||
q->end->next = new_m;
|
||||
}
|
||||
|
||||
q->end = new_m;
|
||||
}
|
||||
|
||||
/* update line to show receipt was received after queue removal */
|
||||
static void cqueue_mark_read(ToxWindow *self, struct cqueue_msg *msg)
|
||||
{
|
||||
struct line_info *line = self->chatwin->hst->line_end;
|
||||
|
||||
while (line) {
|
||||
if (line->id != msg->line_id) {
|
||||
line = line->prev;
|
||||
continue;
|
||||
}
|
||||
|
||||
line->type = msg->type == OUT_ACTION ? OUT_ACTION_READ : OUT_MSG_READ;
|
||||
|
||||
if (line->noread_flag == true) {
|
||||
line->len -= 2;
|
||||
line->noread_flag = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
struct chat_queue *q = self->chatwin->cqueue;
|
||||
struct cqueue_msg *msg = q->root;
|
||||
|
||||
while (msg) {
|
||||
if (msg->receipt != receipt) {
|
||||
msg = msg->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
char selfname[TOX_MAX_NAME_LENGTH];
|
||||
uint16_t len = tox_get_self_name(m, (uint8_t *) selfname);
|
||||
selfname[len] = '\0';
|
||||
|
||||
write_to_log(msg->message, selfname, self->chatwin->log, msg->type == OUT_ACTION);
|
||||
cqueue_mark_read(self, msg);
|
||||
|
||||
struct cqueue_msg *next = msg->next;
|
||||
|
||||
if (msg->prev == NULL) { /* root */
|
||||
if (next)
|
||||
next->prev = NULL;
|
||||
|
||||
free(msg);
|
||||
q->root = next;
|
||||
} else {
|
||||
struct cqueue_msg *prev = msg->prev;
|
||||
free(msg);
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#define CQUEUE_TRY_SEND_INTERVAL 10
|
||||
|
||||
/* Tries to send the oldest unsent message in queue. */
|
||||
void cqueue_try_send(ToxWindow *self, Tox *m)
|
||||
{
|
||||
struct chat_queue *q = self->chatwin->cqueue;
|
||||
struct cqueue_msg *msg = q->root;
|
||||
uint64_t curtime = get_unix_time();
|
||||
|
||||
while (msg) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
51
src/message_queue.h
Normal file
51
src/message_queue.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/* message_queue.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 MESSAGE_QUEUE_H
|
||||
#define MESSAGE_QUEUE_H
|
||||
|
||||
struct cqueue_msg {
|
||||
char message[MAX_STR_SIZE];
|
||||
int len;
|
||||
int line_id;
|
||||
uint8_t type;
|
||||
uint32_t receipt;
|
||||
uint64_t last_send_try;
|
||||
struct cqueue_msg *next;
|
||||
struct cqueue_msg *prev;
|
||||
};
|
||||
|
||||
struct chat_queue {
|
||||
struct cqueue_msg *root;
|
||||
struct cqueue_msg *end;
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
/* Tries to send the oldest unsent message in queue. */
|
||||
void cqueue_try_send(ToxWindow *self, Tox *m);
|
||||
|
||||
/* removes message with matching receipt from queue, writes to log and updates line to show the message was received. */
|
||||
void cqueue_remove(ToxWindow *self, Tox *m, uint32_t receipt);
|
||||
|
||||
#endif /* #define MESSAGE_QUEUE_H */
|
||||
@@ -35,7 +35,7 @@
|
||||
#include "file_senders.h"
|
||||
|
||||
extern ToxWindow *prompt;
|
||||
extern struct user_settings *user_settings_;
|
||||
extern struct user_settings *user_settings;
|
||||
|
||||
static uint64_t current_unix_time;
|
||||
|
||||
@@ -82,12 +82,12 @@ struct tm *get_time(void)
|
||||
/*Puts the current time in buf in the format of [HH:mm:ss] */
|
||||
void get_time_str(char *buf, int bufsize)
|
||||
{
|
||||
if (user_settings_->timestamps == TIMESTAMPS_OFF) {
|
||||
if (user_settings->timestamps == TIMESTAMPS_OFF) {
|
||||
buf[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
const char *t = user_settings_->time == TIME_12 ? "[%-I:%M:%S] " : "[%H:%M:%S] ";
|
||||
const char *t = user_settings->time == TIME_12 ? "%I:%M:%S " : "%H:%M:%S ";
|
||||
strftime(buf, bufsize, t, get_time());
|
||||
}
|
||||
|
||||
@@ -306,8 +306,38 @@ void bytes_convert_str(char *buf, int size, uint64_t bytes)
|
||||
}
|
||||
|
||||
/* checks if a file exists. Returns true or false */
|
||||
bool file_exists(const char *fp)
|
||||
bool file_exists(const char *path)
|
||||
{
|
||||
struct stat s;
|
||||
return stat(fp, &s) == 0;
|
||||
return stat(path, &s) == 0;
|
||||
}
|
||||
|
||||
/* returns file size or -1 on error */
|
||||
off_t file_size(const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (stat(path, &st) == -1)
|
||||
return -1;
|
||||
|
||||
return st.st_size;
|
||||
}
|
||||
|
||||
/* compares the first size bytes of fp to signature.
|
||||
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 */
|
||||
int check_file_signature(const char *signature, size_t size, FILE *fp)
|
||||
{
|
||||
char buf[size];
|
||||
|
||||
if (fread(buf, size, 1, fp) != 1)
|
||||
return -1;
|
||||
|
||||
int ret = memcmp(signature, buf, size);
|
||||
|
||||
if (fseek(fp, 0L, SEEK_SET) == -1)
|
||||
return -1;
|
||||
|
||||
return ret == 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
@@ -19,8 +19,10 @@
|
||||
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#ifndef _misc_tools_h
|
||||
#define _misc_tools_h
|
||||
#ifndef MISC_TOOLS_H
|
||||
#define MISC_TOOLS_H
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "windows.h"
|
||||
#include "toxic.h"
|
||||
@@ -110,6 +112,15 @@ int char_rfind(const char *s, char ch, int len);
|
||||
void bytes_convert_str(char *buf, int size, uint64_t bytes);
|
||||
|
||||
/* checks if a file exists. Returns true or false */
|
||||
bool file_exists(const char *fp);
|
||||
bool file_exists(const char *path);
|
||||
|
||||
#endif /* #define _misc_tools_h */
|
||||
/* returns file size or -1 on error */
|
||||
off_t file_size(const char *path);
|
||||
|
||||
/* compares the first size bytes of fp and signature.
|
||||
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 */
|
||||
int check_file_signature(const char *signature, size_t size, FILE *fp);
|
||||
|
||||
#endif /* #define MISC_TOOLS_H */
|
||||
|
||||
385
src/notify.c
385
src/notify.c
@@ -20,21 +20,23 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "notify.h"
|
||||
#include "device.h"
|
||||
#include "settings.h"
|
||||
#include "line_info.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if defined(_AUDIO) || defined(_SOUND_NOTIFY)
|
||||
#include "notify.h"
|
||||
#include "device.h"
|
||||
#include "settings.h"
|
||||
#include "line_info.h"
|
||||
#include "misc_tools.h"
|
||||
|
||||
#if defined(AUDIO) || defined(SOUND_NOTIFY)
|
||||
#ifdef __APPLE__
|
||||
#include <OpenAL/al.h>
|
||||
#include <OpenAL/alc.h>
|
||||
@@ -46,54 +48,55 @@
|
||||
#include <AL/alext.h>
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _SOUND_NOTIFY
|
||||
#ifdef SOUND_NOTIFY
|
||||
#include <AL/alut.h> /* freealut packet */
|
||||
#endif
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
|
||||
#ifdef _X11
|
||||
#ifdef X11
|
||||
#include <X11/Xlib.h>
|
||||
#endif /* _X11 */
|
||||
#endif /* X11 */
|
||||
|
||||
#ifdef _BOX_NOTIFY
|
||||
#ifdef BOX_NOTIFY
|
||||
#include <libnotify/notify.h>
|
||||
#endif
|
||||
|
||||
#define MAX_BOX_MSG_LEN 127
|
||||
#define SOUNDS_SIZE 10
|
||||
#define ACTIVE_NOTIFS_MAX 50
|
||||
|
||||
extern struct user_settings *user_settings_;
|
||||
extern struct user_settings *user_settings;
|
||||
|
||||
struct _Control {
|
||||
struct Control {
|
||||
time_t cooldown;
|
||||
time_t notif_timeout;
|
||||
unsigned long this_window;
|
||||
#ifdef _X11
|
||||
#ifdef X11
|
||||
Display *display;
|
||||
#endif /* _X11 */
|
||||
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];
|
||||
_Bool poll_active;
|
||||
bool poll_active;
|
||||
#endif
|
||||
|
||||
#ifdef _SOUND_NOTIFY
|
||||
#ifdef SOUND_NOTIFY
|
||||
uint32_t device_idx; /* index of output device */
|
||||
char* sounds[SOUNDS_SIZE];
|
||||
#endif /* _SOUND_NOTIFY */
|
||||
#endif /* SOUND_NOTIFY */
|
||||
} Control = {0};
|
||||
|
||||
struct _ActiveNotifications {
|
||||
#ifdef _SOUND_NOTIFY
|
||||
#ifdef SOUND_NOTIFY
|
||||
uint32_t source;
|
||||
uint32_t buffer;
|
||||
_Bool looping;
|
||||
bool looping;
|
||||
#endif
|
||||
_Bool active;
|
||||
bool active;
|
||||
int *id_indicator;
|
||||
#ifdef _BOX_NOTIFY
|
||||
#ifdef BOX_NOTIFY
|
||||
NotifyNotification* box;
|
||||
char messages[128][128];
|
||||
char messages[MAX_BOX_MSG_LEN + 1][MAX_BOX_MSG_LEN + 1];
|
||||
char title[24];
|
||||
size_t size;
|
||||
time_t n_timeout;
|
||||
@@ -105,43 +108,92 @@ struct _ActiveNotifications {
|
||||
/**********************************************************************************/
|
||||
/**********************************************************************************/
|
||||
|
||||
/* coloured tab notifications: primary notification type */
|
||||
static void tab_notify(ToxWindow *self, uint64_t flags)
|
||||
{
|
||||
if (self == NULL)
|
||||
return;
|
||||
|
||||
if (flags & NT_WNDALERT_0)
|
||||
self->alert = WINDOW_ALERT_0;
|
||||
else if ( (flags & NT_WNDALERT_1) && (!self->alert || self->alert > WINDOW_ALERT_0) )
|
||||
self->alert = WINDOW_ALERT_1;
|
||||
else if ( (flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1) )
|
||||
self->alert = WINDOW_ALERT_2;
|
||||
}
|
||||
|
||||
#ifdef X11
|
||||
long unsigned int get_focused_window_id()
|
||||
{
|
||||
#ifdef _X11
|
||||
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)
|
||||
{
|
||||
bool res = flags & NT_RESTOL && Control.cooldown > get_unix_time();
|
||||
#ifdef X11
|
||||
return res || (flags & NT_NOFOCUS && Control.this_window == get_focused_window_id());
|
||||
#else
|
||||
return 0;
|
||||
#endif /* _X11 */
|
||||
return res;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void control_lock()
|
||||
{
|
||||
#if defined(_SOUND_NOTIFY) || defined(_BOX_NOTIFY)
|
||||
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
||||
pthread_mutex_lock(Control.poll_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void control_unlock()
|
||||
{
|
||||
#if defined(_SOUND_NOTIFY) || defined(_BOX_NOTIFY)
|
||||
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
||||
pthread_mutex_unlock(Control.poll_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _SOUND_NOTIFY
|
||||
_Bool is_playing(int source)
|
||||
#ifdef SOUND_NOTIFY
|
||||
bool is_playing(int source)
|
||||
{
|
||||
int ready;
|
||||
alGetSourcei(source, AL_SOURCE_STATE, &ready);
|
||||
return ready == AL_PLAYING;
|
||||
}
|
||||
|
||||
/* Terminate all sounds but wait them to finish first */
|
||||
/* TODO maybe find better way to do this */
|
||||
/* cooldown is in seconds */
|
||||
#define DEVICE_COOLDOWN 5 /* TODO perhaps load this from config? */
|
||||
static bool device_opened = false;
|
||||
time_t last_opened_update = 0;
|
||||
|
||||
bool m_open_device()
|
||||
{
|
||||
last_opened_update = time(NULL);
|
||||
|
||||
if (device_opened) return true;
|
||||
|
||||
/* Blah error check */
|
||||
open_primary_device(output, &Control.device_idx, 48000, 20, 1);
|
||||
|
||||
return (device_opened = true);
|
||||
}
|
||||
|
||||
bool m_close_device()
|
||||
{
|
||||
if (!device_opened) return true;
|
||||
|
||||
close_device(output, Control.device_idx);
|
||||
|
||||
return !(device_opened = false);
|
||||
}
|
||||
|
||||
/* Terminate all sounds but wait for them to finish first */
|
||||
void graceful_clear()
|
||||
{
|
||||
int i;
|
||||
@@ -149,7 +201,7 @@ void graceful_clear()
|
||||
while (1) {
|
||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
||||
if (actives[i].active) {
|
||||
#ifdef _BOX_NOTIFY
|
||||
#ifdef BOX_NOTIFY
|
||||
if (actives[i].box) {
|
||||
GError* ignore;
|
||||
notify_notification_close(actives[i].box, &ignore);
|
||||
@@ -167,10 +219,10 @@ void graceful_clear()
|
||||
else break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (i == ACTIVE_NOTIFS_MAX) {
|
||||
m_close_device(); /* In case it's opened */
|
||||
control_unlock();
|
||||
return;
|
||||
}
|
||||
@@ -183,11 +235,19 @@ void* do_playing(void* _p)
|
||||
{
|
||||
(void)_p;
|
||||
int i;
|
||||
|
||||
bool has_looping = false;
|
||||
|
||||
while(Control.poll_active) {
|
||||
control_lock();
|
||||
|
||||
|
||||
for (i = 0; i < ACTIVE_NOTIFS_MAX; i ++) {
|
||||
|
||||
if (actives[i].looping) has_looping = true;
|
||||
|
||||
if (actives[i].active && !actives[i].looping
|
||||
#ifdef _BOX_NOTIFY
|
||||
#ifdef BOX_NOTIFY
|
||||
&& !actives[i].box
|
||||
#endif
|
||||
) {
|
||||
@@ -199,7 +259,7 @@ void* do_playing(void* _p)
|
||||
memset(&actives[i], 0, sizeof(struct _ActiveNotifications));
|
||||
}
|
||||
}
|
||||
#ifdef _BOX_NOTIFY
|
||||
#ifdef BOX_NOTIFY
|
||||
else if (actives[i].box && time(NULL) >= actives[i].n_timeout)
|
||||
{
|
||||
GError* ignore;
|
||||
@@ -218,13 +278,21 @@ void* do_playing(void* _p)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* device is opened and no activity in under DEVICE_COOLDOWN time, close device*/
|
||||
if (device_opened && !has_looping &&
|
||||
(time(NULL) - last_opened_update) > DEVICE_COOLDOWN) {
|
||||
m_close_device();
|
||||
}
|
||||
has_looping = false;
|
||||
|
||||
control_unlock();
|
||||
usleep(10000);
|
||||
}
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
int play_source(uint32_t source, uint32_t buffer, _Bool looping)
|
||||
int play_source(uint32_t source, uint32_t buffer, bool looping)
|
||||
{
|
||||
int i = 0;
|
||||
for (; i < ACTIVE_NOTIFS_MAX && actives[i].active; i ++);
|
||||
@@ -242,7 +310,7 @@ int play_source(uint32_t source, uint32_t buffer, _Bool looping)
|
||||
return i;
|
||||
}
|
||||
|
||||
#elif _BOX_NOTIFY
|
||||
#elif BOX_NOTIFY
|
||||
void* do_playing(void* _p)
|
||||
{
|
||||
(void)_p;
|
||||
@@ -297,15 +365,16 @@ void graceful_clear()
|
||||
/* Opens primary device */
|
||||
int init_notify(int login_cooldown, int notification_timeout)
|
||||
{
|
||||
#ifdef _SOUND_NOTIFY
|
||||
#ifdef SOUND_NOTIFY
|
||||
alutInitWithoutContext(NULL, NULL);
|
||||
if (open_primary_device(output, &Control.device_idx, 48000, 20, 1) != de_None)
|
||||
return -1;
|
||||
#endif /* _SOUND_NOTIFY */
|
||||
#endif /* SOUND_NOTIFY */
|
||||
|
||||
#if defined(_SOUND_NOTIFY) || defined(_BOX_NOTIFY)
|
||||
pthread_mutex_init(Control.poll_mutex, NULL);
|
||||
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
||||
if (pthread_mutex_init(Control.poll_mutex, NULL) != 0)
|
||||
return -1;
|
||||
|
||||
pthread_t thread;
|
||||
|
||||
if (pthread_create(&thread, NULL, do_playing, NULL) != 0 || pthread_detach(thread) != 0 ) {
|
||||
pthread_mutex_destroy(Control.poll_mutex);
|
||||
return -1;
|
||||
@@ -314,15 +383,13 @@ int init_notify(int login_cooldown, int notification_timeout)
|
||||
#endif
|
||||
|
||||
Control.cooldown = time(NULL) + login_cooldown;
|
||||
#ifdef _X11
|
||||
#ifdef X11
|
||||
Control.display = XOpenDisplay(NULL);
|
||||
Control.this_window = get_focused_window_id();
|
||||
#else
|
||||
Control.this_window = 1;
|
||||
#endif /* _X11 */
|
||||
#endif /* X11 */
|
||||
|
||||
|
||||
#ifdef _BOX_NOTIFY
|
||||
#ifdef BOX_NOTIFY
|
||||
notify_init("toxic");
|
||||
#endif
|
||||
Control.notif_timeout = notification_timeout;
|
||||
@@ -331,26 +398,25 @@ int init_notify(int login_cooldown, int notification_timeout)
|
||||
|
||||
void terminate_notify()
|
||||
{
|
||||
#if defined(_SOUND_NOTIFY) || defined(_BOX_NOTIFY)
|
||||
#if defined(SOUND_NOTIFY) || defined(BOX_NOTIFY)
|
||||
if ( !Control.poll_active ) return;
|
||||
Control.poll_active = 0;
|
||||
|
||||
graceful_clear();
|
||||
#endif
|
||||
|
||||
#ifdef _SOUND_NOTIFY
|
||||
#ifdef SOUND_NOTIFY
|
||||
int i = 0;
|
||||
for (; i < SOUNDS_SIZE; i ++) free(Control.sounds[i]);
|
||||
close_device(output, Control.device_idx);
|
||||
alutExit();
|
||||
#endif /* _SOUND_NOTIFY */
|
||||
#endif /* SOUND_NOTIFY */
|
||||
|
||||
#ifdef _BOX_NOTIFY
|
||||
#ifdef BOX_NOTIFY
|
||||
notify_uninit();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _SOUND_NOTIFY
|
||||
#ifdef SOUND_NOTIFY
|
||||
int set_sound(Notification sound, const char* value)
|
||||
{
|
||||
if (sound == silent) return 0;
|
||||
@@ -365,11 +431,13 @@ int set_sound(Notification sound, const char* value)
|
||||
return stat(value, &buf) == 0;
|
||||
}
|
||||
|
||||
int play_sound_internal(Notification what, _Bool loop)
|
||||
int play_sound_internal(Notification what, bool loop)
|
||||
{
|
||||
uint32_t source;
|
||||
uint32_t buffer;
|
||||
|
||||
m_open_device();
|
||||
|
||||
alGenSources(1, &source);
|
||||
alGenBuffers(1, &buffer);
|
||||
buffer = alutCreateBufferFromFile(Control.sounds[what]);
|
||||
@@ -406,7 +474,7 @@ int play_notify_sound(Notification notif, uint64_t flags)
|
||||
void stop_sound(int id)
|
||||
{
|
||||
if (id >= 0 && id < ACTIVE_NOTIFS_MAX && actives[id].looping && actives[id].active ) {
|
||||
#ifdef _BOX_NOTIFY
|
||||
#ifdef BOX_NOTIFY
|
||||
if (actives[id].box) {
|
||||
GError* ignore;
|
||||
notify_notification_close(actives[id].box, &ignore);
|
||||
@@ -424,17 +492,17 @@ void stop_sound(int id)
|
||||
|
||||
static int m_play_sound(Notification notif, uint64_t flags)
|
||||
{
|
||||
#ifdef _SOUND_NOTIFY
|
||||
#ifdef SOUND_NOTIFY
|
||||
return play_notify_sound(notif, flags);
|
||||
#else
|
||||
if (notif != silent)
|
||||
beep();
|
||||
|
||||
return -1;
|
||||
#endif /* _SOUND_NOTIFY */
|
||||
#endif /* SOUND_NOTIFY */
|
||||
}
|
||||
|
||||
#ifdef _BOX_NOTIFY
|
||||
#ifdef BOX_NOTIFY
|
||||
void m_notify_action(NotifyNotification *box, char *action, void* data)
|
||||
{
|
||||
}
|
||||
@@ -442,27 +510,21 @@ void m_notify_action(NotifyNotification *box, char *action, void* data)
|
||||
|
||||
int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator)
|
||||
{
|
||||
/* Consider colored notify as primary */
|
||||
if (self) {
|
||||
if (flags & NT_WNDALERT_0) self->alert = WINDOW_ALERT_0;
|
||||
else if ( (flags & NT_WNDALERT_1) && (!self->alert || self->alert > WINDOW_ALERT_0) ) self->alert = WINDOW_ALERT_1;
|
||||
else if ( (flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1) ) self->alert = WINDOW_ALERT_2;
|
||||
}
|
||||
|
||||
if ((flags & NT_RESTOL && Control.cooldown > time(NULL)) ||
|
||||
((flags & NT_NOFOCUS && Control.this_window == get_focused_window_id()) ))
|
||||
tab_notify(self, flags);
|
||||
|
||||
if (notifications_are_disabled(flags))
|
||||
return -1;
|
||||
|
||||
int id = -1;
|
||||
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_USERSTATUS_BUSY) && user_settings->alerts == ALERTS_ENABLED)
|
||||
id = m_play_sound(notif, flags);
|
||||
|
||||
else if (flags & NT_ALWAYS)
|
||||
id = m_play_sound(notif, flags);
|
||||
|
||||
#if defined(_BOX_NOTIFY) && !defined(_SOUND_NOTIFY)
|
||||
#if defined(BOX_NOTIFY) && !defined(SOUND_NOTIFY)
|
||||
|
||||
if (id == -1) {
|
||||
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].box; id ++);
|
||||
@@ -486,19 +548,13 @@ int sound_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_in
|
||||
|
||||
int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
|
||||
{
|
||||
/* Consider colored notify as primary */
|
||||
if (self) {
|
||||
if (flags & NT_WNDALERT_0) self->alert = WINDOW_ALERT_0;
|
||||
else if ( (flags & NT_WNDALERT_1) && (!self->alert || self->alert > WINDOW_ALERT_0) ) self->alert = WINDOW_ALERT_1;
|
||||
else if ( (flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1) ) self->alert = WINDOW_ALERT_2;
|
||||
}
|
||||
tab_notify(self, flags);
|
||||
|
||||
if ((flags & NT_RESTOL && Control.cooldown > time(NULL)) ||
|
||||
((flags & NT_NOFOCUS && Control.this_window == get_focused_window_id()) ))
|
||||
if (notifications_are_disabled(flags))
|
||||
return -1;
|
||||
|
||||
if (id < 0 || id >= ACTIVE_NOTIFS_MAX) return -1;
|
||||
#ifdef _SOUND_NOTIFY
|
||||
#ifdef SOUND_NOTIFY
|
||||
control_lock();
|
||||
|
||||
if (!actives[id].active || !Control.sounds[notif]) {
|
||||
@@ -506,6 +562,8 @@ int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
|
||||
return -1;
|
||||
}
|
||||
|
||||
m_open_device();
|
||||
|
||||
alSourceStop(actives[id].source);
|
||||
alDeleteSources(1, &actives[id].source);
|
||||
alDeleteBuffers(1,&actives[id].buffer);
|
||||
@@ -527,46 +585,47 @@ int sound_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id)
|
||||
beep();
|
||||
|
||||
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, ...)
|
||||
{
|
||||
if ((flags & NT_RESTOL && Control.cooldown > time(NULL)) ||
|
||||
((flags & NT_NOFOCUS && Control.this_window == get_focused_window_id()) ))
|
||||
if (notifications_are_disabled(flags)) {
|
||||
tab_notify(self, flags);
|
||||
return -1;
|
||||
|
||||
#ifdef _BOX_NOTIFY
|
||||
|
||||
}
|
||||
|
||||
#ifdef BOX_NOTIFY
|
||||
|
||||
int id = sound_notify(self, notif, flags, id_indicator);
|
||||
|
||||
|
||||
control_lock();
|
||||
|
||||
#ifdef _SOUND_NOTIFY
|
||||
|
||||
#ifdef SOUND_NOTIFY
|
||||
if (id == -1) { /* Could not play */
|
||||
|
||||
|
||||
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++);
|
||||
if ( id == ACTIVE_NOTIFS_MAX ) {
|
||||
control_unlock();
|
||||
return -1; /* Full */
|
||||
}
|
||||
|
||||
|
||||
actives[id].active = 1;
|
||||
actives[id].id_indicator = id_indicator;
|
||||
if (id_indicator) *id_indicator = id;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
strncpy(actives[id].title, title, 24);
|
||||
if (strlen(title) > 23) strcpy(actives[id].title + 20, "...");
|
||||
|
||||
va_list __ARGS__; va_start (__ARGS__, format);
|
||||
vsnprintf (actives[id].messages[0], 127, format, __ARGS__);
|
||||
vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
|
||||
va_end (__ARGS__);
|
||||
|
||||
if (strlen(actives[id].messages[0]) > 124)
|
||||
strcpy(actives[id].messages[0] + 124, "...");
|
||||
|
||||
|
||||
if (strlen(actives[id].messages[0]) > MAX_BOX_MSG_LEN - 3)
|
||||
strcpy(actives[id].messages[0] + MAX_BOX_MSG_LEN - 3, "...");
|
||||
|
||||
actives[id].box = notify_notification_new(actives[id].title, actives[id].messages[0], NULL);
|
||||
actives[id].size ++;
|
||||
actives[id].n_timeout = time(NULL) + Control.notif_timeout / 1000;
|
||||
@@ -575,7 +634,7 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi
|
||||
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_show(actives[id].box, NULL);
|
||||
|
||||
|
||||
control_unlock();
|
||||
return id;
|
||||
#else
|
||||
@@ -585,48 +644,48 @@ int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indi
|
||||
|
||||
int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, const char* format, ...)
|
||||
{
|
||||
if ((flags & NT_RESTOL && Control.cooldown > time(NULL)) ||
|
||||
((flags & NT_NOFOCUS && Control.this_window == get_focused_window_id()) ))
|
||||
if (notifications_are_disabled(flags)) {
|
||||
tab_notify(self, flags);
|
||||
return -1;
|
||||
|
||||
#ifdef _BOX_NOTIFY
|
||||
|
||||
}
|
||||
|
||||
#ifdef BOX_NOTIFY
|
||||
|
||||
if (sound_notify2(self, notif, flags, id) == -1)
|
||||
return -1;
|
||||
|
||||
|
||||
control_lock();
|
||||
|
||||
if (!actives[id].box || actives[id].size >= 128 ) {
|
||||
|
||||
if (!actives[id].box || actives[id].size >= MAX_BOX_MSG_LEN + 1) {
|
||||
control_unlock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
va_list __ARGS__; va_start (__ARGS__, format);
|
||||
vsnprintf (actives[id].messages[actives[id].size], 127, format, __ARGS__);
|
||||
vsnprintf (actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __ARGS__);
|
||||
va_end (__ARGS__);
|
||||
|
||||
if (strlen(actives[id].messages[actives[id].size]) > 124)
|
||||
strcpy(actives[id].messages[actives[id].size] + 124, "...");
|
||||
|
||||
|
||||
if (strlen(actives[id].messages[actives[id].size]) > MAX_BOX_MSG_LEN - 3)
|
||||
strcpy(actives[id].messages[actives[id].size] + MAX_BOX_MSG_LEN - 3, "...");
|
||||
|
||||
actives[id].size ++;
|
||||
actives[id].n_timeout = time(NULL) + Control.notif_timeout / 1000;
|
||||
|
||||
|
||||
char formated[128 * 129] = {'\0'};
|
||||
|
||||
|
||||
int i = 0;
|
||||
for (; i <actives[id].size; i ++) {
|
||||
strcat(formated, actives[id].messages[i]);
|
||||
strcat(formated, "\n");
|
||||
}
|
||||
|
||||
|
||||
formated[strlen(formated) - 1] = '\0';
|
||||
|
||||
|
||||
notify_notification_update(actives[id].box, actives[id].title, formated, NULL);
|
||||
notify_notification_show(actives[id].box, NULL);
|
||||
|
||||
|
||||
control_unlock();
|
||||
|
||||
|
||||
return id;
|
||||
#else
|
||||
return sound_notify2(self, notif, flags, id);
|
||||
@@ -635,53 +694,47 @@ int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, con
|
||||
|
||||
int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const char* title, const char* format, ...)
|
||||
{
|
||||
/* Always do colored notify */
|
||||
if (self) {
|
||||
if (flags & NT_WNDALERT_0) self->alert = WINDOW_ALERT_0;
|
||||
else if ( (flags & NT_WNDALERT_1) && (!self->alert || self->alert > WINDOW_ALERT_0) ) self->alert = WINDOW_ALERT_1;
|
||||
else if ( (flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1) ) self->alert = WINDOW_ALERT_2;
|
||||
}
|
||||
|
||||
if ((flags & NT_RESTOL && Control.cooldown > time(NULL)) ||
|
||||
((flags & NT_NOFOCUS && Control.this_window == get_focused_window_id()) ))
|
||||
tab_notify(self, flags);
|
||||
|
||||
if (notifications_are_disabled(flags))
|
||||
return -1;
|
||||
|
||||
#ifdef _BOX_NOTIFY
|
||||
|
||||
|
||||
#ifdef BOX_NOTIFY
|
||||
|
||||
control_lock();
|
||||
|
||||
|
||||
int id;
|
||||
for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++);
|
||||
if ( id == ACTIVE_NOTIFS_MAX ) {
|
||||
control_unlock();
|
||||
return -1; /* Full */
|
||||
}
|
||||
|
||||
|
||||
if (id_indicator) {
|
||||
actives[id].id_indicator = id_indicator;
|
||||
*id_indicator = id;
|
||||
}
|
||||
|
||||
|
||||
strncpy(actives[id].title, title, 24);
|
||||
if (strlen(title) > 23) strcpy(actives[id].title + 20, "...");
|
||||
|
||||
|
||||
va_list __ARGS__; va_start (__ARGS__, format);
|
||||
vsnprintf (actives[id].messages[0], 127, format, __ARGS__);
|
||||
vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
|
||||
va_end (__ARGS__);
|
||||
|
||||
if (strlen(actives[id].messages[0]) > 124)
|
||||
strcpy(actives[id].messages[0] + 124, "...");
|
||||
|
||||
|
||||
if (strlen(actives[id].messages[0]) > MAX_BOX_MSG_LEN - 3)
|
||||
strcpy(actives[id].messages[0] + MAX_BOX_MSG_LEN - 3, "...");
|
||||
|
||||
actives[id].active = 1;
|
||||
actives[id].box = notify_notification_new(actives[id].title, actives[id].messages[0], NULL);
|
||||
actives[id].size ++;
|
||||
actives[id].n_timeout = time(NULL) + Control.notif_timeout / 1000;
|
||||
|
||||
|
||||
notify_notification_set_timeout(actives[id].box, Control.notif_timeout);
|
||||
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_show(actives[id].box, NULL);
|
||||
|
||||
|
||||
control_unlock();
|
||||
return id;
|
||||
#else
|
||||
@@ -691,51 +744,45 @@ int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const
|
||||
|
||||
int box_silent_notify2(ToxWindow* self, uint64_t flags, int id, const char* format, ...)
|
||||
{
|
||||
/* Always do colored notify */
|
||||
if (self) {
|
||||
if (flags & NT_WNDALERT_0) self->alert = WINDOW_ALERT_0;
|
||||
else if ( (flags & NT_WNDALERT_1) && (!self->alert || self->alert > WINDOW_ALERT_0) ) self->alert = WINDOW_ALERT_1;
|
||||
else if ( (flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1) ) self->alert = WINDOW_ALERT_2;
|
||||
}
|
||||
|
||||
if ((flags & NT_RESTOL && Control.cooldown > time(NULL)) ||
|
||||
((flags & NT_NOFOCUS && Control.this_window == get_focused_window_id()) ))
|
||||
tab_notify(self, flags);
|
||||
|
||||
if (notifications_are_disabled(flags))
|
||||
return -1;
|
||||
|
||||
#ifdef _BOX_NOTIFY
|
||||
|
||||
#ifdef BOX_NOTIFY
|
||||
control_lock();
|
||||
|
||||
if (id < 0 || id >= ACTIVE_NOTIFS_MAX || !actives[id].box || actives[id].size >= 128 ) {
|
||||
|
||||
if (id < 0 || id >= ACTIVE_NOTIFS_MAX || !actives[id].box || actives[id].size >= MAX_BOX_MSG_LEN + 1 ) {
|
||||
control_unlock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
va_list __ARGS__; va_start (__ARGS__, format);
|
||||
vsnprintf (actives[id].messages[actives[id].size], 127, format, __ARGS__);
|
||||
vsnprintf (actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __ARGS__);
|
||||
va_end (__ARGS__);
|
||||
|
||||
if (strlen(actives[id].messages[actives[id].size]) > 124)
|
||||
strcpy(actives[id].messages[actives[id].size] + 124, "...");
|
||||
|
||||
|
||||
if (strlen(actives[id].messages[actives[id].size]) > MAX_BOX_MSG_LEN - 3)
|
||||
strcpy(actives[id].messages[actives[id].size] + MAX_BOX_MSG_LEN - 3, "...");
|
||||
|
||||
actives[id].size ++;
|
||||
actives[id].n_timeout = time(NULL) + Control.notif_timeout / 1000;
|
||||
|
||||
|
||||
char formated[128 * 129] = {'\0'};
|
||||
|
||||
|
||||
int i = 0;
|
||||
for (; i <actives[id].size; i ++) {
|
||||
strcat(formated, actives[id].messages[i]);
|
||||
strcat(formated, "\n");
|
||||
}
|
||||
|
||||
|
||||
formated[strlen(formated) - 1] = '\0';
|
||||
|
||||
|
||||
notify_notification_update(actives[id].box, actives[id].title, formated, NULL);
|
||||
notify_notification_show(actives[id].box, NULL);
|
||||
|
||||
|
||||
control_unlock();
|
||||
|
||||
|
||||
return id;
|
||||
#else
|
||||
return -1;
|
||||
|
||||
10
src/notify.h
10
src/notify.h
@@ -20,8 +20,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _notify_h
|
||||
#define _notify_h
|
||||
#ifndef NOTIFY_H
|
||||
#define NOTIFY_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "windows.h"
|
||||
@@ -73,8 +73,8 @@ int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, con
|
||||
int box_silent_notify(ToxWindow* self, uint64_t flags, int* id_indicator, const char* title, const char* format, ...);
|
||||
int box_silent_notify2(ToxWindow* self, uint64_t flags, int id, const char* format, ...);
|
||||
|
||||
#ifdef _SOUND_NOTIFY
|
||||
#ifdef SOUND_NOTIFY
|
||||
int set_sound(Notification sound, const char* value);
|
||||
#endif /* _SOUND_NOTIFY */
|
||||
#endif /* SOUND_NOTIFY */
|
||||
|
||||
#endif /* _notify_h */
|
||||
#endif /* NOTIFY_H */
|
||||
|
||||
48
src/prompt.c
48
src/prompt.c
@@ -43,15 +43,16 @@
|
||||
#include "autocomplete.h"
|
||||
|
||||
extern ToxWindow *prompt;
|
||||
extern struct user_settings *user_settings_;
|
||||
extern struct _Winthread Winthread;
|
||||
extern struct user_settings *user_settings;
|
||||
extern struct Winthread Winthread;
|
||||
|
||||
_FriendRequests FriendRequests;
|
||||
FriendRequests FrndRequests;
|
||||
|
||||
/* Array of global command names used for tab completion. */
|
||||
const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
|
||||
{ "/accept" },
|
||||
{ "/add" },
|
||||
{ "/avatar" },
|
||||
{ "/clear" },
|
||||
{ "/close" }, /* rm /close when groupchats gets its own list */
|
||||
{ "/connect" },
|
||||
@@ -67,12 +68,12 @@ const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
|
||||
{ "/requests" },
|
||||
{ "/status" },
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
|
||||
{ "/lsdev" },
|
||||
{ "/sdev" },
|
||||
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
};
|
||||
|
||||
void kill_prompt_window(ToxWindow *self)
|
||||
@@ -88,7 +89,6 @@ void kill_prompt_window(ToxWindow *self)
|
||||
delwin(statusbar->topline);
|
||||
|
||||
free(ctx->log);
|
||||
free(ctx->hst);
|
||||
free(ctx);
|
||||
free(self->help);
|
||||
free(statusbar);
|
||||
@@ -132,21 +132,21 @@ void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected)
|
||||
Returns request number on success, -1 if queue is full. */
|
||||
static int add_friend_request(const char *public_key, const char *data)
|
||||
{
|
||||
if (FriendRequests.max_idx >= MAX_FRIEND_REQUESTS)
|
||||
if (FrndRequests.max_idx >= MAX_FRIEND_REQUESTS)
|
||||
return -1;
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= FriendRequests.max_idx; ++i) {
|
||||
if (!FriendRequests.request[i].active) {
|
||||
FriendRequests.request[i].active = true;
|
||||
memcpy(FriendRequests.request[i].key, public_key, TOX_CLIENT_ID_SIZE);
|
||||
snprintf(FriendRequests.request[i].msg, sizeof(FriendRequests.request[i].msg), "%s", data);
|
||||
for (i = 0; i <= FrndRequests.max_idx; ++i) {
|
||||
if (!FrndRequests.request[i].active) {
|
||||
FrndRequests.request[i].active = true;
|
||||
memcpy(FrndRequests.request[i].key, public_key, TOX_CLIENT_ID_SIZE);
|
||||
snprintf(FrndRequests.request[i].msg, sizeof(FrndRequests.request[i].msg), "%s", data);
|
||||
|
||||
if (i == FriendRequests.max_idx)
|
||||
++FriendRequests.max_idx;
|
||||
if (i == FrndRequests.max_idx)
|
||||
++FrndRequests.max_idx;
|
||||
|
||||
++FriendRequests.num_requests;
|
||||
++FrndRequests.num_requests;
|
||||
|
||||
return i;
|
||||
}
|
||||
@@ -184,7 +184,12 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
|
||||
if (key == '\t') { /* TAB key: auto-completes command */
|
||||
if (ctx->len > 1 && ctx->line[0] == '/') {
|
||||
int diff = complete_line(self, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
|
||||
int diff = -1;
|
||||
|
||||
if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0)
|
||||
diff = dir_match(self, m, ctx->line, L"/avatar");
|
||||
else
|
||||
diff = complete_line(self, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);
|
||||
|
||||
if (diff != -1) {
|
||||
if (x + diff > x2 - 1) {
|
||||
@@ -272,7 +277,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
||||
} else {
|
||||
wprintw(statusbar->topline, " [Offline]");
|
||||
wattron(statusbar->topline, A_BOLD);
|
||||
wprintw(statusbar->topline, " %s ", statusbar->nick);
|
||||
wprintw(statusbar->topline, " %s", statusbar->nick);
|
||||
wattroff(statusbar->topline, A_BOLD);
|
||||
}
|
||||
|
||||
@@ -300,7 +305,7 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
|
||||
}
|
||||
|
||||
if (statusbar->statusmsg[0])
|
||||
wprintw(statusbar->topline, " - %s", statusbar->statusmsg);
|
||||
wprintw(statusbar->topline, " : %s", statusbar->statusmsg);
|
||||
|
||||
mvwhline(self->window, y2 - CHATBOX_HEIGHT, 0, ACS_HLINE, x2);
|
||||
|
||||
@@ -456,16 +461,17 @@ static void prompt_onInit(ToxWindow *self, Tox *m)
|
||||
|
||||
line_info_init(ctx->hst);
|
||||
|
||||
if (user_settings_->autolog == AUTOLOG_ON) {
|
||||
if (user_settings->autolog == AUTOLOG_ON) {
|
||||
char myid[TOX_FRIEND_ADDRESS_SIZE];
|
||||
tox_get_address(m, (uint8_t *) myid);
|
||||
log_enable(self->name, myid, ctx->log);
|
||||
log_enable(self->name, myid, NULL, ctx->log, LOG_PROMPT);
|
||||
}
|
||||
|
||||
scrollok(ctx->history, 0);
|
||||
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
||||
|
||||
print_welcome_msg(self);
|
||||
if (user_settings->show_welcome_msg == SHOW_WELCOME_MSG_ON)
|
||||
print_welcome_msg(self);
|
||||
}
|
||||
|
||||
ToxWindow new_prompt(void)
|
||||
|
||||
20
src/prompt.h
20
src/prompt.h
@@ -20,21 +20,21 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PROMPT_H_UZYGWFFL
|
||||
#define PROMPT_H_UZYGWFFL
|
||||
#ifndef PROMPT_H
|
||||
#define PROMPT_H
|
||||
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
|
||||
#ifdef _AUDIO
|
||||
#define AC_NUM_GLOB_COMMANDS 18
|
||||
#ifdef AUDIO
|
||||
#define AC_NUM_GLOB_COMMANDS 19
|
||||
#else
|
||||
#define AC_NUM_GLOB_COMMANDS 16
|
||||
#endif /* _AUDIO */
|
||||
#define AC_NUM_GLOB_COMMANDS 17
|
||||
#endif /* AUDIO */
|
||||
|
||||
#define MAX_FRIEND_REQUESTS 32
|
||||
|
||||
struct _friend_request {
|
||||
struct friend_request {
|
||||
bool active;
|
||||
char msg[MAX_STR_SIZE];
|
||||
uint8_t key[TOX_CLIENT_ID_SIZE];
|
||||
@@ -43,8 +43,8 @@ struct _friend_request {
|
||||
typedef struct {
|
||||
int max_idx;
|
||||
int num_requests;
|
||||
struct _friend_request request[MAX_FRIEND_REQUESTS];
|
||||
} _FriendRequests;
|
||||
struct friend_request request[MAX_FRIEND_REQUESTS];
|
||||
} FriendRequests;
|
||||
|
||||
ToxWindow new_prompt(void);
|
||||
void prep_prompt_win(void);
|
||||
@@ -55,4 +55,4 @@ void prompt_update_status(ToxWindow *prompt, uint8_t status);
|
||||
void prompt_update_connectionstatus(ToxWindow *prompt, bool is_connected);
|
||||
void kill_prompt_window(ToxWindow *self);
|
||||
|
||||
#endif /* end of include guard: PROMPT_H_UZYGWFFL */
|
||||
#endif /* end of include guard: PROMPT_H */
|
||||
|
||||
@@ -31,9 +31,9 @@
|
||||
#include "notify.h"
|
||||
#include "misc_tools.h"
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
#include "device.h"
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
|
||||
#include "settings.h"
|
||||
#include "line_info.h"
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
#define NO_SOUND "silent"
|
||||
|
||||
static struct _ui_strings {
|
||||
static struct ui_strings {
|
||||
const char* self;
|
||||
const char* timestamps;
|
||||
const char* alerts;
|
||||
@@ -54,6 +54,7 @@ static struct _ui_strings {
|
||||
const char* history_size;
|
||||
const char* show_typing_self;
|
||||
const char* show_typing_other;
|
||||
const char* show_welcome_msg;
|
||||
} ui_strings = {
|
||||
"ui",
|
||||
"timestamps",
|
||||
@@ -64,6 +65,7 @@ static struct _ui_strings {
|
||||
"history_size",
|
||||
"show_typing_self",
|
||||
"show_typing_other",
|
||||
"show_welcome_msg",
|
||||
};
|
||||
|
||||
static void ui_defaults(struct user_settings* settings)
|
||||
@@ -76,9 +78,10 @@ static void ui_defaults(struct user_settings* settings)
|
||||
settings->history_size = 700;
|
||||
settings->show_typing_self = SHOW_TYPING_ON;
|
||||
settings->show_typing_other = SHOW_TYPING_ON;
|
||||
settings->show_welcome_msg = SHOW_WELCOME_MSG_ON;
|
||||
}
|
||||
|
||||
static const struct _keys_strings {
|
||||
static const struct keys_strings {
|
||||
const char* self;
|
||||
const char* next_tab;
|
||||
const char* prev_tab;
|
||||
@@ -116,24 +119,27 @@ static void key_defaults(struct user_settings* settings)
|
||||
settings->key_peer_list_down = T_KEY_C_RB;
|
||||
}
|
||||
|
||||
static const struct _tox_strings {
|
||||
static const struct tox_strings {
|
||||
const char* self;
|
||||
const char* download_path;
|
||||
const char* chatlogs_path;
|
||||
const char* avatar_path;
|
||||
} tox_strings = {
|
||||
"tox",
|
||||
"download_path",
|
||||
"chatlogs_path",
|
||||
"avatar_path",
|
||||
};
|
||||
|
||||
static void tox_defaults(struct user_settings* settings)
|
||||
{
|
||||
strcpy(settings->download_path, "");
|
||||
strcpy(settings->chatlogs_path, "");
|
||||
strcpy(settings->avatar_path, "");
|
||||
}
|
||||
|
||||
#ifdef _AUDIO
|
||||
static const struct _audio_strings {
|
||||
#ifdef AUDIO
|
||||
static const struct audio_strings {
|
||||
const char* self;
|
||||
const char* input_device;
|
||||
const char* output_device;
|
||||
@@ -153,8 +159,8 @@ static void audio_defaults(struct user_settings* settings)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _SOUND_NOTIFY
|
||||
static const struct _sound_strings {
|
||||
#ifdef SOUND_NOTIFY
|
||||
static const struct sound_strings {
|
||||
const char* self;
|
||||
const char* error;
|
||||
const char* self_log_in;
|
||||
@@ -209,7 +215,7 @@ int settings_load(struct user_settings *s, const char *patharg)
|
||||
tox_defaults(s);
|
||||
key_defaults(s);
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
audio_defaults(s);
|
||||
#endif
|
||||
|
||||
@@ -250,6 +256,7 @@ int settings_load(struct user_settings *s, const char *patharg)
|
||||
config_setting_lookup_int(setting, ui_strings.history_size, &s->history_size);
|
||||
config_setting_lookup_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_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 */
|
||||
}
|
||||
@@ -276,6 +283,14 @@ int settings_load(struct user_settings *s, const char *patharg)
|
||||
else if (s->chatlogs_path[len - 1] != '/')
|
||||
strcat(&s->chatlogs_path[len - 1], "/");
|
||||
}
|
||||
|
||||
if ( config_setting_lookup_string(setting, tox_strings.avatar_path, &str) ) {
|
||||
snprintf(s->avatar_path, sizeof(s->avatar_path), "%s", str);
|
||||
int len = strlen(s->avatar_path);
|
||||
|
||||
if (len >= sizeof(s->avatar_path))
|
||||
s->avatar_path[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* keys */
|
||||
@@ -292,7 +307,7 @@ int settings_load(struct user_settings *s, const char *patharg)
|
||||
if (config_setting_lookup_string(setting, key_strings.peer_list_down, &tmp)) s->key_peer_list_down = key_parse(&tmp);
|
||||
}
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
if ((setting = config_lookup(cfg, audio_strings.self)) != NULL) {
|
||||
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;
|
||||
@@ -304,7 +319,7 @@ int settings_load(struct user_settings *s, const char *patharg)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _SOUND_NOTIFY
|
||||
#ifdef SOUND_NOTIFY
|
||||
if ((setting = config_lookup(cfg, sound_strings.self)) != NULL) {
|
||||
if ( (config_setting_lookup_string(setting, sound_strings.error, &str) != CONFIG_TRUE) ||
|
||||
!set_sound(error, str) ) {
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _settings_h
|
||||
#define _settings_h
|
||||
#ifndef SETTINGS_H
|
||||
#define SETTINGS_H
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
@@ -35,12 +35,14 @@ struct user_settings {
|
||||
int history_size; /* int between MIN_HISTORY and MAX_HISTORY */
|
||||
int show_typing_self; /* boolean */
|
||||
int show_typing_other; /* boolean */
|
||||
int show_welcome_msg; /* boolean */
|
||||
|
||||
char download_path[PATH_MAX];
|
||||
char chatlogs_path[PATH_MAX];
|
||||
char avatar_path[PATH_MAX];
|
||||
|
||||
int key_next_tab; /* character code */
|
||||
int key_prev_tab; /* character code */
|
||||
int key_next_tab;
|
||||
int key_prev_tab;
|
||||
int key_scroll_line_up;
|
||||
int key_scroll_line_down;
|
||||
int key_half_page_up;
|
||||
@@ -48,7 +50,8 @@ struct user_settings {
|
||||
int key_page_bottom;
|
||||
int key_peer_list_up;
|
||||
int key_peer_list_down;
|
||||
#ifdef _AUDIO
|
||||
|
||||
#ifdef AUDIO
|
||||
int audio_in_dev;
|
||||
int audio_out_dev;
|
||||
double VAD_treshold;
|
||||
@@ -74,8 +77,11 @@ enum {
|
||||
SHOW_TYPING_OFF = 0,
|
||||
SHOW_TYPING_ON = 1,
|
||||
|
||||
SHOW_WELCOME_MSG_OFF = 0,
|
||||
SHOW_WELCOME_MSG_ON = 1,
|
||||
|
||||
DFLT_HST_SIZE = 700,
|
||||
} settings_values;
|
||||
|
||||
int settings_load(struct user_settings *s, const char *patharg);
|
||||
#endif /* #define _settings_h */
|
||||
#endif /* #define SETTINGS_H */
|
||||
|
||||
405
src/toxic.c
405
src/toxic.c
@@ -38,8 +38,10 @@
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include <tox/tox.h>
|
||||
#include <tox/toxencryptsave.h>
|
||||
|
||||
#include "configdir.h"
|
||||
#include "toxic.h"
|
||||
@@ -53,18 +55,20 @@
|
||||
#include "log.h"
|
||||
#include "notify.h"
|
||||
#include "device.h"
|
||||
#include "message_queue.h"
|
||||
#include "execute.h"
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
#include "audio_call.h"
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
|
||||
#ifndef PACKAGE_DATADIR
|
||||
#define PACKAGE_DATADIR "."
|
||||
#endif
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
ToxAv *av;
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
|
||||
/* Export for use in Callbacks */
|
||||
char *DATA_FILE = NULL;
|
||||
@@ -73,13 +77,23 @@ ToxWindow *prompt = NULL;
|
||||
|
||||
#define AUTOSAVE_FREQ 60
|
||||
|
||||
struct _Winthread Winthread;
|
||||
struct Winthread Winthread;
|
||||
struct cqueue_thread cqueue_thread;
|
||||
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 {
|
||||
bool data_is_encrypted;
|
||||
char pass[MAX_PASSWORD_LEN + 1];
|
||||
int len;
|
||||
} user_password;
|
||||
|
||||
static void catch_SIGINT(int sig)
|
||||
{
|
||||
Winthread.sig_exit_toxic = true;
|
||||
Winthread.sig_exit_toxic = 1;
|
||||
}
|
||||
|
||||
static void catch_SIGSEGV(int sig)
|
||||
@@ -92,7 +106,7 @@ static void catch_SIGSEGV(int sig)
|
||||
|
||||
static void flag_window_resize(int sig)
|
||||
{
|
||||
Winthread.flag_resize = true;
|
||||
Winthread.flag_resize = 1;
|
||||
}
|
||||
|
||||
static void init_signal_catchers(void)
|
||||
@@ -105,20 +119,21 @@ static void init_signal_catchers(void)
|
||||
void exit_toxic_success(Tox *m)
|
||||
{
|
||||
store_data(m, DATA_FILE);
|
||||
memset(&user_password, 0, sizeof(struct user_password));
|
||||
close_all_file_senders(m);
|
||||
kill_all_windows(m);
|
||||
|
||||
free(DATA_FILE);
|
||||
free(BLOCK_FILE);
|
||||
free(user_settings_);
|
||||
free(user_settings);
|
||||
|
||||
#ifdef _SOUND_NOTIFY
|
||||
#ifdef SOUND_NOTIFY
|
||||
// sound_notify(NULL, self_log_out, NT_ALWAYS, NULL);
|
||||
#endif /* _SOUND_NOTIFY */
|
||||
#endif /* SOUND_NOTIFY */
|
||||
terminate_notify();
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
terminate_audio();
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
tox_kill(m);
|
||||
endwin();
|
||||
exit(EXIT_SUCCESS);
|
||||
@@ -157,7 +172,7 @@ static void init_term(void)
|
||||
short bg_color = COLOR_BLACK;
|
||||
start_color();
|
||||
|
||||
if (user_settings_->colour_theme == NATIVE_COLS) {
|
||||
if (user_settings->colour_theme == NATIVE_COLS) {
|
||||
if (assume_default_colors(-1, -1) == OK)
|
||||
bg_color = -1;
|
||||
}
|
||||
@@ -182,8 +197,15 @@ static struct _init_messages {
|
||||
} init_messages;
|
||||
|
||||
/* One-time queue for messages created during init. Do not use after program init. */
|
||||
static void queue_init_message(const char *msg)
|
||||
static void queue_init_message(const char *msg, ...)
|
||||
{
|
||||
char frmt_msg[MAX_STR_SIZE] = {0};
|
||||
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
vsnprintf(frmt_msg, sizeof(frmt_msg), msg, args);
|
||||
va_end(args);
|
||||
|
||||
int i = init_messages.num;
|
||||
++init_messages.num;
|
||||
|
||||
@@ -197,11 +219,11 @@ static void queue_init_message(const char *msg)
|
||||
if (new_msgs[i] == NULL)
|
||||
exit_toxic_err("Failed in queue_init_message", FATALERR_MEMORY);
|
||||
|
||||
snprintf(new_msgs[i], MAX_STR_SIZE, "%s", msg);
|
||||
snprintf(new_msgs[i], MAX_STR_SIZE, "%s", frmt_msg);
|
||||
init_messages.msgs = new_msgs;
|
||||
}
|
||||
|
||||
/* called after messages have been printed to console and are no longer needed */
|
||||
/* called after messages have been printed to prompt and are no longer needed */
|
||||
static void cleanup_init_messages(void)
|
||||
{
|
||||
if (init_messages.num <= 0)
|
||||
@@ -237,16 +259,16 @@ static Tox *init_tox(void)
|
||||
char tmp[48];
|
||||
snprintf(tmp, sizeof(tmp), "Using proxy %s : %d",
|
||||
arg_opts.proxy_address, arg_opts.proxy_port);
|
||||
queue_init_message(tmp);
|
||||
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(msg);
|
||||
queue_init_message("%s", msg);
|
||||
msg = "Use the -t option to disable UDP.";
|
||||
queue_init_message(msg);
|
||||
queue_init_message("%s", msg);
|
||||
}
|
||||
|
||||
/* Init core */
|
||||
@@ -283,6 +305,7 @@ static Tox *init_tox(void)
|
||||
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"));
|
||||
@@ -302,7 +325,7 @@ static Tox *init_tox(void)
|
||||
#define MAXNODES 50
|
||||
#define NODELEN (MAX_NODE_LINE - TOX_CLIENT_ID_SIZE - 7)
|
||||
|
||||
static struct _toxNodes {
|
||||
static struct toxNodes {
|
||||
int lines;
|
||||
char nodes[MAXNODES][NODELEN];
|
||||
uint16_t ports[MAXNODES];
|
||||
@@ -456,6 +479,104 @@ static void load_friendlist(Tox *m)
|
||||
sort_friendlist_index();
|
||||
}
|
||||
|
||||
/* return length of password on success, 0 on failure */
|
||||
static int password_prompt(char *buf, int size)
|
||||
{
|
||||
buf[0] = '\0';
|
||||
|
||||
/* disable terminal echo */
|
||||
struct termios oflags, nflags;
|
||||
tcgetattr(fileno(stdin), &oflags);
|
||||
nflags = oflags;
|
||||
nflags.c_lflag &= ~ECHO;
|
||||
nflags.c_lflag |= ECHONL;
|
||||
|
||||
if (tcsetattr(fileno(stdin), TCSANOW, &nflags) != 0)
|
||||
return 0;
|
||||
|
||||
const char *p = fgets(buf, size, stdin);
|
||||
int len = strlen(buf);
|
||||
|
||||
/* re-enable terminal echo */
|
||||
tcsetattr(fileno(stdin), TCSANOW, &oflags);
|
||||
|
||||
if (p == NULL || len <= 1)
|
||||
return 0;
|
||||
|
||||
/* eat overflowed stdin and return error */
|
||||
if (buf[--len] != '\n') {
|
||||
int ch;
|
||||
while ((ch = getchar()) != '\n' && ch > 0)
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
|
||||
buf[len] = '\0';
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Ask user if they would like to encrypt the data file and set password */
|
||||
static void first_time_encrypt(const char *msg)
|
||||
{
|
||||
char ch[256] = {0};
|
||||
|
||||
do {
|
||||
system("clear");
|
||||
printf("%s ", msg);
|
||||
|
||||
if (!strcasecmp(ch, "y\n") || !strcasecmp(ch, "n\n") || !strcasecmp(ch, "yes\n")
|
||||
|| !strcasecmp(ch, "no\n") || !strcasecmp(ch, "q\n"))
|
||||
break;
|
||||
|
||||
} while (fgets(ch, sizeof(ch), stdin));
|
||||
|
||||
printf("\n");
|
||||
|
||||
if (ch[0] == 'q' || ch[0] == 'Q')
|
||||
exit(0);
|
||||
|
||||
if (ch[0] == 'y' || ch[0] == 'Y') {
|
||||
int len = 0;
|
||||
bool valid_password = false;
|
||||
char passconfirm[MAX_PASSWORD_LEN + 1] = {0};
|
||||
printf("Enter a new password (must be at least %d characters) ", MIN_PASSWORD_LEN);
|
||||
|
||||
while (valid_password == false) {
|
||||
len = password_prompt(user_password.pass, sizeof(user_password.pass));
|
||||
user_password.len = len;
|
||||
|
||||
if (strcasecmp(user_password.pass, "q") == 0)
|
||||
exit(0);
|
||||
|
||||
if (string_is_empty(passconfirm) && (len < MIN_PASSWORD_LEN || len > MAX_PASSWORD_LEN)) {
|
||||
printf("Password must be between %d and %d characters long. ", MIN_PASSWORD_LEN, MAX_PASSWORD_LEN);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string_is_empty(passconfirm)) {
|
||||
printf("Enter password again ");
|
||||
snprintf(passconfirm, sizeof(passconfirm), "%s", user_password.pass);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(user_password.pass, passconfirm) != 0) {
|
||||
memset(passconfirm, 0, sizeof(passconfirm));
|
||||
memset(user_password.pass, 0, sizeof(user_password.pass));
|
||||
printf("Passwords don't match. Try again. ");
|
||||
continue;
|
||||
}
|
||||
|
||||
valid_password = true;
|
||||
}
|
||||
|
||||
queue_init_message("Data file '%s' has been encrypted", DATA_FILE);
|
||||
memset(passconfirm, 0, sizeof(passconfirm));
|
||||
user_password.data_is_encrypted = true;
|
||||
}
|
||||
|
||||
system("clear");
|
||||
}
|
||||
|
||||
/*
|
||||
* Store Messenger to given location
|
||||
* Return 0 stored successfully or ignoring data file
|
||||
@@ -464,7 +585,7 @@ static void load_friendlist(Tox *m)
|
||||
* Return -3 opening path failed
|
||||
* Return -4 fwrite failed
|
||||
*/
|
||||
int store_data(Tox *m, char *path)
|
||||
int store_data(Tox *m, const char *path)
|
||||
{
|
||||
if (arg_opts.ignore_data_file)
|
||||
return 0;
|
||||
@@ -472,13 +593,16 @@ int store_data(Tox *m, char *path)
|
||||
if (path == NULL)
|
||||
return -1;
|
||||
|
||||
int len = tox_size(m);
|
||||
int len = user_password.data_is_encrypted ? tox_encrypted_size(m) : tox_size(m);
|
||||
char *buf = malloc(len);
|
||||
|
||||
if (buf == NULL)
|
||||
return -2;
|
||||
|
||||
tox_save(m, (uint8_t *) buf);
|
||||
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);
|
||||
else
|
||||
tox_save(m, (uint8_t *) buf);
|
||||
|
||||
FILE *fd = fopen(path, "wb");
|
||||
|
||||
@@ -506,9 +630,12 @@ static void load_data(Tox *m, char *path)
|
||||
FILE *fd;
|
||||
|
||||
if ((fd = fopen(path, "rb")) != NULL) {
|
||||
fseek(fd, 0, SEEK_END);
|
||||
int len = ftell(fd);
|
||||
fseek(fd, 0, SEEK_SET);
|
||||
off_t len = file_size(path);
|
||||
|
||||
if (len == -1) {
|
||||
fclose(fd);
|
||||
exit_toxic_err("failed in load_data", FATALERR_FILEOP);
|
||||
}
|
||||
|
||||
char *buf = malloc(len);
|
||||
|
||||
@@ -520,10 +647,54 @@ static void load_data(Tox *m, char *path)
|
||||
if (fread(buf, len, 1, fd) != 1) {
|
||||
free(buf);
|
||||
fclose(fd);
|
||||
exit_toxic_err("failed in load_data", FATALERR_FREAD);
|
||||
exit_toxic_err("failed in load_data", FATALERR_FILEOP);
|
||||
}
|
||||
|
||||
bool is_encrypted = tox_is_data_encrypted((uint8_t *) buf);
|
||||
|
||||
/* attempt to encrypt an already encrypted data file */
|
||||
if (arg_opts.encrypt_data && is_encrypted)
|
||||
exit_toxic_err("failed in load_data", FATALERR_ENCRYPT);
|
||||
|
||||
if (arg_opts.unencrypt_data && is_encrypted)
|
||||
queue_init_message("Data file '%s' has been unencrypted", path);
|
||||
else if (arg_opts.unencrypt_data)
|
||||
queue_init_message("Warning: passed --unencrypt-data option with unencrypted data file '%s'", path);
|
||||
|
||||
if (is_encrypted) {
|
||||
if (!arg_opts.unencrypt_data)
|
||||
user_password.data_is_encrypted = true;
|
||||
|
||||
int pwlen = 0;
|
||||
system("clear");
|
||||
printf("Enter password (q to quit) ");
|
||||
|
||||
while (true) {
|
||||
pwlen = password_prompt(user_password.pass, sizeof(user_password.pass));
|
||||
user_password.len = pwlen;
|
||||
|
||||
if (strcasecmp(user_password.pass, "q") == 0)
|
||||
exit(0);
|
||||
|
||||
if (pwlen < MIN_PASSWORD_LEN) {
|
||||
system("clear");
|
||||
sleep(1);
|
||||
printf("Invalid password. Try again. ");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tox_encrypted_load(m, (uint8_t *) buf, len, (uint8_t *) user_password.pass, pwlen) == 0) {
|
||||
break;
|
||||
} else {
|
||||
system("clear");
|
||||
sleep(1);
|
||||
printf("Invalid password. Try again. ");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tox_load(m, (uint8_t *) buf, len);
|
||||
}
|
||||
|
||||
tox_load(m, (uint8_t *) buf, len);
|
||||
load_friendlist(m);
|
||||
load_blocklist(BLOCK_FILE);
|
||||
|
||||
@@ -553,6 +724,7 @@ void *thread_winref(void *data)
|
||||
{
|
||||
Tox *m = (Tox *) data;
|
||||
uint8_t draw_count = 0;
|
||||
init_signal_catchers();
|
||||
|
||||
while (true) {
|
||||
draw_active_window(m);
|
||||
@@ -560,7 +732,7 @@ void *thread_winref(void *data)
|
||||
|
||||
if (Winthread.flag_resize) {
|
||||
on_window_resize();
|
||||
Winthread.flag_resize = false;
|
||||
Winthread.flag_resize = 0;
|
||||
} else if (draw_count >= INACTIVE_WIN_REFRESH_RATE) {
|
||||
refresh_inactive_windows();
|
||||
draw_count = 0;
|
||||
@@ -573,13 +745,34 @@ void *thread_winref(void *data)
|
||||
}
|
||||
}
|
||||
|
||||
void *thread_cqueue(void *data)
|
||||
{
|
||||
Tox *m = (Tox *) data;
|
||||
|
||||
while (true) {
|
||||
pthread_mutex_lock(&Winthread.lock);
|
||||
int i;
|
||||
|
||||
for (i = 2; i < MAX_WINDOWS_NUM; ++i) {
|
||||
ToxWindow *toxwin = get_window_ptr(i);
|
||||
|
||||
if (toxwin != NULL && toxwin->is_chat && tox_get_friend_connection_status(m, toxwin->num) == 1)
|
||||
cqueue_try_send(toxwin, m);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&Winthread.lock);
|
||||
usleep(7000);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: toxic [OPTION] [FILE ...]\n");
|
||||
fprintf(stderr, " -4, --ipv4 Force IPv4 connection\n");
|
||||
fprintf(stderr, " -b --debug Enable stderr for debugging\n");
|
||||
fprintf(stderr, " -b, --debug Enable stderr for debugging\n");
|
||||
fprintf(stderr, " -c, --config Use specified config file\n");
|
||||
fprintf(stderr, " -d, --default-locale Use default POSIX locale\n");
|
||||
fprintf(stderr, " -e, --encrypt-data Encrypt an unencrypted data file\n");
|
||||
fprintf(stderr, " -f, --file Use specified data file\n");
|
||||
fprintf(stderr, " -h, --help Show this message and exit\n");
|
||||
fprintf(stderr, " -n, --nodes Use specified DHTnodes file\n");
|
||||
@@ -587,19 +780,15 @@ static void print_usage(void)
|
||||
fprintf(stderr, " -p, --proxy Use proxy: Requires [IP] [port]\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, " -u, --unencrypt-data Unencrypt an encrypted data file\n");
|
||||
fprintf(stderr, " -x, --nodata Ignore data file\n");
|
||||
}
|
||||
|
||||
static void set_default_opts(void)
|
||||
{
|
||||
arg_opts.use_ipv4 = 0;
|
||||
arg_opts.ignore_data_file = 0;
|
||||
arg_opts.debug = 0;
|
||||
arg_opts.default_locale = 0;
|
||||
arg_opts.use_custom_data = 0;
|
||||
arg_opts.no_connect = 0;
|
||||
arg_opts.force_tcp = 0;
|
||||
arg_opts.use_proxy = 0;
|
||||
memset(&arg_opts, 0, sizeof(struct arg_opts));
|
||||
|
||||
/* set any non-zero defaults here*/
|
||||
}
|
||||
|
||||
static void parse_args(int argc, char *argv[])
|
||||
@@ -613,16 +802,18 @@ static void parse_args(int argc, char *argv[])
|
||||
{"debug", no_argument, 0, 'b'},
|
||||
{"default-locale", no_argument, 0, 'd'},
|
||||
{"config", required_argument, 0, 'c'},
|
||||
{"encrypt-data", no_argument, 0, 'e'},
|
||||
{"nodes", required_argument, 0, 'n'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"noconnect", no_argument, 0, 'o'},
|
||||
{"dnslist", required_argument, 0, 'r'},
|
||||
{"force-tcp", no_argument, 0, 't'},
|
||||
{"proxy", required_argument, 0, 'p'},
|
||||
{"unencrypt-data", no_argument, 0, 'u'},
|
||||
{NULL, no_argument, NULL, 0},
|
||||
};
|
||||
|
||||
const char *opts_str = "4bdhotxc:f:n:r:p:";
|
||||
const char *opts_str = "4bdehotuxc:f:n:r:p:";
|
||||
int opt, indexptr;
|
||||
|
||||
while ((opt = getopt_long(argc, argv, opts_str, long_opts, &indexptr)) != -1) {
|
||||
@@ -649,6 +840,10 @@ static void parse_args(int argc, char *argv[])
|
||||
queue_init_message("Using default POSIX locale");
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
arg_opts.encrypt_data = 1;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
arg_opts.use_custom_data = 1;
|
||||
DATA_FILE = strdup(optarg);
|
||||
@@ -660,9 +855,8 @@ static void parse_args(int argc, char *argv[])
|
||||
strcpy(BLOCK_FILE, optarg);
|
||||
strcat(BLOCK_FILE, "-blocklist");
|
||||
|
||||
char tmp[PATH_MAX];
|
||||
snprintf(tmp, sizeof(tmp), "Using '%s' data file", DATA_FILE);
|
||||
queue_init_message(tmp);
|
||||
queue_init_message("Using '%s' data file", DATA_FILE);
|
||||
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
@@ -700,6 +894,10 @@ static void parse_args(int argc, char *argv[])
|
||||
arg_opts.force_tcp = 1;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
arg_opts.unencrypt_data = 1;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
arg_opts.ignore_data_file = 1;
|
||||
queue_init_message("Ignoring data file");
|
||||
@@ -715,7 +913,7 @@ static void parse_args(int argc, char *argv[])
|
||||
|
||||
#define DATANAME "data"
|
||||
#define BLOCKNAME "data-blocklist"
|
||||
static int init_data_files(void)
|
||||
static int init_default_data_files(void)
|
||||
{
|
||||
if (arg_opts.use_custom_data)
|
||||
return 0;
|
||||
@@ -723,28 +921,26 @@ static int init_data_files(void)
|
||||
char *user_config_dir = get_user_config_dir();
|
||||
int config_err = create_user_config_dirs(user_config_dir);
|
||||
|
||||
if (DATA_FILE == NULL ) {
|
||||
if (config_err) {
|
||||
DATA_FILE = strdup(DATANAME);
|
||||
BLOCK_FILE = strdup(BLOCKNAME);
|
||||
if (config_err) {
|
||||
DATA_FILE = strdup(DATANAME);
|
||||
BLOCK_FILE = strdup(BLOCKNAME);
|
||||
|
||||
if (DATA_FILE == NULL || BLOCK_FILE == NULL)
|
||||
exit_toxic_err("failed in load_data_structures", FATALERR_MEMORY);
|
||||
} else {
|
||||
DATA_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(DATANAME) + 1);
|
||||
BLOCK_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(BLOCKNAME) + 1);
|
||||
if (DATA_FILE == NULL || BLOCK_FILE == NULL)
|
||||
exit_toxic_err("failed in load_data_structures", FATALERR_MEMORY);
|
||||
} else {
|
||||
DATA_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(DATANAME) + 1);
|
||||
BLOCK_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen(BLOCKNAME) + 1);
|
||||
|
||||
if (DATA_FILE == NULL || BLOCK_FILE == NULL)
|
||||
exit_toxic_err("failed in load_data_structures", FATALERR_MEMORY);
|
||||
if (DATA_FILE == NULL || BLOCK_FILE == NULL)
|
||||
exit_toxic_err("failed in load_data_structures", FATALERR_MEMORY);
|
||||
|
||||
strcpy(DATA_FILE, user_config_dir);
|
||||
strcat(DATA_FILE, CONFIGDIR);
|
||||
strcat(DATA_FILE, DATANAME);
|
||||
strcpy(DATA_FILE, user_config_dir);
|
||||
strcat(DATA_FILE, CONFIGDIR);
|
||||
strcat(DATA_FILE, DATANAME);
|
||||
|
||||
strcpy(BLOCK_FILE, user_config_dir);
|
||||
strcat(BLOCK_FILE, CONFIGDIR);
|
||||
strcat(BLOCK_FILE, BLOCKNAME);
|
||||
}
|
||||
strcpy(BLOCK_FILE, user_config_dir);
|
||||
strcat(BLOCK_FILE, CONFIGDIR);
|
||||
strcat(BLOCK_FILE, BLOCKNAME);
|
||||
}
|
||||
|
||||
free(user_config_dir);
|
||||
@@ -772,35 +968,54 @@ static useconds_t optimal_msleepval(uint64_t *looptimer, uint64_t *loopcount, ui
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
init_signal_catchers();
|
||||
parse_args(argc, argv);
|
||||
|
||||
/* Make sure all written files are read/writeable only by the current user. */
|
||||
umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
int config_err = init_data_files();
|
||||
if (arg_opts.encrypt_data && arg_opts.unencrypt_data) {
|
||||
arg_opts.encrypt_data = 0;
|
||||
arg_opts.unencrypt_data = 0;
|
||||
queue_init_message("Warning: Using --unencrypt-data and --encrypt-data simultaneously has no effect");
|
||||
}
|
||||
|
||||
/* init user_settings struct and load settings from conf file */
|
||||
user_settings_ = calloc(1, sizeof(struct user_settings));
|
||||
|
||||
if (user_settings_ == NULL)
|
||||
exit_toxic_err("failed in main", FATALERR_MEMORY);
|
||||
|
||||
char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL;
|
||||
int settings_err = settings_load(user_settings_, p);
|
||||
|
||||
Tox *m = init_tox();
|
||||
init_term();
|
||||
|
||||
/* enable stderr for debugging */
|
||||
/* Use the -b flag to enable stderr */
|
||||
if (!arg_opts.debug)
|
||||
freopen("/dev/null", "w", stderr);
|
||||
|
||||
if (m == NULL)
|
||||
exit_toxic_err("failed in main", FATALERR_NETWORKINIT);
|
||||
/* Make sure all written files are read/writeable only by the current user. */
|
||||
umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
|
||||
int config_err = init_default_data_files();
|
||||
bool datafile_exists = file_exists(DATA_FILE);
|
||||
|
||||
if (!arg_opts.ignore_data_file) {
|
||||
if (!datafile_exists && !arg_opts.unencrypt_data)
|
||||
first_time_encrypt("Creating new data file. Would you like to encrypt it? Y/n (q to quit)");
|
||||
else if (arg_opts.encrypt_data)
|
||||
first_time_encrypt("Encrypt existing data file? Y/n (q to quit)");
|
||||
}
|
||||
|
||||
/* init user_settings struct and load settings from conf file */
|
||||
user_settings = calloc(1, sizeof(struct user_settings));
|
||||
|
||||
if (user_settings == NULL)
|
||||
exit_toxic_err("failed in main", FATALERR_MEMORY);
|
||||
|
||||
const char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL;
|
||||
int settings_err = settings_load(user_settings, p);
|
||||
|
||||
Tox *m = init_tox();
|
||||
|
||||
if (m == NULL)
|
||||
exit_toxic_err("failed in main", FATALERR_NETWORKINIT);
|
||||
|
||||
if (!arg_opts.ignore_data_file) {
|
||||
if (arg_opts.encrypt_data && !datafile_exists)
|
||||
arg_opts.encrypt_data = 0;
|
||||
|
||||
if (!arg_opts.ignore_data_file)
|
||||
load_data(m, DATA_FILE);
|
||||
|
||||
}
|
||||
|
||||
init_term();
|
||||
prompt = init_windows(m);
|
||||
prompt_init_statusbar(prompt, m);
|
||||
|
||||
@@ -811,31 +1026,34 @@ int main(int argc, char *argv[])
|
||||
if (pthread_create(&Winthread.tid, NULL, thread_winref, (void *) m) != 0)
|
||||
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
|
||||
|
||||
#ifdef _AUDIO
|
||||
/* thread for message queue */
|
||||
if (pthread_create(&cqueue_thread.tid, NULL, thread_cqueue, (void *) m) != 0)
|
||||
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
|
||||
|
||||
#ifdef AUDIO
|
||||
|
||||
av = init_audio(prompt, m);
|
||||
|
||||
set_primary_device(input, user_settings->audio_in_dev);
|
||||
set_primary_device(output, user_settings->audio_out_dev);
|
||||
|
||||
set_primary_device(input, user_settings_->audio_in_dev);
|
||||
set_primary_device(output, user_settings_->audio_out_dev);
|
||||
|
||||
#elif _SOUND_NOTIFY
|
||||
#elif SOUND_NOTIFY
|
||||
if ( init_devices() == de_InternalError )
|
||||
queue_init_message("Failed to init audio devices");
|
||||
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
|
||||
init_notify(60, 3000);
|
||||
|
||||
#ifdef _SOUND_NOTIFY
|
||||
#ifdef SOUND_NOTIFY
|
||||
// sound_notify(prompt, self_log_in, 0, NULL);
|
||||
#endif /* _SOUND_NOTIFY */
|
||||
#endif /* SOUND_NOTIFY */
|
||||
|
||||
const char *msg;
|
||||
|
||||
if (config_err) {
|
||||
msg = "Unable to determine configuration directory. Defaulting to 'data' for data file...";
|
||||
queue_init_message(msg);
|
||||
queue_init_message("%s", msg);
|
||||
}
|
||||
|
||||
if (settings_err == -1)
|
||||
@@ -844,6 +1062,11 @@ int main(int argc, char *argv[])
|
||||
print_init_messages(prompt);
|
||||
cleanup_init_messages();
|
||||
|
||||
/* set user avatar from config file. if no path is supplied tox_unset_avatar is called */
|
||||
char avatarstr[MAX_STR_SIZE];
|
||||
snprintf(avatarstr, sizeof(avatarstr), "/avatar \"%s\"", user_settings->avatar_path);
|
||||
execute(prompt->chatwin->history, prompt, m, avatarstr, GLOBAL_COMMAND_MODE);
|
||||
|
||||
uint64_t last_save = (uint64_t) time(NULL);
|
||||
uint64_t looptimer = last_save;
|
||||
useconds_t msleepval = 40000;
|
||||
|
||||
20
src/toxic.h
20
src/toxic.h
@@ -20,8 +20,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _toxic_h
|
||||
#define _toxic_h
|
||||
#ifndef TOXIC_H
|
||||
#define TOXIC_H
|
||||
|
||||
#ifndef TOXICVER
|
||||
#define TOXICVER "NOVER_" /* Use the -D flag to set this */
|
||||
@@ -45,7 +45,7 @@
|
||||
#define MAX_STR_SIZE TOX_MAX_MESSAGE_LENGTH
|
||||
#define MAX_CMDNAME_SIZE 64
|
||||
#define TOXIC_MAX_NAME_LENGTH 32 /* Must be <= TOX_MAX_NAME_LENGTH */
|
||||
#define KEY_IDENT_DIGITS 2 /* number of hex digits to display for the pub-key based identifier */
|
||||
#define KEY_IDENT_DIGITS 3 /* number of hex digits to display for the pub-key based identifier */
|
||||
#define TIME_STR_SIZE 16
|
||||
|
||||
/* ASCII key codes */
|
||||
@@ -69,9 +69,9 @@
|
||||
|
||||
typedef enum _FATAL_ERRS {
|
||||
FATALERR_MEMORY = -1, /* heap memory allocation failed */
|
||||
FATALERR_FREAD = -2, /* fread() failed on critical read */
|
||||
FATALERR_THREAD_CREATE = -3, /* thread creation failed */
|
||||
FATALERR_MUTEX_INIT = -4, /* mutex init failed */
|
||||
FATALERR_FILEOP = -2, /* critical file operation failed */
|
||||
FATALERR_THREAD_CREATE = -3, /* thread creation failed for critical thread */
|
||||
FATALERR_MUTEX_INIT = -4, /* mutex init for critical thread failed */
|
||||
FATALERR_THREAD_ATTR = -5, /* thread attr object init failed */
|
||||
FATALERR_LOCALE_SET = -6, /* system locale not set */
|
||||
FATALERR_STORE_DATA = -7, /* store_data failed in critical section */
|
||||
@@ -79,6 +79,7 @@ typedef enum _FATAL_ERRS {
|
||||
FATALERR_INFLOOP = -9, /* infinite loop detected */
|
||||
FATALERR_WININIT = -10, /* window init failed */
|
||||
FATALERR_PROXY = -11, /* Tox network failed to init using a proxy */
|
||||
FATALERR_ENCRYPT = -12, /* Data file encryption failure */
|
||||
} FATAL_ERRS;
|
||||
|
||||
/* Fixes text color problem on some terminals.
|
||||
@@ -88,7 +89,7 @@ typedef enum _FATAL_ERRS {
|
||||
void exit_toxic_success(Tox *m);
|
||||
void exit_toxic_err(const char *errmsg, int errcode);
|
||||
|
||||
int store_data(Tox *m, char *path);
|
||||
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);
|
||||
void on_connectionchange(Tox *m, int32_t friendnumber, uint8_t status, void *userdata);
|
||||
@@ -100,7 +101,7 @@ void on_statusmessagechange(Tox *m, int32_t friendnumber, const uint8_t *string,
|
||||
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 *userdata);
|
||||
void on_groupaction(Tox *m, int groupnumber, int peernumber, const uint8_t *action, uint16_t length, void *userdata);
|
||||
void on_groupinvite(Tox *m, int32_t friendnumber, const uint8_t *group_pub_key, void *userdata);
|
||||
void on_groupinvite(Tox *m, int32_t friendnumber, 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_file_sendrequest(Tox *m, int32_t friendnumber, uint8_t filenumber, uint64_t filesize, const uint8_t *pathname,
|
||||
uint16_t pathname_length, void *userdata);
|
||||
@@ -108,5 +109,6 @@ void on_file_control(Tox *m, int32_t friendnumber, uint8_t receive_send, uint8_t
|
||||
const uint8_t *data, uint16_t length, void *userdata);
|
||||
void on_file_data(Tox *m, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length, void *userdata);
|
||||
void on_typing_change(Tox *m, int32_t friendnumber, uint8_t is_typing, void *userdata);
|
||||
void on_read_receipt(Tox *m, int32_t, uint32_t, void *userdata);
|
||||
|
||||
#endif /* #define _toxic_h */
|
||||
#endif /* #define TOXIC_H */
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _toxic_strings_h
|
||||
#define _toxic_strings_h
|
||||
#ifndef TOXIC_STRINGS_H
|
||||
#define TOXIC_STRINGS_H
|
||||
|
||||
#include "windows.h"
|
||||
|
||||
@@ -61,4 +61,4 @@ void add_line_to_hist(ChatContext *ctx);
|
||||
resets line if at end of history */
|
||||
void fetch_hist_item(ChatContext *ctx, int key_dir);
|
||||
|
||||
#endif /* #define _toxic_strings_h */
|
||||
#endif /* #define TOXIC_STRINGS_H */
|
||||
|
||||
@@ -35,12 +35,12 @@
|
||||
|
||||
#include "settings.h"
|
||||
extern char *DATA_FILE;
|
||||
extern struct _Winthread Winthread;
|
||||
extern struct Winthread Winthread;
|
||||
static ToxWindow windows[MAX_WINDOWS_NUM];
|
||||
static ToxWindow *active_window;
|
||||
|
||||
extern ToxWindow *prompt;
|
||||
extern struct user_settings *user_settings_;
|
||||
extern struct user_settings *user_settings;
|
||||
|
||||
static int num_active_windows;
|
||||
|
||||
@@ -67,7 +67,7 @@ void on_connectionchange(Tox *m, int32_t friendnumber, uint8_t status, void *use
|
||||
|
||||
void on_typing_change(Tox *m, int32_t friendnumber, uint8_t is_typing, void *userdata)
|
||||
{
|
||||
if (user_settings_->show_typing_other == SHOW_TYPING_OFF)
|
||||
if (user_settings->show_typing_other == SHOW_TYPING_OFF)
|
||||
return;
|
||||
|
||||
int i;
|
||||
@@ -164,13 +164,13 @@ void on_groupaction(Tox *m, int groupnumber, int peernumber, const uint8_t *acti
|
||||
}
|
||||
}
|
||||
|
||||
void on_groupinvite(Tox *m, int32_t friendnumber, const uint8_t *group_pub_key, void *userdata)
|
||||
void on_groupinvite(Tox *m, int32_t friendnumber, const uint8_t *group_pub_key, uint16_t length, void *userdata)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i].onGroupInvite != NULL)
|
||||
windows[i].onGroupInvite(&windows[i], m, friendnumber, (const char *) group_pub_key);
|
||||
windows[i].onGroupInvite(&windows[i], m, friendnumber, (const char *) group_pub_key, length);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,6 +219,15 @@ void on_file_data(Tox *m, int32_t friendnumber, uint8_t filenumber, const uint8_
|
||||
}
|
||||
}
|
||||
|
||||
void on_read_receipt(Tox *m, int32_t friendnumber, uint32_t receipt, void *userdata)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
|
||||
if (windows[i].onReadReceipt != NULL)
|
||||
windows[i].onReadReceipt(&windows[i], m, friendnumber, receipt);
|
||||
}
|
||||
}
|
||||
/* CALLBACKS END */
|
||||
|
||||
int add_window(Tox *m, ToxWindow w)
|
||||
@@ -269,7 +278,7 @@ void set_next_window(int ch)
|
||||
ToxWindow *inf = active_window;
|
||||
|
||||
while (true) {
|
||||
if (ch == user_settings_->key_next_tab) {
|
||||
if (ch == user_settings->key_next_tab) {
|
||||
if (++active_window > end)
|
||||
active_window = windows;
|
||||
} else if (--active_window < windows)
|
||||
@@ -357,12 +366,12 @@ void on_window_resize(void)
|
||||
w->stb->topline = subwin(w->window, 2, x2, 0, 0);
|
||||
}
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
if (w->chatwin->infobox.active) {
|
||||
delwin(w->chatwin->infobox.win);
|
||||
w->chatwin->infobox.win = newwin(INFOBOX_HEIGHT, INFOBOX_WIDTH + 1, 1, x2 - INFOBOX_WIDTH);
|
||||
}
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
|
||||
scrollok(w->chatwin->history, 0);
|
||||
}
|
||||
@@ -453,7 +462,7 @@ void draw_active_window(Tox *m)
|
||||
ltr = isprint(ch);
|
||||
#endif /* HAVE_WIDECHAR */
|
||||
|
||||
if (!ltr && (ch == user_settings_->key_next_tab || ch == user_settings_->key_prev_tab)) {
|
||||
if (!ltr && (ch == user_settings->key_next_tab || ch == user_settings->key_prev_tab)) {
|
||||
set_next_window((int) ch);
|
||||
} else {
|
||||
pthread_mutex_lock(&Winthread.lock);
|
||||
|
||||
@@ -20,18 +20,19 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _windows_h
|
||||
#define _windows_h
|
||||
#ifndef WINDOWS_H
|
||||
#define WINDOWS_H
|
||||
|
||||
#include <pthread.h>
|
||||
#include <wctype.h>
|
||||
#include <wchar.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <tox/tox.h>
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
#include <tox/toxav.h>
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
|
||||
#include "toxic.h"
|
||||
|
||||
@@ -64,11 +65,15 @@ typedef enum {
|
||||
Uncomment if necessary */
|
||||
/* #define URXVT_FIX */
|
||||
|
||||
struct _Winthread {
|
||||
struct Winthread {
|
||||
pthread_t tid;
|
||||
pthread_mutex_t lock;
|
||||
bool sig_exit_toxic;
|
||||
bool flag_resize;
|
||||
volatile sig_atomic_t sig_exit_toxic;
|
||||
volatile sig_atomic_t flag_resize;
|
||||
};
|
||||
|
||||
struct cqueue_thread {
|
||||
pthread_t tid;
|
||||
};
|
||||
|
||||
struct arg_opts {
|
||||
@@ -79,7 +84,8 @@ struct arg_opts {
|
||||
int default_locale;
|
||||
int use_custom_data;
|
||||
int no_connect;
|
||||
|
||||
int encrypt_data;
|
||||
int unencrypt_data;
|
||||
char dns_path[MAX_STR_SIZE];
|
||||
char config_path[MAX_STR_SIZE];
|
||||
char nodes_path[MAX_STR_SIZE];
|
||||
@@ -109,14 +115,15 @@ struct ToxWindow {
|
||||
void(*onAction)(ToxWindow *, Tox *, int32_t, const char *, uint16_t);
|
||||
void(*onGroupMessage)(ToxWindow *, Tox *, int, int, const char *, uint16_t);
|
||||
void(*onGroupAction)(ToxWindow *, Tox *, int, int, const char *, uint16_t);
|
||||
void(*onGroupInvite)(ToxWindow *, Tox *, int32_t, const char *);
|
||||
void(*onGroupInvite)(ToxWindow *, Tox *, int32_t, const char *, uint16_t);
|
||||
void(*onGroupNamelistChange)(ToxWindow *, Tox *, int, int, uint8_t);
|
||||
void(*onFileSendRequest)(ToxWindow *, Tox *, int32_t, uint8_t, uint64_t, const char *, uint16_t);
|
||||
void(*onFileControl)(ToxWindow *, Tox *, int32_t, uint8_t, uint8_t, uint8_t, const char *, uint16_t);
|
||||
void(*onFileData)(ToxWindow *, Tox *, int32_t, uint8_t, const char *, uint16_t);
|
||||
void(*onTypingChange)(ToxWindow *, Tox *, int32_t, uint8_t);
|
||||
void(*onReadReceipt)(ToxWindow *, Tox *, int32_t, uint32_t);
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
|
||||
void(*onInvite)(ToxWindow *, ToxAv *, int);
|
||||
void(*onRinging)(ToxWindow *, ToxAv *, int);
|
||||
@@ -135,7 +142,7 @@ struct ToxWindow {
|
||||
int device_selection[2]; /* -1 if not set, if set uses these selections instead of primary device */
|
||||
|
||||
int ringing_sound;
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
|
||||
int active_box; /* For box notify */
|
||||
|
||||
@@ -169,7 +176,7 @@ struct StatusBar {
|
||||
bool is_online;
|
||||
};
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
|
||||
|
||||
#define INFOBOX_HEIGHT 7
|
||||
@@ -188,7 +195,7 @@ struct infobox {
|
||||
|
||||
WINDOW *win;
|
||||
};
|
||||
#endif /* _AUDIO */
|
||||
#endif /* AUDIO */
|
||||
|
||||
#define MAX_LINE_HIST 128
|
||||
|
||||
@@ -208,8 +215,9 @@ struct ChatContext {
|
||||
|
||||
struct history *hst;
|
||||
struct chatlog *log;
|
||||
struct chat_queue *cqueue;
|
||||
|
||||
#ifdef _AUDIO
|
||||
#ifdef AUDIO
|
||||
struct infobox infobox;
|
||||
#endif
|
||||
|
||||
@@ -240,4 +248,4 @@ ToxWindow *get_window_ptr(int i);
|
||||
call at least once per second */
|
||||
void refresh_inactive_windows(void);
|
||||
|
||||
#endif /* #define _windows_h */
|
||||
#endif /* #define WINDOWS_H */
|
||||
|
||||
Reference in New Issue
Block a user